lit 1.1.2 → 1.1.6

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4d3b3569eb99f453aea4b65451511bdeb76680774b664ab108f445359b9e10f0
4
- data.tar.gz: cbf55f8eefb23231f5201087e612a58172e2ce4537fc0c8211a597ebba8e5f88
3
+ metadata.gz: 1bda244665d30fcad8f9ad16a593e47ffd6cf54d8d7c9a6a777d5038bad75f1b
4
+ data.tar.gz: 7217df2945e7a5b1813d2a4892eebf46fcf8a97cdd8e9d8648c7a23a2962715f
5
5
  SHA512:
6
- metadata.gz: be93a781bdea6ff7a095bd86a60fc671c5f325f6d6f37a45bfea883b549f3655c4d9d5e768b125181501b944303dccc89d3032180952f4f870a8878bc7d6816d
7
- data.tar.gz: 8655233c8aba69f06bf775bd28df3bc7e17f81f4378dab0f8818c6fac05e22e521ef966c5ae3706dfc3f2552d747687d22c241422f51aeab1f34764bc30bd698
6
+ metadata.gz: 5b6f9f9d65dc9463316c0abd3a56ad2ddcff9a56b6a8a4ed86b4fc6a1b526ac90b46298adf5109d40d58eccd2f5b5164f5e5f4ef424787b156c7248d6f94c2a1
7
+ data.tar.gz: 3f7888ee62c7c037b32d83ca184cc06715e90366a789f7c39f51f4205d1f0134aa8460755228f169e66d3b1724e23bf87f2b88589f34f09d7f68a02453158743
data/README.md CHANGED
@@ -22,9 +22,14 @@ Highly inspired by Copycopter by thoughtbot.
22
22
  9. (On request) stores paths where translation keys were called
23
23
  10. (On request) is able to show all translation keys used to render current page
24
24
 
25
+
25
26
  ### Screenshots
26
27
 
27
- Check wiki: [Screenshots](https://github.com/prograils/lit/wiki/Screenshots)
28
+ [Feature overview on YouTube](https://www.youtube.com/watch?v=_T9Kg05VvLI)
29
+
30
+ ![lit live translation](https://prograils-com-stuff.s3.amazonaws.com/lit/lit-front.gif)
31
+
32
+ Check wiki for more: [Screenshots](https://github.com/prograils/lit/wiki/Screenshots)
28
33
 
29
34
  ### Installation
30
35
 
@@ -130,6 +135,10 @@ Lit::CloudTranslation.provider = Lit::CloudTranslation::Providers::Google
130
135
  ```
131
136
  gem 'google-cloud-translate', '~> 1.2.4'
132
137
  ```
138
+ ...we also support V2 of Google Cloud Translate gem, should you need it:
139
+ ```
140
+ gem 'google-cloud-translate', '~> 2.1.2'
141
+ ```
133
142
 
134
143
  To use translation via Google, you need to obtain a [service account key](https://cloud.google.com/iam/docs/creating-managing-service-account-keys) containing all the credentials required by the API.
135
144
 
@@ -199,17 +208,17 @@ Also applies to upgrading from `0.4.pre.alpha` versions.
199
208
 
200
209
  1. Add `Lit::FrontendHelper` to your `ApplicationController`
201
210
 
202
- ```ruby
203
- helper Lit::FrontendHelper
204
- ```
211
+ ```ruby
212
+ helper Lit::FrontendHelper
213
+ ```
205
214
 
206
215
  2. In you layout file include lit assets
207
216
 
208
- ```erb
209
- <% if admin_user_signed_in? %>
210
- <%= lit_frontend_assets %>
211
- <% end %>
212
- ```
217
+ ```erb
218
+ <% if admin_user_signed_in? %>
219
+ <%= lit_frontend_assets %>
220
+ <% end %>
221
+ ```
213
222
 
214
223
  3. You're good to go - now log in to lit (if required) and open your frontend in separate tab (to have session persisted). On the bottom-right of your page you should see "Enable / disable lit highlight" - after enabling it you'll be able to click and translate phrases directly in your frontend
215
224
 
@@ -217,13 +226,14 @@ Also applies to upgrading from `0.4.pre.alpha` versions.
217
226
 
218
227
  5. This feature requires jQuery! (at least for now)
219
228
 
229
+
220
230
  ### Storing request info
221
231
 
222
- 1. Include `Lit::Concerns::RequestInfoStore` concern in your `ApplicationController`
232
+ 1. Include `Lit::RequestInfoStore` concern in your `ApplicationController`
223
233
 
224
- ```ruby
225
- include Lit::Concerns::RequestInfoStore
226
- ```
234
+ ```ruby
235
+ include Lit::RequestInfoStore
236
+ ```
227
237
 
228
238
  2. In lit initializer (`lit.rb`) set `store_request_info` config to true
229
239
 
@@ -238,25 +248,31 @@ Lit.store_request_info = true
238
248
 
239
249
  1. Add `Lit::FrontendHelper` in your `ApplicationController`
240
250
 
241
- ```ruby
242
- include Lit::FrontendHelper
243
- ```
251
+ ```ruby
252
+ helper Lit::FrontendHelper
253
+ ```
254
+
255
+ 2. Include `Lit::RequestKeysStore` concern in your `ApplicationController`
256
+
257
+ ```ruby
258
+ include Lit::RequestKeysStore
259
+ ```
244
260
 
245
- 2. Include `Lit::Concerns::RequestKeysStore` concern in your `ApplicationController`
261
+ 3. Enable storing of request keys in lit initializer `config/initializers/lit.rb`
246
262
 
247
- ```ruby
248
- include Lit::Concerns::RequestKeysStore
249
- ```
263
+ ```ruby
264
+ Lit.store_request_keys = true
265
+ ```
250
266
 
251
- 3. On the bottom of you layout file call `lit_translations_info` helper function
267
+ 4. On the bottom of you layout file call `lit_translations_info` helper function
252
268
 
253
- ```erb
254
- <%= lit_translations_info %>
255
- ```
269
+ ```erb
270
+ <%= lit_translations_info %>
271
+ ```
256
272
 
257
- 4. From now on you'll be able to see all translation keys that were used to render current page. This feature works great with on-site live translations!
273
+ 5. From now on you'll be able to see all translation keys that were used to render current page. This feature works great with on-site live translations!
258
274
 
259
- 5. Lit authorized user must be signed in for this feature to work! This feature requires jQuery!
275
+ 6. Lit authorized user must be signed in for this feature to work! This feature requires jQuery!
260
276
 
261
277
 
262
278
 
@@ -1,9 +1,11 @@
1
1
  .lit-key-generic {
2
2
  }
3
- .lit-key-highlight{
4
- text-decoration: underline wavy red !important;
3
+ .lit-key-highlight {
4
+ text-decoration: underline !important;
5
+ text-decoration-color: red !important;
6
+ text-decoration-style: wavy !important;
5
7
  }
6
- #lit_button_wrapper{
8
+ #lit_button_wrapper {
7
9
  position: fixed;
8
10
  bottom: 20px;
9
11
  right: 20px;
@@ -15,16 +17,15 @@
15
17
  cursor: pointer;
16
18
  color: white;
17
19
  }
18
- #lit_button_wrapper.lit-highlight-enabled{
20
+ #lit_button_wrapper.lit-highlight-enabled {
19
21
  background-color: lightgreen;
20
22
  }
21
- #lit_textarea{
23
+ #lit_textarea {
22
24
  position: absolute;
23
25
  padding: 0 0 1px 0;
24
26
  margin: 0 0 0 0;
25
27
  border: 0;
26
28
  border-bottom: 1px solid red;
27
-
28
29
  }
29
30
  .lit-translations-info.collapsed {
30
31
  position: fixed;
@@ -38,7 +39,7 @@
38
39
  cursor: pointer;
39
40
  color: white;
40
41
  }
41
- .lit-translations-info.expanded{
42
+ .lit-translations-info.expanded {
42
43
  position: absolute;
43
44
  display: block;
44
45
  width: 80%;
@@ -52,16 +53,16 @@
52
53
  z-index: 90;
53
54
  }
54
55
 
55
- .lit-translations-info.collapsed span.lit-open-button{
56
+ .lit-translations-info.collapsed span.lit-open-button {
56
57
  display: block;
57
58
  }
58
- .lit-translations-info.expanded span.lit-open-button{
59
+ .lit-translations-info.expanded span.lit-open-button {
59
60
  display: none;
60
61
  }
61
- .lit-translations-info.collapsed span.lit-close-button{
62
+ .lit-translations-info.collapsed span.lit-close-button {
62
63
  display: none;
63
64
  }
64
- .lit-translations-info.expanded span.lit-close-button{
65
+ .lit-translations-info.expanded span.lit-close-button {
65
66
  display: block;
66
67
  position: fixed;
67
68
  right: 10%;
@@ -71,16 +72,16 @@
71
72
  background-color: white;
72
73
  padding: 10px 10px 5px;
73
74
  }
74
- .lit-translations-info.collapsed ul.lit-translations-list{
75
+ .lit-translations-info.collapsed ul.lit-translations-list {
75
76
  display: none;
76
77
  }
77
- .lit-translations-info.expanded ul.lit-translations-list{
78
+ .lit-translations-info.expanded ul.lit-translations-list {
78
79
  }
79
80
 
80
- .lit-translations-info.expanded ul.lit-translations-list li{
81
+ .lit-translations-info.expanded ul.lit-translations-list li {
81
82
  margin: 5px;
82
83
  }
83
84
 
84
- .lit-translations-info.expanded #lit_textarea{
85
+ .lit-translations-info.expanded #lit_textarea {
85
86
  padding: 2px;
86
87
  }
@@ -1,18 +1,3 @@
1
- module Lit
2
- module RequestInfoStore
3
- extend ::ActiveSupport::Concern
4
- included do
5
- before_action :store_request_path
6
- end
7
-
8
- private
9
-
10
- def store_request_path
11
- Thread.current[:lit_current_request_path] = request&.path
12
- end
13
- end
14
- end
15
-
16
1
  module Lit::Concerns::RequestInfoStore
17
2
  extend ActiveSupport::Concern
18
3
 
@@ -1,18 +1,3 @@
1
- module Lit
2
- module RequestKeysStore
3
- extend ::ActiveSupport::Concern
4
- included do
5
- before_action :init_request_keys
6
- end
7
-
8
- private
9
-
10
- def init_request_keys
11
- Thread.current[:lit_request_keys] = {}
12
- end
13
- end
14
- end
15
-
16
1
  module Lit::Concerns::RequestKeysStore
17
2
  extend ActiveSupport::Concern
18
3
 
@@ -0,0 +1,10 @@
1
+ module Lit::RequestInfoStore
2
+ extend ::ActiveSupport::Concern
3
+ included { before_action :store_request_path }
4
+
5
+ private
6
+
7
+ def store_request_path
8
+ Thread.current[:lit_current_request_path] = request&.path
9
+ end
10
+ end
@@ -0,0 +1,10 @@
1
+ module Lit::RequestKeysStore
2
+ extend ::ActiveSupport::Concern
3
+ included { before_action :init_request_keys }
4
+
5
+ private
6
+
7
+ def init_request_keys
8
+ Thread.current[:lit_request_keys] = {}
9
+ end
10
+ end
@@ -1,83 +1,95 @@
1
- module Lit
2
- module FrontendHelper
3
- include ActionView::Helpers::TranslationHelper
4
-
5
- module TranslationKeyWrapper
6
- def translate(key, options = {})
7
- count = options[:count]
8
- options = options.with_indifferent_access
9
- key = scope_key_by_partial(key)
10
- key = pluralized_key(key, count) if count
11
-
12
- content = super(key, **options.symbolize_keys)
13
- if !options[:skip_lit] && lit_authorized?
14
- content = get_translateable_span(key, content)
15
- end
16
- content
17
- end
1
+ module Lit::FrontendHelper
2
+ include ActionView::Helpers::TranslationHelper
18
3
 
19
- def pluralized_key(key, count)
20
- pluralizer = I18n.backend.send(:pluralizer, locale)
21
- return unless pluralizer.respond_to?(:call)
22
- last = count.zero? ? :zero : pluralizer.call(count)
23
- format '%<key>s.%<last>s', key: key, last: last
24
- end
4
+ module TranslationKeyWrapper
5
+ def translate(key, options = {})
6
+ count = options[:count]
7
+ options = options.with_indifferent_access
8
+ key = scope_key_by_partial(key)
9
+ key = pluralized_key(key, count) if count
25
10
 
26
- def t(key, options = {})
27
- translate(key, options)
28
- end
11
+ content = super(key, **options.symbolize_keys)
12
+ content = get_translateable_span(key, content) if !options[:skip_lit] && lit_authorized?
13
+ content
29
14
  end
30
- prepend Lit::FrontendHelper::TranslationKeyWrapper
31
15
 
32
- def javascript_lit_tag
33
- javascript_include_tag 'lit/lit_frontend'
16
+ def pluralized_key(key, count)
17
+ pluralizer = I18n.backend.send(:pluralizer, locale)
18
+ return unless pluralizer.respond_to?(:call)
19
+ last = count.zero? ? :zero : pluralizer.call(count)
20
+ format '%<key>s.%<last>s', key: key, last: last
34
21
  end
35
22
 
36
- def stylesheet_lit_tag
37
- stylesheet_link_tag 'lit/lit_frontend'
23
+ def t(key, options = {})
24
+ translate(key, options)
38
25
  end
39
26
 
40
- def lit_frontend_assets
41
- return unless lit_authorized?
42
- meta = content_tag :meta,
43
- '',
44
- value: lit.find_localization_localization_keys_path,
45
- name: 'lit-url-base'
46
- safe_join [javascript_lit_tag, stylesheet_lit_tag, meta]
27
+ def missing_translation(key, options)
28
+ # We try to humanize the key. Rails will do
29
+ # it anyway in below call to super, but then it will wrap it also in
30
+ # translation_missing span.
31
+ # Humanizing key should be last resort
32
+ if Lit::Services::HumanizeService.should_humanize?(key)
33
+ return Lit::Services::HumanizeService.humanize_and_cache(key, options)
34
+ end
35
+
36
+ super(key, options)
47
37
  end
38
+ end
39
+ prepend Lit::FrontendHelper::TranslationKeyWrapper
48
40
 
49
- def lit_translations_info
50
- return if Thread.current[:lit_request_keys].nil?
51
- return unless lit_authorized?
52
- content_tag :div, class: 'lit-translations-info collapsed' do
53
- concat content_tag(:span, 'Show translations', class: 'lit-open-button')
54
- concat content_tag(:span, 'X', class: 'lit-close-button')
55
- concat translations_list_content_tag
56
- end
41
+ def javascript_lit_tag
42
+ javascript_include_tag 'lit/lit_frontend'
43
+ end
44
+
45
+ def stylesheet_lit_tag
46
+ stylesheet_link_tag 'lit/lit_frontend'
47
+ end
48
+
49
+ def lit_frontend_assets
50
+ return unless lit_authorized?
51
+
52
+ meta = content_tag :meta, '', value: lit.find_localization_localization_keys_path, name: 'lit-url-base'
53
+ safe_join [javascript_lit_tag, stylesheet_lit_tag, meta]
54
+ end
55
+
56
+ def lit_translations_info
57
+ return if Thread.current[:lit_request_keys].nil?
58
+ return unless lit_authorized?
59
+
60
+ content_tag :div, class: 'lit-translations-info collapsed' do
61
+ concat content_tag(:span, 'Show translations', class: 'lit-open-button')
62
+ concat content_tag(:span, 'X', class: 'lit-close-button')
63
+ concat translations_list_content_tag
57
64
  end
65
+ end
58
66
 
59
- def translations_list_content_tag
60
- content_tag :ul, class: 'lit-translations-list' do
61
- Lit.init.cache.request_keys.each do |k, v|
62
- concat(content_tag(:li) do
63
- concat content_tag(:code, "#{k}:")
64
- concat get_translateable_span(k, v, alternative_text: '[empty]')
65
- end)
67
+ def translations_list_content_tag
68
+ content_tag :ul, class: 'lit-translations-list' do
69
+ Lit
70
+ .init
71
+ .cache
72
+ .request_keys
73
+ .each do |k, v|
74
+ concat(
75
+ content_tag(:li) do
76
+ concat content_tag(:code, "#{k}:")
77
+ concat get_translateable_span(k, v, alternative_text: '[empty]')
78
+ end,
79
+ )
66
80
  end
67
- end
68
81
  end
82
+ end
69
83
 
70
- def lit_authorized?
71
- return false if Lit.authentication_verification.blank?
72
- send Lit.authentication_verification
73
- end
84
+ def lit_authorized?
85
+ return false if Lit.authentication_verification.blank?
74
86
 
75
- def get_translateable_span(key, localization, alternative_text: nil)
76
- content_tag :span,
77
- class: 'lit-key-generic',
78
- data: { key: key, locale: I18n.locale } do
79
- localization.blank? ? alternative_text : localization
80
- end
87
+ send Lit.authentication_verification
88
+ end
89
+
90
+ def get_translateable_span(key, localization, alternative_text: nil)
91
+ content_tag :span, class: 'lit-key-generic', data: { key: key, locale: I18n.locale } do
92
+ localization.blank? ? alternative_text : localization
81
93
  end
82
94
  end
83
95
  end
@@ -3,7 +3,7 @@
3
3
  # `nil` will let everyone in.
4
4
  Lit.authentication_function = <%= @authentication_function || 'nil' %>
5
5
 
6
- # Which authentication verification function to use (ie. :user_signed_in)?
6
+ # Which authentication verification function to use (ie. :user_signed_in?)?
7
7
  # This is used together with frontend translation module to determine, if
8
8
  # helper button should be applied and translations wrapped in custom span
9
9
  Lit.authentication_verification = <%= @authentication_verification || 'nil' %>
@@ -53,6 +53,11 @@ Lit.set_last_updated_at_upon_creation = true
53
53
  # For more information please check the README.md
54
54
  Lit.store_request_info = false
55
55
 
56
+ # Store request keys - this will store all keys used to render a page. Useful
57
+ # only when combined with Lit::RequestKeysStore concern to view those keys in
58
+ # frontend
59
+ Lit.store_request_keys = false
60
+
56
61
  # Initialize lit
57
62
  Lit.init
58
63
 
@@ -11,24 +11,22 @@ module Lit
11
11
  desc 'Automates Lit installation'
12
12
 
13
13
  def set_authentication_function
14
- @authentication_function = options['authentication-function'].presence ||
15
- ask("What's the authentication function, ie. :authenticate_user! :").presence ||
16
- nil
14
+ @authentication_function =
15
+ options['authentication-function'].presence ||
16
+ ask("What's the authentication function, ie. :authenticate_user! :").presence || nil
17
17
  end
18
18
 
19
19
  def set_key_value_engine
20
- @key_value_engine = options['key-value-engine'].presence ||
21
- ask("What's the key value engine? ([hash] OR redis):").presence ||
22
- :hash
20
+ @key_value_engine =
21
+ options['key-value-engine'].presence || ask("What's the key value engine? ([hash] OR redis):").presence ||
22
+ :hash
23
23
  end
24
24
 
25
25
  def add_redis_dependency
26
26
  if @key_value_engine == 'redis'
27
27
  puts 'Adding redis dependency'
28
28
  gem 'redis'
29
- Bundler.with_clean_env do
30
- run 'bundle install'
31
- end
29
+ Bundler.with_clean_env { run 'bundle install' }
32
30
  end
33
31
  end
34
32
 
@@ -42,7 +40,7 @@ module Lit
42
40
  puts 'Skipping config/initializers/lit.rb creation, file already exists!'
43
41
  else
44
42
  puts 'Adding lit initializer (config/initializers/lit.rb)...'
45
- template 'initializer.rb', path
43
+ template 'initializer.erb', path
46
44
  end
47
45
  end
48
46
 
@@ -1,4 +1,4 @@
1
- module Lit
1
+ module Lit::Adapters
2
2
  class HashStorage < Hash
3
3
  def incr(key)
4
4
  self[key] ||= 0
@@ -25,7 +25,7 @@ module Lit
25
25
 
26
26
  cache_localizations = form_cache_localizations(keys_of_subtree)
27
27
 
28
- full_subtree = Lit::LocalizationKeysToHashService.call(cache_localizations)
28
+ full_subtree = Lit::Services::LocalizationKeysToHashService.call(cache_localizations)
29
29
  requested_part = full_subtree.dig(*key.split('.'))
30
30
  return nil if requested_part.blank?
31
31
  return requested_part if requested_part.is_a?(String)
@@ -13,7 +13,7 @@ module Lit
13
13
  Lit.redis_url || ENV[ENV['REDIS_PROVIDER'] || 'REDIS_URL']
14
14
  end
15
15
 
16
- class RedisStorage
16
+ class Adapters::RedisStorage
17
17
  def initialize
18
18
  Lit.redis
19
19
  end
@@ -44,9 +44,7 @@ module Lit
44
44
  delete(k)
45
45
  if v.is_a?(Array)
46
46
  Lit.redis.set(_prefixed_key_for_array(k), '1')
47
- v.each do |ve|
48
- Lit.redis.rpush(_prefixed_key(k), ve.to_s)
49
- end
47
+ v.each { |ve| Lit.redis.rpush(_prefixed_key(k), ve.to_s) }
50
48
  elsif v.nil?
51
49
  Lit.redis.set(_prefixed_key_for_nil(k), '1')
52
50
  Lit.redis.set(_prefixed_key(k), '')
@@ -79,9 +77,7 @@ module Lit
79
77
  end
80
78
 
81
79
  def sort
82
- Lit.redis.keys.sort.map do |k|
83
- [k, self.[](k)]
84
- end
80
+ Lit.redis.keys.sort.map { |k| [k, self.[](k)] }
85
81
  end
86
82
 
87
83
  def prefix
@@ -119,7 +115,7 @@ module Lit
119
115
  values_of_subtree = Lit.redis.mget(keys_of_subtree)
120
116
  cache_localizations = form_cache_localizations(keys_of_subtree, values_of_subtree)
121
117
 
122
- full_subtree = Lit::LocalizationKeysToHashService.call(cache_localizations)
118
+ full_subtree = Lit::Services::LocalizationKeysToHashService.call(cache_localizations)
123
119
  requested_part = full_subtree.dig(*key.split('.'))
124
120
  return nil if requested_part.blank?
125
121
  return requested_part if requested_part.is_a?(String)
@@ -0,0 +1,2 @@
1
+ module Lit::Adapters
2
+ end
@@ -45,13 +45,10 @@ module Lit::CloudTranslation::Providers
45
45
  # end
46
46
  class Google < Base
47
47
  def translate(text:, from: nil, to:, **opts)
48
- @client ||=
49
- ::Google::Cloud::Translate.new(project_id: config.keyfile_hash['project_id'],
50
- credentials: config.keyfile_hash)
51
- result = @client.translate(sanitize_text(text), from: from, to: to, **opts)
48
+ result = client.translate(sanitize_text(text), from: from, to: to, **opts)
52
49
  unsanitize_text(
53
50
  case result
54
- when ::Google::Cloud::Translate::Translation then result.text
51
+ when translation_class then result.text
55
52
  when Array then result.map(&:text)
56
53
  end
57
54
  )
@@ -67,6 +64,27 @@ module Lit::CloudTranslation::Providers
67
64
 
68
65
  private
69
66
 
67
+ def client
68
+ @client ||= begin
69
+ args = {
70
+ project_id: config.keyfile_hash['project_id'], credentials: config.keyfile_hash,
71
+ version: :v2
72
+ }
73
+ if Gem.loaded_specs['google-cloud-translate'].version < Gem::Version.create('2.0')
74
+ args = args.tap { |hs| hs.delete(:version) }
75
+ end
76
+ ::Google::Cloud::Translate.new(**args)
77
+ end
78
+ end
79
+
80
+ def translation_class
81
+ if Gem.loaded_specs['google-cloud-translate'].version < Gem::Version.create('2.0')
82
+ ::Google::Cloud::Translate::Translation
83
+ else
84
+ ::Google::Cloud::Translate::V2::Translation
85
+ end
86
+ end
87
+
70
88
  def default_config
71
89
  if ENV['GOOGLE_TRANSLATE_API_KEYFILE'].blank?
72
90
  env_keys = ENV.keys.grep(/\AGOOGLE_TRANSLATE_API_/)
@@ -93,7 +111,7 @@ module Lit::CloudTranslation::Providers
93
111
  def sanitize_text(text_or_array)
94
112
  case text_or_array
95
113
  when String
96
- text_or_array.gsub(/%{(.+?)}/, '<code>__LIT__\1__LIT__</code>')
114
+ text_or_array.gsub(/%{(.+?)}/, '<code>__LIT__\1__LIT__</code>').gsub(/\r\n/, '<code>0</code>')
97
115
  when Array
98
116
  text_or_array.map { |s| sanitize_text(s) }
99
117
  when nil
@@ -106,7 +124,7 @@ module Lit::CloudTranslation::Providers
106
124
  def unsanitize_text(text_or_array)
107
125
  case text_or_array
108
126
  when String
109
- text_or_array.gsub(/<code>__LIT__(.+?)__LIT__<\/code>/, '%{\1}')
127
+ text_or_array.gsub(%r{<code>0</code>}, "\r\n").gsub(%r{<code>__LIT__(.+?)__LIT__</code>}, '%{\1}')
110
128
  when Array
111
129
  text_or_array.map { |s| unsanitize_text(s) }
112
130
  else
data/lib/lit/engine.rb CHANGED
@@ -3,7 +3,8 @@ module Lit
3
3
  require 'jquery-rails'
4
4
 
5
5
  config.autoload_paths += %W[#{Lit::Engine.root}/app/controllers/lit/concerns]
6
- paths.add 'lib', eager_load: true # Zeitwerk compatibility
6
+
7
+ paths.add 'lib'
7
8
 
8
9
  isolate_namespace Lit
9
10
 
@@ -13,16 +14,12 @@ module Lit
13
14
  end
14
15
 
15
16
  initializer 'lit.reloader' do |app|
16
- config.to_prepare do
17
- Lit.loader.cache.reset_local_cache if Lit.loader
18
- end
17
+ config.to_prepare { Lit.loader.cache.reset_local_cache if Lit.loader }
19
18
  end
20
19
 
21
20
  initializer 'lit.migrations.append' do |app|
22
21
  unless app.root.to_s.include?(root.to_s)
23
- config.paths['db/migrate'].expanded.each do |expanded_path|
24
- app.config.paths['db/migrate'] << expanded_path
25
- end
22
+ config.paths['db/migrate'].expanded.each { |expanded_path| app.config.paths['db/migrate'] << expanded_path }
26
23
  end
27
24
  end
28
25
 
data/lib/lit/export.rb CHANGED
@@ -4,7 +4,7 @@ require 'lit/services/localization_keys_to_hash_service'
4
4
  module Lit
5
5
  class Export
6
6
  def self.call(locale_keys:, format:, include_hits_count: false)
7
- raise ArgumentError, "format must be yaml or csv" if %i[yaml csv].exclude?(format)
7
+ raise ArgumentError, 'format must be yaml or csv' if %i[yaml csv].exclude?(format)
8
8
  Lit.loader.cache.load_all_translations
9
9
  localizations_scope = Lit::Localization.active
10
10
  if locale_keys.present?
@@ -12,13 +12,11 @@ module Lit
12
12
  localizations_scope = localizations_scope.where(locale_id: locale_ids) unless locale_ids.empty?
13
13
  end
14
14
  db_localizations = {}
15
- localizations_scope.find_each do |l|
16
- db_localizations[l.full_key] = l.translation
17
- end
15
+ localizations_scope.find_each { |l| db_localizations[l.full_key] = l.translation }
18
16
 
19
17
  case format
20
18
  when :yaml
21
- exported_keys = Lit::LocalizationKeysToHashService.call(db_localizations)
19
+ exported_keys = Lit::Services::LocalizationKeysToHashService.call(db_localizations)
22
20
  exported_keys.to_yaml
23
21
  when :csv
24
22
  relevant_locales = locale_keys.presence || I18n.available_locales.map(&:to_s)
@@ -46,9 +44,7 @@ module Lit
46
44
  relevant_locales.map { |l| Array.wrap(db_localizations["#{l}.#{key_without_locale}"]) }
47
45
  transpose(key_localizations_per_locale).each do |translation_series|
48
46
  csv_row = [key_without_locale, *translation_series]
49
- if include_hits_count
50
- csv_row << (Lit.init.cache.get_global_hits_counter(key_without_locale) || 0)
51
- end
47
+ csv_row << (Lit.init.cache.get_global_hits_counter(key_without_locale) || 0) if include_hits_count
52
48
  csv << csv_row
53
49
  end
54
50
  end
@@ -59,9 +55,7 @@ module Lit
59
55
  # This is like Array#transpose but ignores size differences between inner arrays.
60
56
  private_class_method def self.transpose(matrix)
61
57
  maxlen = matrix.max { |x| x.length }.length
62
- matrix.each do |array|
63
- array[maxlen - 1] = nil if array.length < maxlen
64
- end
58
+ matrix.each { |array| array[maxlen - 1] = nil if array.length < maxlen }
65
59
  matrix.transpose
66
60
  end
67
61
  end
@@ -1,4 +1,5 @@
1
1
  require 'i18n'
2
+ require 'lit/services/humanize_service'
2
3
 
3
4
  module Lit
4
5
  class I18nBackend
@@ -16,9 +17,22 @@ module Lit
16
17
  I18n.const_set(:RESERVED_KEYS, reserved_keys.freeze)
17
18
  end
18
19
 
20
+ ## DOC
21
+ ## Translation flow starts with Rails-provided ActionView::Helpers::TranslationHelper `translate` method
22
+ ## In that method any calls to `I18n.translate` are catched by this method below (because Lit acts as I18 backend)
23
+ ## Any calls in Lit to `super` go straight to I18n
19
24
  def translate(locale, key, options = {})
20
25
  options[:lit_default_copy] = options[:default].dup if can_dup_default(options)
21
26
  content = super(locale, key, options)
27
+
28
+ if on_rails_6_1_or_higher?
29
+ @untranslated_key = key if key.present? && options[:default].instance_of?(Object)
30
+
31
+ if key.nil? && options[:lit_default_copy].present?
32
+ update_default_localization(locale, options)
33
+ end
34
+ end
35
+
22
36
  if Lit.all_translations_are_html_safe && content.respond_to?(:html_safe)
23
37
  content.html_safe
24
38
  else
@@ -54,6 +68,19 @@ module Lit
54
68
 
55
69
  private
56
70
 
71
+ def on_rails_6_1_or_higher?
72
+ "#{::Rails::VERSION::MAJOR}#{::Rails::VERSION::MINOR}".to_i == 61 ||
73
+ ::Rails::VERSION::MAJOR >= 7
74
+ end
75
+
76
+ def update_default_localization(locale, options)
77
+ parts = I18n.normalize_keys(locale, @untranslated_key, options[:scope], options[:separator])
78
+ key_with_locale = parts.join('.')
79
+ content = options[:lit_default_copy]
80
+ # we do not force array on singular strings packed into Array
81
+ @cache.update_locale(key_with_locale, content, content.is_a?(Array) && content.length > 1)
82
+ end
83
+
57
84
  def can_dup_default(options = {})
58
85
  return false unless options.key?(:default)
59
86
  return true if options[:default].is_a?(String)
@@ -94,12 +121,18 @@ module Lit
94
121
  if options[:lit_default_copy].is_a?(Array)
95
122
  default = options[:lit_default_copy].map do |key_or_value|
96
123
  if key_or_value.is_a?(Symbol)
97
- I18n.normalize_keys(nil, key_or_value.to_s, options[:scope], options[:separator]).join('.').to_sym
124
+ normalized = I18n.normalize_keys(
125
+ nil, key_or_value.to_s, options[:scope], options[:separator]
126
+ ).join('.')
127
+ if on_rails_6_1_or_higher? && Lit::Services::HumanizeService.should_humanize?(key)
128
+ Lit::Services::HumanizeService.humanize(normalized)
129
+ else
130
+ normalized.to_sym
131
+ end
98
132
  else
99
133
  key_or_value
100
134
  end
101
135
  end
102
- default = default.first if default.is_a?(Array)
103
136
  else
104
137
  default = options[:lit_default_copy]
105
138
  end
@@ -107,22 +140,16 @@ module Lit
107
140
  end
108
141
  # if we have content now, let's store it in cache
109
142
  if content.present?
110
- @cache[key_with_locale] = content
111
- content = @cache[key_with_locale]
112
- end
113
- # content might be nil - default value passed to cache was in fact
114
- # useless.
115
- # if content is still nil, we may try to humanize it. Rails will do
116
- # it anyway if we return nil, but then it will wrap it also in
117
- # translation_missing span.
118
- # Humanizing key should be last resort
119
- if content.nil? && Lit.humanize_key && Lit.humanize_key_ignored.match(key).nil?
120
- content = key.to_s.split('.').last.humanize
121
- if content.present?
122
- @cache[key_with_locale] = content
123
- content = @cache[key_with_locale]
143
+ content = Array.wrap(content).compact.reject(&:empty?).reverse.find do |default_cand|
144
+ @cache[key_with_locale] = default_cand
145
+ @cache[key_with_locale]
124
146
  end
125
147
  end
148
+
149
+ if content.nil? && !on_rails_6_1_or_higher? && Lit::Services::HumanizeService.should_humanize?(key)
150
+ @cache[key_with_locale] = Lit::Services::HumanizeService.humanize(key)
151
+ content = @cache[key_with_locale]
152
+ end
126
153
  end
127
154
  end
128
155
  # return translated content
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Lit
4
+ module Services
5
+ # Checks if should humanize based on config and blacklist.
6
+ # Performs humanize if required
7
+ # Caches the value of humanization
8
+ class HumanizeService
9
+ def self.should_humanize?(key)
10
+ Lit.humanize_key && Lit.humanize_key_ignored.match(key).nil?
11
+ end
12
+
13
+ def self.humanize(key)
14
+ key.to_s.split('.').last.humanize
15
+ end
16
+
17
+ def self.humanize_and_cache(key, options)
18
+ content = humanize(key)
19
+ parts = I18n.normalize_keys(
20
+ options[:locale] || I18n.locale, key, options[:scope], options[:separator]
21
+ )
22
+ key_with_locale = parts.join('.')
23
+ I18n.cache_store[key_with_locale] = content
24
+ I18n.cache_store[key_with_locale]
25
+ end
26
+ end
27
+ end
28
+ end
@@ -1,23 +1,26 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Lit
4
- # Converts flat hash with localization_keys as keys and translations as values to nested hash
5
- # by nesting on '.' localization key dots
6
- class LocalizationKeysToHashService
7
- # http://subtech.g.hatena.ne.jp/cho45/20061122
8
- def self.call(db_localizations)
9
- deep_proc = proc do |_k, s, o|
10
- next s.merge(o, &deep_proc) if s.is_a?(Hash) && o.is_a?(Hash)
4
+ module Services
5
+ # Converts flat hash with localization_keys as keys and translations as values to nested hash
6
+ # by nesting on '.' localization key dots
7
+ class LocalizationKeysToHashService
8
+ # http://subtech.g.hatena.ne.jp/cho45/20061122
9
+ def self.call(db_localizations)
10
+ deep_proc =
11
+ proc do |_k, s, o|
12
+ next s.merge(o, &deep_proc) if s.is_a?(Hash) && o.is_a?(Hash)
11
13
 
12
- next o
14
+ next o
15
+ end
16
+ nested_keys = {}
17
+ db_localizations.sort.each do |k, v|
18
+ key_parts = k.to_s.split('.')
19
+ converted = key_parts.reverse.reduce(v) { |a, n| { n => a } }
20
+ nested_keys.merge!(converted, &deep_proc)
21
+ end
22
+ nested_keys
13
23
  end
14
- nested_keys = {}
15
- db_localizations.sort.each do |k, v|
16
- key_parts = k.to_s.split('.')
17
- converted = key_parts.reverse.reduce(v) { |a, n| { n => a } }
18
- nested_keys.merge!(converted, &deep_proc)
19
- end
20
- nested_keys
21
24
  end
22
25
  end
23
26
  end
data/lib/lit/version.rb CHANGED
@@ -1,3 +1,17 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Lit
2
- VERSION = '1.1.2'.freeze
4
+ module_function
5
+
6
+ def version
7
+ Gem::Version.new Version::STRING
8
+ end
9
+
10
+ module Version
11
+ MAJOR = 1
12
+ MINOR = 1
13
+ TINY = 6
14
+
15
+ STRING = [MAJOR, MINOR, TINY].compact.join('.')
16
+ end
3
17
  end
data/lib/lit.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  require 'lit/engine'
2
2
  require 'lit/loader'
3
+ require 'lit/adapters'
3
4
 
4
5
  module Lit
5
6
  mattr_accessor :authentication_function
@@ -30,7 +31,7 @@ module Lit
30
31
  self.loader ||= Loader.new
31
32
  Lit.humanize_key = false if Lit.humanize_key.nil?
32
33
  Lit.humanize_key_ignored_keys = [] if Lit.humanize_key_ignored_keys.nil?
33
- Lit.humanize_key_ignored = %w[i18n date datetime number time support ]
34
+ Lit.humanize_key_ignored = %w[i18n date datetime number time support]
34
35
  Lit.humanize_key_ignored |= Lit.humanize_key_ignored_keys
35
36
  Lit.humanize_key_ignored = Regexp.new("(#{Lit.humanize_key_ignored.join('|')}).*")
36
37
  Lit.ignore_yaml_on_startup = true if Lit.ignore_yaml_on_startup.nil?
@@ -42,6 +43,7 @@ module Lit
42
43
  Lit.hits_counter_enabled = false if Lit.hits_counter_enabled.nil?
43
44
  Lit.store_request_info = false if Lit.store_request_info.nil?
44
45
  Lit.store_request_keys = false if Lit.store_request_keys.nil?
46
+
45
47
  # if loading all translations on start, migrations have to be already
46
48
  # performed, fails on first deploy
47
49
  # self.loader.cache.load_all_translations
@@ -55,10 +57,10 @@ module Lit
55
57
  rescue ActiveRecord::ActiveRecordError => e
56
58
  log_txt =
57
59
  "An #{e.class} error has been raised during Lit initialization. " \
58
- "Lit assumes that database tables do not exist.\n\n" \
59
- "Error: #{e.message}\n\n" \
60
- "Backtrace:\n" \
61
- "#{e.backtrace.join("\n")}"
60
+ "Lit assumes that database tables do not exist.\n\n" \
61
+ "Error: #{e.message}\n\n" \
62
+ "Backtrace:\n" \
63
+ "#{e.backtrace.join("\n")}"
62
64
  Logger.new(STDOUT).error(log_txt) if ::Rails.env.test? # ensure this is logged to stdout in test
63
65
  ::Rails.logger.error(log_txt)
64
66
  false
@@ -68,18 +70,16 @@ module Lit
68
70
  case Lit.key_value_engine
69
71
  when 'redis'
70
72
  require 'lit/adapters/redis_storage'
71
- return RedisStorage.new
73
+ return ::Lit::Adapters::RedisStorage.new
72
74
  else
73
75
  require 'lit/adapters/hash_storage'
74
- return HashStorage.new
76
+ return ::Lit::Adapters::HashStorage.new
75
77
  end
76
78
  end
77
79
 
78
80
  def self.fallback=(_value)
79
- ::Rails.logger.error "[DEPRECATION] Lit.fallback= has been deprecated, please use `config.i18n.fallbacks` instead"
81
+ ::Rails.logger.error '[DEPRECATION] Lit.fallback= has been deprecated, please use `config.i18n.fallbacks` instead'
80
82
  end
81
83
  end
82
84
 
83
- if defined? Rails
84
- require 'lit/rails'
85
- end
85
+ require 'lit/rails' if defined?(Rails)
metadata CHANGED
@@ -1,17 +1,17 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lit
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.2
4
+ version: 1.1.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - Maciej Litwiniuk
8
8
  - Piotr Boniecki
9
9
  - Michał Buszkiewicz
10
10
  - Szymon Soppa
11
- autorequire:
11
+ autorequire:
12
12
  bindir: bin
13
13
  cert_chain: []
14
- date: 2021-04-26 00:00:00.000000000 Z
14
+ date: 2022-03-28 00:00:00.000000000 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: rails
@@ -19,14 +19,14 @@ dependencies:
19
19
  requirements:
20
20
  - - ">="
21
21
  - !ruby/object:Gem::Version
22
- version: 4.2.0
22
+ version: 5.2.0
23
23
  type: :runtime
24
24
  prerelease: false
25
25
  version_requirements: !ruby/object:Gem::Requirement
26
26
  requirements:
27
27
  - - ">="
28
28
  - !ruby/object:Gem::Version
29
- version: 4.2.0
29
+ version: 5.2.0
30
30
  - !ruby/object:Gem::Dependency
31
31
  name: jquery-rails
32
32
  requirement: !ruby/object:Gem::Requirement
@@ -111,20 +111,6 @@ dependencies:
111
111
  - - "~>"
112
112
  - !ruby/object:Gem::Version
113
113
  version: 4.7.1
114
- - !ruby/object:Gem::Dependency
115
- name: google-cloud-translate
116
- requirement: !ruby/object:Gem::Requirement
117
- requirements:
118
- - - "~>"
119
- - !ruby/object:Gem::Version
120
- version: 1.2.4
121
- type: :development
122
- prerelease: false
123
- version_requirements: !ruby/object:Gem::Requirement
124
- requirements:
125
- - - "~>"
126
- - !ruby/object:Gem::Version
127
- version: 1.2.4
128
114
  - !ruby/object:Gem::Dependency
129
115
  name: minitest
130
116
  requirement: !ruby/object:Gem::Requirement
@@ -233,6 +219,8 @@ files:
233
219
  - app/controllers/lit/locales_controller.rb
234
220
  - app/controllers/lit/localization_keys_controller.rb
235
221
  - app/controllers/lit/localizations_controller.rb
222
+ - app/controllers/lit/request_info_store.rb
223
+ - app/controllers/lit/request_keys_store.rb
236
224
  - app/controllers/lit/sources_controller.rb
237
225
  - app/helpers/lit/application_helper.rb
238
226
  - app/helpers/lit/dashboard_helper.rb
@@ -305,9 +293,10 @@ files:
305
293
  - db/migrate/20181018075955_lit_add_localization_key_is_deleted_to_localization_keys.rb
306
294
  - db/migrate/20181030111522_lit_add_is_visited_again_to_localization_keys.rb
307
295
  - db/migrate/20181129103819_lit_add_localization_key_locale_unique_index_to_localizations.rb
308
- - lib/generators/lit/install/templates/initializer.rb
296
+ - lib/generators/lit/install/templates/initializer.erb
309
297
  - lib/generators/lit/install_generator.rb
310
298
  - lib/lit.rb
299
+ - lib/lit/adapters.rb
311
300
  - lib/lit/adapters/hash_storage.rb
312
301
  - lib/lit/adapters/redis_storage.rb
313
302
  - lib/lit/cache.rb
@@ -323,6 +312,7 @@ files:
323
312
  - lib/lit/middleware.rb
324
313
  - lib/lit/rails.rb
325
314
  - lib/lit/railtie.rb
315
+ - lib/lit/services/humanize_service.rb
326
316
  - lib/lit/services/localization_keys_to_hash_service.rb
327
317
  - lib/lit/version.rb
328
318
  - lib/tasks/lit_tasks.rake
@@ -330,7 +320,7 @@ homepage: https://github.com/prograils/lit
330
320
  licenses:
331
321
  - MIT
332
322
  metadata: {}
333
- post_install_message:
323
+ post_install_message:
334
324
  rdoc_options: []
335
325
  require_paths:
336
326
  - lib
@@ -346,7 +336,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
346
336
  version: '0'
347
337
  requirements: []
348
338
  rubygems_version: 3.1.6
349
- signing_key:
339
+ signing_key:
350
340
  specification_version: 4
351
341
  summary: Database powered i18n backend with web gui
352
342
  test_files: []