我最近参与了一个令人兴奋的项目,涉及创建一个能够在不同语言之间切换以吸引更广泛受众的网站。这使我更好地理解了“本地化”这一概念,通常涉及调整内容,使其对不同语言和地区的用户具有相关性、可访问性和亲和力。
本地化不仅仅是翻译文字,更是创造一种让用户无论使用何种语言都感觉宾至如归的体验。例如,像亚马逊这样的全球平台使语言切换如此流畅,以至于几乎感觉像是魔法般的。除了提升用户体验,这一功能还在扩大业务范围、与全球客户建立更紧密联系方面发挥着至关重要的作用。
目录
什么是i18n,为什么要使用它?
i18n,即国际化(internationalization)的缩写,意味着一个应用程序支持多种语言。”i18n”源自于在”internationalization”中第一个”i”和最后一个”n”之间有18个字母这一事实。这一切都是为了使您的应用程序能够适应全球受众,通过处理文本翻译、日期和数字格式化、管理货币以及适应地区习俗来实现。
通过启用国际化,您的应用程序不仅成为一个工具,更是一个能直接契合用户偏好和文化的包容平台。
让我们开始吧
我们将创建一个非常简单的演示多语言Web应用程序,其中包含一个暗黑模式切换功能,以演示如何实现这一概念。
先决条件
-
React的基础知识 – 您应该了解如何创建组件、管理状态以及使用像
useState
和useEffect
这样的Hooks。如果您对React还不熟悉,我建议您从官方React文档开始学习,打下坚实的基础。 -
国际化概念的熟悉度 – 了解国际化(i18n)的基本知识及其重要性将为您的项目提供背景。本文的早期部分涵盖了基本要素。
-
Tailwind CSS – 我们将使用 Tailwind CSS 进行样式设计。这是一个以工具优先的 CSS 框架,帮助您在不离开 HTML 的情况下构建现代响应式设计。如果您不熟悉,可以查看 Tailwind 的文档。
-
Node.js – 确保您的系统上安装了 Node.js 以处理依赖项。您可以从 Node.js 下载最新版本。
-
包管理器 – 需要使用 npm(随 Node.js 一起包含)或 yarn 来管理项目依赖项
我们将使用的工具
-
代码编辑器
-
本地化库: react-i18next
-
图标库: 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
目录中,为每种语言创建子文件夹(例如,en
、fr
)并包含 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
钩子公开了来自的 实例,用于与国际化设置进行交互。 -
handleLanguageChange
函数用于更新用户选择的语言。当用户从下拉菜单中选择新语言时触发。
实现文本方向
HTML中的dir
属性是确保网络应用程序具有可访问性和包容性的关键功能,特别是在处理文本方向不同的语言时。例如:
-
从左到右(LTR):大多数语言,包括英语、法语和西班牙语,都遵循这个方向。
从右到左(RTL):阿拉伯语和希伯来语等语言需要将文本对齐和布局翻转,以保持可读性和文化背景。
为了在我们的应用中实现这一点,我们将document.body.dir
设置为从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
组件作为DarkModeToggle
和languageSelector
组件的父组件。
import DarkModeToggle from "./DarkModeToggle";
import LanguageSelector from "./LanguageSelector";
const Header = () => {
return (
<header className="container flex justify-between">
<DarkModeToggle />
<LanguageSelector />
</header>
);
};
export default Header;
第四步:主应用程序组件
在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.json
,fr.json
)来获取翻译字符串。
通过遵循这些步骤,您的应用现在应该已经完全集成了翻译,功能正常。这是我们应用的最终结果:
结论
创建允许用户选择其首选语言的网站不仅仅是技术上的成就,更是朝着使网络更具包容性和友好迈出的一步。
通过将国际化(i18n)与React-i18next等工具以及使用Tailwind CSS进行样式设置相结合,您可以构建灵活、用户友好且适合全球受众的应用程序。
在这个项目中,我们介绍了设置i18n、添加语言切换器以及包含“深色模式”以提高可用性的步骤。
参考资料
Source:
https://www.freecodecamp.org/news/build-multilingual-apps-with-i18n-in-react/