Näin rakennat modernin i18n AI-verkkosovelluksen vuonna 2026
Kattava opas monikielisten web-sovellusten rakentamiseen Linguin ja AI-käännösten avulla. Automatisoi tuki 17 kielelle käyttäen Next.js:ää, Claudea ja T3 Turboa.

Title: Kuule, meidän täytyy puhua i18n:stä vuonna 2026
Excerpt: Useimmat i18n-tutoriaalit ovat jämähtäneet menneisyyteen. Tässä artikkelissa näytän, kuinka rakensimme tuotantotason verkkosovelluksen, joka puhuu sujuvasti 17 kieltä käyttäen Next.js:ää, Lingui:ta ja tekoälyä – murto-osalla perinteisistä kustannuksista.
Content: Kuule, meidän täytyy puhua i18n:stä vuonna 2026.
Useimmat tutoriaalit neuvovat sinua kääntämään merkkijonot käsin, palkkaamaan kääntäjiä tai käyttämään jotain kömpelöä Google Translate API:a. Mutta tässä on juttu: elät Claude Sonnet 4.5 -aikakaudella. Miksi käännät sovellustasi kuin elettäisiin vuotta 2019?
Aion näyttää, kuinka rakensimme tuotantotason verkkosovelluksen, joka puhuu sujuvasti 17 kieltä. Käytimme kaksiosaista i18n-arkkitehtuuria, jossa on oikeasti järkeä:
- Lingui hoitaa erottelun (extraction), kääntämisen (compilation) ja ajonaikaisen taikuuden
- Kustomoitu i18n-paketti, joka hyödyntää LLM:iä automatisoituun, kontekstitietoiseen kääntämiseen
Meidän tech stack? Create T3 Turbo, jossa on Next.js, tRPC, Drizzle, Postgres, Tailwind ja AI SDK. Jos et käytä tätä vuonna 2026, meidän täytyy käydä eri keskustelu.
Rakennetaan.
Ongelma perinteisessä i18n:ssä
Perinteiset i18n-työnkulut näyttävät tältä:
# Erottele merkkijonot (Extract)
$ lingui extract
# ??? Hanki käännökset jotenkin ???
# (palkkaa kääntäjiä, käytä hämäriä palveluita, itke)
# Käännä (Compile)
$ lingui compile
Tuo keskimmäinen vaihe? Se on painajainen. Olet joko:
- Maksamassa maltaita ihmiskääntäjistä (hidasta, kallista)
- Käyttämässä perus käännös-API:eja (ei ymmärrä kontekstia, kuulostaa robotilta)
- Kääntämässä käsin (ei skaalaudu)
Me teemme tämän paremmin.
Kaksiosainen arkkitehtuuri
Tässä on meidän setup:
┌─────────────────────────────────────────────┐
│ Next.js App (Lingui-integraatio) │
│ ├─ Erottele merkkijonot macroilla │
│ ├─ Trans/t -komponentit koodissasi │
│ └─ Ajonaikainen i18n käännöskatalogeilla │
└─────────────────────────────────────────────┘
↓ generoi .po -tiedostot
┌─────────────────────────────────────────────┐
│ @acme/i18n Package (LLM-käännös) │
│ ├─ Lukee .po -tiedostot │
│ ├─ Kääntää erissä Claude/GPT-5:llä │
│ ├─ Kontekstitietoinen, tuotespesifi │
│ └─ Kirjoittaa käännetyt .po -tiedostot │
└─────────────────────────────────────────────┘
↓ kääntää TypeScriptiksi
┌─────────────────────────────────────────────┐
│ Compiled Message Catalogs │
│ └─ Nopeat, tyypitetyt ajonaikaiset käännökset │
└─────────────────────────────────────────────┘
Osa 1 (Lingui) hoitaa kehittäjäkokemuksen (DX). Osa 2 (Kustomoitu i18n-paketti) hoitaa käännöstaikuuden.
Sukelletaanpa kumpaankin.

Osa 1: Lingui:n asennus Next.js:ään
Asennus
T3 Turbo -monorepossa:
# Hakemistossa apps/nextjs
pnpm add @lingui/core @lingui/react @lingui/macro
pnpm add -D @lingui/cli @lingui/swc-plugin
Lingui Config
Luo 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 kieltä heti kättelyssä. Koska miksi ei?
Next.js Integraatio
Päivitä next.config.js käyttämään Linguin SWC-pluginia:
const linguiConfig = require("./lingui.config");
module.exports = {
experimental: {
swcPlugins: [
[
"@lingui/swc-plugin",
{
// Tämä nopeuttaa buildiasi
},
],
],
},
// ... loput konfiguraatiostasi
};
Server-Side Setup
Luo 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>>();
// Luo i18n-instanssit valmiiksi kaikille kielille
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")!;
}
Miksi? Server Componenteilla ei ole React Contextia. Tämä mahdollistaa palvelinpuolen käännökset.
Client-Side Provider
Luo 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>;
}
Kääri sovelluksesi tiedostossa layout.tsx:
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>
);
}
Käännösten käyttö koodissa
Server Componenteissa:
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`),
};
}
Client Componenteissa:
"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>
{/* Muuttujien kanssa */}
<p>{t`${credits} credits remaining`}</p>
</div>
);
}
Macro-syntaksi on AVAIN. Lingui erottelee nämä build-vaiheessa.
Osa 2: Tekoälyllä toimiva käännöspaketti
Nyt homma menee mielenkiintoiseksi.
Paketin rakenne
Luo packages/i18n/:
packages/i18n/
├── package.json
├── src/
│ ├── translateWithLLM.ts # LLM-käännöksen ydin
│ ├── enhanceTranslations.ts # Eräajoprosessori
│ └── utils.ts # Apufunktiot
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"
}
}
LLM-käännösmoottori
Tässä on salainen ainesosa – 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, // Matala = johdonmukaisempi
});
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",
// ... jne
};
return names[locale] ?? locale;
}
Miksi tämä toimii:
- Kontekstitietoinen: LLM tietää mikä "acme" on
- Strukturoitu ulostulo: Zod-skeema varmistaa validin JSON:in
- Matala lämpötila (temperature): Johdonmukaiset käännökset
- Säilyttää muotoilun: HTML ja muuttujat pysyvät ehjinä
Eräajoprosessori (Batch Processor)
Luo enhanceTranslations.ts:
import fs from "fs";
import path from "path";
import pofile from "pofile";
import { translateWithLLM } from "./translateWithLLM";
const BATCH_SIZE = 30; // Käännä 30 merkkijonoa kerralla
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"));
// Etsi kääntämättömät kohdat
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}...`);
// Prosessoi erissä
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);
// Päivitä PO-tiedosto
translations.forEach((translation, index) => {
const item = batch[index];
if (item) {
item.msgstr = [translation.msgstr];
}
});
console.log(` ${i + batch.length}/${untranslated.length} translated`);
// Tallenna edistyminen
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}`);
// Jatka seuraavaan erään
}
}
console.log(`✓ ${locale}: Translation complete!`);
}
Eräajo (Batch processing) estää token-rajojen ylittymisen ja säästää kustannuksia.
Käännösskripti
Luo 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() {
// Vaihe 1: Erottele merkkijonot koodista
console.log("📝 Extracting strings...");
await execAsync("pnpm run lingui:extract --clean");
// Vaihe 2: Automaattikäännä puuttuvat merkkijonot
console.log("\n🤖 Translating with AI...");
const catalogPath = "./src/locales";
for (const locale of LOCALES) {
await enhanceTranslations(locale, catalogPath);
}
// Vaihe 3: Käännä TypeScriptiksi
console.log("\n⚡ Compiling catalogs...");
await execAsync("npx lingui compile --typescript");
console.log("\n✅ Done! All translations updated.");
}
main().catch(console.error);
Lisää package.json -tiedostoon:
{
"scripts": {
"i18n": "tsx script/i18n.ts",
"lingui:extract": "lingui extract",
"lingui:compile": "lingui compile --typescript"
}
}
i18n-putken ajaminen
# Yksi komento hallitsemaan kaikkia
$ 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.
Siinä se. Lisää uusi merkkijono koodiisi, aja pnpm i18n, boom – käännetty 17 kielelle.

Kielen vaihtaminen (Locale Switching)
Älä unohda käyttäjäkokemusta (UX). Tässä on kielenvalitsin:
"use client";
import { useLocaleSwitcher } from "@/hooks/useLocaleSwitcher";
import { useLocale } from "@/hooks/useLocale";
const LOCALES = {
en: "English",
zh_CN: "简体中文",
zh_TW: "繁體中文",
ja: "日本語",
ko: "한국어",
// ... jne
};
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>
);
}
Hookin toteutus:
// hooks/useLocaleSwitcher.tsx
"use client";
import { setUserLocale } from "@/utils/i18n/localeDetection";
export function useLocaleSwitcher() {
const switchLocale = (locale: string) => {
setUserLocale(locale);
window.location.reload(); // Pakota uudelleenlataus kielen vaihtamiseksi
};
return { switchLocale };
}
Tallenna preferenssi evästeeseen:
// 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 vuosi
});
}
export function getLocale(): string {
const cookieStore = cookies();
return cookieStore.get("NEXT_LOCALE")?.value ?? "en";
}
Edistynyttä: Tyypitetyt käännökset
Haluatko tyyppiturvallisuutta? Lingui hoitaa homman:
// Tämän sijaan:
t`Hello ${name}`
// Käytä msg descriptoria:
import { msg } from "@lingui/core/macro";
const greeting = msg`Hello ${name}`;
const translated = i18n._(greeting);
IDE:si täydentää käännösavaimet automaattisesti. Kaunista.
Suorituskykyyn liittyvät huomiot
1. Käännä build-vaiheessa (Compile at Build Time)
Lingui kääntää käännökset minifikoiduksi JSON:ksi. Ei ajonaikaista jäsennyskuormaa.
// Käännetty output (minifikoitu):
export const messages = JSON.parse('{"ICt8/V":["视频"],"..."}');
2. Esilataa palvelinkatalogit
Lataa kaikki katalogit kerran käynnistyksen yhteydessä (katso appRouterI18n.ts yllä). Ei tiedosto-I/O:ta jokaisella pyynnöllä.
3. Client Bundle -koko
Toimita asiakkaalle vain aktiivinen kieli:
<LinguiClientProvider
locale={locale}
messages={allMessages[locale]} // Vain yksi kieli
>
4. LLM-kustannusten optimointi
- Eräkäännökset: 30 merkkijonoa per API-kutsu
- Välimuisti: Älä käännä muuttumattomia merkkijonoja uudelleen
- Käytä halvempia malleja: GPT-4o-mini vähemmän kriittisille kielille
Meidän kustannukset? ~$2-3 dollaria 800+ merkkijonosta × 16 kieltä. Senttejä verrattuna ihmiskääntäjiin.
Koko Tech Stackin integraatio
Katsotaanpa, miten tämä toimii yhteen muun T3 Turbon kanssa:
tRPC ja 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 }) => {
// Virheet voidaan myös kääntää!
if (!ctx.session?.user) {
throw new TRPCError({
code: "UNAUTHORIZED",
message: ctx.i18n._(msg`You must be logged in`),
});
}
// ... tilauslogiikka
}),
});
Välitä i18n-instanssi kontekstin kautta:
// 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,
};
};
Tietokanta ja Drizzle
Tallenna käyttäjän kielivalinta:
// 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"),
// ... muut kentät
});
AI SDK Integraatio
Käännä tekoälyn vastaukset lennosta:
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 };
}
Parhaat käytännöt, jotka opimme
1. Käytä aina Macroja
// ❌ Huono: Ajonaikainen käännös (ei erotella)
const text = t("Hello world");
// ✅ Hyvä: Macro (erotellaan build-vaiheessa)
const text = t`Hello world`;
2. Konteksti on kaikki kaikessa
Lisää kommentteja kääntäjille:
// i18n: This appears in the pricing table header
<Trans>Monthly</Trans>
// i18n: Button to submit payment form
<button>{t`Subscribe Now`}</button>
Lingui erottelee nämä kääntäjän muistiinpanoiksi.
3. Hoida monikot oikein
import { Plural } from "@lingui/react/macro";
<Plural
value={count}
one="# credit remaining"
other="# credits remaining"
/>
Eri kielillä on eri monikkosäännöt. Lingui hoitaa tämän.
4. Päivämäärä/Numero -muotoilu
Käytä Intl API:a:
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-tuki
Arabian kielelle, hoida suunta (direction):
export default function RootLayout({ children }) {
const locale = getLocale();
const direction = locale === "ar" ? "rtl" : "ltr";
return (
<html lang={locale} dir={direction}>
<body>{children}</body>
</html>
);
}
Lisää Tailwind-konfiguraatioon:
module.exports = {
plugins: [
require('tailwindcss-rtl'),
],
};
Käytä suuntaan perustuvia luokkia:
<div className="ms-4"> {/* margin-start, toimii sekä LTR/RTL */}
Deployment-tarkistuslista
Ennen kuin julkaiset:
- Aja
pnpm i18nvarmistaaksesi, että kaikki käännökset ovat ajan tasalla - Testaa jokainen kieli tuotantotilassa
- Varmista kieli-evästeen säilyminen
- Tarkista RTL-asettelu arabian kielelle
- Testaa kielenvalitsimen UX
- Lisää hreflang-tagit SEO:ta varten
- Aseta kieleen perustuva reititys tarvittaessa
- Seuraa LLM-käännöskustannuksia
Tulokset
Tämän järjestelmän käyttöönoton jälkeen:
- 17 kieltä tuettuna heti kättelyssä
- ~850 merkkijonoa käännetty automaattisesti
- $2-3 kokonaiskustannus täydelle käännökselle
- 2 minuutin päivityssykli uusia merkkijonoja lisätessä
- Nolla manuaalista käännöstyötä
- Kontekstitietoiset, korkealaatuiset käännökset
Verrataanpa tätä:
- Ihmiskääntäjät: $0.10-0.30 per sana = $1,000+
- Perinteiset palvelut: Yhä kalliita, yhä hitaita
- Manuaalinen työ: Ei skaalaudu
Miksi tällä on väliä vuonna 2026
Kuule, verkko on globaali. Jos toimitat sovelluksesi vain englanniksi vuonna 2026, jätät 90% maailmasta ulkopuolelle.
Mutta perinteinen i18n on tuskallista. Tämä lähestymistapa tekee siitä triviaalia:
- Kirjoita koodia Trans/t -macroilla (vie 2 sekuntia)
- Aja
pnpm i18n(automatisoitu) - Toimita maailmalle (tuottoa)
Yhdistelmä Linguin kehittäjäkokemusta + LLM-pohjaisia käännöksiä on pelin muuttaja. Saat:
- Tyypitetyt käännökset
- Nollakuormituksen ajonaikana
- Automaattisen erottelun
- Kontekstitietoiset AI-käännökset
- Senttejä per kieli
- Skaalautuu loputtomiin
Menossa pidemmälle
Haluatko viedä homman seuraavalle tasolle? Kokeile:
Dynaamisen sisällön kääntäminen
Tallenna käännökset tietokantaasi:
// 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"),
// ... jne
});
Automaattikäännä tallennuksen yhteydessä:
import { translateWithLLM } from "@acme/i18n";
export const blogRouter = createTRPCRouter({
create: protectedProcedure
.input(z.object({ title: z.string() }))
.mutation(async ({ input }) => {
// Käännä kaikille kielille
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),
});
}),
});
Käyttäjien tarjoamat käännökset
Anna käyttäjien ehdottaa parempia käännöksiä:
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);
// Ilmoita ylläpitäjille
await sendEmail({
to: "i18n@acme.com",
subject: `New translation suggestion for ${input.locale}`,
body: `"${input.msgid}" → "${input.suggestion}"`,
});
}),
});
Käännösten A/B-testaus
Testaa mitkä käännökset konvertoivat paremmin:
const variant = await abTest.getVariant("pricing-cta", locale);
const ctaText = variant === "A"
? t`Start Your Free Trial`
: t`Try acme Free`;
Koodi
Kaikki tämä on tuotantokoodia oikeasta sovelluksesta. Täysi toteutus löytyy monorepostamme:
t3-acme-app/
├── apps/nextjs/
│ ├── lingui.config.ts
│ ├── src/
│ │ ├── locales/ # Käännetyt katalogit
│ │ ├── utils/i18n/ # i18n apufunktiot
│ │ └── providers/ # LinguiClientProvider
│ └── script/i18n.ts # Käännösskripti
└── packages/i18n/
└── src/
├── translateWithLLM.ts
├── enhanceTranslations.ts
└── utils.ts
Lopuksi
Monikielisen AI-sovelluksen rakentaminen vuonna 2026 ei ole enää vaikeaa. Työkalut ovat täällä:
- Lingui erotteluun ja ajonaikaiseen toimintaan
- Claude/GPT kontekstitietoiseen kääntämiseen
- T3 Turbo parhaaseen mahdolliseen kehittäjäkokemukseen
Lopeta tuhansien maksaminen käännöksistä. Lopeta sovelluksesi rajoittaminen vain englantiin.
Rakenna globaalisti. Toimita nopeasti. Käytä tekoälyä.
Näin me teemme sen vuonna 2026.
Kysymyksiä? Ongelmia? Löydät minut Twitteristä tai tsekkaa Lingui docs ja AI SDK docs.
Nyt mene ja julkaise se monikielinen sovellus. Maailma odottaa.
Jaa tämä

Kirjoittanut Feng Liu
shenjian8628@gmail.com