پياده سازي Internationalization در mvc
شناسه پست: 1356
بازدید: 1075

چکیده: استفاده از Angular.js برای پیاده سازی Internationalization در اپلیکیشن ASP.NET MVC

 

بازار جهانی بازار بزرگی است که به صورت الکترونیکی برای تمام مردم جهان در دسترس است. برنامه های وب، شیوه ایست برای اینکه ما به مخاطبین بیشماری در سراسر جهان دسترسی داشته باشیم. اگر یک سازمان قصد دارد که برنامه های تجاری (مانند فروشگاه آنلاین، ارائه خدمات، انتشارات و غیره) توسعه دهد و توسط تمام مردم در سراسر جهان مورد دسترسی قرار بگیرد، بهتر است اپلیکیشن هایی را بسازند که به راحتی با زبان و فرهنگ های مختلف همخوانی داشته باشد. این امر توسط Internationalization قایل انجام است.

وب اپلیکیشنهای امروزی از تکنولوژی هایی استفاده میکنند که از الگوها و بهترین شیوه ها سمت سرور و کلاینت استفاده میکنند. از آنجایی که ما تکنولوژی ASP.NET MVC را سمت سرور  داریم، برای تکمیل آن،تکنولوژی ماژولار AngularJS را نیز سمت کلاینت داریم. AngularJS یک فریم ورک MVC سمت کلاینت است که ماژول را بتفکیک شده با استفاده از  Services, Controllers, Factory, Directives و غیره ارائه میدهد.

 

Internationalization در ASP.NET MVC 

در این اپلیکیشن، ما روی پیاده سازی Internationalization در ASP.NET MVC و Angular.js کار خواهیم کرد. این اپلیکیشن با استفاده از  Free Community edition of Visual Studio 2015 ساخته شده است، اگرچه Visual Studio 2013 نیز اینجا میتواند مورد استفاده قرار بگیرد.
 
مرحله 1: ویژوال استودیو را باز کنید و یک ASP.NET MVC application جدید با نام NG_Int_App ایجاد نمایید. ok را کلیک کنید و سپس در پنجره بعدی، مانند شکل زیر template را از نوع Empty انتخاب نمایید.
create-mvc-project

ما چک باکسهای ASP.NET MVC  و Web API را انتخاب کرده ایم. از این رو ما میتوانیم از ساختار MVC و سرویس Web API برای ایجاد داده ها در Angular.js استفاده نماییم.

مرحله 2: در پوشه App_Data یک دیتابیس از نوع Sql Server به نام  ApplicationDB.mdf اضافه نمایید. در این دیتابیس، یک جدول جدید با اسکریپت زیر ایجاد نمایید:

CREATE TABLE [dbo].[EmployeeInfo] (
    [EmpNo]       INT          IDENTITY (1, 1) NOT NULL,
    [EmpName]     VARCHAR (50) NOT NULL,
    [Salary]      DECIMAL (18) NOT NULL,
    [DeptName]    VARCHAR (50) NOT NULL,
    [Designation] VARCHAR (50) NOT NULL,
    PRIMARY KEY CLUSTERED ([EmpNo] ASC)
);

داده های تستی زیر را به آن اضافه نمایید:

INSERT INTO [dbo].[EmployeeInfo] ([EmpNo], [EmpName], [Salary], [DeptName], [Designation]) VALUES (1, N'MS', CAST(78000 AS Decimal(18, 0)), N'IT', N'Manager')
INSERT INTO [dbo].[EmployeeInfo] ([EmpNo], [EmpName], [Salary], [DeptName], [Designation]) VALUES (2, N'VB', CAST(52000 AS Decimal(18, 0)), N'HR', N'LEAD')

مرحله 3: ما باید یک لایه Data Access بسازیم. بنابراین از ADO.NET Entity Framework برای دسترسی به داده ها استفاده مینماییم. در پوشه Models، یک ADO.NET Entity Data Model جدید به نام ApplicationDS ایجاد نمایید. در ویزارد مورد نظر، دیتابیس ApplicationDB.mdf و سپس جدول EmployeeInfo را انتخاب نمایید. بعد از اتمام ویزارد، کلاس EmployeeInfo  با خصوصیات جدول EmployeeInfo  ایجاد میشود. در نتیجه، ویزارد، کلاسهای مورد نیاز برای عملیات CRUD برای جدول EmployeeInfo  را تولید مینماید.

مرحله 4: در پوشه Controllers ، یک Web API controller جدید با اکشن های مورد نظر با استفاده از entity framework اضافه نمایید. نام این کنترلر را EmployeeInfoAPIController بگذارید. کنترلر را با Model class، Data Context class   و  controller nameمشخص شده در شکل زیر ایجاد نمایید:

اضافه کردن web api

در نتیجه، متدها برای انجام  عملیات مبتنی بر Http بر روی موجودیت EmployeeInfo ایجاد میشود.

برنامه را Build نمایید.

مرحله 5: در پروژه، اسکریپتهای فریم ورک AngularJS  را با استفاده از NuGet Package Manager اضافه نمایید. بر روی پروژه راست کلیک کرده و از Manage NuGet Packager، کلمه AngularJS  را جست و جو نمایید که در نتیجه گزینه ای مانند تصویر زیر نمایان می شود:

آن را نصب نمایید. بعد از نصب،یک پوشه Scripts در پروژه با رفرنس های مربوط به Angular اضافه میشود. در این پوشه، یک زیرپوشه به نام i18n  وجود دارد که شامل اسکریپتهای internationalization 
میباشد. اینها برای بومی سازی محصولات در هر زبان وفرهنگ مورد استفاده قرار میگیرد. در پروژه، فریم ورک
Bootstrap  را با استفاده از Manage NuGet Package به همان شیوه ای که Angular را نصب کردید نصب نمایید.

مرحله 6: در پروژه، یک پوشه به نام MyScript اضافه نمایید. در این پوشه، ما یک اسکریپت برای تعریف ماژول Angular ، Service و Controller  اضافه  میکنیم. در این پوشه، یک فایل جاوااسکریپت جدید به نام  logic.js اضافه کنید و کدهای زیر را درون آن قرار دهید:

//1.
var app = angular.module('app', []);
//2.
app.service('serv', function ($http) {
    this.getData = function () {
        var response = $http.get('http://localhost:54733/api/EmployeeInfoAPI');
        return response;
    };
    this.post = function (emp) {
        var response = $http({
            url: 'http://localhost:54733/api/EmployeeInfoAPI',
            method: 'post',
            data: emp,
            datatype:'json',
            contenttype:'application/json;utf-8'
        });
        return response;
    };
});
 
//3.
app.controller('ctrl', function ($scope, serv) {
    $scope.Employee = {
        EmpNo: 0,
        EmpName: '',
        Salary: 0,
        DeptName: '',
        Designation:''
    };
 
    $scope.Employees = [];
    $scope.Message = '';
 
    load();
    function load() {
        var promise = serv.getData();
        promise.then(function (resp) {
            $scope.Employees = resp.data;
            $scope.Message = 'Call is successful...';
 
        }, function (err) {
            $scope.Message = 'Call failed...' + err.status;
        });
    };
 
    $scope.clear = function () {
        $scope.Employee.EmpNo = 0;
        $scope.Employee.EmpName = '';
        $scope.Employee.Salary = 0;
        $scope.Employee.DeptName = '';
        $scope.Employee.Designation = '';
    };
 
    $scope.save = function () {
        var promise = crudserv.post($scope.Employee);
        promise.then(function (resp) {
            $scope.Employee.EmpNo = resp.data.EmpNo;
            $scope.Message = 'Call Completed Succesfully';
            loadData();
        }, function (err) {
            $scope.Message = 'Call Fail ' + err.status;
        });
    };
});

کد بالا شامل موارد زیر است:

(توجه: شماره خطهای زیر مطابق با شماره کامنتهای مشخص شده در کد بالا میباشد.)

1.      تعریف ماژول angular  به نام appmodule

2.      سررویس Angular  به نام serv  با وابستگی $http تعریف شده است. این برای فراخوانی Web API مورد استفاده قرار میگیرد. این سرویس شامل تابع ()getData است که  یک درخواست GET به Web API میفرستد  و داده های مربوط به کارمندان را دریافت میکند. تابع ()post پارامتر emp را به عنوان ورودی میگیرد و آن را  با POST Http به سمت Web API ارسال میکند. این تابع ها، آبجکت promise  را برمیگرداند.

3.      یک کنترلر Angular  به نام ctrl  با  وابستگی$scope   و  serv تعریف شده است. این کنترلر، آبجکت Employee scope را تعریف میکند. این آبجکت برای اتصال با View مورد استفاده قرار میگیرد. تابع ()load ، تابع ()getData از service را فراخوانی میکند و آرایه مربوط به اطلاعات کارمندان را دریافت میکند. تابع ()save تابع ()post در service را فراخوانی میکند و آبجکت employee  را به عنوان ورودی به آن پاس میدهد. تابع  ()clear مقادیر آبجکت Employee  را reset میکند.

مرحله 7: در پوشه Controllers، یک Empty MVC controller جدید به نام EmployeeInfoMVCController اضافه نمایید. این کنترلر، یک اکشن متد به نام Index  دارد. یک  view خالی از این اکشن به نام Index.cshtml را Scaffold  نمایید. کدهای HTML را به همراه سینتکس مربوط به اتصال داده های Angular  مانند زیر در View اضافه نمایید:

<link href="~/Content/bootstrap.min.css" rel="stylesheet" />
<a href="http://~/Scripts/angular.min.js" rel="nofollow" target="_blank">http://~/Scripts/angular.min.js</a>
<a href="http://~/MyScript/logic.js" rel="nofollow" target="_blank">http://~/MyScript/logic.js</a>
 
<table class="table table-striped table-bordered table-condensed" ng-app="appmodule"
       ng-controller="ctrl">
   <tr>
       <td>
           <table class="table table-striped table-bordered table-condensed">
               <tr>
                   <td>EmpNo</td>
                   <td>
                      <input type="text" ng-model="Employee.EmpNo"/>
                   </td>
               </tr>
               <tr>
                   <td>EmpName</td>
                   <td>
                       <input type="text" ng-model="Employee.EmpName"/>
                   </td>
               </tr>
               <tr>
                   <td>Salary</td>
                   <td>
                       <input type="text" ng-model="Employee.Salary"/>
                   </td>
               </tr>
               <tr>
                   <td>DeptName</td>
                   <td>
                       <input type="text" ng-model="Employee.DeptName"/>
                   </td>
               </tr>
               <tr>
                   <td>Designation</td>
                   <td>
                       <input type="text" ng-model="Employee.Designation"/>
                   </td>
               </tr>
               <tr>
                   <td>
                       <input type="button" value="Clear" ng-click="clear()"/>
                   </td>
                   <td>
                       <input type="button" value="Save" ng-click="save()"/>
                   </td>
               </tr>
           </table>
       </td>
   </tr>
   <tr>
       <td>
           <table class="table table-striped table-bordered table-condensed">
               <thead>
                   <tr>
                       <td>EmpNo</td>
                       <td>EmpName</td>
                       <td>Salary</td>
                       <td>DeptName</td>
                       <td>Designation</td>
                   </tr>
               </thead>
               <tbody>
                   <tr ng-repeat="Emp in Employees">
                       <td>{{Emp.EmpNo}}</td>
                       <td>{{Emp.EmpName}}</td>
                       <td>{{Emp.Salary}}</td>
                       <td>{{Emp.DeptName}}</td>
                       <td>{{Emp.Designation}}</td>
                   </tr>
               </tbody>
           </table>
</td>
   </tr>
</table>

مرحله 8: در فایل RouteConfig.cs، به صورت زیر، Route را برای کنترلر EmployeeInfoMVC  اضافه نمایید:

routes.MapRoute(
    name: "Default",
    url: "{controller}/{action}/{id}",
    defaults: new { controller = "EmployeeInfoMVC", action = "Index", id = UrlParameter.Optional }
);

برنامه را اجرا نمایید.

فرم ثبت اطلاعات کارمند در mvc

پیاده سازی Internationalization  برای اپلیکیشن MVC با استفاده از تنظیمات مرورگر

برای پیاده سازی internationalization، ما باید فایلهای resource  را در اپلیکیشن ایجاد نماییم. قصد داریم نتایج را در صفحه وب به فرمهای آلمانی و انگلیسی نمایش دهیم.

مرحله 9: در پروژه MVC، یک ASP.NET Folder App_LocalResources اضافه نمایید. در این پوشه، یک فایل Resource  جدید به نام MVCInternational.resx اضافه نمایید. Access Modifier این فایل را مانند شکل زیر به Public  تغییر دهید.

فایل resource در mvc

مقادیر Name/Value های زیر را در فایل MVCInternational.resx وارد نمایید:

فایل MVCInternational.resx را در همین پوشه کپی نمایید و نام آن را به VCInternational.de.resx تغییر دهید. Access Modifier این فایل را نیز به Public تغییر دهید. ما از این فایل برای کلمات آلمانی استفاده مینماییم. از Google Translator برای پیدا کردن مقادیر آلمانی برای نام برچسب ها استفاده نمایید. این فایل با مقادیر آلمانی در شکل زیر نمایش داده شده است:

فایل resource آلمانی

ما باید این فایلهای resource  را در اسمبلی embed نماییم. به این منظور روی آنها راست کلیک کرده و Build Action را به عنوان Embedded Resource تنظیم نمایید.

پروژه را Build نمایید.

مرحله 10: در پوشه Controllers ، یک empty Web API Controller جدید به نام ResourceAPIController اضافه نمایید. در این فایل، ما کدهای زیر را برای خواندن داده ها از فایلهای resource  اضافه مینماییم:

public class ResourceAPIController : ApiController
{
    [HttpGet]
    [Route("api/accessresources")]
    public IHttpActionResult GetResourceStringsFromResources()
    {
        //1.  
        ResourceSet resources = MVCInternattional.ResourceManager.GetResourceSet(CultureInfo.CurrentUICulture, true, true);
        Dictionary<string, string> resDictionary = new Dictionary<string, string>();
        //2.
        foreach (DictionaryEntry resource in resources)
        {
            resDictionary.Add(resource.Key.ToString(), resource.Value.ToString());
        }
        //3.
        return Ok(resDictionary);
    }
}

کد بالا شامل موارد زیر میباشد:

شماره خطها مطابق با شماره کامنتهای مشخص شده در کد بالا میباشد.

1.      Resource ها با استفاده از کلاس MVCInternational  برای culture کنونی load میشود.

2.      با حلقه بر روی Resource ها، مقادیر Key/Value آنها خوانده شده و در Dictionary ذخیره میشوند.

3.      این Dictionary برگردانده میشود.

اپلیکیشن را اجرا نمایید و در مرورگر، url زیر را وارد نمایید:

http://localhost:.api/accessresurces

نتیجه به صورت زیر نمایش داده خواهد شد:

فایل json انگلیسی

حال برای مشاهده نتیجه آلمانی، از افزونه Quick Language Switcher برای مرورگر کروم استفاده کنید. (از پلاگین ضروری برای مرورگرهای مختلف استفاده کنید و یا میتوانید به صورت دستی، زبانهای مرورگر را تغییر دهید). از طریق افزونه switcher، مطمئن شوید که زبان آلمانی در تنظیمات کروم اضافه شده است. با سوییچ به زبان آلمانی، نتیجه به صورت زیر نمایش داده خواهد شد:

فایل json آلمانی

مرحله 11: برای دسترسی به داده های JSON  درWeb API مطابق با تنظیمات culture ، تابع زیر را در سرویس serv  در فایل logic.js اضافه کنید.

this.getResources = function () {
    var response = $http.get('http://localhost:54733/api/accessresources');
    return response;
};

مرحله 12: تغییرات زیر را در controller از فایل logic.js ایجاد نمایید:

app.controller('ctrl', function ($scope, serv) {
    $scope.Employee = {
        EmpNo: 0,
        EmpName: '',
        Salary: 0,
        DeptName: '',
        Designation:''
    };
 
    $scope.resourcesData = {};
 
    $scope.Employees = [];
    $scope.Message = '';
 
    load();
    function load() {
        var promise = serv.getData();
        promise.then(function (resp) {
            $scope.Employees = resp.data;
            $scope.Message = 'Call is successful...';
            getResources();
 
        }, function (err) {
            $scope.Message = 'Call failed...' + err.status;
        });
    };
 
    function getResources() {
        var promise = serv.getResources();
        promise.then(function (resp) {
            $scope.resourcesData = resp.data;
        }, function (err) {
            $scope.Message = 'Call failed...' + err.status;
        });
    };
 
 
    $scope.clear = function () {
        $scope.Employee.EmpNo = 0;
        $scope.Employee.EmpName = '';
        $scope.Employee.Salary = 0;
        $scope.Employee.DeptName = '';
        $scope.Employee.Designation = '';
    };
 
    $scope.save = function () {
        var promise = crudserv.post($scope.Employee);
        promise.then(function (resp) {
            $scope.Employee.EmpNo = resp.data.EmpNo;
            $scope.Message = 'Call Completed Succesfully';
            loadData();
        }, function (err) {
            $scope.Message = 'Call Fail ' + err.status;
        });
    };
});

کد های highlighte شده به کنترلر اضافه شده است. کنترلر یک scope object جدید با نام resourcesData دارد. این آبجکت برای ذخیره داده های JSON مربوط به culture دریافت شده از سرور مورد استفاده قرار میگیرد. تابع ()getResources ، تابع ()getResources از Angular service را فراخوانی میکند که در نتیجه، داده های JSON مبتنی بر culture درخواست شده از سمت مرورگر را دریافت میکند. این تابع در success callback از تابع ()load در کنترلر فراخوانی شده است. 

مرحله 13: برای نمایش صفحه در فرمت ویژه culture، ما باید تغییراتی در Html فایل Index.cshtml ایجاد نماییم.تغییرات زیر را در آن انجام دهید:

@{
ViewBag.Title = "Index";
}
<link href="~/Content/bootstrap.min.css" rel="stylesheet" />
<a href="http://~/Scripts/angular.min.js" rel="nofollow" target="_blank">http://~/Scripts/angular.min.js</a>
<a href="http://~/MyScript/logic.js" rel="nofollow" target="_blank">http://~/MyScript/logic.js</a>
<body ng-app="appmodule">
<h2>{{resourcesData.EmployeeInformationLabel}}</h2>
 
 
<table class="table table-striped table-bordered table-condensed"
   ng-controller="ctrl">
<tr>
    <td>
        <table class="table table-striped table-bordered table-condensed">
            <tr>
                <td>{{resourcesData.EmpNoLabel}}</td>
                <td>
                    <input type="text" ng-model="Employee.EmpNo" />
                </td>
            </tr>
            <tr>
                <td>{{resourcesData.EmpNameLabel}}</td>
                <td>
                    <input type="text" ng-model="Employee.EmpName" />
                </td>
            </tr>
            <tr>
                <td>{{resourcesData.SalaryLabel}}</td>
                <td>
                    <input type="text" ng-model="Employee.Salary" />
                </td>
            </tr>
            <tr>
                <td>{{resourcesData.DeptNameLabel}}</td>
                <td>
                    <input type="text" ng-model="Employee.DeptName" />
                </td>
            </tr>
            <tr>
                <td>{{resourcesData.DesignationLabel}}</td>
                <td>
                    <input type="text" ng-model="Employee.Designation" />
                </td>
            </tr>
            <tr>
                <td>
                    <input type="button" value="{{resourcesData.ClearLabel}}" ng-click="clear()" />
                </td>
                <td>
                    <input type="button" value="{{resourcesData.SaveLabel}}" ng-click="save()" />
                </td>
            </tr>
        </table>
    </td>
</tr>
<tr>
    <td>
        <table class="table table-striped table-bordered table-condensed">
            <thead>
                <tr>
                    <td>{{resourcesData.EmpNoLabel}}</td>
                    <td>{{resourcesData.EmpNameLabel}}</td>
                    <td>{{resourcesData.SalaryLabel}}</td>
                    <td>{{resourcesData.DeptNameLabel}}</td>
                    <td>{{resourcesData.DesignationLabel}}</td>
                </tr>
            </thead>
            <tbody>
                <tr ng-repeat="Emp in Employees">
                    <td>{{Emp.EmpNo}}</td>
                    <td>{{Emp.EmpName}}</td>
                    <td>{{Emp.Salary}}</td>
                    <td>{{Emp.DeptName}}</td>
                    <td>{{Emp.Designation}}</td>
                </tr>
            </tbody>
        </table>
    </td>
</tr>
</table>
 
</body>

کد بالا ، داده های ذخیره شده در آبجکت resourcesData scope را بر اساس Angular Expression ها به قسمتهای مشخص شده در HTML اتصال میدهد.

مرحله 14: در فایل web.config، به صورت زیر تنظیمات را برای globalization  در قسمت  <system.web> تعریف نمایید:

<globalization culture="auto" uiCulture="auto" />

مرحله 15: برنامه را اجرا نمایید و lable های انگلیسی به صورت پیش فرض مانند شکل زیر نمایش داده میشود:

نتیجه انگلیسی

ما افزونه Quick Language Switcher اضافه شده در مرورگر را از قبل داریم. روی آن کلیک نمایید و زبان را آلمانی انتخاب کنید. در نتیجه یک فراخوانی http با Accept-Language از نوع آلمانی ایجاد میشود و صفحه تمام lable های مربوط به زبان آلمانی را مانند شکل زیر نمایش میدهد:

نتیجه آلمانی

این نحوه set کردن تنظیمات culture برای صفحه میباشد.

 

استفاده از اسکریپتهای i18n در Angular

وقتی ما پکیج Angular را در برنامه مان نصب میکنیم، یک زیرپوشه با نام i18n در اختیار ما قرار میگیرد که شامل اسکریپتها برای تمام culture ها میباشد. ما میتوانیم این اسکریپتها را بر اساس culture انتخابی از سمت مرورگر با استفاده از پلاگین Quick Language Switcher بارگزاری نماییم.

مرحله 16: فایل _layout.cshtml را باز نمایید و کد زیر را در آن قرار دهید:

@{
    var culture = HttpContext.Current.Request.UserLanguages[0].ToString();
}

این کد، زبان انتخاب شده توسط کاربر در مرورگر را دریافت میکند. زبان مورد نظر در Accept-Language از http request به سرور پاس داده میشود.

خط زیر را بعد از تمام رفرنسهای مربوط به اسکریپتها در انتهای فایل _layout.cshtml اضافه نمایید:

<script src=”@Url.Content(“~/Scripts/i18n/angular-locale_” + culture + “.js”)”></script>

این، اسکریپت، culture Angular مورد نظر در صفحه را مبتنی بر زبان انتخاب شده در Http Accept-Language بارگزاری مینماید.

برنامه را اجرا نمایید. صفحه با زبان پیش فرض انگلیسی بارگزاری میشود. ابزار توسعه دهنده کروم را باز نمایید، میبینید که angular-locale_en.js بارگزاری شده است و صفحه، culture انگلیسی را مانند شکل زیر نمایش میدهد:

اسکریپت culture انگلیسی angular

اگر به شکل دقت کنید میبینید که واحد حقوق $ میباشد.

حال زبان را با استفاده از افزونه Quick Language Switcher به آلمانی تغییر دهید.  نتیجه زیر با واحد یورو نمایش داده خواهد شد و همچنین فایل angular-locale_de.js بارگزاری میشود:

به همین ترتیب مبتنی بر هر Accept-Language در header، هر culture پشتیبانی شده میتواند بارگزاری شود.

نتیجه گیری

فریم ورک Angular.js، یک شیوه بی نقص برای پیاده سازی Internationalization  در اپلیکیشنهای ASP.NET MVC را ارائه میدهد.

برای دانلود سورس برنامه، اینجا کلیک کنید.

نویسنده

امید عباسی
من امید عباسی هستم. سالهاست که در زمینه برنامه نویسی با تکنولوژی دات نت فعالیت میکنم و عاشق این هستم که تجربیات و دانش خودم را در این زمینه با دیگران به اشتراک بزارم. خیلی دوست دارم که نظر و انتقاد خودتون رو در مورد این نوشته برای من بنویسید تا بتونم در آینده، مطالب بهتر و ارزشمندتری را برای شما فراهم کنم. در صورت داشتن هرگونه سوال هم در قسمت دیدگاه ها میتونید با بنده در ارتباط باشید