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