ui icon indicating copy to clipboard operation
ui copied to clipboard

How to have localized links in ContentSearch?

Open MartinLednar opened this issue 3 months ago • 0 comments

Package

v4.x

Description

I’m using @nuxt/content, @nuxt/ui, and @nuxtjs/i18n together, and I’m trying to have localized URLs in the search results rendered by the <UContentSearch> component.

Currently, the component works fine and fetches all the correct results, but the item.path values are always non-localized (e.g. /blog/my-post instead of /sk/blog/my-post). Even though my site is fully localized and I’m correctly fetching content from language-specific collections like blogs_en and blogs_sk.

I couldn’t find a built-in way to localize the links inside the search results. Is there a recommended approach to make <UContentSearch> output localized URLs?

What I tried

  1. Transforming the urls when fetching the navigation and searchSections, which works but, all the results are highlighted by default, because my guess is that NuxtLinks is-active is not set to exact url path.

  2. Setting locale prefix to nuxt/content collection, for example for sk locale it would be /sk/blog. This worked as well but the result was as in the point 1.

This is how I fetch the data ( Version with the transformations )

const { locale, t } = useI18n();
const localePath = useLocalePath();
const route = useRoute();

const normalizedPath = computed(() =>
  withLeadingSlash(joinURL("blog", ...(Array.isArray(route.params.slug) ? route.params.slug : [route.params.slug])))
);

const { data: page } = await useAsyncData(
  normalizedPath.value,
  () => queryCollection(`blogs_${locale.value}`).path(normalizedPath.value).first(),
  { watch: [locale, route] }
);

const { data: navigation } = await useAsyncData(
  `navigation-${locale.value}-${normalizedPath.value}`,
  async () => {
    const nav = await queryCollectionNavigation(`blogs_${locale.value}`).where(
      "path",
      "LIKE",
      `%${normalizedPath.value}%`
    );

    const transformNav = (items) =>
      items.map((item) => ({
        ...item,
        path: localePath(item.path),
        children: item.children ? transformNav(item.children) : undefined,
      }));

    return transformNav(nav);
  },
  { watch: [locale, route] }
);

const { data: searchSections } = await useLazyAsyncData(
  `search-sections-${locale.value}-${normalizedPath.value}`,
  () =>
    queryCollectionSearchSections(`blogs_${locale.value}`).where(
      "path",
      "LIKE",
      `%${normalizedPath.value}%`
    ),
  {
    watch: [locale, route],
    server: false,
  }
);

This is how I render the ContentSearch

<ClientOnly>
    <UContentSearch
      shortcut="meta_shift_k"
      :navigation="navigation"
      :files="searchSections"
      autofocus
      :fuse="{ resultLimit: 20 }"
      :placeholder="$t('blogDetail.searchInArticle')"
      :color-mode="false"
      :ui="{}"
    >
      <template #empty="{ searchTerm }">
        <template v-if="searchTerm">
          {{ $t("blogDetail.searchEmpty") }}
          "{{ searchTerm }}"
        </template>
      </template>
    </UContentSearch>
</ClientOnly>

Thank you in advance for any suggestions.

MartinLednar avatar Oct 31 '25 20:10 MartinLednar