爱名网(22科技集团)

ASP.NET Core 多语言(本地化)配置

2026-09-07 16:32小俞

 

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.csTest 下,则资源文件为 Resources/SharedResource.resxResources/SharedResource.zh-CN.resx
  • 若放命名空间为 Test.A,则为 Resources/A/SharedResource.resxResources/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)

三种方式可以按需选择,也可以在同一项目中组合使用。

曝光131浏览9