rori18n-rails 1.0.0 → 1.2.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 +4 -4
- data/README.md +360 -0
- data/lib/rori18n/version.rb +1 -1
- data/rori18n-rails.gemspec +5 -3
- metadata +8 -4
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: adf721134937acd15e542d0763193c55f2a978d456b9bb61d7cfb16af37c761c
|
|
4
|
+
data.tar.gz: '08c22af47a7123428b315f4ce00a23c7d2c56d226c2c33f6b98cd8961e3d27ae'
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 34c82ebfdfa96a300067ce7115fabe9055bcee1e11eaa97265c51655669edc74ea71dbbf99460689aa4f4df742f7b181a6ddb695e2be4684328b9bdb83d2e62b
|
|
7
|
+
data.tar.gz: 01d10bc140dc2654452d597f6b7ea4bb8d5ee23bdb99ff1f6e5358610df3d2a3634fd222f6b3f91eac41e31b8375dbc8ed7b06f440a3b8753a14617a701eb107
|
data/README.md
ADDED
|
@@ -0,0 +1,360 @@
|
|
|
1
|
+
# rori18n-rails
|
|
2
|
+
|
|
3
|
+
Rails i18n toolchain. Extracts hardcoded strings, injects `t()` calls,
|
|
4
|
+
translates via Google Cloud, deduplicates, and renames keys — all from one CLI.
|
|
5
|
+
|
|
6
|
+
A drop-in replacement for `i18n-tasks` write commands with capabilities it
|
|
7
|
+
lacks.
|
|
8
|
+
|
|
9
|
+
```sh
|
|
10
|
+
bin/rori18n generate --fix --root .
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## What it does that i18n-tasks can't
|
|
16
|
+
|
|
17
|
+
| Capability | Command |
|
|
18
|
+
| -------------------------------------------- | ----------------- |
|
|
19
|
+
| Find every hardcoded string in ERB/Ruby | `report` |
|
|
20
|
+
| Replace hardcoded strings with `t()` calls | `generate --fix` |
|
|
21
|
+
| Merge sentence fragments into a single `t()` | `merge-fragments` |
|
|
22
|
+
| Translate missing keys via Google Cloud | `translate` |
|
|
23
|
+
| Rename a key across YAML and all callers | `refactor-key` |
|
|
24
|
+
| Deduplicate identical strings to `shared.*` | `consolidate` |
|
|
25
|
+
|
|
26
|
+
Also covers everything i18n-tasks does: lint, audit, prune.
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
|
|
30
|
+
## Install
|
|
31
|
+
|
|
32
|
+
```ruby
|
|
33
|
+
# Gemfile
|
|
34
|
+
gem "rori18n-rails", group: :development
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
```sh
|
|
38
|
+
bundle install
|
|
39
|
+
bundle exec rails g rori18n:install # creates bin/rori18n
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
The binary is downloaded automatically on first run and cached at
|
|
43
|
+
`~/.rori18n/bin/`. Nothing to install manually.
|
|
44
|
+
|
|
45
|
+
**Supported platforms:** macOS (Apple Silicon, Intel), Linux (x86_64).
|
|
46
|
+
|
|
47
|
+
---
|
|
48
|
+
|
|
49
|
+
## Usage
|
|
50
|
+
|
|
51
|
+
All commands take `--root <path-to-rails-app>`. If you run from inside the app,
|
|
52
|
+
`--root .` works.
|
|
53
|
+
|
|
54
|
+
```sh
|
|
55
|
+
bin/rori18n <command> --root <rails-app-root> [flags]
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
Or via Rake:
|
|
59
|
+
|
|
60
|
+
```sh
|
|
61
|
+
bundle exec rake rori18n:run ARGS="<command> [flags]"
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
---
|
|
65
|
+
|
|
66
|
+
## Workflow
|
|
67
|
+
|
|
68
|
+
### 1. See what needs extracting
|
|
69
|
+
|
|
70
|
+
```sh
|
|
71
|
+
bin/rori18n report --root .
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
Lists every hardcoded user-visible string in `app/` with file and line number.
|
|
75
|
+
Read-only — nothing is changed.
|
|
76
|
+
|
|
77
|
+
```sh
|
|
78
|
+
# CI: fail if hardcoded strings exist in changed files
|
|
79
|
+
git diff --name-only origin/main | \
|
|
80
|
+
bin/rori18n report --root . --fail-on-found --changed-files -
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
### 2. Extract strings to YAML
|
|
84
|
+
|
|
85
|
+
```sh
|
|
86
|
+
# Preview first
|
|
87
|
+
bin/rori18n generate --root . --fix --dry-run
|
|
88
|
+
|
|
89
|
+
# Apply
|
|
90
|
+
bin/rori18n generate --root . --fix
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
One pass does everything:
|
|
94
|
+
|
|
95
|
+
- Strings used in multiple files → written to `shared.{lang}.yml`
|
|
96
|
+
- Unique strings → written to the matching topic file (`home.en.yml`, etc.)
|
|
97
|
+
- Source files rewritten — hardcoded strings replaced with `t('key')` calls
|
|
98
|
+
|
|
99
|
+
The app behaves identically after this step.
|
|
100
|
+
|
|
101
|
+
```sh
|
|
102
|
+
# Only process changed files
|
|
103
|
+
git diff --name-only origin/main | \
|
|
104
|
+
bin/rori18n generate --root . --fix --changed-files -
|
|
105
|
+
|
|
106
|
+
# Also create ES/FR skeleton files
|
|
107
|
+
bin/rori18n generate --root . --fix --languages es,fr
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
### 3. Merge ERB fragments
|
|
111
|
+
|
|
112
|
+
Sentences split across ERB interpolations are merged into a single `t()` call:
|
|
113
|
+
|
|
114
|
+
```erb
|
|
115
|
+
<%# Before %>
|
|
116
|
+
<p>Hello <%= current_user.name %>, you have <%= count %> messages.</p>
|
|
117
|
+
|
|
118
|
+
<%# After %>
|
|
119
|
+
<p><%= t('.greeting', name: current_user.name, count: count) %></p>
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
```sh
|
|
123
|
+
bin/rori18n merge-fragments --root . --dry-run
|
|
124
|
+
bin/rori18n merge-fragments --root . --fix
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
Complex cases (boolean operators, nested HTML) are flagged for manual review and
|
|
128
|
+
never auto-patched.
|
|
129
|
+
|
|
130
|
+
### 4. Lint
|
|
131
|
+
|
|
132
|
+
```sh
|
|
133
|
+
bin/rori18n lint --root .
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
Exits `0` if every `t('key')` call resolves to a defined YAML entry. Exits `1`
|
|
137
|
+
with `file:line: error: missing key "..."` output. Add to CI.
|
|
138
|
+
|
|
139
|
+
### 5. Translate
|
|
140
|
+
|
|
141
|
+
Requires a [Google Cloud Translation API](https://cloud.google.com/translate)
|
|
142
|
+
service account key.
|
|
143
|
+
|
|
144
|
+
```sh
|
|
145
|
+
export GOOGLE_APPLICATION_CREDENTIALS=/path/to/service-account.json
|
|
146
|
+
|
|
147
|
+
bin/rori18n translate --root . --to es,fr --dry-run
|
|
148
|
+
bin/rori18n translate --root . --to es,fr
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
**Write safety:** only fills empty values and `TODO:`/`FIXME:` placeholders.
|
|
152
|
+
Human translations are never overwritten.
|
|
153
|
+
|
|
154
|
+
Results are cached — re-running the same source string does not hit the API
|
|
155
|
+
again.
|
|
156
|
+
|
|
157
|
+
```sh
|
|
158
|
+
# Protect brand names from being translated
|
|
159
|
+
bin/rori18n translate --root . --to es,fr \
|
|
160
|
+
--protect-words "Acme Corp,AbstractAPI"
|
|
161
|
+
|
|
162
|
+
# Or from a file (one phrase per line)
|
|
163
|
+
bin/rori18n translate --root . --to es,fr \
|
|
164
|
+
--protect-file .translate-dictionary.txt
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
### 6. Prune dead keys
|
|
168
|
+
|
|
169
|
+
```sh
|
|
170
|
+
bin/rori18n prune --root . --dry-run
|
|
171
|
+
bin/rori18n prune --root .
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
Deletes YAML keys that no source file calls. Understands pluralization —
|
|
175
|
+
`foo.one` / `foo.other` are kept when source calls `t('foo', count: n)`.
|
|
176
|
+
|
|
177
|
+
---
|
|
178
|
+
|
|
179
|
+
## All commands
|
|
180
|
+
|
|
181
|
+
| Command | What it does |
|
|
182
|
+
| ----------------- | ----------------------------------------------------------- |
|
|
183
|
+
| `report` | List hardcoded strings (read-only, CI-safe) |
|
|
184
|
+
| `generate` | Extract strings to YAML; optionally replace them with `t()` |
|
|
185
|
+
| `merge-fragments` | Merge ERB sentence fragments into single `t()` calls |
|
|
186
|
+
| `lint` | Exit 1 if any `t()` call references an undefined key |
|
|
187
|
+
| `audit` | Report missing, orphaned, and empty keys |
|
|
188
|
+
| `add-key` | Add one key-value pair to the correct YAML file |
|
|
189
|
+
| `prune` | Delete YAML keys never referenced in source |
|
|
190
|
+
| `translate` | Fill missing keys via Google Cloud Translation |
|
|
191
|
+
| `analyze` | Find duplicate key names or identical values |
|
|
192
|
+
| `consolidate` | Deduplicate keys and rewrite all callers in one pass |
|
|
193
|
+
| `refactor-key` | Rename a key in YAML and all `t()` callers |
|
|
194
|
+
|
|
195
|
+
---
|
|
196
|
+
|
|
197
|
+
## Command reference
|
|
198
|
+
|
|
199
|
+
### `report`
|
|
200
|
+
|
|
201
|
+
```sh
|
|
202
|
+
bin/rori18n report --root .
|
|
203
|
+
bin/rori18n report --root . --fail-on-found
|
|
204
|
+
bin/rori18n report --root . --erb-only
|
|
205
|
+
|
|
206
|
+
# Limit to changed files (reads newline-separated paths from stdin)
|
|
207
|
+
git diff --name-only origin/main | \
|
|
208
|
+
bin/rori18n report --root . --changed-files -
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
### `generate`
|
|
212
|
+
|
|
213
|
+
```sh
|
|
214
|
+
bin/rori18n generate --root . --fix --dry-run
|
|
215
|
+
bin/rori18n generate --root . --fix
|
|
216
|
+
bin/rori18n generate --root . --fix --languages es,fr
|
|
217
|
+
bin/rori18n generate --root . --fix --safe-only # only reuse existing keys
|
|
218
|
+
bin/rori18n generate --root . --fix --no-shared # skip shared.yml consolidation
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
### `merge-fragments`
|
|
222
|
+
|
|
223
|
+
```sh
|
|
224
|
+
bin/rori18n merge-fragments --root . --dry-run
|
|
225
|
+
bin/rori18n merge-fragments --root . --fix
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
### `lint`
|
|
229
|
+
|
|
230
|
+
```sh
|
|
231
|
+
bin/rori18n lint --root .
|
|
232
|
+
bin/rori18n lint --root . --lang fr
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
### `audit`
|
|
236
|
+
|
|
237
|
+
```sh
|
|
238
|
+
bin/rori18n audit --root . --orphaned # in YAML, never called
|
|
239
|
+
bin/rori18n audit --root . --missing # called in source, not in YAML
|
|
240
|
+
bin/rori18n audit --root . --all
|
|
241
|
+
bin/rori18n audit --root . --empty-values
|
|
242
|
+
bin/rori18n audit --root . --compare-locale fr
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
### `add-key`
|
|
246
|
+
|
|
247
|
+
```sh
|
|
248
|
+
bin/rori18n add-key --root . \
|
|
249
|
+
--key shared.buttons.save \
|
|
250
|
+
--value "Save changes"
|
|
251
|
+
|
|
252
|
+
bin/rori18n add-key --root . --lang es \
|
|
253
|
+
--key shared.buttons.save \
|
|
254
|
+
--value "Guardar cambios"
|
|
255
|
+
```
|
|
256
|
+
|
|
257
|
+
Key is routed to the YAML file matching its top-level namespace
|
|
258
|
+
(`shared.buttons.save` → `shared.en.yml`, `dashboard.foo` → `dashboard.en.yml`).
|
|
259
|
+
|
|
260
|
+
### `prune`
|
|
261
|
+
|
|
262
|
+
```sh
|
|
263
|
+
bin/rori18n prune --root . --dry-run
|
|
264
|
+
bin/rori18n prune --root .
|
|
265
|
+
bin/rori18n prune --root . --lang fr
|
|
266
|
+
bin/rori18n prune --root . --pattern 'shared\.common\.'
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
### `translate`
|
|
270
|
+
|
|
271
|
+
```sh
|
|
272
|
+
export GOOGLE_APPLICATION_CREDENTIALS=/path/to/service-account.json
|
|
273
|
+
|
|
274
|
+
bin/rori18n translate --root . --to es,fr --dry-run
|
|
275
|
+
bin/rori18n translate --root . --to es
|
|
276
|
+
bin/rori18n translate --root . --to es --no-cache
|
|
277
|
+
bin/rori18n translate --root . --to es --report-file reports/translate.json
|
|
278
|
+
bin/rori18n translate --root . --to es --protect-words "Acme,AbstractAPI"
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
### `analyze`
|
|
282
|
+
|
|
283
|
+
```sh
|
|
284
|
+
bin/rori18n analyze --root .
|
|
285
|
+
bin/rori18n analyze --root . --all # include same-name, different-value keys
|
|
286
|
+
bin/rori18n analyze --root . --source # also scan ERB for hardcoded duplicates
|
|
287
|
+
```
|
|
288
|
+
|
|
289
|
+
### `consolidate`
|
|
290
|
+
|
|
291
|
+
```sh
|
|
292
|
+
bin/rori18n consolidate --root . --dry-run
|
|
293
|
+
bin/rori18n consolidate --root .
|
|
294
|
+
bin/rori18n consolidate --root . --no-prune # rewrite callers, skip key deletion
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
### `refactor-key`
|
|
298
|
+
|
|
299
|
+
```sh
|
|
300
|
+
# Always dry-run first
|
|
301
|
+
bin/rori18n refactor-key --root . \
|
|
302
|
+
--old shared.common.copy_btn \
|
|
303
|
+
--new shared.buttons.copy \
|
|
304
|
+
--dry-run
|
|
305
|
+
|
|
306
|
+
bin/rori18n refactor-key --root . \
|
|
307
|
+
--old shared.common.copy_btn \
|
|
308
|
+
--new shared.buttons.copy
|
|
309
|
+
|
|
310
|
+
# EN only (skip other locale files)
|
|
311
|
+
bin/rori18n refactor-key --root . \
|
|
312
|
+
--old shared.common.copy_btn \
|
|
313
|
+
--new shared.buttons.copy \
|
|
314
|
+
--all-lang=false
|
|
315
|
+
```
|
|
316
|
+
|
|
317
|
+
---
|
|
318
|
+
|
|
319
|
+
## CI integration
|
|
320
|
+
|
|
321
|
+
```yaml
|
|
322
|
+
# Minimal: lint only
|
|
323
|
+
- name: Lint i18n keys
|
|
324
|
+
run: bin/rori18n lint --root .
|
|
325
|
+
|
|
326
|
+
# Full: block hardcoded strings + lint
|
|
327
|
+
- name: Check hardcoded strings
|
|
328
|
+
run: |
|
|
329
|
+
git diff --name-only origin/main | \
|
|
330
|
+
bin/rori18n report --root . --fail-on-found --changed-files -
|
|
331
|
+
|
|
332
|
+
- name: Lint i18n keys
|
|
333
|
+
run: bin/rori18n lint --root .
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
---
|
|
337
|
+
|
|
338
|
+
## YAML layout expected
|
|
339
|
+
|
|
340
|
+
```
|
|
341
|
+
config/locales/
|
|
342
|
+
en/
|
|
343
|
+
home.en.yml # en.home.*
|
|
344
|
+
dashboard.en.yml # en.dashboard.*
|
|
345
|
+
shared.en.yml # en.shared.*
|
|
346
|
+
es/
|
|
347
|
+
home.es.yml
|
|
348
|
+
shared.es.yml
|
|
349
|
+
fr/
|
|
350
|
+
...
|
|
351
|
+
```
|
|
352
|
+
|
|
353
|
+
---
|
|
354
|
+
|
|
355
|
+
## vs i18n-tasks
|
|
356
|
+
|
|
357
|
+
rori18n handles all write operations. `i18n-tasks` is still useful as a passive
|
|
358
|
+
health-checker (`bundle exec i18n-tasks health`) — its scanner covers some
|
|
359
|
+
Rails-specific patterns (before_actions, model translations) that static
|
|
360
|
+
analysis misses. Use both: rori18n for writes, i18n-tasks health-only in CI.
|
data/lib/rori18n/version.rb
CHANGED
data/rori18n-rails.gemspec
CHANGED
|
@@ -5,9 +5,11 @@ Gem::Specification.new do |s|
|
|
|
5
5
|
s.version = Rori18n::VERSION
|
|
6
6
|
s.authors = ["Eliaz Bobadilla"]
|
|
7
7
|
s.email = ["eliaz.bobadilladev@gmail.com"]
|
|
8
|
-
s.summary = "
|
|
9
|
-
s.description = "
|
|
10
|
-
"
|
|
8
|
+
s.summary = "Rails i18n toolchain: extract strings, inject t() calls, translate, prune, refactor keys"
|
|
9
|
+
s.description = "rori18n is a Rails i18n CLI that replaces i18n-tasks write commands and adds " \
|
|
10
|
+
"capabilities it lacks: automatic hardcoded-string extraction from ERB, t() call " \
|
|
11
|
+
"injection, ERB fragment merging, Google Cloud Translation, deduplication, and " \
|
|
12
|
+
"key refactoring. "
|
|
11
13
|
s.homepage = "https://github.com/bobadilla-tech/rori18n"
|
|
12
14
|
s.license = "MIT"
|
|
13
15
|
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: rori18n-rails
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.
|
|
4
|
+
version: 1.2.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Eliaz Bobadilla
|
|
@@ -9,8 +9,10 @@ bindir: exe
|
|
|
9
9
|
cert_chain: []
|
|
10
10
|
date: 1980-01-02 00:00:00.000000000 Z
|
|
11
11
|
dependencies: []
|
|
12
|
-
description:
|
|
13
|
-
|
|
12
|
+
description: 'rori18n is a Rails i18n CLI that replaces i18n-tasks write commands
|
|
13
|
+
and adds capabilities it lacks: automatic hardcoded-string extraction from ERB,
|
|
14
|
+
t() call injection, ERB fragment merging, Google Cloud Translation, deduplication,
|
|
15
|
+
and key refactoring. '
|
|
14
16
|
email:
|
|
15
17
|
- eliaz.bobadilladev@gmail.com
|
|
16
18
|
executables:
|
|
@@ -18,6 +20,7 @@ executables:
|
|
|
18
20
|
extensions: []
|
|
19
21
|
extra_rdoc_files: []
|
|
20
22
|
files:
|
|
23
|
+
- README.md
|
|
21
24
|
- exe/rori18n
|
|
22
25
|
- lib/generators/rori18n/install/install_generator.rb
|
|
23
26
|
- lib/generators/rori18n/install/templates/binstub.tt
|
|
@@ -51,5 +54,6 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
51
54
|
requirements: []
|
|
52
55
|
rubygems_version: 4.0.6
|
|
53
56
|
specification_version: 4
|
|
54
|
-
summary:
|
|
57
|
+
summary: 'Rails i18n toolchain: extract strings, inject t() calls, translate, prune,
|
|
58
|
+
refactor keys'
|
|
55
59
|
test_files: []
|