PUFF-Jファイルフォーマット
PUFF-J
PUFF-Jは、ローカライズされるリソースを記述するための、UTF-8文字エンコードを使用するJSONベースのファイル形式です。リソースとは、翻訳のためにリンギストに提出される文字列です。
この形式では、リソースをマップの形式で提供できます。
- キー: リソースの一意の識別子。
- 値: リソース値を含むオブジェクト。リソース値は、翻訳のためにリンギストに提出される値です。
リソースオブジェクトは、次のいずれかを提供するいくつかのプロパティで修飾できます。
- リソースの説明。リソースが使用されるコンテキストなどを含めることができます。
- リソースのライフサイクル(翻訳プロセス中またはリソースが使用される実行時)において、そのリソースがどのように処理されるかに関する追加情報。
この形式は開発者向けで、人が判読でき、編集しやすいように設計されています。ビルド時には、実行時に容易に使用できる内部形式に変換されます。
PUFF-Jファイルの拡張子はpuff.jsonにする必要があります。
リソースレベルのプロパティ
リソース識別子
翻訳用に提出される各リソースは、一意の識別子によって識別されます。このリソースIDは、リソースオブジェクトのプロパティ名として指定します。JSONではこの文字列に実質的に任意のUnicode文字を使用できますが、PUFF-Jでは次の文字セットに制限されています。
^(\\w[\\w-:]*)$`.
\wは[a-zA-Z_0-9]と同じです。
リソース値
リソース値は、翻訳のためにリンギストに提出される実際の値です。通常はvalueプロパティに指定され、次の3つのタイプのいずれかにすることができます。
オプションのプロパティ
リソースオブジェクトには、追加のプロパティを含めることができます。これらのプロパティを通じて、翻訳プロセスでのリソースの処理方法に関する詳細情報を提供します。
translate- 文字列を翻訳するかどうかを示すフラグ。省略されている場合、または値がtrueの場合、文字列を翻訳する必要があります。これは、翻訳リクエストに含められることを意味します。
note- コンテキストに関するノート。追加することを強く推奨します。
- 各ノートの文字数は3,000文字に制限されます。
- ノートは開発者のコメントを表し、文字列やプレースホルダーに関して、翻訳者の助けとなる幅広いコンテキストを提供します。
例:
{
"dir" : "ltr",
"resources": {
"messageXml": {
"note" : "{0}は顧客注文の追跡番号です。",
"value": "注文番号は{0}です。"
},
"messageXml2": {
"translate": false,
"note" : "この変数を翻訳者が翻訳する必要はありません。MessageFormatでローカライズされます。",
"value": "{numItems,number,integer}"
}
}
}
リソースタイプ
前述のとおり、翻訳のためにリンギストに送信されるリソース値は、次の3つのタイプのいずれかにすることができます。
このセクションでは、各タイプの詳細と、それらをPUFF-Jファイルで適切に表現する方法に関するベストプラクティスを説明します。
重要なポイント
MessageFormatの複雑な複数形パターンや選択パターンを編集したり読み取ったりする労力を軽減するには、構造化リソース値タイプを使用します。-
ICUの
MessageFormatのドキュメント(英語のみ)より:複雑な引数(複数形分岐など)を持つメッセージ文字列では、最小限の部分だけを処理したくなりがちです。しかし、これは翻訳者にとって2つの理由から困難です。 第一に翻訳者には、引数のサブメッセージに含まれている文の断片が、文の残りの部分とどのように関係するかがわからない場合があります。第二に、メッセージ全体を翻訳対象言語に合わせようとしても、引数の文の一部を短縮または拡張してよいかどうか、どのように短縮または拡張すればよいかを翻訳者が知る方法はありません。
推奨される方法: 可能であれば、複雑な引数をメッセージの最も外側の構造として使用し、そのサブメッセージ内に文全体を記述します。選択分岐と複数形分岐の引数を入れ子にする場合は、選択分岐引数(およびその固定の選択肢のセット)を外側に配置し、複数形分岐引数(なるべく最大1つ)を内側に入れ子にします。
- コンテキストノートを追加します。これらのノートは開発者のコメントを表し、文字列やプレースホルダーに関する幅広いコンテキストを翻訳者に提供します。また、複数に解釈される可能性のある単語や概念を、翻訳者が理解するために役立つ情報も提供します(たとえば、「window」という単語は、コンピューター上のウィンドウを意味する場合と、家の窓を意味する場合があります)。
以降では、さまざまなリソースタイプ、ユースケース、推奨事項について詳しく見ていきます。
文字列タイプ
単純な文字列はJSON文字列として表されます。文字列はMessageFormatパターンとして記述され、必要に応じてパラメーター(文字列、数値、日付、時刻など)のプレースホルダーを含めることができます。パラメーターは実行時にフォーマットされ、挿入されます。
文字列には、エスケープされた制御文字を除く任意のUnicode文字を使用できます。エスケープ構文を参照してください。
ただし、ストレートアポストロフィU+0027(')(英語(米国)キーボードのデフォルトの一重引用符)は例外です。これはJSONでは有効ですが、MessageFormatのパターンでは特殊文字として扱われます。この文字はソース文字列で使用しないことをお勧めします。一重引用符を表すには、代わりに右一重引用符U+2019(’)文字を使用してください。
ソース文字列に一重引用符が含まれていなくても、翻訳された文字列に一重引用符を含めることが必要になる場合があります。これは、たとえばフランス語の翻訳で特によく起こります。この場合は、右一重引用符U+2019(’)文字を使用するように翻訳者に指示してください。開発者がコンテキストノートで翻訳者に注意を促すのも有効な方法です。
MessageFormat パターンにリテラルのストレートアポストロフィ文字をあえて含める必要がある場合は、ストレートアポストロフィを2つ続けることでエスケープできます。たとえば、MessageFormatパターン内の''は「'」としてレンダリングされます。
もう1つの例外は中かっこです。これもMessageFormatパターンの特殊文字です。ストレートアポストロフィを使用する必要のあるケースの1つが、MessageFormatパターンにリテラルの中かっこ文字を含めるためのエスケープ文字として使用する場合です。たとえば、MessageFormatパターン内の'{''}'は「{'}」としてレンダリングされます。このような用法については、翻訳者向けのコンテキストノートを含めるのが最適です。また、構文が直観的でないため、返された翻訳を注意深く確認することも必要です。
プレースホルダーがある場合とない場合の単純な文字列の例(簡略な表現):
"stringId1": "This is a window.",
"stringId2": "Hello {user}, this is a window."
最初の例は、プレースホルダーのない単純な文字列を示しています。2番目の例は、文字列プレースホルダーのある文字列を示しています。
注: 数値、日付、時刻のプレースホルダーでは、構文に書式タイプを含める必要があります。
値構造の例(詳細な表現):
"stringId1": {
"value": "This is a window.",
"note": "これはコンピューター上のウィンドウを指しています。"
},
"stringId2": {
"value": "Hello {user}, this is a window.",
"note": "これはコンピューター上のウィンドウを指しています。"
},
最初の例は、プレースホルダのない文字列を示しています。2番目の例は、文字列プレースホルダーのある文字列を示しています。コンテキストノートを追加することで、windowがコンピューター上のウィンドウなのか、家の物理的な窓なのかを翻訳者が明確に判断できるようになります。
推奨される方法: 翻訳者の助けとなるように、コンテキストノート付きの値構造を使用することを強くお勧めします。特に、文字列にプレースホルダーが含まれている場合はコンテキストノートが必要です。
構造化ソース値タイプ
構造化リソース値タイプを使用すると、MessageFormatの複雑な複数形パターンや選択パターンを編集したり読み取ったりする労力が軽減されます。パラメーターに基づいて分岐するサブパターンを、パラメーター値をキーとするマップとして提供できます。マップ内の各項目は、サブパターンのさまざまな分岐を表します。
複数形分岐タイプ
推奨される方法: MessageFormatの複雑な複数形パターンを記述する作業は込み入っていて、間違いを引き起こすことがよくあります。この理由から、そしてリソースの読みやすさを向上させるためにも、開発者には、複数形分岐構造化リソース値タイプを使用して複数形分岐形式を構築することを強くお勧めします。この形式により、複数形分岐の項目ごとに翻訳可能な文全体を記述することが促され、複雑なMessageFormat構造を回避できます。この方法に従うと、高品質な翻訳を実現するために役立ちます。
文字列に数値を挿入するときによく問題となるのが、最終的に文法的に正しい文を作成することです。たとえば、次のようなMessageFormatパターンがあるとします。
"You have {0,number,integer} **items** in your cart"
ただし、itemの数が1つの場合、この文は次のようにする必要があります。
"You have 1 **item** in your cart"
このケースへの対応として浮かびやすいのは、2つの文字列を作成する方法です。
"itemsInCartPattern_singular"
および
"itemsInCartPattern_plural"
または、次のような「ニュートラル」な文字列を使用して問題を回避しようとする場合もあります。
"You have {0,number,integer} item(s) in your cart"
しかし、これらのソリューションはどちらも、ほかの言語の文法要件を考慮していません。ほかの言語の文法が、たった2つのカテゴリーに常に当てはまるとは限りません。
MessageFormatには複数形を処理するためのパターン構文がありますが、扱いやすくはありません。そこで、代わりに複数形分岐構造化リソース値タイプの構文を使用すると、どの言語でも文法的に正しい複数形を記述することが簡単になります。
複数形分岐リソースを構築するには、次の2つのパラメーターを指定する必要があります。
param: メッセージを選択するために使用する変数の名前。pluralItems: ルールが関連付けられた文字列のリスト。これらの項目から選択されます。
パラメーター値に基づいて、適切な複数形バリアントが選択されます。関連するパラメーターのIDはparamプロパティで指定します。MessageFormat内のパラメーターは名前でも番号でも指定できるため、このプロパティは文字列と数値のどちらでも構いません。
複数形バリアントはpluralItemsプロパティに格納します。このプロパティは、複数形分岐パラメーターの値と複数形バリアントのマップです。
パラメーター名には次の形式を使用できます。
[^[[:Pattern_Syntax:][:Pattern_White_Space:]]]+
[:Pattern_Syntax:]と[:Pattern_White_Space:]はICU UnicodeSet(英語のみ)です。
パラメーター名にスペースを含めることはできません。
使用できる複数形分岐パラメーターの値は次のとおりです。
zeroonetwofewmany^(=[0-9]+)$other(必須:otherは常に指定する必要があります。これは、パラメーター値がほかのどのルールにも一致しない場合にトリガーされるルールです)
注: 複数形分岐パラメーターの値セットは言語によって異なります。英語では、=0、one、otherが使用されます。文法上、two、few、many、^(=[0-9]+)$に対応する明確なユースケースはありません。ソース文字列が英語の場合、後者の値がソースの複数形分岐構造化リソース値に現れることはありません。
ルールは、列挙ルールと数値ルールの2つのカテゴリーに分けられます。列挙ルールには、zero、one、two、few、many、otherがあります。名前は示唆的ですが、これらのルールが必ずしも「文字どおり」の意味になるとは限りません。ルールがトリガーされるロジックはロケールごとに異なります。たとえば英語では、oneルールは値が1の場合にトリガーされます。しかしこのルールは、日本語や中国語など、文法上複数形のない言語ではトリガーされず、ほかのいくつかのロケールでは、1で終わる数値(21、31など)のような異なる値に対してトリガーされます。
数値ルールは特定の値に一致します。後述の例では、=0ルールが値0に一致します。数値ルールは列挙ルールよりも優先されます。特定のメッセージを値に結び付けるには、数値ルールを記述する必要があります。たとえば、「あと1回でアカウントがロックされます」というメッセージを表示する場合は、oneルールではなく=1ルールを使用して、パラメーター値が1の場合にのみ常にメッセージが表示されるようにします。
リソースを英語で作成するときは、例で使用されている=0、one、otherのルールを常に記述してください。ローカリゼーションでは、翻訳プロセス中にほかのロケールで必要となるすべてのルールを生成する必要があります。必要に応じて、上記の=1の場合のような数値ルールを追加します。
複数形分岐構造化リソース値の例を以下に示します。
{
"resources": {
"message1": {
"value": {
"param": "appleCount",
"pluralItems": {
"=0": "You have no apples in a basket",
"one": "You have {appleCount,number,integer} apple in a basket",
"other": "You have {appleCount,number,integer} apples in a basket"
}
}
}
}
同じ例を番号パラメーターで記述すると、次のようになります。
{
"resources": {
"message1": {
"value": {
"param": 0,
"pluralItems": {
"=0": "You have no apples in a basket",
"one": "You have {0,number,integer} apple in a basket",
"other": "You have {0,number,integer} apples in a basket"
}
}
}
}
}
上記の例では、パラメーターが分岐条件に使用され、分岐項目の文にも出現しています。
複数形分岐の使用が適した場面
文に数値や価格を挿入する場合は、常に複数形分岐を使用します。以下に例を示します。
"You have 2 items in your cart"
または
"You will be charged $5 per item."
英語の文字列がすべての値で文法的に正しい場合でも、複数形分岐を使用してください。ほかの言語では、すべての値で文法的に正しくなるとは限らないためです。
複数形分岐の使用が適さない場面
数値や値が文の一部でない場合は、複数形分岐を使用しません。以下に例を示します。
"Number of items: 2"
または
"Price: $3.27"
複数形分岐タイプのサンプルユースケース
サンプルのユースケースを見てみましょう。ここでは、顧客のカートに入っている商品の数を表示するために、文字列に数値を挿入する必要があるとします。以下に例を示します。
"You have no items in your cart."
"You have 1 item in your cart."
"You have 2 items in your cart."
...
この例では、各ユーザーの言語で文法的に正しい結果が得られるように、複数形分岐構造化リソース値を作成する必要があります。これにより、複雑なMessageFormatパターンを編集したり読み取ったりする手間もなくなります。
推奨される方法: 以下の形式を強くお勧めします。複数形分岐構造化リソース値タイプでは、複数形分岐項目ごとに翻訳可能な文全体を記述します。これにより、翻訳者にとっての読みやすさが向上し、文字列の詳細なコンテキストが与えられます。また、文全体を提供すれば、言語の自然な流れに合わせて翻訳の語順を並べ替えることが容易になります。次の例には、翻訳者に追加情報を提供するコンテキストノートも含まれています。
{
"resources": {
"number-of-items-in-cart": {
"note": "cartItemsはカート内の商品の数を示すプレースホルダーです。",
"value": {
"param": "cartItems",
"pluralItems": {
"=0": "You have zero items in your cart.",
"one": "You have {cartItems,number,integer} item in your cart.",
"other": "You have {cartItems,number,integer} items in your cart."
}
}
}
}
}
推奨されない方法: 以下の形式は十分に考慮がなされていません。この場合、翻訳の語順に問題が生じる可能性があり、翻訳者がコンテキストを理解することも困難です。
{
"resources": {
"plural-message-format": "You have {cartItems,plural,=0 {zero items} one {{cartItems,number,integer} item} other {{cartItems,number,integer} items}} in your cart."
}
}
選択分岐タイプ
文字列に名前や名詞を挿入すると、その文法上の性別プロパティが、文字列内で関連するほかの単語に影響する可能性があります。MessageFormatの選択パターンは、文法上の性別に基づく語尾変化の処理を支援するように設計されています。詳細については、ICUのSelectFormatのドキュメント(英語のみ)を参照してください。
選択分岐構造化リソース値タイプは、MessageFormatの選択パターンの使用方法を簡素化するものです。このタイプは、任意の値を持つパラメーターに基づく分岐を表します。選択分岐構造化リソース値には、次の2つの必須プロパティがあります。
param: メッセージを選択するために使用する変数の名前。selectItems: パラメーター値が関連付けられた文字列のリスト。これらの項目から選択されます。
選択分岐パラメーターのIDはparamプロパティで指定します。MessageFormatパターン内のパラメーターは名前でも番号でも指定できるため、このプロパティは文字列と数値のどちらでも構いません。
分岐はselectItemsプロパティ内の項目として指定します。選択分岐項目のキーには、JSONの文字列型に適用される制限以外の制限はありません。
パラメーター名には次の形式を使用できます。
[^[[:Pattern_Syntax:][:Pattern_White_Space:]]]+
[:Pattern_Syntax:]と[:Pattern_White_Space:]はICU UnicodeSet(英語のみ)です。
パラメーター名にスペースを含めることはできません。
selectItemsのリスト内には、otherルールを含める必要があります。otherは、パラメーター値がほかのどの項目キーにも一致しない場合にトリガーされるルールです。
選択分岐構造化リソース値の例
{
"resources": {
"message2": {
"note" : "簡単な選択分岐の例",
"value": {
"param": "gender",
"selectItems": {
"female": "She has invited us for supper.",
"male": "He has invited us for supper.",
"other": "They have invited us for supper."
}
}
}
}
}
同じ例を番号パラメーターで記述すると、次のようになります。
{
"resources": {
"message2": {
"note" : "簡単な選択分岐の例",
"value": {
"param": 0,
"selectItems": {
"female": "She has invited us for supper.",
"male": "He has invited us for supper.",
"other": "They have invited us for supper."
}
}
}
}
}
上記の例では、パラメーターは分岐条件にのみ使用され、どの分岐項目の文にも出現していません。
選択分岐タイプのサンプルユースケース
サンプルのユースケースを見てみましょう。ここでは、ホストの性別に応じて、次の文字列のいずれかを表示する必要があるとします。
"{hostName} invites you to her party."
"{hostName} invites you to his party."
"{hostName} invites you to their party."
これを実現するには、選択操作のパラメーターとして文字列を使用する選択分岐構造化リソース値を指定します。selectItemsには、項目の1つとしてotherルールを指定する必要があることに注意してください。
{
"resources": {
"party-invitation": {
"note" : "hostGenderはホストの性別を表す文字列パラメーターです。hostNameはホスト名のプレースホルダーです。",
"value": {
"param": "hostGender",
"selectItems": {
"female": "{hostName} invites you to her party.",
"male": "{hostName} invites you to his party.",
"other": "{hostName} invites you to their party.",
}
}
}
}
}
入れ子
文は、2つ以上の複数形分岐パラメーターや選択分岐パラメーターに応じて変化する場合があります。
There are 3 warnings and 1 error.
これは回避できる場合もありますが、状況によっては、複数のパラメーターをサポートし、それらのパラメーターに基づいて分岐することが実際に必要になります。これを実現するには、構造化リソース値を入れ子にします。
複数形分岐や選択分岐の各項目は、数値、文字列、複数形分岐、選択分岐のいずれかのタイプにすることができます。したがって、複数形分岐と選択分岐の構造化リソース値を入れ子にすることが可能です。最も深い階層の複雑な形式の項目が、翻訳文全体を表します。
入れ子になった構造化リソース値の例
{
"resources": {
"party-invitation-status": {
"note" : "guestCountは招待されたゲストの数を表す数値パラメーターです。hostGenderはホストの性別を表す文字列パラメーターです。hostNameはホスト名の文字列プレースホルダーです。",
"value": {
"param": "guestCount",
"pluralItems": {
"=0": {
"param": "hostGender",
"selectItems": {
"female": "{hostName} did not invite any guests to her party.",
"male": "{hostName} did not invite any guests to his party.",
"other": "{hostName} did not invite any guests to their party."
}
},
"one": {
"param": "hostGender",
"selectItems": {
"female": "{hostName} invited one guest to her party.",
"male": "{hostName} invited one guest to his party.",
"other": "{hostName} invited one guest to their party."
}
},
"other": {
"param": "hostGender",
"selectItems": {
"female": "{hostName} invited {guestCount,number,integer} guests to her party.",
"male": "{hostName} invited {guestCount,number,integer} guests to his party.",
"other": "{hostName} invited {guestCount,number,integer} guests to their party."
}
}
}
}
}
}
}
上記の例は、構造化リソース値を入れ子にして、2つのパラメーター(複数形分岐用と選択分岐用)に依存するローカライズメッセージの分岐を定義する方法を示しています。3番目のパラメーター{hostName}は、分岐項目の選択とは関係のないほかのパラメーターを複数形分岐や選択分岐に含めることができる例として追加されています。
エスケープ構文
PUFF-Jの文字列は、標準のJSONの定義(英語のみ)に従います。
文字列は、0文字以上の連続するUnicode文字を二重引用符で囲んだものです。エスケープにはバックスラッシュが使用されます。文字は単一文字の文字列として表されます。文字列はCやJavaの文字列とよく似ています。
複数行の文字列
JSONの定義では、複数行の文字列はサポートされていません。改行文字はすべて\nに置き換える必要があります。
Last updated: 2025年9月30日

