saccoai-multilingual
This skill adds full multilingual support to any Next.js site. It installs next-intl, extracts every translatable string into structured JSON namespace files, generates AI-assisted translations with Swiss-specific context, wires up the LanguageSwitcher and hreflang tags, and produces a validation report with per-locale coverage percentages.
Default languages: DE + FR + IT + EN (full Swiss). Configurable down to any subset. Works on pipeline-built sites and any existing Next.js project.
Inputs
| Input | Required | Default | Description |
|---|---|---|---|
| Project path | Yes | cwd | An existing built Next.js project |
| Languages | No | de, fr, it, en | Comma-separated locale codes |
| Default locale | No | First in list | The primary language (source of truth for extraction) |
| Translation mode | No | ai-assisted | ai-assisted (AI SDK + AI Gateway + human review) or manual (empty files for human translation) |
Execution Model
Single-agent hybrid. Phases 1–3, 5–6 are sequential. Phase 4 (translate) uses superpowers dispatching-parallel-agents to translate all non-primary locales simultaneously — one agent per locale.
Preconditions
- Next.js project:
package.jsonmust include anextdependency. Abort with a clear message if not found. - Existing i18n detection: Before proceeding, check for existing i18n config (see Phase 1 Step 1). If found, report the current setup and ask whether to extend or replace — do not proceed automatically.
Phase 1: Analyze
Detect existing i18n setup and inventory all translatable content.
-
Check for existing i18n config: look for
next.config.ts(or.js) i18n block,next-intl,next-i18next, or any custom routing middleware that handles locale detection. -
If i18n already exists: report the current setup (library, configured locales, routing strategy). Ask: "An existing i18n setup was found ({details}). Extend it with new locales, or replace it with next-intl? (extend/replace)" Wait for confirmation before continuing.
-
Inventory all translatable content:
- Page content from
src/data/*.ts(if pipeline-built) or inline JSX text nodes - Metadata (
title,description) from page files and layouts - Navigation labels from header/footer components
- UI strings: button labels, form placeholders, error messages, aria-labels
- Structured data (JSON-LD) text fields:
name,description,addressLocality - Alt text on
<Image>and<img>elements
- Page content from
-
Confirm before proceeding: Print "{N} translatable strings found across {M} pages. Proceed with {languages} in {mode} mode? (yes/no)"
Phase 2: Configure
Set up Next.js i18n routing with next-intl.
-
Install next-intl:
npm install next-intl -
Configure path-based routing:
/de/,/fr/,/it/,/en/. Every page is accessible at/{locale}/path. The root/redirects to the default locale. -
Default locale redirect: e.g. if Italian is default,
/→/it/. Configure in middleware. -
Create
src/i18n/config.ts:export const locales = ['de', 'fr', 'it', 'en'] as const; export type Locale = typeof locales[number]; export const defaultLocale: Locale = 'de'; export const localeNames: Record<Locale, string> = { de: 'Deutsch', fr: 'Français', it: 'Italiano', en: 'English', };Populate from the user's input languages and default locale.
-
Set up middleware (
middleware.tsat project root orsrc/):- Use
createMiddlewarefrom next-intl for locale detection and routing - Detect locale from URL prefix first, then
Accept-Languageheader as fallback - Redirect bare
/to/{defaultLocale}/
- Use
-
Create message loading infrastructure:
src/locales/{locale}/{namespace}.jsondirectory structure. Create empty directories for all locales now; namespace files are populated in Phase 3.
Phase 3: Extract
Pull all translatable strings into structured namespace files.
-
Namespace file structure — for each locale:
src/locales/{locale}/common.json— shared strings: nav labels, footer text, button labels, error messages, form placeholderssrc/locales/{locale}/home.json— homepage content: hero heading, subheading, section titles, CTA textsrc/locales/{locale}/metadata.json— page<title>and<meta name="description">for every page, plus OG title/descriptionsrc/locales/{locale}/{page-slug}.json— per-page content for each page beyond the homepage
-
Replace inline text in components:
- Client components:
const t = useTranslations('namespace')→{t('key')} - Server components and layouts:
const t = await getTranslations('namespace')→{t('key')} - Preserve interpolation variables exactly:
{name},{count},{count, plural, one {# item} other {# items}}
- Client components:
-
Generate primary locale files: populate only the primary locale's JSON files with the original extracted content. Other locales remain empty at this stage — they are filled in Phase 4.
Example
src/locales/de/common.json:{ "nav": { "home": "Startseite", "about": "Über uns", "contact": "Kontakt" }, "buttons": { "submit": "Absenden", "learnMore": "Mehr erfahren" } }
Phase 4: Translate
Generate translations for all non-primary locales.
AI-assisted mode (default)
Use superpowers dispatching-parallel-agents — one agent per non-primary locale — each running the following steps:
-
System prompt (send to AI SDK + AI Gateway for each translation request):
You are a professional Swiss translator. Translate the following JSON strings from {source_locale} to {target_locale}. Swiss-specific conventions: - German (de): Use formal "Sie" (not "du"). Use Swiss German conventions where applicable (e.g., "ss" not "ß"). - French (fr): Use Swiss French conventions. Avoid Belgicisms and Canadianisms. - Italian (it): Use Ticino Italian register (formal, standard Italian — not Milan business Italian). Rules: - Preserve all interpolation variables exactly: {name}, {count}, {count, plural, ...} — do not translate variable names - Preserve HTML tags within strings: <strong>, <em>, <a href="..."> — keep tags, translate only text content - Keep JSON keys unchanged — only translate values - If you are unsure about a translation, prefix the value with "⚠️ REVIEW: " so it can be flagged for human review - Return valid JSON only -
Translate every namespace file for that locale.
-
Flag low-confidence translations: any value prefixed with
⚠️ REVIEW:is collected intosrc/locales/translation-review.md:# Translation Review ## {locale} — {namespace}.json | Key | Source | Translation | Reason | |-----|--------|-------------|--------| | nav.contact | Kontakt | ⚠️ REVIEW: Contact | Ambiguous in context |
Manual mode
- Generate all locale JSON files with the correct key structure but
"TODO"as every value:{ "nav": { "home": "TODO", "about": "TODO" } } - Stop after generating the files. Print instructions:
Manual translation mode: locale files generated with TODO placeholders. Files to translate: src/locales/fr/common.json src/locales/fr/home.json ... (full list) Fill in all TODO values, then re-run Phase 5 to integrate. - Do not proceed to Phase 5 automatically.
Phase 5: Integrate
Wire translations into the site's infrastructure and navigation.
-
<LanguageSwitcher>component (src/components/language-switcher.tsx):- Renders a list of locale links using
localesandlocaleNamesfromsrc/i18n/config.ts - Uses next-intl's
useRouterandusePathnameto switch locale while preserving the current path - Highlights the active locale
- Matches the site's existing nav pattern (inline list, dropdown, or icon — read the header component to match the style)
- Add to the site header alongside the existing navigation
- Renders a list of locale links using
-
<html lang>attribute: update the root layout to setlang={locale}dynamically from the next-intl locale:<html lang={locale}> -
hreflang link tags: add to the root layout
<head>for every page:{locales.map((loc) => ( <link key={loc} rel="alternate" hrefLang={loc} href={`https://{domain}/{loc}{pathname}`} /> ))} <link rel="alternate" hrefLang="x-default" href={`https://{domain}/{defaultLocale}{pathname}`} /> -
Per-locale sitemaps in
app/sitemap.ts:- Generate one sitemap entry per page per locale
- Include
alternates.languagesmap on each entry (all locale variants of the same page) - Example entry:
{ url: 'https://example.com/de/about', alternates: { languages: { de: '/de/about', fr: '/fr/about', it: '/it/about', en: '/en/about' } } }
-
robots.ts: add all per-locale sitemap URLs to thesitemaparray. -
Locale-aware structured data (JSON-LD): update JSON-LD objects to include
inLanguage: localedynamically. -
OG tags per locale: update
generateMetadatafunctions to include:openGraph.locale: current locale (e.g.,de_CH,fr_CH)openGraph.alternateLocale: array of all other locales
Phase 6: Validate
Verify completeness and correctness before signing off.
-
Completeness check: for every key in the primary locale's JSON files, verify the same key exists in every other locale's corresponding file. Flag any missing keys.
-
Missing translation report with per-locale coverage percentage:
de: 100% (primary) fr: 94% — 8 keys missing in home.json, metadata.json it: 100% en: 87% — 18 keys missing across 3 files -
hreflang validation: for every page, verify that all locale variants link to each other correctly. Check for self-referential hreflang and x-default presence.
-
Visual comparison: take a screenshot of the same representative page (homepage) in each locale. Check for layout breaks caused by longer or shorter translations (German text is typically 30–40% longer than English; flag if text overflows containers).
-
Output — save to
.saccoai/i18n/validation.md:# i18n Validation Report **Date**: {date} **Project**: {project name} **Locales**: {list} ## Coverage | Locale | Coverage | Missing Keys | |--------|----------|--------------| | de | 100% | — | | fr | 94% | 8 | | it | 100% | — | | en | 87% | 18 | ## Missing Keys (per-locale, per-file breakdown) ## hreflang Status (per-page pass/fail) ## Layout Issues (flagged pages with screenshot evidence)
Composition
saccoai-website-rebuild ──→ saccoai-multilingual (optional Phase 5.5, between Build and SEO)
any Next.js project ──────→ saccoai-multilingual (standalone)
When a user specifies target languages during a website rebuild, the rebuild pipeline invokes this skill after the Build phase and before SEO — because SEO needs the locale-aware sitemaps and hreflang tags to be in place before generating the sitemap and structured data.
Standalone: invoke directly on any existing Next.js project regardless of how it was built.
Standalone Usage
Invoke this skill directly when:
- An existing site needs translations added (Swiss client, multilingual market)
- The user says "add German", "make it multilingual", "translate the site", "add DE/FR/IT", or "i18n"
- A new Swiss client project requires the full four-language setup from day one
- The user wants to add a single additional language to an already-multilingual site
When invoked standalone, ask for: the project path (default: cwd), languages (default: de, fr, it, en), default locale (default: first in list), and translation mode (default: ai-assisted). Then run all six phases.
Edge Cases
-
Existing i18n config found: report the current setup (library, locales, routing). Ask whether to extend (add new locales) or replace (migrate to next-intl) before proceeding. Do not touch the codebase until confirmed.
-
Interpolation variables in source strings: preserve
{name},{count}, and ICU plural patterns like{count, plural, one {# item} other {# items}}exactly. Include this instruction in the AI translation prompt and validate the output — if a variable is missing or renamed in a translated value, flag it as⚠️ REVIEW:. -
Long translations breaking layout: German text is typically 30–40% longer than English source. Flag in the validation report with screenshot evidence. The fix is the developer's responsibility, but the report surfaces the specific pages and components affected.
-
Manual mode: all locale files are generated with
"TODO"values. The skill stops after Phase 3 and prints the full list of files to translate with instructions. Phase 5 (integrate) is not run automatically — the user must re-invoke the skill (or run Phase 5 explicitly) after translations are complete.
More from saccoai/agent-skills
website-analysis
Crawl any website in a single pass to produce both a complete structural map and full content extraction. Discovers all pages, routes, navigation, multilingual variants, and issues while simultaneously extracting all text, images, metadata, and assets. Use before any migration, redesign, or audit.
16nextjs-fullstack
Opinionated Next.js fullstack patterns — App Router, Tailwind CSS v4, shadcn/ui, Better Auth, Drizzle ORM, Server Actions, and Vercel deployment. Use when scaffolding a new project or enforcing consistent architecture across client projects.
13seo-migration
SEO preservation during website migrations — redirect mapping, canonical URLs, sitemap generation, structured data, meta tags, and Search Console verification. Use when rebuilding a site to ensure zero SEO loss from URL changes, content moves, or domain switches.
9project-handoff
Generate complete client handoff documentation — deployment guide, environment setup, CMS instructions, maintenance checklist, architecture overview, and operational runbook. Use when delivering a finished project to a client or their team.
8client-proposal
Generate a professional project proposal from a website audit. Analyzes the prospect's current site, identifies issues, and produces a structured proposal with scope, deliverables, tech recommendations, and phased timeline. Use as a sales tool or for scoping client engagements.
6web-audit
Comprehensive website quality audit — Lighthouse scores, accessibility (axe-core), cross-browser testing, performance budgets, and mobile responsiveness. Generates actionable reports with pass/fail per page. Use to audit any live website or as a QA gate before deployment.
6