diff --git a/docs/content/docs/1.getting-started/6.integrations/4.i18n/1.nuxt.md b/docs/content/docs/1.getting-started/6.integrations/4.i18n/1.nuxt.md index eb638c0ffd..f32b8b8142 100644 --- a/docs/content/docs/1.getting-started/6.integrations/4.i18n/1.nuxt.md +++ b/docs/content/docs/1.getting-started/6.integrations/4.i18n/1.nuxt.md @@ -157,6 +157,22 @@ const { locale } = useI18n() ``` +#### Automatic link localization :badge{label="Soon" class="align-text-top"} + +When `@nuxtjs/i18n` is installed, the [Link](/docs/components/link) component automatically localizes internal links using the `$localeRoute` helper. This means you don't need to manually wrap your links with `localePath()` or `localeRoute()`. + +```vue + +``` + +::tip +External links and absolute URLs are automatically detected and skip localization. You can still manually use `localePath()` or `localeRoute()` if needed. +:: + :: ### Dynamic direction diff --git a/docs/content/docs/2.components/link.md b/docs/content/docs/2.components/link.md index a0bcdd2bbf..2fea995ca5 100644 --- a/docs/content/docs/2.components/link.md +++ b/docs/content/docs/2.components/link.md @@ -75,9 +75,8 @@ slots: Link :: -## IntelliSense - -If you're using VSCode and wish to get autocompletion for the classes `active-class` and `inactive-class`, you can add the following settings to your `.vscode/settings.json`: +::callout{icon="i-simple-icons-visualstudiocode"} +If you're using the [Tailwind CSS IntelliSense](https://marketplace.visualstudio.com/items?itemName=bradlc.vscode-tailwindcss) extension for VSCode and wish to get autocompletion for the `active-class` and `inactive-class` props, you can add the following settings to your `.vscode/settings.json`: ```json [.vscode/settings.json] { @@ -87,6 +86,26 @@ If you're using VSCode and wish to get autocompletion for the classes `active-cl ] } ``` +:: + +### Locale :badge{label="Soon" class="align-text-top"} + +The Link component automatically integrates with [`@nuxtjs/i18n`](https://i18n.nuxtjs.org/) when installed. Internal links are automatically localized using the `$localeRoute` helper without requiring manual wrapping. + +```vue + +``` + +::tip +You can still manually use `localePath()` or `localeRoute()` if needed. The Link component handles already-localized paths correctly without double-localizing. +:: + +::note{to="/docs/getting-started/integrations/i18n/nuxt#dynamic-locale"} +Learn more about Internationalization in Nuxt UI. +:: ## API diff --git a/src/runtime/components/Link.vue b/src/runtime/components/Link.vue index 91d42d6cdf..6a0a0da80a 100644 --- a/src/runtime/components/Link.vue +++ b/src/runtime/components/Link.vue @@ -102,8 +102,9 @@ import { computed } from 'vue' import { isEqual } from 'ohash/utils' import { useForwardProps } from 'reka-ui' import { defu } from 'defu' +import { hasProtocol } from 'ufo' import { reactiveOmit } from '@vueuse/core' -import { useRoute, useAppConfig } from '#imports' +import { useRoute, useAppConfig, useNuxtApp } from '#imports' import { mergeClasses } from '../utils' import { tv } from '../utils/tv' import { isPartiallyEqual } from '../utils/link' @@ -121,6 +122,7 @@ defineSlots() const route = useRoute() const appConfig = useAppConfig() as Link['AppConfig'] +const nuxtApp = useNuxtApp() const nuxtLinkProps = useForwardProps(reactiveOmit(props, 'as', 'type', 'disabled', 'active', 'exact', 'exactQuery', 'exactHash', 'activeClass', 'inactiveClass', 'to', 'href', 'raw', 'custom', 'class')) @@ -136,7 +138,25 @@ const ui = computed(() => tv({ }, appConfig.ui?.link || {}) })) -const to = computed(() => props.to ?? props.href) +const to = computed(() => { + const path = props.to ?? props.href + if (!path) return path + + // Skip external links and absolute URLs + if (props.external || (typeof path === 'string' && hasProtocol(path, { acceptRelative: true }))) { + return path + } + + // Use `$localeRoute` from `@nuxtjs/i18n` if available + const localeRoute = nuxtApp.$localeRoute as ((route: RouteLocationRaw) => RouteLocationRaw | undefined) | undefined + if (localeRoute) { + const localizedPath = localeRoute(path) + // Fallback to original path if localeRoute returns undefined (e.g., route not found) + return localizedPath ?? path + } + + return path +}) function isLinkActive({ route: linkRoute, isActive, isExactActive }: any) { if (props.active !== undefined) {