Localization - Ruin0x11/OpenNefia GitHub Wiki
OpenNefia has support for localization in (hopefully) any arbitrary language. This would allow Elona to be played in languages besides English and Japanese. This page walks you through how the localization system works.
Locale Files
Each mod can contain a special folder named locale, which holds localized text for different languages. Each folder in locale contains folders named with a language code like en or jp, and each folder contains Lua files with the localized text. On startup, the files in the locale folder corresponding to the current language are loaded.
locale
├── en
│ ├── chara.lua
│ └── ui.lua
└── jp
├── chara.lua
└── ui.lua
Here is the format of the Lua scripts in locale:
return {
ui = {
menu = {
name = "My Menu",
ok = "Ok",
cancel = "Cancel",
},
-- parameterized string
prompt = function(_1, _2)
return ("%s %s looking for %s.")
:format(he(_1), is(_1), itemname(_2))
end,
-- randomly chosen
sounds = { "*clink*", "*smash*", "*thud*" },
}
}
These scripts should return a single table containing the localized data. The leaf values of the table can be one of the following:
- A string, containing the localized text.
- A function, accepting parameters to localize and returning a string.
- A list-like table of either of the above. When localized, one of the entries will be chosen randomly.
Functions in localized string lists can use a set of special helper functions depending on the current language. For example, the function he() in the en language accepts an IChara game object and returns a string with the appropriate subject pronoun based on the character's gender, visibility in the map, and other variables. For more information on what helper functions are available, check the code in the directory internal/i18n/env. This system should help in dealing with the strange rules in various languages related to gender and quantity, in a way not possible with systems like gettext.
Localizing Text in the Code
To localize text, use the I18N API. The simplest use of this API is I18N.get(), returning a string for a localized string key.
local I18N = require("api.I18N")
local text = I18N.get("ui.menu.name")
Gui.mes(text) -- "My Menu"
The locale key passed to I18N.get() corresponds to the nested table value defined in the locale file. If the specified key does not exist, a string containing the missing key as an error message is returned instead.
To handle the case when a locale key does not exist, if you don't always expect it to, use I18N.get_optional(). This function returns nil instead of an error message if the key doesn't exist.
local text = I18N.get_optional("ui.menu.hint")
if text ~= nil then
Gui.mes(text)
end
If the locale key points to a function, you can pass parameters to either of these functions, which will in turn be passed to the localization function:
local player = Chara.player()
local item = Item.create("elona.putitoro")
local text = I18N.get("ui.prompt", player, item)
Gui.mes(text) -- "You are looking for a putitoro."
Next Steps
Proceed to Object Oriented Programming in OpenNefia.