161 lines
4.4 KiB
Lua
161 lines
4.4 KiB
Lua
local PurchaseError = require(script.Parent.Parent.PurchaseError)
|
|
local Symbol = require(script.Parent.Parent.Symbol)
|
|
|
|
local KeyMappings = require(script.Parent.KeyMappings)
|
|
local addGroupDelimiters = require(script.Parent.Parent.addGroupDelimiters)
|
|
|
|
local DEBUG_LOCALIZATION = false
|
|
|
|
--[[
|
|
Locale-specific group delimiters for displaying numbers. Used to
|
|
format values like 100000 to strings like "100,000". This table
|
|
does not provide any info regarding decimal separators
|
|
]]
|
|
local groupDelimiterByLocale = {
|
|
["en-us"] = ",",
|
|
["en-gb"] = ",",
|
|
["es-mx"] = ",",
|
|
["es-es"] = ".",
|
|
["fr-fr"] = " ",
|
|
["de-de"] = " ",
|
|
["pt-br"] = ".",
|
|
["zh-cn"] = ",",
|
|
["zh-tw"] = ",",
|
|
["ko-kr"] = ",",
|
|
["ja-jp"] = ",",
|
|
["it-it"] = " ",
|
|
["ru-ru"] = ".",
|
|
["id-id"] = ".",
|
|
["vi-vn"] = ".",
|
|
["th-th"] = ",",
|
|
["tr-tr"] = ".",
|
|
}
|
|
|
|
--[[
|
|
This is a marker used to indicate that a provided param needs a locale-aware
|
|
formatting pass. We need this for nested localization and number formatting
|
|
]]
|
|
local FormattedParamTag = Symbol.named("FormattedParam")
|
|
|
|
local function isFormattedParam(paramValue)
|
|
return typeof(paramValue) == "table" and paramValue[FormattedParamTag] == true
|
|
end
|
|
|
|
local function createFormattedParam(formatFunc)
|
|
return {
|
|
[FormattedParamTag] = true,
|
|
format = formatFunc,
|
|
}
|
|
end
|
|
|
|
--[[
|
|
Looks up the given key in the localization context's translation table
|
|
]]
|
|
local function getLocalizedString(localizationContext, key)
|
|
local translations = localizationContext.translations
|
|
|
|
if DEBUG_LOCALIZATION and translations[key] == nil then
|
|
warn(("Missing translation for %s in locale %s"):format(key, localizationContext.locale))
|
|
end
|
|
|
|
return translations[key]
|
|
end
|
|
|
|
local LocalizationService = {}
|
|
|
|
function LocalizationService.formatNumber(localizationContext, number)
|
|
local delimiter = groupDelimiterByLocale[localizationContext.locale]
|
|
|
|
return addGroupDelimiters(number, delimiter)
|
|
end
|
|
|
|
--[[
|
|
Generates a placeholder for a number param that needs locale-aware formatting
|
|
]]
|
|
function LocalizationService.numberParam(number)
|
|
return createFormattedParam(function(localizationContext)
|
|
return LocalizationService.formatNumber(localizationContext, number)
|
|
end)
|
|
end
|
|
|
|
--[[
|
|
Generates a placeholder for a param substitution that needs
|
|
its own localization pass
|
|
]]
|
|
function LocalizationService.nestedKeyParam(key)
|
|
return createFormattedParam(function(localizationContext)
|
|
return getLocalizedString(localizationContext, key)
|
|
end)
|
|
end
|
|
|
|
--[[
|
|
Utility function returns the localization key for a given asset id
|
|
]]
|
|
function LocalizationService.getAssetTypeKey(assetTypeId)
|
|
assert(typeof(assetTypeId) == "number" or typeof(assetTypeId) == "string",
|
|
"provided asset type must be a number or string")
|
|
|
|
local assetType = KeyMappings.AssetTypeById[tostring(assetTypeId)]
|
|
|
|
if DEBUG_LOCALIZATION and assetType == nil then
|
|
warn("Invalid Asset Type id " .. tostring(assetTypeId))
|
|
end
|
|
|
|
return assetType
|
|
end
|
|
|
|
--[[
|
|
Utility function returns the localization key for a given
|
|
builders club level
|
|
]]
|
|
function LocalizationService.getBuildersClubLevelKey(bcLevelId)
|
|
assert(typeof(bcLevelId) == "number" or typeof(bcLevelId) == "string",
|
|
"provided builders club level must be a number")
|
|
local bcLevel = KeyMappings.BuildersClubLevelById[tostring(bcLevelId)]
|
|
|
|
if DEBUG_LOCALIZATION and bcLevel == nil then
|
|
warn("Invalid Builders Club Level id " .. tostring(bcLevelId))
|
|
end
|
|
|
|
return bcLevel
|
|
end
|
|
|
|
--[[
|
|
Utility function to retrieve relevant localization key for various
|
|
types of errors that may be encountered
|
|
]]
|
|
function LocalizationService.getErrorKey(errorType)
|
|
assert(PurchaseError.isMember(errorType),
|
|
"provided value " .. tostring(errorType) .. " is not a member of PurchaseError enum")
|
|
|
|
return KeyMappings.PurchaseErrorKey[errorType]
|
|
end
|
|
|
|
--[[
|
|
The primary function of this object
|
|
|
|
Retrieves a localized string from the provided context with the
|
|
given key and performs parameter substitutions
|
|
]]
|
|
function LocalizationService.getString(localizationContext, key, params)
|
|
assert(localizationContext ~= nil, "Must provide valid localization context")
|
|
|
|
local localizedString = getLocalizedString(localizationContext, key)
|
|
|
|
if params ~= nil then
|
|
for param, value in pairs(params) do
|
|
local replacement = value
|
|
local paramPlaceholder = ("{%s}"):format(param)
|
|
|
|
if isFormattedParam(value) then
|
|
replacement = value.format(localizationContext)
|
|
end
|
|
|
|
localizedString = string.gsub(localizedString, paramPlaceholder, replacement)
|
|
end
|
|
end
|
|
|
|
return localizedString
|
|
end
|
|
|
|
return LocalizationService |