summaryrefslogtreecommitdiffstats
path: root/src/linguist/Qt6LinguistToolsMacros.cmake
diff options
context:
space:
mode:
Diffstat (limited to 'src/linguist/Qt6LinguistToolsMacros.cmake')
-rw-r--r--src/linguist/Qt6LinguistToolsMacros.cmake596
1 files changed, 498 insertions, 98 deletions
diff --git a/src/linguist/Qt6LinguistToolsMacros.cmake b/src/linguist/Qt6LinguistToolsMacros.cmake
index f0d99dd4d..5e3baecc2 100644
--- a/src/linguist/Qt6LinguistToolsMacros.cmake
+++ b/src/linguist/Qt6LinguistToolsMacros.cmake
@@ -1,35 +1,6 @@
-#=============================================================================
# Copyright (C) 2020 The Qt Company Ltd.
# Copyright 2005-2011 Kitware, Inc.
-# All rights reserved.
-#
-# Redistribution and use in source and binary forms, with or without
-# modification, are permitted provided that the following conditions
-# are met:
-#
-# * Redistributions of source code must retain the above copyright
-# notice, this list of conditions and the following disclaimer.
-#
-# * Redistributions in binary form must reproduce the above copyright
-# notice, this list of conditions and the following disclaimer in the
-# documentation and/or other materials provided with the distribution.
-#
-# * Neither the name of Kitware, Inc. nor the names of its
-# contributors may be used to endorse or promote products derived
-# from this software without specific prior written permission.
-#
-# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
-# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
-# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
-# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
-# HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
-# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
-# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
-# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
-# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
-# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-#=============================================================================
+# SPDX-License-Identifier: BSD-3-Clause
include(CMakeParseArguments)
@@ -64,11 +35,16 @@ function(qt6_create_translation _qm_files)
list(APPEND _my_sources ${_abs_FILE})
endif()
endforeach()
+ set(stamp_file_dir "${CMAKE_CURRENT_BINARY_DIR}/.lupdate")
+ if(NOT EXISTS "${stamp_file_dir}")
+ file(MAKE_DIRECTORY "${stamp_file_dir}")
+ endif()
+ set(stamp_files "")
foreach(_ts_file ${_my_tsfiles})
+ get_filename_component(_ts_name ${_ts_file} NAME)
if(_my_sources)
# make a list file to call lupdate on, so we don't make our commands too
# long for some systems
- get_filename_component(_ts_name ${_ts_file} NAME)
set(_ts_lst_file "${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/${_ts_name}_lst_file")
set(_lst_file_srcs)
set(_dependencies)
@@ -91,24 +67,34 @@ function(qt6_create_translation _qm_files)
file(WRITE ${_ts_lst_file} "${_lst_file_srcs}")
endif()
- add_custom_command(OUTPUT ${_ts_file}
+ file(RELATIVE_PATH _ts_relative_path ${CMAKE_CURRENT_SOURCE_DIR} ${_ts_file})
+ string(REPLACE "../" "__/" _ts_relative_path "${_ts_relative_path}")
+ set(stamp_file "${stamp_file_dir}/${_ts_relative_path}.stamp")
+ list(APPEND stamp_files ${stamp_file})
+ get_filename_component(full_stamp_file_dir "${stamp_file}" DIRECTORY)
+ if(NOT EXISTS "${full_stamp_file_dir}")
+ file(MAKE_DIRECTORY "${full_stamp_file_dir}")
+ endif()
+ add_custom_command(OUTPUT ${stamp_file}
COMMAND ${QT_CMAKE_EXPORT_NAMESPACE}::lupdate
ARGS ${_lupdate_options} "@${_ts_lst_file}" -ts ${_ts_file}
+ COMMAND ${CMAKE_COMMAND} -E touch "${stamp_file}"
DEPENDS ${_dependencies}
VERBATIM)
endforeach()
- qt6_add_translation(${_qm_files} ${_my_tsfiles})
+ qt6_add_translation(${_qm_files} ${_my_tsfiles} __QT_INTERNAL_TIMESTAMP_FILES ${stamp_files})
set(${_qm_files} ${${_qm_files}} PARENT_SCOPE)
endfunction()
function(qt6_add_translation _qm_files)
set(options)
set(oneValueArgs)
- set(multiValueArgs OPTIONS)
+ set(multiValueArgs OPTIONS __QT_INTERNAL_TIMESTAMP_FILES)
cmake_parse_arguments(_LRELEASE "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
set(_lrelease_files ${_LRELEASE_UNPARSED_ARGUMENTS})
+ set(idx 0)
foreach(_current_FILE ${_lrelease_files})
get_filename_component(_abs_FILE ${_current_FILE} ABSOLUTE)
get_filename_component(qm ${_abs_FILE} NAME)
@@ -122,16 +108,66 @@ function(qt6_add_translation _qm_files)
set(qm "${CMAKE_CURRENT_BINARY_DIR}/${FILE_NAME}.qm")
endif()
+ if(_LRELEASE___QT_INTERNAL_TIMESTAMP_FILES)
+ list(GET _LRELEASE___QT_INTERNAL_TIMESTAMP_FILES ${idx} qm_dep)
+ math(EXPR idx "${idx} + 1")
+ else()
+ set(qm_dep "${_abs_FILE}")
+ endif()
+
add_custom_command(OUTPUT ${qm}
COMMAND ${QT_CMAKE_EXPORT_NAMESPACE}::lrelease
ARGS ${_LRELEASE_OPTIONS} ${_abs_FILE} -qm ${qm}
- DEPENDS ${_abs_FILE} VERBATIM
+ DEPENDS ${qm_dep} VERBATIM
)
list(APPEND ${_qm_files} ${qm})
endforeach()
set(${_qm_files} ${${_qm_files}} PARENT_SCOPE)
endfunction()
+function(_qt_internal_collect_translation_source_targets out_var dir)
+ set(result "")
+ get_property(excluded DIRECTORY "${dir}" PROPERTY QT_EXCLUDE_FROM_TRANSLATION)
+ if(NOT excluded)
+ get_property(subdirs DIRECTORY "${dir}" PROPERTY SUBDIRECTORIES)
+ foreach(subdir IN LISTS subdirs)
+ _qt_internal_collect_translation_source_targets(subresult "${subdir}")
+ list(APPEND result ${subresult})
+ endforeach()
+ get_property(dir_targets DIRECTORY "${dir}" PROPERTY BUILDSYSTEM_TARGETS)
+ foreach(target IN LISTS dir_targets)
+ get_target_property(target_type ${target} TYPE)
+ if(CMAKE_VERSION VERSION_LESS "3.19" AND target_type STREQUAL "INTERFACE_LIBRARY")
+ # Skip INTERFACE libraries with CMake < 3.19 to avoid an error about
+ # QT_EXCLUDE_FROM_TRANSLATION not being whitelisted.
+ continue()
+ endif()
+ get_target_property(excluded ${target} QT_EXCLUDE_FROM_TRANSLATION)
+ if(NOT excluded AND NOT target_type STREQUAL "UTILITY")
+ list(APPEND result ${target})
+ endif()
+ endforeach()
+ endif()
+ set("${out_var}" "${result}" PARENT_SCOPE)
+endfunction()
+
+function(qt6_collect_translation_source_targets out_var)
+ set(no_value_options "")
+ set(single_value_options DIRECTORY)
+ set(multi_value_options "")
+ cmake_parse_arguments(PARSE_ARGV 1 arg
+ "${no_value_options}" "${single_value_options}" "${multi_value_options}"
+ )
+
+ set(dir "${arg_DIRECTORY}")
+ if(dir STREQUAL "")
+ set(dir "${CMAKE_CURRENT_SOURCE_DIR}")
+ endif()
+
+ _qt_internal_collect_translation_source_targets(result "${dir}")
+ set("${out_var}" "${result}" PARENT_SCOPE)
+endfunction()
+
# Makes the paths in the unparsed arguments absolute and stores them in out_var.
function(qt_internal_make_paths_absolute out_var)
set(result "")
@@ -142,33 +178,95 @@ function(qt_internal_make_paths_absolute out_var)
set("${out_var}" "${result}" PARENT_SCOPE)
endfunction()
+# If the given TS_FILE does not exist, write an initial .ts file that can be read by lrelease and
+# updated by lupdate.
+function(_qt_internal_ensure_ts_file)
+ set(no_value_options "")
+ set(single_value_options TS_FILE)
+ set(multi_value_options "")
+ cmake_parse_arguments(PARSE_ARGV 0 arg
+ "${no_value_options}" "${single_value_options}" "${multi_value_options}"
+ )
+
+ if(EXISTS "${arg_TS_FILE}")
+ return()
+ endif()
+
+ file(WRITE "${arg_TS_FILE}"
+ [[<?xml version="1.0" encoding="utf-8"?>
+<!DOCTYPE TS>
+<TS/>
+]])
+endfunction()
+
# Needed to locate Qt6LupdateProject.json.in file inside functions
set(_Qt6_LINGUIST_TOOLS_DIR ${CMAKE_CURRENT_LIST_DIR} CACHE INTERNAL "")
-function(qt6_add_lupdate target)
+function(qt6_add_lupdate)
set(options
NO_GLOBAL_TARGET)
- set(oneValueArgs)
+ set(oneValueArgs
+ PLURALS_TS_FILE
+ LUPDATE_TARGET)
set(multiValueArgs
+ SOURCE_TARGETS
TS_FILES
SOURCES
INCLUDE_DIRECTORIES
OPTIONS)
cmake_parse_arguments(arg "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
+
+ # Set up the list of targets. Support the old command signature that takes one target as first
+ # argument.
+ set(targets "${arg_SOURCE_TARGETS}")
+ if("${targets}" STREQUAL "")
+ list(POP_FRONT arg_UNPARSED_ARGUMENTS target)
+ if(TARGET "${target}")
+ list(APPEND targets ${target})
+ endif()
+ unset(target)
+ endif()
+
+ if("${targets}" STREQUAL "" AND "${arg_SOURCES}" STREQUAL "")
+ message(FATAL_ERROR "No SOURCE_TARGETS nor SOURCES were given.")
+ endif()
+
+ # Set up the name of the custom target.
+ set(lupdate_target "${arg_LUPDATE_TARGET}")
+ if("${lupdate_target}" STREQUAL "")
+ set(lupdate_target "${PROJECT_NAME}_lupdate")
+ set(lupdate_target_orig "${lupdate_target}")
+ set(n 1)
+ while(TARGET "${lupdate_target}")
+ set(lupdate_target "${lupdate_target_orig}${n}")
+ math(EXPR n "${n} + 1")
+ endwhile()
+ endif()
+
+ set(includePaths "")
+ set(sources "")
+ list(LENGTH targets targets_length)
+
if(arg_INCLUDE_DIRECTORIES)
- qt_internal_make_paths_absolute(includePaths "${arg_INCLUDE_DIRECTORIES}")
- else()
- set(includePaths "$<TARGET_PROPERTY:${target},INCLUDE_DIRECTORIES>")
+ qt_internal_make_paths_absolute(additionalIncludePaths "${arg_INCLUDE_DIRECTORIES}")
endif()
if(arg_SOURCES)
- qt_internal_make_paths_absolute(sources "${arg_SOURCES}")
- else()
- set(sources "$<TARGET_PROPERTY:${target},SOURCES>")
+ qt_internal_make_paths_absolute(additionalSources "${arg_SOURCES}")
endif()
+ set(lupdate_work_dir "${CMAKE_CURRENT_BINARY_DIR}/.lupdate")
qt_internal_make_paths_absolute(ts_files "${arg_TS_FILES}")
+ set(plurals_ts_file "")
+ set(raw_plurals_ts_file "")
+ if(NOT "${arg_PLURALS_TS_FILE}" STREQUAL "")
+ qt_internal_make_paths_absolute(plurals_ts_file "${arg_PLURALS_TS_FILE}")
+ _qt_internal_ensure_ts_file(TS_FILE "${plurals_ts_file}")
+ get_filename_component(raw_plurals_ts_file "${plurals_ts_file}" NAME)
+ string(PREPEND raw_plurals_ts_file "${lupdate_work_dir}/")
+ list(APPEND ts_files "${raw_plurals_ts_file}")
+ endif()
- set(lupdate_project_base "${CMAKE_CURRENT_BINARY_DIR}/.lupdate/${target}_project")
+ set(lupdate_project_base "${lupdate_work_dir}/${lupdate_target}_project")
set(lupdate_project_cmake "${lupdate_project_base}")
get_property(multi_config GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
if(multi_config)
@@ -176,19 +274,63 @@ function(qt6_add_lupdate target)
endif()
string(APPEND lupdate_project_cmake ".cmake")
set(lupdate_project_json "${lupdate_project_base}.json")
- file(GENERATE OUTPUT "${lupdate_project_cmake}"
- CONTENT "set(lupdate_project_file \"${CMAKE_CURRENT_LIST_FILE}\")
-set(lupdate_include_paths \"${includePaths}\")
-set(lupdate_sources \"${sources}\")
+ set(content "set(lupdate_project_file \"${CMAKE_CURRENT_LIST_FILE}\")
set(lupdate_translations \"${ts_files}\")
+set(lupdate_include_paths \"${additionalIncludePaths}\")
+set(lupdate_sources \"${additionalSources}\")
+set(lupdate_subproject_count ${targets_length})
+")
+ set(exclude_ts "\\.ts$")
+ set(n 1)
+ foreach(target IN LISTS targets)
+ set(includePaths "$<TARGET_PROPERTY:${target},INCLUDE_DIRECTORIES>")
+ set(sources "$<FILTER:$<TARGET_PROPERTY:${target},SOURCES>,EXCLUDE,${exclude_ts}>")
+ set(excluded "$<TARGET_PROPERTY:${target},QT_EXCLUDE_SOURCES_FROM_TRANSLATION>")
+ set(autogen_build_dir_genex "$<TARGET_PROPERTY:${target},AUTOGEN_BUILD_DIR>")
+ set(default_autogen_build_dir "$<TARGET_PROPERTY:${target},BINARY_DIR>/${target}_autogen")
+ set(autogen_dir "$<IF:$<BOOL:${autogen_build_dir_genex}>,${autogen_build_dir_genex},${default_autogen_build_dir}>")
+ string(APPEND content "
+set(lupdate_subproject${n}_source_dir \"$<TARGET_PROPERTY:${target},SOURCE_DIR>\")
+set(lupdate_subproject${n}_include_paths \"${includePaths}\")
+set(lupdate_subproject${n}_sources \"${sources}\")
+set(lupdate_subproject${n}_excluded \"${excluded}\")
+set(lupdate_subproject${n}_autogen_dir \"${autogen_dir}\")
")
+ math(EXPR n "${n} + 1")
+ endforeach()
+ file(GENERATE OUTPUT "${lupdate_project_cmake}" CONTENT "${content}")
- add_custom_target(${target}_lupdate
+ _qt_internal_get_tool_wrapper_script_path(tool_wrapper)
+ set(lupdate_command
+ COMMAND
+ "${tool_wrapper}"
+ $<TARGET_FILE:${QT_CMAKE_EXPORT_NAMESPACE}::lupdate>)
+ set(prepare_native_ts_command "")
+ set(finish_native_ts_command "")
+ if(NOT plurals_ts_file STREQUAL "")
+ # Copy the existing .ts file to preserve already translated strings.
+ set(prepare_native_ts_command
+ COMMAND
+ "${CMAKE_COMMAND}" -E copy "${plurals_ts_file}" "${raw_plurals_ts_file}"
+ )
+
+ # Filter out the non-numerus forms with lconvert.
+ set(finish_native_ts_command
+ COMMAND
+ "${tool_wrapper}"
+ $<TARGET_FILE:${QT_CMAKE_EXPORT_NAMESPACE}::lconvert>
+ -pluralonly
+ -i "${raw_plurals_ts_file}"
+ -o "${plurals_ts_file}"
+ )
+ endif()
+ add_custom_target(${lupdate_target}
COMMAND "${CMAKE_COMMAND}" "-DIN_FILE=${lupdate_project_cmake}"
"-DOUT_FILE=${lupdate_project_json}"
-P "${_Qt6_LINGUIST_TOOLS_DIR}/GenerateLUpdateProject.cmake"
- COMMAND ${QT_CMAKE_EXPORT_NAMESPACE}::lupdate -project "${lupdate_project_json}"
- ${arg_OPTIONS}
+ ${prepare_native_ts_command}
+ ${lupdate_command} -project "${lupdate_project_json}" ${arg_OPTIONS}
+ ${finish_native_ts_command}
DEPENDS ${QT_CMAKE_EXPORT_NAMESPACE}::lupdate
VERBATIM)
@@ -197,18 +339,62 @@ set(lupdate_translations \"${ts_files}\")
endif()
if(NOT arg_NO_GLOBAL_TARGET)
- if(NOT TARGET ${QT_GLOBAL_LUPDATE_TARGET})
- add_custom_target(${QT_GLOBAL_LUPDATE_TARGET})
+ _qt_internal_add_phony_target(${QT_GLOBAL_LUPDATE_TARGET}
+ WARNING_VARIABLE QT_NO_GLOBAL_LUPDATE_TARGET_CREATION_WARNING
+ )
+ _qt_internal_add_phony_target_dependencies(${QT_GLOBAL_LUPDATE_TARGET}
+ ${lupdate_target}
+ )
+ endif()
+endfunction()
+
+function(_qt_internal_store_languages_from_ts_files_in_targets targets ts_files)
+ if(NOT APPLE)
+ return()
+ endif()
+ set(supported_languages "")
+ foreach(ts_file IN LISTS ts_files)
+ execute_process(COMMAND /usr/bin/xmllint --xpath "string(/TS/@language)" ${ts_file}
+ OUTPUT_STRIP_TRAILING_WHITESPACE
+ OUTPUT_VARIABLE language_code
+ ERROR_VARIABLE xmllint_error)
+ if(NOT language_code OR xmllint_error)
+ message(WARNING "Failed to resolve language code for ${ts_file}. "
+ "Please update CFBundleLocalizations in your Info.plist manually.")
endif()
- add_dependencies(${QT_GLOBAL_LUPDATE_TARGET} ${target}_lupdate)
+ endforeach()
+ foreach(target IN LISTS targets)
+ set_property(TARGET "${target}" APPEND PROPERTY
+ _qt_apple_supported_languages "${supported_languages}"
+ )
+ endforeach()
+endfunction()
+
+# Store in ${out_var} the file path to the .qm file that will be generated from the given .ts file.
+function(_qt_internal_generated_qm_file_path out_var ts_file default_out_dir)
+ get_filename_component(qm ${ts_file} NAME_WLE)
+ string(APPEND qm ".qm")
+ get_source_file_property(output_location ${ts_file} OUTPUT_LOCATION)
+ if(output_location)
+ if(NOT IS_ABSOLUTE "${output_location}")
+ get_filename_component(output_location "${output_location}" ABSOLUTE
+ BASE_DIR "${default_out_dir}")
+ endif()
+ string(PREPEND qm "${output_location}/")
+ else()
+ string(PREPEND qm "${default_out_dir}/")
endif()
+ set("${out_var}" "${qm}" PARENT_SCOPE)
endfunction()
-function(qt6_add_lrelease target)
+function(qt6_add_lrelease)
set(options
- NO_TARGET_DEPENDENCY
+ NO_TARGET_DEPENDENCY ### Qt7: remove together with legacy signature
+ EXCLUDE_FROM_ALL
NO_GLOBAL_TARGET)
set(oneValueArgs
+ __QT_INTERNAL_DEFAULT_QM_OUT_DIR
+ LRELEASE_TARGET
QM_FILES_OUTPUT_VARIABLE)
set(multiValueArgs
TS_FILES
@@ -216,43 +402,88 @@ function(qt6_add_lrelease target)
cmake_parse_arguments(arg "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
qt_internal_make_paths_absolute(ts_files "${arg_TS_FILES}")
+ # Support the old command signature that takes one target as first argument.
+ set(legacy_signature_used FALSE)
+ set(legacy_target "")
+ list(LENGTH arg_UNPARSED_ARGUMENTS unparsed_arguments_count)
+ if(unparsed_arguments_count GREATER 0)
+ list(POP_FRONT arg_UNPARSED_ARGUMENTS legacy_target)
+ if(TARGET "${legacy_target}")
+ set(legacy_signature_used TRUE)
+ else()
+ set(legacy_target "")
+ endif()
+ endif()
+
+ # Set up the driving target.
+ set(lrelease_target "${arg_LRELEASE_TARGET}")
+ if("${lrelease_target}" STREQUAL "")
+ set(lrelease_target "${PROJECT_NAME}_lrelease")
+ set(lrelease_target_orig "${lrelease_target}")
+ set(n 1)
+ while(TARGET "${lrelease_target}")
+ set(lrelease_target "${lrelease_target_orig}${n}")
+ math(EXPR n "${n} + 1")
+ endwhile()
+ endif()
+
+ _qt_internal_get_tool_wrapper_script_path(tool_wrapper)
+ set(lrelease_command
+ COMMAND
+ "${tool_wrapper}"
+ $<TARGET_FILE:${QT_CMAKE_EXPORT_NAMESPACE}::lrelease>)
+
+ set(default_qm_out_dir "${CMAKE_CURRENT_BINARY_DIR}")
+ if(NOT "${arg___QT_INTERNAL_DEFAULT_QM_OUT_DIR}" STREQUAL "")
+ set(default_qm_out_dir "${arg___QT_INTERNAL_DEFAULT_QM_OUT_DIR}")
+ endif()
+
set(qm_files "")
foreach(ts_file ${ts_files})
if(NOT EXISTS "${ts_file}")
message(WARNING "Translation file '${ts_file}' does not exist. "
- "Consider building the target '${target}_lupdate' to create an initial "
+ "Consider building the target 'update_translations' to create an initial "
"version of that file.")
-
- # Provide a command that creates an initial .ts file with the right language set.
- # The language is guessed by lupdate from the file name.
- add_custom_command(OUTPUT ${ts_file}
- COMMAND ${QT_CMAKE_EXPORT_NAMESPACE}::lupdate -ts ${ts_file}
- VERBATIM)
- endif()
- get_filename_component(qm ${ts_file} NAME_WLE)
- string(APPEND qm ".qm")
- get_source_file_property(output_location ${ts_file} OUTPUT_LOCATION)
- if(output_location)
- if(NOT IS_ABSOLUTE "${output_location}")
- get_filename_component(output_location "${output_location}" ABSOLUTE
- BASE_DIR "${CMAKE_CURRENT_BINARY_DIR}")
- endif()
- file(MAKE_DIRECTORY "${output_location}")
- string(PREPEND qm "${output_location}/")
- else()
- string(PREPEND qm "${CMAKE_CURRENT_BINARY_DIR}/")
+ _qt_internal_ensure_ts_file(TS_FILE "${ts_file}")
endif()
+
+ _qt_internal_generated_qm_file_path(qm "${ts_file}" "${default_qm_out_dir}")
+ get_filename_component(qm_dir "${qm}" DIRECTORY)
add_custom_command(OUTPUT ${qm}
- COMMAND ${QT_CMAKE_EXPORT_NAMESPACE}::lrelease
- ${arg_OPTIONS} ${ts_file} -qm ${qm}
- DEPENDS ${QT_CMAKE_EXPORT_NAMESPACE}::lrelease ${ts_file}
+ COMMAND "${CMAKE_COMMAND}" -E make_directory "${qm_dir}"
+ ${lrelease_command} ${arg_OPTIONS} ${ts_file} -qm ${qm}
+ DEPENDS ${QT_CMAKE_EXPORT_NAMESPACE}::lrelease "${ts_file}"
VERBATIM)
list(APPEND qm_files "${qm}")
+
+ # QTBUG-103470: Save the target responsible for driving the build of the custom command
+ # into an internal source file property. It will be added as a dependency for targets
+ # created by _qt_internal_process_resource, to avoid the Xcode issue of not allowing
+ # multiple targets depending on the output, without having a common target ancestor.
+ set(scope_args "")
+ if(legacy_signature_used AND CMAKE_VERSION VERSION_GREATER_EQUAL "3.18")
+ set(scope_args TARGET_DIRECTORY ${legacy_target})
+ endif()
+ set_source_files_properties("${qm}" ${scope_args} PROPERTIES
+ _qt_resource_target_dependency "${lrelease_target}"
+ )
endforeach()
- add_custom_target(${target}_lrelease DEPENDS ${qm_files})
- if(NOT arg_NO_TARGET_DEPENDENCY)
- add_dependencies(${target} ${target}_lrelease)
+ if(legacy_signature_used)
+ _qt_internal_store_languages_from_ts_files_in_targets("${legacy_target}" "${ts_files}")
+ endif()
+
+ if(legacy_signature_used)
+ add_custom_target(${lrelease_target} DEPENDS ${qm_files})
+ if(NOT arg_NO_TARGET_DEPENDENCY)
+ add_dependencies(${legacy_target} ${lrelease_target})
+ endif()
+ else()
+ set(maybe_all ALL)
+ if(arg_EXCLUDE_FROM_ALL)
+ set(maybe_all "")
+ endif()
+ add_custom_target(${lrelease_target} ${maybe_all} DEPENDS ${qm_files})
endif()
if(NOT DEFINED QT_GLOBAL_LRELEASE_TARGET)
@@ -263,7 +494,7 @@ function(qt6_add_lrelease target)
if(NOT TARGET ${QT_GLOBAL_LRELEASE_TARGET})
add_custom_target(${QT_GLOBAL_LRELEASE_TARGET})
endif()
- add_dependencies(${QT_GLOBAL_LRELEASE_TARGET} ${target}_lrelease)
+ add_dependencies(${QT_GLOBAL_LRELEASE_TARGET} ${lrelease_target})
endif()
if(NOT "${arg_QM_FILES_OUTPUT_VARIABLE}" STREQUAL "")
@@ -271,22 +502,40 @@ function(qt6_add_lrelease target)
endif()
endfunction()
-# This function is currently in Technical Preview.
-# It's signature and behavior might change.
-function(qt6_add_translations target)
- set(options)
+function(qt6_add_translations)
+ set(options
+ IMMEDIATE_CALL
+ NO_GENERATE_PLURALS_TS_FILE)
set(oneValueArgs
+ __QT_INTERNAL_DEFAULT_QM_OUT_DIR
+ LUPDATE_TARGET
+ LRELEASE_TARGET
QM_FILES_OUTPUT_VARIABLE
RESOURCE_PREFIX
OUTPUT_TARGETS)
set(multiValueArgs
+ TARGETS
+ SOURCE_TARGETS
TS_FILES
+ TS_FILE_BASE
+ TS_FILE_DIR
+ PLURALS_TS_FILE
SOURCES
INCLUDE_DIRECTORIES
LUPDATE_OPTIONS
LRELEASE_OPTIONS)
cmake_parse_arguments(arg "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
+ set(targets "${arg_TARGETS}")
+ if(NOT "${arg_UNPARSED_ARGUMENTS}" STREQUAL "")
+ list(POP_FRONT arg_UNPARSED_ARGUMENTS target)
+ list(PREPEND targets "${target}")
+ unset(target)
+ set(arg_TARGETS ${targets}) # to forward this argument
+ endif()
+ if(targets STREQUAL "")
+ message(FATAL_ERROR "No targets provided.")
+ endif()
if(DEFINED arg_RESOURCE_PREFIX AND DEFINED arg_QM_FILES_OUTPUT_VARIABLE)
message(FATAL_ERROR "QM_FILES_OUTPUT_VARIABLE cannot be specified "
"together with RESOURCE_PREFIX.")
@@ -299,23 +548,166 @@ function(qt6_add_translations target)
set(arg_RESOURCE_PREFIX "/i18n")
endif()
- qt6_add_lupdate(${target}
+ # Determine the .ts file paths if necessary. This must happen before function deferral.
+ if(NOT DEFINED arg_TS_FILES)
+ if(NOT DEFINED arg_TS_FILE_DIR)
+ set(arg_TS_FILE_DIR "${CMAKE_CURRENT_SOURCE_DIR}")
+ endif()
+ if(NOT DEFINED arg_TS_FILE_BASE)
+ set(arg_TS_FILE_BASE "${PROJECT_NAME}")
+ string(REPLACE " " "-" arg_TS_FILE_BASE "${arg_TS_FILE_BASE}")
+ endif()
+ set(arg_TS_FILES "")
+ foreach(lang IN LISTS QT_I18N_TRANSLATED_LANGUAGES)
+ list(APPEND arg_TS_FILES "${arg_TS_FILE_DIR}/${arg_TS_FILE_BASE}_${lang}.ts")
+ endforeach()
+
+ # Default the source language to "en" in case the user doesn't use
+ # qt_standard_project_setup.
+ set(source_lang en)
+ if(NOT "${QT_I18N_SOURCE_LANGUAGE}" STREQUAL "")
+ set(source_lang ${QT_I18N_SOURCE_LANGUAGE})
+ endif()
+
+ # Determine the path to the plurals-only .ts file if necessary.
+ if(NOT arg_NO_GENERATE_PLURALS_TS_FILE
+ AND NOT DEFINED arg_PLURALS_TS_FILE
+ AND NOT "${source_lang}" IN_LIST QT_I18N_TRANSLATED_LANGUAGES)
+ set(arg_PLURALS_TS_FILE
+ "${arg_TS_FILE_DIR}/${arg_TS_FILE_BASE}_${source_lang}.ts")
+ endif()
+ endif()
+
+ # Defer the actual function call if SOURCE_TARGETS was not given and an immediate call was not
+ # requested.
+ set(source_targets "${arg_SOURCE_TARGETS}")
+ if(source_targets STREQUAL "" AND NOT arg_IMMEDIATE_CALL)
+ if(DEFINED arg_OUTPUT_TARGETS)
+ # We don't have the infrastructure to predict the resource target names.
+ message(FATAL_ERROR "Deferring qt6_add_translations is not supported with "
+ "OUTPUT_TARGETS. Pass IMMEDIATE_CALL or specify SOURCE_TARGETS.")
+ endif()
+ if(CMAKE_VERSION VERSION_LESS "3.19")
+ message(WARNING
+ "qt6_add_translations cannot defer function calls with this CMake version. "
+ "Only targets created prior to the qt6_add_translations call are used for i18n. "
+ "To avoid this warning, make sure this command is called at the end of the "
+ "top-level directory scope and pass the IMMEDIATE_CALL keyword. "
+ "Alternatively, upgrade to CMake 3.19 or newer."
+ )
+ qt6_add_translations(IMMEDIATE_CALL ${ARGV})
+ else()
+ # Predict the names of generated .qm files.
+ if(DEFINED arg_QM_FILES_OUTPUT_VARIABLE)
+ set(qm_files "")
+ foreach(ts_file IN LISTS arg_TS_FILES arg_PLURALS_TS_FILE)
+ _qt_internal_generated_qm_file_path(qm_file "${ts_file}"
+ "${CMAKE_CURRENT_BINARY_DIR}")
+ list(APPEND qm_files "${qm_file}")
+ endforeach()
+ set("${arg_QM_FILES_OUTPUT_VARIABLE}" "${qm_files}" PARENT_SCOPE)
+ endif()
+
+ # Forward options.
+ set(forwarded_args
+ IMMEDIATE_CALL
+ __QT_INTERNAL_DEFAULT_QM_OUT_DIR "${CMAKE_CURRENT_BINARY_DIR}"
+ )
+ foreach(keyword IN LISTS options)
+ if(arg_${keyword})
+ list(APPEND forwarded_args ${keyword})
+ endif()
+ endforeach()
+
+ # Forward one-value and multi-value arguments.
+ # Filter path variables. We will forward those separately.
+ set(to_forward ${oneValueArgs} ${multiValueArgs})
+ set(path_variables
+ TS_FILES
+ PLURALS_TS_FILE
+ SOURCES
+ INCLUDE_DIRECTORIES
+ )
+ set(ignored_variables
+ TS_FILE_BASE
+ TS_FILE_DIR
+ )
+ list(REMOVE_ITEM to_forward ${path_variables} ${ignored_variables})
+ foreach(keyword IN LISTS to_forward)
+ if(DEFINED arg_${keyword})
+ list(APPEND forwarded_args ${keyword} ${arg_${keyword}})
+ endif()
+ endforeach()
+
+ # Make variables that specify paths absolute.
+ # Relative paths are considered to be relative to the current source dir.
+ foreach(var IN LISTS path_variables)
+ qt_internal_make_paths_absolute(absolute_paths ${arg_${var}})
+ if(NOT "${absolute_paths}" STREQUAL "")
+ list(APPEND forwarded_args ${var} ${absolute_paths})
+ endif()
+ endforeach()
+
+ # Schedule this command to be called at the end of the project's source dir.
+ cmake_language(EVAL CODE
+ "cmake_language(DEFER
+ DIRECTORY \"${PROJECT_SOURCE_DIR}\"
+ CALL qt6_add_translations ${forwarded_args})")
+ endif()
+ return()
+ endif()
+
+ if(source_targets STREQUAL "")
+ qt6_collect_translation_source_targets(source_targets)
+ endif()
+ qt6_add_lupdate(
+ SOURCE_TARGETS "${source_targets}"
+ LUPDATE_TARGET "${arg_LUPDATE_TARGET}"
TS_FILES "${arg_TS_FILES}"
+ PLURALS_TS_FILE "${arg_PLURALS_TS_FILE}"
SOURCES "${arg_SOURCES}"
INCLUDE_DIRECTORIES "${arg_INCLUDE_DIRECTORIES}"
- OPTIONS "${arg_LUPDATE_OPTIONS}")
- qt6_add_lrelease(${target}
- TS_FILES "${arg_TS_FILES}"
+ OPTIONS "${arg_LUPDATE_OPTIONS}"
+ )
+ qt6_add_lrelease(
+ LRELEASE_TARGET "${arg_LRELEASE_TARGET}"
+ TS_FILES "${arg_TS_FILES}" ${arg_PLURALS_TS_FILE}
QM_FILES_OUTPUT_VARIABLE qm_files
- OPTIONS "${arg_LRELEASE_OPTIONS}")
+ OPTIONS "${arg_LRELEASE_OPTIONS}"
+ __QT_INTERNAL_DEFAULT_QM_OUT_DIR "${arg___QT_INTERNAL_DEFAULT_QM_OUT_DIR}"
+ )
+
+ if("${QT_I18N_TRANSLATED_LANGUAGES}" STREQUAL "")
+ _qt_internal_store_languages_from_ts_files_in_targets("${targets}" "${arg_TS_FILES}")
+ endif()
+
+ # Mark .qm files as GENERATED, so that calling _qt_internal_expose_deferred_files_to_ide
+ # doesn't cause an error at generation time saying "Cannot find source file:" when
+ # qt6_add_lrelease is called from a subdirectory different than the target.
+ # The issue happend when the user project called cmake_minimum_required(VERSION)
+ # with a version less than 3.20 or set the CMP0118 policy value to OLD.
+ set(scope_args "")
+ if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.18")
+ set(scope_args TARGET_DIRECTORY ${targets})
+ endif()
+ set_source_files_properties(${qm_files}
+ ${scope_args}
+ PROPERTIES GENERATED TRUE
+ )
+
if(NOT "${arg_RESOURCE_PREFIX}" STREQUAL "")
- qt6_add_resources(${target} "translations"
- PREFIX "${arg_RESOURCE_PREFIX}"
- BASE "${CMAKE_CURRENT_BINARY_DIR}"
- OUTPUT_TARGETS out_targets
- FILES ${qm_files})
+ set(accumulated_out_targets "")
+ foreach(target IN LISTS targets)
+ get_target_property(target_binary_dir ${target} BINARY_DIR)
+ qt6_add_resources(${target} "${target}_translations"
+ PREFIX "${arg_RESOURCE_PREFIX}"
+ BASE "${target_binary_dir}"
+ OUTPUT_TARGETS out_targets
+ FILES ${qm_files})
+ list(APPEND accumulated_out_targets ${out_targets})
+ endforeach()
if(DEFINED arg_OUTPUT_TARGETS)
- set("${arg_OUTPUT_TARGETS}" "${out_targets}" PARENT_SCOPE)
+ set("${arg_OUTPUT_TARGETS}" "${accumulated_out_targets}" PARENT_SCOPE)
endif()
endif()
if(NOT "${arg_QM_FILES_OUTPUT_VARIABLE}" STREQUAL "")
@@ -340,6 +732,14 @@ if(NOT QT_NO_CREATE_VERSIONLESS_FUNCTIONS)
endif()
set("${_qm_files}" "${${_qm_files}}" PARENT_SCOPE)
endfunction()
+ function(qt_collect_translation_source_targets out_var)
+ if(QT_DEFAULT_MAJOR_VERSION EQUAL 6)
+ qt6_collect_translation_source_targets("${out_var}" ${ARGN})
+ else()
+ message(FATAL_ERROR "qt_collect_translation_source_targets() is only available in Qt 6.")
+ endif()
+ set("${out_var}" "${${out_var}}" PARENT_SCOPE)
+ endfunction()
function(qt_add_lupdate)
if(QT_DEFAULT_MAJOR_VERSION EQUAL 6)
qt6_add_lupdate(${ARGN})