我必须解决gettext
的限制才能识别ES6模板字符串,并考虑获得"非内插值"模板字符串作为编译步骤,以便只有"正常"代码中的字符串。
基本上我想要实现的是改变这个
const adjective = 'wonderful'
const something = `Look, I am a ${adjective} string`
console.log(something)
> "Look, I am a wonderful string"
进入这个
const adjective = 'wonderful'
const something = 'Look, I am a ${adjective} string'
console.log(something)
> "Look, I am a ${adjective} string"
实现这一目标的一种野蛮方式是使用sed
,但它肯定不是更优雅(也可能更容易出错)
sed "s/\`/'/g" FILENAME
想到任何更好,更清洁的想法?
答案 0 :(得分:7)
好问题。我想到了四种解决方案:
如您所知,在扫描可翻译字符串之前使用引号标记强制替换反引号并不是一个可怕的想法,只要您了解风险。例如,考虑:
"hello, this word is in `backticks`"
另一个边缘案例是
`${`I am nested`}`
这种方法也会破坏多行模板字符串。
xgettext
当然,“正确”的解决方案是编写一个处理模板字符串的xgettext
分支。然后你可以写
const something = _(`Look, I am a ${adjective} string`);
不幸的是,这看起来可能更难。 xgettext中有一堆与字符串相关的硬连线逻辑。如果你要承担这个项目,很多人会感谢你。
更强大的替代方法是使用Esprima等JavaScript解析器。这些解析器提供了获取令牌的能力(例如模板字符串)。正如您在http://esprima.org/demo/parse.html所看到的,要查找的相关令牌类型为TemplateLiteral
。
另一个(糟糕的?)想法是将模板字符串作为常规字符串编写,然后在运行时将它们视为模板字符串。我们定义了一个函数eval_template
:
const template = _("Look, I am a ${adjective} string");
const something = eval_template(template, {adjective});
eval_template
将字符串转换为评估模板。模板字符串中使用的本地作用域中的任何变量都需要作为第二个参数中传递的对象的一部分提供给eval_template
(因为使用Function
创建的函数位于全局作用域中,并且无法访问局部变量,所以我们必须通过它们。它实现如下:
function eval_template_(s, params) {
var keys = Object.keys(params);
var vals = keys.map(key => params[key]);
var f = Function(...keys, "return `" + s + "`");
return f(...vals);
}
当然,这有点尴尬。这种方法的唯一优点是它不需要预扫描重写。
小点,但如果原始模板字符串是多行的,则不能直接将其重写为常规字符串。在这种情况下,您可以将其保留为反向标记的模板字符串,但将$
作为\$
转义,一切都会很好:
底线:除非您想重写xgettext
,使用解析器或参与其他hackery,否则请进行强力替换。
答案 1 :(得分:0)
目前,我正在开发一个基于es6模板文字的本地化解决方案。你可以在这里查看 - https://c-3po.js.org。该项目具有提取功能(基于babel插件)。而且你也可以用它来构建本地化的js。这是它的样子:
t`Hello ${name}`