Yii2と多言語主義の組織

待望のYii 2.0 Betaのリリースは、Yiiを使用する多くの開発者に、フレームワークの2番目のバージョンに切り替えるインセンティブを与えました。 フレームワークの開発者は、下位互換性に触れないようにし、主にバグの修正とドキュメントの完成に集中することを示しました。 これは、実際のプロジェクトでのYii2の使用により大きな推進力を与えます。



私たちは革新に追いつくことに決め、素晴らしいYiiフレームワークの2番目のバージョンを選択しました。 プロジェクトの開発時に、サイトで多言語を整理する必要が生じました。



問題の声明



1.言語の数に制限はありません。

2. WebサイトのURLは、CNCおよびSEO最適化として表示されます。 フォームのリンク:

example.com/en/mypage

example.com/en/mypage

example.com/de/mypage

3.フレームワークを使用する際の最小限の変更。 example.com/mypageのリソースは、デフォルトの言語で指定する必要があります。 ルーティングルールは、言語の数に応じて変更しないでください。



言語ストレージ



言語の数は無制限であり、デフォルトの言語を指定する必要があるという事実に基づいて、このリストを別のデータベーステーブルに格納することが決定されました。 次のフィールドを使用してlangテーブルを作成します。

id-言語識別子

url-URLに表示する言語のアルファベット識別子(ru、en、de、...)

local-ユーザー言語(ロケール)

名前-名前(英語、ロシア語、...)

default-デフォルト言語を示すフラグ(1-デフォルト言語)

date_update-更新日(unixtimestamp内)

date_create-作成日(unixtimestamp内)



CREATE TABLE IF NOT EXISTS `lang` ( `id` int(11) NOT NULL AUTO_INCREMENT, `url` varchar(255) NOT NULL, `local` varchar(255) NOT NULL, `name` varchar(255) NOT NULL, `default` smallint(6) NOT NULL DEFAULT '0', `date_update` int(11) NOT NULL, `date_create` int(11) NOT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;
      
      







そして、2つの言語をテーブルに追加します。1つはdefault = 1の値からでなければならないことを考慮して



 INSERT INTO `lang` (`url`, `local`, `name`, `default`, `date_update`, `date_create`) VALUES ('en', 'en-EN', 'English', 0, UNIX_TIMESTAMP(), UNIX_TIMESTAMP()), ('ru', 'ru-RU', '', 1, UNIX_TIMESTAMP(), UNIX_TIMESTAMP());
      
      







または、php yii migrate / create langコマンドを実行して移行を作成します。 作成されたファイルに、次を挿入します。



 public function safeUp() { $tableOptions = null; if ($this->db->driverName === 'mysql') { $tableOptions = 'CHARACTER SET utf8 COLLATE utf8_general_ci ENGINE=InnoDB'; } $this->createTable('{{%lang}}', [ 'id' => Schema::TYPE_PK, 'url' => Schema::TYPE_STRING . '(255) NOT NULL', 'local' => Schema::TYPE_STRING . '(255) NOT NULL', 'name' => Schema::TYPE_STRING . '(255) NOT NULL', 'default' => Schema::TYPE_SMALLINT . ' NOT NULL DEFAULT 0', 'date_update' => Schema::TYPE_INTEGER . ' NOT NULL', 'date_create' => Schema::TYPE_INTEGER . ' NOT NULL', ], $tableOptions); $this->batchInsert('lang', ['url', 'local', 'name', 'default', 'date_update', 'date_create'], [ ['en', 'en-EN', 'English', 0, time(), time()], ['ru', 'ru-RU', '', 1, time(), time()], ]); } public function safeDown() { $this->dropTable('{{%lang}}'); }
      
      







php yii migrateコマンドで移行を適用します。



言語モデル



giiを使用して、Langモデルを作成し、CRUDを生成します。

モデルに動作を追加して、langテーブルのエントリを編集および作成するときに日付を自動的に更新します。



 public function behaviors() { return [ 'timestamp' => [ 'class' => 'yii\behaviors\TimestampBehavior', 'attributes' => [ \yii\db\ActiveRecord::EVENT_BEFORE_INSERT => ['date_create', 'date_update'], \yii\db\ActiveRecord::EVENT_BEFORE_UPDATE => ['date_update'], ], ], ]; }
      
      







Langモデルの言語オブジェクトを操作するための補助メソッドも追加します。



 //,      static $current = null; //    static function getCurrent() { if( self::$current === null ){ self::$current = self::getDefaultLang(); } return self::$current; } //       static function setCurrent($url = null) { $language = self::getLangByUrl($url); self::$current = ($language === null) ? self::getDefaultLang() : $language; Yii::$app->language = self::$current->local; } //     static function getDefaultLang() { return Lang::find()->where('`default` = :default', [':default' => 1])->one(); } //      static function getLangByUrl($url = null) { if ($url === null) { return null; } else { $language = Lang::find()->where('url = :url', [':url' => $url])->one(); if ( $language === null ) { return null; }else{ return $language; } } }
      
      







URL生成



URL Manager(urlManager)は、URLを作成するためのアプリケーションの組み込みコンポーネントです。 このコンポーネントにより、アプリケーション内のすべてのURLが作成されます。 言語のアルファベット識別子のプレフィックスをURLに追加するには、 UrlManagerクラスのcreateUrlメソッドを再定義し、アプリケーション構成で使用するURLマネージャーを指定するだけです。



config / main.php構成ファイルのコンポーネントブロックに、次を追加します。



 'urlManager' => [ 'enablePrettyUrl' => true, 'showScriptName' => false, 'class'=>'frontend\components\LangUrlManager', 'rules'=>[ '/' => 'site/index', '<controller:\w+>/<action:\w+>/*'=>'<controller>/<action>', ] ],
      
      







components / LangUrlManager.phpファイルを作成し、createUrlをオーバーライドします。



 <?php namespace frontend\components; use yii\web\UrlManager; use frontend\models\Lang; class LangUrlManager extends UrlManager { public function createUrl($params) { if( isset($params['lang_id']) ){ //   ,       , //      $lang = Lang::findOne($params['lang_id']); if( $lang === null ){ $lang = Lang::getDefaultLang(); } unset($params['lang_id']); } else { //    ,      $lang = Lang::getCurrent(); } $url = parent::createUrl($params); return $url == '/' ? '/'.$lang->url : '/'.$lang->url.$url; } }
      
      







言語定義



言語識別子情報はURLにのみ保存されます。 したがって、現在の言語は、URLを解析することによってのみ決定できます。 これを行うには、 RequestクラスのresolvePathInfoメソッドを再定義し、アプリケーション構成ファイルで使用する要求コンポーネントを指定します。 ResolvePathInfoメソッド-URLの一部($ pathInfo)を「?」に返します そしてログインスクリプトの後。



言語のアルファベット識別子を考慮してUrlManagerのルールを書き換えないようにするために、それ(アルファベット識別子)を$ pathInfoから削除し、Lang :: setCurrentを介して現在の言語を設定し、$ pathInfoを返しますが、言語プレフィックスはありません。



components / LangRequest.phpファイルを作成し、resolvePathInfoをオーバーライドします。



 <?php namespace frontend\components; use Yii; use yii\web\Request; use frontend\models\Lang; class LangRequest extends Request { private $_lang_url; public function getLangUrl() { if ($this->_lang_url === null) { $this->_lang_url = $this->getUrl(); $url_list = explode('/', $this->_lang_url); $lang_url = isset($url_list[1]) ? $url_list[1] : null; Lang::setCurrent($lang_url); if( $lang_url !== null && $lang_url === Lang::getCurrent()->url && strpos($this->_lang_url, Lang::getCurrent()->url) === 1 ) { $this->_lang_url = substr($this->_lang_url, strlen(Lang::getCurrent()->url)+1); } } return $this->_lang_url; } protected function resolvePathInfo() { $pathInfo = $this->getLangUrl(); if (($pos = strpos($pathInfo, '?')) !== false) { $pathInfo = substr($pathInfo, 0, $pos); } $pathInfo = urldecode($pathInfo); // try to encode in UTF8 if not so // http://w3.org/International/questions/qa-forms-utf-8.html if (!preg_match('%^(?: [\x09\x0A\x0D\x20-\x7E] # ASCII | [\xC2-\xDF][\x80-\xBF] # non-overlong 2-byte | \xE0[\xA0-\xBF][\x80-\xBF] # excluding overlongs | [\xE1-\xEC\xEE\xEF][\x80-\xBF]{2} # straight 3-byte | \xED[\x80-\x9F][\x80-\xBF] # excluding surrogates | \xF0[\x90-\xBF][\x80-\xBF]{2} # planes 1-3 | [\xF1-\xF3][\x80-\xBF]{3} # planes 4-15 | \xF4[\x80-\x8F][\x80-\xBF]{2} # plane 16 )*$%xs', $pathInfo) ) { $pathInfo = utf8_encode($pathInfo); } $scriptUrl = $this->getScriptUrl(); $baseUrl = $this->getBaseUrl(); if (strpos($pathInfo, $scriptUrl) === 0) { $pathInfo = substr($pathInfo, strlen($scriptUrl)); } elseif ($baseUrl === '' || strpos($pathInfo, $baseUrl) === 0) { $pathInfo = substr($pathInfo, strlen($baseUrl)); } elseif (isset($_SERVER['PHP_SELF']) && strpos($_SERVER['PHP_SELF'], $scriptUrl) === 0) { $pathInfo = substr($_SERVER['PHP_SELF'], strlen($scriptUrl)); } else { throw new InvalidConfigException('Unable to determine the path info of the current request.'); } if (isset($pathInfo[0]) && $pathInfo[0] === '/') { $pathInfo = substr($pathInfo, 1); } return (string) $pathInfo; } }
      
      







config / main.php構成ファイルのコンポーネントブロックに、次を追加します。



 'request' => [ 'class' => 'frontend\components\LangRequest' ],
      
      







アプリケーションの国際化



アプリケーションの翻訳には2つの言語が関係しています。

アプリケーション言語($言語) -アプリケーションで作業するユーザーの言語。

アプリケーションのソース言語($ sourceLanguage) -アプリケーションのソースコードで使用される言語。 デフォルトでは、$ sourceLanguage = 'en'。



メッセージはYii :: tメソッド($カテゴリ、$メッセージ、$ params = []、$言語= null)を使用して翻訳されます



構成ファイルにデフォルト値$ sourceLanguage = 'en'および$ language = 'ru-RU'を設定します。 $ languageの値は、LangRequest :: resolvePathInfoで$ pathInfoを定義するとき、つまりすべてのHTTP要求で、リセットされます(Lang :: setCurrentメソッド、行Yii :: $ app-> language = self :: $ current-> local;)。



メッセージの翻訳をメッセージディレクトリに保存します。 各言語には独自のディレクトリ(message / ruおよびmessage / en)があり、カテゴリごとに翻訳が保存されます。



config / main.php構成ファイルのコンポーネントブロックに、次を追加します。



 'language'=>'ru-RU', 'i18n' => [ 'translations' => [ '*' => [ 'class' => 'yii\i18n\PhpMessageSource', 'basePath' => '@frontend/messages', 'sourceLanguage' => 'en', 'fileMap' => [ //'main' => 'main.php', ], ], ], ],
      
      







詳細はこちらをご覧ください



言語切り替えウィジェット



フロントエンド/ウィジェット/ Lang.phpを作成します。



 <?php namespace frontend\widgets; use frontend\models\Lang; class WLang extends \yii\bootstrap\Widget { public function init(){} public function run() { return $this->render('lang/view', [ 'current' => Lang::getCurrent(), 'langs' => Lang::find()->where('id != :current_id', [':current_id' => Lang::getCurrent()->id])->all(), ]); } }
      
      







そして、フロントエンド/ウィジェット/ビュー/lang/view.phpを表示します:



 <?php use yii\helpers\Html; ?> <div id="lang"> <span id="current-lang"> <?= $current->name;?> <span class="show-more-lang"></span> </span> <ul id="langs"> <?php foreach ($langs as $lang):?> <li class="item-lang"> <?= Html::a($lang->name, '/'.$lang->url.Yii::$app->getRequest()->getLangUrl()) ?> </li> <?php endforeach;?> </ul> </div>
      
      







ウィジェット出力:



 <?php use frontend\widgets\WLang; ?> ... <?= WLang::widget();?>
      
      






All Articles