Skip to content

Commit

Permalink
fix: React macros fixes (#958)
Browse files Browse the repository at this point in the history
* chore: fix pseudolocalize tests

* fix: <Select /> choices not extracted

* fix: <Plural /> props on macro not exported
  • Loading branch information
semoal committed Jan 26, 2021
1 parent 57482c0 commit 353c537
Show file tree
Hide file tree
Showing 4 changed files with 135 additions and 41 deletions.
6 changes: 3 additions & 3 deletions packages/cli/src/api/pseudoLocalize.test.ts
Expand Up @@ -43,7 +43,7 @@ describe("PseudoLocalization", () => {
"{count, plural, offset:1 zero {There are no messages} other {There are # messages in your inbox}}"
)
).toEqual(
"{count, plural, offset:1 zero {泞磨膿艜膿'艜膿 艅艒 m膿艣艣脿臐膿艣} other {泞磨膿艜膿'艜膿 # m膿艣艣脿臐膿艣 末艅 欧艒农艜 末艅苺艒x}}"
"{count, plural, offset:1 zero {泞磨膿艜膿 脿艜膿 艅艒 m膿艣艣脿臐膿艣} other {泞磨膿艜膿 脿艜膿 # m膿艣艣脿臐膿艣 末艅 欧艒农艜 末艅苺艒x}}"
)
})

Expand All @@ -53,7 +53,7 @@ describe("PseudoLocalization", () => {
"{count, plural, zero {There's # <span>message</span>} other {There are # messages}"
)
).toEqual(
"{count, plural, zero {泞磨膿艜膿'艣 # <span>m膿艣艣脿臐膿</span>} other {泞磨膿艜膿'艜膿 # m膿艣艣脿臐膿艣}"
"{count, plural, zero {泞磨膿艜膿'艣 # <span>m膿艣艣脿臐膿</span>} other {泞磨膿艜膿 脿艜膿 # m膿艣艣脿臐膿艣}"
)
})

Expand All @@ -63,7 +63,7 @@ describe("PseudoLocalization", () => {
"{count, plural, =0 {There's # <span>message</span>} other {There are # messages}"
)
).toEqual(
"{count, plural, =0 {泞磨膿艜膿'艣 # <span>m膿艣艣脿臐膿</span>} other {泞磨膿艜膿'艜膿 # m膿艣艣脿臐膿艣}"
"{count, plural, =0 {泞磨膿艜膿'艣 # <span>m膿艣艣脿臐膿</span>} other {泞磨膿艜膿 脿艜膿 # m膿艣艣脿臐膿艣}"
)
})
})
Expand Down
62 changes: 51 additions & 11 deletions packages/macro/src/macroJs.test.ts
Expand Up @@ -6,9 +6,9 @@ function createMacro() {
return new MacroJs({ types }, { i18nImportName: "i18n" })
}

describe("js macro", function () {
describe("tokenizeTemplateLiteral", function () {
it("simple message without arguments", function () {
describe("js macro", () => {
describe("tokenizeTemplateLiteral", () => {
it("simple message without arguments", () => {
const macro = createMacro()
const exp = parseExpression("t`Message`")
const tokens = macro.tokenizeTemplateLiteral(exp)
Expand All @@ -20,7 +20,7 @@ describe("js macro", function () {
])
})

it("message with named argument", function () {
it("message with named argument", () => {
const macro = createMacro()
const exp = parseExpression("t`Message ${name}`")
const tokens = macro.tokenizeTemplateLiteral(exp)
Expand All @@ -40,7 +40,7 @@ describe("js macro", function () {
])
})

it("message with positional argument", function () {
it("message with positional argument", () => {
const macro = createMacro()
const exp = parseExpression("t`Message ${obj.name}`")
const tokens = macro.tokenizeTemplateLiteral(exp)
Expand All @@ -59,7 +59,7 @@ describe("js macro", function () {
])
})

it("message with plural", function () {
it("message with plural", () => {
const macro = createMacro()
const exp = parseExpression("t`Message ${plural(count, {})}`")
const tokens = macro.tokenizeTemplateLiteral(exp)
Expand All @@ -81,8 +81,8 @@ describe("js macro", function () {
})
})

describe("tokenizeChoiceMethod", function () {
it("plural", function () {
describe("tokenizeChoiceMethod", () => {
it("plural", () => {
const macro = createMacro()
const exp = parseExpression(
"plural(count, { one: '# book', other: '# books'})"
Expand All @@ -103,7 +103,7 @@ describe("js macro", function () {
})
})

it("plural with offset", function () {
it("plural with offset", () => {
const macro = createMacro()
const exp = parseExpression(
`plural(count, {
Expand Down Expand Up @@ -131,7 +131,7 @@ describe("js macro", function () {
})
})

it("plural with template literal", function () {
it("plural with template literal", () => {
const macro = createMacro()
const exp = parseExpression(
"plural(count, { one: `# glass of ${drink}`, other: `# glasses of ${drink}`})"
Expand Down Expand Up @@ -178,7 +178,7 @@ describe("js macro", function () {
})
})

it("plural with select", function () {
it("plural with select", () => {
const macro = createMacro()
const exp = parseExpression(
`plural(count, {
Expand Down Expand Up @@ -218,5 +218,45 @@ describe("js macro", function () {
},
})
})

it("select", () => {
const macro = createMacro()
const exp = parseExpression(
`select(gender, {
male: "he",
female: "she",
other: "they"
})`
)
const tokens = macro.tokenizeChoiceComponent(exp)
expect(tokens).toEqual({
format: "select",
name: "gender",
options: expect.objectContaining({
female: "she",
male: "he",
offset: undefined,
other: "they"
}),
type: "arg",
value: {
end: 13,
loc: {
end: expect.objectContaining({
column: 13,
line: 1,
}),
identifierName: "gender",
start: expect.objectContaining({
column: 7,
line: 1,
}),
},
name: "gender",
start: 7,
type: "Identifier",
}
})
})
})
})
65 changes: 53 additions & 12 deletions packages/macro/src/macroJsx.test.ts
Expand Up @@ -11,9 +11,9 @@ function createMacro() {
return new MacroJSX({ types })
}

describe("jsx macro", function () {
describe("tokenizeTrans", function () {
it("simple message without arguments", function () {
describe("jsx macro", () => {
describe("tokenizeTrans", () => {
it("simple message without arguments", () => {
const macro = createMacro()
const exp = parseExpression("<Trans>Message</Trans>")
const tokens = macro.tokenizeTrans(exp)
Expand All @@ -25,7 +25,7 @@ describe("jsx macro", function () {
])
})

it("message with named argument", function () {
it("message with named argument", () => {
const macro = createMacro()
const exp = parseExpression("<Trans>Message {name}</Trans>")
const tokens = macro.tokenizeTrans(exp)
Expand All @@ -45,7 +45,7 @@ describe("jsx macro", function () {
])
})

it("message with positional argument", function () {
it("message with positional argument", () => {
const macro = createMacro()
const exp = parseExpression("<Trans>Message {obj.name}</Trans>")
const tokens = macro.tokenizeTrans(exp)
Expand All @@ -64,7 +64,7 @@ describe("jsx macro", function () {
])
})

it("message with plural", function () {
it("message with plural", () => {
const macro = createMacro()
const exp = parseExpression(
"<Trans>Message <Plural value={count} /></Trans>"
Expand All @@ -88,8 +88,8 @@ describe("jsx macro", function () {
})
})

describe("tokenizeChoiceComponent", function () {
it("plural", function () {
describe("tokenizeChoiceComponent", () => {
it("plural", () => {
const macro = createMacro()
const exp = parseExpression(
"<Plural value={count} one='# book' other='# books' />"
Expand All @@ -110,7 +110,7 @@ describe("jsx macro", function () {
})
})

it("plural with offset", function () {
it("plural with offset", () => {
const macro = createMacro()
const exp = parseExpression(
`<Plural
Expand Down Expand Up @@ -139,7 +139,7 @@ describe("jsx macro", function () {
})
})

it("plural with template literal", function () {
it("plural with template literal", () => {
const macro = createMacro()
const exp = parseExpression(
"<Plural value={count} one={`# glass of ${drink}`} other={`# glasses of ${drink}`} />"
Expand Down Expand Up @@ -186,11 +186,11 @@ describe("jsx macro", function () {
})
})

it("plural with select", function () {
it("plural with select", () => {
const macro = createMacro()
const exp = parseExpression(
`<Plural
value={count}
value={count}
one={
<Select
value={gender}
Expand Down Expand Up @@ -228,5 +228,46 @@ describe("jsx macro", function () {
},
})
})

it("Select", () => {
const macro = createMacro()
const exp = parseExpression(
`<Select
value={gender}
male="he"
one="heone"
female="she"
other="they"
/>`
)
const tokens = macro.tokenizeNode(exp)
expect(tokens).toEqual({
format: "select",
name: "gender",
options: expect.objectContaining({
female: "she",
male: "he",
offset: undefined,
other: "they"
}),
type: "arg",
value: expect.objectContaining({
"end": 31,
"loc": {
"end": {
"column": 23,
"line": 2,
},
"identifierName": "gender",
"start": {
"column": 17,
"line": 2,
},
},
name: "gender",
type: "Identifier",
})
})
})
})
})
43 changes: 28 additions & 15 deletions packages/macro/src/macroJsx.ts
Expand Up @@ -157,16 +157,17 @@ export default class MacroJSX {
path.replaceWith(newNode)
}

attrName = (names, exclude = false) => {
const namesRe = new RegExp("^(" + names.join("|") + ")$")
return (attr) =>
exclude ? !namesRe.test(attr.name.name) : namesRe.test(attr.name.name)
}

stripMacroAttributes = (node) => {
const { attributes } = node.openingElement
const attrName = (names, exclude = false) => {
const namesRe = new RegExp("^(" + names.join("|") + ")$")
return (attr) =>
exclude ? !namesRe.test(attr.name.name) : namesRe.test(attr.name.name)
}
const id = attributes.filter(attrName([ID]))[0]
const message = attributes.filter(attrName([MESSAGE]))[0]
const comment = attributes.filter(attrName([COMMENT]))[0]
const id = attributes.filter(this.attrName([ID]))[0]
const message = attributes.filter(this.attrName([MESSAGE]))[0]
const comment = attributes.filter(this.attrName([COMMENT]))[0]

let reserved = [ID, MESSAGE, COMMENT]
if (this.isI18nComponent(node)) {
Expand All @@ -191,7 +192,7 @@ export default class MacroJSX {
id: maybeNodeValue(id),
message: maybeNodeValue(message),
comment: maybeNodeValue(comment),
attributes: attributes.filter(attrName(reserved, true)),
attributes: attributes.filter(this.attrName(reserved, true)),
}
}

Expand Down Expand Up @@ -227,10 +228,10 @@ export default class MacroJSX {
}
} else if (this.types.isTemplateLiteral(exp)) {
const tokenize = R.pipe(
// Don't output tokens without text.
// Don"t output tokens without text.
R.evolve({
quasis: R.map((text: babelTypes.TemplateElement) => {
// Don't output tokens without text.
// Don"t output tokens without text.
const value = text.value.raw
if (value === "") return null

Expand Down Expand Up @@ -268,7 +269,15 @@ export default class MacroJSX {
tokenizeChoiceComponent = (node) => {
const element = node.openingElement
const format = element.name.name.toLowerCase()
const props = element.attributes
const props = element.attributes.filter(this.attrName([
ID,
COMMENT,
MESSAGE,
// we remove <Trans /> react props that are not useful for translation
"render",
"component",
"components"
], true))

const token = {
type: "arg",
Expand All @@ -294,14 +303,18 @@ export default class MacroJSX {
token.options.offset = this.types.isStringLiteral(attr.value)
? attr.value.value
: attr.value.expression.value
} else if (pluralRuleRe.test(name)) {
} else {
let value
if (this.types.isStringLiteral(attr.value)) {
value = attr.value.extra.raw.replace(/(["'])(.*)\1/, "$2")
} else {
value = this.tokenizeChildren(attr.value)
}
token.options[jsx2icuExactChoice(name)] = value
if (pluralRuleRe.test(name)) {
token.options[jsx2icuExactChoice(name)] = value
} else {
token.options[name] = value
}
}
}

Expand Down Expand Up @@ -348,7 +361,7 @@ export default class MacroJSX {

/**
* We clean '//\` ' to just '`'
*/
* */
clearBackslashes(value: string){
return value.replace(removeExtraScapedLiterals, "`")
}
Expand Down

1 comment on commit 353c537

@vercel
Copy link

@vercel vercel bot commented on 353c537 Jan 26, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.