3
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Yiiで気に入らない標準の翻訳文言を書き換える

Last updated at Posted at 2015-12-08

Yiiでは、エラー等に使うメッセージには翻訳ファイルを使います。標準のバリデーターやウィジェットを使うと、Yiiに同梱されたメッセージリソースが使われます。この標準の文言が気に入らないという場合、次の3つの方法があります。

特定のバリデーションエラーをカスタマイズしたい

フォームのバリデーション定義で、個々のルールに message プロパティを指定します。それを、yii カテゴリのものではなく app カテゴリ、つまりアプリケーションの翻訳リソースのものにしてしまいます。

    public function rules()
    {
        return [
            [['name'], 'required', 'message' => Yii::t('app', '{attribute} cannot be blank.')],
        ];
    }

そのまま文字列を書いてもかまいませんが、Yii::t() を使ってアプリケーション独自の翻訳リソースを使うようにすれば、サイトの多言語化に対応できます。

messages/ja/app.php
<?php
return [
    '{attribute} cannot be blank.' => '{attribute}は必須です。',
];

ユーザーが使うフォームが比較的少ないサイトであれば大丈夫ですが、フォームが多いと、すべての箇所にこのカスタマイズを仕込むのは大変です。

翻訳ファイルをすべて管理する

vendor/yiisoft/yii2/messages の全ファイルをアプリケーションの messages にコピーし、アプリケーションの i18n コンポーネントをカスタマイズして yii カテゴリでも @app/messages を参照するようにさせます。

config/web.php
$config = [
    'language' => 'ja',
    'components' => [
        'i18n' => [
            'translations' => [
                'yii' => [
                    'class' => 'yii\i18n\PhpMessageSource',
                    'sourceLanguage' => 'en-US',
                    'basePath' => '@app/messages',
                ],
            ],
        ],
    ],
];

もっとも簡単に文言変更が可能ですが、Yiiのマイナーバージョンアップ時に翻訳がメンテされる可能性を考えると、少々管理が大変です。

Yiiならなんでもカスタマイズできる

Yiiの翻訳リソースローダーは、翻訳システムとは独立したオブジェクトで、差し替え可能です。カテゴリごとに、独自形式のファイルやデータベースから読み込むローダーとさえ差し替えられるようになっています。

標準の PhpMessageSource は特定のカテゴリにおけるすべての言語の翻訳ファイルが一箇所におさまっている想定で実装されているところだけが不都合なので、少しオーバーライドして、ファイルの配置が柔軟に設定できるバージョンの PhpMessageSource を作ってみます。

utils/i18n/PhpMessageSource.php
<?php
namespace app\utils\i18n;

use Yii;

class PhpMessageSource extends \yii\i18n\PhpMessageSource
{
    /**
     * @var array
     *
     * 特定の言語のときのみ標準のパス以外からメッセージをロードする
     *
     * ~~~
     * [
     *     'ja' => '@app/messages/japanese',
     *     'en' => '@app/messages/english',
     * ]
     * ~~~
     */
    public $languagePathMap = [];

    /**
     * @inheritdoc
     */
    protected function getMessageFilePath($category, $language)
    {
        if (isset($this->languagePathMap[$language])) {
            $messageFile = rtrim(Yii::getAlias($this->languagePathMap[$language]), '/') . "/";
            if (isset($this->fileMap[$category])) {
                $messageFile .= $this->fileMap[$category];
            } else {
                $messageFile .= str_replace('\\', '/', $category) . '.php';
            }
            return $messageFile;
        } else {
            return parent::getMessageFilePath($category, $language);
        }
    }
}

この実装を使って...

config/web.php
$config = [
    'language' => 'ja',
    'components' => [
        'i18n' => [
            'translations' => [
                'yii' => [
                    'class' => 'app\utils\i18n\PhpMessageSource',
                    'sourceLanguage' => 'en-US',
                    'basePath' => '@yii/messages',
                    'languagePathMap' => [
                        'ja' => '@app/messages/ja',
                    ],
                ],
            ],
        ],
    ],
];

これで、yii カテゴリの翻訳は、日本語の場合だけ @yii/messages/* (vendorの中) の代わりに @app/messages/ja から読むという設定になりました。

あとは vendor の下から messages/ja/yii.php にコピーして... よりも、こんなふうに、部分書き換えをしてやるといかがでしょうか。

messages/ja/yii.php
<?php
return array_merge(include(\Yii::getAlias('@yii/messages/ja/yii.php')), [

    // 気に入らない: '{attribute} cannot be blank.' => '{attribute}は空白ではいけません。',

    '{attribute} cannot be blank.' => '{attribute}は必須です。',
]);

こんなのは超絶コンフィグ可能なライブラリなら想定済みなのかもしれませんが、Yiiの考え方では、素朴な実装で高速な動作を尊重します。そこで、ごく普通にユーザーとして使っている人でも、フレームワークのソースをちょっと調べるだけで、標準機能が仕事に合わない箇所をカスタマイズできる。この点が Yii の素敵なところですね。

3
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?