--- 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