Yii2-advanced:Redisのソースで国際化を行う

Yii2には、国際化のための3つのオプションを実装する機能があります。



  1. 次の形式の配列ファイル:key => translation(柔軟に)
    ヘルプリンク:



    コレクターの構成ファイルを作成します



    コンソールコマンドを実行する

    php ./yii message/config @common/config/i18n.php //   php ./yii message/config-template @common/config/i18n.php
          
          





    ps Windows環境の場合php yii .....コンソールでの作業を構成する必要があります 必要なコンポーネントを接続する必要があります。



    /common/config/i18n.phpファイルを作成する必要があります。

     return [ 'sourcePath' => __DIR__. '..' . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR, 'languages' => ['pt-PT','ru-RU','uk-UA','en-US'], //      'translator' => 'Yii::t', 'sort' => false, 'removeUnused' => false, 'only' => ['*.php'],//       'except' => [//   '.svn', '.git', '.gitignore', '.gitkeep', '.hgignore', '.hgkeep', '/messages', '/vendor', ], 'format' => 'php',//    'messagePath' => __DIR__ . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . 'messages', 'overwrite' => true, ];
          
          







    翻訳を保存するためのcommon / messagesフォルダーを作成してください!



    国際化コンポーネントを追加



    構成ファイルcommon / main.php

     'language'=> 'pt-PT',//  'sourceLanguage' => 'uk-UA',//  'components' => [ ... 'i18n' => [ 'translations' => [ 'frontend*' => [ 'class' => 'yii\i18n\PhpMessageSource', 'basePath' => '@common/messages', /* fileMap ,       .        'fileMap' => [ 'app' => 'app.php', 'app/error' => 'error.php', ],*/ ], 'backend*' => [ 'class' => 'yii\i18n\PhpMessageSource', 'basePath' => '@common/messages', ], //       *     '*' => [ 'class' => 'yii\i18n\PhpMessageSource', 'basePath' => '@common/messages', 'on missingTranslation' => ['common\components\TranslationEventHandler', 'handleMissingTranslation']//     ], ], ], ....
          
          







    提出物はどうあるべきか



    Yiiドキュメントの例:: t()

      //     /        frontend/home.php echo \Yii::t('frontend/home', 'key home'); echo \Yii::t('frontend/login', 'key login');
          
          





    カテゴリ名には、使用するページの名前が含まれているとよいでしょう。 翻訳を検索するとき、Yiiはカテゴリ全体を選択します。



    見つからない翻訳のハンドラー



      common\components\TranslationEventHandler.php namespace common\components; use yii\i18n\MissingTranslationEvent; class TranslationEventHandler { public static function handleMissingTranslation(MissingTranslationEvent $event) { //     $event->translatedMessage = "@MISSING: {$event->category}.{$event->message} FOR LANGUAGE {$event->language} @"; //    } }
          
          







    キーの作成を開始



    php yii message/extract @common/config/i18n.php





    その後、ファイルを作成する必要があります。

    • 共通\メッセージ\ ru-RU \フロントエンド\ home.php
    • common \ messages \ uk-UA \ frontend \ home.php
    • common \ messages \ en-US \ frontend \ home.php
    • common \ messages \ ru-RU \ frontend \ login.php
    • common \ messages \ uk-UA \ frontend \ login.php
    • common \ messages \ en-US \ frontend \ login.php
    • ....


    フォルダ構造はカテゴリ名に依存します。 これは、フロントエンド/ログインおよびフロントエンド\ホームに基づいています

    このタイプのカテゴリ(キー)を使用した場合Yii::t('frontend','home')





    すべての翻訳が含まれる各言語(common \ messages \ ru-RU \ frontend.php)にすべて1つのファイルを作成し、1つのビューを翻訳するために、Yiiはこのページで必要のないすべての翻訳をダウンロードします。



    ファイルは次のようになります。

     return [ 'key home' => '', 'key login' => '' ];
          
          





    私たちは自分自身を翻訳します。



    ファイルビュー/ site / ru-RU / index.phpを作成し、デフォルトの言語language = ru-RUを作成すると、このビューが最初にレンダリングされます。





  2. 拡張子が.po、.moバイナリのファイル(コンパイラが必要、高速)
    ヘルプリンク:



    構成ファイルの作成



    php yii message/config @common/config/i18n.php





    ファイルcommon / config / i18n.phpを取得します

     return [ 'color' => null, 'interactive' => true, 'sourcePath' => __DIR__. '..' . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR, 'languages' => ['pt-PT','ru-RU','uk-UA','en-US'], 'translator' => 'Yii::t', 'sort' => false, 'removeUnused' => false, 'only' => ['*.php'], 'except' => [ '.svn', '.git', '.gitignore', '.gitkeep', '.hgignore', '.hgkeep', '/messages', '/vendor', ], 'format' => 'po', 'messagePath' => __DIR__ . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . 'messages', 'overwrite' => true, ];
          
          





    これはphp形式と同じです。 フォーマットのみが異なります:) 'format' => 'po'







    翻訳を保存するためのcommon / messagesフォルダーを作成してください!



    この形式とphp形式の違いは、 php yii message/extract @common/config/i18n.php



    コマンドでアプリケーションからキーを収集した後、拡張子.so(frontend.so)のファイルがcommon \ messagesフォルダーにphp yii message/extract @common/config/i18n.php



    され、プログラムでコンパイルされることです、たとえばpoeditウィンドウと単純な保存では、拡張子が.soのバイナリファイルが作成されます。





  3. Mysqlデータベース、キーと翻訳用の2つのテーブル
    ヘルプリンク:



    common / config / i18n.php構成ファイルを作成します



    コマンドを実行する

    php yii message/config @common/config/i18n.php





    次の一般的な/ config / i18n.phpファイルが作成されます。

     return [ 'color' => null, 'interactive' => true, 'help' => null, 'sourcePath' => __DIR__. '..' . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR, 'messagePath' => __DIR__ . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . 'messages', 'languages' => ['pt-PT','ru-RU','uk-UA','en-US'],//       'translator' => 'Yii::t', 'sort' => false, 'overwrite' => true, 'removeUnused' => false, 'markUnused' => true, 'except' => [ '.svn', '.git', '.gitignore', '.gitkeep', '.hgignore', '.hgkeep', '/messages', '/BaseYii.php', ], 'only' => [ '*.php', ], 'format' => 'db', 'db' => 'db', 'sourceMessageTable' => '{{%source_message}}',//      'messageTable' => '{{%message}}',//     'ignoreCategories' => ['yii'],//   ];
          
          







    コンポーネントを追加



    コンポーネントの例は、php形式のバージョンです

    構成ファイルcommon / main.php

     'language'=> 'ru-RU',//  'sourceLanguage' => 'uk-UA',//  'components' => [ ... 'i18n' => [ 'translations' => [ // * -   '*' => [ 'class' => 'yii\i18n\DbMessageSource', 'on missingTranslation' => ['common\components\TranslationEventHandler', 'handleMissingTranslation'] ], ], ], ....
          
          







    見つからない翻訳の一般的な\ components \ TranslationEventHandlerのハンドラーもphp形式の例にあります



    ビューには、コンポーネントYii :: t()のメソッドへの呼び出しが必要です。ヘルプリンクを参照してください

    例:

     echo \Yii::t('frontend/home', 'key home') ; echo \Yii::t('frontend/login', 'key login') ;
          
          







    移行を実行



    翻訳を保存するには、テーブル作成スクリプトを実行します

    php yii migrate --migrationPath=@yii/i18n/migrations





    2つのテーブルが作成されます。

     --  CREATE TABLE IF NOT EXISTS `source_message` ( `id` int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY, `category` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL, `message` text COLLATE utf8_unicode_ci, KEY `idx_source_message_category` (`category`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; --  CREATE TABLE IF NOT EXISTS `message` ( `id` int(11) NOT NULL PRIMARY KEY, `language` varchar(16) COLLATE utf8_unicode_ci NOT NULL, `translation` text COLLATE utf8_unicode_ci, KEY `idx_message_language` (`language`), CONSTRAINT `fk_message_source_message` FOREIGN KEY (`id`) REFERENCES `source_message` (`id`) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci;
          
          







    これで、コンソールコマンドを実行してすべてのカテゴリを収集し、データベースに保存できます

    php yii message/extract @common/config/i18n.php







Mongoに翻訳を保存することもできます。


ただし、自分でキーのコレクションを作成する必要があります。

yii \ mongodb \ i18n \ MongoDbMessageSource
類推によって...

国際化コンポーネント
 return [ 'language'=> 'uk-UA',//'ru-RU', //.... 'components' => [ // ... 'i18n' => [ 'translations' => [ '*' => [ 'class' => 'yii\mongodb\i18n\MongoDbMessageSource' ] ] ], ] ];
      
      







コレクションを作成します。



 $messages=Yii::$app->mongodb->getCollection('messages'); $messages->insert([ "_id"=>1, "category"=>"frontend/index", "language"=>"uk", "messages"=>["Hello world!"=>"і Welt!","Hello"=>"і"] ]); $messages->insert([ "_id"=>2, "category"=>"frontend/index", "language"=>"ru", "messages"=>["Hello world!"=>" Welt!","Hello"=>""] ]);
      
      







次のドキュメントを取得します。
 { "_id": 1, "category": "frontend/index", "language": "uk", "messages": { "Hello world!": "і Welt!", "Hello": "і" } }, { "_id": 2, "category": "frontend/index", "language": "ru", "messages": { "Hello world!": "Hallo Welt!", "Hello": "" } }
      
      









そして、あなたが転送を呼び出すとき



echo \Yii::t('frontend/index', 'Hello');

echo \Yii::t('frontend/index', 'Hello world!');







言語'language'=> 'uk-UA'



のメッセージコレクションからの選択が機能します。

カテゴリ"category": "frontend/index"



カテゴリのすべてのキーを一度に取得します。すべての翻訳を最大限に活用するカテゴリを決定することは理にかなっています。





または、データベース内の翻訳のストレージをベースとして、独自の管理(キー生成、転送、およびストレージ)を使用するバージョン。



メイン





長所は何ですか:





i18n.php構成ファイルの作成



まず、次のコンソールコマンドを使用してキーコレクター構成ファイルを作成します。



 php yii message/config @common/config/i18n.php
      
      





このコンソールコマンドの後、i18n.phpファイルはcommon / config /に表示されるか、次のように作成されます。



common / config / i18n.php
  return [ 'color' => null, 'interactive' => true, 'help' => null, 'sourcePath' => __DIR__. '..' . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR, 'languages' => ['ru-RU','uk-UA','en-US'],//    'translator' => 'Yii::t', 'sort' => false, 'overwrite' => true, 'removeUnused' => false, 'markUnused' => true, 'except' => [ '.svn', '.git', '.gitignore', '.gitkeep', '.hgignore', '.hgkeep', '/messages', '/BaseYii.php', ], 'only' => [ '*.php', ], 'format' => 'db', 'db' => 'db', //'messageTable' => '{{%message}}', //       gr_dictionary 'sourceMessageTable' => '{{%gr_dictionary}}',//   'ignoreCategories' => ['yii'], ];
      
      





MySQLでテーブルを作成する



次に、翻訳を含むすべての言語のメインストレージ用に3つのテーブルを作成します。



gr_language(言語)
 CREATE TABLE IF NOT EXISTS `gr_language` ( `id` smallint(5) unsigned NOT NULL AUTO_INCREMENT PRIMARY KEY, `code_lang` varchar(255) NOT NULL, `local` varchar(255) NOT NULL, `name` varchar(255) NOT NULL, `status` tinyint(4) NOT NULL DEFAULT '1', UNIQUE KEY `code_lang` (`code_lang`), UNIQUE KEY `local` (`local`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; INSERT INTO `gr_language` (`id`, `code_lang`, `local`, `name`, `status`) VALUES (1, 'en', 'en-US', 'English', 1), (2, 'ru', 'ru-RU', '', 1), (3, 'uk', 'uk-UA', 'ї', 1);
      
      







gr_dictionary_keys(キー)
  --    CREATE TABLE IF NOT EXISTS `gr_dictionary_keys` ( `id` int(10) unsigned NOT NULL AUTO_INCREMENT PRIMARY KEY, `key` varchar(250) NOT NULL, UNIQUE KEY `id` (`id`), KEY `key` (`key`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
      
      







gr_dictionary(翻訳)
 --    CREATE TABLE IF NOT EXISTS `gr_dictionary` ( `id` int(11) NOT NULL AUTO_INCREMENT PRIMARY KEY, `language_id` smallint(5) unsigned NOT NULL, `key` int(10) unsigned NOT NULL, `value` varchar(255) NOT NULL COMMENT '', `translator` text NOT NULL COMMENT '', `type` set('w','m') DEFAULT NULL COMMENT 'w/m /', `status` tinyint(4) NOT NULL DEFAULT '1', CONSTRAINT `gr_dictionary_ibfk_1` FOREIGN KEY (`language_id`) REFERENCES `gr_language` (`id`) ON DELETE CASCADE ON UPDATE CASCADE, CONSTRAINT `gr_dictionary_ibfk_2` FOREIGN KEY (`key`) REFERENCES `gr_dictionary_keys` (`id`) ON DELETE CASCADE ON UPDATE CASCADE, UNIQUE KEY `language_id` (`language_id`,`key`,`type`), KEY `code_lang` (`language_id`), KEY `type` (`type`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
      
      







コンソールコントローラーを再定義する



次に、キーを収集する前に、すべてのキーを収集するコンソールコントローラー\ yii \ console \ controllers \ MessageControllerを再定義します。 これを行うには、それから継承される独自のコントローラーを作成します。



この種類のconsole \ controllers \ Message2Controller.phpファイルを作成します。



コンソール\コントローラー\ Message2Controller.php
 namespace console\controllers; use Yii; use yii\console\Exception; class Message2Controller extends \yii\console\controllers\MessageController { /** * Saves messages to database * * @param array $messages     [[]=>[[],[...]] ,... ] * @param \yii\db\Connection $db * @param string $sourceMessageTable     * @param string $messageTable   * @param boolean $removeUnused * @param array $languages    languages  i18n.php ['ru-RU',...] * @param boolean $markUnused */ protected function saveMessagesToDb($messages, $db, $sourceMessageTable, $messageTable, $removeUnused, $languages, $markUnused) { try{ $pr_iskey=Yii::$app->db->createCommand("SELECT `id` FROM `gr_dictionary_keys` WHERE `key`=:key"); $pr_inskey=Yii::$app->db->createCommand("INSERT INTO `gr_dictionary_keys`( `key`) VALUES (:key)"); $pr_delkey=Yii::$app->db->createCommand("DELETE FROM `gr_dictionary_keys` WHERE `id`=:id"); $id_lang=[]; $pr_l=Yii::$app->db->createCommand("SELECT SQL_NO_CACHE id FROM gr_language WHERE local=:local LIMIT 1"); foreach ($languages as $language) { if(!isset($id_lang[$language])){ $id_language=(int)$pr_l->bindValue(":local", $language,2)->queryScalar(); if(empty($id_language)){ continue; // throw new Exception("Unknow lang type $language"); } $id_lang[$language]=(int)$id_language; } } if(empty($id_lang))throw new Exception("empty lang"); //ALTER TABLE `yii2advanced`.`gr_dictionary` ADD UNIQUE (`language_id`, `key`, `type`); $pr_d=Yii::$app->db->createCommand("INSERT IGNORE INTO `gr_dictionary`( `language_id`, `key`, `value`, `type`) VALUES (:language_id,:key,:value,:type)"); foreach ($messages as $category => $msgs){ list($type,$key)=explode(":", $category); if(empty($id=$pr_iskey->bindValue(":key", $key,2)->queryScalar())){ $pr_inskey->bindValue(":key", $key,2)->execute(); $id=Yii::$app->db->lastInsertID; } foreach ($id_lang as $id_language) { $pr_d->bindValue(":language_id", $id_language,1) ->bindValue(":key", $id,1) ->bindValue(":value", $msgs[0],2) ->bindValue(":type", $type,2) ->execute(); } } //     status=1 (   ) $query=Yii::$app->db->createCommand("SELECT SQL_NO_CACHE dk.`id`,CONCAT(d.`type`,':',dk.`key`) as 'key_' FROM `gr_dictionary` d,gr_dictionary_keys dk WHERE d.`key`=dk.id AND status=1")->query(); //$pr_del=Yii::$app->db->createCommand("DELETE FROM `gr_dictionary` WHERE `key`=:key"); while(($data=$query->read())!=false){ if(array_key_exists($data['key_'], $messages)===false){ //$pr_del->bindValue(":key", $data['id'],1)->execute(); $pr_delkey->bindValue(":id", $data['id'],1)->execute(); } } Yii::$app->db->createCommand("ALTER TABLE gr_dictionary AUTO_INCREMENT = 1;")->execute(); }catch (\Exception $e){ //   } } }
      
      









一番下の行は、saveMessagesToDbメソッドが1つだけ必要なことです。このメソッドは、common / config / i18n.php構成ファイルからgr_dictionaryテーブルを埋めます。



 'sourceMessageTable' => '{{%gr_dictionary}}'
      
      





Yii :: t()で以前呼び出したサイトからキーを収集しましたが、別のテーブルを使用することもできます。 キーの削除が追加され、このキーがサイトで使用されなくなった場合、外部キーリンクを介して転送されます。



これで、コントローラーへのコマンドでキーのコレクションを呼び出すことができます。



 php yii message2/extract @common/config/i18n.php
      
      





その結果、2つのテーブル(gr_dictionaryとgr_dictionary_keys)を設定する必要があります。 gr_languageテーブルから、言語ごとに翻訳用のエントリが作成されます。



コンポーネントi18nを追加する



次に、共通の\ config \ main.php設定ファイルをi18nコンポーネントに追加します。



common \ config \ main.php
  ... 'language'=> 'ru-RU', 'sourceLanguage' => 'en-US', 'components' => [ 'i18n' => [ 'translations' => [ '*' => [ 'class' => 'common\models\AltDbMessageSource', //   yii\i18n\DbMessageSource ], ], ], 'lng' => [ 'class' => '\common\components\LanguageExtension', ], ...
      
      







  1. Yii i18nコンポーネントは、Yii :: $ app-> t()が呼び出されると起動します。これを担当するクラスはyii \ i18n \ DbMessageSourceですが、common \ models \ AltDbMessageSourceを再定義します。



  2. lngコンポーネントは、Redisとの連携を担当するクラス\ common \ components \ LanguageExtensionです。


yii \ i18n \ DbMessageSourceをオーバーライドする



独自の方法で実装する翻訳を担当するクラス



yii \ i18n \ DbMessageSource
 namespace common\models; use Yii; class AltDbMessageSource extends \yii\i18n\MessageSource { public $sourceLanguage; public function init() { parent::init(); if ($this->sourceLanguage === null) { $this->sourceLanguage = Yii::$app->sourceLanguage; } } protected function translateMessage($category, $message, $language) { /*    (w:key)         lng    w  m    ,          . */ list($type,) = explode(":",$category); return Yii::$app->lng->$type($category); } public function translate($category, $message, $language) { if ( $language !== $this->sourceLanguage ) { return $this->translateMessage($category, $message, $language); } else { return false; } } }
      
      







translateMessageメソッドは、Yii :: t( 'category'、 'value')を呼び出すときに呼び出されます。 キーの種類をどのように整理するかが重要です。 セパレーターを使用して、Redisで階層のあるフォルダーを作成することで、わかりやすくできます。 例:そのようなキー

Yii::t('ru-RU:type:uniq_view','')



は、RedisAdminで次のようになります。



  • ru-RU:

    • タイプ:

      • uniq_view:値
      • uniq_view:値
      • uniq_view:値


Redisを使用してそのような選択を行うことができるもの:

 $redis->executeCommand("KEYS",["KEY" => $lang_key.":".$type.":*"]); $redis->executeCommand("KEYS",["KEY" => $lang_key.":*"]);
      
      





言語キーru-RUなどは、Redisをコンポーネント\ common \ components \ LanguageExtensionに入力するときに追加されます。



コンポーネント\ common \ components \ LanguageExtensionを書きましょう



コンポーネントは、Redisからのキー転送またはRedisが落ちた場合のアレイを受信するために必要です。



common \ components \ LanguageExtension
 namespace common\components\extensions; use Yii; use common\components\exceptions\LanguageException; use yii\db\Exception; use PDO; /** * Class LanguageExtension * @package common\components\extensions * : *   *   redis */ class LanguageExtension extends \yii\base\Object { private $language; //   -   ru private $w = []; //   private $m = []; //   private $storageConnection; //     private $storageStatus; //     private $numbDb; //  redis private $default_key; //    private $expire; public function __construct() { try{ $this->expire = Yii::$app->params['secretKeyExpire']??(60 * 60 * 60); $this->language = \Yii::$app->language; $language=LanguageExtension::currentLang(); if(!empty($language)){ if($this->idKeyLang($language)) { $this->language= $language; } } $this->numbDb=Yii::$app->params['redisLangDB']??11; $this->storageStatus = false; $this->default_key= $this->language.":index"; $this->storageConnection = new \yii\redis\Connection([ 'hostname' => Yii::$app->params['redisHost'], // 'password' => '', 'port' => 6379, 'database' => $this->numbDb, ]); if(empty($this->language)) throw new LanguageException("not default language",0); $this->init(); }catch ( LanguageException $event){ // echo $event->getMessage(); }catch ( \yii\db\Exception $event){ $this->init(); }catch (\Exception $event){ // echo $event->getMessage(); } } public function __destruct() { try{ if($this->storageConnection->isActive) $this->storageConnection->close(); }catch (\Exception $event){ } } /** *  . *  .      . *     . */ public function init(){ try{ $this->storageConnection->open(); //     redis if(!$this->isFullData()){ //   mysql    redis $this->loadRedis(); } $this->storageStatus = true; } catch ( \yii\db\Exception $event) { $this->storageStatus = false; //  . //     $w  $m     . $this->loadVariable(); } } public static function currentLang(){ try{ $language = isset($_COOKIE['userLang']) ? $_COOKIE['userLang'] : null; if(!$language && Yii::$app->session->has('userLang')) { $language = Yii::$app->session('userLang'); } if(empty($language))$language=\Yii::$app->language; return $language; } catch (\Exception $e){ print_r($e->getMessage());exit; } } private function idKeyLang(string $key){ if(!empty($key)){ return Yii::$app->db->createCommand("SELECT `id` FROM `gr_language` WHERE local=:local") ->bindValue(":local", $key,PDO::PARAM_STR) ->queryScalar(); } return false; } /** * @param string $type * @param string $key * @return string *   */ private function getKeyMD5(string $type,string $key):string { return $this->language.":".$type.":".md5($key); } /** * @return bool *     */ private function loadVariable():bool{ try{ //  . //     $w  $m     . $language_id=$this->idKeyLang($this->language); $res=\Yii::$app->db->createCommand("SELECT d.`type`,d.`value`,d.`translator`, dk.`key` FROM `gr_dictionary` d,gr_dictionary_keys dk WHERE d.`key`=dk.id AND d.language_id=:language_id") ->bindValue(":language_id", $language_id,PDO::PARAM_INT)->query(); $this->w=$this->m=[]; while(($data=$res->read())!=false){ if(method_exists($this, $data['type'])){ $this->{$data['type']}[$this->getKeyMD5($data['type'],$data['key'])]=$data['translator']; } } return true; }catch (\Exception $event){ echo $event->getLine()."|".$event->getMessage();exit; return false; } } /** * @return bool *    redis  mysql ( ) */ private function loadRedis():bool{ try{ $language_id=$this->idKeyLang($this->language); $res=\Yii::$app->db->createCommand("SELECT d.`type`,dk.`key`, d.`value`,d.`translator` FROM `gr_dictionary` d,gr_dictionary_keys dk WHERE d.`key`=dk.id AND d.language_id=:language_id") ->bindValue(":language_id", $language_id,PDO::PARAM_INT)->query(); $this->storageConnection->executeCommand('SETEX', [ "KEY" => $this->default_key,"SECONDS"=>$this->expire,"VALUE"=> "1"]); while(($data=$res->read())!=false){ $this->storageConnection->executeCommand('SETEX', ["KEY" => $this->getKeyMD5($data['type'],$data['key']),"SECONDS"=>$this->expire,"VALUE"=> $data['translator']]); } if(empty($this->storageConnection->executeCommand('LASTSAVE', [] ))) $this->storageConnection->executeCommand('BGSAVE', [] ); return true; }catch (\Exception $event){ echo $event->getMessage();exit; } } /** *  Redis */ public function flushdb(){ try{ if($this->storageConnection->isActive) $this->storageConnection->executeCommand('FLUSHDB'); else { $this->w=[]; $this->m=[]; } }catch (\Exception $event){ } } /** * @return bool *    redis         */ private function isFullData():bool { try{ $res= $this->storageConnection->executeCommand('INFO', [ ] ); preg_match("/.*db$this->numbDb:keys=([\d])*.*?/uis",$res,$arr); if(isset($arr[1]) && $arr[1]>1){ return $this->exists($this->default_key); } return false; }catch (\Exception $event){ echo $event->getMessage(); return false; } } /** * @param string $key * @return string *         */ public function w(string $key) : string { return $this->getKeyValue($key, 'w'); } /** * @param string $key * @return string *         */ public function m(string $key) : string { return $this->getKeyValue($key, 'm'); } /** * @param string $key * @param string $type * @return string *    *  .      -. */ private function getKeyValue ( string &$key, string $type ) : string { try{ if(!$key=trim($key)) throw new LanguageException("Error dictionary ".addslashes($key).". The ".addslashes($key)." can not be empty or contain only whitespace.", 777001); if($this->storageStatus) $value = $this->storageConnection->executeCommand("GET",["KEY" =>$this->getKeyMD5($type,$key)]); else{ $value = @$this->$type[$this->getKeyMD5($type,$key)]; } /*   if(!$value){ if ($this->hasEventHandlers(\yii\i18n\MessageSource::EVENT_MISSING_TRANSLATION)) { $event = new \yii\i18n\MissingTranslationEvent([ 'category' => $key, 'message' => $key, 'language' => $this->language, ]); $this->trigger(\yii\i18n\MessageSource::EVENT_MISSING_TRANSLATION, $event); } }*/ return $value ? $value : $key; }catch (\Exception $event){ return $key; } } /** * @param $key * @return bool *   */ public function del($key):bool{ try{ if($this->storageConnection->isActive){ return $this->storageConnection->executeCommand("DEL",["KEY" =>$key]);// keys test:1:v }else{ list($lang_key,$type,$key_)= explode(":", $key); if(method_exists($this, $type) && isset($this->$type[$key_])){ unset($this->$type[$key_]); return true; } return false; } }catch (\Exception $event){ return false; } } /** * @param string $lang_key * @param null $type * @return bool *         */ public function delAll(string $lang_key,$type=null){ try{ if($this->storageConnection->isActive){ $keys= $this->keys($lang_key,$type); if(!empty($keys)){ foreach ($keys as $key){ $this->del($key); } if($type==null) $this->del($lang_key.":index"); } }else{ $this->w=$this->m=[]; return true; } }catch (\Exception $event){ return false; } } /** * @param $type * @param $key * @return array *     */ public function keys(string $lang_key,$type=null):array{ try{ if($this->storageConnection->isActive){ if($type!=null) return $this->storageConnection->executeCommand("KEYS",["KEY" => $lang_key.":".$type.":*"]); else return $this->storageConnection->executeCommand("KEYS",["KEY" => $lang_key.":*"]); }else{ if($type!=null){ return $this->w+$this->m; }else{ if(method_exists($this, $type))return $this->$type; } return []; } }catch (\Exception $event){ return []; } } /** * @param $type * @param $key * @return bool *    */ public function exists($key):bool{ try{ if($this->storageConnection->isActive){ return $this->storageConnection->executeCommand("EXISTS",["KEY" =>$key]); }else{ // return (method_exists($this, $type) && isset($this->$type[$key])); list($lang_key,$type,$key_)= explode(":", $key); if(method_exists($this, $type))return isset($this->$type[$key_]); return false; } return false; }catch (\Exception $event){ return false; } } }
      
      







エッセンス



デフォルトのYii::$app->language



による言語辞書全体の保存Yii::$app->language



値(Cookieデータがない場合、RedisまたはRedisが機能しなかった場合は配列)、値型$this->w[] ,$this->m[]



。 しかし、これは私の実装であり、すべてを1つのバッファーに入れることができます。



彼はどのように働いていますか



初期化時に、Redis接続を確認します。 満たされていない場合は、バッファを満たし、満たされている場合はそれを埋め、両方の場合のソースはMySQLです。



, , ru-RU:index



.



, MySQL 4 . ru-RU , ? Redis MySQL ru-RU , en-US, Redis , .







 $redis->executeCommand('SETEX', ["KEY" => $this->getKeyMD5($data['type'],$data['key']),"SECONDS"=>$this->expire,"VALUE"=> $data['translator']]);
      
      







frontend\widgets\WLang
 namespace frontend\widgets\WLang; use frontend\models\Lang; use Yii; use PDO; class WLang extends \yii\bootstrap\Widget { public function init(){} public function run() { return $this->render('index', [ 'current' => \common\components\LanguageExtension::currentLang(), 'default' => \Yii::$app->db->createCommand("SELECT `id`, `code_lang`, `local`, `name`, `default_lang`, `status` FROM `gr_language` WHERE local=:local LIMIT 1")->bindValue(":local",\common\components\LanguageExtension::currentLang(),PDO::PARAM_STR)->queryOne(PDO::FETCH_OBJ), 'langs' =>\Yii::$app->db->createCommand("SELECT `id`, `code_lang`, `local`, `name`, `status` FROM `gr_language` WHERE 1")->queryAll(PDO::FETCH_OBJ), ]); } } <div> <?php use yii\helpers\Html; ?> <script> function click_(el) { var lang = $(el).attr('data-lang'); var date = new Date; date.setDate(date.getDate() + 1); document.cookie = "userLang=" + lang + "; path=/; expires=" + date.toUTCString() + ";"; location.reload(); } </script> <div id="lang"> <span id="current-lang"> <span class="show-more-lang" >  <?= $current;?></span> </span> <ul id="langs"> <?php foreach ($langs as $lang):?> <li class="item-lang"><a href="#" onclick="click_(this)" data-lang="<?=$lang->local?>"><?=$lang->code_lang?></a></li> <?php endforeach;?> </ul> </div> </div>
      
      







ウィジェットの目的は、使用可能なすべての言語を表示し、Cookieデータを設定することです。



さらに、アプリケーションのページでさらに翻訳が追加または削除された場合、キーのコレクションを呼び出してその値をMySQLに入力するだけです。



頑張って、ジェクシュメク



All Articles