1# Copyright (c) 2012, Jarryd Beck 2# All rights reserved. 3# 4# Redistribution and use in source and binary forms, with or without 5# modification, are permitted provided that the following conditions are met: 6# 7# Redistributions of source code must retain the above copyright notice, this 8# list of conditions and the following disclaimer. 9# Redistributions in binary form must reproduce the above copyright notice, 10# this list of conditions and the following disclaimer in the documentation 11# and/or other materials provided with the distribution. 12# 13# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 14# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 16# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 17# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 18# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 19# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 20# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 21# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 22# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 23# POSSIBILITY OF SUCH DAMAGE. 24 25 26# This module creates build rules for updating translation files made 27# with gettext 28# In your top level CMakeLists.txt, do 29# include(GettextTranslate) 30# then in any po directory where you want things to be translated, write 31# GettextTranslate() 32# 33# This module also finds the gettext binaries. If these are in a non-standard 34# location, you can define the following variables to provide paths to search 35# in 36# GettextTranslate_BINARIES --- a path in which to look for every program 37# GettextTranslate_XGETTEXT --- the xgettext program 38# GettextTranslate_MSGINIT --- the msginit program 39# GettextTranslate_MSGFILTER --- the msgfilter program 40# GettextTranslate_MSGCONV --- the msgconv program 41# GettextTranslate_MSGMERGE --- the msgmerge program 42# GettextTranslate_MSGFMT --- the msgfmt program 43# these are searched first before $PATH, so set this if you have your own 44# version that overrides the system version 45# 46# it reads variables from Makevars, one of the most important being DOMAIN 47# it reads the languages to generate from LINGUAS 48# 49# it adds the following targets 50# update-po 51# update-gmo 52# ${DOMAIN}-pot.update 53# generate-${DOMAIN}-${lang}-po 54# generate-${DOMAIN}-${lang}-gmo 55# 56# where ${DOMAIN} is the DOMAIN variable read from Makevars 57# and ${lang} is each language mentioned in LINGUAS 58# 59# if you want update-gmo to be added to the "all" target, then define the 60# variable GettextTranslate_ALL before including this file 61# 62# by default, the gmo files are built in the source directory. If you want 63# them to be built in the binary directory, then define the variable 64# GettextTranslate_GMO_BINARY 65 66 67 68# add the update-po and update-gmo targets, the actual files that need to 69# depend on this will be added as we go 70 71if (DEFINED GettextTranslate_ALL) 72 set(_addToALL "ALL") 73endif() 74 75add_custom_target(update-po) 76add_custom_target(update-gmo ${_addToALL}) 77 78#look for all the programs 79#xgettext, msginit, msgfilter, msgconv, msgmerge, msgfmt 80 81function(REQUIRE_BINARY binname varname) 82 if (defined ${${varname}-NOTFOUND}) 83 message(FATAL_ERROR "Could not find " binname) 84 endif() 85endfunction() 86 87find_program(GettextTranslate_XGETTEXT_EXECUTABLE xgettext 88 HINTS ${GettextTranslate_XGETTEXT} ${GettextTranslate_BINARIES} 89) 90REQUIRE_BINARY(xgettext GettextTranslate_XGETTEXT_EXECUTABLE) 91 92find_program(GettextTranslate_MSGINIT_EXECUTABLE msginit 93 HINTS ${GettextTranslate_MSGINIT} ${GettextTranslate_BINARIES} 94) 95REQUIRE_BINARY(msginit GettextTranslate_MSGINIT_EXECUTABLE) 96 97find_program(GettextTranslate_MSGFILTER_EXECUTABLE msgfilter 98 HINTS ${GettextTranslate_MSGFILTER} ${GettextTranslate_BINARIES} 99) 100REQUIRE_BINARY(msgfilter GettextTranslate_MSGFILTER_EXECUTABLE) 101 102find_program(GettextTranslate_MSGCONV_EXECUTABLE msgconv 103 HINTS ${GettextTranslate_MSGCONV} ${GettextTranslate_BINARIES} 104) 105REQUIRE_BINARY(msgconv GettextTranslate_MSGCONV_EXECUTABLE) 106 107find_program(GettextTranslate_MSGMERGE_EXECUTABLE msgmerge 108 HINTS ${GettextTranslate_MSGMERGE} ${GettextTranslate_BINARIES} 109) 110REQUIRE_BINARY(msgmerge GettextTranslate_MSGMERGE_EXECUTABLE) 111 112find_program(GettextTranslate_MSGFMT_EXECUTABLE msgfmt 113 HINTS ${GettextTranslate_MSGFMT} ${GettextTranslate_BINARIES} 114) 115REQUIRE_BINARY(msgfmt GettextTranslate_MSGFMT_EXECUTABLE) 116 117mark_as_advanced( 118 GettextTranslate_MSGCONV_EXECUTABLE 119 GettextTranslate_MSGFILTER_EXECUTABLE 120 GettextTranslate_MSGFMT_EXECUTABLE 121 GettextTranslate_MSGINIT_EXECUTABLE 122 GettextTranslate_MSGMERGE_EXECUTABLE 123 GettextTranslate_XGETTEXT_EXECUTABLE 124) 125 126macro(GettextTranslate) 127 128 if(GettextTranslate_GMO_BINARY) 129 set (GMO_BUILD_DIR ${CMAKE_CURRENT_BINARY_DIR}) 130 else() 131 set (GMO_BUILD_DIR ${CMAKE_CURRENT_SOURCE_DIR}) 132 endif() 133 134 if (NOT EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/POTFILES.in) 135 message(FATAL_ERROR "There is no POTFILES.in in 136 ${CMAKE_CURRENT_SOURCE_DIR}") 137 endif() 138 139 if (NOT EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/Makevars) 140 message(FATAL_ERROR "There is no Makevars in ${CMAKE_CURRENT_SOURCE_DIR}") 141 endif() 142 143 file(STRINGS ${CMAKE_CURRENT_SOURCE_DIR}/Makevars makevars 144 REGEX "^[^=]+=(.*)$" 145 ) 146 147 foreach(makevar ${makevars}) 148 string(REGEX REPLACE "^([^= ]+) =[ ]?(.*)$" "\\1" MAKEVAR_KEY ${makevar}) 149 string(REGEX REPLACE "^([^= ]+) =[ ]?(.*)$" "\\2" 150 MAKEVAR_${MAKEVAR_KEY} ${makevar}) 151 endforeach() 152 153 configure_file(${CMAKE_CURRENT_SOURCE_DIR}/POTFILES.in 154 ${CMAKE_CURRENT_BINARY_DIR}/POTFILES 155 COPYONLY 156 ) 157 158 configure_file(${CMAKE_CURRENT_SOURCE_DIR}/LINGUAS 159 ${CMAKE_CURRENT_BINARY_DIR}/LINGUAS 160 COPYONLY 161 ) 162 163 #set the directory to not clean 164 set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} 165 PROPERTY CLEAN_NO_CUSTOM true) 166 167 file(STRINGS ${CMAKE_CURRENT_SOURCE_DIR}/POTFILES.in potfiles 168 REGEX "^[^#].*" 169 ) 170 171 foreach(potfile ${potfiles}) 172 list(APPEND source_translatable 173 ${CMAKE_CURRENT_SOURCE_DIR}/${MAKEVAR_top_builddir}/${potfile}) 174 endforeach() 175 176 set(TEMPLATE_FILE ${MAKEVAR_DOMAIN}.pot) 177 set(TEMPLATE_FILE_ABS ${CMAKE_CURRENT_SOURCE_DIR}/${TEMPLATE_FILE}) 178 string(REGEX MATCHALL "[^ ]+" XGETTEXT_OPTS ${MAKEVAR_XGETTEXT_OPTIONS}) 179 #add_custom_target(${MAKEVAR_DOMAIN}.pot-update DEPENDS 180 # ${TEMPLATE_FILE_ABS} 181 #) 182 183 add_custom_target(${MAKEVAR_DOMAIN}.pot-update 184 COMMAND ${GettextTranslate_XGETTEXT_EXECUTABLE} ${XGETTEXT_OPTS} 185 -o ${TEMPLATE_FILE_ABS} 186 --default-domain=${MAKEVAR_DOMAIN} 187 --add-comments=TRANSLATORS: 188 --copyright-holder=${MAKEVAR_COPYRIGHT_HOLDER} 189 --msgid-bugs-address="${MAKEVAR_MSGID_BUGS_ADDRESS}" 190 --directory=${MAKEVAR_top_builddir} 191 --files-from=${CMAKE_CURRENT_BINARY_DIR}/POTFILES 192 --package-version=${VERSION} 193 --package-name=${CMAKE_PROJECT_NAME} 194 DEPENDS ${source_translatable} 195 ${CMAKE_CURRENT_SOURCE_DIR}/POTFILES.in 196 WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} 197 ) 198 199 #add_custom_command(OUTPUT ${TEMPLATE_FILE_ABS} 200 # COMMAND ${GettextTranslate_XGETTEXT_EXECUTABLE} ${XGETTEXT_OPTS} 201 # -o ${TEMPLATE_FILE_ABS} 202 # --default-domain=${MAKEVAR_DOMAIN} 203 # --add-comments=TRANSLATORS: 204 # --copyright-holder=${MAKEVAR_COPYRIGHT_HOLDER} 205 # --msgid-bugs-address="${MAKEVAR_MSGID_BUGS_ADDRESS}" 206 # --directory=${MAKEVAR_top_builddir} 207 # --files-from=${CMAKE_CURRENT_BINARY_DIR}/POTFILES 208 # --package-version=${VERSION} 209 # --package-name=${CMAKE_PROJECT_NAME} 210 # DEPENDS ${source_translatable} 211 # ${CMAKE_CURRENT_SOURCE_DIR}/POTFILES.in 212 # WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} 213 #) 214 215 #add_dependencies(update-po ${MAKEVAR_DOMAIN}.pot-update) 216 217 file(STRINGS ${CMAKE_CURRENT_SOURCE_DIR}/LINGUAS LINGUAS 218 REGEX "^[^#].*") 219 string(REGEX MATCHALL "[^ ]+" languages ${LINGUAS}) 220 221 foreach(lang ${languages}) 222 set(PO_FILE_NAME "${CMAKE_CURRENT_SOURCE_DIR}/${lang}.po") 223 set(GMO_FILE_NAME "${GMO_BUILD_DIR}/${lang}.gmo") 224 set(PO_TARGET "generate-${MAKEVAR_DOMAIN}-${lang}-po") 225 set(GMO_TARGET "generate-${MAKEVAR_DOMAIN}-${lang}-gmo") 226 list(APPEND po_files ${PO_TARGET}) 227 list(APPEND gmo_files ${GMO_TARGET}) 228 229 if(${lang} MATCHES "en@(.*)quot") 230 231 add_custom_command(OUTPUT ${lang}.insert-header 232 COMMAND 233 sed -e "'/^#/d'" -e 's/HEADER/${lang}.header/g' 234 ${CMAKE_CURRENT_SOURCE_DIR}/insert-header.sin > ${lang}.insert-header 235 ) 236 237 #generate the en@quot files 238 add_custom_command(OUTPUT ${PO_FILE_NAME} 239 COMMAND 240 ${GettextTranslate_MSGINIT_EXECUTABLE} -i ${TEMPLATE_FILE_ABS} 241 --no-translator -l ${lang} 242 -o - 2>/dev/null 243 | sed -f ${CMAKE_CURRENT_BINARY_DIR}/${lang}.insert-header 244 | ${GettextTranslate_MSGCONV_EXECUTABLE} -t UTF-8 245 | ${GettextTranslate_MSGFILTER_EXECUTABLE} sed -f 246 ${CMAKE_CURRENT_SOURCE_DIR}/`echo ${lang} 247 | sed -e 's/.*@//'`.sed 2>/dev/null > 248 ${PO_FILE_NAME} 249 DEPENDS ${lang}.insert-header ${TEMPLATE_FILE_ABS} 250 WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} 251 ) 252 253 else() 254 255 add_custom_command(OUTPUT ${PO_FILE_NAME} 256 COMMAND ${GettextTranslate_MSGMERGE_EXECUTABLE} --lang=${lang} 257 ${PO_FILE_NAME} ${TEMPLATE_FILE_ABS} 258 -o ${PO_FILE_NAME}.new 259 COMMAND mv ${PO_FILE_NAME}.new ${PO_FILE_NAME} 260 DEPENDS ${TEMPLATE_FILE_ABS} 261 ) 262 263 endif() 264 265 add_custom_command(OUTPUT ${GMO_FILE_NAME} 266 COMMAND ${GettextTranslate_MSGFMT_EXECUTABLE} -c --statistics --verbose 267 -o ${GMO_FILE_NAME} ${PO_FILE_NAME} 268 DEPENDS ${PO_TARGET} 269 ) 270 add_custom_target(${GMO_TARGET} DEPENDS ${GMO_FILE_NAME}) 271 272 add_custom_target(${PO_TARGET} DEPENDS ${PO_FILE_NAME}) 273 add_dependencies(${PO_TARGET} ${MAKEVAR_DOMAIN}.pot-update) 274 275 install(FILES ${GMO_FILE_NAME} DESTINATION 276 ${LOCALEDIR}/${lang}/LC_MESSAGES 277 RENAME ${MAKEVAR_DOMAIN}.mo 278 ) 279 280 endforeach() 281 282 add_dependencies(update-po ${po_files}) 283 add_dependencies(update-gmo ${gmo_files}) 284 285#string(REGEX MATCH "^[^=]+=(.*)$" parsed_variables ${makevars}) 286 287endmacro() 288