چند زبانه کردن سایت در MVC

دوشنبه 5 مرداد 1394

در این مقاله، پیاده سازی چندزبانه کردن سایت در MVC ، ایجاد JavaScript bundleهای سفارشی به همراه پیغام های مبتنی بر زبان کاربر، کلاس های Custom HTML Helper، چگونگی تنظیم زبان کاربر براساس کوکی مربوط به Login کاربر، نمایش ترجمه مقادیر resource در یک فرم و همچنین چگونگی نگه داری نام ها و مقادیر در Resource File را مرور خواهیم کرد.

چند زبانه کردن سایت در MVC

ایده مقاله:

در ادامه نرم افزار MVCای خواهیم ساخت که با توجه به زبان های مختلف انتخابی کاربر، نمایش داده می شود. محتوای فرم با توجه به نام و زبان مربوطه از Resource File نمایش داده می شود و برای این کار، هر زمان که کاربر فرمی را Submit کند یا اطلاعاتی جهت اعتبارسنجی ارسال کند، پیامی توسط  bundled JavaScript سفارشی جاوا براساس زبان کاربر، نمایش داده می شود.

آموزش تصویری و فارسی ساخت سایت چند زبانه در MVC

مطالب پیش رو:

به همراه پیاده سازی این نمونه برنامه MVC، مفاهیم زیر را یاد خواهیم گرفت:

1. ایجاد Resource File با استفاده از ترکیب کلید و مقدار برای زبان موردنظر

2. نمایش مقدار Resource Key با توجه به زبان کاربر در فرم

3. پیاده سازی کوکی در MVC

4. Bundling و Minification

5. کلاس های Custom HTML Helper

6. ایجاد Bundleهای سفارشی

7. ترجمه پیغام های جاوا اسکریپت به زبان انتخابی کاربر

گام اول:

یک پروژه MVC به نام  “MultilingualMVCApp” ایجاد می کنیم.

گام دوم:

یک application folder جدید به نام “App_GlobalResources” ایجاد می کنیم که برای نگه داری Resource File ترکیبی کلید/مقدار برای زبان های مختلف از آن استفاده می کنیم. روی “MultiLingualMVCApp” کلیک و گزینه "Add" را انتخاب کرده و پس از آن “Add ASP.NET Folder” را انتخاب می کنیم و سپس بر روی “App_GlobalResources” کلیک می کنیم. در شکل زیر می توانید، مراحل انجام کار را مشاهده نمایید.

گام سوم:

با توجه به تصاویر زیر، Resource Fileای برای زبان پیش فرض انگلیسی بسازید و نام آن را "Notifications.resx" بگذارید. برای این کار، روی فولدر “App_GlobalResources” راست کلیک کرده، "Add" را انتخاب و روی “Resource file” کلیک می کنیم و نام آن را به "Notifications" تغییر داده و OK می کنیم.

روی "Resources File" کلیک کنید و مانند شکل زیر، "Notifications" را وارد کنید.

با همین روش، Resource File ای با نام “Notifications.fa.resx” زیر شاخه فایل App_GlobalResources می سازیم. پس از انجام عملیات فوق، Solution Explorer پروژه به این صورت درخواهد آمد.

گام چهارم:

در این مرحله، نمونه کد Resource Key را به همراه مقادیر ترجمه آنها برای زبان انگلیسی و فارسی اضافه خواهیم کرد. برای این کار روی فایل "Notifications.resx" دابل کلیک می کنیم، فایلی با سه ستون نمایش داده می شود که ستون های آن به این ترتیب هستند:

Name(نام)، Value(مقدار) و comment(توضیح)

Name: این فیلد نام، مانند یک Resource Key رفتار می کند و مقدار آن در فایل باید یکتا باشد و خالی هم نباشد.

حالا می توانید مطابق آنچه در شکل زیر نشان داده شده است، کلید نمونه و مقدار مربوط به آن را برای زبان پیش فرض (انگلیسی) وارد کنید.

با همین روش، کلید مقدارهایی که در “Notifications.resx” به همراه مقادیر ترجمه برای زبان فارسی نام گذاری شده اند، اضافه کنید.

با همین روش، شما می توانید Resource File های مختلف را برای زبان های مختلف وارد کنید و همچنین می توانید چندین نوع Resource را به فایل های resx اضافه کنید. (مانند رشته، تصویر، آیکون و...)

گام پنجم:

در این مرحله، یک Controller به نام “DemoController” به پروژه اضافه می کنیم. مطابق شکل زیر روی فولدر "Controllers" راست کلیک کرده و سپس گزینه Add را انتخاب و روی "Controller" کلیک می کنیم.

روی "Controller.." کلیک کرده و گزینه "MVC5 Controller - Empty" را انتخاب و Add را کلیک می کنیم.

و سپس نام آن را  “DemoController” می گذاریم و "Add" را کلیک می کنیم.

همان طور که در شکل زیر می بینید، Controller با Action پیش فرضی با نام index ایجاد شد.

گام ششم:

با راست کلیک کردن روی View و انتخاب "Add View" یک view به متد index اضافه می کنیم. شکل زیر به شما کمک می کند تا مراحل را درست انجام دهید.

با کلیک روی "Add View..."پنجره ای به این شکل باز می شود:

حالا روی دکمه "Add" کلیک کنید، فایلی با عنوان Index.cshtml ساخته می شود.

گام هفتم:

کدهای طراحی را با کدهای زیر که شامل یک فرم نمونه برای وارد کردن نام کاربری، زبان انتخابی کاربر و دکمه Submit است، جایگزین می کنیم.

    @{  
        ViewBag.Title = "Index";  
    }  
      
    <h2>Demo</h2>  
    <div>  
        @using (Html.BeginForm("Index", "Demo", FormMethod.Post))  
        {  
            <label>Enter User Name</label>  
            <input type="text" name="txtName" placeholder="Guest"   
                   class="form-control" />  
            <br/>  
            <label>Select Language:</label>  
            <select name="ddlLanguage" class="form-control">  
                <option value="en">English</option>  
                <option value="fa">French</option>  
            </select>  
            <br />  
            <input type="submit" name="Submit" class="form-control" />  
        }  
    </div>  

حالا، برنامه را Build کنید و آن را با آدرس (http://localhost:49624/Demo/Index) اجرا کنید تا فرمی شبیه به شکل زیر را مشاهده نمایید.

گام هشتم:

در این مرحله، قطعه کدی برای Action مربوط به دکمه submit می نویسیم تا زبان انتخابی کاربر را در کوکی ها و نام کاربر را در TempData(برای ارسال داده بین کنترلرها استفاده می شود) ثبت کند و سپس کاربر را به صفحه اصلی هدایت کند.

    [HttpPost]  
     public ActionResult Index(FormCollection collection)  
     {  
         TempData.Add("LoggedInUser", collection["txtName"]);  
         string language = collection["ddlLanguage"];  
         SetCulture(language);  
      
         return RedirectToAction("Home");  
     }  
      
     /// <summary>  
     /// Set the culture based on culture code and set the   
     /// value in cookie  
     /// </summary>  
     /// <param name="cultureCode"></param>  
     private void SetCulture(string cultureCode)  
     {  
      
         var cookieCultureLanguage = new HttpCookie("UserLanguage")  
         {  
             Value = cultureCode  
         };  
      
         Response.Cookies.Set(cookieCultureLanguage);  
      
         //Sets  Culture for Current thread  
         Thread.CurrentThread.CurrentCulture =  
         System.Globalization.CultureInfo.CreateSpecificCulture("en");  
      
         //Ui Culture for Localized text in the UI  
         Thread.CurrentThread.CurrentUICulture =  
         new System.Globalization.CultureInfo(cultureCode);  
      
     }  

کوکی که در کد قبلی با استفاده از متد “SetCulture” تنظیم شد، کمک می کند تا مقادیر ترجمه شده زبان انتخابی کاربر از Resource File در یک فرم نمایش داده شود.

گام نهم:

در این مرحله، یک Controller به نام "Home" را به DemoController.cs" اضافه می کنیم و یک view از آن می سازیم.

/// <summary>  
/// Home Action Controller Method  
/// </summary>  
/// <returns></returns>  
public ActionResult Home()  
{  
    return View();  
}  

سپس در متد Home روی View()، راست کلیک کرده و گزینه "Add View..." را انتخاب می کنیم، پس از انتخاب این گزینه قالب آماده ای باز می شود، اگر روی گزینه "Add" کلیک کنیم، صفحه ای با طراحی پیش فرض به نام “Home.cshtml” ساخته می شود. درحال حاضر، این صفحه را با طراحی پیش فرض رها می کنیم تا در مرحله بعد، تغییرات را اعمال کنیم.

گام دهم:

متدی با نام “Application_AcquireRequestState” به فایل Global.asax.cs اضافه می کنیم تا درصورت وجود کوکی، culture را براساس زبان انتخابی کاربر تنظیم کند و در غیر این صورت آن را روی زبان پیش فرض انگلیسی تنظیم نماید.

 /// <summary>  
 /// Application AcquireRequestState  
 /// </summary>  
 /// <param name="sender"></param>  
 /// <param name="e"></param>  
 protected void Application_AcquireRequestState(object sender,   
EventArgs e)  
 {  
  
     string culture;  
     HttpCookie cookie = Request.Cookies["UserLanguage"];  
     if (cookie != null && cookie.Value != null   
        && cookie.Value.Trim() != string.Empty)  
         culture = cookie.Value;  
     else  
         culture = "en";  
  
     //Default Language/Culture for all number, Date format  
     System.Threading.Thread.CurrentThread.CurrentCulture =  
     System.Globalization.CultureInfo.CreateSpecificCulture("en");  
  
     //Ui Culture for Localized text in the UI  
     System.Threading.Thread.CurrentThread.CurrentUICulture =  
     new System.Globalization.CultureInfo(culture);  
 } 

گام یازدهم:

در این مرحله، یک کلاس مترجم سفارشی شده JavaScript bundle پیاده سازی می کنیم. این کلاس کمک می کند یک JavaScript bundle برای پیام های موجود در فایل جاوا اسکریپت مانند alert, input validation و ... براساس زبان انتخابی کاربر بسازیم.

پس در ابتدا یک فولدر به نام “ResourceHandler” می سازیم. برای این کار، روی پروژه "MultiLingualMVCApp" راست کلیک کرده و گزینه "Add" را انتخاب و سپس “Add New Folder” را انتخاب می کنیم و نام آن را “ResourceHandler” می گذاریم و یک کلاس به نام “JSTranslator” به این فولدر اضافه می کنیم.

کد درون این کلاس را، با کد زیر تغییر دهید.

    using System.Text.RegularExpressions;  
    using System.Web;  
    using System.Web.Optimization;  
      
    namespace MultiLingualMVCApp.ResourceHandler  
    {  
        public class JSTranslator : IBundleTransform  
        {  
            #region IBundleTransform  
      
            /// <summary>  
            /// IBundleTransform Process method  
            /// </summary>  
            /// <param name="context">Bundle Context</param>  
            /// <param name="response">Bundle Response</param>  
            public void Process(BundleContext context, BundleResponse response)  
            {  
                string translated = ScriptTranslator(response.Content);  
                response.Content = translated;  
            }  
     
            #endregion  
     
            #region Localization Of Js Bundle Flow  
      
            private static readonly Regex Regex =   
                new Regex(@"GetResourceValue\(([^\))]*)\)",  
                               RegexOptions.Singleline | RegexOptions.Compiled);  
      
            /// <summary>  
            /// Translated script based on JavaScript content  
            /// </summary>  
            /// <param name="text"></param>  
            /// <returns></returns>  
            private string ScriptTranslator(string text)  
            {  
                MatchCollection matches = Regex.Matches(text);  
                foreach (Match match in matches)  
                {  
                    object obj = HttpContext.GetGlobalResourceObject("Notifications",   
                        match.Groups[1].Value);  
                    if (obj != null)  
                        text = text.Replace(match.Value, CleanText(obj.ToString()));  
                }  
      
                return text;  
            }  
      
            /// <summary>  
            /// Format the text as Clean while displaying  
            /// in JavaScript notifications  
            /// </summary>  
            /// <param name="text"></param>  
            /// <returns></returns>  
            private static string CleanText(string text)  
            {  
                text = text.Replace("'", "");  
                return text;  
            }  
     
            #endregion  
        }  
    }  

نکاتی درباره کد JSTranslator.cs

- کلاس JSTranslator.cs از “IbundleTransform” ارث بری نموده است.

- متد Process به این صورت پیاده سازی شده است که: محتوای BundleResponse را می گیرد و پیام های جاوا اسکریپت را در صورت وجود با استفاده از متد ScriptTranslator به زبان انتخابی کاربر ترجمه می کند و دوباره به BundleResonse برمی گرداند.

- عبارت Regex که در فایل اسکریپت استفاده کرده ایم، یک کلمه کلیدی از نوع regular expression است.

- مثالی از کلمه کلیدی Regex که در اسکریپت استفاده کرده ایم به این صورت است:  GetResourceValue(ResourceKeyName)

- متد ScriptTranslator ابتدا یک شی "MatchCollection" براساس عبارت regex می گیرد و سپس براساس مجموعه Match نام کلید و با استفاده از متد “GetGlobalResourceObject” مقادیر ترجمه شده را می گیرد.

- GetGlobalResourceObject پارامترهای نام فایل منبع Resource file name و Resource Key name را می گیرد.

- متد CleanText هر کاراکتری را که زمان نمایش به صورت جاوا اسکریپت، تولید مشکل می کند، پاک می نماید.

به این ترتیب شما یک کلاس سفارشی JavaScript bundle ایجاد کردید.

گام دوازدهم:

در این مرحله، دو فایل جاوا اسکریپت را به همراه توابع نمونه به زیرشاخه فولدر “Scripts” اضافه می کنیم.

فایل اول، “UserNotifications” نام دارد و شامل تابع زیر است:

function UserTermsNotification() {  
    alert('GetResourceValue(UserTermsDisplayNotification)');  
} 

دومین فایل به نام “UserOperations” می باشد و تابع آن به شکل زیر است:

function AddUserMessage() {  
    alert('GetResourceValue(UserAdded)');  
}  
  
function DeleteUserMessage() {  
    alert('GetResourceValue(UserDeleted)');  
} 

گام سیزدهم:

در این مرحله، فایل جاوا اسکریپتی را که در مراحل قبل ساختیم، در فایل BundleConfig.cs (می توانید آن را در فولدر App_Start ببینید) با استفاده از JavaScript bundle سفارشی که در فایل JSTranslator.cs ایجاد کردیم، Bundle می کنیم. کد بلاک زیر را به متد RegisterBundles اضافه می کنیم و همچنین فضاهای نام زیر را به پروژه اضافه کنید.

using System.Collections.Generic;
using MultiLingualMVCApp.ResourceHandler;
var lstLangCultures = new List<string>() { "en", "fa" };  
 //Loops through available languages to add language specific   
 //JavaScript minified bundles  
 foreach (var cultureName in lstLangCultures)  
 {  
     var extJsNotifications = new Bundle(string.Format("~/Scripts  
                             /Notifications-{0}", cultureName))  
        .Include("~/Scripts/UserNotifications.js")  
        .Include("~/Scripts/UserOperations.js");  
     extJsNotifications.Transforms.Clear();  
     extJsNotifications.Transforms.Add(new JSTranslator());  
     extJsNotifications.Transforms.Add(new JsMinify());  
     bundles.Add(extJsNotifications);  
 }  

گام چهاردهم:

در این مرحله، کلاس Custom HTML Helper را پیاده سازی می کنیم که به ما کمک می کند، JavaScript bundle سفارشی براساس نیازهای خود بسازیم. بنابراین یک کلاس به نام HtmlHelpers زیرشاخه فولدر App_Start می سازیم و کد آن را به این شکل تغییر می دهیم.

using System.Web;  
  
namespace MultiLingualMVCApp  
{  
    public class HtmlHelpers  
    {  
        /// <summary>  
        /// Localized JavaScript bundle   
        /// </summary>  
        /// <param name="fileName"></param>  
        /// <returns></returns>  
        public static HtmlString LocalizedJsBundle(string fileName)  
        {  
            string culture;  
            var cookie = HttpContext.Current.Request.Cookies["UserLanguage"];  
            if (cookie != null && cookie.Value != null   
                && cookie.Value.Trim() != string.Empty)  
                culture = cookie.Value;  
            else  
                culture = "en";  
            fileName = string.Concat(fileName, "-", culture);  
            var output = (HtmlString)System.Web.Optimization.Scripts  
                .Render(fileName);  
            return output;  
        }  
    }  
} 

طبق آنچه که در گام 13و 14 گفته شد، JavaScript bundle سفارشی شده را در فایل BundleConfig.cs include کردیم و برای استفاده از Bundle مخصوص هر زبان، براساس زبان انتخابی کاربر کلاس custom HTML helper را ساختیم.

مفهموم Bundling و Minification در کاهش ترافیک شبکه و کاهش حجم فایل زمانی که فایل بارگیری می شود، بسیار مفید است. زیرا چندین فایل جاوا اسکریپت را به یک فایل تبدیل می کند و آن فایل را cache می کند. اگر محتوای فایل را تغییر دهید، به طور خودکار محتوای جدید را به وسیله یک شماره نسخه جدید می گیرد. بنابراین باعث بالا رفتن کارآیی صفحه از تمامی جهات می شود.

گام پانزدهم:

در این مرحله، فایل “Home.cshtml” را از طراحی پیش فرض به طراحی دلخواهمان تغییر می دهیم.

به این ترتیب، نرم افزار چندزبانه کردن MVC با استفاده از فایل های JavaScript bundled کوچک شده و براساس زبان انتخابی کاربر را پیاده سازی کردیم. حالا پروژه را Build کنید و آن را با آدرس (http://localhost:49624/Demo/Index) اجرا کنید.

نام کاربری را وارد کرده و زبان انگلیسی را انتخاب کنید، صفحه زیر نمایش داده می شود.

اگر روی دکمه Submit کلیک کنید، به صفحه اصلی به این صورت هدایت می شوید.

صفحه بالا توضیحی درباره امکانات پیاده سازی شده می باشد. به همین صورت اگر روی "Add User" و "Delete User" کلیک کنید پیغامی به زبان انگلیسی نمایش داده می شود.

گام شانزدهم:

در این مرحله، دوباره به آدرس (http://localhost:49624/Demo/Index) بروید و این بار زبان فارسی را انتخاب کنید، باید خروجی زیر را مشاهده کنید.

روی Submit کلیک کنید تا به صفحه اصلی هدایت شوید.

صفحه بالا توضیحی درباره امکانات پیاده سازی شده می باشد. به همین صورت اگر روی "Add User" و "Delete User" کلیک کنید پیغامی به زبان فارسی نمایش داده می شود.

فایل های ضمیمه

برنامه نویسان

نویسنده 3355 مقاله در برنامه نویسان

کاربرانی که از نویسنده این مقاله تشکر کرده اند

در صورتی که در رابطه با این مقاله سوالی دارید، در تاپیک های انجمن مطرح کنید