@ssml-builder-js/ssml-editor-react 2.12.0 → 2.13.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/dist/index.mjs CHANGED
@@ -782,6 +782,152 @@ var SILENCE_VALUE_DESCRIPTIONS = {
782
782
  };
783
783
 
784
784
  // src/locales.ts
785
+ var SSML_ELEMENT_COPY = {
786
+ ja: {
787
+ dialog: {
788
+ label: "\u30C0\u30A4\u30A2\u30ED\u30B0",
789
+ description: "\u8907\u6570\u306E\u8A71\u8005\u30BF\u30FC\u30F3\u3092\u307E\u3068\u3081\u307E\u3059\u3002",
790
+ validationErrors: { turn: "turn \u306F dialog \u306E\u76F4\u4E0B\u306B\u914D\u7F6E\u3057\u3066\u304F\u3060\u3055\u3044\u3002" }
791
+ },
792
+ "mstts:dialog": {
793
+ label: "\u30C0\u30A4\u30A2\u30ED\u30B0",
794
+ description: "\u8907\u6570\u306E\u8A71\u8005\u30BF\u30FC\u30F3\u3092\u307E\u3068\u3081\u307E\u3059\u3002",
795
+ validationErrors: { turn: "turn \u306F dialog \u306E\u76F4\u4E0B\u306B\u914D\u7F6E\u3057\u3066\u304F\u3060\u3055\u3044\u3002" }
796
+ },
797
+ turn: {
798
+ label: "\u8A71\u8005\u30BF\u30FC\u30F3",
799
+ description: "\u30C0\u30A4\u30A2\u30ED\u30B0\u5185\u306E\u8A71\u8005\u3068\u767A\u8A71\u5185\u5BB9\u3092\u6307\u5B9A\u3057\u307E\u3059\u3002",
800
+ validationErrors: { voice: "voice \u307E\u305F\u306F speaker \u3092\u6307\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044\u3002" }
801
+ },
802
+ "mstts:turn": {
803
+ label: "\u8A71\u8005\u30BF\u30FC\u30F3",
804
+ description: "\u30C0\u30A4\u30A2\u30ED\u30B0\u5185\u306E\u8A71\u8005\u3068\u767A\u8A71\u5185\u5BB9\u3092\u6307\u5B9A\u3057\u307E\u3059\u3002",
805
+ validationErrors: { voice: "voice \u307E\u305F\u306F speaker \u3092\u6307\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044\u3002" }
806
+ },
807
+ backgroundaudio: {
808
+ label: "\u80CC\u666F\u97F3\u58F0",
809
+ description: "\u5408\u6210\u97F3\u58F0\u306E\u80CC\u5F8C\u3067\u518D\u751F\u3059\u308B\u97F3\u58F0\u30D5\u30A1\u30A4\u30EB\u3092\u6307\u5B9A\u3057\u307E\u3059\u3002",
810
+ validationErrors: { src: "\u80CC\u666F\u97F3\u58F0\u306B\u306F URL \u3092\u6307\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044\u3002" }
811
+ },
812
+ "mstts:backgroundaudio": {
813
+ label: "\u80CC\u666F\u97F3\u58F0",
814
+ description: "\u5408\u6210\u97F3\u58F0\u306E\u80CC\u5F8C\u3067\u518D\u751F\u3059\u308B\u97F3\u58F0\u30D5\u30A1\u30A4\u30EB\u3092\u6307\u5B9A\u3057\u307E\u3059\u3002",
815
+ validationErrors: { src: "\u80CC\u666F\u97F3\u58F0\u306B\u306F URL \u3092\u6307\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044\u3002" }
816
+ },
817
+ ttsembedding: {
818
+ label: "\u97F3\u58F0\u57CB\u3081\u8FBC\u307F",
819
+ description: "\u30AB\u30B9\u30BF\u30E0\u97F3\u58F0\u307E\u305F\u306F\u8A71\u8005\u30D7\u30ED\u30D5\u30A1\u30A4\u30EB\u306E\u30E1\u30BF\u30C7\u30FC\u30BF\u3092\u57CB\u3081\u8FBC\u307F\u307E\u3059\u3002",
820
+ validationErrors: { speakerProfileId: "\u8A71\u8005\u30D7\u30ED\u30D5\u30A1\u30A4\u30EB ID \u3092\u6307\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044\u3002" }
821
+ },
822
+ "mstts:ttsembedding": {
823
+ label: "\u97F3\u58F0\u57CB\u3081\u8FBC\u307F",
824
+ description: "\u30AB\u30B9\u30BF\u30E0\u97F3\u58F0\u307E\u305F\u306F\u8A71\u8005\u30D7\u30ED\u30D5\u30A1\u30A4\u30EB\u306E\u30E1\u30BF\u30C7\u30FC\u30BF\u3092\u57CB\u3081\u8FBC\u307F\u307E\u3059\u3002",
825
+ validationErrors: { speakerProfileId: "\u8A71\u8005\u30D7\u30ED\u30D5\u30A1\u30A4\u30EB ID \u3092\u6307\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044\u3002" }
826
+ },
827
+ embedding: {
828
+ label: "\u57CB\u3081\u8FBC\u307F",
829
+ description: "\u8A71\u8005\u57CB\u3081\u8FBC\u307F\u306E\u30E1\u30BF\u30C7\u30FC\u30BF\u3092\u6307\u5B9A\u3057\u307E\u3059\u3002",
830
+ validationErrors: {}
831
+ },
832
+ "mstts:embedding": {
833
+ label: "\u57CB\u3081\u8FBC\u307F",
834
+ description: "\u8A71\u8005\u57CB\u3081\u8FBC\u307F\u306E\u30E1\u30BF\u30C7\u30FC\u30BF\u3092\u6307\u5B9A\u3057\u307E\u3059\u3002",
835
+ validationErrors: {}
836
+ },
837
+ silence: {
838
+ label: "\u7121\u97F3",
839
+ description: "\u767A\u8A71\u524D\u5F8C\u307E\u305F\u306F\u53E5\u8AAD\u70B9\u306E\u5883\u754C\u306B\u7121\u97F3\u3092\u8FFD\u52A0\u3057\u307E\u3059\u3002",
840
+ validationErrors: { value: "\u7121\u97F3\u306E\u9577\u3055\u3092\u6307\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044\u3002" }
841
+ },
842
+ "mstts:silence": {
843
+ label: "\u7121\u97F3",
844
+ description: "\u767A\u8A71\u524D\u5F8C\u307E\u305F\u306F\u53E5\u8AAD\u70B9\u306E\u5883\u754C\u306B\u7121\u97F3\u3092\u8FFD\u52A0\u3057\u307E\u3059\u3002",
845
+ validationErrors: { value: "\u7121\u97F3\u306E\u9577\u3055\u3092\u6307\u5B9A\u3057\u3066\u304F\u3060\u3055\u3044\u3002" }
846
+ },
847
+ voiceconversion: {
848
+ label: "\u97F3\u58F0\u5909\u63DB",
849
+ description: "\u30AB\u30B9\u30BF\u30E0\u97F3\u58F0\u306E\u5909\u63DB\u30E1\u30BF\u30C7\u30FC\u30BF\u3092\u6307\u5B9A\u3057\u307E\u3059\u3002",
850
+ validationErrors: {}
851
+ },
852
+ "mstts:voiceconversion": {
853
+ label: "\u97F3\u58F0\u5909\u63DB",
854
+ description: "\u30AB\u30B9\u30BF\u30E0\u97F3\u58F0\u306E\u5909\u63DB\u30E1\u30BF\u30C7\u30FC\u30BF\u3092\u6307\u5B9A\u3057\u307E\u3059\u3002",
855
+ validationErrors: {}
856
+ }
857
+ },
858
+ en: {
859
+ dialog: {
860
+ label: "Dialog",
861
+ description: "Groups multiple speaker turns.",
862
+ validationErrors: { turn: "Place turns directly inside a dialog." }
863
+ },
864
+ "mstts:dialog": {
865
+ label: "Dialog",
866
+ description: "Groups multiple speaker turns.",
867
+ validationErrors: { turn: "Place turns directly inside a dialog." }
868
+ },
869
+ turn: {
870
+ label: "Dialog turn",
871
+ description: "Specifies a speaker and utterance within a dialog.",
872
+ validationErrors: { voice: "Provide a voice or speaker." }
873
+ },
874
+ "mstts:turn": {
875
+ label: "Dialog turn",
876
+ description: "Specifies a speaker and utterance within a dialog.",
877
+ validationErrors: { voice: "Provide a voice or speaker." }
878
+ },
879
+ backgroundaudio: {
880
+ label: "Background audio",
881
+ description: "Specifies an audio file played behind synthesized speech.",
882
+ validationErrors: { src: "Provide a background audio URL." }
883
+ },
884
+ "mstts:backgroundaudio": {
885
+ label: "Background audio",
886
+ description: "Specifies an audio file played behind synthesized speech.",
887
+ validationErrors: { src: "Provide a background audio URL." }
888
+ },
889
+ ttsembedding: {
890
+ label: "TTS embedding",
891
+ description: "Embeds custom voice or speaker profile metadata.",
892
+ validationErrors: { speakerProfileId: "Provide a speaker profile ID." }
893
+ },
894
+ "mstts:ttsembedding": {
895
+ label: "TTS embedding",
896
+ description: "Embeds custom voice or speaker profile metadata.",
897
+ validationErrors: { speakerProfileId: "Provide a speaker profile ID." }
898
+ },
899
+ embedding: {
900
+ label: "Embedding",
901
+ description: "Specifies speaker embedding metadata.",
902
+ validationErrors: {}
903
+ },
904
+ "mstts:embedding": {
905
+ label: "Embedding",
906
+ description: "Specifies speaker embedding metadata.",
907
+ validationErrors: {}
908
+ },
909
+ silence: {
910
+ label: "Silence",
911
+ description: "Adds silence before, after, or around punctuation.",
912
+ validationErrors: { value: "Provide a silence duration." }
913
+ },
914
+ "mstts:silence": {
915
+ label: "Silence",
916
+ description: "Adds silence before, after, or around punctuation.",
917
+ validationErrors: { value: "Provide a silence duration." }
918
+ },
919
+ voiceconversion: {
920
+ label: "Voice conversion",
921
+ description: "Specifies custom voice conversion metadata.",
922
+ validationErrors: {}
923
+ },
924
+ "mstts:voiceconversion": {
925
+ label: "Voice conversion",
926
+ description: "Specifies custom voice conversion metadata.",
927
+ validationErrors: {}
928
+ }
929
+ }
930
+ };
785
931
  var EDITOR_COPY = {
786
932
  ja: {
787
933
  editorAriaLabel: "SSML\u30A8\u30C7\u30A3\u30BF\u30FC",
@@ -999,6 +1145,42 @@ var SSML_HOVER_COPY = {
999
1145
  parameters: {
1000
1146
  value: { title: "value", description: "\u76EE\u6A19\u6642\u9593\u3002\u4F8B: `10s`\u3001`5000ms`\u3001`00:00:10`\u3002" }
1001
1147
  }
1148
+ },
1149
+ "mstts:dialog": { title: "\u30C0\u30A4\u30A2\u30ED\u30B0", description: "\u8907\u6570\u306E\u8A71\u8005\u30BF\u30FC\u30F3\u3092\u307E\u3068\u3081\u307E\u3059\u3002", parameters: {} },
1150
+ "mstts:turn": {
1151
+ title: "\u8A71\u8005\u30BF\u30FC\u30F3",
1152
+ description: "\u30C0\u30A4\u30A2\u30ED\u30B0\u5185\u306E\u8A71\u8005\u3068\u767A\u8A71\u5185\u5BB9\u3092\u6307\u5B9A\u3057\u307E\u3059\u3002",
1153
+ parameters: {
1154
+ voice: { title: "voice", description: "\u3053\u306E\u30BF\u30FC\u30F3\u3067\u4F7F\u7528\u3059\u308B Azure \u97F3\u58F0\u540D\u3002" },
1155
+ speaker: { title: "speaker", description: "\u8A71\u8005\u8B58\u5225\u5B50\u3002" }
1156
+ }
1157
+ },
1158
+ "mstts:backgroundaudio": {
1159
+ title: "\u80CC\u666F\u97F3\u58F0",
1160
+ description: "\u5408\u6210\u97F3\u58F0\u306E\u80CC\u5F8C\u3067\u518D\u751F\u3059\u308B\u97F3\u58F0\u30D5\u30A1\u30A4\u30EB\u3092\u6307\u5B9A\u3057\u307E\u3059\u3002",
1161
+ parameters: { src: { title: "src", description: "\u97F3\u58F0\u30D5\u30A1\u30A4\u30EB\u306E HTTPS URL\u3002" } }
1162
+ },
1163
+ "mstts:ttsembedding": {
1164
+ title: "\u97F3\u58F0\u57CB\u3081\u8FBC\u307F",
1165
+ description: "\u30AB\u30B9\u30BF\u30E0\u97F3\u58F0\u307E\u305F\u306F\u8A71\u8005\u30D7\u30ED\u30D5\u30A1\u30A4\u30EB\u306E\u30E1\u30BF\u30C7\u30FC\u30BF\u3092\u57CB\u3081\u8FBC\u307F\u307E\u3059\u3002",
1166
+ parameters: { speakerProfileId: { title: "speakerProfileId", description: "\u8A71\u8005\u30D7\u30ED\u30D5\u30A1\u30A4\u30EB ID\u3002" } }
1167
+ },
1168
+ "mstts:embedding": {
1169
+ title: "\u57CB\u3081\u8FBC\u307F",
1170
+ description: "\u8A71\u8005\u57CB\u3081\u8FBC\u307F\u306E\u30E1\u30BF\u30C7\u30FC\u30BF\u3092\u6307\u5B9A\u3057\u307E\u3059\u3002",
1171
+ parameters: {
1172
+ id: { title: "id", description: "\u57CB\u3081\u8FBC\u307F ID\u3002" },
1173
+ speakerProfileId: { title: "speakerProfileId", description: "\u8A71\u8005\u30D7\u30ED\u30D5\u30A1\u30A4\u30EB ID\u3002" }
1174
+ }
1175
+ },
1176
+ "mstts:voiceconversion": {
1177
+ title: "\u97F3\u58F0\u5909\u63DB",
1178
+ description: "\u30AB\u30B9\u30BF\u30E0\u97F3\u58F0\u306E\u5909\u63DB\u30E1\u30BF\u30C7\u30FC\u30BF\u3092\u6307\u5B9A\u3057\u307E\u3059\u3002",
1179
+ parameters: {
1180
+ url: { title: "url", description: "\u97F3\u58F0\u5909\u63DB\u30D7\u30ED\u30D5\u30A1\u30A4\u30EB URL\u3002" },
1181
+ profile: { title: "profile", description: "\u5909\u63DB\u30D7\u30ED\u30D5\u30A1\u30A4\u30EB\u3002" },
1182
+ speakerProfileId: { title: "speakerProfileId", description: "\u8A71\u8005\u30D7\u30ED\u30D5\u30A1\u30A4\u30EB ID\u3002" }
1183
+ }
1002
1184
  }
1003
1185
  }
1004
1186
  },
@@ -1163,6 +1345,42 @@ var SSML_HOVER_COPY = {
1163
1345
  parameters: {
1164
1346
  value: { title: "value", description: "The target duration, such as `10s`, `5000ms`, or `00:00:10`." }
1165
1347
  }
1348
+ },
1349
+ "mstts:dialog": { title: "Dialog", description: "Groups multiple speaker turns.", parameters: {} },
1350
+ "mstts:turn": {
1351
+ title: "Dialog turn",
1352
+ description: "Specifies a speaker and utterance within a dialog.",
1353
+ parameters: {
1354
+ voice: { title: "voice", description: "The Azure voice used by this turn." },
1355
+ speaker: { title: "speaker", description: "The speaker identifier." }
1356
+ }
1357
+ },
1358
+ "mstts:backgroundaudio": {
1359
+ title: "Background audio",
1360
+ description: "Specifies an audio file played behind synthesized speech.",
1361
+ parameters: { src: { title: "src", description: "The HTTPS URL of the audio file." } }
1362
+ },
1363
+ "mstts:ttsembedding": {
1364
+ title: "TTS embedding",
1365
+ description: "Embeds custom voice or speaker profile metadata.",
1366
+ parameters: { speakerProfileId: { title: "speakerProfileId", description: "The speaker profile ID." } }
1367
+ },
1368
+ "mstts:embedding": {
1369
+ title: "Embedding",
1370
+ description: "Specifies speaker embedding metadata.",
1371
+ parameters: {
1372
+ id: { title: "id", description: "The embedding ID." },
1373
+ speakerProfileId: { title: "speakerProfileId", description: "The speaker profile ID." }
1374
+ }
1375
+ },
1376
+ "mstts:voiceconversion": {
1377
+ title: "Voice conversion",
1378
+ description: "Specifies custom voice conversion metadata.",
1379
+ parameters: {
1380
+ url: { title: "url", description: "The voice conversion profile URL." },
1381
+ profile: { title: "profile", description: "The conversion profile." },
1382
+ speakerProfileId: { title: "speakerProfileId", description: "The speaker profile ID." }
1383
+ }
1166
1384
  }
1167
1385
  }
1168
1386
  }
@@ -4775,14 +4993,55 @@ var VISUAL_ELEMENT_FIELDS = {
4775
4993
  function getElementFields(element) {
4776
4994
  return VISUAL_ELEMENT_FIELDS[elementLabel(element)] ?? [];
4777
4995
  }
4996
+ function localizedElementLabel(element, locale) {
4997
+ return SSML_ELEMENT_COPY[locale][elementLabel(element)]?.label ?? elementLabel(element);
4998
+ }
4999
+ function filteredVoices(voiceCatalog, locale, region, style) {
5000
+ return (voiceCatalog ?? []).filter((voice) => {
5001
+ if (locale && voice.locale.toLowerCase() !== locale.toLowerCase()) return false;
5002
+ if (region && voice.region && voice.region.toLowerCase() !== region.toLowerCase()) return false;
5003
+ if (style && !voice.styles?.some((candidate) => candidate.toLowerCase() === style.toLowerCase())) return false;
5004
+ return true;
5005
+ });
5006
+ }
5007
+ function DefaultVoiceSelector({ value, voices, readOnly, locale, onChange }) {
5008
+ return /* @__PURE__ */ jsxs2(
5009
+ "select",
5010
+ {
5011
+ "aria-label": locale === "ja" ? "\u97F3\u58F0" : "Voice",
5012
+ value,
5013
+ disabled: readOnly,
5014
+ onChange: (event) => onChange(event.target.value),
5015
+ children: [
5016
+ /* @__PURE__ */ jsx6("option", { value: "", children: locale === "ja" ? "\u97F3\u58F0\u3092\u9078\u629E" : "Select a voice" }),
5017
+ voices.map((voice) => /* @__PURE__ */ jsxs2("option", { value: voice.name, children: [
5018
+ voice.name,
5019
+ voice.preview || voice.status === "preview" ? " (preview)" : ""
5020
+ ] }, voice.name))
5021
+ ]
5022
+ }
5023
+ );
5024
+ }
4778
5025
  function VisualElementInspector({
4779
5026
  document: document2,
4780
5027
  element,
4781
5028
  path,
4782
5029
  readOnly,
4783
- commit
5030
+ commit,
5031
+ locale,
5032
+ customInspector,
5033
+ renderVoiceSelector,
5034
+ voiceCatalog,
5035
+ voiceLocale,
5036
+ voiceRegion,
5037
+ voiceStyle
4784
5038
  }) {
5039
+ if (customInspector) {
5040
+ return /* @__PURE__ */ jsx6(Fragment3, { children: customInspector({ document: document2, element, path, readOnly, onChange: commit, locale }) });
5041
+ }
4785
5042
  const fields = getElementFields(element);
5043
+ const availableVoices = filteredVoices(voiceCatalog, voiceLocale, voiceRegion, voiceStyle);
5044
+ const renderSelector = renderVoiceSelector ?? DefaultVoiceSelector;
4786
5045
  return /* @__PURE__ */ jsxs2("fieldset", { children: [
4787
5046
  /* @__PURE__ */ jsx6("legend", { children: `<${elementLabel(element)}>` }),
4788
5047
  fields.length === 0 ? /* @__PURE__ */ jsx6("p", { children: "This element is preserved in the visual tree. Edit its attributes in Code mode." }) : fields.map((field) => {
@@ -4790,8 +5049,47 @@ function VisualElementInspector({
4790
5049
  const inputValue = value === void 0 ? "" : String(value);
4791
5050
  const inputId = `ssml-visual-${field.key}`;
4792
5051
  return /* @__PURE__ */ jsxs2("label", { htmlFor: inputId, children: [
4793
- field.label,
4794
- field.multiline ? /* @__PURE__ */ jsx6(
5052
+ locale === "ja" ? {
5053
+ name: "\u540D\u524D",
5054
+ effect: "\u52B9\u679C",
5055
+ rate: "\u901F\u5EA6",
5056
+ pitch: "\u30D4\u30C3\u30C1",
5057
+ volume: "\u97F3\u91CF",
5058
+ contour: "\u30D4\u30C3\u30C1\u66F2\u7DDA",
5059
+ range: "\u7BC4\u56F2",
5060
+ style: "\u30B9\u30BF\u30A4\u30EB",
5061
+ styleDegree: "\u30B9\u30BF\u30A4\u30EB\u5F37\u5EA6",
5062
+ role: "\u5F79\u5272",
5063
+ interpretAs: "\u89E3\u91C8",
5064
+ alphabet: "\u30A2\u30EB\u30D5\u30A1\u30D9\u30C3\u30C8",
5065
+ ph: "\u767A\u97F3",
5066
+ level: "\u5F37\u8ABF\u30EC\u30D9\u30EB",
5067
+ src: "\u97F3\u58F0 URL",
5068
+ desc: "\u8AAC\u660E",
5069
+ clipBegin: "\u958B\u59CB\u4F4D\u7F6E",
5070
+ clipEnd: "\u7D42\u4E86\u4F4D\u7F6E",
5071
+ speed: "\u901F\u5EA6",
5072
+ repeatCount: "\u7E70\u308A\u8FD4\u3057\u56DE\u6570",
5073
+ repeatDuration: "\u7E70\u308A\u8FD4\u3057\u6642\u9593",
5074
+ soundLevel: "\u97F3\u91CF\u30EC\u30D9\u30EB",
5075
+ mark: "\u30D6\u30C3\u30AF\u30DE\u30FC\u30AF\u540D",
5076
+ alias: "\u5225\u540D",
5077
+ lang: "\u8A00\u8A9E",
5078
+ uri: "\u8F9E\u66F8 URI",
5079
+ typeValue: "\u7121\u97F3\u306E\u7A2E\u985E",
5080
+ value: "\u5024",
5081
+ id: "\u57CB\u3081\u8FBC\u307F ID",
5082
+ speakerProfileId: "\u8A71\u8005\u30D7\u30ED\u30D5\u30A1\u30A4\u30EB ID",
5083
+ url: "\u97F3\u58F0\u5909\u63DB URL",
5084
+ profile: "\u30D7\u30ED\u30D5\u30A1\u30A4\u30EB"
5085
+ }[field.key] ?? field.label : field.label,
5086
+ field.key === "name" && elementLabel(element) === "voice" && voiceCatalog ? renderSelector({
5087
+ value: inputValue,
5088
+ voices: availableVoices,
5089
+ readOnly,
5090
+ locale,
5091
+ onChange: (value2) => commit(updateOptionalElementProperty(document2, path, field.key, value2))
5092
+ }) : field.multiline ? /* @__PURE__ */ jsx6(
4795
5093
  "textarea",
4796
5094
  {
4797
5095
  id: inputId,
@@ -4887,13 +5185,21 @@ function VisualSsmlEditor({
4887
5185
  document: document2,
4888
5186
  readOnly = false,
4889
5187
  onChange,
4890
- onPreviewSelection
5188
+ onPreviewSelection,
5189
+ locale = "en",
5190
+ customInspectors,
5191
+ renderVoiceSelector,
5192
+ voiceCatalog,
5193
+ voiceLocale,
5194
+ voiceRegion,
5195
+ voiceStyle
4891
5196
  }) {
4892
5197
  const [selectedPath, setSelectedPath] = useState2(null);
4893
5198
  const [selection, setSelection] = useState2({ start: 0, end: 0 });
4894
5199
  const textLeaves = useMemo(() => collectTextLeaves(document2.children ?? []), [document2]);
4895
5200
  const selectedLeaf = textLeaves.find((leaf) => leaf.path.join(".") === selectedPath?.join(".")) ?? textLeaves[0];
4896
5201
  const selectedElement = selectedPath ? getNodeAtPath(document2.children ?? [], selectedPath) : void 0;
5202
+ const selectedCustomInspector = selectedElement && isElement(selectedElement) ? customInspectors?.[elementLabel(selectedElement)] ?? customInspectors?.[selectedElement.type] : void 0;
4897
5203
  const diagnostics = useMemo(() => validateAzureSsml(buildSsml3(document2)), [document2]);
4898
5204
  const commit = (nextDocument) => onChange?.(nextDocument);
4899
5205
  const applyWrapper = (tag, attributes) => {
@@ -4928,25 +5234,39 @@ function VisualSsmlEditor({
4928
5234
  isElement(node) ? elementLabel(node) : JSON.stringify(node)
4929
5235
  )) })
4930
5236
  ] }),
4931
- /* @__PURE__ */ jsx6("div", { className: "ssml-editor-visual-form", children: selectedElement && isElement(selectedElement) && selectedElement.type === "mstts:dialog" ? /* @__PURE__ */ jsxs2("fieldset", { children: [
4932
- /* @__PURE__ */ jsx6("legend", { children: "Dialog" }),
4933
- /* @__PURE__ */ jsx6("p", { children: "Add and edit speaker turns in this dialog." }),
5237
+ /* @__PURE__ */ jsx6("div", { className: "ssml-editor-visual-form", children: selectedCustomInspector && selectedElement && isElement(selectedElement) ? selectedCustomInspector({
5238
+ document: document2,
5239
+ element: selectedElement,
5240
+ path: selectedPath ?? [],
5241
+ readOnly,
5242
+ onChange: commit,
5243
+ locale
5244
+ }) : selectedElement && isElement(selectedElement) && selectedElement.type === "mstts:dialog" ? /* @__PURE__ */ jsxs2("fieldset", { children: [
5245
+ /* @__PURE__ */ jsx6("legend", { children: localizedElementLabel(selectedElement, locale) }),
5246
+ /* @__PURE__ */ jsx6("p", { children: SSML_ELEMENT_COPY[locale][elementLabel(selectedElement)]?.description }),
4934
5247
  /* @__PURE__ */ jsx6(
4935
5248
  "button",
4936
5249
  {
4937
5250
  type: "button",
4938
5251
  disabled: readOnly,
4939
5252
  onClick: () => commit(addDialogTurn(document2, selectedPath ?? [])),
4940
- children: "Add turn"
5253
+ children: locale === "ja" ? "\u30BF\u30FC\u30F3\u3092\u8FFD\u52A0" : "Add turn"
4941
5254
  }
4942
5255
  )
4943
5256
  ] }) : selectedElement && isElement(selectedElement) && selectedElement.type === "mstts:turn" ? /* @__PURE__ */ jsxs2("fieldset", { children: [
4944
- /* @__PURE__ */ jsx6("legend", { children: "Dialog turn" }),
4945
- /* @__PURE__ */ jsxs2("label", { children: [
4946
- "Voice",
4947
- /* @__PURE__ */ jsx6(
5257
+ /* @__PURE__ */ jsx6("legend", { children: localizedElementLabel(selectedElement, locale) }),
5258
+ /* @__PURE__ */ jsxs2("label", { htmlFor: "ssml-visual-turn-voice", children: [
5259
+ locale === "ja" ? "\u97F3\u58F0" : "Voice",
5260
+ voiceCatalog ? (renderVoiceSelector ?? DefaultVoiceSelector)({
5261
+ value: selectedElement.voice ?? "",
5262
+ voices: filteredVoices(voiceCatalog, voiceLocale, voiceRegion, voiceStyle),
5263
+ readOnly,
5264
+ locale,
5265
+ onChange: (value) => commit(updateOptionalElementProperty(document2, selectedPath ?? [], "voice", value))
5266
+ }) : /* @__PURE__ */ jsx6(
4948
5267
  "input",
4949
5268
  {
5269
+ id: "ssml-visual-turn-voice",
4950
5270
  value: selectedElement.voice ?? "",
4951
5271
  readOnly,
4952
5272
  onChange: (event) => commit(updateOptionalElementProperty(document2, selectedPath ?? [], "voice", event.target.value))
@@ -4954,7 +5274,7 @@ function VisualSsmlEditor({
4954
5274
  )
4955
5275
  ] }),
4956
5276
  /* @__PURE__ */ jsxs2("label", { children: [
4957
- "Speaker",
5277
+ locale === "ja" ? "\u8A71\u8005" : "Speaker",
4958
5278
  /* @__PURE__ */ jsx6(
4959
5279
  "input",
4960
5280
  {
@@ -4965,7 +5285,7 @@ function VisualSsmlEditor({
4965
5285
  )
4966
5286
  ] }),
4967
5287
  /* @__PURE__ */ jsxs2("label", { children: [
4968
- "Turn text",
5288
+ locale === "ja" ? "\u767A\u8A71\u30C6\u30AD\u30B9\u30C8" : "Turn text",
4969
5289
  /* @__PURE__ */ jsx6(
4970
5290
  "textarea",
4971
5291
  {
@@ -4982,9 +5302,9 @@ function VisualSsmlEditor({
4982
5302
  )
4983
5303
  ] })
4984
5304
  ] }) : selectedElement && isElement(selectedElement) && selectedElement.type === "mstts:backgroundaudio" ? /* @__PURE__ */ jsxs2("fieldset", { children: [
4985
- /* @__PURE__ */ jsx6("legend", { children: "Background audio" }),
5305
+ /* @__PURE__ */ jsx6("legend", { children: localizedElementLabel(selectedElement, locale) }),
4986
5306
  /* @__PURE__ */ jsxs2("label", { children: [
4987
- "Source URL",
5307
+ locale === "ja" ? "\u97F3\u58F0 URL" : "Source URL",
4988
5308
  /* @__PURE__ */ jsx6(
4989
5309
  "input",
4990
5310
  {
@@ -4995,7 +5315,7 @@ function VisualSsmlEditor({
4995
5315
  )
4996
5316
  ] }),
4997
5317
  /* @__PURE__ */ jsxs2("label", { children: [
4998
- "Volume",
5318
+ locale === "ja" ? "\u97F3\u91CF" : "Volume",
4999
5319
  /* @__PURE__ */ jsx6(
5000
5320
  "input",
5001
5321
  {
@@ -5006,7 +5326,7 @@ function VisualSsmlEditor({
5006
5326
  )
5007
5327
  ] }),
5008
5328
  /* @__PURE__ */ jsxs2("label", { children: [
5009
- "Fade in",
5329
+ locale === "ja" ? "\u30D5\u30A7\u30FC\u30C9\u30A4\u30F3" : "Fade in",
5010
5330
  /* @__PURE__ */ jsx6(
5011
5331
  "input",
5012
5332
  {
@@ -5017,7 +5337,7 @@ function VisualSsmlEditor({
5017
5337
  )
5018
5338
  ] }),
5019
5339
  /* @__PURE__ */ jsxs2("label", { children: [
5020
- "Fade out",
5340
+ locale === "ja" ? "\u30D5\u30A7\u30FC\u30C9\u30A2\u30A6\u30C8" : "Fade out",
5021
5341
  /* @__PURE__ */ jsx6(
5022
5342
  "input",
5023
5343
  {
@@ -5034,7 +5354,14 @@ function VisualSsmlEditor({
5034
5354
  element: selectedElement,
5035
5355
  path: selectedPath ?? [],
5036
5356
  readOnly,
5037
- commit
5357
+ commit,
5358
+ locale,
5359
+ customInspector: customInspectors?.[elementLabel(selectedElement)] ?? customInspectors?.[selectedElement.type],
5360
+ renderVoiceSelector,
5361
+ voiceCatalog,
5362
+ voiceLocale,
5363
+ voiceRegion,
5364
+ voiceStyle
5038
5365
  }
5039
5366
  ) : selectedLeaf ? /* @__PURE__ */ jsxs2(Fragment3, { children: [
5040
5367
  /* @__PURE__ */ jsxs2("label", { children: [
@@ -5673,6 +6000,12 @@ var SsmlEditor = forwardRef(function SsmlEditor2({
5673
6000
  insertionGroups,
5674
6001
  customInsertions,
5675
6002
  additionalInsertions,
6003
+ customInspectors,
6004
+ renderVoiceSelector,
6005
+ voiceCatalog,
6006
+ voiceLocale,
6007
+ voiceRegion,
6008
+ voiceStyle,
5676
6009
  emotionStyles,
5677
6010
  className,
5678
6011
  style,
@@ -6114,7 +6447,14 @@ var SsmlEditor = forwardRef(function SsmlEditor2({
6114
6447
  document: draftDocument,
6115
6448
  readOnly: isReadOnly,
6116
6449
  onChange: commit,
6117
- onPreviewSelection
6450
+ onPreviewSelection,
6451
+ locale: localeProp ?? languageProp,
6452
+ customInspectors,
6453
+ renderVoiceSelector,
6454
+ voiceCatalog,
6455
+ voiceLocale,
6456
+ voiceRegion,
6457
+ voiceStyle
6118
6458
  }
6119
6459
  ) }) : /* @__PURE__ */ jsxs3("div", { style: { ...editorStyles.editor, minHeight: editorMinHeight }, children: [
6120
6460
  /* @__PURE__ */ jsx7(
@@ -6192,6 +6532,7 @@ var SsmlEditor = forwardRef(function SsmlEditor2({
6192
6532
  export {
6193
6533
  EDITOR_COPY,
6194
6534
  INLINE_BADGE_COPY,
6535
+ SSML_ELEMENT_COPY,
6195
6536
  SSML_HOVER_COPY,
6196
6537
  SSML_INSERTIONS,
6197
6538
  SsmlEditor,