@npm-questionpro/wick-ui-i18n 0.14.0 → 2.0.0-next.4

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
@@ -7,98 +7,99 @@ translatable props to `{wt("...")}`, and emits `wick-ui-i18n.json`.
7
7
 
8
8
  ## JSX text
9
9
 
10
- | Input | Output |
11
- |---|---|
12
- | `<WuButton>Hello</WuButton>` | ✅ `<WuTranslate __i18nKey="Hello" />` |
13
- | `<WuIcon>star</WuIcon>` | ❌ |
14
- | `<div>Hello</div>` | ❌ |
15
- | `<WuButton data-skip>Hello</WuButton>` | ❌ |
16
- | `<span data-i18n-wrapper>Hello</span>` | ✅ `<WuTranslate __i18nKey="Hello" />` |
17
- | `<WuButton data-i18n-key="k">Hello</WuButton>` | ✅ `<WuTranslate __i18nKey="k" />` |
18
- | `<WuButton>&amp;</WuButton>` | ❌ |
19
- | `<WuButton>Hello &amp; World</WuButton>` | ✅ `<WuTranslate __i18nKey="Hello" /> &amp; <WuTranslate __i18nKey="World" />` |
10
+ | Input | Output |
11
+ | ---------------------------------------------- | ------------------------------------------------------------------------------ |
12
+ | `<WuButton>Hello</WuButton>` | ✅ `<WuTranslate __i18nKey="Hello" />` |
13
+ | `<WuIcon>star</WuIcon>` | ❌ |
14
+ | `<div>Hello</div>` | ❌ |
15
+ | `<WuButton data-skip>Hello</WuButton>` | ❌ |
16
+ | `<span data-i18n-wrapper>Hello</span>` | ✅ `<WuTranslate __i18nKey="Hello" />` |
17
+ | `<WuButton data-i18n-key="k">Hello</WuButton>` | ✅ `<WuTranslate __i18nKey="k" />` |
18
+ | `<WuButton>&amp;</WuButton>` | ❌ |
19
+ | `<WuButton>Hello &amp; World</WuButton>` | ✅ `<WuTranslate __i18nKey="Hello" /> &amp; <WuTranslate __i18nKey="World" />` |
20
20
 
21
21
  ## JSX string expressions
22
22
 
23
- | Input | Output |
24
- |---|---|
25
- | `<WuButton>{"Hello"}</WuButton>` | ✅ `<WuTranslate __i18nKey="Hello" />` |
26
- | `` <WuButton>{`Hello`}</WuButton> `` | ✅ `<WuTranslate __i18nKey="Hello" />` |
27
- | `<WuButton>{variable}</WuButton>` | ❌ |
23
+ | Input | Output |
24
+ | ---------------------------------- | -------------------------------------- |
25
+ | `<WuButton>{"Hello"}</WuButton>` | ✅ `<WuTranslate __i18nKey="Hello" />` |
26
+ | ``<WuButton>{`Hello`}</WuButton>`` | ✅ `<WuTranslate __i18nKey="Hello" />` |
27
+ | `<WuButton>{variable}</WuButton>` | ❌ |
28
28
 
29
29
  ## JSX ternaries
30
30
 
31
- | Input | Output |
32
- |---|---|
33
- | `<WuButton>{flag ? "Yes" : "No"}</WuButton>` | ✅ `{flag ? <WuTranslate __i18nKey="Yes" /> : <WuTranslate __i18nKey="No" />}` |
34
- | `<WuButton>{flag ? "Yes" : variable}</WuButton>` | ✅ `{flag ? <WuTranslate __i18nKey="Yes" /> : variable}` |
35
- | `<WuButton>{flag ? variable : variable}</WuButton>` | ❌ |
36
- | `<WuButton>{a ? "A" : b ? "B" : "C"}</WuButton>` | ✅ `{a ? <WuTranslate __i18nKey="A" /> : b ? <WuTranslate __i18nKey="B" /> : <WuTranslate __i18nKey="C" />}` |
31
+ | Input | Output |
32
+ | --------------------------------------------------- | ------------------------------------------------------------------------------------------------------------ |
33
+ | `<WuButton>{flag ? "Yes" : "No"}</WuButton>` | ✅ `{flag ? <WuTranslate __i18nKey="Yes" /> : <WuTranslate __i18nKey="No" />}` |
34
+ | `<WuButton>{flag ? "Yes" : variable}</WuButton>` | ✅ `{flag ? <WuTranslate __i18nKey="Yes" /> : variable}` |
35
+ | `<WuButton>{flag ? variable : variable}</WuButton>` | ❌ |
36
+ | `<WuButton>{a ? "A" : b ? "B" : "C"}</WuButton>` | ✅ `{a ? <WuTranslate __i18nKey="A" /> : b ? <WuTranslate __i18nKey="B" /> : <WuTranslate __i18nKey="C" />}` |
37
37
 
38
38
  ## JSX template literals with expressions
39
39
 
40
- | Input | Output |
41
- |---|---|
42
- | `` <WuButton>{`Hello ${name}`}</WuButton> `` | ✅ `<><WuTranslate __i18nKey="Hello" /> {name}</>` |
43
- | `` <WuButton>{`${name} world`}</WuButton> `` | ✅ `<>{name} <WuTranslate __i18nKey="world" /></>` |
44
- | `` <WuButton>{`Hello ${a} and ${b}`}</WuButton> `` | ✅ `<><WuTranslate __i18nKey="Hello" /> {a} <WuTranslate __i18nKey="and" /> {b}</>` |
45
- | `` <WuButton>{`${a}${b}`}</WuButton> `` | ❌ |
40
+ | Input | Output |
41
+ | ------------------------------------------------ | ----------------------------------------------------------------------------------- |
42
+ | ``<WuButton>{`Hello ${name}`}</WuButton>`` | ✅ `<><WuTranslate __i18nKey="Hello" /> {name}</>` |
43
+ | ``<WuButton>{`${name} world`}</WuButton>`` | ✅ `<>{name} <WuTranslate __i18nKey="world" /></>` |
44
+ | ``<WuButton>{`Hello ${a} and ${b}`}</WuButton>`` | ✅ `<><WuTranslate __i18nKey="Hello" /> {a} <WuTranslate __i18nKey="and" /> {b}</>` |
45
+ | ``<WuButton>{`${a}${b}`}</WuButton>`` | ❌ |
46
46
 
47
47
  ## JSX mixed children
48
48
 
49
- | Input | Output |
50
- |---|---|
49
+ | Input | Output |
50
+ | ----------------------------------- | --------------------------------------------- |
51
51
  | `<WuButton>Hello {name}</WuButton>` | ✅ `<WuTranslate __i18nKey="Hello" /> {name}` |
52
- | `<WuButton>{a} and {b}</WuButton>` | ✅ `{a} <WuTranslate __i18nKey="and" /> {b}` |
53
- | `<WuButton>{a} {b}</WuButton>` | ❌ |
52
+ | `<WuButton>{a} and {b}</WuButton>` | ✅ `{a} <WuTranslate __i18nKey="and" /> {b}` |
53
+ | `<WuButton>{a} {b}</WuButton>` | ❌ |
54
54
 
55
55
  ## JSX props
56
56
 
57
57
  Defaults: `Label`, `placeholder`, `title`, `aria-label`, `aria-placeholder`.
58
58
 
59
- | Input | Output |
60
- |---|---|
61
- | `<WuField Label="First name" />` | ✅ `Label={wt("First name")}` |
59
+ | Input | Output |
60
+ | -------------------------------------- | ----------------------------------- |
61
+ | `<WuField Label="First name" />` | ✅ `Label={wt("First name")}` |
62
62
  | `<WuInput placeholder="Enter name" />` | ✅ `placeholder={wt("Enter name")}` |
63
- | `<WuDialog title="Confirm?" />` | ✅ `title={wt("Confirm?")}` |
64
- | `<WuField Label={variable} />` | ❌ |
65
- | `<WuField Label="" />` | ❌ |
66
- | `<WuIcon Label="x" />` | ❌ |
67
- | `<input placeholder="x" />` | ❌ |
68
- | `<WuField data-skip Label="x" />` | ❌ |
63
+ | `<WuDialog title="Confirm?" />` | ✅ `title={wt("Confirm?")}` |
64
+ | `<WuField Label={variable} />` | ❌ |
65
+ | `<WuField Label="" />` | ❌ |
66
+ | `<WuIcon Label="x" />` | ❌ |
67
+ | `<input placeholder="x" />` | ❌ |
68
+ | `<WuField data-skip Label="x" />` | ❌ |
69
69
 
70
70
  ## `wt()` calls
71
71
 
72
- Plugin records static args into `wick-ui-i18n.json`. No code rewrite unless template literal with expressions.
72
+ Plugin records static args into `wick-ui-i18n.json`. No code rewrite unless
73
+ template literal with expressions.
73
74
 
74
- | Input | Dictionary | Code output |
75
- |---|---|---|
76
- | `wt("Hello")` | ✅ `"Hello"` | `wt("Hello")` |
77
- | `` wt(`Hello`) `` | ✅ `"Hello"` | `` wt(`Hello`) `` |
78
- | `` wt(`Hello ${name}`) `` | ✅ `"Hello"` | `` `${wt("Hello")} ${name}` `` |
79
- | `` wt(`Hello ${a} and ${b}`) `` | ✅ `"Hello"`, `"and"` | `` `${wt("Hello")} ${a} ${wt("and")} ${b}` `` |
80
- | `wt(variable)` | ❌ | — |
81
- | `` wt(`${a}${b}`) `` | ❌ | — |
75
+ | Input | Dictionary | Code output |
76
+ | ----------------------------- | --------------------- | --------------------------------------------- |
77
+ | `wt("Hello")` | ✅ `"Hello"` | `wt("Hello")` |
78
+ | ``wt(`Hello`)`` | ✅ `"Hello"` | ``wt(`Hello`)`` |
79
+ | ``wt(`Hello ${name}`)`` | ✅ `"Hello"` | `` `${wt("Hello")} ${name}` `` |
80
+ | ``wt(`Hello ${a} and ${b}`)`` | ✅ `"Hello"`, `"and"` | `` `${wt("Hello")} ${a} ${wt("and")} ${b}` `` |
81
+ | `wt(variable)` | ❌ | — |
82
+ | ``wt(`${a}${b}`)`` | ❌ | — |
82
83
 
83
84
  ## Data files (`extractFromKeys` option)
84
85
 
85
86
  No code rewrite — keys only recorded in `wick-ui-i18n.json`.
86
87
 
87
- | Input | Dictionary |
88
- |---|---|
88
+ | Input | Dictionary |
89
+ | ------------------------------------------------------- | ---------------- |
89
90
  | `{ label: 'Analytics' }` + `extractFromKeys: ['label']` | ✅ `"Analytics"` |
90
- | `{ label: variable }` | ❌ |
91
- | `{ label: '' }` | ❌ |
91
+ | `{ label: variable }` | ❌ |
92
+ | `{ label: '' }` | ❌ |
92
93
 
93
94
  ---
94
95
 
95
96
  ## Options
96
97
 
97
- | Option | Default | Description |
98
- |---|---|---|
99
- | `components` | `[]` | Extra components treated like Wu* |
100
- | `ignoreComponents` | `[]` | Extra components never translated |
101
- | `translatableProps` | `['Label','placeholder','title','aria-label','aria-placeholder']` | Props rewritten to `wt()` |
102
- | `extractFromKeys` | `[]` | Object keys extracted into dictionary |
103
- | `excludeFiles` | — | Files skipped entirely |
104
- | `debug` | `false` | Log transforms to console |
98
+ | Option | Default | Description |
99
+ | ------------------- | ----------------------------------------------------------------- | ------------------------------------- |
100
+ | `components` | `[]` | Extra components treated like Wu\* |
101
+ | `ignoreComponents` | `[]` | Extra components never translated |
102
+ | `translatableProps` | `['Label','placeholder','title','aria-label','aria-placeholder']` | Props rewritten to `wt()` |
103
+ | `extractFromKeys` | `[]` | Object keys extracted into dictionary |
104
+ | `excludeFiles` | — | Files skipped entirely |
105
+ | `debug` | `false` | Log transforms to console |
package/index.d.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  import type {Plugin} from 'vite'
2
2
 
3
+ // eslint-disable-next-line @typescript-eslint/naming-convention
3
4
  export interface WickI18nOptions {
4
5
  /** Extra component names to translate (in addition to Wu* components). */
5
6
  components?: string[]
package/index.js CHANGED
@@ -18,10 +18,10 @@
18
18
  * };
19
19
  */
20
20
 
21
- import { createFilter } from "vite";
22
- import { TranslationProcessor } from "./src/processor.js";
23
- import { transformFile } from "./src/transform.js";
24
- import { printReport } from "./src/debug.js";
21
+ import {createFilter} from 'vite'
22
+ import {TranslationProcessor} from './src/processor.js'
23
+ import {transformFile} from './src/transform.js'
24
+ import {printReport} from './src/debug.js'
25
25
 
26
26
  /**
27
27
  * @typedef {object} WickI18nOptions
@@ -46,15 +46,15 @@ export default function wickuiI18nPlugin(options = {}) {
46
46
  translatableProps: options.translatableProps,
47
47
  extractFromKeys: options.extractFromKeys,
48
48
  debug: options.debug,
49
- });
49
+ })
50
50
 
51
- const filter = createFilter([/\.(jsx|tsx|ts)$/], options.excludeFiles);
51
+ const filter = createFilter([/\.(jsx|tsx|ts)$/], options.excludeFiles)
52
52
 
53
- let base = "/";
53
+ let base = '/'
54
54
 
55
55
  return {
56
- name: "wick-ui-i18n",
57
- enforce: "pre",
56
+ name: 'wick-ui-i18n',
57
+ enforce: 'pre',
58
58
 
59
59
  /**
60
60
  * Capture the resolved base so the dev-server middleware path matches
@@ -63,7 +63,7 @@ export default function wickuiI18nPlugin(options = {}) {
63
63
  * @param {import('vite').ResolvedConfig} resolvedConfig
64
64
  */
65
65
  configResolved(resolvedConfig) {
66
- base = resolvedConfig.base;
66
+ base = resolvedConfig.base
67
67
  },
68
68
 
69
69
  /**
@@ -71,8 +71,8 @@ export default function wickuiI18nPlugin(options = {}) {
71
71
  * watch-mode rebuilds.
72
72
  */
73
73
  buildStart() {
74
- processor.dictionary.clear();
75
- processor.entries = [];
74
+ processor.dictionary.clear()
75
+ processor.entries = []
76
76
  },
77
77
 
78
78
  /**
@@ -84,14 +84,14 @@ export default function wickuiI18nPlugin(options = {}) {
84
84
  */
85
85
  transform(code, id) {
86
86
  const hasAnyTarget =
87
- code.includes("Wu") ||
87
+ code.includes('Wu') ||
88
88
  /\bwt\(/.test(code) ||
89
89
  (processor.components.size > 0 &&
90
90
  [...processor.components].some(c => code.includes(c))) ||
91
91
  (processor.extractFromKeys.size > 0 &&
92
- [...processor.extractFromKeys].some(k => code.includes(k)));
93
- if (!filter(id) || !hasAnyTarget) return null;
94
- return transformFile(code, id, processor);
92
+ [...processor.extractFromKeys].some(k => code.includes(k)))
93
+ if (!filter(id) || !hasAnyTarget) return null
94
+ return transformFile(code, id, processor)
95
95
  },
96
96
 
97
97
  /**
@@ -101,26 +101,26 @@ export default function wickuiI18nPlugin(options = {}) {
101
101
  */
102
102
  configureServer(server) {
103
103
  server.middlewares.use(`${base}wick-ui-i18n.json`, (_req, res) => {
104
- res.setHeader("Content-Type", "application/json");
104
+ res.setHeader('Content-Type', 'application/json')
105
105
  res.end(
106
106
  JSON.stringify(Object.fromEntries(processor.dictionary), null, 2),
107
- );
108
- });
107
+ )
108
+ })
109
109
  },
110
110
 
111
111
  /** Emit the translation dictionary as a build asset and print debug table. */
112
112
  generateBundle() {
113
113
  this.emitFile({
114
- type: "asset",
115
- fileName: "wick-ui-i18n.json",
114
+ type: 'asset',
115
+ fileName: 'wick-ui-i18n.json',
116
116
  source: JSON.stringify(
117
117
  Object.fromEntries(processor.dictionary),
118
118
  null,
119
119
  2,
120
120
  ),
121
- });
121
+ })
122
122
 
123
- printReport(processor.entries);
123
+ printReport(processor.entries)
124
124
  },
125
- };
125
+ }
126
126
  }
package/package.json CHANGED
@@ -1,10 +1,10 @@
1
1
  {
2
2
  "name": "@npm-questionpro/wick-ui-i18n",
3
- "version": "0.14.0",
3
+ "version": "2.0.0-next.4",
4
+ "private": false,
4
5
  "license": "ISC",
5
6
  "description": "Auto-translation AST wrapper for Wick UI",
6
7
  "type": "module",
7
- "main": "index.js",
8
8
  "types": "index.d.ts",
9
9
  "exports": {
10
10
  ".": {
@@ -13,19 +13,36 @@
13
13
  }
14
14
  },
15
15
  "peerDependencies": {
16
- "vite": "^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0"
16
+ "vite": "^8.0.15"
17
17
  },
18
18
  "devDependencies": {
19
19
  "@types/babel__traverse": "^7.28.0",
20
- "vite": "^7.3.1",
21
- "vitest": "^3.2.4"
20
+ "vite": "^8.0.15",
21
+ "vitest": "^4.1.8",
22
+ "@vitest/coverage-v8": "^4.1.8",
23
+ "eslint": "^10.4.1",
24
+ "@npm-questionpro/wick-ui-eslint-config": "1.0.0",
25
+ "@wick-ui/tsconfig": "1.0.0"
22
26
  },
23
27
  "dependencies": {
24
28
  "@babel/parser": "^7.29.0",
25
29
  "@babel/traverse": "^7.29.0",
26
30
  "magic-string": "^0.30.21"
27
31
  },
32
+ "files": [
33
+ "index.js",
34
+ "index.d.ts",
35
+ "src",
36
+ "llms.txt"
37
+ ],
38
+ "prettier": "@npm-questionpro/wick-ui-prettier-config",
28
39
  "scripts": {
29
- "test": "vitest run"
40
+ "test": "vitest run",
41
+ "test:watch": "vitest",
42
+ "test:ci": "vitest run --coverage",
43
+ "format": "prettier --write .",
44
+ "format:ci": "prettier --check .",
45
+ "lint": "eslint . --fix",
46
+ "lint:ci": "eslint --max-warnings 0 ."
30
47
  }
31
48
  }
package/src/debug.js CHANGED
@@ -4,7 +4,7 @@
4
4
  * after the bundle is generated.
5
5
  */
6
6
 
7
- import { basename } from "node:path";
7
+ import {basename} from 'node:path'
8
8
 
9
9
  /**
10
10
  * Walk up the Babel path and collect JSX element names from outermost inward.
@@ -13,17 +13,17 @@ import { basename } from "node:path";
13
13
  * @returns {string} e.g. `"WuProvider > div > WuButton"`
14
14
  */
15
15
  export function getComponentTree(path) {
16
- const parts = [];
17
- path.findParent((p) => {
16
+ const parts = []
17
+ path.findParent(p => {
18
18
  if (p.isJSXElement()) {
19
19
  const name =
20
20
  p.node.openingElement.name.name ||
21
- p.node.openingElement.name.property?.name;
22
- if (name) parts.unshift(name);
21
+ p.node.openingElement.name.property?.name
22
+ if (name) parts.unshift(name)
23
23
  }
24
- return false;
25
- });
26
- return parts.join(" > ") || "(root)";
24
+ return false
25
+ })
26
+ return parts.join(' > ') || '(root)'
27
27
  }
28
28
 
29
29
  /**
@@ -42,39 +42,38 @@ export function getComponentTree(path) {
42
42
  */
43
43
  export function printReport(entries) {
44
44
  if (!entries.length) {
45
- console.log("\n[wick-i18n] No translations captured.\n");
46
- return;
45
+ console.log('\n[wick-i18n] No translations captured.\n')
46
+ return
47
47
  }
48
48
 
49
- const headers = ["Text", "File", "Component Tree"];
49
+ const headers = ['Text', 'File', 'Component Tree']
50
50
 
51
- const rows = entries.map((e) => [e.text, basename(e.file), e.componentTree]);
51
+ const rows = entries.map(e => [e.text, basename(e.file), e.componentTree])
52
52
 
53
- const cols = headers.length;
54
53
  const widths = headers.map((h, i) =>
55
- Math.max(h.length, ...rows.map((r) => r[i].length)),
56
- );
54
+ Math.max(h.length, ...rows.map(r => r[i].length)),
55
+ )
57
56
 
58
- const pad = (str, w) => str.padEnd(w);
57
+ const pad = (str, w) => str.padEnd(w)
59
58
  const sep = (l, m, r, fill) =>
60
- l + widths.map((w) => fill.repeat(w + 2)).join(m) + r;
59
+ l + widths.map(w => fill.repeat(w + 2)).join(m) + r
61
60
 
62
- const top = sep("", "", "", "");
63
- const mid = sep("", "", "", "");
64
- const bottom = sep("", "", "", "");
65
- const row = (cells) =>
66
- "" + cells.map((c, i) => ` ${pad(c, widths[i])} `).join("") + "";
61
+ const top = sep('', '', '', '')
62
+ const mid = sep('', '', '', '')
63
+ const bottom = sep('', '', '', '')
64
+ const row = cells =>
65
+ '' + cells.map((c, i) => ` ${pad(c, widths[i])} `).join('') + ''
67
66
 
68
67
  const lines = [
69
- "",
68
+ '',
70
69
  `[wick-i18n] Build report — ${entries.length} translation(s) captured`,
71
70
  top,
72
71
  row(headers),
73
72
  mid,
74
73
  ...rows.map(row),
75
74
  bottom,
76
- "",
77
- ];
75
+ '',
76
+ ]
78
77
 
79
- console.log(lines.join("\n"));
78
+ console.log(lines.join('\n'))
80
79
  }