diff --git a/.vscode/extensions.json b/.vscode/extensions.json index 87400b48b3..c2fe9b8640 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -1,3 +1,3 @@ { - "recommendations": ["oxc.oxc-vscode", "Vue.volar"] + "recommendations": ["oxc.oxc-vscode", "Vue.volar", "lokalise.i18n-ally"] } diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000000..f33841cbac --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,4 @@ +{ + "i18n-ally.localesPaths": ["./i18n/locales"], + "i18n-ally.keystyle": "nested" +} diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index c13a1354eb..189f5c37a1 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -208,6 +208,89 @@ const props = defineProps<{ Ideally, extract utilities into separate files so they can be unit tested. 🙏 +## Localization (i18n) + +npmx.dev uses [@nuxtjs/i18n](https://i18n.nuxtjs.org/) for internationalization. We aim to make the UI accessible to users in their preferred language. + +### Approach + +- All user-facing strings should use translation keys via `$t()` in templates or `t()` in script +- Translation files live in `i18n/locales/` (e.g., `en.json`) +- We use the `no_prefix` strategy (no `/en/` or `/fr/` in URLs) +- Locale preference is stored in cookies and respected on subsequent visits + +### Adding translations + +1. Add your translation key to `i18n/locales/en.json` first (English is the source of truth) +2. Use the key in your component: + + ```vue + + ``` + + Or in script: + + ```typescript + const { t } = useI18n() + const message = t('my.translation.key') + ``` + +3. For dynamic values, use interpolation: + + ```json + { "greeting": "Hello, {name}!" } + ``` + + ```vue +

{{ $t('greeting', { name: userName }) }}

+ ``` + +### Translation key conventions + +- Use dot notation for hierarchy: `section.subsection.key` +- Keep keys descriptive but concise +- Group related keys together +- Use `common.*` for shared strings (loading, retry, close, etc.) +- Use component-specific prefixes: `package.card.*`, `settings.*`, `nav.*` + +### Using i18n-ally (recommended) + +We recommend the [i18n-ally](https://marketplace.visualstudio.com/items?itemName=lokalise.i18n-ally) VSCode extension for a better development experience: + +- Inline translation previews in your code +- Auto-completion for translation keys +- Missing translation detection +- Easy navigation to translation files + +The extension is included in our workspace recommendations, so VSCode should prompt you to install it. + +### Adding a new locale + +1. Create a new JSON file in `i18n/locales/` (e.g., `fr.json`) +2. Add the locale to `nuxt.config.ts`: + + ```typescript + i18n: { + locales: [ + { code: 'en', language: 'en-US', name: 'English', file: 'en.json' }, + { code: 'fr', language: 'fr-FR', name: 'Francais', file: 'fr.json' }, + ], + } + ``` + +3. Translate all keys from `en.json` + +### Formatting with locale + +When formatting numbers or dates that should respect the user's locale, pass the locale: + +```typescript +const { locale } = useI18n() +const formatted = formatNumber(12345, locale.value) // "12,345" in en-US +``` + ## Testing ### Unit tests diff --git a/app/components/AppFooter.vue b/app/components/AppFooter.vue index cba4d974d1..04a604d3b2 100644 --- a/app/components/AppFooter.vue +++ b/app/components/AppFooter.vue @@ -85,35 +85,35 @@ onMounted(() => { >
- + -

not affiliated with npm, Inc.

+

{{ $t('non_affiliation_disclaimer') }}

diff --git a/app/components/AppHeader.vue b/app/components/AppHeader.vue index 4762bb3210..7c1468b631 100644 --- a/app/components/AppHeader.vue +++ b/app/components/AppHeader.vue @@ -21,7 +21,7 @@ const { isConnected, npmUser } = useConnector()