zoukankan      html  css  js  c++  java
  • .NET Core中多语言支持

    在.NET Core项目中也是可以使用.resx资源文件,来为程序提供多语言支持。以下我们就以一个.NET Core控制台项目为例,来讲解资源文件的使用。

    新建一个.NET Core控制台项目,然后我们在其中新建一个.resx资源文件叫DemoResource.resx

    注意.resx资源文件默认是Internal访问级别的,这会导致其它程序集无法访问资源文件类,所以我们最好将其改为Public访问级别

    然后我们在资源文件DemoResource.resx中定义一个字符串叫"Message",值为"Hello",如下所示:

    由于资源文件是支持多语言的,其文件名命名格式如下:

    {资源文件名}.{语言文化名称}.resx

    其中{语言文化名称}就是诸如:zh-CN、en-US、ja-JP等语言字符串,代表了一种特定的语言,例如zh-CN就是简体中文。

    所以现在我们就为资源文件DemoResource.resx再创造两种语言:

    DemoResource.zh-CN.resx,简体中文资源文件:

    DemoResource.ja-JP.resx,日语资源文件:

    所以我们现在,就有三个资源文件:

    • DemoResource.resx是默认的资源文件,我们将其内部的字符串Message定义为了英文。
    • DemoResource.zh-CN.resx是简体中文资源文件,我们将其内部的字符串Message定义为了简体中文。
    • DemoResource.ja-JP.resx是日语资源文件,我们将其内部的字符串Message定义为了日语。

    其实它们代表的都是DemoResource资源文件,只不过是不同的语言版本罢了,现在项目结构如下所示:

    好了,现在定义好了资源文件,我们就来看看怎么使用它们。

    在.NET Core中.resx资源文件是和线程的语言相关,其主要和当前线程的如下两个语言属性相关:

    • Thread.CurrentThread.CurrentCulture
    • Thread.CurrentThread.CurrentUICulture

    如果当前线程的这两个属性是什么语言,那么.resx资源文件就会返回对应语言的内容。

    首先我们在.NET Core控制台项目的Main方法中,设置当前线程的CurrentCulture和CurrentUICulture为zh-CN:

    static void Main(string[] args)
    {
        Thread.CurrentThread.CurrentCulture = new CultureInfo("zh-CN");
        Thread.CurrentThread.CurrentUICulture = new CultureInfo("zh-CN");
    
        Console.WriteLine($"Message为:{DemoResource.Message}");
    
        Console.WriteLine("按任意键结束...");
        Console.ReadKey();
    }

    运行结果如下,我们可以看到显示的Message为中文"你好"

    现在我们将当前线程的CurrentCulture和CurrentUICulture设置为ja-JP:

    static void Main(string[] args)
    {
        Thread.CurrentThread.CurrentCulture = new CultureInfo("ja-JP");
        Thread.CurrentThread.CurrentUICulture = new CultureInfo("ja-JP");
    
        Console.WriteLine($"Message为:{DemoResource.Message}");
    
        Console.WriteLine("按任意键结束...");
        Console.ReadKey();
    }

    运行结果如下,我们可以看到显示的Message为日文"こんにちは"

    然后,我们将当前线程的CurrentCulture和CurrentUICulture设置为fr-FR,代表法语:

    static void Main(string[] args)
    {
        Thread.CurrentThread.CurrentCulture = new CultureInfo("fr-FR");
        Thread.CurrentThread.CurrentUICulture = new CultureInfo("fr-FR");
    
        Console.WriteLine($"Message为:{DemoResource.Message}");
    
        Console.WriteLine("按任意键结束...");
        Console.ReadKey();
    }

    那么现在结果是什么呢,如下所示:

    可能很多同学会觉得很奇怪为什么Message显示的是英语"Hello"。其实道理很简单,因为我们没有定义DemoResource.fr-FR.resx这个法语资源文件啊,所以在当前线程的CurrentCulture和CurrentUICulture为fr-FR时,调用DemoResource.Message时,.NET Core只好使用DemoResource默认资源文件DemoResource.resx的内容,所以DemoResource.Message输出的是英文"Hello"。

    其实资源文件类DemoResource也是可以通过设置其Culture属性来指定使用某一种特定的语言,如下代码所示,虽然我们设置当前线程的CurrentCulture和CurrentUICulture为ja-JP,但是由于我们设置了DemoResource.Culture为zh-CN:

    static void Main(string[] args)
    {
        Thread.CurrentThread.CurrentCulture = new CultureInfo("ja-JP");
        Thread.CurrentThread.CurrentUICulture = new CultureInfo("ja-JP");
    
        DemoResource.Culture = new CultureInfo("zh-CN");
    
        Console.WriteLine($"Message为:{DemoResource.Message}");
    
        Console.WriteLine("按任意键结束...");
        Console.ReadKey();
    }

    所以最后显示的Message为中文"你好"

    Async和Await模式对线程语言的影响

    有的同学可能会想.NET Core中的Async和Await模式,会对Thread.CurrentThread.CurrentCulture和Thread.CurrentThread.CurrentUICulture这两个线程的语言属性产生影响吗。

    我们来看看如下代码:

    /// <summary>
    /// 测试Async和Await模式,是否会对Thread.CurrentThread.CurrentCulture和Thread.CurrentThread.CurrentUICulture产生影响
    /// </summary>
    static void AsyncAwaitThreadCulture()
    {
        //设置主线程的CurrentCulture和CurrentUICulture为语言ja-JP
        Thread.CurrentThread.CurrentCulture = new CultureInfo("ja-JP");
        Thread.CurrentThread.CurrentUICulture = new CultureInfo("ja-JP");
    
        Console.WriteLine($"Thread id:{Thread.CurrentThread.ManagedThreadId.ToString()}=>主线程的CurrentCulture是{Thread.CurrentThread.CurrentCulture.ToString()}, CurrentUICulture是{Thread.CurrentThread.CurrentUICulture.ToString()}");
    
        //通过Task来启动第一层线程
        Task.Run(async () =>
        {
            Console.WriteLine($"Thread id:{Thread.CurrentThread.ManagedThreadId.ToString()}=>第一层线程的CurrentCulture是{Thread.CurrentThread.CurrentCulture.ToString()}, CurrentUICulture是{Thread.CurrentThread.CurrentUICulture.ToString()}");
    
            //通过Task来启动第二层线程
            Task task = Task.Run(() =>
            {
                Console.WriteLine($"Thread id:{Thread.CurrentThread.ManagedThreadId.ToString()}=>第二层线程的CurrentCulture是{Thread.CurrentThread.CurrentCulture.ToString()}, CurrentUICulture是{Thread.CurrentThread.CurrentUICulture.ToString()}");
    
                //通过Thread来启动第三层线程
                Thread th = new Thread(new ThreadStart(() =>
                {
    
                    Thread.Sleep(3000);
    
                    Console.WriteLine($"Thread id:{Thread.CurrentThread.ManagedThreadId.ToString()}=>第三层线程的CurrentCulture是{Thread.CurrentThread.CurrentCulture.ToString()}, CurrentUICulture是{Thread.CurrentThread.CurrentUICulture.ToString()}");
                }));
    
                th.IsBackground = true;
                th.Start();
    
                th.Join();//阻塞第二层线程,直到第三层线程th结束
            });
    
            Thread.Sleep(1000);
    
            Console.WriteLine($"Thread id:{Thread.CurrentThread.ManagedThreadId.ToString()}=>await之前CurrentCulture是{Thread.CurrentThread.CurrentCulture.ToString()}, CurrentUICulture是{Thread.CurrentThread.CurrentUICulture.ToString()}");
    
            await task;//await,直到第二层线程结束
    
            Console.WriteLine($"Thread id:{Thread.CurrentThread.ManagedThreadId.ToString()}=>await之后CurrentCulture是{Thread.CurrentThread.CurrentCulture.ToString()}, CurrentUICulture是{Thread.CurrentThread.CurrentUICulture.ToString()}");
    
        }).Wait();//阻塞主线程,直到第一层线程执行完毕
    }

    运行结果如下所示:

    我们在AsyncAwaitThreadCulture方法中,将主线程的CurrentCulture和CurrentUICulture设置为了ja-JP,结果可以发现后续启动的线程其CurrentCulture和CurrentUICulture也都为ja-JP

    现在我们设置主线程的CurrentCulture和CurrentUICulture为ja-JP,但是将第一层线程的CurrentCulture和CurrentUICulture改为zh-CN

    /// <summary>
    /// 测试Async和Await模式,是否会对Thread.CurrentThread.CurrentCulture和Thread.CurrentThread.CurrentUICulture产生影响
    /// </summary>
    static void AsyncAwaitThreadCulture()
    {
        //设置主线程的CurrentCulture和CurrentUICulture为语言ja-JP
        Thread.CurrentThread.CurrentCulture = new CultureInfo("ja-JP");
        Thread.CurrentThread.CurrentUICulture = new CultureInfo("ja-JP");
    
        Console.WriteLine($"Thread id:{Thread.CurrentThread.ManagedThreadId.ToString()}=>主线程的CurrentCulture是{Thread.CurrentThread.CurrentCulture.ToString()}, CurrentUICulture是{Thread.CurrentThread.CurrentUICulture.ToString()}");
    
        //通过Task来启动第一层线程
        Task.Run(async () =>
        {
            //将第一层线程的CurrentCulture和CurrentUICulture改为zh-CN
            Thread.CurrentThread.CurrentCulture = new CultureInfo("zh-CN");
            Thread.CurrentThread.CurrentUICulture = new CultureInfo("zh-CN");
    
            Console.WriteLine($"Thread id:{Thread.CurrentThread.ManagedThreadId.ToString()}=>第一层线程的CurrentCulture是{Thread.CurrentThread.CurrentCulture.ToString()}, CurrentUICulture是{Thread.CurrentThread.CurrentUICulture.ToString()}");
    
            //通过Task来启动第二层线程
            Task task = Task.Run(() =>
            {
                Console.WriteLine($"Thread id:{Thread.CurrentThread.ManagedThreadId.ToString()}=>第二层线程的CurrentCulture是{Thread.CurrentThread.CurrentCulture.ToString()}, CurrentUICulture是{Thread.CurrentThread.CurrentUICulture.ToString()}");
    
                //通过Thread来启动第三层线程
                Thread th = new Thread(new ThreadStart(() =>
                {
    
                    Thread.Sleep(3000);
    
                    Console.WriteLine($"Thread id:{Thread.CurrentThread.ManagedThreadId.ToString()}=>第三层线程的CurrentCulture是{Thread.CurrentThread.CurrentCulture.ToString()}, CurrentUICulture是{Thread.CurrentThread.CurrentUICulture.ToString()}");
                }));
    
                th.IsBackground = true;
                th.Start();
    
                th.Join();//阻塞第二层线程,直到第三层线程th结束
            });
    
            Thread.Sleep(1000);
    
            Console.WriteLine($"Thread id:{Thread.CurrentThread.ManagedThreadId.ToString()}=>await之前CurrentCulture是{Thread.CurrentThread.CurrentCulture.ToString()}, CurrentUICulture是{Thread.CurrentThread.CurrentUICulture.ToString()}");
    
            await task;//await,直到第二层线程结束
    
            Console.WriteLine($"Thread id:{Thread.CurrentThread.ManagedThreadId.ToString()}=>await之后CurrentCulture是{Thread.CurrentThread.CurrentCulture.ToString()}, CurrentUICulture是{Thread.CurrentThread.CurrentUICulture.ToString()}");
    
        }).Wait();//阻塞主线程,直到第一层线程执行完毕
    }

    现在运行结果如下:

    我们可以看到从第一层线程开始,后续启动线程的CurrentCulture和CurrentUICulture都为zh-CN了

    这说明在.NET Core中,默认情况下线程的CurrentCulture和CurrentUICulture属性是由启动它的线程来决定的,上面的结果很明显由于第一层线程的CurrentCulture和CurrentUICulture为zh-CN,所以由第一层线程启动的后续线程(第二层和第三层线程)也都为zh-CN。所以在.NET Core中要设置线程的CurrentCulture和CurrentUICulture属性,最简单的办法就是在根线程(主线程)上设置CurrentCulture和CurrentUICulture的语言即可。

    最后如果是在ASP.NET Core中,只需要写一个中间件(Middleware),来更改主线程的CurrentCulture和CurrentUICulture属性为特定语言,即可实现.resx资源文件的全局利用,当然ASP.NET Core中也有一套自带的资源文件匹配规则,这里大家觉得怎么用起来方便怎么用即可。

    本文示例源代码

  • 相关阅读:
    SCOM 初探 [SCOM应用系列之一]
    SCOM 安装部署 [SCOM应用系列之二]
    CMMI 配置管理(Configuration Management)系列(1) 简介
    设计模式总结之创建型设计模式
    tabbar图片渲染的问题
    react实现自定义hooks(节流和防抖)
    前端工程化5js源码编译和ast
    react实现自定义hooks(跑马灯)
    react实现自定义hooks(倒计时)
    react实现自定义hooks(移动端拖拽)
  • 原文地址:https://www.cnblogs.com/OpenCoder/p/10075643.html
Copyright © 2011-2022 走看看