چکیده: استفاده از Angular.js برای پیاده سازی Internationalization در اپلیکیشن ASP.NET MVC
بازار جهانی بازار بزرگی است که به صورت الکترونیکی برای تمام مردم جهان در دسترس است. برنامه های وب، شیوه ایست برای اینکه ما به مخاطبین بیشماری در سراسر جهان دسترسی داشته باشیم. اگر یک سازمان قصد دارد که برنامه های تجاری (مانند فروشگاه آنلاین، ارائه خدمات، انتشارات و غیره) توسعه دهد و توسط تمام مردم در سراسر جهان مورد دسترسی قرار بگیرد، بهتر است اپلیکیشن هایی را بسازند که به راحتی با زبان و فرهنگ های مختلف همخوانی داشته باشد. این امر توسط Internationalization قایل انجام است.
وب اپلیکیشنهای امروزی از تکنولوژی هایی استفاده میکنند که از الگوها و بهترین شیوه ها سمت سرور و کلاینت استفاده میکنند. از آنجایی که ما تکنولوژی ASP.NET MVC را سمت سرور داریم، برای تکمیل آن،تکنولوژی ماژولار AngularJS را نیز سمت کلاینت داریم. AngularJS یک فریم ورک MVC سمت کلاینت است که ماژول را بتفکیک شده با استفاده از Services, Controllers, Factory, Directives و غیره ارائه میدهد.
Internationalization در ASP.NET MVC
ما چک باکسهای 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مشخص شده در شکل زیر ایجاد نمایید:
در نتیجه، متدها برای انجام عملیات مبتنی بر 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 } ); |
برنامه را اجرا نمایید.
پیاده سازی Internationalization برای اپلیکیشن MVC با استفاده از تنظیمات مرورگر
برای پیاده سازی internationalization، ما باید فایلهای resource را در اپلیکیشن ایجاد نماییم. قصد داریم نتایج را در صفحه وب به فرمهای آلمانی و انگلیسی نمایش دهیم.
مرحله 9: در پروژه MVC، یک ASP.NET Folder App_LocalResources اضافه نمایید. در این پوشه، یک فایل Resource جدید به نام MVCInternational.resx اضافه نمایید. Access Modifier این فایل را مانند شکل زیر به Public تغییر دهید.
مقادیر Name/Value های زیر را در فایل MVCInternational.resx وارد نمایید:
فایل MVCInternational.resx را در همین پوشه کپی نمایید و نام آن را به VCInternational.de.resx تغییر دهید. Access Modifier این فایل را نیز به Public تغییر دهید. ما از این فایل برای کلمات آلمانی استفاده مینماییم. از Google Translator برای پیدا کردن مقادیر آلمانی برای نام برچسب ها استفاده نمایید. این فایل با مقادیر آلمانی در شکل زیر نمایش داده شده است:
ما باید این فایلهای 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
نتیجه به صورت زیر نمایش داده خواهد شد:
حال برای مشاهده نتیجه آلمانی، از افزونه Quick Language Switcher برای مرورگر کروم استفاده کنید. (از پلاگین ضروری برای مرورگرهای مختلف استفاده کنید و یا میتوانید به صورت دستی، زبانهای مرورگر را تغییر دهید). از طریق افزونه switcher، مطمئن شوید که زبان آلمانی در تنظیمات کروم اضافه شده است. با سوییچ به زبان آلمانی، نتیجه به صورت زیر نمایش داده خواهد شد:
مرحله 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 انگلیسی را مانند شکل زیر نمایش میدهد:
اگر به شکل دقت کنید میبینید که واحد حقوق $ میباشد.
حال زبان را با استفاده از افزونه Quick Language Switcher به آلمانی تغییر دهید. نتیجه زیر با واحد یورو نمایش داده خواهد شد و همچنین فایل angular-locale_de.js بارگزاری میشود:
به همین ترتیب مبتنی بر هر Accept-Language در header، هر culture پشتیبانی شده میتواند بارگزاری شود.
نتیجه گیری
فریم ورک Angular.js، یک شیوه بی نقص برای پیاده سازی Internationalization در اپلیکیشنهای ASP.NET MVC را ارائه میدهد.
برای دانلود سورس برنامه، اینجا کلیک کنید.