From angular
Externalize an Angular app's hardcoded UI strings into @ngx-translate/core keys backed by an Excel (.xlsx) sheet, then compile the sheet to i18n JSON with the xlsxToJsonTranslate CLI. Trigger when the user wants to translate or internationalize Angular UI, externalize hardcoded strings (in any source language) into translation keys, add or fill translation keys in an .xlsx, add a new language column, find missing translations, or (re)generate i18n JSON from a translations spreadsheet.
How this skill is triggered — by the user, by Claude, or both
Slash command
/angular:ngx-translate-xlsxThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Externalize hardcoded UI strings in an Angular app into [`@ngx-translate/core`](https://github.com/ngx-translate/core)
Externalize hardcoded UI strings in an Angular app into @ngx-translate/core
keys, keep the source-of-truth in an Excel sheet, and compile that sheet to per-language JSON with
xlsxToJsonTranslate.
Two layers, kept separate:
.xlsx is the editable source (one row per key, one column per language).xlsxToJsonTranslate compiles a chosen language column into nested JSON that ngx-translate loads.This skill is for incremental work: translating a screen/component, filling missing strings, or adding a language — not whole-app one-shots.
This skill is project-agnostic. It discovers the project's settings (translations file, i18n output dir, key-namespace style) instead of assuming them. The only hard requirement is the workbook layout below.
Do this first, every time. The translate pipe/keys are useless if the library isn't wired up.
package.json for @ngx-translate/core (and @ngx-translate/http-loader if
the app loads JSON over HTTP). npm ls @ngx-translate/core confirms.provideTranslateService(...) in app.config.ts (or wherever
ApplicationConfig/bootstrapApplication providers live), with a TranslateLoader.
rg "provideTranslateService|TranslateLoader|TranslateModule" src.TranslateModule.forRoot({ loader: … }) in the root module.npm i @ngx-translate/core @ngx-translate/http-loader.public/i18n/ (Angular 18+ default static folder) or
src/assets/i18n/ (older). Create it.// app.config.ts
import { provideHttpClient } from '@angular/common/http';
import { provideTranslateService, TranslateLoader } from '@ngx-translate/core';
import { HttpClient } from '@angular/common/http';
import { inject } from '@angular/core';
class JsonTranslateLoader implements TranslateLoader {
private http = inject(HttpClient);
getTranslation(lang: string) { return this.http.get(`i18n/${lang}.json`); }
}
export const appConfig = {
providers: [
provideHttpClient(),
provideTranslateService({
fallbackLang: 'en', // your default source language
loader: { provide: TranslateLoader, useClass: JsonTranslateLoader },
}),
// set the active language at startup (e.g. inject TranslateService and call .use(...))
],
};
The provideTranslateService config keys vary by version (v17 uses fallbackLang; older uses
defaultLanguage, or TranslateModule.forRoot). Match the installed version — see the
ngx-translate repo.npx ng build or the project's lint/test) before translating anything.Record the discovered/created i18n output dir and loader URL prefix (i18n/) — you'll use them
when compiling JSON.
xlsxToJsonTranslate on PATH. If missing: pipx install xlsxToJsonTranslate
(which xlsxToJsonTranslate to check).scripts/xlsx-i18n.mjs — no npm install, no zip/unzip).| col 0 | col 1 | col 2 | col 3 | … |
|---|---|---|---|---|
Informations | Key | en | fr | … |
| Home page | APP.HOME.TITLE | Welcome | Bienvenue |
Key — xlsxToJsonTranslate reads the key from column
index 1 (its default) and you must NOT pass -k/--keycolumn (a bug makes the value a string
and crashes the tool — see references/tooling.md).en, fr, …). The tool selects
the column by exact header match for -l <lang>.<NAMESPACE>.<NAME>) → the tool builds nested JSON (A.B.C → {A:{B:{C}}}).Informations) is a free-text note for humans; the tool ignores it.scripts/xlsx-i18n.mjsRun it from the project root (path is relative to this skill folder, i.e.
<skill-dir>/scripts/xlsx-i18n.mjs):
| Command | Purpose |
|---|---|
create <file> [--langs en,fr] [--force] | Create a new workbook with the header row. |
dump <file> [--missing <lang>] | Print all rows as JSON; --missing <lang> lists keys with an empty cell for that lang. |
add <file> [--rows <rows.json>] [--create] [--langs en,fr] | Upsert rows (from a JSON file or stdin). New key → append; existing key → update the given language cells. Auto-adds referenced language columns. --create makes the file if absent. |
add-lang <file> <lang> | Append an empty language column. |
Row JSON shape (array) accepted by add — nested or flat:
[
{ "info": "Home page", "key": "APP.HOME.TITLE", "values": { "en": "Welcome", "fr": "Bienvenue" } },
{ "info": "Home page", "key": "APP.HOME.RESULTS-PLURAL", "en": "{{count}} results" }
]
It round-trips files edited in Excel (preserves other sheets/styles/columns). {{param}}
placeholders, accents, apostrophes and non-breaking spaces are preserved verbatim.
.xlsx — ask the user, or search the repo for an existing .xlsx. If
none, create one: … create <file> (choose the source language column(s), e.g. --langs en or
--langs en,fr). Pick a workbook path with the user (e.g. at repo root or next to the i18n dir).… dump <file>.references/conventions.md.… add <file> --rows /tmp/rows.json (or pipe
via stdin). Add --create if the file may not exist yet.references/conventions.md):
{{ "KEY" | translate }}; element inputs → [attr]="'KEY' | translate".translateService.instant('KEY', { params }).…-SINGULAR/…-PLURAL) chosen in code + {{count}}.--keycolumn:
xlsxToJsonTranslate -i <file> -o <i18n-dir>/<lang>.json -l <lang>
Use the i18n output dir discovered/created in Step 0.node <skill-dir>/scripts/xlsx-i18n.mjs add-lang <file> <lang> # add the column
# fill it: in Excel, or `… add <file> --rows rows.json` with { key, values:{ <lang>: "..." } }
xlsxToJsonTranslate -i <file> -o <i18n-dir>/<lang>.json -l <lang>
Then make the app aware of the language (e.g. an allowed-languages list / language switcher) so the loader can serve it.
node <skill-dir>/scripts/xlsx-i18n.mjs dump <file> --missing <lang> # keys with an empty cell
# translate them, `… add` the values, then re-compile <lang>.json
references/conventions.md)<NAMESPACE>.<NAME> (uppercase, dash-separated), one namespace per
page/feature/popup. Detect the project's existing prefix/style from the sheet and match it; if
starting fresh, pick a short, consistent scheme.COMMON (or similar) namespace for strings shared across the app; a TECHNICAL namespace for
locale-adapted format patterns (date/number formats fed to pipes).…, NBSP)..xlsx; else create one.TranslateLoader (e.g. i18n/${lang}.json
served from public/i18n/ or src/assets/i18n/).xlsxToJsonTranslate are otherwise project-independent. Keep the Key in
column 1 (the tool's --keycolumn is unusable — see references/tooling.md).Provides behavioral guidelines to reduce common LLM coding mistakes, focusing on simplicity, surgical changes, assumption surfacing, and verifiable success criteria.
Searches, retrieves, and installs Agent Skills from prompts.chat registry using MCP tools like search_skills and get_skill. Activates for finding skills, browsing catalogs, or extending Claude.
npx claudepluginhub etiennepasteur/claudeplugins --plugin angular