Magentoに関わり始めた頃、一番苦しんだのは翻訳作業でした。今から6年ほど前のことです。
当時はまだMagentoが最初の正式版になる直前で、この頃のロケールデータは頻繁に変更が入っていました。
さすがに正式版リリース後はなくなりましたが、未だに当時行った作業の残骸が残っている箇所があり、多くの方に迷惑をかけてしまっています。

さて、このエントリではMagentoの翻訳機能の仕組みについて解説します。
Magentoがどういう流れでロケールデータを読み込み、どの順で適用しているか。またどのように書くことで適切にロケールが適用されるかを解説します。

Magentoのロケールデータの分類

Magentoには大きく分けて3種類のロケールデータ・ファイルがあります。

  • モジュール固有のロケールファイル
  • テーマ固有のロケールファイル
  • インライントランスレータによるロケールデータ

一般的に各国のコミュニティによって作成・配布されているのは、「モジュール固有のロケールファイル」です。
Magentoコアモジュールのロケールファイルがパッケージングした状態で配布されています。

モジュール固有のロケールファイル

モジュール固有のロケールファイルは、「app/locale」ディレクトリ以下に配置されているCSVファイルです。
サードパーティ製のエクステンションについては各開発元が作成して、エクステンションに同梱した形で配布しています。

たいていのエクステンションではen_USやja_JPといった開発元に所属している開発者が扱える言語が同梱されています。
それ以外の言語については、利用者が自分で作成する必要があります。
なお、ロケールファイルが付属しないエクステンションの場合は、プログラム上に書かれている文字列がそのまま画面に表示されます。 

テーマ固有のロケールファイル

テーマ固有のロケールファイルは、フロントエンドとバックエンドそれぞれに作成することができるロケールファイルです。
もちろんテーマ別に作成できるため、マルチサイト運用時にはサイト別に異なる文言を出力する、ということも可能です。 

インライントランスレータによるロケールデータ

Magentoの初期バージョンから搭載されている便利機能「インライントランスレータ」を使って、サイト上の文言を修正すると、このデータが作成されます。
インライントランスレータを使って作成したロケールデータはすべてデータベースに格納されていくのですが、エクスポート・インポート機能が標準では備わっていません。
テストサイトから本番サイトへデータを受け渡したい場合は、SQLを使ってテーブルのデータを取り出すか、サードパーティ製のエクステンションを利用する必要があります。

ロケールの適用優先度

ロケールは次の順番に適用されるようになっています。(数字が大きいほど優先度は高くなります)

  1. モジュール固有のロケールファイル
  2. テーマ固有のロケールファイル
  3. インライントランスレータによるロケールデータ

つまり、インライントランスレータによるロケールデータは全てに優先して適用されるということです。
ただしインライントランスレータは前述のとおりデータベースに格納されるため、移行ツールがなければその環境固有のデータになってしまいます。

そのため、サードパーティ製のエクステンションを使わず、かつテーマ別にロケールを変えたい場合には、テーマ固有のロケールファイルを活用する方法が安価かつ便利であると言えます。

ロケールファイルの書き方

Magentoのロケールファイルは基本的にCSVファイルです。
以下のルールにもとづいて作成されているので、作成・編集は容易です。

  • 文字コードは必ずUTF-8であること
  • フィールドは「"」で括ること
  • フィールドの区切り文字列は「,」であること
文字コードがUTF-8なので、ExcelやOpenOfficeで編集するのは避けたほうがよいでしょう。
Windowsの場合はCSV編集専用のフリーソフトも多数ありますので、UTF-8の読み書きができるものを使うのがお勧めです。 

 

ダブルクオート

ロケールファイルのフィールドは必ずダブルクオート(")で括ります。
そのため。HTMLタグを書きたい場合には注意が必要です。そのままダブルクオートを1個だけ書いてしまうと、フィールドが途中で終わってしまい、CSVファイルの読み込みでエラーが出ます。
どうしてもダブルクオートを書きたい場合は、以下の例のように書きます。

"Click <a href=""%s"" onclick=""this.target=\'_blank\'"">here to print</a> a copy of your order confirmation."

 例ではダブルクオートを2つ重ねています。これはSQLなどではよく用いられる「エスケープ」という方法です。
ダブルクオートを2つ重ねることで、ダブルクオート自体の意味を打ち消します。こうすることでロケールエントリ上にHTMLタグなどを書き込むことができるようになります。

シングルクオート

ロケールファイル上にはシングルクオート(')も当然存在します。
Magentoのモジュールやテンプレート上では、

$this->__('Click <a href="%s" onclick="this.target=\'_blank\'">here to print</a> a copy of your order confirmation.', $this->getPrintUrl()) 

というような記述が存在します。
これに対応するロケールエントリは、ダブルクオートのところで紹介したように書かれているのですが、これは実際には動作しません。
というのも、PHPの言語仕様では文字列を囲む記号としてシングルクオートもダブルクオートも使えます。

ダブルクオートで文字列を囲んだ場合、その中にPHPの変数を書くことができ、その変数は出力時に自動的にPHPによって格納している値に変換されます。
シングルクオートではこの処理は行われないため、マイクロ秒レベルの差ではありますが、積もり積もるとミリ秒レベルの差になります。
そのため、パフォーマンスを重視する書き方をする場合は、文字列をシングルクオートで囲む書き方をします。

前述のプログラム例では、文字列をシングルクオートで囲んでいます。ところが、その文字列中にシングルクオートが存在しています。
そのまま処理させるとエラーになってしまうため、バックスラッシュ(\)でこれまた無効化しています。

ですが、ロケールエントリを作る際にはこのバックスラッシュは実は不要です。
バックスラッシュは自動的に取り除かれた状態でMagentoはロケールエントリを探しに行くため、バックスラッシュを含んだロケールエントリをいくら翻訳しても正しく翻訳されません。
このような場合はロケールエントリを以下のように書きます。

"Click <a href=""%s"" onclick=""this.target='_blank'"">here to print</a> a copy of your order confirmation." 

このように書くことで、正しく処理されるロケールエントリを作ることができます。

変数の埋め込み

ロケールエントリには変数を埋め込むことができます。
まず例を示しましょう。

"%d Shopping Cart Price Rules based on ""%s"" attribute have been disabled."

"Buy %1$s for %2$s (%3$s incl. tax) each"

最初の例では、「%d」「%s」という2つの文字があります。これは「%d」が数字、「%s」が文字列を意味していて、ロケールを処理する際に与えられた変数を自動的に割り当てるようになっています。このような記述はMagentoのロケール上でよく見られます。

2番めの例では、「%1$s」「%2$s」「%3$s」「%4$s」という文字列があります。
この書き方を用いると、ロケールを処理する際に与えたパラメータのうち、何番目のものを使用するかを明示することができるのです。
最初の例ではこの書き方をしていないので、「%d」が1番目、「%s」が2番めのパラメータを自動的に使用します。

もし、言語によって順番を入れ替えないと不自然になるようなロケールエントリを作らなければならない場合は、変数の順番を指定する書き方をしたほうが翻訳作業がしやすいと思います。

テーマ固有のロケールファイル

最後にテーマ固有のロケールファイルの作り方について解説します。
テーマ固有のロケールファイルは、必ず「translate.csv」というファイル名で、

app/design/(frontend|adminhtml)/デザインパッケージ名/テーマ名/locale/言語コード/translate.csv

というパスに作成します。
基本的な作成方法はモジュール固有のロケールファイルと変わりません。
ただし、1点だけ異なる点があります。 

モジュール固有のロケールファイルとの違い

モジュール固有のロケールファイルは、モジュールごとにファイルがわかれているため、同じ文字列のロケールエントリであっても、モジュールが異なれば別の訳を適用することができます。

ところがテーマ固有のロケールファイルは1つしかファイルが存在しないため、モジュールを識別することができません。

モジュールをtranslate.csv上で識別させたい場合は、以下のように書きます。

"Mage_Customer::Log In","ログイン"

要はロケールエントリの前に、「モジュール名::」を追加するわけです。
こうすれば、モジュールを識別できるようになるため、異なる訳を当てることができるようになります。

もちろん、そのテーマでしか使わないロケールエントリや、すべてのロケールエントリの中で1つしかそのエントリが存在しない場合は不要です。
この方法は複数のモジュールが同じ文字列のロケールエントリを持っていて、それをテーマ側で変更したい場合に使用します。

まとめ

  • Magentoには3つのロケールデータがある
  • モジュール固有 < テーマ固有 < インライントランスレータ の順に優先度は高くなる
  • インライントランスレータで翻訳したデータは、標準ではほかのサイトに移植することはできない
  • ダブルクオート・シングルクオートの扱いに注意する
  • 変数を使用する場合は言語による文脈の変化を考慮しておくと後で多言語展開が楽
  • テーマ固有のロケールファイルを作る場合は、「translate.csv」というファイル名で作成する
  • 複数のモジュールで同じ文字列のロケールエントリがある場合は、translate.csv上では「モジュール名::」をつけて区別する