Gettextの紹介

WordPressはi18nのためにgettextライブラリとツールを使用していますが、直接ではありません。文字列翻訳を可能にするために特別に作成された一連の関数があります。これらの関数は以下に示されています。これらはあなたのプラグイン内で使用すべき関数です。

Gettextについての詳細は、gettextオンラインマニュアルをお読みください。

テキストドメイン

プラグインに属するすべてのテキストを示すためにテキストドメインを使用します。テキストドメインは、WordPressがすべての読み込まれた翻訳を区別できるようにするための一意の識別子です。これにより、移植性が向上し、既存のWordPressツールとより良く連携します。

テキストドメインはプラグインのslugと一致する必要があります。プラグインがmy-plugin.phpという単一のファイルである場合、またはmy-pluginというフォルダーに含まれている場合、ドメイン名はmy-pluginでなければなりません。プラグインがwordpress.orgにホストされている場合、プラグインURLのスラッグ部分である必要があります(wordpress.org/plugins/**<slug>)。

テキストドメイン名はダッシュを使用し、アンダースコアを使用せず、小文字で、スペースを含まない必要があります。

テキストドメインはプラグインヘッダーにも追加する必要があります。WordPressは、プラグインが無効になっている場合でも、プラグインメタデータを国際化するためにこれを使用します。テキストドメインは、テキストドメインを読み込むときに使用されるものと同じであるべきです。

ヘッダーの例:

  1. /*
  2. * Plugin Name: My Plugin
  3. * Author: Plugin Author
  4. * Text Domain: my-plugin
  5. */

再度、「my-plugin」をプラグインのスラッグに変更してください。

WordPress 4.6以降、Text Domainヘッダーはオプションです。なぜなら、それはプラグインスラッグと同じでなければならないからです。含めても問題はありませんが、必須ではありません。

ドメインパス

ドメインパスは、プラグインの翻訳の場所を定義します。これはいくつかの用途があり、特にプラグインが無効になっている場合でもWordPressが翻訳を見つける場所を知るために重要です。これは、プラグインが見つかるフォルダーにデフォルトで設定されます。

たとえば、翻訳がプラグイン内のlanguagesというフォルダーにある場合、ドメインパスは/languagesであり、最初のスラッシュで書かれる必要があります:

ヘッダーの例:

  1. /*
  2. * Plugin Name: My Plugin
  3. * Author: Plugin Author
  4. * Text Domain: my-plugin
  5. * Domain Path: /languages
  6. */

Domain Pathヘッダーは、プラグインが公式のWordPressプラグインディレクトリにある場合は省略できます。

基本的な文字列

基本的な文字列(プレースホルダーや複数形のない文字列)には()を使用します。これはその引数の翻訳を返します:

  1. __( 'Blog Options', 'my-plugin' );

gettext関数のテキストドメイン部分に変数名や定数を使用しないでください。たとえば、ショートカットとしてこれを行わないでください:

  1. __( 'Translate me.' , $text_domain );

取得した翻訳をエコーするには、_e()を使用します。したがって、次のように書く代わりに:

  1. echo __( 'WordPress is the best!', 'my-plugin' );

次のように使用できます:

  1. _e( 'WordPress is the best!', 'my-plugin' );

変数

次のような文字列がある場合はどうしますか:

  1. echo 'Your city is $city.'

この場合、$cityは変数であり、翻訳の一部であってはなりません。解決策は、変数のためにプレースホルダーを使用し、printfファミリーの関数を使用することです。特にprintfsprintfが役立ちます。正しい解決策は次のようになります:

  1. printf(
  2. /* translators: %s: Name of a city */
  3. __( 'Your city is %s.', 'my-plugin' ),
  4. $city
  5. );

ここで翻訳のための文字列はテンプレート"Your city is %s."であり、ソースと実行時の両方で同じです。

また、プレースホルダーのコンテキストを知るためのヒントが翻訳者に提供されます。

文字列にプレースホルダーが複数ある場合は、引数の入れ替えを使用することをお勧めします。この場合、文字列の周りにシングルクォート(')が必須です。なぜなら、ダブルクォート(")はphpに$ss変数として解釈させるからで、これは望ましくありません。

  1. printf(
  2. /* translators: 1: Name of a city 2: ZIP code */
  3. __( 'Your city is %1$s, and your zip code is %2$s.', 'my-plugin' ),
  4. $city,
  5. $zipcode
  6. );

ここでは、郵便番号が市名の後に表示されています。一部の言語では、郵便番号と市を逆の順序で表示する方が適切です。上記の例で%sプレフィックスを使用することで、そのような場合に対応できます。したがって、翻訳は次のように書くことができます:

  1. printf(
  2. /* translators: 1: Name of a city 2: ZIP code */
  3. __( 'Your zip code is %2$s, and your city is %1$s.', 'my-plugin' ),
  4. $city,
  5. $zipcode
  6. );

重要! 次のコードは不正です:

  1. // This is incorrect do not use.
  2. _e( "Your city is $city.", 'my-plugin' );

翻訳のための文字列はソースから抽出されるため、翻訳者はこのフレーズを翻訳することになります: "Your city is $city."

しかし、アプリケーションでは_e"Your city is London."のような引数で呼び出され、gettextはこの翻訳に適したものを見つけられず、引数"Your city is London."を返します。残念ながら、正しく翻訳されていません。

複数形

基本的な複数形化

アイテムの数が変わると文字列も変わる場合、翻訳に反映させる方法が必要です。たとえば、英語では"One comment""Two comments"があります。他の言語では複数の複数形がある場合があります。これをWordPressで処理するには、_n()関数を使用します。

  1. printf(
  2. _n(
  3. '%s comment',
  4. '%s comments',
  5. get_comments_number(),
  6. 'my-plugin'
  7. ),
  8. number_format_i18n( get_comments_number() )
  9. );
  1. - 単数形 文字列の単数形(いくつかの言語では1以外の数字にも使用できるため、`````'%s item'``````````'One item'`````の代わりに使用する必要があります)
  2. - 複数形 文字列の複数形
  3. - カウント オブジェクトの数で、単数形または複数形のどちらを返すかを決定します(2つ以上の形を持つ言語もあります)
  4. - テキストドメイン プラグインのテキストドメイン
  5. 関数の戻り値は、指定されたカウントに対応する正しい翻訳形です。
  6. いくつかの言語では、他の数字に対して単数形を使用することがあります(例: 2131など、英語の「21st」、「31st」のように)。単数形を特別扱いしたい場合は、特にそれを確認してください:
  7. ``````bash
  8. if ( 1 === $count ) {
  9. printf( esc_html__( 'Last thing!', 'my-text-domain' ), $count );
  10. } else {
  11. printf( esc_html( _n( '%d thing.', '%d things.', $count, 'my-text-domain' ) ), $count );
  12. }
  13. `

また、$countパラメータはしばしば2回使用されます。最初に$count_n()に渡され、どの翻訳された文字列を使用するかを決定し、その後$countprintf()に渡され、翻訳された文字列に数を代入します。

後での複数形化

最初に_n_noop()または_nx_noop()で複数形の文字列を設定します。

  1. $comments_plural = _n_noop(
  2. '%s comment.',
  3. '%s comments.'
  4. );

その後、コードの後のポイントでtranslate_nooped_plural()を使用して文字列を読み込むことができます。

  1. printf(
  2. translate_nooped_plural(
  3. $comments_plural,
  4. get_comments_number(),
  5. 'my-plugin'
  6. ),
  7. number_format_i18n( get_comments_number() )
  8. );

コンテキストによる曖昧さの解消

時々、1つの用語がいくつかのコンテキストで使用され、英語では同じ単語であっても他の言語では異なる翻訳が必要です。たとえば、Postという単語は、動詞"Click here to post your comment"としても名詞"Edit this post"としても使用されることがあります。このような場合は、_x()または_ex()関数を使用する必要があります。これは()および_e()に似ていますが、追加の引数—コンテキストがあります:

  1. _x( 'Post', 'noun', 'my-plugin' );
  2. _x( 'Post', 'verb', 'my-plugin' );

この方法を使用すると、両方のケースで元のバージョンの文字列「Comment」を取得できますが、翻訳者は異なるコンテキストで2つの「Comment」文字列を翻訳することになります。

()に似て、_x()にはechoバージョンがあります: _ex()。前の例は次のように書くことができます:

  1. _ex( 'Post', 'noun', 'my-plugin' );
  2. _ex( 'Post', 'verb', 'my-plugin' );

読みやすさとコーディングの容易さを向上させるものを使用してください。

説明

翻訳者が( 'g:i:s a' )のような文字列をどのように翻訳するかを知るために、ソースコードに明確なコメントを追加できます。これはtranslators:という言葉で始まり、gettext呼び出しの前の最後のPHPコメントである必要があります。以下はその例です:

  1. /* translators: draft saved date format, see http://php.net/date */
  2. $saved_date_format = __( 'g:i:s a' );

これは_n_noop( '<strong>Version %1$s</strong> addressed %2$s bug.','<strong>Version %1$s</strong> addressed %2$s bugs.' )のような文字列のプレースホルダーを説明するためにも使用されます。

  1. /* translators: 1: WordPress version number, 2: plural number of bugs. */
  2. _n_noop( '<strong>Version %1$s</strong> addressed %2$s bug.','<strong>Version %1$s</strong>strong> addressed %2$s bugs.' );

改行文字

Gettextは翻訳可能な文字列内のr(ASCIIコード: 13)を好まないため、これを避けてnを使用してください。

空の文字列

空の文字列は内部Gettext使用のために予約されており、空の文字列を国際化しようとしないでください。また、翻訳者はコンテキストを見ないため、意味がありません。

空の文字列を国際化する正当な使用例がある場合は、翻訳者を助けるためにコンテキストを追加し、Gettextシステムと平和でいるようにしてください。

文字列のエスケープ

すべての文字列をエスケープすることは良いことであり、これにより翻訳者は悪意のあるコードを実行できなくなります。国際化関数と統合されたエスケープ関数がいくつかあります。

ローカリゼーション関数

基本関数

翻訳とエスケープ関数

翻訳が必要で、HTMLタグの属性で使用される文字列はエスケープする必要があります。

日付と数値関数

文字列を書くためのベストプラクティス

文字列を書くためのベストプラクティスは次のとおりです。

  • 適切な英語スタイルを使用する – スラングや略語を最小限に抑える。
  • 完全な文を使用する – ほとんどの言語では、単語の順序が英語とは異なります。
  • 段落で分割する – 関連する文を統合しますが、1つの文字列に全ページのテキストを含めないでください。
  • 翻訳可能なフレーズに先頭または末尾の空白を残さないでください。
  • 翻訳時に文字列が2倍の長さになる可能性があると仮定する。
  • 異常なマークアップや異常な制御文字を避ける – テキストを囲むタグを含めないでください。
  • 翻訳された文字列に不必要なHTMLマークアップを含めないでください。
  • 翻訳のためにURLを残さないでください。別の言語のバージョンがある場合を除きます。
  • 変数をプレースホルダーとして文字列に追加します。一部の言語ではプレースホルダーの位置が変わるためです。
  1. printf(
  2. __( 'Search results for: %s', 'my-plugin' ),
  3. get_search_query()
  4. );
  • 文字列の連結の代わりにフォーマット文字列を使用する – フレーズを翻訳し、単語ではなくprintf( __( 'Your city is %1$s, and your zip code is %2$s.', 'my-plugin' ), $city, $zipcode );は常に__( 'Your city is ', 'my-plugin' ) . $city . __( ', and your zip code is ', 'my-plugin' ) . $zipcode;よりも良いです。
  • 同じ単語と同じ記号を使用して、複数の文字列を翻訳する必要がないようにします。例: ( 'Posts:', 'my-plugin' );( 'Posts', 'my-plugin' );

文字列にテキストドメインを追加する

すべての()_e()、およびn()gettext呼び出しに引数としてテキストドメインを追加する必要があります。そうしないと、翻訳が機能しません。

例:

  • ( 'Post' )( 'Post', 'my-theme' )にする必要があります。
  • _e( 'Post' )_e( 'Post', 'my-theme' )にする必要があります。
  • _n( '%s post', '%s posts', $count )_n( '%s post', '%s posts', $count, 'my-theme' )にする必要があります。

プラグイン内にWordPressコアでも使用される文字列(例: ‘Settings’)がある場合は、それらにも独自のテキストドメインを追加する必要があります。そうしないと、コア文字列が変更された場合に翻訳されなくなります(これは発生します)。

手動でテキストドメインを追加することは、コードを書くときに継続的に行わないと負担になる可能性があるため、自動的に行うことができます:

  • テキストドメインを追加したいファイルがあるフォルダーにadd-textdomain.phpスクリプトをダウンロードします。
  • コマンドラインでファイルがあるディレクトリに移動します。
  • テキストドメインが追加された新しいファイルを作成するためにこのコマンドを実行します:
  1. php add-textdomain.php my-plugin my-plugin.php > new-my-plugin.php
  1. ``````bash
  2. php /path/to/add-textdomain.php my-plugin my-plugin.php > new-my-plugin.php
  3. `

新しいファイルを出力したくない場合は、このコマンドを使用します:

  1. php add-textdomain.php -i my-plugin my-plugin.php

ディレクトリ内の複数のファイルを変更したい場合は、スクリプトにディレクトリを渡すこともできます:

  1. php add-textdomain.php -i my-plugin my-plugin-directory

完了すると、ファイル内のすべてのgettext呼び出しの最後にテキストドメインが追加されます。既存のテキストドメインがある場合は置き換えられません。

テキストドメインの読み込み

翻訳はload_plugin_textdomainを使用して読み込むことができます。たとえば:

  1. add_action( 'init', 'wpdocs_load_textdomain' );
  2. function wpdocs_load_textdomain() {
  3. load_plugin_textdomain( 'wpdocs_textdomain', false, dirname( plugin_basename( __FILE__ ) ) . '/languages' );
  4. }

WordPress.orgのプラグイン

WordPress 4.6以降、翻訳は現在translate.wordpress.orgを優先し、translate.wordpress.orgを介して翻訳されたプラグインはもはやload_plugin_textdomain()を必要としません。プラグインにload_plugin_textdomain()呼び出しを追加したくない場合は、readme.txtのRequires at least:フィールドを4.6以上に設定する必要があります。

独自の翻訳を読み込み、translateからのものを使用したくない場合は、load_textdomain_mofileという名前のフックフィルターを使用する必要があります。

.moファイルがプラグインの/languages/ディレクトリにあり、メインプラグインファイルにこのコードが挿入されている場合:

  1. function my_plugin_load_my_own_textdomain( $mofile, $domain ) {
  2. if ( 'my-domain' === $domain && false !== strpos( $mofile, WP_LANG_DIR . '/plugins/' ) ) {
  3. $locale = apply_filters( 'plugin_locale', determine_locale(), $domain );
  4. $mofile = WP_PLUGIN_DIR . '/' . dirname( plugin_basename( __FILE__ ) ) . '/languages/' . $domain . '-' . $locale . '.mo';
  5. }
  6. return $mofile;
  7. }
  8. add_filter( 'load_textdomain_mofile', 'my_plugin_load_my_own_textdomain', 10, 2 );

JavaScriptファイルの処理

国際化javascriptセクションのCommon APIs Handbookを確認して、翻訳ファイルを正しく読み込む方法を確認してください。また、Gutenburgプラグインドキュメントページも参照してください。

言語パック

言語パックとtranslate.wordpress.orgへのインポートの仕組みに興味がある場合は、翻訳に関するMeta Handbookページをお読みください。

また、プロジェクトを翻訳するためのPlugin/Theme Authors Guide in Polyglots Handbooksも参照してください。