PokeAPI / pokeapi

The Pokémon API
https://pokeapi.co
BSD 3-Clause "New" or "Revised" License
4.39k stars 954 forks source link

Search Pokémons by localized name #818

Open la-urre opened 1 year ago

la-urre commented 1 year ago

Hey there!

I would like to be able to access details about a Pokémon based on its name in a specific language. It seems the info exists as you return it in the response of https://pokeapi.co/api/v2/pokemon-species/{id or name}/. My use case is to get stats about a Pokémon by their name in a given language, so exactly what is returned by https://pokeapi.co/api/v2/ability/{id or name}/.

Could it be possible to add a parameter to this endpoint to be able to pass the language that corresponds to the name of the Pokémon that is supplied ? Happy to help if I can

Naramsim commented 1 year ago

Hi, we don't plan to add such functionality to the v2 API. What's your use case?

  1. search for a pokemon in French (ie: Bulbizarre)
  2. look up its abilities for a specific gen
  3. return the value in French (ie: Booste les capacités, Plante en cas de besoin.)

Like this?

la-urre commented 1 year ago

Yes something similar, my goal at the moment is to get the stats of a Pokémon (attack, defense, ...) from its French name.

Is there any workaround that I could use ?

Naramsim commented 1 year ago

Hmm, the best idea would be to have an offline list of french pokemon names and their corresponding ID.

Maybe you can build that list using a one-time script:

  1. fetch all the pokemon in English: https://pokeapi.co/api/v2/pokemon-species?limit=100000
  2. loop all over the keys and make 1008 additional calls to the API, storing their french name.
  3. use that list in your application

Surely the solution above is the fastest.

Otherwise you could get the ID of a pokemon from his name using the GraphQL query here: https://github.com/PokeAPI/pokeapi/issues/235#issuecomment-1381734720 . You can pull its stats in the same GQL query like below:

query searchForPokemonInFrench {
  pokemon_v2_pokemonspecies(
    where: {
      pokemon_v2_pokemonspeciesnames: {
        pokemon_v2_language: { name: { _eq: "fr" } }
        name: { _regex: "Bulbizarre" }
      }
    }
  ) {
    pokemon_v2_pokemonspeciesnames(
      where: { pokemon_v2_language: { name: { _eq: "fr" } } }
    ) {
      name
    }
    id
    pokemon_v2_pokemons {
      pokemon_v2_pokemonstats {
        base_stat
        pokemon_v2_stat {
          name
        }
      }
    }
  }
}
helblinglilly commented 1 year ago

I recommend keeping an offline list as Naramism has suggested.

I scraped a list down with 200ms delays for all Pokemon, Items, Moves and Abilities to get their ID and keep all language entries so you can search through them. Takes a while to download but worth it.

Putting the search term into a regex and looking up by a specific language key is performing quite well at this size. Of course, that introduces the burden on your end to update this list every so often. And your cold-start times might be a bit higher if you need to load this data in each time.

Feel free to use the .json files I scraped at https://github.com/helblingjoel/pokewiki/tree/main/src/data where there should also be a scraper.js file if you choose to update this.

I can't think of a quicker way to do this.

lbineau commented 1 year ago

Hmm, the best idea would be to have an offline list of french pokemon names and their corresponding ID.

Maybe you can build that list using a one-time script:

1. fetch all the pokemon in English: https://pokeapi.co/api/v2/pokemon-species?limit=100000

2. loop all over the keys and make 1008 additional calls to the API, storing their french name.

3. use that list in your application

Surely the solution above is the fastest.

Otherwise you could get the ID of a pokemon from his name using the GraphQL query here: #235 (comment) . You can pull its stats in the same GQL query like below:

query searchForPokemonInFrench {
  pokemon_v2_pokemonspecies(
    where: {
      pokemon_v2_pokemonspeciesnames: {
        pokemon_v2_language: { name: { _eq: "fr" } }
        name: { _regex: "Bulbizarre" }
      }
    }
  ) {
    pokemon_v2_pokemonspeciesnames(
      where: { pokemon_v2_language: { name: { _eq: "fr" } } }
    ) {
      name
    }
    id
    pokemon_v2_pokemons {
      pokemon_v2_pokemonstats {
        base_stat
        pokemon_v2_stat {
          name
        }
      }
    }
  }
}

I did the same for types and GraphQL is soooo fast compared to endpoint API! I'm struggling to build dynamic language switching with graphQL query variables (ex: https://v4.apollo.vuejs.org/guide-composable/query.html#variables). How would you do that @Naramsim?

Naramsim commented 1 year ago

I simplified it a bit:

query searchForPokemonInFrench ($lang: String, $name: String) {
  pokemon_v2_pokemonspecies(
    where: {
      pokemon_v2_pokemonspeciesnames: {
        pokemon_v2_language: { name: { _eq: $lang } }
        name: { _regex: $name }
      }
    }
  ) {
    pokemon_v2_pokemonspeciesnames(
      where: { pokemon_v2_language: { name: { _eq: $lang } } }
    ) {
      name
    }
    id
  }
}
{
  "lang": "de",
  "name": "Bis"
}
lbineau commented 1 year ago

Thank you, I was using query searchForPokemonInFrench ($language: **!LANGUAGE**, $name: String) and the LANGUAGE type is not existing ofc... The language switcher is working like a charm with $language: String I'm very new to GraphQL language but it looks very powerful! Thank you for your help :-)

acxz commented 3 weeks ago

Here is my solution in python for obtaining a mapping of localized names to their canonical names used by pokeapi's endpoints. Similar to @Naramsim's offline list suggestion and @helblinglilly's scraper.js

https://github.com/acxz/pokeshell/blob/master/scripts/create_pokemon_identifiers.py

@helblinglilly's output wasn't in the format that I needed as I needed a simple mapping. i.e. I wanted to simply do:

input_name = "フシギダネ"
pokemon_identifiers = {...}

# Get name that pokeapi endpoints understand
canonical_name = pokemon_identifiers[input_name]

# Get response
...

Here is the output of the above script: https://github.com/acxz/pokeshell/blob/master/share/pokemon_identifiers.json

I also attached the file directly here, so you don't have to run the script for your purposes: pokemon_identifiers.json

Subset of the output file:

{
  "1": "bulbasaur",
  "bulbasaur": "bulbasaur",
  "フシギダネ": "bulbasaur",
  "fushigidane": "bulbasaur",
  "이상해씨": "bulbasaur",
  "妙蛙種子": "bulbasaur",
  "bulbizarre": "bulbasaur",
  "bisasam": "bulbasaur",
  "2": "ivysaur",
  "ivysaur": "ivysaur",
  "フシギソウ": "ivysaur"
}

You can use this very easily by loading this json file as a dictionary in python and then passing your input through this dictionary to get the name that pokeapi's endpoint does understand.

Hopefully this helps anyone coming across this issue.