zlocalize 4.1.0

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.
@@ -0,0 +1,248 @@
1
+ # -*- encoding : utf-8 -*-
2
+
3
+ # Memory representation of a list of translation strings in a given language
4
+ # Reads and writes each entry with a list of references to occurences in source files.
5
+
6
+ require 'yaml'
7
+
8
+ module ZLocalize
9
+
10
+ def self.escape_ruby_string(s)
11
+ s2 = s.to_s.dup
12
+ # s2.gsub!("'","\\\\'") # no need to escape single quotes, since we will be writing only double-quoted strings
13
+ s2.gsub!("\"","\\\"")
14
+ s2.gsub!("\r\n","\n")
15
+ s2.gsub!("\n\r","\n")
16
+ s2.gsub!("\n","\\n")
17
+ s2
18
+ end
19
+
20
+ def self.unescape_ruby_string(s)
21
+ s2 = s.to_s
22
+ s2.gsub!("\\'","'")
23
+ s2.gsub!('\\"','"')
24
+ s2.gsub!("\\n","\n")
25
+ s2.gsub("\\","")
26
+ s2
27
+ end
28
+
29
+ def self.clean_ruby_string(s)
30
+ s2 = s.to_s
31
+ if s2.size > 1
32
+ # remove single or double quotes
33
+ if (s2[0] == '"' && s2[s2.size-1] == '"') || (s2[0] == "'" && s2[s2.size-1] == "'")
34
+ s2 = s2[1..s2.size-2].to_s
35
+ end
36
+ end
37
+ unescape_ruby_string(s2)
38
+ end
39
+
40
+ class TranslationFileError < StandardError; end
41
+
42
+ class TranslationEntry #:nodoc: all
43
+ attr_accessor :plural
44
+ attr_accessor :source
45
+ attr_accessor :translation
46
+ attr_accessor :references
47
+ attr_accessor :id
48
+ attr_accessor :ignore
49
+
50
+ def initialize(opts = {})
51
+ # opts = HashWithIndifferentAccess.new(opts)
52
+ @plural = opts['plural']
53
+ @source = opts['source']
54
+ @translation = opts['translation']
55
+ @references = opts['references']
56
+ @id = opts['id']
57
+ @ignore = opts['ignore']
58
+ end
59
+
60
+ def add_reference(ref)
61
+ @references << ref unless @references.include?(ref)
62
+ end
63
+
64
+ def synchronize_references(entry)
65
+ # first, remove references that are not present for other entry
66
+ @references.delete_if { |ref| !entry.references.include?(ref) }
67
+ # add all references from other entry (duplicates are avoided)
68
+ entry.references.each { |ref| add_reference(ref) }
69
+ end
70
+
71
+ def to_yaml
72
+ # write YAML ourselves, to allow UTF-8 strings as they are
73
+ out = "entry_#{sprintf('%0.6d',id.to_i)}:\n" +
74
+ " id: #{@id}\n" +
75
+ " ignore: #{@ignore ? 'true' : 'false'}\n" +
76
+ " plural: #{@plural ? 'true' : 'false'}\n" +
77
+ " references:\n" +
78
+ @references.map { |r| " - #{r}" }.join("\n") + "\n" +
79
+ " source: #{data_to_yaml(@source)}\n" +
80
+ " translation: #{data_to_yaml(@translation)}\n"
81
+ out.force_encoding("UTF-8")
82
+ end
83
+
84
+ def data_to_yaml(data)
85
+ if data.nil?
86
+ nil
87
+ elsif data.is_a?(Array)
88
+ "\n" + data.map { |el| " - \"#{ZLocalize.escape_ruby_string(el)}\"" }.join("\n")
89
+ else
90
+ "\"#{ZLocalize.escape_ruby_string(data)}\""
91
+ end
92
+ end
93
+
94
+ end
95
+
96
+
97
+ class TranslationEntryCollection < Hash #:nodoc: all
98
+
99
+ def add_entry(key,ref)
100
+ if entry = self[key]
101
+ entry.add_reference(ref)
102
+ else
103
+ entry = TranslationEntry.new(:source => key, :references => [ref], :translation => nil)
104
+ self[key] = entry
105
+ end
106
+ entry
107
+ end
108
+
109
+ def synchronize_with(collection, purge = false)
110
+ if purge
111
+ # first, remove our entries that are not present in the other collection
112
+ self.delete_if { |key,entry| !collection.key?(key) }
113
+ end
114
+ # add entries from the other collection that are not already in this collection
115
+ collection.each do |key,entry|
116
+ if self.key?(key)
117
+ self[key].synchronize_references(entry)
118
+ else
119
+ self[key] = entry
120
+ end
121
+ end
122
+ end
123
+
124
+ # return an Array of entries, sorted by id
125
+ def sort_by_id
126
+ # Hash#sort will convert each item to an Array of 2 elements [key, value]
127
+ sort { |entry1,entry2| entry1[1].id.to_i <=> entry2[1].id.to_i }.collect { |el| el[1] }
128
+ end
129
+
130
+ end
131
+
132
+
133
+ class TranslationFile #:nodoc: all
134
+
135
+ attr_accessor :entries
136
+
137
+ # regex to match Revision line
138
+ REGEX_REVISION = /^#\s*Revision:\s+([0-9]+)/i
139
+
140
+ # regex to match an entry delimiter
141
+ REGEX_ENTRY = /^#\s*entry\s+([0-9]+)/
142
+
143
+ # regex to match file and line number references for an entry
144
+ REGEX_FILE_REF = /^#\s*file:\s+(.*?)\s*,\s*line\s+([0-9]{1,6})/
145
+
146
+ # regex to match an optional # IGNORE line indicating that entry should be ignored
147
+ REGEX_IGNORE_ENTRY = /^#\s*IGNORE/
148
+
149
+ def self.load(file_name)
150
+ f = new
151
+ f.load(file_name)
152
+ f
153
+ end
154
+
155
+ def initialize
156
+ @entries = TranslationEntryCollection.new
157
+ end
158
+
159
+ def revision
160
+ @revision.to_i > 0 ? @revision + 1 : 1
161
+ end
162
+
163
+ def list_entries
164
+ @entries.each do |e|
165
+ puts e.inspect
166
+ puts "\n"
167
+ end
168
+ end
169
+
170
+ def clear_entries
171
+ @entries.clear
172
+ end
173
+
174
+ def add_entry(key,ref)
175
+ @entries.add_entry(key,ref)
176
+ end
177
+
178
+ def synchronize_with(translation_file)
179
+ @entries.synchronize_with(translation_file.entries)
180
+ end
181
+
182
+ def get_max_entry_id
183
+ max_id = 0
184
+ @entries.values.each do |e|
185
+ max_id = e.id.to_i if e.id.to_i > max_id
186
+ end
187
+ max_id
188
+ end
189
+
190
+ def ensure_entry_ids
191
+ next_id = get_max_entry_id + 1
192
+ @entries.values.each do |e|
193
+ unless e.id.to_i > 0
194
+ e.id = next_id
195
+ next_id += 1
196
+ end
197
+ end
198
+ end
199
+
200
+ def load(filename)
201
+ if File.exists?(filename)
202
+ content = File.open(filename,"r") { |f| f.read }
203
+ read_yaml_header(content)
204
+ entries = YAML::load(content)
205
+ if entries && !entries.is_a?(Hash)
206
+ raise TranslationFileError.new("Invalid YAML translation file #{filename}\n\n#{entries.inspect}")
207
+ end
208
+ else
209
+ raise TranslationFileError.new("Specified translation file does not exist: #{filename}")
210
+ end
211
+ entries ||= {}
212
+ @entries.clear
213
+ entries.each_pair do |k,entry|
214
+ @entries[entry['source']] = TranslationEntry.new(entry)
215
+ end
216
+ end
217
+
218
+ def read_yaml_header(content)
219
+ re = /#\s*Revision:\s+([0-9]+)/i
220
+ if m = re.match(content)
221
+ @revision = m[1].to_i
222
+ else
223
+ @revision = 0
224
+ end
225
+ end
226
+
227
+ def output_header
228
+ out = "# Generated on: #{Time.now.strftime('%Y/%m/%d %H:%M')}\n"
229
+ out << "# Revision: #{revision}\n\n"
230
+ out
231
+ end
232
+
233
+ def to_yaml
234
+ ensure_entry_ids
235
+ out = output_header
236
+ @entries.sort_by_id.each do |e|
237
+ out << e.to_yaml
238
+ out << "\n"
239
+ end
240
+ out
241
+ end
242
+
243
+ def non_translated_entries
244
+ @entries.sort_by_id.collect { |e| e.translation.to_s.strip == "" }
245
+ end
246
+
247
+ end # class TranlationFile
248
+ end # module ZLocalize
data/lib/zlocalize.rb ADDED
@@ -0,0 +1,9 @@
1
+ # -*- encoding : utf-8 -*-
2
+
3
+ zlocalize_path = File.expand_path(File.dirname(__FILE__))
4
+ $:.unshift(zlocalize_path) if File.directory?(zlocalize_path) && !$:.include?(zlocalize_path)
5
+
6
+ require 'active_support/core_ext/string/output_safety'
7
+ require 'zlocalize/rails/railtie' # hook into Rails framework
8
+ require 'zlocalize/backend'
9
+
metadata ADDED
@@ -0,0 +1,117 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: zlocalize
3
+ version: !ruby/object:Gem::Version
4
+ version: 4.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Charles Bedard
8
+ - Stephane Volet
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2015-03-02 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: activerecord
16
+ requirement: !ruby/object:Gem::Requirement
17
+ requirements:
18
+ - - '>='
19
+ - !ruby/object:Gem::Version
20
+ version: 4.1.0
21
+ type: :runtime
22
+ prerelease: false
23
+ version_requirements: !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - '>='
26
+ - !ruby/object:Gem::Version
27
+ version: 4.1.0
28
+ - !ruby/object:Gem::Dependency
29
+ name: activesupport
30
+ requirement: !ruby/object:Gem::Requirement
31
+ requirements:
32
+ - - '>='
33
+ - !ruby/object:Gem::Version
34
+ version: 4.1.0
35
+ type: :runtime
36
+ prerelease: false
37
+ version_requirements: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - '>='
40
+ - !ruby/object:Gem::Version
41
+ version: 4.1.0
42
+ - !ruby/object:Gem::Dependency
43
+ name: actionpack
44
+ requirement: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - '>='
47
+ - !ruby/object:Gem::Version
48
+ version: 4.1.0
49
+ type: :runtime
50
+ prerelease: false
51
+ version_requirements: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - '>='
54
+ - !ruby/object:Gem::Version
55
+ version: 4.1.0
56
+ - !ruby/object:Gem::Dependency
57
+ name: i18n
58
+ requirement: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - '>='
61
+ - !ruby/object:Gem::Version
62
+ version: 0.5.0
63
+ type: :runtime
64
+ prerelease: false
65
+ version_requirements: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - '>='
68
+ - !ruby/object:Gem::Version
69
+ version: 0.5.0
70
+ description:
71
+ email: zzeligg@gmail.com
72
+ executables: []
73
+ extensions: []
74
+ extra_rdoc_files: []
75
+ files:
76
+ - lib/zlocalize/backend.rb
77
+ - lib/zlocalize/config.rb
78
+ - lib/zlocalize/harvester.rb
79
+ - lib/zlocalize/rails/active_record.rb
80
+ - lib/zlocalize/rails/attached_translations.rb
81
+ - lib/zlocalize/rails/decimal_attributes.rb
82
+ - lib/zlocalize/rails/generators/initializer.rb
83
+ - lib/zlocalize/rails/generators/templates/initializer_template.rb
84
+ - lib/zlocalize/rails/generators/templates/translations_migration_template.rb
85
+ - lib/zlocalize/rails/generators/translations_migration.rb
86
+ - lib/zlocalize/rails/railtie.rb
87
+ - lib/zlocalize/rails/tasks/harvest.rake
88
+ - lib/zlocalize/rails/translated_columns.rb
89
+ - lib/zlocalize/rails/translation.rb
90
+ - lib/zlocalize/rails/translation_validator.rb
91
+ - lib/zlocalize/source_parser.rb
92
+ - lib/zlocalize/translation_file.rb
93
+ - lib/zlocalize.rb
94
+ homepage:
95
+ licenses: []
96
+ metadata: {}
97
+ post_install_message:
98
+ rdoc_options: []
99
+ require_paths:
100
+ - lib
101
+ required_ruby_version: !ruby/object:Gem::Requirement
102
+ requirements:
103
+ - - '>='
104
+ - !ruby/object:Gem::Version
105
+ version: 1.9.3
106
+ required_rubygems_version: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - '>='
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ requirements: []
112
+ rubyforge_project:
113
+ rubygems_version: 2.0.14
114
+ signing_key:
115
+ specification_version: 4
116
+ summary: Translation engine for Rails applications
117
+ test_files: []