Integrations

Nuxt i18n 模块

学习如何使用 Nuxt Content 和 @nuxtjs/i18n 模块创建多语言网站。

Nuxt Content 与 @nuxtjs/i18n 集成,用于创建多语言网站。当两个模块同时配置时,你可以按语言组织内容,并根据用户的区域设置自动提供正确的内容。

设置

安装所需模块

terminal
npm install @nuxtjs/i18n

配置你的 nuxt.config.ts

nuxt.config.ts
export default defineNuxtConfig({
  modules: ['@nuxt/content', '@nuxtjs/i18n'],
  i18n: {
    locales: [
      { code: 'en', name: 'English', language: 'en-US', dir: 'ltr' },
      { code: 'fr', name: 'French', language: 'fr-FR' },
      { code: 'fa', name: 'Farsi', language: 'fa-IR', dir: 'rtl' },
    ],
    strategy: 'prefix_except_default',
    defaultLocale: 'en',
  }
})

为每种语言定义集合

content.config.ts 中为每种语言创建单独的集合:

content.config.ts
const commonSchema = ...;

export default defineContentConfig({
  collections: {
    // 英文内容集合
    content_en: defineCollection({
      type: 'page',
      source: {
        include: 'en/**',
        prefix: '',
      },
      schema: commonSchema,
    }),
    // 法文内容集合
    content_fr: defineCollection({
      type: 'page',
      source: {
        include: 'fr/**',
        prefix: '',
      },
      schema: commonSchema,
    }),
    // 波斯文内容集合
    content_fa: defineCollection({
      type: 'page',
      source: {
        include: 'fa/**',
        prefix: '',
      },
      schema: commonSchema,
    }),
  },
})

创建动态页面

创建一个通配页面,根据当前区域设置获取内容:

pages/[...slug].vue
<script setup lang="ts">
import { withLeadingSlash } from 'ufo'
import type { Collections } from '@nuxt/content'

const route = useRoute()
const { locale } = useI18n()
const slug = computed(() => Array.isArray(route.params.slug) ? withLeadingSlash(String(route.params.slug.join('/'))) : withLeadingSlash(String(route.params.slug)))

const { data: page } = await useAsyncData('page-' + slug.value, async () => {
  // 根据当前语言构建集合名称
  const collection = ('content_' + locale.value) as keyof Collections
  const content = await queryCollection(collection).path(slug.value).first()

  // 可选:若内容缺失则回退到默认语言
  if (!content && locale.value !== 'en') {
    return await queryCollection('content_en').path(slug.value).first()
  }

  return content
}, {
  watch: [locale], // 语言切换时重新获取数据
})
</script>

<template>
  <ContentRenderer v-if="page" :value="page" />
  <div v-else>
    <h1>页面未找到</h1>
    <p>该页面不存在于 {{ locale }} 语言中。</p>
  </div>
</template>

就是这样!🚀 你的多语言内容站点已准备就绪。

内容结构

将内容文件按语言放置在对应的文件夹中,以匹配你的集合:

content/
  en/
    index.md
    about.md
    blog/
      post-1.md
  fr/
    index.md
    about.md
    blog/
      post-1.md
  fa/
    index.md
    about.md

每个语言文件夹应包含相同的结构,以确保各语言内容一致。

回退策略

你可以实现回退策略,当当前语言内容缺失时显示默认语言内容:

pages/[...slug].vue
const { data: page } = await useAsyncData('page-' + slug.value, async () => {
  const collection = ('content_' + locale.value) as keyof Collections
  let content = await queryCollection(collection).path(slug.value).first()

  // 内容缺失时回退到默认语言
  if (!content && locale.value !== 'en') {
    content = await queryCollection('content_en').path(slug.value).first()
  }

  return content
})
确保优雅地处理缺失内容的情况,并在用户首选语言内容不可用时给予清晰提示。

完整示例

你可以查看完整的工作示例: