.NET Core中多语言支持

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

 

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

 

注意.resx资源文件默认是Internal访问级别的,这会致使其它程序集没法访问资源文件类,因此咱们最好将其改成Public访问级别spa

 

而后咱们在资源文件DemoResource.resx中定义一个字符串叫"Message",值为"Hello",以下所示:线程

 

因为资源文件是支持多语言的,其文件名命名格式以下:code

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

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

 

因此如今咱们就为资源文件DemoResource.resx再创造两种语言:ip

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中也有一套自带的资源文件匹配规则,这里你们以为怎么用起来方便怎么用便可。

 

本文示例源代码

相关文章
相关标签/搜索