.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中也有一套自帶的資源文件匹配規則,這里大家覺得怎么用起來方便怎么用即可。

 

本文示例源代碼

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM