def pull(language): LOG.info("Pulling language: %s...", language) command = 'tx pull -l {language} -r "stanford-openedx.*"'.format( language=language, ) execute(command) LOG.info("Pulled language: %s.", language)
def run(self, args): """ Main entry point for script """ logging.basicConfig(stream=sys.stdout, level=logging.INFO) configuration = self.configuration if args.ltr: langs = configuration.ltr_langs elif args.rtl: langs = configuration.rtl_langs else: langs = configuration.translated_locales for locale in langs: merge_files(configuration, locale, fail_if_missing=args.strict) # Dummy text is not required. Don't raise exception if files are missing. for locale in configuration.dummy_locales: merge_files(configuration, locale, fail_if_missing=False) # Merge the source locale, so we have the canonical .po files. if configuration.source_locale not in langs: merge_files(configuration, configuration.source_locale, fail_if_missing=args.strict) compile_cmd = 'django-admin.py compilemessages -v{}'.format( args.verbose) if args.verbose: stderr = None else: stderr = DEVNULL execute(compile_cmd, working_directory=configuration.root_dir, stderr=stderr)
def merge(locale, target='django.po', sources=('django-partial.po', ), fail_if_missing=True): """ For the given locale, merge the `sources` files to become the `target` file. Note that the target file might also be one of the sources. If fail_if_missing is true, and the files to be merged are missing, throw an Exception, otherwise return silently. If fail_if_missing is false, and the files to be merged are missing, just return silently. """ LOG.info('Merging %s locale %s', target, locale) locale_directory = config.CONFIGURATION.get_messages_dir(locale) try: validate_files(locale_directory, sources) except Exception: # pylint: disable=broad-except if not fail_if_missing: return raise # merged file is merged.po merge_cmd = 'msgcat -o merged.po ' + ' '.join(sources) execute(merge_cmd, working_directory=locale_directory) # clean up redunancies in the metadata merged_filename = locale_directory.joinpath('merged.po') clean_pofile(merged_filename) # rename merged.po -> django.po (default) target_filename = locale_directory.joinpath(target) os.rename(merged_filename, target_filename)
def run(self, args): """ Main entry point for script """ logging.basicConfig(stream=sys.stdout, level=logging.INFO) if args.ltr: langs = config.CONFIGURATION.ltr_langs elif args.rtl: langs = config.CONFIGURATION.rtl_langs else: langs = config.CONFIGURATION.translated_locales for locale in langs: merge_files(locale, fail_if_missing=args.strict) # Dummy text is not required. Don't raise exception if files are missing. for locale in config.CONFIGURATION.dummy_locales: merge_files(locale, fail_if_missing=False) compile_cmd = 'django-admin.py compilemessages -v{}'.format(args.verbose) if args.verbose: stderr = None else: stderr = DEVNULL execute(compile_cmd, working_directory=config.BASE_DIR, stderr=stderr)
def merge(locale, target='django.po', sources=('django-partial.po',), fail_if_missing=True): """ For the given locale, merge the `sources` files to become the `target` file. Note that the target file might also be one of the sources. If fail_if_missing is true, and the files to be merged are missing, throw an Exception, otherwise return silently. If fail_if_missing is false, and the files to be merged are missing, just return silently. """ LOG.info('Merging {target} for locale {locale}'.format(target=target, locale=locale)) locale_directory = config.CONFIGURATION.get_messages_dir(locale) try: validate_files(locale_directory, sources) except Exception: # pylint: disable=broad-except if not fail_if_missing: return raise # merged file is merged.po merge_cmd = 'msgcat -o merged.po ' + ' '.join(sources) execute(merge_cmd, working_directory=locale_directory) # clean up redunancies in the metadata merged_filename = locale_directory.joinpath('merged.po') clean_pofile(merged_filename) # rename merged.po -> django.po (default) target_filename = locale_directory.joinpath(target) os.rename(merged_filename, target_filename)
def _extract_babel(file_config, file_output, template_directory='.', working_directory='.'): babel_command = BABEL_COMMAND_TEMPLATE.format( config=file_config, output=file_output, template_directory=template_directory, ) execute(babel_command, working_directory) return file_output
def _merge_combine(target_source, target_filename, common_file, language): output = CONFIG.get_messages_dir(language) / target_filename command = "msgmerge --no-fuzzy-matching {common_file} {target_source} -o {output}".format( common_file=common_file, target_source=target_source, output=output, ) execute(command)
def _merge_pull(target_source, common_file, language, existing): existing_file = CONFIG.get_messages_dir(language) / existing command = "msgcomm {existing_file} {target_source} -o {output}".format( existing_file=existing_file, target_source=target_source, output=common_file, ) execute(command)
def merge(locale, outputfile, outputfile_name): locale_directory = config.CONFIGURATION.get_messages_dir(locale) merge_cmd = 'msgcat -o merged.po ' + ' '.join( [outputfile, outputfile_name + '-studio.po']) execute(merge_cmd, working_directory=locale_directory) merged_filename = locale_directory.joinpath('merged.po') target_filename = locale_directory.joinpath(outputfile) os.rename(merged_filename, target_filename)
def pull_all(): """ Pulls all translations - reviewed or not - for all languages. Only cleans locales: listed in conf/locale/config.yaml """ print("Pulling all translations for all languages, reviewed or not, from transifex...") execute('tx pull --all') clean_translated_locales()
def main(): logging.basicConfig(stream=sys.stdout, level=logging.INFO) for locale in CONFIGURATION.locales: merge(locale) # Dummy text is not required. Don't raise exception if files are missing. merge(CONFIGURATION.dummy_locale, fail_if_missing=False) compile_cmd = "django-admin.py compilemessages" execute(compile_cmd, working_directory=BASE_DIR)
def clean_conf_folder(locale): """Remove the configuration directory for `locale`""" dirname = CONFIGURATION.get_messages_dir(locale) command = "rm -rf {}".format(dirname) print(command) try: execute(command) except Exception as exc: print("Encountered error {}; continuing...".format(exc)) return
def pull(): """ Pull translations from all languages listed in conf/locale/config.yaml where there is at least 10% reviewed translations """ print("Pulling conf/locale/config.yaml:locales from Transifex...") for lang in config.CONFIGURATION.translated_locales: execute('tx pull --mode=reviewed -l ' + lang) clean_translated_locales()
def main(): logging.basicConfig(stream=sys.stdout, level=logging.INFO) for locale in CONFIGURATION.locales: merge_files(locale) # Dummy text is not required. Don't raise exception if files are missing. merge_files(CONFIGURATION.dummy_locale, fail_if_missing=False) compile_cmd = 'django-admin.py compilemessages' execute(compile_cmd, working_directory=BASE_DIR)
def pull_all_ltr(configuration): """ Pulls all translations - reviewed or not - for LTR languages """ print("Pulling all translated LTR languages from transifex...") for lang in configuration.ltr_langs: print('rm -rf conf/locale/' + lang) execute('rm -rf conf/locale/' + lang) execute('tx pull -l ' + lang) clean_translated_locales(configuration, langs=configuration.ltr_langs)
def pull_all_rtl(): """ Pulls all translations - reviewed or not - for RTL languages """ print("Pulling all translated RTL languages from transifex...") for lang in config.CONFIGURATION.rtl_langs: print ('rm -rf conf/locale/' + lang) execute('rm -rf conf/locale/' + lang) execute('tx pull -l ' + lang) clean_translated_locales(langs=config.CONFIGURATION.rtl_langs)
def pull_all_rtl(configuration): """ Pulls all translations - reviewed or not - for RTL languages """ print("Pulling all translated RTL languages from transifex...") for lang in configuration.rtl_langs: print('rm -rf conf/locale/' + lang) execute('rm -rf conf/locale/' + lang) execute('tx pull -l ' + lang) clean_translated_locales(configuration, langs=configuration.rtl_langs)
def pull_all_ltr(): """ Pulls all translations - reviewed or not - for LTR languages """ print("Pulling all translated LTR languages from transifex...") for lang in config.CONFIGURATION.ltr_langs: print('rm -rf conf/locale/' + lang) execute('rm -rf conf/locale/' + lang) execute('tx pull -l ' + lang) clean_translated_locales(langs=config.CONFIGURATION.ltr_langs)
def push_all(): """ Push translation source English files and all translations to Transifex """ print("\n\nWARNING! This command pushes source AND translations files. Use with caution.\n") proceed = raw_input("Are you sure you want to proceed? (Y/n) ") if proceed.lower() == 'y': # http://docs.transifex.com/client/push/ # Push source & translation files. Force new resources, continue on errors. # Don't require user input (it does it for each resource, so we ask above) execute('tx push -s -t --force --skip --no-interactive') else: print("\n")
def push(*resources): """ Push translation source English files to Transifex. Arguments name specific resources to push. Otherwise, push all the source files. """ cmd = 'tx push -s' if resources: for resource in resources: execute(cmd + ' -r {resource}'.format(resource=resource)) else: execute(cmd)
def merge(configuration, locale, target='django.po', sources=('django-partial.po', ), fail_if_missing=True): """ For the given locale, merge the `sources` files to become the `target` file. Note that the target file might also be one of the sources. If fail_if_missing is true, and the files to be merged are missing, throw an Exception, otherwise return silently. If fail_if_missing is false, and the files to be merged are missing, just return silently. """ LOG.info('Merging %s locale %s', target, locale) locale_directory = configuration.get_messages_dir(locale) valid_sources = [] for filename in sources: try: validate_file(locale_directory, filename) valid_sources.append(filename) except (ValueError, IOError): if fail_if_missing: raise if not valid_sources: return # merged file is merged.po merge_cmd = 'msgcat -o merged.po ' + ' '.join(valid_sources) execute(merge_cmd, working_directory=locale_directory) # clean up redunancies in the metadata merged_filename = locale_directory.joinpath('merged.po') duplicate_entries = clean_pofile(merged_filename) # rename merged.po -> django.po (default) target_filename = locale_directory.joinpath(target) os.rename(merged_filename, target_filename) # Write duplicate messages to a file if duplicate_entries: dup_file = target_filename.replace(".po", ".dup") with codecs.open(dup_file, "w", encoding="utf8") as dfile: for (entry, translations) in duplicate_entries: dfile.write(f"{entry}\n") dfile.write(f"Translations found were:\n\t{translations}\n\n") LOG.warning(" %s duplicates in %s, details in .dup file", len(duplicate_entries), target_filename)
def detect_changes(self): """ Detect if changes have been made to the msgid or msgstr lines in the translation files. Returns: boolean: True, if changes detected; otherwise, False. Note: This method requires ``git`` to be installed on the executing machine. """ try: execute('git diff --exit-code -G "^(msgid|msgstr)"') return False except CalledProcessError: return True
def main(strict=True, verbosity=1): """ Main entry point for script """ for locale in CONFIGURATION.translated_locales: merge_files(locale, fail_if_missing=strict) # Dummy text is not required. Don't raise exception if files are missing. for locale in CONFIGURATION.dummy_locales: merge_files(locale, fail_if_missing=False) compile_cmd = 'django-admin.py compilemessages -v{}'.format(verbosity) if verbosity: stderr = None else: stderr = DEVNULL execute(compile_cmd, working_directory=BASE_DIR, stderr=stderr)
def main(argv=None): logging.basicConfig(stream=sys.stdout, level=logging.INFO) parser = argparse.ArgumentParser(description="Generate merged and compiled message files.") parser.add_argument("--strict", action='store_true', help="Complain about missing files.") args = parser.parse_args(argv or []) for locale in CONFIGURATION.translated_locales: merge_files(locale, fail_if_missing=args.strict) # Dummy text is not required. Don't raise exception if files are missing. for locale in CONFIGURATION.dummy_locales: merge_files(locale, fail_if_missing=False) compile_cmd = 'django-admin.py compilemessages' execute(compile_cmd, working_directory=BASE_DIR)
def extract_platform_django(file_base='django'): filename = CONFIG.source_messages_dir / file_base + '.po' filename_backup = filename + '.backup' filename_stanford = CONFIG.source_messages_dir / 'stanford_' + file_base + '.po' os.rename(filename, filename_backup) makemessages = 'django-admin.py makemessages -l en' ignores = ' '.join([ '--ignore="{}/*"'.format(directory) for directory in CONFIG.ignore_dirs ]) if ignores: makemessages += ' ' + ignores if file_base == 'djangojs': makemessages += ' -d djangojs' execute(makemessages) os.rename(filename, filename_stanford) os.rename(filename_backup, filename) return filename_stanford
def merge(locale, target='django.po', sources=('django-partial.po', ), fail_if_missing=True): """ For the given locale, merge the `sources` files to become the `target` file. Note that the target file might also be one of the sources. If fail_if_missing is true, and the files to be merged are missing, throw an Exception, otherwise return silently. If fail_if_missing is false, and the files to be merged are missing, just return silently. """ LOG.info('Merging %s locale %s', target, locale) locale_directory = config.CONFIGURATION.get_messages_dir(locale) try: validate_files(locale_directory, sources) except Exception: # pylint: disable=broad-except if not fail_if_missing: return raise # merged file is merged.po merge_cmd = 'msgcat -o merged.po ' + ' '.join(sources) execute(merge_cmd, working_directory=locale_directory) # clean up redunancies in the metadata merged_filename = locale_directory.joinpath('merged.po') duplicate_entries = clean_pofile(merged_filename) # rename merged.po -> django.po (default) target_filename = locale_directory.joinpath(target) os.rename(merged_filename, target_filename) # Write duplicate messages to a file if duplicate_entries: dup_file = target_filename.replace(".po", ".dup") with codecs.open(dup_file, "w", encoding="utf8") as dfile: for (entry, translations) in duplicate_entries: dfile.write(u"{}\n".format(entry)) dfile.write( u"Translations found were:\n\t{}\n\n".format(translations)) LOG.warning(" %s duplicates in %s, details in .dup file", len(duplicate_entries), target_filename)
def run(self, args): """ Main entry point for script """ logging.basicConfig(stream=sys.stdout, level=logging.INFO) configuration = self.configuration if args.ltr: langs = configuration.ltr_langs elif args.rtl: langs = configuration.rtl_langs else: langs = configuration.translated_locales for locale in langs: merge_files(configuration, locale, fail_if_missing=args.strict) # Dummy text is not required. Don't raise exception if files are missing. for locale in configuration.dummy_locales: merge_files(configuration, locale, fail_if_missing=False) # Merge the source locale, so we have the canonical .po files. if configuration.source_locale not in langs: merge_files(configuration, configuration.source_locale, fail_if_missing=args.strict) compile_cmd = u'django-admin.py compilemessages -v{}'.format( args.verbose) if args.verbose: stderr = None else: stderr = DEVNULL execute(compile_cmd, working_directory=configuration.root_dir, stderr=stderr) # Check for any mapped languages and copy directories around accordingly for source_locale, dest_locale in configuration.edx_lang_map.items(): source_dirname = configuration.get_messages_dir(source_locale) dest_dirname = configuration.get_messages_dir(dest_locale) LOG.info(u"Copying mapped locale %s to %s", source_dirname, dest_dirname) path.rmtree_p(path(dest_dirname)) path.copytree(path(source_dirname), path(dest_dirname))
def main(argv=None): logging.basicConfig(stream=sys.stdout, level=logging.INFO) parser = argparse.ArgumentParser( description="Generate merged and compiled message files.") parser.add_argument("--strict", action='store_true', help="Complain about missing files.") args = parser.parse_args(argv or []) for locale in CONFIGURATION.translated_locales: merge_files(locale, fail_if_missing=args.strict) # Dummy text is not required. Don't raise exception if files are missing. for locale in CONFIGURATION.dummy_locales: merge_files(locale, fail_if_missing=False) compile_cmd = 'django-admin.py compilemessages' execute(compile_cmd, working_directory=BASE_DIR)
def pull(configuration, *resources): """ Pull translations from all languages listed in conf/locale/config.yaml where there is at least 10% reviewed translations. If arguments are provided, they are specific resources to pull. Otherwise, all resources are pulled. """ print("Pulling conf/locale/config.yaml:locales from Transifex...") for lang in configuration.translated_locales: cmd = 'tx pull -f --mode=reviewed -l {lang}'.format(lang=lang) if resources: for resource in resources: execute(cmd + ' -r {resource}'.format(resource=resource)) else: execute(cmd) clean_translated_locales(configuration)
def pull(*resources): """ Pull translations from all languages listed in conf/locale/config.yaml where there is at least 10% reviewed translations. If arguments are provided, they are specific resources to pull. Otherwise, all resources are pulled. """ print("Pulling conf/locale/config.yaml:locales from Transifex...") for lang in config.CONFIGURATION.translated_locales: cmd = 'tx pull -f --mode=reviewed -l {lang}'.format(lang=lang) if resources: for resource in resources: execute(cmd + ' -r {resource}'.format(resource=resource)) else: execute(cmd) clean_translated_locales()
def merge(locale, target='django.po', sources=('django-partial.po',), fail_if_missing=True): """ For the given locale, merge the `sources` files to become the `target` file. Note that the target file might also be one of the sources. If fail_if_missing is true, and the files to be merged are missing, throw an Exception, otherwise return silently. If fail_if_missing is false, and the files to be merged are missing, just return silently. """ LOG.info('Merging %s locale %s', target, locale) locale_directory = config.CONFIGURATION.get_messages_dir(locale) try: validate_files(locale_directory, sources) except Exception: # pylint: disable=broad-except if not fail_if_missing: return raise # merged file is merged.po merge_cmd = 'msgcat -o merged.po ' + ' '.join(sources) execute(merge_cmd, working_directory=locale_directory) # clean up redunancies in the metadata merged_filename = locale_directory.joinpath('merged.po') duplicate_entries = clean_pofile(merged_filename) # rename merged.po -> django.po (default) target_filename = locale_directory.joinpath(target) os.rename(merged_filename, target_filename) # Write duplicate messages to a file if duplicate_entries: dup_file = target_filename.replace(".po", ".dup") with codecs.open(dup_file, "w", encoding="utf8") as dfile: for (entry, translations) in duplicate_entries: dfile.write(u"{}\n".format(entry)) dfile.write(u"Translations found were:\n\t{}\n\n".format(translations)) LOG.warn(" %s duplicates in %s, details in .dup file", len(duplicate_entries), target_filename)
def run(self, args): """ Main entry point for script """ logging.basicConfig(stream=sys.stdout, level=logging.INFO) configuration = self.configuration if args.ltr: langs = configuration.ltr_langs elif args.rtl: langs = configuration.rtl_langs else: langs = configuration.translated_locales for locale in langs: merge_files(configuration, locale, fail_if_missing=args.strict) # Dummy text is not required. Don't raise exception if files are missing. for locale in configuration.dummy_locales: merge_files(configuration, locale, fail_if_missing=False) # Merge the source locale, so we have the canonical .po files. if configuration.source_locale not in langs: merge_files(configuration, configuration.source_locale, fail_if_missing=args.strict) compile_cmd = 'django-admin.py compilemessages -v{}'.format(args.verbose) if args.verbose: stderr = None else: stderr = DEVNULL execute(compile_cmd, working_directory=configuration.root_dir, stderr=stderr) # Check for any mapped languages and copy directories around accordingly for source_locale, dest_locale in configuration.edx_lang_map.items(): source_dirname = configuration.get_messages_dir(source_locale) dest_dirname = configuration.get_messages_dir(dest_locale) LOG.info("Copying mapped locale %s to %s", source_dirname, dest_dirname) path.rmtree_p(path(dest_dirname)) path.copytree(path(source_dirname), path(dest_dirname))
def run_babel_extraction(self, outputfile_name, babel_cfg_name, babel_verbosity, stderr): # --keyword informs Babel that `interpolate()` is an expected # gettext function, which is necessary because the `tokenize` function # in the `markey` module marks it as such and passes it to Babel. # (These functions are called in the django-babel-underscore module.) babel_extract_template = ( 'pybabel {verbosity} extract --mapping={config} ' '--add-comments="Translators:" --keyword="interpolate" ' '. --output={output}') babel_init_template = ( 'pybabel init -D {file_name} -i {input} -d {base_dir} -l {locale}') babel_update_template = ( 'pybabel update -D {file_name} -i {input} -d {base_dir}') outputfile = outputfile_name + '.po' babel_cfg = base(config.LOCALE_DIR, babel_cfg_name) outputfile_path = base(config.LOCALE_DIR, outputfile) locale_dir = base(config.LOCALE_DIR) if babel_cfg.exists(): # extract strings to outputfile_name babel_cmd = babel_extract_template.format( verbosity=babel_verbosity, config=babel_cfg, output=outputfile_path) execute(babel_cmd, working_directory=config.BASE_DIR, stderr=stderr) for locale in config.CONFIGURATION.locales: locale_msg_dir = config.CONFIGURATION.get_messages_dir(locale) # creating translation catalog should only occur once if os.path.isfile(base(locale_msg_dir, outputfile)): merge(locale, outputfile, outputfile_name) else: babel_cmd = babel_init_template.format( file_name=outputfile_name, input=outputfile_path, base_dir=locale_dir, locale=locale) execute(babel_cmd, working_directory=config.BASE_DIR, stderr=stderr) # update process babel_cmd = babel_update_template.format( file_name=outputfile_name, input=outputfile_path, base_dir=locale_dir, ) execute(babel_cmd, working_directory=config.BASE_DIR, stderr=stderr) if os.path.isfile(outputfile_path): os.remove(base(outputfile_path))
def main(): logging.basicConfig(stream=sys.stdout, level=logging.INFO) create_dir_if_necessary(LOCALE_DIR) source_msgs_dir = CONFIGURATION.source_messages_dir remove_file(source_msgs_dir.joinpath('django.po')) # Extract strings from mako templates. babel_mako_cmd = 'pybabel extract -F %s -c "Translators:" . -o %s' % (BABEL_CONFIG, BABEL_OUT) execute(babel_mako_cmd, working_directory=BASE_DIR) makemessages = "django-admin.py makemessages -l en" ignores = " ".join('--ignore="{}/*"'.format(d) for d in CONFIGURATION.ignore_dirs) if ignores: makemessages += " " + ignores # Extract strings from django source files, including .py files. make_django_cmd = makemessages + ' --extension html' execute(make_django_cmd, working_directory=BASE_DIR) # Extract strings from Javascript source files. make_djangojs_cmd = makemessages + ' -d djangojs --extension js' execute(make_djangojs_cmd, working_directory=BASE_DIR) # makemessages creates 'django.po'. This filename is hardcoded. # Rename it to django-partial.po to enable merging into django.po later. os.rename( source_msgs_dir.joinpath('django.po'), source_msgs_dir.joinpath('django-partial.po') ) # makemessages creates 'djangojs.po'. This filename is hardcoded. # Rename it to djangojs-partial.po to enable merging into djangojs.po later. os.rename( source_msgs_dir.joinpath('djangojs.po'), source_msgs_dir.joinpath('djangojs-partial.po') ) # Segment the generated files. segmented_files = segment_pofiles("en") # Finish each file. for filename in segmented_files: LOG.info('Cleaning %s' % filename) po = pofile(source_msgs_dir.joinpath(filename)) # replace default headers with edX headers fix_header(po) # replace default metadata with edX metadata fix_metadata(po) # remove key strings which belong in messages.po strip_key_strings(po) po.save()
def main(): logging.basicConfig(stream=sys.stdout, level=logging.INFO) create_dir_if_necessary(LOCALE_DIR) source_msgs_dir = CONFIGURATION.source_messages_dir remove_file(source_msgs_dir.joinpath('django.po')) makemessages = "django-admin.py makemessages -l en" ignores = " ".join('--ignore="{}/*"'.format(d) for d in CONFIGURATION.ignore_dirs) if ignores: makemessages += " " + ignores # Extract strings from mako templates. babel_mako_cmd = 'pybabel extract -F %s -c "Translators:" . -o %s' % ( BABEL_CONFIG, BABEL_OUT) execute(babel_mako_cmd, working_directory=BASE_DIR) # Extract strings from django source files, including .py files. make_django_cmd = makemessages + ' --extension html' execute(make_django_cmd, working_directory=BASE_DIR) # Extract strings from Javascript source files. make_djangojs_cmd = makemessages + ' -d djangojs --extension js' execute(make_djangojs_cmd, working_directory=BASE_DIR) # makemessages creates 'django.po'. This filename is hardcoded. # Rename it to django-partial.po to enable merging into django.po later. os.rename(source_msgs_dir.joinpath('django.po'), source_msgs_dir.joinpath('django-partial.po')) # Segment the generated files. segmented_files = segment_pofiles("en") # Finish each file. for filename in segmented_files: LOG.info('Cleaning %s' % filename) po = pofile(source_msgs_dir.joinpath(filename)) # replace default headers with edX headers fix_header(po) # replace default metadata with edX metadata fix_metadata(po) # remove key strings which belong in messages.po strip_key_strings(po) po.save()
def main(): logging.basicConfig(stream=sys.stdout, level=logging.INFO) create_dir_if_necessary(LOCALE_DIR) source_msgs_dir = CONFIGURATION.source_messages_dir remove_file(source_msgs_dir.joinpath("django.po")) generated_files = ("django-partial.po", "djangojs.po", "mako.po") for filename in generated_files: remove_file(source_msgs_dir.joinpath(filename)) # Prepare makemessages command. ignore_dirs = ["docs", "src", "i18n", "test_root"] ignores = " ".join("--ignore={}/*".format(d) for d in ignore_dirs) makemessages = "django-admin.py makemessages -l en " + ignores # Extract strings from mako templates. babel_mako_cmd = 'pybabel extract -F %s -c "Translators:" . -o %s' % (BABEL_CONFIG, BABEL_OUT) execute(babel_mako_cmd, working_directory=BASE_DIR) # Extract strings from django source files, including .py files. make_django_cmd = makemessages + " --extension html" execute(make_django_cmd, working_directory=BASE_DIR) # Extract strings from Javascript source files. make_djangojs_cmd = makemessages + " -d djangojs --extension js" execute(make_djangojs_cmd, working_directory=BASE_DIR) # makemessages creates 'django.po'. This filename is hardcoded. # Rename it to django-partial.po to enable merging into django.po later. os.rename(source_msgs_dir.joinpath("django.po"), source_msgs_dir.joinpath("django-partial.po")) for filename in generated_files: LOG.info("Cleaning %s" % filename) po = pofile(source_msgs_dir.joinpath(filename)) # replace default headers with edX headers fix_header(po) # replace default metadata with edX metadata fix_metadata(po) # remove key strings which belong in messages.po strip_key_strings(po) po.save()
def main(): logging.basicConfig(stream=sys.stdout, level=logging.INFO) create_dir_if_necessary(LOCALE_DIR) source_msgs_dir = CONFIGURATION.source_messages_dir remove_file(source_msgs_dir.joinpath('django.po')) # Extract strings from mako templates. babel_mako_cmd = 'pybabel extract -k ugettext_lazy -k _u -F {config} -c "Translators:" . -o {output}' babel_mako_cmd = babel_mako_cmd.format( config=base(LOCALE_DIR, 'babel_mako.cfg'), output=base(CONFIGURATION.source_messages_dir, 'mako.po'), ) execute(babel_mako_cmd, working_directory=BASE_DIR) makemessages = "django-admin.py makemessages -l en" ignores = " ".join('--ignore="{}/*"'.format(d) for d in CONFIGURATION.ignore_dirs) if ignores: makemessages += " " + ignores # Extract strings from django source files, including .py files. make_django_cmd = makemessages + ' --extension html' execute(make_django_cmd, working_directory=BASE_DIR) # Extract strings from Javascript source files. make_djangojs_cmd = makemessages + ' -d djangojs --extension js' execute(make_djangojs_cmd, working_directory=BASE_DIR) # makemessages creates 'django.po'. This filename is hardcoded. # Rename it to django-partial.po to enable merging into django.po later. os.rename( source_msgs_dir.joinpath('django.po'), source_msgs_dir.joinpath('django-partial.po') ) # makemessages creates 'djangojs.po'. This filename is hardcoded. # Rename it to djangojs-partial.po to enable merging into djangojs.po later. os.rename( source_msgs_dir.joinpath('djangojs.po'), source_msgs_dir.joinpath('djangojs-partial.po') ) files_to_clean = set() # Extract strings from third-party applications. for app_name in CONFIGURATION.third_party: # Import the app to find out where it is. Then use pybabel to extract # from that directory. app_module = importlib.import_module(app_name) app_dir = path(app_module.__file__).dirname().dirname() output_file = source_msgs_dir / (app_name + ".po") files_to_clean.add(output_file) babel_cmd = 'pybabel extract -F {config} -c "Translators:" {app} -o {output}' babel_cmd = babel_cmd.format( config=LOCALE_DIR / 'babel_third_party.cfg', app=app_name, output=output_file, ) execute(babel_cmd, working_directory=app_dir) # Segment the generated files. segmented_files = segment_pofiles("en") files_to_clean.update(segmented_files) # Finish each file. for filename in files_to_clean: LOG.info('Cleaning %s' % filename) po = pofile(source_msgs_dir.joinpath(filename)) # replace default headers with edX headers fix_header(po) # replace default metadata with edX metadata fix_metadata(po) # remove key strings which belong in messages.po strip_key_strings(po) po.save()
def run(self, args): """ Main entry point of script """ logging.basicConfig(stream=sys.stdout, level=logging.INFO) configuration = self.configuration configuration.locale_dir.parent.makedirs_p() # pylint: disable=attribute-defined-outside-init self.source_msgs_dir = configuration.source_messages_dir # The extraction process clobbers django.po and djangojs.po. # Save them so that it won't do that. self.rename_source_file('django.po', 'django-saved.po') self.rename_source_file('djangojs.po', 'djangojs-saved.po') # Extract strings from mako templates. verbosity_map = { 0: "-q", 1: "", 2: "-v", } babel_verbosity = verbosity_map.get(args.verbose, "") if args.verbose: stderr = None else: stderr = DEVNULL # --keyword informs Babel that `interpolate()` is an expected # gettext function, which is necessary because the `tokenize` function # in the `markey` module marks it as such and passes it to Babel. # (These functions are called in the django-babel-underscore module.) babel_cmd_template = ( 'pybabel {verbosity} extract --mapping={config} ' '--add-comments="Translators:" --keyword="interpolate" ' '. --output={output}') babel_mako_cfg = self.base(configuration.locale_dir, 'babel_mako.cfg') if babel_mako_cfg.exists(): babel_mako_cmd = babel_cmd_template.format( verbosity=babel_verbosity, config=babel_mako_cfg, output=self.base(configuration.source_messages_dir, 'mako.po'), ) execute(babel_mako_cmd, working_directory=configuration.root_dir, stderr=stderr) babel_underscore_cfg = self.base(configuration.locale_dir, 'babel_underscore.cfg') if babel_underscore_cfg.exists(): babel_underscore_cmd = babel_cmd_template.format( verbosity=babel_verbosity, config=babel_underscore_cfg, output=self.base(configuration.source_messages_dir, 'underscore.po'), ) execute(babel_underscore_cmd, working_directory=configuration.root_dir, stderr=stderr) makemessages = "django-admin.py makemessages -l en -v{}".format( args.verbose) ignores = " ".join('--ignore="{}/*"'.format(d) for d in configuration.ignore_dirs) if ignores: makemessages += " " + ignores # Extract strings from django source files (*.py, *.html, *.txt). make_django_cmd = makemessages + ' -d django' execute(make_django_cmd, working_directory=configuration.root_dir, stderr=stderr) # Extract strings from Javascript source files (*.js, *jsx). make_djangojs_cmd = makemessages + ' -d djangojs -e js,jsx' execute(make_djangojs_cmd, working_directory=configuration.root_dir, stderr=stderr) # makemessages creates 'django.po'. This filename is hardcoded. # Rename it to django-partial.po to enable merging into django.po later. self.rename_source_file('django.po', 'django-partial.po') # makemessages creates 'djangojs.po'. This filename is hardcoded. # Rename it to djangojs-partial.po to enable merging into djangojs.po later. self.rename_source_file('djangojs.po', 'djangojs-partial.po') files_to_clean = set() # Extract strings from third-party applications. for app_name in configuration.third_party: # Import the app to find out where it is. Then use pybabel to extract # from that directory. app_module = importlib.import_module(app_name) app_dir = Path(app_module.__file__).dirname().dirname() # pylint: disable=no-value-for-parameter output_file = self.source_msgs_dir / (app_name + ".po") files_to_clean.add(output_file) babel_cmd = 'pybabel {verbosity} extract -F {config} -c "Translators:" {app} -o {output}' babel_cmd = babel_cmd.format( verbosity=babel_verbosity, config=configuration.locale_dir / 'babel_third_party.cfg', app=app_name, output=output_file, ) execute(babel_cmd, working_directory=app_dir, stderr=stderr) # Segment the generated files. segmented_files = segment_pofiles(configuration, configuration.source_locale) files_to_clean.update(segmented_files) # Finish each file. for filename in files_to_clean: LOG.info('Cleaning %s', filename) pofile = polib.pofile(self.source_msgs_dir.joinpath(filename)) # replace default headers with edX headers fix_header(pofile) # replace default metadata with edX metadata fix_metadata(pofile) # remove key strings which belong in messages.po strip_key_strings(pofile) pofile.save() # Restore the saved .po files. self.rename_source_file('django-saved.po', 'django.po') self.rename_source_file('djangojs-saved.po', 'djangojs.po')
def pull(): print("Pulling languages from transifex...") execute('tx pull --mode=reviewed --all') clean_translated_locales()
def run(self, args): """ Main entry point of script """ logging.basicConfig(stream=sys.stdout, level=logging.INFO) config.LOCALE_DIR.parent.makedirs_p() source_msgs_dir = config.CONFIGURATION.source_messages_dir remove_file(source_msgs_dir.joinpath('django.po')) # Extract strings from mako templates. verbosity_map = { 0: "-q", 1: "", 2: "-v", } babel_verbosity = verbosity_map.get(args.verbose, "") babel_mako_cfg = base(config.LOCALE_DIR, 'babel_mako.cfg') if args.verbose: stderr = None else: stderr = DEVNULL if babel_mako_cfg.exists(): babel_mako_cmd = 'pybabel {verbosity} extract -F {config} -c "Translators:" . -o {output}' babel_mako_cmd = babel_mako_cmd.format( verbosity=babel_verbosity, config=babel_mako_cfg, output=base(config.CONFIGURATION.source_messages_dir, 'mako.po'), ) execute(babel_mako_cmd, working_directory=config.BASE_DIR, stderr=stderr) makemessages = "django-admin.py makemessages -l en -v{}".format(args.verbose) ignores = " ".join('--ignore="{}/*"'.format(d) for d in config.CONFIGURATION.ignore_dirs) if ignores: makemessages += " " + ignores # Extract strings from django source files, including .py files. make_django_cmd = makemessages + ' --extension html' execute(make_django_cmd, working_directory=config.BASE_DIR, stderr=stderr) # Extract strings from Javascript source files. make_djangojs_cmd = makemessages + ' -d djangojs --extension js' execute(make_djangojs_cmd, working_directory=config.BASE_DIR, stderr=stderr) # makemessages creates 'django.po'. This filename is hardcoded. # Rename it to django-partial.po to enable merging into django.po later. os.rename( source_msgs_dir.joinpath('django.po'), source_msgs_dir.joinpath('django-partial.po') ) # makemessages creates 'djangojs.po'. This filename is hardcoded. # Rename it to djangojs-partial.po to enable merging into djangojs.po later. os.rename( source_msgs_dir.joinpath('djangojs.po'), source_msgs_dir.joinpath('djangojs-partial.po') ) files_to_clean = set() # Extract strings from third-party applications. for app_name in config.CONFIGURATION.third_party: # Import the app to find out where it is. Then use pybabel to extract # from that directory. app_module = importlib.import_module(app_name) app_dir = path(app_module.__file__).dirname().dirname() output_file = source_msgs_dir / (app_name + ".po") files_to_clean.add(output_file) babel_cmd = 'pybabel {verbosity} extract -F {config} -c "Translators:" {app} -o {output}' babel_cmd = babel_cmd.format( verbosity=babel_verbosity, config=config.LOCALE_DIR / 'babel_third_party.cfg', app=app_name, output=output_file, ) execute(babel_cmd, working_directory=app_dir, stderr=stderr) # Segment the generated files. segmented_files = segment_pofiles("en") files_to_clean.update(segmented_files) # Finish each file. for filename in files_to_clean: LOG.info('Cleaning %s', filename) pofile = polib.pofile(source_msgs_dir.joinpath(filename)) # replace default headers with edX headers fix_header(pofile) # replace default metadata with edX metadata fix_metadata(pofile) # remove key strings which belong in messages.po strip_key_strings(pofile) pofile.save()
def main(verbosity=1): """ Main entry point of script """ logging.basicConfig(stream=sys.stdout, level=logging.INFO) LOCALE_DIR.parent.makedirs_p() source_msgs_dir = CONFIGURATION.source_messages_dir remove_file(source_msgs_dir.joinpath('django.po')) # Extract strings from mako templates. verbosity_map = { 0: "-q", 1: "", 2: "-v", } babel_verbosity = verbosity_map.get(verbosity, "") babel_mako_cmd = 'pybabel {verbosity} extract -F {config} -c "Translators:" . -o {output}' babel_mako_cmd = babel_mako_cmd.format( verbosity=babel_verbosity, config=base(LOCALE_DIR, 'babel_mako.cfg'), output=base(CONFIGURATION.source_messages_dir, 'mako.po'), ) if verbosity: stderr = None else: stderr = DEVNULL execute(babel_mako_cmd, working_directory=BASE_DIR, stderr=stderr) makemessages = "django-admin.py makemessages -l en -v{}".format(verbosity) ignores = " ".join('--ignore="{}/*"'.format(d) for d in CONFIGURATION.ignore_dirs) if ignores: makemessages += " " + ignores # Extract strings from django source files, including .py files. make_django_cmd = makemessages + ' --extension html' execute(make_django_cmd, working_directory=BASE_DIR, stderr=stderr) # Extract strings from Javascript source files. make_djangojs_cmd = makemessages + ' -d djangojs --extension js' execute(make_djangojs_cmd, working_directory=BASE_DIR, stderr=stderr) # Extract and megre strings from underscore files extract_and_merge_underscore() # makemessages creates 'django.po'. This filename is hardcoded. # Rename it to django-partial.po to enable merging into django.po later. os.rename( source_msgs_dir.joinpath('django.po'), source_msgs_dir.joinpath('django-partial.po') ) # makemessages creates 'djangojs.po'. This filename is hardcoded. # Rename it to djangojs-partial.po to enable merging into djangojs.po later. os.rename( source_msgs_dir.joinpath('djangojs.po'), source_msgs_dir.joinpath('djangojs-partial.po') ) files_to_clean = set() # Extract strings from third-party applications. for app_name in CONFIGURATION.third_party: # Import the app to find out where it is. Then use pybabel to extract # from that directory. app_module = importlib.import_module(app_name) app_dir = path(app_module.__file__).dirname().dirname() output_file = source_msgs_dir / (app_name + ".po") files_to_clean.add(output_file) babel_cmd = 'pybabel {verbosity} extract -F {config} -c "Translators:" {app} -o {output}' babel_cmd = babel_cmd.format( verbosity=babel_verbosity, config=LOCALE_DIR / 'babel_third_party.cfg', app=app_name, output=output_file, ) execute(babel_cmd, working_directory=app_dir, stderr=stderr) # Segment the generated files. segmented_files = segment_pofiles("en") files_to_clean.update(segmented_files) # Finish each file. for filename in files_to_clean: LOG.info('Cleaning %s' % filename) po = pofile(source_msgs_dir.joinpath(filename)) # replace default headers with edX headers fix_header(po) # replace default metadata with edX metadata fix_metadata(po) # remove key strings which belong in messages.po strip_key_strings(po) po.save()
def extract_and_merge_underscore(): source_msgs_dir = CONFIGURATION.source_messages_dir # Extract strings from .underscore file by using grep and sed into # a temp file 'underscore.po'. It is done by the following steps: # # 1. Extract all the patterns of gettext('...') or gettext("...") # using grep's regexp "gettext\([\'\"][^\(\)]+\)", and grep will # return each occurence as "<filename>:<line number>:<string>" # 2. Replace all the single quotes in grep's output into double quotes # by using two consequent sed's regexps s/\(\'/\(\"/ and s/\'\)/\"\)/ # 3. Replace the starting './' of each line into '#: ' to make the filename # looks like occurrence string already in .po files, by using sed's # regexp s/^\.[/]/#\:\ / # 4. Replace the first occurence of ':gettext(' (which is always the matched # string returned by grep) into '\nmsgid ' by using sed's regexp # s/\:gettext\(/\\nmsgid\ / # 5. Replace the last occurence of ')' by '\nmsgstr ""\n' by using sed's # regexp s/\)$/\\nmsgstr\ \"\"\\n/ # # For example, if step 1 returns a string like the following line: # ./cms/templates/js/edit-textbook.underscore:25:gettext("Save") # Then after steps 2 - 5, it will be converted into the following three lines: # #: cms/templates/js/edit-textbook.underscore:25 # msgid "Save" # msgstr "" # extract_underscore_cmd = 'find -name *.underscore -exec {step1_cmd} \\; '\ '| {step2_cmd_1} | {step2_cmd_2} | {step3_cmd} '\ '| {step4_cmd} | {step5_cmd} > {output}' extract_underscore_cmd = extract_underscore_cmd.format( step1_cmd='grep -HnoE "gettext\\([\\\'\\"][^\\(\\)]+\\)" \'{}\'', step2_cmd_1='sed s/\\(\\\'/\\(\\"/', step2_cmd_2='sed s/\\\'\\)/\\"\\)/', step3_cmd='sed s/^\\.[/]/#\\:\\ /', step4_cmd='sed s/\\:gettext\\(/\\\\nmsgid\\ /', step5_cmd='sed s/\\)$/\\\\nmsgstr\\ \\"\\"\\\\n/', output=source_msgs_dir.joinpath('underscore.po') ) execute(extract_underscore_cmd, working_directory=BASE_DIR) # Construct a dictionary by using the string as key and occurrence as value # from underscore.po. This dictionary is used for merging later underscore_po = pofile(source_msgs_dir.joinpath('underscore.po')) underscore_po_occurrences = {} for msg in underscore_po: if msg.msgid in underscore_po_occurrences: if msg.occurrences[0] not in underscore_po_occurrences[msg.msgid]: underscore_po_occurrences[msg.msgid].extend(msg.occurrences) else: underscore_po_occurrences[msg.msgid] = msg.occurrences # The temp file can be safely deleted os.remove(source_msgs_dir.joinpath('underscore.po')) # Merge the messages into djangojs.po djangojs_po = pofile(source_msgs_dir.joinpath('djangojs.po')) # Step 1: # Append new occurrences from .underscore files for the strings already in djangojs.po for msg in djangojs_po: msg.occurrences.extend(underscore_po_occurrences.pop(msg.msgid, [])) # Step 2: # Append all the remaining strings into djangojs.po for msgid in underscore_po_occurrences: msg = copy.deepcopy(djangojs_po[0]) msg.msgid = msgid msg.occurrences = underscore_po_occurrences[msgid] djangojs_po.append(msg) djangojs_po.save(source_msgs_dir.joinpath('djangojs.po'))
def pull(): print("Pulling languages from transifex...") # Pull translations from all languages where there is # at least 10% reviewed translations execute('tx pull --mode=reviewed --all') clean_translated_locales()
just return silently. """ LOG.info('Merging {target} for locale {locale}'.format(target=target, locale=locale)) locale_directory = CONFIGURATION.get_messages_dir(locale) try: validate_files(locale_directory, sources) except Exception, e: if not fail_if_missing: return raise e # merged file is merged.po merge_cmd = 'msgcat -o merged.po ' + ' '.join(sources) execute(merge_cmd, working_directory=locale_directory) # clean up redunancies in the metadata merged_filename = locale_directory.joinpath('merged.po') clean_pofile(merged_filename) # rename merged.po -> django.po (default) target_filename = locale_directory.joinpath(target) os.rename(merged_filename, target_filename) def merge_files(locale, fail_if_missing=True): """ Merge all the files in `locale`, as specified in config.yaml. """ for target, sources in CONFIGURATION.generate_merge.items():
def push(): execute('tx push -s')
If fail_if_missing is false, and the files to be merged are missing, just return silently. """ LOG.info('Merging {target} for locale {locale}'.format(target=target, locale=locale)) locale_directory = CONFIGURATION.get_messages_dir(locale) try: validate_files(locale_directory, sources) except Exception, e: if not fail_if_missing: return raise # merged file is merged.po merge_cmd = 'msgcat -o merged.po ' + ' '.join(sources) execute(merge_cmd, working_directory=locale_directory) # clean up redunancies in the metadata merged_filename = locale_directory.joinpath('merged.po') clean_pofile(merged_filename) # rename merged.po -> django.po (default) target_filename = locale_directory.joinpath(target) os.rename(merged_filename, target_filename) def merge_files(locale, fail_if_missing=True): """ Merge all the files in `locale`, as specified in config.yaml. """ for target, sources in CONFIGURATION.generate_merge.items():