设置
配置一个示例教程项目
介绍
这是一份更深入的教程,讲解如何使用 gt-next 搭建一个非常简单的 Next.js 项目。
我们将从零开始带你完成整个流程,包括项目搭建与翻译。
在本教程中,我们会从基础逐步推进到更高级的概念。
本教程假设你对 TypeScript、Next.js 和 React 有基本了解。
以下是本教程将涵盖的内容:
- 创建一个新的 Next.js 项目
- 使用 <T>组件为应用做翻译
- 使用 <Var>、<Currency>、<DateTime>和<Num>等变量组件翻译动态内容
- 使用 <Plural>和<Branch>等分支组件翻译条件内容
- 在应用中使用 i18n 路由
我们将构建一个简单的应用,用于查询不同货币之间的转换汇率。
我们只会使用内联样式,并且只使用 gt-next 库,以尽可能保持精简。
本示例基于 GeeksforGeeks 上的 Currency Converter 教程构建。
设置你的 Next 应用
首先,我们来创建一个新的 Next.js 应用。你可以运行以下命令:
npx create-next-app@latest这将带你进入设置向导,在那里你可以选择应用的名称和要使用的模板。
在本教程中,将名称设为 currencies,并在询问是否使用 TypeScript 时选择 Yes。
进入项目目录,开始启动应用吧!
cd currencies
npm install
npm run dev这会在 http://localhost:3000 启动应用。
让我们添加一些内容!
现在我们的应用已设置好,让我们改写应用的内容来展示一个简单的货币转换器。
只需将以下代码复制并粘贴到 src/app/page.tsx 和 src/app/layout.tsx 文件中。
暂时不用太在意它是如何工作的。 这段代码只是模拟从货币汇率 API 拉取数据,并显示两种货币之间的汇率。
"use client";
import { useEffect, useState, useCallback } from "react";
// 货币对与其汇率的映射(from -> to)
type ExchTable = Record<string, Record<string, number>>;
const EXCH_RATES: ExchTable = {
  usd: { usd: 1, inr: 73.5, eur: 0.85, jpy: 105.45, gbp: 0.72 },
  inr: { usd: 0.014, inr: 1, eur: 0.012, jpy: 1.46, gbp: 0.01 },
  eur: { usd: 1.18, inr: 85.5, eur: 1, jpy: 123.5, gbp: 0.85 },
  jpy: { usd: 0.0095, inr: 0.68, eur: 0.0081, jpy: 1, gbp: 0.0068 },
  gbp: { usd: 1.39, inr: 99.5, eur: 1.17, jpy: 146.5, gbp: 1 },
};
// 按钮样式
const buttonStyle = {
  backgroundColor: "#007bff",
  color: "white",
  border: "none",
  padding: "10px 20px",
  cursor: "pointer",
  borderRadius: "5px",
  fontSize: "16px",
  margin: "20px",
};
/**
 * 该函数用于模拟一次 API 拉取请求以获取当前汇率。
 * 在返回汇率前等待 1 秒。
 * @returns 两种货币之间的汇率
 */
async function fetchExchangeRate(from: string, to: string): Promise<number> {
  await new Promise((resolve) => setTimeout(resolve, 1000));
  return EXCH_RATES[from][to];
}
function Page() {
  // 汇率信息
  const [info, setInfo] = useState<ExchTable>({});
  const options = ["usd", "inr", "eur", "jpy", "gbp"];
  // 货币
  const [from, setFrom] = useState("usd");
  const [to, setTo] = useState("inr");
  // 金额
  const [input, setInput] = useState(0);
  const [output, setOutput] = useState(0);
  // 货币转换函数
  const convert = useCallback(() => {
    if (info?.[from]?.[to]) {
      const rate = info[from][to];
      setOutput(input * rate);
    } else {
      setOutput(0);
    }
  }, [info, input, to, from]);
  // 每当源货币或目标货币变化时调用 API
  useEffect(() => {
    // 如果已存在汇率,则直接转换
    if (info?.[from]?.[to]) {
      convert();
      return;
    }
    // 获取汇率
    (async () => {
      const response = await fetchExchangeRate(from, to);
      // 在不覆盖旧数据的情况下写入新结果
      setInfo((prevInfo) => ({
        ...prevInfo,
        [from]: {
          ...(prevInfo?.[from] || undefined),
          [to]: response,
        },
      }));
    })();
  }, [from, to, convert, info]);
  // 每当用户切换货币时调用 convert
  useEffect(() => {
    convert();
  }, [info, convert]);
  // 切换两种货币的函数
  function flip() {
    const temp = from;
    setFrom(to);
    setTo(temp);
  }
  return (
    <div style={{ margin: "0 auto", width: "50%", textAlign: "center" }}>
      <div style={{ margin: "20px 0", paddingBottom: "20px" }}>
        <h1 style={{ fontSize: "2.5em", fontWeight: "bold" }}>
          货币转换器
        </h1>
      </div>
      <div style={{ flex: 2, textAlign: "center", margin: "20px 0" }}>
        金额
        <input
          type="text"
          placeholder="请输入金额"
          style={{ textAlign: "center" }}
          onChange={(e) => {
            setInput(Number(e.target.value));
          }}
        />
      </div>
      <div
        style={{ display: "flex", justifyContent: "center", margin: "20px 0" }}
      >
        <div style={{ flex: 1, textAlign: "center" }}>
          <label htmlFor="from">
            源货币
          </label>
          <select
            name="from"
            id="from"
            value={from}
            onChange={(e) => setFrom(e.target.value)}
          >
            {options.map((option) => (
              <option key={option} value={option}>
                {option.toUpperCase()}
              </option>
            ))}
          </select>
        </div>
        <div style={{ flex: 1, textAlign: "center" }}>
          <button
            onClick={() => {
              flip();
            }}
            style={buttonStyle}
          >
            互换
          </button>
        </div>
        <div style={{ flex: 1, textAlign: "center" }}>
          <label htmlFor="to">
            目标货币
          </label>
          <select
            name="to"
            id="to"
            value={to}
            onChange={(e) => setTo(e.target.value)}
          >
            {options.map((option) => (
              <option key={option} value={option}>
                {option.toUpperCase()}
              </option>
            ))}
          </select>
        </div>
      </div>
      <div style={{ margin: "0 auto", width: "50%", textAlign: "center" }}>
        <button
          onClick={() => {
            convert();
          }}
          style={buttonStyle}
        >
          转换
        </button>
        转换结果:
        <p>{input + " " + from + " = " + output.toFixed(2) + " " + to}</p>
      </div>
    </div>
  );
}
export default Page;import type { Metadata } from "next";
import { Geist, Geist_Mono } from "next/font/google";
import "./globals.css";
const geistSans = Geist({
  variable: "--font-geist-sans",
  subsets: ["latin"],
});
const geistMono = Geist_Mono({
  variable: "--font-geist-mono",
  subsets: ["latin"],
});
export const metadata: Metadata = {
  title: "货币转换器",
  description: "一个简单的货币转换器",
};
export default function RootLayout({
  children,
}: Readonly<{
  children: React.ReactNode;
}>) {
  return (
    <html lang="en">
      <body
        className={`${geistSans.variable} ${geistMono.variable} antialiased`}
      >
        {children}
      </body>
    </html>
  );
}总结
这份指南怎么样?

