Accéder au contenu.
Menu Sympa

trad-gnu - Re: [[TRAD GNU]] Problème avec make report

Objet : Liste de travail pour la traduction de la philosophie GNU (liste à inscription publique)

Archives de la liste

Re: [[TRAD GNU]] Problème avec make report


Chronologique Discussions 
  • From: Therese Godefroy <godef.th AT free.fr>
  • To: trad-gnu AT april.org
  • Subject: Re: [[TRAD GNU]] Problème avec make report
  • Date: Fri, 23 Mar 2012 19:35:21 +0100

Le vendredi 23 mars 2012 à 14:44 +0100, D. Barbier a écrit :
> Le 23 mars 2012 14:22, Therese Godefroy a écrit :
> > Le jeudi 22 mars 2012 à 23:08 +0100, D. Barbier a écrit :
> >> Le 22 mars 2012 15:48, D. Barbier a écrit :
> >> > Le 22 mars 2012 15:35, Therese Godefroy a écrit :
> >> >> Bonjour Denis,
> >> >>
> >> >> J'ai un problème avec "make report" et "make VCS=yes" :
> >> >>
> >> >> ~/GNU/www/server/gnun$ make report TEAM=fr
> >> >> There are no translations for language fr.
> >>
> >> Groumpf, c'est bizarre. On dirait que ton server/gnun/gnun.mk est
> >> corrompu.
> >>
> >> Denis
> >
> > 3 installations depuis hier et toujours la même chose :
> > ~/GNU/www/server/gnun$ make report TEAM=fr
> > There are no translations for language fr.
>
> Tu peux m'envoyer ton fichier server/gnun/GNUMakefile ?
> Vérifie aussi que tu as bien un fichier server/gnun/generic.fr.html

Oui j'ai bien le fichier server/gnun/generic.fr.html
GNUmakefile est en pj.

Thérèse
# Copyright (C) 2007, 2008, 2009, 2010, 2011, 2012 Free Software
#   Foundation, Inc.

# This file is part of GNUnited Nations.

# GNUnited Nations is free software: you can redistribute it and/or
# modify it under the terms of the GNU General Public License as
# published by the Free Software Foundation, either version 3 of the
# License, or (at your option) any later version.

# GNUnited Nations is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.

# You should have received a copy of the GNU General Public License
# along with GNUnited Nations.  If not, see <http://www.gnu.org/licenses/>.

_have-Makefile := $(shell test -f Makefile && echo yes)
_have-Makefile.in := $(shell test -f Makefile.in && echo yes)

ifeq ($(_have-Makefile.in),yes)
ifeq ($(_have-Makefile),)
$(error Please run "./configure" first)
endif
endif

include config.mk

VALIDATE-HTML-NOTIFY := $(pkglibexecdir)/validate-html-notify
MAILFAIL := $(pkglibexecdir)/mailfail
MAKE-PROTOTYPE := $(pkglibexecdir)/make-prototype
UPDATE-LOCALIZED-URLS := $(pkglibexecdir)/update-localized-urls
ADD-FUZZY-DIFF := $(pkglibexecdir)/add-fuzzy-diff
COPY-MSGID := $(pkglibexecdir)/copy-msgid

PO4A-GETTEXTIZEFLAGS := -o porefs=none
PO4A-TRANSLATEFLAGS := --keep=0

PO4A-XHTMLFLAGS := --format=xhtml --master-charset=utf-8 \
		    -o ontagerror=silent \
		    -o "attributes=<meta>content" \
		    -o "untranslated=W<gnun> W<script>" \
		    -o "translated=W<pre>"

# The lower limit of the number of repeating msgids to include in compendium.
COMMONALITY := 10

# Default period to delay notice about translation being out of date
ifdef GRACE
  OUTDATED-GRACE := 60
else
# no OUTDATED-GRACE by default when there is no GRACE
  OUTDATED-GRACE := -1
endif

# Determine the VCS to use.  The conditional is for efficiency --
# there's no need to spawn a shell to determine the value when all VCS
# operations will be skipped anyway.  For the time being, Bzr is used
# as a fallback since gnu.org is expected to switch soon.
ifneq (,$(findstring yes,$(VCS)))
vcs := $(shell (test -d CVS && echo cvs) \
         || (test -d .svn && echo svn) || echo bzr)
endif

# By default, do not add any files to the repository unless VCS=yes.
ifneq (,$(findstring yes,$(VCS)))
VCSSKIP :=
else
VCSSKIP := echo "SKIP:"
endif

# Do not validate any files by default unless VALIDATE=yes.
ifneq (,$(findstring yes,$(VALIDATE)))
VALIDATESKIP :=
else
VALIDATESKIP := echo "SKIP:"
endif

# Do not send warning mails by default unless NOTIFY=yes.
ifneq (,$(findstring yes,$(NOTIFY)))
NOTIFYSKIP :=
else
NOTIFYSKIP := --dry-run
endif

rootdir := ../..

include gnun.mk

# FIXME: footer-short and footer-min are remnants from the old-new
# design; they should go at some point.
localized-includes := server/header server/head-include-1 \
		      server/head-include-2 server/banner \
		      server/html5-header server/html5-head-include-1 \
		      server/body-include-1 server/body-include-2 \
		      server/footer server/footer-short server/footer-min \
		      $(extra-templates)

# Issue a command to substitute localized includes in a HTML file.
# Usage: $(call substitute-localized-includes,$(lang)) file.$(lang).html
define substitute-localized-includes
$(SED) --in-place $(foreach inc, $(localized-includes), \
  -e 's%\(<!--#include virtual=\"/$(inc)\)\(.html\" -->\)%\1.$(1)\2%g')
endef

### Special variables for the `www' master templates ###
template-dir := $(rootdir)/server
template-files := head-include-2 \
		  body-include-1 \
		  body-include-2 \
		  footer-text \
		  outdated
template-translated-base := $(addprefix $(template-dir)/,$(template-files))
template-translated-base += $(addprefix $(rootdir)/,$(extra-templates))
template-pots := $(addsuffix .pot, \
		   $(addprefix $(template-dir)/po/,$(template-files)) \
		   $(foreach template,$(extra-templates), \
		     $(addprefix $(rootdir)/, \
		       $(dir $(template)))po/$(notdir $(template))))
template-lang = $(addsuffix .$(1).html,$(template-translated-base))
template-translated := $(foreach t-lang,$(TEMPLATE_LINGUAS), \
			 $(call template-lang,$(t-lang)))
ifeq ($(VERBOSE),yes)
$(info template-pots = $(template-pots))
$(info template-translated = $(template-translated))
endif
### End of variables declaration (templates) ###

### Special variables for whatsnew (a.k.a. gnunews) ###
# Compute everything based on the present PO files.
wn-po := $(wildcard $(template-dir)/po/whatsnew.*.po)
wn-html := $(wn-po:%.po=%.html)
gnusfl := $(subst $(template-dir)/po/whatsnew,$(rootdir)/gnusflashes, \
	    $(wn-po:%.po=%.include))
gnunews := $(template-dir)/po/whatsnew.pot $(wn-html) $(gnusfl)
ifeq ($(VERBOSE),yes)
$(info gnunews = $(gnunews))
endif
### End of variables declaration (whatsnew) ###

### Special variables for the home pages ###
home-lang = $(rootdir)/home.$(1).html $(rootdir)/home-staged.$(1).html
home-translated := $(foreach h-lang,$(HOME_LINGUAS), \
		     $(call home-lang,$(h-lang)))
ifeq ($(VERBOSE),yes)
$(info home-translated = $(home-translated))
endif
### End of variables declaration (homepages) ###

find-po = $(wildcard $(1).*.po)
### Special variables for `no-grace' items ###
staged-articles := $(no-grace-articles:%=%-staged)
staged-originals := $(subst /po/,/,$(staged-articles:%=%.html))
no-grace-items := $(no-grace-articles) $(staged-articles)
no-grace-pot := $(no-grace-items:%=%.pot)
no-grace-po := $(foreach pot, $(no-grace-pot),\
		 $(call find-po,$(basename $(pot))))
no-grace-translated := $(subst /po/,/,$(no-grace-po:%.po=%.html))
### End of variables declaration (`no-grace' items) ###

### Special variables for all other articles ###
# FIXME: Variables' computation could be optimized, but in any event
# it is much better if translators do not have to add manually anything.
articles := $(foreach dir,$(ALL_DIRS),$(addprefix $(dir)/po/,$(value $(dir))))
articles-pot := $(addprefix $(rootdir)/,$(articles:%=%.pot))
root-articles := $(foreach root-article,$(ROOT), \
		   $(addprefix $(rootdir)/po/,$(root-article)))
root-articles-pot := $(root-articles:%=%.pot)
ALL_POTS := $(articles-pot) $(root-articles-pot)
ALL_BASE := $(ALL_POTS:%.pot=%)
ALL_POS := $(foreach pot,$(ALL_POTS),$(call find-po,$(basename $(pot))))
ALL_POS_BASE := $(ALL_POS:%.po=%)
articles-translated := $(subst /po/,/,$(ALL_POS:%.po=%.html))
ifeq ($(VERBOSE),yes)
$(info ALL_POTS = $(ALL_POTS))				
$(info articles-translated = $(articles-translated))
endif
### End of variables declaration (all articles) ###

.PHONY: all vcs-add-always no-grace-items
ifeq ($(_have-Makefile),yes)
include Makefile
else
all: compendia $(template-pots) $(template-translated) $(gnunews) \
     $(home-translated) $(ALL_POTS) $(staged-originals) \
     $(articles-translated) final-stage
endif
no-grace-items: $(template-pots) $(template-translated) \
		$(home-translated) $(staged-originals) \
		$(no-grace-translated) final-stage

.PHONY: substitute-localized-urls update-localized-URLs final-stage

# Unconditional actions to run at the end of build process.
final-stage: substitute-localized-urls vcs-add-always

# Regenerate lists of localized URLs in localized-urls.mk
update-localized-URLs:
	$(UPDATE-LOCALIZED-URLS)
-include localized-urls.mk

# Substitute and unsubstitute localised URLs in translations.
substitute-localized-urls:
	$(foreach source, ${localized-url-sources}, \
	  langs=$$(echo ${rootdir}/${source}.*.html | \
		   $(SED) 's%${rootdir}/${source}\.%%g;s/\.html//g;s/\*//'); \
	  test -z "$${langs}" \
	    || for l in $${langs}; do \
		 article=${source}; \
		 po=${rootdir}/$${article%/*}/po/$${article##*/}.$${l}.po; \
		  test -f "$${po}" || continue; \
		 script=; \
		 for url in ${${source}-localized-urls}; do \
		   base=$${url%.*}; ext=$${url##*.}; \
		   escaped_url=$$(echo $${url} | $(SED) 's/\./\\./g'); \
		   escaped_localized_url=$$(echo $${url%.*}.$${l}.$${url##*.} \
					    | $(SED) 's/\./\\./g'); \
		   if test -f ${rootdir}$${url%.*}.$${l}.$${url##*.}; then \
		     script="s@$${escaped_url}@$${url%.*}.$${l}.$${url##*.}@g; \
			     $${script}"; \
		   else \
		     script="s@$${escaped_localized_url}@$${url}@g; \
			     $${script}"; \
		   fi; \
		 done; \
		 script=$$(echo $${script} | $(SED) "s/^ *//g"); \
		 file=${rootdir}/${source}.$${l}.html; \
		 if test -n "$${script}"; then \
		   $(SED) "$${script}" $${file} \
		     > $${file}.tmp; \
		   if ! cmp -s $${file} $${file}.tmp; then \
		     cp $${file}.tmp $${file}; \
		   fi; \
		   $(RM) $${file}.tmp; \
		 fi;\
	       done;)

define staged-rules
$(1)-staged.html: $(1).html
	$$(addfile)
	cp $$< $$@
endef
$(foreach article, $(subst /po/,/,$(no-grace-articles)) $(rootdir)/home,\
  $(eval $(call staged-rules,$(article))))

# The command to add a file to the repository.
define add-file
[ -f $(1) ] || (touch $(1) $(2) ; $(VCSSKIP) $(vcs) add $(1))
endef

# Specific case of add-file invocation used in many places
define addfile 
$(call add-file,$@)
endef

# Check whether the changes in the PO file are not trivial;
# update the PO when needed and remove the temporary file.
# It is assumed that the old file is $(1), and the new one is $(1).tmp.
define check-new-po
if ([ ! -f $(1) ] || [ "`diff -U 0 $(1) $(1).tmp \
     | $(GREP) -v "^\(---\|+++\|@@\)" \
     | $(GREP) -v '^[-+]"\(POT-Creation-Date\|PO-Revision-Date\|Language\):' \
     | wc -c`" -ne 0 ]); then \
  mv $(1).tmp $(1) ; \
else \
  $(RM) $(1).tmp; \
fi
endef

### Declarations for compendia ###
#
# All files specifically processed here shall live in compendia/.
# The manually maintained files are:
#
## exclude.pot
#
# Strings that shouldn't go to compendia, like GNUN slots.
#
## master.${lang}.po
#
# Translations that should be used when the specified msgid appears in
# an article; in other words, this file overrides the translations from
# other files.  Other PO files will be rebuilt whenever this file
# changes.
#
# The generated files are:
#
## compendium.pot
#
# Compiled from all POT files; a msgid is included when it appears
# more than $(COMMONALITY) times.
#
## compendium.${lang}.po
#
# Translations of strings from compendium.pot collected
# from all ${lang} PO files.
# 
# This file can be used by the human editor to update master.${lang}.po.
#
## fuzzified-compendium.${lang}.po
#
# Translations from compendium.${lang}.po marked fuzzy even if they
# are not, "previous" msgid is added when absent.
#
# This file is used as a source for missing msgstrs when merging
# the translations; it is not kept in CVS.
#
## master-translated.${lang}.po
#
# Translated current messages from master.${lang}.po.
#
# This file is used to actually update the translations in ${lang};
# it is not kept in CVS.

# Target to rebuild compendia.
.PHONY: compendia

compendia: $(foreach lang,$(TEMPLATE_LINGUAS), \
             compendia/fuzzified-compendium.$(lang).po)

compendia/compendium.pot: $(template-pots) $(ALL_POTS)
	$(addfile)
# The `--use-first' option is needed to avoid stacked "translations"
# of the header (msgid="").
	$(MSGCAT) --use-first --more-than=$(COMMONALITY) -o $@.tmp.pot $^
# msgcat produces an error when handling files with Charset "CHARSET"
# unless all files have .pot extention, so we can't just use .tmp.
	$(MSGCAT) --use-first --less-than=3 -o $@.tmp.pot $@.tmp.pot \
	  compendia/exclude.pot
	$(MSGCAT) --use-first --unique -o $@.tmp.pot $@.tmp.pot \
	  compendia/exclude.pot
	mv $@.tmp.pot $@.tmp
	$(call check-new-po,$@)

define compendium-rules
ALL_$(1)_POS := \
  $(shell ls -t $(filter %.$(1).po,$(ALL_POS) $(template-pots:.pot=.$(1).po)))

MASTER-$(1) :=
MASTER-$(1)-OPTION :=

# Define rules for compendia if there are any translations.
ifneq ($$(ALL_$(1)_POS),)

ifeq ($$(shell test -s compendia/master.$(1).po && echo yes),yes)

# Extract current translations from master compendium.
compendia/master-translated.$(1).po: compendia/master.$(1).po
	$(MSGATTRIB) --no-fuzzy --translated -o $$@ $$<

MASTER-$(1) := compendia/master-translated.$(1).po
MASTER-$(1)-OPTION := -C $$(MASTER-$(1))

endif # eq ($$(shell test -s compendia/master.$(1).po && echo yes),yes)

compendia/compendium.$(1).po: compendia/compendium.pot $$(ALL_$(1)_POS)
	$(MSGCAT) --use-first -o $$@.tmp1 $$(ALL_$(1)_POS)
	addfile=no; prev_comp=$$@; \
  test -s $$@ || { addfile=yes; prev_comp=/dev/null; } ; \
  if test -s $$@.tmp1; then \
    $(MSGMERGE) --previous -C $$@.tmp1 -o $$@.tmp $$$${prev_comp} $$<; \
  fi \
  && $(RM) $$@.tmp1 \
  && if test -s $$@.tmp; then \
       test $$$${addfile} = no || $$(addfile); \
       $(call check-new-po,$$@); \
     else \
       $(RM) $$@.tmp; \
     fi

compendia/fuzzified-compendium.$(1).po: compendia/compendium.$(1).po
	$(MSGATTRIB) --translated --clear-obsolete --set-fuzzy $$< \
  | $(COPY-MSGID) > $$@

COMPENDIUM-$(1)-OPTION := \
  $$(shell test -s compendia/fuzzified-compendium.$(1).po \
    && echo -C compendia/fuzzified-compendium.$(1).po)

endif # ifneq ($$(ALL_$(1)_POS),)
endef # compendium-rules

$(foreach lang,$(TEMPLATE_LINGUAS),$(eval $(call compendium-rules,$(lang))))

### End declarations for compendia ###

# Compile translations list
define generate-translinks
$(call add-file,$(1).translist); \
file=$(1).translist; cp translinks-head.html $$$${file}; \
$(GREP) -v "^#" languages.txt \
  | while read language; do \
      code=$$$${language%%	*}; \
      case $$$${code} in \
        en ) suffix=""; \
             url_suffix=$(if $(findstring no, $(MULTIVIEWS)),"",".en") ;; \
        * ) suffix=.$$$${code}; url_suffix="$$$${suffix}" ;; \
      esac; \
      lang=$$$${language%	*}; lang=$$$${lang#*	}; \
      name=$$$${language##*	}; \
      url_stem=$(subst /po/,/,$(subst $(rootdir),,$(1))); \
      article=$(subst /po/,/,$(1)); \
      if test -f $$$${article}$$$${suffix}.html; then \
        echo '<!-- '$$$${lang}' -->' >> $$$${file}; \
        echo -n '<li><a href="'$$$${url_stem}$$$${url_suffix}.html'">' \
                 >> $$$${file}; \
        echo $$$${name}'</a>&nbsp;['$$$${code}']</li>' >> $$$${file}; \
      fi; \
    done; \
cat translinks-tail.html >> $$$${file};
endef

# Replace SSI directives to include initial translations list with
# directives to include the generated translist file.
define update-translinks-include
if $(GREP) \
       '<!--#include virtual="/server/gnun/initial-translations-list\.html" ' \
       $(subst /po/,/,$(1).html); then \
  $(SED) --in-place \
    '/^<!--#set var="article_name"/d;\
     s/<!--#include virtual="\/server\/gnun\/initial-translations-list\.html/\
     <!--#include virtual="$(subst /,\/,$(subst $(rootdir),,$(1))).translist/' \
    $(subst /po/,/,$(1).html); \
fi
endef

# The command to generate pot file which perform additional checks
# whether the changes are not trivial (regarding only
# POT-Creation-Date), in which case the changes are ignored.
define generate-pot
$(MAILFAIL) $(NOTIFYSKIP) $(web-addr) \
  "[GNUN Error] POT generation of $(subst $(rootdir)/,,$@) failed" \
  $(PO4A_GETTEXTIZE) $(PO4A-XHTMLFLAGS) $(PO4A-GETTEXTIZEFLAGS) \
  --master $< --po $@.tmp
$(call check-new-po,$@)
touch $@
endef

# The command to generate the translated article $(3) in language $(1)
# in HTML format from a PO file $(2).  The result is further manipulated
# in the recipes.
#
# If a translator commits a PO file based on an old version of the
# POT, it is not msgmerge'd as `make' considers the corresponding
# $(2) target up-to-date.  As a result, the generated HTML
# translations have English strings (but no fuzzy strings in the PO)
# since there's no match between msgid/msgstr.  Invoke update-po
# unconditionally to cope with that (valid) scenario.
define generate-html
$(call update-po,$(2),$(2:.$(1).po=.pot),$(1)); \
$(PO4A_TRANSLATE) $(PO4A-XHTMLFLAGS) $(PO4A-TRANSLATEFLAGS) \
  --master $$< --po $(2) --localized $(3); \
  $(call substitute-localized-includes,$(1)) $(3)
endef

comma := ,
# Generate diff file against latest translated revision
# when available.
# Add notice about the translation being out of date.
# The notice is inserted after every line beginning with
# "<!--GNUN: OUT-OF-DATE NOTICE-->"
# If no such lines are found in the file, the notice
# is inserted after <!--#include virtual="/server/banner"-->.
# Limitation: it doesn't notice that GRACE is expired
# unless the POT file is updated at least once after
# the HTML file is marked outdated. In practice this doesn't
# matter since GRACE value is very high.
define mark-outdated
marker='GNUN: OUT-OF-DATE NOTICE'; \
$(GREP) -q '^<!--'"$$$${marker}-->" $(1) \
 || marker='#include virtual="\/server\/banner'; \
original=$(1); original=$$$${original%$(2).html}html; \
$(if $(WDIFF), \
  saved_file=$$$${original%/*.html}/po/$$$${original##*/}; \
  saved_file=$$$${saved_file%html}$(2);\
  diff_file=$$$${saved_file}-diff.html; \
  saved_file=$$$${saved_file}-en.html; \
  if test -f $$$${saved_file}; then \
    $(call add-file $(comma) $$$${diff_file}) \
    $(SED) "s/</\&lt;/g;s/>/\&gt;/g" < $$$${saved_file} \
	   > $$$${saved_file}.tmp; \
    $(SED) "s/</\&lt;/g;s/>/\&gt;/g" < $$$${original} \
	   > $$$${saved_file}.tmp1; \
    $(SED) "s%<title></title>%<title>$$$${original#$(rootdir)}-diff</title>%" \
	   < diff-page-head.html > $$$${diff_file}; \
    $(WDIFF) --start-delete '<span class="removed"><del><strong>' \
	     --end-delete '</em></strong></span>' \
	     --start-insert '<span class="inserted"><ins><em>' \
	     --end-insert '</em></ins></span>' \
	    $$$${saved_file}.tmp $$$${saved_file}.tmp1 \
	    >> $$$${diff_file}; \
    cat diff-page-tail.html >> $$$${diff_file}; \
    $(RM) $$$${saved_file}.tmp $$$${saved_file}.tmp1; \
  fi; \
  test -f "$$$${diff_file}" || diff_file=""; \
 , diff_file=""; \
 ) \
$(SED) --in-place \
'/^<!--#set var="PO_FILE"/,/<!--#include virtual="\/server\/outdated/d;\
 /^<!--'"$$$${marker}"'/a\
  <!--#set var="PO_FILE"\n \
    value='"'<a href=\"http://www.gnu.org$$$${PO#$(rootdir)}\">\n\
           http://www.gnu.org$$$${PO#$(rootdir)}</a>'"' -->\n\
  <!--#set var="ORIGINAL_FILE" value="'"$$$${original#$(rootdir)}"'" -->\n \
  <!--#set var="DIFF_FILE" value="'"$$$${diff_file#$(rootdir)}"'" -->\n \
<!--#include virtual="/server/outdated.$(2).html" -->' $(1) \
 || true
endef

# The command to check the validity of a PO file.
define check-po
$(MAILFAIL) $(NOTIFYSKIP) $(transl-addr) \
  "[GNUN Error] $$$${PO#../../} is not a valid PO file" \
  $(VALIDATESKIP) $(MSGFMT) --check --verbose --output-file=/dev/null $$$$PO
endef

# Get the generation date of the oldest POT with incomplete
# translation stored in `Outdated-Since' field of the header.
define extract-outdated-date
($(SED) --quiet \
   '1,/^msgstr/d;/^$$$$/q 0;/^"Outdated-Since:/{s/^"Outdated-Since: \(.*\).."$$$$/\1/;p;q 1;}' $(1); \
 test $$$$? != 0 \
)
endef

# Copy POT generation date to `Outdated-Since' field
# unless the latter is already present.
# Insert the field after `Content-Transfer-Encoding'
# whither msgmerge would move it.
define insert-outdated-date
($(call extract-outdated-date,$(1)) > /dev/null \
 || $(SED) --in-place \
      '1,/^"POT-Creation-Date:/{\
           p;s/^"POT-Creation-Date:/"Outdated-Since:/;h;d};\
       1,/^"Content-Transfer-Encoding:/{\
         s/^\("Content-Transfer-Encoding: \)/\1/;p;t insert;d;\
         :insert x}' $(1))
endef

# Remove `Outdated-Since' field from the header.
define remove-outdated-date
$(SED) --in-place \
  '/^msgid ""$$$$/,/^$$$$/{s/^"Outdated-Since: //;t rm;p;:rm d}' $(1)
endef

define update-po-status
if LC_ALL=C $(MSGFMT) --statistics -o /dev/null $(1) 2>&1 \
    | $(EGREP) '(fuzzy|untranslated)' > /dev/null; then \
  $(call insert-outdated-date,$(1)); \
else \
  $(call remove-outdated-date,$(1)); \
fi
endef

# Check whether language code $(1) is present in list $(2)
# It assumes that language codes can't contain `.';
# it takes into account possibility of partial matches like
# `br' vs. `pt-br'.
define find-language
$(findstring .$(1).,$(addsuffix .,$(addprefix .,$(2))))
endef

# The command to update a PO file ($(1)) from the POT ($(2)).
# $(3) is the language code.
#
# The target is `touched' in order to make `make' to consider it
# up-to-date even if there is nothing to merge.  The default values of
# Content-Type and Content-Transfer-Encoding are replaced with commonly
# used values.  When appropriate, $(ADD-FUZZY-DIFF) is invoked.
#
# When compendia/master-translated.$(3).po present, its translations override
# the translations from $(1); when compendia/fuzzy-compendium.$(3).po is
# present, it is checked for missing translations.
define update-po
$(SED) \
  '1,/^$$$$/ { \
     s@^\("Content-Type: text/plain; charset\)=CHARSET\\n"@\1=UTF-8\\n"@; \
     s/^\("Content-Transfer-Encoding:\) ENCODING\\n"/\1 8bit\\n"/; \
   }' $(1) \
  $(if $(MASTER-$(3)), \
     | $(MSGATTRIB) --clear-obsolete \
     | $(MSGCAT) --use-first --more-than=1 $(MASTER-$(3)) - \
     | $(MSGCAT) --use-first --less-than=2 $(1) -) \
  | $(MSGMERGE) --previous $(MASTER-$(3)-OPTION) $(COMPENDIUM-$(3)-OPTION) \
    -o $(1).tmp - $(2) \
  && $(call check-new-po,$(1)) && touch $(1) \
  && ($(call update-po-status,$(1)); \
      $(if $(and $(WDIFF),$(call find-language,$(3),$(FUZZY_DIFF_LINGUAS))), \
           $(ADD-FUZZY-DIFF) --in-place $(1);) \
     )
endef

# The command to mail errors from make-prototype.
define mail-error-proto
$(MAILFAIL) $(NOTIFYSKIP) $(web-addr),$(devel-addr) \
  "[GNUN Error] Incompatible change in $(subst $(rootdir)/,,$<)"
endef

# The command to restore the necessary write permissions of the
# target.  This is a workaround for a CVS quirk that affects only the
# `www' repository.
# http://lists.gnu.org/archive/html/savannah-hackers-public/2008-06/msg00046.html
define fixperm
chmod +w $@
endef

# The command to touch the prerequisite $PO if HTML validation fails.
# Unfortunately, merely touching it does not work for the automatic
# build, because `cvs commit' is invoked after `make' and it resets
# the `Date' keyword of the faulty target (thus resetting its
# timestamp), so it becomes newer than the prerequisite.  `touch-hook'
# creates an unique file in $(CURDIR) based on the target, which is
# then processed by the `triggers' rule.  In a normal situation, the
# filename shouldn't be unique as `make' fails on the first
# encountered error.  However, this is necessary for `make -j' so it
# has to be parallel safe like all the rules.  Also for `make -k'.
# Touching the prerequisite is still needed for local non-VCS builds
# to DTRT and halt when $PO is not rectified.
# After a commit, cvs updates the working copy expanding all keywords
# on the way and sets the timestamp as per the server time.  When the
# client is not synchronized -- i.e. fencepost is currently lagging 2
# minutes -- the timestamp is in the future so touching it after `cvs
# commit' does not work.  The solution is to record a command sequence
# that will update the timestamp based on the timestamp of the target.
define touch-hook
sleep 1 ; touch $$PO ; \
echo "touch --reference=$@ --date='+1 seconds' $$PO" > $(@F).hook ; \
exit 1
endef

# The command to extract a meaningful human-readable title from a
# .LANG.html.  Some HTML entities that are sometimes used in titles
# are transformed, to avoid annoying stuff in email subjects.  The
# title is base64-encoded as the Subject header must comply with RFC
# 2822, otherwise the message is rejected by the gnu.org servers
# (sysadmin RT #600797).  Used only in article-rules, and only if
# ANNOUNCE=yes.
define extract-title
echo -n \`$(GREP) --max-count=1 '<h2' $$@\` \
  | $(SED) 's/<h2[^>]*>\(.*\)<\/h2>/\1/' | $(SED) 's/\&mdash;/--/g' \
  | $(SED) 's/\&..quo;/"/g' | base64 --wrap=0
endef

# Construct a command sequence suitable for `mail', if the .hook-ann
# file exists.  Only applicable for article-rules, if ANNOUNCE=yes.
# The .hook-ann files are treated differently in the `triggers' rule,
# because it is a valid (and often occurring in practice) scenario to
# have a new translation which is invalid HTML.
define announce
if test -f $$(@F).hook-ann; then \
  echo "echo '<URL:$$(subst $(rootdir),http://www.gnu.org,$$@)>' \
  | mail -s '[$(2)] New translation: =?utf-8?B?`$(extract-title)`?=' \
    -a Keywords:$(2)-ann $(ann-addr)" > $$(@F).hook-ann; \
fi
endef

# The command to validate an ordinary article, and create a hook in
# case validation fails.  Used only in article-rules.
define validate-article
$(VALIDATESKIP) $(VALIDATE-HTML-NOTIFY) $(NOTIFYSKIP) $(transl-addr) \
  $$@ || (PO=$(1).po ; $$(touch-hook))
endef

# Ensure that generic.LANG.html is always present for the homepage and
# articles' generation.

define generic-var
GENERIC_LINGUAS += $(1)
endef

define generic-rules
generic.$(1).html:
	$$(addfile)
endef

$(foreach h-lang,$(HOME_LINGUAS),$(eval $(call generic-var,$(h-lang))))
$(foreach po-base,$(ALL_POS_BASE), \
  $(eval $(call generic-var,$(subst .,,$(suffix $(po-base))))))
$(foreach g-lang,$(sort $(GENERIC_LINGUAS)), \
  $(eval $(call generic-rules,$(g-lang))))

### Specific rules for the templates ###
.PRECIOUS: $(template-dir)/po/%.pot
$(template-dir)/po/%.pot: $(template-dir)/%.html
	$(addfile)
	$(generate-pot)

define template-rules
.PRECIOUS: $(template-dir)/po/%.$(1).po
$(template-dir)/po/%.$(1).po: $(template-dir)/po/%.pot $(MASTER-$(1))
# If the POT is new, it is natural that teams cannot translate it at
# once.  Create a copy for every PO file in TEMPLATE_LINGUAS so that
# the build can continue without errors.
# FIXME: Check if this approach works with gettext >> 0.14.
	[ -f $$@ ] || (cp $$< $$@ ; $(VCSSKIP) $(vcs) add $$@)
# Since we handle the case when new templates are added by webmasters,
# it is OK to ignore errors from these, at least until fencepost has
# an old version of gettext.  The HTML validation errors should be
# clear even if the bug is in the server templates translations.
	-PO=$$@ ; $(check-po)
	$(call update-po,$$@,$$<,$(1))

$(template-dir)/%.$(1).html: $(template-dir)/%.html \
			     $(template-dir)/po/%.$(1).po
# If the PO file is invalid and is not fixed within the next GNUN
# build, touch the proper prerequisite to trigger another rebuild.
# Otherwise, next time make doesn't execute the recipe as it considers
# the target up-to-date.  This safeguards against sneaking of an empty
# and/or corrupt articles which are then #include'd in others thus
# rendering them invalid.
	PO=$(template-dir)/po/$$(*F).$(1).po ; $(check-po) \
	  || (touch $$$$PO ; exit 1)
	$$(addfile)
	$(call generate-html,$(1),$(template-dir)/po/$$(*F).$(1).po,$$@)
	$(SED) --in-place \
	  ':egin;N;$$$$!begin;s/\([ \t]*\n[ \t]*\)\{3,\}<!--/\n\n<!--/g' $$@
endef

$(foreach t-lang,$(TEMPLATE_LINGUAS),$(eval $(call template-rules,$(t-lang))))
### End of the templates-specific rules ###

### Specific rules for extra templates ###
# Essentially duplicate rules for templates, but define per-template
# rules rather than use static patterns
define extra-template-lang-rules
.PRECIOUS: $(1).$(2).po
$(1).$(2).po: $(1).pot $(MASTER-$(2))
	[ -f $$@ ] || (cp $$< $$@ ; $(VCSSKIP) $(vcs) add $$@)
	-PO=$$@ ; $(check-po)
	$(call update-po,$$@,$$<,$(2))

$(subst /po/,/,$(1)).$(2).html: $(subst /po/,/,$(1)).html \
			     $(1).$(2).po
	PO=$(1).$(2).po ; $(check-po) || (touch $$$$PO ; exit 1)
	$$(addfile)
	$(call generate-html,$(2),$(1).$(2).po,$$@)
	$(SED) --in-place \
	  ':egin;N;$$$$!begin;s/\([ \t]*\n[ \t]*\)\{3,\}<!--/\n\n<!--/g' $$@
endef

define extra-template-rules
.PRECIOUS: $(1).pot
$(1).pot: $(subst /po/,/,$(1)).html
	$$(addfile)
	$$(generate-pot)

$(foreach t-lang,$(TEMPLATE_LINGUAS),\
  $(eval $(call extra-template-lang-rules,$(strip $(1)),$(t-lang))))
endef

$(foreach template, $(extra-templates),\
  $(eval $(call extra-template-rules, \
	   $(addprefix $(rootdir)/, \
	    $(if $(findstring $(dir $(template)),./),,\
	      $(dir $(template)))po/$(notdir $(template))))))

### End of rules for extra templates ###

# generate-translinks is desined to be used from eval'ed expression,
# this is why we can't invoke it from whatsnew rules and rather
# indirectly define a rule to build the file.
define whatsnew-translist-rule
.PHONY: regen-whatsnew-translist
regen-whatsnew-translist:
	$(call generate-translinks,$(template-dir)/po/whatsnew)
endef
$(eval $(whatsnew-translist-rule))

### Specific rules for the What's New system (a.k.a. GNU news) ###
# There is a lot of duplication with article-rules, but at least one
# command in every recipe has to be different.  Also, we don't want
# whatsnew to be in gnun.mk as if it is it will be built by the
# article-rules anyway.  The `whatsnew' targets are built before the
# homepages in order any newly generated gnusflashes.LANG.include to
# be #include'd automatically in the corresponding homepage.
$(template-dir)/po/whatsnew.proto: $(template-dir)/whatsnew.html
	$(VALIDATESKIP) $(VALIDATE-HTML-NOTIFY) $(NOTIFYSKIP) $(web-addr) $<
	$(mail-error-proto) $(MAKE-PROTOTYPE) --input=$< \
	  --generic=generic.html --home --output=$@ \
	  || ($(RM) $@ ; exit 1)
	$(SED) --in-place "s/\$$Date.*\$$/<gnun>\0<\/gnun>/g" $@
	$(MAKE) regen-whatsnew-translist

$(template-dir)/po/whatsnew.pot: $(template-dir)/po/whatsnew.proto \
				 $(template-dir)/whatsnew.include
	$(addfile)
# The generation of whatsnew.pot is special, as it contains all
# strings for building whatsnew.LANG.html and whatsnew.LANG.include.
	$(MAILFAIL) $(NOTIFYSKIP) $(web-addr) \
	  "[GNUN Error] POT generation of $(subst $(rootdir)/,,$@) failed" \
	  $(PO4A_GETTEXTIZE) $(PO4A-XHTMLFLAGS) $(PO4A-GETTEXTIZEFLAGS) \
	  --master $< --master $(template-dir)/whatsnew.include --po $@.tmp
	if ([ ! -f $@ ] \
	  || [ "`diff -U 0 $@ $@.tmp | $(GREP) -v "^\(---\|+++\|@@\)" \
	  | $(GREP) -v '^[-+]\"POT-Creation-Date:' | wc -c`" -ne 0 ]); then \
	  mv $@.tmp $@; \
	  fi; \
	  touch $@
	$(RM) $@.tmp

# Reordering the prerequisites would save the redundant usage of the
# $* automatic variable but $(addfile) wouldn't work.
.PRECIOUS: $(template-dir)/whatsnew.%.include
$(template-dir)/whatsnew.%.include: $(template-dir)/whatsnew.include \
				    $(template-dir)/po/whatsnew.%.po
	PO=$(template-dir)/po/whatsnew.$*.po ; \
	  $(MAILFAIL) $(NOTIFYSKIP) $(transl-addr) \
	  "[GNUN Error] $${PO#../../} is not a valid PO file" \
	  $(VALIDATESKIP) $(MSGFMT) --check --verbose \
	  --output-file=/dev/null $$PO || (touch $$PO ; exit 1)
	$(addfile)
# The <dd> element is not wrapped on purpose, for easy generation of
# gnusflashes.LANG.include.
# FIXME: Unfortunately, if the translator wraps the msgstr with M-q,
# then grep in the gnusflashes recipe skips all those wrapped news as
# there is no match.  Figure out how to avoid this problem or
# alternatively, say louder that wrapping of msgstr is a BAD thing.
	PO=$(template-dir)/po/whatsnew.$*.po OUT=$@ ; \
	  $(PO4A_TRANSLATE) $(PO4A-XHTMLFLAGS) $(PO4A-TRANSLATEFLAGS) \
	  -o "translated=W<dd>" --master $< --po $$PO --localized $$OUT

# Derive the targets from whatsnew.LANG.include.  Pattern rules rule.
$(rootdir)/gnusflashes.%.include: $(template-dir)/whatsnew.%.include
# If there is a homepage, touch its PO file in order to be regenerated
# in the same GNUN run to include gnusflashes.LANG.include.
	[ -f $@ ] || (touch $@ ; $(VCSSKIP) $(vcs) add $@ \
	  && ([ ! -f $(rootdir)/home.$*.html ] \
	      || touch $(rootdir)/po/home.$*.po))
	$(fixperm)
	echo "<!--Automatically generated by GNUN; do not edit!-->" > $@
	$(GREP) --max-count=3 '<dd>.*</dd>' $< >> $@
	$(SED) --in-place "s/\(\/\?\)dd>/\1p>/g" $@ || (touch $< ; exit 1)

# This target is deliberately generated in the wrong sub-directory,
# otherwise it will be built by template-rules which we want to avoid
# at all cost.
$(template-dir)/po/whatsnew.%.html: $(template-dir)/po/whatsnew.proto \
				    $(template-dir)/po/whatsnew.%.po \
				    $(template-dir)/whatsnew.%.include \
				    generic.%.html
	$(if $(call find-language,$*,$(TEMPLATE_LINGUAS)),, \
	  echo 'The "$*" language code is not defined in TEMPLATE_LINGUAS.' \
	    $(if $(NOTIFYSKIP),, | mail $(transl-addr) -s \
	      "[GNUN Error] Could not build $(subst $(rootdir)/,,$@)"); \
	  exit 1)
	PO=$(template-dir)/po/whatsnew.$*.po ; $(MAILFAIL) \
	  $(NOTIFYSKIP) $(transl-addr) \
	  "[GNUN Error] $${PO#../../} is not a valid PO file" \
	  $(VALIDATESKIP) $(MSGFMT) --check --verbose --output-file=/dev/null \
	  $$PO || (touch $$PO ; exit 1)
	[ -f $(template-dir)/$(@F) ] \
	  || (touch $(template-dir)/$(@F) ; \
	     $(VCSSKIP) $(vcs) add $(template-dir)/$(@F))
# Unconditionally update the PO file; see the comment in `generate-html'.
	$(call update-po,$(template-dir)/po/whatsnew.$*.po,\
	  $(template-dir)/po/whatsnew.pot,$*)
	  $(PO4A_TRANSLATE) $(PO4A-XHTMLFLAGS) $(PO4A-TRANSLATEFLAGS) \
	    --master $< --po $(template-dir)/po/whatsnew.$*.po \
	    --localized $(template-dir)/po/whatsnew.$*.m4
	$(SED) --in-place \
	  "s/\(<gnun>m4_include(\`.*\)\([.]html')<\/gnun>\)/\1.$*\2/g" \
	  $(template-dir)/po/whatsnew.$*.m4
	$(SED) --in-place "s/<gnun>\(.*\)<\/gnun>/\1/g" \
	  $(template-dir)/po/whatsnew.$*.m4
	$(SED) --in-place \
	  ':egin;N;$$!begin;s/\([ \t]*\n[ \t]*\)\{3,\}<!--/\n\n<!--/g' \
	  $(template-dir)/po/whatsnew.$*.m4
	$(call substitute-localized-includes,$*) \
	  $(template-dir)/po/whatsnew.$*.m4
	$(SED) --in-place \
	  "s/\(<!--#include virtual=\".*whatsnew\)\(.include\" -->\)/\1.$*\2/g" \
	  $(template-dir)/po/whatsnew.$*.m4
	$(M4) $(template-dir)/po/whatsnew.$*.m4 > $@
	$(VALIDATESKIP) $(VALIDATE-HTML-NOTIFY) $(NOTIFYSKIP) $(transl-addr) \
	  $@ || (PO=$(template-dir)/po/whatsnew.$*.po ; $(touch-hook))
# Copy the target where it belongs.
	cp $@ $(template-dir)
	$(MAKE) regen-whatsnew-translist
### End of the whatsnew-specific rules ###

### Specific rules for the homepages ###
$(rootdir)/po/home.proto: $(rootdir)/home.html
# Delete the target if the script exits with a non-zero status in
# order to prevent further messing up in the chain.  For extra safety,
# exit with an error so that make does not proceed to the next
# command.
	$(VALIDATESKIP) $(VALIDATE-HTML-NOTIFY) $(NOTIFYSKIP) $(web-addr) $<
	$(mail-error-proto) $(MAKE-PROTOTYPE) --home --input=$< \
	  --generic=generic.html --output=$@ || ($(RM) $@ ; exit 1)
	$(SED) --in-place "s/\$$Date.*\$$/<gnun>\0<\/gnun>/g" $@

$(rootdir)/po/home.pot: $(rootdir)/po/home.proto
	$(addfile)
	$(fixperm)
	$(generate-pot)

$(rootdir)/po/home-staged.proto: $(rootdir)/home-staged.html
# Delete the target if the script exits with a non-zero status in
# order to prevent further messing up in the chain.  For extra safety,
# exit with an error so that make does not proceed to the next
# command.
	$(VALIDATESKIP) $(VALIDATE-HTML-NOTIFY) $(NOTIFYSKIP) $(web-addr) $<
	$(mail-error-proto) $(MAKE-PROTOTYPE) --home --input=$< \
	  --generic=generic.html --output=$@ || ($(RM) $@ ; exit 1)
	$(SED) --in-place "s/\$$Date.*\$$/<gnun>\0<\/gnun>/g" $@

$(rootdir)/po/home-staged.pot: $(rootdir)/po/home-staged.proto
	$(addfile)
	$(fixperm)
	$(generate-pot)

define home-rules
$(rootdir)/po/$(2).$(1).po: $(rootdir)/po/$(2).pot $(MASTER-$(1))
	PO=$$@ ; $(check-po)
	$$(fixperm)
	$(call update-po,$$@,$$<,$(1))

$(rootdir)/$(2).$(1).html: $(rootdir)/po/$(2).proto \
			   $(rootdir)/po/$(2).$(1).po generic.$(1).html
# Check if the language is present in TEMPLATE_LINGUAS.
ifeq (,$(call find-language,$(1),$(TEMPLATE_LINGUAS)))
ifndef NOTIFYSKIP
	echo 'The "$(1)" language code is not defined in TEMPLATE_LINGUAS.' \
	  | mail $(transl-addr) -s \
	  "[GNUN Error] Could not build $$(subst $$(rootdir)/,,$$@)"  
else
	@echo 'The "$(1)" language code is not defined in TEMPLATE_LINGUAS.'
endif
	exit 1
endif # eq (,$(call find-language,$(1),$(TEMPLATE_LINGUAS)))
# If $PO is not valid, then the generated page could be broken even
# for the reader.  Ensure that the build still barfs next time if the
# translator doesn't fix it quickly.
	PO=$(rootdir)/po/$(2).$(1).po ; $(check-po) || (touch $$$$PO ; exit 1)
	$$(addfile)
	$$(fixperm)
	$(call generate-html,$(1), \
	  $(rootdir)/po/$(2).$(1).po,$(rootdir)/po/$(2).$(1).m4)
	$(SED) --in-place \
	  "s/\(<gnun>m4_include(\`.*\)\([.]html')<\/gnun>\)/\1.$(1)\2/g" \
	  $(rootdir)/po/$(2).$(1).m4
	$(SED) --in-place "s/<gnun>\(.*\)<\/gnun>/\1/g" \
	  $(rootdir)/po/$(2).$(1).m4
	$(SED) --in-place \
	  ':egin;N;$$$$!begin;s/\([ \t]*\n[ \t]*\)\{3,\}<!--/\n\n<!--/g' \
	  $(rootdir)/po/$(2).$(1).m4
	[ ! -f $(rootdir)/gnusflashes.$(1).include ] || $(SED) --in-place \
	  "s/\(<!--#include file=\"gnusflashes*\)\(.include\" -->\)/\1.$(1)\2/g" \
	  $(rootdir)/po/$(2).$(1).m4
	$(call extract-outdated-date,$(rootdir)/po/$(2).$(1).po) > /dev/null \
	|| ($(call add-file,$(rootdir)/po/$(2).$(1)-en.html); \
	    cp $(rootdir)/$(2).html $(rootdir)/po/$(2).$(1)-en.html)
	$(M4) $(rootdir)/po/$(2).$(1).m4 > $$@
	$(VALIDATESKIP) $(VALIDATE-HTML-NOTIFY) $(NOTIFYSKIP) $(transl-addr) \
	  $$@ || (PO=$(rootdir)/po/$(2).$(1).po ; $$(touch-hook))
endef

$(foreach h-name,home home-staged, \
  $(foreach h-lang,$(HOME_LINGUAS), \
    $(eval $(call home-rules,$(h-lang),$(h-name)))))
### End of the homepages-specific rules ###

### Rules for all other articles ###
define article-pot-rules
$(1).proto: $(subst /po/,/,$(1).html)
# Skip the validation step if the article is in `no-validate-articles'.
ifneq ($(1), $(findstring $(1),$(no-validate-articles)))
	$(VALIDATESKIP) $(VALIDATE-HTML-NOTIFY) $(NOTIFYSKIP) $(web-addr) $$<
endif
	$(call generate-translinks,$(1))
	$(call update-translinks-include,$(1)) 
	$$(mail-error-proto) $(MAKE-PROTOTYPE) --home --input=$$< \
	  --generic=generic.html --output=$(1).proto \
	    || ($(RM) $(1).proto ; exit 1)
	$(SED) --in-place "s/\$$$$Date.*\$$$$/<gnun>\0<\/gnun>/g" $(1).proto

$(1).pot: $(1).proto
	$$(addfile)
	$$(fixperm)
	$$(generate-pot)
endef

# Produce article HTML file, announce and validate it if needed
define output-article-html
$(M4) $(1).m4 > $$@ \
$(if $(findstring $(basename $(1)),$(no-validate-articles)), , \
  && $(announce) && $(validate-article))
endef

define grace-is-over
(timestamp="`$(call extract-outdated-date,$(1))`"; \
  test -n "$$$${timestamp}" \
  && test "`date --date="$(2) days ago" +%s`" \
       -ge "`date --date="$$$${timestamp}" +%s`" \
)
endef

define article-rules
$(1).po: $(basename $(1)).pot $(MASTER-$(2))
	PO=$$@ ; $(check-po)
	$$(fixperm)
	$(call update-po,$$@,$$<,$(2))

$(subst /po/,/,$(1).html): $(basename $(1)).proto \
			   $(1).po generic.$(2).html
# If the server templates are missing, assume the worst and exit with
# an error to prevent the generation of broken translations -- even if
# validation is not enforced there will be Apache error.  The case
# when the templates are present but not built by GNUN is valid in
# practice, but not recommended.
ifeq (,$(call find-language,$(2),$(TEMPLATE_LINGUAS)))
ifndef NOTIFYSKIP
	echo 'The "$(2)" language code is not defined in TEMPLATE_LINGUAS.' \
	  | mail $(transl-addr) -s \
	  "[GNUN Error] Could not build $$(subst $$(rootdir)/,,$$@)"  
else
	@echo 'The "$(2)" language code is not defined in TEMPLATE_LINGUAS.'
endif
	exit 1
endif
# A slightly modified version of $(addfile) that takes care to create
# a .hook-ann file if ANNOUNCE is enabled and it is a new translation.
ifeq (yes,$(ANNOUNCE))
	[ -f $$@ ] || (touch $$@ $$(@F).hook-ann; $(VCSSKIP) $(vcs) add $$@)
else
	$$(addfile)
endif
# If a new PO file is invalid, an empty .LANG.html will be committed
# so it is not appropriate to announce it as a "new translation".
# Record a magic string in the .hook-ann file to make the `triggers'
# rule DTRT.
	PO=$(1).po; $(check-po) || (touch $$$$PO; \
	  if test -f $$(@F).hook-ann; then \
	    echo "gnun-do-not-delete-me" > $$(@F).hook-ann; \
	  fi; exit 1)
# This is needed for only a few articles, but as it is harmless there
# is no real need to determine them and run the command conditionally.
	$$(fixperm)
	$(call generate-html,$(2),$(1).po,$(1).m4)
	$(SED) --in-place \
	  "s/\(<gnun>m4_include(\`.*\)\([.]html')<\/gnun>\)/\1.$(2)\2/g" $(1).m4
	$(SED) --in-place "s/<gnun>\(.*\)<\/gnun>/\1/g" $(1).m4
	$(SED) --in-place \
	  ':egin;N;$$$$!begin;s/\([ \t]*\n[ \t]*\)\{3,\}<!--/\n\n<!--/g' \
	  $(1).m4
# If GRACE is not defined, which is the usual case for local manual
# builds, update the target and validate the result.
ifndef GRACE
	$(output-article-html);
# Check if the article is not in `no-grace-items'.
else ifneq ($(basename $(1)), \
	    $(findstring $(basename $(1)),$(no-grace-items)))
# If there are no fuzzy strings, there might be untranslated or
# obsolete, so proceed as usual.  If there are fuzzy strings, compare
# the Outdated-Since in the $(1).po with the current time shifted by value
# of the $(GRACE) period and invoke regeneration only if the grace period
# is over. Likewise, check against $(OUTDATED-GRACE) and insert a notice
# into the HTML file when the grace period is over.
# If the target is of zero size, it means that it was just touched by
# $(addfile) -- GRACE is ignored in this case to avoid committing
# empty files to the repository.
	if ! $(call extract-outdated-date,$(1).po) > /dev/null \
	      || ! test -s $$@; then \
	  $(output-article-html); \
	elif $(call grace-is-over,$(1).po,$(GRACE)) ; then \
	  $(output-article-html); \
	else \
	  sleep 1; touch $(1).po; \
	fi
else
	@echo 'Ignoring grace period for article "$(notdir $(basename $(1)))"'
	$(output-article-html);
endif
	$(if $(findstring $(basename $(1)),$(no-grace-items)), \
	    echo 'Ignoring delay for article "$(notdir $(basename $(1)))"', \
	    if $(call grace-is-over,$(1).po,$(OUTDATED-GRACE)); then \
	      PO=$(1).po; $(call mark-outdated,$$@,$(2)); \
	    fi)
	$(call generate-translinks,$(basename $(1)))
	$(call extract-outdated-date,$(1).po) > /dev/null \
	|| ($(call add-file,$(1)-en.html); \
	    cp $(subst /po/,/,$(1:.$(2)=).html) $(1)-en.html)
endef

$(foreach base,$(ALL_BASE),$(eval $(call article-pot-rules,$(base))))
$(foreach po-base,$(ALL_POS_BASE), \
  $(eval $(call article-rules,$(po-base),$(subst .,,$(suffix $(po-base))))))
### End of all articles' rules ###

# If VCS=always, add all necessary files.  The templates' POT are not
# handled for the moment, but they are more or less stable.  Also,
# there is no sense in adding home.pot as this should happen only once.
# WARNING: This is horribly slow and is implemented just in case.
ifneq (,$(findstring always,$(VCS)))
vcs-add-always:
	for file in $(template-translated) $(home-translated) $(ALL_POTS) \
	  $(articles-translated) $(gnunews) $(wildcard generic.*.html); do \
	  ($(vcs) add $$file ; exit 0) ; done
else
vcs-add-always: ;
endif

# Special target to sync the original English articles from the `www'
# repository.  It is intended to be invoked by a fencepost cron job
# and will be useful even when GNUN is deployed.  Automatic adding and
# removal is not implemented (except adding `verbatim-templates'), so
# make sure to `cvs add'/`cvs remove' and commit the article when
# editing gnun.mk.
wwwdir := $(rootdir)/$(rootdir)/www
orig-templates := $(addsuffix .html,$(template-translated-base))
orig-articles := $(addsuffix .html,$(subst /po/,/,$(ALL_BASE)))
files-to-sync := $(rootdir)/home.html $(orig-templates) $(orig-articles)
abs-files-to-sync := $(subst $(rootdir)/,,$(files-to-sync))
# Templates that are not gettextized, but are necessary to reside in
# trans-coord for HTML validation at build time.
verbatim-templates-set := header head-include-1 html5-header \
  html5-head-include banner footer
verbatim-templates := $(addprefix server/, \
  $(foreach template,$(verbatim-templates-set), \
     $(foreach temp-lang,$(TEMPLATE_LINGUAS),$(template).$(temp-lang).html) \
   ) \
  whatsnew.html whatsnew.include)

.PHONY: sync
sync: 
# Synchronize all articles and report if an article has been deleted
# from the master repository.
	for file in $(abs-files-to-sync) ; do \
	  if [ ! -f $(wwwdir)/$$file ] ; then \
	    echo "Warning: $$file missing in www; update the variable?" \
	    | $(VCSSKIP) mail -s "sync: missing file" $(devel-addr) ; \
	  else \
	    cp -p --update $(wwwdir)/$$file $(rootdir)/$$file ; \
	  fi ; done
# Copy all necessary templates that are not under GNUN's control and
# add them if VCS=yes.
	for t in $(verbatim-templates) ; do \
	  if [ ! -f $(rootdir)/$$t ] ; then \
	    cp -p $(wwwdir)/$$t $(rootdir)/$$t \
	      && $(VCSSKIP) $(vcs) add $(rootdir)/$$t ; \
	  else \
	    cp -p --update $(wwwdir)/$$t $(rootdir)/$$t ; \
	  fi ; done
	cd $(rootdir) ; \
	  $(VCSSKIP) $(vcs) commit -m \
	  "Automatic sync from the master www repository."

# Special target to check which translations need updating.
.PHONY: report
report: 
ifndef TEAM
	$(error Please specify a language code, for example TEAM=fr)
endif
ifneq ($(TEAM),$(call find-language,$(TEAM),$(sort $(GENERIC_LINGUAS))))
	@echo "There are no translations for language $(TEAM)."
else
	@cd $(rootdir) ; LC_ALL=C find -name '*.$(TEAM).po' -printf "%p: " \
	  -exec $(MSGFMT) --statistics -o /dev/null '{}' \; 2>&1 \
	    | sort | $(EGREP) '(fuzzy|untranslated)' \
	  || echo "All translations seem to be up-to-date."
endif

# Special target to compile report about number of outdated translations
# for all languages.
.PHONY: reports-summary
reports-summary:
	@$(foreach lang,$(TEMPLATE_LINGUAS), echo -n "$(lang): "; \
	   $(MAKE) report TEAM=$(lang) \
	   | $(EGREP) -v "^(make|All translations|There are no translations)" \
	   | wc -l; )

# Special target to touch all the prerequisites of the targets that
# failed HTML validation and thus to trigger a rebuild in the next
# run.
.PHONY: triggers
triggers:
ifeq (,$(wildcard *.hook))
	@echo "No triggers to process; build apparently successful."
else
# Execute the command recorded in every .hook file.
	@for t in *.hook; do \
	  echo -n "Processing $$t... " && bash $$t && echo done.; \
	done
# Delete all *.hook files, or else there will be useless rebuilds
# every time updating the `Date' timestamp in .LANG.html.
	$(RM) *.hook
endif
# Handle announcements of new translations.
ifeq (,$(wildcard *.hook-ann))
	@echo "No new translations."
else
# If the .hook-ann file contains "gnun-do-not-delete-me", it means
# that the build failed in article-rules while checking the PO file.
# The .LANG.html is empty, not suitable to be announced, so do nothing
# in this case.
	@for t in *.hook-ann; do \
	  if ! $(GREP) --quiet 'gnun-do-not-delete-me' $$t; then \
	    echo -n "Sending announcement for $$t... " \
	    && bash $$t && echo done.; $(RM) $$t; \
	  fi; \
	done
endif

### Everything that has a beginning has an end. ###



Archives gérées par MHonArc 2.6.16.

Haut de le page