glotfox 0.0.0-stage → 0.1.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.
- package/README.md +128 -2
- package/dist/_shared/formats.d.ts +18 -0
- package/dist/check.d.ts +23 -0
- package/dist/chunk-AQOIF7AF.js +1286 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +137 -0
- package/dist/config.d.ts +25 -0
- package/dist/extract.d.ts +45 -0
- package/dist/glob.d.ts +5 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +24 -0
- package/dist/init.d.ts +8 -0
- package/dist/scan.d.ts +18 -0
- package/dist/sync.d.ts +37 -0
- package/dist/types.d.ts +21 -0
- package/package.json +31 -3
package/README.md
CHANGED
|
@@ -1,3 +1,129 @@
|
|
|
1
|
-
#
|
|
1
|
+
# glotfox
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Command-line tool for [GlotFox](https://glotfox.app.dukauskas.lt). It extracts translation keys from React, Next.js and vanilla JS/TS projects into the source-locale files.
|
|
4
|
+
|
|
5
|
+
Requires Node 22+.
|
|
6
|
+
|
|
7
|
+
```sh
|
|
8
|
+
npx glotfox init --source en --targets de,fr
|
|
9
|
+
npx glotfox extract
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
## Commands
|
|
13
|
+
|
|
14
|
+
### `glotfox init`
|
|
15
|
+
|
|
16
|
+
Writes `glotfox.config.json` in the current directory. It refuses to overwrite an existing file unless you pass `--force`.
|
|
17
|
+
|
|
18
|
+
| Option | Description |
|
|
19
|
+
|--------|-------------|
|
|
20
|
+
| `--source <locale>` | Source locale (default `en`). |
|
|
21
|
+
| `--targets <a,b,...>` | Comma-separated target locales (default: none). |
|
|
22
|
+
| `--force` | Overwrite an existing config. |
|
|
23
|
+
|
|
24
|
+
`include` is set to the `src`, `app`, `pages` and `components` folders that exist (falling back to `src`).
|
|
25
|
+
|
|
26
|
+
### `glotfox extract`
|
|
27
|
+
|
|
28
|
+
Scans the files matched by `include`/`exclude` and writes the keys it finds into `<output.dir>/<sourceLocale>/<namespace>.json`.
|
|
29
|
+
|
|
30
|
+
| Option | Description |
|
|
31
|
+
|--------|-------------|
|
|
32
|
+
| `--dry-run` | Report what would change without writing files. |
|
|
33
|
+
| `--force` | Overwrite descriptions that already exist in `*.meta.json`. |
|
|
34
|
+
|
|
35
|
+
Behavior:
|
|
36
|
+
|
|
37
|
+
- **Never deletes.** Existing keys and values (including hand-edited source text and all target-locale translations) are kept as they are. New keys are added and files are written with sorted keys.
|
|
38
|
+
- **Reports unused keys.** Keys that are in the source locale but no longer found in code are listed; they stay in the file.
|
|
39
|
+
- Creates missing target-locale files for each namespace. With `output.emptyValues: "empty"`, missing keys are added as `""`; the default `"omit"` leaves them out.
|
|
40
|
+
- Keys that are invalid (see the file format spec) or that conflict with an existing key (one being a prefix of the other) are skipped with a warning.
|
|
41
|
+
|
|
42
|
+
### `glotfox push` / `glotfox pull`
|
|
43
|
+
|
|
44
|
+
Sync with the GlotFox service using a project API key (create one in the dashboard):
|
|
45
|
+
|
|
46
|
+
```sh
|
|
47
|
+
export GLOTFOX_API_KEY=gf_...
|
|
48
|
+
npx glotfox extract
|
|
49
|
+
npx glotfox push # upload source keys and descriptions
|
|
50
|
+
npx glotfox pull # write approved translations into the locale files
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
| Option | Description |
|
|
54
|
+
|--------|-------------|
|
|
55
|
+
| `--api-url <url>` | Server URL (default `$GLOTFOX_API_URL`, then `https://glotfox.app.dukauskas.lt`). |
|
|
56
|
+
| `--dry-run` | Report what would happen without uploading (`push`) or writing files (`pull`). |
|
|
57
|
+
|
|
58
|
+
- `push` sends every key of the source-locale files as `namespace:key` with its text and its `*.meta.json` description. It never deletes keys on the server.
|
|
59
|
+
- `pull` fetches the **approved** translations of each `targetLocales` entry and merges them into `<output.dir>/<locale>/<namespace>.json` (sorted keys). Approved text wins; other local keys are left alone.
|
|
60
|
+
|
|
61
|
+
### `glotfox check`
|
|
62
|
+
|
|
63
|
+
Read-only check for CI (see `packages/action`). Exits with 1 if code uses keys that are not in the source-locale files (run `extract`) or if the generated types file (`output.types`) is missing or out of date. Writes nothing.
|
|
64
|
+
|
|
65
|
+
It also runs the translation QA checks (`@glotfox/shared/qa`) on every non-empty target-locale message: `icu-invalid` is an error and fails the check; other findings (missing/extra placeholders, plural categories, whitespace, punctuation, numbers, untranslated) are listed as warnings. `--strict` turns warnings into failures.
|
|
66
|
+
|
|
67
|
+
### `glotfox types`
|
|
68
|
+
|
|
69
|
+
Generates a TypeScript declaration file from the source-locale files, so unknown keys and missing or mistyped ICU placeholders become compile errors. The file path comes from `output.types` in the config (e.g. `"types": "src/glotfox.d.ts"`); `extract` runs the same step at the end when `output.types` is set.
|
|
70
|
+
|
|
71
|
+
| Option | Description |
|
|
72
|
+
|--------|-------------|
|
|
73
|
+
| `--out <file>` | Output file, relative to the config directory (overrides `output.types`). |
|
|
74
|
+
| `--dry-run` | Report whether the file would change without writing it. |
|
|
75
|
+
|
|
76
|
+
Placeholder types follow the file format spec: `{x}` → `string | number`, `number`/`plural`/`selectordinal` → `number`, `date`/`time` → `Date | number`, `select` → its branch names (`'a' | 'b' | (string & {})`), and `<tag>` → `(chunks) => unknown`. Messages that fail to parse produce a warning and untyped placeholders.
|
|
77
|
+
|
|
78
|
+
The generated file exports `TFunction`, `TranslationKey` and `GlotfoxMessages`. Keys are available as `namespace:key`, and as plain `key` for the default namespace. Use `TFunction` to type your translate function:
|
|
79
|
+
|
|
80
|
+
```ts
|
|
81
|
+
import type { TFunction } from "./glotfox"; // src/glotfox.d.ts
|
|
82
|
+
|
|
83
|
+
declare const t: TFunction;
|
|
84
|
+
|
|
85
|
+
t("greeting", { name: "Ada" }); // "greeting": "Hello, {name}!"
|
|
86
|
+
t("greeting"); // error: missing placeholder "name"
|
|
87
|
+
t("missing.key"); // error: unknown key
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
With i18next/react-i18next, wrap your `t` once: `const typedT = t as unknown as TFunction`. Re-run `glotfox types` (or `extract`) after changing the source-locale files.
|
|
91
|
+
|
|
92
|
+
## What is detected
|
|
93
|
+
|
|
94
|
+
| Pattern | Notes |
|
|
95
|
+
|---------|-------|
|
|
96
|
+
| `t('key')`, `i18n.t('key')`, `` t(`key`) `` | String literals only; dynamic keys (`t(variable)`) are ignored. |
|
|
97
|
+
| `t('key', 'Default text')` | Default text becomes the source string. |
|
|
98
|
+
| `t('key', { defaultValue: '...', description: '...', ns: '...' })` | `description` is written to `<namespace>.meta.json`. |
|
|
99
|
+
| `<Trans i18nKey="key" defaults="..." ns="..." />` | Default text from `defaults`, or from plain-text children. |
|
|
100
|
+
| `useTranslation('ns')` / `useTranslation(['ns', ...])` | The first namespace is the default for `t` and `<Trans>` in that file. |
|
|
101
|
+
| `t('ns:key')` | Explicit namespace prefix. |
|
|
102
|
+
|
|
103
|
+
Without a default text, a new key's value is set to the key itself and a warning is printed. Keys without a namespace go to `defaultNamespace` (default `common`).
|
|
104
|
+
|
|
105
|
+
## Config
|
|
106
|
+
|
|
107
|
+
See `glotfox.config.json` in the translation file format spec. Example:
|
|
108
|
+
|
|
109
|
+
```json
|
|
110
|
+
{
|
|
111
|
+
"version": 1,
|
|
112
|
+
"sourceLocale": "en",
|
|
113
|
+
"targetLocales": ["de", "fr"],
|
|
114
|
+
"defaultNamespace": "common",
|
|
115
|
+
"include": ["src/**/*.{ts,tsx,js,jsx,mjs,cjs}"],
|
|
116
|
+
"exclude": ["**/*.test.*", "**/node_modules/**"],
|
|
117
|
+
"output": { "dir": "locales", "pattern": "{locale}/{namespace}.json", "emptyValues": "omit" }
|
|
118
|
+
}
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
Unknown fields are rejected. `output.format` is `"json"` (default), `"po"` or `"yaml"`; use a matching `output.pattern` (e.g. `{locale}/{namespace}.po`). Descriptions always stay in `<namespace>.meta.json`.
|
|
122
|
+
|
|
123
|
+
## Development
|
|
124
|
+
|
|
125
|
+
```sh
|
|
126
|
+
pnpm install
|
|
127
|
+
pnpm --filter glotfox test
|
|
128
|
+
pnpm --filter glotfox build
|
|
129
|
+
```
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Translation file formats (docs/file-format.html): JSON, gettext PO and YAML.
|
|
3
|
+
* Every format maps to the same model: a flat `key -> ICU message` object where keys may contain dots.
|
|
4
|
+
* Dependency-free and self-contained so the CLI, worker and web app can share it.
|
|
5
|
+
*/
|
|
6
|
+
export declare const FILE_FORMATS: readonly ["json", "po", "yaml"];
|
|
7
|
+
export type FileFormat = (typeof FILE_FORMATS)[number];
|
|
8
|
+
export type Messages = Record<string, string>;
|
|
9
|
+
export declare const isFileFormat: (v: unknown) => v is FileFormat;
|
|
10
|
+
export declare const FORMAT_EXTENSION: Record<FileFormat, string>;
|
|
11
|
+
export declare const defaultPattern: (format: FileFormat) => string;
|
|
12
|
+
export interface SerializeOptions {
|
|
13
|
+
/** Written to the PO header (`Language:`). */
|
|
14
|
+
locale?: string;
|
|
15
|
+
}
|
|
16
|
+
export declare function parseMessages(format: FileFormat, text: string): Messages;
|
|
17
|
+
/** Keys sorted, always ending with a newline. */
|
|
18
|
+
export declare function serializeMessages(format: FileFormat, messages: Messages, opts?: SerializeOptions): string;
|
package/dist/check.d.ts
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { type Issue } from "@glotfox/shared/qa";
|
|
2
|
+
export interface CheckResult {
|
|
3
|
+
/** "ns:key" found in code but missing from the source-locale files (run `glotfox extract`). */
|
|
4
|
+
missing: string[];
|
|
5
|
+
/** The generated types file is missing or out of date (run `glotfox types`). */
|
|
6
|
+
typesStale: boolean;
|
|
7
|
+
typesFile?: string;
|
|
8
|
+
warnings: string[];
|
|
9
|
+
/** QA findings for non-empty target translations (see `@glotfox/shared/qa`). */
|
|
10
|
+
issues: QaFinding[];
|
|
11
|
+
ok: boolean;
|
|
12
|
+
}
|
|
13
|
+
export interface QaFinding {
|
|
14
|
+
locale: string;
|
|
15
|
+
/** "ns:key" */
|
|
16
|
+
key: string;
|
|
17
|
+
issue: Issue;
|
|
18
|
+
}
|
|
19
|
+
/** Read-only verification used in CI: nothing is written. `strict` makes QA warnings fail the check. */
|
|
20
|
+
export declare function check(opts: {
|
|
21
|
+
cwd: string;
|
|
22
|
+
strict?: boolean;
|
|
23
|
+
}): CheckResult;
|