
Išsamus ASP.NET Core lokalizavimo vadovas
Nuo IStringLocalizer iki gamybinės aplinkos: sukonfigūruokite ištekliais pagrįstą lokalizavimą ASP.NET Core, tada automatizuokite vertimus naudodami DI.
Įjungti lokalizavimo paslaugas
Užregistruokite lokalizavimo paslaugas Program.cs su AddLocalization(), sukonfigūruokite palaikomas kultūras ir pridėkite užklausos lokalizavimo tarpinę programinę įrangą. Taip prijungiamas visas ASP.NET Core programos lokalizavimo konvejeris.
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();Sukurti RESX išteklių failus
ASP.NET Core vertimams naudoja RESX (XML išteklių) failus. Sukurkite po vieną kiekvienos kultūros failą kiekvienai klasei: HomeController.en.resx, HomeController.de.resx ir t. t. Sistema išsprendžia tinkamą failą pagal dabartinės užklausos kultūrą.
<!-- 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><!-- 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 { }Naudoti IStringLocalizer valdikliuose ir paslaugose
Per priklausomybių įterpimą įterpkite IStringLocalizer<T> į bet kurį valdiklį, paslaugą ar tarpinę programinę įrangą. Bendrasis tipo parametras T nustato, kurį RESX failą įkelti. Išverstoms eilutėms gauti naudokite skliaustų sintaksę localizer["Key"] ir, jei reikia, formato parametrus.
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 });
}
}Sukonfigūruoti užklausos kultūros tarpinę programinę įrangą
ASP.NET Core nustato užklausos kultūrą naudodamas teikėjų grandinę: užklausos eilutę, slapuką ir antraštę Accept-Language (tokia tvarka). Galite pridėti pasirinktinių teikėjų, pavyzdžiui, kultūrai nuskaityti iš URL maršruto segmento /de/home.
// 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: 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);
}Lokalizuoti duomenų anotacijas
Tikrinimo atributus, pavyzdžiui, [Required], [StringLength] ir [Display], galima lokalizuoti nustatant jų ypatybes ErrorMessage arba Name į RESX raktų pavadinimus. Program.cs iškvieskite AddDataAnnotationsLocalization(), kad tai įjungtumėte.
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"Apdoroti daugiskaitą ir ICU pranešimus
.NET neturi integruoto daugiskaitos taisyklių palaikymo kaip ICU. Paprastais atvejais naudokite atskirus RESX raktus (ItemCount_One, ItemCount_Other) ir kodo perjungiklį. Visapusiškam ICU MessageFormat palaikymui visose CLDR daugiskaitos kategorijose naudokite biblioteką MessageFormat.NET.
// 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 {# عنصر}}";Lokalizuoti Razor rodinius
Razor rodiniuose naudokite IViewLocalizer per @inject. Jis išsprendžia RESX failus pagal rodinio failo kelią. HTML saugioms eilutėms su žymėjimu naudokite IHtmlLocalizer. Tokie žymų pagalbininkai kaip asp-for ir asp-validation-for automatiškai naudoja lokalizuotus Display ir ErrorMessage atributus.
@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>Automatizuoti RESX vertimus
Baigę lokalizavimo sąranką išverskite RESX failus naudodami DI. IDE paprašykite DI asistento išversti šaltinio RESX arba naudokite i18n Agent CLI CI/CD konvejeryje, kad vertimai liktų sinchronizuoti.
# 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,esAutomatizuoti vertimo kokybę
Ištaisykite atsarginę lokalę su LocaleChain.NET
Integruota .NET CultureInfo.Parent hierarchija naudoja tik BCP 47 trumpinimą: pt-BR grįžta prie pt, tada InvariantCulture, praleisdama pt-PT. LocaleChain.NET suteikia konfigūruojamas kiekvienos lokalės atsargines grandines visai .NET ekosistemai.
dotnet add package I18nAgent.LocaleChainusing 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<>));Dažnos klaidos
Užklausoje nenustatyta kultūra
RESX failas nerastas
Netinkama tarpinės programinės įrangos tvarka
Foninė gija naudoja netinkamą kultūrą
Rekomenduojama projekto struktūra
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.csprojIšbandykite i18n Agent dabar
Nuvilkite vertimo failą čia
JSON, YAML, PO, XML, CSV, Markdown, Properties
arba spustelėkite norėdami pasirinkti
Tikslinės kalbos
Atsarginė lokalė su I18nAgent.LocaleChain
Kai regioninėje lokalėje, pavyzdžiui, pt-BR, trūksta vertimo rakto, .NET iškart pereina prie invariantinės kultūros, užuot pirmiausia patikrinusi pirminę lokalę pt.
dotnet add package I18nAgent.LocaleChainusing I18nAgent.LocaleChain;
LocaleChain.Configure(new Dictionary<string, string[]>
{
["pt-BR"] = new[] {"pt", "en"},
["zh-Hant-HK"] = new[] {"zh-Hant", "zh", "en"},
});Visą palaikomų sistemų sąrašą ir 75 integruotas grandines rasite mūsų atsarginių lokalių vadove. Learn more →