新增记忆字母表功能

This commit is contained in:
2025-10-09 11:23:56 +08:00
parent 5b7cac029b
commit 4829ab9531
16 changed files with 1135 additions and 9 deletions

View File

@@ -0,0 +1,132 @@
[
{
"letter": "a",
"letter_name_ipa": "[eɪ]",
"letter_sound_ipa": "[æ], [eɪ], [ɑː], [ə]"
},
{
"letter": "b",
"letter_name_ipa": "[biː]",
"letter_sound_ipa": "[b]"
},
{
"letter": "c",
"letter_name_ipa": "[siː]",
"letter_sound_ipa": "[k], [s]"
},
{
"letter": "d",
"letter_name_ipa": "[diː]",
"letter_sound_ipa": "[d]"
},
{
"letter": "e",
"letter_name_ipa": "[iː]",
"letter_sound_ipa": "[ɛ], [iː], [ə]"
},
{
"letter": "f",
"letter_name_ipa": "[ɛf]",
"letter_sound_ipa": "[f]"
},
{
"letter": "g",
"letter_name_ipa": "[dʒiː]",
"letter_sound_ipa": "[ɡ], [dʒ]"
},
{
"letter": "h",
"letter_name_ipa": "[eɪtʃ]",
"letter_sound_ipa": "[h]"
},
{
"letter": "i",
"letter_name_ipa": "[aɪ]",
"letter_sound_ipa": "[ɪ], [aɪ]"
},
{
"letter": "j",
"letter_name_ipa": "[dʒeɪ]",
"letter_sound_ipa": "[dʒ]"
},
{
"letter": "k",
"letter_name_ipa": "[keɪ]",
"letter_sound_ipa": "[k]"
},
{
"letter": "l",
"letter_name_ipa": "[ɛl]",
"letter_sound_ipa": "[l]"
},
{
"letter": "m",
"letter_name_ipa": "[ɛm]",
"letter_sound_ipa": "[m]"
},
{
"letter": "n",
"letter_name_ipa": "[ɛn]",
"letter_sound_ipa": "[n]"
},
{
"letter": "o",
"letter_name_ipa": "[oʊ]",
"letter_sound_ipa": "[ɒ], [oʊ], [ʌ]"
},
{
"letter": "p",
"letter_name_ipa": "[piː]",
"letter_sound_ipa": "[p]"
},
{
"letter": "q",
"letter_name_ipa": "[kjuː]",
"letter_sound_ipa": "[k]"
},
{
"letter": "r",
"letter_name_ipa": "[ɑːr]",
"letter_sound_ipa": "[r]"
},
{
"letter": "s",
"letter_name_ipa": "[ɛs]",
"letter_sound_ipa": "[s], [z]"
},
{
"letter": "t",
"letter_name_ipa": "[tiː]",
"letter_sound_ipa": "[t]"
},
{
"letter": "u",
"letter_name_ipa": "[juː]",
"letter_sound_ipa": "[ʌ], [juː], [ʊ]"
},
{
"letter": "v",
"letter_name_ipa": "[viː]",
"letter_sound_ipa": "[v]"
},
{
"letter": "w",
"letter_name_ipa": "[ˈdʌbəl.juː]",
"letter_sound_ipa": "[w]"
},
{
"letter": "x",
"letter_name_ipa": "[ɛks]",
"letter_sound_ipa": "[ks], [ɡz]"
},
{
"letter": "y",
"letter_name_ipa": "[waɪ]",
"letter_sound_ipa": "[j], [aɪ], [ɪ]"
},
{
"letter": "z",
"letter_name_ipa": "[zɛd] or [ziː]",
"letter_sound_ipa": "[z]"
}
]

View File

@@ -0,0 +1,142 @@
[
{
"letter": "a",
"letter_name_ipa": "[a]",
"letter_sound_ipa": "[a]"
},
{
"letter": "b",
"letter_name_ipa": "[bo]",
"letter_sound_ipa": "[b]"
},
{
"letter": "c",
"letter_name_ipa": "[t͡so]",
"letter_sound_ipa": "[t͡s]"
},
{
"letter": "ĉ",
"letter_name_ipa": "[t͡ʃo]",
"letter_sound_ipa": "[t͡ʃ]"
},
{
"letter": "d",
"letter_name_ipa": "[do]",
"letter_sound_ipa": "[d]"
},
{
"letter": "e",
"letter_name_ipa": "[e]",
"letter_sound_ipa": "[e]"
},
{
"letter": "f",
"letter_name_ipa": "[fo]",
"letter_sound_ipa": "[f]"
},
{
"letter": "g",
"letter_name_ipa": "[ɡo]",
"letter_sound_ipa": "[ɡ]"
},
{
"letter": "ĝ",
"letter_name_ipa": "[d͡ʒo]",
"letter_sound_ipa": "[d͡ʒ]"
},
{
"letter": "h",
"letter_name_ipa": "[ho]",
"letter_sound_ipa": "[h]"
},
{
"letter": "ĥ",
"letter_name_ipa": "[xo]",
"letter_sound_ipa": "[x]"
},
{
"letter": "i",
"letter_name_ipa": "[i]",
"letter_sound_ipa": "[i]"
},
{
"letter": "j",
"letter_name_ipa": "[jo]",
"letter_sound_ipa": "[j]"
},
{
"letter": "ĵ",
"letter_name_ipa": "[ʒo]",
"letter_sound_ipa": "[ʒ]"
},
{
"letter": "k",
"letter_name_ipa": "[ko]",
"letter_sound_ipa": "[k]"
},
{
"letter": "l",
"letter_name_ipa": "[lo]",
"letter_sound_ipa": "[l]"
},
{
"letter": "m",
"letter_name_ipa": "[mo]",
"letter_sound_ipa": "[m]"
},
{
"letter": "n",
"letter_name_ipa": "[no]",
"letter_sound_ipa": "[n]"
},
{
"letter": "o",
"letter_name_ipa": "[o]",
"letter_sound_ipa": "[o]"
},
{
"letter": "p",
"letter_name_ipa": "[po]",
"letter_sound_ipa": "[p]"
},
{
"letter": "r",
"letter_name_ipa": "[ro]",
"letter_sound_ipa": "[r]"
},
{
"letter": "s",
"letter_name_ipa": "[so]",
"letter_sound_ipa": "[s]"
},
{
"letter": "ŝ",
"letter_name_ipa": "[ʃo]",
"letter_sound_ipa": "[ʃ]"
},
{
"letter": "t",
"letter_name_ipa": "[to]",
"letter_sound_ipa": "[t]"
},
{
"letter": "u",
"letter_name_ipa": "[u]",
"letter_sound_ipa": "[u]"
},
{
"letter": "ŭ",
"letter_name_ipa": "[u̯o]",
"letter_sound_ipa": "[u̯]"
},
{
"letter": "v",
"letter_name_ipa": "[vo]",
"letter_sound_ipa": "[v]"
},
{
"letter": "z",
"letter_name_ipa": "[zo]",
"letter_sound_ipa": "[z]"
}
]

View File

@@ -0,0 +1,554 @@
[
{
"letter": "あ",
"letter_name_ipa": "[a]",
"letter_sound_ipa": "[a]",
"roman_letter": "a"
},
{
"letter": "ア",
"letter_name_ipa": "[a]",
"letter_sound_ipa": "[a]",
"roman_letter": "a"
},
{
"letter": "い",
"letter_name_ipa": "[i]",
"letter_sound_ipa": "[i]",
"roman_letter": "i"
},
{
"letter": "イ",
"letter_name_ipa": "[i]",
"letter_sound_ipa": "[i]",
"roman_letter": "i"
},
{
"letter": "う",
"letter_name_ipa": "[ɯ]",
"letter_sound_ipa": "[ɯ]",
"roman_letter": "u"
},
{
"letter": "ウ",
"letter_name_ipa": "[ɯ]",
"letter_sound_ipa": "[ɯ]",
"roman_letter": "u"
},
{
"letter": "え",
"letter_name_ipa": "[e]",
"letter_sound_ipa": "[e]",
"roman_letter": "e"
},
{
"letter": "エ",
"letter_name_ipa": "[e]",
"letter_sound_ipa": "[e]",
"roman_letter": "e"
},
{
"letter": "お",
"letter_name_ipa": "[o]",
"letter_sound_ipa": "[o]",
"roman_letter": "o"
},
{
"letter": "オ",
"letter_name_ipa": "[o]",
"letter_sound_ipa": "[o]",
"roman_letter": "o"
},
{
"letter": "か",
"letter_name_ipa": "[ka]",
"letter_sound_ipa": "[ka]",
"roman_letter": "ka"
},
{
"letter": "カ",
"letter_name_ipa": "[ka]",
"letter_sound_ipa": "[ka]",
"roman_letter": "ka"
},
{
"letter": "き",
"letter_name_ipa": "[ki]",
"letter_sound_ipa": "[ki]",
"roman_letter": "ki"
},
{
"letter": "キ",
"letter_name_ipa": "[ki]",
"letter_sound_ipa": "[ki]",
"roman_letter": "ki"
},
{
"letter": "く",
"letter_name_ipa": "[kɯ]",
"letter_sound_ipa": "[kɯ]",
"roman_letter": "ku"
},
{
"letter": "ク",
"letter_name_ipa": "[kɯ]",
"letter_sound_ipa": "[kɯ]",
"roman_letter": "ku"
},
{
"letter": "け",
"letter_name_ipa": "[ke]",
"letter_sound_ipa": "[ke]",
"roman_letter": "ke"
},
{
"letter": "ケ",
"letter_name_ipa": "[ke]",
"letter_sound_ipa": "[ke]",
"roman_letter": "ke"
},
{
"letter": "こ",
"letter_name_ipa": "[ko]",
"letter_sound_ipa": "[ko]",
"roman_letter": "ko"
},
{
"letter": "コ",
"letter_name_ipa": "[ko]",
"letter_sound_ipa": "[ko]",
"roman_letter": "ko"
},
{
"letter": "さ",
"letter_name_ipa": "[sa]",
"letter_sound_ipa": "[sa]",
"roman_letter": "sa"
},
{
"letter": "サ",
"letter_name_ipa": "[sa]",
"letter_sound_ipa": "[sa]",
"roman_letter": "sa"
},
{
"letter": "し",
"letter_name_ipa": "[ɕi]",
"letter_sound_ipa": "[ɕi]",
"roman_letter": "shi"
},
{
"letter": "シ",
"letter_name_ipa": "[ɕi]",
"letter_sound_ipa": "[ɕi]",
"roman_letter": "shi"
},
{
"letter": "す",
"letter_name_ipa": "[sɯ]",
"letter_sound_ipa": "[sɯ]",
"roman_letter": "su"
},
{
"letter": "ス",
"letter_name_ipa": "[sɯ]",
"letter_sound_ipa": "[sɯ]",
"roman_letter": "su"
},
{
"letter": "せ",
"letter_name_ipa": "[se]",
"letter_sound_ipa": "[se]",
"roman_letter": "se"
},
{
"letter": "セ",
"letter_name_ipa": "[se]",
"letter_sound_ipa": "[se]",
"roman_letter": "se"
},
{
"letter": "そ",
"letter_name_ipa": "[so]",
"letter_sound_ipa": "[so]",
"roman_letter": "so"
},
{
"letter": "ソ",
"letter_name_ipa": "[so]",
"letter_sound_ipa": "[so]",
"roman_letter": "so"
},
{
"letter": "た",
"letter_name_ipa": "[ta]",
"letter_sound_ipa": "[ta]",
"roman_letter": "ta"
},
{
"letter": "タ",
"letter_name_ipa": "[ta]",
"letter_sound_ipa": "[ta]",
"roman_letter": "ta"
},
{
"letter": "ち",
"letter_name_ipa": "[tɕi]",
"letter_sound_ipa": "[tɕi]",
"roman_letter": "chi"
},
{
"letter": "チ",
"letter_name_ipa": "[tɕi]",
"letter_sound_ipa": "[tɕi]",
"roman_letter": "chi"
},
{
"letter": "つ",
"letter_name_ipa": "[t͡sɯ]",
"letter_sound_ipa": "[t͡sɯ]",
"roman_letter": "tsu"
},
{
"letter": "ツ",
"letter_name_ipa": "[t͡sɯ]",
"letter_sound_ipa": "[t͡sɯ]",
"roman_letter": "tsu"
},
{
"letter": "て",
"letter_name_ipa": "[te]",
"letter_sound_ipa": "[te]",
"roman_letter": "te"
},
{
"letter": "テ",
"letter_name_ipa": "[te]",
"letter_sound_ipa": "[te]",
"roman_letter": "te"
},
{
"letter": "と",
"letter_name_ipa": "[to]",
"letter_sound_ipa": "[to]",
"roman_letter": "to"
},
{
"letter": "ト",
"letter_name_ipa": "[to]",
"letter_sound_ipa": "[to]",
"roman_letter": "to"
},
{
"letter": "な",
"letter_name_ipa": "[na]",
"letter_sound_ipa": "[na]",
"roman_letter": "na"
},
{
"letter": "ナ",
"letter_name_ipa": "[na]",
"letter_sound_ipa": "[na]",
"roman_letter": "na"
},
{
"letter": "に",
"letter_name_ipa": "[ni]",
"letter_sound_ipa": "[ni]",
"roman_letter": "ni"
},
{
"letter": "ニ",
"letter_name_ipa": "[ni]",
"letter_sound_ipa": "[ni]",
"roman_letter": "ni"
},
{
"letter": "ぬ",
"letter_name_ipa": "[nɯ]",
"letter_sound_ipa": "[nɯ]",
"roman_letter": "nu"
},
{
"letter": "ヌ",
"letter_name_ipa": "[nɯ]",
"letter_sound_ipa": "[nɯ]",
"roman_letter": "nu"
},
{
"letter": "ね",
"letter_name_ipa": "[ne]",
"letter_sound_ipa": "[ne]",
"roman_letter": "ne"
},
{
"letter": "ネ",
"letter_name_ipa": "[ne]",
"letter_sound_ipa": "[ne]",
"roman_letter": "ne"
},
{
"letter": "の",
"letter_name_ipa": "[no]",
"letter_sound_ipa": "[no]",
"roman_letter": "no"
},
{
"letter": "",
"letter_name_ipa": "[no]",
"letter_sound_ipa": "[no]",
"roman_letter": "no"
},
{
"letter": "は",
"letter_name_ipa": "[ha]",
"letter_sound_ipa": "[ha]",
"roman_letter": "ha"
},
{
"letter": "ハ",
"letter_name_ipa": "[ha]",
"letter_sound_ipa": "[ha]",
"roman_letter": "ha"
},
{
"letter": "ひ",
"letter_name_ipa": "[çi]",
"letter_sound_ipa": "[çi]",
"roman_letter": "hi"
},
{
"letter": "ヒ",
"letter_name_ipa": "[çi]",
"letter_sound_ipa": "[çi]",
"roman_letter": "hi"
},
{
"letter": "ふ",
"letter_name_ipa": "[ɸɯ]",
"letter_sound_ipa": "[ɸɯ]",
"roman_letter": "fu"
},
{
"letter": "フ",
"letter_name_ipa": "[ɸɯ]",
"letter_sound_ipa": "[ɸɯ]",
"roman_letter": "fu"
},
{
"letter": "へ",
"letter_name_ipa": "[he]",
"letter_sound_ipa": "[he]",
"roman_letter": "he"
},
{
"letter": "ヘ",
"letter_name_ipa": "[he]",
"letter_sound_ipa": "[he]",
"roman_letter": "he"
},
{
"letter": "ほ",
"letter_name_ipa": "[ho]",
"letter_sound_ipa": "[ho]",
"roman_letter": "ho"
},
{
"letter": "ホ",
"letter_name_ipa": "[ho]",
"letter_sound_ipa": "[ho]",
"roman_letter": "ho"
},
{
"letter": "ま",
"letter_name_ipa": "[ma]",
"letter_sound_ipa": "[ma]",
"roman_letter": "ma"
},
{
"letter": "マ",
"letter_name_ipa": "[ma]",
"letter_sound_ipa": "[ma]",
"roman_letter": "ma"
},
{
"letter": "み",
"letter_name_ipa": "[mi]",
"letter_sound_ipa": "[mi]",
"roman_letter": "mi"
},
{
"letter": "ミ",
"letter_name_ipa": "[mi]",
"letter_sound_ipa": "[mi]",
"roman_letter": "mi"
},
{
"letter": "む",
"letter_name_ipa": "[mɯ]",
"letter_sound_ipa": "[mɯ]",
"roman_letter": "mu"
},
{
"letter": "ム",
"letter_name_ipa": "[mɯ]",
"letter_sound_ipa": "[mɯ]",
"roman_letter": "mu"
},
{
"letter": "め",
"letter_name_ipa": "[me]",
"letter_sound_ipa": "[me]",
"roman_letter": "me"
},
{
"letter": "メ",
"letter_name_ipa": "[me]",
"letter_sound_ipa": "[me]",
"roman_letter": "me"
},
{
"letter": "も",
"letter_name_ipa": "[mo]",
"letter_sound_ipa": "[mo]",
"roman_letter": "mo"
},
{
"letter": "モ",
"letter_name_ipa": "[mo]",
"letter_sound_ipa": "[mo]",
"roman_letter": "mo"
},
{
"letter": "や",
"letter_name_ipa": "[ja]",
"letter_sound_ipa": "[ja]",
"roman_letter": "ya"
},
{
"letter": "ヤ",
"letter_name_ipa": "[ja]",
"letter_sound_ipa": "[ja]",
"roman_letter": "ya"
},
{
"letter": "ゆ",
"letter_name_ipa": "[jɯ]",
"letter_sound_ipa": "[jɯ]",
"roman_letter": "yu"
},
{
"letter": "ユ",
"letter_name_ipa": "[jɯ]",
"letter_sound_ipa": "[jɯ]",
"roman_letter": "yu"
},
{
"letter": "よ",
"letter_name_ipa": "[jo]",
"letter_sound_ipa": "[jo]",
"roman_letter": "yo"
},
{
"letter": "ヨ",
"letter_name_ipa": "[jo]",
"letter_sound_ipa": "[jo]",
"roman_letter": "yo"
},
{
"letter": "ら",
"letter_name_ipa": "[ɾa]",
"letter_sound_ipa": "[ɾa]",
"roman_letter": "ra"
},
{
"letter": "ラ",
"letter_name_ipa": "[ɾa]",
"letter_sound_ipa": "[ɾa]",
"roman_letter": "ra"
},
{
"letter": "り",
"letter_name_ipa": "[ɾi]",
"letter_sound_ipa": "[ɾi]",
"roman_letter": "ri"
},
{
"letter": "リ",
"letter_name_ipa": "[ɾi]",
"letter_sound_ipa": "[ɾi]",
"roman_letter": "ri"
},
{
"letter": "る",
"letter_name_ipa": "[ɾɯ]",
"letter_sound_ipa": "[ɾɯ]",
"roman_letter": "ru"
},
{
"letter": "ル",
"letter_name_ipa": "[ɾɯ]",
"letter_sound_ipa": "[ɾɯ]",
"roman_letter": "ru"
},
{
"letter": "れ",
"letter_name_ipa": "[ɾe]",
"letter_sound_ipa": "[ɾe]",
"roman_letter": "re"
},
{
"letter": "レ",
"letter_name_ipa": "[ɾe]",
"letter_sound_ipa": "[ɾe]",
"roman_letter": "re"
},
{
"letter": "ろ",
"letter_name_ipa": "[ɾo]",
"letter_sound_ipa": "[ɾo]",
"roman_letter": "ro"
},
{
"letter": "ロ",
"letter_name_ipa": "[ɾo]",
"letter_sound_ipa": "[ɾo]",
"roman_letter": "ro"
},
{
"letter": "わ",
"letter_name_ipa": "[wa]",
"letter_sound_ipa": "[wa]",
"roman_letter": "wa"
},
{
"letter": "ワ",
"letter_name_ipa": "[wa]",
"letter_sound_ipa": "[wa]",
"roman_letter": "wa"
},
{
"letter": "を",
"letter_name_ipa": "[o]",
"letter_sound_ipa": "[o]",
"roman_letter": "wo"
},
{
"letter": "ヲ",
"letter_name_ipa": "[o]",
"letter_sound_ipa": "[o]",
"roman_letter": "wo"
},
{
"letter": "ん",
"letter_name_ipa": "[n]",
"letter_sound_ipa": "[n], [m], [ŋ]",
"roman_letter": "n"
},
{
"letter": "ン",
"letter_name_ipa": "[n]",
"letter_sound_ipa": "[n], [m], [ŋ]",
"roman_letter": "n"
}
]

View File

@@ -0,0 +1,162 @@
[
{
"letter": "ئا",
"letter_name_ipa": "[ʔɑ]",
"letter_sound_ipa": "[ɑ]"
},
{
"letter": "ئە",
"letter_name_ipa": "[ʔæ]",
"letter_sound_ipa": "[æ]"
},
{
"letter": "ب",
"letter_name_ipa": "[bɛ]",
"letter_sound_ipa": "[b]"
},
{
"letter": "پ",
"letter_name_ipa": "[pɛ]",
"letter_sound_ipa": "[p]"
},
{
"letter": "ت",
"letter_name_ipa": "[tɛ]",
"letter_sound_ipa": "[t]"
},
{
"letter": "ج",
"letter_name_ipa": "[dʒɛ]",
"letter_sound_ipa": "[dʒ]"
},
{
"letter": "چ",
"letter_name_ipa": "[tʃɛ]",
"letter_sound_ipa": "[tʃ]"
},
{
"letter": "خ",
"letter_name_ipa": "[xɛ]",
"letter_sound_ipa": "[x]"
},
{
"letter": "د",
"letter_name_ipa": "[dɛ]",
"letter_sound_ipa": "[d]"
},
{
"letter": "ر",
"letter_name_ipa": "[rɛ]",
"letter_sound_ipa": "[r]"
},
{
"letter": "ز",
"letter_name_ipa": "[zɛ]",
"letter_sound_ipa": "[z]"
},
{
"letter": "ژ",
"letter_name_ipa": "[ʒɛ]",
"letter_sound_ipa": "[ʒ]"
},
{
"letter": "س",
"letter_name_ipa": "[sɛ]",
"letter_sound_ipa": "[s]"
},
{
"letter": "ش",
"letter_name_ipa": "[ʃɛ]",
"letter_sound_ipa": "[ʃ]"
},
{
"letter": "غ",
"letter_name_ipa": "[ʁɛ]",
"letter_sound_ipa": "[ʁ]"
},
{
"letter": "ف",
"letter_name_ipa": "[fɛ]",
"letter_sound_ipa": "[f]"
},
{
"letter": "ق",
"letter_name_ipa": "[qɛ]",
"letter_sound_ipa": "[q]"
},
{
"letter": "ك",
"letter_name_ipa": "[kɛ]",
"letter_sound_ipa": "[k]"
},
{
"letter": "گ",
"letter_name_ipa": "[gɛ]",
"letter_sound_ipa": "[g]"
},
{
"letter": "ڭ",
"letter_name_ipa": "[ŋɛ]",
"letter_sound_ipa": "[ŋ]"
},
{
"letter": "ل",
"letter_name_ipa": "[lɛ]",
"letter_sound_ipa": "[l]"
},
{
"letter": "م",
"letter_name_ipa": "[mɛ]",
"letter_sound_ipa": "[m]"
},
{
"letter": "ن",
"letter_name_ipa": "[nɛ]",
"letter_sound_ipa": "[n]"
},
{
"letter": "ھ",
"letter_name_ipa": "[hɛ]",
"letter_sound_ipa": "[h]"
},
{
"letter": "ئو",
"letter_name_ipa": "[ʔo]",
"letter_sound_ipa": "[o]"
},
{
"letter": "ئۇ",
"letter_name_ipa": "[ʔu]",
"letter_sound_ipa": "[u]"
},
{
"letter": "ئۆ",
"letter_name_ipa": "[ʔø]",
"letter_sound_ipa": "[ø]"
},
{
"letter": "ئۈ",
"letter_name_ipa": "[ʔy]",
"letter_sound_ipa": "[y]"
},
{
"letter": "ۋ",
"letter_name_ipa": "[wɛ]",
"letter_sound_ipa": "[w], [v]"
},
{
"letter": "ئې",
"letter_name_ipa": "[ʔe]",
"letter_sound_ipa": "[e]"
},
{
"letter": "ئى",
"letter_name_ipa": "[ʔi]",
"letter_sound_ipa": "[i]"
},
{
"letter": "ي",
"letter_name_ipa": "[jɛ]",
"letter_sound_ipa": "[j]"
}
]

View File

@@ -1,4 +1,5 @@
2025.10.08 加快了TTS的速度将IPA生成设置为可选项
2025.09.25 新增记忆字母表功能
2025.10.08 加快了TTS的生成速度将IPA生成设置为可选项
2025.10.07 新增文本朗读器优化了视频播放器UI
2025.10.06 更新了主页面UI移除IPA生成与文本朗读功能新增全语言翻译器
2025.10.05 新增IPA生成与文本朗读功能

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#1f1f1f"><path d="m256-200-56-56 224-224-224-224 56-56 224 224 224-224 56 56-224 224 224 224-56 56-224-224-224 224Z"/></svg>

After

Width:  |  Height:  |  Size: 222 B

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#1f1f1f"><path d="M240-400q-33 0-56.5-23.5T160-480q0-33 23.5-56.5T240-560q33 0 56.5 23.5T320-480q0 33-23.5 56.5T240-400Zm240 0q-33 0-56.5-23.5T400-480q0-33 23.5-56.5T480-560q33 0 56.5 23.5T560-480q0 33-23.5 56.5T480-400Zm240 0q-33 0-56.5-23.5T640-480q0-33 23.5-56.5T720-560q33 0 56.5 23.5T800-480q0 33-23.5 56.5T720-400Z"/></svg>

After

Width:  |  Height:  |  Size: 427 B

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" height="24px" viewBox="0 -960 960 960" width="24px" fill="#1f1f1f"><path d="M480-160q-134 0-227-93t-93-227q0-134 93-227t227-93q69 0 132 28.5T720-690v-110h80v280H520v-80h168q-32-56-87.5-88T480-720q-100 0-170 70t-70 170q0 100 70 170t170 70q77 0 139-44t87-116h84q-28 106-114 173t-196 67Z"/></svg>

After

Width:  |  Height:  |  Size: 333 B

View File

@@ -0,0 +1,46 @@
import Button from "@/components/Button";
import IconClick from "@/components/IconClick";
import IMAGES from "@/config/images";
import { Letter, SupportedAlphabets } from "@/interfaces";
import { Dispatch, SetStateAction, useRef, useState } from "react";
export default function MemoryCard(
{
alphabet,
language,
setChosenAlphabet
}: {
alphabet: Letter[],
language: string,
setChosenAlphabet: Dispatch<SetStateAction<SupportedAlphabets | null>>
}
) {
const [index, setIndex] = useState(Math.floor(Math.random() * alphabet.length));
const [more, setMore] = useState(false);
const [ipaDisplay, setIPADisplay] = useState(true);
const [letterDisplay, setLetterDisplay] = useState(true);
const letter = alphabet[index];
return (
<div className="w-full flex justify-center items-center">
<div className="m-4 p-4 w-full md:w-[60dvw] flex-col rounded-2xl shadow border-gray-200 border flex justify-center items-center">
<div className="w-full flex justify-end items-center">
<IconClick size={32} alt="close" src={IMAGES.close} onClick={() => setChosenAlphabet(null)}></IconClick>
</div>
<div className="flex flex-col gap-12 justify-center items-center">
<span className="text-7xl md:text-9xl">{letterDisplay ? letter.letter : ''}</span>
<span className="text-5xl md:text-7xl text-gray-400">{ipaDisplay ? letter.letter_sound_ipa : ''}</span>
</div>
<div className="flex flex-row mt-32 items-center justify-center gap-2">
<IconClick size={48} alt="refresh" src={IMAGES.refresh} onClick={() => setIndex(Math.floor(Math.random() * alphabet.length))}></IconClick>
<IconClick size={48} alt="more" src={IMAGES.more_horiz} onClick={() => setMore(!more)}></IconClick>
{
more ? (<>
<Button className="w-20" label={letterDisplay ? '隐藏字母' : '显示字母'} onClick={() => { setLetterDisplay(!letterDisplay) }}></Button>
<Button className="w-20" label={ipaDisplay ? '隐藏IPA' : '显示IPA'} onClick={() => { setIPADisplay(!ipaDisplay) }}></Button>
</>) : (<></>)
}
</div>
</div>
</div>
);
}

70
src/app/alphabet/page.tsx Normal file
View File

@@ -0,0 +1,70 @@
'use client';
import Button from "@/components/Button";
import { Letter, SupportedAlphabets } from "@/interfaces";
import { useEffect, useState } from "react";
import MemoryCard from "./MemoryCard";
export default function Home() {
const [chosenAlphabet, setChosenAlphabet] = useState<SupportedAlphabets | null>(null);
const [alphabetData, setAlphabetData] = useState<Record<SupportedAlphabets, Letter[] | null>>({
japanese: null,
english: null,
esperanto: null,
uyghur: null
});
const [loadingState, setLoadingState] = useState<'idle' | 'loading' | 'success' | 'error'>('idle');
useEffect(() => {
if (chosenAlphabet && !alphabetData[chosenAlphabet]) {
setLoadingState('loading');
fetch('/alphabets/' + chosenAlphabet + '.json')
.then(res => {
if (!res.ok) throw new Error('Network response was not ok');
return res.json();
}).then((obj) => {
setAlphabetData(prev => ({ ...prev, [chosenAlphabet]: obj as Letter[] }));
setLoadingState('success');
}).catch(() => {
setLoadingState('error');
});
}
}, [chosenAlphabet, alphabetData]);
useEffect(() => {
if (loadingState === 'error') {
const timer = setTimeout(() => {
setLoadingState('idle');
setChosenAlphabet(null);
}, 2000);
return () => clearTimeout(timer);
}
}, [loadingState]);
if (!chosenAlphabet) return (
<div className="border border-gray-200 m-4 mt-4 flex flex-col justify-center items-center p-4 rounded-2xl gap-2">
<span className="text-2xl md:text-3xl"></span>
<div className="flex gap-1 flex-wrap">
<Button label="日语假名" onClick={() => setChosenAlphabet('japanese')}></Button>
<Button label="英文字母" onClick={() => setChosenAlphabet('english')}></Button>
<Button label="维吾尔字母" onClick={() => setChosenAlphabet('uyghur')}></Button>
<Button label="世界语字母" onClick={() => setChosenAlphabet('esperanto')}></Button>
</div>
</div>);
if (loadingState === 'loading') {
return '加载中...';
}
if (loadingState === 'error') {
return '加载失败,请重试';
}
if (loadingState === 'success' && alphabetData[chosenAlphabet]) {
return (<MemoryCard
language={chosenAlphabet}
alphabet={alphabetData[chosenAlphabet]}
setChosenAlphabet={setChosenAlphabet}>
</MemoryCard>);
}
return null;
}

View File

@@ -56,6 +56,11 @@ function LinkGrid() {
name="逐句视频播放器"
description="基于SRT字幕文件逐句播放视频以模仿母语者的发音"
color="#3c988d"></LinkArea>
<LinkArea
href="/alphabet"
name="记忆字母表"
description="从字母表开始新语言的学习"
color="#dd7486"></LinkArea>
<LinkArea
href="#"
name="更多功能"

View File

@@ -1,7 +1,7 @@
'use client';
import { BOARD_WIDTH, TEXT_WIDTH, BOARD_HEIGHT, TEXT_SIZE } from "@/constants";
import Word from "@/interfaces/Word";
import { Word } from "@/interfaces";
import { Dispatch, SetStateAction, useEffect } from "react";
export default function WordBoard(

View File

@@ -2,7 +2,7 @@
import WordBoard from "@/app/word-board/WordBoard";
import Button from "../../components/Button";
import { KeyboardEvent, useRef, useState } from "react";
import Word from "@/interfaces/Word";
import { Word } from "@/interfaces";
import { BOARD_WIDTH, TEXT_WIDTH, BOARD_HEIGHT, TEXT_SIZE } from "@/constants";
import { inspect } from "@/utils";

View File

@@ -8,7 +8,10 @@ const IMAGES = {
autoplay: '/images/autoplay_24dp_1F1F1F_FILL0_wght400_GRAD0_opsz24.svg',
autopause: '/images/autopause_24dp_1F1F1F_FILL0_wght400_GRAD0_opsz24.svg',
speed_1x: '/images/1x_mobiledata_24dp_1F1F1F_FILL0_wght400_GRAD0_opsz24.svg',
play_arrow: '/images/play_arrow_24dp_1F1F1F_FILL0_wght400_GRAD0_opsz24.svg'
play_arrow: '/images/play_arrow_24dp_1F1F1F_FILL0_wght400_GRAD0_opsz24.svg',
close: '/images/close_24dp_1F1F1F_FILL0_wght400_GRAD0_opsz24.svg',
refresh: '/images/refresh_24dp_1F1F1F_FILL0_wght400_GRAD0_opsz24.svg',
more_horiz: '/images/more_horiz_24dp_1F1F1F_FILL0_wght400_GRAD0_opsz24.svg',
}
export default IMAGES;

13
src/interfaces.ts Normal file
View File

@@ -0,0 +1,13 @@
export interface Word {
word: string;
x: number;
y: number;
}export interface Letter {
letter: string;
letter_name_ipa: string;
letter_sound_ipa: string;
roman_letter?: string;
}
export type SupportedAlphabets = 'japanese' | 'english' | 'esperanto' | 'uyghur';

View File

@@ -1,5 +0,0 @@
export default interface Word {
word: string,
x: number,
y: number
}