在工作中,我们有一个自定义的翻译解决方案。实施如下:
smarty
模板中,调用get_string('unique_string_identifier', 'Default string')
以获取已翻译的字符串。我目前正在使用React.js
重写部分应用程序,并且正在实施javascript
get_string
版getString
(称之为getString
1}})。
translate
函数位于名为getString
的全局模块中。我认为这是一个完美的解决方案是创建一个babel变换,将所有import React from 'react'
import {getString} from 'translate'
export default class TestComponent extends React.Component {
render() {
const translatedString = getString('unique_string_identifier_1', 'Default string 1')
return <div>
{getString('unique_string_identifier_2', 'Default string 2')}
</div>
}
}
调用移动到顶部作用域,将变量作为参考。这样我就可以相对轻松地解决这两个问题。
import React from 'react'
import {getString} from 'translate'
const _getStringRef0 = getString('unique_string_identifier_1', 'Default string 1')
const _getStringRef1 = getString('unique_string_identifier_2', 'Default string 2')
export default class TestComponent extends React.Component {
render() {
const translatedString = _getStringRef0
return <div>
{_getStringRef1}
</div>
}
}
会变成:
{{1}}
我将如何做到这一点?
答案 0 :(得分:1)
import React from 'react'
import {getString, makeGetString} from 'translate'
const _ = makeGetString({
prefix: 'unique_prefix'
})
export default class TestComponent extends React.Component {
render() {
const translatedString = getString('unique_string_identifier_1', 'Default string 1 %s', dynamic1, dynamic2)
return <div>
{getString('unique_string_identifier_2', 'Default string 2')}
{_('string_identifier_3')}
</div>
}
}
...变为
import React from 'react'
import {getString, makeGetString} from 'translate'
const _getString = getString('unique_string_identifier_1', 'Default string 1 %s');
const _getString2 = getString('unique_string_identifier_2', 'Default string 2');
const _ = makeGetString({
prefix: 'unique_prefix'
})
const _ref = _('string_identifier_3');
export default class TestComponent extends React.Component {
render() {
const translatedString = _getString(dynamic1, dynamic2)
return <div>
{_getString2()}
{_ref()}
</div>
}
}
这实际上就是我所拥有的:
module.exports = function(babel) {
const {types: t} = babel
const origFnNames = [
'getString',
'makeGetString',
]
const getStringVisitor = {
CallExpression(path) {
const callee = path.get('callee')
if(callee && callee.node && this.fnMap[callee.node.name]) {
this.replacePaths.push(path)
}
}
}
const makeGetStringVisitor = {
VariableDeclaration(path) {
path.node.declarations.forEach((decl) => {
if(!(decl.init && decl.init.callee && !decl.parent)) {
return
}
const fnInfo = this.fnMap[decl.init.callee.name]
if(fnInfo && fnInfo.name === 'makeGetString') {
this.fnMap[decl.id.name] = {
name: decl.id.name,
path
}
}
})
}
}
return {
visitor: {
ImportDeclaration(path) {
if(path.node.source.value === 'translate') {
const fnMap = {}
path.node.specifiers.forEach((s) => {
if(origFnNames.indexOf(s.imported.name) !== -1) {
fnMap[s.local.name] = {
name: s.imported.name,
path
}
}
})
path.parentPath.traverse(makeGetStringVisitor, {fnMap})
const replacePaths = []
path.parentPath.traverse(getStringVisitor, {fnMap, replacePaths})
delete fnMap.makeGetString
Object.keys(fnMap).map((k) => {
const fnInfo = fnMap[k]
const paths = replacePaths.filter((p) => p.get('callee').node.name === fnInfo.name)
const expressions = paths.map((rPath) => {
const id = rPath.scope.generateUidIdentifierBasedOnNode(rPath.node)
const args = rPath.node.arguments
rPath.replaceWith(t.callExpression(id, args.slice(2)))
const expr = t.callExpression(t.identifier(fnInfo.name), args.slice(0, 2))
return t.variableDeclaration('const', [t.variableDeclarator(id, expr)])
})
fnInfo.path.insertAfter(expressions)
})
}
}
}
}
}