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
@@ -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