6. Görünümlerin Uluslararasılaştırılması
Burada görünümlerin uluslararasılaştırılması sorununu ele alacağız. Bu karmaşık bir sorundur ve Scott Hanselman’ın aşağıdaki makalesinde bu konuya ilişkin iyi bir açıklama bulabilirsiniz:
[http://www.hanselman.com/blog/GlobalizationInternationalizationAndLocalizationInASPNETMVC3JavaScriptAndJQueryPart1.aspx]
Öncelikle, görünümlerin uluslararasılaştırılmasıyla ilgili çeşitli terimlerin tanımlarına bir göz atalım:
Uluslararasılaştırma (i18n) | uygulamanın farklı dilleri ve yerel ayarları desteklemesini sağlamak |
Yerelleştirme (l10n) | uygulamanın belirli bir dil/yerel ayar çiftini desteklemesini sağlamak |
Küreselleştirme | Internationalisation ve Localisation'in birleşimi |
Dil | konuşulan dil – ISO kodu ile belirtilir (fr: Fransızca, es: İspanyolca, en: İngilizce, ...) |
Yerel ayar | dilin bir varyantı – yine bir kodla belirtilir: ISO (en_GB: Büyük Britanya İngilizcesi, en_US: ABD İngilizcesi, ...) |
Sorunu ilk örnekle ele alalım.
6.1. Gerçek sayıların yerelleştirilmesi
Önceki giriş formunda bir tutarsızlık göze çarpmaktadır:
![]() |
Gerçek sayı için [0,3] yazdık ancak bu kabul edilmedi. [0.3] yazmak gerekiyor:
![]() |
Dolayısıyla beklenen format, Fransız formatı değil, İngilizce formatıdır. İnternette arama yaptığımızda bazı çözümler buluyoruz. İşte bunlardan biri.
[GET] ve [POST] eylemleri şu şekilde değiştirilir:
// Eylem13-GET
[HttpGet]
public ViewResult Action13Get()
{
return View("Action13Get", new ViewModel11());
}
// Eylem13-POST
[HttpPost]
public ViewResult Action13Post(ViewModel11 modèle)
{
return View("Action13Get", modèle);
}
[Action13Get.cshtml] görünümü, JavaScript komut dosyaları dışında [Action12Get.cshtml] görünümüyle aynıdır:
<head>
<meta name="viewport" content="width=device-width" />
<title>Action13Get</title>
<link rel="stylesheet" href="~/Content/Site.css" />
<script type="text/javascript" src="~/Scripts/jquery-1.8.2.min.js"></script>
<script type="text/javascript" src="~/Scripts/jquery.validate.min.js"></script>
<script type="text/javascript" src="~/Scripts/jquery.validate.unobtrusive.min.js"></script>
...
<script type="text/javascript" src="~/Scripts/myscripts.js"></script>
</head>
Not: 5. satırda, jQuery sürümünü kendi Visual Studio sürümünüze göre uyarlayın.
- 9. satırda, [myscripts.js] komut dosyasını ekledik. Bu komut dosyası şöyledir:
![]() |
// http://blog.instance-factory.com/?p=268
$.validator.methods.number = function (value, element) {
return this.optional(element) ||
!isNaN(Globalize.parseFloat(value));
}
$.validator.methods.date = function (value, element) {
return this.optional(element) ||
!isNaN(Globalize.parseDate(value));
}
jQuery.extend(jQuery.validator.methods, {
range: function (value, element, param) {
//Değeri ayrıştırmak için Globalization eklentisini kullanın
var val = Globalize.parseFloat(value);
return this.optional(element) || (
val >= param[0] && val <= param[1]);
}
});
// belge yüklendiğinde
$(document).ready(function () {
var culture = 'fr-FR';
Globalize.culture(culture);
});
Bu komut dosyasının nerede bulunduğunu 1. satırda belirttim. Anlamadığım için bunu açıklamaya çalışmayacağım. Javascript bazen anlaşılması zor yönleri olabilir. 4., 9. ve 15. satırlarda [Globalize] nesnesi kullanılıyor. Bu nesne, JQuery Globalization kütüphanesi tarafından sağlanıyor ve şu komutla edinilebilir:
![]() |
![]() |
- [1]'te, [Exemple-03] projesinin [NuGet] paketlerini yönetin;
- [2]'te, çevrimiçi paketlere göz atın;
- [3]'te, [globalization] terimini yazın;
- [4]'te, JQuery projesine ait [Globalize] paketini kurun.
[Globalize] paketi kurulduktan sonra, [Scripts] klasöründe yeni bir dal belirir:
![]() |
- [1]'te, ana komut dosyası [globalize.js] ile birlikte [globalize] klasörü oluşturulmuştur;
- [2]'te, ana komut dosyası [globalize.js], dil ve yerel ayarlara özgü komut dosyalarıyla tamamlanmıştır;
- [3]'te, Fransızca dile özgü komut dosyaları, Belçika (BE), Kanada (CA), Fransa (FR), İsviçre (CH), Lüksemburg (LU) Monako (MC).
[globalize.js] alfabesi ve kültürümüzün alfabesi olan [globalize.culture.fr-FR.js], [Action13Get.cshtml] sayfamızda yer alan alfabe listesine dahil edilmelidir:
<head>
<meta name="viewport" content="width=device-width" />
<title>Action13Get</title>
...
<script type="text/javascript" src="~/Scripts/globalize/globalize.js"></script>
<script type="text/javascript" src="~/Scripts/globalize/cultures/globalize.culture.fr-FR.js"></script>
<script type="text/javascript" src="~/Scripts/myscripts.js"></script>
</head>
- 5. satır: [globalize] komut dosyası;
- 6. satır: [globalize.culture.fr-FR.js] betiği;
- 7. satır: [myscripts.js] komut dosyası;
Son komut dosyasına geri dönelim:
// http://blog.instance-factory.com/?p=268
$.validator.methods.number = function (value, element) {
return this.optional(element) ||
!isNaN(Globalize.parseFloat(value));
}
...
// belge yüklendiğinde
$(document).ready(function () {
var culture = 'fr-FR';
Globalize.culture(culture);
});
10-13. satırlar, istemci tarafındaki kültürü [fr-FR] olarak belirler:
- 10. satır: Komut dosyasının bulunduğu belge tarayıcı tarafından tamamen yüklendiğinde JQuery [ready] işlevi çalıştırılır;
- 11-12. satırlar: istemci tarafındaki dil ayarı [fr-FR] olarak belirlenir. Bunun için [globalize.culture.fr-FR.js] dosyasının, belgeyle ilişkili JavaScript komut dosyaları listesine eklenmesi gerekir.
Şimdi yeni uygulamayı test edebiliriz:
![]() |
Artık gerçek sayı olarak [0,3] yazabiliriz; bu, daha önce yapamadığımız bir şeydi. Ancak başka bir sorunla karşılaşıyoruz:
Yukarıda, istemci tarafındaki doğrulama, İngilizce sayı biçimini kullanarak [11.2] yazmamıza izin veriyor. Formu gönderdiğimizde bu değer sunucu tarafında kabul edilmiyor:
[11,2] yazmak gerekiyor ve bu durumda hem istemci hem de sunucu tarafında çalışıyor. İstemci tarafında İngilizce notasyonun kabul edilmemesi gerekir. Bu mümkün olmalı...
Şimdi de görünümlerin uluslararasılaştırılmasına geçelim. Önceki form örneğiyle devam edeceğiz ve bunu iki dilde sunacağız: Fransızca ve İngilizce.
6.2. Kültür Yönetimi
Görünümlerin dili, [Thread.CurrentThread.CurrentUICulture] nesnesi tarafından kontrol edilir. Sayfaları [fr-FR] kültüründe görüntülemek için şunu yazıyoruz:
Yerelleştirme (tarihler, sayılar, para birimleri, saatler vb.) [Thread.CurrentThread.CurrentCulture] nesnesi tarafından kontrol edilir. Daha önce yazılanlara benzer şekilde şunu yazacağız:
Bu iki komut, uygulamanın her bir denetleyicisinin oluşturucusunda yer alabilir. Ancak, tüm denetleyicilerde ortak olan bu kodu faktörlere ayırmak da istenebilir. Biz bu yolu izleyeceğiz.
İki yeni denetleyici oluşturuyoruz:
![]() |
- [I18NController], uluslararasılaştırma kullanan tüm denetleyicilerin ana sınıfı olacaktır;
- [SecondController] ise [I18NController]'ten türetilmiş örnek bir denetleyicidir.
[I18NController] denetleyicisinin kodu şöyledir:
using System.Threading;
using System.Web;
using System.Web.Mvc;
namespace Exemples.Controllers
{
public abstract class I18NController : Controller
{
public I18NController()
{
// mevcut isteğin bağlamı alınır
HttpContext httpContext = HttpContext.Current;
// istek, [lang] parametresini aramak üzere incelenir
// URL parametreleri içinde aranır
string langue = httpContext.Request.QueryString["lang"];
if (langue == null)
{
// gönderilen parametreler içinde aranır
langue = httpContext.Request.Form["lang"];
}
if (langue == null)
{
// kullanıcının oturumunda aranıyor
langue = httpContext.Session["lang"] as string;
}
if (langue == null)
{
// HTTP başlığının ilk parametresi AcceptLanguages
langue = httpContext.Request.UserLanguages[0];
}
if (langue == null)
{
// fr-FR dil ayarı
langue = "fr-FR";
}
// dil, oturuma eklenir
httpContext.Session["lang"] = langue;
// iş parçacığının kültürleri değiştiriliyor
Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo(langue);
Thread.CurrentThread.CurrentUICulture = Thread.CurrentThread.CurrentCulture;
}
}
}
- 7. satır: [I18NController], [Controller] sınıfından türetilmiştir;
- 7. satır: Sınıf, doğrudan örneklenmesini önlemek için [abstract] olarak tanımlanmıştır: kullanılabilmesi için mutlaka türetilmesi gerekir;
- 9. satır: Sınıfın oluşturucusu – [I18NController] sınıfından türetilen bir denetleyicinin her örneklendirilmesinde çalıştırılacaktır;
- 12. satır: Denetleyici tarafından işlenmekte olan HTTP isteğinin bağlamı alınır;
- satır 15: dilin, farklı yerlerde bulunabilen bir [lang] parametresiyle belirlendiği varsayılır. Sırasıyla şu yerlerde aranır:
- 15. satır: URL ve [?lang=en-US] parametrelerinde,
- 19. satır: gönderilen [lang=de] parametrelerinde,
- 24. satır: kullanıcı oturumunda,
- 29. satır: HTTP istemcisi tarafından gönderilen dil tercihlerinde,
- 26. satır: hiçbir şey bulunamazsa, kültür [fr-FR] olarak ayarlanır;
- satır 37: kültür, oturumda kaydedilir. Sonraki isteklerde buradan alınacaktır. Kullanıcı, GET veya POST komutunun parametrelerine girerek bunu değiştirebilir;
- 39-40. satırlar: Mevcut isteğin işlenmesi tamamlandıktan sonra görüntülenecek görünümün dil ayarı belirlenir.
[SecondController] denetleyicisi şu şekilde olacaktır:
using Exemple_03.Models;
using Exemples.Controllers;
using System.Web.Mvc;
namespace Exemple_03.Controllers
{
public class SecondController : I18NController
{
// Eylem14-GET
[HttpGet]
public ViewResult Action14Get()
{
return View("Action14Get", new ViewModel14());
}
// Eylem14-POST
[HttpPost]
public ViewResult Action14Post(ViewModel14 modèle)
{
return View("Action14Get", modèle);
}
}
}
- 7. satır: [SecondController], [I18NController]'ten türetilmiştir. Böylece, görüntülenecek görünümün kültürünün başlatılmış olacağı garanti altına alınır;
- 13. satır: Daha sonra tanıtacağımız [ViewModel14] görünüm şablonu kullanılır;
- 13. ve 20. satırlar: [Action14Get.cshtml] görünümü, formun görüntülenmesini sağlar.
6.3. [ViewModel14] görünüm şablonunu uluslararası hale getirme
[ViewModel14] görünüm şablonu şu şekildedir:
![]() |
using Exemple_03.Resources;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Globalization;
using System.Net.Mail;
namespace Exemple_03.Models
{
public class ViewModel14 : IValidatableObject
{
[Required(ErrorMessageResourceType = typeof(MyResources), ErrorMessageResourceName = "infoRequise")]
[Display(ResourceType = typeof(MyResources), Name = "chaineaumoins4")]
[RegularExpression(@"^.{4,}$", ErrorMessageResourceType = typeof(MyResources), ErrorMessageResourceName = "infoIncorrecte")]
public string Chaine1 { get; set; }
[Display(ResourceType = typeof(MyResources), Name = "chaineauplus4")]
[Required(ErrorMessageResourceType = typeof(MyResources), ErrorMessageResourceName = "infoRequise")]
[RegularExpression(@"^.{1,4}$", ErrorMessageResourceType = typeof(MyResources), ErrorMessageResourceName = "infoIncorrecte")]
public string Chaine2 { get; set; }
[Required(ErrorMessageResourceType = typeof(MyResources), ErrorMessageResourceName = "infoRequise")]
[Display(ResourceType = typeof(MyResources), Name = "chaine4exactement")]
[RegularExpression(@"^.{4,4}$", ErrorMessageResourceType = typeof(MyResources), ErrorMessageResourceName = "infoIncorrecte")]
public string Chaine3 { get; set; }
[Required(ErrorMessageResourceType = typeof(MyResources), ErrorMessageResourceName = "infoRequise")]
[Display(ResourceType = typeof(MyResources), Name = "entier")]
public int Entier1 { get; set; }
[Display(ResourceType = typeof(MyResources), Name = "entierentrebornes")]
[Required(ErrorMessageResourceType = typeof(MyResources), ErrorMessageResourceName = "infoRequise")]
[Range(1, 100, ErrorMessageResourceType = typeof(MyResources), ErrorMessageResourceName = "infoIncorrecte")]
public int Entier2 { get; set; }
[Display(ResourceType = typeof(MyResources), Name = "reel")]
[Required(ErrorMessageResourceType = typeof(MyResources), ErrorMessageResourceName = "infoRequise")]
public double Reel1 { get; set; }
[Display(ResourceType = typeof(MyResources), Name = "reelentrebornes")]
[Required(ErrorMessageResourceType = typeof(MyResources), ErrorMessageResourceName = "infoRequise")]
[Range(10.2, 11.3, ErrorMessageResourceType = typeof(MyResources), ErrorMessageResourceName = "infoIncorrecte")]
public double Reel2 { get; set; }
[Display(ResourceType = typeof(MyResources), Name = "email")]
[Required(ErrorMessageResourceType = typeof(MyResources), ErrorMessageResourceName = "infoRequise")]
[EmailAddress(ErrorMessageResourceType = typeof(MyResources), ErrorMessageResourceName = "infoIncorrecte", ErrorMessage="")]
public string Email1 { get; set; }
[Display(ResourceType = typeof(MyResources), Name = "date1")]
[RegularExpression(@"\s*\d{2}/\d{2}/\d{4}\s*", ErrorMessageResourceType = typeof(MyResources), ErrorMessageResourceName = "infoIncorrecte")]
[Required(ErrorMessageResourceType = typeof(MyResources), ErrorMessageResourceName = "infoRequise")]
public string Regexp1 { get; set; }
[Display(ResourceType = typeof(MyResources), Name = "date2")]
[Required(ErrorMessageResourceType = typeof(MyResources), ErrorMessageResourceName = "infoRequise")]
[DataType(DataType.Date)]
public DateTime Date1 { get; set; }
// onay
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
// hata listesi
List<ValidationResult> résultats = new List<ValidationResult>();
// hepsi için aynı hata mesajı
string errorMessage=MyResources.ResourceManager.GetObject("infoIncorrecte", new CultureInfo(System.Web.HttpContext.Current.Session["lang"] as string)).ToString();
// Tarih 1
if (Date1.Date <= DateTime.Now.Date)
{
résultats.Add(new ValidationResult(errorMessage, new string[] { "Date1" }));
}
// E-posta 1
try
{
new MailAddress(Email1);
}
catch
{
résultats.Add(new ValidationResult(errorMessage, new string[] { "Email1" }));
}
// Regexp1
try
{
DateTime.ParseExact(Regexp1, "dd/MM/yyyy", CultureInfo.CreateSpecificCulture("fr-FR"));
}
catch
{
résultats.Add(new ValidationResult(errorMessage, new string[] { "Regexp1" }));
}
// hata listesi görüntüleniyor
return résultats;
}
}
}
Bu model, önceki [ViewModel11] modelinin uluslararasılaştırılmış halidir. İlk özelliğin ilk özniteliği için uluslararasılaştırma mekanizmasını açıklayacağız. Diğer öznitelikler de aynı mekanizmayı izler.
[Required(ErrorMessageResourceType = typeof(MyResources), ErrorMessageResourceName = "infoRequise")]
public string Chaine1 { get; set; }
Önceki [ViewModel11] modelinde bu satırlar şöyleydi:
[Required(ErrorMessage = "Information requise")]
public string Chaine1 { get; set; }
Uluslararasılaştırılmış sürümde, 1. satırda görüntülenecek metinler bir kaynak dosyasına yerleştirilmiştir. Burada bu dosyanın adı [MyResources.resx] (typeof) olup, projenin kök dizinine yerleştirilmiştir. Buna kaynak dosyası denir.
![]() |
Burada üç kaynak dosyası oluşturduk:
- [MyResources]: geçerli dil ayarı için kaynak bulunmadığında kullanılan varsayılan kaynak;
- [MyResources.fr-FR]: [fr-FR] yerel ayarı için kaynak;
- [MyResources.en-US]: [en-US] yerel ayarı için kaynak;
Bir kaynak dosyası oluşturmak için şu adımlar izlenir: [1, 2, 3]:
![]() |
![]() |
Bu işlem, [MyResources2.resx] kaynak dosyasını oluşturur. Dosyaya çift tıkladığınızda şu sayfa açılır:
![]() |
Bir kaynak dosyası, anahtarlar ve bu anahtarlara atanan değerlerden oluşan bir sözlüktür. Anahtar [1], değer [2], kaynağın kapsamı ise [3] olarak girilir. Bu kaynakların okunabilir olması için [Public] kapsamına sahip olmaları gerekir. Şu satıra geri dönelim:
[Required(ErrorMessageResourceType = typeof(MyResources), ErrorMessageResourceName = "infoRequise")]
- [ErrorMessageResourceType]: kaynak dosyasını belirtir. [typeof] parametresi dosya adıdır. Bu, derleme süreciyle bir sınıfa dönüştürülür ve ikili dosyası projenin derlemesine dahil edilir. Dolayısıyla sonuç olarak [MyResources], kaynak sınıfının adıdır;
- [ErrorMessageResourceName = "infoRequise"]: kaynak dosyasındaki bir anahtarı belirtir. Sonuç olarak, bu satır, görüntülenecek hata mesajının [infoRequise] anahtarına atanan [MyResources] dosyasının değeri olduğunu ifade eder.
[infoRequise] anahtarını ve [MyResources] dosyasında buna ilişkin değeri oluşturmak için aşağıdaki adımları izleyin:
![]() |
Anahtarı [1], değeri [2] ve kaynağın kapsamını [3] olarak girin.
Açıklığa kavuşturulması gereken son bir nokta daha var: [MyResources] sınıfının ad alanı. Bu, [MyResources.resx] dosyasının özelliklerinde tanımlanmıştır:
![]() |
[1] dosyasında, [MyResources.resx] kaynak dosyasından oluşturulacak [MyResources] sınıfının ad alanını tanımlıyoruz. İncelediğimiz uluslararasılaştırılmış satıra geri dönelim:
[Required(ErrorMessageResourceType = typeof(MyResources), ErrorMessageResourceName = "infoRequise")]
typeof operatörü bir sınıf bekler; burada bu sınıf [MyResources]'tir. Bu sınıfın bulunabilmesi için, ad alanının [ViewModel14] sınıfına içe aktarılması gerekir:
using Exemple_03.Resources;
[MyResources] sınıfının görünür olması için, [MyResources] kaynak dosyasının oluşturulmasından bu yana projenin en az bir kez derlenmiş olması gerekir. Bu sınıfın kodu, [MyResources.Designer.cs] dosyasında görülebilir:
Bu dosyaya çift tıklandığında, [MyResources] sınıfının koduna erişilir:
namespace Exemple_03.Resources {
using System;
[global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
[global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
[global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
public class MyResources2 {
...
public static string infoRequise {
get {
return ResourceManager.GetString("infoRequise", resourceCulture);
}
}
}
}
- 1. satır: sınıfın ad alanı;
- 11. satır: [infoRequise] anahtarı, [MyResources] sınıfının statik bir özelliği haline gelmiştir. Bu özelliğe [MyResources.infoRequise] notasyonu ile erişilebilir. Ayrıca, bu özelliğin kapsamının [public] olduğu unutulmamalıdır. Aksi takdirde bu özelliğe erişilemez. Bunu hatırlamakta fayda var, çünkü ne yazık ki varsayılan kapsam [internal]'tir ve bu kapsamı değiştirmeyi unutursanız anlaşılması zor hatalara neden olur.
Peki neden şimdi üç kaynak dosyası var?
[MyResources.resx] dosyasını oluşturduk. Bu, kök kaynaktır. Ardından, yönetilecek yerel ayar (dil) sayısı kadar [MyResources.locale.resx] kaynak dosyası oluşturuyoruz. Burada Fransızca [fr-FR] ve Amerikan İngilizcesi [en-US]'i yönetiyoruz. Geçerli dil [fr-FR] veya [en-US] olmadığında, kök kaynak olan [MyResources.resx] kullanılır.
[MyResources.resx]'in nihai içeriği şöyledir:
![]() |
Yerel ayar tanınmadığında mesajlar Fransızca olacaktır. [MyResources.fr-FR.resx] dosyasının nihai içeriği aynıdır ve dosyanın basitçe kopyalanmasıyla elde edilir.
[MyResources.en-US.resx] dosyasının nihai içeriği de dosya kopyalanarak elde edilir ve ardından şu şekilde değiştirilir:
![]() |
[ViewModel14] görünümüne ve [Validate] yöntemine geri dönelim:
// doğrulama
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
// hata listesi
List<ValidationResult> résultats = new List<ValidationResult>();
// hepsi için aynı hata mesajı
string errorMessage=MyResources.ResourceManager.GetObject("infoIncorrecte", new CultureInfo(System.Web.HttpContext.Current.Session["lang"] as string)).ToString();
// Tarih 1
if (Date1.Date <= DateTime.Now.Date)
{
résultats.Add(new ValidationResult(errorMessage, new string[] { "Date1" }));
}
...
// hata listesi görüntüleniyor
return résultats;
}
7. satır, [MyResources] kaynak dosyasından bir mesajın nasıl alınacağını göstermektedir. Burada, [infoIncorrecte] anahtarıyla ilişkili mesajı, o andaki kültürde almak istiyoruz:
- MyResources.ResourceManager.GetObject("infoIncorrecte", new CultureInfo("en-US")) : [MyResources.en-US.resx] kaynak dosyasında [infoIncorrecte] anahtarıyla ilişkili nesneyi alır;
- [I18NController] denetleyicisinin, [lang] anahtarıyla ilişkili oturuma geçerli kültürü ayarladığını görmüştük. Dolayısıyla geçerli kültür, System.Web.HttpContext.Current.Session["lang"] as string ile alınabilir;
- kaynak, [object] türüyle alınır. Hata mesajını almak için, ona [ToString] yöntemi uygulanır.
6.4. [Action14Get.cshtml] görünümünü uluslararası hale getirme
Formun görüntülenmesini şu şekilde değiştiriyoruz:
![]() |
@model Exemple_03.Models.ViewModel14
@using Exemple_03.Resources
@{
Layout = null;
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>Action14Get</title>
<link rel="stylesheet" href="~/Content/Site.css" />
<script type="text/javascript" src="~/Scripts/jquery-1.8.2.min.js"></script>
<script type="text/javascript" src="~/Scripts/jquery.validate.min.js"></script>
<script type="text/javascript" src="~/Scripts/jquery.validate.unobtrusive.min.js"></script>
<script type="text/javascript" src="~/Scripts/globalize/globalize.js"></script>
<script type="text/javascript" src="~/Scripts/globalize/cultures/globalize.culture.fr-FR.js"></script>
<script type="text/javascript" src="~/Scripts/globalize/cultures/globalize.culture.en-US.js"></script>
<script type="text/javascript" src="~/Scripts/myscripts2.js"></script>
<script>
$(document).ready(function () {
var culture = '@System.Threading.Thread.CurrentThread.CurrentCulture';
Globalize.culture(culture);
});
</script>
</head>
<body>
<h3>Formulaire ASP.NET MVC - Internationalisation</h3>
@using (Html.BeginForm("Action14Post", "Second"))
{
<table>
<thead>
<tr>
<th>@MyResources.type</th>
<th>@MyResources.value</th>
<th>@MyResources.error</th>
</tr>
</thead>
<tbody>
<tr>
<td>@Html.LabelFor(m => m.Chaine1)</td>
<td>@Html.EditorFor(m => m.Chaine1)</td>
<td>@Html.ValidationMessageFor(m => m.Chaine1)</td>
</tr>
...
</tbody>
</table>
<p>
<input type="submit" value="Valider" />
</p>
}
</body>
</html>
<!-- dil seçimi -->
@using (Html.BeginForm("Lang", "Second"))
{
<table>
<tr>
<td><a href="javascript:postForm('fr-FR','/Second/Action14Get')">Français</a></td>
<td><a href="javascript:postForm('en-US','/Second/Action14Get')">English</a></td>
</tr>
</table>
}
Not: 14. satırda, jQuery sürümünü kendi Visual Studio sürümünüze göre uyarlayın.
En basit olan 36-38. satırlarla başlayalım. Bu satırlar, az önce açıkladığımız [MyResources] sınıfının statik özelliklerini kullanır. [MyResources] sınıfına erişmek için, bu sınıfın ad alanını içe aktarmanız gerekir (2. satır).
Uluslararasılaştırılmış mesajlarda, istemci tarafındaki doğrulama çerçevesinin görüntülediği mesajlar da dikkate alınmalıdır. Bunun için 17-19. satırlardaki JQuery kütüphanelerini kullanmak gerekir. Yönettiğimiz iki dil için JQuery dosyalarını kullanıyoruz: [fr-FR] ve [en-US]. Ayrıca, [Action13Get] görünümünün aşağıdaki [myscripts.js] JavaScript betiğini kullandığını hatırlayabilirsiniz:
// belge yüklenirken
$(document).ready(function () {
var culture = 'fr-FR';
Globalize.culture(culture);
});
Artık veri kaynağı sadece [fr-FR] değil, değişkenlik gösteriyor. Bu nedenle bu satırlar artık 21-26. satırlarda [Action14Get] görünümü tarafından üretilmektedir. Bu altı satır, müşteriye gönderilen HTML sayfasına dahil edilecektir.
- 23. satır: [culture] adlı JavaScript değişkeni, işlenmekte olan isteğin iş parçacığının geçerli kültürüyle başlatılır. Hatırlanacağı üzere, bu değişken [I18NController] sınıfının oluşturucusu tarafından başlatılmıştı:
// dil oturuma kaydediliyor
httpContext.Session["lang"] = langue;
// iş parçacığının kültürleri değiştiriliyor
Thread.CurrentThread.CurrentCulture = new System.Globalization.CultureInfo(langue);
Thread.CurrentThread.CurrentUICulture = Thread.CurrentThread.CurrentCulture;
Geçerli kültür [en-US] ise, HTML sayfasına gömülü JavaScript betiği şu şekilde olur:
<script>
$(document).ready(function () {
var culture = 'en-US';
Globalize.culture(culture);
});
</script>
Daha önce, [$(document).ready] işlevinin, tarayıcı tarafından sayfanın yüklenmesi tamamlandığında çalıştırıldığı belirtilmişti. Bu işlevin çalıştırılması, istemci tarafındaki doğrulama çerçevesinin dil ayarını belirleyecektir. [en-US] dil ayarıyla, çerçevenin hata mesajları İngilizce olacak ve [MyResources.en-US.resx] kaynak dosyasından alınacaktır. Bunun nasıl olduğunu göreceğiz.
Şimdi 57-65. satırları inceleyelim:
<!-- dil seçimi -->
@using (Html.BeginForm("Lang", "Second"))
{
<table>
<tr>
<td><a href="javascript:postForm('fr-FR','/Second/Action14Get')">Français</a></td>
<td><a href="javascript:postForm('en-US','/Second/Action14Get')">English</a></td>
</tr>
</table>
}
Burada ikinci bir form var; ilki 31-53. satırlarda yer alıyor. Bu form, sayfanın altında şu bağlantıları görüntülüyor:
![]() |
- 2. satır: Form, [Second] denetleyicisinin [Lang] eylemine gönderilir. Şu an için gönderilebilecek herhangi bir değer görünmüyor;
- 6. ve 7. satırlar: Bağlantılara tıklandığında [postForm] adlı JavaScript işlevi çalıştırılır. Bu işlev nerede bulunur? Görünümün 20. satırında referans verilen [myscripts2.js] komut dosyasında:
![]() |
İçeriği şöyledir:
function postForm(lang, url) {
// belgedeki ikinci form alınır
var form = document.forms[1];
// forma gizli lang özniteliği eklenir
var hiddenField = document.createElement("input");
hiddenField.setAttribute("type", "hidden");
hiddenField.setAttribute("name", "lang");
hiddenField.setAttribute("value", lang);
// formda gizli alan ekleniyor
form.appendChild(hiddenField);
// gizli url özniteliği ekleniyor
var hiddenField = document.createElement("input");
hiddenField.setAttribute("type", "hidden");
hiddenField.setAttribute("name", "url");
hiddenField.setAttribute("value", url);
// formda gizli alan eklenir
form.appendChild(hiddenField);
// gönderme
form.submit();
}
// http://blog.instance-factory.com/?p=268
$.validator.methods.number = function (value, element) {
return this.optional(element) ||
!isNaN(Globalize.parseFloat(value));
}
$.validator.methods.date = function (value, element) {
return this.optional(element) ||
!isNaN(Globalize.parseDate(value));
}
jQuery.extend(jQuery.validator.methods, {
range: function (value, element, param) {
//Değeri ayrıştırmak için Globalization eklentisini kullanın
var val = Globalize.parseFloat(value);
return this.optional(element) || (
val >= param[0] && val <= param[1]);
}
});
22-40. satırlar, önceki örnekte kullanılan [myscripts.js] betiğinde zaten mevcut olan satırlardır. Bunlara tekrar değinmeyeceğiz. Dil bağlantılarına tıklandığında çalıştırılan [postForm] işlevi 1-20. satırlarda yer almaktadır:
- 1. satır: İşlev iki parametre kabul eder; [lang], kullanıcı tarafından seçilen kültürdür; [url] ise kültür değişikliği gerçekleştirildikten sonra istemci tarayıcısının yönlendirilmesi gereken URL adresidir. Bu iki parametre, çağrı sırasında belirtilir:
<td><a href="javascript:postForm('fr-FR','/Second/Action14Get')">Français</a></td>
<td><a href="javascript:postForm('en-US','/Second/Action14Get')">English</a></td>
- 3. satır: belgenin ikinci formundan bir referans alınır;
- 5-8. satırlar: programlama yoluyla
etiketini programlama yoluyla oluşturulur; burada [xx-XX], fonksiyonun [lang] parametresinin değeridir;
- 10. satır: yine programlama yoluyla bu etiketi ikinci forma eklenir. Sonuç olarak, her şey sanki bu etiket başından beri ikinci formda varmış gibi gerçekleşir. Dolayısıyla değeri gönderilecektir. İstediğimiz de buydu;
- 11-17. satırlar: Aynı mekanizmayı bir etiket için tekrarlıyoruz
için aynı mekanizmayı tekrarlarız; burada [url], fonksiyonun [url] parametresinin değeridir;
- 19. satır: İkinci form artık gönderildi. Hangi URL değerine?
[Action14Get.cshtml] sayfasındaki ikinci formun koduna geri dönmeliyiz:
@using (Html.BeginForm("Lang", "Second"))
{
...
}
Dolayısıyla form, URL [/Second/Lang] adresine gönderiliyor. Bu durumda, [SecondController] denetleyicisinde bir [Lang] eylemi tanımlamamız gerekiyor. Bu eylem şu şekilde olacaktır:
public class SecondController : I18NController
{
// Eylem14-GET
[HttpGet]
public ViewResult Action14Get()
{
return View("Action14Get", new ViewModel14());
}
// Eylem14-POST
[HttpPost]
public ViewResult Action14Post(ViewModel14 modèle)
{
return View("Action14Get", modèle);
}
// dil
[HttpPost]
public RedirectResult Lang(string url)
{
// istemciyi URL'ye yönlendirir
return new RedirectResult(url);
}
}
- 18. satır: eylem yalnızca bir [POST]'e yanıt verir;
- 19. satır: Yalnızca [url] adlı parametreyi alır;
- 22. satır: müşteriye bu URL adresine yönlendirilmesi için yanıt verir.
Peki, [lang] adlı parametreye ne oldu? Şimdi, [SecondController] denetleyicisinin [I18NController] sınıfından türediğini hatırlamamız gerekir (aşağıdaki 1. satır). [lang] parametresini yöneten işte bu denetleyicidir:
public abstract class I18NController : Controller
{
public I18NController()
{
// geçerli isteğin bağlamı alınır
HttpContext httpContext = System.Web.HttpContext.Current;
// istek, [lang] parametresini aramak üzere incelenir
// URL parametreleri içinde aranır
string langue = httpContext.Request.QueryString["lang"];
if (langue == null)
{
// gönderilen parametreler içinde aranır
langue = httpContext.Request.Form["lang"];
}
if (langue == null)
{
// kullanıcının oturumunda aranır
langue = httpContext.Session["lang"] as string;
}
if (langue == null)
{
// HTTP başlığının 1. parametresi AcceptLanguages
langue = httpContext.Request.UserLanguages[0];
}
if (langue == null)
{
// fr-FR dil ayarı
langue = "fr-FR";
}
// dil, oturuma eklenir
httpContext.Session["lang"] = langue;
// iş parçacığının kültürleri değiştiriliyor
Thread.CurrentThread.CurrentCulture = new CultureInfo(langue);
Thread.CurrentThread.CurrentUICulture = Thread.CurrentThread.CurrentCulture;
}
İncelediğimiz örnekte, [lang] parametresi gönderilir. Dolayısıyla bu parametre 13. satırda bulunur, 31. satırda oturuma alınır ve 33-34. satırlarda geçerli iş parçacığının kültürünü güncellemek için kullanılır.
Peki bundan sonra ne olacak? Bağlantılara tekrar bakalım:
<td><a href="javascript:postForm('fr-FR','/Second/Action14Get')">Français</a></td>
<td><a href="javascript:postForm('en-US','/Second/Action14Get')">English</a></td>
Yönlendirme URL, [/Second/Action14Get]'tir. Dolayısıyla [Action14Get] eylemi yürütülür:
public class SecondController : I18NController
{
// Eylem14-GET
[HttpGet]
public ViewResult Action14Get()
{
return View("Action14Get", new ViewModel14());
}
...
}
Bundan önce, [I18NController] sınıfının oluşturucusu çalıştırılır:
public abstract class I18NController : Controller
{
public I18NController()
{
// geçerli isteğin bağlamını alıyoruz
HttpContext httpContext = System.Web.HttpContext.Current;
// isteği inceleyerek [lang] parametresini aranıyor
// URL parametrelerinde aranır
string langue = httpContext.Request.QueryString["lang"];
if (langue == null)
{
// gönderilen parametreler içinde aranır
langue = httpContext.Request.Form["lang"];
}
if (langue == null)
{
// kullanıcının oturumunda aranıyor
langue = httpContext.Session["lang"] as string;
}
if (langue == null)
{
// HTTP başlığının 1. parametresi AcceptLanguages
langue = httpContext.Request.UserLanguages[0];
}
if (langue == null)
{
// fr-FR dil ayarı
langue = "fr-FR";
}
// dil, oturuma eklenir
httpContext.Session["lang"] = langue;
// iş parçacığının kültürleri değiştiriliyor
Thread.CurrentThread.CurrentCulture = new CultureInfo(langue);
Thread.CurrentThread.CurrentUICulture = Thread.CurrentThread.CurrentCulture;
}
Bu sefer, [lang] parametresi oturumda 18. satırda bulunur. Değerinin [en-US] olduğunu varsayalım. Bu kültür, dolayısıyla isteğin yürütme iş parçacığının kültürü haline gelir (33-34. satırlar). [Action14Get] eylemine geri dönelim:
// Eylem14-GET
[HttpGet]
public ViewResult Action14Get()
{
return View("Action14Get", new ViewModel14());
}
- satırda, [ViewModel14] görünüm modelinin bir örneği oluşturulacak:
public class ViewModel14 : IValidatableObject
{
[Required(ErrorMessageResourceType = typeof(MyResources), ErrorMessageResourceName = "infoRequise")]
[Display(ResourceType = typeof(MyResources), Name = "chaineaumoins4")]
[RegularExpression(@"^.{4,}$", ErrorMessageResourceType = typeof(MyResources), ErrorMessageResourceName = "infoIncorrecte")]
public string Chaine1 { get; set; }
....
Mevcut iş parçacığının kültürü [en-US] olduğu için, [MyResources.en-US.resx] dosyası kullanılacaktır. Dolayısıyla hata mesajları İngilizce olacaktır.
[ViewModel14] şablonu örneklendiğinde, [Action14Get.cshtml] görünümü görüntülenir:
@model Exemple_03.Models.ViewModel14
@using Exemple_03.Resources
@using System.Threading
@{
Layout = null;
}
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<title>Action14Get</title>
...
<script>
$(document).ready(function () {
var culture = '@Thread.CurrentThread.CurrentCulture';
Globalize.culture(culture);
});
</script>
</head>
<body>
<h3>Formulaire ASP.NET MVC - Internationalisation</h3>
@using (Html.BeginForm("Action14Post", "Second"))
{
<table>
<thead>
<tr>
<th>@MyResources.type</th>
<th>@MyResources.value</th>
<th>@MyResources.error</th>
</tr>
</thead>
<tbody>
<tr>
...
</tr>
<tr>
Geçerli iş parçacığının kültürü [en-US] olduğu için, sayfanın 15-20. satırlarında yer alan gömülü komut dosyası şöyledir:
<script>
$(document).ready(function () {
var culture = 'en-US';
Globalize.culture(culture);
});
</script>
Bu, doğrulama çerçevesinin Amerikan formatlarıyla (tarih, para birimi, sayılar vb.) çalışmasını sağlar. Yine aynı nedenden ötürü, 30-32. satırlardaki mesajlar [MyResources.en-US.resx] kaynak dosyasından alınacak ve dolayısıyla İngilizce olacaktır.
6.5. Çalıştırma örnekleri
İşte birkaç çalışma örneği:
![]() |
- [1] dosyasında form Fransızca, [2] dosyasında ise İngilizce olarak yer almaktadır.
![]() |
- [3]'te, istemci tarafında hata mesajları artık İngilizce olarak görüntüleniyor.
Sayfanın kaynak koduna bakıldığında, bu hata mesajlarının sayfaya gömülü olduğu, dolayısıyla ASP.NET [Action14Get] görünümü ve [ViewModel14] şablonu tarafından oluşturulduğu görülmektedir:
<tr>
<td><label for="Reel1">Real number</label></td>
<td><input class="text-box single-line" data-val="true" data-val-number="The field Real number must be a number." data-val-required="Required data" id="Reel1" name="Reel1" type="text" value="0" /></td>
<td><span class="field-validation-valid" data-valmsg-for="Reel1" data-valmsg-replace="true"></span></td>
</tr>
<tr>
<td><label for="Reel2">Real number in range [10.2-11.3]</label></td>
<td><input class="text-box single-line" data-val="true" data-val-number="The field Real number in range [10.2-11.3] must be a number." data-val-range="Invalid data" data-val-range-max="11.3" data-val-range-min="10.2" data-val-required="Required data" id="Reel2" name="Reel2" type="text" value="0" /></td>
<td><span class="field-validation-valid" data-valmsg-for="Reel2" data-valmsg-replace="true"></span></td>
</tr>
6.6. Tarihlerin uluslararasılaştırılması
Uluslararasılaştırma karmaşık bir konudur. Bu nedenle, [Date1] özelliğine ve takvimine bir göz atalım:
![]() |
Takvimin Fransız takvimi olduğu görülürken, sayfanın kültürü [en-US]'tir. HTML5'te, sayfanın veya sayfanın bir bileşeninin dilini belirlemeye yarayan [lang] özniteliği bulunmaktadır. Bu durumda, [Action14Get.cshtml] görünümüne aşağıdaki kodu yazabiliriz:
@model Exemple_03.Models.ViewModel14
@using Exemple_03.Resources
@using System.Threading
@{
Layout = null;
var lang = Session["lang"] as string;
}
<!DOCTYPE html>
<html lang="@lang">
<head>
...
- 6. satır: oturumdan kültür bilgisi alınır;
- 11. satır: Sayfanın [lang] özniteliği bu değerle ayarlanır.
Testler, sayfa başka bir dilde (örneğin İngilizce) görüntülenirken bile takvimin Fransızca kaldığını göstermektedir. Formdaki diğer tarihle ilgili de bir sorun vardır:
![]() |
[1]'te tarih, Fransızca jj/mm/aaaa (20/11/2013) biçiminde istenmeye devam ederken, Amerikan biçimi mm/dd/yyyy (10/21/2013) şeklindedir. Bu iki sorunu yeni bir görünüm ve yeni bir görünüm şablonu ile çözmeye çalışacağız.
JQuery, UI, JQuery projesinden türetilmiş bir projedir ve formlar için takvim dahil çeşitli bileşenler sunar. Bu takvim uluslararası hale getirilebilir. Şimdi bunu göstereceğiz.
Başlangıç olarak, [JQuery UI]'i projemize ekleyelim.
![]() |
![]() |
JQuery ve UI kurulduktan sonra, projede yeni öğeler belirir:
![]() |
- [1] içinde, [JQuery UI] kütüphanesi normal ve minifiye edilmiş sürümleriyle;
- [2]'te, [JQuery UI] stil sayfası;
JQuery UI takvimi varsayılan olarak İngilizcedir. Uluslararası hale getirmek için, URL [https://github.com/jquery/jquery-ui/tree/master/ui/i18n] dosyasında bulunan komut dosyalarını eklemek gerekir:
![]() |
JQuery UI takvimini Fransızca olarak elde etmek için, yukarıdaki [jquery.ui.datepicker-fr.js] dosyasının içeriğini projenin [Scripts] klasörüne kopyalayınız.
![]() |
Yeni görünüm [Action15.cshtml]'in kodu, önceki görünüm [Action14.cshtml]'in kopyalanması ve ardından değiştirilmesi yoluyla elde edilir. Burada sadece yapılan değişiklikleri sunuyoruz:
![]() |
@model Exemple_03.Models.ViewModel15
@using Exemple_03.Resources
@using System.Threading
@{
Layout = null;
}
<!DOCTYPE html>
<html lang="@Model.Culture">
<head>
<meta name="viewport" content="width=device-width" />
<title>Action15</title>
...
<link rel="stylesheet" href="~/Content/themes/base/jquery-ui.css" />
<script type="text/javascript" src="~/Scripts/jquery-ui-1.10.3.js"></script>
<script type="text/javascript" src="~/Scripts/jquery.ui.datepicker-fr.js"></script>
<script>
$(document).ready(function () {
var culture = '@Thread.CurrentThread.CurrentCulture';
Globalize.culture(culture);
$("#Date1").datepicker($.datepicker.regional['@Model.Regionale']);
});
</script>
</head>
<body>
<h3>@MyResources.titre</h3>
@using (Html.BeginForm("Action15", "Second"))
{
<table>
...
<tr>
<td>@Html.LabelFor(m => m.Date1)</td>
<td>@Html.TextBox("Date1", Model.StrDate1)</td>
<td>@Html.ValidationMessageFor(m => m.Date1)</td>
</tr>
</tbody>
</table>
<p>
<input type="submit" value="Valider" />
</p>
}
<!-- dil seçimi -->
@using (Html.BeginForm("Lang", "Second"))
{
<table>
<tr>
<td><a href="javascript:postForm('fr-FR','/Second/Action15')">Français</a></td>
<td><a href="javascript:postForm('en-US','/Second/Action15')">English</a></td>
</tr>
</table>
}
</body>
</html>
Not: 16. satırda, jQuery-ui sürümünü indirdiğiniz sürüme göre uyarlayın.
- 15. satır: JQuery ve UI stil sayfalarına referans verilir;
- 16. satır: İndirdiğiniz JQuery ve UI sürümlerine referans verilir;
- 17. satır: Az önce indirdiğimiz Fransız takvim betiğine atıfta bulunulur;
- 34. satır: [Html.TextBox] yöntemi burada, [text] türünde, ID'si [Date1] ve adı [Date1] olan bir etiket oluşturacaktır;
- 19. satır: Sayfanın yüklenmesi tamamlandığında, JQuery UI [datepicker] işlevi, id'si [Date1] olan öğeye, yani 34. satırdaki öğeye uygulanacaktır. Bu işlev, kullanıcı [Date1] giriş alanına odaklandığında, tarih girebilmesi için bir takvimin görünmesini sağlar. [datepicker] işlevi, takvimin dilini belirten bir parametre kabul eder. [@Model.Regionale] değişkeninin değeri:
- Fransızca takvim için 'fr',
- İngilizce takvim için '';
Önceki görünüm şablonu [Action15.cshtml], aşağıdaki [ViewModel15] şablonu olacaktır:
![]() |
Bu şablonun kodu, [ViewModel14] şablonunun hafifçe değiştirilmiş halidir. Yalnızca yapılan değişiklikleri sunuyoruz:
using Exemple_03.Resources;
...
using System.Web;
namespace Exemple_03.Models
{
[Bind(Exclude = "Culture,Regionale,StrDate1,FormatDate")]
public class ViewModel15 : IValidatableObject
{
...
[Display(ResourceType = typeof(MyResources), Name = "date1")]
[RegularExpression(@"\s*\d{2}/\d{2}/\d{4}\s*", ErrorMessageResourceType = typeof(MyResources), ErrorMessageResourceName = "infoIncorrecte")]
[Required(ErrorMessageResourceType = typeof(MyResources), ErrorMessageResourceName = "infoRequise")]
public string Regexp1 { get; set; }
[Display(ResourceType = typeof(MyResources), Name = "date2")]
[Required(ErrorMessageResourceType = typeof(MyResources), ErrorMessageResourceName = "infoRequise")]
[DataType(DataType.Date)]
public DateTime Date1 { get; set; }
// oluşturucu
public ViewModel15()
{
// Geçerli kültür
Culture = HttpContext.Current.Session["lang"] as string;
cultureInfo=new CultureInfo(Culture);
// Takvim bölgesi JQuery
Regionale = MyResources.ResourceManager.GetObject("regionale", cultureInfo).ToString();
// tarih biçimi
FormatDate = MyResources.ResourceManager.GetObject("formatDate", cultureInfo).ToString();
}
// doğrulama
public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
{
// hata listesi
List<ValidationResult> résultats = new List<ValidationResult>();
// hepsi için aynı hata mesajı
string errorMessage = MyResources.ResourceManager.GetObject("infoIncorrecte", cultureInfo).ToString();
...
// Regexp1
try
{
DateTime.ParseExact(Regexp1, FormatDate, cultureInfo);
}
catch
{
résultats.Add(new ValidationResult(errorMessage, new string[] { "Regexp1" }));
}
// hata listesi görüntüleniyor
return résultats;
}
// eylem şablonunun dışındaki alanlar
public string Culture { get; set; }
public string Regionale { get; set; }
public string StrDate1 { get; set; }
public string FormatDate { get; set; }
// yerel veriler
private CultureInfo cultureInfo;
}
}
Önceki [ViewModel14] modeline kıyasla dört ek özellik bulunmaktadır:
- 60. satır: görünümün dil ayarı, 'fr-FR' veya 'en-US'. Bu dil ayarı, 26. satırdaki oluşturucuda başlatılır;
- 61. satır: JQuery takviminin bölgesel kültürü; Fransız takvimi için 'fr', İngilizce takvim için ''. Bu alan, oluşturucunun 29. satırında başlatılır;
- satır 63: satır 15'teki tarih biçimi: Fransız tarihi için 'dd/MM/yyyy', İngilizce tarihi için 'MM/dd/yyyy'. Bu alan, oluşturucunun 31. satırında başlatılır;
- 62. satır: [Date1] giriş alanında görüntülenecek karakter dizisi. Bu alan eylem tarafından başlatılacaktır;
- 47. satır: [Regexp1] tarihi artık geçerli kültür formatına göre doğrulanır.
[Regionale] ve [FormatDate] özelliklerinin değerleri, [MyResources] kaynak dosyalarında bulunur. Fransızca kaynak dosyaları [MyResources], [MyResources.fr-FR], [1] ve İngilizce kaynak dosyası [2] şu şekilde güncellenmiştir:
![]() |
Neredeyse hazırız. [SecondController] denetleyicisine [Action15] eylemini ekliyoruz:
// Eylem15
public ViewResult Action15(FormCollection formData)
{
// yöntem HTTP
string method = Request.HttpMethod.ToLower();
// şablon
ViewModel15 modèle = new ViewModel15();
if (method == "get")
{
modèle.StrDate1 = "";
}
else
{
TryUpdateModel(modèle, formData);
modèle.StrDate1 = modèle.Date1.ToString(modèle.FormatDate);
}
// görünüm ekranı
return View("Action15", modèle);
}
- 2. satır: [Action15] yöntemi, hem [GET] hem de [POST]'leri işler. İkinci durumda, gönderilen değerler [formData] parametresinden alınır;
- 5. satır: İsteğin HTTP yöntemini alırız;
- 7. satır: Görüntülenecek görünüm şablonu (form) oluşturulur;
- satır 8-11: [GET] komutu durumunda, [Date1] giriş alanı boş bir dize ile başlatılır;
- 12-16. satırlar: [POST] siparişi durumunda:
- 14. satır: şablon, kaydedilen değerlerle başlatılır;
- satır 15: [Date1] giriş alanı, geçerli kültür ayarlarına göre biçimlendirilmiş [Date1] değerini içeren bir karakter dizisiyle başlatılır; Fransız tarihi için [dd/MM/yyyy], [MM/dd/yyyy];
- 18. satır: [Action15.cshtml] görünümü, şablonuyla birlikte görüntülenir.
Testler yapalım:
![]() |
- [1] olarak, sayfa Fransızca olduğunda bir Fransız takvimi;
- [2], sayfa İngilizce olduğunda İngilizce takvim;
- [3], sayfa Fransızca olduğunda Fransızca tarih biçimi;
- [4], sayfa İngilizce olduğunda aynı tarihin İngilizce biçiminde;
6.7. Conclusion
Anlaşıldığı üzere, bir uygulamanın uluslararasılaştırılması karmaşık bir konudur...
































