Можете ли вы "заглушить" строки шаблона ES6 до нормальных строк?
Я должен обойти ограничения 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
Любая лучшая и более чистая идея приходит на ум?
2 ответа
Отличный вопрос На ум приходят четыре решения:
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);
}
Конечно, это немного неловко. Единственное преимущество этого подхода состоит в том, что он не требует перезаписи перед сканированием.
Минорная точка, но если исходная строка шаблона многострочная, вы не можете напрямую переписать ее как обычную строку. В этом случае вы можете оставить его как заданную галочкой строку шаблона, но экранировать $
как \$
и все будет хорошо
Итог: если вы не хотите переписать xgettext
использовать парсер или заниматься другими хакерскими атаками, делать грубую замену.
В настоящее время я работаю над решением по локализации, основанным на литералах шаблонов es6. Вы можете проверить это здесь - https://c-3po.js.org/. Этот проект имеет функциональность извлечения (на основе плагина babel). А также вы можете использовать его для создания локализованных JS. Вот как это выглядит:
t`Hello ${name}`