How to use Yii2 i18n DbMessageSource with oracle database

  1. create database table as following schema

/Database Schema for oracle database/

drop table if exists "source_message";

drop table if exists "message";

CREATE TABLE "source_message"

(

"id"          integer NOT NULL PRIMARY KEY,


"category"    varchar(255),


"message"     clob

);

CREATE SEQUENCE "source_message_SEQ";

CREATE TABLE "message"

(

"id"          integer NOT NULL,


"language"    varchar(16) NOT NULL,


"translation" clob,


primary key ("id", "language"),


foreign key ("id") references "source_message" ("id") on delete cascade

);

CREATE INDEX idx_message_language ON "message"("language");

CREATE INDEX idx_source_message_category ON "source_message"("category");

  1. Extend the yii\i18n\DbMessageSource Class to common\components\CDbMessageSource.php as following,



<?php

namespace common\components;


use Yii;

use yii\db\Expression;

use yii\helpers\ArrayHelper;

use yii\db\Query;

use yii\i18n\DbMessageSource;


class CDbMessageSource extends DbMessageSource

{


    /**

     * Loads the messages from database.

     * You may override this method to customize the message storage in the database.

     * @param string $category the message category.

     * @param string $language the target language.

     * @return array the messages loaded from database.

     */

    protected function loadMessagesFromDb($category, $language)

    {

        $mainQuery = (new Query())->select(['message' => 'to_char("t1"."message")', 'translation' => 'to_char("t2"."translation")'])

            ->from(['t1' => $this->sourceMessageTable, 't2' => $this->messageTable])

            ->where([

                't1.id' => new Expression('[[t2.id]]'),

                't1.category' => $category,

                't2.language' => $language,

            ]);


        $fallbackLanguage = substr($language, 0, 2);

        $fallbackSourceLanguage = substr($this->sourceLanguage, 0, 2);


        if ($fallbackLanguage !== $language) {

            $mainQuery->union($this->createFallbackQuery($category, $language, $fallbackLanguage), true);

        } elseif ($language === $fallbackSourceLanguage) {

            $mainQuery->union($this->createFallbackQuery($category, $language, $fallbackSourceLanguage), true);

        }


        $messages = $mainQuery->createCommand($this->db)->queryAll();

        return ArrayHelper::map($messages, 'message', 'translation');

    }


    /**

     * The method builds the [[Query]] object for the fallback language messages search.

     * Normally is called from [[loadMessagesFromDb]].

     *

     * @param string $category the message category

     * @param string $language the originally requested language

     * @param string $fallbackLanguage the target fallback language

     * @return Query

     * @see loadMessagesFromDb

     * @since 2.0.7

     */

    protected function createFallbackQuery($category, $language, $fallbackLanguage)

    {

        return (new Query())->select(['message' => 'to_char("t1"."message")', 'translation' => 'to_char("t2"."translation")'])

            ->from(['t1' => $this->sourceMessageTable, 't2' => $this->messageTable])

            ->where([

                't1.id' => new Expression('[[t2.id]]'),

                't1.category' => $category,

                't2.language' => $fallbackLanguage,

            ])->andWhere([

                'NOT IN', 't2.id', (new Query())->select('[[id]]')->from($this->messageTable)->where(['language' => $language])

            ]);

    }

}




  1. component can be configured in the application configuration as follows,



'components' => [

    // ...

    'i18n' => [

        'translations' => [

            'app*' => [

                'class' => 'common\components\CDbMessageSource',

            ],

        ],

    ],

],



  1. Wrap a text message

The method Yii::t() can be used like the following,




echo \Yii::t('app', 'This is a string to translate!');