po_deep-translator.py 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177
  1. #!/usr/bin/env python3
  2. try:
  3. from deep_translator import GoogleTranslator
  4. except ModuleNotFoundError:
  5. print('You need to install deep-translator. If you have no better idea, try:')
  6. print('pip install deep-translator')
  7. exit(1)
  8. import argparse
  9. import io
  10. import os
  11. from pathlib import Path
  12. import polib
  13. import sys
  14. import textwrap
  15. import time
  16. # Available Translators from deep-translator
  17. '''
  18. from deep_translator import (GoogleTranslator, PonsTranslator,
  19. LingueeTranslator, MyMemoryTranslator,
  20. YandexTranslator, DeepL,
  21. QCRI, single_detection,
  22. batch_detection)
  23. '''
  24. _my_name = os.path.basename(__file__)
  25. _my_input_default = 'my_strings.po'
  26. _my_output_default = 'auto_strings.po'
  27. DESCRIPTION = """
  28. You may need to install deep-translator, e.g.
  29. > pip install deep-translator
  30. Opens the INFILE, assumed to be in 'english',
  31. and the needed language selected as --language
  32. Replace all (-r), or just fill in the missing translations ('msgstr':s),
  33. and save to OUTFILE
  34. """
  35. USAGE_EXAMPLE = f"""
  36. Examples:
  37. > ./{_my_name} -i input.pot -l danish -o output.da.po
  38. > ./{_my_name} -i input.po -l danish -o output.da.po --replace
  39. In case you did not get them all, or already have most of them:
  40. > ./{_my_name} -i test.da.po -l danish -o test.da.po
  41. """
  42. def parse_arguments():
  43. parser = argparse.ArgumentParser(_my_name,
  44. formatter_class=argparse.RawDescriptionHelpFormatter,
  45. description=textwrap.dedent(DESCRIPTION),
  46. epilog=textwrap.dedent(USAGE_EXAMPLE))
  47. add = parser.add_argument
  48. add('-r', '--replace', action='store_true',
  49. help='replace all translations (if using a .po file)')
  50. add('-q', '--quiet', action='store_true',
  51. help='be more quiet')
  52. add('-v', '--verbose', action='store_true',
  53. help='be more verbose')
  54. add('-l', '--language', metavar='LANGUAGE',
  55. help='select language')
  56. add('-i', '--input', metavar='INFILE',
  57. required=True,
  58. help='.po or .pot file for extraction')
  59. add('-o', '--output', metavar='OUTFILE',
  60. default=_my_output_default,
  61. help='output .po file with results')
  62. return parser.parse_args()
  63. def has_valid_text(the_string):
  64. if the_string.isspace():
  65. return False
  66. if len(the_string):
  67. return True
  68. return False
  69. def translate_gettext_file(file_name, language, options):
  70. '''
  71. Look for msgid's then translate their msgstr to language,
  72. note that these files are (expected to be) coded as UTF-8
  73. '''
  74. pofile = polib.pofile(file_name)
  75. translator = GoogleTranslator(source='english', target=language)
  76. # Check if language is supported -- pointless
  77. '''
  78. available_languages = translator.get_supported_languages(as_dict=True)
  79. if not language in available_languages.values() or available_languages.keys():
  80. print(f'Sorry, this imported translator do not speak {language}')
  81. print(f'but they know')
  82. for language_code,language in available_languages.items():
  83. print(' ' +language+':'+language_code)
  84. return
  85. '''
  86. translations = 0
  87. fails = 0
  88. result = 'FAIL'
  89. for entry in pofile:
  90. source = entry.msgid
  91. if options.verbose:
  92. print(f'In: "{source}"')
  93. else:
  94. print('.', end="")
  95. if not source:
  96. continue
  97. if not has_valid_text(source):
  98. result = source
  99. else:
  100. if not options.replace:
  101. if has_valid_text(entry.msgstr):
  102. result = entry.msgstr
  103. if options.verbose:
  104. print(f'Keeping: {result}\n')
  105. continue
  106. retries = 5
  107. untranslated = True
  108. while retries:
  109. try:
  110. # number-only entry somehow can't be translated :(
  111. result = translator.translate(source)
  112. except:
  113. retries -= 1
  114. print(f'Exception, will try {retries} more after sleeping')
  115. time.sleep(1)
  116. result = ""
  117. else:
  118. untranslated = False
  119. translations += 1
  120. retries = 0
  121. if options.verbose:
  122. print(f'Got: {result}\n')
  123. if untranslated:
  124. fails += 1
  125. entry.msgstr = result
  126. if not options.verbose:
  127. print()
  128. print(f'Did {translations} translations')
  129. if fails:
  130. print(f'Left {fails} translations empty, rerun with -f')
  131. else:
  132. print('Everything is translated')
  133. if translations:
  134. pofile.save(options.output)
  135. else:
  136. print(' or did you forget --replace?')
  137. def main(options):
  138. # To be able to make debug-printout
  139. #sys.stdout = io.TextIOWrapper(sys.stdout.detach(), encoding = 'utf-8')
  140. #sys.stderr = io.TextIOWrapper(sys.stderr.detach(), encoding = 'utf-8')
  141. input_file_name = options.input
  142. if not os.path.exists(input_file_name):
  143. print(f'{options.input}, from the -i option, does not exist - giving up')
  144. exit(3)
  145. start = time.time()
  146. translate_gettext_file(input_file_name, options.language, options)
  147. end = time.time()
  148. print('Total time:', end - start, 's')
  149. if __name__ == '__main__':
  150. main(parse_arguments())