@seliseblocks/cli-os 0.2.1 → 0.2.3
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/AI_USAGE_GUIDE.md +551 -546
- package/LICENSE +21 -21
- package/README.md +171 -171
- package/bin/run.js +2 -2
- package/dist/commands/data/files/delete.js +5 -4
- package/dist/commands/data/files/get-many.js +1 -1
- package/dist/commands/data/files/get.js +1 -1
- package/dist/commands/data/files/info.js +1 -1
- package/dist/commands/data/files/object-tree.d.ts +23 -0
- package/dist/commands/data/files/object-tree.js +238 -0
- package/dist/commands/data/files/presigned-upload-url.js +9 -2
- package/dist/commands/data/files/update-additional-info.js +2 -2
- package/dist/commands/data/files/upload-to-local-storage.js +2 -2
- package/dist/commands/data/files/upload.d.ts +2 -4
- package/dist/commands/data/files/upload.js +14 -28
- package/dist/index.js +685 -647
- package/dist/lib/scaffold-web/root-files.js +158 -0
- package/dist/skills/blocks-data-gateway-configuration/SKILL.md +204 -204
- package/dist/skills/blocks-data-gateway-crud/SKILL.md +223 -223
- package/dist/skills/blocks-data-storage/SKILL.md +253 -161
- package/dist/skills/blocks-data-storage/flows/object-management.md +124 -0
- package/dist/skills/blocks-frontend-local-https/SKILL.md +100 -100
- package/dist/skills/blocks-iam-account/SKILL.md +169 -169
- package/dist/skills/blocks-iam-sso-oidc-implementation/SKILL.md +80 -80
- package/dist/skills/blocks-iam-users/SKILL.md +131 -131
- package/dist/skills/blocks-localization-configuration/SKILL.md +149 -149
- package/dist/skills/blocks-localization-implementation/SKILL.md +63 -63
- package/dist/skills/blocks-onboarding/SKILL.md +77 -77
- package/dist/skills/blocks-storage-configuration/SKILL.md +4 -4
- package/package.json +47 -47
- package/dist/commands/data/files/create-folder.d.ts +0 -1
- package/dist/commands/data/files/create-folder.js +0 -34
- package/dist/commands/data/files/delete-folder.d.ts +0 -1
- package/dist/commands/data/files/delete-folder.js +0 -25
- package/dist/commands/data/files/dms-list.d.ts +0 -1
- package/dist/commands/data/files/dms-list.js +0 -27
- package/dist/commands/data/files/dms-upload.d.ts +0 -6
- package/dist/commands/data/files/dms-upload.js +0 -41
|
@@ -1,149 +1,149 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: blocks-localization-configuration
|
|
3
|
-
description: "Configure app translations (i18n) for a SELISE Blocks project through the `blocks` CLI — never raw fetch/curl. Covers authoring local i18n JSON dictionaries, validate/push/pull with the Localization service, managing languages and modules directly, glossary terms, AI translation suggestions, and the composed translate-and-export flow. Use for 'add translations for my login screen', 'push/pull localization changes', 'create a module', 'add a new language'."
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# Blocks Localization — Configuration
|
|
7
|
-
|
|
8
|
-
Translations (i18n) for a Blocks project's static UI text — labels, titles, button copy — are authored locally as JSON and synced to the Localization service entirely through the `blocks` CLI. There is no supported reason to hand-roll raw `fetch`/`curl` calls anymore, and there's no SDK-based authoring path either — `@seliseblocks/client`'s localization surface (`languages()`, `modules()`, `languagesForCurrentTenant()`, `translations()`, `cloudTranslations()`, `keysByNames()`) is entirely **read-only**, meant for apps to *consume* translations at runtime, not to author them. Authoring is CLI-only.
|
|
9
|
-
|
|
10
|
-
**Prerequisite:** `blocks init` has been run and a project is selected (`blocks use <tenantId>`). Note `blocks init` does **not** create a `blocks/localization/` folder — it only scaffolds `blocks/data/schemas/`, `blocks/data/rules.json`, and `.env.example`. The `blocks/localization/` directory and its dictionary files come into existence lazily, the first time `blocks localization pull` writes one out (or the first time you author one by hand). If either the project selection is missing, or auth state is unknown, run the blocks-onboarding skill first — it covers `auth status` probing, login, and project selection in detail; this skill assumes that's already done.
|
|
11
|
-
|
|
12
|
-
## The three commands
|
|
13
|
-
|
|
14
|
-
| Command | What it does |
|
|
15
|
-
|---|---|
|
|
16
|
-
| `blocks localization validate --module <name> --language <culture> [--file <path>] [--json]` | Validates a local i18n JSON dictionary. **Local-only, no API call.** |
|
|
17
|
-
| `blocks localization push --module <name> --language <culture> [--file <path>] [--route <route>] [--context <text>] [--dry-run] [--yes] [--json]` | Creates/updates keys from the local dictionary. If the module doesn't exist yet, creates it first — **this is the only way this tooling creates a module.** Mutating. |
|
|
18
|
-
| `blocks localization pull --module <name> --language <culture> [--out <path>] [--json]` | Downloads the **published** cloud dictionary into a local JSON file. Read-only, overwrites the local file. |
|
|
19
|
-
|
|
20
|
-
`--module` is the feature-area bundle name (`common`, `login`, `dashboard`, …). `--language` is a culture code (`en`, `de-DE`, `bn-BD`, …) — see the culture-matching gotcha below before picking one.
|
|
21
|
-
|
|
22
|
-
## File convention
|
|
23
|
-
|
|
24
|
-
Local dictionaries default to:
|
|
25
|
-
|
|
26
|
-
```text
|
|
27
|
-
blocks/localization/<module>.<language>.json
|
|
28
|
-
```
|
|
29
|
-
|
|
30
|
-
for example `blocks/localization/login.de-DE.json`. Pass `--file`/`--out` to override the path. Content is a flat or nested JSON object of string values — nested objects are flattened with `.` before validation/push, so either of these is fine and produces the same keys:
|
|
31
|
-
|
|
32
|
-
```json
|
|
33
|
-
{ "login.title": "Anmelden", "login.submit": "Absenden" }
|
|
34
|
-
```
|
|
35
|
-
|
|
36
|
-
```json
|
|
37
|
-
{ "login": { "title": "Anmelden", "submit": "Absenden" } }
|
|
38
|
-
```
|
|
39
|
-
|
|
40
|
-
Key names must match `^[A-Za-z0-9][A-Za-z0-9._:-]*$` (letters, numbers, dot, dash, underscore, colon — no spaces) after flattening, and every value must be a non-empty string. `localization validate` enforces exactly this, locally, before anything touches the network.
|
|
41
|
-
|
|
42
|
-
## Workflow: add or update translations
|
|
43
|
-
|
|
44
|
-
1. **Generate or edit the local dictionary** at `blocks/localization/<module>.<language>.json` — write the JSON yourself (nested or flat), covering every key the screen/feature needs.
|
|
45
|
-
2. **Validate locally, no API call:**
|
|
46
|
-
```bash
|
|
47
|
-
blocks localization validate --module login --language de-DE --json
|
|
48
|
-
```
|
|
49
|
-
Fix every flagged key/value before moving on.
|
|
50
|
-
3. **Dry-run the push** to see exactly what would happen (module create-or-reuse, key count, target project):
|
|
51
|
-
```bash
|
|
52
|
-
blocks localization push --module login --language de-DE --dry-run --json
|
|
53
|
-
```
|
|
54
|
-
4. **Get user approval, then push for real:**
|
|
55
|
-
```bash
|
|
56
|
-
blocks localization push --module login --language de-DE --yes --json
|
|
57
|
-
```
|
|
58
|
-
This is mutating. Never skip straight to `--yes`. Every key in the file is saved as immediately published, so a successful push is live for reads right away — there is no separate "generate/publish" step in this CLI.
|
|
59
|
-
|
|
60
|
-
Optional flags on `push`: `--route <route>` tags every key in this push with one route (e.g. the screen path the strings belong to); `--context <text>` attaches one context/hint string to every key in the push — both apply to the whole file, not per-key.
|
|
61
|
-
|
|
62
|
-
## Workflow: multiple languages for the same screen
|
|
63
|
-
|
|
64
|
-
Each `push` call carries exactly one `--language` (one culture stamped onto every key in that file). Translating one module into several languages means **one dictionary file and one push per language**, all against the same `--module`:
|
|
65
|
-
|
|
66
|
-
```bash
|
|
67
|
-
blocks localization validate --module login --language de-DE --json
|
|
68
|
-
blocks localization validate --module login --language bn-BD --json
|
|
69
|
-
blocks localization push --module login --language de-DE --dry-run --json
|
|
70
|
-
blocks localization push --module login --language bn-BD --dry-run --json
|
|
71
|
-
# after approval:
|
|
72
|
-
blocks localization push --module login --language de-DE --yes --json
|
|
73
|
-
blocks localization push --module login --language bn-BD --yes --json
|
|
74
|
-
```
|
|
75
|
-
|
|
76
|
-
The module (`login`) is only created on the *first* push that needs it; the second push reuses the module the first one created.
|
|
77
|
-
|
|
78
|
-
## Refreshing local files from the cloud
|
|
79
|
-
|
|
80
|
-
```bash
|
|
81
|
-
blocks localization pull --module login --language de-DE --out blocks/localization/login.de-DE.json --json
|
|
82
|
-
```
|
|
83
|
-
|
|
84
|
-
Use this to pull down what's actually published before editing further — same reasoning as pulling data schemas before editing them: don't blindly overwrite translations someone else edited in the portal or in a prior session.
|
|
85
|
-
|
|
86
|
-
## Managing languages directly
|
|
87
|
-
|
|
88
|
-
Pushing translations into an existing language and *configuring the tenant's set of languages* are different operations — the latter has its own standalone commands, independent of `push`/`pull`:
|
|
89
|
-
|
|
90
|
-
| Command | What it does |
|
|
91
|
-
|---|---|
|
|
92
|
-
| `blocks localization language save --language-name <n> --language-code <c> [--is-default] [--item-id <id>] [--dry-run] [--yes] [--json]` | Creates or updates a language. Omit `--item-id` to create a new one. Mutating, full dry-run/confirm gate. |
|
|
93
|
-
| `blocks localization language delete <languageName> [--dry-run] [--yes] [--json]` | Deletes a language. Mutating. |
|
|
94
|
-
| `blocks localization language set-default <languageName> [--dry-run] [--yes] [--json]` | Marks a language as the tenant default. Mutating. |
|
|
95
|
-
| `blocks localization language list [--json]` | Lists all languages. Read-only. |
|
|
96
|
-
| `blocks localization language list-for-tenant [--json]` | Lists languages configured for the current tenant. Read-only. |
|
|
97
|
-
|
|
98
|
-
So "add German as a supported language for the tenant" is a real, supported request: `blocks localization language save --language-name German --language-code de-DE --dry-run`, get approval, then re-run with `--yes`. This is distinct from `localization push --language de-DE`, which stamps translations onto keys and doesn't touch the tenant's language configuration at all.
|
|
99
|
-
|
|
100
|
-
## Managing modules directly
|
|
101
|
-
|
|
102
|
-
A module is still created implicitly by the first `localization push` into it, but it can also be created or updated on its own, with no keys, via a standalone command:
|
|
103
|
-
|
|
104
|
-
| Command | What it does |
|
|
105
|
-
|---|---|
|
|
106
|
-
| `blocks localization module save --module-name <n> [--item-id <id>] [--dry-run] [--yes] [--json]` | Creates or updates a module. Omit `--item-id` to create a new one. Mutating. |
|
|
107
|
-
| `blocks localization module list [--json]` | Lists all modules. Read-only. |
|
|
108
|
-
| `blocks localization module list-for-tenant [--json]` | Lists modules configured for the current tenant. Read-only. |
|
|
109
|
-
|
|
110
|
-
So "create a `billing` module with no keys yet" is directly supported: `blocks localization module save --module-name billing --dry-run` → approve → `--yes`. `localization push`'s implicit module creation is just a convenience on top of the same underlying call, not the only path to it.
|
|
111
|
-
|
|
112
|
-
## Other localization commands
|
|
113
|
-
|
|
114
|
-
A few more commands round out the surface beyond push/pull/validate/language/module — useful, but secondary to the core authoring workflow above:
|
|
115
|
-
|
|
116
|
-
| Command | What it does |
|
|
117
|
-
|---|---|
|
|
118
|
-
| `blocks localization key translate-and-export --module-id <id> [--wait] [--dry-run] [--yes] [--json]` | Composed flow: `translate-all` (machine-translates every untranslated key in the module) → if `--wait`, polls until the operation settles → `generate-uilm-file` → `uilm-export`. Without `--wait` the three steps just fire back-to-back. Mutating. |
|
|
119
|
-
| `blocks localization glossary save --name <n> [--item-id <id>] [--language <c>] [--type <t>] [--context <text>] [--additional-note <text>] [--is-global] [--module-ids a,b] [--dry-run] [--yes] [--json]` | Creates or updates a glossary term. Mutating. |
|
|
120
|
-
| `blocks localization glossary list [--search <text>] [--module-id <id>] [--is-global] [--page-number <n>] [--page-size <n>] [--json]` | Lists glossary terms. Read-only. |
|
|
121
|
-
| `blocks localization glossary get <itemId> [--json]` | Fetches one glossary term. Read-only. |
|
|
122
|
-
| `blocks localization glossary suggested <itemId> [--max-results <n>] [--json]` | Suggests glossary terms relevant to an item. Read-only. |
|
|
123
|
-
| `blocks localization glossary delete <itemId> [--dry-run] [--yes] [--json]` | Deletes a glossary term. Mutating. |
|
|
124
|
-
| `blocks localization assistant translation-suggestion --source-text <text> [--current-language <c>] [--destination-language <name>] [--destination-language-code <c>] [--module-id <id>] [--glossary-ids a,b] [--element-type <t>] [--element-application-context <text>] [--element-detail-context <text>] [--max-character-length <n>] [--temperature <n>] [--json]` | Gets an AI translation suggestion for a single string. Read-only (no confirm gate). |
|
|
125
|
-
| `blocks localization config get-webhook [--json]` | Gets the tenant's localization webhook config. Read-only. |
|
|
126
|
-
| `blocks localization config save-webhook --url <url> --content-type <type> --secret <s> --header-key <k> [--is-disabled] [--item-id <id>] [--dry-run] [--yes] [--json]` | Saves the tenant's localization webhook config. Mutating; the secret is redacted in `--dry-run` output. |
|
|
127
|
-
|
|
128
|
-
## Gotchas
|
|
129
|
-
|
|
130
|
-
- **`--dry-run` before `--yes`** on `localization push` — always. Same pattern as every other mutating `blocks` command.
|
|
131
|
-
- **`--language` on `push` is not validated against configured cultures.** `localization push` stamps whatever string you pass as `--language` directly into each key's `culture` field — it does not check that culture against the tenant's actual configured languages, and doesn't call `language list`/`list-for-tenant` to look. Get the culture code wrong (`de` instead of `de-DE`, or a culture the tenant never configured via `language save`) and the key saves without error but may never surface at runtime, because runtime lookups match by the tenant's real configured `languageCode`. Confirm the exact culture code with the user (or run `localization language list-for-tenant`) before pushing, especially for less common languages like Bengali (`bn-BD` vs `bn`).
|
|
132
|
-
- **Module auto-create is silent and permanent.** The first push against a new `--module` name creates it with no separate confirmation prompt beyond the push's own `--dry-run`/`--yes` gate — `--dry-run` output will tell you a module lookup happened, but won't distinguish "will create" from "already exists" as clearly as it could, so read the dry-run JSON's module info carefully, or ask the user to confirm the module name is intentional (typos become new, mostly-empty modules). Prefer `localization module save` first if the user wants the module created deliberately, without an accompanying key push.
|
|
133
|
-
- **`localization validate` is local-only** — it confirms the JSON is well-formed and keys/values pass the naming rules; it does not confirm the push will succeed against the server (module resolution, auth, project selection). Still run `--dry-run` on the actual push.
|
|
134
|
-
- **One culture per file/push.** Don't try to cram multiple languages into one dictionary file — the format is flat key → string value, not key → {culture: value}. Multiple languages means multiple files and multiple push invocations (see above).
|
|
135
|
-
- **No standalone "generate" or "publish" step for `push`.** `shouldPublish: true` is baked into every key `localization push` sends — once the push succeeds, the translations are live. That's separate from `key generate-uilm-file`/`key uilm-export` (and the composed `key translate-and-export`), which build downloadable runtime language files rather than affect `push`'s own publish behavior.
|
|
136
|
-
- **`language delete` and `set-default` are permanent, mutating calls** — always dry-run first, and confirm with the user before deleting a language or changing the tenant default, since either can affect what's visible at runtime for existing translations.
|
|
137
|
-
|
|
138
|
-
## Example trigger prompts
|
|
139
|
-
|
|
140
|
-
- "Add German translations for my login screen." → push `login.de-DE.json` after validate + dry-run + approval.
|
|
141
|
-
- "Add German and Bengali translations for my login screen." → two dictionary files, two validate/push pairs (`de-DE`, `bn-BD`), same module.
|
|
142
|
-
- "Set up a `common` module for shared strings like Save/Cancel/Delete." → write `common.<language>.json` with those keys, validate, push (this is what creates the `common` module) — or use `localization module save --module-name common` directly if no keys exist yet.
|
|
143
|
-
- "Pull the latest translations for the dashboard module before I edit them." → `localization pull --module dashboard --language en`.
|
|
144
|
-
- "Validate my localization file before pushing." → `localization validate` only, no network call.
|
|
145
|
-
- "Can we add Bengali as a new supported language for the tenant?" → `localization language save --language-name Bengali --language-code bn-BD --dry-run`, confirm, then `--yes`.
|
|
146
|
-
- "Create a new translation module called `billing` with no keys yet." → `localization module save --module-name billing --dry-run` → confirm → `--yes`.
|
|
147
|
-
- "Machine-translate the whole `login` module and give me the export." → `localization key translate-and-export --module-id <id> --wait --dry-run` → confirm → `--yes`.
|
|
148
|
-
- "Suggest a translation for this button label." → `localization assistant translation-suggestion --source-text "Save changes" --destination-language-code de-DE`.
|
|
149
|
-
- "What's our webhook config for localization events?" → `localization config get-webhook`.
|
|
1
|
+
---
|
|
2
|
+
name: blocks-localization-configuration
|
|
3
|
+
description: "Configure app translations (i18n) for a SELISE Blocks project through the `blocks` CLI — never raw fetch/curl. Covers authoring local i18n JSON dictionaries, validate/push/pull with the Localization service, managing languages and modules directly, glossary terms, AI translation suggestions, and the composed translate-and-export flow. Use for 'add translations for my login screen', 'push/pull localization changes', 'create a module', 'add a new language'."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Blocks Localization — Configuration
|
|
7
|
+
|
|
8
|
+
Translations (i18n) for a Blocks project's static UI text — labels, titles, button copy — are authored locally as JSON and synced to the Localization service entirely through the `blocks` CLI. There is no supported reason to hand-roll raw `fetch`/`curl` calls anymore, and there's no SDK-based authoring path either — `@seliseblocks/client`'s localization surface (`languages()`, `modules()`, `languagesForCurrentTenant()`, `translations()`, `cloudTranslations()`, `keysByNames()`) is entirely **read-only**, meant for apps to *consume* translations at runtime, not to author them. Authoring is CLI-only.
|
|
9
|
+
|
|
10
|
+
**Prerequisite:** `blocks init` has been run and a project is selected (`blocks use <tenantId>`). Note `blocks init` does **not** create a `blocks/localization/` folder — it only scaffolds `blocks/data/schemas/`, `blocks/data/rules.json`, and `.env.example`. The `blocks/localization/` directory and its dictionary files come into existence lazily, the first time `blocks localization pull` writes one out (or the first time you author one by hand). If either the project selection is missing, or auth state is unknown, run the blocks-onboarding skill first — it covers `auth status` probing, login, and project selection in detail; this skill assumes that's already done.
|
|
11
|
+
|
|
12
|
+
## The three commands
|
|
13
|
+
|
|
14
|
+
| Command | What it does |
|
|
15
|
+
|---|---|
|
|
16
|
+
| `blocks localization validate --module <name> --language <culture> [--file <path>] [--json]` | Validates a local i18n JSON dictionary. **Local-only, no API call.** |
|
|
17
|
+
| `blocks localization push --module <name> --language <culture> [--file <path>] [--route <route>] [--context <text>] [--dry-run] [--yes] [--json]` | Creates/updates keys from the local dictionary. If the module doesn't exist yet, creates it first — **this is the only way this tooling creates a module.** Mutating. |
|
|
18
|
+
| `blocks localization pull --module <name> --language <culture> [--out <path>] [--json]` | Downloads the **published** cloud dictionary into a local JSON file. Read-only, overwrites the local file. |
|
|
19
|
+
|
|
20
|
+
`--module` is the feature-area bundle name (`common`, `login`, `dashboard`, …). `--language` is a culture code (`en`, `de-DE`, `bn-BD`, …) — see the culture-matching gotcha below before picking one.
|
|
21
|
+
|
|
22
|
+
## File convention
|
|
23
|
+
|
|
24
|
+
Local dictionaries default to:
|
|
25
|
+
|
|
26
|
+
```text
|
|
27
|
+
blocks/localization/<module>.<language>.json
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
for example `blocks/localization/login.de-DE.json`. Pass `--file`/`--out` to override the path. Content is a flat or nested JSON object of string values — nested objects are flattened with `.` before validation/push, so either of these is fine and produces the same keys:
|
|
31
|
+
|
|
32
|
+
```json
|
|
33
|
+
{ "login.title": "Anmelden", "login.submit": "Absenden" }
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
```json
|
|
37
|
+
{ "login": { "title": "Anmelden", "submit": "Absenden" } }
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Key names must match `^[A-Za-z0-9][A-Za-z0-9._:-]*$` (letters, numbers, dot, dash, underscore, colon — no spaces) after flattening, and every value must be a non-empty string. `localization validate` enforces exactly this, locally, before anything touches the network.
|
|
41
|
+
|
|
42
|
+
## Workflow: add or update translations
|
|
43
|
+
|
|
44
|
+
1. **Generate or edit the local dictionary** at `blocks/localization/<module>.<language>.json` — write the JSON yourself (nested or flat), covering every key the screen/feature needs.
|
|
45
|
+
2. **Validate locally, no API call:**
|
|
46
|
+
```bash
|
|
47
|
+
blocks localization validate --module login --language de-DE --json
|
|
48
|
+
```
|
|
49
|
+
Fix every flagged key/value before moving on.
|
|
50
|
+
3. **Dry-run the push** to see exactly what would happen (module create-or-reuse, key count, target project):
|
|
51
|
+
```bash
|
|
52
|
+
blocks localization push --module login --language de-DE --dry-run --json
|
|
53
|
+
```
|
|
54
|
+
4. **Get user approval, then push for real:**
|
|
55
|
+
```bash
|
|
56
|
+
blocks localization push --module login --language de-DE --yes --json
|
|
57
|
+
```
|
|
58
|
+
This is mutating. Never skip straight to `--yes`. Every key in the file is saved as immediately published, so a successful push is live for reads right away — there is no separate "generate/publish" step in this CLI.
|
|
59
|
+
|
|
60
|
+
Optional flags on `push`: `--route <route>` tags every key in this push with one route (e.g. the screen path the strings belong to); `--context <text>` attaches one context/hint string to every key in the push — both apply to the whole file, not per-key.
|
|
61
|
+
|
|
62
|
+
## Workflow: multiple languages for the same screen
|
|
63
|
+
|
|
64
|
+
Each `push` call carries exactly one `--language` (one culture stamped onto every key in that file). Translating one module into several languages means **one dictionary file and one push per language**, all against the same `--module`:
|
|
65
|
+
|
|
66
|
+
```bash
|
|
67
|
+
blocks localization validate --module login --language de-DE --json
|
|
68
|
+
blocks localization validate --module login --language bn-BD --json
|
|
69
|
+
blocks localization push --module login --language de-DE --dry-run --json
|
|
70
|
+
blocks localization push --module login --language bn-BD --dry-run --json
|
|
71
|
+
# after approval:
|
|
72
|
+
blocks localization push --module login --language de-DE --yes --json
|
|
73
|
+
blocks localization push --module login --language bn-BD --yes --json
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
The module (`login`) is only created on the *first* push that needs it; the second push reuses the module the first one created.
|
|
77
|
+
|
|
78
|
+
## Refreshing local files from the cloud
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
blocks localization pull --module login --language de-DE --out blocks/localization/login.de-DE.json --json
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Use this to pull down what's actually published before editing further — same reasoning as pulling data schemas before editing them: don't blindly overwrite translations someone else edited in the portal or in a prior session.
|
|
85
|
+
|
|
86
|
+
## Managing languages directly
|
|
87
|
+
|
|
88
|
+
Pushing translations into an existing language and *configuring the tenant's set of languages* are different operations — the latter has its own standalone commands, independent of `push`/`pull`:
|
|
89
|
+
|
|
90
|
+
| Command | What it does |
|
|
91
|
+
|---|---|
|
|
92
|
+
| `blocks localization language save --language-name <n> --language-code <c> [--is-default] [--item-id <id>] [--dry-run] [--yes] [--json]` | Creates or updates a language. Omit `--item-id` to create a new one. Mutating, full dry-run/confirm gate. |
|
|
93
|
+
| `blocks localization language delete <languageName> [--dry-run] [--yes] [--json]` | Deletes a language. Mutating. |
|
|
94
|
+
| `blocks localization language set-default <languageName> [--dry-run] [--yes] [--json]` | Marks a language as the tenant default. Mutating. |
|
|
95
|
+
| `blocks localization language list [--json]` | Lists all languages. Read-only. |
|
|
96
|
+
| `blocks localization language list-for-tenant [--json]` | Lists languages configured for the current tenant. Read-only. |
|
|
97
|
+
|
|
98
|
+
So "add German as a supported language for the tenant" is a real, supported request: `blocks localization language save --language-name German --language-code de-DE --dry-run`, get approval, then re-run with `--yes`. This is distinct from `localization push --language de-DE`, which stamps translations onto keys and doesn't touch the tenant's language configuration at all.
|
|
99
|
+
|
|
100
|
+
## Managing modules directly
|
|
101
|
+
|
|
102
|
+
A module is still created implicitly by the first `localization push` into it, but it can also be created or updated on its own, with no keys, via a standalone command:
|
|
103
|
+
|
|
104
|
+
| Command | What it does |
|
|
105
|
+
|---|---|
|
|
106
|
+
| `blocks localization module save --module-name <n> [--item-id <id>] [--dry-run] [--yes] [--json]` | Creates or updates a module. Omit `--item-id` to create a new one. Mutating. |
|
|
107
|
+
| `blocks localization module list [--json]` | Lists all modules. Read-only. |
|
|
108
|
+
| `blocks localization module list-for-tenant [--json]` | Lists modules configured for the current tenant. Read-only. |
|
|
109
|
+
|
|
110
|
+
So "create a `billing` module with no keys yet" is directly supported: `blocks localization module save --module-name billing --dry-run` → approve → `--yes`. `localization push`'s implicit module creation is just a convenience on top of the same underlying call, not the only path to it.
|
|
111
|
+
|
|
112
|
+
## Other localization commands
|
|
113
|
+
|
|
114
|
+
A few more commands round out the surface beyond push/pull/validate/language/module — useful, but secondary to the core authoring workflow above:
|
|
115
|
+
|
|
116
|
+
| Command | What it does |
|
|
117
|
+
|---|---|
|
|
118
|
+
| `blocks localization key translate-and-export --module-id <id> [--wait] [--dry-run] [--yes] [--json]` | Composed flow: `translate-all` (machine-translates every untranslated key in the module) → if `--wait`, polls until the operation settles → `generate-uilm-file` → `uilm-export`. Without `--wait` the three steps just fire back-to-back. Mutating. |
|
|
119
|
+
| `blocks localization glossary save --name <n> [--item-id <id>] [--language <c>] [--type <t>] [--context <text>] [--additional-note <text>] [--is-global] [--module-ids a,b] [--dry-run] [--yes] [--json]` | Creates or updates a glossary term. Mutating. |
|
|
120
|
+
| `blocks localization glossary list [--search <text>] [--module-id <id>] [--is-global] [--page-number <n>] [--page-size <n>] [--json]` | Lists glossary terms. Read-only. |
|
|
121
|
+
| `blocks localization glossary get <itemId> [--json]` | Fetches one glossary term. Read-only. |
|
|
122
|
+
| `blocks localization glossary suggested <itemId> [--max-results <n>] [--json]` | Suggests glossary terms relevant to an item. Read-only. |
|
|
123
|
+
| `blocks localization glossary delete <itemId> [--dry-run] [--yes] [--json]` | Deletes a glossary term. Mutating. |
|
|
124
|
+
| `blocks localization assistant translation-suggestion --source-text <text> [--current-language <c>] [--destination-language <name>] [--destination-language-code <c>] [--module-id <id>] [--glossary-ids a,b] [--element-type <t>] [--element-application-context <text>] [--element-detail-context <text>] [--max-character-length <n>] [--temperature <n>] [--json]` | Gets an AI translation suggestion for a single string. Read-only (no confirm gate). |
|
|
125
|
+
| `blocks localization config get-webhook [--json]` | Gets the tenant's localization webhook config. Read-only. |
|
|
126
|
+
| `blocks localization config save-webhook --url <url> --content-type <type> --secret <s> --header-key <k> [--is-disabled] [--item-id <id>] [--dry-run] [--yes] [--json]` | Saves the tenant's localization webhook config. Mutating; the secret is redacted in `--dry-run` output. |
|
|
127
|
+
|
|
128
|
+
## Gotchas
|
|
129
|
+
|
|
130
|
+
- **`--dry-run` before `--yes`** on `localization push` — always. Same pattern as every other mutating `blocks` command.
|
|
131
|
+
- **`--language` on `push` is not validated against configured cultures.** `localization push` stamps whatever string you pass as `--language` directly into each key's `culture` field — it does not check that culture against the tenant's actual configured languages, and doesn't call `language list`/`list-for-tenant` to look. Get the culture code wrong (`de` instead of `de-DE`, or a culture the tenant never configured via `language save`) and the key saves without error but may never surface at runtime, because runtime lookups match by the tenant's real configured `languageCode`. Confirm the exact culture code with the user (or run `localization language list-for-tenant`) before pushing, especially for less common languages like Bengali (`bn-BD` vs `bn`).
|
|
132
|
+
- **Module auto-create is silent and permanent.** The first push against a new `--module` name creates it with no separate confirmation prompt beyond the push's own `--dry-run`/`--yes` gate — `--dry-run` output will tell you a module lookup happened, but won't distinguish "will create" from "already exists" as clearly as it could, so read the dry-run JSON's module info carefully, or ask the user to confirm the module name is intentional (typos become new, mostly-empty modules). Prefer `localization module save` first if the user wants the module created deliberately, without an accompanying key push.
|
|
133
|
+
- **`localization validate` is local-only** — it confirms the JSON is well-formed and keys/values pass the naming rules; it does not confirm the push will succeed against the server (module resolution, auth, project selection). Still run `--dry-run` on the actual push.
|
|
134
|
+
- **One culture per file/push.** Don't try to cram multiple languages into one dictionary file — the format is flat key → string value, not key → {culture: value}. Multiple languages means multiple files and multiple push invocations (see above).
|
|
135
|
+
- **No standalone "generate" or "publish" step for `push`.** `shouldPublish: true` is baked into every key `localization push` sends — once the push succeeds, the translations are live. That's separate from `key generate-uilm-file`/`key uilm-export` (and the composed `key translate-and-export`), which build downloadable runtime language files rather than affect `push`'s own publish behavior.
|
|
136
|
+
- **`language delete` and `set-default` are permanent, mutating calls** — always dry-run first, and confirm with the user before deleting a language or changing the tenant default, since either can affect what's visible at runtime for existing translations.
|
|
137
|
+
|
|
138
|
+
## Example trigger prompts
|
|
139
|
+
|
|
140
|
+
- "Add German translations for my login screen." → push `login.de-DE.json` after validate + dry-run + approval.
|
|
141
|
+
- "Add German and Bengali translations for my login screen." → two dictionary files, two validate/push pairs (`de-DE`, `bn-BD`), same module.
|
|
142
|
+
- "Set up a `common` module for shared strings like Save/Cancel/Delete." → write `common.<language>.json` with those keys, validate, push (this is what creates the `common` module) — or use `localization module save --module-name common` directly if no keys exist yet.
|
|
143
|
+
- "Pull the latest translations for the dashboard module before I edit them." → `localization pull --module dashboard --language en`.
|
|
144
|
+
- "Validate my localization file before pushing." → `localization validate` only, no network call.
|
|
145
|
+
- "Can we add Bengali as a new supported language for the tenant?" → `localization language save --language-name Bengali --language-code bn-BD --dry-run`, confirm, then `--yes`.
|
|
146
|
+
- "Create a new translation module called `billing` with no keys yet." → `localization module save --module-name billing --dry-run` → confirm → `--yes`.
|
|
147
|
+
- "Machine-translate the whole `login` module and give me the export." → `localization key translate-and-export --module-id <id> --wait --dry-run` → confirm → `--yes`.
|
|
148
|
+
- "Suggest a translation for this button label." → `localization assistant translation-suggestion --source-text "Save changes" --destination-language-code de-DE`.
|
|
149
|
+
- "What's our webhook config for localization events?" → `localization config get-webhook`.
|
|
@@ -1,63 +1,63 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: blocks-localization-implementation
|
|
3
|
-
description: "Consume SELISE Blocks localization at runtime in a scaffolded frontend, entirely through the `@seliseblocks/client` SDK's `localization` namespace — never raw fetch/curl. Use for making a Blocks web app multilingual on the client: language/module discovery, loading dictionaries, the built-in `t()` lookup, and a language switcher that reloads and re-renders. Frontend consumption only — authoring/pushing translation content is the sibling skill blocks-localization-configuration."
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# Blocks Localization — Implementation (frontend)
|
|
7
|
-
|
|
8
|
-
Make a scaffolded Blocks web app render its UI in the user's language, using only the `localization` namespace on the SDK client — `createBlocksClient(...).localization`. No fetch, no manual query strings, no hand-rolled caching: the SDK client already does all of that.
|
|
9
|
-
|
|
10
|
-
The translations themselves (keys, modules, per-language values) are authored and pushed with the blocks-localization-configuration skill (uses `blocks localization *`). This skill only covers loading and rendering them in the app.
|
|
11
|
-
|
|
12
|
-
## The client and its cache
|
|
13
|
-
|
|
14
|
-
`localization` is a `BlocksLocalizationClient` instance created once inside `createBlocksClient()`. It holds its dictionary cache as instance state — a `Map` keyed by `` `${language}:${moduleName}` `` plus an `activeLanguage`. That cache is **only as shared as the client instance is**: the canonical scaffold creates one `blocksClient` singleton (`src/lib/blocks/client.ts`, from `createBlocksClient()`) and imports it everywhere, so every `t()` call sees every dictionary loaded anywhere in the app. If you instantiate a second `createBlocksClient()` somewhere, it gets its own empty cache — don't do that; import the one singleton.
|
|
15
|
-
|
|
16
|
-
## Public vs. authenticated methods
|
|
17
|
-
|
|
18
|
-
Every method has a matching pair — one public, one tenant/session-scoped:
|
|
19
|
-
|
|
20
|
-
| Public (no token sent) | Authenticated (sends token when configured) |
|
|
21
|
-
|---|---|
|
|
22
|
-
| `languages()` | `languagesForCurrentTenant()` |
|
|
23
|
-
| `modules()` | `modulesForCurrentTenant()` |
|
|
24
|
-
| `translations(moduleName, language)` | `cloudTranslations(moduleName, language)` |
|
|
25
|
-
| `load(language, modules[])` | `loadCloud(language, modules[])` |
|
|
26
|
-
|
|
27
|
-
- `languages()`/`modules()`/`translations()`/`load()` are explicitly public — all tenant-supported cultures and translation bundles, usable pre-login for a language picker or startup locale selection.
|
|
28
|
-
- `languagesForCurrentTenant()`/`modulesForCurrentTenant()`/`cloudTranslations()`/`loadCloud()` are scoped to whichever tenant the active `x-blocks-key` resolves to (and send the caller's access token if the client is configured with one) — use these for protected, tenant-specific dictionaries behind a signed-in session.
|
|
29
|
-
|
|
30
|
-
`keysByNames({ keyNames, moduleId? })` fetches specific key records (metadata/translations) without downloading a whole module dictionary; useful for a one-off label or an admin screen that inspects individual keys.
|
|
31
|
-
|
|
32
|
-
**Argument order matters**: `translations(moduleName, language)` and `cloudTranslations(moduleName, language)` take module first, language second — easy to transpose.
|
|
33
|
-
|
|
34
|
-
## Startup sequence
|
|
35
|
-
|
|
36
|
-
1. **List languages** on app boot (or in a query hook) — `blocksClient.localization.languagesForCurrentTenant()` (or `languages()` if you want it available pre-login). Use `isDefault`/`languageCode` from the result to build the picker and preselect a default, falling back to a persisted user choice (e.g. `localStorage`).
|
|
37
|
-
2. **Load dictionaries** for the active language — `blocksClient.localization.load(language, modules)` where `modules` is the list of bundles the app needs (e.g. `["common", "dashboard", "assets"]`). `load()` fetches each module's dictionary in parallel via `translations()` and merges them into one object, with later modules in the array overwriting earlier ones on key collision. Use `loadCloud()` instead for protected dictionaries once the user is signed in.
|
|
38
|
-
3. **Render labels** with `blocksClient.localization.t(key, fallback, { language, moduleName })`. It reads from dictionaries already loaded by `translations()`/`load()` (or their cloud equivalents) — it does not fetch anything itself. Missing key → `fallback` → the raw key, in that order.
|
|
39
|
-
4. **Switch language**: on switcher change, call `load()` (or `loadCloud()`) again with the new language and the same module list, then re-render. There's no separate "invalidate" step — loading a language populates its own cache entries; you don't need to clear the old language's entries (they just stop being read once `activeLanguage`/your app state moves on).
|
|
40
|
-
|
|
41
|
-
The canonical scaffold (`blocks new web`) wires exactly this pattern in `src/lib/i18n/LocalizationProvider.tsx`: a React context holds `language` state (seeded from `localStorage`), a `useEffect` on `language` calls `blocksClient.localization.load(language, MODULES)` and stores the merged dictionary in state, and `t(key, fallback)` reads `cloudDictionary[key] ?? defaultDictionary[key] ?? fallback ?? key` — layering the network dictionary over a build-time `defaultDictionary` (from `src/lib/i18n/dictionary.ts`, generated from the same keys as the seed JSON in `blocks/localization/*.json`) as an offline/first-paint safety net, itself falling back to the caller-supplied fallback and finally the key. Mirror this shape rather than inventing your own provider — it's already generated into new projects. Note the scaffold's own `t()` is a plain function on context, not the SDK's `localization.t()` — either is fine; the SDK's built-in `t()` needs no separate context/provider if you're happy reading `blocksClient.localization.t(...)` directly in components.
|
|
42
|
-
|
|
43
|
-
## `t()` lookup details worth knowing
|
|
44
|
-
|
|
45
|
-
- If you pass `moduleName`, `t()` does an exact `` `${language}:${moduleName}` `` cache lookup — deterministic.
|
|
46
|
-
- If you omit `moduleName`, `t()` scans all cached dictionaries and returns the first match whose cache key starts with `` `${language}:` `` (or any language if you didn't pass one). Scan order follows Map insertion order, which is the order the underlying HTTP requests *resolved* in (not necessarily the order you listed modules in `load()`) — fine when keys are unique across modules, ambiguous if two modules define the same key. Pass `moduleName` explicitly whenever you know it and key collisions across modules are possible.
|
|
47
|
-
- `t()` never throws and never fetches — call `load()`/`translations()` (or the cloud variants) first, or every lookup falls straight to `fallback`/the key.
|
|
48
|
-
|
|
49
|
-
## Gotchas
|
|
50
|
-
|
|
51
|
-
- **No raw fetch/curl, ever** — every read here goes through `blocksClient.localization.*`. The SDK already sends `x-blocks-key` and, for the authenticated variants, the caller's access token when configured.
|
|
52
|
-
- **One client, one cache** — don't call `createBlocksClient()` more than once in the app; import the scaffold's `blocksClient` singleton everywhere `t()`/`load()` is needed, or dictionaries loaded in one part of the app won't be visible in another.
|
|
53
|
-
- **`translations`/`cloudTranslations` take `(moduleName, language)`** — module first.
|
|
54
|
-
- **Dictionaries only contain string values** — the SDK strips any non-string fields from the raw response (and unwraps a `data` envelope if present) before caching, so don't expect nested objects in a loaded dictionary.
|
|
55
|
-
- **This skill doesn't author content.** Adding a new key/module or changing a translated value goes through `blocks-localization-configuration`'s `blocks localization *` commands, not this skill.
|
|
56
|
-
|
|
57
|
-
## Example trigger prompts
|
|
58
|
-
|
|
59
|
-
- "Add a language switcher and translate the UI."
|
|
60
|
-
- "Load the `common` and `dashboard` translation modules on app startup and use them to render labels."
|
|
61
|
-
- "The Assets page still has hard-coded English strings — replace them with `t()` lookups."
|
|
62
|
-
- "Show only the languages this tenant actually has configured, with the default one preselected."
|
|
63
|
-
- "I need one specific translated key without pulling down the whole module."
|
|
1
|
+
---
|
|
2
|
+
name: blocks-localization-implementation
|
|
3
|
+
description: "Consume SELISE Blocks localization at runtime in a scaffolded frontend, entirely through the `@seliseblocks/client` SDK's `localization` namespace — never raw fetch/curl. Use for making a Blocks web app multilingual on the client: language/module discovery, loading dictionaries, the built-in `t()` lookup, and a language switcher that reloads and re-renders. Frontend consumption only — authoring/pushing translation content is the sibling skill blocks-localization-configuration."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Blocks Localization — Implementation (frontend)
|
|
7
|
+
|
|
8
|
+
Make a scaffolded Blocks web app render its UI in the user's language, using only the `localization` namespace on the SDK client — `createBlocksClient(...).localization`. No fetch, no manual query strings, no hand-rolled caching: the SDK client already does all of that.
|
|
9
|
+
|
|
10
|
+
The translations themselves (keys, modules, per-language values) are authored and pushed with the blocks-localization-configuration skill (uses `blocks localization *`). This skill only covers loading and rendering them in the app.
|
|
11
|
+
|
|
12
|
+
## The client and its cache
|
|
13
|
+
|
|
14
|
+
`localization` is a `BlocksLocalizationClient` instance created once inside `createBlocksClient()`. It holds its dictionary cache as instance state — a `Map` keyed by `` `${language}:${moduleName}` `` plus an `activeLanguage`. That cache is **only as shared as the client instance is**: the canonical scaffold creates one `blocksClient` singleton (`src/lib/blocks/client.ts`, from `createBlocksClient()`) and imports it everywhere, so every `t()` call sees every dictionary loaded anywhere in the app. If you instantiate a second `createBlocksClient()` somewhere, it gets its own empty cache — don't do that; import the one singleton.
|
|
15
|
+
|
|
16
|
+
## Public vs. authenticated methods
|
|
17
|
+
|
|
18
|
+
Every method has a matching pair — one public, one tenant/session-scoped:
|
|
19
|
+
|
|
20
|
+
| Public (no token sent) | Authenticated (sends token when configured) |
|
|
21
|
+
|---|---|
|
|
22
|
+
| `languages()` | `languagesForCurrentTenant()` |
|
|
23
|
+
| `modules()` | `modulesForCurrentTenant()` |
|
|
24
|
+
| `translations(moduleName, language)` | `cloudTranslations(moduleName, language)` |
|
|
25
|
+
| `load(language, modules[])` | `loadCloud(language, modules[])` |
|
|
26
|
+
|
|
27
|
+
- `languages()`/`modules()`/`translations()`/`load()` are explicitly public — all tenant-supported cultures and translation bundles, usable pre-login for a language picker or startup locale selection.
|
|
28
|
+
- `languagesForCurrentTenant()`/`modulesForCurrentTenant()`/`cloudTranslations()`/`loadCloud()` are scoped to whichever tenant the active `x-blocks-key` resolves to (and send the caller's access token if the client is configured with one) — use these for protected, tenant-specific dictionaries behind a signed-in session.
|
|
29
|
+
|
|
30
|
+
`keysByNames({ keyNames, moduleId? })` fetches specific key records (metadata/translations) without downloading a whole module dictionary; useful for a one-off label or an admin screen that inspects individual keys.
|
|
31
|
+
|
|
32
|
+
**Argument order matters**: `translations(moduleName, language)` and `cloudTranslations(moduleName, language)` take module first, language second — easy to transpose.
|
|
33
|
+
|
|
34
|
+
## Startup sequence
|
|
35
|
+
|
|
36
|
+
1. **List languages** on app boot (or in a query hook) — `blocksClient.localization.languagesForCurrentTenant()` (or `languages()` if you want it available pre-login). Use `isDefault`/`languageCode` from the result to build the picker and preselect a default, falling back to a persisted user choice (e.g. `localStorage`).
|
|
37
|
+
2. **Load dictionaries** for the active language — `blocksClient.localization.load(language, modules)` where `modules` is the list of bundles the app needs (e.g. `["common", "dashboard", "assets"]`). `load()` fetches each module's dictionary in parallel via `translations()` and merges them into one object, with later modules in the array overwriting earlier ones on key collision. Use `loadCloud()` instead for protected dictionaries once the user is signed in.
|
|
38
|
+
3. **Render labels** with `blocksClient.localization.t(key, fallback, { language, moduleName })`. It reads from dictionaries already loaded by `translations()`/`load()` (or their cloud equivalents) — it does not fetch anything itself. Missing key → `fallback` → the raw key, in that order.
|
|
39
|
+
4. **Switch language**: on switcher change, call `load()` (or `loadCloud()`) again with the new language and the same module list, then re-render. There's no separate "invalidate" step — loading a language populates its own cache entries; you don't need to clear the old language's entries (they just stop being read once `activeLanguage`/your app state moves on).
|
|
40
|
+
|
|
41
|
+
The canonical scaffold (`blocks new web`) wires exactly this pattern in `src/lib/i18n/LocalizationProvider.tsx`: a React context holds `language` state (seeded from `localStorage`), a `useEffect` on `language` calls `blocksClient.localization.load(language, MODULES)` and stores the merged dictionary in state, and `t(key, fallback)` reads `cloudDictionary[key] ?? defaultDictionary[key] ?? fallback ?? key` — layering the network dictionary over a build-time `defaultDictionary` (from `src/lib/i18n/dictionary.ts`, generated from the same keys as the seed JSON in `blocks/localization/*.json`) as an offline/first-paint safety net, itself falling back to the caller-supplied fallback and finally the key. Mirror this shape rather than inventing your own provider — it's already generated into new projects. Note the scaffold's own `t()` is a plain function on context, not the SDK's `localization.t()` — either is fine; the SDK's built-in `t()` needs no separate context/provider if you're happy reading `blocksClient.localization.t(...)` directly in components.
|
|
42
|
+
|
|
43
|
+
## `t()` lookup details worth knowing
|
|
44
|
+
|
|
45
|
+
- If you pass `moduleName`, `t()` does an exact `` `${language}:${moduleName}` `` cache lookup — deterministic.
|
|
46
|
+
- If you omit `moduleName`, `t()` scans all cached dictionaries and returns the first match whose cache key starts with `` `${language}:` `` (or any language if you didn't pass one). Scan order follows Map insertion order, which is the order the underlying HTTP requests *resolved* in (not necessarily the order you listed modules in `load()`) — fine when keys are unique across modules, ambiguous if two modules define the same key. Pass `moduleName` explicitly whenever you know it and key collisions across modules are possible.
|
|
47
|
+
- `t()` never throws and never fetches — call `load()`/`translations()` (or the cloud variants) first, or every lookup falls straight to `fallback`/the key.
|
|
48
|
+
|
|
49
|
+
## Gotchas
|
|
50
|
+
|
|
51
|
+
- **No raw fetch/curl, ever** — every read here goes through `blocksClient.localization.*`. The SDK already sends `x-blocks-key` and, for the authenticated variants, the caller's access token when configured.
|
|
52
|
+
- **One client, one cache** — don't call `createBlocksClient()` more than once in the app; import the scaffold's `blocksClient` singleton everywhere `t()`/`load()` is needed, or dictionaries loaded in one part of the app won't be visible in another.
|
|
53
|
+
- **`translations`/`cloudTranslations` take `(moduleName, language)`** — module first.
|
|
54
|
+
- **Dictionaries only contain string values** — the SDK strips any non-string fields from the raw response (and unwraps a `data` envelope if present) before caching, so don't expect nested objects in a loaded dictionary.
|
|
55
|
+
- **This skill doesn't author content.** Adding a new key/module or changing a translated value goes through `blocks-localization-configuration`'s `blocks localization *` commands, not this skill.
|
|
56
|
+
|
|
57
|
+
## Example trigger prompts
|
|
58
|
+
|
|
59
|
+
- "Add a language switcher and translate the UI."
|
|
60
|
+
- "Load the `common` and `dashboard` translation modules on app startup and use them to render labels."
|
|
61
|
+
- "The Assets page still has hard-coded English strings — replace them with `t()` lookups."
|
|
62
|
+
- "Show only the languages this tenant actually has configured, with the default one preselected."
|
|
63
|
+
- "I need one specific translated key without pulling down the whole module."
|