0

On my application I have a custom plugin with a form of about 80 translatable fields. The form will be available in the backend (for admins) and in the frontend (for end users) with the same labels.

I would like to use the Rainlab Translate plugin to translate all the field's labels so the admins can easily change them to suit their needs.

The problem is that all the backend translations are stored in the file system (e.g /plugins/my-plugin/lang/en/lang.php).

Would it be possible to manage a custom plugin's translations with the Rainlab Translate plugin ? This will avoid having duplicates between the php translation files and the database.

I've installed Rainlab Translate plugin so far to translate the front-end in french and german.

Thank you guys!

David Galvis
  • 11
  • 1
  • 3

2 Answers2

1

I came up with a solution creating a custom Plugin that extends the October CMS Backend Translator service. I've added the following code to the boot() method of my plugin :

 // Custom Backend Translator that handles the Backend localisation with the Rainlab Translator plugin
    $this->app->singleton('translator', function ($app) {
        $loader = $app['translation.loader'];

        // When registering the translator component, we'll need to set the default
        // locale as well as the fallback locale. So, we'll grab the application
        // configuration so we can easily get both of these values from there.
        $locale = $app['config']['app.locale'];
        // extending October CMS Translator class
        $trans = new Translator($loader, $locale);
        // setting locale to message
        Message::$locale = $locale;

        $trans->setFallback($app['config']['app.fallback_locale']);

        return $trans;
    });

I've create a Translator class that extends the default one and implements a database lookup for translations. It also has a fallback to the default array file based translations if no translation is found.

<?php namespace Author\MyPlugin\Classes\Translation;

use Author\MyPlugin\Classes\Translation\Message as Message;

class Translator extends \October\Rain\Translation\Translator
{
    /**
     * Get the translation for the given key.
     *
     * @param  string $key
     * @param  array $replace
     * @param  string $locale
     * @return string
     */
    public function get($key, array $replace = [], $locale = null)
    {
        // getting translation from database
        $message = Message::trans($key);
        // if there's a translation we return it
        if ($message != null && $message !== $key) {
            return $message;
        }
        // otherwise fallback to file array translations
        return parent::get($key, $replace, $locale);
    }
}

And the code of the Message class below:

<?php namespace Author\MyPlugin\Classes\Translation;


class Message extends \RainLab\Translate\Models\Message
{
    /**
     * Creates or finds an untranslated message string.
     * @param  string $messageId
     * @return string
     */
    public static function get($messageId)
    {
        if (!self::$locale) {
            return $messageId;
        }

        if (!is_string($messageId)) {
            return null;
        }

        // we let full translation key for the backend
        if (!\App::runningInBackend()) {
            $messageCode = self::makeMessageCode($messageId);
        } else {
            $messageCode = $messageId;
        }

        /*
        * Found in cache
        */
        if (array_key_exists($messageCode, self::$cache)) {
            return self::$cache[$messageCode];
        }

        /*
         * Uncached item
         */
        $item = static::firstOrNew([
            'code' => $messageCode
        ]);

        /*
         * Create a default entry
         */
        if (!$item->exists) {
            $data = [static::DEFAULT_LOCALE => $messageId];
            $item->message_data = $item->message_data ?: $data;
        }

        /*
         * Schedule new cache and go
         */
        $msg = $item->forLocale(self::$locale, $messageId);
        self::$cache[$messageCode] = $msg;
        self::$hasNew = true;

        return $msg;
    }
}

Any feedback of this solution is welcome.

David Galvis
  • 11
  • 1
  • 3
0

In theory I think it should be possible to return an array that is loaded through the Translate instance, instead of returning a predefined array.

So instead of returning a simple array in lang/en/lang.php you fill the array with keys that match the keys from the front-end.

So instead of:

return [
    'key' => 'language-string'
];

Do something like this:

  • Retrieve all language-keys
  • Loop through all keys and get correct language-string
  • Add keys to an assoc-array

Update:

The quickest way I could find is to make a config file with all related keys, and use that in a query on the rainlab_translate_messages table. You convert all values to the correct format (assoc array) and your return this in the lang.php file.

It's insanely hacky, feels dirty and probably is very error-prone. But should work.

Note: If someone comes up with a better way, please use that. This isn't really something I would advise. But hey, I guess it works.