多言語アプリを構築する方法:PHPとGettextを使用したデモ

公開: 2022-03-11

Webサイトを構築している場合でも、本格的なWebアプリケーションを構築している場合でも、より多くのユーザーがWebサイトにアクセスできるようにするには、多くの場合、さまざまな言語とロケールで利用できる必要があります。

ほとんどの人間の言語間の根本的な違いにより、これは簡単ではありません。 文法規則、言語のニュアンス、日付形式などの違いが組み合わさって、ローカリゼーションはユニークで手ごわい課題になります。

この簡単な例を考えてみましょう。

英語の複数形の規則は非常に単純です。単語の単数形または複数形の単語を使用できます。

ただし、スラブ語などの他の言語では、単数形に加えて2つの複数形があります。 スロベニア語、アイルランド語、アラビア語など、合計4つ、5つ、または6つの複数形の言語を見つけることもできます。

コードの編成方法、およびコンポーネントとインターフェースの設計方法は、アプリケーションをどれだけ簡単にローカライズできるかを決定する上で重要な役割を果たします。

コードベースの国際化(i18n)は、コードベースをさまざまな言語や地域に比較的簡単に適応できるようにするのに役立ちます。 国際化は通常1回行われ、できればプロジェクトの開始時に行われ、将来的にソースコードを大幅に変更する必要がなくなります。

多言語アプリの作成方法:PHPとGettextを使用したデモ

コードベースが国際化されると、ローカリゼーション(l10n)は、アプリケーションのコンテンツを特定の言語/ロケールに翻訳する問題になります。

新しい言語または地域をサポートする必要があるたびに、ローカリゼーションを実行する必要があります。 また、インターフェイスの一部(テキストを含む)が更新されるたびに、新しいコンテンツが利用可能になります。これは、サポートされているすべてのロケールにローカライズ(つまり、翻訳)する必要があります。

この記事では、PHPで記述されたソフトウェアを国際化およびローカライズする方法を学習します。 プロセスを容易にするために、さまざまな実装オプションと自由に使用できるさまざまなツールについて説明します。

国際化のためのツール

PHPソフトウェアを国際化する最も簡単な方法は、配列ファイルを使用することです。 配列には翻訳された文字列が入力され、テンプレート内から検索できます。

 <h1><?=$TRANS['title_about_page']?></h1>

ただし、これは将来のメンテナンスの問題を確実に引き起こすため、深刻なプロジェクトにはほとんどお勧めできません。 変数の補間や名詞の複数形化のサポートの欠如など、いくつかの問題が最初から現れることさえあります。

最も古典的なツールの1つ(多くの場合、i18nおよびl10nのリファレンスとして使用されます)は、Gettextと呼ばれるUnixツールです。

1995年にさかのぼりますが、それでも使いやすいソフトウェアを翻訳するための包括的なツールです。 始めるのは非常に簡単ですが、それでも強力なサポートツールがあります。

Gettextは、この投稿で使用するものです。 l10nソースファイルを簡単に更新するために使用できる優れたGUIアプリケーションを紹介します。これにより、コマンドラインを処理する必要がなくなります。

物事を簡単にするライブラリ

Gettextをサポートする主要なPHPWebフレームワークとライブラリ

Gettextおよびi18nの他の実装をサポートする主要なPHPWebフレームワークおよびライブラリがあります。 インストールが簡単なものもあれば、追加機能を備えているものや、さまざまなi18nファイル形式をサポートしているものもあります。 このドキュメントでは、PHPコアで提供されるツールに焦点を当てていますが、言及する価値のある他のツールのリストを次に示します。

  • oscarotero / Gettext:オブジェクト指向インターフェースによるGettextのサポート。 改善されたヘルパー関数、いくつかのファイル形式用の強力なエクストラクタが含まれています(それらのいくつかはgettextコマンドによってネイティブにサポートされていません)。 .mo / .poファイル以外の形式にエクスポートすることもできます。これは、JavaScriptインターフェイスなど、翻訳ファイルをシステムの他の部分に統合する必要がある場合に役立ちます。

  • symfony / translation:多くの異なるフォーマットをサポートしますが、冗長なXLIFFを使用することをお勧めします。 ヘルパー関数や組み込みのエクストラクタは含まれていませんが、内部でstrtr()を使用してプレースホルダーをサポートしています。

  • zend / i18n:配列およびINIファイル、またはGettext形式をサポートします。 毎回ファイルシステムを読み取る必要がないように、キャッシュレイヤーを実装します。 ビューヘルパー、ロケール対応の入力フィルターとバリデーターも含まれます。 ただし、メッセージエクストラクタはありません。

他のフレームワークにもi18nモジュールが含まれていますが、それらはコードベースの外部では利用できません。

  • Laravel:基本的な配列ファイルをサポートします。 自動抽出機能はありませんが、テンプレートファイル用の@langヘルパーが含まれています。

  • Yii:配列、Gettext、およびデータベースベースの翻訳をサポートし、メッセージエクストラクタが含まれています。 PHP 5.3以降で利用可能で、ICUプロジェクトに基づくIntl拡張機能に支えられています。 これにより、Yiiは、数字のスペル、日付、時刻、間隔、通貨、序数の書式設定など、強力な置換を実行できます。

エクストラクタを提供しないライブラリの1つを選択する場合は、Gettext形式を使用することをお勧めします。これにより、この章の残りの部分で説明するように、元のGettextツールチェーン(Poeditを含む)を使用できます。

Gettextのインストール

apt-getやyumなどのパッケージマネージャーを使用して、Gettextと関連するPHPライブラリをインストールする必要がある場合があります。 インストール後、 php.iniファイルにextension=gettext.so (Linux / Unix)またはextension=php_gettext.dll (Windows)を追加して有効にします。

ここでは、Poeditを使用して翻訳ファイルを作成します。 おそらく、システムのパッケージマネージャーにあります。 Unix、Mac、およびWindowsで利用でき、Webサイトから無料でダウンロードすることもできます。

Gettextファイルの種類

Gettextを操作するときに通常扱うファイルの種類は3つあります。

主なものはPO(ポータブルオブジェクト)ファイルとMO(マシンオブジェクト)ファイルで、最初は読み取り可能な「変換されたオブジェクト」のリストであり、2番目は対応するバイナリです(ローカリゼーションを行うときにGettextによって解釈されます)。 POT(POテンプレート)ファイルもあります。これには、ソースファイルの既存のすべてのキーが含まれているだけで、すべてのPOファイルを生成および更新するためのガイドとして使用できます。

テンプレートファイルは必須ではありません。 l10nを実行するために使用しているツールによっては、PO/MOファイルだけで問題ありません。 言語と地域ごとに1組のPO/MOファイルがありますが、ドメインごとに1つのPOTしかありません。

ドメインの分離

大規模なプロジェクトでは、同じ単語が異なるコンテキストで異なる意味を伝える場合に、翻訳を分離する必要がある場合があります。

そのような場合は、それらを異なる「ドメイン」に分割する必要があります。これらのドメインは、基本的にPOT / PO / MOファイルのグループと呼ばれ、ファイル名は上記の翻訳ドメインです。

中小規模のプロジェクトでは、通常、簡単にするために1つのドメインのみを使用します。 その名前は任意ですが、コードサンプルには「main」を使用します。

たとえば、Symfonyプロジェクトでは、ドメインは検証メッセージの翻訳を分離するために使用されます。

ロケールコード

ロケールは、言語の1つのバージョンを識別する単なるコードです。 これは、ISO639-1およびISO3166-1 alpha-2仕様に従って定義されています。言語を表す2つの小文字、オプションで、国または地域のコードを識別するアンダースコアと2つの大文字が続きます。

まれな言語の場合、3文字が使用されます。

一部のスピーカーにとって、国の部分は冗長に見えるかもしれません。 実際、オーストリアドイツ語(de_AT)やブラジルポルトガル語(pt_BR)など、一部の言語にはさまざまな国で方言があります。 2番目の部分は、これらの方言を区別するために使用されます。存在しない場合は、言語の「一般的な」バージョンまたは「ハイブリッド」バージョンと見なされます。

ディレクトリ構造

Gettextを使用するには、フォルダーの特定の構造に準拠する必要があります。

まず、ソースリポジトリ内のl10nファイルの任意のルートを選択する必要があります。 その中には、必要なロケールごとのフォルダーと、すべてのPO/MOペアを含む固定の「LC_MESSAGES」フォルダーがあります。

LC_MESSAGESフォルダー

複数形

冒頭で述べたように、言語が異なれば、複数形のルールも異なる可能性があります。 ただし、Gettextはこの問題を回避します。

新しい.poファイルを作成するときは、その言語の複数形の規則を宣言する必要があります。複数形に依存する翻訳された部分は、それらの規則ごとに異なる形式になります。

コードでGettextを呼び出すときは、文に関連する番号を指定する必要があります(たとえば、「You have n messages。」というフレーズの場合は、nの値を指定する必要があります)。これにより、正しい形式が実行されます。使用する-必要に応じて文字列置換を使用することもできます。

複数のルールは、各ルールのブールテストで必要な数のルールで構成されます(最大で1つのルールのテストは省略できます)。 例えば:

  • 日本語: nplurals=1; plural=0; nplurals=1; plural=0; -1つのルール:複数形はありません

  • 英語: nplurals=2; plural=(n != 1); nplurals=2; plural=(n != 1); -2つのルール:nが1でない場合にのみ複数形を使用し、それ以外の場合は単数形を使用します。

  • ブラジルポルトガル語: nplurals=2; plural=(n > 1); nplurals=2; plural=(n > 1); -2つのルール、nが1より大きい場合にのみ複数形を使用し、それ以外の場合は単数形を使用します。

より詳細な説明については、オンラインで利用できる有益なLingoHubチュートリアルがあります。

Gettextは、提供された番号に基づいて使用するルールを決定し、文字列の正しいローカライズされたバージョンを使用します。 複数形を処理する必要がある文字列の場合、定義された複数形のルールごとに異なる文を.poファイルに含める必要があります。

サンプル実装

その理論がすべて終わったら、少し実用的にしましょう。 .poファイルの抜粋を次に示します(構文についてはあまり気にしないでください。代わりに、全体的な内容を理解してください)。

 msgid "" msgstr "" "Language: pt_BR\n" "Content-Type: text/plain; charset=UTF-8\n" "Plural-Forms: nplurals=2; plural=(n > 1);\n" msgid "We're now translating some strings" msgstr "Nos estamos traduzindo algumas strings agora" msgid "Hello %1$s! Your last visit was on %2$s" msgstr "Ola %1$s! Sua ultima visita foi em %2$s" msgid "Only one unread message" msgid_plural "%d unread messages" msgstr[0] "So uma mensagem nao lida" msgstr[1] "%d mensagens nao lidas"

最初のセクションはヘッダーのように機能し、 msgidmsgstrは空です。

ファイルのエンコーディング、複数形、その他いくつかのことを説明しています。 2番目のセクションは、単純な文字列を英語からブラジルポルトガル語に翻訳し、3番目のセクションも同じことを行いますが、 sprintfからの文字列置換を利用して、翻訳にユーザー名と訪問日を含めることができます。

最後のセクションは複数形のサンプルで、単数形と複数形を英語のmsgidとして表示し、対応する翻訳をmsgstr 0および1(複数形の規則で指定された数に従う)として表示します。

ここでは、文字列の置換も使用されているため、 %dを使用すると、数字を文の中で直接確認できます。 複数形には常に2つのmsgid (単数形と複数形)があるため、翻訳のソースとして複雑な言語を使用しないことをお勧めします。

ローカリゼーションキー

お気づきかもしれませんが、ソースIDとして実際の英語の文を使用しています。 そのmsgidは、すべての.poファイルで使用されているものと同じです。つまり、他の言語は同じ形式で同じmsgidフィールドを持ちますが、 msgstr行は変換されます。

翻訳キーと言えば、ここには2つの標準的な「哲学的」アプローチがあります。

1.実文としてのmsgid

このアプローチの主な利点は次のとおりです。

  • 特定の言語に翻訳されていないソフトウェアの部分がある場合でも、表示されるキーは何らかの意味を維持します。 たとえば、英語からスペイン語への翻訳方法は知っているが、フランス語への翻訳についてサポートが必要な場合は、フランス語の文章が欠落している新しいページを公開すると、代わりにWebサイトの一部が英語で表示されます。

  • 翻訳者が何が起こっているのかを理解し、 msgidに基づいて適切な翻訳を行う方がはるかに簡単です。

  • これにより、1つの言語(ソース言語)に対して「無料」のl10nが提供されます。

一方、主な欠点は、実際のテキストを変更する必要がある場合、複数の言語ファイルで同じmsgidを置き換える必要があることです。

2.一意の構造化キーとしてのmsgid

これは、アプリケーションでの文の役割を構造化された方法で記述します。これには、コンテンツの代わりに文字列が配置されているテンプレートまたは部分が含まれます。

これは、テキストコンテンツをテンプレートロジックから分離して、コードを整理するための優れた方法です。 ただし、それは文脈を見逃す翻訳者に問題をもたらす可能性があります。

他の翻訳の基礎として、ソース言語ファイルが必要になります。 たとえば、開発者は理想的には「en.po」ファイルを持っており、翻訳者はそれを読んで「fr.po」に何を書くかを理解します。

翻訳が欠落していると、画面に意味のないキーが表示されます(翻訳されていないフランス語のページの「Hellothere、User!」ではなく「top_menu.welcome」)。

これは、公開する前に翻訳を完了させるので良いことですが、翻訳の問題がインターフェースで本当にひどいので悪いことです。 ただし、一部のライブラリには、特定の言語を「フォールバック」として指定するオプションが含まれており、他のアプローチと同様の動作をします。

Gettextマニュアルは、一般的に、問題が発生した場合に翻訳者とユーザーにとってより簡単であるため、最初のアプローチを支持しています。 これは、ここでも使用するアプローチです。

ただし、Symfonyのドキュメントでは、テンプレートに影響を与えることなくすべての翻訳を独立して変更できるように、キーワードベースの翻訳が推奨されていることに注意してください。

日常の使用法

一般的なアプリケーションでは、ページに静的テキストを書き込むときに、いくつかのGettext関数を使用します。

これらの文は、.poファイルに表示され、翻訳され、.moファイルにコンパイルされてから、実際のインターフェイスをレンダリングするときにGettextによって使用されます。 それを踏まえて、これまでに説明したことを段階的な例で結び付けましょう。

1.いくつかの異なるgettext呼び出しを含むサンプルテンプレートファイル

<?php include 'i18n_setup.php' ?> <div> <h1><?=sprintf(gettext('Welcome, %s!'), $name)?></h1> <!-- code indented this way only for legibility → <?php if ($unread): ?> <h2> <?=sprintf( ngettext('Only one unread message', '%d unread messages', $unread), $unread )?> </h2> <?php endif ?> </div> <h1><?=gettext('Introduction')?></h1> <p><?=gettext('We\'re now translating some strings')?></p>
  • gettext()は、msgidを特定の言語の対応するmsgidに変換するmsgstrです。 同じように機能する省略関数_()もあります

  • ngettext()は同じことをしますが、複数のルールがあります

  • dgettext()dngettext() )もあり、1回の呼び出しでドメインをオーバーライドできます(次の例でドメイン構成について詳しく説明します)。

2.サンプルセットアップファイル(上記で使用したi18n_setup.php)、正しいロケールを選択し、Gettextを構成します

Gettextの使用には、ボイラープレートコードが少し含まれますが、ほとんどの場合、localesディレクトリを構成し、適切なパラメータ(ロケールとドメイン)を選択する必要があります。

 <?php /** * Verifies if the given $locale is supported in the project * @param string $locale * @return bool */ function valid($locale) { return in_array($locale, ['en_US', 'en', 'pt_BR', 'pt', 'es_ES', 'es'); } //setting the source/default locale, for informational purposes $lang = 'en_US'; if (isset($_GET['lang']) && valid($_GET['lang'])) { // the locale can be changed through the query-string $lang = $_GET['lang']; //you should sanitize this! setcookie('lang', $lang); //it's stored in a cookie so it can be reused } elseif (isset($_COOKIE['lang']) && valid($_COOKIE['lang'])) { // if the cookie is present instead, let's just keep it $lang = $_COOKIE['lang']; //you should sanitize this! } elseif (isset($_SERVER['HTTP_ACCEPT_LANGUAGE'])) { // default: look for the languages the browser says the user accepts $langs = explode(',', $_SERVER['HTTP_ACCEPT_LANGUAGE']); array_walk($langs, function (&$lang) { $lang = strtr(strtok($lang, ';'), ['-' => '_']); }); foreach ($langs as $browser_lang) { if (valid($browser_lang)) { $lang = $browser_lang; break; } } } // here we define the global system locale given the found language putenv("LANG=$lang"); // this might be useful for date functions (LC_TIME) or money formatting (LC_MONETARY), for instance setlocale(LC_ALL, $lang); // this will make Gettext look for ../locales/<lang>/LC_MESSAGES/main.mo bindtextdomain('main', '../locales'); // indicates in what encoding the file should be read bind_textdomain_codeset('main', 'UTF-8'); // if your application has additional domains, as cited before, you should bind them here as well bindtextdomain('forum', '../locales'); bind_textdomain_codeset('forum', 'UTF-8'); // here we indicate the default domain the gettext() calls will respond to textdomain('main'); // this would look for the string in forum.mo instead of main.mo // echo dgettext('forum', 'Welcome back!'); ?>

3.最初の実行のための翻訳の準備

Gettextがカスタムフレームワークi18nパッケージに対して持つ大きな利点の1つは、その広範で強力なファイル形式です。

おそらく、「ああ、それを手で理解して編集するのは非常に難しいので、単純な配列の方が簡単だろう」と考えているかもしれません。 間違いなく、Poeditのようなアプリケーションが役に立ちます-たくさんあります。 プログラムは彼らのウェブサイトから入手できます。無料で、すべてのプラットフォームで利用できます。 これは非常に使いやすいツールであると同時に、非常に強力なツールです。Gettextが利用できるすべての機能を使用します。 ここでは、最新バージョンのPoedit1.8を使用します。

Poeditの内部を表示します。

最初の実行では、メニューから「ファイル>新規…」を選択する必要があります。 言語の入力を求められます。 翻訳する言語を選択/フィルタリングするか、 en_USpt_BRなどの前述の形式を使用します。

言語の選択。

次に、ファイルを保存します。前述のディレクトリ構造を使用します。 次に、[ソースから抽出]をクリックする必要があります。ここで、抽出および翻訳タスクのさまざまな設定を構成します。 これらはすべて、後で「カタログ>プロパティ」から見つけることができます。

  • ソースパス: gettext() (および兄弟)が呼び出されるプロジェクトのすべてのフォルダーを含めます。これは通常、テンプレート/ビューフォルダーです。 これが唯一の必須設定です。

  • 翻訳プロパティ:

    • プロジェクト名とバージョン、チームとチームの電子メールアドレス: .poファイルヘッダーに含まれる有用な情報。
    • 複数形:これらは前に述べた規則です。 Poeditにはすでに多くの言語の複数形の便利なデータベースが含まれているため、ほとんどの場合、デフォルトのオプションのままにしておくことができます。
    • 文字セット: UTF-8、できれば。
    • ソースコードの文字セット:コードベースで使用されている文字セット-おそらくUTF-8もそうですよね?
  • ソースキーワード:基盤となるソフトウェアは、 gettext()および同様の関数呼び出しがいくつかのプログラミング言語でどのように見えるかを知っていますが、独自の翻訳関数を作成することもできます。 ここで、これらの他のメソッドを追加します。 これについては、後の「ヒント」セクションで説明します。

これらのプロパティを設定した後、Poeditはソースファイルをスキャンして、すべてのローカリゼーション呼び出しを見つけます。 スキャンするたびに、Poeditは検出されたものとソースファイルから削除されたものの概要を表示します。 新しいエントリは翻訳テーブルに空になり、ローカライズされたバージョンの文字列を入力できるようになります。 保存すると、.moファイルが同じフォルダーに(再)コンパイルされ、プロジェクトが国際化されます。

プロジェクトは国際化されました。

Poeditは、Webおよび以前のファイルからの一般的な翻訳を提案することもできます。 便利なので、意味があるかどうかを確認して受け入れるだけです。 翻訳について不明な点がある場合は、ファジーとしてマークを付けると、黄色で表示されます。 青いエントリは、翻訳がないエントリです。

4.文字列の翻訳

お気づきかもしれませんが、ローカライズされた文字列には、単純なものと複数形の文字列の2つの主要なタイプがあります。

単純なものには、ソースとローカライズされた文字列の2つのボックスしかありません。 Gettext / Poeditにはソースファイルを変更する機能が含まれていないため、ソース文字列を変更することはできません。 むしろ、ソース自体を変更してファイルを再スキャンする必要があります。 (ヒント:翻訳行を右クリックすると、その文字列が使用されているソースファイルと行のヒントが表示されます。)

複数形の文字列には、2つのソース文字列を表示する2つのボックスと、さまざまな最終的なフォームを構成できるタブが含まれています。

最終フォームの構成。

Poeditの複数形の文字列の例で、それぞれの翻訳タブが表示されています。

ソースコードファイルを変更して翻訳を更新する必要がある場合は、[更新]をクリックするだけで、Poeditがコードを再スキャンし、存在しないエントリを削除し、変更されたエントリをマージして、新しいエントリを追加します。

Poeditは、あなたが行った他の翻訳に基づいて、いくつかの翻訳を推測しようとする場合もあります。 それらの推測と変更されたエントリには、レビューが必要であることを示す「ファジー」マーカーが表示され、リストに黄色で表示されます。

また、翻訳チームがいて、誰かがわからないことを書き込もうとした場合にも役立ちます。ファジーとマークするだけで、後で誰かがレビューします。

最後に、エントリを忘れないようにするために、[表示]>[未翻訳のエントリを最初に]マークを付けたままにしておくことをお勧めします。 そのメニューから、必要に応じて翻訳者にコンテキスト情報を残すことができるUIの一部を開くこともできます。

ヒントとコツ

Webサーバーが.moファイルをキャッシュしてしまう可能性があります。

PHPをApache(mod_php)でモジュールとして実行している場合、キャッシュされる.moファイルで問題が発生する可能性があります。 これは最初に読み取られたときに発生し、その後、更新するにはサーバーを再起動する必要がある場合があります。

NginxとPHP5では、通常、翻訳キャッシュを更新するのに数ページの更新しか必要ありません。PHP7では、それが必要になることはめったにありません。

ライブラリは、ローカリゼーションコードを短くするためのヘルパー関数を提供します。

多くの人が好むように、 gettext() )の代わりに_()を使用する方が簡単です。 フレームワークのカスタムi18nライブラリの多くは、翻訳されたコードを短くするために、 t()に似たものも使用しています。 ただし、ショートカットを使用できるのはそれだけです。

プロジェクトに、 ngettext()__()_n() )、またはgettext()sprintf()の呼び出しを結合する派手な_r()など、他のいくつかを追加することもできます。 oscaroteroのGettextなどの他のライブラリも、このようなヘルパー関数を提供します。

そのような場合、これらの新しい関数から文字列を抽出する方法についてGettextユーティリティに指示する必要があります。 恐れることはありません、それはとても簡単です。 これは、.poファイルのフィールドまたはPoeditの設定画面です(エディターでは、そのオプションは「カタログ>プロパティ>ソースキーワード」内にあります)。

注意:Gettextはすでに多くの言語のデフォルト関数を知っているので、そのリストが空に見えても心配しないでください。 この特定の形式に従って、新しい関数の仕様をそのリストに含める必要があります。

  • 文字列の翻訳を返すだけのt()のようなものを作成する場合は、それをtとして指定できます。 Gettextは、関数の引数が変換される文字列のみであることを認識します。

  • 関数に複数の引数がある場合は、最初の文字列がどれであるかを指定でき、必要に応じて複数形も指定できます。 たとえば、関数のシグネチャが__('one user', '%d users', $number)の場合、仕様は__:1,2になります。つまり、最初の形式が最初の引数で、2番目の形式が2番目の引数。 代わりにあなたの番号が最初の引数として来る場合、仕様は__:2,3になり、最初の形式が2番目の引数であることを示します。

これらの新しいルールを.poファイルに含めた後、新しいスキャンにより、以前と同じように簡単に新しい文字列が取り込まれます。

GettextでPHPアプリを多言語化

Gettextは、PHPプロジェクトを国際化するための非常に強力なツールです。 多数の人間の言語をサポートできる柔軟性に加えて、20を超えるプログラミング言語をサポートしているため、PHPでの使用に関する知識をPython、Java、C#などの他の言語に簡単に転送できます。

さらに、Poeditは、コードと翻訳された文字列の間のパスをスムーズにするのに役立ち、プロセスをより簡単でわかりやすくします。 また、Crowdinとの統合により、共有翻訳の取り組みを合理化することもできます。

可能な限り、ユーザーが話す可能性のある他の言語を検討してください。 これは、英語以外のプロジェクトにとって最も重要です。英語と母国語でリリースすると、ユーザーアクセスを向上させることができます。

もちろん、すべてのプロジェクトで国際化が必要なわけではありませんが、プロジェクトの初期段階でi18nを開始する方が、最初は必要ない場合でも、後で必要になった場合に開始するよりもはるかに簡単です。 また、GettextやPoeditなどのツールを使用すると、これまでになく簡単になります。

関連: PHP 7の概要:新機能と廃止内容