From f87cec4baae8c7bc02850edef84ac1d219df82b6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sl=C3=A1vek=20Banko?= Date: Sun, 25 Nov 2018 01:55:01 +0100 Subject: [PATCH] Add TDEL10n module MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Slávek Banko --- modules/TDEL10n.cmake | 353 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 353 insertions(+) create mode 100644 modules/TDEL10n.cmake diff --git a/modules/TDEL10n.cmake b/modules/TDEL10n.cmake new file mode 100644 index 0000000..166ab00 --- /dev/null +++ b/modules/TDEL10n.cmake @@ -0,0 +1,353 @@ +################################################# +# +# (C) 2018 Slávek Banko +# slavek (DOT) banko (AT) axis.cz +# +# Improvements and feedback are welcome +# +# This file is released under GPL >= 2 +# +################################################# + + +##### include essential TDE macros ############## + +if( NOT DEFINED MASTER_SOURCE_DIR ) + set( MASTER_SOURCE_DIR "${CMAKE_SOURCE_DIR}" ) + include( TDEMacros ) +endif( ) + + +##### verify required programs ################## + +if( NOT DEFINED TDE_PREFIX AND IS_DIRECTORY /opt/trinity ) + set( TDE_PREFIX "/opt/trinity" ) +else( ) + set( TDE_PREFIX "/usr" ) +endif( ) + +if( NOT DEFINED KDE_XGETTEXT_EXECUTABLE ) + find_program( KDE_XGETTEXT_EXECUTABLE + NAMES kde-xgettext + HINTS "${TDE_PREFIX}/bin" + ) + if( NOT KDE_XGETTEXT_EXECUTABLE ) + tde_message_fatal( "kde-xgettext is required but not found" ) + endif( ) +endif( ) + +if( NOT DEFINED EXTRACTRC_EXECUTABLE ) + find_program( EXTRACTRC_EXECUTABLE + NAMES extractrc + HINTS "${TDE_PREFIX}/bin" + ) + if( NOT EXTRACTRC_EXECUTABLE ) + tde_message_fatal( "extractrc is required but not found" ) + endif( ) +endif( ) + +if( NOT DEFINED XGETTEXT_EXECUTABLE ) + find_program( XGETTEXT_EXECUTABLE + NAMES xgettext + HINTS "${TDE_PREFIX}/bin" + ) + if( NOT XGETTEXT_EXECUTABLE ) + tde_message_fatal( "xgettext is required but not found" ) + endif( ) + execute_process( + COMMAND ${XGETTEXT_EXECUTABLE} --version + OUTPUT_VARIABLE _xgettext_version + ERROR_VARIABLE _xgettext_version + ) + string( REGEX REPLACE "^xgettext[^\n]* ([^ ]*)\n.*" "\\1" _xgettext_version ${_xgettext_version} ) + if( "${_xgettext_version}" VERSION_LESS "0.19" ) + tde_message_fatal( "xgettext version >= 0.19 is required but found only ${_xgettext_version}" ) + endif( ) +endif( ) + +if( NOT DEFINED MSGUNIQ_EXECUTABLE ) + find_program( MSGUNIQ_EXECUTABLE + NAMES msguniq + HINTS "${TDE_PREFIX}/bin" + ) + if( NOT MSGUNIQ_EXECUTABLE ) + tde_message_fatal( "msguniq is required but not found" ) + endif( ) +endif( ) + + +################################################# +##### +##### tde_add_l10n_subdirectory +##### +##### The function simulates the add_subdirectory() behavior, but +##### the CMakeL10n.txt file is used instead of CMakeLists.txt. +##### + +function( tde_add_l10n_subdirectory _dir ) + set( CMAKE_CURRENT_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/${_dir}" ) + set( CMAKE_CURRENT_BINARY_DIR "${CMAKE_CURRENT_BINARY_DIR}/${_dir}" ) + include( ${CMAKE_CURRENT_SOURCE_DIR}/CMakeL10n.txt ) +endfunction( ) + + +################################################# +##### +##### tde_auto_add_l10n_subdirectories + +function( tde_auto_add_l10n_subdirectories ) + file( GLOB _dirs RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "${CMAKE_CURRENT_SOURCE_DIR}/*" ) + foreach( _dir ${_dirs} ) + if( IS_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/${_dir} + AND NOT ${_dir} STREQUAL ".svn" + AND EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${_dir}/CMakeL10n.txt ) + tde_add_l10n_subdirectory( ${_dir} ) + endif( ) + endforeach( ) +endfunction( ) + + +################################################# +##### +##### tde_create_l10n_template + +macro( tde_create_l10n_template ) + + unset( _catalog ) + unset( _sources ) + unset( _files ) + unset( _rcs ) + unset( _desktops ) + unset( _dest ) + unset( _keywords ) + unset( _directive ) + unset( _var ) + unset( _pot ) + + foreach( _arg ${ARGN} ) + + # found directive "CATALOG" + if( "+${_arg}" STREQUAL "+CATALOG" ) + unset( _catalog ) + set( _var _catalog ) + set( _directive 1 ) + endif( ) + + # found directive "SOURCES" + if( "+${_arg}" STREQUAL "+SOURCES" ) + unset( _sources ) + set( _var _sources ) + set( _directive 1 ) + endif( ) + + # found directive "DESTINATION" + if( "+${_arg}" STREQUAL "+DESTINATION" ) + unset( _dest ) + set( _var _dest ) + set( _directive 1 ) + endif( ) + + # found directive "KEYWORDS" + if( "+${_arg}" STREQUAL "+KEYWORDS" ) + unset( _keywords ) + set( _var _keywords ) + set( _directive 1 ) + endif( ) + + # collect data + if( _directive ) + unset( _directive ) + elseif( _var ) + list( APPEND ${_var} ${_arg} ) + endif( ) + + endforeach( ) + + # verify catalog + if( NOT _catalog ) + tde_message_fatal( "the name of the translation catalog is not defined" ) + endif( ) + if( ${_dest} MATCHES "[^/]$" ) + set( _dest "${_dest}/" ) + endif( ) + + get_filename_component( _potFilename "${CMAKE_CURRENT_SOURCE_DIR}/${_dest}${_catalog}.pot" ABSOLUTE ) + file( RELATIVE_PATH _potFilename ${CMAKE_SOURCE_DIR} ${_potFilename} ) + message( STATUS "Create translation template ${_potFilename}" ) + + # verify sources + if( NOT _sources ) + # add current directory + list( APPEND _sources "." ) + endif( ) + foreach( _src ${_sources} ) + + # add all source files from directory + if( IS_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/${_src} ) + if( ${_src} STREQUAL "." ) + set( _dir "${CMAKE_CURRENT_SOURCE_DIR}" ) + else( ) + set( _dir "${CMAKE_CURRENT_SOURCE_DIR}/${_src}" ) + endif( ) + file( GLOB_RECURSE _add_files + RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} + ${_dir}/*.c + ${_dir}/*.cc + ${_dir}/*.cpp + ${_dir}/*.h + ${_dir}/*.kcfg + ${_dir}/*.rc + ${_dir}/*.ui + ) + list( SORT _add_files ) + list( APPEND _files ${_add_files} ) + + # add files by the specified mask + elseif( ${_src} MATCHES "(\\*|\\?)" ) + file( GLOB_RECURSE _add_files + RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_SOURCE_DIR}/${_src} + ) + list( SORT _add_files ) + list( APPEND _files ${_add_files} ) + + # add a single file + elseif( EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${_src} ) + list( APPEND _files ${_src} ) + endif( ) + + endforeach( ) + if( NOT _files ) + tde_message_fatal( "no source files found" ) + endif( ) + + # prepare additional keywords + unset( _add_keywords ) + foreach( _keyword ${_keywords} ) + list( APPEND _add_keywords "-k${_keyword}" ) + endforeach( ) + + # pick resource files *.kcfg, *.rc and *.ui + foreach( _src ${_files} ) + if( ${_src} MATCHES "\\.(kcfg|rc|ui)(\\.cmake)?$" ) + list( APPEND _rcs ${_src} ) + list( REMOVE_ITEM _files ${_src} ) + endif( ) + endforeach( ) + + # process resource files + if( _rcs ) + execute_process( + COMMAND ${EXTRACTRC_EXECUTABLE} ${_rcs} + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + OUTPUT_FILE ${CMAKE_CURRENT_SOURCE_DIR}/extracted-rc.cpp + ) + list( APPEND _files extracted-rc.cpp ) + endif( ) + + # pick desktop files *.desktop and *.protocol + foreach( _src ${_files} ) + if( ${_src} MATCHES "\\.(desktop|protocol)(\\.cmake)?$" ) + list( APPEND _desktops ${_src} ) + list( REMOVE_ITEM _files ${_src} ) + endif( ) + endforeach( ) + + # create translation template + if( _files ) + execute_process( + COMMAND ${KDE_XGETTEXT_EXECUTABLE} --foreign-user -C + -ki18n -ki18n:1,2 -ktr2i18n -ktr2i18n:1,2 + -kI18N_NOOP -kI18N_NOOP2 ${_add_keywords} + -o - ${_files} + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + OUTPUT_VARIABLE _pot + ) + + # set charset and encoding headers + if( _pot ) + string( REPLACE "Content-Type: text/plain charset=CHARSET" "Content-Type: text/plain charset=UTF-8" _pot ${_pot} ) + string( REPLACE "Content-Transfer-Encoding: ENCODING" "Content-Transfer-Encoding: 8bit" _pot ${_pot} ) + endif( ) + endif( ) + + # process desktop files + if( _desktops ) + # create translation template for desktop files + if( _pot ) + set( _withPotHeader "--omit-header" ) + else( ) + set( _withPotHeader "--foreign-user" ) + endif( ) + execute_process( + COMMAND ${XGETTEXT_EXECUTABLE} ${_withPotHeader} -L Desktop + -kDescription -kExtraNames -kX-TDE-Submenu ${_add_keywords} + -o - ${_desktops} + WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} + OUTPUT_VARIABLE _potDesktop + ) + + # merge translation templates + if( _potDesktop ) + if( _pot ) + file( WRITE ${CMAKE_CURRENT_SOURCE_DIR}/extracted-pot.tmp ${_pot} ) + file( APPEND ${CMAKE_CURRENT_SOURCE_DIR}/extracted-pot.tmp ${_potDesktop} ) + execute_process( + COMMAND ${MSGUNIQ_EXECUTABLE} + INPUT_FILE ${CMAKE_CURRENT_SOURCE_DIR}/extracted-pot.tmp + OUTPUT_VARIABLE _pot + ) + file( REMOVE ${CMAKE_CURRENT_SOURCE_DIR}/extracted-pot.tmp ) + else( ) + set( _pot ${_potDesktop} ) + + # set charset and encoding headers + string( REPLACE "Content-Type: text/plain charset=CHARSET" "Content-Type: text/plain charset=UTF-8" _pot ${_pot} ) + string( REPLACE "Content-Transfer-Encoding: ENCODING" "Content-Transfer-Encoding: 8bit" _pot ${_pot} ) + endif( ) + endif( ) + endif( ) + + # finalize translation template + if( _pot ) + + # update references for resources to original files and line numbers + if( _rcs ) + file( STRINGS "${CMAKE_CURRENT_SOURCE_DIR}/extracted-rc.cpp" _extractedRC ) + list( LENGTH _extractedRC _extractedRC_len ) + set( _rcPos 0 ) + while( _rcPos LESS ${_extractedRC_len} ) + list( GET _extractedRC ${_rcPos} _rcLine ) + math( EXPR _rcPos "${_rcPos}+1" ) + if( "${_rcLine}" MATCHES "^//i18n: file .* line [0-9]*$" ) + string( REGEX REPLACE "^//i18n: file (.*) line ([0-9]*)$" "\\1:\\2" _rcOrig ${_rcLine} ) + endif( ) + if( "${_rcLine}" MATCHES "^i18n\\(" AND _rcOrig ) + string( REGEX REPLACE "(^|\n)(#:.*) extracted-rc.cpp:${_rcPos}( |\n)" "\\1\\2 ${_rcOrig}\\3" _pot ${_pot} ) + unset( _rcOrig ) + endif( ) + endwhile( ) + endif( ) + + # save translation template + if( EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/${_dest}${_catalog}.pot" ) + file( READ "${CMAKE_CURRENT_SOURCE_DIR}/${_dest}${_catalog}.pot" _potOrig ) + else( ) + unset( _potOrig ) + endif( ) + if( _potOrig ) + string( REGEX REPLACE "\n\"POT-Creation-Date: [^\"]*\"\n" "" _potOrig ${_potOrig} ) + string( REGEX REPLACE "\n\"POT-Creation-Date: [^\"]*\"\n" "" _potNew ${_pot} ) + endif( ) + if( NOT _potOrig OR NOT "${_potNew}" STREQUAL "${_potOrig}" ) + file( WRITE "${CMAKE_CURRENT_SOURCE_DIR}/${_dest}${_catalog}.pot" ${_pot} ) + endif( ) + + endif( _pot ) + + # cleanup + if( _rcs ) + file( REMOVE ${CMAKE_CURRENT_SOURCE_DIR}/extracted-rc.cpp ) + endif( ) + +endmacro( )