From: <hug...@li...> - 2013-04-20 10:20:12
|
branch: details: http://hugin.hg.sourceforge.net/hgweb/hugin/hugin/hgroot/hugin/hugin/rev/564a9d870fb8 changeset: 6264:564a9d870fb8 user: Kornel Benko <kor...@us...> date: Sat Apr 20 12:19:39 2013 +0200 description: New option "REBUILD_TRANSLATIONS" for cmake-build. Provided that the needed programs (python, xgettext, msgmerge, msguniq) are avaliable, compilation of hugin now creates also the newest hugin.pot-template and the derived po-files in the build-directory. This patch is developped in collaboration with Thomas Modes diffstat: CMakeLists.txt | 5 - CMakeModules/FindMSGFMT.cmake | 51 +++++------ src/translations/CMakeLists.txt | 154 +++++++++++++++++++++++++++++++++++- src/translations/xrc_correct.py | 41 +++++++++ src/translations/xrc_pot.py | 169 ++++++++++++++++++++++++++++++++++++++++ 5 files changed, 385 insertions(+), 35 deletions(-) Unterschiede (458 Zeilen): diff -r 1ef490fcda32 -r 564a9d870fb8 CMakeLists.txt --- a/CMakeLists.txt Wed Apr 17 19:36:40 2013 +0200 +++ b/CMakeLists.txt Sat Apr 20 12:19:39 2013 +0200 @@ -281,11 +281,6 @@ INCLUDE_DIRECTORIES(${Boost_INCLUDE_DIRS}) LINK_DIRECTORIES(${Boost_LIBRARY_DIRS}) -FIND_PACKAGE(MSGFMT REQUIRED) -IF(MSGFMT_FOUND) - MESSAGE(STATUS "Program msgfmt found (${MSGFMT_EXECUTABLE})") -ENDIF(MSGFMT_FOUND) - FIND_PACKAGE(Threads) FIND_PACKAGE(ZThread) FIND_PACKAGE(flann) diff -r 1ef490fcda32 -r 564a9d870fb8 CMakeModules/FindMSGFMT.cmake --- a/CMakeModules/FindMSGFMT.cmake Wed Apr 17 19:36:40 2013 +0200 +++ b/CMakeModules/FindMSGFMT.cmake Sat Apr 20 12:19:39 2013 +0200 @@ -18,37 +18,34 @@ IF(MSGFMT_EXECUTABLE) SET(MSGFMT_FOUND TRUE) -ELSE(MSGFMT_EXECUTABLE) +ELSE() FIND_PROGRAM(MSGFMT_EXECUTABLE - NAMES msgfmt gmsgfmt msgfmt.exe - PATHS /bin /usr/bin /usr/local/bin c:/MinGW/bin ${SOURCE_BASE_DIR}/gettext/bin) - IF(MSGFMT_EXECUTABLE) - SET(MSGFMT_FOUND TRUE) - ELSE(MSGFMT_EXECUTABLE) - IF(NOT MSGFMT_FIND_QUIETLY) - IF(MSGFMT_FIND_REQUIRED) - MESSAGE(FATAL_ERROR "msgfmt program couldn't be found") - ENDIF(MSGFMT_FIND_REQUIRED) - ENDIF(NOT MSGFMT_FIND_QUIETLY) - ENDIF(MSGFMT_EXECUTABLE) - MARK_AS_ADVANCED(MSGFMT_EXECUTABLE) -ENDIF (MSGFMT_EXECUTABLE) + NAMES msgfmt gmsgfmt msgfmt.exe + PATHS /bin /usr/bin /usr/local/bin c:/MinGW/bin ${SOURCE_BASE_DIR}/gettext/bin) +ENDIF() -MACRO(ADD_TRANSLATIONS _baseName) +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(MSGFMT + DEFAULT_MSG MSGFMT_EXECUTABLE) + +MARK_AS_ADVANCED(MSGFMT_EXECUTABLE) + +MACRO(ADD_TRANSLATIONS _potfile) SET(_outputs) + get_filename_component(_baseName ${_potfile} NAME_WE) FOREACH(_file ${ARGN}) - GET_FILENAME_COMPONENT(_file_we ${_file} NAME_WE) - SET(_out "${CMAKE_CURRENT_BINARY_DIR}/${_file_we}.gmo") - SET(_in "${CMAKE_CURRENT_SOURCE_DIR}/${_file_we}.po") - ADD_CUSTOM_COMMAND( - OUTPUT ${_out} - COMMAND ${MSGFMT_EXECUTABLE} -o ${_out} ${_in} - DEPENDS ${_in} ) - INSTALL(FILES ${_out} - DESTINATION ${LOCALEDIR}/${_file_we}/LC_MESSAGES/ - RENAME ${_baseName}.mo ) - SET(_outputs ${_outputs} ${_out}) + GET_FILENAME_COMPONENT(_file_we ${_file} NAME_WE) + SET(_out "${CMAKE_CURRENT_BINARY_DIR}/${_file_we}.gmo") + SET(_in ${_file}) + ADD_CUSTOM_COMMAND( + OUTPUT ${_out} + COMMAND ${MSGFMT_EXECUTABLE} -o ${_out} ${_in} + DEPENDS ${_in} ) + INSTALL(FILES ${_out} + DESTINATION ${LOCALEDIR}/${_file_we}/LC_MESSAGES/ + RENAME ${_baseName}.mo ) + list(APPEND _outputs ${_out}) ENDFOREACH(_file) - SET(MSGFMT_TARGET translations${_baseName}) + SET(MSGFMT_TARGET translations) ADD_CUSTOM_TARGET(${MSGFMT_TARGET} ALL DEPENDS ${_outputs}) ENDMACRO(ADD_TRANSLATIONS) diff -r 1ef490fcda32 -r 564a9d870fb8 src/translations/CMakeLists.txt --- a/src/translations/CMakeLists.txt Wed Apr 17 19:36:40 2013 +0200 +++ b/src/translations/CMakeLists.txt Sat Apr 20 12:19:39 2013 +0200 @@ -1,5 +1,153 @@ +# This file is part of hugin, a GUI for the panorama tools suite +# Licence details can be found in the file COPYING. +# +# Copyright (c) 2013 Kornel Benko, <Kor...@be...> +# -# automatically include all po files in the directory -FILE(GLOB PO_FILES *.po) +OPTION(REBUILD_TRANSLATIONS "Build hugin.pot and <lang>.po files inside the build dir" OFF) -ADD_TRANSLATIONS(hugin ${PO_FILES}) +find_package(MSGFMT QUIET REQUIRED) + +# Check for needed programms python2, wxrc, xgettext, msgmerge, msguniq +if(REBUILD_TRANSLATIONS) + # Check for needed python version 2 + set(prg_err_msg) + find_package(PythonInterp) + if (NOT PYTHONINTERP_FOUND) + set(prg_err_msg "No python interpreter found") + endif() + + if(NOT prg_err_msg) + find_program(XGETTEXT_EXECUTABLE + NAMES xgettext + PATHS /bin /usr/bin /usr/local/bin c:/MinGW/bin ${SOURCE_BASE_DIR}/gettext/bin) + if(NOT XGETTEXT_EXECUTABLE) + set(prg_err_msg "xgettext not found") + endif() + endif() + + if(NOT prg_err_msg) + find_program(MSGMERGE_EXECUTABLE + NAMES msgmerge gmsgmerge msgmerge.exe + PATHS /bin /usr/bin /usr/local/bin c:/MinGW/bin ${SOURCE_BASE_DIR}/gettext/bin) + if(NOT MSGMERGE_EXECUTABLE) + set(prg_err_msg "msgmerge not found") + endif() + endif() + + if(NOT prg_err_msg) + find_program(MSGUNIQ_EXECUTABLE + NAMES msguniq gmsguniq msguniq.exe + PATHS /bin /usr/bin /usr/local/bin c:/MinGW/bin ${SOURCE_BASE_DIR}/gettext/bin) + if(NOT MSGUNIQ_EXECUTABLE) + set(prg_err_msg "msguniq not found") + endif() + endif() + + if(prg_err_msg) + message(STATUS ${prg_err_msg} ", disabling REBUILD_TRANSLATIONS") + set(REBUILD_TRANSLATIONS OFF) + else() + message(STATUS "Needed programs for REBUILD_TRANSLATIONS found") + endif() +endif() + +if(REBUILD_TRANSLATIONS) + + # create updated template hugin.pot and remerged po-files + # in the build-directory + + # This part should do the same, as extract-messages.sh + set(BUGADDR "https://bugs.launchpad.net/hugin/") + set(COPYRIGHT "Pablo dAngelo") + # create xrc.cpp + # Preparing rc files + file(GLOB_RECURSE xrc_files RELATIVE "${CMAKE_SOURCE_DIR}/src" "${CMAKE_SOURCE_DIR}/src/*.xrc") + list(SORT xrc_files) + + # creating infiles.list + file(GLOB_RECURSE _infiles RELATIVE "${CMAKE_SOURCE_DIR}/src" + "${CMAKE_SOURCE_DIR}/src/*.cpp" + "${CMAKE_SOURCE_DIR}/src/*.h" + "${CMAKE_SOURCE_DIR}/src/*.c") +# list(APPEND _infiles "translations/xrc.cpp") + list(REMOVE_ITEM _infiles "translations/xrc.cpp") + list(REMOVE_DUPLICATES _infiles) + list(SORT _infiles) + + # create infiles.list, containing the list of input source files + file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/infiles.tmp") + set(infiles_depend) + foreach(_f ${_infiles}) + if(NOT _f STREQUAL "translations/xrc.cpp") + list(APPEND infiles_depend "${CMAKE_SOURCE_DIR}/src/${_f}") + endif() + file(APPEND "${CMAKE_CURRENT_BINARY_DIR}/infiles.tmp" "./${_f}\n") + endforeach() + file(STRINGS "${CMAKE_CURRENT_SOURCE_DIR}/POTFILES.in" POTFILE) + foreach(_p ${POTFILE}) + list(APPEND infiles_depend "${CMAKE_SOURCE_DIR}/src/${_p}") + file(APPEND "${CMAKE_CURRENT_BINARY_DIR}/infiles.tmp" "${_p}\n") + endforeach() + execute_process(COMMAND ${CMAKE_COMMAND} -E copy_if_different "${CMAKE_CURRENT_BINARY_DIR}/infiles.tmp" "${CMAKE_CURRENT_BINARY_DIR}/infiles.list") + + # create in_xrc_files.list, containing the list of searched xrc source files + file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/in_xrc_files.tmp") + foreach(_f ${xrc_files}) + set(_fabs "${CMAKE_SOURCE_DIR}/src/${_f}") + list(APPEND inxrcdepend ${_fabs}) + file(APPEND "${CMAKE_CURRENT_BINARY_DIR}/in_xrc_files.tmp" "${_fabs}\n") + endforeach() + execute_process(COMMAND ${CMAKE_COMMAND} -E copy_if_different + "${CMAKE_CURRENT_BINARY_DIR}/in_xrc_files.tmp" "${CMAKE_CURRENT_BINARY_DIR}/in_xrc_files.list") + + # now create the hugintmp.pot file, with possible duplicated entries + add_custom_command(OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/hugintmp.pot" + COMMAND ${XGETTEXT_EXECUTABLE} --from-code=UTF-8 -C -k_ --copyright-holder=${COPYRIGHT} + --msgid-bugs-address="${BUGADDR}" + --files-from="${CMAKE_CURRENT_BINARY_DIR}/infiles.list" + -D "${CMAKE_SOURCE_DIR}/src" + -o "${CMAKE_CURRENT_BINARY_DIR}/hugintmp1.pot" + COMMAND ${PYTHON_EXECUTABLE} "${CMAKE_CURRENT_SOURCE_DIR}/xrc_pot.py" + -o "${CMAKE_CURRENT_BINARY_DIR}/hugintmp1.pot" + -b "${CMAKE_SOURCE_DIR}/src" + -t xrc -s "${CMAKE_CURRENT_BINARY_DIR}/in_xrc_files.list" + COMMAND ${PYTHON_EXECUTABLE} "${CMAKE_CURRENT_SOURCE_DIR}/xrc_correct.py" + -o "${CMAKE_CURRENT_BINARY_DIR}/hugintmp.pot" + "${CMAKE_CURRENT_BINARY_DIR}/hugintmp1.pot" + WORKING_DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}" + DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/infiles.list" + "${CMAKE_CURRENT_BINARY_DIR}/in_xrc_files.list" + "${CMAKE_CURRENT_SOURCE_DIR}/xrc_pot.py" + ${infiles_depend}) + + # Last step in creating hugin.pot + # concatenate duplicated entries and correct some non-ascii not handled by msguniq + add_custom_command(OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/hugin.pot" + COMMAND ${MSGUNIQ_EXECUTABLE} -o "${CMAKE_CURRENT_BINARY_DIR}/hugin.pot" + "${CMAKE_CURRENT_BINARY_DIR}/hugintmp.pot" + DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/hugintmp.pot" + "${CMAKE_CURRENT_SOURCE_DIR}/xrc_correct.py") + + #now get the po-files + file(GLOB pofiles RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/*.po") + set(PO_FILES) + foreach(_po ${pofiles}) + list(APPEND PO_FILES "${CMAKE_CURRENT_BINARY_DIR}/${_po}") + add_custom_command(OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/${_po}" + COMMAND ${MSGMERGE_EXECUTABLE} --verbose -o "${CMAKE_CURRENT_BINARY_DIR}/${_po}" + "${CMAKE_CURRENT_SOURCE_DIR}/${_po}" "${CMAKE_CURRENT_BINARY_DIR}/hugin.pot" + DEPENDS "${CMAKE_CURRENT_SOURCE_DIR}/${_po}" "${CMAKE_CURRENT_BINARY_DIR}/hugin.pot" + COMMENT "${MSGMERGE_EXECUTABLE} --verbose -o ${CMAKE_CURRENT_BINARY_DIR}/${_po} ${CMAKE_CURRENT_SOURCE_DIR}/${_po} ${CMAKE_CURRENT_BINARY_DIR}/hugin.pot" + ) + endforeach() + + ADD_TRANSLATIONS("${CMAKE_CURRENT_BINARY_DIR}/hugin.pot" ${PO_FILES}) + +else() + # simply use all po files and hugin.pot from the source directory + FILE(GLOB PO_FILES "${CMAKE_CURRENT_SOURCE_DIR}/*.po") + + ADD_TRANSLATIONS("${CMAKE_CURRENT_SOURCE_DIR}/hugin.pot" ${PO_FILES}) +endif() + diff -r 1ef490fcda32 -r 564a9d870fb8 src/translations/xrc_correct.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/translations/xrc_correct.py Sat Apr 20 12:19:39 2013 +0200 @@ -0,0 +1,41 @@ +#! /usr/bin/env python +# -*- coding: iso-8859-15 -*- + +import sys, re +import codecs +from getopt import getopt + +usage = ''' +python xrc_correct.py [-o OUTFILE] FILE + +Change charset of given po-template to UTF-8 + +If the -o argument is not given, writes to stdout. +''' + +outfile = "" + +(options, args) = getopt(sys.argv[1:], "ho:") +for (opt, param) in options: + if opt == "-o": + outfile = param + elif opt == "-h": + sys.stdout.write(usage + "\n") + sys.exit(0) + +charset_pat = re.compile(r'^"(Content-Type:\s+text/plain;\s+charset=)CHARSET\\n"[\r\n]*$',re.IGNORECASE) +if outfile: + out = codecs.open(outfile, "w", 'utf-8') +else: + out = sys.stdout +for f in args: + fil = codecs.open(f, "r", 'utf-8') + for l in fil: + if charset_pat.match(l): + (string,) = charset_pat.match(l).groups() + l = "\"" + string + "UTF-8\\n\"\n" + out.write(l) + fil.close() + +if outfile: + out.close() diff -r 1ef490fcda32 -r 564a9d870fb8 src/translations/xrc_pot.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/translations/xrc_pot.py Sat Apr 20 12:19:39 2013 +0200 @@ -0,0 +1,169 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +# file xrc_pot.py +# This file is part of hugin +# The idea inspired from LyX +# Licence details can be found in the file COPYING. +# +# autors Kornel Benko <Kor...@be...> +# Thomas Modes <Tho...@gm...> +# +# original \author Bo Peng +# +# Full author contact details are available in file CREDITS + +# Usage: use +# xrc_pot.py -h +# to get usage message + +# This script will extract translatable strings from input files and write +# to output in gettext .pot format. +# +import sys, os, re, getopt +import codecs + +if sys.version_info < (2, 4, 0): + from sets import Set as set + +def relativePath(path, base): + '''return relative path from top source dir''' + # full pathname of path + path1 = os.path.normpath(os.path.realpath(path)).split(os.sep) + path2 = os.path.normpath(os.path.realpath(base)).split(os.sep) + if path1[:len(path2)] != path2: + sys.out.write("Path %s is not under top source directory\n" % path) + path3 = os.path.join(*path1[len(path2):]); + # replace all \ by / such that we get the same comments on Windows and *nix + path3 = path3.replace('\\', '/') + return path3 + + +def writeString(outfile, infile, basefile, lineno, string): + string = string.replace('\\', '\\\\').replace('"', '') + if string == "": + return + outfile.write('#: %s:%d\nmsgid "%s"\nmsgstr ""\n\n' % \ + (relativePath(infile, basefile), lineno, string)) + +def convertString(string): + string = string.replace('&', '&').replace('"', '"') + string = string.replace('_', '&') + string = string.replace('<', '<').replace('>', '>') + string = string.replace('\\n', r'
') + string = string.replace('\\', '\\\\').replace('"', r'\"') + string = string.replace('
', r'\n') + #string = string.decode('iso-8859-1') # this is for python2 OK + return string + +def xrc_l10n(input_files, output, base): + '''Generate pot file from src/..../*.xrc''' + output = codecs.open(output, 'a', 'utf-8') + #output = open(output, 'a') + pat_ret = re.compile(r'(.*)\r') + pat_txt = re.compile(r'\s*<(label|help|value|longhelp|tooltip|htmlcode|title|item)(\s+[^>]*)?>(.*)</\1>') + pat_multi = re.compile(r'\s*<(label|help|value|longhelp|tooltip|htmlcode|title|item)(\s+[^>]*)?>(.*)$') + pat_end = re.compile(r'(.*)</(label|help|value|longhelp|tooltip|htmlcode|title|item)>') + pat_whole = re.compile(r'(.*)$') + numeric = re.compile(r'^\d+$') + ignored = ["_(\"\");\n"] + for line in open(base + "/translations/ignored-strings.txt"): + ignored.append(line) + nodewait = "" # expect this node in closing on multiline + multi = 0 # multiline text + stringmulti = "" + string = "" + stringline = 0 + for src in input_files: + input = codecs.open(src, 'r', 'iso-8859-1') + for lineno, line in enumerate(input.readlines()): + # get lines that match e.g. <label>...</label> + if pat_ret.match(line): + (line,) = pat_ret.match(line).groups() + if multi > 0: + if pat_end.match(line): + (string2, node2) = pat_end.match(line).groups() + stringline = lineno + 1 - multi + if not node2 == nodewait: + sys.out.write("node2 = \"" + node2 + "\"\n" + \ + "nodewait = \"" + nodewait + "\"\n" + \ + "file = \"" + src + "\":" + str(stringline)) + exit(1) + multi = 0 + string = stringmulti + '\\n' + convertString(string2) + stringmulti = "" + else: + (string2,) = pat_whole.match(line).groups() + stringmulti = stringmulti + '\\n' + convertString(string2) + multi += 1 + continue + elif pat_txt.match(line): + (node,pars,string,) = pat_txt.match(line).groups() + if numeric.match(string): + continue + string = convertString(string) + stringline = lineno + elif pat_multi.match(line): + (node,pars,string,) = pat_multi.match(line).groups() + nodewait = node + multi = 1 + stringmulti = convertString(string) + continue + + if numeric.match(string): + string = "" + continue + istring = "_(\"" + string + "\");\n" + if istring not in ignored: + output.write('#: %s:%d\nmsgid "%s"\nmsgstr ""\n\n' % \ + (relativePath(src, base), stringline+1, string)) + string = "" + input.close() + output.close() + + +Usage = ''' +xrc_pot.py [-b|--base top_src_dir] [-o|--output output_file] [-h|--help] [-s|src_file filename] -t|--type input_type input_files + +where + --base: + path to the top source directory. default to '.' + --output: + output pot file, default to './xrc.pot' + --src_file + filename that contains a list of input files in each line + --input_type can be + xrc: xrc files +''' + +if __name__ == '__main__': + input_type = None + output = 'xrc.pot' + base = '.' + input_files = [] + # + optlist, args = getopt.getopt(sys.argv[1:], 'ht:o:b:s:', + ['help', 'type=', 'output=', 'base=', 'src_file=']) + for (opt, value) in optlist: + if opt in ['-h', '--help']: + sys.out.write(Usage + "\n") + sys.exit(0) + elif opt in ['-o', '--output']: + output = value + elif opt in ['-b', '--base']: + base = value + elif opt in ['-t', '--type']: + input_type = value + elif opt in ['-s', '--src_file']: + input_files = [f.strip() for f in open(value)] + + if input_type not in ['xrc'] or output is None: + sys.out.write('Wrong input type or output filename.\n') + sys.exit(1) + + input_files += args + + if input_type == 'xrc': + xrc_l10n(input_files, output, base) + + |