diff --git a/packaging/univention-ucs-translation-template/base_makefile b/packaging/univention-ucs-translation-template/base_makefile new file mode 100644 index 0000000..47d531a --- /dev/null +++ b/packaging/univention-ucs-translation-template/base_makefile @@ -0,0 +1,49 @@ +#!/usr/bin/make -f +# -*- coding: utf-8 -*- +# +# Copyright 2016 Univention GmbH +# +# http://www.univention.de/ +# +# All rights reserved. +# +# The source code of this program is made available +# under the terms of the GNU Affero General Public License version 3 +# (GNU AGPL V3) as published by the Free Software Foundation. +# +# Binary versions of this program provided by Univention to you as +# well as other copyrighted, protected or trademarked materials like +# Logos, graphics, fonts, specific documentations and configurations, +# cryptographic keys etc. are subject to a license agreement between +# you and Univention and not subject to the GNU AGPL V3. +# +# In the case you use this program under the terms of the GNU AGPL V3, +# the program is provided in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public +# License with the Debian GNU/Linux or Univention distribution in file +# /usr/share/common-licenses/AGPL-3; if not, see +# . + +# This Makefile is copied to translation source packages generated by +# univention-ucs-translation-build-package. It defines the receipts to build +# binary translation targets(mo files). The include 'all_targets.mk' is +# generated by the same script and contains all actual targets. + +include all_targets.mk + +%.mo: + mkdir -p $(@D) + msgfmt --check --output-file="$@" "$<" + +%.json: + dh-umc-po2json "$<" # creates .json file in the same directory as the .po file + mkdir -p $(@D) + mv "$(patsubst %.po,%.json,$<)" "$@" + +build: + +install: $(ALL_TARGETS) diff --git a/packaging/univention-ucs-translation-template/debian/univention-ucs-translation-template.install b/packaging/univention-ucs-translation-template/debian/univention-ucs-translation-template.install index 1b1e420..ebc82ef 100644 --- a/packaging/univention-ucs-translation-template/debian/univention-ucs-translation-template.install +++ b/packaging/univention-ucs-translation-template/debian/univention-ucs-translation-template.install @@ -1,4 +1,6 @@ translationhelper.py usr/share/pyshared/univention specialcases.json usr/share/univention-ucs-translation-template -univention-ucs-translation-build-package.py usr/bin +base_makefile usr/share/univention-ucs-translation-template +univention-ucs-translation-merge usr/bin +univention-ucs-translation-build-package usr/bin univention-ucs-translation-fakemessage usr/bin diff --git a/packaging/univention-ucs-translation-template/test0.py b/packaging/univention-ucs-translation-template/test0.py new file mode 100755 index 0000000..c43122a --- /dev/null +++ b/packaging/univention-ucs-translation-template/test0.py @@ -0,0 +1,116 @@ +#!/usr/bin/env python +import os +import fnmatch +import random +import subprocess +import sys +import shutil +import polib +import logging +from pdb import set_trace as dbg + + +class InvalidCommandError(Exception): + pass + + +def _get_matching_file_paths(path, pattern): + """Recursively walk through path and match file paths with pattern, + return matches""" + matched_files_paths = list() + for dirname, dns, fnames in os.walk(path): + for fn in fnames: + matched_files_paths.append(os.path.join(dirname, fn)) + return fnmatch.filter(matched_files_paths, pattern) + + +def _call(*command_parts): + if not command_parts: + raise InvalidCommandError() + try: + subprocess.check_call([part for part in command_parts]) + except subprocess.CalledProcessError as exc: + print('Error: Subprocess exited unsuccessfully. Attempted command:') + print(' '.join(exc.cmd)) + raise InvalidCommandError() + except AttributeError as exc: + print('Command must be a string like object.') + raise InvalidCommandError() + except OSError as exc: + print('Error: {}'.format(exc.strerror)) + print('Error: failed to start subprocess.') + raise InvalidCommandError() + + +def _change_generated_fuzzy_entries(changed_entry, po_file_path): + po_file = polib.pofile(po_file_path) + found_change = False + for fuzzy in po_file.fuzzy_entries(): + if fuzzy.occurrences == changed_entry.occurrences: + found_change = True + else: + print('DBG: fuzzy entry not produced by test.') + sys.exit(1) + return found_change + + +def _remove_fuzzy_flags(po_file_path): + po_file = polib.pofile(po_file_path) + for fuzzy_entry in po_file.fuzzy_entries(): + fuzzy_entry.flags.remove('fuzzy') + po_file.save() + + +def _change_entry_in_source_file(module_path, po_entry): + for source_file, line_number in po_entry.occurrences: + source_file = os.path.join('svn_repo', module_path, source_file) + original_source_file = '{}.orig'.format(source_file) + os.rename(source_file, original_source_file) + with open(source_file, 'w') as changed_js: + with open(original_source_file, 'r') as fd: + for i, line in enumerate(fd): + if i == int(line_number) - 1: + logging.info('Changing {} in line {}'.format(source_file, line_number)) + line = line.replace(po_entry.msgid, 'TEST! {}'.format(po_entry.msgid)) + changed_js.write(line) + + +TRANSLATION_PKG_NAME = 'univention-ucs-translation-XX' +if __name__ == '__main__': + # _call('svn', 'checkout', 'http://forge.univention.org/svn/dev/branches/ucs-4.1/ucs-4.1-1/management/univention-management-console-module-passwordchange/', 'svn_repo') + try: + shutil.rmtree('svn_repo') + shutil.rmtree(TRANSLATION_PKG_NAME) + except Exception: + pass + + try: + _call('svn', 'checkout', 'http://forge.univention.org/svn/dev/branches/ucs-4.1/ucs-4.1-1/management/univention-management-console-module-passwordchange/', 'svn_repo/management/univention-management-console-module-passwordchange') + _call('univention-ucs-translation-build-package', '--source=svn_repo', '--languagecode=XX', '--locale=fr_FR.UTF-8:UTF-8', '--languagename=TEST0') + _call('univention-ucs-translation-fakemessage', TRANSLATION_PKG_NAME) + except InvalidCommandError: + print('Error: Tried to launch invalid command. Exiting.') + sys.exit(1) + + # Choose js files to manipulate + js_po_files = _get_matching_file_paths(TRANSLATION_PKG_NAME, '*umc*js*.po') + choosen_po_path = random.choice(js_po_files) + module_path = '/'.join(choosen_po_path.split('/')[2:4]) + choosen_po = polib.pofile(choosen_po_path) + random_entry = random.choice(choosen_po) + + _change_entry_in_source_file(module_path, random_entry) + _call('univention-ucs-translation-merge', 'XX', 'svn_repo', TRANSLATION_PKG_NAME) + + if _change_generated_fuzzy_entries(random_entry, choosen_po_path): + print('Test: Success: fuzzy entries found!') + else: + print('FAILED: There should be fuzzy entries for this change.') + + _remove_fuzzy_flags(choosen_po_path) + _call('svn', 'revert', '--recursive', 'svn_repo/management/univention-management-console-module-passwordchange') + _call('univention-ucs-translation-merge', 'XX', 'svn_repo', TRANSLATION_PKG_NAME) + + _remove_fuzzy_flags(choosen_po_path) + # Should be same as build + fakemassage + # TODO: Test for this.. diff --git a/packaging/univention-ucs-translation-template/translationhelper.py b/packaging/univention-ucs-translation-template/translationhelper.py index 9cbb9e8..1728f6a 100644 --- a/packaging/univention-ucs-translation-template/translationhelper.py +++ b/packaging/univention-ucs-translation-template/translationhelper.py @@ -44,26 +44,6 @@ MODULE_BLACKLIST = [ '0001-6-7' ] -MAKEFILE_HEADER = """#!/usr/bin/make -f - -%.mo: - mkdir -p $(@D) - msgfmt --check --output-file="$@" "$<" - -%.json: - #python -c "import univention.dh_umc as dhumc; dhumc.create_json_file('$<')" - dh-umc-po2json "$<" # creates .json file in the same directory as the .po file - mkdir -p $(@D) - mv "$(patsubst %.po,%.json,$<)" "$@" - #install -D $($<:.po=.json) "$@" - -""" - -MAKEFILE_END = """build: - -install: $(ALL_TARGETS) -""" - class UMCModuleTranslation(dh_umc.UMC_Module): def __init__(self, attrs, target_language): @@ -96,7 +76,7 @@ class UMCModuleTranslation(dh_umc.UMC_Module): try: module = UMCModuleTranslation._get_core_module_from_source_package(module_in_source_tree, target_language) except AttributeError as e: - print "%s core module load failed" % str(e) + print("%s core module load failed" % str(e)) # TODO: Module not loaded at all --> exception? else: print("Successfully loaded as core module: {}".format(module_in_source_tree.get('abs_path_to_src_pkg'))) @@ -134,7 +114,8 @@ class UMCModuleTranslation(dh_umc.UMC_Module): attrs['relative_path_src_pkg'] = module.get('relative_path_src_pkg') return UMCModuleTranslation(attrs, target_language) -#TODO: actually.. (module, output_dir) + +# TODO: actually.. (module, output_dir) def update_package_translation_files(module, output_dir): print("Creating directories and PO files for {module_name} in translation source package".format(**module)) start_dir = os.getcwd() @@ -154,7 +135,7 @@ def update_package_translation_files(module, output_dir): try: dh_umc.create_po_file(new_po_file_abs_path, module['module_name'], src_files) except dh_umc.Error as exc: - print str(exc) + print(str(exc)) # build python po files _create_po_files(module.python_po_files, module.python_files) @@ -168,11 +149,11 @@ def update_package_translation_files(module, output_dir): try: dh_umc.module_xml2po(module, po_file_full_path, lang) except dh_umc.Error as exc: - print str(exc) + print(str(exc)) except OSError as exc: - print traceback.format_exc() - print "error in update_package_translation_files: %s" % (exc,) + print(traceback.format_exc()) + print("error in update_package_translation_files: %s" % (exc,)) finally: os.chdir(start_dir) return abs_path_translated_src_pkg @@ -195,12 +176,11 @@ def write_makefile(all_modules, special_cases, new_package_dir, target_language) for scase in special_cases: _append_to_target_lists(scase.get('mo_destination'), '{lang}/{po_subdir}/{lang}.po'.format(lang=target_language, **scase)) - with open(os.path.join(new_package_dir, 'Makefile'), 'w') as fd: - fd.writelines(MAKEFILE_HEADER) + with open(os.path.join(new_package_dir, 'all_targets.mk'), 'w') as fd: + fd.write("# This file is auto-generated by univention-ucs-translation-build-package and should not be edited!\n\n") fd.write('ALL_TARGETS = {}\n\n'.format(' \\\n\t'.join(mo_targets_list))) fd.write('\n'.join(target_prerequisite)) fd.write('\n') - fd.writelines(MAKEFILE_END) # special case e.g. univention-management-modules-frontend: translation files are built with a makefile @@ -212,7 +192,7 @@ def translate_special_case(special_case, source_dir, target_language, output_dir # TODO: Checks whether a special case is valid should be done on special case parsing path_src_pkg = os.path.join(source_dir, special_case.get('package_dir')) if not os.path.isdir(path_src_pkg): - # TODO: Exception + # TODO: Exception return new_po_path = os.path.join(output_dir, special_case.get('po_subdir')) @@ -229,17 +209,22 @@ def translate_special_case(special_case, source_dir, target_language, output_dir if not matches: # TODO: Exception print('Error: specialcase for {} didn\'t match any files.'.format(special_case.get('package_dir'))) + # FIXME: create_po should handle path itself? + cwd = os.getcwd() + os.chdir(path_src_pkg) try: + matches = [os.path.relpath(match, start=os.getcwd()) for match in matches] dh_umc.create_po_file(new_po_path, special_case.get('package_name'), matches) except dh_umc.Error as exc: repr(exc) except TypeError as exc: repr(exc) + os.chdir(cwd) def find_base_translation_modules(startdir, source_dir, module_basefile_name): - print 'looking in %s' % source_dir - print 'looking for files matching %s' % module_basefile_name + print('looking in %s' % source_dir) + print('looking for files matching %s' % module_basefile_name) os.chdir(source_dir) matches = [] for root, dirnames, filenames in os.walk('.'): @@ -250,18 +235,18 @@ def find_base_translation_modules(startdir, source_dir, module_basefile_name): regex = re.compile(".*/(.*)/debian/.*%s$" % re.escape(module_basefile_name)) for match in matches: - print match + print(match) packagenameresult = regex.search(match) if packagenameresult: packagename = packagenameresult.group(1) modulename = os.path.basename(match.replace(module_basefile_name, '')) if modulename in MODULE_BLACKLIST: - print "Ignoring module %s: Module is blacklisted\n" % modulename + print("Ignoring module %s: Module is blacklisted\n" % modulename) continue package_dir = os.path.dirname(os.path.dirname(match)) - print "Found package: %s" % package_dir + print("Found package: %s" % package_dir) module = {} module['module_name'] = modulename module['binary_package_name'] = packagename @@ -269,7 +254,7 @@ def find_base_translation_modules(startdir, source_dir, module_basefile_name): module['relative_path_src_pkg'] = os.path.relpath(package_dir) base_translation_modules.append(module) else: - print "could not obtain packagename from directory %s" % match + print("could not obtain packagename from directory %s" % match) os.chdir(startdir) return base_translation_modules @@ -278,7 +263,7 @@ def find_base_translation_modules(startdir, source_dir, module_basefile_name): def create_new_package(new_package_dir, target_language, target_locale, language_name, startdir): new_package_dir_debian = os.path.join(new_package_dir, 'debian') if not os.path.exists(new_package_dir_debian): - print "creating directory: %s" % new_package_dir_debian + print("creating directory: %s" % new_package_dir_debian) os.makedirs(new_package_dir_debian) translation_package_name = "univention-ucs-translation-%s" % target_language @@ -409,7 +394,8 @@ usr/share/univention-management-console/i18n/%(lang)s usr/share/locale/%(lang)s/LC_MESSAGES """ % language_dict) - ### Move source files and installed .mo files to new package dir + shutil.copyfile('/usr/share/univention-ucs-translation-template/base_makefile', os.path.join(new_package_dir, 'Makefile')) + # Move source files and installed .mo files to new package dir if os.path.exists(os.path.join(new_package_dir, 'usr')): shutil.rmtree(os.path.join(new_package_dir, 'usr')) #shutil.copytree(os.path.join(startdir, 'usr'), os.path.join(new_package_dir, 'usr')) @@ -419,4 +405,3 @@ usr/share/locale/%(lang)s/LC_MESSAGES shutil.rmtree(os.path.join(new_package_dir, target_language)) shutil.copytree(os.path.join(startdir, target_language), os.path.join(new_package_dir, target_language)) shutil.rmtree(os.path.join(startdir, target_language)) - diff --git a/packaging/univention-ucs-translation-template/univention-ucs-translation-build-package b/packaging/univention-ucs-translation-template/univention-ucs-translation-build-package new file mode 100755 index 0000000..957295c --- /dev/null +++ b/packaging/univention-ucs-translation-template/univention-ucs-translation-build-package @@ -0,0 +1,93 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +# Copyright 2013-2014 Univention GmbH +# +# http://www.univention.de/ +# +# All rights reserved. +# +# The source code of this program is made available +# under the terms of the GNU Affero General Public License version 3 +# (GNU AGPL V3) as published by the Free Software Foundation. +# +# Binary versions of this program provided by Univention to you as +# well as other copyrighted, protected or trademarked materials like +# Logos, graphics, fonts, specific documentations and configurations, +# cryptographic keys etc. are subject to a license agreement between +# you and Univention and not subject to the GNU AGPL V3. +# +# In the case you use this program under the terms of the GNU AGPL V3, +# the program is provided in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public +# License with the Debian GNU/Linux or Univention distribution in file +# /usr/share/common-licenses/AGPL-3; if not, see +# . + +from optparse import OptionParser + +import os +import json +import univention.dh_umc as dh_umc +import univention.translationhelper as tlh + + +SPECIALCASES_PATH = "/usr/share/univention-ucs-translation-template/specialcases.json" + + +if __name__ == '__main__': + usage = '''%prog [options] -s source_dir -c language_code -l locale -n language_name +e.g.: -s /path/to/ucs-repository/ -c de -l de_DE.UTF-8:UTF-8 -n Deutsch''' + parser = OptionParser(usage=usage) + parser.add_option('-s', '--source', action='store', dest='source_dir', help='UCS source dir from which translation files are gathered, e.g. an UCS svn base dir') + parser.add_option('-c', '--languagecode', action='store', dest='target_language', help='Target language code (e.g. de)') + parser.add_option('-b', '--basefiles', action='store', dest='basefiles', default='.umc-modules', help='xml file basename (default: .umc-modules)') + parser.add_option('-l', '--locale', action='store', dest='target_locale', help='Target locale (e.g. de_DE.UTF-8:UTF-8)') + parser.add_option('-n', '--languagename', action='store', dest='target_name', help='Language name that is shown in the UMC (e.g. Deutsch)') + + (options, args) = parser.parse_args() + help_message = 'Use --help to show additional help.' + + if not options.source_dir: + parser.error('Missing argument -s. %s' % help_message) + + if not options.target_language: + parser.error('Missing argument -c. %s' % help_message) + + if not options.target_locale: + parser.error('Missing argument -l. %s' % help_message) + + if not options.target_name: + parser.error('Missing argument -n. %s' % help_message) + + options.source_dir = os.path.abspath(options.source_dir) + # find all module files and move them to a language specific directory + startdir = os.getcwd() + base_translation_modules = tlh.find_base_translation_modules(startdir, options.source_dir, options.basefiles) + dh_umc.LANGUAGES = (options.target_language, ) + all_modules = list() + output_dir = os.path.join(os.getcwd(), options.target_language) + for module_attrs in base_translation_modules: + module = tlh.UMCModuleTranslation.from_source_package(module_attrs, options.target_language) + all_modules.append(module) + abs_path_translated_src_pkg = tlh.update_package_translation_files(module, output_dir) + + # special cases, e.g. univention-management-console-frontend + special_cases = [] + if os.path.exists(SPECIALCASES_PATH): + with open(SPECIALCASES_PATH, 'rb') as fd: + special_cases = json.load(fd) + else: + print("Error: Could not find file {}. Several files will not be handled.".format(SPECIALCASES_PATH)) + + for s_case in special_cases: + tlh.translate_special_case(s_case, options.source_dir, options.target_language, output_dir) + + # create new package + new_package_dir = os.path.join(startdir, 'univention-ucs-translation-%s' % options.target_language) + tlh.create_new_package(new_package_dir, options.target_language, options.target_locale, options.target_name, startdir) + tlh.write_makefile(all_modules, special_cases, new_package_dir, options.target_language) diff --git a/packaging/univention-ucs-translation-template/univention-ucs-translation-build-package.py b/packaging/univention-ucs-translation-template/univention-ucs-translation-build-package.py deleted file mode 100755 index 9e0de51..0000000 --- a/packaging/univention-ucs-translation-template/univention-ucs-translation-build-package.py +++ /dev/null @@ -1,93 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -# -# Copyright 2013-2014 Univention GmbH -# -# http://www.univention.de/ -# -# All rights reserved. -# -# The source code of this program is made available -# under the terms of the GNU Affero General Public License version 3 -# (GNU AGPL V3) as published by the Free Software Foundation. -# -# Binary versions of this program provided by Univention to you as -# well as other copyrighted, protected or trademarked materials like -# Logos, graphics, fonts, specific documentations and configurations, -# cryptographic keys etc. are subject to a license agreement between -# you and Univention and not subject to the GNU AGPL V3. -# -# In the case you use this program under the terms of the GNU AGPL V3, -# the program is provided in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU Affero General Public License for more details. -# -# You should have received a copy of the GNU Affero General Public -# License with the Debian GNU/Linux or Univention distribution in file -# /usr/share/common-licenses/AGPL-3; if not, see -# . - -from optparse import OptionParser - -import os -import json -import univention.dh_umc as dh_umc -import univention.translationhelper as tlh - - -SPECIALCASES_PATH = "/usr/share/univention-ucs-translation-template/specialcases.json" - - -if __name__ == '__main__': - usage = '''%prog [options] -s source_dir -c language_code -l locale -n language_name -e.g.: -s /path/to/ucs-repository/ -c de -l de_DE.UTF-8:UTF-8 -n Deutsch''' - parser = OptionParser(usage=usage) - parser.add_option('-s', '--source', action='store', dest='source_dir', help='UCS source dir from which translation files are gathered, e.g. an UCS svn base dir') - parser.add_option('-c', '--languagecode', action='store', dest='target_language', help='Target language code (e.g. de)') - parser.add_option('-b', '--basefiles', action='store', dest='basefiles', default='.umc-modules', help='xml file basename (default: .umc-modules)') - parser.add_option('-l', '--locale', action='store', dest='target_locale', help='Target locale (e.g. de_DE.UTF-8:UTF-8)') - parser.add_option('-n', '--languagename', action='store', dest='target_name', help='Language name that is shown in the UMC (e.g. Deutsch)') - - (options, args) = parser.parse_args() - help_message = 'Use --help to show additional help.' - - if not options.source_dir: - parser.error('Missing argument -s. %s' % help_message) - - if not options.target_language: - parser.error('Missing argument -c. %s' % help_message) - - if not options.target_locale: - parser.error('Missing argument -l. %s' % help_message) - - if not options.target_name: - parser.error('Missing argument -n. %s' % help_message) - - options.source_dir = os.path.abspath(options.source_dir) - # find all module files and move them to a language specific directory - startdir = os.getcwd() - base_translation_modules = tlh.find_base_translation_modules(startdir, options.source_dir, options.basefiles) - dh_umc.LANGUAGES = (options.target_language, ) - all_modules = list() - output_dir = os.path.join(os.getcwd(), options.target_language) - for module_attrs in base_translation_modules: - module = tlh.UMCModuleTranslation.from_source_package(module_attrs, options.target_language) - all_modules.append(module) - abs_path_translated_src_pkg = tlh.update_package_translation_files(module, output_dir) - - # special cases, e.g. univention-management-console-frontend - special_cases = [] - if os.path.exists(SPECIALCASES_PATH): - with open(SPECIALCASES_PATH, 'rb') as fd: - special_cases = json.load(fd) - else: - print "Error: Could not find file %s. Several files will not be handled." % SPECIALCASES_PATH - - for s_case in special_cases: - tlh.translate_special_case(s_case, options.source_dir, options.target_language, output_dir) - - # create new package - new_package_dir = os.path.join(startdir, 'univention-ucs-translation-%s' % options.target_language) - tlh.create_new_package(new_package_dir, options.target_language, options.target_locale, options.target_name, startdir) - tlh.write_makefile(all_modules, special_cases, new_package_dir, options.target_language) diff --git a/packaging/univention-ucs-translation-template/univention-ucs-translation-fakemessage b/packaging/univention-ucs-translation-template/univention-ucs-translation-fakemessage index f6405c9..d074aa0 100755 --- a/packaging/univention-ucs-translation-template/univention-ucs-translation-fakemessage +++ b/packaging/univention-ucs-translation-template/univention-ucs-translation-fakemessage @@ -37,15 +37,16 @@ USAGE = """ Usage: univention-ucs-translation-fakemessage [directory] This script walks over all po files in a given directory and its subfolders. -It fills all msgid strings to the corresponding msgid and prepeding it with a -character sequence '!TR!'. +It fills all msgid strings with the same content as the corresponding msgid, +prepeding it with the character sequence '!TR!'. It is useful for visual quick testing of translation coverage and po file generation. """ + def main(po_dir): for _dir, dns, fns in os.walk(os.path.abspath(po_dir)): - for po_file in fnmatch.filter(fns, '*po'): + for po_file in fnmatch.filter(fns, '*.po'): po = polib.pofile(os.path.join(_dir, po_file)) for entry in po: if entry.msgid == '': diff --git a/packaging/univention-ucs-translation-template/univention-ucs-translation-merge b/packaging/univention-ucs-translation-template/univention-ucs-translation-merge index 0b93217..e5a8aa9 100755 --- a/packaging/univention-ucs-translation-template/univention-ucs-translation-merge +++ b/packaging/univention-ucs-translation-template/univention-ucs-translation-merge @@ -29,12 +29,14 @@ # . import argparse import fnmatch -import polib import os import sys +import shutil import univention.translationhelper as tlh import univention.dh_umc as dh_umc import json +import subprocess +from pdb import set_trace as dbg SPECIALCASES_PATH = "/usr/share/univention-ucs-translation-template/specialcases.json" @@ -50,6 +52,17 @@ def _get_po_files_from_dir(directory, return_relative_path=False): return po_files +def _msgmerge(source, destination): + try: + subprocess.check_call(['msgmerge', '--update', '--sort-output', destination, source]) + except TypeError: + print('Error: arguments must be names of existing files. Exiting.') + sys.exit(1) + except subprocess.CalledProcessError: + print('Error: PO file merge failed. Exiting.') + sys.exit(1) + + def merge_po_file_trees(source_tree, target_tree): upstream_pos = _get_po_files_from_dir(source_tree, return_relative_path=True) translated_pos = _get_po_files_from_dir(target_tree, return_relative_path=True) @@ -62,16 +75,18 @@ def merge_po_file_trees(source_tree, target_tree): # add new for new_po in new_pos: new_po_path = os.path.join(target_tree, new_po) - os.makedirs(os.path.dirname(new_po_path)) + try: + os.makedirs(os.path.dirname(new_po_path)) + except OSError as exc: + if not exc.errno == 17: + raise + pass os.rename(os.path.join(source_tree, new_po), new_po_path) + upstream_pos.remove(new_po) # merge upstream changes... - for dir, dirs, files in os.walk(target_tree): - for po_file in fnmatch.filter([os.path.join(dir, fn) for fn in files], '*.po'): - translated = polib.pofile(po_file) - upstream = polib.pofile(po_file.replace(target_tree, source_tree)) - translated.merge(upstream) - translated.save() - + for po_file in upstream_pos: + _msgmerge(os.path.join(source_tree, po_file), os.path.join(target_tree, po_file)) + return pos_delete_upstream, new_pos if __name__ == '__main__': parser = argparse.ArgumentParser(description="Merge upstream changes in translation files to existing translation source package.") @@ -91,8 +106,10 @@ if __name__ == '__main__': dh_umc.LANGUAGES = (args.lang_code, ) modules_upstream = tlh.find_base_translation_modules(os.getcwd(), args.upstream, '.umc-modules') output_dir = os.path.join(args.translation, '{}_merge'.format(args.lang_code)) + modules = list() for module_attrs in modules_upstream: module = tlh.UMCModuleTranslation.from_source_package(module_attrs, args.lang_code) + modules.append(module) tlh.update_package_translation_files(module, output_dir) # special cases, e.g. univention-management-console-frontend special_cases = [] @@ -100,9 +117,18 @@ if __name__ == '__main__': with open(SPECIALCASES_PATH, 'rb') as fd: special_cases = json.load(fd) else: - print "Error: Could not find file %s. Several files will not be handled." % SPECIALCASES_PATH + print("Error: Could not find file {}.\nSeveral files will not be handled.".format(SPECIALCASES_PATH)) for scase in special_cases: tlh.translate_special_case(scase, args.upstream, args.lang_code, output_dir) - merge_po_file_trees(output_dir, os.path.join(args.translation, args.lang_code)) + removed, new = merge_po_file_trees(output_dir, os.path.join(args.translation, args.lang_code)) + print('Merge summary: ') + if removed: + print('Following files have been removed:') + print('\n'.join(removed)) + if new: + print('Following files habe been added:') + print('\n'.join(new)) + shutil.rmtree(output_dir) + tlh.write_makefile(modules, special_cases, args.translation, args.lang_code)