tr8n_core 4.0.17 → 4.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (40) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +7 -9
  3. data/lib/tr8n/{api_client.rb → api/client.rb} +66 -30
  4. data/lib/tr8n/api/post_office.rb +71 -0
  5. data/lib/tr8n/application.rb +115 -102
  6. data/lib/tr8n/base.rb +1 -1
  7. data/lib/tr8n/cache.rb +13 -1
  8. data/lib/tr8n/cache_adapters/file.rb +18 -11
  9. data/lib/tr8n/cache_adapters/memcache.rb +5 -5
  10. data/lib/tr8n/cache_adapters/memory.rb +85 -0
  11. data/lib/tr8n/component.rb +4 -4
  12. data/lib/tr8n/config.rb +5 -5
  13. data/lib/tr8n/decorators/base.rb +9 -1
  14. data/lib/tr8n/decorators/default.rb +5 -1
  15. data/lib/tr8n/decorators/html.rb +43 -12
  16. data/lib/tr8n/language.rb +23 -16
  17. data/lib/tr8n/language_case.rb +5 -29
  18. data/lib/tr8n/language_case_rule.rb +8 -26
  19. data/lib/tr8n/language_context.rb +5 -15
  20. data/lib/tr8n/language_context_rule.rb +3 -18
  21. data/lib/tr8n/logger.rb +16 -4
  22. data/lib/tr8n/session.rb +71 -13
  23. data/lib/tr8n/source.rb +45 -11
  24. data/lib/tr8n/translation.rb +1 -44
  25. data/lib/tr8n/translation_key.rb +10 -22
  26. data/lib/tr8n/translator.rb +5 -13
  27. data/lib/tr8n/utils.rb +6 -2
  28. data/lib/tr8n_core.rb +3 -2
  29. data/lib/tr8n_core/ext/array.rb +1 -1
  30. data/lib/tr8n_core/ext/date.rb +1 -2
  31. data/lib/tr8n_core/ext/fixnum.rb +1 -1
  32. data/lib/tr8n_core/ext/hash.rb +1 -1
  33. data/lib/tr8n_core/ext/string.rb +1 -1
  34. data/lib/tr8n_core/ext/time.rb +1 -1
  35. data/lib/tr8n_core/generators/cache/base.rb +40 -18
  36. data/lib/tr8n_core/generators/cache/cdb.rb +1 -1
  37. data/lib/tr8n_core/generators/cache/file.rb +99 -21
  38. data/lib/tr8n_core/languages/{en-US.json → en.json} +2 -2
  39. data/lib/tr8n_core/version.rb +2 -2
  40. metadata +6 -4
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 470f4942f0fab2b30f5a0d7b712ae1a23794303c
4
- data.tar.gz: b7066bedabf3daa74aaad31d11ca3cb8bf76b45b
3
+ metadata.gz: 0baac64dd209fa38abfdbd9e9b74dc73a8bef620
4
+ data.tar.gz: 9c3aee8e89c3aad83151f5ce1ec5970d96de34e5
5
5
  SHA512:
6
- metadata.gz: 2d17fb49dd55b1f0fd6e6798060dc6e90694f3e77bec6771fa00ef41aae6b0b446a4e6f331db0ee0f67a0b99890a7085c6a1d502160c52cfb37a18da3967425f
7
- data.tar.gz: 86a847db7c7af547f2c036d3b38c0eb2c51bd13b3310cfc2f565f9f2997c01f0768b61348f951699ecb482346ce643a048442a410a9c92cb12dbcb6be429c8c0
6
+ metadata.gz: b8c57324b77a158776980bcbac2d4d439d150105aa2fabf3baeaf33c6f920ad04f7d064d263ed6e1f7db23cbaed62601bff4a5ea6b264f0f66b6d38aa5d7c78d
7
+ data.tar.gz: 1eb5e3b4a46aa22dbf63a99ae85755ac821e22bcb84f9e14206162d1cc447c644e79c0fe199123a12dec6e06f1c5338af4dc44e9027333030a8c63762bfc5f3d
data/README.md CHANGED
@@ -13,8 +13,8 @@ Tr8n Core Library For Ruby
13
13
  Tr8n core library for Ruby is a set of classes that provide translation functionality for any Ruby based application.
14
14
  The library uses Tr8n's TML (Translation Markup Language) that allows you to encode complex language structures in simple, yet powerful forms.
15
15
 
16
- The library works in conjunctions with tr8nhub.com service that provides machine and human translations for your application.
17
- In order to use the library, you should sign up at tr8nhub.com, create a new application and copy the application key and secret.
16
+ The library works in conjunctions with TranslationExchange.com service that provides machine and human translations for your application.
17
+ In order to use the library, you should sign up at TranslationExchange.com, create a new application and copy the application key and secret.
18
18
 
19
19
 
20
20
  Rails Integration
@@ -38,7 +38,7 @@ gem install tr8n_core
38
38
  Registering Your App
39
39
  ===================================
40
40
 
41
- Before you can proceed with the integration, please register with https://translationexchange.com and create a new application.
41
+ Before you can proceed with the integration, please register with http://translationexchange.com and create a new application.
42
42
 
43
43
  At the end of the registration process you will be given a key and a secret. You will need to enter them in the initialization function of the Tr8n SDK.
44
44
 
@@ -208,23 +208,21 @@ irb(main)> russian.translate('This is a new phrase without translations')
208
208
  Links
209
209
  ==================
210
210
 
211
- * Register on TranslationExchange.com: https://translationexchange.com
211
+ * Register on TranslationExchange.com: http://translationexchange.com
212
212
 
213
- * Read TranslationExchange's documentation: http://wiki.tr8nhub.com
214
-
215
- * Visit TranslationExchange's blog: http://blog.tr8nhub.com
213
+ * Read TranslationExchange's documentation: http://translationexchange.com/docs
216
214
 
217
215
  * Follow TranslationExchange on Twitter: https://twitter.com/translationx
218
216
 
219
217
  * Connect with TranslationExchange on Facebook: https://www.facebook.com/translationexchange
220
218
 
221
- * If you have any questions or suggestions, contact us: info@translationexchange.com
219
+ * If you have any questions or suggestions, contact us: feedback@translationexchange.com
222
220
 
223
221
 
224
222
  Copyright and license
225
223
  ==================
226
224
 
227
- Copyright (c) 2014 Michael Berkovich, TranslationExchange.com
225
+ Copyright (c) 2015 Translation Exchange, Inc
228
226
 
229
227
  Permission is hereby granted, free of charge, to any person obtaining
230
228
  a copy of this software and associated documentation files (the
@@ -32,38 +32,39 @@
32
32
 
33
33
  require 'faraday'
34
34
 
35
- class Tr8n::ApiClient < Tr8n::Base
36
- API_HOST = 'https://translationexchange.com'
37
- API_PATH = '/tr8n/api/'
35
+ class Tr8n::Api::Client < Tr8n::Base
36
+ API_HOST = 'https://api.translationexchange.com'
37
+ API_PATH = '/v1'
38
38
 
39
39
  attributes :application
40
40
 
41
41
  def access_token
42
42
  application.access_token ||= begin
43
- api("oauth/request_token",
44
- {
45
- :client_id => application.key,
46
- :client_secret => application.secret,
47
- :grant_type => :client_credentials
48
- },
49
- {
50
- :host => application.host
51
- }
52
- )
43
+ Tr8n.cache.fetch("#{application.key}/access_token") do
44
+ api('oauth/token', {
45
+ :client_id => application.key,
46
+ :client_secret => application.secret,
47
+ :grant_type => :client_credentials
48
+ }, {:method => :post})
49
+ end
53
50
  end
54
- application.access_token["access_token"]
51
+ application.access_token['access_token']
52
+ end
53
+
54
+ def results(path, params = {}, opts = {})
55
+ get(path, params, opts)['results']
55
56
  end
56
57
 
57
58
  def get(path, params = {}, opts = {})
58
- api(path, params.merge(:client_id => application.key, :t => Time.now.to_i), opts.merge(:method => :get))
59
+ api(path, params, opts.merge(:method => :get))
59
60
  end
60
61
 
61
62
  def post(path, params = {}, opts = {})
62
- api(path, params.merge(:access_token => access_token, :t => Time.now.to_i), opts.merge(:method => :post))
63
+ api(path, params, opts.merge(:method => :post))
63
64
  end
64
65
 
65
66
  def self.error?(data)
66
- not data["error"].nil?
67
+ not data['error'].nil?
67
68
  end
68
69
 
69
70
  def host
@@ -79,9 +80,13 @@ class Tr8n::ApiClient < Tr8n::Base
79
80
  end
80
81
 
81
82
  def api(path, params = {}, opts = {})
83
+ if Tr8n.session.inline_mode?
84
+ return process_response(execute_request(path, params, opts), opts)
85
+ end
86
+
82
87
  if opts[:method] == :get and opts[:cache_key]
83
88
  data = Tr8n.cache.fetch(opts[:cache_key]) do
84
- execute_request(path, params, opts)
89
+ Tr8n.cache.read_only? ? {} : execute_request(path, params, opts)
85
90
  end
86
91
  process_response(data, opts)
87
92
  else
@@ -89,19 +94,49 @@ class Tr8n::ApiClient < Tr8n::Base
89
94
  end
90
95
  end
91
96
 
97
+ def paginate(path, params = {}, opts = {})
98
+ data = get(path, params, opts.merge({'raw' => true}))
99
+
100
+ while data
101
+ if data['results'].is_a?(Array)
102
+ data['results'].each do |result|
103
+ yield(result)
104
+ end
105
+ else
106
+ yield(data['results'])
107
+ end
108
+
109
+ if data['pagination'] and data['pagination']['links']['next']
110
+ data = get(data['pagination']['links']['next'], {}, opts.merge({'raw' => true}))
111
+ else
112
+ data = nil
113
+ end
114
+ end
115
+ end
116
+
117
+ def prepare_api_path(path)
118
+ return path if path.index('oauth')
119
+ return path if path.match(/^https?:\/\//)
120
+ "#{API_PATH}#{path[0] == '/' ? '' : '/'}#{path}"
121
+ end
122
+
92
123
  def execute_request(path, params = {}, opts = {})
93
124
  response = nil
94
125
  error = nil
95
126
 
96
- Tr8n.logger.trace_api_call(path, params) do
127
+ # oauth path is separate from versioned APIs
128
+ path = prepare_api_path(path)
129
+ params = params.merge(:access_token => access_token) unless path.index('oauth')
130
+
131
+ Tr8n.logger.trace_api_call(path, params, opts) do
97
132
  begin
98
133
  if opts[:method] == :post
99
- response = connection.post("#{API_PATH}#{path}", params)
134
+ response = connection.post(path, params)
100
135
  else
101
- response = connection.get("#{API_PATH}#{path}", params)
136
+ response = connection.get(path, params)
102
137
  end
103
138
  rescue Exception => ex
104
- Tr8n.logger.error("Failed to execute request: #{ex}")
139
+ Tr8n.logger.error("Failed to execute request: #{ex.message[0..255]}")
105
140
  error = ex
106
141
  nil
107
142
  end
@@ -115,11 +150,11 @@ class Tr8n::ApiClient < Tr8n::Base
115
150
  begin
116
151
  data = JSON.parse(response.body)
117
152
  rescue Exception => ex
118
- raise Tr8n::Exception.new("Error: #{ex}")
153
+ raise Tr8n::Exception.new("Failed to parse response: #{ex.message[0..255]}")
119
154
  end
120
155
 
121
- unless data["error"].nil?
122
- raise Tr8n::Exception.new("Error: #{data["error"]}")
156
+ if data.is_a?(Hash) and not data['error'].nil?
157
+ raise Tr8n::Exception.new("Error: #{data['error']}")
123
158
  end
124
159
 
125
160
  data
@@ -131,18 +166,19 @@ class Tr8n::ApiClient < Tr8n::Base
131
166
  end
132
167
 
133
168
  def process_response(data, opts)
134
- if data["results"]
135
- Tr8n.logger.debug("received #{data["results"].size} result(s)")
136
- return data["results"] unless object_class(opts)
169
+ return data if opts['raw']
170
+
171
+ if data.is_a?(Hash) and data['results']
172
+ #Tr8n.logger.debug("received #{data['results'].size} result(s)")
173
+ return data['results'] unless object_class(opts)
137
174
  objects = []
138
- data["results"].each do |data|
175
+ data['results'].each do |data|
139
176
  objects << object_class(opts).new(data.merge(opts[:attributes] || {}))
140
177
  end
141
178
  return objects
142
179
  end
143
180
 
144
181
  return data unless object_class(opts)
145
- #Tr8n.logger.debug("constructing #{object_class(opts).name}")
146
182
  object_class(opts).new(data.merge(opts[:attributes] || {}))
147
183
  end
148
184
 
@@ -0,0 +1,71 @@
1
+ # encoding: UTF-8
2
+ #--
3
+ # Copyright (c) 2014 Michael Berkovich, TranslationExchange.com
4
+ #
5
+ # _______ _ _ _ ______ _
6
+ # |__ __| | | | | (_) | ____| | |
7
+ # | |_ __ __ _ _ __ ___| | __ _| |_ _ ___ _ __ | |__ __ _____| |__ __ _ _ __ __ _ ___
8
+ # | | '__/ _` | '_ \/ __| |/ _` | __| |/ _ \| '_ \| __| \ \/ / __| '_ \ / _` | '_ \ / _` |/ _ \
9
+ # | | | | (_| | | | \__ \ | (_| | |_| | (_) | | | | |____ > < (__| | | | (_| | | | | (_| | __/
10
+ # |_|_| \__,_|_| |_|___/_|\__,_|\__|_|\___/|_| |_|______/_/\_\___|_| |_|\__,_|_| |_|\__, |\___|
11
+ # __/ |
12
+ # |___/
13
+ # Permission is hereby granted, free of charge, to any person obtaining
14
+ # a copy of this software and associated documentation files (the
15
+ # "Software"), to deal in the Software without restriction, including
16
+ # without limitation the rights to use, copy, modify, merge, publish,
17
+ # distribute, sublicense, and/or sell copies of the Software, and to
18
+ # permit persons to whom the Software is furnished to do so, subject to
19
+ # the following conditions:
20
+ #
21
+ # The above copyright notice and this permission notice shall be
22
+ # included in all copies or substantial portions of the Software.
23
+ #
24
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
25
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
26
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
27
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
28
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
29
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
30
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31
+ #++
32
+
33
+ class Tr8n::Api::PostOffice < Tr8n::Api::Client
34
+ POST_OFFICE_HOST = 'https://postoffice.translationexchange.com'
35
+ POST_OFFICE_API_VERSION = 'v1'
36
+
37
+ attributes :application
38
+
39
+ def templates
40
+ api('templates', {
41
+ :access_token => access_token
42
+ })
43
+ end
44
+
45
+ def channels
46
+ api('channels', {
47
+ :access_token => access_token
48
+ })
49
+ end
50
+
51
+ def deliver(template, to, tokens = {}, options = {})
52
+ api("templates/#{template}/deliver", {
53
+ :access_token => access_token,
54
+ :tokens => tokens,
55
+ :to => to,
56
+ :via => options[:via],
57
+ :from => options[:from],
58
+ :locale => options[:locale],
59
+ :realtime => options[:realtime]
60
+ }, options.merge(:method => :post))
61
+ end
62
+
63
+ def host
64
+ application.tools['postoffice'] || POST_OFFICE_HOST
65
+ end
66
+
67
+ def prepare_api_path(path)
68
+ "/api/#{POST_OFFICE_API_VERSION}#{path.first == '/' ? '' : '/'}#{path}"
69
+ end
70
+
71
+ end
@@ -33,11 +33,19 @@
33
33
  require 'faraday'
34
34
 
35
35
  class Tr8n::Application < Tr8n::Base
36
- attributes :host, :key, :secret, :access_token, :name, :description, :threshold, :default_locale, :default_level
37
- has_many :features, :languages, :featured_locales, :sources, :components, :tokens, :css, :shortcuts
36
+ attributes :host, :id, :key, :secret, :access_token, :name, :description, :threshold, :default_locale, :default_level, :tools
37
+ has_many :features, :languages, :featured_locales, :sources, :components, :tokens, :css, :shortcuts, :translations
38
+
39
+ def self.cache_key
40
+ 'application'
41
+ end
42
+
43
+ def self.translations_cache_key(locale)
44
+ "#{locale}/translations"
45
+ end
38
46
 
39
47
  def fetch
40
- update_attributes(api_client.get("application", {:definition => true}, {:cache_key => key}))
48
+ update_attributes(api_client.get('applications/current', {:definition => true}, {:cache_key => self.class.cache_key}))
41
49
  rescue Tr8n::Exception => ex
42
50
  Tr8n.logger.error("Failed to load application: #{ex}")
43
51
  self
@@ -46,49 +54,26 @@ class Tr8n::Application < Tr8n::Base
46
54
  def update_attributes(attrs)
47
55
  super
48
56
 
49
- self.host ||= "https://translationexchange.com"
50
-
51
57
  self.attributes[:languages] = []
52
58
  if hash_value(attrs, :languages)
53
59
  self.attributes[:languages] = hash_value(attrs, :languages).collect{ |l| Tr8n::Language.new(l.merge(:application => self)) }
54
60
  end
55
61
 
56
- self.attributes[:sources] = []
57
- if hash_value(attrs, :sources)
58
- self.attributes[:sources] = hash_value(attrs, :sources).collect{ |l| Tr8n::Source.new(l.merge(:application => self)) }
59
- end
60
-
61
- self.attributes[:components] = []
62
- if hash_value(attrs, :components)
63
- self.attributes[:components] = hash_value(attrs, :components).collect{ |l| Tr8n::Component.new(l.merge(:application => self)) }
64
- end
65
-
66
- @translation_keys = {}
67
- @sources_by_key = {}
68
- @components_by_key = {}
69
-
70
- @languages_by_locale = nil
71
- @missing_keys_by_sources = nil
72
-
73
62
  self
74
63
  end
75
64
 
76
65
  def language(locale = nil)
66
+ locale = nil if locale.strip == ''
77
67
  locale ||= default_locale || Tr8n.config.default_locale
78
68
  @languages_by_locale ||= {}
79
-
80
- unless Tr8n.session.current_translator and Tr8n.session.current_translator.inline?
81
- cache_key = "#{locale}/language"
82
- end
83
-
84
69
  @languages_by_locale[locale] ||= api_client.get(
85
- 'language',
86
- {:locale => locale},
87
- {
88
- :class => Tr8n::Language,
89
- :attributes => {:locale => locale, :application => self},
90
- :cache_key => cache_key
91
- }
70
+ "languages/#{locale}",
71
+ {:definition => true},
72
+ {
73
+ :class => Tr8n::Language,
74
+ :attributes => {:locale => locale, :application => self},
75
+ :cache_key => Tr8n::Language.cache_key(locale)
76
+ }
92
77
  )
93
78
  rescue Tr8n::Exception => e
94
79
  Tr8n.logger.error(e)
@@ -110,76 +95,34 @@ class Tr8n::Application < Tr8n::Base
110
95
  @locales ||= languages.collect{|lang| lang.locale}
111
96
  end
112
97
 
113
- def url_for(path)
114
- "#{host}#{path}"
98
+ def tools
99
+ @attributes[:tools] || {}
115
100
  end
116
101
 
117
- def source(key, locale)
118
- @sources_by_key ||= {}
119
- return @sources_by_key[key] if @sources_by_key[key]
120
-
121
- unless Tr8n.session.current_translator and Tr8n.session.current_translator.inline?
122
- cache_key = Tr8n::Source.cache_key(key, locale)
123
- end
102
+ def url_for(path)
103
+ "#{tools['assets']}#{path}"
104
+ end
124
105
 
125
- @sources_by_key[key] ||= api_client.get(
126
- "source",
127
- {:source => key, :locale => locale, :translations => true},
128
- {
129
- :class => Tr8n::Source,
130
- :attributes => {:application => self},
131
- :cache_key => cache_key
132
- }
133
- )
134
- rescue
135
- @sources_by_key[key] = Tr8n::Source.new(:source => key)
106
+ def source(source, locale)
107
+ self.sources ||= {}
108
+ self.sources[source] ||= Tr8n::Source.new(
109
+ :application => self,
110
+ :source => source
111
+ ).fetch_translations(locale)
136
112
  end
137
113
 
138
114
  def component(key, register = true)
139
115
  key = key.key if key.is_a?(Tr8n::Component)
140
116
 
141
- return @components_by_key[key] if @components_by_key[key]
117
+ return self.components[key] if self.components[key]
142
118
  return nil unless register
143
119
 
144
- @components_by_key[key] ||= api_client.post("component/register", {:component => key}, {:class => Tr8n::Component, :attributes => {:application => self}})
145
- end
146
-
147
- def translation_keys
148
- @translation_keys ||= {}
149
- end
150
-
151
- def translation_key(key)
152
- translation_keys[key]
153
- end
154
-
155
- def cache_translation_key(tkey)
156
- cached_key = translation_key(tkey.key)
157
-
158
- if cached_key
159
- # move translations from tkey to the cached key
160
- tkey.translations.each do |locale, translations|
161
- cached_key.set_language_translations(language(locale), translations)
162
- end
163
- return cached_key
164
- end
165
-
166
- tkey.set_application(self)
167
- @translation_keys[tkey.key] = tkey
168
- end
169
-
170
- def cache_translation_keys(tkeys)
171
- tkeys.each do |tkey|
172
- cache_translation_key(tkey)
173
- end
174
- end
175
-
176
- def reset_translation_cache
177
- @translation_keys = {}
178
- @sources_by_key = {}
179
- @components_by_key = {}
120
+ self.components[key] ||= api_client.post('components/register', {:component => key}, {:class => Tr8n::Component, :attributes => {:application => self}})
180
121
  end
181
122
 
182
123
  def register_missing_key(source_key, tkey)
124
+ return if Tr8n.cache.read_only? and not Tr8n.session.inline_mode?
125
+
183
126
  @missing_keys_by_sources ||= {}
184
127
  @missing_keys_by_sources[source_key] ||= {}
185
128
  @missing_keys_by_sources[source_key][tkey.key] ||= tkey
@@ -188,12 +131,14 @@ class Tr8n::Application < Tr8n::Base
188
131
 
189
132
  def register_keys(keys)
190
133
  params = []
191
- keys.each do |source, keys|
134
+ keys.each do |source_key, keys|
192
135
  next unless keys.values.any?
193
- params << {:source => source, :keys => keys.values.collect{|tkey| tkey.to_hash(:label, :description, :locale, :level)}}
136
+ source = Tr8n::Source.new(:source => source_key, :application => self)
137
+ params << {:source => source_key, :keys => keys.values.collect{|tkey| tkey.to_hash(:label, :description, :locale, :level)}}
138
+ source.reset_cache
194
139
  end
195
140
 
196
- api_client.post('source/register_keys', {:source_keys => params.to_json})
141
+ api_client.post('sources/register_keys', {:source_keys => params.to_json})
197
142
  rescue Tr8n::Exception => e
198
143
  Tr8n.logger.error('Failed to register missing translation keys...')
199
144
  Tr8n.logger.error(e)
@@ -208,14 +153,82 @@ class Tr8n::Application < Tr8n::Base
208
153
 
209
154
  def featured_languages
210
155
  @featured_languages ||= begin
211
- locales = api_client.get("application/featured_locales", {}, {:cache_key => "featured_locales"})
212
- # use app languages, there is no need for rules for this call
156
+ locales = api_client.get('applications/current/featured_locales', {}, {:cache_key => 'featured_locales'})
213
157
  (locales.nil? or locales.empty?) ? [] : languages.select{|l| locales.include?(l.locale)}
214
158
  end
159
+ rescue
160
+ []
215
161
  end
216
162
 
217
163
  def translators
218
- @translators ||= api_client.get("application/translators", {}, {:class => Tr8n::Translator, :attributes => {:application => self}})
164
+ @translators ||= api_client.get('applications/current/translators', {}, {:class => Tr8n::Translator, :attributes => {:application => self}})
165
+ rescue
166
+ []
167
+ end
168
+
169
+ def reset_translation_cache
170
+ self.sources = {}
171
+ self.translations = {}
172
+ @languages_by_locale = nil
173
+ @missing_keys_by_sources = nil
174
+ end
175
+
176
+ def fetch_translations(locale)
177
+ self.translations ||= {}
178
+ self.translations[locale] ||= begin
179
+ results = Tr8n.cache.fetch(Tr8n::Application.translations_cache_key(locale)) do
180
+ data = {}
181
+ unless Tr8n.cache.read_only?
182
+ api_client.paginate('applications/current/translations', :per_page => 1000) do |translations|
183
+ data.merge!(translations)
184
+ end
185
+ end
186
+ data
187
+ end
188
+
189
+ translations_by_key = {}
190
+ results.each do |key, data|
191
+ translations_data = data.is_a?(Hash) ? data['translations'] : data
192
+ translations_by_key[key] = translations_data.collect do |t|
193
+ Tr8n::Translation.new(
194
+ :locale => t['locale'] || locale,
195
+ :label => t['label'],
196
+ :context => t['context']
197
+ )
198
+ end
199
+ end
200
+ translations_by_key
201
+ end
202
+ rescue Tr8n::Exception => ex
203
+ {}
204
+ end
205
+
206
+ def cache_translations(locale, key, new_translations)
207
+ self.translations ||= {}
208
+ self.translations[locale] ||= {}
209
+ self.translations[locale][key] = new_translations.collect do |t|
210
+ Tr8n::Translation.new(
211
+ :locale => t['locale'] || locale,
212
+ :label => t['label'],
213
+ :context => t['context']
214
+ )
215
+ end
216
+ end
217
+
218
+ def cached_translations(locale, key)
219
+ return unless self.translations and self.translations[locale]
220
+ self.translations[locale][key]
221
+ end
222
+
223
+ def debug_translations
224
+ return 'no translations' unless self.translations
225
+ self.translations.each do |locale, keys|
226
+ pp [locale, keys.collect{|key, translations|
227
+ [key, translations.collect{|t|
228
+ [t.label, t.context]
229
+ }]
230
+ }]
231
+ end
219
232
  end
220
233
 
221
234
  def default_decoration_token(token)
@@ -230,12 +243,12 @@ class Tr8n::Application < Tr8n::Base
230
243
  hash_value(features, key.to_s)
231
244
  end
232
245
 
233
- #######################################################################################################
234
- ## API Methods
235
- #######################################################################################################
236
-
237
246
  def api_client
238
- @api_client ||= Tr8n::ApiClient.new(:application => self)
247
+ @api_client ||= Tr8n::Api::Client.new(:application => self)
248
+ end
249
+
250
+ def postoffice
251
+ @postoffice ||= Tr8n::Api::PostOffice.new(:application => self)
239
252
  end
240
253
 
241
254
  end