Building a Country-to-Flag Emoji Converter App with Vite, TypeScript, and Tolgee

Introduction

Hello there friends, we're still in the season of Hacktoberfest and in this blog post, we'll build a simple Country-to-Flag Emoji Converter App. We will utilize some great tools and technologies:

  • Vite: A modern build tool that significantly improves the development experience with its fast hot module replacement (HMR) and optimized build processes. Vite is perfect for building fast applications and is particularly well-suited for projects using frameworks like React.

  • TypeScript: A superset of JavaScript that adds static typing. By using TypeScript, we can catch errors early in the development process, making our code more robust and maintainable. It enhances the developer experience by providing better autocompletion and type-checking capabilities.

  • Tailwind CSS: A utility-first CSS framework that allows for rapid design and styling of components. With Tailwind, we can easily create responsive layouts without the need for writing extensive CSS. It enables us to focus on building our application without getting bogged down in design details.

  • Tolgee: A powerful localization tool that simplifies the process of adding internationalization (i18n) to our app. With Tolgee, we can easily manage translations, enabling users from different linguistic backgrounds to interact with our app comfortably.

  • REST Countries API: An API that provides detailed information about countries, including their flags, names, and codes. This API will be the backbone of our application, allowing us to fetch flag emojis based on user input.

Let's dive into building our Country-to-Flag Emoji Converter!

Section 1: Setting Up the Project

Hold up, before we actually jump into coding, let’s set up our project environment. In this section, we will initialize a new Vite project with TypeScript, configure Tailwind CSS for styling, and integrate Tolgee for localization. This foundational setup is crucial for building a well-structured and maintainable application.

1. Initialize the Vite App

To start, we need to create a new Vite project configured for TypeScript. Vite offers a simple and quick setup process. Follow these steps:

  1. Open your terminal: Ensure you have Node.js and npm installed on your machine. You can check your installations with the following commands:

     node -v
     npm -v
    
  2. Create a new Vite project: Run the following command to create a new Vite project. Replace country-flag-emoji-converter with your desired project name:

     npm create vite@latest country-flag-emoji-converter -- --template react-ts
    
  3. Navigate to the project directory:

     cd country-flag-emoji-converter
    
  4. Install dependencies: Once inside the project directory, install the required dependencies:

     npm install
    
  5. Start the development server: Run the following command to start the Vite development server:

     npm run dev
    

    Open your browser and navigate to http://localhost:5173/ to see your Vite app in action. You should see the default Vite welcome screen.

2. Install and Configure Tailwind CSS

Now that we have our Vite app set up, we can proceed to install and configure Tailwind CSS. Tailwind CSS allows for rapid and responsive UI development using utility classes.

  1. Install Tailwind CSS: Use npm to install Tailwind CSS and its peer dependencies:

     npm install -D tailwindcss postcss autoprefixer
    
  2. Initialize Tailwind CSS: After installation, initialize Tailwind CSS. This will create a tailwind.config.js file in your project:

     npx tailwindcss init -p
    
  3. Configure Tailwind to remove unused styles in production: Open the tailwind.config.js file and update the content array to include your HTML and TypeScript files:

     /** @type {import('tailwindcss').Config} */
     module.exports = {
       content: [
         "./index.html",
         "./src/**/*.{js,ts,jsx,tsx}",
       ],
       theme: {
         extend: {},
       },
       plugins: [],
     };
    
  4. Add Tailwind’s directives to your CSS: Open the src/index.css file (or create one if it doesn’t exist) and add the following lines to include Tailwind’s base, components, and utilities:

     @tailwind base;
     @tailwind components;
     @tailwind utilities;
    
  5. Start your development server: If it’s not already running, start your Vite development server again with:

     npm run dev
    

    You can now use Tailwind CSS classes in your components to style your app.

3. Install Tolgee

To make our app accessible to users in different languages, we’ll integrate Tolgee for localization. Tolgee simplifies the process of managing translations in React applications.

  1. Install Tolgee: Run the following command to install Tolgee and its React package:

     npm install @tolgee/react
    
  2. Copy the code below to wrap your App component in your main.tsx file:

import { StrictMode } from "react"; import { createRoot } from "react-dom/client"; import { Tolgee, DevTools, TolgeeProvider, FormatSimple } from "@tolgee/react"; import App from "./App.tsx"; import "./index.css";

const tolgee = Tolgee().use(DevTools()).use(FormatSimple()).init({ language: "en",

// for development apiUrl: process.env.VITE_APP_TOLGEE_API_URL, apiKey: process.env.VITE_APP_TOLGEE_API_KEY,

});

createRoot(document.getElementById("root")!).render( );

**Create an env file for your keys**
Visit the [Tolgee website](app.tolgee.io) to get your API key and put in your env file like so:
```typescript
VITE_APP_TOLGEE_API_URL=https://app.tolgee.io
VITE_APP_TOLGEE_API_KEY=your-api-key

An error will popup in your main.tsx file so we're going to install type definitions for our vite app

npm i --save-dev @types/node

Now open your vite.config.ts file and paste the code below

import { defineConfig, loadEnv } from 'vite'
import react from '@vitejs/plugin-react'

// https://vitejs.dev/config/
export default defineConfig(({ mode }) => {
  const env = loadEnv(mode, process.cwd(), '');
  return {
    define: {
      'process.env.VITE_APP_TOLGEE_API_URL': JSON.stringify(env.VITE_APP_TOLGEE_API_URL),
      'process.env.VITE_APP_TOLGEE_API_KEY': JSON.stringify(env.VITE_APP_TOLGEE_API_KEY)
    },
    plugins: [react()],
  }
})

Now we have setup our project with Vite, TypeScript, Tailwind CSS, and Tolgee for localization. We’re ready to start building the core features of your Country-to-Flag Emoji Converter app. In the next sections, we will dive into creating the main functionality and user interface for our application.

Section 4: Building the main project

In your src folder, create a file called LanguageSelect.tsx and paste the code below

import { T, useTolgee } from "@tolgee/react";

export default function LanguageSelect() {
  const tolgee = useTolgee(["language"]);
  return (
    <div className="flex items-center space-x-2">
      <label
        htmlFor="language-select"
        className="block text-sm font-medium text-gray-700 mb-1"
      >
        <T keyName="label">Change App Language</T>
      </label>
      <select
        value={tolgee.getLanguage()}
        onChange={(e) => tolgee.changeLanguage(e.target.value)}
        className="border border-slate-500 z-50"
      >
        <option value="en">English</option>
        <option value="fr">Français</option>
        <option value="de">German</option>
      </select>
    </div>
  );
}

we import { T, useTolgee } from "@tolgee/react" to use the tolgee library

Here <T keyName="label">Change App Language</T>, we wrap the text in the T tag provided by tolgee to be able to translate the text to the other languages we listed in our option tags

Now open your App.tsx file and paste the code below

import { useState } from "react";
import { T, useTranslate } from "@tolgee/react";
import LanguageSelect from "./LanguageSelect";


export default function App() {
  const [country, setCountry] = useState("");
  const [flag, setFlag] = useState("");
  const { t } = useTranslate();

  const handleInputChange = (e: React.ChangeEvent<HTMLInputElement>) => {
    setCountry(e.target.value);
  };

  const fetchFlag = async () => {
    if (country.trim() === "") return;
    try {
      const response = await fetch(
        `https://restcountries.com/v3.1/name/${country}`
      );
      const data = await response.json();
      if (data && data[0] && data[0].flags) {
        setFlag(data[0].flags.png);
      } else {
        setFlag("Country not found");
      }
    } catch (error) {
      setFlag("Error fetching data");
    }
  };

  return (
    <>
      <div className="min-h-screen flex flex-col items-center justify-center bg-gray-100">
        <LanguageSelect />
        <div className="p-6 bg-white shadow-lg rounded-md w-full max-w-4xl text-center mt-4">
          <h1 className="font-bold text-3xl mb-4">
            <T keyName="app_title">
              Flagmoji | Country to Flag Emoji Converter
            </T>
          </h1>
          <T keyName="flag_emoji_short_text">
            Type a country name to see its flag emoji.
          </T>
          <div className="flex flex-col lg:flex-row lg:items-center lg:space-x-4">
            <div className="flex flex-col w-full lg:w-1/2 my-5 lg:mb-0">
              <input
                type="text"
                value={country}
                onChange={handleInputChange}
                placeholder={t("placeholder_country_name", "Enter country name")}
                className="border p-2 rounded-md mb-2 w-full"
              />
              <div className="flex items-start mt-3">
                <button
                  onClick={fetchFlag}
                  className="bg-slate-800 text-white py-1 px-4 rounded hover:bg-slate-900"
                >
                  <T keyName="button_fetch_flag">View</T>
                </button>
              </div>
            </div>
            {flag && (
              <div className="flex justify-center lg:w-1/2 mt-4 lg:mt-5">
                {flag.startsWith("http") ? (
                  <img src={flag} alt="Country flag" className="w-32 h-32" />
                ) : (
                  <p>{flag}</p>
                )}
              </div>
            )}
          </div>
        </div>
      </div>
    </>
  );
}

So we import { T, useTranslate } from "@tolgee/react" and in this line of code const { t } = useTranslate(); we use the destructuring assignment to extract the translation function t from the object returned by the useTranslate hook.

The function const fetch flag is to call the Rest Countries API and use it in our app

We wrap this text using the T tag to be able to translate them <T keyName="app_title">Flagmoji | Country to Flag Emoji Converter</T> <T keyName="flag_emoji_short_text">Type a country name to see its flag emoji.</T>

and here as well placeholder={t("placeholder_country_name", "Enter country name")}

Now open the app in your browser localhost:5173/, you should see this:

Screenshot

Section 5. Translating our App

On your browser, hold down your ALT key and hover over the Change App Language text and tap on it. A popup should appear like so:

Screenshot

write down the text you want to translate in the English text box and scroll down and click create

Go to your tolgee app dashboard, click on the translations tab and locate the new key you just created

Screenshot

On the right in the picture above, select the language and the translation and save. Voila!, you just added translations to your app. Now do the same for the other text we wrapped with the T tag

Conclusion

In this blog post, we just built a simple Country-to-Flag Emoji Converter app. Leveraging the powerful combination of Vite for fast development, TypeScript for type safety, Tailwind CSS for responsive design, and Tolgee for seamless internationalization. The flexibility of these tools allowed us to efficiently implement key features and customize the app according to our needs.

Got any questions? Ask me in the comments

Happy coding!

0
Subscribe to my newsletter

Read articles from Anietie Brownson directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Anietie Brownson
Anietie Brownson