使用 Objective-C 在 iPhone 上本地化动态复数名词消息(例如“5 Items Processed”)

发布于 2024-10-19 01:50:25 字数 862 浏览 5 评论 0原文

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

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

目前效果很好。但我正在本地化我的应用程序,并希望确保我将应用程序翻译成的所有语言的文本在语法上都是正确的。我可以做这样的事情:

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

但是,并非所有语言对于复数的运作方式都有相同的规则!例如,(请原谅我在这里的非常具体的例子)在俄语中,用最后一位数字 1 结尾的数字修饰的名词(即 21、31,但不是 11)采用主格,数字以2-4 采用单数属格,5+ 采用复数属格。这将需要更严肃的逻辑来处理如何以语法正确的方式使特定名词复数,并且这种逻辑与英语逻辑不匹配。因此,理论上,我不能在我的 Objective-C 代码中拥有语法逻辑,而应该在字符串文件中拥有语法逻辑。有办法做到这一点吗? 人们如何翻译应用程序的动态文本以保持语法正确?

In my current app, I have code that displays a message, e.g. "5 Items Processed." To keep the phrase grammatically correct, i.e. whether or not it should be "5 Item" or "5 Items," I use the following code:

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

This works fine for now. But I'm localizing my app, and want to make sure that the text is grammatically correct in all the languages I am translating the app into. I could do something like this:

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

However, not all languages have the same rules for how plurals operate! For example, (forgive my very specific example here) in Russian, nouns modified with numbers ending with the last digit 1 (i.e., 21, 31, but not 11) take the nominative case, numbers ending in 2-4 take the genitive singular, and 5+ take the genitive plural case. This would require much more serious logic to handle how to pluralize a particular noun in a grammatically correct fashion, and this logic would not match up to the English logic. Therefore, in theory, I cannot have the grammatical logic in my Objective-C code, but should rather have the grammatical logic in the strings file. Is there a way to do this? How do people translate dynamic text for their apps so that it remains grammatically correct?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

蓝眸 2024-10-26 01:50:25

从 iOS 7 开始,Foundation 框架具有 对多元化的原生支持。
这是如何使用它的快速教程:

创建一个名为 Localized.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>

波兰语本地化:

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

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

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

编辑:
感谢 Zaphod 指出这一点 ->:您还需要在 . stringsdict 使复数工作(即使它是空的)。

As of iOS 7, Foundation framework has native support for pluralization.
Here is a quick tutorial how to use it:

Create a plist file named as Localizable.stringsdict

English Localization:

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

Polish Localization:

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

And finally in your implementation file, you can call the dictionary like this:

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

EDIT:
Thanks Zaphod for pointing this out ->: You also need to create the Localizable.strings file alongside the .stringsdict to have the pluralization work (even if it's empty).

﹏半生如梦愿梦如真 2024-10-26 01:50:25

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

基本前提是复数字符串的键根据 CLDR 复数规则 并且字符串的查找不使用典型的 NSLocalizedString。

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

"%d Items Processed##{one}"   = "1 Item Processed";    
"%d Items Processed##{other}" = "%d Items Processed";

然后,将使用 SLPluralizedString 函数完成查找

SLPluralizedString(@”%d Items Processed”, numItems, @”Number of items processed”);

在运行时,对于英文,将根据 numItems 的值返回字符串“1 Item Processed”或“%d Items Processed” 。

俄语文件将如下所示:

"%d Items Processed##{one}"   = "%d элемент обработан";
"%d Items Processed##{few}"   = "%d элемента обработано";
"%d Items Processed##{many}"  = "%d элементов обработано";
"%d Items Processed##{other}" = "%d элемента обработано";

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

请随时分享您对图书馆的想法、建议、改进等。

My team developed an open source library for handling just this situation, checkout our iOS i18n plural library on github.

The basic premise is that the keys for plural strings are extended to contain their plural form according to the CLDR plural rules and the lookup of the strings does not use the typical NSLocalizedString.

The English file for the example posted would look like this:

"%d Items Processed##{one}"   = "1 Item Processed";    
"%d Items Processed##{other}" = "%d Items Processed";

The lookup would then be done using a SLPluralizedString function

SLPluralizedString(@”%d Items Processed”, numItems, @”Number of items processed”);

At runtime, for English the String "1 Item Processed" or "%d Items Processed" would be returned depending on the value of numItems.

The Russian file would then look like this:

"%d Items Processed##{one}"   = "%d элемент обработан";
"%d Items Processed##{few}"   = "%d элемента обработано";
"%d Items Processed##{many}"  = "%d элементов обработано";
"%d Items Processed##{other}" = "%d элемента обработано";

Your code then to lookup "Items Processed" for Russian or any other language wouldn't have to change and the library would return the correct String according to the CLDR plural rules for that particular language.

Please feel free to share your thoughts on the library, suggestions, improvements, etc.

无可置疑 2024-10-26 01:50:25

在英语中,只有两种复数形式,例如“1 file”和“5 files”。俄语中,除非计算非整数,否则有 3 种复数形式(101 файл、2 файла、11 файлов)。实际上,一种语言实际上最多可以有 6 个复数形式(例如阿拉伯语有 6 个)。似乎有 3 种方法可以解决这个问题,只要选择足够好但对你来说不太复杂的方法即可:

  1. 尝试使用复数中性消息,例如“已处理的项目数:%d”而不是“%” d 项已处理 | %d 项已处理”。

  2. 支持每种复数形式的本地化,最多 6 种。

    "%d 金币##{PluralForm0}" -> "%d золотая монета" // 例如 1 个金币
    "%d 金币##{PluralForm1}" -> "%d золотые монеты" // 例如 2 个金币
    “%d 金币##{PluralForm2}”-> "%d золотых монет" // 例如 5 个金币
    ……
    “%d 金币##{PluralForm5}”-> “%d 如果这不是阿拉伯语,我们怎么会到这里???”
    

    知道 %d 的值和目标语言,您的应用程序将必须在运行时检测复数形式编号,即实现类似的东西

    unsigned int "NumberToPluralFormNumber(unsigned int number, const std::string& langCode);
    

    方法。如果您仅支持 2-5 种语言,并且消息中的数字始终为非负整数,那么实现它实际上非常简单,无需任何 3d 方库,您可以为每种语言复制/粘贴与 C 兼容的单行代码来自 http://docs.translatehouse.org/projects 的语言/localization-guide/en/latest/l10n/pluralforms.html 。请注意,它仅对非负整数有效,因此复数形式的数量可能与 unicode.org 所说的不同。

  3. 3D 派对库。

In English, there are just 2 plural forms, e.g. "1 file" and "5 files". In Russian, there are 3 plural forms (101 файл, 2 файла, 11 файлов), unless you count non-integers. Actually, there can actually be up to 6 plural forms in a language (e.g. Arabic has 6) . There seems to be 3 ways to deal with the problem, just choose whatever is good enough but not too complicated for you:

  1. Try to use plural-neutral messages, e.g. "Number of items processed: %d" instead of "%d item processed | %d items processed ".

  2. Support localizations for each plural form, up to 6.

    "%d Gold Coins##{PluralForm0}" -> "%d золотая монета" // e.g. 1 gold coin
    "%d Gold Coins##{PluralForm1}" -> "%d золотые монеты" // e.g. 2 gold coins
    "%d Gold Coins##{PluralForm2}" -> "%d золотых монет"  // e.g. 5 gold coins
    …
    "%d Gold Coins##{PluralForm5}" -> "%d How did we get here if this is not Arabic???"
    

    Knowing the value of %d and the target language, you app will have to detect the plural form number in the runtime, i.e. implement something like

    unsigned int "NumberToPluralFormNumber(unsigned int number, const std::string& langCode);
    

    method. If you support just 2-5 languages and the numbers in the messages are always non-negative ints, it is actually quite simple to implement it w/o any 3d party lib, you can copy/paste C-compatible one-liners for each language from http://docs.translatehouse.org/projects/localization-guide/en/latest/l10n/pluralforms.html . Please note that it's valid for non-negative integers only, so the number of plural forms might differ from what unicode.org says.

  3. 3d party libs.
霓裳挽歌倾城醉 2024-10-26 01:50:25

我会考虑显示相同信息的替代方法,也许类似于:

@"Items processed: %d"

MDC 有一个长期、全面的内容如果您有兴趣,可以查看多元化规则列表,但我真的认为不值得付出努力来实施所有这些规则。您可能需要考虑的另一件事是,是否有任何语言会在复数形式后出现数字,因为它会破坏您的格式字符串(我想不出任何语言会超出我的头脑,但也许有一个地方请谨慎对待任何涉及数字的更复杂的本地化字符串)。

I would consider alternative ways to display the same information, perhaps something like:

@"Items processed: %d"

MDC has a long, comprehensive list of pluralisation rules if you're interested, but I really don't think it is worth the effort to implement all these rules. Another thing you might have to consider is if any languages would have the number appear after the pluralisation, as it would throw your format string off (I can't think of any languages that would off the top of my head, but perhaps a place for caution in any of your more complicated localised strings with numbers involved).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文