Translations.cmake 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. # translations.cmake - Translations using APT's translation system.
  2. # Copyright (C) 2009, 2016 Julian Andres Klode <jak@debian.org>
  3. function(apt_add_translation_domain)
  4. set(options)
  5. set(oneValueArgs DOMAIN)
  6. set(multiValueArgs TARGETS SCRIPTS EXCLUDE_LANGUAGES)
  7. cmake_parse_arguments(NLS "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
  8. # Build the list of source files of the target
  9. set(files "")
  10. set(abs_files "")
  11. set(scripts "")
  12. set(abs_scripts "")
  13. set(targets ${NLS_TARGETS})
  14. set(domain ${NLS_DOMAIN})
  15. set(xgettext_params
  16. --add-comments
  17. --foreign
  18. --package-name=${PROJECT_NAME}
  19. --package-version=${PACKAGE_VERSION}
  20. --msgid-bugs-address=${PACKAGE_MAIL}
  21. )
  22. foreach(source ${NLS_SCRIPTS})
  23. string(SUBSTRING ${source} 0 1 init_char)
  24. string(COMPARE EQUAL ${init_char} "/" is_absolute)
  25. if (${is_absolute})
  26. set(file "${source}")
  27. else()
  28. set(file "${CMAKE_CURRENT_SOURCE_DIR}/${source}")
  29. endif()
  30. file(RELATIVE_PATH relfile ${PROJECT_SOURCE_DIR} ${file})
  31. list(APPEND scripts ${relfile})
  32. list(APPEND abs_scripts ${file})
  33. endforeach()
  34. foreach(target ${targets})
  35. get_target_property(source_dir ${target} SOURCE_DIR)
  36. get_target_property(sources ${target} SOURCES)
  37. foreach(source ${sources})
  38. string(SUBSTRING ${source} 0 1 init_char)
  39. string(COMPARE EQUAL ${init_char} "/" is_absolute)
  40. if (${is_absolute})
  41. set(file "${source}")
  42. else()
  43. set(file "${source_dir}/${source}")
  44. endif()
  45. file(RELATIVE_PATH relfile ${PROJECT_SOURCE_DIR} ${file})
  46. set(files ${files} ${relfile})
  47. set(abs_files ${abs_files} ${file})
  48. endforeach()
  49. target_compile_definitions(${target} PRIVATE -DAPT_DOMAIN="${domain}")
  50. endforeach()
  51. if("${scripts}" STREQUAL "")
  52. set(sh_pot "/dev/null")
  53. else()
  54. set(sh_pot ${PROJECT_BINARY_DIR}/${domain}.sh.pot)
  55. # Create the template for this specific sub-domain
  56. add_custom_command (OUTPUT ${sh_pot}
  57. COMMAND xgettext ${xgettext_params} -L Shell
  58. -o ${sh_pot} ${scripts}
  59. DEPENDS ${abs_scripts}
  60. VERBATIM
  61. WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
  62. )
  63. endif()
  64. add_custom_command (OUTPUT ${PROJECT_BINARY_DIR}/${domain}.c.pot
  65. COMMAND xgettext ${xgettext_params} -k_ -kN_
  66. --keyword=P_:1,2
  67. -o ${PROJECT_BINARY_DIR}/${domain}.c.pot ${files}
  68. DEPENDS ${abs_files}
  69. VERBATIM
  70. WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
  71. )
  72. # We are building a ${domain}.pot with a header for launchpad, but we also
  73. # build a ${domain.pot}-tmp as a byproduct. The msgfmt command than depend
  74. # on the byproduct while their target depends on the output, so that msgfmt
  75. # does not have to be rerun if nothing in the template changed.
  76. add_custom_command (OUTPUT ${PROJECT_BINARY_DIR}/${domain}.pot
  77. BYPRODUCTS ${PROJECT_BINARY_DIR}/${domain}.pot-tmp
  78. COMMAND msgcomm --more-than=0 --sort-by-file
  79. ${sh_pot}
  80. ${PROJECT_BINARY_DIR}/${domain}.c.pot
  81. --output=${PROJECT_BINARY_DIR}/${domain}.pot
  82. COMMAND msgcomm --more-than=0 --omit-header --sort-by-file
  83. ${sh_pot}
  84. ${PROJECT_BINARY_DIR}/${domain}.c.pot
  85. --output=${PROJECT_BINARY_DIR}/${domain}.pot-tmp0
  86. COMMAND cmake -E copy_if_different
  87. ${PROJECT_BINARY_DIR}/${domain}.pot-tmp0
  88. ${PROJECT_BINARY_DIR}/${domain}.pot-tmp
  89. DEPENDS ${sh_pot}
  90. ${PROJECT_BINARY_DIR}/${domain}.c.pot
  91. WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}
  92. )
  93. # We need a target to depend on otherwise, the msgmerge might not get called
  94. # with the make generator
  95. add_custom_target(nls-${domain}-template DEPENDS ${PROJECT_BINARY_DIR}/${domain}.pot)
  96. # Build .mo files
  97. file(GLOB translations "${PROJECT_SOURCE_DIR}/po/*.po")
  98. list(SORT translations)
  99. foreach(file ${translations})
  100. get_filename_component(langcode ${file} NAME_WE)
  101. if ("${langcode}" IN_LIST NLS_EXCLUDE_LANGUAGES)
  102. continue()
  103. endif()
  104. set(outdir ${PROJECT_BINARY_DIR}/locale/${langcode}/LC_MESSAGES)
  105. file(MAKE_DIRECTORY ${outdir})
  106. # Command to merge and compile the messages. As explained in the custom
  107. # command for msgcomm, this depends on byproduct to avoid reruns
  108. add_custom_command(OUTPUT ${outdir}/${domain}.po
  109. COMMAND msgmerge -qo ${outdir}/${domain}.po ${file} ${PROJECT_BINARY_DIR}/${domain}.pot-tmp
  110. DEPENDS ${file} ${PROJECT_BINARY_DIR}/${domain}.pot-tmp
  111. )
  112. add_custom_command(OUTPUT ${outdir}/${domain}.mo
  113. COMMAND msgfmt --statistics -o ${outdir}/${domain}.mo ${outdir}/${domain}.po
  114. DEPENDS ${outdir}/${domain}.po
  115. )
  116. set(mofiles ${mofiles} ${outdir}/${domain}.mo)
  117. install(FILES ${outdir}/${domain}.mo
  118. DESTINATION "${CMAKE_INSTALL_LOCALEDIR}/${langcode}/LC_MESSAGES")
  119. endforeach(file ${translations})
  120. add_custom_target(nls-${domain} ALL DEPENDS ${mofiles} nls-${domain}-template)
  121. endfunction()
  122. # Usage: apt_add_update_po(output domain [domain ...])
  123. function(apt_add_update_po)
  124. set(options)
  125. set(oneValueArgs TEMPLATE)
  126. set(multiValueArgs DOMAINS EXCLUDE_LANGUAGES)
  127. cmake_parse_arguments(NLS "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
  128. set(output ${CMAKE_CURRENT_SOURCE_DIR}/${NLS_TEMPLATE}.pot)
  129. foreach(domain ${NLS_DOMAINS})
  130. list(APPEND potfiles ${PROJECT_BINARY_DIR}/${domain}.pot)
  131. endforeach()
  132. get_filename_component(master_name ${output} NAME_WE)
  133. add_custom_target(nls-${master_name}
  134. COMMAND msgcomm --sort-by-file --add-location=file
  135. --more-than=0 --output=${output}
  136. ${potfiles}
  137. DEPENDS ${potfiles})
  138. file(GLOB translations "${PROJECT_SOURCE_DIR}/po/*.po")
  139. if (NOT TARGET update-po)
  140. add_custom_target(update-po)
  141. endif()
  142. foreach(translation ${translations})
  143. get_filename_component(langcode ${translation} NAME_WE)
  144. if ("${langcode}" IN_LIST NLS_EXCLUDE_LANGUAGES)
  145. continue()
  146. endif()
  147. add_custom_target(update-po-${langcode}
  148. COMMAND msgmerge -q --update --backup=none ${translation} ${output}
  149. DEPENDS nls-${master_name}
  150. )
  151. add_dependencies(update-po update-po-${langcode})
  152. endforeach()
  153. add_dependencies(update-po nls-${master_name})
  154. endfunction()
  155. function(apt_add_po_statistics excluded)
  156. add_custom_target(statistics)
  157. file(GLOB translations "${PROJECT_SOURCE_DIR}/po/*.po")
  158. foreach(translation ${translations})
  159. get_filename_component(langcode ${translation} NAME_WE)
  160. if ("${langcode}" IN_LIST excluded)
  161. add_custom_command(
  162. TARGET statistics PRE_BUILD
  163. COMMAND printf "%-6s " "${langcode}:"
  164. COMMAND echo "ignored"
  165. VERBATIM
  166. )
  167. continue()
  168. endif()
  169. add_custom_command(
  170. TARGET statistics PRE_BUILD
  171. COMMAND printf "%-6s " "${langcode}:"
  172. COMMAND msgfmt --statistics -o /dev/null ${translation}
  173. VERBATIM
  174. )
  175. endforeach()
  176. endfunction()