#!/usr/bin/env python # -*- coding: utf-8 -*- ''' :codeauthor: :email:`Pedro Algarvio (pedro@algarvio.me)` update-transifex-source-translations ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Update the transifex sources configuration file and push the source ''' # Import python libs import os import sys import time import logging import subprocess import ConfigParser try: import txclib.utils except ImportError: sys.stdout.write( 'The \'transifex-client\' library needs to be installed. ' 'Please execute one of \'pip install transifex-client\' or ' '\'easy_install transifex-client\'\n' ) sys.exit(1) DOC_DIR = os.path.abspath(os.path.dirname(os.path.dirname(__file__))) def main(): ''' Run the update code ''' os.chdir(DOC_DIR) sys.stdout.write('Extracting translatable strings....\n') try: subprocess.check_call(['make', 'gettext']) except subprocess.CalledProcessError as exc: sys.stdout.write('An error occurred while extracting the translation ' 'strings: {0}\n'.format(exc)) sys.exit(1) locale_dir = os.path.join(DOC_DIR, 'locale') pot_dir = os.path.join(DOC_DIR, '_build', 'locale') tx_root = txclib.utils.find_dot_tx() tx_config = os.path.join(tx_root, '.tx', 'config') if not tx_root: sys.stdout.write( 'Unable to find the \'.tx/\' directory. Unable to continue\n' ) sys.exit(1) # We do not want the txclib INFO or WARNING logging logging.getLogger('txclib').setLevel(logging.ERROR) sys.stdout.write('Gathering the translation template files...') sys.stdout.flush() entries = [] for dirpath, dirnames, filenames in os.walk(pot_dir): for filename in filenames: pot_file = os.path.join(dirpath, filename) base, ext = os.path.splitext(pot_file) if ext != '.pot': continue resource_path = os.path.relpath(base, pot_dir) try: import babel.messages.pofile if not len(babel.messages.pofile.read_po(open(pot_file))): # Empty pot file, continue continue except ImportError: # No babel package, let's keep on going pass resource_name = resource_path.replace( '\\', '/').replace('/', '--').replace('.', '_') entries.append((resource_path, resource_name)) sys.stdout.write('Done\n') # Let's load the resources already present in the configuration file cfg = ConfigParser.SafeConfigParser() cfg.read([tx_config]) handled_resources = set( section for section in cfg.sections() if section.startswith('salt.') ) sys.stdout.write('Updating the entries in \'.tx/config\'...\n') sys.stdout.flush() total_entries = len(entries) for idx, (resource_path, resource_name) in enumerate(sorted(entries)): sys.stdout.write( '[{0:>{pad}}/{1}] Updating resource for ' '{resource_path}.pot ({resource_name})'.format( idx + 1, total_entries, pad=len(str(total_entries)), locale_dir=locale_dir, resource_name=resource_name, resource_path=resource_path ) ) sys.stdout.flush() try: txclib.utils.exec_command( 'set', '--auto-local -r salt.{resource_name} ' '{locale_dir}//LC_MESSAGES/{resource_path}.po ' '--source-lang en ' '--source-file {pot_dir}/{resource_path}.pot ' '--source-name {resource_path}.rst ' '--execute'.format( resource_name=resource_name, resource_path=resource_path, locale_dir=locale_dir, pot_dir=pot_dir.rstrip('/') ).split(), tx_root ) sys.stdout.write('\n') if 'salt.{0}'.format(resource_name) in handled_resources: handled_resources.remove('salt.{0}'.format(resource_name)) except Exception as err: sys.stdout.write('An error occurred: {0}\n'.format(err)) except KeyboardInterrupt: sys.stdout.write('\n') sys.exit(1) time.sleep(0.025) if handled_resources: non_handled_resources = len(handled_resources) sys.stdout.write( 'Removing old resources from configuration and upstream' '(if possible)\n' ) for idx, resource_name in enumerate(sorted(handled_resources)): sys.stdout.write( '[{0:>{pad}}/{1}] Removing resource {resource_name!r}'.format( idx + 1, non_handled_resources, pad=len(str(non_handled_resources)), resource_name=resource_name, ) ) sys.stdout.flush() try: txclib.utils.exec_command( 'delete', ['-r', resource_name], tx_root ) handled_resources.remove(resource_name) except Exception as err: sys.stdout.write('An error occurred: {0}\n'.format(err)) finally: if cfg.has_section(resource_name): cfg.remove_section(resource_name) sys.stdout.write('\n') time.sleep(0.025) cfg.write(open(tx_config, 'w')) sys.stdout.write('\n') # Set the translations file type we're using txclib.utils.exec_command('set', ['-t', 'PO'], tx_root) time.sleep(0.025) if 'TRANSIFEX_NO_PUSH' not in os.environ: sys.stdout.write('\n') sys.stdout.write('Pushing translation template files...\n') for idx, (resource_path, resource_name) in enumerate(sorted(entries)): sys.stdout.write( '[{0:>{pad}}/{1}] Pushing resource for ' '{resource_path}.pot ({resource_name})'.format( idx + 1, total_entries, pad=len(str(total_entries)), locale_dir=locale_dir, resource_name=resource_name, resource_path=resource_path ) ) sys.stdout.flush() try: txclib.utils.exec_command( 'push', '--resource salt.{resource_name} ' '--source ' '--skip ' '--no-interactive'.format( resource_name=resource_name, resource_path=resource_path, locale_dir=locale_dir ).split(), tx_root ) sys.stdout.write('\n') except Exception as err: sys.stdout.write('An error occurred: {0}\n'.format(err)) except KeyboardInterrupt: sys.stdout.write('\n') sys.exit(1) time.sleep(0.025) if handled_resources: sys.stdout.write('=' * 80) sys.stdout.write( '\nDon\'t forget to delete the following remote resources:\n') for resource_name in sorted(handled_resources): sys.stdout.write(' {0}\n'.format(resource_name)) sys.stdout.write('=' * 80) sys.stdout.write('\nDONE\n') if __name__ == '__main__': main()