让现有vue前端项目快速支持多语言 - 用.net core程序快速替换中文为资源Key,咱不干体力活
前言
这是我第一次发博客,2020年立个flag以后要经常发。
最近应公司上层要求,需要将现有项目尽快支持多语言,而中文内容可以找专业人员翻译。那么咱们说干就干,首先我们项目的前端是用vue写的spa程序且组件方面用的element ui,那么自然而然想到用vue官方推荐的vue i18n,我快速过了下i18n整个Guide官方文档,看来使用很简单,主要步骤就是:
- npm 安装vue i18n插件
- 定义多语言资源字典对象
- 实例化vue i18n实例
- vue实例上挂载vue i18n 实例
这里有一个最简单的实例
相信大家都看就懂,但大家有没想过,我前面说了公司要求是把现有项目尽快支持多语言,那说明我们的项目已经存在大量的代码。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年身体健康,过得顺心!!!
让现有vue前端项目快速支持多语言 - 用.net core程序快速替换中文为资源Key,咱不干体力活的更多相关文章
- 基于vue+springboot+docker网站搭建【五】部署vue前端项目
		部署vue前端项目 一.下载项目到本地 https://github.com/macrozheng/mall-admin-web 二.npm install 三.修改api配置,改为你接下来要部 ... 
- vue前端项目优化策略
		vue前端项目有什么优化策略? .生成打包报告.(可以发现一些问题,并进行解决)2.使用第三方库启用CDN加载3.使用Element-ui的话,按需加载组件4.使用路由懒加载 生成打包报告: .生成打 ... 
- VUE前端项目配置代理解决跨域问题
		VUE前端项目配置代理解决跨域问题 问题如下,经常在本地调试接口出现这种问题 解决方式1:Chrome 的扩展插件 以前使用Chrome 的扩展插件,但是有时候还是会出现莫名其妙的问题. 需要梯子才行 ... 
- 现有 Vue.js 项目快速实现多语言切换的一种思路
		Web 项目多语言(i18n,即国际化)是比较常见的需求,常规的做法大概有以下几种: 每种语言单独开发页面,适用于 CMS 之类的网站 多语言文本和页面结构分离,运行时动态替换.适用于单页应用(SPA ... 
- VUE 前端项目优化方法
		前端项目通过webpack打包会生成app.js和vendor.js,如果第三方组件依赖过多,会造成打包后的vendor.js过大,页面首次加载的时候会出现白屏时间过长,影响用户体验.对此,我们需要通 ... 
- 在Vue前端项目中,附件展示的自定义组件开发
		在Vue前端界面中,自定义组件很重要,也很方便,我们一般是把一些通用的界面模块进行拆分,创建自己的自定义组件,这样操作可以大大降低页面的代码量,以及提高功能模块的开发效率,本篇随笔继续介绍在Vue&a ... 
- 【vue】创建一个vue前端项目,编译,发布
		npm: Nodejs下的包管理器. webpack: 它主要的用途是通过CommonJS的语法把所有浏览器端需要发布的静态资源做相应的准备,比如资源的合并和打包. vue-cli: 用户生成Vue工 ... 
- vue前端项目初始化的步骤
		前端项目初始化的步骤 1. 安装vue脚手架 2.通过vue脚手架创建项目 可以直接 vue create 项目名 也可以 vue ui 3.配置vue路由 4.配置Element-ui 组件 ... 
- 【vue】vue前端项目结构
		[一]项目结构 [二]项目结构释意 目录/文件 说明 build 项目构建(webpack)相关代码 config 配置目录,包括端口号等.我们初学可以使用默认的. node_modules npm ... 
随机推荐
- P1086 最大素数积
			题目描述 我们称一个整数 \(x\) 是"素数积"当且仅当 \(x = a \times b\) 并且 \(a\) 和 \(b\) 都是素数. 现在告诉你一个数 \(N(1 \le ... 
- PHP PDO扩展整理,包括环境配置\基本增删改查\事务\预处理
			相关文章:PHP的mysql扩展整理,操作数据库的实现过程分析 PHPmysqli扩展整理,包括面向过程和面向对象的比较\事务控制\批量执行\预处理 介绍 PDO是一种PHP程序连接数据库的接口 ... 
- P1016 高精度除法
			题目描述 给你两个很大的正整数A和B,你需要计算A除以B的商和余数. 输入格式 输入一行包含两个正整数A和B,以一个空格分隔(A和B的位数都不超过 \(10^5\)) 输出格式 输出一行包含两个整数, ... 
- Linux 内核链表头数据结构
			链表头必须在使用前用 INIT_LIST_HEAD 宏来初始化. 一个"要做的事情"的链表头可能声 明并且初始化用: struct list_head todo_list; INI ... 
- Javascript中数组方法reduce的妙用之处
			Javascript数组方法中,相比map.filter.forEach等常用的迭代方法,reduce常常被我们所忽略,今天一起来探究一下reduce在我们实战开发当中,能有哪些妙用之处,下面从red ... 
- 关于axios的一些封装
			关于Axios的封装 为何需要在封装 应用场景,项目中涉及100个AJAX请求,其中: 1.其中60个需要在请求头header设置token headers: {token: token}用于权限校验 ... 
- phpcms 增加备案号、联系方式等字段
			准备好记事本或者dreamweaver或者其它文本编辑器 打开\phpcms\languages\zh-cn\admin.lang.php PHPCMS的中文语言定义文件. 查找“site_manag ... 
- jsp页面出错 Cannot call sendRedirect() after the response has been committed
			sendRedirect()不能多次调用,检查下代码 
- web快速开发框架 WebBuilder 8.7发布
			一个强大的web开发框架往往与他开发速度有关,他需要帮助程序员尽可能快的完成项目的同时确保它的安全性,WebBuilder是基于Java的web开发框架,其核心开发目标是开发迅速,代码少,学习简单,功 ... 
- Linux基础:CentOS 6重置密码
			1.开机,按"e"键,进入GNU GRUB引导界面,上下键选择中间行 2.按"e"键,进入编辑界面,末行quiet后空格,输入"1"或者&q ... 
