From d0e3693574743ac492c9d697f34148234fec3166 Mon Sep 17 00:00:00 2001 From: Wolfang Torres Date: Wed, 20 May 2026 02:06:39 +0800 Subject: [PATCH] add suport for paragraph trsanlations --- anki-hsk-creator/__main__.py | 215 ++++++++++++++++++++----- data/HSK1-1.txt | 0 data/input/{HSK => HSK1}/HSK1-1.txt | 0 data/input/{HSK => HSK1}/HSK1-2.txt | 0 data/input/{HSK => HSK1}/HSK1-3.txt | 0 data/input/{HSK => HSK1}/HSK1-4.txt | 0 data/input/口语/口语-第9课.-text.txt | 2 + data/output/HSK1/HSK1-1.apkg | Bin 0 -> 53466 bytes data/output/{HSK => HSK1}/HSK1-1.tsv | 0 data/output/{HSK => HSK1}/HSK1-2.tsv | 0 data/output/{HSK => HSK1}/HSK1-3.tsv | 0 data/output/{HSK => HSK1}/HSK1-4.tsv | 0 data/output/口语/口语-第9课.-text.apkg | Bin 0 -> 53466 bytes 13 files changed, 173 insertions(+), 44 deletions(-) create mode 100644 data/HSK1-1.txt rename data/input/{HSK => HSK1}/HSK1-1.txt (100%) rename data/input/{HSK => HSK1}/HSK1-2.txt (100%) rename data/input/{HSK => HSK1}/HSK1-3.txt (100%) rename data/input/{HSK => HSK1}/HSK1-4.txt (100%) create mode 100644 data/input/口语/口语-第9课.-text.txt create mode 100644 data/output/HSK1/HSK1-1.apkg rename data/output/{HSK => HSK1}/HSK1-1.tsv (100%) rename data/output/{HSK => HSK1}/HSK1-2.tsv (100%) rename data/output/{HSK => HSK1}/HSK1-3.tsv (100%) rename data/output/{HSK => HSK1}/HSK1-4.tsv (100%) create mode 100644 data/output/口语/口语-第9课.-text.apkg diff --git a/anki-hsk-creator/__main__.py b/anki-hsk-creator/__main__.py index e5ed330..627c489 100644 --- a/anki-hsk-creator/__main__.py +++ b/anki-hsk-creator/__main__.py @@ -1,55 +1,91 @@ ## Imports from pathlib import Path +import random import csv +## PIP from cedict_utils.cedict import CedictParser from pinyin_tone_converter.pinyin_tone_converter import PinyinToneConverter - -# from genanki import Deck, Note - -# import argostranslate.package -# import argostranslate.translate +from genanki import Deck, Note, Model, Package +import argostranslate.package +import argostranslate.translate ## Constants CCCEDICT = Path(__file__).parent / "cedict_ts.u8" -DATA = Path(__file__).parent.parent / "data" +DATA = Path(__file__).parent.parent / "data" INPUT = DATA / "input" OUTPUT = DATA / "output" -CN = "cn" +CN = "zh" EN = "en" +TEXT_TYPE = "TEXT_TYPE" +CSS = """ +.card { + font-family: arial; + font-size: 20px; + text-align: center; + color: black; + background-color: white; +} +.simple { +font-family: Arial; +font-size: 100px; +} +.trad { +font-family: Arial; +font-size: 75px; +} +""" ## Classess -## Main +SIMPLE_MODEL = Model( + 2076166425, + "Simple Model", + fields=[ + {"name": "Question"}, + {"name": "Answer"}, + ], + templates=[ + { + "name": "Card 1", + "qfmt": "{{Question}}", + "afmt": '{{FrontSide}}
{{Answer}}', + }, + ], + css=CSS, +) -# Download and install Argos Translate package -# argostranslate.package.update_package_index() -# available_packages = argostranslate.package.get_available_packages() -# package_to_install = next( -# filter( -# lambda x: x.from_code == CN and x.to_code == EN, available_packages -# ) -# ) -# argostranslate.package.install_from_path(package_to_install.download()) +HSK_MODEL = Model( + 1708536519, + "HSK Model", + fields=[ + {"name": "English"}, + {"name": "Pinyin"}, + {"name": "Simplified"}, + {"name": "Traditional"}, + ], + templates=[ + { + "name": "Card 1", + "qfmt": "{{Pinyin}}
{{English}}", + "afmt": "{{FrontSide}}
{{Simplified}}

{{Traditional}}
", + }, + { + "name": "Card 2", + "qfmt": "
{{Simplified}}

{{Traditional}}
", + "afmt": '{{FrontSide}}
{{Pinyin}}
{{English}}', + }, + ], + css=CSS, +) -def process_files(): - print("Select data file:") - files = [] - for n, file in enumerate(INPUT.glob('**/*.txt')): - files.append(file) - print(f"{n+1} - {file.relative_to(INPUT)}") - s = None - while not s or not s.isnumeric() or not (1 <= int(s) <= len(files)): - s = input(f"Please select the file [1-{len(files)}]: ") - in_file = files[int(s)-1] - relative = in_file.relative_to(INPUT) - out_file = OUTPUT / relative - out_file.parent.mkdir(parents=True, exist_ok=True) - return in_file, out_file -def dictionary_process(in_file, out_file): - """Process dictionary files""" +## Functions + + +def create_cedict(): + """Creates a create_cedict dictionary object""" parser = CedictParser() parser.read_file(CCCEDICT) entries = parser.parse() @@ -60,17 +96,49 @@ def dictionary_process(in_file, out_file): dictionary[entry.simplified] = [entry] else: dictionary[entry.simplified].append(entry) - - out_file = DATA / f"{in_file.stem}.tsv" - words_list = in_file.open(encoding="utf8").read().split() + return dictionary + + +def create_translator(): + """Download and install Argos Translate package""" + argostranslate.package.update_package_index() + available_packages = argostranslate.package.get_available_packages() + package_to_install = next( + filter(lambda x: x.from_code == CN and x.to_code == EN, available_packages) + ) + argostranslate.package.install_from_path(package_to_install.download()) + + +## Main + + +def process_files(): + print("Select data file:") + files = [] + for n, file in enumerate(INPUT.glob("**/*.txt")): + files.append(file) + print(f"{n+1} - {file.relative_to(INPUT)}") + s = None + while not s or not s.isnumeric() or not (1 <= int(s) <= len(files)): + s = input(f"Please select the file [1-{len(files)}]: ") + in_file = files[int(s) - 1] + relative = in_file.relative_to(INPUT) + out_file = OUTPUT / relative + out_file.parent.mkdir(parents=True, exist_ok=True) + with in_file.open(encoding="utf8") as input_file: + file_type = input_file.read().split()[0] + return in_file, out_file, file_type + + +def dictionary_process(dictionary, in_file): + """Process dictionary files""" + words_list = in_file.open(encoding="utf8").read().split() results = [] for word in words_list: if v := dictionary.get(word): if len(v) > 1: - print( - f"\nWARNING: {word} has multiple meanings:" - ) + print(f"\nWARNING: {word} has multiple meanings:") for n, w in enumerate(v): print(f"{n+1} - {w}") for m in w.meanings: @@ -78,7 +146,7 @@ def dictionary_process(in_file, out_file): s = None while not s or not s.isnumeric() or not (1 <= int(s) <= len(v)): s = input(f"Please select the correct word [1-{len(v)}]: ") - v = v[int(s)-1] + v = v[int(s) - 1] else: v = v[0] results.append(v) @@ -86,21 +154,80 @@ def dictionary_process(in_file, out_file): print("============================================") print(f"===================>ERROR: {word} not found") print("============================================") - with out_file.open("w", encoding="utf8", newline="") as csvfile: + return results + + +def trasnlator_process(in_file): + """Process text trasnlate files""" + text_list = in_file.open(encoding="utf8").read().split()[1:] + results = [] + for text in text_list: + text = text.strip() + for par in text.split("。"): + if par: + translatedText = argostranslate.translate.translate(par, CN, EN) + results.append([translatedText, par]) + return results + + +def output_tsv(out_file, results): + """writes the output as a tsv file""" + final_file = out_file.parent / f"{out_file.stem}.tsv" + with final_file.open("w", encoding="utf8", newline="") as csvfile: writer = csv.writer(csvfile, delimiter="\t", quotechar='"') for entry in results: writer.writerow( [ - "\n ".join(f"{n+1}. {m}" for n,m in enumerate(entry.meanings)), + "\n ".join(f"{n+1}. {m}" for n, m in enumerate(entry.meanings)), PinyinToneConverter().convert_text(entry.pinyin), entry.simplified, entry.traditional, ] ) + +def output_anki_dictionary(out_file, results): + final_file = out_file.parent / f"{out_file.stem}.apkg" + deck_name = "::".join(out_file.relative_to(OUTPUT).parts[:-1] + (out_file.stem,)) + deck = Deck(random.randrange(1 << 30, 1 << 31), deck_name) + for entry in results: + note = Note( + model=HSK_MODEL, + fields=[ + "\n ".join(f"{n+1}. {m}" for n, m in enumerate(entry.meanings)), + PinyinToneConverter().convert_text(entry.pinyin), + entry.simplified, + entry.traditional, + ], + ) + deck.add_note(note) + Package(deck).write_to_file(final_file) + + +def output_anki_text(out_file, results): + final_file = out_file.parent / f"{out_file.stem}.apkg" + deck_name = "::".join(out_file.relative_to(OUTPUT).parts[:-1] + (out_file.stem,)) + deck = Deck(random.randrange(1 << 30, 1 << 31), deck_name) + for entry in results: + note = Note( + model=SIMPLE_MODEL, + fields=entry, + ) + deck.add_note(note) + Package(deck).write_to_file(final_file) + + def main(): - in_file, out_file = process_files() - dictionary_process(in_file, out_file) + in_file, out_file, file_type = process_files() + if TEXT_TYPE == file_type: + create_translator() + results = trasnlator_process(in_file) + output_anki_text(out_file, results) + else: + dictionary = create_cedict() + results = dictionary_process(dictionary, in_file) + output_anki_dictionary(out_file, results) + if __name__ == "__main__": main() diff --git a/data/HSK1-1.txt b/data/HSK1-1.txt new file mode 100644 index 0000000..e69de29 diff --git a/data/input/HSK/HSK1-1.txt b/data/input/HSK1/HSK1-1.txt similarity index 100% rename from data/input/HSK/HSK1-1.txt rename to data/input/HSK1/HSK1-1.txt diff --git a/data/input/HSK/HSK1-2.txt b/data/input/HSK1/HSK1-2.txt similarity index 100% rename from data/input/HSK/HSK1-2.txt rename to data/input/HSK1/HSK1-2.txt diff --git a/data/input/HSK/HSK1-3.txt b/data/input/HSK1/HSK1-3.txt similarity index 100% rename from data/input/HSK/HSK1-3.txt rename to data/input/HSK1/HSK1-3.txt diff --git a/data/input/HSK/HSK1-4.txt b/data/input/HSK1/HSK1-4.txt similarity index 100% rename from data/input/HSK/HSK1-4.txt rename to data/input/HSK1/HSK1-4.txt diff --git a/data/input/口语/口语-第9课.-text.txt b/data/input/口语/口语-第9课.-text.txt new file mode 100644 index 0000000..7af8beb --- /dev/null +++ b/data/input/口语/口语-第9课.-text.txt @@ -0,0 +1,2 @@ +TEXT_TYPE +周六那场篮球比在,对手很厉害。前半场他们一直赢,后半场我们对才超过他们,领先得并不轻松。 \ No newline at end of file diff --git a/data/output/HSK1/HSK1-1.apkg b/data/output/HSK1/HSK1-1.apkg new file mode 100644 index 0000000000000000000000000000000000000000..e112a59da0fc772be0db9466c2a56106cd318a66 GIT binary patch literal 53466 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 K!{;=17Wg0Br_q-H literal 0 HcmV?d00001