Skip to main content

ASP.NET Core yerelleştirmesine yönelik eksiksiz rehber

IStringLocalizer'dan üretim ortamına kadar ASP.NET Core'da kaynak tabanlı yerelleştirmeyi kurun ve ardından çevirileri yapay zeka ile otomatikleştirin.

1

Yerelleştirme hizmetlerini etkinleştirin

Yerelleştirme hizmetlerini Program.cs içinde AddLocalization() ile kaydedin, desteklenen kültürleri yapılandırın ve istek yerelleştirme ara yazılımını ekleyin. Bu işlem, ASP.NET Core uygulamanızın yerelleştirme işlem hattının tamamını bağlar.

AddLocalization(), IStringLocalizer ve IStringLocalizerFactory bileşenlerini DI kapsayıcısına kaydeder. ResourcesPath, .resx dosyalarınızı nerede bulacağını çerçeveye bildirir. AddViewLocalization(), Razor görünümlerinde IViewLocalizer'ı etkinleştirir; AddDataAnnotationsLocalization() ise yerelleştirilmiş doğrulama iletilerini etkinleştirir.
Program.cs
using Microsoft.AspNetCore.Localization;
using System.Globalization;

var builder = WebApplication.CreateBuilder(args);

// 1. Register localization services
builder.Services.AddLocalization(o => o.ResourcesPath = "Resources");

// 2. Add MVC with view/data-annotation localization
builder.Services.AddControllersWithViews()
    .AddViewLocalization()
    .AddDataAnnotationsLocalization();

var app = builder.Build();

// 3. Configure supported cultures
var supportedCultures = new[] { "en", "de", "ja", "es", "pt-BR" }
    .Select(c => new CultureInfo(c)).ToArray();

app.UseRequestLocalization(new RequestLocalizationOptions
{
    DefaultRequestCulture = new RequestCulture("en"),
    SupportedCultures = supportedCultures,
    SupportedUICultures = supportedCultures,
});

app.UseStaticFiles();
app.UseRouting();
app.MapControllers();
app.Run();
2

RESX kaynak dosyalarını oluşturun

ASP.NET Core, çeviriler için RESX (XML kaynağı) dosyalarını kullanır. Her kültür ve sınıf için bir dosya oluşturun: HomeController.en.resx, HomeController.de.resx vb. Çerçeve, geçerli istek kültürüne göre doğru dosyayı çözümler.

Resources/Controllers/HomeController.{culture}.resx
<!-- Resources/Controllers/HomeController.en.resx -->
<?xml version="1.0" encoding="utf-8"?>
<root>
  <data name="Welcome" xml:space="preserve">
    <value>Welcome to our application</value>
  </data>
  <data name="Greeting" xml:space="preserve">
    <value>Hello, {0}!</value>
  </data>
</root>

<!-- Resources/Controllers/HomeController.de.resx -->
<?xml version="1.0" encoding="utf-8"?>
<root>
  <data name="Welcome" xml:space="preserve">
    <value>Willkommen in unserer Anwendung</value>
  </data>
  <data name="Greeting" xml:space="preserve">
    <value>Hallo, {0}!</value>
  </data>
</root>
Denetleyiciler ve görünümler arasında paylaşılan dizeler (düğme etiketleri, gezinme öğeleri ve yaygın doğrulama iletileri) için kendi RESX dosyaları bulunan bir SharedResource sınıfı kullanın. Böylece anahtarların denetleyiciye özgü onlarca RESX dosyasında yinelenmesini önlersiniz.
Shared resources for cross-cutting strings
<!-- Resources/SharedResource.en.resx — shared across controllers -->
<?xml version="1.0" encoding="utf-8"?>
<root>
  <data name="AppName" xml:space="preserve">
    <value>My Application</value>
  </data>
  <data name="Save" xml:space="preserve"><value>Save</value></data>
  <data name="Cancel" xml:space="preserve"><value>Cancel</value></data>
</root>

// Marker class (empty — only used for type lookup)
namespace MyApp;
public class SharedResource { }
3

Denetleyicilerde ve hizmetlerde IStringLocalizer kullanın

IStringLocalizer&lt;T&gt; bileşenini bağımlılık ekleme aracılığıyla herhangi bir denetleyiciye, hizmete veya ara yazılıma ekleyin. T genel tür parametresi hangi RESX dosyasının yükleneceğini belirler. Çevrilmiş dizeleri almak için isteğe bağlı biçim parametreleriyle localizer["Key"] köşeli parantez söz dizimini kullanın.

Controllers/HomeController.cs
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Localization;

public class HomeController(
    IStringLocalizer<HomeController> localizer,
    IStringLocalizer<SharedResource> shared) : Controller
{
    public IActionResult Index()
    {
        ViewData["Welcome"] = localizer["Welcome"];
        ViewData["AppName"] = shared["AppName"];

        // String interpolation with format parameters
        var greeting = localizer["Greeting", User.Identity?.Name ?? "Guest"];
        return View(new HomeViewModel { Greeting = greeting });
    }
}
IStringLocalizer çevrilmiş değer yerine anahtar adını döndürürse üç noktayı denetleyin: (1) RESX dosyasının adı sınıfın ad alanıyla eşleşiyor mu, (2) AddLocalization() içindeki ResourcesPath doğru klasörü gösteriyor mu ve (3) RESX dosyasının Build Action ayarı Visual Studio'da Embedded Resource olarak belirlenmiş mi?
4

İstek kültürü ara yazılımını yapılandırın

ASP.NET Core, istek kültürünü sırasıyla sorgu dizesi, çerez ve Accept-Language üst bilgisinden oluşan bir sağlayıcı zinciriyle belirler. Özel sağlayıcılar ekleyebilirsiniz; örneğin kültürü /de/home gibi bir URL yolu bölümünden okuyabilirsiniz.

Custom RouteDataRequestCultureProvider
// Culture resolved in order: QueryString, Cookie, Accept-Language
// Custom provider: read culture from URL route segment /de/home
public class RouteDataRequestCultureProvider : RequestCultureProvider
{
    public override Task<ProviderCultureResult?> DetermineProviderCultureResult(
        HttpContext httpContext)
    {
        var culture = httpContext.GetRouteValue("culture")?.ToString();
        if (string.IsNullOrEmpty(culture))
            return NullProviderCultureResult;
        return Task.FromResult<ProviderCultureResult?>(
            new ProviderCultureResult(culture));
    }
}

// Register in Program.cs (route provider first = highest priority):
app.UseRequestLocalization(new RequestLocalizationOptions
{
    DefaultRequestCulture = new RequestCulture("en"),
    SupportedCultures = supportedCultures,
    SupportedUICultures = supportedCultures,
    RequestCultureProviders = new List<IRequestCultureProvider>
    {
        new RouteDataRequestCultureProvider(),
        new QueryStringRequestCultureProvider(),
        new CookieRequestCultureProvider(),
        new AcceptLanguageHeaderRequestCultureProvider(),
    }
});
Language Switcher Action
// Language switcher: persist choice in cookie
[HttpPost]
public IActionResult SetLanguage(string culture, string returnUrl)
{
    Response.Cookies.Append(
        CookieRequestCultureProvider.DefaultCookieName,
        CookieRequestCultureProvider.MakeCookieValue(new RequestCulture(culture)),
        new CookieOptions { Expires = DateTimeOffset.UtcNow.AddYears(1) });
    return LocalRedirect(returnUrl);
}
Ara yazılımların sırası önemlidir. UseRequestLocalization(), UseRouting() sonrasında ancak UseEndpoints() veya MapControllers() öncesinde çağrılmalıdır. Çok geç yerleştirilirse denetleyicileriniz çalışırken kültür ayarlanmamış olur.
5

Veri ek açıklamalarını yerelleştirin

[Required], [StringLength] ve [Display] gibi doğrulama öznitelikleri, ErrorMessage veya Name özellikleri RESX anahtar adlarına ayarlanarak yerelleştirilebilir. Bunu etkinleştirmek için Program.cs içinde AddDataAnnotationsLocalization() çağrısını yapın.

ViewModels/RegisterViewModel.cs
using System.ComponentModel.DataAnnotations;

public class RegisterViewModel
{
    [Required(ErrorMessage = "NameRequired")]
    [Display(Name = "FullName")]
    [StringLength(100, ErrorMessage = "NameLength", MinimumLength = 2)]
    public string Name { get; set; } = string.Empty;

    [Required(ErrorMessage = "EmailRequired")]
    [EmailAddress(ErrorMessage = "EmailInvalid")]
    [Display(Name = "EmailAddress")]
    public string Email { get; set; } = string.Empty;

    [Required(ErrorMessage = "PasswordRequired")]
    [StringLength(100, ErrorMessage = "PasswordLength", MinimumLength = 8)]
    [Display(Name = "Password")]
    public string Password { get; set; } = string.Empty;
}
// RESX keys map to ErrorMessage/Name values:
// RegisterViewModel.de.resx: NameRequired = "Name ist erforderlich"
// RegisterViewModel.de.resx: FullName = "Vollständiger Name"
Veri ek açıklaması yerelleştirmesi, RESX dosyalarını bulmak için Controller yerine ViewModel sınıfının adını kullanır. Çerçeve, RegisterViewModel için Resources/ViewModels/RegisterViewModel.de.resx dosyasını arar. RESX dosyalarınız denetleyicinin adını taşıyorsa doğrulama iletileri yerelleştirilmez.
6

Çoğulları ve ICU iletilerini yönetin

.NET, ICU gibi yerleşik çoğul kuralı desteğine sahip değildir. Basit durumlarda bir kod anahtarıyla ayrı RESX anahtarları (ItemCount_One, ItemCount_Other) kullanın. Tüm CLDR çoğul kategorilerinde eksiksiz ICU MessageFormat desteği için MessageFormat.NET kitaplığını kullanın.

Plural handling strategies
// Option 1: Separate RESX keys with code switch
// HomeController.en.resx: ItemCount_One = "You have {0} item"
// HomeController.en.resx: ItemCount_Other = "You have {0} items"
public string GetItemCount(int count)
{
    var key = count == 1 ? "ItemCount_One" : "ItemCount_Other";
    return _localizer[key, count];
}

// Option 2: ICU MessageFormat (dotnet add package MessageFormat.NET)
using Jeffijoe.MessageFormat;
var formatter = new MessageFormatter();

var pattern = "{count, plural, one {# item} other {# items}} in your cart";
var result = formatter.FormatMessage(pattern,
    new Dictionary<string, object> { { "count", 5 } });
// => "5 items in your cart"

// Arabic: 6 plural forms (zero, one, two, few, many, other)
var arPattern = @"{count, plural,
    zero {لا عناصر} one {عنصر واحد} two {عنصران}
    few {# عناصر} many {# عنصرًا} other {# عنصر}}";
Tekil biçimleri algılamak için asla count == 1 kullanmayın. Fransızca 0'ı tekil kabul eder. Rusçada 'few' ve 'many' için ayrı biçimler bulunur. Arapçada altı çoğul kategorisi vardır. CLDR'yi bilen çoğul kurallarını veya bunu doğru yöneten MessageFormat.NET gibi bir kitaplığı kullanın.
7

Razor görünümlerini yerelleştirin

Razor görünümlerinde @inject aracılığıyla IViewLocalizer kullanın. Bu bileşen RESX dosyalarını görünümün dosya yoluna göre çözümler. İşaretleme içeren ve HTML açısından güvenli dizeler için IHtmlLocalizer kullanın. asp-for ve asp-validation-for gibi Tag Helpers bileşenleri, yerelleştirilmiş Display ve ErrorMessage özniteliklerini otomatik olarak kullanır.

Views/Home/Index.cshtml
@using Microsoft.AspNetCore.Mvc.Localization
@inject IViewLocalizer Localizer
@inject IHtmlLocalizer<SharedResource> SharedHtml

<h1>@Localizer["Welcome"]</h1>
<p>@Localizer["Greeting", User.Identity?.Name]</p>

@* IHtmlLocalizer: does NOT escape — use for RESX values with HTML *@
<p>@SharedHtml["TermsNotice"]</p>

@* Tag Helpers auto-localize Display/ErrorMessage attributes *@
<form asp-action="Register">
    <label asp-for="Name"></label>
    <input asp-for="Name" />
    <span asp-validation-for="Name"></span>
    <button type="submit">@Localizer["Submit"]</button>
</form>
IViewLocalizer, RESX dosyalarını görünüm yoluna göre çözümler: Views/Home/Index.cshtml, Resources/Views/Home/Index.de.resx dosyasını arar. Dizeleri görünümler arasında paylaşmak istiyorsanız IStringLocalizer&lt;SharedResource&gt; bileşenini ayrıca ekleyin.
8

RESX çevirilerini otomatikleştirin

Yerelleştirme kurulumunuz tamamlandıktan sonra RESX dosyalarınızı yapay zeka kullanarak çevirin. IDE'nizde yapay zeka yardımcınızdan kaynak RESX dosyanızı çevirmesini isteyin veya çevirileri eş zamanlı tutmak için CI/CD işlem hattınızda i18n Agent CLI'ı kullanın.

Terminal
# In your IDE, ask your AI assistant:
> Translate Resources/Controllers/HomeController.en.resx to German, Japanese, Spanish

# HomeController.de.resx created (1.2s)
# HomeController.ja.resx created (1.5s)
# HomeController.es.resx created (1.1s)

# Or use the CLI in CI/CD:
npx i18n-agent translate Resources/Controllers/HomeController.en.resx --lang de,ja,es
Aşamalı çeviri yapın: kaynak RESX dosyanıza yeni anahtarlar eklediğinizde tüm dosyaları yeniden oluşturmak yerine yalnızca farkı çevirin. Böylece insanlar tarafından incelenmiş çeviriler korunur ve gereksiz değişiklikler en aza iner.

Çeviri kalitesini otomatikleştirin

Eksik anahtarları ve bozuk yer tutucuları kullanıma sunulmadan önce i18n-validate ile yakalayın. Gerçek çeviriler gelmeden önce kullanıcı arayüzünüzü i18n-pseudo ile sözde çeviriler kullanarak sınayın.

LocaleChain.NET ile yerel ayar yedeklemesini düzeltin

.NET'in yerleşik CultureInfo.Parent hiyerarşisi yalnızca BCP 47 kısaltmasını kullanır: pt-BR önce pt'ye, ardından pt-PT'yi atlayarak InvariantCulture'a geçer. LocaleChain.NET, tüm .NET ekosistemi için yerel ayar başına yapılandırılabilir yedekleme zincirleri sağlar.

LocaleChain.NET olmadan, eksik bir Portekizce dizeyle karşılaşan pt-BR kullanıcısı eksiksiz bir pt-PT çeviriniz olsa bile İngilizce görür. Aynı sorun es-MX (es-419'u atlar), zh-Hant (zh-Hans'ı atlar) ve diğer onlarca bölgesel varyantı etkiler.
Terminal
dotnet add package I18nAgent.LocaleChain
Program.cs
using I18nAgent.LocaleChain;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddLocalization(o => o.ResourcesPath = "Resources");

// Zero-config: built-in chains (pt-BR -> pt-PT -> pt -> en, etc.)
LocaleChain.Configure();

// Or customize specific chains:
LocaleChain.Configure(new Dictionary<string, string[]>
{
    ["pt-BR"] = new[] { "pt-PT", "pt", "en" },
    ["es-MX"] = new[] { "es-419", "es", "en" },
});

// Register the chain-aware string localizer
builder.Services.AddSingleton(
    typeof(IStringLocalizer<>),
    typeof(LocaleChainStringLocalizer<>));

Yaygın hatalar

İstekte kültürün ayarlanmaması

Çeviriler her zaman varsayılan dili gösterir. Ara yazılım işlem hattında UseRequestLocalization() çağrısının yapıldığını ve kültür sağlayıcılarının yapılandırıldığını denetleyin. Tarayıcının Accept-Language üst bilgilerini gönderdiğini doğrulayın. Ara yazılımın çalıştığını onaylamak için sorgu dizesinde ?culture=de ile sınayın.

RESX dosyasının bulunamaması

IStringLocalizer çevrilmiş değer yerine anahtar adını döndürür. En yaygın neden, ResourcesPath'e göre sınıfın tam ad alanı yoluyla eşleşmeyen bir RESX dosya adıdır. Çerçevenin hangi yolları aradığını görmek için Microsoft.Extensions.Localization hata ayıklama günlüklerini etkinleştirin.

Ara yazılım sırasının yanlış olması

UseRequestLocalization(), UseEndpoints() ve MapControllers() öncesinde yer almalıdır. Sonrasına yerleştirilirse denetleyiciler çalışırken istek kültürü ayarlanmamış olur. .NET 6+ asgari barındırmada bu işlevi app.MapControllers() öncesinde çağırın.

Arka plan iş parçacığının yanlış kültürü kullanması

CultureInfo.CurrentCulture ve CurrentUICulture iş parçacığı başınadır. Arka plan görevleri (Task.Run, barındırılan hizmetler), istek kültürünü değil iş parçacığı havuzunun kültürünü devralır. Arka plan işini gönderirken kültürü açıkça yakalayıp ayarlayın.

Önerilen proje yapısı

Project Structure
MyAspNetApp/
├── Controllers/
│   └── HomeController.cs
├── ViewModels/
│   └── RegisterViewModel.cs
├── Views/
│   └── Home/
│       └── Index.cshtml
├── Resources/
│   ├── Controllers/
│   │   ├── HomeController.en.resx     # English (source)
│   │   ├── HomeController.de.resx     # German
│   │   └── HomeController.ja.resx     # Japanese
│   ├── ViewModels/
│   │   ├── RegisterViewModel.en.resx
│   │   └── RegisterViewModel.de.resx
│   ├── Views/Home/
│   │   ├── Index.en.resx
│   │   └── Index.de.resx
│   └── SharedResource.en.resx
├── SharedResource.cs                  # Marker class
├── Program.cs
└── MyAspNetApp.csproj

i18n Agent'ı şimdi deneyin

Çeviri dosyanızı buraya bırakın

JSON, YAML, PO, XML, CSV, Markdown, Properties

veya göz atmak için tıklayın

Hedef diller

Kayıt gerekmezAnında fiyat tahmini

I18nAgent.LocaleChain ile yerel ayar yedeklemesi

pt-BR gibi bölgesel bir yerel ayarda çeviri anahtarı eksik olduğunda .NET, önce üst yerel ayar pt'yi denetlemek yerine doğrudan değişmez kültüre geçer.

Terminal
dotnet add package I18nAgent.LocaleChain
Configuration
using I18nAgent.LocaleChain;

LocaleChain.Configure(new Dictionary<string, string[]>
{
    ["pt-BR"] = new[] {"pt", "en"},
    ["zh-Hant-HK"] = new[] {"zh-Hant", "zh", "en"},
});

Desteklenen çerçevelerin ve 75 yerleşik zincirin tam listesi için Yerel Ayar Yedekleme Rehberimize bakın. Learn more →

Sık sorulan sorular