web-dev-qa-db-ja.com

Objective-Cを使用してiPhoneで動的複数名詞メッセージ(「5ItemsProcessed」など)をローカライズする

現在のアプリには、メッセージを表示するコードがあります。 「5つのアイテムが処理されました。」フレーズを文法的に正しく保つために、つまり「5アイテム」にするか「5アイテム」にするかを決めるために、次のコードを使用します。

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

これは今のところ問題なく動作します。しかし、私はアプリをローカライズしており、アプリを翻訳するすべての言語でテキストが文法的に正しいことを確認したいと思います。私couldは次のようなことをします:

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

ただし、すべての言語で複数形の動作について同じ規則があるわけではありません。たとえば、(ここで私の非常に具体的な例を許してください)ロシア語では、名詞は最後の数字1で終わる数字で変更されます(つまり、21、31、しかしnot11)主格を取り、2-4で終わる数字は属格単数を取り、5 +は属格複数を取ります。これには、特定の名詞を文法的に正しい方法で複数形にする方法を処理するために、はるかに深刻なロジックが必要になり、このロジックは英語のロジックと一致しません。したがって、理論的には、Objective-Cコードに文法ロジックを含めることはできませんが、文字列ファイルに文法ロジックを含める必要があります。これを行う方法はありますか? 文法的に正しいままになるように、アプリの動的テキストをどのように翻訳しますか?

34
Jason

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>

ポーランド語のローカリゼーション:

<?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と一緒にLocalizable.stringsファイルを作成する必要もあります(空の場合でも) 。

62
Alp

私のチームは、この状況を処理するためのオープンソースライブラリを開発しました。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 ItemProcessed」または「%dItemsProcessed」が返されます。

ロシア語のファイルは次のようになります。

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

次に、ロシア語またはその他の言語の「処理されたアイテム」を検索するコードを変更する必要はなく、ライブラリはその特定の言語のCLDR複数形に従って正しい文字列を返します。

ライブラリ、提案、改善点などについて、お気軽にご意見をお聞かせください。

12
Greg Jones

英語では、複数形は2つしかありません。 「1ファイル」と「5ファイル」。ロシア語では、非整数を数えない限り、3つの複数形(101файл、2файла、11файлов)があります。実際には、言語には最大6つの複数形が存在する可能性があります(たとえば、アラビア語には6つあります)。問題に対処するには3つの方法があるようです。十分に良いが、複雑すぎないものを選択してください。

  1. 複数形に中立なメッセージを使用してみてください。 「処理されたアイテムの数:%d」の代わりに「%dアイテムが処理されました|%dアイテムが処理されました」。

  2. 最大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???"
    

    %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. サードパーティのライブラリ。
2
user2937889

同じ情報を表示する別の方法を検討します。おそらく次のようなものです。

@"Items processed: %d"

[〜#〜] mdc [〜#〜] 興味がある場合は、複数化ルールの長く包括的なリストがありますが、これらすべてのルールを実装する価値はないと思います。 。あなたが考慮しなければならないかもしれないもう一つのことは、フォーマット文字列を捨ててしまうので、複数形の後に数字が表示される言語があるかどうかです(頭から離れる言語は考えられませんが、おそらく場所です数字が含まれる、より複雑なローカライズされた文字列には注意が必要です)。

0
dreamlax