9

我必须解决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

有什么更好更干净的想法吗?

4

2 回答 2

8

好问题。想到了四种解决方案:

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. 不明智的黑客攻击

另一个(坏的?)想法是将模板字符串作为常规字符串开始编写,然后在运行时将它们视为模板字符串。我们定义一个函数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);
}

诚然,这有点尴尬。这种方法的唯一优点是它不需要预扫描重写。

小问题,但是如果原始模板字符串是多行的,则不能直接将其重写为常规字符串。在这种情况下,您可以将其保留为反引号的模板字符串,但将$as转义\$,一切都会好起来的:

底线:除非您想重写xgettext、使用解析器或从事其他黑客行为,否则请进行蛮力替换。

于 2016-01-19T17:43:55.280 回答
0

目前,我正在研究基于 es6 模板文字的本地化解决方案。你可以在这里查看 - https://c-3po.js.org。该项目具有提取功能(基于 babel 插件)。你也可以用它来构建本地化的js。这是它的样子:

t`Hello ${name}`
于 2017-01-31T16:38:00.553 回答