i18next-cli 1.34.0 → 1.35.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (66) hide show
  1. package/README.md +1 -1
  2. package/dist/cjs/cli.js +271 -1
  3. package/dist/cjs/config.js +211 -1
  4. package/dist/cjs/extractor/core/ast-visitors.js +372 -1
  5. package/dist/cjs/extractor/core/extractor.js +245 -1
  6. package/dist/cjs/extractor/core/key-finder.js +132 -1
  7. package/dist/cjs/extractor/core/translation-manager.js +745 -1
  8. package/dist/cjs/extractor/parsers/ast-utils.js +85 -1
  9. package/dist/cjs/extractor/parsers/call-expression-handler.js +942 -1
  10. package/dist/cjs/extractor/parsers/comment-parser.js +375 -1
  11. package/dist/cjs/extractor/parsers/expression-resolver.js +362 -1
  12. package/dist/cjs/extractor/parsers/jsx-handler.js +492 -1
  13. package/dist/cjs/extractor/parsers/jsx-parser.js +355 -1
  14. package/dist/cjs/extractor/parsers/scope-manager.js +408 -1
  15. package/dist/cjs/extractor/plugin-manager.js +106 -1
  16. package/dist/cjs/heuristic-config.js +99 -1
  17. package/dist/cjs/index.js +28 -1
  18. package/dist/cjs/init.js +174 -1
  19. package/dist/cjs/linter.js +431 -1
  20. package/dist/cjs/locize.js +269 -1
  21. package/dist/cjs/migrator.js +196 -1
  22. package/dist/cjs/rename-key.js +354 -1
  23. package/dist/cjs/status.js +336 -1
  24. package/dist/cjs/syncer.js +120 -1
  25. package/dist/cjs/types-generator.js +165 -1
  26. package/dist/cjs/utils/default-value.js +43 -1
  27. package/dist/cjs/utils/file-utils.js +136 -1
  28. package/dist/cjs/utils/funnel-msg-tracker.js +75 -1
  29. package/dist/cjs/utils/logger.js +36 -1
  30. package/dist/cjs/utils/nested-object.js +124 -1
  31. package/dist/cjs/utils/validation.js +71 -1
  32. package/dist/esm/cli.js +269 -1
  33. package/dist/esm/config.js +206 -1
  34. package/dist/esm/extractor/core/ast-visitors.js +370 -1
  35. package/dist/esm/extractor/core/extractor.js +241 -1
  36. package/dist/esm/extractor/core/key-finder.js +130 -1
  37. package/dist/esm/extractor/core/translation-manager.js +743 -1
  38. package/dist/esm/extractor/parsers/ast-utils.js +80 -1
  39. package/dist/esm/extractor/parsers/call-expression-handler.js +940 -1
  40. package/dist/esm/extractor/parsers/comment-parser.js +373 -1
  41. package/dist/esm/extractor/parsers/expression-resolver.js +360 -1
  42. package/dist/esm/extractor/parsers/jsx-handler.js +490 -1
  43. package/dist/esm/extractor/parsers/jsx-parser.js +334 -1
  44. package/dist/esm/extractor/parsers/scope-manager.js +406 -1
  45. package/dist/esm/extractor/plugin-manager.js +103 -1
  46. package/dist/esm/heuristic-config.js +97 -1
  47. package/dist/esm/index.js +11 -1
  48. package/dist/esm/init.js +172 -1
  49. package/dist/esm/linter.js +425 -1
  50. package/dist/esm/locize.js +265 -1
  51. package/dist/esm/migrator.js +194 -1
  52. package/dist/esm/rename-key.js +352 -1
  53. package/dist/esm/status.js +334 -1
  54. package/dist/esm/syncer.js +118 -1
  55. package/dist/esm/types-generator.js +163 -1
  56. package/dist/esm/utils/default-value.js +41 -1
  57. package/dist/esm/utils/file-utils.js +131 -1
  58. package/dist/esm/utils/funnel-msg-tracker.js +72 -1
  59. package/dist/esm/utils/logger.js +34 -1
  60. package/dist/esm/utils/nested-object.js +120 -1
  61. package/dist/esm/utils/validation.js +68 -1
  62. package/package.json +2 -2
  63. package/types/extractor/core/ast-visitors.d.ts.map +1 -1
  64. package/types/extractor/parsers/call-expression-handler.d.ts +3 -2
  65. package/types/extractor/parsers/call-expression-handler.d.ts.map +1 -1
  66. package/types/locize.d.ts.map +1 -1
@@ -1 +1,355 @@
1
- "use strict";var e=require("./ast-utils.js"),t=require("react"),r=require("react-i18next");function n(e){var t=Object.create(null);return e&&Object.keys(e).forEach(function(r){if("default"!==r){var n=Object.getOwnPropertyDescriptor(e,r);Object.defineProperty(t,r,n.get?n:{enumerable:!0,get:function(){return e[r]}})}}),t.default=e,Object.freeze(t)}var i=n(t);function a(t){return"StringLiteral"===t.value?.type?t.value.value:"JSXExpressionContainer"===t.value?.type?function(t){if(t)return"StringLiteral"===t.type?t.value:"TemplateLiteral"===t.type&&e.isSimpleTemplateLiteral(t)?t.quasis[0].cooked:void 0}(t.value.expression):void 0}function s(e){const t=()=>null;return Object.defineProperty(t,"name",{value:e}),t.displayName=e,t}function u(t){switch(t.type){case"JSXEmptyExpression":return null;case"TsAsExpression":case"ParenthesisExpression":return u(t.expression);case"ConditionalExpression":{const e=u(t.consequent),r=u(t.alternate);return"string"==typeof e&&"string"==typeof r&&r.length!==e.length&&r.startsWith(e)?r:e}case"StringLiteral":return t.value;case"TemplateLiteral":if(e.isSimpleTemplateLiteral(t))return t.quasis[0].raw;break;case"Identifier":return{[t.value]:t.value};case"ObjectExpression":{const e=t.properties.map(e=>"KeyValueProperty"!==e.type||"Identifier"!==e.key.type&&"StringLiteral"!==e.key.type?"Identifier"===e.type?e.value:null:e.key.value).filter(e=>null!==e);return Object.fromEntries(e.map(e=>[e,e]))}}return i.createElement("expression",{expression:t})}function l(e){switch(e.type){case"JSXText":return r=(r=e.value).replace(/\r\n/g,"\n"),/^\s+$/.test(r)&&/\n/.test(r)?null:r=(r=(r=r.replace(/^[ \t]*\n[ \t]*/,"")).replace(/[ \t]*\n[ \t]*$/,"")).replace(/[ \t]*\n[ \t]*/g," ");case"JSXExpressionContainer":return u(e.expression);case"JSXSpreadChild":return"";case"JSXElement":return i.createElement(function(e){switch(e.type){case"Identifier":return/\p{Uppercase_Letter}/u.test(e.value)?s(e.value):e.value;case"JSXMemberExpression":return s(e.property.value);case"JSXNamespacedName":return`${e.namespace.value}:${e.name.value}`}}(e.opening.name),(t=e.opening.attributes).length?Object.fromEntries(t.map(e=>"SpreadElement"===e.type?null:"Identifier"===e.name.type?[e.name.value,""]:[`${e.name.namespace.value}:${e.name.name.value}`,""]).filter(e=>null!=e)):null,...p(e.children));case"JSXFragment":return i.createElement(i.Fragment,null,...p(e.children))}var t,r}function p(e){return e.map(l).filter(e=>null!==e)}exports.extractFromTransComponent=function(t,n){const i=t.opening.attributes?.find(e=>"JSXAttribute"===e.type&&"Identifier"===e.name.type&&"i18nKey"===e.name.value),s=t.opening.attributes?.find(e=>"JSXAttribute"===e.type&&"Identifier"===e.name.type&&"defaults"===e.name.value),u=t.opening.attributes?.find(e=>"JSXAttribute"===e.type&&"Identifier"===e.name.type&&"count"===e.name.value),l=t.opening.attributes?.find(e=>"JSXAttribute"===e.type&&"Identifier"===e.name.type&&"values"===e.name.value);let o;u||"JSXAttribute"!==l?.type||"JSXExpressionContainer"!==l.value?.type||"ObjectExpression"!==l.value.expression.type||(o=e.getObjectPropValueExpression(l.value.expression,"count"));const c=!!u||!!o,y=t.opening.attributes?.find(e=>"JSXAttribute"===e.type&&"Identifier"===e.name.type&&"tOptions"===e.name.value),f="JSXAttribute"===y?.type&&"JSXExpressionContainer"===y.value?.type&&"ObjectExpression"===y.value.expression.type?y.value.expression:void 0,v=t.opening.attributes?.find(e=>"JSXAttribute"===e.type&&"Identifier"===e.name.type&&"ordinal"===e.name.value),m=!!v,d=t.opening.attributes?.find(e=>"JSXAttribute"===e.type&&"Identifier"===e.name.type&&"context"===e.name.value);let x="JSXAttribute"===d?.type&&"JSXExpressionContainer"===d.value?.type?d.value.expression:"JSXAttribute"===d?.type&&"StringLiteral"===d.value?.type?d.value:void 0;const S=t.opening.attributes?.find(e=>"JSXAttribute"===e.type&&"Identifier"===e.name.type&&"ns"===e.name.value);let b;b="JSXAttribute"===S?.type?a(S):void 0,f&&(void 0===b&&(b=e.getObjectPropValue(f,"ns")),void 0===x&&(x=e.getObjectPropValueExpression(f,"context")));const g=function(e,t){const n={...r.getDefaults()};t.extract.transKeepBasicHtmlNodesFor&&(n.transKeepBasicHtmlNodesFor=t.extract.transKeepBasicHtmlNodesFor);return r.nodesToString(p(e),n)}(t.children,n);let E;const J="JSXAttribute"===s?.type?a(s):void 0;if(void 0!==J)E=J;else{const e=n.extract.defaultValue;E="string"==typeof e?e:""}let X,h;if("JSXAttribute"===i?.type){if("StringLiteral"===i.value?.type){if(X=i.value,h=X.value,!h||""===h.trim())return null;if(b&&"StringLiteral"===X.type){const e=n.extract.nsSeparator??":",t=X.value;if(e&&t.startsWith(`${b}${e}`)){if(h=t.slice(`${b}${e}`.length),!h||""===h.trim())return null;X={...X,value:h}}}}else"JSXExpressionContainer"===i.value?.type&&"JSXEmptyExpression"!==i.value.expression.type&&(X=i.value.expression);if(!X)return null}return s||!h||g.trim()?!s&&g.trim()&&(E=g):E=h,{keyExpression:X,serializedChildren:g,ns:b,defaultValue:E,hasCount:c,isOrdinal:m,contextExpression:x,optionsNode:f,explicitDefault:void 0!==J||(e=>{if(!e||!Array.isArray(e.properties))return!1;for(const t of e.properties)if(t&&"KeyValueProperty"===t.type&&t.key){const e="Identifier"===t.key.type&&t.key.value||"StringLiteral"===t.key.type&&t.key.value;if("string"==typeof e&&e.startsWith("defaultValue"))return!0}return!1})(f)}};
1
+ 'use strict';
2
+
3
+ var astUtils = require('./ast-utils.js');
4
+ var React = require('react');
5
+ var reactI18next = require('react-i18next');
6
+
7
+ function _interopNamespaceDefault(e) {
8
+ var n = Object.create(null);
9
+ if (e) {
10
+ Object.keys(e).forEach(function (k) {
11
+ if (k !== 'default') {
12
+ var d = Object.getOwnPropertyDescriptor(e, k);
13
+ Object.defineProperty(n, k, d.get ? d : {
14
+ enumerable: true,
15
+ get: function () { return e[k]; }
16
+ });
17
+ }
18
+ });
19
+ }
20
+ n.default = e;
21
+ return Object.freeze(n);
22
+ }
23
+
24
+ var React__namespace = /*#__PURE__*/_interopNamespaceDefault(React);
25
+
26
+ function getStringLiteralFromExpression(expression) {
27
+ if (!expression)
28
+ return undefined;
29
+ if (expression.type === 'StringLiteral') {
30
+ return expression.value;
31
+ }
32
+ if (expression.type === 'TemplateLiteral' && astUtils.isSimpleTemplateLiteral(expression)) {
33
+ return expression.quasis[0].cooked;
34
+ }
35
+ return undefined;
36
+ }
37
+ function getStringLiteralFromAttribute(attr) {
38
+ if (attr.value?.type === 'StringLiteral') {
39
+ return attr.value.value;
40
+ }
41
+ if (attr.value?.type === 'JSXExpressionContainer') {
42
+ return getStringLiteralFromExpression(attr.value.expression);
43
+ }
44
+ return undefined;
45
+ }
46
+ /**
47
+ * Extracts translation keys from JSX Trans components.
48
+ *
49
+ * This function handles various Trans component patterns:
50
+ * - Explicit i18nKey prop: `<Trans i18nKey="my.key">content</Trans>`
51
+ * - Implicit keys from children: `<Trans>Hello World</Trans>`
52
+ * - Namespace specification: `<Trans ns="common">content</Trans>`
53
+ * - Default values: `<Trans defaults="Default text">content</Trans>`
54
+ * - Pluralization: `<Trans count={count}>content</Trans>`
55
+ * - HTML preservation: `<Trans>Hello <strong>world</strong></Trans>`
56
+ *
57
+ * @param node - The JSX element node to process
58
+ * @param config - The toolkit configuration containing extraction settings
59
+ * @returns Extracted key information or null if no valid key found
60
+ *
61
+ * @example
62
+ * ```typescript
63
+ * // Input JSX:
64
+ * // <Trans i18nKey="welcome.title" ns="home" defaults="Welcome!">
65
+ * // Welcome to our <strong>amazing</strong> app!
66
+ * // </Trans>
67
+ *
68
+ * const result = extractFromTransComponent(jsxNode, config)
69
+ * // Returns: {
70
+ * // key: 'welcome.title',
71
+ * // keyExpression: { ... },
72
+ * // ns: 'home',
73
+ * // defaultValue: 'Welcome!',
74
+ * // hasCount: false
75
+ * // }
76
+ * ```
77
+ */
78
+ function extractFromTransComponent(node, config) {
79
+ const i18nKeyAttr = node.opening.attributes?.find((attr) => attr.type === 'JSXAttribute' &&
80
+ attr.name.type === 'Identifier' &&
81
+ attr.name.value === 'i18nKey');
82
+ const defaultsAttr = node.opening.attributes?.find((attr) => attr.type === 'JSXAttribute' &&
83
+ attr.name.type === 'Identifier' &&
84
+ attr.name.value === 'defaults');
85
+ const countAttr = node.opening.attributes?.find((attr) => attr.type === 'JSXAttribute' &&
86
+ attr.name.type === 'Identifier' &&
87
+ attr.name.value === 'count');
88
+ const valuesAttr = node.opening.attributes?.find((attr) => attr.type === 'JSXAttribute' && attr.name.type === 'Identifier' && attr.name.value === 'values');
89
+ // Find the 'count' property in the 'values' object if count={...} is not defined
90
+ let valuesCountProperty;
91
+ if (!countAttr &&
92
+ valuesAttr?.type === 'JSXAttribute' &&
93
+ valuesAttr.value?.type === 'JSXExpressionContainer' &&
94
+ valuesAttr.value.expression.type === 'ObjectExpression') {
95
+ valuesCountProperty = astUtils.getObjectPropValueExpression(valuesAttr.value.expression, 'count');
96
+ }
97
+ const hasCount = !!countAttr || !!valuesCountProperty;
98
+ const tOptionsAttr = node.opening.attributes?.find((attr) => attr.type === 'JSXAttribute' &&
99
+ attr.name.type === 'Identifier' &&
100
+ attr.name.value === 'tOptions');
101
+ const optionsNode = (tOptionsAttr?.type === 'JSXAttribute' && tOptionsAttr.value?.type === 'JSXExpressionContainer' && tOptionsAttr.value.expression.type === 'ObjectExpression')
102
+ ? tOptionsAttr.value.expression
103
+ : undefined;
104
+ // Find isOrdinal prop on the <Trans> component
105
+ const ordinalAttr = node.opening.attributes?.find((attr) => attr.type === 'JSXAttribute' &&
106
+ attr.name.type === 'Identifier' &&
107
+ attr.name.value === 'ordinal');
108
+ const isOrdinal = !!ordinalAttr;
109
+ const contextAttr = node.opening.attributes?.find((attr) => attr.type === 'JSXAttribute' &&
110
+ attr.name.type === 'Identifier' &&
111
+ attr.name.value === 'context');
112
+ let contextExpression = (contextAttr?.type === 'JSXAttribute' && contextAttr.value?.type === 'JSXExpressionContainer')
113
+ ? contextAttr.value.expression
114
+ : (contextAttr?.type === 'JSXAttribute' && contextAttr.value?.type === 'StringLiteral')
115
+ ? contextAttr.value
116
+ : undefined;
117
+ // 1. Prioritize direct props for 'ns' and 'context'
118
+ const nsAttr = node.opening.attributes?.find(attr => attr.type === 'JSXAttribute' && attr.name.type === 'Identifier' && attr.name.value === 'ns');
119
+ let ns;
120
+ if (nsAttr?.type === 'JSXAttribute') {
121
+ ns = getStringLiteralFromAttribute(nsAttr);
122
+ }
123
+ else {
124
+ ns = undefined;
125
+ }
126
+ // 2. If not found, fall back to looking inside tOptions
127
+ if (optionsNode) {
128
+ if (ns === undefined) {
129
+ ns = astUtils.getObjectPropValue(optionsNode, 'ns');
130
+ }
131
+ if (contextExpression === undefined) {
132
+ contextExpression = astUtils.getObjectPropValueExpression(optionsNode, 'context');
133
+ }
134
+ }
135
+ const serialized = serializeJSXChildren(node.children, config);
136
+ // Handle default value properly
137
+ let defaultValue;
138
+ const defaultAttributeLiteral = defaultsAttr?.type === 'JSXAttribute' ? getStringLiteralFromAttribute(defaultsAttr) : undefined;
139
+ if (defaultAttributeLiteral !== undefined) {
140
+ // Explicit defaults attribute takes precedence
141
+ defaultValue = defaultAttributeLiteral;
142
+ }
143
+ else {
144
+ // Use the configured default value or fall back to empty string
145
+ const configuredDefault = config.extract.defaultValue;
146
+ if (typeof configuredDefault === 'string') {
147
+ defaultValue = configuredDefault;
148
+ }
149
+ else {
150
+ // For function-based defaults or undefined, use empty string as placeholder
151
+ // The translation manager will handle function resolution with proper context
152
+ defaultValue = '';
153
+ }
154
+ }
155
+ let keyExpression;
156
+ let processedKeyValue;
157
+ if (i18nKeyAttr?.type === 'JSXAttribute') {
158
+ if (i18nKeyAttr.value?.type === 'StringLiteral') {
159
+ keyExpression = i18nKeyAttr.value;
160
+ processedKeyValue = keyExpression.value;
161
+ // Validate that the key is not empty
162
+ if (!processedKeyValue || processedKeyValue.trim() === '') {
163
+ return null;
164
+ }
165
+ // Handle namespace prefix removal when both ns and i18nKey are provided
166
+ if (ns && keyExpression.type === 'StringLiteral') {
167
+ const nsSeparator = config.extract.nsSeparator ?? ':';
168
+ const keyValue = keyExpression.value;
169
+ // If the key starts with the namespace followed by the separator, remove the prefix
170
+ if (nsSeparator && keyValue.startsWith(`${ns}${nsSeparator}`)) {
171
+ processedKeyValue = keyValue.slice(`${ns}${nsSeparator}`.length);
172
+ // Validate processed key is not empty
173
+ if (!processedKeyValue || processedKeyValue.trim() === '') {
174
+ return null;
175
+ }
176
+ // Create a new StringLiteral with the namespace prefix removed
177
+ keyExpression = {
178
+ ...keyExpression,
179
+ value: processedKeyValue
180
+ };
181
+ }
182
+ }
183
+ }
184
+ else if (i18nKeyAttr.value?.type === 'JSXExpressionContainer' &&
185
+ i18nKeyAttr.value.expression.type !== 'JSXEmptyExpression') {
186
+ keyExpression = i18nKeyAttr.value.expression;
187
+ }
188
+ if (!keyExpression)
189
+ return null;
190
+ }
191
+ // If no explicit defaults provided and we have a processed key, use it as default value
192
+ // This matches the behavior of other similar tests in the codebase
193
+ if (!defaultsAttr && processedKeyValue && !serialized.trim()) {
194
+ defaultValue = processedKeyValue;
195
+ }
196
+ else if (!defaultsAttr && serialized.trim()) {
197
+ defaultValue = serialized;
198
+ }
199
+ // Determine if tOptions contained explicit defaultValue* properties
200
+ const optionsHasDefaultProps = (opts) => {
201
+ if (!opts || !Array.isArray(opts.properties))
202
+ return false;
203
+ for (const p of opts.properties) {
204
+ if (p && p.type === 'KeyValueProperty' && p.key) {
205
+ const keyName = (p.key.type === 'Identifier' && p.key.value) || (p.key.type === 'StringLiteral' && p.key.value);
206
+ if (typeof keyName === 'string' && keyName.startsWith('defaultValue'))
207
+ return true;
208
+ }
209
+ }
210
+ return false;
211
+ };
212
+ const explicitDefault = defaultAttributeLiteral !== undefined || optionsHasDefaultProps(optionsNode);
213
+ return {
214
+ keyExpression,
215
+ serializedChildren: serialized,
216
+ ns,
217
+ defaultValue,
218
+ hasCount,
219
+ isOrdinal,
220
+ contextExpression,
221
+ optionsNode,
222
+ explicitDefault
223
+ };
224
+ }
225
+ /**
226
+ * Creates a dummy React component. The implementation / return value is
227
+ * irrelevant, as long as we have something realistic-looking to pass to
228
+ * react-i18next.
229
+ */
230
+ function makeDummyComponent(name) {
231
+ const result = () => null;
232
+ Object.defineProperty(result, 'name', { value: name });
233
+ result.displayName = name;
234
+ return result;
235
+ }
236
+ function makeDummyProps(attributes) {
237
+ return attributes.length
238
+ ? Object.fromEntries(attributes.map((attr) => {
239
+ if (attr.type === 'SpreadElement') {
240
+ return null;
241
+ }
242
+ else if (attr.name.type === 'Identifier') {
243
+ return [attr.name.value, ''];
244
+ }
245
+ else {
246
+ return [`${attr.name.namespace.value}:${attr.name.name.value}`, ''];
247
+ }
248
+ }).filter(i => i != null))
249
+ : null;
250
+ }
251
+ function getElementName(element) {
252
+ switch (element.type) {
253
+ case 'Identifier':
254
+ return /\p{Uppercase_Letter}/u.test(element.value) ? makeDummyComponent(element.value) : element.value;
255
+ case 'JSXMemberExpression':
256
+ // element.object should be irrelevant for naming purposes here
257
+ return makeDummyComponent(element.property.value);
258
+ case 'JSXNamespacedName':
259
+ return `${element.namespace.value}:${element.name.value}`;
260
+ }
261
+ }
262
+ function trimTextNode(text) {
263
+ text = text.replace(/\r\n/g, '\n'); // Normalize line endings
264
+ // If text is ONLY whitespace AND contains a newline, remove it entirely
265
+ if (/^\s+$/.test(text) && /\n/.test(text)) {
266
+ return null;
267
+ }
268
+ // Trim leading/trailing whitespace sequences containing newlines
269
+ text = text.replace(/^[ \t]*\n[ \t]*/, '');
270
+ text = text.replace(/[ \t]*\n[ \t]*$/, '');
271
+ // Replace whitespace sequences containing newlines with single space
272
+ text = text.replace(/[ \t]*\n[ \t]*/g, ' ');
273
+ return text;
274
+ }
275
+ function swcExpressionToReactNode(expr) {
276
+ switch (expr.type) {
277
+ case 'JSXEmptyExpression':
278
+ return null;
279
+ case 'TsAsExpression':
280
+ return swcExpressionToReactNode(expr.expression);
281
+ case 'ParenthesisExpression':
282
+ return swcExpressionToReactNode(expr.expression);
283
+ case 'ConditionalExpression': {
284
+ const consequent = swcExpressionToReactNode(expr.consequent);
285
+ const alternate = swcExpressionToReactNode(expr.alternate);
286
+ // Heuristic:
287
+ // - If one branch is a strict prefix of the other, pick the longer (keeps extra static tail),
288
+ // e.g. "to select" vs "to select, or right click..."
289
+ // - Otherwise, stay deterministic and prefer consequent (avoids choosing alternates just because they’re 1 char longer).
290
+ if (typeof consequent === 'string' &&
291
+ typeof alternate === 'string' &&
292
+ alternate.length !== consequent.length &&
293
+ alternate.startsWith(consequent)) {
294
+ return alternate;
295
+ }
296
+ return consequent;
297
+ }
298
+ case 'StringLiteral':
299
+ return expr.value;
300
+ case 'TemplateLiteral':
301
+ if (astUtils.isSimpleTemplateLiteral(expr)) {
302
+ return expr.quasis[0].raw;
303
+ }
304
+ // Too complex!
305
+ break;
306
+ case 'Identifier':
307
+ // Not a valid React element, but props for Trans interpolation
308
+ // TODO: This might actually be an error - not sure that react-i18next can handle at runtime
309
+ return { [expr.value]: expr.value };
310
+ case 'ObjectExpression': {
311
+ const keys = expr.properties.map((prop) => {
312
+ if (prop.type === 'KeyValueProperty' && (prop.key.type === 'Identifier' || prop.key.type === 'StringLiteral')) {
313
+ return prop.key.value;
314
+ }
315
+ else if (prop.type === 'Identifier') {
316
+ return prop.value;
317
+ }
318
+ else {
319
+ // Too complex to represent! TODO: Flag an error
320
+ return null;
321
+ }
322
+ }).filter(k => k !== null);
323
+ // Not a valid React element, but props for Trans interpolation
324
+ return Object.fromEntries(keys.map(k => [k, k]));
325
+ }
326
+ }
327
+ // Too complex to represent! TODO: Flag an error
328
+ return React__namespace.createElement('expression', { expression: expr });
329
+ }
330
+ function swcChildToReactNode(node) {
331
+ switch (node.type) {
332
+ case 'JSXText':
333
+ return trimTextNode(node.value);
334
+ case 'JSXExpressionContainer':
335
+ return swcExpressionToReactNode(node.expression);
336
+ case 'JSXSpreadChild':
337
+ return '';
338
+ case 'JSXElement':
339
+ return React__namespace.createElement(getElementName(node.opening.name), makeDummyProps(node.opening.attributes), ...swcChildrenToReactNodes(node.children));
340
+ case 'JSXFragment':
341
+ return React__namespace.createElement(React__namespace.Fragment, null, ...swcChildrenToReactNodes(node.children));
342
+ }
343
+ }
344
+ function swcChildrenToReactNodes(children) {
345
+ return children.map(swcChildToReactNode).filter(n => n !== null);
346
+ }
347
+ function serializeJSXChildren(children, config) {
348
+ const i18nextOptions = { ...reactI18next.getDefaults() };
349
+ if (config.extract.transKeepBasicHtmlNodesFor) {
350
+ i18nextOptions.transKeepBasicHtmlNodesFor = config.extract.transKeepBasicHtmlNodesFor;
351
+ }
352
+ return reactI18next.nodesToString(swcChildrenToReactNodes(children), i18nextOptions);
353
+ }
354
+
355
+ exports.extractFromTransComponent = extractFromTransComponent;