
Cjelovit vodič za lokalizaciju u ASP.NET Coreu
Od sučelja IStringLocalizer do produkcije: postavite lokalizaciju temeljenu na resursima u ASP.NET Coreu, a zatim automatizirajte prevođenje pomoću AI-ja.
Omogućite usluge lokalizacije
Registrirajte usluge lokalizacije u datoteci Program.cs pomoću AddLocalization(), konfigurirajte podržane kulture i dodajte međuverzje za lokalizaciju zahtjeva. Time povezujete cijeli tijek lokalizacije svoje ASP.NET Core aplikacije.
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();Izradite datoteke resursa RESX
ASP.NET Core za prijevode koristi RESX datoteke (XML datoteke resursa). Izradite po jednu datoteku za svaku kulturu i klasu: HomeController.en.resx, HomeController.de.resx itd. Radni okvir odabire ispravnu datoteku prema kulturi trenutačnog zahtjeva.
<!-- 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 { }Upotrebljavajte IStringLocalizer u kontrolerima i uslugama
Umetnite IStringLocalizer<T> u bilo koji kontroler, uslugu ili međuverzje putem umetanja ovisnosti. Generički parametar vrste T određuje koja se RESX datoteka učitava. Prevedene tekstove dohvatite sintaksom uglatih zagrada localizer["Key"], uz neobavezne parametre oblikovanja.
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 });
}
}Konfigurirajte međuverzje za kulturu zahtjeva
ASP.NET Core određuje kulturu zahtjeva lancem pružatelja: iz parametra upita, kolačića i zaglavlja Accept-Language, tim redoslijedom. Možete dodati prilagođene pružatelje — primjerice, za čitanje kulture iz segmenta URL putanje kao što je /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);
}Lokalizirajte podatkovne anotacije
Atribute provjere valjanosti poput [Required], [StringLength] i [Display] možete lokalizirati tako da njihova svojstva ErrorMessage ili Name postavite na nazive RESX ključeva. To omogućite pozivom AddDataAnnotationsLocalization() u datoteci Program.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"Obradite množinu i ICU poruke
.NET nema ugrađenu podršku za pravila množine poput ICU-a. U jednostavnim slučajevima upotrijebite zasebne RESX ključeve (ItemCount_One, ItemCount_Other) i naredbu switch u kodu. Za potpunu podršku za format ICU MessageFormat u svim CLDR kategorijama množine upotrijebite biblioteku 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 {# عنصر}}";Lokalizirajte prikaze Razor
U prikazima Razor upotrebljavajte IViewLocalizer putem @inject. On odabire RESX datoteke prema putanji datoteke prikaza. Za tekstove s oznakama koji su sigurni za HTML upotrijebite IHtmlLocalizer. Pomagači oznaka poput asp-for i asp-validation-for automatski upotrebljavaju lokalizirane atribute Display i ErrorMessage.
@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>Automatizirajte prevođenje RESX datoteka
Nakon postavljanja lokalizacije prevedite RESX datoteke pomoću AI-ja. U svojem IDE-u zatražite od AI pomoćnika da prevede izvornu RESX datoteku ili upotrijebite i18n Agent CLI u CI/CD procesu kako bi prijevodi ostali usklađeni.
# 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,esAutomatizirajte provjeru kvalitete prijevoda
Ispravite pričuvni odabir jezika uz LocaleChain.NET
Ugrađena hijerarhija CultureInfo.Parent u .NET-u upotrebljava samo skraćivanje oznaka prema standardu BCP 47: pt-BR prelazi na pt, a zatim na InvariantCulture, preskačući pt-PT. LocaleChain.NET pruža prilagodljive lance pričuvnog odabira za svaku jezičnu inačicu u cijelom .NET ekosustavu.
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<>));Česte zamke
Kultura zahtjeva nije postavljena
RESX datoteka nije pronađena
Pogrešan redoslijed međuverzja
Pozadinska nit upotrebljava pogrešnu kulturu
Preporučena struktura projekta
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.csprojIsprobajte i18n Agent odmah
Povucite datoteku za prijevod ovdje
JSON, YAML, PO, XML, CSV, Markdown, Properties
ili kliknite za odabir
Ciljni jezici
Pričuvni odabir jezika uz I18nAgent.LocaleChain
Kada ključ prijevoda nedostaje u regionalnoj jezičnoj inačici poput pt-BR, .NET odmah prelazi na nepromjenjivu kulturu umjesto da najprije provjeri nadređenu jezičnu oznaku 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"},
});U našem vodiču za pričuvni odabir jezika pogledajte cjelovit popis podržanih radnih okvira i 75 ugrađenih lanaca. Learn more →