Use Cases

Comment implémenter efficacement l'i18n avec Claude Code

Découvrez comment implémenter efficacement l'i18n avec Claude Code. Conseils pratiques et exemples de code inclus.

多言語対応でClaude Codeが活きる場面

国際化(i18n)の実装は、翻訳ファイルの管理、ロケール切り替え、日付・数値のフォーマット、RTL対応など多岐にわたります。Claude Codeはこれらの作業を一括で処理し、翻訳漏れのチェックまで行えます。

Next.jsでのi18n基盤構築

> Next.js App Routerでnext-intlを使った多言語対応を設定して。
> 日本語と英語をサポートして。URLパスにロケールを含める形式で。

ディレクトリ構成

src/
  messages/
    ja.json
    en.json
  app/
    [locale]/
      layout.tsx
      page.tsx
  i18n/
    request.ts
    routing.ts

ルーティング設定

// src/i18n/routing.ts
import { defineRouting } from 'next-intl/routing';

export const routing = defineRouting({
  locales: ['ja', 'en'],
  defaultLocale: 'ja',
  pathnames: {
    '/': '/',
    '/about': {
      ja: '/about',
      en: '/about',
    },
    '/blog': {
      ja: '/blog',
      en: '/blog',
    },
  },
});
// src/i18n/request.ts
import { getRequestConfig } from 'next-intl/server';
import { routing } from './routing';

export default getRequestConfig(async ({ requestLocale }) => {
  let locale = await requestLocale;
  if (!locale || !routing.locales.includes(locale as 'ja' | 'en')) {
    locale = routing.defaultLocale;
  }

  return {
    locale,
    messages: (await import(`../messages/${locale}.json`)).default,
  };
});

翻訳ファイル

// src/messages/ja.json
{
  "common": {
    "siteName": "マイアプリ",
    "navigation": {
      "home": "ホーム",
      "about": "概要",
      "blog": "blog",
      "contact": "お問い合わせ"
    },
    "footer": {
      "copyright": "© {year} マイアプリ. All rights reserved."
    }
  },
  "home": {
    "hero": {
      "title": "最高のサービスを提供します",
      "subtitle": "{count, plural, =0 {ユーザーはまだいません} one {# 人のユーザー} other {# 人のユーザー}}が利用中"
    }
  }
}
// src/messages/en.json
{
  "common": {
    "siteName": "MyApp",
    "navigation": {
      "home": "Home",
      "about": "About",
      "blog": "Blog",
      "contact": "Contact"
    },
    "footer": {
      "copyright": "© {year} MyApp. All rights reserved."
    }
  },
  "home": {
    "hero": {
      "title": "We provide the best service",
      "subtitle": "{count, plural, =0 {No users yet} one {# user} other {# users}} using our service"
    }
  }
}

コンポーネントでの使用

import { useTranslations } from 'next-intl';

export default function HomePage() {
  const t = useTranslations('home');
  const tc = useTranslations('common');

  return (
    <main>
      <h1>{t('hero.title')}</h1>
      <p>{t('hero.subtitle', { count: 1500 })}</p>

      <nav aria-label={tc('navigation.home')}>
        <a href="/">{tc('navigation.home')}</a>
        <a href="/about">{tc('navigation.about')}</a>
      </nav>
    </main>
  );
}

翻訳の一括生成

Claude Codeに翻訳ファイルの生成を依頼できます。

> src/messages/ja.json を元に英語の翻訳ファイルを生成して。
> 技術用語はそのまま英語で、UIテキストは自然な英語にして。

翻訳漏れのチェック

> ja.jsonとen.jsonのキーを比較して、翻訳漏れがないかチェックして。
> 不足しているキーがあれば追加して。
// scripts/check-translations.ts
import ja from '../src/messages/ja.json';
import en from '../src/messages/en.json';

function getKeys(obj: object, prefix = ''): string[] {
  return Object.entries(obj).flatMap(([key, value]) => {
    const path = prefix ? `${prefix}.${key}` : key;
    if (typeof value === 'object' && value !== null) {
      return getKeys(value as object, path);
    }
    return [path];
  });
}

const jaKeys = new Set(getKeys(ja));
const enKeys = new Set(getKeys(en));

const missingInEn = [...jaKeys].filter(k => !enKeys.has(k));
const missingInJa = [...enKeys].filter(k => !jaKeys.has(k));

if (missingInEn.length) {
  console.log('Missing in en.json:', missingInEn);
}
if (missingInJa.length) {
  console.log('Missing in ja.json:', missingInJa);
}

日付・数値のフォーマット

import { useFormatter } from 'next-intl';

function PriceDisplay({ amount, date }: { amount: number; date: Date }) {
  const format = useFormatter();

  return (
    <div>
      <p>{format.number(amount, { style: 'currency', currency: 'USD' })}</p>
      <time>{format.dateTime(date, { year: 'numeric', month: 'long', day: 'numeric' })}</time>
      <p>{format.relativeTime(date)}</p>
    </div>
  );
}
// ja: $1,500 / 2026年3月24日 / 2週間前
// en: $1,500 / March 24, 2026 / 2 weeks ago

言語切り替えコンポーネント

'use client';
import { useRouter, usePathname } from 'next/navigation';
import { useLocale } from 'next-intl';

function LanguageSwitcher() {
  const locale = useLocale();
  const router = useRouter();
  const pathname = usePathname();

  const switchLocale = (newLocale: string) => {
    const newPath = pathname.replace(`/${locale}`, `/${newLocale}`);
    router.push(newPath);
  };

  return (
    <div role="radiogroup" aria-label="Language selection">
      <button
        role="radio"
        aria-checked={locale === 'ja'}
        onClick={() => switchLocale('ja')}
        className={locale === 'ja' ? 'font-bold' : ''}
      >
        日本語
      </button>
      <button
        role="radio"
        aria-checked={locale === 'en'}
        onClick={() => switchLocale('en')}
        className={locale === 'en' ? 'font-bold' : ''}
      >
        English
      </button>
    </div>
  );
}

Summary

Claude Codeを使えば、i18n基盤の構築から翻訳ファイルの生成、翻訳漏れのチェックまでを効率的に進められます。特に翻訳ファイルの一括生成と整合性チェックは、Claude Codeの強みが発揮される場面です。プロジェクトの多言語対応方針はCLAUDE.mdに記述しておくと一貫性を保てます。またプロンプトテクニックを使って翻訳の品質を高めることもできます。

Claude Codeの詳細はAnthropic公式ドキュメントをご覧ください。

#Claude Code #i18n #internationalization #multilingual #React