@neyugn/agent-kits 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (158) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +514 -0
  3. package/README.vi.md +410 -0
  4. package/README.zh.md +410 -0
  5. package/dist/cli.d.ts +1 -0
  6. package/dist/cli.js +422 -0
  7. package/kits/coder/ARCHITECTURE.md +289 -0
  8. package/kits/coder/agents/ai-engineer.md +344 -0
  9. package/kits/coder/agents/backend-specialist.md +270 -0
  10. package/kits/coder/agents/cloud-architect.md +363 -0
  11. package/kits/coder/agents/code-reviewer.md +284 -0
  12. package/kits/coder/agents/data-engineer.md +401 -0
  13. package/kits/coder/agents/database-specialist.md +251 -0
  14. package/kits/coder/agents/debugger.md +209 -0
  15. package/kits/coder/agents/devops-engineer.md +281 -0
  16. package/kits/coder/agents/documentation-writer.md +296 -0
  17. package/kits/coder/agents/frontend-specialist.md +298 -0
  18. package/kits/coder/agents/i18n-specialist.md +348 -0
  19. package/kits/coder/agents/integration-specialist.md +314 -0
  20. package/kits/coder/agents/mobile-developer.md +271 -0
  21. package/kits/coder/agents/multi-tenant-architect.md +281 -0
  22. package/kits/coder/agents/orchestrator.md +263 -0
  23. package/kits/coder/agents/performance-analyst.md +327 -0
  24. package/kits/coder/agents/project-planner.md +277 -0
  25. package/kits/coder/agents/queue-specialist.md +282 -0
  26. package/kits/coder/agents/realtime-specialist.md +267 -0
  27. package/kits/coder/agents/security-auditor.md +253 -0
  28. package/kits/coder/agents/test-engineer.md +315 -0
  29. package/kits/coder/agents/ux-researcher.md +388 -0
  30. package/kits/coder/rules/.cursorrules +287 -0
  31. package/kits/coder/rules/CLAUDE.md +287 -0
  32. package/kits/coder/rules/CODEX.md +287 -0
  33. package/kits/coder/rules/GEMINI.md +287 -0
  34. package/kits/coder/scripts/checklist.py +318 -0
  35. package/kits/coder/scripts/kit_status.py +292 -0
  36. package/kits/coder/scripts/skills_manager.py +243 -0
  37. package/kits/coder/scripts/verify_all.py +391 -0
  38. package/kits/coder/skills/accessibility-patterns/SKILL.md +372 -0
  39. package/kits/coder/skills/accessibility-patterns/scripts/a11y_checker.py +211 -0
  40. package/kits/coder/skills/ai-rag-patterns/SKILL.md +444 -0
  41. package/kits/coder/skills/api-patterns/SKILL.md +316 -0
  42. package/kits/coder/skills/api-patterns/assets/.gitkeep +1 -0
  43. package/kits/coder/skills/api-patterns/references/deep-dive.md +21 -0
  44. package/kits/coder/skills/api-patterns/scripts/api_validator.py +253 -0
  45. package/kits/coder/skills/api-patterns/scripts/validate.py +56 -0
  46. package/kits/coder/skills/auth-patterns/SKILL.md +267 -0
  47. package/kits/coder/skills/aws-patterns/SKILL.md +576 -0
  48. package/kits/coder/skills/brainstorming/SKILL.md +370 -0
  49. package/kits/coder/skills/brainstorming/assets/.gitkeep +1 -0
  50. package/kits/coder/skills/brainstorming/references/deep-dive.md +21 -0
  51. package/kits/coder/skills/brainstorming/scripts/validate.py +56 -0
  52. package/kits/coder/skills/clean-code/SKILL.md +240 -0
  53. package/kits/coder/skills/clean-code/assets/.gitkeep +1 -0
  54. package/kits/coder/skills/clean-code/references/deep-dive.md +21 -0
  55. package/kits/coder/skills/clean-code/scripts/lint_runner.py +186 -0
  56. package/kits/coder/skills/clean-code/scripts/validate.py +56 -0
  57. package/kits/coder/skills/database-design/SKILL.md +255 -0
  58. package/kits/coder/skills/database-design/assets/.gitkeep +1 -0
  59. package/kits/coder/skills/database-design/references/deep-dive.md +21 -0
  60. package/kits/coder/skills/database-design/scripts/schema_validator.py +272 -0
  61. package/kits/coder/skills/database-design/scripts/validate.py +56 -0
  62. package/kits/coder/skills/docker-patterns/SKILL.md +240 -0
  63. package/kits/coder/skills/documentation-templates/SKILL.md +441 -0
  64. package/kits/coder/skills/e2e-testing/SKILL.md +457 -0
  65. package/kits/coder/skills/flutter-patterns/SKILL.md +330 -0
  66. package/kits/coder/skills/frontend-design/SKILL.md +127 -0
  67. package/kits/coder/skills/github-actions/SKILL.md +349 -0
  68. package/kits/coder/skills/gitlab-ci-patterns/SKILL.md +466 -0
  69. package/kits/coder/skills/graphql-patterns/SKILL.md +558 -0
  70. package/kits/coder/skills/i18n-localization/SKILL.md +345 -0
  71. package/kits/coder/skills/i18n-localization/scripts/i18n_checker.py +267 -0
  72. package/kits/coder/skills/kubernetes-patterns/SKILL.md +357 -0
  73. package/kits/coder/skills/mermaid-diagrams/SKILL.md +351 -0
  74. package/kits/coder/skills/mobile-design/SKILL.md +305 -0
  75. package/kits/coder/skills/monitoring-observability/SKILL.md +458 -0
  76. package/kits/coder/skills/multi-tenancy/SKILL.md +317 -0
  77. package/kits/coder/skills/multi-tenancy/assets/.gitkeep +1 -0
  78. package/kits/coder/skills/multi-tenancy/references/deep-dive.md +21 -0
  79. package/kits/coder/skills/multi-tenancy/scripts/validate.py +56 -0
  80. package/kits/coder/skills/nodejs-best-practices/SKILL.md +220 -0
  81. package/kits/coder/skills/performance-profiling/SKILL.md +333 -0
  82. package/kits/coder/skills/performance-profiling/assets/.gitkeep +1 -0
  83. package/kits/coder/skills/performance-profiling/references/deep-dive.md +21 -0
  84. package/kits/coder/skills/performance-profiling/scripts/validate.py +56 -0
  85. package/kits/coder/skills/plan-writing/SKILL.md +360 -0
  86. package/kits/coder/skills/plan-writing/assets/.gitkeep +1 -0
  87. package/kits/coder/skills/plan-writing/references/deep-dive.md +21 -0
  88. package/kits/coder/skills/plan-writing/scripts/validate.py +56 -0
  89. package/kits/coder/skills/postgres-patterns/SKILL.md +361 -0
  90. package/kits/coder/skills/prompt-engineering/SKILL.md +277 -0
  91. package/kits/coder/skills/queue-patterns/SKILL.md +359 -0
  92. package/kits/coder/skills/queue-patterns/assets/.gitkeep +1 -0
  93. package/kits/coder/skills/queue-patterns/references/deep-dive.md +21 -0
  94. package/kits/coder/skills/queue-patterns/scripts/validate.py +56 -0
  95. package/kits/coder/skills/react-native-patterns/SKILL.md +393 -0
  96. package/kits/coder/skills/react-patterns/SKILL.md +319 -0
  97. package/kits/coder/skills/realtime-patterns/SKILL.md +506 -0
  98. package/kits/coder/skills/realtime-patterns/assets/.gitkeep +1 -0
  99. package/kits/coder/skills/realtime-patterns/references/deep-dive.md +21 -0
  100. package/kits/coder/skills/realtime-patterns/scripts/validate.py +56 -0
  101. package/kits/coder/skills/redis-patterns/SKILL.md +484 -0
  102. package/kits/coder/skills/security-fundamentals/SKILL.md +363 -0
  103. package/kits/coder/skills/security-fundamentals/assets/.gitkeep +1 -0
  104. package/kits/coder/skills/security-fundamentals/references/deep-dive.md +21 -0
  105. package/kits/coder/skills/security-fundamentals/scripts/security_scan.py +326 -0
  106. package/kits/coder/skills/security-fundamentals/scripts/validate.py +56 -0
  107. package/kits/coder/skills/seo-patterns/SKILL.md +262 -0
  108. package/kits/coder/skills/seo-patterns/scripts/seo_checker.py +211 -0
  109. package/kits/coder/skills/systematic-debugging/SKILL.md +478 -0
  110. package/kits/coder/skills/systematic-debugging/assets/.gitkeep +1 -0
  111. package/kits/coder/skills/systematic-debugging/references/deep-dive.md +21 -0
  112. package/kits/coder/skills/systematic-debugging/scripts/validate.py +56 -0
  113. package/kits/coder/skills/tailwind-patterns/SKILL.md +395 -0
  114. package/kits/coder/skills/terraform-patterns/SKILL.md +470 -0
  115. package/kits/coder/skills/testing-patterns/SKILL.md +285 -0
  116. package/kits/coder/skills/testing-patterns/assets/.gitkeep +1 -0
  117. package/kits/coder/skills/testing-patterns/references/deep-dive.md +21 -0
  118. package/kits/coder/skills/testing-patterns/scripts/test_runner.py +219 -0
  119. package/kits/coder/skills/testing-patterns/scripts/validate.py +56 -0
  120. package/kits/coder/skills/typescript-patterns/SKILL.md +417 -0
  121. package/kits/coder/skills/ui-ux-pro-max/SKILL.md +364 -0
  122. package/kits/coder/skills/ui-ux-pro-max/data/charts.csv +26 -0
  123. package/kits/coder/skills/ui-ux-pro-max/data/colors.csv +97 -0
  124. package/kits/coder/skills/ui-ux-pro-max/data/icons.csv +101 -0
  125. package/kits/coder/skills/ui-ux-pro-max/data/landing.csv +31 -0
  126. package/kits/coder/skills/ui-ux-pro-max/data/products.csv +97 -0
  127. package/kits/coder/skills/ui-ux-pro-max/data/prompts.csv +24 -0
  128. package/kits/coder/skills/ui-ux-pro-max/data/react-performance.csv +45 -0
  129. package/kits/coder/skills/ui-ux-pro-max/data/stacks/flutter.csv +53 -0
  130. package/kits/coder/skills/ui-ux-pro-max/data/stacks/html-tailwind.csv +56 -0
  131. package/kits/coder/skills/ui-ux-pro-max/data/stacks/nextjs.csv +53 -0
  132. package/kits/coder/skills/ui-ux-pro-max/data/stacks/nuxt-ui.csv +51 -0
  133. package/kits/coder/skills/ui-ux-pro-max/data/stacks/nuxtjs.csv +59 -0
  134. package/kits/coder/skills/ui-ux-pro-max/data/stacks/react-native.csv +52 -0
  135. package/kits/coder/skills/ui-ux-pro-max/data/stacks/react.csv +54 -0
  136. package/kits/coder/skills/ui-ux-pro-max/data/stacks/shadcn.csv +61 -0
  137. package/kits/coder/skills/ui-ux-pro-max/data/stacks/svelte.csv +54 -0
  138. package/kits/coder/skills/ui-ux-pro-max/data/stacks/swiftui.csv +51 -0
  139. package/kits/coder/skills/ui-ux-pro-max/data/stacks/vue.csv +50 -0
  140. package/kits/coder/skills/ui-ux-pro-max/data/styles.csv +59 -0
  141. package/kits/coder/skills/ui-ux-pro-max/data/typography.csv +58 -0
  142. package/kits/coder/skills/ui-ux-pro-max/data/ui-reasoning.csv +101 -0
  143. package/kits/coder/skills/ui-ux-pro-max/data/ux-guidelines.csv +100 -0
  144. package/kits/coder/skills/ui-ux-pro-max/data/web-interface.csv +31 -0
  145. package/kits/coder/skills/ui-ux-pro-max/scripts/__pycache__/core.cpython-314.pyc +0 -0
  146. package/kits/coder/skills/ui-ux-pro-max/scripts/__pycache__/design_system.cpython-314.pyc +0 -0
  147. package/kits/coder/skills/ui-ux-pro-max/scripts/core.py +257 -0
  148. package/kits/coder/skills/ui-ux-pro-max/scripts/design_system.py +488 -0
  149. package/kits/coder/skills/ui-ux-pro-max/scripts/search.py +76 -0
  150. package/kits/coder/workflows/.gitkeep +20 -0
  151. package/kits/coder/workflows/create.md +152 -0
  152. package/kits/coder/workflows/debug.md +223 -0
  153. package/kits/coder/workflows/deploy.md +283 -0
  154. package/kits/coder/workflows/orchestrate.md +243 -0
  155. package/kits/coder/workflows/plan.md +134 -0
  156. package/kits/coder/workflows/test.md +237 -0
  157. package/kits/coder/workflows/ui-ux-pro-max.md +109 -0
  158. package/package.json +49 -0
@@ -0,0 +1,345 @@
1
+ ---
2
+ name: i18n-localization
3
+ description: Internationalization and localization patterns. Use when implementing multi-language support, translation workflows, locale handling, RTL support, or currency/date formatting.
4
+ allowed-tools: Read, Write, Edit, Glob, Grep, Bash
5
+ ---
6
+
7
+ # i18n & Localization Patterns
8
+
9
+ > Make software work beautifully in every language and culture.
10
+
11
+ ---
12
+
13
+ ## Core Principles
14
+
15
+ 1. **Externalize all strings** - No hardcoded text in components
16
+ 2. **Use ICU Message Format** - Handle plurals, gender, and complex formatting
17
+ 3. **Design for translation** - Leave room for text expansion (30-50%)
18
+ 4. **Test with pseudo-localization** - Catch issues early
19
+ 5. **Locale is more than language** - Includes date, number, currency formats
20
+
21
+ ---
22
+
23
+ ## šŸ”§ Framework Selection
24
+
25
+ | Framework | Platform | Best For |
26
+ | --------------------- | ------------ | --------------------------- |
27
+ | **next-intl** | Next.js | App Router, RSC support |
28
+ | **react-intl** | React | Established, ICU format |
29
+ | **i18next** | Universal | Flexible, plugin ecosystem |
30
+ | **vue-i18n** | Vue | Vue-native, composition API |
31
+ | **expo-localization** | React Native | Mobile apps with Expo |
32
+
33
+ ### Decision Tree
34
+
35
+ ```
36
+ Next.js App Router?
37
+ ā”œā”€ā”€ Yes → next-intl (best RSC support)
38
+ └── No → React SPA?
39
+ ā”œā”€ā”€ Yes → react-intl or i18next
40
+ └── No → Vue?
41
+ ā”œā”€ā”€ Yes → vue-i18n
42
+ └── No → i18next (universal)
43
+ ```
44
+
45
+ ---
46
+
47
+ ## šŸ“ Project Structure
48
+
49
+ ```
50
+ locales/
51
+ ā”œā”€ā”€ en/
52
+ │ ā”œā”€ā”€ common.json # Shared strings
53
+ │ ā”œā”€ā”€ auth.json # Auth-related
54
+ │ ā”œā”€ā”€ dashboard.json # Feature-specific
55
+ │ └── errors.json # Error messages
56
+ ā”œā”€ā”€ vi/
57
+ │ ā”œā”€ā”€ common.json
58
+ │ ā”œā”€ā”€ auth.json
59
+ │ └── ...
60
+ └── ja/
61
+ └── ...
62
+ ```
63
+
64
+ ### Namespace Strategy
65
+
66
+ | Namespace | Contents |
67
+ | ----------- | --------------------------- |
68
+ | `common` | Shared: buttons, labels |
69
+ | `auth` | Login, register, password |
70
+ | `errors` | Error messages, validations |
71
+ | `[feature]` | Feature-specific strings |
72
+
73
+ ---
74
+
75
+ ## šŸŒ Key Naming Convention
76
+
77
+ ```json
78
+ // āœ… GOOD: Descriptive, hierarchical keys
79
+ {
80
+ "auth": {
81
+ "login": {
82
+ "title": "Sign In",
83
+ "button": "Sign In",
84
+ "forgotPassword": "Forgot password?"
85
+ }
86
+ }
87
+ }
88
+
89
+ // āŒ BAD: Flat, unclear keys
90
+ {
91
+ "login_title": "Sign In",
92
+ "btn1": "Sign In"
93
+ }
94
+ ```
95
+
96
+ ### Naming Rules
97
+
98
+ | Rule | Example |
99
+ | --------------------- | ---------------------------- |
100
+ | **camelCase keys** | `forgotPassword` |
101
+ | **Nested by feature** | `auth.login.title` |
102
+ | **Semantic naming** | `submitButton` not `button1` |
103
+ | **No hardcoded text** | Even for "OK" or "Cancel" |
104
+
105
+ ---
106
+
107
+ ## šŸ“ ICU Message Format
108
+
109
+ ### Plurals
110
+
111
+ ```json
112
+ {
113
+ "itemCount": "{count, plural, =0 {No items} one {# item} other {# items}}"
114
+ }
115
+ ```
116
+
117
+ ### Gender/Select
118
+
119
+ ```json
120
+ {
121
+ "greeting": "{gender, select, male {Mr.} female {Ms.} other {}} {name}"
122
+ }
123
+ ```
124
+
125
+ ### Date & Number
126
+
127
+ ```json
128
+ {
129
+ "lastUpdated": "Updated {date, date, medium}",
130
+ "price": "Price: {amount, number, ::currency/USD}"
131
+ }
132
+ ```
133
+
134
+ ### Rich Text (react-intl)
135
+
136
+ ```tsx
137
+ <FormattedMessage
138
+ id="terms"
139
+ defaultMessage="By signing up, you agree to our <link>Terms of Service</link>"
140
+ values={{
141
+ link: (chunks) => <Link href="/terms">{chunks}</Link>,
142
+ }}
143
+ />
144
+ ```
145
+
146
+ ---
147
+
148
+ ## šŸ”„ Translation Workflow
149
+
150
+ ### Development Flow
151
+
152
+ ```
153
+ 1. Add key to en/[namespace].json
154
+ 2. Use key in component
155
+ 3. Export for translators
156
+ 4. Import translations
157
+ 5. Review in context
158
+ ```
159
+
160
+ ### Translation Management
161
+
162
+ | Tool | Pricing | Best For |
163
+ | ------------ | ----------- | ---------------------- |
164
+ | **Crowdin** | Free tier | Open source, community |
165
+ | **Lokalise** | Paid | Professional teams |
166
+ | **Phrase** | Paid | Enterprise |
167
+ | **Tolgee** | Open source | Self-hosted |
168
+
169
+ ### Pseudo-localization
170
+
171
+ ```typescript
172
+ // Test without real translations
173
+ // "Hello" → "[Ħëľľö]" (longer + special chars)
174
+
175
+ const pseudoLocalize = (str: string) => {
176
+ const map: Record<string, string> = {
177
+ a: "Ƥ",
178
+ e: "Ć«",
179
+ i: "ĆÆ",
180
+ o: "ƶ",
181
+ u: "ü",
182
+ A: "Ƅ",
183
+ E: "Ƌ",
184
+ I: "Ə",
185
+ O: "Ɩ",
186
+ U: "Ü",
187
+ };
188
+ const converted = str.replace(/[aeiouAEIOU]/g, (c) => map[c] || c);
189
+ return `[${converted}]`;
190
+ };
191
+ ```
192
+
193
+ ---
194
+
195
+ ## šŸ“± RTL Support
196
+
197
+ ### CSS Approach
198
+
199
+ ```css
200
+ /* Use logical properties */
201
+ .container {
202
+ /* āŒ Physical */
203
+ margin-left: 16px;
204
+ padding-right: 8px;
205
+
206
+ /* āœ… Logical (RTL-aware) */
207
+ margin-inline-start: 16px;
208
+ padding-inline-end: 8px;
209
+ }
210
+
211
+ /* Direction-aware flex */
212
+ .row {
213
+ display: flex;
214
+ flex-direction: row; /* Auto-reverses in RTL */
215
+ }
216
+ ```
217
+
218
+ ### Logical Properties Mapping
219
+
220
+ | Physical | Logical |
221
+ | ------------------ | --------------------- |
222
+ | `left` | `inline-start` |
223
+ | `right` | `inline-end` |
224
+ | `top` | `block-start` |
225
+ | `bottom` | `block-end` |
226
+ | `margin-left` | `margin-inline-start` |
227
+ | `padding-right` | `padding-inline-end` |
228
+ | `text-align: left` | `text-align: start` |
229
+
230
+ ### HTML Direction
231
+
232
+ ```tsx
233
+ <html dir={isRTL ? 'rtl' : 'ltr'} lang={locale}>
234
+ ```
235
+
236
+ ---
237
+
238
+ ## šŸ”¢ Formatting
239
+
240
+ ### Dates
241
+
242
+ ```typescript
243
+ // Use Intl.DateTimeFormat
244
+ const formatDate = (date: Date, locale: string) => {
245
+ return new Intl.DateTimeFormat(locale, {
246
+ year: "numeric",
247
+ month: "long",
248
+ day: "numeric",
249
+ }).format(date);
250
+ };
251
+
252
+ // Results:
253
+ // en-US: "January 15, 2025"
254
+ // vi-VN: "15 thƔng 1, 2025"
255
+ // ja-JP: "2025幓1月15ę—„"
256
+ ```
257
+
258
+ ### Numbers & Currency
259
+
260
+ ```typescript
261
+ const formatCurrency = (amount: number, locale: string, currency: string) => {
262
+ return new Intl.NumberFormat(locale, {
263
+ style: "currency",
264
+ currency,
265
+ }).format(amount);
266
+ };
267
+
268
+ // Results for 1234.56:
269
+ // en-US, USD: "$1,234.56"
270
+ // vi-VN, VND: "1.234,56 ā‚«"
271
+ // ja-JP, JPY: "„1,235" (no decimals)
272
+ ```
273
+
274
+ ### Relative Time
275
+
276
+ ```typescript
277
+ const formatRelative = (date: Date, locale: string) => {
278
+ const rtf = new Intl.RelativeTimeFormat(locale, { numeric: "auto" });
279
+ const diff = (date.getTime() - Date.now()) / 1000;
280
+
281
+ if (Math.abs(diff) < 60) return rtf.format(Math.round(diff), "second");
282
+ if (Math.abs(diff) < 3600) return rtf.format(Math.round(diff / 60), "minute");
283
+ // ... etc
284
+ };
285
+ ```
286
+
287
+ ---
288
+
289
+ ## āœ… Implementation Checklist
290
+
291
+ ### Setup
292
+
293
+ - [ ] i18n library installed and configured
294
+ - [ ] Default locale defined
295
+ - [ ] Locale detection (browser/user preference)
296
+ - [ ] Fallback locale strategy
297
+
298
+ ### Content
299
+
300
+ - [ ] All user-facing strings externalized
301
+ - [ ] ICU format for plurals/formatting
302
+ - [ ] No string concatenation for sentences
303
+ - [ ] Translator context/comments added
304
+
305
+ ### Styling
306
+
307
+ - [ ] CSS uses logical properties
308
+ - [ ] RTL tested with real RTL content
309
+ - [ ] Text expansion tested (30-50% longer)
310
+ - [ ] Fonts support all target languages
311
+
312
+ ### Testing
313
+
314
+ - [ ] Pseudo-localization tested
315
+ - [ ] All locales render correctly
316
+ - [ ] Date/number formats verified
317
+ - [ ] RTL layout tested
318
+
319
+ ---
320
+
321
+ ## āŒ Anti-Patterns
322
+
323
+ | āŒ Don't | āœ… Do |
324
+ | --------------------------------- | ------------------------------------------ |
325
+ | Concatenate strings for sentences | Use ICU message format |
326
+ | Hardcode "OK", "Cancel", etc. | Externalize ALL strings |
327
+ | Use physical CSS properties | Use logical properties for RTL |
328
+ | Assume text length stays same | Design for 30-50% expansion |
329
+ | Store locale in localStorage only | Support URL-based locale switching |
330
+ | Use images with embedded text | Separate text layer or generate per-locale |
331
+
332
+ ---
333
+
334
+ ## šŸ”— Related Skills
335
+
336
+ | Need | Skill |
337
+ | -------------- | ------------------------ |
338
+ | React patterns | `react-patterns` |
339
+ | API design | `api-patterns` |
340
+ | Accessibility | `accessibility-patterns` |
341
+ | Testing | `testing-patterns` |
342
+
343
+ ---
344
+
345
+ > **Remember:** Localization is not just translation. It's making users feel the product was made for them, in their language, with their cultural expectations.
@@ -0,0 +1,267 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ i18n Checker - Internationalization audit for AGT-Kit
4
+ ======================================================
5
+
6
+ Detects hardcoded strings and checks translation completeness.
7
+
8
+ Usage:
9
+ python3 .agent/skills/i18n-localization/scripts/i18n_checker.py <project_path>
10
+
11
+ Checks:
12
+ - Hardcoded strings in JSX/Vue/Python
13
+ - Locale file completeness (missing keys)
14
+ - i18n library usage patterns
15
+ """
16
+
17
+ import sys
18
+ import re
19
+ import json
20
+ from pathlib import Path
21
+ from datetime import datetime
22
+ from typing import Dict, List, Set, Any
23
+
24
+ # Fix console encoding
25
+ try:
26
+ sys.stdout.reconfigure(encoding='utf-8', errors='replace')
27
+ except:
28
+ pass
29
+
30
+ SKIP_DIRS = {'node_modules', '.git', 'dist', 'build', '__pycache__', '.next', 'venv'}
31
+
32
+ # Patterns indicating hardcoded strings
33
+ HARDCODED_PATTERNS = {
34
+ 'jsx': [
35
+ r'>\s*[A-Z][a-zA-Z\s]{3,30}\s*</', # Text in JSX
36
+ r'(title|placeholder|label|alt)="[A-Z][a-zA-Z\s]{2,}"', # Attributes
37
+ ],
38
+ 'vue': [
39
+ r'>\s*[A-Z][a-zA-Z\s]{3,30}\s*</',
40
+ r'(placeholder|label|title)="[A-Z][a-zA-Z\s]{2,}"',
41
+ ],
42
+ 'python': [
43
+ r'(print|raise\s+\w+)\s*\(\s*["\'][A-Z][^"\']{5,}["\']',
44
+ r'flash\s*\(\s*["\'][A-Z][^"\']{5,}["\']',
45
+ ]
46
+ }
47
+
48
+ # Patterns indicating proper i18n usage
49
+ I18N_PATTERNS = [
50
+ r't\(["\']', # react-i18next
51
+ r'useTranslation', # React hook
52
+ r'\$t\(', # Vue i18n
53
+ r'_\(["\']', # Python gettext
54
+ r'gettext\(', # Python
55
+ r'useTranslations', # next-intl
56
+ r'FormattedMessage', # react-intl
57
+ ]
58
+
59
+
60
+ def find_locale_files(project_path: Path) -> List[Path]:
61
+ """Find translation/locale files."""
62
+ patterns = [
63
+ '**/locales/**/*.json',
64
+ '**/translations/**/*.json',
65
+ '**/lang/**/*.json',
66
+ '**/i18n/**/*.json',
67
+ '**/messages/*.json',
68
+ ]
69
+
70
+ files = []
71
+ for pattern in patterns:
72
+ for f in project_path.glob(pattern):
73
+ if not any(skip in f.parts for skip in SKIP_DIRS):
74
+ files.append(f)
75
+
76
+ return files
77
+
78
+
79
+ def flatten_keys(d: dict, prefix: str = '') -> Set[str]:
80
+ """Flatten nested dict keys."""
81
+ keys = set()
82
+ for k, v in d.items():
83
+ new_key = f"{prefix}.{k}" if prefix else k
84
+ if isinstance(v, dict):
85
+ keys.update(flatten_keys(v, new_key))
86
+ else:
87
+ keys.add(new_key)
88
+ return keys
89
+
90
+
91
+ def check_locale_completeness(locale_files: List[Path]) -> Dict[str, Any]:
92
+ """Check if all locales have the same keys."""
93
+ issues = []
94
+ passed = []
95
+
96
+ if not locale_files:
97
+ return {'passed': ['No locale files found (not required)'], 'issues': []}
98
+
99
+ # Group by language folder
100
+ locales: Dict[str, Dict[str, Set[str]]] = {}
101
+
102
+ for f in locale_files:
103
+ if f.suffix == '.json':
104
+ try:
105
+ lang = f.parent.name
106
+ content = json.loads(f.read_text(encoding='utf-8'))
107
+ if lang not in locales:
108
+ locales[lang] = {}
109
+ locales[lang][f.stem] = flatten_keys(content)
110
+ except:
111
+ continue
112
+
113
+ if len(locales) < 2:
114
+ passed.append(f"Found {len(locale_files)} locale file(s)")
115
+ return {'passed': passed, 'issues': issues}
116
+
117
+ passed.append(f"Found {len(locales)} languages: {', '.join(locales.keys())}")
118
+
119
+ # Compare keys across locales
120
+ all_langs = list(locales.keys())
121
+ base_lang = all_langs[0]
122
+
123
+ for namespace in locales.get(base_lang, {}):
124
+ base_keys = locales[base_lang].get(namespace, set())
125
+
126
+ for lang in all_langs[1:]:
127
+ other_keys = locales.get(lang, {}).get(namespace, set())
128
+
129
+ missing = base_keys - other_keys
130
+ if missing:
131
+ issues.append(f"{lang}/{namespace}: Missing {len(missing)} keys")
132
+
133
+ extra = other_keys - base_keys
134
+ if extra and len(extra) > 3:
135
+ issues.append(f"{lang}/{namespace}: {len(extra)} extra keys")
136
+
137
+ if not issues:
138
+ passed.append("All locales have matching keys")
139
+
140
+ return {'passed': passed, 'issues': issues}
141
+
142
+
143
+ def check_hardcoded_strings(project_path: Path) -> Dict[str, Any]:
144
+ """Check for hardcoded strings in code files."""
145
+ issues = []
146
+ passed = []
147
+
148
+ extensions = {
149
+ '.tsx': 'jsx', '.jsx': 'jsx', '.ts': 'jsx', '.js': 'jsx',
150
+ '.vue': 'vue',
151
+ '.py': 'python'
152
+ }
153
+
154
+ code_files = []
155
+ for ext in extensions:
156
+ for f in project_path.rglob(f"*{ext}"):
157
+ if not any(skip in f.parts for skip in SKIP_DIRS):
158
+ if not any(x in f.name for x in ['test', 'spec', 'config']):
159
+ code_files.append(f)
160
+
161
+ if not code_files:
162
+ return {'passed': ['No code files found'], 'issues': []}
163
+
164
+ files_with_i18n = 0
165
+ files_with_hardcoded = 0
166
+ examples = []
167
+
168
+ for file_path in code_files[:50]: # Limit
169
+ try:
170
+ content = file_path.read_text(encoding='utf-8', errors='ignore')
171
+ ext = file_path.suffix
172
+ file_type = extensions.get(ext, 'jsx')
173
+
174
+ # Check for i18n usage
175
+ has_i18n = any(re.search(p, content) for p in I18N_PATTERNS)
176
+ if has_i18n:
177
+ files_with_i18n += 1
178
+
179
+ # Check for hardcoded strings
180
+ patterns = HARDCODED_PATTERNS.get(file_type, [])
181
+
182
+ for pattern in patterns:
183
+ matches = re.findall(pattern, content)
184
+ if matches and not has_i18n:
185
+ files_with_hardcoded += 1
186
+ if len(examples) < 5:
187
+ examples.append(f"{file_path.name}: {str(matches[0])[:30]}...")
188
+ break
189
+
190
+ except:
191
+ continue
192
+
193
+ passed.append(f"Analyzed {len(code_files)} code files")
194
+
195
+ if files_with_i18n > 0:
196
+ passed.append(f"{files_with_i18n} files use i18n patterns")
197
+
198
+ if files_with_hardcoded > 0:
199
+ issues.append(f"{files_with_hardcoded} files may have hardcoded strings")
200
+ for ex in examples[:3]:
201
+ issues.append(f" → {ex}")
202
+ else:
203
+ passed.append("No obvious hardcoded strings detected")
204
+
205
+ return {'passed': passed, 'issues': issues}
206
+
207
+
208
+ def main():
209
+ project_path = Path(sys.argv[1] if len(sys.argv) > 1 else ".").resolve()
210
+
211
+ print(f"\n{'='*60}")
212
+ print(f"[AGT-KIT i18n CHECKER] Internationalization Audit")
213
+ print(f"{'='*60}")
214
+ print(f"Project: {project_path}")
215
+ print(f"Time: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}")
216
+ print("-"*60)
217
+
218
+ # Check locale files
219
+ locale_files = find_locale_files(project_path)
220
+ locale_result = check_locale_completeness(locale_files)
221
+
222
+ # Check hardcoded strings
223
+ code_result = check_hardcoded_strings(project_path)
224
+
225
+ # Print results
226
+ print("\nšŸ“ LOCALE FILES")
227
+ print("-"*40)
228
+ for item in locale_result['passed']:
229
+ print(f" āœ… {item}")
230
+ for item in locale_result['issues']:
231
+ print(f" āš ļø {item}")
232
+
233
+ print("\nšŸ’» CODE ANALYSIS")
234
+ print("-"*40)
235
+ for item in code_result['passed']:
236
+ print(f" āœ… {item}")
237
+ for item in code_result['issues']:
238
+ print(f" āš ļø {item}")
239
+
240
+ # Summary
241
+ all_issues = locale_result['issues'] + code_result['issues']
242
+ critical = sum(1 for i in all_issues if 'hardcoded' in i.lower() or 'missing' in i.lower())
243
+
244
+ print("\n" + "="*60)
245
+
246
+ passed = critical == 0
247
+
248
+ if passed:
249
+ print("āœ… i18n CHECK PASSED")
250
+ else:
251
+ print(f"āš ļø i18n CHECK: {critical} issues found")
252
+
253
+ output = {
254
+ "script": "i18n_checker",
255
+ "skill": "i18n-localization",
256
+ "project": str(project_path),
257
+ "locale_files": len(locale_files),
258
+ "issues": len(all_issues),
259
+ "passed": passed
260
+ }
261
+
262
+ print("\n" + json.dumps(output, indent=2))
263
+ sys.exit(0 if passed else 1)
264
+
265
+
266
+ if __name__ == "__main__":
267
+ main()