ローカライズ

t() 関数

導入

ローカライズについてお話しする際、t() 関数が開発者が主に気をつけるべき関数です。

この関数は、一つ以上のパラメーターを許容します。最初のパラメーターは、翻訳すべき文字列です。例えば、キャンセルボタンは次のように記述することができます。

<button><?php echo t('Cancel'); ?></button>

concrete5 が自動的に Cancel を現在のユーザーの言語に翻訳してくれるわけです。いいでしょう?

パラメーター

しばしば、翻訳する文字列にダイナミックなコンテンツを挿入したい場合があります。

例を見てみましょう。もし $blockTypeName がブロックタイプ名を格納している場合、次のようなコードを翻訳表示したいと思います。

echo 'Edit '.$blockTypeName;

そのまま考えると、 echo t('Edit '.$blockTypeName) のように記述すれば良いと思うかもしれませんが、これは間違いです。なぜなら、翻訳する文字列は、変化してはいけないからです。また、 echo t('Edit').' '.$blockTypeName; のように書きたいかもしれませんが、この方法も避けるべきです。なぜなら、すべての言語で 'Edit' の言葉がブロックタイプ名の前に来るとは限らないからです(例えば、ドイツ語では逆になります)。ですので、正しい方法は echo sprintf(t('Edit %s'), $blockTypeName); という書き方になります。t 関数を使うと、PHP の sprintf 関数を使わずに、次のように記述することが可能です。

echo t('Edit %s', $blockTypeName);

翻訳する文字列に、複数の変数がある場合はどうでしょうか。このケースでは、言語によって言葉の順番が違うことに注意する必要があります。

例えば、次のようなメッセージを翻訳したいとしましょう。

echo 'Posted by '.$user.' on '.$date;

この場合、 echo t('Posted by %s on %s', $user, $date); のように書くのではなく、

echo t('Posted by %1$s on %2$s', $user, $date);

のように数字をつけた引数を設定し、言語ごとに異なる順番で正しく翻訳することが可能になります。

PS: 変数のプレースホルダーの詳細は、PHPマニュアルの sprintf ページを参照ください。

コメント

パラメーターを使用する際は、翻訳者に変数プレースホルダーが何を意味しているのかを伝えるためにコメントを書くことができます。

コメントは、次のように、シンプルにPHPでコメントを記述すればOKです。

echo t(/*i18n %1$s is a user name, %2$s is a date/time*/'Posted by %1$s at %2$s', $user, $date);

これらのパラメーターが翻訳者に表示される際に、翻訳の手助けとなるでしょう。

t2() 関数

単数系とと複数形など、数字に依存した文字列を翻訳したい場合があると思います。良くある間違いとしては、シンプルにPHPの if-then-else で記述してしまうことです。

echo ($pages == 1) ? t('%d page', $pages) : t('%d pages', $pages);

この方法は、すべての言語が1かそれ以上という2つの複数形である場合にしか使えません。この過程は、誤りです。例えば、ロシア語は3つの複数形を持っていますし、フランス語では、単数系はゼロのときに使います。

このような理由で、複数形を翻訳する際は、 t() 関数ではなく、 t2() 関数を使います。この関数は、少なくとも3つのパラメーターをとります。

echo t2('%d page', '%d pages', $pages);

t2() 関数は、3つ目のパラメーター(この場合は $pages)に基づいて、正しい複数形を返します。さらに、sprintfが呼び出され、$pages が結果の文字列に挿入されます。

tc() 関数

しばしば、英語のテキストは複数の意味を持ち、複数の翻訳が存在する場合があります。例えば、set という言葉について考えてみましょう。この単語は実に様々な意味を持ちますので、様々な翻訳が存在します。どれが正しい翻訳でしょうか?それは、この単語が使われるコンテキストに依存します。tc() 関数を使うと、テキストのコンテキストを指定することが可能です。この関数は t() 関数と似ていますが、最初のパラメーターがコンテキストを表す文字列になります。例えば、

echo tc('A group of items', 'Set');

または

echo tc('Apply a value to an option', 'Set');

のように、同じ単語に複数のコンテキストを設定できます。コンテキストを使うことで、同じ英語のテキストに異なる翻訳を割り当てることが可能になります。コンテキスト以外のオプションを使用していないことに注意してください。Set という同じ単語に対して、英語のテキストを理解するのを助ける働きもあります。

おそらく、コンテキストを使うべきなのはいつなのかという疑問があると思います。コンテキストを使いすぎると、翻訳作業が不必要に増えていきます。tc() をあまり使わないと、翻訳者を悩ませ、ウェブページにわかりにくい翻訳が増えることになります。

一般的に、翻訳されるテキストは長く(3つ以上の単語に)なりますので、そのテキスト自体がコンテキストを表しているため、コンテキストは必要にはなりません。短いテキストの場合は、コンテキストに依存します。単語が set のように複数の意味を持つときは、コンテキストを使うべきでしょう(つまり tc() を使い t() は使わない)。もし単語が OK のように複数の意味を持たない場合は、コンテキストを使わない方が良いでしょう。

何れにしても、翻訳者からのフィードバックに耳を傾けてください。正しい方法は、ひとつとは限らないのですから。

コアコンテキスト

翻訳上の問題を回避するため、concrete5 は次のコンテキストを実装しています。

  • AreaName エリア名
  • AttributeKeyName 属性キー名
  • AttributeSetName 属性セット名
  • AttributeTypeName 属性タイプ名
  • BlockTypeSetName ブロックセット名
  • ConversationEditorName エディター名
  • ConversationRatingTypeName 会話の評価タイプ名
  • FeedDescription フィードの説明
  • FeedTitle フィードのタイトル
  • GatheringDataSourceName ギャザリングのデータソース名
  • GatheringItemTemplateName ギャザリングのアイテムテンプレート名
  • GroupDescription ユーザーグループの説明
  • GroupName ユーザーグループ名
  • ImageEditorControlSetName names of the control sets of the image editor
  • ImageEditorFilterName names of the filters of the image editor
  • JobSetName names of the job sets
  • PageTemplateName names of the page templates
  • PageTypeComposerControlName names of the controls of the page type composers
  • PageTypeComposerControlTypeName names of the types controls of the page type composers
  • PageTypeComposerFormLayoutSetControlCustomLabel names of the set of layouts of the page type composers
  • PageTypeComposerFormLayoutSetName names of the sets of page type composer forms
  • PageTypePublishTargetTypeName names of the targets of page types
  • PermissionAccessEntityTypeName names of permission access entity types
  • PermissionKeyDescription descriptions of permission keys
  • PermissionKeyName names of permission keys
  • PresetName names of style presets
  • SelectAttributeValue values of the select attribute types
  • StyleName names of the styles
  • StyleSetName names of the set of styles
  • SystemContentEditorSnippetName names of the snippets of the content editor
  • TemplateFileName names associated to template files
  • ThumbnailTypeName names of the types of the image thumbnails
  • Topic topics
  • TopicCategoryName names of the topic categories
  • TopicName topic names
  • TreeName names of the trees

日付と時間

PHPでは、現在の月を表示したい場合に次のように記述できます。

echo date('F');

しかし、現在のサイトの言語に従った月の名前を取得するにはどうすれば良いでしょうか。

concrete5のテーマでは、日付についての記述を助ける Date ヘルパを使うことができます。使い方は次のようになります。

$dateHelper = \Core::make('helper/date');

ローカライズされた月の名前を取得するには、PHPのdate関数と同じように使うことができます。

echo $dateHelper->date('F');

これでOKです。このメソッドはPHPのdate関数と同じフォーマットの文字列をパラメーターとして受け付けます。

さらに、日付のフォーマットを指定したい場合があると思います。現在の日付を英語の長いフォーマットで表示するには、次のように記述することができます。

echo date('F d, Y');

おそらく、 $dateHelper->date('F d, Y'); のように記述することができるのではないかと思われるかもしれませんが、すべての言語で月を名前で表記し(F)、次に日付を表示し(d)、カンマの後に年を表示する(Y)わけではないため、これは誤りです。

正しい日付と時間のローカライズのためには、あらかじめ用意された Date ヘルパのメソッドを使用するのが良いでしょう。

Date ヘルパはその他にも便利な日付関連の機能を持っています。詳細はAPIドキュメントを参照ください。

パッケージの翻訳

パッケージを開発した?素晴らしい!世界を変えるための準備はほぼできたというわけです。実際に世界中で使われるようにするために、t() 関数で翻訳の準備も整えたとしましょう。

では次に?あなたの翻訳可能なパッケージが他の言語で表示されるには何をしたらいいのでしょうか。

PHPファイルから翻訳可能な文字列を抽出し、翻訳したい言語ごとに言語ファイルを作成する必要があります。

バージョン 5.7.5.4 から、concrete5 自身にこの作業をさせることができます。コンソールウィンドウを開き、次のコマンドを実行してください(Windowsの場合は / を ¥ に変更してください)。

PATH-TO-CONCRETE5-ROOT-FOLDER/concrete/bin/concrete5 c5:package-translate PACKAGE_HANDLE OPTIONS

詳細

  • PATH-TO-CONCRETE5-ROOT-FOLDER は concrete5 がインストールされたディレクトリへのパスです。
  • PACKAGE_HANDLE はパッケージのハンドルです(または、パッケージを含むディレクトリのパスでも構いません)。
  • OPTIONS --help で利用可能なオプションのリストを見ることができます。もっとも重要なものは --locale (または短く -l) で、作成したい言語を指定することができます。

例えば、 handyman というハンドルでパッケージを開発していたとしましょう。翻訳を抽出しドイツ語とイタリア語の言語ファイルを作成したい場合は、次のコマンドを実行します。

concrete5 c5:package-translate handyman -l it_IT -l de_DE

このコマンドは次のファイルを生成します。

  • packages/handyman/languages/messages.pot このファイルは gettext の Portable Object Template ファイルです。このファイルは、パッケージ内のすべての翻訳可能な文字列を含みます。このテンプレートファイルは新しい言語ファイルを作成するために使用できますが、コマンドで実行することもできますので、無視して構いません。
  • packages/handyman/languages/it_IT/LC_MESSAGES/messages.po このファイルはイタリア語に翻訳されるべき Portable Object ファイルです。
  • packages/handyman/languages/it_IT/LC_MESSAGES/messages.mo このファイルは .po ファイルがコンパイルされた Machine Object ファイルです。
  • packages/handyman/languages/de_DE/LC_MESSAGES/messages.po it_IT ディレクトリ内のファイルと同じですが、ドイツ語用です。
  • packages/handyman/languages/de_DE/LC_MESSAGES/messages.mo it_IT ディレクトリ内のファイルと同じですがドイツ語用です。

次に行うことは、翻訳者が .po ファイルを翻訳することです。UTF-8 をサポートした普通のテキストエディターも使えますが、専用のソフトを使う方が楽でしょう(例えば、POEdit, BetterPOEditor, など)。

concrete5 は .po ファイルを直接使うことはできないため、.mo ファイルにコンパイルする必要があります。コンパイルを行うためには、単に再度 c5:package-translate コマンドを実行すればOKです(パッケージハンドルの指定だけで可能です)。

concrete5 c5:package-translate handyman

このコマンドは作成済みのイタリア語とドイツ語の .po ファイルを見つけ、.mo フォーマットにコンパイルします(別の c5:package-pack コマンドを使うこともできます)。

.po フィアルを困ぱいつしたら、concrete5 のキャッシュをクリアして、新しい翻訳を確認しましょう。キャッシュのクリアは、管理画面からか、 c5:clear-cache コマンドで実行できます。

PS:パッケージを配信する際、concrete5 は .mo ファイルしか使用しないため、.pot ファイルと .po ファイルは削除して構いません。c5:package-pack コマンドはそのように処理します。

原文:Localization