# Copyright (C) 2007, 2008 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

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

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

# Do not `cvs add' any files by default unless VCS=yes.
ifneq (,$(findstring yes,$(VCS)))
CVSSKIP :=
else
CVSSKIP := 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

# Email addresses for notifications.
devel-addr := trans-coord-devel@gnu.org
# FIXME: Change to www-discuss in the official instance.
web-addr := trans-coord-devel@gnu.org
# FIXME: Change to trans-coord-discuss in the official instance.
transl-addr := trans-coord-devel@gnu.org

rootdir := ../..

# FIXME: footer-short and footer-min are remnants from the old-new
# design; they should go at some point.
localized-includes := header banner footer footer-short footer-min

include gnun.mk

### Special variables for the `www' master templates ###
template-dir := $(rootdir)/server
template-files := banner \
		  footer-text
template-translated-base := $(addprefix $(template-dir)/,$(template-files))
template-pots := $(addsuffix .pot, \
		   $(addprefix $(template-dir)/po/,$(template-files)))
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).shtml
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) ###

### Special variables for all other articles ###
# FIXME: Variables' computatation 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=%)
find-po = $(wildcard $(1).*.po)
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
ifeq ($(_have-Makefile),yes)
include Makefile
else
all: $(template-pots) $(template-translated) $(gnunews) $(home-translated) \
     $(ALL_POTS) $(articles-translated) vcs-add-always
endif

# The command to add a file to the repository.
define addfile
[ -f $@ ] || (touch $@ ; $(CVSSKIP) $(CVS) add $@)
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
@echo Generating POT...
$(PO4A_GETTEXTIZE) $(PO4A-XHTMLFLAGS) $(PO4A-GETTEXTIZEFLAGS) \
  --master $< --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
endef

# The command to generate the translated article OUT in HTML format
# from a PO file.  The result is further manipulated in the recipes.
define generate-html
$(PO4A_TRANSLATE) $(PO4A-XHTMLFLAGS) $(PO4A-TRANSLATEFLAGS) \
  --master $$< --po $$$$PO --localized $$$$OUT
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

# The command to update a PO file from the POT.  The target is
# `touched' in order `make' to consider it up-to-date even if there
# is nothing to merge.
define update-po
$(MSGMERGE) --update $$@ $$< && touch $$@
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 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
# 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 $$< $$@ ; $(CVSSKIP) $(CVS) 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 XHTML validation errors should be
# clear even if the bug is in the server templates translations.
	-PO=$$@ ; $(check-po)
	$(update-po)

$(template-dir)/%.$(1).html: $(template-dir)/%.html \
			     $(template-dir)/po/%.$(1).po
	$$(addfile)
# 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)
	PO=$(template-dir)/po/$$(*F).$(1).po OUT=$$@ ; $(generate-html)
	$(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 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 --translinks=$(basename $@).translinks \
	  --output=$@ \
	  || ($(RM) $@ $(basename $@).translinks ; exit 1)
	$(SED) --in-place "s/\$$Date.*\$$/<gnun>\0<\/gnun>/g" $@

# This target is present because the whatsnew.%.html target depends on
# it so when make is run for the first time and whatsnew.translinks is
# not present, it exits with an error.
$(template-dir)/po/whatsnew.translinks: $(template-dir)/po/whatsnew.proto

$(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.
	$(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
	$(addfile)
	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)
# 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 $@ ; $(CVSSKIP) $(CVS) add $@ \
	  && ([ ! -f $(rootdir)/home.$*.shtml ] \
	      || 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.translinks \
				    $(template-dir)/po/whatsnew.%.po \
				    $(template-dir)/whatsnew.%.include \
				    generic.%.html
	[ -f $(template-dir)/$(@F) ] \
	  || (touch $(template-dir)/$(@F) ; \
	     $(CVSSKIP) $(CVS) add $(template-dir)/$(@F))
	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)
	PO=$(template-dir)/po/whatsnew.$*.po \
	  OUT=$(template-dir)/po/whatsnew.$*.m4 ; $(PO4A_TRANSLATE) \
	  $(PO4A-XHTMLFLAGS) $(PO4A-TRANSLATEFLAGS) --master $< \
	  --po $$PO --localized $$OUT
	$(SED) --in-place \
	  "s/\(<gnun>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
	for inc in $(localized-includes); do \
	  $(SED) --in-place \
	  "s/\(<!--#include virtual=\".*$$inc\)\(.html\" -->\)/\1.$*\2/g" \
	  $(template-dir)/po/whatsnew.$*.m4; \
	done
	$(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)
### End of the whatsnew-specific rules ###

### Specific rules for the homepages ###
$(rootdir)/po/home.proto: $(rootdir)/home.shtml
# 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)

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

$(rootdir)/home.$(1).shtml: $(rootdir)/po/home.proto \
			    $(rootdir)/po/home.$(1).po generic.$(1).html
	$$(addfile)
# 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/home.$(1).po ; $(check-po) || (touch $$$$PO ; exit 1)
	$$(fixperm)
	PO=$(rootdir)/po/home.$(1).po OUT=$(rootdir)/po/home.$(1).m4 ; \
	  $(generate-html)
	$(SED) --in-place \
	  "s/\(<gnun>include(\`.*\)\([.]html')<\/gnun>\)/\1.$(1)\2/g" \
	  $(rootdir)/po/home.$(1).m4
	$(SED) --in-place "s/<gnun>\(.*\)<\/gnun>/\1/g" \
	  $(rootdir)/po/home.$(1).m4
	$(SED) --in-place \
	  ':egin;N;$$$$!begin;s/\([ \t]*\n[ \t]*\)\{3,\}<!--/\n\n<!--/g' \
	  $(rootdir)/po/home.$(1).m4
	for inc in $(localized-includes); do \
	  $(SED) --in-place \
	  "s/\(<!--#include virtual=\".*$$$$inc\)\(.html\" -->\)/\1.$(1)\2/g" \
	  $(rootdir)/po/home.$(1).m4; \
	done
	[ ! -f $(rootdir)/gnusflashes.$(1).include ] || $(SED) --in-place \
	  "s/\(<!--#include file=\"gnusflashes*\)\(.include\" -->\)/\1.$(1)\2/g" \
	  $(rootdir)/po/home.$(1).m4
	$(M4) $(rootdir)/po/home.$(1).m4 > $$@
	$(VALIDATESKIP) $(VALIDATE-HTML-NOTIFY) $(NOTIFYSKIP) $(transl-addr) \
	  $$@ || (PO=$(rootdir)/po/home.$(1).po ; $$(touch-hook))
endef

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

### Rules for all other articles ###
define article-pot-rules
$(1).proto $(1).translinks: $(subst /po/,/,$(1).html)
	$(VALIDATESKIP) $(VALIDATE-HTML-NOTIFY) $(NOTIFYSKIP) $(web-addr) $$<
	$$(mail-error-proto) $(MAKE-PROTOTYPE) --input=$$< \
	  --generic=generic.html --output=$(1).proto \
	  --translinks=$(1).translinks \
	    || ($(RM) $(1).proto $(1).translinks ; exit 1)
	$(SED) --in-place "s/\$$$$Date.*\$$$$/<gnun>\0<\/gnun>/g" $(1).proto

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

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

$(subst /po/,/,$(1).html): $(basename $(1)).proto $(basename $(1)).translinks \
			   $(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 (,$(findstring $(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
	$$(addfile)
	PO=$(1).po ; $(check-po) || (touch $$$$PO ; exit 1)
# 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
# `$(1).po' target up-to-date.  As a result, the generated HTML
# translations has English strings (but no fuzzy strings in the PO)
# since there's no match between msgid/msgstr.  Invoke msgmerge
# unconditionally to cope with that (valid) scenario.
	$(MSGMERGE) --update $(1).po $(basename $(1)).pot
# 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)
	PO=$(1).po OUT=$(1).m4 ; $(generate-html)
	$(SED) --in-place \
	  "s/\(<gnun>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
	for inc in $(localized-includes); do \
	  $(SED) --in-place \
	  "s/\(<!--#include virtual=\".*$$$$inc\)\(.html\" -->\)/\1.$(2)\2/g" \
	  $(1).m4; \
	done
# If GRACE is not defined, which is the usual case for local manual
# builds, update the target and validate the result.
ifndef GRACE
	$(M4) $(1).m4 > $$@
	$(validate-article)
# Check if the article is not in `no-grace-articles'.
else ifneq ($(basename $(1)), \
	    $(findstring $(basename $(1)),$(no-grace-articles)))
# If there are no fuzzy strings, there might be untranslated or
# obsolete, so proceed as usual.  If there are fuzzy strings, compare
# the POT-Creation-Date in the PO with the current value of the grace
# period and invoke regeneration only if the grace period is over.
	if ! $(GREP) --quiet "^#, fuzzy" $(1).po ; \
	  then \
	    ($(M4) $(1).m4 > $$@ ; $(validate-article)) ; \
	  else \
	  if [ "`date --date="$(GRACE) days ago" +%Y%m%d`" -ge \
	       "`$(AWK) '/POT-Creation-Date/ { gsub(/-/, ""); print $$$$2 }' \
	         $(1).po`" ] ; \
	    then \
	      $(M4) $(1).m4 > $$@ && $(validate-article) ; \
	    else \
	      sleep 1 ; touch $(1).po ; \
	  fi ; \
	fi
else
	@echo 'Ignoring grace period for article "$(notdir $(basename $(1)))"'
	$(M4) $(1).m4 > $$@
	$(validate-article)
endif
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 \
	  ($(CVS) 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.shtml $(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 := $(addprefix server/,header.html footer.html \
					  header.af.html footer.af.html \
					  header.ar.html footer.ar.html \
					  header.bg.html footer.bg.html \
					  header.ca.html footer.ca.html \
					  header.es.html footer.es.html \
					  header.fr.html footer.fr.html \
					  header.it.html footer.it.html \
					  header.pt.html footer.pt.html \
					  header.pt-br.html footer.pt-br.html \
					  header.ru.html footer.ru.html \
					  header.tr.html footer.tr.html \
					  header.zh-cn.html footer.zh-cn.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?" \
	    | $(CVSSKIP) 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
# `cvs add' them if VCS=yes.
	for t in $(verbatim-templates) ; do \
	  if [ ! -f $(rootdir)/$$t ] ; then \
	    cp -p $(wwwdir)/$$t $(rootdir)/$$t \
	      && $(CVSSKIP) $(CVS) add $(rootdir)/$$t ; \
	  else \
	    cp -p --update $(wwwdir)/$$t $(rootdir)/$$t ; \
	  fi ; done
	cd $(rootdir) ; \
	  $(CVSSKIP) $(CVS) 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),$(findstring $(TEAM),$(sort $(GENERIC_LINGUAS))))
	$(error There are no translations for language "$(TEAM)")
endif
	@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."

# 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

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