So baust du 2026 eine moderne, KI-gestützte Web-App mit i18n

Der komplette Guide für mehrsprachige Web-Apps mit Lingui + AI-Übersetzungen. Unterstütze automatisch 17 Sprachen mit Next.js, Claude und T3 Turbo.

So baust du 2026 eine moderne, KI-gestützte Web-App mit i18n
Feng LiuFeng Liu
24. Januar 2026

Hör zu, wir müssen über i18n im Jahr 2026 reden.

Die meisten Tutorials werden dir raten, Strings manuell zu übersetzen, Übersetzer einzustellen oder irgendeine wackelige Google Translate API zu nutzen. Aber hier ist der Punkt: Du lebst in der Ära von Claude Sonnet 4.5. Warum übersetzt du immer noch, als wäre es 2019?

Ich zeige dir, wie wir eine Produktiv-Webapp gebaut haben, die 17 Sprachen fließend spricht – mit einer zweiteiligen i18n-Architektur, die tatsächlich Sinn ergibt:

  1. Lingui für die Extraktion, Kompilierung und die Runtime-Magie
  2. Ein eigenes i18n-Package, angetrieben von LLMs für automatisierte, kontextbezogene Übersetzungen

Unser Stack? Create T3 Turbo mit Next.js, tRPC, Drizzle, Postgres, Tailwind und dem AI SDK. Wenn du das 2026 noch nicht nutzt, müssen wir uns mal ernsthaft unterhalten.

Lass uns bauen.


Das Problem mit traditionellem i18n

Traditionelle i18n-Workflows sehen so aus:

# Strings extrahieren
$ lingui extract

# ??? Irgendwie Übersetzungen bekommen ???
# (Übersetzer anheuern, dubiose Dienste nutzen, weinen)

# Kompilieren
$ lingui compile

Dieser mittlere Schritt? Ein absoluter Albtraum. Du hast die Wahl zwischen:

  • $$$ für menschliche Übersetzer zahlen (langsam, teuer)
  • Einfache Übersetzungs-APIs nutzen (kontextblind, klingt wie ein Roboter)
  • Manuell übersetzen (skaliert nicht)

Wir machen das besser.


Die zweiteilige Architektur

Hier ist unser Setup:

┌─────────────────────────────────────────────┐
│  Next.js App (Lingui Integration)          │
│  ├─ Strings mit Makros extrahieren          │
│  ├─ Trans/t Komponenten in deinem Code      │
│  └─ Runtime i18n mit kompilierten Katalogen │
└─────────────────────────────────────────────┘
              ↓ generiert .po Dateien
┌─────────────────────────────────────────────┐
│  @acme/i18n Package (LLM Übersetzung)     │
│  ├─ Liest .po Dateien                       │
│  ├─ Batch-Übersetzung mit Claude/GPT-5      │
│  ├─ Kontextbewusst, produktspezifisch       │
│  └─ Schreibt übersetzte .po Dateien         │
└─────────────────────────────────────────────┘
              ↓ kompiliert zu TypeScript
┌─────────────────────────────────────────────┐
│  Kompilierte Message-Kataloge               │
│  └─ Schnelle, typsichere Runtime-Translat.  │
└─────────────────────────────────────────────┘

Teil 1 (Lingui) kümmert sich um die Developer Experience. Teil 2 (Custom i18n Package) übernimmt die Übersetzungsmagie.

Tauchen wir in beides ein.


Technisches Flussdiagramm: Web UI → KI-Übersetzungs-Cloud → Datenbank, drei Ebenen verbunden durch Pfeile

Teil 1: Lingui in Next.js einrichten

Installation

In deinem T3 Turbo Monorepo:

# In apps/nextjs
pnpm add @lingui/core @lingui/react @lingui/macro
pnpm add -D @lingui/cli @lingui/swc-plugin

Lingui Konfiguration

Erstelle apps/nextjs/lingui.config.ts:

import type { LinguiConfig } from "@lingui/conf";

const config: LinguiConfig = {
  locales: [
    "en", "zh_CN", "zh_TW", "ja", "ko",
    "de", "fr", "es", "pt", "ar", "it",
    "ru", "tr", "th", "id", "vi", "hi"
  ],
  sourceLocale: "en",
  fallbackLocales: {
    default: "en"
  },
  catalogs: [
    {
      path: "<rootDir>/src/locales/{locale}/messages",
      include: ["src"],
    },
  ],
};

export default config;

17 Sprachen direkt "out of the box". Warum auch nicht?

Next.js Integration

Aktualisiere next.config.js, um Linguis SWC-Plugin zu nutzen:

const linguiConfig = require("./lingui.config");

module.exports = {
  experimental: {
    swcPlugins: [
      [
        "@lingui/swc-plugin",
        {
          // Das macht deine Builds schneller
        },
      ],
    ],
  },
  // ... Rest deiner Config
};

Server-Side Setup

Erstelle src/utils/i18n/appRouterI18n.ts:

import { setupI18n } from "@lingui/core";
import { allMessages } from "./initLingui";

const locales = ["en", "zh_CN", "zh_TW", /* ... */] as const;

const instances = new Map<string, ReturnType<typeof setupI18n>>();

// i18n-Instanzen für alle Locales vorerstellen
locales.forEach((locale) => {
  const i18n = setupI18n({
    locale,
    messages: { [locale]: allMessages[locale] },
  });
  instances.set(locale, i18n);
});

export function getI18nInstance(locale: string) {
  return instances.get(locale) ?? instances.get("en")!;
}

Warum? Server Components haben keinen React Context. Das hier gibt dir serverseitige Übersetzungen.

Client-Side Provider

Erstelle src/providers/LinguiClientProvider.tsx:

"use client";

import { I18nProvider } from "@lingui/react";
import { setupI18n } from "@lingui/core";
import { useEffect, useState } from "react";

export function LinguiClientProvider({
  children,
  locale,
  messages
}: {
  children: React.ReactNode;
  locale: string;
  messages: any;
}) {
  const [i18n] = useState(() =>
    setupI18n({
      locale,
      messages: { [locale]: messages },
    })
  );

  useEffect(() => {
    i18n.load(locale, messages);
    i18n.activate(locale);
  }, [locale, messages, i18n]);

  return <I18nProvider i18n={i18n}>{children}</I18nProvider>;
}

Wickle deine App in layout.tsx ein:

import { LinguiClientProvider } from "@/providers/LinguiClientProvider";
import { getLocale } from "@/utils/i18n/localeDetection";
import { allMessages } from "@/utils/i18n/initLingui";

export default function RootLayout({ children }: { children: React.ReactNode }) {
  const locale = getLocale();

  return (
    <html lang={locale}>
      <body>
        <LinguiClientProvider locale={locale} messages={allMessages[locale]}>
          {children}
        </LinguiClientProvider>
      </body>
    </html>
  );
}

Übersetzungen im Code verwenden

In Server Components:

import { msg } from "@lingui/core/macro";
import { getI18nInstance } from "@/utils/i18n/appRouterI18n";

export async function generateMetadata({ params }) {
  const locale = getLocale();
  const i18n = getI18nInstance(locale);

  return {
    title: i18n._(msg`Pricing Plans | acme`),
    description: i18n._(msg`Choose the perfect plan for you`),
  };
}

In Client Components:

"use client";

import { Trans, useLingui } from "@lingui/react/macro";

export function PricingCard() {
  const { t } = useLingui();

  return (
    <div>
      <h1><Trans>Pricing Plans</Trans></h1>
      <p>{t`Ultimate entertainment experience`}</p>

      {/* Mit Variablen */}
      <p>{t`${credits} credits remaining`}</p>
    </div>
  );
}

Die Makro-Syntax ist der SCHLÜSSEL. Lingui extrahiert diese zur Build-Zeit.


Teil 2: Das KI-gestützte Übersetzungs-Package

Jetzt wird es spannend.

Package Struktur

Erstelle packages/i18n/:

packages/i18n/
├── package.json
├── src/
│   ├── translateWithLLM.ts      # Kern-LLM-Übersetzung
│   ├── enhanceTranslations.ts   # Batch-Prozessor
│   └── utils.ts                  # Hilfsfunktionen

package.json

{
  "name": "@acme/i18n",
  "version": "0.1.0",
  "dependencies": {
    "@acme/ai": "workspace:*",
    "openai": "^4.77.3",
    "pofile": "^1.1.4",
    "zod": "^3.23.8"
  }
}

Die LLM Übersetzungs-Engine

Hier ist das Geheimrezept – translateWithLLM.ts:

import { openai } from "@ai-sdk/openai";
import { generateText } from "ai";
import { z } from "zod";

const translationSchema = z.object({
  translations: z.array(
    z.object({
      msgid: z.string(),
      msgstr: z.string(),
    })
  ),
});

export async function translateWithLLM(
  messages: Array<{ msgid: string; msgstr: string }>,
  targetLocale: string,
  options?: { model?: string }
) {
  const prompt = `You are a professional translator for acme, an AI-powered creative platform.

Translate the following strings from English to ${getLanguageName(targetLocale)}.

CONTEXT:
- acme is a platform for AI chat, image generation, and creative content
- Keep brand names unchanged (acme, Claude, etc.)
- Preserve HTML tags, variables like {count}, and placeholders
- Adapt culturally where appropriate
- Maintain tone: friendly, creative, engaging

STRINGS TO TRANSLATE:
${JSON.stringify(messages, null, 2)}

Return a JSON object with this structure:
{
  "translations": [
    { "msgid": "original", "msgstr": "translation" },
    ...
  ]
}`;

  const result = await generateText({
    model: openai(options?.model ?? "gpt-4o"),
    prompt,
    temperature: 0.3, // Niedriger = konsistenter
  });

  const parsed = translationSchema.parse(JSON.parse(result.text));
  return parsed.translations;
}

function getLanguageName(locale: string): string {
  const names: Record<string, string> = {
    zh_CN: "Simplified Chinese",
    zh_TW: "Traditional Chinese",
    ja: "Japanese",
    ko: "Korean",
    de: "German",
    fr: "French",
    es: "Spanish",
    pt: "Portuguese",
    ar: "Arabic",
    // ... usw.
  };
  return names[locale] ?? locale;
}

Warum das funktioniert:

  • Kontextbewusst: Das LLM weiß, was "acme" ist.
  • Strukturierter Output: Das Zod-Schema garantiert valides JSON.
  • Niedrige Temperature: Konsistente Übersetzungen.
  • Erhält Formatierung: HTML und Variablen bleiben intakt.

Batch Translation Processor

Erstelle enhanceTranslations.ts:

import fs from "fs";
import path from "path";
import pofile from "pofile";
import { translateWithLLM } from "./translateWithLLM";

const BATCH_SIZE = 30; // 30 Strings auf einmal übersetzen
const DELAY_MS = 1000; // Rate Limiting

export async function enhanceTranslations(
  locale: string,
  catalogPath: string
) {
  const poPath = path.join(catalogPath, locale, "messages.po");
  const po = pofile.parse(fs.readFileSync(poPath, "utf-8"));

  // Unübersetzte Items finden
  const untranslated = po.items.filter(
    (item) => item.msgid && (!item.msgstr || item.msgstr[0] === "")
  );

  if (untranslated.length === 0) {
    console.log(`✓ ${locale}: All strings translated`);
    return;
  }

  console.log(`Translating ${untranslated.length} strings for ${locale}...`);

  // In Batches verarbeiten
  for (let i = 0; i < untranslated.length; i += BATCH_SIZE) {
    const batch = untranslated.slice(i, i + BATCH_SIZE);
    const messages = batch.map((item) => ({
      msgid: item.msgid,
      msgstr: item.msgstr?.[0] ?? "",
    }));

    try {
      const translations = await translateWithLLM(messages, locale);

      // PO Datei aktualisieren
      translations.forEach((translation, index) => {
        const item = batch[index];
        if (item) {
          item.msgstr = [translation.msgstr];
        }
      });

      console.log(`  ${i + batch.length}/${untranslated.length} translated`);

      // Fortschritt speichern
      fs.writeFileSync(poPath, po.toString());

      // Rate Limiting
      if (i + BATCH_SIZE < untranslated.length) {
        await new Promise((resolve) => setTimeout(resolve, DELAY_MS));
      }
    } catch (error) {
      console.error(`  Error translating batch: ${error}`);
      // Mit nächstem Batch fortfahren
    }
  }

  console.log(`✓ ${locale}: Translation complete!`);
}

Batch-Verarbeitung verhindert Token-Limits und spart Kosten.

Das Übersetzungs-Skript

Erstelle apps/nextjs/script/i18n.ts:

import { enhanceTranslations } from "@acme/i18n";
import { exec } from "child_process";
import { promisify } from "util";

const execAsync = promisify(exec);

const LOCALES = [
  "zh_CN", "zh_TW", "ja", "ko", "de",
  "fr", "es", "pt", "ar", "it", "ru"
];

async function main() {
  // Schritt 1: Strings aus dem Code extrahieren
  console.log("📝 Extracting strings...");
  await execAsync("pnpm run lingui:extract --clean");

  // Schritt 2: Fehlende Strings automatisch übersetzen
  console.log("\n🤖 Translating with AI...");
  const catalogPath = "./src/locales";

  for (const locale of LOCALES) {
    await enhanceTranslations(locale, catalogPath);
  }

  // Schritt 3: Zu TypeScript kompilieren
  console.log("\n⚡ Compiling catalogs...");
  await execAsync("npx lingui compile --typescript");

  console.log("\n✅ Done! All translations updated.");
}

main().catch(console.error);

Füge dies zu package.json hinzu:

{
  "scripts": {
    "i18n": "tsx script/i18n.ts",
    "lingui:extract": "lingui extract",
    "lingui:compile": "lingui compile --typescript"
  }
}

Deine i18n-Pipeline ausführen

# Ein Befehl für alles
$ pnpm run i18n

📝 Extracting strings...
Catalog statistics for src/locales/{locale}/messages:
┌──────────┬─────────────┬─────────┐
│ Language │ Total count │ Missing │
├──────────┼─────────────┼─────────┤
│ en       │         847 │       0 │
│ zh_CN    │         847 │     123 │
│ ja       │         847 │      89 │
└──────────┴─────────────┴─────────┘

🤖 Translating with AI...
Translating 123 strings for zh_CN...
  30/123 translated
  60/123 translated
  90/123 translated
  123/123 translated
✓ zh_CN: Translation complete!

⚡ Compiling catalogs...
✅ Done! All translations updated.

Das war's. Füge einen neuen String in deinen Code ein, führe pnpm i18n aus, boom – übersetzt in 17 Sprachen.


Vorher/Nachher Split-Screen: Links ein gestresster Entwickler mit Übersetzungs-Papieren und einer 1000$-Rechnung

Locale Switching

Vergiss nicht die UX-Seite. Hier ist ein Locale-Switcher:

"use client";

import { useLocaleSwitcher } from "@/hooks/useLocaleSwitcher";
import { useLocale } from "@/hooks/useLocale";

const LOCALES = {
  en: "English",
  zh_CN: "简体中文",
  zh_TW: "繁體中文",
  ja: "日本語",
  ko: "한국어",
  // ... usw.
};

export function LocaleSelector() {
  const currentLocale = useLocale();
  const { switchLocale } = useLocaleSwitcher();

  return (
    <select
      value={currentLocale}
      onChange={(e) => switchLocale(e.target.value)}
    >
      {Object.entries(LOCALES).map(([code, name]) => (
        <option key={code} value={code}>
          {name}
        </option>
      ))}
    </select>
  );
}

Die Hook-Implementierung:

// hooks/useLocaleSwitcher.tsx
"use client";

import { setUserLocale } from "@/utils/i18n/localeDetection";

export function useLocaleSwitcher() {
  const switchLocale = (locale: string) => {
    setUserLocale(locale);
    window.location.reload(); // Force reload um Locale anzuwenden
  };

  return { switchLocale };
}

Speichere die Präferenz in einem Cookie:

// utils/i18n/localeDetection.ts
import { cookies } from "next/headers";

export function setUserLocale(locale: string) {
  cookies().set("NEXT_LOCALE", locale, {
    maxAge: 365 * 24 * 60 * 60, // 1 Jahr
  });
}

export function getLocale(): string {
  const cookieStore = cookies();
  return cookieStore.get("NEXT_LOCALE")?.value ?? "en";
}

Fortgeschritten: Typsichere Übersetzungen

Willst du Typsicherheit? Lingui hat dich abgedeckt:

// Statt so:
t`Hello ${name}`

// Nutze msg descriptor:
import { msg } from "@lingui/core/macro";

const greeting = msg`Hello ${name}`;
const translated = i18n._(greeting);

Deine IDE wird die Translation-Keys autovervollständigen. Wunderschön.


Performance Überlegungen

1. Zur Build-Zeit kompilieren

Lingui kompiliert Übersetzungen zu minifiziertem JSON. Kein Parsing-Overhead zur Laufzeit.

// Kompilierter Output (minifiziert):
export const messages = JSON.parse('{"ICt8/V":["视频"],"..."}');

2. Server-Kataloge vorladen

Lade alle Kataloge einmal beim Start (siehe appRouterI18n.ts oben). Kein Datei-I/O bei jedem Request.

3. Client Bundle Size

Liefere nur das aktive Locale an den Client aus:

<LinguiClientProvider
  locale={locale}
  messages={allMessages[locale]} // Nur ein Locale
>

4. LLM Kostenoptimierung

  • Batch-Übersetzungen: 30 Strings pro API-Call
  • Übersetzungen cachen: Unveränderte Strings nicht neu übersetzen
  • Günstigere Modelle nutzen: GPT-4o-mini für weniger kritische Sprachen

Unsere Kosten? ~$2-3 für 800+ Strings × 16 Sprachen. Pfennigbeträge im Vergleich zu menschlichen Übersetzern.


Die Integration in den Full Tech Stack

Schauen wir uns an, wie das mit dem Rest von T3 Turbo zusammenspielt:

tRPC mit i18n

// server/api/routers/user.ts
import { createTRPCRouter, publicProcedure } from "../trpc";
import { msg } from "@lingui/core/macro";

export const userRouter = createTRPCRouter({
  subscribe: publicProcedure
    .mutation(async ({ ctx }) => {
      // Fehler können auch übersetzt werden!
      if (!ctx.session?.user) {
        throw new TRPCError({
          code: "UNAUTHORIZED",
          message: ctx.i18n._(msg`You must be logged in`),
        });
      }

      // ... Subscription Logik
    }),
});

Reiche die i18n-Instanz via Context weiter:

// server/api/trpc.ts
import { getI18nInstance } from "@/utils/i18n/appRouterI18n";

export const createTRPCContext = async (opts: CreateNextContextOptions) => {
  const locale = getLocale();
  const i18n = getI18nInstance(locale);

  return {
    session: await getServerAuthSession(),
    i18n,
    locale,
  };
};

Datenbank mit Drizzle

Speichere die Locale-Präferenz des Users:

// packages/db/schema/user.ts
import { pgTable, text, varchar } from "drizzle-orm/pg-core";

export const users = pgTable("user", {
  id: varchar("id", { length: 255 }).primaryKey(),
  locale: varchar("locale", { length: 10 }).default("en"),
  // ... andere Felder
});

AI SDK Integration

Übersetze KI-Antworten on-the-fly:

import { openai } from "@ai-sdk/openai";
import { generateText } from "ai";
import { useLingui } from "@lingui/react/macro";

export function useAIChat() {
  const { i18n } = useLingui();

  const chat = async (prompt: string) => {
    const systemPrompt = i18n._(msg`You are a helpful AI assistant for acme.`);

    return generateText({
      model: openai("gpt-4"),
      messages: [
        { role: "system", content: systemPrompt },
        { role: "user", content: prompt },
      ],
    });
  };

  return { chat };
}

Best Practices, die wir gelernt haben

1. Immer Makros verwenden

// ❌ Schlecht: Runtime-Übersetzung (wird nicht extrahiert)
const text = t("Hello world");

// ✅ Gut: Makro (wird zur Build-Zeit extrahiert)
const text = t`Hello world`;

2. Kontext ist alles

Füge Kommentare für Übersetzer hinzu:

// i18n: This appears in the pricing table header
<Trans>Monthly</Trans>

// i18n: Button to submit payment form
<button>{t`Subscribe Now`}</button>

Lingui extrahiert diese als Notizen für Übersetzer (bzw. das LLM).

3. Pluralformen richtig behandeln

import { Plural } from "@lingui/react/macro";

<Plural
  value={count}
  one="# credit remaining"
  other="# credits remaining"
/>

Verschiedene Sprachen haben verschiedene Pluralregeln. Lingui regelt das.

4. Datums-/Zahlenformatierung

Nutze Intl APIs:

const date = new Intl.DateTimeFormat(locale, {
  dateStyle: "long",
}).format(new Date());

const price = new Intl.NumberFormat(locale, {
  style: "currency",
  currency: "USD",
}).format(29.99);

5. RTL Support

Für Arabisch musst du die Richtung beachten:

export default function RootLayout({ children }) {
  const locale = getLocale();
  const direction = locale === "ar" ? "rtl" : "ltr";

  return (
    <html lang={locale} dir={direction}>
      <body>{children}</body>
    </html>
  );
}

Zur Tailwind Config hinzufügen:

module.exports = {
  plugins: [
    require('tailwindcss-rtl'),
  ],
};

Nutze richtungsabhängige Klassen:

<div className="ms-4"> {/* margin-start, funktioniert für LTR & RTL */}

Deployment Checklist

Bevor du shippst:

  • Führe pnpm i18n aus, um sicherzustellen, dass alle Übersetzungen aktuell sind
  • Teste jedes Locale im Production-Mode
  • Überprüfe, ob das Locale-Cookie bestehen bleibt
  • Checke das RTL-Layout für Arabisch
  • Teste die UX des Locale-Switchers
  • Füge hreflang-Tags für SEO hinzu
  • Richte bei Bedarf Routing basierend auf Locales ein
  • Überwache die LLM-Übersetzungskosten

Die Ergebnisse

Nach der Implementierung dieses Systems:

  • 17 Sprachen unterstützt out of the box
  • ~850 Strings automatisch übersetzt
  • $2-3 Gesamtkosten für die komplette Übersetzung
  • 2-Minuten Update-Zyklus beim Hinzufügen neuer Strings
  • Null manuelle Übersetzungsarbeit
  • Kontextbewusste, hochwertige Übersetzungen

Vergleich das mal mit:

  • Menschlichen Übersetzern: $0.10-0.30 pro Wort = $1.000+
  • Traditionellen Agenturen: Immer noch teuer, immer noch langsam
  • Manueller Arbeit: Skaliert nicht

Warum das 2026 wichtig ist

Hör zu, das Web ist global. Wenn du 2026 nur Englisch auslieferst, lässt du 90% der Welt außen vor.

Aber traditionelles i18n ist schmerzhaft. Dieser Ansatz macht es trivial:

  1. Code mit Trans/t Makros schreiben (dauert 2 Sekunden)
  2. pnpm i18n ausführen (automatisiert)
  3. An die Welt shippen (Profit)

Die Kombination aus Linguis Developer Experience + LLM-gestützten Übersetzungen ist ein echter Gamechanger. Du bekommst:

  • Typsichere Übersetzungen
  • Null Runtime-Overhead
  • Automatische Extraktion
  • Kontextbewusste KI-Übersetzungen
  • Pfennigbeträge pro Sprache
  • Unendliche Skalierbarkeit

Weiterführende Ideen

Willst du noch einen draufsetzen? Versuch das:

Dynamische Content-Übersetzung

Speichere Übersetzungen in deiner Datenbank:

// packages/db/schema/content.ts
export const blogPosts = pgTable("blog_post", {
  id: varchar("id", { length: 255 }).primaryKey(),
  titleEn: text("title_en"),
  titleZhCn: text("title_zh_cn"),
  titleJa: text("title_ja"),
  // ... usw.
});

Auto-Übersetzung beim Speichern:

import { translateWithLLM } from "@acme/i18n";

export const blogRouter = createTRPCRouter({
  create: protectedProcedure
    .input(z.object({ title: z.string() }))
    .mutation(async ({ input }) => {
      // In alle Sprachen übersetzen
      const translations = await Promise.all(
        LOCALES.map(async (locale) => {
          const result = await translateWithLLM(
            [{ msgid: input.title, msgstr: "" }],
            locale
          );
          return [locale, result[0].msgstr];
        })
      );

      await db.insert(blogPosts).values({
        id: generateId(),
        titleEn: input.title,
        ...Object.fromEntries(translations),
      });
    }),
});

User-Provided Translations

Lass Nutzer bessere Übersetzungen vorschlagen:

export const i18nRouter = createTRPCRouter({
  suggestTranslation: publicProcedure
    .input(z.object({
      msgid: z.string(),
      locale: z.string(),
      suggestion: z.string(),
    }))
    .mutation(async ({ input }) => {
      await db.insert(translationSuggestions).values(input);

      // Maintainer benachrichtigen
      await sendEmail({
        to: "i18n@acme.com",
        subject: `New translation suggestion for ${input.locale}`,
        body: `"${input.msgid}" → "${input.suggestion}"`,
      });
    }),
});

A/B Testing für Übersetzungen

Teste, welche Übersetzungen besser konvertieren:

const variant = await abTest.getVariant("pricing-cta", locale);

const ctaText = variant === "A"
  ? t`Start Your Free Trial`
  : t`Try acme Free`;

Der Code

All das ist Production-Code aus einer echten App. Die volle Implementierung liegt in unserem Monorepo:

t3-acme-app/
├── apps/nextjs/
│   ├── lingui.config.ts
│   ├── src/
│   │   ├── locales/           # Kompilierte Kataloge
│   │   ├── utils/i18n/        # i18n Utilities
│   │   └── providers/         # LinguiClientProvider
│   └── script/i18n.ts         # Übersetzungs-Skript
└── packages/i18n/
    └── src/
        ├── translateWithLLM.ts
        ├── enhanceTranslations.ts
        └── utils.ts

Abschließende Gedanken

Eine mehrsprachige AI-App im Jahr 2026 zu bauen ist nicht mehr schwer. Die Tools sind da:

  • Lingui für Extraktion und Runtime
  • Claude/GPT für kontextbewusste Übersetzung
  • T3 Turbo für die beste DX im Spiel

Hör auf, Tausende für Übersetzungen zu zahlen. Hör auf, deine App auf Englisch zu beschränken.

Baue global. Shippe schnell. Nutze KI.

So machen wir das 2026.


Fragen? Probleme? Find mich auf Twitter oder check die Lingui Docs und AI SDK Docs.

Und jetzt geh und shippe diese mehrsprachige App. Die Welt wartet.

Teilen

Feng Liu

Feng Liu

shenjian8628@gmail.com

So baust du 2026 eine moderne, KI-gestützte Web-App mit i18n | Feng Liu