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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6448a3718185d09a6712428f671e02121e59c967199ae6e24f27b8623f12b280
4
- data.tar.gz: c0f2501d9c937b26088ee23a6603a842121cb6a88516ae19d09d40abe1968161
3
+ metadata.gz: d8c05601cd8f8684c1523aa4b92d87d10afad700c50d197e40b6886fd4bc9412
4
+ data.tar.gz: ddc3d0616655b4bda4a40ecf1a96af9c17c5ef54d7c372a05bdf9eb29c2dcdee
5
5
  SHA512:
6
- metadata.gz: be178f379eb4abbb4d50c4f3817422c665bed0c8a75f256c083b0229a57594956ca8c42648fe98be40ed1c4183f0e00fd51fcaf153a87ed408279c1d2ac152ec
7
- data.tar.gz: db7dd0efdb0d9a7b72116adba959a04b899e41d5ccd89181f48e2ec2e1d097ebfebb732e6592c725b831cebf89134e77e0639deb8591876267306583064efa96
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',
@@ -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 << api_client.upload_file(
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?
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module LokaliseRails
4
- VERSION = '1.4.0'
4
+ VERSION = '2.0.0.rc1'
5
5
  end
@@ -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 '189934715f57a162257d74.88352370' do
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('189934715f57a162257d74.88352370')
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
- File.open("#{Rails.root}/config/locales/nested/en.yml", 'w+:UTF-8') do |f|
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
- File.open("#{Rails.root}/config/locales/ru.yml", 'w+:UTF-8') do |f|
36
- f.write ru_data
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
- File.open("#{Rails.root}/config/lokalise_rails.rb", 'w+:UTF-8') do |f|
50
- f.write data
51
- end
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
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module SpecAddons
4
- def allow_project_id(value = ENV['LOKALISE_PROJECT_ID'])
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: 1.4.0
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-07-29 00:00:00.000000000 Z
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: '0'
260
+ version: 1.3.1
261
261
  requirements: []
262
- rubygems_version: 3.2.24
262
+ rubygems_version: 3.2.25
263
263
  signing_key:
264
264
  specification_version: 4
265
265
  summary: Lokalise integration for Ruby on Rails