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