You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tde-cmake/modules/TDEL10n.cmake

435 lines
13 KiB

#################################################
#
# (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 EXTRACTATTR_EXECUTABLE )
find_program( EXTRACTATTR_EXECUTABLE
NAMES extractattr
HINTS "${TDE_PREFIX}/bin"
)
if( NOT EXTRACTATTR_EXECUTABLE )
tde_message_fatal( "extractattr 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
#####
##### The function is equivalent to tde_auto_add_subdirectories, but
##### the CMakeL10n.txt file is used instead of CMakeLists.txt.
#####
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 is used to generate a translation template - POT file.
#####
##### Syntax:
##### tde_create_l10n_template(
##### CATALOG file_name
##### [SOURCES source_spec [source_spec]]
##### [KEYWORDS keyword [keyword]]
##### [ATTRIBUTES attrib_spec [attrib_spec]]
##### [DESTINATION directory]
##### )
#####
##### Where:
##### CATALOG determines the target file name (without pot suffix).
##### SOURCES can be specified by several options:
##### a) Do not specify anything
##### - all usual source files will be automatically searched.
##### b) Enter the directory name - for example, '.' or 'src'
##### - all the usual source files in the specified directory
##### and subdirectories will be searched.
##### c) Enter the mask - for example '*.cpp'
##### - all files with the specified mask will be searched.
##### d) Specify the name of the individual file.
##### The methods from b) to d) can be combined.
##### KEYWORDS determines additional keywords for xgettext.
##### ATTRIBUTES determines files and specification for extractattr:
##### source_spec:element,attribute[,context]
##### DESTINATION determines directory to save translation template.
#####
macro( tde_create_l10n_template )
unset( _catalog )
unset( _sources )
unset( _files )
unset( _rcs )
unset( _desktops )
unset( _dest )
unset( _keywords )
unset( _attributes )
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( )
# found directive "ATTRIBUTES"
if( "+${_arg}" STREQUAL "+ATTRIBUTES" )
unset( _attributes )
set( _var _attributes )
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 AND NOT _attributes )
# 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 individual file
elseif( EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${_src} )
list( APPEND _files ${_src} )
endif( )
endforeach( )
if( NOT _files AND NOT _attributes )
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( )
# prepare extracted-rc.cpp
if( _rcs OR _attributes )
file( WRITE ${CMAKE_CURRENT_SOURCE_DIR}/extracted-rc.cpp "" )
list( APPEND _files extracted-rc.cpp )
endif( )
# process resource files
if( _rcs )
execute_process(
COMMAND ${EXTRACTRC_EXECUTABLE} ${_rcs}
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
OUTPUT_VARIABLE _sources_rc
)
file( APPEND ${CMAKE_CURRENT_SOURCE_DIR}/extracted-rc.cpp ${_sources_rc} )
endif( )
# extract attributes
if( _attributes )
foreach( _attrib ${_attributes} )
if( ${_attrib} MATCHES "^([^:]+):(.+)$" )
string( REGEX REPLACE "^([^:]+):(.+)$" "\\1" _attrib_glob ${_attrib} )
string( REGEX REPLACE "^([^:]+):(.+)$" "\\2" _attrib_spec ${_attrib} )
file( GLOB_RECURSE _attrib_files
RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}
${CMAKE_CURRENT_SOURCE_DIR}/${_attrib_glob}
)
if( _attrib_files )
list( SORT _attrib_files )
execute_process(
COMMAND ${EXTRACTATTR_EXECUTABLE}
--attr=${_attrib_spec} ${_attrib_files}
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
OUTPUT_VARIABLE _attrib_rc
)
file( APPEND ${CMAKE_CURRENT_SOURCE_DIR}/extracted-rc.cpp ${_attrib_rc} )
endif( )
endif( )
endforeach( )
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 OR _attributes )
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 OR _attributes )
file( REMOVE ${CMAKE_CURRENT_SOURCE_DIR}/extracted-rc.cpp )
endif( )
endmacro( )