rails_i18n_manager 1.1.3 → 1.1.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +82 -0
- data/app/controllers/rails_i18n_manager/translation_apps_controller.rb +1 -1
- data/app/controllers/rails_i18n_manager/translations_controller.rb +43 -23
- data/app/views/layouts/rails_i18n_manager/_utility_css.html.erb +6 -0
- data/app/views/rails_i18n_manager/translations/_filter_bar.html.slim +7 -6
- data/app/views/rails_i18n_manager/translations/index.html.slim +8 -8
- data/lib/rails_i18n_manager/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 754d64695feb342f539cf20c2f7e0eb56307d347c09a0aff1ee2dd6424bef236
|
4
|
+
data.tar.gz: dc20afbd566dd69f283f8e520fa523d551ece87e00bc8d2dc7361f7043890a1f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9c7271c5b764f6730d8fdb33e31e936b9ceb738391d170f663ec133543eddaf52843b24bd20ebf97c671d507e1193dcae0671c25d6bdfcca27a9f2d737f040f0
|
7
|
+
data.tar.gz: d1c51faed0c9049ca72c9c6891a531338fcdcc183d08dc65bf3de3d558328bb1cdddfca96b99eef5500ac1b409d66c26563b0fa1ff8a069e770ed04722815538
|
data/README.md
CHANGED
@@ -142,6 +142,88 @@ curl https://translations-manager.example.com/translations.zip?export_format=jso
|
|
142
142
|
&& echo "Locales are now updated, app restart not-required"
|
143
143
|
```
|
144
144
|
|
145
|
+
## Recommended Workflow for Teams
|
146
|
+
|
147
|
+
It is desirable to reduce how often import/export is performed. It is also desirable that we do not violate the regular PR lifecycle/process. The following workflow should allow for this.
|
148
|
+
|
149
|
+
When creating a PR you can just create a new YAML file named after your feature name or ticket number and then use the following format:
|
150
|
+
|
151
|
+
```yaml
|
152
|
+
# config/locales/some_new_feature.yml
|
153
|
+
|
154
|
+
en:
|
155
|
+
some_new_key: "foo"
|
156
|
+
fr:
|
157
|
+
some_new_key: "bar"
|
158
|
+
es:
|
159
|
+
some_new_key: "baz"
|
160
|
+
```
|
161
|
+
|
162
|
+
Whenever releasing a new version of your application, pre-deploy or some other cadence, then you can have a step where all translation files are uploaded to the `rails_i18n_manager`, have your translator folks double check everything, then export your new files and cleanup all the feature files.
|
163
|
+
|
164
|
+
## Recommended I18n Configuration
|
165
|
+
|
166
|
+
The default I18n backend has some glaring issues
|
167
|
+
|
168
|
+
- It will silently show "translation_missing" text which is very undesirable
|
169
|
+
- It will not fallback to your default or any other locale
|
170
|
+
|
171
|
+
You can avoid these issues using either of the techniques below
|
172
|
+
|
173
|
+
```ruby
|
174
|
+
# config/initializers/i18n.rb
|
175
|
+
|
176
|
+
Rails.configuration do |config|
|
177
|
+
config.i18n.raise_on_missing_translations = true # WARNING: this will raise exceptions in Production too, preventing your users from using your application even when some silly little translation is missing
|
178
|
+
|
179
|
+
config.i18n.fallbacks = [I18n.default_locale, :en].uniq # fallback to default locale, or if that is missing then fallback to english translation
|
180
|
+
end
|
181
|
+
```
|
182
|
+
|
183
|
+
You will likely find that `raise_on_missing_translations` is too aggressive. Causing major outages just because a translation is missing. In that scenario its better to use something like the following:
|
184
|
+
|
185
|
+
```ruby
|
186
|
+
# config/initializers/i18n.rb
|
187
|
+
|
188
|
+
Rails.configuration do |config|
|
189
|
+
config.i18n.raise_on_missing_translations = false # Instead we use the custom backend below
|
190
|
+
|
191
|
+
config.i18n.fallbacks = [I18n.default_locale, :en].uniq # fallback to default locale, or if that is missing then fallback to english translation
|
192
|
+
end
|
193
|
+
|
194
|
+
module I18n
|
195
|
+
class CustomI18nBackend
|
196
|
+
include I18n::Backend::Base
|
197
|
+
|
198
|
+
def translate(locale, key, options = EMPTY_HASH)
|
199
|
+
if !key.nil? && key.to_s != "i18n.plural.rule"
|
200
|
+
translation_value = lookup(locale, key, options[:scope], options)
|
201
|
+
|
202
|
+
if translation_value.blank?
|
203
|
+
if Rails.env.production?
|
204
|
+
# send an email or some other warning mechanism
|
205
|
+
else
|
206
|
+
# Raise exception in non-production environments
|
207
|
+
raise "Translation not found (locale: #{locale}, key: #{key})"
|
208
|
+
end
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
212
|
+
return nil # allow the Backend::Chain to continue to the next backend
|
213
|
+
end
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
217
|
+
if I18n.backend.is_a?(I18n::Backend::Chain)
|
218
|
+
I18n.backend.backends.unshift(I18n::CustomI18nBackend)
|
219
|
+
else
|
220
|
+
I18n.backend = I18n::Backend::Chain.new(
|
221
|
+
I18n::CustomI18nBackend,
|
222
|
+
I18n.backend, # retain original backend
|
223
|
+
)
|
224
|
+
end
|
225
|
+
```
|
226
|
+
|
145
227
|
## Development
|
146
228
|
|
147
229
|
Run migrations using: `rails db:migrate`
|
@@ -36,12 +36,16 @@ module RailsI18nManager
|
|
36
36
|
|
37
37
|
case request.format.to_sym
|
38
38
|
when :csv
|
39
|
+
if params.dig(:filters, :app_name).present?
|
40
|
+
@translation_keys = @translation_keys.joins(:translation_app).where(TranslationApp.table_name => {name: params.dig(:filters, :app_name)})
|
41
|
+
end
|
42
|
+
|
39
43
|
send_data @translation_keys.to_csv, filename: "translations.csv"
|
40
44
|
when :zip
|
41
|
-
file = @translation_keys.export_to(format: params[:export_format], zip: true, app_name: params
|
45
|
+
file = @translation_keys.export_to(format: params[:export_format], zip: true, app_name: params.dig(:filters, :app_name).presence)
|
42
46
|
|
43
47
|
if file
|
44
|
-
send_file file, filename: "translations-#{params[:export_format]}-#{params
|
48
|
+
send_file file, filename: "translations-#{params[:export_format]}-#{params.dig(:filters, :app_name).presence || "all-apps"}.zip"
|
45
49
|
else
|
46
50
|
flash[:alert] = "Sorry, Nothing to export"
|
47
51
|
redirect_to action: :index
|
@@ -68,7 +72,7 @@ module RailsI18nManager
|
|
68
72
|
redirect_to edit_translation_path(@translation_key)
|
69
73
|
else
|
70
74
|
flash[:notice] = "Update failed."
|
71
|
-
render "
|
75
|
+
render "edit"
|
72
76
|
end
|
73
77
|
end
|
74
78
|
|
@@ -89,10 +93,10 @@ module RailsI18nManager
|
|
89
93
|
|
90
94
|
apply_filters
|
91
95
|
|
92
|
-
|
96
|
+
@translation_keys.destroy_all
|
93
97
|
|
94
|
-
|
95
|
-
|
98
|
+
flash[:notice] = "Delete Inactive was successful."
|
99
|
+
redirect_to translations_path(filters: params[:filters].to_unsafe_h)
|
96
100
|
end
|
97
101
|
|
98
102
|
def import
|
@@ -132,8 +136,8 @@ module RailsI18nManager
|
|
132
136
|
translated_count = 0
|
133
137
|
total_missing = 0
|
134
138
|
|
135
|
-
if params
|
136
|
-
app_locales = TranslationApp.find_by(name: params
|
139
|
+
if params.dig(:filters, :app_name)
|
140
|
+
app_locales = TranslationApp.find_by(name: params.dig(:filters, :app_name)).additional_locales_array
|
137
141
|
else
|
138
142
|
@translation_keys = @translation_keys.includes(:translation_app)
|
139
143
|
end
|
@@ -184,7 +188,7 @@ module RailsI18nManager
|
|
184
188
|
if params[:translation_key_id]
|
185
189
|
url = request.referrer || translation_path(params[:translation_key_id])
|
186
190
|
else
|
187
|
-
url =
|
191
|
+
url = translations_path(filters: params[:filters].to_unsafe_h)
|
188
192
|
end
|
189
193
|
|
190
194
|
redirect_to url, notice: "Translated #{translated_count} of #{total_missing} total missing translations"
|
@@ -201,8 +205,8 @@ module RailsI18nManager
|
|
201
205
|
end
|
202
206
|
|
203
207
|
def apply_filters
|
204
|
-
if params
|
205
|
-
@translation_keys = @translation_keys.joins(:translation_app).where(TranslationApp.table_name => {name: params
|
208
|
+
if params.dig(:filters, :app_name).present?
|
209
|
+
@translation_keys = @translation_keys.joins(:translation_app).where(TranslationApp.table_name => {name: params.dig(:filters, :app_name)})
|
206
210
|
end
|
207
211
|
|
208
212
|
if params[:translation_key_id].present?
|
@@ -212,24 +216,40 @@ module RailsI18nManager
|
|
212
216
|
if request.format.html?
|
213
217
|
### ONLY FOR HTML - SO THAT WE DONT DOWNLOAD INCOMPLETE TRANSLATION EXPORT PACKAGES
|
214
218
|
|
215
|
-
if params
|
216
|
-
@translation_keys = @translation_keys.search(params
|
219
|
+
if params.dig(:filters, :search).present?
|
220
|
+
@translation_keys = @translation_keys.search(params.dig(:filters, :search))
|
221
|
+
end
|
222
|
+
|
223
|
+
if params.dig(:filters, :status).blank?
|
224
|
+
params[:filters] ||= {}
|
225
|
+
params[:filters][:status] = "All Active Translations"
|
217
226
|
end
|
218
227
|
|
219
|
-
if params
|
228
|
+
if params.dig(:filters, :status) == "Inactive Translations"
|
220
229
|
@translation_keys = @translation_keys.where(active: false)
|
221
|
-
elsif params
|
230
|
+
elsif params.dig(:filters, :status) == "All Translations"
|
222
231
|
# Do nothing
|
223
|
-
|
232
|
+
elsif params.dig(:filters, :status) == "All Active Translations"
|
224
233
|
@translation_keys = @translation_keys.where(active: true)
|
225
|
-
|
226
|
-
|
227
|
-
if params[:status] == "Missing"
|
234
|
+
elsif params.dig(:filters, :status).start_with?("Missing")
|
228
235
|
missing_key_ids = []
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
236
|
+
|
237
|
+
if params.dig(:filters, :app_name).present?
|
238
|
+
translation_apps = TranslationApp.where(name: params.dig(:filters, :app_name))
|
239
|
+
else
|
240
|
+
translation_apps = TranslationApp.all
|
241
|
+
end
|
242
|
+
|
243
|
+
translation_apps.includes(translation_keys: [:translation_values]).each do |app_record|
|
244
|
+
app_record.translation_keys.each do |key_record|
|
245
|
+
if params.dig(:filters, :status) == "Missing Default Translation"
|
246
|
+
if key_record.translation_values.detect{|x| x.locale == app_record.default_locale}&.translation.blank?
|
247
|
+
missing_key_ids << key_record.id
|
248
|
+
end
|
249
|
+
else
|
250
|
+
if key_record.any_missing_translations?
|
251
|
+
missing_key_ids << key_record.id
|
252
|
+
end
|
233
253
|
end
|
234
254
|
end
|
235
255
|
end
|
@@ -1,17 +1,18 @@
|
|
1
1
|
form
|
2
2
|
.row.align-items-center.g-1
|
3
3
|
.col-auto
|
4
|
-
= select_tag
|
4
|
+
= select_tag "filters[app_name]", options_for_select(RailsI18nManager::TranslationApp.order(name: :asc).pluck(:name), params.dig(:filters, :app_name)), prompt: "All Apps", class: "form-select", style: "min-width: 220px"
|
5
5
|
|
6
6
|
.col-auto
|
7
|
-
= select_tag :status, options_for_select([
|
7
|
+
= select_tag :status, options_for_select(["All Translations", "All Active Translations", "Inactive Translations", "Missing Default Translation", "Missing Any Translation"], params.dig(:filters, :status)), class: 'form-select', style: "min-width: 215px;"
|
8
8
|
|
9
9
|
.col-auto
|
10
|
-
= text_field_tag :search, params
|
10
|
+
= text_field_tag :search, params.dig(:filters, :search), placeholder: "Search", class: "form-control"
|
11
11
|
|
12
12
|
.col-auto
|
13
13
|
button.btn.btn-primary.btn-sm type="submit" Filter
|
14
14
|
|
15
|
-
- if
|
16
|
-
-
|
17
|
-
|
15
|
+
- if params.dig(:filters, :app_name).present? || params.dig(:filters, :search).present?
|
16
|
+
- if params.dig(:filters, :status).present?
|
17
|
+
- link_params = {filters: {status: params.dig(:filters, :status)}}
|
18
|
+
= link_to "Clear", (link_params || {}), class: "btn btn-sm space-left"
|
@@ -1,19 +1,19 @@
|
|
1
1
|
.pull-right
|
2
|
-
= link_to "Translate with Google",
|
2
|
+
= link_to "Translate with Google", translate_missing_translations_path(filters: params[:filters].to_unsafe_h), class: "btn btn-primary btn-sm", "data-method" => "post", "data-confirm" => "Are you sure you want to proceed with translating the missing translations in the currently filtered list?"
|
3
3
|
= link_to "Import Translations", import_translations_path, class: "btn btn-secondary btn-sm space-left2"
|
4
|
-
= link_to "Delete Inactive",
|
4
|
+
= link_to "Delete Inactive", delete_inactive_keys_translations_path(filters: params[:filters].to_unsafe_h), class: "btn btn-danger btn-sm space-left2", "data-method" => "delete", "data-confirm" => "Warning! This is a highly destructive action.\n\nIts possible to incorrectly upload an incomplete or incorrect file to 'Mark Inactive Translations from Source' which can leave you with inactive keys that maybe shouldnt have been inactivated.\n\nPlease proceed only if you are certain that you do not have any keys that are incorrectly marked inactive.\n\nAre you sure you want to proceed with deleting the inactive translations in the currently filtered list?"
|
5
5
|
|
6
6
|
h2.page-title Translations
|
7
|
-
- if params[:app_name]
|
7
|
+
- if params[:app_name].present?
|
8
8
|
h5.page-title App Name: #{params[:app_name]}
|
9
9
|
|
10
10
|
br
|
11
11
|
|
12
12
|
.well.well-sm
|
13
13
|
.btn-group.pull-right.text-right
|
14
|
-
= link_to "Export to CSV",
|
15
|
-
= link_to "YAML",
|
16
|
-
= link_to "JSON",
|
14
|
+
= link_to "Export to CSV", translations_path(format: :csv, app_name: params[:app_name]), class: "btn btn-sm btn-success"
|
15
|
+
= link_to "YAML", translations_path(format: :zip, export_format: :yaml, app_name: params[:app_name]), class: "btn btn-sm btn-success"
|
16
|
+
= link_to "JSON", translations_path(format: :zip, export_format: :json, app_name: params[:app_name]), class: "btn btn-sm btn-success"
|
17
17
|
|
18
18
|
.pull-right.space-right2
|
19
19
|
|
@@ -25,7 +25,7 @@ table.table.table-striped.table-hover.space-above3.list-table
|
|
25
25
|
th = sort_link(:app_name)
|
26
26
|
th = sort_link(:key)
|
27
27
|
th Default Translation
|
28
|
-
- if params[:status]
|
28
|
+
- if params[:status] != "All Active Translations"
|
29
29
|
th Status
|
30
30
|
th = sort_link(:updated_at)
|
31
31
|
th Actions
|
@@ -35,7 +35,7 @@ table.table.table-striped.table-hover.space-above3.list-table
|
|
35
35
|
td = x.translation_app.name
|
36
36
|
td = x.key
|
37
37
|
td = x.default_translation
|
38
|
-
- if params[:status]
|
38
|
+
- if params[:status] != "All Active Translations"
|
39
39
|
td Inactive
|
40
40
|
td = x.updated_at&.strftime("%Y-%m-%d %l:%M %p")
|
41
41
|
td
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rails_i18n_manager
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.1.
|
4
|
+
version: 1.1.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Weston Ganger
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2025-02-
|
11
|
+
date: 2025-02-14 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|