@npm-questionpro/wick-ui-i18n 2.13.0 → 2.14.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.
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # wick-ui-i18n
2
2
 
3
- Vite plugin — wraps JSX text in Wu\* components with `<WuTranslate>`, rewrites translatable props to `{useWt()("...")}`,
3
+ Vite plugin — wraps JSX text in Wu\* components with `<WuTranslate>`, rewrites translatable props to `{wt("...")}`,
4
4
  records `wt()` / `useWt()()` calls, and emits `wick-ui-i18n.json`.
5
5
 
6
6
  > Full docs and examples: Storybook → **i18n/Overview**
@@ -22,7 +22,7 @@ export default defineConfig({plugins: [react(), wickI18n()]})
22
22
  | Source | Output |
23
23
  | ----------------------------------------- | --------------------------------------------- |
24
24
  | `<WuButton>Save</WuButton>` | `<WuTranslate __i18nKey="Save" />` |
25
- | `<WuInput Label="First name" />` | `Label={useWt()("First name")}` |
25
+ | `<WuInput Label="First name" />` | `Label={wt("First name")}` |
26
26
  | ``<WuButton>{`${n} results`}</WuButton>`` | `<><WuTranslate __i18nKey="results" />{n}</>` |
27
27
  | `wt("Hello")` | recorded in dictionary |
28
28
  | ``wt(`Hello ${name}`)`` | `` `${wt("Hello")} ${name}` `` |
@@ -37,7 +37,7 @@ export default defineConfig({plugins: [react(), wickI18n()]})
37
37
  | ------------------- | ----------------------------------------------------------------- | --------------------------------------------------------------------------------------- |
38
38
  | `components` | `[]` | Extra components treated like Wu\* |
39
39
  | `ignoreComponents` | `[]` | Extra components never translated |
40
- | `translatableProps` | `['Label','placeholder','title','aria-label','aria-placeholder']` | Props rewritten to `useWt()()` |
40
+ | `translatableProps` | `['Label','placeholder','title','aria-label','aria-placeholder']` | Props rewritten to `wt()` |
41
41
  | `dataLabelKeys` | `[]` | Property names whose values are labels in mixed data files |
42
42
  | `dictionaryFiles` | — | Globs (project files via Vite) or exact paths (anywhere, incl. `node_modules` via `fs`) |
43
43
  | `excludeFiles` | — | Files skipped entirely |
package/index.d.ts CHANGED
@@ -9,7 +9,7 @@ export interface WickI18nOptions {
9
9
  ignoreComponents?: string[]
10
10
 
11
11
  /**
12
- * Extra JSX prop names rewritten to `{useWt()("...")}` on Wu* components.
12
+ * Extra JSX prop names rewritten to `{wt("...")}` on Wu* components.
13
13
  * Appended to the defaults — defaults are always kept:
14
14
  * `['Label', 'placeholder', 'title', 'aria-label', 'aria-placeholder']`.
15
15
  */
@@ -67,7 +67,7 @@ export interface WickI18nOptions {
67
67
  * Vite plugin that automatically translates Wick UI components.
68
68
  *
69
69
  * - JSX text content inside Wu* → `<WuTranslate __i18nKey="..." />`
70
- * - Translatable props (`Label`, `placeholder`, `title`, …) → `{useWt()("...")}`
70
+ * - Translatable props (`Label`, `placeholder`, `title`, …) → `{wt("...")}`
71
71
  * - `wt("literal")` and `useWt()("literal")` calls → keys recorded in dictionary
72
72
  * - `wt(\`Hello ${name}\`)` and `useWt()(\`Hello ${name}\`)` → each static quasi extracted and rewritten
73
73
  * - Emits `wick-ui-i18n.json` at build time / serves it at `GET /wick-ui-i18n.json` in dev
package/index.js CHANGED
@@ -31,7 +31,7 @@ import {extractStringsFromFile} from './src/extractStrings.js'
31
31
  * @typedef {object} WickI18nOptions
32
32
  * @property {string[]} [components] - Extra component names that trigger translation.
33
33
  * @property {string[]} [ignoreComponents] - Component names to exclude from translation.
34
- * @property {string[]} [translatableProps] - JSX prop names rewritten to `{useWt()("...")}`. Defaults to `['Label','placeholder','title','aria-label','aria-placeholder']`.
34
+ * @property {string[]} [translatableProps] - JSX prop names rewritten to `{wt("...")}`. Defaults to `['Label','placeholder','title','aria-label','aria-placeholder']`.
35
35
  * @property {string[]} [dataLabelKeys] - Object property names whose string values are labels in mixed data
36
36
  * files (e.g. `['label', 'title']` in nav config arrays). No code rewrite;
37
37
  * keys are recorded into `wick-ui-i18n.json` for the translation API.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@npm-questionpro/wick-ui-i18n",
3
- "version": "2.13.0",
3
+ "version": "2.14.0",
4
4
  "private": false,
5
5
  "license": "ISC",
6
6
  "description": "Auto-translation AST wrapper for Wick UI",
package/src/processor.js CHANGED
@@ -27,7 +27,7 @@ export class TranslationProcessor {
27
27
  * @param {object} options
28
28
  * @param {string[]} options.components - Component names that trigger translation.
29
29
  * @param {string[]} [options.ignoreComponents] - Extra components to exclude.
30
- * @param {string[]} [options.translatableProps] - Extra JSX prop names to rewrite to useWt()(). Appended to defaults.
30
+ * @param {string[]} [options.translatableProps] - Extra JSX prop names to rewrite to wt(). Appended to defaults.
31
31
  * @param {string[]} [options.dataLabelKeys] - Object property names whose string values are labels in mixed
32
32
  * data files (e.g. ['label', 'title'] in nav config arrays).
33
33
  * @param {boolean} [options.debug] - Enable verbose logging.
@@ -121,7 +121,7 @@ export class TranslationProcessor {
121
121
  /**
122
122
  * Return `true` when `propName` is in the translatable-props set and the
123
123
  * immediate parent JSX element is a Wu* component or in `components`, and
124
- * is not in `ignoreComponents`. Matched props are rewritten to `{useWt()("...")}` by the transform.
124
+ * is not in `ignoreComponents`. Matched props are rewritten to `{wt("...")}` by the transform.
125
125
  *
126
126
  * @param {string} propName
127
127
  * @param {import('@babel/traverse').NodePath} path - JSXAttribute path.
package/src/transform.js CHANGED
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * @fileoverview AST transform — parses a JSX/TSX/TS file and:
3
3
  * - Rewrites JSX text content inside Wu* components to `<WuTranslate>`
4
- * - Rewrites translatable props (placeholder, title, …) to `{useWt()("…")}`
4
+ * - Rewrites translatable props (placeholder, title, …) to `{wt("…")}`
5
5
  * - Prepends the necessary imports when added.
6
6
  * - Optionally records Wu* component usages into a TelemetryCollector.
7
7
  */
@@ -75,12 +75,12 @@ function handleCapture(path, text, start, end, ms, processor, id, skipExplicitKe
75
75
  }
76
76
 
77
77
  /**
78
- * Transform a JSX prop value that is a TemplateLiteral into a useWt()() call
79
- * (or a new template literal with useWt()() for each static quasi).
78
+ * Transform a JSX prop value that is a TemplateLiteral into a wt() call
79
+ * (or a new template literal with wt() for each static quasi).
80
80
  *
81
- * Static: Label={`hello`} → Label={useWt()("hello")}
82
- * Dynamic: Label={`${name} hello`} → Label={`${name} ${useWt()("hello")}`}
83
- * Dynamic: Label={`${a} and ${b}`} → Label={`${a} ${useWt()("and")} ${b}`}
81
+ * Static: Label={`hello`} → Label={wt("hello")}
82
+ * Dynamic: Label={`${name} hello`} → Label={`${name} ${wt("hello")}`}
83
+ * Dynamic: Label={`${a} and ${b}`} → Label={`${a} ${wt("and")} ${b}`}
84
84
  *
85
85
  * @param {import('@babel/traverse').NodePath} path - JSXAttribute path.
86
86
  * @param {import('@babel/types').TemplateLiteral} expr
@@ -102,11 +102,11 @@ function transformPropTemplateLiteral(path, expr, code, ms, processor, id) {
102
102
  if (!text || HTML_ENTITY_RE.test(text)) return false
103
103
  processor.record(text, text, id, componentTree)
104
104
  // Overwrite the entire JSXExpressionContainer
105
- ms.overwrite(path.node.value.start, path.node.value.end, `{useWt()(${JSON.stringify(text)})}`)
105
+ ms.overwrite(path.node.value.start, path.node.value.end, `{wt(${JSON.stringify(text)})}`)
106
106
  return true
107
107
  }
108
108
 
109
- // Dynamic template literal: walk quasis, replace static parts with useWt()()
109
+ // Dynamic template literal: walk quasis, replace static parts with wt()
110
110
  const parts = ['`']
111
111
  let hasTranslatable = false
112
112
 
@@ -116,7 +116,7 @@ function transformPropTemplateLiteral(path, expr, code, ms, processor, id) {
116
116
 
117
117
  if (text && !HTML_ENTITY_RE.test(text)) {
118
118
  processor.record(text, text, id, componentTree)
119
- parts.push(`${leading}\${useWt()(${JSON.stringify(text)})}${trailing}`)
119
+ parts.push(`${leading}\${wt(${JSON.stringify(text)})}${trailing}`)
120
120
  hasTranslatable = true
121
121
  } else {
122
122
  parts.push(cooked)
@@ -157,8 +157,11 @@ export function transformFile(code, id, processor, {telemetry} = {}) {
157
157
  const ms = new MagicString(code)
158
158
  let needsImport = false
159
159
  let hasImport = false
160
- let needsUseWtImport = false
161
- let hasUseWtImport = false
160
+ let needsWtImport = false
161
+ let hasWtImport = false
162
+ // Offset just before the closing `}` of an existing named import from wick-ui-lib,
163
+ // used to splice in extra names instead of prepending a second import statement.
164
+ let wickUiLibImportInsertPos = null
162
165
  // Local names of components actually imported from @npm-questionpro/* — telemetry only
163
166
  // counts these, so a same-named Wu* component from an unrelated package (e.g. a legacy
164
167
  // internal UI lib) never pollutes the @npm-questionpro/wick-ui-* usage stats.
@@ -178,9 +181,13 @@ export function transformFile(code, id, processor, {telemetry} = {}) {
178
181
  /** Track whether WuTranslate / wt are already imported so we don't duplicate them. */
179
182
  ImportDeclaration(path) {
180
183
  if (path.node.source.value.includes('wick-ui-lib')) {
184
+ const namedSpecifiers = path.node.specifiers.filter(s => s.type === 'ImportSpecifier')
185
+ if (namedSpecifiers.length) {
186
+ wickUiLibImportInsertPos = namedSpecifiers[namedSpecifiers.length - 1].end
187
+ }
181
188
  for (const s of path.node.specifiers) {
182
189
  if (s.imported?.name === 'WuTranslate') hasImport = true
183
- if (s.imported?.name === 'useWt') hasUseWtImport = true
190
+ if (s.imported?.name === 'wt') hasWtImport = true
184
191
  }
185
192
  }
186
193
  if (path.node.source.value.startsWith('@npm-questionpro/')) {
@@ -210,12 +217,12 @@ export function transformFile(code, id, processor, {telemetry} = {}) {
210
217
 
211
218
  /**
212
219
  * Translatable props (Label, placeholder, title, aria-label, ...)
213
- * rewritten to `{useWt()("foo")}` on Wu* components.
220
+ * rewritten to `{wt("foo")}` on Wu* components.
214
221
  *
215
222
  * Handles all three value shapes:
216
- * Label="hello" → Label={useWt()("hello")}
217
- * Label={`hello`} → Label={useWt()("hello")}
218
- * Label={`${name} hello`} → Label={`${name} ${useWt()("hello")}`}
223
+ * Label="hello" → Label={wt("hello")}
224
+ * Label={`hello`} → Label={wt("hello")}
225
+ * Label={`${name} hello`} → Label={`${name} ${wt("hello")}`}
219
226
  */
220
227
  JSXAttribute(path) {
221
228
  const propName = path.node.name.name
@@ -231,8 +238,8 @@ export function transformFile(code, id, processor, {telemetry} = {}) {
231
238
  if (!text) return
232
239
  if (!processor.shouldTranslateProp(propName, path)) return
233
240
  processor.record(text, text, id, getComponentTree(path))
234
- ms.overwrite(value.start, value.end, `{useWt()(${JSON.stringify(text)})}`)
235
- needsUseWtImport = true
241
+ ms.overwrite(value.start, value.end, `{wt(${JSON.stringify(text)})}`)
242
+ needsWtImport = true
236
243
  return
237
244
  }
238
245
 
@@ -240,7 +247,7 @@ export function transformFile(code, id, processor, {telemetry} = {}) {
240
247
  // Label={`hello`} or Label={`${name} hello`}
241
248
  if (value.type === 'JSXExpressionContainer' && value.expression.type === 'TemplateLiteral') {
242
249
  if (transformPropTemplateLiteral(path, value.expression, code, ms, processor, id)) {
243
- needsUseWtImport = true
250
+ needsWtImport = true
244
251
  }
245
252
  }
246
253
  },
@@ -315,12 +322,18 @@ export function transformFile(code, id, processor, {telemetry} = {}) {
315
322
 
316
323
  if (!ms.hasChanged()) return null
317
324
 
318
- if (needsUseWtImport && !hasUseWtImport) {
319
- ms.prepend(`import { useWt } from '@npm-questionpro/wick-ui-lib';\n`)
320
- }
325
+ // Merge into one statement — either spliced into an existing wick-ui-lib import or a
326
+ // single new prepended import never two separate `import ... from 'wick-ui-lib'` lines.
327
+ const namesToImport = []
328
+ if (needsWtImport && !hasWtImport) namesToImport.push('wt')
329
+ if (needsImport && !hasImport) namesToImport.push('WuTranslate')
321
330
 
322
- if (needsImport && !hasImport) {
323
- ms.prepend(`import { WuTranslate } from '@npm-questionpro/wick-ui-lib';\n`)
331
+ if (namesToImport.length) {
332
+ if (wickUiLibImportInsertPos !== null) {
333
+ ms.appendLeft(wickUiLibImportInsertPos, `, ${namesToImport.join(', ')}`)
334
+ } else {
335
+ ms.prepend(`import { ${namesToImport.join(', ')} } from '@npm-questionpro/wick-ui-lib';\n`)
336
+ }
324
337
  }
325
338
 
326
339
  return {code: ms.toString(), map: ms.generateMap({hires: true})}