セットアップ
チュートリアル用プロジェクトのセットアップ
はじめに
これは、gt-next を使ってごくシンプルな Next.js プロジェクトをセットアップする方法を、より詳しく解説するチュートリアルガイドです。
プロジェクトの準備から翻訳まで、最初から最後まで順を追って説明します。
このチュートリアルでは、基本からより高度な概念へと段階的に進めていきます。
このチュートリアルは、TypeScript、Next.js、React の基礎的な理解があることを前提としています。
このチュートリアルで扱う項目は次のとおりです:
- 新しい Next.js プロジェクトのセットアップ
- アプリを翻訳するための
<T>コンポーネントの使用 - 動的コンテンツを翻訳するための
<Var>、<Currency>、<DateTime>、<Num>などの Variable コンポーネントの使用 - 条件付きコンテンツを翻訳するための
<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へのデータ取得を擬似的に行い、2つの通貨間の為替レートを表示するだけです。
"use client";
import { useEffect, useState, useCallback } from "react";
// 2つの通貨間の為替レートのマップ(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 2つの通貨間の為替レート
*/
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]);
// from または to の通貨が変わるたびに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]);
// ユーザーが通貨を切り替えるたびに換算を実行
useEffect(() => {
convert();
}, [info, convert]);
// 2つの通貨を入れ替える関数
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>
);
}結論
このガイドはいかがですか?