lit 1.1.2 → 1.1.6
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.
- checksums.yaml +4 -4
- data/README.md +42 -26
- data/app/assets/stylesheets/lit/lit_frontend.css +16 -15
- data/app/controllers/lit/concerns/request_info_store.rb +0 -15
- data/app/controllers/lit/concerns/request_keys_store.rb +0 -15
- data/app/controllers/lit/request_info_store.rb +10 -0
- data/app/controllers/lit/request_keys_store.rb +10 -0
- data/app/helpers/lit/frontend_helper.rb +76 -64
- data/lib/generators/lit/install/templates/{initializer.rb → initializer.erb} +6 -1
- data/lib/generators/lit/install_generator.rb +8 -10
- data/lib/lit/adapters/hash_storage.rb +2 -2
- data/lib/lit/adapters/redis_storage.rb +4 -8
- data/lib/lit/adapters.rb +2 -0
- data/lib/lit/cloud_translation/providers/google.rb +25 -7
- data/lib/lit/engine.rb +4 -7
- data/lib/lit/export.rb +5 -11
- data/lib/lit/i18n_backend.rb +43 -16
- data/lib/lit/services/humanize_service.rb +28 -0
- data/lib/lit/services/localization_keys_to_hash_service.rb +18 -15
- data/lib/lit/version.rb +15 -1
- data/lib/lit.rb +11 -11
- metadata +12 -22
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1bda244665d30fcad8f9ad16a593e47ffd6cf54d8d7c9a6a777d5038bad75f1b
|
4
|
+
data.tar.gz: 7217df2945e7a5b1813d2a4892eebf46fcf8a97cdd8e9d8648c7a23a2962715f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
-
|
28
|
+
[Feature overview on YouTube](https://www.youtube.com/watch?v=_T9Kg05VvLI)
|
29
|
+
|
30
|
+

|
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
|
-
|
203
|
-
|
204
|
-
|
211
|
+
```ruby
|
212
|
+
helper Lit::FrontendHelper
|
213
|
+
```
|
205
214
|
|
206
215
|
2. In you layout file include lit assets
|
207
216
|
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
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::
|
232
|
+
1. Include `Lit::RequestInfoStore` concern in your `ApplicationController`
|
223
233
|
|
224
|
-
|
225
|
-
|
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
|
-
|
242
|
-
|
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
|
-
|
261
|
+
3. Enable storing of request keys in lit initializer `config/initializers/lit.rb`
|
246
262
|
|
247
|
-
|
248
|
-
|
249
|
-
|
263
|
+
```ruby
|
264
|
+
Lit.store_request_keys = true
|
265
|
+
```
|
250
266
|
|
251
|
-
|
267
|
+
4. On the bottom of you layout file call `lit_translations_info` helper function
|
252
268
|
|
253
|
-
|
254
|
-
|
255
|
-
|
269
|
+
```erb
|
270
|
+
<%= lit_translations_info %>
|
271
|
+
```
|
256
272
|
|
257
|
-
|
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
|
-
|
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
|
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
|
|
@@ -1,83 +1,95 @@
|
|
1
|
-
module Lit
|
2
|
-
|
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
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
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
|
-
|
27
|
-
|
28
|
-
|
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
|
33
|
-
|
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
|
37
|
-
|
23
|
+
def t(key, options = {})
|
24
|
+
translate(key, options)
|
38
25
|
end
|
39
26
|
|
40
|
-
def
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
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
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
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
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
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
|
-
|
71
|
-
|
72
|
-
send Lit.authentication_verification
|
73
|
-
end
|
84
|
+
def lit_authorized?
|
85
|
+
return false if Lit.authentication_verification.blank?
|
74
86
|
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
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 =
|
15
|
-
|
16
|
-
|
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 =
|
21
|
-
|
22
|
-
|
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
|
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.
|
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
|
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
|
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)
|
data/lib/lit/adapters.rb
ADDED
@@ -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
|
-
|
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
|
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(
|
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
|
-
|
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
|
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
|
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,
|
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
|
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
|
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
|
data/lib/lit/i18n_backend.rb
CHANGED
@@ -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(
|
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
|
-
|
111
|
-
|
112
|
-
|
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
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
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
|
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?
|
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.
|
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:
|
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:
|
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:
|
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.
|
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: []
|