Revision e971ab5a
Added by Marc Dequènes almost 14 years ago
- ID e971ab5a16a21dbf2b682cbd27a87ffed5f1ea9d
bin/clerk | ||
---|---|---|
|
||
|
||
module CyborgHood
|
||
module DSL
|
||
include I18nTranslation
|
||
bindtextdomain("cyborghood_clerk", {:path => Config::L10N_DIR, :output_charset => "UTF-8"})
|
||
end
|
||
module ClerkLand
|
||
include I18nTranslation
|
||
bindtextdomain("cyborghood_clerk", {:path => Config::L10N_DIR, :output_charset => "UTF-8"})
|
||
... | ... | |
b.bot { CyborgHood::ClerkLand::Clerk.new(b.clerk_land) }
|
||
end
|
||
|
||
|
||
bot = reg.bot
|
||
|
||
|
lib/cyborghood/base/language.rb | ||
---|---|---|
attr_reader :untranslated, :parts
|
||
|
||
def initialize(untranslated, parts, context, method)
|
||
@untranslated = untranslated % parts
|
||
@untranslated = untranslated
|
||
@parts = parts
|
||
@context = context
|
||
@method = method
|
lib/cyborghood/command_runner.rb | ||
---|---|---|
#--
|
||
# CyborgHood, a distributed system management software.
|
||
# Copyright (c) 2009-2011 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 'tempfile'
|
||
require 'shellwords'
|
||
require 'cyborghood/order'
|
||
require 'cyborghood/objects'
|
||
|
||
|
||
module CyborgHood
|
||
class CommandRunner
|
||
include I18nTranslation
|
||
|
||
def self.run(order)
|
||
result_list = []
|
||
order.commands.each do |cmd|
|
||
result = OpenStruct.new
|
||
result.cmd = cmd.cmdline
|
||
result.ok = false
|
||
|
||
if cmd.valid?
|
||
logger.info "Executing command: #{cmd.cmdline}"
|
||
begin
|
||
execute_cmd(order.user, cmd.cmdsplit, result)
|
||
rescue CyberError => e
|
||
result.message = tm_(e.message.capitalize + ".")
|
||
rescue
|
||
logger.error "Command crashed: " + $!
|
||
logger.error "Crash trace: " + $!.backtrace.join("\n")
|
||
result.message = _("Internal error. Administrator is warned.")
|
||
end
|
||
|
||
tag = result.ok ? "SUCCESS" : "FAILURE"
|
||
logger.debug "Command result: [#{tag}] #{result.message.untranslated}"
|
||
else
|
||
logger.info "Invalid command detected: #{cmd.cmdline}"
|
||
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
|
||
result_list
|
||
end
|
||
|
||
private
|
||
|
||
def self.execute_cmd(user, cmdline, result)
|
||
subsys = cmdline.shift
|
||
case subsys.upcase
|
||
when "DNS"
|
||
return if cmdline.empty?
|
||
case cmdline.shift.upcase
|
||
when "INFO"
|
||
return unless cmdline.empty?
|
||
list = DnsDomain.find_by_manager(user)
|
||
txt_list = list.collect{|z| z.cn }.sort.join(", ")
|
||
result.ok = true
|
||
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
|
||
when "ZONE"
|
||
return if cmdline.empty?
|
||
zone = cmdline.shift.downcase
|
||
|
||
dom = DnsDomain.new(zone)
|
||
unless dom.hosted?
|
||
result.message = _("This zone is not hosted here.")
|
||
return result
|
||
end
|
||
unless dom.managed_by? user
|
||
result.message = _("You are not allowed to manage this zone.")
|
||
return result
|
||
end
|
||
|
||
srv_dns = Services::DNS.new(zone)
|
||
zone_content = srv_dns.read_zone
|
||
|
||
result.ok = true
|
||
result.message = _("Requested zone content attached.")
|
||
zone_ref = {:content => zone_content, :filename => "dnszone_#{zone}.txt"}.to_ostruct
|
||
result.refs = [zone_ref]
|
||
end
|
||
when "SET"
|
||
return if cmdline.empty?
|
||
case cmdline.shift.upcase
|
||
when "ZONE"
|
||
return if cmdline.empty?
|
||
zone = cmdline.shift.downcase
|
||
dom = DnsDomain.new(zone)
|
||
unless dom.hosted?
|
||
result.message = _("This zone is not hosted here.")
|
||
return result
|
||
end
|
||
unless dom.managed_by? user
|
||
result.message = _("You are not allowed to manage this zone.")
|
||
return result
|
||
end
|
||
srv_dns = Services::DNS.new(zone)
|
||
|
||
if cmdline.empty?
|
||
result.message = _("No attachment number provided")
|
||
return result
|
||
end
|
||
|
||
zone_data = cmdline.shift
|
||
unless zone_data.content_type == "text/plain"
|
||
result.message = _("Zone data has wrong content-type.")
|
||
return result
|
||
end
|
||
|
||
f = Tempfile.new(zone)
|
||
f.write(zone_data.content)
|
||
f.close
|
||
logger.debug "Created temporary zone file '#{f.path}'"
|
||
|
||
srv_dns = Services::DNS.new(zone)
|
||
current_serial = srv_dns.serial
|
||
logger.debug "Current serial: #{current_serial}"
|
||
|
||
dns_result = srv_dns.check_zone_file(f.path)
|
||
unless dns_result.ok
|
||
result.message = _("Invalid zone data.")
|
||
f.close!
|
||
return result
|
||
end
|
||
logger.debug "New serial: #{dns_result.serial}"
|
||
# allow new serial or missing serial (to allow creating a new zone or replacing a broken zone)
|
||
unless current_serial.nil? or dns_result.serial > current_serial
|
||
result.message = _("Zone serial is not superior to current serial.")
|
||
f.close!
|
||
return result
|
||
end
|
||
|
||
begin
|
||
srv_dns.write_zone_from_file(f.path)
|
||
logger.debug "zone changed"
|
||
if srv_dns.reload_zone
|
||
logger.debug "zone reloaded"
|
||
result.ok = true
|
||
result.message = _("Zone updated.")
|
||
else
|
||
logger.warn "zone reload failed, replacing old content"
|
||
srv_dns.replace_zone_with_backup
|
||
result.message = _("Internal error. Administrator is warned.")
|
||
end
|
||
rescue
|
||
logger.warn "Writing zone file failed"
|
||
raise
|
||
ensure
|
||
f.close!
|
||
end
|
||
end
|
||
end
|
||
end
|
||
|
||
if result.message.nil?
|
||
# here fall lost souls
|
||
result.message = _("Command not recognized.")
|
||
end
|
||
end
|
||
end
|
||
end
|
lib/cyborghood/command_runner.rb.bak | ||
---|---|---|
#--
|
||
# CyborgHood, a distributed system management software.
|
||
# Copyright (c) 2009-2011 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 'tempfile'
|
||
require 'shellwords'
|
||
require 'cyborghood/order'
|
||
require 'cyborghood/objects'
|
||
|
||
|
||
module CyborgHood
|
||
class CommandRunner
|
||
include I18nTranslation
|
||
|
||
def self.run(order)
|
||
result_list = []
|
||
order.commands.each do |cmd|
|
||
result = OpenStruct.new
|
||
result.cmd = cmd.cmdline
|
||
result.ok = false
|
||
|
||
if cmd.valid?
|
||
logger.info "Executing command: #{cmd.cmdline}"
|
||
begin
|
||
execute_cmd(order.user, cmd.cmdsplit, result)
|
||
rescue CyberError => e
|
||
result.message = tm_(e.message.capitalize + ".")
|
||
rescue
|
||
logger.error "Command crashed: " + $!
|
||
logger.error "Crash trace: " + $!.backtrace.join("\n")
|
||
result.message = _("Internal error. Administrator is warned.")
|
||
end
|
||
|
||
tag = result.ok ? "SUCCESS" : "FAILURE"
|
||
logger.debug "Command result: [#{tag}] #{result.message.untranslated}"
|
||
else
|
||
logger.info "Invalid command detected: #{cmd.cmdline}"
|
||
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
|
||
result_list
|
||
end
|
||
|
||
private
|
||
|
||
def self.execute_cmd(user, cmdline, result)
|
||
subsys = cmdline.shift
|
||
case subsys.upcase
|
||
when "DNS"
|
||
return if cmdline.empty?
|
||
case cmdline.shift.upcase
|
||
when "INFO"
|
||
return unless cmdline.empty?
|
||
list = DnsDomain.find_by_manager(user)
|
||
txt_list = list.collect{|z| z.cn }.sort.join(", ")
|
||
result.ok = true
|
||
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
|
||
when "ZONE"
|
||
return if cmdline.empty?
|
||
zone = cmdline.shift.downcase
|
||
|
||
dom = DnsDomain.new(zone)
|
||
unless dom.hosted?
|
||
result.message = _("This zone is not hosted here.")
|
||
return result
|
||
end
|
||
unless dom.managed_by? user
|
||
result.message = _("You are not allowed to manage this zone.")
|
||
return result
|
||
end
|
||
|
||
srv_dns = Services::DNS.new(zone)
|
||
zone_content = srv_dns.read_zone
|
||
|
||
result.ok = true
|
||
result.message = _("Requested zone content attached.")
|
||
zone_ref = {:content => zone_content, :filename => "dnszone_#{zone}.txt"}.to_ostruct
|
||
result.refs = [zone_ref]
|
||
end
|
||
when "SET"
|
||
return if cmdline.empty?
|
||
case cmdline.shift.upcase
|
||
when "ZONE"
|
||
return if cmdline.empty?
|
||
zone = cmdline.shift.downcase
|
||
dom = DnsDomain.new(zone)
|
||
unless dom.hosted?
|
||
result.message = _("This zone is not hosted here.")
|
||
return result
|
||
end
|
||
unless dom.managed_by? user
|
||
result.message = _("You are not allowed to manage this zone.")
|
||
return result
|
||
end
|
||
srv_dns = Services::DNS.new(zone)
|
||
|
||
if cmdline.empty?
|
||
result.message = _("No attachment number provided")
|
||
return result
|
||
end
|
||
|
||
zone_data = cmdline.shift
|
||
unless zone_data.content_type == "text/plain"
|
||
result.message = _("Zone data has wrong content-type.")
|
||
return result
|
||
end
|
||
|
||
f = Tempfile.new(zone)
|
||
f.write(zone_data.content)
|
||
f.close
|
||
logger.debug "Created temporary zone file '#{f.path}'"
|
||
|
||
srv_dns = Services::DNS.new(zone)
|
||
current_serial = srv_dns.serial
|
||
logger.debug "Current serial: #{current_serial}"
|
||
|
||
dns_result = srv_dns.check_zone_file(f.path)
|
||
unless dns_result.ok
|
||
result.message = _("Invalid zone data.")
|
||
f.close!
|
||
return result
|
||
end
|
||
logger.debug "New serial: #{dns_result.serial}"
|
||
# allow new serial or missing serial (to allow creating a new zone or replacing a broken zone)
|
||
unless current_serial.nil? or dns_result.serial > current_serial
|
||
result.message = _("Zone serial is not superior to current serial.")
|
||
f.close!
|
||
return result
|
||
end
|
||
|
||
begin
|
||
srv_dns.write_zone_from_file(f.path)
|
||
logger.debug "zone changed"
|
||
if srv_dns.reload_zone
|
||
logger.debug "zone reloaded"
|
||
result.ok = true
|
||
result.message = _("Zone updated.")
|
||
else
|
||
logger.warn "zone reload failed, replacing old content"
|
||
srv_dns.replace_zone_with_backup
|
||
result.message = _("Internal error. Administrator is warned.")
|
||
end
|
||
rescue
|
||
logger.warn "Writing zone file failed"
|
||
raise
|
||
ensure
|
||
f.close!
|
||
end
|
||
end
|
||
end
|
||
end
|
||
|
||
if result.message.nil?
|
||
# here fall lost souls
|
||
result.message = _("Command not recognized.")
|
||
end
|
||
end
|
||
end
|
||
end
|
po/cyborghood.pot | ||
---|---|---|
msgid ""
|
||
msgstr ""
|
||
"Project-Id-Version: CyborgHood 0.4.0\n"
|
||
"POT-Creation-Date: 2011-03-07 02:42+0100\n"
|
||
"POT-Creation-Date: 2011-03-08 01:13+0100\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"
|
||
... | ... | |
#: lib/cyborghood/order.rb:96
|
||
msgid "Syntax error in command."
|
||
msgstr ""
|
||
|
||
#: lib/cyborghood/command_runner.rb:46 lib/cyborghood/command_runner.rb:161
|
||
msgid "Internal error. Administrator is warned."
|
||
msgstr ""
|
||
|
||
#: lib/cyborghood/command_runner.rb:74
|
||
msgid "You are manager of the following zones: %{zone_list}."
|
||
msgstr ""
|
||
|
||
#: lib/cyborghood/command_runner.rb:84 lib/cyborghood/command_runner.rb:108
|
||
msgid "This zone is not hosted here."
|
||
msgstr ""
|
||
|
||
#: lib/cyborghood/command_runner.rb:88 lib/cyborghood/command_runner.rb:112
|
||
msgid "You are not allowed to manage this zone."
|
||
msgstr ""
|
||
|
||
#: lib/cyborghood/command_runner.rb:96
|
||
msgid "Requested zone content attached."
|
||
msgstr ""
|
||
|
||
#: lib/cyborghood/command_runner.rb:118
|
||
msgid "No attachment number provided"
|
||
msgstr ""
|
||
|
||
#: lib/cyborghood/command_runner.rb:124
|
||
msgid "Zone data has wrong content-type."
|
||
msgstr ""
|
||
|
||
#: lib/cyborghood/command_runner.rb:139
|
||
msgid "Invalid zone data."
|
||
msgstr ""
|
||
|
||
#: lib/cyborghood/command_runner.rb:146
|
||
msgid "Zone serial is not superior to current serial."
|
||
msgstr ""
|
||
|
||
#: lib/cyborghood/command_runner.rb:157
|
||
msgid "Zone updated."
|
||
msgstr ""
|
||
|
||
#: lib/cyborghood/command_runner.rb:175
|
||
msgid "Command not recognized."
|
||
msgstr ""
|
po/cyborghood_clerk.pot | ||
---|---|---|
msgid ""
|
||
msgstr ""
|
||
"Project-Id-Version: CyborgHood 0.4.0\n"
|
||
"POT-Creation-Date: 2011-03-07 02:42+0100\n"
|
||
"POT-Creation-Date: 2011-03-08 01:13+0100\n"
|
||
"PO-Revision-Date: 2011-03-07 02:39+0100\n"
|
||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||
... | ... | |
"Content-Transfer-Encoding: 8bit\n"
|
||
"Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n"
|
||
|
||
#: lib/cyborghood-clerk/interface/_commands/_dns/info.rb:30
|
||
#: lib/cyborghood-clerk/interface/_commands/_dns/info.rb:32
|
||
msgid "You do not manage any zone."
|
||
msgstr ""
|
||
|
||
#: lib/cyborghood-clerk/interface/_commands/_dns/info.rb:31
|
||
#: lib/cyborghood-clerk/interface/_commands/_dns/info.rb:33
|
||
msgid "You are manager of the following zones: %{zone_list}."
|
||
msgstr ""
|
po/cyborghood_mapmaker.pot | ||
---|---|---|
msgid ""
|
||
msgstr ""
|
||
"Project-Id-Version: CyborgHood 0.4.0\n"
|
||
"POT-Creation-Date: 2011-03-07 02:42+0100\n"
|
||
"POT-Creation-Date: 2011-03-08 01:13+0100\n"
|
||
"PO-Revision-Date: 2011-03-07 02:39+0100\n"
|
||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
po/cyborghood_postman.pot | ||
---|---|---|
msgid ""
|
||
msgstr ""
|
||
"Project-Id-Version: CyborgHood 0.4.0\n"
|
||
"POT-Creation-Date: 2011-03-07 02:42+0100\n"
|
||
"POT-Creation-Date: 2011-03-08 01:13+0100\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"
|
po/fr/cyborghood.po | ||
---|---|---|
msgid ""
|
||
msgstr ""
|
||
"Project-Id-Version: CyborgHood 0.4.0\n"
|
||
"POT-Creation-Date: 2011-03-07 02:42+0100\n"
|
||
"POT-Creation-Date: 2011-03-08 01:13+0100\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"
|
||
... | ... | |
msgid "Syntax error in command."
|
||
msgstr "Erreur de syntaxe dans la commande."
|
||
|
||
#: lib/cyborghood/command_runner.rb:46 lib/cyborghood/command_runner.rb:161
|
||
msgid "Internal error. Administrator is warned."
|
||
msgstr "Erreur interne. L'administrateur a été prévenu."
|
||
#~ msgid "Internal error. Administrator is warned."
|
||
#~ msgstr "Erreur interne. L'administrateur a été prévenu."
|
||
|
||
#: lib/cyborghood/command_runner.rb:74
|
||
msgid "You are manager of the following zones: %{zone_list}."
|
||
msgstr "Vous gérez les zones suivantes : %{zone_list}."
|
||
#~ msgid "You are manager of the following zones: %{zone_list}."
|
||
#~ msgstr "Vous gérez les zones suivantes : %{zone_list}."
|
||
|
||
#: lib/cyborghood/command_runner.rb:84 lib/cyborghood/command_runner.rb:108
|
||
msgid "This zone is not hosted here."
|
||
msgstr "Cette zone n'est pas hébergée ici."
|
||
#~ msgid "This zone is not hosted here."
|
||
#~ msgstr "Cette zone n'est pas hébergée ici."
|
||
|
||
#: lib/cyborghood/command_runner.rb:88 lib/cyborghood/command_runner.rb:112
|
||
msgid "You are not allowed to manage this zone."
|
||
msgstr "Vous n'êtes pas autorisé à gérer cette zone."
|
||
#~ msgid "You are not allowed to manage this zone."
|
||
#~ msgstr "Vous n'êtes pas autorisé à gérer cette zone."
|
||
|
||
#: lib/cyborghood/command_runner.rb:96
|
||
msgid "Requested zone content attached."
|
||
msgstr "Le contenu de la zone demandée est en pièce jointe."
|
||
#~ msgid "Requested zone content attached."
|
||
#~ msgstr "Le contenu de la zone demandée est en pièce jointe."
|
||
|
||
#: lib/cyborghood/command_runner.rb:118
|
||
msgid "No attachment number provided"
|
||
msgstr ""
|
||
|
||
#: lib/cyborghood/command_runner.rb:124
|
||
#, fuzzy
|
||
msgid "Zone data has wrong content-type."
|
||
msgstr "La pièce jointe a un mauvais type de contenu (content-type)."
|
||
#~ msgid "Zone data has wrong content-type."
|
||
#~ msgstr "La pièce jointe a un mauvais type de contenu (content-type)."
|
||
|
||
#: lib/cyborghood/command_runner.rb:139
|
||
msgid "Invalid zone data."
|
||
msgstr "Données pour la zone invalides."
|
||
#~ msgid "Invalid zone data."
|
||
#~ msgstr "Données pour la zone invalides."
|
||
|
||
#: lib/cyborghood/command_runner.rb:146
|
||
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."
|
||
#~ 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."
|
||
|
||
#: lib/cyborghood/command_runner.rb:157
|
||
msgid "Zone updated."
|
||
msgstr "Zone mise à jour."
|
||
#~ msgid "Zone updated."
|
||
#~ msgstr "Zone mise à jour."
|
||
|
||
#: lib/cyborghood/command_runner.rb:175
|
||
msgid "Command not recognized."
|
||
msgstr "Commande non reconnue."
|
||
#~ msgid "Command not recognized."
|
||
#~ msgstr "Commande non reconnue."
|
||
|
||
#~ msgid "Replay detected."
|
||
#~ msgstr "Rejeu détecté."
|
po/fr/cyborghood_clerk.po | ||
---|---|---|
msgid ""
|
||
msgstr ""
|
||
"Project-Id-Version: CyborgHood 0.4.0\n"
|
||
"POT-Creation-Date: 2011-03-07 02:42+0100\n"
|
||
"POT-Creation-Date: 2011-03-08 01:13+0100\n"
|
||
"PO-Revision-Date: 2011-03-07 02:39+0100\n"
|
||
"Last-Translator: Marc Dequènes (Duck) <Duck@DuckCorp.org>\n"
|
||
"MIME-Version: 1.0\n"
|
||
... | ... | |
"Content-Transfer-Encoding: 8bit\n"
|
||
"Plural-Forms: nplurals=2; plural=(n > 1);\n"
|
||
|
||
#: lib/cyborghood-clerk/interface/_commands/_dns/info.rb:30
|
||
#: lib/cyborghood-clerk/interface/_commands/_dns/info.rb:32
|
||
msgid "You do not manage any zone."
|
||
msgstr "Vous ne gérez aucune zone."
|
||
|
||
#: lib/cyborghood-clerk/interface/_commands/_dns/info.rb:31
|
||
#: lib/cyborghood-clerk/interface/_commands/_dns/info.rb:33
|
||
msgid "You are manager of the following zones: %{zone_list}."
|
||
msgstr "Vous êtes administrateur des zones suivantes : %{zone_list}."
|
po/fr/cyborghood_postman.po | ||
---|---|---|
msgid ""
|
||
msgstr ""
|
||
"Project-Id-Version: CyborgHood 0.4.0\n"
|
||
"POT-Creation-Date: 2011-03-07 02:42+0100\n"
|
||
"POT-Creation-Date: 2011-03-08 01:13+0100\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"
|
Also available in: Unified diff
[fix] I18n: late-translation fixes (core and Clerk only)