remote_translation_loader 1.0.3 → 1.1.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 39a20a05a27f27a7ee285c238b407b1d0053dcaf3e13d00a4c921e55e7046df9
4
- data.tar.gz: d804308dbeebe07dc34f6910cae12d795399912c502d93d2c46f35925dac9162
3
+ metadata.gz: 630b226c234b0e1e9a7924ccb6c9d6aed627d212d8c96f73b5430a0da6e2a33e
4
+ data.tar.gz: ff2437901e7631175cb2acea53876775b29be23d9d09a8be5c8db5a17b227d42
5
5
  SHA512:
6
- metadata.gz: 490ec23b5607c361c6872e1cdd7d1265980744c51714e35d36d461c1946d4715a8c89ba74e375efd78a00c20763d0e573ff07d1b38bd43aa6a76c011ecadceeb
7
- data.tar.gz: 8c2e25fe0bf39717e51e76001c8387a307a8a001cc875afbf3ae9370e2670aabb1e43a1c53703d86fcc8a243e5af032b4f1302f6eeec5907d43e054c11177a62
6
+ metadata.gz: 6319d125210796a2aebb8621d50a25f21ebea905321a02295970d0ef4891cfe822c98cbf17460d0bac3ba98179bf76e8498f2989e39357cc5ab4161c67fba17e
7
+ data.tar.gz: 328d493ea7a39831d05d9cd543d952aeb91bb2d5e731feac10e8390ba8ba01a98f110ab7d7212ebe30e6bb1812822370b71591b825b4ff930cc4b32de29d0ee5
data/README.md CHANGED
@@ -1,15 +1,31 @@
1
- # Remote Translation Loader [![Gem Version](https://badge.fury.io/rb/remote_translation_loader.svg)](https://badge.fury.io/rb/remote_translation_loader)
1
+ # RemoteTranslationLoader
2
2
 
3
- `remote_translation_loader` is a Ruby gem for fetching YAML translation files from remote sources and dynamically loading them into your Ruby on Rails application’s I18n translations. This gem is useful for applications that need to integrate external translations without writing them to local files.
3
+ [![Gem Version](https://badge.fury.io/rb/remote_translation_loader.svg?icon=si%3Arubygems)](https://badge.fury.io/rb/remote_translation_loader)
4
+ [![Downloads](https://img.shields.io/gem/dt/remote_translation_loader.svg)](https://badge.fury.io/rb/remote_translation_loader)
5
+ [![Github forks](https://img.shields.io/github/forks/gklsan/remote_translation_loader.svg)](https://github.com/gklsan/remote_translation_loader/network)
6
+ [![Github stars](https://img.shields.io/github/stars/gklsan/remote_translation_loader.svg)](https://github.com/gklsan/remote_translation_loader/stargazers)
7
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
4
8
 
5
- ## Features
6
9
 
7
- - Fetch translation files from remote URLs
8
- - Merge remote translations with local translations
9
- - Directly load translations into Rails I18n without writing to files
10
- - Handles YAML parsing errors and HTTP request failures
10
+ **RemoteTranslationLoader** is a Ruby gem designed to dynamically fetch and load translation files (YAML format) into your Ruby or Ruby on Rails application. It supports multiple sources such as HTTP URLs, local files, and AWS S3, allowing you to seamlessly integrate external translations.
11
11
 
12
- ## Installation
12
+ ---
13
+
14
+ ## **Features**
15
+
16
+ - Fetch translations from multiple sources:
17
+ - **HTTP URLs**
18
+ - **Local files**
19
+ - **AWS S3 buckets**
20
+ - Supports deep merging of translations with existing `I18n` backend.
21
+ - Namespace support for isolating translations.
22
+ - Dry-run mode to simulate translation loading.
23
+ - Rake tasks for easy integration with Rails applications.
24
+ - CLI tool for manual loading.
25
+
26
+ ---
27
+
28
+ ## **Installation**
13
29
 
14
30
  Add this line to your application's Gemfile:
15
31
 
@@ -17,120 +33,169 @@ Add this line to your application's Gemfile:
17
33
  gem 'remote_translation_loader'
18
34
  ```
19
35
 
20
- Then execute:
36
+ And then execute:
21
37
 
22
38
  ```bash
23
39
  bundle install
24
40
  ```
25
41
 
26
- Or install it yourself as:
42
+ Or install it directly:
27
43
 
28
44
  ```bash
29
45
  gem install remote_translation_loader
30
46
  ```
31
47
 
32
- ## Usage
48
+ ---
33
49
 
34
- ### Basic Setup
50
+ ## **Usage**
35
51
 
36
- 1. **Initialize the Loader**
52
+ ### **Basic Usage**
37
53
 
38
- Create an instance of the `RemoteTranslationLoader::Loader` class with a list of remote YAML URLs:
54
+ #### **1. HTTP Fetching**
55
+ ```ruby
56
+ require 'remote_translation_loader'
39
57
 
40
- ```ruby
41
- loader = RemoteTranslationLoader::Loader.new([
42
- 'https://example.com/translations/en.yml',
43
- 'https://example.com/translations/fr.yml'
44
- ])
45
- ```
58
+ urls = ['https://example.com/en.yml', 'https://example.com/fr.yml']
59
+ loader = RemoteTranslationLoader::Loader.new(urls)
60
+ loader.fetch_and_load
61
+ ```
46
62
 
47
- 2. **Fetch and Load Translations**
63
+ #### **2. Local File Fetching**
64
+ ```ruby
65
+ require 'remote_translation_loader'
48
66
 
49
- Call the `fetch_and_load` method to fetch and load the translations:
67
+ files = ['/path/to/local/en.yml', '/path/to/local/fr.yml']
68
+ loader = RemoteTranslationLoader::Loader.new(files, fetcher: RemoteTranslationLoader::Fetchers::FileFetcher.new)
69
+ loader.fetch_and_load
70
+ ```
50
71
 
51
- ```ruby
52
- loader.fetch_and_load
53
- ```
72
+ #### **3. AWS S3 Fetching**
73
+ ```ruby
74
+ require 'remote_translation_loader'
54
75
 
55
- This will:
56
- - Fetch the YAML files from the specified URLs
57
- - Parse the YAML content
58
- - Merge the remote translations with your existing local translations
59
- - Load the merged translations into Rails I18n
76
+ bucket = 'your-s3-bucket'
77
+ s3_fetcher = RemoteTranslationLoader::Fetchers::S3Fetcher.new(bucket, region: 'us-east-1')
78
+ keys = ['translations/en.yml', 'translations/fr.yml']
60
79
 
61
- ### Example
80
+ loader = RemoteTranslationLoader::Loader.new(keys, fetcher: s3_fetcher)
81
+ loader.fetch_and_load
82
+ ```
62
83
 
84
+ ---
85
+
86
+ ### **Advanced Options**
87
+
88
+ #### **Namespace Support**
89
+ Add a namespace to group translations under a specific key:
63
90
  ```ruby
64
- require 'remote_translation_loader'
91
+ loader.fetch_and_load(namespace: 'remote')
92
+ # Translations will be grouped under the `remote` key, e.g., `remote.en.some_key`
93
+ ```
94
+
95
+ #### **Dry-Run Mode**
96
+ Simulate the loading process without modifying the `I18n` backend:
97
+ ```ruby
98
+ loader.fetch_and_load(dry_run: true)
99
+ # Outputs fetched translations to the console without loading them
100
+ ```
65
101
 
66
- # Initialize the loader with remote YAML URLs
67
- loader = RemoteTranslationLoader::Loader.new([
68
- 'https://example.com/translations/en.yml',
69
- 'https://example.com/translations/fr.yml'
70
- ])
102
+ ---
71
103
 
72
- # Fetch and load translations
73
- loader.fetch_and_load
104
+ ## **CLI Usage**
105
+
106
+ Install the gem globally and use the CLI tool:
74
107
 
75
- # Now you can use the loaded translations in your application
76
- puts I18n.t('greetings.hello') # Output will depend on the remote translation files
108
+ ```bash
109
+ remote_translation_loader https://example.com/en.yml /path/to/local/fr.yml
77
110
  ```
78
111
 
79
- ### Handling Errors
112
+ - The CLI fetches and loads the specified translations.
113
+ - Add the executable to your `$PATH` for easier access.
80
114
 
81
- The gem will raise errors in case of:
82
- - **Invalid YAML Content**: If the remote YAML file is invalid, a `RuntimeError` will be raised with a message indicating a YAML parsing error.
83
- - **HTTP Request Failures**: If fetching the remote YAML file fails, a `RuntimeError` will be raised with a message indicating the failure.
115
+ ---
84
116
 
85
- ### Customizing Error Handling
117
+ ## **Rails Integration**
86
118
 
87
- You can customize the error handling by rescuing from `RuntimeError` or any other specific exceptions as needed:
119
+ ### **1. Rake Task**
120
+ Use the provided Rake task to fetch translations in a Rails application:
88
121
 
122
+ #### Add this to your `Rakefile`:
89
123
  ```ruby
90
- begin
91
- loader.fetch_and_load
92
- rescue RuntimeError => e
93
- puts "An error occurred: #{e.message}"
94
- end
124
+ require 'remote_translation_loader'
125
+ load 'remote_translation_loader/tasks/remote_translation_loader.rake'
95
126
  ```
96
127
 
97
- ## Development
128
+ #### Run the task:
129
+ ```bash
130
+ rake translations:load[https://example.com/en.yml,/path/to/local/fr.yml]
131
+ ```
98
132
 
99
- To contribute to the development of `remote_translation_loader`, follow these steps:
133
+ ### **2. Automatic Loading**
100
134
 
101
- 1. **Clone the Repository**
135
+ Add an initializer to load translations on application startup:
102
136
 
103
- ```bash
104
- git clone https://github.com/gklsan/remote_translation_loader.git
105
- cd remote_translation_loader
106
- ```
137
+ #### `config/initializers/remote_translation_loader.rb`
138
+ ```ruby
139
+ require 'remote_translation_loader'
140
+
141
+ urls = ['https://example.com/en.yml', '/path/to/local/fr.yml']
142
+ loader = RemoteTranslationLoader::Loader.new(urls)
143
+ loader.fetch_and_load(namespace: 'remote')
144
+ ```
145
+
146
+ ---
147
+
148
+ ## **Contributing**
107
149
 
108
- 2. **Install Dependencies**
150
+ We welcome contributions! Follow these steps:
109
151
 
152
+ 1. Fork the repository.
153
+ 2. Create your feature branch:
110
154
  ```bash
111
- bundle install
155
+ git checkout -b feature/my-new-feature
156
+ ```
157
+ 3. Commit your changes:
158
+ ```bash
159
+ git commit -m 'Add some feature'
112
160
  ```
161
+ 4. Push the branch:
162
+ ```bash
163
+ git push origin feature/my-new-feature
164
+ ```
165
+ 5. Create a pull request.
166
+
167
+ ---
113
168
 
114
- 3. **Run Tests**
169
+ ## **Development**
115
170
 
116
- Run the test suite to ensure everything is working correctly:
171
+ To work on the gem locally:
117
172
 
173
+ 1. Clone the repository:
174
+ ```bash
175
+ git clone https://github.com/gklsan/remote_translation_loader.git
176
+ cd remote_translation_loader
177
+ ```
178
+ 2. Install dependencies:
179
+ ```bash
180
+ bundle install
181
+ ```
182
+ 3. Run tests:
118
183
  ```bash
119
- bundle exec rspec
184
+ rspec
120
185
  ```
121
186
 
122
- 4. **Make Your Changes**
187
+ ---
123
188
 
124
- Implement your changes or features and ensure they are covered by tests.
189
+ ## **License**
125
190
 
126
- 5. **Submit a Pull Request**
191
+ This gem is released under the MIT License. See the [LICENSE](LICENSE) file for details.
127
192
 
128
- Push your changes to your forked repository and submit a pull request with a clear description of the changes.
193
+ ---
129
194
 
130
- ## License
195
+ ## **Acknowledgments**
131
196
 
132
- `remote_translation_loader` is licensed under the MIT License. See the [LICENSE](LICENSE) file for more details.
197
+ A big thanks to the open-source community for the inspiration and support. Special mention to contributors who helped shape this gem!
133
198
 
134
- ## Contact
199
+ ---
135
200
 
136
- For questions or support, please open an issue on [GitHub](https://github.com/gklsan/remote_translation_loader/issues).
201
+ For questions, bug reports, or feature requests, feel free to [open an issue](https://github.com/gklsan/remote_translation_loader/issues). 🚀
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RemoteTranslationLoader
4
+ module Fetchers
5
+ class BaseFetcher
6
+ def fetch(_source)
7
+ raise NotImplementedError, "Subclasses must implement the `fetch` method"
8
+ end
9
+
10
+ def parse(content)
11
+ YAML.safe_load(content)
12
+ rescue Psych::SyntaxError => e
13
+ raise "Failed to parse content: #{e.message}"
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'http'
4
+
5
+ module RemoteTranslationLoader
6
+ module Fetchers
7
+ class HttpFetcher < BaseFetcher
8
+ def fetch(url)
9
+ response = HTTP.get(url)
10
+ raise "Failed to fetch data from #{url}" unless response.status.success?
11
+
12
+ parse(response.body.to_s)
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RemoteTranslationLoader
4
+ module Fetchers
5
+ class FileFetcher < BaseFetcher
6
+ def fetch(path)
7
+ raise "File not found: #{path}" unless File.exist?(path)
8
+
9
+ parse(File.read(path))
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'aws-sdk-s3'
4
+
5
+ module RemoteTranslationLoader
6
+ module Fetchers
7
+ class S3Fetcher < BaseFetcher
8
+ def initialize(s3_client = Aws::S3::Client.new)
9
+ @s3_client = s3_client
10
+ end
11
+
12
+ def fetch(bucket, key)
13
+ response = @s3_client.get_object(bucket: bucket, key: key)
14
+ parse(response.body.read)
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,47 @@
1
+ require 'i18n'
2
+
3
+ module RemoteTranslationLoader
4
+ class Loader
5
+ def initialize(urls, fetcher: Fetchers::HttpFetcher.new)
6
+ @urls = urls
7
+ @fetcher = fetcher
8
+ end
9
+
10
+ def fetch_and_load(dry_run: false, namespace: nil)
11
+ @urls.each do |url|
12
+ content = @fetcher.fetch(url)
13
+ validate_translations!(content)
14
+
15
+ if dry_run
16
+ puts "Simulating loading for #{url}: #{content.inspect}"
17
+ else
18
+ merge_into_i18n(content, namespace: namespace)
19
+ end
20
+ end
21
+ end
22
+
23
+ private
24
+
25
+ def validate_translations!(translations)
26
+ raise "Invalid translations format!" unless translations.is_a?(Hash)
27
+ end
28
+
29
+ def merge_into_i18n(content, namespace: nil)
30
+ content.each do |locale, translations|
31
+ next unless translations.is_a?(Hash)
32
+
33
+ translations = { namespace => translations } if namespace
34
+ existing = I18n.backend.send(:translations)[locale.to_sym] || {}
35
+ merged = deep_merge(existing, translations)
36
+ I18n.backend.store_translations(locale.to_sym, merged)
37
+ end
38
+ puts "Translations loaded successfully!"
39
+ end
40
+
41
+ def deep_merge(existing, incoming)
42
+ existing.merge(incoming) do |_, old_val, new_val|
43
+ old_val.is_a?(Hash) && new_val.is_a?(Hash) ? deep_merge(old_val, new_val) : new_val
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,11 @@
1
+ namespace :translations do
2
+ desc "Fetch and load remote translations"
3
+ task :load, [:urls] => :environment do |_task, args|
4
+ urls = args[:urls].to_s.split(',')
5
+ raise "No URLs provided" if urls.empty?
6
+
7
+ loader = RemoteTranslationLoader::Loader.new(urls)
8
+ loader.fetch_and_load
9
+ puts "Translations loaded successfully!"
10
+ end
11
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module RemoteTranslationLoader
4
- VERSION = "1.0.3"
4
+ VERSION = "1.1.0"
5
5
  end
@@ -1,54 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative "remote_translation_loader/version"
4
-
5
- require 'http'
6
- require 'yaml'
7
- require 'i18n'
4
+ require_relative "remote_translation_loader/loader"
5
+ require_relative "remote_translation_loader/fetchers/base_fetcher"
6
+ require_relative "remote_translation_loader/fetchers/http_fetcher"
7
+ require_relative "remote_translation_loader/fetchers/file_fetcher"
8
+ require_relative "remote_translation_loader/fetchers/s3_fetcher"
8
9
 
9
10
  module RemoteTranslationLoader
10
- class Loader
11
- def initialize(urls)
12
- @urls = urls
13
- end
14
-
15
- def fetch_and_load
16
- @urls.each do |url|
17
- yml_content = fetch_yaml(url)
18
- merge_into_i18n(yml_content)
19
- end
20
- end
21
-
22
- private
23
-
24
- def fetch_yaml(url)
25
- response = HTTP.get(url)
26
- raise "Failed to fetch YAML from #{url}" unless response.status.success?
27
-
28
- begin
29
- YAML.safe_load(response.body.to_s)
30
- rescue Psych::SyntaxError => e
31
- raise "Failed to parse YAML from #{url}: #{e.message}"
32
- end
33
- end
34
-
35
- def merge_into_i18n(yml_content)
36
- yml_content.each do |locale, remote_translations|
37
- if remote_translations.is_a?(Hash)
38
- existing_translations = I18n.backend.send(:translations)[locale.to_sym] || {}
39
- merged_translations = deep_merge(existing_translations, remote_translations)
40
-
41
- I18n.backend.store_translations(locale.to_sym, merged_translations)
42
- else
43
- raise "Invalid data format for locale #{locale}"
44
- end
45
- end
46
- end
47
-
48
- def deep_merge(existing, incoming)
49
- existing.merge(incoming) do |key, oldval, newval|
50
- oldval.is_a?(Hash) && newval.is_a?(Hash) ? deep_merge(oldval, newval) : newval
51
- end
52
- end
53
- end
54
11
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: remote_translation_loader
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.3
4
+ version: 1.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Gokul (gklsan)
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-09-08 00:00:00.000000000 Z
11
+ date: 2025-03-31 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: http
@@ -81,6 +81,12 @@ files:
81
81
  - README.md
82
82
  - Rakefile
83
83
  - lib/remote_translation_loader.rb
84
+ - lib/remote_translation_loader/fetchers/base_fetcher.rb
85
+ - lib/remote_translation_loader/fetchers/file_fetcher.rb
86
+ - lib/remote_translation_loader/fetchers/http_fetcher.rb
87
+ - lib/remote_translation_loader/fetchers/s3_fetcher.rb
88
+ - lib/remote_translation_loader/loader.rb
89
+ - lib/remote_translation_loader/tasks/remote_translation_loader.rake
84
90
  - lib/remote_translation_loader/version.rb
85
91
  - sig/remote_translation_loader.rbs
86
92
  homepage: https://github.com/gklsan/remote_translation_loader
@@ -105,7 +111,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
105
111
  - !ruby/object:Gem::Version
106
112
  version: '0'
107
113
  requirements: []
108
- rubygems_version: 3.5.17
114
+ rubygems_version: 3.5.3
109
115
  signing_key:
110
116
  specification_version: 4
111
117
  summary: Fetches and loads remote YAML translation files into Rails I18n