{"id":1931,"date":"2017-12-17T17:19:29","date_gmt":"2017-12-17T14:19:29","guid":{"rendered":"https:\/\/gokhan-gokalp.com\/?p=1931"},"modified":"2017-12-17T17:19:29","modified_gmt":"2017-12-17T14:19:29","slug":"globalization-in-aspnet-core-and-elasticsearch","status":"publish","type":"post","link":"https:\/\/gokhan-gokalp.com\/tr\/globalization-in-aspnet-core-and-elasticsearch\/","title":{"rendered":"ASP.NET Core MVC ve Elasticsearch&#8217;de Globalization"},"content":{"rendered":"<p>Merhaba arkada\u015flar.<\/p>\n<p>Biliyoruz ki g\u00fcn\u00fcm\u00fcz teknoloji \u00e7a\u011f\u0131nda firmalar, e-ticaret siteleri \u00fczerinden hi\u00e7 tan\u0131mad\u0131\u011f\u0131 ve farkl\u0131 \u015fehirdeki insanlara \u00fcr\u00fcnlerini satabilmektedirler. Bu sat\u0131\u015flar\u0131n\u0131 daha geni\u015f bir alanda yapabilmek ve farkl\u0131 \u00fclkelere de satabilmek i\u00e7in ise, <strong>globalization<\/strong> konusu b\u00fcy\u00fck bir \u00f6nem ta\u015f\u0131maktad\u0131r.<\/p>\n<p>Bu makale i\u00e7erisinde ise\u00a0<strong>ASP.NET Core MVC<\/strong> ve <strong>Elasticsearch <\/strong>i\u00e7erisinde, nas\u0131l &#8220;<em>globalization<\/em>&#8221; deste\u011fini sa\u011flayabiliriz konusuna de\u011finmeye \u00e7al\u0131\u015faca\u011f\u0131m.<\/p>\n<p><a href=\"\/wp-content\/uploads\/2017\/12\/topic-globalization.jpg\"><img decoding=\"async\" class=\"aligncenter size-full wp-image-1933 lazyload\" data-src=\"\/wp-content\/uploads\/2017\/12\/topic-globalization.jpg\" alt=\"\" width=\"1000\" height=\"563\" data-srcset=\"https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2017\/12\/topic-globalization.jpg 1000w, https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2017\/12\/topic-globalization-300x169.jpg 300w, https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2017\/12\/topic-globalization-768x432.jpg 768w\" data-sizes=\"(max-width: 1000px) 100vw, 1000px\" src=\"data:image\/svg+xml;base64,PHN2ZyB3aWR0aD0iMSIgaGVpZ2h0PSIxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjwvc3ZnPg==\" style=\"--smush-placeholder-width: 1000px; --smush-placeholder-aspect-ratio: 1000\/563;\" \/><\/a><\/p>\n<h4>1) ASP.NET Core MVC&#8217;de Globalization<\/h4>\n<p>Globalization konusunun \u00f6nemiyle alakal\u0131 k\u00fc\u00e7\u00fck bir giri\u015f yapman\u0131n ard\u0131ndan, <em>ASP.NET Core<\/em>\u00a0<em>MVC<\/em> i\u00e7erisinde globalization i\u015flemlerini nas\u0131l ger\u00e7ekle\u015ftirebiliriz konusuna \u00f6ncelikle bir bakal\u0131m. Globalization konusunda <em>ASP.NET Core<\/em>, bize farkl\u0131 &#8220;dil&#8221; ve &#8220;culture&#8221; bilgileri i\u00e7in localization i\u015flemlerini ger\u00e7ekle\u015ftirebilmemiz ad\u0131na middleware ve servisler sunmaktad\u0131r.<\/p>\n<p>Localization i\u015flemini ger\u00e7ekle\u015ftirebilmek i\u00e7in uygulayaca\u011f\u0131m\u0131z \u00fc\u00e7 temel nokta bulunmaktad\u0131r:<\/p>\n<ol>\n<li>Uygulaman\u0131n content&#8217;ini &#8220;localizable&#8221; bir hale getirmek<\/li>\n<li>\u0130stenilen dil bilgileri i\u00e7in localize edilmi\u015f &#8220;resource&#8221; dosyalar\u0131na sahip olmak<\/li>\n<li>Son olarak da configure edip bir &#8220;implementasyon stratejisi&#8221; belirlememiz gerekmektedir<\/li>\n<\/ol>\n<p>Bu noktalardan yola \u00e7\u0131karak, uygulaman\u0131n content&#8217;ini nas\u0131l localizable bir hale getirebiliriz konusuna bir bakal\u0131m.<\/p>\n<blockquote><p><strong>NOT<\/strong>: \u00d6rnekler i\u00e7in &#8220;<em>ASP.NET Core Web App (Model-View-Controller)<\/em>&#8221; template&#8217;ini kullanaca\u011f\u0131m. &#8220;<em>dotnet new mvc<\/em>&#8220;<\/p><\/blockquote>\n<h5>1) Uygulaman\u0131n Content&#8217;ini Localizable Bir Hale Getirmek<\/h5>\n<p>Asl\u0131nda,\u00a0<strong>ASP.NET<\/strong> deki &#8220;<em>.resx<\/em>&#8221; resource dosyalar\u0131 ile benzerlik g\u00f6stermektedir. Hat\u0131rlarsak uygulama i\u00e7erisinde desteklenen her bir culture bilgisi i\u00e7in bir &#8220;<em>.resx<\/em>&#8221; resource dosyas\u0131 ekliyorduk. Ard\u0131ndan ise &#8220;<em>Resources.Name<\/em>&#8221; \u015feklinde eri\u015fim sa\u011flayarak, culture bilgisine uygun olan localize edilmi\u015f content&#8217;i kullan\u0131yorduk.<\/p>\n<p><em>ASP.NET Core<\/em> i\u00e7erisinde ise localize edilmi\u015f content&#8217;i alabilmek i\u00e7in &#8220;<em>Resources.Name<\/em>&#8221; yakla\u015f\u0131m\u0131 yerine, &#8220;<strong>IStringLocalizer<\/strong>&#8221; ve &#8220;<strong>IStringLocalizer<\/strong>&#8221; tipinde iki adet abstraction bulunmaktad\u0131r.<\/p>\n<p>\u00d6rne\u011fin:<\/p>\n<pre class=\"lang:c# decode:true\">public class TodoController : Controller\r\n{\r\n    private readonly IStringLocalizer&lt;TodoController&gt; _localizer;\r\n\r\n    public TodoController(IStringLocalizer&lt;TodoController&gt; localizer)\r\n    {\r\n        _localizer = localizer;\r\n    }\r\n\r\n    public IActionResult Index()\r\n    {\r\n        string hello = _localizer[\"Hello!\"];\r\n\r\n        return View(hello);\r\n    }\r\n}<\/pre>\n<p>Localizer&#8217;\u0131n kullan\u0131m\u0131na dikkat ettiniz mi? Localizer&#8217;\u0131n i\u00e7erisine bir key set etmek yerine, bir content set ettik. <em>ASP.NET Core<\/em> i\u00e7erisindeki en b\u00fcy\u00fck fark ise, istenilen culture bilgisi i\u00e7in localize bir content bulunamaz ise, i\u00e7erisine set edilen content&#8217;i resource olarak kullanmaktad\u0131r. Bu sayede main culture bilgisi i\u00e7in bir resource dosyas\u0131 olu\u015fturmaya gerek kalmamaktad\u0131r. Tabi code review&#8217;lar s\u0131ras\u0131nda <strong>magic string&#8217;lere<\/strong> tak\u0131nt\u0131l\u0131 biri olarak, bu durumdan pek ho\u015fland\u0131\u011f\u0131m\u0131 s\u00f6yleyemem. :)<\/p>\n<blockquote><p><strong>NOT<\/strong>: <em>HTML<\/em> i\u00e7eren content&#8217;ler i\u00e7in ise, &#8220;<em>IHtmlLocalizer<\/em>&#8221; ve &#8220;<em>IHtmlLocalizer<\/em>&#8221; tipleri de bulunmaktad\u0131r.<\/p><\/blockquote>\n<p>Farkl\u0131 tiplerdeki localizer&#8217;lara eri\u015febilmek i\u00e7in ise birde &#8220;<strong>IStringLocalizerFactory<\/strong>&#8221; bulunmaktad\u0131r.<\/p>\n<p>\u00d6rne\u011fin shared resource&#8217;lara eri\u015febilmek i\u00e7in, a\u015fa\u011f\u0131daki gibi kullanabilmekteyiz.<\/p>\n<pre class=\"lang:c# decode:true\">public class TodoController : Controller\r\n{\r\n    private readonly IStringLocalizer _localizerForShared;\r\n\r\n    public CulturesController(IStringLocalizerFactory localizerFactory)\r\n    {\r\n        _localizerForShared = localizerFactory.Create(typeof(SharedResource));\r\n\r\n    }\r\n}<\/pre>\n<p>Factory \u00fczerinde bulunan &#8220;<em>Create<\/em>&#8221; method&#8217;u ile, istenilen resource i\u00e7in bir localizer olu\u015fturabiliriz.<\/p>\n<p>View localization k\u0131sm\u0131na bakt\u0131\u011f\u0131m\u0131zda ise,\u00a0servis olarak kullanabilece\u011fimiz\u00a0&#8220;<strong>IViewLocalizer<\/strong>&#8221; bulunmaktad\u0131r. &#8220;<em>ViewLocalizer<\/em>&#8221; ise &#8220;<em>IHtmlLocalizer<\/em>&#8221; \u0131 implemente etmektedir. Bu noktada <em>Razor<\/em>, parametreler hari\u00e7 localize edilmi\u015f string&#8217;i <em>HTML<\/em> encode yapmamaktad\u0131r.<\/p>\n<p>\u00d6rnek bir view&#8217;a bakal\u0131m:<\/p>\n<pre class=\"lang:default decode:true\">@using Microsoft.AspNetCore.Mvc.Localization\r\n\r\n@inject IViewLocalizer Localizer\r\n\r\n@Localizer[\"&lt;h1&gt;Selam {0}&lt;\/h1&gt;\", \"&lt;b&gt;G\u00f6khan&lt;\/b&gt;\"]<\/pre>\n<p>Yukar\u0131daki localize edilmi\u015f string&#8217;in \u00e7\u0131kt\u0131s\u0131, a\u015fa\u011f\u0131daki gibi olacakt\u0131r.<\/p>\n<p><a href=\"\/wp-content\/uploads\/2017\/12\/aspnet-core-razor-html.png\"><img decoding=\"async\" class=\"aligncenter size-full wp-image-2026 lazyload\" data-src=\"\/wp-content\/uploads\/2017\/12\/aspnet-core-razor-html.png\" alt=\"\" width=\"1986\" height=\"374\" data-srcset=\"https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2017\/12\/aspnet-core-razor-html.png 1986w, https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2017\/12\/aspnet-core-razor-html-300x56.png 300w, https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2017\/12\/aspnet-core-razor-html-768x145.png 768w, https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2017\/12\/aspnet-core-razor-html-1024x193.png 1024w\" data-sizes=\"(max-width: 1986px) 100vw, 1986px\" src=\"data:image\/svg+xml;base64,PHN2ZyB3aWR0aD0iMSIgaGVpZ2h0PSIxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjwvc3ZnPg==\" style=\"--smush-placeholder-width: 1986px; --smush-placeholder-aspect-ratio: 1986\/374;\" \/><\/a><\/p>\n<p>\u00c7\u0131kt\u0131ya bakt\u0131\u011f\u0131m\u0131zda ise <em>Razor<\/em>&#8216;\u0131n, parametre de\u011ferleri hari\u00e7 localize edilmi\u015f string&#8217;i\u00a0<em>HTML<\/em> encode yapmad\u0131\u011f\u0131n\u0131 g\u00f6rmekteyiz.<\/p>\n<p>View&#8217;lar\u0131 en basit haliyle nas\u0131l localize edebilece\u011fimizi g\u00f6rd\u00fck. \u015eimdi birde\u00a0<strong>Data Annotations<\/strong>&#8216;lar\u0131n localization konusuna bir bakal\u0131m. Bu noktada ise yine i\u015fimiz gayet basittir. <em>ASP.NET Core<\/em> i\u00e7erisinde data annotations&#8217;lar hali haz\u0131rda &#8220;<strong>IStringLocalizer&lt;T&gt;&lt;<\/strong>&#8221; ile localize edilmi\u015f durumdad\u0131r.<\/p>\n<p>\u00d6rne\u011fin:<\/p>\n<pre class=\"lang:default decode:true\">public class TodoModel\r\n{\r\n    [Required(ErrorMessage = \"This field is required.\")]\r\n    [Display(Name = \"Name\")]\r\n    public string Name { get; set; }\r\n}<\/pre>\n<p>Yukar\u0131daki gibi bir kullan\u0131mda &#8220;<em>This field is required.<\/em>&#8221; ve &#8220;<em>Name<\/em>&#8221; string&#8217;leri, istenilen culture&#8217;da bir resource dosyas\u0131 varsa bu de\u011ferler localize edilecektir.<\/p>\n<h5>2) Localize Edilmi\u015f Resource Dosyas\u0131 Olu\u015fturmak<\/h5>\n<p>Asl\u0131nda makalenin giri\u015finde de bahsetti\u011fim gibi localize edilmi\u015f resource dosyalar\u0131, <em>ASP.NET<\/em>&#8216;deki &#8220;<em>.resx<\/em>&#8221; resource dosyalar\u0131 ile ayn\u0131d\u0131r. <em>Visual Studio<\/em> \u00fczerinden, a\u015fa\u011f\u0131daki gibi ekleyebilmekteyiz.<\/p>\n<p><a href=\"\/wp-content\/uploads\/2017\/12\/resource-file-add.jpg\"><img decoding=\"async\" class=\"aligncenter size-full wp-image-2028 lazyload\" data-src=\"\/wp-content\/uploads\/2017\/12\/resource-file-add.jpg\" alt=\"\" width=\"1787\" height=\"889\" data-srcset=\"https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2017\/12\/resource-file-add.jpg 1787w, https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2017\/12\/resource-file-add-300x149.jpg 300w, https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2017\/12\/resource-file-add-768x382.jpg 768w, https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2017\/12\/resource-file-add-1024x509.jpg 1024w\" data-sizes=\"(max-width: 1787px) 100vw, 1787px\" src=\"data:image\/svg+xml;base64,PHN2ZyB3aWR0aD0iMSIgaGVpZ2h0PSIxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjwvc3ZnPg==\" style=\"--smush-placeholder-width: 1787px; --smush-placeholder-aspect-ratio: 1787\/889;\" \/><\/a><\/p>\n<blockquote><p><strong>NOT<\/strong>: Hen\u00fcz <em>Visual Studio Code<\/em> ve <em>Visual Studio for MAC<\/em> \u00fczerinden eklenememektedir. :(<\/p><\/blockquote>\n<p>Bu noktada dikkat etmemiz gereken \u00f6nemli unsurlardan birisi, resource dosyalar\u0131n\u0131n isimlendirilmesidir.<\/p>\n<p>Hem class&#8217;lar\u0131n hem de view&#8217;lar\u0131n i\u00e7erisinde kullanm\u0131\u015f oldu\u011fumuz localizer&#8217;lar, iki farkl\u0131 y\u00f6ntemle localize edilmi\u015f resource&#8217;lara eri\u015fim sa\u011flamaktad\u0131r.<\/p>\n<ol>\n<li>Fully-qualified class name&#8217;inden eri\u015febilmektedir. \u00d6rne\u011fin: &#8220;<em>Controllers.TodoController.en-US.resx<\/em>&#8221; &#8211; &#8220;<em>Views.Todo.Index-en-US.resx<\/em>&#8220;<\/li>\n<li>Folder structure&#8217;\u0131 \u00fczerinden de eri\u015febilmektedir. \u00d6rne\u011fin: &#8220;<em>Resources\/Controllers\/TodoController.en-US.resx&#8221; &#8211; &#8220;Resources\/Views\/Todo\/Index.en-US.resx&#8221;<\/em><\/li>\n<\/ol>\n<p>Buradaki kullan\u0131m tercihi tamamen bize kalm\u0131\u015f durumdad\u0131r.<\/p>\n<h5>3) Configurasyon ve Implementasyon Stratejisi<\/h5>\n<p>Bu noktaya kadar content&#8217;leri nas\u0131l localize bir hale getirebiliriz konular\u0131na bakt\u0131k. \u015eimdi ise localization servislerini, uygulama i\u00e7erisine nas\u0131l ekleyebiliriz ve configure edebiliriz k\u0131s\u0131mlar\u0131na de\u011finece\u011fiz.<\/p>\n<p>\u0130lk olarak resource dosyalar\u0131 i\u00e7in olan path&#8217;i,\u00a0<em>Startup<\/em> class&#8217;\u0131 i\u00e7erisinde a\u015fa\u011f\u0131daki gibi belirleyebilmek m\u00fcmk\u00fcnd\u00fcr.<\/p>\n<pre class=\"lang:default decode:true\">public void ConfigureServices(IServiceCollection services)\r\n{\r\n    services.AddLocalization(options =&gt; {\r\n        options.ResourcesPath = \"Resources\";\r\n    });\r\n}<\/pre>\n<blockquote><p><strong>NOT<\/strong>: E\u011fer herhangi bir path set etmez isek, localization servisi culture resource&#8217;lar\u0131n\u0131 uygulaman\u0131n root folder&#8217;\u0131 alt\u0131nda arayacakt\u0131r.<\/p><\/blockquote>\n<p>View&#8217;lar i\u00e7in localization&#8217;\u0131 etkinle\u015ftirebilmek ise localization servisini a\u015fa\u011f\u0131daki gibi service collection&#8217;\u0131na ekleyebiliriz.<\/p>\n<pre class=\"lang:default decode:true\">public void ConfigureServices(IServiceCollection services)\r\n{\r\n    services.AddMvc()\r\n    .AddViewLocalization()\r\n}<\/pre>\n<p>E\u011fer resource dosyalar\u0131 olu\u015fturmak yerine culture&#8217;lara g\u00f6re farkl\u0131 view&#8217;lar olu\u015fturmak istersek, &#8220;<em>LanguageViewLocationExpanderFormat<\/em>&#8221; parametresi ile m\u00fcmk\u00fcnd\u00fcr.<\/p>\n<pre class=\"lang:default decode:true\">public void ConfigureServices(IServiceCollection services)\r\n{\r\n    services.AddMvc()\r\n    .AddViewLocalization(LanguageViewLocationExpanderFormat.Suffix)\r\n}<\/pre>\n<p>&#8220;<em>LanguageViewLocationExpanderFormat<\/em>&#8221; enum&#8217;\u0131, &#8220;<em>SubFolder<\/em>&#8221; ve &#8220;<em>Suffix<\/em>&#8221; de\u011ferlerine sahiptir.<\/p>\n<ul>\n<li>Suffix: &#8220;<em>Todo.en-US.cshtml<\/em>&#8220;<\/li>\n<li>SubFolder: &#8220;<em>en-US\/Todo.cshtml<\/em>&#8220;<\/li>\n<\/ul>\n<p>Data annotation&#8217;lar i\u00e7in ise localization&#8217;\u0131, &#8220;<em>AddDataAnnotationsLocalization<\/em>&#8221; method&#8217;u sa\u011flayabiliriz:<\/p>\n<pre class=\"lang:default decode:true\">public void ConfigureServices(IServiceCollection services)\r\n{\r\n    services.AddMvc()\r\n    .AddDataAnnotationsLocalization();\r\n}<\/pre>\n<p>Data annotation&#8217;lar i\u00e7in shared bir resource kullanmak istiyorsak e\u011fer, a\u015fa\u011f\u0131daki gibi configure etmemiz yeterli olacakt\u0131r.<\/p>\n<pre class=\"lang:default decode:true\">public void ConfigureServices(IServiceCollection services)\r\n{\r\n    services.AddMvc()\r\n    .AddDataAnnotationsLocalization(options =&gt;\r\n    {\r\n        options.DataAnnotationLocalizerProvider = (type, factory) =&gt; {\r\n            return factory.Create(typeof(SharedResource));\r\n        }\r\n    });\r\n}\r\n\r\npublic class SharedResource\r\n{\r\n}<\/pre>\n<p>&#8220;<em>Configure<\/em>&#8221; method&#8217;u i\u00e7erisinde eklememiz gereken bir di\u011fer \u00f6nemli middleware ise, <strong>Request Localization<\/strong> middleware&#8217;idir.<\/p>\n<pre class=\"lang:default decode:true\">public void Configure(IApplicationBuilder app, IHostingEnvironment env)\r\n{\r\n    var supportedCultures = new List\r\n    {\r\n        new CultureInfo(\"tr-TR\"),\r\n        new CultureInfo(\"en-US\"),\r\n    };\r\n\r\n    app.UseRequestLocalization(new RequestLocalizationOptions\r\n    {\r\n        DefaultRequestCulture = new RequestCulture(\"tr-TR\"),\r\n        SupportedCultures = supportedCultures,\r\n        SupportedUICultures = supportedCultures\r\n    });\r\n\r\n    app.UseMvc(routes =&gt;\r\n    {\r\n        routes.MapRoute(\r\n            name: \"default\",\r\n            template: \"{controller=Home}\/{action=Index}\/{id?}\");\r\n    });\r\n}<\/pre>\n<p>Burada uygulaman\u0131n destekleyece\u011fi culture bilgilerini ve default culture bilgisini belirleyebiliriz.<\/p>\n<p>Localization&#8217;\u0131n son k\u0131sm\u0131 olarak implementasyon stratejilerine bakaca\u011f\u0131z. Request localization middleware&#8217;i, current culture&#8217;\u0131 se\u00e7ebilmek i\u00e7in default olarak \u00fc\u00e7 farkl\u0131 opsiyona sahiptir.<\/p>\n<ol>\n<li><strong>QueryStringRequestCultureProvider<br \/>\n<\/strong>&#8220;<em>QueryStringRequestCultureProvider&#8221;<\/em>, &#8220;<em>RequestCultureProvider&#8221;<\/em> i\u00e7erisinde ilk provider olarak kay\u0131tl\u0131d\u0131r. Query string \u00fczerinden localization i\u015flemini ger\u00e7ekle\u015ftirmektedir. \u00d6rne\u011fin: &#8220;<em>http:\/\/localhost:5000\/?culture=en-US<\/em>&#8220;<\/li>\n<li><strong>CookieRequestCultureProvider<br \/>\n<\/strong><em>&#8220;CookieRequestCultureProvider&#8221;<\/em> ise kullan\u0131c\u0131n\u0131n se\u00e7mi\u015f oldu\u011fu culture&#8217;\u0131, cookie bilgisini kullanarak track edebilmeyi sa\u011flamaktad\u0131r.<\/li>\n<li><strong>AcceptLanguageHeaderRequestCultureProvider<br \/>\n<\/strong>&#8220;<em>AcceptLanguageHeaderRequestCultureProvider<\/em>&#8221; ise kullan\u0131c\u0131n\u0131n browser&#8217;\u0131nda \u00f6n tan\u0131ml\u0131 olarak gelen culture bilgisine g\u00f6re, uygulaman\u0131n localize edilmesini sa\u011flamaktad\u0131r.<\/li>\n<\/ol>\n<p>Opsiyonel olarak kullanabilece\u011fimiz birde, &#8220;<strong>RouteDataRequestCultureProvider<\/strong>&#8221; vard\u0131r. Bununla birlikte route \u00fczerinden\u00a0localize edebilmek m\u00fcmk\u00fcnd\u00fcr. \u00d6rne\u011fin:\u00a0&#8220;<em>http:\/\/localhost:5000\/en-US\/home<\/em>&#8221;<\/p>\n<p>Bunun i\u00e7in:<\/p>\n<pre class=\"lang:c# decode:true\">public void Configure(IApplicationBuilder app, IHostingEnvironment env)\r\n{\r\n    app.UseRouter(routes =&gt;\r\n    {\r\n        routes.MapMiddlewareRoute(\"{culture=tr-TR}\/{*mvcRoute}\", _app =&gt;\r\n        {\r\n            var supportedCultures = new List&lt;CultureInfo&gt;\r\n            {\r\n                new CultureInfo(\"tr-TR\"),\r\n                new CultureInfo(\"en-US\")                                   \r\n            };\r\n\r\n            var requestLocalizationOptions = new RequestLocalizationOptions\r\n            {\r\n                DefaultRequestCulture = new RequestCulture(\"tr-TR\"),\r\n                SupportedCultures = supportedCultures,\r\n                SupportedUICultures = supportedCultures\r\n            };\r\n\r\n            requestLocalizationOptions.RequestCultureProviders.Insert(0, new RouteDataRequestCultureProvider());\r\n            _app.UseRequestLocalization(requestLocalizationOptions);\r\n\r\n            _app.UseMvc(mvcRoutes =&gt;\r\n            {\r\n                mvcRoutes.MapRoute(\r\n                    name: \"default\",\r\n                    template: \"{culture=tr-TR}\/{controller=Home}\/{action=Index}\/{id?}\");\r\n            });\r\n        });\r\n    });\r\n}<\/pre>\n<p>Yukar\u0131daki kod blo\u011funa bakt\u0131\u011f\u0131m\u0131zda &#8220;<em>MapMiddlewareRoute<\/em>&#8221; method&#8217;u ile culture bilgisini, localization middleware&#8217;i \u00e7al\u0131\u015fmadan \u00f6nce yakal\u0131yoruz. Bunu yapmam\u0131z\u0131n sebebi ise, localization middleware&#8217;inin\u00a0<em>MVC<\/em> router&#8217;\u0131ndan \u00f6nce \u00e7al\u0131\u015f\u0131yor olmas\u0131d\u0131r. Ard\u0131ndan &#8220;<em>RouteDataRequestCultureProvider<\/em>&#8221; \u0131 ilk request culture provider&#8217;\u0131 olarak insert ederek, request localization middleware&#8217;ini configure ettik. Son olarak route template&#8217;i i\u00e7erisine ise birde culture bilgisini ekledik. Bu configuration ile, localization i\u015flemi route \u00fczerinden gelen culture bilgisi ile ger\u00e7ekle\u015ftirilecektir.<\/p>\n<blockquote><p><strong>NOT<\/strong>: Bu implementasyonlar\u0131 i\u00e7eren bir \u00f6rne\u011fi, makalenin sonunda payla\u015f\u0131yor olaca\u011f\u0131m.<\/p><\/blockquote>\n<h4>2) Elasticsearch \u0130\u00e7erisinde Globalization<\/h4>\n<p><a href=\"\/wp-content\/uploads\/2016\/07\/elasticsearch-nest.png\"><img decoding=\"async\" class=\"aligncenter wp-image-696 lazyload\" data-src=\"\/wp-content\/uploads\/2016\/07\/elasticsearch-nest.png\" alt=\"\" width=\"1084\" height=\"347\" data-srcset=\"https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2016\/07\/elasticsearch-nest.png 1500w, https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2016\/07\/elasticsearch-nest-300x96.png 300w, https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2016\/07\/elasticsearch-nest-1024x328.png 1024w\" data-sizes=\"(max-width: 1084px) 100vw, 1084px\" src=\"data:image\/svg+xml;base64,PHN2ZyB3aWR0aD0iMSIgaGVpZ2h0PSIxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjwvc3ZnPg==\" style=\"--smush-placeholder-width: 1084px; --smush-placeholder-aspect-ratio: 1084\/347;\" \/><\/a><\/p>\n<p><em>Elasticsearch<\/em> k\u0131sm\u0131nda ise her bir culture bilgisi i\u00e7in, <strong>farkl\u0131 index&#8217;ler<\/strong> olu\u015fturarak multi-language deste\u011fini sa\u011flayaca\u011f\u0131z. Burada tercih edebilece\u011finiz farkl\u0131 y\u00f6ntemlerde mevcut. \u00d6rne\u011fin tek bir index \u00fczerinde multi-field&#8217;lar ile multi-language deste\u011fini sa\u011flayabilmek gibi. Farkl\u0131 index&#8217;ler olu\u015fturarak multi-language deste\u011fi sa\u011flamak, ileride farkl\u0131 culture bilgilerinin de kolayl\u0131kla entegre olabilmesi a\u00e7\u0131s\u0131ndan kolayl\u0131k sa\u011flayacakt\u0131r. Buna ek olarak her bir dil bilgisi i\u00e7in analyzer&#8217;lar ayarlayabilmek de kolay olacakt\u0131r. (Ben daha \u00f6nce bu \u015fekilde kulland\u0131m)<\/p>\n<p>\u00d6rnek i\u00e7erisinde ASP.NET Core MVC i\u00e7erisinde <em>NEST<\/em> k\u00fct\u00fcphanesinin implementasyonunu ger\u00e7ekle\u015ftirece\u011fiz. \u00d6ncelikle &#8220;<em>IProductService<\/em>&#8221; isminde bir interface tan\u0131mlayal\u0131m.<\/p>\n<pre class=\"lang:default decode:true\">namespace ASPNETCoreAndESearch.Business\r\n{\r\n    public interface IProductService\r\n    {\r\n        Task CreateIndexAsync(string indexName);\r\n        Task&lt;bool&gt; IndexAsync(List&lt;Product&gt; products, string langCode);\r\n        Task&lt;ProductSearchResponse&gt; SearchAsync(string keyword, string langCode);\r\n    }\r\n}<\/pre>\n<p>&#8220;<em>CreateIndexAsync<\/em>&#8221; method&#8217;u ile bir index olu\u015fturup, &#8220;<em>IndexAsync<\/em>&#8221; method&#8217;u ile de product&#8217;lar\u0131 indexleyece\u011fiz. Ard\u0131ndan kullan\u0131c\u0131n\u0131n istedi\u011fi culture bilgisine g\u00f6re ise search i\u015flemini &#8220;SearchAsync&#8221; method&#8217;u ile ger\u00e7ekle\u015ftirece\u011fiz.<\/p>\n<p>\u015eimdi &#8220;<em>ProductService<\/em>&#8221; isminde bir class olu\u015ftural\u0131m ve a\u015fa\u011f\u0131daki gibi implemente edelim.<\/p>\n<pre class=\"lang:c# decode:true\">namespace ASPNETCoreAndESearch.Business\r\n{\r\n    public class ProductService : IProductService\r\n    {\r\n        private readonly ElasticClient _elasticClient;\r\n\r\n        public ProductService(ConnectionSettings connectionSettings)\r\n        {\r\n            _elasticClient = new ElasticClient(connectionSettings);\r\n        }\r\n\r\n        public async Task CreateIndexAsync(string indexName)\r\n        {\r\n            var createIndexDescriptor = new CreateIndexDescriptor(indexName.ToLowerInvariant())\r\n                                         .Mappings(m =&gt; m.Map&lt;Product&gt;(p =&gt; p.AutoMap()));\r\n\r\n            await _elasticClient.CreateIndexAsync(createIndexDescriptor);\r\n        }\r\n\r\n        public async Task&lt;bool&gt; IndexAsync(List&lt;Product&gt; products, string langCode)\r\n        {\r\n            string indexName = $\"products_{langCode}\";\r\n\r\n            IBulkResponse response = await _elasticClient.IndexManyAsync(products, indexName);\r\n\r\n            return response.IsValid;\r\n        }\r\n\r\n        public async Task&lt;ProductSearchResponse&gt; SearchAsync(string keyword, string langCode)\r\n        {\r\n            ProductSearchResponse productSearchResponse = new ProductSearchResponse();\r\n            string indexName = $\"products_{langCode}\";\r\n\r\n            ISearchResponse&lt;Product&gt; searchResponse = await _elasticClient.SearchAsync&lt;Product&gt;(x =&gt; x\r\n                .Index(indexName)\r\n                .Query(q =&gt;\r\n                            q.MultiMatch(mp =&gt; mp\r\n                                        .Query(keyword)\r\n                                        .Fields(f =&gt; f.Fields(f1 =&gt; f1.Name, f2 =&gt; f2.Description)))\r\n                ));\r\n\r\n            if (searchResponse.IsValid &amp;&amp; searchResponse.Documents != null)\r\n            {\r\n                productSearchResponse.Total = (int)searchResponse.Total;\r\n                productSearchResponse.Products = searchResponse.Documents;\r\n            }\r\n\r\n            return productSearchResponse;\r\n        }\r\n    }\r\n}<\/pre>\n<p>&#8220;<em>IndexAsync<\/em>&#8221; method&#8217;u ile &#8220;<em>products_{langCode}<\/em>&#8221; \u015feklinde bir index name olu\u015fturduk ve product&#8217;lar\u0131 bu index name ile indexleyece\u011fiz. &#8220;<em>SearchAsync<\/em>&#8221; method&#8217;u ile ise, istenilen dil bilgisine g\u00f6re &#8220;<em>Name<\/em>&#8221; ve &#8220;<em>Description<\/em>&#8221; field&#8217;lar\u0131 \u00fczerinde full text search i\u015flemini ger\u00e7ekle\u015ftirece\u011fiz.<\/p>\n<p>\u00d6rnek olarak a\u015fa\u011f\u0131daki gibi bir controller olu\u015ftural\u0131m.<\/p>\n<pre class=\"lang:c# decode:true\">namespace ASPNETCoreAndESearch.Controllers\r\n{\r\n    public class HomeController : Controller\r\n    {\r\n        private readonly IProductService _productService;\r\n\r\n        public HomeController(IProductService productService)\r\n        {\r\n            _productService = productService;\r\n        }\r\n        \r\n        public async Task&lt;IActionResult&gt; Index()\r\n        {   \r\n            string indexName = $\"products\";\r\n            await FeedProductsInTurkish(indexName, \"tr\");\r\n            await FeedProductsInEnglish(indexName, \"en\");\r\n\r\n            return View();\r\n        }\r\n\r\n        public async Task&lt;IActionResult&gt; Products(string keyword)\r\n        {\r\n            var requestCultureFeature = Request.HttpContext.Features.Get&lt;IRequestCultureFeature&gt;();\r\n            CultureInfo culture = requestCultureFeature.RequestCulture.Culture;\r\n    \r\n            ProductSearchResponse productSearchResponse = await _productService.SearchAsync(keyword, culture.TwoLetterISOLanguageName);\r\n\r\n            return View(productSearchResponse);\r\n        }\r\n\r\n        private async Task FeedProductsInTurkish(string indexName, string lang)\r\n        {\r\n            List&lt;Product&gt; products = new List&lt;Product&gt;\r\n            {\r\n                new Product\r\n                {\r\n                    ProductId = 1,\r\n                    Name = \"Iphone X Cep Telefonu\",\r\n                    Description = \"G\u00fcm\u00fc\u015f renk, 128 GB\",\r\n                    Price = 6000\r\n                },\r\n                new Product\r\n                {\r\n                    ProductId = 2,\r\n                    Name = \"Iphone X Cep Telefonu\",\r\n                    Description = \"Uzay grisi rengi, 128 GB\",\r\n                    Price = 6000\r\n                },\r\n                new Product\r\n                {\r\n                    ProductId = 3,\r\n                    Name = \"Rayban Erkek G\u00f6zl\u00fck\",\r\n                    Description = \"Ye\u015fil renk\"\r\n                },\r\n                new Product\r\n                {\r\n                    ProductId = 4,\r\n                    Name = \"Rayban Kad\u0131n G\u00f6zl\u00fck\",\r\n                    Description = \"Gri renk\"\r\n                }\r\n            };\r\n\r\n            await _productService.CreateIndexAsync($\"{indexName}_{lang}\");\r\n            await _productService.IndexAsync(products, lang);\r\n        }\r\n\r\n        private async Task FeedProductsInEnglish(string indexName, string lang)\r\n        {\r\n            List&lt;Product&gt; products = new List&lt;Product&gt;\r\n            {\r\n                new Product\r\n                {\r\n                    ProductId = 1,\r\n                    Name = \"Iphone X Mobile Phone\",\r\n                    Description = \"Silver color, 128 GB\",\r\n                    Price = 6000\r\n                },\r\n                new Product\r\n                {\r\n                    ProductId = 2,\r\n                    Name = \"Iphone X Mobile Phone\",\r\n                    Description = \"Space gray color, 128 GB\",\r\n                    Price = 6000\r\n                },\r\n                new Product\r\n                {\r\n                    ProductId = 3,\r\n                    Name = \"Rayban Men's Glasses\",\r\n                    Description = \"Green color\"\r\n                },\r\n                new Product\r\n                {\r\n                    ProductId = 4,\r\n                    Name = \"Rayban Women's Glasses\",\r\n                    Description = \"Gray color\"\r\n                }\r\n            };\r\n\r\n            await _productService.CreateIndexAsync($\"{indexName}_{lang}\");\r\n            await _productService.IndexAsync(products, lang);\r\n        }\r\n    }\r\n}<\/pre>\n<p>Controller&#8217;\u0131n &#8220;<em>Index<\/em>&#8221; method&#8217;u i\u00e7erisinde <strong>T\u00fcrk\u00e7e<\/strong> ve <strong>\u0130ngilizce<\/strong> culture&#8217;lar\u0131 i\u00e7in bir index olu\u015fturaca\u011f\u0131z ve product&#8217;lar\u0131 olu\u015fturulan bu index&#8217;e feed edece\u011fiz. &#8220;<em>Products<\/em>&#8221; action i\u00e7erisinde ise query string \u00fczerinden alacak oldu\u011fumuz &#8220;<em>keyword<\/em>&#8221; ile, culture&#8217;a uygun product index&#8217;i \u00fczerinden search i\u015flemini ger\u00e7ekle\u015ftirece\u011fiz.<\/p>\n<p>&#8220;<em>Products<\/em>&#8221; action i\u00e7in ise a\u015fa\u011f\u0131daki gibi bir view olu\u015ftural\u0131m.<\/p>\n<pre class=\"lang:default decode:true\">@model ProductSearchResponse\r\n@using Microsoft.AspNetCore.Mvc.Localization\r\n@inject IViewLocalizer Localizer\r\n\r\n&lt;div class=\"container\"&gt;\r\n  &lt;h3&gt;@Localizer[\"Toplam {0} \u00fcr\u00fcn bulundu.\", Model.Total]&lt;\/h3&gt;\r\n  &lt;table class=\"table\"&gt;\r\n    &lt;thead&gt;\r\n      &lt;tr&gt;\r\n        &lt;th&gt;Id&lt;\/th&gt;\r\n        &lt;th&gt;@Localizer[\"\u0130sim\"]&lt;\/th&gt;\r\n        &lt;th&gt;@Localizer[\"A\u00e7\u0131klama\"]&lt;\/th&gt;\r\n        &lt;th&gt;@Localizer[\"Fiyat\"]&lt;\/th&gt;\r\n        &lt;th&gt;&lt;\/th&gt;\r\n      &lt;\/tr&gt;\r\n    &lt;\/thead&gt;\r\n    &lt;tbody&gt;\r\n        @foreach(var product in Model.Products)\r\n        {\r\n          &lt;tr&gt;\r\n            &lt;td&gt;@product.ProductId&lt;\/td&gt;\r\n            &lt;td&gt;@product.Name&lt;\/td&gt;\r\n            &lt;td&gt;@product.Description&lt;\/td&gt;\r\n            &lt;td&gt;@product.Price&lt;\/td&gt;\r\n          &lt;\/tr&gt;\r\n        }\r\n    &lt;\/tbody&gt;\r\n  &lt;\/table&gt;\r\n&lt;\/div&gt;<\/pre>\n<p><em>Docker<\/em> \u00fczerinde test i\u015flemleri i\u00e7in single-node olarak bir\u00a0<em>Elasticsearch<\/em>\u00a0\u00e7al\u0131\u015ft\u0131ral\u0131m.<\/p>\n<pre class=\"lang:default decode:true \">docker run -p 9200:9200 -p 9300:9300 -e \"discovery.type=single-node\" docker.elastic.co\/elasticsearch\/elasticsearch:6.0.1<\/pre>\n<p>Son olarak &#8220;<em>Startup<\/em>&#8221; class&#8217;\u0131 i\u00e7erisinde ise, &#8220;<em>ProductService<\/em>&#8221; ve &#8220;<em>ConnectionSettings<\/em>&#8221; class&#8217;lar\u0131n\u0131n service collection&#8217;\u0131na injection i\u015flemini a\u015fa\u011f\u0131daki gibi ger\u00e7ekle\u015ftirelim.<\/p>\n<pre class=\"lang:default decode:true\">public void ConfigureServices(IServiceCollection services)\r\n{\r\n    services.AddMvc();\r\n\r\n    services.AddSingleton(x =&gt; new ConnectionSettings(new Uri(\"http:\/\/localhost:9200\")));\r\n    services.AddTransient&lt;IProductService, ProductService&gt;();\r\n}<\/pre>\n<p>\u0130\u015fte bu kadar.<\/p>\n<p>\u015eimdi projeyi &#8220;<em>dotnet run<\/em>&#8221; komut sat\u0131r\u0131 ile \u00e7al\u0131\u015ft\u0131ral\u0131m. Ard\u0131ndan\u00a0&#8220;<em>http:\/\/localhost:5000\/tr-TR\/home<\/em>&#8221; URL&#8217;ine girelim. B\u00f6ylece product index&#8217;i olu\u015fturulacak ve product dok\u00fcmanlar\u0131 indexlenecektir.<\/p>\n<p>\u015eimdi search i\u015flemi i\u00e7in &#8220;<em>http:\/\/localhost:5000\/tr-TR\/home\/products?keyword=Cep Telefonu<\/em>&#8221; URL&#8217;ine browser \u00fczerinden girelim ve sonucuna bakal\u0131m.<\/p>\n<p><a href=\"\/wp-content\/uploads\/2017\/12\/localization-tr.png\"><img decoding=\"async\" class=\"aligncenter size-full wp-image-1976 lazyload\" data-src=\"\/wp-content\/uploads\/2017\/12\/localization-tr.png\" alt=\"\" width=\"2118\" height=\"580\" data-srcset=\"https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2017\/12\/localization-tr.png 2118w, https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2017\/12\/localization-tr-300x82.png 300w, https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2017\/12\/localization-tr-768x210.png 768w, https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2017\/12\/localization-tr-1024x280.png 1024w\" data-sizes=\"(max-width: 2118px) 100vw, 2118px\" src=\"data:image\/svg+xml;base64,PHN2ZyB3aWR0aD0iMSIgaGVpZ2h0PSIxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjwvc3ZnPg==\" style=\"--smush-placeholder-width: 2118px; --smush-placeholder-aspect-ratio: 2118\/580;\" \/><\/a><\/p>\n<p>E\u011fer response&#8217;a bakarsak,\u00a0resource&#8217;lar\u0131n culture&#8217;a g\u00f6re localize edildi\u011fini, ayr\u0131ca product result&#8217;lar\u0131n\u0131n da &#8220;<em>products_tr<\/em>&#8221; index&#8217;i i\u00e7erisinde arand\u0131\u011f\u0131n\u0131 g\u00f6rebiliriz.<\/p>\n<p>Culture bilgisini birde &#8220;<em>en-US<\/em>&#8220;, keyword&#8217;\u00fc ise &#8220;<em>Cell Phone<\/em>&#8221; olarak de\u011fi\u015ftirelim ve response&#8217;a tekrar bir bakal\u0131m. URL ise: &#8220;<em>http:\/\/localhost:5000\/en-US\/home\/products?keyword=Cell Phone<\/em>&#8220;.<\/p>\n<p><a href=\"\/wp-content\/uploads\/2017\/12\/localization-en.png\"><img decoding=\"async\" class=\"aligncenter size-full wp-image-1977 lazyload\" data-src=\"\/wp-content\/uploads\/2017\/12\/localization-en.png\" alt=\"\" width=\"2106\" height=\"584\" data-srcset=\"https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2017\/12\/localization-en.png 2106w, https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2017\/12\/localization-en-300x83.png 300w, https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2017\/12\/localization-en-768x213.png 768w, https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2017\/12\/localization-en-1024x284.png 1024w\" data-sizes=\"(max-width: 2106px) 100vw, 2106px\" src=\"data:image\/svg+xml;base64,PHN2ZyB3aWR0aD0iMSIgaGVpZ2h0PSIxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjwvc3ZnPg==\" style=\"--smush-placeholder-width: 2106px; --smush-placeholder-aspect-ratio: 2106\/584;\" \/><\/a><\/p>\n<p>\u015eimdi ise resource&#8217;lar &#8220;<em>en-US<\/em>&#8221; culture&#8217;\u0131 i\u00e7in localize olmu\u015f durumda ve product result&#8217;lar\u0131 ise &#8220;<em>products_en<\/em>&#8221; index&#8217;i i\u00e7erisinde aranm\u0131\u015ft\u0131r.<\/p>\n<p>\u00d6rnek projeye ise buradan ula\u015fabilirsiniz:\u00a0<a href=\"https:\/\/github.com\/GokGokalp\/Globalization-In-ASP.NET-Core-MVC-And-Elasticsearch\" target=\"_blank\" rel=\"noopener\">https:\/\/github.com\/GokGokalp\/Globalization-In-ASP.NET-Core-MVC-And-Elasticsearch<\/a><\/p>\n<h5>Referanslar<\/h5>\n<blockquote><p>https:\/\/docs.microsoft.com\/en-us\/aspnet\/core\/fundamentals\/localization<\/p>\n<p>https:\/\/joonasw.net\/view\/aspnet-core-localization-deep-dive<\/p><\/blockquote>\n","protected":false},"excerpt":{"rendered":"<p>Merhaba arkada\u015flar. Biliyoruz ki g\u00fcn\u00fcm\u00fcz teknoloji \u00e7a\u011f\u0131nda firmalar, e-ticaret siteleri \u00fczerinden hi\u00e7 tan\u0131mad\u0131\u011f\u0131 ve farkl\u0131 \u015fehirdeki insanlara \u00fcr\u00fcnlerini satabilmektedirler. Bu sat\u0131\u015flar\u0131n\u0131 daha geni\u015f bir alanda yapabilmek ve farkl\u0131 \u00fclkelere de satabilmek i\u00e7in ise, globalization konusu b\u00fcy\u00fck bir \u00f6nem ta\u015f\u0131maktad\u0131r. Bu makale i\u00e7erisinde ise\u00a0ASP.NET Core MVC&#8230;<\/p>\n<div class=\"more-link-wrapper\"><a class=\"more-link\" href=\"https:\/\/gokhan-gokalp.com\/tr\/globalization-in-aspnet-core-and-elasticsearch\/\">Devam\u0131n\u0131 okuyun<span class=\"screen-reader-text\">ASP.NET Core MVC ve Elasticsearch&#8217;de Globalization<\/span><\/a><\/div>\n","protected":false},"author":1,"featured_media":1933,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[417,193],"tags":[419,464,467,470,194,465,466,469,468],"class_list":["post-1931","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-asp-net-core","category-search-engine","tag-asp-net-core","tag-asp-net-core-elasticsearch","tag-asp-net-core-globalization","tag-asp-net-core-mvc","tag-elasticsearch","tag-globalization","tag-globalization-elasticsearch","tag-localization-elasticsearch","tag-multilanguage-elasticsearch","entry"],"translation":{"provider":"WPGlobus","version":"3.0.2","language":"tr","enabled_languages":["en","tr"],"languages":{"en":{"title":true,"content":true,"excerpt":false},"tr":{"title":true,"content":true,"excerpt":false}}},"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.3 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>ASP.NET Core MVC ve Elasticsearch&#039;de Globalization - G\u00f6khan G\u00f6kalp<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/gokhan-gokalp.com\/globalization-in-aspnet-core-and-elasticsearch\/\" \/>\n<meta property=\"og:locale\" content=\"tr_TR\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"ASP.NET Core MVC ve Elasticsearch&#039;de Globalization - G\u00f6khan G\u00f6kalp\" \/>\n<meta property=\"og:url\" content=\"https:\/\/gokhan-gokalp.com\/globalization-in-aspnet-core-and-elasticsearch\/\" \/>\n<meta property=\"og:site_name\" content=\"G\u00f6khan G\u00f6kalp\" \/>\n<meta property=\"article:published_time\" content=\"2017-12-17T14:19:29+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2017\/12\/topic-globalization.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"1000\" \/>\n\t<meta property=\"og:image:height\" content=\"563\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"author\" content=\"G\u00f6khan G\u00f6kalp\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Yazan:\" \/>\n\t<meta name=\"twitter:data1\" content=\"G\u00f6khan G\u00f6kalp\" \/>\n\t<meta name=\"twitter:label2\" content=\"Tahmini okuma s\u00fcresi\" \/>\n\t<meta name=\"twitter:data2\" content=\"24 dakika\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/gokhan-gokalp.com\\\/globalization-in-aspnet-core-and-elasticsearch\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/gokhan-gokalp.com\\\/globalization-in-aspnet-core-and-elasticsearch\\\/\"},\"author\":{\"name\":\"G\u00f6khan G\u00f6kalp\",\"@id\":\"https:\\\/\\\/gokhan-gokalp.com\\\/#\\\/schema\\\/person\\\/7e2a7fa98babd22a5fdae563c4b8cdbe\"},\"headline\":\"ASP.NET Core MVC ve Elasticsearch&#8217;de Globalization\",\"datePublished\":\"2017-12-17T14:19:29+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/gokhan-gokalp.com\\\/globalization-in-aspnet-core-and-elasticsearch\\\/\"},\"wordCount\":3138,\"commentCount\":4,\"publisher\":{\"@id\":\"https:\\\/\\\/gokhan-gokalp.com\\\/#\\\/schema\\\/person\\\/7e2a7fa98babd22a5fdae563c4b8cdbe\"},\"image\":{\"@id\":\"https:\\\/\\\/gokhan-gokalp.com\\\/globalization-in-aspnet-core-and-elasticsearch\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/gokhan-gokalp.com\\\/wp-content\\\/uploads\\\/2017\\\/12\\\/topic-globalization.jpg\",\"keywords\":[\"asp.net core\",\"asp.net core elasticsearch\",\"asp.net core globalization\",\"asp.net core mvc\",\"elasticsearch\",\"globalization\",\"globalization elasticsearch\",\"localization elasticsearch\",\"multilanguage elasticsearch\"],\"articleSection\":[\"ASP.NET Core\",\"Search Engine\"],\"inLanguage\":\"tr\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/gokhan-gokalp.com\\\/globalization-in-aspnet-core-and-elasticsearch\\\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/gokhan-gokalp.com\\\/globalization-in-aspnet-core-and-elasticsearch\\\/\",\"url\":\"https:\\\/\\\/gokhan-gokalp.com\\\/globalization-in-aspnet-core-and-elasticsearch\\\/\",\"name\":\"ASP.NET Core MVC ve Elasticsearch'de Globalization - G\u00f6khan G\u00f6kalp\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/gokhan-gokalp.com\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/gokhan-gokalp.com\\\/globalization-in-aspnet-core-and-elasticsearch\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/gokhan-gokalp.com\\\/globalization-in-aspnet-core-and-elasticsearch\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/gokhan-gokalp.com\\\/wp-content\\\/uploads\\\/2017\\\/12\\\/topic-globalization.jpg\",\"datePublished\":\"2017-12-17T14:19:29+00:00\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/gokhan-gokalp.com\\\/globalization-in-aspnet-core-and-elasticsearch\\\/#breadcrumb\"},\"inLanguage\":\"tr\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/gokhan-gokalp.com\\\/globalization-in-aspnet-core-and-elasticsearch\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"tr\",\"@id\":\"https:\\\/\\\/gokhan-gokalp.com\\\/globalization-in-aspnet-core-and-elasticsearch\\\/#primaryimage\",\"url\":\"https:\\\/\\\/gokhan-gokalp.com\\\/wp-content\\\/uploads\\\/2017\\\/12\\\/topic-globalization.jpg\",\"contentUrl\":\"https:\\\/\\\/gokhan-gokalp.com\\\/wp-content\\\/uploads\\\/2017\\\/12\\\/topic-globalization.jpg\",\"width\":1000,\"height\":563},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/gokhan-gokalp.com\\\/globalization-in-aspnet-core-and-elasticsearch\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/gokhan-gokalp.com\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Globalization in ASP.NET Core MVC and Elasticsearch\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/gokhan-gokalp.com\\\/#website\",\"url\":\"https:\\\/\\\/gokhan-gokalp.com\\\/\",\"name\":\"G\u00f6khan G\u00f6kalp\",\"description\":\"C# &amp; Python lover\",\"publisher\":{\"@id\":\"https:\\\/\\\/gokhan-gokalp.com\\\/#\\\/schema\\\/person\\\/7e2a7fa98babd22a5fdae563c4b8cdbe\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/gokhan-gokalp.com\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"tr\"},{\"@type\":[\"Person\",\"Organization\"],\"@id\":\"https:\\\/\\\/gokhan-gokalp.com\\\/#\\\/schema\\\/person\\\/7e2a7fa98babd22a5fdae563c4b8cdbe\",\"name\":\"G\u00f6khan G\u00f6kalp\",\"pronouns\":\"he\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"tr\",\"@id\":\"https:\\\/\\\/gokhan-gokalp.com\\\/wp-content\\\/litespeed\\\/avatar\\\/e645f66b6264ced10d7b6d8b1f85509b.jpg?ver=1776170659\",\"url\":\"https:\\\/\\\/gokhan-gokalp.com\\\/wp-content\\\/litespeed\\\/avatar\\\/e645f66b6264ced10d7b6d8b1f85509b.jpg?ver=1776170659\",\"contentUrl\":\"https:\\\/\\\/gokhan-gokalp.com\\\/wp-content\\\/litespeed\\\/avatar\\\/e645f66b6264ced10d7b6d8b1f85509b.jpg?ver=1776170659\",\"caption\":\"G\u00f6khan G\u00f6kalp\"},\"logo\":{\"@id\":\"https:\\\/\\\/gokhan-gokalp.com\\\/wp-content\\\/litespeed\\\/avatar\\\/e645f66b6264ced10d7b6d8b1f85509b.jpg?ver=1776170659\"},\"sameAs\":[\"https:\\\/\\\/gokhan-gokalp.com\"],\"url\":\"https:\\\/\\\/gokhan-gokalp.com\\\/tr\\\/author\\\/gok-gokalp\\\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"ASP.NET Core MVC ve Elasticsearch'de Globalization - G\u00f6khan G\u00f6kalp","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/gokhan-gokalp.com\/globalization-in-aspnet-core-and-elasticsearch\/","og_locale":"tr_TR","og_type":"article","og_title":"ASP.NET Core MVC ve Elasticsearch'de Globalization - G\u00f6khan G\u00f6kalp","og_url":"https:\/\/gokhan-gokalp.com\/globalization-in-aspnet-core-and-elasticsearch\/","og_site_name":"G\u00f6khan G\u00f6kalp","article_published_time":"2017-12-17T14:19:29+00:00","og_image":[{"width":1000,"height":563,"url":"https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2017\/12\/topic-globalization.jpg","type":"image\/jpeg"}],"author":"G\u00f6khan G\u00f6kalp","twitter_card":"summary_large_image","twitter_misc":{"Yazan:":"G\u00f6khan G\u00f6kalp","Tahmini okuma s\u00fcresi":"24 dakika"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/gokhan-gokalp.com\/globalization-in-aspnet-core-and-elasticsearch\/#article","isPartOf":{"@id":"https:\/\/gokhan-gokalp.com\/globalization-in-aspnet-core-and-elasticsearch\/"},"author":{"name":"G\u00f6khan G\u00f6kalp","@id":"https:\/\/gokhan-gokalp.com\/#\/schema\/person\/7e2a7fa98babd22a5fdae563c4b8cdbe"},"headline":"ASP.NET Core MVC ve Elasticsearch&#8217;de Globalization","datePublished":"2017-12-17T14:19:29+00:00","mainEntityOfPage":{"@id":"https:\/\/gokhan-gokalp.com\/globalization-in-aspnet-core-and-elasticsearch\/"},"wordCount":3138,"commentCount":4,"publisher":{"@id":"https:\/\/gokhan-gokalp.com\/#\/schema\/person\/7e2a7fa98babd22a5fdae563c4b8cdbe"},"image":{"@id":"https:\/\/gokhan-gokalp.com\/globalization-in-aspnet-core-and-elasticsearch\/#primaryimage"},"thumbnailUrl":"https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2017\/12\/topic-globalization.jpg","keywords":["asp.net core","asp.net core elasticsearch","asp.net core globalization","asp.net core mvc","elasticsearch","globalization","globalization elasticsearch","localization elasticsearch","multilanguage elasticsearch"],"articleSection":["ASP.NET Core","Search Engine"],"inLanguage":"tr","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/gokhan-gokalp.com\/globalization-in-aspnet-core-and-elasticsearch\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/gokhan-gokalp.com\/globalization-in-aspnet-core-and-elasticsearch\/","url":"https:\/\/gokhan-gokalp.com\/globalization-in-aspnet-core-and-elasticsearch\/","name":"ASP.NET Core MVC ve Elasticsearch'de Globalization - G\u00f6khan G\u00f6kalp","isPartOf":{"@id":"https:\/\/gokhan-gokalp.com\/#website"},"primaryImageOfPage":{"@id":"https:\/\/gokhan-gokalp.com\/globalization-in-aspnet-core-and-elasticsearch\/#primaryimage"},"image":{"@id":"https:\/\/gokhan-gokalp.com\/globalization-in-aspnet-core-and-elasticsearch\/#primaryimage"},"thumbnailUrl":"https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2017\/12\/topic-globalization.jpg","datePublished":"2017-12-17T14:19:29+00:00","breadcrumb":{"@id":"https:\/\/gokhan-gokalp.com\/globalization-in-aspnet-core-and-elasticsearch\/#breadcrumb"},"inLanguage":"tr","potentialAction":[{"@type":"ReadAction","target":["https:\/\/gokhan-gokalp.com\/globalization-in-aspnet-core-and-elasticsearch\/"]}]},{"@type":"ImageObject","inLanguage":"tr","@id":"https:\/\/gokhan-gokalp.com\/globalization-in-aspnet-core-and-elasticsearch\/#primaryimage","url":"https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2017\/12\/topic-globalization.jpg","contentUrl":"https:\/\/gokhan-gokalp.com\/wp-content\/uploads\/2017\/12\/topic-globalization.jpg","width":1000,"height":563},{"@type":"BreadcrumbList","@id":"https:\/\/gokhan-gokalp.com\/globalization-in-aspnet-core-and-elasticsearch\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/gokhan-gokalp.com\/"},{"@type":"ListItem","position":2,"name":"Globalization in ASP.NET Core MVC and Elasticsearch"}]},{"@type":"WebSite","@id":"https:\/\/gokhan-gokalp.com\/#website","url":"https:\/\/gokhan-gokalp.com\/","name":"G\u00f6khan G\u00f6kalp","description":"C# &amp; Python lover","publisher":{"@id":"https:\/\/gokhan-gokalp.com\/#\/schema\/person\/7e2a7fa98babd22a5fdae563c4b8cdbe"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/gokhan-gokalp.com\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"tr"},{"@type":["Person","Organization"],"@id":"https:\/\/gokhan-gokalp.com\/#\/schema\/person\/7e2a7fa98babd22a5fdae563c4b8cdbe","name":"G\u00f6khan G\u00f6kalp","pronouns":"he","image":{"@type":"ImageObject","inLanguage":"tr","@id":"https:\/\/gokhan-gokalp.com\/wp-content\/litespeed\/avatar\/e645f66b6264ced10d7b6d8b1f85509b.jpg?ver=1776170659","url":"https:\/\/gokhan-gokalp.com\/wp-content\/litespeed\/avatar\/e645f66b6264ced10d7b6d8b1f85509b.jpg?ver=1776170659","contentUrl":"https:\/\/gokhan-gokalp.com\/wp-content\/litespeed\/avatar\/e645f66b6264ced10d7b6d8b1f85509b.jpg?ver=1776170659","caption":"G\u00f6khan G\u00f6kalp"},"logo":{"@id":"https:\/\/gokhan-gokalp.com\/wp-content\/litespeed\/avatar\/e645f66b6264ced10d7b6d8b1f85509b.jpg?ver=1776170659"},"sameAs":["https:\/\/gokhan-gokalp.com"],"url":"https:\/\/gokhan-gokalp.com\/tr\/author\/gok-gokalp\/"}]}},"_links":{"self":[{"href":"https:\/\/gokhan-gokalp.com\/tr\/wp-json\/wp\/v2\/posts\/1931","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/gokhan-gokalp.com\/tr\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/gokhan-gokalp.com\/tr\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/gokhan-gokalp.com\/tr\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/gokhan-gokalp.com\/tr\/wp-json\/wp\/v2\/comments?post=1931"}],"version-history":[{"count":79,"href":"https:\/\/gokhan-gokalp.com\/tr\/wp-json\/wp\/v2\/posts\/1931\/revisions"}],"predecessor-version":[{"id":2030,"href":"https:\/\/gokhan-gokalp.com\/tr\/wp-json\/wp\/v2\/posts\/1931\/revisions\/2030"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/gokhan-gokalp.com\/tr\/wp-json\/wp\/v2\/media\/1933"}],"wp:attachment":[{"href":"https:\/\/gokhan-gokalp.com\/tr\/wp-json\/wp\/v2\/media?parent=1931"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/gokhan-gokalp.com\/tr\/wp-json\/wp\/v2\/categories?post=1931"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/gokhan-gokalp.com\/tr\/wp-json\/wp\/v2\/tags?post=1931"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}