.net core在Linux本地化Localization的一次填坑

  使用ABP框架開發.net core程序已經有一段時間了,由於以前部署在windows服務器上,使用一直很正常。自從前段時間切換服務器上了Linux的Centos服務器,發現以前中文的語言變成了英文,一直找不到緣由。linux

 

  由於以前windows是好的,因此確定是環境問題,最直接的就是Linux本地化引發的。若是對Linux本地化命令不瞭解的,能夠看一下這裏docker

 

果真是en_US,嘗試切換使用 LANG=zh_CNshell

成功了,這裏得要全局設置使用 export LANG=zh_CN ,不然其餘session 不會生效。如今好了,重新訪問,但仍是不行。既然Linux系統的本地化已經設置好了,但程序仍是不行,只能從代碼入手。ubuntu

Abp.Localization.Dictionaries.DictionaryBasedLocalizationSource GetStringOrNull 中發現,windows

var cultureName = culture.Name;
var dictionaries = DictionaryProvider.Dictionaries;

//Try to get from original dictionary (with country code)
ILocalizationDictionary originalDictionary;
if (dictionaries.TryGetValue(cultureName, out originalDictionary))
{
    var strOriginal = originalDictionary.GetOrNull(name);
    if (strOriginal != null)
    {
        return strOriginal.Value;
    }
}

它是經過DictionaryProvider.Dictionaries 的字典類型,找到咱們預約的字體語言集bash

可是,經過服務器

ILocalizationDictionaryProvider DictionaryProvider = ((IDictionaryBasedLocalizationSource)LocalizationManager.GetSource(CmsIdentityConsts.LocalizationSourceName)).DictionaryProvider;

發現DictionaryProvider.Dictionaries 只有一個en的類型,也就是咱們默認第一個的英文字體包,爲何沒有了咱們定義的中文和繁體包了呢?session

經過追查代碼在Abp.Localization.Dictionaries.Xml.XmlEmbeddedFileLocalizationDictionaryProvider 的 Initialize 中發現,它的代碼以下:框架

var allCultureInfos = CultureInfo.GetCultures(CultureTypes.AllCultures);
var resourceNames = _assembly.GetManifestResourceNames().Where(resouceName => allCultureInfos.Any(culture => resouceName.EndsWith($"{sourceName}.xml", true, null) || resouceName.EndsWith($"{sourceName}-{culture.Name}.xml", true, null))).ToList();

 主要是這個CultureInfo.GetCultures(CultureTypes.AllCultures) 函數,它的結果發現以下:ide

截取部分,發現並無zh-CN,取而代之的是zh-Hans-CN。而咱們判斷當前線程是什麼語言,使用的是Thread.CurrentThread.CurrentUICulture 或者 CultureInfo.CurrentUICulture 或者 CultureInfo.CurrentCulture 這三個函數,分別得到的結果是

這兩個對不上,是否是很奇怪,爲何CultureInfo.GetCultures(CultureTypes.AllCultures) 和CultureInfo.CurrentCulture 這兩個結果盡然不一致。那爲何咱們在windows時候是好的呢,再在windows下執行以下:

發現原來windows是有的,linux就沒有了。這就解釋了爲何windows是好的,而Linux則出問題。網上查了好多資料,說是zh-CN過期了,不推薦,新的標準的zh-Hans-CN,反正都是沒什麼用的。

 經過代碼發現它是經過拼接,獲得咱們定義的語言集的 {sourceName}-{culture.Name}.xml , 那咱們不是改如下文件的命名就能夠了,說幹就幹。

果真,如今加載的時候可以得到三個語言包了。可是zh-Hans-CN和zh-CN的名字對不上怎麼辦?嘗試設置線程 

var currentCulture = System.Globalization.CultureInfo.CreateSpecificCulture("zh-Hans-CN");
Thread.CurrentThread.CurrentCulture = currentCulture;
Thread.CurrentThread.CurrentUICulture = currentCulture.GetConsoleFallbackUICulture();

 很不幸,三個函數中只有最後一個才能得到:

上ABP官網論壇和網上找了半天,別人都沒有說這裏有問題,摒着不改源代碼,相信廣大碼農的原則下,自我排查,是否是還有別的方法。靈感一現,文件名對應着語言的包名,XML裏面不是還定義了一個參數麼,把它改爲zh-CN會不會好使:

再訪問網站

結果,哈哈成功了!證實它經過當前線程查找的語言包是和內部XML定義的一致,完美解決!

Docker部署

說白了,在linux下運行,那Docker是必不可少的。可是直接運行在ubuntu 上面的鏡像是沒有語言包的。

sudo docker run -i -t <id> /bin/bash
root@<id>:/# locale
LANG=
LANGUAGE=
LC_CTYPE="POSIX"
LC_NUMERIC="POSIX"
LC_TIME="POSIX"
LC_COLLATE="POSIX"
LC_MONETARY="POSIX"
LC_MESSAGES="POSIX"
LC_PAPER="POSIX"
LC_NAME="POSIX"
LC_ADDRESS="POSIX"
LC_TELEPHONE="POSIX"
LC_MEASUREMENT="POSIX"
LC_IDENTIFICATION="POSIX"
LC_ALL=

或者

root@4acd55cd86a7:/# locale -a
C
C.UTF-8
POSIX

顯然是沒有語言包。須要重構建鏡像入手Dockerfile文件以下

FROM ubuntu:trusty
RUN locale-gen en_US.UTF-8  
ENV LANG en_US.UTF-8  
ENV LANGUAGE en_US:en  
ENV LC_ALL en_US.UTF-8
CMD ["/bin/bash"]

這樣就能夠了,可是若是直接在ubuntu 上構建不行

須要以下處理,簡單說就是安裝語言包locales 命令

FROM ubuntu
RUN apt-get update
RUN apt-get install -y locales locales-all
ENV LC_ALL en_US.UTF-8
ENV LANG en_US.UTF-8
ENV LANGUAGE en_US.UTF-8

 大功告成!

相關文章
相關標籤/搜索