关于i18n:react项目国际化实现自动装配方案

该计划提供一个外挂式的前端我的项目国际化实现计划,能够反对因为某些起因在一开始没有反对国际化,后续在简直不须要革新原有业务代码的状况下反对国际化。利用构建工具,做到业务开发无感的国际化计划。在国际化开发过程的流程个别为:前端开发工程师在碰到中文时,须要先设计一个编码,通常为了防止编码反复,还须要合乎肯定规定且随着业务迭代越来越简短的编码;而后导入国际化多语言工具函数,调用国际化多语言函数;而后翻译保护国际化配置数据;如果国际化数据是放在数据库中,反对线上动静配置,还须要数据给后端,对立保护在零碎。整个过程简短且须要不同人员协同,极易呈现问题。 如应用react-intl-universal反对国际化: import intl from 'react-intl-universal';// 初始化代码在整个零碎的入口文件时。intl.get('SIMPLE').d('简略');假如开发一个前端转译工具,在碰到代码中的中文时,主动导入国际化的工具函数,主动依照肯定的规定生成编码,将原来的中文代码替换为国际化函数的调用,而后在整个我的项目编译后,收集所有的国际化语言数据,能够间接生成国际化语言的配置文件也好,或者生成肯定的结构化数据用于插入数据库。 依照这个思路,就能够实现一个为我的项目主动拆卸国际化的计划。在该计划中,前端开发工程师开发时无需关注国际化,获取跟不须要国际化反对的我的项目一样的开发体验,能够将精力更多的放在业务开发上。同样该计划为一个根底撑持,挂载式的模式,可能疾速反对一个开始不反对国际化,起初因为倒退,须要面向国内的我的项目。 同样,这个计划着重点是如何主动生成国际化多语言函数的调用代码,对应用某个国际化框架是没有限度的。能够依据理论需要,抉择任何国际化框架,而后对它的应用进行代码转换。 该计划只针对简略的国际化需要,对于一些简单的需要,如金额,日期等,还是须要手动应用一些国际化框架的api。但一个我的项目中,最多的应该还是对于一些简略的展现文本进行国际化反对。 从计划的设计来看,次要是分为两局部: 剖析代码:当碰到中文时,转译为国际化函数调用语句。收集信息:将剖析代码过程中的转换语句的信息收集起来,用于生成配置数据。两个局部别离用两个工具去解决。 代码剖析工具剖析代码能够实现一个babel插件,在转译js代码时进行中文国际化解决。 中文文本,次要是字符串或在模版字符串中,所以只须要对这两种语句进行解析转化即可,也就在babel插件须要解决StringLiteral和TemplateLiteral语句即可。 那么插件的次要构造为: module.exports = (babel) => { visitor: { StringLiteral(path, state) { }, TemplateLiteral: { enter(_path, state) { }, }, },};TemplateLiteral解决起来比较复杂,所以以StringLiteral为例阐明要害逻辑。在StringLiteral语句中剖析字符串是否蕴含中文,用正则判断: StringLiteral(path, state) { const { node } = path; const text = node.value; if (str.search(/[^\x00-\xff]/) === -1) { return; }},如果不蕴含中文,则间接返回不解决。如果蕴含中文,则转换为国际化导入函数(以react-intl-universal库的应用形式): const intlMember = t.memberExpression( t.identifier('intl'), t.identifier('get'), false, false,);// 编码生成,这里间接用中文作为编码。如果怕乱码等问题,// 能够采纳md5码或者或者依据理论规定和文件门路生成编码const codeText = text;const codeTextNode = t.stringLiteral(codeText);// 解决codeTextNode.extra = { rawValue: codeText, raw: `'${codeText.split("'").join('\\\'').split('\n').join('\\\n')}'`,};const intlCall = t.callExpression(intlMember, [codeTextNode]);const memberExpression = t.memberExpression(intlCall, t.identifier('d'), false, false);let fnNode = t.callExpression(memberExpression, [node]);const parentNode = _.get(path, 'parentPath.node');if (t.isJSXAttribute(parentNode)) { fnNode = t.jsxExpressionContainer(fnNode);}path.replaceWith(fnNode);这样对于文本 ...

February 15, 2022 · 2 min · jiezi

国际化i18n-各国语言缩写

国际化开发的各国语言标识 **国家地区** **语言标识**简体中文(中国) zh_CN繁体中文(台湾地区) zh_TW繁体中文(香港) zh_HK英语(香港) en_HK英语(美国) en_US英语(英国) en_GB英语(全球) en_WW英语(加拿大) en_CA英语(澳大利亚) en_AU英语(爱尔兰) en_IE英语(芬兰) en_FI芬兰语(芬兰) fi_FI英语(丹麦) en_DK丹麦语(丹麦) da_DK英语(以色列) en_IL希伯来语(以色列) he_IL英语(南非) en_ZA英语(印度) en_IN英语(挪威) en_NO英语(新加坡) en_SG英语(新西兰) en_NZ英语(印度尼西亚) en_ID英语(菲律宾) en_PH英语(泰国) en_TH英语(马来西亚) en_MY英语(阿拉伯) en_XA韩文(韩国) ko_KR日语(日本) ja_JP荷兰语(荷兰) nl_NL荷兰语(比利时) nl_BE葡萄牙语(葡萄牙) pt_PT葡萄牙语(巴西) pt_BR法语(法国) fr_FR法语(卢森堡) fr_LU法语(瑞士) fr_CH法语(比利时) fr_BE法语(加拿大) fr_CA西班牙语(拉丁美洲) es_LA西班牙语(西班牙) es_ES西班牙语(阿根廷) es_AR西班牙语(美国) es_US西班牙语(墨西哥) es_MX西班牙语(哥伦比亚) es_CO西班牙语(波多黎各) es_PR德语(德国) de_DE德语(奥地利) de_AT德语(瑞士) de_CH俄语(俄罗斯) ru_RU意大利语(意大利) it_IT希腊语(希腊) el_GR挪威语(挪威) no_NO匈牙利语(匈牙利) hu_HU土耳其语(土耳其) tr_TR捷克语(捷克共和国) cs_CZ斯洛文尼亚语 sl_SL波兰语(波兰) pl_PL瑞典语(瑞典) sv_SE西班牙语 (智利) es_CL

May 24, 2019 · 1 min · jiezi

踩坑vue国际化(V18n)+ jquery国际化(jquert.i18n.properties.js)

目前公司在搞国际化,虽然刚开始接触,但还是遇到了一些问题,如对你有帮助,烦请点个赞,谢谢。先分享一下vue的国际化,目前vue的国际化采用的是vue-i18n。首先新建一个存放语言的文件目录,把提取后的中文、英文放在对应的文件中如下图:通过Vue.use调用内部install方法,最后别忘了在main.js中引入,绑定在vue实例上。在组件的html中语法:在js中语法:在js中调用 this.$i18n.locale = language(例:en_US,跟语言文件export出的对象名称保持一致)实现修改语言。注意这里:1、养成良好的变成喜欢,在写逻辑判断的时候,不要根据中文去判断,不然做国际化要改起来很麻烦。比如使用if (xxx === ‘中文’)、xxx.indexof(‘中文’)等;2、在使用V18n的时候我发现,在页面created之后mounted之前V18n才执行的,就意味着有些人在data()里面用中文初始化了一些属性,但是此时V18n还没有执行,于是一些属性被赋值成了$t(‘xxxxx’),即键值。如图,我在data中初始化了title属性,然后在created时候打印该属性,发现控制台报了2个警告,然后该属性被赋值成了键值。解决方案就是:在data中初始化时不指定默认值,在mounted的时候进行赋值就ok了之后就可以手动调用this.$i18n.locale = en_US方法实现中英文切换了,也可以根据cookie去赋值.分享一个kiwi插件,kiwi是一款提取替换中文的插件,喜欢的也可以试试,十分好用,大家可以看一下链接中的文档。最后简单说一下jq的国际化吧,引入jquery.i18n.properties.js文件,配置项如下: function loadI18nProperties(lang) { $.i18n.properties({ name: ‘strings’, // 对应国际化文件名称 path: ‘/static/js/i18n/’, // 对应国际化文件目录 mode : ‘map’, //用Map的方式使用资源文件中的值 language: lang, // 调用国际化语言 callback: function() { // 回调函数 } }); $(document).ready(function() { loadI18nProperties(‘zh_CN’); });name属性指的是国际化的文件名,jq的存放语言的文件是.properties为后缀的,以上面的例子,语言文件名为strings_en_US、strings_zh_CN。如果path写的不对的话,会报一个跨域的错误,提示让你去修改服务器配置文件去支持.properties文件,这里注意一下就好了。其他的在html中使用自定义属性方式赋值,js中就是简单的变量的方式。修改语言,就是将loadI18nProperties(lang)传递参数就去就可以了。// html<h1 data-i18n=“UserName”></h1>// js中var Title = $.i18n.prop(‘js.UserName’);

March 8, 2019 · 1 min · jiezi

聊聊前端国际化文案该如何处理

背景最近接到一个海外项目业务需求,项目最终会被来自不同国家的客户所使用,期望能让客户有一个良好的用户体验,因此前端需要适配国际化。面临的挑战乍一听,这个海外项目需求并没有什么特别的地方,似乎就多了一个国际化适配。但细细一想,事情可没这么简单,前端开发面临了很多新的问题。下面梳理一下国际化开发中通常会面临的挑战:页面文案全部可配置需要配置的文案大致有四种:label、placeholder、字段校验提示信息、超链接。页面文案样式处理文案样式需要特别注意,不同语言的文字,可能会有不同的表现。例如下面两张图所示:英语(页面样式正常)俄语(页面样式异常)日期、数字格式处理页面上展示日期或数量的地方,也是需要做国际化适配。LTR/RTL很多中东国家的语言习惯都是 RTL,可以尝试使用 direction 和 transform 来解决。图片(banner)国际化如果你想把国际化做的足够精细,那么图片国际化也是需要考虑的。第三方 UI 组件如果使用了第三方 UI 组件,如:elementUI、ant design UI 等,这些 UI 框架通常都宣称支持国际化,但支持的国际化语言数量有限,并不一定能满足业务需求。前端开发工作量和后期维护成本激增大量的文案需要被提取出来,被提取出来的文案最终会被合并到一个文件中去,如:en-US.json。这些工作如果通过手工完成,那么工作量会是非常巨大的。国际化文案的处理思路以上列举出了很多挑战,但实际上“页面文案处理”才是最主要的矛盾,因为它直接导致前端开发工作量和维护成本的激增。下面我们重点来讨论文案处理思路,其实从实现国际化的角度来看,jQuery、Vue、React 等都只是载体而已,实现思路都是相通的,因此国际化文案处理与具体的技术框架并不耦合。接下来将会抛出几种国际化文案处理思路,每种思路对生产力和生产关系的要求有高有低,姑且将其分别对应为石器时期、青铜时期、黄金时期。石器时期传统的国际化开发流程:前端开发到一定阶段,将文案提取到资源文件(通常为 en-US.json),然后将资源文件发送给翻译团队,翻译团队翻译出各国语言版本的文案,每种语言对应一个资源文件,最后将这些资源文件发回给前端开发人员,前端开发人员更新到自己本地。如下图所示:适用场景页面上要提取的文案不多支持的国际化语言较少,比如:只需要支持中文和英文项目需求较固定,后期只做简单维护,不会新增大的需求分析这是国际化开发的基本流程,“前端开发”和“翻译团队”是必不可少的两个节点,但它们相互之间依赖的太重。“提取文案”的过程本质上是在重复劳动,因此可以考虑由程序来完成。代码示例App.jsimport React, { Component } from ‘react’;import { IntlProvider, FormattedMessage } from ‘react-intl’;import qs from ‘querystring’;import logo from ‘./logo.svg’;import ‘./App.css’;import DEFAULT_MESSAGES from ‘./i18n/en-US.json’;const DEFAULT_LOCALE = ’en-US’;class App extends Component { state = { messages: DEFAULT_MESSAGES, }; componentWillMount() { const search = window.location.search.slice(1); const params = qs.parse(search); const locale = params.locale || DEFAULT_LOCALE; const messages = require(./i18n/${locale}.json); debugger; this.setState({ messages, }); } render() { const { messages } = this.state; return ( <IntlProvider locale=“en” messages={messages}> <div className=“App”> <header className=“App-header”> <img src={logo} className=“App-logo” alt=“logo” /> <p> <FormattedMessage id=“welcome” defaultMessage={Hello world!} /> </p> <a className=“App-link” href="/?locale=zh-CN" rel=“noopener noreferrer” > zh-CN </a> <a className=“App-link” href="/?locale=en-US" rel=“noopener noreferrer” > en-US </a> </header> </div> </IntlProvider> ); }}export default App;en-US.json{ “welcome”: “Hello world!"}青铜时期前面分析了“提取文案”的过程本质上是在重复劳动,那我们看看有没有办法进行改进。我们可以先对比一下“无国际化需求”和“有国际化需求”时的前端开发流程。如图所示:可以看出右边多了三个过程:将文案提取为变量为变量命名,要合乎其场景将变量和文案信息存到资源文件这里我们提出一个期望或愿景:希望能像开发普通业务一样去开发有国际化需求的业务!为了达成这一愿景,我们需要有一个工具:它能够扫描指定的文件,并能识别出文件中的字符串,然后能根据字符串的含义生成变量名,并用变量表达式替换掉原来的字符串,最后能够将提取出来的变量自动追加到资源文件中。如何实现这样的工具?我们可以用 Babel 将js文件解析为一颗语法树,然后遍历并找出字符串节点,接下来调用 Google Cloud Translation API 将字符串翻译为英文,并以此作为变量名得到变量表达式,最后用变量表达式替换掉原来的文本即可。如下图所示:幸运的是,i18n-pick 已经有那么点味道了~分析这是站在开发层面,对前端开发体验和开发效率提出的改进办法,将重复的事情交给程序去完成。黄金时期有了石器时期的生产方式作为铺垫,我们可以在此基础上继续做改进。既然“前端开发”和“翻译团队”之间依赖的太重,那我们可以在中间加一个节点“文案配置平台”。前端将提取的文案直接上传到“文案配置平台”,翻译团队直接在“文案配置平台”上进行文案翻译,前端直接从“文案配置平台”获取翻译后的最新文案。 文案配置平台应当具备的基本能力面向前端开发人员:文案录入、输出面向翻译团队:文案翻译、发布其他:文案版本控制适用场景有大量的国际化业务需求希望将其沉淀为通用能力平台,提升业务开发效率分析这是从架构层面对国际化开发方式进行优化和提效,一般大的互联网公司因为其自身业务的复杂度,都早已沉淀出很多的通用能力平台。总结以上每种思路都有各自适用的场景,实际生产中需要从开发成本、开发体验、后期维护、能力沉淀等多维度进行考虑。这篇文章旨在抛砖引玉打开思路,各位看官可以将自己的思路抛出来一起讨论。参考Internationalization国际化 - 通用 LTR/RTL 布局解决方案i18n-pickBabel 插件开发指南Google Cloud Translation API: Node.js Client文章可随意转载,但请保留此 原文链接。非常欢迎有激情的你加入 ES2049 Studio,简历请发送至 caijun.hcj(at)alibaba-inc.com 。 ...

February 18, 2019 · 1 min · jiezi

前端国际化的另类方式

关于国际化一个项目发展到一定的环境或者一开始就是为多国打造的,就需要考虑国际化了。简单来说,就是一套页面,多套语言。前不久做了一个国际化的项目,基于react和antd,里面用到了国际化,使用方式也很简单import zhCN from ‘antd/lib/locale-provider/zh_CN’;return ( <LocaleProvider locale={zhCN}> <App /> </LocaleProvider>);然后,页面所有的官方组件都变成了中文(默认是英文)。如果你使用其他工程,也有相应的解决方案,比如vue + vue-i18nangular + angular-translatereact + react-intljquery + jquery.i18n.property具体使用方式可以自行搜索,无非就是看各种api和配置文件。可以说相当成熟了,那么,如何自己实现?国际化的实现原理其实原理很简单,这里只讲最基本的原理,不谈框架的特性。上面列举这里这么多js框架,有一个共同的特征,就是都有一个类似语言包的东西。zh.jsonen.jsonjp.json…这个也很好理解,把各种语言独立开来,便于管理和维护。便于测试,我们把请求的过程去掉了,直接写在一个json对象里面,如下intl.jsvar intl = { “zh”: { “title”: “测试”, “content”: “这是一个测试” }, “cn”: { “title”: “test”, “content”: “this is a test” }}大概会写一些这样的配置语言,然后通过某种手段把对应的字段设置到相应的位置就可以了。下面是伪代码<h2 id=“title”>测试</h2><p id=“content”>这是一个测试</p>var lang = getGlobalVar(‘LOCALE’)||‘zh’;//获取语言var local = intl[’lang’];$title.innerHTML = local[’title’];$content.innerHTML = local[‘content’];上面是一个简单的实现思路,如果是一个简单的静态页面,大可以用这种方式,也不需要引入一些第三方库,然后啃他的api。当然,国际化还远不止页面静态文字的简单翻译,还包括本地化服务(时间、货币等等),如果涉及到这些还是使用现成的库来的快。另类的尝试除了以上js的思路,还有没有其他的方法呢?这不是废话吗,如果没有就不会来写这篇文章了。下面重点来了,如何不借助js来实现国际化?国际化的解决要点实现国际化有两个基本要素语言配置前端呈现语言配置是指如何设置多语言,也就是说如何把多种语言记录下来,就像前面js里面的配置文件。前端配置是指如何根据需要把需要展示的语言显示在页面,比如在中文环境下显示中文,英文环境下显示英文,用户看得到才算数。乍一看,好像不借助js根本行不通啊,又要配置文件,又要渲染页面内容,简直无解啊。content生成技术css中有个content生成属性,一般配合伪类:before或者:after来使用。可能一提到content,很多人可能就明白了,没错,content就可以实现内容生成。那么,试一试?<!DOCTYPE html><html lang=“en”><body> <h2 class=“title”></h2> <h3 class=“paragraph”></h3> <h4 class=“summary”></h4></body></html>/ch/html:lang(ch) .title:after{ content: ‘标题’;}html:lang(ch) .paragraph:after{ content: ‘段落’;}html:lang(ch) .summary:after{ content: ‘描述’;}/en/html:lang(en) .title:after{ content: ’title’;}html:lang(en) .paragraph:after{ content: ‘paragraph’;}html:lang(en) .summary:after{ content: ‘summary’;}怎么样?是眼前一亮还是。。很锉?好吧,我也觉得很挫,写起来比较麻烦,不过也是一种思路。content+attr上面的方式确实不怎么样,但是思维也需要一个渐进的过程下面用到了使用属性值作为content内容,之前的用纯css实现打星星效果(三)也使用这个特性,大家有兴趣可以回过去看下,这里简单介绍一下用法<style> span:after{content:attr(a)}</style><span a=“我是A”></span>这样就可以通过属性值来生成内容。为什么要用属性值呢?上一种方式之前不好原因还有一点,就是语义化太差,单独看html文件完全不知道是什么内容<h2 class=“title”></h2><h3 class=“paragraph”></h3><h4 class=“summary”></h4>下面我加点属性<h2 data-lang-ch=“标题” data-lang-en=“title”></h2><h3 data-lang-ch=“段落” data-lang-en=“paragraph”></h3><h4 data-lang-ch=“描述” data-lang-en=“summary”></h4>这下语义化应该没什么问题了吧,很清楚知道每个标签的内容大家应该知道我要做什么了吧,如下/ch/html:lang(ch) [data-lang-ch]:after{ content: attr(data-lang-ch);}/en/html:lang(en) [data-lang-en]:after{ content: attr(data-lang-en);}很简单,各自取各自对应的属性即可,需要什么语言直接在html添加属性即可,也不需要什么js结合之前讲过的css地址选择器,可以很轻松的实现根据地址栏来适配各种语言[data-lang-ch]:after,#ch:target~[data-lang-ch]:after{ content: attr(data-lang-ch);}#en:target~[data-lang-en]:after{ content: attr(data-lang-en);}页面添加一点元素<body> <div id=“ch”></div> <div id=“en”></div> <h2 data-lang-ch=“标题” data-lang-en=“title”></h2> <h3 data-lang-ch=“段落” data-lang-en=“paragraph”></h3> <h4 data-lang-ch=“描述” data-lang-en=“summary”></h4> <a href="#ch">中文</a> <a href="#en">英文</a></body>下面是demo小节以上主要探讨了两种完全不同的国际化方式,前一种主流,后一种完全属于另类,但还是有用武之地的。如果你的页面不太复杂,完全可以采取这种方式。没有了js,速度也快了,视野也开阔了,腰也不酸了,腿也不疼了…虽然以上跳过js实现了国际化需求,但是如果说是一些动态内容,比如时间,就没法放在属性里面的,这一部分,就只能通过js来处理了,实属无奈。。还有一个就是,如果页面复杂,或者需适配语言太多,那就意味着属性要写很多<h2 data-lang-ch=“标题” data-lang-en=“title” data-lang-fr=“XXX” data-lang-jp=“XXX” data-lang-de=“XXX” data-lang-fi=“XXX” data-lang-it=“XXX” ></h2>这样就不太友好了,这种情况下就推荐主流的js解决方式如果喜欢的文章的话,可以点赞并收藏,多多关注我的博客 ...

November 14, 2018 · 1 min · jiezi