From 69a0ed765038ba118d9d53ac5c12dd9d03191f57 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sl=C3=A1vek=20Banko?= Date: Wed, 9 Jan 2019 03:15:00 +0100 Subject: [PATCH] Update TDEL10n module + Use excludes also on files for extracting attributes. + Add ability to extract multiple attributes for one source_spec. + Add function to prepare attributes from XML files for xgettext. + Use tde_l10n_prepare_xmlattr function instead of extractattr script. + Handle working files for multiple extractions from the same source file. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Slávek Banko (cherry picked from commit a1f62e623930038072f77d96a71502758d6dc427) --- modules/TDEL10n.cmake | 315 +++++++++++++++++++++++++++++++++++++----- 1 file changed, 284 insertions(+), 31 deletions(-) diff --git a/modules/TDEL10n.cmake b/modules/TDEL10n.cmake index eab973f..cc10e6d 100644 --- a/modules/TDEL10n.cmake +++ b/modules/TDEL10n.cmake @@ -34,16 +34,6 @@ if( NOT DEFINED KDE_XGETTEXT_EXECUTABLE ) 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 @@ -153,7 +143,7 @@ endfunction( ) ##### KEYWORDS determines additional keywords for xgettext. ##### Use "-" if is needed to disable default keywords. ##### ATTRIBUTES determines files and specification for extractattr: -##### source_spec:element,attribute[,context] +##### source_spec:element,attribute[,context][[:element,attribute[,context]]...] ##### DESTINATION determines directory to save translation template. ##### The destination directory is determined as follows: ##### a) Directory is specified as an argument. @@ -371,19 +361,21 @@ macro( tde_l10n_create_template ) # prepare resource files *.kcfg, *.rc and *.ui foreach( _src ${_files} ) if( ${_src} MATCHES "\\.(kcfg|rc|ui)(\\.cmake)?$" ) - tde_l10n_prepare_xml( ${_src} ) + set( _src_index 0 ) + set( _src_l10n "${_src}.tde_l10n" ) + list( FIND _files "${_src_l10n}" _src_file_index ) + while( "${_src_file_index}" GREATER -1 ) + set( _src_l10n "${_src}.tde_l10n${_src_index}" ) + list( FIND _files "${_src_l10n}" _src_file_index ) + math( EXPR _src_index "${_src_index}+1" ) + endwhile( ) + tde_l10n_prepare_xml( SOURCE ${_src} TARGET ${_src_l10n} ) list( REMOVE_ITEM _files ${_src} ) - list( APPEND _files "${_src}.tde_l10n" ) + list( APPEND _files "${_src_l10n}" ) endif( ) endforeach( ) - # prepare extracted-rc.tde_l10n - if( _attributes ) - file( WRITE ${CMAKE_CURRENT_SOURCE_DIR}/extracted-rc.tde_l10n "" ) - list( APPEND _files extracted-rc.tde_l10n ) - endif( ) - - # extract attributes + # prepare attributes if( _attributes ) foreach( _attrib ${_attributes} ) if( ${_attrib} MATCHES "^([^:]+):(.+)$" ) @@ -393,15 +385,34 @@ macro( tde_l10n_create_template ) RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/${_attrib_glob} ) + if( _excludes ) + foreach( _src ${_attrib_files} ) + foreach( _exclude ${_excludes} ) + if( ${_src} MATCHES ${_exclude} ) + list( REMOVE_ITEM _attrib_files ${_src} ) + endif( ) + endforeach( ) + endforeach( ) + endif( ) 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.tde_l10n "${_attrib_rc}" ) + string( REGEX MATCHALL "[^:]+" _attrib_spec "${_attrib_spec}" ) + foreach( _src ${_attrib_files} ) + set( _src_index 0 ) + set( _src_l10n "${_src}.tde_l10n" ) + list( FIND _files "${_src_l10n}" _src_file_index ) + while( "${_src_file_index}" GREATER -1 ) + set( _src_l10n "${_src}.tde_l10n${_src_index}" ) + list( FIND _files "${_src_l10n}" _src_file_index ) + math( EXPR _src_index "${_src_index}+1" ) + endwhile( ) + tde_l10n_prepare_xmlattr( + SOURCE ${_src} + TARGET ${_src_l10n} + ATTRIBUTES ${_attrib_spec} + ) + list( APPEND _files "${_src_l10n}" ) + endforeach( ) endif( ) endif( ) endforeach( ) @@ -418,7 +429,7 @@ macro( tde_l10n_create_template ) # pick desktop files *.desktop and *.protocol foreach( _src ${_files} ) - if( ${_src} MATCHES "\\.(desktop|protocol)(\\.cmake)?(\\.tde_l10n)?$" ) + if( ${_src} MATCHES "\\.(desktop|protocol)(\\.cmake)?$" ) list( APPEND _desktops ${_src} ) list( REMOVE_ITEM _files ${_src} ) endif( ) @@ -504,7 +515,9 @@ macro( tde_l10n_create_template ) if( _pot ) # update references for resources to original files and line numbers - if( _attributes ) + list( FIND _files "extracted-rc.tde_l10n" _extractedRC_index ) + if( "${_extractedRC_index}" GREATER -1 + AND EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/extracted-rc.tde_l10n ) file( READ "${CMAKE_CURRENT_SOURCE_DIR}/extracted-rc.tde_l10n" _extractedRC ) string( REGEX REPLACE "[^\n]" "" _extractedRC_len "${_extractedRC}" ) string( LENGTH "+${_extractedRC_len}" _extractedRC_len ) @@ -524,7 +537,7 @@ macro( tde_l10n_create_template ) endif( ) # update references for modified source files (".tde_l10n" extension) - string( REGEX REPLACE "\\.tde_l10n(:[0-9]+)" "\\1" _pot "${_pot}" ) + string( REGEX REPLACE "\\.tde_l10n[0-9]*(:[0-9]+)" "\\1" _pot "${_pot}" ) # save translation template if( EXISTS "${_dest}${_catalog}.pot" ) @@ -544,7 +557,7 @@ macro( tde_l10n_create_template ) # cleanup foreach( _file ${_files} ${_desktops} ) - if( "${_file}" MATCHES "\\.tde_l10n$" ) + if( "${_file}" MATCHES "\\.tde_l10n[0-9]*$" ) file( REMOVE ${CMAKE_CURRENT_SOURCE_DIR}/${_file} ) endif( ) endforeach( ) @@ -775,3 +788,243 @@ function( tde_l10n_prepare_xml ) file( WRITE ${_target} "${_xml_l10n}" ) endfunction( ) + + +################################################# +##### +##### tde_l10n_prepare_xmlattr +##### +##### The function is used to prepare attributes in XML file +##### for xgettext, comparable to extractattr. +##### + +function( tde_l10n_prepare_xmlattr ) + + unset( _source ) + unset( _target ) + unset( _context ) + unset( _attribs ) + unset( _directive ) + set( _preserve "line-wrap" "lines-leading" "spaces-leading" "spaces-trailing" "spaces-multi" ) + set( _var _source ) + + foreach( _arg ${ARGN} ) + + # found directive "SOURCE" + if( "+${_arg}" STREQUAL "+SOURCE" ) + unset( _source ) + set( _var _source ) + set( _directive 1 ) + endif( ) + + # found directive "TARGET" + if( "+${_arg}" STREQUAL "+TARGET" ) + unset( _target ) + set( _var _target ) + set( _directive 1 ) + endif( ) + + # found directive "CONTEXT" + if( "+${_arg}" STREQUAL "+CONTEXT" ) + unset( _context ) + set( _var _context ) + set( _directive 1 ) + endif( ) + + # found directive "ATTRIBUTES" + if( "+${_arg}" STREQUAL "+ATTRIBUTES" ) + unset( _attribs ) + set( _var _attribs ) + set( _directive 1 ) + endif( ) + + # found directive "PRESERVE" + if( "+${_arg}" STREQUAL "+PRESERVE" ) + unset( _preserve ) + set( _var _preserve ) + set( _directive 1 ) + endif( ) + + # collect data + if( _directive ) + unset( _directive ) + elseif( _var ) + list( APPEND ${_var} ${_arg} ) + endif( ) + + endforeach( ) + + # verify source + if( NOT _source ) + tde_message_fatal( "no source XML file" ) + endif( ) + if( NOT "${_source}" MATCHES "^/" ) + set( _source "${CMAKE_CURRENT_SOURCE_DIR}/${_source}" ) + endif( ) + if( NOT _target ) + set( _target "${_source}.tde_l10n" ) + endif( ) + if( NOT "${_target}" MATCHES "^/" ) + set( _target "${CMAKE_CURRENT_SOURCE_DIR}/${_target}" ) + endif( ) + + # prepare tags to regexp + if( NOT _attribs ) + tde_message_fatal( "no attributes specified" ) + endif( ) + unset( _tags ) + foreach( _attrib ${_attribs} ) + string( REGEX REPLACE "^([^,]+),.*" "\\1" _tag "${_attrib}" ) + list( APPEND _tags "${_tag}" ) + endforeach( ) + list( REMOVE_DUPLICATES _tags ) + string( REPLACE ";" "|" _tags "${_tags}" ) + + # read file + file( READ ${_source} _xml_data ) + string( REGEX REPLACE "[^\n]" "" _xml_len ${_xml_data} ) + string( LENGTH "+${_xml_len}" _xml_len ) + + # process lines + set( _xml_pos 0 ) + unset( _xml_l10n ) + unset( _xml_inside_tag ) + unset( _xml_inside_attrib ) + unset( _xml_attrib_empty ) + while( _xml_pos LESS ${_xml_len} ) + # pick line + string( REGEX REPLACE "^([^\n]*)\n(.*)" "\\1" _xml_line "${_xml_data}" ) + string( REGEX REPLACE "^([^\n]*)\n(.*)" "\\2" _xml_data "${_xml_data}" ) + math( EXPR _xml_pos "${_xml_pos}+1" ) + set( _xml_newline 1 ) + + # process tags on line + while( _xml_newline OR NOT "${_xml_line}" STREQUAL "" ) + unset( _xml_line_rest ) + if( NOT _xml_inside_tag ) + if( "${_xml_line}" MATCHES "<(${_tags})([ \t\n][^>]*|$)" ) + set( _xml_inside_tag 1 ) + string( REGEX MATCH "<(${_tags})([ \t\n][^>]*|$)(.*)" _xml_line "${_xml_line}" ) + string( REGEX REPLACE "^<(${_tags})[ \t\n]*.*" "\\1" _xml_tag "${_xml_line}" ) + string( REGEX REPLACE "^<(${_tags})[ \t\n]*" "" _xml_line "${_xml_line}" ) + unset( _tag_attribs ) + foreach( _attrib ${_attribs} ) + if( "${_attrib}" MATCHES "^${_xml_tag}," ) + string( REGEX REPLACE "^([^,]+),([^,]+),?(.*)" "\\2" _attrib "${_attrib}" ) + list( APPEND _tag_attribs "${_attrib}" ) + endif( ) + endforeach( ) + string( REPLACE ";" "|" _tag_attribs "${_tag_attribs}" ) + unset( _xml_inside_attrib ) + else( ) + set( _xml_line "" ) + endif( ) + endif( ) + + if( _xml_inside_tag ) + if( "${_xml_line}" MATCHES "^(([ \t]*[^>=]+=\"[^\"]*\")*)[ \t]*/?>" ) + unset( _xml_inside_tag ) + string( REGEX REPLACE "^(([ \t]*[^>=]+=\"[^\"]*\")*)[ \t]*/?>(.*)" "\\3" _xml_line_rest "${_xml_line}" ) + string( REGEX REPLACE "^(([ \t]*[^>=]+=\"[^\"]*\")*)[ \t]*/?>(.*)" "\\1" _xml_line "${_xml_line}" ) + endif( ) + + # process attribs on line + set( _xml_attrib_line "${_xml_line}" ) + while( _xml_newline OR NOT "${_xml_attrib_line}" STREQUAL "" ) + unset( _xml_newline ) + unset( _xml_line_prefix ) + unset( _xml_line_suffix ) + unset( _xml_attrib_line_rest ) + + if( NOT _xml_inside_attrib ) + if( "${_xml_attrib_line}" MATCHES "(^|[ \t]+)(${_tag_attribs})=\"" ) + set( _xml_inside_attrib 1 ) + string( REGEX MATCH "(^|[ \t]+)(${_tag_attribs})=\"(.*)" _xml_attrib_line "${_xml_attrib_line}" ) + string( REGEX REPLACE "^[ \t]*(${_tag_attribs})=\".*" "\\1" _xml_attrib "${_xml_attrib_line}" ) + string( REGEX REPLACE "^[ \t]*(${_tag_attribs})=\"" "" _xml_attrib_line "${_xml_attrib_line}" ) + set( _xml_context "${_context}" ) + foreach( _attrib ${_attribs} ) + if( "${_attrib}" MATCHES "^${_xml_tag},${_xml_attrib}," ) + string( REGEX REPLACE "^([^,]+),([^,]+),?(.*)" "\\3" _xml_context "${_attrib}" ) + endif( ) + endforeach( ) + set( _xml_line_prefix "i18n(" ) + if( _xml_context ) + set( _xml_line_prefix "${_xml_line_prefix}\"${_xml_context}\", " ) + endif( ) + set( _xml_attrib_empty 1 ) + else( ) + set( _xml_attrib_line "" ) + endif( ) + endif( ) + + if( _xml_inside_attrib ) + if( "${_xml_attrib_line}" MATCHES "\"" ) + unset( _xml_inside_attrib ) + string( REGEX REPLACE "\"(.*)" "\\1" _xml_attrib_line_rest "${_xml_attrib_line}" ) + string( REGEX REPLACE "\"(.*)" "" _xml_attrib_line "${_xml_attrib_line}" ) + set( _xml_line_suffix ");" ) + endif( ) + + string( REGEX REPLACE "\\\\" "\\\\\\\\" _xml_attrib_line "${_xml_attrib_line}" ) + string( REGEX REPLACE "\\\"" "\\\\\"" _xml_attrib_line "${_xml_attrib_line}" ) + string( REGEX REPLACE "\t" "\\\\t" _xml_attrib_line "${_xml_attrib_line}" ) + if( NOT ";${_preserve};" MATCHES ";entities;" ) + string( REGEX REPLACE "<" "<" _xml_attrib_line "${_xml_attrib_line}" ) + string( REGEX REPLACE ">" ">" _xml_attrib_line "${_xml_attrib_line}" ) + string( REGEX REPLACE "&" "&" _xml_attrib_line "${_xml_attrib_line}" ) + endif( ) + if( NOT ";${_preserve};" MATCHES ";spaces-leading;" ) + string( REGEX REPLACE "^ +" "" _xml_attrib_line "${_xml_attrib_line}" ) + endif( ) + if( NOT ";${_preserve};" MATCHES ";spaces-trailing;" ) + string( REGEX REPLACE " +$" "" _xml_attrib_line "${_xml_attrib_line}" ) + endif( ) + if( NOT ";${_preserve};" MATCHES ";spaces-multi;" ) + string( REGEX REPLACE " +" " " _xml_attrib_line "${_xml_attrib_line}" ) + endif( ) + + if( NOT "${_xml_inside_attrib}" STREQUAL "" ) + if( ";${_preserve};" MATCHES ";line-wrap;" ) + if( ";${_preserve};" MATCHES ";lines-leading;" + OR NOT "${_xml_attrib_line}" STREQUAL "" OR NOT _xml_attrib_empty ) + set( _xml_attrib_line "${_xml_attrib_line}\\n" ) + endif( ) + elseif( NOT "${_xml_attrib_line}" STREQUAL "" AND NOT _xml_attrib_empty ) + set( _xml_attrib_line " ${_xml_attrib_line}" ) + endif( ) + endif( ) + if( NOT "${_xml_attrib_line}" STREQUAL "" ) + unset( _xml_attrib_empty ) + endif( ) + endif( ) + + # drop empty attrib on single line + if( _xml_line_prefix AND _xml_line_suffix AND _xml_attrib_empty ) + # skip empty translation + + # add current attrib to output + else( ) + set( _xml_l10n "${_xml_l10n}${_xml_line_prefix}" ) + if( NOT "${_xml_attrib_line}" STREQUAL "" OR ( _xml_line_suffix AND _xml_attrib_empty ) ) + set( _xml_l10n "${_xml_l10n}\"${_xml_attrib_line}\"" ) + endif( ) + set( _xml_l10n "${_xml_l10n}${_xml_line_suffix}" ) + endif( ) + + # take the rest of the line for processing + set( _xml_attrib_line "${_xml_attrib_line_rest}" ) + endwhile( ) + endif( ) + + # take the rest of the line for processing + unset( _xml_newline ) + set( _xml_line "${_xml_line_rest}" ) + endwhile( ) + set( _xml_l10n "${_xml_l10n}\n" ) + endwhile( ) + + # write file + file( WRITE ${_target} "${_xml_l10n}" ) + +endfunction( )