#!/usr/bin/env python3 try: from simplytranslate_engines.googletranslate import GoogleTranslateEngine from simplytranslate_engines.utils import to_lang_code except ModuleNotFoundError: print('You need to install SimplyTranslate-Engines. If you have no better idea, try:') print('pip install git+https://codeberg.org/SimpleWeb/SimplyTranslate-Engines') exit(1) import asyncio import argparse import io import os from pathlib import Path import polib import sys import textwrap import time # Available Translators from SimplyTranslate-Engines ''' from simplytranslate_engines.libretranslate import LibreTranslateEngine from simplytranslate_engines.googletranslate import GoogleTranslateEngine from simplytranslate_engines.icibatranslate import IcibaTranslateEngine from simplytranslate_engines.deepl import DeeplEngine from simplytranslate_engines.reverso import ReversoTranslateEngine ''' _my_name = os.path.basename(__file__) _my_input_default = 'my_strings.po' _my_output_default = 'auto_strings.po' DESCRIPTION = """ You may need to install SimplyTranslate-Engines, e.g. > pip install git+https://codeberg.org/SimpleWeb/SimplyTranslate-Engines Opens the INFILE, assumed to be in 'english', and the needed language selected as --language Replace all (-r), or just fill in the missing translations ('msgstr':s), and save to OUTFILE """ USAGE_EXAMPLE = f""" Examples: > ./{_my_name} -i input.pot -l danish -o output.da.po > ./{_my_name} -i input.po -l danish -o output.da.po --replace In case you did not get them all, or already have most of them: > ./{_my_name} -i test.da.po -l danish -o test.da.po """ def parse_arguments(): parser = argparse.ArgumentParser(_my_name, formatter_class=argparse.RawDescriptionHelpFormatter, description=textwrap.dedent(DESCRIPTION), epilog=textwrap.dedent(USAGE_EXAMPLE)) add = parser.add_argument add('-r', '--replace', action='store_true', help='replace all translations (if using a .po file)') add('-q', '--quiet', action='store_true', help='be more quiet') add('-v', '--verbose', action='store_true', help='be more verbose') add('-l', '--language', metavar='LANGUAGE', help='select language') add('-i', '--input', metavar='INFILE', required=True, help='.po or .pot file for extraction') add('-o', '--output', metavar='OUTFILE', default=_my_output_default, help='output .po file with results') return parser.parse_args() def has_valid_text(the_string): if the_string.isspace(): return False if len(the_string): return True return False def translate_gettext_file(file_name, language, options): ''' Look for msgid's then translate their msgstr to language, note that these files are (expected to be) coded as UTF-8 ''' pofile = polib.pofile(file_name) translator = GoogleTranslateEngine() # Remember to add instance URL for LibreTranslateEngine, api key is optional # Reference: https://codeberg.org/SimpleWeb/SimplyTranslate-CLI ''' api_key = None if instance is None: instance = "https://libretranslate.de" elif not (instance.startswith("https://") or instance.startswith("http://")): instance = f"https://{instance}" if api_key is None: translator = LibreTranslateEngine(instance) else: translator = LibreTranslateEngine(instance, api_key=api_key) ''' from_language = 'english' to_language = language # Check if language is supported async def get_languages(): return await asyncio.gather( asyncio.create_task(to_lang_code(from_language, translator)), asyncio.create_task(to_lang_code(to_language, translator)) ) from_language, to_language = asyncio.run(get_languages()) translations = 0 fails = 0 result = 'FAIL' for entry in pofile: source = entry.msgid if options.verbose: print(f'In: "{source}"') else: print('.', end="") if not source: continue if not has_valid_text(source): result = source else: if not options.replace: if has_valid_text(entry.msgstr): result = entry.msgstr if options.verbose: print(f'Keeping: {result}\n') continue retries = 5 untranslated = True while retries: try: proposal = translator.translate(source, from_language=from_language, to_language=to_language) result = asyncio.run(proposal)['translated-text'] except: retries -= 1 print(f'Exception, will try {retries} more after sleeping') time.sleep(1) result = "" else: untranslated = False translations += 1 retries = 0 if options.verbose: print(f'Got: {result}\n') if untranslated: fails += 1 entry.msgstr = result if not options.verbose: print() print(f'Did {translations} translations') if fails: print(f'Left {fails} translations empty, rerun with -f') else: print('Everything is translated') if translations: pofile.save(options.output) else: print(' or did you forget --replace?') def main(options): # To be able to make debug-printout #sys.stdout = io.TextIOWrapper(sys.stdout.detach(), encoding = 'utf-8') #sys.stderr = io.TextIOWrapper(sys.stderr.detach(), encoding = 'utf-8') input_file_name = options.input if not os.path.exists(input_file_name): print(f'{options.input}, from the -i option, does not exist - giving up') exit(3) start = time.time() translate_gettext_file(input_file_name, options.language, options) end = time.time() print('Total time:', end - start, 's') if __name__ == '__main__': main(parse_arguments())