commit eb6e0359e66f7e92e69b30eaa3795818d2e29ab0
Author: Marc Dequènes (Duck) <Duck@DuckCorp.org>
Date:   Sun Apr 4 02:27:55 2010 +0200

    [evol] translation rework: new mechanism to handle translated/untranslated strings, make use of translation parameters, moved I18n class, translations update

diff --git a/bin/postman b/bin/postman
index 1a01e90..ee5fe00 100755
--- a/bin/postman
+++ b/bin/postman
@@ -24,6 +24,7 @@ $: << File.join(File.dirname(__FILE__), "..", "lib")
 #require 'socket'
 require 'tempfile'
 require 'shellwords'
+require 'cyborghood/language'
 require 'cyborghood/imap'
 require 'cyborghood/mail'
 require 'cyborghood/mail_order'
@@ -35,12 +36,12 @@ require 'cyborghood/services/dns'
 
 module CyborgHood
   module PostmanHome
-    include GetText
+    include CHTranslation
     bindtextdomain("cyborghood_postman", {:path => Config::L10N_DIR, :charset => "UTF-8"})
 
     # not yet ready to be a real Cyborg
     class Postman #< Cyborg
-      include GetText
+      include CHTranslation
 
       def initialize
         # load config
@@ -132,7 +133,9 @@ module CyborgHood
             end
           end
           result_tag = report.ok? ? "SUCCESS" : "FAILURE"
-          logger.info "Processing result: #{result_tag} (#{report.error})"
+          result_msg = "Processing result: #{result_tag}"
+	  result_msg += " (#{report.error.untranslated})" unless report.ok?
+          logger.info result_msg
 
           i18n = I18n.instance
           i18n.set_language_for_user(report.user)
@@ -140,10 +143,10 @@ module CyborgHood
           unless report.ok?
             if report.warn_sender
               logger.info "Sending reply for rejected message"
-              intro = report.user ? sprintf(_("Hello %s,"), report.user.cn) : _("Hello,")
-              mail_reply = mail.create_simple_reject_reply(intro + "\n\n" + sprintf(
-                           _("A message (ID: %s), apparently from you, was rejected for the following reason:"),
-                           mail.message_id) + "\n  " + _(report.error) + "\n" + mail_signature())
+              reply_intro = report.user ? _("Hello %{cn},", :cn =>report.user.cn) : _("Hello,")
+              mail_reply = mail.create_simple_reject_reply(reply_intro.to_s + "\n\n" +
+                           _("A message (ID: %{id}), apparently from you, was rejected for the following reason:",
+                           :id => mail.message_id).to_s + "\n  " + report.error.to_s + "\n" + mail_signature())
               mail_reply.deliver
             end
             msg.delete
@@ -152,13 +155,17 @@ module CyborgHood
 
           order = MailOrder.parse(report.user, report.message)
           result_tag = order.valid? ? "SUCCESS" : "FAILURE"
-          logger.info "Processing result: #{result_tag} (#{order.error})"
+          result_msg = "Processing result: #{result_tag}"
+	  result_msg += " (#{order.error.untranslated})" unless order.valid?
+          logger.info result_msg
+
+          reply_intro = _("Hello %{cn},", :cn => order.user.cn)
 
           unless order.valid?
             logger.info "Sending reply for rejected order"
-            mail_reply = mail.create_simple_reject_reply(sprintf(_("Hello %s,"), order.user.cn) + "\n\n" +
-                         sprintf(_("An order, in a message (ID: %s) from you, was rejected for the following reason:"),
-                         mail.message_id) + "\n  " + _(order.error) + "\n" + mail_signature())
+            mail_reply = mail.create_simple_reject_reply(reply_intro.to_s + "\n\n" +
+                         _("An order, in a message (ID: %{id}) from you, was rejected for the following reason:",
+                         :id => mail.message_id).to_s + "\n  " + order.error.to_s + "\n" + mail_signature())
             mail_reply.sign_and_crypt(order.user.keyFingerPrint)
             mail_reply.deliver
             msg.delete
@@ -170,8 +177,8 @@ module CyborgHood
 
           # create transcript
           logger.debug "Preparing reply"
-          reply_txt = sprintf(_("Hello %s,"), order.user.cn) + "\n\n"
-          reply_txt += _("Follows the transcript of your commands:") + "\n"
+          reply_txt = reply_intro.to_s + "\n\n"
+          reply_txt += _("Follows the transcript of your commands:").to_s + "\n"
           reply_attachments = []
           result_list.each do |result|
             reply_txt += "> #{result.cmd}\n"
@@ -220,14 +227,14 @@ module CyborgHood
         s = "\n" +
           "-- \n" +
           "#{CyborgHood::PRODUCT} v#{CyborgHood::VERSION}\n"
-        s += _("Contact eMail:") + " \"#{@config.contact.name}\" <#{@config.contact.email}>\n" if @config.contact.email
-        s += _("Contact URL:") + " #{@config.contact.url}\n" if @config.contact.url
+        s += _("Contact eMail:").to_s + " \"#{@config.contact.name}\" <#{@config.contact.email}>\n" if @config.contact.email
+        s += _("Contact URL:").to_s + " #{@config.contact.url}\n" if @config.contact.url
         s
       end
     end
 
     class CommandRunner
-      include GetText
+      include CHTranslation
 
       def self.run(order)
         result_list = []
@@ -243,15 +250,17 @@ module CyborgHood
             rescue CyberError => e
               result.message = e.message.capitalize + "."
             rescue
-              logger.warn "Command crashed: " + $!
+              logger.error "Command crashed: " + $!
+	      logger.error "Crash trace: " + $!.backtrace.join("\n")
               result.message = _("Internal error. Administrator is warned.")
             end
 
-            tag = result.ok ? "SUCCESS" :"FAILURE"
+            tag = result.ok ? "SUCCESS" : "FAILURE"
             logger.debug "Command result: [#{tag}] #{result.message}"
           else
             logger.info "Invalid command detected: #{cmd.cmdline}"
-            result.message = cmd.parsing_errors.collect{|err| _(err) }.join("\n")
+	    cmd.parsing_errors.collect{|err| logger.debug "Invalid command detected - reason: " + err.untranslated }
+            result.message = cmd.parsing_errors.collect{|err| err.to_s }.join("\n")
           end
           result_list << result
         end
@@ -271,7 +280,7 @@ module CyborgHood
             list = CyborgHood::DnsDomain.find_by_manager(user)
             txt_list = list.collect{|z| z.cn }.sort.join(", ")
             result.ok = true
-            result.message = sprintf(_("You are manager of the following zones: %s."), txt_list)
+            result.message = _("You are manager of the following zones: %{zone_list}.", :zone_list => txt_list)
           when "GET"
             return if cmdline.empty?
             case cmdline.shift.upcase
diff --git a/lib/cyborghood/base.rb b/lib/cyborghood/base.rb
index 4d613b9..50769a7 100644
--- a/lib/cyborghood/base.rb
+++ b/lib/cyborghood/base.rb
@@ -21,13 +21,13 @@ require 'jcode'
 require 'singleton'
 require 'yaml'
 require 'log4r'
-require 'gettext'
 require "cyborghood/config"
 require "cyborghood/info"
 require "cyborghood/lang_additions"
+require 'cyborghood/language'
 
 module CyborgHood
-  include GetText
+  include CHTranslation
   bindtextdomain("cyborghood", {:path => Config::L10N_DIR, :charset => "UTF-8"})
 
   # severities: :grave :unrecoverable :processable :ignorable
@@ -152,48 +152,4 @@ module CyborgHood
       return new_conf
     end
   end
-
-  class I18n
-    include Singleton
-    include GetText
-
-    def initialize
-      @config = Config.instance
-    end
-
-    def available_languages
-      list = ['en'] + Dir.new(Config::L10N_DIR).select{|d| File.directory?(d) and d[0..0] != "." }
-      # local admin can restrict available languages
-      # (may be useful if l10n is partial due to third party plugins)
-      list = list & @config.i18n.restricted_language_set if @config.i18n.restricted_language_set
-      list = ['en'] if list.empty?
-      list
-    end
-
-    def set_language(lang)
-      set_locale_all(lang)
-    end
-
-    def set_default_language
-      set_language('en')
-    end
-
-    def set_language_for_user(user)
-      if user.nil?
-        set_default_language
-      else
-        logger.debug "User preference for language: " + user.preferredLanguage
-
-        lang = user.prefered_language(self.available_languages)
-        if lang.nil?
-          logger.debug "No available langage fits the user preference, using english"
-          lang = 'en'
-        else
-          logger.debug "Language better fitting user preference: " + lang
-        end
-
-        set_language(lang)
-      end
-    end
-  end
 end
diff --git a/lib/cyborghood/language.rb b/lib/cyborghood/language.rb
new file mode 100644
index 0000000..f330add
--- /dev/null
+++ b/lib/cyborghood/language.rb
@@ -0,0 +1,122 @@
+#--
+# CyborgHood, a distributed system management software.
+# Copyright (c) 2009 Marc Dequènes (Duck) <Duck@DuckCorp.org>
+#
+# This program 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.
+#
+# This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.
+#++
+
+require 'singleton'
+require 'gettext'
+
+
+module CyborgHood
+  class I18n
+    include Singleton
+    include GetText
+
+    def initialize
+      @config = Config.instance
+    end
+
+    def available_languages
+      list = ['en'] + Dir.new(Config::L10N_DIR).select{|d| p d; File.directory?(d) and d[0..0] != "." }
+      # local admin can restrict available languages
+      # (may be useful if l10n is partial due to third party plugins)
+      list = list & @config.i18n.restricted_language_set if @config.i18n.restricted_language_set
+      list = ['en'] if list.empty?
+      list
+    end
+
+    def set_language(lang)
+      set_locale_all(lang)
+    end
+
+    def set_default_language
+      set_language('en')
+    end
+
+    def set_language_for_user(user)
+      if user.nil?
+        set_default_language
+      else
+        logger.debug "User preference for language: " + user.preferredLanguage
+
+        lang = user.prefered_language(self.available_languages)
+        if lang.nil?
+          logger.debug "No available language fits the user preference, using english"
+          lang = 'en'
+        else
+          logger.debug "Language better fitting user preference: " + lang
+        end
+
+        set_language(lang)
+      end
+    end
+  end
+
+  class CHMessage
+    attr_reader :translated, :untranslated, :parts
+
+    def initialize(translated, untranslated, parts)
+      @translated = translated % parts
+      @untranslated = untranslated % parts
+      @parts = parts
+    end
+
+    def to_s
+      @translated
+    end
+  end
+
+  module CHTranslation
+    def self.included(base)
+      base.class_eval("include GetText")
+
+      # translation methods needs to be available at class level too
+      base.extend(self)
+    end
+    include GetText
+
+    alias :_orig :_
+    def _(message, parts = {})
+      create_tm(:_orig, message, parts)
+    end
+
+    alias :n_orig :n_
+    def n_(message, parts = {})
+      create_tm(:n_orig, message, parts)
+    end
+
+    alias :s_orig :s_
+    def s_(message, parts = {})
+      create_tm(:s_orig, message, parts)
+    end
+
+    alias :ns_orig :ns_
+    def ns_(message, parts = {})
+      create_tm(:ns_orig, message, parts)
+    end
+
+    alias :np_orig :np_
+    def np_(message, parts = {})
+      create_tm(:np_orig, message, parts)
+    end
+
+    def create_tm(method, message, parts)
+      CHMessage.new(self.send(method, message), message, parts)
+    end
+
+    module_function :_, :n_, :s_, :ns_, :np_
+  end
+end
diff --git a/lib/cyborghood/mail.rb b/lib/cyborghood/mail.rb
index 198dac1..41ed66a 100644
--- a/lib/cyborghood/mail.rb
+++ b/lib/cyborghood/mail.rb
@@ -64,7 +64,7 @@ module CyborgHood
   class Mail < Delegator
     include ActionMailer::Quoting
     include ActionMailer::Utils
-    include GetText
+    include CHTranslation
 
     MAX_DRIFT_TIME = 3600
 
@@ -90,13 +90,13 @@ module CyborgHood
 
     def process
       if is_marked?
-        return MailReport.new(:error => "Replay detected.")
+        return MailReport.new(:error => _("Replay detected."))
       end
 
       return process_signed() if is_pgp_signed?
       return process_encrypted() if is_pgp_encrypted?
 
-      MailReport.new(:error => "Mail not RFC3156 compliant.")
+      MailReport.new(:error => _("Mail not RFC3156 compliant."))
     end
 
     def create_reply
@@ -170,14 +170,14 @@ module CyborgHood
 
     def process_signed
       sigs_check = verify_pgp_signature()
-      return MailReport.new(:error => "Mail not formatted correctly (signed part).") if sigs_check.nil? or sigs_check.size != 1
+      return MailReport.new(:error => _("Mail not formatted correctly (signed part).")) if sigs_check.nil? or sigs_check.size != 1
 
       sig_check = sigs_check.first
-      return MailReport.new(:error => "Mail content tampered or badly signed: " + sig_check.to_s) unless sig_check.status == 0
+      return MailReport.new(:error => _("Mail content tampered or badly signed: %{sig_err}", :sig_err => sig_check.to_s)) unless sig_check.status == 0
 
       logger.info "Mail content was properly signed by key #{sig_check.fingerprint}"
       user = Person.find_by_fingerprint(sig_check.fingerprint)
-      return MailReport.new(:error => "Mail is from an unknown person.", :warn_sender => true) if user.nil?
+      return MailReport.new(:error => _("Mail is from an unknown person."), :warn_sender => true) if user.nil?
 
       logger.info "Mail is from user #{user.uid} (#{user.cn})"
       self.user = user
@@ -186,11 +186,11 @@ module CyborgHood
       logger.debug "Signature drift time: #{drift}"
       unless drift.abs < MAX_DRIFT_TIME
         if drift > 0
-          return MailReport.new(:error => N_("The signature was made too long ago (check your system clock). Rejected message to avoid replay attacks."), :user => user)
+          return MailReport.new(:error => _("The signature was made too long ago (check your system clock). Rejected message to avoid replay attacks."), :user => user)
         else
           # mark message to prevent later replay of the message
           mark_processed(sig_check.timestamp)
-          return MailReport.new(:error => N_("The signature was made in the future (check your system clock). Rejected message to avoid replay attacks."), :user => user)
+          return MailReport.new(:error => _("The signature was made in the future (check your system clock). Rejected message to avoid replay attacks."), :user => user)
         end
       end
 
@@ -235,7 +235,7 @@ module CyborgHood
         end
       end
 
-      MailReport.new(:error => "Mail not formatted correctly (encrypted part).")
+      MailReport.new(:error => _("Mail not formatted correctly (encrypted part)."))
     end
 
     def mark_dir
diff --git a/lib/cyborghood/mail_order.rb b/lib/cyborghood/mail_order.rb
index ef2bcdf..8194355 100644
--- a/lib/cyborghood/mail_order.rb
+++ b/lib/cyborghood/mail_order.rb
@@ -22,7 +22,7 @@ module CyborgHood
         order_txt = message.body if message.content_type == "text/plain"
         shared_parameters = {}
       end
-      return new(:error => N_("Mail does not contain a proper text part for commands."), :user => user) if order_txt.nil?
+      return new(:error => _("Mail does not contain a proper text part for commands."), :user => user) if order_txt.nil?
 
       command_lines = order_txt.split("\n")
 
@@ -35,8 +35,7 @@ module CyborgHood
           ref = $1
           d_ref, d_param = dereference_param(shared_parameters, param)
           if d_ref.nil?
-            # TODO: a message class is needed to handle passing translatable strings with parameters (doing late sprintf for example)
-            errors << N_("Attachment '#{ref}' not found.")
+            errors << _("Attachment '%{ref}' not found.", :ref => ref)
           else
             used_refs << d_ref
           end
diff --git a/lib/cyborghood/order.rb b/lib/cyborghood/order.rb
index e8ddcd4..c7b088a 100644
--- a/lib/cyborghood/order.rb
+++ b/lib/cyborghood/order.rb
@@ -31,7 +31,7 @@ module CyborgHood
   end
 
   class Order
-    include GetText
+    include CHTranslation
     attr_reader :error, :user, :commands, :shared_parameters
 
     def initialize(params = {})
@@ -54,7 +54,7 @@ module CyborgHood
         begin
           raw_cmd_parts = line.shellsplit
         rescue
-          errors << N_("Syntax error in command.")
+          errors << _("Syntax error in command.")
           raw_cmd_parts = []
         end
         cmd_parts = raw_cmd_parts.collect do |word|
diff --git a/po/cyborghood.pot b/po/cyborghood.pot
index 46b8a1e..4ef61cf 100644
--- a/po/cyborghood.pot
+++ b/po/cyborghood.pot
@@ -7,7 +7,7 @@
 msgid ""
 msgstr ""
 "Project-Id-Version: CyborgHood 0.2.0~dev\n"
-"POT-Creation-Date: 2010-03-07 19:04+0100\n"
+"POT-Creation-Date: 2010-04-04 02:19+0200\n"
 "PO-Revision-Date: 2009-03-07 21:38+0100\n"
 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
 "Language-Team: LANGUAGE <LL@li.org>\n"
@@ -20,6 +20,26 @@ msgstr ""
 msgid "Syntax error in command."
 msgstr ""
 
+#: lib/cyborghood/mail.rb:93
+msgid "Replay detected."
+msgstr ""
+
+#: lib/cyborghood/mail.rb:99
+msgid "Mail not RFC3156 compliant."
+msgstr ""
+
+#: lib/cyborghood/mail.rb:173
+msgid "Mail not formatted correctly (signed part)."
+msgstr ""
+
+#: lib/cyborghood/mail.rb:176
+msgid "Mail content tampered or badly signed: %{sig_err}"
+msgstr ""
+
+#: lib/cyborghood/mail.rb:180
+msgid "Mail is from an unknown person."
+msgstr ""
+
 #: lib/cyborghood/mail.rb:189
 msgid ""
 "The signature was made too long ago (check your system clock). Rejected "
@@ -32,6 +52,14 @@ msgid ""
 "message to avoid replay attacks."
 msgstr ""
 
+#: lib/cyborghood/mail.rb:238
+msgid "Mail not formatted correctly (encrypted part)."
+msgstr ""
+
 #: lib/cyborghood/mail_order.rb:25
 msgid "Mail does not contain a proper text part for commands."
 msgstr ""
+
+#: lib/cyborghood/mail_order.rb:38
+msgid "Attachment '%{ref}' not found."
+msgstr ""
diff --git a/po/cyborghood_postman.pot b/po/cyborghood_postman.pot
index 8f9bacb..284a95f 100644
--- a/po/cyborghood_postman.pot
+++ b/po/cyborghood_postman.pot
@@ -7,7 +7,7 @@
 msgid ""
 msgstr ""
 "Project-Id-Version: CyborgHood 0.2.0~dev\n"
-"POT-Creation-Date: 2010-03-07 19:04+0100\n"
+"POT-Creation-Date: 2010-04-04 02:19+0200\n"
 "PO-Revision-Date: 2009-03-07 21:38+0100\n"
 "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
 "Language-Team: LANGUAGE <LL@li.org>\n"
@@ -16,75 +16,74 @@ msgstr ""
 "Content-Transfer-Encoding: 8bit\n"
 "Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n"
 
-#: /opt/cyborghood-dev/bin/postman:143 /opt/cyborghood-dev/bin/postman:159
-#: /opt/cyborghood-dev/bin/postman:173
-msgid "Hello %s,"
+#: /opt/cyborghood-dev/bin/postman:146 /opt/cyborghood-dev/bin/postman:162
+msgid "Hello %{cn},"
 msgstr ""
 
-#: /opt/cyborghood-dev/bin/postman:143
+#: /opt/cyborghood-dev/bin/postman:146
 msgid "Hello,"
 msgstr ""
 
-#: /opt/cyborghood-dev/bin/postman:145
+#: /opt/cyborghood-dev/bin/postman:148
 msgid ""
-"A message (ID: %s), apparently from you, was rejected for the following "
+"A message (ID: %{id}), apparently from you, was rejected for the following "
 "reason:"
 msgstr ""
 
-#: /opt/cyborghood-dev/bin/postman:160
+#: /opt/cyborghood-dev/bin/postman:167
 msgid ""
-"An order, in a message (ID: %s) from you, was rejected for the following "
+"An order, in a message (ID: %{id}) from you, was rejected for the following "
 "reason:"
 msgstr ""
 
-#: /opt/cyborghood-dev/bin/postman:174
+#: /opt/cyborghood-dev/bin/postman:181
 msgid "Follows the transcript of your commands:"
 msgstr ""
 
-#: /opt/cyborghood-dev/bin/postman:223
+#: /opt/cyborghood-dev/bin/postman:230
 msgid "Contact eMail:"
 msgstr ""
 
-#: /opt/cyborghood-dev/bin/postman:224
+#: /opt/cyborghood-dev/bin/postman:231
 msgid "Contact URL:"
 msgstr ""
 
-#: /opt/cyborghood-dev/bin/postman:247 /opt/cyborghood-dev/bin/postman:356
+#: /opt/cyborghood-dev/bin/postman:255 /opt/cyborghood-dev/bin/postman:365
 msgid "Internal error. Administrator is warned."
 msgstr ""
 
-#: /opt/cyborghood-dev/bin/postman:274
-msgid "You are manager of the following zones: %s."
+#: /opt/cyborghood-dev/bin/postman:283
+msgid "You are manager of the following zones: %{zone_list}."
 msgstr ""
 
-#: /opt/cyborghood-dev/bin/postman:284 /opt/cyborghood-dev/bin/postman:306
+#: /opt/cyborghood-dev/bin/postman:293 /opt/cyborghood-dev/bin/postman:315
 msgid "This zone is not hosted here."
 msgstr ""
 
-#: /opt/cyborghood-dev/bin/postman:288 /opt/cyborghood-dev/bin/postman:310
+#: /opt/cyborghood-dev/bin/postman:297 /opt/cyborghood-dev/bin/postman:319
 msgid "You are not allowed to manage this zone."
 msgstr ""
 
-#: /opt/cyborghood-dev/bin/postman:294
+#: /opt/cyborghood-dev/bin/postman:303
 msgid "Requested zone content attached."
 msgstr ""
 
-#: /opt/cyborghood-dev/bin/postman:319
+#: /opt/cyborghood-dev/bin/postman:328
 msgid "Attachment has wrong content-type."
 msgstr ""
 
-#: /opt/cyborghood-dev/bin/postman:334
+#: /opt/cyborghood-dev/bin/postman:343
 msgid "Invalid zone data."
 msgstr ""
 
-#: /opt/cyborghood-dev/bin/postman:341
+#: /opt/cyborghood-dev/bin/postman:350
 msgid "Zone serial is not superior to current serial."
 msgstr ""
 
-#: /opt/cyborghood-dev/bin/postman:352
+#: /opt/cyborghood-dev/bin/postman:361
 msgid "Zone updated."
 msgstr ""
 
-#: /opt/cyborghood-dev/bin/postman:370
+#: /opt/cyborghood-dev/bin/postman:379
 msgid "Command not recognized."
 msgstr ""
diff --git a/po/fr/cyborghood.po b/po/fr/cyborghood.po
index 17d4896..bddae9e 100644
--- a/po/fr/cyborghood.po
+++ b/po/fr/cyborghood.po
@@ -7,8 +7,8 @@
 msgid ""
 msgstr ""
 "Project-Id-Version: CyborgHood 0.2.0~dev\n"
-"POT-Creation-Date: 2010-03-07 19:04+0100\n"
-"PO-Revision-Date: 2009-03-07 20:59+0100\n"
+"POT-Creation-Date: 2010-04-04 02:19+0200\n"
+"PO-Revision-Date: 2010-04-04 20:59+0100\n"
 "Last-Translator: Marc Dequènes (Duck) <Duck@DuckCorp.org>\n"
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=UTF-8\n"
@@ -17,7 +17,27 @@ msgstr ""
 
 #: lib/cyborghood/order.rb:57
 msgid "Syntax error in command."
-msgstr ""
+msgstr "Erreur de syntaxe dans la commande."
+
+#: lib/cyborghood/mail.rb:93
+msgid "Replay detected."
+msgstr "Rejeu détecté."
+
+#: lib/cyborghood/mail.rb:99
+msgid "Mail not RFC3156 compliant."
+msgstr "Mail ne respectant pas la RFC3156."
+
+#: lib/cyborghood/mail.rb:173
+msgid "Mail not formatted correctly (signed part)."
+msgstr "Mail formaté incorrectement (partie signée)."
+
+#: lib/cyborghood/mail.rb:176
+msgid "Mail content tampered or badly signed: %{sig_err}"
+msgstr "Contenu du mail altéré ou mal signé: %{sig_err}"
+
+#: lib/cyborghood/mail.rb:180
+msgid "Mail is from an unknown person."
+msgstr "Mail provenant d'une personne inconnue"
 
 #: lib/cyborghood/mail.rb:189
 msgid ""
@@ -35,7 +55,15 @@ msgstr ""
 "La signature a été faite dans le futur (vérifiez votre horloge système. "
 "Message rejeté pour éviter les attaques par rejeux."
 
+#: lib/cyborghood/mail.rb:238
+msgid "Mail not formatted correctly (encrypted part)."
+msgstr "Mail formaté incorrectement (partie chiffrée)."
+
 #: lib/cyborghood/mail_order.rb:25
 msgid "Mail does not contain a proper text part for commands."
 msgstr ""
 "Le mail ne contient pas de partie textuelle correcte pour les commandes."
+
+#: lib/cyborghood/mail_order.rb:38
+msgid "Attachment '%{ref}' not found."
+msgstr "La pièce jointe '%{ref}' n'a pas été trouvée."
diff --git a/po/fr/cyborghood_postman.po b/po/fr/cyborghood_postman.po
index 24c0374..4bd2adc 100644
--- a/po/fr/cyborghood_postman.po
+++ b/po/fr/cyborghood_postman.po
@@ -7,87 +7,86 @@
 msgid ""
 msgstr ""
 "Project-Id-Version: CyborgHood 0.2.0~dev\n"
-"POT-Creation-Date: 2010-03-07 19:04+0100\n"
-"PO-Revision-Date: 2009-03-07 21:27+0100\n"
+"POT-Creation-Date: 2010-04-04 02:19+0200\n"
+"PO-Revision-Date: 2010-04-04 21:27+0100\n"
 "Last-Translator: Marc Dequènes (Duck) <Duck@DuckCorp.org>\n"
 "MIME-Version: 1.0\n"
 "Content-Type: text/plain; charset=UTF-8\n"
 "Content-Transfer-Encoding: 8bit\n"
 "Plural-Forms: nplurals=1; plural=(n != 1);\n"
 
-#: /opt/cyborghood-dev/bin/postman:143 /opt/cyborghood-dev/bin/postman:159
-#: /opt/cyborghood-dev/bin/postman:173
-msgid "Hello %s,"
-msgstr "Bonjour %s,"
+#: /opt/cyborghood-dev/bin/postman:146 /opt/cyborghood-dev/bin/postman:162
+msgid "Hello %{cn},"
+msgstr "Bonjour %{cn},"
 
-#: /opt/cyborghood-dev/bin/postman:143
+#: /opt/cyborghood-dev/bin/postman:146
 msgid "Hello,"
 msgstr "Bonjour,"
 
-#: /opt/cyborghood-dev/bin/postman:145
+#: /opt/cyborghood-dev/bin/postman:148
 msgid ""
-"A message (ID: %s), apparently from you, was rejected for the following "
+"A message (ID: %{id}), apparently from you, was rejected for the following "
 "reason:"
 msgstr ""
-"Un message (ID: %s), provenant apparemment de vous, a été rejeté pour la "
+"Un message (ID: %{id}), provenant apparemment de vous, a été rejeté pour la "
 "raison suivante :"
 
-#: /opt/cyborghood-dev/bin/postman:160
+#: /opt/cyborghood-dev/bin/postman:167
 msgid ""
-"An order, in a message (ID: %s) from you, was rejected for the following "
+"An order, in a message (ID: %{id}) from you, was rejected for the following "
 "reason:"
 msgstr ""
-"Un order, dans in message (ID: %s) venant de vous, a été rejeté pour la "
+"Un order, dans in message (ID: %{id}) venant de vous, a été rejeté pour la "
 "raison suivante :"
 
-#: /opt/cyborghood-dev/bin/postman:174
+#: /opt/cyborghood-dev/bin/postman:181
 msgid "Follows the transcript of your commands:"
 msgstr "La retranscription des commandes suit :"
 
-#: /opt/cyborghood-dev/bin/postman:223
+#: /opt/cyborghood-dev/bin/postman:230
 msgid "Contact eMail:"
 msgstr "eMail de Contact :"
 
-#: /opt/cyborghood-dev/bin/postman:224
+#: /opt/cyborghood-dev/bin/postman:231
 msgid "Contact URL:"
 msgstr "URL de Contact :"
 
-#: /opt/cyborghood-dev/bin/postman:247 /opt/cyborghood-dev/bin/postman:356
+#: /opt/cyborghood-dev/bin/postman:255 /opt/cyborghood-dev/bin/postman:365
 msgid "Internal error. Administrator is warned."
 msgstr "Erreur interne. L'administrateur a été prévenu."
 
-#: /opt/cyborghood-dev/bin/postman:274
-msgid "You are manager of the following zones: %s."
-msgstr "Vous gérez les zones suivantes : %s."
+#: /opt/cyborghood-dev/bin/postman:283
+msgid "You are manager of the following zones: %{zone_list}."
+msgstr "Vous gérez les zones suivantes : %{zone_list}."
 
-#: /opt/cyborghood-dev/bin/postman:284 /opt/cyborghood-dev/bin/postman:306
+#: /opt/cyborghood-dev/bin/postman:293 /opt/cyborghood-dev/bin/postman:315
 msgid "This zone is not hosted here."
 msgstr "Cette zone n'est pas hébergée ici."
 
-#: /opt/cyborghood-dev/bin/postman:288 /opt/cyborghood-dev/bin/postman:310
+#: /opt/cyborghood-dev/bin/postman:297 /opt/cyborghood-dev/bin/postman:319
 msgid "You are not allowed to manage this zone."
 msgstr "Vous n'êtes pas autorisé à gérer cette zone."
 
-#: /opt/cyborghood-dev/bin/postman:294
+#: /opt/cyborghood-dev/bin/postman:303
 msgid "Requested zone content attached."
 msgstr "Le contenu de la zone demandée est en pièce jointe."
 
-#: /opt/cyborghood-dev/bin/postman:319
+#: /opt/cyborghood-dev/bin/postman:328
 msgid "Attachment has wrong content-type."
 msgstr "La pièce jointe a un mauvais type de contenu (content-type)."
 
-#: /opt/cyborghood-dev/bin/postman:334
+#: /opt/cyborghood-dev/bin/postman:343
 msgid "Invalid zone data."
 msgstr "Données pour la zone invalides."
 
-#: /opt/cyborghood-dev/bin/postman:341
+#: /opt/cyborghood-dev/bin/postman:350
 msgid "Zone serial is not superior to current serial."
 msgstr "Le numéro de série de la zone n'est pas supèrieur à celui actuel."
 
-#: /opt/cyborghood-dev/bin/postman:352
+#: /opt/cyborghood-dev/bin/postman:361
 msgid "Zone updated."
 msgstr "Zone mise à jour."
 
-#: /opt/cyborghood-dev/bin/postman:370
+#: /opt/cyborghood-dev/bin/postman:379
 msgid "Command not recognized."
-msgstr "Commande non reconnue"
+msgstr "Commande non reconnue."
