[C#] CultureInfo 在 Windows 與 Linux Docker 行為不一致的現象

  • 573
  • 0
  • C#
  • 2020-11-13

剛第一次文章存檔,又遭遇跟上次相同問題

點下新增按鈕後,畫面重整回到首頁
再進入管理後台的文章列表,卻沒有看到剛剛新增的文章

重新再點一次新增文章,裡面有可供還原的暫存草稿
也是一開始剛編輯這篇文章的版本,不是幾分鐘前寫完要存檔的

還好這次都有先複製原始碼出去,再按存檔
在猜測是不是編輯文章時網頁如果放置太久,就會發生類似 session 斷線的問題
其實早已變成離線狀態在編輯了 -.- ?
 


今天遇到 2 個狀況:在 C# 專案使用了資源檔定義多語系文字
*.resx (英文)
*.zh-cn.resx (簡體中文)

並利用以下方法,讓前端傳入語系字串 lang ("en-us"、"zh-cn")
查詢、組合出多語系物件後,回傳給前端共用

var cultureInfo = new CultureInfo(lang);
var resourceSet = resourceManager.GetResourceSet(cultureInfo, true, true);

1. 在 Win10 本機上運作符合預期
但當跑在 docker 裡面時,傳入 zh-cn 返回的結果卻依然是英文?


2. 第二個問題是,前端在 index.html 若沒找到語系 Cookie,會向後端查詢語系預設值
後端是使用下面這個方法,取得當前 CultureInfo.Name 回傳

CultureInfo.CurrentUICulture.Name

但在 docker 內執行卻發生收到空字串 "" 的情形

使用的 docker image 是這個版本
mcr.microsoft.com/dotnet/core/aspnet:3.1-buster-slim

 

經過一番查詢,找到以下 2 個相關的 Issue:

zh-CN / zh-TW don't use parent cultures of zh-Hans/zh-Hant on Linux #12263
https://github.com/dotnet/runtime/issues/12263

Cultures aliased by ICU cannot be used for resource localization on non-Windows environments #3897
https://github.com/dotnet/msbuild/issues/3897

第 2 個 Issue 是反應在 msbuild repo 的,不過我覺得大致是相關問題
第 1 個 Issue 則是 .NET runtime repo 的,剛好都是同一個 maintainer 回覆問題

這個 maintainer 說

zh-CN and zh-TW are not the ISO names of the cultures.
These are Microsoft thingy and Linux just allow creating them as aliased cultures.

The right culture names are
zh-Hans-CN
zh-Hant-TW

大意是說 zh-CN、zh-TW 都不是標準的 ISO Culture Name
正確的應該是 zh-Hans-CN、zh-Hant-TW
在 Windows 可以跑,那是微軟搞的東西 (大概是指有自動做一些別名的相容處理?請求指正)

他不想要因為相同理由也在 .NET Core (前幾天變 .NET 5 了!) 為這些 Culture 做一些客製的事情
建議就直接改用正確的 Culture Name。
好了我要 close issue 了!

 

回到自己的問題:

1. 那就從善如流,將 *.zh-cn.resx 都更名為 zh-Hans-CN.resx
前端要給後端的語系查詢字串也一併修改

2. 這個比較看每個系統流程上想要怎麼給預設值,可以在前端也可以在後端處理
總之在前端呼叫設定語系前 $translate.set(languageCode)

萬一檢查到
CultureInfo.CurrentUICulture 等於 CultureInfo.InvariantCulture
CultureInfo.CurrentUICulture.Name 等於"" (空字串)
等情況

可以
設定預設語系 System.Threading.Thread.CurrentThread.CurrentUICulture = CultureInfo.GetCultureInfo("en-US");
或是前端直接設定 $translate.set('en-US')

之類的......

 

有錯誤之處請包涵並協助指正,感謝

 

參考連結
https://github.com/dotnet/runtime/issues/12263
https://github.com/dotnet/msbuild/issues/3897
.NET globalization and ICU
https://docs.microsoft.com/zh-tw/dotnet/standard/globalization-localization/globalization-icu