どっちがいいんだろう?
$=jQuery; // 1 $('#f').on('click x', function(e){ alert('do'); })).trigger('x'); // 2 $('#f').on('click', (function(){ var f = function(){ alert('do'); }; f.call(); return f; });
なんかほかにもあったような気がする。
どっちがいいんだろう?
$=jQuery; // 1 $('#f').on('click x', function(e){ alert('do'); })).trigger('x'); // 2 $('#f').on('click', (function(){ var f = function(){ alert('do'); }; f.call(); return f; });
なんかほかにもあったような気がする。
普通にpoeditとgettextで行けるでしょ、って思ったらそうでもなかったということで。
gettextは、「ソースコード」→「.potファイル」→「.poファイル」→「.moファイル」となり最終的には.moファイルを使う。
.potファイルができれば.moファイルはpoeditで作れる。ソースコードから.potを作るにはxgettextを使う。その辺りは下記のエントリ参照。
ただ、このxgettextはPHPやC、Javaなどのプログラミング言語のgettext用のキーワードを抜き出しているのだけど当然その中にPHP-Smartyは含まれていないのである。今時のフレームワークでPHPをテンプレートとして使うものなら問題ないのだけど、LaravelなんかのBladeテンプレートもさてどうするんだろうという感じである。
正規表現でSmartyテンプレートから抜き出すかなぁ・・・と考えてたんだけどこんなのを見つけた。
ということで取り組んでみる。
こんな感じ。Smartyブロックで囲む。
<{t}>This is English sentence.<{/t}> <{t 1=$user_name}>You are Login as %1.<{/t}>
このSmartyブロックは、smarty-gettextにblock.t.phpというファイルがあるので、Smartyのプラグインディレクトリにコピーしておく。
Smartyテンプレート内に前述のようにgettextを適用したら、smarty-gettextにあるスクリプト、tsmarty2c.phpを使う。
このファイルのSmartyの「デリミタ」「gettext用ブロックプラグイン」「テンプレート拡張子」を自分が使っているものに変更する。
<?php // smarty open tag $ldq = preg_quote('<{'); // smarty close tag $rdq = preg_quote('}>'); // smarty command $cmd = preg_quote('t'); // extensions of smarty files, used when going through a directory $extensions = array('html');
対象となるディレクトリやファイルを指定してpotを作成する。対象が複数ある場合は引数をどんどんと伸ばしていく。
php tsmarty2c.php -o smarty.pot target/smarty/template/directory target/smarty/template/file1.tpl target/smarty/template/file2.tpl
対象となるPHPスクリプトの一覧をtarget_phpfile.listにfind使って書き出して、xgettextコマンドの実行。
xgettext --language=PHP --from-code=utf-8 -f target_phpfile.list --keyword=__ -o php.pot
Smarty由来のpotと、PHPスクリプト由来のpotを合体。
msgcat smarty.pot php.pot > php_smarty.pot
既に翻訳を始めていながら、新しくsmartyテンプレートやPHPプログラムが追加になった場合は、既に翻訳済みのpoと合体させる。
msgmerge php_smarty_prevous.po new_version.pot -o php_smarty.po
前2つのエントリでハマりまくったPHPのsetlocaleのまとめ。*1
setlocale()の挙動について調べている際に、ApacheからではなくCLIから調べていた。
このCLIの場合の調査は下記の通り。
英語・日本語の.moを用意し、setlocale()する最初のスクリプトを書いたところ、CentOSでは問題なくそれぞれの言語カタログが当たったが、debianでは上手くいかない。英語の方を見に行ってしまう。
で、gettextが欲しければ素直に追加しろということで、root権限で追加した。
en_US.UTF-8 UTF-8 ja_JP.UTF-8 UTF-8
最終行に追加。
# locale-gen Generating locales (this might take a while)... en_US.UTF-8... done ja_JP.UTF-8... done Generation complete.
すると、$locale -a で
$ locale -a C C.UTF-8 en_US.utf8 ja_JP.utf8 POSIX
となった。
しかし、先ほどの空くプロとでgettext()で反映させようとしても出てこない。
ちなみに、en_US.utf8というのは、en_US.UTF8でもen_US.UTF-8でもen_US.utf-8でも良いみたい。
task-japaneseというパッケージらしい。しかし、これを普通にapt-get installしたところでlocaleが変わるのか・・・?
# apt-cache search task-japanese task-japanese - Japanese environment task-japanese-desktop - Japanese desktop task-japanese-gnome-desktop - Japanese GNOME desktop task-japanese-kde-desktop - Japanese KDE desktop
まだインストールしてないのを確認
# dpkg -l task-japanese dpkg-query: no packages found matching task-japanese
Debianの公式Wikiを調べて ChangeLanguage - Debian Wiki
# dpkg-reconfigure locales
を行う。
ここでチェックが入っているのは、/etc/locale.genで有効化されている言語。
ja_JP.UTF-8にチェックを入れて、進む。
デフォルトのLocaleはLocale - Debian Wikiによると「None」でイイらしい。
Get root and type dpkg-reconfigure locales and select the locale(s) you want to generate. At the end, you'll be asked which one should be the default. If you have users who access the system through ssh, it is recommended that you choose None as your default locale.
さて・・・・。
# dpkg -l task-japanese dpkg-query: no packages found matching task-japanese
あれ?パッケージがインストールされてない。
仕方ないので、手動でインストール
# apt-get install -y task-japanese
しかし、まだgettext()はja_JPの方を見に行かない。
んー、デフォルトのLanguageに引っ張られてるのか?
# env |grep LANG LANG=en_US.UTF-8 LANGUAGE=en_US:en
デフォルトLanguageを日本語にする。
# update-locale LANG=ja_JP.UTF-8 LANGUAGE=ja_JP:ja
$ more /etc/default/locale # File generated by update-locale LANG=ja_JP.UTF-8 LANGUAGE=ja_JP:ja
で、・・・・あ、gettext()で日本語が出た。確かにgettext()がデフォルト設定のロケールに引っ張られている。・・・ということは今度は日本語に切り替えようとしても切り替わらない・・・。困ったな。
色々調べてたら、
$export LANGUAGE="en_US" $php checmMO.php
というように、環境変数LANGUAGEの値に影響がされていた。
しかも、これはコンソールからCLIのPHPを動作させた時であって、Apacheから見た時はこの設定に影響されず、ちゃんと切り替わっていた。
PHPでgettextを使って国際化しようとかいうとだいたいこういう記事がヒットする。
<?php // 日本-日本語にロケールをセットして setlocale(LC_ALL, 'ja_JP'); // 翻訳カタログが入ったmessage.moファイルのエンコードをUTF-8と宣言して bind_textdomain_codeset('message', 'UTF-8'); // message.moのディレクトリを指定して bindtextdomain('message', dirname(__FILE__)); // gettext()がコールされた際に、message.moからカタログを検索するようにして textdomain('message'); // 翻訳言語を出す echo gettext('hoge');
bindtextdomain()で、/path/to/language/catalog/directoryを設定したら、実際に.moファイルを置くのは
/path/to/language/catalog/directory/ja_JP/LC_MESSAGES
である。
まぁ、これはちょっとよくハマリがちな罠。
これにハマった。setlocale効かない。
RHEL/CentOS系だとロケールは何でもガンガンと入れてくれるらしい。
$ locale -a C POSIX aa_DJ aa_DJ.iso88591 aa_DJ.utf8 ... en_SG.utf8 en_US en_US.iso88591 en_US.iso885915 en_US.utf8 ... ja_JP ja_JP.eucjp ja_JP.ujis ja_JP.utf8 japanese japanese.euc ... zu_ZA zu_ZA.iso88591 zu_ZA.utf8
と500近く出てくるが、debianだと
$ locale -a C C.UTF-8 en_US.utf8 POSIX
これだけになる。
返り値をチェックして、設定した言語とstrcasecmp()===0になれば成功。
$ php -r 'var_dump(setlocale(LC_ALL, "en_US.UTF-8"));' string(11) "en_US.UTF-8" $ php -r 'var_dump(setlocale(LC_ALL, "en_US"));' bool(false) $ php -r 'var_dump(setlocale(LC_ALL, "ja_JP.UTF-8"));' bool(false) $ php -r 'var_dump(setlocale(LC_ALL, "ja_JP"));' bool(false)
Windowsは知らん。もっとややこしいらしい。
注意: Windows では、setlocale(LC_ALL, '') を使用するとシステムの地域と言語の設定の値を使用します (コントロールパネルで確認できます)。
自体に色々と罠が潜んでいるとマニュアルに書いてあった。
たとえば
$ php -r 'var_dump(setlocale(LC_ALL, ""));' string(18) "Japanese_Japan.932"
などというものを返す。
$ php -r 'var_dump(setlocale(LC_ALL, "en_US"));' bool(false)
en_USすらダメ。ほとんどsetlocaleを使うなという気もする。あるいは、完全にWindowsのみでコードと.moの設置場所を書くかしかない。
なんか、setlocaleが成功したり失敗したりする。。。。
検索したらPHPドキュメントのコメントが・・・。 PHP: setlocale - Manual
Omer Sabic
On Linux/Apache, when you install and try to use a new locale, the setlocale() function with the new locale will fail sometimes, but not always. To furthermore complicate, setlocale() will always complete with any of the previously installed locales. This would seem a really weird behaviour, which you can fix by restarting Apache, as Kari Sderholm aka Haprog mentioned, but I felt it needed to be properly pointed out.
Apacheを再起動せよと・・・・。
確かに治った。
ロケールに関する設定は、OSのロケール機能を使っているからということになる。PHP側でも実装するのダルイもんね。
ただ、ロケールに影響を受けるPHP関数は多々あるようで、それはそれで問題だとは思うけどとりあえずgettextが使えればいいので今のところはスルーする。時間表記とか気になるのだけれども、それはその時に下記のエントリを読んで考える。 hnw.hatenablog.com
setlocaleしないで自前でロケールの切り替えを行う。一番簡単なのは、ドメイン名にロケール名称を入れてしまうこと。
また、PHPのgettextモジュールが入ってない場合もあるかもしれないが、その場合も考慮したPHPのgettextライブラリがある。
名称・リンク | リリース(初版 - 最新) | ライセンス | 備考 |
---|---|---|---|
php-gettext | 2003/10/23 - 2015/11/11 | GPL | WordPressもこれを使っている |
PEARのFile_Gettext | 2004/03/30 - 2012/03/04 | BSD | 4年半の沈黙を破り、現時点のリリースはびびる |
oscarotero/Gettext | 2013/12/01 - 2017/03/05 | MIT | composerの名称がgettext/gettextという意欲作。Bladeからpotを作る機能もある。PHP5.4以上 |
oscarotero/Gettextを使いたいなーと思うのだけど、意外と依存性が高いのとPHP5.3は使えないみたいなので若干敷居が高い。
phpMyAdminも独自でgettextを持っていて、CVE - CVE-2015-8980なんてあげられてたりする。
<?php require_once 'File/Gettext.php'; function __($str) { static $mo; if (is_null($mo)){ $mo = File_Gettext::factory('MO'); $mo->load('locale/ja_JP/LC_MESSAGES/message.mo'); } $catalog = $mo->toArray(); if (isset($catalog['strings'][$str])){ return $catalog['strings'][$str]; } return $str; } echo __('email');
こんな感じかな。gettextの機能を全く使わないでいるので、複数形とか来た時にイマイチな感じがする。
ただし、PHPのgettextモジュールが組み込まれてなくても使えるのでポータビリティとしてはかなり高い。
今回の自分のケース。
gettextは現在のロケールとドメインによってカタログを見に行くので、どのディレクトリでも対応するなら、Cロケールを使ってその中に各言語ごとのファイルを用意しておけばいいんじゃん?っておもったのだけど、
gettext(3C) (SunOS リファレンスマニュアル (3) : 基本ライブラリ関数)
現在のロケールが C ロケールの場合、gettext()、gettext()、dcgettext() は、渡されたメッセージ文字列をそのまま返します。
ということで、ダメみたい。