
Ang Kumpletong Gabay sa ASP.NET Core Localization
Mula IStringLocalizer hanggang production: i-set up ang resource-based localization sa ASP.NET Core, pagkatapos ay i-automate ang pagsasalin gamit ang AI.
I-enable ang Localization Services
I-register ang localization services sa Program.cs gamit ang AddLocalization(), i-configure ang mga sinusuportahang culture, at idagdag ang request localization middleware. Ikinakabit nito ang buong localization pipeline para sa inyong ASP.NET Core application.
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();Gumawa ng mga RESX Resource File
Gumagamit ang ASP.NET Core ng mga RESX (XML resource) file para sa mga pagsasalin. Gumawa ng isang file bawat culture bawat class: HomeController.en.resx, HomeController.de.resx, atbp. Reresolbahin ng framework ang tamang file batay sa kasalukuyang request culture.
<!-- 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 { }Gamitin ang IStringLocalizer sa mga Controller at Service
I-inject ang IStringLocalizer<T> sa anumang controller, service, o middleware sa pamamagitan ng dependency injection. Ang generic type parameter na T ang nagtatakda kung aling RESX file ang ilo-load. Gamitin ang bracket syntax na localizer["Key"] para kunin ang isinaling string, na may opsyonal na mga format parameter.
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 });
}
}I-configure ang Request Culture Middleware
Tinutukoy ng ASP.NET Core ang request culture gamit ang chain ng provider: query string, cookie, at Accept-Language header (sa ganitong pagkakasunod). Maaari kayong magdagdag ng mga custom provider — halimbawa, pagbabasa ng culture mula sa URL route segment tulad ng /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);
}I-localize ang Data Annotations
Maaaring i-localize ang mga validation attribute tulad ng [Required], [StringLength], at [Display] sa pamamagitan ng pag-set ng kanilang ErrorMessage o Name property sa mga pangalan ng RESX key. Tawagin ang AddDataAnnotationsLocalization() sa Program.cs upang paganahin ito.
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"Hawakan ang mga Plural at ICU Message
.NET ay walang built-in na suporta para sa plural rule tulad ng ICU. Para sa mga simpleng kaso, gumamit ng hiwa-hiwalay na RESX key (ItemCount_One, ItemCount_Other) na may code switch. Para sa kumpletong ICU MessageFormat support sa lahat ng CLDR plural category, gamitin ang MessageFormat.NET library.
// 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 {# عنصر}}";I-localize ang mga Razor View
Gumamit ng IViewLocalizer sa mga Razor view sa pamamagitan ng @inject. Tinutugma nito ang mga RESX file batay sa file path ng view. Para sa mga string na may markup at ligtas sa HTML, gamitin ang IHtmlLocalizer. Awtomatikong ginagamit ng mga Tag Helper tulad ng asp-for at asp-validation-for ang mga localized na Display at ErrorMessage attribute.
@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>I-automate ang Pagsasalin ng RESX
Kapag kumpleto na ang inyong localization setup, isalin ang inyong mga RESX file gamit ang AI. Sa inyong IDE, hilingin sa inyong AI assistant na isalin ang source RESX, o gamitin ang i18n Agent CLI sa inyong CI/CD pipeline upang panatilihing naka-sync ang mga pagsasalin.
# 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,esI-automate ang Kalidad ng Pagsasalin
Ayusin ang Locale Fallback gamit ang LocaleChain.NET
BCP 47 truncation lang ang ginagamit ng built-in na CultureInfo.Parent hierarchy ng .NET: bumabagsak ang pt-BR sa pt at pagkatapos sa InvariantCulture, at nilalaktawan ang pt-PT. Nagbibigay ang LocaleChain.NET ng configurable na per-locale fallback chain para sa buong .NET ecosystem.
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<>));Mga Karaniwang Pitfall
Hindi Naka-set ang Culture sa Request
Hindi Nahanap ang RESX File
Mali ang Pagkakasunod-sunod ng Middleware
Maling Culture ang Ginagamit ng Background Thread
Inirerekomendang 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.csprojSubukan ang i18n Agent Ngayon
I-drop dito ang inyong translation file
JSON, YAML, PO, XML, CSV, Markdown, Properties
o i-click para mag-browse
Mga target language
Locale Fallback gamit ang I18nAgent.LocaleChain
Kapag may nawawalang translation key sa isang regional locale tulad ng pt-BR, diretsong tumatalon ang .NET sa invariant culture sa halip na tingnan muna ang parent locale na 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"},
});Tingnan ang aming Locale Fallback Guide para sa kumpletong listahan ng mga sinusuportahang framework at 75 built-in na chain. Learn more →