i18n_backend_database 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +29 -0
- data/README.textile +125 -0
- data/data/locales.yml +4 -0
- data/generators/i18n_backend_database/i18n_backend_database_generator.rb +8 -0
- data/generators/i18n_backend_database/templates/migrate/create_i18n_tables.rb +25 -0
- data/init.rb +1 -0
- data/lib/controllers/locales_controller.rb +86 -0
- data/lib/controllers/translations_controller.rb +141 -0
- data/lib/ext/i18n.rb +68 -0
- data/lib/google_language.rb +33 -0
- data/lib/i18n_backend_database.rb +9 -0
- data/lib/i18n_backend_database/database.rb +263 -0
- data/lib/i18n_util.rb +148 -0
- data/lib/models/locale.rb +67 -0
- data/lib/models/translation.rb +46 -0
- data/lib/models/translation_option.rb +26 -0
- data/lib/public/images/custom1_bar.gif +0 -0
- data/lib/public/images/custom1_box.gif +0 -0
- data/lib/public/images/percentImage.png +0 -0
- data/lib/public/images/percentImage_back.png +0 -0
- data/lib/public/images/percentImage_back1.png +0 -0
- data/lib/public/images/percentImage_back2.png +0 -0
- data/lib/public/images/percentImage_back3.png +0 -0
- data/lib/public/images/percentImage_back4.png +0 -0
- data/lib/public/javascripts/jsProgressBarHandler.js +509 -0
- data/lib/routing.rb +15 -0
- data/lib/views/layouts/translations.html.erb +23 -0
- data/lib/views/locales/edit.html.erb +20 -0
- data/lib/views/locales/index.html.erb +22 -0
- data/lib/views/locales/new.html.erb +19 -0
- data/lib/views/locales/show.html.erb +14 -0
- data/lib/views/translations/asset_translations.html.erb +32 -0
- data/lib/views/translations/edit.html.erb +35 -0
- data/lib/views/translations/index.html.erb +27 -0
- data/lib/views/translations/new.html.erb +19 -0
- data/lib/views/translations/show.html.erb +32 -0
- data/lib/views/translations/translations.html.erb +28 -0
- data/lib/views/translations/update.rjs +7 -0
- data/routes.rb +3 -0
- data/spec/assets/public/es/favicons/favicon1.gif +0 -0
- data/spec/assets/public/es/images/icons/icon1.gif +0 -0
- data/spec/assets/public/es/images/image1.gif +0 -0
- data/spec/assets/public/favicons/favicon1.gif +0 -0
- data/spec/assets/public/favicons/favicon2.gif +0 -0
- data/spec/assets/public/images/icons/icon1.gif +0 -0
- data/spec/assets/public/images/icons/icon2.gif +0 -0
- data/spec/assets/public/images/image1.gif +0 -0
- data/spec/assets/public/images/image2.gif +0 -0
- data/spec/assets/public/images/promo/sfc08_140x400_3.gif +0 -0
- data/spec/assets/views/test_view1.html.erb +1 -0
- data/spec/assets/views/test_view2.html.erb +30 -0
- data/spec/caching_spec.rb +87 -0
- data/spec/controllers/locales_controller_spec.rb +173 -0
- data/spec/controllers/locales_routing_spec.rb +59 -0
- data/spec/controllers/translations_controller_spec.rb +189 -0
- data/spec/controllers/translations_routing_spec.rb +59 -0
- data/spec/database_spec.rb +199 -0
- data/spec/i18n_ext_spec.rb +40 -0
- data/spec/localize_spec.rb +66 -0
- data/spec/localize_text_spec.rb +76 -0
- data/spec/models/locale_spec.rb +111 -0
- data/spec/models/translation_spec.rb +44 -0
- data/spec/spec_helper.rb +16 -0
- data/spec/translate_asset_spec.rb +57 -0
- data/spec/translate_spec.rb +546 -0
- data/tasks/i18n.rake +60 -0
- metadata +155 -0
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'cgi'
|
2
|
+
require 'net/http'
|
3
|
+
require 'json'
|
4
|
+
|
5
|
+
class GoogleLanguage
|
6
|
+
|
7
|
+
# Thanks http://ruby.geraldbauer.ca/google-translation-api.html
|
8
|
+
def self.translate( text, to, from='en' )
|
9
|
+
|
10
|
+
base = 'http://ajax.googleapis.com/ajax/services/language/translate'
|
11
|
+
|
12
|
+
# assemble query params
|
13
|
+
params = {
|
14
|
+
:langpair => "#{from}|#{to}",
|
15
|
+
:q => text,
|
16
|
+
:v => 1.0
|
17
|
+
}
|
18
|
+
|
19
|
+
query = params.map{ |k,v| "#{k}=#{CGI.escape(v.to_s)}" }.join('&')
|
20
|
+
|
21
|
+
# send get request
|
22
|
+
response = Net::HTTP.get_response( URI.parse( "#{base}?#{query}" ) )
|
23
|
+
|
24
|
+
json = JSON.parse( response.body )
|
25
|
+
|
26
|
+
if json['responseStatus'] == 200
|
27
|
+
json['responseData']['translatedText']
|
28
|
+
else
|
29
|
+
raise StandardError, response['responseDetails']
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/models/locale'
|
2
|
+
require File.dirname(__FILE__) + '/models/translation'
|
3
|
+
require File.dirname(__FILE__) + '/models/translation_option'
|
4
|
+
require File.dirname(__FILE__) + '/routing'
|
5
|
+
require File.dirname(__FILE__) + '/controllers/locales_controller'
|
6
|
+
require File.dirname(__FILE__) + '/controllers/translations_controller'
|
7
|
+
require File.dirname(__FILE__) + '/i18n_backend_database/database'
|
8
|
+
require File.dirname(__FILE__) + '/ext/i18n'
|
9
|
+
ActionController::Routing::RouteSet::Mapper.send(:include, I18n::BackendDatabase::Routing)
|
@@ -0,0 +1,263 @@
|
|
1
|
+
|
2
|
+
module I18n
|
3
|
+
module Backend
|
4
|
+
class Database
|
5
|
+
INTERPOLATION_RESERVED_KEYS = %w(scope default)
|
6
|
+
MATCH = /(\\\\)?\{\{([^\}]+)\}\}/
|
7
|
+
|
8
|
+
attr_accessor :locale
|
9
|
+
attr_accessor :cache_store
|
10
|
+
attr_accessor :localize_text_tag
|
11
|
+
|
12
|
+
def initialize(options = {})
|
13
|
+
store = options.delete(:cache_store)
|
14
|
+
text_tag = options.delete(:localize_text_tag)
|
15
|
+
@cache_store = store ? ActiveSupport::Cache.lookup_store(store) : Rails.cache
|
16
|
+
@localize_text_tag = text_tag ? text_tag : '^^'
|
17
|
+
end
|
18
|
+
|
19
|
+
def locale=(code)
|
20
|
+
@locale = Locale.find_by_code(code)
|
21
|
+
end
|
22
|
+
|
23
|
+
def cache_store=(store)
|
24
|
+
@cache_store = ActiveSupport::Cache.lookup_store(store)
|
25
|
+
end
|
26
|
+
|
27
|
+
# Handles the lookup and addition of translations to the database
|
28
|
+
#
|
29
|
+
# On an initial translation, the locale is checked to determine if
|
30
|
+
# this is the default locale. If it is, we'll create a complete
|
31
|
+
# translation record for this locale with both the key and value.
|
32
|
+
#
|
33
|
+
# If the current locale is checked, and it differs from the default
|
34
|
+
# locale, we'll create a translation record with a nil value. This
|
35
|
+
# allows for the lookup of untranslated records in a given locale.
|
36
|
+
def translate(locale, key, options = {})
|
37
|
+
@locale = locale_in_context(locale)
|
38
|
+
|
39
|
+
options[:scope] = [options[:scope]] unless options[:scope].is_a?(Array) || options[:scope].blank?
|
40
|
+
key = "#{options[:scope].join('.')}.#{key}".to_sym if options[:scope] && key.is_a?(Symbol)
|
41
|
+
count = options[:count]
|
42
|
+
# pull out values for interpolation
|
43
|
+
values = options.reject { |name, value| [:scope, :default].include?(name) }
|
44
|
+
|
45
|
+
entry = lookup(@locale, key)
|
46
|
+
cache_lookup = true unless entry.nil?
|
47
|
+
|
48
|
+
# if no entry exists for the current locale and the current locale is not the default locale then lookup translations for the default locale for this key
|
49
|
+
unless entry || @locale.default_locale?
|
50
|
+
entry = use_and_copy_default_locale_translations_if_they_exist(@locale, key)
|
51
|
+
end
|
52
|
+
|
53
|
+
# if we have no entry and some defaults ... start looking them up
|
54
|
+
unless entry || key.is_a?(String) || options[:default].blank?
|
55
|
+
default = options[:default].is_a?(Array) ? options[:default].shift : options.delete(:default)
|
56
|
+
return translate(@locale.code, default, options.dup)
|
57
|
+
end
|
58
|
+
|
59
|
+
# this needs to be folded into the above at some point.
|
60
|
+
# this handles the case where the default of the string key is a space
|
61
|
+
if !entry && key.is_a?(String) && options[:default] == " "
|
62
|
+
default = options[:default].is_a?(Array) ? options[:default].shift : options.delete(:default)
|
63
|
+
return translate(@locale.code, default, options.dup)
|
64
|
+
end
|
65
|
+
|
66
|
+
# The requested key might not be a parent node in a hierarchy of keys instead of a regular 'leaf' node
|
67
|
+
# that would simply result in a string return. If so, check the database for possible children
|
68
|
+
# and return them in a nested hash if we find them.
|
69
|
+
# We can safely ignore pluralization indeces here since they should never apply to a hash return
|
70
|
+
if !entry && (key.is_a?(String) || key.is_a?(Symbol))
|
71
|
+
#We need to escape % and \. Rails will handle the rest.
|
72
|
+
escaped_key = key.to_s.gsub('\\', '\\\\\\\\').gsub(/%/, '\%')
|
73
|
+
children = @locale.translations.find :all, :conditions => ["raw_key like ?", "#{escaped_key}.%"]
|
74
|
+
if children.size > 0
|
75
|
+
entry = hashify_record_array(key.to_s, children)
|
76
|
+
@cache_store.write(Translation.ck(@locale, key), entry) unless cache_lookup == true
|
77
|
+
return entry
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
# we check the database before creating a translation as we can have translations with nil values
|
82
|
+
# if we still have no blasted translation just go and create one for the current locale!
|
83
|
+
unless entry
|
84
|
+
pluralization_index = (options[:count].nil? || options[:count] == 1) ? 1 : 0
|
85
|
+
translation = @locale.translations.find_by_key_and_pluralization_index(Translation.hk(key), pluralization_index) ||
|
86
|
+
@locale.create_translation(key, key, pluralization_index)
|
87
|
+
entry = translation.value_or_default
|
88
|
+
end
|
89
|
+
|
90
|
+
# write to cache unless we've already had a successful cache hit
|
91
|
+
@cache_store.write(Translation.ck(@locale, key), entry) unless cache_lookup == true
|
92
|
+
|
93
|
+
entry = pluralize(@locale, entry, count)
|
94
|
+
entry = interpolate(@locale.code, entry, values)
|
95
|
+
entry.is_a?(Array) ? entry.dup : entry # array's can get frozen with cache writes
|
96
|
+
end
|
97
|
+
|
98
|
+
# Acts the same as +strftime+, but returns a localized version of the
|
99
|
+
# formatted date string. Takes a key from the date/time formats
|
100
|
+
# translations as a format argument (<em>e.g.</em>, <tt>:short</tt> in <tt>:'date.formats'</tt>).
|
101
|
+
def localize(locale, object, format = :default)
|
102
|
+
raise ArgumentError, "Object must be a Date, DateTime or Time object. #{object.inspect} given." unless object.respond_to?(:strftime)
|
103
|
+
|
104
|
+
type = object.respond_to?(:sec) ? 'time' : 'date'
|
105
|
+
format = translate(locale, "#{type}.formats.#{format.to_s}") unless format.to_s.index('%') # lookup keyed formats unless a custom format is passed
|
106
|
+
|
107
|
+
format.gsub!(/%a/, translate(locale, :"date.abbr_day_names")[object.wday])
|
108
|
+
format.gsub!(/%A/, translate(locale, :"date.day_names")[object.wday])
|
109
|
+
format.gsub!(/%b/, translate(locale, :"date.abbr_month_names")[object.mon])
|
110
|
+
format.gsub!(/%B/, translate(locale, :"date.month_names")[object.mon])
|
111
|
+
format.gsub!(/%p/, translate(locale, :"time.#{object.hour < 12 ? :am : :pm}")) if object.respond_to? :hour
|
112
|
+
|
113
|
+
object.strftime(format)
|
114
|
+
end
|
115
|
+
|
116
|
+
# Returns the text string with the text within the localize text tags translated.
|
117
|
+
def localize_text(locale, text)
|
118
|
+
text_tag = Regexp.escape(localize_text_tag).to_s
|
119
|
+
expression = Regexp.new(text_tag + "(.*?)" + text_tag)
|
120
|
+
tagged_text = text[expression, 1]
|
121
|
+
while tagged_text do
|
122
|
+
text = text.sub(expression, translate(locale, tagged_text))
|
123
|
+
tagged_text = text[expression, 1]
|
124
|
+
end
|
125
|
+
return text
|
126
|
+
end
|
127
|
+
|
128
|
+
def available_locales
|
129
|
+
Locale.available_locales
|
130
|
+
end
|
131
|
+
|
132
|
+
def reload!
|
133
|
+
# get's called on initialization
|
134
|
+
# let's not do anything yet
|
135
|
+
end
|
136
|
+
|
137
|
+
protected
|
138
|
+
# keep a local copy of the locale in context for use within the translation
|
139
|
+
# routine, and also accept an arbitrary locale for one time locale lookups
|
140
|
+
def locale_in_context(locale)
|
141
|
+
return @locale if @locale && @locale.code == locale.to_s
|
142
|
+
#Locale.find_by_code(locale.to_s) rescue nil && (raise InvalidLocale.new(locale))
|
143
|
+
locale = Locale.find_by_code(locale.to_s)
|
144
|
+
raise InvalidLocale.new(locale) unless locale
|
145
|
+
locale
|
146
|
+
end
|
147
|
+
|
148
|
+
# lookup key in cache and db, if the db is hit the value is cached
|
149
|
+
def lookup(locale, key)
|
150
|
+
cache_key = Translation.ck(locale, key)
|
151
|
+
if @cache_store.exist?(cache_key) && value = @cache_store.read(cache_key)
|
152
|
+
return value
|
153
|
+
else
|
154
|
+
translations = locale.translations.find_all_by_key(Translation.hk(key))
|
155
|
+
case translations.size
|
156
|
+
when 0
|
157
|
+
value = nil
|
158
|
+
when 1
|
159
|
+
value = translations.first.value_or_default
|
160
|
+
else
|
161
|
+
value = translations.inject([]) do |values, t|
|
162
|
+
values[t.pluralization_index] = t.value_or_default
|
163
|
+
values
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
@cache_store.write(cache_key, (value.nil? ? nil : value))
|
168
|
+
return value
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
# looks up translations for the default locale, and if they exist untranslated records are created for the locale and the default locale values are returned
|
173
|
+
def use_and_copy_default_locale_translations_if_they_exist(locale, key)
|
174
|
+
default_locale_entry = lookup(Locale.default_locale, key)
|
175
|
+
return unless default_locale_entry
|
176
|
+
|
177
|
+
if default_locale_entry.is_a?(Array)
|
178
|
+
default_locale_entry.each_with_index do |entry, index|
|
179
|
+
locale.create_translation(key, nil, index) if entry
|
180
|
+
end
|
181
|
+
else
|
182
|
+
locale.create_translation(key, nil)
|
183
|
+
end
|
184
|
+
|
185
|
+
return default_locale_entry
|
186
|
+
end
|
187
|
+
|
188
|
+
def pluralize(locale, entry, count)
|
189
|
+
return entry unless entry.is_a?(Array) and count
|
190
|
+
count = count == 1 ? 1 : 0
|
191
|
+
entry.compact[count]
|
192
|
+
end
|
193
|
+
|
194
|
+
# Interpolates values into a given string.
|
195
|
+
#
|
196
|
+
# interpolate "file {{file}} opened by \\{{user}}", :file => 'test.txt', :user => 'Mr. X'
|
197
|
+
# # => "file test.txt opened by {{user}}"
|
198
|
+
#
|
199
|
+
# Note that you have to double escape the <tt>\\</tt> when you want to escape
|
200
|
+
# the <tt>{{...}}</tt> key in a string (once for the string and once for the
|
201
|
+
# interpolation).
|
202
|
+
def interpolate(locale, string, values = {})
|
203
|
+
return string unless string.is_a?(String)
|
204
|
+
|
205
|
+
if string.respond_to?(:force_encoding)
|
206
|
+
original_encoding = string.encoding
|
207
|
+
string.force_encoding(Encoding::BINARY)
|
208
|
+
end
|
209
|
+
|
210
|
+
result = string.gsub(MATCH) do
|
211
|
+
escaped, pattern, key = $1, $2, $2.to_sym
|
212
|
+
|
213
|
+
if escaped
|
214
|
+
pattern
|
215
|
+
elsif INTERPOLATION_RESERVED_KEYS.include?(pattern)
|
216
|
+
raise ReservedInterpolationKey.new(pattern, string)
|
217
|
+
elsif !values.include?(key)
|
218
|
+
raise MissingInterpolationArgument.new(pattern, string)
|
219
|
+
else
|
220
|
+
values[key].to_s
|
221
|
+
end
|
222
|
+
end
|
223
|
+
|
224
|
+
result.force_encoding(original_encoding) if original_encoding
|
225
|
+
result
|
226
|
+
end
|
227
|
+
|
228
|
+
def strip_root_key(root_key, key)
|
229
|
+
return nil if key.nil?
|
230
|
+
return key.gsub(/^#{root_key}\./, '')
|
231
|
+
end
|
232
|
+
|
233
|
+
def hashify_record_array(root_key, record_array)
|
234
|
+
return nil if record_array.nil? || record_array.empty?
|
235
|
+
|
236
|
+
#Make sure that all of our records have raw_keys
|
237
|
+
record_array.reject! {|record| record.raw_key.nil?}
|
238
|
+
|
239
|
+
# Start building our return hash
|
240
|
+
result = {}
|
241
|
+
record_array.each { |record|
|
242
|
+
key = strip_root_key(root_key, record.raw_key)
|
243
|
+
next unless key.present?
|
244
|
+
|
245
|
+
# If we contain a period delimiter, we need to add a sub-hash.
|
246
|
+
# Otherwise, we just insert the value at this level.
|
247
|
+
if key.index(".")
|
248
|
+
internal_node = key.slice(0, key.index('.'))
|
249
|
+
new_root = root_key + '.' + internal_node
|
250
|
+
new_record_array = record_array.select {|record| record.raw_key.starts_with? new_root}
|
251
|
+
result[internal_node.to_sym] = hashify_record_array(new_root, new_record_array)
|
252
|
+
else
|
253
|
+
value = record.value
|
254
|
+
value = value.to_i if value == "0" || value.to_i != 0 #simple integer cast
|
255
|
+
result[key.to_sym] = value
|
256
|
+
end
|
257
|
+
}
|
258
|
+
result
|
259
|
+
end
|
260
|
+
|
261
|
+
end
|
262
|
+
end
|
263
|
+
end
|
data/lib/i18n_util.rb
ADDED
@@ -0,0 +1,148 @@
|
|
1
|
+
class I18nUtil
|
2
|
+
|
3
|
+
# Create tanslation records from the YAML file. Will create the required locales if they do not exist.
|
4
|
+
def self.load_from_yml(file_name)
|
5
|
+
data = YAML::load(IO.read(file_name))
|
6
|
+
data.each do |code, translations|
|
7
|
+
locale = Locale.find_or_create_by_code(code)
|
8
|
+
backend = I18n::Backend::Simple.new
|
9
|
+
keys = extract_i18n_keys(translations)
|
10
|
+
keys.each do |key|
|
11
|
+
value = backend.send(:lookup, code, key)
|
12
|
+
|
13
|
+
pluralization_index = 1
|
14
|
+
|
15
|
+
if key.ends_with?('.one')
|
16
|
+
key.gsub!('.one', '')
|
17
|
+
end
|
18
|
+
|
19
|
+
if key.ends_with?('.other')
|
20
|
+
key.gsub!('.other', '')
|
21
|
+
pluralization_index = 0
|
22
|
+
end
|
23
|
+
|
24
|
+
if value.is_a?(Array)
|
25
|
+
value.each_with_index do |v, index|
|
26
|
+
create_translation(locale, "#{key}", index, v) unless v.nil?
|
27
|
+
end
|
28
|
+
else
|
29
|
+
create_translation(locale, key, pluralization_index, value)
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
# Finds or creates a translation record and updates the value
|
37
|
+
def self.create_translation(locale, key, pluralization_index, value)
|
38
|
+
translation = locale.translations.find_by_key_and_pluralization_index(Translation.hk(key), pluralization_index) # find existing record by hash key
|
39
|
+
unless translation # or build new one with raw key
|
40
|
+
translation = locale.translations.build(:key =>key, :pluralization_index => pluralization_index)
|
41
|
+
puts "from yaml create translation for #{locale.code} : #{key} : #{pluralization_index}" unless RAILS_ENV['test']
|
42
|
+
end
|
43
|
+
translation.value = value
|
44
|
+
translation.save!
|
45
|
+
end
|
46
|
+
|
47
|
+
def self.extract_i18n_keys(hash, parent_keys = [])
|
48
|
+
hash.inject([]) do |keys, (key, value)|
|
49
|
+
full_key = parent_keys + [key]
|
50
|
+
if value.is_a?(Hash)
|
51
|
+
# Nested hash
|
52
|
+
keys += extract_i18n_keys(value, full_key)
|
53
|
+
elsif !value.nil?
|
54
|
+
# String leaf node
|
55
|
+
keys << full_key.join(".")
|
56
|
+
end
|
57
|
+
keys
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
# Create translation records for all existing locales from translation calls with the application. Ignores errors from tranlations that require objects.
|
62
|
+
def self.seed_application_translations(dir='app')
|
63
|
+
translated_objects(dir).each do |object|
|
64
|
+
interpolation_arguments= object.scan(/\{\{(.*?)\}\}/).flatten
|
65
|
+
object = object[/'(.*?)'/, 1] || object[/"(.*?)"/, 1]
|
66
|
+
options = {}
|
67
|
+
interpolation_arguments.each { |arg| options[arg.to_sym] = nil }
|
68
|
+
next if object.nil?
|
69
|
+
|
70
|
+
puts "translating for #{object} with options #{options.inspect}" unless RAILS_ENV['test']
|
71
|
+
I18n.t(object, options) # default locale first
|
72
|
+
locales = Locale.available_locales
|
73
|
+
locales.delete(I18n.default_locale)
|
74
|
+
# translate for other locales
|
75
|
+
locales.each do |locale|
|
76
|
+
I18n.t(object, options.merge(:locale => locale))
|
77
|
+
end
|
78
|
+
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def self.translated_objects(dir='app')
|
83
|
+
assets = []
|
84
|
+
Dir.glob("#{dir}/*").each do |item|
|
85
|
+
if File.directory?(item)
|
86
|
+
assets += translated_objects(item) unless item.ends_with?('i18n_backend_database') # ignore self
|
87
|
+
else
|
88
|
+
File.readlines(item).each do |l|
|
89
|
+
assets += l.scan(/I18n.t\((.*?)\)/).flatten
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
assets.uniq
|
94
|
+
end
|
95
|
+
|
96
|
+
# Populate translation records from the default locale to other locales if no record exists.
|
97
|
+
def self.synchronize_translations
|
98
|
+
non_default_locales = Locale.non_defaults
|
99
|
+
Locale.default_locale.translations.each do |t|
|
100
|
+
non_default_locales.each do |locale|
|
101
|
+
unless locale.translations.exists?(:key => t.key, :pluralization_index => t.pluralization_index)
|
102
|
+
value = t.value =~ /^---(.*)\n/ ? t.value : nil # well will copy across YAML, like symbols
|
103
|
+
locale.translations.create!(:key => t.raw_key, :value => value, :pluralization_index => t.pluralization_index)
|
104
|
+
puts "synchronizing has created translation for #{locale.code} : #{t.raw_key} : #{t.pluralization_index}" unless RAILS_ENV['test']
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
def self.google_translate
|
111
|
+
Locale.non_defaults.each do |locale|
|
112
|
+
locale.translations.untranslated.each do |translation|
|
113
|
+
default_locale_value = translation.default_locale_value
|
114
|
+
unless needs_human_eyes?(default_locale_value)
|
115
|
+
interpolation_arguments= default_locale_value.scan(/\{\{(.*?)\}\}/).flatten
|
116
|
+
|
117
|
+
if interpolation_arguments.empty?
|
118
|
+
translation.value = GoogleLanguage.translate(default_locale_value, locale.code, Locale.default_locale.code)
|
119
|
+
translation.save!
|
120
|
+
else
|
121
|
+
placeholder_value = 990 # at least in :es it seems to leave a 3 digit number in the postion on the string
|
122
|
+
placeholders = {}
|
123
|
+
|
124
|
+
# replace {{interpolation_arguments}} with a numeric place holder
|
125
|
+
interpolation_arguments.each do |interpolation_argument|
|
126
|
+
default_locale_value.gsub!("{{#{interpolation_argument}}}", "#{placeholder_value}")
|
127
|
+
placeholders[placeholder_value] = interpolation_argument
|
128
|
+
placeholder_value += 1
|
129
|
+
end
|
130
|
+
|
131
|
+
# translate string
|
132
|
+
translated_value = GoogleLanguage.translate(default_locale_value, locale.code, Locale.default_locale.code)
|
133
|
+
|
134
|
+
# replace numeric place holders with {{interpolation_arguments}}
|
135
|
+
placeholders.each {|placeholder_value,interpolation_argument| translated_value.gsub!("#{placeholder_value}", "{{#{interpolation_argument}}}") }
|
136
|
+
translation.value = translated_value
|
137
|
+
translation.save!
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
def self.needs_human_eyes?(value)
|
145
|
+
return true if value.index('%') # date formats
|
146
|
+
return true if value =~ /^---(.*)\n/ # YAML
|
147
|
+
end
|
148
|
+
end
|