@nextsparkjs/ai-workflow 0.1.0-beta.100

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 (272) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +115 -0
  3. package/claude/_docs/workflows-optimizations.md +359 -0
  4. package/claude/agents/api-tester.md +634 -0
  5. package/claude/agents/architecture-supervisor.md +1351 -0
  6. package/claude/agents/backend-developer.md +997 -0
  7. package/claude/agents/backend-validator.md +417 -0
  8. package/claude/agents/bdd-docs-writer.md +737 -0
  9. package/claude/agents/block-developer.md +677 -0
  10. package/claude/agents/code-reviewer.md +1432 -0
  11. package/claude/agents/db-developer.md +721 -0
  12. package/claude/agents/db-validator.md +407 -0
  13. package/claude/agents/demo-video-generator.md +493 -0
  14. package/claude/agents/documentation-writer.md +1268 -0
  15. package/claude/agents/frontend-developer.md +1234 -0
  16. package/claude/agents/frontend-validator.md +777 -0
  17. package/claude/agents/functional-validator.md +630 -0
  18. package/claude/agents/mock-analyst.md +387 -0
  19. package/claude/agents/product-manager.md +963 -0
  20. package/claude/agents/qa-automation.md +1762 -0
  21. package/claude/agents/release-manager.md +634 -0
  22. package/claude/agents/selectors-translator.md +262 -0
  23. package/claude/agents/unit-test-writer.md +785 -0
  24. package/claude/agents/visual-comparator.md +329 -0
  25. package/claude/agents/workflow-maintainer.md +352 -0
  26. package/claude/commands/do/README.md +88 -0
  27. package/claude/commands/do/create-api.md +64 -0
  28. package/claude/commands/do/create-entity.md +66 -0
  29. package/claude/commands/do/create-migration.md +64 -0
  30. package/claude/commands/do/create-plugin.md +56 -0
  31. package/claude/commands/do/create-theme.md +70 -0
  32. package/claude/commands/do/mock-data.md +67 -0
  33. package/claude/commands/do/reset-db.md +71 -0
  34. package/claude/commands/do/setup-scheduled-action.md +75 -0
  35. package/claude/commands/do/sync-code-review.md +117 -0
  36. package/claude/commands/do/update-selectors.md +112 -0
  37. package/claude/commands/do/use-skills.md +90 -0
  38. package/claude/commands/do/validate-blocks.md +69 -0
  39. package/claude/commands/how-to/README.md +261 -0
  40. package/claude/commands/how-to/add-metadata.md +692 -0
  41. package/claude/commands/how-to/add-taxonomies.md +806 -0
  42. package/claude/commands/how-to/add-translations.md +571 -0
  43. package/claude/commands/how-to/create-api.md +577 -0
  44. package/claude/commands/how-to/create-block.md +575 -0
  45. package/claude/commands/how-to/create-child-entities.md +771 -0
  46. package/claude/commands/how-to/create-entity.md +597 -0
  47. package/claude/commands/how-to/create-migrations.md +605 -0
  48. package/claude/commands/how-to/create-plugin.md +654 -0
  49. package/claude/commands/how-to/customize-app.md +481 -0
  50. package/claude/commands/how-to/customize-dashboard.md +553 -0
  51. package/claude/commands/how-to/customize-theme.md +438 -0
  52. package/claude/commands/how-to/define-features-flows.md +632 -0
  53. package/claude/commands/how-to/deploy.md +507 -0
  54. package/claude/commands/how-to/handle-file-uploads.md +746 -0
  55. package/claude/commands/how-to/implement-search.md +1001 -0
  56. package/claude/commands/how-to/install-plugins.md +352 -0
  57. package/claude/commands/how-to/manage-test-coverage.md +984 -0
  58. package/claude/commands/how-to/run-tests.md +400 -0
  59. package/claude/commands/how-to/set-app-languages.md +601 -0
  60. package/claude/commands/how-to/set-plans-and-permissions.md +575 -0
  61. package/claude/commands/how-to/set-scheduled-actions.md +527 -0
  62. package/claude/commands/how-to/set-user-roles-and-permissions.md +550 -0
  63. package/claude/commands/how-to/setup-authentication.md +388 -0
  64. package/claude/commands/how-to/setup-claude-code.md +440 -0
  65. package/claude/commands/how-to/setup-database.md +274 -0
  66. package/claude/commands/how-to/setup-email-providers.md +598 -0
  67. package/claude/commands/how-to/setup-mobile-dev.md +627 -0
  68. package/claude/commands/how-to/start.md +500 -0
  69. package/claude/commands/how-to/use-devtools.md +639 -0
  70. package/claude/commands/how-to/use-superadmin.md +622 -0
  71. package/claude/commands/session/README.md +193 -0
  72. package/claude/commands/session/block-create.md +190 -0
  73. package/claude/commands/session/block-list.md +203 -0
  74. package/claude/commands/session/block-update.md +192 -0
  75. package/claude/commands/session/block-validate.md +218 -0
  76. package/claude/commands/session/changelog.md +115 -0
  77. package/claude/commands/session/close.md +225 -0
  78. package/claude/commands/session/commit.md +174 -0
  79. package/claude/commands/session/db-entity.md +206 -0
  80. package/claude/commands/session/db-fix.md +212 -0
  81. package/claude/commands/session/db-sample.md +206 -0
  82. package/claude/commands/session/demo.md +178 -0
  83. package/claude/commands/session/doc-bdd.md +207 -0
  84. package/claude/commands/session/doc-feature.md +218 -0
  85. package/claude/commands/session/doc-read.md +225 -0
  86. package/claude/commands/session/execute.md +204 -0
  87. package/claude/commands/session/explain.md +202 -0
  88. package/claude/commands/session/fix-bug.md +210 -0
  89. package/claude/commands/session/fix-build.md +182 -0
  90. package/claude/commands/session/fix-test.md +189 -0
  91. package/claude/commands/session/pending.md +232 -0
  92. package/claude/commands/session/refine.md +188 -0
  93. package/claude/commands/session/resume.md +192 -0
  94. package/claude/commands/session/review.md +192 -0
  95. package/claude/commands/session/scope-change.md +181 -0
  96. package/claude/commands/session/start-blocks.md +347 -0
  97. package/claude/commands/session/start.md +604 -0
  98. package/claude/commands/session/status.md +169 -0
  99. package/claude/commands/session/test-fix.md +221 -0
  100. package/claude/commands/session/test-run.md +203 -0
  101. package/claude/commands/session/test-write.md +242 -0
  102. package/claude/commands/session/validate.md +162 -0
  103. package/claude/config/context.json +40 -0
  104. package/claude/config/github.json +69 -0
  105. package/claude/config/github.schema.json +106 -0
  106. package/claude/config/team.json +46 -0
  107. package/claude/config/team.schema.json +106 -0
  108. package/claude/config/workspace.json +43 -0
  109. package/claude/config/workspace.schema.json +75 -0
  110. package/claude/skills/README.md +228 -0
  111. package/claude/skills/accessibility/SKILL.md +573 -0
  112. package/claude/skills/api-bypass-layers/SKILL.md +550 -0
  113. package/claude/skills/asana-integration/SKILL.md +499 -0
  114. package/claude/skills/better-auth/SKILL.md +666 -0
  115. package/claude/skills/billing-subscriptions/SKILL.md +660 -0
  116. package/claude/skills/block-decision-matrix/SKILL.md +359 -0
  117. package/claude/skills/clickup-integration/SKILL.md +434 -0
  118. package/claude/skills/core-theme-responsibilities/SKILL.md +485 -0
  119. package/claude/skills/create-plugin/SKILL.md +425 -0
  120. package/claude/skills/create-theme/SKILL.md +331 -0
  121. package/claude/skills/cypress-api/SKILL.md +511 -0
  122. package/claude/skills/cypress-api/scripts/generate-api-controller.py +329 -0
  123. package/claude/skills/cypress-api/scripts/generate-api-test.py +930 -0
  124. package/claude/skills/cypress-e2e/SKILL.md +526 -0
  125. package/claude/skills/cypress-e2e/scripts/extract-selectors.py +383 -0
  126. package/claude/skills/cypress-e2e/scripts/generate-uat-test.py +788 -0
  127. package/claude/skills/cypress-selectors/SKILL.md +309 -0
  128. package/claude/skills/cypress-selectors/scripts/extract-missing.py +243 -0
  129. package/claude/skills/cypress-selectors/scripts/generate-block-selectors.py +283 -0
  130. package/claude/skills/cypress-selectors/scripts/validate-selectors.py +145 -0
  131. package/claude/skills/database-migrations/SKILL.md +335 -0
  132. package/claude/skills/database-migrations/scripts/generate-sample-data.py +284 -0
  133. package/claude/skills/database-migrations/scripts/validate-migration.py +323 -0
  134. package/claude/skills/design-system/SKILL.md +682 -0
  135. package/claude/skills/documentation/SKILL.md +540 -0
  136. package/claude/skills/entity-api/SKILL.md +482 -0
  137. package/claude/skills/entity-system/SKILL.md +635 -0
  138. package/claude/skills/entity-system/scripts/generate-child-migration.py +298 -0
  139. package/claude/skills/entity-system/scripts/generate-metas-migration.py +233 -0
  140. package/claude/skills/entity-system/scripts/generate-migration.py +382 -0
  141. package/claude/skills/entity-system/scripts/generate-sample-data.py +418 -0
  142. package/claude/skills/entity-system/scripts/scaffold-entity.py +661 -0
  143. package/claude/skills/github/SKILL.md +467 -0
  144. package/claude/skills/i18n-nextintl/SKILL.md +302 -0
  145. package/claude/skills/i18n-nextintl/scripts/add-translation.py +243 -0
  146. package/claude/skills/i18n-nextintl/scripts/extract-hardcoded.py +246 -0
  147. package/claude/skills/i18n-nextintl/scripts/validate-translations.py +260 -0
  148. package/claude/skills/impact-analysis/SKILL.md +203 -0
  149. package/claude/skills/jest-unit/SKILL.md +306 -0
  150. package/claude/skills/jest-unit/references/component-testing.md +371 -0
  151. package/claude/skills/jest-unit/references/mocking-patterns.md +380 -0
  152. package/claude/skills/jest-unit/references/service-hook-testing.md +454 -0
  153. package/claude/skills/jira-integration/SKILL.md +539 -0
  154. package/claude/skills/media-library/SKILL.md +743 -0
  155. package/claude/skills/mock-analysis/SKILL.md +276 -0
  156. package/claude/skills/monorepo-architecture/SKILL.md +162 -0
  157. package/claude/skills/nextjs-api-development/SKILL.md +364 -0
  158. package/claude/skills/nextjs-api-development/scripts/generate-crud-tests.py +456 -0
  159. package/claude/skills/nextjs-api-development/scripts/scaffold-endpoint.py +481 -0
  160. package/claude/skills/nextjs-api-development/scripts/validate-api.py +283 -0
  161. package/claude/skills/notion-integration/SKILL.md +641 -0
  162. package/claude/skills/npm-development-workflow/SKILL.md +480 -0
  163. package/claude/skills/page-builder-blocks/SKILL.md +530 -0
  164. package/claude/skills/page-builder-blocks/scripts/scaffold-block.py +444 -0
  165. package/claude/skills/permissions-system/SKILL.md +619 -0
  166. package/claude/skills/plugins/SKILL.md +340 -0
  167. package/claude/skills/plugins/references/plugin-templates.md +414 -0
  168. package/claude/skills/plugins/references/plugin-testing.md +353 -0
  169. package/claude/skills/plugins/references/plugin-types.md +198 -0
  170. package/claude/skills/plugins/scripts/scaffold-plugin.py +443 -0
  171. package/claude/skills/pom-patterns/SKILL.md +452 -0
  172. package/claude/skills/pom-patterns/scripts/generate-pom.py +392 -0
  173. package/claude/skills/rate-limiting/SKILL.md +342 -0
  174. package/claude/skills/react-best-practices/AGENTS.md +2410 -0
  175. package/claude/skills/react-best-practices/README.md +123 -0
  176. package/claude/skills/react-best-practices/SKILL.md +125 -0
  177. package/claude/skills/react-best-practices/metadata.json +15 -0
  178. package/claude/skills/react-best-practices/rules/_sections.md +46 -0
  179. package/claude/skills/react-best-practices/rules/_template.md +28 -0
  180. package/claude/skills/react-best-practices/rules/advanced-event-handler-refs.md +55 -0
  181. package/claude/skills/react-best-practices/rules/advanced-use-latest.md +49 -0
  182. package/claude/skills/react-best-practices/rules/async-api-routes.md +38 -0
  183. package/claude/skills/react-best-practices/rules/async-defer-await.md +80 -0
  184. package/claude/skills/react-best-practices/rules/async-dependencies.md +36 -0
  185. package/claude/skills/react-best-practices/rules/async-parallel.md +28 -0
  186. package/claude/skills/react-best-practices/rules/async-suspense-boundaries.md +99 -0
  187. package/claude/skills/react-best-practices/rules/bundle-barrel-imports.md +59 -0
  188. package/claude/skills/react-best-practices/rules/bundle-conditional.md +31 -0
  189. package/claude/skills/react-best-practices/rules/bundle-defer-third-party.md +49 -0
  190. package/claude/skills/react-best-practices/rules/bundle-dynamic-imports.md +35 -0
  191. package/claude/skills/react-best-practices/rules/bundle-preload.md +50 -0
  192. package/claude/skills/react-best-practices/rules/client-event-listeners.md +74 -0
  193. package/claude/skills/react-best-practices/rules/client-localstorage-schema.md +71 -0
  194. package/claude/skills/react-best-practices/rules/client-passive-event-listeners.md +48 -0
  195. package/claude/skills/react-best-practices/rules/client-swr-dedup.md +56 -0
  196. package/claude/skills/react-best-practices/rules/js-batch-dom-css.md +82 -0
  197. package/claude/skills/react-best-practices/rules/js-cache-function-results.md +80 -0
  198. package/claude/skills/react-best-practices/rules/js-cache-property-access.md +28 -0
  199. package/claude/skills/react-best-practices/rules/js-cache-storage.md +70 -0
  200. package/claude/skills/react-best-practices/rules/js-combine-iterations.md +32 -0
  201. package/claude/skills/react-best-practices/rules/js-early-exit.md +50 -0
  202. package/claude/skills/react-best-practices/rules/js-hoist-regexp.md +45 -0
  203. package/claude/skills/react-best-practices/rules/js-index-maps.md +37 -0
  204. package/claude/skills/react-best-practices/rules/js-length-check-first.md +49 -0
  205. package/claude/skills/react-best-practices/rules/js-min-max-loop.md +82 -0
  206. package/claude/skills/react-best-practices/rules/js-set-map-lookups.md +24 -0
  207. package/claude/skills/react-best-practices/rules/js-tosorted-immutable.md +57 -0
  208. package/claude/skills/react-best-practices/rules/rendering-activity.md +26 -0
  209. package/claude/skills/react-best-practices/rules/rendering-animate-svg-wrapper.md +47 -0
  210. package/claude/skills/react-best-practices/rules/rendering-conditional-render.md +40 -0
  211. package/claude/skills/react-best-practices/rules/rendering-content-visibility.md +38 -0
  212. package/claude/skills/react-best-practices/rules/rendering-hoist-jsx.md +46 -0
  213. package/claude/skills/react-best-practices/rules/rendering-hydration-no-flicker.md +82 -0
  214. package/claude/skills/react-best-practices/rules/rendering-svg-precision.md +28 -0
  215. package/claude/skills/react-best-practices/rules/rerender-defer-reads.md +39 -0
  216. package/claude/skills/react-best-practices/rules/rerender-dependencies.md +45 -0
  217. package/claude/skills/react-best-practices/rules/rerender-derived-state.md +29 -0
  218. package/claude/skills/react-best-practices/rules/rerender-functional-setstate.md +74 -0
  219. package/claude/skills/react-best-practices/rules/rerender-lazy-state-init.md +58 -0
  220. package/claude/skills/react-best-practices/rules/rerender-memo.md +44 -0
  221. package/claude/skills/react-best-practices/rules/rerender-transitions.md +40 -0
  222. package/claude/skills/react-best-practices/rules/server-after-nonblocking.md +73 -0
  223. package/claude/skills/react-best-practices/rules/server-cache-lru.md +41 -0
  224. package/claude/skills/react-best-practices/rules/server-cache-react.md +76 -0
  225. package/claude/skills/react-best-practices/rules/server-parallel-fetching.md +83 -0
  226. package/claude/skills/react-best-practices/rules/server-serialization.md +38 -0
  227. package/claude/skills/react-patterns/SKILL.md +688 -0
  228. package/claude/skills/registry-system/SKILL.md +331 -0
  229. package/claude/skills/scheduled-actions/SKILL.md +671 -0
  230. package/claude/skills/scope-enforcement/SKILL.md +542 -0
  231. package/claude/skills/scope-enforcement/scripts/validate-scope.py +357 -0
  232. package/claude/skills/server-actions/SKILL.md +493 -0
  233. package/claude/skills/service-layer/SKILL.md +587 -0
  234. package/claude/skills/session-management/SKILL.md +266 -0
  235. package/claude/skills/session-management/scripts/create-session.py +166 -0
  236. package/claude/skills/session-management/scripts/iteration-close.sh +105 -0
  237. package/claude/skills/session-management/scripts/iteration-init.sh +180 -0
  238. package/claude/skills/session-management/scripts/session-archive.sh +87 -0
  239. package/claude/skills/session-management/scripts/session-close.sh +133 -0
  240. package/claude/skills/session-management/scripts/session-init.sh +225 -0
  241. package/claude/skills/session-management/scripts/session-list.sh +163 -0
  242. package/claude/skills/session-management/scripts/split-plan.sh +116 -0
  243. package/claude/skills/shadcn-components/SKILL.md +586 -0
  244. package/claude/skills/shadcn-theming/SKILL.md +446 -0
  245. package/claude/skills/suspense-loading/SKILL.md +280 -0
  246. package/claude/skills/tailwind-theming/SKILL.md +507 -0
  247. package/claude/skills/tanstack-query/SKILL.md +608 -0
  248. package/claude/skills/test-coverage/SKILL.md +239 -0
  249. package/claude/skills/web-design-guidelines/SKILL.md +39 -0
  250. package/claude/skills/zod-validation/SKILL.md +537 -0
  251. package/claude/templates/blocks/progress.md +86 -0
  252. package/claude/templates/iteration/changes.md +61 -0
  253. package/claude/templates/iteration/progress.md +55 -0
  254. package/claude/templates/log.md +31 -0
  255. package/claude/templates/story/context.md +77 -0
  256. package/claude/templates/story/pendings.md +37 -0
  257. package/claude/templates/story/plan.md +299 -0
  258. package/claude/templates/story/requirements.md +109 -0
  259. package/claude/templates/story/scope.json +10 -0
  260. package/claude/templates/story/tests.md +91 -0
  261. package/claude/templates/task/progress.md +58 -0
  262. package/claude/templates/task/requirements.md +54 -0
  263. package/claude/workflows/README.md +154 -0
  264. package/claude/workflows/blocks.md +614 -0
  265. package/claude/workflows/story.md +1207 -0
  266. package/claude/workflows/task.md +927 -0
  267. package/claude/workflows/tweak.md +527 -0
  268. package/cursor/.gitkeep +0 -0
  269. package/package.json +35 -0
  270. package/scripts/postinstall.mjs +198 -0
  271. package/scripts/setup.mjs +282 -0
  272. package/scripts/sync.mjs +209 -0
@@ -0,0 +1,302 @@
1
+ ---
2
+ name: i18n-nextintl
3
+ description: |
4
+ Internationalization with next-intl for Next.js 15.
5
+ Supports core/theme/entity message layers, namespace groups, and translation registry.
6
+ Use this skill when adding translations, validating i18n, or working with localized content.
7
+ allowed-tools: Read, Glob, Grep, Bash(python:*)
8
+ version: 1.0.0
9
+ ---
10
+
11
+ # i18n with next-intl Skill
12
+
13
+ Internationalization patterns for Next.js 15 using next-intl with auto-generated translation registry.
14
+
15
+ ## Architecture Overview
16
+
17
+ ```
18
+ ┌─────────────────────────────────────────────────────────────────┐
19
+ │ TRANSLATION SOURCES │
20
+ ├─────────────────────────────────────────────────────────────────┤
21
+ │ │
22
+ │ 1. CORE MESSAGES (Application-wide) │
23
+ │ core/messages/{locale}/ │
24
+ │ ├── index.ts # Re-exports all namespaces │
25
+ │ ├── common.json # Buttons, labels, etc. │
26
+ │ ├── auth.json # Authentication messages │
27
+ │ ├── dashboard.json # Dashboard UI │
28
+ │ └── ... │
29
+ │ │
30
+ │ 2. THEME MESSAGES (Theme-specific overrides) │
31
+ │ contents/themes/{theme}/messages/{locale}.json │
32
+ │ - Extends/overrides core translations │
33
+ │ - Custom roles (editor, moderator) ONLY here │
34
+ │ │
35
+ │ 3. ENTITY MESSAGES (Entity-specific) │
36
+ │ contents/themes/{theme}/entities/{entity}/messages/ │
37
+ │ - Field labels, placeholders, descriptions │
38
+ │ │
39
+ └─────────────────────────────────────────────────────────────────┘
40
+ ```
41
+
42
+ ## When to Use This Skill
43
+
44
+ - Adding new translations to components
45
+ - Validating translation completeness (EN/ES)
46
+ - Finding hardcoded strings in UI
47
+ - Understanding namespace structure
48
+ - Working with custom team roles (theme-level only)
49
+
50
+ ## Supported Locales
51
+
52
+ - `en` - English (default)
53
+ - `es` - Spanish
54
+
55
+ ## Key Concepts
56
+
57
+ ### Namespace Groups
58
+
59
+ The system uses optimized namespace loading based on page context:
60
+
61
+ ```typescript
62
+ const NAMESPACE_GROUPS = {
63
+ // Public pages (includes auth for login/signup buttons)
64
+ PUBLIC_INITIAL: ['common', 'public', 'auth'],
65
+
66
+ // Dashboard (authenticated users)
67
+ DASHBOARD_AUTHENTICATED: ['common', 'dashboard', 'settings', 'public', 'teams'],
68
+
69
+ // Auth-specific pages
70
+ AUTH_ONLY: ['common', 'auth', 'validation'],
71
+
72
+ // Fallback (all namespaces)
73
+ ALL: ['common', 'dashboard', 'settings', 'auth', 'public', 'validation', 'teams']
74
+ }
75
+ ```
76
+
77
+ ### Translation Registry
78
+
79
+ Auto-generated at `core/lib/registries/translation-registry.ts`:
80
+
81
+ ```typescript
82
+ // ✅ CORRECT - Use registry functions
83
+ import { loadThemeTranslation } from '@/core/lib/registries/translation-registry'
84
+
85
+ const translations = await loadThemeTranslation(themeName, locale)
86
+
87
+ // ❌ NEVER - Runtime string interpolation
88
+ const translations = await import(`@/contents/themes/${theme}/messages/${locale}.json`)
89
+ ```
90
+
91
+ ## Component Patterns
92
+
93
+ ### Server Components
94
+
95
+ ```typescript
96
+ import { getTranslations } from 'next-intl/server'
97
+
98
+ export default async function WelcomePage() {
99
+ const t = await getTranslations('welcome')
100
+
101
+ return (
102
+ <div>
103
+ <h1>{t('title')}</h1>
104
+ <p>{t('description')}</p>
105
+ </div>
106
+ )
107
+ }
108
+ ```
109
+
110
+ ### Client Components
111
+
112
+ ```typescript
113
+ 'use client'
114
+ import { useTranslations } from 'next-intl'
115
+
116
+ export function WelcomeCard() {
117
+ const t = useTranslations('welcome')
118
+
119
+ return (
120
+ <div>
121
+ <h2>{t('title')}</h2>
122
+ <p>{t('description')}</p>
123
+ </div>
124
+ )
125
+ }
126
+ ```
127
+
128
+ ### With Dynamic Values
129
+
130
+ ```typescript
131
+ // Translation file
132
+ {
133
+ "welcome": {
134
+ "greeting": "Hello, {name}!",
135
+ "items": "{count, plural, =0 {No items} =1 {One item} other {# items}}"
136
+ }
137
+ }
138
+
139
+ // Component
140
+ const t = useTranslations('welcome')
141
+ <p>{t('greeting', { name: user.name })}</p>
142
+ <p>{t('items', { count: items.length })}</p>
143
+ ```
144
+
145
+ ## Custom Roles Rule (CRITICAL)
146
+
147
+ **Custom role translations MUST NEVER be in core/messages/. They belong ONLY in theme messages.**
148
+
149
+ | Translation Key | Core (`core/messages/`) | Theme (`contents/themes/*/messages/`) |
150
+ |-----------------|-------------------------|---------------------------------------|
151
+ | `teams.roles.owner` | MUST define here | Can override |
152
+ | `teams.roles.admin` | MUST define here | Can override |
153
+ | `teams.roles.member` | MUST define here | Can override |
154
+ | `teams.roles.viewer` | MUST define here | Can override |
155
+ | `teams.roles.editor` | MUST NOT define | MUST define here |
156
+ | `teams.roles.moderator` | MUST NOT define | MUST define here |
157
+
158
+ ### Correct Pattern
159
+
160
+ ```json
161
+ // core/messages/en/teams.json - ONLY core roles
162
+ {
163
+ "teams": {
164
+ "roles": {
165
+ "owner": "Owner",
166
+ "admin": "Administrator",
167
+ "member": "Member",
168
+ "viewer": "Viewer"
169
+ }
170
+ }
171
+ }
172
+
173
+ // contents/themes/default/messages/en.json - Theme extends
174
+ {
175
+ "teams": {
176
+ "roles": {
177
+ "editor": "Editor",
178
+ "moderator": "Moderator"
179
+ }
180
+ }
181
+ }
182
+ ```
183
+
184
+ ## Translation Key Naming
185
+
186
+ ```typescript
187
+ // ✅ CORRECT - Hierarchical, descriptive
188
+ {
189
+ "auth": {
190
+ "login": {
191
+ "title": "Sign In",
192
+ "emailLabel": "Email Address",
193
+ "errors": {
194
+ "invalidCredentials": "Invalid email or password"
195
+ }
196
+ }
197
+ }
198
+ }
199
+
200
+ // ❌ FORBIDDEN - Flat, unclear keys
201
+ {
202
+ "login_title": "Sign In",
203
+ "email": "Email"
204
+ }
205
+ ```
206
+
207
+ ## Scripts
208
+
209
+ ### Find Hardcoded Strings
210
+ ```bash
211
+ # Find hardcoded strings in components
212
+ python .claude/skills/i18n-nextintl/scripts/extract-hardcoded.py \
213
+ --path contents/themes/default/components/
214
+
215
+ # Preview without file details
216
+ python .claude/skills/i18n-nextintl/scripts/extract-hardcoded.py \
217
+ --path app/ \
218
+ --dry-run
219
+ ```
220
+
221
+ ### Validate Translation Completeness
222
+ ```bash
223
+ # Compare EN and ES translations
224
+ python .claude/skills/i18n-nextintl/scripts/validate-translations.py
225
+
226
+ # Check theme-specific translations
227
+ python .claude/skills/i18n-nextintl/scripts/validate-translations.py \
228
+ --theme default
229
+
230
+ # Strict mode (exit with error if missing keys)
231
+ python .claude/skills/i18n-nextintl/scripts/validate-translations.py \
232
+ --strict
233
+ ```
234
+
235
+ ### Add Translation Key
236
+ ```bash
237
+ # Add key to both locales
238
+ python .claude/skills/i18n-nextintl/scripts/add-translation.py \
239
+ --key "settings.profile.title" \
240
+ --en "Profile Settings" \
241
+ --es "Configuracion de Perfil"
242
+
243
+ # Add to theme messages instead of core
244
+ python .claude/skills/i18n-nextintl/scripts/add-translation.py \
245
+ --key "teams.roles.editor" \
246
+ --en "Editor" \
247
+ --es "Editor" \
248
+ --theme default
249
+
250
+ # Preview without writing
251
+ python .claude/skills/i18n-nextintl/scripts/add-translation.py \
252
+ --key "new.key" \
253
+ --en "Value" \
254
+ --es "Valor" \
255
+ --dry-run
256
+ ```
257
+
258
+ ## Anti-Patterns
259
+
260
+ ```typescript
261
+ // ❌ NEVER: Hardcoded user-facing text
262
+ export function WelcomeCard() {
263
+ return <h1>Welcome to Dashboard</h1> // Wrong!
264
+ }
265
+
266
+ // ❌ NEVER: String concatenation
267
+ const message = "Welcome, " + userName + "!"
268
+
269
+ // ❌ NEVER: Runtime string interpolation in imports
270
+ const translations = await import(`@/core/messages/${locale}/`)
271
+
272
+ // ✅ CORRECT: Use translations
273
+ export function WelcomeCard() {
274
+ const t = useTranslations('dashboard')
275
+ return <h1>{t('welcome')}</h1>
276
+ }
277
+
278
+ // ✅ CORRECT: Use interpolation
279
+ const message = t('greeting', { name: userName })
280
+ ```
281
+
282
+ ## File Locations
283
+
284
+ | Type | Location | Who Modifies |
285
+ |------|----------|--------------|
286
+ | Core translations | `core/messages/{locale}/` | Core maintainers |
287
+ | Theme translations | `contents/themes/{theme}/messages/{locale}.json` | Theme developers |
288
+ | Entity translations | Entity config `i18n.loaders` | Entity developers |
289
+ | Translation registry | `core/lib/registries/translation-registry.ts` | Auto-generated |
290
+ | i18n config | `core/i18n.ts` | Core maintainers |
291
+
292
+ ## Checklist
293
+
294
+ Before committing i18n changes:
295
+
296
+ - [ ] All user-facing text uses translation keys (no hardcoded strings)
297
+ - [ ] Translation keys exist in ALL supported locales (en, es)
298
+ - [ ] Translation keys follow hierarchical naming convention
299
+ - [ ] Pluralization uses ICU message format
300
+ - [ ] Dynamic values use translation interpolation (no concatenation)
301
+ - [ ] Custom roles defined ONLY in theme messages (never core)
302
+ - [ ] No runtime string interpolation in dynamic imports
@@ -0,0 +1,243 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ Add Translation Script
4
+
5
+ Adds a translation key to both EN and ES locales.
6
+ Supports both core messages and theme messages.
7
+
8
+ Usage:
9
+ python add-translation.py --key KEY --en VALUE --es VALUE [--theme THEME]
10
+
11
+ Options:
12
+ --key KEY Dot-notation key (e.g., "settings.profile.title")
13
+ --en VALUE English translation value
14
+ --es VALUE Spanish translation value
15
+ --theme THEME Add to theme messages instead of core
16
+ --namespace NS Core namespace file (e.g., "dashboard", "common")
17
+ --dry-run Preview without writing files
18
+ """
19
+
20
+ import os
21
+ import sys
22
+ import json
23
+ import argparse
24
+ from pathlib import Path
25
+ from typing import Dict, Any
26
+
27
+
28
+ def get_active_theme() -> str:
29
+ """Get active theme from environment or default."""
30
+ return os.environ.get('NEXT_PUBLIC_ACTIVE_THEME', 'default')
31
+
32
+
33
+ def load_json_file(file_path: Path) -> dict:
34
+ """Load JSON file and return dict."""
35
+ try:
36
+ with open(file_path, 'r', encoding='utf-8') as f:
37
+ return json.load(f)
38
+ except FileNotFoundError:
39
+ return {}
40
+ except json.JSONDecodeError as e:
41
+ print(f" Error: Invalid JSON in {file_path}: {e}")
42
+ sys.exit(1)
43
+
44
+
45
+ def save_json_file(file_path: Path, data: dict, dry_run: bool = False) -> None:
46
+ """Save dict to JSON file with proper formatting."""
47
+ if dry_run:
48
+ print(f" Would write to: {file_path}")
49
+ return
50
+
51
+ # Ensure parent directory exists
52
+ file_path.parent.mkdir(parents=True, exist_ok=True)
53
+
54
+ with open(file_path, 'w', encoding='utf-8') as f:
55
+ json.dump(data, f, indent=2, ensure_ascii=False)
56
+ f.write('\n') # Add trailing newline
57
+
58
+
59
+ def set_nested_value(data: dict, key_path: str, value: Any) -> dict:
60
+ """Set a value in a nested dict using dot notation."""
61
+ keys = key_path.split('.')
62
+ current = data
63
+
64
+ # Navigate to the parent of the target key
65
+ for key in keys[:-1]:
66
+ if key not in current:
67
+ current[key] = {}
68
+ elif not isinstance(current[key], dict):
69
+ # Key exists but is not a dict, cannot proceed
70
+ raise ValueError(f"Cannot set '{key_path}': '{key}' is not an object")
71
+ current = current[key]
72
+
73
+ # Set the final value
74
+ current[keys[-1]] = value
75
+ return data
76
+
77
+
78
+ def get_nested_value(data: dict, key_path: str) -> Any:
79
+ """Get a value from a nested dict using dot notation."""
80
+ keys = key_path.split('.')
81
+ current = data
82
+
83
+ for key in keys:
84
+ if not isinstance(current, dict) or key not in current:
85
+ return None
86
+ current = current[key]
87
+
88
+ return current
89
+
90
+
91
+ def infer_namespace(key: str) -> str:
92
+ """Infer namespace from key path."""
93
+ # First part of key is typically the namespace
94
+ parts = key.split('.')
95
+ if len(parts) >= 1:
96
+ return parts[0]
97
+ return 'common'
98
+
99
+
100
+ def add_to_core(key: str, en_value: str, es_value: str, namespace: str, dry_run: bool) -> bool:
101
+ """Add translation to core messages."""
102
+ # Determine file paths
103
+ en_path = Path(f'core/messages/en/{namespace}.json')
104
+ es_path = Path(f'core/messages/es/{namespace}.json')
105
+
106
+ # Load existing data
107
+ en_data = load_json_file(en_path)
108
+ es_data = load_json_file(es_path)
109
+
110
+ # Remove namespace prefix from key if it matches
111
+ key_without_ns = key
112
+ if key.startswith(f'{namespace}.'):
113
+ key_without_ns = key[len(namespace) + 1:]
114
+
115
+ # Check if key already exists
116
+ if get_nested_value(en_data, key_without_ns) is not None:
117
+ print(f" Warning: Key '{key}' already exists in EN")
118
+
119
+ # Set values
120
+ en_data = set_nested_value(en_data, key_without_ns, en_value)
121
+ es_data = set_nested_value(es_data, key_without_ns, es_value)
122
+
123
+ # Save files
124
+ save_json_file(en_path, en_data, dry_run)
125
+ save_json_file(es_path, es_data, dry_run)
126
+
127
+ return True
128
+
129
+
130
+ def add_to_theme(key: str, en_value: str, es_value: str, theme: str, dry_run: bool) -> bool:
131
+ """Add translation to theme messages."""
132
+ en_path = Path(f'contents/themes/{theme}/messages/en.json')
133
+ es_path = Path(f'contents/themes/{theme}/messages/es.json')
134
+
135
+ # Check if theme exists
136
+ theme_path = Path(f'contents/themes/{theme}')
137
+ if not theme_path.exists():
138
+ print(f" Error: Theme '{theme}' not found at {theme_path}")
139
+ return False
140
+
141
+ # Load existing data
142
+ en_data = load_json_file(en_path)
143
+ es_data = load_json_file(es_path)
144
+
145
+ # Check if key already exists
146
+ if get_nested_value(en_data, key) is not None:
147
+ print(f" Warning: Key '{key}' already exists in EN")
148
+
149
+ # Set values
150
+ en_data = set_nested_value(en_data, key, en_value)
151
+ es_data = set_nested_value(es_data, key, es_value)
152
+
153
+ # Save files
154
+ save_json_file(en_path, en_data, dry_run)
155
+ save_json_file(es_path, es_data, dry_run)
156
+
157
+ return True
158
+
159
+
160
+ def main():
161
+ parser = argparse.ArgumentParser(description='Add translation key')
162
+ parser.add_argument('--key', required=True, help='Dot-notation key path')
163
+ parser.add_argument('--en', required=True, help='English value')
164
+ parser.add_argument('--es', required=True, help='Spanish value')
165
+ parser.add_argument('--theme', default=None, help='Add to theme instead of core')
166
+ parser.add_argument('--namespace', default=None, help='Core namespace file')
167
+ parser.add_argument('--dry-run', action='store_true', help='Preview without writing')
168
+
169
+ args = parser.parse_args()
170
+
171
+ print(f"\n{'=' * 60}")
172
+ print(f"ADDING TRANSLATION")
173
+ print(f"{'=' * 60}")
174
+ print(f"Key: {args.key}")
175
+ print(f"EN: {args.en}")
176
+ print(f"ES: {args.es}")
177
+
178
+ if args.theme:
179
+ print(f"Target: Theme ({args.theme})")
180
+ else:
181
+ namespace = args.namespace or infer_namespace(args.key)
182
+ print(f"Target: Core (namespace: {namespace})")
183
+
184
+ print(f"Dry run: {args.dry_run}")
185
+ print(f"{'=' * 60}\n")
186
+
187
+ try:
188
+ if args.theme:
189
+ # Add to theme messages
190
+ success = add_to_theme(args.key, args.en, args.es, args.theme, args.dry_run)
191
+ else:
192
+ # Add to core messages
193
+ namespace = args.namespace or infer_namespace(args.key)
194
+ success = add_to_core(args.key, args.en, args.es, namespace, args.dry_run)
195
+
196
+ if success:
197
+ if args.dry_run:
198
+ print(" DRY RUN: No files were modified")
199
+ else:
200
+ print(" Translation added successfully!")
201
+
202
+ print(f"\n{'=' * 60}")
203
+ print("USAGE IN COMPONENT:")
204
+ print("=" * 60)
205
+
206
+ # Show usage example
207
+ namespace = args.namespace or infer_namespace(args.key)
208
+ key_parts = args.key.split('.')
209
+ if len(key_parts) > 1:
210
+ t_namespace = key_parts[0]
211
+ t_key = '.'.join(key_parts[1:])
212
+ else:
213
+ t_namespace = namespace
214
+ t_key = args.key
215
+
216
+ print(f"""
217
+ // Client component
218
+ import {{ useTranslations }} from 'next-intl'
219
+
220
+ const t = useTranslations('{t_namespace}')
221
+ <span>{{t('{t_key}')}}</span>
222
+
223
+ // Server component
224
+ import {{ getTranslations }} from 'next-intl/server'
225
+
226
+ const t = await getTranslations('{t_namespace}')
227
+ <span>{{t('{t_key}')}}</span>
228
+ """)
229
+ print("=" * 60 + "\n")
230
+ return 0
231
+ else:
232
+ return 1
233
+
234
+ except ValueError as e:
235
+ print(f" Error: {e}")
236
+ return 1
237
+ except Exception as e:
238
+ print(f" Unexpected error: {e}")
239
+ return 1
240
+
241
+
242
+ if __name__ == '__main__':
243
+ sys.exit(main())