Lingo.dev CLI překládá soubory Markdoc i JSON katalogy řetězců uživatelského rozhraní přes nakonfigurovaný lokalizační engine. Markdoc je autorský formát postavený na Markdownu s typovanými vlastními tagy napojenými na React – skvěle se proto hodí pro weby na Next.js App Routeru, které kombinují dlouhý obsah s interaktivními komponentami.
Tento návod vás provede lokalizací webu na Next.js App Routeru od začátku do konce: od konfigurace CLI přes organizaci obsahu podle jazyků a vykreslování Markdoc v dynamických routách až po automatizaci překladů pomocí GitHub Actions.
Ukázkový repozitář
Naklonujte si nebo forkněte lingodotdev/markdoc-nextjs-localization-example a pokračujte podle návodu. Repozitář obsahuje funkční aplikaci na Next.js App Routeru s obsahem v Markdoc, konfigurací Lingo.dev CLI a workflow pro GitHub Actions.
Jak funguje lokalizace v Next.js + Markdoc#
Většina webů na Next.js App Routeru rozděluje lokalizovaný obsah do dvou vrstev:
| Vrstva | Co sem patří | Ukázkový soubor |
|---|---|---|
| Dlouhý obsah | Marketingové stránky, dokumentace, blogové příspěvky | src/content/[locale]/pages/home.md |
| Řetězce uživatelského rozhraní | Popisky navigace, CTA, stavy tlačítek | src/content/[locale]/ui.json |
Routy žijí pod src/app/[lang]/ a při zpracování požadavku načítají soubory pro odpovídající jazyk. Middleware vybere výchozí jazyk z hlavičky prohlížeče Accept-Language a přesměruje základní cesty jako / na /en (nebo na nejbližší shodu).
Bucket markdoc v CLI parsuje soubory Markdoc se zachováním frontmatteru i vlastních tagů a bucket json zpracovává katalog řetězců uživatelského rozhraní. Oba překládají pouze změny přes váš lokalizační engine a zapisují soubory pro jednotlivé jazyky vedle zdrojových souborů.
Předpoklady#
Vytvořte lokalizační engine
Každé spuštění CLI posílá obsah přes lokalizační engine – konfiguraci, která určuje, jaký model LLM, glosář, hlas značky a instrukce se použijí. Vytvořte ho v Lingo.dev dashboardu a vygenerujte API klíč.
Ověřte verzi Node.js
CLI vyžaduje Node.js 18 nebo novější:
node -vPřipravte projekt v Next.js
Váš projekt potřebuje App Router (src/app/) a adresář s obsahem pro jednotlivé jazyky. Ukázkový repozitář používá src/content/[locale]/ se dvěma podsložkami (pages/ a blog/) a souborem ui.json. Základy routování najdete v internationalization v Next.js.
Uspořádejte obsah#
Rozdělte obsah podle jeho role. Dlouhé stránky a příspěvky se píšou v Markdoc, zatímco krátké řetězce uživatelského rozhraní žijí v JSON, aby je komponenty mohly načítat přímo.
src/content/
en/ # Source locale
pages/home.md # Long-form Markdoc
blog/hello.md
ui.json # UI strings (navbar, CTAs, button states)
es/ # Target locales – generated by Lingo.dev
fr/
de/Soubory Markdoc podporují frontmatter pro metadata jednotlivých stránek (title, description, date, author) a vlastní tagy, které se vykreslují jako React komponenty. Minimální stránka vypadá takto:
---
title: Author once in Markdoc, ship in every language.
description: An example Next.js App Router app that localizes Markdoc with Lingo.
---
{% inline-callout type="info" %}
This page is authored in Markdoc and translated by Lingo.dev.
{% /inline-callout %}
## Built from three pieces
Markdoc custom tags render as React components – even interactive ones.Nakonfigurujte CLI#
V kořenovém adresáři projektu vytvořte soubor i18n.json. Deklarujte dva buckety – jeden pro obsah v Markdoc a druhý pro katalog řetězců uživatelského rozhraní:
{
"$schema": "https://lingo.dev/schema/i18n.json",
"version": "1.15",
"locale": {
"source": "en",
"targets": ["es", "fr", "de"]
},
"buckets": {
"markdoc": {
"include": [
"src/content/[locale]/pages/*.md",
"src/content/[locale]/blog/*.md"
]
},
"json": {
"include": ["src/content/[locale]/ui.json"]
}
}
}Zástupný symbol [locale] se vyhodnotí na každý nakonfigurovaný kód jazyka. Při použití source: "en" CLI čte z src/content/en/ a zapisuje přeložené soubory do src/content/es/, src/content/fr/ a src/content/de/.
Katalogy v jednom souboru
Pokud vaše řetězce uživatelského rozhraní nejsou rozdělené do jednoho souboru pro každý jazyk, ale žijí v jediném vícejazyčném JSON souboru, použijte typ bucketu json-per-locale. Kompletní seznam typů bucketů najdete v Static Content Localization.
Vykreslení Markdoc v App Routeru#
Typická dynamická route načte dokument a vykreslí transformovaný strom. Ukázkový repozitář k tomu přidává malý helper:
// src/lib/markdoc.ts
export async function loadDoc(
locale: Locale,
collection: "pages" | "blog",
slug: string,
) {
const raw = await fs.readFile(
path.join(process.cwd(), "src/content", locale, collection, `${slug}.md`),
"utf8",
);
const ast = Markdoc.parse(raw);
const frontmatter = ast.attributes.frontmatter
? parseFrontmatter(ast.attributes.frontmatter)
: {};
const content = Markdoc.transform(ast, { ...schema, variables: { frontmatter } });
return { frontmatter, content };
}Stránka v App Routeru je jen tenká vrstva, která propojí dokument s řetězci uživatelského rozhraní pro daný jazyk:
// src/app/[lang]/page.tsx
export default async function Home({ params }: PageProps<"/[lang]">) {
const { lang } = await params;
const doc = await loadDoc(lang, "pages", "home");
const { home } = await getMessages(lang);
return (
<main>
<h1>{doc.frontmatter.title}</h1>
{renderMarkdoc(doc.content)}
</main>
);
}Vlastní tagy Markdoc (callout, bento, blog-hero atd.) jsou deklarované v markdoc.schema.ts a napojené na React komponenty v src/components/markdoc/. Kompletní API najdete v Markdoc schema docs.
Detekce jazyka v middleware#
Middleware v Next.js kontroluje požadavek ještě před vykreslením routy. Použijte ho k přesměrování základních cest na nejlépe odpovídající jazyk podle hlavičky Accept-Language:
// src/middleware.ts
export function middleware(request: NextRequest) {
const { pathname } = request.nextUrl;
const hasLocale = locales.some(
(locale) => pathname === `/${locale}` || pathname.startsWith(`/${locale}/`),
);
if (hasLocale) return;
const locale = pickLocale(request); // parses Accept-Language
const url = request.nextUrl.clone();
url.pathname = `/${locale}${pathname === "/" ? "" : pathname}`;
return NextResponse.redirect(url);
}
export const config = {
matcher: ["/((?!_next|api|.*\\..*).*)", ],
};Návštěvníci se tak dostanou na /en, /es, /fr nebo /de, aniž by prefix kdy sami psali.
Překládejte lokálně#
Nastavte API klíč a spusťte CLI:
export LINGO_API_KEY="your-api-key"
npx lingo.dev@latest runCLI načte všechny soubory odpovídající vzorům vašich bucketů, pomocí lockfile identifikuje nepřeložené položky, přeloží jen změny přes váš lokalizační engine a zapíše výsledky do adresáře každého cílového jazyka. Klíče frontmatteru, vlastní tagy Markdoc i struktura JSON zůstávají zachované – mění se pouze přeložitelný text.
Pokud chcete při vývoji cílit na konkrétní jazyk:
npx lingo.dev@latest run --target-locale esAutomatizujte pomocí GitHub Actions#
Přidejte workflow soubor do .github/workflows/translate.yml, aby se překlad spouštěl při každém pushi:
Překlady se commitují přímo do main – bez zbytečných překážek, ideální pro malé týmy:
name: Translate
on:
push:
branches: [main]
permissions:
contents: write
jobs:
translate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Lingo.dev
uses: lingodotdev/lingo.dev@main
with:
api-key: ${{ secrets.LINGODOTDEV_API_KEY }}Uložte API klíč jako LINGODOTDEV_API_KEY v Settings > Secrets and variables > Actions ve svém GitHub repozitáři.
Ověřte vše před nasazením#
Použijte příznak --frozen jako podmínku nasazení, abyste měli jistotu, že se do produkce nedostane žádný nepřeložený obsah. Pokud některé položky čekají na překlad, CLI skončí s nenulovým stavem:
npx lingo.dev@latest run --frozenPřidejte tento krok jako samostatnou CI fázi před buildem Next.js:
- name: Verify translations
run: npx lingo.dev@latest run --frozen
- name: Build
run: pnpm build