diff options
author | Aurélien Gâteau <agateau@kde.org> | 2014-04-16 10:27:45 +0200 |
---|---|---|
committer | Aurélien Gâteau <agateau@kde.org> | 2014-04-16 10:28:18 +0200 |
commit | 071581a3f899c881c9938efd082fd32589822b45 (patch) | |
tree | 314f51d5b7fce80b445f33f694bf570178ca9d5e /modules | |
parent | ecbefa6959452af98485288388a92cbf35a28e99 (diff) | |
download | extra-cmake-modules-071581a3f899c881c9938efd082fd32589822b45.tar.gz extra-cmake-modules-071581a3f899c881c9938efd082fd32589822b45.tar.bz2 |
Make ECMCreateQmFromPoFiles usable from within trunk/l10n-kf5
REVIEW: 117560
Diffstat (limited to 'modules')
-rw-r--r-- | modules/ECMCreateQmFromPoFiles.cmake | 195 | ||||
-rw-r--r-- | modules/ECMQmLoader.cpp.in | 30 |
2 files changed, 159 insertions, 66 deletions
diff --git a/modules/ECMCreateQmFromPoFiles.cmake b/modules/ECMCreateQmFromPoFiles.cmake index 92d0d1a8..b8f3c651 100644 --- a/modules/ECMCreateQmFromPoFiles.cmake +++ b/modules/ECMCreateQmFromPoFiles.cmake @@ -6,47 +6,69 @@ # # :: # -# ecm_create_qm_from_po_files(PO_DIR <po_dir> -# POT_NAME <pot_name> -# [DATA_INSTALL_DIR <data_install_dir>] -# [DATA_INSTALL_SUB_DIR <data_install_sub_dir>] -# [CREATE_LOADER <source_file_var>]) +# ecm_create_qm_from_po_files(PO_FILES <file1>... <fileN> +# [CATALOG_NAME <catalog_name>] +# [INSTALL_DESTINATION <install_destination>]) # -# Creates the necessary rules to compile .po files into .qm files, usable by -# QTranslator. It can also generate a C++ file which takes care of automatically -# loading those translations. +# Creates the necessary rules to compile .po files into .qm files, and install +# them. # -# PO_DIR is the path to a directory containing .po files. +# The .qm files are installed in ``<install_destination>/<lang>/LC_MESSAGES``, +# where <install_destination> is the INSTALL_DESTINATION argument and <lang> is +# extracted from the "Language" field inside the .po file. # -# POT_NAME is the name of the .pot file for the project. This file must be in -# PO_DIR. +# INSTALL_DESTINATION defaults to ``${LOCALE_INSTALL_DIR}`` if defined, +# otherwise it uses "share/locale". # -# .qm files are installed in "DATA_INSTALL_DIR/DATA_INSTALL_SUB_DIR". +# CATALOG_NAME defines the name of the installed .qm files. If set, .qm files +# will be installed as ``<catalog_name>.qm``. If not set .qm files will be named +# after the name of their source .po file. # -# DATA_INSTALL_DIR defaults to ${DATA_INSTALL_DIR} if defined, otherwise it uses -# "share". It must point to a directory which is in the list returned by: +# Setting the catalog name is useful when all .po files for a target are kept +# in a single source directory. For example, the "mylib" probject might keep all +# its translations in a "po" directory, like this:: # -# .. code-block:: cpp +# po/ +# es.po +# fr.po # -# QStandardPath::standardLocations(QStandardPath::GenericDataLocation) +# Without setting CATALOG_NAME, those .po will be turned into .qm and installed +# as:: # -# otherwise the C++ loader will fail to load the translations. +# share/locale/fr/LC_MESSAGES/fr.qm +# share/locale/es/LC_MESSAGES/es.qm # -# DATA_INSTALL_SUB_DIR defaults to the value of POT_NAME, without the ".pot" -# extension. +# If CATALOG_NAME is set to "mylib", they will be installed as:: +# +# share/locale/fr/LC_MESSAGES/mylib.qm +# share/locale/es/LC_MESSAGES/mylib.qm +# +# Which is what the loader created by ecm_create_qm_loader() expects. # # ecm_create_qm_from_po_files() creates a "translation" target. This target # builds all .po files into .qm files. # -# If ecm_create_qm_from_po_files() is called with the CREATE_LOADER argument, -# it generates a C++ file which ensures translations are automatically loaded -# at startup. The path of the .cpp file is stored in <source_file_var>. This -# variable must be added to the list of sources to build, like this: +# :: +# +# ecm_create_qm_loader(<source_file_var> <catalog_name>) +# +# ecm_create_qm_loader() generates a C++ file which ensures translations are +# automatically loaded at startup. The path of the .cpp file is stored in +# <source_file_var>. This variable must be added to the list of sources to +# build. For example this call: # # .. code-block:: cmake # -# ecm_create_qm_from_po_files(PO_DIR po POT_NAME mylib CREATE_LOADER myloader) -# set(mylib_SRCS foo.cpp bar.cpp ${myloader}) +# ecm_create_qm_loader(qmloader mylib) +# +# generates a C++ file which loads "mylib.qm" at startup, assuming it has been +# installed by ecm_create_qm_from_po_files(). The name of the C++ file is +# stored in the ``${qmloader}`` CMake variable. This variable must be integrated +# in the list of source files for the library: +# +# .. code-block:: cmake +# +# set(mylib_SRCS foo.cpp bar.cpp ${qmloader}) # add_library(mylib ${mylib_SRCS}) #============================================================================= @@ -66,7 +88,29 @@ # See https://bugreports.qt-project.org/browse/QTBUG-37937 find_package(Qt5LinguistTools CONFIG REQUIRED) -function(_ecm_qm_create_target po_dir pot_name data_install_dir data_install_sub_dir) +# Stolen from FindGettext.cmake +function(_ECM_QM_GET_UNIQUE_TARGET_NAME _name _unique_name) + set(propertyName "_ECM_QM_UNIQUE_COUNTER_${_name}") + get_property(currentCounter GLOBAL PROPERTY "${propertyName}") + if(NOT currentCounter) + set(currentCounter 1) + endif() + set(${_unique_name} "${_name}_${currentCounter}" PARENT_SCOPE) + math(EXPR currentCounter "${currentCounter} + 1") + set_property(GLOBAL PROPERTY ${propertyName} ${currentCounter} ) +endfunction() + +function(_ECM_QM_EXTRACT_LANGUAGE out_language po_file) + file(READ ${po_file} content) + # msginit uses "Language: <lang>" but lconvert uses "X-Language: <lang>" + string(REGEX MATCH "\"(X-)?Language: ([a-z_A-Z]+)" match "${content}") + if (NOT match) + message(FATAL_ERROR "_ECM_QM_EXTRACT_LANGUAGE: Could not extract language from ${po_file}") + endif() + set(${out_language} ${CMAKE_MATCH_2} PARENT_SCOPE) +endfunction() + +function(_ECM_QM_CREATE_TARGET install_destination catalog_name) # Find lconvert get_target_property(lrelease_location Qt5::lrelease LOCATION) get_filename_component(lrelease_path ${lrelease_location} PATH) @@ -75,8 +119,13 @@ function(_ecm_qm_create_target po_dir pot_name data_install_dir data_install_sub PATHS ${lrelease_path} ) - file(GLOB po_files "${po_dir}/*.po") - foreach (it ${po_files}) + if (catalog_name) + set(install_args RENAME ${catalog_name}.qm) + else() + set(install_args) + endif() + + foreach (it ${ARGN}) get_filename_component(filename_base ${it} ABSOLUTE) get_filename_component(filename_base ${it} NAME_WE) @@ -84,67 +133,103 @@ function(_ecm_qm_create_target po_dir pot_name data_install_dir data_install_sub set(tsfile ${CMAKE_CURRENT_BINARY_DIR}/${filename_base}.ts) set(qmfile ${CMAKE_CURRENT_BINARY_DIR}/${filename_base}.qm) + _ECM_QM_EXTRACT_LANGUAGE(language ${it}) + # lconvert from .po to .ts and then run lupdate to generate the correct # strings. Finally run lrelease to create the .qm files. add_custom_command(OUTPUT ${qmfile} COMMAND ${lconvert_executable} ARGS -i ${it} -o ${tsfile} - COMMAND Qt5::lupdate - ARGS ${CMAKE_SOURCE_DIR}/src -silent -noobsolete -ts ${tsfile} COMMAND Qt5::lrelease ARGS -compress -removeidentical -silent ${tsfile} -qm ${qmfile} DEPENDS ${it} ) + install( + FILES ${qmfile} + DESTINATION ${install_destination}/${language}/LC_MESSAGES + ${install_args} + ) set(qmfiles ${qmfiles} ${qmfile}) endforeach() if(NOT TARGET translations) add_custom_target(translations ALL) endif() - add_custom_target(translations-${pot_name} DEPENDS ${qmfiles}) - add_dependencies(translations translations-${pot_name}) - - install(FILES ${qmfiles} DESTINATION ${data_install_dir}/${data_install_sub_dir}) + _ecm_qm_get_unique_target_name(translations target_name) + add_custom_target(${target_name} DEPENDS ${qmfiles}) + add_dependencies(translations ${target_name}) endfunction() -function(_ecm_qm_create_loader pot_name data_install_sub_dir) - # data_install_sub_dir is used in ECMQmLoader.cpp.in - get_filename_component(qm_name ${pot_name} NAME_WE) +function(ECM_CREATE_QM_LOADER out_var catalog_name) + # catalog_name is used in ECMQmLoader.cpp.in configure_file(${ECM_MODULE_DIR}/ECMQmLoader.cpp.in ECMQmLoader.cpp @ONLY) + set(${out_var} ${CMAKE_CURRENT_BINARY_DIR}/ECMQmLoader.cpp PARENT_SCOPE) endfunction() function(ECM_CREATE_QM_FROM_PO_FILES) + foreach (arg ${ARGN}) + if (arg STREQUAL "PO_DIR") + _ecm_create_qm_from_po_files_legacy(${ARGN}) + return() + endif() + endforeach() + set(options) - set(oneValueArgs PO_DIR POT_NAME DATA_INSTALL_DIR DATA_INSTALL_SUB_DIR CREATE_LOADER) - set(multiValueArgs) + set(oneValueArgs CATALOG_NAME INSTALL_DESTINATION) + set(multiValueArgs PO_FILES) cmake_parse_arguments(ARGS "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) if(ARGS_UNPARSED_ARGUMENTS) message(FATAL_ERROR "Unknown keywords given to ECM_CREATE_QM_FROM_PO_FILES(): \"${ARGS_UNPARSED_ARGUMENTS}\"") endif() - if(NOT ARGS_PO_DIR) - message(FATAL_ERROR "Required argument PO_DIR missing in ECM_CREATE_QM_FROM_PO_FILES() call") - endif() - - if(NOT ARGS_POT_NAME) - message(FATAL_ERROR "Required argument POT_NAME missing in ECM_CREATE_QM_FROM_PO_FILES() call") + if(NOT ARGS_PO_FILES) + message(FATAL_ERROR "ECM_CREATE_QM_FROM_PO_FILES(): Must be called with PO_FILES argument") endif() - if(NOT ARGS_DATA_INSTALL_DIR) - if (DATA_INSTALL_DIR) - set(ARGS_DATA_INSTALL_DIR ${DATA_INSTALL_DIR}) + if(NOT ARGS_INSTALL_DESTINATION) + if (LOCALE_INSTALL_DIR) + set(ARGS_INSTALL_DESTINATION ${LOCALE_INSTALL_DIR}) else() - set(ARGS_DATA_INSTALL_DIR share) + set(ARGS_INSTALL_DESTINATION share/locale) endif() endif() - if(NOT ARGS_DATA_INSTALL_SUB_DIR) - get_filename_component(ARGS_DATA_INSTALL_SUB_DIR "${ARGS_POT_NAME}" NAME_WE) + + _ecm_qm_create_target(${ARGS_INSTALL_DESTINATION} "${ARGS_CATALOG_NAME}" ${ARGS_PO_FILES}) +endfunction() + +# Handles the syntax exposed in ECM 0.0.12, shipped with KDE Frameworks 5.0beta1 +# +# This is a macro so that the value written in ${ARGS_CREATE_LOADER} is +# correctly propagated to ECM_CREATE_QM_FROM_PO_FILES parent scope. If it were +# not a macro, ECM_CREATE_QM_FROM_PO_FILES would have to ckeck if +# CREATE_LOADER is in the arguments and propagate the value itself. +macro(_ECM_CREATE_QM_FROM_PO_FILES_LEGACY) + set(options) + set(oneValueArgs PO_DIR POT_NAME DATA_INSTALL_DIR DATA_INSTALL_SUB_DIR CREATE_LOADER) + set(multiValueArgs) + cmake_parse_arguments(ARGS "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) + + if(ARGS_UNPARSED_ARGUMENTS) + message(FATAL_ERROR "Unknown keywords given to _ECM_CREATE_QM_FROM_PO_FILES_LEGACY(): \"${ARGS_UNPARSED_ARGUMENTS}\"") + endif() + + if(NOT ARGS_POT_NAME) + message(FATAL_ERROR "Required argument POT_NAME missing in _ECM_CREATE_QM_FROM_PO_FILES_LEGACY() call") + endif() + get_filename_component(catalog_name ${ARGS_POT_NAME} NAME_WE) + + if (LOCALE_INSTALL_DIR) + set(install_destination ${LOCALE_INSTALL_DIR}) + else() + set(install_destination share/locale) endif() - _ecm_qm_create_target(${ARGS_PO_DIR} ${ARGS_POT_NAME} ${ARGS_DATA_INSTALL_DIR} ${ARGS_DATA_INSTALL_SUB_DIR}) + file(GLOB po_files "${ARGS_PO_DIR}/*.po") + _ecm_qm_create_target(${install_destination} "${catalog_name}" ${po_files}) + if (ARGS_CREATE_LOADER) - _ecm_qm_create_loader(${ARGS_POT_NAME} ${ARGS_DATA_INSTALL_SUB_DIR}) - set(${ARGS_CREATE_LOADER} ${CMAKE_CURRENT_BINARY_DIR}/ECMQmLoader.cpp PARENT_SCOPE) + ecm_create_qm_loader(loader ${catalog_name}) + set(${ARGS_CREATE_LOADER} ${loader} PARENT_SCOPE) endif() -endfunction() +endmacro() diff --git a/modules/ECMQmLoader.cpp.in b/modules/ECMQmLoader.cpp.in index 4fd9c116..fd530602 100644 --- a/modules/ECMQmLoader.cpp.in +++ b/modules/ECMQmLoader.cpp.in @@ -8,25 +8,33 @@ #include <QStandardPaths> #include <QTranslator> -static QTranslator *createTranslator() -{ - QString installSubDir = QStringLiteral("@data_install_sub_dir@"); - QString qmName = QStringLiteral("@qm_name@"); +#include <QDebug> - QString dir = QStandardPaths::locate(QStandardPaths::GenericDataLocation, installSubDir, QStandardPaths::LocateDirectory); +static QTranslator *createTranslator(const QString &localeDirName) +{ + QString subPath = QStringLiteral("locale/") + localeDirName + QStringLiteral("/LC_MESSAGES/@catalog_name@.qm"); + QString fullPath = QStandardPaths::locate(QStandardPaths::GenericDataLocation, subPath); + if (fullPath.isEmpty()) { + return 0; + } QTranslator *translator = new QTranslator(QCoreApplication::instance()); - translator->load(QLocale::system(), qmName, QStringLiteral("-") /* prefix */, dir); + if (!translator->load(fullPath)) { + delete translator; + return 0; + } return translator; } static void load() { - QTranslator *translator = createTranslator(); - if (translator->isEmpty()) { - delete translator; - return; + QLocale locale = QLocale::system(); + QTranslator *translator = createTranslator(locale.name()); + if (!translator) { + translator = createTranslator(locale.bcp47Name()); + if (!translator) { + return; + } } - translator->setParent(QCoreApplication::instance()); QCoreApplication::instance()->installTranslator(translator); } |