ruby-lokalise-api 3.1.0 → 4.3.0
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/.github/CONTRIBUTING.md +7 -0
- data/CHANGELOG.md +1 -116
- data/LICENSE +9 -18
- data/README.md +17 -1847
- data/lib/ruby-lokalise-api.rb +1 -0
- data/lib/ruby-lokalise-api/client.rb +3 -2
- data/lib/ruby-lokalise-api/collections/base.rb +1 -1
- data/lib/ruby-lokalise-api/connection.rb +10 -4
- data/lib/ruby-lokalise-api/data/attributes.json +6 -2
- data/lib/ruby-lokalise-api/resources/base.rb +4 -4
- data/lib/ruby-lokalise-api/resources/project.rb +1 -1
- data/lib/ruby-lokalise-api/resources/webhook.rb +1 -1
- data/lib/ruby-lokalise-api/rest/files.rb +2 -1
- data/lib/ruby-lokalise-api/utils/attribute_helpers.rb +12 -9
- data/lib/ruby-lokalise-api/utils/string_utils.rb +1 -1
- data/lib/ruby-lokalise-api/version.rb +1 -1
- data/ruby-lokalise-api.gemspec +5 -3
- data/spec/lib/ruby-lokalise-api/connection_spec.rb +39 -1
- data/spec/lib/ruby-lokalise-api/custom_json_parser_spec.rb +4 -4
- data/spec/lib/ruby-lokalise-api/rest/orders_spec.rb +26 -2
- data/spec/lib/ruby-lokalise-api/rest/payment_cards_spec.rb +3 -3
- data/spec/lib/ruby-lokalise-api/rest/tasks_spec.rb +8 -7
- data/spec/lib/ruby-lokalise-api/rest/translations_spec.rb +10 -9
- data/spec/lib/ruby-lokalise-api_spec.rb +6 -0
- metadata +26 -12
data/lib/ruby-lokalise-api.rb
CHANGED
@@ -24,12 +24,13 @@ require 'ruby-lokalise-api/rest/webhooks'
|
|
24
24
|
module Lokalise
|
25
25
|
class Client
|
26
26
|
attr_reader :token
|
27
|
-
attr_accessor :timeout, :open_timeout
|
27
|
+
attr_accessor :timeout, :open_timeout, :enable_compression
|
28
28
|
|
29
29
|
def initialize(token, params = {})
|
30
30
|
@token = token
|
31
31
|
@timeout = params.fetch(:timeout, nil)
|
32
32
|
@open_timeout = params.fetch(:open_timeout, nil)
|
33
|
+
@enable_compression = params.fetch(:enable_compression, false)
|
33
34
|
end
|
34
35
|
|
35
36
|
# rubocop:disable Metrics/ParameterLists
|
@@ -56,7 +57,7 @@ module Lokalise
|
|
56
57
|
return params unless object_key
|
57
58
|
|
58
59
|
params = [params] unless params.is_a?(Array)
|
59
|
-
|
60
|
+
{object_key => params}
|
60
61
|
end
|
61
62
|
|
62
63
|
alias c_r construct_request
|
@@ -91,7 +91,7 @@ module Lokalise
|
|
91
91
|
# Collection example: `{ "content": {"comments": [ ... ]} }`
|
92
92
|
def produce_collection_for(response)
|
93
93
|
model_class = self.class.name.base_class_name
|
94
|
-
data_key_plural = data_key_for model_class, true, true
|
94
|
+
data_key_plural = data_key_for model_class: model_class, plural: true, collection: true
|
95
95
|
|
96
96
|
# Fetch collection data and instantiate an individual resource for each object
|
97
97
|
# We also preserve the `client` to be able to chain API methods later
|
@@ -5,7 +5,16 @@ module Lokalise
|
|
5
5
|
BASE_URL = 'https://api.lokalise.com/api2/'
|
6
6
|
|
7
7
|
def connection(client)
|
8
|
-
options
|
8
|
+
Faraday.new(options(client), request_params_for(client)) do |faraday|
|
9
|
+
faraday.use(:gzip) if client.enable_compression
|
10
|
+
faraday.adapter Faraday.default_adapter
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
def options(client)
|
17
|
+
{
|
9
18
|
headers: {
|
10
19
|
accept: 'application/json',
|
11
20
|
user_agent: "ruby-lokalise-api gem/#{Lokalise::VERSION}",
|
@@ -13,11 +22,8 @@ module Lokalise
|
|
13
22
|
},
|
14
23
|
url: BASE_URL
|
15
24
|
}
|
16
|
-
Faraday.new(options, request_params_for(client)) { |faraday| faraday.adapter Faraday.default_adapter }
|
17
25
|
end
|
18
26
|
|
19
|
-
private
|
20
|
-
|
21
27
|
# Allows to customize request params per-client
|
22
28
|
def request_params_for(client)
|
23
29
|
{request: {timeout: client.timeout, open_timeout: client.open_timeout}}
|
@@ -86,7 +86,9 @@
|
|
86
86
|
"translation_tier",
|
87
87
|
"translation_tier_name",
|
88
88
|
"briefing",
|
89
|
-
"total"
|
89
|
+
"total",
|
90
|
+
"payment_method",
|
91
|
+
"dry_run"
|
90
92
|
],
|
91
93
|
"payment_card": [
|
92
94
|
"card_id",
|
@@ -162,6 +164,7 @@
|
|
162
164
|
"languages",
|
163
165
|
"auto_close_languages",
|
164
166
|
"auto_close_task",
|
167
|
+
"auto_close_items",
|
165
168
|
"completed_at",
|
166
169
|
"completed_at_timestamp",
|
167
170
|
"completed_by",
|
@@ -207,7 +210,8 @@
|
|
207
210
|
"is_fuzzy",
|
208
211
|
"is_reviewed",
|
209
212
|
"words",
|
210
|
-
"custom_translation_statuses"
|
213
|
+
"custom_translation_statuses",
|
214
|
+
"task_id"
|
211
215
|
],
|
212
216
|
"translation_provider": [
|
213
217
|
"provider_id",
|
@@ -95,7 +95,7 @@ module Lokalise
|
|
95
95
|
# Instantiates a new resource or collection based on the given response
|
96
96
|
def object_from(response, params)
|
97
97
|
model_class = name.base_class_name
|
98
|
-
data_key_plural = data_key_for model_class, true
|
98
|
+
data_key_plural = data_key_for model_class: model_class, plural: true
|
99
99
|
# Preserve the initial path to allow chaining
|
100
100
|
response['path'] = params.delete(:_initial_path) if params.key?(:_initial_path)
|
101
101
|
|
@@ -107,7 +107,7 @@ module Lokalise
|
|
107
107
|
end
|
108
108
|
|
109
109
|
def produce_resource(model_class, response)
|
110
|
-
data_key_singular = data_key_for model_class
|
110
|
+
data_key_singular = data_key_for model_class: model_class
|
111
111
|
if response['content'].key? data_key_singular
|
112
112
|
data = response['content'].delete data_key_singular
|
113
113
|
response['content'].merge! data
|
@@ -124,7 +124,7 @@ module Lokalise
|
|
124
124
|
# Generates path for the individual resource based on the path for the collection
|
125
125
|
def infer_path_from(response, endpoint_generator = nil)
|
126
126
|
id_key = id_key_for self.class.name.base_class_name
|
127
|
-
data_key = data_key_for self.class.name.base_class_name
|
127
|
+
data_key = data_key_for model_class: self.class.name.base_class_name
|
128
128
|
|
129
129
|
path_with_id response, id_key, data_key, endpoint_generator
|
130
130
|
end
|
@@ -164,7 +164,7 @@ module Lokalise
|
|
164
164
|
# Store all resources attributes under the corresponding instance variables.
|
165
165
|
# `ATTRIBUTES` is defined inside resource-specific classes
|
166
166
|
def populate_attributes_for(content)
|
167
|
-
data_key = data_key_for self.class.name.base_class_name
|
167
|
+
data_key = data_key_for model_class: self.class.name.base_class_name
|
168
168
|
|
169
169
|
self.class.const_get(:ATTRIBUTES).each do |attr|
|
170
170
|
value = if content.key?(data_key) && content[data_key].is_a?(Hash)
|
@@ -22,7 +22,8 @@ module Lokalise
|
|
22
22
|
c_r Lokalise::Resources::File, :download, [project_id, 'download'], params
|
23
23
|
end
|
24
24
|
|
25
|
-
# Imports translation file to the given project. File data must base64-encoded
|
25
|
+
# Imports translation file to the given project. File data must base64-encoded.
|
26
|
+
# To encode your data in Base64, use `Base64.strict_encode64()` method.
|
26
27
|
#
|
27
28
|
# @see https://app.lokalise.com/api2docs/curl/#transition-upload-a-file-post
|
28
29
|
# @return [Hash]
|
@@ -16,16 +16,21 @@ module Lokalise
|
|
16
16
|
# @return [String]
|
17
17
|
# @param model_class [String]
|
18
18
|
# @param plural [Boolean] Should the returned value be pluralized?
|
19
|
-
def data_key_for(model_class
|
20
|
-
data_key_plural = get_key(
|
19
|
+
def data_key_for(model_class:, plural: false, collection: false)
|
20
|
+
data_key_plural = get_key(
|
21
|
+
name: 'DATA_KEY_PLURAL',
|
22
|
+
model_class: model_class,
|
23
|
+
collection: true,
|
24
|
+
strict: true
|
25
|
+
)
|
21
26
|
|
22
27
|
return data_key_plural if collection && data_key_plural
|
23
28
|
|
24
|
-
data_key = get_key 'DATA_KEY', model_class, collection
|
29
|
+
data_key = get_key name: 'DATA_KEY', model_class: model_class, collection: collection
|
25
30
|
|
26
31
|
return data_key unless plural
|
27
32
|
|
28
|
-
data_key
|
33
|
+
"#{data_key}s"
|
29
34
|
end
|
30
35
|
|
31
36
|
# Returns key used to determine resource id (for example `user_id` or `project_id`).
|
@@ -35,16 +40,14 @@ module Lokalise
|
|
35
40
|
# @return [String]
|
36
41
|
# @param model_class [String]
|
37
42
|
def id_key_for(model_class)
|
38
|
-
get_key('ID_KEY', model_class)
|
43
|
+
"#{get_key(name: 'ID_KEY', model_class: model_class)}_id"
|
39
44
|
end
|
40
45
|
|
41
46
|
# Loads attributes for the given resource based on its name
|
42
47
|
#
|
43
48
|
# @return [Array<String>]
|
44
49
|
def attributes_for(klass)
|
45
|
-
@attributes ||=
|
46
|
-
YAML.load_file(File.expand_path('../data/attributes.json', __dir__)).freeze
|
47
|
-
end
|
50
|
+
@attributes ||= YAML.load_file(File.expand_path('../data/attributes.json', __dir__)).freeze
|
48
51
|
|
49
52
|
name = unify klass.name.snakecase
|
50
53
|
@attributes[name]
|
@@ -52,7 +55,7 @@ module Lokalise
|
|
52
55
|
|
53
56
|
private
|
54
57
|
|
55
|
-
def get_key(name
|
58
|
+
def get_key(name:, model_class:, collection: false, strict: false)
|
56
59
|
key = if collection && Module.const_defined?("Lokalise::Collections::#{model_class}::#{name}")
|
57
60
|
Module.const_get "Lokalise::Collections::#{model_class}::#{name}"
|
58
61
|
elsif Module.const_defined? "Lokalise::Resources::#{model_class}::#{name}"
|
data/ruby-lokalise-api.gemspec
CHANGED
@@ -10,8 +10,9 @@ Gem::Specification.new do |spec|
|
|
10
10
|
spec.summary = 'Ruby interface to the Lokalise API'
|
11
11
|
spec.description = 'Opinionated Ruby client for the Lokalise platform API allowing to work with translations, projects, users and other resources as with Ruby objects.'
|
12
12
|
spec.homepage = 'https://github.com/lokalise/ruby-lokalise-api'
|
13
|
-
spec.license = '
|
13
|
+
spec.license = 'BSD-3-Clause'
|
14
14
|
spec.platform = Gem::Platform::RUBY
|
15
|
+
spec.required_ruby_version = '>= 2.5.0'
|
15
16
|
|
16
17
|
spec.files = Dir['README.md', 'LICENSE',
|
17
18
|
'CHANGELOG.md', 'lib/**/*.rb', 'lib/ruby-lokalise-api/data/attributes.json',
|
@@ -23,6 +24,7 @@ Gem::Specification.new do |spec|
|
|
23
24
|
|
24
25
|
spec.add_dependency 'addressable', '~> 2.5'
|
25
26
|
spec.add_dependency 'faraday', '~> 1.0'
|
27
|
+
spec.add_dependency 'faraday_middleware', '~> 1.0'
|
26
28
|
spec.add_dependency 'json', '>= 1.8.0'
|
27
29
|
|
28
30
|
spec.add_development_dependency 'codecov', '~> 0.1'
|
@@ -30,9 +32,9 @@ Gem::Specification.new do |spec|
|
|
30
32
|
spec.add_development_dependency 'oj', '~> 3.10'
|
31
33
|
spec.add_development_dependency 'rake', '~> 13.0'
|
32
34
|
spec.add_development_dependency 'rspec', '~> 3.6'
|
33
|
-
spec.add_development_dependency 'rubocop', '~>
|
35
|
+
spec.add_development_dependency 'rubocop', '~> 1.6'
|
34
36
|
spec.add_development_dependency 'rubocop-performance', '~> 1.5'
|
35
|
-
spec.add_development_dependency 'rubocop-rspec', '~>
|
37
|
+
spec.add_development_dependency 'rubocop-rspec', '~> 2.0'
|
36
38
|
spec.add_development_dependency 'simplecov', '~> 0.16'
|
37
39
|
spec.add_development_dependency 'vcr', '~> 6.0'
|
38
40
|
end
|
@@ -3,6 +3,9 @@
|
|
3
3
|
RSpec.describe Lokalise::Connection do
|
4
4
|
include described_class
|
5
5
|
|
6
|
+
let(:project_id) { '803826145ba90b42d5d860.46800099' }
|
7
|
+
let(:key_id) { 44_596_059 }
|
8
|
+
|
6
9
|
before { Lokalise.reset_client! }
|
7
10
|
|
8
11
|
after do
|
@@ -10,11 +13,12 @@ RSpec.describe Lokalise::Connection do
|
|
10
13
|
Faraday.default_adapter = :net_http
|
11
14
|
end
|
12
15
|
|
13
|
-
it 'timeouts should not be set by default but the token must be present' do
|
16
|
+
it 'timeouts and compression should not be set by default but the token must be present' do
|
14
17
|
conn = connection test_client
|
15
18
|
expect(conn.options.timeout).to be_nil
|
16
19
|
expect(conn.options.open_timeout).to be_nil
|
17
20
|
expect(conn.headers['X-api-token']).to eq(test_client.token)
|
21
|
+
expect(conn.builder.handlers).not_to include(FaradayMiddleware::Gzip)
|
18
22
|
end
|
19
23
|
|
20
24
|
it 'allows to customize timeouts' do
|
@@ -42,4 +46,38 @@ RSpec.describe Lokalise::Connection do
|
|
42
46
|
expect(another_conn.builder.adapter).to eq(Faraday::Adapter::Excon)
|
43
47
|
expect(conn.builder.adapter).to eq(Faraday::Adapter::NetHttp)
|
44
48
|
end
|
49
|
+
|
50
|
+
it 'allows to customize compression' do
|
51
|
+
custom_client = Lokalise.client(ENV['LOKALISE_API_TOKEN'], enable_compression: true)
|
52
|
+
conn = connection custom_client
|
53
|
+
expect(conn.headers['X-api-token']).to eq(custom_client.token)
|
54
|
+
expect(conn.builder.handlers).to include(FaradayMiddleware::Gzip)
|
55
|
+
end
|
56
|
+
|
57
|
+
it 'is possible to enable gzip compression' do
|
58
|
+
gzip_client = Lokalise.client(ENV['LOKALISE_API_TOKEN'], enable_compression: true)
|
59
|
+
keys = VCR.use_cassette('all_keys_gzip') do
|
60
|
+
gzip_client.keys project_id
|
61
|
+
end.collection
|
62
|
+
|
63
|
+
expect(keys.first.key_id).to eq(key_id)
|
64
|
+
end
|
65
|
+
|
66
|
+
it 'is possible to disable gzip compression' do
|
67
|
+
no_gzip_client = Lokalise.client(ENV['LOKALISE_API_TOKEN'], enable_compression: false)
|
68
|
+
keys = VCR.use_cassette('all_keys_no_gzip') do
|
69
|
+
no_gzip_client.keys project_id
|
70
|
+
end.collection
|
71
|
+
|
72
|
+
expect(keys.first.key_id).to eq(key_id)
|
73
|
+
end
|
74
|
+
|
75
|
+
it 'gzip compression is off by default' do
|
76
|
+
default_gzip_client = Lokalise.client(ENV['LOKALISE_API_TOKEN'])
|
77
|
+
keys = VCR.use_cassette('all_keys_default_gzip') do
|
78
|
+
default_gzip_client.keys project_id
|
79
|
+
end.collection
|
80
|
+
|
81
|
+
expect(keys.first.key_id).to eq(key_id)
|
82
|
+
end
|
45
83
|
end
|
@@ -27,7 +27,7 @@ RSpec.describe Lokalise::JsonHandler do
|
|
27
27
|
'{":name":"rspec proj",":description":"demo project for rspec"}'
|
28
28
|
end
|
29
29
|
|
30
|
-
# rubocop:disable RSpec/LeakyConstantDeclaration
|
30
|
+
# rubocop:disable RSpec/LeakyConstantDeclaration, Lint/ConstantDefinitionInBlock
|
31
31
|
before do
|
32
32
|
module Lokalise
|
33
33
|
module JsonHandler
|
@@ -55,10 +55,10 @@ RSpec.describe Lokalise::JsonHandler do
|
|
55
55
|
end
|
56
56
|
end
|
57
57
|
end
|
58
|
-
# rubocop:enable RSpec/LeakyConstantDeclaration
|
58
|
+
# rubocop:enable RSpec/LeakyConstantDeclaration, Lint/ConstantDefinitionInBlock
|
59
59
|
|
60
60
|
it 'allows to customize #load' do
|
61
|
-
|
61
|
+
allow(Oj).to receive(:load).and_return(loaded_json)
|
62
62
|
expect(JSON).not_to receive(:parse)
|
63
63
|
projects = VCR.use_cassette('all_projects_pagination') do
|
64
64
|
test_client.projects limit: 1, page: 2
|
@@ -70,7 +70,7 @@ RSpec.describe Lokalise::JsonHandler do
|
|
70
70
|
end
|
71
71
|
|
72
72
|
it 'allows to customize #dump' do
|
73
|
-
|
73
|
+
allow(Oj).to receive(:dump).and_return(dumped_json)
|
74
74
|
expect(JSON).not_to receive(:dump)
|
75
75
|
project = VCR.use_cassette('new_project') do
|
76
76
|
test_client.create_project name: 'rspec proj', description: 'demo project for rspec'
|
@@ -37,8 +37,8 @@ RSpec.describe Lokalise::Client do
|
|
37
37
|
|
38
38
|
expect(order.order_id).to eq(order_id)
|
39
39
|
expect(order.project_id).to eq(project_id)
|
40
|
-
expect(order.card_id).to eq(card_id
|
41
|
-
expect(order.status).to eq('
|
40
|
+
expect(order.card_id).to eq(card_id)
|
41
|
+
expect(order.status).to eq('completed')
|
42
42
|
expect(order.created_at).to eq('2019-03-19 18:18:21 (Etc/UTC)')
|
43
43
|
expect(order.created_by).to eq(20_181)
|
44
44
|
expect(order.created_by_email).to eq('bodrovis@protonmail.com')
|
@@ -52,6 +52,7 @@ RSpec.describe Lokalise::Client do
|
|
52
52
|
expect(order.translation_tier_name).to eq('Professional translator')
|
53
53
|
expect(order.briefing).to eq('Some briefing')
|
54
54
|
expect(order.total).to eq(0.07)
|
55
|
+
expect(order.payment_method).to be_nil
|
55
56
|
end
|
56
57
|
|
57
58
|
specify '#reload_data' do
|
@@ -86,4 +87,27 @@ RSpec.describe Lokalise::Client do
|
|
86
87
|
expect(order.order_id).to eq(order_id)
|
87
88
|
expect(order.status).to eq('in progress')
|
88
89
|
end
|
90
|
+
|
91
|
+
it 'creates an order with dry run' do
|
92
|
+
order = VCR.use_cassette('create_order_dry_run') do
|
93
|
+
test_client.create_order team_id,
|
94
|
+
project_id: project_id,
|
95
|
+
card_id: card_id,
|
96
|
+
briefing: 'Some briefing',
|
97
|
+
source_language_iso: 'en',
|
98
|
+
target_language_isos: [
|
99
|
+
'ru'
|
100
|
+
],
|
101
|
+
keys: [
|
102
|
+
74_189_435
|
103
|
+
],
|
104
|
+
provider_slug: 'gengo',
|
105
|
+
translation_tier: '1',
|
106
|
+
dry_run: true
|
107
|
+
end
|
108
|
+
|
109
|
+
expect(order.order_id).to be_nil
|
110
|
+
expect(order.status).to eq('draft')
|
111
|
+
expect(order.dry_run).to be true
|
112
|
+
end
|
89
113
|
end
|
@@ -36,9 +36,9 @@ RSpec.describe Lokalise::Client do
|
|
36
36
|
specify '#create_payment_card' do
|
37
37
|
card = VCR.use_cassette('new_payment_card') do
|
38
38
|
test_client.create_payment_card number: '4242424242424242',
|
39
|
-
|
40
|
-
|
41
|
-
|
39
|
+
cvc: '123',
|
40
|
+
exp_month: 1,
|
41
|
+
exp_year: 2030
|
42
42
|
end
|
43
43
|
|
44
44
|
expect(card.card_id).to eq(card_id)
|
@@ -35,8 +35,8 @@ RSpec.describe Lokalise::Client do
|
|
35
35
|
expect(task.task_id).to eq(11_925)
|
36
36
|
expect(task.title).to eq('node updated')
|
37
37
|
expect(task.description).to eq('')
|
38
|
-
expect(task.status).to eq('
|
39
|
-
expect(task.progress).to eq(
|
38
|
+
expect(task.status).to eq('completed')
|
39
|
+
expect(task.progress).to eq(0)
|
40
40
|
expect(task.due_date).to eq(nil)
|
41
41
|
expect(task.due_date_timestamp).to eq(nil)
|
42
42
|
expect(task.keys_count).to eq(16)
|
@@ -45,17 +45,18 @@ RSpec.describe Lokalise::Client do
|
|
45
45
|
expect(task.created_at_timestamp).to eq(1_557_764_126)
|
46
46
|
expect(task.created_by).to eq(20_181)
|
47
47
|
expect(task.created_by_email).to eq('bodrovis@protonmail.com')
|
48
|
-
expect(task.can_be_parent).to eq(
|
48
|
+
expect(task.can_be_parent).to eq(false)
|
49
49
|
expect(task.task_type).to eq('review')
|
50
50
|
expect(task.parent_task_id).to eq(nil)
|
51
51
|
expect(task.closing_tags).to eq([])
|
52
52
|
expect(task.languages.first['language_iso']).to eq('sq')
|
53
53
|
expect(task.auto_close_languages).to eq(true)
|
54
54
|
expect(task.auto_close_task).to eq(true)
|
55
|
-
expect(task.
|
56
|
-
expect(task.
|
57
|
-
expect(task.
|
58
|
-
expect(task.
|
55
|
+
expect(task.auto_close_items).to eq(true)
|
56
|
+
expect(task.completed_by).to eq(20_181)
|
57
|
+
expect(task.completed_by_email).to eq('bodrovis@protonmail.com')
|
58
|
+
expect(task.completed_at).to eq('2019-10-01 11:09:12 (Etc/UTC)')
|
59
|
+
expect(task.completed_at_timestamp).to eq(1_569_928_152)
|
59
60
|
expect(task.do_lock_translations).to eq(false)
|
60
61
|
expect(task.custom_translation_status_ids).to eq([])
|
61
62
|
end
|