Настройка
Подготовка учебного проекта
Введение
Это более подробное руководство по настройке простого проекта Next.js с использованием gt-next.
Мы проведём вас от начала до конца: от создания проекта до его перевода.
По ходу урока мы перейдём от простых к более продвинутым концепциям.
Предполагается, что вы в целом знакомы с TypeScript, Next.js и React.
Вот список тем, которые мы рассмотрим в этом руководстве:
- Настройка нового проекта Next.js
- Использование компонента
<T>для перевода приложения - Использование компонент переменных, таких как
<Var>,<Currency>,<DateTime>и<Num>, для перевода динамического контента - Использование ветвящихся компонент, таких как
<Plural>и<Branch>, для перевода условного контента - Использование i18n‑маршрутизации в вашем приложении
Наше приложение будет простым и позволит проверять курс конвертации между валютами.
Мы будем использовать только встроенные стили и библиотеку gt-next, чтобы оставить решение максимально лёгким.
Этот пример основан на руководстве Currency Converter на GeeksforGeeks.
Настройка приложения Next
Сначала создадим новое приложение Next.js. Для этого выполните следующую команду:
npx create-next-app@latestЭто откроет мастер настройки, где вы сможете выбрать имя приложения и шаблон, который хотите использовать.
Для этого руководства укажите имя currencies и выберите «Yes», когда вас спросят, хотите ли вы использовать TypeScript.
Перейдите в каталог проекта и запустим приложение!
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",
};
/**
* This function is meant to simulate an api fetch request to get the current exchange.
* Waits for 1 second before returning the exchange rate.
* @returns the exchange rate between two currencies
*/
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>
);
}Итоги
Насколько полезно это руководство?