C# WinForms 多語系完整教學 (無法切換語言的解決方式、ResXManager 套件使用)

通常我們會在專案中再建立一層資料夾,名稱為 Resources ,將所有多語系和其他資源放在這個資料夾內。
使用滑鼠右鍵點擊 Resources 資料夾 > 加入 > 新增項目

選擇「C# 項目」中的「資源檔」,預設名稱是 Resource1.resx ,我們示範的專案是 WinForms ,要在 Form1.cs 中將程式碼產生的文字內容做多語系轉換,所以這裡命名為 Form1.resx

本次示範很簡單,就是在 Form1.cs 中顯示一個 MessageBox,後面會將此訊息依照不同的語系顯示不同的內容:
    
public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();

        MessageBox.Show("Initializing", "Form1");
    }
}
    

筆者平時使用 Rider 編輯器開發,就算使用 Visual Studio 時也會使用 ReSharper 套件(付費),可以自動將文字內容抽取放到文字資源檔中,具筆者所知 Visual Studio 預設是沒有類似的功能。
所以我們回到剛剛建立的 Form1.resx 檔案中,加入兩筆紀錄,這個是在不指定語系時預設要顯示的內容:
    
Form1_Constructor_MessageBox_Text	Initializing
Form1_Constructor_MessageBox_Title	Form1
    


此時回到程式內就可以使用這個文字資源:
    
public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();

        MessageBox.Show(
            Resources.Form1.Form1_Constructor_MessageBox_Text,
            Resources.Form1.Form1_Constructor_MessageBox_Title
        );
    }
}
    

可以正常執行,阿多語系呢?別急,再依照相同的步驟再建立一次資源檔,這次命名為 Form1.zh-hant-tw.resx

然後修改 Program.cs ,加入以下三行:
    
static class Program
{
    /// <summary>
    ///  The main entry point for the application.
    /// </summary>
    [STAThread]
    static void Main()
    {
        // To customize application configuration such as set high DPI settings or default font,
        // see https://aka.ms/applicationconfiguration.

        var culture = CultureInfo.GetCultureInfo("zh-hant-tw");
        CultureInfo.DefaultThreadCurrentCulture = culture;
        CultureInfo.DefaultThreadCurrentUICulture = culture;

        ApplicationConfiguration.Initialize();
        Application.Run(new Form1());
    }
}
    

這時候直接執行:

很好,成...什麼鬼?怎麼不能?! 執行不能那發布呢?發布的參數不論是選擇 Framework 相依性、獨立式、可攜式、或是單獨指定作業系統版本筆者全部都嘗試了很多遍,剛剛測試時使用 Rider 編輯器明明都可以的阿...阿使用 Visual Studio 怎麼都無法讀取到正確的語系資料?比對之後發現產生出來的檔案居然沒有包含語系檔:

不過若是使用指令執行則可以正常產生語系檔案,執行結果也是正常的會依照語系內容轉換:
    
dotnet run
    


那使用指令發布呢?
    
dotnet publish -c Release
    

也是有正常出現語系名稱的 zh-hant-tw 資料夾,裡面也有打包後的 WinFormsAppLocalizationTest2.resources.dll 資源檔案。

那再次使用筆者最常用的開發工具 Rider 呢?

發布也是有正常出現資源檔案,可以正常切換語系。

研究了許久後發現比較有可能的是在資源檔的「存取修飾詞」是沒有程式碼產生,和檔案屬性的「複製到輸出目錄」為「不要複製」

在專案的 .csproj 檔案中預設內容如下
    
<Project Sdk="Microsoft.NET.Sdk">

    <PropertyGroup>
        <OutputType>WinExe</OutputType>
        <TargetFramework>net6.0-windows</TargetFramework>
        <Nullable>enable</Nullable>
        <UseWindowsForms>true</UseWindowsForms>
        <ImplicitUsings>enable</ImplicitUsings>
    </PropertyGroup>

    <ItemGroup>
      <Compile Update="Resources\Form1.Designer.cs">
        <DesignTime>True</DesignTime>
        <AutoGen>True</AutoGen>
        <DependentUpon>Form1.resx</DependentUpon>
      </Compile>
    </ItemGroup>

    <ItemGroup>
      <EmbeddedResource Update="Resources\Form1.resx">
        <Generator>ResXFileCodeGenerator</Generator>
        <LastGenOutput>Form1.Designer.cs</LastGenOutput>
      </EmbeddedResource>
      <EmbeddedResource Update="Resources\Form1.zh-hant-tw.resx">
        <Generator></Generator>
      </EmbeddedResource>
    </ItemGroup>

</Project>
    

就算將「複製到輸出目錄」改為「永遠複製」,也只是在 Generator 下面增加了
    
        <CopyToOutputDirectory>Always</CopyToOutputDirectory>
    

在除錯和發布時會產生 Resources/Form1.zh-hant-tw.resx ,並不會和指令和 Rider 發布時一樣經過處理,轉換為 dll 檔案

將 Form1 的 Localizable 設定為 True 也是一樣,並且 EmbeddedResource 中的 Update 也無法改為 Include ,會出現下列錯誤:
    
0>------- Started building project: WinFormsAppLocalizationTest2
0>Microsoft.NET.Sdk.DefaultItems.Shared.targets(201,5): Error NETSDK1022 : 包含 'EmbeddedResource' 個重複的項目。根據預設,.NET SDK 會包含來自您專案目錄的 'EmbeddedResource' 個項目。您可以從專案檔移除這些項目,或若想要在專案檔中明確地納入這些項目,也可以將 'EnableDefaultEmbeddedResourceItems' 屬性設定為 'false'。如需詳細資訊,請參閱 https://aka.ms/sdkimplicititems。重複的項目為: 'Resources\Form1.zh-hant-tw.resx'
0>------- Finished building project: WinFormsAppLocalizationTest2. Succeeded: False. Errors: 1. Warnings: 0
    

因為預設在打包的時候就會包含了,所以直接使用 dotnet 指令才會可以成功,目前筆者還沒有找出在 Visual Studio 2022 中可以正常執行的方式,但是測試了許多方式使用指令發布的檔案在測試的其他環境中都是可以正常執行的,或許真的是 Visual Studio 的問題,目前發布的時候可能真的只能先使用指令或 Rider 發布了。

使用 ResXManager 套件編輯多語系檔案

在 Visual Studio 2022 上方工具列 延伸模組 > 管理延伸模組 > 線上,在右上角搜尋框輸入 ResXManager ,點選下載,然後將 Visual Studio 關閉後會跳出安裝介面,安裝完成後再次開啟 Visual Studio:

此時在任意多語系檔案上面點選滑鼠右鍵 > Open in ResX Manager 就會開啟這個套件的編輯介面,和 Visual Studio 原本的文字資源編輯介面相比,這個專門設計用來編輯多語系的介面真的好用很多,可以一次看到不同語言的內容,在修改上非常方便,也可以匯出和匯入 csv 檔案方便處理。

如果是使用 Rider ,也有好用的 Localization Manager 工具可以使用,預設直接點擊多語系檔案就會跳出,也可以同時看到不同的語系,同樣也有匯出和匯入 csv 的功能。



參考資料:
Microsoft.Learn - Localization in .NET
Microsoft.Learn - Work with .resx files programmatically
Microsoft.Learn - dotnet publish
Visual Studio Marketplace - ResXManager

留言