设置
设置教程项目
介绍
这是一篇更为深入的教程,讲解如何使用 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";
// A map between two currencies and their exchange rate (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 },
};
// some styles for button
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() {
// exch rates
const [info, setInfo] = useState<ExchTable>({});
const options = ["usd", "inr", "eur", "jpy", "gbp"];
// currencies
const [from, setFrom] = useState("usd");
const [to, setTo] = useState("inr");
// values
const [input, setInput] = useState(0);
const [output, setOutput] = useState(0);
// Function to convert the currency
const convert = useCallback(() => {
if (info?.[from]?.[to]) {
const rate = info[from][to];
setOutput(input * rate);
} else {
setOutput(0);
}
}, [info, input, to, from]);
// Calling the api whenever from or to currency changes
useEffect(() => {
// If the exchange rate is already present, then convert
if (info?.[from]?.[to]) {
convert();
return;
}
// Fetch the exchange rate
(async () => {
const response = await fetchExchangeRate(from, to);
// Enter new response without overwriting old info
setInfo((prevInfo) => ({
...prevInfo,
[from]: {
...(prevInfo?.[from] || undefined),
[to]: response,
},
}));
})();
}, [from, to, convert, info]);
// Call convert whenever a user switches the currency
useEffect(() => {
convert();
}, [info, convert]);
// Function to switch between two currency
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" }}>
<h3>金额</h3>
<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">
<h3>源货币</h3>
</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">
<h3>目标货币</h3>
</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>
<h2>转换结果:</h2>
<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>
);
}总结
本指南如何?