﻿
{"id":23744,"date":"2021-11-21T01:14:34","date_gmt":"2021-11-21T01:14:34","guid":{"rendered":"https:\/\/www.gencayyildiz.com\/blog\/?p=23744"},"modified":"2021-11-21T01:14:34","modified_gmt":"2021-11-21T01:14:34","slug":"asp-net-coreda-cok-dilli-uygulamalar-gelistirme","status":"publish","type":"post","link":"https:\/\/www.gencayyildiz.com\/blog\/asp-net-coreda-cok-dilli-uygulamalar-gelistirme\/","title":{"rendered":"Asp.NET Core&#8217;da \u00c7ok Dilli Uygulamalar Geli\u015ftirme"},"content":{"rendered":"<div id=\"fb-root\"><\/div>\n<p>Merhaba,<\/p>\n<p>Her web uygulamas\u0131n\u0131n ideali, \u00fcretildi\u011fi k\u00fclt\u00fcr\u00fcn s\u0131n\u0131rlar\u0131n\u0131 a\u015fabilmek ve daha geni\u015f kitlelere ula\u015farak farkl\u0131 co\u011frafyalara hitap edebilmektir. Bu ideali ger\u00e7ekle\u015ftirebilmek ve kozmopolit bir platform olu\u015fturabilmek i\u00e7in birden \u00e7ok dili destekleyebilmek ve gelen ziyaret\u00e7ilerin b\u00f6lge ve k\u00fclt\u00fcrlerine uygun i\u00e7erik sunabilecek uygulamalar geli\u015ftirmek gerekmektedir. Asp.NET Core mimarisi, bu ihtiyaca istinaden \u00f6z\u00fcnde zengin bir k\u00fcreselle\u015ftirme(globalization) ve yerelle\u015ftirme(localization) deste\u011fi bar\u0131nd\u0131rmakta ve biz geli\u015ftiriciler a\u00e7\u0131s\u0131ndan kolayl\u0131kla \u00e7ok dilli uygulamalar olu\u015fturmam\u0131z\u0131 sa\u011flayacak olan \u00f6zellikler sunmaktad\u0131r. Bu i\u00e7eri\u011fimizde, web uygulamalar\u0131m\u0131zda ziyaret\u00e7ilerin tercihlerine g\u00f6re yerelle\u015ftirilmi\u015f i\u00e7erikler sunabilmek i\u00e7in kullanabilece\u011fimiz yap\u0131lar\u0131 sizlere tan\u0131tacak ve \u00e7oklu dil deste\u011finin temelde hangi mant\u0131kla sa\u011fland\u0131\u011f\u0131n\u0131 pratiksel olarak inceliyor olaca\u011f\u0131z.<\/p>\n<h3>Ba\u015flarken<\/h3>\n<p>\u0130\u00e7eri\u011fimiz boyunca anlat\u0131lanlara tatbik ama\u00e7l\u0131 e\u015flik edebilmek istiyorsan\u0131z e\u011fer makaleye ba\u015flamadan \u00f6nce hali haz\u0131rda bir Asp.NET Core MVC ya da API uygulamas\u0131 olu\u015fturman\u0131z\u0131 tavsiye ederim. Ben deniz bu i\u00e7eri\u011fimizdeki t\u00fcm kodlar\u0131 .NET 6 &#8211; Asp.NET Core mimarisi \u00fczerinden \u00f6rneklendirece\u011fim ve \u00e7al\u0131\u015fma neticesinde \u00f6rnek projeyi makalenin sonunda payla\u015f\u0131yor olaca\u011f\u0131m.<\/p>\n<h3>Asp.NET Core&#8217;da Localization(Yerelle\u015ftirme) Yap\u0131land\u0131rmas\u0131<\/h3>\n<p>Asp.NET Core mimarisinin en g\u00fc\u00e7l\u00fc yanlar\u0131ndan biri do\u011fu\u015ftan middleware yap\u0131lanmas\u0131na dayanmas\u0131d\u0131r. Haliyle client&#8217;lardan gelen istekleri seri bir \u015fekilde t\u00fcrl\u00fc kontroller ve i\u015f ak\u0131\u015flar\u0131ndan ge\u00e7irebilmekte ve duruma g\u00f6re an \u00f6ncesi aksiyonlar al\u0131p, gerekli \u00f6nc\u00fcl \u00e7al\u0131\u015fmalar\u0131 sa\u011flayabilmekteyiz.<\/p>\n<p>Bu mant\u0131kla olay\u0131 de\u011ferlendirirsek e\u011fer, bir client&#8217;\u0131n b\u00f6lgesine g\u00f6re gerekli yerelle\u015ftirmeyi sa\u011flayabilmek i\u00e7in yap\u0131lan iste\u011fin handle edilme s\u00fcrecinde k\u00fclt\u00fcr\u00fcn otomatik olarak ayarlanmas\u0131 gerekmektedir. \u0130\u015fte bu sebepten dolay\u0131 <strong><em>UseRequestLocalization<\/em><\/strong> middleware&#8217;ini yap\u0131land\u0131rmam\u0131z gerekmektedir. Bunun i\u00e7in \u00f6ncelikle ilgili uygulaman\u0131n &#8216;Program.cs&#8217; dosyas\u0131na gelerek(Asp.NET Core 6.0&#8217;dan \u00f6nceki s\u00fcr\u00fcmlerde Startup.cs dosyas\u0131na) a\u015fa\u011f\u0131daki konfig\u00fcrasyonun sa\u011flanmas\u0131 gerekmektedir.<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n.\r\n.\r\n.\r\nvar builder = WebApplication.CreateBuilder(args);\r\n\r\nbuilder.Services.AddControllersWithViews()\r\n                .AddViewLocalization();\r\n\r\nbuilder.Services.AddLocalization(options =&gt;\r\n{\r\n    options.ResourcesPath = &quot;Resources&quot;;\r\n});\r\n.\r\n.\r\n.\r\n<\/pre>\n<p>Yukar\u0131daki kod blo\u011funa g\u00f6z atarsan\u0131z e\u011fer; ilgili uygulamaya 9. sat\u0131rda yerelle\u015ftirme ile ilgili <strong><em>AddLocalization<\/em><\/strong> servisinin eklendi\u011fini g\u00f6rmekteyiz. Bu servis i\u00e7erisindeki &#8216;ResourcesPath&#8217; \u00f6zelli\u011fi sayesinde, uygulaman\u0131n localization i\u00e7in nereden beslenece\u011fine dair temel kaynak(resource) dosyalar\u0131n\u0131n bulundu\u011fu dizin bildirimini ger\u00e7ekle\u015ftirmektedir.<\/p>\n<p>Bunun d\u0131\u015f\u0131nda 6. sat\u0131ra nazar eylersek e\u011fer uygulamaya &#8216;AddControllersWithViews&#8217; servisi akabinde <strong><em>AddViewLocalization<\/em><\/strong> servisi eklenmektedir. Bu servis ise M<em><strong>V<\/strong><\/em>C mimarisindeki <em><strong>V<\/strong><\/em>&#8216;nin yani &#8216;View&#8217; dosyalar\u0131n\u0131n yerelle\u015ftirme i\u00e7in ihtiyac\u0131 olan hizmeti sa\u011flamakta ve uygulamaya aktarmaktad\u0131r.<\/p>\n<h3>Uygulama Taraf\u0131ndan Desteklenecek K\u00fclt\u00fcrlerin Yap\u0131land\u0131r\u0131lmas\u0131<\/h3>\n<p>Temel localization yap\u0131land\u0131rmas\u0131ndan sonra s\u0131ra <strong><em>RequestLocalizationOptions<\/em><\/strong> konfig\u00fcrasyonu \u00fczerinden uygulama taraf\u0131ndan desteklenecek k\u00fclt\u00fcrlerin yap\u0131land\u0131rmas\u0131na gelmi\u015ftir. Bunun i\u00e7in yine &#8216;Program.cs&#8217; dosyas\u0131nda(ya da Startup.cs) a\u015fa\u011f\u0131daki gibi \u00e7al\u0131\u015f\u0131lmas\u0131 yeterlidir;<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n.\r\n.\r\n.\r\nbuilder.Services.Configure&lt;RequestLocalizationOptions&gt;(options =&gt;\r\n{\r\n    options.DefaultRequestCulture = new(&quot;tr-TR&quot;);\r\n\r\n    CultureInfo&#x5B;] cultures = new CultureInfo&#x5B;]\r\n    {\r\n        new(&quot;tr-TR&quot;),\r\n        new(&quot;en-US&quot;),\r\n        new(&quot;fr-FR&quot;)\r\n    };\r\n\r\n    options.SupportedCultures = cultures;\r\n    options.SupportedUICultures = cultures;\r\n});\r\n.\r\n.\r\n.\r\n<\/pre>\n<p>Yukar\u0131daki kod blo\u011funa g\u00f6z atarsan\u0131z e\u011fer, uygulama s\u00fcrecinde kullan\u0131lacak k\u00fclt\u00fcrlerin tan\u0131mlamas\u0131 ger\u00e7ekle\u015ftirilmi\u015ftir. Bizler \u00f6rneklendirmemizde &#8216;T\u00fcrk\u00e7e&#8217;, &#8216;\u0130ngilizce&#8217; ve &#8216;Frans\u0131zca&#8217; olmak \u00fczere \u00fc\u00e7 dil kullanaca\u011f\u0131z. Bu k\u00fclt\u00fcrler aras\u0131ndan &#8216;T\u00fcrk\u00e7e&#8217;nin varsay\u0131lan k\u00fclt\u00fcr olarak belirlendi\u011fine dikkatinizi \u00e7ekerim.<\/p>\n<p>T\u00fcm bu i\u015flemlerden sonra art\u0131k yap\u0131lmas\u0131 gereken tek hamle <strong><em>UseRequestLocalization<\/em><\/strong> middleware&#8217;inin \u00e7a\u011fr\u0131larak, etkinle\u015ftirilmesidir.<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n.\r\n.\r\n.\r\napp.UseRequestLocalization();\r\n.\r\n.\r\n.\r\n<\/pre>\n<p><strong><em>Kullan\u0131c\u0131lar\u0131n hangi k\u00fclt\u00fcrden oldu\u011funu nereden anlayaca\u011f\u0131z?<\/em><\/strong><br \/>\nGelen isteklerin hangi k\u00fclt\u00fcrden oldu\u011funu anlayabilmek i\u00e7in \u015fu ana kadar konfig\u00fcrasyonunu olu\u015fturdu\u011fumuz <strong><em>UseRequestLocalization<\/em><\/strong> middleware&#8217;inin \u00e7al\u0131\u015fma mant\u0131\u011f\u0131n\u0131 incelememiz yeterli olacakt\u0131r. <strong><em>UseRequestLocalization<\/em><\/strong> middleware&#8217;i tetiklendi\u011fi anda konfig\u00fcre edilmi\u015f olan <strong><em>RequestLocalizationOptions<\/em><\/strong> t\u00fcr\u00fcnden nesnenin ayarlar\u0131n\u0131 uygulamaya y\u00fcklemekte ve gelen istekteki k\u00fclt\u00fcr\u00fc <strong><em>RequestCultureProvider<\/em><\/strong> \u015feklinde nitelendirilen bir sa\u011flay\u0131c\u0131 dizisiyle kontrol etmektedir. Bu sa\u011flay\u0131c\u0131 dizisi;<\/p>\n<ul>\n<li><em style=\"color:orange;\">QueryStringRequestCultureProvider<\/em><\/li>\n<li><em style=\"color:orange;\">CookieRequestCultureProvider<\/em><\/li>\n<li><em style=\"color:orange;\">AcceptLanguageHeaderRequestCultureProvider<\/em><\/li>\n<\/ul>\n<p>olmak \u00fczere \u00fc\u00e7 adettir. Kullan\u0131c\u0131 yapt\u0131\u011f\u0131 iste\u011fin hangi k\u00fclt\u00fcrden oldu\u011funu bu sa\u011flay\u0131c\u0131lar\u0131n herhangi biriyle server&#8217;a bildirecektir. Haliyle bizler bu bildirime g\u00f6re gerekli dil d\u00f6n\u00fc\u015f\u00fcm\u00fcn\u00fc sa\u011flayaca\u011f\u0131z. E\u011fer ki kullan\u0131c\u0131dan herhangi bir provider&#8217;da k\u00fclt\u00fcr bilgisi s\u00f6z konusu de\u011filse o zaman &#8216;DefaultRequestCulture&#8217; property&#8217;sine verilen k\u00fclt\u00fcr ge\u00e7erli olacakt\u0131r.<\/p>\n<p><strong><em>Peki hoca! bu sa\u011flay\u0131c\u0131lar\u0131 hafiften a\u00e7\u0131klayabilir misin?<\/em><\/strong><br \/>\nYaz\u0131m\u0131z\u0131n devam\u0131nda, \u00e7ok dillili\u011fi test edebilmek i\u00e7in bu provider&#8217;lar\u0131 tek tek tam teferruatl\u0131 mevzu bahis ediyor olaca\u011f\u0131z. Amma velakin sizlerin meram\u0131n\u0131 dindirebilmek ve haz\u0131r laf\u0131 ge\u00e7mi\u015fken hafiften \u00f6n bilgi verebilmek i\u00e7in a\u015fa\u011f\u0131da sa\u011flay\u0131c\u0131lara dair k\u0131saca a\u00e7\u0131klamalarda bulunal\u0131m.<\/p>\n<ul>\n<li><em style=\"color:orange;\">QueryStringRequestCultureProvider<\/em><br \/>\n<span style=\"font-size:13px;\">Gelen iste\u011fin hangi k\u00fclt\u00fcrden oldu\u011funu query string&#8217;de &#8216;culture&#8217; parametresi e\u015fli\u011finde bildirmektedir.<\/span>\n<\/li>\n<li><em style=\"color:orange;\">CookieRequestCultureProvider<\/em><br \/>\n<span style=\"font-size:13px;\">Gelen iste\u011fin hangi k\u00fclt\u00fcrden oldu\u011funu Cookie&#8217;de &#8216;.AspNetCore.Culture&#8217; key&#8217;ine kar\u015f\u0131l\u0131k bildirmektedir.<\/span>\n<\/li>\n<li><em style=\"color:orange;\">AcceptLanguageHeaderRequestCultureProvider<\/em><br \/>\n<span style=\"font-size:13px;\">Gelen iste\u011fin hangi k\u00fclt\u00fcrden oldu\u011funu header&#8217;da &#8216;Accept-Language&#8217; key&#8217;ine kar\u015f\u0131l\u0131k bildirmektedir. <\/span>\n<\/li>\n<\/ul>\n<p>Art\u0131k uygulama \u00fczerinde temel localization konfig\u00fcrasyonu tamamlanm\u0131\u015f bulunmaktad\u0131r. Bundan sonra, farkl\u0131 dillerde metin kar\u015f\u0131l\u0131\u011f\u0131n\u0131 bar\u0131nd\u0131racak olan resource dosyalar\u0131n\u0131n adland\u0131rma ve konum kurallar\u0131n\u0131n detaylar\u0131n\u0131 konu\u015fmaya ge\u00e7ebiliriz.<\/p>\n<h3>Resource Dosyalar\u0131n\u0131 Adland\u0131rma ve Konumland\u0131rma Kurallar\u0131<\/h3>\n<p>Asp.NET Core uygulamalar\u0131nda, klasik Asp.NET&#8217;te oldu\u011fu gibi simgeler, resimler, \u00f6zelle\u015ftirilmi\u015f dosyalar yahut sabit metinler i\u00e7in <code>.resx<\/code> uzant\u0131l\u0131 resource yap\u0131lar\u0131 kullan\u0131lmaktad\u0131r. Bu yap\u0131lar sayesinde harici uzant\u0131lar\u0131 ve sabit metinleri kaynak kodundan ay\u0131rabilmekte ve daha dinamik bir \u015fekilde y\u00f6netebilmekteyiz. Bu mant\u0131kla farkl\u0131 k\u00fclt\u00fcr ve dillere dair gerekli verileri resource dosyalar\u0131nda tutmam\u0131z ve o anki k\u00fclt\u00fcre g\u00f6re ihtiya\u00e7 do\u011frultusunda ilgili resource dosyas\u0131ndan verileri getirmemiz olduk\u00e7a ideal bir yakla\u015f\u0131m olacakt\u0131r. <\/p>\n<p><strong>Peki resource dosyalar\u0131n\u0131 nerede ve nas\u0131l olu\u015fturmal\u0131y\u0131z?<\/strong><br \/>\n\u00c7oklu dil operasyonlar\u0131 i\u00e7in olu\u015fturulacak resource dosyalar\u0131nda isim standard\u0131<br \/>\n<code style=\"font-size:14px;color:green;\">[file-name].[language-code].resx<\/code> \u015feklinde olacakt\u0131r. Buna \u00f6rnek vermemiz gerekirse e\u011fer; \u0130ngilizce dil verilerini depolayaca\u011f\u0131m\u0131z resource kayna\u011f\u0131n\u0131n ad\u0131 <code style=\"font-size:14px;color:green;\">Lang.en-US.resx<\/code> olacakken, benzer mant\u0131kla Frans\u0131zca i\u00e7in <code style=\"font-size:14px;color:green;\">Lang.fr-FR.resx<\/code> \u015feklinde olacakt\u0131r. Eee haliyle T\u00fcrk\u00e7e dil kayna\u011f\u0131n\u0131n ise <code style=\"font-size:14px;color:green;\">Lang.tr-TR.resx<\/code> olacakt\u0131r. Tabi buradaki isim format\u0131 her ne kadar bir standart gerektirse de kendi karar\u0131n\u0131za g\u00f6re de\u011fi\u015ftirilebilir.<\/p>\n<p>Resource dosyalar\u0131n\u0131n nerede tan\u0131mlanaca\u011f\u0131na gelirsek e\u011fer bunun i\u00e7in yukar\u0131da <strong><em>AddLocalization<\/em><\/strong> servisini tan\u0131mlarken <em>ResourcesPath<\/em> property&#8217;sine verdi\u011fimiz &#8216;Resources&#8217; de\u011ferini kullanaca\u011f\u0131z. Bu de\u011fer, projenin k\u00f6k dizininde &#8216;Resources&#8217; ad\u0131nda bir klas\u00f6r olaca\u011f\u0131 ve i\u00e7erisinde <code>.resx<\/code> uzant\u0131l\u0131 dil kaynaklar\u0131n\u0131n bar\u0131nd\u0131r\u0131laca\u011f\u0131 anlam\u0131na gelmektedir.<br \/>\n<a href=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2021\/11\/Asp.NET-Coreda-Cok-Dilli-Uygulamalar-Gelistirme-4.jpg\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2021\/11\/Asp.NET-Coreda-Cok-Dilli-Uygulamalar-Gelistirme-4.jpg\" alt=\"Asp.NET Core&#039;da \u00c7ok Dilli Uygulamalar Geli\u015ftirme\" width=\"187\" height=\"288\" class=\"aligncenter size-full wp-image-23829\" \/><\/a>Yukar\u0131daki g\u00f6rselde g\u00f6r\u00fcld\u00fc\u011f\u00fc \u00fczere &#8216;<em>Resources\\Languages<\/em>&#8216; dizini alt\u0131nda \u00f6rneklendirmemiz gere\u011fi \u00fc\u00e7 dile kar\u015f\u0131l\u0131k dil depolar\u0131 olu\u015fturulmu\u015f bulunmaktad\u0131r. Burada zihinlerinizden ge\u00e7en <em style=\"font-size:13px;\">Neden Resources klas\u00f6r\u00fc alt\u0131na Languages klas\u00f6r\u00fc eklendi?<\/em> sorusunu duyar gibiyim&#8230; Bunun nedeni birazdan bu resource dosyalar\u0131n\u0131 okumay\u0131 ele al\u0131rken anla\u015f\u0131lacakt\u0131r. O noktaya gelmeden \u015fimdilik bu kaynak dosyalar\u0131n\u0131 a\u00e7al\u0131m ve i\u00e7lerini a\u015fa\u011f\u0131daki gibi olacak \u015fekilde doldural\u0131m.<\/p>\n<table>\n<thead>\n<tr>\n<th>Lang.tr-TR<\/th>\n<th>Lang.fr-FR<\/th>\n<th>Lang.en-US<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td><a href=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2021\/11\/Asp.NET-Coreda-Cok-Dilli-Uygulamalar-Gelistirme-1.jpg\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2021\/11\/Asp.NET-Coreda-Cok-Dilli-Uygulamalar-Gelistirme-1.jpg\" alt=\"Asp.NET Core&#039;da \u00c7ok Dilli Uygulamalar Geli\u015ftirme\" width=\"170\" height=\"67\" class=\"aligncenter size-full wp-image-23814\" \/><\/a><\/td>\n<td><a href=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2021\/11\/Asp.NET-Coreda-Cok-Dilli-Uygulamalar-Gelistirme-2.jpg\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2021\/11\/Asp.NET-Coreda-Cok-Dilli-Uygulamalar-Gelistirme-2.jpg\" alt=\"Asp.NET Core&#039;da \u00c7ok Dilli Uygulamalar Geli\u015ftirme\" width=\"201\" height=\"64\" class=\"aligncenter size-full wp-image-23815\" \/><\/a><\/td>\n<td><a href=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2021\/11\/Asp.NET-Coreda-Cok-Dilli-Uygulamalar-Gelistirme-3.jpg\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2021\/11\/Asp.NET-Coreda-Cok-Dilli-Uygulamalar-Gelistirme-3.jpg\" alt=\"Asp.NET Core&#039;da \u00c7ok Dilli Uygulamalar Geli\u015ftirme\" width=\"138\" height=\"63\" class=\"aligncenter size-full wp-image-23816\" \/><\/a><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<h3>Resource Dosyalar\u0131n\u0131n Okunmas\u0131<\/h3>\n<p>Ziyaret\u00e7ilerin k\u00fclt\u00fcrlerine g\u00f6re resource dosyalar\u0131n\u0131n okunabilmesi i\u00e7in temelde <\/p>\n<ul style=\"font-size:13px;\">\n<li><em style=\"color:purple;\">IStringLocalizer | IStringLocalizer&lt;T&gt;<\/em><\/li>\n<li><em style=\"color:purple;\">IHtmlLocalizer | IHtmlLocalizer&lt;T&gt;<\/em><\/li>\n<\/ul>\n<p>olmak \u00fczere iki farkl\u0131 yerel servis mevcuttur. Her bir servisin kendi \u015fahs\u0131na m\u00fcnhas\u0131r davran\u0131\u015f modelinin mevcut olmas\u0131n\u0131n yan\u0131nda t\u00fcm\u00fcnde ortak olan teknik bir nokta vard\u0131r. O da, t\u00fcm servisler de resource dosyalar\u0131n\u0131n okunmas\u0131n\u0131n pratikte ayn\u0131 altyap\u0131y\u0131 gerektirmesidir. Haliyle bu servisleri incelemeye gelmeden \u00f6nce mevzu bahis altyap\u0131y\u0131 olu\u015fturup hali haz\u0131r duruma getirelim.<\/p>\n<p>Bunun i\u00e7in tek yap\u0131lmas\u0131 gereken resource dosyalar\u0131yla ayn\u0131 isimde olan bir s\u0131n\u0131f\u0131n olu\u015fturulmas\u0131d\u0131r. Bizlerin dil verilerini depolad\u0131\u011f\u0131m\u0131z dosyalara tekrar g\u00f6z atarsan\u0131z <code style=\"font-size:14px;color:green;\"><span style=\"color:red;\">Lang<\/span>.***.resx<\/code> format\u0131nda olu\u015fturuldu\u011funu g\u00f6receksiniz. Haliyle bu resource dosyalar\u0131ndan okuma i\u015flemini yapacak olan s\u0131n\u0131f\u0131m\u0131z\u0131n ad\u0131 da <code style=\"font-size:14px;color:green;\"><span style=\"color:red;\">Lang<\/span>.cs<\/code> olacakt\u0131r. Burada isimlendirme format\u0131n\u0131n kritik arz etti\u011fi a\u015fikard\u0131r. Dosyalar\u0131n format\u0131 ne ise, okuma i\u015fleminden sorumlu s\u0131n\u0131f\u0131n ad\u0131 da bire bir o olmal\u0131d\u0131r.<\/p>\n<p><strong>Peki bu s\u0131n\u0131f nerede olu\u015fturulacakt\u0131r?<\/strong><br \/>\n\u0130\u015fte bu sorunun cevab\u0131 yukar\u0131da olu\u015fturulan &#8216;<em>Resources\\<span style=\"color:red;\">Languages<\/span><\/em>&#8216;de sakl\u0131d\u0131r. Evet, bu s\u0131n\u0131f projenin k\u00f6k dizininde bulunan &#8216;Languages&#8217; isimli bir klas\u00f6rde tan\u0131mlanmal\u0131d\u0131r. Ya da bu s\u0131n\u0131f\u0131n namespace&#8217;i <code>namespace Project.Languages<\/code> \u015feklinde olmal\u0131d\u0131r. Aksi taktirde .NET Core&#8217;da ki yerel localization servisleri bu s\u0131n\u0131f\u0131n dizinini, ilgili dil verilerinin bulundu\u011fu depolar\u0131n diziniyle e\u015fle\u015ftiremeyecek ve b\u00f6ylece veri okuma kabileyeti s\u00f6z konusu olmayacakt\u0131r. Burada genelleme yaparsak e\u011fer resource dosyalar\u0131 &#8216;a\\b&#8217; dizininde ise bu resource dosyalar\u0131ndaki verileri okuyacak s\u0131n\u0131f proje k\u00f6k dizini i\u00e7erisinde tan\u0131mlanm\u0131\u015f &#8216;b&#8217; dizinin de olmal\u0131d\u0131r.<\/p>\n<p>\u015eimdi localization a\u00e7\u0131s\u0131ndan resource dosyalar\u0131n\u0131 okumam\u0131z\u0131 sa\u011flayacak servisleri s\u0131ras\u0131yla incelemeye ge\u00e7ebiliriz.<\/p>\n<ul style=\"font-size:14px;\">\n<li><strong><em style=\"color:purple;\">IStringLocalizer | IStringLocalizer&lt;T&gt;<\/em><\/strong><br \/>\nController s\u0131n\u0131flar\u0131nda resource dosyalar\u0131ndan localization verilerini metinsel olarak almam\u0131z\u0131 sa\u011flayan servistir.<\/p>\n<p>Kullan\u0131m\u0131;<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\nprivate readonly IStringLocalizer&lt;Lang&gt; _stringLocalizer;\r\n<\/pre>\n<p>\u015feklindedir. Dikkat ederseniz generic olarak resource dosyalar\u0131n\u0131 okuyacak olan s\u0131n\u0131f\u0131n(Lang) bildirimi yap\u0131lmaktad\u0131r.<\/p>\n<p>\u00d6rnek olarak a\u015fa\u011f\u0131daki kod blo\u011funu inceleyebilirsiniz.<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n    public class HomeController : Controller\r\n    {\r\n        private readonly IStringLocalizer&lt;Lang&gt; _stringLocalizer;\r\n\r\n        public HomeController(IStringLocalizer&lt;Lang&gt; stringLocalizer)\r\n            =&gt; _stringLocalizer = stringLocalizer;\r\n\r\n        public IActionResult Index()\r\n        {\r\n            ViewBag.PageAbout = _stringLocalizer&#x5B;&quot;page.About&quot;];\r\n            ViewBag.PageHome = _stringLocalizer&#x5B;&quot;page.Home&quot;];\r\n            return View();\r\n        }\r\n    }\r\n<\/pre>\n<p>G\u00f6r\u00fcld\u00fc\u011f\u00fc \u00fczere &#8216;IStringLocalizer&#8217; dependency injection ile talep edilebilmekte ve belirtilen key&#8217;lere kar\u015f\u0131l\u0131k uygun localization verinin gelmesi sa\u011flanmaktad\u0131r.\n<\/li>\n<li><strong><em style=\"color:purple;\">IHtmlLocalizer | IHtmlLocalizer&lt;T&gt;<\/em><\/strong><br \/>\nResource dosyalar\u0131nda kay\u0131tl\u0131 verilerin i\u00e7erisinde varsa HTML kodlar\u0131, bunlar\u0131n taray\u0131c\u0131 taraf\u0131ndan derlenebilecek \u015fekilde bi\u00e7imlendirmesini sa\u011flayan servistir. &#8216;IStringLocalizer&#8217; verileri direkt getirirken, &#8216;IHtmlLocalizer&#8217; ise HTML etiketlerini bi\u00e7imlendirerek getirir.<\/p>\n<p>Kullan\u0131m\u0131 &#8216;IStringLocalizer&#8217; ile birebir benzerdir;<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\nprivate readonly IHtmlLocalizer&lt;Lang&gt; _htmlLocalizer;\r\n<\/pre>\n<p>\u00d6rnek mahiyetinde a\u015fa\u011f\u0131daki kodu inceleyebilirsiniz.<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n    public class HomeController : Controller\r\n    {\r\n        private readonly IHtmlLocalizer&lt;Lang&gt; _htmlLocalizer;\r\n\r\n        public HomeController(IHtmlLocalizer&lt;Lang&gt; htmlLocalizer)\r\n            =&gt; _htmlLocalizer = htmlLocalizer;\r\n\r\n        public IActionResult Index()\r\n        {\r\n            ViewBag.PageAbout = _htmlLocalizer&#x5B;&quot;page.About&quot;];\r\n            ViewBag.PageHome = _htmlLocalizer&#x5B;&quot;page.Home&quot;];\r\n            return View();\r\n        }\r\n    }\r\n<\/pre>\n<\/li>\n<\/ul>\n<h3>RequestCultureProvider \u0130le Kullan\u0131c\u0131 K\u00fclt\u00fcr\u00fcn\u00fc Yakalama<\/h3>\n<p>Yaz\u0131m\u0131z\u0131n \u00f6nceki sat\u0131rlar\u0131nda, ziyaret\u00e7ilerden gelen istekler \u00fczerinden k\u00fclt\u00fcrlerini <strong><em>RequestCultureProvider<\/em><\/strong> ismi verilen sa\u011flay\u0131c\u0131lar sayesinde edinebilece\u011fimizden ve bu sa\u011flay\u0131c\u0131lar\u0131n <em>QueryStringRequestCultureProvider<\/em>, <em>CookieRequestCultureProvider <\/em>ve <em>AcceptLanguageHeaderRequestCultureProvider<\/em> olmak \u00fczere \u00fc\u00e7 adet oldu\u011fundan bahsetmi\u015ftik. \u015eimdi gelin, ziyaret\u00e7ilerin k\u00fclt\u00fcrlerini \u00f6\u011frenebilmemizi sa\u011flayacak olan bu sa\u011flay\u0131c\u0131lar\u0131 tek tek teferruatlar\u0131yla inceleyelim.<\/p>\n<ul style=\"font-size:14px;\">\n<li><em style=\"color:orange;\"><strong>QueryStringRequestCultureProvider<\/strong><\/em><br \/>\nGelen ziyaret\u00e7i web uygulamas\u0131ndaki varsay\u0131lan dilden farkl\u0131 bir k\u00fclt\u00fcre aitse buna m\u00fcdahale edebilmek ve dili kendine g\u00f6re de\u011fi\u015ftirebilmek i\u00e7in query string \u00fczerinden &#8216;culture&#8217; parametresini a\u015fa\u011f\u0131daki gibi g\u00f6nderebilir.<br \/>\n<a href=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2021\/11\/Asp.NET-Coreda-Cok-Dilli-Uygulamalar-Gelistirme.gif\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2021\/11\/Asp.NET-Coreda-Cok-Dilli-Uygulamalar-Gelistirme.gif\" alt=\"Asp.NET Core&#039;da \u00c7ok Dilli Uygulamalar Geli\u015ftirme\" width=\"564\" height=\"202\" class=\"aligncenter size-full wp-image-23848\" \/><\/a>\n<\/li>\n<li><em style=\"color:orange;\"><strong>AcceptLanguageHeaderRequestCultureProvider<\/strong><\/em><br \/>\nBenzer \u015fekilde gelen ziyaret\u00e7i yine varsay\u0131lan dilden farkl\u0131 bir k\u00fclt\u00fcre aitse buna m\u00fcdahale edebilmek i\u00e7in yapaca\u011f\u0131 request&#8217;in header&#8217;da &#8216;Accept-Language&#8217; key&#8217;ine kar\u015f\u0131l\u0131k dil bildiriminde bulunabilir.<br \/>\n<a href=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2021\/11\/Asp.NET-Coreda-Cok-Dilli-Uygulamalar-Gelistirme.jpg\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2021\/11\/Asp.NET-Coreda-Cok-Dilli-Uygulamalar-Gelistirme.jpg\" alt=\"\" width=\"246\" height=\"173\" class=\"aligncenter size-full wp-image-23860\" \/><\/a>\n<\/li>\n<li><em style=\"color:orange;\"><strong>CookieRequestCultureProvider<\/strong><\/em><br \/>\n\u00c7o\u011fu web uygulamas\u0131, ziyaret\u00e7i k\u00fclt\u00fcr\u00fcn\u00fc Cookie&#8217;de tutmaktad\u0131r. Haliyle bizler de ziyaret\u00e7iden gelen dil bilgisini <em>CookieRequestCultureProvider<\/em> ile cookie&#8217;de saklayabiliriz. Bunun i\u00e7in a\u015fa\u011f\u0131daki geli\u015ftirmenin yap\u0131lmas\u0131 gerekmektedir.<\/p>\n<ul>\n<li><em>1. Ad\u0131m<\/em><br \/>\nKullan\u0131c\u0131dan gelen istek neticesinde k\u00fclt\u00fcr\u00fcne uygun cookie de\u011ferini olu\u015fturacak middleware&#8217;i tan\u0131mlayal\u0131m.<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n    public class RequestLocalizationCookiesMiddleware : IMiddleware\r\n    {\r\n        readonly CookieRequestCultureProvider _provider;\r\n\r\n        public RequestLocalizationCookiesMiddleware(IOptions&lt;RequestLocalizationOptions&gt; requestLocalizationOptions)\r\n            =&gt; _provider = requestLocalizationOptions.Value.RequestCultureProviders.Where(x =&gt; x is CookieRequestCultureProvider).Cast&lt;CookieRequestCultureProvider&gt;().FirstOrDefault();\r\n\r\n        public async Task InvokeAsync(HttpContext context, RequestDelegate next)\r\n        {\r\n            if (_provider != null)\r\n            {\r\n                IRequestCultureFeature feature = context.Features.Get&lt;IRequestCultureFeature&gt;();\r\n                if (feature != null)\r\n                    context.Response.Cookies.Append(_provider.CookieName, CookieRequestCultureProvider.MakeCookieValue(feature.RequestCulture));\r\n            }\r\n\r\n            await next(context);\r\n        }\r\n    }\r\n<\/pre>\n<p>Burada ziyaret\u00e7inin k\u00fclt\u00fcr\u00fc ister query string&#8217;den(QueryStringRequestCultureProvider) isterse de header bilgisinden(AcceptLanguageHeaderRequestCultureProvider) gelsin fark etmeksizin yakalanmakta ve cookie olarak response&#8217;a eklenmektedir.\n<\/li>\n<li><em>2. Ad\u0131m<\/em><br \/>\nBu middleware&#8217;i pipeline&#8217;a entegre edecek olan extension metodu tasarlayal\u0131m.<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n    public static class RequestLocalizationCookiesMiddlewareExtensions\r\n    {\r\n        public static IApplicationBuilder UseRequestLocalizationCookies(this IApplicationBuilder app)\r\n            =&gt; app.UseMiddleware&lt;RequestLocalizationCookiesMiddleware&gt;();\r\n    }\r\n<\/pre>\n<\/li>\n<li><em>3. Ad\u0131m<\/em><br \/>\nOlu\u015fturulan middleware&#8217;i dependency injection container&#8217;\u0131na ekleyelim.<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\nbuilder.Services.AddScoped&lt;RequestLocalizationCookiesMiddleware&gt;();\r\n<\/pre>\n<p>Ve ard\u0131ndan <strong><em>UseRequestLocalization<\/em><\/strong> middleware&#8217;inden sonra olu\u015fturdu\u011fumuz &#8216;UseRequestLocalizationCookies&#8217; extension metodunu \u00e7a\u011f\u0131ral\u0131m.<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\napp.UseRequestLocalization();\r\n\r\napp.UseRequestLocalizationCookies();\r\n<\/pre>\n<\/li>\n<\/ul>\n<p>Bu \u00e7al\u0131\u015fmadan sonra ziyaret\u00e7i hangi dili g\u00f6nderiyorsa o cookie&#8217;ye kaydedilecektir.<br \/>\n<a href=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2021\/11\/Asp.NET-Coreda-Cok-Dilli-Uygulamalar-Gelistirme-1.gif\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2021\/11\/Asp.NET-Coreda-Cok-Dilli-Uygulamalar-Gelistirme-1.gif\" alt=\"Asp.NET Core&#039;da \u00c7ok Dilli Uygulamalar Geli\u015ftirme\" width=\"800\" height=\"452\" class=\"aligncenter size-full wp-image-23853\" \/><\/a><br \/>\nDikkat ederseniz e\u011fer cookie&#8217;ye <em style=\"color:blue;\">.AspNetCore.Culture<\/em> key&#8217;i kar\u015f\u0131l\u0131\u011f\u0131nda kaydedilen dil bilgisi sayesinde ziyaret\u00e7inin tekrardan dili g\u00f6nderme gibi bir sorumlulu\u011fu kalmamaktad\u0131r.\n<\/li>\n<\/ul>\n<h3>Web Uygulamas\u0131nda Desteklenen Dillerin Bilgisini Almak<\/h3>\n<p>Localization operasyonlar\u0131nda en \u00f6nemli hususlardan biri uygulama s\u00fcrecinde desteklenmekte olan dillerin toplu bilgisini alabilmektir. Bunun i\u00e7in t\u00fcrl\u00fc y\u00f6ntemler uygulanabilece\u011fi gibi .NET Core localization servislerinin bizlere sa\u011flad\u0131\u011f\u0131 a\u015fa\u011f\u0131daki gibi pratik dokunu\u015flar da mevcuttur.<\/p>\n<pre class=\"brush: jscript; title: ; notranslate\" title=\"\">\r\n    public class LangController : Controller\r\n    {\r\n        readonly RequestLocalizationOptions _localizationOptions;\r\n\r\n        public LangController(IOptions&lt;RequestLocalizationOptions&gt; localizationOptions)\r\n            =&gt; _localizationOptions = localizationOptions.Value;\r\n\r\n        public IActionResult AllLanguages()\r\n        {\r\n            IRequestCultureFeature requestCulture = HttpContext.Features.Get&lt;IRequestCultureFeature&gt;();\r\n            var allCultures = _localizationOptions.SupportedCultures\r\n                    .Select(culture =&gt; new\r\n                    {\r\n                        Name = culture.Name,\r\n                        Text = culture.DisplayName\r\n                    }).ToList();\r\n            return Ok(allCultures);\r\n        }\r\n    }\r\n<\/pre>\n<p><a href=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2021\/11\/Asp.NET-Coreda-Cok-Dilli-Uygulamalar-Gelistirme-5.jpg\"><img loading=\"lazy\" decoding=\"async\" src=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2021\/11\/Asp.NET-Coreda-Cok-Dilli-Uygulamalar-Gelistirme-5.jpg\" alt=\"Asp.NET Core&#039;da \u00c7ok Dilli Uygulamalar Geli\u015ftirme\" width=\"333\" height=\"439\" class=\"aligncenter size-full wp-image-23864\" srcset=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2021\/11\/Asp.NET-Coreda-Cok-Dilli-Uygulamalar-Gelistirme-5.jpg 333w, https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2021\/11\/Asp.NET-Coreda-Cok-Dilli-Uygulamalar-Gelistirme-5-228x300.jpg 228w\" sizes=\"auto, (max-width: 333px) 100vw, 333px\" \/><\/a>G\u00f6r\u00fcld\u00fc\u011f\u00fc \u00fczere <strong><em>IRequestCultureFeature<\/em><\/strong> aray\u00fcz\u00fc sayesinde uygulaman\u0131n &#8216;Program.cs'(Startup.cs) dosyas\u0131nda konfig\u00fcre edilen <strong><em>RequestLocalizationOptions<\/em><\/strong> servisinin i\u00e7erisinde tan\u0131mlanan t\u00fcm k\u00fclt\u00fcrler basit bir \u015fekilde taraf\u0131m\u0131zca elde edilmi\u015ftir.<\/p>\n<p>Nihai olarak;<br \/>\nBu i\u00e7eri\u011fimizde, web geli\u015ftiricileri a\u00e7\u0131s\u0131ndan korkutucu bir konu olan \u00e7oklu dil deste\u011finin \u00f6z\u00fcnde gayet basit ve s\u0131radan bir mimariye sahip oldu\u011funu g\u00f6zlemlemi\u015f olduk. Hele hele bu s\u0131radanl\u0131\u011f\u0131n Asp.NET Core mimarisiyle daha da basit bir hale getirildi\u011fini g\u00f6rm\u00fc\u015f ve hi\u00e7 kompleks i\u015fleme gerek duyulmaks\u0131z\u0131n h\u0131zl\u0131ca nas\u0131l entegre yap\u0131labilece\u011fini tecr\u00fcbe etmi\u015f olduk. Bu i\u00e7eri\u011fimiz boyunca, bir web uygulamas\u0131nda yerelle\u015ftirme operasyonlar\u0131n\u0131n nas\u0131l yap\u0131land\u0131r\u0131ld\u0131\u011f\u0131na, \u00e7al\u0131\u015fma zaman\u0131nda ziyaret\u00e7ilere uygun dile web uygulamas\u0131n\u0131n nas\u0131l e\u015flik edebilece\u011fine ve belli ba\u015fl\u0131 k\u00fclt\u00fcr sa\u011flay\u0131c\u0131lar\u0131n\u0131n neler oldu\u011funa teorik ve pratik olmak \u00fczere temas etmeye \u00e7al\u0131\u015ft\u0131k. Bol bol faydalaman\u0131z dile\u011fiyle&#8230; <\/p>\n<p>Sabredip okudu\u011funuz i\u00e7in te\u015fekk\u00fcr ederim.<\/p>\n<p>\u0130lgilenenlerin faydalanmas\u0131 dile\u011fiyle&#8230;<br \/>\nSonraki yaz\u0131lar\u0131mda g\u00f6r\u00fc\u015fmek \u00fczere&#8230;<br \/>\n\u0130yi \u00e7al\u0131\u015fmalar&#8230;<\/p>\n<p>Not : \u00d6rnek projeyi indirebilmek i\u00e7in <a href=\"https:\/\/www.gencayyildiz.com\/blog\/wp-content\/uploads\/2021\/11\/AspNetCoreMultilingual.zip\" rel=\"noopener\" target=\"_blank\">buraya<\/a> t\u0131klay\u0131n\u0131z.<\/p>\n<!-- AddThis Advanced Settings generic via filter on the_content --><!-- AddThis Share Buttons generic via filter on the_content -->","protected":false},"excerpt":{"rendered":"<p>Merhaba, Her web uygulamas\u0131n\u0131n ideali, \u00fcretildi\u011fi k\u00fclt\u00fcr\u00fcn s\u0131n\u0131rlar\u0131n\u0131 a\u015fabilmek ve daha geni\u015f kitlelere ula\u015farak farkl\u0131 co\u011frafyalara hitap edebilmektir. Bu ideali ger\u00e7ekle\u015ftirebilmek ve kozmopolit bir platform olu\u015fturabilmek i\u00e7in birden \u00e7ok dili destekleyebilmek ve gelen ziyaret\u00e7ilerin&#46;&#46;&#46;<!-- AddThis Advanced Settings generic via filter on get_the_excerpt --><!-- AddThis Share Buttons generic via filter on get_the_excerpt --><\/p>\n","protected":false},"author":1,"featured_media":9596,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[3102,4443],"tags":[4441,4440,4442,4444,4445],"class_list":["post-23744","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-asp-net-core","category-asp-net-core-6-0","tag-asp-net-core-coklu-dil","tag-asp-net-core-coklu-dil-uygulamasi","tag-asp-net-core-coklu-multi-language","tag-asp-net-core-localization","tag-asp-net-core-yerellestirme"],"amp_enabled":true,"_links":{"self":[{"href":"https:\/\/www.gencayyildiz.com\/blog\/wp-json\/wp\/v2\/posts\/23744","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.gencayyildiz.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.gencayyildiz.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.gencayyildiz.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.gencayyildiz.com\/blog\/wp-json\/wp\/v2\/comments?post=23744"}],"version-history":[{"count":113,"href":"https:\/\/www.gencayyildiz.com\/blog\/wp-json\/wp\/v2\/posts\/23744\/revisions"}],"predecessor-version":[{"id":23872,"href":"https:\/\/www.gencayyildiz.com\/blog\/wp-json\/wp\/v2\/posts\/23744\/revisions\/23872"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.gencayyildiz.com\/blog\/wp-json\/wp\/v2\/media\/9596"}],"wp:attachment":[{"href":"https:\/\/www.gencayyildiz.com\/blog\/wp-json\/wp\/v2\/media?parent=23744"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.gencayyildiz.com\/blog\/wp-json\/wp\/v2\/categories?post=23744"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.gencayyildiz.com\/blog\/wp-json\/wp\/v2\/tags?post=23744"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}