better_translate 1.0.0.1 โ 1.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.rubocop.yml +28 -0
- data/.rubocop_todo.yml +291 -0
- data/CHANGELOG.md +88 -0
- data/CLAUDE.md +12 -7
- data/CONTRIBUTING.md +432 -0
- data/README.md +240 -1
- data/Rakefile +14 -1
- data/SECURITY.md +160 -0
- data/Steepfile +0 -1
- data/brakeman.yml +37 -0
- data/codecov.yml +34 -0
- data/lib/better_translate/analyzer/code_scanner.rb +149 -0
- data/lib/better_translate/analyzer/key_scanner.rb +109 -0
- data/lib/better_translate/analyzer/orphan_detector.rb +91 -0
- data/lib/better_translate/analyzer/reporter.rb +155 -0
- data/lib/better_translate/cli.rb +81 -2
- data/lib/better_translate/configuration.rb +76 -3
- data/lib/better_translate/errors.rb +9 -0
- data/lib/better_translate/json_handler.rb +227 -0
- data/lib/better_translate/translator.rb +205 -23
- data/lib/better_translate/version.rb +1 -1
- data/lib/better_translate/yaml_handler.rb +59 -0
- data/lib/better_translate.rb +7 -0
- data/lib/generators/better_translate/install/install_generator.rb +2 -2
- data/lib/generators/better_translate/install/templates/initializer.rb.tt +22 -34
- data/lib/generators/better_translate/translate/translate_generator.rb +65 -46
- data/lib/tasks/better_translate.rake +62 -45
- data/sig/better_translate/analyzer/code_scanner.rbs +59 -0
- data/sig/better_translate/analyzer/key_scanner.rbs +40 -0
- data/sig/better_translate/analyzer/orphan_detector.rbs +43 -0
- data/sig/better_translate/analyzer/reporter.rbs +70 -0
- data/sig/better_translate/cli.rbs +2 -0
- data/sig/better_translate/configuration.rbs +6 -0
- data/sig/better_translate/errors.rbs +4 -0
- data/sig/better_translate/json_handler.rbs +65 -0
- data/sig/better_translate/progress_tracker.rbs +1 -1
- data/sig/better_translate/translator.rbs +12 -1
- data/sig/better_translate/yaml_handler.rbs +6 -0
- data/sig/better_translate.rbs +4 -0
- data/sig/csv.rbs +16 -0
- metadata +32 -3
- data/regenerate_vcr.rb +0 -47
data/CONTRIBUTING.md
ADDED
|
@@ -0,0 +1,432 @@
|
|
|
1
|
+
# Contributing to BetterTranslate
|
|
2
|
+
|
|
3
|
+
First off, thank you for considering contributing to BetterTranslate! ๐
|
|
4
|
+
|
|
5
|
+
It's people like you that make BetterTranslate such a great tool. We welcome contributions from everyone, whether you're fixing a typo or implementing a major feature.
|
|
6
|
+
|
|
7
|
+
## Table of Contents
|
|
8
|
+
|
|
9
|
+
- [Code of Conduct](#code-of-conduct)
|
|
10
|
+
- [Getting Started](#getting-started)
|
|
11
|
+
- [Development Workflow](#development-workflow)
|
|
12
|
+
- [Testing](#testing)
|
|
13
|
+
- [Code Style](#code-style)
|
|
14
|
+
- [Commit Messages](#commit-messages)
|
|
15
|
+
- [Pull Requests](#pull-requests)
|
|
16
|
+
- [Reporting Bugs](#reporting-bugs)
|
|
17
|
+
- [Suggesting Features](#suggesting-features)
|
|
18
|
+
|
|
19
|
+
## Code of Conduct
|
|
20
|
+
|
|
21
|
+
This project and everyone participating in it is governed by our [Code of Conduct](CODE_OF_CONDUCT.md). By participating, you are expected to uphold this code.
|
|
22
|
+
|
|
23
|
+
## Getting Started
|
|
24
|
+
|
|
25
|
+
### Prerequisites
|
|
26
|
+
|
|
27
|
+
- Ruby >= 3.0.0
|
|
28
|
+
- Bundler
|
|
29
|
+
- Git
|
|
30
|
+
|
|
31
|
+
### Fork and Clone
|
|
32
|
+
|
|
33
|
+
1. Fork the repository on GitHub
|
|
34
|
+
2. Clone your fork locally:
|
|
35
|
+
```bash
|
|
36
|
+
git clone https://github.com/YOUR_USERNAME/better_translate.git
|
|
37
|
+
cd better_translate
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
3. Add the upstream repository:
|
|
41
|
+
```bash
|
|
42
|
+
git remote add upstream https://github.com/alessiobussolari/better_translate.git
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### Install Dependencies
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
bundle install
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### Set Up Environment
|
|
52
|
+
|
|
53
|
+
1. Copy the example environment file:
|
|
54
|
+
```bash
|
|
55
|
+
cp .env.example .env
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
2. Add your API keys (optional, only needed for integration tests):
|
|
59
|
+
```env
|
|
60
|
+
OPENAI_API_KEY=sk-...
|
|
61
|
+
GEMINI_API_KEY=...
|
|
62
|
+
ANTHROPIC_API_KEY=sk-ant-...
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## Development Workflow
|
|
66
|
+
|
|
67
|
+
### 1. Create a Branch
|
|
68
|
+
|
|
69
|
+
Always create a new branch for your work:
|
|
70
|
+
|
|
71
|
+
```bash
|
|
72
|
+
git checkout -b feature/your-feature-name
|
|
73
|
+
# or
|
|
74
|
+
git checkout -b fix/your-bug-fix
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### 2. Make Your Changes
|
|
78
|
+
|
|
79
|
+
- Write clean, readable code
|
|
80
|
+
- Follow the existing code style
|
|
81
|
+
- Add tests for new features
|
|
82
|
+
- Update documentation as needed
|
|
83
|
+
|
|
84
|
+
### 3. Run Tests
|
|
85
|
+
|
|
86
|
+
Before committing, make sure all tests pass:
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
# Run all tests
|
|
90
|
+
bundle exec rake
|
|
91
|
+
|
|
92
|
+
# Or run individual checks:
|
|
93
|
+
bundle exec rake spec # Tests
|
|
94
|
+
bundle exec rake rubocop # Linting
|
|
95
|
+
bundle exec rake steep # Type checking
|
|
96
|
+
bundle exec rake brakeman # Security scan
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### 4. Commit Your Changes
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
git add .
|
|
103
|
+
git commit -m "feat: Add awesome feature"
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
See [Commit Messages](#commit-messages) for guidelines.
|
|
107
|
+
|
|
108
|
+
### 5. Push and Create PR
|
|
109
|
+
|
|
110
|
+
```bash
|
|
111
|
+
git push origin feature/your-feature-name
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
Then create a Pull Request on GitHub.
|
|
115
|
+
|
|
116
|
+
## Testing
|
|
117
|
+
|
|
118
|
+
### Test Structure
|
|
119
|
+
|
|
120
|
+
- **Unit Tests**: `spec/better_translate/`
|
|
121
|
+
- Fast, no API calls
|
|
122
|
+
- Use WebMock for HTTP stubs
|
|
123
|
+
|
|
124
|
+
- **Integration Tests**: `spec/integration/`
|
|
125
|
+
- Real API interactions via VCR
|
|
126
|
+
- Require API keys for first run
|
|
127
|
+
- Subsequent runs use recorded cassettes
|
|
128
|
+
|
|
129
|
+
### Running Tests
|
|
130
|
+
|
|
131
|
+
```bash
|
|
132
|
+
# All tests
|
|
133
|
+
bundle exec rspec
|
|
134
|
+
|
|
135
|
+
# Only unit tests (fast)
|
|
136
|
+
bundle exec rspec spec/better_translate/
|
|
137
|
+
|
|
138
|
+
# Only integration tests
|
|
139
|
+
bundle exec rspec spec/integration/ --tag integration
|
|
140
|
+
|
|
141
|
+
# Specific file
|
|
142
|
+
bundle exec rspec spec/better_translate/translator_spec.rb
|
|
143
|
+
|
|
144
|
+
# Specific line
|
|
145
|
+
bundle exec rspec spec/better_translate/translator_spec.rb:42
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
### Writing Tests
|
|
149
|
+
|
|
150
|
+
**We follow Test-Driven Development (TDD)**:
|
|
151
|
+
|
|
152
|
+
1. **RED**: Write a failing test
|
|
153
|
+
2. **GREEN**: Write minimum code to pass
|
|
154
|
+
3. **REFACTOR**: Clean up code
|
|
155
|
+
|
|
156
|
+
Example:
|
|
157
|
+
|
|
158
|
+
```ruby
|
|
159
|
+
RSpec.describe MyNewFeature do
|
|
160
|
+
describe "#awesome_method" do
|
|
161
|
+
it "does something awesome" do
|
|
162
|
+
feature = MyNewFeature.new
|
|
163
|
+
result = feature.awesome_method
|
|
164
|
+
|
|
165
|
+
expect(result).to eq("awesome")
|
|
166
|
+
end
|
|
167
|
+
end
|
|
168
|
+
end
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
### Test Coverage
|
|
172
|
+
|
|
173
|
+
We maintain **93%+ test coverage**. New code should include tests:
|
|
174
|
+
|
|
175
|
+
```bash
|
|
176
|
+
# Check coverage
|
|
177
|
+
bundle exec rspec
|
|
178
|
+
# View coverage report: open coverage/index.html
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
## Code Style
|
|
182
|
+
|
|
183
|
+
### RuboCop
|
|
184
|
+
|
|
185
|
+
We use RuboCop for code style enforcement:
|
|
186
|
+
|
|
187
|
+
```bash
|
|
188
|
+
# Check style
|
|
189
|
+
bundle exec rubocop
|
|
190
|
+
|
|
191
|
+
# Auto-fix issues
|
|
192
|
+
bundle exec rubocop -a
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
### Key Guidelines
|
|
196
|
+
|
|
197
|
+
- Use double quotes for strings
|
|
198
|
+
- 2 spaces for indentation (no tabs)
|
|
199
|
+
- Maximum line length: 120 characters
|
|
200
|
+
- Frozen string literals at top of files: `# frozen_string_literal: true`
|
|
201
|
+
- YARD documentation for public methods
|
|
202
|
+
|
|
203
|
+
### YARD Documentation
|
|
204
|
+
|
|
205
|
+
All public methods must have YARD documentation:
|
|
206
|
+
|
|
207
|
+
```ruby
|
|
208
|
+
# Translates text to target language
|
|
209
|
+
#
|
|
210
|
+
# @param text [String] The text to translate
|
|
211
|
+
# @param lang [String] Target language code (e.g., "it", "fr")
|
|
212
|
+
# @return [String] Translated text
|
|
213
|
+
# @raise [ValidationError] If input is invalid
|
|
214
|
+
#
|
|
215
|
+
# @example
|
|
216
|
+
# translate("Hello", "it") #=> "Ciao"
|
|
217
|
+
#
|
|
218
|
+
def translate(text, lang)
|
|
219
|
+
# ...
|
|
220
|
+
end
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
### Type Checking
|
|
224
|
+
|
|
225
|
+
We use Steep for static type checking:
|
|
226
|
+
|
|
227
|
+
```bash
|
|
228
|
+
# Run type checker
|
|
229
|
+
bundle exec steep check
|
|
230
|
+
|
|
231
|
+
# Check specific file
|
|
232
|
+
bundle exec steep check lib/better_translate/translator.rb
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
Type signatures go in `sig/` directory (RBS format).
|
|
236
|
+
|
|
237
|
+
## Commit Messages
|
|
238
|
+
|
|
239
|
+
We follow the [Conventional Commits](https://www.conventionalcommits.org/) specification:
|
|
240
|
+
|
|
241
|
+
### Format
|
|
242
|
+
|
|
243
|
+
```
|
|
244
|
+
<type>(<scope>): <subject>
|
|
245
|
+
|
|
246
|
+
<body>
|
|
247
|
+
|
|
248
|
+
<footer>
|
|
249
|
+
```
|
|
250
|
+
|
|
251
|
+
### Types
|
|
252
|
+
|
|
253
|
+
- `feat`: New feature
|
|
254
|
+
- `fix`: Bug fix
|
|
255
|
+
- `docs`: Documentation changes
|
|
256
|
+
- `style`: Code style changes (formatting, no logic change)
|
|
257
|
+
- `refactor`: Code refactoring
|
|
258
|
+
- `test`: Adding or updating tests
|
|
259
|
+
- `chore`: Maintenance tasks
|
|
260
|
+
|
|
261
|
+
### Examples
|
|
262
|
+
|
|
263
|
+
```bash
|
|
264
|
+
# Good commits
|
|
265
|
+
git commit -m "feat: Add support for JSON locale files"
|
|
266
|
+
git commit -m "fix: Handle nil values in translations"
|
|
267
|
+
git commit -m "docs: Update README with new examples"
|
|
268
|
+
git commit -m "test: Add coverage for edge cases"
|
|
269
|
+
|
|
270
|
+
# With scope
|
|
271
|
+
git commit -m "feat(cli): Add --dry-run flag"
|
|
272
|
+
git commit -m "fix(cache): Fix TTL expiration bug"
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
### Multi-line Commits
|
|
276
|
+
|
|
277
|
+
For complex changes:
|
|
278
|
+
|
|
279
|
+
```
|
|
280
|
+
feat: Add parallel translation support
|
|
281
|
+
|
|
282
|
+
- Implement thread-based concurrent execution
|
|
283
|
+
- Add max_concurrent_requests configuration
|
|
284
|
+
- Include progress tracking for parallel operations
|
|
285
|
+
|
|
286
|
+
Closes #42
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
## Pull Requests
|
|
290
|
+
|
|
291
|
+
### Before Submitting
|
|
292
|
+
|
|
293
|
+
- [ ] Tests pass: `bundle exec rake`
|
|
294
|
+
- [ ] Code follows style guide
|
|
295
|
+
- [ ] YARD documentation added for public methods
|
|
296
|
+
- [ ] CHANGELOG.md updated (for notable changes)
|
|
297
|
+
- [ ] README.md updated (if needed)
|
|
298
|
+
|
|
299
|
+
### PR Title
|
|
300
|
+
|
|
301
|
+
Use conventional commit format:
|
|
302
|
+
|
|
303
|
+
```
|
|
304
|
+
feat: Add awesome feature
|
|
305
|
+
fix: Resolve critical bug
|
|
306
|
+
docs: Improve installation guide
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
### PR Description Template
|
|
310
|
+
|
|
311
|
+
```markdown
|
|
312
|
+
## Description
|
|
313
|
+
Brief description of changes
|
|
314
|
+
|
|
315
|
+
## Type of Change
|
|
316
|
+
- [ ] Bug fix
|
|
317
|
+
- [ ] New feature
|
|
318
|
+
- [ ] Breaking change
|
|
319
|
+
- [ ] Documentation update
|
|
320
|
+
|
|
321
|
+
## Testing
|
|
322
|
+
How has this been tested?
|
|
323
|
+
|
|
324
|
+
## Checklist
|
|
325
|
+
- [ ] Tests pass locally
|
|
326
|
+
- [ ] Tests added for new features
|
|
327
|
+
- [ ] Documentation updated
|
|
328
|
+
- [ ] No RuboCop offenses
|
|
329
|
+
- [ ] No Brakeman warnings
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
### Review Process
|
|
333
|
+
|
|
334
|
+
1. Automated checks run (CI/CD)
|
|
335
|
+
2. Maintainer reviews code
|
|
336
|
+
3. Address feedback if needed
|
|
337
|
+
4. Maintainer merges PR
|
|
338
|
+
|
|
339
|
+
## Reporting Bugs
|
|
340
|
+
|
|
341
|
+
### Before Submitting
|
|
342
|
+
|
|
343
|
+
- Check existing issues
|
|
344
|
+
- Try latest version
|
|
345
|
+
- Gather reproduction steps
|
|
346
|
+
|
|
347
|
+
### Bug Report Template
|
|
348
|
+
|
|
349
|
+
```markdown
|
|
350
|
+
**Describe the bug**
|
|
351
|
+
Clear description of the bug
|
|
352
|
+
|
|
353
|
+
**To Reproduce**
|
|
354
|
+
Steps to reproduce:
|
|
355
|
+
1. ...
|
|
356
|
+
2. ...
|
|
357
|
+
3. ...
|
|
358
|
+
|
|
359
|
+
**Expected behavior**
|
|
360
|
+
What you expected to happen
|
|
361
|
+
|
|
362
|
+
**Actual behavior**
|
|
363
|
+
What actually happened
|
|
364
|
+
|
|
365
|
+
**Environment**
|
|
366
|
+
- Ruby version: [e.g., 3.3.4]
|
|
367
|
+
- BetterTranslate version: [e.g., 1.1.0]
|
|
368
|
+
- OS: [e.g., macOS, Ubuntu]
|
|
369
|
+
|
|
370
|
+
**Additional context**
|
|
371
|
+
Any other relevant information
|
|
372
|
+
```
|
|
373
|
+
|
|
374
|
+
## Suggesting Features
|
|
375
|
+
|
|
376
|
+
We love feature suggestions! Open an issue with:
|
|
377
|
+
|
|
378
|
+
```markdown
|
|
379
|
+
**Feature Description**
|
|
380
|
+
Clear description of the feature
|
|
381
|
+
|
|
382
|
+
**Use Case**
|
|
383
|
+
Why is this feature needed?
|
|
384
|
+
|
|
385
|
+
**Proposed Solution**
|
|
386
|
+
How should it work?
|
|
387
|
+
|
|
388
|
+
**Alternatives Considered**
|
|
389
|
+
Other approaches you've thought about
|
|
390
|
+
|
|
391
|
+
**Additional Context**
|
|
392
|
+
Screenshots, mockups, examples, etc.
|
|
393
|
+
```
|
|
394
|
+
|
|
395
|
+
## Development Commands
|
|
396
|
+
|
|
397
|
+
```bash
|
|
398
|
+
# Run all checks
|
|
399
|
+
bundle exec rake
|
|
400
|
+
|
|
401
|
+
# Individual checks
|
|
402
|
+
bundle exec rake spec # Tests (541 examples)
|
|
403
|
+
bundle exec rake rubocop # Linting
|
|
404
|
+
bundle exec rake steep # Type checking
|
|
405
|
+
bundle exec rake brakeman # Security scan
|
|
406
|
+
|
|
407
|
+
# Code quality
|
|
408
|
+
bundle exec rubocop -a # Auto-fix style issues
|
|
409
|
+
bundle exec yard doc # Generate documentation
|
|
410
|
+
bundle exec bundler-audit # Check dependencies
|
|
411
|
+
|
|
412
|
+
# Interactive console
|
|
413
|
+
bin/console
|
|
414
|
+
|
|
415
|
+
# Demo app
|
|
416
|
+
ruby spec/dummy/demo_translation.rb
|
|
417
|
+
```
|
|
418
|
+
|
|
419
|
+
## Questions?
|
|
420
|
+
|
|
421
|
+
Feel free to:
|
|
422
|
+
- Open an issue
|
|
423
|
+
- Start a discussion
|
|
424
|
+
- Email: alessio.bussolari@pandev.it
|
|
425
|
+
|
|
426
|
+
## License
|
|
427
|
+
|
|
428
|
+
By contributing, you agree that your contributions will be licensed under the MIT License.
|
|
429
|
+
|
|
430
|
+
---
|
|
431
|
+
|
|
432
|
+
Thank you for contributing to BetterTranslate! ๐
|
data/README.md
CHANGED
|
@@ -2,9 +2,15 @@
|
|
|
2
2
|
|
|
3
3
|
> AI-powered YAML locale file translator for Rails and Ruby projects
|
|
4
4
|
|
|
5
|
+
[](https://github.com/alessiobussolari/better_translate/actions/workflows/main.yml)
|
|
6
|
+
[](https://codecov.io/gh/alessiobussolari/better_translate)
|
|
7
|
+
[](https://badge.fury.io/rb/better_translate)
|
|
8
|
+
[](https://rubygems.org/gems/better_translate)
|
|
5
9
|
[](https://www.ruby-lang.org/en/)
|
|
6
10
|
[](LICENSE.txt)
|
|
7
|
-
[](https://brakemanscanner.org/)
|
|
12
|
+
[](https://github.com/soutaro/steep)
|
|
13
|
+
[](https://github.com/alessiobussolari/better_translate/graphs/commit-activity)
|
|
8
14
|
|
|
9
15
|
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
16
|
|
|
@@ -31,6 +37,14 @@ BetterTranslate automatically translates your YAML locale files using cutting-ed
|
|
|
31
37
|
- ๐ซ **Flexible Exclusions**: Global exclusions for all languages + language-specific exclusions for fine-grained control
|
|
32
38
|
- ๐จ **Translation Context**: Provide domain-specific context for medical, legal, financial, or technical terminology
|
|
33
39
|
- ๐ **Similarity Analysis**: Built-in Levenshtein distance analyzer to identify similar translations
|
|
40
|
+
- ๐ **Orphan Key Analyzer**: Find unused translation keys in your codebase with comprehensive reports (text, JSON, CSV)
|
|
41
|
+
|
|
42
|
+
### New in v1.1.0 ๐
|
|
43
|
+
- ๐๏ธ **Provider-Specific Options**: Fine-tune AI behavior with `model`, `temperature`, and `max_tokens`
|
|
44
|
+
- ๐พ **Automatic Backups**: Configurable backup rotation before overwriting files (`.bak`, `.bak.1`, `.bak.2`)
|
|
45
|
+
- ๐ฆ **JSON Support**: Full support for JSON locale files (React, Vue, modern JS frameworks)
|
|
46
|
+
- โก **Parallel Translation**: Translate multiple languages concurrently with thread-based execution
|
|
47
|
+
- ๐ **Multiple Files**: Translate multiple files with arrays or glob patterns (`**/*.en.yml`)
|
|
34
48
|
|
|
35
49
|
### Development & Quality
|
|
36
50
|
- ๐งช **Comprehensive Testing**: Unit tests + integration tests with VCR cassettes (18 cassettes, 260KB)
|
|
@@ -160,6 +174,11 @@ BetterTranslate.configure do |config|
|
|
|
160
174
|
config.request_timeout = 30 # seconds
|
|
161
175
|
config.max_retries = 3
|
|
162
176
|
config.retry_delay = 2.0 # seconds
|
|
177
|
+
|
|
178
|
+
# ๐ v1.1.0: Provider-specific options
|
|
179
|
+
config.model = "gpt-5-nano" # Specify model (optional)
|
|
180
|
+
config.temperature = 0.3 # Creativity (0.0-2.0, default: 0.3)
|
|
181
|
+
config.max_tokens = 2000 # Response length limit
|
|
163
182
|
end
|
|
164
183
|
```
|
|
165
184
|
|
|
@@ -195,6 +214,90 @@ end
|
|
|
195
214
|
|
|
196
215
|
Get your API key from [Anthropic Console](https://console.anthropic.com/).
|
|
197
216
|
|
|
217
|
+
### New Features (v1.1.0)
|
|
218
|
+
|
|
219
|
+
#### Automatic Backups
|
|
220
|
+
|
|
221
|
+
Protect your translation files with automatic backup creation:
|
|
222
|
+
|
|
223
|
+
```ruby
|
|
224
|
+
config.create_backup = true # Enable backups (default: true)
|
|
225
|
+
config.max_backups = 5 # Keep up to 5 backup versions
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
Backup files are created with rotation:
|
|
229
|
+
- First backup: `it.yml.bak`
|
|
230
|
+
- Second backup: `it.yml.bak.1`
|
|
231
|
+
- Third backup: `it.yml.bak.2`
|
|
232
|
+
- Older backups are automatically deleted
|
|
233
|
+
|
|
234
|
+
#### JSON File Support
|
|
235
|
+
|
|
236
|
+
Translate JSON locale files for modern JavaScript frameworks:
|
|
237
|
+
|
|
238
|
+
```ruby
|
|
239
|
+
# Automatically detects JSON format from file extension
|
|
240
|
+
config.input_file = "config/locales/en.json"
|
|
241
|
+
config.output_folder = "config/locales"
|
|
242
|
+
|
|
243
|
+
# All features work with JSON: backups, incremental mode, exclusions, etc.
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
Example JSON file:
|
|
247
|
+
```json
|
|
248
|
+
{
|
|
249
|
+
"en": {
|
|
250
|
+
"common": {
|
|
251
|
+
"greeting": "Hello %{name}"
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
#### Parallel Translation
|
|
258
|
+
|
|
259
|
+
Translate multiple languages concurrently for faster processing:
|
|
260
|
+
|
|
261
|
+
```ruby
|
|
262
|
+
config.target_languages = [
|
|
263
|
+
{ short_name: "it", name: "Italian" },
|
|
264
|
+
{ short_name: "fr", name: "French" },
|
|
265
|
+
{ short_name: "es", name: "Spanish" },
|
|
266
|
+
{ short_name: "de", name: "German" }
|
|
267
|
+
]
|
|
268
|
+
|
|
269
|
+
config.max_concurrent_requests = 4 # Translate 4 languages at once
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
**Performance improvement:** With 4 languages and `max_concurrent_requests = 4`, translation time is reduced by ~75% compared to sequential processing.
|
|
273
|
+
|
|
274
|
+
#### Multiple Files Support
|
|
275
|
+
|
|
276
|
+
Translate multiple files in a single run:
|
|
277
|
+
|
|
278
|
+
```ruby
|
|
279
|
+
# Array of specific files
|
|
280
|
+
config.input_files = [
|
|
281
|
+
"config/locales/common.en.yml",
|
|
282
|
+
"config/locales/errors.en.yml",
|
|
283
|
+
"config/locales/admin.en.yml"
|
|
284
|
+
]
|
|
285
|
+
|
|
286
|
+
# Or use glob patterns (recommended)
|
|
287
|
+
config.input_files = "config/locales/**/*.en.yml"
|
|
288
|
+
|
|
289
|
+
# Or combine both approaches
|
|
290
|
+
config.input_files = [
|
|
291
|
+
"config/locales/**/*.en.yml",
|
|
292
|
+
"app/javascript/translations/*.en.json"
|
|
293
|
+
]
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
Output files preserve the original structure:
|
|
297
|
+
- `common.en.yml` โ `common.it.yml`
|
|
298
|
+
- `errors.en.yml` โ `errors.it.yml`
|
|
299
|
+
- `admin/settings.en.yml` โ `admin/settings.it.yml`
|
|
300
|
+
|
|
198
301
|
### Language Configuration
|
|
199
302
|
|
|
200
303
|
```ruby
|
|
@@ -444,6 +547,142 @@ Enable detailed logging for debugging:
|
|
|
444
547
|
config.verbose = true
|
|
445
548
|
```
|
|
446
549
|
|
|
550
|
+
## ๐ Orphan Key Analyzer
|
|
551
|
+
|
|
552
|
+
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.
|
|
553
|
+
|
|
554
|
+
### CLI Usage
|
|
555
|
+
|
|
556
|
+
Find orphan keys from the command line:
|
|
557
|
+
|
|
558
|
+
```bash
|
|
559
|
+
# Basic text report (default)
|
|
560
|
+
better_translate analyze \
|
|
561
|
+
--source config/locales/en.yml \
|
|
562
|
+
--scan-path app/
|
|
563
|
+
|
|
564
|
+
# JSON format (great for CI/CD)
|
|
565
|
+
better_translate analyze \
|
|
566
|
+
--source config/locales/en.yml \
|
|
567
|
+
--scan-path app/ \
|
|
568
|
+
--format json
|
|
569
|
+
|
|
570
|
+
# CSV format (easy to share with team)
|
|
571
|
+
better_translate analyze \
|
|
572
|
+
--source config/locales/en.yml \
|
|
573
|
+
--scan-path app/ \
|
|
574
|
+
--format csv
|
|
575
|
+
|
|
576
|
+
# Save to file
|
|
577
|
+
better_translate analyze \
|
|
578
|
+
--source config/locales/en.yml \
|
|
579
|
+
--scan-path app/ \
|
|
580
|
+
--output orphan_report.txt
|
|
581
|
+
```
|
|
582
|
+
|
|
583
|
+
### Sample Output
|
|
584
|
+
|
|
585
|
+
**Text format:**
|
|
586
|
+
```
|
|
587
|
+
============================================================
|
|
588
|
+
Orphan Keys Analysis Report
|
|
589
|
+
============================================================
|
|
590
|
+
|
|
591
|
+
Statistics:
|
|
592
|
+
Total keys: 50
|
|
593
|
+
Used keys: 45
|
|
594
|
+
Orphan keys: 5
|
|
595
|
+
Usage: 90.0%
|
|
596
|
+
|
|
597
|
+
Orphan Keys (5):
|
|
598
|
+
------------------------------------------------------------
|
|
599
|
+
|
|
600
|
+
Key: users.old_message
|
|
601
|
+
Value: This feature was removed
|
|
602
|
+
|
|
603
|
+
Key: products.deprecated_label
|
|
604
|
+
Value: Old Label
|
|
605
|
+
...
|
|
606
|
+
============================================================
|
|
607
|
+
```
|
|
608
|
+
|
|
609
|
+
**JSON format:**
|
|
610
|
+
```json
|
|
611
|
+
{
|
|
612
|
+
"orphans": ["users.old_message", "products.deprecated_label"],
|
|
613
|
+
"orphan_details": {
|
|
614
|
+
"users.old_message": "This feature was removed",
|
|
615
|
+
"products.deprecated_label": "Old Label"
|
|
616
|
+
},
|
|
617
|
+
"orphan_count": 5,
|
|
618
|
+
"total_keys": 50,
|
|
619
|
+
"used_keys": 45,
|
|
620
|
+
"usage_percentage": 90.0
|
|
621
|
+
}
|
|
622
|
+
```
|
|
623
|
+
|
|
624
|
+
### Programmatic Usage
|
|
625
|
+
|
|
626
|
+
Use the analyzer in your Ruby code:
|
|
627
|
+
|
|
628
|
+
```ruby
|
|
629
|
+
# Scan YAML file
|
|
630
|
+
key_scanner = BetterTranslate::Analyzer::KeyScanner.new("config/locales/en.yml")
|
|
631
|
+
all_keys = key_scanner.scan # Returns Hash of all keys
|
|
632
|
+
|
|
633
|
+
# Scan code for used keys
|
|
634
|
+
code_scanner = BetterTranslate::Analyzer::CodeScanner.new("app/")
|
|
635
|
+
used_keys = code_scanner.scan # Returns Set of used keys
|
|
636
|
+
|
|
637
|
+
# Detect orphans
|
|
638
|
+
detector = BetterTranslate::Analyzer::OrphanDetector.new(all_keys, used_keys)
|
|
639
|
+
orphans = detector.detect
|
|
640
|
+
|
|
641
|
+
# Get statistics
|
|
642
|
+
puts "Orphan count: #{detector.orphan_count}"
|
|
643
|
+
puts "Usage: #{detector.usage_percentage}%"
|
|
644
|
+
|
|
645
|
+
# Generate report
|
|
646
|
+
reporter = BetterTranslate::Analyzer::Reporter.new(
|
|
647
|
+
orphans: orphans,
|
|
648
|
+
orphan_details: detector.orphan_details,
|
|
649
|
+
total_keys: all_keys.size,
|
|
650
|
+
used_keys: used_keys.size,
|
|
651
|
+
usage_percentage: detector.usage_percentage,
|
|
652
|
+
format: :text
|
|
653
|
+
)
|
|
654
|
+
|
|
655
|
+
puts reporter.generate
|
|
656
|
+
reporter.save_to_file("orphan_report.txt")
|
|
657
|
+
```
|
|
658
|
+
|
|
659
|
+
### Supported Translation Patterns
|
|
660
|
+
|
|
661
|
+
The analyzer recognizes these i18n patterns:
|
|
662
|
+
|
|
663
|
+
- `t('key')` - Rails short form
|
|
664
|
+
- `t("key")` - Rails short form with double quotes
|
|
665
|
+
- `I18n.t(:key)` - Symbol syntax
|
|
666
|
+
- `I18n.t('key')` - String syntax
|
|
667
|
+
- `I18n.translate('key')` - Full method name
|
|
668
|
+
- `<%= t('key') %>` - ERB templates
|
|
669
|
+
- `I18n.t('key', param: value)` - With parameters
|
|
670
|
+
|
|
671
|
+
**Nested keys:**
|
|
672
|
+
```yaml
|
|
673
|
+
en:
|
|
674
|
+
users:
|
|
675
|
+
profile:
|
|
676
|
+
title: "Profile" # Detected as: users.profile.title
|
|
677
|
+
```
|
|
678
|
+
|
|
679
|
+
**Use cases:**
|
|
680
|
+
- Clean up unused translations before deployment
|
|
681
|
+
- Identify dead code after refactoring
|
|
682
|
+
- Reduce locale file size
|
|
683
|
+
- Improve translation maintenance
|
|
684
|
+
- Generate reports for translation teams
|
|
685
|
+
|
|
447
686
|
## ๐งช Development & Testing
|
|
448
687
|
|
|
449
688
|
BetterTranslate includes comprehensive testing infrastructure with **unit tests**, **integration tests**, and a **Rails dummy app** for realistic testing.
|
data/Rakefile
CHANGED
|
@@ -15,4 +15,17 @@ task :steep do
|
|
|
15
15
|
sh "bundle exec steep check"
|
|
16
16
|
end
|
|
17
17
|
|
|
18
|
-
|
|
18
|
+
# Security scanning with Brakeman
|
|
19
|
+
desc "Run security scanning with Brakeman"
|
|
20
|
+
task :brakeman do
|
|
21
|
+
require "brakeman"
|
|
22
|
+
result = Brakeman.run(
|
|
23
|
+
app_path: ".",
|
|
24
|
+
print_report: true,
|
|
25
|
+
pager: false,
|
|
26
|
+
force_scan: true
|
|
27
|
+
)
|
|
28
|
+
exit Brakeman::Warnings_Found_Exit_Code unless result.filtered_warnings.empty?
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
task default: %i[spec rubocop steep brakeman]
|