• 让现有vue前端项目快速支持多语言


    前言

    这是我第一次发博客,2020年立个flag以后要经常发。

    最近应公司上层要求,需要将现有项目尽快支持多语言,而中文内容可以找专业人员翻译。那么咱们说干就干,首先我们项目的前端是用vue写的spa程序且组件方面用的element ui,那么自然而然想到用vue官方推荐的vue i18n,我快速过了下i18n整个Guide官方文档,看来使用很简单,主要步骤就是:

    这里有一个最简单的实例

    相信大家都看就懂,但大家有没想过,我前面说了公司要求是把现有项目尽快支持多语言,那说明我们的项目已经存在大量的代码。duang,尼玛,那不是做“定义多语言资源字典对象”是一个体力活? 要知道,我们这个前端项目至少有成百上千个页面,如果让我一个一个的翻译里面的中文跟换成vue i18n要求的$t('key'),那估计我跟团队得累死呀!!!所以,为了不干体力活,就有了这篇文章。

    先随便拿一个前端文件看看最终的效果图:

    自动替换前:

    自动替换后:

    感觉如何?最终的代码点这里

    下面我们来详细介绍下实现的各个步骤

    要想替换前端代码为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年身体健康,过得顺心!!!

    联系作者请添加微信号:sutong324,并注明:来自cnblogs
  • 相关阅读:
    java根据图片路径下载到服务器方案 (转)
    什么是JSP (转)
    获取给定月中哪些天有聊天记录
    患者咨询服务区数据获取
    获取 不在当前设置录入状态,但是曾经设定过的测量指标 的最后测量日期
    MySQL 常用函数之——substr()
    MySql查询时间段的方法(转)
    MySQL 百万级分页优化(Mysql千万级快速分页)(转)
    mysql的sql分页函数limit使用 (转)
    MySql实现分页查询的SQL,mysql实现分页查询的sql语句 (转)
  • 原文地址:https://www.cnblogs.com/sutong/p/12221577.html
Copyright © 2020-2023  润新知