diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 189f5c37a1..f84ae007ad 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -214,7 +214,7 @@ npmx.dev uses [@nuxtjs/i18n](https://i18n.nuxtjs.org/) for internationalization. ### Approach -- All user-facing strings should use translation keys via `$t()` in templates or `t()` in script +- All user-facing strings should use translation keys via `$t()` in templates and 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 @@ -233,8 +233,9 @@ npmx.dev uses [@nuxtjs/i18n](https://i18n.nuxtjs.org/) for internationalization. Or in script: ```typescript - const { t } = useI18n() - const message = t('my.translation.key') + ``` 3. For dynamic values, use interpolation: diff --git a/app/components/ClaimPackageModal.vue b/app/components/ClaimPackageModal.vue index fa918adce1..ca356ebd96 100644 --- a/app/components/ClaimPackageModal.vue +++ b/app/components/ClaimPackageModal.vue @@ -8,8 +8,6 @@ const props = defineProps<{ const open = defineModel('open', { default: false }) -const { t } = useI18n() - const { isConnected, state, @@ -34,7 +32,7 @@ async function checkAvailability() { try { checkResult.value = await checkPackageName(props.packageName) } catch (err) { - publishError.value = err instanceof Error ? err.message : t('claim.modal.failed_to_check') + publishError.value = err instanceof Error ? err.message : $t('claim.modal.failed_to_check') } finally { isChecking.value = false } @@ -84,7 +82,7 @@ async function handleClaim() { connectorModalOpen.value = true } } catch (err) { - publishError.value = err instanceof Error ? err.message : t('claim.modal.failed_to_claim') + publishError.value = err instanceof Error ? err.message : $t('claim.modal.failed_to_claim') } finally { isPublishing.value = false } @@ -171,7 +169,7 @@ const connectorModalOpen = shallowRef(false)
- +
diff --git a/app/components/ConnectorStatus.client.vue b/app/components/ConnectorStatus.client.vue index a32bd0cbe8..28c993870e 100644 --- a/app/components/ConnectorStatus.client.vue +++ b/app/components/ConnectorStatus.client.vue @@ -12,12 +12,10 @@ const { const showModal = shallowRef(false) const showTooltip = shallowRef(false) -const { t } = useI18n() - const tooltipText = computed(() => { - if (isConnecting.value) return t('connector.status.connecting') - if (isConnected.value) return t('connector.status.connected') - return t('connector.status.connect_cli') + if (isConnecting.value) return $t('connector.status.connecting') + if (isConnected.value) return $t('connector.status.connected') + return $t('connector.status.connect_cli') }) const statusColor = computed(() => { @@ -31,9 +29,9 @@ const operationCount = computed(() => activeOperations.value.length) const ariaLabel = computed(() => { if (error.value) return error.value - if (isConnecting.value) return t('connector.status.aria_connecting') - if (isConnected.value) return t('connector.status.aria_connected') - return t('connector.status.aria_click_to_connect') + if (isConnecting.value) return $t('connector.status.aria_connecting') + if (isConnected.value) return $t('connector.status.aria_connected') + return $t('connector.status.aria_click_to_connect') }) @@ -62,7 +60,7 @@ const ariaLabel = computed(() => { () -const { t } = useI18n() const { listUserOrgs } = useConnector() const isOpen = ref(false) @@ -23,11 +22,11 @@ async function loadOrgs() { // Already sorted alphabetically by server, take top 10 orgs.value = orgList.slice(0, 10) } else { - error.value = t('header.orgs_dropdown.error') + error.value = $t('header.orgs_dropdown.error') } hasLoaded.value = true } catch { - error.value = t('header.orgs_dropdown.error') + error.value = $t('header.orgs_dropdown.error') } finally { isLoading.value = false } @@ -62,7 +61,7 @@ function handleKeydown(event: KeyboardEvent) { :to="`/~${username}/orgs`" class="link-subtle font-mono text-sm inline-flex items-center gap-1" > - {{ t('header.orgs') }} + {{ $t('header.orgs') }}
{{ - t('header.orgs_dropdown.title') + $t('header.orgs_dropdown.title') }}
- {{ t('header.orgs_dropdown.loading') }} + {{ $t('header.orgs_dropdown.loading') }}
- {{ t('header.orgs_dropdown.error') }} + {{ $t('header.orgs_dropdown.error') }}
- {{ t('header.orgs_dropdown.empty') }} + {{ $t('header.orgs_dropdown.empty') }}
@@ -112,7 +111,7 @@ function handleKeydown(event: KeyboardEvent) { :to="`/~${username}/orgs`" class="link-subtle font-mono text-xs inline-flex items-center gap-1" > - {{ t('header.orgs_dropdown.view_all') }} + {{ $t('header.orgs_dropdown.view_all') }}
diff --git a/app/components/HeaderPackagesDropdown.vue b/app/components/HeaderPackagesDropdown.vue index 4c77e50400..4c6a09c378 100644 --- a/app/components/HeaderPackagesDropdown.vue +++ b/app/components/HeaderPackagesDropdown.vue @@ -3,7 +3,6 @@ const props = defineProps<{ username: string }>() -const { t } = useI18n() const { listUserPackages } = useConnector() const isOpen = ref(false) @@ -23,11 +22,11 @@ async function loadPackages() { // Sort alphabetically and take top 10 packages.value = Object.keys(pkgMap).sort().slice(0, 10) } else { - error.value = t('header.packages_dropdown.error') + error.value = $t('header.packages_dropdown.error') } hasLoaded.value = true } catch { - error.value = t('header.packages_dropdown.error') + error.value = $t('header.packages_dropdown.error') } finally { isLoading.value = false } @@ -62,7 +61,7 @@ function handleKeydown(event: KeyboardEvent) { :to="`/~${username}`" class="link-subtle font-mono text-sm inline-flex items-center gap-1" > - {{ t('header.packages') }} + {{ $t('header.packages') }}
{{ - t('header.packages_dropdown.title') + $t('header.packages_dropdown.title') }}
- {{ t('header.packages_dropdown.loading') }} + {{ $t('header.packages_dropdown.loading') }}
- {{ t('header.packages_dropdown.error') }} + {{ $t('header.packages_dropdown.error') }}
    @@ -104,7 +103,7 @@ function handleKeydown(event: KeyboardEvent) {
- {{ t('header.packages_dropdown.empty') }} + {{ $t('header.packages_dropdown.empty') }}
@@ -112,7 +111,7 @@ function handleKeydown(event: KeyboardEvent) { :to="`/~${username}`" class="link-subtle font-mono text-xs inline-flex items-center gap-1" > - {{ t('header.packages_dropdown.view_all') }} + {{ $t('header.packages_dropdown.view_all') }}
diff --git a/app/components/LoadingSpinner.vue b/app/components/LoadingSpinner.vue index af94573085..b221b83c38 100644 --- a/app/components/LoadingSpinner.vue +++ b/app/components/LoadingSpinner.vue @@ -3,8 +3,6 @@ defineProps<{ /** Text to display next to the spinner */ text?: string }>() - -const { t } = useI18n() diff --git a/app/components/OrgMembersPanel.vue b/app/components/OrgMembersPanel.vue index 37f452583e..8218fd5276 100644 --- a/app/components/OrgMembersPanel.vue +++ b/app/components/OrgMembersPanel.vue @@ -10,8 +10,6 @@ const emit = defineEmits<{ 'select-team': [teamName: string] }>() -const { t } = useI18n() - const { isConnected, lastExecutionTime, @@ -347,7 +345,7 @@ watch(lastExecutionTime, () => { :aria-pressed="filterRole === role" @click="filterRole = role" > - {{ t(`org.members.role.${role}`) }} + {{ $t(`org.members.role.${role}`) }} ({{ roleCounts[role] }}) @@ -465,9 +463,9 @@ watch(lastExecutionTime, () => { ) " > - - - + + + @@ -192,37 +190,37 @@ defineOgImageComponent('Default', { - +

- {{ t('org.page.no_packages') }} @{{ orgName }} + {{ $t('org.page.no_packages') }} @{{ orgName }}

- {{ t('org.page.no_packages_hint') }} + {{ $t('org.page.no_packages_hint') }}

-
+

- {{ t('org.page.packages_title') }} + {{ $t('org.page.packages_title') }}

@@ -232,7 +230,7 @@ defineOgImageComponent('Default', { v-if="filteredAndSortedPackages.length === 0" class="text-fg-muted py-8 text-center font-mono" > - {{ t('org.page.no_match', { query: filterText }) }} + {{ $t('org.page.no_match', { query: filterText }) }}

diff --git a/app/pages/[...package].vue b/app/pages/[...package].vue index 1a15a901a5..c5d171bda0 100644 --- a/app/pages/[...package].vue +++ b/app/pages/[...package].vue @@ -6,8 +6,6 @@ import { onKeyStroke } from '@vueuse/core' import { joinURL } from 'ufo' import { areUrlsEquivalent } from '#shared/utils/url' -const { t } = useI18n() - definePageMeta({ name: 'package', alias: ['/package/:package(.*)*'], @@ -432,7 +430,7 @@ defineOgImageComponent('Package', { {{ displayVersion.version }} v{{ displayVersion.version }} @@ -443,7 +441,7 @@ defineOgImageComponent('Package', { target="_blank" rel="noopener noreferrer" class="inline-flex items-center justify-center gap-1.5 text-fg-muted hover:text-fg transition-colors duration-200 min-w-6 min-h-6" - :title="t('package.verified_provenance')" + :title="$t('package.verified_provenance')" > {{ t('package.not_latest') }}{{ $t('package.not_latest') }} @@ -482,11 +480,11 @@ defineOgImageComponent('Package', { target="_blank" rel="noopener noreferrer" class="link-subtle font-mono text-sm inline-flex items-center gap-1.5 ml-auto shrink-0 self-center" - :title="t('common.view_on_npm')" + :title="$t('common.view_on_npm')" >
@@ -863,7 +861,7 @@ defineOgImageComponent('Package', {

- {{ t('package.readme.title') }} + {{ $t('package.readme.title') }}

- {{ t('package.readme.no_readme') }} + {{ $t('package.readme.no_readme') }} {{ t('package.readme.view_on_github') }}{{ $t('package.readme.view_on_github') }}

@@ -897,7 +895,7 @@ defineOgImageComponent('Package', {

- {{ t('package.keywords_title') }} + {{ $t('package.keywords_title') }}

  • @@ -927,7 +925,7 @@ defineOgImageComponent('Package', { id="compatibility-heading" class="text-xs text-fg-subtle uppercase tracking-wider mb-3" > - {{ t('package.compatibility') }} + {{ $t('package.compatibility') }}
    @@ -982,11 +980,11 @@ defineOgImageComponent('Package', { diff --git a/app/pages/code/[...path].vue b/app/pages/code/[...path].vue index 319885aace..84cfcb868c 100644 --- a/app/pages/code/[...path].vue +++ b/app/pages/code/[...path].vue @@ -5,8 +5,6 @@ import type { PackageFileContentResponse, } from '#shared/types' -const { t } = useI18n() - definePageMeta({ name: 'code', alias: ['/package/code/:path(.*)*'], @@ -308,7 +306,7 @@ useSeoMeta({
    - +