-
Notifications
You must be signed in to change notification settings - Fork 0
Localization
Localization.lua: a plain-table fallback lookup, and native ESO string-ID registration for addons that want the engine-native approach. Two different weights of the same job; pick whichever fits.
The simple option: a pure lookup function, no engine registration at all.
Chain: override language → client language (as resolved by the caller into langCode) → English → the raw key itself (so a typo'd key shows as the key instead of erroring). Extra varargs go through string.format.
function MyAddon.L(key, ...)
local lang_code = MyAddon.settings.override_language or GetCVar("Language.2")
return LibAPH.Localize(MyAddon.Lang, lang_code, key, ...)
endlangTable is your own {code -> {key -> string}} table, populated by your own lang/*.lua files: this function never touches those files, just the fallback chain over whatever you hand it.
Registers strings into ESO's native ZO_CreateStringId/SafeAddString/GetString() system, instead of the plain lookup table Localize above uses.
The collision problem this solves: ZO_CreateStringId(name, value) creates a global Lua variable, shared across every addon in the whole game session. Two unrelated addons' language files commonly reuse the same generic key name, like FIELD_WIZARD or BTN_CLOSE. Say MyAddon1 and MyAddon2 both ship a BTN_CLOSE key: feeding either raw table straight into the string-ID system unprefixed means whichever addon registers second silently overwrites the first one's text for that key. addonPrefix ("SI_MYADDON1_", "SI_MYADDON2_") is mandatory specifically to prevent this, since prefixing turns one shared global into two separate ones before registration ever happens.
Mechanism: prefers the separately-installed LibLanguage library if present (declared OptionalDependsOn, not required). Its SafeAddString wrapper works around a ZOS engine quirk where SafeAddString's own version-protection isn't reliably enforced. Falls back to registering directly via ZO_CreateStringId/SafeAddString if LibLanguage isn't installed, so this never hard-requires it.
overrideLang is a third registration pass, for a player-chosen language that isn't necessarily their client's own (an in-menu Language dropdown letting a player pick any contributed language regardless of client language), registered at version 3, above the default (1) and client-detected (2) passes, so it wins over both.
-- your own L() wrapper, called by every existing call site unchanged:
function MyAddon.L(key, ...)
local id = _G["SI_MYADDON_" .. key]
local str = id and GetString(id) or key
if select("#", ...) > 0 then return string.format(str, ...) end
return str
end
-- once, in init() after MyAddon.settings exists:
LibAPH.LoadLocalization("SI_MYADDON_", MyAddon.Lang, "en", MyAddon.settings.override_language)Note: this doesn't require the $(language) manifest-token pattern (loading only the client's matching language file): both addons deliberately load every lang/*.lua file unconditionally instead, because a $(language)-gated manifest only ever loads one language's table, which breaks a manual override dropdown that needs every language available to switch into.
Returns a ready-made LAM2 control list: a "current language" description, plus a dropdown and (gamepad only) an Apply button to override the client-detected language.
opts: L (your localize function), settings, addonPrefix, langTable, getAvailableLanguages, getLanguageDisplayName, formatCurrentLanguageText, isPad, reference, getPending/setPending (gamepad's pending-choice state).
local controls = LibAPH.BuildLanguagePickerControls({
L = MyAddon.L,
settings = MyAddon.settings,
addonPrefix = "SI_MYADDON_",
langTable = MyAddon.Lang,
getAvailableLanguages = MyAddon.get_available_languages,
getLanguageDisplayName = MyAddon.get_language_display_name,
formatCurrentLanguageText = MyAddon.format_current_language_text,
isPad = IsInGamepadPreferredMode(),
})
for _, c in ipairs(controls) do build_data[#build_data + 1] = c end