Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
189 views
in Technique[技术] by (71.8m points)

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

I have to work around the limitation of gettext to recognise ES6 template strings, and I thought about getting the "non interpolated value" of the template strings as a compilation step, in order to have only "normal" strings in the code.

Basically what I would like to achieve is transform this

const adjective = 'wonderful'
const something = `Look, I am a ${adjective} string`

console.log(something)
> "Look, I am a wonderful string"

into this

const adjective = 'wonderful'
const something = 'Look, I am a ${adjective} string'

console.log(something)
> "Look, I am a ${adjective} string"

One brutal way of achieving this is using sed, but it's most certainly not the more elegant (and probably also error prone)

sed "s/`/'/g" FILENAME

Any better and cleaner idea comes to mind?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Great question. There are four solutions that come to mind:

1. Brute force

A brute force replacement of backticks with quote marks prior to scanning for translatable strings, as you suggested, is not a horrible idea, as long as you understand the risks. For instance, consider:

"hello, this word is in `backticks`"

Another edge case is

`${`I am nested`}`

This approach will also break multi-line template strings.

2. Fix xgettext

Of course, the "correct" solution is to write a fork of xgettext that deals with template strings. Then you could just write

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

Unfortunately, this could be harder that it seems. There is a bunch of hard-wired logic inside xgettext related to strings. If you were to undertake this project, many would thank you.

3. Using a parser

The more robust alternative is to use a JavaScript parser such as Esprima. These parsers expose the ability to pick up tokens (such as template strings). As you can see at http://esprima.org/demo/parse.html, the relevant token type to look for is TemplateLiteral.

4. Unadvisable hacks

Another (bad?) idea is to write template strings as regular strings to start with, then treat them as template strings at run-time. We define a function eval_template:

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

eval_template converts a string into an evaluated template. Any variable in local scope used in the template string needs to be provided to eval_template as part of the object passed in the second parameter (because functions created using Function are in the global scope and cannot access local variables, so we have to pass them in). It is implemented as follows:

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

Granted, this is a bit awkward. The only advantage of this approach is that it requires no pre-scan rewriting.

Minor point, but if the original template string is multi-line, you cannot directly rewrite it as a regular string. In that case, you can leave it as a back-ticked template string but escape the $ as $, and all will be well:

Bottom line: unless you want to rewrite xgettext, use a parser, or engage in other hackery, do the brute force replacement.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...