【Laravel】言語ファイルを別言語に自動翻訳する

 Laravel は PHP のフレームワークであり、多様な言語の話者が web サイトを見る場合の便利機能も備えています。これは次の多言語化にまとまっています。この仕組みは Laravel に設定された、あるいは動的に設定されるロケールにしたがってresources/lang/{ロケール}/validation.phpなどのメッセージファイルを読み取り、それを出力できるようにする、というものです。
多言語化 8.x Laravel
 便利なのですが言語数 * メッセージ数のメッセージ文字列を用意するのは非常に手間です。ここでは Google 翻訳でこれを自動で他言語に変換するスクリプトを紹介します。これを使えば、メッセージ数分だけのメッセージ文字列を用意すれば大丈夫です(もっとも厳密に多言語化するならばきちんとした翻訳をするべきですが)。

 Google 翻訳には API が存在し、これを楽に使うためのライブラリ google-translate-php があります。
Stichoza/google-translate-php: 🌐 Free Google Translate API PHP Package. Translates totally free of charge.
 メッセージファイルを読み込み、google-translate-php で翻訳し、メッセージファイルとして出力することでスクリプトによる自動翻訳を実現します。

 ソースコードは次で、app/Console/Commands/LangTranslateDumper.php に配置してphp artisan dev:lang-translate-dumperと打てば、それで起動します。ソースコード内では日本語から英語への変換を決め打ちしていますが、ソースコード内に現れる”ja”, “en”を代えることで別言語の翻訳もできます。

<?php

namespace App\Console\Commands;

use Illuminate\Console\Command;
use Stichoza\GoogleTranslate\GoogleTranslate;

class LangTranslateDumper extends Command
{
    protected $name        = 'dev:lang-translate-dumper';
    protected $description = '日本語から翻訳した言語ファイルをダンプする';

    /**
     * @throws \ErrorException
     */
    public function handle(): void
    {
        $translator = $this->getTranslator();
        // メッセージファイルへのフルパスを全て取得
        foreach (glob(resource_path('lang/ja/*')) as $file) {
            // メッセージファイルが配列なので require で中身を実体にできます。
            $messages           = require $file;
            // メッセージファイルの中身を翻訳
            $translatedMessages = $this->recursiveTranslate($translator, $messages);
            // 翻訳結果配列を PHP ソースコード文字列に変換
            $arrStr             = var_export($translatedMessages, true);
            // メッセージファイルとして完成された PHP ソースコード文字列を生成
            $phpCode            = <<<CODE
<?php

return {$arrStr};

CODE;
            // 翻訳結果を翻訳対象言語ファイルとして保存
            file_put_contents(str_replace('/ja/', '/en/', $file), $phpCode);
            $this->info('output: '.str_replace('/ja/', '/en/', $file));
        }
    }

    /**
     * 翻訳用ライブラリを準備
     * @see https://github.com/Stichoza/google-translate-php
     * @return GoogleTranslate
     */
    public function getTranslator(): GoogleTranslate
    {
        $tr = new GoogleTranslate();
        $tr->setSource('ja');
        $tr->setSource();
        $tr->setTarget('en');

        return $tr;
    }

    /**
     * 多次元配列のメッセージを Google 翻訳に再帰的にかける
     * @param GoogleTranslate        $translator
     * @param float|int|string|array $message
     *@throws \ErrorException
     * @return float|int|string|array|null
     */
    private function recursiveTranslate(GoogleTranslate $translator, $message)
    {
        if (is_string($message)) {
            // 文字列ならば翻訳すべきメッセージとして処理
            // :hoge の置き換え文字列を翻訳対象から退避
            $this->info('pre translate: '.$message);
            preg_match_all('/:[a-zA-Z0-9]+/', $message, $replacers);
            $replacedMessage = str_replace(
                $replacers[0],
                array_map(static fn ($i) => "@$i", range(0, count($replacers))),
                $message
            );
            // 翻訳
            $translateMsg = $translator->translate($replacedMessage);
            // 退避した翻訳文字列を復元
            $ret = str_replace(
                // この "@ ${インデックス番号}"はgoogle翻訳の仕様の変更で簡単に崩れるので注意
                array_map(static fn ($i) => "@ $i", range(0, count($replacers))),
                $replacers[0],
                $translateMsg,
            );
            $this->warn('post translate: '.$ret);
            sleep(1); // Google 翻訳への過剰アクセス防止
            return $ret;
        }
        if (is_int($message) || is_float($message) || $message === null) {
            // 数値や空ならばそのまま返す
            return $message;
        }
        if (is_array($message)) {
            // 配列ならば更に配列の深いところへ潜る
            foreach ($message as $key => $item) {
                $message[$key] = $this->recursiveTranslate($translator, $item);
            }
        }

        // 全て翻訳し終わった結果を返す
        return $message;
    }
}

 これを実行すると次の様に翻訳結果がコンソールに都度出力され、ファイルについて処理が終わる度にファイルが出力されます。

 URL を作る都合なのか & を含むなど一部文字列については google-translate-php がうまく動いてくれず、そういった特殊なメッセージこそ手作業をしなければなりません。とはいえ、それを含めても非常に楽に言語ファイルを作れる様になります。

>株式会社シーポイントラボ

株式会社シーポイントラボ

TEL:053-543-9889
営業時間:9:00~18:00(月〜金)
住所:〒432-8003
   静岡県浜松市中央区和地山3-1-7
   浜松イノベーションキューブ 315
※ご来社の際はインターホンで「316」をお呼びください

CTR IMG