LÖVE game localization library. https://doublefourteen.io
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

110 lines
3.2 KiB

--- LÖVE Localization Library
--
-- Basic localization utilities, providing message translation
-- to multiple languages with fallback to English.
-- When package is first require()d, a default dictionary
-- is loaded from: assets/dict.lua
--
-- A dictionary may also be loaded explicitly via loadDictFile().
--
-- @module moonspeak
-- @copyright 2022 The DoubleFourteen Code Forge
-- @author Lorenzo Cogotti
local serialize = require 'lib.serialize'
local moonspeak = {
--- (string) current locale language.
lang = "english",
--- (table|nil) current raw dictionary contents, as loaded by last loadDictFile().
dict = nil
}
--- Attempts to set a locale based on the current system settings.
--
-- Fallbacks to 'english'.
function moonspeak.setDefaultLocale()
moonspeak.lang = "english" -- by default
local lang = os.getenv("LANG")
if lang ~= nil then
local function startswith(s, p) return s:sub(1, #p) == p end
if startswith(lang, "ja_") then
moonspeak.lang = "japanese"
elseif startswith(lang, "it_") then
moonspeak.lang = "italian"
elseif startswith(lang, "fr_") then
moonspeak.lang = "french"
end
end
end
--- Load dictionary from file and set it as the current message source.
--
-- In general there is no need to call this function explicitly, as a
-- default dictionary file is automatically loaded upon require().
--
-- A dictionary file is a file containing a regular Lua table containing
-- key-message pairs.
--
-- @usage
-- -- Dictionary file example:
-- {
-- ["Hello, World!"] = {
-- english = "Hello, World!", -- this can be omitted, as it's identical to key.
-- italian = "Ciao, Mondo!"
-- -- more translations...
-- },
-- ["Hello, %s!"] = { -- message with string.format() arguments.
-- -- english = ..., -- not necessary, key is used as a fallback anyway.
-- italian = "Ciao, %s!"
-- },
-- ["I am %d years old."] = {
-- -- english = ..., -- ditto.
-- italian = "Ho %d anni."
-- }
-- }
--
-- @param name (string) dictionary file name.
function moonspeak.loadDictFile(name)
local data = assert(love.filesystem.read(name))
local dict = assert(serialize.unpack(data, name))
moonspeak.dict = dict
end
--- Translate message.
--
-- A message is looked up inside dictionary using key 'id'.
-- If such message provides a translation string in the current locale, then
-- that translation is used, otherwise the 'id' itself is used as the default message string.
--
-- The selected string is then format()ted, as if by string.format(),
-- forwarding any argument.
--
-- @param id (string) key to be used for locale message lookup.
-- @param ... optional additional string.format() arguments.
--
-- @return localized and formatted string.
function moonspeak.translate(id, ...)
local dict = moonspeak.dict
local lang = moonspeak.lang
local msg = dict and dict[id] or nil
if msg ~= nil and msg[lang] then
-- Found localized string.
return msg[lang]:format(...)
end
return id:format(...) -- fallback to default
end
-- Load default dictionary
if love.filesystem.getInfo("assets/dict.lua") then
moonspeak.loadDictFile("assets/dict.lua")
end
return moonspeak