场景
今天接到客户的一种需求,将已有网站实现国际化方案,要的比较急,该项目已经使用了类似i18n的国际化方案,当我信心满满的以为问题不大的时候,发现需要翻译的字段多达五千多。。。这要是一个个翻译下来。。。更要命的是,客户还要求菜单类甚至标题也要国际化,这代码里明显没有此功能啊,那下来不还得加各个配置项的多语言输入啊。。。啊这
技术选型
然后,我就思考找其他解决方案,类似整页翻译的插件,结果发现这个东西也就类似谷歌api这样的了,但是谷歌。。。不翻墙的话很难使用,在我的不懈努力(百度)下,挖掘了很多老代码,但是多多少少都有些问题,这个时候我想到,谷歌浏览器插件是如何实现整站翻译的?于是我换了个方向思考,能不能找到谷歌翻译插件的源码了解原理再进行改造,功夫不负有心人,还真的让我找到了能用的
EdgeTranslate/EdgeTranslate: A translation extension. (github.com)
这个是edge浏览器的翻译插件,接下来让我们看看如何改造
代码改造
因为翻译插件包含的不只是整页翻译的功能,还有其他功能,所以我们需要把我们需要的代码抽离出来,接下来是探索过程
- 首先我们看插件执行翻译的过程
安装翻译插件后,在网站右键会呼出翻译此页菜单,在源码中搜索翻译此页,得到如下结果
- 找到我们需要的
谷歌网页翻译,此处推测GooglePageTranslate为执行谷歌网页翻译的方法
源码搜索GooglePageTranslate找到执行方法
3. 接着找
executeGoogleScript方法
4. 发现最终引入了
init.js这个文件,查看文件源码
5. 这个插件是真不戳,经过一番仔细的验证之后,发现要使用的代码都在
google这个文件夹下
- 不过还不能直接用,需要把
init.js的代码进行改造,毕竟此项目的环境是浏览器插件,我们需要改成浏览器引入,思路如下,把google文件夹放置网站根目录,移除对chrome.runtime.getURL("")的依赖,替换为./,网站默认语言为中文,定义let user_lang = 'zh-CN',移除对请求的依赖,当然这里也可以自行跟后台配合使用接口返回默认语音, - 经过改造后,代码如下
let s = document.getElementById("google-translate-injection");
if (s !== null) {
s.remove();
}
s = document.createElement("script");
let user_lang = "zh-CN";
s.id = "google-translate-injection";
s.src = `./google/injection.js`;
s.setAttribute("user-lang", user_lang);
s.setAttribute("edge-translate-url", "./");
document.getElementsByTagName("head")[0].appendChild(s)
- 简单跑个DEMO
- 到这里应该结束了。。。。才怪,这么明显的东西放在页面顶部,客户不说还好,万一不好看想改样式怎么办?
- 如果要修改样式,正常情况下只需要一步,就是找到这个元素,给他修改css就行,实在不行就加上
!important,但是发现这个行不通,因为这个翻译插件是通过iframe引入的。。。所以就稍微复杂了起来 - 本来一步就行的操作需要分为两步,一是隐藏引入的iframe,把页面打乱的样式恢复,二是由于把人家的翻译隐藏了,就需要找到原有的翻译逻辑,额外自己实现
- 隐藏样式
.goog-te-banner-frame{
display:none;
}
body{
top:0px!important;
min-height: 0px!important;
}
13. 翻译逻辑,经过一番掉头发的操作后,终于发现了端倪,翻译是通过判断当前的cookie值来进行默认语言翻译的,可以通过修改cookie值,然后刷新网站来进行语言切换翻译
14. 整理各个语种对应的字段,用几个拿几个
{"sq":"阿尔巴尼亚语","ar":"阿拉伯语","am":"阿姆哈拉语","az":"阿塞拜疆语","ga":"爱尔兰语","et":"爱沙尼亚语","or":"奥里亚语(奥里亚文)","eu":"巴斯克语","be":"白俄罗斯语","bg":"保加利亚语","is":"冰岛语","pl":"波兰语","bs":"波斯尼亚语","fa":"波斯语","af":"布尔语(南非荷兰语)","tt":"鞑靼语","da":"丹麦语","de":"德语","ru":"俄语","fr":"法语","tl":"菲律宾语","fi":"芬兰语","fy":"弗里西语","km":"高棉语","ka":"格鲁吉亚语","gu":"古吉拉特语","kk":"哈萨克语","ht":"海地克里奥尔语","ko":"韩语","ha":"豪萨语","nl":"荷兰语","ky":"吉尔吉斯语","gl":"加利西亚语","ca":"加泰罗尼亚语","cs":"捷克语","kn":"卡纳达语","co":"科西嘉语","hr":"克罗地亚语","ku":"库尔德语","la":"拉丁语","lv":"拉脱维亚语","lo":"老挝语","lt":"立陶宛语","lb":"卢森堡语","rw":"卢旺达语","ro":"罗马尼亚语","mg":"马尔加什语","mt":"马耳他语","mr":"马拉地语","ml":"马拉雅拉姆语","ms":"马来语","mk":"马其顿语","mi":"毛利语","mn":"蒙古语","bn":"孟加拉语","my":"缅甸语","hmn":"苗语","xh":"南非科萨语","zu":"南非祖鲁语","ne":"尼泊尔语","no":"挪威语","pa":"旁遮普语","pt":"葡萄牙语","ps":"普什图语","ny":"齐切瓦语","ja":"日语","sv":"瑞典语","sm":"萨摩亚语","sr":"塞尔维亚语","st":"塞索托语","si":"僧伽罗语","eo":"世界语","sk":"斯洛伐克语","sl":"斯洛文尼亚语","sw":"斯瓦希里语","gd":"苏格兰盖尔语","ceb":"宿务语","so":"索马里语","tg":"塔吉克语","te":"泰卢固语","ta":"泰米尔语","th":"泰语","tr":"土耳其语","tk":"土库曼语","cy":"威尔士语","ug":"维吾尔语","ur":"乌尔都语","uk":"乌克兰语","uz":"乌兹别克语","es":"西班牙语","iw":"希伯来语","el":"希腊语","haw":"夏威夷语","sd":"信德语","hu":"匈牙利语","sn":"修纳语","hy":"亚美尼亚语","ig":"伊博语","it":"意大利语","yi":"意第绪语","hi":"印地语","su":"印尼巽他语","id":"印尼语","jw":"印尼爪哇语","en":"英语","yo":"约鲁巴语","vi":"越南语","zh-CN":"中文"}
15. 最后是代码地址,本示例仅供参考,如果大家有更好的方案,欢迎留言
FE-YJP/google_translate (github.com)
我正在参与掘金技术社区创作者签约计划招募活动,点击链接报名投稿。