Skip to content

Commit

Permalink
fix(extractor): allow i18._(foo.bar) without warning. (#1492)
Browse files Browse the repository at this point in the history
  • Loading branch information
timofei-iatsenko authored Mar 9, 2023
1 parent 27ee8e2 commit 3ae3c1e
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 48 deletions.
63 changes: 31 additions & 32 deletions packages/babel-plugin-extract-messages/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import {
Node,
ObjectExpression,
ObjectProperty,
StringLiteral,
} from "@babel/types"
import type { PluginObj, PluginPass } from "@babel/core"
import type { NodePath } from "@babel/core"
Expand Down Expand Up @@ -63,16 +62,27 @@ function collectMessage(
function getTextFromExpression(
t: BabelTypes,
exp: Expression,
hub: Hub
hub: Hub,
emitErrorOnVariable = true
): string {
if (t.isStringLiteral(exp)) {
return exp.value
}

if (t.isBinaryExpression(exp)) {
return (
getTextFromExpression(t, exp.left as Expression, hub) +
getTextFromExpression(t, exp.right as Expression, hub)
getTextFromExpression(
t,
exp.left as Expression,
hub,
emitErrorOnVariable
) +
getTextFromExpression(
t,
exp.right as Expression,
hub,
emitErrorOnVariable
)
)
}

Expand All @@ -91,13 +101,15 @@ function getTextFromExpression(
return exp.quasis[0]?.value?.cooked
}

console.warn(
hub.buildError(
exp,
"Only strings or template literals could be extracted.",
SyntaxError
).message
)
if (emitErrorOnVariable) {
console.warn(
hub.buildError(
exp,
"Only strings or template literals could be extracted.",
SyntaxError
).message
)
}
}

function extractFromObjectExpression(
Expand All @@ -121,11 +133,6 @@ function extractFromObjectExpression(
export default function ({ types: t }: { types: BabelTypes }): PluginObj {
let localTransComponentName: string

// We need to remember all processed nodes. When JSX expressions are
// replaced with CallExpressions, all children are traversed for each CallExpression.
// Then, i18n._ methods are visited multiple times for each parent CallExpression.
const visitedNodes = new WeakSet<Node>()

function isTransComponent(node: Node) {
return (
t.isJSXElement(node) &&
Expand Down Expand Up @@ -213,8 +220,6 @@ export default function ({ types: t }: { types: BabelTypes }): PluginObj {
},

CallExpression(path, ctx) {
if (visitedNodes.has(path.node)) return

const hasComment = [path.node, path.parent].some((node) =>
hasI18nComment(node)
)
Expand All @@ -230,16 +235,15 @@ export default function ({ types: t }: { types: BabelTypes }): PluginObj {
if (!hasComment && !isNonMacroI18n) return

let props: Record<string, unknown> = {
id: (firstArgument as StringLiteral).value,
id: getTextFromExpression(
t,
firstArgument as Expression,
ctx.file.hub,
false
),
}

if (!props.id) {
// don't rise warning when translating from variables
if (!t.isIdentifier(firstArgument)) {
console.warn(
path.buildCodeFrameError("Missing message ID, skipping.").message
)
}
return
}

Expand All @@ -256,17 +260,14 @@ export default function ({ types: t }: { types: BabelTypes }): PluginObj {
}
}

visitedNodes.add(path.node)
collectMessage(path, props, ctx)
},

StringLiteral(path, ctx) {
if (!hasI18nComment(path.node) || visitedNodes.has(path.node)) {
if (!hasI18nComment(path.node)) {
return
}

visitedNodes.add(path.node)

const props = {
id: path.node.value,
}
Expand All @@ -283,12 +284,10 @@ export default function ({ types: t }: { types: BabelTypes }): PluginObj {

// Extract message descriptors
ObjectExpression(path, ctx) {
if (!hasI18nComment(path.node) || visitedNodes.has(path.node)) {
if (!hasI18nComment(path.node)) {
return
}

visitedNodes.add(path.node)

const props = extractFromObjectExpression(t, path.node, ctx.file.hub, [
"id",
"message",
Expand Down
41 changes: 25 additions & 16 deletions packages/babel-plugin-extract-messages/test/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,10 +92,10 @@ describe("@lingui/babel-plugin-extract-messages", function () {
import { Trans } from "@lingui/react";
<Trans id={message} />;
<Trans id={message.field} />;
`
expectNoConsole(() => {
const messages = transformCode(code)

expect(messages.length).toBe(0)
})
})
Expand Down Expand Up @@ -127,22 +127,14 @@ import { Trans } from "@lingui/react";
})
})

it("Should log error when no ID provided", () => {
const code = `const msg = i18n._('', {}, {message: "My Message"})`

return mockConsole((console) => {
const messages = transformCode(code)

expect(messages.length).toBe(0)
expect(console.error).not.toBeCalled()
expect(console.warn).toBeCalledWith(
expect.stringContaining(`Missing message ID`)
)
})
})

it("Should not rise warning when translation from variable", () => {
const code = `i18n._(message)`
const code = `
i18n._(message);
// member expression
i18n._(foo.bar);
// function call
i18n._(getMessage());
`

expectNoConsole(() => {
const messages = transformCode(code)
Expand All @@ -165,6 +157,23 @@ import { Trans } from "@lingui/react";
})
})

it("Should support extract id from TplLiteral and Concatenation", () => {
const code = `
const msg = i18n._(\`message.id\`);
const msg2 = i18n._("second" + '.' + "id")
`

expectNoConsole(() => {
const messages = transformCode(code)
expect(messages[0]).toMatchObject({
id: "message.id",
})
expect(messages[1]).toMatchObject({
id: "second.id",
})
})
})

it("Should support string concatenation", () => {
const code = `const msg = i18n._('message.id', {}, {comment: "first " + "second " + "third"})`

Expand Down

0 comments on commit 3ae3c1e

Please sign in to comment.