Skip to content

Commit d5054be

Browse files
committed
cmake: Introduce translate.cmake script for translate target
Using `file(GLOB)` in the generates step is discouraged because the globbing result may be out of date when the target is built. Performing the globbing in a script that is executed as the build target means the result is always reproducable and the overhead of globbing is only paid when used. As a follow up, the dependency on `sed` may be removed by performing the replacement with cmake. Also, the logic from extract_strings_qt.py can be migrated to cmake.
1 parent 57e8f34 commit d5054be

File tree

2 files changed

+94
-53
lines changed

2 files changed

+94
-53
lines changed

share/qt/translate.cmake

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
# Copyright (c) 2025 The Bitcoin Core developers
2+
# Distributed under the MIT software license, see the accompanying
3+
# file COPYING or http://www.opensource.org/licenses/mit-license.php.
4+
5+
set(input_variables
6+
PROJECT_SOURCE_DIR
7+
COPYRIGHT_HOLDERS
8+
LCONVERT_EXECUTABLE
9+
LUPDATE_EXECUTABLE
10+
PYTHON_EXECUTABLE
11+
SED_EXECUTABLE
12+
XGETTEXT_EXECUTABLE
13+
)
14+
15+
foreach(var IN LISTS input_variables)
16+
if(NOT DEFINED ${var})
17+
message(FATAL_ERROR "Variable '${var}' is not defined!")
18+
endif()
19+
endforeach()
20+
21+
file(GLOB_RECURSE translatable_sources
22+
"${PROJECT_SOURCE_DIR}/src/*.h"
23+
"${PROJECT_SOURCE_DIR}/src/*.cpp"
24+
"${PROJECT_SOURCE_DIR}/src/*.mm"
25+
)
26+
27+
file(GLOB_RECURSE qt_translatable_sources
28+
"${PROJECT_SOURCE_DIR}/src/qt/*.h"
29+
"${PROJECT_SOURCE_DIR}/src/qt/*.cpp"
30+
"${PROJECT_SOURCE_DIR}/src/qt/*.mm"
31+
)
32+
33+
file(GLOB ui_files
34+
"${PROJECT_SOURCE_DIR}/src/qt/forms/*.ui"
35+
)
36+
37+
set(subtrees crc32c crypto/ctaes leveldb minisketch secp256k1)
38+
set(exclude_dirs bench compat crypto support test univalue)
39+
foreach(directory IN LISTS subtrees exclude_dirs)
40+
list(FILTER translatable_sources
41+
EXCLUDE REGEX "${PROJECT_SOURCE_DIR}/src/${directory}/.*"
42+
)
43+
endforeach()
44+
45+
execute_process(
46+
COMMAND ${CMAKE_COMMAND} -E env
47+
XGETTEXT=${XGETTEXT_EXECUTABLE}
48+
COPYRIGHT_HOLDERS=${COPYRIGHT_HOLDERS}
49+
${PYTHON_EXECUTABLE}
50+
${CMAKE_CURRENT_LIST_DIR}/extract_strings_qt.py
51+
${translatable_sources}
52+
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/src
53+
COMMAND_ERROR_IS_FATAL ANY
54+
)
55+
56+
execute_process(
57+
COMMAND ${LUPDATE_EXECUTABLE}
58+
-no-obsolete
59+
-I ${PROJECT_SOURCE_DIR}/src
60+
-locations relative
61+
${ui_files}
62+
${qt_translatable_sources}
63+
${PROJECT_SOURCE_DIR}/src/qt/bitcoinstrings.cpp
64+
-ts ${PROJECT_SOURCE_DIR}/src/qt/locale/bitcoin_en.ts
65+
COMMAND_ERROR_IS_FATAL ANY
66+
)
67+
68+
execute_process(
69+
COMMAND ${LCONVERT_EXECUTABLE}
70+
-drop-translations
71+
-o ${PROJECT_SOURCE_DIR}/src/qt/locale/bitcoin_en.xlf
72+
-i ${PROJECT_SOURCE_DIR}/src/qt/locale/bitcoin_en.ts
73+
COMMAND_ERROR_IS_FATAL ANY
74+
)
75+
76+
execute_process(
77+
COMMAND ${SED_EXECUTABLE}
78+
-i.old
79+
-e "s|source-language=\"en\" target-language=\"en\"|source-language=\"en\"|"
80+
-e "/<target xml:space=\"preserve\"><\\/target>/d"
81+
${PROJECT_SOURCE_DIR}/src/qt/locale/bitcoin_en.xlf
82+
COMMAND_ERROR_IS_FATAL ANY
83+
)
84+
85+
file(REMOVE "${PROJECT_SOURCE_DIR}/src/qt/locale/bitcoin_en.xlf.old")

src/qt/CMakeLists.txt

Lines changed: 9 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -289,44 +289,6 @@ if(BUILD_GUI_TESTS)
289289
add_subdirectory(test)
290290
endif()
291291

292-
293-
# Gets sources to be parsed to gather translatable strings.
294-
function(get_translatable_sources var)
295-
set(result)
296-
set(targets)
297-
foreach(dir IN ITEMS ${ARGN})
298-
get_directory_property(dir_targets DIRECTORY ${PROJECT_SOURCE_DIR}/${dir} BUILDSYSTEM_TARGETS)
299-
list(APPEND targets ${dir_targets})
300-
endforeach()
301-
foreach(target IN LISTS targets)
302-
get_target_property(target_sources ${target} SOURCES)
303-
if(target_sources)
304-
foreach(source IN LISTS target_sources)
305-
# Get an expression from the generator expression, if any.
306-
if(source MATCHES ":([^>]+)>$")
307-
set(source ${CMAKE_MATCH_1})
308-
endif()
309-
cmake_path(GET source EXTENSION LAST_ONLY ext)
310-
if(ext STREQUAL ".qrc")
311-
continue()
312-
endif()
313-
if(NOT IS_ABSOLUTE source)
314-
get_target_property(target_source_dir ${target} SOURCE_DIR)
315-
cmake_path(APPEND target_source_dir ${source} OUTPUT_VARIABLE source)
316-
endif()
317-
get_property(is_generated
318-
SOURCE ${source} TARGET_DIRECTORY ${target}
319-
PROPERTY GENERATED
320-
)
321-
if(NOT is_generated)
322-
list(APPEND result ${source})
323-
endif()
324-
endforeach()
325-
endif()
326-
endforeach()
327-
set(${var} ${result} PARENT_SCOPE)
328-
endfunction()
329-
330292
find_program(XGETTEXT_EXECUTABLE xgettext)
331293
find_program(SED_EXECUTABLE sed)
332294
if(NOT XGETTEXT_EXECUTABLE)
@@ -338,20 +300,14 @@ elseif(NOT SED_EXECUTABLE)
338300
COMMAND ${CMAKE_COMMAND} -E echo "Error: GNU sed not found"
339301
)
340302
else()
341-
set(translatable_sources_directories src src/qt src/util)
342-
if(ENABLE_WALLET)
343-
list(APPEND translatable_sources_directories src/wallet)
344-
endif()
345-
get_translatable_sources(translatable_sources ${translatable_sources_directories})
346-
get_translatable_sources(qt_translatable_sources src/qt)
347-
file(GLOB ui_files ${CMAKE_CURRENT_SOURCE_DIR}/forms/*.ui)
348-
add_custom_target(translate
349-
COMMAND ${CMAKE_COMMAND} -E env XGETTEXT=${XGETTEXT_EXECUTABLE} COPYRIGHT_HOLDERS=${COPYRIGHT_HOLDERS} $<TARGET_FILE:Python3::Interpreter> ${PROJECT_SOURCE_DIR}/share/qt/extract_strings_qt.py ${translatable_sources}
350-
COMMAND Qt6::lupdate -no-obsolete -I ${PROJECT_SOURCE_DIR}/src -locations relative ${CMAKE_CURRENT_SOURCE_DIR}/bitcoinstrings.cpp ${ui_files} ${qt_translatable_sources} -ts ${CMAKE_CURRENT_SOURCE_DIR}/locale/bitcoin_en.ts
351-
COMMAND Qt6::lconvert -drop-translations -o ${CMAKE_CURRENT_SOURCE_DIR}/locale/bitcoin_en.xlf -i ${CMAKE_CURRENT_SOURCE_DIR}/locale/bitcoin_en.ts
352-
COMMAND ${SED_EXECUTABLE} -i.old -e "s|source-language=\"en\" target-language=\"en\"|source-language=\"en\"|" -e "/<target xml:space=\"preserve\"><\\/target>/d" ${CMAKE_CURRENT_SOURCE_DIR}/locale/bitcoin_en.xlf
353-
COMMAND ${CMAKE_COMMAND} -E rm ${CMAKE_CURRENT_SOURCE_DIR}/locale/bitcoin_en.xlf.old
354-
WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/src
355-
VERBATIM
303+
add_custom_target(translate COMMAND ${CMAKE_COMMAND}
304+
-D "PROJECT_SOURCE_DIR=${PROJECT_SOURCE_DIR}"
305+
-D "COPYRIGHT_HOLDERS=${COPYRIGHT_HOLDERS}"
306+
-D "LCONVERT_EXECUTABLE=$<TARGET_FILE:Qt6::lconvert>"
307+
-D "LUPDATE_EXECUTABLE=$<TARGET_FILE:Qt6::lupdate>"
308+
-D "PYTHON_EXECUTABLE=$<TARGET_FILE:Python3::Interpreter>"
309+
-D "SED_EXECUTABLE=${SED_EXECUTABLE}"
310+
-D "XGETTEXT_EXECUTABLE=${XGETTEXT_EXECUTABLE}"
311+
-P ${PROJECT_SOURCE_DIR}/share/qt/translate.cmake
356312
)
357313
endif()

0 commit comments

Comments
 (0)