CakePHP2を使用して多言語化

CakePHPを用いて多言語化をする方法をまとめます。
今のご時世、複数言語でサービスを運用するのは当たり前になりつつあります。
少なくとも1つのサービス内で、日本語、英語くらいは切り替えたいですよね。

今回はi18nを使用して多言語化をはかりたいと思います。
i18nに関しては以下のページを参考にしてみてください。

I18N【国際化】 – IT用語辞典

国際化と地域化 – Wikipedia

それでは多言語化の手順を紹介していきます。

CakePHPのインストール

まずはCakePHPをインストールしましょう。
今回はわかりやすいように

インストール→コントローラ、ビューの作成→i18nを使って多言語化

をしようと思います。
それでは以下からダウンロードしましょう。

CakePHP – github

【tmpフォルダ書き込み権限付与】
解凍してアクセス場所に置いたら、tmp/を書き込み可能にしましょう。

cd path/to/cakephp/app
chmod -R 707 tmp/

【Security.saltの更新】
適当な文字列を生成しましょう。
Config/core.php 内のSecurity.salt,Security.cipherSeed部分を更新しましょう。
いつもがちゃがちゃキーボード叩いて出来るだけランダムにしようとしています。

【データベースの設定】
今回データベースは使いませんがエラーメッセージ出てるのが気持ち悪いので適当なデータベースを設定しておきましょう。
database.php.defaultをコピーして名前をdatabase.phpに変更後、サーバー名などを入力してください。

【routes.phpの設定】
これからHogeController.phpを作成するのだが、デフォルトの状態だとPagesController.phpが表示されてしまう。
以下のように設定しよう。

Router::connect('/', array('controller' => 'hoges', 'action' => 'index'));

とりあえず準備は完了しました。

画像を見てもわかると思いますが、今回はCakePHP2.2.1を使用しています。

Controller,Viewの作成

それではControllerを作成しよう。
Controller/HogesController.phpを作成します。

<?php
class HogesController extends AppController {
        public function index(){

        }
}

特に何もしていない。
次はView。
View/Hoges/index.ctpを作成しよう。

<h2><?php echo __('Intermationalization');?></h2>
<p><?php echo __('Test now');?></p>

ここで (‘ ‘)で囲んだ部分がのちのち、i18nで翻訳する部分です。
翻訳する部分は全て
(‘ ‘)で囲もう!
__はアンダーバー2個なので注意!!

もちろん中にいれる文章が日本語でも問題ない。

※例えば翻訳したい部分に変数などが入っている場合は以下のようにするとなんとかなる。

$lang = 'Japanese';
echo sprintf(__('%s version'), $lang);

それではこれをブラウザで表示してみよう。
以下のようになる。

それではこの画面をi18nを使用して日本語表示にしてみよう。

POファイルを作成する

これからはコンソールで作業する。

cd /path/to/cakephp/Console
./cake i18n -app /path/to/cakephp/app

cakeを実行すると下記のようになる。

---------------------------------------------------------------
I18n Shell
---------------------------------------------------------------
[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)
>

POTファイルを作成するので「E」をタイプしてEnterする

What is the path you would like to extract?
[Q]uit [D]one  
[/path/to/cakephp/app/] > 

抽出元は?と聞かれるのでそのままEnterを押す

What is the path you would like to extract?
[Q]uit [D]one  
[D] > 

出力先は?と聞かれるのでこれもそのままEnterを押す

Would you like to extract the messages from the CakePHP core? (y/n) 
[n] > 

1つのファイルに翻訳ファイルをまとめるか聞かれるのでここは「y」にして1つにまとめておく。
「n」にすると別々のファイルで作成される。

出力中…

Processing /home/daiki/public_html/cakephp/app/Controller/HogesController.php...
Processing /home/daiki/public_html/cakephp/app/View/Hoges/index.ctp...
Processing /home/daiki/public_html/cakephp/app/View/Layouts/default.ctp...


Done.

完了したので「Q」を押してスクリプトから抜けだそう。
/cake/to/path/Console に default.potというファイルが出来ているはずである。
この default.pot というファイルを /cake/to/path/Locale/jpn/LC_MESSAGES/ に default.po というファイル名でコピーしよう。
途中のフォルダがない場合は作成しよう。

移動させたファイルである default.po ファイルをテキストエディタでひらいてみよう。

#: View/Hoges/index.ctp:1
msgid "Intermationalization"
msgstr ""

#: View/Hoges/index.ctp:2
msgid "Test now"
msgstr ""

msgidが元の文章、msgstrに翻訳する文章を入れる。
それでは上記のファイルに以下のように書いてみよう。

#: View/Hoges/index.ctp:1
msgid "Intermationalization"
msgstr "国際化"

#: View/Hoges/index.ctp:2
msgid "Test now"
msgstr "テストなう"

上書き保存したら、ブラウザでさきほどの画面を更新してみよう。
以下のように表示されるはずである。

やった!多言語化出来た!!

多言語化のテスト

ただこのままでは国を移動しない限り日本語で表示され続けてしまう。
これはブラウザがサーバーに送信するヘッダー情報から言語情報を抜き出してCakePHPが判断しているからである。
それでは日本にいながら英語を表示するためにはどうしたらいいのか。
以下の関数をAppController.phpのbeforeFilter()にでも書けば英語に戻る。

function beforeFilter() {
    Configure::write('Config.language', 'en');
}

更新してみよう。ほら、英語にもどった!

さて、ここまで作業をした人は気づいたことだろう。
/cake/to/path/Locale に作成した英語のPOファイルを格納するフォルダ名は eng
しかし日本語にするためには Configure::write で指定するときは en
になる。
つまりフォルダ名と関数に指定するものが違うのである。

これはどこで指定しているかというと、 /cake/to/path/lib/Cake/I18n/L10n.php の $_l10nMap で指定してある。
ここでは配列で指定してあるが、キーがLocale内のフォルダ名、値が Configure::writeで指定する文字列となる。

つまりまとめるとこうなる。

例えば中国語を新たに追加するとする。
/cake/to/path/lib/Cake/I18n/L10n.php の $_l10nMapを見てみると中国語は以下のように書いてある。

/* Chinese */ ‘chi’ => ‘zh’,

よって、

◯ /cake/to/path/Locale/chi/LC_MESSAGES を作成し default.poをコピー
◯ テストする場合は Configure::write(‘Config.language’,’zh’);

以下に使うことが多いとおもわれるものをリスト化しておく。参考にしてほしい。

/* Chinese */ ‘chi’ => ‘zh’(英語でChinese)
/* Chinese */ ‘zho’ => ‘zh’(中国語でZhongwen)
/* English */ ‘eng’ => ‘en’
/* French (Standard) */ ‘fre’ => ‘fr’
/* French (Standard) */ ‘fra’ => ‘fr’
/* Japanese */ ‘jpn’ => ‘ja’

これで多言語化は完璧なはず!

もしよかったらいいね!またはツイートを押していただけると嬉しいです。