@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 +1 -1
- package/dist/index.js +1 -1
- package/dist/skills/i18n-usage/SKILL.md +190 -40
- package/dist/{src-CmtJDo3Y.js → src-CusYgPAm.js} +2 -2
- package/package.json +1 -1
- package/skills/i18n-usage/SKILL.md +190 -40
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-
|
|
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-
|
|
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:
|
|
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 &
|
|
6
|
+
# Skill: Application Internationalization & Formatting Protocol
|
|
7
7
|
|
|
8
|
-
Use this skill when
|
|
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
|
|
12
|
+
## 1. The MCP Discovery Protocol (Single Source of Truth)
|
|
13
13
|
|
|
14
|
-
Do **NOT** guess component localization
|
|
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.
|
|
36
|
+
## 2. Root Provider Setup (`WangsUiI18nProvider`)
|
|
35
37
|
|
|
36
|
-
|
|
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
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
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
|
-
|
|
45
|
-
|
|
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
|
-
|
|
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
|
-
|
|
52
|
-
|
|
53
|
-
|
|
88
|
+
```tsx
|
|
89
|
+
// ✅ Good — Natural English
|
|
90
|
+
t('Invoice Summary');
|
|
91
|
+
t('Are you sure you want to delete this customer?');
|
|
54
92
|
|
|
55
|
-
|
|
56
|
-
|
|
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
|
-
|
|
60
|
-
Use ICU plural format for quantity-dependent sentences:
|
|
112
|
+
### D. ICU Pluralization & Zero-State (`=0`)
|
|
61
113
|
|
|
62
|
-
|
|
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
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
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
|
-
|
|
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
|
-
##
|
|
224
|
+
## 6. Strict Behavioral Constraints (MUST NOT)
|
|
79
225
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
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:
|
|
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 [2m(v1.0.
|
|
147
|
+
intro(`\x1b[1m\x1b[36m📦 Wangs UI Consumer Skills Registry\x1b[0m [2m(v1.0.61)[0m`);
|
|
148
148
|
const allSkills = loadAllSkills();
|
|
149
149
|
const targetDirs = getAgentSkillDirs(baseDir);
|
|
150
150
|
if (allSkills.length === 0) {
|
package/package.json
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: i18n-usage
|
|
3
|
-
description:
|
|
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 &
|
|
6
|
+
# Skill: Application Internationalization & Formatting Protocol
|
|
7
7
|
|
|
8
|
-
Use this skill when
|
|
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
|
|
12
|
+
## 1. The MCP Discovery Protocol (Single Source of Truth)
|
|
13
13
|
|
|
14
|
-
Do **NOT** guess component localization
|
|
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.
|
|
36
|
+
## 2. Root Provider Setup (`WangsUiI18nProvider`)
|
|
35
37
|
|
|
36
|
-
|
|
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
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
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
|
-
|
|
45
|
-
|
|
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
|
-
|
|
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
|
-
|
|
52
|
-
|
|
53
|
-
|
|
88
|
+
```tsx
|
|
89
|
+
// ✅ Good — Natural English
|
|
90
|
+
t('Invoice Summary');
|
|
91
|
+
t('Are you sure you want to delete this customer?');
|
|
54
92
|
|
|
55
|
-
|
|
56
|
-
|
|
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
|
-
|
|
60
|
-
Use ICU plural format for quantity-dependent sentences:
|
|
112
|
+
### D. ICU Pluralization & Zero-State (`=0`)
|
|
61
113
|
|
|
62
|
-
|
|
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
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
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
|
-
|
|
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
|
-
##
|
|
224
|
+
## 6. Strict Behavioral Constraints (MUST NOT)
|
|
79
225
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
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.
|