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> <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
21.7.5 请求报文头 Cookie
方式
如果使用第三方工具请求,也可以添加请求报文头方式,如:
Cookie: c%3Den-US%7Cuic%3Den-USen-US
它的明文格式为:c=en-US|uic=en-US
。
这种方式不能使用 明文
,否则无效。另外 c
和 uic
的值通常一致。
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.resx
或 Lang.zh-Hant.resx
或 Lang.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-Language
和 cookies
方式,有关配置可查阅相关 Issue
:https://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 - 全局化和本地化 章节。