add-locale and remove-locale
Adding a language touches five files and a manifest. These two commands do all of it, and the manifest is what makes the removal exact.
add-locale
Usage: smart-admin add-locale <code> [--from <src>] [--label "<native name>"] [--dry-run]
e.g. smart-admin add-locale fr --label "Français"
smart-admin add-locale ru --from ar # copy from Arabic, not the base| Option | What it does |
|---|---|
--label | The native name the switcher shows. |
--from | Copy the starting values from this locale instead of the base. Use it when the new language is closer to another one than to English. |
--dry-run | Print the plan; write nothing. |
What it does
npm run smart-admin -- add-locale nl --label "Nederlands"Adding locale "nl"
copying from en (declared base)
created src/locales/nl.json
edited src/core/i18n/index.ts (AvailableLocale + lazyLocales)
edited src/core/i18n/localeMeta.ts (Intl tag + label + date-fns importer)
switcher label: Nederlands
edited src/core/config/defaultConfig.ts (config.locale union)
created .smart-admin/locales/nl.json
✔ Locale "nl" wired.
Next steps:
1. Translate src/locales/nl.json — one file, every namespace, "en" values as placeholders.
2. Set the region in src/core/i18n/localeMeta.ts:
intlTag 'nl' → e.g. 'nl-XX' · label is already 'Nederlands'
No flag is set, by design — a flag is a country and a locale is a
language. The switcher shows the code; add /flags/xx.svg by hand
on that row if you use flags at all.
The date-fns importer points at date-fns/locale/nl — if that
subpath does not exist the build fails loudly, by design.
3. smart-admin analyze --locales # shows what is still untranslated
4. Restart dev if it is running.One new file, three edits, one manifest. The type union in three separate places is updated together, which is the part that is easy to get wrong by hand.
Two deliberate choices
No flag is set. A flag is a country and a locale is a language, and the two do not map. The switcher falls back to the code. Add /flags/xx.svg to that row yourself if you use flags at all — the nine shipped locales do.
The date-fns importer is not checked. It points at date-fns/locale/{code}, and if that subpath does not exist the build fails loudly rather than the calendar quietly falling back to English.
The manifest
Every added locale writes .smart-admin/locales/{code}.json:
{
"code": "nl",
"addedAt": "2026-09-24T16:32:21.042Z",
"source": "en",
"createdFiles": [
"src/locales/nl.json"
],
"editedFiles": [
"src/core/i18n/index.ts",
"src/core/i18n/localeMeta.ts",
"src/core/config/defaultConfig.ts"
]
}That is what remove-locale reads, which is why removal is exact rather than a search-and-hope. The directory also holds manifests for the shipped locales that were added this way.
remove-locale
Usage: smart-admin remove-locale <code> [--force] [--backup|--no-backup]
e.g. smart-admin remove-locale ru
--backup / --no-backup answer the backup prompt up front, so a
script or CI run never blocks waiting for a terminal.
To keep backups out of non-development runs entirely, create
.smart-admin/config.json with:
{ "backups": { "devOnly": true } }
Backups are then skipped whenever NODE_ENV=production or CI is set.
An explicit --backup still wins over it.It refuses while anything still names the code
"nl" is still referenced in 1 file(s):
src/modules/forms/pages/selects.vue
Remove those references first, or re-run with --force.That is the check worth having: a locale removed from the registry but still named in a page leaves a control pointing at a language that does not exist.
--force warns rather than staying quiet
⚠ FORCED PAST STRAY REFERENCES
1 file(s) still name "nl" and were NOT edited:
src/modules/forms/pages/selects.vue
Each one now points at a locale that no longer exists.
Fix them by hand, then re-run `npm run build` before you trust this tree.
backed up to .smart-admin/backups/1790267589377/
.gitignore already covers .smart-admin/backups/
Removing locale "nl"
deleted src/locales/nl.json
edited src/core/i18n/index.ts (AvailableLocale + lazyLocales)
edited src/core/i18n/localeMeta.ts (registry row)
edited src/core/config/defaultConfig.ts (config.locale union)
deleted .smart-admin/locales/nl.json
✔ Locale "nl" removed.
Backup: .smart-admin/backups/1790267589377/ · restore with `smart-admin reset`
Delete it later with `smart-admin remove-backups`.It names the files it did not touch and tells you to build before trusting the tree. The manifest goes with the locale, so the record and the code stay in step.
The base locale
en is the base. Every other file is measured against it, and add-locale copies from it unless --from says otherwise. A locale file always holds every key — untranslated values are the base's own words, not blanks, so a gap reads as English rather than a raw nav.foo.
Right-to-left locales
Direction is not a flag on the locale. ar, he, fa and ur are right-to-left, and useDirection derives it from the code. Add one of those and the layout mirrors with no extra setting up.
Checking the result
npm run smart-admin -- analyze --localesanalyze reports key coverage per locale and how many values are still identical to the base.
Related
- Add a language — the whole flow, with the translation step.
- Internationalization — the registry, plurals and
uiText. useLocale— switching at runtime.analyze— what is still untranslated.