【问题标题】:Can you "dumb down" ES6 template strings to normal strings?你能将 ES6 模板字符串“简化”为普通字符串吗?
【发布时间】:2016-04-25 05:45:18
【问题描述】:

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

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

【问题讨论】:

  • 不,您不能在不丢失“智能”属性(包括字符串扩展)的情况下“简化”模板字符串。请注意(`A ${b=alert()}`) 将执行alert(),而'A ${b=alert()}' 不会发生这种情况
  • 我知道。我不需要gettext 的聪明才智,因为它不够聪明,无法理解模板字符串。 (我已经澄清了更多我的问题)
  • 你是问字符串插值,还是需要模板标签?
  • 你试过像 babel 这样的转译器吗?
  • 转译器不是一个可行的选择,因为翻译字符串被包装在一个也会被转换的函数中。例如。 t('translate me') 变成 function(par, 0)('translate me'),gettext 不理解

标签: javascript localization ecmascript-6 gettext template-strings


【解决方案1】:

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

1。蛮力

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

"hello, this word is in `backticks`"

另一个极端情况是

`${`I am nested`}`

这种方法也会破坏多行模板字符串。

2。修复xgettext

当然,“正确”的解决方案是编写一个处理模板字符串的xgettext 的fork。然后你可以写

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);
}

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

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

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

【讨论】:

  • 除此之外,您可以使用t => Function('return `' + t + '`')()。希望它有效。
  • 很遗憾,这不起作用,因为与eval不同,使用Function构造函数定义的函数是在全局范围内,不能访问adjective等变量。
  • 好点。确实很好。无论如何,必须有一种更简单的方法。
【解决方案2】:

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

t`Hello ${name}`

【讨论】:

猜你喜欢
  • 2016-09-19
  • 1970-01-01
  • 2015-02-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-01-23
相关资源
最近更新 更多