@robsun/create-keystone-app 0.2.7 → 0.2.9

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 (29) hide show
  1. package/dist/create-keystone-app.js +0 -0
  2. package/dist/create-module.js +0 -0
  3. package/package.json +7 -6
  4. package/template/.claude/skills/keystone-dev/SKILL.md +38 -13
  5. package/template/.claude/skills/keystone-dev/references/CAPABILITIES.md +80 -2
  6. package/template/.claude/skills/keystone-dev/references/TEMPLATES.md +220 -0
  7. package/template/.codex/skills/keystone-dev/SKILL.md +38 -13
  8. package/template/.codex/skills/keystone-dev/references/CAPABILITIES.md +80 -2
  9. package/template/.codex/skills/keystone-dev/references/TEMPLATES.md +220 -0
  10. package/template/apps/server/go.mod +1 -1
  11. package/template/apps/server/go.sum +1 -0
  12. package/template/apps/server/internal/modules/example/api/handler/item_handler.go +35 -32
  13. package/template/apps/server/internal/modules/example/domain/service/errors.go +13 -0
  14. package/template/apps/server/internal/modules/example/i18n/i18n.go +16 -0
  15. package/template/apps/server/internal/modules/example/i18n/keys.go +23 -0
  16. package/template/apps/server/internal/modules/example/i18n/locales/en-US.json +18 -0
  17. package/template/apps/server/internal/modules/example/i18n/locales/zh-CN.json +18 -0
  18. package/template/apps/server/internal/modules/example/module.go +9 -3
  19. package/template/apps/web/package.json +3 -1
  20. package/template/apps/web/src/app.config.ts +8 -1
  21. package/template/apps/web/src/modules/example/index.ts +7 -1
  22. package/template/apps/web/src/modules/example/locales/en-US/example.json +32 -0
  23. package/template/apps/web/src/modules/example/locales/zh-CN/example.json +32 -0
  24. package/template/apps/web/src/modules/example/pages/ExampleItemsPage.tsx +47 -45
  25. package/template/apps/web/src/modules/example/routes.tsx +6 -2
  26. package/template/docs/CONVENTIONS.md +73 -1
  27. package/template/docs/I18N.md +319 -0
  28. package/template/package.json +1 -0
  29. package/template/scripts/generate-i18n-types.js +154 -0
@@ -0,0 +1,154 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * i18n Type Definition Generator
4
+ *
5
+ * Generates TypeScript type definitions from JSON locale files
6
+ * for type-safe translations in your application.
7
+ *
8
+ * Usage:
9
+ * node scripts/generate-i18n-types.js
10
+ *
11
+ * Output:
12
+ * apps/web/src/types/i18n.d.ts
13
+ */
14
+
15
+ import fs from 'fs'
16
+ import path from 'path'
17
+ import { fileURLToPath } from 'url'
18
+
19
+ const __filename = fileURLToPath(import.meta.url)
20
+ const __dirname = path.dirname(__filename)
21
+ const rootDir = path.resolve(__dirname, '..')
22
+ const webSrcDir = path.join(rootDir, 'apps/web/src')
23
+
24
+ // Configuration
25
+ const LOCALE_DIRS = [
26
+ // Platform locales from keystone-web-core (reference only, not generated)
27
+ // Module locales
28
+ path.join(webSrcDir, 'modules'),
29
+ ]
30
+
31
+ const OUTPUT_FILE = path.join(webSrcDir, 'types/i18n.d.ts')
32
+
33
+ /**
34
+ * Recursively flattens a nested object into dot-notation keys
35
+ */
36
+ function flattenKeys(obj, prefix = '') {
37
+ const keys = []
38
+ for (const [key, value] of Object.entries(obj)) {
39
+ const fullKey = prefix ? `${prefix}.${key}` : key
40
+ if (typeof value === 'object' && value !== null && !Array.isArray(value)) {
41
+ keys.push(...flattenKeys(value, fullKey))
42
+ } else {
43
+ keys.push(fullKey)
44
+ }
45
+ }
46
+ return keys
47
+ }
48
+
49
+ /**
50
+ * Finds all locale JSON files in a directory
51
+ */
52
+ function findLocaleFiles(dir) {
53
+ const files = []
54
+ if (!fs.existsSync(dir)) return files
55
+
56
+ const entries = fs.readdirSync(dir, { withFileTypes: true })
57
+ for (const entry of entries) {
58
+ const fullPath = path.join(dir, entry.name)
59
+ if (entry.isDirectory()) {
60
+ // Look for locales directory
61
+ if (entry.name === 'locales') {
62
+ const zhDir = path.join(fullPath, 'zh-CN')
63
+ if (fs.existsSync(zhDir)) {
64
+ const jsonFiles = fs.readdirSync(zhDir).filter(f => f.endsWith('.json'))
65
+ for (const jsonFile of jsonFiles) {
66
+ files.push({
67
+ namespace: path.basename(jsonFile, '.json'),
68
+ path: path.join(zhDir, jsonFile),
69
+ })
70
+ }
71
+ }
72
+ } else {
73
+ files.push(...findLocaleFiles(fullPath))
74
+ }
75
+ }
76
+ }
77
+ return files
78
+ }
79
+
80
+ /**
81
+ * Generates TypeScript type definitions
82
+ */
83
+ function generateTypes() {
84
+ const namespaces = new Map()
85
+
86
+ // Collect all locale files
87
+ for (const localeDir of LOCALE_DIRS) {
88
+ const files = findLocaleFiles(localeDir)
89
+ for (const file of files) {
90
+ try {
91
+ const content = fs.readFileSync(file.path, 'utf-8')
92
+ const json = JSON.parse(content)
93
+ const keys = flattenKeys(json)
94
+ namespaces.set(file.namespace, keys)
95
+ } catch (err) {
96
+ console.warn(`Warning: Could not parse ${file.path}:`, err.message)
97
+ }
98
+ }
99
+ }
100
+
101
+ if (namespaces.size === 0) {
102
+ console.log('No locale files found. Skipping type generation.')
103
+ return
104
+ }
105
+
106
+ // Generate TypeScript content
107
+ let output = `// Auto-generated by scripts/generate-i18n-types.js
108
+ // Do not edit manually
109
+
110
+ import 'react-i18next'
111
+
112
+ declare module 'react-i18next' {
113
+ interface CustomTypeOptions {
114
+ defaultNS: 'common'
115
+ resources: {
116
+ `
117
+
118
+ for (const [namespace, keys] of namespaces) {
119
+ output += ` ${namespace}: {\n`
120
+ for (const key of keys) {
121
+ // Create nested type from dot notation
122
+ output += ` '${key}': string\n`
123
+ }
124
+ output += ` }\n`
125
+ }
126
+
127
+ output += ` }
128
+ }
129
+ }
130
+
131
+ // Type-safe translation keys
132
+ `
133
+
134
+ for (const [namespace, keys] of namespaces) {
135
+ const typeName = namespace.charAt(0).toUpperCase() + namespace.slice(1) + 'Keys'
136
+ output += `export type ${typeName} = \n`
137
+ output += keys.map(k => ` | '${k}'`).join('\n')
138
+ output += '\n\n'
139
+ }
140
+
141
+ // Ensure output directory exists
142
+ const outputDir = path.dirname(OUTPUT_FILE)
143
+ if (!fs.existsSync(outputDir)) {
144
+ fs.mkdirSync(outputDir, { recursive: true })
145
+ }
146
+
147
+ // Write output file
148
+ fs.writeFileSync(OUTPUT_FILE, output, 'utf-8')
149
+ console.log(`Generated i18n types: ${OUTPUT_FILE}`)
150
+ console.log(`Namespaces: ${[...namespaces.keys()].join(', ')}`)
151
+ }
152
+
153
+ // Run generator
154
+ generateTypes()