واجهة برمجة Intl.DurationFormat

تنسيق المدد الزمنية في جافا سكريبت مع التوطين التلقائي

مقدمة

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

const hours = 1;
const minutes = 46;
const seconds = 40;
const duration = `${hours}h ${minutes}m ${seconds}s`;

هذا ينتج "1h 46m 40s" لجميع المستخدمين بغض النظر عن اللغة. يرى المستخدمون الفرنسيون "1h 46m 40s" عندما يتوقعون "1 h 46 min 40 s". يرى المستخدمون الألمان نفس الاختصارات الإنجليزية. لا يحصل المستخدمون الإسبان على حرف العطف "y" بين الوحدات.

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

const duration = { hours: 1, minutes: 46, seconds: 40 };
new Intl.DurationFormat('fr-FR', { style: 'short' }).format(duration);
// "1 h, 46 min et 40 s"

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

ما هي المدد

المدة تمثل فترة زمنية، وليست نقطة في الزمن. التواريخ والأوقات تحدد متى يحدث شيء ما. المدد تقيس كم من الوقت يستغرق شيء ما.

هذا التمييز مهم للتنسيق. تتضمن التواريخ التقويمات والمناطق الزمنية والقواعد التاريخية. المدد أبسط: فهي تقيس الوقت المنقضي بوحدات قياسية دون سياق تقويمي.

تتعامل واجهة برمجة التطبيقات Intl.DurationFormat مع المدد. تتعامل واجهة برمجة التطبيقات Intl.DateTimeFormat مع التواريخ والأوقات. استخدم الأداة المناسبة لكل مهمة.

إنشاء منسق للمدة

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

const formatter = new Intl.DurationFormat('en', { style: 'long' });

استدعِ format() مع كائن المدة. يحتوي الكائن على خصائص رقمية لوحدات الوقت. قم بتضمين الوحدات التي تريد عرضها فقط.

const duration = { hours: 2, minutes: 30 };
formatter.format(duration);
// "2 hours and 30 minutes"

تدعم واجهة برمجة التطبيقات وحدات الوقت التالية: years، months، weeks، days، hours، minutes، seconds، milliseconds، microseconds، nanoseconds. استخدم أي وحدات تتناسب مع بياناتك.

اختيار نمط التنسيق

يتحكم خيار style في كثافة الإخراج. تتوفر أربعة أنماط: long، وshort، وnarrow، وdigital.

النمط الطويل يستخدم كلمات كاملة. استخدم هذا للنثر وإمكانية الوصول.

const duration = { hours: 1, minutes: 46, seconds: 40 };
new Intl.DurationFormat('en', { style: 'long' }).format(duration);
// "1 hour, 46 minutes and 40 seconds"

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

new Intl.DurationFormat('en', { style: 'short' }).format(duration);
// "1 hr, 46 min and 40 sec"

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

new Intl.DurationFormat('en', { style: 'narrow' }).format(duration);
// "1h 46m 40s"

النمط الرقمي ينتج إخراجًا يشبه المؤقت باستخدام النقطتين. استخدم هذا لمشغلات الوسائط وشاشات العد التنازلي.

new Intl.DurationFormat('en', { style: 'digital' }).format(duration);
// "1:46:40"

التوطين عبر اللغات

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

const duration = { hours: 1, minutes: 46, seconds: 40 };

new Intl.DurationFormat('en', { style: 'long' }).format(duration);
// "1 hour, 46 minutes and 40 seconds"

new Intl.DurationFormat('fr', { style: 'long' }).format(duration);
// "1 heure, 46 minutes et 40 secondes"

new Intl.DurationFormat('de', { style: 'long' }).format(duration);
// "1 Stunde, 46 Minuten und 40 Sekunden"

new Intl.DurationFormat('es', { style: 'long' }).format(duration);
// "1 hora, 46 minutos y 40 segundos"

new Intl.DurationFormat('ja', { style: 'long' }).format(duration);
// "1時間46分40秒"

لاحظ كيف تستخدم كل لغة محلية كلمات واختصارات وروابط مختلفة. الفرنسية تستخدم "et"، والألمانية تستخدم "und"، والإسبانية تستخدم "y"، واليابانية لا تستخدم روابط. واجهة البرمجة تعرف هذه القواعد.

الأنماط القصيرة والضيقة تتوطن أيضًا بشكل صحيح.

new Intl.DurationFormat('fr', { style: 'short' }).format(duration);
// "1 h, 46 min et 40 s"

new Intl.DurationFormat('de', { style: 'narrow' }).format(duration);
// "1 Std. 46 Min. 40 Sek."

إنشاء كائنات المدة من حسابات الوقت

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

قم بتحويل الميلي ثانية إلى وحدات المدة بالقسمة على العوامل المناسبة.

const milliseconds = 6400000; // 1 ساعة، 46 دقيقة، 40 ثانية
const hours = Math.floor(milliseconds / 3600000);
const minutes = Math.floor((milliseconds % 3600000) / 60000);
const seconds = Math.floor((milliseconds % 60000) / 1000);

const duration = { hours, minutes, seconds };
new Intl.DurationFormat('en', { style: 'short' }).format(duration);
// "1 hr, 46 min and 40 sec"

احسب المدة من تاريخين بطرح الطوابع الزمنية.

const start = new Date('2025-01-01T10:00:00');
const end = new Date('2025-01-01T11:46:40');
const diffMs = end - start;

const hours = Math.floor(diffMs / 3600000);
const minutes = Math.floor((diffMs % 3600000) / 60000);
const seconds = Math.floor((diffMs % 60000) / 1000);

const duration = { hours, minutes, seconds };

قم بتضمين الوحدات التي تحتاجها فقط. تجاهل القيم الصفرية ما لم ترغب في عرضها.

const duration = { minutes: 5, seconds: 30 };
new Intl.DurationFormat('en', { style: 'long' }).format(duration);
// "5 minutes and 30 seconds"

التحكم في الوحدات التي تظهر

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

حدد نمط العرض لكل وحدة بشكل فردي. الخيارات هي long، short، narrow، numeric، و2-digit.

const duration = { hours: 1, minutes: 5, seconds: 3 };

new Intl.DurationFormat('en', {
  hours: 'long',
  minutes: 'numeric',
  seconds: '2-digit'
}).format(duration);
// "1 hour, 5:03"

نمط numeric يعرض الرقم بدون تسميات. نمط 2-digit يضيف تعبئة بالأصفار. استخدم هذه للعروض المدمجة التي تمزج النص والأرقام.

أخفِ الوحدات بحذفها من كائن المدة والخيارات.

const duration = { hours: 2, minutes: 30 };
new Intl.DurationFormat('en', { style: 'short' }).format(duration);
// "2 hr and 30 min"

النمط الرقمي يتطلب وجود جميع الوحدات من الأكبر إلى الأصغر أو تكوينها بشكل صريح.

const duration = { minutes: 5, seconds: 30 };
new Intl.DurationFormat('en', { style: 'digital' }).format(duration);
// "5:30"

تنسيق مدة مشغل الفيديو

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

function formatVideoDuration(seconds) {
  const hours = Math.floor(seconds / 3600);
  const minutes = Math.floor((seconds % 3600) / 60);
  const secs = Math.floor(seconds % 60);

  const duration = hours > 0
    ? { hours, minutes, seconds: secs }
    : { minutes, seconds: secs };

  const locale = navigator.language;
  return new Intl.DurationFormat(locale, { style: 'digital' }).format(duration);
}

formatVideoDuration(6400); // "1:46:40"
formatVideoDuration(330);  // "5:30"

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

تنسيق أوقات الرحلات والسفر

تعرض واجهات حجز السفر مدة الرحلة. استخدم النمط القصير لسهولة القراءة في المساحات المحدودة.

function formatFlightDuration(departureDate, arrivalDate, locale) {
  const diffMs = arrivalDate - departureDate;
  const hours = Math.floor(diffMs / 3600000);
  const minutes = Math.floor((diffMs % 3600000) / 60000);

  const duration = { hours, minutes };
  return new Intl.DurationFormat(locale, { style: 'short' }).format(duration);
}

const departure = new Date('2025-06-15T10:30:00');
const arrival = new Date('2025-06-15T18:45:00');

formatFlightDuration(departure, arrival, 'en');
// "8 hr and 15 min"

formatFlightDuration(departure, arrival, 'fr');
// "8 h et 15 min"

تنسيق مدة التمارين والأنشطة

تتبع تطبيقات اللياقة البدنية مدة التمرين. استخدم النمط الطويل لملخصات الجلسات والنمط الضيق لعروض القوائم.

function formatWorkoutDuration(startTime, endTime, locale) {
  const diffMs = endTime - startTime;
  const hours = Math.floor(diffMs / 3600000);
  const minutes = Math.floor((diffMs % 3600000) / 60000);

  const duration = hours > 0
    ? { hours, minutes }
    : { minutes };

  return new Intl.DurationFormat(locale, { style: 'long' }).format(duration);
}

const workoutStart = new Date('2025-06-15T07:00:00');
const workoutEnd = new Date('2025-06-15T08:15:00');

formatWorkoutDuration(workoutStart, workoutEnd, 'en');
// "1 hour and 15 minutes"

الحصول على أجزاء منسقة للعرض المخصص

تُرجع طريقة formatToParts() مصفوفة من الكائنات تمثل كل جزء من المخرجات المنسقة. استخدم هذا لتنسيق الأجزاء الفردية أو بناء تخطيطات مخصصة.

const duration = { hours: 1, minutes: 46, seconds: 40 };
const parts = new Intl.DurationFormat('en', { style: 'long' }).formatToParts(duration);

كل جزء له type وvalue. تتضمن الأنواع hour، وminute، وsecond، وliteral، وتسميات الوحدات مثل hourUnit، وminuteUnit.

[
  { type: "integer", value: "1" },
  { type: "literal", value: " " },
  { type: "unit", value: "hour" },
  { type: "literal", value: ", " },
  { type: "integer", value: "46" },
  { type: "literal", value: " " },
  { type: "unit", value: "minutes" },
  { type: "literal", value: " and " },
  { type: "integer", value: "40" },
  { type: "literal", value: " " },
  { type: "unit", value: "seconds" }
]

قم بالتكرار على الأجزاء لتطبيق التنسيق المخصص.

function StyledDuration({ duration }) {
  const parts = new Intl.DurationFormat('en', { style: 'long' }).formatToParts(duration);

  return parts.map((part, i) => {
    if (part.type === 'integer') {
      return <strong key={i}>{part.value}</strong>;
    }
    return <span key={i}>{part.value}</span>;
  });
}

إعادة استخدام نماذج المنسق لتحسين الأداء

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

const formatter = new Intl.DurationFormat('en', { style: 'short' });

const durations = [
  { hours: 1, minutes: 30 },
  { hours: 2, minutes: 15 },
  { hours: 0, minutes: 45 }
];

durations.map(d => formatter.format(d));
// ["1 hr and 30 min", "2 hr and 15 min", "45 min"]

يحسن هذا النمط الأداء عند تنسيق العديد من المدد في الحلقات أو العروض.

الانتقال من بناء السلاسل النصية يدويًا

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

قبل:

function formatDuration(hours, minutes) {
  if (hours > 0 && minutes > 0) {
    return `${hours}h ${minutes}m`;
  } else if (hours > 0) {
    return `${hours}h`;
  } else {
    return `${minutes}m`;
  }
}

بعد:

function formatDuration(hours, minutes, locale) {
  const duration = {};
  if (hours > 0) duration.hours = hours;
  if (minutes > 0) duration.minutes = minutes;

  return new Intl.DurationFormat(locale, { style: 'narrow' }).format(duration);
}

إصدار واجهة برمجة التطبيقات يتعامل مع جميع المنطق الشرطي تلقائيًا ويدعم لغات متعددة.

الانتقال من المكتبات

توفر مكتبات مثل Moment.js و date-fns تنسيق المدة الزمنية ولكنها تزيد من حجم الحزمة. واجهة البرمجة الأصلية تلغي هذه التبعية.

استبدال تنسيق المدة في Moment.js:

// قبل: Moment.js
const duration = moment.duration(6400, 'seconds');
const formatted = duration.hours() + 'h ' + duration.minutes() + 'm';

// بعد: Intl.DurationFormat
const duration = {
  hours: Math.floor(6400 / 3600),
  minutes: Math.floor((6400 % 3600) / 60)
};
new Intl.DurationFormat('en', { style: 'narrow' }).format(duration);

استبدال تنسيق المدة في date-fns:

// قبل: date-fns
import { formatDuration, intervalToDuration } from 'date-fns';
const duration = intervalToDuration({ start: 0, end: 6400000 });
const formatted = formatDuration(duration);

// بعد: Intl.DurationFormat
const ms = 6400000;
const duration = {
  hours: Math.floor(ms / 3600000),
  minutes: Math.floor((ms % 3600000) / 60000),
  seconds: Math.floor((ms % 60000) / 1000)
};
new Intl.DurationFormat('en', { style: 'long' }).format(duration);

توفر واجهة البرمجة الأصلية نفس الوظائف بدون تبعيات.

دعم المتصفحات والبدائل

أصبحت واجهة برمجة التطبيقات Intl.DurationFormat أساسية في مارس 2025. وهي تعمل في أحدث إصدارات Chrome وEdge وFirefox وSafari.

تحقق من الدعم قبل الاستخدام:

if (typeof Intl.DurationFormat !== 'undefined') {
  const formatter = new Intl.DurationFormat('en', { style: 'short' });
  return formatter.format(duration);
} else {
  // بديل للمتصفحات القديمة
  return `${duration.hours}h ${duration.minutes}m`;
}

للحصول على دعم أوسع، استخدم polyfill. يوفر مشروع FormatJS حزمة @formatjs/intl-durationformat.

npm install @formatjs/intl-durationformat

استيراد وتطبيق polyfill إذا لزم الأمر:

if (!Intl.DurationFormat) {
  await import('@formatjs/intl-durationformat/polyfill');
}

يضيف polyfill حوالي 15 كيلوبايت مضغوطة بتقنية gzip. قم بتحميله بشكل مشروط لتجنب العبء الزائد على المتصفحات الحديثة.

متى تستخدم DurationFormat

استخدم Intl.DurationFormat عند عرض الوقت المنقضي، أو الوقت المتبقي، أو قياسات المدة. يشمل ذلك مشغلات الفيديو، والمؤقتات، والعد التنازلي، وتطبيقات التتبع، وحجوزات السفر، وعرض مدة الجلسات.

لا تستخدمه للتواريخ أو الأوقات أو الطوابع الزمنية. استخدم Intl.DateTimeFormat لتلك الحالات. لا تستخدمه للتعبيرات الزمنية النسبية مثل "قبل ساعتين". استخدم Intl.RelativeTimeFormat لتلك الحالات.

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