Tag Archive แปลภาษา

YII2 GRUD GRID FROM หลายภาษา

จากเรื่องที่แล้ว ทำตาราง yii 2 ให้เก็บหลายภาษา โดยเราสามารถอ้างถึง attribute ตามรูปแบบ {attribute name}_{language} เช่น ในตาราง _lang ฟิลย์ชื่อ name ก็ใช้ $model->name_en, $model->name_jp, $model->name_th ในวิวถ้าต้องการแสดงผล

ในบทความที่ยังขาดตัวอย่างในการแสดงข้อมูล การใช้ในกริดที่แสดงรายการทั้งหมด, ฟอร์มที่จะกรอกข้อมูล และวิวที่จะแสดงสิ่งที่เราเก็บเอาไว้ออกมา ตัวอย่าง code ที่ผมใช้

GridView ต้องการให้แสดงภาษาอังกฤษเป็นหลัก อีกช่องที่เหลือแสดงสลับกันระหว่างภาษาไทย และญี่ปุ่น ทำได้โดยแทนที่จะอ้าง name_th หรือ name_jp ตรงๆ ก็อ้างผ่านตัวแปรไปแทน

...

if(Yii::$app->language == 'jp')
{
	$name = 'name_jp';
}
else
{
	$name = 'name_th';
}
...
echo GridView::widget([
'dataProvider' => $dataProvider,
'filterModel' => $searchModel,
'columns' => [
	['class' => 'yii\grid\SerialColumn'],
...
	'name_en',
	$name,
...
	'post_id',
	'status',
],
]);
...

form ก็สามารถใช้เหมือนรูบแบบปกติได้เลย โดยเราสามารถกรอกข้อมูล แก้ไขตัวแปลภาษาทั้งหมดได้พร้อมกันในครั้งเดียว เช่น

...
<?= $form->field($model, 'name_en')->textInput() ?>
<?= $form->field($model, 'name_jp')->textInput() ?>
<?= $form->field($model, 'name_th')->textInput() ?>
...

วิวก็ตามรูปแบบเหมือนตัวอื่นๆตามปกติ

...
<?= DetailView::widget([
        'model' => $model,
        'attributes' => [
            'post_id',
            'status',
...
            'name_en',
            'name_jp',
            'name_th',
...
            'date_publish',
            'date_expire',
            'log_created',
            'log_created_by',
            'log_updated',
            'log_updated_by',
        ],
    ]) ?>
...

ทำตาราง yii 2 ให้เก็บหลายภาษา

ต่อจาก ทำ yii 2 ให้รับหลายภาษา หลังจากใส่คำแปรให้ text ต่างๆ แล้วเราจะแยกเก็บ database ภาษาต่างๆ ออกจากกัน คนไทยก็อยากจะอ่านภาษาไทย คนจีนก็อ่านเป็นแต่ภาษาตัวเอง

  1. ติดตั้ง OmgDef/yii2-multilingual-behavior โดยแก้ composer.json ใส่
        "require": {
     ...
            "omgdef/yii2-multilingual-behavior": "~2.0"
     ...
        },
    

    run composer update

  2. สร้างตาราง โดยแยกตารางหลักที่เก็บ id และฟิลย์ที่ใช้ร่วมกัน อีกตารางเก็บ field ที่แยกตามภาษาต่างๆเช่น content, title
    CREATE TABLE IF NOT EXISTS `post` (
        `id` int(11) NOT NULL AUTO_INCREMENT,
        `enabled` tinyint(1) NOT NULL DEFAULT '1',
        `log_created` datetime NOT NULL,
        `log_updated` datetime NOT NULL,
        PRIMARY KEY (`id`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
    
    CREATE TABLE IF NOT EXISTS `postLang` (
        `id` int(11) NOT NULL AUTO_INCREMENT,
        `post_id` int(11) NOT NULL,
        `language` varchar(6) NOT NULL,
        `title` varchar(255) NOT NULL,
        `content` TEXT NOT NULL,
        PRIMARY KEY (`id`),
        KEY `post_id` (`post_id`),
        KEY `language` (`language`)
    ) ENGINE=InnoDB  DEFAULT CHARSET=utf8;
    
    ALTER TABLE `postLang`
    ADD CONSTRAINT `postlang_ibfk_1` FOREIGN KEY (`post_id`) REFERENCES `post` (`id`) ON DELETE CASCADE ON UPDATE CASCADE;
    

    อย่าลืมใส่ id และ language มันจำเป็นต้องใช้ เก็บว่า record นี้เป็นภาษาอะไร

  3. สร้าง model โดยใช้ gii ตามปกติทั้ง 2 ตาราง
  4. เปิด model ของตารางหลัก ตัวอย่างคือ ..\model\Post.php ใส่ code
    ...
    use omgdef\multilingual\MultilingualBehavior;
    use omgdef\multilingual\MultilingualQuery;
    ...
    	public static function find()
    	{
    		$q = new MultilingualQuery(get_called_class());
    		$q->multilingual();
    		return $q;
    	}
    
    	public function behaviors()
    	{
    		return [
    			'ml' => [
    				'class' => MultilingualBehavior::className(),
    				'languages' => [
    					'en',
    					'jp',
    					'th',
    				],
    				'defaultLanguage' => 'en',
    				'langForeignKey' => 'post_id',
    				'tableName' => "{{%postlang}}",
    				'attributes' => [
    					'content',
    					'title',
    				]
    			]
    		];
    	}
    ...
    
    • languages ภาษาทั้งหมดที่ใช้ได้
    • defaultLanguage ภาษาเริ่มต้น
    • langForeignKey ใส่ฟิลย์ที่ เชื่อมทั้ง 2 ตารางไว้ด้วยกัน (primary key)
    • tableName ชื่อตารางที่เก็บส่วนแปลภาษาไว้
    • attributes ฟิลย์ทั้งหมด ที่ต้องการทำระบบแปลภาษา
  5. เปิด ไฟล์ _form.php ที่เราใช้กับโมเดลนี้ขึ้นมา ใส่
    ...
        <?= $form->field($model, 'title_jp')->textInput(['maxlength' => 255]) ?>
        <?= $form->field($model, 'title_en')->textInput(['maxlength' => 255]) ?>
        <?= $form->field($model, 'title_th')->textInput(['maxlength' => 255]) ?>
    ...
    
  6. ทดลอง save ดู ตารางใน database จะเก็บข้อมูลไว้

  7. แก้จุดอื่นๆ อย่าง view index.php ตามรูปแบบ ฟิลย์_ตัวย่อภาษา

YII 2 Widget เปลี่ยนภาษา

หลังจากทำให้ yii รองรับหลายภาษาในเรื่อง ทำ yii 2 ให้รับหลายภาษา เรามาทำตัวเปลี่ยนภาษากันต่อ โดยเขียนเป็น Widget เพื่อที่สามารถนำไปใช้ได้สดวก

เป้าหมายคือ

  1. สามารถเปลี่ยนภาษาได้โดยใช้ตัวแปร get language=EN หรือภาษาอะไรก็ได้ จะเรียกใช้จาก link ธรรมดาก็ได้ หรือเลือกผ่าน widget ก็ได้
  2. จดจำได้ว่า user เคยเลือกภาษาอะไรไว้

สร้างไฟล์ common\components\languageSwitcher.php เนื่้อหาคือ

<?php
/*
author :: Pitt Phunsanit
website :: https://pitt.plusmagi.com
change language by get language=EN, language=TH,...
or select on this widget
 */

namespace common\components;

use Yii;
use yii\base\Widget;
use yii\bootstrap\ButtonDropdown;
use yii\helpers\Url;
use yii\web\Cookie;

class languageSwitcher extends Widget
{
    /* ใส่ภาษาของคุณที่นี่ */
    public $languages = [
        'en' => 'English (United States)',
        'jp' => 'Japanese (Japan)',
        'th' => 'Thai (Thailand)',
    ];

    public function init()
    {
        if(php_sapi_name() === 'cli')
		{
            return true;
        }

        parent::init();
        $languageNew = Yii::$app->request->get('language');
        $cookies     = Yii::$app->request->cookies;
        if($languageNew) {
            if(isset($this->languages[$languageNew])) {
                Yii::$app->language = $languageNew;
                Yii::$app->response->cookies->add(new \yii\web\Cookie([
                    'name'  => 'language',
                    'value' => $languageNew,
                ]));
            }
        }
        elseif($cookies->has('language'))
        {
            Yii::$app->language = $cookies->getValue('language');
        }

    }

    public function run()
    {
        $languages = $this->languages;
        $current   = $languages[Yii::$app->language];
        unset($languages[Yii::$app->language]);

        $items = [];
        foreach($languages as $code => $language)
        {
            $temp          = [];
            $temp['label'] = $language;
            $temp['url']   = Url::current(['language' => $code]);
            array_push($items, $temp);
        }

        echo ButtonDropdown::widget([
            'label'    => $current,
            'dropdown' => [
                'items' => $items,
            ],
        ]);
    }

คำสั่ง php_sapi_name() มีไว้เพื่่อตรวจสอบไม่ให้ทำงานถ้าโดนเรียกใช้ใน console เพราะว่า class cookie ของ console จะใช้ต่างจากปกติ

ไปเปิดไฟล์ common\config\main.php เพิ่ม code

...
	'bootstrap' => [
...
		'languageSwitcher',
...
	],
...
...
	'components' => [
...
		'languageSwitcher' => [
			'class' => 'common\components\languageSwitcher',
		],
...
	],
...

เปิดไฟล์ frontend\views\layouts\main.php เพิ่ม

...
use common\components\languageSwitcher;
...
<?= languageSwitcher::Widget() ?>
...

ทดสอบโดยเปลี่ยนเป็นภาษาอื่นดู บริเวณที่เราใส่ code แปลภาษาไว้จะเปลี่ยนตามภาษาที่เลือกรึเปล่า

ทำ yii 2 ให้รับหลายภาษา

ทำโปรเจค yii แบบหลายภาษา ไทย อังกฤษ ญี่ปุ่น หรือประเทศอื่น

  1. สร้าง folder common\messages ในโพลเดอร์โปรเจค
  2. สร้างไฟล์ common\config\i18n.php ตามตัวอย่าง
    <?php
    return [
    	'languages' => [
    		'US',
    		'JP',
    		'TH',
    	], /* Add languages to the array for the language files to be generated. */
    
    	'except' => [
    		'.git',
    		'.gitignore',
    		'.gitkeep',
    		'.hgignore',
    		'.hgkeep',
    		'.svn',
    		'/messages',
    		'/vendor',
    	],/*  exclude file */
    	'format' => 'php',
    	'messagePath' => __DIR__ . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . 'messages',
    	'only' => ['*.php'],
    	'overwrite' => true,
    	'removeUnused' => false,
    	'sort' => true,
    	'sourcePath' => __DIR__. '..' . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR,
    	'translator' => 'Yii::t'
    ];
    
  3. เปิดไฟล์ common\config\main.php เพิ่ม language(ภาษา default), sourceLanguage ภาษาที่ใช้เป็นหลัก ใช้ en-US เป็นหลัก เพราะเวลาให้ชาติอื่นแปลจะง่ายกว่าแปลจากภาษาไทย สองตัวนี้ต้องต่างกันนะครับ ไม่งั้นมันจะไม่แปลให้ และเพิ่ม 18n ใน components
    <?php
    return [
      ...
        'components' => [
            'cache' => [
                'class' => 'yii\caching\FileCache',
            ],
    		'i18n' => [
    			'translations' => [
    				'common*' => [
    					'class' => 'yii\i18n\PhpMessageSource',
    					'basePath' => '@common/messages',
    				],
    			],
                'on missingTranslation' => ['app\components\TranslationEventHandler', 'handleMissingTranslation'],
    		],
        ],
      ...
    	'language' => 'TH', /* must difren sourceLanguage */
    	'sourceLanguage' => 'US',
      ...
    ];
    
  4. เปิด view ที่จะแปลขึ้นมา เช่น D:\xampp\htdocs\YiiAdvanced\frontend\views\site\index.php เพิ่ม
    <?php echo Yii::t('common', 'Congratulations!'); ?>
    
  5. เปิด command cd ไปที่เราเก็บ project เช่น
    cd D:\xampp\htdocs\YiiAdvanced
    yii message/extract @common/config/i18n.php
    
  6. เปิดไฟล์ใน common/messages ที่สร้าง folder ตามเงื่อนไขในไฟล์ i18n.php และ คอนฟิกใน i18n ใส่คำแปลไป เช่น
    		'Congratulations!' => 'สำเร็จแล้ว';
    
  7. ชื่อไฟล์ คือ index ของ translations ถ้าเราต้องการแยกตัวแปลภาษา frontend กับ backend ออกจากกันก็แก้ i18n เป็น
    'components' => [
    	...
    		'i18n' => [
    			'translations' => [
    				'frontend*' => [
    					'class' => 'yii\i18n\PhpMessageSource',
    					'basePath' => '@common/messages',
    				],
    				'backend*' => [
    					'class' => 'yii\i18n\PhpMessageSource',
    					'basePath' => '@common/messages',
    				],
    			],
    		],
    		...
    		],
    

    เวลาใช้ก็

     <?php echo Yii::t('frontend', 'Translatable String'); ?>
     <?php echo Yii::t('backend', 'Translatable String'); ?>
  8. ถ้าต้องการเพิ่มตัวแปลใหม่ก็ทำขั้นตอนที่ 5 และ 6 ใหม่อีกครั้ง
  9. มีภาค 2 การเปลี่ยนภาษา YII 2 Widget เปลี่ยนภาษา
  10. มีภาค 3 เกี่ยวกับการเก็บข้อมูลลงฐานข้อมูล ทำตาราง yii 2 ให้เก็บหลายภาษา