lokalise_manager 5.1.0 → 5.1.2

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: e651c10cfc08624f8bbfe88970210ed7a9e012e8637cc8cbb61aa4328942016b
4
- data.tar.gz: f0dea631f1afba287ff49ff7336a1d74030347feafbafb848e8e5f445d466df9
3
+ metadata.gz: 109786a5056b1b17efbc2214df611dcbef3b774169f04b71a1d5ee3f531bc514
4
+ data.tar.gz: 250e0e838b6d3166e3e9fa5135e6417af1bf5b853719712ddecbef181015ee48
5
5
  SHA512:
6
- metadata.gz: d4792e56612597b654536c72b0c29550b15c9e3666da1422208d613e546cb2870b9749a7150111e40296bd5e2550ca9eacedc55715b0c28292eb1cff45eddf9c
7
- data.tar.gz: 59cfbc87f48a4293fa064946d638b27510211d05bdd8dd5b9c4c63716455b55cdec851da5b2f35b4a4941d153639874bf87e2e34040cc433fe6a46ce978bc0c8
6
+ metadata.gz: 1206ab988a7545b40838b3e053d2e5af54ef3b2bd8bf63a4d48e8d4544d8b005c4e74f6b4549010f8263b5a1c469abbe9a09b9371a43627c0ecfdfc4b76390e4
7
+ data.tar.gz: 90887ab6f6b8b5d5d05688ca20a8e0e0d6afe195a4b3edee1a6021fc5f481f830fa5be856b60fe95c0ddbe07eb6deaecfb5ff29744187b601cc2b4506dfaa4e8
data/CHANGELOG.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # Changelog
2
2
 
3
+ ## 5.1.2 (01-Nov-2024)
4
+
5
+ * Update dependencies
6
+
7
+ ## 5.1.1 (10-May-2024)
8
+
9
+ * Update documentation, minor code fixes
10
+
3
11
  ## 5.1.0 (09-Feb-2024)
4
12
 
5
13
  * Handle rare case when the server returns HTML instead of JSON which happens when too many requests are sent
data/README.md CHANGED
@@ -6,17 +6,22 @@
6
6
  [![Maintainability](https://api.codeclimate.com/v1/badges/9b682367a274ee3dcdee/maintainability)](https://codeclimate.com/github/bodrovis/lokalise_manager/maintainability)
7
7
  ![Downloads total](https://img.shields.io/gem/dt/lokalise_manager)
8
8
 
9
- This gem provides [Lokalise](http://lokalise.com) integration for Ruby and allows to exchange translation files between your project and TMS easily. It relies on [ruby-lokalise-api](https://lokalise.github.io/ruby-lokalise-api) to send APIv2 requests.
9
+ The LokaliseManager gem provides seamless integration with [Lokalise](http://lokalise.com), enabling easy exchange of translation files between your Ruby project and the Lokalise translation management system (TMS). It leverages the [ruby-lokalise-api](https://lokalise.github.io/ruby-lokalise-api) to send and manage APIv2 requests.
10
10
 
11
- If you are looking for a Rails integration, please check [lokalise_rails](https://github.com/bodrovis/lokalise_rails) which provides a set of Rake tasks for importing/exporting.
11
+ For integration directly with Rails applications, refer to [lokalise_rails](https://github.com/bodrovis/lokalise_rails), which offers a suite of Rake tasks specifically designed for importing and exporting translation files.
12
12
 
13
- ## Getting started
13
+ ## Getting Started
14
14
 
15
15
  ### Requirements
16
16
 
17
- This gem requires Ruby 3.0+. You will also need to [setup a Lokalise account](https://app.lokalise.com/signup) and create a [translation project](https://docs.lokalise.com/en/articles/1400460-projects). Finally, you will need to generate a [read/write API token](https://docs.lokalise.com/en/articles/1929556-api-tokens) at your Lokalise profile.
17
+ - **Ruby version**: Ruby 3.0 or higher is required.
18
+ - **Lokalise account**: You must have an active [Lokalise account](https://app.lokalise.com/signup).
19
+ - **Project setup**: Create a [translation project](https://docs.lokalise.com/en/articles/1400460-projects) within your Lokalise account.
20
+ - **API token**: Obtain a read/write [API token](https://docs.lokalise.com/en/articles/1929556-api-tokens) from your Lokalise profile.
18
21
 
19
- Alternatively, you can utilize a token obtained via OAuth 2 flow. When using such a token, you'll have to set `:use_oauth2_token` option to `true` (see below).
22
+ ### Optional
23
+
24
+ - **OAuth 2 token**: If you prefer using an OAuth 2 token instead of a standard API token, set the `:use_oauth2_token` option to `true` in your configuration settings.
20
25
 
21
26
  ### Installation
22
27
 
@@ -1,11 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module LokaliseManager
4
- # LokaliseManager error class, subclass of StandardError
4
+ # The Error class provides a custom exception type for the LokaliseManager,
5
+ # allowing the library to raise specific errors that can be easily identified
6
+ # and handled separately from other StandardError exceptions in Ruby.
5
7
  class Error < StandardError
6
8
  # Initializes a new Error object
7
9
  def initialize(message = '')
8
- super(message)
10
+ super
9
11
  end
10
12
  end
11
13
  end
@@ -1,7 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module LokaliseManager
4
- # Global configuration options available for LokaliseManager
4
+ # GlobalConfig provides a central place to manage configuration settings for LokaliseManager.
5
+ # It allows setting various operational parameters such as API tokens, paths, and behavior modifiers.
5
6
  class GlobalConfig
6
7
  class << self
7
8
  attr_accessor :api_token, :project_id
@@ -11,58 +12,57 @@ module LokaliseManager
11
12
  :max_retries_export, :max_retries_import, :use_oauth2_token, :silent_mode,
12
13
  :raise_on_export_fail
13
14
 
14
- # Main interface to provide configuration options
15
+ # Yield self to block for configuration
15
16
  def config
16
17
  yield self
17
18
  end
18
19
 
19
- # When enabled, will re-raise any exception that happens during file exporting
20
+ # Return whether to raise on export failure
20
21
  def raise_on_export_fail
21
- @raise_on_export_fail || true
22
+ @raise_on_export_fail.nil? ? true : @raise_on_export_fail
22
23
  end
23
24
 
24
- # When enabled, won't print any debugging info to $stdout
25
+ # Return whether debugging information is suppressed
25
26
  def silent_mode
26
27
  @silent_mode || false
27
28
  end
28
29
 
29
- # When enabled, will use OAuth 2 Lokalise client and will require to provide a token obtained via OAuth 2 flow
30
- # rather than via Lokalise profile
30
+ # Return whether to use OAuth2 tokens instead of regular API tokens
31
31
  def use_oauth2_token
32
32
  @use_oauth2_token || false
33
33
  end
34
34
 
35
- # Full path to directory with translation files
35
+ # Return the path to locales
36
36
  def locales_path
37
37
  @locales_path || "#{Dir.getwd}/locales"
38
38
  end
39
39
 
40
- # Project branch to use
40
+ # Return the project branch
41
41
  def branch
42
42
  @branch || ''
43
43
  end
44
44
 
45
- # Set request timeouts for the Lokalise API client
45
+ # Return API request timeouts
46
46
  def timeouts
47
47
  @timeouts || {}
48
48
  end
49
49
 
50
- # Maximum number of retries for file exporting
50
+ # Return the max retries for export
51
51
  def max_retries_export
52
52
  @max_retries_export || 5
53
53
  end
54
54
 
55
- # Maximum number of retries for file importing
55
+ # Return the max retries for import
56
56
  def max_retries_import
57
57
  @max_retries_import || 5
58
58
  end
59
59
 
60
- # Regular expression used to select translation files with proper extensions
60
+ # Return the regex for file extensions
61
61
  def file_ext_regexp
62
62
  @file_ext_regexp || /\.ya?ml\z/i
63
63
  end
64
64
 
65
- # Options for import rake task
65
+ # Return import options with defaults
66
66
  def import_opts
67
67
  @import_opts || {
68
68
  format: 'ruby_yaml',
@@ -74,33 +74,32 @@ module LokaliseManager
74
74
  }
75
75
  end
76
76
 
77
- # Options for export rake task
77
+ # Return export options
78
78
  def export_opts
79
79
  @export_opts || {}
80
80
  end
81
81
 
82
- # Enables safe mode for import. When enabled, will check whether the target folder is empty or not
82
+ # Return whether import should check if target is empty
83
83
  def import_safe_mode
84
84
  @import_safe_mode.nil? ? false : @import_safe_mode
85
85
  end
86
86
 
87
- # Additional file skip criteria to apply when performing export
87
+ # Return whether to skip file export based on a lambda condition
88
88
  def skip_file_export
89
89
  @skip_file_export || ->(_) { false }
90
90
  end
91
91
 
92
+ # Load translations from raw data
92
93
  def translations_loader
93
- @translations_loader || ->(raw_data) { YAML.safe_load raw_data }
94
+ @translations_loader || ->(raw_data) { YAML.safe_load(raw_data) }
94
95
  end
95
96
 
96
- # Converts translations data to the proper format
97
+ # Convert raw translation data to YAML format
97
98
  def translations_converter
98
99
  @translations_converter || ->(raw_data) { YAML.dump(raw_data).gsub('\\\\n', '\n') }
99
100
  end
100
101
 
101
- # Infers lang ISO for the given translation file
102
- # The lambda expects to accept the raw contents of the translation file
103
- # and the full path to the file (instance of the `Pathname` class)
102
+ # Infer language ISO code from translation file
104
103
  def lang_iso_inferer
105
104
  @lang_iso_inferer || ->(data, _path) { YAML.safe_load(data)&.keys&.first }
106
105
  end
@@ -5,41 +5,27 @@ require 'pathname'
5
5
 
6
6
  module LokaliseManager
7
7
  module TaskDefinitions
8
- # Base class for LokaliseManager task definitions that includes common methods and logic
8
+ # Base class for LokaliseManager task definitions, providing common methods and logic
9
+ # for importer and exporter classes. Handles API client interactions and configuration merging.
9
10
  class Base
10
11
  using LokaliseManager::Utils::HashUtils
11
12
 
12
13
  attr_accessor :config
13
14
 
14
- # Creates a new importer or exporter. It accepts custom config and merges it
15
- # with the global config (custom config take precendence)
15
+ # Initializes a new task object by merging custom and global configurations.
16
16
  #
17
- # @param custom_opts [Hash]
18
- # @param global_config [Object]
17
+ # @param custom_opts [Hash] Custom configurations for specific tasks.
18
+ # @param global_config [Object] Reference to the global configuration.
19
19
  def initialize(custom_opts = {}, global_config = LokaliseManager::GlobalConfig)
20
- primary_opts = global_config
21
- .singleton_methods
22
- .filter { |m| m.to_s.end_with?('=') }
23
- .each_with_object({}) do |method, opts|
24
- reader = method.to_s.delete_suffix('=')
25
- opts[reader.to_sym] = global_config.send(reader)
26
- end
27
-
28
- all_opts = primary_opts.deep_merge(custom_opts)
29
-
30
- config_klass = Struct.new(*all_opts.keys, keyword_init: true)
31
-
32
- @config = config_klass.new all_opts
20
+ merged_opts = merge_configs(global_config, custom_opts)
21
+ @config = build_config_class(merged_opts)
33
22
  end
34
23
 
35
- # Creates a Lokalise API client
24
+ # Retrieves or creates a Lokalise API client based on configuration.
36
25
  #
37
- # @return [RubyLokaliseApi::Client]
26
+ # @return [RubyLokaliseApi::Client] Lokalise API client.
38
27
  def api_client
39
- client_opts = [config.api_token, config.timeouts]
40
- client_method = config.use_oauth2_token ? :oauth2_client : :client
41
-
42
- @api_client = ::RubyLokaliseApi.send(client_method, *client_opts)
28
+ @api_client ||= create_api_client
43
29
  end
44
30
 
45
31
  # Resets API client
@@ -51,41 +37,63 @@ module LokaliseManager
51
37
 
52
38
  private
53
39
 
54
- # Checks task options
55
- #
56
- # @return Array
40
+ # Creates a Lokalise API client based on configuration.
41
+ def create_api_client
42
+ client_opts = [config.api_token, config.timeouts]
43
+ client_method = config.use_oauth2_token ? :oauth2_client : :client
44
+
45
+ ::RubyLokaliseApi.public_send(client_method, *client_opts)
46
+ end
47
+
48
+ # Merges global and custom configurations.
49
+ def merge_configs(global_config, custom_opts)
50
+ primary_opts = global_config
51
+ .singleton_methods
52
+ .select { |m| m.to_s.end_with?('=') }
53
+ .each_with_object({}) do |method, opts|
54
+ reader = method.to_s.delete_suffix('=')
55
+ opts[reader.to_sym] = global_config.public_send(reader)
56
+ end
57
+
58
+ primary_opts.deep_merge(custom_opts)
59
+ end
60
+
61
+ # Builds a config class with the given options.
62
+ def build_config_class(all_opts)
63
+ config_klass = Struct.new(*all_opts.keys, keyword_init: true)
64
+ config_klass.new(all_opts)
65
+ end
66
+
67
+ # Checks and validates task options, raising errors if configurations are missing.
57
68
  def check_options_errors!
58
69
  errors = []
59
70
  errors << 'Project ID is not set!' if config.project_id.nil? || config.project_id.empty?
60
71
  errors << 'Lokalise API token is not set!' if config.api_token.nil? || config.api_token.empty?
61
-
62
- raise(LokaliseManager::Error, errors.join(' ')) if errors.any?
72
+ raise LokaliseManager::Error, errors.join(' ') unless errors.empty?
63
73
  end
64
74
 
65
- # Checks whether the provided file has a proper extension as dictated by the `file_ext_regexp` option
75
+ # Checks if the file has the correct extension based on the configuration.
66
76
  #
67
- # @return Boolean
68
- # @param raw_path [String, Pathname]
77
+ # @param raw_path [String, Pathname] Path to check.
78
+ # @return [Boolean] True if the extension matches, false otherwise.
69
79
  def proper_ext?(raw_path)
70
80
  path = raw_path.is_a?(Pathname) ? raw_path : Pathname.new(raw_path)
71
81
  config.file_ext_regexp.match? path.extname
72
82
  end
73
83
 
74
- # Returns directory and filename for the given entry
84
+ # Extracts the directory and filename from a given path.
75
85
  #
76
- # @return Array
77
- # @param entry [String]
86
+ # @param entry [String] The file path.
87
+ # @return [Array] Contains [Pathname, Pathname] representing the directory and filename.
78
88
  def subdir_and_filename_for(entry)
79
89
  Pathname.new(entry).split
80
90
  end
81
91
 
82
- # Returns Lokalise project ID and branch, semicolumn separated
92
+ # Constructs a project identifier string that may include a branch.
83
93
  #
84
- # @return [String]
94
+ # @return [String] Project identifier potentially including the branch.
85
95
  def project_id_with_branch
86
- return config.project_id.to_s if config.branch.to_s.strip.empty?
87
-
88
- "#{config.project_id}:#{config.branch}"
96
+ config.branch.to_s.strip.empty? ? config.project_id.to_s : "#{config.project_id}:#{config.branch}"
89
97
  end
90
98
 
91
99
  # In rare cases the server might return HTML instead of JSON.
@@ -93,7 +101,7 @@ module LokaliseManager
93
101
  # Until this is fixed, we revert to this quick'n'dirty solution.
94
102
  EXCEPTIONS = [JSON::ParserError, RubyLokaliseApi::Error::TooManyRequests].freeze
95
103
 
96
- # Sends request with exponential backoff mechanism
104
+ # Handles retries with exponential backoff for specific exceptions.
97
105
  def with_exp_backoff(max_retries)
98
106
  return unless block_given?
99
107
 
@@ -4,96 +4,105 @@ require 'base64'
4
4
 
5
5
  module LokaliseManager
6
6
  module TaskDefinitions
7
- # Exporter class is used when you want to upload translation files from your project to Lokalise
7
+ # Class to handle exporting translation files from a local project to Lokalise.
8
8
  class Exporter < Base
9
- # Lokalise allows no more than 6 requests per second
9
+ # Maximum number of concurrent uploads to avoid exceeding Lokalise API rate limits.
10
10
  MAX_THREADS = 6
11
11
 
12
- # Performs translation file export to Lokalise and returns an array of queued processes
12
+ # Exports translation files to Lokalise and handles any necessary concurrency and error checking.
13
13
  #
14
- # @return [Array]
14
+ # @return [Array] An array of process statuses for each file uploaded.
15
15
  def export!
16
16
  check_options_errors!
17
17
 
18
- queued_processes = []
19
-
20
- all_files.each_slice(MAX_THREADS) do |files_group|
21
- parallel_upload(files_group).each do |thr|
22
- raise_on_fail(thr) if config.raise_on_export_fail
23
-
24
- queued_processes.push thr
18
+ queued_processes = all_files.each_slice(MAX_THREADS).flat_map do |files_group|
19
+ parallel_upload(files_group).tap do |threads|
20
+ threads.each { |thr| raise_on_fail(thr) if config.raise_on_export_fail }
25
21
  end
26
22
  end
27
23
 
28
- $stdout.print('Task complete!') unless config.silent_mode
24
+ print_completion_message unless config.silent_mode
29
25
 
30
26
  queued_processes
31
27
  end
32
28
 
33
29
  private
34
30
 
31
+ # Handles parallel uploads of a group of files, utilizing threading.
32
+ #
33
+ # @param files_group [Array] Group of files to be uploaded.
34
+ # @return [Array] Array of threads handling the file uploads.
35
35
  def parallel_upload(files_group)
36
36
  files_group.map do |file_data|
37
- do_upload(*file_data)
37
+ Thread.new { do_upload(*file_data) }
38
38
  end.map(&:value)
39
39
  end
40
40
 
41
+ # Raises an error if a file upload thread failed.
42
+ #
43
+ # @param thread [Struct] The result of the file upload thread.
41
44
  def raise_on_fail(thread)
42
45
  return if thread.success
43
46
 
44
- raise(thread.error.class, "Error while trying to upload #{thread.path}: #{thread.error.message}")
47
+ raise thread.error.class, "Error while trying to upload #{thread.path}: #{thread.error.message}"
45
48
  end
46
49
 
47
- # Performs the actual file uploading to Lokalise. If the API rate limit is exceeed,
48
- # applies exponential backoff
50
+ # Performs the actual upload of a file to Lokalise.
51
+ #
52
+ # @param f_path [Pathname] Full path to the file.
53
+ # @param r_path [Pathname] Relative path of the file within the project.
54
+ # @return [Struct] A struct with the success status, process details, and any error information.
49
55
  def do_upload(f_path, r_path)
50
56
  proc_klass = Struct.new(:success, :process, :path, :error, keyword_init: true)
51
57
 
52
- Thread.new do
53
- process = with_exp_backoff(config.max_retries_export) do
54
- api_client.upload_file project_id_with_branch, opts(f_path, r_path)
55
- end
56
- proc_klass.new success: true, process: process, path: f_path
57
- rescue StandardError => e
58
- proc_klass.new success: false, path: f_path, error: e
58
+ process = with_exp_backoff(config.max_retries_export) do
59
+ api_client.upload_file(project_id_with_branch, opts(f_path, r_path))
59
60
  end
61
+
62
+ proc_klass.new(success: true, process: process, path: f_path)
63
+ rescue StandardError => e
64
+ proc_klass.new(success: false, path: f_path, error: e)
60
65
  end
61
66
 
62
- # Gets translation files from the specified directory
63
- def all_files
64
- loc_path = config.locales_path
65
- Dir["#{loc_path}/**/*"].filter_map do |f|
66
- full_path = Pathname.new f
67
+ # Prints a completion message to standard output.
68
+ def print_completion_message
69
+ $stdout.puts 'Task complete!'
70
+ end
67
71
 
68
- next unless file_matches_criteria? full_path
72
+ # Retrieves all translation files from the specified directory.
73
+ #
74
+ # @return [Array] Array of [Pathname, Pathname] pairs representing full and relative paths.
75
+ def all_files
76
+ loc_path = Pathname.new(config.locales_path)
69
77
 
70
- relative_path = full_path.relative_path_from Pathname.new(loc_path)
78
+ Dir["#{loc_path}/**/*"].filter_map do |file|
79
+ full_path = Pathname.new(file)
80
+ next unless file_matches_criteria?(full_path)
71
81
 
82
+ relative_path = full_path.relative_path_from(loc_path)
72
83
  [full_path, relative_path]
73
84
  end
74
85
  end
75
86
 
76
- # Generates export options
87
+ # Generates options for file upload to Lokalise.
77
88
  #
78
- # @return [Hash]
79
- # @param full_p [Pathname]
80
- # @param relative_p [Pathname]
89
+ # @param full_p [Pathname] Full path to the file.
90
+ # @param relative_p [Pathname] Relative path within the project.
91
+ # @return [Hash] Options for the Lokalise API upload.
81
92
  def opts(full_p, relative_p)
82
- content = File.read full_p
93
+ content = File.read(full_p).strip
83
94
 
84
- initial_opts = {
85
- data: Base64.strict_encode64(content.strip),
86
- filename: relative_p,
95
+ {
96
+ data: Base64.strict_encode64(content),
97
+ filename: relative_p.to_s,
87
98
  lang_iso: config.lang_iso_inferer.call(content, full_p)
88
- }
89
-
90
- initial_opts.merge config.export_opts
99
+ }.merge(config.export_opts)
91
100
  end
92
101
 
93
- # Checks whether the specified file has to be processed or not
102
+ # Checks whether the specified file meets the criteria for upload.
94
103
  #
95
- # @return [Boolean]
96
- # @param full_path [Pathname]
104
+ # @param full_path [Pathname] Full path to the file.
105
+ # @return [Boolean] True if the file matches criteria, false otherwise.
97
106
  def file_matches_criteria?(full_path)
98
107
  full_path.file? && proper_ext?(full_path) &&
99
108
  !config.skip_file_export.call(full_path)
@@ -6,11 +6,13 @@ require 'fileutils'
6
6
 
7
7
  module LokaliseManager
8
8
  module TaskDefinitions
9
- # Importer class is used when you want to download translation files from Lokalise into your project
9
+ # The Importer class handles downloading translation files from Lokalise
10
+ # and importing them into the specified project directory.
10
11
  class Importer < Base
11
- # Performs translation files import from Lokalise
12
+ # Initiates the import process by checking configuration, ensuring safe mode conditions,
13
+ # downloading files, and processing them. Outputs task completion status.
12
14
  #
13
- # @return [Boolean]
15
+ # @return [Boolean] Returns true if the import completes successfully, false if cancelled.
14
16
  def import!
15
17
  check_options_errors!
16
18
 
@@ -27,10 +29,9 @@ module LokaliseManager
27
29
 
28
30
  private
29
31
 
30
- # Downloads files from Lokalise using the specified config.
31
- # Utilizes exponential backoff if "too many requests" error is received
32
+ # Downloads translation files from Lokalise, handling retries and errors using exponential backoff.
32
33
  #
33
- # @return [Hash]
34
+ # @return [Hash] Returns the response from Lokalise API containing download details.
34
35
  def download_files
35
36
  with_exp_backoff(config.max_retries_import) do
36
37
  api_client.download_files project_id_with_branch, config.import_opts
@@ -39,67 +40,56 @@ module LokaliseManager
39
40
  raise e.class, "There was an error when trying to download files: #{e.message}"
40
41
  end
41
42
 
42
- # Opens ZIP archive (local or remote) with translations and processes its entries
43
+ # Opens a ZIP archive from a given path and processes each entry if it matches the required file extension.
43
44
  #
44
- # @param path [String]
45
+ # @param path [String] The URL or local path to the ZIP archive.
45
46
  def open_and_process_zip(path)
46
47
  Zip::File.open_buffer(open_file_or_remote(path)) do |zip|
47
- fetch_zip_entries(zip) { |entry| process!(entry) }
48
+ zip.each { |entry| process_entry(entry) if proper_ext?(entry.name) }
48
49
  end
49
50
  rescue StandardError => e
50
- raise(e.class, "There was an error when trying to process the downloaded files: #{e.message}")
51
+ raise e.class, "Error processing ZIP file: #{e.message}"
51
52
  end
52
53
 
53
- # Iterates over ZIP entries. Each entry may be a file or folder.
54
- def fetch_zip_entries(zip)
55
- return unless block_given?
56
-
57
- zip.each do |entry|
58
- next unless proper_ext? entry.name
59
-
60
- yield entry
61
- end
62
- end
63
-
64
- # Processes ZIP entry by reading its contents and creating the corresponding translation file
65
- def process!(zip_entry)
66
- data = data_from zip_entry
67
- subdir, filename = subdir_and_filename_for zip_entry.name
68
- full_path = "#{config.locales_path}/#{subdir}"
54
+ # Processes a single ZIP entry by extracting data, determining the correct directory structure,
55
+ # and writing the data to the appropriate file.
56
+ #
57
+ # @param zip_entry [Zip::Entry] The ZIP entry to process.
58
+ def process_entry(zip_entry)
59
+ data = data_from(zip_entry)
60
+ subdir, filename = subdir_and_filename_for(zip_entry.name)
61
+ full_path = File.join(config.locales_path, subdir)
69
62
  FileUtils.mkdir_p full_path
70
63
 
71
- File.open(File.join(full_path, filename), 'w+:UTF-8') do |f|
72
- f.write config.translations_converter.call(data)
73
- end
64
+ File.write(File.join(full_path, filename), config.translations_converter.call(data), mode: 'w+:UTF-8')
74
65
  rescue StandardError => e
75
- raise e.class, "Error when trying to process #{zip_entry&.name}: #{e.message}"
66
+ raise e.class, "Error processing entry #{zip_entry.name}: #{e.message}"
76
67
  end
77
68
 
78
- # Checks whether the user wishes to proceed when safe mode is enabled and the target directory is not empty
69
+ # Determines if the import should proceed based on the safe mode setting and the content of the target directory.
70
+ # In safe mode, the directory must be empty, or the user must confirm continuation.
79
71
  #
80
- # @return [Boolean]
72
+ # @return [Boolean] Returns true if the import should proceed, false otherwise.
81
73
  def proceed_when_safe_mode?
82
74
  return true unless config.import_safe_mode && !Dir.empty?(config.locales_path.to_s)
83
75
 
84
76
  $stdout.puts "The target directory #{config.locales_path} is not empty!"
85
77
  $stdout.print 'Enter Y to continue: '
86
- answer = $stdin.gets
87
- answer.to_s.strip == 'Y'
78
+ $stdin.gets.strip.upcase == 'Y'
88
79
  end
89
80
 
90
- # Opens a local file or a remote URL using the provided patf
81
+ # Opens a local file or a remote URL using the provided path, safely handling different path schemes.
91
82
  #
92
- # @return [String]
83
+ # @param path [String] The path to the file, either a local path or a URL.
84
+ # @return [IO] Returns an IO object for the file.
93
85
  def open_file_or_remote(path)
94
- parsed_path = URI.parse(path)
95
-
96
- if parsed_path&.scheme&.include?('http')
97
- parsed_path.open
98
- else
99
- File.open path
100
- end
86
+ uri = URI.parse(path)
87
+ uri.scheme&.start_with?('http') ? uri.open : File.open(path)
101
88
  end
102
89
 
90
+ # Loads translations from the ZIP file.
91
+ #
92
+ # @param zip_entry [Zip::Entry] The ZIP entry to process.
103
93
  def data_from(zip_entry)
104
94
  config.translations_loader.call zip_entry.get_input_stream.read
105
95
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module LokaliseManager
4
- VERSION = '5.1.0'
4
+ VERSION = '5.1.2'
5
5
  end
@@ -6,34 +6,34 @@ require 'yaml'
6
6
  loader = Zeitwerk::Loader.for_gem
7
7
  loader.setup
8
8
 
9
- # LokaliseManager main module that exposes helper methods:
10
- #
11
- # importer = LokaliseManager.importer api_token: '1234abc', project_id: '123.abc'
12
- # exporter = LokaliseManager.exporter api_token: '1234abc', project_id: '123.abc'
13
- #
14
- # Use the instantiated objects to import or export your translation files:
9
+ # The LokaliseManager module provides functionalities to import and export translation
10
+ # files to and from the Lokalise TMS. It simplifies interactions with the Lokalise API
11
+ # by providing a straightforward interface to instantiate importers and exporters.
15
12
  #
13
+ # Example:
14
+ # importer = LokaliseManager.importer(api_token: '1234abc', project_id: '123.abc')
15
+ # exporter = LokaliseManager.exporter(api_token: '1234abc', project_id: '123.abc')
16
16
  # importer.import!
17
17
  # exporter.export!
18
18
  #
19
19
  module LokaliseManager
20
20
  class << self
21
- # Initializes a new importer client which is used to download
22
- # translation files from Lokalise to the current project
21
+ # Creates an importer object for downloading translation files from Lokalise.
22
+ #
23
+ # @param custom_opts [Hash] Custom options for the importer (e.g., API token and project ID).
24
+ # @param global_config [Object] Global configuration settings, defaults to LokaliseManager::GlobalConfig.
25
+ # @return [LokaliseManager::TaskDefinitions::Importer] An instance of the importer.
23
26
  #
24
- # @return [LokaliseManager::TaskDefinitions::Importer]
25
- # @param custom_opts [Hash]
26
- # @param global_config [Object]
27
27
  def importer(custom_opts = {}, global_config = LokaliseManager::GlobalConfig)
28
28
  LokaliseManager::TaskDefinitions::Importer.new custom_opts, global_config
29
29
  end
30
30
 
31
- # Initializes a new exporter client which is used to upload
32
- # translation files from the current project to Lokalise
31
+ # Creates an exporter object for uploading translation files to Lokalise.
32
+ #
33
+ # @param custom_opts [Hash] Custom options for the exporter (e.g., API token and project ID).
34
+ # @param global_config [Object] Global configuration settings, defaults to LokaliseManager::GlobalConfig.
35
+ # @return [LokaliseManager::TaskDefinitions::Exporter] An instance of the exporter.
33
36
  #
34
- # @return [LokaliseManager::TaskDefinitions::Exporter]
35
- # @param custom_opts [Hash]
36
- # @param global_config [Object]
37
37
  def exporter(custom_opts = {}, global_config = LokaliseManager::GlobalConfig)
38
38
  LokaliseManager::TaskDefinitions::Exporter.new custom_opts, global_config
39
39
  end
@@ -27,13 +27,13 @@ Gem::Specification.new do |spec|
27
27
  spec.add_dependency 'rubyzip', '~> 2.3'
28
28
  spec.add_dependency 'zeitwerk', '~> 2.4'
29
29
 
30
- spec.add_development_dependency 'dotenv', '~> 2.5'
30
+ spec.add_development_dependency 'dotenv', '~> 3.0'
31
31
  spec.add_development_dependency 'rake', '~> 13.0'
32
32
  spec.add_development_dependency 'rspec', '~> 3.6'
33
33
  spec.add_development_dependency 'rubocop', '~> 1.0'
34
34
  spec.add_development_dependency 'rubocop-performance', '~> 1.5'
35
35
  spec.add_development_dependency 'rubocop-rake', '~> 0.6'
36
- spec.add_development_dependency 'rubocop-rspec', '~> 2.6'
36
+ spec.add_development_dependency 'rubocop-rspec', '~> 3.0'
37
37
  spec.add_development_dependency 'simplecov', '~> 0.16'
38
38
  spec.add_development_dependency 'simplecov-lcov', '~> 0.8'
39
39
  spec.add_development_dependency 'webmock', '~> 3.18'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lokalise_manager
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.1.0
4
+ version: 5.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ilya Krukowski
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-02-09 00:00:00.000000000 Z
11
+ date: 2024-11-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: ruby-lokalise-api
@@ -58,14 +58,14 @@ dependencies:
58
58
  requirements:
59
59
  - - "~>"
60
60
  - !ruby/object:Gem::Version
61
- version: '2.5'
61
+ version: '3.0'
62
62
  type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
66
  - - "~>"
67
67
  - !ruby/object:Gem::Version
68
- version: '2.5'
68
+ version: '3.0'
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: rake
71
71
  requirement: !ruby/object:Gem::Requirement
@@ -142,14 +142,14 @@ dependencies:
142
142
  requirements:
143
143
  - - "~>"
144
144
  - !ruby/object:Gem::Version
145
- version: '2.6'
145
+ version: '3.0'
146
146
  type: :development
147
147
  prerelease: false
148
148
  version_requirements: !ruby/object:Gem::Requirement
149
149
  requirements:
150
150
  - - "~>"
151
151
  - !ruby/object:Gem::Version
152
- version: '2.6'
152
+ version: '3.0'
153
153
  - !ruby/object:Gem::Dependency
154
154
  name: simplecov
155
155
  requirement: !ruby/object:Gem::Requirement
@@ -238,7 +238,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
238
238
  - !ruby/object:Gem::Version
239
239
  version: '0'
240
240
  requirements: []
241
- rubygems_version: 3.5.6
241
+ rubygems_version: 3.5.22
242
242
  signing_key:
243
243
  specification_version: 4
244
244
  summary: Lokalise integration for Ruby