cmake: Drop python dependency for translate

Resolves #33146
This commit is contained in:
Daniel Pfeifer
2025-08-18 10:01:53 +02:00
parent f58de8749e
commit 3c4a109aa8
3 changed files with 58 additions and 96 deletions

View File

@@ -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 <QtGlobal>
// 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()

View File

@@ -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 ";" "<cmake-semicolon>" msgid "${msgid}")
list(APPEND messages "${msgid}")
endif()
endforeach()
set(content [[// Automatically generated by translate.cmake
#include <QtGlobal>
#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 "<cmake-semicolon>" ";" 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(

View File

@@ -300,7 +300,6 @@ else()
-D "COPYRIGHT_HOLDERS=${COPYRIGHT_HOLDERS}"
-D "LCONVERT_EXECUTABLE=$<TARGET_FILE:Qt6::lconvert>"
-D "LUPDATE_EXECUTABLE=$<TARGET_FILE:Qt6::lupdate>"
-D "PYTHON_EXECUTABLE=$<TARGET_FILE:Python3::Interpreter>"
-D "XGETTEXT_EXECUTABLE=${XGETTEXT_EXECUTABLE}"
-P ${PROJECT_SOURCE_DIR}/share/qt/translate.cmake
)