lokalise_rails 1.4.0 → 2.0.0.rc1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +12 -0
- data/README.md +2 -0
- data/lib/generators/templates/lokalise_rails_config.rb +3 -0
- data/lib/lokalise_rails.rb +6 -1
- data/lib/lokalise_rails/task_definition/base.rb +1 -1
- data/lib/lokalise_rails/task_definition/exporter.rb +16 -3
- data/lib/lokalise_rails/version.rb +1 -1
- data/spec/lib/lokalise_rails/task_definition/exporter_spec.rb +40 -0
- data/spec/lib/lokalise_rails/task_definition/importer_spec.rb +3 -2
- data/spec/lib/lokalise_rails_spec.rb +5 -0
- data/spec/support/file_manager.rb +17 -9
- data/spec/support/spec_addons.rb +1 -1
- metadata +5 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d8c05601cd8f8684c1523aa4b92d87d10afad700c50d197e40b6886fd4bc9412
|
4
|
+
data.tar.gz: ddc3d0616655b4bda4a40ecf1a96af9c17c5ef54d7c372a05bdf9eb29c2dcdee
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1bfb463dbed7826bf9cad245c53cca76b5ec0c0bc35ddeb42c24c0e9789e93d77adf45e12c772dfcb764e60ffbe3724ecbebb0106bbead653030db1a458df275
|
7
|
+
data.tar.gz: aadd4c0108d6871683c90f4d0d8647f80f072a34e0d4597ec9d4fcb97a9e9494e085b6fe93481925d71a594e0a110ef6575d0499ede0e407d517727bdb0b9baf
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,17 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
+
## 2.0.0.rc1 (12-Aug-21)
|
4
|
+
|
5
|
+
* **Lokalise is introducing API rate limiting.** Access to all endpoints will be limited to 6 requests per second from 14 September, 2021. This limit is applied per API token and per IP address. If you exceed the limit, a 429 HTTP status code will be returned and a `Lokalise::Error::TooManyRequests` exception will be raised. Therefore, to overcome this issue LokaliseRails is introducing an exponential backoff mechanism for file exports. Why? Because if you have, say, 10 translation files, we'll have to send 10 separate API requests which will probably mean exceeding the limit (this is not the case with importing as we're always receiving a single archive). Thus, if the HTTP status code 429 was received, we'll do the following:
|
6
|
+
|
7
|
+
```ruby
|
8
|
+
sleep 2 ** retries
|
9
|
+
retries += 1
|
10
|
+
```
|
11
|
+
|
12
|
+
* If the maximum number of retries has been reached LokaliseRails will re-raise the `Lokalise::Error::TooManyRequests` error and give up. By default, the maximum number of retries is set to `5` but you can control it using the `max_retries_export` option.
|
13
|
+
* Enabled compression for the API client.
|
14
|
+
|
3
15
|
## 1.4.0 (29-Jun-21)
|
4
16
|
|
5
17
|
* Re-worked exception handling. Now when something goes wrong during the import or export process, this gem will re-raise all such errors (previously it just printed out some errors to the `$stdout`). If you run a Rake task, it will exit with a status code `1` and the actual error message. If you run a task programattically, you'll get an exception.
|
data/README.md
CHANGED
@@ -134,6 +134,8 @@ en_US:
|
|
134
134
|
c.skip_file_export = ->(file) { f.split[1].to_s.include?('fr') }
|
135
135
|
```
|
136
136
|
|
137
|
+
* `max_retries_export` (`integer`) - this option is introduced to properly handle Lokalise API rate limiting during file exporting. If the HTTP status code 429 (too many requests) has been received, LokaliseRails will apply an exponential backoff mechanism with a very simple formula: `2 ** retries` (initially `retries` is `0`). If the maximum number of retries has been reached, a `Lokalise::Error::TooManyRequests` exception will be raised and the export operation will be halted. By default, LokaliseRails will make up to `5` retries which potentially means `1 + 2 + 4 + 8 + 16 + 32 = 63` seconds of waiting time. If the `max_retries_export` is less than `1`, LokaliseRails will not perform any retries and give up immediately after receiving error 429.
|
138
|
+
|
137
139
|
### Settings to work with formats other than YAML
|
138
140
|
|
139
141
|
If your translation files are not in YAML format, you will need to adjust the following options:
|
@@ -16,6 +16,9 @@ LokaliseRails.config do |c|
|
|
16
16
|
# Provide request timeouts for the Lokalise API client:
|
17
17
|
# c.timeouts = {open_timeout: nil, timeout: nil}
|
18
18
|
|
19
|
+
# Provide maximum number of retries for file exporting:
|
20
|
+
# c.max_retries_export = 5
|
21
|
+
|
19
22
|
# Import options have the following defaults:
|
20
23
|
# c.import_opts = {
|
21
24
|
# format: 'yaml',
|
data/lib/lokalise_rails.rb
CHANGED
@@ -10,7 +10,7 @@ module LokaliseRails
|
|
10
10
|
attr_accessor :api_token, :project_id
|
11
11
|
attr_writer :import_opts, :import_safe_mode, :export_opts, :locales_path,
|
12
12
|
:file_ext_regexp, :skip_file_export, :branch, :timeouts,
|
13
|
-
:translations_loader, :translations_converter, :lang_iso_inferer
|
13
|
+
:translations_loader, :translations_converter, :lang_iso_inferer, :max_retries_export
|
14
14
|
|
15
15
|
# Main interface to provide configuration options for rake tasks
|
16
16
|
def config
|
@@ -32,6 +32,11 @@ module LokaliseRails
|
|
32
32
|
@timeouts || {}
|
33
33
|
end
|
34
34
|
|
35
|
+
# Maximum number of retries for file exporting
|
36
|
+
def max_retries_export
|
37
|
+
@max_retries_export || 5
|
38
|
+
end
|
39
|
+
|
35
40
|
# Regular expression used to select translation files with proper extensions
|
36
41
|
def file_ext_regexp
|
37
42
|
@file_ext_regexp || /\.ya?ml\z/i
|
@@ -13,7 +13,7 @@ module LokaliseRails
|
|
13
13
|
#
|
14
14
|
# @return [Lokalise::Client]
|
15
15
|
def api_client
|
16
|
-
@api_client ||= ::Lokalise.client LokaliseRails.api_token, LokaliseRails.timeouts
|
16
|
+
@api_client ||= ::Lokalise.client LokaliseRails.api_token, {enable_compression: true}.merge(LokaliseRails.timeouts)
|
17
17
|
end
|
18
18
|
|
19
19
|
# Resets API client
|
@@ -14,9 +14,7 @@ module LokaliseRails
|
|
14
14
|
|
15
15
|
queued_processes = []
|
16
16
|
each_file do |full_path, relative_path|
|
17
|
-
queued_processes <<
|
18
|
-
project_id_with_branch, opts(full_path, relative_path)
|
19
|
-
)
|
17
|
+
queued_processes << do_upload(full_path, relative_path)
|
20
18
|
rescue StandardError => e
|
21
19
|
raise e.class, "Error while trying to upload #{full_path}: #{e.message}"
|
22
20
|
end
|
@@ -26,6 +24,21 @@ module LokaliseRails
|
|
26
24
|
queued_processes
|
27
25
|
end
|
28
26
|
|
27
|
+
# Performs the actual file uploading to Lokalise. If the API rate limit is exceeed,
|
28
|
+
# applies exponential backoff
|
29
|
+
def do_upload(f_path, r_path)
|
30
|
+
retries = 0
|
31
|
+
begin
|
32
|
+
api_client.upload_file project_id_with_branch, opts(f_path, r_path)
|
33
|
+
rescue Lokalise::Error::TooManyRequests => e
|
34
|
+
raise(e.class, "Gave up after #{retries} retries") if retries >= LokaliseRails.max_retries_export
|
35
|
+
|
36
|
+
sleep 2**retries
|
37
|
+
retries += 1
|
38
|
+
retry
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
29
42
|
# Processes each translation file in the specified directory
|
30
43
|
def each_file
|
31
44
|
return unless block_given?
|
@@ -7,6 +7,45 @@ describe LokaliseRails::TaskDefinition::Exporter do
|
|
7
7
|
let(:path) { "#{Rails.root}/config/locales/nested/#{filename}" }
|
8
8
|
let(:relative_name) { "nested/#{filename}" }
|
9
9
|
|
10
|
+
context 'with many translation files' do
|
11
|
+
let(:fake_class) { described_class }
|
12
|
+
|
13
|
+
before :all do
|
14
|
+
add_translation_files! with_ru: true, additional: 5
|
15
|
+
end
|
16
|
+
|
17
|
+
after :all do
|
18
|
+
rm_translation_files
|
19
|
+
end
|
20
|
+
|
21
|
+
describe '.export!' do
|
22
|
+
it 'sends a proper API request and handles rate limiting' do
|
23
|
+
allow_project_id '672198945b7d72fc048021.15940510'
|
24
|
+
|
25
|
+
process = VCR.use_cassette('upload_files_multiple') do
|
26
|
+
described_class.export!
|
27
|
+
end.first
|
28
|
+
|
29
|
+
expect(process.project_id).to eq(LokaliseRails.project_id)
|
30
|
+
expect(process.status).to eq('queued')
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'handles too many requests' do
|
34
|
+
allow_project_id '672198945b7d72fc048021.15940510'
|
35
|
+
allow(LokaliseRails).to receive(:max_retries_export).and_return(2)
|
36
|
+
|
37
|
+
fake_client = double
|
38
|
+
allow(fake_client).to receive(:upload_file).and_raise(Lokalise::Error::TooManyRequests)
|
39
|
+
allow(fake_class).to receive(:api_client).and_return(fake_client)
|
40
|
+
|
41
|
+
expect(-> { fake_class.export! }).to raise_error(Lokalise::Error::TooManyRequests, /Gave up after 2 retries/i)
|
42
|
+
expect(LokaliseRails).to have_received(:max_retries_export).exactly(3).times
|
43
|
+
expect(fake_class).to have_received(:api_client).exactly(3).times
|
44
|
+
expect(fake_client).to have_received(:upload_file).exactly(3).times
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
10
49
|
context 'with one translation file' do
|
11
50
|
before :all do
|
12
51
|
add_translation_files!
|
@@ -26,6 +65,7 @@ describe LokaliseRails::TaskDefinition::Exporter do
|
|
26
65
|
|
27
66
|
expect(process.project_id).to eq(LokaliseRails.project_id)
|
28
67
|
expect(process.status).to eq('queued')
|
68
|
+
expect(LokaliseRails.max_retries_export).to eq(5)
|
29
69
|
end
|
30
70
|
|
31
71
|
it 'sends a proper API request when a different branch is provided' do
|
@@ -17,13 +17,14 @@ describe LokaliseRails::TaskDefinition::Importer do
|
|
17
17
|
|
18
18
|
describe '.download_files' do
|
19
19
|
it 'returns a proper download URL' do
|
20
|
-
allow_project_id '
|
20
|
+
allow_project_id '672198945b7d72fc048021.15940510' do
|
21
21
|
response = VCR.use_cassette('download_files') do
|
22
22
|
described_class.download_files
|
23
23
|
end
|
24
24
|
|
25
|
-
expect(response['project_id']).to eq('
|
25
|
+
expect(response['project_id']).to eq('672198945b7d72fc048021.15940510')
|
26
26
|
expect(response['bundle_url']).to include('s3-eu-west-1.amazonaws.com')
|
27
|
+
expect(described_class.api_client.enable_compression).to eq(true)
|
27
28
|
end
|
28
29
|
end
|
29
30
|
|
@@ -58,6 +58,11 @@ describe LokaliseRails do
|
|
58
58
|
fake_class.import_safe_mode = true
|
59
59
|
end
|
60
60
|
|
61
|
+
it 'is possible to set max_retries_export' do
|
62
|
+
allow(fake_class).to receive(:max_retries_export=).with(10)
|
63
|
+
fake_class.max_retries_export = 10
|
64
|
+
end
|
65
|
+
|
61
66
|
it 'is possible to set api_token' do
|
62
67
|
allow(fake_class).to receive(:api_token=).with('abc')
|
63
68
|
fake_class.api_token = 'abc'
|
@@ -24,16 +24,20 @@ module FileManager
|
|
24
24
|
locales_dir.count { |file| File.file?(file) }
|
25
25
|
end
|
26
26
|
|
27
|
-
def add_translation_files!(with_ru: false)
|
27
|
+
def add_translation_files!(with_ru: false, additional: nil)
|
28
28
|
FileUtils.mkdir_p "#{Rails.root}/config/locales/nested"
|
29
|
-
|
30
|
-
f.write en_data
|
31
|
-
end
|
29
|
+
open_and_write('config/locales/nested/en.yml') { |f| f.write en_data }
|
32
30
|
|
33
31
|
return unless with_ru
|
34
32
|
|
35
|
-
|
36
|
-
|
33
|
+
open_and_write('config/locales/ru.yml') { |f| f.write ru_data }
|
34
|
+
|
35
|
+
return unless additional
|
36
|
+
|
37
|
+
additional.times do |i|
|
38
|
+
data = {'en' => {"key_#{i}" => "value #{i}"}}
|
39
|
+
|
40
|
+
open_and_write("config/locales/en_#{i}.yml") { |f| f.write data.to_yaml }
|
37
41
|
end
|
38
42
|
end
|
39
43
|
|
@@ -46,9 +50,13 @@ module FileManager
|
|
46
50
|
end
|
47
51
|
DATA
|
48
52
|
|
49
|
-
|
50
|
-
|
51
|
-
|
53
|
+
open_and_write('config/lokalise_rails.rb') { |f| f.write data }
|
54
|
+
end
|
55
|
+
|
56
|
+
def open_and_write(rel_path, &block)
|
57
|
+
return unless block
|
58
|
+
|
59
|
+
File.open("#{Rails.root}/#{rel_path}", 'w+:UTF-8', &block)
|
52
60
|
end
|
53
61
|
|
54
62
|
def remove_config
|
data/spec/support/spec_addons.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module SpecAddons
|
4
|
-
def allow_project_id(value =
|
4
|
+
def allow_project_id(value = '189934715f57a162257d74.88352370')
|
5
5
|
allow(LokaliseRails).to receive(:project_id).and_return(value)
|
6
6
|
return unless block_given?
|
7
7
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: lokalise_rails
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 2.0.0.rc1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ilya Bodrov
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-
|
11
|
+
date: 2021-08-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: ruby-lokalise-api
|
@@ -255,11 +255,11 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
255
255
|
version: 2.5.0
|
256
256
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
257
257
|
requirements:
|
258
|
-
- - "
|
258
|
+
- - ">"
|
259
259
|
- !ruby/object:Gem::Version
|
260
|
-
version:
|
260
|
+
version: 1.3.1
|
261
261
|
requirements: []
|
262
|
-
rubygems_version: 3.2.
|
262
|
+
rubygems_version: 3.2.25
|
263
263
|
signing_key:
|
264
264
|
specification_version: 4
|
265
265
|
summary: Lokalise integration for Ruby on Rails
|