مقدمة :
ان عملية بناء أي موقع ونشره على الانترنت تواجه العديد من المشاكل ولعل أهمها حاجز اللغة وأعني به هنا لغة التطبيق التي يتعامل معها المستخدم غالبا (لغة عربية/انجليزية)...فمما يعيبنا نحن العرب ان أغلب تطبيقاتنا تكون احادية اللغة(عربية فقط) مما يقلص من عدد مستخدمي هذه البرامج والمواقع ,اضافة الى ذلك فانه من المؤكد عند بناء تطبيق ثنائي اللغة فهذا يضيف الى المشروع ميزة رائعة تفضله على غيره ولست أعني هنا لغة واجهة التطبيق فحسب بل كافة اعدادت اللغة من حيث التاريخ (هجري/ميلادي) والارقام المستخدمة في النظام...لذا فانني في هذه المقالة سأناقش اكثر طرق بناء التطبيقات متعددة اللغات شيوعاً عسى الله أن ينفعنا بها واياكم فان احسنت فمن الله وان أسأت فمن نفسي .
الحلول المتوفرة :
أول الحلول المتوفرة لهذه المعضلة هي بناء تطبيقين منفصلين يختلفان من ناحية الـCulture/UICulture من خلال الملف Web.config او نسخ الصفحات الموجودة و ووضعها في مسار اخر وتغيير اعدادت اللغة لها Culture/UICulture ...ولعل هذا الحل هو الاكثر شيوعاً بيننا أو كما يظن البعض هو الأسهل ... وهو حل مناسب لغالب التطبيقات ...ولكن تخيل لو أنك تريد اضافة احد الامتيازات او السطور البرمجية الى برنامجك , أو اذا ما ظهر خطأ في البرنامج ؟؟!!!!
ستقوم طبعا بفتح التطبيقين وتكرار كتابة نفس السطور البرمجية مرتين على كلا التطبيقين واختبار كل منهم على حدة....هذا ان كنت تريد بناء تطبيق يدعم لغتين فقط ..!
حسنا ماذا يكون الحال اذا طلب منك اضافة لغة أخرى الى التطبيق (الفرنسية مثلاً) والتي قد تكون لا تجيدها مثلي :) ...ستقوم باحضار الشخص الذي يجيد هذه اللغة ليشاركك بناء التطبيق الثالث صفحة بصفحة !!!! وكذلك ستضيف الكثير من الاعباء عليك في صيانة وتعديل ثلاث نسخ من تطبيقك وانت ترفع يديك عاليا ان لا يطلب منك اضافة لغة أخرى الى التطبيق ..
اذا فما الحل ....
بناء التطبيق متعدد اللغة بسهولة :
لنقوم بذلك علينا ان نستوعب ان الفكرة تكمن في حفظ النصوص المراد تغييرها في التطبيق والقيم التي تأخذها هذه اللغة على شكل مفتاح وقيمة key/value
في ملف Resx . بالشكل التالي : <fileName>.<culture>.resx
اي استخدام اكثر من ملف لكل لغة ...اي ان التطبيق سيحوي على سبيل المثال:
controls.ar-SA.resx و controls.en-US.resx .
لنترك التنظير وننتقل الى الجزء العملي :
اذا كنت تستخدم Visual Studio 2003 عندئذ قم بفتح التطبيق و من ثم بالزر اليمين Add--->Add New Item -->Assembly Resource Fileِ قم بانشاء ملف جديد بالاسم control.en-US.resx ..افتح الملف وقم بتسجيل اسم الاداة التي تريد تعريب نصها في الخانة name والنص الذي تريد أن يظهر بها في الخاصية value واترك باقي الخانات كما هي ...أما اذا كنت تستخدم Visual Studio 2005 فهناك ميزة جميلة يقدمه VS.net2005 نيابة عنك وهي باختيار "Generate Local Resource" من القائمة Tools .
...بعد الانتهاء من تسجيل أسماء كل الادوات في مشروعك داخل الملف قم بنسخ هذا الملف وتغييره الى control.ar-SA.resx ليكون لدينا في المشروع ملفين هما control.en-US.resx و control.ar-SA.resx .
لننتقل الى صفحات المشروع ...افتح ملف الaspx وقم بوضع اداة DropDownList قم بتسميتها ddlSelectLang وقم باعداد الخاصية AutoPostBack الى القيمة True ثم قم باضافة عناصر اللغات التي تريد استخدمها في مشروعك لتصبح الاداة داخل ملف الaspx بالشكل :
<asp:DropDownList id="ddlSelectLang" runat="server" AutoPostBack="True"> <asp:ListItem Value="ar-SA">العربية</asp:ListItem> <asp:ListItem Value="en-US">English</asp:ListItem> </asp:DropDownList>
قم بالرجوع الى ملف الcode behind ذو الامتداد .CS الخاص بالصفحة نفسها ...ومن ثم قم باضافة:
using System.Globalization; using System.Resources; using System.Reflection; using System.Threading;
قم بانشاء الدالة getFromResource والتي تقرأ القيم من ملف الresx اذا كنت تستخدم ASP.Net 1.1 :
public string getFromResource(string key)
{
ResourceManager rmloc = new ResourceManager("WF.controls",Assembly.GetExecutingAssembly());
return rmloc.GetString(key);
}أما اذا كنت تستخدم ASP.Net 2.0:
public string getFromResource(string key)
{
ResourceManager rmloc = new ResourceManager("Resources."+PageName, Assembly.Load("App_GlobalResources"));
return rmloc.GetString(key);
}لاحظ ان WF هو اسم الnamespace و controls هو اسم ملف ال.resx في الدالة السابقة والتي عليك تغييرها حسب ما المشروع الذي تعمل عليه .
و اذا كنت تستخدم Visual Studio 2005 فان PageName هي اسم الصفحة المراد تعريبها مع مراعاة وضع ملفات الresx داخل المجلد App_GlobalResources
لننتقل الان الى الحدث Page_Load ونقوم بكتابة الاتي :
if ((ddlSelectLang.Items.Count>0)&&(!Page.IsPostBack)) ddlSelectLang.Items.FindByValue(Thread.CurrentThread.CurrentUICulture.Name).Selected=true; Thread.CurrentThread.CurrentUICulture=new CultureInfo(ddlSelectLang.SelectedValue.ToString()); lblErrorMsg.Text=getFromResource(lblErrorMsg.ID); lblPassword.Text=getFromResource(lblPassword.ID); lblSelectLang.Text=getFromResource(lblSelectLang.ID); lblUserName.Text=getFromResource(lblUserName.ID); chkRememberMe.Text=getFromResource(chkRememberMe.ID); BtnLogin.Text=getFromResource(BtnLogin.ID);
ولأقوم باعطاء شرح أوفى لما تم القيام به انفا ..فقد قمت باضافة
using System.Globalization;
لتمكيني من استخدام الفتات المندرجة تحت هذا القسم والتي تعنى بمعلومات عن لغة التطبيق وهنا استخدمناها حتى نتمكن من استخدام CultureInfo .
وبالانتقال الى السطر الذي يله :
using System.Resources;
فقد قمت بوضعه حتى اتمكن من التعامل مع ResourceManager وبالتالي القراءة من الملف .resx .
واما بخصوص السطر :
using System.Reflection;
فقد قمت باضافته حتى نتمكن من استخدام Assembly.GetExecutingAssembly() والذي تعيد الassembly الخاص بالتطبيق وهو معامل يجب اضافته لانشاء ResourceManager
وبالانتقال الى الكود الموجود في Page_Load :
if ((ddlSelectLang.Items.Count>0)&&(!Page.IsPostBack)) ddlSelectLang.Items.FindByValue(Thread.CurrentThread.CurrentUICulture.Name).Selected=true;
فانه يقوم باختيارلغة الصفحة واختيارها في الاداة , أما السطر :
Thread.CurrentThread.CurrentUICulture=new CultureInfo(ddlSelectLang.SelectedValue.ToString());
فانه يقوم بتغيير اللغة الحالية للتطبيق عن طريق تغيير لغة الThread الحالي وهو السبب لاضافتنا using System.Threading .
اما باقي السطور فتقوم بتغيير النص الخاص بالادوات حسب اللغة الحالية للThread .
الصور أدناه توضح التطبيق بعد دعم تعدد اللغة .
بقي شي واحد قد يتبادر الى ذهنك وهو اتجاه الصفحة Dir حيث ان اتجاه اللغة العربية من اليمين الى اليسار اما بقية اللغات فهي من اليسار الى اليمين ..فكيف يتم التعامل مع هذه المعضلة ؟؟؟؟
وفي الحقيقة هي لا تعد معضلة اساسا فالحل أسهل مما تتصور ...
فقط قم بالتحول الى كود الHTML لصفحة الaspx واستبدال
الواسمة <body> بـ
<body dir=<%=Dir %>>
ومن ثم قم بالانتقال الى كود الCS واضف الخاصية Dir الى الكلاس الخاص بالصفحة لتكون بالشكل :
public string Dir
{
get
{
if (Thread.CurrentThread.CurrentUICulture.Name.StartsWith("ar-"))
return "rtl";
else
return "ltr";
}
}لاحظ أن الخاصية Dir تقوم باسترجاع "rtl" اذا كانت اللغة الحالية للتطبيق تبدأ بـar اي لغة عربية .
أرجو أن تنفعكم هذه المقالة المتواضعة ولا تنسوني يا اخوتي الكرام بالدعوات في هذا الشهر الفضيل ..وكل عام وانت بخير ...
