142 lines
4.0 KiB
Lua
142 lines
4.0 KiB
Lua
--[[
|
|
Contains all of the loaded translations and provides methods to translate
|
|
keys and parameters to strings.
|
|
|
|
LocalizationContext doesn't handle loading of specific languages, but does
|
|
recommend what languages should be loaded (if available).
|
|
|
|
To create a new LocalizationContext:
|
|
|
|
local currentLanguage = LocalizationService.RobloxLocaleId
|
|
local languages = LocalizationContext.getRelevantLanguages(currentLanguage)
|
|
|
|
local translations = {}
|
|
|
|
-- Use the list of languages to load a set of translation tables here.
|
|
-- A translation table is just a map from key to the translated string.
|
|
-- `translations` is a map from language to translation tables.
|
|
|
|
local context = LocalizationContext.new(translations)
|
|
|
|
-- Get a string that doesn't require parameters
|
|
context:getString(currentLanguage, "SOME_KEY")
|
|
|
|
-- Passing parameters:
|
|
context:getString(currentLanguage, "FANCY_KEY", {
|
|
apples = 5,
|
|
})
|
|
|
|
Additional languages can be added after the LocalizationContext is created
|
|
by calling `addTranslations`. Whenever the user's language changes, call
|
|
`getRelevantLanguages` to get a new list of languages to load, load them,
|
|
then call `addTranslations` to merge them in with the existing tables.
|
|
]]
|
|
|
|
--[[
|
|
Finds the base language code for the given language, if there is one.
|
|
|
|
We assume:
|
|
* Language codes are of the form LANGUAGE or LANGUAGE_COUNTRY
|
|
* LANGUAGE_COUNTRY is more specific than LANGUAGE
|
|
]]
|
|
|
|
local function getBaseLanguage(languageName)
|
|
return languageName:match("^(%w+)[-_]")
|
|
end
|
|
|
|
local LocalizationContext = {}
|
|
LocalizationContext.__index = LocalizationContext
|
|
|
|
function LocalizationContext.new(translations)
|
|
local self = {
|
|
_translations = translations,
|
|
}
|
|
|
|
setmetatable(self, LocalizationContext)
|
|
|
|
return self
|
|
end
|
|
|
|
--[[
|
|
Add translations to an existing LocalizationContext, such as when a user
|
|
switches languages while the app is running.
|
|
]]
|
|
function LocalizationContext:addTranslations(translations)
|
|
self._translations = translations
|
|
end
|
|
|
|
--[[
|
|
Yields a list of languages relevant to the current user.
|
|
|
|
When the user's language changes, query this value, load those translations,
|
|
and add them to the LocalizationContext using addTranslations.
|
|
]]
|
|
function LocalizationContext.getRelevantLanguages(primaryLanguage)
|
|
local languages = {}
|
|
|
|
-- Load the language itself if available.
|
|
table.insert(languages, primaryLanguage)
|
|
|
|
-- If there's a fallback for our current language, load that as well.
|
|
local fallbackLanguage = getBaseLanguage(primaryLanguage)
|
|
if fallbackLanguage then
|
|
table.insert(languages, fallbackLanguage)
|
|
end
|
|
|
|
-- We should always load English, as it should contain every valid key.
|
|
table.insert(languages, "en-us")
|
|
return languages
|
|
end
|
|
|
|
function LocalizationContext:_getSourceString(language, key)
|
|
local translationTable = self._translations[language]
|
|
|
|
if not translationTable then
|
|
return nil
|
|
end
|
|
|
|
return translationTable[key]
|
|
end
|
|
|
|
--[[
|
|
Translate a key with a set of arguments into the given language.
|
|
|
|
`language` must be explicitly provided
|
|
]]
|
|
function LocalizationContext:getString(language, key, parameters)
|
|
local exactValue = self:_getSourceString(language, key)
|
|
|
|
local baseLanguage = getBaseLanguage(language)
|
|
|
|
local baseLanguageValue
|
|
if baseLanguage then
|
|
baseLanguageValue = self:_getSourceString(baseLanguage, key)
|
|
end
|
|
|
|
local englishValue = self:_getSourceString("en-us", key)
|
|
|
|
-- We try to find source strings in descending priority here:
|
|
local sourceString = exactValue or baseLanguageValue or englishValue
|
|
|
|
-- Missing translations are considered a developer error, so we throw here.
|
|
if not sourceString then
|
|
local message = (
|
|
"Couldn't find value for translation key %q!\n" ..
|
|
"Tried these languages: %s, %s, %s"
|
|
):format(
|
|
key,
|
|
language, baseLanguage, "en-us"
|
|
)
|
|
error(message, 2)
|
|
end
|
|
|
|
-- If we have parameters to insert into the string, put them in!
|
|
-- We don't check for missing parameters, should we in the future?
|
|
if parameters then
|
|
return (sourceString:gsub("{(.-)}", parameters))
|
|
else
|
|
return sourceString
|
|
end
|
|
end
|
|
|
|
return LocalizationContext |