<header class="flex items-center">

<NuxtImg src="logo.png" class="w-18" alt="Dywan Dev - Digital tools & templates" format="webp" quality="80" loading="lazy" />

<Item><nuxt-link href="/">Home</nuxt-link></Item>

<Item><nuxt-link href="/about">About</nuxt-link></Item>

<Item><nuxt-link href="/works"> Portfolio</nuxt-link></Item>

<Item><nuxt-link href="/contact_me"> Contact</nuxt-link></Item>

<a href="/contact-me" title="Get in touch with Dywan Dev"> Contact </a>

<themeswitch class="moon">Dark/Light</themeswitch>

<langswitch class="en">en/fa</langswitch>

</header>

<initilizecontent class="content">Hello World - Dywan Dev</initilizecontent>

<myname is="Dywan Dev" />

<jobtitle is="Digital tools · Templates · Case studies" />

<portfolios are="ready" number="8" />

<experience years="more than 6" />

<birthdate year="1998" month="july" day="11" />

<skills :list="['NUXT', 'Vue', 'React', 'Next', 'Javascript','Responsive Design', 'i18n', 'TypeScript]" />

<contactDetails :list="['contact@dywandev.com', 'linkedin.com/in/dywan-dev', 'github.com/dywan-dev']" />

Dywan Dev
المدونة
دعم RTL وLTR في React مع i18next: دليل عملي للتطبيقات ثنائية اللغة

دعم RTL وLTR في React مع i18next: دليل عملي للتطبيقات ثنائية اللغة

مقدمة

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

يوثّق هذا الدليل بالضبط كيف نفّذت دعم RTL وLTR في Dywan Dev، منصة ويب fullstack مبنية بـ React وVite وi18next. بلا نظريات طويلة: ما يعمل فقط.

1. إعداد i18next في تطبيق React + Vite

ثبّت الحزم المطلوبة أولًا:

npm install i18next react-i18next i18next-browser-languagedetector

أنشئ ملفات الترجمة:

src/
  locales/
    en/translation.json
    fr/translation.json
    ar/translation.json

هيّئ i18next في ملف مخصّص src/i18n.js:

import i18n from 'i18next';
import { initReactI18next } from 'react-i18next';
import LanguageDetector from 'i18next-browser-languagedetector';

import en from './locales/en/translation.json';
import fr from './locales/fr/translation.json';
import ar from './locales/ar/translation.json';

i18n
  .use(LanguageDetector)
  .use(initReactI18next)
  .init({
    resources: { en: { translation: en }, fr: { translation: fr }, ar: { translation: ar } },
    fallbackLng: 'en',
    interpolation: { escapeValue: false }
  });

export default i18n;

استورده مرة واحدة في أعلى main.jsx:

import './i18n';

2. التعامل مع تبديل الاتجاه — الطريقة الصحيحة

وهنا تتوقف أغلب الشروحات مبكرًا جدًا. تغيير اللغة لا يكفي: يجب تحديث خاصيتَي HTML dir وlang ديناميكيًا في كل مرة تتغيّر فيها اللغة.

أنشئ خطافًا مخصصًا useDirection.js:

import { useEffect } from 'react';
import { useTranslation } from 'react-i18next';

const RTL_LANGUAGES = ['ar'];

export const useDirection = () => {
  const { i18n } = useTranslation();

  useEffect(() => {
    const isRTL = RTL_LANGUAGES.includes(i18n.language);
    document.documentElement.dir = isRTL ? 'rtl' : 'ltr';
    document.documentElement.lang = i18n.language;
  }, [i18n.language]);
};

استدعِ هذا الخطاف مرة واحدة في جذر App.jsx:

import { useDirection } from './hooks/useDirection';

function App() {
  useDirection();
  return (...);
}

بهذا تستجيب واجهتك بالكامل تلقائيًا لتغيّرات اللغة.

3. الجزء الأصعب — الحركات والصور في RTL

قليل من المقالات تتناول هذا. عند التبديل إلى RTL، يتولى CSS النص وأجزاء كبيرة من التخطيط تلقائيًا. لكن الحركات والصور لا تتبع ذلك دائمًا.

الحركات

إذا كنت تستخدم Framer Motion، فيجب أن تحترم الحركات الاتجاهية الاتجاه الحالي. بدل تثبيت قيمة x: 100، اقرأ الاتجاه ديناميكيًا:

import { useTranslation } from 'react-i18next';

const { i18n } = useTranslation();
const isRTL = i18n.language === 'ar';

const slideVariant = {
  hidden: { x: isRTL ? -100 : 100, opacity: 0 },
  visible: { x: 0, opacity: 1 }
};

الصور

الصور الزخرفية ذات الاتجاه — أسهم، شخصيات تواجه جهةً ما، رسوم واجهة — قد تحتاج إلى انعكاس في RTL. استخدم صنف CSS مشروطًا:

.mirror-rtl {
  transform: scaleX(-1);
}
<img
  src={arrow}
  className={isRTL ? 'mirror-rtl' : ''}
  alt="direction indicator"
/>

طبّق ذلك فقط على الصور التي يكون للاتجاه فيها معنى بصري. ليست كل الصور بحاجة للانعكاس — فقط التي توحي باتجاه بصريًا.

4. Tailwind CSS وRTL

يدعم Tailwind من الإصدار 3 فما فوق RTL بشكل مدمج. فعّله في tailwind.config.js (مسارات content الافتراضية تكفي عادةً)؛ ثم استخدم متغيّرات ltr: وrtl: للأدوات الاتجاهية:

<div class="ltr:pl-4 rtl:pr-4">
  Content
</div>

هذا يحافظ على تخطيط نظيف دون كتابة أنماط RTL منفصلة.

5. مكوّن تبديل اللغة

فيما يلي مبدّل لغة بسيط وواضح يحدّث كلًا من اللغة والاتجاه:

import { useTranslation } from 'react-i18next';

const languages = [
  { code: 'en', label: 'EN' },
  { code: 'fr', label: 'FR' },
  { code: 'ar', label: 'ع' }
];

export const LanguageSwitcher = () => {
  const { i18n } = useTranslation();

  return (
    <div className="flex gap-2">
      {languages.map(({ code, label }) => (
        <button
          key={code}
          onClick={() => i18n.changeLanguage(code)}
          className={
            i18n.language === code
              ? 'px-3 py-1 rounded bg-primary text-white'
              : 'px-3 py-1 rounded bg-transparent'
          }
        >
          {label}
        </button>
      ))}
    </div>
  );
};

الخاتمة

دعم RTL ليس مجرد مسألة ترجمة — إنه أيضًا تخطيط وحركة وتجربة مستخدم. الجمع بين i18next للمحتوى، وخطاف للاتجاه لخصائص HTML، ومنطق شرطي للحركات يغطي نحو 95٪ من الحالات العملية.

إن كنت تبني لأسواق ناطقة بالعربية — أو لأي جمهور ثنائي اللغة — فالإحكام من البداية يوفر عليك إعادة هيكلة كبيرة لاحقًا.

Dywan Dev مبني على هذا النموذج نفسه: منصة متعددة اللغات جاهزة لـ RTL ومصممة للوصول العالمي. إذا احتجت موقعًا يتحدث لغة جمهورك حرفيًا، تواصل معي.

تابع القراءة

عرض الكلعرض الكل
واتساب