Terug naar blog
Terminal output showing a translation script writing de.json and fr.json, alongside a folder tree and a browser rendering the German locale route.

Hoe een Next.js-app te vertalen met PolyLingo in minder dan 30 minuten

By Robert

Hoe een Next.js-app te vertalen met PolyLingo in minder dan 30 minuten

Aan het einde van deze tutorial heb je een werkend meertalig Next.js App Router-project: strings geëxtraheerd naar messages/en.json, vertaalde locale-bestanden voor elke taal die je nodig hebt, next-intl die het juiste bestand per route serveert, en een enkel Node-script dat je opnieuw kunt uitvoeren wanneer je inhoud verandert.

Geen vertaalsplatform om je voor aan te melden. Geen vaste kosten per taal. Eén API-aanroep behandelt al je doeltalen tegelijk.

Wat je nodig hebt:

  • Een Next.js-project dat de App Router gebruikt (Next.js 14 of 15)
  • Node.js 18 of later
  • Een gratis PolyLingo-account en API-sleutel

Stap 1: Haal je PolyLingo API-sleutel (5 minuten)

Maak een gratis account aan op usepolylingo.com. Het gratis abonnement bevat 100.000 tokens per maand, wat genoeg is om een middelgroot locale-bestand meerdere keren in 10+ talen te vertalen.

Als je bent ingelogd, ga dan naar API keys in het dashboard en maak een sleutel aan. Je ziet de volledige waarde maar één keer, dus kopieer deze direct.

Voeg deze toe aan je project als een omgevingsvariabele. Zet deze nooit in versiebeheer en maak deze nooit zichtbaar in client-side code:

# .env.local
POLYLINGO_API_KEY="pl_your_key_here"

Controleer of de API bereikbaar is voordat je verder gaat:

curl -sS "https://api.usepolylingo.com/v1/health"

Je zou een kleine JSON-payload moeten terugkrijgen met "status": "ok".


Stap 2: Installeer next-intl en stel routing in (10 minuten)

Installeer de bibliotheek:

npm install next-intl

Maak een i18n.ts bestand aan in de root van je project. Dit vertelt next-intl welke locales je ondersteunt en hoe het juiste berichtbestand voor elk verzoek geladen moet worden:

// i18n.ts
import { getRequestConfig } from 'next-intl/server'

export const locales = ['en', 'de', 'fr'] as const
export type Locale = (typeof locales)[number]
export const defaultLocale: Locale = 'en'

export default getRequestConfig(async ({ requestLocale }) => {
  let locale = await requestLocale
  if (!locale || !locales.includes(locale as Locale)) {
    locale = defaultLocale
  }
  return {
    locale,
    messages: (await import(`./messages/${locale}.json`)).default,
  }
})

Voeg middleware toe om routes te prefixen met de locale:

// middleware.ts
import createMiddleware from 'next-intl/middleware'
import { locales, defaultLocale } from './i18n'

export default createMiddleware({
  locales: [...locales],
  defaultLocale,
  localePrefix: 'as-needed',
})

export const config = {
  matcher: ['/((?!api|_next|.*\..*).*)'],
}

Verplaats je pagina-bestanden naar app/[locale]/. Werk je root layout bij om de locale-parameter te ontvangen en wikkel kinderen met NextIntlClientProvider:

// app/[locale]/layout.tsx
import { NextIntlClientProvider } from 'next-intl'
import { getMessages } from 'next-intl/server'

export default async function LocaleLayout({
  children,
  params,
}: {
  children: React.ReactNode
  params: Promise<{ locale: string }>
}) {
  const { locale } = await params
  const messages = await getMessages()
  return (
    <html lang={locale}>
      <body>
        <NextIntlClientProvider messages={messages}>
          {children}
        </NextIntlClientProvider>
      </body>
    </html>
  )
}

Stap 3: Extraheer je strings naar een JSON-berichtbestand (10 minuten)

Maak een messages/ map aan in de root van je project. Voeg een en.json bestand toe met je bronstrings. next-intl gebruikt een geneste sleutelstructuur:

{
  "Home": {
    "title": "Welcome",
    "cta": "Get started"
  }
}

Werk je pagina's bij om useTranslations te gebruiken in plaats van hardcoded strings:

// app/[locale]/page.tsx
import { useTranslations } from 'next-intl'

export default function HomePage() {
  const t = useTranslations('Home')
  return (
    <main>
      <h1>{t('title')}</h1>
      <button type="button">{t('cta')}</button>
    </main>
  )
}

Schrijf nu het vertaalscript. Dit leest messages/en.json, stuurt het naar de PolyLingo API met format: "json", en schrijft één uitvoerbestand per doellocale. De format: "json" vlag vertelt de API om de sleutelstructuur te behouden en alleen stringwaarden te vertalen — geneste sleutels, arrays en niet-string types blijven ongewijzigd.

// scripts/translate-messages.mjs
// Run with: node scripts/translate-messages.mjs

import fs from 'node:fs'
import path from 'node:path'

const API_KEY = process.env.POLYLINGO_API_KEY
const API_URL = (process.env.POLYLINGO_API_URL || 'https://api.usepolylingo.com/v1').replace(/\/$/, '')
const TARGETS = ['de', 'fr'] // extend this array to add more locales

const enPath = path.join('messages', 'en.json')
const en = JSON.parse(fs.readFileSync(enPath, 'utf8'))

const res = await fetch(`${API_URL}/translate`, {
  method: 'POST',
  headers: {
    Authorization: `Bearer ${API_KEY}`,
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    content: JSON.stringify(en),
    format: 'json',
    targets: TARGETS,
    model: 'standard',
  }),
})

if (!res.ok) {
  const err = await res.text()
  throw new Error(`PolyLingo ${res.status}: ${err}`)
}

const { translations } = await res.json()

for (const locale of TARGETS) {
  const out = path.join('messages', `${locale}.json`)
  fs.writeFileSync(out, JSON.stringify(JSON.parse(translations[locale]), null, 2) + '\n')
  console.log('Wrote', out)
}

Voer het uit:

node scripts/translate-messages.mjs

Je zou output moeten zien zoals:

Wrote messages/de.json
Wrote messages/fr.json

Open die bestanden en controleer ze. Je sleutels zullen identiek zijn aan en.json. Alleen de stringwaarden zijn veranderd.


Stap 4: Test de routes (5 minuten)

Start je dev-server:

npm run dev

Bezoek http://localhost:3000 en http://localhost:3000/de. De kop en knop zouden respectievelijk in het Engels en Duits moeten worden weergegeven. Voeg meer locales toe door de TARGETS array in het script en de locales array in i18n.ts uit te breiden, en voer het script opnieuw uit.

Controleer je tokengebruik in het PolyLingo-dashboard onder Usage. Voor een klein locale-bestand vertaald in twee talen heb je enkele honderden tokens van je maandelijkse tegoed gebruikt.


Waar te gaan vanaf hier

Voeg meer locales toe. Het script stuurt één verzoek ongeacht hoeveel items er in TARGETS staan. Het toevoegen van Japans, Spaans en Arabisch kost één API-aanroep, niet drie.

Koppel het aan CI. Voeg POLYLINGO_API_KEY toe als een repository secret in GitHub Actions en voer het script uit als onderdeel van je build pipeline. Je locale-bestanden blijven automatisch synchroon wanneer en.json verandert.

Vertaal andere formaten. Hetzelfde scriptpatroon werkt voor Markdown-documentatiepagina's (format: "markdown") en HTML-e-mailtemplates (format: "html"). De API behoudt de structuur in alle gevallen.

Gebruik de batch-endpoint voor grotere projecten. Als je meerdere aparte JSON-bestanden hebt (één per featuregebied bijvoorbeeld), accepteert POST /translate/batch tot 100 items in één verzoek, elk met een eigen id en format.


Probeer het gratis

Het gratis abonnement van PolyLingo bevat 100.000 tokens per maand. Geen creditcard vereist.

curl -sS -X POST "https://api.usepolylingo.com/v1/translate" \
  -H "Authorization: Bearer $POLYLINGO_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "content": "{\"Home\":{\"title\":\"Welcome\",\"cta\":\"Get started\"}}",
    "format": "json",
    "targets": ["de", "fr", "es", "ja"]
  }'

Haal je API-sleutel op