@lincyaw/workbench 0.0.0-stage → 0.2.0-rc.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.
- package/LICENSE +202 -0
- package/README.md +66 -2
- package/package.json +68 -3
- package/src/MediaClipEditor.tsx +122 -0
- package/src/StepProductionEditor.tsx +130 -0
- package/src/approvals.tsx +60 -0
- package/src/assistant-mascot.ts +62 -0
- package/src/audio-recording-messages.ts +44 -0
- package/src/audio-recording.ts +192 -0
- package/src/audio-wav.ts +25 -0
- package/src/audio-waveform.ts +110 -0
- package/src/audition.ts +84 -0
- package/src/authoring-client.ts +136 -0
- package/src/authoring-draft-fragment.ts +28 -0
- package/src/base-controls.tsx +47 -0
- package/src/caption-timing-drafts.ts +61 -0
- package/src/caption-timing-messages.ts +14 -0
- package/src/caption-timing.css +20 -0
- package/src/caption-timing.ts +14 -0
- package/src/component-draft-actions.ts +54 -0
- package/src/component-draft-inspection.ts +35 -0
- package/src/component-properties.css +24 -0
- package/src/component-properties.ts +45 -0
- package/src/component-property-drafts.ts +273 -0
- package/src/component-property-messages.ts +31 -0
- package/src/components.tsx +631 -0
- package/src/context.tsx +27 -0
- package/src/diagnostics.ts +113 -0
- package/src/document-draft-store.ts +179 -0
- package/src/document-drafts.ts +178 -0
- package/src/document-editor/BlockNoteSurface.tsx +209 -0
- package/src/document-editor/ComponentMaterials.tsx +62 -0
- package/src/document-editor/ComponentPropertiesDialog.tsx +282 -0
- package/src/document-editor/DocumentBlockFallback.tsx +31 -0
- package/src/document-editor/DocumentBlockPreview.tsx +239 -0
- package/src/document-editor/DocumentComments.tsx +282 -0
- package/src/document-editor/DocumentEditor.tsx +192 -0
- package/src/document-editor/DocumentStepNarration.tsx +93 -0
- package/src/document-editor/NarrationEditor.tsx +110 -0
- package/src/document-editor/NewCommentDrafts.tsx +224 -0
- package/src/document-editor/authoring.tsx +259 -0
- package/src/document-editor/block-playback.ts +90 -0
- package/src/document-editor/block-preview-messages.ts +13 -0
- package/src/document-editor/blocknote-messages.ts +98 -0
- package/src/document-editor/clipboard.ts +40 -0
- package/src/document-editor/colors.ts +57 -0
- package/src/document-editor/comment-draft-actions.ts +58 -0
- package/src/document-editor/comment-draft-inspection.ts +38 -0
- package/src/document-editor/comment-drafts.ts +361 -0
- package/src/document-editor/comments.ts +410 -0
- package/src/document-editor/file-input.ts +71 -0
- package/src/document-editor/focus.ts +54 -0
- package/src/document-editor/inline.ts +104 -0
- package/src/document-editor/math.tsx +63 -0
- package/src/document-editor/messages.ts +14 -0
- package/src/document-editor/narration-schema.tsx +85 -0
- package/src/document-editor/narration.ts +37 -0
- package/src/document-editor/popover.tsx +107 -0
- package/src/document-editor/projection.ts +423 -0
- package/src/document-editor/rich-text.ts +152 -0
- package/src/document-editor/schema.tsx +117 -0
- package/src/document-editor/selection.ts +152 -0
- package/src/document-editor/style.css +9 -0
- package/src/document-editor/styles.d.ts +1 -0
- package/src/document-editor/table-identities.ts +67 -0
- package/src/document-preview.ts +112 -0
- package/src/document-return-point.ts +59 -0
- package/src/document-session.ts +678 -0
- package/src/document-timing-drafts.ts +61 -0
- package/src/document-voices.ts +2 -0
- package/src/history.ts +167 -0
- package/src/index.ts +36 -0
- package/src/jobs.ts +111 -0
- package/src/mascot-preference.ts +37 -0
- package/src/media-drafts.ts +83 -0
- package/src/media-messages.ts +53 -0
- package/src/media-time.ts +12 -0
- package/src/messages.ts +781 -0
- package/src/outline.ts +97 -0
- package/src/panels/ChangeTrail.tsx +79 -0
- package/src/panels/DocumentNarrationPanel.tsx +27 -0
- package/src/panels/DocumentView.tsx +462 -0
- package/src/panels/DocumentVoiceDialog.tsx +179 -0
- package/src/panels/DocumentVoiceField.tsx +35 -0
- package/src/panels/ExportPanel.tsx +133 -0
- package/src/panels/HistoryPanel.tsx +88 -0
- package/src/panels/HomePanel.tsx +184 -0
- package/src/panels/PageDeleteDialog.tsx +33 -0
- package/src/panels/PageRenameDialog.tsx +27 -0
- package/src/panels/PreviewPanel.tsx +79 -0
- package/src/panels/ProductionCaptionTiming.tsx +122 -0
- package/src/panels/ProductionMediaClips.tsx +156 -0
- package/src/panels/ProductionPanel.tsx +272 -0
- package/src/panels/ProductionRecording.tsx +107 -0
- package/src/panels/ProductionRecordingRange.tsx +118 -0
- package/src/panels/ProductionTimeline.tsx +62 -0
- package/src/panels/ProductionTranscription.tsx +140 -0
- package/src/panels/SourceDocumentPanel.tsx +215 -0
- package/src/panels/SpeechSettingsPanel.tsx +64 -0
- package/src/panels/TranscriptionAdoption.tsx +147 -0
- package/src/panels/VoiceCloneDialog.tsx +152 -0
- package/src/panels/VoicePreviewDialog.tsx +74 -0
- package/src/panels/VoiceScopeField.tsx +30 -0
- package/src/panels/VoiceoverDialog.tsx +216 -0
- package/src/places.ts +102 -0
- package/src/preview-playback.ts +125 -0
- package/src/preview-pool.ts +320 -0
- package/src/preview.ts +110 -0
- package/src/production-messages.ts +151 -0
- package/src/production-playback.ts +109 -0
- package/src/production-voice-playback.ts +114 -0
- package/src/recording-adoption.ts +33 -0
- package/src/schema-form/PmSchemaForm.tsx +187 -0
- package/src/schema-form/context.ts +26 -0
- package/src/schema-form/fields.tsx +59 -0
- package/src/schema-form/templates.tsx +50 -0
- package/src/schema-form/validator.ts +36 -0
- package/src/schema-form/widgets.tsx +60 -0
- package/src/shortcuts.ts +8 -0
- package/src/sortable-list.tsx +201 -0
- package/src/speech-settings-messages.ts +40 -0
- package/src/step-production.css +5 -0
- package/src/step-production.ts +51 -0
- package/src/styles.css +1025 -0
- package/src/telemetry.ts +152 -0
- package/src/transcription-messages.ts +26 -0
- package/src/transcription-session.ts +159 -0
- package/src/use-recording-adoption.ts +84 -0
- package/src/voice-clone-messages.ts +92 -0
- package/src/voice-drafts.ts +89 -0
- package/src/voice-messages.ts +146 -0
- package/src/voice-snapshot.ts +55 -0
- package/src/voiceover-jobs.ts +87 -0
- package/src/workbench.ts +2328 -0
- package/src/workspace-client.ts +480 -0
package/src/messages.ts
ADDED
|
@@ -0,0 +1,781 @@
|
|
|
1
|
+
import { localeOf } from '@lincyaw/kernel'
|
|
2
|
+
import { SHORTCUTS } from './shortcuts.ts'
|
|
3
|
+
|
|
4
|
+
export type Locale = 'zh-CN' | 'en'
|
|
5
|
+
export { localeOf }
|
|
6
|
+
|
|
7
|
+
/** A place of the document as the author's message to the AI names it: the section's title and the passage, as readers see them. */
|
|
8
|
+
export interface AgentPlace {
|
|
9
|
+
section?: string
|
|
10
|
+
quote?: string
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
// A Latin word or a number set after Chinese text is spaced from it (docs/glossary.md 2).
|
|
14
|
+
const spaced = (text: string) => (/^[A-Za-z0-9]/.test(text) ? ` ${text}` : text)
|
|
15
|
+
|
|
16
|
+
// Names of commands follow Microsoft Word's (撤消/Undo, 新建批注/New Comment, 版本历史/Version History…).
|
|
17
|
+
const zh = {
|
|
18
|
+
voiceSaveUnconfirmed: '音色设置尚未确认保存,草稿已保留,请重试。',
|
|
19
|
+
documentEditor: '文稿编辑',
|
|
20
|
+
documentPositionRemoved: '上次位置已移除,请重新定位。',
|
|
21
|
+
documentExport: '导出文稿',
|
|
22
|
+
documentNarration: '字幕',
|
|
23
|
+
documentNarrationHint: '编辑字幕和配音的开始时机',
|
|
24
|
+
historyPendingSave: '尚未确认撤消或恢复的结果。草稿已保留,请查看保存提示后重试。',
|
|
25
|
+
presentationPreview: '放映',
|
|
26
|
+
pageTitle: '页面标题',
|
|
27
|
+
pageMore: (title: string) => `“${title}”的更多操作`,
|
|
28
|
+
pageRenameTitle: '重命名页面',
|
|
29
|
+
pageCopy: '复制页面',
|
|
30
|
+
movePageUp: '上移页面',
|
|
31
|
+
movePageDown: '下移页面',
|
|
32
|
+
previewPreparing: '正在准备预览,首次打开可能需要一些时间…',
|
|
33
|
+
previewStalled: '无法连接预览。请重新加载,诊断已保留。',
|
|
34
|
+
contentWorkspace: '内容',
|
|
35
|
+
sequenceWorkspace: '编排',
|
|
36
|
+
workspaceLabel: '编辑区域',
|
|
37
|
+
stepTimeline: '页面步骤',
|
|
38
|
+
previousStep: '上一步',
|
|
39
|
+
nextStep: '下一步',
|
|
40
|
+
exitPresentation: '结束放映',
|
|
41
|
+
presentationReturnFailed: '暂时无法确认放映位置。当前位置与草稿已保留,请再次结束放映。',
|
|
42
|
+
presentationPending: '请先保存正文,并等待放映准备完成。',
|
|
43
|
+
presentationPreparing: '正在准备放映…',
|
|
44
|
+
presentationCompileFailed: '无法用当前保存的版本准备放映。正文与草稿已保留,请查看诊断后重试。',
|
|
45
|
+
presentationSourceChanged: '准备放映期间文稿已更新。请等待当前输入保存后,再放映或更新。',
|
|
46
|
+
presentationCompiled: '当前保存版本',
|
|
47
|
+
presentationOutdated: '需要更新',
|
|
48
|
+
presentationRecompile: '更新',
|
|
49
|
+
timingDraftPending: '有尚未采用的播放时机,请先修改或使用继承值。',
|
|
50
|
+
stepLabel: (step: number, total: number) => `步骤 ${step} / ${total}`,
|
|
51
|
+
pages: '页面',
|
|
52
|
+
newPage: '新建页面',
|
|
53
|
+
untitledPage: '未命名页面',
|
|
54
|
+
pageEditFiles: '此文稿的页面分散在多处,暂不支持直接重命名或移动。原内容已保留。',
|
|
55
|
+
pageEditBoundary: '暂时无法确认此页的完整边界。请重新加载文稿后重试。',
|
|
56
|
+
pageEditHierarchy: '只能移动相邻的同级页面;封面和章节边界保持原位。',
|
|
57
|
+
pageEditImplicitTitle: '此页使用文稿标题,尚不支持单独重命名。',
|
|
58
|
+
pageEditFormattedTitle: '此标题包含复杂格式,暂不支持在这里重命名。原格式已保留。',
|
|
59
|
+
pageEditInvalidTitle: '请输入不含换行的页面标题。',
|
|
60
|
+
pageEditBusy: '页面修改尚未完成,请稍候。',
|
|
61
|
+
pageEditPreview: '请等待预览就绪后再修改页面。',
|
|
62
|
+
pageEditChanged: '文稿或预览已切换,本次页面修改已停止。',
|
|
63
|
+
pageEditFlushTimeout: '等待正文或讲稿保存超时。草稿已保留,请重试。',
|
|
64
|
+
pageEditDraft: '正文或讲稿仍有未解决的保存问题。请先处理对应草稿。',
|
|
65
|
+
pageEditSourceDraft: '还有未采用的素材草稿。请先保存或放弃该草稿,再修改页面。',
|
|
66
|
+
pageEditRefresh: '页面修改已保存,但预览尚未确认更新。请重新加载文稿。',
|
|
67
|
+
pageEditCompiler: '当前工作区服务尚不支持中文页面标题的链接。请重新启动 Presmium 后重试,页面内容尚未修改。',
|
|
68
|
+
pageEditRequestFailed: '无法完成页面修改。草稿已保留,请重试。',
|
|
69
|
+
pageRenamed: (title: string) => `重命名页面为“${title}”`,
|
|
70
|
+
pageMoved: (title: string) => `移动页面“${title}”`,
|
|
71
|
+
pageDelete: '删除页面',
|
|
72
|
+
pageDeleteTitle: (title: string) => `删除“${title}”?`,
|
|
73
|
+
pageDeleteLoading: '正在检查页面范围与内容引用…',
|
|
74
|
+
pageDeleteHint: (steps: number, narration: number) => `此页包含 ${steps} 个步骤、${narration} 段讲稿。删除后可以在版本历史中撤消,共享的素材会保留。`,
|
|
75
|
+
pageDeleteLast: '这是最后一页。将清空页内内容,并保留一个空白页。',
|
|
76
|
+
pageDeleteReferenced: '其他内容仍引用此页面或页内目标。请先移除对应引用,再删除页面。',
|
|
77
|
+
pageDeleteExternalBindings: '此页的讲稿单独保存,暂不能与页面一起安全删除。页面内容已保留。',
|
|
78
|
+
pageDeleteReferencesUnavailable: '相关文稿仍在更新,暂时无法确认全部引用。页面已保留,请稍后重试。',
|
|
79
|
+
pageTimeout: '新建页面未收到确认。请检查文稿后重试。',
|
|
80
|
+
pageBoundary: '无法确定此页面的范围,暂时不能在这里新建页面。',
|
|
81
|
+
blockUnknown: '未找到对应的页面。',
|
|
82
|
+
blockConflict: '文稿已更新,当前草稿已保留。请重新加载后继续编辑。',
|
|
83
|
+
blockFiles: '此页面的内容分散在多处,暂不支持在这里调整内容块。',
|
|
84
|
+
blockStepOrder: '此页面使用逐项显示,暂不支持在这里调整内容块的顺序。正文草稿已保留。',
|
|
85
|
+
blockSourceBinding: '原有内容的关联已失效,暂时无法安全还原此内容块。正文草稿已保留,可在版本历史中还原原内容。',
|
|
86
|
+
nativeEditTarget: '原文字的位置已改变,暂时无法安全保存。修改已保留,请查看当前文稿后重试或复制修改。',
|
|
87
|
+
nativeEditConflict: '这处原文或版本已改变,草稿已保留。请先核对当前原文,再复制或明确放弃待确认的改字。',
|
|
88
|
+
nativeEditDraft: '标题或特殊文字还有待处理的草稿,修改已保留。请先保存或明确放弃对应草稿。',
|
|
89
|
+
nativeEditUnavailable: '当前服务还不能核对这段文字的版本。修改已保留,请重新启动 Presmium 后重试。',
|
|
90
|
+
nativeEditFormat: '这次修改跨过了格式或特殊标记,无法安全写回。修改已保留,可缩小修改范围后重试或复制修改。',
|
|
91
|
+
nativeEditConfirmation: '文字可能已写入,但还未确认对应版本。修改已保留,请查看当前文稿后重试。',
|
|
92
|
+
blockContainer: '此内容块包含嵌套的讲稿或范围设置,暂不支持调整结构。原文已保留。',
|
|
93
|
+
editedBody: (title: string) => `编辑“${title}”的正文`,
|
|
94
|
+
sourceUnknown: '未找到此内容块。请重新加载后重试。',
|
|
95
|
+
sourceChanged: '此内容块已在别处修改。草稿已保留,请重新加载。',
|
|
96
|
+
sourceIgnored: '相关文件不在版本历史的记录范围内,无法与文稿一起保存。请让管理员调整后重试。',
|
|
97
|
+
sourceLarge: '此内容块超过编辑器支持的大小。',
|
|
98
|
+
sourceAnimationUnavailable: '此文稿尚未启用动画内容块。',
|
|
99
|
+
sourceRefresh: '内容已保存,但预览尚未更新。请重新加载文稿后继续。',
|
|
100
|
+
createdAnimation: '插入动画',
|
|
101
|
+
editedSource: (title: string) => `编辑“${title}”中的内容块`,
|
|
102
|
+
narration: '讲稿',
|
|
103
|
+
narrationFormatted: '讲稿包含格式或动作提示,无法整体替换。请分段编辑,草稿已保留。',
|
|
104
|
+
narrationText: '当前步骤讲稿',
|
|
105
|
+
narrationPlaceholder: '输入本步骤的讲稿,用于配音和字幕。',
|
|
106
|
+
narrationAutosave: '自动保存;切换步骤会保留未完成的草稿。',
|
|
107
|
+
narrationDiscard: '放弃草稿',
|
|
108
|
+
narrationRecoveryUnavailable: '浏览器无法在本机保留草稿。草稿仍在本次会话中,请保存后再关闭窗口。',
|
|
109
|
+
documentDraftFound: '发现本地草稿',
|
|
110
|
+
documentDraftSelect: '恢复草稿',
|
|
111
|
+
documentDraftChoose: '请选择草稿',
|
|
112
|
+
documentDraftRestore: '恢复草稿',
|
|
113
|
+
documentDraftChanged: '本地草稿已更新,请重新选择。',
|
|
114
|
+
documentDraftUnreadable: '部分本地草稿无法读取。',
|
|
115
|
+
documentDraftBackingUp: '正在备份…',
|
|
116
|
+
documentDraftOption: (index: number, date: string, source: 'durable' | 'rescue') => `${date} · ${source === 'rescue' ? '临时副本' : '草稿'} ${index}`,
|
|
117
|
+
narrationCompositionInterrupted: '输入法组字未完成,草稿已保留。请检查文字后保存或继续编辑。',
|
|
118
|
+
narrationRefresh: '讲稿已写入,但画面尚未完成更新。草稿已保留,请等待预览恢复后重试。',
|
|
119
|
+
narrationDuring: '与动画同步',
|
|
120
|
+
narrationAfter: '动画结束后',
|
|
121
|
+
narrationMode: '配音时机',
|
|
122
|
+
narrationChanged: '文稿已更新。请保留当前草稿,重新加载本步骤后保存。',
|
|
123
|
+
narrationPending: '有未保存的修改,请先保存或取消。',
|
|
124
|
+
narrationScript: '当前页面的讲稿单独保存,暂不支持在这里编辑。',
|
|
125
|
+
narrationFiles: '本步骤的讲稿分散在多处或涉及不同的内容范围,请在文稿中分别编辑。',
|
|
126
|
+
narrationLoading: '正在加载讲稿…',
|
|
127
|
+
narrationTimeline: '播放时序',
|
|
128
|
+
narrationAnimation: '动画',
|
|
129
|
+
narrationSpeech: '配音',
|
|
130
|
+
narrationStep: (page: number, step: number) => `第 ${page} 页 · 第 ${step} 步`,
|
|
131
|
+
editedNarration: (step: number) => `修改第 ${step} 步的讲稿`,
|
|
132
|
+
documents: '文稿',
|
|
133
|
+
workspace: '工作区',
|
|
134
|
+
allDocuments: '全部文稿',
|
|
135
|
+
search: '搜索文稿',
|
|
136
|
+
noMatch: '没有找到匹配的文稿。',
|
|
137
|
+
newDocument: '新建文稿',
|
|
138
|
+
noDocuments: '还没有文稿。点“新建文稿”开始。',
|
|
139
|
+
notGit: '这个文件夹还没有开启版本历史,新建、重命名、创建副本、删除和撤消都需要它。请让管理员为这个文件夹开启版本历史。',
|
|
140
|
+
bundleDisabled: '无法加载文稿:Presmium 的扩展在“插件”页中被关闭了。请从“更多”打开“插件”,重新开启 Presmium,然后重新加载页面。',
|
|
141
|
+
more: (title: string) => `“${title}”的更多操作`,
|
|
142
|
+
open: '打开',
|
|
143
|
+
rename: '重命名',
|
|
144
|
+
makeCopy: '创建副本',
|
|
145
|
+
remove: '删除',
|
|
146
|
+
title: '标题',
|
|
147
|
+
titlePlaceholder: '例如:第三讲 注意力机制',
|
|
148
|
+
template: '模板',
|
|
149
|
+
create: '新建',
|
|
150
|
+
save: '保存',
|
|
151
|
+
confirmRemove: (title: string) => `确定删除“${title}”吗?`,
|
|
152
|
+
removeImpact: (files: number) => `将删除 ${files} 个文件或链接。`,
|
|
153
|
+
projectInspecting: '正在检查…',
|
|
154
|
+
cancel: '取消',
|
|
155
|
+
close: '关闭',
|
|
156
|
+
created: (title: string) => `已创建“${title}”`,
|
|
157
|
+
renamed: (title: string) => `已重命名为“${title}”`,
|
|
158
|
+
copied: (title: string) => `已创建副本“${title}”`,
|
|
159
|
+
removed: (title: string) => `已删除“${title}”`,
|
|
160
|
+
back: '返回文稿列表',
|
|
161
|
+
undo: '撤消',
|
|
162
|
+
redo: '恢复',
|
|
163
|
+
undoWhat: (what: string) => `撤消:${what}(${SHORTCUTS.undo})`,
|
|
164
|
+
redoWhat: (what: string) => `恢复:${what}(${SHORTCUTS.redo})`,
|
|
165
|
+
nothingToUndo: '没有可撤消的操作',
|
|
166
|
+
nothingToRedo: '没有可恢复的操作',
|
|
167
|
+
saving: '正在保存…',
|
|
168
|
+
saved: '已保存',
|
|
169
|
+
unsaved: '未保存',
|
|
170
|
+
savedAt: (time: string) => `已保存 · ${time}`,
|
|
171
|
+
saveLocked: 'AI 正在修改,请稍后再编辑这里。',
|
|
172
|
+
saveFailed: (reason: string) => `无法保存文稿。${reason}`,
|
|
173
|
+
failureReasons: {
|
|
174
|
+
'document-version-changed': '文稿已在别处修改。输入已保留,请重新加载后再保存。',
|
|
175
|
+
'document-readback-changed': '文稿已在别处修改。输入已保留,请重新加载后再保存。',
|
|
176
|
+
'document-identity-changed': '这份文稿已被替换。请重新打开它。',
|
|
177
|
+
'document-invalid': '修改后的文稿无法通过检查。输入已保留,请撤消最近的修改后重试。',
|
|
178
|
+
'document-files-ignored': '版本历史忽略了这份文稿的文件,无法保存。请让管理员检查工作区设置。',
|
|
179
|
+
'document-change-id-reused': '这次修改已经保存过。请重新加载后核对。',
|
|
180
|
+
'document-disconnected': '无法连接工作区服务。输入已保留,请检查网络后重试。',
|
|
181
|
+
'document-request-failed': '工作区服务没有完成请求。输入已保留,请重试。',
|
|
182
|
+
'page-context-changed': '页面已经变化。请重新选择后重试。',
|
|
183
|
+
'authoring-review-required': '这项修改需要先在“待确认”中允许。',
|
|
184
|
+
'authoring-permission-denied': '没有修改这份文稿的权限。',
|
|
185
|
+
'preview-timeout': '准备预览超时。正文和草稿已保留,请重试。',
|
|
186
|
+
'no-conversation': '对话尚未准备好,请稍后重试。',
|
|
187
|
+
network: '无法连接工作区服务。请检查网络后重试。',
|
|
188
|
+
} as Record<string, string>,
|
|
189
|
+
failureGeneric: '请重试;如果仍然失败,请重新加载页面。',
|
|
190
|
+
|
|
191
|
+
editingMode: '编辑',
|
|
192
|
+
viewingMode: '查看',
|
|
193
|
+
modeLabel: '模式',
|
|
194
|
+
editingHint: '单击内容即可编辑、批注或发送给 AI',
|
|
195
|
+
viewingHint: '像读者一样阅读,链接和互动内容都可以使用',
|
|
196
|
+
view: '视图',
|
|
197
|
+
renderers: { web: '网页', slides: '幻灯片' },
|
|
198
|
+
present: '放映',
|
|
199
|
+
readDocument: '阅读与运行',
|
|
200
|
+
editDocument: '返回编辑',
|
|
201
|
+
readingFailed: '无法准备文稿阅读视图。请确认文稿已保存,并查看诊断后重试。',
|
|
202
|
+
video: '视频',
|
|
203
|
+
videoHint: '讲授视频的效果:幻灯片、配音、字幕与动画按时间播放,修改内容后随即更新',
|
|
204
|
+
videoFile: '视频文件',
|
|
205
|
+
noVideoFile: '尚未导出',
|
|
206
|
+
makeVideoFile: '导出视频',
|
|
207
|
+
remakeVideoFile: '重新导出',
|
|
208
|
+
playVideoFile: '播放',
|
|
209
|
+
presentHint: '逐步放映幻灯片;设置了讲授时可播放配音、字幕与动画。视频文件在“导出”中导出。',
|
|
210
|
+
slidesHint: '幻灯片的版式,与放映时相同',
|
|
211
|
+
commands: '命令',
|
|
212
|
+
moreCommands: '更多',
|
|
213
|
+
navigation: '导航',
|
|
214
|
+
navigationPane: '导航窗格',
|
|
215
|
+
closeNavigation: '关闭导航窗格',
|
|
216
|
+
headings: '标题',
|
|
217
|
+
noSections: '这份文稿还没有页面。',
|
|
218
|
+
loadingPages: '正在加载页面…',
|
|
219
|
+
statusBar: '状态栏',
|
|
220
|
+
pageOf: (n: number, total: number) => `第 ${n} 页,共 ${total} 页`,
|
|
221
|
+
slideOf: (n: number, total: number) => `幻灯片 ${n} / ${total}`,
|
|
222
|
+
words: (n: number) => `${n.toLocaleString('zh-CN')} 字`,
|
|
223
|
+
comments: '批注',
|
|
224
|
+
newComment: '新建批注',
|
|
225
|
+
commentPlaceholder: '输入批注…',
|
|
226
|
+
postComment: '发布',
|
|
227
|
+
noComments: '还没有批注。选中文字或单击一段内容,点“新建批注”写下要改的地方;写完几条后一起发送给 AI。',
|
|
228
|
+
askAboutComment: '发送给 AI',
|
|
229
|
+
askAboutAll: '全部发送给 AI',
|
|
230
|
+
sendComments: (n: number) => `发送 ${n} 条批注给 AI`,
|
|
231
|
+
pendingComments: (n: number) => `${n} 条批注等待发送。写完后一起发送给 AI,AI 的修改会成为一个版本。`,
|
|
232
|
+
resolve: '解决',
|
|
233
|
+
reopen: '重新打开',
|
|
234
|
+
deleteComment: '删除批注',
|
|
235
|
+
sentToAi: '已发送给 AI',
|
|
236
|
+
resolved: '已解决',
|
|
237
|
+
showResolved: '显示已解决的批注',
|
|
238
|
+
inSection: (title: string) => `位于“${title}”`,
|
|
239
|
+
pointerTools: '对所选内容的操作',
|
|
240
|
+
askFailed: (reason: string) => `无法发送给 AI。${reason}`,
|
|
241
|
+
formattedEdit: '这一处带有格式或特殊内容,不能直接修改文字。要用 AI 改写吗?',
|
|
242
|
+
rewriteEdit: '用 AI 改写',
|
|
243
|
+
versionHistory: '版本历史',
|
|
244
|
+
historyNewer: '较新版本',
|
|
245
|
+
historyOlder: '更早版本',
|
|
246
|
+
exportPane: '导出',
|
|
247
|
+
makeLabel: '导出',
|
|
248
|
+
outputLabels: { web: '网站', slides: '幻灯片网站', notebook: 'Notebook', lecture: '讲授' } as Record<string, string>,
|
|
249
|
+
makeOutput: (label: string) => `导出${spaced(label)}`,
|
|
250
|
+
outputsList: '导出记录',
|
|
251
|
+
noOutputs: '还没有导出过文件。',
|
|
252
|
+
jobStates: { queued: '排队中', running: '正在导出', done: '已完成', failed: '导出失败', cancelled: '已取消' },
|
|
253
|
+
jobPhases: { prepare: '正在准备', export: '正在导出', build: '正在导出', frames: '正在录制画面' } as Record<string, string>,
|
|
254
|
+
jobProgress: (phase: string, done?: number, total?: number) => (total ? `${phase} ${done ?? 0} / ${total}` : `${phase}…`),
|
|
255
|
+
currentContent: '文稿保存版本相同',
|
|
256
|
+
outputVersionUnknown: '未记录保存版本',
|
|
257
|
+
outputConfirmingSave: '正在确认文稿保存…',
|
|
258
|
+
outputStarting: '正在开始导出已保存的版本…',
|
|
259
|
+
jobFailureReasons: {
|
|
260
|
+
'runtime-job-limit': '当前有其他文稿正在生成。请稍后重试。',
|
|
261
|
+
'runtime-timeout': '生成超出运行时限。请精简文稿资源后重试。',
|
|
262
|
+
'runtime-memory-limit': '生成超出内存限制。请精简文稿资源后重试。',
|
|
263
|
+
'runtime-output-limit': '产物超出存储限制。请精简资源后重新导出。',
|
|
264
|
+
'runtime-input-limit': '文稿使用的文件超出大小限制。请精简资源后重试。',
|
|
265
|
+
'runtime-container-lost': '生成服务已中断。正文已保留,请重新导出。',
|
|
266
|
+
'runtime-container-create-failed': '暂时无法启动生成服务。请稍后重试或联系运营者。',
|
|
267
|
+
'runtime-container-start-failed': '暂时无法启动生成服务。请稍后重试或联系运营者。',
|
|
268
|
+
'runtime-profile-changed': '生成服务的配置已更新。请重新导出。',
|
|
269
|
+
'runtime-storage-unavailable': '暂时无法访问产物存储。请稍后重试或联系运营者。',
|
|
270
|
+
'runtime-process-failed': '文稿未能完成生成。请检查文稿与工程文件后重试。',
|
|
271
|
+
'runtime-output-empty': '未生成可用产物。请检查文稿与工程文件后重试。',
|
|
272
|
+
'runtime-job-failed': '文稿未能完成生成。请检查文稿与工程文件后重试。',
|
|
273
|
+
'preview-build-failed': '预览未能生成。正文已保留,请检查文稿后重试。',
|
|
274
|
+
'preview-build-cancelled': '预览生成已取消。需要时可再次打开预览。',
|
|
275
|
+
'job-source-required': '尚未确认文稿保存版本。请保存后重新导出。',
|
|
276
|
+
'permission-denied': '没有执行此操作的权限。请联系空间所有者。',
|
|
277
|
+
'document-disconnected': '连接中断,文稿尚未确认保存。请检查连接并重试保存。',
|
|
278
|
+
'document-request-failed': '文稿保存失败,请先检查草稿并重试。',
|
|
279
|
+
'document-identity-changed': '文稿已被替换,请重新打开并检查草稿。',
|
|
280
|
+
'document-invalid': '文稿中有无法正确显示的内容,请查看诊断。草稿已保留。',
|
|
281
|
+
'job-translations-invalid': '无法准备译本,请查看诊断后重新导出。',
|
|
282
|
+
'job-save-required': '请先确认并保存当前文稿。',
|
|
283
|
+
'job-timing-draft': '请先处理尚未确认的播放时机。',
|
|
284
|
+
'job-caption-draft': '请先在视频制作中应用或放弃字幕时间。',
|
|
285
|
+
'document-draft-unconfirmed': '请先完成输入法组字,或确认恢复的草稿。',
|
|
286
|
+
'document-version-changed': '文稿已在别处修改,请先处理保存冲突。',
|
|
287
|
+
'document-composition-interrupted': '输入法组字曾中断,请先检查并确认草稿。',
|
|
288
|
+
'document-save-timeout': '文稿保存尚未确认,请检查连接后重试。',
|
|
289
|
+
'save-locked': '文稿正在进行其他修改,请完成后重试。',
|
|
290
|
+
'job-source-changed': '已保存文稿发生变化,请重新导出。',
|
|
291
|
+
'job-source-not-compiled': '无法准备当前保存的版本,请查看诊断后重试。',
|
|
292
|
+
'job-inputs-changed': '导出期间文稿使用的文件发生变化,请重新导出。'
|
|
293
|
+
} as Record<string, string>,
|
|
294
|
+
olderContent: '与当前编辑版本不同',
|
|
295
|
+
openOutput: '打开',
|
|
296
|
+
playOutput: '播放',
|
|
297
|
+
downloadOutput: '下载',
|
|
298
|
+
cancelOutput: '取消',
|
|
299
|
+
outputLog: '详细信息',
|
|
300
|
+
outputFiles: (n: number) => `${n} 个文件`,
|
|
301
|
+
outputFailed: (reason: string) => `无法完成:${reason}`,
|
|
302
|
+
noHistory: '还没有版本。每次修改都会自动保存为一个版本。',
|
|
303
|
+
undoChange: '撤消此更改',
|
|
304
|
+
redoChange: '恢复此更改',
|
|
305
|
+
undone: '已撤消',
|
|
306
|
+
byYou: '你',
|
|
307
|
+
byAi: 'AI',
|
|
308
|
+
byDocument: '文稿操作',
|
|
309
|
+
outside: (n: number) => `有 ${n} 个文件在别处被修改,尚未记入版本历史。`,
|
|
310
|
+
recordOutside: '记为一个版本',
|
|
311
|
+
outsideChange: '在别处所做的修改',
|
|
312
|
+
historyFailed: (reason: string) => `无法完成:${reason}`,
|
|
313
|
+
historyFailureReasons: {
|
|
314
|
+
'history-target-changed': '版本历史已变化,这一更改不再是下一步可撤消或恢复的更改。请查看最新的历史后重试。',
|
|
315
|
+
'history-conflict': '这次更改之后,相关内容又被修改过,或有尚未记入版本的修改,无法自动撤消。',
|
|
316
|
+
'history-source-changed': '文稿已在别处修改,请查看最新的历史后重试。',
|
|
317
|
+
'history-snapshot-changed': '版本历史已变化,请查看最新的历史后重试。',
|
|
318
|
+
'history-revision-not-found': '找不到这个版本,它可能已不在当前历史中。',
|
|
319
|
+
'history-change-already-undone': '这一更改已撤消。',
|
|
320
|
+
'history-baseline-has-no-parent': '这是最初的版本,无法撤消。',
|
|
321
|
+
'history-revert-outside-documents': '这一更改涉及文稿之外的文件,只有工作区所有者可以撤消。',
|
|
322
|
+
'history-busy': '正在进行其他版本操作,请稍后重试。',
|
|
323
|
+
'history-git-unavailable': '这个文件夹没有开启版本历史。',
|
|
324
|
+
'history-intent-reused': '这次操作与之前的请求冲突,请重新操作。',
|
|
325
|
+
'history-result-no-longer-current': '之前的结果已不是当前版本,请查看最新的历史。',
|
|
326
|
+
'authoring-review-required': '有修改等待你审阅,请先接受或放弃。',
|
|
327
|
+
} as Record<string, string>,
|
|
328
|
+
agentWorking: 'AI 正在修改文稿…',
|
|
329
|
+
agentWaiting: (n: number) => `AI 修改了 ${n} 处内容,要接受这些修改吗?`,
|
|
330
|
+
accept: '接受',
|
|
331
|
+
reject: '拒绝',
|
|
332
|
+
problems: (n: number) => `有 ${n} 处内容无法正确显示。`,
|
|
333
|
+
fixWithAi: '用 AI 修复',
|
|
334
|
+
fixing: '正在发送给 AI…',
|
|
335
|
+
fixFailed: (reason: string) => `无法发送给 AI。${reason}`,
|
|
336
|
+
details: '详细信息',
|
|
337
|
+
diagnosticsUnavailable: '暂时无法检查内容是否正确显示,正在重新连接。',
|
|
338
|
+
retry: '重试',
|
|
339
|
+
preview: '文稿',
|
|
340
|
+
previewTitle: (title: string) => `${title}`,
|
|
341
|
+
previewFailed: (reason: string) => `文稿暂时无法显示。${reason}`,
|
|
342
|
+
previewLoading: '正在打开文稿…',
|
|
343
|
+
reloadPreview: '重新加载',
|
|
344
|
+
noSlides: '这份文稿没有幻灯片。',
|
|
345
|
+
versionMismatch: '需要重新启动 Presmium 才能显示这份文稿。',
|
|
346
|
+
previewIdentityMismatch: '显示的内容与所选文稿不一致,请重新加载。',
|
|
347
|
+
focusFailed: (reason: string) => `所选内容没有同步给 AI。${reason}`,
|
|
348
|
+
justNow: '刚刚',
|
|
349
|
+
editedSection: (title: string) => (title ? `编辑“${title}”` : '编辑文字'),
|
|
350
|
+
retitled: (title: string) => `重命名为“${title}”`,
|
|
351
|
+
agentRequest: (instruction: string, places: AgentPlace[]) => [
|
|
352
|
+
instruction.trim(),
|
|
353
|
+
...places.map((place, i) => [
|
|
354
|
+
places.length > 1 ? `${i + 1}.` : '',
|
|
355
|
+
place.section ? `位置:“${place.section}”` : '',
|
|
356
|
+
place.quote ? `\n原文:“${place.quote}”` : '',
|
|
357
|
+
].join('')).filter(Boolean),
|
|
358
|
+
].join('\n\n'),
|
|
359
|
+
commentsRequest: (comments: (AgentPlace & { text: string })[]) => [
|
|
360
|
+
comments.length === 1 ? '我在文稿上写了一条批注:' : `我在文稿上写了 ${comments.length} 条批注:`,
|
|
361
|
+
...comments.map((comment, i) => [
|
|
362
|
+
`${comments.length > 1 ? `${i + 1}. ` : ''}“${comment.text}”`,
|
|
363
|
+
comment.section ? `\n位置:“${comment.section}”` : '',
|
|
364
|
+
comment.quote ? `\n原文:“${comment.quote}”` : '',
|
|
365
|
+
].join('')),
|
|
366
|
+
].join('\n\n'),
|
|
367
|
+
approvals: (count: number) => `待确认 ${count}`,
|
|
368
|
+
approvalsTitle: '待确认的操作',
|
|
369
|
+
approvalFrom: (who: string) => `来自${spaced(who)}`,
|
|
370
|
+
approvalOrigin: { 'presmium.mcp': '外部 AI 工具' } as Record<string, string>,
|
|
371
|
+
approvalOtherOrigin: '其他程序',
|
|
372
|
+
approvalAllow: '允许',
|
|
373
|
+
approvalDeny: '拒绝',
|
|
374
|
+
approvalExpired: '此请求已结束或超时,未执行。',
|
|
375
|
+
approvalFailed: '无法发送答复,请重试。',
|
|
376
|
+
rewriteEditRequest: (before: string, after: string) => `把这段文字改成:“${after}”,保留原有的格式与结构。原来是:“${before}”`,
|
|
377
|
+
}
|
|
378
|
+
|
|
379
|
+
export type WorkbenchMessages = typeof zh
|
|
380
|
+
|
|
381
|
+
const en: WorkbenchMessages = {
|
|
382
|
+
voiceSaveUnconfirmed: 'Couldn’t confirm that voice settings were saved. Your draft is kept; try again.',
|
|
383
|
+
documentEditor: 'Document Editing',
|
|
384
|
+
documentPositionRemoved: 'Your previous location was removed. Choose a new location.',
|
|
385
|
+
documentExport: 'Export Document',
|
|
386
|
+
documentNarration: 'Captions',
|
|
387
|
+
documentNarrationHint: 'Edit captions and when the voiceover starts',
|
|
388
|
+
historyPendingSave: 'Couldn’t confirm the result of undo or redo. Your draft is kept; check the save message and try again.',
|
|
389
|
+
presentationPreview: 'Presentation',
|
|
390
|
+
pageTitle: 'Page title',
|
|
391
|
+
pageMore: (title: string) => `More Actions for “${title}”`,
|
|
392
|
+
pageRenameTitle: 'Rename Page',
|
|
393
|
+
pageCopy: 'Duplicate Page',
|
|
394
|
+
movePageUp: 'Move Page Up',
|
|
395
|
+
movePageDown: 'Move Page Down',
|
|
396
|
+
previewPreparing: 'Preparing the preview. Opening it the first time may take a moment…',
|
|
397
|
+
previewStalled: 'Couldn’t connect to the preview. Reload to try again; the diagnostics are kept.',
|
|
398
|
+
contentWorkspace: 'Content',
|
|
399
|
+
sequenceWorkspace: 'Sequence',
|
|
400
|
+
workspaceLabel: 'Editing Area',
|
|
401
|
+
stepTimeline: 'Page Steps',
|
|
402
|
+
previousStep: 'Previous Step',
|
|
403
|
+
nextStep: 'Next Step',
|
|
404
|
+
exitPresentation: 'End Show',
|
|
405
|
+
presentationReturnFailed: 'Couldn’t confirm the presentation position. Your position and draft are kept; choose End Show again.',
|
|
406
|
+
presentationPending: 'Save the document and wait until the presentation is prepared.',
|
|
407
|
+
presentationPreparing: 'Preparing presentation…',
|
|
408
|
+
presentationCompileFailed: 'Couldn’t prepare the presentation from the saved version. Your document and draft are kept; check the diagnostics and try again.',
|
|
409
|
+
presentationSourceChanged: 'The document changed while the presentation was being prepared. Wait for the current input to save, then present or update again.',
|
|
410
|
+
presentationCompiled: 'Current saved version',
|
|
411
|
+
presentationOutdated: 'Update needed',
|
|
412
|
+
presentationRecompile: 'Update',
|
|
413
|
+
timingDraftPending: 'Some playback timing has not been applied. Edit it or use the inherited value before presenting.',
|
|
414
|
+
stepLabel: (step: number, total: number) => `Step ${step} / ${total}`,
|
|
415
|
+
pages: 'Pages',
|
|
416
|
+
newPage: 'New Page',
|
|
417
|
+
untitledPage: 'Untitled page',
|
|
418
|
+
pageEditFiles: 'This document’s pages are stored in several places, so they can’t be renamed or moved here. The original content is kept.',
|
|
419
|
+
pageEditBoundary: 'Couldn’t tell where this page ends. Reload the document and try again.',
|
|
420
|
+
pageEditHierarchy: 'Only adjacent peer pages can be moved. Cover and chapter boundaries remain fixed.',
|
|
421
|
+
pageEditImplicitTitle: 'This page uses the document title and cannot yet be renamed separately.',
|
|
422
|
+
pageEditFormattedTitle: 'This title contains complex formatting and cannot yet be renamed here. Its formatting is kept.',
|
|
423
|
+
pageEditInvalidTitle: 'Enter a page title without line breaks.',
|
|
424
|
+
pageEditBusy: 'A page change is still in progress. Wait a moment.',
|
|
425
|
+
pageEditPreview: 'Wait until the preview is ready before changing pages.',
|
|
426
|
+
pageEditChanged: 'The document or preview changed. This page operation was stopped.',
|
|
427
|
+
pageEditFlushTimeout: 'Waiting for body or script edits to save timed out. Your drafts are kept; try again.',
|
|
428
|
+
pageEditDraft: 'Body or script edits have an unresolved save problem. Resolve those drafts first.',
|
|
429
|
+
pageEditSourceDraft: 'An asset draft has not been applied. Save or discard it before changing pages.',
|
|
430
|
+
pageEditRefresh: 'The page change was saved, but its preview has not confirmed the update. Reload the document.',
|
|
431
|
+
pageEditCompiler: 'This workspace service can’t keep links to pages with non-English titles yet. Restart Presmium and try again. The page has not been changed.',
|
|
432
|
+
pageEditRequestFailed: 'Couldn’t finish the page change. Your drafts are kept; try again.',
|
|
433
|
+
pageRenamed: (title: string) => `Rename page to “${title}”`,
|
|
434
|
+
pageMoved: (title: string) => `Move page “${title}”`,
|
|
435
|
+
pageDelete: 'Delete Page',
|
|
436
|
+
pageDeleteTitle: (title: string) => `Delete “${title}”?`,
|
|
437
|
+
pageDeleteLoading: 'Checking page boundaries and incoming references…',
|
|
438
|
+
pageDeleteHint: (steps: number, narration: number) => `This page contains ${steps} ${steps === 1 ? 'step' : 'steps'} and ${narration} ${narration === 1 ? 'script' : 'scripts'}. You can undo the deletion in Version History. Shared assets are kept.`,
|
|
439
|
+
pageDeleteLast: 'This is the last page. Its content will be cleared and an empty page kept.',
|
|
440
|
+
pageDeleteReferenced: 'Other content still references this page or a target inside it. Remove those references before deleting the page.',
|
|
441
|
+
pageDeleteExternalBindings: 'This page’s scripts are stored separately, so the page can’t be deleted safely with them yet. The page is kept.',
|
|
442
|
+
pageDeleteReferencesUnavailable: 'Related documents are still updating, so their references cannot be confirmed yet. The page is kept; retry shortly.',
|
|
443
|
+
pageTimeout: 'Couldn’t confirm the new page. Check the document before trying again.',
|
|
444
|
+
pageBoundary: 'Couldn’t tell where this page ends, so a new page can’t be added here yet.',
|
|
445
|
+
blockUnknown: 'The page could not be found.',
|
|
446
|
+
blockConflict: 'The document changed. Your draft is kept. Reload before continuing.',
|
|
447
|
+
blockFiles: 'This page’s content is stored in several places, so its blocks can’t be rearranged here yet.',
|
|
448
|
+
blockStepOrder: 'This page reveals its items one by one, so its blocks can’t be reordered here yet. Your draft is kept.',
|
|
449
|
+
blockSourceBinding: 'The link to the original content no longer holds, so this block can’t be restored safely. Your draft is kept; restore the original content from Version History.',
|
|
450
|
+
nativeEditTarget: 'The original text moved, so it can’t be saved safely. Your edit is kept; review the current document, then try again or copy your changes.',
|
|
451
|
+
nativeEditConflict: 'The original text or its version changed. Your draft is kept; review the current text, then copy or discard the edit.',
|
|
452
|
+
nativeEditDraft: 'A draft of a title or special text still needs attention. Your edit is kept; save or discard that draft first.',
|
|
453
|
+
nativeEditUnavailable: 'This service can’t check the version of this text yet. Your edit is kept; restart Presmium and try again.',
|
|
454
|
+
nativeEditFormat: 'This edit crosses formatting or special marks and can’t be saved safely. Your edit is kept; make a smaller change or copy it.',
|
|
455
|
+
nativeEditConfirmation: 'The text may have been saved, but its version is not confirmed. Your edit is kept; review the current document before trying again.',
|
|
456
|
+
blockContainer: 'This block contains nested scripts or scope settings, so its structure can’t be changed here yet. The original is kept.',
|
|
457
|
+
editedBody: (title: string) => `Edit Text in “${title}”`,
|
|
458
|
+
sourceUnknown: 'Couldn’t find this block. Reload and try again.',
|
|
459
|
+
sourceChanged: 'This block changed elsewhere. Your draft is kept; reload it.',
|
|
460
|
+
sourceIgnored: 'Related files are outside what Version History records, so they can’t be saved with the document. Ask your administrator to change this and try again.',
|
|
461
|
+
sourceLarge: 'This block is larger than the editor supports.',
|
|
462
|
+
sourceAnimationUnavailable: 'Animation blocks are not enabled for this document.',
|
|
463
|
+
sourceRefresh: 'The content was saved, but the preview has not updated. Reload the document to continue.',
|
|
464
|
+
createdAnimation: 'Insert Animation',
|
|
465
|
+
editedSource: (title: string) => `Edit Block in “${title}”`,
|
|
466
|
+
narration: 'Script',
|
|
467
|
+
narrationFormatted: 'This script includes formatting or action cues and can’t be replaced as a whole. Edit it in smaller parts; your draft is kept.',
|
|
468
|
+
narrationText: 'Current step script',
|
|
469
|
+
narrationPlaceholder: 'Enter this step’s script for voiceover and captions.',
|
|
470
|
+
narrationAutosave: 'Saved automatically. Switching steps keeps unfinished drafts.',
|
|
471
|
+
narrationDiscard: 'Discard Draft',
|
|
472
|
+
narrationRecoveryUnavailable: 'This browser can’t keep drafts on this device. Your draft stays in this session; save before closing the window.',
|
|
473
|
+
documentDraftFound: 'Drafts found on this device',
|
|
474
|
+
documentDraftSelect: 'Recover Draft',
|
|
475
|
+
documentDraftChoose: 'Choose a draft',
|
|
476
|
+
documentDraftRestore: 'Recover Draft',
|
|
477
|
+
documentDraftChanged: 'The draft on this device changed. Choose it again.',
|
|
478
|
+
documentDraftUnreadable: 'Couldn’t read some drafts on this device.',
|
|
479
|
+
documentDraftBackingUp: 'Backing up…',
|
|
480
|
+
documentDraftOption: (index: number, date: string, source: 'durable' | 'rescue') => `${date} · ${source === 'rescue' ? 'Temporary copy' : 'Draft'} ${index}`,
|
|
481
|
+
narrationCompositionInterrupted: 'Typing with the input method was interrupted. Your draft is kept; review it before saving, or keep editing.',
|
|
482
|
+
narrationRefresh: 'The script was written, but the preview has not updated yet. Your draft is kept; retry after the preview recovers.',
|
|
483
|
+
narrationDuring: 'During animation',
|
|
484
|
+
narrationAfter: 'After animation',
|
|
485
|
+
narrationMode: 'Voiceover timing',
|
|
486
|
+
narrationChanged: 'The document changed. Keep your draft and reload this step before saving.',
|
|
487
|
+
narrationPending: 'This draft is not saved. Save or cancel before switching steps.',
|
|
488
|
+
narrationScript: 'This page’s script is stored separately and can’t be edited here yet.',
|
|
489
|
+
narrationFiles: 'This step’s script is stored in several places or covers different content. Edit those parts in the document separately.',
|
|
490
|
+
narrationLoading: 'Loading script…',
|
|
491
|
+
narrationTimeline: 'Playback sequence',
|
|
492
|
+
narrationAnimation: 'Animation',
|
|
493
|
+
narrationSpeech: 'Voiceover',
|
|
494
|
+
narrationStep: (page: number, step: number) => `Page ${page} · Step ${step}`,
|
|
495
|
+
editedNarration: (step: number) => `Edit Script for Step ${step}`,
|
|
496
|
+
documents: 'Documents',
|
|
497
|
+
workspace: 'Workspace',
|
|
498
|
+
allDocuments: 'All documents',
|
|
499
|
+
search: 'Search documents',
|
|
500
|
+
noMatch: 'No matching documents.',
|
|
501
|
+
newDocument: 'New Document',
|
|
502
|
+
noDocuments: 'No documents yet. Choose New Document to start.',
|
|
503
|
+
notGit: 'Version History is not turned on for this folder. New, Rename, Make a Copy, Delete, and Undo need it. Ask your administrator to turn on Version History for this folder.',
|
|
504
|
+
bundleDisabled: 'Couldn’t load the documents: the Presmium extension was turned off on the Plugins page. Open Plugins from More, turn Presmium on again, then reload the page.',
|
|
505
|
+
more: (title: string) => `More Actions for “${title}”`,
|
|
506
|
+
open: 'Open',
|
|
507
|
+
rename: 'Rename',
|
|
508
|
+
makeCopy: 'Make a Copy',
|
|
509
|
+
remove: 'Delete',
|
|
510
|
+
title: 'Title',
|
|
511
|
+
titlePlaceholder: 'For example: Lecture 3, Attention',
|
|
512
|
+
template: 'Template',
|
|
513
|
+
create: 'Create',
|
|
514
|
+
save: 'Save',
|
|
515
|
+
confirmRemove: (title: string) => `Delete “${title}”?`,
|
|
516
|
+
removeImpact: (files: number) => `${files} ${files === 1 ? 'file or link' : 'files or links'} will be deleted.`,
|
|
517
|
+
projectInspecting: 'Checking…',
|
|
518
|
+
cancel: 'Cancel',
|
|
519
|
+
close: 'Close',
|
|
520
|
+
created: (title: string) => `Created “${title}”`,
|
|
521
|
+
renamed: (title: string) => `Renamed to “${title}”`,
|
|
522
|
+
copied: (title: string) => `Made a copy: “${title}”`,
|
|
523
|
+
removed: (title: string) => `Deleted “${title}”`,
|
|
524
|
+
back: 'Back to Documents',
|
|
525
|
+
undo: 'Undo',
|
|
526
|
+
redo: 'Redo',
|
|
527
|
+
undoWhat: (what: string) => `Undo: ${what} (${SHORTCUTS.undo})`,
|
|
528
|
+
redoWhat: (what: string) => `Redo: ${what} (${SHORTCUTS.redo})`,
|
|
529
|
+
nothingToUndo: 'Nothing to undo',
|
|
530
|
+
nothingToRedo: 'Nothing to redo',
|
|
531
|
+
saving: 'Saving…',
|
|
532
|
+
saved: 'Saved',
|
|
533
|
+
unsaved: 'Not saved',
|
|
534
|
+
savedAt: (time: string) => `Saved · ${time}`,
|
|
535
|
+
saveLocked: 'The AI is editing the document. Edit this again in a moment.',
|
|
536
|
+
saveFailed: (reason: string) => `Couldn’t save the document. ${reason}`,
|
|
537
|
+
failureReasons: {
|
|
538
|
+
'document-version-changed': 'The document changed elsewhere. Your input is kept; reload, then save again.',
|
|
539
|
+
'document-readback-changed': 'The document changed elsewhere. Your input is kept; reload, then save again.',
|
|
540
|
+
'document-identity-changed': 'This document was replaced. Open it again.',
|
|
541
|
+
'document-invalid': 'The changed document doesn’t pass the check. Your input is kept; undo the latest change and try again.',
|
|
542
|
+
'document-files-ignored': 'Version History ignores this document’s files, so it can’t be saved. Ask the administrator to check the workspace settings.',
|
|
543
|
+
'document-change-id-reused': 'This change was already saved. Reload and check it.',
|
|
544
|
+
'document-disconnected': 'Couldn’t reach the workspace service. Your input is kept; check the connection and try again.',
|
|
545
|
+
'document-request-failed': 'The workspace service didn’t finish the request. Your input is kept; try again.',
|
|
546
|
+
'page-context-changed': 'The page changed. Select it again and retry.',
|
|
547
|
+
'authoring-review-required': 'This change needs to be allowed in Pending Approvals first.',
|
|
548
|
+
'authoring-permission-denied': 'You don’t have permission to change this document.',
|
|
549
|
+
'preview-timeout': 'Preparing the preview timed out. Your content and drafts are kept; try again.',
|
|
550
|
+
'no-conversation': 'The chat is not ready yet. Try again in a moment.',
|
|
551
|
+
network: 'Couldn’t reach the workspace service. Check the connection and try again.',
|
|
552
|
+
} as Record<string, string>,
|
|
553
|
+
failureGeneric: 'Try again. If it keeps failing, reload the page.',
|
|
554
|
+
|
|
555
|
+
editingMode: 'Editing',
|
|
556
|
+
viewingMode: 'Viewing',
|
|
557
|
+
modeLabel: 'Mode',
|
|
558
|
+
editingHint: 'Click content to edit it, comment on it, or send it to the AI',
|
|
559
|
+
viewingHint: 'Read it as your readers do; links and interactive content work',
|
|
560
|
+
view: 'View',
|
|
561
|
+
renderers: { web: 'Web', slides: 'Slides' },
|
|
562
|
+
present: 'Present',
|
|
563
|
+
readDocument: 'Read and Run',
|
|
564
|
+
editDocument: 'Back to Editing',
|
|
565
|
+
readingFailed: 'Couldn’t prepare the document reading view. Confirm the document is saved, check the diagnostics, then try again.',
|
|
566
|
+
video: 'Video',
|
|
567
|
+
videoHint: 'The lecture video as it will look: the slides, voiceover, captions, and animations on its timeline, updated as you edit',
|
|
568
|
+
videoFile: 'Video file',
|
|
569
|
+
noVideoFile: 'Not exported yet',
|
|
570
|
+
makeVideoFile: 'Export Video',
|
|
571
|
+
remakeVideoFile: 'Export Again',
|
|
572
|
+
playVideoFile: 'Play',
|
|
573
|
+
presentHint: 'Present the slides step by step, with voiceover, captions, and animations when the lecture is set up. Export makes the video file.',
|
|
574
|
+
slidesHint: 'The slides’ own layout, as when presenting them',
|
|
575
|
+
commands: 'Commands',
|
|
576
|
+
moreCommands: 'More',
|
|
577
|
+
navigation: 'Navigation',
|
|
578
|
+
navigationPane: 'Navigation Pane',
|
|
579
|
+
closeNavigation: 'Close Navigation Pane',
|
|
580
|
+
headings: 'Headings',
|
|
581
|
+
noSections: 'This document has no pages yet.',
|
|
582
|
+
loadingPages: 'Loading pages…',
|
|
583
|
+
statusBar: 'Status Bar',
|
|
584
|
+
pageOf: (n: number, total: number) => `Page ${n} of ${total}`,
|
|
585
|
+
slideOf: (n: number, total: number) => `Slide ${n} of ${total}`,
|
|
586
|
+
words: (n: number) => `${n.toLocaleString('en')} ${n === 1 ? 'word' : 'words'}`,
|
|
587
|
+
comments: 'Comments',
|
|
588
|
+
newComment: 'New Comment',
|
|
589
|
+
commentPlaceholder: 'Write a comment…',
|
|
590
|
+
postComment: 'Post',
|
|
591
|
+
noComments: 'No comments yet. Select some text or click a block and choose New Comment to note what should change; when you have written them, send them to the AI together.',
|
|
592
|
+
askAboutComment: 'Send to AI',
|
|
593
|
+
askAboutAll: 'Send All to AI',
|
|
594
|
+
sendComments: (n: number) => `Send ${n} ${n === 1 ? 'Comment' : 'Comments'} to AI`,
|
|
595
|
+
pendingComments: (n: number) => `${n} comment${n === 1 ? ' is' : 's are'} waiting to be sent. Send them to the AI together; its changes become one version.`,
|
|
596
|
+
resolve: 'Resolve',
|
|
597
|
+
reopen: 'Reopen',
|
|
598
|
+
deleteComment: 'Delete Comment',
|
|
599
|
+
sentToAi: 'Sent to AI',
|
|
600
|
+
resolved: 'Resolved',
|
|
601
|
+
showResolved: 'Show resolved comments',
|
|
602
|
+
inSection: (title: string) => `In “${title}”`,
|
|
603
|
+
pointerTools: 'Actions on the selection',
|
|
604
|
+
askFailed: (reason: string) => `Couldn’t send to the AI. ${reason}`,
|
|
605
|
+
formattedEdit: 'This text has formatting or special content and can’t be edited directly. Rewrite it with AI?',
|
|
606
|
+
rewriteEdit: 'Rewrite with AI',
|
|
607
|
+
versionHistory: 'Version History',
|
|
608
|
+
historyNewer: 'Newer versions',
|
|
609
|
+
historyOlder: 'Older versions',
|
|
610
|
+
exportPane: 'Export',
|
|
611
|
+
makeLabel: 'Export',
|
|
612
|
+
outputLabels: { web: 'Website', slides: 'Slides Website', notebook: 'Notebook', lecture: 'Lecture' },
|
|
613
|
+
makeOutput: (label: string) => `Export ${label}`,
|
|
614
|
+
outputsList: 'Export History',
|
|
615
|
+
noOutputs: 'Nothing exported yet.',
|
|
616
|
+
jobStates: { queued: 'Queued', running: 'Exporting', done: 'Completed', failed: 'Export failed', cancelled: 'Canceled' },
|
|
617
|
+
jobPhases: { prepare: 'Preparing', export: 'Exporting', build: 'Exporting', frames: 'Recording frames' },
|
|
618
|
+
jobProgress: (phase: string, done?: number, total?: number) => (total ? `${phase} ${done ?? 0} of ${total}` : `${phase}…`),
|
|
619
|
+
currentContent: 'Same saved document version',
|
|
620
|
+
outputVersionUnknown: 'Saved version not recorded',
|
|
621
|
+
outputConfirmingSave: 'Confirming the document save…',
|
|
622
|
+
outputStarting: 'Starting to export the saved version…',
|
|
623
|
+
jobFailureReasons: {
|
|
624
|
+
'runtime-job-limit': 'Other documents are being generated. Try again shortly.',
|
|
625
|
+
'runtime-timeout': 'Generation exceeded its runtime limit. Reduce document resources and retry.',
|
|
626
|
+
'runtime-memory-limit': 'Generation exceeded its memory limit. Reduce document resources and retry.',
|
|
627
|
+
'runtime-output-limit': 'The output exceeded its storage limit. Reduce resources and export again.',
|
|
628
|
+
'runtime-input-limit': 'The document files exceeded the size limit. Reduce resources and retry.',
|
|
629
|
+
'runtime-container-lost': 'The generation service was interrupted. Your document is kept. Export again.',
|
|
630
|
+
'runtime-container-create-failed': 'The generation service could not start. Retry later or contact the operator.',
|
|
631
|
+
'runtime-container-start-failed': 'The generation service could not start. Retry later or contact the operator.',
|
|
632
|
+
'runtime-profile-changed': 'The generation service configuration changed. Export again.',
|
|
633
|
+
'runtime-storage-unavailable': 'Output storage is unavailable. Retry later or contact the operator.',
|
|
634
|
+
'runtime-process-failed': 'The document could not be generated. Check the document and project files, then retry.',
|
|
635
|
+
'runtime-output-empty': 'No usable output was generated. Check the document and project files, then retry.',
|
|
636
|
+
'runtime-job-failed': 'The document could not be generated. Check the document and project files, then retry.',
|
|
637
|
+
'preview-build-failed': 'The preview could not be generated. Your document is kept. Check it and retry.',
|
|
638
|
+
'preview-build-cancelled': 'Preview generation was canceled. Open the preview again when needed.',
|
|
639
|
+
'job-source-required': 'The saved document version is not confirmed. Save and export again.',
|
|
640
|
+
'permission-denied': 'You do not have permission for this action. Contact the space owner.',
|
|
641
|
+
'document-disconnected': 'The connection was interrupted. The document save is not confirmed. Check the connection and retry saving.',
|
|
642
|
+
'document-request-failed': 'Couldn’t save the document. Review the draft and try again.',
|
|
643
|
+
'document-identity-changed': 'The document was replaced. Reopen it and review your draft.',
|
|
644
|
+
'document-invalid': 'The document has content that can’t be displayed correctly. Check the diagnostics; your draft is kept.',
|
|
645
|
+
'job-translations-invalid': 'Couldn’t prepare a translation. Check the diagnostics and export again.',
|
|
646
|
+
'job-save-required': 'Confirm and save the current document first.',
|
|
647
|
+
'job-timing-draft': 'Resolve the playback timing that is not confirmed first.',
|
|
648
|
+
'job-caption-draft': 'Apply or discard caption times in Video Production first.',
|
|
649
|
+
'document-draft-unconfirmed': 'Finish typing with the input method, or confirm the recovered draft first.',
|
|
650
|
+
'document-version-changed': 'The document changed elsewhere. Resolve the save conflict first.',
|
|
651
|
+
'document-composition-interrupted': 'Typing with the input method was interrupted. Review and confirm the draft first.',
|
|
652
|
+
'document-save-timeout': 'The save has not been confirmed. Check the connection and retry.',
|
|
653
|
+
'save-locked': 'Another change is in progress. Finish it and retry.',
|
|
654
|
+
'job-source-changed': 'The saved document changed. Start the export again.',
|
|
655
|
+
'job-source-not-compiled': 'Couldn’t prepare the saved version. Check the diagnostics and try again.',
|
|
656
|
+
'job-inputs-changed': 'Files used by the document changed during the export. Start the export again.'
|
|
657
|
+
},
|
|
658
|
+
olderContent: 'Different from the current editing version',
|
|
659
|
+
openOutput: 'Open',
|
|
660
|
+
playOutput: 'Play',
|
|
661
|
+
downloadOutput: 'Download',
|
|
662
|
+
cancelOutput: 'Cancel',
|
|
663
|
+
outputLog: 'Details',
|
|
664
|
+
outputFiles: (n: number) => `${n} ${n === 1 ? 'file' : 'files'}`,
|
|
665
|
+
outputFailed: (reason: string) => `Couldn’t finish: ${reason}`,
|
|
666
|
+
noHistory: 'No versions yet. Every change is saved as a version automatically.',
|
|
667
|
+
undoChange: 'Undo This Change',
|
|
668
|
+
redoChange: 'Redo This Change',
|
|
669
|
+
undone: 'Undone',
|
|
670
|
+
byYou: 'You',
|
|
671
|
+
byAi: 'AI',
|
|
672
|
+
byDocument: 'Document',
|
|
673
|
+
outside: (n: number) => `${n} file${n === 1 ? ' was' : 's were'} changed elsewhere and ${n === 1 ? 'is' : 'are'} not in Version History yet.`,
|
|
674
|
+
recordOutside: 'Save as a Version',
|
|
675
|
+
outsideChange: 'Changes made elsewhere',
|
|
676
|
+
historyFailed: (reason: string) => `Couldn’t finish: ${reason}`,
|
|
677
|
+
historyFailureReasons: {
|
|
678
|
+
'history-target-changed': 'Version History changed; this change is no longer the next one to undo or redo. Review the latest history and try again.',
|
|
679
|
+
'history-conflict': 'The content was changed again after this change, or has changes not yet saved as a version, so it can’t be undone automatically.',
|
|
680
|
+
'history-source-changed': 'The document changed elsewhere. Review the latest history and try again.',
|
|
681
|
+
'history-snapshot-changed': 'Version History changed. Review the latest history and try again.',
|
|
682
|
+
'history-revision-not-found': 'Couldn’t find this version; it may no longer be in the current history.',
|
|
683
|
+
'history-change-already-undone': 'This change has already been undone.',
|
|
684
|
+
'history-baseline-has-no-parent': 'This is the first version and can’t be undone.',
|
|
685
|
+
'history-revert-outside-documents': 'This change touches files outside the documents; only the workspace owner can undo it.',
|
|
686
|
+
'history-busy': 'Another version operation is in progress. Try again shortly.',
|
|
687
|
+
'history-git-unavailable': 'Version History is not turned on for this folder.',
|
|
688
|
+
'history-intent-reused': 'This operation conflicts with an earlier request. Do it again.',
|
|
689
|
+
'history-result-no-longer-current': 'The earlier result is no longer the current version. Review the latest history.',
|
|
690
|
+
'authoring-review-required': 'Changes are waiting for your review. Accept or discard them first.',
|
|
691
|
+
},
|
|
692
|
+
agentWorking: 'The AI is editing the document…',
|
|
693
|
+
agentWaiting: (n: number) => `The AI changed ${n} file${n === 1 ? '' : 's'}. Accept the changes?`,
|
|
694
|
+
accept: 'Accept',
|
|
695
|
+
reject: 'Reject',
|
|
696
|
+
problems: (n: number) => `${n} item${n === 1 ? '' : 's'} can’t be displayed correctly.`,
|
|
697
|
+
fixWithAi: 'Fix with AI',
|
|
698
|
+
fixing: 'Sending to the AI…',
|
|
699
|
+
fixFailed: (reason: string) => `Couldn’t send to the AI. ${reason}`,
|
|
700
|
+
details: 'Details',
|
|
701
|
+
diagnosticsUnavailable: 'Can’t check the document right now. Reconnecting…',
|
|
702
|
+
retry: 'Retry',
|
|
703
|
+
preview: 'Document',
|
|
704
|
+
previewTitle: (title: string) => `${title}`,
|
|
705
|
+
previewFailed: (reason: string) => `The document can’t be shown right now. ${reason}`,
|
|
706
|
+
previewLoading: 'Opening the document…',
|
|
707
|
+
reloadPreview: 'Reload',
|
|
708
|
+
noSlides: 'This document has no slides.',
|
|
709
|
+
versionMismatch: 'Restart Presmium to show this document.',
|
|
710
|
+
previewIdentityMismatch: 'What is shown does not match the chosen document. Reload it.',
|
|
711
|
+
focusFailed: (reason: string) => `The selection did not reach the AI. ${reason}`,
|
|
712
|
+
justNow: 'just now',
|
|
713
|
+
editedSection: (title: string) => (title ? `Edit “${title}”` : 'Edit Text'),
|
|
714
|
+
retitled: (title: string) => `Rename to “${title}”`,
|
|
715
|
+
agentRequest: (instruction: string, places: AgentPlace[]) => [
|
|
716
|
+
instruction.trim(),
|
|
717
|
+
...places.map((place, i) => [
|
|
718
|
+
places.length > 1 ? `${i + 1}. ` : '',
|
|
719
|
+
place.section ? `Where: “${place.section}”` : '',
|
|
720
|
+
place.quote ? `\nText: “${place.quote}”` : '',
|
|
721
|
+
].join('')).filter(Boolean),
|
|
722
|
+
].join('\n\n'),
|
|
723
|
+
commentsRequest: (comments: (AgentPlace & { text: string })[]) => [
|
|
724
|
+
comments.length === 1 ? 'I left a comment on the document:' : `I left ${comments.length} comments on the document:`,
|
|
725
|
+
...comments.map((comment, i) => [
|
|
726
|
+
`${comments.length > 1 ? `${i + 1}. ` : ''}“${comment.text}”`,
|
|
727
|
+
comment.section ? `\nWhere: “${comment.section}”` : '',
|
|
728
|
+
comment.quote ? `\nText: “${comment.quote}”` : '',
|
|
729
|
+
].join('')),
|
|
730
|
+
].join('\n\n'),
|
|
731
|
+
approvals: (count: number) => `Pending Approvals (${count})`,
|
|
732
|
+
approvalsTitle: 'Pending Approvals',
|
|
733
|
+
approvalFrom: (who: string) => `From ${who}`,
|
|
734
|
+
approvalOrigin: { 'presmium.mcp': 'an external AI tool' },
|
|
735
|
+
approvalOtherOrigin: 'another program',
|
|
736
|
+
approvalAllow: 'Allow',
|
|
737
|
+
approvalDeny: 'Deny',
|
|
738
|
+
approvalExpired: 'This request already ended or timed out; nothing was done.',
|
|
739
|
+
approvalFailed: 'Couldn’t send your answer. Try again.',
|
|
740
|
+
rewriteEditRequest: (before: string, after: string) => `Change this text to “${after}”, keeping its formatting and structure. It was “${before}”.`,
|
|
741
|
+
}
|
|
742
|
+
|
|
743
|
+
export const MESSAGES: Record<Locale, WorkbenchMessages> = { 'zh-CN': zh, en }
|
|
744
|
+
|
|
745
|
+
const NETWORK_FAILURE = /^(?:Failed to fetch|NetworkError when attempting to fetch resource\.|Load failed|network error)$/i
|
|
746
|
+
const reported = new Set<string>()
|
|
747
|
+
|
|
748
|
+
/**
|
|
749
|
+
* The localized sentence for why an operation failed. A server or the browser gives a stable code (`document-version-changed`)
|
|
750
|
+
* or its own words; an author sees only catalog text, and words without an entry become the generic sentence (the raw
|
|
751
|
+
* reason goes to the console once, for whoever reads the log).
|
|
752
|
+
*/
|
|
753
|
+
export function failureReason(t: WorkbenchMessages, reason: string | undefined): string {
|
|
754
|
+
if (reason && reason in t.failureReasons) return t.failureReasons[reason]!
|
|
755
|
+
if (reason && NETWORK_FAILURE.test(reason)) return t.failureReasons.network!
|
|
756
|
+
if (reason && !reported.has(reason)) { reported.add(reason); console.warn(`presmium: failure reason without a catalog entry: ${reason}`) }
|
|
757
|
+
return t.failureGeneric
|
|
758
|
+
}
|
|
759
|
+
|
|
760
|
+
/** Text the workbench writes into a document (new page titles, copy names) follows the document's `lang`, not the interface's. */
|
|
761
|
+
const CONTENT = {
|
|
762
|
+
'zh-CN': { newPage: '新页面', copyTitle: (title: string) => `${title}(副本)` },
|
|
763
|
+
en: { newPage: 'New page', copyTitle: (title: string) => `${title} (copy)` },
|
|
764
|
+
} satisfies Record<Locale, unknown>
|
|
765
|
+
|
|
766
|
+
export function contentText(lang: string | undefined): typeof CONTENT[Locale] {
|
|
767
|
+
return CONTENT[localeOf(lang ?? 'zh-CN') ?? 'en']
|
|
768
|
+
}
|
|
769
|
+
|
|
770
|
+
/** A time as "just now", "5 minutes ago", or a date for older ones. */
|
|
771
|
+
export function timeAgo(iso: string, locale: Locale, now = Date.now()): string {
|
|
772
|
+
const then = Date.parse(iso)
|
|
773
|
+
if (!Number.isFinite(then)) return ''
|
|
774
|
+
const seconds = Math.round((then - now) / 1000)
|
|
775
|
+
if (seconds > -45) return MESSAGES[locale].justNow
|
|
776
|
+
const format = new Intl.RelativeTimeFormat(locale, { numeric: 'auto' })
|
|
777
|
+
if (seconds > -3600) return format.format(Math.round(seconds / 60), 'minute')
|
|
778
|
+
if (seconds > -86_400) return format.format(Math.round(seconds / 3600), 'hour')
|
|
779
|
+
if (seconds > -7 * 86_400) return format.format(Math.round(seconds / 86_400), 'day')
|
|
780
|
+
return new Date(then).toLocaleDateString(locale)
|
|
781
|
+
}
|