❤️ 关注 Furion 微信公众号有惊喜哦!
🫠 遇到问题了
Skip to main content
⭐️ 开通 VIP 服务仅需 499 元/年,尊享 365 天项目无忧23 立即开通23 ⭐️
特别赞助

21. 全球化和本地化

📝 模块更新日志
  • 新特性

    •   多语言支持 L.GetDefaultCulture() 获取本地配置默认语言 4.8.8.49 ⏱️2023.10.25 !858
    •   多语言支持 L.GetString(name, culture) 获取指定区域翻译 4.8.8.41 ⏱️2023.08.04 044b0ed
    •   多语言支持 DateTime 时间格式化配置节点 DateTimeFormatCulture 4.8.7.31 ⏱️2023.03.31 #I6RUOU
    •   多语言支持 .json 文件配置方式(推荐) 4.8.6 ⏱️2023.02.08 #I6DL71 #I5DXKP
    •   L.SetCurrentUICulture(culture)L.GetCurrentUICulture() 静态方法,可在运行时动态修改当前线程区域性 4.8.3.10 ⏱️2022.12.23 #I66JWA
    •   L.SetCulture(culture, immediately) 方法重载,可配置运行时修改多语言立即有效 4.8.3.10 ⏱️2022.12.23 #I66JWA
  • 其他更改

    •   多语言中间件 app.UseAppLocalization() 添加 Action<options> 委托参数 4.8.7.30 ⏱️2023.03.31 #I6RUOU
  • 文档

    •   多语言 .json 配置方式文档

21.1 全球化和本地化

全球化 是设计支持不同区域性的应用程序的过程。 全球化添加了对一组有关特定地理区域的已定义语言脚本的输入、显示和输出支持。

本地化 是将已经针对可本地化性进行处理的全球化应用调整为特定的区域性/区域设置的过程。

通俗来说,就是使应用或系统支持多语言切换。Furion 框架提供了完整支持多语言处理的服务。

21.2 注册服务

在使用多语言服务之前,必须先注册服务,如:

public void ConfigureServices(IServiceCollection services)
{
services.AddControllersWithViews()
.AddAppLocalization(); // 注册多语言
}

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}

// 配置多语言,必须在 路由注册之前
app.UseAppLocalization();

app.UseStaticFiles();
app.UseRouting();

// 其他中间件
}
特别注意

app.UseAppLocalization(); 必须在 app.UseRouting(); 之前注册。

21.3 如何使用

21.3.1 配置 LocalizationSettings

添加 LocalizationSettings 配置选项:

{
"LocalizationSettings": {
"SupportedCultures": ["zh-CN", "en-US"], // 配置支持的语言列表
"DefaultCulture": "zh-CN" // 配置默认语言,如果不配置,取 SupportedCultures 的第一项
}
}

21.3.2 创建 Resources 文件夹

接下来在 Web启动项目层 添加 Resources 文件夹,如图:(可配置放置任意层,见配置 AssemblyName

21.4 L 静态类

Furion 框架主要通过 L 静态类完成多语言转换,该静态类有以下属性和方法:

  • L.Text[文本]:转换文本多语言
  • L.Html[HTML代码, 格式化]:转换 Html 多语言
  • L.TextOf<T>()[文本]:转换文本多语言,使用该方式那么资源文件需使用完整类型限定名,Furion 4.8.6+ 支持
  • L.HtmlOf<T>()[HTML代码, 格式化]:转换 Html 多语言,使用该方式那么资源文件需使用完整类型限定名,Furion 4.8.6+ 支持
  • L.SetCulture(区域码):设置当前语言区域,默认在下一次请求有效,第二个参数设置 true 立即有效
  • L.GetSelectCulture():获取当前的语言区域
  • L.GetCultures():获取系统支持的多语言列表
  • L.SetCurrentUICulture(区域码):运行时设置当前线程语言区域,立即有效,Furion 4.8.3.10+ 版本有效
  • L.GetCurrentUICulture(): 获取当前线程 UI 区域性,Furion 4.8.3.10+ 版本有效
  • L.GetString<T>(u => u.属性): 根据表达式获取翻译,Furion 4.8.3.10+ 版本有效
  • L.GetString(name, culture): 获取指定的区域翻译,Furion 4.8.8.41+ 版本有效
  • L.GetDefaultCulture(): 获取本地配置默认语言,Furion 4.8.8.49+ 版本有效
小提示

通过 L.SetCulture 实际上是往客户端写入区域 Cookie 数据,也就是只对下一次请求有效,如果希望运行时立即有效,可通过 L.SetCurrentUICulture 设置或一起设置即可。

也可以直接通过设置 L.SetCulture(区域码, true) 立即生效(包含当前请求(线程)和下一次请求)。

21.5 使用例子

通过上面的配置步骤之后,我们就可以通过 L 静态类在代码任何位置使用了,如:

21.5.1 在类中使用

// 文本多语言
var apiInterface = L.Text["API 接口"];
var sourceCode = L.Text["源码地址"];
var other = L.Text["其他{0}", "的"];

// HTML 标记多语言
var name = L.Html["<b>Hello</b><i> {0}</i>", name];

21.5.2 在视图中使用

@using Furion.Localization

<div style="text-align:center;margin-top:50px;">
<p>让 .NET 开发更简单,更通用,更流行。</p>
<p>
<a href="/api">@L.Text["API 接口"]</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<a
href="https://gitee.com/dotnetchina/Furion"
target="_blank"
>@L.Text["源码地址"]</a
>
</p>
</div>

21.5.3 在验证特性中使用

[Required(ErrorMessage = "必填消息")]

所有验证特性已经自动支持多语言配置了,无需通过 L.Text[] 调用。

21.5.4 在异常消息中使用

using Furion.FriendlyException;

namespace Furion.Application
{
[ErrorCodeType]
public enum ErrorCodes
{
[ErrorCodeItemMetadata("用户名不能为空")]
z1000
}
}

所有异常消息特性已经自动支持多语言配置了,无需通过 L.Text[] 调用。

throw Oops.Oh(ErrorCodes.z1000);    // 自动应用多语言

21.5.5 SharedResource 模式

版本说明

以下内容仅限 Furion 4.3.7 + 版本使用。

正常情况下,我们都是通过 L.Text["Hello"] 方式输出 Hello 在不同的区域语言的翻译,但是会导致 Hello 硬编码字符串散落到处都是。

所以 Furion 提供了 SharedResource 模式,只需要创建一个 SharedResource.cs 类(可以任何名字)并添加对应的属性即可,如:

namespace Furion.Core;

public class SharedResource
{
public string Hello { get; set; }

public string Name { get; set; }
}

使用如下:

var hello = L.GetString<SharedResource>(u => u.Hello);  // 比 L.Text["Hello"]; 容易维护
var name = L.GetString<SharedResource>(u => u.Name); // 比 L.Text["Name"]; 容易维护

当然也有更简单的方式,就是使用 nameof,如:

var hello = L.Text[nameof(SharedResource.Hello)];  // 比 L.Text["Hello"]; 容易维护
var name = L.Text[nameof(SharedResource.Name)]; // 比 L.Text["Name"]; 容易维护

21.6 创建语言翻译文件

Furion 框架中,如果没找到对应的语言翻译文件,则自动显示字符串文本,如:

L.Text["没找到"];   // => 如果设置为英文,但是没有文件,则直接输出 “没找到”

21.6.1 在 Resources 文件夹中创建语言文件

接下来,我们只需要在刚刚的 Resources 文件夹中添加 .resx 资源文件即可,资源文件命名规则:Lang.区域码.resx,如:Lang.en-US.resx

接下来,只需要把对应语言版本的键值对填写即可。

自定义资源文件名或存放程序集

默认情况下,资源文件名必须以 Lang 开头,且默认放在启动层,如果需要自定义,添加配置文件即可

{
"LocalizationSettings": {
"LanguageFilePrefix": "MyLang"
// "AssemblyName": "你的其他层程序集名称"
}
}

之后,就可以:MyLang.区域码.resx

21.7 切换语言

Furion 提供了三种语言切换方式进行切换语言:

  • URL 参数 方式: ?culture=en-US此方式优先级最高,格式为:culture=区域码
  • Cookies 方式:调用 L.SetCulture(区域码) 方式切换
  • 客户端浏览器语言自动匹配:如果前面两种方式都没有设置,支持自动根据客户端浏览器语言进行匹配。

21.7.1 URL 参数 方式

21.7.2 Cookies 方式

此方式只需要提供一个 api 或设置代码即可:

L.SetCulture("en-US");  // en-US 也可以通过前端传递过来,这样就可以不用 `culture` 参数了,可以自定义参数。

这样就可以直接根据客户端存储的 cookies 自动切换了。

21.7.3 客户端浏览器语言自动切换

推荐此方式,可以自动根据浏览器的语言自动配置:

21.7.4 请求报文头 Accept-Language 方式

如果使用第三方工具请求,也可以添加请求报文头方式,如:

Accept-Language: en-US

如果使用第三方工具请求,也可以添加请求报文头方式,如:

Cookie: c%3Den-US%7Cuic%3Den-USen-US

它的明文格式为:c=en-US|uic=en-US

注意

这种方式不能使用 明文,否则无效。另外 cuic 的值通常一致。

21.8 依赖注入方式使用

Furion 框架也兼容 .NET Core 自带的依赖注入方式,如:

 public class TestController : Controller
{
private readonly IStringLocalizer _localizer;

public TestController(IStringLocalizerFactory factory)
{
_localizer = factory.Create();
}

public IActionResult About()
{
ViewData["Message"] = _localizer["Your application description page."];
}
}

21.9 LocalizationSettings 配置

  • LocalizationSettings 多语言配置根节点
    • ResourcesPath:资源目录,string 类型,默认 Resources
    • SupportedCultures:支持的语言区域码类别,string[] 类型
    • DefaultCulture:默认语言区域码,如果为空,则取 SupportedCultures 第一项
    • LanguageFilePrefix:配置资源文件前缀,string 类型,默认 Lang
    • AssemblyName:配置资源文件存放程序集名,string 类型,默认 启动层 名称

21.10 关于中文不能切换问题

若通过 dotnet build 命令行编译后发布的代码(比如 jenkins 以及其他 devops 工具),无法生成 zh-CN 资源文件,会出现中文无法显示的问题,这时候只需要将 Lang.zh-CN.resx 修改为:Lang.zh-Hans.resxLang.zh-Hant.resxLang.zh.resx 即可。

相关文档说明 https://docs.microsoft.com/zh-cn/dotnet/api/system.globalization.cultureinfo?view=net-6.0

21.11 基于 JSON 文件多语言

版本说明

以下内容仅限 Furion 4.8.6 + 版本使用。

在默认情况下,微软推荐使用 .resx 资源文件格式作为多语言配置文件格式,但此方式无法在运行时进行修改。所以社区更多使用的是 .json 文件格式作为多语言配置,可在运行时动态修改。


Furion 框架默认不提供 json 多语言配置功能,但非常容易集成第三方多语言库,在这里推荐:https://github.com/hishamco/My.Extensions.Localization.Json

1. 安装 My.Extensions.Localization.Json 拓展,通常安装在 XXX.Web.Core

dotnet add package My.Extensions.Localization.Json

2. 在 Startup.cs 中注册服务

public void ConfigureServices(IServiceCollection services)
{
services.AddControllersWithViews()
.AddAppLocalization(settings =>
{
// 集成第三方 json 配置
services.AddJsonLocalization(options => options.ResourcesPath = settings.ResourcesPath);
}); // 注册多语言
}

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}

// 配置多语言,必须在 路由注册之前
app.UseAppLocalization();

app.UseStaticFiles();
app.UseRouting();

// 其他中间件
}
特别注意

app.UseAppLocalization(); 必须在 app.UseRouting(); 之前注册。

3. 在 Resources 文件夹中添加 .json 文件即可,资源文件命名规则:Lang.区域码.json,如:Lang.en-US.json

自定义资源文件名或存放程序集

默认情况下,资源文件名必须以 Lang 开头,且默认放在启动层,如果需要自定义,添加配置文件即可

{
"LocalizationSettings": {
"LanguageFilePrefix": "MyLang"
// "AssemblyName": "你的其他层程序集名称"
}
}

之后,就可以:MyLang.区域码.json

4. 在代码中使用

L.Text["Furion"];   // => 如果设置为英文,但是没有文件,则直接输出 “Furion”
小知识

集成第三方多语言库除了注册服务和文件后缀名有区别,其他用法一模一样(包括全局配置,用法等),也就是任何时候替换成第三方都可以,业务使用代码无需更改。

21.12 多语言其他实现

asp.net core 本地化 文档中微软推荐了三个拓展开源项目:https://docs.microsoft.com/zh-cn/aspnet/core/fundamentals/localization-extensibility?view=aspnetcore-6.0#localization-resources

选择自己合适的即可。

21.13 在 WinForm/WPF 中使用

框架提供了完整的多语言在 WinForm/WPF 中使用。

21.13.1 WinForm 中使用

  • 注册 services.AddAppLocalization() 服务
using Microsoft.Extensions.DependencyInjection;

namespace WinFormsApp1;

internal static class Program
{
[STAThread]
static void Main()
{
Serve.RunNative(services =>
{
services.AddAppLocalization();
});
ApplicationConfiguration.Initialize();
Application.Run(new Form1());
}
}
  • 添加 appsettings.json 配置文件,并设置属性为 如果较新则复制
{
"LocalizationSettings": {
"SupportedCultures": ["zh-CN", "en-US"], // 配置支持的语言列表
"DefaultCulture": "zh-CN" // 配置默认语言,如果不配置,取 SupportedCultures 的第一项
}
}
  • 添加 Resources 文件夹并添加 Lang.区域码.resx 资源文件

参考 21.6.1 在 Resources 文件夹中创建语言文件

  • 在代码中使用
// 设置当前线程 UI 区域性
L.SetCurrentUICulture("en-US");
// 通过 L.Text[Key] 获取
label1.Text = L.Text["API 接口"];

21.13.2 在 WPF 中使用

  • 注册 services.AddAppLocalization() 服务
namespace WpfApp1;

public partial class App : Application
{
public App()
{
Serve.RunNative(services =>
{
services.AddAppLocalization();
});
}
}
  • 添加 appsettings.json 配置文件,并设置属性为 如果较新则复制
{
"LocalizationSettings": {
"SupportedCultures": ["zh-CN", "en-US"], // 配置支持的语言列表
"DefaultCulture": "zh-CN" // 配置默认语言,如果不配置,取 SupportedCultures 的第一项
}
}
  • 添加 Resources 文件夹并添加 Lang.区域码.resx 资源文件

参考 21.6.1 在 Resources 文件夹中创建语言文件

  • 在代码中使用
// 设置当前线程 UI 区域性
L.SetCurrentUICulture("en-US");
// 通过 L.Text[Key] 获取
label1.Name = L.Text["API 接口"];

21.14 关于 DateTime.Now 问题

版本说明

以下内容仅限 Furion 4.8.7.31 + 版本使用。

启用了多语言功能之后很有可能会影响 DateTime.Now 获取的时间所在的时区,比如设置多语言区域设置为 en-US,那么获取的就是国外的时间。所以,尽可能的使用 DateTime.UtcNow 或者 DateTimeOffset.UtNow 记录时间

当然也可以添加配置,固定时间区域为特定时区,比如北京时间。

{
"LocalizationSettings": {
"DateTimeFormatCulture": "zh-CN"
}
}

21.15 关于 Blazor 项目问题

如果使用的是 .razor 组件,那么只支持请求头中携带 Accept-Languagecookies 方式,有关配置可查阅相关 Issuehttps://gitee.com/dotnetchina/Furion/issues/I7ERGO

21.16 区域码列表

  • af 公用荷兰语
  • af-ZA 公用荷兰语 - 南非
  • sq 阿尔巴尼亚
  • sq-AL 阿尔巴尼亚 -阿尔巴尼亚
  • ar 阿拉伯语
  • ar-DZ 阿拉伯语 -阿尔及利亚
  • ar-BH 阿拉伯语 -巴林
  • ar-EG 阿拉伯语 -埃及
  • ar-IQ 阿拉伯语 -伊拉克
  • ar-JO 阿拉伯语 -约旦
  • ar-KW 阿拉伯语 -科威特
  • ar-LB 阿拉伯语 -黎巴嫩
  • ar-LY 阿拉伯语 -利比亚
  • ar-MA 阿拉伯语 -摩洛哥
  • ar-OM 阿拉伯语 -阿曼
  • ar-QA 阿拉伯语 -卡塔尔
  • ar-SA 阿拉伯语 - 沙特阿拉伯
  • ar-SY 阿拉伯语 -叙利亚共和国
  • ar-TN 阿拉伯语 -北非的共和国
  • ar-AE 阿拉伯语 - 阿拉伯联合酋长国
  • ar-YE 阿拉伯语 -也门
  • hy 亚美尼亚
  • hy-AM 亚美尼亚的 -亚美尼亚
  • az Azeri
  • az-AZ-Cyrl Azeri-(西里尔字母的) 阿塞拜疆
  • az-AZ-Latn Azeri(拉丁文)- 阿塞拜疆
  • eu 巴斯克
  • eu-ES 巴斯克 -巴斯克
  • be Belarusian
  • be-BY Belarusian-白俄罗斯
  • bg 保加利亚
  • bg-BG 保加利亚 -保加利亚
  • ca 嘉泰罗尼亚
  • ca-ES 嘉泰罗尼亚 -嘉泰罗尼亚
  • zh-HK 华 - 香港的 SAR
  • zh-MO 华 - 澳门的 SAR
  • zh-CN 华 -中国
  • zh-CHS 华 (单一化)
  • zh-SG 华 -新加坡
  • zh-TW 华 -台湾
  • zh-CHT 华 (传统的)
  • hr 克罗埃西亚
  • hr-HR 克罗埃西亚 -克罗埃西亚
  • cs 捷克
  • cs-CZ 捷克 - 捷克
  • da 丹麦文
  • da-DK 丹麦文 -丹麦
  • div Dhivehi
  • div-MV Dhivehi-马尔代夫
  • nl 荷兰
  • nl-BE 荷兰 -比利时
  • nl-NL 荷兰 - 荷兰
  • en 英国
  • en-AU 英国 -澳洲
  • en-BZ 英国 -伯利兹
  • en-CA 英国 -加拿大
  • en-CB 英国 -加勒比海
  • en-IE 英国 -爱尔兰
  • en-JM 英国 -牙买加
  • en-NZ 英国 - 新西兰
  • en-PH 英国 -菲律宾共和国
  • en-ZA 英国 - 南非
  • en-TT 英国 - 千里达托贝哥共和国
  • en-GB 英国 - 英国
  • en-US 英国 - 美国
  • en-ZW 英国 -津巴布韦
  • et 爱沙尼亚
  • et-EE 爱沙尼亚的 -爱沙尼亚
  • fo Faroese
  • fo-FO Faroese- 法罗群岛
  • fa 波斯语
  • fa-IR 波斯语 -伊朗王国
  • fi 芬兰语
  • fi-FI 芬兰语 -芬兰
  • fr 法国
  • fr-BE 法国 -比利时
  • fr-CA 法国 -加拿大
  • fr-FR 法国 -法国
  • fr-LU 法国 -卢森堡
  • fr-MC 法国 -摩纳哥
  • fr-CH 法国 -瑞士
  • gl 加利西亚
  • gl-ES 加利西亚 -加利西亚
  • ka 格鲁吉亚州
  • ka-GE 格鲁吉亚州 -格鲁吉亚州
  • de 德国
  • de-AT 德国 -奥地利
  • de-DE 德国 -德国
  • de-LI 德国 -列支敦士登
  • de-LU 德国 -卢森堡
  • de-CH 德国 -瑞士
  • el 希腊
  • el-GR 希腊 -希腊
  • gu Gujarati
  • gu-IN Gujarati-印度
  • he 希伯来
  • he-IL 希伯来 -以色列
  • hi 北印度语
  • hi-IN 北印度的 -印度
  • hu 匈牙利
  • hu-HU 匈牙利的 -匈牙利
  • is 冰岛语
  • is-IS 冰岛的 -冰岛
  • id 印尼
  • id-ID 印尼 -印尼
  • it 意大利
  • it-IT 意大利 -意大利
  • it-CH 意大利 -瑞士
  • ja 日本
  • ja-JP 日本 -日本
  • kn 卡纳达语
  • kn-IN 卡纳达语 -印度
  • kk Kazakh
  • kk-KZ Kazakh-哈萨克
  • kok Konkani
  • kok-IN Konkani-印度
  • ko 韩国
  • ko-KR 韩国 -韩国
  • ky Kyrgyz
  • ky-KZ Kyrgyz-哈萨克
  • lv 拉脱维亚
  • lv-LV 拉脱维亚的 -拉脱维亚
  • lt 立陶宛
  • lt-LT 立陶宛 -立陶宛
  • mk 马其顿
  • mk-MK 马其顿 -FYROM
  • ms 马来
  • ms-BN 马来 -汶莱
  • ms-MY 马来 -马来西亚
  • mr 马拉地语
  • mr-IN 马拉地语 -印度
  • mn 蒙古
  • mn-MN 蒙古 -蒙古
  • no 挪威
  • nb-NO 挪威 (Bokm?l) - 挪威
  • nn-NO 挪威 (Nynorsk)- 挪威
  • pl 波兰
  • pl-PL 波兰 -波兰
  • pt 葡萄牙
  • pt-BR 葡萄牙 -巴西
  • pt-PT 葡萄牙 -葡萄牙
  • pa Punjab 语
  • pa-IN Punjab 语 -印度
  • ro 罗马尼亚语
  • ro-RO 罗马尼亚语 -罗马尼亚
  • ru 俄国
  • ru-RU 俄国 -俄国
  • sa 梵文
  • sa-IN 梵文 -印度
  • sr-SP-Cyrl 塞尔维亚 -(西里尔字母的) 塞尔维亚共和国
  • sr-SP-Latn 塞尔维亚 (拉丁文)- 塞尔维亚共和国
  • sk 斯洛伐克
  • sk-SK 斯洛伐克 -斯洛伐克
  • sl 斯洛文尼亚
  • sl-SI 斯洛文尼亚 -斯洛文尼亚
  • es 西班牙
  • es-AR 西班牙 -阿根廷
  • es-BO 西班牙 -玻利维亚
  • es-CL 西班牙 -智利
  • es-CO 西班牙 -哥伦比亚
  • es-CR 西班牙 - 哥斯达黎加
  • es-DO 西班牙 - 多米尼加共和国
  • es-EC 西班牙 -厄瓜多尔
  • es-SV 西班牙 - 萨尔瓦多
  • es-GT 西班牙 -危地马拉
  • es-HN 西班牙 -洪都拉斯
  • es-MX 西班牙 -墨西哥
  • es-NI 西班牙 -尼加拉瓜
  • es-PA 西班牙 -巴拿马
  • es-PY 西班牙 -巴拉圭
  • es-PE 西班牙 -秘鲁
  • es-PR 西班牙 - 波多黎各
  • es-ES 西班牙 -西班牙
  • es-UY 西班牙 -乌拉圭
  • es-VE 西班牙 -委内瑞拉
  • sw Swahili
  • sw-KE Swahili-肯尼亚
  • sv 瑞典
  • sv-FI 瑞典 -芬兰
  • sv-SE 瑞典 -瑞典
  • syr Syriac
  • syr-SY Syriac-叙利亚共和国
  • ta 坦米尔
  • ta-IN 坦米尔 -印度
  • tt Tatar
  • tt-RU Tatar-俄国
  • te Telugu
  • te-IN Telugu-印度
  • th 泰国
  • th-TH 泰国 -泰国
  • tr 土耳其语
  • tr-TR 土耳其语 -土耳其
  • uk 乌克兰
  • uk-UA 乌克兰 -乌克兰
  • ur Urdu
  • ur-PK Urdu-巴基斯坦
  • uz Uzbek
  • uz-UZ-Cyrl Uzbek-(西里尔字母的) 乌兹别克斯坦
  • uz-UZ-Latn Uzbek(拉丁文)- 乌兹别克斯坦
  • vi 越南
  • vi-VN 越南 -越南

21.17 反馈与建议

与我们交流

给 Furion 提 Issue


了解更多

想了解更多 多语言 知识可查阅 ASP.NET Core - 全局化和本地化 章节。