Babelize Elements
مبدّلات اللغة

مبدّل اللغة

مبدّل لغة لـ React جاهز للنسخ واللصق، مع قائمة منسدلة وبحث ودعم RTL وإمكانية وصول كاملة. يعمل مع next-intl وreact-i18next وأي إعداد i18n.

التثبيت

npx shadcn@latest add @babelize/language-switcher

الاستخدام

"use client";

import { useState } from "react";
import { LanguageSwitcher } from "@/components/ui/language-switcher";

const locales = [{ code: "en" }, { code: "fr" }, { code: "es" }, { code: "ja" }, { code: "ar" }];

export function LocaleSwitcher() {
  const [locale, setLocale] = useState("en");

  return (
    <LanguageSwitcher
      locales={locales} // only `code` is required, labels and flags are auto-resolved
      value={locale} // omit for uncontrolled, use defaultValue instead
      onValueChange={setLocale}
      label="native" // or "english" (default)
      showFlags
    />
  );
}

الخصائص

الخاصيةالنوعمطلوبالوصف
localesLocale[]نعممصفوفة الإعدادات المحلية المتاحة — code فقط مطلوب
valuestringلارمز الإعدادات المحلية المحدد — مرّره للتحكم في المكوّن
defaultValuestringلارمز الإعدادات المحلية المحدد الأولي (الافتراضي: رمز أول إعدادات محلية)
onValueChange(code: string) => voidلادالة استدعاء عند تغيّر الإعدادات المحلية
label"native" | "english"لاعرض التسميات باللغة الأصلية أو الإنجليزية (الافتراضي: "english")
showFlagsbooleanلاإظهار أعلام emoji (الافتراضي: false)
maxHeightnumber | stringلاأقصى ارتفاع لقائمة الخيارات القابلة للتمرير (الافتراضي: "15rem")
showCodebooleanلاإظهار رمز الإعدادات المحلية بجانب كل خيار (الافتراضي: false)
variant"outline" | "ghost" | "secondary"لانمط الزر المُشغّل (الافتراضي: "outline")
size"sm" | "default" | "lg"لاحجم الزر المُشغّل (الافتراضي: "default")
align"start" | "end"لاالحافة التي تصطف القائمة معها في الزر المُشغّل (الافتراضي: "start")
side"top" | "bottom"لاالجانب المفضل للقائمة؛ يتبدّل عند عدم وجود مساحة (الافتراضي: "bottom")
searchablebooleanلاإظهار حقل البحث (الافتراضي: true)
searchPlaceholderstringلاالنص النائب للبحث (الافتراضي: "Search languages...")
emptyMessageReactNodeلايُعرض عندما لا يطابق البحث أي نتيجة (الافتراضي: "No languages found.")
labelsPartial<LanguageSwitcherLabels>لاتجاوز نصوص الواجهة الإنجليزية المدمجة (انظر أدناه)
disabledbooleanلاتعطيل الزر المُشغّل
renderOption(locale, state) => ReactNodeلااستبدال محتوى كل صف خيار؛ يحوي state على selected وactive وlabel وflag
classNamesLanguageSwitcherClassNamesلاأصناف لكل جزء: trigger، content، search، list، item، empty
classNamestringلاأصناف CSS إضافية على الجذر

كائن الإعدادات المحلية

الخاصيةالنوعالوصف
codestringرمز ISO 639-1 / BCP 47 (مثل "en"، "fr-FR"، "ar-SA") — مطلوب
labelstringتجاوز اسم العرض (يُحدَّد تلقائيًا من الجدول المدمج عند الحذف)
flagstringتجاوز علم emoji (يُكتشف تلقائيًا من الرمز عند الحذف)
rtlbooleanتجاوز RTL (يُكتشف تلقائيًا من الرمز عند الحذف)

أمثلة

مع Babelize SDK

اقرن مبدّل اللغة مع Babelize SDK للترجمة التلقائية:

"use client";

import { useState } from "react";
import { useRouter } from "next/navigation";
import { LanguageSwitcher } from "@/components/ui/language-switcher";
import { useBabelize } from "@babelize/sdk/react";

const locales = [
  { code: "en", label: "English", flag: "🇺🇸" },
  { code: "fr", label: "Français", flag: "🇫🇷" },
  { code: "es", label: "Español", flag: "🇪🇸" },
  { code: "de", label: "Deutsch", flag: "🇩🇪" },
  { code: "ja", label: "日本語", flag: "🇯🇵" },
  { code: "ar", label: "العربية", flag: "🇸🇦" },
];

export function LocaleSwitcher() {
  const router = useRouter();
  const { locale, setLocale } = useBabelize();

  return (
    <LanguageSwitcher
      locales={locales}
      value={locale}
      onValueChange={(code) => {
        setLocale(code);
        router.push(`/${code}`);
      }}
    />
  );
}

مع next-intl

"use client";

import { useRouter } from "next/navigation";
import { LanguageSwitcher } from "@/components/ui/language-switcher";

export function LocaleSwitcher() {
  const router = useRouter();

  return (
    <LanguageSwitcher
      locales={[{ code: "en" }, { code: "fr" }]}
      defaultValue="en"
      onValueChange={(code) => router.push(`/${code}`)}
    />
  );
}

مع react-i18next

"use client";

import { useTranslation } from "react-i18next";
import { LanguageSwitcher } from "@/components/ui/language-switcher";

export function LocaleSwitcher() {
  const { i18n } = useTranslation();

  return (
    <LanguageSwitcher
      locales={[{ code: "en" }, { code: "fr" }]}
      value={i18n.language}
      onValueChange={(code) => i18n.changeLanguage(code)}
    />
  );
}

التسميات الأصلية + الأعلام

"use client";

import { LanguageSwitcher } from "@/components/ui/language-switcher";

export default function App() {
  return (
    <LanguageSwitcher
      locales={[{ code: "en" }, { code: "fr" }, { code: "es" }]}
      defaultValue="en"
      label="native"
      showFlags
    />
  );
}

تخصيص الأجزاء

يُنسَّق المبدّل برموز سمة shadcn، فيتبع سمتك. استخدم classNames لإعادة تنسيق أي جزء، أو renderOption لتغيير ما يعرضه كل صف:

<LanguageSwitcher
  locales={locales}
  variant="ghost"
  size="sm"
  align="end"
  classNames={{ content: "w-64", item: "py-2" }}
  renderOption={(locale, { label, flag, selected }) => (
    <>
      <span className="text-base leading-none">{flag}</span>
      <span className="flex-1">{label}</span>
      <span className="text-xs text-muted-foreground">{selected ? "Current" : locale.code}</span>
    </>
  )}
/>

نصوص الواجهة المترجمة

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

"use client";

import { LanguageSwitcher } from "@/components/ui/language-switcher";

export default function App() {
  return (
    <LanguageSwitcher
      locales={[{ code: "en" }, { code: "fr" }, { code: "es" }]}
      defaultValue="fr"
      label="native"
      labels={{
        searchPlaceholder: "Rechercher une langue…",
        searchLabel: "Rechercher une langue",
        clearSearch: "Effacer la recherche",
        emptyMessage: "Aucune langue trouvée.",
        listbox: "Choisir la langue",
        current: (name) => `Langue actuelle : ${name}`,
      }}
    />
  );
}
المفتاحالافتراضييُستخدم في
searchPlaceholder"Search languages..."النص النائب لحقل البحث
searchLabel"Search languages"تسمية إمكانية الوصول لحقل البحث
clearSearch"Clear search"تسمية إمكانية الوصول لزر المسح
emptyMessage"No languages found."يُعرض عند عدم وجود تطابق
listbox"Select language"تسمية إمكانية الوصول لقائمة الخيارات
current(name) => "Current language: " + nameتسمية إمكانية الوصول للزر المُشغّل

دعم لوحة المفاتيح

تتبع النافذة المنبثقة نمط combobox في WAI-ARIA: يبقى التركيز في حقل البحث، الذي يُعرض كـ role="combobox"، ويُعلَن عن الخيار المميّز عبر aria-activedescendant.

المفتاحالإجراء
Enter، Space، أو النقرافتح النافذة المنبثقة من الزر المُشغّل
ArrowDown / ArrowUp (مغلقة)افتح مع تمييز أول إعدادات محلية / آخرها
ArrowDown / ArrowUpانقل التمييز، مع الالتفاف عند الطرفين
Home / Endمميّز أول إعدادات محلية / آخرها
Enterاختر الإعدادات المحلية المميّزة وأعد التركيز إلى الزر المُشغّل
Escapeأغلق النافذة المنبثقة وأعد التركيز إلى الزر المُشغّل
الكتابةصفِّ حسب الاسم أو الرمز؛ يبدأ التمييز من الأعلى مجددًا

يبقى التمييز على الصف الذي ظهر فيه عند فتح القائمة — وتتمرر القائمة أسفله، كالقائمة الأصلية — ولا تتمرر الصفحة نفسها أبدًا. مرّر maxHeight لتغيير ارتفاع القائمة قبل أن تبدأ بالتمرير.

الميزات

  • بلا إعداد — مرّر الرموز فقط، وتُحدَّد التسميات والأعلام تلقائيًا
  • قائمة منسدلة مع بحث — صفِّ الإعدادات المحلية حسب الاسم أو الرمز
  • يراعي RTL — يكتشف الإعدادات المحلية من نوع RTL (ar وhe وfa وur) ويعدّل التخطيط
  • متاح عبر لوحة المفاتيح — التنقل بمفاتيح الأسهم وHome / End وEnter وEscape
  • تسميات ARIA — حقل البحث role="combobox" مع aria-activedescendant، إضافةً إلى aria-expanded وaria-haspopup وaria-selected
  • الوضع الداكن — مبني بـ Tailwind CSS ومتوافق مع الوضع الداكن
  • مستقل عن المكتبات — يعمل مع أي إعداد i18n عبر دالة الاستدعاء

اللغات المدعومة

تُكتشف التسميات والأعلام تلقائيًا من رمز اللغة. مرّر الرمز فقط:

الرمزاللغةالعلمRTL
enEnglish🇺🇸
frFrançais🇫🇷
esEspañol🇪🇸
deDeutsch🇩🇪
ja日本語🇯🇵
ko한국어🇰🇷
zh中文🇨🇳
arالعربية🇸🇦✓
ptPortuguês🇧🇷
itItaliano🇮🇹
nlNederlands🇳🇱
ruРусский🇷🇺
plPolski🇵🇱
trTürkçe🇹🇷
viTiếng Việt🇻🇳
thไทย🇹🇭
idBahasa Indonesia🇮🇩
hiहिन्दी🇮🇳
bnবাংলা🇧🇩
ukУкраїнська🇺🇦
csČeština🇨🇿
svSvenska🇸🇪
daDansk🇩🇰
fiSuomi🇫🇮
noNorsk🇳🇴
elΕλληνικά🇬🇷
heעברית🇮🇱✓
faفارسی🇮🇷✓
roRomână🇷🇴
huMagyar🇭🇺
skSlovenčina🇸🇰
bgБългарски🇧🇬
hrHrvatski🇭🇷
srСрпски🇷🇸
slSlovenščina🇸🇮
ltLietuvių🇱🇹
lvLatviešu🇱🇻
etEesti🇪🇪
gaGaeilge🇮🇪
caCatalà🇪🇸
isÍslenska🇮🇸
swKiswahili🇹🇿
amአማርኛ🇪🇹
neनेपाली🇳🇵
siසිංහල🇱🇰
myမြန်မာ🇲🇲
kmខ្មែរ🇰🇭
loລາວ🇱🇦
kaქართული🇬🇪
hyՀայերեն🇦🇲
kkҚазақ🇰🇿
uzOʻzbek🇺🇿
mnМонгол🇲🇳
urاردو🇵🇰✓
mlമലയാളം🇮🇳
taதமிழ்🇮🇳
teతెలుగు🇮🇳
knಕನ್ನಡ🇮🇳
mrमराठी🇮🇳
guગુજરાતી🇮🇳
paਪੰਜਾਬੀ🇮🇳
yoYorùbá🇳🇬
igIgbo🇳🇬
zuisiZulu🇿🇦
afAfrikaans🇿🇦
haHausa🇳🇬
tlFilipino🇵🇭
miTe Reo Māori🇳🇿
smGagana Samoa🇼🇸
toLea Faka-Tonga🇹🇴
eoEsperanto🌐

تحتاج لغة غير مدرجة؟ مرّر label وflag مخصصين للتجاوز:

<LanguageSwitcher
  locales={[{ code: "xyz", label: "My Language", flag: "🏴" }]}
  defaultValue="xyz"
/>

الاعتماديات

يستخدم هذا المكوّن:

  • clsx وtailwind-merge (مُضمّنة كاعتماديات)

الاعتماديات النظيرة:

  • react >= 18
  • react-dom >= 18
  • tailwindcss >= 3

الإسناد

من إنشاء sapatmohit.

في هذه الصفحة