Currency Converter

Configuración

Configurar un proyecto de tutorial

Introducción

Este es un tutorial más detallado sobre cómo configurar un proyecto muy simple de NextJS usando gt-next. Te llevaremos desde el principio hasta el final, incluyendo la configuración del proyecto y luego su traducción. A lo largo de este tutorial, construiremos nuestro camino desde conceptos simples hasta más avanzados. Este tutorial asume que tienes un entendimiento general de Typescript, Next.js y React.

Aquí hay una lista de elementos que cubriremos en este tutorial:

  • Configuración de un nuevo proyecto de Next.js
  • Uso del componente <T> para traducir una aplicación
  • Uso de componentes de variable como <Var>, <Currency>, <DateTime>, y <Num> para traducir contenido dinámico
  • Uso de componentes de rama como <Plural>, y <Branch> para traducir contenido condicional
  • Uso de enrutamiento i18n en tu aplicación

Nuestra aplicación será una aplicación simple que nos permitirá verificar la tasa de conversión entre monedas. Solo usaremos estilos en línea y solo la biblioteca gt-next para mantener las cosas lo más simples posible. Este ejemplo fue construido basado en el tutorial de Currency Converter en GeeksforGeeks.

Configura Tu Próxima Aplicación

Primero, vamos a crear una nueva aplicación NextJS. Puedes hacerlo ejecutando el siguiente comando:

npx create-next-app@latest

Esto te llevará al asistente de configuración, donde puedes elegir el nombre de tu aplicación y la plantilla que deseas usar. Para este tutorial, usa el nombre currencies y selecciona cuando se te pregunte si deseas usar TypeScript.

Navega al directorio del proyecto, ¡y comencemos la aplicación!

cd currencies
npm install
npm run dev

Esto iniciará la aplicación en http://localhost:3000.

¡Agreguemos Algo de Contenido!

Ahora que tenemos nuestra aplicación configurada, vamos a sobrescribir el contenido de nuestra aplicación para mostrar un simple convertidor de divisas. Simplemente copia y pega el siguiente código en los archivos src/app/page.tsx y src/app/layout.tsx.

No te preocupes demasiado por cómo funciona por ahora. Todo este código hace es simular una obtención de datos de una API de intercambio de divisas y muestra la tasa de cambio entre dos monedas.

src/app/page.tsx
"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" }}>
          Convertidor de Moneda
        </h1>
      </div>
      <div style={{ flex: 2, textAlign: "center", margin: "20px 0" }}>
        <h3>Cantidad</h3>
        <input
          type="text"
          placeholder="Ingrese la cantidad"
          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>De</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}
          >
            Cambiar
          </button>
        </div>
        <div style={{ flex: 1, textAlign: "center" }}>
          <label htmlFor="to">
            <h3>A</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}
        >
          Convertir
        </button>
        <h2>Cantidad Convertida:</h2>
        <p>{input + " " + from + " = " + output.toFixed(2) + " " + to}</p>
      </div>
    </div>
  );
}

export default Page;
src/app/layout.tsx
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: "Currency Converter",
  description: "A simple currency converter",
};

export default function RootLayout({
  children,
}: Readonly<{
  children: React.ReactNode;
}>) {
  return (
    <html lang="en">
      <body
        className={`${geistSans.variable} ${geistMono.variable} antialiased`}
      >
        {children}
      </body>
    </html>
  );
}

Conclusión

Ahora tienes una aplicación normal de NextJS configurada y lista para ser traducida usando gt-next.

¿Qué te parece esta guía?