···4343- [RTL Support](#rtl-support)
4444- [Localization (i18n)](#localization-i18n)
4545 - [Approach](#approach)
4646+ - [i18n commands](#i18n-commands)
4647 - [Adding a new locale](#adding-a-new-locale)
4748 - [Update translation](#update-translation)
4849 - [Adding translations](#adding-translations)
···380381- We use the `no_prefix` strategy (no `/en-US/` or `/fr-FR/` in URLs)
381382- Locale preference is stored in cookies and respected on subsequent visits
382383384384+### i18n commands
385385+386386+The following scripts help manage translation files. `en.json` is the reference locale.
387387+388388+| Command | Description |
389389+| ------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
390390+| `pnpm i18n:check [locale]` | Compares `en.json` with other locale files. Shows missing and extra keys. Optionally filter output by locale (e.g. `pnpm i18n:check ja-JP`). |
391391+| `pnpm i18n:check:fix [locale]` | Same as check, but adds missing keys to other locales with English placeholders. |
392392+| `pnpm i18n:report` | Audits translation keys against code usage in `.vue` and `.ts` files. Reports missing keys (used in code but not in locale), unused keys (in locale but not in code), and dynamic keys. |
393393+| `pnpm i18n:report:fix` | Removes unused keys from `en.json` and all other locale files. |
394394+383395### Adding a new locale
384396385397We are using localization using country variants (ISO-6391) via [multiple translation files](https://i18n.nuxtjs.org/docs/guide/lazy-load-translations#multiple-files-lazy-loading) to avoid repeating every key per country.
···423435We track the current progress of translations with [Lunaria](https://lunaria.dev/) on this site: https://i18n.npmx.dev/
424436If you see any outdated translations in your language, feel free to update the keys to match the English version.
425437426426-In order to make sure you have everything up-to-date, you can run:
427427-428428-```bash
429429-pnpm i18n:check <country-code>
430430-```
431431-432432-For example to check if all Japanese translation keys are up-to-date, run:
433433-434434-```bash
435435-pnpm i18n:check ja-JP
436436-```
437437-438438-To automatically add missing keys with English placeholders, use `--fix`:
439439-440440-```bash
441441-pnpm i18n:check:fix fr-FR
442442-```
443443-444444-This will add missing keys with `"EN TEXT TO REPLACE: {english text}"` as placeholder values, making it easier to see what needs translation.
438438+Use `pnpm i18n:check` and `pnpm i18n:check:fix` to verify and fix your locale (see [i18n commands](#i18n-commands) above for details).
445439446440#### Country variants (advanced)
447441···529523- Use `common.*` for shared strings (loading, retry, close, etc.)
530524- Use component-specific prefixes: `package.card.*`, `settings.*`, `nav.*`
531525- Do not use dashes (`-`) in translation keys; always use underscore (`_`): e.g., `privacy_policy` instead of `privacy-policy`
526526+- **Always use static string literals as translation keys.** Our i18n scripts (`pnpm i18n:report`) rely on static analysis to detect unused and missing keys. Dynamic keys cannot be analyzed and will be flagged as errors.
527527+528528+ **Bad:**
529529+530530+ ```vue
531531+ <!-- Template literal -->
532532+ <p>{{ $t(`package.tabs.${tab}`) }}</p>
533533+534534+ <!-- Variable -->
535535+ <p>{{ $t(myKey) }}</p>
536536+ ```
537537+538538+ **Good:**
539539+540540+ ```typescript
541541+ const { t } = useI18n()
542542+543543+ const tabLabels = computed(() => ({
544544+ readme: t('package.tabs.readme'),
545545+ versions: t('package.tabs.versions'),
546546+ }))
547547+ ```
548548+549549+ ```vue
550550+ <p>{{ tabLabels[tab] }}</p>
551551+ ```
532552533553### Using i18n-ally (recommended)
534554