واجهة برمجة التطبيقات Intl.DisplayNames

تحويل رموز اللغة والمنطقة والعملة والنص البرمجي إلى أسماء قابلة للقراءة

مقدمة

يحتوي تطبيقك على رمز الدولة US، لكن المستخدمين يرون النص "الولايات المتحدة". لديك رمز اللغة fr، لكن مبدل اللغة يعرض "الفرنسية". لديك رمز العملة EUR، لكن صفحة الدفع تعرض "اليورو".

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

يلغي هذا الحاجة إلى مكتبات خارجية أو جداول بحث مخصصة تتطلب صيانة وتوطيناً. يتعامل المتصفح مع البيانات والترجمات معاً.

تحويل رموز المناطق إلى أسماء الدول

حالة الاستخدام الأكثر شيوعاً تتضمن تحويل رموز الدول ISO إلى أسماء الدول. أنشئ نسخة من DisplayNames مع لغة ونوع، ثم استدع طريقة of() مع رمز الدولة:

const regionNames = new Intl.DisplayNames(["en"], { type: "region" });

console.log(regionNames.of("US")); // "United States"
console.log(regionNames.of("GB")); // "United Kingdom"
console.log(regionNames.of("JP")); // "Japan"

يقبل المعامل الأول مصفوفة من رموز اللغات التي تتبع معيار BCP 47. يستخدم المتصفح أول لغة مدعومة من المصفوفة. يحدد خيار type نوع الرمز الذي تريد تحويله.

تنتج نفس الرموز مخرجات مختلفة عند توطينها للغات مختلفة:

const englishRegions = new Intl.DisplayNames(["en"], { type: "region" });
const japaneseRegions = new Intl.DisplayNames(["ja"], { type: "region" });
const spanishRegions = new Intl.DisplayNames(["es"], { type: "region" });

console.log(englishRegions.of("FR")); // "France"
console.log(japaneseRegions.of("FR")); // "フランス"
console.log(spanishRegions.of("FR")); // "Francia"

يعمل هذا النمط لبناء محددات الدول، وعروض المواقع، وأي عنصر واجهة يحول رموز الدول إلى أسماء قابلة للقراءة.

تحويل رموز اللغات إلى أسماء اللغات

تستخدم رموز اللغات نفس النمط مثل رموز المناطق. اضبط type: "language" لتحويل رموز اللغات إلى أسماء اللغات:

const languageNames = new Intl.DisplayNames(["en"], { type: "language" });

console.log(languageNames.of("en")); // "English"
console.log(languageNames.of("es")); // "Spanish"
console.log(languageNames.of("zh")); // "Chinese"
console.log(languageNames.of("ar")); // "Arabic"

يمكن أن تتضمن رموز اللغة علامات فرعية للمنطقة للمتغيرات الإقليمية:

const languageNames = new Intl.DisplayNames(["en"], { type: "language" });

console.log(languageNames.of("en-US")); // "American English"
console.log(languageNames.of("en-GB")); // "British English"
console.log(languageNames.of("fr-CA")); // "Canadian French"
console.log(languageNames.of("pt-BR")); // "Brazilian Portuguese"

يحول هذا رموز اللغة إلى أسماء مناسبة لمبدلات اللغة وواجهات الترجمة ومحددات تفضيلات اللغة.

عرض أسماء اللغات بلغتها الخاصة

غالبًا ما تعرض مبدلات اللغة كل لغة بنظام كتابتها الخاص. أنشئ نسخة DisplayNames منفصلة لكل لغة مستهدفة:

const english = new Intl.DisplayNames(["en"], { type: "language" });
const french = new Intl.DisplayNames(["fr"], { type: "language" });
const japanese = new Intl.DisplayNames(["ja"], { type: "language" });
const arabic = new Intl.DisplayNames(["ar"], { type: "language" });

console.log(english.of("en")); // "English"
console.log(french.of("fr")); // "français"
console.log(japanese.of("ja")); // "日本語"
console.log(arabic.of("ar")); // "العربية"

يتعرف المستخدمون على لغتهم بسرعة أكبر عند عرضها بنظام كتابتها الأصلي.

تحويل رموز العملات إلى أسماء العملات

تتبع رموز العملات معيار ISO 4217. اضبط type: "currency" لتحويل رموز العملات المكونة من ثلاثة أحرف إلى أسماء العملات:

const currencyNames = new Intl.DisplayNames(["en"], { type: "currency" });

console.log(currencyNames.of("USD")); // "US Dollar"
console.log(currencyNames.of("EUR")); // "Euro"
console.log(currencyNames.of("GBP")); // "British Pound"
console.log(currencyNames.of("JPY")); // "Japanese Yen"

تتم ترجمة أسماء العملات بناءً على لغة العرض:

const englishCurrency = new Intl.DisplayNames(["en"], { type: "currency" });
const germanCurrency = new Intl.DisplayNames(["de"], { type: "currency" });
const japaneseCurrency = new Intl.DisplayNames(["ja"], { type: "currency" });

console.log(englishCurrency.of("EUR")); // "Euro"
console.log(germanCurrency.of("EUR")); // "Euro"
console.log(japaneseCurrency.of("EUR")); // "ユーロ"

يعمل هذا النمط لمحددات العملات في تدفقات الدفع ولوحات المعلومات المالية وواجهات تحويل العملات.

تحويل رموز الكتابة إلى أسماء الكتابة

تستخدم رموز الكتابة معيار ISO 15924. اضبط type: "script" لتحويل رموز الكتابة المكونة من أربعة أحرف إلى أسماء الكتابة:

const scriptNames = new Intl.DisplayNames(["en"], { type: "script" });

console.log(scriptNames.of("Latn")); // "Latin"
console.log(scriptNames.of("Arab")); // "Arabic"
console.log(scriptNames.of("Cyrl")); // "Cyrillic"
console.log(scriptNames.of("Hans")); // "Simplified Chinese"
console.log(scriptNames.of("Hant")); // "Traditional Chinese"

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

تحويل رموز التقويم إلى أسماء التقويم

تختلف أنظمة التقويم عبر الثقافات. اضبط type: "calendar" لتحويل معرفات التقويم إلى أسماء التقويم:

const calendarNames = new Intl.DisplayNames(["en"], { type: "calendar" });

console.log(calendarNames.of("gregory")); // "Gregorian Calendar"
console.log(calendarNames.of("japanese")); // "Japanese Calendar"
console.log(calendarNames.of("buddhist")); // "Buddhist Calendar"
console.log(calendarNames.of("hebrew")); // "Hebrew Calendar"
console.log(calendarNames.of("islamic")); // "Islamic Calendar"
console.log(calendarNames.of("chinese")); // "Chinese Calendar"

يصبح هذا مفيدًا لتطبيقات الجدولة ومنتقيات التاريخ مع اختيار نظام التقويم وواجهات التقويم المعولمة.

تحويل رموز حقول التاريخ والوقت إلى أسماء الحقول

تحتوي واجهات التاريخ والوقت على حقول معنونة مثل السنة والشهر واليوم. اضبط type: "dateTimeField" لتحويل معرفات الحقول إلى أسماء حقول مترجمة:

const dateFields = new Intl.DisplayNames(["en"], { type: "dateTimeField" });

console.log(dateFields.of("year")); // "year"
console.log(dateFields.of("month")); // "month"
console.log(dateFields.of("day")); // "day"
console.log(dateFields.of("hour")); // "hour"
console.log(dateFields.of("minute")); // "minute"
console.log(dateFields.of("weekday")); // "day of the week"
console.log(dateFields.of("dayPeriod")); // "AM/PM"
console.log(dateFields.of("timeZoneName")); // "time zone"

تتم ترجمة أسماء هذه الحقول حسب لغة العرض:

const englishFields = new Intl.DisplayNames(["en"], { type: "dateTimeField" });
const spanishFields = new Intl.DisplayNames(["es"], { type: "dateTimeField" });
const japaneseFields = new Intl.DisplayNames(["ja"], { type: "dateTimeField" });

console.log(englishFields.of("month")); // "month"
console.log(spanishFields.of("month")); // "mes"
console.log(japaneseFields.of("month")); // "月"

تتضمن معرفات الحقول الصالحة era، وyear، وquarter، وmonth، وweekOfYear، وweekday، وday، وdayPeriod، وhour، وminute، وsecond، وtimeZoneName.

يدعم هذا النمط بناء أدوات اختيار التاريخ التي يمكن الوصول إليها، وواجهات التقويم، ومكونات اختيار الوقت مع تسميات مترجمة بشكل صحيح.

التحكم في طول العرض باستخدام خيارات النمط

يتحكم خيار style في مدى تفصيل المخرجات. تنتج ثلاث قيم أطوالاً مختلفة:

const longNames = new Intl.DisplayNames(["en"], {
  type: "region",
  style: "long",
});

const shortNames = new Intl.DisplayNames(["en"], {
  type: "region",
  style: "short",
});

const narrowNames = new Intl.DisplayNames(["en"], {
  type: "region",
  style: "narrow",
});

console.log(longNames.of("US")); // "United States"
console.log(shortNames.of("US")); // "US"
console.log(narrowNames.of("US")); // "US"

ينتج نمط long (الافتراضي) الاسم الكامل. ينتج نمطا short وnarrow أشكالاً مختصرة عند توفرها، على الرغم من أن ليس جميع الرموز لها متغيرات أقصر.

يصبح النمط أكثر أهمية مع أسماء اللغات:

const longLanguages = new Intl.DisplayNames(["en"], {
  type: "language",
  style: "long",
});

const shortLanguages = new Intl.DisplayNames(["en"], {
  type: "language",
  style: "short",
});

console.log(longLanguages.of("en-US")); // "American English"
console.log(shortLanguages.of("en-US")); // "US English"

استخدم long للتسميات الكاملة في النماذج والواجهات التفصيلية. استخدم short أو narrow للعروض المدمجة مثل التنقل عبر الهاتف المحمول أو عناصر واجهة المستخدم المحدودة المساحة.

التعامل مع متغيرات اللغة الإقليمية باستخدام languageDisplay

يمكن عرض رموز اللغة التي تحتوي على علامات فرعية إقليمية كلهجات أو كأسماء لغات قياسية مع مؤهلات إقليمية. يتحكم خيار languageDisplay في هذا السلوك ويطبق فقط عندما type: "language":

const dialectNames = new Intl.DisplayNames(["en"], {
  type: "language",
  languageDisplay: "dialect",
});

const standardNames = new Intl.DisplayNames(["en"], {
  type: "language",
  languageDisplay: "standard",
});

console.log(dialectNames.of("nl-BE")); // "Flemish"
console.log(standardNames.of("nl-BE")); // "Dutch (Belgium)"

console.log(dialectNames.of("en-AU")); // "Australian English"
console.log(standardNames.of("en-AU")); // "English (Australia)"

تعرض قيمة dialect (الافتراضية) المتغيرات الإقليمية باستخدام أسماءها الشائعة. تعرض قيمة standard دائماً اللغة الأساسية مع مؤهل إقليمي بين قوسين.

اختر dialect عندما يكون للمتغيرات الإقليمية أسماء معروفة يتعرف عليها المستخدمون. اختر standard للتنسيق المتسق أو عند العمل مع مجموعات لغة-منطقة أقل شيوعاً.

التحكم في سلوك الرجوع للأكواد غير الصالحة

تتلقى الدالة of() أكوادًا قد لا تحتوي على أسماء عرض مقابلة. يحدد الخيار fallback ما يحدث:

const withCodeFallback = new Intl.DisplayNames(["en"], {
  type: "region",
  fallback: "code",
});

const withNoneFallback = new Intl.DisplayNames(["en"], {
  type: "region",
  fallback: "none",
});

console.log(withCodeFallback.of("ZZ")); // "ZZ"
console.log(withNoneFallback.of("ZZ")); // undefined

تُرجع القيمة code (الافتراضية) كود الإدخال عندما لا يوجد اسم عرض. تُرجع القيمة none القيمة undefined للأكواد غير المعينة.

استخدم code عندما تحتاج دائمًا إلى قيمة نصية للعرض، حتى لو رجعت إلى الكود نفسه. استخدم none عندما تحتاج إلى اكتشاف الأكواد غير الصالحة ومعالجتها بشكل صريح:

const regionNames = new Intl.DisplayNames(["en"], {
  type: "region",
  fallback: "none",
});

function getRegionName(code) {
  const name = regionNames.of(code);
  if (name === undefined) {
    return "Unknown region";
  }
  return name;
}

console.log(getRegionName("US")); // "United States"
console.log(getRegionName("INVALID")); // "Unknown region"

بناء مكون محدد الدولة

يتكامل واجهة برمجة التطبيقات Intl.DisplayNames مباشرة في مكونات الواجهة. يبني هذا المثال محدد دولة يعرض أسماء الدول بلغة المستخدم:

function CountrySelector({ locale, value, onChange }) {
  const regionNames = new Intl.DisplayNames([locale], { type: "region" });

  const countries = [
    "US",
    "GB",
    "CA",
    "AU",
    "FR",
    "DE",
    "JP",
    "CN",
    "BR",
    "IN",
  ];

  return (
    <select value={value} onChange={(e) => onChange(e.target.value)}>
      <option value="">Select a country</option>
      {countries.map((code) => (
        <option key={code} value={code}>
          {regionNames.of(code)}
        </option>
      ))}
    </select>
  );
}

يتلقى المكون خاصية locale تتحكم في لغة العرض. يؤدي تغيير خاصية locale إلى إعادة عرض القائمة المنسدلة بأسماء الدول المترجمة.

بناء مكون مبدل اللغة

تعرض مبدلات اللغة كل لغة بنظام كتابتها الخاص. أنشئ نسخة DisplayNames لكل لغة:

function LanguageSwitcher({ currentLocale, onLocaleChange }) {
  const languages = [
    { code: "en", name: "English" },
    { code: "es", name: "Español" },
    { code: "fr", name: "Français" },
    { code: "de", name: "Deutsch" },
    { code: "ja", name: "日本語" },
    { code: "zh", name: "中文" },
  ];

  return (
    <div>
      {languages.map((lang) => {
        const displayNames = new Intl.DisplayNames([lang.code], {
          type: "language",
        });
        const nativeName = displayNames.of(lang.code);

        return (
          <button
            key={lang.code}
            onClick={() => onLocaleChange(lang.code)}
            className={currentLocale === lang.code ? "active" : ""}
          >
            {nativeName}
          </button>
        );
      })}
    </div>
  );
}

يعرض كل زر اسم اللغة بنظام كتابتها الخاص. يتعرف المستخدمون على لغتهم فورًا بغض النظر عن لغة الواجهة الحالية.

بناء مكون محدد العملة

تستفيد محددات العملة من أسماء العملات المترجمة. ينشئ هذا المثال محدد عملة يتكيف مع لغة العرض:

function CurrencySelector({ locale, value, onChange }) {
  const currencyNames = new Intl.DisplayNames([locale], { type: "currency" });

  const currencies = ["USD", "EUR", "GBP", "JPY", "CNY", "CAD", "AUD"];

  return (
    <select value={value} onChange={(e) => onChange(e.target.value)}>
      <option value="">Select currency</option>
      {currencies.map((code) => (
        <option key={code} value={code}>
          {code} - {currencyNames.of(code)}
        </option>
      ))}
    </select>
  );
}

تعرض القائمة المنسدلة كلاً من كود العملة واسم العملة المترجم. يرى المستخدمون في مناطق مختلفة أسماء العملات بلغتهم الخاصة.

الحصول على جميع القيم المدعومة

تُرجع الدالة Intl.supportedValuesOf() مصفوفات بجميع القيم المدعومة لكل نوع. يلغي هذا الحاجة إلى قوائم ثابتة من الرموز:

const regions = Intl.supportedValuesOf("region");
console.log(regions); // ["AD", "AE", "AF", "AG", "AI", ...]

const languages = Intl.supportedValuesOf("language");
console.log(languages); // ["aa", "ab", "ae", "af", "ak", ...]

const currencies = Intl.supportedValuesOf("currency");
console.log(currencies); // ["AED", "AFN", "ALL", "AMD", ...]

const calendars = Intl.supportedValuesOf("calendar");
console.log(calendars); // ["buddhist", "chinese", "coptic", ...]

أنشئ محددات ديناميكية تتضمن تلقائياً جميع القيم المدعومة:

function UniversalCountrySelector({ locale, value, onChange }) {
  const regionNames = new Intl.DisplayNames([locale], { type: "region" });
  const allRegions = Intl.supportedValuesOf("region");

  return (
    <select value={value} onChange={(e) => onChange(e.target.value)}>
      <option value="">Select a country</option>
      {allRegions.map((code) => (
        <option key={code} value={code}>
          {regionNames.of(code)}
        </option>
      ))}
    </select>
  );
}

يتضمن هذا المكون كل رمز منطقة مدعوم من قبل المتصفح دون الحاجة للحفاظ على قائمة ثابتة.

فهم متطلبات تنسيق الرموز

يتوقع كل نوع رموزاً بتنسيقات محددة. التنسيقات غير الصحيحة تنتج سلوك احتياطي بدلاً من أسماء العرض.

تتبع رموز المناطق معيار ISO 3166-1 alpha-2 (حرفان) أو UN M.49 (ثلاثة أرقام):

const regionNames = new Intl.DisplayNames(["en"], { type: "region" });

console.log(regionNames.of("US")); // "United States" (ISO 3166-1)
console.log(regionNames.of("001")); // "world" (UN M.49)
console.log(regionNames.of("150")); // "Europe" (UN M.49)

تتبع رموز اللغات معيار BCP 47، الذي يجمع بين رموز اللغات ISO 639 مع علامات فرعية اختيارية للمنطقة والنص:

const languageNames = new Intl.DisplayNames(["en"], { type: "language" });

console.log(languageNames.of("en")); // "English"
console.log(languageNames.of("en-US")); // "American English"
console.log(languageNames.of("zh-Hans")); // "Simplified Chinese"
console.log(languageNames.of("zh-Hans-CN")); // "Simplified Chinese (China)"

تتبع رموز العملات معيار ISO 4217 (ثلاثة أحرف):

const currencyNames = new Intl.DisplayNames(["en"], { type: "currency" });

console.log(currencyNames.of("USD")); // "US Dollar"
console.log(currencyNames.of("EUR")); // "Euro"

تتبع رموز النصوص معيار ISO 15924 (أربعة أحرف، بأحرف كبيرة):

const scriptNames = new Intl.DisplayNames(["en"], { type: "script" });

console.log(scriptNames.of("Latn")); // "Latin"
console.log(scriptNames.of("Arab")); // "Arabic"

مقارنة الرموز غير حساسة لحالة الأحرف، لكن اتباع الأحرف الكبيرة القياسية يحسن قابلية القراءة:

const regionNames = new Intl.DisplayNames(["en"], { type: "region" });

console.log(regionNames.of("US")); // "United States"
console.log(regionNames.of("us")); // "United States"
console.log(regionNames.of("Us")); // "United States"

دعم المتصفحات والتوافق

أصبحت واجهة برمجة التطبيقات Intl.DisplayNames متاحة عبر جميع المتصفحات الرئيسية في عام 2021. يمكن للتطبيقات الحديثة استخدامها دون الحاجة إلى polyfills.

واجهة برمجة التطبيقات الأساسية مع أنواع language وregion وscript وcurrency لها دعم شامل. ظهر نوعا calendar وdateTimeField في إصدارات متصفحات لاحقة لكن لهما دعم واسع اعتباراً من عام 2025.

تحقق من دعم الميزات في وقت التشغيل عند الضرورة:

if (typeof Intl.DisplayNames !== "undefined") {
  const regionNames = new Intl.DisplayNames(["en"], { type: "region" });
  console.log(regionNames.of("US"));
} else {
  console.log("Intl.DisplayNames not supported");
}

بالنسبة للتطبيقات التي تدعم المتصفحات الأقدم، استخدم جداول بحث ثابتة أو مكتبات طرف ثالث عندما تكون واجهة برمجة التطبيقات غير متاحة.

تحسين الأداء باستخدام التخزين المؤقت

إنشاء نُسخ DisplayNames له تكلفة إضافية ضئيلة، لكن التطبيقات التي تحوّل العديد من الرموز يجب أن تعيد استخدام النُسخ:

const cache = new Map();

function getDisplayNames(locale, type) {
  const key = `${locale}-${type}`;

  if (!cache.has(key)) {
    cache.set(key, new Intl.DisplayNames([locale], { type }));
  }

  return cache.get(key);
}

function getCountryName(locale, code) {
  const displayNames = getDisplayNames(locale, "region");
  return displayNames.of(code);
}

console.log(getCountryName("en", "US")); // "United States"
console.log(getCountryName("en", "FR")); // "France"
console.log(getCountryName("es", "US")); // "Estados Unidos"

يخزّن الذاكرة المؤقتة النُسخ مفهرسة حسب اللغة والنوع. تعيد الاستدعاءات اللاحقة استخدام النُسخ الموجودة بدلاً من إنشاء نُسخ جديدة.

يهم هذا النمط بشكل أساسي في مسارات الكود الحرجة التي تحوّل مئات أو آلاف الرموز، مثل عرض جداول كبيرة من البيانات المترجمة.

المقارنة مع الأساليب البديلة

قبل واجهة برمجة التطبيقات Intl.DisplayNames، استخدمت التطبيقات عدة أساليب لتحويل الرموز إلى أسماء.

تطلبت جداول البحث المشفرة صيانة ودعمت فقط اللغات المحددة مسبقاً:

const countryNames = {
  US: "United States",
  GB: "United Kingdom",
  FR: "France",
};

function getCountryName(code) {
  return countryNames[code] || code;
}

يفشل هذا الأسلوب عند إضافة لغات جديدة لأن كل لغة تحتاج إلى جدول بحث منفصل.

وفرت مكتبات الطرف الثالث بيانات الترجمة لكنها زادت حجم الحزمة:

import countries from "i18n-iso-countries";
import countriesEN from "i18n-iso-countries/langs/en.json";
import countriesES from "i18n-iso-countries/langs/es.json";

countries.registerLocale(countriesEN);
countries.registerLocale(countriesES);

console.log(countries.getName("US", "en")); // "United States"
console.log(countries.getName("US", "es")); // "Estados Unidos"

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

تلغي واجهة برمجة التطبيقات Intl.DisplayNames كلتا المشكلتين. يحتفظ المتصفح بالبيانات، مما يبقيها محدثة ويلغي مخاوف حجم الحزمة. تدعم البيانات جميع اللغات التي يدعمها المتصفح دون تنزيلات إضافية.