@ssml-builder-js/ssml-editor-elements 2.4.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/CHANGELOG.md +45 -0
- package/dist/index.d.mts +72 -0
- package/dist/index.d.ts +72 -0
- package/dist/index.js +3822 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +3790 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +42 -0
- package/src/SsmlEditorElement.ts +1084 -0
- package/src/index.ts +12 -0
- package/tsconfig.json +21 -0
- package/tsup.config.ts +14 -0
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,3790 @@
|
|
|
1
|
+
var __defProp = Object.defineProperty;
|
|
2
|
+
var __export = (target, all) => {
|
|
3
|
+
for (var name in all)
|
|
4
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
5
|
+
};
|
|
6
|
+
|
|
7
|
+
// src/SsmlEditorElement.ts
|
|
8
|
+
import { buildSsml as buildSsml2, parseSsml as parseSsml2 } from "@ssml-builder-js/ssml-core";
|
|
9
|
+
|
|
10
|
+
// ../ssml-editor-react/src/clearSsmlDocument.ts
|
|
11
|
+
function getDocumentChildren(document2) {
|
|
12
|
+
return document2.children ?? (document2.content === void 0 ? [] : [document2.content]);
|
|
13
|
+
}
|
|
14
|
+
function appendNode(nodes, node) {
|
|
15
|
+
if (typeof node === "string") {
|
|
16
|
+
const lastNode = nodes[nodes.length - 1];
|
|
17
|
+
if (typeof lastNode === "string") {
|
|
18
|
+
nodes[nodes.length - 1] = lastNode + node;
|
|
19
|
+
} else if (node !== "") {
|
|
20
|
+
nodes.push(node);
|
|
21
|
+
}
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
nodes.push(node);
|
|
25
|
+
}
|
|
26
|
+
function clearNodes(nodes) {
|
|
27
|
+
const clearedNodes = [];
|
|
28
|
+
for (const node of nodes) {
|
|
29
|
+
if (typeof node === "string") {
|
|
30
|
+
appendNode(clearedNodes, node);
|
|
31
|
+
continue;
|
|
32
|
+
}
|
|
33
|
+
if (node.type === "text") {
|
|
34
|
+
appendNode(clearedNodes, node.value);
|
|
35
|
+
continue;
|
|
36
|
+
}
|
|
37
|
+
const children = clearNodes(node.children ?? []);
|
|
38
|
+
if (node.type === "voice") {
|
|
39
|
+
appendNode(clearedNodes, { ...node, children });
|
|
40
|
+
continue;
|
|
41
|
+
}
|
|
42
|
+
for (const child of children) {
|
|
43
|
+
appendNode(clearedNodes, child);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return clearedNodes;
|
|
47
|
+
}
|
|
48
|
+
function clearSsmlDocument(document2) {
|
|
49
|
+
const nextDocument = {
|
|
50
|
+
...document2,
|
|
51
|
+
children: clearNodes(getDocumentChildren(document2))
|
|
52
|
+
};
|
|
53
|
+
if (nextDocument.content !== void 0) {
|
|
54
|
+
delete nextDocument.content;
|
|
55
|
+
}
|
|
56
|
+
return nextDocument;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// ../ssml-editor-react/src/editableSsml.ts
|
|
60
|
+
import { buildSsml, parseSsml } from "@ssml-builder-js/ssml-core";
|
|
61
|
+
|
|
62
|
+
// ../ssml-editor-react/src/formatXml.ts
|
|
63
|
+
var INDENT = " ";
|
|
64
|
+
var FRAGMENT_ROOT = "ssml-builder-fragment";
|
|
65
|
+
var XML_ENTITY_NAMES = /* @__PURE__ */ new Set(["amp", "apos", "gt", "lt", "quot"]);
|
|
66
|
+
var INTRINSICALLY_EMPTY_ELEMENTS = /* @__PURE__ */ new Set([
|
|
67
|
+
"break",
|
|
68
|
+
"bookmark",
|
|
69
|
+
"lexicon",
|
|
70
|
+
"mark",
|
|
71
|
+
"mstts:silence",
|
|
72
|
+
"mstts:viseme",
|
|
73
|
+
"silence",
|
|
74
|
+
"viseme"
|
|
75
|
+
]);
|
|
76
|
+
function isXmlNameStart(value) {
|
|
77
|
+
return value !== void 0 && /[A-Za-z_]/.test(value);
|
|
78
|
+
}
|
|
79
|
+
function isXmlNameCharacter(value) {
|
|
80
|
+
return value !== void 0 && /[A-Za-z0-9_.:-]/.test(value);
|
|
81
|
+
}
|
|
82
|
+
function isXmlWhitespace(value) {
|
|
83
|
+
return value === " " || value === " " || value === "\r" || value === "\n";
|
|
84
|
+
}
|
|
85
|
+
function fail(message) {
|
|
86
|
+
throw new Error(message);
|
|
87
|
+
}
|
|
88
|
+
function skipWhitespace(source, index) {
|
|
89
|
+
while (isXmlWhitespace(source[index])) {
|
|
90
|
+
index += 1;
|
|
91
|
+
}
|
|
92
|
+
return index;
|
|
93
|
+
}
|
|
94
|
+
function readName(source, start, end) {
|
|
95
|
+
if (!isXmlNameStart(source[start])) {
|
|
96
|
+
fail("Invalid XML name");
|
|
97
|
+
}
|
|
98
|
+
let index = start + 1;
|
|
99
|
+
while (index < end && isXmlNameCharacter(source[index])) {
|
|
100
|
+
index += 1;
|
|
101
|
+
}
|
|
102
|
+
return { name: source.slice(start, index), index };
|
|
103
|
+
}
|
|
104
|
+
function validateCharacterReference(entity) {
|
|
105
|
+
const isHexadecimal = entity.startsWith("#x") || entity.startsWith("#X");
|
|
106
|
+
const isDecimal = entity.startsWith("#");
|
|
107
|
+
if (!isHexadecimal && !isDecimal) {
|
|
108
|
+
if (!XML_ENTITY_NAMES.has(entity)) {
|
|
109
|
+
fail(`Unknown XML entity: &${entity};`);
|
|
110
|
+
}
|
|
111
|
+
return;
|
|
112
|
+
}
|
|
113
|
+
const digits = entity.slice(isHexadecimal ? 2 : 1);
|
|
114
|
+
const validDigits = isHexadecimal ? /^[0-9A-Fa-f]+$/.test(digits) : /^[0-9]+$/.test(digits);
|
|
115
|
+
const codePoint = Number.parseInt(digits, isHexadecimal ? 16 : 10);
|
|
116
|
+
if (!validDigits || !Number.isInteger(codePoint) || codePoint < 0 || codePoint > 1114111 || codePoint >= 55296 && codePoint <= 57343 || codePoint < 32 && ![9, 10, 13].includes(codePoint)) {
|
|
117
|
+
fail(`Invalid XML character reference: &${entity};`);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
function validateEntityReferences(value) {
|
|
121
|
+
let index = 0;
|
|
122
|
+
while (true) {
|
|
123
|
+
const ampersand = value.indexOf("&", index);
|
|
124
|
+
if (ampersand === -1) {
|
|
125
|
+
return;
|
|
126
|
+
}
|
|
127
|
+
const semicolon = value.indexOf(";", ampersand + 1);
|
|
128
|
+
if (semicolon === -1) {
|
|
129
|
+
fail("Unterminated XML entity reference");
|
|
130
|
+
}
|
|
131
|
+
validateCharacterReference(value.slice(ampersand + 1, semicolon));
|
|
132
|
+
index = semicolon + 1;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
function findTagEnd(source, start, hasInternalSubset = false) {
|
|
136
|
+
let quote;
|
|
137
|
+
let subsetDepth = 0;
|
|
138
|
+
for (let index = start + 1; index < source.length; index += 1) {
|
|
139
|
+
const character = source[index];
|
|
140
|
+
if (quote !== void 0) {
|
|
141
|
+
if (character === quote) {
|
|
142
|
+
quote = void 0;
|
|
143
|
+
}
|
|
144
|
+
continue;
|
|
145
|
+
}
|
|
146
|
+
if (character === '"' || character === "'") {
|
|
147
|
+
quote = character;
|
|
148
|
+
continue;
|
|
149
|
+
}
|
|
150
|
+
if (hasInternalSubset) {
|
|
151
|
+
if (character === "[") {
|
|
152
|
+
subsetDepth += 1;
|
|
153
|
+
continue;
|
|
154
|
+
}
|
|
155
|
+
if (character === "]" && subsetDepth > 0) {
|
|
156
|
+
subsetDepth -= 1;
|
|
157
|
+
continue;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
if (character === ">" && subsetDepth === 0) {
|
|
161
|
+
return index;
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
fail("Unclosed XML markup");
|
|
165
|
+
}
|
|
166
|
+
function parseStartTag(source, start, end) {
|
|
167
|
+
const nameResult = readName(source, start + 1, end);
|
|
168
|
+
let index = nameResult.index;
|
|
169
|
+
let hasAttribute = false;
|
|
170
|
+
const attributeNames = /* @__PURE__ */ new Set();
|
|
171
|
+
while (index < end) {
|
|
172
|
+
const beforeWhitespace = index;
|
|
173
|
+
index = skipWhitespace(source, index);
|
|
174
|
+
if (index === end) {
|
|
175
|
+
break;
|
|
176
|
+
}
|
|
177
|
+
if (source[index] === "/") {
|
|
178
|
+
if (index + 1 !== end) {
|
|
179
|
+
fail("Invalid XML self-closing tag");
|
|
180
|
+
}
|
|
181
|
+
return { name: nameResult.name, selfClosing: true };
|
|
182
|
+
}
|
|
183
|
+
if (hasAttribute && beforeWhitespace === index) {
|
|
184
|
+
fail("XML attributes must be separated by whitespace");
|
|
185
|
+
}
|
|
186
|
+
const attribute = readName(source, index, end);
|
|
187
|
+
index = skipWhitespace(source, attribute.index);
|
|
188
|
+
if (source[index] !== "=") {
|
|
189
|
+
fail(`XML attribute ${attribute.name} must have a value`);
|
|
190
|
+
}
|
|
191
|
+
index = skipWhitespace(source, index + 1);
|
|
192
|
+
const quote = source[index];
|
|
193
|
+
if (quote !== '"' && quote !== "'") {
|
|
194
|
+
fail(`XML attribute ${attribute.name} must use a quoted value`);
|
|
195
|
+
}
|
|
196
|
+
index += 1;
|
|
197
|
+
const valueStart = index;
|
|
198
|
+
while (index < end && source[index] !== quote) {
|
|
199
|
+
if (source[index] === "<") {
|
|
200
|
+
fail(`Invalid "<" in XML attribute ${attribute.name}`);
|
|
201
|
+
}
|
|
202
|
+
index += 1;
|
|
203
|
+
}
|
|
204
|
+
if (index === end) {
|
|
205
|
+
fail(`Unclosed XML attribute ${attribute.name}`);
|
|
206
|
+
}
|
|
207
|
+
if (attributeNames.has(attribute.name)) {
|
|
208
|
+
fail(`Duplicate XML attribute: ${attribute.name}`);
|
|
209
|
+
}
|
|
210
|
+
attributeNames.add(attribute.name);
|
|
211
|
+
validateEntityReferences(source.slice(valueStart, index));
|
|
212
|
+
index += 1;
|
|
213
|
+
hasAttribute = true;
|
|
214
|
+
}
|
|
215
|
+
return { name: nameResult.name, selfClosing: false };
|
|
216
|
+
}
|
|
217
|
+
function parseClosingTag(source, start, end) {
|
|
218
|
+
const nameResult = readName(source, start + 2, end);
|
|
219
|
+
if (skipWhitespace(source, nameResult.index) !== end) {
|
|
220
|
+
fail("Invalid XML closing tag");
|
|
221
|
+
}
|
|
222
|
+
return nameResult.name;
|
|
223
|
+
}
|
|
224
|
+
function parseProcessingInstruction(source, start, end) {
|
|
225
|
+
readName(source, start + 2, end);
|
|
226
|
+
}
|
|
227
|
+
function parseDeclaration(source, start, end) {
|
|
228
|
+
readName(source, start + 2, end);
|
|
229
|
+
}
|
|
230
|
+
function appendNode2(nodes, node) {
|
|
231
|
+
const previous = nodes[nodes.length - 1];
|
|
232
|
+
if (node.kind === "text" && previous?.kind === "text") {
|
|
233
|
+
previous.value += node.value;
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
236
|
+
nodes.push(node);
|
|
237
|
+
}
|
|
238
|
+
function currentElement(stack) {
|
|
239
|
+
return stack[stack.length - 1];
|
|
240
|
+
}
|
|
241
|
+
function parseXml(source) {
|
|
242
|
+
const children = [];
|
|
243
|
+
const stack = [];
|
|
244
|
+
let root;
|
|
245
|
+
let index = 0;
|
|
246
|
+
while (index < source.length) {
|
|
247
|
+
if (source[index] !== "<") {
|
|
248
|
+
const textStart = index;
|
|
249
|
+
while (index < source.length && source[index] !== "<") {
|
|
250
|
+
index += 1;
|
|
251
|
+
}
|
|
252
|
+
const value = source.slice(textStart, index);
|
|
253
|
+
if (value.includes("]]>")) {
|
|
254
|
+
fail("CDATA termination is not valid in ordinary XML text");
|
|
255
|
+
}
|
|
256
|
+
validateEntityReferences(value);
|
|
257
|
+
if (stack.length === 0 && value.trim() !== "") {
|
|
258
|
+
fail("Unexpected text outside the root XML element");
|
|
259
|
+
}
|
|
260
|
+
appendNode2(currentElement(stack)?.children ?? children, { kind: "text", value });
|
|
261
|
+
continue;
|
|
262
|
+
}
|
|
263
|
+
if (source.startsWith("<!--", index)) {
|
|
264
|
+
const end2 = source.indexOf("-->", index + 4);
|
|
265
|
+
if (end2 === -1) {
|
|
266
|
+
fail("Unclosed XML comment");
|
|
267
|
+
}
|
|
268
|
+
const content = source.slice(index + 4, end2);
|
|
269
|
+
if (content.includes("--") || content.endsWith("-")) {
|
|
270
|
+
fail("Invalid XML comment");
|
|
271
|
+
}
|
|
272
|
+
appendNode2(currentElement(stack)?.children ?? children, {
|
|
273
|
+
kind: "comment",
|
|
274
|
+
raw: source.slice(index, end2 + 3)
|
|
275
|
+
});
|
|
276
|
+
index = end2 + 3;
|
|
277
|
+
continue;
|
|
278
|
+
}
|
|
279
|
+
if (source.startsWith("<![CDATA[", index)) {
|
|
280
|
+
const end2 = source.indexOf("]]>", index + "<![CDATA[".length);
|
|
281
|
+
if (end2 === -1) {
|
|
282
|
+
fail("Unclosed XML CDATA section");
|
|
283
|
+
}
|
|
284
|
+
if (stack.length === 0) {
|
|
285
|
+
fail("CDATA is not allowed outside the root XML element");
|
|
286
|
+
}
|
|
287
|
+
appendNode2(currentElement(stack)?.children ?? children, {
|
|
288
|
+
kind: "cdata",
|
|
289
|
+
raw: source.slice(index, end2 + 3)
|
|
290
|
+
});
|
|
291
|
+
index = end2 + 3;
|
|
292
|
+
continue;
|
|
293
|
+
}
|
|
294
|
+
if (source.startsWith("<?", index)) {
|
|
295
|
+
const end2 = source.indexOf("?>", index + 2);
|
|
296
|
+
if (end2 === -1) {
|
|
297
|
+
fail("Unclosed XML processing instruction");
|
|
298
|
+
}
|
|
299
|
+
parseProcessingInstruction(source, index, end2);
|
|
300
|
+
appendNode2(currentElement(stack)?.children ?? children, {
|
|
301
|
+
kind: "processing-instruction",
|
|
302
|
+
raw: source.slice(index, end2 + 2)
|
|
303
|
+
});
|
|
304
|
+
index = end2 + 2;
|
|
305
|
+
continue;
|
|
306
|
+
}
|
|
307
|
+
if (source.startsWith("</", index)) {
|
|
308
|
+
const end2 = findTagEnd(source, index);
|
|
309
|
+
const name2 = parseClosingTag(source, index, end2);
|
|
310
|
+
const element = currentElement(stack);
|
|
311
|
+
if (element === void 0 || element.name !== name2) {
|
|
312
|
+
fail(`Mismatched closing XML element: </${name2}>`);
|
|
313
|
+
}
|
|
314
|
+
element.close = source.slice(index, end2 + 1);
|
|
315
|
+
stack.pop();
|
|
316
|
+
index = end2 + 1;
|
|
317
|
+
continue;
|
|
318
|
+
}
|
|
319
|
+
if (source.startsWith("<!", index)) {
|
|
320
|
+
const end2 = findTagEnd(source, index, true);
|
|
321
|
+
parseDeclaration(source, index, end2);
|
|
322
|
+
appendNode2(currentElement(stack)?.children ?? children, {
|
|
323
|
+
kind: "declaration",
|
|
324
|
+
raw: source.slice(index, end2 + 1)
|
|
325
|
+
});
|
|
326
|
+
index = end2 + 1;
|
|
327
|
+
continue;
|
|
328
|
+
}
|
|
329
|
+
const end = findTagEnd(source, index);
|
|
330
|
+
const { name, selfClosing } = parseStartTag(source, index, end);
|
|
331
|
+
if (stack.length === 0) {
|
|
332
|
+
if (root !== void 0) {
|
|
333
|
+
fail("Multiple root XML elements are not allowed");
|
|
334
|
+
}
|
|
335
|
+
root = {
|
|
336
|
+
kind: "element",
|
|
337
|
+
name,
|
|
338
|
+
open: source.slice(index, end + 1),
|
|
339
|
+
selfClosing,
|
|
340
|
+
children: []
|
|
341
|
+
};
|
|
342
|
+
children.push(root);
|
|
343
|
+
} else {
|
|
344
|
+
const element = {
|
|
345
|
+
kind: "element",
|
|
346
|
+
name,
|
|
347
|
+
open: source.slice(index, end + 1),
|
|
348
|
+
selfClosing,
|
|
349
|
+
children: []
|
|
350
|
+
};
|
|
351
|
+
currentElement(stack)?.children.push(element);
|
|
352
|
+
if (!selfClosing) {
|
|
353
|
+
stack.push(element);
|
|
354
|
+
}
|
|
355
|
+
index = end + 1;
|
|
356
|
+
continue;
|
|
357
|
+
}
|
|
358
|
+
if (!selfClosing) {
|
|
359
|
+
stack.push(root);
|
|
360
|
+
}
|
|
361
|
+
index = end + 1;
|
|
362
|
+
}
|
|
363
|
+
if (stack.length > 0) {
|
|
364
|
+
fail(`Unclosed XML element: <${currentElement(stack)?.name}>`);
|
|
365
|
+
}
|
|
366
|
+
if (root === void 0) {
|
|
367
|
+
fail("XML input does not contain a root element");
|
|
368
|
+
}
|
|
369
|
+
return { children, root };
|
|
370
|
+
}
|
|
371
|
+
function indentation(depth) {
|
|
372
|
+
return INDENT.repeat(depth);
|
|
373
|
+
}
|
|
374
|
+
function renderInline(node) {
|
|
375
|
+
const content = node.children.map((child) => {
|
|
376
|
+
if (child.kind === "element") {
|
|
377
|
+
return renderInline(child);
|
|
378
|
+
}
|
|
379
|
+
return child.kind === "text" ? child.value : child.raw;
|
|
380
|
+
}).join("");
|
|
381
|
+
return `${node.open}${content}${node.close ?? ""}`;
|
|
382
|
+
}
|
|
383
|
+
function hasOnlyTextChildren(node) {
|
|
384
|
+
return node.children.every((child) => child.kind === "text");
|
|
385
|
+
}
|
|
386
|
+
function hasSignificantText(node) {
|
|
387
|
+
return node.children.some((child) => child.kind === "text" && child.value.trim() !== "");
|
|
388
|
+
}
|
|
389
|
+
function hasOnlyWhitespaceText(node) {
|
|
390
|
+
return node.children.every((child) => child.kind === "text" && child.value.trim() === "");
|
|
391
|
+
}
|
|
392
|
+
function toSelfClosingTag(open) {
|
|
393
|
+
return `${open.slice(0, -1).trimEnd()}/>`;
|
|
394
|
+
}
|
|
395
|
+
function formatElement(node, depth, isRoot) {
|
|
396
|
+
const prefix = indentation(depth);
|
|
397
|
+
if (node.selfClosing) {
|
|
398
|
+
return [`${prefix}${node.open}`];
|
|
399
|
+
}
|
|
400
|
+
if (node.close === void 0) {
|
|
401
|
+
fail(`Unclosed XML element: <${node.name}>`);
|
|
402
|
+
}
|
|
403
|
+
if (INTRINSICALLY_EMPTY_ELEMENTS.has(node.name) && hasOnlyWhitespaceText(node)) {
|
|
404
|
+
return [`${prefix}${toSelfClosingTag(node.open)}`];
|
|
405
|
+
}
|
|
406
|
+
if (isRoot && hasOnlyTextChildren(node)) {
|
|
407
|
+
const text = node.children.filter((child) => child.kind === "text").map((child) => child.value).join("");
|
|
408
|
+
const trimmedText = text.trim();
|
|
409
|
+
if (trimmedText === "") {
|
|
410
|
+
return [`${prefix}${node.open}`, `${prefix}${node.close}`];
|
|
411
|
+
}
|
|
412
|
+
if (text.includes("\n") || text.includes("\r") || text !== trimmedText) {
|
|
413
|
+
return [`${prefix}${renderInline(node)}`];
|
|
414
|
+
}
|
|
415
|
+
return [`${prefix}${node.open}`, `${indentation(depth + 1)}${trimmedText}`, `${prefix}${node.close}`];
|
|
416
|
+
}
|
|
417
|
+
if (hasSignificantText(node)) {
|
|
418
|
+
return [`${prefix}${renderInline(node)}`];
|
|
419
|
+
}
|
|
420
|
+
const lines = [`${prefix}${node.open}`];
|
|
421
|
+
for (const child of node.children) {
|
|
422
|
+
if (child.kind === "text") {
|
|
423
|
+
continue;
|
|
424
|
+
}
|
|
425
|
+
if (child.kind === "element") {
|
|
426
|
+
lines.push(...formatElement(child, depth + 1, false));
|
|
427
|
+
} else {
|
|
428
|
+
lines.push(`${indentation(depth + 1)}${child.raw}`);
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
lines.push(`${prefix}${node.close}`);
|
|
432
|
+
return lines;
|
|
433
|
+
}
|
|
434
|
+
function stripTrailingWhitespace(value) {
|
|
435
|
+
return value.replace(/[ \t]+$/gm, "");
|
|
436
|
+
}
|
|
437
|
+
function getTrailingLineBreaks(value) {
|
|
438
|
+
let start = value.length;
|
|
439
|
+
while (start > 0) {
|
|
440
|
+
if (value[start - 1] === "\n") {
|
|
441
|
+
start -= 1;
|
|
442
|
+
if (start > 0 && value[start - 1] === "\r") {
|
|
443
|
+
start -= 1;
|
|
444
|
+
}
|
|
445
|
+
continue;
|
|
446
|
+
}
|
|
447
|
+
if (value[start - 1] === "\r") {
|
|
448
|
+
start -= 1;
|
|
449
|
+
continue;
|
|
450
|
+
}
|
|
451
|
+
break;
|
|
452
|
+
}
|
|
453
|
+
return value.slice(start);
|
|
454
|
+
}
|
|
455
|
+
function stripTrailingLineBreaks(value) {
|
|
456
|
+
let end = value.length;
|
|
457
|
+
while (end > 0) {
|
|
458
|
+
if (value[end - 1] === "\n") {
|
|
459
|
+
end -= 1;
|
|
460
|
+
if (end > 0 && value[end - 1] === "\r") {
|
|
461
|
+
end -= 1;
|
|
462
|
+
}
|
|
463
|
+
continue;
|
|
464
|
+
}
|
|
465
|
+
if (value[end - 1] === "\r") {
|
|
466
|
+
end -= 1;
|
|
467
|
+
continue;
|
|
468
|
+
}
|
|
469
|
+
break;
|
|
470
|
+
}
|
|
471
|
+
return value.slice(0, end);
|
|
472
|
+
}
|
|
473
|
+
function preserveTrailingLineBreak(formatted, trailingLineBreaks) {
|
|
474
|
+
if (trailingLineBreaks === "") {
|
|
475
|
+
return formatted;
|
|
476
|
+
}
|
|
477
|
+
return `${stripTrailingLineBreaks(formatted)}${trailingLineBreaks}`;
|
|
478
|
+
}
|
|
479
|
+
function renderDocument(document2) {
|
|
480
|
+
const lines = [];
|
|
481
|
+
for (const child of document2.children) {
|
|
482
|
+
if (child.kind === "text") {
|
|
483
|
+
continue;
|
|
484
|
+
}
|
|
485
|
+
if (child.kind === "element") {
|
|
486
|
+
lines.push(...formatElement(child, 0, child === document2.root));
|
|
487
|
+
} else {
|
|
488
|
+
lines.push(child.raw);
|
|
489
|
+
}
|
|
490
|
+
}
|
|
491
|
+
return stripTrailingWhitespace(lines.join("\n")).trim();
|
|
492
|
+
}
|
|
493
|
+
function unwrapFormattedFragment(formatted) {
|
|
494
|
+
const opening = `<${FRAGMENT_ROOT}>`;
|
|
495
|
+
const closing = `</${FRAGMENT_ROOT}>`;
|
|
496
|
+
if (!formatted.startsWith(opening) || !formatted.endsWith(closing)) {
|
|
497
|
+
return void 0;
|
|
498
|
+
}
|
|
499
|
+
if (formatted === `${opening}${closing}`) {
|
|
500
|
+
return "";
|
|
501
|
+
}
|
|
502
|
+
const multilineOpening = `${opening}
|
|
503
|
+
`;
|
|
504
|
+
const multilineClosing = `
|
|
505
|
+
${closing}`;
|
|
506
|
+
if (formatted.startsWith(multilineOpening) && formatted.endsWith(multilineClosing)) {
|
|
507
|
+
const content = formatted.slice(multilineOpening.length, -multilineClosing.length);
|
|
508
|
+
return content.split("\n").map((line) => line.startsWith(INDENT) ? line.slice(INDENT.length) : line).join("\n");
|
|
509
|
+
}
|
|
510
|
+
return formatted.slice(opening.length, -closing.length);
|
|
511
|
+
}
|
|
512
|
+
function formatXmlFragment(xml) {
|
|
513
|
+
const trailingLineBreaks = getTrailingLineBreaks(xml);
|
|
514
|
+
const source = xml.trim();
|
|
515
|
+
if (source === "") {
|
|
516
|
+
return "";
|
|
517
|
+
}
|
|
518
|
+
const wrapped = `<${FRAGMENT_ROOT}>${source}</${FRAGMENT_ROOT}>`;
|
|
519
|
+
let formatted;
|
|
520
|
+
try {
|
|
521
|
+
formatted = renderDocument(parseXml(wrapped));
|
|
522
|
+
} catch {
|
|
523
|
+
return xml;
|
|
524
|
+
}
|
|
525
|
+
return preserveTrailingLineBreak(unwrapFormattedFragment(formatted) ?? xml, trailingLineBreaks);
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
// ../ssml-editor-react/src/editableSsml.ts
|
|
529
|
+
function isSsmlElement(node) {
|
|
530
|
+
return typeof node !== "string" && node.type !== "text";
|
|
531
|
+
}
|
|
532
|
+
function isVoice(element) {
|
|
533
|
+
return element.type === "voice";
|
|
534
|
+
}
|
|
535
|
+
function isProsody(element) {
|
|
536
|
+
return element.type === "prosody";
|
|
537
|
+
}
|
|
538
|
+
function getSsmlElementName(element) {
|
|
539
|
+
return element.type === "custom" || element.type === "element" ? element.name : element.type;
|
|
540
|
+
}
|
|
541
|
+
function findEditableTagEnd(source, start) {
|
|
542
|
+
let quote;
|
|
543
|
+
for (let index = start + 1; index < source.length; index += 1) {
|
|
544
|
+
const character = source[index];
|
|
545
|
+
if (quote !== void 0) {
|
|
546
|
+
if (character === quote) {
|
|
547
|
+
quote = void 0;
|
|
548
|
+
}
|
|
549
|
+
continue;
|
|
550
|
+
}
|
|
551
|
+
if (character === '"' || character === "'") {
|
|
552
|
+
quote = character;
|
|
553
|
+
continue;
|
|
554
|
+
}
|
|
555
|
+
if (character === ">") {
|
|
556
|
+
return index;
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
return source.length;
|
|
560
|
+
}
|
|
561
|
+
function collectEditableStartTags(source) {
|
|
562
|
+
const tags = [];
|
|
563
|
+
let index = 0;
|
|
564
|
+
while (index < source.length) {
|
|
565
|
+
if (source[index] !== "<") {
|
|
566
|
+
index += 1;
|
|
567
|
+
continue;
|
|
568
|
+
}
|
|
569
|
+
if (source.startsWith("<!--", index)) {
|
|
570
|
+
const end2 = source.indexOf("-->", index + 4);
|
|
571
|
+
index = end2 === -1 ? source.length : end2 + 3;
|
|
572
|
+
continue;
|
|
573
|
+
}
|
|
574
|
+
if (source.startsWith("<![CDATA[", index)) {
|
|
575
|
+
const end2 = source.indexOf("]]>", index + 9);
|
|
576
|
+
index = end2 === -1 ? source.length : end2 + 3;
|
|
577
|
+
continue;
|
|
578
|
+
}
|
|
579
|
+
if (source.startsWith("<?", index)) {
|
|
580
|
+
const end2 = source.indexOf("?>", index + 2);
|
|
581
|
+
index = end2 === -1 ? source.length : end2 + 2;
|
|
582
|
+
continue;
|
|
583
|
+
}
|
|
584
|
+
if (source.startsWith("</", index) || source.startsWith("<!", index)) {
|
|
585
|
+
const end2 = findEditableTagEnd(source, index);
|
|
586
|
+
index = end2 === source.length ? source.length : end2 + 1;
|
|
587
|
+
continue;
|
|
588
|
+
}
|
|
589
|
+
const end = findEditableTagEnd(source, index);
|
|
590
|
+
if (end === source.length) {
|
|
591
|
+
break;
|
|
592
|
+
}
|
|
593
|
+
const raw = source.slice(index, end + 1);
|
|
594
|
+
const match = raw.match(/^<([A-Za-z_][A-Za-z0-9_.:-]*)/);
|
|
595
|
+
if (match) {
|
|
596
|
+
tags.push({ name: match[1], selfClosing: /\/\s*>$/.test(raw) });
|
|
597
|
+
}
|
|
598
|
+
index = end + 1;
|
|
599
|
+
}
|
|
600
|
+
return tags;
|
|
601
|
+
}
|
|
602
|
+
function preserveEmptyPairElements(nodes, startTags, startTagIndex) {
|
|
603
|
+
return nodes.map((node) => {
|
|
604
|
+
if (!isSsmlElement(node)) {
|
|
605
|
+
return node;
|
|
606
|
+
}
|
|
607
|
+
const elementName = getSsmlElementName(node);
|
|
608
|
+
const startTag = startTags[startTagIndex.value];
|
|
609
|
+
startTagIndex.value += 1;
|
|
610
|
+
if (node.children === void 0 || node.children.length === 0) {
|
|
611
|
+
return startTag?.name === elementName && !startTag.selfClosing && !INTRINSICALLY_EMPTY_ELEMENTS.has(elementName) ? { ...node, children: [""] } : node;
|
|
612
|
+
}
|
|
613
|
+
const children = preserveEmptyPairElements(node.children, startTags, startTagIndex);
|
|
614
|
+
if (children.every((child, index) => child === node.children?.[index])) {
|
|
615
|
+
return node;
|
|
616
|
+
}
|
|
617
|
+
return { ...node, children };
|
|
618
|
+
});
|
|
619
|
+
}
|
|
620
|
+
function getDocumentChildren2(document2) {
|
|
621
|
+
return document2.children ?? (document2.content === void 0 ? [] : [document2.content]);
|
|
622
|
+
}
|
|
623
|
+
function findFirstElementPath(nodes, predicate, ancestors = []) {
|
|
624
|
+
for (const node of nodes) {
|
|
625
|
+
if (!isSsmlElement(node)) {
|
|
626
|
+
continue;
|
|
627
|
+
}
|
|
628
|
+
const path = [...ancestors, node];
|
|
629
|
+
if (predicate(node)) {
|
|
630
|
+
return path;
|
|
631
|
+
}
|
|
632
|
+
const childPath = findFirstElementPath(node.children ?? [], predicate, path);
|
|
633
|
+
if (childPath) {
|
|
634
|
+
return childPath;
|
|
635
|
+
}
|
|
636
|
+
}
|
|
637
|
+
return void 0;
|
|
638
|
+
}
|
|
639
|
+
function updateFirstElement(nodes, predicate, update) {
|
|
640
|
+
let updated = false;
|
|
641
|
+
const nextNodes = nodes.map((node) => {
|
|
642
|
+
if (updated || !isSsmlElement(node)) {
|
|
643
|
+
return node;
|
|
644
|
+
}
|
|
645
|
+
if (predicate(node)) {
|
|
646
|
+
updated = true;
|
|
647
|
+
return update(node);
|
|
648
|
+
}
|
|
649
|
+
if (node.children) {
|
|
650
|
+
const result = updateFirstElement(node.children, predicate, update);
|
|
651
|
+
if (result.updated) {
|
|
652
|
+
updated = true;
|
|
653
|
+
return { ...node, children: result.nodes };
|
|
654
|
+
}
|
|
655
|
+
}
|
|
656
|
+
return node;
|
|
657
|
+
});
|
|
658
|
+
return { nodes: nextNodes, updated };
|
|
659
|
+
}
|
|
660
|
+
function withChildren(document2, children) {
|
|
661
|
+
const nextDocument = { ...document2, children };
|
|
662
|
+
if (nextDocument.content !== void 0) {
|
|
663
|
+
delete nextDocument.content;
|
|
664
|
+
}
|
|
665
|
+
return nextDocument;
|
|
666
|
+
}
|
|
667
|
+
function parseEditableText(value, lang) {
|
|
668
|
+
try {
|
|
669
|
+
const wrapper = buildSsml({
|
|
670
|
+
version: "1.0",
|
|
671
|
+
lang,
|
|
672
|
+
children: []
|
|
673
|
+
});
|
|
674
|
+
const openingTagEnd = wrapper.indexOf(">") + 1;
|
|
675
|
+
const children = parseSsml(`${wrapper.slice(0, openingTagEnd)}${value}</speak>`).children ?? [];
|
|
676
|
+
return children.some(isSsmlElement) ? preserveEmptyPairElements(children, collectEditableStartTags(value), { value: 0 }) : [value];
|
|
677
|
+
} catch {
|
|
678
|
+
return [value];
|
|
679
|
+
}
|
|
680
|
+
}
|
|
681
|
+
function serializeEditableText(nodes, lang) {
|
|
682
|
+
if (nodes.length === 1 && typeof nodes[0] === "string") {
|
|
683
|
+
return nodes[0];
|
|
684
|
+
}
|
|
685
|
+
const xml = buildSsml({
|
|
686
|
+
version: "1.0",
|
|
687
|
+
lang,
|
|
688
|
+
children: nodes
|
|
689
|
+
});
|
|
690
|
+
const contentStart = xml.indexOf(">") + 1;
|
|
691
|
+
return xml.slice(contentStart, -"</speak>".length);
|
|
692
|
+
}
|
|
693
|
+
function getEditableRegion(document2) {
|
|
694
|
+
const children = getDocumentChildren2(document2);
|
|
695
|
+
const path = findFirstElementPath(children, isProsody) ?? findFirstElementPath(children, isVoice);
|
|
696
|
+
const element = path ? path[path.length - 1] : void 0;
|
|
697
|
+
const voice = path ? [...path].reverse().find(isVoice) : void 0;
|
|
698
|
+
return {
|
|
699
|
+
children: element?.children ?? children,
|
|
700
|
+
...voice ? { voiceName: voice.name } : {}
|
|
701
|
+
};
|
|
702
|
+
}
|
|
703
|
+
function getEditableText(document2) {
|
|
704
|
+
return serializeEditableText(getEditableRegion(document2).children, document2.lang);
|
|
705
|
+
}
|
|
706
|
+
function updateEditableText(document2, value) {
|
|
707
|
+
const nextChildren = parseEditableText(value, document2.lang);
|
|
708
|
+
const editableChildren = nextChildren.length > 0 ? nextChildren : [value];
|
|
709
|
+
const children = getDocumentChildren2(document2);
|
|
710
|
+
const prosodyResult = updateFirstElement(children, isProsody, (prosody) => ({
|
|
711
|
+
...prosody,
|
|
712
|
+
children: editableChildren
|
|
713
|
+
}));
|
|
714
|
+
if (prosodyResult.updated) {
|
|
715
|
+
return withChildren(document2, prosodyResult.nodes);
|
|
716
|
+
}
|
|
717
|
+
const voiceResult = updateFirstElement(children, isVoice, (voice) => ({
|
|
718
|
+
...voice,
|
|
719
|
+
children: editableChildren
|
|
720
|
+
}));
|
|
721
|
+
if (voiceResult.updated) {
|
|
722
|
+
return withChildren(document2, voiceResult.nodes);
|
|
723
|
+
}
|
|
724
|
+
return withChildren(document2, editableChildren);
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
// ../ssml-editor-react/src/constants/ssmlPresets.ts
|
|
728
|
+
var ssmlPresets_exports = {};
|
|
729
|
+
__export(ssmlPresets_exports, {
|
|
730
|
+
BREAK_STRENGTH_PRESETS: () => BREAK_STRENGTH_PRESETS,
|
|
731
|
+
BREAK_TIME_DESCRIPTIONS: () => BREAK_TIME_DESCRIPTIONS,
|
|
732
|
+
BREAK_TIME_PRESETS: () => BREAK_TIME_PRESETS,
|
|
733
|
+
EMPHASIS_LEVEL_DESCRIPTIONS: () => EMPHASIS_LEVEL_DESCRIPTIONS,
|
|
734
|
+
EMPHASIS_LEVEL_PRESETS: () => EMPHASIS_LEVEL_PRESETS,
|
|
735
|
+
EXPRESS_AS_ROLE_PRESETS: () => EXPRESS_AS_ROLE_PRESETS,
|
|
736
|
+
EXPRESS_AS_STYLE_CATEGORIES: () => EXPRESS_AS_STYLE_CATEGORIES,
|
|
737
|
+
EXPRESS_AS_STYLE_DESCRIPTIONS: () => EXPRESS_AS_STYLE_DESCRIPTIONS,
|
|
738
|
+
EXPRESS_AS_STYLE_PRESETS: () => EXPRESS_AS_STYLE_PRESETS,
|
|
739
|
+
LANGUAGE_DESCRIPTIONS: () => LANGUAGE_DESCRIPTIONS,
|
|
740
|
+
LANGUAGE_PRESETS: () => LANGUAGE_PRESETS,
|
|
741
|
+
PHONEME_ALPHABET_PRESETS: () => PHONEME_ALPHABET_PRESETS,
|
|
742
|
+
PROSODY_PITCH_DESCRIPTIONS: () => PROSODY_PITCH_DESCRIPTIONS,
|
|
743
|
+
PROSODY_PITCH_PRESETS: () => PROSODY_PITCH_PRESETS,
|
|
744
|
+
PROSODY_RATE_DESCRIPTIONS: () => PROSODY_RATE_DESCRIPTIONS,
|
|
745
|
+
PROSODY_RATE_PRESETS: () => PROSODY_RATE_PRESETS,
|
|
746
|
+
PROSODY_RATE_VALUES: () => PROSODY_RATE_VALUES,
|
|
747
|
+
PROSODY_VOLUME_DESCRIPTIONS: () => PROSODY_VOLUME_DESCRIPTIONS,
|
|
748
|
+
PROSODY_VOLUME_PRESETS: () => PROSODY_VOLUME_PRESETS,
|
|
749
|
+
SAY_AS_DESCRIPTIONS: () => SAY_AS_DESCRIPTIONS,
|
|
750
|
+
SAY_AS_PRESETS: () => SAY_AS_PRESETS,
|
|
751
|
+
SILENCE_TYPE_PRESETS: () => SILENCE_TYPE_PRESETS,
|
|
752
|
+
SILENCE_VALUE_DESCRIPTIONS: () => SILENCE_VALUE_DESCRIPTIONS,
|
|
753
|
+
SILENCE_VALUE_PRESETS: () => SILENCE_VALUE_PRESETS,
|
|
754
|
+
SSML_ATTRIBUTE_PRESETS: () => SSML_ATTRIBUTE_PRESETS,
|
|
755
|
+
SSML_PRESETS: () => SSML_PRESETS,
|
|
756
|
+
SSML_PRESET_EXAMPLES: () => SSML_PRESET_EXAMPLES,
|
|
757
|
+
VISEME_TYPE_PRESETS: () => VISEME_TYPE_PRESETS,
|
|
758
|
+
VOICE_STYLE_MAP: () => VOICE_STYLE_MAP,
|
|
759
|
+
getExpressAsStyleCategory: () => getExpressAsStyleCategory,
|
|
760
|
+
resolveExpressAsStyles: () => resolveExpressAsStyles
|
|
761
|
+
});
|
|
762
|
+
var SSML_PRESETS = [
|
|
763
|
+
{
|
|
764
|
+
id: "basic",
|
|
765
|
+
label: "Basic speech",
|
|
766
|
+
ssml: '<speak version="1.0" xml:lang="en-US">Hello, world!</speak>',
|
|
767
|
+
description: "A minimal SSML document."
|
|
768
|
+
},
|
|
769
|
+
{
|
|
770
|
+
id: "voice",
|
|
771
|
+
label: "Voice selection",
|
|
772
|
+
ssml: '<speak version="1.0" xml:lang="en-US"><voice name="en-US-JennyNeural">Hello, world!</voice></speak>',
|
|
773
|
+
description: "Speaks text with a selected voice."
|
|
774
|
+
},
|
|
775
|
+
{
|
|
776
|
+
id: "prosody",
|
|
777
|
+
label: "Prosody",
|
|
778
|
+
ssml: '<speak version="1.0" xml:lang="en-US"><prosody rate="fast" pitch="+2st">Hello, world!</prosody></speak>',
|
|
779
|
+
description: "Adjusts the speech rate and pitch."
|
|
780
|
+
}
|
|
781
|
+
];
|
|
782
|
+
var BREAK_TIME_PRESETS = ["500ms", "1s", "2s", "3s"];
|
|
783
|
+
var BREAK_STRENGTH_PRESETS = ["none", "x-weak", "weak", "medium", "strong", "x-strong"];
|
|
784
|
+
var PROSODY_RATE_PRESETS = ["x-slow", "slow", "medium", "fast", "x-fast"];
|
|
785
|
+
var PROSODY_RATE_VALUES = [...PROSODY_RATE_PRESETS, "percentage"];
|
|
786
|
+
var PROSODY_PITCH_PRESETS = ["+2st", "-2st", "0st", "+4st", "-4st", "+8st", "-8st", "+12st", "-12st"];
|
|
787
|
+
var PROSODY_VOLUME_PRESETS = ["silent", "x-soft", "soft", "medium", "loud", "x-loud"];
|
|
788
|
+
var EXPRESS_AS_STYLE_PRESETS = [
|
|
789
|
+
"cheerful",
|
|
790
|
+
"friendly",
|
|
791
|
+
"calm",
|
|
792
|
+
"sad",
|
|
793
|
+
"angry",
|
|
794
|
+
"excited",
|
|
795
|
+
"serious",
|
|
796
|
+
"assistant",
|
|
797
|
+
"chat",
|
|
798
|
+
"customerservice",
|
|
799
|
+
"hopeful",
|
|
800
|
+
"newscast",
|
|
801
|
+
"shouting",
|
|
802
|
+
"terrified",
|
|
803
|
+
"unfriendly",
|
|
804
|
+
"whispering",
|
|
805
|
+
"empathetic",
|
|
806
|
+
"relieved",
|
|
807
|
+
"fearful",
|
|
808
|
+
"depressed",
|
|
809
|
+
"disgruntled",
|
|
810
|
+
"embarrassed",
|
|
811
|
+
"narration-relaxed",
|
|
812
|
+
"poetry-reading",
|
|
813
|
+
"sports_commentary",
|
|
814
|
+
"sports_commentary_excited",
|
|
815
|
+
"story"
|
|
816
|
+
];
|
|
817
|
+
var EXPRESS_AS_STYLE_CATEGORIES = {
|
|
818
|
+
emotions: [
|
|
819
|
+
"cheerful",
|
|
820
|
+
"sad",
|
|
821
|
+
"angry",
|
|
822
|
+
"calm",
|
|
823
|
+
"fearful",
|
|
824
|
+
"depressed",
|
|
825
|
+
"disgruntled",
|
|
826
|
+
"embarrassed",
|
|
827
|
+
"empathetic",
|
|
828
|
+
"envious",
|
|
829
|
+
"excited",
|
|
830
|
+
"friendly",
|
|
831
|
+
"gentle",
|
|
832
|
+
"hopeful",
|
|
833
|
+
"relieved",
|
|
834
|
+
"serious",
|
|
835
|
+
"shouting",
|
|
836
|
+
"terrified",
|
|
837
|
+
"unfriendly",
|
|
838
|
+
"whispering"
|
|
839
|
+
],
|
|
840
|
+
scenarios: ["chat", "customerservice", "assistant", "livecommercial", "poetry-reading", "story"],
|
|
841
|
+
media: [
|
|
842
|
+
"newscast",
|
|
843
|
+
"newscast-casual",
|
|
844
|
+
"newscast-formal",
|
|
845
|
+
"narration-professional",
|
|
846
|
+
"narration-relaxed",
|
|
847
|
+
"documentary-narration",
|
|
848
|
+
"advertisement_upbeat",
|
|
849
|
+
"sports_commentary",
|
|
850
|
+
"sports_commentary_excited"
|
|
851
|
+
]
|
|
852
|
+
};
|
|
853
|
+
function getExpressAsStyleCategory(style) {
|
|
854
|
+
for (const [category, styles] of Object.entries(EXPRESS_AS_STYLE_CATEGORIES)) {
|
|
855
|
+
if (styles.includes(style)) {
|
|
856
|
+
return category;
|
|
857
|
+
}
|
|
858
|
+
}
|
|
859
|
+
return "other";
|
|
860
|
+
}
|
|
861
|
+
var VOICE_STYLE_MAP = {
|
|
862
|
+
"ja-JP-MayuNeural": ["calm", "cheerful", "sad"],
|
|
863
|
+
"ja-JP-KeitaNeural": ["chat"],
|
|
864
|
+
"ja-JP-NanamiNeural": ["chat", "customerservice", "cheerful", "whispering", "sad"],
|
|
865
|
+
"en-US-JennyMultilingualNeural": [
|
|
866
|
+
"cheerful",
|
|
867
|
+
"empathetic",
|
|
868
|
+
"excited",
|
|
869
|
+
"friendly",
|
|
870
|
+
"hopeful",
|
|
871
|
+
"sad",
|
|
872
|
+
"shouting",
|
|
873
|
+
"terrified",
|
|
874
|
+
"unfriendly",
|
|
875
|
+
"whispering"
|
|
876
|
+
],
|
|
877
|
+
"en-US-AndrewNeural": ["empathetic", "relieved"],
|
|
878
|
+
"en-US-JennyNeural": [
|
|
879
|
+
"assistant",
|
|
880
|
+
"chat",
|
|
881
|
+
"customerservice",
|
|
882
|
+
"newscast",
|
|
883
|
+
"cheerful",
|
|
884
|
+
"empathetic",
|
|
885
|
+
"excited",
|
|
886
|
+
"friendly",
|
|
887
|
+
"hopeful",
|
|
888
|
+
"sad",
|
|
889
|
+
"shouting",
|
|
890
|
+
"terrified",
|
|
891
|
+
"unfriendly",
|
|
892
|
+
"whispering"
|
|
893
|
+
],
|
|
894
|
+
"en-US-GuyNeural": [
|
|
895
|
+
"angry",
|
|
896
|
+
"cheerful",
|
|
897
|
+
"excited",
|
|
898
|
+
"friendly",
|
|
899
|
+
"hopeful",
|
|
900
|
+
"newscast",
|
|
901
|
+
"sad",
|
|
902
|
+
"shouting",
|
|
903
|
+
"terrified",
|
|
904
|
+
"unfriendly",
|
|
905
|
+
"whispering"
|
|
906
|
+
],
|
|
907
|
+
"ko-KR-SunHiNeural": ["cheerful", "sad"],
|
|
908
|
+
"zh-CN-XiaoxiaoNeural": [
|
|
909
|
+
"assistant",
|
|
910
|
+
"chat",
|
|
911
|
+
"customerservice",
|
|
912
|
+
"newscast",
|
|
913
|
+
"cheerful",
|
|
914
|
+
"empathetic",
|
|
915
|
+
"excited",
|
|
916
|
+
"friendly",
|
|
917
|
+
"hopeful",
|
|
918
|
+
"sad",
|
|
919
|
+
"terrified",
|
|
920
|
+
"whispering",
|
|
921
|
+
"poetry-reading",
|
|
922
|
+
"sports_commentary",
|
|
923
|
+
"sports_commentary_excited",
|
|
924
|
+
"story"
|
|
925
|
+
],
|
|
926
|
+
"zh-CN-YunxiNeural": [
|
|
927
|
+
"narration-relaxed",
|
|
928
|
+
"embarrassed",
|
|
929
|
+
"fearful",
|
|
930
|
+
"sad",
|
|
931
|
+
"disgruntled",
|
|
932
|
+
"serious",
|
|
933
|
+
"angry",
|
|
934
|
+
"depressed",
|
|
935
|
+
"chat",
|
|
936
|
+
"cheerful",
|
|
937
|
+
"assistant"
|
|
938
|
+
],
|
|
939
|
+
"fr-FR-DeniseNeural": ["cheerful", "sad"],
|
|
940
|
+
"fr-FR-HenriNeural": ["cheerful", "sad"],
|
|
941
|
+
"pt-BR-FranciscaNeural": ["calm"],
|
|
942
|
+
"it-IT-ElsaNeural": ["cheerful", "sad"],
|
|
943
|
+
"de-DE-KatjaNeural": ["cheerful", "sad"],
|
|
944
|
+
"de-DE-ConradNeural": ["cheerful", "sad"],
|
|
945
|
+
"ru-RU-SvetlanaNeural": ["cheerful", "sad", "angry", "disgruntled", "embarrassed", "fearful"]
|
|
946
|
+
};
|
|
947
|
+
var VOICE_STYLE_MAP_BY_NORMALIZED_NAME = new Map(
|
|
948
|
+
Object.entries(VOICE_STYLE_MAP).map(([voiceName, styles]) => [voiceName.toLowerCase(), styles])
|
|
949
|
+
);
|
|
950
|
+
function resolveExpressAsStyles(voiceName, candidates = EXPRESS_AS_STYLE_PRESETS) {
|
|
951
|
+
const normalizedVoiceName = voiceName?.trim().toLowerCase();
|
|
952
|
+
if (!normalizedVoiceName) {
|
|
953
|
+
return candidates;
|
|
954
|
+
}
|
|
955
|
+
const supportedStyles = VOICE_STYLE_MAP_BY_NORMALIZED_NAME.get(normalizedVoiceName);
|
|
956
|
+
if (supportedStyles === void 0) {
|
|
957
|
+
return [];
|
|
958
|
+
}
|
|
959
|
+
const supportedStyleSet = new Set(supportedStyles);
|
|
960
|
+
return candidates.filter((style) => supportedStyleSet.has(style));
|
|
961
|
+
}
|
|
962
|
+
var EXPRESS_AS_ROLE_PRESETS = [
|
|
963
|
+
"Girl",
|
|
964
|
+
"Boy",
|
|
965
|
+
"YoungAdultFemale",
|
|
966
|
+
"YoungAdultMale",
|
|
967
|
+
"OlderAdultFemale",
|
|
968
|
+
"OlderAdultMale",
|
|
969
|
+
"SeniorFemale",
|
|
970
|
+
"SeniorMale"
|
|
971
|
+
];
|
|
972
|
+
var EMPHASIS_LEVEL_PRESETS = ["strong", "moderate", "reduced", "none"];
|
|
973
|
+
var SAY_AS_PRESETS = [
|
|
974
|
+
"characters",
|
|
975
|
+
"spell-out",
|
|
976
|
+
"cardinal",
|
|
977
|
+
"ordinal",
|
|
978
|
+
"number",
|
|
979
|
+
"date",
|
|
980
|
+
"time",
|
|
981
|
+
"telephone",
|
|
982
|
+
"fraction",
|
|
983
|
+
"address",
|
|
984
|
+
"name",
|
|
985
|
+
"currency"
|
|
986
|
+
];
|
|
987
|
+
var LANGUAGE_PRESETS = ["ja-JP", "en-US", "de-DE", "fr-FR"];
|
|
988
|
+
var SILENCE_VALUE_PRESETS = ["300ms", "500ms", "1s"];
|
|
989
|
+
var SILENCE_TYPE_PRESETS = [
|
|
990
|
+
"Leading",
|
|
991
|
+
"Tailing",
|
|
992
|
+
"Sentenceboundary",
|
|
993
|
+
"Comma",
|
|
994
|
+
"Semicolon",
|
|
995
|
+
"Enumerationcomma"
|
|
996
|
+
];
|
|
997
|
+
var PHONEME_ALPHABET_PRESETS = ["ipa", "sapi", "ups", "x-sampa"];
|
|
998
|
+
var VISEME_TYPE_PRESETS = ["redlips_front", "FacialExpression"];
|
|
999
|
+
var SSML_ATTRIBUTE_PRESETS = {
|
|
1000
|
+
break: {
|
|
1001
|
+
strength: BREAK_STRENGTH_PRESETS,
|
|
1002
|
+
time: BREAK_TIME_PRESETS
|
|
1003
|
+
},
|
|
1004
|
+
prosody: {
|
|
1005
|
+
rate: PROSODY_RATE_PRESETS,
|
|
1006
|
+
pitch: PROSODY_PITCH_PRESETS,
|
|
1007
|
+
volume: PROSODY_VOLUME_PRESETS
|
|
1008
|
+
},
|
|
1009
|
+
"mstts:express-as": {
|
|
1010
|
+
style: EXPRESS_AS_STYLE_PRESETS,
|
|
1011
|
+
role: EXPRESS_AS_ROLE_PRESETS
|
|
1012
|
+
},
|
|
1013
|
+
"express-as": {
|
|
1014
|
+
style: EXPRESS_AS_STYLE_PRESETS,
|
|
1015
|
+
role: EXPRESS_AS_ROLE_PRESETS
|
|
1016
|
+
},
|
|
1017
|
+
expressAs: {
|
|
1018
|
+
style: EXPRESS_AS_STYLE_PRESETS,
|
|
1019
|
+
role: EXPRESS_AS_ROLE_PRESETS
|
|
1020
|
+
},
|
|
1021
|
+
"say-as": {
|
|
1022
|
+
"interpret-as": SAY_AS_PRESETS
|
|
1023
|
+
},
|
|
1024
|
+
sayAs: {
|
|
1025
|
+
"interpret-as": SAY_AS_PRESETS
|
|
1026
|
+
},
|
|
1027
|
+
emphasis: {
|
|
1028
|
+
level: EMPHASIS_LEVEL_PRESETS
|
|
1029
|
+
},
|
|
1030
|
+
lang: {
|
|
1031
|
+
"xml:lang": LANGUAGE_PRESETS
|
|
1032
|
+
},
|
|
1033
|
+
phoneme: {
|
|
1034
|
+
alphabet: PHONEME_ALPHABET_PRESETS
|
|
1035
|
+
},
|
|
1036
|
+
"mstts:silence": {
|
|
1037
|
+
type: SILENCE_TYPE_PRESETS,
|
|
1038
|
+
value: SILENCE_VALUE_PRESETS
|
|
1039
|
+
},
|
|
1040
|
+
silence: {
|
|
1041
|
+
type: SILENCE_TYPE_PRESETS,
|
|
1042
|
+
value: SILENCE_VALUE_PRESETS
|
|
1043
|
+
},
|
|
1044
|
+
"mstts:viseme": {
|
|
1045
|
+
type: VISEME_TYPE_PRESETS
|
|
1046
|
+
},
|
|
1047
|
+
viseme: {
|
|
1048
|
+
type: VISEME_TYPE_PRESETS
|
|
1049
|
+
}
|
|
1050
|
+
};
|
|
1051
|
+
var SSML_PRESET_EXAMPLES = {
|
|
1052
|
+
breakTime: "500ms",
|
|
1053
|
+
prosodyRate: "fast",
|
|
1054
|
+
prosodyPitch: "+2st",
|
|
1055
|
+
prosodyVolume: "loud",
|
|
1056
|
+
expressAsStyle: "cheerful",
|
|
1057
|
+
phonemeAlphabet: "ipa",
|
|
1058
|
+
silenceValue: "300ms"
|
|
1059
|
+
};
|
|
1060
|
+
var BREAK_TIME_DESCRIPTIONS = {
|
|
1061
|
+
"500ms": {
|
|
1062
|
+
ja: "500\u30DF\u30EA\u79D2\u306E\u7121\u97F3",
|
|
1063
|
+
en: "Inserts 500 milliseconds of silence."
|
|
1064
|
+
},
|
|
1065
|
+
"1s": {
|
|
1066
|
+
ja: "1\u79D2\u306E\u7121\u97F3",
|
|
1067
|
+
en: "Inserts one second of silence."
|
|
1068
|
+
},
|
|
1069
|
+
"2s": {
|
|
1070
|
+
ja: "2\u79D2\u306E\u7121\u97F3",
|
|
1071
|
+
en: "Inserts two seconds of silence."
|
|
1072
|
+
},
|
|
1073
|
+
"3s": {
|
|
1074
|
+
ja: "3\u79D2\u306E\u7121\u97F3",
|
|
1075
|
+
en: "Inserts three seconds of silence."
|
|
1076
|
+
}
|
|
1077
|
+
};
|
|
1078
|
+
var EMPHASIS_LEVEL_DESCRIPTIONS = {
|
|
1079
|
+
strong: {
|
|
1080
|
+
ja: "\u5F37\u3044\u5F37\u8ABF",
|
|
1081
|
+
en: "Applies strong emphasis."
|
|
1082
|
+
},
|
|
1083
|
+
moderate: {
|
|
1084
|
+
ja: "\u4E2D\u7A0B\u5EA6\u306E\u5F37\u8ABF",
|
|
1085
|
+
en: "Applies moderate emphasis."
|
|
1086
|
+
},
|
|
1087
|
+
reduced: {
|
|
1088
|
+
ja: "\u5F31\u3081\u306E\u5F37\u8ABF",
|
|
1089
|
+
en: "Applies reduced emphasis."
|
|
1090
|
+
},
|
|
1091
|
+
none: {
|
|
1092
|
+
ja: "\u5F37\u8ABF\u306A\u3057",
|
|
1093
|
+
en: "Applies no emphasis."
|
|
1094
|
+
}
|
|
1095
|
+
};
|
|
1096
|
+
var PROSODY_RATE_DESCRIPTIONS = {
|
|
1097
|
+
"x-slow": {
|
|
1098
|
+
ja: "\u6700\u3082\u9045\u3044\u901F\u5EA6",
|
|
1099
|
+
en: "Uses the slowest speech rate."
|
|
1100
|
+
},
|
|
1101
|
+
slow: {
|
|
1102
|
+
ja: "\u9045\u3044\u901F\u5EA6",
|
|
1103
|
+
en: "Uses a slow speech rate."
|
|
1104
|
+
},
|
|
1105
|
+
medium: {
|
|
1106
|
+
ja: "\u6A19\u6E96\u7684\u306A\u901F\u5EA6",
|
|
1107
|
+
en: "Uses the standard speech rate."
|
|
1108
|
+
},
|
|
1109
|
+
fast: {
|
|
1110
|
+
ja: "\u901F\u3044\u901F\u5EA6",
|
|
1111
|
+
en: "Uses a fast speech rate."
|
|
1112
|
+
},
|
|
1113
|
+
"x-fast": {
|
|
1114
|
+
ja: "\u6700\u3082\u901F\u3044\u901F\u5EA6",
|
|
1115
|
+
en: "Uses the fastest speech rate."
|
|
1116
|
+
}
|
|
1117
|
+
};
|
|
1118
|
+
var PROSODY_PITCH_DESCRIPTIONS = {
|
|
1119
|
+
"+2st": {
|
|
1120
|
+
ja: "\u57FA\u6E96\u306E\u58F0\u306E\u9AD8\u3055\u3088\u308A2\u534A\u97F3\u4E0A",
|
|
1121
|
+
en: "Raises the pitch by two semitones."
|
|
1122
|
+
},
|
|
1123
|
+
"-2st": {
|
|
1124
|
+
ja: "\u57FA\u6E96\u306E\u58F0\u306E\u9AD8\u3055\u3088\u308A2\u534A\u97F3\u4E0B",
|
|
1125
|
+
en: "Lowers the pitch by two semitones."
|
|
1126
|
+
},
|
|
1127
|
+
"0st": {
|
|
1128
|
+
ja: "\u57FA\u6E96\u306E\u58F0\u306E\u9AD8\u3055",
|
|
1129
|
+
en: "Keeps the baseline pitch."
|
|
1130
|
+
},
|
|
1131
|
+
"+4st": {
|
|
1132
|
+
ja: "\u57FA\u6E96\u306E\u58F0\u306E\u9AD8\u3055\u3088\u308A4\u534A\u97F3\u4E0A",
|
|
1133
|
+
en: "Raises the pitch by four semitones."
|
|
1134
|
+
},
|
|
1135
|
+
"-4st": {
|
|
1136
|
+
ja: "\u57FA\u6E96\u306E\u58F0\u306E\u9AD8\u3055\u3088\u308A4\u534A\u97F3\u4E0B",
|
|
1137
|
+
en: "Lowers the pitch by four semitones."
|
|
1138
|
+
},
|
|
1139
|
+
"+8st": {
|
|
1140
|
+
ja: "\u57FA\u6E96\u306E\u58F0\u306E\u9AD8\u3055\u3088\u308A8\u534A\u97F3\u4E0A",
|
|
1141
|
+
en: "Raises the pitch by eight semitones."
|
|
1142
|
+
},
|
|
1143
|
+
"-8st": {
|
|
1144
|
+
ja: "\u57FA\u6E96\u306E\u58F0\u306E\u9AD8\u3055\u3088\u308A8\u534A\u97F3\u4E0B",
|
|
1145
|
+
en: "Lowers the pitch by eight semitones."
|
|
1146
|
+
},
|
|
1147
|
+
"+12st": {
|
|
1148
|
+
ja: "\u57FA\u6E96\u306E\u58F0\u306E\u9AD8\u3055\u3088\u308A12\u534A\u97F3\u4E0A",
|
|
1149
|
+
en: "Raises the pitch by twelve semitones."
|
|
1150
|
+
},
|
|
1151
|
+
"-12st": {
|
|
1152
|
+
ja: "\u57FA\u6E96\u306E\u58F0\u306E\u9AD8\u3055\u3088\u308A12\u534A\u97F3\u4E0B",
|
|
1153
|
+
en: "Lowers the pitch by twelve semitones."
|
|
1154
|
+
}
|
|
1155
|
+
};
|
|
1156
|
+
var PROSODY_VOLUME_DESCRIPTIONS = {
|
|
1157
|
+
silent: {
|
|
1158
|
+
ja: "\u7121\u97F3",
|
|
1159
|
+
en: "Makes the selected text silent."
|
|
1160
|
+
},
|
|
1161
|
+
"x-soft": {
|
|
1162
|
+
ja: "\u6700\u3082\u5C0F\u3055\u3044\u97F3\u91CF",
|
|
1163
|
+
en: "Uses the quietest volume."
|
|
1164
|
+
},
|
|
1165
|
+
soft: {
|
|
1166
|
+
ja: "\u5C0F\u3055\u3044\u97F3\u91CF",
|
|
1167
|
+
en: "Uses a soft volume."
|
|
1168
|
+
},
|
|
1169
|
+
medium: {
|
|
1170
|
+
ja: "\u6A19\u6E96\u7684\u306A\u97F3\u91CF",
|
|
1171
|
+
en: "Uses the standard volume."
|
|
1172
|
+
},
|
|
1173
|
+
loud: {
|
|
1174
|
+
ja: "\u5927\u304D\u3044\u97F3\u91CF",
|
|
1175
|
+
en: "Uses a loud volume."
|
|
1176
|
+
},
|
|
1177
|
+
"x-loud": {
|
|
1178
|
+
ja: "\u6700\u3082\u5927\u304D\u3044\u97F3\u91CF",
|
|
1179
|
+
en: "Uses the loudest volume."
|
|
1180
|
+
}
|
|
1181
|
+
};
|
|
1182
|
+
var EXPRESS_AS_STYLE_DESCRIPTIONS = {
|
|
1183
|
+
cheerful: {
|
|
1184
|
+
ja: "\u660E\u308B\u304F\u5143\u6C17\u306A\u30B9\u30BF\u30A4\u30EB",
|
|
1185
|
+
en: "Uses a cheerful style."
|
|
1186
|
+
},
|
|
1187
|
+
friendly: {
|
|
1188
|
+
ja: "\u89AA\u3057\u307F\u3084\u3059\u3044\u30B9\u30BF\u30A4\u30EB",
|
|
1189
|
+
en: "Uses a friendly style."
|
|
1190
|
+
},
|
|
1191
|
+
calm: {
|
|
1192
|
+
ja: "\u7A4F\u3084\u304B\u306A\u30B9\u30BF\u30A4\u30EB",
|
|
1193
|
+
en: "Uses a calm style."
|
|
1194
|
+
},
|
|
1195
|
+
sad: {
|
|
1196
|
+
ja: "\u60B2\u3057\u3052\u306A\u30B9\u30BF\u30A4\u30EB",
|
|
1197
|
+
en: "Uses a sad style."
|
|
1198
|
+
},
|
|
1199
|
+
angry: {
|
|
1200
|
+
ja: "\u6012\u3063\u305F\u3088\u3046\u306A\u30B9\u30BF\u30A4\u30EB",
|
|
1201
|
+
en: "Uses an angry style."
|
|
1202
|
+
},
|
|
1203
|
+
excited: {
|
|
1204
|
+
ja: "\u8208\u596E\u3057\u305F\u30B9\u30BF\u30A4\u30EB",
|
|
1205
|
+
en: "Uses an excited style."
|
|
1206
|
+
},
|
|
1207
|
+
empathetic: {
|
|
1208
|
+
ja: "\u5171\u611F\u3092\u793A\u3059\u30B9\u30BF\u30A4\u30EB",
|
|
1209
|
+
en: "Uses an empathetic style."
|
|
1210
|
+
},
|
|
1211
|
+
relieved: {
|
|
1212
|
+
ja: "\u5B89\u5FC3\u3057\u305F\u30B9\u30BF\u30A4\u30EB",
|
|
1213
|
+
en: "Uses a relieved style."
|
|
1214
|
+
},
|
|
1215
|
+
fearful: {
|
|
1216
|
+
ja: "\u6050\u308C\u3092\u611F\u3058\u3055\u305B\u308B\u30B9\u30BF\u30A4\u30EB",
|
|
1217
|
+
en: "Uses a fearful style."
|
|
1218
|
+
},
|
|
1219
|
+
depressed: {
|
|
1220
|
+
ja: "\u843D\u3061\u8FBC\u3093\u3060\u30B9\u30BF\u30A4\u30EB",
|
|
1221
|
+
en: "Uses a depressed style."
|
|
1222
|
+
},
|
|
1223
|
+
disgruntled: {
|
|
1224
|
+
ja: "\u4E0D\u6E80\u3092\u611F\u3058\u3055\u305B\u308B\u30B9\u30BF\u30A4\u30EB",
|
|
1225
|
+
en: "Uses a disgruntled style."
|
|
1226
|
+
},
|
|
1227
|
+
embarrassed: {
|
|
1228
|
+
ja: "\u6065\u305A\u304B\u3057\u305D\u3046\u306A\u30B9\u30BF\u30A4\u30EB",
|
|
1229
|
+
en: "Uses an embarrassed style."
|
|
1230
|
+
},
|
|
1231
|
+
serious: {
|
|
1232
|
+
ja: "\u771F\u5263\u306A\u30B9\u30BF\u30A4\u30EB",
|
|
1233
|
+
en: "Uses a serious style."
|
|
1234
|
+
},
|
|
1235
|
+
assistant: {
|
|
1236
|
+
ja: "\u30C7\u30B8\u30BF\u30EB\u30A2\u30B7\u30B9\u30BF\u30F3\u30C8\u5411\u3051\u306E\u30B9\u30BF\u30A4\u30EB",
|
|
1237
|
+
en: "Uses a digital assistant style."
|
|
1238
|
+
},
|
|
1239
|
+
chat: {
|
|
1240
|
+
ja: "\u4F1A\u8A71\u5411\u3051\u306E\u30B9\u30BF\u30A4\u30EB",
|
|
1241
|
+
en: "Uses a conversational style."
|
|
1242
|
+
},
|
|
1243
|
+
customerservice: {
|
|
1244
|
+
ja: "\u30AB\u30B9\u30BF\u30DE\u30FC\u30B5\u30FC\u30D3\u30B9\u5411\u3051\u306E\u30B9\u30BF\u30A4\u30EB",
|
|
1245
|
+
en: "Uses a customer service style."
|
|
1246
|
+
},
|
|
1247
|
+
hopeful: {
|
|
1248
|
+
ja: "\u5E0C\u671B\u306B\u6E80\u3061\u305F\u30B9\u30BF\u30A4\u30EB",
|
|
1249
|
+
en: "Uses a hopeful style."
|
|
1250
|
+
},
|
|
1251
|
+
newscast: {
|
|
1252
|
+
ja: "\u30CB\u30E5\u30FC\u30B9\u8AAD\u307F\u4E0A\u3052\u5411\u3051\u306E\u30B9\u30BF\u30A4\u30EB",
|
|
1253
|
+
en: "Uses a newscast style."
|
|
1254
|
+
},
|
|
1255
|
+
shouting: {
|
|
1256
|
+
ja: "\u53EB\u3076\u3088\u3046\u306A\u30B9\u30BF\u30A4\u30EB",
|
|
1257
|
+
en: "Uses a shouting style."
|
|
1258
|
+
},
|
|
1259
|
+
terrified: {
|
|
1260
|
+
ja: "\u6050\u6016\u306B\u6E80\u3061\u305F\u30B9\u30BF\u30A4\u30EB",
|
|
1261
|
+
en: "Uses a terrified style."
|
|
1262
|
+
},
|
|
1263
|
+
unfriendly: {
|
|
1264
|
+
ja: "\u7121\u611B\u60F3\u306A\u30B9\u30BF\u30A4\u30EB",
|
|
1265
|
+
en: "Uses an unfriendly style."
|
|
1266
|
+
},
|
|
1267
|
+
whispering: {
|
|
1268
|
+
ja: "\u3055\u3055\u3084\u304F\u3088\u3046\u306A\u30B9\u30BF\u30A4\u30EB",
|
|
1269
|
+
en: "Uses a whispering style."
|
|
1270
|
+
},
|
|
1271
|
+
"narration-relaxed": {
|
|
1272
|
+
ja: "\u30EA\u30E9\u30C3\u30AF\u30B9\u3057\u305F\u30CA\u30EC\u30FC\u30B7\u30E7\u30F3\u5411\u3051\u306E\u30B9\u30BF\u30A4\u30EB",
|
|
1273
|
+
en: "Uses a relaxed narration style."
|
|
1274
|
+
},
|
|
1275
|
+
"poetry-reading": {
|
|
1276
|
+
ja: "\u8A69\u306E\u6717\u8AAD\u5411\u3051\u306E\u30B9\u30BF\u30A4\u30EB",
|
|
1277
|
+
en: "Uses a poetry-reading style."
|
|
1278
|
+
},
|
|
1279
|
+
sports_commentary: {
|
|
1280
|
+
ja: "\u30B9\u30DD\u30FC\u30C4\u5B9F\u6CC1\u5411\u3051\u306E\u30B9\u30BF\u30A4\u30EB",
|
|
1281
|
+
en: "Uses a sports commentary style."
|
|
1282
|
+
},
|
|
1283
|
+
sports_commentary_excited: {
|
|
1284
|
+
ja: "\u8208\u596E\u3057\u305F\u30B9\u30DD\u30FC\u30C4\u5B9F\u6CC1\u5411\u3051\u306E\u30B9\u30BF\u30A4\u30EB",
|
|
1285
|
+
en: "Uses an excited sports commentary style."
|
|
1286
|
+
},
|
|
1287
|
+
story: {
|
|
1288
|
+
ja: "\u7269\u8A9E\u306E\u6717\u8AAD\u5411\u3051\u306E\u30B9\u30BF\u30A4\u30EB",
|
|
1289
|
+
en: "Uses a storytelling style."
|
|
1290
|
+
}
|
|
1291
|
+
};
|
|
1292
|
+
var SAY_AS_DESCRIPTIONS = {
|
|
1293
|
+
characters: {
|
|
1294
|
+
ja: "1\u6587\u5B57\u305A\u3064\u306E\u8AAD\u307F\u4E0A\u3052",
|
|
1295
|
+
en: "Speaks the characters one by one."
|
|
1296
|
+
},
|
|
1297
|
+
"spell-out": {
|
|
1298
|
+
ja: "\u7DB4\u308A\u306E\u8AAD\u307F\u4E0A\u3052\uFF081\u6587\u5B57\u305A\u3064\uFF09",
|
|
1299
|
+
en: "Spells out the text character by character."
|
|
1300
|
+
},
|
|
1301
|
+
cardinal: {
|
|
1302
|
+
ja: "\u57FA\u6570\u3068\u3057\u3066\u306E\u8AAD\u307F\u4E0A\u3052",
|
|
1303
|
+
en: "Speaks the value as a cardinal number."
|
|
1304
|
+
},
|
|
1305
|
+
ordinal: {
|
|
1306
|
+
ja: "\u5E8F\u6570\u3068\u3057\u3066\u306E\u8AAD\u307F\u4E0A\u3052",
|
|
1307
|
+
en: "Speaks the value as an ordinal number."
|
|
1308
|
+
},
|
|
1309
|
+
number: {
|
|
1310
|
+
ja: "\u6570\u5024\u3068\u3057\u3066\u306E\u8AAD\u307F\u4E0A\u3052",
|
|
1311
|
+
en: "Speaks the value as a number."
|
|
1312
|
+
},
|
|
1313
|
+
date: {
|
|
1314
|
+
ja: "\u65E5\u4ED8\u3068\u3057\u3066\u306E\u8AAD\u307F\u4E0A\u3052",
|
|
1315
|
+
en: "Speaks the value as a date."
|
|
1316
|
+
},
|
|
1317
|
+
time: {
|
|
1318
|
+
ja: "\u6642\u523B\u3068\u3057\u3066\u306E\u8AAD\u307F\u4E0A\u3052",
|
|
1319
|
+
en: "Speaks the value as a time."
|
|
1320
|
+
},
|
|
1321
|
+
telephone: {
|
|
1322
|
+
ja: "\u96FB\u8A71\u756A\u53F7\u3068\u3057\u3066\u306E\u8AAD\u307F\u4E0A\u3052",
|
|
1323
|
+
en: "Speaks the value as a telephone number."
|
|
1324
|
+
},
|
|
1325
|
+
fraction: {
|
|
1326
|
+
ja: "\u5206\u6570\u3068\u3057\u3066\u306E\u8AAD\u307F\u4E0A\u3052",
|
|
1327
|
+
en: "Speaks the value as a fraction."
|
|
1328
|
+
},
|
|
1329
|
+
address: {
|
|
1330
|
+
ja: "\u4F4F\u6240\u3068\u3057\u3066\u306E\u8AAD\u307F\u4E0A\u3052",
|
|
1331
|
+
en: "Speaks the value as an address."
|
|
1332
|
+
},
|
|
1333
|
+
name: {
|
|
1334
|
+
ja: "\u540D\u524D\u3068\u3057\u3066\u306E\u8AAD\u307F\u4E0A\u3052",
|
|
1335
|
+
en: "Speaks the value as a name."
|
|
1336
|
+
},
|
|
1337
|
+
currency: {
|
|
1338
|
+
ja: "\u901A\u8CA8\u3068\u3057\u3066\u306E\u8AAD\u307F\u4E0A\u3052",
|
|
1339
|
+
en: "Speaks the value as currency."
|
|
1340
|
+
}
|
|
1341
|
+
};
|
|
1342
|
+
var LANGUAGE_DESCRIPTIONS = {
|
|
1343
|
+
"ja-JP": {
|
|
1344
|
+
ja: "\u65E5\u672C\u8A9E\uFF08\u65E5\u672C\uFF09\u3067\u8AAD\u307F\u4E0A\u3052\u307E\u3059\u3002",
|
|
1345
|
+
en: "Speaks the text in Japanese (Japan)."
|
|
1346
|
+
},
|
|
1347
|
+
"en-US": {
|
|
1348
|
+
ja: "\u82F1\u8A9E\uFF08\u7C73\u56FD\uFF09\u3067\u8AAD\u307F\u4E0A\u3052\u307E\u3059\u3002",
|
|
1349
|
+
en: "Speaks the text in English (United States)."
|
|
1350
|
+
},
|
|
1351
|
+
"de-DE": {
|
|
1352
|
+
ja: "\u30C9\u30A4\u30C4\u8A9E\uFF08\u30C9\u30A4\u30C4\uFF09\u3067\u8AAD\u307F\u4E0A\u3052\u307E\u3059\u3002",
|
|
1353
|
+
en: "Speaks the text in German (Germany)."
|
|
1354
|
+
},
|
|
1355
|
+
"fr-FR": {
|
|
1356
|
+
ja: "\u30D5\u30E9\u30F3\u30B9\u8A9E\uFF08\u30D5\u30E9\u30F3\u30B9\uFF09\u3067\u8AAD\u307F\u4E0A\u3052\u307E\u3059\u3002",
|
|
1357
|
+
en: "Speaks the text in French (France)."
|
|
1358
|
+
}
|
|
1359
|
+
};
|
|
1360
|
+
var SILENCE_VALUE_DESCRIPTIONS = {
|
|
1361
|
+
"300ms": {
|
|
1362
|
+
ja: "\u5148\u982D\u306B300\u30DF\u30EA\u79D2\u306E\u7121\u97F3\u3092\u633F\u5165\u3057\u307E\u3059\u3002",
|
|
1363
|
+
en: "Inserts 300 milliseconds of leading silence."
|
|
1364
|
+
},
|
|
1365
|
+
"500ms": {
|
|
1366
|
+
ja: "\u5148\u982D\u306B500\u30DF\u30EA\u79D2\u306E\u7121\u97F3\u3092\u633F\u5165\u3057\u307E\u3059\u3002",
|
|
1367
|
+
en: "Inserts 500 milliseconds of leading silence."
|
|
1368
|
+
},
|
|
1369
|
+
"1s": {
|
|
1370
|
+
ja: "\u5148\u982D\u306B1\u79D2\u306E\u7121\u97F3\u3092\u633F\u5165\u3057\u307E\u3059\u3002",
|
|
1371
|
+
en: "Inserts one second of leading silence."
|
|
1372
|
+
}
|
|
1373
|
+
};
|
|
1374
|
+
|
|
1375
|
+
// ../ssml-editor-react/src/ssmlContext.ts
|
|
1376
|
+
function findTagEnd2(source, start, limit) {
|
|
1377
|
+
let quote;
|
|
1378
|
+
for (let index = start + 1; index < limit; index += 1) {
|
|
1379
|
+
const character = source[index];
|
|
1380
|
+
if (quote !== void 0) {
|
|
1381
|
+
if (character === quote) {
|
|
1382
|
+
quote = void 0;
|
|
1383
|
+
}
|
|
1384
|
+
continue;
|
|
1385
|
+
}
|
|
1386
|
+
if (character === '"' || character === "'") {
|
|
1387
|
+
quote = character;
|
|
1388
|
+
continue;
|
|
1389
|
+
}
|
|
1390
|
+
if (character === ">") {
|
|
1391
|
+
return index;
|
|
1392
|
+
}
|
|
1393
|
+
}
|
|
1394
|
+
return -1;
|
|
1395
|
+
}
|
|
1396
|
+
function getVoiceName(tag) {
|
|
1397
|
+
return tag.match(/\bname\s*=\s*(["'])([\s\S]*?)\1/i)?.[2];
|
|
1398
|
+
}
|
|
1399
|
+
function closeElement(stack, name) {
|
|
1400
|
+
for (let index = stack.length - 1; index >= 0; index -= 1) {
|
|
1401
|
+
if (stack[index]?.name === name) {
|
|
1402
|
+
stack.splice(index);
|
|
1403
|
+
return;
|
|
1404
|
+
}
|
|
1405
|
+
}
|
|
1406
|
+
}
|
|
1407
|
+
function findActiveSsmlTags(source, offset) {
|
|
1408
|
+
const limit = Math.max(0, Math.min(offset, source.length));
|
|
1409
|
+
const stack = [];
|
|
1410
|
+
let index = 0;
|
|
1411
|
+
while (index < source.length) {
|
|
1412
|
+
const tagStart = source.indexOf("<", index);
|
|
1413
|
+
if (tagStart === -1 || tagStart > limit) {
|
|
1414
|
+
break;
|
|
1415
|
+
}
|
|
1416
|
+
const nonContentEnd = source.startsWith("<!--", tagStart) ? source.indexOf("-->", tagStart + 4) : source.startsWith("<![CDATA[", tagStart) ? source.indexOf("]]>", tagStart + 9) : source.startsWith("<?", tagStart) ? source.indexOf("?>", tagStart + 2) : void 0;
|
|
1417
|
+
if (nonContentEnd !== void 0) {
|
|
1418
|
+
const delimiterLength = source.startsWith("<?", tagStart) ? 2 : 3;
|
|
1419
|
+
const end = nonContentEnd === -1 ? source.length : nonContentEnd + delimiterLength;
|
|
1420
|
+
if (limit < end) {
|
|
1421
|
+
break;
|
|
1422
|
+
}
|
|
1423
|
+
index = end;
|
|
1424
|
+
continue;
|
|
1425
|
+
}
|
|
1426
|
+
const tagEnd = findTagEnd2(source, tagStart, source.length);
|
|
1427
|
+
const tag = source.slice(tagStart, tagEnd === -1 ? source.length : tagEnd + 1);
|
|
1428
|
+
const closingMatch = tag.match(/^<\s*\/\s*([A-Za-z_][A-Za-z0-9_.:-]*)/);
|
|
1429
|
+
const openingMatch = tag.match(/^<\s*([A-Za-z_][A-Za-z0-9_.:-]*)/);
|
|
1430
|
+
if (tagEnd === -1 || limit <= tagEnd) {
|
|
1431
|
+
if (openingMatch?.[1]) {
|
|
1432
|
+
stack.push({ name: openingMatch[1].toLowerCase() });
|
|
1433
|
+
}
|
|
1434
|
+
break;
|
|
1435
|
+
}
|
|
1436
|
+
if (closingMatch?.[1]) {
|
|
1437
|
+
closeElement(stack, closingMatch[1].toLowerCase());
|
|
1438
|
+
} else if (openingMatch?.[1] && !/\/\s*>$/.test(tag)) {
|
|
1439
|
+
stack.push({ name: openingMatch[1].toLowerCase() });
|
|
1440
|
+
}
|
|
1441
|
+
index = tagEnd + 1;
|
|
1442
|
+
}
|
|
1443
|
+
return new Set(stack.map(({ name }) => name));
|
|
1444
|
+
}
|
|
1445
|
+
function findSsmlVoiceContext(source, offset) {
|
|
1446
|
+
const limit = Math.max(0, Math.min(offset, source.length));
|
|
1447
|
+
const stack = [];
|
|
1448
|
+
let index = 0;
|
|
1449
|
+
while (index < limit) {
|
|
1450
|
+
const tagStart = source.indexOf("<", index);
|
|
1451
|
+
if (tagStart === -1 || tagStart >= limit) {
|
|
1452
|
+
break;
|
|
1453
|
+
}
|
|
1454
|
+
if (source.startsWith("<!--", tagStart)) {
|
|
1455
|
+
const end = source.indexOf("-->", tagStart + 4);
|
|
1456
|
+
index = end === -1 || end + 3 > limit ? limit : end + 3;
|
|
1457
|
+
continue;
|
|
1458
|
+
}
|
|
1459
|
+
if (source.startsWith("<![CDATA[", tagStart)) {
|
|
1460
|
+
const end = source.indexOf("]]>", tagStart + 9);
|
|
1461
|
+
index = end === -1 || end + 3 > limit ? limit : end + 3;
|
|
1462
|
+
continue;
|
|
1463
|
+
}
|
|
1464
|
+
if (source.startsWith("<?", tagStart)) {
|
|
1465
|
+
const end = source.indexOf("?>", tagStart + 2);
|
|
1466
|
+
index = end === -1 || end + 2 > limit ? limit : end + 2;
|
|
1467
|
+
continue;
|
|
1468
|
+
}
|
|
1469
|
+
const tagEnd = findTagEnd2(source, tagStart, limit);
|
|
1470
|
+
if (tagEnd === -1) {
|
|
1471
|
+
break;
|
|
1472
|
+
}
|
|
1473
|
+
const tag = source.slice(tagStart, tagEnd + 1);
|
|
1474
|
+
if (tag.startsWith("<!")) {
|
|
1475
|
+
index = tagEnd + 1;
|
|
1476
|
+
continue;
|
|
1477
|
+
}
|
|
1478
|
+
const closingMatch = tag.match(/^<\s*\/\s*([A-Za-z_][A-Za-z0-9_.:-]*)/);
|
|
1479
|
+
if (closingMatch?.[1]) {
|
|
1480
|
+
closeElement(stack, closingMatch[1].toLowerCase());
|
|
1481
|
+
index = tagEnd + 1;
|
|
1482
|
+
continue;
|
|
1483
|
+
}
|
|
1484
|
+
const openingMatch = tag.match(/^<\s*([A-Za-z_][A-Za-z0-9_.:-]*)/);
|
|
1485
|
+
if (openingMatch?.[1] && !/\/\s*>$/.test(tag)) {
|
|
1486
|
+
const name = openingMatch[1].toLowerCase();
|
|
1487
|
+
stack.push({
|
|
1488
|
+
name,
|
|
1489
|
+
...name === "voice" ? { voiceName: getVoiceName(tag) } : {}
|
|
1490
|
+
});
|
|
1491
|
+
}
|
|
1492
|
+
index = tagEnd + 1;
|
|
1493
|
+
}
|
|
1494
|
+
for (let stackIndex = stack.length - 1; stackIndex >= 0; stackIndex -= 1) {
|
|
1495
|
+
const element = stack[stackIndex];
|
|
1496
|
+
if (element?.name === "voice") {
|
|
1497
|
+
return element.voiceName === void 0 ? {} : { voiceName: element.voiceName };
|
|
1498
|
+
}
|
|
1499
|
+
}
|
|
1500
|
+
return void 0;
|
|
1501
|
+
}
|
|
1502
|
+
|
|
1503
|
+
// ../ssml-editor-react/src/ssmlCompletion.ts
|
|
1504
|
+
var SSML_ATTRIBUTE_VALUE_PATTERN = /<([\w:-]+)\s+[^>]*?\b([\w:-]+)=["']([^"']*)$/i;
|
|
1505
|
+
var EXPRESS_AS_TAG_NAMES = /* @__PURE__ */ new Set(["mstts:express-as", "express-as", "expressas"]);
|
|
1506
|
+
function findSsmlAttributePresets(tagName, attributeName) {
|
|
1507
|
+
const tagPresets = Object.entries(SSML_ATTRIBUTE_PRESETS).find(
|
|
1508
|
+
([presetTagName]) => presetTagName.toLowerCase() === tagName.toLowerCase()
|
|
1509
|
+
)?.[1];
|
|
1510
|
+
return Object.entries(tagPresets ?? {}).find(
|
|
1511
|
+
([presetAttributeName]) => presetAttributeName.toLowerCase() === attributeName.toLowerCase()
|
|
1512
|
+
)?.[1];
|
|
1513
|
+
}
|
|
1514
|
+
var SSML_COMPLETION_SNIPPETS = [
|
|
1515
|
+
{
|
|
1516
|
+
label: "break",
|
|
1517
|
+
insertText: '<break time="500ms" />'
|
|
1518
|
+
},
|
|
1519
|
+
{
|
|
1520
|
+
label: "prosody",
|
|
1521
|
+
insertText: `<prosody rate="medium" pitch="medium">\${1:text}</prosody>`
|
|
1522
|
+
},
|
|
1523
|
+
{
|
|
1524
|
+
label: "mstts:express-as",
|
|
1525
|
+
insertText: `<mstts:express-as style="cheerful">\${1:text}</mstts:express-as>`
|
|
1526
|
+
},
|
|
1527
|
+
{
|
|
1528
|
+
label: "sub",
|
|
1529
|
+
insertText: `<sub alias="\${1:\u8AAD\u307F}">\${2:\u6F22\u5B57}</sub>`
|
|
1530
|
+
}
|
|
1531
|
+
];
|
|
1532
|
+
function registerSsmlCompletionProvider(monaco, options = {}) {
|
|
1533
|
+
const provider = {
|
|
1534
|
+
provideCompletionItems(model, position) {
|
|
1535
|
+
if (options.model && options.model !== model) {
|
|
1536
|
+
return { suggestions: [] };
|
|
1537
|
+
}
|
|
1538
|
+
const value = model.getValue();
|
|
1539
|
+
const offset = model.getOffsetAt(position);
|
|
1540
|
+
const textUntilPosition = value.slice(0, offset);
|
|
1541
|
+
const isClosingTag = /<\/[a-zA-Z0-9:-]*$/.test(textUntilPosition);
|
|
1542
|
+
if (isClosingTag) {
|
|
1543
|
+
return { suggestions: [] };
|
|
1544
|
+
}
|
|
1545
|
+
const attributeMatch = SSML_ATTRIBUTE_VALUE_PATTERN.exec(textUntilPosition);
|
|
1546
|
+
let attributeValues = attributeMatch ? findSsmlAttributePresets(attributeMatch[1], attributeMatch[2]) : void 0;
|
|
1547
|
+
if (attributeMatch && attributeValues && EXPRESS_AS_TAG_NAMES.has(attributeMatch[1].toLowerCase()) && attributeMatch[2].toLowerCase() === "style") {
|
|
1548
|
+
const voiceContext = findSsmlVoiceContext(value, offset);
|
|
1549
|
+
const voiceName = voiceContext === void 0 ? options.getOuterVoiceName?.() : voiceContext.voiceName;
|
|
1550
|
+
attributeValues = resolveExpressAsStyles(voiceName, attributeValues);
|
|
1551
|
+
}
|
|
1552
|
+
const openTagMatch = textUntilPosition.match(/<(?!\/)[a-zA-Z0-9:-]*$/);
|
|
1553
|
+
const openTagLength = openTagMatch?.[0].length ?? 0;
|
|
1554
|
+
const isAfterBracket = model.getValueInRange({
|
|
1555
|
+
startLineNumber: position.lineNumber,
|
|
1556
|
+
startColumn: position.column - 1,
|
|
1557
|
+
endLineNumber: position.lineNumber,
|
|
1558
|
+
endColumn: position.column
|
|
1559
|
+
}) === "<";
|
|
1560
|
+
const hasClosingBracket = isAfterBracket && model.getValueInRange({
|
|
1561
|
+
startLineNumber: position.lineNumber,
|
|
1562
|
+
startColumn: position.column,
|
|
1563
|
+
endLineNumber: position.lineNumber,
|
|
1564
|
+
endColumn: position.column + 1
|
|
1565
|
+
}) === ">";
|
|
1566
|
+
const range = {
|
|
1567
|
+
startLineNumber: position.lineNumber,
|
|
1568
|
+
startColumn: openTagLength > 0 ? position.column - openTagLength : position.column,
|
|
1569
|
+
endLineNumber: position.lineNumber,
|
|
1570
|
+
endColumn: hasClosingBracket ? position.column + 1 : position.column
|
|
1571
|
+
};
|
|
1572
|
+
return {
|
|
1573
|
+
suggestions: [
|
|
1574
|
+
...attributeMatch ? [] : SSML_COMPLETION_SNIPPETS.map(({ label, insertText }) => ({
|
|
1575
|
+
label,
|
|
1576
|
+
kind: monaco.languages.CompletionItemKind.Snippet,
|
|
1577
|
+
insertText,
|
|
1578
|
+
insertTextRules: monaco.languages.CompletionItemInsertTextRule.InsertAsSnippet,
|
|
1579
|
+
range
|
|
1580
|
+
})),
|
|
1581
|
+
...attributeValues?.map((value2) => ({
|
|
1582
|
+
label: value2,
|
|
1583
|
+
kind: monaco.languages.CompletionItemKind.Value,
|
|
1584
|
+
insertText: value2,
|
|
1585
|
+
range
|
|
1586
|
+
})) ?? []
|
|
1587
|
+
]
|
|
1588
|
+
};
|
|
1589
|
+
},
|
|
1590
|
+
triggerCharacters: ["<", '"', "'"]
|
|
1591
|
+
};
|
|
1592
|
+
return monaco.languages.registerCompletionItemProvider("xml", provider);
|
|
1593
|
+
}
|
|
1594
|
+
|
|
1595
|
+
// ../ssml-editor-react/src/locales.ts
|
|
1596
|
+
var EDITOR_COPY = {
|
|
1597
|
+
ja: {
|
|
1598
|
+
editorAriaLabel: "SSML\u30A8\u30C7\u30A3\u30BF\u30FC",
|
|
1599
|
+
toolbarAriaLabel: "SSML\u30C4\u30FC\u30EB\u30D0\u30FC",
|
|
1600
|
+
clearAll: "\u5168\u3066\u30AF\u30EA\u30A2",
|
|
1601
|
+
clearAllTitle: "\u97F3\u58F0\u8A2D\u5B9A\u3092\u4FDD\u6301\u3057\u3066XML\u8981\u7D20\u3092\u524A\u9664\u3057\u672C\u6587\u3092\u6B8B\u3059",
|
|
1602
|
+
undo: "\u5143\u306B\u623B\u3059",
|
|
1603
|
+
undoTitle: "\u76F4\u524D\u306E\u5909\u66F4\u3092\u5143\u306B\u623B\u3059",
|
|
1604
|
+
redo: "\u3084\u308A\u76F4\u3059",
|
|
1605
|
+
redoTitle: "\u5143\u306B\u623B\u3057\u305F\u5909\u66F4\u3092\u3084\u308A\u76F4\u3059",
|
|
1606
|
+
help: "\u8AAC\u660E",
|
|
1607
|
+
helpTitle: "\u30DC\u30BF\u30F3\u3068\u30D1\u30E9\u30E1\u30FC\u30BF\u306E\u8AAC\u660E\u3092\u8868\u793A",
|
|
1608
|
+
helpHeading: "\u30DC\u30BF\u30F3\u3068\u30D1\u30E9\u30E1\u30FC\u30BF\u306E\u8AAC\u660E",
|
|
1609
|
+
helpDescription: "\u5404\u30B3\u30F3\u30C8\u30ED\u30FC\u30EB\u306E\u6A5F\u80FD\u3068\u30D1\u30E9\u30E1\u30FC\u30BF\u3092\u78BA\u8A8D\u3067\u304D\u307E\u3059\u3002",
|
|
1610
|
+
parameters: "\u30D1\u30E9\u30E1\u30FC\u30BF",
|
|
1611
|
+
format: "\u30D5\u30A9\u30FC\u30DE\u30C3\u30C8",
|
|
1612
|
+
formatTitle: "\u672C\u6587\u306EXML\u3092\u6539\u884C\u3057\u3066\u898B\u3084\u3059\u304F\u8868\u793A",
|
|
1613
|
+
decorations: "\u88C5\u98FE",
|
|
1614
|
+
decorationsShowTitle: "\u30A4\u30F3\u30E9\u30A4\u30F3\u88C5\u98FE\u3092\u8868\u793A",
|
|
1615
|
+
decorationsHideTitle: "\u30A4\u30F3\u30E9\u30A4\u30F3\u88C5\u98FE\u3092\u975E\u8868\u793A",
|
|
1616
|
+
syntaxError: "\u69CB\u6587\u30A8\u30E9\u30FC",
|
|
1617
|
+
selectionActions: "\u9078\u629E\u7BC4\u56F2\u306E\u64CD\u4F5C",
|
|
1618
|
+
selectionCountSuffix: "\u6587\u5B57",
|
|
1619
|
+
previewSelection: "\u9078\u629E\u90E8\u5206\u3092\u8A66\u8074",
|
|
1620
|
+
previewSelectionTitle: "\u9078\u629E\u90E8\u5206\u306ESSML\u3092\u8A66\u8074",
|
|
1621
|
+
noAvailableOptions: "\u5229\u7528\u53EF\u80FD\u306A\u9078\u629E\u80A2\u304C\u3042\u308A\u307E\u305B\u3093\u3002",
|
|
1622
|
+
styleNotSupported: "\u3053\u306E\u97F3\u58F0\u306F\u30B9\u30BF\u30A4\u30EB\u6307\u5B9A\u306B\u5BFE\u5FDC\u3057\u3066\u3044\u307E\u305B\u3093",
|
|
1623
|
+
categoryEmotions: "\u611F\u60C5\u30FB\u30C8\u30FC\u30F3",
|
|
1624
|
+
categoryScenarios: "\u4F1A\u8A71\u30FB\u30B7\u30CA\u30EA\u30AA",
|
|
1625
|
+
categoryMedia: "\u30E1\u30C7\u30A3\u30A2\u30FB\u30CA\u30EC\u30FC\u30B7\u30E7\u30F3",
|
|
1626
|
+
categoryOther: "\u305D\u306E\u4ED6"
|
|
1627
|
+
},
|
|
1628
|
+
en: {
|
|
1629
|
+
editorAriaLabel: "SSML editor",
|
|
1630
|
+
toolbarAriaLabel: "SSML toolbar",
|
|
1631
|
+
clearAll: "Clear all",
|
|
1632
|
+
clearAllTitle: "Remove non-voice XML elements and keep the text and voice settings",
|
|
1633
|
+
undo: "Undo",
|
|
1634
|
+
undoTitle: "Undo the last change",
|
|
1635
|
+
redo: "Redo",
|
|
1636
|
+
redoTitle: "Redo the last undone change",
|
|
1637
|
+
help: "Help",
|
|
1638
|
+
helpTitle: "Show button and parameter descriptions",
|
|
1639
|
+
helpHeading: "Button and parameter descriptions",
|
|
1640
|
+
helpDescription: "Review what each control does and its parameters.",
|
|
1641
|
+
parameters: "Parameters",
|
|
1642
|
+
format: "Format",
|
|
1643
|
+
formatTitle: "Format the XML in the editor",
|
|
1644
|
+
decorations: "Decorations",
|
|
1645
|
+
decorationsShowTitle: "Show inline decorations",
|
|
1646
|
+
decorationsHideTitle: "Hide inline decorations",
|
|
1647
|
+
syntaxError: "Syntax error",
|
|
1648
|
+
selectionActions: "Selection actions",
|
|
1649
|
+
selectionCountSuffix: " characters",
|
|
1650
|
+
previewSelection: "Preview selection",
|
|
1651
|
+
previewSelectionTitle: "Preview the selected SSML",
|
|
1652
|
+
noAvailableOptions: "No options are available.",
|
|
1653
|
+
styleNotSupported: "This voice does not support style selection.",
|
|
1654
|
+
categoryEmotions: "Emotions / Tone",
|
|
1655
|
+
categoryScenarios: "Conversations / Scenarios",
|
|
1656
|
+
categoryMedia: "Media / Broadcast",
|
|
1657
|
+
categoryOther: "Other"
|
|
1658
|
+
}
|
|
1659
|
+
};
|
|
1660
|
+
var SSML_HOVER_COPY = {
|
|
1661
|
+
ja: {
|
|
1662
|
+
parameterHeading: "\u30D1\u30E9\u30E1\u30FC\u30BF",
|
|
1663
|
+
parametersHeading: "\u30D1\u30E9\u30E1\u30FC\u30BF",
|
|
1664
|
+
allowedValues: "\u4F7F\u7528\u3067\u304D\u308B\u5024",
|
|
1665
|
+
example: "\u4F8B",
|
|
1666
|
+
noParameters: "\u3053\u306E\u8981\u7D20\u306B\u30D1\u30E9\u30E1\u30FC\u30BF\u306F\u3042\u308A\u307E\u305B\u3093\u3002",
|
|
1667
|
+
tags: {
|
|
1668
|
+
voice: {
|
|
1669
|
+
title: "\u97F3\u58F0",
|
|
1670
|
+
description: "\u56F2\u307E\u308C\u305F\u30C6\u30AD\u30B9\u30C8\u306E\u5408\u6210\u306B\u4F7F\u7528\u3059\u308B\u97F3\u58F0\u3068\u3001\u4EFB\u610F\u306E\u97F3\u58F0\u52B9\u679C\u3092\u9078\u629E\u3057\u307E\u3059\u3002",
|
|
1671
|
+
parameters: {
|
|
1672
|
+
name: { title: "name", description: "\u97F3\u58F0\u540D\u3002\u4F8B: `en-US-JennyNeural`\u3002" },
|
|
1673
|
+
effect: { title: "effect", description: "\u4EFB\u610F\u306E\u97F3\u58F0\u52B9\u679C\u3002\u4F8B: `eq_car`\u3002" }
|
|
1674
|
+
}
|
|
1675
|
+
},
|
|
1676
|
+
prosody: {
|
|
1677
|
+
title: "\u97FB\u5F8B",
|
|
1678
|
+
description: "\u56F2\u307E\u308C\u305F\u30C6\u30AD\u30B9\u30C8\u306E\u901F\u5EA6\u3001\u30D4\u30C3\u30C1\u3001\u97F3\u91CF\u3001\u307E\u305F\u306F\u30D4\u30C3\u30C1\u66F2\u7DDA\u3092\u5909\u66F4\u3057\u307E\u3059\u3002",
|
|
1679
|
+
parameters: {
|
|
1680
|
+
rate: { title: "rate", description: "\u767A\u8A71\u901F\u5EA6\u3092\u6307\u5B9A\u3057\u307E\u3059\u3002" },
|
|
1681
|
+
pitch: { title: "pitch", description: "\u540D\u524D\u4ED8\u304D\u306E\u5024\u3001\u5272\u5408\u3001\u5468\u6CE2\u6570\u3001\u307E\u305F\u306F\u534A\u97F3\u3067\u30D4\u30C3\u30C1\u3092\u8ABF\u6574\u3057\u307E\u3059\u3002" },
|
|
1682
|
+
volume: { title: "volume", description: "\u540D\u524D\u4ED8\u304D\u306E\u5024\u3001\u5272\u5408\u3001\u307E\u305F\u306F\u30C7\u30B7\u30D9\u30EB\u5024\u3067\u97F3\u91CF\u3092\u6307\u5B9A\u3057\u307E\u3059\u3002" },
|
|
1683
|
+
contour: { title: "contour", description: "\u30C6\u30AD\u30B9\u30C8\u5185\u306E\u4F4D\u7F6E\u3054\u3068\u306E\u76F8\u5BFE\u7684\u306A\u30D4\u30C3\u30C1\u5909\u5316\u3092\u5B9A\u7FA9\u3057\u307E\u3059\u3002" },
|
|
1684
|
+
range: { title: "range", description: "\u97F3\u58F0\u306E\u30D4\u30C3\u30C1\u7BC4\u56F2\u3092\u8ABF\u6574\u3057\u307E\u3059\u3002" }
|
|
1685
|
+
}
|
|
1686
|
+
},
|
|
1687
|
+
break: {
|
|
1688
|
+
title: "\u9593",
|
|
1689
|
+
description: "\u5358\u8A9E\u3084\u305D\u306E\u4ED6\u306E\u97F3\u58F0\u30B3\u30F3\u30C6\u30F3\u30C4\u306E\u9593\u306B\u30DD\u30FC\u30BA\u3092\u633F\u5165\u3057\u307E\u3059\u3002",
|
|
1690
|
+
parameters: {
|
|
1691
|
+
time: { title: "time", description: "\u30DD\u30FC\u30BA\u306E\u9577\u3055\u3002\u4F8B: `500ms` \u307E\u305F\u306F `1s`\u3002" },
|
|
1692
|
+
strength: { title: "strength", description: "\u76F8\u5BFE\u7684\u306A\u30DD\u30FC\u30BA\u306E\u5F37\u3055\u3002" }
|
|
1693
|
+
}
|
|
1694
|
+
},
|
|
1695
|
+
"mstts:express-as": {
|
|
1696
|
+
title: "\u8868\u73FE",
|
|
1697
|
+
description: "\u56F2\u307E\u308C\u305F\u30C6\u30AD\u30B9\u30C8\u306B\u97F3\u58F0\u30B9\u30BF\u30A4\u30EB\u3001\u30B9\u30BF\u30A4\u30EB\u306E\u5F37\u3055\u3001\u307E\u305F\u306F\u5F79\u5272\u3092\u9069\u7528\u3057\u307E\u3059\u3002",
|
|
1698
|
+
parameters: {
|
|
1699
|
+
style: { title: "style", description: "\u9078\u629E\u3057\u305F\u97F3\u58F0\u304C\u5BFE\u5FDC\u3059\u308B\u97F3\u58F0\u30B9\u30BF\u30A4\u30EB\u3002\u4F8B: `cheerful`\u3002" },
|
|
1700
|
+
styledegree: { title: "styledegree", description: "\u9078\u629E\u3057\u305F\u97F3\u58F0\u30B9\u30BF\u30A4\u30EB\u306E\u5F37\u3055\u3092\u6307\u5B9A\u3057\u307E\u3059\u3002" },
|
|
1701
|
+
role: { title: "role", description: "\u5BFE\u5FDC\u3057\u3066\u3044\u308B\u5834\u5408\u306B\u97F3\u58F0\u306E\u5F79\u5272\u3092\u5909\u66F4\u3057\u307E\u3059\u3002" }
|
|
1702
|
+
}
|
|
1703
|
+
},
|
|
1704
|
+
"say-as": {
|
|
1705
|
+
title: "\u8AAD\u307F\u4E0A\u3052\u65B9",
|
|
1706
|
+
description: "\u56F2\u307E\u308C\u305F\u30C6\u30AD\u30B9\u30C8\u306E\u89E3\u91C8\u65B9\u6CD5\u3068\u8AAD\u307F\u4E0A\u3052\u65B9\u3092\u6307\u5B9A\u3057\u307E\u3059\u3002",
|
|
1707
|
+
parameters: {
|
|
1708
|
+
"interpret-as": { title: "interpret-as", description: "\u6587\u5B57\u3001\u6570\u5B57\u3001\u65E5\u4ED8\u3001\u6642\u523B\u306A\u3069\u306E\u89E3\u91C8\u3092\u6307\u5B9A\u3057\u307E\u3059\u3002" },
|
|
1709
|
+
format: { title: "format", description: "\u9078\u629E\u3057\u305F\u89E3\u91C8\u306E\u5F62\u5F0F\u3092\u88DC\u8DB3\u3057\u307E\u3059\u3002" },
|
|
1710
|
+
detail: { title: "detail", description: "\u9078\u629E\u3057\u305F\u89E3\u91C8\u306E\u8A73\u7D30\u3092\u88DC\u8DB3\u3057\u307E\u3059\u3002" }
|
|
1711
|
+
}
|
|
1712
|
+
},
|
|
1713
|
+
phoneme: {
|
|
1714
|
+
title: "\u97F3\u7D20",
|
|
1715
|
+
description: "\u6307\u5B9A\u3057\u305F\u97F3\u7D20\u8868\u8A18\u3067\u901A\u5E38\u306E\u767A\u97F3\u3092\u7F6E\u304D\u63DB\u3048\u307E\u3059\u3002",
|
|
1716
|
+
parameters: {
|
|
1717
|
+
alphabet: { title: "alphabet", description: "`ph` \u5024\u306B\u4F7F\u7528\u3059\u308B\u97F3\u7D20\u30A2\u30EB\u30D5\u30A1\u30D9\u30C3\u30C8\u3002" },
|
|
1718
|
+
ph: { title: "ph", description: "\u56F2\u307E\u308C\u305F\u30C6\u30AD\u30B9\u30C8\u306E\u97F3\u7D20\u8868\u8A18\u3002" }
|
|
1719
|
+
}
|
|
1720
|
+
},
|
|
1721
|
+
emphasis: {
|
|
1722
|
+
title: "\u5F37\u8ABF",
|
|
1723
|
+
description: "\u56F2\u307E\u308C\u305F\u30C6\u30AD\u30B9\u30C8\u3092\u5F37\u8ABF\u3057\u307E\u3059\u3002",
|
|
1724
|
+
parameters: {
|
|
1725
|
+
level: { title: "level", description: "\u5F37\u8ABF\u306E\u5EA6\u5408\u3044\u3092\u6307\u5B9A\u3057\u307E\u3059\u3002" }
|
|
1726
|
+
}
|
|
1727
|
+
},
|
|
1728
|
+
audio: {
|
|
1729
|
+
title: "\u97F3\u58F0\u30D5\u30A1\u30A4\u30EB",
|
|
1730
|
+
description: "\u5408\u6210\u7D50\u679C\u306E\u4E00\u90E8\u3068\u3057\u3066\u97F3\u58F0\u30D5\u30A1\u30A4\u30EB\u3092\u518D\u751F\u3057\u307E\u3059\u3002",
|
|
1731
|
+
parameters: {
|
|
1732
|
+
src: { title: "src", description: "\u97F3\u58F0\u30D5\u30A1\u30A4\u30EB\u306E URI\u3002" },
|
|
1733
|
+
desc: { title: "desc", description: "\u97F3\u58F0\u3092\u518D\u751F\u3067\u304D\u306A\u3044\u5834\u5408\u306B\u4F7F\u7528\u3059\u308B\u4EE3\u66FF\u30C6\u30AD\u30B9\u30C8\u3002" },
|
|
1734
|
+
clipBegin: { title: "clipBegin", description: "\u97F3\u58F0\u30D5\u30A1\u30A4\u30EB\u5185\u306E\u958B\u59CB\u4F4D\u7F6E\u3002\u4F8B: `0s`\u3002" },
|
|
1735
|
+
clipEnd: { title: "clipEnd", description: "\u97F3\u58F0\u30D5\u30A1\u30A4\u30EB\u5185\u306E\u7D42\u4E86\u4F4D\u7F6E\u3002\u4F8B: `5s`\u3002" },
|
|
1736
|
+
speed: { title: "speed", description: "\u97F3\u58F0\u30D5\u30A1\u30A4\u30EB\u306E\u518D\u751F\u901F\u5EA6\u3002\u4F8B: `1.0`\u3002" },
|
|
1737
|
+
repeatCount: { title: "repeatCount", description: "\u97F3\u58F0\u3092\u7E70\u308A\u8FD4\u3059\u56DE\u6570\u3002\u4F8B: `2`\u3002" },
|
|
1738
|
+
repeatDuration: { title: "repeatDuration", description: "\u97F3\u58F0\u3092\u7E70\u308A\u8FD4\u3059\u5408\u8A08\u6642\u9593\u3002\u4F8B: `10s`\u3002" },
|
|
1739
|
+
soundLevel: { title: "soundLevel", description: "\u30C7\u30B7\u30D9\u30EB\u5358\u4F4D\u306E\u97F3\u91CF\u8ABF\u6574\u3002\u4F8B: `-3dB`\u3002" }
|
|
1740
|
+
}
|
|
1741
|
+
},
|
|
1742
|
+
sub: {
|
|
1743
|
+
title: "\u7F6E\u63DB",
|
|
1744
|
+
description: "\u56F2\u307E\u308C\u305F\u30C6\u30AD\u30B9\u30C8\u306E\u4EE3\u308F\u308A\u306B\u5225\u540D\u30C6\u30AD\u30B9\u30C8\u3092\u8AAD\u307F\u4E0A\u3052\u307E\u3059\u3002",
|
|
1745
|
+
parameters: {
|
|
1746
|
+
alias: { title: "alias", description: "\u5143\u306E\u30C6\u30AD\u30B9\u30C8\u306E\u4EE3\u308F\u308A\u306B\u8AAD\u307F\u4E0A\u3052\u308B\u30C6\u30AD\u30B9\u30C8\u3002\u4F8B: `World Wide Web`\u3002" }
|
|
1747
|
+
}
|
|
1748
|
+
},
|
|
1749
|
+
lang: {
|
|
1750
|
+
title: "\u8A00\u8A9E",
|
|
1751
|
+
description: "\u56F2\u307E\u308C\u305F\u30C6\u30AD\u30B9\u30C8\u306E\u8AAD\u307F\u4E0A\u3052\u8A00\u8A9E\u3092\u5909\u66F4\u3057\u307E\u3059\u3002",
|
|
1752
|
+
parameters: {
|
|
1753
|
+
"xml:lang": { title: "xml:lang", description: "BCP-47 \u8A00\u8A9E\u30BF\u30B0\u3002\u4F8B: `ja-JP`\u3002" }
|
|
1754
|
+
}
|
|
1755
|
+
},
|
|
1756
|
+
mark: {
|
|
1757
|
+
title: "\u30DE\u30FC\u30AB\u30FC",
|
|
1758
|
+
description: "\u5408\u6210\u97F3\u58F0\u30B9\u30C8\u30EA\u30FC\u30E0\u306B\u30AB\u30B9\u30BF\u30E0\u30DE\u30FC\u30AB\u30FC\u3092\u633F\u5165\u3057\u307E\u3059\u3002",
|
|
1759
|
+
parameters: {
|
|
1760
|
+
name: { title: "name", description: "\u30A2\u30D7\u30EA\u30B1\u30FC\u30B7\u30E7\u30F3\u3067\u5B9A\u7FA9\u3057\u305F\u30DE\u30FC\u30AB\u30FC\u540D\u3002\u4F8B: `chapter-1`\u3002" }
|
|
1761
|
+
}
|
|
1762
|
+
},
|
|
1763
|
+
bookmark: {
|
|
1764
|
+
title: "\u30D6\u30C3\u30AF\u30DE\u30FC\u30AF",
|
|
1765
|
+
description: "\u5408\u6210\u97F3\u58F0\u30B9\u30C8\u30EA\u30FC\u30E0\u306B\u30D6\u30C3\u30AF\u30DE\u30FC\u30AF\u30DE\u30FC\u30AB\u30FC\u3092\u633F\u5165\u3057\u307E\u3059\u3002",
|
|
1766
|
+
parameters: {
|
|
1767
|
+
mark: { title: "mark", description: "\u30A2\u30D7\u30EA\u30B1\u30FC\u30B7\u30E7\u30F3\u3067\u5B9A\u7FA9\u3057\u305F\u30D6\u30C3\u30AF\u30DE\u30FC\u30AF\u540D\u3002\u4F8B: `chapter-1`\u3002" }
|
|
1768
|
+
}
|
|
1769
|
+
},
|
|
1770
|
+
lexicon: {
|
|
1771
|
+
title: "\u767A\u97F3\u8F9E\u66F8",
|
|
1772
|
+
description: "\u5408\u6210\u6587\u66F8\u306B\u767A\u97F3\u8F9E\u66F8\u3092\u95A2\u9023\u4ED8\u3051\u307E\u3059\u3002",
|
|
1773
|
+
parameters: {
|
|
1774
|
+
uri: { title: "uri", description: "\u767A\u97F3\u8F9E\u66F8\u306E URI\u3002" }
|
|
1775
|
+
}
|
|
1776
|
+
},
|
|
1777
|
+
p: { title: "\u6BB5\u843D", description: "\u30C6\u30AD\u30B9\u30C8\u3092\u6BB5\u843D\u3068\u3057\u3066\u307E\u3068\u3081\u307E\u3059\u3002", parameters: {} },
|
|
1778
|
+
s: { title: "\u6587", description: "\u30C6\u30AD\u30B9\u30C8\u3092\u6587\u3068\u3057\u3066\u307E\u3068\u3081\u307E\u3059\u3002", parameters: {} },
|
|
1779
|
+
w: { title: "\u5358\u8A9E", description: "\u30C6\u30AD\u30B9\u30C8\u3092\u5358\u8A9E\u3068\u3057\u3066\u307E\u3068\u3081\u307E\u3059\u3002", parameters: {} },
|
|
1780
|
+
"mstts:silence": {
|
|
1781
|
+
title: "\u7121\u97F3",
|
|
1782
|
+
description: "\u30C6\u30AD\u30B9\u30C8\u306E\u524D\u5F8C\u3001\u307E\u305F\u306F\u53E5\u8AAD\u70B9\u306E\u5883\u754C\u306B\u6307\u5B9A\u3057\u305F\u7121\u97F3\u3092\u8FFD\u52A0\u3057\u307E\u3059\u3002",
|
|
1783
|
+
parameters: {
|
|
1784
|
+
type: { title: "type", description: "\u7121\u97F3\u306E\u4F4D\u7F6E\u307E\u305F\u306F\u53E5\u8AAD\u70B9\u306E\u5883\u754C\u3002" },
|
|
1785
|
+
value: { title: "value", description: "\u7121\u97F3\u306E\u9577\u3055\u3002\u4F8B: `300ms`\u3002" }
|
|
1786
|
+
}
|
|
1787
|
+
},
|
|
1788
|
+
"mstts:viseme": {
|
|
1789
|
+
title: "\u30D3\u30BC\u30FC\u30E0",
|
|
1790
|
+
description: "\u5408\u6210\u97F3\u58F0\u306E\u30D3\u30BC\u30FC\u30E0\u30A4\u30D9\u30F3\u30C8\u3092\u8981\u6C42\u3057\u307E\u3059\u3002",
|
|
1791
|
+
parameters: {
|
|
1792
|
+
type: { title: "type", description: "\u30D3\u30BC\u30FC\u30E0\u30A4\u30D9\u30F3\u30C8\u306E\u5F62\u5F0F\u3002" }
|
|
1793
|
+
}
|
|
1794
|
+
}
|
|
1795
|
+
}
|
|
1796
|
+
},
|
|
1797
|
+
en: {
|
|
1798
|
+
parameterHeading: "Parameter",
|
|
1799
|
+
parametersHeading: "Parameters",
|
|
1800
|
+
allowedValues: "Allowed values",
|
|
1801
|
+
example: "Example",
|
|
1802
|
+
noParameters: "This element has no parameters.",
|
|
1803
|
+
tags: {
|
|
1804
|
+
voice: {
|
|
1805
|
+
title: "Voice",
|
|
1806
|
+
description: "Selects the voice and optional voice effect used to synthesize the enclosed text.",
|
|
1807
|
+
parameters: {
|
|
1808
|
+
name: { title: "name", description: "The voice name, such as `en-US-JennyNeural`." },
|
|
1809
|
+
effect: { title: "effect", description: "An optional voice effect, such as `eq_car`." }
|
|
1810
|
+
}
|
|
1811
|
+
},
|
|
1812
|
+
prosody: {
|
|
1813
|
+
title: "Prosody",
|
|
1814
|
+
description: "Changes the speaking rate, pitch, volume, or pitch contour of the enclosed text.",
|
|
1815
|
+
parameters: {
|
|
1816
|
+
rate: { title: "rate", description: "Controls speaking speed." },
|
|
1817
|
+
pitch: {
|
|
1818
|
+
title: "pitch",
|
|
1819
|
+
description: "Adjusts pitch using a named value, percentage, frequency, or semitone value."
|
|
1820
|
+
},
|
|
1821
|
+
volume: {
|
|
1822
|
+
title: "volume",
|
|
1823
|
+
description: "Controls loudness using a named value, percentage, or decibel value."
|
|
1824
|
+
},
|
|
1825
|
+
contour: {
|
|
1826
|
+
title: "contour",
|
|
1827
|
+
description: "Defines a sequence of relative pitch changes at positions in the text."
|
|
1828
|
+
},
|
|
1829
|
+
range: { title: "range", description: "Adjusts the pitch range of the voice." }
|
|
1830
|
+
}
|
|
1831
|
+
},
|
|
1832
|
+
break: {
|
|
1833
|
+
title: "Break",
|
|
1834
|
+
description: "Inserts a pause between words or other spoken content.",
|
|
1835
|
+
parameters: {
|
|
1836
|
+
time: { title: "time", description: "The pause duration, for example `500ms` or `1s`." },
|
|
1837
|
+
strength: { title: "strength", description: "The relative pause strength." }
|
|
1838
|
+
}
|
|
1839
|
+
},
|
|
1840
|
+
"mstts:express-as": {
|
|
1841
|
+
title: "Express-as",
|
|
1842
|
+
description: "Applies a speaking style, style degree, or role to the enclosed text.",
|
|
1843
|
+
parameters: {
|
|
1844
|
+
style: {
|
|
1845
|
+
title: "style",
|
|
1846
|
+
description: "The speaking style supported by the selected voice, such as `cheerful`."
|
|
1847
|
+
},
|
|
1848
|
+
styledegree: { title: "styledegree", description: "Controls the intensity of the selected speaking style." },
|
|
1849
|
+
role: { title: "role", description: "Changes the speaking role when supported by the selected voice." }
|
|
1850
|
+
}
|
|
1851
|
+
},
|
|
1852
|
+
"say-as": {
|
|
1853
|
+
title: "Say-as",
|
|
1854
|
+
description: "Controls how the enclosed text is interpreted and spoken.",
|
|
1855
|
+
parameters: {
|
|
1856
|
+
"interpret-as": {
|
|
1857
|
+
title: "interpret-as",
|
|
1858
|
+
description: "Specifies the interpretation, such as characters, digits, date, or time."
|
|
1859
|
+
},
|
|
1860
|
+
format: { title: "format", description: "Provides a format hint for the selected interpretation." },
|
|
1861
|
+
detail: {
|
|
1862
|
+
title: "detail",
|
|
1863
|
+
description: "Provides an additional detail hint for the selected interpretation."
|
|
1864
|
+
}
|
|
1865
|
+
}
|
|
1866
|
+
},
|
|
1867
|
+
phoneme: {
|
|
1868
|
+
title: "Phoneme",
|
|
1869
|
+
description: "Replaces normal pronunciation with the supplied phonetic pronunciation.",
|
|
1870
|
+
parameters: {
|
|
1871
|
+
alphabet: { title: "alphabet", description: "The phonetic alphabet used by the `ph` value." },
|
|
1872
|
+
ph: { title: "ph", description: "The phonetic pronunciation for the enclosed text." }
|
|
1873
|
+
}
|
|
1874
|
+
},
|
|
1875
|
+
emphasis: {
|
|
1876
|
+
title: "Emphasis",
|
|
1877
|
+
description: "Adds emphasis to the enclosed text.",
|
|
1878
|
+
parameters: {
|
|
1879
|
+
level: { title: "level", description: "Controls the amount of emphasis." }
|
|
1880
|
+
}
|
|
1881
|
+
},
|
|
1882
|
+
audio: {
|
|
1883
|
+
title: "Audio",
|
|
1884
|
+
description: "Plays an audio file as part of the synthesized output.",
|
|
1885
|
+
parameters: {
|
|
1886
|
+
src: { title: "src", description: "The URI of the audio file." },
|
|
1887
|
+
desc: { title: "desc", description: "Alternative text to use if the audio cannot be played." },
|
|
1888
|
+
clipBegin: { title: "clipBegin", description: "The starting offset within the audio file." },
|
|
1889
|
+
clipEnd: { title: "clipEnd", description: "The ending offset within the audio file." },
|
|
1890
|
+
speed: { title: "speed", description: "The playback speed of the audio file." },
|
|
1891
|
+
repeatCount: { title: "repeatCount", description: "The number of times to repeat the audio." },
|
|
1892
|
+
repeatDuration: {
|
|
1893
|
+
title: "repeatDuration",
|
|
1894
|
+
description: "The total duration for which the audio may repeat."
|
|
1895
|
+
},
|
|
1896
|
+
soundLevel: { title: "soundLevel", description: "The audio volume adjustment in decibels." }
|
|
1897
|
+
}
|
|
1898
|
+
},
|
|
1899
|
+
sub: {
|
|
1900
|
+
title: "Substitution",
|
|
1901
|
+
description: "Substitutes the alias text when speaking the enclosed text.",
|
|
1902
|
+
parameters: {
|
|
1903
|
+
alias: { title: "alias", description: "The text to speak instead of the enclosed text." }
|
|
1904
|
+
}
|
|
1905
|
+
},
|
|
1906
|
+
lang: {
|
|
1907
|
+
title: "Language",
|
|
1908
|
+
description: "Changes the language used for the enclosed text.",
|
|
1909
|
+
parameters: {
|
|
1910
|
+
"xml:lang": { title: "xml:lang", description: "The BCP-47 language tag." }
|
|
1911
|
+
}
|
|
1912
|
+
},
|
|
1913
|
+
mark: {
|
|
1914
|
+
title: "Mark",
|
|
1915
|
+
description: "Inserts a custom marker into the synthesized audio stream.",
|
|
1916
|
+
parameters: {
|
|
1917
|
+
name: { title: "name", description: "The application-defined marker name." }
|
|
1918
|
+
}
|
|
1919
|
+
},
|
|
1920
|
+
bookmark: {
|
|
1921
|
+
title: "Bookmark",
|
|
1922
|
+
description: "Inserts a bookmark marker into the synthesized audio stream.",
|
|
1923
|
+
parameters: {
|
|
1924
|
+
mark: { title: "mark", description: "The application-defined bookmark name." }
|
|
1925
|
+
}
|
|
1926
|
+
},
|
|
1927
|
+
lexicon: {
|
|
1928
|
+
title: "Lexicon",
|
|
1929
|
+
description: "Associates a pronunciation lexicon with the synthesized document.",
|
|
1930
|
+
parameters: {
|
|
1931
|
+
uri: { title: "uri", description: "The URI of the pronunciation lexicon." }
|
|
1932
|
+
}
|
|
1933
|
+
},
|
|
1934
|
+
p: { title: "Paragraph", description: "Groups text into a paragraph.", parameters: {} },
|
|
1935
|
+
s: { title: "Sentence", description: "Groups text into a sentence.", parameters: {} },
|
|
1936
|
+
w: { title: "Word", description: "Groups text into a word.", parameters: {} },
|
|
1937
|
+
"mstts:silence": {
|
|
1938
|
+
title: "Silence",
|
|
1939
|
+
description: "Adds a specified silence before or after text or at a punctuation boundary.",
|
|
1940
|
+
parameters: {
|
|
1941
|
+
type: { title: "type", description: "The silence position or punctuation boundary." },
|
|
1942
|
+
value: { title: "value", description: "The silence duration, for example `300ms`." }
|
|
1943
|
+
}
|
|
1944
|
+
},
|
|
1945
|
+
"mstts:viseme": {
|
|
1946
|
+
title: "Viseme",
|
|
1947
|
+
description: "Requests viseme events for the synthesized audio.",
|
|
1948
|
+
parameters: {
|
|
1949
|
+
type: { title: "type", description: "The viseme event format." }
|
|
1950
|
+
}
|
|
1951
|
+
}
|
|
1952
|
+
}
|
|
1953
|
+
}
|
|
1954
|
+
};
|
|
1955
|
+
|
|
1956
|
+
// ../ssml-editor-react/src/ssmlHover.ts
|
|
1957
|
+
var {
|
|
1958
|
+
BREAK_STRENGTH_PRESETS: BREAK_STRENGTH_PRESETS2,
|
|
1959
|
+
EMPHASIS_LEVEL_PRESETS: EMPHASIS_LEVEL_PRESETS2,
|
|
1960
|
+
PHONEME_ALPHABET_PRESETS: PHONEME_ALPHABET_PRESETS2,
|
|
1961
|
+
PROSODY_RATE_VALUES: PROSODY_RATE_VALUES2,
|
|
1962
|
+
PROSODY_VOLUME_PRESETS: PROSODY_VOLUME_PRESETS2,
|
|
1963
|
+
SILENCE_TYPE_PRESETS: SILENCE_TYPE_PRESETS2,
|
|
1964
|
+
SSML_PRESET_EXAMPLES: SSML_PRESET_EXAMPLES2,
|
|
1965
|
+
VISEME_TYPE_PRESETS: VISEME_TYPE_PRESETS2
|
|
1966
|
+
} = ssmlPresets_exports;
|
|
1967
|
+
var SSML_TAG_DEFINITIONS = [
|
|
1968
|
+
{
|
|
1969
|
+
name: "voice",
|
|
1970
|
+
description: "Selects the voice and optional voice effect used to synthesize the enclosed text.",
|
|
1971
|
+
parameters: [
|
|
1972
|
+
{
|
|
1973
|
+
name: "name",
|
|
1974
|
+
description: "The voice name, such as `en-US-JennyNeural`.",
|
|
1975
|
+
example: "en-US-JennyNeural"
|
|
1976
|
+
},
|
|
1977
|
+
{
|
|
1978
|
+
name: "effect",
|
|
1979
|
+
description: "An optional voice effect, such as `eq_car`."
|
|
1980
|
+
}
|
|
1981
|
+
]
|
|
1982
|
+
},
|
|
1983
|
+
{
|
|
1984
|
+
name: "prosody",
|
|
1985
|
+
description: "Changes the speaking rate, pitch, volume, or pitch contour of the enclosed text.",
|
|
1986
|
+
parameters: [
|
|
1987
|
+
{
|
|
1988
|
+
name: "rate",
|
|
1989
|
+
description: "Controls speaking speed.",
|
|
1990
|
+
values: PROSODY_RATE_VALUES2,
|
|
1991
|
+
example: SSML_PRESET_EXAMPLES2.prosodyRate
|
|
1992
|
+
},
|
|
1993
|
+
{
|
|
1994
|
+
name: "pitch",
|
|
1995
|
+
description: "Adjusts pitch using a named value, percentage, frequency, or semitone value.",
|
|
1996
|
+
example: SSML_PRESET_EXAMPLES2.prosodyPitch
|
|
1997
|
+
},
|
|
1998
|
+
{
|
|
1999
|
+
name: "volume",
|
|
2000
|
+
description: "Controls loudness using a named value, percentage, or decibel value.",
|
|
2001
|
+
values: PROSODY_VOLUME_PRESETS2,
|
|
2002
|
+
example: SSML_PRESET_EXAMPLES2.prosodyVolume
|
|
2003
|
+
},
|
|
2004
|
+
{
|
|
2005
|
+
name: "contour",
|
|
2006
|
+
description: "Defines a sequence of relative pitch changes at positions in the text.",
|
|
2007
|
+
example: "(0%,+0st) (100%,+2st)"
|
|
2008
|
+
},
|
|
2009
|
+
{
|
|
2010
|
+
name: "range",
|
|
2011
|
+
description: "Adjusts the pitch range of the voice.",
|
|
2012
|
+
example: "+2st"
|
|
2013
|
+
}
|
|
2014
|
+
]
|
|
2015
|
+
},
|
|
2016
|
+
{
|
|
2017
|
+
name: "break",
|
|
2018
|
+
description: "Inserts a pause between words or other spoken content.",
|
|
2019
|
+
parameters: [
|
|
2020
|
+
{
|
|
2021
|
+
name: "time",
|
|
2022
|
+
description: "The pause duration, for example `500ms` or `1s`.",
|
|
2023
|
+
example: SSML_PRESET_EXAMPLES2.breakTime
|
|
2024
|
+
},
|
|
2025
|
+
{
|
|
2026
|
+
name: "strength",
|
|
2027
|
+
description: "The relative pause strength.",
|
|
2028
|
+
values: BREAK_STRENGTH_PRESETS2
|
|
2029
|
+
}
|
|
2030
|
+
]
|
|
2031
|
+
},
|
|
2032
|
+
{
|
|
2033
|
+
name: "mstts:express-as",
|
|
2034
|
+
aliases: ["express-as", "expressAs"],
|
|
2035
|
+
description: "Applies a speaking style, style degree, or role to the enclosed text.",
|
|
2036
|
+
parameters: [
|
|
2037
|
+
{
|
|
2038
|
+
name: "style",
|
|
2039
|
+
description: "The speaking style supported by the selected voice, such as `cheerful`.",
|
|
2040
|
+
example: SSML_PRESET_EXAMPLES2.expressAsStyle
|
|
2041
|
+
},
|
|
2042
|
+
{
|
|
2043
|
+
name: "styledegree",
|
|
2044
|
+
aliases: ["style-degree", "styleDegree"],
|
|
2045
|
+
description: "Controls the intensity of the selected speaking style.",
|
|
2046
|
+
example: "1.5"
|
|
2047
|
+
},
|
|
2048
|
+
{
|
|
2049
|
+
name: "role",
|
|
2050
|
+
description: "Changes the speaking role when supported by the selected voice.",
|
|
2051
|
+
example: "YoungAdultFemale"
|
|
2052
|
+
}
|
|
2053
|
+
]
|
|
2054
|
+
},
|
|
2055
|
+
{
|
|
2056
|
+
name: "say-as",
|
|
2057
|
+
aliases: ["sayAs"],
|
|
2058
|
+
description: "Controls how the enclosed text is interpreted and spoken.",
|
|
2059
|
+
parameters: [
|
|
2060
|
+
{
|
|
2061
|
+
name: "interpret-as",
|
|
2062
|
+
description: "Specifies the interpretation, such as characters, digits, date, or time.",
|
|
2063
|
+
example: "characters"
|
|
2064
|
+
},
|
|
2065
|
+
{
|
|
2066
|
+
name: "format",
|
|
2067
|
+
description: "Provides a format hint for the selected interpretation."
|
|
2068
|
+
},
|
|
2069
|
+
{
|
|
2070
|
+
name: "detail",
|
|
2071
|
+
description: "Provides an additional detail hint for the selected interpretation."
|
|
2072
|
+
}
|
|
2073
|
+
]
|
|
2074
|
+
},
|
|
2075
|
+
{
|
|
2076
|
+
name: "phoneme",
|
|
2077
|
+
description: "Replaces normal pronunciation with the supplied phonetic pronunciation.",
|
|
2078
|
+
parameters: [
|
|
2079
|
+
{
|
|
2080
|
+
name: "alphabet",
|
|
2081
|
+
description: "The phonetic alphabet used by the `ph` value.",
|
|
2082
|
+
values: PHONEME_ALPHABET_PRESETS2,
|
|
2083
|
+
example: SSML_PRESET_EXAMPLES2.phonemeAlphabet
|
|
2084
|
+
},
|
|
2085
|
+
{
|
|
2086
|
+
name: "ph",
|
|
2087
|
+
description: "The phonetic pronunciation for the enclosed text.",
|
|
2088
|
+
example: "h\u0259\u02C8lo\u028A"
|
|
2089
|
+
}
|
|
2090
|
+
]
|
|
2091
|
+
},
|
|
2092
|
+
{
|
|
2093
|
+
name: "emphasis",
|
|
2094
|
+
description: "Adds emphasis to the enclosed text.",
|
|
2095
|
+
parameters: [
|
|
2096
|
+
{
|
|
2097
|
+
name: "level",
|
|
2098
|
+
description: "Controls the amount of emphasis.",
|
|
2099
|
+
values: EMPHASIS_LEVEL_PRESETS2
|
|
2100
|
+
}
|
|
2101
|
+
]
|
|
2102
|
+
},
|
|
2103
|
+
{
|
|
2104
|
+
name: "audio",
|
|
2105
|
+
description: "Plays an audio file as part of the synthesized output.",
|
|
2106
|
+
parameters: [
|
|
2107
|
+
{
|
|
2108
|
+
name: "src",
|
|
2109
|
+
description: "The URI of the audio file.",
|
|
2110
|
+
example: "https://example.com/intro.wav"
|
|
2111
|
+
},
|
|
2112
|
+
{
|
|
2113
|
+
name: "desc",
|
|
2114
|
+
description: "Alternative text to use if the audio cannot be played."
|
|
2115
|
+
},
|
|
2116
|
+
{
|
|
2117
|
+
name: "clipBegin",
|
|
2118
|
+
description: "The starting offset within the audio file.",
|
|
2119
|
+
example: "0s"
|
|
2120
|
+
},
|
|
2121
|
+
{
|
|
2122
|
+
name: "clipEnd",
|
|
2123
|
+
description: "The ending offset within the audio file.",
|
|
2124
|
+
example: "5s"
|
|
2125
|
+
},
|
|
2126
|
+
{
|
|
2127
|
+
name: "speed",
|
|
2128
|
+
description: "The playback speed of the audio file.",
|
|
2129
|
+
example: "1.0"
|
|
2130
|
+
},
|
|
2131
|
+
{
|
|
2132
|
+
name: "repeatCount",
|
|
2133
|
+
description: "The number of times to repeat the audio.",
|
|
2134
|
+
example: "2"
|
|
2135
|
+
},
|
|
2136
|
+
{
|
|
2137
|
+
name: "repeatDuration",
|
|
2138
|
+
description: "The total duration for which the audio may repeat.",
|
|
2139
|
+
example: "10s"
|
|
2140
|
+
},
|
|
2141
|
+
{
|
|
2142
|
+
name: "soundLevel",
|
|
2143
|
+
description: "The audio volume adjustment in decibels.",
|
|
2144
|
+
example: "-3dB"
|
|
2145
|
+
}
|
|
2146
|
+
]
|
|
2147
|
+
},
|
|
2148
|
+
{
|
|
2149
|
+
name: "sub",
|
|
2150
|
+
description: "Substitutes the alias text when speaking the enclosed text.",
|
|
2151
|
+
parameters: [
|
|
2152
|
+
{
|
|
2153
|
+
name: "alias",
|
|
2154
|
+
description: "The text to speak instead of the enclosed text.",
|
|
2155
|
+
example: "World Wide Web"
|
|
2156
|
+
}
|
|
2157
|
+
]
|
|
2158
|
+
},
|
|
2159
|
+
{
|
|
2160
|
+
name: "lang",
|
|
2161
|
+
description: "Changes the language used for the enclosed text.",
|
|
2162
|
+
parameters: [
|
|
2163
|
+
{
|
|
2164
|
+
name: "xml:lang",
|
|
2165
|
+
aliases: ["lang"],
|
|
2166
|
+
description: "The BCP-47 language tag.",
|
|
2167
|
+
example: "ja-JP"
|
|
2168
|
+
}
|
|
2169
|
+
]
|
|
2170
|
+
},
|
|
2171
|
+
{
|
|
2172
|
+
name: "mark",
|
|
2173
|
+
description: "Inserts a custom marker into the synthesized audio stream.",
|
|
2174
|
+
parameters: [
|
|
2175
|
+
{
|
|
2176
|
+
name: "name",
|
|
2177
|
+
description: "The application-defined marker name.",
|
|
2178
|
+
example: "chapter-1"
|
|
2179
|
+
}
|
|
2180
|
+
]
|
|
2181
|
+
},
|
|
2182
|
+
{
|
|
2183
|
+
name: "bookmark",
|
|
2184
|
+
description: "Inserts a bookmark marker into the synthesized audio stream.",
|
|
2185
|
+
parameters: [
|
|
2186
|
+
{
|
|
2187
|
+
name: "mark",
|
|
2188
|
+
description: "The application-defined bookmark name.",
|
|
2189
|
+
example: "chapter-1"
|
|
2190
|
+
}
|
|
2191
|
+
]
|
|
2192
|
+
},
|
|
2193
|
+
{
|
|
2194
|
+
name: "lexicon",
|
|
2195
|
+
description: "Associates a pronunciation lexicon with the synthesized document.",
|
|
2196
|
+
parameters: [
|
|
2197
|
+
{
|
|
2198
|
+
name: "uri",
|
|
2199
|
+
description: "The URI of the pronunciation lexicon.",
|
|
2200
|
+
example: "https://example.com/lexicon.pls"
|
|
2201
|
+
}
|
|
2202
|
+
]
|
|
2203
|
+
},
|
|
2204
|
+
{
|
|
2205
|
+
name: "p",
|
|
2206
|
+
description: "Groups text into a paragraph.",
|
|
2207
|
+
parameters: []
|
|
2208
|
+
},
|
|
2209
|
+
{
|
|
2210
|
+
name: "s",
|
|
2211
|
+
description: "Groups text into a sentence.",
|
|
2212
|
+
parameters: []
|
|
2213
|
+
},
|
|
2214
|
+
{
|
|
2215
|
+
name: "w",
|
|
2216
|
+
description: "Groups text into a word.",
|
|
2217
|
+
parameters: []
|
|
2218
|
+
},
|
|
2219
|
+
{
|
|
2220
|
+
name: "mstts:silence",
|
|
2221
|
+
aliases: ["silence"],
|
|
2222
|
+
description: "Adds a specified silence before or after text or at a punctuation boundary.",
|
|
2223
|
+
parameters: [
|
|
2224
|
+
{
|
|
2225
|
+
name: "type",
|
|
2226
|
+
description: "The silence position or punctuation boundary.",
|
|
2227
|
+
values: SILENCE_TYPE_PRESETS2
|
|
2228
|
+
},
|
|
2229
|
+
{
|
|
2230
|
+
name: "value",
|
|
2231
|
+
description: "The silence duration, for example `300ms`.",
|
|
2232
|
+
example: SSML_PRESET_EXAMPLES2.silenceValue
|
|
2233
|
+
}
|
|
2234
|
+
]
|
|
2235
|
+
},
|
|
2236
|
+
{
|
|
2237
|
+
name: "mstts:viseme",
|
|
2238
|
+
aliases: ["viseme"],
|
|
2239
|
+
description: "Requests viseme events for the synthesized audio.",
|
|
2240
|
+
parameters: [
|
|
2241
|
+
{
|
|
2242
|
+
name: "type",
|
|
2243
|
+
description: "The viseme event format.",
|
|
2244
|
+
values: VISEME_TYPE_PRESETS2
|
|
2245
|
+
}
|
|
2246
|
+
]
|
|
2247
|
+
}
|
|
2248
|
+
];
|
|
2249
|
+
var definitionsByName = /* @__PURE__ */ new Map();
|
|
2250
|
+
for (const definition of SSML_TAG_DEFINITIONS) {
|
|
2251
|
+
definitionsByName.set(definition.name, definition);
|
|
2252
|
+
for (const alias of definition.aliases ?? []) {
|
|
2253
|
+
definitionsByName.set(alias, definition);
|
|
2254
|
+
}
|
|
2255
|
+
}
|
|
2256
|
+
function isXmlNameStart2(value) {
|
|
2257
|
+
return value !== void 0 && /[A-Za-z_]/.test(value);
|
|
2258
|
+
}
|
|
2259
|
+
function isXmlNameCharacter2(value) {
|
|
2260
|
+
return value !== void 0 && /[A-Za-z0-9_.:-]/.test(value);
|
|
2261
|
+
}
|
|
2262
|
+
function isXmlWhitespace2(value) {
|
|
2263
|
+
return value === " " || value === " " || value === "\r" || value === "\n";
|
|
2264
|
+
}
|
|
2265
|
+
function positionToOffset(source, lineNumber, column) {
|
|
2266
|
+
if (!Number.isInteger(lineNumber) || !Number.isInteger(column) || lineNumber < 1 || column < 1) {
|
|
2267
|
+
return void 0;
|
|
2268
|
+
}
|
|
2269
|
+
let lineStart = 0;
|
|
2270
|
+
for (let line = 1; line < lineNumber; line += 1) {
|
|
2271
|
+
const newline = source.indexOf("\n", lineStart);
|
|
2272
|
+
if (newline === -1) {
|
|
2273
|
+
return void 0;
|
|
2274
|
+
}
|
|
2275
|
+
lineStart = newline + 1;
|
|
2276
|
+
}
|
|
2277
|
+
const lineEnd = source.indexOf("\n", lineStart);
|
|
2278
|
+
const lineLength = lineEnd === -1 ? source.length - lineStart : lineEnd - lineStart;
|
|
2279
|
+
if (column > lineLength + 1) {
|
|
2280
|
+
return void 0;
|
|
2281
|
+
}
|
|
2282
|
+
return lineStart + column - 1;
|
|
2283
|
+
}
|
|
2284
|
+
function offsetToPosition(source, offset) {
|
|
2285
|
+
const lastNewline = source.lastIndexOf("\n", offset - 1);
|
|
2286
|
+
const lineNumber = source.slice(0, offset).split("\n").length;
|
|
2287
|
+
return {
|
|
2288
|
+
lineNumber,
|
|
2289
|
+
column: offset - lastNewline
|
|
2290
|
+
};
|
|
2291
|
+
}
|
|
2292
|
+
function toRange(source, token) {
|
|
2293
|
+
const start = offsetToPosition(source, token.start);
|
|
2294
|
+
const end = offsetToPosition(source, token.end);
|
|
2295
|
+
return {
|
|
2296
|
+
startLineNumber: start.lineNumber,
|
|
2297
|
+
startColumn: start.column,
|
|
2298
|
+
endLineNumber: end.lineNumber,
|
|
2299
|
+
endColumn: end.column
|
|
2300
|
+
};
|
|
2301
|
+
}
|
|
2302
|
+
function containsOffset(token, offset) {
|
|
2303
|
+
return offset >= token.start && offset < token.end;
|
|
2304
|
+
}
|
|
2305
|
+
function findTagEnd3(source, start) {
|
|
2306
|
+
let quote;
|
|
2307
|
+
for (let index = start; index < source.length; index += 1) {
|
|
2308
|
+
const character = source[index];
|
|
2309
|
+
if (quote !== void 0) {
|
|
2310
|
+
if (character === quote) {
|
|
2311
|
+
quote = void 0;
|
|
2312
|
+
}
|
|
2313
|
+
} else if (character === '"' || character === "'") {
|
|
2314
|
+
quote = character;
|
|
2315
|
+
} else if (character === ">") {
|
|
2316
|
+
return index;
|
|
2317
|
+
}
|
|
2318
|
+
}
|
|
2319
|
+
return void 0;
|
|
2320
|
+
}
|
|
2321
|
+
function parseTag(source, start, contentEnd, tokenEnd) {
|
|
2322
|
+
let index = start + 1;
|
|
2323
|
+
let closing = false;
|
|
2324
|
+
if (source[index] === "/") {
|
|
2325
|
+
closing = true;
|
|
2326
|
+
index += 1;
|
|
2327
|
+
}
|
|
2328
|
+
while (index < contentEnd && isXmlWhitespace2(source[index])) {
|
|
2329
|
+
index += 1;
|
|
2330
|
+
}
|
|
2331
|
+
if (!isXmlNameStart2(source[index])) {
|
|
2332
|
+
return void 0;
|
|
2333
|
+
}
|
|
2334
|
+
const nameStart = index;
|
|
2335
|
+
index += 1;
|
|
2336
|
+
while (index < contentEnd && isXmlNameCharacter2(source[index])) {
|
|
2337
|
+
index += 1;
|
|
2338
|
+
}
|
|
2339
|
+
const nameEnd = index;
|
|
2340
|
+
const attributes = [];
|
|
2341
|
+
if (!closing) {
|
|
2342
|
+
while (index < contentEnd) {
|
|
2343
|
+
while (index < contentEnd && isXmlWhitespace2(source[index])) {
|
|
2344
|
+
index += 1;
|
|
2345
|
+
}
|
|
2346
|
+
if (index >= contentEnd || source[index] === "/") {
|
|
2347
|
+
break;
|
|
2348
|
+
}
|
|
2349
|
+
if (!isXmlNameStart2(source[index])) {
|
|
2350
|
+
index += 1;
|
|
2351
|
+
continue;
|
|
2352
|
+
}
|
|
2353
|
+
const attributeStart = index;
|
|
2354
|
+
index += 1;
|
|
2355
|
+
while (index < contentEnd && isXmlNameCharacter2(source[index])) {
|
|
2356
|
+
index += 1;
|
|
2357
|
+
}
|
|
2358
|
+
const attributeEnd = index;
|
|
2359
|
+
while (index < contentEnd && isXmlWhitespace2(source[index])) {
|
|
2360
|
+
index += 1;
|
|
2361
|
+
}
|
|
2362
|
+
let value;
|
|
2363
|
+
if (source[index] === "=") {
|
|
2364
|
+
index += 1;
|
|
2365
|
+
while (index < contentEnd && isXmlWhitespace2(source[index])) {
|
|
2366
|
+
index += 1;
|
|
2367
|
+
}
|
|
2368
|
+
const quote = source[index];
|
|
2369
|
+
if (quote === '"' || quote === "'") {
|
|
2370
|
+
index += 1;
|
|
2371
|
+
const valueStart = index;
|
|
2372
|
+
while (index < contentEnd && source[index] !== quote) {
|
|
2373
|
+
index += 1;
|
|
2374
|
+
}
|
|
2375
|
+
value = { start: valueStart, end: index };
|
|
2376
|
+
if (index < contentEnd) {
|
|
2377
|
+
index += 1;
|
|
2378
|
+
}
|
|
2379
|
+
} else {
|
|
2380
|
+
const valueStart = index;
|
|
2381
|
+
while (index < contentEnd && !isXmlWhitespace2(source[index]) && source[index] !== "/") {
|
|
2382
|
+
index += 1;
|
|
2383
|
+
}
|
|
2384
|
+
value = { start: valueStart, end: index };
|
|
2385
|
+
}
|
|
2386
|
+
}
|
|
2387
|
+
attributes.push({
|
|
2388
|
+
name: { start: attributeStart, end: attributeEnd },
|
|
2389
|
+
value
|
|
2390
|
+
});
|
|
2391
|
+
}
|
|
2392
|
+
}
|
|
2393
|
+
return {
|
|
2394
|
+
name: source.slice(nameStart, nameEnd),
|
|
2395
|
+
nameRange: { start: nameStart, end: nameEnd },
|
|
2396
|
+
start,
|
|
2397
|
+
end: tokenEnd,
|
|
2398
|
+
closing,
|
|
2399
|
+
attributes
|
|
2400
|
+
};
|
|
2401
|
+
}
|
|
2402
|
+
function findTagAtOffset(source, offset) {
|
|
2403
|
+
let searchStart = 0;
|
|
2404
|
+
while (searchStart < source.length) {
|
|
2405
|
+
const start = source.indexOf("<", searchStart);
|
|
2406
|
+
if (start === -1 || start > offset) {
|
|
2407
|
+
return void 0;
|
|
2408
|
+
}
|
|
2409
|
+
if (source.startsWith("<!--", start)) {
|
|
2410
|
+
const commentEnd = source.indexOf("-->", start + 4);
|
|
2411
|
+
const tokenEnd2 = commentEnd === -1 ? source.length : commentEnd + 3;
|
|
2412
|
+
if (offset < tokenEnd2) {
|
|
2413
|
+
return void 0;
|
|
2414
|
+
}
|
|
2415
|
+
searchStart = tokenEnd2;
|
|
2416
|
+
continue;
|
|
2417
|
+
}
|
|
2418
|
+
if (source.startsWith("<![CDATA[", start)) {
|
|
2419
|
+
const cdataEnd = source.indexOf("]]>", start + 9);
|
|
2420
|
+
const tokenEnd2 = cdataEnd === -1 ? source.length : cdataEnd + 3;
|
|
2421
|
+
if (offset < tokenEnd2) {
|
|
2422
|
+
return void 0;
|
|
2423
|
+
}
|
|
2424
|
+
searchStart = tokenEnd2;
|
|
2425
|
+
continue;
|
|
2426
|
+
}
|
|
2427
|
+
if (source.startsWith("<?", start)) {
|
|
2428
|
+
const processingEnd = source.indexOf("?>", start + 2);
|
|
2429
|
+
const tokenEnd2 = processingEnd === -1 ? source.length : processingEnd + 2;
|
|
2430
|
+
if (offset < tokenEnd2) {
|
|
2431
|
+
return void 0;
|
|
2432
|
+
}
|
|
2433
|
+
searchStart = tokenEnd2;
|
|
2434
|
+
continue;
|
|
2435
|
+
}
|
|
2436
|
+
const tagEnd = findTagEnd3(source, start + 1);
|
|
2437
|
+
const contentEnd = tagEnd ?? source.length;
|
|
2438
|
+
const tokenEnd = tagEnd === void 0 ? source.length : tagEnd + 1;
|
|
2439
|
+
if (offset < tokenEnd) {
|
|
2440
|
+
return parseTag(source, start, contentEnd, tokenEnd);
|
|
2441
|
+
}
|
|
2442
|
+
if (tagEnd === void 0) {
|
|
2443
|
+
return void 0;
|
|
2444
|
+
}
|
|
2445
|
+
searchStart = tokenEnd;
|
|
2446
|
+
}
|
|
2447
|
+
return void 0;
|
|
2448
|
+
}
|
|
2449
|
+
function findParameter(definition, name) {
|
|
2450
|
+
return definition.parameters.find(
|
|
2451
|
+
(parameter) => parameter.name === name || parameter.aliases?.includes(name) === true
|
|
2452
|
+
);
|
|
2453
|
+
}
|
|
2454
|
+
function getSsmlTagDefinition(name) {
|
|
2455
|
+
return definitionsByName.get(name);
|
|
2456
|
+
}
|
|
2457
|
+
function findSsmlHoverTarget(source, lineNumber, column) {
|
|
2458
|
+
const offset = positionToOffset(source, lineNumber, column);
|
|
2459
|
+
if (offset === void 0) {
|
|
2460
|
+
return void 0;
|
|
2461
|
+
}
|
|
2462
|
+
const tag = findTagAtOffset(source, offset);
|
|
2463
|
+
if (!tag) {
|
|
2464
|
+
return void 0;
|
|
2465
|
+
}
|
|
2466
|
+
const definition = getSsmlTagDefinition(tag.name);
|
|
2467
|
+
if (!definition) {
|
|
2468
|
+
return void 0;
|
|
2469
|
+
}
|
|
2470
|
+
if (containsOffset(tag.nameRange, offset)) {
|
|
2471
|
+
return {
|
|
2472
|
+
kind: "tag",
|
|
2473
|
+
tagName: tag.name,
|
|
2474
|
+
isClosingTag: tag.closing,
|
|
2475
|
+
definition,
|
|
2476
|
+
range: toRange(source, tag.nameRange)
|
|
2477
|
+
};
|
|
2478
|
+
}
|
|
2479
|
+
for (const attribute of tag.attributes) {
|
|
2480
|
+
if (containsOffset(attribute.name, offset)) {
|
|
2481
|
+
const parameter = findParameter(definition, source.slice(attribute.name.start, attribute.name.end));
|
|
2482
|
+
if (!parameter) {
|
|
2483
|
+
return void 0;
|
|
2484
|
+
}
|
|
2485
|
+
return {
|
|
2486
|
+
kind: "parameter",
|
|
2487
|
+
tagName: tag.name,
|
|
2488
|
+
isClosingTag: tag.closing,
|
|
2489
|
+
definition,
|
|
2490
|
+
parameter,
|
|
2491
|
+
range: toRange(source, attribute.name)
|
|
2492
|
+
};
|
|
2493
|
+
}
|
|
2494
|
+
if (attribute.value && containsOffset(attribute.value, offset)) {
|
|
2495
|
+
const parameter = findParameter(definition, source.slice(attribute.name.start, attribute.name.end));
|
|
2496
|
+
if (!parameter) {
|
|
2497
|
+
return void 0;
|
|
2498
|
+
}
|
|
2499
|
+
return {
|
|
2500
|
+
kind: "parameter-value",
|
|
2501
|
+
tagName: tag.name,
|
|
2502
|
+
isClosingTag: tag.closing,
|
|
2503
|
+
definition,
|
|
2504
|
+
parameter,
|
|
2505
|
+
range: toRange(source, attribute.value)
|
|
2506
|
+
};
|
|
2507
|
+
}
|
|
2508
|
+
}
|
|
2509
|
+
return void 0;
|
|
2510
|
+
}
|
|
2511
|
+
function code(value) {
|
|
2512
|
+
return `\`${value.replace(/\\/g, "\\\\").replace(/`/g, "\\`")}\``;
|
|
2513
|
+
}
|
|
2514
|
+
function formatParameter(parameter, tagName, locale) {
|
|
2515
|
+
const localizedParameter = SSML_HOVER_COPY[locale].tags[tagName]?.parameters[parameter.name];
|
|
2516
|
+
const description = localizedParameter?.description ?? parameter.description;
|
|
2517
|
+
const values = parameter.values && parameter.values.length > 0 ? ` ${SSML_HOVER_COPY[locale].allowedValues}: ${parameter.values.map(code).join(", ")}.` : "";
|
|
2518
|
+
const example = parameter.example ? ` ${SSML_HOVER_COPY[locale].example}: ${code(parameter.example)}.` : "";
|
|
2519
|
+
return `- ${code(parameter.name)}: ${description}${values}${example}`;
|
|
2520
|
+
}
|
|
2521
|
+
function formatSsmlHover(target, locale = "en") {
|
|
2522
|
+
const localizedTag = SSML_HOVER_COPY[locale].tags[target.definition.name];
|
|
2523
|
+
const tagTitle = localizedTag?.title ?? target.definition.name;
|
|
2524
|
+
const tagDescription = localizedTag?.description ?? target.definition.description;
|
|
2525
|
+
const tagSyntax = target.isClosingTag ? `</${target.tagName}>` : `<${target.tagName}>`;
|
|
2526
|
+
const lines = [`### ${code(tagSyntax)}`, "", `**${tagTitle}**`, "", tagDescription];
|
|
2527
|
+
if (target.parameter) {
|
|
2528
|
+
const localizedParameter = localizedTag?.parameters[target.parameter.name];
|
|
2529
|
+
const parameterTitle = localizedParameter?.title ?? target.parameter.name;
|
|
2530
|
+
const parameterDescription = localizedParameter?.description ?? target.parameter.description;
|
|
2531
|
+
lines.push("", `**${SSML_HOVER_COPY[locale].parameterHeading} ${code(parameterTitle)}**`, "", parameterDescription);
|
|
2532
|
+
if (target.parameter.values && target.parameter.values.length > 0) {
|
|
2533
|
+
lines.push("", `${SSML_HOVER_COPY[locale].allowedValues}: ${target.parameter.values.map(code).join(", ")}.`);
|
|
2534
|
+
}
|
|
2535
|
+
if (target.parameter.example) {
|
|
2536
|
+
lines.push("", `${SSML_HOVER_COPY[locale].example}: ${code(target.parameter.example)}.`);
|
|
2537
|
+
}
|
|
2538
|
+
} else if (target.definition.parameters.length > 0) {
|
|
2539
|
+
lines.push(
|
|
2540
|
+
"",
|
|
2541
|
+
`**${SSML_HOVER_COPY[locale].parametersHeading}**`,
|
|
2542
|
+
"",
|
|
2543
|
+
...target.definition.parameters.map((parameter) => formatParameter(parameter, target.definition.name, locale))
|
|
2544
|
+
);
|
|
2545
|
+
} else {
|
|
2546
|
+
lines.push("", SSML_HOVER_COPY[locale].noParameters);
|
|
2547
|
+
}
|
|
2548
|
+
return lines.join("\n");
|
|
2549
|
+
}
|
|
2550
|
+
|
|
2551
|
+
// ../ssml-editor-react/src/constants/ui.ts
|
|
2552
|
+
var SSML_INSERTION_MODES = {
|
|
2553
|
+
insert: "insert",
|
|
2554
|
+
wrap: "wrap"
|
|
2555
|
+
};
|
|
2556
|
+
|
|
2557
|
+
// ../ssml-editor-react/src/ssmlInsertion.ts
|
|
2558
|
+
function isLineStart(value, offset) {
|
|
2559
|
+
return offset === 0 || value[offset - 1] === "\n" || value[offset - 1] === "\r";
|
|
2560
|
+
}
|
|
2561
|
+
function isLineEnd(value, offset) {
|
|
2562
|
+
return offset === value.length || value[offset] === "\n" || value[offset] === "\r";
|
|
2563
|
+
}
|
|
2564
|
+
function getLineBreakAt(value, offset) {
|
|
2565
|
+
if (value.startsWith("\r\n", offset)) {
|
|
2566
|
+
return "\r\n";
|
|
2567
|
+
}
|
|
2568
|
+
if (value[offset] === "\n" || value[offset] === "\r") {
|
|
2569
|
+
return value[offset];
|
|
2570
|
+
}
|
|
2571
|
+
return "";
|
|
2572
|
+
}
|
|
2573
|
+
function startsWithLineBreak(value) {
|
|
2574
|
+
return value.startsWith("\n") || value.startsWith("\r");
|
|
2575
|
+
}
|
|
2576
|
+
function endsWithLineBreak(value) {
|
|
2577
|
+
return value.endsWith("\n") || value.endsWith("\r");
|
|
2578
|
+
}
|
|
2579
|
+
function createSsmlInsertionEdit(source, startOffset, endOffset, template, eol = "\n", selectedText = startOffset === endOffset ? "" : source.slice(startOffset, endOffset)) {
|
|
2580
|
+
if (template.mode === SSML_INSERTION_MODES.wrap) {
|
|
2581
|
+
const trailingLineBreak2 = getLineBreakAt(source, endOffset) === "" ? eol : "";
|
|
2582
|
+
return {
|
|
2583
|
+
replacement: `${template.prefix}${selectedText}${template.suffix}${trailingLineBreak2}`,
|
|
2584
|
+
selectionOffset: template.prefix.length
|
|
2585
|
+
};
|
|
2586
|
+
}
|
|
2587
|
+
const followingLineBreak = getLineBreakAt(source, endOffset);
|
|
2588
|
+
const leadingLineBreak = !isLineStart(source, startOffset) && !startsWithLineBreak(template.prefix) ? eol : "";
|
|
2589
|
+
const needsTrailingLineBreak = selectedText.length > 0 ? !selectedText.startsWith("\n") && !selectedText.startsWith("\r") : !isLineEnd(source, endOffset) || followingLineBreak === "";
|
|
2590
|
+
const trailingLineBreak = needsTrailingLineBreak && !endsWithLineBreak(template.prefix) ? eol : "";
|
|
2591
|
+
const insertionPrefix = `${leadingLineBreak}${template.prefix}`;
|
|
2592
|
+
return {
|
|
2593
|
+
replacement: `${insertionPrefix}${trailingLineBreak}${selectedText}`,
|
|
2594
|
+
selectionOffset: insertionPrefix.length + trailingLineBreak.length + (selectedText.length === 0 && trailingLineBreak === "" ? followingLineBreak.length : 0)
|
|
2595
|
+
};
|
|
2596
|
+
}
|
|
2597
|
+
|
|
2598
|
+
// ../ssml-editor-react/src/ssmlInsertions.ts
|
|
2599
|
+
function createInsertionOptions(values, descriptions) {
|
|
2600
|
+
return values.map((value) => ({
|
|
2601
|
+
value,
|
|
2602
|
+
labels: { ja: value, en: value },
|
|
2603
|
+
...descriptions?.[value] ? { descriptions: descriptions[value] } : {}
|
|
2604
|
+
}));
|
|
2605
|
+
}
|
|
2606
|
+
var SSML_INSERTIONS = [
|
|
2607
|
+
{
|
|
2608
|
+
id: "break",
|
|
2609
|
+
icon: "\u23F8",
|
|
2610
|
+
tagName: "break",
|
|
2611
|
+
selfClosing: true,
|
|
2612
|
+
labels: { ja: "\u9593", en: "Break" },
|
|
2613
|
+
descriptions: {
|
|
2614
|
+
ja: "\u6307\u5B9A\u3057\u305F\u6642\u9593\u3060\u3051\u7121\u97F3\u306E\u9593\u3092\u633F\u5165\u3057\u307E\u3059\u3002",
|
|
2615
|
+
en: "Inserts a silent pause for the selected duration."
|
|
2616
|
+
},
|
|
2617
|
+
parameterDescription: {
|
|
2618
|
+
ja: "\u7121\u97F3\u306B\u3059\u308B\u6642\u9593\u3092\u9078\u629E\u3057\u307E\u3059\u3002",
|
|
2619
|
+
en: "Selects the duration of the silent pause."
|
|
2620
|
+
},
|
|
2621
|
+
options: createInsertionOptions(BREAK_TIME_PRESETS, BREAK_TIME_DESCRIPTIONS),
|
|
2622
|
+
createTemplate: (value) => ({
|
|
2623
|
+
prefix: `<break time="${value}"/>`,
|
|
2624
|
+
suffix: "",
|
|
2625
|
+
mode: "insert"
|
|
2626
|
+
})
|
|
2627
|
+
},
|
|
2628
|
+
{
|
|
2629
|
+
id: "emphasis",
|
|
2630
|
+
icon: "\u2726",
|
|
2631
|
+
tagName: "emphasis",
|
|
2632
|
+
labels: { ja: "\u5F37\u8ABF", en: "Emphasis" },
|
|
2633
|
+
descriptions: {
|
|
2634
|
+
ja: "\u9078\u629E\u7BC4\u56F2\u306E\u5F37\u8ABF\u30EC\u30D9\u30EB\u3092\u5909\u66F4\u3057\u307E\u3059\u3002",
|
|
2635
|
+
en: "Changes the emphasis level of the selected text."
|
|
2636
|
+
},
|
|
2637
|
+
parameterDescription: {
|
|
2638
|
+
ja: "\u9078\u629E\u7BC4\u56F2\u306E\u5F37\u8ABF\u30EC\u30D9\u30EB\u3092\u9078\u629E\u3057\u307E\u3059\u3002",
|
|
2639
|
+
en: "Selects the emphasis level for the selected text."
|
|
2640
|
+
},
|
|
2641
|
+
options: createInsertionOptions(EMPHASIS_LEVEL_PRESETS, EMPHASIS_LEVEL_DESCRIPTIONS),
|
|
2642
|
+
createTemplate: (value) => ({
|
|
2643
|
+
prefix: `<emphasis level="${value}">`,
|
|
2644
|
+
suffix: "</emphasis>",
|
|
2645
|
+
mode: "wrap"
|
|
2646
|
+
})
|
|
2647
|
+
},
|
|
2648
|
+
{
|
|
2649
|
+
id: "rate",
|
|
2650
|
+
icon: "\u2195",
|
|
2651
|
+
tagName: "prosody",
|
|
2652
|
+
labels: { ja: "\u901F\u5EA6", en: "Rate" },
|
|
2653
|
+
descriptions: {
|
|
2654
|
+
ja: "\u9078\u629E\u7BC4\u56F2\u306E\u8AAD\u307F\u4E0A\u3052\u901F\u5EA6\u3092\u5909\u66F4\u3057\u307E\u3059\u3002",
|
|
2655
|
+
en: "Changes the speech rate of the selected text."
|
|
2656
|
+
},
|
|
2657
|
+
parameterDescription: {
|
|
2658
|
+
ja: "\u9078\u629E\u7BC4\u56F2\u306E\u8AAD\u307F\u4E0A\u3052\u901F\u5EA6\u3092\u9078\u629E\u3057\u307E\u3059\u3002",
|
|
2659
|
+
en: "Selects the speech rate for the selected text."
|
|
2660
|
+
},
|
|
2661
|
+
options: createInsertionOptions(PROSODY_RATE_PRESETS, PROSODY_RATE_DESCRIPTIONS),
|
|
2662
|
+
createTemplate: (value) => ({
|
|
2663
|
+
prefix: `<prosody rate="${value}">`,
|
|
2664
|
+
suffix: "</prosody>",
|
|
2665
|
+
mode: "wrap"
|
|
2666
|
+
})
|
|
2667
|
+
},
|
|
2668
|
+
{
|
|
2669
|
+
id: "pitch",
|
|
2670
|
+
icon: "\u2197",
|
|
2671
|
+
tagName: "prosody",
|
|
2672
|
+
labels: { ja: "\u9AD8\u3055", en: "Pitch" },
|
|
2673
|
+
descriptions: {
|
|
2674
|
+
ja: "\u9078\u629E\u7BC4\u56F2\u306E\u58F0\u306E\u9AD8\u3055\u3092\u5909\u66F4\u3057\u307E\u3059\u3002",
|
|
2675
|
+
en: "Changes the pitch of the selected text."
|
|
2676
|
+
},
|
|
2677
|
+
parameterDescription: {
|
|
2678
|
+
ja: "\u9078\u629E\u7BC4\u56F2\u306E\u58F0\u306E\u9AD8\u3055\u3092\u534A\u97F3\u5358\u4F4D\u3067\u9078\u629E\u3057\u307E\u3059\u3002",
|
|
2679
|
+
en: "Selects the pitch adjustment in semitone steps."
|
|
2680
|
+
},
|
|
2681
|
+
options: createInsertionOptions(PROSODY_PITCH_PRESETS, PROSODY_PITCH_DESCRIPTIONS),
|
|
2682
|
+
createTemplate: (value) => ({
|
|
2683
|
+
prefix: `<prosody pitch="${value}">`,
|
|
2684
|
+
suffix: "</prosody>",
|
|
2685
|
+
mode: "wrap"
|
|
2686
|
+
})
|
|
2687
|
+
},
|
|
2688
|
+
{
|
|
2689
|
+
id: "volume",
|
|
2690
|
+
icon: "\u{1F50A}",
|
|
2691
|
+
tagName: "prosody",
|
|
2692
|
+
labels: { ja: "\u97F3\u91CF", en: "Volume" },
|
|
2693
|
+
descriptions: {
|
|
2694
|
+
ja: "\u9078\u629E\u7BC4\u56F2\u306E\u97F3\u91CF\u3092\u5909\u66F4\u3057\u307E\u3059\u3002",
|
|
2695
|
+
en: "Changes the volume of the selected text."
|
|
2696
|
+
},
|
|
2697
|
+
parameterDescription: {
|
|
2698
|
+
ja: "\u9078\u629E\u7BC4\u56F2\u306E\u97F3\u91CF\u30EC\u30D9\u30EB\u3092\u9078\u629E\u3057\u307E\u3059\u3002",
|
|
2699
|
+
en: "Selects the volume level for the selected text."
|
|
2700
|
+
},
|
|
2701
|
+
options: createInsertionOptions(PROSODY_VOLUME_PRESETS, PROSODY_VOLUME_DESCRIPTIONS),
|
|
2702
|
+
createTemplate: (value) => ({
|
|
2703
|
+
prefix: `<prosody volume="${value}">`,
|
|
2704
|
+
suffix: "</prosody>",
|
|
2705
|
+
mode: "wrap"
|
|
2706
|
+
})
|
|
2707
|
+
},
|
|
2708
|
+
{
|
|
2709
|
+
id: "emotion",
|
|
2710
|
+
icon: "\u263A",
|
|
2711
|
+
tagName: "mstts:express-as",
|
|
2712
|
+
labels: { ja: "\u611F\u60C5", en: "Emotion" },
|
|
2713
|
+
descriptions: {
|
|
2714
|
+
ja: "\u9078\u629E\u7BC4\u56F2\u306B\u97F3\u58F0\u306E\u611F\u60C5\u30B9\u30BF\u30A4\u30EB\u3092\u9069\u7528\u3057\u307E\u3059\u3002",
|
|
2715
|
+
en: "Applies a voice emotion style to the selected text."
|
|
2716
|
+
},
|
|
2717
|
+
parameterDescription: {
|
|
2718
|
+
ja: "\u9078\u629E\u7BC4\u56F2\u306B\u9069\u7528\u3059\u308B\u97F3\u58F0\u306E\u611F\u60C5\u30B9\u30BF\u30A4\u30EB\u3092\u9078\u629E\u3057\u307E\u3059\u3002",
|
|
2719
|
+
en: "Selects the voice emotion style to apply."
|
|
2720
|
+
},
|
|
2721
|
+
options: createInsertionOptions(EXPRESS_AS_STYLE_PRESETS, EXPRESS_AS_STYLE_DESCRIPTIONS),
|
|
2722
|
+
createTemplate: (value) => ({
|
|
2723
|
+
prefix: `<mstts:express-as style="${value}">`,
|
|
2724
|
+
suffix: "</mstts:express-as>",
|
|
2725
|
+
mode: "wrap"
|
|
2726
|
+
})
|
|
2727
|
+
},
|
|
2728
|
+
{
|
|
2729
|
+
id: "say-as",
|
|
2730
|
+
icon: "Aa",
|
|
2731
|
+
tagName: "say-as",
|
|
2732
|
+
labels: { ja: "\u8AAD\u307F\u4E0A\u3052", en: "Say as" },
|
|
2733
|
+
descriptions: {
|
|
2734
|
+
ja: "\u6570\u5B57\u3084\u65E5\u4ED8\u306A\u3069\u306E\u8AAD\u307F\u4E0A\u3052\u65B9\u3092\u6307\u5B9A\u3057\u307E\u3059\u3002",
|
|
2735
|
+
en: "Specifies how values such as numbers or dates are spoken."
|
|
2736
|
+
},
|
|
2737
|
+
parameterDescription: {
|
|
2738
|
+
ja: "\u9078\u629E\u7BC4\u56F2\u306E\u8AAD\u307F\u4E0A\u3052\u65B9\u3092\u9078\u629E\u3057\u307E\u3059\u3002",
|
|
2739
|
+
en: "Selects how the selected text is spoken."
|
|
2740
|
+
},
|
|
2741
|
+
options: createInsertionOptions(SAY_AS_PRESETS, SAY_AS_DESCRIPTIONS),
|
|
2742
|
+
createTemplate: (value) => ({
|
|
2743
|
+
prefix: `<say-as interpret-as="${value}">`,
|
|
2744
|
+
suffix: "</say-as>",
|
|
2745
|
+
mode: "wrap"
|
|
2746
|
+
})
|
|
2747
|
+
},
|
|
2748
|
+
{
|
|
2749
|
+
id: "lang",
|
|
2750
|
+
icon: "\u6587",
|
|
2751
|
+
tagName: "lang",
|
|
2752
|
+
labels: { ja: "\u8A00\u8A9E", en: "Language" },
|
|
2753
|
+
descriptions: {
|
|
2754
|
+
ja: "\u9078\u629E\u7BC4\u56F2\u306E\u8AAD\u307F\u4E0A\u3052\u8A00\u8A9E\u3092\u5909\u66F4\u3057\u307E\u3059\u3002",
|
|
2755
|
+
en: "Changes the speaking language of the selected text."
|
|
2756
|
+
},
|
|
2757
|
+
parameterDescription: {
|
|
2758
|
+
ja: "\u9078\u629E\u7BC4\u56F2\u306B\u9069\u7528\u3059\u308B BCP-47 \u8A00\u8A9E\u30BF\u30B0\u3092\u9078\u629E\u3057\u307E\u3059\u3002",
|
|
2759
|
+
en: "Selects the BCP-47 language tag for the selected text."
|
|
2760
|
+
},
|
|
2761
|
+
options: createInsertionOptions(LANGUAGE_PRESETS, LANGUAGE_DESCRIPTIONS),
|
|
2762
|
+
createTemplate: (value) => ({
|
|
2763
|
+
prefix: `<lang xml:lang="${value}">`,
|
|
2764
|
+
suffix: "</lang>",
|
|
2765
|
+
mode: "wrap"
|
|
2766
|
+
})
|
|
2767
|
+
},
|
|
2768
|
+
{
|
|
2769
|
+
id: "mstts:silence",
|
|
2770
|
+
icon: "\u23F3",
|
|
2771
|
+
tagName: "mstts:silence",
|
|
2772
|
+
selfClosing: true,
|
|
2773
|
+
labels: { ja: "\u7121\u97F3", en: "Silence" },
|
|
2774
|
+
descriptions: {
|
|
2775
|
+
ja: "\u7121\u97F3\u6642\u9593\u3092\u633F\u5165\u3057\u307E\u3059\u3002",
|
|
2776
|
+
en: "Inserts a silence interval."
|
|
2777
|
+
},
|
|
2778
|
+
parameterDescription: {
|
|
2779
|
+
ja: "\u7121\u97F3\u306B\u3059\u308B\u6642\u9593\u3092\u9078\u629E\u3057\u307E\u3059\u3002",
|
|
2780
|
+
en: "Selects the silence duration."
|
|
2781
|
+
},
|
|
2782
|
+
options: createInsertionOptions(SILENCE_VALUE_PRESETS, SILENCE_VALUE_DESCRIPTIONS),
|
|
2783
|
+
createTemplate: (value) => ({
|
|
2784
|
+
prefix: `<mstts:silence type="Leading" value="${value}"/>`,
|
|
2785
|
+
suffix: "",
|
|
2786
|
+
mode: "insert"
|
|
2787
|
+
})
|
|
2788
|
+
}
|
|
2789
|
+
];
|
|
2790
|
+
var DEFAULT_INSERTION_GROUPS = [
|
|
2791
|
+
{
|
|
2792
|
+
id: "pauses",
|
|
2793
|
+
labels: { ja: "\u9593\u30FB\u7121\u97F3", en: "Pauses" },
|
|
2794
|
+
insertionIds: ["break", "mstts:silence"]
|
|
2795
|
+
},
|
|
2796
|
+
{
|
|
2797
|
+
id: "prosody",
|
|
2798
|
+
labels: { ja: "\u58F0\u306E\u8ABF\u6574", en: "Voice" },
|
|
2799
|
+
insertionIds: ["rate", "pitch", "volume"]
|
|
2800
|
+
},
|
|
2801
|
+
{
|
|
2802
|
+
id: "expression",
|
|
2803
|
+
labels: { ja: "\u8868\u73FE", en: "Expression" },
|
|
2804
|
+
insertionIds: ["emphasis", "emotion"]
|
|
2805
|
+
},
|
|
2806
|
+
{
|
|
2807
|
+
id: "pronunciation",
|
|
2808
|
+
labels: { ja: "\u8AAD\u307F\u4E0A\u3052", en: "Pronunciation" },
|
|
2809
|
+
insertionIds: ["say-as", "lang"]
|
|
2810
|
+
}
|
|
2811
|
+
];
|
|
2812
|
+
|
|
2813
|
+
// src/SsmlEditorElement.ts
|
|
2814
|
+
var HTMLElementBase = typeof HTMLElement === "undefined" ? class {
|
|
2815
|
+
} : HTMLElement;
|
|
2816
|
+
var STYLE_ID = "ssml-editor-elements-theme";
|
|
2817
|
+
var STYLE_CSS = `
|
|
2818
|
+
[data-ssml-editor] {
|
|
2819
|
+
--ssml-editor-color: #111827;
|
|
2820
|
+
--ssml-editor-bg: #ffffff;
|
|
2821
|
+
--ssml-editor-border: #d1d5db;
|
|
2822
|
+
--ssml-editor-control-bg: #f9fafb;
|
|
2823
|
+
--ssml-editor-control-border: #9ca3af;
|
|
2824
|
+
--ssml-editor-active-bg: #dbeafe;
|
|
2825
|
+
--ssml-editor-active-border: #2563eb;
|
|
2826
|
+
--ssml-editor-preview-bg: #f3f4f6;
|
|
2827
|
+
}
|
|
2828
|
+
section[data-ssml-editor] {
|
|
2829
|
+
display: grid;
|
|
2830
|
+
grid-template-rows: auto minmax(8rem, 1fr);
|
|
2831
|
+
gap: 0.75rem;
|
|
2832
|
+
box-sizing: border-box;
|
|
2833
|
+
width: 100%;
|
|
2834
|
+
min-height: 100%;
|
|
2835
|
+
padding: 1rem;
|
|
2836
|
+
border: 1px solid var(--ssml-editor-border);
|
|
2837
|
+
border-radius: 0.5rem;
|
|
2838
|
+
color: var(--ssml-editor-color);
|
|
2839
|
+
background: var(--ssml-editor-bg);
|
|
2840
|
+
}
|
|
2841
|
+
[data-ssml-editor][data-theme="dark"] {
|
|
2842
|
+
--ssml-editor-color: #f9fafb;
|
|
2843
|
+
--ssml-editor-bg: #1f2937;
|
|
2844
|
+
--ssml-editor-border: #374151;
|
|
2845
|
+
--ssml-editor-control-bg: #111827;
|
|
2846
|
+
--ssml-editor-control-border: #4b5563;
|
|
2847
|
+
--ssml-editor-active-bg: #1e3a8a;
|
|
2848
|
+
--ssml-editor-active-border: #60a5fa;
|
|
2849
|
+
--ssml-editor-preview-bg: #111827;
|
|
2850
|
+
}
|
|
2851
|
+
[data-ssml-editor] .ssml-editor-toolbar {
|
|
2852
|
+
display: flex;
|
|
2853
|
+
align-items: center;
|
|
2854
|
+
flex-wrap: wrap;
|
|
2855
|
+
gap: 0.5rem;
|
|
2856
|
+
}
|
|
2857
|
+
[data-ssml-editor] .ssml-editor-toolbar-actions {
|
|
2858
|
+
display: flex;
|
|
2859
|
+
align-items: center;
|
|
2860
|
+
flex-wrap: wrap;
|
|
2861
|
+
gap: 0.5rem;
|
|
2862
|
+
}
|
|
2863
|
+
[data-ssml-editor] .ssml-editor-toolbar-separator {
|
|
2864
|
+
width: 1px;
|
|
2865
|
+
height: 2.25rem;
|
|
2866
|
+
margin: 0 0.25rem;
|
|
2867
|
+
background: var(--ssml-editor-border);
|
|
2868
|
+
}
|
|
2869
|
+
[data-ssml-editor] .ssml-editor-toolbar-dropdown {
|
|
2870
|
+
display: inline-block;
|
|
2871
|
+
}
|
|
2872
|
+
[data-ssml-editor] .ssml-editor-toolbar-button {
|
|
2873
|
+
display: inline-flex;
|
|
2874
|
+
align-items: center;
|
|
2875
|
+
gap: 0.375rem;
|
|
2876
|
+
min-height: 2.25rem;
|
|
2877
|
+
padding: 0.375rem 0.625rem;
|
|
2878
|
+
border: 1px solid var(--ssml-editor-control-border);
|
|
2879
|
+
border-radius: 0.25rem;
|
|
2880
|
+
color: var(--ssml-editor-color);
|
|
2881
|
+
background: var(--ssml-editor-control-bg);
|
|
2882
|
+
font: inherit;
|
|
2883
|
+
cursor: pointer;
|
|
2884
|
+
}
|
|
2885
|
+
[data-ssml-editor] .ssml-editor-toolbar-button:hover,
|
|
2886
|
+
[data-ssml-editor] .ssml-editor-toolbar-option:hover {
|
|
2887
|
+
background: var(--ssml-editor-preview-bg);
|
|
2888
|
+
}
|
|
2889
|
+
[data-ssml-editor] .ssml-editor-toolbar-button:disabled {
|
|
2890
|
+
cursor: not-allowed;
|
|
2891
|
+
opacity: 0.55;
|
|
2892
|
+
}
|
|
2893
|
+
[data-ssml-editor] .ssml-editor-toolbar-button[data-active="true"] {
|
|
2894
|
+
border-color: var(--ssml-editor-active-border);
|
|
2895
|
+
background: var(--ssml-editor-active-bg);
|
|
2896
|
+
}
|
|
2897
|
+
[data-ssml-editor] .ssml-editor-toolbar-icon {
|
|
2898
|
+
display: inline-flex;
|
|
2899
|
+
width: 1.25rem;
|
|
2900
|
+
justify-content: center;
|
|
2901
|
+
font-size: 1.1rem;
|
|
2902
|
+
line-height: 1;
|
|
2903
|
+
}
|
|
2904
|
+
[data-ssml-editor] .ssml-editor-toolbar-chevron {
|
|
2905
|
+
font-size: 0.7rem;
|
|
2906
|
+
line-height: 1;
|
|
2907
|
+
}
|
|
2908
|
+
[data-ssml-editor] .ssml-editor-toolbar-switch {
|
|
2909
|
+
display: inline-flex;
|
|
2910
|
+
align-items: center;
|
|
2911
|
+
gap: 0.375rem;
|
|
2912
|
+
min-height: 2.25rem;
|
|
2913
|
+
}
|
|
2914
|
+
[data-ssml-editor] .ssml-editor-switch-track {
|
|
2915
|
+
display: inline-flex;
|
|
2916
|
+
align-items: center;
|
|
2917
|
+
width: 2.75rem;
|
|
2918
|
+
height: 1.5rem;
|
|
2919
|
+
padding: 0.1875rem;
|
|
2920
|
+
border: 0;
|
|
2921
|
+
border-radius: 999px;
|
|
2922
|
+
background: var(--ssml-editor-control-border);
|
|
2923
|
+
cursor: pointer;
|
|
2924
|
+
transition: background-color 0.2s ease;
|
|
2925
|
+
}
|
|
2926
|
+
[data-ssml-editor] .ssml-editor-switch-track[aria-checked="true"] {
|
|
2927
|
+
background: var(--ssml-editor-active-border);
|
|
2928
|
+
}
|
|
2929
|
+
[data-ssml-editor] .ssml-editor-switch-track:focus-visible {
|
|
2930
|
+
outline: 2px solid var(--ssml-editor-active-border);
|
|
2931
|
+
outline-offset: 2px;
|
|
2932
|
+
}
|
|
2933
|
+
[data-ssml-editor] .ssml-editor-switch-thumb {
|
|
2934
|
+
width: 1.125rem;
|
|
2935
|
+
height: 1.125rem;
|
|
2936
|
+
border-radius: 50%;
|
|
2937
|
+
background: var(--ssml-editor-bg);
|
|
2938
|
+
transition: transform 0.2s ease;
|
|
2939
|
+
}
|
|
2940
|
+
[data-ssml-editor] .ssml-editor-switch-track[aria-checked="true"] .ssml-editor-switch-thumb {
|
|
2941
|
+
transform: translateX(1.25rem);
|
|
2942
|
+
}
|
|
2943
|
+
[data-ssml-editor].ssml-editor-toolbar-menu {
|
|
2944
|
+
position: fixed;
|
|
2945
|
+
z-index: 9999;
|
|
2946
|
+
display: grid;
|
|
2947
|
+
min-width: max-content;
|
|
2948
|
+
max-height: min(24rem, calc(100vh - 1rem));
|
|
2949
|
+
gap: 0.125rem;
|
|
2950
|
+
padding: 0.25rem;
|
|
2951
|
+
border: 1px solid var(--ssml-editor-control-border);
|
|
2952
|
+
border-radius: 0.25rem;
|
|
2953
|
+
background: var(--ssml-editor-control-bg);
|
|
2954
|
+
box-shadow: 0 0.25rem 0.75rem rgb(0 0 0 / 20%);
|
|
2955
|
+
overflow-y: auto;
|
|
2956
|
+
}
|
|
2957
|
+
[data-ssml-editor] .ssml-editor-toolbar-option {
|
|
2958
|
+
padding: 0.375rem 0.5rem;
|
|
2959
|
+
border: 0;
|
|
2960
|
+
border-radius: 0.125rem;
|
|
2961
|
+
color: var(--ssml-editor-color);
|
|
2962
|
+
background: transparent;
|
|
2963
|
+
font: inherit;
|
|
2964
|
+
text-align: left;
|
|
2965
|
+
white-space: nowrap;
|
|
2966
|
+
cursor: pointer;
|
|
2967
|
+
}
|
|
2968
|
+
[data-ssml-editor] .ssml-editor-toolbar-option-group {
|
|
2969
|
+
display: grid;
|
|
2970
|
+
gap: 0.125rem;
|
|
2971
|
+
margin: 0;
|
|
2972
|
+
padding: 0;
|
|
2973
|
+
border: 0;
|
|
2974
|
+
}
|
|
2975
|
+
[data-ssml-editor] .ssml-editor-toolbar-option-group legend {
|
|
2976
|
+
padding: 0.375rem 0.5rem 0.125rem;
|
|
2977
|
+
font-size: 0.875rem;
|
|
2978
|
+
font-weight: 600;
|
|
2979
|
+
white-space: nowrap;
|
|
2980
|
+
}
|
|
2981
|
+
[data-ssml-editor] .ssml-editor-help {
|
|
2982
|
+
display: grid;
|
|
2983
|
+
gap: 0.5rem;
|
|
2984
|
+
padding: 0.75rem;
|
|
2985
|
+
border: 1px solid var(--ssml-editor-control-border);
|
|
2986
|
+
border-radius: 0.25rem;
|
|
2987
|
+
background: var(--ssml-editor-preview-bg);
|
|
2988
|
+
}
|
|
2989
|
+
[data-ssml-editor] .ssml-editor-help h3,
|
|
2990
|
+
[data-ssml-editor] .ssml-editor-help p {
|
|
2991
|
+
margin: 0;
|
|
2992
|
+
}
|
|
2993
|
+
[data-ssml-editor] .ssml-editor-help-list {
|
|
2994
|
+
display: grid;
|
|
2995
|
+
gap: 0.375rem;
|
|
2996
|
+
margin: 0;
|
|
2997
|
+
padding-left: 1.25rem;
|
|
2998
|
+
}
|
|
2999
|
+
[data-ssml-editor] .ssml-editor-help-item {
|
|
3000
|
+
list-style: none;
|
|
3001
|
+
}
|
|
3002
|
+
[data-ssml-editor] .ssml-editor-help-item details {
|
|
3003
|
+
margin-top: 0.375rem;
|
|
3004
|
+
border: 1px solid var(--ssml-editor-control-border);
|
|
3005
|
+
border-radius: 0.25rem;
|
|
3006
|
+
background: var(--ssml-editor-control-bg);
|
|
3007
|
+
}
|
|
3008
|
+
[data-ssml-editor] .ssml-editor-help-item summary {
|
|
3009
|
+
padding: 0.5rem 0.625rem;
|
|
3010
|
+
cursor: pointer;
|
|
3011
|
+
}
|
|
3012
|
+
[data-ssml-editor] .ssml-editor-help-item details p,
|
|
3013
|
+
[data-ssml-editor] .ssml-editor-help-item details ul {
|
|
3014
|
+
margin: 0.5rem 0.75rem 0.75rem;
|
|
3015
|
+
font-size: 0.875rem;
|
|
3016
|
+
}
|
|
3017
|
+
[data-ssml-editor] .ssml-editor-display {
|
|
3018
|
+
display: grid;
|
|
3019
|
+
grid-template-rows: auto minmax(8rem, 1fr);
|
|
3020
|
+
gap: 0.5rem;
|
|
3021
|
+
min-height: 0;
|
|
3022
|
+
}
|
|
3023
|
+
[data-ssml-editor] .ssml-editor-editor {
|
|
3024
|
+
position: relative;
|
|
3025
|
+
min-height: 8rem;
|
|
3026
|
+
height: 100%;
|
|
3027
|
+
border: 1px solid var(--ssml-editor-control-border);
|
|
3028
|
+
border-radius: 0.25rem;
|
|
3029
|
+
overflow: visible;
|
|
3030
|
+
}
|
|
3031
|
+
`.trim();
|
|
3032
|
+
function injectStyles() {
|
|
3033
|
+
if (typeof document === "undefined" || document.getElementById(STYLE_ID)) {
|
|
3034
|
+
return;
|
|
3035
|
+
}
|
|
3036
|
+
const style = document.createElement("style");
|
|
3037
|
+
style.id = STYLE_ID;
|
|
3038
|
+
style.textContent = STYLE_CSS;
|
|
3039
|
+
document.head.appendChild(style);
|
|
3040
|
+
}
|
|
3041
|
+
function isDarkTheme(theme) {
|
|
3042
|
+
return theme === "vs-dark" || theme.toLowerCase().includes("dark");
|
|
3043
|
+
}
|
|
3044
|
+
function getMenuPosition(trigger, menu) {
|
|
3045
|
+
const bounds = trigger.getBoundingClientRect();
|
|
3046
|
+
const margin = 8;
|
|
3047
|
+
const top = Math.min(bounds.bottom + 4, window.innerHeight - menu.offsetHeight - margin);
|
|
3048
|
+
const left = Math.min(bounds.left, window.innerWidth - menu.offsetWidth - margin);
|
|
3049
|
+
return {
|
|
3050
|
+
top: Math.max(margin, top),
|
|
3051
|
+
left: Math.max(margin, left)
|
|
3052
|
+
};
|
|
3053
|
+
}
|
|
3054
|
+
var SsmlEditorElement = class extends HTMLElementBase {
|
|
3055
|
+
constructor() {
|
|
3056
|
+
super(...arguments);
|
|
3057
|
+
this.editor = null;
|
|
3058
|
+
this.model = null;
|
|
3059
|
+
this.monaco = null;
|
|
3060
|
+
this.root = null;
|
|
3061
|
+
this.toolbar = null;
|
|
3062
|
+
this.toolbarActions = null;
|
|
3063
|
+
this.display = null;
|
|
3064
|
+
this.editorContainer = null;
|
|
3065
|
+
this.helpPanel = null;
|
|
3066
|
+
this.openMenu = null;
|
|
3067
|
+
this.openMenuTrigger = null;
|
|
3068
|
+
this.toolbarButtons = /* @__PURE__ */ new Map();
|
|
3069
|
+
this.contentDisposable = null;
|
|
3070
|
+
this.cursorDisposable = null;
|
|
3071
|
+
this.completionDisposable = null;
|
|
3072
|
+
this.hoverDisposable = null;
|
|
3073
|
+
this.suppressChangeEvent = false;
|
|
3074
|
+
this.initializationToken = 0;
|
|
3075
|
+
this.documentState = null;
|
|
3076
|
+
this.decorationsVisible = false;
|
|
3077
|
+
this.helpOpen = false;
|
|
3078
|
+
this.handleDocumentPointerDown = (event) => {
|
|
3079
|
+
const target = event.target;
|
|
3080
|
+
if (this.openMenu && target instanceof Node && !this.openMenu.contains(target) && !this.openMenuTrigger?.contains(target)) {
|
|
3081
|
+
this.closeMenu();
|
|
3082
|
+
}
|
|
3083
|
+
};
|
|
3084
|
+
this.handleDocumentKeyDown = (event) => {
|
|
3085
|
+
if (event.key === "Escape" && this.openMenu) {
|
|
3086
|
+
this.closeMenu(true);
|
|
3087
|
+
}
|
|
3088
|
+
};
|
|
3089
|
+
}
|
|
3090
|
+
get value() {
|
|
3091
|
+
return this.valueState ?? this.getAttribute("value") ?? "";
|
|
3092
|
+
}
|
|
3093
|
+
set value(value) {
|
|
3094
|
+
this.valueState = value;
|
|
3095
|
+
this.setAttribute("value", value);
|
|
3096
|
+
}
|
|
3097
|
+
get theme() {
|
|
3098
|
+
return this.getAttribute("theme") || "light";
|
|
3099
|
+
}
|
|
3100
|
+
set theme(theme) {
|
|
3101
|
+
this.setAttribute("theme", theme);
|
|
3102
|
+
}
|
|
3103
|
+
get readonly() {
|
|
3104
|
+
return this.hasAttribute("readonly");
|
|
3105
|
+
}
|
|
3106
|
+
set readonly(readonly) {
|
|
3107
|
+
if (readonly) {
|
|
3108
|
+
this.setAttribute("readonly", "");
|
|
3109
|
+
} else {
|
|
3110
|
+
this.removeAttribute("readonly");
|
|
3111
|
+
}
|
|
3112
|
+
}
|
|
3113
|
+
get locale() {
|
|
3114
|
+
return this.getAttribute("locale") === "en" ? "en" : "ja";
|
|
3115
|
+
}
|
|
3116
|
+
set locale(locale) {
|
|
3117
|
+
this.setAttribute("locale", locale);
|
|
3118
|
+
}
|
|
3119
|
+
prepareDocument(value) {
|
|
3120
|
+
try {
|
|
3121
|
+
this.documentState = parseSsml2(value);
|
|
3122
|
+
return getEditableText(this.documentState);
|
|
3123
|
+
} catch {
|
|
3124
|
+
this.documentState = null;
|
|
3125
|
+
return value;
|
|
3126
|
+
}
|
|
3127
|
+
}
|
|
3128
|
+
connectedCallback() {
|
|
3129
|
+
if (this.editor || this.root) {
|
|
3130
|
+
return;
|
|
3131
|
+
}
|
|
3132
|
+
injectStyles();
|
|
3133
|
+
document.addEventListener("pointerdown", this.handleDocumentPointerDown);
|
|
3134
|
+
document.addEventListener("keydown", this.handleDocumentKeyDown);
|
|
3135
|
+
this.render();
|
|
3136
|
+
const token = ++this.initializationToken;
|
|
3137
|
+
void this.initialize(token);
|
|
3138
|
+
}
|
|
3139
|
+
disconnectedCallback() {
|
|
3140
|
+
this.initializationToken += 1;
|
|
3141
|
+
document.removeEventListener("pointerdown", this.handleDocumentPointerDown);
|
|
3142
|
+
document.removeEventListener("keydown", this.handleDocumentKeyDown);
|
|
3143
|
+
this.closeMenu();
|
|
3144
|
+
this.disposeEditor();
|
|
3145
|
+
}
|
|
3146
|
+
attributeChangedCallback(name, _oldValue, newValue) {
|
|
3147
|
+
if (name === "value") {
|
|
3148
|
+
this.valueState = newValue ?? "";
|
|
3149
|
+
if (this.editor) {
|
|
3150
|
+
const value = newValue ?? "";
|
|
3151
|
+
const editableValue = this.prepareDocument(value);
|
|
3152
|
+
if (this.editor.getValue() !== editableValue) {
|
|
3153
|
+
this.suppressChangeEvent = true;
|
|
3154
|
+
try {
|
|
3155
|
+
this.editor.setValue(editableValue);
|
|
3156
|
+
} finally {
|
|
3157
|
+
this.suppressChangeEvent = false;
|
|
3158
|
+
}
|
|
3159
|
+
}
|
|
3160
|
+
}
|
|
3161
|
+
return;
|
|
3162
|
+
}
|
|
3163
|
+
if (name === "theme" && this.monaco) {
|
|
3164
|
+
this.monaco.editor.setTheme(this.theme);
|
|
3165
|
+
this.updateTheme();
|
|
3166
|
+
return;
|
|
3167
|
+
}
|
|
3168
|
+
if (name === "readonly") {
|
|
3169
|
+
this.editor?.updateOptions({ readOnly: this.readonly });
|
|
3170
|
+
this.renderToolbar();
|
|
3171
|
+
return;
|
|
3172
|
+
}
|
|
3173
|
+
if (name === "locale" || name === "show-toolbar" || name === "show-toolbar-labels") {
|
|
3174
|
+
this.renderToolbar();
|
|
3175
|
+
this.renderHelp();
|
|
3176
|
+
return;
|
|
3177
|
+
}
|
|
3178
|
+
if (name === "show-decorations") {
|
|
3179
|
+
this.decorationsVisible = newValue !== null;
|
|
3180
|
+
this.updateDecorations();
|
|
3181
|
+
}
|
|
3182
|
+
}
|
|
3183
|
+
render() {
|
|
3184
|
+
const root = document.createElement("section");
|
|
3185
|
+
root.dataset.ssmlEditor = "";
|
|
3186
|
+
root.setAttribute("aria-label", EDITOR_COPY[this.locale].editorAriaLabel);
|
|
3187
|
+
root.dataset.theme = isDarkTheme(this.theme) ? "dark" : "light";
|
|
3188
|
+
const toolbar = document.createElement("div");
|
|
3189
|
+
toolbar.className = "ssml-editor-toolbar";
|
|
3190
|
+
toolbar.dataset.ssmlEditorToolbar = "";
|
|
3191
|
+
const toolbarActions = document.createElement("div");
|
|
3192
|
+
toolbarActions.className = "ssml-editor-toolbar-actions";
|
|
3193
|
+
toolbarActions.setAttribute("role", "toolbar");
|
|
3194
|
+
toolbarActions.setAttribute("aria-label", EDITOR_COPY[this.locale].toolbarAriaLabel);
|
|
3195
|
+
toolbarActions.dataset.ssmlEditorToolbarActions = "";
|
|
3196
|
+
toolbar.append(toolbarActions);
|
|
3197
|
+
const display = document.createElement("div");
|
|
3198
|
+
display.className = "ssml-editor-display";
|
|
3199
|
+
display.dataset.ssmlEditorDisplay = "";
|
|
3200
|
+
const editorContainer = document.createElement("div");
|
|
3201
|
+
editorContainer.className = "ssml-editor-editor";
|
|
3202
|
+
display.append(editorContainer);
|
|
3203
|
+
root.append(toolbar, display);
|
|
3204
|
+
this.replaceChildren(root);
|
|
3205
|
+
this.root = root;
|
|
3206
|
+
this.toolbar = toolbar;
|
|
3207
|
+
this.toolbarActions = toolbarActions;
|
|
3208
|
+
this.display = display;
|
|
3209
|
+
this.editorContainer = editorContainer;
|
|
3210
|
+
this.renderToolbar();
|
|
3211
|
+
this.renderHelp();
|
|
3212
|
+
}
|
|
3213
|
+
renderToolbar() {
|
|
3214
|
+
const toolbar = this.toolbar;
|
|
3215
|
+
const toolbarActions = this.toolbarActions;
|
|
3216
|
+
if (!toolbar || !toolbarActions) {
|
|
3217
|
+
return;
|
|
3218
|
+
}
|
|
3219
|
+
this.closeMenu();
|
|
3220
|
+
const copy = EDITOR_COPY[this.locale];
|
|
3221
|
+
toolbar.hidden = this.getAttribute("show-toolbar") === "false";
|
|
3222
|
+
toolbar.setAttribute("aria-label", copy.toolbarAriaLabel);
|
|
3223
|
+
toolbarActions.setAttribute("aria-label", copy.toolbarAriaLabel);
|
|
3224
|
+
toolbarActions.replaceChildren();
|
|
3225
|
+
this.toolbarButtons.clear();
|
|
3226
|
+
if (toolbar.hidden) {
|
|
3227
|
+
return;
|
|
3228
|
+
}
|
|
3229
|
+
const insertionById = new Map(SSML_INSERTIONS.map((insertion) => [insertion.id, insertion]));
|
|
3230
|
+
const toolbarIds = [
|
|
3231
|
+
"undo",
|
|
3232
|
+
"redo",
|
|
3233
|
+
...DEFAULT_INSERTION_GROUPS.flatMap((group) => group.insertionIds),
|
|
3234
|
+
"clearAll",
|
|
3235
|
+
"format",
|
|
3236
|
+
"decorations",
|
|
3237
|
+
"help"
|
|
3238
|
+
];
|
|
3239
|
+
const groupByButtonId = /* @__PURE__ */ new Map();
|
|
3240
|
+
for (const group of DEFAULT_INSERTION_GROUPS) {
|
|
3241
|
+
for (const buttonId of group.insertionIds) {
|
|
3242
|
+
groupByButtonId.set(buttonId, group.id);
|
|
3243
|
+
}
|
|
3244
|
+
}
|
|
3245
|
+
groupByButtonId.set("undo", "history");
|
|
3246
|
+
groupByButtonId.set("redo", "history");
|
|
3247
|
+
groupByButtonId.set("clearAll", "document");
|
|
3248
|
+
groupByButtonId.set("format", "document");
|
|
3249
|
+
groupByButtonId.set("decorations", "document");
|
|
3250
|
+
groupByButtonId.set("help", "help");
|
|
3251
|
+
let previousGroup;
|
|
3252
|
+
for (const id of toolbarIds) {
|
|
3253
|
+
const group = groupByButtonId.get(id);
|
|
3254
|
+
if (previousGroup !== void 0 && group !== previousGroup) {
|
|
3255
|
+
const separator = document.createElement("span");
|
|
3256
|
+
separator.className = "ssml-editor-toolbar-separator";
|
|
3257
|
+
separator.setAttribute("aria-hidden", "true");
|
|
3258
|
+
toolbarActions.append(separator);
|
|
3259
|
+
}
|
|
3260
|
+
previousGroup = group;
|
|
3261
|
+
const insertion = insertionById.get(id);
|
|
3262
|
+
if (insertion) {
|
|
3263
|
+
toolbarActions.append(this.createInsertionButton(insertion));
|
|
3264
|
+
} else if (id === "decorations") {
|
|
3265
|
+
toolbarActions.append(this.createDecorationsSwitch());
|
|
3266
|
+
} else {
|
|
3267
|
+
toolbarActions.append(this.createActionButton(id));
|
|
3268
|
+
}
|
|
3269
|
+
}
|
|
3270
|
+
this.updateActiveButtons();
|
|
3271
|
+
}
|
|
3272
|
+
createActionButton(id) {
|
|
3273
|
+
const copy = EDITOR_COPY[this.locale];
|
|
3274
|
+
const labels = {
|
|
3275
|
+
undo: copy.undo,
|
|
3276
|
+
redo: copy.redo,
|
|
3277
|
+
clearAll: copy.clearAll,
|
|
3278
|
+
format: copy.format,
|
|
3279
|
+
help: copy.help
|
|
3280
|
+
};
|
|
3281
|
+
const icons = {
|
|
3282
|
+
undo: "\u21A9",
|
|
3283
|
+
redo: "\u21AA",
|
|
3284
|
+
clearAll: "\xD7",
|
|
3285
|
+
format: "\u2261",
|
|
3286
|
+
help: "?"
|
|
3287
|
+
};
|
|
3288
|
+
const titles = {
|
|
3289
|
+
undo: copy.undoTitle,
|
|
3290
|
+
redo: copy.redoTitle,
|
|
3291
|
+
clearAll: copy.clearAllTitle,
|
|
3292
|
+
format: copy.formatTitle,
|
|
3293
|
+
help: copy.helpTitle
|
|
3294
|
+
};
|
|
3295
|
+
const button = document.createElement("button");
|
|
3296
|
+
button.type = "button";
|
|
3297
|
+
button.className = "ssml-editor-toolbar-button";
|
|
3298
|
+
button.dataset.ssmlEditorButton = id;
|
|
3299
|
+
button.setAttribute("aria-label", labels[id] ?? id);
|
|
3300
|
+
button.title = titles[id] ?? labels[id] ?? id;
|
|
3301
|
+
button.disabled = this.readonly && id !== "help";
|
|
3302
|
+
if (id === "help") {
|
|
3303
|
+
button.setAttribute("aria-expanded", String(this.helpOpen));
|
|
3304
|
+
}
|
|
3305
|
+
const icon = document.createElement("span");
|
|
3306
|
+
icon.className = "ssml-editor-toolbar-icon";
|
|
3307
|
+
icon.setAttribute("aria-hidden", "true");
|
|
3308
|
+
icon.textContent = icons[id] ?? "";
|
|
3309
|
+
button.append(icon);
|
|
3310
|
+
if (this.hasAttribute("show-toolbar-labels")) {
|
|
3311
|
+
button.append(document.createTextNode(labels[id] ?? id));
|
|
3312
|
+
}
|
|
3313
|
+
button.addEventListener("click", () => {
|
|
3314
|
+
if (id === "help") {
|
|
3315
|
+
this.helpOpen = !this.helpOpen;
|
|
3316
|
+
button.setAttribute("aria-expanded", String(this.helpOpen));
|
|
3317
|
+
this.renderHelp();
|
|
3318
|
+
} else if (!this.readonly) {
|
|
3319
|
+
this.handleAction(id);
|
|
3320
|
+
}
|
|
3321
|
+
});
|
|
3322
|
+
this.toolbarButtons.set(id, button);
|
|
3323
|
+
return button;
|
|
3324
|
+
}
|
|
3325
|
+
createDecorationsSwitch() {
|
|
3326
|
+
const copy = EDITOR_COPY[this.locale];
|
|
3327
|
+
const wrapper = document.createElement("div");
|
|
3328
|
+
wrapper.className = "ssml-editor-toolbar-switch";
|
|
3329
|
+
const icon = document.createElement("span");
|
|
3330
|
+
icon.className = "ssml-editor-toolbar-icon";
|
|
3331
|
+
icon.setAttribute("aria-hidden", "true");
|
|
3332
|
+
icon.textContent = "\u2606";
|
|
3333
|
+
wrapper.append(icon);
|
|
3334
|
+
if (this.hasAttribute("show-toolbar-labels")) {
|
|
3335
|
+
wrapper.append(document.createTextNode(copy.decorations));
|
|
3336
|
+
}
|
|
3337
|
+
const button = document.createElement("button");
|
|
3338
|
+
button.type = "button";
|
|
3339
|
+
button.className = "ssml-editor-switch-track";
|
|
3340
|
+
button.dataset.ssmlEditorButton = "decorations";
|
|
3341
|
+
button.setAttribute("role", "switch");
|
|
3342
|
+
button.setAttribute("aria-label", copy.decorations);
|
|
3343
|
+
button.addEventListener("click", () => {
|
|
3344
|
+
this.decorationsVisible = !this.decorationsVisible;
|
|
3345
|
+
this.updateDecorations();
|
|
3346
|
+
});
|
|
3347
|
+
wrapper.append(button);
|
|
3348
|
+
this.toolbarButtons.set("decorations", button);
|
|
3349
|
+
this.updateDecorations();
|
|
3350
|
+
return wrapper;
|
|
3351
|
+
}
|
|
3352
|
+
createInsertionButton(insertion) {
|
|
3353
|
+
const button = document.createElement("button");
|
|
3354
|
+
button.type = "button";
|
|
3355
|
+
button.className = "ssml-editor-toolbar-button";
|
|
3356
|
+
button.dataset.ssmlEditorButton = insertion.id;
|
|
3357
|
+
button.setAttribute("aria-label", insertion.labels[this.locale]);
|
|
3358
|
+
button.setAttribute("aria-haspopup", "menu");
|
|
3359
|
+
button.setAttribute("aria-expanded", "false");
|
|
3360
|
+
button.title = insertion.titles?.[this.locale] ?? `${insertion.labels[this.locale]} \u2014 ${insertion.descriptions[this.locale]}`;
|
|
3361
|
+
const icon = document.createElement("span");
|
|
3362
|
+
icon.className = "ssml-editor-toolbar-icon";
|
|
3363
|
+
icon.setAttribute("aria-hidden", "true");
|
|
3364
|
+
icon.textContent = insertion.icon;
|
|
3365
|
+
button.append(icon);
|
|
3366
|
+
if (this.hasAttribute("show-toolbar-labels")) {
|
|
3367
|
+
button.append(document.createTextNode(insertion.labels[this.locale]));
|
|
3368
|
+
}
|
|
3369
|
+
const chevron = document.createElement("span");
|
|
3370
|
+
chevron.className = "ssml-editor-toolbar-chevron";
|
|
3371
|
+
chevron.setAttribute("aria-hidden", "true");
|
|
3372
|
+
chevron.textContent = "\u25BE";
|
|
3373
|
+
button.append(chevron);
|
|
3374
|
+
button.addEventListener("click", () => this.toggleInsertionMenu(insertion, button));
|
|
3375
|
+
this.toolbarButtons.set(insertion.id, button);
|
|
3376
|
+
const wrapper = document.createElement("div");
|
|
3377
|
+
wrapper.className = "ssml-editor-toolbar-dropdown";
|
|
3378
|
+
wrapper.append(button);
|
|
3379
|
+
return wrapper;
|
|
3380
|
+
}
|
|
3381
|
+
toggleInsertionMenu(insertion, trigger) {
|
|
3382
|
+
if (this.openMenuTrigger === trigger) {
|
|
3383
|
+
this.closeMenu();
|
|
3384
|
+
return;
|
|
3385
|
+
}
|
|
3386
|
+
this.closeMenu();
|
|
3387
|
+
const menu = this.createInsertionMenu(insertion);
|
|
3388
|
+
document.body.append(menu);
|
|
3389
|
+
const position = getMenuPosition(trigger, menu);
|
|
3390
|
+
menu.style.top = `${position.top}px`;
|
|
3391
|
+
menu.style.left = `${position.left}px`;
|
|
3392
|
+
trigger.setAttribute("aria-expanded", "true");
|
|
3393
|
+
trigger.setAttribute("aria-controls", menu.id);
|
|
3394
|
+
this.openMenu = menu;
|
|
3395
|
+
this.openMenuTrigger = trigger;
|
|
3396
|
+
}
|
|
3397
|
+
createInsertionMenu(insertion) {
|
|
3398
|
+
const menu = document.createElement("div");
|
|
3399
|
+
menu.className = "ssml-editor-toolbar-menu";
|
|
3400
|
+
menu.dataset.ssmlEditor = "";
|
|
3401
|
+
menu.dataset.theme = isDarkTheme(this.theme) ? "dark" : "light";
|
|
3402
|
+
menu.id = `ssml-editor-elements-menu-${insertion.id.replace(/[^A-Za-z0-9_-]/g, "-")}`;
|
|
3403
|
+
menu.setAttribute("role", "menu");
|
|
3404
|
+
menu.setAttribute("aria-label", insertion.labels[this.locale]);
|
|
3405
|
+
menu.addEventListener("pointerdown", (event) => event.stopPropagation());
|
|
3406
|
+
const options = this.getInsertionOptions(insertion);
|
|
3407
|
+
if (options.length === 0) {
|
|
3408
|
+
const empty = document.createElement("p");
|
|
3409
|
+
empty.className = "ssml-editor-toolbar-option";
|
|
3410
|
+
empty.textContent = EDITOR_COPY[this.locale].noAvailableOptions;
|
|
3411
|
+
menu.append(empty);
|
|
3412
|
+
} else {
|
|
3413
|
+
for (const group of this.getOptionGroups(insertion, options)) {
|
|
3414
|
+
if (group.label) {
|
|
3415
|
+
const fieldset = document.createElement("fieldset");
|
|
3416
|
+
fieldset.className = "ssml-editor-toolbar-option-group";
|
|
3417
|
+
const legend = document.createElement("legend");
|
|
3418
|
+
legend.textContent = group.label;
|
|
3419
|
+
fieldset.append(legend);
|
|
3420
|
+
for (const option of group.options) {
|
|
3421
|
+
fieldset.append(this.createOptionButton(insertion, option));
|
|
3422
|
+
}
|
|
3423
|
+
menu.append(fieldset);
|
|
3424
|
+
} else {
|
|
3425
|
+
for (const option of group.options) {
|
|
3426
|
+
menu.append(this.createOptionButton(insertion, option));
|
|
3427
|
+
}
|
|
3428
|
+
}
|
|
3429
|
+
}
|
|
3430
|
+
}
|
|
3431
|
+
return menu;
|
|
3432
|
+
}
|
|
3433
|
+
getInsertionOptions(insertion) {
|
|
3434
|
+
if (insertion.id !== "emotion") {
|
|
3435
|
+
return insertion.options;
|
|
3436
|
+
}
|
|
3437
|
+
const model = this.model;
|
|
3438
|
+
const selection = this.editor?.getSelection();
|
|
3439
|
+
const voiceContext = model && selection ? findSsmlVoiceContext(model.getValue(), model.getOffsetAt(selection.getStartPosition())) : void 0;
|
|
3440
|
+
const voiceName = voiceContext === void 0 ? this.documentState ? getEditableRegion(this.documentState).voiceName : void 0 : voiceContext.voiceName;
|
|
3441
|
+
const availableStyles = new Set(
|
|
3442
|
+
resolveExpressAsStyles(
|
|
3443
|
+
voiceName,
|
|
3444
|
+
insertion.options.map((option) => option.value)
|
|
3445
|
+
)
|
|
3446
|
+
);
|
|
3447
|
+
return insertion.options.filter((option) => availableStyles.has(option.value));
|
|
3448
|
+
}
|
|
3449
|
+
getOptionGroups(insertion, options) {
|
|
3450
|
+
if (insertion.id !== "emotion") {
|
|
3451
|
+
return [{ label: "", options }];
|
|
3452
|
+
}
|
|
3453
|
+
const copy = EDITOR_COPY[this.locale];
|
|
3454
|
+
const labels = {
|
|
3455
|
+
emotions: copy.categoryEmotions,
|
|
3456
|
+
scenarios: copy.categoryScenarios,
|
|
3457
|
+
media: copy.categoryMedia,
|
|
3458
|
+
other: copy.categoryOther
|
|
3459
|
+
};
|
|
3460
|
+
const categories = ["emotions", "scenarios", "media", "other"];
|
|
3461
|
+
return categories.map((category) => ({
|
|
3462
|
+
label: labels[category],
|
|
3463
|
+
options: options.filter((option) => getExpressAsStyleCategory(option.value) === category)
|
|
3464
|
+
})).filter((group) => group.options.length > 0);
|
|
3465
|
+
}
|
|
3466
|
+
createOptionButton(insertion, option) {
|
|
3467
|
+
const button = document.createElement("button");
|
|
3468
|
+
button.type = "button";
|
|
3469
|
+
button.className = "ssml-editor-toolbar-option";
|
|
3470
|
+
button.setAttribute("role", "menuitem");
|
|
3471
|
+
button.title = option.descriptions?.[this.locale] ?? insertion.descriptions[this.locale];
|
|
3472
|
+
button.textContent = option.labels[this.locale];
|
|
3473
|
+
button.disabled = this.readonly;
|
|
3474
|
+
button.addEventListener("click", () => {
|
|
3475
|
+
if (!this.readonly) {
|
|
3476
|
+
this.applyInsertion(insertion, option);
|
|
3477
|
+
}
|
|
3478
|
+
this.closeMenu(true);
|
|
3479
|
+
});
|
|
3480
|
+
button.addEventListener("mousedown", (event) => event.preventDefault());
|
|
3481
|
+
return button;
|
|
3482
|
+
}
|
|
3483
|
+
handleAction(id) {
|
|
3484
|
+
if (!this.editor) {
|
|
3485
|
+
return;
|
|
3486
|
+
}
|
|
3487
|
+
if (id === "undo" || id === "redo") {
|
|
3488
|
+
this.editor.trigger("ssml-toolbar", id, null);
|
|
3489
|
+
this.editor.focus();
|
|
3490
|
+
} else if (id === "clearAll") {
|
|
3491
|
+
if (this.documentState) {
|
|
3492
|
+
this.replaceDocument(clearSsmlDocument(this.documentState));
|
|
3493
|
+
}
|
|
3494
|
+
} else if (id === "format") {
|
|
3495
|
+
if (this.documentState) {
|
|
3496
|
+
this.replaceDocument(updateEditableText(this.documentState, formatXmlFragment(this.editor.getValue())));
|
|
3497
|
+
} else {
|
|
3498
|
+
this.replaceEditorValue(formatXmlFragment(this.editor.getValue()));
|
|
3499
|
+
}
|
|
3500
|
+
}
|
|
3501
|
+
}
|
|
3502
|
+
applyInsertion(insertion, option) {
|
|
3503
|
+
const editor = this.editor;
|
|
3504
|
+
const model = this.model;
|
|
3505
|
+
const selection = editor?.getSelection();
|
|
3506
|
+
if (!editor || !model || !selection) {
|
|
3507
|
+
return;
|
|
3508
|
+
}
|
|
3509
|
+
const startOffset = model.getOffsetAt(selection.getStartPosition());
|
|
3510
|
+
const endOffset = model.getOffsetAt(selection.getEndPosition());
|
|
3511
|
+
const selectedText = selection.isEmpty() ? "" : model.getValueInRange(selection);
|
|
3512
|
+
const result = createSsmlInsertionEdit(
|
|
3513
|
+
model.getValue(),
|
|
3514
|
+
startOffset,
|
|
3515
|
+
endOffset,
|
|
3516
|
+
insertion.createTemplate(option.value),
|
|
3517
|
+
model.getEOL(),
|
|
3518
|
+
selectedText
|
|
3519
|
+
);
|
|
3520
|
+
editor.pushUndoStop();
|
|
3521
|
+
const applied = editor.executeEdits("ssml-toolbar", [{ range: selection, text: result.replacement }]);
|
|
3522
|
+
editor.pushUndoStop();
|
|
3523
|
+
if (!applied) {
|
|
3524
|
+
return;
|
|
3525
|
+
}
|
|
3526
|
+
const start = model.getPositionAt(startOffset + result.selectionOffset);
|
|
3527
|
+
const end = model.getPositionAt(endOffset + result.selectionOffset);
|
|
3528
|
+
editor.setSelection({
|
|
3529
|
+
selectionStartLineNumber: start.lineNumber,
|
|
3530
|
+
selectionStartColumn: start.column,
|
|
3531
|
+
positionLineNumber: end.lineNumber,
|
|
3532
|
+
positionColumn: end.column
|
|
3533
|
+
});
|
|
3534
|
+
editor.focus();
|
|
3535
|
+
}
|
|
3536
|
+
replaceEditorValue(value) {
|
|
3537
|
+
const editor = this.editor;
|
|
3538
|
+
const model = editor?.getModel();
|
|
3539
|
+
if (!editor || !model || editor.getValue() === value) {
|
|
3540
|
+
return;
|
|
3541
|
+
}
|
|
3542
|
+
editor.pushUndoStop();
|
|
3543
|
+
editor.executeEdits("ssml-editor-toolbar", [
|
|
3544
|
+
{
|
|
3545
|
+
range: model.getFullModelRange(),
|
|
3546
|
+
text: value,
|
|
3547
|
+
forceMoveMarkers: true
|
|
3548
|
+
}
|
|
3549
|
+
]);
|
|
3550
|
+
editor.pushUndoStop();
|
|
3551
|
+
editor.focus();
|
|
3552
|
+
}
|
|
3553
|
+
replaceDocument(document2) {
|
|
3554
|
+
const editor = this.editor;
|
|
3555
|
+
const model = editor?.getModel();
|
|
3556
|
+
const editableValue = getEditableText(document2);
|
|
3557
|
+
const fullValue = buildSsml2(document2);
|
|
3558
|
+
this.documentState = document2;
|
|
3559
|
+
this.valueState = fullValue;
|
|
3560
|
+
if (!editor || !model || editor.getValue() === editableValue) {
|
|
3561
|
+
this.updateActiveButtons();
|
|
3562
|
+
this.dispatchChange(fullValue);
|
|
3563
|
+
return;
|
|
3564
|
+
}
|
|
3565
|
+
editor.pushUndoStop();
|
|
3566
|
+
editor.executeEdits("ssml-editor-toolbar", [
|
|
3567
|
+
{
|
|
3568
|
+
range: model.getFullModelRange(),
|
|
3569
|
+
text: editableValue,
|
|
3570
|
+
forceMoveMarkers: true
|
|
3571
|
+
}
|
|
3572
|
+
]);
|
|
3573
|
+
editor.pushUndoStop();
|
|
3574
|
+
editor.focus();
|
|
3575
|
+
}
|
|
3576
|
+
dispatchChange(value) {
|
|
3577
|
+
if (this.suppressChangeEvent) {
|
|
3578
|
+
return;
|
|
3579
|
+
}
|
|
3580
|
+
this.dispatchEvent(
|
|
3581
|
+
new CustomEvent("change", {
|
|
3582
|
+
detail: { value },
|
|
3583
|
+
bubbles: true,
|
|
3584
|
+
composed: true
|
|
3585
|
+
})
|
|
3586
|
+
);
|
|
3587
|
+
}
|
|
3588
|
+
updateDecorations() {
|
|
3589
|
+
const button = this.toolbarButtons.get("decorations");
|
|
3590
|
+
if (button) {
|
|
3591
|
+
const copy = EDITOR_COPY[this.locale];
|
|
3592
|
+
button.setAttribute("aria-checked", String(this.decorationsVisible));
|
|
3593
|
+
button.title = this.decorationsVisible ? copy.decorationsHideTitle : copy.decorationsShowTitle;
|
|
3594
|
+
}
|
|
3595
|
+
this.editor?.updateOptions({
|
|
3596
|
+
inlayHints: { enabled: this.decorationsVisible ? "on" : "off" }
|
|
3597
|
+
});
|
|
3598
|
+
}
|
|
3599
|
+
renderHelp() {
|
|
3600
|
+
const display = this.display;
|
|
3601
|
+
if (!display) {
|
|
3602
|
+
return;
|
|
3603
|
+
}
|
|
3604
|
+
this.helpPanel?.remove();
|
|
3605
|
+
this.helpPanel = null;
|
|
3606
|
+
const root = this.root;
|
|
3607
|
+
if (root) {
|
|
3608
|
+
root.setAttribute("aria-label", EDITOR_COPY[this.locale].editorAriaLabel);
|
|
3609
|
+
this.updateTheme();
|
|
3610
|
+
}
|
|
3611
|
+
if (!this.helpOpen || this.getAttribute("show-toolbar") === "false") {
|
|
3612
|
+
return;
|
|
3613
|
+
}
|
|
3614
|
+
const copy = EDITOR_COPY[this.locale];
|
|
3615
|
+
const panel = document.createElement("section");
|
|
3616
|
+
panel.className = "ssml-editor-help";
|
|
3617
|
+
panel.setAttribute("aria-label", copy.helpHeading);
|
|
3618
|
+
const heading = document.createElement("h3");
|
|
3619
|
+
heading.textContent = copy.helpHeading;
|
|
3620
|
+
const description = document.createElement("p");
|
|
3621
|
+
description.textContent = copy.helpDescription;
|
|
3622
|
+
const list = document.createElement("ul");
|
|
3623
|
+
list.className = "ssml-editor-help-list";
|
|
3624
|
+
for (const insertion of SSML_INSERTIONS) {
|
|
3625
|
+
const item = document.createElement("li");
|
|
3626
|
+
item.className = "ssml-editor-help-item";
|
|
3627
|
+
const details = document.createElement("details");
|
|
3628
|
+
const summary = document.createElement("summary");
|
|
3629
|
+
summary.textContent = `${insertion.icon} ${insertion.labels[this.locale]} \u2014 ${insertion.descriptions[this.locale]}`;
|
|
3630
|
+
const parameters = document.createElement("p");
|
|
3631
|
+
parameters.textContent = `${copy.parameters}: ${insertion.parameterDescription[this.locale]}`;
|
|
3632
|
+
const options = document.createElement("ul");
|
|
3633
|
+
for (const option of insertion.options) {
|
|
3634
|
+
const optionItem = document.createElement("li");
|
|
3635
|
+
optionItem.textContent = `${option.labels[this.locale]}${option.descriptions?.[this.locale] ? ` \u2014 ${option.descriptions[this.locale]}` : ""}`;
|
|
3636
|
+
options.append(optionItem);
|
|
3637
|
+
}
|
|
3638
|
+
details.append(summary, parameters, options);
|
|
3639
|
+
item.append(details);
|
|
3640
|
+
list.append(item);
|
|
3641
|
+
}
|
|
3642
|
+
panel.append(heading, description, list);
|
|
3643
|
+
display.prepend(panel);
|
|
3644
|
+
this.helpPanel = panel;
|
|
3645
|
+
}
|
|
3646
|
+
updateTheme() {
|
|
3647
|
+
if (this.root) {
|
|
3648
|
+
this.root.dataset.theme = isDarkTheme(this.theme) ? "dark" : "light";
|
|
3649
|
+
}
|
|
3650
|
+
}
|
|
3651
|
+
updateActiveButtons() {
|
|
3652
|
+
const editor = this.editor;
|
|
3653
|
+
const model = this.model;
|
|
3654
|
+
const selection = editor?.getSelection();
|
|
3655
|
+
if (!editor || !model || !selection) {
|
|
3656
|
+
return;
|
|
3657
|
+
}
|
|
3658
|
+
const activeTags = findActiveSsmlTags(model.getValue(), model.getOffsetAt(selection.getStartPosition()));
|
|
3659
|
+
for (const insertion of SSML_INSERTIONS) {
|
|
3660
|
+
const button = this.toolbarButtons.get(insertion.id);
|
|
3661
|
+
if (button) {
|
|
3662
|
+
button.dataset.active = String(
|
|
3663
|
+
insertion.tagName !== void 0 && activeTags.has(insertion.tagName.toLowerCase())
|
|
3664
|
+
);
|
|
3665
|
+
}
|
|
3666
|
+
}
|
|
3667
|
+
}
|
|
3668
|
+
async initialize(token) {
|
|
3669
|
+
const container = this.editorContainer;
|
|
3670
|
+
if (!container) {
|
|
3671
|
+
return;
|
|
3672
|
+
}
|
|
3673
|
+
const monacoModule = await import("monaco-editor");
|
|
3674
|
+
if (token !== this.initializationToken || !this.isConnected) {
|
|
3675
|
+
return;
|
|
3676
|
+
}
|
|
3677
|
+
const model = monacoModule.editor.createModel(this.prepareDocument(this.value), "xml");
|
|
3678
|
+
const editor = monacoModule.editor.create(container, {
|
|
3679
|
+
model,
|
|
3680
|
+
theme: this.theme,
|
|
3681
|
+
readOnly: this.readonly,
|
|
3682
|
+
automaticLayout: true,
|
|
3683
|
+
minimap: { enabled: false },
|
|
3684
|
+
wordWrap: "on",
|
|
3685
|
+
inlayHints: { enabled: this.decorationsVisible ? "on" : "off" }
|
|
3686
|
+
});
|
|
3687
|
+
if (token !== this.initializationToken || !this.isConnected) {
|
|
3688
|
+
editor.dispose();
|
|
3689
|
+
model.dispose();
|
|
3690
|
+
return;
|
|
3691
|
+
}
|
|
3692
|
+
this.monaco = monacoModule;
|
|
3693
|
+
this.model = model;
|
|
3694
|
+
this.editor = editor;
|
|
3695
|
+
this.contentDisposable = editor.onDidChangeModelContent(() => {
|
|
3696
|
+
const value = editor.getValue();
|
|
3697
|
+
let nextValue = value;
|
|
3698
|
+
if (this.documentState) {
|
|
3699
|
+
this.documentState = updateEditableText(this.documentState, value);
|
|
3700
|
+
nextValue = buildSsml2(this.documentState);
|
|
3701
|
+
}
|
|
3702
|
+
this.valueState = nextValue;
|
|
3703
|
+
this.updateActiveButtons();
|
|
3704
|
+
this.dispatchChange(nextValue);
|
|
3705
|
+
});
|
|
3706
|
+
this.cursorDisposable = editor.onDidChangeCursorPosition(() => this.updateActiveButtons());
|
|
3707
|
+
this.completionDisposable = registerSsmlCompletionProvider(monacoModule, {
|
|
3708
|
+
model,
|
|
3709
|
+
getOuterVoiceName: () => this.documentState ? getEditableRegion(this.documentState).voiceName : void 0
|
|
3710
|
+
});
|
|
3711
|
+
this.hoverDisposable = monacoModule.languages.registerHoverProvider("xml", {
|
|
3712
|
+
provideHover: (hoverModel, position) => {
|
|
3713
|
+
const target = findSsmlHoverTarget(hoverModel.getValue(), position.lineNumber, position.column);
|
|
3714
|
+
if (!target) {
|
|
3715
|
+
return void 0;
|
|
3716
|
+
}
|
|
3717
|
+
return {
|
|
3718
|
+
contents: [
|
|
3719
|
+
{
|
|
3720
|
+
isTrusted: false,
|
|
3721
|
+
supportHtml: false,
|
|
3722
|
+
value: formatSsmlHover(target)
|
|
3723
|
+
}
|
|
3724
|
+
],
|
|
3725
|
+
range: target.range
|
|
3726
|
+
};
|
|
3727
|
+
}
|
|
3728
|
+
});
|
|
3729
|
+
this.updateActiveButtons();
|
|
3730
|
+
}
|
|
3731
|
+
closeMenu(restoreFocus = false) {
|
|
3732
|
+
this.openMenu?.remove();
|
|
3733
|
+
this.openMenu = null;
|
|
3734
|
+
if (this.openMenuTrigger) {
|
|
3735
|
+
this.openMenuTrigger.setAttribute("aria-expanded", "false");
|
|
3736
|
+
this.openMenuTrigger.removeAttribute("aria-controls");
|
|
3737
|
+
if (restoreFocus) {
|
|
3738
|
+
this.openMenuTrigger.focus();
|
|
3739
|
+
}
|
|
3740
|
+
}
|
|
3741
|
+
this.openMenuTrigger = null;
|
|
3742
|
+
}
|
|
3743
|
+
disposeEditor() {
|
|
3744
|
+
this.closeMenu();
|
|
3745
|
+
this.contentDisposable?.dispose();
|
|
3746
|
+
this.contentDisposable = null;
|
|
3747
|
+
this.cursorDisposable?.dispose();
|
|
3748
|
+
this.cursorDisposable = null;
|
|
3749
|
+
this.completionDisposable?.dispose();
|
|
3750
|
+
this.completionDisposable = null;
|
|
3751
|
+
this.hoverDisposable?.dispose();
|
|
3752
|
+
this.hoverDisposable = null;
|
|
3753
|
+
this.editor?.dispose();
|
|
3754
|
+
this.editor = null;
|
|
3755
|
+
this.model?.dispose();
|
|
3756
|
+
this.model = null;
|
|
3757
|
+
this.monaco = null;
|
|
3758
|
+
this.root?.remove();
|
|
3759
|
+
this.root = null;
|
|
3760
|
+
this.toolbar = null;
|
|
3761
|
+
this.toolbarActions = null;
|
|
3762
|
+
this.display = null;
|
|
3763
|
+
this.editorContainer = null;
|
|
3764
|
+
this.helpPanel = null;
|
|
3765
|
+
this.toolbarButtons.clear();
|
|
3766
|
+
}
|
|
3767
|
+
};
|
|
3768
|
+
SsmlEditorElement.tagName = "ssml-editor";
|
|
3769
|
+
SsmlEditorElement.observedAttributes = [
|
|
3770
|
+
"value",
|
|
3771
|
+
"theme",
|
|
3772
|
+
"readonly",
|
|
3773
|
+
"locale",
|
|
3774
|
+
"show-toolbar",
|
|
3775
|
+
"show-toolbar-labels",
|
|
3776
|
+
"show-decorations"
|
|
3777
|
+
];
|
|
3778
|
+
|
|
3779
|
+
// src/index.ts
|
|
3780
|
+
function defineSsmlEditorElement() {
|
|
3781
|
+
if (typeof customElements === "undefined" || customElements.get(SsmlEditorElement.tagName)) {
|
|
3782
|
+
return;
|
|
3783
|
+
}
|
|
3784
|
+
customElements.define(SsmlEditorElement.tagName, SsmlEditorElement);
|
|
3785
|
+
}
|
|
3786
|
+
export {
|
|
3787
|
+
SsmlEditorElement,
|
|
3788
|
+
defineSsmlEditorElement
|
|
3789
|
+
};
|
|
3790
|
+
//# sourceMappingURL=index.mjs.map
|