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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c8c49e7c74fc30821db32ed869c698211245a5c89df34ba7e2f2ed6334ac8005
4
- data.tar.gz: 3c2f7300ac6a78679fc69b79850329d3f7ef73b4db91dd6674896eafd3073405
3
+ metadata.gz: adf721134937acd15e542d0763193c55f2a978d456b9bb61d7cfb16af37c761c
4
+ data.tar.gz: '08c22af47a7123428b315f4ce00a23c7d2c56d226c2c33f6b98cd8961e3d27ae'
5
5
  SHA512:
6
- metadata.gz: 23c94d808d6f69d3c929ea5975a677177f3659c135a35bdb06ae2318a5cf2bd695ecb2aa46b529126143702759da30dca35015c106078649b15c4cb7813ee83e
7
- data.tar.gz: 44ddc37a740aede0b62a9619e90e2ce6f3bb25bb11944504cb2ac34a3fcee5b74e0836bdf748396a8b3c54f672cf15a59a132fd55f6a33933d993e6d8350df0b
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.
@@ -1,4 +1,4 @@
1
1
  module Rori18n
2
- VERSION = "1.0.0"
2
+ VERSION = "1.2.0"
3
3
  CLI_VERSION = VERSION
4
4
  end
@@ -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 = "Use rori18n Go CLI as a Rails development dependency"
9
- s.description = "Wraps the rori18n Go CLI tool so it behaves like a native Rails dev dependency. " \
10
- "Downloads the correct binary on first run. No manual installation required."
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.0.0
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: Wraps the rori18n Go CLI tool so it behaves like a native Rails dev dependency.
13
- Downloads the correct binary on first run. No manual installation required.
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: Use rori18n Go CLI as a Rails development dependency
57
+ summary: 'Rails i18n toolchain: extract strings, inject t() calls, translate, prune,
58
+ refactor keys'
55
59
  test_files: []