From a5570333926d2729f1871d2c4a5850d90f10b215 Mon Sep 17 00:00:00 2001 From: Piotr Dziwinski Date: Sun, 21 Sep 2014 00:07:52 +0200 Subject: [PATCH] Finish rewriting translation generation: help directory support --- CMakeLists.txt | 1 + help/CMakeLists.txt | 28 ++++++- i18n-tools/HelpI18N.cmake | 83 +++++++++++++++++++ i18n-tools/LevelsI18N.cmake | 21 ++--- i18n-tools/scripts/clean_po_files.sh | 18 +++- ...ations.sh => create_level_translations.sh} | 32 +++---- i18n-tools/scripts/run_po4a.sh | 36 ++++++++ levels/CMakeLists.txt | 8 +- 8 files changed, 194 insertions(+), 33 deletions(-) create mode 100644 i18n-tools/HelpI18N.cmake rename i18n-tools/scripts/{create_translations.sh => create_level_translations.sh} (60%) create mode 100755 i18n-tools/scripts/run_po4a.sh diff --git a/CMakeLists.txt b/CMakeLists.txt index dea049d1..3b0f11c8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -19,5 +19,6 @@ install(DIRECTORY textures DESTINATION ${COLOBOT_INSTALL_DATA_DIR}) install(DIRECTORY DESTINATION ${COLOBOT_INSTALL_DATA_DIR}/mods) # Empty directory set(DATA_SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}) + add_subdirectory(help) add_subdirectory(levels) diff --git a/help/CMakeLists.txt b/help/CMakeLists.txt index 2efb7932..b9d54928 100644 --- a/help/CMakeLists.txt +++ b/help/CMakeLists.txt @@ -1,3 +1,29 @@ cmake_minimum_required(VERSION 2.8) -# TODO handle help files... \ No newline at end of file + +include(../i18n-tools/HelpI18N.cmake) + +set(HELP_INSTALL_DATA_DIR ${COLOBOT_INSTALL_DATA_DIR}/help) + +## +# Add help category directory +## +function(add_help_category help_category_dir) + file(GLOB help_files RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} ${help_category_dir}/E/*.txt) + list(SORT help_files) + if(PO4A AND EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${help_category_dir}/po/) + generate_help_i18n(translated_help_dirs "${help_files}" ${help_category_dir}/po) + else() + set(translated_help_dirs "") + endif() + install(DIRECTORY ${help_category_dir}/E DESTINATION ${HELP_INSTALL_DATA_DIR}/${help_category_dir}) + foreach(translated_help_dir ${translated_help_dirs}) + install(DIRECTORY ${translated_help_dir} DESTINATION ${HELP_INSTALL_DATA_DIR}/${help_category_dir}) + endforeach() +endfunction() + + +add_help_category(bots) +add_help_category(cbot) +add_help_category(generic) +add_help_category(object) diff --git a/i18n-tools/HelpI18N.cmake b/i18n-tools/HelpI18N.cmake new file mode 100644 index 00000000..bc33c2af --- /dev/null +++ b/i18n-tools/HelpI18N.cmake @@ -0,0 +1,83 @@ +## +# Meta-infrastructure to allow po-based translation of Colobot help files +## + +find_program(PO4A po4a) + +if(NOT PO4A) + message(WARNING "PO4A not found, help files will NOT be translated!") +endif() + +set(HELP_I18N_WORK_DIR ${CMAKE_CURRENT_BINARY_DIR}/help-po) + +## +# Generate translated help files in separate directories per language +## +function(generate_help_i18n result_generated_help_dirs source_help_files po_dir) + get_filename_component(abs_po_dir ${po_dir} ABSOLUTE) + # generated config file for po4a + set(po4a_cfg_file ${HELP_I18N_WORK_DIR}/${po_dir}/help_po4a.cfg) + + # get translations from po directory + file(WRITE ${po4a_cfg_file} "[po_directory] ${abs_po_dir}\n") + + set(output_help_dir ${HELP_I18N_WORK_DIR}/${po_dir}/help) + set(output_help_subdirs "") + + # prepare output directories + file(GLOB po_files ${po_dir}/*.po) + foreach(po_file ${po_files}) + get_filename_component(po_file_name ${po_file} NAME) + # get language letter e.g. "de.po" -> "d" + string(REGEX REPLACE ".\\.po" "" language_char ${po_file_name}) + string(TOUPPER ${language_char} language_char) + set(language_help_subdir ${output_help_dir}/${language_char}) + file(MAKE_DIRECTORY ${language_help_subdir}) + list(APPEND output_help_subdirs ${language_help_subdir}) + endforeach() + + # add translation rules for help files + foreach(source_help_file ${source_help_files}) + get_filename_component(abs_source_help_file ${source_help_file} ABSOLUTE) + get_filename_component(help_file_name ${source_help_file} NAME) + + file(APPEND ${po4a_cfg_file} "\n[type:colobothelp] ${abs_source_help_file}") + foreach(po_file ${po_files}) + get_filename_component(po_file_name ${po_file} NAME) + # get language code e.g. "de.po" -> "de" + string(REPLACE ".po" "" language_code ${po_file_name}) + # get language letter e.g. "de.po" -> "d" + string(REGEX REPLACE ".\\.po" "" language_char ${po_file_name}) + string(TOUPPER ${language_char} language_char) + # generated file for single language + set(generated_help_file ${output_help_dir}/${language_char}/${help_file_name}) + file(APPEND ${po4a_cfg_file} " \\\n ${language_code}:${generated_help_file}") + endforeach() + endforeach() + + # dummy files to signal that scripts have finished running + set(translation_signalfile ${HELP_I18N_WORK_DIR}/${po_dir}/translations) + set(po_clean_signalfile ${HELP_I18N_WORK_DIR}/${po_dir}/po_clean) + + # script to run po4a and generate translated files + add_custom_command(OUTPUT ${translation_signalfile} + COMMAND ${DATA_SOURCE_DIR}/i18n-tools/scripts/run_po4a.sh ${po4a_cfg_file} ${translation_signalfile} + DEPENDS ${po_files}) + + file(GLOB pot_file ${po_dir}/*.pot) + set(po_files ${po_files} ${pot_file}) + + # script to do some cleanups in updated *.po and *.pot files + string(REPLACE ";" ":" escaped_po_files "${po_files}") + add_custom_command(OUTPUT ${po_clean_signalfile} + COMMAND ${DATA_SOURCE_DIR}/i18n-tools/scripts/clean_po_files.sh ${escaped_po_files} ${translation_signalfile} ${po_clean_signalfile} + DEPENDS ${translation_signalfile} + ) + + # generate some unique string for target name + string(REGEX REPLACE "[/\\]" "_" target_suffix ${po_dir}) + add_custom_target(level_i18n-${target_suffix} ALL DEPENDS ${translation_signalfile} ${po_clean_signalfile}) + + # return the translated files + set(${result_generated_help_dirs} ${output_help_subdirs} PARENT_SCOPE) +endfunction() \ No newline at end of file diff --git a/i18n-tools/LevelsI18N.cmake b/i18n-tools/LevelsI18N.cmake index 4c85382e..d3593c77 100644 --- a/i18n-tools/LevelsI18N.cmake +++ b/i18n-tools/LevelsI18N.cmake @@ -1,5 +1,5 @@ ## -# Meta-infrastructure to allow po-based translation of Colobot help files and scene-description (level) files. +# Meta-infrastructure to allow po-based translation of Colobot level files ## find_program(PO4A po4a) @@ -8,9 +8,6 @@ if(NOT PO4A) message(WARNING "PO4A not found, level files will NOT be translated!") endif() -set(LEVEL_INSTALL_DATA_DIR ${COLOBOT_INSTALL_DATA_DIR}/levels) -set(HELP_INSTALL_DATA_DIR ${COLOBOT_INSTALL_DATA_DIR}/help) - set(LEVELS_I18N_WORK_DIR ${CMAKE_CURRENT_BINARY_DIR}/levels-po) ## @@ -63,7 +60,8 @@ function(generate_chaptertitles_i18n result_translated_chaptertitle_files source string(REPLACE ";" ":" escaped_abs_source_chaptertitle_files "${abs_source_chaptertitle_files}") string(REPLACE ";" ":" escaped_translated_chaptertitle_files "${translated_chaptertitle_files}") add_custom_command(OUTPUT ${translation_signalfile} - COMMAND ${DATA_SOURCE_DIR}/i18n-tools/scripts/create_translations.sh ${escaped_abs_source_chaptertitle_files} ${escaped_translated_chaptertitle_files} ${po4a_cfg_file} ${translation_signalfile} + COMMAND ${DATA_SOURCE_DIR}/i18n-tools/scripts/run_po4a.sh ${po4a_cfg_file} + COMMAND ${DATA_SOURCE_DIR}/i18n-tools/scripts/create_level_translations.sh ${escaped_abs_source_chaptertitle_files} ${escaped_translated_chaptertitle_files} ${translation_signalfile} DEPENDS ${po_files}) file(GLOB pot_file ${po_dir}/*.pot) @@ -87,7 +85,7 @@ endfunction() ## # Generate translated level and help files using po4a ## -function(generate_level_i18n result_translated_level_file result_translated_help_files source_level_file help_dir po_dir) +function(generate_level_i18n result_translated_level_file result_translated_help_files source_level_file source_help_files po_dir) get_filename_component(abs_po_dir ${po_dir} ABSOLUTE) # generated config file for po4a set(po4a_cfg_file ${LEVELS_I18N_WORK_DIR}/${po_dir}/scene_po4a.cfg) @@ -121,12 +119,10 @@ function(generate_level_i18n result_translated_level_file result_translated_help set(output_help_dir ${LEVELS_I18N_WORK_DIR}/${po_dir}/help) set(translated_help_files "") - file(GLOB help_files ${help_dir}/*.txt) - list(SORT help_files) - foreach(help_file ${help_files}) - get_filename_component(help_file_name ${help_file} NAME) + foreach(source_help_file ${source_help_files}) + get_filename_component(help_file_name ${source_help_file} NAME) - file(APPEND ${po4a_cfg_file} "\n[type:colobothelp] ${help_file}") + file(APPEND ${po4a_cfg_file} "\n[type:colobothelp] ${source_help_file}") foreach(po_file ${po_files}) get_filename_component(po_file_name ${po_file} NAME) # get language code e.g. "de.po" -> "de" @@ -149,7 +145,8 @@ function(generate_level_i18n result_translated_level_file result_translated_help # script to run po4a and consolidate the translations add_custom_command(OUTPUT ${translation_signalfile} - COMMAND ${DATA_SOURCE_DIR}/i18n-tools/scripts/create_translations.sh ${abs_source_level_file} ${output_level_file} ${po4a_cfg_file} ${translation_signalfile} + COMMAND ${DATA_SOURCE_DIR}/i18n-tools/scripts/run_po4a.sh ${po4a_cfg_file} + COMMAND ${DATA_SOURCE_DIR}/i18n-tools/scripts/create_level_translations.sh ${abs_source_level_file} ${output_level_file} ${translation_signalfile} DEPENDS ${po_files}) file(GLOB pot_file ${po_dir}/*.pot) diff --git a/i18n-tools/scripts/clean_po_files.sh b/i18n-tools/scripts/clean_po_files.sh index b1d89a9d..bc0799a4 100755 --- a/i18n-tools/scripts/clean_po_files.sh +++ b/i18n-tools/scripts/clean_po_files.sh @@ -1,6 +1,20 @@ #!/bin/bash -# Stop on errors +## +# Script to do some cleaning up of merged/generated *.po and *.pot files +# +# It is basically a sed wrapper that does two things: +# - remove information about absolute filenames which were used to generate translations +# - remove modification date of file +# +# By doing these two things, it makes sure that *.po and *.pot files do not change +# compared to versions stored in repository when building the project +# +# The arguments are a colon-separated list of *.po or *.pot files and +# two dummy signal files used by build system that must be updated +## + +# stop on errors set -e if [ $# -ne 3 ]; then @@ -17,7 +31,7 @@ IFS=':' read -a po_files_array <<< "$PO_FILES" for po_file in "${po_files_array[@]}"; do # strip unnecessary part of file names - sed -i -E 's|^#: .*(levels/.*)$|#: \1|' "$po_file" + sed -i -E 's|^#: .*data/(.*)$|#: \1|' "$po_file" # remove the creation date sed -i -E 's|^("POT-Creation-Date:).*$|\1 DATE\\n"|' "$po_file" done diff --git a/i18n-tools/scripts/create_translations.sh b/i18n-tools/scripts/create_level_translations.sh similarity index 60% rename from i18n-tools/scripts/create_translations.sh rename to i18n-tools/scripts/create_level_translations.sh index 93e53d53..88d9f9ba 100755 --- a/i18n-tools/scripts/create_translations.sh +++ b/i18n-tools/scripts/create_level_translations.sh @@ -1,29 +1,31 @@ #!/bin/bash +## +# Script to consolidate multiple translated level files (scene.txt or chaptertitle.txt), +# generated previously by PO4A, into a single all-in-one output file +# +# It supports multiple pairs of source and output files and makes the assumption that +# each source file was processed by PO4A to yield output files named like $output_file.$language_code +# +# Basically, it is a simple sed wrapper that uses the source file and the translated files to copy-paste +# content into resulting output file +# +# The arugments are list of source files as a colon-separated list, list of output files also as colon-separated list +# and dummy signal file used by build system +## + # Stop on errors set -e -if [ $# -ne 4 ]; then +if [ $# -ne 3 ]; then echo "Invalid arguments!" >&2 - echo "Usage: $0 source_file1[:source_file2:...] output_file1[:output_file2:...] po4a_config_file translation_signalfile" >&2 + echo "Usage: $0 source_file1[:source_file2:...] output_file1[:output_file2:...] translation_signalfile" >&2 exit 1 fi SOURCE_FILES="$1" OUTPUT_FILES="$2" -PO4A_FILE="$3" -TRANSLATION_SIGNALFILE="$4" - -# get the directory where the script is in -SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" - -# generate translated files using po4a -if [ -n "$VERBOSE" ]; then - verbosity="-v" -else - verbosity="-q" -fi -PERL5LIB="${SCRIPT_DIR}/perllib${PERL5LIB+:}$PERL5LIB" po4a -k0 $verbosity -f "$PO4A_FILE" --msgmerge-opt --no-wrap +TRANSLATION_SIGNALFILE="$3" IFS=':' read -a source_files_array <<< "$SOURCE_FILES" IFS=':' read -a output_files_array <<< "$OUTPUT_FILES" diff --git a/i18n-tools/scripts/run_po4a.sh b/i18n-tools/scripts/run_po4a.sh new file mode 100755 index 00000000..d45895e2 --- /dev/null +++ b/i18n-tools/scripts/run_po4a.sh @@ -0,0 +1,36 @@ +#!/bin/bash + +## +# Script to execute PO4A with proper enviroment and commandline options +# +# The arguments are config file which is assumed to be already present and +# optional dummy signal file which is used by build system +## + +# stop on errors +set -e + +if [ $# -ne 1 -a $# -ne 2 ]; then + echo "Invalid arguments!" >&2 + echo "Usage: $0 po4a_config_file [po4a_signalfile]" >&2 + exit 1 +fi + +PO4A_CONFIG_FILE="$1" +PO4A_SIGNALFILE="$2" + +# get the directory where the script is in +SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" + +# run po4a +if [ -n "$VERBOSE" ]; then + verbosity="-v" +else + verbosity="-q" +fi +PERL5LIB="${SCRIPT_DIR}/perllib${PERL5LIB+:}$PERL5LIB" po4a -k0 $verbosity -f "$PO4A_CONFIG_FILE" --msgmerge-opt --no-wrap + +# if applicable, touch dummy signal file to indicate success +if [ -n "$PO4A_SIGNALFILE" ]; then + touch "$PO4A_SIGNALFILE" +fi \ No newline at end of file diff --git a/levels/CMakeLists.txt b/levels/CMakeLists.txt index c28da7e7..a2541475 100644 --- a/levels/CMakeLists.txt +++ b/levels/CMakeLists.txt @@ -2,6 +2,8 @@ cmake_minimum_required(VERSION 2.8) include(../i18n-tools/LevelsI18N.cmake) +set(LEVEL_INSTALL_DATA_DIR ${COLOBOT_INSTALL_DATA_DIR}/levels) + ## # Add level category directory with all chapters inside ## @@ -44,14 +46,14 @@ endfunction() # Add level directory ## function(add_level level_dir) + file(GLOB original_help_files ${level_dir}/help/*.txt) + list(SORT original_help_files) if(PO4A AND EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${level_dir}/po/) - generate_level_i18n(translated_level_file translated_help_files ${level_dir}/scene.txt ${level_dir}/help ${level_dir}/po) + generate_level_i18n(translated_level_file translated_help_files ${level_dir}/scene.txt "${original_help_files}" ${level_dir}/po) else() set(translated_level_file ${level_dir}/scene.txt) endif() install(FILES ${translated_level_file} DESTINATION ${LEVEL_INSTALL_DATA_DIR}/${level_dir}) - - file(GLOB original_help_files ${level_dir}/help/*.txt) install(FILES ${original_help_files} DESTINATION ${LEVEL_INSTALL_DATA_DIR}/${level_dir}/help) install(FILES ${translated_help_files} DESTINATION ${LEVEL_INSTALL_DATA_DIR}/${level_dir}/help) endfunction()