i18n-translators-tools 0.1.1 → 0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.md +72 -22
- data/Rakefile +36 -3
- data/bin/i18n-translate +11 -68
- data/i18n-translators-tools.gemspec +44 -3
- data/lib/i18n-translate.rb +5 -0
- data/lib/i18n/backend/po.rb +20 -0
- data/lib/i18n/backend/properties.rb +19 -0
- data/lib/i18n/backend/translate.rb +2 -2
- data/lib/i18n/backend/ts.rb +19 -0
- data/lib/i18n/processor.rb +56 -1
- data/lib/i18n/processor/gettext.rb +63 -22
- data/lib/i18n/processor/properties.rb +78 -0
- data/lib/i18n/processor/ruby.rb +1 -1
- data/lib/i18n/processor/ts.rb +149 -0
- data/lib/i18n/processor/yaml.rb +2 -2
- data/lib/i18n/translate.rb +84 -69
- data/lib/i18n/translator.rb +76 -0
- data/test/all.rb +89 -0
- data/test/backend.rb +51 -0
- data/test/locale/src/cze.po +26 -0
- data/test/locale/src/cze.rb +24 -2
- data/test/locale/src/cze.yml +24 -6
- data/test/locale/src/deep/cze.yml +4 -0
- data/test/locale/src/deep/default.yml +4 -0
- data/test/locale/src/deep/eng.yml +4 -0
- data/test/locale/src/default.yml +14 -6
- data/test/processor.rb +42 -0
- data/test/tc_backend_po.rb +16 -0
- data/test/tc_backend_properties.rb +16 -0
- data/test/tc_backend_translate.rb +16 -0
- data/test/tc_backend_ts.rb +16 -0
- data/test/tc_i18n-translate.rb +128 -0
- data/test/tc_processor.rb +49 -0
- data/test/tc_processor_gettext.rb +15 -0
- data/test/tc_processor_properties.rb +35 -0
- data/test/tc_processor_ruby.rb +15 -0
- data/test/tc_processor_ts.rb +26 -0
- data/test/tc_processor_yaml.rb +15 -0
- data/test/tc_translate.rb +106 -87
- metadata +88 -19
@@ -20,9 +20,9 @@ module I18n
|
|
20
20
|
def translate(locale, key, options = {})
|
21
21
|
result = super(locale, key, options)
|
22
22
|
return result unless result.kind_of?(Hash)
|
23
|
-
return nil unless result[:t]
|
23
|
+
return nil unless result[:t] or result[:translation]
|
24
24
|
|
25
|
-
tr = result[:t]
|
25
|
+
tr = result[:translation] || result[:t]
|
26
26
|
values = options.except(*I18n::Backend::Base::RESERVED_KEYS)
|
27
27
|
|
28
28
|
tr = resolve(locale, key, tr, options)
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
# vi: fenc=utf-8:expandtab:ts=2:sw=2:sts=2
|
3
|
+
#
|
4
|
+
# @author: Petr Kovar <pejuko@gmail.com>
|
5
|
+
|
6
|
+
module I18n::Backend
|
7
|
+
|
8
|
+
# to use QT linguist TS files you should just include this backend
|
9
|
+
#
|
10
|
+
# I18n::Backend::Simple.send(:include, I18n::Backend::TS)
|
11
|
+
module TS
|
12
|
+
protected
|
13
|
+
def load_ts(fname)
|
14
|
+
locale = ::File.basename(fname, '.ts')
|
15
|
+
tr = I18n::Translate::Translate.new(locale, {:empty => true})
|
16
|
+
data = I18n::Translate::Processor::TS.new(fname, tr).read
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
data/lib/i18n/processor.rb
CHANGED
@@ -37,6 +37,12 @@ module I18n::Translate
|
|
37
37
|
nil
|
38
38
|
end
|
39
39
|
|
40
|
+
def self.init(default='yml')
|
41
|
+
@processors.each do |processor|
|
42
|
+
processor.register(default)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
40
46
|
|
41
47
|
class Template
|
42
48
|
FORMAT = []
|
@@ -50,6 +56,21 @@ module I18n::Translate
|
|
50
56
|
def initialize(fname, tr)
|
51
57
|
@filename = fname
|
52
58
|
@translate = tr
|
59
|
+
fname =~ %r{/?([^/]+)\.[^\.]+$}i
|
60
|
+
@lang = $1.to_s.strip
|
61
|
+
end
|
62
|
+
|
63
|
+
def self.register(default='yml')
|
64
|
+
self::FORMAT.each do |format|
|
65
|
+
unless I18n::Translate::FORMATS.include?(format)
|
66
|
+
# default format will be first
|
67
|
+
if default == format
|
68
|
+
I18n::Translate::FORMATS.unshift(format)
|
69
|
+
else
|
70
|
+
I18n::Translate::FORMATS << format
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
53
74
|
end
|
54
75
|
|
55
76
|
def read
|
@@ -68,7 +89,7 @@ module I18n::Translate
|
|
68
89
|
end
|
69
90
|
|
70
91
|
def self.can_handle?(fname)
|
71
|
-
fname =~ %r{\.([^\.]+)$}
|
92
|
+
fname =~ %r{\.([^\.]+)$}i
|
72
93
|
self::FORMAT.include?($1)
|
73
94
|
end
|
74
95
|
|
@@ -82,6 +103,35 @@ module I18n::Translate
|
|
82
103
|
data
|
83
104
|
end
|
84
105
|
|
106
|
+
def uninspect(str)
|
107
|
+
return nil unless str
|
108
|
+
str.gsub(%r!\\([\\#"abefnrstvx]|u\d{4}|u\{[^\}]+\}|\d{1,3}|x\d{1,2}|cx|C-[a-zA-Z]|M-[a-zA-Z])!) do |m|
|
109
|
+
repl = ""
|
110
|
+
if ['\\', '#', '"'].include?($1)
|
111
|
+
repl = $1
|
112
|
+
else
|
113
|
+
repl = eval("\"\\#{$1}\"")
|
114
|
+
end
|
115
|
+
repl
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
# convert old and shorthand fields
|
120
|
+
def migrate(data)
|
121
|
+
keys = I18n::Translate.hash_to_keys(data, @translate.options[:separator])
|
122
|
+
keys.each do |key|
|
123
|
+
k, prop = $1, $2 if key =~ /(.*)\.([^\.]+)$/
|
124
|
+
next unless prop or k
|
125
|
+
next unless ["old", "t"].include?(prop)
|
126
|
+
entry = I18n::Translate.find(k, data, @translate.options[:separator])
|
127
|
+
value = entry.delete(prop)
|
128
|
+
prop = (prop == "old") ? "old_default" : "translation"
|
129
|
+
entry[prop] = value
|
130
|
+
I18n::Translate.set(k, entry, data, @translate.options[:separator])
|
131
|
+
end
|
132
|
+
data
|
133
|
+
end
|
134
|
+
|
85
135
|
def mode(m)
|
86
136
|
mode = m.dup
|
87
137
|
mode << ":" << @translate.options[:encoding] if defined?(Encoding)
|
@@ -96,4 +146,9 @@ end
|
|
96
146
|
require 'i18n/processor/yaml'
|
97
147
|
require 'i18n/processor/ruby'
|
98
148
|
require 'i18n/processor/gettext'
|
149
|
+
require 'i18n/processor/ts'
|
150
|
+
require 'i18n/processor/properties'
|
151
|
+
|
99
152
|
|
153
|
+
# initialize all registred processors
|
154
|
+
I18n::Translate::Processor.init
|
@@ -6,7 +6,7 @@
|
|
6
6
|
module I18n::Translate::Processor
|
7
7
|
|
8
8
|
class Gettext < Template
|
9
|
-
FORMAT = ['po']
|
9
|
+
FORMAT = ['po', 'pot']
|
10
10
|
|
11
11
|
protected
|
12
12
|
|
@@ -20,6 +20,7 @@ module I18n::Translate::Processor
|
|
20
20
|
# empty line starts new entry
|
21
21
|
if line =~ %r{^\s*$}
|
22
22
|
if not entry.empty? and key
|
23
|
+
key = entry["default"].dup unless key
|
23
24
|
I18n::Translate.set(key, entry, hash, @translate.options[:separator])
|
24
25
|
end
|
25
26
|
key = nil
|
@@ -34,9 +35,17 @@ module I18n::Translate::Processor
|
|
34
35
|
when %r{^# (.*)$}
|
35
36
|
entry["comment"] = $1.to_s.strip
|
36
37
|
|
37
|
-
#
|
38
|
+
# extracted comment
|
39
|
+
when %r{^#\. (.*)$}
|
40
|
+
entry["extracted_comment"] = $1.to_s.strip
|
41
|
+
|
42
|
+
# reference
|
38
43
|
when %r{^#: (.*)$}
|
39
|
-
entry["
|
44
|
+
entry["reference"] = $1.to_s.strip
|
45
|
+
if entry["reference"] =~ %r{^(.*):(\d+)$}
|
46
|
+
entry["file"] = $1.to_s.strip
|
47
|
+
entry["line"] = $2.to_s.strip
|
48
|
+
end
|
40
49
|
|
41
50
|
# flag
|
42
51
|
when %r{^#, (.*)$}
|
@@ -47,34 +56,52 @@ module I18n::Translate::Processor
|
|
47
56
|
else
|
48
57
|
flags.delete_if{|x| not I18n::Translate::FLAGS.include?(x)}
|
49
58
|
entry["flag"] = flags.first unless flags.empty?
|
59
|
+
entry["fuzzy"] = true
|
50
60
|
end
|
51
61
|
|
52
62
|
# old default
|
53
|
-
when %r{^#\| msgid (.*)$}
|
54
|
-
entry["
|
63
|
+
when %r{^#\| msgid "(.*)"$}
|
64
|
+
entry["old_default"] = $1.to_s
|
65
|
+
# expect that this entry has no key
|
66
|
+
# if does, will be overwriten later
|
67
|
+
key = entry["old_default"].dup
|
55
68
|
|
56
|
-
# key
|
69
|
+
# key (context)
|
57
70
|
when %r{^msgctxt "(.*)"$}
|
58
71
|
key = $1.to_s.strip
|
59
72
|
last = "key"
|
60
73
|
|
61
74
|
# default
|
62
75
|
when %r{^msgid "(.*)"$}
|
63
|
-
|
64
|
-
|
76
|
+
if $1.to_s.strip.empty?
|
77
|
+
last = "po-header"
|
78
|
+
else
|
79
|
+
last = "default"
|
80
|
+
entry[last] = uninspect($1.to_s)
|
81
|
+
key = entry[last].dup unless key
|
82
|
+
end
|
65
83
|
|
66
84
|
# translation
|
67
85
|
when %r{^msgstr "(.*)"$}
|
68
|
-
last = "
|
69
|
-
entry[last] = $1.to_s
|
86
|
+
last = "translation" unless last == "po-header"
|
87
|
+
entry[last] = uninspect($1.to_s)
|
70
88
|
|
71
89
|
# string continuation
|
72
90
|
when %r{^"(.*)"$}
|
73
91
|
if last == "key"
|
74
|
-
key = "#{key}#{$1
|
92
|
+
key = "#{key}#{$1}"
|
93
|
+
elsif last == "po-header"
|
94
|
+
case $1
|
95
|
+
when %r{^Content-Type: text/plain; charset=(.*)$}
|
96
|
+
enc = uninspect($1.to_s).strip
|
97
|
+
@translate.options[:encoding] = enc unless enc.empty?
|
98
|
+
when %r{^X-Language: (.*)$}
|
99
|
+
# skip language is set from filename
|
100
|
+
end
|
75
101
|
elsif last
|
76
|
-
entry[last] = "#{entry[last]}#{$1
|
102
|
+
entry[last] = "#{entry[last]}#{uninspect($1)}"
|
77
103
|
end
|
104
|
+
|
78
105
|
end
|
79
106
|
end
|
80
107
|
|
@@ -87,31 +114,45 @@ module I18n::Translate::Processor
|
|
87
114
|
end
|
88
115
|
|
89
116
|
|
90
|
-
# this export ignores data
|
91
117
|
def export(data)
|
118
|
+
target = data[@translate.lang]
|
92
119
|
str = ""
|
93
120
|
keys = I18n::Translate.hash_to_keys(@translate.default).sort
|
94
121
|
|
122
|
+
str << %~msgid ""\n~
|
123
|
+
str << %~msgstr ""\n~
|
124
|
+
str << %~"Content-Type: text/plain; charset=#{@translate.options[:encoding]}\\n"\n~
|
125
|
+
str << %~"X-Language: #{@translate.lang}\\n"\n~
|
95
126
|
keys.each do |key|
|
96
127
|
entry = [""]
|
97
|
-
value = @translate.find(key,
|
128
|
+
value = @translate.find(key, target)
|
98
129
|
next unless value
|
99
130
|
|
100
131
|
if value.kind_of?(String)
|
101
|
-
|
102
|
-
|
132
|
+
# leave out msgctxt if using po strings as a key
|
133
|
+
default = @translate.find(key, @translate.default)
|
134
|
+
entry << %~msgctxt #{key.inspect}~ if key != default
|
135
|
+
entry << %~msgid #{default.to_s.inspect}~
|
103
136
|
entry << %~msgstr #{value.to_s.inspect}~
|
104
137
|
else
|
105
|
-
entry << %~# #{value["comment"]}~ unless value["comment"].to_s.empty?
|
106
|
-
entry <<
|
138
|
+
entry << %~# #{value["comment"].to_s.strip}~ unless value["comment"].to_s.strip.empty?
|
139
|
+
entry << %~#. #{value["extracted_comment"].to_s.strip}~ unless value["extracted_comment"].to_s.strip.empty?
|
140
|
+
if not value["reference"].to_s.strip.empty?
|
141
|
+
entry << %~#: #{value["reference"].to_s.strip}~
|
142
|
+
elsif value["file"] or value["line"]
|
143
|
+
entry << %~#: #{value["file"].to_s.strip}:#{value["line"].to_s.strip}~
|
144
|
+
end
|
145
|
+
key_default = nil
|
146
|
+
key_default = value["default"] if value["default"] == key
|
147
|
+
key_default = value["old_default"] if value["old_default"] == key
|
107
148
|
flags = []
|
108
|
-
flags << "fuzzy" if value["
|
149
|
+
flags << "fuzzy" if (not value["flag"].nil?) and (value["flag"] != "ok")
|
109
150
|
flags << value["flag"] unless value["flag"].to_s.strip.empty?
|
110
151
|
entry << %~#, #{flags.join(", ")}~ unless flags.empty?
|
111
|
-
entry << %~#| msgid #{value["
|
112
|
-
entry << %~msgctxt #{key.inspect}~
|
152
|
+
entry << %~#| msgid #{value["old_default"].to_s.inspect}~ unless value["old_default"].to_s.empty?
|
153
|
+
entry << %~msgctxt #{key.inspect}~ if key != key_default
|
113
154
|
entry << %~msgid #{value["default"].to_s.inspect}~
|
114
|
-
entry << %~msgstr #{value["
|
155
|
+
entry << %~msgstr #{value["translation"].to_s.inspect}~
|
115
156
|
end
|
116
157
|
|
117
158
|
entry << ""
|
@@ -0,0 +1,78 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
# vi: fenc=utf-8:expandtab:ts=2:sw=2:sts=2
|
3
|
+
#
|
4
|
+
# @author: Petr Kovar <pejuko@gmail.com>
|
5
|
+
|
6
|
+
module I18n::Translate::Processor
|
7
|
+
|
8
|
+
class Properties < Template
|
9
|
+
FORMAT = ['properties']
|
10
|
+
|
11
|
+
protected
|
12
|
+
|
13
|
+
def import(data)
|
14
|
+
hash = {}
|
15
|
+
|
16
|
+
key = nil
|
17
|
+
value = nil
|
18
|
+
line_number = 0
|
19
|
+
data.each_line do |line|
|
20
|
+
line_number += 1
|
21
|
+
# skip empty line and comments
|
22
|
+
next if (line =~ %r{^\s*$}) or (line =~ %r{^#.*})
|
23
|
+
|
24
|
+
case line
|
25
|
+
# multiline string
|
26
|
+
when %r{^([^=]+)\s*=\s*(.*)\\$}
|
27
|
+
key = $1.to_s.strip
|
28
|
+
value = $2.to_s.strip
|
29
|
+
|
30
|
+
# continuous multiline string
|
31
|
+
when %r{^\s*([^=]+)\\$}
|
32
|
+
value << $1.to_s.strip
|
33
|
+
|
34
|
+
# end of continuous string
|
35
|
+
when %r{^\s*([^=]+)$}
|
36
|
+
value << $1.to_s.strip
|
37
|
+
I18n::Translate.set(key, uninspect(value), hash, @translate.options[:separator])
|
38
|
+
value = nil
|
39
|
+
|
40
|
+
# simple key = value
|
41
|
+
when %r{^([^=]+)\s*=\s*(.*)$}
|
42
|
+
key, value = $1.to_s.strip, $2.to_s.strip
|
43
|
+
I18n::Translate.set(key, uninspect(value), hash, @translate.options[:separator])
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
{@lang => hash}
|
48
|
+
end
|
49
|
+
|
50
|
+
|
51
|
+
# this export ignores data
|
52
|
+
def export(data)
|
53
|
+
target = data[@translate.lang]
|
54
|
+
str = ""
|
55
|
+
keys = I18n::Translate.hash_to_keys(@translate.default).sort
|
56
|
+
|
57
|
+
keys.each do |key|
|
58
|
+
value = @translate.find(key, target)
|
59
|
+
next unless value
|
60
|
+
entry = ""
|
61
|
+
|
62
|
+
|
63
|
+
if value.kind_of?(String)
|
64
|
+
entry = value.strip
|
65
|
+
else
|
66
|
+
entry = value["translation"].to_s.strip
|
67
|
+
end
|
68
|
+
|
69
|
+
# create record in format: key = value
|
70
|
+
str << key << " = " << entry.gsub("\n", "\\n") << "\n"
|
71
|
+
end
|
72
|
+
|
73
|
+
str
|
74
|
+
end
|
75
|
+
|
76
|
+
end
|
77
|
+
|
78
|
+
end
|
data/lib/i18n/processor/ruby.rb
CHANGED
@@ -0,0 +1,149 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
# vi: fenc=utf-8:expandtab:ts=2:sw=2:sts=2
|
3
|
+
#
|
4
|
+
# @author: Petr Kovar <pejuko@gmail.com>
|
5
|
+
|
6
|
+
require 'rexml/document'
|
7
|
+
require 'cgi'
|
8
|
+
|
9
|
+
module I18n::Translate::Processor
|
10
|
+
|
11
|
+
class TS < Template
|
12
|
+
FORMAT = ['ts']
|
13
|
+
|
14
|
+
protected
|
15
|
+
|
16
|
+
def get(xml, path, key=nil)
|
17
|
+
elements = []
|
18
|
+
xml.elements.each(path) {|e| elements << e}
|
19
|
+
element = elements.first
|
20
|
+
ret = ""
|
21
|
+
ret = element.get_text.to_s if element and not key
|
22
|
+
ret = element.attributes[key].to_s.strip if element and key
|
23
|
+
ret.gsub!("'", "'")
|
24
|
+
ret = uninspect(::CGI::unescapeHTML(ret))
|
25
|
+
ret
|
26
|
+
end
|
27
|
+
|
28
|
+
def import(data)
|
29
|
+
hash = {}
|
30
|
+
xml = ::REXML::Document.new(data)
|
31
|
+
lang = @translate.lang
|
32
|
+
lang = get(xml, "TS", "language").to_s.strip if lang.empty?
|
33
|
+
xml.elements.each("//TS/context") do |context|
|
34
|
+
key = get(context, "name")
|
35
|
+
context.elements.each("message") do |message|
|
36
|
+
entry = {}
|
37
|
+
entry["file"] = get(message, "location", "filename").to_s.strip
|
38
|
+
entry["line"] = get(message, "location", "line").to_s.strip
|
39
|
+
unless entry["file"].empty? or entry["line"].empty?
|
40
|
+
entry["reference"] = "#{entry['file']}:#{entry['line']}"
|
41
|
+
end
|
42
|
+
if key.to_s.strip.empty?
|
43
|
+
# this happen if you use linguist on converting po to ts
|
44
|
+
# context is saved as a comment
|
45
|
+
key = get(message, "comment").to_s.strip
|
46
|
+
# if converted from po using linguist, there is one message
|
47
|
+
# without key
|
48
|
+
#raise "No key for message: #{message.to_s}" if key.empty?
|
49
|
+
end
|
50
|
+
entry["default"] = get(message, "source")
|
51
|
+
entry["old_default"] = get(message, "oldsource")
|
52
|
+
entry["extracted_comment"] = get(message, "extracomment").to_s.strip
|
53
|
+
entry["comment"] = get(message, "translatorcomment").to_s.strip
|
54
|
+
entry["translation"] = get(message, "translation")
|
55
|
+
fuzzy = get(message, "translation", "type").to_s.strip
|
56
|
+
entry["fuzzy"] = true unless fuzzy.empty?
|
57
|
+
flag = get(message, "extra-po-flags").to_s.strip
|
58
|
+
entry["flag"] = flag unless flag.empty?
|
59
|
+
entry.delete_if {|k,v| v.to_s.empty?}
|
60
|
+
if key
|
61
|
+
# not key means it can be header of po file converted to ts
|
62
|
+
I18n::Translate.set(key, entry, hash, @translate.options[:separator])
|
63
|
+
end
|
64
|
+
key = nil
|
65
|
+
end
|
66
|
+
end
|
67
|
+
{lang => hash}
|
68
|
+
end
|
69
|
+
|
70
|
+
|
71
|
+
# serialize hash to XML
|
72
|
+
def export(data, indent=0)
|
73
|
+
target = data[@translate.lang]
|
74
|
+
xml = <<EOF
|
75
|
+
<?xml version="1.0" encoding="#{@translate.options[:encoding]}"?>
|
76
|
+
<!DOCTYPE TS>
|
77
|
+
<TS version="2.0" language="#{@translate.lang}">
|
78
|
+
EOF
|
79
|
+
|
80
|
+
keys = I18n::Translate.hash_to_keys(@translate.default).sort
|
81
|
+
keys.each do |key|
|
82
|
+
value = @translate.find(key, target)
|
83
|
+
next unless value
|
84
|
+
|
85
|
+
if value.kind_of?(String)
|
86
|
+
fuzzy = (value.to_s.empty?) ? %~ type="unfinished"~ : ""
|
87
|
+
xml += <<EOF
|
88
|
+
<context>
|
89
|
+
<name>#{::CGI.escapeHTML(key)}</name>
|
90
|
+
<message>
|
91
|
+
<source>#{::CGI.escapeHTML(@translate.find(key, @translate.default).to_s)}</source>
|
92
|
+
<translation#{fuzzy}>#{::CGI.escapeHTML(value.to_s)}</translation>
|
93
|
+
</message>
|
94
|
+
</context>
|
95
|
+
EOF
|
96
|
+
else
|
97
|
+
fuzzy = ((value["flag"] == "ok") or value["flag"].to_s.strip.empty?) ? "" : %~ type="unfinished"~
|
98
|
+
xml += <<EOF
|
99
|
+
<context>
|
100
|
+
<name>#{::CGI.escapeHTML(key)}</name>
|
101
|
+
<message>
|
102
|
+
EOF
|
103
|
+
if value["file"] or value["line"]
|
104
|
+
xml += <<EOF
|
105
|
+
<location filename="#{::CGI.escapeHTML(value["file"].to_s)}" line="#{::CGI.escapeHTML(value["line"].to_s)}" />
|
106
|
+
EOF
|
107
|
+
end
|
108
|
+
xml += <<EOF
|
109
|
+
<source>#{::CGI.escapeHTML(value["default"].to_s)}</source>
|
110
|
+
EOF
|
111
|
+
unless value["old_default"].to_s.empty?
|
112
|
+
xml += <<EOF
|
113
|
+
<oldsource>#{::CGI.escapeHTML(value["old_default"].to_s)}</oldsource>
|
114
|
+
EOF
|
115
|
+
end
|
116
|
+
unless value["extracted_comment"].to_s.empty?
|
117
|
+
xml += <<EOF
|
118
|
+
<extracomment>#{::CGI.escapeHTML(value["extracted_comment"].to_s)}</extracomment>
|
119
|
+
EOF
|
120
|
+
end
|
121
|
+
unless value["comment"].to_s.empty?
|
122
|
+
xml += <<EOF
|
123
|
+
<translatorcomment>#{::CGI.escapeHTML(value["comment"].to_s)}</translatorcomment>
|
124
|
+
EOF
|
125
|
+
end
|
126
|
+
xml += <<EOF
|
127
|
+
<translation#{fuzzy}>#{::CGI.escapeHTML(value["translation"].to_s)}</translation>
|
128
|
+
EOF
|
129
|
+
unless value["flag"].to_s.strip.empty?
|
130
|
+
xml += <<EOF
|
131
|
+
<extra-po-flags>#{::CGI.escapeHTML(value["flag"].to_s.strip)}</extra-po-flags>
|
132
|
+
EOF
|
133
|
+
end
|
134
|
+
xml += <<EOF
|
135
|
+
</message>
|
136
|
+
</context>
|
137
|
+
EOF
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
xml += <<EOF
|
142
|
+
</TS>
|
143
|
+
EOF
|
144
|
+
xml
|
145
|
+
end
|
146
|
+
|
147
|
+
end
|
148
|
+
|
149
|
+
end
|