lokalise-api-next 0.0.2

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.
Files changed (58) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +13 -0
  3. data/README.md +92 -0
  4. data/lib/lokalise_api_next/base_client.rb +32 -0
  5. data/lib/lokalise_api_next/client_vantage.rb +10 -0
  6. data/lib/lokalise_api_next/collections/base.rb +26 -0
  7. data/lib/lokalise_api_next/collections/vantage/content_units.rb +14 -0
  8. data/lib/lokalise_api_next/collections/vantage/exports.rb +14 -0
  9. data/lib/lokalise_api_next/collections/vantage/project_items.rb +14 -0
  10. data/lib/lokalise_api_next/collections/vantage/project_languages.rb +12 -0
  11. data/lib/lokalise_api_next/collections/vantage/projects.rb +14 -0
  12. data/lib/lokalise_api_next/collections/vantage/segments.rb +14 -0
  13. data/lib/lokalise_api_next/collections/vantage/tasks.rb +14 -0
  14. data/lib/lokalise_api_next/collections/vantage/uploads.rb +14 -0
  15. data/lib/lokalise_api_next/concerns/paginated.rb +24 -0
  16. data/lib/lokalise_api_next/connection.rb +59 -0
  17. data/lib/lokalise_api_next/endpoints/base.rb +27 -0
  18. data/lib/lokalise_api_next/endpoints/vantage/content_units.rb +18 -0
  19. data/lib/lokalise_api_next/endpoints/vantage/exports.rb +40 -0
  20. data/lib/lokalise_api_next/endpoints/vantage/imports.rb +18 -0
  21. data/lib/lokalise_api_next/endpoints/vantage/project_items.rb +18 -0
  22. data/lib/lokalise_api_next/endpoints/vantage/project_languages.rb +18 -0
  23. data/lib/lokalise_api_next/endpoints/vantage/projects.rb +23 -0
  24. data/lib/lokalise_api_next/endpoints/vantage/segments.rb +31 -0
  25. data/lib/lokalise_api_next/endpoints/vantage/tasks.rb +22 -0
  26. data/lib/lokalise_api_next/endpoints/vantage/translation_statuses.rb +22 -0
  27. data/lib/lokalise_api_next/endpoints/vantage/uploads.rb +27 -0
  28. data/lib/lokalise_api_next/error.rb +105 -0
  29. data/lib/lokalise_api_next/models/base.rb +34 -0
  30. data/lib/lokalise_api_next/models/vantage/content_unit.rb +19 -0
  31. data/lib/lokalise_api_next/models/vantage/export.rb +19 -0
  32. data/lib/lokalise_api_next/models/vantage/export_download_url.rb +12 -0
  33. data/lib/lokalise_api_next/models/vantage/import.rb +12 -0
  34. data/lib/lokalise_api_next/models/vantage/project.rb +23 -0
  35. data/lib/lokalise_api_next/models/vantage/project_item.rb +18 -0
  36. data/lib/lokalise_api_next/models/vantage/project_language.rb +17 -0
  37. data/lib/lokalise_api_next/models/vantage/segment.rb +24 -0
  38. data/lib/lokalise_api_next/models/vantage/task.rb +23 -0
  39. data/lib/lokalise_api_next/models/vantage/translation_status.rb +17 -0
  40. data/lib/lokalise_api_next/models/vantage/upload.rb +23 -0
  41. data/lib/lokalise_api_next/models/vantage/upload_batch.rb +15 -0
  42. data/lib/lokalise_api_next/request.rb +32 -0
  43. data/lib/lokalise_api_next/response.rb +34 -0
  44. data/lib/lokalise_api_next/rest/vantage/content_units.rb +19 -0
  45. data/lib/lokalise_api_next/rest/vantage/exports.rb +39 -0
  46. data/lib/lokalise_api_next/rest/vantage/imports.rb +19 -0
  47. data/lib/lokalise_api_next/rest/vantage/project_items.rb +19 -0
  48. data/lib/lokalise_api_next/rest/vantage/project_languages.rb +19 -0
  49. data/lib/lokalise_api_next/rest/vantage/projects.rb +26 -0
  50. data/lib/lokalise_api_next/rest/vantage/segments.rb +26 -0
  51. data/lib/lokalise_api_next/rest/vantage/tasks.rb +19 -0
  52. data/lib/lokalise_api_next/rest/vantage/translation_statuses.rb +19 -0
  53. data/lib/lokalise_api_next/rest/vantage/uploads.rb +33 -0
  54. data/lib/lokalise_api_next/rest_vantage.rb +20 -0
  55. data/lib/lokalise_api_next/version.rb +5 -0
  56. data/lib/lokalise_api_next.rb +16 -0
  57. data/lokalise-api-next.gemspec +31 -0
  58. metadata +156 -0
@@ -0,0 +1,105 @@
1
+ # frozen_string_literal: true
2
+
3
+ module LokaliseApiNext
4
+ # Represents an error returned by the Vantage API.
5
+ class Error < StandardError
6
+ attr_reader :code, :details, :status, :validation_errors
7
+
8
+ VALIDATION_ERROR_FIELDS = %w[keyword instancePath schemaPath].freeze
9
+
10
+ def initialize(message, code:, details: nil, status: nil)
11
+ super(message)
12
+
13
+ @code = code
14
+ @details = details
15
+ @status = status
16
+ @validation_errors = extract_validation_errors
17
+ end
18
+
19
+ class << self
20
+ def from_response(body, status:)
21
+ raw_errors = body.is_a?(Hash) ? body['errors'] : nil
22
+
23
+ if raw_errors.is_a?(Array)
24
+ errors = raw_errors.filter_map { |item| parse(item, status: status) }
25
+ return Aggregate.new(errors, status: status) unless errors.empty?
26
+ end
27
+
28
+ parse(body, status: status) || generic_error_for(status)
29
+ end
30
+
31
+ def generic_error_for(status)
32
+ new(
33
+ 'An unknown error occurred',
34
+ code: 'unknown_error',
35
+ status: status,
36
+ details: {
37
+ 'status' => status,
38
+ 'reason' => 'unexpected response format'
39
+ }
40
+ )
41
+ end
42
+
43
+ private
44
+
45
+ def parse(value, status:)
46
+ return unless value.is_a?(Hash)
47
+
48
+ message = value['message']
49
+ code = value['errorCode']
50
+
51
+ return unless message.is_a?(String) && code.is_a?(String)
52
+
53
+ details = value['details']
54
+
55
+ new(
56
+ message,
57
+ code: code,
58
+ details: details.is_a?(Hash) ? details : nil,
59
+ status: status
60
+ )
61
+ end
62
+ end
63
+
64
+ def detailed_message
65
+ result = "#{message} (Code: #{code})"
66
+ result += " | Details: #{Oj.dump(details)}" if details
67
+ result
68
+ end
69
+
70
+ private
71
+
72
+ def extract_validation_errors
73
+ return unless code.casecmp?('VALIDATION_ERROR')
74
+ return unless details.is_a?(Hash)
75
+
76
+ error_details = details['error']
77
+ return unless error_details.is_a?(Array)
78
+
79
+ error_details.select { |issue| validation_fields?(issue) }
80
+ end
81
+
82
+ # :reek:UtilityFunction
83
+ def validation_fields?(issue)
84
+ issue.is_a?(Hash) &&
85
+ VALIDATION_ERROR_FIELDS.all? { |key| issue[key].is_a?(String) } &&
86
+ issue['params'].is_a?(Hash) &&
87
+ (!issue.key?('message') || issue['message'].is_a?(String))
88
+ end
89
+
90
+ # Represents multiple errors returned in a single response.
91
+ class Aggregate < Error
92
+ attr_reader :errors
93
+
94
+ def initialize(errors, status:)
95
+ @errors = errors.freeze
96
+
97
+ super(
98
+ "Vantage API returned #{errors.size} error(s)",
99
+ code: 'multiple_errors',
100
+ status: status
101
+ )
102
+ end
103
+ end
104
+ end
105
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ module LokaliseApiNext
4
+ module Models
5
+ # Base class for mapping API responses to model attributes.
6
+ class Base
7
+ attr_reader :warnings
8
+
9
+ class << self
10
+ def from_response(response)
11
+ new(
12
+ response.fetch('data'),
13
+ warnings: response.fetch('warnings', [])
14
+ )
15
+ end
16
+
17
+ def attributes(fields)
18
+ const_set(:ATTRIBUTES, fields.freeze)
19
+ attr_reader(*fields)
20
+ end
21
+ end
22
+
23
+ def initialize(json, warnings: [])
24
+ @warnings = warnings
25
+
26
+ self.class::ATTRIBUTES.each do |name|
27
+ json_key = name.to_s.gsub(/_([a-z])/) { Regexp.last_match(1).upcase }
28
+
29
+ instance_variable_set(:"@#{name}", json[json_key])
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module LokaliseApiNext
4
+ module Models
5
+ module Vantage
6
+ # Represents a content unit in a Vantage project.
7
+ class ContentUnit < Base
8
+ attributes %i[
9
+ id
10
+ project_id
11
+ type
12
+ key
13
+ position
14
+ source_segments_count
15
+ ]
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module LokaliseApiNext
4
+ module Models
5
+ module Vantage
6
+ # Represents a Vantage export operation and its status.
7
+ class Export < Base
8
+ attributes %i[
9
+ export_id
10
+ status
11
+ created_at
12
+ total_items_count
13
+ processed_items_count
14
+ fail_reason
15
+ ]
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ module LokaliseApiNext
4
+ module Models
5
+ module Vantage
6
+ # Represents a download URL for a completed Vantage export.
7
+ class ExportDownloadUrl < Base
8
+ attributes %i[download_url]
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ module LokaliseApiNext
4
+ module Models
5
+ module Vantage
6
+ # Represents a Vantage project import.
7
+ class Import < Base
8
+ attributes %i[import_id]
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module LokaliseApiNext
4
+ module Models
5
+ module Vantage
6
+ # Represents a Vantage project.
7
+ class Project < Base
8
+ attributes %i[
9
+ project_id
10
+ team_id
11
+ name
12
+ description
13
+ base_language
14
+ target_languages
15
+ translation_settings
16
+ content_source_type
17
+ content_source_name
18
+ project_type
19
+ ]
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module LokaliseApiNext
4
+ module Models
5
+ module Vantage
6
+ # Represents an item belonging to a Vantage project.
7
+ class ProjectItem < Base
8
+ attributes %i[
9
+ id
10
+ project_id
11
+ name
12
+ created_at
13
+ updated_at
14
+ ]
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module LokaliseApiNext
4
+ module Models
5
+ module Vantage
6
+ # Represents a language configured for a Vantage project.
7
+ class ProjectLanguage < Base
8
+ attributes %i[
9
+ language_id
10
+ locale
11
+ language_name
12
+ is_rtl
13
+ ]
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module LokaliseApiNext
4
+ module Models
5
+ module Vantage
6
+ # Represents a segment belonging to a Vantage content unit.
7
+ class Segment < Base
8
+ attributes %i[
9
+ id
10
+ number
11
+ value
12
+ status
13
+ last_change_source
14
+ content_language_id
15
+ content_unit_id
16
+ project_id
17
+ metadata
18
+ created_at
19
+ updated_at
20
+ ]
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module LokaliseApiNext
4
+ module Models
5
+ module Vantage
6
+ # Represents a task in a Vantage project.
7
+ class Task < Base
8
+ attributes %i[
9
+ id
10
+ public_id
11
+ title
12
+ type
13
+ status
14
+ description
15
+ task_assignments
16
+ due_date
17
+ created_at
18
+ requested_by
19
+ ]
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module LokaliseApiNext
4
+ module Models
5
+ module Vantage
6
+ # Represents the translation status of a Vantage import.
7
+ class TranslationStatus < Base
8
+ attributes %i[
9
+ project_id
10
+ import_id
11
+ status
12
+ languages
13
+ ]
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module LokaliseApiNext
4
+ module Models
5
+ module Vantage
6
+ # Represents a file upload in a Vantage project.
7
+ class Upload < Base
8
+ attributes %i[
9
+ upload_id
10
+ batch_id
11
+ file_name
12
+ size
13
+ created_at
14
+ status
15
+ word_count
16
+ locale
17
+ item_id
18
+ error
19
+ ]
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module LokaliseApiNext
4
+ module Models
5
+ module Vantage
6
+ # Represents a batch of staged Vantage uploads.
7
+ class UploadBatch < Base
8
+ attributes %i[
9
+ batch_id
10
+ uploads
11
+ ]
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ module LokaliseApiNext
4
+ # Performs HTTP requests.
5
+ module Request
6
+ private
7
+
8
+ def get(uri, params: {})
9
+ Response.new(connection.get(uri, params: params)).body
10
+ end
11
+
12
+ def post(uri, body:)
13
+ response = connection.post(
14
+ uri,
15
+ body: Oj.dump(body, mode: :strict),
16
+ headers: { 'Content-Type' => 'application/json' }
17
+ )
18
+
19
+ Response.new(response).body
20
+ end
21
+
22
+ def patch(uri, body:)
23
+ response = connection.patch(
24
+ uri,
25
+ body: Oj.dump(body, mode: :strict),
26
+ headers: { 'Content-Type' => 'application/json' }
27
+ )
28
+
29
+ Response.new(response).body
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ module LokaliseApiNext
4
+ # Parses HTTP responses and handles API errors.
5
+ class Response
6
+ def initialize(http_response)
7
+ @http_response = http_response
8
+ end
9
+
10
+ def body
11
+ @http_response.raise_for_status if @http_response.is_a?(HTTPX::ErrorResponse)
12
+
13
+ parsed_body = parse_body
14
+ status = @http_response.status
15
+
16
+ raise Error.from_response(parsed_body, status: status) unless status.between?(200, 299)
17
+
18
+ parsed_body
19
+ end
20
+
21
+ private
22
+
23
+ def parse_body
24
+ raw = @http_response.body.to_s
25
+ return nil if raw.empty?
26
+
27
+ Oj.load(raw, mode: :strict)
28
+ rescue Oj::ParseError
29
+ raise if @http_response.status.between?(200, 299)
30
+
31
+ raw
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module LokaliseApiNext
4
+ module Rest
5
+ module Vantage
6
+ # Provides project API operations.
7
+ module ContentUnits
8
+ ENDPOINT = Endpoints::Vantage::ContentUnits
9
+ COLLECTION = Collections::Vantage::ContentUnits
10
+
11
+ def content_units(project_id, item_id, params = {})
12
+ uri = ENDPOINT.list(project_id: project_id, item_id: item_id)
13
+
14
+ COLLECTION.from_response(get(uri, params: params))
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ module LokaliseApiNext
4
+ module Rest
5
+ module Vantage
6
+ # Provides project export API operations.
7
+ module Exports
8
+ ENDPOINT = Endpoints::Vantage::Exports
9
+ COLLECTION = Collections::Vantage::Exports
10
+ MODEL = COLLECTION::MODEL
11
+ DOWNLOAD_URL_MODEL = Models::Vantage::ExportDownloadUrl
12
+
13
+ def exports(project_id, params = {})
14
+ uri = ENDPOINT.list(project_id: project_id)
15
+
16
+ COLLECTION.from_response(get(uri, params: params))
17
+ end
18
+
19
+ def export(project_id, export_id)
20
+ uri = ENDPOINT.fetch(project_id: project_id, export_id: export_id)
21
+
22
+ MODEL.from_response(get(uri))
23
+ end
24
+
25
+ def create_export(project_id, params = {})
26
+ uri = ENDPOINT.create(project_id: project_id)
27
+
28
+ MODEL.from_response(post(uri, body: params))
29
+ end
30
+
31
+ def export_download_url(project_id, export_id)
32
+ uri = ENDPOINT.download_url(project_id: project_id, export_id: export_id)
33
+
34
+ DOWNLOAD_URL_MODEL.from_response(get(uri))
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module LokaliseApiNext
4
+ module Rest
5
+ module Vantage
6
+ # Provides project import API operations.
7
+ module Imports
8
+ ENDPOINT = Endpoints::Vantage::Imports
9
+ MODEL = Models::Vantage::Import
10
+
11
+ def create_import(project_id, params)
12
+ uri = ENDPOINT.create(project_id: project_id)
13
+
14
+ MODEL.from_response(post(uri, body: params))
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module LokaliseApiNext
4
+ module Rest
5
+ module Vantage
6
+ # Provides project API operations.
7
+ module ProjectItems
8
+ ENDPOINT = Endpoints::Vantage::ProjectItems
9
+ COLLECTION = Collections::Vantage::ProjectItems
10
+
11
+ def project_items(project_id, params = {})
12
+ uri = ENDPOINT.list(project_id: project_id)
13
+
14
+ COLLECTION.from_response(get(uri, params: params))
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module LokaliseApiNext
4
+ module Rest
5
+ module Vantage
6
+ # Provides project languages API operations.
7
+ module ProjectLanguages
8
+ ENDPOINT = Endpoints::Vantage::ProjectLanguages
9
+ COLLECTION = Collections::Vantage::ProjectLanguages
10
+
11
+ def project_languages(project_id)
12
+ uri = ENDPOINT.list(project_id: project_id)
13
+
14
+ COLLECTION.from_response(get(uri))
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module LokaliseApiNext
4
+ module Rest
5
+ module Vantage
6
+ # Provides project API operations.
7
+ module Projects
8
+ ENDPOINT = Endpoints::Vantage::Projects
9
+ COLLECTION = Collections::Vantage::Projects
10
+ MODEL = COLLECTION::MODEL
11
+
12
+ def projects(team_id, params = {})
13
+ uri = ENDPOINT.list(team_id: team_id)
14
+
15
+ COLLECTION.from_response(get(uri, params: params))
16
+ end
17
+
18
+ def project(project_id)
19
+ uri = ENDPOINT.fetch(project_id: project_id)
20
+
21
+ MODEL.from_response(get(uri))
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module LokaliseApiNext
4
+ module Rest
5
+ module Vantage
6
+ # Provides project API operations.
7
+ module Segments
8
+ ENDPOINT = Endpoints::Vantage::Segments
9
+ COLLECTION = Collections::Vantage::Segments
10
+ MODEL = COLLECTION::MODEL
11
+
12
+ def segments(project_id, content_unit_id, params = {})
13
+ uri = ENDPOINT.list(project_id: project_id, content_unit_id: content_unit_id)
14
+
15
+ COLLECTION.from_response(get(uri, params: params))
16
+ end
17
+
18
+ def update_segment(project_id, segment_id, params)
19
+ uri = ENDPOINT.update(project_id: project_id, segment_id: segment_id)
20
+
21
+ MODEL.from_response(patch(uri, body: params))
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module LokaliseApiNext
4
+ module Rest
5
+ module Vantage
6
+ # Provides task API operations.
7
+ module Tasks
8
+ ENDPOINT = Endpoints::Vantage::Tasks
9
+ COLLECTION = Collections::Vantage::Tasks
10
+
11
+ def tasks(team_id, project_id, params = {})
12
+ uri = ENDPOINT.list(team_id: team_id, project_id: project_id)
13
+
14
+ COLLECTION.from_response(get(uri, params: params))
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module LokaliseApiNext
4
+ module Rest
5
+ module Vantage
6
+ # Provides translation status API operations.
7
+ module TranslationStatuses
8
+ ENDPOINT = Endpoints::Vantage::TranslationStatuses
9
+ MODEL = Models::Vantage::TranslationStatus
10
+
11
+ def translation_status(project_id, import_id)
12
+ uri = ENDPOINT.fetch(project_id: project_id, import_id: import_id)
13
+
14
+ MODEL.from_response(get(uri))
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end