# gt-react: General Translation React SDK: 为迷你商店实现国际化 URL: https://generaltranslation.com/zh/docs/react/tutorials/mini-shop.mdx --- title: 为迷你商店实现国际化 description: 一篇实操型 React 教程,使用 GT React 组件、钩子和共享字符串为一个简单商店实现国际化 --- 搭建一个小巧、完全本地运行的“迷你商店”,并完成翻译——无需外部服务、无需路由、无需 UI 框架。你将端到端使用 GT React 的核心功能,并了解它们如何在一个简单但贴近实际的 UI 中协同工作。 前提条件:React、基础 JavaScript/TypeScript 你将构建的内容 * 一个带有商品网格和简单内存购物车的单页“商店” * 语言切换器和共享导航标签 * 正确国际化处理数字、货币和复数 * 可选:用于生产构建的本地翻译存储 本教程中使用的链接 * Provider:[``](/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) *** ## 安装并用 Provider 包裹应用 安装相关包,并用 provider 包裹你的应用。 ```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`) 。 创建一个最小的 Provider 设置。 ```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 密钥 即使没有密钥,你也可以按照本教程操作 (页面会显示默认语言) 。如果你想在开发环境中查看实时翻译并测试语言切换,请添加开发环境密钥。 更多信息请参见[生产环境与开发环境](/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 的商品卡片 使用 [``](/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) 处理库存状态。 ```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

} />
); } ``` *** ## 购物车中的复数形式与总额 使用 [``](/docs/react/api/components/plural) 表达“购物车中有 X 件商品”,使用 [``](/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` 处理属性和占位符 对于输入框占位符和 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)