Bug(バグ) #2490
完了翻訳ファイルの優先順位がキャッシュ時に逆になっている
100%
説明
概要¶
i18n 翻訳用のメッセージファイルは複数ファイルで同じ語に対する翻訳を記述した場合、「モジュール → アプリケーション → 全体」の優先順に読み込まれる仕様であるが、翻訳ファイルのキャッシュを生成する過程の処理に誤りがあり、この優先順位が逆になってしまう問題がある。
これにより mobile_frontend 用の i18n ファイルに半角カタカナのエントリーを追加しているにもかかわらず、全角カタカナが表示されてしまうような現象が発生する。
なお、キャッシュファイルがない状態でアクセスした場合にはこの現象は発生しない。
詳細¶
opI18N::generateApplicationMessages() でキャッシュファイルを生成するが、この中で複数の i18n のメッセージファイルの内容をマージする処理で優先度の低いファイルの内容を優先してマージをしてしまっている。
opI18N::generateApplicationMessages() の引数 $dirs には優先度の高い順にディレクトリパスが格納された配列が渡されるが、foreach のループ内では後の値を前の値よりも優先させる形で array_merge() を使っているために本来の優先順位と逆の内容のキャッシュファイルが生成されていた。
修正前のコード:
public function generateApplicationMessages($dirs) { $catalogues = array(); ... foreach ($files as $file) { ... $data = $messageSource->loadData($file); $catalogues[$name] = array_merge($catalogues[$name], $data); }
確認バージョン¶
OpenPNE 3.7.0-dev (master)
OpenPNE 3.6.1 (stable-3.6.x)
Maki Takahashi さんが約13年前に更新
- 説明 を更新 (差分)
- ステータス を New(新規) から Accepted(着手) に変更
- 担当者 を Maki Takahashi にセット
Maki Takahashi さんが約13年前に更新
- ステータス を Accepted(着手) から Pending Review(レビュー待ち) に変更
- 進捗率 を 0 から 50 に変更
更新履歴 7047ccf4ebcc6891319e783d1c10142e9d45b6e3 で適用されました。
Minoru Takai さんがほぼ13年前に更新
- 優先度 を Normal(通常) から High(高め) に変更
この問題の重要度についてコメントします。
これにより mobile_frontend 用の i18n ファイルに半角カタカナのエントリーを追加しているにもかかわらず、全角カタカナが表示されてしまうような現象が発生する。
チケットで示されている内容が正しいと仮定すると、 OpenPNE 側の実装に誤りがあるために、国際化の機構(i18n による機能)について、キャッシュが使われるときと使われないときで動作結果が異なり、上記の引用内容のような不具合を生じさせているということになります。
キャッシュが使われる場合に、翻訳ファイルが適切に(想定される順序で)適用されないことは、適切に翻訳ファイルを用意している場合であっても上記のような問題が起こることだけでなく、この問題の原因が分からない開発者が翻訳関連でこの問題に遭遇したときに不毛な調査を要してしまうことが懸念されます。
この問題は可及的速やかに対応すべきと考えます。これを示す意味でチケットの優先度を High に設定します。
Kousuke Ebihara さんがほぼ13年前に更新
- ステータス を Pending Review(レビュー待ち) から Rejected(差し戻し) に変更
- 3.6 で発生するか を Unknown (未調査) にセット
- 3.4 で発生するか を Unknown (未調査) にセット
この修正により、たとえば携帯版ログイン画面において、「ログイン」と翻訳されていた文言が「ログイン」に置き換わってしまいます。
このチケットで修正された opI18N::generateApplicationMessages()
の第一引数の $dir
は、「優先度の高い順に i18n ディレクトリのパス文字列が格納された配列」ですので、修正内容自体は正しいように見えます。ですが、肝心の $dir
の順序が間違っているために、この修正を適用することで、前述の「ログイン」のように誤った翻訳がなされる箇所が出てきてしまいます。
opI18N::generateApplicationMessages()
に渡される引数は opApplicationConfiguration::getI18NDirs()
により生成されたものです。したがって、この修正を適用するためには、併せて opApplicationConfiguration::getI18NDirs()
も修正する必要があります。
opApplicationConfiguration::getI18NDirs()
により生成される配列要素の順序は以下のようになります(太字は sfApplicationConfiguration::getI18NDirs()
の生成した配列要素)。
0. [sf_root_dir]/i18n
1. plugins/op*Plugin/apps/[app_name]/i18n
2. plugins/op*Plugin/apps/[app_name]/modules/[module_name]/i18n
3. apps/[app_name]/modules/[module_name]/i18n
4. apps/[app_name]/i18n
5. plugins/*/modules/[module_name]/i18n
6. plugins/*/i18n
しかし、これは期待通りの結果ではありません。上述の結果を、期待通りの順番に並び替えたものが以下です。
2. plugins/op*Plugin/apps/[app_name]/modules/[module_name]/i18n
1. plugins/op*Plugin/apps/[app_name]/i18n
3. apps/[app_name]/modules/[module_name]/i18n
4. apps/[app_name]/i18n
0. [sf_root_dir]/i18n
5. plugins/*/modules/[module_name]/i18n
6. plugins/*/i18n
この並び順は以下のような考え方に基づいています。
- OpenPNE 3 プラグインのディレクトリ(
plugins/op*Plugin/
以下)は、 OpenPNE 3 本体よりも優先される - OpenPNE 3 本体のディレクトリは、 symfony プラグインのディレクトリ(
plugins/*/modules
とplugins/*/i18n
)よりも優先される?
これは、『symfony 1.4 による Web アプリケーション開発』(拙著/共著)の p399 に記載されている考え方に沿っています。以下に引用します。
このような symfony プラグインと OpenPNE プラグインとの差異は、 symfony プラグインが「symfony を拡張する」という役割を担っており、拡張された symfony を利用して開発を進めていくことを想定しているのに対し、 OpenPNE プラグインの場合は、「既に完成された symfony アプリケーションを拡張する」という役割を担っているというところから生じています。
ということで、これでよさそうに思いますが、「0. [sf_root_dir]/i18n
」の順番が妥当かどうかは若干怪しいところです(このディレクトリの立ち位置はいまひとつ明確でない気がしています)。
なので、 [sf_root_dir]/i18n
に関してだけはとりあえずこの修正前の挙動を維持する形で、以下のような順序にすることもアリだと思います。ちなみに、この順序ならば sfApplicationConfiguration::getI18NDirs()
の結果が利用できます。
2. plugins/op*Plugin/apps/[app_name]/modules/[module_name]/i18n
1. plugins/op*Plugin/apps/[app_name]/i18n
3. apps/[app_name]/modules/[module_name]/i18n
4. apps/[app_name]/i18n
5. plugins/*/modules/[module_name]/i18n
6. plugins/*/i18n
0. [sf_root_dir]/i18n
Maki Takahashi さんがほぼ13年前に更新
- ステータス を Rejected(差し戻し) から Pending Review(レビュー待ち) に変更
更新履歴 cbab5cb65cdb2876bf02054ec0768df186e312b0 で適用されました。
Kousuke Ebihara さんがほぼ13年前に更新
- ステータス を Pending Review(レビュー待ち) から Rejected(差し戻し) に変更
この修正により生成されることになる配列要素の順序は以下のようになります。
1. plugins/op*Plugin/apps/[app_name]/i18n
2. plugins/op*Plugin/apps/[app_name]/modules/[module_name]/i18n
3. apps/[app_name]/modules/[module_name]/i18n
4. apps/[app_name]/i18n
5. plugins/*/modules/[module_name]/i18n
6. plugins/*/i18n
0. [sf_root_dir]/i18n
これは http://redmine.openpne.jp/issues/2490#note-4 にて示した見解とは異なります(1 と 2 の順序が違う)。これは意図したものなのでしょうか。
モジュールに与えられた翻訳よりもアプリケーションに与えられた翻訳を優先する妥当な理由はないように思います。
Maki Takahashi さんがほぼ13年前に更新
- ステータス を Rejected(差し戻し) から Pending Review(レビュー待ち) に変更
更新履歴 aef957686b79094fe51dd5fad3c5a3e9b144f59a で適用されました。
Kousuke Ebihara さんがほぼ13年前に更新
- ステータス を Pending Review(レビュー待ち) から Pending Testing(テスト待ち) に変更
- 進捗率 を 50 から 70 に変更
Shouta Kashiwagi さんが12年以上前に更新
- ステータス を Pending Testing(テスト待ち) から Fixed(完了) に変更
- 進捗率 を 70 から 100 に変更
テストOKです。