@npm-questionpro/wick-ui-i18n 2.0.0-next.19 → 2.0.0-next.21

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,7 +1,7 @@
1
1
  # wick-ui-i18n
2
2
 
3
- Vite plugin — wraps JSX text in Wu components with `<WuTranslate>`, rewrites
4
- translatable props to `{wt("...")}`, and emits `wick-ui-i18n.json`.
3
+ Vite plugin — wraps JSX text in Wu components with `<WuTranslate>`, rewrites translatable props to `{wt("...")}`, and
4
+ emits `wick-ui-i18n.json`.
5
5
 
6
6
  ---
7
7
 
@@ -69,8 +69,7 @@ Defaults: `Label`, `placeholder`, `title`, `aria-label`, `aria-placeholder`.
69
69
 
70
70
  ## `wt()` calls
71
71
 
72
- Plugin records static args into `wick-ui-i18n.json`. No code rewrite unless
73
- template literal with expressions.
72
+ Plugin records static args into `wick-ui-i18n.json`. No code rewrite unless template literal with expressions.
74
73
 
75
74
  | Input | Dictionary | Code output |
76
75
  | ----------------------------- | --------------------- | --------------------------------------------- |
package/index.js CHANGED
@@ -86,10 +86,8 @@ export default function wickuiI18nPlugin(options = {}) {
86
86
  const hasAnyTarget =
87
87
  code.includes('Wu') ||
88
88
  /\bwt\(/.test(code) ||
89
- (processor.components.size > 0 &&
90
- [...processor.components].some(c => code.includes(c))) ||
91
- (processor.extractFromKeys.size > 0 &&
92
- [...processor.extractFromKeys].some(k => code.includes(k)))
89
+ (processor.components.size > 0 && [...processor.components].some(c => code.includes(c))) ||
90
+ (processor.extractFromKeys.size > 0 && [...processor.extractFromKeys].some(k => code.includes(k)))
93
91
  if (!filter(id) || !hasAnyTarget) return null
94
92
  return transformFile(code, id, processor)
95
93
  },
@@ -102,9 +100,7 @@ export default function wickuiI18nPlugin(options = {}) {
102
100
  configureServer(server) {
103
101
  server.middlewares.use(`${base}wick-ui-i18n.json`, (_req, res) => {
104
102
  res.setHeader('Content-Type', 'application/json')
105
- res.end(
106
- JSON.stringify(Object.fromEntries(processor.dictionary), null, 2),
107
- )
103
+ res.end(JSON.stringify(Object.fromEntries(processor.dictionary), null, 2))
108
104
  })
109
105
  },
110
106
 
@@ -113,11 +109,7 @@ export default function wickuiI18nPlugin(options = {}) {
113
109
  this.emitFile({
114
110
  type: 'asset',
115
111
  fileName: 'wick-ui-i18n.json',
116
- source: JSON.stringify(
117
- Object.fromEntries(processor.dictionary),
118
- null,
119
- 2,
120
- ),
112
+ source: JSON.stringify(Object.fromEntries(processor.dictionary), null, 2),
121
113
  })
122
114
 
123
115
  printReport(processor.entries)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@npm-questionpro/wick-ui-i18n",
3
- "version": "2.0.0-next.19",
3
+ "version": "2.0.0-next.21",
4
4
  "private": false,
5
5
  "license": "ISC",
6
6
  "description": "Auto-translation AST wrapper for Wick UI",
package/src/debug.js CHANGED
@@ -16,9 +16,7 @@ export function getComponentTree(path) {
16
16
  const parts = []
17
17
  path.findParent(p => {
18
18
  if (p.isJSXElement()) {
19
- const name =
20
- p.node.openingElement.name.name ||
21
- p.node.openingElement.name.property?.name
19
+ const name = p.node.openingElement.name.name || p.node.openingElement.name.property?.name
22
20
  if (name) parts.unshift(name)
23
21
  }
24
22
  return false
@@ -50,19 +48,15 @@ export function printReport(entries) {
50
48
 
51
49
  const rows = entries.map(e => [e.text, basename(e.file), e.componentTree])
52
50
 
53
- const widths = headers.map((h, i) =>
54
- Math.max(h.length, ...rows.map(r => r[i].length)),
55
- )
51
+ const widths = headers.map((h, i) => Math.max(h.length, ...rows.map(r => r[i].length)))
56
52
 
57
53
  const pad = (str, w) => str.padEnd(w)
58
- const sep = (l, m, r, fill) =>
59
- l + widths.map(w => fill.repeat(w + 2)).join(m) + r
54
+ const sep = (l, m, r, fill) => l + widths.map(w => fill.repeat(w + 2)).join(m) + r
60
55
 
61
56
  const top = sep('┌', '┬', '┐', '─')
62
57
  const mid = sep('├', '┼', '┤', '─')
63
58
  const bottom = sep('└', '┴', '┘', '─')
64
- const row = cells =>
65
- '│' + cells.map((c, i) => ` ${pad(c, widths[i])} `).join('│') + '│'
59
+ const row = cells => '│' + cells.map((c, i) => ` ${pad(c, widths[i])} `).join('│') + '│'
66
60
 
67
61
  const lines = [
68
62
  '',
package/src/processor.js CHANGED
@@ -4,13 +4,7 @@
4
4
  */
5
5
 
6
6
  /** Prop names translated by default on Wu* components. Pass `translatableProps` to override. */
7
- const DEFAULT_TRANSLATABLE_PROPS = [
8
- 'Label',
9
- 'placeholder',
10
- 'title',
11
- 'aria-label',
12
- 'aria-placeholder',
13
- ]
7
+ const DEFAULT_TRANSLATABLE_PROPS = ['Label', 'placeholder', 'title', 'aria-label', 'aria-placeholder']
14
8
 
15
9
  /** Components always excluded from translation regardless of user config. */
16
10
  const DEFAULT_IGNORE = [
@@ -39,13 +33,9 @@ export class TranslationProcessor {
39
33
  */
40
34
  constructor(options) {
41
35
  this.components = new Set(options.components)
42
- this.ignoreComponents = new Set(
43
- DEFAULT_IGNORE.concat(options.ignoreComponents || []),
44
- )
36
+ this.ignoreComponents = new Set(DEFAULT_IGNORE.concat(options.ignoreComponents || []))
45
37
  /** @type {Set<string>} JSX prop names that should be translated. */
46
- this.translatableProps = new Set(
47
- options.translatableProps ?? DEFAULT_TRANSLATABLE_PROPS,
48
- )
38
+ this.translatableProps = new Set(options.translatableProps ?? DEFAULT_TRANSLATABLE_PROPS)
49
39
  /** @type {Set<string>} Object property key names whose string values are extracted (e.g. 'label'). */
50
40
  this.extractFromKeys = new Set(options.extractFromKeys || [])
51
41
  /** @type {Map<string, string>} key → original text */
@@ -74,9 +64,7 @@ export class TranslationProcessor {
74
64
  */
75
65
  record(key, text, file, componentTree) {
76
66
  if (this.dictionary.has(key) && this.dictionary.get(key) !== text) {
77
- console.warn(
78
- `[wick-i18n] Collision in ${file}\nKey: "${key}"\nNew: "${text}"`,
79
- )
67
+ console.warn(`[wick-i18n] Collision in ${file}\nKey: "${key}"\nNew: "${text}"`)
80
68
  return
81
69
  }
82
70
  this.dictionary.set(key, text)
@@ -102,14 +90,10 @@ export class TranslationProcessor {
102
90
  path.findParent(p => {
103
91
  if (!p.isJSXElement()) return false
104
92
 
105
- const name =
106
- p.node.openingElement.name.name ||
107
- p.node.openingElement.name.property?.name
93
+ const name = p.node.openingElement.name.name || p.node.openingElement.name.property?.name
108
94
  const attrs = p.node.openingElement.attributes || []
109
95
 
110
- if (
111
- attrs.some(a => ['data-skip', 'data-i18n-skip'].includes(a.name?.name))
112
- ) {
96
+ if (attrs.some(a => ['data-skip', 'data-i18n-skip'].includes(a.name?.name))) {
113
97
  isIgnored = true
114
98
  return true
115
99
  }
@@ -150,8 +134,7 @@ export class TranslationProcessor {
150
134
  if (this.ignoreComponents.has(name)) return false
151
135
  // Respect data-skip / data-i18n-skip on the same element
152
136
  const attrs = openingEl.attributes || []
153
- if (attrs.some(a => ['data-skip', 'data-i18n-skip'].includes(a.name?.name)))
154
- return false
137
+ if (attrs.some(a => ['data-skip', 'data-i18n-skip'].includes(a.name?.name))) return false
155
138
  return name.startsWith('Wu') || this.components.has(name)
156
139
  }
157
140
 
@@ -166,14 +149,9 @@ export class TranslationProcessor {
166
149
  let result = null
167
150
  path.findParent(p => {
168
151
  if (!p.isJSXElement()) return false
169
- const attr = p.node.openingElement.attributes.find(
170
- a => a.name?.name === 'data-i18n-key',
171
- )
152
+ const attr = p.node.openingElement.attributes.find(a => a.name?.name === 'data-i18n-key')
172
153
  if (!attr) return false
173
- const val =
174
- attr.value.type === 'StringLiteral'
175
- ? attr.value.value
176
- : attr.value.expression?.value
154
+ const val = attr.value.type === 'StringLiteral' ? attr.value.value : attr.value.expression?.value
177
155
  if (!val) {
178
156
  console.warn(
179
157
  `[wick-i18n] data-i18n-key on <${p.node.openingElement.name.name}> is dynamic or empty — falling back to text content.`,
package/src/transform.js CHANGED
@@ -29,8 +29,7 @@ const HTML_ENTITY_RE = /&(?:[a-zA-Z][a-zA-Z0-9]*|#[0-9]+|#x[0-9a-fA-F]+);/
29
29
  /** @param {import('@babel/types').Node} node @returns {string|null} */
30
30
  function getStaticString(node) {
31
31
  if (node.type === 'StringLiteral') return node.value
32
- if (node.type === 'TemplateLiteral' && !node.expressions.length)
33
- return node.quasis[0].value.cooked
32
+ if (node.type === 'TemplateLiteral' && !node.expressions.length) return node.quasis[0].value.cooked
34
33
  return null
35
34
  }
36
35
 
@@ -51,17 +50,7 @@ function handleConditional(expr, path, ms, processor, id) {
51
50
  for (const branch of [expr.consequent, expr.alternate]) {
52
51
  const text = getStaticString(branch)
53
52
  if (text !== null) {
54
- changed =
55
- handleCapture(
56
- path,
57
- text,
58
- branch.start,
59
- branch.end,
60
- ms,
61
- processor,
62
- id,
63
- true,
64
- ) || changed
53
+ changed = handleCapture(path, text, branch.start, branch.end, ms, processor, id, true) || changed
65
54
  } else if (branch.type === 'ConditionalExpression') {
66
55
  changed = handleConditional(branch, path, ms, processor, id) || changed
67
56
  }
@@ -83,16 +72,7 @@ function handleConditional(expr, path, ms, processor, id) {
83
72
  * @param {string} id - File path (for collision warnings).
84
73
  * @returns {boolean} `true` when replacement was made.
85
74
  */
86
- function handleCapture(
87
- path,
88
- text,
89
- start,
90
- end,
91
- ms,
92
- processor,
93
- id,
94
- skipExplicitKey = false,
95
- ) {
75
+ function handleCapture(path, text, start, end, ms, processor, id, skipExplicitKey = false) {
96
76
  const cleanText = text
97
77
  .trim()
98
78
  .replace(/\n/g, ' ')
@@ -105,11 +85,7 @@ function handleCapture(
105
85
  const key = (!skipExplicitKey && processor.getExplicitKey(path)) || cleanText
106
86
  processor.record(key, cleanText, id, getComponentTree(path))
107
87
 
108
- ms.overwrite(
109
- start,
110
- end,
111
- `<WuTranslate __i18nKey=${JSON.stringify(key)}></WuTranslate>`,
112
- )
88
+ ms.overwrite(start, end, `<WuTranslate __i18nKey=${JSON.stringify(key)}></WuTranslate>`)
113
89
  return true
114
90
  }
115
91
 
@@ -219,17 +195,7 @@ export function transformFile(code, id, processor) {
219
195
  return
220
196
  }
221
197
  const start = path.node.start + text.indexOf(trimmed)
222
- if (
223
- handleCapture(
224
- path,
225
- trimmed,
226
- start,
227
- start + trimmed.length,
228
- ms,
229
- processor,
230
- id,
231
- )
232
- ) {
198
+ if (handleCapture(path, trimmed, start, start + trimmed.length, ms, processor, id)) {
233
199
  needsImport = true
234
200
  }
235
201
  },
@@ -249,10 +215,7 @@ export function transformFile(code, id, processor) {
249
215
 
250
216
  if (expr.type === 'StringLiteral') {
251
217
  text = expr.value
252
- } else if (
253
- expr.type === 'TemplateLiteral' &&
254
- expr.expressions.length > 0
255
- ) {
218
+ } else if (expr.type === 'TemplateLiteral' && expr.expressions.length > 0) {
256
219
  if (transformTemplateLiteralExpression(path, code, ms, processor, id)) {
257
220
  needsImport = true
258
221
  }
@@ -264,18 +227,7 @@ export function transformFile(code, id, processor) {
264
227
  return
265
228
  }
266
229
 
267
- if (
268
- text &&
269
- handleCapture(
270
- path,
271
- text,
272
- path.node.start,
273
- path.node.end,
274
- ms,
275
- processor,
276
- id,
277
- )
278
- ) {
230
+ if (text && handleCapture(path, text, path.node.start, path.node.end, ms, processor, id)) {
279
231
  needsImport = true
280
232
  }
281
233
  },
@@ -26,14 +26,12 @@ import {getComponentTree} from './debug.js'
26
26
  * "Hello &amp; World" → ["Hello ", "&amp;", " World"]
27
27
  * "&lt;Tag&gt;" → ["", "&lt;", "Tag", "&gt;", ""]
28
28
  */
29
- const HTML_ENTITY_SPLIT_RE =
30
- /(&(?:[a-zA-Z][a-zA-Z0-9]*|#[0-9]+|#x[0-9a-fA-F]+);)/g
29
+ const HTML_ENTITY_SPLIT_RE = /(&(?:[a-zA-Z][a-zA-Z0-9]*|#[0-9]+|#x[0-9a-fA-F]+);)/g
31
30
 
32
31
  /**
33
32
  * Tests whether a single segment (from the split above) is itself an entity.
34
33
  */
35
- const HTML_ENTITY_SEGMENT_RE =
36
- /^&(?:[a-zA-Z][a-zA-Z0-9]*|#[0-9]+|#x[0-9a-fA-F]+);$/
34
+ const HTML_ENTITY_SEGMENT_RE = /^&(?:[a-zA-Z][a-zA-Z0-9]*|#[0-9]+|#x[0-9a-fA-F]+);$/
37
35
 
38
36
  /**
39
37
  * Given a text segment, extract leading whitespace, the translatable core,
@@ -73,13 +71,7 @@ function splitSegment(raw) {
73
71
  * @param {string} id - Source file path (for collision warnings).
74
72
  * @returns {boolean} `true` when a replacement was written.
75
73
  */
76
- export function transformJsxTextWithEntities(
77
- path,
78
- rawSource,
79
- ms,
80
- processor,
81
- id,
82
- ) {
74
+ export function transformJsxTextWithEntities(path, rawSource, ms, processor, id) {
83
75
  if (!processor.shouldTranslate(path)) return false
84
76
 
85
77
  // data-i18n-key cannot span multiple split segments — warn and ignore it.
@@ -109,9 +101,7 @@ export function transformJsxTextWithEntities(
109
101
 
110
102
  if (text) {
111
103
  processor.record(text, text, id, componentTree)
112
- parts.push(
113
- `${leading}<WuTranslate __i18nKey=${JSON.stringify(text)}></WuTranslate>${trailing}`,
114
- )
104
+ parts.push(`${leading}<WuTranslate __i18nKey=${JSON.stringify(text)}></WuTranslate>${trailing}`)
115
105
  hasTranslatable = true
116
106
  } else {
117
107
  // Pure whitespace between / around entities — preserve as JSX text
@@ -45,13 +45,7 @@ function splitQuasi(raw) {
45
45
  * @param {string} id - Source file path (for collision warnings).
46
46
  * @returns {boolean} `true` when a replacement was written.
47
47
  */
48
- export function transformTemplateLiteralExpression(
49
- path,
50
- code,
51
- ms,
52
- processor,
53
- id,
54
- ) {
48
+ export function transformTemplateLiteralExpression(path, code, ms, processor, id) {
55
49
  if (!processor.shouldTranslate(path)) return false
56
50
 
57
51
  const container = path.node
@@ -68,9 +62,7 @@ export function transformTemplateLiteralExpression(
68
62
 
69
63
  if (text) {
70
64
  processor.record(text, text, id, componentTree)
71
- parts.push(
72
- `${leading}<WuTranslate __i18nKey=${JSON.stringify(text)}></WuTranslate>${trailing}`,
73
- )
65
+ parts.push(`${leading}<WuTranslate __i18nKey=${JSON.stringify(text)}></WuTranslate>${trailing}`)
74
66
  hasTranslatable = true
75
67
  }
76
68
  // whitespace-only or empty quasi — emit nothing (no key, no node)
@@ -101,8 +101,7 @@ export function transformWtTemplateLiteral(path, code, ms, processor, id) {
101
101
  if (args.length !== 1) return false
102
102
 
103
103
  const arg = args[0]
104
- if (arg.type !== 'TemplateLiteral' || arg.expressions.length === 0)
105
- return false
104
+ if (arg.type !== 'TemplateLiteral' || arg.expressions.length === 0) return false
106
105
 
107
106
  const {quasis, expressions} = arg
108
107
  const parts = ['`']