update-transifex-source-translations 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223
  1. #!/usr/bin/env python
  2. # -*- coding: utf-8 -*-
  3. '''
  4. :codeauthor: Pedro Algarvio (pedro@algarvio.me)
  5. update-transifex-source-translations
  6. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  7. Update the transifex sources configuration file and push the source
  8. '''
  9. # Import python libs
  10. import os
  11. import sys
  12. import time
  13. import logging
  14. import subprocess
  15. import ConfigParser
  16. try:
  17. import txclib.utils
  18. except ImportError:
  19. sys.stdout.write(
  20. 'The \'transifex-client\' library needs to be installed. '
  21. 'Please execute one of \'pip install transifex-client\' or '
  22. '\'easy_install transifex-client\'\n'
  23. )
  24. sys.exit(1)
  25. DOC_DIR = os.path.abspath(os.path.dirname(os.path.dirname(__file__)))
  26. def main():
  27. '''
  28. Run the update code
  29. '''
  30. os.chdir(DOC_DIR)
  31. sys.stdout.write('Extracting translatable strings....\n')
  32. try:
  33. subprocess.check_call(['make', 'gettext'])
  34. except subprocess.CalledProcessError as exc:
  35. sys.stdout.write('An error occurred while extracting the translation '
  36. 'strings: {0}\n'.format(exc))
  37. sys.exit(1)
  38. locale_dir = os.path.join(DOC_DIR, 'locale')
  39. pot_dir = os.path.join(DOC_DIR, '_build', 'locale')
  40. tx_root = txclib.utils.find_dot_tx()
  41. tx_config = os.path.join(tx_root, '.tx', 'config')
  42. if not tx_root:
  43. sys.stdout.write(
  44. 'Unable to find the \'.tx/\' directory. Unable to continue\n'
  45. )
  46. sys.exit(1)
  47. # We do not want the txclib INFO or WARNING logging
  48. logging.getLogger('txclib').setLevel(logging.ERROR)
  49. sys.stdout.write('Gathering the translation template files...')
  50. sys.stdout.flush()
  51. entries = []
  52. for dirpath, dirnames, filenames in os.walk(pot_dir):
  53. for filename in filenames:
  54. pot_file = os.path.join(dirpath, filename)
  55. base, ext = os.path.splitext(pot_file)
  56. if ext != '.pot':
  57. continue
  58. resource_path = os.path.relpath(base, pot_dir)
  59. try:
  60. import babel.messages.pofile
  61. if not len(babel.messages.pofile.read_po(open(pot_file))):
  62. # Empty pot file, continue
  63. continue
  64. except ImportError:
  65. # No babel package, let's keep on going
  66. pass
  67. resource_name = resource_path.replace(
  68. '\\', '/').replace('/', '--').replace('.', '_')
  69. entries.append((resource_path, resource_name))
  70. sys.stdout.write('Done\n')
  71. # Let's load the resources already present in the configuration file
  72. cfg = ConfigParser.SafeConfigParser()
  73. cfg.read([tx_config])
  74. handled_resources = set(
  75. section for section in
  76. cfg.sections() if section.startswith('salt.')
  77. )
  78. sys.stdout.write('Updating the entries in \'.tx/config\'...\n')
  79. sys.stdout.flush()
  80. total_entries = len(entries)
  81. for idx, (resource_path, resource_name) in enumerate(sorted(entries)):
  82. sys.stdout.write(
  83. '[{0:>{pad}}/{1}] Updating resource for '
  84. '{resource_path}.pot ({resource_name})'.format(
  85. idx + 1,
  86. total_entries,
  87. pad=len(str(total_entries)),
  88. locale_dir=locale_dir,
  89. resource_name=resource_name,
  90. resource_path=resource_path
  91. )
  92. )
  93. sys.stdout.flush()
  94. try:
  95. txclib.utils.exec_command(
  96. 'set',
  97. '--auto-local -r salt.{resource_name} '
  98. '{locale_dir}/<lang>/LC_MESSAGES/{resource_path}.po '
  99. '--source-lang en '
  100. '--source-file {pot_dir}/{resource_path}.pot '
  101. '--source-name {resource_path}.rst '
  102. '--execute'.format(
  103. resource_name=resource_name,
  104. resource_path=resource_path,
  105. locale_dir=locale_dir,
  106. pot_dir=pot_dir.rstrip('/')
  107. ).split(),
  108. tx_root
  109. )
  110. sys.stdout.write('\n')
  111. if 'salt.{0}'.format(resource_name) in handled_resources:
  112. handled_resources.remove('salt.{0}'.format(resource_name))
  113. except Exception as err:
  114. sys.stdout.write('An error occurred: {0}\n'.format(err))
  115. except KeyboardInterrupt:
  116. sys.stdout.write('\n')
  117. sys.exit(1)
  118. time.sleep(0.025)
  119. if handled_resources:
  120. non_handled_resources = len(handled_resources)
  121. sys.stdout.write(
  122. 'Removing old resources from configuration and upstream'
  123. '(if possible)\n'
  124. )
  125. for idx, resource_name in enumerate(sorted(handled_resources)):
  126. sys.stdout.write(
  127. '[{0:>{pad}}/{1}] Removing resource \'{resource_name}\''.format(
  128. idx + 1,
  129. non_handled_resources,
  130. pad=len(str(non_handled_resources)),
  131. resource_name=resource_name,
  132. )
  133. )
  134. sys.stdout.flush()
  135. try:
  136. txclib.utils.exec_command(
  137. 'delete',
  138. ['-r', resource_name],
  139. tx_root
  140. )
  141. handled_resources.remove(resource_name)
  142. except Exception as err:
  143. sys.stdout.write('An error occurred: {0}\n'.format(err))
  144. finally:
  145. if cfg.has_section(resource_name):
  146. cfg.remove_section(resource_name)
  147. sys.stdout.write('\n')
  148. time.sleep(0.025)
  149. cfg.write(open(tx_config, 'w'))
  150. sys.stdout.write('\n')
  151. # Set the translations file type we're using
  152. txclib.utils.exec_command('set', ['-t', 'PO'], tx_root)
  153. time.sleep(0.025)
  154. if 'TRANSIFEX_NO_PUSH' not in os.environ:
  155. sys.stdout.write('\n')
  156. sys.stdout.write('Pushing translation template files...\n')
  157. for idx, (resource_path, resource_name) in enumerate(sorted(entries)):
  158. sys.stdout.write(
  159. '[{0:>{pad}}/{1}] Pushing resource for '
  160. '{resource_path}.pot ({resource_name})'.format(
  161. idx + 1,
  162. total_entries,
  163. pad=len(str(total_entries)),
  164. locale_dir=locale_dir,
  165. resource_name=resource_name,
  166. resource_path=resource_path
  167. )
  168. )
  169. sys.stdout.flush()
  170. try:
  171. txclib.utils.exec_command(
  172. 'push',
  173. '--resource salt.{resource_name} '
  174. '--source '
  175. '--skip '
  176. '--no-interactive'.format(
  177. resource_name=resource_name,
  178. resource_path=resource_path,
  179. locale_dir=locale_dir
  180. ).split(),
  181. tx_root
  182. )
  183. sys.stdout.write('\n')
  184. except Exception as err:
  185. sys.stdout.write('An error occurred: {0}\n'.format(err))
  186. except KeyboardInterrupt:
  187. sys.stdout.write('\n')
  188. sys.exit(1)
  189. time.sleep(0.025)
  190. if handled_resources:
  191. sys.stdout.write('=' * 80)
  192. sys.stdout.write(
  193. '\nDon\'t forget to delete the following remote resources:\n')
  194. for resource_name in sorted(handled_resources):
  195. sys.stdout.write(' {0}\n'.format(resource_name))
  196. sys.stdout.write('=' * 80)
  197. sys.stdout.write('\nDONE\n')
  198. if __name__ == '__main__':
  199. main()