po_translatepy.py 5.1 KB

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