defmodule WarframeWorldstateDataElixirTools.Translations do @moduledoc """ This module contains methods for translating keys to proper user facing strings. """ @locales [ :en, :cs, :de, :es, :fr, :it, :ko, :pl, :pt, :ru, :sr, :tr, :uk, :zh ] @data_files %{ arcanes: "arcanes.json", archon_shards: "archonShards.json", conclave_data: "conclaveData.json", events_data: "eventsData.json", factions_data: "factionsData.json", fissure_modifiers: "fissureModifiers.json", languages: "languages.json", mission_types: "missionTypes.json", operation_types: "operationTypes.json", persistent_enemy_data: "persistentEnemyData.json", sol_nodes: "solNodes.json", sortie_data: "sortieData.json", steel_path: "steelPath.json", syndicates_data: "syndicatesData.json", synth_targets: "synthTargets.json", tutorials: "tutorials.json", upgrade_types: "upgradeTypes.json" } @focus_map %{ "Focus/Attack" => "Madurai", "Focus/Defense" => "Vazarin", "Focus/Tactic" => "Naramon", "Focus/Power" => "Zenurik", "Focus/Ward" => "Unairu" } @polarity_map %{ "AP_ATTACK" => "Madurai", "AP_DEFENSE" => "Vazarin", "AP_TACTIC" => "Naramon", "AP_POWER" => "Zenurik", "AP_WARD" => "Unairu", "AP_UMBRA" => "Umbra", "AP_ANY" => "Aura" } @calendar_event_map %{ "CET_CHALLENGE" => "To Do", "CET_UPGRADE" => "Override", "CET_REWARD" => "Big Prize!", "CET_PLOT" => "Birthday" } @archimedia_map %{ "CT_LAB" => "Deep Archimedea", "CT_HEX" => "Temporal Archimedea" } @doc """ Gets the translation of the name of an in game node in the requested locale. ## Examples iex> WarframeWorldstateDataElixirTools.Translations.node("SolNode1") "Galatea (Neptune)" iex> WarframeWorldstateDataElixirTools.Translations.node("SolNode1", :de) "Galatea (Neptun)" iex> WarframeWorldstateDataElixirTools.Translations.node("SolarSystem/Foo") "Foo" """ def node(key, locale \\ :en) when is_binary(key) and is_atom(locale) and locale in @locales do case sol_node(key, "value", locale) do {:ok, value} -> value {:error, _} -> key end end @doc """ Gets the translation of the enemy faction of an in game node in the requested locale. ## Examples iex> WarframeWorldstateDataElixirTools.Translations.node_enemy("SolNode1") "Corpus" iex> WarframeWorldstateDataElixirTools.Translations.node_enemy("SolNode1", :ko) "코퍼스" """ def node_enemy(key, locale \\ :en) do case sol_node(key, "enemy", locale) do {:ok, value} -> value {:error, _} -> key end end @doc """ Gets the translation of the mission type of an in game node in the requested locale. ## Examples iex> WarframeWorldstateDataElixirTools.Translations.node_mission_type("SolNode1") "Capture" iex> WarframeWorldstateDataElixirTools.Translations.node_mission_type("SolNode1", :de) "Gefangennahme" """ def node_mission_type(key, locale \\ :en) do case sol_node(key, "type", locale) do {:ok, value} -> value {:error, _} -> key end end @doc """ Gets the translation for a mission type from a missions_type.json file. If the translation for the key is not found it returns a "normalized" version of the key. ## Examples iex> WarframeWorldstateDataElixirTools.Translations.mission_type("MT_DEFENSE") "Defense" iex> WarframeWorldstateDataElixirTools.Translations.mission_type("MT_DEFENSE", :de) "Verteidigung" iex> WarframeWorldstateDataElixirTools.Translations.mission_type("MT_random") "Random" """ def mission_type(key, locale \\ :en) when is_binary(key) do case WarframeWorldstateDataElixirTools.DataBundle.read_data_file( @data_files.mission_types, locale ) do {:ok, %{^key => %{"value" => value}}} -> value _ -> String.replace(key, "MT_", "") |> string_to_title() end end @doc """ Gets the translation for a fissure's type in the requested locale. ## Examples iex> WarframeWorldstateDataElixirTools.Translations.fissure_type("VoidT1") "Lith" iex> WarframeWorldstateDataElixirTools.Translations.fissure_type("VoidT1", :de) "Lith" iex> WarframeWorldstateDataElixirTools.Translations.fissure_type("random") "random" """ def fissure_type(key, locale \\ :en) when is_binary(key) and is_atom(locale) do case fissure_modifier(key, "value", locale) do {_, res} -> res end end @doc """ Gets the tier of a fissure by its key in the requested locale. ## Examples iex> WarframeWorldstateDataElixirTools.Translations.fissure_tier("VoidT1") 1 iex> WarframeWorldstateDataElixirTools.Translations.fissure_tier("random") 0 """ def fissure_tier(key, locale \\ :en) when is_binary(key) and is_atom(locale) do case fissure_modifier(key, "num", locale) do {:ok, tier} -> tier _ -> 0 end end @doc """ Gets the localized string value for a given languages.json key. ## Examples iex> key = "/lotus/types/challenges/seasons/daily/seasondailycollecthundredresources" iex> WarframeWorldstateDataElixirTools.Translations.language_string(key) "Gatherer" iex> key = "/lotus/types/challenges/seasons/daily/seasondailycollecthundredresources" iex> WarframeWorldstateDataElixirTools.Translations.language_string(key, :de) "Sammler" iex> WarframeWorldstateDataElixirTools.Translations.language_string("") "[PH] value" iex> WarframeWorldstateDataElixirTools.Translations.language_string("SomeUnknownKey") "Some Unknown Key" """ def language_string(key, locale \\ :en) def language_string("", _) do "[PH] value" end def language_string(key, locale) when is_binary(key) and is_atom(locale) do case search_languages(key, "value", locale) do {:error, _} -> key |> last_resource_name() |> split_resource_name() |> string_to_title() value -> value end end @doc """ Gets the localized description for a given languages.json key. ## Examples iex> key = "/lotus/types/challenges/seasons/daily/seasondailycollecthundredresources" iex> WarframeWorldstateDataElixirTools.Translations.language_desc(key) "Collect 1,500 Resources" iex> key = "/lotus/types/challenges/seasons/daily/seasondailycollecthundredresources" iex> WarframeWorldstateDataElixirTools.Translations.language_desc(key, :de) "Sammle 1.500 Ressourcen" iex> WarframeWorldstateDataElixirTools.Translations.language_desc("") "[PH] Description" iex> WarframeWorldstateDataElixirTools.Translations.language_desc("SomeUnknownKey") "[PH] Some Unknown Key Description" """ def language_desc(key, locale \\ :en) def language_desc("", _) do "[PH] Description" end def language_desc(key, locale) when is_binary(key) and is_atom(locale) do case search_languages(key, "desc", locale) do {:error, _} -> res = key |> last_resource_name() |> split_resource_name() |> string_to_title() "[PH] #{res} Description" desc -> desc end end @doc """ Translates a faction key to its display name in the given locale. Falls back to the key itself if not found. ## Examples iex> WarframeWorldstateDataElixirTools.Translations.faction("FC_CORPUS") "Corpus" iex> WarframeWorldstateDataElixirTools.Translations.faction("FC_INFESTATION", :de) "Befallene" iex> WarframeWorldstateDataElixirTools.Translations.faction("FC_UNKNOWN") "FC_UNKNOWN" """ def faction(key, locale \\ :en) when is_binary(key) and is_atom(locale) do case search_factions(key, locale) do {:ok, faction} -> faction _ -> key end end @doc """ Returns the display name of a sortie boss for the given key and locale. Falls back to the key itself if not found. ## Examples iex> WarframeWorldstateDataElixirTools.Translations.sortie_boss("SORTIE_BOSS_HYENA") "Hyena Pack" iex> WarframeWorldstateDataElixirTools.Translations.sortie_boss("SORTIE_BOSS_UNKNOWN") "SORTIE_BOSS_UNKNOWN" """ def sortie_boss(key, locale \\ :en) when is_binary(key) and is_atom(locale) do case find_sortie("bosses", key, locale) do {:ok, %{"name" => name}} -> name _ -> key end end @doc """ Returns the faction of a sortie boss for the given key and locale. Falls back to the key itself if not found. ## Examples iex> WarframeWorldstateDataElixirTools.Translations.sortie_faction("SORTIE_BOSS_HYENA") "Corpus" iex> WarframeWorldstateDataElixirTools.Translations.sortie_faction("SORTIE_BOSS_UNKNOWN") "SORTIE_BOSS_UNKNOWN" """ def sortie_faction(key, locale \\ :en) when is_binary(key) and is_atom(locale) do case find_sortie("bosses", key, locale) do {:ok, %{"faction" => faction}} -> faction _ -> key end end @doc """ Returns the display name of a sortie modifier type for the given key and locale. Falls back to the key itself if not found. ## Examples iex> WarframeWorldstateDataElixirTools.Translations.sortie_modifier("SORTIE_MODIFIER_LOW_ENERGY") "Energy Reduction" iex> WarframeWorldstateDataElixirTools.Translations.sortie_modifier("SORTIE_MODIFIER_LOW_ENERGY", :de) "reduzierte Energie" iex> WarframeWorldstateDataElixirTools.Translations.sortie_modifier("SORTIE_MODIFIER_UNKNOWN") "SORTIE_MODIFIER_UNKNOWN" """ def sortie_modifier(key, locale \\ :en) when is_binary(key) and is_atom(locale) do case find_sortie("modifierTypes", key, locale) do {:ok, modifier} -> modifier _ -> key end end @doc """ Returns the description of a sortie modifier for the given key and locale. Falls back to the key itself if not found. ## Examples iex> WarframeWorldstateDataElixirTools.Translations.sortie_modifier_description("SORTIE_MODIFIER_LOW_ENERGY") "Maximum Warframe Energy capacity is quartered. Energy Siphon is less effective." iex> WarframeWorldstateDataElixirTools.Translations.sortie_modifier_description("SORTIE_MODIFIER_UNKNOWN") "SORTIE_MODIFIER_UNKNOWN" """ def sortie_modifier_description(key, locale \\ :en) when is_binary(key) and is_atom(locale) do case find_sortie("modifierDescriptions", key, locale) do {:ok, description} -> description _ -> key end end @doc """ Returns the display name of an Archon Shard for the given color key and locale. Falls back to the color key itself if not found. ## Examples iex> WarframeWorldstateDataElixirTools.Translations.archon_shard_color("ACC_BLUE") "Azure" iex> WarframeWorldstateDataElixirTools.Translations.archon_shard_color("ACC_UNKNOWN") "ACC_UNKNOWN" """ def archon_shard_color(color, locale \\ :en) when is_binary(color) and is_atom(locale) do case archon_shard(color, locale) do {:ok, %{"value" => shard_color}} -> shard_color _ -> color end end @doc """ Returns the translated effect of an Archon Shard upgrade type. Falls back to the last path segment of the upgrade_type key if not found. ## Examples iex> WarframeWorldstateDataElixirTools.Translations.archon_shard_upgrade_type("ACC_BLUE", "/Lotus/Upgrades/Invigorations/ArchonCrystalUpgrades/ArchonCrystalUpgradeWarframeHealthMax") "+150% Health" iex> WarframeWorldstateDataElixirTools.Translations.archon_shard_upgrade_type("ACC_BLUE", "/Lotus/Upgrades/Invigorations/ArchonCrystalUpgrades/ArchonCrystalUpgradeUnknown") "ArchonCrystalUpgradeUnknown" iex> WarframeWorldstateDataElixirTools.Translations.archon_shard_upgrade_type("ACC_UNKNOWN", "/Lotus/Upgrades/Invigorations/ArchonCrystalUpgrades/ArchonCrystalUpgradeWarframeHealthMax") "ArchonCrystalUpgradeWarframeHealthMax" """ def archon_shard_upgrade_type(color, upgrade_type, locale \\ :en) when is_binary(color) and is_binary(upgrade_type) and is_atom(locale) do case archon_shard(color, locale) do {:ok, %{"upgradeTypes" => %{^upgrade_type => %{"value" => shard_upgrade_type}}}} -> shard_upgrade_type _ -> last_resource_name(upgrade_type) end end @doc """ Translates a focus school key to its display name. ## Examples iex> WarframeWorldstateDataElixirTools.Translations.translate_focus("Focus/Attack") "Madurai" iex> WarframeWorldstateDataElixirTools.Translations.translate_focus("Unknown") "None" """ def translate_focus(focus) when is_binary(focus) do map_value(focus, @focus_map) end @doc """ Translates a polarity code to its display name. ## Examples iex> WarframeWorldstateDataElixirTools.Translations.translate_polarity("AP_ATTACK") "Madurai" iex> WarframeWorldstateDataElixirTools.Translations.translate_polarity("Unknown") "None" """ def translate_polarity(polarity) when is_binary(polarity) do map_value(polarity, @polarity_map) end @doc """ Translates a calendar event code to its display name. ## Examples iex> WarframeWorldstateDataElixirTools.Translations.translate_calendar_event("CET_CHALLENGE") "To Do" iex> WarframeWorldstateDataElixirTools.Translations.translate_calendar_event("Unknown") "None" """ def translate_calendar_event(event) when is_binary(event) do map_value(event, @calendar_event_map) end @doc """ Strips the "CST_" prefix from a season string. ## Examples iex> WarframeWorldstateDataElixirTools.Translations.translate_season("CST_SPRING") "SPRING" iex> WarframeWorldstateDataElixirTools.Translations.translate_season("SUMMER") "SUMMER" """ def translate_season(season) when is_binary(season) do String.replace(season, "CST_", "") end @doc """ Translates an Archimedea type code to its display name. ## Examples iex> WarframeWorldstateDataElixirTools.Translations.translate_archemedia_type("CT_LAB") "Deep Archimedea" iex> WarframeWorldstateDataElixirTools.Translations.translate_archemedia_type("Unknown") "None" """ def translate_archemedia_type(type) when is_binary(type) do map_value(type, @archimedia_map) end @doc """ Returns a map containing translated steel path rewards. ## Examples iex> sp = WarframeWorldstateDataElixirTools.Translations.steel_path() iex> is_map(sp) true """ def steel_path(locale \\ :en) do case WarframeWorldstateDataElixirTools.DataBundle.read_data_file( @data_files.steel_path, locale ) do {:ok, sp} -> sp _ -> %{} end end @doc """ Returns the translated name of a syndicate. Falls back to the key itself if not found. ## Examples iex> WarframeWorldstateDataElixirTools.Translations.syndicate("ArbitersSyndicate", :en) "Arbiters of Hexis" iex> WarframeWorldstateDataElixirTools.Translations.syndicate("ArbitersSyndicateUnkown") "ArbitersSyndicateUnkown" """ def syndicate(key, locale \\ :en) when is_binary(key) and is_atom(locale) do case find_syndicate(key, locale) do {:ok, %{"name" => name}} -> name _ -> key end end @doc """ Returns the translated value of a global upgrade. Falls back to the key itself if not found. ## Examples iex> WarframeWorldstateDataElixirTools.Translations.upgrade("GAMEPLAY_MONEY_PICKUP_AMOUNT") "Credit Drop amount" iex> WarframeWorldstateDataElixirTools.Translations.upgrade("GAMEPLAY_MONEY_PICKUP_AMOUNT_UNKOWN") "GAMEPLAY_MONEY_PICKUP_AMOUNT_UNKOWN" """ def upgrade(key, locale \\ :en) when is_binary(key) and is_atom(locale) do case find_upgrade(key, locale) do {:ok, %{"value" => value}} -> value _ -> key end end defp find_upgrade(key, locale) do case WarframeWorldstateDataElixirTools.DataBundle.read_data_file( @data_files.upgrade_types, locale ) do {:ok, %{^key => upgrade}} -> {:ok, upgrade} _ -> {:error, :not_found} end end defp find_syndicate(key, locale) when is_binary(key) and is_atom(locale) do case WarframeWorldstateDataElixirTools.DataBundle.read_data_file( @data_files.syndicates_data, locale ) do {:ok, %{^key => syndicate}} -> {:ok, syndicate} _ -> {:error, :not_found} end end defp archon_shard(color, locale) do case WarframeWorldstateDataElixirTools.DataBundle.read_data_file( @data_files.archon_shards, locale ) do {:ok, %{^color => shard}} -> {:ok, shard} _ -> {:error, :not_found} end end defp search_factions(key, locale) do case WarframeWorldstateDataElixirTools.DataBundle.read_data_file( @data_files.factions_data, locale ) do {:ok, %{^key => %{"value" => value}}} -> {:ok, value} _ -> {:error, key} end end defp search_languages(key, field, locale) when is_binary(key) and is_binary(field) and is_atom(locale) do lower_case_key = String.downcase(key) with {:error, :not_found} <- find_language(lower_case_key, field, locale) do find_language(key, field, locale) end end defp fissure_modifier(key, field, locale) do case WarframeWorldstateDataElixirTools.DataBundle.read_data_file( @data_files.fissure_modifiers, locale ) do {:ok, %{^key => %{^field => field_value}}} -> {:ok, field_value} _ -> {:error, key} end end defp sol_node(node_key, field, locale) do case WarframeWorldstateDataElixirTools.DataBundle.read_data_file( @data_files.sol_nodes, locale ) do {:ok, %{^node_key => node}} -> {:ok, node[field]} {:ok, _} -> {:ok, last_resource_name(node_key)} {:error, _} = x -> x end end defp last_resource_name(res) when is_binary(res) do String.split(res, "/", trim: true) |> List.last() end defp string_to_title(str) when is_binary(str) do str |> String.split() |> Enum.map(&String.capitalize/1) |> Enum.join(" ") end defp split_resource_name(str) when is_binary(str) do splitter = ~r/([A-Z]+(?=[A-Z][a-z]))|([A-Z]?[a-z]+)/ splitter |> Regex.split(str, include_captures: true, trim: true) |> Enum.join(" ") end defp find_language(key, field, locale) do case WarframeWorldstateDataElixirTools.DataBundle.find_key( @data_files.languages, key, locale ) do {:ok, %{^field => value}} -> value _ -> {:error, :not_found} end end defp find_sortie(key, field, locale) do case WarframeWorldstateDataElixirTools.DataBundle.find_key( @data_files.sortie_data, key, locale ) do {:ok, %{^field => value}} -> {:ok, value} _ -> {:error, :not_found} end end defp map_value(key, map) do Map.keys(map) |> Enum.find_value("None", fn k -> String.contains?(key, k) && map[k] end) end end