Skip to content

Commit

Permalink
[Tools] Add TemplateLiteral parsing to i18n_check tool (#24580) (#24719)
Browse files Browse the repository at this point in the history
* [Tools] Add TemplateLiteral parsing to i18n_check tool

* Add comments
  • Loading branch information
LeanidShutau authored Oct 30, 2018
1 parent fef9624 commit f249182
Show file tree
Hide file tree
Showing 4 changed files with 60 additions and 9 deletions.
14 changes: 13 additions & 1 deletion src/dev/i18n/extractors/__snapshots__/i18n_call.test.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,19 @@ Array [
]
`;

exports[`dev/i18n/extractors/i18n_call throws if defaultMessage is not a string literal 1`] = `"defaultMessage value should be a string literal (\\"message-id\\")."`;
exports[`dev/i18n/extractors/i18n_call extracts "i18n" and "i18n.translate" functions call message 3`] = `
Array [
"message-id-3",
Object {
"context": "Message
context 3",
"message": "Default
message 3",
},
]
`;

exports[`dev/i18n/extractors/i18n_call throws if defaultMessage is not a string literal 1`] = `"defaultMessage value should be a string or template literal (\\"message-id\\")."`;

exports[`dev/i18n/extractors/i18n_call throws if message id value is not a string literal 1`] = `"Message id should be a string literal."`;

Expand Down
4 changes: 2 additions & 2 deletions src/dev/i18n/extractors/__snapshots__/react.test.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ Array [
]
`;
exports[`dev/i18n/extractors/react extractIntlMessages throws if context value is not a string literal 1`] = `"context value should be a string literal (\\"message-id\\")."`;
exports[`dev/i18n/extractors/react extractIntlMessages throws if context value is not a string literal 1`] = `"context value should be a string or template literal (\\"message-id\\")."`;
exports[`dev/i18n/extractors/react extractIntlMessages throws if defaultMessage value is not a string literal 1`] = `"defaultMessage value should be a string literal (\\"message-id\\")."`;
exports[`dev/i18n/extractors/react extractIntlMessages throws if defaultMessage value is not a string literal 1`] = `"defaultMessage value should be a string or template literal (\\"message-id\\")."`;
exports[`dev/i18n/extractors/react extractIntlMessages throws if message id is not a string literal 1`] = `"Message id should be a string literal."`;
12 changes: 12 additions & 0 deletions src/dev/i18n/extractors/i18n_call.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,12 @@ const translateCallMessageSource = `
i18n.translate('message-id-2', { defaultMessage: 'Default message 2', context: 'Message context 2' });
`;

const i18nCallMessageWithTemplateLiteralSource = `
i18n('message-id-3', { defaultMessage: \`Default
message 3\`, context: \`Message
context 3\` });
`;

describe('dev/i18n/extractors/i18n_call', () => {
test('extracts "i18n" and "i18n.translate" functions call message', () => {
let callExpressionNode = [...traverseNodes(parse(i18nCallMessageSource).program.body)].find(
Expand All @@ -44,6 +50,12 @@ describe('dev/i18n/extractors/i18n_call', () => {
);

expect(extractI18nCallMessages(callExpressionNode)).toMatchSnapshot();

callExpressionNode = [
...traverseNodes(parse(i18nCallMessageWithTemplateLiteralSource).program.body),
].find(node => isCallExpression(node));

expect(extractI18nCallMessages(callExpressionNode)).toMatchSnapshot();
});

test('throws if message id value is not a string literal', () => {
Expand Down
39 changes: 33 additions & 6 deletions src/dev/i18n/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import {
isObjectExpression,
isObjectProperty,
isStringLiteral,
isTemplateLiteral,
} from '@babel/types';
import fs from 'fs';
import glob from 'glob';
Expand Down Expand Up @@ -197,20 +198,46 @@ export function extractMessageIdFromNode(node) {
return node.value;
}

function parseTemplateLiteral(node, messageId) {
// TemplateLiteral consists of quasis (strings) and expressions.
// If we have at least one expression in template literal, then quasis length
// will be greater than 1
if (node.quasis.length > 1) {
throw createFailError(`expressions are not allowed in template literals ("${messageId}").`);
}

// Babel reads 'cooked' and 'raw' versions of a string.
// 'cooked' acts like a normal StringLiteral value and interprets backslashes
// 'raw' is primarily designed for TaggedTemplateLiteral and escapes backslashes
return node.quasis[0].value.cooked;
}

export function extractMessageValueFromNode(node, messageId) {
if (!isStringLiteral(node)) {
throw createFailError(`defaultMessage value should be a string literal ("${messageId}").`);
if (isStringLiteral(node)) {
return node.value;
}

return node.value;
if (isTemplateLiteral(node)) {
return parseTemplateLiteral(node, messageId);
}

throw createFailError(
`defaultMessage value should be a string or template literal ("${messageId}").`
);
}

export function extractContextValueFromNode(node, messageId) {
if (!isStringLiteral(node)) {
throw createFailError(`context value should be a string literal ("${messageId}").`);
if (isStringLiteral(node)) {
return node.value;
}

return node.value;
if (isTemplateLiteral(node)) {
return parseTemplateLiteral(node, messageId);
}

throw createFailError(
`context value should be a string or template literal ("${messageId}").`
);
}

export function extractValuesKeysFromNode(node, messageId) {
Expand Down

0 comments on commit f249182

Please sign in to comment.