henkan 0.6.1 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (63) hide show
  1. package/README.md +4 -2
  2. package/dist/index.cjs.js +53 -165
  3. package/dist/index.cjs.js.map +3 -3
  4. package/dist/index.mjs +53 -163
  5. package/dist/index.mjs.map +2 -2
  6. package/dist/types/constants.d.ts +0 -3
  7. package/dist/types/constants.d.ts.map +1 -1
  8. package/dist/types/types.d.ts +21 -6
  9. package/dist/types/types.d.ts.map +1 -1
  10. package/dist/types/utils.d.ts +10 -14
  11. package/dist/types/utils.d.ts.map +1 -1
  12. package/docs/api/README.md +1 -1
  13. package/docs/api/functions/capitalizeString.md +1 -1
  14. package/docs/api/functions/convertJMdict.md +1 -1
  15. package/docs/api/functions/convertKanjiDic.md +1 -1
  16. package/docs/api/functions/convertKradFile.md +1 -1
  17. package/docs/api/functions/convertRadkFile.md +1 -1
  18. package/docs/api/functions/convertTanakaCorpus.md +1 -1
  19. package/docs/api/functions/generateAnkiNote.md +1 -1
  20. package/docs/api/functions/generateAnkiNotesFile.md +1 -1
  21. package/docs/api/functions/getKanji.md +1 -1
  22. package/docs/api/functions/getKanjiExtended.md +1 -1
  23. package/docs/api/functions/getWord.md +1 -1
  24. package/docs/api/functions/isStringArray.md +1 -1
  25. package/docs/api/functions/isValidArray.md +1 -1
  26. package/docs/api/functions/isValidArrayWithFirstElement.md +1 -1
  27. package/docs/api/functions/shuffleArray.md +1 -1
  28. package/docs/api/functions/synthesizeSpeech.md +25 -13
  29. package/docs/api/interfaces/DictKanji.md +5 -5
  30. package/docs/api/interfaces/DictKanjiForm.md +4 -4
  31. package/docs/api/interfaces/DictKanjiMisc.md +5 -5
  32. package/docs/api/interfaces/DictKanjiReading.md +3 -3
  33. package/docs/api/interfaces/DictKanjiReadingMeaning.md +3 -3
  34. package/docs/api/interfaces/DictKanjiReadingMeaningGroup.md +3 -3
  35. package/docs/api/interfaces/DictKanjiWithRadicals.md +3 -3
  36. package/docs/api/interfaces/DictMeaning.md +11 -11
  37. package/docs/api/interfaces/DictRadical.md +4 -4
  38. package/docs/api/interfaces/DictReading.md +5 -5
  39. package/docs/api/interfaces/DictWord.md +8 -8
  40. package/docs/api/interfaces/ExamplePart.md +7 -7
  41. package/docs/api/interfaces/GlossSpecificNumber.md +31 -0
  42. package/docs/api/interfaces/Grammar.md +15 -15
  43. package/docs/api/interfaces/GrammarMeaning.md +3 -3
  44. package/docs/api/interfaces/Kana.md +11 -11
  45. package/docs/api/interfaces/Kanji.md +22 -22
  46. package/docs/api/interfaces/KanjiComponent.md +3 -3
  47. package/docs/api/interfaces/KanjiForm.md +4 -4
  48. package/docs/api/interfaces/NoteAndTag.md +3 -3
  49. package/docs/api/interfaces/Phrase.md +16 -4
  50. package/docs/api/interfaces/Radical.md +16 -16
  51. package/docs/api/interfaces/Reading.md +5 -5
  52. package/docs/api/interfaces/ResultEntry.md +7 -7
  53. package/docs/api/interfaces/TanakaExample.md +16 -6
  54. package/docs/api/interfaces/Translation.md +3 -3
  55. package/docs/api/interfaces/UsefulRegExps.md +8 -20
  56. package/docs/api/interfaces/Word.md +14 -14
  57. package/docs/api/type-aliases/Dict.md +1 -1
  58. package/docs/api/type-aliases/DictName.md +1 -1
  59. package/docs/api/type-aliases/EntryType.md +1 -1
  60. package/docs/api/type-aliases/JLPT.md +1 -1
  61. package/docs/api/type-aliases/Result.md +1 -1
  62. package/package.json +5 -5
  63. package/docs/api/functions/makeSSML.md +0 -33
package/README.md CHANGED
@@ -36,7 +36,7 @@ pnpm add henkan
36
36
  - JMdict, KANJIDIC, Tanaka Corpus, RADK and KRAD conversion
37
37
  - User-friendly schemas for dictionary entries
38
38
  - Anki note generation
39
- - Other useful tools (AWS Polly audio generation, Japanese RegExps, array checking etc.)
39
+ - Other useful tools (TTSFree.com audio generation, Japanese RegExps, array checking etc.)
40
40
 
41
41
  ---
42
42
 
@@ -55,12 +55,14 @@ const dictContent = fs.readFileSync(dictPath, 'utf-8');
55
55
 
56
56
  const dictWords = convertJMdict(dictContent);
57
57
 
58
+ const jmDict = undefined, id = undefined, kanjiDic = undefined, tanakaCorpus = undefined;
59
+
58
60
  const noteTypeName = 'Word';
59
61
  const deckName = 'Japanese::Vocabulary::No kanji form words';
60
62
 
61
63
  const noKanjiFormWords = dictWords
62
64
  .filter(word => word.kanjiForms === undefined)
63
- .map(word => getWord(undefined, undefined, undefined, undefined, word, noteTypeName, deckName));
65
+ .map(word => getWord(jmDict, id, kanjiDic, tanakaCorpus, word, noteTypeName, deckName));
64
66
 
65
67
  const ankiNotesFile = generateAnkiNotesFile(noKanjiFormWords);
66
68
 
package/dist/index.cjs.js CHANGED
@@ -49,14 +49,10 @@ __export(index_exports, {
49
49
  isValidArray: () => isValidArray,
50
50
  isValidArrayWithFirstElement: () => isValidArrayWithFirstElement,
51
51
  isWord: () => isWord,
52
- makeSSML: () => makeSSML,
53
52
  notSearchedForms: () => notSearchedForms,
54
53
  noteMap: () => noteMap,
55
- numberMap: () => numberMap,
56
54
  regexps: () => regexps,
57
- romajiMap: () => romajiMap,
58
55
  shuffleArray: () => shuffleArray,
59
- symbolMap: () => symbolMap,
60
56
  synthesizeSpeech: () => synthesizeSpeech
61
57
  });
62
58
  module.exports = __toCommonJS(index_exports);
@@ -66,60 +62,11 @@ var regexps = {
66
62
  hiragana: /[\u{3040}-\u{309F}]/u,
67
63
  katakana: /[\u{30A0}-\u{30FF}]/u,
68
64
  kanji: new RegExp("\\p{Script=Han}+", "u"),
69
- scriptSplit: /([\p{sc=Han}]+|[\p{sc=Hiragana}]+|[\p{sc=Katakana}]+|[^\p{sc=Han}\p{sc=Hiragana}\p{sc=Katakana}]+)/u,
70
65
  regExChars: /[-\/\\^$*+?.()|[\]{}]/,
71
66
  tanakaID: /#ID=(?<id>\d+_\d+)$/,
72
67
  tanakaPart: /(?<base>[^()\[\]\{\}\s]+)(?:\((?<reading>[\S]+)\))?(?:\[(?<glossnum>[\S]+)\])?(?:\{(?<inflection>[\S]+)\})?/,
73
68
  tanakaReferenceID: /#(?<entryid>[\d]+)/
74
69
  };
75
- var romajiMap = {
76
- A: "\u30A8\u30FC",
77
- B: "\u30D3\u30FC",
78
- C: "\u30B7\u30FC",
79
- D: "\u30C7\u30A3\u30FC",
80
- E: "\u30A4\u30FC",
81
- F: "\u30A8\u30D5",
82
- G: "\u30B8\u30FC",
83
- H: "\u30A8\u30A4\u30C1",
84
- I: "\u30A2\u30A4",
85
- J: "\u30B8\u30A7\u30FC",
86
- K: "\u30B1\u30FC",
87
- L: "\u30A8\u30EB",
88
- M: "\u30A8\u30E0",
89
- N: "\u30A8\u30CC",
90
- O: "\u30AA\u30FC",
91
- P: "\u30D4\u30FC",
92
- Q: "\u30AD\u30E5\u30FC",
93
- R: "\u30A2\u30FC\u30EB",
94
- S: "\u30A8\u30B9",
95
- T: "\u30C6\u30A3\u30FC",
96
- U: "\u30E6\u30FC",
97
- V: "\u30D6\u30A4",
98
- W: "\u30C0\u30D6\u30EA\u30E5\u30FC",
99
- X: "\u30A8\u30C3\u30AF\u30B9",
100
- Y: "\u30EF\u30A4",
101
- Z: "\u30BC\u30C3\u30C8"
102
- };
103
- var numberMap = {
104
- "0": "\u30BC\u30ED",
105
- "1": "\u30A4\u30C1",
106
- "2": "\u30CB",
107
- "3": "\u30B5\u30F3",
108
- "4": "\u30E8\u30F3",
109
- "5": "\u30B4",
110
- "6": "\u30ED\u30AF",
111
- "7": "\u30CA\u30CA",
112
- "8": "\u30CF\u30C1",
113
- "9": "\u30AD\u30E5\u30A6"
114
- };
115
- var symbolMap = {
116
- "\uFF04": "\u30C9\u30EB",
117
- "%": "\u30D1\u30FC\u30BB\u30F3\u30C8",
118
- "\xA5": "\u30A8\u30F3",
119
- "#": "\u30B7\u30E3\u30FC\u30D7",
120
- "@": "\u30A2\u30C3\u30C8",
121
- "&": "\u30A2\u30F3\u30C9"
122
- };
123
70
  var notSearchedForms = /* @__PURE__ */ new Set([
124
71
  "search-only kana form",
125
72
  "Search-only kana form",
@@ -1187,7 +1134,7 @@ var noteMap = /* @__PURE__ */ new Map([
1187
1134
  var import_libxmljs2 = __toESM(require("libxmljs2"));
1188
1135
  var import_xml2js = __toESM(require("xml2js"));
1189
1136
  var import_iconv_lite = __toESM(require("iconv-lite"));
1190
- var import_client_polly = require("@aws-sdk/client-polly");
1137
+ var import_node_fetch = __toESM(require("node-fetch"));
1191
1138
  var Kuroshiro = require("kuroshiro");
1192
1139
  var KuromojiAnalyzer = require("kuroshiro-analyzer-kuromoji");
1193
1140
  function capitalizeString(value) {
@@ -1333,11 +1280,9 @@ function convertJMdict(xmlString, examples) {
1333
1280
  ).map((reading) => reading.reading)
1334
1281
  );
1335
1282
  const kanjiForms2 = entryObj.kanjiForms ? new Set(
1336
- entryObj.kanjiForms.filter(
1337
- (kanjiForm) => (!kanjiForm.notes || !kanjiForm.notes.some(
1338
- (note) => notSearchedForms.has(note)
1339
- )) && (entryObj.isCommon === void 0 || kanjiForm.commonness && kanjiForm.commonness.length > 0)
1340
- ).map((kanjiForm) => kanjiForm.form)
1283
+ entryObj.kanjiForms.map(
1284
+ (kanjiForm) => kanjiForm.form
1285
+ )
1341
1286
  ) : void 0;
1342
1287
  let existsExample = false;
1343
1288
  if (kanjiForms2 && kanjiForms2.size > 0 && tanakaParts) {
@@ -1519,9 +1464,9 @@ function convertRadkFile(radkBuffer, kanjiDic) {
1519
1464
  try {
1520
1465
  const fileParsed = import_iconv_lite.default.decode(radkBuffer, "euc-jp").split("\n").filter((line) => !line.startsWith("#"));
1521
1466
  const radicals = [];
1522
- for (let i = 0; i <= fileParsed.length; i++) {
1467
+ for (let i = 0; i < fileParsed.length; i++) {
1523
1468
  const line = fileParsed[i];
1524
- if (!line) throw new Error("Invalid radkfile2 buffer");
1469
+ if (!line) continue;
1525
1470
  if (line.startsWith("$ ")) {
1526
1471
  const radical = {
1527
1472
  radical: line.charAt(2).trim(),
@@ -1529,7 +1474,7 @@ function convertRadkFile(radkBuffer, kanjiDic) {
1529
1474
  };
1530
1475
  let j = i + 1;
1531
1476
  let kanjiLine = fileParsed[j];
1532
- if (!kanjiLine) throw new Error("Invalid radkfile2 buffer");
1477
+ if (!kanjiLine) continue;
1533
1478
  const kanjiList = [];
1534
1479
  while (kanjiLine && !kanjiLine.startsWith("$ ")) {
1535
1480
  const kanjis = kanjiLine.split("");
@@ -1565,8 +1510,7 @@ function convertKradFile(kradBuffer, kanjiDic, katakanaList) {
1565
1510
  const split = line.split(" : ");
1566
1511
  const kanjiChar = split[0];
1567
1512
  const radicalsRow = split[1];
1568
- if (!kanjiChar || !radicalsRow)
1569
- throw new Error("Invalid kradfile2 buffer");
1513
+ if (!kanjiChar || !radicalsRow) continue;
1570
1514
  const kanji = {
1571
1515
  ...kanjiChar && radicalsRow && kanjiChar.length === 1 && radicalsRow.length > 0 ? { kanji: kanjiChar } : { kanji: "" },
1572
1516
  radicals: []
@@ -1779,11 +1723,9 @@ function getWord(dict, id, kanjiDic, examples, dictWord, noteTypeName, deckPath)
1779
1723
  ).map((reading) => reading.reading)
1780
1724
  );
1781
1725
  const kanjiForms = word.kanjiForms ? new Set(
1782
- word.kanjiForms.filter(
1783
- (kanjiForm) => (!kanjiForm.notes || !kanjiForm.notes.some(
1784
- (note) => notSearchedForms.has(note)
1785
- )) && (word.common === void 0 || kanjiForm.common === true)
1786
- ).map((kanjiForm) => kanjiForm.kanjiForm)
1726
+ word.kanjiForms.map(
1727
+ (kanjiForm) => kanjiForm.kanjiForm
1728
+ )
1787
1729
  ) : void 0;
1788
1730
  const kanjiFormExamples = [];
1789
1731
  const readingMatchingKanjiFormExamples = [];
@@ -1791,7 +1733,7 @@ function getWord(dict, id, kanjiDic, examples, dictWord, noteTypeName, deckPath)
1791
1733
  const partParts = /* @__PURE__ */ new Set();
1792
1734
  for (const example of examples)
1793
1735
  for (const part of example.parts) {
1794
- const readingAsReadingMatch = part.reading !== void 0 && readings.has(part.reading);
1736
+ const readingAsReadingMatch = part.reading !== void 0 && readings.has(part.reading) || part.inflectedForm !== void 0 && readings.has(part.inflectedForm);
1795
1737
  if (kanjiForms && kanjiForms.size > 0 && kanjiForms.has(part.baseForm)) {
1796
1738
  if (readingAsReadingMatch) {
1797
1739
  readingMatchingKanjiFormExamples.push(example);
@@ -1804,17 +1746,20 @@ function getWord(dict, id, kanjiDic, examples, dictWord, noteTypeName, deckPath)
1804
1746
  }
1805
1747
  const readingAsBaseFormMatch = readings.has(part.baseForm);
1806
1748
  const referenceIDMatch = part.referenceID !== void 0 && word.id !== void 0 && part.referenceID === word.id;
1807
- if (readingAsReadingMatch || readingAsBaseFormMatch || referenceIDMatch) {
1749
+ if (readingAsBaseFormMatch || referenceIDMatch) {
1808
1750
  readingExamples.push(example);
1809
- if (readingAsReadingMatch) partParts.add(part.reading);
1810
1751
  if (readingAsBaseFormMatch) partParts.add(part.baseForm);
1811
1752
  if (referenceIDMatch) partParts.add(part.referenceID);
1812
1753
  break;
1813
1754
  }
1814
1755
  }
1815
1756
  const exampleSize = readingMatchingKanjiFormExamples.length + kanjiFormExamples.length + readingExamples.length;
1816
- const includeKanjiFormExamples = readingMatchingKanjiFormExamples.length < Math.max(2, Math.round(exampleSize * 0.05));
1817
- const includeReadingExamples = word.usuallyInKana === void 0 && includeKanjiFormExamples && readingExamples.length >= Math.max(10, Math.round(exampleSize * 0.15)) || word.usuallyInKana === true && readingExamples.length >= Math.max(2, Math.round(exampleSize * 0.5));
1757
+ const includeReadingThreshold = Math.max(
1758
+ 10,
1759
+ Math.round(exampleSize * 0.5)
1760
+ );
1761
+ const includeKanjiFormExamples = word.kanjiForms !== void 0;
1762
+ const includeReadingExamples = readingExamples.length >= includeReadingThreshold && readingExamples.length >= readingMatchingKanjiFormExamples.length && readingExamples.length >= kanjiFormExamples.length || readingExamples.length >= includeReadingThreshold && word.usuallyInKana === true || word.kanjiForms === void 0;
1818
1763
  let wordExamples = [
1819
1764
  ...readingMatchingKanjiFormExamples,
1820
1765
  ...includeKanjiFormExamples ? kanjiFormExamples : [],
@@ -1826,7 +1771,11 @@ function getWord(dict, id, kanjiDic, examples, dictWord, noteTypeName, deckPath)
1826
1771
  outer: for (const example of wordExamples) {
1827
1772
  if (seenPhrases.has(example.phrase)) continue;
1828
1773
  for (const part of example.parts)
1829
- if (part.glossNumber === i + 1 && (partParts.has(part.baseForm) || part.reading && partParts.has(part.reading) || part.referenceID && partParts.has(part.referenceID))) {
1774
+ if (part.glossNumber === i + 1 && (partParts.has(part.baseForm) || includeReadingExamples && (part.reading && partParts.has(part.reading) || part.inflectedForm && partParts.has(part.inflectedForm) || part.referenceID && partParts.has(part.referenceID)))) {
1775
+ example.glossNumber = {
1776
+ wordId: word.id,
1777
+ glossNumber: i + 1
1778
+ };
1830
1779
  glossSpecificExamples.push(example);
1831
1780
  seenPhrases.add(example.phrase);
1832
1781
  break outer;
@@ -1847,7 +1796,8 @@ function getWord(dict, id, kanjiDic, examples, dictWord, noteTypeName, deckPath)
1847
1796
  return {
1848
1797
  phrase: (_a = ex.furigana) != null ? _a : ex.phrase,
1849
1798
  translation: ex.translation,
1850
- originalPhrase: ex.phrase
1799
+ originalPhrase: ex.phrase,
1800
+ ...ex.glossNumber ? { glossNumber: ex.glossNumber } : {}
1851
1801
  };
1852
1802
  });
1853
1803
  }
@@ -2052,92 +2002,34 @@ function getKanjiExtended(kanjiChar, info, dict, useJpdbWords, jmDict, svgList,
2052
2002
  throw err;
2053
2003
  }
2054
2004
  }
2055
- var getCharType = (char) => {
2056
- if (regexps.kanji.test(char)) return "kanji";
2057
- if (regexps.hiragana.test(char)) return "hiragana";
2058
- if (regexps.katakana.test(char)) return "katakana";
2059
- return "other";
2060
- };
2061
- var splitByScript = (text) => text.match(regexps.scriptSplit) || [];
2062
- var convertToHiragana = (str) => str.replace(
2063
- regexps.katakana,
2064
- (c) => String.fromCharCode(c.charCodeAt(0) - 96)
2065
- );
2066
- var convertOtherToKatakana = (str) => str.split("").map((c) => {
2067
- if (romajiMap[c.toUpperCase()]) return romajiMap[c.toUpperCase()];
2068
- if (numberMap[c]) return numberMap[c];
2069
- if (symbolMap[c]) return symbolMap[c];
2070
- return c;
2071
- }).join("");
2072
- function makeSSML(formText, fullReading) {
2073
- let ssml = "";
2074
- const allTypes = Array.from(
2075
- formText
2076
- ).map((c) => getCharType(c));
2077
- const uniqueTypes = Array.from(new Set(allTypes));
2078
- if (uniqueTypes.length === 1)
2079
- switch (uniqueTypes[0]) {
2080
- case "kanji":
2081
- ssml = `<speak><phoneme alphabet="x-amazon-yomigana" ph="${fullReading}">${formText}</phoneme></speak>`;
2082
- break;
2083
- case "katakana":
2084
- ssml = `<speak><phoneme alphabet="x-amazon-pron-kana" ph="${formText}">${formText}</phoneme></speak>`;
2085
- break;
2086
- case "hiragana":
2087
- default:
2088
- ssml = `<speak>${formText}</speak>`;
2089
- }
2090
- else {
2091
- const segments = splitByScript(formText);
2092
- let pureKanjiReading = convertToHiragana(fullReading);
2093
- segments.forEach((seg) => {
2094
- const type = getCharType(
2095
- seg[0]
2096
- );
2097
- if (type !== "kanji") {
2098
- const converted = type === "other" ? convertToHiragana(convertOtherToKatakana(seg)) : convertToHiragana(seg);
2099
- pureKanjiReading = pureKanjiReading.replace(converted, "");
2100
- }
2101
- });
2102
- const kanjiSegments = segments.filter(
2103
- (seg) => getCharType(seg[0]) === "kanji"
2104
- );
2105
- let readingPointer = 0;
2106
- const ssmlSegments = segments.map((seg) => {
2107
- const type = getCharType(
2108
- seg[0]
2109
- );
2110
- if (type === "kanji") {
2111
- const expectedLength = pureKanjiReading.length / kanjiSegments.length;
2112
- const allocated = pureKanjiReading.slice(
2113
- readingPointer,
2114
- readingPointer + Math.ceil(expectedLength)
2115
- );
2116
- readingPointer += allocated.length;
2117
- return `<phoneme alphabet="x-amazon-yomigana" ph="${allocated}">${seg}</phoneme>`;
2118
- } else if (type === "katakana")
2119
- return `<phoneme alphabet="x-amazon-pron-kana" ph="${seg}">${seg}</phoneme>`;
2120
- else if (type === "other") {
2121
- const katakanaReading = convertOtherToKatakana(seg);
2122
- return `<phoneme alphabet="x-amazon-pron-kana" ph="${katakanaReading}">${seg}</phoneme>`;
2123
- } else return seg;
2124
- });
2125
- ssml = `<speak>${ssmlSegments.join("")}</speak>`;
2126
- }
2127
- return ssml;
2128
- }
2129
- async function synthesizeSpeech(client, ssmlText, options) {
2005
+ async function synthesizeSpeech(textOrSSML, apiKey, options) {
2130
2006
  return await new Promise(
2131
2007
  async (resolve, reject) => {
2132
2008
  try {
2133
- const command = new import_client_polly.SynthesizeSpeechCommand({
2134
- Text: ssmlText,
2135
- TextType: "ssml",
2136
- ...options
2009
+ const res = await (0, import_node_fetch.default)("https://ttsfree.com/api/v1/tts", {
2010
+ method: "POST",
2011
+ body: JSON.stringify({
2012
+ text: textOrSSML,
2013
+ ...options
2014
+ }),
2015
+ headers: {
2016
+ "Content-Type": "application/json",
2017
+ apikey: apiKey
2018
+ }
2137
2019
  });
2138
- const response = await client.send(command);
2139
- const stream = response.AudioStream ? Buffer.from(await response.AudioStream.transformToByteArray()) : null;
2140
- resolve(stream);
2020
+ if (!res.ok)
2021
+ throw new Error(
2022
+ `TTS request failed:
2023
+ ${res.status}: ${res.statusText}`
2024
+ );
2025
+ const data = await res.json();
2026
+ if (data.status !== "success" || data.mess !== "success" || data.audioData.length === 0)
2027
+ throw new Error("Invalid TTS response data");
2028
+ const mp3Buffer = Buffer.from(
2029
+ data.audioData,
2030
+ "base64"
2031
+ );
2032
+ resolve(mp3Buffer);
2141
2033
  } catch (err) {
2142
2034
  reject(err);
2143
2035
  }
@@ -2184,7 +2076,7 @@ function generateAnkiNote(entry) {
2184
2076
  ).join("") : noKanjiForms
2185
2077
  ],
2186
2078
  entry.translations.map(
2187
- (translationEntry, index) => `${index > 2 ? "<details><summary>Show translation</summary>" : ""}${createEntry(`<span class="word word-translation">${translationEntry.translation}</span>`, translationEntry.notes)}${index > 2 ? "</details>" : ""}`
2079
+ (translationEntry, index) => `<span class="word word-index${entry.phrases && entry.phrases.some((phrase, index2) => index === index2 && phrase.glossNumber && phrase.glossNumber.wordId === entry.id && phrase.glossNumber.glossNumber === index + 1) ? " gloss-specific" : ""}">${index + 1}</span>${index > 2 ? "<details><summary>Show translation</summary>" : ""}${createEntry(`<span class="word word-translation">${translationEntry.translation}</span>`, translationEntry.notes)}${index > 2 ? "</details>" : ""}`
2188
2080
  ).join(""),
2189
2081
  entry.kanji ? entry.kanji.map(
2190
2082
  (kanjiEntry) => createEntry(
@@ -2193,11 +2085,11 @@ function generateAnkiNote(entry) {
2193
2085
  )
2194
2086
  ).join("") : '<span class="word word-kanji">(no kanji)</span>',
2195
2087
  entry.phrases ? entry.phrases.map(
2196
- (phraseEntry) => createEntry(
2088
+ (phraseEntry, index) => `<span class="word word-index${entry.translations.some((_translation, index2) => index === index2 && phraseEntry.glossNumber && phraseEntry.glossNumber.wordId === entry.id && phraseEntry.glossNumber.glossNumber === index2 + 1) ? " gloss-specific" : ""}">${index + 1}</span>${createEntry(
2197
2089
  `<span class="word word-phrase"><span class="word word-phrase-original">${phraseEntry.originalPhrase}</span><span class="word word-phrase-furigana">${phraseEntry.phrase}</span></span>`,
2198
2090
  [phraseEntry.translation],
2199
2091
  true
2200
- )
2092
+ )}`
2201
2093
  ).join("") : '<span class="word word-phrase">(no phrases) (Search on dictionaries!)</span>',
2202
2094
  ...entry.tags && entry.tags.length > 0 ? [
2203
2095
  entry.tags.map(
@@ -2379,14 +2271,10 @@ ${ankiNotes}`;
2379
2271
  isValidArray,
2380
2272
  isValidArrayWithFirstElement,
2381
2273
  isWord,
2382
- makeSSML,
2383
2274
  notSearchedForms,
2384
2275
  noteMap,
2385
- numberMap,
2386
2276
  regexps,
2387
- romajiMap,
2388
2277
  shuffleArray,
2389
- symbolMap,
2390
2278
  synthesizeSpeech
2391
2279
  });
2392
2280
  //# sourceMappingURL=index.cjs.js.map