# gt-react: General Translation React SDK: Mini Shop を国際化する URL: https://generaltranslation.com/ja/docs/react/tutorials/mini-shop.mdx --- title: Mini Shop を国際化する description: GT React コンポーネント、フック、共有文字列を使って、シンプルなショップを国際化する実践的な React チュートリアル --- 小さくて完全にローカルな「ミニショップ」を動かしながら翻訳対応していきます。外部サービス、ルーティング、UI フレームワークは不要です。GT React の主要機能をひととおり使い、シンプルで実践的な UI の中でそれらがどう組み合わさるかを確認できます。 前提条件: React、JavaScript/TypeScript の基礎知識 作成するもの * 商品グリッドとシンプルなインメモリのカートを備えたシングルページの「ショップ」 * 言語切り替え機能と共有ナビゲーションラベル * 適切に国際化された数値、通貨、複数形処理 * 任意: 本番ビルド向けのローカル翻訳ストレージ このチュートリアルで使用するリンク * プロバイダー: [``](/docs/react/api/components/gtprovider) * コンポーネント: [``](/docs/react/api/components/t), [``](/docs/react/api/components/var), [``](/docs/react/api/components/num), [``](/docs/react/api/components/currency), [``](/docs/react/api/components/datetime), [``](/docs/react/api/components/branch), [``](/docs/react/api/components/plural), [``](/docs/react/api/components/locale-selector) * 文字列と共有文字列: [`useGT`](/docs/react/api/strings/use-gt), [`msg`](/docs/react/api/strings/msg), [`useMessages`](/docs/react/api/strings/use-messages) * ガイド: [変数](/docs/react/guides/variables), [分岐](/docs/react/guides/branches), [文字列](/docs/react/guides/strings), [ローカル翻訳ストレージ](/docs/react/guides/local-tx), [言語の切り替え](/docs/react/guides/languages) *** ## インストールしてアプリをプロバイダーでラップする パッケージをインストールし、プロバイダーでアプリをラップします。 ```bash npm i gt-react npm i --save-dev gt ``` ```bash yarn add gt-react yarn add --dev gt ``` ```bash bun add gt-react bun add --dev gt ``` ```bash pnpm add gt-react pnpm add --save-dev gt ``` 任意: スタータープロジェクト (Vite) ゼロから始める場合は、まず Vite の React + TypeScript アプリを作成し、その後で GT パッケージをインストールします。 ```bash copy npm create vite@latest mini-shop -- --template react-ts cd mini-shop npm i gt-react npm i --save-dev gt ``` 次に、以下のセクションにあるファイル (例: `src/main.tsx`, `src/App.tsx`, `src/components/*`, `src/data.ts`, `src/nav.ts`) を追加します。 最小限のプロバイダーセットアップを作成します。 ```tsx title="src/main.tsx" copy import { StrictMode } from 'react'; import { createRoot } from 'react-dom/client'; import { GTProvider } from 'gt-react'; // 参照: /docs/react/api/components/gtprovider import App from './App'; createRoot(document.getElementById('root')!).render( {/* スペイン語とフランス語を有効化 */} ); ``` 必要に応じて、ここで `gt.config.json` を追加できます (後で CI やローカルストレージで役立ちます) : ```json title="gt.config.json" copy { "defaultLocale": "en", "locales": ["es", "fr"] } ``` ### 開発用 API キー キーがなくてもこのチュートリアルを進められます (デフォルト言語で表示されます) 。開発中にライブ翻訳を確認したり、言語切り替えをテストしたりするには、開発用キーを追加してください。 詳しくは、[Production vs Development](/docs/react/concepts/environments) を参照してください。 ```bash title=".env.local" copy VITE_GT_API_KEY="your-dev-api-key" VITE_GT_PROJECT_ID="your-project-id" ``` ```bash title=".env.local" copy REACT_APP_GT_API_KEY="your-dev-api-key" REACT_APP_GT_PROJECT_ID="your-project-id" ``` * ダッシュボード: https://dash.generaltranslation.com/signup * または CLI で取得: ```bash copy npx gt auth ``` *** ## シードデータとアプリの構成 小さな商品配列をハードコードし、すべてクライアント側で完結させます。サーバーもルーティングも使いません。 ```ts title="src/data.ts" copy export type Product = { id: string; name: string; description: string; price: number; currency: 'USD' | 'EUR'; inStock: boolean; addedAt: string; // ISO日付文字列 }; export const products: Product[] = [ { id: 'p-1', name: 'Wireless Headphones', description: 'Noise-cancelling over-ear design with 30h battery', price: 199.99, currency: 'USD', inStock: true, addedAt: new Date().toISOString() }, { id: 'p-2', name: 'Travel Mug', description: 'Double-wall insulated stainless steel (12oz)', price: 24.5, currency: 'USD', inStock: false, addedAt: new Date().toISOString() } ]; ``` *** ## msg と useMessages を使った共有ナビゲーションラベル 設定で共有文字列をマークするには [`msg`](/docs/react/api/strings/msg) を使い、レンダリング時に [`useMessages`](/docs/react/api/strings/use-messages) でデコードします。 ```tsx title="src/nav.ts" copy import { msg } from 'gt-react'; // 参照: /docs/react/api/strings/msg export const nav = [ { label: msg('Home'), href: '#' }, { label: msg('Products'), href: '#products' }, { label: msg('Cart'), href: '#cart' } ]; ``` ```tsx title="src/components/Header.tsx" copy import { LocaleSelector, T } from 'gt-react'; import { useMessages } from 'gt-react'; // 参照: /docs/react/api/strings/use-messages import { nav } from '../nav'; export default function Header() { const m = useMessages(); return (

Mini Shop

{/* 参照: /docs/react/api/components/t */}
{/* 参照: /docs/react/api/components/locale-selector */}
); } ``` *** ## T、変数、Branch、Currency を使う商品カード JSX の翻訳には [``](/docs/react/api/components/t) を使用します。動的コンテンツは、[``](/docs/react/api/components/var)、[``](/docs/react/api/components/num)、[``](/docs/react/api/components/currency)、[``](/docs/react/api/components/datetime) などの変数コンポーネントで囲みます。在庫状態は [``](/docs/react/api/components/branch) で処理します。 ```tsx title="src/components/ProductCard.tsx" copy import { T, Var, Num, Currency, DateTime, Branch } from 'gt-react'; import type { Product } from '../data'; export default function ProductCard({ product, onAdd }: { product: Product; onAdd: () => void; }) { return (

{product.name}

{product.description}

Price: {product.price}

Added: {new Date(product.addedAt)}

In stock

} false={

Out of stock

} />
); } ``` *** ## 複数形処理と合計金額を扱うカート 「カート内の X 個の商品」は [``](/docs/react/api/components/plural) で表し、合計金額には [``](/docs/react/api/components/currency) を使用します。[``](/docs/react/api/components/t)、[``](/docs/react/api/components/var)、[``](/docs/react/api/components/num) と組み合わせて使います。 ```tsx title="src/components/Cart.tsx" copy import { T, Plural, Var, Num, Currency } from 'gt-react'; import type { Product } from '../data'; export default function Cart({ items, onClear }: { items: Product[]; onClear: () => void; }) { const total = items.reduce((sum, p) => sum + p.price, 0); const itemCount = items.length; return (

Cart

Your cart is empty

} one={

You have {itemCount} item

} other={

You have {itemCount} items

} />
{items.map((p) => (

{p.name}{p.price}

))}

Total: {total}

); } ``` *** ## `useGT` を使った属性とプレースホルダー input のプレースホルダーや ARIA ラベルなど、通常の文字列を翻訳するには [`useGT`](/docs/react/api/strings/use-gt) を使用します。 ```tsx title="src/components/Search.tsx" copy import { useGT } from 'gt-react'; export default function Search({ onQuery }: { onQuery: (q: string) => void; }) { const gt = useGT(); return ( onQuery(e.target.value)} style={{ padding: 8, width: '100%', maxWidth: 320 }} /> ); } ``` *** ## まとめ インメモリのカートとシンプルな検索フィルターを備えたシングルページアプリです。 ```tsx title="src/App.tsx" copy import { useMemo, useState } from 'react'; import Header from './components/Header'; import Search from './components/Search'; import ProductCard from './components/ProductCard'; import Cart from './components/Cart'; import { products } from './data'; export default function App() { const [query, setQuery] = useState(''); const [cart, setCart] = useState([]); const filtered = useMemo(() => { const q = query.toLowerCase(); return products.filter(p => p.name.toLowerCase().includes(q) || p.description.toLowerCase().includes(q) ); }, [query]); const items = products.filter(p => cart.includes(p.id)); return (
{filtered.map(p => ( setCart(c => (p.inStock ? [...new Set([...c, p.id])] : c))} /> ))}
setCart([])} />
); } ``` *** ## ローカルで実行する `package.json` に簡単な開発用スクリプトを追加し、アプリを起動します。 ```json title="package.json" copy { "scripts": { "dev": "vite" } } ``` 実行: ```bash npm run dev ``` ```json title="package.json" copy { "scripts": { "start": "react-scripts start" } } ``` 実行: ```bash npm start ``` *** ## 学んだこと * [``](/docs/react/api/components/t) を使った JSX の翻訳と、[``](/docs/react/api/components/var)、[``](/docs/react/api/components/num)、[``](/docs/react/api/components/currency)、[``](/docs/react/api/components/datetime) による動的コンテンツの扱い * [``](/docs/react/api/components/branch) による条件付きコンテンツの表現と、[``](/docs/react/api/components/plural) による数量の表現 * [`useGT`](/docs/react/api/strings/use-gt) を使った属性の翻訳 * [`msg`](/docs/react/api/strings/msg) を使ったナビゲーションや設定の文字列の共有と、[`useMessages`](/docs/react/api/strings/use-messages) によるデコード * [``](/docs/react/api/components/locale-selector) を使った言語の切り替え ## 次のステップ * 参考: [変数ガイド](/docs/react/guides/variables), [分岐ガイド](/docs/react/guides/branches), [文字列ガイド](/docs/react/guides/strings), [言語の切り替え](/docs/react/guides/languages)