diff --git a/Base/Python/CMakeLists.txt b/Base/Python/CMakeLists.txt index 9331ad9c957..25264b03b67 100644 --- a/Base/Python/CMakeLists.txt +++ b/Base/Python/CMakeLists.txt @@ -6,6 +6,7 @@ set(Slicer_PYTHON_SCRIPTS slicer/slicerqt slicer/testing slicer/util + slicer/i18n freesurfer mrml vtkAddon diff --git a/Base/Python/slicer/i18n.py b/Base/Python/slicer/i18n.py new file mode 100644 index 00000000000..a453a3a3e25 --- /dev/null +++ b/Base/Python/slicer/i18n.py @@ -0,0 +1,4 @@ + +def tr(context, text): + from slicer import app + return app.translate(context, text) diff --git a/CMake/RewriteTr.py b/CMake/RewriteTr.py new file mode 100644 index 00000000000..58b919eb72d --- /dev/null +++ b/CMake/RewriteTr.py @@ -0,0 +1,82 @@ +import ast +import errno +import getopt +import os +import sys + +import astor + + +class RewriteTr(ast.NodeTransformer): + """Replace tr to QT_TRANSLATE_NOOP + """ + def visit_Call(self, node): + self.generic_visit(node) + # Transform 'tr' into 'QT_TRANSLATE_NOOP' """ + if (isinstance(node.func, ast.Name) and \ + ("tr" == node.func.id) and \ + len(node.args) == 2): + call = ast.Call(func=ast.Name(id='QT_TRANSLATE_NOOP', ctx=ast.Load()), + args=node.args, + keywords=[]) + ast.copy_location(call, node) + # Add lineno & col_offset to the nodes we created + ast.fix_missing_locations(call) + return call + + # Return the original node if we don't want to change it. + return node + + +def mkdir_p(path): + """Ensure directory ``path`` exists. If needed, parent directories + are created. + Adapted from http://stackoverflow.com/a/600612/1539918 + """ + try: + os.makedirs(path) + except OSError as exc: # Python >2.5 + if exc.errno == errno.EEXIST and os.path.isdir(path): + pass + else: # pragma: no cover + raise + + +def main(argv): + + input_file = '' + output_file = '' + try: + opts, args = getopt.getopt(argv, "hi:o:", ["ifile=","ofile="]) + except getopt.GetoptError: + print('RewriteTr.py -i -o ') + sys.exit(2) + for opt, arg in opts: + if opt == '-h': + print('RewriteTr.py -i -o ') + sys.exit() + elif opt in ("-i", "--ifile"): + input_file = arg + elif opt in ("-o", "--ofile"): + output_file = arg + + with open(input_file, "r") as source: + tree = ast.parse(source.read()) + + tree_new = RewriteTr().visit(tree) + all_lines = astor.to_source(tree_new) + + # if needed, create output directory + output_dir = os.path.dirname(output_file) + #print("output_dir [%s]" % output_dir) + mkdir_p(output_dir) + + # replace the single quotation marks to double quotation marks. It is necessary for lupdate + with open(output_file, "w") as destination: + for line in all_lines: + linenew = line.replace('\'', "\"") + destination.write(linenew) + + +if __name__ == "__main__": + main(sys.argv[1:]) diff --git a/CMake/SlicerConfig.cmake.in b/CMake/SlicerConfig.cmake.in index 585f1791930..1423695fbf2 100644 --- a/CMake/SlicerConfig.cmake.in +++ b/CMake/SlicerConfig.cmake.in @@ -126,6 +126,12 @@ set(Slicer_BUILD_EXTENSIONMANAGER_SUPPORT "@Slicer_BUILD_EXTENSIONMANAGER_SUPPOR set(Slicer_BUILD_PARAMETERSERIALIZER_SUPPORT "@Slicer_BUILD_PARAMETERSERIALIZER_SUPPORT@") set(Slicer_BUILD_TESTING "@BUILD_TESTING@") set(Slicer_BUILD_WEBENGINE_SUPPORT "@Slicer_BUILD_WEBENGINE_SUPPORT@") +set(Slicer_BUILD_I18N_SUPPORT "@Slicer_BUILD_I18N_SUPPORT@") +set(Slicer_UPDATE_TRANSLATION "@Slicer_UPDATE_TRANSLATION@") + +if(Slicer_BUILD_I18N_SUPPORT) + set(Slicer_LANGUAGES "@Slicer_LANGUAGES@") +endif() set(Slicer_REQUIRED_QT_VERSION "@Slicer_REQUIRED_QT_VERSION@") set(Slicer_REQUIRED_QT_MODULES "@Slicer_REQUIRED_QT_MODULES@") @@ -348,6 +354,8 @@ if(Slicer_USE_PYTHONQT) set(Slicer_INSTALL_QTSCRIPTEDMODULES_SHARE_DIR "@Slicer_INSTALL_QTSCRIPTEDMODULES_SHARE_DIR@") endif() +set(Slicer_INSTALL_QM_DIR "@Slicer_INSTALL_QM_DIR@") + set(Slicer_INSTALL_THIRDPARTY_BIN_DIR "${Slicer_INSTALL_ROOT}${Slicer_BUNDLE_EXTENSIONS_LOCATION}${Slicer_THIRDPARTY_BIN_DIR}") set(Slicer_INSTALL_THIRDPARTY_LIB_DIR "${Slicer_INSTALL_ROOT}${Slicer_BUNDLE_EXTENSIONS_LOCATION}${Slicer_THIRDPARTY_LIB_DIR}") set(Slicer_INSTALL_THIRDPARTY_SHARE_DIR "${Slicer_INSTALL_ROOT}${Slicer_BUNDLE_EXTENSIONS_LOCATION}${Slicer_THIRDPARTY_SHARE_DIR}") @@ -355,7 +363,6 @@ set(Slicer_INSTALL_THIRDPARTY_SHARE_DIR "${Slicer_INSTALL_ROOT}${Slicer_BUNDLE_E # The Slicer install prefix (*not* defined in the install tree) set(Slicer_INSTALL_PREFIX "@CMAKE_INSTALL_PREFIX@") - # -------------------------------------------------------------------------- # Testing # -------------------------------------------------------------------------- diff --git a/CMake/SlicerMacroBuildApplication.cmake b/CMake/SlicerMacroBuildApplication.cmake index af90539c4d8..30d40f9f67e 100644 --- a/CMake/SlicerMacroBuildApplication.cmake +++ b/CMake/SlicerMacroBuildApplication.cmake @@ -175,9 +175,7 @@ macro(slicerMacroBuildAppLibrary) # Translation # -------------------------------------------------------------------------- if(Slicer_BUILD_I18N_SUPPORT) - set(TS_DIR - "${CMAKE_CURRENT_SOURCE_DIR}/Resources/Translations/" - ) + set(TS_DIR "${CMAKE_CURRENT_SOURCE_DIR}/Resources/Translations") get_property(Slicer_LANGUAGES GLOBAL PROPERTY Slicer_LANGUAGES) include(SlicerMacroTranslation) @@ -187,13 +185,7 @@ macro(slicerMacroBuildAppLibrary) TS_DIR ${TS_DIR} TS_BASEFILENAME ${SLICERAPPLIB_NAME} TS_LANGUAGES ${Slicer_LANGUAGES} - QM_OUTPUT_DIR_VAR QM_OUTPUT_DIR - QM_OUTPUT_FILES_VAR QM_OUTPUT_FILES ) - - set_property(GLOBAL APPEND PROPERTY Slicer_QM_OUTPUT_DIRS ${QM_OUTPUT_DIR}) - else() - set(QM_OUTPUT_FILES ) endif() # -------------------------------------------------------------------------- @@ -204,7 +196,6 @@ macro(slicerMacroBuildAppLibrary) ${SLICERAPPLIB_MOC_OUTPUT} ${SLICERAPPLIB_UI_CXX} ${SLICERAPPLIB_QRC_SRCS} - ${QM_OUTPUT_FILES} ) set_target_properties(${lib_name} PROPERTIES LABELS ${lib_name}) diff --git a/CMake/SlicerMacroBuildBaseQtLibrary.cmake b/CMake/SlicerMacroBuildBaseQtLibrary.cmake index e7ba64316d0..2eca91d7bf2 100644 --- a/CMake/SlicerMacroBuildBaseQtLibrary.cmake +++ b/CMake/SlicerMacroBuildBaseQtLibrary.cmake @@ -174,9 +174,7 @@ macro(SlicerMacroBuildBaseQtLibrary) # Translation # -------------------------------------------------------------------------- if(Slicer_BUILD_I18N_SUPPORT) - set(TS_DIR - "${CMAKE_CURRENT_SOURCE_DIR}/Resources/Translations/" - ) + set(TS_DIR "${CMAKE_CURRENT_SOURCE_DIR}/Resources/Translations") get_property(Slicer_LANGUAGES GLOBAL PROPERTY Slicer_LANGUAGES) include(SlicerMacroTranslation) @@ -186,13 +184,7 @@ macro(SlicerMacroBuildBaseQtLibrary) TS_DIR ${TS_DIR} TS_BASEFILENAME ${SLICERQTBASELIB_NAME} TS_LANGUAGES ${Slicer_LANGUAGES} - QM_OUTPUT_DIR_VAR QM_OUTPUT_DIR - QM_OUTPUT_FILES_VAR QM_OUTPUT_FILES ) - - set_property(GLOBAL APPEND PROPERTY Slicer_QM_OUTPUT_DIRS ${QM_OUTPUT_DIR}) - else() - set(QM_OUTPUT_FILES ) endif() # -------------------------------------------------------------------------- @@ -203,7 +195,6 @@ macro(SlicerMacroBuildBaseQtLibrary) ${SLICERQTBASELIB_MOC_OUTPUT} ${SLICERQTBASELIB_UI_CXX} ${SLICERQTBASELIB_QRC_SRCS} - ${QM_OUTPUT_FILES} ) set_target_properties(${lib_name} PROPERTIES LABELS ${lib_name}) diff --git a/CMake/SlicerMacroBuildLoadableModule.cmake b/CMake/SlicerMacroBuildLoadableModule.cmake index 197d485a4b3..e3e5b1646ca 100644 --- a/CMake/SlicerMacroBuildLoadableModule.cmake +++ b/CMake/SlicerMacroBuildLoadableModule.cmake @@ -167,7 +167,7 @@ macro(slicerMacroBuildLoadableModule) # Translation # -------------------------------------------------------------------------- if(Slicer_BUILD_I18N_SUPPORT) - set(TS_DIR "${CMAKE_CURRENT_SOURCE_DIR}/Resources/Translations/") + set(TS_DIR "${CMAKE_CURRENT_SOURCE_DIR}/Resources/Translations") get_property(Slicer_LANGUAGES GLOBAL PROPERTY Slicer_LANGUAGES) include(SlicerMacroTranslation) @@ -177,13 +177,7 @@ macro(slicerMacroBuildLoadableModule) TS_DIR ${TS_DIR} TS_BASEFILENAME ${LOADABLEMODULE_NAME} TS_LANGUAGES ${Slicer_LANGUAGES} - QM_OUTPUT_DIR_VAR QM_OUTPUT_DIR - QM_OUTPUT_FILES_VAR QM_OUTPUT_FILES ) - set_property(GLOBAL APPEND PROPERTY Slicer_QM_OUTPUT_DIRS ${QM_OUTPUT_DIR}) - - else() - set(QM_OUTPUT_FILES ) endif() # -------------------------------------------------------------------------- @@ -194,7 +188,6 @@ macro(slicerMacroBuildLoadableModule) ${LOADABLEMODULE_MOC_OUTPUT} ${LOADABLEMODULE_UI_CXX} ${LOADABLEMODULE_QRC_SRCS} - ${QM_OUTPUT_FILES} ) # Set loadable modules output path diff --git a/CMake/SlicerMacroBuildModuleWidgets.cmake b/CMake/SlicerMacroBuildModuleWidgets.cmake index e67d93242f2..e274ff2b9c9 100644 --- a/CMake/SlicerMacroBuildModuleWidgets.cmake +++ b/CMake/SlicerMacroBuildModuleWidgets.cmake @@ -83,7 +83,7 @@ macro(SlicerMacroBuildModuleWidgets) # Translation #----------------------------------------------------------------------------- if(Slicer_BUILD_I18N_SUPPORT) - set(TS_DIR "${CMAKE_CURRENT_SOURCE_DIR}/Resources/Translations/") + set(TS_DIR "${CMAKE_CURRENT_SOURCE_DIR}/Resources/Translations") get_property(Slicer_LANGUAGES GLOBAL PROPERTY Slicer_LANGUAGES) include(SlicerMacroTranslation) @@ -93,13 +93,7 @@ macro(SlicerMacroBuildModuleWidgets) TS_DIR ${TS_DIR} TS_BASEFILENAME ${MODULEWIDGETS_NAME} TS_LANGUAGES ${Slicer_LANGUAGES} - QM_OUTPUT_DIR_VAR QM_OUTPUT_DIR - QM_OUTPUT_FILES_VAR QM_OUTPUT_FILES ) - set_property(GLOBAL APPEND PROPERTY Slicer_QM_OUTPUT_DIRS ${QM_OUTPUT_DIR}) - - else() - set(QM_OUTPUT_FILES ) endif() # -------------------------------------------------------------------------- @@ -110,7 +104,7 @@ macro(SlicerMacroBuildModuleWidgets) EXPORT_DIRECTIVE ${MODULEWIDGETS_EXPORT_DIRECTIVE} FOLDER ${MODULEWIDGETS_FOLDER} INCLUDE_DIRECTORIES ${MODULEWIDGETS_INCLUDE_DIRECTORIES} - SRCS ${MODULEWIDGETS_SRCS} ${QM_OUTPUT_FILES} + SRCS ${MODULEWIDGETS_SRCS} MOC_SRCS ${MODULEWIDGETS_MOC_SRCS} UI_SRCS ${MODULEWIDGETS_UI_SRCS} TARGET_LIBRARIES ${MODULEWIDGETS_TARGET_LIBRARIES} diff --git a/CMake/SlicerMacroBuildScriptedModule.cmake b/CMake/SlicerMacroBuildScriptedModule.cmake index 3cf67d4653a..d75c2a6a21d 100644 --- a/CMake/SlicerMacroBuildScriptedModule.cmake +++ b/CMake/SlicerMacroBuildScriptedModule.cmake @@ -97,6 +97,9 @@ macro(slicerMacroBuildScriptedModule) set(_no_install_subdir_option "") endif() + # -------------------------------------------------------------------------- + # Copy and/or compile scripts and associated resources + # -------------------------------------------------------------------------- ctkMacroCompilePythonScript( TARGET_NAME ${MY_SLICER_NAME} SCRIPTS "${MY_SLICER_SCRIPTS}" @@ -106,6 +109,36 @@ macro(slicerMacroBuildScriptedModule) ${_no_install_subdir_option} ) + # -------------------------------------------------------------------------- + # Translations + # -------------------------------------------------------------------------- + + set(scripts ) + foreach(file IN ITEMS ${MY_SLICER_SCRIPTS}) + # Append "py" extension if needed + get_filename_component(file_ext ${file} EXT) + if(NOT "${file_ext}" MATCHES "py") + set(file "${file}.py") + endif() + list(APPEND scripts ${file}) + endforeach() + + set(TS_DIR "${CMAKE_CURRENT_SOURCE_DIR}/Resources/Translations") + include(SlicerMacroTranslation) + SlicerMacroTranslation( + SRCS ${scripts} + TS_DIR ${TS_DIR} + TS_BASEFILENAME ${MY_SLICER_NAME} + TS_LANGUAGES ${Slicer_LANGUAGES} + ) + + #if("${CTK_COMPILE_PYTHON_SCRIPTS_GLOBAL_TARGET_NAME}" STREQUAL "") + # SlicerFunctionAddPythonScriptTrFilesTargets(${MY_SLICER_NAME}) + #endif() + + # -------------------------------------------------------------------------- + # Tests + # -------------------------------------------------------------------------- if(BUILD_TESTING AND MY_SLICER_WITH_GENERIC_TESTS) set(_generic_unitest_scripts) SlicerMacroConfigureGenericPythonModuleTests("${MY_SLICER_NAME}" _generic_unitest_scripts) @@ -121,4 +154,3 @@ macro(slicerMacroBuildScriptedModule) endif() endmacro() - diff --git a/CMake/SlicerMacroTranslation.cmake b/CMake/SlicerMacroTranslation.cmake index 72bf849e305..18e49f12f7d 100644 --- a/CMake/SlicerMacroTranslation.cmake +++ b/CMake/SlicerMacroTranslation.cmake @@ -32,22 +32,16 @@ # # TS_LANGUAGES...........: Variable with all the languages # -# QM_OUTPUT_DIR_VAR .....: Translation's dirs generated by the macro -# -# QM_OUTPUT_FILES_VAR....: Translation's files generated by the macro -# function(SlicerMacroTranslation) set(options) - set(oneValueArgs QM_OUTPUT_DIR_VAR TS_DIR TS_BASEFILENAME) - set(multiValueArgs SRCS UI_SRCS TS_LANGUAGES QM_OUTPUT_FILES_VAR) + set(oneValueArgs TS_DIR TS_BASEFILENAME) + set(multiValueArgs SRCS UI_SRCS TS_LANGUAGES) cmake_parse_arguments(MY "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) # --------------------------------------------------------------------------------- # Sanity Checks # --------------------------------------------------------------------------------- - #set(expected_nonempty_vars SRCS UI_SRCS TS_INPUT) -#add TS_LANGUAGES also set(expected_nonempty_vars SRCS TS_DIR TS_BASEFILENAME ) foreach(var ${expected_nonempty_vars}) if("${MY_${var}}" STREQUAL "") @@ -56,46 +50,146 @@ function(SlicerMacroTranslation) endforeach() # --------------------------------------------------------------------------------- - # Set File to translate + # Set FILES_TO_TRANSLATE # --------------------------------------------------------------------------------- - - set(FILES_TO_TRANSLATE - ${MY_SRCS} - ${MY_UI_SRCS} - ) + set(FILES_TO_TRANSLATE ) + foreach(file IN LISTS MY_SRCS MY_UI_SRCS) + if(NOT IS_ABSOLUTE ${file}) + set(file ${CMAKE_CURRENT_SOURCE_DIR}/${file}) + endif() + list(APPEND FILES_TO_TRANSLATE ${file}) + endforeach() # --------------------------------------------------------------------------------- # Set TS_FILES # --------------------------------------------------------------------------------- set(TS_FILES) foreach(language ${MY_TS_LANGUAGES}) - set(ts_file "${MY_TS_DIR}${MY_TS_BASEFILENAME}_${language}.ts") + set(ts_file "${MY_TS_DIR}/${MY_TS_BASEFILENAME}_${language}.ts") - if(NOT Slicer_UPDATE_TRANSLATION AND NOT EXISTS ${ts_file}) + if(NOT EXISTS ${ts_file}) continue() endif() list(APPEND TS_FILES ${ts_file}) endforeach() + # --------------------------------------------------------------------------------- + # Set properties used in SlicerFunctionAddGenerateSlicerTranslationQMFilesTarget + # --------------------------------------------------------------------------------- + set_property(GLOBAL APPEND PROPERTY Slicer_TS_BASEFILENAMES ${MY_TS_BASEFILENAME}) + set_property(GLOBAL PROPERTY Slicer_${MY_TS_BASEFILENAME}_FILES_TO_TRANSLATE "${FILES_TO_TRANSLATE}") + set_property(GLOBAL PROPERTY Slicer_${MY_TS_BASEFILENAME}_TS_DIR "${MY_TS_DIR}") + set_property(GLOBAL PROPERTY Slicer_${MY_TS_BASEFILENAME}_TS_FILES "${TS_FILES}") + set_property(GLOBAL PROPERTY Slicer_${MY_TS_BASEFILENAME}_QM_OUTPUT_DIR "${CMAKE_CURRENT_BINARY_DIR}") + +endfunction() + + +function(SlicerFunctionAddGenerateSlicerTranslationQMFilesTarget) + set(options) + set(oneValueArgs ) + set(multiValueArgs QM_OUTPUT_DIRS_VAR) + cmake_parse_arguments(MY "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) + + # --------------------------------------------------------------------------------- + # Sanity Checks + # --------------------------------------------------------------------------------- + set(expected_nonempty_vars QM_OUTPUT_DIRS_VAR) + foreach(var ${expected_nonempty_vars}) + if("${MY_${var}}" STREQUAL "") + message(FATAL_ERROR "error: CMake variable ${var} is empty !") + endif() + endforeach() + + set(rewrite_script "${Slicer_CMAKE_DIR}/RewriteTr.py") + if(NOT EXISTS ${rewrite_script}) + message(FATAL_ERROR "Rewrite script does not exist [${rewrite_script}]") + endif() + + # --------------------------------------------------------------------------------- + set(qm_output_dirs) + set(untranslated_ts_files) + # --------------------------------------------------------------------------------- # UPDATE or ADD translation # --------------------------------------------------------------------------------- + get_property(ts_basefilenames GLOBAL PROPERTY Slicer_TS_BASEFILENAMES) + foreach(ts_basefilename IN LISTS ts_basefilenames) + get_property(files_to_translate GLOBAL PROPERTY Slicer_${ts_basefilename}_FILES_TO_TRANSLATE) + get_property(ts_dir GLOBAL PROPERTY Slicer_${ts_basefilename}_TS_DIR) + get_property(ts_files GLOBAL PROPERTY Slicer_${ts_basefilename}_TS_FILES) + get_property(qm_output_dir GLOBAL PROPERTY Slicer_${ts_basefilename}_QM_OUTPUT_DIR) + + # Keep track of cpp source files and python scripts independently + set(srcs_to_translate) + set(scripts_to_translate) + foreach(file IN LISTS files_to_translate) + get_filename_component(file_ext ${file} EXT) + if("${file_ext}" MATCHES "py") + list(APPEND scripts_to_translate ${file}) + else() + list(APPEND srcs_to_translate ${file}) + endif() + endforeach() + + # Add custom commands for rewriting python scripts + set(rewritten_scripts_to_translate_for_context) + if(Slicer_USE_PYTHONQT) + foreach(script IN LISTS scripts_to_translate) + set(rewritten_src_file "${script}.tr") + set(rewritten_src "${qm_output_dir}/${rewritten_src_file}") + + add_custom_command(DEPENDS ${script} + COMMAND ${PYTHON_EXECUTABLE} + ${rewrite_script} -i ${script} -o ${rewritten_src} + OUTPUT ${rewritten_src} + COMMENT "Generating .py.tr file into binary directory: ${rewritten_src_file}") + + list(APPEND rewritten_scripts_to_translate_for_context ${rewritten_src}) + endforeach() + endif() + # Add custom commands for creating or updating "*_untranslated.ts" files. + set(untranslated_ts_dir "${CMAKE_BINARY_DIR}/TranslationTemplates") + set(untranslated_ts_file ${untranslated_ts_dir}/${ts_basefilename}_untranslated.ts) + SLICER_CREATE_TRANSLATION_ONLY( + ${srcs_to_translate} ${rewritten_scripts_to_translate_for_context} ${untranslated_ts_file} + OPTIONS -source-language en_US -no-ui-lines -locations none + ) + + set_source_files_properties(${ts_files} PROPERTIES OUTPUT_LOCATION ${qm_output_dir}) if(Slicer_UPDATE_TRANSLATION) - QT5_CREATE_TRANSLATION(QM_OUTPUT_FILES ${FILES_TO_TRANSLATE} ${TS_FILES}) + # Add custom command for creating or updating "*_.ts" translation files, and for + # generating the associated "*_.qm" files. + QT5_CREATE_TRANSLATION( + QM_OUTPUT_FILES ${srcs_to_translate} ${rewritten_scripts_to_translate_for_context} ${ts_files} + OPTIONS -source-language en_US -no-ui-lines -locations none + ) else() - QT5_ADD_TRANSLATION(QM_OUTPUT_FILES ${TS_FILES}) + # Add custom command for generating the associated "*_.qm" files. + QT5_ADD_TRANSLATION(QM_OUTPUT_FILES ${ts_files}) endif() + list(APPEND untranslated_ts_files ${untranslated_ts_file}) + list(APPEND qm_output_dirs ${qm_output_dir}) + endforeach() + # --------------------------------------------------------------------------------- - # Set the variable qm_output_dir + # Targets # --------------------------------------------------------------------------------- - # Extract the path associated with the first file of the list QM_OUTPUT_FILES - # -> QM_OUTPUT_DIR - list(GET QM_OUTPUT_FILES 0 QM_OUTPUT_FIRST_FILE) - get_filename_component(qm_output_dir "${QM_OUTPUT_FIRST_FILE}" PATH) + set(_all) + if(Slicer_UPDATE_TRANSLATION) + set(_all ALL) + endif() + add_custom_target(GenerateSlicerTranslationTemplates ${_all} DEPENDS + ${untranslated_ts_files} + ) + + add_custom_target(GenerateSlicerTranslationQMFiles ALL DEPENDS + ${QM_OUTPUT_FILES} + ) # --------------------------------------------------------------------------------- # Install language @@ -104,17 +198,61 @@ function(SlicerMacroTranslation) FILES ${QM_OUTPUT_FILES} DESTINATION ${Slicer_INSTALL_QM_DIR} COMPONENT Runtime - ) + ) # --------------------------------------------------------------------------------- - # ADD custom command and target + # Output variables # --------------------------------------------------------------------------------- + set(${MY_QM_OUTPUT_DIRS_VAR} ${qm_output_dirs} PARENT_SCOPE) - #add_custom_command(OUTPUT ${TS_FILES} DEPENDS ${FILES_TO_TRANSLATE} APPEND) - #add_custom_target(TS_TRANSLATE DEPENDS ${MY_QM_FILES}) +endfunction() - # Output variables - set(${MY_QM_OUTPUT_DIR_VAR} ${qm_output_dir} PARENT_SCOPE) - set(${MY_QM_OUTPUT_FILES_VAR} ${QM_OUTPUT_FILES} PARENT_SCOPE) +function(SLICER_CREATE_TRANSLATION_ONLY) + # Adapted from QT5_CREATE_TRANSLATION: + # - remove call to "qt5_add_translation" + # - remove setting of "_qm_files" output variable + set(options) + set(oneValueArgs) + set(multiValueArgs OPTIONS) + + cmake_parse_arguments(_LUPDATE "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) + set(_lupdate_files ${_LUPDATE_UNPARSED_ARGUMENTS}) + set(_lupdate_options ${_LUPDATE_OPTIONS}) + + set(_my_sources) + set(_my_tsfiles) + foreach(_file ${_lupdate_files}) + get_filename_component(_ext ${_file} EXT) + get_filename_component(_abs_FILE ${_file} ABSOLUTE) + if(_ext MATCHES "ts") + list(APPEND _my_tsfiles ${_abs_FILE}) + else() + list(APPEND _my_sources ${_abs_FILE}) + endif() + endforeach() + foreach(_ts_file ${_my_tsfiles}) + if(_my_sources) + # make a list file to call lupdate on, so we don't make our commands too + # long for some systems + get_filename_component(_ts_name ${_ts_file} NAME_WE) + set(_ts_lst_file "${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/${_ts_name}_lst_file") + set(_lst_file_srcs) + foreach(_lst_file_src ${_my_sources}) + set(_lst_file_srcs "${_lst_file_src}\n${_lst_file_srcs}") + endforeach() + + get_directory_property(_inc_DIRS INCLUDE_DIRECTORIES) + foreach(_pro_include ${_inc_DIRS}) + get_filename_component(_abs_include "${_pro_include}" ABSOLUTE) + set(_lst_file_srcs "-I${_pro_include}\n${_lst_file_srcs}") + endforeach() + + file(WRITE ${_ts_lst_file} "${_lst_file_srcs}") + endif() + add_custom_command(OUTPUT ${_ts_file} + COMMAND ${Qt5_LUPDATE_EXECUTABLE} + ARGS ${_lupdate_options} "@${_ts_lst_file}" -ts ${_ts_file} + DEPENDS ${_my_sources} ${_ts_lst_file} VERBATIM) + endforeach() endfunction() diff --git a/CMakeLists.txt b/CMakeLists.txt index fbc16a5210d..7286498b433 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -417,7 +417,8 @@ include(SlicerFunctionAddPythonQtResources) #----------------------------------------------------------------------------- if(Slicer_BUILD_I18N_SUPPORT) set(Slicer_LANGUAGES - "fr" + "es_ES" + "fr_FR" ) set_property(GLOBAL PROPERTY Slicer_LANGUAGES ${Slicer_LANGUAGES}) endif() @@ -1045,9 +1046,27 @@ endforeach() unset(Slicer_DIR) # -------------------------------------------------------------------------- -# Recover the QM output directories +# Create targets CopySlicerPython{Resource, Script}Files, CompileSlicerPythonFiles # -------------------------------------------------------------------------- -get_property(Slicer_QM_OUTPUT_DIRS GLOBAL PROPERTY Slicer_QM_OUTPUT_DIRS) +if(Slicer_USE_PYTHONQT) + slicerFunctionAddPythonQtResourcesTargets(SlicerPythonResources) + ctkFunctionAddCompilePythonScriptTargets( + ${CTK_COMPILE_PYTHON_SCRIPTS_GLOBAL_TARGET_NAME} + DEPENDS + SlicerPythonResources + ) +endif() + +# -------------------------------------------------------------------------- +# Create target GenerateSlicerTranslationQMFiles (Slicer_QM_OUTPUT_DIRS is used in vtkSlicerConfigure.h) +# -------------------------------------------------------------------------- +if(Slicer_BUILD_I18N_SUPPORT) + SlicerFunctionAddGenerateSlicerTranslationQMFilesTarget( + QM_OUTPUT_DIRS_VAR Slicer_QM_OUTPUT_DIRS + ) +else() + set(Slicer_QM_OUTPUT_DIRS) +endif() # -------------------------------------------------------------------------- # Configure and install headers @@ -1148,16 +1167,6 @@ endif() # This must come after all tests have been added that reference the group, so we put it last. ExternalData_Add_Target(${Slicer_ExternalData_DATA_MANAGEMENT_TARGET}) -#----------------------------------------------------------------------------- -# Create targets CopySlicerPython{Resource, Script}Files, CompileSlicerPythonFiles -if(Slicer_USE_PYTHONQT) - slicerFunctionAddPythonQtResourcesTargets(SlicerPythonResources) - ctkFunctionAddCompilePythonScriptTargets( - ${CTK_COMPILE_PYTHON_SCRIPTS_GLOBAL_TARGET_NAME} - DEPENDS SlicerPythonResources - ) -endif() - #----------------------------------------------------------------------------- # The commands in this directory are intended to be executed as # the end of the whole configuration process, as a "last step". diff --git a/Libs/MRML/Widgets/CMakeLists.txt b/Libs/MRML/Widgets/CMakeLists.txt index 649c1af2f1a..62bc0f49b9f 100644 --- a/Libs/MRML/Widgets/CMakeLists.txt +++ b/Libs/MRML/Widgets/CMakeLists.txt @@ -458,9 +458,7 @@ endif() # Translation # -------------------------------------------------------------------------- if(Slicer_BUILD_I18N_SUPPORT) - set(TS_DIR - "${CMAKE_CURRENT_SOURCE_DIR}/Resources/Translations/" - ) + set(TS_DIR "${CMAKE_CURRENT_SOURCE_DIR}/Resources/Translations") get_property(Slicer_LANGUAGES GLOBAL PROPERTY Slicer_LANGUAGES) include(SlicerMacroTranslation) @@ -470,13 +468,7 @@ endif() TS_DIR ${TS_DIR} TS_BASEFILENAME ${PROJECT_NAME} TS_LANGUAGES ${Slicer_LANGUAGES} - QM_OUTPUT_DIR_VAR QM_OUTPUT_DIR - QM_OUTPUT_FILES_VAR QM_OUTPUT_FILES ) - - set_property(GLOBAL APPEND PROPERTY Slicer_QM_OUTPUT_DIRS ${QM_OUTPUT_DIR}) - else() - set(QM_OUTPUT_FILES ) endif() # -------------------------------------------------------------------------- @@ -490,7 +482,6 @@ add_library(${lib_name} ${MRMLWidgets_MOC_CXX} ${MRMLWidgets_UI_CXX} ${MRMLWidgets_QRC_CXX} - ${QM_OUTPUT_FILES} ) set(MRMLWidgets_LIBRARIES diff --git a/Modules/Scripted/Endoscopy/Endoscopy.py b/Modules/Scripted/Endoscopy/Endoscopy.py index 73a4c9819f1..461f2916a79 100644 --- a/Modules/Scripted/Endoscopy/Endoscopy.py +++ b/Modules/Scripted/Endoscopy/Endoscopy.py @@ -5,6 +5,8 @@ from slicer.ScriptedLoadableModule import * import logging +from slicer.i18n import tr + # # Endoscopy # @@ -64,7 +66,7 @@ def setup(self): # Path collapsible button pathCollapsibleButton = ctk.ctkCollapsibleButton() - pathCollapsibleButton.text = "Path" + pathCollapsibleButton.text = tr("EndoscopyWidget", "Path") self.layout.addWidget(pathCollapsibleButton) # Layout within the path collapsible button @@ -80,7 +82,7 @@ def setup(self): cameraNodeSelector.removeEnabled = False cameraNodeSelector.connect('currentNodeChanged(bool)', self.enableOrDisableCreateButton) cameraNodeSelector.connect('currentNodeChanged(vtkMRMLNode*)', self.setCameraNode) - pathFormLayout.addRow("Camera:", cameraNodeSelector) + pathFormLayout.addRow(tr("EndoscopyWidget", "Camera:"), cameraNodeSelector) self.parent.connect('mrmlSceneChanged(vtkMRMLScene*)', cameraNodeSelector, 'setMRMLScene(vtkMRMLScene*)') @@ -94,12 +96,12 @@ def setup(self): inputFiducialsNodeSelector.addEnabled = False inputFiducialsNodeSelector.removeEnabled = False inputFiducialsNodeSelector.connect('currentNodeChanged(bool)', self.enableOrDisableCreateButton) - pathFormLayout.addRow("Input Fiducials:", inputFiducialsNodeSelector) + pathFormLayout.addRow(tr("EndoscopyWidget", "Input Fiducials:"), inputFiducialsNodeSelector) self.parent.connect('mrmlSceneChanged(vtkMRMLScene*)', inputFiducialsNodeSelector, 'setMRMLScene(vtkMRMLScene*)') # CreatePath button - createPathButton = qt.QPushButton("Create path") + createPathButton = qt.QPushButton(tr("EndoscopyWidget", "Create path")) createPathButton.toolTip = "Create the path." createPathButton.enabled = False pathFormLayout.addRow(createPathButton) @@ -108,7 +110,7 @@ def setup(self): # Flythrough collapsible button flythroughCollapsibleButton = ctk.ctkCollapsibleButton() - flythroughCollapsibleButton.text = "Flythrough" + flythroughCollapsibleButton.text = tr("EndoscopyWidget", "Flythrough") flythroughCollapsibleButton.enabled = False self.layout.addWidget(flythroughCollapsibleButton) diff --git a/SuperBuild.cmake b/SuperBuild.cmake index 3e8c4ea481a..2fde0f738f8 100644 --- a/SuperBuild.cmake +++ b/SuperBuild.cmake @@ -155,6 +155,10 @@ if(Slicer_USE_PYTHONQT) endif() endif() +if(Slicer_BUILD_I18N_SUPPORT AND Slicer_USE_PYTHONQT) + list(APPEND Slicer_DEPENDENCIES python-astor) +endif() + if(Slicer_USE_TBB) list(APPEND Slicer_DEPENDENCIES tbb) endif() diff --git a/SuperBuild/External_python-astor.cmake b/SuperBuild/External_python-astor.cmake new file mode 100644 index 00000000000..37e36e8514c --- /dev/null +++ b/SuperBuild/External_python-astor.cmake @@ -0,0 +1,45 @@ +set(proj python-astor) + +# Set dependency list +set(${proj}_DEPENDENCIES python python-setuptools) + +if(NOT DEFINED Slicer_USE_SYSTEM_${proj}) + set(Slicer_USE_SYSTEM_${proj} ${Slicer_USE_SYSTEM_python}) +endif() + +# Include dependent projects if any +ExternalProject_Include_Dependencies(${proj} PROJECT_VAR proj DEPENDS_VAR ${proj}_DEPENDENCIES) + +if(Slicer_USE_SYSTEM_${proj}) + ExternalProject_FindPythonPackage( + MODULE_NAME "astor" + REQUIRED + ) +endif() + +if(NOT Slicer_USE_SYSTEM_${proj}) + + set(_version "0.7.1") + + ExternalProject_Add(${proj} + ${${proj}_EP_ARGS} + URL "https://files.pythonhosted.org/packages/99/80/f9482277c919d28bebd85813c0a70117214149a96b08981b72b63240b84c/astor-${_version}.tar.gz" + URL_HASH "SHA256=95c30d87a6c2cf89aa628b87398466840f0ad8652f88eb173125a6df8533fb8d" + DOWNLOAD_DIR ${CMAKE_BINARY_DIR} + SOURCE_DIR ${CMAKE_BINARY_DIR}/${proj} + BUILD_IN_SOURCE 1 + CONFIGURE_COMMAND "" + BUILD_COMMAND "" + INSTALL_COMMAND ${PYTHON_EXECUTABLE} setup.py install + LOG_INSTALL 1 + DEPENDS + ${${proj}_DEPENDENCIES} + ) + + ExternalProject_GenerateProjectDescription_Step(${proj} + VERSION ${_version} + ) + +else() + ExternalProject_Add_Empty(${proj} DEPENDS ${${proj}_DEPENDENCIES}) +endif()