Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,22 @@ const { locale } = useI18n()
</template>
```

#### 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
<template>
<!-- Automatically becomes /en/about or /fr/about based on current locale -->
<ULink to="/about">About</ULink>
<UButton to="/contact">Contact</UButton>
</template>
```

::tip
External links and absolute URLs are automatically detected and skip localization. You can still manually use `localePath()` or `localeRoute()` if needed.
::

::

### Dynamic direction
Expand Down
25 changes: 22 additions & 3 deletions docs/content/docs/2.components/link.md
Original file line number Diff line number Diff line change
Expand Up @@ -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]
{
Expand All @@ -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
<template>
<!-- Automatically becomes /en/about or /fr/about based on current locale -->
<ULink to="/about">About</ULink>
</template>
```

::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

Expand Down
24 changes: 22 additions & 2 deletions src/runtime/components/Link.vue
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand All @@ -121,6 +122,7 @@ defineSlots<LinkSlots>()

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'))

Expand All @@ -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) {
Expand Down
Loading