tr8n_core 4.0.17 → 4.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.
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
@@ -59,7 +59,7 @@ class Tr8n::TranslationKey < Tr8n::Base
59
59
  end
60
60
  end
61
61
 
62
- def self.generate_key(label, desc = "")
62
+ def self.generate_key(label, desc = '')
63
63
  "#{Digest::MD5.hexdigest("#{label};;;#{desc}")}~"[0..-2].to_s
64
64
  end
65
65
 
@@ -67,39 +67,27 @@ class Tr8n::TranslationKey < Tr8n::Base
67
67
  translations and translations[language.locale] and translations[language.locale].any?
68
68
  end
69
69
 
70
- def fetch_translations(language, options = {})
71
- return self if self.id and has_translations_for_language?(language)
72
-
73
- if options[:dry] or Tr8n.session.block_options[:dry]
74
- return application.cache_translation_key(self)
70
+ def set_translations(locale, translations)
71
+ translations.each do |translation|
72
+ translation.locale ||= locale
73
+ translation.translation_key = self
74
+ translation.language = self.application.language(translation.locale)
75
75
  end
76
-
77
- tkey = application.post("translation_key/translations",
78
- {:key => key, :label => label, :description => description, :locale => language.locale},
79
- {:class => Tr8n::TranslationKey, :attributes => {:application => application}})
80
-
81
- application.cache_translation_key(tkey)
76
+ self.translations[locale] = translations
82
77
  end
83
78
 
84
79
  # switches to a new application
85
80
  def set_application(app)
86
81
  self.application = app
87
82
  translations.values.each do |locale_translations|
88
- locale_translations.each do |t|
89
- t.set_translation_key(self)
83
+ locale_translations.each do |translation|
84
+ translation.translation_key = self
85
+ translation.language = self.application.language(translation.locale)
90
86
  end
91
87
  end
92
88
  self
93
89
  end
94
90
 
95
- def set_language_translations(language, translations)
96
- translations.each do |translation|
97
- translation.locale = language.locale
98
- translation.set_translation_key(self)
99
- end
100
- self.translations[language.locale] = translations
101
- end
102
-
103
91
  ###############################################################
104
92
  ## Translation Methods
105
93
  ###############################################################
@@ -30,31 +30,29 @@
30
30
  # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
31
31
  #++
32
32
 
33
- require 'digest/md5'
34
-
35
33
  class Tr8n::Translator < Tr8n::Base
36
34
  belongs_to :application
37
- attributes :id, :name, :email, :gender, :mugshot, :link, :inline, :features
35
+ attributes :id, :name, :email, :gender, :mugshot, :link, :inline, :features, :image_url
38
36
  attributes :voting_power, :rank, :level, :locale, :manager, :code, :access_token
39
37
 
40
38
  def self.authorize(application, username, password, options = {})
41
- data = application.get('oauth/request_token', {:grant_type => :password, :username => username, :password => password})
39
+ data = application.api_client.get('oauth/request_token', {:grant_type => :password, :username => username, :password => password})
42
40
  init(application, data['access_token'])
43
41
  end
44
42
 
45
43
  def self.init(application, access_token)
46
- application.get('translator', {:access_token => access_token}, {:class => Tr8n::Translator, :attributes => {
44
+ application.api_client.get('translator', {:access_token => access_token}, {:class => Tr8n::Translator, :attributes => {
47
45
  :application => application,
48
46
  :access_token => access_token
49
47
  }})
50
48
  end
51
49
 
52
50
  def applications
53
- application.get("translator/applications", {:access_token => access_token}, {:class => Tr8n::Application})
51
+ application.api_client.get('translator/applications', {:access_token => access_token}, {:class => Tr8n::Application})
54
52
  end
55
53
 
56
54
  def translations
57
- application.get("translator/translations", {:access_token => access_token}, {:class => Tr8n::Application})
55
+ application.api_client.get('translator/translations', {:access_token => access_token}, {:class => Tr8n::Application})
58
56
  end
59
57
 
60
58
  def feature_enabled?(key)
@@ -62,12 +60,6 @@ class Tr8n::Translator < Tr8n::Base
62
60
  hash_value(features, key)
63
61
  end
64
62
 
65
- def mugshot_url
66
- return nil unless email
67
- gravatar_id = Digest::MD5.hexdigest(email.downcase)
68
- "http://gravatar.com/avatar/#{gravatar_id}.png?s=48"
69
- end
70
-
71
63
  def inline?
72
64
  return Tr8n.session.block_options[:inline] unless Tr8n.session.block_options[:inline].nil?
73
65
  super
data/lib/tr8n/utils.rb CHANGED
@@ -105,11 +105,15 @@ module Tr8n
105
105
  signed_request = URI::decode(signed_request)
106
106
  signed_request = Base64.decode64(signed_request)
107
107
 
108
- encoded_sig, payload = signed_request.split('.', 2)
108
+ parts = signed_request.split('.')
109
+ return JSON.parse(Base64.decode64(parts.first)) if parts.size == 1
110
+
111
+ encoded_sig = parts.first
112
+ payload = parts.last
109
113
  expected_sig = OpenSSL::HMAC.digest('sha256', secret, payload)
110
114
  expected_sig = Base64.encode64(expected_sig)
111
115
  if expected_sig != encoded_sig
112
- raise Tr8n::Exception.new("Bad signature")
116
+ raise Tr8n::Exception.new('Bad signature')
113
117
  end
114
118
 
115
119
  JSON.parse(Base64.decode64(payload))
data/lib/tr8n_core.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  # encoding: UTF-8
2
2
  #--
3
- # Copyright (c) 2014 Michael Berkovich, TranslationExchange.com
3
+ # Copyright (c) 2015 Translation Exchange Inc. http://translationexchange.com
4
4
  #
5
5
  # _______ _ _ _ ______ _
6
6
  # |__ __| | | | | (_) | ____| | |
@@ -38,6 +38,7 @@ module Tr8nCore
38
38
  end
39
39
 
40
40
  module Tr8n
41
+ module Api end
41
42
  module Tokens end
42
43
  module Tokenizers end
43
44
  module Rules end
@@ -45,7 +46,7 @@ module Tr8n
45
46
  module CacheAdapters end
46
47
  end
47
48
 
48
- %w(tr8n/base.rb tr8n tr8n/rules_engine tr8n/tokens tr8n/tokenizers tr8n/decorators tr8n/cache_adapters tr8n/cache tr8n/cache/generators tr8n_core/ext tr8n_core/modules tr8n_core/generators/cache).each do |f|
49
+ %w(tr8n/base.rb tr8n tr8n/api tr8n/rules_engine tr8n/tokens tr8n/tokenizers tr8n/decorators tr8n/cache_adapters tr8n/cache tr8n/cache/generators tr8n_core/ext tr8n_core/modules tr8n_core/generators/cache).each do |f|
49
50
  if f.index('.rb')
50
51
  require(File.expand_path(File.join(File.dirname(__FILE__), f)))
51
52
  next
@@ -1,5 +1,5 @@
1
1
  #--
2
- # Copyright (c) 2014 Michael Berkovich, TranslationExchange.com
2
+ # Copyright (c) 2015 Translation Exchange Inc. http://translationexchange.com
3
3
  #
4
4
  # _______ _ _ _ ______ _
5
5
  # |__ __| | | | | (_) | ____| | |
@@ -1,5 +1,5 @@
1
1
  #--
2
- # Copyright (c) 2014 Michael Berkovich, TranslationExchange.com
2
+ # Copyright (c) 2015 Translation Exchange Inc. http://translationexchange.com
3
3
  #
4
4
  # _______ _ _ _ ______ _
5
5
  # |__ __| | | | | (_) | ____| | |
@@ -69,7 +69,6 @@ class Date
69
69
  end
70
70
  end
71
71
 
72
-
73
72
  tokens = {}
74
73
  selected_tokens.each do |token|
75
74
  case token
@@ -1,5 +1,5 @@
1
1
  #--
2
- # Copyright (c) 2014 Michael Berkovich, TranslationExchange.com
2
+ # Copyright (c) 2015 Translation Exchange Inc. http://translationexchange.com
3
3
  #
4
4
  # _______ _ _ _ ______ _
5
5
  # |__ __| | | | | (_) | ____| | |
@@ -1,5 +1,5 @@
1
1
  #--
2
- # Copyright (c) 2014 Michael Berkovich, TranslationExchange.com
2
+ # Copyright (c) 2015 Translation Exchange Inc. http://translationexchange.com
3
3
  #
4
4
  # _______ _ _ _ ______ _
5
5
  # |__ __| | | | | (_) | ____| | |
@@ -1,5 +1,5 @@
1
1
  #--
2
- # Copyright (c) 2014 Michael Berkovich, TranslationExchange.com
2
+ # Copyright (c) 2015 Translation Exchange Inc. http://translationexchange.com
3
3
  #
4
4
  # _______ _ _ _ ______ _
5
5
  # |__ __| | | | | (_) | ____| | |
@@ -1,5 +1,5 @@
1
1
  #--
2
- # Copyright (c) 2014 Michael Berkovich, TranslationExchange.com
2
+ # Copyright (c) 2015 Translation Exchange Inc. http://translationexchange.com
3
3
  #
4
4
  # _______ _ _ _ ______ _
5
5
  # |__ __| | | | | (_) | ____| | |
@@ -1,5 +1,5 @@
1
1
  #--
2
- # Copyright (c) 2014 Michael Berkovich, TranslationExchange.com
2
+ # Copyright (c) 2015 Translation Exchange Inc. http://translationexchange.com
3
3
  #
4
4
  # _______ _ _ _ ______ _
5
5
  # |__ __| | | | | (_) | ____| | |
@@ -34,19 +34,25 @@ class Tr8nCore::Generators::Cache::Base
34
34
  attr_accessor :started_at, :finished_at
35
35
 
36
36
  def log(msg)
37
- Tr8n.logger.debug("#{Time.now.strftime('%Y-%m-%d %H:%M:%S')}: #{msg}\n")
37
+ msg = "#{Time.now.strftime('%Y-%m-%d %H:%M:%S')}: #{msg}"
38
+ puts msg
39
+ Tr8n.logger.debug(msg)
38
40
  end
39
41
 
40
42
  def cache_path
41
- raise Tr8n::Exception.new("Must be implemented by the subclass")
43
+ raise Tr8n::Exception.new('Must be implemented by the subclass')
44
+ end
45
+
46
+ def cache_version
47
+ @started_at.strftime('%Y%m%d%H%M%S')
42
48
  end
43
49
 
44
50
  def cache(key, data)
45
- raise Tr8n::Exception.new("Must be implemented by the subclass")
51
+ raise Tr8n::Exception.new('Must be implemented by the subclass')
46
52
  end
47
53
 
48
54
  def execute
49
- raise Tr8n::Exception.new("Must be implemented by the subclass")
55
+ raise Tr8n::Exception.new('Must be implemented by the subclass')
50
56
  end
51
57
 
52
58
  def run
@@ -57,39 +63,55 @@ class Tr8nCore::Generators::Cache::Base
57
63
 
58
64
  def prepare
59
65
  @started_at = Time.now
66
+ Tr8n.session.init
67
+ cache_path
68
+ end
69
+
70
+ def api_client
71
+ Tr8n.session.application.api_client
72
+ end
73
+
74
+ def application
75
+ @application ||= api_client.get('applications/current', {:definition => true})
76
+ end
77
+
78
+ def languages
79
+ application['languages']
60
80
  end
61
81
 
62
82
  def finalize
63
83
  @finished_at = Time.now
64
84
  log("Cache has been stored in #{cache_path}")
65
85
  log("Cache generation took #{@finished_at - @started_at} mls.")
66
- log("Done.")
86
+ log('Done.')
67
87
  end
68
88
 
69
89
  def cache_application
70
- log("Downloading application...")
71
- app = Tr8n.session.application.get("application", :definition => true)
72
- cache(Tr8n::Application.cache_key(app["key"]), app)
73
- log("Application has been cached.")
74
- app
90
+ log('Downloading application...')
91
+ cache(Tr8n::Application.cache_key, application)
92
+ log('Application has been cached.')
75
93
  end
76
94
 
77
95
  def cache_languages
78
- log("Downloading languages...")
79
- languages = Tr8n.session.application.get("application/languages", :definition => true)
96
+ log('Downloading languages...')
97
+ unless application['languages']
98
+ log('No languages are available...')
99
+ return
100
+ end
80
101
  languages.each do |lang|
81
- cache(Tr8n::Language.cache_key(lang["locale"]), lang)
102
+ language = api_client.get("languages/#{lang['locale']}", :definition => true)
103
+ cache(Tr8n::Language.cache_key(language['locale']), language)
82
104
  end
83
- log("#{languages.count} languages have been cached.")
84
- languages
105
+ log("#{application['languages'].count} languages have been cached.")
85
106
  end
86
107
 
87
108
  def symlink_path
88
- raise Tr8n::Exception.new("Must be implemented by the subclass")
109
+ "#{Tr8n.config.cache[:path]}/current"
89
110
  end
90
111
 
91
112
  def generate_symlink
92
113
  FileUtils.rm(symlink_path) if File.exist?(symlink_path)
93
- FileUtils.ln_s(cache_path, symlink_path)
114
+ FileUtils.ln_s(cache_version, symlink_path)
115
+ log('Symlink has been updated.')
94
116
  end
95
117
  end
@@ -1,5 +1,5 @@
1
1
  #--
2
- # Copyright (c) 2014 Michael Berkovich, TranslationExchange.com
2
+ # Copyright (c) 2015 Translation Exchange Inc. http://translationexchange.com
3
3
  #
4
4
  # _______ _ _ _ ______ _
5
5
  # |__ __| | | | | (_) | ____| | |
@@ -1,5 +1,5 @@
1
1
  #--
2
- # Copyright (c) 2014 Michael Berkovich, TranslationExchange.com
2
+ # Copyright (c) 2015 Translation Exchange Inc. http://translationexchange.com
3
3
  #
4
4
  # _______ _ _ _ ______ _
5
5
  # |__ __| | | | | (_) | ____| | |
@@ -33,7 +33,7 @@ class Tr8nCore::Generators::Cache::File < Tr8nCore::Generators::Cache::Base
33
33
 
34
34
  def cache_path
35
35
  @cache_path ||= begin
36
- path = "#{Tr8n.config.cache[:path]}/files/tr8n_#{Tr8n.session.application.key}_#{@started_at.strftime('%Y_%m_%d_%H_%M_%S')}"
36
+ path = "#{Tr8n.config.cache[:path]}/#{cache_version}"
37
37
  log("Cache will be stored in #{path}")
38
38
  FileUtils.mkdir_p(path)
39
39
  FileUtils.chmod(0777, path)
@@ -42,40 +42,118 @@ class Tr8nCore::Generators::Cache::File < Tr8nCore::Generators::Cache::Base
42
42
  end
43
43
 
44
44
  def file_path(key)
45
- "#{cache_path}/#{Tr8n::CacheAdapters::File.file_name(key)}"
45
+ path = key.split('/')
46
+ if path.count > 1
47
+ filename = path.pop
48
+ path = File.join(cache_path, path)
49
+ FileUtils.mkdir_p(path)
50
+ File.join(path, "#{filename}.json")
51
+ else
52
+ File.join(cache_path, "#{path.first}.json")
53
+ end
46
54
  end
47
55
 
48
56
  def cache(key, data)
49
57
  File.open(file_path(key), 'w') { |file| file.write(JSON.pretty_generate(data)) }
50
58
  end
51
59
 
52
- def symlink_path
53
- Tr8n::CacheAdapters::File.cache_path
54
- end
55
-
56
60
  def execute
57
- Tr8n.session.init_application
58
61
  cache_application
59
- @languages = cache_languages
62
+ cache_languages
60
63
  cache_translations
61
64
  generate_symlink
62
65
  end
63
66
 
64
67
  def cache_translations
65
- log("Downloading translations...")
66
- sources = Tr8n.config.application.get("application/sources")
67
- @languages.each do |language|
68
- log("--------------------------------------------------------------")
69
- log("Downloading #{language["locale"]} language...")
70
- log("--------------------------------------------------------------")
71
-
72
- sources.each do |source|
73
- log("Downloading #{source["source"]} in #{language["locale"]}...")
74
- translation_keys = Tr8n.session.application.get("source/translations", {:source => source["source"], :locale => language["locale"]})
75
- data = {:source => source["source"], :translation_keys => translation_keys}
76
- cache(Tr8n::Source.cache_key(source["source"], language["locale"]), data)
68
+ log('Downloading translations...')
69
+
70
+ languages.each do |language|
71
+ log("Downloading #{language['english_name']} language...")
72
+
73
+ if Tr8n.config.cache[:segmented]
74
+ api_client.paginate('applications/current/sources') do |source|
75
+ next unless source['source']
76
+
77
+ cache_path = Tr8n::Source.cache_key(language['locale'], source['source'])
78
+ log("Downloading #{source['source']} in #{language['locale']} to #{cache_path}...")
79
+
80
+ data = api_client.get("sources/#{source['key']}/translations", {:locale => language['locale'], :original => true, :per_page => 1000})
81
+ cache(cache_path, data)
82
+ end
83
+ else
84
+ cache_path = Tr8n::Application.translations_cache_key(language['locale'])
85
+ log("Downloading translations in #{language['locale']} to #{cache_path}...")
86
+ data = {}
87
+ api_client.paginate('applications/current/translations', {:locale => language['locale'], :original => true, :per_page => 1000}) do |translations|
88
+ data.merge!(translations)
89
+ end
90
+ cache(cache_path, data)
77
91
  end
78
92
  end
79
93
  end
80
94
 
95
+ def rollback
96
+ folders = Dir["#{Tr8n.config.cache[:path]}/*"]
97
+ folders.delete_if{|e| e.index('current')}.sort!
98
+
99
+ if File.exist?(symlink_path)
100
+ current_dest = File.readlink("#{Tr8n.config.cache[:path]}/current")
101
+ current_dest = "#{Tr8n.config.cache[:path]}/#{current_dest}"
102
+ else
103
+ current_dest = 'undefined'
104
+ end
105
+
106
+ index = folders.index(current_dest)
107
+
108
+ if index == 0
109
+ log('There are no earlier cache versions')
110
+ return
111
+ end
112
+
113
+ if index.nil?
114
+ new_version_path = folders[folders.size-1]
115
+ else
116
+ new_version_path = folders[index-1]
117
+ end
118
+
119
+ new_version_path = new_version_path.split('/').last
120
+
121
+ FileUtils.rm(symlink_path) if File.exist?(symlink_path)
122
+ FileUtils.ln_s(new_version_path, symlink_path)
123
+
124
+ log("Cache has been rolled back to version #{new_version_path}.")
125
+ end
126
+
127
+ def rollup
128
+ folders = Dir["#{Tr8n.config.cache[:path]}/*"]
129
+ folders.delete_if{|e| e.index('current')}.sort!
130
+
131
+ if File.exist?(symlink_path)
132
+ current_dest = File.readlink("#{Tr8n.config.cache[:path]}/current")
133
+ current_dest = "#{Tr8n.config.cache[:path]}/#{current_dest}"
134
+ else
135
+ current_dest = 'undefined'
136
+ end
137
+
138
+ index = folders.index(current_dest)
139
+
140
+ if index == (folders.size - 1)
141
+ log('You are on the latest version of the cache already. No further versions are available')
142
+ return
143
+ end
144
+
145
+ if index.nil?
146
+ new_version_path = folders[0]
147
+ else
148
+ new_version_path = folders[index+1]
149
+ end
150
+
151
+ new_version_path = new_version_path.split('/').last
152
+
153
+ FileUtils.rm(symlink_path) if File.exist?(symlink_path)
154
+ FileUtils.ln_s(new_version_path, symlink_path)
155
+
156
+ log("Cache has been upgraded to version #{new_version_path}.")
157
+ end
158
+
81
159
  end