From 94d9c78cea317af2be6da3518a3e613066037dee Mon Sep 17 00:00:00 2001 From: Timofei Iatsenko Date: Mon, 8 Apr 2024 09:51:42 +0200 Subject: [PATCH 1/4] refactor(macro): use message descriptor for Trans --- .../babel-plugin-lingui-macro/src/macroJs.ts | 27 +---- .../babel-plugin-lingui-macro/src/macroJsx.ts | 97 +++------------ .../src/messageDescriptorUtils.ts | 112 ++++++++++++++++++ 3 files changed, 133 insertions(+), 103 deletions(-) create mode 100644 packages/babel-plugin-lingui-macro/src/messageDescriptorUtils.ts diff --git a/packages/babel-plugin-lingui-macro/src/macroJs.ts b/packages/babel-plugin-lingui-macro/src/macroJs.ts index 0a1980a2d..12dfe9341 100644 --- a/packages/babel-plugin-lingui-macro/src/macroJs.ts +++ b/packages/babel-plugin-lingui-macro/src/macroJs.ts @@ -32,6 +32,7 @@ import { MACRO_LEGACY_PACKAGE, } from "./constants" import { generateMessageId } from "@lingui/message-utils/generateMessageId" +import { createMessageDescriptorFromTokens } from "./messageDescriptorUtils" function buildICUFromTokens(tokens: Tokens) { const messageFormat = new ICUMessageFormat() @@ -76,7 +77,7 @@ export class MacroJs { linguiInstance?: babelTypes.Expression ) => { return this.createI18nCall( - this.createMessageDescriptorFromTokens(tokens, path.node.loc), + createMessageDescriptorFromTokens(tokens, path.node.loc), linguiInstance ) } @@ -102,7 +103,7 @@ export class MacroJs { this.isDefineMessage(path.get("tag")) ) { const tokens = this.tokenizeTemplateLiteral(path.get("quasi")) - return this.createMessageDescriptorFromTokens(tokens, path.node.loc) + return createMessageDescriptorFromTokens(tokens, path.node.loc) } if (path.isTaggedTemplateExpression()) { @@ -255,7 +256,7 @@ export class MacroJs { if (currentPath.isTaggedTemplateExpression()) { const tokens = this.tokenizeTemplateLiteral(currentPath) - const descriptor = this.createMessageDescriptorFromTokens( + const descriptor = createMessageDescriptorFromTokens( tokens, currentPath.node.loc ) @@ -543,26 +544,6 @@ export class MacroJs { ) } - createMessageDescriptorFromTokens(tokens: Tokens, oldLoc?: SourceLocation) { - const { message, values } = buildICUFromTokens(tokens) - - const properties: ObjectProperty[] = [ - this.createIdProperty(message), - - !this.stripNonEssentialProps - ? this.createObjectProperty(MESSAGE, this.types.stringLiteral(message)) - : null, - - this.createValuesProperty(values), - ] - - return this.createMessageDescriptor( - properties, - // preserve line numbers for extractor - oldLoc - ) - } - createMessageDescriptor( properties: ObjectProperty[], oldLoc?: SourceLocation diff --git a/packages/babel-plugin-lingui-macro/src/macroJsx.ts b/packages/babel-plugin-lingui-macro/src/macroJsx.ts index 1ab59d782..a86623bca 100644 --- a/packages/babel-plugin-lingui-macro/src/macroJsx.ts +++ b/packages/babel-plugin-lingui-macro/src/macroJsx.ts @@ -14,12 +14,7 @@ import { } from "@babel/types" import { NodePath } from "@babel/traverse" -import ICUMessageFormat, { - ArgToken, - ElementToken, - TextToken, - Token, -} from "./icu" +import { ArgToken, ElementToken, TextToken, Token } from "./icu" import { makeCounter } from "./utils" import { COMMENT, @@ -30,8 +25,11 @@ import { MACRO_REACT_PACKAGE, MACRO_LEGACY_PACKAGE, } from "./constants" -import { generateMessageId } from "@lingui/message-utils/generateMessageId" import cleanJSXElementLiteralChild from "./utils/cleanJSXElementLiteralChild" +import { + createMessageDescriptorFromTokens, + createStringObjectProperty, +} from "./messageDescriptorUtils" const pluralRuleRe = /(_[\d\w]+|zero|one|two|few|many|other)/ const jsx2icuExactChoice = (value: string) => @@ -87,87 +85,26 @@ export class MacroJSX { return false } - const messageFormat = new ICUMessageFormat() - const { message, values, jsxElements } = messageFormat.fromTokens(tokens) const { attributes, id, comment, context } = this.stripMacroAttributes( path as NodePath ) - if (!id && !message) { - throw new Error("Incorrect usage of Trans") - } - - if (id) { - attributes.push( - this.types.jsxAttribute( - this.types.jsxIdentifier(ID), - this.types.stringLiteral(id) - ) - ) - } else { - attributes.push( - this.createStringJsxAttribute(ID, generateMessageId(message, context)) - ) - } - - if (!this.stripNonEssentialProps) { - if (message) { - attributes.push(this.createStringJsxAttribute(MESSAGE, message)) - } - - if (comment) { - attributes.push( - this.types.jsxAttribute( - this.types.jsxIdentifier(COMMENT), - this.types.stringLiteral(comment) - ) - ) - } - - if (context) { - attributes.push( - this.types.jsxAttribute( - this.types.jsxIdentifier(CONTEXT), - this.types.stringLiteral(context) - ) - ) - } - } - - // Parameters for variable substitution - const valuesObject = Object.keys(values).map((key) => - this.types.objectProperty(this.types.identifier(key), values[key]) + const messageDescriptor = createMessageDescriptorFromTokens( + tokens, + path.node.loc, + { + id, + context, + comment, + }, + this.stripNonEssentialProps ) - if (valuesObject.length) { - attributes.push( - this.types.jsxAttribute( - this.types.jsxIdentifier("values"), - this.types.jsxExpressionContainer( - this.types.objectExpression(valuesObject) - ) - ) - ) + if (!id && !tokens) { + throw new Error("Incorrect usage of Trans") } - // Inline elements - if (Object.keys(jsxElements).length) { - attributes.push( - this.types.jsxAttribute( - this.types.jsxIdentifier("components"), - this.types.jsxExpressionContainer( - this.types.objectExpression( - Object.keys(jsxElements).map((key) => - this.types.objectProperty( - this.types.identifier(key), - jsxElements[key] - ) - ) - ) - ) - ) - ) - } + attributes.push(this.types.jsxSpreadAttribute(messageDescriptor)) const newNode = this.types.jsxElement( this.types.jsxOpeningElement( diff --git a/packages/babel-plugin-lingui-macro/src/messageDescriptorUtils.ts b/packages/babel-plugin-lingui-macro/src/messageDescriptorUtils.ts new file mode 100644 index 000000000..1eced8fa5 --- /dev/null +++ b/packages/babel-plugin-lingui-macro/src/messageDescriptorUtils.ts @@ -0,0 +1,112 @@ +import ICUMessageFormat, { Tokens, ParsedResult } from "./icu" +import { SourceLocation, ObjectProperty, ObjectExpression } from "@babel/types" +import { MESSAGE, ID, EXTRACT_MARK, COMMENT, CONTEXT } from "./constants" +import * as types from "@babel/types" +import { generateMessageId } from "@lingui/message-utils/generateMessageId" + +function buildICUFromTokens(tokens: Tokens) { + const messageFormat = new ICUMessageFormat() + return messageFormat.fromTokens(tokens) +} + +export function createMessageDescriptorFromTokens( + tokens: Tokens, + oldLoc?: SourceLocation, + defaults: { id?: string; context?: string; comment?: string } = {}, + stripNonEssentialProps = true +) { + const { message, values, jsxElements } = buildICUFromTokens(tokens) + + const properties: ObjectProperty[] = [] + + properties.push( + defaults.id + ? createStringObjectProperty(ID, defaults.id) + : createIdProperty(message, defaults.context) + ) + + if (!stripNonEssentialProps) { + properties.push(createStringObjectProperty(MESSAGE, message)) + + if (defaults.comment) { + properties.push(createStringObjectProperty(COMMENT, defaults.comment)) + } + + if (defaults.context) { + properties.push(createStringObjectProperty(CONTEXT, defaults.context)) + } + } + + properties.push(createValuesProperty(values)) + properties.push(createComponentsProperty(jsxElements)) + + return createMessageDescriptor( + properties, + // preserve line numbers for extractor + oldLoc + ) +} + +function createIdProperty(message: string, context?: string) { + return createStringObjectProperty(ID, generateMessageId(message, context)) +} + +function createValuesProperty(values: ParsedResult["values"]) { + const valuesObject = Object.keys(values).map((key) => + types.objectProperty(types.identifier(key), values[key]) + ) + + if (!valuesObject.length) return + + return types.objectProperty( + types.identifier("values"), + types.objectExpression(valuesObject) + ) +} + +function createComponentsProperty(values: ParsedResult["jsxElements"]) { + const valuesObject = Object.keys(values).map((key) => + types.objectProperty(types.identifier(key), values[key]) + ) + + if (!valuesObject.length) return + + return types.objectProperty( + types.identifier("components"), + types.objectExpression(valuesObject) + ) +} + +// if (Object.keys(jsxElements).length) { +// attributes.push( +// this.types.jsxAttribute( +// this.types.jsxIdentifier("components"), +// this.types.jsxExpressionContainer( +// this.types.objectExpression( +// Object.keys(jsxElements).map((key) => +// this.types.objectProperty( +// this.types.identifier(key), +// jsxElements[key] +// ) +// ) +// ) +// ) +// ) +// ) +// } +export function createStringObjectProperty(key: string, value: string) { + return types.objectProperty(types.identifier(key), types.stringLiteral(value)) +} + +function createMessageDescriptor( + properties: ObjectProperty[], + oldLoc?: SourceLocation +): ObjectExpression { + const newDescriptor = types.objectExpression(properties.filter(Boolean)) + types.addComment(newDescriptor, "leading", EXTRACT_MARK) + if (oldLoc) { + newDescriptor.loc = oldLoc + } + + return newDescriptor +} From 1e13834d5139b63c0b90ed4dd58deda25f741589 Mon Sep 17 00:00:00 2001 From: Timofei Iatsenko Date: Fri, 12 Apr 2024 11:58:43 +0200 Subject: [PATCH 2/4] update snapshots --- .../src/constants.ts | 2 + .../babel-plugin-lingui-macro/src/macroJs.ts | 174 +++--- .../babel-plugin-lingui-macro/src/macroJsx.ts | 16 +- .../src/messageDescriptorUtils.ts | 130 +++-- .../js-defineMessage.test.ts.snap | 26 +- .../test/__snapshots__/js-t.test.ts.snap | 38 +- .../__snapshots__/js-useLingui.test.ts.snap | 4 +- .../__snapshots__/jsx-plural.test.ts.snap | 174 +++--- .../__snapshots__/jsx-select.test.ts.snap | 83 +-- .../jsx-selectOrdinal.test.ts.snap | 66 ++- .../test/__snapshots__/jsx-trans.test.ts.snap | 504 +++++++++++++----- .../jsx-keep-forced-newlines.expected.js | 10 +- .../test/js-t.test.ts | 2 + .../test/jsx-trans.test.ts | 1 + 14 files changed, 778 insertions(+), 452 deletions(-) diff --git a/packages/babel-plugin-lingui-macro/src/constants.ts b/packages/babel-plugin-lingui-macro/src/constants.ts index e74209e98..fbb8b2059 100644 --- a/packages/babel-plugin-lingui-macro/src/constants.ts +++ b/packages/babel-plugin-lingui-macro/src/constants.ts @@ -1,6 +1,8 @@ export const ID = "id" export const MESSAGE = "message" export const COMMENT = "comment" +export const VALUES = "values" +export const COMPONENTS = "components" export const EXTRACT_MARK = "i18n" export const CONTEXT = "context" export const MACRO_LEGACY_PACKAGE = "@lingui/macro" diff --git a/packages/babel-plugin-lingui-macro/src/macroJs.ts b/packages/babel-plugin-lingui-macro/src/macroJs.ts index 12dfe9341..3c55f0bda 100644 --- a/packages/babel-plugin-lingui-macro/src/macroJs.ts +++ b/packages/babel-plugin-lingui-macro/src/macroJs.ts @@ -6,24 +6,16 @@ import { Node, ObjectExpression, ObjectProperty, - SourceLocation, StringLiteral, TemplateLiteral, } from "@babel/types" import { NodePath } from "@babel/traverse" -import ICUMessageFormat, { - ArgToken, - ParsedResult, - TextToken, - Token, - Tokens, -} from "./icu" +import { ArgToken, TextToken, Token, Tokens } from "./icu" import { makeCounter } from "./utils" import { COMMENT, CONTEXT, - EXTRACT_MARK, ID, MESSAGE, MACRO_CORE_PACKAGE, @@ -31,16 +23,8 @@ import { MACRO_REACT_PACKAGE, MACRO_LEGACY_PACKAGE, } from "./constants" -import { generateMessageId } from "@lingui/message-utils/generateMessageId" import { createMessageDescriptorFromTokens } from "./messageDescriptorUtils" -function buildICUFromTokens(tokens: Tokens) { - const messageFormat = new ICUMessageFormat() - const { message, values } = messageFormat.fromTokens(tokens) - - return { message, values } -} - export type MacroJsOpts = { i18nImportName: string useLinguiImportName: string @@ -77,7 +61,11 @@ export class MacroJs { linguiInstance?: babelTypes.Expression ) => { return this.createI18nCall( - createMessageDescriptorFromTokens(tokens, path.node.loc), + createMessageDescriptorFromTokens( + tokens, + path.node.loc, + this.stripNonEssentialProps + ), linguiInstance ) } @@ -103,7 +91,11 @@ export class MacroJs { this.isDefineMessage(path.get("tag")) ) { const tokens = this.tokenizeTemplateLiteral(path.get("quasi")) - return createMessageDescriptorFromTokens(tokens, path.node.loc) + return createMessageDescriptorFromTokens( + tokens, + path.node.loc, + this.stripNonEssentialProps + ) } if (path.isTaggedTemplateExpression()) { @@ -258,7 +250,8 @@ export class MacroJs { const descriptor = createMessageDescriptorFromTokens( tokens, - currentPath.node.loc + currentPath.node.loc, + this.stripNonEssentialProps ) const callExpr = this.types.callExpression( @@ -325,15 +318,17 @@ export class MacroJs { const contextProperty = this.getObjectPropertyByKey(descriptor, CONTEXT) const commentProperty = this.getObjectPropertyByKey(descriptor, COMMENT) - const properties: ObjectProperty[] = [] - - if (idProperty) { - properties.push(idProperty.node) - } + // const properties: ObjectProperty[] = [] + // + // if (idProperty) { + // properties.push(idProperty.node) + // } + // + // if (!this.stripNonEssentialProps && contextProperty) { + // properties.push(contextProperty.node) + // } - if (!this.stripNonEssentialProps && contextProperty) { - properties.push(contextProperty.node) - } + let tokens: Token[] = [] // if there's `message` property, replace macros with formatted message if (messageProperty) { @@ -341,61 +336,52 @@ export class MacroJs { // Template strings are always processed as if they were wrapped by `t`. const messageValue = messageProperty.get("value") - const tokens = messageValue.isTemplateLiteral() + tokens = messageValue.isTemplateLiteral() ? this.tokenizeTemplateLiteral(messageValue) : this.tokenizeNode(messageValue, true) - let messageNode = messageValue.node as StringLiteral - - if (tokens) { - const { message, values } = buildICUFromTokens(tokens) - messageNode = this.types.stringLiteral(message) + // let messageNode = messageValue.node as StringLiteral - properties.push(this.createValuesProperty(values)) - } - - if (!this.stripNonEssentialProps) { - properties.push( - this.createObjectProperty(MESSAGE, messageNode as Expression) - ) - } - - if (!idProperty && this.types.isStringLiteral(messageNode)) { - const context = - contextProperty && - this.getTextFromExpression( - contextProperty.get("value").node as Expression - ) - - properties.push(this.createIdProperty(messageNode.value, context)) - } - } - - if (!this.stripNonEssentialProps && commentProperty) { - properties.push(commentProperty.node) + // if (tokens) { + // const { message, values } = buildICUFromTokens(tokens) + // messageNode = this.types.stringLiteral(message) + // + // properties.push(this.createValuesProperty(values)) + // } + + // if (!this.stripNonEssentialProps) { + // properties.push( + // this.createObjectProperty(MESSAGE, messageNode as Expression) + // ) + // } + + // if (!idProperty && this.types.isStringLiteral(messageNode)) { + // const context = + // contextProperty && + // this.getTextFromExpression( + // contextProperty.get("value").node as Expression + // ) + // + // properties.push(this.createIdProperty(messageNode.value, context)) + // } } - return this.createMessageDescriptor(properties, descriptor.node.loc) - } - - createIdProperty(message: string, context?: string) { - return this.createObjectProperty( - ID, - this.types.stringLiteral(generateMessageId(message, context)) - ) - } - - createValuesProperty(values: ParsedResult["values"]) { - const valuesObject = Object.keys(values).map((key) => - this.types.objectProperty(this.types.identifier(key), values[key]) + return createMessageDescriptorFromTokens( + tokens, + descriptor.node.loc, + this.stripNonEssentialProps, + { + id: idProperty?.node, + context: contextProperty?.node, + comment: commentProperty?.node, + } ) - if (!valuesObject.length) return + // if (!this.stripNonEssentialProps && commentProperty) { + // properties.push(commentProperty.node) + // } - return this.types.objectProperty( - this.types.identifier("values"), - this.types.objectExpression(valuesObject) - ) + // return this.createMessageDescriptor(properties, descriptor.node.loc) } tokenizeNode(path: NodePath, ignoreExpression = false): Token[] { @@ -416,6 +402,15 @@ export class MacroJs { ), ] } + + if (path.isStringLiteral()) { + return [ + { + type: "text", + value: path.node.value, + } satisfies TextToken, + ] + } // if (isFormatMethod(node.callee)) { // // date, number // return transformFormatMethod(node, file, props, root) @@ -544,25 +539,6 @@ export class MacroJs { ) } - createMessageDescriptor( - properties: ObjectProperty[], - oldLoc?: SourceLocation - ): ObjectExpression { - const newDescriptor = this.types.objectExpression( - properties.filter(Boolean) - ) - this.types.addComment(newDescriptor, "leading", EXTRACT_MARK) - if (oldLoc) { - newDescriptor.loc = oldLoc - } - - return newDescriptor - } - - createObjectProperty(key: string, value: Expression) { - return this.types.objectProperty(this.types.identifier(key), value) - } - getObjectPropertyByKey( objectExp: NodePath, key: string @@ -637,16 +613,4 @@ export class MacroJs { return JsMacroName.selectOrdinal } } - - getTextFromExpression(exp: Expression): string { - if (this.types.isStringLiteral(exp)) { - return exp.value - } - - if (this.types.isTemplateLiteral(exp)) { - if (exp?.quasis.length === 1) { - return exp.quasis[0]?.value?.cooked - } - } - } } diff --git a/packages/babel-plugin-lingui-macro/src/macroJsx.ts b/packages/babel-plugin-lingui-macro/src/macroJsx.ts index a86623bca..61e4e1e58 100644 --- a/packages/babel-plugin-lingui-macro/src/macroJsx.ts +++ b/packages/babel-plugin-lingui-macro/src/macroJsx.ts @@ -11,6 +11,7 @@ import { Node, StringLiteral, TemplateLiteral, + SourceLocation, } from "@babel/types" import { NodePath } from "@babel/traverse" @@ -26,10 +27,7 @@ import { MACRO_LEGACY_PACKAGE, } from "./constants" import cleanJSXElementLiteralChild from "./utils/cleanJSXElementLiteralChild" -import { - createMessageDescriptorFromTokens, - createStringObjectProperty, -} from "./messageDescriptorUtils" +import { createMessageDescriptorFromTokens } from "./messageDescriptorUtils" const pluralRuleRe = /(_[\d\w]+|zero|one|two|few|many|other)/ const jsx2icuExactChoice = (value: string) => @@ -37,14 +35,14 @@ const jsx2icuExactChoice = (value: string) => type JSXChildPath = NodePath -function maybeNodeValue(node: Node): string { +function maybeNodeValue(node: Node): { text: string; loc: SourceLocation } { if (!node) return null - if (node.type === "StringLiteral") return node.value + if (node.type === "StringLiteral") return { text: node.value, loc: node.loc } if (node.type === "JSXAttribute") return maybeNodeValue(node.value) if (node.type === "JSXExpressionContainer") return maybeNodeValue(node.expression) if (node.type === "TemplateLiteral" && node.expressions.length === 0) - return node.quasis[0].value.raw + return { text: node.quasis[0].value.raw, loc: node.loc } return null } @@ -92,12 +90,12 @@ export class MacroJSX { const messageDescriptor = createMessageDescriptorFromTokens( tokens, path.node.loc, + this.stripNonEssentialProps, { id, context, comment, - }, - this.stripNonEssentialProps + } ) if (!id && !tokens) { diff --git a/packages/babel-plugin-lingui-macro/src/messageDescriptorUtils.ts b/packages/babel-plugin-lingui-macro/src/messageDescriptorUtils.ts index 1eced8fa5..b0715cbca 100644 --- a/packages/babel-plugin-lingui-macro/src/messageDescriptorUtils.ts +++ b/packages/babel-plugin-lingui-macro/src/messageDescriptorUtils.ts @@ -1,6 +1,20 @@ -import ICUMessageFormat, { Tokens, ParsedResult } from "./icu" -import { SourceLocation, ObjectProperty, ObjectExpression } from "@babel/types" -import { MESSAGE, ID, EXTRACT_MARK, COMMENT, CONTEXT } from "./constants" +import ICUMessageFormat, { Tokens } from "./icu" +import { + SourceLocation, + ObjectProperty, + ObjectExpression, + isObjectProperty, + Expression, +} from "@babel/types" +import { + MESSAGE, + ID, + EXTRACT_MARK, + COMMENT, + CONTEXT, + VALUES, + COMPONENTS, +} from "./constants" import * as types from "@babel/types" import { generateMessageId } from "@lingui/message-utils/generateMessageId" @@ -9,11 +23,20 @@ function buildICUFromTokens(tokens: Tokens) { return messageFormat.fromTokens(tokens) } +type TextWithLoc = { + text: string + loc?: SourceLocation +} + export function createMessageDescriptorFromTokens( tokens: Tokens, - oldLoc?: SourceLocation, - defaults: { id?: string; context?: string; comment?: string } = {}, - stripNonEssentialProps = true + oldLoc: SourceLocation, + stripNonEssentialProps: boolean, + defaults: { + id?: TextWithLoc | ObjectProperty + context?: TextWithLoc | ObjectProperty + comment?: TextWithLoc | ObjectProperty + } = {} ) { const { message, values, jsxElements } = buildICUFromTokens(tokens) @@ -21,24 +44,51 @@ export function createMessageDescriptorFromTokens( properties.push( defaults.id - ? createStringObjectProperty(ID, defaults.id) - : createIdProperty(message, defaults.context) + ? isObjectProperty(defaults.id) + ? defaults.id + : createStringObjectProperty(ID, defaults.id.text, defaults.id.loc) + : createIdProperty( + message, + defaults.context + ? isObjectProperty(defaults.context) + ? getTextFromExpression(defaults.context.value as Expression) + : defaults.context.text + : null + ) ) if (!stripNonEssentialProps) { - properties.push(createStringObjectProperty(MESSAGE, message)) + if (message) { + properties.push(createStringObjectProperty(MESSAGE, message)) + } if (defaults.comment) { - properties.push(createStringObjectProperty(COMMENT, defaults.comment)) + properties.push( + isObjectProperty(defaults.comment) + ? defaults.comment + : createStringObjectProperty( + COMMENT, + defaults.comment.text, + defaults.comment.loc + ) + ) } if (defaults.context) { - properties.push(createStringObjectProperty(CONTEXT, defaults.context)) + properties.push( + isObjectProperty(defaults.context) + ? defaults.context + : createStringObjectProperty( + CONTEXT, + defaults.context.text, + defaults.context.loc + ) + ) } } - properties.push(createValuesProperty(values)) - properties.push(createComponentsProperty(jsxElements)) + properties.push(createValuesProperty(VALUES, values)) + properties.push(createValuesProperty(COMPONENTS, jsxElements)) return createMessageDescriptor( properties, @@ -51,7 +101,7 @@ function createIdProperty(message: string, context?: string) { return createStringObjectProperty(ID, generateMessageId(message, context)) } -function createValuesProperty(values: ParsedResult["values"]) { +function createValuesProperty(key: string, values: Record) { const valuesObject = Object.keys(values).map((key) => types.objectProperty(types.identifier(key), values[key]) ) @@ -59,43 +109,37 @@ function createValuesProperty(values: ParsedResult["values"]) { if (!valuesObject.length) return return types.objectProperty( - types.identifier("values"), + types.identifier(key), types.objectExpression(valuesObject) ) } -function createComponentsProperty(values: ParsedResult["jsxElements"]) { - const valuesObject = Object.keys(values).map((key) => - types.objectProperty(types.identifier(key), values[key]) +export function createStringObjectProperty( + key: string, + value: string, + oldLoc?: SourceLocation +) { + const property = types.objectProperty( + types.identifier(key), + types.stringLiteral(value) ) + if (oldLoc) { + property.loc = oldLoc + } - if (!valuesObject.length) return - - return types.objectProperty( - types.identifier("components"), - types.objectExpression(valuesObject) - ) + return property } -// if (Object.keys(jsxElements).length) { -// attributes.push( -// this.types.jsxAttribute( -// this.types.jsxIdentifier("components"), -// this.types.jsxExpressionContainer( -// this.types.objectExpression( -// Object.keys(jsxElements).map((key) => -// this.types.objectProperty( -// this.types.identifier(key), -// jsxElements[key] -// ) -// ) -// ) -// ) -// ) -// ) -// } -export function createStringObjectProperty(key: string, value: string) { - return types.objectProperty(types.identifier(key), types.stringLiteral(value)) +function getTextFromExpression(exp: Expression): string { + if (types.isStringLiteral(exp)) { + return exp.value + } + + if (types.isTemplateLiteral(exp)) { + if (exp?.quasis.length === 1) { + return exp.quasis[0]?.value?.cooked + } + } } function createMessageDescriptor( diff --git a/packages/babel-plugin-lingui-macro/test/__snapshots__/js-defineMessage.test.ts.snap b/packages/babel-plugin-lingui-macro/test/__snapshots__/js-defineMessage.test.ts.snap index 7e2d1c419..414de0c8c 100644 --- a/packages/babel-plugin-lingui-macro/test/__snapshots__/js-defineMessage.test.ts.snap +++ b/packages/babel-plugin-lingui-macro/test/__snapshots__/js-defineMessage.test.ts.snap @@ -35,10 +35,10 @@ const msg = defineMessage({ const msg = /*i18n*/ { + id: "oT92lS", values: { name: name, }, - id: "oT92lS", }; `; @@ -59,8 +59,8 @@ const message1 = const message2 = /*i18n*/ { - message: "Message", id: "xDAtGP", + message: "Message", }; `; @@ -80,12 +80,12 @@ const message = defineMessage2({ const message = /*i18n*/ { + id: "SlmyxX", + message: "{value, plural, one {book} other {books}}", + comment: "Description", values: { value: value, }, - message: "{value, plural, one {book} other {books}}", - id: "SlmyxX", - comment: "Description", }; `; @@ -117,12 +117,12 @@ const message = defineMessage({ const message = /*i18n*/ { + id: "SlmyxX", + message: "{value, plural, one {book} other {books}}", + comment: "Description", values: { value: value, }, - message: "{value, plural, one {book} other {books}}", - id: "SlmyxX", - comment: "Description", }; `; @@ -138,8 +138,8 @@ const message = defineMessage({ const message = /*i18n*/ { - message: "Message", id: "xDAtGP", + message: "Message", }; `; @@ -173,11 +173,11 @@ const message = defineMessage({ const message = /*i18n*/ { + id: "OVaF9k", + message: "Hello {name}", values: { name: name, }, - message: "Hello {name}", - id: "OVaF9k", }; `; @@ -193,11 +193,11 @@ const message = defineMessage({ const message = /*i18n*/ { + id: "A2aVLF", + message: "Message {name}", values: { name: name, }, - message: "Message {name}", - id: "A2aVLF", }; `; diff --git a/packages/babel-plugin-lingui-macro/test/__snapshots__/js-t.test.ts.snap b/packages/babel-plugin-lingui-macro/test/__snapshots__/js-t.test.ts.snap index 84b1a27b4..5a0781f59 100644 --- a/packages/babel-plugin-lingui-macro/test/__snapshots__/js-t.test.ts.snap +++ b/packages/babel-plugin-lingui-macro/test/__snapshots__/js-t.test.ts.snap @@ -41,17 +41,17 @@ import { i18n as _i18n } from "@lingui/core"; _i18n._( /*i18n*/ { - context: "my custom", - message: "Hello", id: "BYqAaU", + message: "Hello", + context: "my custom", } ); _i18n._( /*i18n*/ { - context: \`my custom\`, - message: "Hello", id: "BYqAaU", + message: "Hello", + context: \`my custom\`, } ); @@ -68,8 +68,8 @@ const msg = message.error( _i18n._( /*i18n*/ { - message: "dasd", id: "9ZMZjU", + message: "dasd", } ) ); @@ -145,12 +145,12 @@ const msg = _i18n._( /*i18n*/ { id: "msgId", + message: "Hello {name}", + comment: "description for translators", context: "My Context", values: { name: name, }, - message: "Hello {name}", - comment: "description for translators", } ); @@ -256,16 +256,16 @@ import { i18n as _i18n } from "@lingui/core"; _i18n._( /*i18n*/ { - message: "Hello", id: "uzTaYi", + message: "Hello", } ); _i18n._( /*i18n*/ { - context: "my custom", - message: "Hello", id: "BYqAaU", + message: "Hello", + context: "my custom", } ); @@ -286,11 +286,11 @@ const msg = _i18n._( /*i18n*/ { id: "msgId", + message: "{val, plural, one {...} other {...}}", + comment: "description for translators", values: { val: val, }, - message: "{val, plural, one {...} other {...}}", - comment: "description for translators", } ); @@ -323,10 +323,10 @@ const msg = _i18n._( /*i18n*/ { id: "msgId", + message: "Some {value}", values: { value: value, }, - message: "Some {value}", } ); @@ -368,11 +368,11 @@ import { i18n as _i18n } from "@lingui/core"; const msg = _i18n._( /*i18n*/ { + id: "OVaF9k", + message: "Hello {name}", values: { name: name, }, - message: "Hello {name}", - id: "OVaF9k", } ); @@ -389,11 +389,11 @@ import { i18n } from "./lingui"; const msg = i18n._( /*i18n*/ { + id: "OVaF9k", + message: "Hello {name}", values: { name: name, }, - message: "Hello {name}", - id: "OVaF9k", } ); @@ -408,11 +408,11 @@ const msg = t(global.i18n)({ message: \`Hello \${name}\` }); const msg = global.i18n._( /*i18n*/ { + id: "OVaF9k", + message: "Hello {name}", values: { name: name, }, - message: "Hello {name}", - id: "OVaF9k", } ); diff --git a/packages/babel-plugin-lingui-macro/test/__snapshots__/js-useLingui.test.ts.snap b/packages/babel-plugin-lingui-macro/test/__snapshots__/js-useLingui.test.ts.snap index a4540ff99..3045b937e 100644 --- a/packages/babel-plugin-lingui-macro/test/__snapshots__/js-useLingui.test.ts.snap +++ b/packages/babel-plugin-lingui-macro/test/__snapshots__/js-useLingui.test.ts.snap @@ -123,9 +123,9 @@ function MyComponent() { const a = _t( /*i18n*/ { - context: "my custom", - message: "Hello", id: "BYqAaU", + message: "Hello", + context: "my custom", } ); } diff --git a/packages/babel-plugin-lingui-macro/test/__snapshots__/jsx-plural.test.ts.snap b/packages/babel-plugin-lingui-macro/test/__snapshots__/jsx-plural.test.ts.snap index 78ce0b0ed..920ba58e5 100644 --- a/packages/babel-plugin-lingui-macro/test/__snapshots__/jsx-plural.test.ts.snap +++ b/packages/babel-plugin-lingui-macro/test/__snapshots__/jsx-plural.test.ts.snap @@ -14,16 +14,20 @@ import { Plural } from "@lingui/react/macro"; import { Trans as _Trans } from "@lingui/react"; <_Trans - id={"tYX0sm"} - message={ - "{count, plural, offset:1 =0 {Zero items} few {{count} items} other {<0>A lot of them}}" + { + /*i18n*/ + ...{ + id: "tYX0sm", + message: + "{count, plural, offset:1 =0 {Zero items} few {{count} items} other {<0>A lot of them}}", + values: { + count: count, + }, + components: { + 0: , + }, + } } - values={{ - count: count, - }} - components={{ - 0: , - }} />; `; @@ -48,17 +52,21 @@ import { Trans, Plural } from "@lingui/react/macro"; import { Trans as _Trans } from "@lingui/react"; <_Trans - id={"X8eyr1"} - message={ - "{count, plural, one {<0># slot added} other {<1># slots added}}" + { + /*i18n*/ + ...{ + id: "X8eyr1", + message: + "{count, plural, one {<0># slot added} other {<1># slots added}}", + values: { + count: count, + }, + components: { + 0: , + 1: , + }, + } } - values={{ - count: count, - }} - components={{ - 0: , - 1: , - }} />; `; @@ -80,16 +88,20 @@ import { Plural } from "@lingui/react/macro"; import { Trans as _Trans } from "@lingui/react"; <_Trans render="strong" - id="msg.plural" - message={ - "{count, plural, offset:1 =0 {Zero items} few {{count} items} other {<0>A lot of them}}" + { + /*i18n*/ + ...{ + id: "msg.plural", + message: + "{count, plural, offset:1 =0 {Zero items} few {{count} items} other {<0>A lot of them}}", + values: { + count: count, + }, + components: { + 0: , + }, + } } - values={{ - count: count, - }} - components={{ - 0: , - }} />; `; @@ -111,18 +123,22 @@ import { Trans, Plural } from "@lingui/react/macro"; import { Trans as _Trans } from "@lingui/react"; <_Trans - id="inner-id-removed" - message={ - "Looking for {0, plural, offset:1 =0 {zero items} few {{1} items {2}} other {<0>a lot of them}}" + { + /*i18n*/ + ...{ + id: "inner-id-removed", + message: + "Looking for {0, plural, offset:1 =0 {zero items} few {{1} items {2}} other {<0>a lot of them}}", + values: { + 0: items.length, + 1: items.length, + 2: 42, + }, + components: { + 0: , + }, + } } - values={{ - 0: items.length, - 1: items.length, - 2: 42, - }} - components={{ - 0: , - }} />; `; @@ -140,17 +156,21 @@ import { Plural } from "@lingui/react/macro"; import { Trans as _Trans } from "@lingui/react"; <_Trans - id={"EQvNfC"} - message={ - "{count, plural, =0 {Zero items} one {{oneText}} other {<0>A lot of them}}" + { + /*i18n*/ + ...{ + id: "EQvNfC", + message: + "{count, plural, =0 {Zero items} one {{oneText}} other {<0>A lot of them}}", + values: { + count: count, + oneText: oneText, + }, + components: { + 0: , + }, + } } - values={{ - count: count, - oneText: oneText, - }} - components={{ - 0: , - }} />; `; @@ -163,11 +183,16 @@ import { Plural as Plural2 } from "@lingui/react/macro"; import { Trans as _Trans } from "@lingui/react"; <_Trans - id={"EMgKyP"} - message={"{count, plural, one {...} other {...}}"} - values={{ - count: count, - }} + { + /*i18n*/ + ...{ + id: "EMgKyP", + message: "{count, plural, one {...} other {...}}", + values: { + count: count, + }, + } + } />; `; @@ -191,18 +216,22 @@ import { Plural } from "@lingui/react/macro"; import { Trans as _Trans } from "@lingui/react"; <_Trans render={() => {}} - id="custom.id" - message={ - "{count, plural, offset:1 =0 {Zero items} few {{count} items} other {<0>A lot of them}}" + { + /*i18n*/ + ...{ + id: "custom.id", + message: + "{count, plural, offset:1 =0 {Zero items} few {{count} items} other {<0>A lot of them}}", + comment: "Comment for translator", + context: "translation context", + values: { + count: count, + }, + components: { + 0: , + }, + } } - comment="Comment for translator" - context="translation context" - values={{ - count: count, - }} - components={{ - 0: , - }} />; `; @@ -219,11 +248,16 @@ import { Trans, Plural } from "@lingui/react/macro"; import { Trans as _Trans } from "@lingui/react"; <_Trans - id={"oukcm6"} - message={"{count, plural, one {One hello} other {Other hello}}"} - values={{ - count: count, - }} + { + /*i18n*/ + ...{ + id: "oukcm6", + message: "{count, plural, one {One hello} other {Other hello}}", + values: { + count: count, + }, + } + } />; `; diff --git a/packages/babel-plugin-lingui-macro/test/__snapshots__/jsx-select.test.ts.snap b/packages/babel-plugin-lingui-macro/test/__snapshots__/jsx-select.test.ts.snap index b1e47e5c9..de204cabc 100644 --- a/packages/babel-plugin-lingui-macro/test/__snapshots__/jsx-select.test.ts.snap +++ b/packages/babel-plugin-lingui-macro/test/__snapshots__/jsx-select.test.ts.snap @@ -13,14 +13,19 @@ import { Select } from "@lingui/react/macro"; import { Trans as _Trans } from "@lingui/react"; <_Trans - id={"Imwef9"} - message={"{count, select, male {He} female {She} other {<0>Other}}"} - values={{ - count: count, - }} - components={{ - 0: , - }} + { + /*i18n*/ + ...{ + id: "Imwef9", + message: "{count, select, male {He} female {She} other {<0>Other}}", + values: { + count: count, + }, + components: { + 0: , + }, + } + } />; `; @@ -41,14 +46,19 @@ import { Select } from "@lingui/react/macro"; import { Trans as _Trans } from "@lingui/react"; <_Trans render="strong" - id="msg.select" - message={"{0, select, male {He} female {She} other {<0>Other}}"} - values={{ - 0: user.gender, - }} - components={{ - 0: , - }} + { + /*i18n*/ + ...{ + id: "msg.select", + message: "{0, select, male {He} female {She} other {<0>Other}}", + values: { + 0: user.gender, + }, + components: { + 0: , + }, + } + } />; `; @@ -69,12 +79,17 @@ import { Select } from "@lingui/react/macro"; import { Trans as _Trans } from "@lingui/react"; <_Trans render="strong" - id="msg.select" - message={"{0, select, male {He} female {She} other {{otherText}}}"} - values={{ - 0: user.gender, - otherText: otherText, - }} + { + /*i18n*/ + ...{ + id: "msg.select", + message: "{0, select, male {He} female {She} other {{otherText}}}", + values: { + 0: user.gender, + otherText: otherText, + }, + } + } />; `; @@ -100,15 +115,21 @@ import { Select, Trans } from "@lingui/react/macro"; import { Trans as _Trans } from "@lingui/react"; <_Trans - id={"f1ZLwG"} - message={"{0, select, happy {Hooray! <0/>} sad {Oh no! <1/>} other {Dunno}}"} - values={{ - 0: "happy", - }} - components={{ - 0: , - 1: , - }} + { + /*i18n*/ + ...{ + id: "f1ZLwG", + message: + "{0, select, happy {Hooray! <0/>} sad {Oh no! <1/>} other {Dunno}}", + values: { + 0: "happy", + }, + components: { + 0: , + 1: , + }, + } + } />; `; diff --git a/packages/babel-plugin-lingui-macro/test/__snapshots__/jsx-selectOrdinal.test.ts.snap b/packages/babel-plugin-lingui-macro/test/__snapshots__/jsx-selectOrdinal.test.ts.snap index 9ab615e8a..9617b9c32 100644 --- a/packages/babel-plugin-lingui-macro/test/__snapshots__/jsx-selectOrdinal.test.ts.snap +++ b/packages/babel-plugin-lingui-macro/test/__snapshots__/jsx-selectOrdinal.test.ts.snap @@ -17,16 +17,20 @@ import { Trans, SelectOrdinal } from "@lingui/react/macro"; import { Trans as _Trans } from "@lingui/react"; <_Trans - id={"3YEV8L"} - message={ - "This is my {count, selectordinal, one {#st} two {#nd} other {<0>#rd}} cat." + { + /*i18n*/ + ...{ + id: "3YEV8L", + message: + "This is my {count, selectordinal, one {#st} two {#nd} other {<0>#rd}} cat.", + values: { + count: count, + }, + components: { + 0: , + }, + } } - values={{ - count: count, - }} - components={{ - 0: , - }} />; `; @@ -48,16 +52,20 @@ import { Trans, SelectOrdinal } from "@lingui/react/macro"; import { Trans as _Trans } from "@lingui/react"; <_Trans - id={"Dz3XK1"} - message={ - "This is my{count, selectordinal, one {#st} two {#nd} other {<0>#rd}} cat." + { + /*i18n*/ + ...{ + id: "Dz3XK1", + message: + "This is my{count, selectordinal, one {#st} two {#nd} other {<0>#rd}} cat.", + values: { + count: count, + }, + components: { + 0: , + }, + } } - values={{ - count: count, - }} - components={{ - 0: , - }} />; `; @@ -79,16 +87,20 @@ import { Trans, SelectOrdinal } from "@lingui/react/macro"; import { Trans as _Trans } from "@lingui/react"; <_Trans - id={"CDpzE+"} - message={ - "This is my {0, selectordinal, one {#st} two {#nd} other {<0>#rd}} cat." + { + /*i18n*/ + ...{ + id: "CDpzE+", + message: + "This is my {0, selectordinal, one {#st} two {#nd} other {<0>#rd}} cat.", + values: { + 0: user.numCats, + }, + components: { + 0: , + }, + } } - values={{ - 0: user.numCats, - }} - components={{ - 0: , - }} />; `; diff --git a/packages/babel-plugin-lingui-macro/test/__snapshots__/jsx-trans.test.ts.snap b/packages/babel-plugin-lingui-macro/test/__snapshots__/jsx-trans.test.ts.snap index e536169c9..8edb94936 100644 --- a/packages/babel-plugin-lingui-macro/test/__snapshots__/jsx-trans.test.ts.snap +++ b/packages/babel-plugin-lingui-macro/test/__snapshots__/jsx-trans.test.ts.snap @@ -18,18 +18,23 @@ import { Trans } from "@lingui/react/macro"; import { Trans as _Trans } from "@lingui/react"; <_Trans - id={"k9gsHO"} - message={"Hello <0>World!<1/><2>My name is <3> <4>{name}"} - values={{ - name: name, - }} - components={{ - 0: , - 1:
, - 2:

, - 3: , - 4: , - }} + { + /*i18n*/ + ...{ + id: "k9gsHO", + message: "Hello <0>World!<1/><2>My name is <3> <4>{name}", + values: { + name: name, + }, + components: { + 0: , + 1:
, + 2:

, + 3: , + 4: , + }, + } + } />; `; @@ -42,11 +47,16 @@ import { Trans } from "@lingui/react/macro"; import { Trans as _Trans } from "@lingui/react"; <_Trans - id={"1cZQQW"} - message={"<0>Component inside expression container"} - components={{ - 0: , - }} + { + /*i18n*/ + ...{ + id: "1cZQQW", + message: "<0>Component inside expression container", + components: { + 0: , + }, + } + } />; `; @@ -59,11 +69,16 @@ import { Trans } from "@lingui/react/macro"; import { Trans as _Trans } from "@lingui/react"; <_Trans - id={"SCJtqt"} - message={"<0/>"} - components={{ - 0:
, - }} + { + /*i18n*/ + ...{ + id: "SCJtqt", + message: "<0/>", + components: { + 0:
, + }, + } + } />; `; @@ -79,18 +94,22 @@ import { Trans } from "@lingui/react/macro"; import { Trans as _Trans } from "@lingui/react"; <_Trans - id={"HjKDmx"} - message={ - "Property {0}, function {1}, array {2}, constant {3}, object {4}, everything {5}" + { + /*i18n*/ + ...{ + id: "HjKDmx", + message: + "Property {0}, function {1}, array {2}, constant {3}, object {4}, everything {5}", + values: { + 0: props.name, + 1: random(), + 2: array[index], + 3: 42, + 4: new Date(), + 5: props.messages[index].value(), + }, + } } - values={{ - 0: props.name, - 1: random(), - 2: array[index], - 3: 42, - 4: new Date(), - 5: props.messages[index].value(), - }} />; `; @@ -102,7 +121,15 @@ import { Trans } from "@lingui/react/macro"; ↓ ↓ ↓ ↓ ↓ ↓ import { Trans as _Trans } from "@lingui/react"; -<_Trans id={"mY42CM"} message={"Hello World"} />; +<_Trans + { + /*i18n*/ + ...{ + id: "mY42CM", + message: "Hello World", + } + } +/>; `; @@ -114,8 +141,25 @@ import { Trans } from "@lingui/react/macro"; ↓ ↓ ↓ ↓ ↓ ↓ import { Trans as _Trans } from "@lingui/react"; -<_Trans id={"mY42CM"} message={"Hello World"} />; -<_Trans id={"SO/WB8"} message={"Hello World"} context="my context" />; +<_Trans + { + /*i18n*/ + ...{ + id: "mY42CM", + message: "Hello World", + } + } +/>; +<_Trans + { + /*i18n*/ + ...{ + id: "SO/WB8", + message: "Hello World", + context: "my context", + } + } +/>; `; @@ -129,11 +173,16 @@ import { Trans } from "@lingui/react/macro"; import { Trans as _Trans } from "@lingui/react"; <_Trans - id={"K/1Xpr"} - message={"<0>This should work \\xA0"} - components={{ - 0: , - }} + { + /*i18n*/ + ...{ + id: "K/1Xpr", + message: "<0>This should work \\xA0", + components: { + 0: , + }, + } + } />; `; @@ -145,7 +194,15 @@ import { Trans } from "@lingui/react/macro"; ↓ ↓ ↓ ↓ ↓ ↓ import { Trans as _Trans } from "@lingui/react"; -<_Trans id={"i0M2R8"} message={"Hello World"} />; +<_Trans + { + /*i18n*/ + ...{ + id: "i0M2R8", + message: "Hello World", + } + } +/>; `; @@ -159,15 +216,36 @@ import { Trans } from "@lingui/react/macro"; import { Trans as _Trans } from "@lingui/react"; <_Trans - id={"UT5PlM"} - message={"Hello, {0}"} - values={{ - 0: props.world ? ( - <_Trans id={"ELi2P3"} message={"world"} /> - ) : ( - <_Trans id={"39nd+2"} message={"guys"} /> - ), - }} + { + /*i18n*/ + ...{ + id: "UT5PlM", + message: "Hello, {0}", + values: { + 0: props.world ? ( + <_Trans + { + /*i18n*/ + ...{ + id: "ELi2P3", + message: "world", + } + } + /> + ) : ( + <_Trans + { + /*i18n*/ + ...{ + id: "39nd+2", + message: "guys", + } + } + /> + ), + }, + } + } />; `; @@ -189,17 +267,46 @@ import { Trans } from "@lingui/react/macro"; import { Trans as _Trans } from "@lingui/react"; <_Trans - id={"UT5PlM"} - message={"Hello, {0}"} - values={{ - 0: props.world ? ( - <_Trans id={"ELi2P3"} message={"world"} /> - ) : props.b ? ( - <_Trans id={"lV+268"} message={"nested"} /> - ) : ( - <_Trans id={"39nd+2"} message={"guys"} /> - ), - }} + { + /*i18n*/ + ...{ + id: "UT5PlM", + message: "Hello, {0}", + values: { + 0: props.world ? ( + <_Trans + { + /*i18n*/ + ...{ + id: "ELi2P3", + message: "world", + } + } + /> + ) : props.b ? ( + <_Trans + { + /*i18n*/ + ...{ + id: "lV+268", + message: "nested", + } + } + /> + ) : ( + <_Trans + { + /*i18n*/ + ...{ + id: "39nd+2", + message: "guys", + } + } + /> + ), + }, + } + } />; `; @@ -211,7 +318,15 @@ import { Trans } from "@lingui/react/macro"; ↓ ↓ ↓ ↓ ↓ ↓ import { Trans as _Trans } from "@lingui/react"; -<_Trans id="msg.hello" message={"Hello World"} />; +<_Trans + { + /*i18n*/ + ...{ + id: "msg.hello", + message: "Hello World", + } + } +/>; `; @@ -222,7 +337,15 @@ import { Trans } from "@lingui/react/macro"; ↓ ↓ ↓ ↓ ↓ ↓ import { Trans as _Trans } from "@lingui/react"; -<_Trans id="msg.hello" message={"Hello World"} />; +<_Trans + { + /*i18n*/ + ...{ + id: "msg.hello", + message: "Hello World", + } + } +/>; `; @@ -233,7 +356,15 @@ import { Trans } from "@lingui/react/macro"; ↓ ↓ ↓ ↓ ↓ ↓ import { Trans as _Trans } from "@lingui/react"; -<_Trans id="msg.hello" message={"Hello World"} />; +<_Trans + { + /*i18n*/ + ...{ + id: "msg.hello", + message: "Hello World", + } + } +/>; `; @@ -246,7 +377,16 @@ import { Trans } from "@lingui/react/macro"; ↓ ↓ ↓ ↓ ↓ ↓ import { Trans as _Trans } from "@lingui/react"; -<_Trans id="msg.hello" message={"Hello World"} comment="Hello World" />; +<_Trans + { + /*i18n*/ + ...{ + id: "msg.hello", + message: "Hello World", + comment: "Hello World", + } + } +/>; `; @@ -260,7 +400,14 @@ import { Trans } from "@lingui/react/macro"; ↓ ↓ ↓ ↓ ↓ ↓ import { Trans as _Trans } from "@lingui/react"; -<_Trans id="msg.hello" />; +<_Trans + { + /*i18n*/ + ...{ + id: "msg.hello", + } + } +/>; `; @@ -273,7 +420,14 @@ import { Trans } from "@lingui/react/macro"; ↓ ↓ ↓ ↓ ↓ ↓ import { Trans as _Trans } from "@lingui/react"; -<_Trans id="msg.hello" />; +<_Trans + { + /*i18n*/ + ...{ + id: "msg.hello", + } + } +/>; `; @@ -285,8 +439,24 @@ import { Trans } from "@lingui/react/macro"; ↓ ↓ ↓ ↓ ↓ ↓ import { Trans as _Trans } from "@lingui/react"; -<_Trans id={"NWmRwM"} message={'Speak "friend"!'} />; -<_Trans id="custom-id" message={'Speak "friend"!'} />; +<_Trans + { + /*i18n*/ + ...{ + id: "NWmRwM", + message: 'Speak "friend"!', + } + } +/>; +<_Trans + { + /*i18n*/ + ...{ + id: "custom-id", + message: 'Speak "friend"!', + } + } +/>; `; @@ -298,7 +468,17 @@ const cmp = Hello; ↓ ↓ ↓ ↓ ↓ ↓ import { Trans as _Trans } from "@lingui/react"; -const cmp = <_Trans id={"uzTaYi"} message={"Hello"} />; +const cmp = ( + <_Trans + { + /*i18n*/ + ...{ + id: "uzTaYi", + message: "Hello", + } + } + /> +); `; @@ -318,10 +498,15 @@ import { Trans } from "@lingui/react/macro"; import { Trans as _Trans } from "@lingui/react"; <_Trans render={() => {}} - id="custom.id" - message={"Hello World"} - comment="Comment for translator" - context="translation context" + { + /*i18n*/ + ...{ + id: "custom.id", + message: "Hello World", + comment: "Comment for translator", + context: "translation context", + } + } />; `; @@ -334,8 +519,13 @@ import { Trans } from "@lingui/react/macro"; import { Trans as _Trans } from "@lingui/react"; <_Trans - id={"U8dd/d"} - message={"hello {count, plural, one {world} other {worlds}}"} + { + /*i18n*/ + ...{ + id: "U8dd/d", + message: "hello {count, plural, one {world} other {worlds}}", + } + } />; `; @@ -348,11 +538,16 @@ import { Trans } from "@lingui/react/macro"; import { Trans as _Trans } from "@lingui/react"; <_Trans - id={"tRMgLt"} - message={"Strip whitespace around arguments: '{name}'"} - values={{ - name: name, - }} + { + /*i18n*/ + ...{ + id: "tRMgLt", + message: "Strip whitespace around arguments: '{name}'", + values: { + name: name, + }, + } + } />; `; @@ -367,11 +562,16 @@ import { Trans } from "@lingui/react/macro"; import { Trans as _Trans } from "@lingui/react"; <_Trans - id={"Ud4KOf"} - message={"Strip whitespace around tags, but keep <0>forced spaces!"} - components={{ - 0: , - }} + { + /*i18n*/ + ...{ + id: "Ud4KOf", + message: "Strip whitespace around tags, but keep <0>forced spaces!", + components: { + 0: , + }, + } + } />; `; @@ -390,14 +590,18 @@ import { Trans } from "@lingui/react/macro"; import { Trans as _Trans } from "@lingui/react"; <_Trans - id={"3YVd0H"} - message={ - "Wonderful framework <0>Next.js say hi. And <1>Next.js say hi." + { + /*i18n*/ + ...{ + id: "3YVd0H", + message: + "Wonderful framework <0>Next.js say hi. And <1>Next.js say hi.", + components: { + 0:
, + 1: , + }, + } } - components={{ - 0: , - 1: , - }} />; `; @@ -410,12 +614,17 @@ import { Trans } from "@lingui/react/macro"; import { Trans as _Trans } from "@lingui/react"; <_Trans - id={"exe3kM"} - message={"How much is {expression}? {count}"} - values={{ - expression: expression, - count: count, - }} + { + /*i18n*/ + ...{ + id: "exe3kM", + message: "How much is {expression}? {count}", + values: { + expression: expression, + count: count, + }, + } + } />; `; @@ -427,7 +636,15 @@ import { Trans as Trans2 } from "@lingui/react/macro"; ↓ ↓ ↓ ↓ ↓ ↓ import { Trans as _Trans } from "@lingui/react"; -<_Trans id={"mY42CM"} message={"Hello World"} />; +<_Trans + { + /*i18n*/ + ...{ + id: "mY42CM", + message: "Hello World", + } + } +/>; `; @@ -446,25 +663,30 @@ import { t } from "@lingui/core/macro"; import { i18n as _i18n } from "@lingui/core"; import { Trans as _Trans } from "@lingui/react"; <_Trans - id={"QZyANg"} - message={"Read <0>more"} - components={{ - 0: ( - - ), - }} + { + /*i18n*/ + ...{ + id: "QZyANg", + message: "Read <0>more", + components: { + 0: ( + + ), + }, + } + } />; `; @@ -509,7 +731,15 @@ import { Trans } from "@lingui/react/macro"; ↓ ↓ ↓ ↓ ↓ ↓ import { Trans as _Trans } from "@lingui/react"; -<_Trans id={"EwTON7"} message={"&"} />; +<_Trans + { + /*i18n*/ + ...{ + id: "EwTON7", + message: "&", + } + } +/>; `; @@ -523,12 +753,17 @@ import { Trans } from "@lingui/react/macro"; import { Trans as _Trans } from "@lingui/react"; <_Trans - id={"y10VRI"} - message={"Hi {yourName}, my name is {myName}"} - values={{ - yourName: yourName, - myName: myName, - }} + { + /*i18n*/ + ...{ + id: "y10VRI", + message: "Hi {yourName}, my name is {myName}", + values: { + yourName: yourName, + myName: myName, + }, + } + } />; `; @@ -543,11 +778,16 @@ import { Trans } from "@lingui/react/macro"; import { Trans as _Trans } from "@lingui/react"; <_Trans - id={"+nhkwg"} - message={"{duplicate} variable {duplicate}"} - values={{ - duplicate: duplicate, - }} + { + /*i18n*/ + ...{ + id: "+nhkwg", + message: "{duplicate} variable {duplicate}", + values: { + duplicate: duplicate, + }, + } + } />; `; diff --git a/packages/babel-plugin-lingui-macro/test/fixtures/jsx-keep-forced-newlines.expected.js b/packages/babel-plugin-lingui-macro/test/fixtures/jsx-keep-forced-newlines.expected.js index 4bf775382..b6df26f95 100644 --- a/packages/babel-plugin-lingui-macro/test/fixtures/jsx-keep-forced-newlines.expected.js +++ b/packages/babel-plugin-lingui-macro/test/fixtures/jsx-keep-forced-newlines.expected.js @@ -1,2 +1,10 @@ import { Trans as _Trans } from "@lingui/react" -;<_Trans id={"9xE5pD"} message={"Keep multiple\nforced\nnewlines!"} /> +;<_Trans + { + /*i18n*/ + ...{ + id: "9xE5pD", + message: "Keep multiple\nforced\nnewlines!", + } + } +/> diff --git a/packages/babel-plugin-lingui-macro/test/js-t.test.ts b/packages/babel-plugin-lingui-macro/test/js-t.test.ts index 9aee0a771..131b971c7 100644 --- a/packages/babel-plugin-lingui-macro/test/js-t.test.ts +++ b/packages/babel-plugin-lingui-macro/test/js-t.test.ts @@ -1,5 +1,7 @@ import { macroTester } from "./macroTester" +describe.skip("", () => {}) + macroTester({ cases: [ { diff --git a/packages/babel-plugin-lingui-macro/test/jsx-trans.test.ts b/packages/babel-plugin-lingui-macro/test/jsx-trans.test.ts index f8f3dcb15..a7289481b 100644 --- a/packages/babel-plugin-lingui-macro/test/jsx-trans.test.ts +++ b/packages/babel-plugin-lingui-macro/test/jsx-trans.test.ts @@ -1,4 +1,5 @@ import { macroTester } from "./macroTester" +describe.skip("", () => {}) macroTester({ cases: [ From 700aa2c5d3f5dd3eb7f093344605e75299f84a0d Mon Sep 17 00:00:00 2001 From: Timofei Iatsenko Date: Fri, 12 Apr 2024 12:06:20 +0200 Subject: [PATCH 3/4] introduce MsgDescriptorPropKey enum --- .../src/constants.ts | 15 +++-- .../babel-plugin-lingui-macro/src/macroJs.ts | 60 ++++++------------- .../babel-plugin-lingui-macro/src/macroJsx.ts | 34 +++++++---- .../src/messageDescriptorUtils.ts | 35 ++++++----- 4 files changed, 66 insertions(+), 78 deletions(-) diff --git a/packages/babel-plugin-lingui-macro/src/constants.ts b/packages/babel-plugin-lingui-macro/src/constants.ts index fbb8b2059..91b528aa7 100644 --- a/packages/babel-plugin-lingui-macro/src/constants.ts +++ b/packages/babel-plugin-lingui-macro/src/constants.ts @@ -1,14 +1,17 @@ -export const ID = "id" -export const MESSAGE = "message" -export const COMMENT = "comment" -export const VALUES = "values" -export const COMPONENTS = "components" export const EXTRACT_MARK = "i18n" -export const CONTEXT = "context" export const MACRO_LEGACY_PACKAGE = "@lingui/macro" export const MACRO_CORE_PACKAGE = "@lingui/core/macro" export const MACRO_REACT_PACKAGE = "@lingui/react/macro" +export enum MsgDescriptorPropKey { + id = "id", + message = "message", + comment = "comment", + values = "values", + components = "components", + context = "context", +} + export enum JsMacroName { t = "t", plural = "plural", diff --git a/packages/babel-plugin-lingui-macro/src/macroJs.ts b/packages/babel-plugin-lingui-macro/src/macroJs.ts index 3c55f0bda..aa4757b97 100644 --- a/packages/babel-plugin-lingui-macro/src/macroJs.ts +++ b/packages/babel-plugin-lingui-macro/src/macroJs.ts @@ -14,14 +14,11 @@ import { NodePath } from "@babel/traverse" import { ArgToken, TextToken, Token, Tokens } from "./icu" import { makeCounter } from "./utils" import { - COMMENT, - CONTEXT, - ID, - MESSAGE, MACRO_CORE_PACKAGE, JsMacroName, MACRO_REACT_PACKAGE, MACRO_LEGACY_PACKAGE, + MsgDescriptorPropKey, } from "./constants" import { createMessageDescriptorFromTokens } from "./messageDescriptorUtils" @@ -313,20 +310,22 @@ export class MacroJs { * */ processDescriptor = (descriptor: NodePath) => { - const messageProperty = this.getObjectPropertyByKey(descriptor, MESSAGE) - const idProperty = this.getObjectPropertyByKey(descriptor, ID) - const contextProperty = this.getObjectPropertyByKey(descriptor, CONTEXT) - const commentProperty = this.getObjectPropertyByKey(descriptor, COMMENT) - - // const properties: ObjectProperty[] = [] - // - // if (idProperty) { - // properties.push(idProperty.node) - // } - // - // if (!this.stripNonEssentialProps && contextProperty) { - // properties.push(contextProperty.node) - // } + const messageProperty = this.getObjectPropertyByKey( + descriptor, + MsgDescriptorPropKey.message + ) + const idProperty = this.getObjectPropertyByKey( + descriptor, + MsgDescriptorPropKey.id + ) + const contextProperty = this.getObjectPropertyByKey( + descriptor, + MsgDescriptorPropKey.context + ) + const commentProperty = this.getObjectPropertyByKey( + descriptor, + MsgDescriptorPropKey.comment + ) let tokens: Token[] = [] @@ -339,31 +338,6 @@ export class MacroJs { tokens = messageValue.isTemplateLiteral() ? this.tokenizeTemplateLiteral(messageValue) : this.tokenizeNode(messageValue, true) - - // let messageNode = messageValue.node as StringLiteral - - // if (tokens) { - // const { message, values } = buildICUFromTokens(tokens) - // messageNode = this.types.stringLiteral(message) - // - // properties.push(this.createValuesProperty(values)) - // } - - // if (!this.stripNonEssentialProps) { - // properties.push( - // this.createObjectProperty(MESSAGE, messageNode as Expression) - // ) - // } - - // if (!idProperty && this.types.isStringLiteral(messageNode)) { - // const context = - // contextProperty && - // this.getTextFromExpression( - // contextProperty.get("value").node as Expression - // ) - // - // properties.push(this.createIdProperty(messageNode.value, context)) - // } } return createMessageDescriptorFromTokens( diff --git a/packages/babel-plugin-lingui-macro/src/macroJsx.ts b/packages/babel-plugin-lingui-macro/src/macroJsx.ts index 61e4e1e58..42f39c24c 100644 --- a/packages/babel-plugin-lingui-macro/src/macroJsx.ts +++ b/packages/babel-plugin-lingui-macro/src/macroJsx.ts @@ -18,13 +18,10 @@ import { NodePath } from "@babel/traverse" import { ArgToken, ElementToken, TextToken, Token } from "./icu" import { makeCounter } from "./utils" import { - COMMENT, - CONTEXT, - ID, - MESSAGE, JsxMacroName, MACRO_REACT_PACKAGE, MACRO_LEGACY_PACKAGE, + MsgDescriptorPropKey, } from "./constants" import cleanJSXElementLiteralChild from "./utils/cleanJSXElementLiteralChild" import { createMessageDescriptorFromTokens } from "./messageDescriptorUtils" @@ -129,12 +126,23 @@ export class MacroJSX { stripMacroAttributes = (path: NodePath) => { const { attributes } = path.node.openingElement - const id = attributes.find(this.attrName([ID])) - const message = attributes.find(this.attrName([MESSAGE])) - const comment = attributes.find(this.attrName([COMMENT])) - const context = attributes.find(this.attrName([CONTEXT])) + const id = attributes.find(this.attrName([MsgDescriptorPropKey.id])) + const message = attributes.find( + this.attrName([MsgDescriptorPropKey.message]) + ) + const comment = attributes.find( + this.attrName([MsgDescriptorPropKey.comment]) + ) + const context = attributes.find( + this.attrName([MsgDescriptorPropKey.context]) + ) - let reserved = [ID, MESSAGE, COMMENT, CONTEXT] + let reserved: string[] = [ + MsgDescriptorPropKey.id, + MsgDescriptorPropKey.message, + MsgDescriptorPropKey.comment, + MsgDescriptorPropKey.context, + ] if (this.isChoiceComponent(path)) { reserved = [ @@ -258,10 +266,10 @@ export class MacroJSX { const props = element.get("attributes").filter((attr) => { return this.attrName( [ - ID, - COMMENT, - MESSAGE, - CONTEXT, + MsgDescriptorPropKey.id, + MsgDescriptorPropKey.comment, + MsgDescriptorPropKey.message, + MsgDescriptorPropKey.context, "key", // we remove react props that are not useful for translation "render", diff --git a/packages/babel-plugin-lingui-macro/src/messageDescriptorUtils.ts b/packages/babel-plugin-lingui-macro/src/messageDescriptorUtils.ts index b0715cbca..735ec45f9 100644 --- a/packages/babel-plugin-lingui-macro/src/messageDescriptorUtils.ts +++ b/packages/babel-plugin-lingui-macro/src/messageDescriptorUtils.ts @@ -6,15 +6,7 @@ import { isObjectProperty, Expression, } from "@babel/types" -import { - MESSAGE, - ID, - EXTRACT_MARK, - COMMENT, - CONTEXT, - VALUES, - COMPONENTS, -} from "./constants" +import { EXTRACT_MARK, MsgDescriptorPropKey } from "./constants" import * as types from "@babel/types" import { generateMessageId } from "@lingui/message-utils/generateMessageId" @@ -46,7 +38,11 @@ export function createMessageDescriptorFromTokens( defaults.id ? isObjectProperty(defaults.id) ? defaults.id - : createStringObjectProperty(ID, defaults.id.text, defaults.id.loc) + : createStringObjectProperty( + MsgDescriptorPropKey.id, + defaults.id.text, + defaults.id.loc + ) : createIdProperty( message, defaults.context @@ -59,7 +55,9 @@ export function createMessageDescriptorFromTokens( if (!stripNonEssentialProps) { if (message) { - properties.push(createStringObjectProperty(MESSAGE, message)) + properties.push( + createStringObjectProperty(MsgDescriptorPropKey.message, message) + ) } if (defaults.comment) { @@ -67,7 +65,7 @@ export function createMessageDescriptorFromTokens( isObjectProperty(defaults.comment) ? defaults.comment : createStringObjectProperty( - COMMENT, + MsgDescriptorPropKey.comment, defaults.comment.text, defaults.comment.loc ) @@ -79,7 +77,7 @@ export function createMessageDescriptorFromTokens( isObjectProperty(defaults.context) ? defaults.context : createStringObjectProperty( - CONTEXT, + MsgDescriptorPropKey.context, defaults.context.text, defaults.context.loc ) @@ -87,8 +85,10 @@ export function createMessageDescriptorFromTokens( } } - properties.push(createValuesProperty(VALUES, values)) - properties.push(createValuesProperty(COMPONENTS, jsxElements)) + properties.push(createValuesProperty(MsgDescriptorPropKey.values, values)) + properties.push( + createValuesProperty(MsgDescriptorPropKey.components, jsxElements) + ) return createMessageDescriptor( properties, @@ -98,7 +98,10 @@ export function createMessageDescriptorFromTokens( } function createIdProperty(message: string, context?: string) { - return createStringObjectProperty(ID, generateMessageId(message, context)) + return createStringObjectProperty( + MsgDescriptorPropKey.id, + generateMessageId(message, context) + ) } function createValuesProperty(key: string, values: Record) { From e6e27ef960407dfd4dd9e55d2b10ed1bba45d63b Mon Sep 17 00:00:00 2001 From: Timofei Iatsenko Date: Fri, 12 Apr 2024 12:38:58 +0200 Subject: [PATCH 4/4] fixes --- .../src/index.ts | 18 ++++++++++++--- .../babel-plugin-lingui-macro/src/macroJs.ts | 6 ----- .../babel-plugin-lingui-macro/src/macroJsx.ts | 20 ++++++----------- .../jsx-plural-select-nested.expected.js | 22 +++++++++++-------- 4 files changed, 35 insertions(+), 31 deletions(-) diff --git a/packages/babel-plugin-extract-messages/src/index.ts b/packages/babel-plugin-extract-messages/src/index.ts index 0fcc54dd4..14e95c691 100644 --- a/packages/babel-plugin-extract-messages/src/index.ts +++ b/packages/babel-plugin-extract-messages/src/index.ts @@ -2,7 +2,6 @@ import type * as BabelTypesNamespace from "@babel/types" import { Expression, Identifier, - JSXAttribute, Node, ObjectExpression, ObjectProperty, @@ -192,9 +191,20 @@ export default function ({ types: t }: { types: BabelTypes }): PluginObj { const { node } = path if (!isTransComponent(path)) return - const attrs = (node.openingElement.attributes as JSXAttribute[]) || [] + const attrs = node.openingElement.attributes || [] + + if ( + t.isJSXSpreadAttribute(attrs[0]) && + hasI18nComment(attrs[0].argument) + ) { + return + } const props = attrs.reduce>((acc, item) => { + if (t.isJSXSpreadAttribute(item)) { + return acc + } + const key = item.name.name if ( key === "id" || @@ -216,7 +226,9 @@ export default function ({ types: t }: { types: BabelTypes }): PluginObj { if (!props.id) { // is valid, don't raise warning - const idProp = attrs.filter((item) => item.name.name === "id")[0] + const idProp = attrs.filter( + (item) => t.isJSXAttribute(item) && item.name.name === "id" + )[0] if (idProp === undefined || t.isLiteral(props.id as any)) { console.warn( path.buildCodeFrameError("Missing message ID, skipping.").message diff --git a/packages/babel-plugin-lingui-macro/src/macroJs.ts b/packages/babel-plugin-lingui-macro/src/macroJs.ts index aa4757b97..62521cc67 100644 --- a/packages/babel-plugin-lingui-macro/src/macroJs.ts +++ b/packages/babel-plugin-lingui-macro/src/macroJs.ts @@ -350,12 +350,6 @@ export class MacroJs { comment: commentProperty?.node, } ) - - // if (!this.stripNonEssentialProps && commentProperty) { - // properties.push(commentProperty.node) - // } - - // return this.createMessageDescriptor(properties, descriptor.node.loc) } tokenizeNode(path: NodePath, ignoreExpression = false): Token[] { diff --git a/packages/babel-plugin-lingui-macro/src/macroJsx.ts b/packages/babel-plugin-lingui-macro/src/macroJsx.ts index 42f39c24c..75c098113 100644 --- a/packages/babel-plugin-lingui-macro/src/macroJsx.ts +++ b/packages/babel-plugin-lingui-macro/src/macroJsx.ts @@ -61,14 +61,6 @@ export class MacroJSX { this.transImportName = opts.transImportName } - createStringJsxAttribute = (name: string, value: string) => { - // This handles quoted JSX attributes and html entities. - return this.types.jsxAttribute( - this.types.jsxIdentifier(name), - this.types.jsxExpressionContainer(this.types.stringLiteral(value)) - ) - } - replacePath = (path: NodePath): false | Node => { if (!path.isJSXElement()) { return false @@ -84,6 +76,10 @@ export class MacroJSX { path as NodePath ) + if (!tokens.length) { + throw new Error("Incorrect usage of Trans") + } + const messageDescriptor = createMessageDescriptorFromTokens( tokens, path.node.loc, @@ -95,10 +91,6 @@ export class MacroJSX { } ) - if (!id && !tokens) { - throw new Error("Incorrect usage of Trans") - } - attributes.push(this.types.jsxSpreadAttribute(messageDescriptor)) const newNode = this.types.jsxElement( @@ -228,7 +220,9 @@ export class MacroJSX { } else if (path.isJSXElement()) { return this.tokenizeNode(path) } else if (path.isJSXSpreadChild()) { - // just do nothing + throw new Error( + "Incorrect usage of Trans: Spread could not be used as Trans children" + ) } else if (path.isJSXText()) { return [this.tokenizeText(cleanJSXElementLiteralChild(path.node.value))] } else { diff --git a/packages/babel-plugin-lingui-macro/test/fixtures/jsx-plural-select-nested.expected.js b/packages/babel-plugin-lingui-macro/test/fixtures/jsx-plural-select-nested.expected.js index dedcebb3d..0de8a73f1 100644 --- a/packages/babel-plugin-lingui-macro/test/fixtures/jsx-plural-select-nested.expected.js +++ b/packages/babel-plugin-lingui-macro/test/fixtures/jsx-plural-select-nested.expected.js @@ -1,13 +1,17 @@ import { Trans as _Trans } from "@lingui/react" ;<_Trans - id={"n0a/bN"} - message={ - "{genderOfHost, select, female {{numGuests, plural, offset:1 =0 {{host} does not give a party.} =1 {{host} invites {guest} to her party.} =2 {{host} invites {guest} and one other person to her party.} other {{host} invites {guest} and # other people to her party.}}} male {{numGuests, plural, offset:1 =0 {{host} does not give a party.} =1 {{host} invites {guest} to his party.} =2 {{host} invites {guest} and one other person to his party.} other {{host} invites {guest} and # other people to his party.}}} other {{numGuests, plural, offset:1 =0 {{host} does not give a party.} =1 {{host} invites {guest} to their party.} =2 {{host} invites {guest} and one other person to their party.} other {{host} invites {guest} and # other people to their party.}}}}" + { + /*i18n*/ + ...{ + id: "n0a/bN", + message: + "{genderOfHost, select, female {{numGuests, plural, offset:1 =0 {{host} does not give a party.} =1 {{host} invites {guest} to her party.} =2 {{host} invites {guest} and one other person to her party.} other {{host} invites {guest} and # other people to her party.}}} male {{numGuests, plural, offset:1 =0 {{host} does not give a party.} =1 {{host} invites {guest} to his party.} =2 {{host} invites {guest} and one other person to his party.} other {{host} invites {guest} and # other people to his party.}}} other {{numGuests, plural, offset:1 =0 {{host} does not give a party.} =1 {{host} invites {guest} to their party.} =2 {{host} invites {guest} and one other person to their party.} other {{host} invites {guest} and # other people to their party.}}}}", + values: { + genderOfHost: genderOfHost, + numGuests: numGuests, + host: host, + guest: guest, + }, + } } - values={{ - genderOfHost: genderOfHost, - numGuests: numGuests, - host: host, - guest: guest, - }} />