Ana Sayfa Microsoft .NETAsp.Net ASP.NET Core ile Çoklu Dil Desteği Olan Uygulamalar Geliştirmek

ASP.NET Core ile Çoklu Dil Desteği Olan Uygulamalar Geliştirmek

by Sinan BOZKUŞ
28.420 kez okundu

Web sitelerimizi daha fazla kitleye ulaştırabilmek veya daha fazla ziyaret alabilmek gibi farklı sebeplerle çoklu dil desteği gerektiren yapılara ihtiyaç duyabilmekteyiz. Bu makale de günümüzde neredeyse standart hale gelen çoklu dil destekli web sitelerinin ASP.NET Core ile birlikte nasıl yapıldığını öğreneceğiz.

Örnekler ve uygulamalar ASP.NET Core 2.x sürümlerini destekleyecek şekilde olacaktır.

ASP.NET Core içerisinde Localization desteğini kullanabilmek için “Microsoft.AspNetCore.Mvc.Localization” sınıfına kütüphanesine ihtiyaç duymaktayız. İlgili kütüphane “Microsoft.AspNetCore.Mvc” içerisinde yer aldığından ayrıca referans vermemize gerek yoktur.

İlk iş olarak “Startup.cs” dosyası altında bulunan “ConfigureServices” metodu içerisinde gerekli sınıflarımızı kayıt etmemiz gerekiyor. Uygulamamız çalışmaya başladığında ilgili sınıflar burada belirtilen şekilde oluşturulacaktır.

Not: Anlatılan konudan bağımsız olduğu için ConfigureServices detaylarına bu makalede girmeyeceğiz, merak edenler ASP.NET Core Dependency Injection olarak araştırabilirler.

[csharp]
// Kayıt işlemimizi gerçekleştiriyoruz, AddMvc() den önce eklediğinizden emin olunuz.
services.AddLocalization(options =>
{
// Resource (kaynak) dosyalarımızı ana dizin altında “Resources” klasorü içerisinde tutacağımızı belirtiyoruz.
options.ResourcesPath = “Resources”;
});

services.AddMvc();
[/csharp]

Kayıt işlemimizi tamamlandıktan sonra yine “Startup.cs” altında bulunan “Configure” metodu içerisinde dil desteğimizin ne şekilde çalışacağını ve hangi dillere destek vereceğimizi tanımlıyoruz. Bu metod çalışma zamanında (runtime) çalışır ve gelen HTTP istekleriyle ilgili yapılandırmalara izin verir.

Dil tanımlamalarımızı yaparken Türkçe ve İngilizce dillerine destek vereceğiz. Varsayılan dil tanımlamamız ise Türkçe olacaktır.

[csharp]
// Bu bölüm UseMvc()’ den önce eklenecektir.
// Uygulamamız içerisinde destek vermemizi istediğimiz dilleri tutan bir liste oluşturuyoruz.
var supportedCultures = new List<CultureInfo>
{
new CultureInfo(“tr-TR”),
new CultureInfo(“en-US”),
};
// SupportedCultures ve SupportedUICultures’a yukarıda oluşturduğumuz dil listesini tanımlıyoruz.
// DefaultRequestCulture’a varsayılan olarak uygulamamızın hangi dil ile çalışması gerektiğini tanımlıyoruz.
app.UseRequestLocalization(new RequestLocalizationOptions
{
SupportedCultures = supportedCultures,
SupportedUICultures = supportedCultures,
DefaultRequestCulture = new RequestCulture(“tr-TR”)
});
[/csharp]

CultureInfo ve RequestCulture sınıfları için aşağıdaki namespace lerin ekli olduğundan emin olun.

[csharp]
using System.Globalization;
using Microsoft.AspNetCore.Localization;
[/csharp]

Not: Uygulamalarınızda İngilizce diline destek verecekseniz “en-US” kullanımının Amerikan İngilizcesini, “en-GB” kullanımının ise İngiliz İngilizcesini belirttiğini unutmayınız.

Dil desteğiyle ilgili tanımlamalarımızı yaptıktan sonra şimdi ilgili metinleri tutacağımız dil dosyalarımızı oluşturabiliriz. Bunun için uygulamamızın ana dizininde “Resources” adında yeni bir klasör oluşturuyoruz. Bu klasör adını “Startup.cs” dosyasındaki “ConfigureServices” altında belirtmiştik. İsimlendirme konusunda özgürüz.

Uygulama içerisinde ek bir Controller veya View oluşturmayacağız, yeni bir ASP.NET Core 2.x projesi oluşturduğumuzda içerisinde varsayılan olarak gelen “HomeController.cs” ve bunun View dosyalarından faydalanacağız.

Not: VS 2019 Update’i ile birlikte Contact action’ı varsayılan olarak gelmemektedir. HomeController.cs içerisinde Contact adında bir action ve buna karşılık bir View oluşturabilirsiniz.

Controller İçerisinden Dil Dosyalarının Kullanımı

İlk olarak “HomeController.cs” içerisinde bulunan “Contact” isimli Action’dan başlayacağız. Buradaki ViewData[“Message”]‘ı kullanıcının seçmiş olduğu dil değerine göre getireceğiz. Bunun için az önce oluşturduğumuz “Resources” klasörü altına “Controllers.HomeController.tr-TR.resx” ve “Controllers.HomeController.en-US.resx” şeklinde iki tane resource dosyası oluşturuyorum. (“Resources” klasörüne sağ tıklayıp “Add New Item” dedikten sonra “Resources File” ı seçmeniz gerekmektedir.)

Dosya adlarını isteğimize bağlı olarak iki farklı şekilde oluşturabiliriz. Biz örneğimizde noktalı şekilde kullanacağız.

Resource Dosyası Adı Noktalı veya Klasör Olarak Adlandırma
Resources/Controllers.HomeController.tr-TR.resx Noktalı şekilde
Resources/Controllers/HomeController.tr-TR.resx Klasör yolu belirterek

Oluşturmuş olduğumuz her iki resource dosyası içerisine de “Message” adında bir anahtar ekliyoruz ve değerlerine Türkçe için “İletişim sayfanız.”, İngilizce için ise “Your contact page.” yazıyoruz.

Controllers.HomeController.tr-TR.resx

Controllers.HomeController.en-US.resx

Resource dosyalarıyla ilgili işlemlerimiz tamamlandı. Şimdi oluşturduğumuz bu resource dosyalarımızı uygulamamızda kullanalım.

“HomeController.cs” dosyasına geliyoruz ve burada bir localizer oluşturacağız. Oluşturacağımız bu localizer IStringLocalizer tipinde olacak ve kullanmak istediğimiz Controller’ı içine gönderip bize ilgili resource dosyasındaki değerlerin gelmesini sağlayacağız. Bu localizer’ı oluştururken dependency injection’dan yararlanıp constructor injection yapacağız.

Aşağıdaki kodları Controller’ımızın hemen üst kısmına ekliyoruz.

[csharp]

private readonly IStringLocalizer<HomeController> _localizer;

public HomeController(IStringLocalizer<HomeController> localizer)
{
_localizer = localizer;
}

[/csharp]

Kodların aşağıdaki şekilde görünmesi gerekiyor.

_localizer nesnemizi ürettiğimize ve bunu dependency injection yöntemi ile dolduruğumuza göre artık bu nesneyi kullanabiliriz.

Contact isimli Action’ımıza geliyoruz ve buradaki ViewData[“Message”] mesajının içeriğini dil dosyamızdan (resource) çekiyoruz. Bunun için ister “_localizer[“Message”]” şeklinde isterseniz “_localizer.GetString(“Message”)” şeklinde kullanabiliriz. Localizer içerisinde tanımladığımız “Message” anahtarı Resources dosyamızdaki Message anahtarına karşılık geliyor. ViewData içerisinde kullandığımız Message ile bir bağlantısı bulunmamakta.

Contact Action’ımızı aşağıdaki şekilde düzenliyoruz.

[csharp]
public IActionResult Contact()
{
//ViewData[“Message”] = _localizer[“Message”];
ViewData[“Message”] = _localizer.GetString(“Message”);

return View();
}
[/csharp]

Uygulamamızı çalıştırıyoruz ve menüden Contact’a tıklayarak ilgili sayfaya gidiyoruz. Karşımıza bilgisayarınızın diline göre bir karşılama mesajı gelecektir.

Şimdi dil desteğimizin çalıştığından emin olalım ve sayfamızı iki farklı şekilde çağıralım.

http://localhost:53218/Home/Contact?culture=tr-TR

http://localhost:53218/Home/Contact?culture=en-US

53218 yerine uygulamanızın çalıştığı port değerini yazmanız gerekmektedir.

Uygulamanızı bu şekilde çağırdığınızda QueryString ile belirtmiş olduğunuz culture değerine göre mesajın değiştiğini göreceksiniz.

Aşağıdaki QueryString tanımlamalarını da kullanabilirsiniz.

[html]
?culture=tr-TR
?ui-culture=tr-TR
?culture=tr-TR&ui-culture=tr-TR
[/html]

Buraya kadar öğrendiklerimiz her bir Controller dosyası için bir dil dosyası (resource) oluşturmak şeklindeydi. “Kaydet”, “İptal” gibi uygulamamızın her alanında kullandığımız genel tanımlamalar için ise paylaşılan bir dil dosyasına (resource) ihtiyacımız olacak. Bunun için Models klasörü altına “SharedResources.cs” şeklinde dummy (yapmacık) bir class oluşturuyoruz. Uygulamanızın yapısına göre farklı bir klasör altında da oluşturabiliriz. Bu class’a karşılık yine Resources klasörü altında bir dil dosyası (resource) oluşturuyoruz. Class’ımızı “Models” klasörü altına koyduğumuzdan dil dosyamızın adı “Models.SharedResource.tr-TR.resx” şeklinde olacak.

Bundan sonrasında dil dosyalarımıza ulaşmak için HomeController.cs içerisinde IStringLocalizer<HomeController>‘ı nasıl kullandıysak aynı şekilde IStringLocalizer<SharedResources>‘ ı kullanabiliriz.

Dil dosyaları içerisinde tutmuş olduğunuz metinler HTML formatında ise IStringLocalizer yerine IHtmlLocalizer tercih etmemiz gerekmektedir.

Viewler (Arayüzler) İçerisinden Dil Dosyalarının Kullanımı

Aynı Controllerlarda olduğu gibi Viewlerimiz için de dil dosyaları (resourcelar) kullanarak birden fazla dil destekleyen arayüzler hazırlayabiliriz.

“Startup.cs” dosyamıza gelerek “ConfigurationServices” metodu altında AddMvc()‘yi bulup sonuna gerekli kodları ekliyoruz.

[csharp]
// ViewLocalization desteğinin eklenmesini ve bunun da format olarak sonuna eklenecek yapıda olacağını belirtiyoruz.
services.AddMvc().AddViewLocalization(LanguageViewLocationExpanderFormat.Suffix)
[/csharp]

Viewler içerisinde localizer kullanabilmek için “Views” klasörü altındaki “_ViewImports.cshtml” dosyasına aşağıdaki “Microsoft.AspNetCore.Mvc.Localization” namespace’ini ekleyip inject (dependency injection) ile bir localizer nesnesi oluşturmamız gerekiyor.

[csharp]
@using Microsoft.AspNetCore.Mvc.Localization
@inject IViewLocalizer Localizer
[/csharp]

Viewlerimiz için dil dosyalarımızı (resource) aynı Controllerlarda olduğu gibi iki farklı şekilde oluşturabiliyoruz. İster noktalı istersek dizin yapısını tercih edebiliyoruz.

Resource Dosyası Adı Noktalı veya Klasör Olarak Adlandırma
Resources/Views.Home.Contact.tr-TR.resx Noktalı şekilde
Resources/Views/Home/Contact.tr-TR.resx Klasör yolu belirterek

Resources klasörü altında “Views.Home.Contact.tr-TR.resx” ve “Views.Home.Contact.en-US.resx” isimlerinde iki tane dil dosyası (resource) oluşturuyoruz.

Dil dosyalarımızın içerisine “Merhaba” anahtarıyla aşağıdaki metinleri ekliyoruz.

Views.Home.Contact.tr-TR.resx

Views.Home.Contact.en-US.resx


Contact.cshtml view dosyamıza geliyoruz ve içerisine “@Localizer[“Merhaba”]” şeklinde metni çağırıyoruz. Mevcut culture değerimize göre ilgili metin dil dosyalarından okunacaktır.

[csharp]@Localizer[“Merhaba”][/csharp]

Dil Seçeneklerine Göre Farklı Viewler (Arayüzler) Oluşturmak

Bir diğer alternatif olarak resource dosyaları ile uğraşmak istemiyorsak veya proje yapımız buna uygun değilse her dil için ayrı viewler de oluşturabiliriz. Bunun için View dizin yapımızın aşağıdaki şekilde olması gerekmektedir.

Dillere Göre Data Annotations Yapısını Kullanmak

Data Annotationslar ile birlikte dil desteği kullanabilmek için “Startup.cs” içerisindeki “ConfigureServices” metodunda bulunan AddMvc()’ye .”AddDataAnnotationsLocalization()” eklememiz gerekmektedir. İlgili kodu ekledikten sonra aşağıdaki gibi görünmesi gerekmektedir.

[csharp]
services.AddMvc()
.AddViewLocalization(LanguageViewLocationExpanderFormat.Suffix)
.AddDataAnnotationsLocalization();
[/csharp]

“HomeController.cs” içerisinde bulunan “Contact” sayfamız için örnek bir iletişim formu hazırlayacağız.

“Models” klasorü içerisinde “ContactFormViewModel.cs” adında yeni bir class oluşturuyoruz. İçeriği aşağıdaki şekilde olacaktır.

[csharp]
using System.ComponentModel.DataAnnotations;

namespace ASPNETCore_Localization.Models
{
public class ContactFormViewModel
{
[Display(Name = “Ad Soyad”)]
[Required(ErrorMessage = “{0} gereklidir.”)]
public string AdSoyad { get; set; }

[Display(Name = “Mesaj”)]
[Required(ErrorMessage = “{0} gereklidir.”)]
public string Mesaj { get; set; }
}
}
[/csharp]

Burada Name ve Message alanlarının ekranda görünen label değerleri için “Display” attribute’ünden, boş geçilememesi için ise “Required” attribute’ünden faydalandık. Hata mesajlarını ise açık bir şekilde Türkçe olarak yazdık.

Dil dosyalarımızı oluşturmak için yine “Resources” klasörümüze geliyoruz. “Models.ContactFormViewModel.en-US.resx”şeklinde yeni bir dil dosyası oluşturuyoruz ve içerisine ilgili metinlerin İngilizce karşılıklarını yazıyoruz.

“Views” klasörümüzün altına geliyoruz ve “Contact.cshtml” e aşağıdaki HTML kodlarını ekliyoruz.

[html]
@model ContactFormViewModel

<form class=”form-horizontal” method=”post” action=”Kaydet”>
<div class=”form-group”>
<label class=”col-sm-2 control-label” asp-for=”AdSoyad”></label>
<div class=”col-sm-10″>
<input type=”text” class=”form-control” asp-for=”AdSoyad”>
<span asp-validation-for=”AdSoyad”></span>
</div>
</div>
<div class=”form-group”>
<label class=”col-sm-2 control-label” asp-for=”Mesaj”></label>
<div class=”col-sm-10″>
<input type=”text” class=”form-control” asp-for=”Mesaj”>
<span asp-validation-for=”Mesaj”></span>
</div>
</div>
<div class=”form-group”>
<div class=”col-sm-offset-2 col-sm-10″>
<button type=”submit” class=”btn btn-default”>Kaydet</button>
</div>
</div>
</form>
[/html]

Şimdi formuzun gönderileceği Action’ı hazırlamamız gerekiyor. Bunun için “HomeController.cs” dosyasına aşağıdaki kodları ekliyoruz.

[csharp]
[HttpPost]
public IActionResult Kaydet(ContactFormViewModel viewModel)
{
return View(“Contact”, viewModel);
}
[/csharp]

Uygulamamızı çalıştırdığımızda eğer culture değerimiz en-US ise İngilizce mesajların değilse Türkçe mesajların geldiğini göreceğiz. Test etmek için tarayıcıdan QueryString ile ?culture-en-US gönderebiliriz.

Routing Mekanizması ile Dil Desteğinin Sağlanması

Uygulamamızda dil desteğini direkt Url/Uri üzerinden vermek isteyebiliriz. Gelen culture değerine göre uygulamamızın dilinin ayarlanmasını sağlayabiliriz.

bilgeadam.com/tr-TR/Home
bilgeadam.com/en-US/Home

gibi…

Bunun için “Startup.cs” dosyamıza geliyoruz ve aşağıdaki kodları “Configure” metodu içerisine ekliyoruz. Kodları eklemeden öne metod içerisinde bulunan UseMvc() ve diğer dil tanımlama ayarlarımızı kaldırıyoruz.

[csharp]

// Uygulamamızın desteklediği dilleri tanımlıyoruz.
var supportedCultures = new List<CultureInfo>
{
new CultureInfo(“tr-TR”),
new CultureInfo(“en-US”),
};

// Dil ayarlarını ve varsayılan dil seçimini tanımlıyoruz.
var localizationOptions = new RequestLocalizationOptions
{
SupportedCultures = supportedCultures,
SupportedUICultures = supportedCultures,
DefaultRequestCulture = new RequestCulture(“tr-TR”),
};
var requestProvider = new RouteDataRequestCultureProvider();
localizationOptions.RequestCultureProviders.Insert(0, requestProvider);

// Mevcut MVC routing yapısı yerine özelleştirilmiş yeni routing yapısını tanımlıyoruz.
app.UseRouter(routes =>
{
routes.MapMiddlewareRoute(“{culture=tr-TR}/{*mvcRoute}”, subApp =>
{
subApp.UseRequestLocalization(localizationOptions);

subApp.UseMvc(mvcRoutes =>
{
mvcRoutes.MapRoute(
name: “default”,
template: “{culture=tr-TR}/{controller=Home}/{action=Index}/{id?}”);
});
});
});

[/csharp]

Github üzerinden uygulamaya ait kodları indirebilirsiniz.
https://github.com/sinanbozkus/ASPNETCore_Localization

Kaynaklar:
https://docs.microsoft.com/en-us/aspnet/core/fundamentals/localization
https://joonasw.net/view/aspnet-core-localization-deep-dive

Bunlara da bakmak isteyebilirsiniz

11 yorum

Yiğit H. 15 Mart 2018 - 12:28

Ayrıntılı, anlaşılır, adım adım anlatılmış. Teşekkürler bu güzel yazı için.

Yanıtla
Muhammet Turşak 15 Mart 2018 - 23:11

Eline sağlık Sinan.

Yanıtla
Brianna 16 Mart 2018 - 21:59

Güzel bölümdü çeviri için teşekkürler.

Yanıtla
Microoyun 04 Aralık 2018 - 12:28

Çok detaylı ve açıklayıcı olmuş. Teşekkürler.

Yanıtla
yiğit 13 Mayıs 2019 - 11:10

Çok güzel bir anlatım olmuş ve örneği bizimle paylaştığınız için teşekkürler

Yanıtla
Sinan BOZKUŞ 15 Mayıs 2019 - 17:00

Teşekkür ederim :)

Yanıtla
borahan 28 Ekim 2019 - 13:06

Anlatımınız çok güzel teşekkürler.
Her control için ayrı ayrı bir dosyamı oluşturuyoruz. normal mvc de bir dosya oluşturup tüm dilleri ona göre ayarlama yapıyorduk. Tek bir resource dosyası ile hallediliyordu. Core tarafında işleri zorlaştırmışlar. Birde artık hiçbir uygulamada uzantıyı tr, en, ru değiştirilerek kullanma kalmadı.

Yanıtla
çağrı karayaka 19 Kasım 2019 - 11:24

İyi Günler Sinan Bey Çalışmanız Çok Güzel Ve Değerli Fakat Bir Sorum Olacaktı Size Kullanıcı Kendi Profil Sayfasından Dil Seçeneğini Ayarladığı Andan İtibaran Bütün Wep Sitesini Ona Ayarladığı Dilde Göstermek İçin Bir Yol Varmı Acaba Çok Araştırdım Fakat Bulamadım Maleysef

Yanıtla
Mustafa 24 Ocak 2022 - 13:49

Herşey tamam da her controller veya view için yeni bir resource dosyasının oluşturulması yanlış olmuş. Sadece her dil için bir tane resource kullanabilirdiniz.

Özetle; 10 controller olsa 10 farklı dil desteği sağlansa 100 tane resource dosyası olacak.

Yanıtla
Abdurrahman Sefer 10 Mayıs 2022 - 14:48

Anlatımınız çok güzel teşekkürler

Yanıtla
Saim selcuk kara 03 Temmuz 2022 - 11:30

Hocam tam aradıgım konuya değinmişsiniz çok teşekkürler

Yanıtla

Bir Yorum Bırakın