CakePHP3を触ってみました 〜ちょっとだけグローバル気分〜

この記事はだいぶ前に書かれたものなので情報が古いかもしれません
エイプリルフールのネタだそうです

この記事を三行にまとめると

いってみよーやってみよー
Follow me!!(CV:東山奈央)
I love youを831と書くようなもんかな?
ウェブサイトを多言語に対応する方法ってのは、いくつか考えられると思います。例えば日本語と英語のページを作る場合、二つのページを用意するとか、シンプルに二つの言語を並べて表記するとか、データベースに言語データ全部突っ込んで切り替えるとか。

今日はそのどれでもなくて、翻訳ファイル(言語ファイル?)ってのを作って、表示を切り替えてみようと思います。難しいことはやりません。「hello」の文字を、日本語で「こんにちは」と切り替えられるようにする程度です。

ではでは、いってみよーやってみよー。



先に書いとくね

これはCakePHP2も3も共通なので、先に書いときますね。

どうやって英語と日本語の表示を切り替えるかって話なんですが、「default.po」というファイルを作って、そこに「hello」と「こんにちは」を記述して切り替えるというやり方です。default.poの中身とビューを、それぞれこんな風にします。

//deafult.po
msgid "hello"
msgstr "こんにちは"

//ビュー
echo __('hello');

これでhelloとこんにちはを切り替えることができます。echoの後ろはアンダーバー二つ使ってます。

ようは、default.poの中にある「msgid」ってやつの値を書けば、それに対応する「msgstr」の文字が出力される感じです。

こうなるように、必要な設定を行ってゆきます。ババーッと説明していくんで、遅れるなよ。Follow me!!(CV:東山奈央)



CakePHP2の場合

ほんじゃあ、毎度お馴染みの、ちり紙こ……まずはCakePHP2系での話。

細かい説明は後にして、とりあえず、今回の作業に関わってくる部分を切り出したフォルダ構成をば。

/cakephp
  ├ /app
  │   └ /Locale
  │       └ /jpn
  │           └ /LC_MESSAGES/
  │               └ default.po
  └ /Cake    
      ├ /Console
      │   └ cake
      └ /I18n
          └ L10n.php

人によっては、CakeフォルダはLibってフォルダの下にあるかもしれませんが、その辺は各々確認してもらうってことで……。

今回作成する「default.po」は、「Locale」というフォルダの下に作成します。ちょい階層が深いですが、Localeというフォルダの下に、必要な言語用のフォルダを作って、その下にさらに「LC_MESSAGES」というフォルダを作って、そこにdefault.poを置きます。

今回は日本語用にファイルを作るので、「jpn」というフォルダを作りました。何でjpnかってーと、上の図の中に「L10n.php」というファイルがありますが、この中に、各言語のID(ロケールIDとか言うそうです)に対応したフォルダ名の配列が書いてあります。日本語の場合、ロケールIDは「ja」なのですが、それに対応する配列のキーを見るとjpnとなっています。なので、フォルダ名をjpnにしています。

他の国の言語に対応したい時は、このL10n.phpの中を見ればどんなフォルダ作れば良いか分かります。



翻訳ファイルは、単純にdefault.poというファイルを新規作成してもダメです。i18nコマンドを使って作らないといけない。sshなどでサーバーに接続してください。

i18nコマンドを使うには、cakeコマンドを実行する必要があります。cakeコマンドは、上の図にもありますが、CakeコアライブラリのConsoleフォルダの中にあります。なので、コマンドを実行する際は、Consoleフォルダまで移動するか、cakeコマンドまでの絶対パを指定して実行します。

# /Consoleまでのパス/cake i18n

i18nってのは「internationalization」の略なんだそうです。iとnの間に18文字あるから、i18nなんだって。I love youを831と書くようなもんかな?

i18nコマンドを実行すると、サーバーから「何のファイル作る?」「どこに作る?」「子供作る?」「私のこと愛してる?」みたいなことをいろいろ質問されるので、順番に答えていきましょう。

これも先に、一連の流れだけ書いちゃいましょっか。

//何のファイルを作る?(Eを選択)
[E]xtract POT file from sources
[I]nitialize i18n database table
[H]elp
[Q]uit
What would you like to do? (E/I/H/Q) 

//どこから抽出する?(一度エンターを押した後、Dを選択)
Current paths: None
What is the path you would like to extract?
[Q]uit [D]one  
[/現在のパス/] > 

//コアからも抽出する?(yを選択)
Would you like to extract the messages from the CakePHP core? (y/n) 

//翻訳ファイルをどこに作る?(フォルダのパスを指定)
What is the path you would like to output?
[Q]uit  
[/現在のパス/] > /cakephpまでのパス/app/Locale/jpn/LC_MESSAGES/

//出力ファイルは一つにまとめとく?(yを選択)
Would you like to merge all domain and category strings into the default.pot file? (y/n) 

最初の質問は「何のファイルを作る?」と訊かれているので、POTファイルを作ると答えます。Eを選択してエンター。

次に「どこから抽出する?」みたいなことを訊かれてます。Dを選択すると次に進むのですが、「Current paths」が「None」になっている状態でDを選択するとエラーになるので、まずは任意のフォルダのパスを指定してエンターを押す必要があります。何も入力せずにエンターを押すと、現在のパスがCurrent pathsにセットされます。

何を抽出するかっていうと、たぶんなんですけど、default.poを作成する際、指定したフォルダの下にあるファイルの中から「__(‘xxx’)」のxxxを抽出してmsgidにセットするとか、そんな感じの動きをしているような気がします。なので、例えば「/cakephp/app/」とかを指定すると、appフォルダの中にある全ファイルの中から「__(‘xxx’)」を抽出しようとします。LibとかVendorに大量のファイルが入っていると、default.poの作成に時間がかかってしまうので、必要ないなら、どこか適当な空のフォルダでも指定しときましょう。

ただし、一つだけ注意。

次の質問で「コアからも抽出する?」みたいなのを訊かれますが、もしここでノー(n)と答えた場合、空のフォルダを指定していると、ファイルが作成されません。たぶん、抽出するものが一つもないと、ファイルはできないのかも。もし空のフォルダを指定するなら、コアからの抽出はイエスと答えましょう。イエスと答えると、Cakeのコアライブラリが抽出対象になります。

何言ってるかよく分かんねーって場合は、とりあえず自信を持ってイエス(^_-)bと答えとけば大丈夫ってことだ。

続いて「翻訳ファイルをどこに作る?」という質問。さっきも言った通り、Localeフォルダの中のjpnの中のLC_MESSAGESの中に作るので、そこまでのパスを指定します。こっちも、何も入力せずにエンターを押すと、現在のパスにファイルが作られます。後で移動させるなら、それでも問題ないです。

最後は「出力ファイルは一つにまとめとく?」みたいな質問です。これもイエスと答えとけば大丈夫でしょう。



一通り質問に答えると「default.pot」というファイルが出来上がります。ここで気をつけたいのが、拡張子が「po」じゃなく、「pot」であること。このままだと使用できないので、手で拡張子をpoに直します。LC_MESSAGESフォルダの下にない場合は、ファイルを移動させてください。

default.poになったら、冒頭に書いた通り、msgidにhello、msgstrにこんにちはを設定して保存すれば、こんにちはと表示されるはずです。

もしされない場合は、現在の環境が日本語の設定になってない可能性がありますので、こんな一文を足してみてください。

Configure::write('Config.language', 'ja');

AppController.phpのbeforeFilter()に書いても良いし、bootstrap.phpとかでも大丈夫。



CakePHP3の場合

2の説明だけで随分長くなっちゃったな……まあいつものことか。

CakePHP3で翻訳ファイルを使う場合も、基本的なことは一緒です。poファイルを作るパスがちょっと違うだけで、作り方は一緒。

3系の場合、フォルダ構成はこんな感じです。

/cakephp
  ├ /bin
  │   └ cake
  └ /src
      └ /Locale
          └ /ja
              └ default.po

CakePHP3では、実行ファイルはbinというフォルダの下にあります。というこで、i18nの実行コマンドも以下のように変わります。

# /binまでのパス/cake i18n

あとは一緒です。質問に答えていけば、default.potファイルができるので、これをdefault.poに直せばオーケー。

CakePHP2と違うのは、Localeの下のフォルダ名が「jpn」じゃなくて「ja」であることと、「LC_MESSAGES」というフォルダは作らなくて良いってところですかね。

CakePHP3には、L10n.phpというファイルが存在しません。フォルダ名に指定するための配列も、見当たりませんでした。

これもたぶんって話ですが、CakePHP3は、インストール時に国際化関数(intl)のインストールも必須になります。だからLocale関数を使うことが前提の動きになってるっぽいです。I18n.phpはCakePHP3でも健在ですが、その中でLocale関数を使ってロケールIDの取得なんかもやっているようなので、それをフォルダ名に使えってことなんでしょう。



ちなみに、先ほどのCakePHP2の時と同様、もし現在の環境が日本語になってないっぽいぞって場合は、この一行をbootstrap.phpに足してください。

ini_set('intl.default_locale', 'ja_JP');

これで大丈夫なはず。もしかしたら「ini_set(‘intl.default_locale’, ‘ja’)」でもいけるかもしれない。






てな感じで、多言語対応のさわりをやってみましたー。

正直なところ、この翻訳ファイルを作る作業は、CakePHP2の方でもやったことありませんでした。でも良い機会だったので、2と3、両方で試してみました。

多言語対応自体はやったことあるんですけど、その時は管理画面でちょくちょく表示内容を更新したいってことだったので、日本語と英語の言語データを全部データベースに突っ込んで、システムで切り替えてました。切り替え方自体は、このpoファイルを使った場合とほぼ同じだと思います。ヘッダーの情報を見てデフォルトの言語を取得して、あとはユーザーが任意に言語を切り替えたら、そっちを優先するみたいな。それがベストなやり方なのかどうかは、未だに自分でもよく分かりません。

どっちが楽かって言われたら、今回やった翻訳ファイルを作る方が楽なんだけど、開発者以外の人が管理画面で簡単に編集できるようにってなると、データベースを使った方が楽な気もするし……こういうのはやっぱり、仕様次第ってことなんですかね?



その他のCakePHP3を触ってみましたの記事はこちら
まとめという名の箸休め
 もしかしたら何か関連しているかも? 
 質問や感想などお気軽にコメントしてください