@chesterbrains/translify-cli 0.4.0 → 0.4.2
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.
- package/README.md +59 -4
- package/dist/http.js +1 -1
- package/dist/version.js +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -9,6 +9,8 @@ The CLI reads a `translify.json` that maps your translation files (i18next JSON,
|
|
|
9
9
|
- `status` to fail CI when local files differ from Translify,
|
|
10
10
|
- `publish` an environment.
|
|
11
11
|
|
|
12
|
+
Complete example apps — React + i18next at runtime, Flutter (ARB) and Angular (XLIFF) at build time — live in [translify-examples](https://github.com/chesterbrains/translify-examples).
|
|
13
|
+
|
|
12
14
|
## Install
|
|
13
15
|
|
|
14
16
|
### Standalone binary (no Node needed)
|
|
@@ -77,9 +79,7 @@ npx translify pull
|
|
|
77
79
|
}
|
|
78
80
|
```
|
|
79
81
|
|
|
80
|
-
|
|
81
|
-
- `format` is `json`, `xliff` or `arb`. JSON also takes `"jsonStyle": "nested"` (default) or `"flat"`.
|
|
82
|
-
- `locales` maps a locale name on disk to the Translify locale code, for example `{ "en_US": "en-US" }`. Omit it when the names already match.
|
|
82
|
+
Every field is described in the [`translify.json` reference](#translifyjson-reference).
|
|
83
83
|
|
|
84
84
|
## Quickstart: Flutter
|
|
85
85
|
|
|
@@ -117,6 +117,26 @@ flutter gen-l10n
|
|
|
117
117
|
|
|
118
118
|
`"@@locale"` is optional in ARB files: when it is absent, the file's locale is used. When it is present it must match the file's locale (case and `_`/`-` are ignored). On `pull`, the CLI writes `@@locale` using the locale name on disk (for example `en_US` in `app_en_US.arb`), as `flutter gen-l10n` expects.
|
|
119
119
|
|
|
120
|
+
## `translify.json` reference
|
|
121
|
+
|
|
122
|
+
`translify.json` lives in the repository root; every command reads it from the current directory. The
|
|
123
|
+
[JSON schema](schema/translify.schema.json) gives editors completion and validation through `$schema`. Unknown
|
|
124
|
+
fields are refused, and so is any field whose name contains `key`, `secret` or `token`: keys never go in this file.
|
|
125
|
+
|
|
126
|
+
| Field | Type | Required | Description |
|
|
127
|
+
|---|---|---|---|
|
|
128
|
+
| `$schema` | string | no | Schema URL for editor support. Ignored by the CLI. |
|
|
129
|
+
| `apiUrl` | URL | yes | The Translify API base, ending in `/api`, e.g. `https://translify.tommasofeltrin.work/api`. |
|
|
130
|
+
| `files` | array | yes | One rule per kind of translation file. Each rule has the fields below. |
|
|
131
|
+
| `files[].pattern` | string | yes | Path relative to `translify.json`, with `/` separators. Must contain `{locale}` once and may contain `{namespace}` once, e.g. `locales/{locale}/{namespace}.json`. |
|
|
132
|
+
| `files[].format` | `json` \| `xliff` \| `arb` | yes | File format: i18next JSON, XLIFF or Flutter ARB. |
|
|
133
|
+
| `files[].namespace` | string | when the pattern has no `{namespace}`, and always for `arb` | Fixed namespace for every file the rule matches. Lowercase kebab-case, at most 64 characters. |
|
|
134
|
+
| `files[].jsonStyle` | `nested` \| `flat` | no | Only for `json`. `nested` (the default) writes `{ "a": { "b": "…" } }`, `flat` writes `{ "a.b": "…" }`. |
|
|
135
|
+
| `locales` | object | no | Maps a locale name on disk to a Translify locale code, e.g. `{ "en_US": "en-US" }`. Unmapped names pass through unchanged. Two names may not map to the same code, and a target may not itself be a mapped name. |
|
|
136
|
+
|
|
137
|
+
Each file must be matched by one rule only, and each (locale, namespace) pair must come from one file only;
|
|
138
|
+
otherwise the CLI stops before sending anything and names the files involved.
|
|
139
|
+
|
|
120
140
|
## Commands
|
|
121
141
|
|
|
122
142
|
| Command | What it does |
|
|
@@ -145,10 +165,44 @@ Options:
|
|
|
145
165
|
- **Source locale: your files win.** Existing source translations are overwritten with what is in the file.
|
|
146
166
|
- **Target locales: Translify fills only the gaps.** Keys that already have a translation are left alone and counted as skipped.
|
|
147
167
|
- `--overwrite-targets` also overwrites existing target translations.
|
|
148
|
-
- `--prune` deletes keys that no longer exist in your source files, together with their translations.
|
|
168
|
+
- `--prune` deletes keys that no longer exist in your source files, together with their translations. See [Prune safety](#prune-safety).
|
|
149
169
|
- `--yes` skips the confirmation prompt for the two destructive flags. Without a terminal and without `--yes`, a destructive push is refused and nothing changes.
|
|
150
170
|
- `--dry-run` shows the effect of any combination and writes nothing.
|
|
151
171
|
|
|
172
|
+
## Prune safety
|
|
173
|
+
|
|
174
|
+
`translify push --prune` is the only command that deletes keys. What it deletes, and what stops it:
|
|
175
|
+
|
|
176
|
+
- **Only the namespaces in this push.** A key is an orphan when its namespace is in the push and its source file no
|
|
177
|
+
longer has it. Namespaces you did not push (another rule, another repository, `--namespace` left them out) are never
|
|
178
|
+
touched.
|
|
179
|
+
- **Never published keys.** A key published to any environment is listed as kept and survives. Unpublish it in
|
|
180
|
+
Translify first if it really should go.
|
|
181
|
+
- **Never a whole namespace by accident.** If a source file in the push has no entries, the push is refused
|
|
182
|
+
(`VALIDATION_FAILED` with `emptySourcePrune`) instead of deleting every key in that namespace. Emptying a namespace
|
|
183
|
+
is done in the Translify web app.
|
|
184
|
+
- **Exactly the list you confirmed.** The CLI always runs a dry run first, shows the keys it would delete and asks
|
|
185
|
+
for confirmation. The real push sends a digest of that list; if the server's list differs by then (keys added,
|
|
186
|
+
removed or published in between), it refuses with `ORPHANS_CHANGED` and writes nothing. A server too old to return
|
|
187
|
+
the digest makes `--prune` refuse.
|
|
188
|
+
- **No silent prune in CI.** Without a terminal, `--prune` is refused unless you pass `--yes`.
|
|
189
|
+
- **Atomic.** The whole push, deletions included, is one transaction: if anything fails, nothing is written.
|
|
190
|
+
|
|
191
|
+
`--yes` confirms whatever that run's dry run lists, so in CI review the list before it runs unattended. One way:
|
|
192
|
+
show the orphans on pull requests and prune on `main`.
|
|
193
|
+
|
|
194
|
+
```yaml
|
|
195
|
+
# on pull_request: list what a prune would delete, change nothing
|
|
196
|
+
- run: npx translify push --prune --dry-run
|
|
197
|
+
env:
|
|
198
|
+
TRANSLIFY_SECRET_KEY: ${{ secrets.TRANSLIFY_SECRET_KEY }}
|
|
199
|
+
|
|
200
|
+
# on push to main: prune for real
|
|
201
|
+
- run: npx translify push --prune --yes
|
|
202
|
+
env:
|
|
203
|
+
TRANSLIFY_SECRET_KEY: ${{ secrets.TRANSLIFY_SECRET_KEY }}
|
|
204
|
+
```
|
|
205
|
+
|
|
152
206
|
## Review
|
|
153
207
|
|
|
154
208
|
When the project has **Require review** turned on in Translify:
|
|
@@ -262,6 +316,7 @@ The server's error `code` decides the exit code first; the HTTP status is only u
|
|
|
262
316
|
| `ORPHANS_CHANGED` | 1 | The orphan list changed between the dry run and the real push (keys were added, removed or published). Nothing was written; run `translify push --prune` again to review the new list. |
|
|
263
317
|
| `REVIEW_DISABLED` | 1 | `push --status draft` or `--status needs-review` on a project without review. Turn on **Require review** in the project settings, or drop `--status`. Nothing was written. |
|
|
264
318
|
| `APPROVED_ONLY_REQUIRES_WORKING` | 1 | `--only-approved` was combined with `--from env:<slug>`. Pull an environment without it; it already holds only what its gate allowed. |
|
|
319
|
+
| `INVALID_CELLS` | 6 | `publish` refused: translations that would go live have placeholder errors. Nothing was published; the output lists them like `lint` does. Fix them in Translify, or re-run with `--allow-errors` to publish anyway (recorded in the activity log). |
|
|
265
320
|
| `TRANSACTION_CONFLICT` | 4 | Another write collided with yours. Retry. |
|
|
266
321
|
| `RATE_LIMITED` | 4 | The CLI already retried 3 times, honouring `Retry-After`. Wait a moment and retry. |
|
|
267
322
|
| `INTERNAL_ERROR` / `DATABASE_ERROR` / 5xx | 4 | A server problem. Retry shortly; if it persists, re-run with `--debug` and report it. |
|
package/dist/http.js
CHANGED
|
@@ -8,7 +8,7 @@ const REQUEST_TIMEOUT_MS = 180_000;
|
|
|
8
8
|
const UPGRADE = 'npm i -g @chesterbrains/translify-cli@latest, or for the standalone binary: curl -fsSL https://github.com/chesterbrains/translify-cli/releases/latest/download/install.sh | sh';
|
|
9
9
|
const sleep = async (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
10
10
|
/** Exit code by the body's `code` first; the status only decides for a code we do not know. */
|
|
11
|
-
const CODE_EXIT = {
|
|
11
|
+
export const CODE_EXIT = {
|
|
12
12
|
VALIDATION_FAILED: EXIT.failed,
|
|
13
13
|
LOCALE_NOT_FOUND: EXIT.failed,
|
|
14
14
|
NAMESPACE_NOT_FOUND: EXIT.failed,
|
package/dist/version.js
CHANGED