很好的问题。我想到了四个解决方案:
1. 暴力破解
在扫描可翻译字符串之前,通过暴力替换反引号为引号,就像你建议的那样,不是一个坏主意,只要你理解其中的风险。例如,考虑以下情况:
"hello, this word is in `backticks`"
另一个特殊情况是:
`${`I am nested`}`
这种方法还会破坏多行模板字符串。
2. 修复
xgettext
当然,"正确"的解决方案是编写一个处理模板字符串的
xgettext
分支。这样,您就可以只需编写:
const something = _(`Look, I am a ${adjective} string`);
很不幸,这可能比看起来更难。xgettext内部有许多与字符串相关的硬编码逻辑。如果您要承担此项目,许多人会感谢您。
3. 使用解析器
更健壮的替代方案是使用JavaScript解析器,如Esprima。这些解析器公开了捕获标记(例如模板字符串)的能力。如
http://esprima.org/demo/parse.html所示,要查找的相关标记类型为
TemplateLiteral
。
4. 不建议使用的hack方法
另一个(不好的?)想法是首先将模板字符串写成常规字符串,然后在运行时将其视为模板字符串。我们定义了一个名为
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
,使用解析器或进行其他黑客行为,否则请进行粗暴的替换。
(`A ${b=alert()}`)
将执行alert()
,而'A ${b=alert()}'
则不会。 - Ismael Miguelgettext
中使用智能功能,因为它无法理解模板字符串。(我已经更明确地表达了我的问题) - domokunt('translate me')
变成了类似于function(par, 0)('translate me')
的东西,而gettext
不理解这个。 - domokun