Next.js統合

@lingo.dev/compilerは、WebpackとTurbopackの両方をサポートする非同期設定ラッパーを通じてNext.js App Routerと統合されます。

セットアップ

1. パッケージのインストール

pnpm install @lingo.dev/compiler

2. Next.jsの設定

next.config.tsを更新して、非同期withLingo()ラッパーを使用します:

import type { NextConfig } from "next";
import { withLingo } from "@lingo.dev/compiler/next";

const nextConfig: NextConfig = {
  // Your existing Next.js config
};

export default async function (): Promise<NextConfig> {
  return await withLingo(nextConfig, {
    sourceRoot: "./app",
    sourceLocale: "en",
    targetLocales: ["es", "de", "fr"],
    models: "lingo.dev",
    dev: {
      usePseudotranslator: true,
    },
  });
}

なぜ非同期なのか? ラッパーはプラグインを遅延ロードし、設定を動的に解決します。これによりビルドを高速に保ち、条件付きプラグインロードを可能にします。

3. プロバイダーの追加

ルートレイアウトでLingoProviderを使用してアプリをラップします:

// app/layout.tsx
import { LingoProvider } from "@lingo.dev/compiler/react";

export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <LingoProvider>
      <html>
        <body>{children}</body>
      </html>
    </LingoProvider>
  );
}

重要: LingoProvider<html>の内側に配置し、すべてのコンテンツをラップします。サーバーコンポーネントとクライアントコンポーネントの両方で動作します。

Reactサーバーコンポーネント

コンパイラはReactサーバーコンポーネント(RSC)を完全にサポートしています。サーバーコンポーネントはビルド時に翻訳され、翻訳はサーバー出力に埋め込まれます。

// app/page.tsx (Server Component)
export default function Page() {
  return (
    <div>
      <h1>Welcome to our app</h1>
      <p>This is a server component—translated at build time</p>
    </div>
  );
}

サーバーコンポーネント内の翻訳されたテキストに対して、クライアント側のJavaScriptは追加されません。

クライアントコンポーネント

クライアントコンポーネントの場合は、"use client"ディレクティブを使用します:

"use client";

import { useLingoContext } from "@lingo.dev/compiler/react";

export function LanguageSwitcher() {
  const { locale, setLocale } = useLingoContext();

  return (
    <select value={locale} onChange={(e) => setLocale(e.target.value)}>
      <option value="en">English</option>
      <option value="es">Español</option>
      <option value="de">Deutsch</option>
    </select>
  );
}

クライアントコンポーネントは最適化された翻訳バンドルを受け取ります。そのコンポーネントで使用される翻訳のみが含まれます。

ロケール検出

デフォルトでは、ロケールはCookie(locale)に保存されます。コンパイラは自動的にロケール検出と永続化を処理します。

カスタムサーバーロケール検出

カスタムロジック(データベース、ヘッダー、サブドメイン)の場合は、.lingo/locale-resolver.server.tsを作成します:

// .lingo/locale-resolver.server.ts
import { headers } from "next/headers";

export async function getServerLocale(): Promise<string> {
  const headersList = await headers();
  const acceptLanguage = headersList.get("accept-language");

  // Parse accept-language header
  const locale = acceptLanguage?.split(",")[0]?.split("-")[0] || "en";

  return locale;
}

この関数は、すべてのリクエストに対してサーバー上で呼び出されます。ロケールコード(例:"en""es")を返す必要があります。

カスタムクライアントロケール永続化

カスタムクライアント側ロジック(localStorage、URLパラメータ)の場合、.lingo/locale-resolver.client.tsを作成します:

// .lingo/locale-resolver.client.ts
export function getClientLocale(): string {
  // Check URL parameter first
  const params = new URLSearchParams(window.location.search);
  const urlLocale = params.get("lang");
  if (urlLocale) return urlLocale;

  // Fall back to localStorage
  return localStorage.getItem("locale") || "en";
}

export function persistLocale(locale: string): void {
  localStorage.setItem("locale", locale);

  // Optionally update URL
  const url = new URL(window.location.href);
  url.searchParams.set("lang", locale);
  window.history.replaceState({}, "", url.toString());
}

詳細については、カスタムロケールリゾルバーを参照してください。

ロケールルーティング用ミドルウェア

ロケールベースのルーティング(/en/about/es/about)が必要な場合は、Next.jsミドルウェアを実装します:

// middleware.ts
import { NextRequest, NextResponse } from "next/server";

const locales = ["en", "es", "de", "fr"];
const defaultLocale = "en";

export function middleware(request: NextRequest) {
  const { pathname } = request.nextUrl;

  // Check if pathname already has a locale
  const pathnameHasLocale = locales.some(
    (locale) => pathname.startsWith(`/${locale}/`) || pathname === `/${locale}`
  );

  if (pathnameHasLocale) return;

  // Get locale from cookie or accept-language header
  const localeCookie = request.cookies.get("locale")?.value;
  const acceptLanguage = request.headers.get("accept-language");
  const locale =
    localeCookie ||
    acceptLanguage?.split(",")[0]?.split("-")[0] ||
    defaultLocale;

  // Redirect to localized pathname
  request.nextUrl.pathname = `/${locale}${pathname}`;
  return NextResponse.redirect(request.nextUrl);
}

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

ルートを更新して[locale]動的セグメントを使用します:

app/
  [locale]/
    page.tsx
    about/
      page.tsx
    layout.tsx

ビルド設定

開発ビルド

{
  dev: {
    usePseudotranslator: true, // Fast fake translations
  }
}

npm run devを実行して、即座に疑似翻訳を使用した開発サーバーを起動します。

本番ビルド

{
  buildMode: "cache-only", // Use pre-generated translations
}

npm run buildを実行して本番用にビルドします。APIキーは不要です。翻訳は.lingo/metadata.jsonから取得されます。

**ベストプラクティス:**本番用にビルドする前に、CIで実際の翻訳を生成してください。推奨されるワークフローについては、ビルドモードを参照してください。

Turbopackサポート

コンパイラーはWebpackとTurbopack(Next.js 15以降)の両方で動作します。

開発環境でTurbopackを使用するには:

next dev --turbo

コンパイラーは適切なバンドラーを自動的に検出して設定します。

TypeScript

コンパイラは完全に型付けされています。@lingo.dev/compilerから型をインポートしてください:

import type { LingoConfig } from "@lingo.dev/compiler";

const config: LingoConfig = {
  sourceRoot: "./app",
  sourceLocale: "en",
  targetLocales: ["es", "de"],
  models: "lingo.dev",
};

よくある問題

「モジュール'@lingo.dev/compiler/react'が見つかりません」 パッケージがインストールされていることを確認してください: pnpm install @lingo.dev/compiler

LingoProviderを追加後、HMRが動作しない LingoProviderがルートレイアウトに正しく配置されており、ネストされたレイアウトやページに配置されていないことを確認してください。

本番ビルドで翻訳が表示されない buildMode: "cache-only"を使用していること、および.lingo/metadata.jsonにすべてのロケールの翻訳が含まれていることを確認してください。

「ロケールXの翻訳が見つかりません」 開発サーバーをusePseudotranslator: falseで実行して実際の翻訳を生成するか、CIビルドを実行して.lingo/metadata.jsonに翻訳を追加してください。

次のステップ