CMake: Introduce qt_deploy_translations

Add the command qt_deploy_translations to the CMake deployment API.
This can be used to deploy a set of Qt translations.

This command is supposed to be called by the generic deployment tool in
a future commit.

[ChangeLog][CMake] Added qt_deploy_translations for deploying Qt
translation catalogs in user projects.

Change-Id: I4492a5042970cf89b2be2ed0c34521c7af904771
Reviewed-by: Alexandru Croitor <alexandru.croitor@qt.io>
This commit is contained in:
Joerg Bornemann 2022-09-05 20:10:20 +02:00
parent c9c04291f5
commit 1b5462c2ac
4 changed files with 264 additions and 5 deletions

View File

@ -394,3 +394,147 @@ function(_qt_internal_show_skip_runtime_deploy_message qt_build_type_string)
"this target platform (${__QT_DEPLOY_SYSTEM_NAME}, ${qt_build_type_string})."
)
endfunction()
# This function is currently in Technical Preview.
# Its signature and behavior might change.
function(qt6_deploy_translations)
set(no_value_options VERBOSE)
set(single_value_options
LCONVERT
)
set(multi_value_options
CATALOGS
LOCALES
)
cmake_parse_arguments(PARSE_ARGV 0 arg
"${no_value_options}" "${single_value_options}" "${multi_value_options}"
)
set(verbose OFF)
if(arg_VERBOSE OR __QT_DEPLOY_VERBOSE)
set(verbose ON)
endif()
if(arg_CATALOGS)
set(catalogs ${arg_CATALOGS})
else()
set(catalogs qt qtbase)
# Find the translations that belong to the Qt modules that are used by the project.
# "Used by the project" means just all modules that are pulled in via find_package for now.
set(modules ${__QT_DEPLOY_ALL_MODULES_FOUND_VIA_FIND_PACKAGE})
set(module_catalog_mapping
"Bluetooth|Nfc" qtconnectivity
"Help" qt_help
"Multimedia(Widgets|QuickPrivate)?" qtmultimedia
"Qml|Quick" qtdeclarative
"SerialPort" qtserialport
"WebEngine" qtwebengine
"WebSockets" qtwebsockets
)
list(LENGTH module_catalog_mapping max_i)
math(EXPR max_i "${max_i} - 1")
foreach(module IN LISTS modules)
foreach(i RANGE 0 ${max_i} 2)
list(GET module_catalog_mapping ${i} module_rex)
if(NOT module MATCHES "^${module_rex}")
continue()
endif()
math(EXPR k "${i} + 1")
list(GET module_catalog_mapping ${k} catalog)
list(APPEND catalogs ${catalog})
endforeach()
endforeach()
endif()
get_filename_component(qt_translations_dir "${__QT_DEPLOY_QT_INSTALL_TRANSLATIONS}" ABSOLUTE
BASE_DIR "${__QT_DEPLOY_QT_INSTALL_PREFIX}"
)
set(locales ${arg_LOCALES})
if(NOT locales)
file(GLOB locales RELATIVE "${qt_translations_dir}" "${qt_translations_dir}/*.qm")
list(TRANSFORM locales REPLACE "\\.qm$" "")
list(TRANSFORM locales REPLACE "^qt_help" "qt-help")
list(TRANSFORM locales REPLACE "^[^_]+" "")
list(TRANSFORM locales REPLACE "^_" "")
list(REMOVE_DUPLICATES locales)
endif()
# Ensure existence of the output directory.
set(output_dir "${QT_DEPLOY_PREFIX}/${QT_DEPLOY_TRANSLATIONS_DIR}")
if(NOT EXISTS "${output_dir}")
file(MAKE_DIRECTORY "${output_dir}")
endif()
# Locate lconvert.
if(arg_LCONVERT)
set(lconvert "${arg_LCONVERT}")
else()
set(lconvert "${__QT_DEPLOY_QT_INSTALL_PREFIX}/${__QT_DEPLOY_QT_INSTALL_BINS}/lconvert")
if(CMAKE_HOST_WIN32)
string(APPEND lconvert ".exe")
endif()
if(NOT EXISTS ${lconvert})
message(STATUS "lconvert was not found. Skipping deployment of translations.")
return()
endif()
endif()
# Find the .qm files for the selected locales
if(verbose)
message(STATUS "Looking for translations in ${qt_translations_dir}")
endif()
foreach(locale IN LISTS locales)
set(qm_files "")
foreach(catalog IN LISTS catalogs)
set(qm_file "${catalog}_${locale}.qm")
if(EXISTS "${qt_translations_dir}/${qm_file}")
list(APPEND qm_files ${qm_file})
endif()
endforeach()
if(NOT qm_files)
message(WARNING "No translations found for requested locale '${locale}'.")
continue()
endif()
if(verbose)
foreach(qm_file IN LISTS qm_files)
message(STATUS "found translation file: ${qm_file}")
endforeach()
endif()
# Merge the .qm files into one qt_${locale}.qm file.
set(output_file_name "qt_${locale}.qm")
set(output_file_path "${output_dir}/${output_file_name}")
message(STATUS "Creating: ${output_file_path}")
set(extra_options)
if(verbose)
list(APPEND extra_options COMMAND_ECHO STDOUT)
endif()
execute_process(
COMMAND ${lconvert} -if qm -o ${output_file_path} ${qm_files}
WORKING_DIRECTORY ${qt_translations_dir}
RESULT_VARIABLE process_result
${extra_options}
)
if(NOT process_result EQUAL "0")
if(process_result MATCHES "^[0-9]+$")
message(WARNING "lconvert failed with exit code ${process_result}.")
else()
message(WARNING "lconvert failed: ${process_result}.")
endif()
endif()
endforeach()
endfunction()
if(NOT __QT_NO_CREATE_VERSIONLESS_FUNCTIONS)
function(qt_deploy_translations)
if(__QT_DEFAULT_MAJOR_VERSION EQUAL 6)
qt6_deploy_translations(${ARGV})
else()
message(FATAL_ERROR "qt_deploy_translations() is only available in Qt 6.")
endif()
endfunction()
endif()

View File

@ -2464,6 +2464,9 @@ endif()
if(NOT QT_DEPLOY_QML_DIR)
set(QT_DEPLOY_QML_DIR \"qml\")
endif()
if(NOT QT_DEPLOY_TRANSLATIONS_DIR)
set(QT_DEPLOY_TRANSLATIONS_DIR \"translations\")
endif()
if(NOT QT_DEPLOY_PREFIX)
set(QT_DEPLOY_PREFIX \"\$ENV{DESTDIR}\${CMAKE_INSTALL_PREFIX}\")
endif()
@ -2484,7 +2487,9 @@ set(__QT_NO_CREATE_VERSIONLESS_FUNCTIONS \"${QT_NO_CREATE_VERSIONLESS_FUNCTIONS}
set(__QT_DEFAULT_MAJOR_VERSION \"${QT_DEFAULT_MAJOR_VERSION}\")
set(__QT_DEPLOY_QT_ADDITIONAL_PACKAGES_PREFIX_PATH \"${QT_ADDITIONAL_PACKAGES_PREFIX_PATH}\")
set(__QT_DEPLOY_QT_INSTALL_PREFIX \"${QT6_INSTALL_PREFIX}\")
set(__QT_DEPLOY_QT_INSTALL_BINS \"${QT6_INSTALL_BINS}\")
set(__QT_DEPLOY_QT_INSTALL_PLUGINS \"${QT6_INSTALL_PLUGINS}\")
set(__QT_DEPLOY_QT_INSTALL_TRANSLATIONS \"${QT6_INSTALL_TRANSLATIONS}\")
set(__QT_DEPLOY_PLUGINS \"\")
# Define the CMake commands to be made available during deployment.
@ -2640,6 +2645,7 @@ function(qt6_generate_deploy_script)
set(boiler_plate "include(${QT_DEPLOY_SUPPORT})
include(\"\${CMAKE_CURRENT_LIST_DIR}/${arg_TARGET}-plugins${config_infix}.cmake\" OPTIONAL)
set(__QT_DEPLOY_ALL_MODULES_FOUND_VIA_FIND_PACKAGE \"${QT_ALL_MODULES_FOUND_VIA_FIND_PACKAGE}\")
")
list(TRANSFORM arg_CONTENT REPLACE "\\$" "\$")
file(GENERATE OUTPUT ${file_name} CONTENT "${boiler_plate}${arg_CONTENT}")

View File

@ -49,7 +49,7 @@ install location and just use the prefix-relative \c{QT_DEPLOY_..._DIR}
variables.
\sa QT_DEPLOY_SUPPORT, QT_DEPLOY_BIN_DIR, QT_DEPLOY_LIB_DIR,
QT_DEPLOY_PLUGINS_DIR, QT_DEPLOY_QML_DIR
QT_DEPLOY_PLUGINS_DIR, QT_DEPLOY_QML_DIR, QT_DEPLOY_TRANSLATIONS_DIR
*/
/*!
@ -90,7 +90,7 @@ should not be used for that scenario.
\include cmake-deploy-runtime-dependencies.qdocinc
\sa QT_DEPLOY_SUPPORT, QT_DEPLOY_PREFIX, QT_DEPLOY_LIB_DIR,
QT_DEPLOY_PLUGINS_DIR, QT_DEPLOY_QML_DIR
QT_DEPLOY_PLUGINS_DIR, QT_DEPLOY_QML_DIR, QT_DEPLOY_TRANSLATIONS_DIR
*/
/*!
@ -132,7 +132,7 @@ should not be used for that scenario.
\include cmake-deploy-modified-variable-values.qdocinc
\sa QT_DEPLOY_SUPPORT, QT_DEPLOY_PREFIX, QT_DEPLOY_BIN_DIR,
QT_DEPLOY_PLUGINS_DIR, QT_DEPLOY_QML_DIR
QT_DEPLOY_PLUGINS_DIR, QT_DEPLOY_QML_DIR, QT_DEPLOY_TRANSLATIONS_DIR
*/
/*!
@ -168,7 +168,7 @@ bundle contents.
\include cmake-deploy-modified-variable-values.qdocinc
\sa QT_DEPLOY_SUPPORT, QT_DEPLOY_PREFIX, QT_DEPLOY_BIN_DIR, QT_DEPLOY_LIB_DIR,
QT_DEPLOY_QML_DIR
QT_DEPLOY_QML_DIR, QT_DEPLOY_TRANSLATIONS_DIR
*/
/*!
@ -206,5 +206,38 @@ to be deployed to different locations within the app bundle.
\include cmake-deploy-modified-variable-values.qdocinc
\sa QT_DEPLOY_SUPPORT, QT_DEPLOY_PREFIX, QT_DEPLOY_BIN_DIR, QT_DEPLOY_LIB_DIR,
QT_DEPLOY_PLUGINS_DIR
QT_DEPLOY_PLUGINS_DIR, QT_DEPLOY_TRANSLATIONS_DIR
*/
/*!
\page cmake-variable-QT_DEPLOY_TRANSLATIONS_DIR.html
\ingroup cmake-variables-qtcore
\title QT_DEPLOY_TRANSLATIONS_DIR
\target cmake-variable-QT_DEPLOY_TRANSLATIONS_DIR
\summary {Prefix-relative subdirectory for deploying Qt translations on some target platforms.}
\include cmake-deploy-var-usage.qdocinc
\cmakevariablesince 6.5
\preliminarycmakevariable
Projects should use \c QT_DEPLOY_TRANSLATIONS_DIR in their deploy scripts to
avoid hard-coding a particular directory under which to deploy translations.
\c QT_DEPLOY_TRANSLATIONS_DIR defaults to the value \c{translations}. To change
the value of \c QT_DEPLOY_TRANSLATIONS_DIR, set it in the project deployment
script before \c QT_DEPLOY_SUPPORT is included.
The \c QT_DEPLOY_TRANSLATIONS_DIR path is relative to \l{QT_DEPLOY_PREFIX}.
This variable is not meaningful when deploying on macOS or Windows.
\section1 Example
\include cmake-deploy-modified-variable-values.qdocinc
\sa QT_DEPLOY_SUPPORT, QT_DEPLOY_PREFIX, QT_DEPLOY_BIN_DIR, QT_DEPLOY_LIB_DIR,
QT_DEPLOY_PLUGINS_DIR, QT_DEPLOY_QML_DIR
*/

View File

@ -0,0 +1,76 @@
// Copyright (C) 2022 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GFDL-1.3-no-invariants-only
/*!
\page qt_deploy_translations.html
\ingroup cmake-commands-qtcore
\title qt_deploy_translations
\target qt_deploy_translations
\summary {Deploy Qt translations needed by an executable.}
\include cmake-find-package-core.qdocinc
Unlike most other CMake commands provided by Qt, \c{qt_deploy_translations()}
can only be called from a deployment script. It cannot be called directly by the
project during the configure stage.
\cmakecommandsince 6.5
\preliminarycmakecommand
\note This command does not usually need to be called directly. It is used
internally by other higher level commands, but projects wishing to
implement more customized deployment logic may find it useful.
\section1 Synopsis
\badcode
qt_deploy_translations(
[CATALOGS catalogs]
[LOCALES locales]
[LCONVERT lconvert_executable]
[VERBOSE]
)
\endcode
\section1 Description
When installing an application, it may be desirable to also install the
translations that belong to the used Qt modules. The \c qt_deploy_translations
command collects the necessary \c{.qm} file from the Qt installation and
compiles them into one \c{qt_${language}.qm} file per language. The \c{.qm}
files are installed into \c{QT_DEPLOY_TRANSLATIONS_DIR}.
\section1 Arguments
The \c LOCALES argument specifies for which locales translations should be
deployed. This is a list of language/region combinations as described in
\l{Changing the Target Locale}{Qt Linguist's manual for translators}. Examples
for valid locales are: \c{de}, \c{pl}, or \c{pt_BR}.
If \c LOCALES is omitted, then all available locales are deployed.
The \c CATALOGS argument specifies a list of \l{Available
Catalogs}{translation catalogs} to be deployed. If this argument is
omitted, then all catalogs are deployed that belong to any Qt module
that is used in the project via \c{find_package}.
The \c LCONVERT argument specifies the \c lconvert executable that is used to
combine the catalogs. By default, the Qt installation's \c lconvert is used.
For debugging purposed, the \c VERBOSE argument can be set to turn on diagnostic
messages.
\sa QT_DEPLOY_TRANSLATIONS_DIR
\section1 Example
The following example deploys Danish and German translations of the Qt
libraries.
\badcode
qt_deploy_translations(
LOCALES da de
)
\endcode
*/