用复数格式化字符串以进行本地化



我有一个简单的命令,我想本地化:"选择5个对象">. 我想过我可以将其模板化为:"Select %d %s">,其中的数字和对象稍后可能会格式化。但这就提出了一个问题:如何恰当地将字符串复数化?

当宾语可以有多个复数时:

  • 0:没有对象
  • 1: 1对象
  • 2个或更多:2个对象

构造字符串模板以适应可选复数的好方法是什么?这对以后的本地化尤其重要,所以我现在尽量聪明一点。

在线阅读,许多本地化最佳实践的热门内容都依赖于苹果的NSLocalizedString库,它允许围绕单词基数的自定义规则的字符串字典。但是,当所有字符串都加载到CSV中时,是否有好的方法来处理这个问题呢?Roblox提供了一个TranslationService,它带有一个Translator类,可以按键格式化字符串。所以我把我的资源组织成这样:

localization.csv

Key, Example, en, fr, es
Command.SelectTemplate, "Select 3 apples", "Select {total : number} {thing : string}", "Sélectionnez {total : number} {thing : string}" "Selecciona {total : number} {thing : string}"
Object.AppleZero, "there are zero apples", "apples", "pommes", "manzanas"
Object.AppleOne, "there is one apple", "apple", "pomme", "manzana"
Object.AppleFew, "there are a few apples", "apples", "pommes", "manzanas"

示例脚本

local LocalizationService = game:GetService("LocalizationService")
local LOCALE = "en"
local res, translator = pcall(function()
return LocalizationService:GetTranslatorForLocaleAsync(LOCALE)
end)
if not res then
warn(string.format("Failed to load the translator with error %s", tostring(translator)))
return
end
local function getSelectionString(numToSelect : number, objectKey : string)
-- TODO : FIND A BETTER WAY TO DO THIS
assert(numToSelect >= 0, "Cannot select a negative number")
local lookupKey
if numToSelect == 0 then
lookupKey = objectKey .. "Zero"
elseif numToSelect == 1 then
lookupKey = objectKey .. "One"
else
lookupKey = objectKey .. "Few"
end
local objectString = translator:FormatByKey(lookupKey)
local formattingArgs = {
total = numToSelect,
thing = objectString,
}
local commandString = translator:FormatByKey("Command.SelectTemplate", formattingArgs)
return commandString
end
-- Test it out
local objectKey = "Object.Apple"
print(getSelectionString(0, objectKey)) -- "Select 0 apples"
print(getSelectionString(1, objectKey)) -- "Select 1 apple"
print(getSelectionString(2, objectKey)) -- "Select 2 apples"

虽然这在技术上是可行的,但它需要为每个对象定义多个键,在其他语言中可能具有复数,并且它假设了一种非常英语的对象复数方式。因此,重申我之前的问题,构造字符串模板以适应可选多个的好方法是什么?

处理复数的最佳方法之一是ICU消息语法。ICU是指Unicode的国际组件——一套广泛使用的C/c++、Java和其他库,为软件和应用程序提供Unicode和全球化支持。

ICU格式允许您创建用户友好的文本,这些文本在一个字符串中组合使用不同的复数、性别、日期和时间形式,这将取决于用户是谁。例如,"Sam给你发了2条消息"one_answers"Emma给你发了1条消息"。

例如:

You have {count, plural,
=0 {no apples}
one {one apple}
other {# apples}
}

可以将这些字符串存储在不同的文件格式中,甚至可以存储在CSV中。不同的语言有不同的复数规则和不同数量的复数形式。因此,翻译人员应该根据目标语言规则翻译ICU字符串。

还有一些本地化文件格式支持原生复数,例如Android XML, iOS Strings。

现代本地化管理平台支持ICU语法。例如,Crowdin。在这里你可以阅读更多关于ICU消息语法支持在Crowdin。此外- ICU消息格式终极指南。

最新更新