使用Objective-C在iPhone上本地化动态复数名词消息(例如"5个已处理项目")

Jas*_*son 34 iphone localization internationalization localizable.strings ios

在我当前的应用程序中,我有显示消息的代码,例如"5个已处理的项目".为了保持短语在语法上正确,即它是否应该是"5 Item"或"5 Items",我使用以下代码:

int numItems = 5;
NSString *myString = [[NSString alloc] initWithFormat:@"%d Item%@ Processed", numItems, (numItems == 1 ? @"" : @"s")];
Run Code Online (Sandbox Code Playgroud)

这个现在工作正常.但我正在本地化我的应用程序,并希望确保我正在翻译应用程序的所有语言中的文本语法正确.我可以这样做:

int numItems = 5;
NSString *myString = (numItems == 1 ? 
NSLocalizedStringWithTable(@"%d Item Processed", @"myApp", @"singular version") :
NSLocalizedStringWithTable(@"%d Items Processed", @"myApp", @"plural version"));
Run Code Online (Sandbox Code Playgroud)

但是,并非所有语言都具有相同的复数操作规则!例如,(原谅我在这里非常具体的例子)俄语中,用最后一个数字1结尾的数字修改的名词(即21,31,但不是 11)采用主格,结束于2-4的数字采用了genitive奇异,5+采取属性复数的情况.这将需要更严格的逻辑来处理如何以语法正确的方式复数特定名词,并且该逻辑与英语逻辑不匹配.因此,从理论上讲,我不能在Objective-C代码中使用语法逻辑,而应该在strings文件中使用语法逻辑.有没有办法做到这一点?人们如何为他们的应用翻译动态文本,以使其在语法上保持正确?

小智 61

从iOS 7开始,Foundation框架本身就支持多元化. 这是一个如何使用它的快速教程:

创建一个名为Localizable.stringsdict的plist文件

英文本地化:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
    <dict>
        <key>%d tasks waiting for action</key>
        <dict>
            <key>NSStringLocalizedFormatKey</key>
            <string>%#@tasks@ waiting for action</string>
            <key>tasks</key>
            <dict>
                <key>NSStringFormatSpecTypeKey</key>
                <string>NSStringPluralRuleType</string>
                <key>NSStringFormatValueTypeKey</key>
                <string>d</string>
                <key>one</key>
                <string>A task is</string>
                <key>two</key>
                <string>Two tasks are</string>
                <key>other</key>
                <string>%d tasks are</string>
            </dict>
        </dict>
    </dict>
</plist>
Run Code Online (Sandbox Code Playgroud)

波兰语本地化:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
    <dict>
        <key>%d tasks waiting for action</key>
        <dict>
            <key>NSStringLocalizedFormatKey</key>
            <string>Masz %#@zadanie@ do zrobienia</string>
            <key>zadanie</key>
            <dict>
                <key>NSStringFormatSpecTypeKey</key>
                <string>NSStringPluralRuleType</string>
                <key>NSStringFormatValueTypeKey</key>
                <string>d</string>
                <key>one</key>
                <string>jedno zadanie</string>
                <key>few</key>
                <string>%d zadania</string>
                <key>other</key>
                <string>%d zada?</string>
            </dict>
        </dict>
    </dict>
</plist>
Run Code Online (Sandbox Code Playgroud)

最后在您的实现文件中,您可以像这样调用字典:

cell.tasksInfoLabel.text = [NSString localizedStringWithFormat:NSLocalizedString(@"%d tasks waiting for action", @"%d tasks waiting for action"), (long)taskCount];
Run Code Online (Sandbox Code Playgroud)

编辑:感谢Zaphod指出这一点 - >:您还需要在.stringsdict旁边创建Localizable.strings文件以使复数工作(即使它是空的).

  • 我相信我正确地实现了这个解决方案,但它似乎并不是多元化的.您能否提供一些有关如何实施的详细信息? (2认同)
  • 我还没有得到这整个多元化的东西为我自己工作,但它并没有阻止我做一些让我们的生活更轻松,更少的XML:https://github.com/dclowd9901/json-to-stringsdict (2认同)
  • @ dclowd9901您还需要在`.stringsdict`旁边创建`Localizable.strings`文件以使复数化工作(即使它是空的).@Alp也许你可以把它添加到你的答案中. (2认同)

小智 12

我的团队开发了一个开源库来处理这种情况,在github上查看我们的iOS i18n复数库.

基本前提是根据CLDR复数规则扩展多个字符串的键以包含它们的复数形式,并且字符串的查找不使用典型的NSLocalizedString.

发布的示例的英文文件如下所示:

"%d Items Processed##{one}"   = "1 Item Processed";    
"%d Items Processed##{other}" = "%d Items Processed";
Run Code Online (Sandbox Code Playgroud)

然后使用SLPluralizedString函数完成查找

SLPluralizedString(@”%d Items Processed”, numItems, @”Number of items processed”);
Run Code Online (Sandbox Code Playgroud)

在运行时,对于英语,将返回字符串"1 Item Processed"或"%d Items Processed",具体取决于numItems的值.

俄语文件将如下所示:

"%d Items Processed##{one}"   = "%d ??????? ?????????";
"%d Items Processed##{few}"   = "%d ???????? ??????????";
"%d Items Processed##{many}"  = "%d ????????? ??????????";
"%d Items Processed##{other}" = "%d ???????? ??????????";
Run Code Online (Sandbox Code Playgroud)

然后,您的代码将查找"已处理的项目"(对于俄语或任何其他语言)不必更改,并且库将根据该特定语言的CLDR复数规则返回正确的字符串.

请随时与您分享您对图书馆,建议,改进等的看法.