讓現有vue前端項目快速支持多語言 - 用.net core程序快速替換中文爲資源Key,咱不幹體力活

##前言javascript

這是我第一次發博客,2020年立個flag之後要常常發。html

最近應公司上層要求,須要將現有項目儘快支持多語言,而中文內容能夠找專業人員翻譯。那麼我們說幹就幹,首先咱們項目的前端是用vue寫的spa程序且組件方面用的element ui,那麼天然而然想到用vue官方推薦的vue i18n,我快速過了下i18n整個Guide官方文檔,看來使用很簡單,主要步驟就是:前端

這裏有一個最簡單的實例vue

相信你們都看就懂,但你們有沒想過,我前面說了公司要求是把現有項目儘快支持多語言,那說明咱們的項目已經存在大量的代碼。duang,尼瑪,那不是作「定義多語言資源字典對象」是一個體力活? 要知道,咱們這個前端項目至少有成百上千個頁面,若是讓我一個一個的翻譯裏面的中文跟換成vue i18n要求的$t('key'),那估計我跟團隊得累死呀!!!因此,爲了避免幹體力活,就有了這篇文章。java

##先隨便拿一個前端文件看看最終的效果圖:git

自動替換前: github

自動替換後: 正則表達式

感受如何?最終的代碼點這裏npm

#下面咱們來詳細介紹下實現的各個步驟c#

要想替換前端代碼爲vue i18n的語法,就涉及到本身編寫一套程序來實現準確替換,在替換以前,咱們須要考慮:

  • 能夠將<template><script>裏面的中文代碼準確找出來(須要排除註釋等特殊狀況,至少能替換98%以上的代碼,少許代碼能夠本身手動替換)
  • 能夠將中文導出excel文件,好讓專業的人能夠進行翻譯
  • 能夠將翻譯後的excel文件生成咱們代碼要求的「定義多語言資源字典對象」

##一,將全部中文Key找出來

因爲vue i18n的資源key是能夠包含中文英文跟特殊字符的,因此咱們能夠直接將文字直接當成key,這樣代碼中的中文信息就算換成多語言函數後也照樣能很容易讀懂,那麼這裏直接上這塊核心的.net core代碼將全部key找出來(天然想到正則表達式去匹配),並保持到一個.txt文件

/// <summary>
        /// 抽離代碼文件中的中文到文件
        /// </summary>
        /// <param name="filePath">代碼文件路徑</param>
        /// <param name="keyFilePath">須要保持的包含全部中文字典的文本文件路徑</param>
        static void CreateKeyTxt(string filePath, string keyFilePath)
        {
            var regex = new Regex(@"((?<key>\w+) *= *['""](?<str>([^'""]*[\u4e00-\u9fa5]+[^'""]*))['""])|((?<start>[`""'>}]*)(?<str>[^\s`""'>}]*[\u4e00-\u9fa5]+[^\s`""'<{]*)(?<end>[`""'<{]*))");
            string fileContent = File.ReadAllText(filePath);

            var chineseMatchs = regex.Matches(fileContent);

            // 有中文須要處理
            if (chineseMatchs.Count > 0)
            {
                Dictionary<string, string> lines = new Dictionary<string, string>();
                foreach (Match htmlMatch in chineseMatchs)
                {
                    var str = htmlMatch.Groups["str"].Value.TrimEnd(':');

                    if (str.Contains("//") || str.Contains("/*") || str.Contains("*/") || str.Contains("<!--") || str.Contains("微軟雅黑"))
                    {
                        continue;
                    }

                    lines[str] = "";
                }

                using (StreamWriter fs = new StreamWriter(keyFilePath, true, Encoding.UTF8))
                {
                    foreach (var line in lines)
                    {
                        fs.WriteLine(line.Key);
                    }
                }
            }
        }

而後,你就能夠拿這這個包含全部須要翻譯的內容,高高興興拿給翻譯人員讓他們辛苦勞做了!

##二,根據包含全部中文Key跟翻譯內容的excel生成vue i18n要求的「定義多語言資源字典對象」文件

這個步驟其實就是生成兩個js文件,一個是zh-cn.js中文資源文件,一個是好比en.js的英文資源文件,而文件的內容就是簡單的K-V文件,好比:

export default {
    "取 消": "CANCEL",
    "確 定": "OK",
    "取消": "CANCEL",
    "肯定": "OK",
    "確認": "OK",
    "@表示RR,- 表示AA": "@ is RR, - is AA",
}

主要代碼是:

static void SaveI18N()
        {
            // 須要生成或者更新的i18n js資源文件夾地址
            var i18nResourceOutputFolderPath = Configuration["i18nResourceOutputFolderPath"];

            // 須要生成或者更新的i18n js資源文件名
            var i18nResourceFileName = Configuration["i18nResourceFileName"];

            if (string.IsNullOrEmpty(i18nResourceOutputFolderPath))
            {
                throw new ApplicationException("失敗:請先配置須要生成或者更新的i18n js資源文件夾地址");
            }
            if (string.IsNullOrEmpty(i18nResourceFileName))
            {
                throw new ApplicationException("失敗:請先配置須要生成或者更新的i18n js資源文件名");
            }

            // 獲取前端資源字典文件數據
            Dictionary<string, string> chineseDic = new Dictionary<string, string>();
            Dictionary<string, string> tDic = new Dictionary<string, string>();
            for (int i = 1; i < ExcelResourceFileData.Rows.Count; i++)
            {
                var shortName = (ExcelResourceFileData.Rows[i][0].ToString()).Trim();
                var chineseContent = (ExcelResourceFileData.Rows[i][1].ToString()).Trim();
                var tContent = (ExcelResourceFileData.Rows[i][2].ToString()).Trim();

                if (string.IsNullOrEmpty(shortName))
                {
                    throw new ApplicationException($"失敗:在第{i + 1}行存在空白的簡稱");
                }
                if (string.IsNullOrEmpty(chineseContent))
                {
                    throw new ApplicationException($"失敗:在第{i + 1}行存在空白的中文");
                }

                var key = $"\"{shortName}\"";
                chineseDic[key] = $"\"{chineseContent}\"";
                tDic[key] = $"\"{tContent}\"";
            }

            SaveI18NFile(i18nResourceOutputFolderPath, "zh-cn.js", chineseDic);
            SaveI18NFile(i18nResourceOutputFolderPath, i18nResourceFileName, tDic);
        }

        private static void SaveI18NFile(string i18nResourceOutputFolderPath, string fileName, Dictionary<string, string> resourceDic)
        {
            resourceDic = GetNewestResourceDic(i18nResourceOutputFolderPath, fileName, resourceDic);

            // 構建資源文件內容
            StringBuilder newFileContent = new StringBuilder();
            newFileContent.AppendLine("export default {");
            foreach (var chineseKeyValue in resourceDic)
            {
                newFileContent.AppendLine($"    {chineseKeyValue.Key}: {chineseKeyValue.Value},");
            }
            newFileContent.AppendLine("}");

            File.WriteAllText(Path.Combine(i18nResourceOutputFolderPath, fileName), newFileContent.ToString(), Encoding.UTF8);
        }

##三,最後固然就是重頭戲,替換中文前端代碼

對於 <template> 裏面的代碼,咱們須要給property還有innerText分別單獨處理,好比

<el-button @click="onCancel" title="取消此上傳功能">取 消</el-button>

其中的title="取消此上傳功能"這個property是須要替換成:title="$t('取消此上傳功能')" 而innerText 取 消是須要替換成{{$t(取 消)}}的,最終替換爲

<el-button @click="onCancel" :title="$t('取消此上傳功能')">{{$t(`取 消`)}}</el-button>

其中對 <template> 的替換核心代碼爲:

/// <summary>
        /// 替換代碼文件template中的中文爲資源key
        /// </summary>
        /// <param name="input">代碼內容</param>
        /// <param name="resourceTypeStr">資源類型</param>
        /// <param name="pattern">正則表達式</param>
        /// <param name="isProperty">是不是屬性</param>
        /// <returns></returns>
        static string ReplaceChineseToI18NKeyForTemplate(string input, string resourceTypeStr, string pattern, bool isProperty = false)
        {
            var htmlMatchs = Regex.Matches(input, pattern, RegexOptions.IgnoreCase);
            int changedLength = 0;
            foreach (Match htmlMatch in htmlMatchs)
            {
                var newHtmlMatchIndex = htmlMatch.Index + changedLength;
                var chineseWordsMatch = Regex.Match(htmlMatch.Value, wordPattern, RegexOptions.IgnoreCase);
                var key = GetResourceKey(chineseWordsMatch.Value);

                // key不會空才須要替換
                if (!string.IsNullOrEmpty(key))
                {
                    string newHtml;

                    if (isProperty)
                    {
                        newHtml = ":" + Regex.Replace(htmlMatch.Value, wordPattern, "$t('" + key + "')");
                    }
                    else
                    {
                        newHtml = Regex.Replace(htmlMatch.Value, wordPattern, "{{$t('" + key + "')}}");
                    }

                    input = input.Substring(0, newHtmlMatchIndex) + newHtml + input.Substring(newHtmlMatchIndex + htmlMatch.Length);

                    changedLength += newHtml.Length - htmlMatch.Length;
                }
            }

            return input;
        }

<script> 的替換核心代碼跟<template> 相似,最主要的區別是js代碼裏面使用的是this.$t('key')。

到這裏咱們就將整個前端系統的中文文本代碼所有修改爲經過資源key動態顯示對應的語言文本了。

##本代碼的一些不足

  • 上面的正則只能提取跟替換大部分中文狀況,少數狀況還須要手動修改;但即便這樣,也比一個一個替換節省了大量的人力物力。
  • <script> 替換爲this.$t('key')中的this有不對的狀況,改進方案是在代碼前面import i18n對象,而後將this換成i18n對象,因爲時間有限,本文的代碼並沒涉及這塊,但實現起來比較容易。

##一些思考 各位,相信大家跟我同樣,認爲本文並無多少技術亮點,說白了,無非就是運用正則表達式替換一些代碼而已。但我想說的,若是咱們一開始就一個頁面一個頁面弄,那得弄多久才能完成老闆給咱們的任務,因此每每解決問題,須要咱們多靜下心來多思考一下,而後運用一些簡單的技術,便可快速實現咱們想要的東西。特別是如今是一個快速發展的時代,更須要咱們高效的解決問題,這樣才能體現咱們的價值。

最終的代碼點這裏

最後但願你們多多評論,2020年身體健康,過得順心!!!

原文出處:https://www.cnblogs.com/sutong/p/12221577.html

相關文章
相關標籤/搜索