كيف تقوم بتنسيق قوائم القياسات مع الوحدات؟

عرض قياسات متعددة مثل 5 كم، 10 كم، 15 كم مع تنسيق قائمة مناسب للغة المحلية باستخدام واجهات برمجة التطبيقات Intl في JavaScript

مقدمة

التطبيقات التي تعرض القياسات غالباً ما تحتاج إلى عرض قيم متعددة معاً. قد يعرض تطبيق اللياقة البدنية أوقات التقسيم كـ "5 كم، 10 كم، 15 كم". قد يعرض تطبيق الطقس درجات الحرارة على مدار الأسبوع كـ "20°م، 22°م، 25°م، 23°م". قد تسرد الوصفة كميات المكونات كـ "كوبان، ملعقة طعام واحدة، 3 ملاعق صغيرة".

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

توفر JavaScript واجهتي برمجة تطبيقات لحل هذه المشكلة. Intl.NumberFormat تنسق القياسات الفردية مع الوحدات. Intl.ListFormat تجمع قيماً متعددة في قائمة صحيحة نحوياً. يشرح هذا الدرس كيفية استخدام كلتا واجهتي برمجة التطبيقات معاً لتنسيق قوائم القياسات التي تطابق توقعات المستخدم في أي لغة محلية.

قوائم القياسات تتطلب خطوتين للتنسيق

عند تنسيق قائمة قياسات، لا يمكنك تخطي أي من خطوتي التنسيق. إذا قمت بتنسيق القائمة دون تنسيق القياسات، ستحصل على فواصل مناسبة للغة المحلية ولكن عرض وحدات غير صحيح. إذا قمت بتنسيق القياسات دون تنسيق القائمة، ستحصل على وحدات صحيحة ولكن فواصل غير صحيحة.

const distances = [5, 10, 15];

// Wrong: list formatted but not measurements
console.log(distances.join(', '));
// Output: "5, 10, 15" (missing units)

// Wrong: measurements formatted but not list
const formatter = new Intl.NumberFormat('en-US', {
  style: 'unit',
  unit: 'kilometer'
});
console.log(distances.map(d => formatter.format(d)).join(', '));
// Output: "5 km, 10 km, 15 km" (hardcoded comma might be wrong for some locales)

النهج الصحيح ينسق القياسات أولاً، ثم ينسق المصفوفة الناتجة من السلاسل النصية كقائمة.

const distances = [5, 10, 15];

const numberFormatter = new Intl.NumberFormat('en-US', {
  style: 'unit',
  unit: 'kilometer'
});

const formattedMeasurements = distances.map(d => numberFormatter.format(d));
// Result: ["5 km", "10 km", "15 km"]

const listFormatter = new Intl.ListFormat('en-US', {
  type: 'unit'
});

console.log(listFormatter.format(formattedMeasurements));
// Output: "5 km, 10 km, 15 km"

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

استخدم نوع الوحدة لقوائم القياسات

يقبل المُنشئ Intl.ListFormat خيار type الذي يتحكم في كيفية دمج عناصر القائمة. يقوم خيار type: 'unit' بتنسيق القوائم وفقاً للاصطلاحات المتبعة في البيانات التقنية والعلمية.

const measurements = ['5 km', '10 km', '15 km'];

const unitList = new Intl.ListFormat('en-US', {
  type: 'unit'
});

console.log(unitList.format(measurements));
// Output: "5 km, 10 km, 15 km"

القوائم التي تستخدم type: 'unit' تحذف أدوات العطف مثل "و" أو "أو". وتستخدم فواصل بسيطة بين العناصر. وهذا يتطابق مع الطريقة التي تُكتب بها القياسات عادةً في السياقات التقنية.

قارن هذا مع type: 'conjunction'، الذي يضيف "و" قبل العنصر الأخير.

const measurements = ['5 km', '10 km', '15 km'];

const conjunctionList = new Intl.ListFormat('en-US', {
  type: 'conjunction'
});

console.log(conjunctionList.format(measurements));
// Output: "5 km, 10 km, and 15 km"

يبدو شكل العطف طبيعياً في النثر ولكنه يبدو غير صحيح في السياقات التقنية. عند عرض قياسات متعددة، استخدم type: 'unit' لاتباع الاصطلاحات القياسية للكتابة العلمية والتقنية.

تنسيق قياسات المسافة في القوائم

تستخدم قياسات المسافة معرّفات الوحدات مثل kilometer، meter، mile، وfoot. بعد تنسيق كل مسافة مع وحدتها، يتم دمجها في قائمة.

const distances = [5, 10, 15, 20];

const numberFormatter = new Intl.NumberFormat('en-US', {
  style: 'unit',
  unit: 'kilometer'
});

const formattedDistances = distances.map(d => numberFormatter.format(d));

const listFormatter = new Intl.ListFormat('en-US', {
  type: 'unit'
});

console.log(listFormatter.format(formattedDistances));
// Output: "5 km, 10 km, 15 km, 20 km"

يعمل نفس النمط مع الأميال.

const distances = [3, 6, 9];

const numberFormatter = new Intl.NumberFormat('en-US', {
  style: 'unit',
  unit: 'mile'
});

const formattedDistances = distances.map(d => numberFormatter.format(d));

const listFormatter = new Intl.ListFormat('en-US', {
  type: 'unit'
});

console.log(listFormatter.format(formattedDistances));
// Output: "3 mi, 6 mi, 9 mi"

يمكنك تنسيق المسافات بمنازل عشرية من خلال تعيين خيارات تنسيق الأرقام.

const distances = [5.2, 10.7, 15.3];

const numberFormatter = new Intl.NumberFormat('en-US', {
  style: 'unit',
  unit: 'kilometer',
  maximumFractionDigits: 1
});

const formattedDistances = distances.map(d => numberFormatter.format(d));

const listFormatter = new Intl.ListFormat('en-US', {
  type: 'unit'
});

console.log(listFormatter.format(formattedDistances));
// Output: "5.2 km, 10.7 km, 15.3 km"

يتعامل منسّق الأرقام مع التقريب والمنازل العشرية قبل أن يقوم منسّق القائمة بدمج القيم.

تنسيق قياسات الوزن في القوائم

تتبع قياسات الوزن نفس النمط باستخدام معرّفات الوحدات مثل kilogram، pound، ounce، وgram.

const weights = [50, 75, 100];

const numberFormatter = new Intl.NumberFormat('en-US', {
  style: 'unit',
  unit: 'kilogram'
});

const formattedWeights = weights.map(w => numberFormatter.format(w));

const listFormatter = new Intl.ListFormat('en-US', {
  type: 'unit'
});

console.log(listFormatter.format(formattedWeights));
// Output: "50 kg, 75 kg, 100 kg"

يمكنك عرض الوزن بالأرطال بدلاً من ذلك.

const weights = [110, 165, 220];

const numberFormatter = new Intl.NumberFormat('en-US', {
  style: 'unit',
  unit: 'pound'
});

const formattedWeights = weights.map(w => numberFormatter.format(w));

const listFormatter = new Intl.ListFormat('en-US', {
  type: 'unit'
});

console.log(listFormatter.format(formattedWeights));
// Output: "110 lb, 165 lb, 220 lb"

يستخدم منسّق الأرقام تلقائياً الاختصار الصحيح لكل وحدة.

تنسيق قياسات درجة الحرارة في القوائم

تستخدم قياسات درجة الحرارة معرفات الوحدات مثل celsius وfahrenheit.

const temperatures = [20, 22, 25, 23, 21];

const numberFormatter = new Intl.NumberFormat('en-US', {
  style: 'unit',
  unit: 'celsius'
});

const formattedTemperatures = temperatures.map(t => numberFormatter.format(t));

const listFormatter = new Intl.ListFormat('en-US', {
  type: 'unit'
});

console.log(listFormatter.format(formattedTemperatures));
// Output: "20°C, 22°C, 25°C, 23°C, 21°C"

تُضيف أدوات تنسيق درجة الحرارة رموز الدرجة تلقائيًا في المخرجات.

تعمل فهرنهايت بنفس الطريقة.

const temperatures = [68, 72, 77, 73, 70];

const numberFormatter = new Intl.NumberFormat('en-US', {
  style: 'unit',
  unit: 'fahrenheit'
});

const formattedTemperatures = temperatures.map(t => numberFormatter.format(t));

const listFormatter = new Intl.ListFormat('en-US', {
  type: 'unit'
});

console.log(listFormatter.format(formattedTemperatures));
// Output: "68°F, 72°F, 77°F, 73°F, 70°F"

يظل النمط متطابقًا عبر أنواع القياسات المختلفة. يتغير معرف الوحدة فقط.

تنسيق قياسات الحجم في القوائم

تستخدم قياسات الحجم معرفات الوحدات مثل liter وgallon وmilliliter وfluid-ounce.

const volumes = [1, 2, 3];

const numberFormatter = new Intl.NumberFormat('en-US', {
  style: 'unit',
  unit: 'liter'
});

const formattedVolumes = volumes.map(v => numberFormatter.format(v));

const listFormatter = new Intl.ListFormat('en-US', {
  type: 'unit'
});

console.log(listFormatter.format(formattedVolumes));
// Output: "1 L, 2 L, 3 L"

تعمل قياسات الحجم مع القيم العشرية.

const volumes = [0.5, 1.5, 2.5];

const numberFormatter = new Intl.NumberFormat('en-US', {
  style: 'unit',
  unit: 'liter',
  maximumFractionDigits: 1
});

const formattedVolumes = volumes.map(v => numberFormatter.format(v));

const listFormatter = new Intl.ListFormat('en-US', {
  type: 'unit'
});

console.log(listFormatter.format(formattedVolumes));
// Output: "0.5 L, 1.5 L, 2.5 L"

تتعامل أداة تنسيق الأرقام مع الدقة العشرية قبل أن تعالج أداة تنسيق القوائم القيم.

تنسيق قياسات السرعة في القوائم

تستخدم قياسات السرعة وحدات مركبة مثل kilometer-per-hour وmile-per-hour.

const speeds = [50, 75, 100];

const numberFormatter = new Intl.NumberFormat('en-US', {
  style: 'unit',
  unit: 'kilometer-per-hour'
});

const formattedSpeeds = speeds.map(s => numberFormatter.format(s));

const listFormatter = new Intl.ListFormat('en-US', {
  type: 'unit'
});

console.log(listFormatter.format(formattedSpeeds));
// Output: "50 km/h, 75 km/h, 100 km/h"

تعمل الأميال في الساعة بنفس الطريقة.

const speeds = [30, 45, 60];

const numberFormatter = new Intl.NumberFormat('en-US', {
  style: 'unit',
  unit: 'mile-per-hour'
});

const formattedSpeeds = speeds.map(s => numberFormatter.format(s));

const listFormatter = new Intl.ListFormat('en-US', {
  type: 'unit'
});

console.log(listFormatter.format(formattedSpeeds));
// Output: "30 mph, 45 mph, 60 mph"

تُنسق الوحدات المركبة تلقائيًا بالاختصارات والفواصل الصحيحة.

تحدد اللغة المحلية تنسيق فاصل القائمة

تتحكم معلمة اللغة المحلية في كيفية فصل عناصر القائمة وترقيمها. تستخدم اللغات المختلفة اصطلاحات مختلفة لتنسيق القوائم.

const distances = [5, 10, 15];

const numberFormatter = new Intl.NumberFormat('en-US', {
  style: 'unit',
  unit: 'kilometer'
});

const formattedDistances = distances.map(d => numberFormatter.format(d));

const enList = new Intl.ListFormat('en-US', {
  type: 'unit'
});

const frList = new Intl.ListFormat('fr-FR', {
  type: 'unit'
});

const deList = new Intl.ListFormat('de-DE', {
  type: 'unit'
});

console.log(enList.format(formattedDistances));
// Output: "5 km, 10 km, 15 km"

console.log(frList.format(formattedDistances));
// Output: "5 km, 10 km, 15 km"

console.log(deList.format(formattedDistances));
// Output: "5 km, 10 km, 15 km"

بينما تظل اختصارات الكيلومتر متشابهة عبر هذه اللغات المحلية، يمكن أن تختلف اصطلاحات المسافات والفواصل. تتعامل واجهة برمجة التطبيقات Intl.ListFormat مع قواعد التنسيق الخاصة باللغة المحلية تلقائيًا.

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

مطابقة لغة الأرقام المحلية مع لغة القائمة المحلية

عند تنسيق قوائم القياسات، استخدم نفس اللغة المحلية لكل من أداة تنسيق الأرقام وأداة تنسيق القوائم. يضمن ذلك تنسيقًا متسقًا في جميع المخرجات.

const distances = [1000, 2000, 3000];

const locale = 'de-DE';

const numberFormatter = new Intl.NumberFormat(locale, {
  style: 'unit',
  unit: 'meter'
});

const formattedDistances = distances.map(d => numberFormatter.format(d));

const listFormatter = new Intl.ListFormat(locale, {
  type: 'unit'
});

console.log(listFormatter.format(formattedDistances));
// Output: "1.000 m, 2.000 m, 3.000 m"

يستخدم التنسيق الألماني النقاط كفواصل للآلاف. يستخدم كل من منسق الأرقام ومنسق القوائم الاصطلاحات الألمانية لأنهما يشتركان في نفس اللغة المحلية.

استخدام لغات محلية مختلفة لتنسيق الأرقام والقوائم ينتج عنه مخرجات غير متسقة.

const distances = [1000, 2000, 3000];

const numberFormatter = new Intl.NumberFormat('de-DE', {
  style: 'unit',
  unit: 'meter'
});

const formattedDistances = distances.map(d => numberFormatter.format(d));

const listFormatter = new Intl.ListFormat('en-US', {
  type: 'unit'
});

console.log(listFormatter.format(formattedDistances));
// Output: "1.000 m, 2.000 m, 3.000 m"

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

التحكم في نمط عرض القائمة

يتحكم خيار style في مدى تفصيل تنسيق القائمة. يقبل الخيار ثلاث قيم: "long"، "short"، و"narrow".

const measurements = ['5 km', '10 km', '15 km'];

const longList = new Intl.ListFormat('en-US', {
  type: 'unit',
  style: 'long'
});

const shortList = new Intl.ListFormat('en-US', {
  type: 'unit',
  style: 'short'
});

const narrowList = new Intl.ListFormat('en-US', {
  type: 'unit',
  style: 'narrow'
});

console.log(longList.format(measurements));
// Output: "5 km, 10 km, 15 km"

console.log(shortList.format(measurements));
// Output: "5 km, 10 km, 15 km"

console.log(narrowList.format(measurements));
// Output: "5 km 10 km 15 km"

ينتج نمطا long وshort مخرجات متشابهة لقوائم الوحدات في اللغة الإنجليزية. يستخدم نمط narrow حداً أدنى من المسافات ويحذف الفواصل بين العناصر.

تُظهر اللغات المحلية المختلفة تبايناً أكبر بين الأنماط. تحدد اللغة المحلية التنسيق الدقيق لكل مستوى نمط.

الدمج مع أسماء الوحدات الطويلة

يمكنك تنسيق القياسات بأسماء الوحدات الكاملة بدلاً من الاختصارات عن طريق تعيين unitDisplay: 'long' في منسق الأرقام.

const distances = [5, 10, 15];

const numberFormatter = new Intl.NumberFormat('en-US', {
  style: 'unit',
  unit: 'kilometer',
  unitDisplay: 'long'
});

const formattedDistances = distances.map(d => numberFormatter.format(d));

const listFormatter = new Intl.ListFormat('en-US', {
  type: 'unit'
});

console.log(listFormatter.format(formattedDistances));
// Output: "5 kilometers, 10 kilometers, 15 kilometers"

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

const distances = [1, 5];

const numberFormatter = new Intl.NumberFormat('en-US', {
  style: 'unit',
  unit: 'kilometer',
  unitDisplay: 'long'
});

const formattedDistances = distances.map(d => numberFormatter.format(d));

const listFormatter = new Intl.ListFormat('en-US', {
  type: 'unit'
});

console.log(listFormatter.format(formattedDistances));
// Output: "1 kilometer, 5 kilometers"

يستخدم منسق الأرقام "كيلومتر" للرقم 1 و"كيلومترات" للرقم 5. يدمجها منسق القوائم بالفواصل المناسبة.

إعادة استخدام المنسقات لأداء أفضل

يتضمن إنشاء نسخ من Intl.NumberFormat وIntl.ListFormat تحميل بيانات اللغة المحلية ومعالجة الخيارات. عندما تقوم بتنسيق قوائم متعددة من القياسات، أنشئ المنسقات مرة واحدة وأعد استخدامها.

const numberFormatter = new Intl.NumberFormat('en-US', {
  style: 'unit',
  unit: 'kilometer'
});

const listFormatter = new Intl.ListFormat('en-US', {
  type: 'unit'
});

const distanceLists = [
  [5, 10, 15],
  [20, 25, 30],
  [35, 40, 45]
];

distanceLists.forEach(distances => {
  const formattedDistances = distances.map(d => numberFormatter.format(d));
  console.log(listFormatter.format(formattedDistances));
});
// Output:
// "5 km, 10 km, 15 km"
// "20 km, 25 km, 30 km"
// "35 km, 40 km, 45 km"

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

إنشاء دالة منسق قابلة لإعادة الاستخدام

يمكنك تغليف نمط التنسيق المكون من خطوتين في دالة قابلة لإعادة الاستخدام.

function formatMeasurementList(values, locale, unit) {
  const numberFormatter = new Intl.NumberFormat(locale, {
    style: 'unit',
    unit: unit
  });

  const formattedValues = values.map(v => numberFormatter.format(v));

  const listFormatter = new Intl.ListFormat(locale, {
    type: 'unit'
  });

  return listFormatter.format(formattedValues);
}

console.log(formatMeasurementList([5, 10, 15], 'en-US', 'kilometer'));
// Output: "5 km, 10 km, 15 km"

console.log(formatMeasurementList([50, 75, 100], 'en-US', 'kilogram'));
// Output: "50 kg, 75 kg, 100 kg"

console.log(formatMeasurementList([20, 22, 25], 'en-US', 'celsius'));
// Output: "20°C, 22°C, 25°C"

تتعامل هذه الدالة مع أي نوع قياس ولغة. يمكنك توسيعها لقبول خيارات تنسيق إضافية.

function formatMeasurementList(values, locale, unit, options = {}) {
  const numberFormatter = new Intl.NumberFormat(locale, {
    style: 'unit',
    unit: unit,
    ...options
  });

  const formattedValues = values.map(v => numberFormatter.format(v));

  const listFormatter = new Intl.ListFormat(locale, {
    type: 'unit'
  });

  return listFormatter.format(formattedValues);
}

console.log(formatMeasurementList(
  [5.123, 10.789, 15.456],
  'en-US',
  'kilometer',
  { maximumFractionDigits: 1 }
));
// Output: "5.1 km, 10.8 km, 15.5 km"

console.log(formatMeasurementList(
  [1, 5, 10],
  'en-US',
  'kilometer',
  { unitDisplay: 'long' }
));
// Output: "1 kilometer, 5 kilometers, 10 kilometers"

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

تنسيق القوائم حسب لغة المستخدم

بدلاً من تحديد لغة معينة بشكل ثابت، يمكنك استخدام تفضيلات لغة متصفح المستخدم. تُرجع خاصية navigator.language اللغة المفضلة للمستخدم.

const userLocale = navigator.language;

const distances = [5, 10, 15];

const numberFormatter = new Intl.NumberFormat(userLocale, {
  style: 'unit',
  unit: 'kilometer'
});

const formattedDistances = distances.map(d => numberFormatter.format(d));

const listFormatter = new Intl.ListFormat(userLocale, {
  type: 'unit'
});

console.log(listFormatter.format(formattedDistances));
// Output varies by user's locale

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

عرض قوائم القياسات في التطبيقات

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

const splitTimes = [5, 10, 15, 20];

const numberFormatter = new Intl.NumberFormat(navigator.language, {
  style: 'unit',
  unit: 'kilometer',
  maximumFractionDigits: 1
});

const formattedTimes = splitTimes.map(t => numberFormatter.format(t));

const listFormatter = new Intl.ListFormat(navigator.language, {
  type: 'unit'
});

const result = listFormatter.format(formattedTimes);

document.getElementById('split-times').textContent = result;
// Displays: "5 km, 10 km, 15 km, 20 km" (or locale equivalent)

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