nsgm-cli 2.1.14 → 2.1.16

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 (69) hide show
  1. package/README.md +49 -26
  2. package/client/components/ClientProviders.tsx +29 -0
  3. package/client/components/LanguageSwitcher.tsx +59 -0
  4. package/client/components/SSRSafeAntdProvider.tsx +24 -0
  5. package/client/components/SuppressHydrationWarnings.tsx +55 -0
  6. package/client/layout/index.tsx +82 -126
  7. package/client/styled/common.ts +0 -1
  8. package/client/styled/layout/index.ts +218 -104
  9. package/client/styled/template/manage.ts +88 -1
  10. package/client/utils/i18n.ts +68 -0
  11. package/client/utils/menu.tsx +42 -36
  12. package/client/utils/navigation.ts +58 -0
  13. package/client/utils/suppressWarnings.ts +32 -0
  14. package/eslint.config.js +17 -20
  15. package/generation/client/redux/reducers.ts +1 -1
  16. package/generation/client/utils/menu.tsx +36 -30
  17. package/generation/env +3 -0
  18. package/generation/next.config.js +7 -3
  19. package/generation/package.json +5 -2
  20. package/generation/tsconfig.json +6 -19
  21. package/lib/cli/commands/create.js +1 -1
  22. package/lib/cli/commands/delete.js +1 -1
  23. package/lib/cli/commands/init.js +6 -6
  24. package/lib/cli/utils/prompt.d.ts +1 -1
  25. package/lib/cli/utils/prompt.js +76 -117
  26. package/lib/constants.d.ts +6 -1
  27. package/lib/constants.js +12 -2
  28. package/lib/generate.js +1 -0
  29. package/lib/generate_create.js +14 -11
  30. package/lib/generate_delete.js +86 -9
  31. package/lib/generate_init.d.ts +6 -0
  32. package/lib/generate_init.js +125 -5
  33. package/lib/generators/file-generator.d.ts +48 -0
  34. package/lib/generators/file-generator.js +455 -0
  35. package/lib/generators/i18n-generator.d.ts +51 -0
  36. package/lib/generators/i18n-generator.js +320 -0
  37. package/lib/generators/page-generator.d.ts +6 -2
  38. package/lib/generators/page-generator.js +182 -156
  39. package/lib/generators/resolver-generator.d.ts +6 -4
  40. package/lib/generators/resolver-generator.js +114 -75
  41. package/lib/generators/service-generator.d.ts +4 -0
  42. package/lib/generators/service-generator.js +120 -6
  43. package/lib/tsconfig.build.tsbuildinfo +1 -1
  44. package/next-i18next.config.js +18 -0
  45. package/next.config.js +55 -16
  46. package/package.json +7 -2
  47. package/pages/_app.tsx +84 -35
  48. package/pages/_document.tsx +39 -2
  49. package/pages/_error.tsx +66 -0
  50. package/pages/index.tsx +46 -29
  51. package/pages/login.tsx +58 -33
  52. package/pages/template/manage.tsx +95 -109
  53. package/public/locales/en-US/common.json +48 -0
  54. package/public/locales/en-US/home.json +57 -0
  55. package/public/locales/en-US/layout.json +22 -0
  56. package/public/locales/en-US/login.json +13 -0
  57. package/public/locales/en-US/template.json +42 -0
  58. package/public/locales/ja-JP/common.json +48 -0
  59. package/public/locales/ja-JP/home.json +57 -0
  60. package/public/locales/ja-JP/layout.json +22 -0
  61. package/public/locales/ja-JP/login.json +13 -0
  62. package/public/locales/ja-JP/template.json +42 -0
  63. package/public/locales/zh-CN/common.json +48 -0
  64. package/public/locales/zh-CN/home.json +57 -0
  65. package/public/locales/zh-CN/layout.json +22 -0
  66. package/public/locales/zh-CN/login.json +13 -0
  67. package/public/locales/zh-CN/template.json +42 -0
  68. package/server/utils/validation.js +163 -0
  69. package/types/i18next.d.ts +10 -0
@@ -0,0 +1,320 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.I18nGenerator = void 0;
4
+ const base_generator_1 = require("./base-generator");
5
+ /**
6
+ * 国际化文件生成器
7
+ * 生成控制器对应的多语言文件
8
+ */
9
+ class I18nGenerator extends base_generator_1.BaseGenerator {
10
+ /**
11
+ * 生成中文翻译文件
12
+ */
13
+ generateChineseTranslation() {
14
+ const capitalizedController = this.getCapitalizedController();
15
+ const formFields = this.getFormFields();
16
+ const displayFields = this.getDisplayFields();
17
+ // 生成字段翻译
18
+ const fieldTranslations = this.generateFieldTranslations(displayFields, formFields, 'zh-CN');
19
+ // 生成占位符翻译
20
+ const placeholderTranslations = this.generatePlaceholderTranslations(formFields, 'zh-CN');
21
+ return JSON.stringify({
22
+ [this.controller]: {
23
+ title: `${capitalizedController} 管理`,
24
+ fields: fieldTranslations,
25
+ buttons: {
26
+ add: '新增',
27
+ edit: '修改',
28
+ delete: '删除',
29
+ search: '搜索',
30
+ export: '导出',
31
+ import: '导入',
32
+ batchDelete: '批量删除',
33
+ confirm: '确认',
34
+ cancel: '取消',
35
+ },
36
+ placeholders: placeholderTranslations,
37
+ messages: {
38
+ confirmDelete: '确认删除吗',
39
+ confirmBatchDelete: '确认批量删除吗',
40
+ uploadSuccess: '文件上传成功',
41
+ uploadFailed: '文件上传失败',
42
+ onlyExcel: '只能上传 Excel 文件!',
43
+ fileSizeLimit: '文件大小不能超过 2MB!',
44
+ noData: '没有数据无需导出',
45
+ noDataBatchDelete: '没有数据不能批量删除',
46
+ },
47
+ modal: {
48
+ addTitle: `新增 ${capitalizedController}`,
49
+ editTitle: `修改 ${capitalizedController}`,
50
+ },
51
+ pagination: {
52
+ total: '共 {{total}} 条记录',
53
+ },
54
+ },
55
+ }, null, 2);
56
+ }
57
+ /**
58
+ * 生成英文翻译文件
59
+ */
60
+ generateEnglishTranslation() {
61
+ const capitalizedController = this.getCapitalizedController();
62
+ const formFields = this.getFormFields();
63
+ const displayFields = this.getDisplayFields();
64
+ // 生成字段翻译
65
+ const fieldTranslations = this.generateFieldTranslations(displayFields, formFields, 'en-US');
66
+ // 生成占位符翻译
67
+ const placeholderTranslations = this.generatePlaceholderTranslations(formFields, 'en-US');
68
+ return JSON.stringify({
69
+ [this.controller]: {
70
+ title: `${capitalizedController} Management`,
71
+ fields: fieldTranslations,
72
+ buttons: {
73
+ add: 'Add',
74
+ edit: 'Edit',
75
+ delete: 'Delete',
76
+ search: 'Search',
77
+ export: 'Export',
78
+ import: 'Import',
79
+ batchDelete: 'Batch Delete',
80
+ confirm: 'Confirm',
81
+ cancel: 'Cancel',
82
+ },
83
+ placeholders: placeholderTranslations,
84
+ messages: {
85
+ confirmDelete: 'Are you sure to delete?',
86
+ confirmBatchDelete: 'Are you sure to batch delete?',
87
+ uploadSuccess: 'File uploaded successfully',
88
+ uploadFailed: 'File upload failed',
89
+ onlyExcel: 'Only Excel files are allowed!',
90
+ fileSizeLimit: 'File size cannot exceed 2MB!',
91
+ noData: 'No data to export',
92
+ noDataBatchDelete: 'No data to batch delete',
93
+ },
94
+ modal: {
95
+ addTitle: `Add ${capitalizedController}`,
96
+ editTitle: `Edit ${capitalizedController}`,
97
+ },
98
+ pagination: {
99
+ total: 'Total {{total}} records',
100
+ },
101
+ },
102
+ }, null, 2);
103
+ }
104
+ /**
105
+ * 生成日文翻译文件
106
+ */
107
+ generateJapaneseTranslation() {
108
+ const capitalizedController = this.getCapitalizedController();
109
+ const formFields = this.getFormFields();
110
+ const displayFields = this.getDisplayFields();
111
+ // 生成字段翻译
112
+ const fieldTranslations = this.generateFieldTranslations(displayFields, formFields, 'ja-JP');
113
+ // 生成占位符翻译
114
+ const placeholderTranslations = this.generatePlaceholderTranslations(formFields, 'ja-JP');
115
+ return JSON.stringify({
116
+ [this.controller]: {
117
+ title: `${capitalizedController}管理`,
118
+ fields: fieldTranslations,
119
+ buttons: {
120
+ add: '追加',
121
+ edit: '編集',
122
+ delete: '削除',
123
+ search: '検索',
124
+ export: 'エクスポート',
125
+ import: 'インポート',
126
+ batchDelete: '一括削除',
127
+ confirm: '確認',
128
+ cancel: 'キャンセル',
129
+ },
130
+ placeholders: placeholderTranslations,
131
+ messages: {
132
+ confirmDelete: '削除してもよろしいですか?',
133
+ confirmBatchDelete: '一括削除してもよろしいですか?',
134
+ uploadSuccess: 'ファイルのアップロードが成功しました',
135
+ uploadFailed: 'ファイルのアップロードが失敗しました',
136
+ onlyExcel: 'Excelファイルのみアップロード可能です!',
137
+ fileSizeLimit: 'ファイルサイズは2MBを超えることはできません!',
138
+ noData: 'エクスポートするデータがありません',
139
+ noDataBatchDelete: '一括削除するデータがありません',
140
+ },
141
+ modal: {
142
+ addTitle: `${capitalizedController}を追加`,
143
+ editTitle: `${capitalizedController}を編集`,
144
+ },
145
+ pagination: {
146
+ total: '合計 {{total}} 件',
147
+ },
148
+ },
149
+ }, null, 2);
150
+ }
151
+ /**
152
+ * 生成字段翻译
153
+ */
154
+ generateFieldTranslations(displayFields, formFields, locale) {
155
+ const translations = {};
156
+ // 合并显示字段和表单字段,去重
157
+ const allFields = [...displayFields, ...formFields];
158
+ const uniqueFields = allFields.filter((field, index, self) => index === self.findIndex((f) => f.name === field.name));
159
+ // 添加操作列
160
+ translations.actions = this.getActionsTranslation(locale);
161
+ // 为每个字段生成翻译
162
+ uniqueFields.forEach((field) => {
163
+ translations[field.name] = this.getFieldTranslation(field, locale);
164
+ });
165
+ return translations;
166
+ }
167
+ /**
168
+ * 生成占位符翻译
169
+ */
170
+ generatePlaceholderTranslations(formFields, locale) {
171
+ const translations = {};
172
+ formFields.forEach((field) => {
173
+ const fieldName = field.name;
174
+ const capitalizedName = fieldName.charAt(0).toUpperCase() + fieldName.slice(1);
175
+ const fieldTranslation = this.getFieldTranslation(field, locale);
176
+ switch (locale) {
177
+ case 'zh-CN':
178
+ translations[`enter${capitalizedName}`] = `请输入${fieldTranslation}搜索`;
179
+ translations[`input${capitalizedName}`] = `请输入${fieldTranslation}`;
180
+ break;
181
+ case 'en-US':
182
+ translations[`enter${capitalizedName}`] = `Enter ${fieldTranslation.toLowerCase()} to search`;
183
+ translations[`input${capitalizedName}`] = `Enter ${fieldTranslation.toLowerCase()}`;
184
+ break;
185
+ case 'ja-JP':
186
+ translations[`enter${capitalizedName}`] = `${fieldTranslation}を入力して検索`;
187
+ translations[`input${capitalizedName}`] = `${fieldTranslation}を入力`;
188
+ break;
189
+ }
190
+ });
191
+ return translations;
192
+ }
193
+ /**
194
+ * 获取字段翻译
195
+ */
196
+ getFieldTranslation(field, locale) {
197
+ // 如果字段有注释且是中文环境,直接使用注释
198
+ if (field.comment && locale === 'zh-CN') {
199
+ return field.comment;
200
+ }
201
+ // 根据字段名生成对应语言的翻译
202
+ switch (field.name.toLowerCase()) {
203
+ case 'id':
204
+ return 'ID';
205
+ case 'name':
206
+ return locale === 'zh-CN' ? '名称' : locale === 'en-US' ? 'Name' : '名前';
207
+ case 'email':
208
+ return locale === 'zh-CN' ? '邮箱' : locale === 'en-US' ? 'Email' : 'メール';
209
+ case 'phone':
210
+ return locale === 'zh-CN' ? '电话' : locale === 'en-US' ? 'Phone' : '電話';
211
+ case 'address':
212
+ return locale === 'zh-CN' ? '地址' : locale === 'en-US' ? 'Address' : '住所';
213
+ case 'description':
214
+ return locale === 'zh-CN' ? '描述' : locale === 'en-US' ? 'Description' : '説明';
215
+ case 'status':
216
+ return locale === 'zh-CN' ? '状态' : locale === 'en-US' ? 'Status' : 'ステータス';
217
+ case 'created_at':
218
+ case 'create_date':
219
+ return locale === 'zh-CN' ? '创建时间' : locale === 'en-US' ? 'Created At' : '作成日時';
220
+ case 'updated_at':
221
+ case 'update_date':
222
+ return locale === 'zh-CN' ? '更新时间' : locale === 'en-US' ? 'Updated At' : '更新日時';
223
+ default:
224
+ // 如果有中文注释,根据语言环境处理
225
+ if (field.comment) {
226
+ switch (locale) {
227
+ case 'zh-CN':
228
+ return field.comment;
229
+ case 'en-US':
230
+ // 尝试将中文字段名转换为英文(简单映射)
231
+ return this.translateChineseToEnglish(field.comment) || this.formatFieldName(field.name);
232
+ case 'ja-JP':
233
+ // 尝试将中文字段名转换为日文(简单映射)
234
+ return this.translateChineseToJapanese(field.comment) || this.formatFieldName(field.name);
235
+ default:
236
+ return field.comment;
237
+ }
238
+ }
239
+ // 如果没有注释,格式化字段名
240
+ return this.formatFieldName(field.name);
241
+ }
242
+ }
243
+ /**
244
+ * 获取操作列翻译
245
+ */
246
+ getActionsTranslation(locale) {
247
+ switch (locale) {
248
+ case 'zh-CN':
249
+ return '操作';
250
+ case 'en-US':
251
+ return 'Actions';
252
+ case 'ja-JP':
253
+ return '操作';
254
+ default:
255
+ return 'Actions';
256
+ }
257
+ }
258
+ /**
259
+ * 格式化字段名
260
+ */
261
+ formatFieldName(fieldName) {
262
+ // 将下划线转换为空格并首字母大写
263
+ return fieldName.replace(/_/g, ' ').replace(/\b\w/g, (l) => l.toUpperCase());
264
+ }
265
+ /**
266
+ * 简单的中文到英文翻译映射
267
+ */
268
+ translateChineseToEnglish(chinese) {
269
+ const translations = {
270
+ 用户名: 'Username',
271
+ 用户: 'User',
272
+ 邮箱: 'Email',
273
+ 电话: 'Phone',
274
+ 手机: 'Mobile',
275
+ 地址: 'Address',
276
+ 描述: 'Description',
277
+ 状态: 'Status',
278
+ 名称: 'Name',
279
+ 标题: 'Title',
280
+ 内容: 'Content',
281
+ 价格: 'Price',
282
+ 数量: 'Quantity',
283
+ 创建时间: 'Created At',
284
+ 更新时间: 'Updated At',
285
+ 修改时间: 'Modified At',
286
+ };
287
+ return translations[chinese] || null;
288
+ }
289
+ /**
290
+ * 简单的中文到日文翻译映射
291
+ */
292
+ translateChineseToJapanese(chinese) {
293
+ const translations = {
294
+ 用户名: 'ユーザー名',
295
+ 用户: 'ユーザー',
296
+ 邮箱: 'メール',
297
+ 电话: '電話',
298
+ 手机: '携帯電話',
299
+ 地址: '住所',
300
+ 描述: '説明',
301
+ 状态: 'ステータス',
302
+ 名称: '名前',
303
+ 标题: 'タイトル',
304
+ 内容: '内容',
305
+ 价格: '価格',
306
+ 数量: '数量',
307
+ 创建时间: '作成日時',
308
+ 更新时间: '更新日時',
309
+ 修改时间: '変更日時',
310
+ };
311
+ return translations[chinese] || null;
312
+ }
313
+ /**
314
+ * 主生成方法(为了继承BaseGenerator需要实现)
315
+ */
316
+ generate() {
317
+ return this.generateChineseTranslation();
318
+ }
319
+ }
320
+ exports.I18nGenerator = I18nGenerator;
@@ -6,9 +6,9 @@ import { BaseGenerator } from './base-generator';
6
6
  export declare class PageGenerator extends BaseGenerator {
7
7
  generate(): string;
8
8
  /**
9
- * 生成键值标题映射
9
+ * 生成翻译键值标题映射
10
10
  */
11
- private generateKeyTitles;
11
+ private generateTranslationKeyTitles;
12
12
  /**
13
13
  * 生成模态框状态变量
14
14
  */
@@ -38,4 +38,8 @@ export declare class PageGenerator extends BaseGenerator {
38
38
  */
39
39
  private generateExcelColumns;
40
40
  private generateTableColumns;
41
+ /**
42
+ * 生成客户端验证逻辑
43
+ */
44
+ private generateClientValidation;
41
45
  }