translate.cmake raw

   1  # Copyright (c) 2025-present 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  cmake_minimum_required(VERSION 3.22)
   6  
   7  set(input_variables
   8    PROJECT_SOURCE_DIR
   9    COPYRIGHT_HOLDERS
  10    LCONVERT_EXECUTABLE
  11    LUPDATE_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  # Extract _("...") strings for translation and convert to Qt stringdefs so that
  22  # they can be picked up by Qt linguist.
  23  function(extract_strings output)
  24    execute_process(
  25      COMMAND ${XGETTEXT_EXECUTABLE}
  26        --output=bitcoinstrings.po
  27        --no-location
  28        --from-code=utf-8
  29        --keyword=_
  30        ${ARGN}
  31      COMMAND_ERROR_IS_FATAL ANY
  32    )
  33  
  34    file(STRINGS "bitcoinstrings.po" text ENCODING "UTF-8")
  35  
  36    set(messages "${COPYRIGHT_HOLDERS}")
  37    foreach(line IN LISTS text)
  38      if(line MATCHES "^msgid \"(.*)\"$")
  39        set(msgid "${CMAKE_MATCH_1}")
  40      elseif(line MATCHES "^\"(.*)\"$")
  41        string(APPEND msgid "${CMAKE_MATCH_1}")
  42      elseif(line MATCHES "^msgstr .*$" AND NOT msgid STREQUAL "")
  43        # CMake uses ';' as a list separator.
  44        # We need to temporarily replace that in order to keep strings intact.
  45        string(REPLACE ";" "<cmake-semicolon>" msgid "${msgid}")
  46        list(APPEND messages "${msgid}")
  47      endif()
  48    endforeach()
  49  
  50    set(content [[// Automatically generated by translate.cmake
  51  
  52  #include <QtGlobal>
  53  
  54  #ifdef __GNUC__
  55  #define UNUSED __attribute__((unused))
  56  #else
  57  #define UNUSED
  58  #endif
  59  
  60  static const char UNUSED *bitcoin_strings[] = {
  61  ]])
  62  
  63    set(prefix "QT_TRANSLATE_NOOP(\"bitcoin-core\", \"")
  64    set(suffix "\"),\n")
  65  
  66    list(SORT messages)
  67    list(JOIN messages "${suffix}${prefix}" messages_str)
  68    string(APPEND content "${prefix}${messages_str}${suffix}")
  69    string(APPEND content "};\n")
  70    string(REPLACE "<cmake-semicolon>" ";" content "${content}")
  71  
  72    file(WRITE "${output}" "${content}")
  73  endfunction()
  74  
  75  file(GLOB_RECURSE translatable_sources
  76    "${PROJECT_SOURCE_DIR}/src/*.h"
  77    "${PROJECT_SOURCE_DIR}/src/*.cpp"
  78    "${PROJECT_SOURCE_DIR}/src/*.mm"
  79  )
  80  
  81  file(GLOB_RECURSE qt_translatable_sources
  82    "${PROJECT_SOURCE_DIR}/src/qt/*.h"
  83    "${PROJECT_SOURCE_DIR}/src/qt/*.cpp"
  84    "${PROJECT_SOURCE_DIR}/src/qt/*.mm"
  85  )
  86  
  87  file(GLOB ui_files
  88    "${PROJECT_SOURCE_DIR}/src/qt/forms/*.ui"
  89  )
  90  
  91  set(subtrees crc32c crypto/ctaes leveldb minisketch secp256k1)
  92  set(exclude_dirs bench compat crypto support test univalue)
  93  foreach(directory IN LISTS subtrees exclude_dirs)
  94    list(FILTER translatable_sources
  95      EXCLUDE REGEX "${PROJECT_SOURCE_DIR}/src/${directory}/.*"
  96    )
  97  endforeach()
  98  
  99  extract_strings("${PROJECT_SOURCE_DIR}/src/qt/bitcoinstrings.cpp"
 100    ${translatable_sources}
 101  )
 102  
 103  execute_process(
 104    COMMAND ${LUPDATE_EXECUTABLE}
 105      -no-obsolete
 106      -I ${PROJECT_SOURCE_DIR}/src
 107      -locations relative
 108      ${ui_files}
 109      ${qt_translatable_sources}
 110      ${PROJECT_SOURCE_DIR}/src/qt/bitcoinstrings.cpp
 111      -ts ${PROJECT_SOURCE_DIR}/src/qt/locale/bitcoin_en.ts
 112    COMMAND_ERROR_IS_FATAL ANY
 113  )
 114  
 115  execute_process(
 116    COMMAND ${LCONVERT_EXECUTABLE}
 117      -drop-translations
 118      -o ${PROJECT_SOURCE_DIR}/src/qt/locale/bitcoin_en.xlf
 119      -i ${PROJECT_SOURCE_DIR}/src/qt/locale/bitcoin_en.ts
 120    COMMAND_ERROR_IS_FATAL ANY
 121  )
 122  
 123  file(READ "${PROJECT_SOURCE_DIR}/src/qt/locale/bitcoin_en.xlf" bitcoin_en)
 124  string(REPLACE "source-language=\"en\" target-language=\"en\""
 125    "source-language=\"en\"" bitcoin_en "${bitcoin_en}"
 126  )
 127  string(REGEX REPLACE " *<target xml:space=\"preserve\"></target>\n"
 128    "" bitcoin_en "${bitcoin_en}"
 129  )
 130  file(WRITE "${PROJECT_SOURCE_DIR}/src/qt/locale/bitcoin_en.xlf" "${bitcoin_en}")
 131