@wangs-ui/skills 1.0.59 → 1.0.61

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/dist/bin.js CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { i as listSkills, n as updateSkills, r as addSkills, t as removeSkills } from "./src-CmtJDo3Y.js";
2
+ import { i as listSkills, n as updateSkills, r as addSkills, t as removeSkills } from "./src-CusYgPAm.js";
3
3
  import path from "node:path";
4
4
  import { parseArgs } from "node:util";
5
5
  //#region bin.ts
package/dist/index.js CHANGED
@@ -1,2 +1,2 @@
1
- import { a as getAgentSkillDirs, c as isSkillInstalled, d as loadAllSkills, i as listSkills, l as removeSkill, n as updateSkills, o as getInstalledSkills, r as addSkills, s as installSkill, t as removeSkills, u as getSkill } from "./src-CmtJDo3Y.js";
1
+ import { a as getAgentSkillDirs, c as isSkillInstalled, d as loadAllSkills, i as listSkills, l as removeSkill, n as updateSkills, o as getInstalledSkills, r as addSkills, s as installSkill, t as removeSkills, u as getSkill } from "./src-CusYgPAm.js";
2
2
  export { addSkills, getAgentSkillDirs, getInstalledSkills, getSkill, installSkill, isSkillInstalled, listSkills, loadAllSkills, removeSkill, removeSkills, updateSkills };
@@ -1,17 +1,17 @@
1
1
  ---
2
2
  name: i18n-usage
3
- description: Guidelines, formatting rules, and MCP discovery protocol for internationalization with @wangs-ui/react-i18n and localized components.
3
+ description: Comprehensive guidelines for application internationalization, JIT translations (t), ICU formatting, and locale-aware formatting with @wangs-ui/react-i18n.
4
4
  ---
5
5
 
6
- # Skill: Application Internationalization & Localization Protocol
6
+ # Skill: Application Internationalization & Formatting Protocol
7
7
 
8
- Use this skill when handling multi-language interfaces, currency inputs, localized date formats, or dynamic text translations in Wangs UI applications.
8
+ Use this skill when implementing multi-language interfaces, translating user-facing text, formatting dates, times, currencies, or numbers in React applications built with Wangs UI and `@wangs-ui/react-i18n`.
9
9
 
10
10
  ---
11
11
 
12
- ## 1. MCP Inspection Protocol (Single Source of Truth)
12
+ ## 1. The MCP Discovery Protocol (Single Source of Truth)
13
13
 
14
- Do **NOT** guess component localization props or language switcher variants. Query the MCP server dynamically to inspect exact contracts and live story implementations:
14
+ Do **NOT** guess component localization contracts, language switcher variants, or datepicker props. Query the MCP server dynamically to inspect exact props and live story implementations:
15
15
 
16
16
  ### Inspect Localized Component Contracts:
17
17
 
@@ -19,6 +19,8 @@ Do **NOT** guess component localization props or language switcher variants. Que
19
19
  get-documentation({ "id": "languageswitcher" })
20
20
  get-documentation({ "id": "currencyinput" })
21
21
  get-documentation({ "id": "datepicker" })
22
+ get-documentation({ "id": "select" })
23
+ get-documentation({ "id": "datatable" })
22
24
  ```
23
25
 
24
26
  ### Inspect Live Story Implementations:
@@ -31,52 +33,200 @@ get-documentation-for-story({ "id": "datepicker", "storyName": "Default" })
31
33
 
32
34
  ---
33
35
 
34
- ## 2. Translation Syntax & Golden Rules
36
+ ## 2. Root Provider Setup (`WangsUiI18nProvider`)
35
37
 
36
- 1. **Sentence Keys in Natural English**:
37
- Always write human-readable English sentence keys:
38
+ Wrap the application root with `WangsUiI18nProvider` from `@wangs-ui/react-i18n` to enable dynamic JIT translations, versioned cache invalidation, and locale context:
38
39
 
39
- ```tsx
40
- // Good
41
- t('Invoice Summary');
42
- t('Are you sure you want to delete this customer?');
40
+ ```tsx
41
+ import { WangsUiI18nProvider } from '@wangs-ui/react-i18n';
42
+ import React from 'react';
43
+ import ReactDOM from 'react-dom/client';
44
+ import App from './App';
43
45
 
44
- // ❌ Bad — artificial dotted keys
45
- t('invoice.summary.title');
46
- ```
46
+ ReactDOM.createRoot(document.getElementById('root')!).render(
47
+ <React.StrictMode>
48
+ <WangsUiI18nProvider defaultLocale="en" baseUrl={import.meta.env.VITE_API_URL || ''}>
49
+ <App />
50
+ </WangsUiI18nProvider>
51
+ </React.StrictMode>,
52
+ );
53
+ ```
54
+
55
+ ---
56
+
57
+ ## 3. Translation Protocol with `useI18n()`
58
+
59
+ The `@wangs-ui/react-i18n` package uses a Just-In-Time (JIT) translation architecture where natural English text strings serve as database keys.
60
+
61
+ ### A. Consumer-Level Translation for `ReactNode` Props (Mandatory)
62
+
63
+ All user-facing text props in Wangs UI components (`placeholder`, `label`, `emptyMessage`, `header`, `tooltip`, etc.) are typed as `ReactNode` and rendered as-is. Components do **NOT** automatically translate custom strings. Translation **MUST** be called at the application/consumer level:
64
+
65
+ ```tsx
66
+ import { useI18n } from '@wangs-ui/react-i18n';
67
+ import Button from '@wangs-ui/react-core/primitive/button';
68
+ import DataTable from '@wangs-ui/react-core/primitive/datatable';
69
+ import Select from '@wangs-ui/react-core/primitive/select';
70
+
71
+ export function OrderList() {
72
+ const { t } = useI18n();
73
+
74
+ return (
75
+ <div>
76
+ <Select placeholder={t('Search category...')} />
77
+ <DataTable emptyMessage={t('No orders found')} />
78
+ <Button label={t('Create new order')} />
79
+ </div>
80
+ );
81
+ }
82
+ ```
83
+
84
+ ### B. Natural English Sentence Keys
47
85
 
48
- 2. **Dynamic Variables in Double Braces (`{{var}}`)**:
49
- Pass variables as an object using `{{variableName}}` interpolation:
86
+ Always write full, natural English sentences as translation keys. Never use artificial dotted namespace keys:
50
87
 
51
- ```tsx
52
- // ✅ Good
53
- t('Welcome back, {{name}}!', { name: user.name });
88
+ ```tsx
89
+ // ✅ Good — Natural English
90
+ t('Invoice Summary');
91
+ t('Are you sure you want to delete this customer?');
54
92
 
55
- // ❌ Bad — string concatenation breaks translation word order
56
- t('Welcome back, ') + user.name + '!';
57
- ```
93
+ // ❌ Bad — Artificial dotted keys
94
+ t('invoice.summary.title');
95
+ t('dialog.delete.customer.confirm');
96
+ ```
97
+
98
+ ### C. Named Variable Interpolation (Single Braces `{var}`)
99
+
100
+ Pass interpolation values inside a plain object using descriptive named variables. This provides crucial semantic context for AI translation engines:
101
+
102
+ ```tsx
103
+ // ✅ Good — Named variables provide context
104
+ t('Upload {count} files to {groupName}', { count: 5, groupName: 'Marketing' });
105
+ t('Welcome back, {userName}!', { userName: user.name });
106
+
107
+ // ❌ Bad — Concatenation or positional arguments
108
+ t('Welcome back, ' + user.name);
109
+ t('Upload {0} files to {1}', 5, 'Marketing');
110
+ ```
58
111
 
59
- 3. **Pluralization with ICU Formats**:
60
- Use ICU plural format for quantity-dependent sentences:
112
+ ### D. ICU Pluralization & Zero-State (`=0`)
61
113
 
62
- ```tsx
63
- t('{count, plural, =0 {No items selected} one {# item selected} other {# items selected}}', {
64
- count: selectedCount,
65
- });
66
- ```
114
+ Always handle singular, plural, and zero states directly within ICU MessageFormat strings. Do **NOT** use JavaScript ternary operators:
67
115
 
68
- 4. **Runtime Locale Switching**:
69
- Use the `useI18n()` hook to read or update active language:
70
- ```tsx
71
- import { useI18n } from '@wangs-ui/react-i18n';
116
+ ```tsx
117
+ // Good Clean ICU pluralization with zero-state handling
118
+ t('{count, plural, =0 {No items selected} one {1 item selected} other {{count} items selected}}', {
119
+ count: selectedCount,
120
+ });
72
121
 
73
- const { t, currentLocale, setLocale } = useI18n();
74
- ```
122
+ // Bad Manual JS branching
123
+ selectedCount === 0
124
+ ? t('No items selected')
125
+ : selectedCount === 1
126
+ ? t('1 item selected')
127
+ : t('{count} items selected', { count: selectedCount });
128
+ ```
129
+
130
+ ### E. Rich Text / Annotated Strings
131
+
132
+ Use standard supported HTML tags (`<a>`, `<b>`, `<i>`, `<u>`, `<s>`, `<br/>`, `<sub>`, `<sup>`, `<code>`, `<mark>`) for inline styling. Tags are automatically parsed into React elements without custom regex or string manipulation:
133
+
134
+ ```tsx
135
+ import Link from '@wangs-ui/foundation/theme/Link';
136
+
137
+ t('You have selected <b>{count} items</b>. Click <a>here</a> to review.', {
138
+ count: selectedCount,
139
+ a: (chunks) => <Link href="/review">{chunks}</Link>,
140
+ });
141
+ ```
142
+
143
+ ---
144
+
145
+ ## 4. Locale Formatting Protocol with `useLocaleFormatter()`
146
+
147
+ For locale-aware formatting of dates, relative times, currencies, numbers, and display names, use the dedicated `useLocaleFormatter()` hook. All functions automatically adapt to the active locale without triggering backend database requests:
148
+
149
+ ```tsx
150
+ import { useLocaleFormatter } from '@wangs-ui/react-i18n';
151
+
152
+ export function SummaryCard({ updatedAt, amount, count }: Props) {
153
+ const {
154
+ formatDate,
155
+ formatRelativeTime,
156
+ formatCurrency,
157
+ formatNumber,
158
+ formatDisplayName,
159
+ formatList,
160
+ truncateText,
161
+ } = useLocaleFormatter();
162
+
163
+ return (
164
+ <div>
165
+ {/* Date formatting with Go tokens or date-fns tokens, and timezone */}
166
+ <p>{formatDate(new Date(), 'dd MMMM yyyy, HH:mm', 'Asia/Jakarta')}</p>
167
+
168
+ {/* Relative time */}
169
+ <p>{formatRelativeTime(updatedAt)}</p>
170
+
171
+ {/* Currency formatting */}
172
+ <p>{formatCurrency(amount, 'IDR')}</p>
173
+
174
+ {/* Number formatting with locale grouping */}
175
+ <p>{formatNumber(count)}</p>
176
+
177
+ {/* ISO code to localized name */}
178
+ <p>{formatDisplayName('id', 'language')}</p>
179
+
180
+ {/* Localized list */}
181
+ <p>{formatList(['Finance', 'Operations', 'IT'])}</p>
182
+
183
+ {/* Emoji & multi-byte safe text truncation */}
184
+ <p>{truncateText('Long product description with emojis 🚀', 20)}</p>
185
+ </div>
186
+ );
187
+ }
188
+ ```
189
+
190
+ > [!NOTE]
191
+ > Formatters MUST NOT be called as standalone `t()` keys (e.g. `t(formatRelativeTime(date))`). Instead, pass the formatted result as a named variable:
192
+ >
193
+ > ```tsx
194
+ > const { t } = useI18n();
195
+ > const { formatRelativeTime } = useLocaleFormatter();
196
+ > const label = t('Updated {time}', { time: formatRelativeTime(updatedAt) });
197
+ > ```
198
+
199
+ ---
200
+
201
+ ## 5. Language Switching UI Integration
202
+
203
+ Connect the Wangs UI `LanguageSwitcher` primitive directly with `useI18n()` state:
204
+
205
+ ```tsx
206
+ import LanguageSwitcher from '@wangs-ui/react-core/primitive/languageswitcher';
207
+ import { useI18n } from '@wangs-ui/react-i18n';
208
+
209
+ export function HeaderLanguageSwitcher() {
210
+ const { locale, setLocale, languageOptions } = useI18n();
211
+
212
+ return (
213
+ <LanguageSwitcher
214
+ options={languageOptions}
215
+ value={locale}
216
+ onChange={(code) => setLocale(code)}
217
+ />
218
+ );
219
+ }
220
+ ```
75
221
 
76
222
  ---
77
223
 
78
- ## 3. Mandatory Implementation Rules
224
+ ## 6. Strict Behavioral Constraints (MUST NOT)
79
225
 
80
- 1. **Inspect Localized Components via MCP**: Query `currencyinput` and `datepicker` documentation before binding locale-sensitive formatters.
81
- 2. **Never Hardcode User-Facing Text**: Every visible label, placeholder, dialog title, tooltip, and error message in the application must pass through `t()`.
82
- 3. **Keep Context Intact**: Do not split sentences into separate phrases across JSX elements; translate the full sentence as a single unit.
226
+ - **NO Formatters Destructured from `useI18n()`:** Formatters are isolated in `useLocaleFormatter()`. Never attempt to import `formatDate` or `formatCurrency` from `useI18n()`.
227
+ - **NO String Concatenation in `t()` Keys:** Never concatenate strings or use dynamic template literals (e.g. `t('Hello ' + user.name)` or ``t(`Hello ${user.name}`)``). This creates infinite distinct keys in the translation database and prevents caching.
228
+ - **NO Manual Zero-State JavaScript Branching:** Always use ICU `=0` syntax inside a single plural key.
229
+ - **NO Dotted Artificial Translation Keys:** Never use dotted keys like `t('app.header.title')`. Use natural English sentences.
230
+ - **NO Custom Markdown Formatting Symbols:** Do not use `*bold*` or `_italic_` in translation keys. Use valid HTML tags like `<b>bold</b>`.
231
+ - **NO Hardcoded Static Translation Dictionaries:** Do not bundle static translation files (`id.json`, `zh.json`). The JIT backend broker manages translations dynamically.
232
+ - **NO Unnecessary English Key Modifications:** Minor typos or punctuation changes in keys create orphaned entries in the translation backend and trigger new AI translation costs.
@@ -12,7 +12,7 @@ var SKILL_default$6 = "---\nname: data-table\ndescription: Architecture, workflo
12
12
  var SKILL_default$5 = "---\nname: dialog-modal\ndescription: Patterns, overlay selection criteria, and MCP discovery protocol for Dialog, Modal, and DialogForm components in Wangs UI.\n---\n\n# Skill: Dialog, Modal & Overlay Workflows\n\nUse this skill when building interactive modals, create/edit dialog forms, destructive action confirmations, or slide-in overlay panels.\n\n---\n\n## 1. MCP Inspection Protocol (Mandatory Single Source of Truth)\n\nDo **NOT** guess overlay props, event names, or footer slots. Query the MCP server dynamically to inspect exact contracts and live story implementations:\n\n### Inspect Overlay Contracts:\n\n```json\nget-documentation({ \"id\": \"dialog\" })\nget-documentation({ \"id\": \"dialogform\" })\nget-documentation({ \"id\": \"modal\" })\nget-documentation({ \"id\": \"toast\" })\n```\n\n### Inspect Live Story Implementations:\n\n```json\nget-documentation-for-story({ \"id\": \"dialog\", \"storyName\": \"Confirmation\" })\nget-documentation-for-story({ \"id\": \"dialogform\", \"storyName\": \"Default\" })\nget-documentation-for-story({ \"id\": \"modal\", \"storyName\": \"Default\" })\n```\n\n### Inspect Knowledge Graph & Usages:\n\n```json\nquery_graph({ \"query\": \"Dialog\" })\nquery_graph({ \"query\": \"DialogForm\" })\n```\n\n---\n\n## 2. Overlay Selection Matrix\n\n| Component | Primary Use Case | Key Characteristics |\n| :--------------- | :-------------------------------------------- | :------------------------------------------------------------------------------------ |\n| **`Dialog`** | Confirmations, alerts, simple detail previews | Standard `header`, `footer`, and body layout; built-in backdrop dimming. |\n| **`DialogForm`** | Create/Edit forms embedded inside a dialog | Built-in form submit/cancel action bar, dirty state tracking, and submit lifecycle. |\n| **`Modal`** | Slide-in drawers, complex custom viewports | Headless overlay primitive with flexible animations, size variants, and drawer modes. |\n\n---\n\n## 3. Mandatory Implementation Rules\n\n1. **Query MCP for Current Code Patterns**: Always inspect `dialog`, `dialogform`, or `modal` stories via MCP before writing overlay code.\n2. **Strict Subpath Imports**: Import via `@wangs-ui/react-core/primitive/dialog`, `@wangs-ui/react-core/primitive/dialogform`, `@wangs-ui/react-core/primitive/modal`, or `@wangs-ui/react-core/primitive/toast`.\n3. **Prevent Dismissal During Async Mutations**: Guard the close handler so users cannot accidentally dismiss the dialog while a mutation request is in-flight.\n4. **Coordinate with Toast Notifications**: Trigger feedback toasts on successful creation, update, or deletion actions.\n5. **Translate All Overlay Copy**: All dialog titles, confirmation descriptions, and button labels must be localized using `t('...')` from `@wangs-ui/react-i18n`.\n";
13
13
  //#endregion
14
14
  //#region skills/i18n-usage/SKILL.md?raw
15
- var SKILL_default$4 = "---\nname: i18n-usage\ndescription: Guidelines, formatting rules, and MCP discovery protocol for internationalization with @wangs-ui/react-i18n and localized components.\n---\n\n# Skill: Application Internationalization & Localization Protocol\n\nUse this skill when handling multi-language interfaces, currency inputs, localized date formats, or dynamic text translations in Wangs UI applications.\n\n---\n\n## 1. MCP Inspection Protocol (Single Source of Truth)\n\nDo **NOT** guess component localization props or language switcher variants. Query the MCP server dynamically to inspect exact contracts and live story implementations:\n\n### Inspect Localized Component Contracts:\n\n```json\nget-documentation({ \"id\": \"languageswitcher\" })\nget-documentation({ \"id\": \"currencyinput\" })\nget-documentation({ \"id\": \"datepicker\" })\n```\n\n### Inspect Live Story Implementations:\n\n```json\nget-documentation-for-story({ \"id\": \"languageswitcher\", \"storyName\": \"Basic\" })\nget-documentation-for-story({ \"id\": \"currencyinput\", \"storyName\": \"Basic\" })\nget-documentation-for-story({ \"id\": \"datepicker\", \"storyName\": \"Default\" })\n```\n\n---\n\n## 2. Translation Syntax & Golden Rules\n\n1. **Sentence Keys in Natural English**:\n Always write human-readable English sentence keys:\n\n ```tsx\n // ✅ Good\n t('Invoice Summary');\n t('Are you sure you want to delete this customer?');\n\n // ❌ Bad — artificial dotted keys\n t('invoice.summary.title');\n ```\n\n2. **Dynamic Variables in Double Braces (`{{var}}`)**:\n Pass variables as an object using `{{variableName}}` interpolation:\n\n ```tsx\n // ✅ Good\n t('Welcome back, {{name}}!', { name: user.name });\n\n // ❌ Bad — string concatenation breaks translation word order\n t('Welcome back, ') + user.name + '!';\n ```\n\n3. **Pluralization with ICU Formats**:\n Use ICU plural format for quantity-dependent sentences:\n\n ```tsx\n t('{count, plural, =0 {No items selected} one {# item selected} other {# items selected}}', {\n count: selectedCount,\n });\n ```\n\n4. **Runtime Locale Switching**:\n Use the `useI18n()` hook to read or update active language:\n ```tsx\n import { useI18n } from '@wangs-ui/react-i18n';\n\n const { t, currentLocale, setLocale } = useI18n();\n ```\n\n---\n\n## 3. Mandatory Implementation Rules\n\n1. **Inspect Localized Components via MCP**: Query `currencyinput` and `datepicker` documentation before binding locale-sensitive formatters.\n2. **Never Hardcode User-Facing Text**: Every visible label, placeholder, dialog title, tooltip, and error message in the application must pass through `t()`.\n3. **Keep Context Intact**: Do not split sentences into separate phrases across JSX elements; translate the full sentence as a single unit.\n";
15
+ var SKILL_default$4 = "---\nname: i18n-usage\ndescription: Comprehensive guidelines for application internationalization, JIT translations (t), ICU formatting, and locale-aware formatting with @wangs-ui/react-i18n.\n---\n\n# Skill: Application Internationalization & Formatting Protocol\n\nUse this skill when implementing multi-language interfaces, translating user-facing text, formatting dates, times, currencies, or numbers in React applications built with Wangs UI and `@wangs-ui/react-i18n`.\n\n---\n\n## 1. The MCP Discovery Protocol (Single Source of Truth)\n\nDo **NOT** guess component localization contracts, language switcher variants, or datepicker props. Query the MCP server dynamically to inspect exact props and live story implementations:\n\n### Inspect Localized Component Contracts:\n\n```json\nget-documentation({ \"id\": \"languageswitcher\" })\nget-documentation({ \"id\": \"currencyinput\" })\nget-documentation({ \"id\": \"datepicker\" })\nget-documentation({ \"id\": \"select\" })\nget-documentation({ \"id\": \"datatable\" })\n```\n\n### Inspect Live Story Implementations:\n\n```json\nget-documentation-for-story({ \"id\": \"languageswitcher\", \"storyName\": \"Basic\" })\nget-documentation-for-story({ \"id\": \"currencyinput\", \"storyName\": \"Basic\" })\nget-documentation-for-story({ \"id\": \"datepicker\", \"storyName\": \"Default\" })\n```\n\n---\n\n## 2. Root Provider Setup (`WangsUiI18nProvider`)\n\nWrap the application root with `WangsUiI18nProvider` from `@wangs-ui/react-i18n` to enable dynamic JIT translations, versioned cache invalidation, and locale context:\n\n```tsx\nimport { WangsUiI18nProvider } from '@wangs-ui/react-i18n';\nimport React from 'react';\nimport ReactDOM from 'react-dom/client';\nimport App from './App';\n\nReactDOM.createRoot(document.getElementById('root')!).render(\n <React.StrictMode>\n <WangsUiI18nProvider defaultLocale=\"en\" baseUrl={import.meta.env.VITE_API_URL || ''}>\n <App />\n </WangsUiI18nProvider>\n </React.StrictMode>,\n);\n```\n\n---\n\n## 3. Translation Protocol with `useI18n()`\n\nThe `@wangs-ui/react-i18n` package uses a Just-In-Time (JIT) translation architecture where natural English text strings serve as database keys.\n\n### A. Consumer-Level Translation for `ReactNode` Props (Mandatory)\n\nAll user-facing text props in Wangs UI components (`placeholder`, `label`, `emptyMessage`, `header`, `tooltip`, etc.) are typed as `ReactNode` and rendered as-is. Components do **NOT** automatically translate custom strings. Translation **MUST** be called at the application/consumer level:\n\n```tsx\nimport { useI18n } from '@wangs-ui/react-i18n';\nimport Button from '@wangs-ui/react-core/primitive/button';\nimport DataTable from '@wangs-ui/react-core/primitive/datatable';\nimport Select from '@wangs-ui/react-core/primitive/select';\n\nexport function OrderList() {\n const { t } = useI18n();\n\n return (\n <div>\n <Select placeholder={t('Search category...')} />\n <DataTable emptyMessage={t('No orders found')} />\n <Button label={t('Create new order')} />\n </div>\n );\n}\n```\n\n### B. Natural English Sentence Keys\n\nAlways write full, natural English sentences as translation keys. Never use artificial dotted namespace keys:\n\n```tsx\n// ✅ Good — Natural English\nt('Invoice Summary');\nt('Are you sure you want to delete this customer?');\n\n// ❌ Bad — Artificial dotted keys\nt('invoice.summary.title');\nt('dialog.delete.customer.confirm');\n```\n\n### C. Named Variable Interpolation (Single Braces `{var}`)\n\nPass interpolation values inside a plain object using descriptive named variables. This provides crucial semantic context for AI translation engines:\n\n```tsx\n// ✅ Good — Named variables provide context\nt('Upload {count} files to {groupName}', { count: 5, groupName: 'Marketing' });\nt('Welcome back, {userName}!', { userName: user.name });\n\n// ❌ Bad — Concatenation or positional arguments\nt('Welcome back, ' + user.name);\nt('Upload {0} files to {1}', 5, 'Marketing');\n```\n\n### D. ICU Pluralization & Zero-State (`=0`)\n\nAlways handle singular, plural, and zero states directly within ICU MessageFormat strings. Do **NOT** use JavaScript ternary operators:\n\n```tsx\n// ✅ Good — Clean ICU pluralization with zero-state handling\nt('{count, plural, =0 {No items selected} one {1 item selected} other {{count} items selected}}', {\n count: selectedCount,\n});\n\n// ❌ Bad — Manual JS branching\nselectedCount === 0\n ? t('No items selected')\n : selectedCount === 1\n ? t('1 item selected')\n : t('{count} items selected', { count: selectedCount });\n```\n\n### E. Rich Text / Annotated Strings\n\nUse standard supported HTML tags (`<a>`, `<b>`, `<i>`, `<u>`, `<s>`, `<br/>`, `<sub>`, `<sup>`, `<code>`, `<mark>`) for inline styling. Tags are automatically parsed into React elements without custom regex or string manipulation:\n\n```tsx\nimport Link from '@wangs-ui/foundation/theme/Link';\n\nt('You have selected <b>{count} items</b>. Click <a>here</a> to review.', {\n count: selectedCount,\n a: (chunks) => <Link href=\"/review\">{chunks}</Link>,\n});\n```\n\n---\n\n## 4. Locale Formatting Protocol with `useLocaleFormatter()`\n\nFor locale-aware formatting of dates, relative times, currencies, numbers, and display names, use the dedicated `useLocaleFormatter()` hook. All functions automatically adapt to the active locale without triggering backend database requests:\n\n```tsx\nimport { useLocaleFormatter } from '@wangs-ui/react-i18n';\n\nexport function SummaryCard({ updatedAt, amount, count }: Props) {\n const {\n formatDate,\n formatRelativeTime,\n formatCurrency,\n formatNumber,\n formatDisplayName,\n formatList,\n truncateText,\n } = useLocaleFormatter();\n\n return (\n <div>\n {/* Date formatting with Go tokens or date-fns tokens, and timezone */}\n <p>{formatDate(new Date(), 'dd MMMM yyyy, HH:mm', 'Asia/Jakarta')}</p>\n\n {/* Relative time */}\n <p>{formatRelativeTime(updatedAt)}</p>\n\n {/* Currency formatting */}\n <p>{formatCurrency(amount, 'IDR')}</p>\n\n {/* Number formatting with locale grouping */}\n <p>{formatNumber(count)}</p>\n\n {/* ISO code to localized name */}\n <p>{formatDisplayName('id', 'language')}</p>\n\n {/* Localized list */}\n <p>{formatList(['Finance', 'Operations', 'IT'])}</p>\n\n {/* Emoji & multi-byte safe text truncation */}\n <p>{truncateText('Long product description with emojis 🚀', 20)}</p>\n </div>\n );\n}\n```\n\n> [!NOTE]\n> Formatters MUST NOT be called as standalone `t()` keys (e.g. `t(formatRelativeTime(date))`). Instead, pass the formatted result as a named variable:\n>\n> ```tsx\n> const { t } = useI18n();\n> const { formatRelativeTime } = useLocaleFormatter();\n> const label = t('Updated {time}', { time: formatRelativeTime(updatedAt) });\n> ```\n\n---\n\n## 5. Language Switching UI Integration\n\nConnect the Wangs UI `LanguageSwitcher` primitive directly with `useI18n()` state:\n\n```tsx\nimport LanguageSwitcher from '@wangs-ui/react-core/primitive/languageswitcher';\nimport { useI18n } from '@wangs-ui/react-i18n';\n\nexport function HeaderLanguageSwitcher() {\n const { locale, setLocale, languageOptions } = useI18n();\n\n return (\n <LanguageSwitcher\n options={languageOptions}\n value={locale}\n onChange={(code) => setLocale(code)}\n />\n );\n}\n```\n\n---\n\n## 6. Strict Behavioral Constraints (MUST NOT)\n\n- **NO Formatters Destructured from `useI18n()`:** Formatters are isolated in `useLocaleFormatter()`. Never attempt to import `formatDate` or `formatCurrency` from `useI18n()`.\n- **NO String Concatenation in `t()` Keys:** Never concatenate strings or use dynamic template literals (e.g. `t('Hello ' + user.name)` or ``t(`Hello ${user.name}`)``). This creates infinite distinct keys in the translation database and prevents caching.\n- **NO Manual Zero-State JavaScript Branching:** Always use ICU `=0` syntax inside a single plural key.\n- **NO Dotted Artificial Translation Keys:** Never use dotted keys like `t('app.header.title')`. Use natural English sentences.\n- **NO Custom Markdown Formatting Symbols:** Do not use `*bold*` or `_italic_` in translation keys. Use valid HTML tags like `<b>bold</b>`.\n- **NO Hardcoded Static Translation Dictionaries:** Do not bundle static translation files (`id.json`, `zh.json`). The JIT backend broker manages translations dynamically.\n- **NO Unnecessary English Key Modifications:** Minor typos or punctuation changes in keys create orphaned entries in the translation backend and trigger new AI translation costs.\n";
16
16
  //#endregion
17
17
  //#region skills/layout-navigation/SKILL.md?raw
18
18
  var SKILL_default$3 = "---\nname: layout-navigation\ndescription: Architecture, navigation hierarchies, and MCP discovery protocol for AppLayout, Sidebar, Breadcrumb, and Tabs in Wangs UI.\n---\n\n# Skill: Application Layout & Navigation Hierarchy\n\nUse this skill when constructing application shells, multi-level sidebars, page headers, breadcrumbs, or tabbed views with `@wangs-ui/react-core`.\n\n---\n\n## 1. MCP Inspection Protocol (Mandatory Single Source of Truth)\n\nDo **NOT** guess layout block slots, sidebar item interfaces, or breadcrumb props. Query the MCP server dynamically to inspect exact contracts and live story implementations:\n\n### Inspect Layout & Navigation Contracts:\n\n```json\nget-documentation({ \"id\": \"applayout\" })\nget-documentation({ \"id\": \"sidebar\" })\nget-documentation({ \"id\": \"breadcrumb\" })\nget-documentation({ \"id\": \"tabs\" })\n```\n\n### Inspect Live Story Implementations:\n\n```json\nget-documentation-for-story({ \"id\": \"applayout\", \"storyName\": \"Default\" })\nget-documentation-for-story({ \"id\": \"sidebar\", \"storyName\": \"Default\" })\nget-documentation-for-story({ \"id\": \"breadcrumb\", \"storyName\": \"Default\" })\nget-documentation-for-story({ \"id\": \"tabs\", \"storyName\": \"Default\" })\n```\n\n### Inspect Knowledge Graph & Usages:\n\n```json\nquery_graph({ \"query\": \"AppLayout\" })\nquery_graph({ \"query\": \"Sidebar\" })\n```\n\n---\n\n## 2. Layout Architecture & Mental Model\n\n1. **Top-Level App Shell (`AppLayout`)**:\n Provides structured slots for `sidebar`, `header`, and main content view, handling responsive viewport scaling and mobile navigation overlays.\n2. **Hierarchical Menu (`Sidebar`)**:\n Renders single and nested navigation items, active route indicators, collapsible state, and notification badges.\n3. **Breadcrumb Trail (`Breadcrumb`)**:\n Maintains clear navigational hierarchy on page headers.\n4. **Tabbed Sub-Views (`Tabs`)**:\n Organizes complex entity detail views or multi-section settings into distinct tabbed panels.\n\n---\n\n## 3. Mandatory Implementation Rules\n\n1. **Query MCP for Current Code Patterns**: Inspect `applayout` and `sidebar` stories via MCP before assembling the layout.\n2. **Strict Subpath Imports**: Import layout blocks via `@wangs-ui/react-core/blocks/*` and primitives via `@wangs-ui/react-core/primitive/*`.\n3. **Consistent Spacing Grid**: Use standard container padding (`p-6` or `p-xxl`) across page contents.\n4. **Page Hierarchy Alignment**: Every page view inside the layout must provide a clear `.heading-1` hierarchy and synchronized breadcrumbs.\n5. **Translate Navigation Labels**: Wrap all sidebar item labels and breadcrumb texts in `t('...')` from `@wangs-ui/react-i18n`.\n";
@@ -144,7 +144,7 @@ function removeSkill(skillId, baseDir = process.cwd()) {
144
144
  //#endregion
145
145
  //#region src/commands/list.ts
146
146
  function listSkills(baseDir = process.cwd()) {
147
- intro(`\x1b[1m\x1b[36m📦 Wangs UI Consumer Skills Registry\x1b[0m (v1.0.59)`);
147
+ intro(`\x1b[1m\x1b[36m📦 Wangs UI Consumer Skills Registry\x1b[0m (v1.0.61)`);
148
148
  const allSkills = loadAllSkills();
149
149
  const targetDirs = getAgentSkillDirs(baseDir);
150
150
  if (allSkills.length === 0) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wangs-ui/skills",
3
- "version": "1.0.59",
3
+ "version": "1.0.61",
4
4
  "description": "CLI to install, update, and manage modular AI agent skills for Wangs UI React applications",
5
5
  "keywords": [
6
6
  "agents",
@@ -1,17 +1,17 @@
1
1
  ---
2
2
  name: i18n-usage
3
- description: Guidelines, formatting rules, and MCP discovery protocol for internationalization with @wangs-ui/react-i18n and localized components.
3
+ description: Comprehensive guidelines for application internationalization, JIT translations (t), ICU formatting, and locale-aware formatting with @wangs-ui/react-i18n.
4
4
  ---
5
5
 
6
- # Skill: Application Internationalization & Localization Protocol
6
+ # Skill: Application Internationalization & Formatting Protocol
7
7
 
8
- Use this skill when handling multi-language interfaces, currency inputs, localized date formats, or dynamic text translations in Wangs UI applications.
8
+ Use this skill when implementing multi-language interfaces, translating user-facing text, formatting dates, times, currencies, or numbers in React applications built with Wangs UI and `@wangs-ui/react-i18n`.
9
9
 
10
10
  ---
11
11
 
12
- ## 1. MCP Inspection Protocol (Single Source of Truth)
12
+ ## 1. The MCP Discovery Protocol (Single Source of Truth)
13
13
 
14
- Do **NOT** guess component localization props or language switcher variants. Query the MCP server dynamically to inspect exact contracts and live story implementations:
14
+ Do **NOT** guess component localization contracts, language switcher variants, or datepicker props. Query the MCP server dynamically to inspect exact props and live story implementations:
15
15
 
16
16
  ### Inspect Localized Component Contracts:
17
17
 
@@ -19,6 +19,8 @@ Do **NOT** guess component localization props or language switcher variants. Que
19
19
  get-documentation({ "id": "languageswitcher" })
20
20
  get-documentation({ "id": "currencyinput" })
21
21
  get-documentation({ "id": "datepicker" })
22
+ get-documentation({ "id": "select" })
23
+ get-documentation({ "id": "datatable" })
22
24
  ```
23
25
 
24
26
  ### Inspect Live Story Implementations:
@@ -31,52 +33,200 @@ get-documentation-for-story({ "id": "datepicker", "storyName": "Default" })
31
33
 
32
34
  ---
33
35
 
34
- ## 2. Translation Syntax & Golden Rules
36
+ ## 2. Root Provider Setup (`WangsUiI18nProvider`)
35
37
 
36
- 1. **Sentence Keys in Natural English**:
37
- Always write human-readable English sentence keys:
38
+ Wrap the application root with `WangsUiI18nProvider` from `@wangs-ui/react-i18n` to enable dynamic JIT translations, versioned cache invalidation, and locale context:
38
39
 
39
- ```tsx
40
- // Good
41
- t('Invoice Summary');
42
- t('Are you sure you want to delete this customer?');
40
+ ```tsx
41
+ import { WangsUiI18nProvider } from '@wangs-ui/react-i18n';
42
+ import React from 'react';
43
+ import ReactDOM from 'react-dom/client';
44
+ import App from './App';
43
45
 
44
- // ❌ Bad — artificial dotted keys
45
- t('invoice.summary.title');
46
- ```
46
+ ReactDOM.createRoot(document.getElementById('root')!).render(
47
+ <React.StrictMode>
48
+ <WangsUiI18nProvider defaultLocale="en" baseUrl={import.meta.env.VITE_API_URL || ''}>
49
+ <App />
50
+ </WangsUiI18nProvider>
51
+ </React.StrictMode>,
52
+ );
53
+ ```
54
+
55
+ ---
56
+
57
+ ## 3. Translation Protocol with `useI18n()`
58
+
59
+ The `@wangs-ui/react-i18n` package uses a Just-In-Time (JIT) translation architecture where natural English text strings serve as database keys.
60
+
61
+ ### A. Consumer-Level Translation for `ReactNode` Props (Mandatory)
62
+
63
+ All user-facing text props in Wangs UI components (`placeholder`, `label`, `emptyMessage`, `header`, `tooltip`, etc.) are typed as `ReactNode` and rendered as-is. Components do **NOT** automatically translate custom strings. Translation **MUST** be called at the application/consumer level:
64
+
65
+ ```tsx
66
+ import { useI18n } from '@wangs-ui/react-i18n';
67
+ import Button from '@wangs-ui/react-core/primitive/button';
68
+ import DataTable from '@wangs-ui/react-core/primitive/datatable';
69
+ import Select from '@wangs-ui/react-core/primitive/select';
70
+
71
+ export function OrderList() {
72
+ const { t } = useI18n();
73
+
74
+ return (
75
+ <div>
76
+ <Select placeholder={t('Search category...')} />
77
+ <DataTable emptyMessage={t('No orders found')} />
78
+ <Button label={t('Create new order')} />
79
+ </div>
80
+ );
81
+ }
82
+ ```
83
+
84
+ ### B. Natural English Sentence Keys
47
85
 
48
- 2. **Dynamic Variables in Double Braces (`{{var}}`)**:
49
- Pass variables as an object using `{{variableName}}` interpolation:
86
+ Always write full, natural English sentences as translation keys. Never use artificial dotted namespace keys:
50
87
 
51
- ```tsx
52
- // ✅ Good
53
- t('Welcome back, {{name}}!', { name: user.name });
88
+ ```tsx
89
+ // ✅ Good — Natural English
90
+ t('Invoice Summary');
91
+ t('Are you sure you want to delete this customer?');
54
92
 
55
- // ❌ Bad — string concatenation breaks translation word order
56
- t('Welcome back, ') + user.name + '!';
57
- ```
93
+ // ❌ Bad — Artificial dotted keys
94
+ t('invoice.summary.title');
95
+ t('dialog.delete.customer.confirm');
96
+ ```
97
+
98
+ ### C. Named Variable Interpolation (Single Braces `{var}`)
99
+
100
+ Pass interpolation values inside a plain object using descriptive named variables. This provides crucial semantic context for AI translation engines:
101
+
102
+ ```tsx
103
+ // ✅ Good — Named variables provide context
104
+ t('Upload {count} files to {groupName}', { count: 5, groupName: 'Marketing' });
105
+ t('Welcome back, {userName}!', { userName: user.name });
106
+
107
+ // ❌ Bad — Concatenation or positional arguments
108
+ t('Welcome back, ' + user.name);
109
+ t('Upload {0} files to {1}', 5, 'Marketing');
110
+ ```
58
111
 
59
- 3. **Pluralization with ICU Formats**:
60
- Use ICU plural format for quantity-dependent sentences:
112
+ ### D. ICU Pluralization & Zero-State (`=0`)
61
113
 
62
- ```tsx
63
- t('{count, plural, =0 {No items selected} one {# item selected} other {# items selected}}', {
64
- count: selectedCount,
65
- });
66
- ```
114
+ Always handle singular, plural, and zero states directly within ICU MessageFormat strings. Do **NOT** use JavaScript ternary operators:
67
115
 
68
- 4. **Runtime Locale Switching**:
69
- Use the `useI18n()` hook to read or update active language:
70
- ```tsx
71
- import { useI18n } from '@wangs-ui/react-i18n';
116
+ ```tsx
117
+ // Good Clean ICU pluralization with zero-state handling
118
+ t('{count, plural, =0 {No items selected} one {1 item selected} other {{count} items selected}}', {
119
+ count: selectedCount,
120
+ });
72
121
 
73
- const { t, currentLocale, setLocale } = useI18n();
74
- ```
122
+ // Bad Manual JS branching
123
+ selectedCount === 0
124
+ ? t('No items selected')
125
+ : selectedCount === 1
126
+ ? t('1 item selected')
127
+ : t('{count} items selected', { count: selectedCount });
128
+ ```
129
+
130
+ ### E. Rich Text / Annotated Strings
131
+
132
+ Use standard supported HTML tags (`<a>`, `<b>`, `<i>`, `<u>`, `<s>`, `<br/>`, `<sub>`, `<sup>`, `<code>`, `<mark>`) for inline styling. Tags are automatically parsed into React elements without custom regex or string manipulation:
133
+
134
+ ```tsx
135
+ import Link from '@wangs-ui/foundation/theme/Link';
136
+
137
+ t('You have selected <b>{count} items</b>. Click <a>here</a> to review.', {
138
+ count: selectedCount,
139
+ a: (chunks) => <Link href="/review">{chunks}</Link>,
140
+ });
141
+ ```
142
+
143
+ ---
144
+
145
+ ## 4. Locale Formatting Protocol with `useLocaleFormatter()`
146
+
147
+ For locale-aware formatting of dates, relative times, currencies, numbers, and display names, use the dedicated `useLocaleFormatter()` hook. All functions automatically adapt to the active locale without triggering backend database requests:
148
+
149
+ ```tsx
150
+ import { useLocaleFormatter } from '@wangs-ui/react-i18n';
151
+
152
+ export function SummaryCard({ updatedAt, amount, count }: Props) {
153
+ const {
154
+ formatDate,
155
+ formatRelativeTime,
156
+ formatCurrency,
157
+ formatNumber,
158
+ formatDisplayName,
159
+ formatList,
160
+ truncateText,
161
+ } = useLocaleFormatter();
162
+
163
+ return (
164
+ <div>
165
+ {/* Date formatting with Go tokens or date-fns tokens, and timezone */}
166
+ <p>{formatDate(new Date(), 'dd MMMM yyyy, HH:mm', 'Asia/Jakarta')}</p>
167
+
168
+ {/* Relative time */}
169
+ <p>{formatRelativeTime(updatedAt)}</p>
170
+
171
+ {/* Currency formatting */}
172
+ <p>{formatCurrency(amount, 'IDR')}</p>
173
+
174
+ {/* Number formatting with locale grouping */}
175
+ <p>{formatNumber(count)}</p>
176
+
177
+ {/* ISO code to localized name */}
178
+ <p>{formatDisplayName('id', 'language')}</p>
179
+
180
+ {/* Localized list */}
181
+ <p>{formatList(['Finance', 'Operations', 'IT'])}</p>
182
+
183
+ {/* Emoji & multi-byte safe text truncation */}
184
+ <p>{truncateText('Long product description with emojis 🚀', 20)}</p>
185
+ </div>
186
+ );
187
+ }
188
+ ```
189
+
190
+ > [!NOTE]
191
+ > Formatters MUST NOT be called as standalone `t()` keys (e.g. `t(formatRelativeTime(date))`). Instead, pass the formatted result as a named variable:
192
+ >
193
+ > ```tsx
194
+ > const { t } = useI18n();
195
+ > const { formatRelativeTime } = useLocaleFormatter();
196
+ > const label = t('Updated {time}', { time: formatRelativeTime(updatedAt) });
197
+ > ```
198
+
199
+ ---
200
+
201
+ ## 5. Language Switching UI Integration
202
+
203
+ Connect the Wangs UI `LanguageSwitcher` primitive directly with `useI18n()` state:
204
+
205
+ ```tsx
206
+ import LanguageSwitcher from '@wangs-ui/react-core/primitive/languageswitcher';
207
+ import { useI18n } from '@wangs-ui/react-i18n';
208
+
209
+ export function HeaderLanguageSwitcher() {
210
+ const { locale, setLocale, languageOptions } = useI18n();
211
+
212
+ return (
213
+ <LanguageSwitcher
214
+ options={languageOptions}
215
+ value={locale}
216
+ onChange={(code) => setLocale(code)}
217
+ />
218
+ );
219
+ }
220
+ ```
75
221
 
76
222
  ---
77
223
 
78
- ## 3. Mandatory Implementation Rules
224
+ ## 6. Strict Behavioral Constraints (MUST NOT)
79
225
 
80
- 1. **Inspect Localized Components via MCP**: Query `currencyinput` and `datepicker` documentation before binding locale-sensitive formatters.
81
- 2. **Never Hardcode User-Facing Text**: Every visible label, placeholder, dialog title, tooltip, and error message in the application must pass through `t()`.
82
- 3. **Keep Context Intact**: Do not split sentences into separate phrases across JSX elements; translate the full sentence as a single unit.
226
+ - **NO Formatters Destructured from `useI18n()`:** Formatters are isolated in `useLocaleFormatter()`. Never attempt to import `formatDate` or `formatCurrency` from `useI18n()`.
227
+ - **NO String Concatenation in `t()` Keys:** Never concatenate strings or use dynamic template literals (e.g. `t('Hello ' + user.name)` or ``t(`Hello ${user.name}`)``). This creates infinite distinct keys in the translation database and prevents caching.
228
+ - **NO Manual Zero-State JavaScript Branching:** Always use ICU `=0` syntax inside a single plural key.
229
+ - **NO Dotted Artificial Translation Keys:** Never use dotted keys like `t('app.header.title')`. Use natural English sentences.
230
+ - **NO Custom Markdown Formatting Symbols:** Do not use `*bold*` or `_italic_` in translation keys. Use valid HTML tags like `<b>bold</b>`.
231
+ - **NO Hardcoded Static Translation Dictionaries:** Do not bundle static translation files (`id.json`, `zh.json`). The JIT backend broker manages translations dynamically.
232
+ - **NO Unnecessary English Key Modifications:** Minor typos or punctuation changes in keys create orphaned entries in the translation backend and trigger new AI translation costs.