
Panduan Lengkap Penyetempatan ASP.NET Core
Daripada IStringLocalizer hingga pengeluaran: sediakan penyetempatan berasaskan sumber dalam ASP.NET Core, kemudian automatikkan terjemahan dengan AI.
Dayakan Perkhidmatan Penyetempatan
Daftarkan perkhidmatan penyetempatan dalam Program.cs dengan AddLocalization(), konfigurasikan budaya yang disokong, dan tambahkan perisian tengah penyetempatan permintaan. Tindakan ini menyediakan seluruh saluran penyetempatan untuk aplikasi ASP.NET Core anda.
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();Cipta Fail Sumber RESX
ASP.NET Core menggunakan fail RESX (sumber XML) untuk terjemahan. Cipta satu fail bagi setiap budaya untuk setiap kelas: HomeController.en.resx, HomeController.de.resx, dan seterusnya. Rangka kerja memilih fail yang betul berdasarkan budaya permintaan semasa.
<!-- 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 { }Gunakan IStringLocalizer dalam Pengawal dan Perkhidmatan
Suntik IStringLocalizer<T> ke dalam mana-mana pengawal, perkhidmatan, atau perisian tengah melalui suntikan kebergantungan. Parameter jenis generik T menentukan fail RESX yang akan dimuatkan. Gunakan sintaks kurungan siku localizer["Key"] untuk mendapatkan rentetan terjemahan, dengan parameter format pilihan.
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 });
}
}Konfigurasikan Perisian Tengah Budaya Permintaan
ASP.NET Core menentukan budaya permintaan menggunakan rantaian penyedia: rentetan pertanyaan, kuki, dan pengepala Accept-Language (mengikut urutan tersebut). Anda boleh menambahkan penyedia tersuai — contohnya, membaca budaya daripada segmen laluan URL seperti /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);
}Setempatkan Anotasi Data
Atribut pengesahan seperti [Required], [StringLength], dan [Display] boleh disetempatkan dengan menetapkan sifat ErrorMessage atau Name kepada nama kekunci RESX. Panggil AddDataAnnotationsLocalization() dalam Program.cs untuk mendayakannya.
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"Kendalikan Bentuk Jamak dan Mesej ICU
.NET tidak mempunyai sokongan terbina dalam untuk peraturan bentuk jamak seperti ICU. Untuk kes mudah, gunakan kekunci RESX berasingan (ItemCount_One, ItemCount_Other) dengan percabangan kod. Untuk sokongan penuh ICU MessageFormat merentas semua kategori bentuk jamak CLDR, gunakan pustaka 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 {# عنصر}}";Setempatkan Paparan Razor
Gunakan IViewLocalizer dalam paparan Razor melalui @inject. IViewLocalizer memilih fail RESX berdasarkan laluan fail paparan. Untuk rentetan yang selamat bagi HTML dan mempunyai penanda, gunakan IHtmlLocalizer. Tag Helper seperti asp-for dan asp-validation-for menggunakan atribut Display dan ErrorMessage yang disetempatkan secara automatik.
@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>Automatikkan Terjemahan RESX
Selepas persediaan penyetempatan selesai, terjemahkan fail RESX anda menggunakan AI. Dalam IDE, minta pembantu AI menterjemahkan RESX sumber anda, atau gunakan CLI i18n Agent dalam saluran CI/CD agar terjemahan kekal disegerakkan.
# 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,esAutomatikkan Kualiti Terjemahan
Baiki Sandaran Lokal dengan LocaleChain.NET
Hierarki CultureInfo.Parent terbina dalam .NET hanya menggunakan pemangkasan BCP 47: pt-BR bersandar kepada pt kemudian InvariantCulture, sambil melangkaui pt-PT. LocaleChain.NET menyediakan rantaian sandaran setiap lokal yang boleh dikonfigurasikan untuk seluruh ekosistem .NET.
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<>));Kesilapan Umum
Budaya Tidak Ditetapkan pada Permintaan
Fail RESX Tidak Ditemui
Urutan Perisian Tengah Salah
Bebenang Latar Belakang Menggunakan Budaya yang Salah
Struktur Projek yang Disyorkan
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.csprojCuba i18n Agent Sekarang
Lepaskan fail terjemahan anda di sini
JSON, YAML, PO, XML, CSV, Markdown, Properties
atau klik untuk semak imbas
Bahasa sasaran
Sandaran Lokal dengan I18nAgent.LocaleChain
Apabila kekunci terjemahan tiada dalam lokal serantau seperti pt-BR, .NET terus beralih kepada budaya invarian dan bukannya menyemak lokal induk pt terlebih dahulu.
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"},
});Lihat Panduan Sandaran Bahasa kami untuk senarai lengkap rangka kerja yang disokong dan 75 rantaian terbina dalam. Learn more →