@object-ui/i18n 3.1.4 → 3.3.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 (42) hide show
  1. package/.turbo/turbo-build.log +1 -1
  2. package/CHANGELOG.md +10 -0
  3. package/dist/index.d.ts +1 -0
  4. package/dist/index.js +2 -0
  5. package/dist/locales/ar.d.ts +202 -1
  6. package/dist/locales/ar.js +202 -1
  7. package/dist/locales/de.d.ts +202 -1
  8. package/dist/locales/de.js +211 -1
  9. package/dist/locales/en.d.ts +201 -0
  10. package/dist/locales/en.js +211 -0
  11. package/dist/locales/es.d.ts +202 -1
  12. package/dist/locales/es.js +202 -1
  13. package/dist/locales/fr.d.ts +202 -1
  14. package/dist/locales/fr.js +211 -1
  15. package/dist/locales/index.d.ts +2041 -9
  16. package/dist/locales/ja.d.ts +213 -1
  17. package/dist/locales/ja.js +213 -1
  18. package/dist/locales/ko.d.ts +202 -1
  19. package/dist/locales/ko.js +202 -1
  20. package/dist/locales/pt.d.ts +202 -1
  21. package/dist/locales/pt.js +202 -1
  22. package/dist/locales/ru.d.ts +213 -1
  23. package/dist/locales/ru.js +222 -1
  24. package/dist/locales/zh.d.ts +202 -1
  25. package/dist/locales/zh.js +212 -1
  26. package/dist/useSafeTranslation.d.ts +5 -0
  27. package/dist/useSafeTranslation.js +46 -0
  28. package/package.json +6 -6
  29. package/src/__tests__/i18n.test.ts +27 -0
  30. package/src/index.ts +3 -0
  31. package/src/locales/ar.ts +202 -1
  32. package/src/locales/de.ts +211 -1
  33. package/src/locales/en.ts +211 -0
  34. package/src/locales/es.ts +202 -1
  35. package/src/locales/fr.ts +211 -1
  36. package/src/locales/ja.ts +213 -1
  37. package/src/locales/ko.ts +202 -1
  38. package/src/locales/pt.ts +202 -1
  39. package/src/locales/ru.ts +222 -1
  40. package/src/locales/zh.ts +212 -1
  41. package/src/useSafeTranslation.ts +49 -0
  42. package/tsconfig.tsbuildinfo +1 -1
@@ -32,6 +32,8 @@ declare const zh: {
32
32
  readonly noResults: "未找到结果";
33
33
  readonly required: "必填";
34
34
  readonly optional: "选填";
35
+ readonly selectOption: "请选择";
36
+ readonly select: "选择...";
35
37
  };
36
38
  readonly validation: {
37
39
  readonly required: "{{field}}不能为空";
@@ -54,6 +56,11 @@ declare const zh: {
54
56
  readonly saveError: "保存失败";
55
57
  readonly unsavedChanges: "您有未保存的更改,确定要离开吗?";
56
58
  readonly stepOf: "第{{current}}步,共{{total}}步";
59
+ readonly createTitle: "新建{{object}}";
60
+ readonly editTitle: "编辑{{object}}";
61
+ readonly createDescription: "向数据库添加新的{{object}}。";
62
+ readonly editDescription: "更新{{object}}的详情";
63
+ readonly saveRecord: "保存记录";
57
64
  };
58
65
  readonly table: {
59
66
  readonly rowsPerPage: "每页行数";
@@ -146,6 +153,22 @@ declare const zh: {
146
153
  readonly deleteCard: "删除卡片";
147
154
  readonly deleteColumn: "删除列";
148
155
  };
156
+ readonly view: {
157
+ readonly rename: "重命名";
158
+ readonly duplicateView: "复制视图";
159
+ readonly shareView: "共享视图";
160
+ readonly setAsDefault: "设为默认";
161
+ readonly pinView: "固定视图";
162
+ readonly unpinView: "取消固定";
163
+ readonly changeViewType: "更改视图类型";
164
+ readonly deleteView: "删除视图";
165
+ readonly addView: "添加视图";
166
+ readonly unsavedChanges: "未保存的更改";
167
+ readonly saveAsView: "另存为视图";
168
+ readonly moreViews: "还有 {{count}} 个";
169
+ readonly activeFilters: "筛选条件生效中";
170
+ readonly activeSort: "排序生效中";
171
+ };
149
172
  readonly detail: {
150
173
  readonly back: "返回";
151
174
  readonly edit: "编辑";
@@ -191,11 +214,137 @@ declare const zh: {
191
214
  readonly sortBy: "排序";
192
215
  readonly filterPlaceholder: "筛选...";
193
216
  readonly highlightFields: "关键字段";
217
+ readonly comments: "评论";
218
+ readonly searchComments: "搜索评论…";
219
+ readonly addCommentPlaceholder: "添加评论… (Ctrl+Enter 提交)";
220
+ readonly noMatchingComments: "没有匹配的评论";
221
+ readonly noCommentsYet: "暂无评论";
222
+ readonly pinned: "已置顶";
223
+ readonly pin: "置顶";
224
+ readonly unpin: "取消置顶";
225
+ readonly justNow: "刚刚";
226
+ readonly minutesAgo: "{{count}}分钟前";
227
+ readonly hoursAgo: "{{count}}小时前";
228
+ readonly daysAgo: "{{count}}天前";
229
+ readonly dropFilesToUpload: "拖拽文件到此处或点击上传";
230
+ readonly attachmentCount: "{{count}} 个附件";
231
+ readonly attachmentCountPlural: "{{count}} 个附件";
232
+ readonly removeAttachment: "移除附件";
233
+ readonly unifiedDiff: "统一视图";
234
+ readonly sideBySideDiff: "并排视图";
235
+ readonly noChanges: "无变更";
236
+ readonly previousVersion: "旧版本";
237
+ readonly currentVersion: "新版本";
238
+ readonly discussion: "讨论";
239
+ readonly showDiscussion: "显示讨论 ({{count}})";
240
+ readonly hideDiscussion: "隐藏讨论";
241
+ readonly bold: "粗体 (Ctrl+B)";
242
+ readonly italic: "斜体 (Ctrl+I)";
243
+ readonly listFormat: "列表";
244
+ readonly inlineCode: "行内代码";
245
+ readonly mentionSomeone: "提及某人";
246
+ readonly preview: "预览";
247
+ readonly submitComment: "提交 (Ctrl+Enter)";
248
+ readonly writeComment: "写评论…";
249
+ readonly subscribedTooltip: "已订阅 — 点击取消订阅";
250
+ readonly unsubscribedTooltip: "订阅通知";
251
+ readonly firstRecord: "第一条记录 (Home)";
252
+ readonly previousRecordKey: "上一条记录 (←)";
253
+ readonly nextRecordKey: "下一条记录 (→)";
254
+ readonly lastRecord: "最后一条记录 (End)";
255
+ readonly noRecords: "无记录";
256
+ readonly searchWhileNavigating: "导航时搜索";
257
+ readonly searchRecords: "搜索记录…";
258
+ readonly allActivity: "全部动态";
259
+ readonly commentsOnly: "仅评论";
260
+ readonly fieldChangesFilter: "字段变更";
261
+ readonly tasksOnly: "仅任务";
262
+ readonly leaveCommentPlaceholder: "留下评论… (Ctrl+Enter 提交)";
263
+ readonly noActivity: "暂无活动记录";
264
+ readonly loadMore: "加载更多";
265
+ readonly edited: "(已编辑)";
266
+ readonly via: "通过 {{source}}";
267
+ readonly replyCount: "{{count}} 条回复";
268
+ readonly replyCountPlural: "{{count}} 条回复";
269
+ readonly replyPlaceholder: "回复…";
270
+ readonly filterActivity: "筛选活动";
271
+ readonly openDiscussion: "打开讨论面板";
272
+ readonly closeDiscussion: "关闭讨论面板";
273
+ readonly subscribeAriaLabel: "订阅通知";
274
+ readonly unsubscribeAriaLabel: "取消订阅通知";
275
+ readonly clearSearch: "清除搜索";
194
276
  };
195
277
  readonly chart: {
196
278
  readonly noData: "暂无图表数据";
197
279
  readonly loading: "图表加载中...";
198
280
  };
281
+ readonly map: {
282
+ readonly searchLocations: "搜索位置…";
283
+ readonly locationDetails: "位置详情";
284
+ readonly markersCount: "{{count}} 个标记";
285
+ readonly invalidCoordinates: "{{count}} 条记录因坐标缺失或无效已从地图中排除。";
286
+ readonly invalidCoordinatesPlural: "{{count}} 条记录因坐标缺失或无效已从地图中排除。";
287
+ };
288
+ readonly workflow: {
289
+ readonly draft: "草稿";
290
+ readonly active: "活跃";
291
+ readonly paused: "已暂停";
292
+ readonly completed: "已完成";
293
+ readonly cancelled: "已取消";
294
+ readonly save: "保存";
295
+ readonly publish: "发布";
296
+ readonly addNode: "添加节点";
297
+ readonly workflowFlow: "工作流程";
298
+ readonly properties: "属性";
299
+ readonly connections: "连接";
300
+ readonly quickConnect: "快速连接";
301
+ readonly fromPlaceholder: "从...";
302
+ readonly toPlaceholder: "到...";
303
+ readonly connect: "连接";
304
+ readonly label: "标签";
305
+ readonly type: "类型";
306
+ readonly description: "描述";
307
+ readonly assignee: "负责人";
308
+ readonly assigneeType: "负责人类型";
309
+ readonly user: "用户";
310
+ readonly role: "角色";
311
+ readonly group: "组";
312
+ readonly expression: "表达式";
313
+ readonly timeoutMinutes: "超时时间(分钟)";
314
+ readonly selectNodeToEdit: "选择节点以编辑其属性";
315
+ readonly workflowTitle: "工作流标题";
316
+ readonly newWorkflow: "新工作流";
317
+ readonly outConnections: "{{count}} 个输出";
318
+ readonly start: "开始";
319
+ readonly end: "结束";
320
+ readonly task: "任务";
321
+ readonly userTask: "用户任务";
322
+ readonly serviceTask: "服务任务";
323
+ readonly scriptTask: "脚本任务";
324
+ readonly approval: "审批";
325
+ readonly condition: "条件";
326
+ readonly parallelGateway: "并行网关";
327
+ readonly joinGateway: "合并网关";
328
+ readonly boundaryEvent: "边界事件";
329
+ readonly delay: "延迟";
330
+ readonly notification: "通知";
331
+ readonly webhook: "Webhook";
332
+ readonly allowConcurrency: "允许(并发执行)";
333
+ readonly forbidConcurrency: "禁止(跳过新任务)";
334
+ readonly replaceConcurrency: "替换(取消现有任务)";
335
+ readonly queueConcurrency: "排队(等待当前完成)";
336
+ readonly conditionEvent: "条件";
337
+ readonly manualEvent: "手动";
338
+ readonly webhookEvent: "Webhook";
339
+ readonly timerEvent: "定时器";
340
+ readonly signalEvent: "信号";
341
+ readonly versionHistory: "版本历史";
342
+ readonly importBpmn: "导入 BPMN";
343
+ readonly exportBpmn: "导出 BPMN";
344
+ readonly undo: "撤销";
345
+ readonly redo: "重做";
346
+ readonly resetZoom: "重置缩放";
347
+ };
199
348
  readonly dashboard: {
200
349
  readonly addWidget: "添加组件";
201
350
  readonly removeWidget: "移除组件";
@@ -349,6 +498,58 @@ declare const zh: {
349
498
  readonly modeLight: "浅色";
350
499
  readonly modeDark: "深色";
351
500
  readonly mobilePreview: "移动端预览";
501
+ readonly objectManager: {
502
+ readonly title: "对象管理器";
503
+ readonly addObject: "新建对象";
504
+ readonly searchPlaceholder: "搜索对象…";
505
+ readonly noObjects: "未找到对象。";
506
+ readonly objectName: "API 名称";
507
+ readonly objectLabel: "标签";
508
+ readonly pluralLabel: "复数标签";
509
+ readonly icon: "图标";
510
+ readonly selectIcon: "选择图标…";
511
+ readonly group: "分组";
512
+ readonly noGroup: "无分组";
513
+ readonly sortOrder: "排序";
514
+ readonly enabled: "启用";
515
+ readonly relationships: "关系";
516
+ readonly systemBadge: "系统";
517
+ readonly fieldCount: "{{count}} 个字段";
518
+ readonly ungrouped: "未分组";
519
+ readonly deleteConfirmTitle: "删除对象?";
520
+ readonly deleteConfirmMessage: "这将永久删除该对象及其所有字段。此操作无法撤销。";
521
+ };
522
+ readonly fieldDesigner: {
523
+ readonly title: "字段设计器";
524
+ readonly addField: "新建字段";
525
+ readonly searchPlaceholder: "搜索字段…";
526
+ readonly allTypes: "所有类型";
527
+ readonly noFields: "未找到字段。";
528
+ readonly fieldName: "API 名称";
529
+ readonly fieldLabel: "标签";
530
+ readonly fieldType: "类型";
531
+ readonly fieldGroup: "分组";
532
+ readonly description: "描述";
533
+ readonly required: "必填";
534
+ readonly unique: "唯一";
535
+ readonly readOnly: "只读";
536
+ readonly hidden: "隐藏";
537
+ readonly indexed: "索引";
538
+ readonly externalId: "外部 ID";
539
+ readonly trackHistory: "追踪历史";
540
+ readonly defaultValue: "默认值";
541
+ readonly placeholder: "占位文本";
542
+ readonly referenceTo: "引用对象";
543
+ readonly formula: "公式";
544
+ readonly options: "选项";
545
+ readonly addOption: "添加选项";
546
+ readonly validationRules: "验证规则";
547
+ readonly addRule: "添加规则";
548
+ readonly systemBadge: "系统";
549
+ readonly ungrouped: "通用";
550
+ readonly deleteConfirmTitle: "删除字段?";
551
+ readonly deleteConfirmMessage: "这将永久删除该字段。此字段中的现有数据将丢失。";
552
+ };
352
553
  };
353
554
  readonly console: {
354
555
  readonly title: "ObjectStack 控制台";
@@ -434,7 +635,7 @@ declare const zh: {
434
635
  readonly generalHint: "视图标题、描述和类型";
435
636
  readonly toolbar: "工具栏";
436
637
  readonly toolbarHint: "搜索、筛选、排序、分组和密度切换";
437
- readonly toolbarEnabledCount: "{{count}} of {{total}} enabled";
638
+ readonly toolbarEnabledCount: "已启用 {{count}}/{{total}} 项";
438
639
  readonly navigationSection: "导航";
439
640
  readonly navigationHint: "行点击行为和详情视图设置";
440
641
  readonly records: "记录";
@@ -32,6 +32,8 @@ const zh = {
32
32
  noResults: '未找到结果',
33
33
  required: '必填',
34
34
  optional: '选填',
35
+ selectOption: '请选择',
36
+ select: '选择...',
35
37
  },
36
38
  validation: {
37
39
  required: '{{field}}不能为空',
@@ -54,6 +56,11 @@ const zh = {
54
56
  saveError: '保存失败',
55
57
  unsavedChanges: '您有未保存的更改,确定要离开吗?',
56
58
  stepOf: '第{{current}}步,共{{total}}步',
59
+ createTitle: '新建{{object}}',
60
+ editTitle: '编辑{{object}}',
61
+ createDescription: '向数据库添加新的{{object}}。',
62
+ editDescription: '更新{{object}}的详情',
63
+ saveRecord: '保存记录',
57
64
  },
58
65
  table: {
59
66
  rowsPerPage: '每页行数',
@@ -146,6 +153,22 @@ const zh = {
146
153
  deleteCard: '删除卡片',
147
154
  deleteColumn: '删除列',
148
155
  },
156
+ view: {
157
+ rename: '重命名',
158
+ duplicateView: '复制视图',
159
+ shareView: '共享视图',
160
+ setAsDefault: '设为默认',
161
+ pinView: '固定视图',
162
+ unpinView: '取消固定',
163
+ changeViewType: '更改视图类型',
164
+ deleteView: '删除视图',
165
+ addView: '添加视图',
166
+ unsavedChanges: '未保存的更改',
167
+ saveAsView: '另存为视图',
168
+ moreViews: '还有 {{count}} 个',
169
+ activeFilters: '筛选条件生效中',
170
+ activeSort: '排序生效中',
171
+ },
149
172
  detail: {
150
173
  back: '返回',
151
174
  edit: '编辑',
@@ -191,11 +214,147 @@ const zh = {
191
214
  sortBy: '排序',
192
215
  filterPlaceholder: '筛选...',
193
216
  highlightFields: '关键字段',
217
+ // Comments
218
+ comments: '评论',
219
+ searchComments: '搜索评论…',
220
+ addCommentPlaceholder: '添加评论… (Ctrl+Enter 提交)',
221
+ noMatchingComments: '没有匹配的评论',
222
+ noCommentsYet: '暂无评论',
223
+ pinned: '已置顶',
224
+ pin: '置顶',
225
+ unpin: '取消置顶',
226
+ justNow: '刚刚',
227
+ minutesAgo: '{{count}}分钟前',
228
+ hoursAgo: '{{count}}小时前',
229
+ daysAgo: '{{count}}天前',
230
+ // Attachments
231
+ dropFilesToUpload: '拖拽文件到此处或点击上传',
232
+ attachmentCount: '{{count}} 个附件',
233
+ attachmentCountPlural: '{{count}} 个附件',
234
+ removeAttachment: '移除附件',
235
+ // Diff
236
+ unifiedDiff: '统一视图',
237
+ sideBySideDiff: '并排视图',
238
+ noChanges: '无变更',
239
+ previousVersion: '旧版本',
240
+ currentVersion: '新版本',
241
+ // Discussion
242
+ discussion: '讨论',
243
+ showDiscussion: '显示讨论 ({{count}})',
244
+ hideDiscussion: '隐藏讨论',
245
+ // Rich text editor
246
+ bold: '粗体 (Ctrl+B)',
247
+ italic: '斜体 (Ctrl+I)',
248
+ listFormat: '列表',
249
+ inlineCode: '行内代码',
250
+ mentionSomeone: '提及某人',
251
+ preview: '预览',
252
+ submitComment: '提交 (Ctrl+Enter)',
253
+ writeComment: '写评论…',
254
+ // Subscription
255
+ subscribedTooltip: '已订阅 — 点击取消订阅',
256
+ unsubscribedTooltip: '订阅通知',
257
+ // Navigation
258
+ firstRecord: '第一条记录 (Home)',
259
+ previousRecordKey: '上一条记录 (←)',
260
+ nextRecordKey: '下一条记录 (→)',
261
+ lastRecord: '最后一条记录 (End)',
262
+ noRecords: '无记录',
263
+ searchWhileNavigating: '导航时搜索',
264
+ searchRecords: '搜索记录…',
265
+ // Activity timeline
266
+ allActivity: '全部动态',
267
+ commentsOnly: '仅评论',
268
+ fieldChangesFilter: '字段变更',
269
+ tasksOnly: '仅任务',
270
+ leaveCommentPlaceholder: '留下评论… (Ctrl+Enter 提交)',
271
+ noActivity: '暂无活动记录',
272
+ loadMore: '加载更多',
273
+ edited: '(已编辑)',
274
+ via: '通过 {{source}}',
275
+ // Replies
276
+ replyCount: '{{count}} 条回复',
277
+ replyCountPlural: '{{count}} 条回复',
278
+ replyPlaceholder: '回复…',
279
+ // 无障碍标签
280
+ filterActivity: '筛选活动',
281
+ openDiscussion: '打开讨论面板',
282
+ closeDiscussion: '关闭讨论面板',
283
+ subscribeAriaLabel: '订阅通知',
284
+ unsubscribeAriaLabel: '取消订阅通知',
285
+ clearSearch: '清除搜索',
194
286
  },
195
287
  chart: {
196
288
  noData: '暂无图表数据',
197
289
  loading: '图表加载中...',
198
290
  },
291
+ map: {
292
+ searchLocations: '搜索位置…',
293
+ locationDetails: '位置详情',
294
+ markersCount: '{{count}} 个标记',
295
+ invalidCoordinates: '{{count}} 条记录因坐标缺失或无效已从地图中排除。',
296
+ invalidCoordinatesPlural: '{{count}} 条记录因坐标缺失或无效已从地图中排除。',
297
+ },
298
+ workflow: {
299
+ draft: '草稿',
300
+ active: '活跃',
301
+ paused: '已暂停',
302
+ completed: '已完成',
303
+ cancelled: '已取消',
304
+ save: '保存',
305
+ publish: '发布',
306
+ addNode: '添加节点',
307
+ workflowFlow: '工作流程',
308
+ properties: '属性',
309
+ connections: '连接',
310
+ quickConnect: '快速连接',
311
+ fromPlaceholder: '从...',
312
+ toPlaceholder: '到...',
313
+ connect: '连接',
314
+ label: '标签',
315
+ type: '类型',
316
+ description: '描述',
317
+ assignee: '负责人',
318
+ assigneeType: '负责人类型',
319
+ user: '用户',
320
+ role: '角色',
321
+ group: '组',
322
+ expression: '表达式',
323
+ timeoutMinutes: '超时时间(分钟)',
324
+ selectNodeToEdit: '选择节点以编辑其属性',
325
+ workflowTitle: '工作流标题',
326
+ newWorkflow: '新工作流',
327
+ outConnections: '{{count}} 个输出',
328
+ start: '开始',
329
+ end: '结束',
330
+ task: '任务',
331
+ userTask: '用户任务',
332
+ serviceTask: '服务任务',
333
+ scriptTask: '脚本任务',
334
+ approval: '审批',
335
+ condition: '条件',
336
+ parallelGateway: '并行网关',
337
+ joinGateway: '合并网关',
338
+ boundaryEvent: '边界事件',
339
+ delay: '延迟',
340
+ notification: '通知',
341
+ webhook: 'Webhook',
342
+ allowConcurrency: '允许(并发执行)',
343
+ forbidConcurrency: '禁止(跳过新任务)',
344
+ replaceConcurrency: '替换(取消现有任务)',
345
+ queueConcurrency: '排队(等待当前完成)',
346
+ conditionEvent: '条件',
347
+ manualEvent: '手动',
348
+ webhookEvent: 'Webhook',
349
+ timerEvent: '定时器',
350
+ signalEvent: '信号',
351
+ versionHistory: '版本历史',
352
+ importBpmn: '导入 BPMN',
353
+ exportBpmn: '导出 BPMN',
354
+ undo: '撤销',
355
+ redo: '重做',
356
+ resetZoom: '重置缩放',
357
+ },
199
358
  dashboard: {
200
359
  addWidget: '添加组件',
201
360
  removeWidget: '移除组件',
@@ -349,6 +508,58 @@ const zh = {
349
508
  modeLight: '浅色',
350
509
  modeDark: '深色',
351
510
  mobilePreview: '移动端预览',
511
+ objectManager: {
512
+ title: '对象管理器',
513
+ addObject: '新建对象',
514
+ searchPlaceholder: '搜索对象…',
515
+ noObjects: '未找到对象。',
516
+ objectName: 'API 名称',
517
+ objectLabel: '标签',
518
+ pluralLabel: '复数标签',
519
+ icon: '图标',
520
+ selectIcon: '选择图标…',
521
+ group: '分组',
522
+ noGroup: '无分组',
523
+ sortOrder: '排序',
524
+ enabled: '启用',
525
+ relationships: '关系',
526
+ systemBadge: '系统',
527
+ fieldCount: '{{count}} 个字段',
528
+ ungrouped: '未分组',
529
+ deleteConfirmTitle: '删除对象?',
530
+ deleteConfirmMessage: '这将永久删除该对象及其所有字段。此操作无法撤销。',
531
+ },
532
+ fieldDesigner: {
533
+ title: '字段设计器',
534
+ addField: '新建字段',
535
+ searchPlaceholder: '搜索字段…',
536
+ allTypes: '所有类型',
537
+ noFields: '未找到字段。',
538
+ fieldName: 'API 名称',
539
+ fieldLabel: '标签',
540
+ fieldType: '类型',
541
+ fieldGroup: '分组',
542
+ description: '描述',
543
+ required: '必填',
544
+ unique: '唯一',
545
+ readOnly: '只读',
546
+ hidden: '隐藏',
547
+ indexed: '索引',
548
+ externalId: '外部 ID',
549
+ trackHistory: '追踪历史',
550
+ defaultValue: '默认值',
551
+ placeholder: '占位文本',
552
+ referenceTo: '引用对象',
553
+ formula: '公式',
554
+ options: '选项',
555
+ addOption: '添加选项',
556
+ validationRules: '验证规则',
557
+ addRule: '添加规则',
558
+ systemBadge: '系统',
559
+ ungrouped: '通用',
560
+ deleteConfirmTitle: '删除字段?',
561
+ deleteConfirmMessage: '这将永久删除该字段。此字段中的现有数据将丢失。',
562
+ },
352
563
  },
353
564
  console: {
354
565
  title: 'ObjectStack 控制台',
@@ -434,7 +645,7 @@ const zh = {
434
645
  generalHint: '视图标题、描述和类型',
435
646
  toolbar: '工具栏',
436
647
  toolbarHint: '搜索、筛选、排序、分组和密度切换',
437
- toolbarEnabledCount: '{{count}} of {{total}} enabled',
648
+ toolbarEnabledCount: '已启用 {{count}}/{{total}} 项',
438
649
  navigationSection: '导航',
439
650
  navigationHint: '行点击行为和详情视图设置',
440
651
  records: '记录',
@@ -0,0 +1,5 @@
1
+ export declare function createSafeTranslation(defaults: Record<string, string>, testKey: string): () => {
2
+ t: (key: string, options?: Record<string, unknown>) => string;
3
+ } | {
4
+ t: import("i18next").TFunction<string, undefined>;
5
+ };
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Safe translation hook with fallback to default strings.
3
+ *
4
+ * When no I18nProvider is available (e.g., in tests or standalone usage),
5
+ * this hook falls back to the provided default translations instead of
6
+ * returning raw i18n keys.
7
+ *
8
+ * @param defaults - Fallback English translations keyed by i18n key
9
+ * @param testKey - A key to test if i18n is properly configured (must be in defaults)
10
+ */
11
+ import { useObjectTranslation } from './provider';
12
+ export function createSafeTranslation(defaults, testKey) {
13
+ return function useSafeTranslation() {
14
+ try {
15
+ const result = useObjectTranslation();
16
+ const testValue = result.t(testKey);
17
+ if (testValue === testKey) {
18
+ return {
19
+ t: (key, options) => {
20
+ let value = defaults[key] || key;
21
+ if (options) {
22
+ for (const [k, v] of Object.entries(options)) {
23
+ value = value.replace(`{{${k}}}`, String(v));
24
+ }
25
+ }
26
+ return value;
27
+ },
28
+ };
29
+ }
30
+ return { t: result.t };
31
+ }
32
+ catch {
33
+ return {
34
+ t: (key, options) => {
35
+ let value = defaults[key] || key;
36
+ if (options) {
37
+ for (const [k, v] of Object.entries(options)) {
38
+ value = value.replace(`{{${k}}}`, String(v));
39
+ }
40
+ }
41
+ return value;
42
+ },
43
+ };
44
+ }
45
+ };
46
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@object-ui/i18n",
3
- "version": "3.1.4",
3
+ "version": "3.3.0",
4
4
  "type": "module",
5
5
  "sideEffects": false,
6
6
  "license": "MIT",
@@ -30,17 +30,17 @@
30
30
  }
31
31
  },
32
32
  "dependencies": {
33
- "i18next": "^25.10.4",
34
- "react-i18next": "^16.6.2"
33
+ "i18next": "^26.0.4",
34
+ "react-i18next": "^17.0.2"
35
35
  },
36
36
  "peerDependencies": {
37
37
  "react": "^18.0.0 || ^19.0.0"
38
38
  },
39
39
  "devDependencies": {
40
40
  "@types/react": "19.2.14",
41
- "react": "19.2.4",
42
- "typescript": "^5.9.3",
43
- "vitest": "^4.1.0"
41
+ "react": "19.2.5",
42
+ "typescript": "^6.0.2",
43
+ "vitest": "^4.1.4"
44
44
  },
45
45
  "scripts": {
46
46
  "build": "tsc",
@@ -47,6 +47,17 @@ describe('@object-ui/i18n', () => {
47
47
  expect(i18n.t('common.cancel')).toBe('Cancel');
48
48
  expect(i18n.t('common.delete')).toBe('Delete');
49
49
  expect(i18n.t('common.loading')).toBe('Loading...');
50
+ expect(i18n.t('common.selectOption')).toBe('Select an option');
51
+ expect(i18n.t('common.select')).toBe('Select...');
52
+ });
53
+
54
+ it('translates new form keys in English', () => {
55
+ const i18n = createI18n({ defaultLanguage: 'en', detectBrowserLanguage: false });
56
+ expect(i18n.t('form.createTitle', { object: 'Contact' })).toBe('Create Contact');
57
+ expect(i18n.t('form.editTitle', { object: 'Contact' })).toBe('Edit Contact');
58
+ expect(i18n.t('form.createDescription', { object: 'Contact' })).toBe('Add a new Contact to your database.');
59
+ expect(i18n.t('form.editDescription', { object: 'Contact' })).toBe('Update details for Contact');
60
+ expect(i18n.t('form.saveRecord')).toBe('Save Record');
50
61
  });
51
62
 
52
63
  it('translates common keys in Chinese', () => {
@@ -55,6 +66,22 @@ describe('@object-ui/i18n', () => {
55
66
  expect(i18n.t('common.cancel')).toBe('取消');
56
67
  expect(i18n.t('common.delete')).toBe('删除');
57
68
  expect(i18n.t('common.loading')).toBe('加载中...');
69
+ expect(i18n.t('common.selectOption')).toBe('请选择');
70
+ expect(i18n.t('common.select')).toBe('选择...');
71
+ });
72
+
73
+ it('translates new form keys in Chinese', () => {
74
+ const i18n = createI18n({ defaultLanguage: 'zh', detectBrowserLanguage: false });
75
+ expect(i18n.t('form.createTitle', { object: '联系人' })).toBe('新建联系人');
76
+ expect(i18n.t('form.editTitle', { object: '联系人' })).toBe('编辑联系人');
77
+ expect(i18n.t('form.createDescription', { object: '联系人' })).toBe('向数据库添加新的联系人。');
78
+ expect(i18n.t('form.editDescription', { object: '联系人' })).toBe('更新联系人的详情');
79
+ expect(i18n.t('form.saveRecord')).toBe('保存记录');
80
+ });
81
+
82
+ it('translates toolbarEnabledCount in Chinese (not English fallback)', () => {
83
+ const i18n = createI18n({ defaultLanguage: 'zh', detectBrowserLanguage: false });
84
+ expect(i18n.t('console.objectView.toolbarEnabledCount', { count: 3, total: 5 })).toBe('已启用 3/5 项');
58
85
  });
59
86
 
60
87
  it('translates common keys in Japanese', () => {
package/src/index.ts CHANGED
@@ -37,6 +37,9 @@ export { createI18n, getDirection, getAvailableLanguages, type I18nConfig, type
37
37
  // React integration
38
38
  export { I18nProvider, useObjectTranslation, useI18nContext, type I18nProviderProps } from './provider';
39
39
 
40
+ // Safe translation hook factory
41
+ export { createSafeTranslation } from './useSafeTranslation';
42
+
40
43
  // Convention-based object/field label i18n
41
44
  export { useObjectLabel, useSafeFieldLabel } from './useObjectLabel';
42
45