translation 1.17 → 1.22
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 +5 -5
- data/README.md +124 -52
- data/lib/translation.rb +12 -9
- data/lib/translation_io/client/base_operation/create_new_mo_files_step.rb +4 -2
- data/lib/translation_io/client/base_operation/save_new_po_files_step.rb +3 -1
- data/lib/translation_io/client/base_operation/save_new_yaml_files_step.rb +1 -1
- data/lib/translation_io/client/base_operation/save_special_yaml_files_step.rb +23 -17
- data/lib/translation_io/client/init_operation.rb +22 -15
- data/lib/translation_io/client/init_operation/cleanup_yaml_files_step.rb +17 -11
- data/lib/translation_io/client/init_operation/update_and_collect_po_files_step.rb +3 -1
- data/lib/translation_io/client/sync_operation.rb +18 -8
- data/lib/translation_io/client/sync_operation/apply_yaml_source_edits_step.rb +119 -62
- data/lib/translation_io/config.rb +127 -38
- data/lib/translation_io/flat_hash.rb +5 -1
- data/lib/translation_io/railtie.rb +9 -3
- data/lib/translation_io/yaml_conversion.rb +10 -2
- data/lib/translation_io/yaml_entry.rb +3 -3
- metadata +11 -12
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: d45218917c9c922310e60826327cd83f9537b07ece00d855a36a83327e04f8ef
|
4
|
+
data.tar.gz: '009b17548c9e57c0a696d7910cd9a75a4e1329049406a45449e1a17382c94b72'
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b438efc2955b5db716b73e8d4ae1044135c6296f57ea829b8f5bc3ba8734ec0f7ff73678842b8a88a0826cc3d8ade340a9dc18ea66e874690ce932b2f9f8c849
|
7
|
+
data.tar.gz: e46d5e83c77b4f3f7fc0b0496c753ca6634b39f0043992b77f83ce604163a4e5433730cff5b3c77318df698a98d936f99a9986fc7b643da1d87c6f009b9b1fbb
|
data/README.md
CHANGED
@@ -35,16 +35,19 @@ Table of contents
|
|
35
35
|
* [Add or Remove Language](#add-or-remove-language)
|
36
36
|
* [Edit Language](#edit-language)
|
37
37
|
* [Custom Languages](#custom-languages)
|
38
|
+
* [Fallbacks](#fallbacks)
|
38
39
|
* [Change the current locale](#change-the-current-locale)
|
39
40
|
* [Globally](#globally)
|
40
41
|
* [Locally](#locally)
|
41
42
|
* [Continuous Integration](#continuous-integration)
|
42
43
|
* [Advanced Configuration Options](#advanced-configuration-options)
|
43
|
-
* [Disable GetText](#disable-gettext)
|
44
|
+
* [Disable GetText or YAML](#disable-gettext-or-yaml)
|
44
45
|
* [Ignored YAML keys](#ignored-yaml-keys)
|
45
|
-
* [Source file formats (for GetText)](#source-file-formats-for-gettext)
|
46
46
|
* [Custom localization key prefixes](#custom-localization-key-prefixes)
|
47
|
+
* [Source file formats (for GetText)](#source-file-formats-for-gettext)
|
48
|
+
* [Gems with GetText strings](#gems-with-gettext-strings)
|
47
49
|
* [Paths where locales are stored (not recommended)](#paths-where-locales-are-stored-not-recommended)
|
50
|
+
* [GetText Object Class Monkey-Patching](#gettext-object-class-monkey-patching)
|
48
51
|
* [Pure Ruby (without Rails)](#pure-ruby-without-rails)
|
49
52
|
* [Testing](#testing)
|
50
53
|
* [Contributing](#contributing)
|
@@ -202,24 +205,37 @@ Since you created a new project, the translation history and tags will unfortuna
|
|
202
205
|
|
203
206
|
### Custom Languages
|
204
207
|
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
+
Custom languages are convenient if you want to customize translations for a specific customer
|
209
|
+
or another instance of your application.
|
210
|
+
|
211
|
+
A custom language is always be derived from an [existing language](https://translation.io/docs/languages).
|
212
|
+
Its structure should be like:
|
213
|
+
|
214
|
+
```ruby
|
215
|
+
"#{existing_language_code}-#{custom_text}"
|
216
|
+
```
|
208
217
|
|
209
|
-
|
218
|
+
where `custom_text` can only contain alphanumeric characters and `-`.
|
210
219
|
|
211
220
|
Examples: `en-microsoft` or `fr-BE-custom`.
|
212
221
|
|
213
|
-
|
214
|
-
|
215
|
-
|
222
|
+
### Fallbacks
|
223
|
+
|
224
|
+
Using [I18n (YAML)](#i18n-yaml) syntax, fallbacks will work as expected for any regional or custom
|
225
|
+
language. It means that if the `en-microsoft.example` key is missing,
|
226
|
+
then it will fallback to `en.example`. So you only need to translate keys that
|
227
|
+
are different from the main language.
|
228
|
+
|
229
|
+
Note that fallbacks are chained, so `fr-BE-custom` will fallback to `fr-BE` that will
|
230
|
+
fallback to `fr`.
|
216
231
|
|
217
|
-
|
218
|
-
|
232
|
+
Just make sure to add `config.i18n.fallbacks = true` to your `config/application.rb` file.
|
233
|
+
You can find more information about this
|
234
|
+
[here](https://guides.rubyonrails.org/configuring.html#configuring-i18n).
|
219
235
|
|
220
|
-
Using GetText syntax, it will only fallback to the source language.
|
221
|
-
create a fallback mechanism by yourself or you avoid fallbacking
|
222
|
-
by translating everything in Translation.io for
|
236
|
+
Using [GetText](#gettext) syntax, it will only fallback to the source language.
|
237
|
+
So either you create a fallback mechanism by yourself or you avoid fallbacking
|
238
|
+
by translating everything in Translation.io for the regional or custom language.
|
223
239
|
|
224
240
|
## Change the current locale
|
225
241
|
|
@@ -235,9 +251,12 @@ class ApplicationController < ActionController::Base
|
|
235
251
|
end
|
236
252
|
```
|
237
253
|
|
238
|
-
|
254
|
+
First time the user will connect, it will automatically set the locale extracted
|
255
|
+
from the user's browser `HTTP_ACCEPT_LANGUAGE` value, and keep it in the session between
|
256
|
+
requests.
|
239
257
|
|
240
|
-
Update the current locale by redirecting the user to https://yourdomain.com?locale=fr
|
258
|
+
Update the current locale by redirecting the user to https://yourdomain.com?locale=fr
|
259
|
+
or even https://yourdomain.com/fr if you scoped your routes like this:
|
241
260
|
|
242
261
|
```ruby
|
243
262
|
scope "/:locale", :constraints => { locale: /[a-z]{2}/ } do
|
@@ -245,7 +264,8 @@ scope "/:locale", :constraints => { locale: /[a-z]{2}/ } do
|
|
245
264
|
end
|
246
265
|
```
|
247
266
|
|
248
|
-
The `set_locale` code is [here](https://github.com/translation/rails/blob/master/lib/translation_io/controller.rb#L3),
|
267
|
+
The `set_locale` code is [here](https://github.com/translation/rails/blob/master/lib/translation_io/controller.rb#L3),
|
268
|
+
feel free to override it with your own locale management.
|
249
269
|
|
250
270
|
Don't forget to define your available locales with [I18n.available_locales](http://guides.rubyonrails.org/i18n.html#setup-the-rails-application-for-internationalization).
|
251
271
|
|
@@ -265,9 +285,9 @@ More examples here: https://translation.io/blog/rails-i18n-with-locale
|
|
265
285
|
|
266
286
|
## Continuous Integration
|
267
287
|
|
268
|
-
If you want fresh translations in your Continuous Integration workflow, you may find yourself calling `bundle exec rake translation:sync` very frequently.
|
288
|
+
If you want fresh translations in your Continuous Integration workflow, you may find yourself calling `bundle exec rake translation:sync` very frequently.
|
269
289
|
|
270
|
-
Since this task can't be concurrently executed (we have a [mutex](https://en.wikipedia.org/wiki/Mutual_exclusion) strategy with a queue but it returns an error under heavy load), we implemented this threadsafe readonly task:
|
290
|
+
Since this task can't be concurrently executed (we have a [mutex](https://en.wikipedia.org/wiki/Mutual_exclusion) strategy with a queue but it returns an error under heavy load), we implemented this threadsafe readonly task:
|
271
291
|
|
272
292
|
```bash
|
273
293
|
$ bundle exec rake translation:sync_readonly
|
@@ -281,12 +301,9 @@ The `TranslationIO.configure` block in `config/initializers/translation.rb` can
|
|
281
301
|
|
282
302
|
Some options are described below but for an exhaustive list, please refer to [config.rb](https://github.com/translation/rails/blob/master/lib/translation_io/config.rb).
|
283
303
|
|
284
|
-
### Disable GetText
|
304
|
+
### Disable GetText or YAML
|
285
305
|
|
286
|
-
|
287
|
-
For these cases, you just have to add `disable_gettext` in the config file.
|
288
|
-
|
289
|
-
For example:
|
306
|
+
If you want to only use YAML files and totally ignore GetText syntax, use:
|
290
307
|
|
291
308
|
```ruby
|
292
309
|
TranslationIO.configure do |config|
|
@@ -296,6 +313,17 @@ TranslationIO.configure do |config|
|
|
296
313
|
end
|
297
314
|
```
|
298
315
|
|
316
|
+
In contrast, if you only want to synchronize GetText files and leave the YAML
|
317
|
+
files unchanged, use:
|
318
|
+
|
319
|
+
```ruby
|
320
|
+
TranslationIO.configure do |config|
|
321
|
+
...
|
322
|
+
config.disable_yaml = true
|
323
|
+
...
|
324
|
+
end
|
325
|
+
```
|
326
|
+
|
299
327
|
### Ignored YAML keys
|
300
328
|
|
301
329
|
Sometimes you would like to ignore some YAML keys coming from gems or so.
|
@@ -307,19 +335,45 @@ For example:
|
|
307
335
|
TranslationIO.configure do |config|
|
308
336
|
...
|
309
337
|
config.ignored_key_prefixes = [
|
310
|
-
'number.human
|
311
|
-
'admin
|
312
|
-
'errors.messages
|
313
|
-
'activerecord.errors.messages
|
314
|
-
'will_paginate
|
315
|
-
'helpers.page_entries_info
|
316
|
-
'views.pagination
|
317
|
-
'enumerize.visibility
|
338
|
+
'number.human',
|
339
|
+
'admin',
|
340
|
+
'errors.messages',
|
341
|
+
'activerecord.errors.messages',
|
342
|
+
'will_paginate',
|
343
|
+
'helpers.page_entries_info',
|
344
|
+
'views.pagination',
|
345
|
+
'enumerize.visibility'
|
318
346
|
]
|
319
347
|
...
|
320
348
|
end
|
321
349
|
```
|
322
350
|
|
351
|
+
### Custom localization key prefixes
|
352
|
+
|
353
|
+
Rails YAML files contain not only translation strings but also localization values (integers, arrays, booleans)
|
354
|
+
in the same place and that's bad. For example: date formats, number separators, default
|
355
|
+
currency or measure units, etc.
|
356
|
+
|
357
|
+
A translator is supposed to translate, not localize. That's not his role to choose how you want your dates or
|
358
|
+
numbers to be displayed, right? Moreover, this special keys often contain special constructions (e.g.,
|
359
|
+
with percent signs or spaces) that he might break.
|
360
|
+
|
361
|
+
We think localization is part of the configuration of the app and it should not reach the translator UI at all.
|
362
|
+
That's why these localization keys are detected and separated on a dedicated YAML file with Translation.io.
|
363
|
+
|
364
|
+
We automatically treat [known localization keys](lib/translation_io/yaml_entry.rb), but if you would like
|
365
|
+
to add some more, use the `localization_key_prefixes` option.
|
366
|
+
|
367
|
+
For example:
|
368
|
+
|
369
|
+
```ruby
|
370
|
+
TranslationIO.configure do |config|
|
371
|
+
...
|
372
|
+
config.localization_key_prefixes = ['my_gem.date.formats']
|
373
|
+
...
|
374
|
+
end
|
375
|
+
```
|
376
|
+
|
323
377
|
### Source file formats (for GetText)
|
324
378
|
|
325
379
|
If you are using GetText and you want to manage other file formats than:
|
@@ -342,28 +396,15 @@ TranslationIO.configure do |config|
|
|
342
396
|
end
|
343
397
|
```
|
344
398
|
|
345
|
-
###
|
346
|
-
|
347
|
-
Rails YAML files contain not only translation strings but also localization values (integers, arrays, booleans)
|
348
|
-
in the same place and that's bad. For example: date formats, number separators, default
|
349
|
-
currency or measure units, etc.
|
350
|
-
|
351
|
-
A translator is supposed to translate, not localize. That's not his role to choose how you want your dates or
|
352
|
-
numbers to be displayed, right? Moreover, this special keys often contain special constructions (e.g.,
|
353
|
-
with percent signs or spaces) that he might break.
|
354
|
-
|
355
|
-
We think localization is part of the configuration of the app and it should not reach the translator UI at all.
|
356
|
-
That's why these localization keys are detected and separated on a dedicated YAML file with Translation.io.
|
399
|
+
### Gems with GetText strings
|
357
400
|
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
For example:
|
401
|
+
Public gems usually don't make use of GetText strings, but if you created and localized your own gems
|
402
|
+
with the GetText syntax, you'll want to be able to synchronize them:
|
362
403
|
|
363
404
|
```ruby
|
364
405
|
TranslationIO.configure do |config|
|
365
406
|
...
|
366
|
-
config.
|
407
|
+
config.parsed_gems = ['your_gem_name']
|
367
408
|
...
|
368
409
|
end
|
369
410
|
```
|
@@ -381,6 +422,30 @@ TranslationIO.configure do |config|
|
|
381
422
|
end
|
382
423
|
```
|
383
424
|
|
425
|
+
### GetText Object Class Monkey-Patching
|
426
|
+
|
427
|
+
GetText methods (`_('')`, etc.) are available everywhere in your application.
|
428
|
+
This is made by extending the global `Object` class.
|
429
|
+
|
430
|
+
You can disable the built-in `Object` monkey-patching if you
|
431
|
+
prefer a more granular approach:
|
432
|
+
|
433
|
+
```ruby
|
434
|
+
TranslationIO.configure do |config|
|
435
|
+
...
|
436
|
+
config.gettext_object_delegate = false
|
437
|
+
...
|
438
|
+
end
|
439
|
+
```
|
440
|
+
|
441
|
+
Don't forget to manually include the GetText methods where needed:
|
442
|
+
|
443
|
+
```ruby
|
444
|
+
class Contact < ApplicationRecord
|
445
|
+
extend TranslationIO::Proxy
|
446
|
+
end
|
447
|
+
```
|
448
|
+
|
384
449
|
## Pure Ruby (without Rails)
|
385
450
|
|
386
451
|
This gem was created specifically for Rails, but you can also use it in a pure Ruby project by making some arrangements:
|
@@ -483,9 +548,16 @@ Credits: [@deecewan](https://github.com/deecewan)
|
|
483
548
|
|
484
549
|
### Others
|
485
550
|
|
486
|
-
If you want to create a new client for your favorite language or framework,
|
487
|
-
|
488
|
-
|
551
|
+
If you want to create a new client for your favorite language or framework, please read our
|
552
|
+
[Create a Translation.io Library](https://translation.io/docs/create-library)
|
553
|
+
guide and use the special
|
554
|
+
[init](https://translation.io/docs/create-library#initialization) and
|
555
|
+
[sync](https://translation.io/docs/create-library#synchronization) endpoints.
|
556
|
+
|
557
|
+
You can also use the more [traditional API](https://translation.io/docs/api).
|
558
|
+
|
559
|
+
Feel free to contact us on [contact@translation.io](mailto:contact@translation.io) if
|
560
|
+
you need some help or if you want to share your library.
|
489
561
|
|
490
562
|
## License
|
491
563
|
|
data/lib/translation.rb
CHANGED
@@ -5,8 +5,6 @@ module TranslationIO
|
|
5
5
|
:nsgettext, :pgettext, :npgettext, :sgettext, :ngettext, :gettext,
|
6
6
|
:np_, :ns_, :Nn_, :n_, :p_, :s_, :N_, :_
|
7
7
|
]
|
8
|
-
|
9
|
-
TEXT_DOMAIN = 'app'
|
10
8
|
end
|
11
9
|
|
12
10
|
require 'translation_io/config'
|
@@ -33,7 +31,7 @@ module TranslationIO
|
|
33
31
|
|
34
32
|
yield @config
|
35
33
|
|
36
|
-
|
34
|
+
if !@config.disable_gettext
|
37
35
|
require_gettext_dependencies
|
38
36
|
add_missing_locales
|
39
37
|
add_parser_for_erb_source_formats(@config.erb_source_formats)
|
@@ -45,13 +43,18 @@ module TranslationIO
|
|
45
43
|
# include is private until Ruby 2.1
|
46
44
|
Proxy.send(:include, GetText)
|
47
45
|
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
46
|
+
@config.bound_text_domains.each do |bound_text_domain|
|
47
|
+
Proxy.bindtextdomain(bound_text_domain, {
|
48
|
+
:path => @config.locales_path,
|
49
|
+
:output_charset => @config.charset
|
50
|
+
})
|
51
|
+
end
|
52
|
+
|
53
|
+
Proxy.textdomain(@config.text_domain)
|
52
54
|
|
53
|
-
|
54
|
-
|
55
|
+
if @config.gettext_object_delegate
|
56
|
+
Object.delegate *GETTEXT_METHODS, :to => Proxy
|
57
|
+
end
|
55
58
|
end
|
56
59
|
|
57
60
|
@client = Client.new(@config.api_key, @config.endpoint)
|
@@ -9,8 +9,10 @@ module TranslationIO
|
|
9
9
|
def run
|
10
10
|
TranslationIO.info "Creating new MO files."
|
11
11
|
|
12
|
-
|
13
|
-
|
12
|
+
text_domain = TranslationIO.config.text_domain
|
13
|
+
|
14
|
+
Dir["#{@locales_path}/*/#{text_domain}.po"].each do |po_path|
|
15
|
+
mo_path = "#{File.dirname(po_path)}/LC_MESSAGES/#{text_domain}.mo"
|
14
16
|
TranslationIO.info mo_path, 2, 2
|
15
17
|
FileUtils.mkdir_p(File.dirname(mo_path))
|
16
18
|
GetText::Tools::MsgFmt.run(po_path, '-o', mo_path)
|
@@ -11,9 +11,11 @@ module TranslationIO
|
|
11
11
|
def run
|
12
12
|
TranslationIO.info "Saving new PO files."
|
13
13
|
|
14
|
+
text_domain = TranslationIO.config.text_domain
|
15
|
+
|
14
16
|
@target_locales.each do |target_locale|
|
15
17
|
if @parsed_response.has_key?("po_data_#{target_locale}")
|
16
|
-
po_path = File.join(@locales_path, Locale::Tag.parse(target_locale).to_s, "#{
|
18
|
+
po_path = File.join(@locales_path, Locale::Tag.parse(target_locale).to_s, "#{text_domain}.po")
|
17
19
|
FileUtils.mkdir_p(File.dirname(po_path))
|
18
20
|
TranslationIO.info po_path, 2, 2
|
19
21
|
|
@@ -19,7 +19,7 @@ module TranslationIO
|
|
19
19
|
|
20
20
|
yaml_data = YAMLConversion.get_yaml_data_from_po_data(@parsed_response["yaml_po_data_#{target_locale}"], target_locale)
|
21
21
|
|
22
|
-
top_comment =
|
22
|
+
top_comment = <<-EOS
|
23
23
|
# WARNING. THIS FILE WAS AUTO-GENERATED BY THE TRANSLATION GEM.
|
24
24
|
# IF YOU UPDATE IT, YOUR CHANGES WILL BE LOST AT THE NEXT SYNC.
|
25
25
|
#
|
@@ -24,6 +24,8 @@ module TranslationIO
|
|
24
24
|
YamlEntry.localization?(key, value)
|
25
25
|
end
|
26
26
|
|
27
|
+
params = {}
|
28
|
+
|
27
29
|
@target_locales.each do |target_locale|
|
28
30
|
yaml_path = File.join(@yaml_locales_path, "localization.#{target_locale}.yml")
|
29
31
|
|
@@ -35,32 +37,36 @@ module TranslationIO
|
|
35
37
|
|
36
38
|
yaml_data = YAMLConversion.get_yaml_data_from_flat_translations(target_flat_special_translations)
|
37
39
|
|
38
|
-
|
39
|
-
file.write(self.class.top_comment)
|
40
|
-
file.write(yaml_data)
|
41
|
-
end
|
42
|
-
end
|
40
|
+
params["yaml_data_#{target_locale}"] = yaml_data
|
43
41
|
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
42
|
+
# To have a localization.xx.yml file during tests (without call to backend)
|
43
|
+
if TranslationIO.config.test
|
44
|
+
if YAML::load(yaml_data).present?
|
45
|
+
File.open(yaml_path, 'wb') do |file|
|
46
|
+
file.write(self.class.top_comment)
|
47
|
+
file.write(yaml_data)
|
48
|
+
end
|
49
|
+
end
|
50
50
|
end
|
51
|
+
end
|
51
52
|
|
52
|
-
|
53
|
+
TranslationIO.info "Collecting YAML localization entries from server."
|
53
54
|
|
55
|
+
# To have a localization.xx.yml file with call to backend
|
56
|
+
if !TranslationIO.config.test
|
54
57
|
uri = URI("#{TranslationIO.client.endpoint}/projects/#{TranslationIO.client.api_key}/fill_yaml_localizations")
|
55
58
|
parsed_response = BaseOperation.perform_request(uri, params)
|
56
59
|
|
57
|
-
|
60
|
+
if !parsed_response.nil?
|
58
61
|
@target_locales.each do |target_locale|
|
59
62
|
yaml_path = File.join(@yaml_locales_path, "localization.#{target_locale}.yml")
|
63
|
+
yaml_data = parsed_response["yaml_data_#{target_locale}"]
|
60
64
|
|
61
|
-
|
62
|
-
|
63
|
-
|
65
|
+
if yaml_data.present? && YAML::load(yaml_data).present?
|
66
|
+
File.open(yaml_path, 'wb') do |file|
|
67
|
+
file.write(self.class.top_comment)
|
68
|
+
file.write(yaml_data)
|
69
|
+
end
|
64
70
|
end
|
65
71
|
end
|
66
72
|
end
|
@@ -68,7 +74,7 @@ module TranslationIO
|
|
68
74
|
end
|
69
75
|
|
70
76
|
def self.top_comment
|
71
|
-
|
77
|
+
<<-EOS
|
72
78
|
# THIS FILE CONTAINS LOCALIZATION KEYS : date and number formats, number precisions,
|
73
79
|
# number separators and all non-textual values depending on the language.
|
74
80
|
# These values must not reach the translator, so they are separated in this file.
|
@@ -19,7 +19,7 @@ module TranslationIO
|
|
19
19
|
yaml_locales_path = config.yaml_locales_path
|
20
20
|
yaml_file_paths = config.yaml_file_paths
|
21
21
|
|
22
|
-
|
22
|
+
if !config.disable_gettext
|
23
23
|
BaseOperation::DumpMarkupGettextKeysStep.new(haml_source_files, :haml).run
|
24
24
|
BaseOperation::DumpMarkupGettextKeysStep.new(slim_source_files, :slim).run
|
25
25
|
end
|
@@ -27,27 +27,34 @@ module TranslationIO
|
|
27
27
|
UpdatePotFileStep.new(pot_path, source_files + erb_source_files).run(params)
|
28
28
|
UpdateAndCollectPoFilesStep.new(target_locales, pot_path, locales_path).run(params)
|
29
29
|
|
30
|
-
|
31
|
-
|
30
|
+
if !config.disable_yaml
|
31
|
+
create_yaml_pot_files_step = CreateYamlPoFilesStep.new(source_locale, target_locales, yaml_file_paths)
|
32
|
+
create_yaml_pot_files_step.run(params)
|
32
33
|
|
33
|
-
|
34
|
+
all_used_yaml_locales = create_yaml_pot_files_step.all_used_yaml_locales.to_a.map(&:to_s).sort
|
34
35
|
|
35
|
-
|
36
|
-
|
36
|
+
warn_source_locale_unfound(source_locale, all_used_yaml_locales)
|
37
|
+
warn_target_locale_unfound(target_locales, all_used_yaml_locales)
|
38
|
+
end
|
37
39
|
|
38
40
|
TranslationIO.info "Sending data to server (it may take some time, please be patient. Sync will be faster)."
|
39
41
|
|
40
42
|
uri = URI("#{client.endpoint}/projects/#{client.api_key}/init")
|
41
43
|
parsed_response = BaseOperation.perform_request(uri, params)
|
42
44
|
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
45
|
+
if !parsed_response.nil?
|
46
|
+
if !config.disable_gettext
|
47
|
+
BaseOperation::SaveNewPoFilesStep.new(target_locales, locales_path, parsed_response).run
|
48
|
+
BaseOperation::CreateNewMoFilesStep.new(locales_path).run
|
49
|
+
end
|
50
|
+
|
51
|
+
if !config.disable_yaml
|
52
|
+
BaseOperation::SaveNewYamlFilesStep.new(target_locales, yaml_locales_path, parsed_response).run
|
53
|
+
BaseOperation::SaveSpecialYamlFilesStep.new(source_locale, target_locales, yaml_locales_path, yaml_file_paths).run
|
54
|
+
CleanupYamlFilesStep.new(source_locale, target_locales, yaml_file_paths, yaml_locales_path).run
|
55
|
+
info_yaml_directory_structure
|
56
|
+
end
|
49
57
|
|
50
|
-
info_yaml_directory_structure
|
51
58
|
info_project_url(parsed_response)
|
52
59
|
end
|
53
60
|
|
@@ -55,7 +62,7 @@ module TranslationIO
|
|
55
62
|
end
|
56
63
|
|
57
64
|
def warn_source_locale_unfound(source_locale, all_used_yaml_locales)
|
58
|
-
is_source_locale_unfound = !
|
65
|
+
is_source_locale_unfound = !all_used_yaml_locales.include?(source_locale)
|
59
66
|
|
60
67
|
if is_source_locale_unfound
|
61
68
|
puts
|
@@ -81,7 +88,7 @@ module TranslationIO
|
|
81
88
|
puts
|
82
89
|
puts "----------"
|
83
90
|
puts "Your `config.target_locales` are [#{target_locales.sort.join(', ')}]."
|
84
|
-
puts "But we haven't found any YAML key for [#{target_locales_unfound.join(', ')}], is this normal?"
|
91
|
+
puts "But we haven't found any YAML key for [#{target_locales_unfound.sort.join(', ')}], is this normal?"
|
85
92
|
puts "If not, check that you haven't misspelled the locale (ex. 'en-GB' instead of 'en')."
|
86
93
|
puts "----------"
|
87
94
|
puts "Do you want to continue? (y/N)"
|
@@ -13,22 +13,28 @@ module TranslationIO
|
|
13
13
|
@yaml_file_paths.each do |locale_file_path|
|
14
14
|
if locale_file_removable?(locale_file_path)
|
15
15
|
if File.exist?(locale_file_path)
|
16
|
-
content_hash
|
16
|
+
content_hash = YAML::load(File.read(locale_file_path)) || {}
|
17
|
+
source_content_hash = content_hash.select { |k| k.to_s == @source_locale.to_s }
|
17
18
|
|
18
|
-
if
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
end
|
23
|
-
|
24
|
-
if new_content_hash.keys.any?
|
19
|
+
if source_content_hash.empty?
|
20
|
+
TranslationIO.info "Removing #{locale_file_path}", 2, 2
|
21
|
+
FileUtils.rm(locale_file_path)
|
22
|
+
elsif content_hash != source_content_hash # in case of mixed languages in source YAML file
|
25
23
|
TranslationIO.info "Rewriting #{locale_file_path}", 2, 2
|
24
|
+
|
25
|
+
if TranslationIO.config.yaml_line_width
|
26
|
+
file_content = source_content_hash.to_yaml(:line_width => TranslationIO.config.yaml_line_width)
|
27
|
+
else
|
28
|
+
file_content = source_content_hash.to_yaml
|
29
|
+
end
|
30
|
+
|
31
|
+
file_content = file_content.gsub(/ $/, '') # remove trailing spaces
|
32
|
+
|
26
33
|
File.open(locale_file_path, 'wb') do |file|
|
27
|
-
file.write(
|
34
|
+
file.write(file_content)
|
28
35
|
end
|
29
36
|
else
|
30
|
-
|
31
|
-
FileUtils.rm(locale_file_path)
|
37
|
+
# don't touch source
|
32
38
|
end
|
33
39
|
end
|
34
40
|
end
|
@@ -11,8 +11,10 @@ module TranslationIO
|
|
11
11
|
def run(params)
|
12
12
|
TranslationIO.info "Updating PO files."
|
13
13
|
|
14
|
+
text_domain = TranslationIO.config.text_domain
|
15
|
+
|
14
16
|
@target_locales.each do |target_locale|
|
15
|
-
po_path = "#{@locales_path}/#{Locale::Tag.parse(target_locale).to_s}/#{
|
17
|
+
po_path = "#{@locales_path}/#{Locale::Tag.parse(target_locale).to_s}/#{text_domain}.po"
|
16
18
|
TranslationIO.info po_path, 2, 2
|
17
19
|
|
18
20
|
if File.exist?(po_path)
|
@@ -22,15 +22,20 @@ module TranslationIO
|
|
22
22
|
yaml_locales_path = config.yaml_locales_path
|
23
23
|
yaml_file_paths = config.yaml_file_paths
|
24
24
|
|
25
|
-
|
25
|
+
if !config.disable_yaml
|
26
|
+
ApplyYamlSourceEditsStep.new(yaml_file_paths, source_locale).run(params)
|
27
|
+
end
|
26
28
|
|
27
|
-
|
29
|
+
if !config.disable_gettext
|
28
30
|
BaseOperation::DumpMarkupGettextKeysStep.new(haml_source_files, :haml).run
|
29
31
|
BaseOperation::DumpMarkupGettextKeysStep.new(slim_source_files, :slim).run
|
30
32
|
end
|
31
33
|
|
32
34
|
UpdatePotFileStep.new(pot_path, source_files + erb_source_files).run(params)
|
33
|
-
|
35
|
+
|
36
|
+
if !config.disable_yaml
|
37
|
+
CreateYamlPotFileStep.new(source_locale, yaml_file_paths).run(params)
|
38
|
+
end
|
34
39
|
|
35
40
|
if purge
|
36
41
|
params['purge'] = 'true'
|
@@ -45,11 +50,16 @@ module TranslationIO
|
|
45
50
|
uri = URI("#{client.endpoint}/projects/#{client.api_key}/sync")
|
46
51
|
parsed_response = BaseOperation.perform_request(uri, params)
|
47
52
|
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
+
if !parsed_response.nil?
|
54
|
+
if !config.disable_gettext
|
55
|
+
BaseOperation::SaveNewPoFilesStep.new(target_locales, locales_path, parsed_response).run
|
56
|
+
BaseOperation::CreateNewMoFilesStep.new(locales_path).run
|
57
|
+
end
|
58
|
+
|
59
|
+
if !config.disable_yaml
|
60
|
+
BaseOperation::SaveNewYamlFilesStep.new(target_locales, yaml_locales_path, parsed_response).run
|
61
|
+
BaseOperation::SaveSpecialYamlFilesStep.new(source_locale, target_locales, yaml_locales_path, yaml_file_paths).run
|
62
|
+
end
|
53
63
|
|
54
64
|
display_unused_segments(parsed_response, show_purgeable, purge)
|
55
65
|
|
@@ -12,66 +12,123 @@ module TranslationIO
|
|
12
12
|
|
13
13
|
params.merge!({ :timestamp => metadata_timestamp })
|
14
14
|
parsed_response = perform_source_edits_request(params)
|
15
|
+
source_edits = parsed_response['source_edits'].to_a
|
15
16
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
sort_by_project_locales_first(@yaml_file_paths).each do |file_path|
|
23
|
-
yaml_hash = YAML::load(File.read(file_path))
|
24
|
-
flat_yaml_hash = FlatHash.to_flat_hash(yaml_hash)
|
25
|
-
|
26
|
-
flat_yaml_hash.each do |key, value|
|
27
|
-
if key == "#{@source_locale}.#{source_edit['key']}"
|
28
|
-
if value == source_edit['old_text']
|
29
|
-
TranslationIO.info "#{source_edit['key']} | #{source_edit['old_text']} -> #{source_edit['new_text']}", 2, 2
|
30
|
-
|
31
|
-
if locale_file_path_in_project?(file_path)
|
32
|
-
flat_yaml_hash[key] = source_edit['new_text']
|
33
|
-
|
34
|
-
File.open(file_path, 'w') do |f|
|
35
|
-
f.write(FlatHash.to_hash(flat_yaml_hash).to_yaml)
|
36
|
-
end
|
37
|
-
else # override source text of gem
|
38
|
-
yaml_path = File.join(TranslationIO.config.yaml_locales_path, "#{@source_locale}.yml")
|
39
|
-
|
40
|
-
if File.exists?(yaml_path) # source yaml file
|
41
|
-
yaml_hash = YAML::load(File.read(yaml_path))
|
42
|
-
flat_yaml_hash = FlatHash.to_flat_hash(yaml_hash)
|
43
|
-
else
|
44
|
-
FileUtils::mkdir_p File.dirname(yaml_path)
|
45
|
-
flat_yaml_hash = {}
|
46
|
-
end
|
47
|
-
|
48
|
-
flat_yaml_hash["#{@source_locale}.#{source_edit['key']}"] = source_edit['new_text']
|
49
|
-
|
50
|
-
File.open(yaml_path, 'w') do |f|
|
51
|
-
f.write(FlatHash.to_hash(flat_yaml_hash).to_yaml)
|
52
|
-
end
|
53
|
-
end
|
54
|
-
|
55
|
-
inserted = true
|
56
|
-
break
|
57
|
-
else
|
58
|
-
TranslationIO.info "#{source_edit['key']} | Ignored because translation was also updated in source YAML file", 2, 2
|
59
|
-
end
|
60
|
-
end
|
61
|
-
end
|
17
|
+
TranslationIO.info "Applying YAML source editions."
|
18
|
+
|
19
|
+
source_edits.each do |source_edit|
|
20
|
+
applied = false
|
21
|
+
|
22
|
+
reload_or_reuse_yaml_sources
|
62
23
|
|
63
|
-
|
24
|
+
@yaml_sources.each do |yaml_source|
|
25
|
+
yaml_file_path = yaml_source[:yaml_file_path]
|
26
|
+
yaml_flat_hash = yaml_source[:yaml_flat_hash]
|
27
|
+
|
28
|
+
yaml_flat_hash.each do |full_key, value|
|
29
|
+
if full_key == "#{@source_locale}.#{source_edit['key']}"
|
30
|
+
apply_source_edit(source_edit, yaml_file_path, yaml_flat_hash)
|
31
|
+
applied = true
|
32
|
+
break
|
33
|
+
end
|
64
34
|
end
|
35
|
+
|
36
|
+
break if applied
|
65
37
|
end
|
66
38
|
end
|
67
39
|
|
68
|
-
|
69
|
-
f.write({ 'timestamp' => Time.now.utc.to_i }.to_yaml)
|
70
|
-
end
|
40
|
+
update_metadata_timestamp
|
71
41
|
end
|
72
42
|
|
73
43
|
private
|
74
44
|
|
45
|
+
def reload_or_reuse_yaml_sources
|
46
|
+
if yaml_sources_reload_needed?
|
47
|
+
@yaml_sources = sort_by_project_locales_first(@yaml_file_paths).collect do |yaml_file_path|
|
48
|
+
yaml_content = File.read(yaml_file_path)
|
49
|
+
yaml_hash = YAML::load(yaml_content)
|
50
|
+
yaml_flat_hash = FlatHash.to_flat_hash(yaml_hash)
|
51
|
+
|
52
|
+
{
|
53
|
+
:yaml_file_path => yaml_file_path,
|
54
|
+
:yaml_flat_hash => yaml_flat_hash
|
55
|
+
}
|
56
|
+
end
|
57
|
+
else
|
58
|
+
@yaml_sources
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def yaml_sources_reload_needed?
|
63
|
+
@yaml_file_paths.sort != @yaml_sources.to_a.collect { |y_s| y_s[:yaml_file_path] }.sort
|
64
|
+
end
|
65
|
+
|
66
|
+
# Sort YAML file paths by project locales first, gem locales after
|
67
|
+
# (to replace "overridden" source first)
|
68
|
+
def sort_by_project_locales_first(yaml_file_paths)
|
69
|
+
yaml_file_paths.sort do |x, y|
|
70
|
+
a = locale_file_path_in_project?(x)
|
71
|
+
b = locale_file_path_in_project?(y)
|
72
|
+
(!a && b) ? 1 : ((a && !b) ? -1 : 0)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def apply_source_edit(source_edit, yaml_file_path, yaml_flat_hash)
|
77
|
+
full_key = "#{@source_locale}.#{source_edit['key']}"
|
78
|
+
|
79
|
+
if yaml_flat_hash[full_key] == source_edit['old_text']
|
80
|
+
TranslationIO.info "#{source_edit['key']} | #{source_edit['old_text']} -> #{source_edit['new_text']}", 2, 2
|
81
|
+
|
82
|
+
if locale_file_path_in_project?(yaml_file_path)
|
83
|
+
apply_application_source_edit(source_edit, yaml_file_path, yaml_flat_hash)
|
84
|
+
else # Override source text of gem inside the app
|
85
|
+
apply_gem_source_edit(source_edit)
|
86
|
+
end
|
87
|
+
else
|
88
|
+
TranslationIO.info "#{source_edit['key']} | #{source_edit['old_text']} -> #{source_edit['new_text']} | Ignored because translation was also updated in source YAML file", 2, 2
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
def apply_application_source_edit(source_edit, yaml_file_path, yaml_flat_hash)
|
93
|
+
full_key = "#{@source_locale}.#{source_edit['key']}"
|
94
|
+
yaml_flat_hash[full_key] = source_edit['new_text']
|
95
|
+
file_content = to_hash_to_yaml(yaml_flat_hash)
|
96
|
+
|
97
|
+
File.open(yaml_file_path, 'w') do |f|
|
98
|
+
f.write(file_content)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
def apply_gem_source_edit(source_edit)
|
103
|
+
# Source yaml file like config/locales/en.yml
|
104
|
+
yaml_file_path = File.expand_path(File.join(TranslationIO.config.yaml_locales_path, "#{@source_locale}.yml"))
|
105
|
+
|
106
|
+
if File.exists?(yaml_file_path)
|
107
|
+
# Complete existing hash if YAML file already exists
|
108
|
+
existing_yaml_source = @yaml_sources.detect { |y_s| normalize_path(y_s[:yaml_file_path]) == normalize_path(yaml_file_path) }
|
109
|
+
yaml_flat_hash = existing_yaml_source[:yaml_flat_hash]
|
110
|
+
else
|
111
|
+
# Create new hash if YAML file doesn't exist yet
|
112
|
+
FileUtils::mkdir_p File.dirname(yaml_file_path)
|
113
|
+
yaml_flat_hash = {}
|
114
|
+
@yaml_file_paths.push(yaml_file_path) # Application YAML are at the end of the list
|
115
|
+
end
|
116
|
+
|
117
|
+
apply_application_source_edit(source_edit, yaml_file_path, yaml_flat_hash)
|
118
|
+
end
|
119
|
+
|
120
|
+
def to_hash_to_yaml(yaml_flat_hash)
|
121
|
+
yaml_hash = FlatHash.to_hash(yaml_flat_hash)
|
122
|
+
|
123
|
+
if TranslationIO.config.yaml_line_width
|
124
|
+
content = yaml_hash.to_yaml(:line_width => TranslationIO.config.yaml_line_width)
|
125
|
+
else
|
126
|
+
content = yaml_hash.to_yaml
|
127
|
+
end
|
128
|
+
|
129
|
+
content.gsub(/ $/, '') # remove trailing spaces
|
130
|
+
end
|
131
|
+
|
75
132
|
def metadata_timestamp
|
76
133
|
if File.exist?(TranslationIO.config.metadata_path)
|
77
134
|
metadata_content = File.read(TranslationIO.config.metadata_path)
|
@@ -87,26 +144,26 @@ module TranslationIO
|
|
87
144
|
end
|
88
145
|
end
|
89
146
|
|
147
|
+
def update_metadata_timestamp
|
148
|
+
File.open(TranslationIO.config.metadata_path, 'w') do |f|
|
149
|
+
f.write({ 'timestamp' => Time.now.utc.to_i }.to_yaml)
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
90
153
|
def perform_source_edits_request(params)
|
91
154
|
uri = URI("#{TranslationIO.client.endpoint}/projects/#{TranslationIO.client.api_key}/source_edits")
|
92
155
|
parsed_response = BaseOperation.perform_request(uri, params)
|
93
156
|
end
|
94
157
|
|
95
|
-
# Sort YAML file paths by project locales first, gem locales after
|
96
|
-
# (to replace "overridden" source first)
|
97
|
-
def sort_by_project_locales_first(yaml_file_paths)
|
98
|
-
yaml_file_paths.sort do |x, y|
|
99
|
-
a = locale_file_path_in_project?(x)
|
100
|
-
b = locale_file_path_in_project?(y)
|
101
|
-
(!a && b) ? 1 : ((a && !b) ? -1 : 0)
|
102
|
-
end
|
103
|
-
end
|
104
|
-
|
105
158
|
def locale_file_path_in_project?(locale_file_path)
|
106
|
-
|
107
|
-
|
159
|
+
normalize_path(locale_file_path).start_with?(
|
160
|
+
normalize_path(TranslationIO.config.yaml_locales_path)
|
108
161
|
)
|
109
162
|
end
|
163
|
+
|
164
|
+
def normalize_path(path)
|
165
|
+
TranslationIO.normalize_path(path)
|
166
|
+
end
|
110
167
|
end
|
111
168
|
end
|
112
169
|
end
|
@@ -1,24 +1,40 @@
|
|
1
1
|
module TranslationIO
|
2
2
|
class Config
|
3
|
-
attr_accessor :api_key
|
4
|
-
attr_accessor :source_locale
|
3
|
+
attr_accessor :api_key
|
4
|
+
attr_accessor :source_locale
|
5
|
+
attr_accessor :target_locales
|
5
6
|
attr_accessor :endpoint
|
7
|
+
attr_accessor :metadata_path
|
6
8
|
attr_accessor :verbose
|
7
9
|
attr_accessor :test
|
8
10
|
|
11
|
+
attr_accessor :disable_yaml
|
12
|
+
|
13
|
+
attr_accessor :yaml_locales_path
|
9
14
|
attr_accessor :ignored_key_prefixes
|
15
|
+
attr_accessor :localization_key_prefixes
|
16
|
+
attr_accessor :yaml_line_width
|
17
|
+
attr_accessor :yaml_remove_empty_keys
|
18
|
+
|
19
|
+
attr_accessor :disable_gettext
|
20
|
+
|
21
|
+
attr_accessor :gettext_object_delegate
|
22
|
+
|
23
|
+
attr_accessor :locales_path
|
24
|
+
|
10
25
|
attr_accessor :ignored_source_paths
|
11
26
|
attr_accessor :ignored_source_files
|
12
27
|
|
28
|
+
attr_accessor :parsed_gems
|
29
|
+
|
13
30
|
attr_accessor :source_formats
|
14
31
|
attr_accessor :erb_source_formats
|
15
32
|
attr_accessor :haml_source_formats
|
16
33
|
attr_accessor :slim_source_formats
|
17
34
|
|
18
|
-
attr_accessor :
|
19
|
-
attr_accessor :
|
35
|
+
attr_accessor :text_domain
|
36
|
+
attr_accessor :bound_text_domains
|
20
37
|
attr_accessor :charset
|
21
|
-
attr_accessor :metadata_path
|
22
38
|
|
23
39
|
attr_accessor :pot_msgid_bugs_address
|
24
40
|
attr_accessor :pot_package_name
|
@@ -27,37 +43,84 @@ module TranslationIO
|
|
27
43
|
attr_accessor :pot_copyright_year
|
28
44
|
|
29
45
|
def initialize
|
30
|
-
self.locales_path = File.join('config', 'locales', 'gettext')
|
31
|
-
self.yaml_locales_path = File.join('config', 'locales')
|
32
|
-
self.source_locale = :en
|
33
|
-
self.target_locales = []
|
34
|
-
self.endpoint = 'https://translation.io/api'
|
35
|
-
self.verbose = 1
|
36
|
-
self.test = false
|
37
|
-
|
38
|
-
self.ignored_key_prefixes = []
|
39
|
-
self.ignored_source_paths = ['vendor/', 'tmp/']
|
40
|
-
self.ignored_source_files = [] # Files not parsed for GetText entries
|
41
|
-
|
42
|
-
self.source_formats = ['rb', 'ruby', 'rabl']
|
43
|
-
self.erb_source_formats = ['erb', 'inky']
|
44
|
-
self.haml_source_formats = ['haml', 'mjmlhaml']
|
45
|
-
self.slim_source_formats = ['slim', 'mjmlslim']
|
46
46
|
|
47
|
+
#######
|
48
|
+
# Global options
|
49
|
+
#######
|
50
|
+
|
51
|
+
self.api_key = ''
|
52
|
+
self.source_locale = :en
|
53
|
+
self.target_locales = []
|
54
|
+
self.endpoint = 'https://translation.io/api'
|
55
|
+
self.metadata_path = File.join('config', 'locales', '.translation_io')
|
56
|
+
self.verbose = 1
|
57
|
+
self.test = false
|
58
|
+
|
59
|
+
#######
|
60
|
+
# YAML options
|
61
|
+
#######
|
62
|
+
|
63
|
+
self.disable_yaml = false
|
64
|
+
|
65
|
+
# YAML directory
|
66
|
+
self.yaml_locales_path = File.join('config', 'locales')
|
67
|
+
|
68
|
+
# Ignored YAML key prefixes (like 'will_paginate.')
|
69
|
+
self.ignored_key_prefixes = []
|
70
|
+
|
71
|
+
# Cf. https://github.com/translation/rails#custom-localization-key-prefixes
|
47
72
|
self.localization_key_prefixes = []
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
self.
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
self.
|
73
|
+
|
74
|
+
# Define max line width of generated YAML files:
|
75
|
+
# Can be nil (default behaviour of Ruby version), -1 (no wrapping) or positive integer (wrapping)
|
76
|
+
# Cf. https://github.com/translation/rails/issues/19
|
77
|
+
self.yaml_line_width = nil
|
78
|
+
|
79
|
+
# Remove empty keys from translated YAML files
|
80
|
+
# Cf. https://github.com/translation/rails/pull/37
|
81
|
+
self.yaml_remove_empty_keys = false
|
82
|
+
|
83
|
+
#######
|
84
|
+
# GetText options
|
85
|
+
#######
|
86
|
+
|
87
|
+
self.disable_gettext = false
|
88
|
+
|
89
|
+
# Cf. https://github.com/translation/rails#gettext-object-class-monkey-patching
|
90
|
+
self.gettext_object_delegate = true
|
91
|
+
|
92
|
+
# GetText directory for PO and MO files
|
93
|
+
self.locales_path = File.join('config', 'locales', 'gettext')
|
94
|
+
|
95
|
+
# These paths and files will not be parsed for GetText entries
|
96
|
+
self.ignored_source_paths = ['vendor/', 'tmp/', 'node_modules/', 'logs/', '.git/', 'public/', 'private/']
|
97
|
+
self.ignored_source_files = []
|
98
|
+
|
99
|
+
# These gems will be parsed by GetText (use gem names)
|
100
|
+
self.parsed_gems = []
|
101
|
+
|
102
|
+
# Extensions for rb/erb/haml/slim file parsers
|
103
|
+
self.source_formats = ['rb', 'ruby', 'rabl']
|
104
|
+
self.erb_source_formats = ['erb', 'inky']
|
105
|
+
self.haml_source_formats = ['haml', 'mjmlhaml']
|
106
|
+
self.slim_source_formats = ['slim', 'mjmlslim']
|
107
|
+
|
108
|
+
# 'text_domain' will be synced (name of .po/.mo files)
|
109
|
+
# 'bound_text_domains' will be read during execution (in that priority order)
|
110
|
+
self.text_domain = 'app'
|
111
|
+
self.bound_text_domains = ['app']
|
112
|
+
self.charset = 'UTF-8'
|
113
|
+
|
114
|
+
# POT header informations
|
115
|
+
self.pot_msgid_bugs_address = 'contact@translation.io'
|
116
|
+
self.pot_package_name = File.basename(Dir.pwd)
|
117
|
+
self.pot_package_version = '1.0'
|
118
|
+
self.pot_copyright_holder = File.basename(Dir.pwd)
|
119
|
+
self.pot_copyright_year = Date.today.year
|
57
120
|
end
|
58
121
|
|
59
122
|
def pot_path
|
60
|
-
File.join(locales_path, "#{
|
123
|
+
File.join(locales_path, "#{text_domain}.pot")
|
61
124
|
end
|
62
125
|
|
63
126
|
def yaml_file_paths
|
@@ -83,19 +146,45 @@ module TranslationIO
|
|
83
146
|
end
|
84
147
|
|
85
148
|
def source_files_for_formats(formats)
|
86
|
-
file_paths =
|
87
|
-
|
88
|
-
|
89
|
-
|
149
|
+
file_paths = []
|
150
|
+
root_paths = ['.']
|
151
|
+
|
152
|
+
# Add gem paths that need to be parsed by GetText ("parsed_gem" option)
|
153
|
+
parsed_gems.each do |gem_name|
|
154
|
+
if Gem.loaded_specs[gem_name]
|
155
|
+
root_paths << Gem.loaded_specs[gem_name].full_gem_path
|
156
|
+
end
|
157
|
+
end
|
90
158
|
|
91
|
-
|
92
|
-
|
93
|
-
|
159
|
+
root_paths.each do |root_path|
|
160
|
+
Pathname.new(root_path).find do |path|
|
161
|
+
if path.directory?
|
162
|
+
if is_ignored_path?(path)
|
163
|
+
Find.prune
|
164
|
+
end
|
165
|
+
else
|
166
|
+
if formats.include?(path.extname[1..-1]) && !is_ignored_file?(path)
|
167
|
+
file_paths << path.to_s
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|
94
171
|
end
|
95
172
|
|
96
173
|
file_paths
|
97
174
|
end
|
98
175
|
|
176
|
+
def is_ignored_path?(path)
|
177
|
+
ignored_source_paths.any? do |ignored_source_path|
|
178
|
+
path == Pathname.new(ignored_source_path).cleanpath
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
def is_ignored_file?(path)
|
183
|
+
ignored_source_files.any? do |ignored_source_file|
|
184
|
+
path == Pathname.new(ignored_source_file).cleanpath
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
99
188
|
def to_s
|
100
189
|
"API Key: #{api_key} | Languages: #{source_locale} => [#{target_locales.join(', ')}]"
|
101
190
|
end
|
@@ -7,9 +7,13 @@ module TranslationIO
|
|
7
7
|
get_flat_hash_for_level(hash)
|
8
8
|
end
|
9
9
|
|
10
|
-
def to_hash(flat_hash)
|
10
|
+
def to_hash(flat_hash, remove_empty_keys = false)
|
11
11
|
hash = {}
|
12
12
|
|
13
|
+
if remove_empty_keys
|
14
|
+
flat_hash = flat_hash.reject { |k, v| v.blank? && !k.end_with?(']') }
|
15
|
+
end
|
16
|
+
|
13
17
|
flat_hash.each_pair do |key, value|
|
14
18
|
build_hash_with_flat(hash, key, value)
|
15
19
|
end
|
@@ -7,8 +7,10 @@ module TranslationIO
|
|
7
7
|
require 'translation_io/tasks'
|
8
8
|
end
|
9
9
|
|
10
|
-
initializer 'translation.
|
11
|
-
|
10
|
+
initializer 'translation.controller_helper' do
|
11
|
+
ActiveSupport.on_load :action_controller do
|
12
|
+
ActionController::Base.send(:include, TranslationIO::Controller)
|
13
|
+
end
|
12
14
|
end
|
13
15
|
|
14
16
|
config.after_initialize do
|
@@ -49,8 +51,12 @@ if defined?(GetText)
|
|
49
51
|
begin
|
50
52
|
parse_path(path, po)
|
51
53
|
rescue SystemExit => e
|
52
|
-
# puts(_("Error parsing %{path}") % {:path => path})
|
53
54
|
puts
|
55
|
+
puts "---------------"
|
56
|
+
puts "Error while parsing this file for GetText: #{path}"
|
57
|
+
puts "Are you sure the file is correctly formatted?"
|
58
|
+
puts "Feel free to contact us to get some help: contact@translation.io"
|
59
|
+
puts "---------------"
|
54
60
|
puts
|
55
61
|
end
|
56
62
|
end
|
@@ -36,8 +36,16 @@ module TranslationIO
|
|
36
36
|
end
|
37
37
|
|
38
38
|
def get_yaml_data_from_flat_translations(flat_translations)
|
39
|
-
|
40
|
-
|
39
|
+
remove_empty_keys = TranslationIO.config.yaml_remove_empty_keys
|
40
|
+
translations = FlatHash.to_hash(flat_translations, remove_empty_keys)
|
41
|
+
|
42
|
+
if TranslationIO.config.yaml_line_width
|
43
|
+
data = translations.to_yaml(:line_width => TranslationIO.config.yaml_line_width)
|
44
|
+
else
|
45
|
+
data = translations.to_yaml
|
46
|
+
end
|
47
|
+
|
48
|
+
data.gsub(/ $/, '') # remove trailing spaces
|
41
49
|
end
|
42
50
|
|
43
51
|
end
|
@@ -2,7 +2,7 @@ module TranslationIO
|
|
2
2
|
module YamlEntry
|
3
3
|
|
4
4
|
IGNORED_KEY_PREFIXES = [
|
5
|
-
'faker
|
5
|
+
'faker'
|
6
6
|
]
|
7
7
|
|
8
8
|
LOCALIZATION_KEY_PREFIXES = [
|
@@ -31,7 +31,7 @@ module TranslationIO
|
|
31
31
|
end
|
32
32
|
|
33
33
|
def ignored?(key)
|
34
|
-
key.present? && ignored_key_prefixes.any? { |
|
34
|
+
key.present? && ignored_key_prefixes.any? { |prefix| key_without_locale(key).match(/^#{Regexp.escape(prefix)}\b/) != nil }
|
35
35
|
end
|
36
36
|
|
37
37
|
def localization?(key, value)
|
@@ -40,7 +40,7 @@ module TranslationIO
|
|
40
40
|
|
41
41
|
def localization_prefix?(key)
|
42
42
|
localization_key_prefixes.any? do |prefix|
|
43
|
-
key_without_locale(key).
|
43
|
+
key_without_locale(key).match(/^#{Regexp.escape(prefix)}\b/) != nil
|
44
44
|
end
|
45
45
|
end
|
46
46
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: translation
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: '1.
|
4
|
+
version: '1.22'
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Michael Hoste
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2020-07-27 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: gettext
|
@@ -35,30 +35,30 @@ dependencies:
|
|
35
35
|
name: rake
|
36
36
|
requirement: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- - "
|
38
|
+
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: '0'
|
40
|
+
version: '12.0'
|
41
41
|
type: :development
|
42
42
|
prerelease: false
|
43
43
|
version_requirements: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
|
-
- - "
|
45
|
+
- - "~>"
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version: '0'
|
47
|
+
version: '12.0'
|
48
48
|
- !ruby/object:Gem::Dependency
|
49
49
|
name: simplecov
|
50
50
|
requirement: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
|
-
- - "
|
52
|
+
- - "~>"
|
53
53
|
- !ruby/object:Gem::Version
|
54
|
-
version: '0'
|
54
|
+
version: '0.11'
|
55
55
|
type: :development
|
56
56
|
prerelease: false
|
57
57
|
version_requirements: !ruby/object:Gem::Requirement
|
58
58
|
requirements:
|
59
|
-
- - "
|
59
|
+
- - "~>"
|
60
60
|
- !ruby/object:Gem::Version
|
61
|
-
version: '0'
|
61
|
+
version: '0.11'
|
62
62
|
- !ruby/object:Gem::Dependency
|
63
63
|
name: rspec
|
64
64
|
requirement: !ruby/object:Gem::Requirement
|
@@ -144,10 +144,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
144
144
|
version: '0'
|
145
145
|
requirements: []
|
146
146
|
rubyforge_project:
|
147
|
-
rubygems_version: 2.
|
147
|
+
rubygems_version: 2.7.6
|
148
148
|
signing_key:
|
149
149
|
specification_version: 4
|
150
150
|
summary: Localize your app with YAML or GetText. Synchronize with your translators
|
151
151
|
on Translation.io.
|
152
152
|
test_files: []
|
153
|
-
has_rdoc: false
|