你能 "dumb down" ES6 模板字符串到普通字符串吗?

Can you "dumb down" ES6 template strings to normal strings?

我必须解决 gettext 的限制才能识别 ES6 模板字符串,并且我考虑将模板字符串的 "non interpolated value" 作为编译步骤,以便只有 "normal" 代码中的字符串。

基本上我想实现的是改造这个

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

有什么更好更简洁的想法吗?

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

1。蛮力

如您所建议的那样,在扫描可翻译字符串之前用引号蛮力替换反引号并不是一个可怕的想法,只要您了解风险即可。例如,考虑:

"hello, this word is in `backticks`"

另一个极端情况是

`${`I am nested`}`

这种方法也会破坏 multi-line 模板字符串。

2。修复 xgettext

当然,"correct" 解决方案是写一个 xgettext 的分支来处理模板字符串。然后你可以写

const something = _(`Look, I am a ${adjective} string`);

不幸的是,这可能比看起来更难。 xgettext里面有一堆hard-wired逻辑跟字符串相关。如果你要承担这个项目,很多人会感谢你。

3。使用解析器

更强大的替代方法是使用 JavaScript 解析器,例如 Esprima。这些解析器公开了获取标记(例如模板字符串)的能力。正如您在 http://esprima.org/demo/parse.html 中所见,要查找的相关标记类型是 TemplateLiteral.

4。不可取的黑客攻击

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

当然,这有点尴尬。这种方法的唯一优点是它不需要 pre-scan 重写。

次要点,但是如果原始模板字符串是multi-line,则不能直接将其重写为常规字符串。在这种情况下,您可以将其保留为 back-ticked 模板字符串,但将 $ 转义为 $,一切都会好起来的:

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

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

t`Hello ${name}`