i18n-js 4.2.4 → 5.0.0.rc1
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/.github/workflows/ruby-tests.yml +8 -14
- data/CHANGELOG.md +37 -0
- data/MIGRATING_CONFIG_FOR_USERS.md +200 -0
- data/MIGRATING_PLUGINS_FOR_PLUGIN_DEVELOPERS.md +299 -0
- data/README.md +78 -61
- data/bin/release +33 -12
- data/i18n-js.gemspec +1 -0
- data/lib/i18n-js/cli/command.rb +1 -7
- data/lib/i18n-js/cli/lint_scripts_command.rb +39 -16
- data/lib/i18n-js/cli/lint_translations_command.rb +68 -43
- data/lib/i18n-js/cli.rb +1 -3
- data/lib/i18n-js/deep_merge.rb +32 -0
- data/lib/i18n-js/embed_fallback_translations_plugin.rb +41 -38
- data/lib/i18n-js/export_files_plugin.rb +9 -28
- data/lib/i18n-js/lint.js +168324 -105047
- data/lib/i18n-js/plugin.rb +34 -24
- data/lib/i18n-js/schema.rb +28 -24
- data/lib/i18n-js/version.rb +1 -1
- data/lib/i18n-js.rb +20 -12
- data/package-lock.json +591 -0
- data/package.json +6 -3
- metadata +30 -7
- data/lib/i18n-js/cli/check_command.rb +0 -17
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 4651d246704c3470ac5139dec7d2351e4aad13866be1d51e20e6bcf960afa2aa
|
|
4
|
+
data.tar.gz: 43ba1c9e9f74c9032c17ee00fd54489b91275d23f559ff042a3b1c1300ddd3e9
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: d4b83c24cb85bcfd1badeef6ecc4e2955a138be41f5fbd68cf5122c21daa0c34b8e5df69a5c16739aca8f007dde7141f1cc35cc4ee9f9166c54754b6d8b33d61
|
|
7
|
+
data.tar.gz: 91a2fb161e6b7f3d1e698f92e49dabd46aa37bb15153ca6ce8f28849acd704204fff033c79ed7a06f599d2246ef9b8ae285a66d8165a2e538b42140e1d5e95a5
|
|
@@ -9,14 +9,12 @@ on:
|
|
|
9
9
|
|
|
10
10
|
jobs:
|
|
11
11
|
build:
|
|
12
|
-
name:
|
|
13
|
-
Tests with Ruby ${{ matrix.ruby }}, Node ${{ matrix.node }} and ${{
|
|
14
|
-
matrix.gemfile }}
|
|
12
|
+
name: Tests with Ruby ${{ matrix.ruby }}, Node ${{ matrix.node }} and ${{ matrix.gemfile }}
|
|
15
13
|
runs-on: "ubuntu-latest"
|
|
16
14
|
strategy:
|
|
17
15
|
fail-fast: false
|
|
18
16
|
matrix:
|
|
19
|
-
ruby: ["3.
|
|
17
|
+
ruby: ["3.4", "3.5", "4.0"]
|
|
20
18
|
node: ["22", "24"]
|
|
21
19
|
gemfile:
|
|
22
20
|
- Gemfile
|
|
@@ -25,26 +23,22 @@ jobs:
|
|
|
25
23
|
github.actor != 'dependabot[bot]'
|
|
26
24
|
|
|
27
25
|
steps:
|
|
28
|
-
- uses: actions/checkout@
|
|
26
|
+
- uses: actions/checkout@v6
|
|
29
27
|
|
|
30
|
-
- uses: actions/cache@
|
|
28
|
+
- uses: actions/cache@v5
|
|
31
29
|
id: bundler-cache
|
|
32
30
|
with:
|
|
33
31
|
path: vendor/bundle
|
|
34
32
|
key: >
|
|
35
|
-
${{ runner.os }}-${{ matrix.ruby }}-gems-${{
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
- uses: actions/cache@v4
|
|
33
|
+
${{ runner.os }}-${{ matrix.ruby }}-gems-${{ hashFiles(matrix.gemfile) }}
|
|
34
|
+
- uses: actions/cache@v5
|
|
39
35
|
id: npm-cache
|
|
40
36
|
with:
|
|
41
37
|
path: vendor/bundle
|
|
42
38
|
key: >
|
|
43
|
-
${{ runner.os }}-${{ matrix.node }}-npm-${{
|
|
44
|
-
hashFiles('package.json') }}
|
|
45
|
-
|
|
39
|
+
${{ runner.os }}-${{ matrix.node }}-npm-${{ hashFiles('package.json') }}
|
|
46
40
|
- name: Set up Node
|
|
47
|
-
uses: actions/setup-node@
|
|
41
|
+
uses: actions/setup-node@v6.4.0
|
|
48
42
|
with:
|
|
49
43
|
node-version: ${{ matrix.node }}
|
|
50
44
|
|
data/CHANGELOG.md
CHANGED
|
@@ -11,6 +11,43 @@ Prefix your message with one of the following:
|
|
|
11
11
|
- [Security] in case of vulnerabilities.
|
|
12
12
|
-->
|
|
13
13
|
|
|
14
|
+
## v5.0.0.rc1 - Jun 02, 2026
|
|
15
|
+
|
|
16
|
+
- [Added] `embed_fallback_translations` plugin now supports `I18n.fallbacks`,
|
|
17
|
+
and will switch to it automatically if you're using a backend that includes
|
|
18
|
+
the `I18n::Backend::Fallbacks` module and have `I18n.fallbacks` configured.
|
|
19
|
+
- [Changed] `i18n lint:translations` and `i18n lint:scripts` now support globs
|
|
20
|
+
in their `ignore` option.
|
|
21
|
+
- [Removed] Previous versions allowed bare keys in lint's `:ignore` rule. This
|
|
22
|
+
is no longer supported; instead, use `*.key`.
|
|
23
|
+
- [Removed] Remove `i18n check`; use `i18n lint:translations` instead.
|
|
24
|
+
- [Fixed] Return the number of missing translations as the exit code when
|
|
25
|
+
running `i18n lint:scripts`.
|
|
26
|
+
- [Changed] Plugin configuration moved from top-level keys to a `pipeline:`
|
|
27
|
+
array in the config file. Each entry requires a `plugin:` key identifying the
|
|
28
|
+
plugin and an `enabled:` key. Plugin-specific options are defined inline in
|
|
29
|
+
the same stage object.
|
|
30
|
+
- [Changed] `I18nJS::Plugin.key` is now a class method returning a String.
|
|
31
|
+
Previously it was an instance method called `config_key` that returned a
|
|
32
|
+
Symbol.
|
|
33
|
+
- [Changed] `I18nJS::Plugin#initialize` now accepts `plugin_config:` and
|
|
34
|
+
`main_config:` instead of a single `config:` argument.
|
|
35
|
+
- [Changed] `I18nJS::Plugin#config` now returns only the plugin's own
|
|
36
|
+
configuration slice instead of the full main config.
|
|
37
|
+
- [Changed] `I18nJS.initialize_plugins!` now returns the list of active plugin
|
|
38
|
+
instances. The `I18nJS.plugins` accessor has been removed.
|
|
39
|
+
- [Changed] `I18nJS::Schema.root_keys` is now a frozen Array. Plugins no longer
|
|
40
|
+
need to register a root key in their `setup` method.
|
|
41
|
+
- [Changed] Schema validation paths in `validate_schema` are now relative to the
|
|
42
|
+
plugin's own config root. Remove the leading `config_key` segment from all
|
|
43
|
+
paths passed to `schema.*` helpers.
|
|
44
|
+
- [Removed] The `check:` root key is no longer recognised by the schema
|
|
45
|
+
validator. Remove it from your config file.
|
|
46
|
+
- [Added] A single plugin class can now appear multiple times in the pipeline
|
|
47
|
+
with different configurations, each running as an independent instance.
|
|
48
|
+
- [Changed] Export translations in parallel. To enable parallel mode, your
|
|
49
|
+
output file definition must include the `:locale` placeholder.
|
|
50
|
+
|
|
14
51
|
## v4.2.3 - Mar 29, 2023
|
|
15
52
|
|
|
16
53
|
- [Fixed] Load plugins when running `i18n lint:*` commands.
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
# Migrating Your Configuration File
|
|
2
|
+
|
|
3
|
+
This guide covers the changes you need to make to your `config/i18n.yml` (or
|
|
4
|
+
equivalent) after the switch to the `pipeline:` API.
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## What changed
|
|
9
|
+
|
|
10
|
+
Plugin configuration used to live at the top level of the config file, each
|
|
11
|
+
plugin using its own root key. All plugins are now listed in a single
|
|
12
|
+
`pipeline:` array. The order of entries in the array determines the order in
|
|
13
|
+
which plugins run.
|
|
14
|
+
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
## 1. `embed_fallback_translations`
|
|
18
|
+
|
|
19
|
+
**Before**
|
|
20
|
+
|
|
21
|
+
```yaml
|
|
22
|
+
translations:
|
|
23
|
+
- file: app/javascript/locales/%{locale}.json
|
|
24
|
+
patterns:
|
|
25
|
+
- "*"
|
|
26
|
+
|
|
27
|
+
embed_fallback_translations:
|
|
28
|
+
enabled: true
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
**After**
|
|
32
|
+
|
|
33
|
+
```yaml
|
|
34
|
+
translations:
|
|
35
|
+
- file: app/javascript/locales/%{locale}.json
|
|
36
|
+
patterns:
|
|
37
|
+
- "*"
|
|
38
|
+
|
|
39
|
+
pipeline:
|
|
40
|
+
- plugin: embed_fallback_translations
|
|
41
|
+
enabled: true
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
---
|
|
45
|
+
|
|
46
|
+
## 2. `export_files`
|
|
47
|
+
|
|
48
|
+
**Before**
|
|
49
|
+
|
|
50
|
+
```yaml
|
|
51
|
+
translations:
|
|
52
|
+
- file: app/javascript/locales/%{locale}.json
|
|
53
|
+
patterns:
|
|
54
|
+
- "*"
|
|
55
|
+
|
|
56
|
+
export_files:
|
|
57
|
+
enabled: true
|
|
58
|
+
files:
|
|
59
|
+
- template: path/to/template.erb
|
|
60
|
+
output: "%{dir}/%{base_name}.ts"
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
**After**
|
|
64
|
+
|
|
65
|
+
```yaml
|
|
66
|
+
translations:
|
|
67
|
+
- file: app/javascript/locales/%{locale}.json
|
|
68
|
+
patterns:
|
|
69
|
+
- "*"
|
|
70
|
+
|
|
71
|
+
pipeline:
|
|
72
|
+
- plugin: export_files
|
|
73
|
+
enabled: true
|
|
74
|
+
files:
|
|
75
|
+
- template: path/to/template.erb
|
|
76
|
+
output: "%{dir}/%{base_name}.ts"
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
Plugin-specific keys (`files:` in this case) move into the pipeline stage
|
|
80
|
+
object, directly alongside `plugin:` and `enabled:`.
|
|
81
|
+
|
|
82
|
+
---
|
|
83
|
+
|
|
84
|
+
## 3. Multiple plugins
|
|
85
|
+
|
|
86
|
+
When you use more than one plugin, list them all under the same `pipeline:`
|
|
87
|
+
key. The plugins run in the order they are listed.
|
|
88
|
+
|
|
89
|
+
**Before**
|
|
90
|
+
|
|
91
|
+
```yaml
|
|
92
|
+
translations:
|
|
93
|
+
- file: app/javascript/locales/%{locale}.json
|
|
94
|
+
patterns:
|
|
95
|
+
- "*"
|
|
96
|
+
|
|
97
|
+
embed_fallback_translations:
|
|
98
|
+
enabled: true
|
|
99
|
+
|
|
100
|
+
export_files:
|
|
101
|
+
enabled: true
|
|
102
|
+
files:
|
|
103
|
+
- template: path/to/template.erb
|
|
104
|
+
output: "%{dir}/%{base_name}.ts"
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
**After**
|
|
108
|
+
|
|
109
|
+
```yaml
|
|
110
|
+
translations:
|
|
111
|
+
- file: app/javascript/locales/%{locale}.json
|
|
112
|
+
patterns:
|
|
113
|
+
- "*"
|
|
114
|
+
|
|
115
|
+
pipeline:
|
|
116
|
+
- plugin: embed_fallback_translations
|
|
117
|
+
enabled: true
|
|
118
|
+
|
|
119
|
+
- plugin: export_files
|
|
120
|
+
enabled: true
|
|
121
|
+
files:
|
|
122
|
+
- template: path/to/template.erb
|
|
123
|
+
output: "%{dir}/%{base_name}.ts"
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
---
|
|
127
|
+
|
|
128
|
+
## 4. Temporarily disabling a plugin
|
|
129
|
+
|
|
130
|
+
Set `enabled: false` on the pipeline stage. The stage stays in the file so you
|
|
131
|
+
can re-enable it without rewriting the config.
|
|
132
|
+
|
|
133
|
+
```yaml
|
|
134
|
+
pipeline:
|
|
135
|
+
- plugin: embed_fallback_translations
|
|
136
|
+
enabled: false # temporarily disabled
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
Previously, removing the top-level key was the only way to disable a plugin.
|
|
140
|
+
|
|
141
|
+
---
|
|
142
|
+
|
|
143
|
+
## 5. Running the same plugin more than once
|
|
144
|
+
|
|
145
|
+
The pipeline allows the same plugin to appear multiple times with different
|
|
146
|
+
options. This was not possible with the old top-level key approach.
|
|
147
|
+
|
|
148
|
+
```yaml
|
|
149
|
+
pipeline:
|
|
150
|
+
- plugin: export_files
|
|
151
|
+
enabled: true
|
|
152
|
+
files:
|
|
153
|
+
- template: templates/esm.erb
|
|
154
|
+
output: "%{dir}/%{base_name}.mjs"
|
|
155
|
+
|
|
156
|
+
- plugin: export_files
|
|
157
|
+
enabled: true
|
|
158
|
+
files:
|
|
159
|
+
- template: templates/cjs.erb
|
|
160
|
+
output: "%{dir}/%{base_name}.cjs"
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
---
|
|
164
|
+
|
|
165
|
+
## 6. The `check` key was removed
|
|
166
|
+
|
|
167
|
+
The `check:` root key is no longer a recognised configuration option and will
|
|
168
|
+
cause a validation error if present. If you used `check.ignore` to suppress
|
|
169
|
+
known-missing translation keys, move those entries to `lint_translations.ignore`
|
|
170
|
+
— it serves the same purpose.
|
|
171
|
+
|
|
172
|
+
**Before**
|
|
173
|
+
|
|
174
|
+
```yaml
|
|
175
|
+
check:
|
|
176
|
+
ignore:
|
|
177
|
+
- "es.bye"
|
|
178
|
+
- "pt.bye"
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
**After**
|
|
182
|
+
|
|
183
|
+
```yaml
|
|
184
|
+
lint_translations:
|
|
185
|
+
ignore:
|
|
186
|
+
- "es.bye"
|
|
187
|
+
- "pt.bye"
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
If your `check:` block contained no `ignore:` list, delete it entirely.
|
|
191
|
+
|
|
192
|
+
---
|
|
193
|
+
|
|
194
|
+
## Quick checklist
|
|
195
|
+
|
|
196
|
+
- [ ] Remove the top-level `embed_fallback_translations:` block and replace with a `pipeline:` entry
|
|
197
|
+
- [ ] Remove the top-level `export_files:` block and replace with a `pipeline:` entry (move `files:` into the stage)
|
|
198
|
+
- [ ] Do the same for any third-party plugin that had its own top-level key
|
|
199
|
+
- [ ] Move `check.ignore` entries to `lint_translations.ignore`, then delete the `check:` block
|
|
200
|
+
- [ ] Verify the `pipeline:` key is a YAML sequence (starts with `-`), not a mapping
|
|
@@ -0,0 +1,299 @@
|
|
|
1
|
+
# Migrating Plugins to the Pipeline API
|
|
2
|
+
|
|
3
|
+
This guide covers the breaking changes to the plugin API introduced in the
|
|
4
|
+
commit that switched plugins from top-level config keys to a `pipeline` array.
|
|
5
|
+
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## Overview of changes
|
|
9
|
+
|
|
10
|
+
| Area | Before | After |
|
|
11
|
+
|------|--------|-------|
|
|
12
|
+
| Config location | Top-level key per plugin | `pipeline:` array |
|
|
13
|
+
| Key method | `config_key` (instance, Symbol) | `Plugin.key` (class method, String) |
|
|
14
|
+
| Constructor | `initialize(config:)` | `initialize(plugin_config:, main_config:)` |
|
|
15
|
+
| `config` accessor | `main_config[config_key]` | plugin-specific hash from pipeline entry |
|
|
16
|
+
| `setup` | registers root schema key | no schema registration needed |
|
|
17
|
+
| `validate_schema` paths | prefixed with `config_key` | relative to plugin config root |
|
|
18
|
+
| `I18nJS.plugins` | global accessor | return value of `initialize_plugins!` |
|
|
19
|
+
| `Schema.root_keys` | mutable Set | frozen Array |
|
|
20
|
+
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## 1. Update the config file
|
|
24
|
+
|
|
25
|
+
Plugin configuration no longer lives at the top level of the YAML file. Move
|
|
26
|
+
every plugin block into the `pipeline:` array and add a `plugin:` key that
|
|
27
|
+
identifies the plugin by its inferred key name (snake_case, no `Plugin`
|
|
28
|
+
suffix).
|
|
29
|
+
|
|
30
|
+
**Before**
|
|
31
|
+
|
|
32
|
+
```yaml
|
|
33
|
+
translations:
|
|
34
|
+
- file: app/javascript/locales/%{locale}.json
|
|
35
|
+
patterns:
|
|
36
|
+
- "*"
|
|
37
|
+
|
|
38
|
+
embed_fallback_translations:
|
|
39
|
+
enabled: true
|
|
40
|
+
|
|
41
|
+
export_files:
|
|
42
|
+
enabled: true
|
|
43
|
+
files:
|
|
44
|
+
- template: templates/export.erb
|
|
45
|
+
output: "%{dir}/%{base_name}-%{digest}.ts"
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
**After**
|
|
49
|
+
|
|
50
|
+
```yaml
|
|
51
|
+
translations:
|
|
52
|
+
- file: app/javascript/locales/%{locale}.json
|
|
53
|
+
patterns:
|
|
54
|
+
- "*"
|
|
55
|
+
|
|
56
|
+
pipeline:
|
|
57
|
+
- plugin: embed_fallback_translations
|
|
58
|
+
enabled: true
|
|
59
|
+
|
|
60
|
+
- plugin: export_files
|
|
61
|
+
enabled: true
|
|
62
|
+
files:
|
|
63
|
+
- template: templates/export.erb
|
|
64
|
+
output: "%{dir}/%{base_name}-%{digest}.ts"
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
All plugin-specific keys (like `files:` above) now live directly inside the
|
|
68
|
+
pipeline stage object, alongside `plugin:` and `enabled:`.
|
|
69
|
+
|
|
70
|
+
---
|
|
71
|
+
|
|
72
|
+
## 2. Rename `config_key` to `Plugin.key`
|
|
73
|
+
|
|
74
|
+
The method that infers the plugin's identifier moved from an **instance**
|
|
75
|
+
method returning a Symbol to a **class** method returning a String.
|
|
76
|
+
|
|
77
|
+
**Before**
|
|
78
|
+
|
|
79
|
+
```ruby
|
|
80
|
+
# instance method, returns Symbol
|
|
81
|
+
def config_key
|
|
82
|
+
:my_plugin
|
|
83
|
+
end
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
**After**
|
|
87
|
+
|
|
88
|
+
```ruby
|
|
89
|
+
# class method, returns String
|
|
90
|
+
def self.key
|
|
91
|
+
"my_plugin"
|
|
92
|
+
end
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
In most cases you do **not** need to override this method at all — it is
|
|
96
|
+
automatically inferred from the class name:
|
|
97
|
+
|
|
98
|
+
| Class name | Inferred key |
|
|
99
|
+
|------------|-------------|
|
|
100
|
+
| `SamplePlugin` | `"sample"` |
|
|
101
|
+
| `EmbedFallbackTranslationsPlugin` | `"embed_fallback_translations"` |
|
|
102
|
+
| `FetchFromHTTPPlugin` | `"fetch_from_http"` |
|
|
103
|
+
|
|
104
|
+
Override only if the inferred name does not match what you want to expose in the
|
|
105
|
+
config file.
|
|
106
|
+
|
|
107
|
+
---
|
|
108
|
+
|
|
109
|
+
## 3. Update the constructor
|
|
110
|
+
|
|
111
|
+
The constructor signature changed. `config:` (the full main config) was
|
|
112
|
+
replaced by two keyword arguments.
|
|
113
|
+
|
|
114
|
+
**Before**
|
|
115
|
+
|
|
116
|
+
```ruby
|
|
117
|
+
def initialize(config:)
|
|
118
|
+
@main_config = config
|
|
119
|
+
@schema = I18nJS::Schema.new(@main_config)
|
|
120
|
+
end
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
**After**
|
|
124
|
+
|
|
125
|
+
The base class handles initialization. You rarely need to override `initialize`
|
|
126
|
+
at all. If you do, call `super` and use the provided accessors:
|
|
127
|
+
|
|
128
|
+
```ruby
|
|
129
|
+
def initialize(plugin_config:, main_config:)
|
|
130
|
+
super
|
|
131
|
+
# @config => plugin-specific hash (the pipeline stage, minus :plugin key)
|
|
132
|
+
# @main_config => full config hash
|
|
133
|
+
# @schema => Schema.new(@config)
|
|
134
|
+
end
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
---
|
|
138
|
+
|
|
139
|
+
## 4. Use `config` instead of `main_config[config_key]`
|
|
140
|
+
|
|
141
|
+
`config` now returns only the plugin's own slice of configuration (the pipeline
|
|
142
|
+
stage hash, with the `plugin:` key removed). You no longer need to dig into
|
|
143
|
+
`main_config` to find your plugin's settings.
|
|
144
|
+
|
|
145
|
+
**Before**
|
|
146
|
+
|
|
147
|
+
```ruby
|
|
148
|
+
def transform(translations:)
|
|
149
|
+
return translations unless main_config[config_key][:enabled]
|
|
150
|
+
# work with main_config[config_key][:my_option]
|
|
151
|
+
end
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
**After**
|
|
155
|
+
|
|
156
|
+
```ruby
|
|
157
|
+
def transform(translations:)
|
|
158
|
+
# work with config[:my_option] directly
|
|
159
|
+
end
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
`enabled?` is also handled by the base class and returns `config[:enabled]`.
|
|
163
|
+
Only enabled plugins are placed in the pipeline, so you rarely need to check
|
|
164
|
+
`enabled?` inside `transform`.
|
|
165
|
+
|
|
166
|
+
---
|
|
167
|
+
|
|
168
|
+
## 5. Remove schema root key registration from `setup`
|
|
169
|
+
|
|
170
|
+
Plugins used to register their top-level config key so the schema validator
|
|
171
|
+
wouldn't reject it. This is no longer necessary — the `pipeline:` array is
|
|
172
|
+
already a recognised root key, and each stage is validated generically.
|
|
173
|
+
|
|
174
|
+
**Before**
|
|
175
|
+
|
|
176
|
+
```ruby
|
|
177
|
+
def setup
|
|
178
|
+
I18nJS::Schema.root_keys << config_key
|
|
179
|
+
end
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
**After**
|
|
183
|
+
|
|
184
|
+
```ruby
|
|
185
|
+
def setup
|
|
186
|
+
# plugin-specific setup only, no schema registration needed
|
|
187
|
+
end
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
If `setup` contained only the `root_keys <<` line, you can delete the method
|
|
191
|
+
entirely.
|
|
192
|
+
|
|
193
|
+
---
|
|
194
|
+
|
|
195
|
+
## 6. Update `validate_schema` paths
|
|
196
|
+
|
|
197
|
+
`Schema` is now initialized with the plugin's own config hash rather than the
|
|
198
|
+
full main config. All paths passed to schema helpers are therefore **relative to
|
|
199
|
+
the plugin config root**, not the global config root.
|
|
200
|
+
|
|
201
|
+
**Before**
|
|
202
|
+
|
|
203
|
+
```ruby
|
|
204
|
+
def validate_schema
|
|
205
|
+
valid_keys = %i[enabled files]
|
|
206
|
+
|
|
207
|
+
schema.expect_required_keys(keys: valid_keys, path: [config_key])
|
|
208
|
+
schema.reject_extraneous_keys(keys: valid_keys, path: [config_key])
|
|
209
|
+
schema.expect_array_with_items(path: [config_key, :files])
|
|
210
|
+
|
|
211
|
+
config[:files].each_with_index do |_, index|
|
|
212
|
+
export_keys = %i[template output]
|
|
213
|
+
schema.expect_required_keys(keys: export_keys, path: [config_key, :files, index])
|
|
214
|
+
schema.expect_type(path: [config_key, :files, index, :template], types: String)
|
|
215
|
+
end
|
|
216
|
+
end
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
**After**
|
|
220
|
+
|
|
221
|
+
```ruby
|
|
222
|
+
def validate_schema
|
|
223
|
+
valid_keys = %i[enabled files]
|
|
224
|
+
|
|
225
|
+
schema.expect_required_keys(keys: valid_keys) # path defaults to []
|
|
226
|
+
schema.reject_extraneous_keys(keys: valid_keys)
|
|
227
|
+
schema.expect_array_with_items(path: [:files]) # relative path
|
|
228
|
+
|
|
229
|
+
export_keys = %i[template output]
|
|
230
|
+
config[:files].each_with_index do |_, index|
|
|
231
|
+
schema.expect_required_keys(keys: export_keys, path: [:files, index])
|
|
232
|
+
schema.expect_type(path: [:files, index, :template], types: String)
|
|
233
|
+
end
|
|
234
|
+
end
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
The rule: **drop the leading `config_key` segment from every path**.
|
|
238
|
+
|
|
239
|
+
---
|
|
240
|
+
|
|
241
|
+
## 7. Stop using `I18nJS.plugins`
|
|
242
|
+
|
|
243
|
+
The global `I18nJS.plugins` accessor was removed. `initialize_plugins!` now
|
|
244
|
+
returns the list of active plugin instances directly.
|
|
245
|
+
|
|
246
|
+
**Before**
|
|
247
|
+
|
|
248
|
+
```ruby
|
|
249
|
+
I18nJS.initialize_plugins!(config:)
|
|
250
|
+
I18nJS.plugins.each { |p| p.do_something }
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
**After**
|
|
254
|
+
|
|
255
|
+
```ruby
|
|
256
|
+
plugins = I18nJS.initialize_plugins!(config:)
|
|
257
|
+
plugins.each { |p| p.do_something }
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
If you were calling `I18nJS.plugins.clear` in tests, switch to
|
|
261
|
+
`I18nJS.available_plugins.clear` (which clears registered plugin classes) or
|
|
262
|
+
simply stop clearing — `initialize_plugins!` now reads solely from the
|
|
263
|
+
`pipeline:` config so stale instances are never carried over.
|
|
264
|
+
|
|
265
|
+
---
|
|
266
|
+
|
|
267
|
+
## 8. One plugin class, multiple pipeline stages
|
|
268
|
+
|
|
269
|
+
A single plugin class can now appear **multiple times** in the pipeline with
|
|
270
|
+
different configurations. Each entry creates an independent plugin instance.
|
|
271
|
+
Each instance receives its own `config` hash.
|
|
272
|
+
|
|
273
|
+
```yaml
|
|
274
|
+
pipeline:
|
|
275
|
+
- plugin: export_files
|
|
276
|
+
enabled: true
|
|
277
|
+
files:
|
|
278
|
+
- template: templates/esm.erb
|
|
279
|
+
output: "app/js/%{base_name}.mjs"
|
|
280
|
+
|
|
281
|
+
- plugin: export_files
|
|
282
|
+
enabled: true
|
|
283
|
+
files:
|
|
284
|
+
- template: templates/cjs.erb
|
|
285
|
+
output: "app/js/%{base_name}.cjs"
|
|
286
|
+
```
|
|
287
|
+
|
|
288
|
+
---
|
|
289
|
+
|
|
290
|
+
## Quick checklist
|
|
291
|
+
|
|
292
|
+
- [ ] Move all plugin blocks from the top level into a `pipeline:` array
|
|
293
|
+
- [ ] Add a `plugin:` key to each pipeline stage
|
|
294
|
+
- [ ] Rename `config_key` instance method to `self.key` class method; change return type from Symbol to String
|
|
295
|
+
- [ ] Remove `initialize` override if it only delegated to `super`; otherwise update signature to `(plugin_config:, main_config:)`
|
|
296
|
+
- [ ] Replace `main_config[config_key][:option]` with `config[:option]`
|
|
297
|
+
- [ ] Delete `setup` if it only registered a root schema key
|
|
298
|
+
- [ ] Drop the leading `config_key` segment from all `schema.*` paths in `validate_schema`
|
|
299
|
+
- [ ] Replace `I18nJS.plugins` with the return value of `initialize_plugins!`
|