Translating strings using online tools

Hi.
We need to translate our app, we have more than 4000 strings and while yii2-translate-manager is an awesome extension it doesn’t offer all the features of other online tools, like Weblate. The big things we’re looking after are glossary and translation memory.

I did a quick search, and it looks like the translation files format used by Yii2 is not very common, I couldn’t find any platform accepting it. Also we’d like to stick with the extension above, as it supports translating database tables. Unfortunately, exporting from yii2-translate-manager doesn’t seem an option either, as it uses only JSON and XML with a custom formatting…

Does anyone have experience with other translation services playing nice with yii2-translate-manager, or with yii2 at least?

Thanks

I think https://crowdin.com/ supported both PHP arrays and gettext (you can use it in Yii 2 as well). Localise supports PHP arrays for sure: https://docs.lokalise.com/en/articles/1400791-php-arrays-php

AFAIK PHP arrays created by Yii2 are not the expected arrays by most translation platforms.

The platforms I found use a key => string format, while Yii has original => translation.

No, it’s fine. Key, in case of default usage of Yii, is original string but it’s still a key. No technical issue.

I figured out how to configure Weblate for Yii2. It requires the source language file to have array values populated with the same string as the key:

return [
   'example string' => 'example string',
...

I added the source language to the 'languages' to be generated by the extractor, but I still need to update the file with the source strings.

Is there some way I can hook to the message/extract command, and adjust the source language file as I need it? I checked the controller source but I haven’t been able to find a way. I cannot even override the controller with a child class, as all methods are protected… I hope I have missed an option.

Otherwise, I need to implement a custom controller/action, but then I must remember to run it every time I run extract.

protected means you can extend from the command class and then use command map to replace the command so when you run message/extract you actually use your new command class.

This is how I implemented it:

<?php

/*
 * This file is part of the YetOpen Helpers Extension project.
 * (c) YetOpen <https://yetopen.com>
 * For the full copyright and license information, please view
 * the LICENSE file that was distributed with this source code.
 */

namespace yetopen\helpers\controllers;

use Yii;
use yii\console\controllers\MessageController as BaseMessageController;
use yii\console\ExitCode;
use yii\helpers\Console;
use yii\helpers\VarDumper;

/**
 * MessageController override for creating `sourceLanguage` translation file with keys
 * matching message string, to be used in Weblate.
 *
 * Prerequisites:
 * 1. controllerMap > message must be configured to link this class
 * 2. app's translation config must include app's `sourceLanguage`
 */
class MessageController extends BaseMessageController
{
    /**
     * Override of the original method to write a full `sourceLanguage` file in 'msg' => 'msg' format.
     * WARNING: the translation config must contain `sourceLanguage` in `languages`.
     *
     * @param array $messages
     * @param string $fileName name of the file to write to
     * @param bool $overwrite if existing file should be overwritten without backup
     * @param bool $removeUnused if obsolete translations should be removed
     * @param bool $sort if translations should be sorted
     * @param string $category message category
     * @param bool $markUnused if obsolete translations should be marked
     * @return int exit code
     */
    protected function saveMessagesCategoryToPHP($messages, $fileName, $overwrite, $removeUnused, $sort, $category, $markUnused)
    {
        // We need to act when the message file we're handling is for app's `sourceLanguage`. At this time we don't have
        // the language anywhere but in `$fileName`, which is in `.../{language}/{category}.php` format.
        $lastDir = dirname($fileName);
        $langFile = substr($lastDir, strrpos($lastDir, DIRECTORY_SEPARATOR) + 1);

        // If the request is for a translation file, process it normally
        if ($langFile != Yii::$app->sourceLanguage) {
            return parent::saveMessagesCategoryToPHP($messages, $fileName, $overwrite, $removeUnused, $sort, $category, $markUnused);
        }

        // Otherwise write the full lang file (portions of code from original method)
        $merged = array_combine($messages, $messages);
        ksort($merged);
        $array = VarDumper::export($merged);
        $content = <<<EOD
<?php
{$this->config['phpFileHeader']}{$this->config['phpDocBlock']}
return $array;

EOD;

        if (file_put_contents($fileName, $content, LOCK_EX) === false) {
            $this->stdout("sourceLanguage file was NOT saved.\n\n", Console::FG_RED);
            return ExitCode::UNSPECIFIED_ERROR;
        }

        $this->stdout("sourceLanguage file saved.\n\n", Console::FG_GREEN);
        return ExitCode::OK;
    }
}