عملت مؤخرًا على مشروع مثير يتضمن إنشاء موقع ويب قادر على التبديل بين اللغات لجذب جمهور أوسع. هذا جعلني أفهم مفهوم “التعريب” بشكل أفضل، والذي عادة ما يتضمن تكييف المحتوى ليكون ذا صلة وسهل الوصول ومناسب للمستخدمين في لغات ومناطق مختلفة.

لا يقتصر التعريب على ترجمة الكلمات، بل يتعلق بخلق تجربة تجعل المستخدمين يشعرون بأنهم في منزلهم، بغض النظر عن لغتهم. على سبيل المثال، تجعل المنصات العالمية مثل أمازون التبديل بين اللغات سلسًا لدرجة أنه يبدو سحريًا تقريبًا. بالإضافة إلى تحسين تجربة المستخدم، تلعب هذه الميزة دورًا حاسمًا في تعزيز الأعمال من خلال الوصول إلى جمهور أوسع وتعزيز الروابط الأقوى مع العملاء في جميع أنحاء العالم.

فهرس المحتويات

ما هو i18n، ولماذا نستخدمه؟

i18n ، وهي اختصار للتدويل، تعني أن التطبيق يدعم عدة لغات. تم استحداث “i18n” نتيجة لوجود 18 حرفًا بين الحرف الأول “i” والحرف الأخير “n” في كلمة “internationalization”. الأمر يتعلق بجعل تطبيقك قابلاً للتكيف للجماهير العالمية من خلال التعامل مع ترجمة النصوص، وتنسيق التواريخ والأرقام، وإدارة العملات، واستيعاب التقاليد الإقليمية.

من خلال تمكين التدويل، يصبح تطبيقك ليس مجرد أداة بل منصة شاملة تتحدث مباشرة إلى تفضيلات وثقافة المستخدم.

لنقم بالانغماس مباشرة

سنقوم بإنشاء تطبيق ويب تجريبي متعدد اللغات بسيط جدًا يحتوي على ميزة تبديل الوضع الداكن لتوضيح كيفية تحقيق هذا المفهوم.

المتطلبات الأساسية

  1. المعرفة الأساسية في React – يجب أن تفهم كيفية إنشاء المكونات، وإدارة الحالة، واستخدام الخطايا مثل useState و useEffect. إذا كنت جديدًا في React، فأنصح بالبدء مع وثائق React الرسمية للحصول على أساس قوي.

  2. معرفة مفاهيم التدويل – معرفة أساسيات التدويل (i18n) ولماذا هو مهم ستمنحك سياقًا للمشروع. تغطي الأقسام السابقة من هذه المقالة الأساسيات.

  3. تايلويند سي إس إس – سنستخدم تايلويند سي إس إس للتصميم. إنه إطار عمل يعتمد على الاستخدام أولاً يساعدك في بناء تصميمات عصرية ومتجاوبة دون مغادرة HTML الخاص بك. إذا لم تكن على دراية، تحقق من وثائق تايلويندن.

  4. نود.جي إس – تأكد من تثبيت نود.جي إس على نظامك للتعامل مع التبعيات. يمكنك تنزيل أحدث إصدار من نود.جي إس.

  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

قم بإنشاء ملف i18n.tsx في مجلد src وقم بتكوين 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 وأدوات أخرى.

  • 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: كيفية بناء المكونات

أنشئ مجلد components في دليل src وأضف المكونات التالية:

محدد اللغة

قم بإنشاء مكون 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 يكشف عن مثيل i18n من i18next للتفاعل مع إعدادات التدويل.

  • ستُستخدم وظيفة handleLanguageChange لتحديث اللغة التي اختارها المستخدم. يتم تشغيلها عندما يختار المستخدم لغة جديدة من قائمة السقط.

تنفيذ اتجاه النص

يعتبر سمة dir في HTML ميزة حرجية لضمان إمكانية الوصول والشمولية في تطبيقات الويب، خاصة عند التعامل مع اللغات التي تختلف في اتجاه النص. على سبيل المثال:

  • من اليسار إلى اليمين (LTR): تتبع معظم اللغات، بما في ذلك الإنجليزية والفرنسية والإسبانية، هذا الاتجاه.

    من اليمين إلى اليسار (RTL): تتطلب اللغات مثل العربية والعبرية محاذاة النص وتخطيطه ليتم قلبها للحفاظ على قراءة النص والسياق الثقافي.

لتحقيق ذلك في تطبيقنا، نقوم بتعيين document.body.dir إلى قيمة سمة dir من i18n مع الاستماع للتغييرات في اختيار اللغة باستخدام خطة الـ 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;

الخطوة 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;
  • تقوم دالة useTranslation من react-i18next بتوفير دالة t، والتي تستخدم لجلب النص المترجم.

  • تقوم بجلب السلسلة المترجمة بناءً على مفتاح من ملفات الترجمة الخاصة بك (على سبيل المثال، en.json، fr.json).

من خلال اتباع هذه الخطوات، يجب أن تعمل تطبيقك الآن بشكل كامل مع تكامل الترجمة بسلاسة. هذا هو الشكل النهائي لتطبيقنا:

تحقق من العرض المباشر وكود المصدر على GitHub

الخاتمة

إنشاء مواقع ويب تمنح المستخدمين المرونة لاختيار لغتهم المفضلة ليس مجرد إنجاز تقني، بل هو خطوة نحو جعل الويب أكثر شمولاً وترحيباً.

من خلال دمج التدويل (i18n) مع أدوات مثل React-i18next وتنسيق باستخدام Tailwind CSS، يمكنك بناء تطبيقات مرنة وسهلة الاستخدام وقابلة للوصول لجمهور عالمي.

في هذا المشروع، قمنا باستعراض إعداد i18n، إضافة محول اللغة، وتضمين “الوضع المظلم” لتحسين قابلية الاستخدام.

المراجع

https://react.i18next.com/

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