ASP.NET Core 多语言(本地化)配置
在 ASP.NET Core 中实现多语言支持,主要有三种方式:使用 IViewLocalizer 按页面加载资源文件、使用 IStringLocalizer<T> 指定共享资源文件,以及自定义 IStringLocalizer 从 JSON 等非 resx 来源加载。下面分别介绍。
一、注册多语言服务
在 Program.cs 中注册 Razor Pages 本地化和资源文件目录:
builder.Services.AddRazorPages().AddViewLocalization();
// 指定资源文件目录
builder.Services.AddLocalization(options => options.ResourcesPath = "Resources");
随后启用请求本地化中间件,声明支持的文化(语言)并设置默认文化:
app.UseRequestLocalization(options =>
{
string[] supportedCultures = ["en-US", "zh-CN"];
options.SetDefaultCulture(supportedCultures[0]) // 设置默认语言
.AddSupportedCultures(supportedCultures) // 影响日期、数字、货币等格式的显示
.AddSupportedUICultures(supportedCultures); // 影响资源文件查找
});
二、方式一:IViewLocalizer(按页面资源文件)
在页面中注入 IViewLocalizer 即可使用:
@using Microsoft.AspNetCore.Mvc.Localization
@inject IViewLocalizer Localizer
<h1>@Localizer["Message"]</h1>
此时启动程序,页面只会显示 Message,因为还没有配置语言资源文件。
在 Resources 目录下新建 Pages/Index.resx(默认语言)和 Pages/Index.zh-CN.resx(中文),再填入对应键值即可。注意:资源文件的目录结构必须与页面文件的目录一一对应,否则无法正确读取。
配置完成后,通过浏览器访问以下地址即可切换语言:
https://localhost:9387/?culture=zh-CN
三、方式二:IStringLocalizer<T>(共享资源文件)
当多个页面需要共用同一份资源时,可以使用 IStringLocalizer<T> 直接指定资源类型。先创建一个空类作为资源定位标记:
public class SharedResource
{
}
在页面中注入:
@inject IStringLocalizer<SharedResource> Localizer
然后在资源文件目录中,按 SharedResource.cs 的命名空间对应目录创建资源文件:
假设项目的名命空间为 Test,
- 若
SharedResource.cs在Test下,则资源文件为Resources/SharedResource.resx和Resources/SharedResource.zh-CN.resx; - 若放命名空间为
Test.A,则为Resources/A/SharedResource.resx和Resources/A/SharedResource.zh-CN.resx。
命名空间与目录挂钩,需保持一致才能正确加载。
四、方式三:自定义 IStringLocalizer(JSON 资源)
如果不想使用 .resx 格式,可以自定义实现 IStringLocalizer,例如从 JSON 文件加载。下面是一个基于 language.json 的实现:
public class CustomStringLocalizer : IStringLocalizer
{
private readonly Dictionary<string, Dictionary<string, string>> _KeyValue;
private readonly string[] supportedCultures = [];
public CustomStringLocalizer(IOptions<LocalizationOptions> options)
{
var filePath = Path.Combine(options.Value.ResourcesPath, "language.json");
_KeyValue = JsonSerializer.Deserialize<Dictionary<string, Dictionary<string, string>>>(File.ReadAllText(filePath)) ?? [];
supportedCultures = [.. _KeyValue.Keys];
}
private LocalizedString GetValue(string name, params object[] arguments)
{
var cultureName = supportedCultures.FirstOrDefault(c => c == CultureInfo.CurrentUICulture.Name)
?? supportedCultures.FirstOrDefault()
?? "";
if (_KeyValue.TryGetValue(cultureName, out Dictionary<string, string>? cultureValue)
&& cultureValue != null && cultureValue.Count > 0)
{
if (cultureValue.TryGetValue(name, out string? value))
{
value = string.Format(value ?? string.Empty, arguments);
return new LocalizedString(name, value);
}
}
return new LocalizedString(name, name);
}
public LocalizedString this[string name] => GetValue(name);
public LocalizedString this[string name, params object[] arguments] => GetValue(name, arguments);
public IEnumerable<LocalizedString> GetAllStrings(bool includeParentCultures)
{
var cultureName = supportedCultures.FirstOrDefault(c => c == CultureInfo.CurrentUICulture.Name)
?? supportedCultures.FirstOrDefault()
?? "";
if (_KeyValue.TryGetValue(cultureName, out Dictionary<string, string>? cultureValue))
{
return (cultureValue ?? []).Select(x => new LocalizedString(x.Key, x.Value));
}
return [];
}
}
在 Program.cs 中注册:
builder.Services.AddScoped<IStringLocalizer, CustomStringLocalizer>();
在 Resources 目录下创建 language.json,按文化名分组定义键值:
{
"default": {
"Message": "default message"
},
"zh-CN": {
"Message": "中文翻译"
}
}
在页面中直接注入并使用:
@inject IStringLocalizer Localizer
<p>@Localizer["Message"]</p>
小结
| 方式 | 适用场景 | 资源格式 |
|---|---|---|
IViewLocalizer |
单页面独立资源,按页面目录组织 | .resx |
IStringLocalizer<T> |
多页面共享资源,按类型命名空间组织 | .resx |
自定义 IStringLocalizer |
需要非 resx 格式或自定义加载逻辑 | 任意(如 JSON) |
三种方式可以按需选择,也可以在同一项目中组合使用。

