Editing Module:Lang

Warning: You are not logged in. Once you make an edit, a temporary account will be created for you. Learn more. Log in or create an account to continue receiving notifications after this account expires, and to access other features.
The edit can be undone. Please check the comparison below to verify that this is what you want to do, and then publish the changes below to finish undoing the edit.
Latest revision Your text
Line 1: Line 1:
local p = {}
local p = {}
local util_module = require("Module:Utilities")
 
local lang_codes_set = mw.loadJsonData("Data:LangCodes.json")
-- Set of valid language codes
local dictionary_module = require("Module:Dictionary")
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
-- the expected key does not have a localization entry
-- the expected key does not have a localization entry
local KEY_OVERRIDES = {
local KEY_OVERRIDES = {
BurnDurationBase_label = 'AfterburnDurationBase_label',
BurnDurationBase_postfix = 'AfterburnDurationBase_postfix',
     MoveSlowPercent_label = 'MovementSlow_label',
     MoveSlowPercent_label = 'MovementSlow_label',
     BonusHealthRegen_label = 'HealthRegen_label',
     BonusHealthRegen_label = 'HealthRegen_label',
Line 19: Line 21:
     EvasionChance_label = 'EvasionChance_Label',
     EvasionChance_label = 'EvasionChance_Label',
     DelayBetweenShots_label = 'DelayBetweenShots_Label',
     DelayBetweenShots_label = 'DelayBetweenShots_Label',
    MoveSlowDuration_postfix = 'EnemyMoveSlowDuration_postfix',
    StaminaRecoveryDisabledDuration_postfix = 'AbilityDuration_postfix',
    PostInvisBuffDuration_label = 'BuffDuration_label',
    PostInvisBuffDuration_postfix = 'BuffDuration_postfix',
    ProjectileFuse_label = 'BellLifetime_label',
    ProjectileFuse_postfix = 'BellLifetime_postfix',
    SelfBuffDuration_label = 'BuffDuration_label',
    SelfBuffDuration_postfix = 'BuffDuration_postfix',
    LifeStealPercentOnHit_label = 'LifestealPercentOnHit_label',
    LifeStealPercentOnHit_postfix = 'LifestealPercentOnHit_postfix',
    AuraFireRateBonus_label = 'FireRateBonus_label',
    AuraFireRateBonus_postfix = 'FireRateBonus_postfix',
    MoveSlowDuration_label = 'SlowDuration_label',
    MoveSlowDuration_postfix = 'SlowDuration_postfix',
DashRange_label = 'TargetDashRadius_label',
DashRange_postfix = 'TargetDashRadius_postfix',
SpeedOnLandDuration_label = 'BuffDuration_label',
SpeedOnLandDuration_postfix = 'BuffDuration_postfix',
SummonCount_label = 'GhoulCount_label',
TetherDuration_label = 'ImmobilizeTrap_CurseDuration_label'
}
}


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


local function process_newlines(text)
-- Get a localized string by the raw key
    if not text or type(text) ~= "string" then return text end
p.get_string = function(frame)
    -- Replace "n with newline character
local key = frame.args[1]
    return text:gsub('"n', '<br/>')
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
end


local function process_html_tags(text, frame)
-- Get a localized string by the raw key, return fallback string if unable to be localized
    if not text or type(text) ~= "string" then return text end
p.get_string_fallback = function(frame)
   
local key = frame.args[1]
    local replacements = {
local fallback = frame.args[2]
    BonusFireRate = {icon='{{Icon/Brown|[[File:Fire_Rate.png|link=Fire Rate|20px]]}}', label_color='#ffefd7', link='Fire Rate'},
    BonusMoveSpeed = {icon='{{Icon/Green|[[File:Move_speed.png|link=Move speed|20px]]}}', label_color='#ffefd7', link='Move speed'},
     local lang_code = get_lang_code()
    BonusSprintSpeed = {icon='{{Icon/Green|[[File:Move_speed.png|link=Sprint speed|20px]]}}', label_color='#ffefd7', link='Sprint speed'},
    BonusSpiritDamage = {icon='{{Icon/NoColor|[[File:Spirit damage.png|link=Spirit Damage|20px]]}}', label_color='#bc8ee8', link='Spirit Damage'},
local data = get_lang_file(lang_code)
    BonusWeaponDamage = {icon='{{Icon/NoColor|[[File:Bullet Damage.png|link=Weapon Damage|20px]]}}', label_color='#ec981a', link='Weapon Damage'},
if (data == nil) then
    bullet_armor_up = {icon='{{Icon/White|[[File:Barrier.png|link=Barrier|20px]]}}', label_color='#ffefd7', link='Barrier'},
return string.format("Lang code '%s' does not have a json file", lang_code)
    bullet_damage = {icon='{{Icon/NoColor|[[File:Bullet_damage.png|link=Weapon Damage|20px]]}}', label_color='#ec981a', link='Weapon Damage'},
end
    BulletResist = {icon='{{Icon/Brown|[[File:Bullet_Armor.png|link=Damage_Resistance|20px]]}}', label_color='#ec981a', link='Damage_Resistance'},
    cast = {icon='{{Icon/White|[[File:Cast.png|link=|20px]]}}', label_color='#ffefd7', link=''},
local label = data[key]
    CombatBarrier = {icon='{{Icon/White|[[File:Bullet Armor (item).png|link=Damage_Resistance|20px]]}}', label_color='#ffefd7', link='Barrier'},
if (label == nil) then  
    cooldown = {icon='{{Icon/White|[[File:AttributeIconTechDuration.png|link=Ability Cooldown|20px]]}}', label_color='#ffefd7', link='Ability Cooldown'},
return fallback
    damage = {icon='{{Icon/NoColor|[[File:Damage heart.png|link=Damage|20px]]}}', label_color='#ec981a', link='Damage'},
end
    DamageAmp = {icon='{{Icon/White|[[File:Damage heart.png|link=Damage Amp|20px]]}}', label_color='#ffefd7', link='Damage Amp'},
    FireRate = {icon='{{Icon/White|[[File:Fire_Rate.png|link=Fire Rate|20px]]}}', label_color='#ffefd7', link='Fire Rate'},
    fire_rate = {icon='{{Icon/White|[[File:Fire_Rate.png|link=Fire Rate|20px]]}}', label_color='#ffefd7', link='Fire Rate'},
    Heal = {icon='{{Icon/Green|[[File:Healing.png|link=Health_Regen|20px]]}}', label_color='#13f278', link='Health_Regen'},
    Healing = {icon='{{Icon/Green|[[File:Healing.png|link=Healing|20px]]}}', label_color='#13f278', link='Healing'},
    Immobilize = {icon='{{Icon/White|[[File:Immobilize.png|link=Status Effects#Immobilized|20px]]}}', label_color='#ffefd7', link='Status Effects#Immobilized'},
    invisible = {icon='{{Icon/White|[[File:Invisible.png|link=|20px]]}}', label_color='#ffefd7', link=''},
    KnockBack = {icon='{{Icon/NoColor|[[File:Displacement.png|link=|20px]]}}', label_color='#ffefd7', link='Status_Effects'},
    KnockUp =  {icon='{{Icon/NoColor|[[File:Displacement.png|link=|20px]]}}', label_color='#ffefd7', link='Status_Effects'},
    MaxHealth = {icon='{{Icon/Green|[[File:Healing.png|link=Health|20px]]}}', label_color='#13f278', link='Health'},
    MeleeDamage = {icon='{{Icon/Brown|[[File:Melee damage.png|link=Melee Damage|20px]]}}', label_color='#ec981a', link='Melee Damage'},
    MoveSpeed = {icon='{{Icon/Green|[[File:Move_speed.png|link=Move speed|20px]]}}', label_color='#ffefd7', link='Move speed'},
    move_speed = {icon='{{Icon/Green|[[File:Move_speed.png|link=Move speed|20px]]}}', label_color='#ffefd7', link='Move speed'},
    Pull =      {icon='{{Icon/NoColor|[[File:Displacement.png|link=|20px]]}}', label_color='#ffefd7', link='Status_Effects'},
    Pulling =  {icon='{{Icon/NoColor|[[File:Displacement.png|link=|20px]]}}', label_color='#ffefd7', link='Status_Effects'},
    Pulls =    {icon='{{Icon/NoColor|[[File:Displacement.png|link=|20px]]}}', label_color='#ffefd7', link='Status_Effects'},
    PureDamage = {icon='{{Icon/NoColor|[[File:Damage.png|link=Pure Damage|20px]]}}', label_color='#ffefd7', link='Pure Damage'},
    ReducedFireRate = {icon='{{Icon/Brown|[[File:Fire_Rate.png|link=Fire Rate|20px]]}}', label_color='#ffefd7', link='Fire Rate'},
    Regen = {icon='{{Icon/Green|[[File:Healing.png|link=Health_Regen|20px]]}}', label_color='#13f278', link='Health_Regen'},
    revealed = {icon='{{Icon/White|[[File:Revealed.png|link=|20px]]}}', label_color='#ffefd7', link=''},
    silence = {icon='{{Icon/White|[[File:Silence.png|link=|20px]]}}', label_color='#ffefd7', link=''},
    Silence = {icon='{{Icon/Purple|[[File:Silence.png|link=Silence|20px]]}}', label_color='#bc8ee8', link='Silence'},
    Slow = {icon='{{Icon/White|[[File:MoveSlow.png|link=Movement_Slow|20px]]}}', label_color='#ffefd7', link='Movement_Slow'},
    slow = {icon='{{Icon/White|[[File:MoveSlow.png|link=Movement_Slow|20px]]}}', label_color='#ffefd7', link='Movement_Slow'},
    SlowResistance = {icon='{{Icon/White|[[File:MoveSlow.png|link=Movement_Slow#Movement_Slow_Resist|20px]]}}', label_color='#ffefd7', link='Movement_Slow#Movement_Slow_Resist'},
    Spirit = {icon='{{Icon/NoColor|[[File:Spirit_icon.png|link=Spirit Power|20px]]}}', label_color='#bc8ee8', link='Spirit Power'},
    SpiritDamage = {icon='{{Icon/NoColor|[[File:Spirit damage.png|link=Spirit Damage|20px]]}}', label_color='#bc8ee8', link='Spirit Damage'},
    SpiritDPS = {icon='{{Icon/NoColor|[[File:Spirit damage.png|link=Spirit Damage|20px]]}}', label_color='#bc8ee8', link='Spirit Damage'},
    SpiritIcon = {icon='{{Icon/NoColor|[[File:Spirit damage.png|link=Spirit Damage|20px]]}}', link='Spirit Damage'},
    SpiritResist = {icon='{{Icon/Purple|[[File:Spirit_Armor.png|link=Damage_Resistance|20px]]}}', label_color='#bc8ee8', link='Damage_Resistance'},
    StatDesc_TechPower = {icon='{{Icon/NoColor|[[File:Spirit damage.png|link=Spirit Damage|20px]]}}', label_color='#bc8ee8', link='Spirit Damage'},
    Stun = {icon='{{Icon/White|[[File:Status_Stun.png|link=Stun|20px]]}}', link='Stun'},
    stun = {icon='{{Icon/White|[[File:Stun.png|link=|20px]]}}', label_color='#ffefd7', link=''},
    tech_armor_up = {icon='{{Icon/White|[[File:Barrier.png|link=Barrier|20px]]}}', label_color='#ffefd7', link='Barrier'},
    tech_damage = {icon='{{Icon/NoColor|[[File:Spirit damage.png|link=Spirit Damage|20px]]}}', link='Spirit Damage'},
    WeaponDamage = {icon='{{Icon/NoColor|[[File:Bullet Damage.png|link=Weapon Damage|20px]]}}', label_color='#ec981a', link='Weapon Damage'},
    Heal = {icon='{{Icon/Green|[[File:Healing.png|link=Healing|20px]]}}', label_color='#13f278', link='Healing'},
    Heals = {icon='{{Icon/Green|[[File:Healing.png|link=Healing|20px]]}}', label_color='#13f278', link='Healing'},
}
 
    -- Process HTML spans
    text = text:gsub('<span class="highlight">(.-)</span>', "<span style= font-weight:bold>%1</span>")
    text = text:gsub('<span class="highlight_spirit">(.-)</span>', '<span style="font-weight:bold; color:#bc8ee8">%1</span>')
    text = text:gsub('<span class="highlight_courage">(.-)</span>', '<span style="font-weight:bold; color:#ec981a">%1</span>')
    text = text:gsub('<span class="diminish">(.-)</span>', '<span style="font-style: italic;color:#C0C0C0">%1</span>')
    text = text:gsub('<span class=".-">(.-)</span>', '%1')
    text = text:gsub('<Panel class=\"AbilityPropertyIcon StatDesc_TechPower\">', '{{Icon/Purple|[[File:Spirit damage.png|link=Spirit Damage|20px]]}}')
    text = text:gsub('</Panel>', '')
   
    -- Process panel tags
text = text:gsub('<Panel class=\"AbilityPropertyIcon prop_(.-)\">', function(key)
    local replacement = replacements[key]
    if replacement then
        local label_color = replacement.label_color or 'inherit'
        local icon = replacement.icon or ''
        local link = replacement.link or ''
        -- pre-process string, then check to omit link if the string is empty
        local translated = frame:preprocess('{{#invoke:Lang|get_string|InlineAttribute_' .. key .. '}}')
       
        if translated == '' then
            return string.format('<span class="no-blue-link" style="text-wrap:nowrap; font-weight:bold; color:%s;">%s</span>', label_color, icon)
        else
            return string.format('<span class="no-blue-link" style="text-wrap:nowrap; font-weight:bold; color:%s;">%s [[%s|%s]]</span>',
                label_color,
                icon,
                link,
                translated)
        end
    else
        return '<span style="color:red;font-weight:bold;border-bottom:1px dotted red;" title="Missing attribute definition - Add \''..key..'\' to local replacements in [Module:Lang]">['..key..']</span>'
    end
end)
   
     -- Process citadel_inline_attribute tags
text = text:gsub("{g:citadel_inline_attribute:'(.-)'}", function(key)
    local replacement = replacements[key]
    if replacement then
        local label_color = replacement.label_color or 'inherit'
        local icon = replacement.icon or ''
        local link = replacement.link or ''
        -- pre-process string, then check to omit link if the string is empty
        local translated = frame:preprocess('{{#invoke:Lang|get_string|InlineAttribute_' .. key .. '}}')
       
        if translated == '' then
            return string.format('<span class="no-blue-link" style="text-wrap:nowrap; font-weight:bold; color:%s;">%s</span>', label_color, icon)
        else
            return string.format('<span class="no-blue-link" style="text-wrap:nowrap; font-weight:bold; color:%s;">%s [[%s|%s]]</span>',
                label_color,
                icon,  
                link,
                translated)
        end
    else
        return '<span style="color:red;font-weight:bold;border-bottom:1px dotted red;" title="Missing attribute definition - Add \''..key..'\' to local replacements in [Module:Lang]">['..key..']</span>'
    end
end)
   
    -- List for keybinds with mismatched names. Replace with the correct name under "citadel_keybind_[key]" in Data:Lang
    keybinds = {
        MoveForward = "forward",
        AltCast = "alt_cast",
        }
   
    -- Process citadel_binding/citadel_keybind tags to replace with keybind strings/templates
text = text:gsub("{g:citadel_binding:'(.-)'}", function(key)
  -- convert key to lowercase
        local lower_key = key:lower()
        -- look up key with Module:Lang. check if it has a replacement key first
        local replacement = keybinds[key] or lower_key
        local translated = frame:preprocess('{{#invoke:Lang|get_string|citadel_keybind_'.. replacement ..'}}')
  if translated ~= nil and translated ~= '' then
        return "'''" .. translated .. "'''"
        else
            return '<span style="color:red;font-weight:bold;border-bottom:1px dotted red;" title="Missing keybind - Add \''..key..'\' to local replacements in [Module:Lang]">['..key..']</span>'
        end
end)
    -- Force spaces around keybinds where the source data omits them
return label
    text = text:gsub("'''([a-zA-Z])", "''' %1")
end


    -- Clean up extra spaces between a keybind and following punctuation
-- get_string, but for internal use by other modules
    text = text:gsub("'''%s+:", "''':")
p._get_string = function(key, lang_override)
lang_code = get_lang_code()


return frame:preprocess(text)
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
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]


function p.get_string(key, lang_code_override, fallback_str, remove_var_index, item_name)
local lang_code = lang_code_override
    -- Get frame object (either passed directly or via first argument)
if (lang_code == '' or lang_code == nil) then
    local frame
    lang_code = get_lang_code()
    if type(key) == "table" and key.args then
end
        frame = type(key.preprocess) == "function" and key or mw.getCurrentFrame()
       
-- Load the language files
        local args = key.args
local data_en = get_lang_file('en')  -- English data
        key = args[1]
local data_lang = get_lang_file(lang_code) -- Target language data
        lang_code_override = args["lang_code_override"]
        fallback_str = args["fallback_str"]
        remove_var_index = args["remove_var_index"]
        item_name = args["item_name"]
    else
        frame = mw.getCurrentFrame()
    end


    -- Determine lang_code if not overridden
if (data_lang == nil) then
    local lang_code = lang_code_override
return string.format("Lang code '%s' does not have a json file", lang_code)
    if (lang_code == '' or lang_code == nil) then
end
        lang_code = p.get_lang_code()
    end
-- Search for the key in the English data
 
local key = nil
    -- Retrieve lang data
for k, v in pairs(data_en) do
    local data = get_lang_file(lang_code)
if v == label then
    if (data == nil) then
key = k  -- Find the key corresponding to the label
        return string.format("Lang code '%s' does not have a json file", lang_code)  
break
    end
end
   
end
    -- Localize
    local label = data[KEY_OVERRIDES[key] or key]


-- Some labels use key with "_postvalue_label" instead, so check this if previous search failed
if (key == nil) then
if label == nil and key ~= nil and key:sub(-6) == '_label' then
return string.format("English label '%s' not found", label)
    local postvalue_key = key:sub(1, -7) .. '_postvalue_label'
    label = data[postvalue_key]
end
end
    if (label == nil) then
if (data_lang[key] == nil) then
        -- Apply fallback (without HTML processing for fallback)
return string.format("Key '%s' not found in for lang code '%s'", key, lang_code)
        local fallback_tooltip = frame:expandTemplate{title = "MissingValveTranslationTooltip"}
end
        local fallback
        if (fallback_str == 'en') then
            fallback = p.get_string(key, 'en', key .. fallback_tooltip, remove_var_index, item_name)
        elseif fallback_str == 'dictionary' then
            return dictionary_module.translate(key, lang_code_override)
        elseif fallback_str ~= nil then
            fallback = fallback_str
        else
            return ''
        end
        return fallback .. fallback_tooltip
    end
   
    -- Always retrieve the last parameter if string contains "|"
    if type(label) == "string" and label:find("|") then
        local parts = mw.text.split(label, "|")
        label = parts[#parts]
    end
   
  -- Remove hashtags
  if type(label) == "string" and label:find("#") then
        local parts = mw.text.split(label, "#")
        label = parts[#parts]
    end
 
    -- Apply remove_var
    if (remove_var_index ~= nil) then
        label = util_module.remove_var(label, remove_var_index)
    end
   
    -- Process variables if item_name is provided
    if item_name and item_name ~= '' then
        local item_data_module = require('Module:ItemData')
        label = label:gsub("{s:([^}]+)}", function(variable_name)
            -- Get the value from ItemData
            local value = item_data_module.get_prop({args = {item_name, variable_name}})
           
            -- If value exists, remove non-number symbols (but keep + and -)
            if value then
                value = value:gsub("[^0-9+-.]", "")
                -- Return empty string if nothing left, otherwise return the filtered value
                return value ~= "" and value or variable_name
            else
                return variable_name -- Fallback to variable name if value not found
            end
        end)
    end
   
    -- Process HTML and return as "raw" HTML
    label = process_newlines(label)
    label = process_html_tags(label, frame)
    -- Create HTML object for safe output
    local html = mw.html.create()
    html:wikitext(label)
    return tostring(html)
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 result = p._search_string(label, lang_code_override)
return data_lang[key]
    result = process_newlines(result)
    return result
end
end


-- search_string, but for internal use by other modules
-- search_string, but for internal use by other modules
p._search_string = function(label, lang_code_override)
p._search_string = function(label)
    lang_code = lang_code_override
lang_code = get_lang_code()
    if (lang_code == '' or lang_code == nil) then
        lang_code = p.get_lang_code()
    end


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


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


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


    return data_lang[key]
return data_lang[key]
end
end


p.get_lang_code = function()
function get_lang_code()
     local title = mw.title.getCurrentTitle()
     local title = mw.title.getCurrentTitle()
     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 (lang_code == nil or lang_codes_set[lang_code]) == nil then
        return 'en'  
return 'en'
    end
end
       
     return lang_code
     return lang_code
end
end


return p
return p
Please note that all contributions to The Deadlock Wiki are considered to be released under the Creative Commons Attribution-NonCommercial-ShareAlike (see Deadlock:Copyrights for details). If you do not want your writing to be edited mercilessly and redistributed at will, then do not submit it here.
You are also promising us that you wrote this yourself, or copied it from a public domain or similar free resource. Do not submit copyrighted work without permission!
Cancel Editing help (opens in new window)
Preview page with this template