我最近參與了一個令人興奮的項目,涉及創建一個能夠在不同語言之間切換以吸引更廣泛受眾的網站。這讓我更好地理解了“本地化”的概念,通常包括調整內容,使其對不同語言和地區的用戶具有相關性、可訪問性和共鳴性。

本地化不僅僅是翻譯文字,更重要的是創造一種讓用戶無論語言如何都感到親切的體驗。例如,像亞馬遜這樣的全球平台使語言切換變得如此流暢,幾乎讓人感覺神奇。除了增強用戶體驗,這一功能在擴大業務規模、觸及更廣泛的受眾並促進與全球客戶之間建立更緊密聯繫方面發揮著至關重要的作用。

目錄

什麼是 i18n,為什麼要使用它?

i18n,即國際化縮寫,表示應用程序支持多種語言。”i18n”源於在”internationalization”中的第一個”i”和最後一個”n”之間有18個字母這一事實。這一切都是為了使您的應用程序能夠適應全球受眾,通過處理文本翻譯、格式化日期和數字、管理貨幣以及符合區域慣例。

通過啟用國際化,您的應用程序不僅成為一個工具,更成為一個能夠直接迎合用戶喜好和文化的包容平台。

讓我們開始吧

我們將創建一個非常簡單的演示多語言網絡應用程序,帶有深色模式切換功能,以演示如何實現這一概念。

先決條件

  1. React的基本知識 – 您應該了解如何創建組件、管理狀態,以及使用像useStateuseEffect這樣的Hooks。如果您對React還不熟悉,我建議從官方React文檔開始打好扎實的基礎

  2. 熟悉國際化概念 – 瞭解國際化 (i18n) 的基礎知識以及其重要性將為您的項目提供背景。本文的前幾節涵蓋了基本內容。

  3. Tailwind CSS – 我們將使用 Tailwind CSS 進行樣式設計。這是一個實用優先的 CSS 框架,可幫助您構建現代、響應式設計,而不必離開 HTML。如果您不熟悉,請查看 Tailwind 的文檔

  4. Node.js – 確保系統已安裝 Node.js 以處理依賴項。您可以從 Node.js 下載最新版本。

  5. 套件管理器 – 需要 npm(隨 Node.js 包含)或 yarn 來管理項目依賴項

我們將使用的工具

  1. 程式碼編輯器

  2. 本地化庫: react-i18next

  3. 圖示庫: hero-icons

步驟1: 如何設定專案

初始化專案

使用 Vite 進行快速設置:

npm create vite@latest multilingual-demo

按照終端機中出現的指示,選擇開發時所需的 React 和 TypeScript,如下圖所示:

安裝依賴項

在終端機中運行以下命令以安裝此專案所需的依賴項:

npm install i18next react-i18next i18next-browser-languagedetector i18next-http-backend heroicons 
npm install tailwindcss postcss autoprefixer  
npx tailwindcss init

配置 TailwindCSS

更新 tailwind.config.ts 檔案:

/** @type {import('tailwindcss').Config} */
module.exports = {
  content: ["./src/**/*.{js,jsx,ts,tsx}"],
  darkMode: "class", // 用於我們的暗黑模式功能
  theme: {
    container: {
      center: true,
      padding: "1.25rem",
      screens: {
        sm: "1200px",
      },
    },
    extend: {},
  },
  plugins: [],
};

將 TailwindCSS 添加到 src/index.css

@tailwind base;  
@tailwind components;  
@tailwind utilities;

第 2 步:如何使用 i18next 設置國際化

初始化 i18next

src 文件夾中創建一個 i18n.tsx 文件並配置 i18next:

import i18next from "i18next";
import LanguageDetector from "i18next-browser-languagedetector";
import { initReactI18next } from "react-i18next";
import Backend from "i18next-http-backend";

i18next.use(LanguageDetector).use(initReactI18next).use(Backend).init({
  returnObjects: true,
  fallbackLng: "en", // 如果所選配置不存在,則回退到的語言
  debug: true, // 啟用我們查看錯誤
  //   lng: "en", //默認語言為英語
});

讓我們快速查看此文件的內容,因為它在啟用翻譯功能方面發揮著關鍵作用。 這個文件負責設置翻譯過程的核心,並確保語言切換功能在應用程序中平穩運行。

  • i18next:我們用於翻譯的核心國際化庫。

  • LanguageDetector:幫助我們根據瀏覽器設置自動檢測用戶偏好的語言。

  • initReactI18next:負責將 i18next 插件與 React 整合,並提供像 useTranslation Hook 和其他實用工具一樣的 Hooks。

  • Backend:動態從外部來源提取翻譯數據。在這種情況下,我們將使用 JSON 文件。

將此文件引入到 main.tsx 文件中:

//main.tsx

import React, { StrictMode } from "react";
import { createRoot } from "react-dom/client";
import "./index.css";
import App from "./App.tsx";
import "./i18n.tsx";  //在這裡引入

createRoot(document.getElementById("root")!).render(
  <StrictMode>
    <React.Suspense fallback="loading">
      <App />
    </React.Suspense>
  </StrictMode>
);

創建翻譯文件

public/locales 目錄中,為每種語言創建子文件夾(例如,enfr),並包括 translation.json 文件:

en/translation.json

{
    "greeting": "Welcome to the Language Playground",
    "detail": {
        "line1": "Did you know that over 7,000 languages are spoken worldwide?",
        "line2": "This Playground demonstrates how web applications can support users in multiple languages, making them accessible and inclusive to people from different backgrounds."
    }
}

fr/translation.json

{
    "greeting": "Bienvenue sur le terrain de jeu linguistique",
    "detail": {
        "line1": "Saviez-vous que plus de 7 000 langues sont parlées dans le monde ?",
        "line2": "Ce terrain de jeu démontre comment les applications web peuvent prendre en charge les utilisateurs dans plusieurs langues, les rendant accessibles et inclusives aux personnes de différents horizons."
    }
}

在這裡,您可以添加許多帶有其翻譯文件的語言,這些文件將提供給 i18next。請注意,JSON 文件中的鍵與在網站上顯示它們時將使用的鍵相同。

步驟 3:如何構建組件

src 目錄中創建一個 components 文件夾,並添加以下組件:

語言選擇器

建立 LanguageSelector 組件 – 包含一個 select 元素,幫助用戶動態切換語言:

import { useEffect, useState } from "react";
import i18next from "i18next";
import { useTranslation } from "react-i18next";

type languageOption = { language: string; code: string };

const languageOptions: languageOption[] = [
  {
    language: "English",
    code: "en",
  },
  { language: "French", code: "fr" },
  { language: "German", code: "de" },
  { language: "Spanish", code: "es" },
  { language: "Arabic", code: "ar" },
  { language: "Yoruba", code: "yo" },
];

const LanguageSelector = () => {
  // 從 i18next 檢測到的或預設的語言設置初始語言
  const [language, setLanguage] = useState(i18next.language);

  const { i18n } = useTranslation();

  const handleLanguageChange = (e: React.ChangeEvent<HTMLSelectElement>) => {
    const selectedLanguage = e.target.value;
    setLanguage(selectedLanguage);
    i18next.changeLanguage(selectedLanguage); // 在 i18next 中更新語言
  };

  useEffect(() => {
    document.body.dir = i18n.dir(); // 設置主體為從左到右或從右到左
  }, [i18n, i18n.language]);

  return (
    <select
      id="language"
      value={language}
      onChange={handleLanguageChange}
      className="p-2 border border-gray-300 rounded-md shadow-sm focus:border-indigo-500 focus:ring focus:ring-indigo-200 focus:ring-opacity-50
        dark:bg-gray-800 dark:border-gray-600 dark:text-gray-200 dark:focus:border-indigo-400 dark:focus:ring-indigo-700 dark:focus:ring-opacity-50"
    >
      {languageOptions.map(({ language, code }, key) => (
        <option value={code} key={key}>
          {language}
        </option>
      ))}
    </select>
  );
};

export default LanguageSelector;
  • 使用 i18next 檢測到的語言或預設語言初始化語言。

  • useTranslation Hook 提供 i18n 實例,讓你能與國際化設置互動。

  • handleLanguageChange 函數用來更新用戶選擇的語言。當用戶從下拉選單中選擇新語言時,該函數會被觸發。

實現文本方向

在 HTML 中,dir 屬性是確保網頁應用程式具有無障礙性和包容性的關鍵特性,特別是在處理文字方向不同的語言時。例如:

  • 從左到右(LTR):大多數語言,包括英語、法語和西班牙語,遵循這個方向。

    從右到左(RTL):像阿拉伯語和希伯來語這樣的語言需要將文字對齊和版面設計翻轉,以保持可讀性和文化背景。

為了在我們的應用程式中實現這一點,我們將document.body.dir設置為i18n中的dir,同時使用useEffect鉤子監聽語言選擇的變化

深色模式切換

創建DarkModeToggle組件以便用戶可以在亮色和暗色模式之間切換。

import { useEffect, useState } from "react";
import { SunIcon, MoonIcon } from "@heroicons/react/solid";

const DarkModeToggle = () => {
  const [darkMode, setDarkMode] = useState(false);

  useEffect(() => {
    // 在第一次加載時檢查本地存儲或系統偏好
    const isDark =
      localStorage.getItem("theme") === "dark" ||
      (!localStorage.getItem("theme") &&
        window.matchMedia("(prefers-color-scheme: dark)").matches);
    setDarkMode(isDark);
    document.documentElement.classList.toggle("dark", isDark);
  }, []);

  const toggleDarkMode = () => {
    setDarkMode(!darkMode);
    document.documentElement.classList.toggle("dark", !darkMode);
    localStorage.setItem("theme", !darkMode ? "dark" : "light");
  };

  return (
    <button
      aria-label="Toggle dark mode"
      onClick={toggleDarkMode}
      className="p-1 rounded"
    >
      {darkMode ? (
        <SunIcon
          className="w-6 h-6 text-yellow-500 "
          onClick={toggleDarkMode}
        />
      ) : (
        <MoonIcon className="w-6 h-6 text-gray-900 " onClick={toggleDarkMode} />
      )}
    </button>
  );
};

export default DarkModeToggle;

頭部組件

Header組件作為DarkModeTogglelanguageSelector組件的父組件。

import DarkModeToggle from "./DarkModeToggle";
import LanguageSelector from "./LanguageSelector";

const Header = () => {
  return (
    <header className="container flex justify-between">
      <DarkModeToggle />
      <LanguageSelector />
    </header>
  );
};

export default Header;

步驟 4:主應用程式組件

src/app文件中,包括以下內容:

import { useTranslation } from "react-i18next";
import Header from "./components/Header";

const App = () => {
  const { t } = useTranslation();

  const line1 = t("detail.line1");
  const line2 = t("detail.line2");

  return (
    <div className="h-[100vh] bg-white text-black dark:bg-gray-900 dark:text-white py-8">
      <Header />
      <div className="container text-center max-w-2xl mt-28">
        <h1 className="text-4xl font-bold">{t("greeting")}</h1>
        <p className="mt-8">{line1}</p>
        <p className="mt-2">{line2}</p>
      </div>
    </div>
  );
};

export default App;
  • react-i18next 中的 useTranslation Hook 暴露了 t 函數,用於獲取翻譯文本。

  • 它基於來自您的翻譯文件的鍵(例如,en.jsonfr.json)來獲取翻譯字符串。

通過遵循這些步驟,您的應用程序現在應該完全具備與翻譯無縫集成的功能。這是我們應用程序的最終結果:

查看 實時演示 以及在 GitHub 上的源代碼

結論

建立允許用戶選擇他們偏好語言的網站不僅是一項技術成就,更是邁向使網絡更具包容性和歡迎性的一步。

通過將國際化(i18n)與 React-i18next 等工具以及使用 Tailwind CSS 進行樣式設計結合,您可以構建適用於全球受眾的靈活、用戶友好且易於訪問的應用程序。

在這個項目中,我們演示了如何設置 i18n、添加語言切換器以及包含“深色模式”以提高可用性。

參考資料

https://react.i18next.com/

https://www.youtube.com/watch?v=dltHi9GWMIo