From 3c4a109aa821cbf1e46a67275b4f456673ed13d8 Mon Sep 17 00:00:00 2001 From: Daniel Pfeifer Date: Mon, 18 Aug 2025 10:01:53 +0200 Subject: [PATCH] cmake: Drop python dependency for translate Resolves #33146 --- share/qt/extract_strings_qt.py | 85 ---------------------------------- share/qt/translate.cmake | 68 +++++++++++++++++++++++---- src/qt/CMakeLists.txt | 1 - 3 files changed, 58 insertions(+), 96 deletions(-) delete mode 100755 share/qt/extract_strings_qt.py diff --git a/share/qt/extract_strings_qt.py b/share/qt/extract_strings_qt.py deleted file mode 100755 index 4297143023e..00000000000 --- a/share/qt/extract_strings_qt.py +++ /dev/null @@ -1,85 +0,0 @@ -#!/usr/bin/env python3 -# Copyright (c) 2012-2021 The Bitcoin Core developers -# Distributed under the MIT software license, see the accompanying -# file COPYING or http://www.opensource.org/licenses/mit-license.php. -''' -Extract _("...") strings for translation and convert to Qt stringdefs so that -they can be picked up by Qt linguist. -''' -from subprocess import Popen, PIPE -import operator -import os -import sys - -OUT_CPP="qt/bitcoinstrings.cpp" -EMPTY=['""'] - -def parse_po(text): - """ - Parse 'po' format produced by xgettext. - Return a list of (msgid,msgstr) tuples. - """ - messages = [] - msgid = [] - msgstr = [] - in_msgid = False - in_msgstr = False - - for line in text.split('\n'): - line = line.rstrip('\r') - if line.startswith('msgid '): - if in_msgstr: - messages.append((msgid, msgstr)) - in_msgstr = False - # message start - in_msgid = True - - msgid = [line[6:]] - elif line.startswith('msgstr '): - in_msgid = False - in_msgstr = True - msgstr = [line[7:]] - elif line.startswith('"'): - if in_msgid: - msgid.append(line) - if in_msgstr: - msgstr.append(line) - - if in_msgstr: - messages.append((msgid, msgstr)) - - return messages - -files = sys.argv[1:] - -# xgettext -n --keyword=_ $FILES -XGETTEXT=os.getenv('XGETTEXT', 'xgettext') -if not XGETTEXT: - print('Cannot extract strings: xgettext utility is not installed or not configured.',file=sys.stderr) - print('Please install package "gettext" and re-run \'cmake -B build\'.',file=sys.stderr) - sys.exit(1) -child = Popen([XGETTEXT,'--output=-','--from-code=utf-8','-n','--keyword=_'] + files, stdout=PIPE) -(out, err) = child.communicate() - -messages = parse_po(out.decode('utf-8')) - -f = open(OUT_CPP, 'w', encoding="utf8") -f.write(""" - -#include - -// Automatically generated by extract_strings_qt.py -#ifdef __GNUC__ -#define UNUSED __attribute__((unused)) -#else -#define UNUSED -#endif -""") -f.write('static const char UNUSED *bitcoin_strings[] = {\n') -f.write('QT_TRANSLATE_NOOP("bitcoin-core", "%s"),\n' % (os.getenv('COPYRIGHT_HOLDERS'),)) -messages.sort(key=operator.itemgetter(0)) -for (msgid, msgstr) in messages: - if msgid != EMPTY: - f.write('QT_TRANSLATE_NOOP("bitcoin-core", %s),\n' % ('\n'.join(msgid))) -f.write('};\n') -f.close() diff --git a/share/qt/translate.cmake b/share/qt/translate.cmake index a4eeef96038..ed32c6dd5b4 100644 --- a/share/qt/translate.cmake +++ b/share/qt/translate.cmake @@ -2,12 +2,13 @@ # Distributed under the MIT software license, see the accompanying # file COPYING or http://www.opensource.org/licenses/mit-license.php. +cmake_minimum_required(VERSION 3.22) + set(input_variables PROJECT_SOURCE_DIR COPYRIGHT_HOLDERS LCONVERT_EXECUTABLE LUPDATE_EXECUTABLE - PYTHON_EXECUTABLE XGETTEXT_EXECUTABLE ) @@ -17,6 +18,60 @@ foreach(var IN LISTS input_variables) endif() endforeach() +# Extract _("...") strings for translation and convert to Qt stringdefs so that +# they can be picked up by Qt linguist. +function(extract_strings output) + execute_process( + COMMAND ${XGETTEXT_EXECUTABLE} + --output=bitcoinstrings.po + --no-location + --from-code=utf-8 + --keyword=_ + ${ARGN} + COMMAND_ERROR_IS_FATAL ANY + ) + + file(STRINGS "bitcoinstrings.po" text ENCODING "UTF-8") + + set(messages "${COPYRIGHT_HOLDERS}") + foreach(line IN LISTS text) + if(line MATCHES "^msgid \"(.*)\"$") + set(msgid "${CMAKE_MATCH_1}") + elseif(line MATCHES "^\"(.*)\"$") + string(APPEND msgid "${CMAKE_MATCH_1}") + elseif(line MATCHES "^msgstr .*$" AND NOT msgid STREQUAL "") + # CMake uses ';' as a list separator. + # We need to temporarily replace that in order to keep strings intact. + string(REPLACE ";" "" msgid "${msgid}") + list(APPEND messages "${msgid}") + endif() + endforeach() + + set(content [[// Automatically generated by translate.cmake + +#include + +#ifdef __GNUC__ +#define UNUSED __attribute__((unused)) +#else +#define UNUSED +#endif + +static const char UNUSED *bitcoin_strings[] = { +]]) + + set(prefix "QT_TRANSLATE_NOOP(\"bitcoin-core\", \"") + set(suffix "\"),\n") + + list(SORT messages) + list(JOIN messages "${suffix}${prefix}" messages_str) + string(APPEND content "${prefix}${messages_str}${suffix}") + string(APPEND content "};\n") + string(REPLACE "" ";" content "${content}") + + file(WRITE "${output}" "${content}") +endfunction() + file(GLOB_RECURSE translatable_sources "${PROJECT_SOURCE_DIR}/src/*.h" "${PROJECT_SOURCE_DIR}/src/*.cpp" @@ -41,15 +96,8 @@ foreach(directory IN LISTS subtrees exclude_dirs) ) endforeach() -execute_process( - COMMAND ${CMAKE_COMMAND} -E env - XGETTEXT=${XGETTEXT_EXECUTABLE} - COPYRIGHT_HOLDERS=${COPYRIGHT_HOLDERS} - ${PYTHON_EXECUTABLE} - ${CMAKE_CURRENT_LIST_DIR}/extract_strings_qt.py - ${translatable_sources} - WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/src - COMMAND_ERROR_IS_FATAL ANY +extract_strings("${PROJECT_SOURCE_DIR}/src/qt/bitcoinstrings.cpp" + ${translatable_sources} ) execute_process( diff --git a/src/qt/CMakeLists.txt b/src/qt/CMakeLists.txt index 5a3f98738f6..c23a7ec6d54 100644 --- a/src/qt/CMakeLists.txt +++ b/src/qt/CMakeLists.txt @@ -300,7 +300,6 @@ else() -D "COPYRIGHT_HOLDERS=${COPYRIGHT_HOLDERS}" -D "LCONVERT_EXECUTABLE=$" -D "LUPDATE_EXECUTABLE=$" - -D "PYTHON_EXECUTABLE=$" -D "XGETTEXT_EXECUTABLE=${XGETTEXT_EXECUTABLE}" -P ${PROJECT_SOURCE_DIR}/share/qt/translate.cmake )