Index: defaults.py
===================================================================
--- defaults.py	(révision 404)
+++ defaults.py	(copie de travail)
@@ -82,3 +82,7 @@
 
 # Right-to-left languages
 rtl_languages = [ 'ar', 'fa', 'he', 'urd', 'yi']
+
+# Dummy function for deferred translation (error messages)
+# See http://docs.python.org/lib/node742.html
+def N_(message): return message.replace("%s","###%s###")
Index: update-stats.py
===================================================================
--- update-stats.py	(révision 407)
+++ update-stats.py	(copie de travail)
@@ -211,10 +211,10 @@
             # Use old POT file
             potfile = newpot
             if defaults.DEBUG: print >> sys.stderr, "Can't generate POT file for %s/%s." % (self.module["id"], po_dir)
-            errors.append(("error", "Can't generate POT file, using old one."))
+            errors.append(("error", defaults.N_("Can't generate POT file, using old one.")))
         elif error or not os.access(potfile, os.R_OK):
             if defaults.DEBUG: print >> sys.stderr, "Can't generate POT file for %s/%s." % (self.module["id"], po_dir)
-            errors.append(("error", "Can't generate POT file, using old one if it exists."))
+            errors.append(("error", defaults.N_("Can't generate POT file, using old one if it exists.")))
             pot_stats = self.po_file_stats(potfile, 0)
             pot_stats['errors'].extend(errors)
             self.update_stats_database(module = self.module["id"], branch = self.branch, type = 'ui',
@@ -243,7 +243,7 @@
         pot_stats['errors'].extend(errors)
 
         if potfile!=newpot and not self.copy_file(potfile, newpot):
-            pot_stats['errors'].append(('error', "Can't copy new POT file to public location."))
+            pot_stats['errors'].append(('error', defaults.N_("Can't copy new POT file to public location.")))
 
         postats = self.update_po_files(base_dir, popath, potfile, out_dir, out_domain, potchanged)
 
@@ -255,7 +255,7 @@
         for lang in postats:
             langs = teams.TranslationLanguages(show_hidden=1)
             if not lang or not langs.has_key(lang):
-                postats[lang]['errors'].append(("warn", "There is no translation team in charge of '%s' translation." % (lang)))
+                postats[lang]['errors'].append(("warn", defaults.N_("There is no translation team in charge of '%s' translation.") % (lang)))
 
             self.update_stats_database(module = self.module["id"], branch = self.branch, type = 'ui',
                                        domain = self.podir, date = NOW, language = lang,
@@ -331,7 +331,7 @@
                         break
                 lfile.close()
                 if not in_config:
-                    errors.append(("warn", "Entry for this language is not present in LINGUAS file."))
+                    errors.append(("warn", defaults.N_("Entry for this language is not present in LINGUAS file.")))
                 return errors
 
         import re
@@ -359,10 +359,10 @@
                         break
                 cfile.close()
                 if not in_config:
-                    errors.append(("warn", "Entry for this language is not present in ALL_LINGUAS in configure file."))
+                    errors.append(("warn", defaults.N_("Entry for this language is not present in ALL_LINGUAS in configure file.")))
                 return errors
 
-        errors.append(("warn", "Don't know where to look if this language is actually used, ask the module maintainer."))
+        errors.append(("warn", defaults.N_("Don't know where to look if this language is actually used, ask the module maintainer.")))
         return errors
 
     def check_pot_regeneration(self, po_path):
@@ -376,23 +376,25 @@
 
         if error:
             if defaults.DEBUG: print >> sys.stderr, "Error running 'intltool-update -m' check."
-            errors.append( ("error", "Errors while running 'intltool-update -m' check.") )
+            errors.append( ("error", defaults.N_("Errors while running 'intltool-update -m' check.")) )
 
         missing = os.path.join(po_path, "missing")
         if os.access(missing, os.R_OK):
             f = open(missing, "r")
             errors.append( ("warn",
-                            "There are some missing files from POTFILES.in: <ul><li>"
+                            defaults.N_("There are some missing files from POTFILES.in: %s")
+                            % ("<ul><li>"
                             + "</li>\n<li>".join(f.readlines())
-                            + "</li>\n</ul>") )
+                            + "</li>\n</ul>")) )
 
         notexist = os.path.join(po_path, "notexist")
         if os.access(notexist, os.R_OK):
             f = open(notexist, "r")
             errors.append(("error",
-                           "Following files are referenced in either POTFILES.in or POTFILES.skip, yet they don't exist: <ul><li>"
+                           defaults.N_("Following files are referenced in either POTFILES.in or POTFILES.skip, yet they don't exist: %s")
+                           % ("<ul><li>"
                            + "</li>\n<li>".join(f.readlines())
-                           + "</li>\n</ul>"))
+                           + "</li>\n</ul>")))
         return errors
 
 
@@ -403,7 +405,7 @@
         errors = []
 
         try: os.stat(pofile)
-        except OSError: errors.append(("error", "PO file '%s' doesn't exist." % pofile))
+        except OSError: errors.append(("error", defaults.N_("PO file '%s' doesn't exist.") % pofile))
 
         if msgfmt_checks:
             command = "LC_ALL=C LANG=C LANGUAGE=C msgfmt -cv -o /dev/null %s" % pofile
@@ -416,12 +418,12 @@
 
         if error:
             if msgfmt_checks:
-                errors.append(("error", "PO file '%s' doesn't pass msgfmt check: not updating." % (pofile)))
+                errors.append(("error", defaults.N_("PO file '%s' doesn't pass msgfmt check: not updating.") % (pofile)))
             else:
-                errors.append(("error", "Can't get statistics for POT file '%s'." % (pofile)))
+                errors.append(("error", defaults.N_("Can't get statistics for POT file '%s'.") % (pofile)))
 
         if msgfmt_checks and os.access(pofile, os.X_OK):
-            errors.append(("warn", "This PO file has an executable bit set."))
+            errors.append(("warn", defaults.N_("This PO file has an executable bit set.")))
 
         import re
         r_tr = re.search(r"([0-9]+) translated", output)
@@ -447,7 +449,7 @@
             if error:
                 myfile = os.path.basename(pofile)
                 errors.append(("warn",
-                               "PO file '%s' is not UTF-8 encoded." % (myfile)))
+                               defaults.N_("PO file '%s' is not UTF-8 encoded.") % (myfile)))
         return {
             'translated' : translated,
             'fuzzy' : fuzzy,
@@ -516,7 +518,7 @@
         errors = []
 
         if not os.path.isdir(sourcedir):
-            errors.append(("error", "Can't find checkout directory."))
+            errors.append(("error", defaults.N_("Can't find checkout directory.")))
             return { 'errors' : errors, 'translated' : 0, 'untranslated' : 0, 'fuzzy' : 0 }
 
         # read interesting variables from the Makefile.am
@@ -536,15 +538,15 @@
         except: pass
 
         if not modulename:
-            errors.append(("error", "Module %s doesn't look like gnome-doc-utils module." % (moduleid)))
+            errors.append(("error", defaults.N_("Module %s doesn't look like gnome-doc-utils module.") % (moduleid)))
             return { 'errors' : errors, 'translated' : 0, 'untranslated' : 0, 'fuzzy' : 0 }
 
         if not os.access(os.path.join(sourcedir, "C", modulename + ".xml"), os.R_OK):
             if os.access(os.path.join(sourcedir, "C", moduleid + ".xml"), os.R_OK):
-                errors.append(("warn", "DOC_MODULE doesn't resolve to a real file, using '%s.xml'." % (moduleid)))
+                errors.append(("warn", defaults.N_("DOC_MODULE doesn't resolve to a real file, using '%s.xml'.") % (moduleid)))
                 modulename = moduleid
             else:
-                errors.append(("error", "DOC_MODULE doesn't point to a real file, probably a macro."))
+                errors.append(("error", defaults.N_("DOC_MODULE doesn't point to a real file, probably a macro.")))
                 return { 'errors' : errors, 'translated' : 0, 'untranslated' : 0, 'fuzzy' : 0 }
 
         out_domain = potbase + "." + self.branch
@@ -570,9 +572,8 @@
         (error, output) = commands.getstatusoutput(command)
         if error:
             errors.append(("error",
-                           "Error regenerating POT file for document %s:\n<pre>%s\n%s</pre>" % (out_domain,
-                                                                                                command,
-                                                                                                output)))
+                           defaults.N_("Error regenerating POT file for document %s:\n<pre>%s\n%s</pre>")
+                           % (out_domain, command, output)))
         if defaults.DEBUG: print >> sys.stderr, output
 
         pot_stats = self.po_file_stats(fullpot,0)
@@ -600,7 +601,7 @@
         langs = teams.TranslationLanguages()
         for lang in postats:
             if lang and not langs.has_key(lang):
-                postats[lang]['errors'].append(("error", "There is no translation team in charge of %s." % (lang)))
+                postats[lang]['errors'].append(("error", defaults.N_("There is no translation team in charge of %s.") % (lang)))
 
             self.update_stats_database(module = self.module["id"], branch = self.branch, type = 'doc',
                                        domain = potbase, date = NOW, language = lang,
@@ -644,7 +645,7 @@
 
                 langstats = self.po_file_stats(outpo, 1)
                 if lang not in languages:
-                    langstats['errors'].append(("warn", "DOC_LINGUAS list doesn't include this language."))
+                    langstats['errors'].append(("warn", defaults.N_("DOC_LINGUAS list doesn't include this language.")))
 
                 stats[lang] = langstats
                 if defaults.DEBUG: print >>sys.stderr, lang + ":\n" + str(langstats)
Index: po/fr.po
===================================================================
--- po/fr.po	(révision 404)
+++ po/fr.po	(copie de travail)
@@ -8,8 +8,8 @@
 msgstr ""
 "Project-Id-Version: damned-lies.HEAD\n"
 "Report-Msgid-Bugs-To: \n"
-"POT-Creation-Date: 2007-05-25 21:42+0200\n"
-"PO-Revision-Date: 2007-05-25 21:45+0200\n"
+"POT-Creation-Date: 2007-07-05 17:24+0200\n"
+"PO-Revision-Date: 2007-07-04 21:22+0200\n"
 "Last-Translator: Claude Paroz <claude@2xlibre.net>\n"
 "Language-Team: GNOME French Team <gnomefr@traduc.org>\n"
 "MIME-Version: 1.0\n"
@@ -434,7 +434,7 @@
 msgid "freedesktop.org (non-GNOME)."
 msgstr "freedesktop.org (non GNOME)"
 
-#: ../teams.py:156 ../teams.py:265
+#: ../teams.py:153 ../teams.py:247
 #, python-format
 msgid "%(lang)s Translation Team"
 msgstr "Équipe de traduction en %(lang)s"
@@ -978,25 +978,149 @@
 msgstr "gallois"
 
 #: ../translation-teams.xml.in.h:135
+msgid "Wolof"
+msgstr "wolof"
+
+#: ../translation-teams.xml.in.h:136
 msgid "Xhosa"
 msgstr "xhosa"
 
-#: ../translation-teams.xml.in.h:136
+#: ../translation-teams.xml.in.h:137
 msgid "Yiddish"
 msgstr "yiddish"
 
-#: ../translation-teams.xml.in.h:137
+#: ../translation-teams.xml.in.h:138
 msgid "Yoruba"
 msgstr "yoruba"
 
-#: ../translation-teams.xml.in.h:138
+#: ../translation-teams.xml.in.h:139
 msgid "Zapotec"
 msgstr "zapotec"
 
-#: ../translation-teams.xml.in.h:139
+#: ../translation-teams.xml.in.h:140
 msgid "Zulu"
 msgstr "zoulou"
 
+#: ../update-stats.py:214
+msgid "Can't generate POT file, using old one."
+msgstr "Impossible de générer le fichier POT, utilisation de l'ancien."
+
+#: ../update-stats.py:217
+msgid "Can't generate POT file, using old one if it exists."
+msgstr ""
+"Impossible de générer le fichier POT, utilisation de l'ancien s'il existe."
+
+#: ../update-stats.py:246
+msgid "Can't copy new POT file to public location."
+msgstr ""
+"Impossible de copier le nouveau fichier POT vers un emplacement public."
+
+#: ../update-stats.py:258
+#, python-format
+msgid "There is no translation team in charge of '%s' translation."
+msgstr "Il n'existe pas d'équipe de traduction pour la traduction de « %s »."
+
+#: ../update-stats.py:334
+msgid "Entry for this language is not present in LINGUAS file."
+msgstr "Le fichier LINGUAS ne contient pas de référence à cette langue."
+
+#: ../update-stats.py:362
+msgid ""
+"Entry for this language is not present in ALL_LINGUAS in configure file."
+msgstr ""
+"La variable ALL_LINGUAS du fichier « configure » ne contient pas de "
+"référence à cette langue."
+
+#: ../update-stats.py:365
+msgid ""
+"Don't know where to look if this language is actually used, ask the module "
+"maintainer."
+msgstr ""
+"Aucune idée de l'endroit où se trouve la référence aux langues vraiment "
+"utilisées, demandez au mainteneur du module."
+
+#: ../update-stats.py:379
+msgid "Errors while running 'intltool-update -m' check."
+msgstr ""
+"Des erreurs se sont produites lors de la vérification par « intltool-update -"
+"m »."
+
+#: ../update-stats.py:385
+#, python-format
+msgid "There are some missing files from POTFILES.in: %s"
+msgstr "Il manque des fichiers dans POTFILES.in : %s"
+
+#: ../update-stats.py:394
+#, python-format
+msgid ""
+"Following files are referenced in either POTFILES.in or POTFILES.skip, yet "
+"they don't exist: %s"
+msgstr ""
+"Les fichiers suivants sont référencés dans POTFILES.in ou dans POTFILES."
+"skip, mais ils n'existent pas : %s"
+
+#: ../update-stats.py:408
+#, python-format
+msgid "PO file '%s' doesn't exist."
+msgstr "Le fichier PO « %s » n'existe pas."
+
+#: ../update-stats.py:421
+#, python-format
+msgid "PO file '%s' doesn't pass msgfmt check: not updating."
+msgstr ""
+"Le fichier PO « %s » ne passe pas la vérification par « msgfmt » : pas de "
+"mise à jour."
+
+#: ../update-stats.py:423
+#, python-format
+msgid "Can't get statistics for POT file '%s'."
+msgstr "Impossible d'obtenir les statistiques pour le fichier POT « %s »."
+
+#: ../update-stats.py:426
+msgid "This PO file has an executable bit set."
+msgstr "Le bit d'exécution de ce fichier PO est activé."
+
+#: ../update-stats.py:452
+#, python-format
+msgid "PO file '%s' is not UTF-8 encoded."
+msgstr "Le fichier PO « %s » n'est pas codé en UTF-8."
+
+#: ../update-stats.py:521
+msgid "Can't find checkout directory."
+msgstr "Impossible de trouver le répertoire des fichiers source."
+
+#: ../update-stats.py:541
+#, python-format
+msgid "Module %s doesn't look like gnome-doc-utils module."
+msgstr "Le module %s ne semble pas être conforme à la norme gnome-doc-utils."
+
+#: ../update-stats.py:546
+#, python-format
+msgid "DOC_MODULE doesn't resolve to a real file, using '%s.xml'."
+msgstr ""
+"La variable DOC_MODULE ne correspond pas à un fichier réel, utilisation de "
+"« %s.xml »."
+
+#: ../update-stats.py:549
+msgid "DOC_MODULE doesn't point to a real file, probably a macro."
+msgstr ""
+"La variable DOC_MODULE ne correspond pas à un fichier réel, il s'agit "
+"probablement d'une macro."
+
+#: ../update-stats.py:575
+#, python-format
+msgid "Error regenerating POT file for document %s:"
+msgstr "Erreur lors de la régénération du fichier POT pour le document %s :"
+
+#: ../update-stats.py:604
+#, python-format
+msgid "There is no translation team in charge of %s."
+msgstr "Il n'existe aucune équipe de traduction responsable de %s."
+
+#: ../update-stats.py:648
+msgid "DOC_LINGUAS list doesn't include this language."
+msgstr "La liste DOC_LINGUAS ne contient pas cette langue."
+
 #: ../templates/index.tmpl:7 ../templates/index.tmpl:25
 msgid "Damned Lies about Gnome"
 msgstr "Damnés mensonges au sujet de GNOME"
@@ -1192,7 +1316,8 @@
 "check each module's web page to see where to send translations."
 msgstr ""
 "Les modules de cette version ne font pas partie du dépôt SVN de GNOME. "
-"Consultez la page Web de chaque module pour savoir où envoyer les traductions."
+"Consultez la page Web de chaque module pour savoir où envoyer les "
+"traductions."
 
 #: ../templates/release.tmpl:29 ../templates/team.tmpl:109
 msgid "Release"
@@ -1231,10 +1356,11 @@
 msgstr "Langues GNOME"
 
 #: ../templates/list-languages.tmpl:24
-msgid "Gnome is being translated to following languages:"
-msgstr "GNOME est en cours de traduction dans les langues suivantes :"
+#, c-format
+msgid "Gnome is being translated to following languages (%s):"
+msgstr "GNOME est en cours de traduction dans les langues suivantes (%s) :"
 
-#: ../templates/list-languages.tmpl:38
+#: ../templates/list-languages.tmpl:48
 msgid "Gnome is currently not being translated to any language. :("
 msgstr "GNOME n'est actuellement traduit dans aucune langue. :("
 
@@ -1322,8 +1448,8 @@
 "This module is not part of the GNOME SVN repository. Please check the "
 "module's web page to see where to send translations."
 msgstr ""
-"Ce module ne fait pas partie du dépôt SVN de GNOME. "
-"Consultez la page Web du module pour savoir où envoyer les traductions."
+"Ce module ne fait pas partie du dépôt SVN de GNOME. Consultez la page Web du "
+"module pour savoir où envoyer les traductions."
 
 #: ../templates/module.tmpl:39
 msgid "Maintainers"
Index: po/POTFILES.in
===================================================================
--- po/POTFILES.in	(révision 404)
+++ po/POTFILES.in	(copie de travail)
@@ -5,6 +5,7 @@
 releases.xml.in
 teams.py
 translation-teams.xml.in
+update-stats.py
 templates/index.tmpl
 templates/show-stats.tmpl
 templates/person.tmpl
Index: view-module.py
===================================================================
--- view-module.py	(révision 404)
+++ view-module.py	(copie de travail)
@@ -58,7 +58,7 @@
 
         here['pot_messages'] = []
         for msg in pot.Messages:
-            here['pot_messages'].append({'type' : msg.Type, 'content' : msg.Description})
+            here['pot_messages'].append({'type' : msg.Type, 'content' : l10n.gettext(msg.Description)})
 
         here['statistics'] = []
         langres = teams.TranslationLanguages(show_hidden=1)
@@ -98,13 +98,13 @@
                 new['po_messages'].append({'type': msg.Type, 'content': msg.Description})
                 if msg.Type=='error':
                     new['po_error'] = 'error'
-                    new['po_error_message'] = msg.Description
+                    new['po_error_message'] = l10n.gettext(msg.Description)
                 elif msg.Type=='warn' and new['po_error'] != 'error':
                     new['po_error'] = 'warn'
-                    new['po_error_message'] = msg.Description
+                    new['po_error_message'] = l10n.gettext(msg.Description)
                 elif msg.Type=='info' and not new['po_error']:
                     new['po_error'] = 'info'
-                    new['po_error_message'] = msg.Description
+                    new['po_error_message'] = l10n.gettext(msg.Description)
 
 
             here['statistics'].append(new)
Index: releases.py
===================================================================
--- releases.py	(révision 404)
+++ releases.py	(copie de travail)
@@ -42,7 +42,7 @@
 
             msgs = []
             for msg in stats[0].Messages:
-                msgs.append( (msg.Type, msg.Description) )
+                msgs.append( (msg.Type, l10n.gettext(msg.Description)) )
 
             return (tr,fz,un, msgs)
         else:
Index: l10n.py
===================================================================
--- l10n.py	(révision 404)
+++ l10n.py	(copie de travail)
@@ -6,6 +6,7 @@
 import defaults
 import accept
 import os
+import re
 
 trans = None
 
@@ -32,12 +33,27 @@
     get_trans()
 
 def gettext(text):
-    return get_trans().ugettext(unicode(text,'utf-8'))
+    if type(text) != type(u""):
+        text = unicode(text,'utf-8')
+    matches = re.findall('###([^#]*)###',text) 
+    if matches:
+        text = re.sub('###([^#]*)###', '%s', text)
 
+    text = get_trans().ugettext(text)
+    
+    #FIXME: if multiple substitutions, works only if order of %s is unchanged in translated string
+    for match in matches:
+    	  text = text.replace('%s',match,1)
+    return text
 
 def ngettext(text, plural, number):
-    return get_trans().ungettext(unicode(text,'utf-8'), unicode(plural,'utf-8'), number)
+    if type(text) != type(u""):
+        text = unicode(text,'utf-8')
+    if type(plural) != type(u""):
+        plural = unicode(plural,'utf-8')
 
+    return get_trans().ungettext(text, plural, number)
+
 class MyFilter(Cheetah.Filters.Filter):
     def filter(self, val, **kw):
         del kw['rawExpr']
