better_translate 1.0.0.1 → 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: b02561def13795980279169998c3a28170f0c2b1c4c7e4ffc58ae61b20b98ff5
4
- data.tar.gz: d44be305f231f038918bb8dbf722db94328d9d9e71f1bcdd8bbe32aefceeb2f1
3
+ metadata.gz: 80868b0f529d5c8310efabe07a402bd89d015e6bced86a3c0e2689e288d702f6
4
+ data.tar.gz: fdaede4b54e2c956d3f2cc936f221a83703a2001e1d647fec3abe2283d11e157
5
5
  SHA512:
6
- metadata.gz: 98e5a8fb7c3103220b6b2102a2242a8bb4d103a8e3b2df24298e3fa4a3f8e75dae3b48ebbb578a59de84e7c547f3bc12cab71a77c789aa9ab347b7d424aea113
7
- data.tar.gz: 6aeaafff6b3ff756c620e229d93582ab64a48dca322d21b32d5d38a408e5f6d085ef5ba280da141d0c65b02ca54c3b5559bda29e204aff81b0a6562fac0b860f
6
+ metadata.gz: 90a863900c1e132d7be3bf96a80a66cfad9580e38d7c634fd0e8dcea891be5768ff4cd548eadae6a74dde15a18c4f839a047e8e0653e6642272e518e6859ebac
7
+ data.tar.gz: 3ffb3062a2919d7296fe0ad95f28f29d5352ea3c126f12d09c89229378194a6386c4da65a7d419e7868d34d2297353a2561364600b1b5fe09d30ee9a24244408
data/.rubocop.yml CHANGED
@@ -1,8 +1,36 @@
1
+ inherit_from: .rubocop_todo.yml
2
+
3
+ inherit_mode:
4
+ merge:
5
+ - Exclude
6
+
7
+ plugins:
8
+ - rubocop-rake
9
+ - rubocop-rspec
10
+
1
11
  AllCops:
2
12
  TargetRubyVersion: 3.0
13
+ NewCops: enable
3
14
 
4
15
  Style/StringLiterals:
5
16
  EnforcedStyle: double_quotes
6
17
 
7
18
  Style/StringLiteralsInInterpolation:
8
19
  EnforcedStyle: double_quotes
20
+
21
+ Metrics/BlockLength:
22
+ Exclude:
23
+ - 'spec/**/*_spec.rb'
24
+ - 'Rakefile'
25
+ - '*.gemspec'
26
+
27
+ # RSpec-specific configurations
28
+ RSpec/MultipleExpectations:
29
+ Max: 5
30
+
31
+ RSpec/ExampleLength:
32
+ Max: 15
33
+
34
+ RSpec/DescribeClass:
35
+ Exclude:
36
+ - 'spec/integration/**/*'
data/.rubocop_todo.yml ADDED
@@ -0,0 +1,291 @@
1
+ # This configuration was generated by
2
+ # `rubocop --auto-gen-config`
3
+ # on 2025-10-22 20:47:42 UTC using RuboCop version 1.81.6.
4
+ # The point is for the user to remove these configuration records
5
+ # one by one as the offenses are removed from the code base.
6
+ # Note that changes in the inspected code, or installation of new
7
+ # versions of RuboCop, may require this file to be generated again.
8
+
9
+ # Offense count: 1
10
+ # This cop supports safe autocorrection (--autocorrect).
11
+ # Configuration parameters: Severity.
12
+ Gemspec/RequireMFA:
13
+ Exclude:
14
+ - 'better_translate.gemspec'
15
+
16
+ # Offense count: 4
17
+ # This cop supports safe autocorrection (--autocorrect).
18
+ Lint/AmbiguousOperatorPrecedence:
19
+ Exclude:
20
+ - 'lib/better_translate/analyzer/reporter.rb'
21
+
22
+ # Offense count: 1
23
+ Lint/FloatComparison:
24
+ Exclude:
25
+ - 'spec/better_translate/providers/chatgpt_provider_spec.rb'
26
+
27
+ # Offense count: 8
28
+ # This cop supports unsafe autocorrection (--autocorrect-all).
29
+ Lint/NonAtomicFileOperation:
30
+ Exclude:
31
+ - 'lib/better_translate/json_handler.rb'
32
+ - 'lib/better_translate/yaml_handler.rb'
33
+ - 'spec/better_translate/analyzer/key_scanner_spec.rb'
34
+ - 'spec/better_translate/analyzer/reporter_spec.rb'
35
+
36
+ # Offense count: 22
37
+ # Configuration parameters: AllowedMethods, AllowedPatterns, CountRepeatedAttributes.
38
+ Metrics/AbcSize:
39
+ Max: 116
40
+
41
+ # Offense count: 7
42
+ # Configuration parameters: CountComments, CountAsOne, AllowedMethods, AllowedPatterns, inherit_mode.
43
+ # AllowedMethods: refine
44
+ Metrics/BlockLength:
45
+ Max: 99
46
+
47
+ # Offense count: 3
48
+ # Configuration parameters: CountComments, CountAsOne.
49
+ Metrics/ClassLength:
50
+ Max: 246
51
+
52
+ # Offense count: 12
53
+ # Configuration parameters: AllowedMethods, AllowedPatterns.
54
+ Metrics/CyclomaticComplexity:
55
+ Max: 24
56
+
57
+ # Offense count: 41
58
+ # Configuration parameters: CountComments, CountAsOne, AllowedMethods, AllowedPatterns.
59
+ Metrics/MethodLength:
60
+ Max: 61
61
+
62
+ # Offense count: 1
63
+ # Configuration parameters: CountKeywordArgs, MaxOptionalParameters.
64
+ Metrics/ParameterLists:
65
+ Max: 6
66
+
67
+ # Offense count: 9
68
+ # Configuration parameters: AllowedMethods, AllowedPatterns.
69
+ Metrics/PerceivedComplexity:
70
+ Max: 25
71
+
72
+ # Offense count: 2
73
+ Naming/AccessorMethodName:
74
+ Exclude:
75
+ - 'lib/better_translate/json_handler.rb'
76
+ - 'lib/better_translate/yaml_handler.rb'
77
+
78
+ # Offense count: 6
79
+ # Configuration parameters: Mode, AllowedMethods, AllowedPatterns, AllowBangMethods, WaywardPredicates.
80
+ # AllowedMethods: call
81
+ # WaywardPredicates: nonzero?
82
+ Naming/PredicateMethod:
83
+ Exclude:
84
+ - 'lib/better_translate/configuration.rb'
85
+ - 'lib/better_translate/validator.rb'
86
+ - 'lib/better_translate/variable_extractor.rb'
87
+
88
+ # Offense count: 30
89
+ RSpec/AnyInstance:
90
+ Exclude:
91
+ - 'spec/better_translate/cli_spec.rb'
92
+ - 'spec/better_translate/direct_translator_spec.rb'
93
+ - 'spec/better_translate/multiple_files_spec.rb'
94
+ - 'spec/better_translate/rake_tasks_spec.rb'
95
+ - 'spec/better_translate/translator_spec.rb'
96
+ - 'spec/better_translate_spec.rb'
97
+ - 'spec/generators/translate_generator_spec.rb'
98
+
99
+ # Offense count: 1
100
+ # This cop supports safe autocorrection (--autocorrect).
101
+ # Configuration parameters: EnforcedStyle.
102
+ # SupportedStyles: be, be_nil
103
+ RSpec/BeNil:
104
+ Exclude:
105
+ - 'spec/better_translate_spec.rb'
106
+
107
+ # Offense count: 6
108
+ RSpec/BeforeAfterAll:
109
+ Exclude:
110
+ - '**/spec/spec_helper.rb'
111
+ - '**/spec/rails_helper.rb'
112
+ - '**/spec/support/**/*.rb'
113
+ - 'spec/generators/analyze_generator_spec.rb'
114
+ - 'spec/generators/install_generator_spec.rb'
115
+ - 'spec/generators/translate_generator_spec.rb'
116
+
117
+ # Offense count: 13
118
+ # Configuration parameters: Prefixes, AllowedPatterns.
119
+ # Prefixes: when, with, without
120
+ RSpec/ContextWording:
121
+ Exclude:
122
+ - 'spec/better_translate/analyzer/reporter_spec.rb'
123
+ - 'spec/better_translate/configuration_spec.rb'
124
+ - 'spec/better_translate/strategies/batch_strategy_spec.rb'
125
+ - 'spec/better_translate/strategies/deep_strategy_spec.rb'
126
+ - 'spec/better_translate/strategies/strategy_selector_spec.rb'
127
+
128
+ # Offense count: 2
129
+ # Configuration parameters: IgnoredMetadata.
130
+ RSpec/DescribeClass:
131
+ Exclude:
132
+ - 'spec/integration/**/*'
133
+ - 'spec/better_translate/multiple_files_spec.rb'
134
+ - 'spec/better_translate/rake_tasks_spec.rb'
135
+
136
+ # Offense count: 1
137
+ # This cop supports unsafe autocorrection (--autocorrect-all).
138
+ # Configuration parameters: SkipBlocks, EnforcedStyle, OnlyStaticConstants.
139
+ # SupportedStyles: described_class, explicit
140
+ RSpec/DescribedClass:
141
+ Exclude:
142
+ - 'spec/better_translate/cli_spec.rb'
143
+
144
+ # Offense count: 18
145
+ # Configuration parameters: Max, CountAsOne.
146
+ RSpec/ExampleLength:
147
+ Exclude:
148
+ - 'spec/better_translate/configuration_spec.rb'
149
+ - 'spec/better_translate/direct_translator_spec.rb'
150
+ - 'spec/better_translate/providers/base_http_provider_spec.rb'
151
+ - 'spec/better_translate/strategies/batch_strategy_spec.rb'
152
+ - 'spec/better_translate/strategies/deep_strategy_spec.rb'
153
+ - 'spec/better_translate/translator_spec.rb'
154
+ - 'spec/integration/analyzer_integration_spec.rb'
155
+
156
+ # Offense count: 11
157
+ # This cop supports safe autocorrection (--autocorrect).
158
+ RSpec/LeadingSubject:
159
+ Exclude:
160
+ - 'spec/better_translate/direct_translator_spec.rb'
161
+ - 'spec/better_translate/json_handler_spec.rb'
162
+ - 'spec/better_translate/providers/anthropic_provider_spec.rb'
163
+ - 'spec/better_translate/providers/base_http_provider_spec.rb'
164
+ - 'spec/better_translate/providers/chatgpt_provider_spec.rb'
165
+ - 'spec/better_translate/providers/gemini_provider_spec.rb'
166
+ - 'spec/better_translate/strategies/base_strategy_spec.rb'
167
+ - 'spec/better_translate/yaml_handler_spec.rb'
168
+ - 'spec/integration/anthropic_integration_spec.rb'
169
+ - 'spec/integration/chatgpt_integration_spec.rb'
170
+ - 'spec/integration/gemini_integration_spec.rb'
171
+
172
+ # Offense count: 32
173
+ # Configuration parameters: EnforcedStyle.
174
+ # SupportedStyles: have_received, receive
175
+ RSpec/MessageSpies:
176
+ Exclude:
177
+ - 'spec/better_translate/strategies/batch_strategy_spec.rb'
178
+ - 'spec/better_translate/strategies/deep_strategy_spec.rb'
179
+
180
+ # Offense count: 1
181
+ RSpec/MultipleDescribes:
182
+ Exclude:
183
+ - 'spec/better_translate/errors_spec.rb'
184
+
185
+ # Offense count: 9
186
+ # Configuration parameters: Max.
187
+ RSpec/MultipleExpectations:
188
+ Exclude:
189
+ - 'spec/better_translate/configuration_spec.rb'
190
+ - 'spec/better_translate/providers/anthropic_provider_spec.rb'
191
+ - 'spec/better_translate/providers/chatgpt_provider_spec.rb'
192
+ - 'spec/better_translate/strategies/batch_strategy_spec.rb'
193
+ - 'spec/better_translate/strategies/deep_strategy_spec.rb'
194
+ - 'spec/better_translate_spec.rb'
195
+ - 'spec/integration/analyzer_integration_spec.rb'
196
+
197
+ # Offense count: 22
198
+ # Configuration parameters: AllowSubject.
199
+ RSpec/MultipleMemoizedHelpers:
200
+ Max: 6
201
+
202
+ # Offense count: 16
203
+ # This cop supports unsafe autocorrection (--autocorrect-all).
204
+ RSpec/ReceiveMessages:
205
+ Exclude:
206
+ - 'spec/better_translate/providers/base_http_provider_spec.rb'
207
+
208
+ # Offense count: 2
209
+ RSpec/RepeatedExample:
210
+ Exclude:
211
+ - 'spec/generators/analyze_generator_spec.rb'
212
+
213
+ # Offense count: 4
214
+ # Configuration parameters: CustomTransform, IgnoreMethods, IgnoreMetadata.
215
+ RSpec/SpecFilePathFormat:
216
+ Exclude:
217
+ - '**/spec/routing/**/*'
218
+ - 'spec/better_translate/providers/chatgpt_provider_spec.rb'
219
+ - 'spec/generators/analyze_generator_spec.rb'
220
+ - 'spec/generators/install_generator_spec.rb'
221
+ - 'spec/generators/translate_generator_spec.rb'
222
+
223
+ # Offense count: 17
224
+ RSpec/StubbedMock:
225
+ Exclude:
226
+ - 'spec/better_translate/strategies/batch_strategy_spec.rb'
227
+ - 'spec/better_translate/strategies/deep_strategy_spec.rb'
228
+
229
+ # Offense count: 4
230
+ RSpec/SubjectStub:
231
+ Exclude:
232
+ - 'spec/better_translate/providers/base_http_provider_spec.rb'
233
+
234
+ # Offense count: 33
235
+ # Configuration parameters: IgnoreNameless, IgnoreSymbolicNames.
236
+ RSpec/VerifiedDoubles:
237
+ Exclude:
238
+ - 'spec/better_translate/providers/anthropic_provider_spec.rb'
239
+ - 'spec/better_translate/providers/base_http_provider_spec.rb'
240
+ - 'spec/better_translate/providers/chatgpt_provider_spec.rb'
241
+ - 'spec/better_translate/providers/gemini_provider_spec.rb'
242
+
243
+ # Offense count: 1
244
+ # This cop supports safe autocorrection (--autocorrect).
245
+ # Configuration parameters: EnforcedStyle.
246
+ # SupportedStyles: trailing_conditional, ternary
247
+ Style/EmptyStringInsideInterpolation:
248
+ Exclude:
249
+ - 'lib/generators/better_translate/analyze/analyze_generator.rb'
250
+
251
+ # Offense count: 14
252
+ # This cop supports safe autocorrection (--autocorrect).
253
+ # Configuration parameters: AllowedVars, DefaultToNil.
254
+ Style/FetchEnvVar:
255
+ Exclude:
256
+ - 'lib/better_translate/cli.rb'
257
+ - 'lib/generators/better_translate/translate/translate_generator.rb'
258
+ - 'lib/tasks/better_translate.rake'
259
+ - 'regenerate_vcr.rb'
260
+
261
+ # Offense count: 5
262
+ # This cop supports safe autocorrection (--autocorrect).
263
+ # Configuration parameters: EnforcedStyle, MaxUnannotatedPlaceholdersAllowed, Mode, AllowedMethods, AllowedPatterns.
264
+ # SupportedStyles: annotated, template, unannotated
265
+ Style/FormatStringToken:
266
+ Exclude:
267
+ - 'lib/better_translate/progress_tracker.rb'
268
+
269
+ # Offense count: 2
270
+ # This cop supports unsafe autocorrection (--autocorrect-all).
271
+ Style/HashExcept:
272
+ Exclude:
273
+ - 'lib/better_translate/json_handler.rb'
274
+ - 'lib/better_translate/yaml_handler.rb'
275
+
276
+ # Offense count: 9
277
+ # This cop supports safe autocorrection (--autocorrect).
278
+ Style/IfUnlessModifier:
279
+ Exclude:
280
+ - 'lib/better_translate/configuration.rb'
281
+ - 'lib/better_translate/providers/anthropic_provider.rb'
282
+ - 'lib/better_translate/providers/chatgpt_provider.rb'
283
+ - 'lib/better_translate/providers/gemini_provider.rb'
284
+ - 'lib/better_translate/translator.rb'
285
+
286
+ # Offense count: 4
287
+ # This cop supports safe autocorrection (--autocorrect).
288
+ # Configuration parameters: AllowHeredoc, AllowURI, AllowQualifiedName, URISchemes, IgnoreCopDirectives, AllowedPatterns, SplitStrings.
289
+ # URISchemes: http, https
290
+ Layout/LineLength:
291
+ Max: 181
data/CHANGELOG.md CHANGED
@@ -5,6 +5,94 @@ All notable changes to BetterTranslate will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [1.1.0] - 2025-10-22
9
+
10
+ ### Added
11
+
12
+ #### Enhanced Configuration
13
+ - **Provider-Specific Options**: Fine-tune AI provider behavior
14
+ - `model`: Specify which AI model to use (e.g., "gpt-5-nano", "gemini-2.0-flash-exp")
15
+ - `temperature`: Control creativity/randomness (0.0-2.0, default: 0.3)
16
+ - `max_tokens`: Limit response length (default: 2000)
17
+ - Configurable via CLI, configuration file, or programmatically
18
+
19
+ #### Automatic Backups
20
+ - **Backup System**: Automatic backup creation before overwriting translation files
21
+ - `create_backup`: Enable/disable automatic backups (default: true)
22
+ - `max_backups`: Keep up to N backup files with rotation (default: 3)
23
+ - Backup format: `.bak`, `.bak.1`, `.bak.2`, etc.
24
+ - Automatic cleanup of old backups beyond `max_backups`
25
+ - Works with both YAML and JSON files
26
+
27
+ #### JSON File Support
28
+ - **JSON Handler**: Complete support for JSON translation files
29
+ - Read and write JSON locale files
30
+ - Automatic format detection based on file extension (.json vs .yml)
31
+ - Same feature set as YAML (incremental mode, backups, exclusions)
32
+ - Pretty-printed output with proper indentation
33
+ - Compatible with modern JavaScript frameworks (React, Vue, etc.)
34
+
35
+ #### Parallel Translation
36
+ - **Concurrent Processing**: Translate multiple languages simultaneously
37
+ - `max_concurrent_requests`: Control concurrency level (default: 3)
38
+ - Thread-based parallel execution for improved performance
39
+ - Automatic fallback to sequential processing when `max_concurrent_requests = 1`
40
+ - Thread-safe error handling
41
+ - Significant time savings for projects with many target languages
42
+
43
+ #### Multiple Files Support
44
+ - **Batch Translation**: Translate multiple files in a single run
45
+ - `input_files`: Accept array of file paths or glob patterns
46
+ - Glob pattern support: `config/locales/**/*.en.yml`
47
+ - Preserves directory structure in output
48
+ - Smart filename handling: `common.en.yml` → `common.it.yml`
49
+ - Works with both YAML and JSON files
50
+ - Backward compatible with single `input_file` attribute
51
+
52
+ ### Examples
53
+
54
+ #### Provider-Specific Options
55
+ ```ruby
56
+ config.model = "gpt-5-nano" # Use specific model
57
+ config.temperature = 0.7 # More creative translations
58
+ config.max_tokens = 1500 # Limit response length
59
+ ```
60
+
61
+ #### Automatic Backups
62
+ ```ruby
63
+ config.create_backup = true # Enable backups (default)
64
+ config.max_backups = 5 # Keep up to 5 backup versions
65
+ ```
66
+
67
+ #### JSON Support
68
+ ```ruby
69
+ config.input_file = "config/locales/en.json"
70
+ config.output_folder = "config/locales"
71
+ # Automatically detects JSON format and uses JsonHandler
72
+ ```
73
+
74
+ #### Parallel Translation
75
+ ```ruby
76
+ config.target_languages = [
77
+ { short_name: "it", name: "Italian" },
78
+ { short_name: "fr", name: "French" },
79
+ { short_name: "es", name: "Spanish" }
80
+ ]
81
+ config.max_concurrent_requests = 3 # Translate 3 languages at once
82
+ ```
83
+
84
+ #### Multiple Files
85
+ ```ruby
86
+ # Array of specific files
87
+ config.input_files = [
88
+ "config/locales/common.en.yml",
89
+ "config/locales/errors.en.yml"
90
+ ]
91
+
92
+ # Or use glob patterns
93
+ config.input_files = "config/locales/**/*.en.yml"
94
+ ```
95
+
8
96
  ## [1.0.0] - 2025-10-22
9
97
 
10
98
  ### Complete Rewrite 🎉
data/README.md CHANGED
@@ -4,7 +4,7 @@
4
4
 
5
5
  [![Ruby Version](https://img.shields.io/badge/ruby-%3E%3D%203.0.0-ruby.svg)](https://www.ruby-lang.org/en/)
6
6
  [![License](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE.txt)
7
- [![Gem Version](https://img.shields.io/badge/version-1.0.0-green.svg)](https://rubygems.org/gems/better_translate)
7
+ [![Gem Version](https://img.shields.io/badge/version-1.1.0-green.svg)](https://rubygems.org/gems/better_translate)
8
8
 
9
9
  BetterTranslate automatically translates your YAML locale files using cutting-edge AI providers (ChatGPT, Google Gemini, and Anthropic Claude). It's designed for Rails applications but works with any Ruby project that uses YAML-based internationalization.
10
10
 
@@ -31,6 +31,14 @@ BetterTranslate automatically translates your YAML locale files using cutting-ed
31
31
  - 🚫 **Flexible Exclusions**: Global exclusions for all languages + language-specific exclusions for fine-grained control
32
32
  - 🎨 **Translation Context**: Provide domain-specific context for medical, legal, financial, or technical terminology
33
33
  - 📊 **Similarity Analysis**: Built-in Levenshtein distance analyzer to identify similar translations
34
+ - 🔍 **Orphan Key Analyzer**: Find unused translation keys in your codebase with comprehensive reports (text, JSON, CSV)
35
+
36
+ ### New in v1.1.0 🎉
37
+ - 🎛️ **Provider-Specific Options**: Fine-tune AI behavior with `model`, `temperature`, and `max_tokens`
38
+ - 💾 **Automatic Backups**: Configurable backup rotation before overwriting files (`.bak`, `.bak.1`, `.bak.2`)
39
+ - 📦 **JSON Support**: Full support for JSON locale files (React, Vue, modern JS frameworks)
40
+ - ⚡ **Parallel Translation**: Translate multiple languages concurrently with thread-based execution
41
+ - 📁 **Multiple Files**: Translate multiple files with arrays or glob patterns (`**/*.en.yml`)
34
42
 
35
43
  ### Development & Quality
36
44
  - 🧪 **Comprehensive Testing**: Unit tests + integration tests with VCR cassettes (18 cassettes, 260KB)
@@ -160,6 +168,11 @@ BetterTranslate.configure do |config|
160
168
  config.request_timeout = 30 # seconds
161
169
  config.max_retries = 3
162
170
  config.retry_delay = 2.0 # seconds
171
+
172
+ # 🆕 v1.1.0: Provider-specific options
173
+ config.model = "gpt-5-nano" # Specify model (optional)
174
+ config.temperature = 0.3 # Creativity (0.0-2.0, default: 0.3)
175
+ config.max_tokens = 2000 # Response length limit
163
176
  end
164
177
  ```
165
178
 
@@ -195,6 +208,90 @@ end
195
208
 
196
209
  Get your API key from [Anthropic Console](https://console.anthropic.com/).
197
210
 
211
+ ### New Features (v1.1.0)
212
+
213
+ #### Automatic Backups
214
+
215
+ Protect your translation files with automatic backup creation:
216
+
217
+ ```ruby
218
+ config.create_backup = true # Enable backups (default: true)
219
+ config.max_backups = 5 # Keep up to 5 backup versions
220
+ ```
221
+
222
+ Backup files are created with rotation:
223
+ - First backup: `it.yml.bak`
224
+ - Second backup: `it.yml.bak.1`
225
+ - Third backup: `it.yml.bak.2`
226
+ - Older backups are automatically deleted
227
+
228
+ #### JSON File Support
229
+
230
+ Translate JSON locale files for modern JavaScript frameworks:
231
+
232
+ ```ruby
233
+ # Automatically detects JSON format from file extension
234
+ config.input_file = "config/locales/en.json"
235
+ config.output_folder = "config/locales"
236
+
237
+ # All features work with JSON: backups, incremental mode, exclusions, etc.
238
+ ```
239
+
240
+ Example JSON file:
241
+ ```json
242
+ {
243
+ "en": {
244
+ "common": {
245
+ "greeting": "Hello %{name}"
246
+ }
247
+ }
248
+ }
249
+ ```
250
+
251
+ #### Parallel Translation
252
+
253
+ Translate multiple languages concurrently for faster processing:
254
+
255
+ ```ruby
256
+ config.target_languages = [
257
+ { short_name: "it", name: "Italian" },
258
+ { short_name: "fr", name: "French" },
259
+ { short_name: "es", name: "Spanish" },
260
+ { short_name: "de", name: "German" }
261
+ ]
262
+
263
+ config.max_concurrent_requests = 4 # Translate 4 languages at once
264
+ ```
265
+
266
+ **Performance improvement:** With 4 languages and `max_concurrent_requests = 4`, translation time is reduced by ~75% compared to sequential processing.
267
+
268
+ #### Multiple Files Support
269
+
270
+ Translate multiple files in a single run:
271
+
272
+ ```ruby
273
+ # Array of specific files
274
+ config.input_files = [
275
+ "config/locales/common.en.yml",
276
+ "config/locales/errors.en.yml",
277
+ "config/locales/admin.en.yml"
278
+ ]
279
+
280
+ # Or use glob patterns (recommended)
281
+ config.input_files = "config/locales/**/*.en.yml"
282
+
283
+ # Or combine both approaches
284
+ config.input_files = [
285
+ "config/locales/**/*.en.yml",
286
+ "app/javascript/translations/*.en.json"
287
+ ]
288
+ ```
289
+
290
+ Output files preserve the original structure:
291
+ - `common.en.yml` → `common.it.yml`
292
+ - `errors.en.yml` → `errors.it.yml`
293
+ - `admin/settings.en.yml` → `admin/settings.it.yml`
294
+
198
295
  ### Language Configuration
199
296
 
200
297
  ```ruby
@@ -444,6 +541,142 @@ Enable detailed logging for debugging:
444
541
  config.verbose = true
445
542
  ```
446
543
 
544
+ ## 🔍 Orphan Key Analyzer
545
+
546
+ The Orphan Key Analyzer helps you find unused translation keys in your codebase. It scans your YAML locale files and compares them against your actual code usage, generating comprehensive reports.
547
+
548
+ ### CLI Usage
549
+
550
+ Find orphan keys from the command line:
551
+
552
+ ```bash
553
+ # Basic text report (default)
554
+ better_translate analyze \
555
+ --source config/locales/en.yml \
556
+ --scan-path app/
557
+
558
+ # JSON format (great for CI/CD)
559
+ better_translate analyze \
560
+ --source config/locales/en.yml \
561
+ --scan-path app/ \
562
+ --format json
563
+
564
+ # CSV format (easy to share with team)
565
+ better_translate analyze \
566
+ --source config/locales/en.yml \
567
+ --scan-path app/ \
568
+ --format csv
569
+
570
+ # Save to file
571
+ better_translate analyze \
572
+ --source config/locales/en.yml \
573
+ --scan-path app/ \
574
+ --output orphan_report.txt
575
+ ```
576
+
577
+ ### Sample Output
578
+
579
+ **Text format:**
580
+ ```
581
+ ============================================================
582
+ Orphan Keys Analysis Report
583
+ ============================================================
584
+
585
+ Statistics:
586
+ Total keys: 50
587
+ Used keys: 45
588
+ Orphan keys: 5
589
+ Usage: 90.0%
590
+
591
+ Orphan Keys (5):
592
+ ------------------------------------------------------------
593
+
594
+ Key: users.old_message
595
+ Value: This feature was removed
596
+
597
+ Key: products.deprecated_label
598
+ Value: Old Label
599
+ ...
600
+ ============================================================
601
+ ```
602
+
603
+ **JSON format:**
604
+ ```json
605
+ {
606
+ "orphans": ["users.old_message", "products.deprecated_label"],
607
+ "orphan_details": {
608
+ "users.old_message": "This feature was removed",
609
+ "products.deprecated_label": "Old Label"
610
+ },
611
+ "orphan_count": 5,
612
+ "total_keys": 50,
613
+ "used_keys": 45,
614
+ "usage_percentage": 90.0
615
+ }
616
+ ```
617
+
618
+ ### Programmatic Usage
619
+
620
+ Use the analyzer in your Ruby code:
621
+
622
+ ```ruby
623
+ # Scan YAML file
624
+ key_scanner = BetterTranslate::Analyzer::KeyScanner.new("config/locales/en.yml")
625
+ all_keys = key_scanner.scan # Returns Hash of all keys
626
+
627
+ # Scan code for used keys
628
+ code_scanner = BetterTranslate::Analyzer::CodeScanner.new("app/")
629
+ used_keys = code_scanner.scan # Returns Set of used keys
630
+
631
+ # Detect orphans
632
+ detector = BetterTranslate::Analyzer::OrphanDetector.new(all_keys, used_keys)
633
+ orphans = detector.detect
634
+
635
+ # Get statistics
636
+ puts "Orphan count: #{detector.orphan_count}"
637
+ puts "Usage: #{detector.usage_percentage}%"
638
+
639
+ # Generate report
640
+ reporter = BetterTranslate::Analyzer::Reporter.new(
641
+ orphans: orphans,
642
+ orphan_details: detector.orphan_details,
643
+ total_keys: all_keys.size,
644
+ used_keys: used_keys.size,
645
+ usage_percentage: detector.usage_percentage,
646
+ format: :text
647
+ )
648
+
649
+ puts reporter.generate
650
+ reporter.save_to_file("orphan_report.txt")
651
+ ```
652
+
653
+ ### Supported Translation Patterns
654
+
655
+ The analyzer recognizes these i18n patterns:
656
+
657
+ - `t('key')` - Rails short form
658
+ - `t("key")` - Rails short form with double quotes
659
+ - `I18n.t(:key)` - Symbol syntax
660
+ - `I18n.t('key')` - String syntax
661
+ - `I18n.translate('key')` - Full method name
662
+ - `<%= t('key') %>` - ERB templates
663
+ - `I18n.t('key', param: value)` - With parameters
664
+
665
+ **Nested keys:**
666
+ ```yaml
667
+ en:
668
+ users:
669
+ profile:
670
+ title: "Profile" # Detected as: users.profile.title
671
+ ```
672
+
673
+ **Use cases:**
674
+ - Clean up unused translations before deployment
675
+ - Identify dead code after refactoring
676
+ - Reduce locale file size
677
+ - Improve translation maintenance
678
+ - Generate reports for translation teams
679
+
447
680
  ## 🧪 Development & Testing
448
681
 
449
682
  BetterTranslate includes comprehensive testing infrastructure with **unit tests**, **integration tests**, and a **Rails dummy app** for realistic testing.