Nuxt Setup

Quick setup guide for Nuxt applications with Stringer CLI

Stringer CLI integrates with Nuxt using the official @nuxtjs/i18n module.

Quick Start

cd your-nuxt-app
stringer

Stringer detects Nuxt and sets up everything automatically. Follow the prompts to convert your files and select target languages.

What Stringer Does

When you run stringer in a Nuxt project:

  1. Installs @nuxtjs/i18n with the correct version for your Nuxt version
  2. Creates locale detection in i18n/localeDetector.ts
  3. Updates nuxt.config.ts with i18n configuration
  4. Converts your components — replaces text with t('key') calls
  5. Generates locale files with your translations

Code Transformation

Components and Pages

<template>
  <div>
    <h1>{{ t('welcome.title') }}</h1>
    <p>{{ t('welcome.description') }}</p>
  </div>
</template>

<script setup lang="ts">
const { t } = useI18n()
</script>

Server API Routes

// server/api/data.get.ts
export default defineEventHandler(async (event) => {
  const t = await useTranslation(event)
  
  return {
    message: t('api.success'),
    data: []
  }
})

What's Converted

Converted:

  • Text in templates and pages
  • Strings in <script setup> that are user-facing
  • Strings inside defineEventHandler on server routes

Not converted:

  • Code comments
  • Console logs and debug messages
  • Content inside <style> tags
  • Strings in /composables folder

Server-Side Translation

Inside Event Handlers

Stringer converts strings inside defineEventHandler:

// ✅ This works — inside the event handler
export default defineEventHandler(async (event) => {
  const t = await useTranslation(event)
  
  return {
    error: t('errors.notFound')
  }
})

Outside Event Handlers

Strings outside the event handler are not converted. If you have helper functions with user-facing strings (like error messages), move them inside the handler:

// ❌ Won't work — function is outside event handler
function formatError(code: string) {
  return t('errors.' + code) // t() doesn't exist here
}

export default defineEventHandler(async (event) => {
  const t = await useTranslation(event)
  // ...
})
// ✅ Works — function is inside event handler
export default defineEventHandler(async (event) => {
  const t = await useTranslation(event)
  
  function formatError(code: string) {
    return t('errors.' + code) // t() is available here
  }
  
  // ...
})

URL-based i18n Routing

Enable SEO-friendly locale prefixes in your URLs (e.g., /en-us/about, /fr-fr/about).

Enabling URL Routing

Option 1: During the convert flow, select "Enable URL-based routing"

Option 2: Run the command:

stringer url-i18n --enable

What Happens

When enabled, Stringer:

  1. Changes strategy in nuxt.config.ts from no_prefix to prefix
  2. Wraps internal links with localePath() automatically
  3. Creates middleware for locale redirects
  4. Installs SEO modules@nuxtjs/sitemap and @nuxtjs/robots
  5. Configures sitemap — auto-generates multilingual XML sitemaps
  6. Configures robots.txt — includes sitemap reference for crawlers

Automatic SEO Setup

When URL routing is enabled, Stringer automatically installs and configures two additional modules for search engine optimization:

@nuxtjs/sitemap generates a multilingual sitemap at /sitemap.xml with:

  • Locale-prefixed URLs for all your pages
  • hreflang annotations linking alternate language versions
  • Automatic exclusion of API routes and internal paths

@nuxtjs/robots generates robots.txt with:

  • Reference to your sitemap for crawler discovery
  • Default allow rules for search engines

The generated nuxt.config.ts will include:

sitemap: {
  autoI18n: true,
  exclude: ['/api/**', '/_nuxt/**', '/billing/**', '/cli/**']
},

robots: {
  sitemap: '/sitemap.xml'
}

Stringer automatically wraps your internal links:

<!-- Before -->
<NuxtLink to="/about">About</NuxtLink>

<!-- After -->
<NuxtLink :to="localePath('/about')">About</NuxtLink>

For any new links you add later, wrap them manually:

<NuxtLink :to="localePath('/contact')">Contact</NuxtLink>
<NuxtLink :to="localePath('/products/' + product.id)">{{ product.name }}</NuxtLink>

Fixing Routing Issues

If you experience 404 errors or infinite redirects after enabling URL routing:

Step 1: Try the repair flow

stringer url-i18n --repair

Step 2: If issues persist, check for middleware conflicts. Temporarily rename custom middleware files to identify conflicts.

Step 3: Ensure API routes and static assets are excluded from locale prefixing.

See Troubleshooting for more details.


Language Switching

<template>
  <select @change="setLocale(($event.target as HTMLSelectElement).value)">
    <option 
      v-for="locale in availableLocales" 
      :key="locale.code" 
      :value="locale.code"
    >
      {{ locale.name }}
    </option>
  </select>
</template>

<script setup lang="ts">
const { locale, locales, setLocale } = useI18n()

const availableLocales = computed(() => locales.value)
</script>

Common Issues

Lists Not Updating on Language Change

Use computed for reactive translations:

// ❌ Won't react to language changes
const items = [{ label: t('item.one') }]

// ✅ Reacts to language changes  
const items = computed(() => [{ label: t('item.one') }])

Module Not Found

npm install @nuxtjs/i18n@latest

Locale Files Not Loading

Check your file structure matches the config:

i18n/
  locales/
    en.json
    es.json

Hydration Mismatches

Ensure consistent locale detection. Check i18n/localeDetector.ts uses the same logic server and client-side.


Need Help?

Next Steps