إطار العمل Yii2: تعدد اللغات

جعل الموقع يدعم لغات متعددة مع إمكانية التبديل بينها

عدنان توتنيمنذ 4 سنوات

عند إنشائك لموقعٍ أو تطبيقٍ ما، فغالباً ستسعى لانتشاره على أوسع نطاق، وخاصّةً إن كان يقدّم خدماتٍ متنوعةً تنفعُ شرائحَ كبيرة في المجتمعات بأكملها.

ويستمرّ الطموح في نشر المحتوى حتى يصبحَ الموقع أو التطبيق متاحاً للجميع حولَ العالم، ويستطيع الزوّار أن يتصفّحوه دون صعوبةٍ في فهم قوائمه ونصوصه وما كُتب فيه من إرشاداتٍ وتوجيهاتٍ وطريقة استعمالٍ أو تواصل.

سنقوم في هذا المقال بجعل الموقع متعدّد اللغات كي يتسنّى لك إضافة ما تريد من لغاتٍ يستطيع الزائر أن يختار منها ما يشاء وفقاً لحاجته.

 

مفاهيم أولية:

الـ bootstrap:

يكاد هذا الاسم لا يخفى على أحدٍ ممّن يعملون في مجال تصميم وتطوير المواقع، فمن خلاله تستطيع أن تجعل من التصميم متوافقاً مع أحجام الشاشات، ويسهّل عليكَ كثيراً من الأمور التي لن تحتاج لكتابتها من جديد باستخدام CSS.

ولكن ليس هذا ما يعنينا، فكلمة bootstrap التي نتحدّث عنها الآن هي أمرٌ مختلفٌ كلياً، فباختصار هي تعني تنفيذ بعض الأكواد البرمجية المحدّدة مسبقاً عند بداية عمل الموقع أو عند إجراء بعض الـ requests من أجل تهيئة الإعدادات والملفات اللازمة لإتمام عملية التشغيل.

عند اختيار لغةٍ معيّنة من قائمة اللغات المتاحة سنقوم بتخزين اللغة المُختارة في الـ cookies (أو الـ session)، وسيتم إعادة توجيه المستخدم إلى الصفحة التي كان فيها عندما قام بتبديل اللغة، وبالتالي سيتم استدعاء الكود الذي سنقوم بكتابته كـ bootstrapper من أجل اعتماد اللغة التي اختارها المستخدم على أنّها لغة الموقع، وسبب استخدامنا للـ bootstrap هو أنّنا لا نريد -ولا يصح- في كلّ صفحةٍ سيزورها المستخدم أن يقوم بتبديل اللغة بشكلٍ يدوي لتوافق متطلّباته، ولا نريد أيضاً أن نضع كوداً برمجياً للتحقق من اللغة في كل action سيتم تنفيذها، لذلك سنضع الأوامر الخاصّة بنا في ملف bootstrapper كي تتم العملية بشكلٍ تلقائيٍ دون تدخّلٍ منّا ودون جهدٍ إضافي.

 

مفهوم تعدد اللغات في الموقع:

عندما نتحدّث عن تعدد اللغات فنحن نعني اللغة التي سيتم من خلالها عرض النّصوص الثابتة في القوائم والأزرار والفقرات التعريفية والإرشادية، أما النوع الآخر من تعدد اللغات فهو أن تجعل قاعدة البيانات الخاصّة بالموقع تخزّن في جداولها قيمةً لكلّ لغةٍ مستخدمةٍ في الموقع، وهذا أمرٌ آخر لن نتطرّق إليه (فأنتَ حينها بحاجةٍ لإضافة عمودٍ في الجدول لتضع فيه القيمة باللغة العربية مثلاً، وعموداً آخر لتضع القيمة باللغة الإنكليزية).

إذاً فنحن نتعامل مع عددٍ محددٍ من النصوص التي سنقوم بترجمتها إلى عدّة لغاتٍ لنعرضها في الموقع، وهنا سنتّبع طريقةَ المصفوفات ذات النّوع key/value.

لنفرض أنّه لدينا ثلاث لغاتٍ في الموقع، فما علينا إلا أن ننشئَ ثلاث ملفاتٍ بلاحقة php ونضع في كلٍّ منها مصفوفة، بحيث تكون الـ keys متطابقة في كلّ المصفوفات، أما الـ values فتختلف تبعاً للغة المستخدمة.

في هذه الحالة عندما تريد وضع عنوانٍ للزر فلن تضطر لاختبار فيما إذا كانت اللغة عربية حتى تكتب عبارة "تسجيل الدخول"، وفي حال كانت اللغة هي الإنكليزية فستكتب عبارة "Login"، فبدلاً من ذلك ستضع key موحّداً لكل اللغات (ولنفرض أنّه login_btn_label)، وتبعاً للغة المُختارة سيتم جلب الـ value المقابلة لهذا الـ key كي يتمّ عرضها.

 

 

الشروع في العمل:

دعونا الآن نقوم بإسقاط الكلام النظري السابق على تطبيقٍ عمليٍ لجعل الموقع الخاصّ بنا يدعم لغتَين مثلاً، هما العربية والإنكليزية.

الخطوة الأولى: تهيئة المجلدات والملفات:

أولاً سنقوم بإنشاء مجلّدٍ اسمه messages (وهو اسمٌ اصطلاحيٌ في العديد من أطُر العمل) وسنضع بداخله مجلّداً خاصّاً لكلِ لغةٍ نريدها، وداخل كلّ مجلدٍ سننشئ ملف php لنضع فيه المصفوفة ذات النوع key/value التي تحدّثنا عنها منذ قليل:

لاحظ أنّ اسم الملف في كل مجلد هو ذاته (أي app.php)، وهذا الاسم سنستخدمه لاحقاً لتحديد الملف الذي سيتم جلب القِيَم التي نريدها منه، فبالطبع تستطيع أن تنظّم عمل الترجمة في عدّة ملفات، منها مثلاً ملفات لرسائل الخطأ، ومنها ملفات لرسائل الإرشادات، ومنها ملفات لرسائل النصوص المستخدمة بكثرة، وما إلى ذلك.

سنقوم في كل ملف بإرجاع مصفوفة، وسنكتب بعض الـ keys والـ values بهدف التجربة والاختبار:

// messages/en/app.php file

<?php 

return [
    'hi' => 'Hi',
    'login' => 'Login',
    'login_information' => 'Please inter your email and password'
];
// messages/ar/app.php file

<?php 

return [
    'hi' => 'مرحبا',
    'login' => 'تسجيل الدخول',
    'login_information' => 'يرجى إدخال بريدك الإلكتروني وكلمة المرور'
];

 

الخطوة الثانية: إنشاء ملف الـ bootstrap:

في مجلد messages الذي أنشأناه في الخطوة السابقة، قم بإنشاء class وليكن اسمه مثلاً SelectLanguage.

هذا الـ class سيقوم بتضمين الـ interface التي اسمها BootstrapInterface من أجل استخدام التابع bootstrap الذي يحقق لنا مرادنا بتنفيذ تعليمات برمجية عند استدعاء الملف وتشغيل الموقع.

<?php 

namespace app\messages;

use yii\base\BootstrapInterface;

class SelectLanguage implements BootstrapInterface{

    public $supported_languages = [];

    public function bootstrap($app){
        $supported_languages = isset($app->request->cookies['language']) ? (string)$app->request->cookies['language'] : null;

        if(empty($supported_languages)){
            $supported_languages = $app->request->getPreferredLanguage($this->supported_languages);
        }

        $app->language = $supported_languages;
    }

}

في الكود السابق قمنا بتعريف مصفوفة فارغة اسمها supported_languages، ولكن سيتم ملؤها لاحقاً في ملف الإعدادات.

في التابع bootstrap بحثنا في الـ cookies عن وجود قيمة مقابلة للـ key الذي اسمه language، فإن كان موجوداً فسيتم استخدامه من أجل بقية الـ requests، أما في حال عدم وجوده فسيتم استخدام إحدى اللغات الموجودة في المصفوفة التي قمنا بتعريفها supported_languages وذلك بعد تحديد إحدى اللغات كما سنرى لاحقاً.

 

الخطوة الثالثة: وضع ملف الـ bootstrap ضمن الإعدادات:

الملف الذي قمنا بإنشائه لن يتم الاقتراب منه وتنفيذ محتواه ما لم نقم بإضافته إلى إعدادات الموقع، ففي ملف config/web.php سنضع هذا الملف ضمن العنصر bootstrap لنُعلِمَ التطبيق أنّه عند بداية عمل التطبيق نحن نريد تنفيذ التعليمات الموجودة في هذا الملف (أو ملفات أخرى إن أردنا ذلك).

وسنضع أيضاً قيماً للمصفوفة التي أنشأناها في الملف السابق supported_languages.

أخيراً في ملف الإعدادات سنضيف component جديد إلى مصفوفة الـ components وهو i18n، وهو اختصار للكلمة internationaization، وهي كلمة تعني الترجمة أو تعدد اللغات، وهذا الـ component يُعنى بالكثير من الأمور المتعلقة بتعدد اللغات، مثل صيغة التاريخ والرموز المتعلقة بالبلدان والعملات وغير ذلك.

// config/web.php

...

'components' => [
    'i18n' => [
        'translations' => [
            'app*' => [
                'class' => 'yii\i18n\PhpMessageSource',
                'sourceLanguage' => 'en',
                'forceTranslation' => 'true',        //ملاحظة 1 
                'fileMap' => [
                    'app' => 'app.php'               //ملاحظة 2
                ]
            ]
        ]
    ],
    ...
],
'bootstrap' => [
    [
        'class' => 'app\messages\SelectLanguage',
        'supported_languages' => ['ar', 'en']       //ملاحظة 3
    ]  
],

* السطر البرمجي عند العبارة "ملاحظة 1": الهدف منه إجبار التطبيق على ترجمة اللغة الأصلية، ففي السطر الذي يسبقه جعلنا اللغة الأصلية هي اللغة en، وبشكلٍ افتراضي فإنّ Yii2 لا تقوم بتحويل الـ keys الموجودة في ملفات الترجمة إلى الـ values المقابلة لها باعتبار أنّ اللغة الأصلية -غالباً- ستكون نصوصها هي الـ keys نفسها، أي أنّنا عندما نضع الـ key الذي اسمه login_information مثلاً سيتم طباعته كما هو في اللغة en لأنها اللغة الأصلية، أما عندما أضفنا السطر forceTranslation فهنا سيتم تحويل الـ key إلى الـ value المقابلة له.

 

* السطر البرمجي عند العبارة "ملاحظة 2": وضعنا في الخاصية fileMap أنّ اسم الملف الذي نريد التعامل معه ضمن مجلدات اللغات (ضمن مجلد messages) هو ملف app.php، وسيكون الـ key هو app؛ والهدف من ذلك هو التالي:

Yii::t('file_name_key', 'translation_key')

التابع t المُستدعى من الـ Yii هو التابع المسؤول عن الترجمة، فنقوم بإعطائه في الوسيط الأول اسم المفتاح الذي يمثّل الملف الذي نريد التعامل معه (وكما وضعنا في الكود السابق أنّ الـ key الذي اسمه app سيمثّل الملفات التي اسمها app.php).

أما الوسيط الثاني فهو المفتاح الذي يمثّل الكلمة التي نريد الحصول على ترجمتها وفقاً للغة المختارة.

 

* السطر البرمجي عند العبارة "ملاحظة 3": هنا وضعنا قيماً للمصفوفة الفارغة الموجودة في ملف SelectLanguage، والقِيَم هي نفسها أسماء المجلدات التي أنشأناها في مجلد messages.

 

الخطوة الرابعة: إنشاء action لتبديل اللغة:

سنستخدم الـ SiteController لوضع الـ action التي تبدّل اللغات، وستأخذ وسيطَين؛ الأول هو اسم اللغة التي نريدها، والثاني هو المسار الحالي، لأنّنا نريد أن يعود المستخدم لنفس الصفحة التي كان فيها عندما ضغط على زر تبديل اللغة.

هذان الوسيطان سيتم تمريرهما عند الضغط على الزر كما سيمرُّ معنا بعد قليل.

// controllers/SiteController.php file

public function actionChangeLanguage($lang, $current_url){
    
    \Yii::$app->language = $lang;

    $languageCookie = new \yii\web\Cookie([
        'name' => 'language',
        'value' => $lang,
    ]);
    Yii::$app->getResponse()->getCookies()->add($languageCookie);
        
    Yii::$app->session->set('language', $lang);
        
    return $this->redirect($current_url);
}

في الكود السابق وضعنا الخاصية language المُستدعاة من Yii::$app هي اللغة الممرّرة كوسيط، ثمّ أنشأنا cookie لوضع اللغة فيها وأضفناها إلى التطبيق، ووضعنا أيضاً session بنفس الآلية، وأخيراً أرجعنا المستخدم إلى الصفحة التي كان فيها (حيث أنّ الوسيط current_url سيمثّل لاحقاً خاصّية جاهزة في الـ Yii2 تُعيد المسار الحالي).

 

الخطوة الخامسة: اختبار تعدد اللغات:

سنقوم بوضع زرّين في صفحة login.php مثلاً، أحدهما لاختيار اللغة العربية، والآخر لاختيار اللغة الإنكليزية (يمكنك وضع زر تبديل اللغات أينما تريد، فمثلاً يمكنك وضع قائمة منسدلة في الشريط العلوي، أو عدد من الأزرار جانب الصفحة، أما هنا فنحن نقوم بالتجربة فقط لإيصال الفكرة).

...

// Button for Arabic language
<?= Html::a('عربي', ['site/change-language', 
     'lang' => 'ar', 'current_url' => Yii::$app->request->url], ['class' => 'btn btn-primary']) ?>

// Button for English language
<?= Html::a('English', ['site/change-language', 
     'lang' => 'en', 'current_url' => Yii::$app->request->url], ['class' => 'btn btn-warning']) ?>

كلا الزرَّين يستدعي الـ action المُنشأة سابقاً في SiteController، والوسيط lang هو ar في حالة الزر العربي، و en في حال الزر الإنكليزي.

أما الوسيط الثاني current_url فقيمته مُستدعاة من الحاصّية الجاهزة في الـ Yii2.

وسنضع في نفس الملف بعض العبارات التي تمكّننا من مشاهدة التغييرات التي سيتم إجراؤها:

<div class='col-md-8' style='direction:<?= Yii::$app->language == "ar" ? "rtl" : "ltr" ?>'>

<h1><?= Yii::t('app', 'hi') ?></h1>
<h3><?= Yii::t('app', 'login_information') ?></h3>

<?php $form = ActiveForm::begin(); ?>

<?= $form->field($user, 'email')->textInput() ?>

<?= $form->field($user, 'password')->passwordInput() ?>

<?= Html::submitButton(Yii::t('app', 'login'), ['class' => 'btn btn-success']) ?>

<?php ActiveForm::end(); ?>

</div>

قمنا بوضع div وجعلنا الخاصّية direction ضمن الـ style الخاص بها يكون تبعاً للغة الحالية (من خلال اختبار القيمة الموجودة في Yii::$app->language).

وبعدها قمنا بجلب القِيَم التي نريد عرض ترجمتها من خلال التابع Yii::t

عند الضغط على زر "English" (أو عند زيارة الصفحة للمرّة الأولى):

عند الضغط على زر "عربي":

تعرّفنا في هذا المقال على كيفية جعل الموقع يدعم عدّة لغات، والآن عندما تريد إضافة لغةٍ جديدةٍ فما عليكَ إلا أن تنشئ مجلداً باسم اللغة، وتنشئ ملفاً فيه مصفوفة الـ key/value، وإضافة اسم هذه اللغة إلى مصفوفة supported_languages.

إنّ عملية الترجمة ستسير معك حتى نهاية الموقع، فكلّما احتجتَ لاستخدام عبارةٍ جديدة ستقوم بإضافة الـ key ذاته إلى مصفوفات الـ key/value في مجلد messages، وستقوم بإضافة الترجمة الموافقة لكل لغة.

0
إعجاب
1054
مشاهدات
0
مشاركة
1
متابع

التعليقات (0)

لايوجد لديك حساب في عالم البرمجة؟

تحب تنضم لعالم البرمجة؟ وتنشئ عالمك الخاص، تنشر المقالات، الدورات، تشارك المبرمجين وتساعد الآخرين، اشترك الآن بخطوات يسيرة !