Module:Lang: Difference between revisions

From The Deadlock Wiki
Jump to navigation Jump to search
Added support for lang codes longer than 2 characters
m Undo revision 10297 by Saag (talk)
Tag: Undo
Line 1: Line 1:
local p = {}
local p = {}
-- Set of valid language codes
local lang_codes_set = {
en = true,
es = true,
['zh-hant'] = true
}


-- Overrides applied to searches by key. Designed to handle edge cases where
-- Overrides applied to searches by key. Designed to handle edge cases where
Line 167: Line 160:
     local lang_code = title.fullText:match(".*/(.*)$")
     local lang_code = title.fullText:match(".*/(.*)$")
if (lang_code == nil or lang_codes_set[lang_code]) == nil then
-- if the last part the url is not two letters, then its not a lang code,
-- so default to english
if (lang_code == nil or string.len(lang_code) ~= 2) then
return 'en'
return 'en'
end
end

Revision as of 10:02, 10 October 2024

Overview

This module serves as the primary interface for retrieving and formatting localized game text from the Data:Lang_*.json files. It handles variable substitution by fetching data from Module:ItemData, automatically applies rich text formatting for game-specific keywords (adding icons, colors, and links), and provides robust fallback mechanisms for missing translations.

Functions

get_string

Localizes a given string key to the current language, i.e. Data:Lang_en.json for English. This function also automatically processes game-specific formatting tags (see "Automatic Text Formatting" section below).

Note: If you need to get a string that uses a value referenced from another Data page, pass the item_name parameter to get_string.

Parameters

  • key - Key string to localize.
  • lang_code_override (OPTIONAL) - Overrides the current language to a specific language code.
  • fallback_str (OPTIONAL) - Specifies behavior when a key is not found in the target language.
    • Passing en causes it to return the English localization.
    • Passing any other string causes it to return that string.
    • Both of the above options have Template:MissingValveTranslationTooltip appended.
    • Passing dictionary causes it to return a translation via Module:Dictionary without the tooltip.
    • Use this often, as some keys are not yet localized in every language by the game. If parsing the fallback_str from Lua is computationally expensive, consider using the fallback outside this function so it only computes when needed.
  • remove_var_index (OPTIONAL) - Removes %variables% from the resulting string. -1 also removes the character prefixing %variables%, while 1 removes the postfixed character, and 0 removes only the %variables%.
  • item_name (OPTIONAL) - Required for strings containing {s:variable} placeholders. It will fetch the corresponding property from Module:ItemData to fill in the variable.

NOTE: When calling from wikitext via #invoke, parameters can be named. When calling from another Lua module, parameters must be passed in order (e.g., p.get_string(key, nil, 'en')).

Internal Logic & Fallbacks

The function includes several automatic behaviors to handle inconsistencies in the source data:

  • Key Overrides: It checks a hardcoded list of overrides for known edge cases. For example, if the key MoveSlowPercent_label is requested, the module will internally use the value for MovementSlow_label to handle this known inconsistency.
  • Post-value Label Fallback: If a key ending in _label is not found, it will automatically try again with a key ending in _postvalue_label.
  • String Parsing: If a retrieved string contains | or #, the function will automatically use only the text that comes after the final instance of that character.

Examples

Invokes from wikitext:

{{#invoke:Lang|get_string|CitadelHeroStats_Weapon_Falloff}}

Falloff Range


{{#invoke:Lang|get_string|CitadelHeroStats_Weapon_Falloff|lang_code_override=es}}

Falloff Range

Strings with Variables

For strings containing {s:variable}, provide the item_name:

Example: {{#invoke:Lang|get_string|upgrade_target_stun_desc|item_name=Knockdown}} → Apply a Stun after {s:StunDelay}s. Stun duration is increased against airborne targets.

Increases the target's gravity for the duration of the stun.

Without item_name, variables won't be filled: {{#invoke:Lang|get_string|upgrade_target_stun_desc}} → Apply a Stun after {s:StunDelay}s. Stun duration is increased against airborne targets.

Increases the target's gravity for the duration of the stun.


Examples for fallback_str

{{#invoke:Lang|get_string|StatDesc_CritDamageBonusScale|lang_code_override=es}}

Crit Bonus Scale


{{#invoke:Lang|get_string|StatDesc_CritDamageBonusScale|lang_code_override=es|fallback_str=en}}

Crit Bonus Scale


{{#invoke:Lang|get_string|StatDesc_CritDamageBonusScale|lang_code_override=es|fallback_str=Crit Damage Bonus Scale}}

Crit Bonus Scale


{{#invoke:Lang|get_string|Tech Items|fallback_str=dictionary}}


Examples for remove_var_index

{{#invoke:Lang|get_string|Citadel_HeroBuilds_DefaultHeroBuild}}

Default %hero_name% Build

TODO: Debug why is =0 still removing that extra space? Doesn't matter yet I suppose, no use cases for 0 yet {{#invoke:Lang|get_string|Citadel_HeroBuilds_DefaultHeroBuild|remove_var_index=0}}

Default %hero_name% Build


{{#invoke:Lang|get_string|Citadel_HeroBuilds_DefaultHeroBuild|remove_var_index=-1}}

Default %hero_name% Build

Automatic Text Formatting

When a string is retrieved by get_string, it undergoes several automatic transformations to convert in-game formatting tags into rich wikitext.

  • Newlines: "n is converted to a line break (
    ).
  • HTML Spans: Tags like ... are converted into styled text (e.g., bolded and colored purple).
  • Game Attribute Icons: Special tags like <Panel class="AbilityPropertyIcon prop_cooldown"> or {g:citadel_inline_attribute:'SpiritDamage'} are replaced with formatted wikitext that includes an icon, a colored label, and a wiki link. If a keyword is not recognized, it will be highlighted in red.
  • Keybinds: Tags like {g:citadel_binding:'Ability1'} are replaced with their respective text string (e.g., Ability 1). A replacement can be added to the list in case of tags that don't match their string name (e.g. AltCast > alt_cast). The module also cleans up spacing around these replacements for better readability. (Note: If we want to add additional text to the string like "[Ability] button" this needs to be supported by localizations)

search_string

Searches for the unlocalized key corresponding to a given English string, then localizes it to the current language. NOTE: Use sparingly. This function is much slower than get_string and should be avoided when the key is known. For use in other Lua modules, see _search_string.

Parameters

  • string - English string to search for.
  • lang_code_override (OPTIONAL) - Overrides the current language to a specific language code.

Examples

From wikitext:

{{#invoke:Lang|search_string|Abrams}}

Abrams

_search_string

This is the internal version of search_string, intended for use by other Lua modules. It provides the core search logic without the wikitext frame overhead or final text processing.

NOTE: This function returns the raw localized string. Unlike the invoked search_string, it does not process newlines ("n). The calling module is responsible for any further processing.

Parameters

  • label (string) - The English string to search for.
  • lang_code_override (string, optional) - The language code to translate to.

Example (from another Lua module)

local lang_module = require("Module:Lang")
-- Searches for the Spanish localization of the string "Abrams"
local localized_name = lang_module._search_string("Abrams", "es")

get_lang_code

Outputs the language subpage of the current page (e.g., "en", "es"). Defaults to "en" if the page is not a language subpage.

{{#invoke:Lang|get_lang_code}}

Script error: The function "get_lang_code" does not exist.


local p = {}

-- Overrides applied to searches by key. Designed to handle edge cases where
-- the expected key does not have a localization entry
local KEY_OVERRIDES = {
    MoveSlowPercent_label = 'MovementSlow_label',
    BonusHealthRegen_label = 'HealthRegen_label',
    BarbedWireRadius_label = 'Radius_label',
    BarbedWireDamagePerMeter_label = 'DamagePerMeter_label',
    BuildUpDuration_label = 'BuildupDuration_label',
    TechArmorDamageReduction_label = 'TechArmorDamageReduction_Label',
    DamageAbsorb_label = 'DamageAbsorb_Label',
    InvisRegen_label = 'InvisRegen_Label',
    EvasionChance_label = 'EvasionChance_Label',
    DelayBetweenShots_label = 'DelayBetweenShots_Label',
}

function get_lang_file(lang_code)
	local file_name = string.format("Data:Lang_%s.json", lang_code)
    local success, data = pcall(mw.loadJsonData, file_name)
    if success then
        return data
    else
        return nil
    end
end

-- Get a localized string by the raw key
p.get_string = function(frame)
	local key = frame.args[1]
	local lang_code_override = frame.args[2]

	local lang_code = lang_code_override
	if (lang_code == '' or lang_code == nil) then
    	lang_code = get_lang_code()
	end

	local data = get_lang_file(lang_code)
	if (data == nil) then
		return string.format("Lang code '%s' does not have a json file", lang_code)	
	end
	
	local label = data[KEY_OVERRIDES[key] or key]
	if (label == nil) then 
		return ''
	end
	
	return label
end

-- Get a localized string by the raw key, return fallback string if unable to be localized
p.get_string_fallback = function(frame)
	local key = frame.args[1]
	local fallback = frame.args[2]
	
    local lang_code = get_lang_code()
	
	local data = get_lang_file(lang_code)
	if (data == nil) then
		return string.format("Lang code '%s' does not have a json file", lang_code)	
	end
	
	local label = data[key]
	if (label == nil) then 
		return fallback
	end
	
	return label
end

-- get_string, but for internal use by other modules
p._get_string = function(key, lang_override)
	lang_code = get_lang_code()

	local data = get_lang_file(lang_override or lang_code)
	if (data == nil) then
		return nil
	end
	
	local label = data[KEY_OVERRIDES[key] or key]
	if (label == nil) then 
		return nil
	end
	
	return label
end

-- Search for a localized string using its English label
p.search_string = function(frame)
	local label = frame.args[1]
	local lang_code_override = frame.args[2]

	local lang_code = lang_code_override
	if (lang_code == '' or lang_code == nil) then
    	lang_code = get_lang_code()
	end
	
	-- Load the language files
	local data_en = get_lang_file('en')  -- English data
	local data_lang = get_lang_file(lang_code)  -- Target language data

	if (data_lang == nil) then
		return string.format("Lang code '%s' does not have a json file", lang_code)	
	end
	
	-- Search for the key in the English data
	local key = nil
	for k, v in pairs(data_en) do
		if v == label then
			key = k  -- Find the key corresponding to the label
			break
		end
	end

	if (key == nil) then
		return string.format("English label '%s' not found", label)
	end
	
	if (data_lang[key] == nil) then
		return string.format("Key '%s' not found in for lang code '%s'", key, lang_code)
	end

	return data_lang[key]
end

-- search_string, but for internal use by other modules
p._search_string = function(label)
	lang_code = get_lang_code()

	-- Load the language files
	local data_en = get_lang_file('en')  -- English data
	local data_lang = get_lang_file(lang_code)  -- Target language data

	if (data_lang == nil) then
		return string.format("Lang code '%s' does not have a json file", lang_code)	
	end
	
	-- Search for the key in the English data
	local key = nil
	for k, v in pairs(data_en) do
		if v == label then
			key = k  -- Find the key corresponding to the label
			break
		end
	end

	if (key == nil) then
		return string.format("English label '%s' not found", label)
	end
	
	if (data_lang[key] == nil) then
		return string.format("Key '%s' not found in for lang code '%s'", key, lang_code)
	end

	return data_lang[key]
end

function get_lang_code()
    local title = mw.title.getCurrentTitle()
    local lang_code = title.fullText:match(".*/(.*)$")
	
	-- if the last part the url is not two letters, then its not a lang code,
	-- so default to english
	if (lang_code == nil or string.len(lang_code) ~= 2) then
		return 'en'	
	end
		
    return lang_code
end

return p