dsh-cait 1.0.3 → 1.0.4
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/CHANGELOG.md +367 -352
- package/LICENSE +201 -201
- package/README.ja.md +4 -3
- package/README.md +424 -423
- package/README.zh-CN.md +391 -390
- package/client/components.js +2377 -2377
- package/client/helpers.js +103 -103
- package/client/locales.js +730 -730
- package/client/rpc.js +93 -93
- package/client/styles.js +258 -258
- package/client.js +3556 -3556
- package/icon.svg +8 -8
- package/index.js +45 -45
- package/lib/api.js +223 -223
- package/lib/docx.js +389 -389
- package/lib/errors.js +8 -8
- package/lib/formats.js +917 -917
- package/lib/glossary.js +178 -178
- package/lib/import-export.js +605 -605
- package/lib/libraries.js +183 -183
- package/lib/markdown.js +28 -28
- package/lib/mt.js +152 -152
- package/lib/persistence.js +321 -321
- package/lib/pptx.js +89 -89
- package/lib/segmenter.js +84 -84
- package/lib/similarity.js +113 -113
- package/lib/store-utils.js +339 -339
- package/lib/store.js +734 -734
- package/lib/tm.js +160 -160
- package/lib/tmx.js +85 -85
- package/lib/tools.js +472 -472
- package/lib/xlsx.js +218 -218
- package/lib/xml.js +31 -31
- package/locale/en.json +11 -11
- package/locale/zh.json +11 -11
- package/package.json +83 -83
- package/scripts/build-client.mjs +13 -13
package/lib/libraries.js
CHANGED
|
@@ -1,183 +1,183 @@
|
|
|
1
|
-
import { CatError } from './errors.js'
|
|
2
|
-
import { DEFAULT_GLOSSARY_ID, DEFAULT_GLOSSARY_NAME, DEFAULT_TM_ID, DEFAULT_TM_NAME, cleanLibraryName, makeId, now, restoredDate } from './store-utils.js'
|
|
3
|
-
|
|
4
|
-
export const libraryMethods = {
|
|
5
|
-
resetLibraryState() {
|
|
6
|
-
const stamp = now()
|
|
7
|
-
this.tmLibraries = [
|
|
8
|
-
{
|
|
9
|
-
tmId: DEFAULT_TM_ID,
|
|
10
|
-
name: DEFAULT_TM_NAME,
|
|
11
|
-
createdAt: stamp,
|
|
12
|
-
updatedAt: stamp,
|
|
13
|
-
},
|
|
14
|
-
]
|
|
15
|
-
this.glossaryLibraries = [
|
|
16
|
-
{
|
|
17
|
-
glossaryId: DEFAULT_GLOSSARY_ID,
|
|
18
|
-
name: DEFAULT_GLOSSARY_NAME,
|
|
19
|
-
createdAt: stamp,
|
|
20
|
-
updatedAt: stamp,
|
|
21
|
-
},
|
|
22
|
-
]
|
|
23
|
-
this.mounts = {
|
|
24
|
-
tmIds: [DEFAULT_TM_ID],
|
|
25
|
-
glossaryIds: [DEFAULT_GLOSSARY_ID],
|
|
26
|
-
defaultTmId: DEFAULT_TM_ID,
|
|
27
|
-
defaultGlossaryId: DEFAULT_GLOSSARY_ID,
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
,
|
|
31
|
-
requireTmLibrary(tmId) {
|
|
32
|
-
const id = String(tmId ?? '').trim() || this.mounts.defaultTmId
|
|
33
|
-
if (!this.tmLibraries.some((library) => library.tmId === id)) {
|
|
34
|
-
throw new CatError('TM_NOT_FOUND', `翻译记忆库不存在: ${id}`, 404)
|
|
35
|
-
}
|
|
36
|
-
return id
|
|
37
|
-
}
|
|
38
|
-
,
|
|
39
|
-
requireMountedTmLibrary(tmId) {
|
|
40
|
-
const id = this.requireTmLibrary(tmId)
|
|
41
|
-
if (!this.mounts.tmIds.includes(id)) {
|
|
42
|
-
throw new CatError(
|
|
43
|
-
'TM_NOT_MOUNTED',
|
|
44
|
-
`翻译记忆库未挂载: ${id},请先在 CAIT 的库面板挂载它。`,
|
|
45
|
-
409,
|
|
46
|
-
)
|
|
47
|
-
}
|
|
48
|
-
return id
|
|
49
|
-
}
|
|
50
|
-
,
|
|
51
|
-
requireGlossaryLibrary(glossaryId) {
|
|
52
|
-
const id = String(glossaryId ?? '').trim() || this.mounts.defaultGlossaryId
|
|
53
|
-
if (!this.glossaryLibraries.some((library) => library.glossaryId === id)) {
|
|
54
|
-
throw new CatError('GLOSSARY_NOT_FOUND', `术语库不存在: ${id}`, 404)
|
|
55
|
-
}
|
|
56
|
-
return id
|
|
57
|
-
}
|
|
58
|
-
,
|
|
59
|
-
requireMountedGlossaryLibrary(glossaryId) {
|
|
60
|
-
const id = this.requireGlossaryLibrary(glossaryId)
|
|
61
|
-
if (!this.mounts.glossaryIds.includes(id)) {
|
|
62
|
-
throw new CatError(
|
|
63
|
-
'GLOSSARY_NOT_MOUNTED',
|
|
64
|
-
`术语库未挂载: ${id},请先在 CAIT 的库面板挂载它。`,
|
|
65
|
-
409,
|
|
66
|
-
)
|
|
67
|
-
}
|
|
68
|
-
return id
|
|
69
|
-
}
|
|
70
|
-
,
|
|
71
|
-
mountsView() {
|
|
72
|
-
return {
|
|
73
|
-
tmIds: [...this.mounts.tmIds],
|
|
74
|
-
glossaryIds: [...this.mounts.glossaryIds],
|
|
75
|
-
defaultTmId: this.mounts.defaultTmId,
|
|
76
|
-
defaultGlossaryId: this.mounts.defaultGlossaryId,
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
,
|
|
80
|
-
librariesView() {
|
|
81
|
-
const mountedTm = new Set(this.mounts.tmIds)
|
|
82
|
-
const mountedGlossary = new Set(this.mounts.glossaryIds)
|
|
83
|
-
return {
|
|
84
|
-
tm: this.tmLibraries.map((library) => ({
|
|
85
|
-
...library,
|
|
86
|
-
mounted: mountedTm.has(library.tmId),
|
|
87
|
-
entryCount: this.tm.filter((entry) => entry.tmId === library.tmId).length,
|
|
88
|
-
})),
|
|
89
|
-
glossary: this.glossaryLibraries.map((library) => ({
|
|
90
|
-
...library,
|
|
91
|
-
mounted: mountedGlossary.has(library.glossaryId),
|
|
92
|
-
entryCount: this.glossary.filter((entry) => entry.glossaryId === library.glossaryId).length,
|
|
93
|
-
})),
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
,
|
|
97
|
-
createLibrary({ kind, name } = {}) {
|
|
98
|
-
const libraryKind = String(kind ?? '').trim()
|
|
99
|
-
const stamp = now()
|
|
100
|
-
if (libraryKind === 'tm') {
|
|
101
|
-
const library = {
|
|
102
|
-
tmId: makeId('tm'),
|
|
103
|
-
name: cleanLibraryName(name, 'Untitled TM'),
|
|
104
|
-
createdAt: stamp,
|
|
105
|
-
updatedAt: stamp,
|
|
106
|
-
}
|
|
107
|
-
this.tmLibraries.push(library)
|
|
108
|
-
this.mounts.tmIds = [...new Set([...this.mounts.tmIds, library.tmId])]
|
|
109
|
-
this.touch()
|
|
110
|
-
this.persist()
|
|
111
|
-
return {
|
|
112
|
-
library: this.librariesView().tm.find((item) => item.tmId === library.tmId),
|
|
113
|
-
mounts: this.mountsView(),
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
if (libraryKind === 'glossary') {
|
|
117
|
-
const library = {
|
|
118
|
-
glossaryId: makeId('gl'),
|
|
119
|
-
name: cleanLibraryName(name, 'Untitled glossary'),
|
|
120
|
-
createdAt: stamp,
|
|
121
|
-
updatedAt: stamp,
|
|
122
|
-
}
|
|
123
|
-
this.glossaryLibraries.push(library)
|
|
124
|
-
this.mounts.glossaryIds = [
|
|
125
|
-
...new Set([...this.mounts.glossaryIds, library.glossaryId]),
|
|
126
|
-
]
|
|
127
|
-
this.touch()
|
|
128
|
-
this.persist()
|
|
129
|
-
return {
|
|
130
|
-
library: this.librariesView().glossary.find(
|
|
131
|
-
(item) => item.glossaryId === library.glossaryId,
|
|
132
|
-
),
|
|
133
|
-
mounts: this.mountsView(),
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
throw new CatError('INVALID_LIBRARY_KIND', '库类型必须是 tm 或 glossary')
|
|
137
|
-
}
|
|
138
|
-
,
|
|
139
|
-
setMounts({ tmIds, glossaryIds, defaultTmId, defaultGlossaryId } = {}) {
|
|
140
|
-
if (tmIds !== undefined && !Array.isArray(tmIds)) {
|
|
141
|
-
throw new CatError('INVALID_TM_MOUNT', 'tmIds 必须是数组。')
|
|
142
|
-
}
|
|
143
|
-
if (glossaryIds !== undefined && !Array.isArray(glossaryIds)) {
|
|
144
|
-
throw new CatError('INVALID_GLOSSARY_MOUNT', 'glossaryIds 必须是数组。')
|
|
145
|
-
}
|
|
146
|
-
const nextTmIds =
|
|
147
|
-
tmIds === undefined
|
|
148
|
-
? [...this.mounts.tmIds]
|
|
149
|
-
: [...new Set(tmIds.filter((id) => typeof id === 'string' && id))]
|
|
150
|
-
const nextGlossaryIds =
|
|
151
|
-
glossaryIds === undefined
|
|
152
|
-
? [...this.mounts.glossaryIds]
|
|
153
|
-
: [...new Set(glossaryIds.filter((id) => typeof id === 'string' && id))]
|
|
154
|
-
|
|
155
|
-
if (!nextTmIds.length) throw new CatError('EMPTY_TM_MOUNT', '至少挂载一个翻译记忆库。')
|
|
156
|
-
if (!nextGlossaryIds.length) throw new CatError('EMPTY_GLOSSARY_MOUNT', '至少挂载一个术语库。')
|
|
157
|
-
for (const id of nextTmIds) this.requireTmLibrary(id)
|
|
158
|
-
for (const id of nextGlossaryIds) this.requireGlossaryLibrary(id)
|
|
159
|
-
|
|
160
|
-
let nextDefaultTmId = defaultTmId === undefined ? this.mounts.defaultTmId : defaultTmId
|
|
161
|
-
let nextDefaultGlossaryId =
|
|
162
|
-
defaultGlossaryId === undefined ? this.mounts.defaultGlossaryId : defaultGlossaryId
|
|
163
|
-
if (!nextTmIds.includes(nextDefaultTmId)) {
|
|
164
|
-
if (defaultTmId === undefined) nextDefaultTmId = nextTmIds[0]
|
|
165
|
-
else throw new CatError('DEFAULT_TM_NOT_MOUNTED', '默认翻译记忆库必须处于挂载状态。')
|
|
166
|
-
}
|
|
167
|
-
if (!nextGlossaryIds.includes(nextDefaultGlossaryId)) {
|
|
168
|
-
if (defaultGlossaryId === undefined) nextDefaultGlossaryId = nextGlossaryIds[0]
|
|
169
|
-
else throw new CatError('DEFAULT_GLOSSARY_NOT_MOUNTED', '默认术语库必须处于挂载状态。')
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
this.mounts = {
|
|
173
|
-
tmIds: nextTmIds,
|
|
174
|
-
glossaryIds: nextGlossaryIds,
|
|
175
|
-
defaultTmId: nextDefaultTmId,
|
|
176
|
-
defaultGlossaryId: nextDefaultGlossaryId,
|
|
177
|
-
}
|
|
178
|
-
this.touch()
|
|
179
|
-
this.persist()
|
|
180
|
-
return { mounts: this.mountsView(), libraries: this.librariesView() }
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
}
|
|
1
|
+
import { CatError } from './errors.js'
|
|
2
|
+
import { DEFAULT_GLOSSARY_ID, DEFAULT_GLOSSARY_NAME, DEFAULT_TM_ID, DEFAULT_TM_NAME, cleanLibraryName, makeId, now, restoredDate } from './store-utils.js'
|
|
3
|
+
|
|
4
|
+
export const libraryMethods = {
|
|
5
|
+
resetLibraryState() {
|
|
6
|
+
const stamp = now()
|
|
7
|
+
this.tmLibraries = [
|
|
8
|
+
{
|
|
9
|
+
tmId: DEFAULT_TM_ID,
|
|
10
|
+
name: DEFAULT_TM_NAME,
|
|
11
|
+
createdAt: stamp,
|
|
12
|
+
updatedAt: stamp,
|
|
13
|
+
},
|
|
14
|
+
]
|
|
15
|
+
this.glossaryLibraries = [
|
|
16
|
+
{
|
|
17
|
+
glossaryId: DEFAULT_GLOSSARY_ID,
|
|
18
|
+
name: DEFAULT_GLOSSARY_NAME,
|
|
19
|
+
createdAt: stamp,
|
|
20
|
+
updatedAt: stamp,
|
|
21
|
+
},
|
|
22
|
+
]
|
|
23
|
+
this.mounts = {
|
|
24
|
+
tmIds: [DEFAULT_TM_ID],
|
|
25
|
+
glossaryIds: [DEFAULT_GLOSSARY_ID],
|
|
26
|
+
defaultTmId: DEFAULT_TM_ID,
|
|
27
|
+
defaultGlossaryId: DEFAULT_GLOSSARY_ID,
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
,
|
|
31
|
+
requireTmLibrary(tmId) {
|
|
32
|
+
const id = String(tmId ?? '').trim() || this.mounts.defaultTmId
|
|
33
|
+
if (!this.tmLibraries.some((library) => library.tmId === id)) {
|
|
34
|
+
throw new CatError('TM_NOT_FOUND', `翻译记忆库不存在: ${id}`, 404)
|
|
35
|
+
}
|
|
36
|
+
return id
|
|
37
|
+
}
|
|
38
|
+
,
|
|
39
|
+
requireMountedTmLibrary(tmId) {
|
|
40
|
+
const id = this.requireTmLibrary(tmId)
|
|
41
|
+
if (!this.mounts.tmIds.includes(id)) {
|
|
42
|
+
throw new CatError(
|
|
43
|
+
'TM_NOT_MOUNTED',
|
|
44
|
+
`翻译记忆库未挂载: ${id},请先在 CAIT 的库面板挂载它。`,
|
|
45
|
+
409,
|
|
46
|
+
)
|
|
47
|
+
}
|
|
48
|
+
return id
|
|
49
|
+
}
|
|
50
|
+
,
|
|
51
|
+
requireGlossaryLibrary(glossaryId) {
|
|
52
|
+
const id = String(glossaryId ?? '').trim() || this.mounts.defaultGlossaryId
|
|
53
|
+
if (!this.glossaryLibraries.some((library) => library.glossaryId === id)) {
|
|
54
|
+
throw new CatError('GLOSSARY_NOT_FOUND', `术语库不存在: ${id}`, 404)
|
|
55
|
+
}
|
|
56
|
+
return id
|
|
57
|
+
}
|
|
58
|
+
,
|
|
59
|
+
requireMountedGlossaryLibrary(glossaryId) {
|
|
60
|
+
const id = this.requireGlossaryLibrary(glossaryId)
|
|
61
|
+
if (!this.mounts.glossaryIds.includes(id)) {
|
|
62
|
+
throw new CatError(
|
|
63
|
+
'GLOSSARY_NOT_MOUNTED',
|
|
64
|
+
`术语库未挂载: ${id},请先在 CAIT 的库面板挂载它。`,
|
|
65
|
+
409,
|
|
66
|
+
)
|
|
67
|
+
}
|
|
68
|
+
return id
|
|
69
|
+
}
|
|
70
|
+
,
|
|
71
|
+
mountsView() {
|
|
72
|
+
return {
|
|
73
|
+
tmIds: [...this.mounts.tmIds],
|
|
74
|
+
glossaryIds: [...this.mounts.glossaryIds],
|
|
75
|
+
defaultTmId: this.mounts.defaultTmId,
|
|
76
|
+
defaultGlossaryId: this.mounts.defaultGlossaryId,
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
,
|
|
80
|
+
librariesView() {
|
|
81
|
+
const mountedTm = new Set(this.mounts.tmIds)
|
|
82
|
+
const mountedGlossary = new Set(this.mounts.glossaryIds)
|
|
83
|
+
return {
|
|
84
|
+
tm: this.tmLibraries.map((library) => ({
|
|
85
|
+
...library,
|
|
86
|
+
mounted: mountedTm.has(library.tmId),
|
|
87
|
+
entryCount: this.tm.filter((entry) => entry.tmId === library.tmId).length,
|
|
88
|
+
})),
|
|
89
|
+
glossary: this.glossaryLibraries.map((library) => ({
|
|
90
|
+
...library,
|
|
91
|
+
mounted: mountedGlossary.has(library.glossaryId),
|
|
92
|
+
entryCount: this.glossary.filter((entry) => entry.glossaryId === library.glossaryId).length,
|
|
93
|
+
})),
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
,
|
|
97
|
+
createLibrary({ kind, name } = {}) {
|
|
98
|
+
const libraryKind = String(kind ?? '').trim()
|
|
99
|
+
const stamp = now()
|
|
100
|
+
if (libraryKind === 'tm') {
|
|
101
|
+
const library = {
|
|
102
|
+
tmId: makeId('tm'),
|
|
103
|
+
name: cleanLibraryName(name, 'Untitled TM'),
|
|
104
|
+
createdAt: stamp,
|
|
105
|
+
updatedAt: stamp,
|
|
106
|
+
}
|
|
107
|
+
this.tmLibraries.push(library)
|
|
108
|
+
this.mounts.tmIds = [...new Set([...this.mounts.tmIds, library.tmId])]
|
|
109
|
+
this.touch()
|
|
110
|
+
this.persist()
|
|
111
|
+
return {
|
|
112
|
+
library: this.librariesView().tm.find((item) => item.tmId === library.tmId),
|
|
113
|
+
mounts: this.mountsView(),
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
if (libraryKind === 'glossary') {
|
|
117
|
+
const library = {
|
|
118
|
+
glossaryId: makeId('gl'),
|
|
119
|
+
name: cleanLibraryName(name, 'Untitled glossary'),
|
|
120
|
+
createdAt: stamp,
|
|
121
|
+
updatedAt: stamp,
|
|
122
|
+
}
|
|
123
|
+
this.glossaryLibraries.push(library)
|
|
124
|
+
this.mounts.glossaryIds = [
|
|
125
|
+
...new Set([...this.mounts.glossaryIds, library.glossaryId]),
|
|
126
|
+
]
|
|
127
|
+
this.touch()
|
|
128
|
+
this.persist()
|
|
129
|
+
return {
|
|
130
|
+
library: this.librariesView().glossary.find(
|
|
131
|
+
(item) => item.glossaryId === library.glossaryId,
|
|
132
|
+
),
|
|
133
|
+
mounts: this.mountsView(),
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
throw new CatError('INVALID_LIBRARY_KIND', '库类型必须是 tm 或 glossary')
|
|
137
|
+
}
|
|
138
|
+
,
|
|
139
|
+
setMounts({ tmIds, glossaryIds, defaultTmId, defaultGlossaryId } = {}) {
|
|
140
|
+
if (tmIds !== undefined && !Array.isArray(tmIds)) {
|
|
141
|
+
throw new CatError('INVALID_TM_MOUNT', 'tmIds 必须是数组。')
|
|
142
|
+
}
|
|
143
|
+
if (glossaryIds !== undefined && !Array.isArray(glossaryIds)) {
|
|
144
|
+
throw new CatError('INVALID_GLOSSARY_MOUNT', 'glossaryIds 必须是数组。')
|
|
145
|
+
}
|
|
146
|
+
const nextTmIds =
|
|
147
|
+
tmIds === undefined
|
|
148
|
+
? [...this.mounts.tmIds]
|
|
149
|
+
: [...new Set(tmIds.filter((id) => typeof id === 'string' && id))]
|
|
150
|
+
const nextGlossaryIds =
|
|
151
|
+
glossaryIds === undefined
|
|
152
|
+
? [...this.mounts.glossaryIds]
|
|
153
|
+
: [...new Set(glossaryIds.filter((id) => typeof id === 'string' && id))]
|
|
154
|
+
|
|
155
|
+
if (!nextTmIds.length) throw new CatError('EMPTY_TM_MOUNT', '至少挂载一个翻译记忆库。')
|
|
156
|
+
if (!nextGlossaryIds.length) throw new CatError('EMPTY_GLOSSARY_MOUNT', '至少挂载一个术语库。')
|
|
157
|
+
for (const id of nextTmIds) this.requireTmLibrary(id)
|
|
158
|
+
for (const id of nextGlossaryIds) this.requireGlossaryLibrary(id)
|
|
159
|
+
|
|
160
|
+
let nextDefaultTmId = defaultTmId === undefined ? this.mounts.defaultTmId : defaultTmId
|
|
161
|
+
let nextDefaultGlossaryId =
|
|
162
|
+
defaultGlossaryId === undefined ? this.mounts.defaultGlossaryId : defaultGlossaryId
|
|
163
|
+
if (!nextTmIds.includes(nextDefaultTmId)) {
|
|
164
|
+
if (defaultTmId === undefined) nextDefaultTmId = nextTmIds[0]
|
|
165
|
+
else throw new CatError('DEFAULT_TM_NOT_MOUNTED', '默认翻译记忆库必须处于挂载状态。')
|
|
166
|
+
}
|
|
167
|
+
if (!nextGlossaryIds.includes(nextDefaultGlossaryId)) {
|
|
168
|
+
if (defaultGlossaryId === undefined) nextDefaultGlossaryId = nextGlossaryIds[0]
|
|
169
|
+
else throw new CatError('DEFAULT_GLOSSARY_NOT_MOUNTED', '默认术语库必须处于挂载状态。')
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
this.mounts = {
|
|
173
|
+
tmIds: nextTmIds,
|
|
174
|
+
glossaryIds: nextGlossaryIds,
|
|
175
|
+
defaultTmId: nextDefaultTmId,
|
|
176
|
+
defaultGlossaryId: nextDefaultGlossaryId,
|
|
177
|
+
}
|
|
178
|
+
this.touch()
|
|
179
|
+
this.persist()
|
|
180
|
+
return { mounts: this.mountsView(), libraries: this.librariesView() }
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
}
|
package/lib/markdown.js
CHANGED
|
@@ -1,28 +1,28 @@
|
|
|
1
|
-
/** Markdown → translatable plain text. Keeps prose, drops formatting noise. */
|
|
2
|
-
|
|
3
|
-
export function stripMarkdown(input) {
|
|
4
|
-
return String(input ?? '')
|
|
5
|
-
.replace(/\r\n?/g, '\n')
|
|
6
|
-
.replace(/<!--[\s\S]*?-->/g, '')
|
|
7
|
-
.replace(/```[^\n]*\n?([\s\S]*?)```/g, '$1')
|
|
8
|
-
.replace(/~~~[^\n]*\n?([\s\S]*?)~~~/g, '$1')
|
|
9
|
-
.replace(/!\[([^\]]*)\]\([^)]*\)/g, '$1')
|
|
10
|
-
.replace(/\[([^\]]+)\]\([^)]*\)/g, '$1')
|
|
11
|
-
.replace(/\[([^\]]+)\]\[[^\]]*\]/g, '$1')
|
|
12
|
-
.replace(/^\s{0,3}#{1,6}\s+/gm, '')
|
|
13
|
-
.replace(/^\s{0,3}>\s?/gm, '')
|
|
14
|
-
.replace(/^\s*[-*+]\s+/gm, '')
|
|
15
|
-
.replace(/^\s*\d+[.)]\s+/gm, '')
|
|
16
|
-
.replace(/^\s*\|?[\s:|-]+\|?\s*$/gm, '')
|
|
17
|
-
.replace(/`([^`]+)`/g, '$1')
|
|
18
|
-
.replace(/\*\*([^*]+)\*\*/g, '$1')
|
|
19
|
-
.replace(/__([^_]+)__/g, '$1')
|
|
20
|
-
.replace(/\*([^*\n]+)\*/g, '$1')
|
|
21
|
-
.replace(/(^|[\s(])_([^_\n]+)_(?=[\s).,;:!?]|$)/g, '$1$2')
|
|
22
|
-
.replace(/~~([^~]+)~~/g, '$1')
|
|
23
|
-
.replace(/<[^>]+>/g, '')
|
|
24
|
-
.replace(/\|/g, ' ')
|
|
25
|
-
.replace(/[ \t]+$/gm, '')
|
|
26
|
-
.replace(/\n{3,}/g, '\n\n')
|
|
27
|
-
.trim()
|
|
28
|
-
}
|
|
1
|
+
/** Markdown → translatable plain text. Keeps prose, drops formatting noise. */
|
|
2
|
+
|
|
3
|
+
export function stripMarkdown(input) {
|
|
4
|
+
return String(input ?? '')
|
|
5
|
+
.replace(/\r\n?/g, '\n')
|
|
6
|
+
.replace(/<!--[\s\S]*?-->/g, '')
|
|
7
|
+
.replace(/```[^\n]*\n?([\s\S]*?)```/g, '$1')
|
|
8
|
+
.replace(/~~~[^\n]*\n?([\s\S]*?)~~~/g, '$1')
|
|
9
|
+
.replace(/!\[([^\]]*)\]\([^)]*\)/g, '$1')
|
|
10
|
+
.replace(/\[([^\]]+)\]\([^)]*\)/g, '$1')
|
|
11
|
+
.replace(/\[([^\]]+)\]\[[^\]]*\]/g, '$1')
|
|
12
|
+
.replace(/^\s{0,3}#{1,6}\s+/gm, '')
|
|
13
|
+
.replace(/^\s{0,3}>\s?/gm, '')
|
|
14
|
+
.replace(/^\s*[-*+]\s+/gm, '')
|
|
15
|
+
.replace(/^\s*\d+[.)]\s+/gm, '')
|
|
16
|
+
.replace(/^\s*\|?[\s:|-]+\|?\s*$/gm, '')
|
|
17
|
+
.replace(/`([^`]+)`/g, '$1')
|
|
18
|
+
.replace(/\*\*([^*]+)\*\*/g, '$1')
|
|
19
|
+
.replace(/__([^_]+)__/g, '$1')
|
|
20
|
+
.replace(/\*([^*\n]+)\*/g, '$1')
|
|
21
|
+
.replace(/(^|[\s(])_([^_\n]+)_(?=[\s).,;:!?]|$)/g, '$1$2')
|
|
22
|
+
.replace(/~~([^~]+)~~/g, '$1')
|
|
23
|
+
.replace(/<[^>]+>/g, '')
|
|
24
|
+
.replace(/\|/g, ' ')
|
|
25
|
+
.replace(/[ \t]+$/gm, '')
|
|
26
|
+
.replace(/\n{3,}/g, '\n\n')
|
|
27
|
+
.trim()
|
|
28
|
+
}
|