get_pomo 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
data/vendor/mofile.rb ADDED
@@ -0,0 +1,296 @@
1
+ =begin
2
+ mofile.rb - A simple class for operating GNU MO file.
3
+
4
+ Copyright (C) 2003-2008 Masao Mutoh
5
+ Copyright (C) 2002 Masahiro Sakai, Masao Mutoh
6
+ Copyright (C) 2001 Masahiro Sakai
7
+
8
+ Masahiro Sakai <s01397ms at sfc.keio.ac.jp>
9
+ Masao Mutoh <mutoh at highway.ne.jp>
10
+
11
+ You can redistribute this file and/or modify it under the same term
12
+ of Ruby. License of Ruby is included with Ruby distribution in
13
+ the file "README".
14
+
15
+ $Id: mo.rb,v 1.10 2008/06/17 16:40:52 mutoh Exp $
16
+ =end
17
+
18
+ require File.join(File.dirname(__FILE__),'iconv')
19
+ require 'stringio'
20
+
21
+ #Modifications:
22
+ # use Iconv or FastGettext::Icvon
23
+
24
+ module GetPomo
25
+ module GetText
26
+ class MOFile < Hash
27
+ class InvalidFormat < RuntimeError; end;
28
+
29
+ attr_reader :filename
30
+
31
+ Header = Struct.new(:magic,
32
+ :revision,
33
+ :nstrings,
34
+ :orig_table_offset,
35
+ :translated_table_offset,
36
+ :hash_table_size,
37
+ :hash_table_offset)
38
+
39
+ # The following are only used in .mo files
40
+ # with minor revision >= 1.
41
+ class HeaderRev1 < Header
42
+ attr_accessor :n_sysdep_segments,
43
+ :sysdep_segments_offset,
44
+ :n_sysdep_strings,
45
+ :orig_sysdep_tab_offset,
46
+ :trans_sysdep_tab_offset
47
+ end
48
+
49
+ MAGIC_BIG_ENDIAN = "\x95\x04\x12\xde"
50
+ MAGIC_LITTLE_ENDIAN = "\xde\x12\x04\x95"
51
+
52
+ def self.open(arg = nil, output_charset = nil)
53
+ result = self.new(output_charset)
54
+ result.load(arg)
55
+ end
56
+
57
+ def initialize(output_charset = nil)
58
+ @filename = nil
59
+ @last_modified = nil
60
+ @little_endian = true
61
+ @output_charset = output_charset
62
+ super()
63
+ end
64
+
65
+ def update!
66
+ if FileTest.exist?(@filename)
67
+ st = File.stat(@filename)
68
+ load(@filename) unless (@last_modified == [st.ctime, st.mtime])
69
+ else
70
+ warn "#{@filename} was lost." if $DEBUG
71
+ clear
72
+ end
73
+ self
74
+ end
75
+
76
+ def load(arg)
77
+ if arg.kind_of? String
78
+ begin
79
+ st = File.stat(arg)
80
+ @last_modified = [st.ctime, st.mtime]
81
+ rescue Exception
82
+ end
83
+ load_from_file(arg)
84
+ else
85
+ load_from_stream(arg)
86
+ end
87
+ @filename = arg
88
+ self
89
+ end
90
+
91
+ def load_from_stream(io)
92
+ magic = io.read(4)
93
+ case magic
94
+ when MAGIC_BIG_ENDIAN
95
+ @little_endian = false
96
+ when MAGIC_LITTLE_ENDIAN
97
+ @little_endian = true
98
+ else
99
+ raise InvalidFormat.new(sprintf("Unknown signature %s", magic.dump))
100
+ end
101
+
102
+ endian_type6 = @little_endian ? 'V6' : 'N6'
103
+ endian_type_astr = @little_endian ? 'V*' : 'N*'
104
+
105
+ header = HeaderRev1.new(magic, *(io.read(4 * 6).unpack(endian_type6)))
106
+
107
+ if header.revision == 1
108
+ # FIXME: It doesn't support sysdep correctly.
109
+ header.n_sysdep_segments = io.read(4).unpack(endian_type6)
110
+ header.sysdep_segments_offset = io.read(4).unpack(endian_type6)
111
+ header.n_sysdep_strings = io.read(4).unpack(endian_type6)
112
+ header.orig_sysdep_tab_offset = io.read(4).unpack(endian_type6)
113
+ header.trans_sysdep_tab_offset = io.read(4).unpack(endian_type6)
114
+ elsif header.revision > 1
115
+ raise InvalidFormat.new(sprintf("file format revision %d isn't supported", header.revision))
116
+ end
117
+ io.pos = header.orig_table_offset
118
+ orig_table_data = io.read((4 * 2) * header.nstrings).unpack(endian_type_astr)
119
+
120
+ io.pos = header.translated_table_offset
121
+ trans_table_data = io.read((4 * 2) * header.nstrings).unpack(endian_type_astr)
122
+
123
+ original_strings = Array.new(header.nstrings)
124
+ for i in 0...header.nstrings
125
+ io.pos = orig_table_data[i * 2 + 1]
126
+ original_strings[i] = io.read(orig_table_data[i * 2 + 0])
127
+ end
128
+
129
+ clear
130
+ for i in 0...header.nstrings
131
+ io.pos = trans_table_data[i * 2 + 1]
132
+ str = io.read(trans_table_data[i * 2 + 0])
133
+
134
+ if (! original_strings[i]) || original_strings[i] == ""
135
+ if str
136
+ @charset = nil
137
+ @nplurals = nil
138
+ @plural = nil
139
+ str.each_line{|line|
140
+ if /^Content-Type:/i =~ line and /charset=((?:\w|-)+)/i =~ line
141
+ @charset = $1
142
+ elsif /^Plural-Forms:\s*nplurals\s*\=\s*(\d*);\s*plural\s*\=\s*([^;]*)\n?/ =~ line
143
+ @nplurals = $1
144
+ @plural = $2
145
+ end
146
+ break if @charset and @nplurals
147
+ }
148
+ @nplurals = "1" unless @nplurals
149
+ @plural = "0" unless @plural
150
+ end
151
+ else
152
+ if @output_charset
153
+ begin
154
+ iconv = Iconv || FastGettext::Iconv
155
+ str = iconv.conv(@output_charset, @charset, str) if @charset
156
+ rescue iconv::Failure
157
+ if $DEBUG
158
+ warn "@charset = ", @charset
159
+ warn"@output_charset = ", @output_charset
160
+ warn "msgid = ", original_strings[i]
161
+ warn "msgstr = ", str
162
+ end
163
+ end
164
+ end
165
+ end
166
+ self[original_strings[i]] = str.freeze
167
+ end
168
+ self
169
+ end
170
+
171
+ # Is this number a prime number ?
172
+ # http://apidock.com/ruby/Prime
173
+ def prime?(number)
174
+ ('1' * number) !~ /^1?$|^(11+?)\1+$/
175
+ end
176
+
177
+ def next_prime(seed)
178
+ require 'mathn'
179
+ prime = Prime.new
180
+ while current = prime.succ
181
+ return current if current > seed
182
+ end
183
+ end
184
+
185
+ # From gettext-0.12.1/gettext-runtime/intl/hash-string.h
186
+ # Defines the so called `hashpjw' function by P.J. Weinberger
187
+ # [see Aho/Sethi/Ullman, COMPILERS: Principles, Techniques and Tools,
188
+ # 1986, 1987 Bell Telephone Laboratories, Inc.]
189
+ HASHWORDBITS = 32
190
+ def hash_string(str)
191
+ hval = 0
192
+ i = 0
193
+ str.each_byte do |b|
194
+ break if b == '\0'
195
+ hval <<= 4
196
+ hval += b.to_i
197
+ g = hval & (0xf << (HASHWORDBITS - 4))
198
+ if (g != 0)
199
+ hval ^= g >> (HASHWORDBITS - 8)
200
+ hval ^= g
201
+ end
202
+ end
203
+ hval
204
+ end
205
+
206
+ def save_to_stream(io)
207
+ #Save data as little endian format.
208
+ header_size = 4 * 7
209
+ table_size = 4 * 2 * size
210
+
211
+ hash_table_size = next_prime((size * 4) / 3)
212
+ hash_table_size = 3 if hash_table_size <= 2
213
+ header = Header.new(
214
+ MAGIC_LITTLE_ENDIAN, # magic
215
+ 0, # revision
216
+ size, # nstrings
217
+ header_size, # orig_table_offset
218
+ header_size + table_size, # translated_table_offset
219
+ hash_table_size, # hash_table_size
220
+ header_size + table_size * 2 # hash_table_offset
221
+ )
222
+ io.write(header.to_a.pack('a4V*'))
223
+
224
+ ary = to_a
225
+ ary.sort!{|a, b| a[0] <=> b[0]} # sort by original string
226
+
227
+ pos = header.hash_table_size * 4 + header.hash_table_offset
228
+
229
+ orig_table_data = Array.new()
230
+ ary.each{|item, _|
231
+ orig_table_data.push(item.size)
232
+ orig_table_data.push(pos)
233
+ pos += item.size + 1 # +1 is <NUL>
234
+ }
235
+ io.write(orig_table_data.pack('V*'))
236
+
237
+ trans_table_data = Array.new()
238
+ ary.each{|_, item|
239
+ trans_table_data.push(item.size)
240
+ trans_table_data.push(pos)
241
+ pos += item.size + 1 # +1 is <NUL>
242
+ }
243
+ io.write(trans_table_data.pack('V*'))
244
+
245
+ hash_tab = Array.new(hash_table_size)
246
+ j = 0
247
+ ary[0...size].each {|key, _|
248
+ hash_val = hash_string(key)
249
+ idx = hash_val % hash_table_size
250
+ if hash_tab[idx] != nil
251
+ incr = 1 + (hash_val % (hash_table_size - 2))
252
+ begin
253
+ if (idx >= hash_table_size - incr)
254
+ idx -= hash_table_size - incr
255
+ else
256
+ idx += incr
257
+ end
258
+ end until (hash_tab[idx] == nil)
259
+ end
260
+ hash_tab[idx] = j + 1
261
+ j += 1
262
+ }
263
+ hash_tab.collect!{|i| i ? i : 0}
264
+
265
+ io.write(hash_tab.pack('V*'))
266
+
267
+ ary.each{|item, _| io.write(item); io.write("\0") }
268
+ ary.each{|_, item| io.write(item); io.write("\0") }
269
+
270
+ self
271
+ end
272
+
273
+ def load_from_file(filename)
274
+ @filename = filename
275
+ begin
276
+ File.open(filename, 'rb'){|f| load_from_stream(f)}
277
+ rescue => e
278
+ e.set_backtrace("File: #{@filename}")
279
+ raise e
280
+ end
281
+ end
282
+
283
+ def save_to_file(filename)
284
+ File.open(filename, 'wb'){|f| save_to_stream(f)}
285
+ end
286
+
287
+ def set_comment(msgid_or_sym, comment)
288
+ #Do nothing
289
+ end
290
+
291
+
292
+ attr_accessor :little_endian, :path, :last_modified
293
+ attr_reader :charset, :nplurals, :plural
294
+ end
295
+ end
296
+ end
metadata ADDED
@@ -0,0 +1,82 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: get_pomo
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.6.0
5
+ platform: ruby
6
+ authors:
7
+ - Michael Grosser
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-11-20 00:00:00 +01:00
13
+ default_executable:
14
+ dependencies: []
15
+
16
+ description:
17
+ email: grosser.michael@gmail.com
18
+ executables: []
19
+
20
+ extensions: []
21
+
22
+ extra_rdoc_files:
23
+ - README.markdown
24
+ files:
25
+ - .gitignore
26
+ - README.markdown
27
+ - Rakefile
28
+ - VERSION
29
+ - get_pomo.gemspec
30
+ - lib/get_pomo.rb
31
+ - lib/get_pomo/mo_file.rb
32
+ - lib/get_pomo/po_file.rb
33
+ - lib/get_pomo/translation.rb
34
+ - prototype_treetop/po.treetop
35
+ - prototype_treetop/test.rb
36
+ - spec/files/complex.mo
37
+ - spec/files/empty.mo
38
+ - spec/files/plural.mo
39
+ - spec/files/singular.mo
40
+ - spec/files/singular_2.mo
41
+ - spec/pomo/mo_file_spec.rb
42
+ - spec/pomo/po_file_spec.rb
43
+ - spec/pomo/translation_spec.rb
44
+ - spec/pomo_spec.rb
45
+ - spec/spec_helper.rb
46
+ - vendor/README.rdoc
47
+ - vendor/iconv.rb
48
+ - vendor/mofile.rb
49
+ has_rdoc: true
50
+ homepage: http://github.com/grosser/get_pomo
51
+ licenses: []
52
+
53
+ post_install_message:
54
+ rdoc_options:
55
+ - --charset=UTF-8
56
+ require_paths:
57
+ - lib
58
+ required_ruby_version: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - ">="
61
+ - !ruby/object:Gem::Version
62
+ version: "0"
63
+ version:
64
+ required_rubygems_version: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: "0"
69
+ version:
70
+ requirements: []
71
+
72
+ rubyforge_project:
73
+ rubygems_version: 1.3.5
74
+ signing_key:
75
+ specification_version: 3
76
+ summary: "Ruby/Gettext: A .po and .mo file parser/generator"
77
+ test_files:
78
+ - spec/spec_helper.rb
79
+ - spec/pomo_spec.rb
80
+ - spec/pomo/translation_spec.rb
81
+ - spec/pomo/mo_file_spec.rb
82
+ - spec/pomo/po_file_spec.rb