|
@@ -0,0 +1,193 @@
|
|
|
+
|
|
|
+
|
|
|
+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
|
|
|
+
|
|
|
+
|
|
|
+'''
|
|
|
+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 translatepy, e.g.
|
|
|
+> pip install translatepy
|
|
|
+
|
|
|
+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()
|
|
|
+
|
|
|
+
|
|
|
+ '''
|
|
|
+ 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
|
|
|
+
|
|
|
+
|
|
|
+ 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):
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ 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())
|