We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
在上次的文章中,主要讲了对旧项目多语言改造整体框架逻辑,包括代码分析,词条提取,excel生成以及语言包的生成。
本文主要讲述项目改造中模板遇到的解析问题,以及工具升级改造做个总结。
在跑项目的时候遇到最多的问题是,你会见到各种千奇百怪的写法,之前写的那几种正则的处理方式无法很好的囊括到方方面面。而且工具类有一个很大的问题是,你一改一个地方,很难判断是否对原有的代码生成有影响。
举个例子,比原本在表达式处理中,匹配的正则是 /^\s*((**\{\{**.*?**\}\}**)|(.+[|].+))\s*$/gm但是后面你发现说有一些情况和你预期的不一样,比如说过滤器其实不应该是属于这种情况,那么你会改成/^\s*((**\{\{**.*[\u4e00-\u9fa5]+.***\}\}**))\s*$/gm 但是这个时候会不会对之前的代码有影响呢?
/^\s*((**\{\{**.*?**\}\}**)|(.+[|].+))\s*$/gm
/^\s*((**\{\{**.*[\u4e00-\u9fa5]+.***\}\}**))\s*$/gm
不确定,也无法确定,毕竟一个项目几百个html文件,你不确定别人会怎么写。
所以更好的方法是写测试用例,所以在这次改造之前,我先把目前几种类型枚举出来,再加上一些跑项目中遇到的奇奇怪怪的模板语法逐个写一个单测。
配合vscode的 Jest、Jest Runner 使用起来十分方便快捷,你改完代码之后,测试脚本会自动跑,只要全绿就没事。
如果遇到一些红了,还可以直接点击上方的debug进行快速断点调试,不要太舒服。
也是这次的项目让我深刻意识到单测的重要性,因为这种项目不同于普通的业务项目,属于偏工具类型,是典型的FP,输入什么,输出什么非常明确,后面在开发一些ast版本的时候,也是测试先行,写完测试文件之后再根据测试用例来写代码。跑项目的时候遇到一些奇怪的语法,也会直接在测试文件里面加上这一项。
这里引用XML之父的一句话,只有经历过一些项目开发才会感同身受
不对代码做测试就像”上完厕所不洗手“
在上一篇中也提到了Angular解析的黑盒,你不知道一个属性传值中,组件内部是用字符串类型解析还是表达式类型解析。
虽然这在Angular2.0以上都用了一个方括号来区分是否是表达式传值<div [expression]="expression" string="string"。但是我们项目Angular1.x还是没有办法很好的解决这个问题。
<div [expression]="expression" string="string"
于是我在之前的判断再优化一下,如果判断了是expression的类型,再用编译器去解析做一个double check,负责返回一个stringCode,这样后面很多处理都只需要考虑一种情况去处理。
function translateExpression2String(params) { const isExpression = Helper.getIsExpressionType(params) if (!isExpression) return params.originString const fakeCode = `<div [e]='${originString}'><div>` const expression = ngCompiler.parseTemplate(fakeCode) const { ast } = expresion.nodes[0].inputs[0].value // 生成代码 const stringCode = generator(ast) return stringCode || originString; }
这里generator是自己写的一个根据ast生成代码,有点类似babel-generator,做的事情就是根据传入的ast-node和是否处于表达式内部,生成对应的angular模板语法。
就像开头说的,项目中千奇百怪的写法都有,很多已经超过普通正则可以处理的范畴了,之前采用正则而不是ast的方法来处理一方面是用了post-html去解析,解析出来只是一个普通的字符串;另一方面是因为目前社区没有找到一款基于angular-ast生成angular目标代码的工具,所以基于当时的场景用正则是最方便快捷有效的方法。
post-html
这一次的升级改造中,对一些情况改用ast生成目标代码,能做到更只能准确的处理词条已经替换后的文案。
大概的做法思路是这样的,首先还是用 post-html 去解析html,对于解析后的一段字符串,再调用 @angular/compiler 做ast解析。最后根据这份ast去做解析、提取词条、生成替换后的ast,最后用 generator 去生成对应的代码。
@angular/compiler
generator
目前关于ast的部分,写了几个比较常用的类:
其中basicText类主要是一些通用处理的基类,这里拿conditionalText来举例说明。
class TextWithConditional extends BasicText { static stringType: number static expressionType: number // 符合当前类的文本,单测的时候可以直接遍历这个属性 static example: string[] // 提取的文案,单测时遍历 example提取的文案与zhExample比对 static zhExample: string[] // 不符合当前类的文本 static wrongExample: string[] // 验证当前是文本否符合该类 static verify(originString: string, params: any): boolean { // 简单的文本判断是否有汉字等 // 生成expression的ast // 判断ast 是否符合,比如我这里是只能有三元 // 而且只能有一个包含文案的三元,不然太多三元文案的话组合得不偿失 } // 生成zhList和newCode private generateZhListWithNewCode(force: boolean) { if (this.zhList.length && this.newCode && !force) return // newCode 主要是组合了 条件判断前后的文案 } private zhList: string[] private newCode: string // 返回提取出来的中文 extract(): string[] { ... this.generateZhListWithNewCode() return this.zhList } // 返回替换后的字符串 replace(): string { ... this.generateZhListWithNewCode() ... return generator(this.newCode) } }
类中verify中如果有多个三元且都有文案的话,是不会命中处理的,不然条件一多,后面的代码变得很不可维护,比如
<!-- 处理前 --> <div> {{ vm.me? '我': '你' }}吃 {{ vm.isPoor? '饭': '菜'}} </div> <!-- 处理后 --> <div> {{ (vm.me && vm.isPoor)? '我吃饭': (vm.me && !vm.isPoor)? '我吃菜': (!vm.me && vm.isPoor)? '你吃饭': '你吃菜' }} </div>
对于ConditionalText,我对他的专项(只针对这个类)的单测大概有这几个,最主要是将原来的文本中 textA {{conditional}} textB 这种类型进行拆分处理,使之更加语义化,不会让翻译的人员一脸懵逼,也会增加翻译人员的意境理解。
textA {{conditional}} textB
目前的替换处理逻辑改为,如果文本符合ast中某个类的规则,则优先使用ast处理,会更加准确,不符合的沿用就逻辑处理,这样也可以在不影响进度及使用的过程中慢慢对各个类做一个升级改造。
多语言改造项目中的模板解析部分应该算是暂告一段落了,后面要做优化改造可能会是去改造更新和删除机制。
更新比如:提取文本的时候是"我吃饭",后面在供应商翻译的过程中产品需求将文案改为"吃饭",那要怎么去处理这种情况?
删除则是:提取文本的时候还有"我吃饭",但是后面迭代的时候,已经把这个文案删除了,这种情况对功能没有影响,但是会造成代码冗余的情况。
最近一周对多语言构建工具项目的升级改造,最大的收获倒不是那些问题的解决方案和边界条件探索,而是开始喜欢上写单测,开始诧异之前写工具居然不配单元测试。
The text was updated successfully, but these errors were encountered:
「收藏即学会」
Sorry, something went wrong.
No branches or pull requests
在上次的文章中,主要讲了对旧项目多语言改造整体框架逻辑,包括代码分析,词条提取,excel生成以及语言包的生成。
本文主要讲述项目改造中模板遇到的解析问题,以及工具升级改造做个总结。
单元测试
在跑项目的时候遇到最多的问题是,你会见到各种千奇百怪的写法,之前写的那几种正则的处理方式无法很好的囊括到方方面面。而且工具类有一个很大的问题是,你一改一个地方,很难判断是否对原有的代码生成有影响。
举个例子,比原本在表达式处理中,匹配的正则是
/^\s*((**\{\{**.*?**\}\}**)|(.+[|].+))\s*$/gm
但是后面你发现说有一些情况和你预期的不一样,比如说过滤器其实不应该是属于这种情况,那么你会改成/^\s*((**\{\{**.*[\u4e00-\u9fa5]+.***\}\}**))\s*$/gm
但是这个时候会不会对之前的代码有影响呢?不确定,也无法确定,毕竟一个项目几百个html文件,你不确定别人会怎么写。
所以更好的方法是写测试用例,所以在这次改造之前,我先把目前几种类型枚举出来,再加上一些跑项目中遇到的奇奇怪怪的模板语法逐个写一个单测。
配合vscode的 Jest、Jest Runner 使用起来十分方便快捷,你改完代码之后,测试脚本会自动跑,只要全绿就没事。
如果遇到一些红了,还可以直接点击上方的debug进行快速断点调试,不要太舒服。
也是这次的项目让我深刻意识到单测的重要性,因为这种项目不同于普通的业务项目,属于偏工具类型,是典型的FP,输入什么,输出什么非常明确,后面在开发一些ast版本的时候,也是测试先行,写完测试文件之后再根据测试用例来写代码。跑项目的时候遇到一些奇怪的语法,也会直接在测试文件里面加上这一项。
这里引用XML之父的一句话,只有经历过一些项目开发才会感同身受
解析模式
在上一篇中也提到了Angular解析的黑盒,你不知道一个属性传值中,组件内部是用字符串类型解析还是表达式类型解析。
虽然这在Angular2.0以上都用了一个方括号来区分是否是表达式传值
<div [expression]="expression" string="string"
。但是我们项目Angular1.x还是没有办法很好的解决这个问题。于是我在之前的判断再优化一下,如果判断了是expression的类型,再用编译器去解析做一个double check,负责返回一个stringCode,这样后面很多处理都只需要考虑一种情况去处理。
这里generator是自己写的一个根据ast生成代码,有点类似babel-generator,做的事情就是根据传入的ast-node和是否处于表达式内部,生成对应的angular模板语法。
AST应用
就像开头说的,项目中千奇百怪的写法都有,很多已经超过普通正则可以处理的范畴了,之前采用正则而不是ast的方法来处理一方面是用了
post-html
去解析,解析出来只是一个普通的字符串;另一方面是因为目前社区没有找到一款基于angular-ast生成angular目标代码的工具,所以基于当时的场景用正则是最方便快捷有效的方法。这一次的升级改造中,对一些情况改用ast生成目标代码,能做到更只能准确的处理词条已经替换后的文案。
大概的做法思路是这样的,首先还是用 post-html 去解析html,对于解析后的一段字符串,再调用
@angular/compiler
做ast解析。最后根据这份ast去做解析、提取词条、生成替换后的ast,最后用generator
去生成对应的代码。目前关于ast的部分,写了几个比较常用的类:
其中basicText类主要是一些通用处理的基类,这里拿conditionalText来举例说明。
类中verify中如果有多个三元且都有文案的话,是不会命中处理的,不然条件一多,后面的代码变得很不可维护,比如
对于ConditionalText,我对他的专项(只针对这个类)的单测大概有这几个,最主要是将原来的文本中
textA {{conditional}} textB
这种类型进行拆分处理,使之更加语义化,不会让翻译的人员一脸懵逼,也会增加翻译人员的意境理解。目前的替换处理逻辑改为,如果文本符合ast中某个类的规则,则优先使用ast处理,会更加准确,不符合的沿用就逻辑处理,这样也可以在不影响进度及使用的过程中慢慢对各个类做一个升级改造。
多语言改造项目中的模板解析部分应该算是暂告一段落了,后面要做优化改造可能会是去改造更新和删除机制。
更新比如:提取文本的时候是"我吃饭",后面在供应商翻译的过程中产品需求将文案改为"吃饭",那要怎么去处理这种情况?
删除则是:提取文本的时候还有"我吃饭",但是后面迭代的时候,已经把这个文案删除了,这种情况对功能没有影响,但是会造成代码冗余的情况。
最近一周对多语言构建工具项目的升级改造,最大的收获倒不是那些问题的解决方案和边界条件探索,而是开始喜欢上写单测,开始诧异之前写工具居然不配单元测试。
The text was updated successfully, but these errors were encountered: