Skip to main content

Pilnīgs ASP.NET Core lokalizācijas ceļvedis

No IStringLocalizer līdz produkcijas videi: iestatiet uz resursiem balstītu lokalizāciju ASP.NET Core, pēc tam automatizējiet tulkošanu ar MI.

1

Iespējot lokalizācijas pakalpojumus

Reģistrējiet lokalizācijas pakalpojumus Program.cs ar AddLocalization(), konfigurējiet atbalstītās kultūras un pievienojiet pieprasījuma lokalizācijas starpprogrammatūru. Tas savieno visu ASP.NET Core lietotnes lokalizācijas konveijeru.

AddLocalization() reģistrē IStringLocalizer un IStringLocalizerFactory DI konteinerā. ResourcesPath norāda sistēmai, kur atrast .resx failus. AddViewLocalization() iespējo IViewLocalizer Razor skatos, bet AddDataAnnotationsLocalization() — lokalizētus validācijas ziņojumus.
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

Izveidot RESX resursu failus

ASP.NET Core tulkojumiem izmanto RESX (XML resursu) failus. Izveidojiet vienu failu katrai kultūrai katrai klasei: HomeController.en.resx, HomeController.de.resx utt. Sistēma atrisina pareizo failu pēc pašreizējā pieprasījuma kultūras.

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>
Kontrolleriem un skatiem kopīgām virknēm — pogu etiķetēm, navigācijas vienumiem un kopīgiem validācijas ziņojumiem — izmantojiet SharedResource klasi ar tās RESX failiem. Tas novērš atslēgu dublēšanu desmitiem kontrolleriem specifisku RESX failu.
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

Izmantot IStringLocalizer kontrolleros un pakalpojumos

Ar atkarību injicēšanu ievadiet IStringLocalizer&lt;T&gt; jebkurā kontrollerī, pakalpojumā vai starpprogrammatūrā. Vispārīgais tipa parametrs T nosaka, kuru RESX failu ielādēt. Tulkotu virkņu iegūšanai izmantojiet iekavu sintaksi localizer["Key"] un pēc izvēles formāta parametrus.

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 });
    }
}
Ja IStringLocalizer tulkotās vērtības vietā atgriež atslēgas nosaukumu, pārbaudiet trīs lietas: 1) RESX faila nosaukums atbilst klases nosaukumvietai; 2) AddLocalization() ResourcesPath norāda pareizo mapi; 3) RESX faila Build Action Visual Studio ir iestatīts uz Embedded Resource.
4

Konfigurēt pieprasījuma kultūras starpprogrammatūru

ASP.NET Core nosaka pieprasījuma kultūru ar nodrošinātāju ķēdi: vaicājuma virkni, sīkfailu un galveni Accept-Language (šādā secībā). Varat pievienot pielāgotus nodrošinātājus, piemēram, kultūras nolasīšanai no URL maršruta segmenta /de/home.

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);
}
Starpprogrammatūras secība ir svarīga. UseRequestLocalization() jāizsauc pēc UseRouting(), bet pirms UseEndpoints() vai MapControllers(). Ja ievietots pārāk vēlu, kultūra nebūs iestatīta, kad izpildās kontrolleri.
5

Lokalizēt datu anotācijas

Validācijas atribūtus, piemēram, [Required], [StringLength] un [Display], var lokalizēt, iestatot to rekvizītus ErrorMessage vai Name uz RESX atslēgu nosaukumiem. Program.cs izsauciet AddDataAnnotationsLocalization(), lai to iespējotu.

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"
Datu anotāciju lokalizācija RESX failus meklē pēc ViewModel klases nosaukuma, nevis kontrollera. RegisterViewModel gadījumā sistēma meklē Resources/ViewModels/RegisterViewModel.de.resx. Ja RESX faili ir nosaukti pēc kontrollera, validācijas ziņojumi netiks lokalizēti.
6

Apstrādāt daudzskaitli un ICU ziņojumus

.NET nav ICU līdzīga iebūvēta daudzskaitļa kārtulu atbalsta. Vienkāršos gadījumos izmantojiet atsevišķas RESX atslēgas (ItemCount_One, ItemCount_Other) un koda pārslēgu. Pilnam ICU MessageFormat atbalstam visās CLDR daudzskaitļa kategorijās izmantojiet bibliotēku MessageFormat.NET.

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 {# عنصر}}";
Vienskaitļa formu noteikšanai nekad neizmantojiet count == 1. Franču valodā 0 uzskata par vienskaitli. Krievu valodā ir atsevišķas few un many formas. Arābu valodā ir sešas daudzskaitļa kategorijas. Izmantojiet CLDR apzinošas daudzskaitļa kārtulas vai tādu bibliotēku kā MessageFormat.NET, kas to apstrādā pareizi.
7

Lokalizēt Razor skatus

Razor skatos izmantojiet IViewLocalizer ar @inject. Tas atrisina RESX failus pēc skata faila ceļa. HTML drošām virknēm ar marķējumu izmantojiet IHtmlLocalizer. Tādi tagu palīgi kā asp-for un asp-validation-for automātiski izmanto lokalizētus Display un ErrorMessage atribūtus.

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 atrisina RESX failus pēc skata ceļa: Views/Home/Index.cshtml meklē Resources/Views/Home/Index.de.resx. Ja vēlaties kopīgot virknes starp skatiem, atsevišķi injicējiet IStringLocalizer&lt;SharedResource&gt;.
8

Automatizēt RESX tulkošanu

Kad lokalizācijas iestatīšana ir pabeigta, tulkojiet RESX failus ar MI. IDE lūdziet MI asistentam iztulkot avota RESX vai izmantojiet i18n Agent CLI CI/CD konveijerā, lai tulkojumi paliktu sinhronizēti.

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
Tulkojiet pakāpeniski — pievienojot avota RESX failam jaunas atslēgas, tulkojiet tikai izmaiņas, nevis ģenerējiet visus failus no jauna. Tas saglabā cilvēku pārskatītos tulkojumus un samazina nevajadzīgu izmaiņu apjomu.

Automatizēt tulkojumu kvalitāti

Ar i18n-validate pirms izlaišanas atrodiet trūkstošās atslēgas un bojātos vietturus. Kamēr īstie tulkojumi vēl nav gatavi, pārbaudiet UI ar i18n-pseudo pseidotulkojumiem.

Izlabojiet lokalizācijas atkāpšanos ar LocaleChain.NET

.NET iebūvētā CultureInfo.Parent hierarhija izmanto tikai BCP 47 saīsināšanu: pt-BR atkāpjas uz pt, tad InvariantCulture, izlaižot pt-PT. LocaleChain.NET nodrošina konfigurējamas atkāpšanās ķēdes katrai lokalizācijai visā .NET ekosistēmā.

Bez LocaleChain.NET pt-BR lietotājs, ja trūkst portugāļu virknes, redz angļu valodu, pat ja jums ir pilnīgs pt-PT tulkojums. Tā pati problēma skar es-MX (izlaiž es-419), zh-Hant (izlaiž zh-Hans) un desmitiem citu reģionālo variantu.
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<>));

Biežākās kļūdas

Pieprasījumā nav iestatīta kultūra

Tulkojumi vienmēr tiek rādīti noklusējuma valodā. Pārbaudiet, vai starpprogrammatūras konveijerā ir izsaukts UseRequestLocalization() un kultūras nodrošinātāji ir konfigurēti. Pārbaudiet, vai pārlūks sūta Accept-Language galvenes. Testējiet ar ?culture=de vaicājuma virknē, lai apstiprinātu starpprogrammatūras darbību.

RESX fails nav atrasts

IStringLocalizer tulkotās vērtības vietā atgriež atslēgas nosaukumu. Visbiežākais iemesls ir RESX faila nosaukums, kas neatbilst pilnam klases nosaukumvietas ceļam attiecībā pret ResourcesPath. Iespējojiet Microsoft.Extensions.Localization atkļūdošanas žurnālus, lai redzētu, kuros ceļos sistēma meklē.

Nepareiza starpprogrammatūras secība

UseRequestLocalization() jāatrodas pirms UseEndpoints() un MapControllers(). Ja ievietota pēc tiem, pieprasījuma kultūra nav iestatīta, kad izpildās kontrolleri. .NET 6+ minimālajā viesošanā izsauciet to pirms app.MapControllers().

Fona pavediens izmanto nepareizu kultūru

CultureInfo.CurrentCulture un CurrentUICulture tiek iestatītas katram pavedienam. Fona uzdevumi (Task.Run, viesotie pakalpojumi) manto pavedienu pūla kultūru, nevis pieprasījuma kultūru. Nosūtot fona darbu, skaidri tveriet un iestatiet kultūru.

Ieteicamā projekta struktūra

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

Izmēģiniet i18n Agent tūlīt

Nometiet tulkošanas failu šeit

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

vai noklikšķiniet, lai izvēlētos

Mērķa valodas

Reģistrācija nav vajadzīgaTūlītēja tāme

Lokalizācijas atkāpšanās ar I18nAgent.LocaleChain

Ja reģionālajā lokalizācijā, piemēram, pt-BR, trūkst tulkojuma atslēgas, .NET uzreiz pāriet uz invarianto kultūru, nevis vispirms pārbauda vecāklokalizāciju pt.

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"},
});

Pilnu atbalstīto sistēmu sarakstu un 75 iebūvētās ķēdes skatiet mūsu lokalizāciju atkāpšanās ceļvedī. Learn more →

Bieži uzdotie jautājumi