Translation for common models used in frontend seems to be not working

tl;dr I have an app-advanced scheme that has a view stored in frontend app. This view renders a typical grid-view that displays data fetched by model stored in common app. Everything seems to be correctly configured and yet only layout and views files are translated. The grid-view widget that uses model from common app is not translated.


I have a Yii 2 App Advanced-based application where I have an Examination model stored in /common/models/. This file has the following method defined:

public function attributeLabels()
{
    return [
        'id' => Yii::t('models', 'ID'),
        'patient_id' => Yii::t('models', 'Patient ID'),
        'created_by' => Yii::t('models', 'Created By'),
        'created_at' => Yii::t('models', 'Created At'),
        'updated_at' => Yii::t('models', 'Updated At'),
    ];
}

As you can see, it uses non-standard models category for translations.

I have run the following command:

php yii message common/i18n.php

And it correctly generated the /common/messages/pl/models.php file (among others, for different languages) with the correct content, which I have then partially translated:

return [
    'Created At' => 'Data utworzenia',
    'Created By' => 'Utworzone przez',
    'ID' => '',
    'Patient ID' => 'Identyfikator pacjenta',
    'Relation between examination and doctor is incorrect' => '',
    'Relation between examination and patient is incorrect' => '',
    'Updated At' => 'Data modyfikacji',
];

I have also a partially modified / translated /frontend/views/examination/index.php file where I use the following part:

Yii::t('app', 'Login')

This time using the default app category.

And I also have a widget configuration there:

<?= GridView::widget([
    'dataProvider' => $dataProvider,
    'columns' => [
        ['class' => 'yii\grid\SerialColumn'],

        'id',
        'patient_id',
        'created_by',
        'created_at',
        'updated_at',
        [
            'class' => ActionColumn::className(),
            'urlCreator' => function ($action, Examination $model, $key, $index, $column) {
                return Url::toRoute([$action, 'id' => $model->id]);
             }
        ],
    ],
]); ?>

The $dataProvider in this view is the very same Examination model (above) injected there by ExaminationController.php:

public function actionIndex()
{
    $dataProvider = new ActiveDataProvider([
        'query' => common\models\Examination::find(),
    ]);

    return $this->render('index', [
        'dataProvider' => $dataProvider,
    ]);
}

After executing another:

php yii message frontend/i18n.php

the /frontend/messages/pl/app.php file has been created with the content that I have also translated:

return [
    'Login' => 'Zaloguj się',
];

So I assume that the configuration for my translation files generator is correct.

I have a main application configuration file for my frontend app (stored in /frontend/config/main.php) with the following component added:

'i18n' => [
    'translations' => [
        'models' => [
            'class' => 'yii\i18n\PhpMessageSource',
            'fileMap' => [
                'app' => 'app.php',
                'app/error' => 'errors.php',
            ],
        ],
    ],
],

Which – I am getting things correctly – causes view files to be translated (among others).

I have also added quite similar configuration to my common app (stored in /common/config/main.php) with the following content:

'i18n' => [
    'translations' => [
        'models' => [
            'class' => 'yii\i18n\PhpMessageSource',
            'fileMap' => [
                'models' => 'models.php',
            ],
        ],
    ],
],

And yet, as in the introduction, the whole thing works only partially. Messages from frontend app are translated correctly, but the widget that uses model from common app is not translated.

What am I missing?

Hello @trejder Tomasz . I haven’t used translation at all so perhaps among more accurate clues, have you tried debug the widget lifecycle every single step? At some moment it has to look for translations because you have used them in ‘attributeLabels’ method but it misses, maybe looking in other location than you think it shoould. It’s tedious but it could get the answer for you.

Thanks for trying to help.

All I managed to figure out so far is that even though my Examination model is stored in common app (common namespace) when it is used inside the frontend app then Yii looks for the translation in files (folders) defined for frontend app, not for common app.

In other words, having models.php translation file inside /common/messages caused that models’ strings were not translated correctly. Moving it to /frontend/messages caused this file to by included by Yii and resulted in models’ strings to be translated correctly again.

Have you seen this little note in the api https://www.yiiframework.com/doc/api/2.0/yii-i18n-phpmessagesource#$fileMap-detail:

The file paths are relative to $basePath.

And by default $basePath is set to ‘@app/messages’.

How about to differentiate and manually set the $basePath in ‘fontend’ and ‘common’ translate component config? Have you tried it?

Thanks for your idea. This is exactly what I was about to use myself. I am pretty sure that with using $basePath and $fileMap I can achieve pretty much everything that I want.

Unfortunately this is not what I am asking for. This post was more like asking why model stored in common app / namespace / folder and only used in frontend app / namespace / folder is still using / looking for a translation stored in frontend, not in common.

This the only thing that I don’t understand. However, until someone with better knowledge of Yii 2 than mine isn’t going to shed some light here, I assume that this is “by design”. And I am trying to workaround this with the ideas that you have provided.

Do you follow the yii-advanced pattern in terms of config? In mentioned $basePath (so the @app alias too) is being set differently in every application (frontend, backed). Thus it should look for translation in different folder in ever application. Maybe someone had a chance to configure it before?

Yes, I do.

You are correct. The $basePath should be set differently for each application.

The thing is that either I don’t understand something or it isn’t. For the model located in common app it still uses $basePath set to frontend.

But, as I said. This topic is pretty much theoretical question on “What am I missing” rather than looking for a solution, because I already have a workaround for this (using $fileMap).

And it is different. Notice that ‘common’ is not an application. It is more like component you’re using in ‘frontend’, ‘backend’ applications. And what is most important, ‘common’ doesn’t set $basePath at all. Above mentioned does. Thus $basePath is never pointing to ‘common’ folder.

So you have solved my puzzle! :slight_smile:

Thank you!