Internationalization V2

View source
Movk Nuxt Docs ships built-in multilingual support powered by @nuxtjs/i18n with an opt-in design. Without configuration it runs single-language; once configured it enables localized routing, per-locale content collections, a language switcher, and multilingual SEO.

Overview

Internationalization is powered by @nuxtjs/i18n with an opt-in design:

  • Disabled — The layer only lists @nuxtjs/i18n as a dependency. The site runs single-language, UI strings come from the built-in translations, and routes are not localized.
  • Enabled — Once you add @nuxtjs/i18n to modules and configure i18n.locales in nuxt.config.ts, localized routing, per-locale content collections, the language switcher, and multilingual SEO activate automatically.

Either way, pages access the current locale, the translation function, and localized paths through a single entry point, useMovkI18n(), with consistent behavior.

Single-language UI

When @nuxtjs/i18n is not enabled, set the UI language via app.config.ts. It decides which language the built-in UI strings (TOC title, edit link, AI assistant, etc.) use.

app.config.ts
export default defineAppConfig({
  i18n: {
    locale: 'en' // UI language, defaults to 'zh-CN'
  }
})

Built-in language packs currently provide zh-CN and en. In this mode URLs carry no locale prefix and the content directory stays single-structured.

Multilingual site

1. Install the dependency

Multilingual requires installing @nuxtjs/i18n manually (the layer does not pull it in):

npm install @nuxtjs/i18n

2. Configure nuxt.config.ts

Add @nuxtjs/i18n to modules and declare defaultLocale and locales:

nuxt.config.ts
export default defineNuxtConfig({
  extends: ['@movk/nuxt-docs'],

  modules: ['@nuxtjs/i18n'],

  i18n: {
    defaultLocale: 'zh-CN',
    locales: [
      { code: 'zh-CN', name: '简体中文', file: 'zh-CN.json' },
      { code: 'en', name: 'English', file: 'en.json' }
    ]
  }
})
The layer forces the routing strategy to prefix_except_default: the default locale has no prefix (/docs), while others are prefixed (/en/docs). You do not need to set strategy manually.

3. Organize content directories

Default-locale content stays in place at the content/ root; other locales live under content/{locale}/:

content/
├── index.md              # Default locale (zh-CN) home
├── docs/                 # Default locale docs → /docs/*
   └── 1.getting-started/
       └── 1.index.md
└── en/                   # English content
    ├── index.md          # English home → /en
    └── docs/             # English docs → /en/docs/*
        └── 1.getting-started/
            └── 1.index.md

The layer generates content collections per locale automatically: the default locale uses docs / landing, while others use docs_{code} / landing_{code} (with - replaced by _ in code, e.g. docs_zh_CN).

Translation files

UI strings (navigation, buttons, AI assistant, etc.) come from translation files. The built-in zh-CN and en live inside the package at i18n/locales/zh-CN.json and i18n/locales/en.json.

Adding a new language requires meeting two conditions, otherwise the locale is filtered out at build time with a warning:

  1. A matching translation file {code}.json exists;
  2. A matching content directory content/{code}/ exists (except the default locale, whose content lives at the content/ root).

UI string resolution order is app.config.ts override ?? translation file. So the string fields in app.config.ts default to empty and are provided by the current locale's translation file; to override a single entry, set it explicitly in app.config.ts.

Language switcher

Once multilingual is enabled, the site header shows a language switcher (LanguageSwitcher) that renders the current locale as a flag emoji, lists all valid locales, and navigates to the equivalent path in the chosen language.

Multilingual SEO

When i18n is enabled and multiple valid locales exist, the layer injects:

  • <link rel="alternate" hreflang="…"> for each locale plus an x-default fallback;
  • og:locale for the current locale;
  • <html lang/dir> driven by @nuxt/ui/locale.

Browser-language redirection is controlled by @nuxtjs/i18n's detectBrowserLanguage; to pin the home page language, disable it in the i18n config.

Unified entry point

Pages, components, and composables access i18n through useMovkI18n(), with consistent behavior whether or not i18n is enabled:

FieldDescription
isEnabledWhether @nuxtjs/i18n is enabled
localeCurrent locale code (reactive)
defaultLocaleDefault locale code
localesList of valid locales
t(key, params?)Translation function with named params
localePath(path)Convert to the current locale's localized path
switchLocalePath(code)Get the path to switch to a given locale
docsRootDocs root path (/docs or /{locale}/docs)
docsCollectionCurrent locale's docs collection name
landingCollectionCurrent locale's landing collection name
useMovkI18n().t is the mode-agnostic entry that also works when i18n is disabled; its key is a plain string with no type completion. When i18n is enabled, the layer turns on @nuxtjs/i18n typed messages, so consumer code that needs key completion should use the native const { t } = useI18n(), which automatically recognizes both the layer's built-in keys and the consumer's custom keys.

Template

For a ready-to-use multilingual site, use the official i18n template:

npx nuxi init -t gh:mhaibaraai/movk-nuxt-docs/templates/i18n my-docs

The template ships with zh-CN (default) and en, the matching content directories, and a preconfigured @nuxtjs/i18n setup.

Copyright © 2024 - 2026