كيف تقوم بتنسيق الأوقات النسبية مثل منذ 3 أيام أو خلال ساعتين؟
استخدم Intl.RelativeTimeFormat لعرض الأوقات مثل منذ 3 أيام أو خلال ساعتين بأي لغة مع الجمع والتوطين التلقائي
مقدمة
تعرض خلاصات وسائل التواصل الاجتماعي وأقسام التعليقات وسجلات النشاط طوابع زمنية مثل "منذ 5 دقائق" أو "منذ ساعتين" أو "خلال 3 أيام". تساعد هذه الطوابع الزمنية النسبية المستخدمين على فهم وقت حدوث شيء ما بسرعة دون الحاجة إلى تحليل تاريخ مطلق.
عندما تقوم بترميز هذه النصوص بشكل ثابت باللغة الإنجليزية، فإنك تفترض أن جميع المستخدمين يتحدثون الإنجليزية ويتبعون قواعد اللغة الإنجليزية. اللغات المختلفة لديها طرق مختلفة للتعبير عن الوقت النسبي. الإسبانية تقول "hace 3 días" بدلاً من "3 days ago". اليابانية تستخدم "3日前" بهيكل مختلف تماماً. كل لغة لديها أيضاً قواعد جمع فريدة تحدد متى يتم استخدام الصيغ المفردة مقابل الصيغ الجمع.
توفر JavaScript واجهة برمجة التطبيقات Intl.RelativeTimeFormat للتعامل مع تنسيق الوقت النسبي تلقائياً. يشرح هذا الدرس كيفية تنسيق الأوقات النسبية بشكل صحيح لأي لغة باستخدام واجهة برمجة التطبيقات المدمجة هذه.
لماذا يحتاج تنسيق الوقت النسبي إلى التدويل
تعبر اللغات المختلفة عن الوقت النسبي بطرق مختلفة. الإنجليزية تضع وحدة الوقت قبل "ago" للأوقات الماضية وبعد "in" للأوقات المستقبلية. اللغات الأخرى تستخدم ترتيبات كلمات مختلفة أو حروف جر مختلفة أو هياكل نحوية مختلفة تماماً.
const rtfEnglish = new Intl.RelativeTimeFormat('en');
console.log(rtfEnglish.format(-3, 'day'));
// "3 days ago"
const rtfSpanish = new Intl.RelativeTimeFormat('es');
console.log(rtfSpanish.format(-3, 'day'));
// "hace 3 días"
const rtfJapanese = new Intl.RelativeTimeFormat('ja');
console.log(rtfJapanese.format(-3, 'day'));
// "3 日前"
تنتج كل لغة مخرجات طبيعية تتبع اصطلاحاتها الخاصة. لا تحتاج إلى معرفة هذه الاصطلاحات أو الاحتفاظ بملفات الترجمة. تتعامل واجهة برمجة التطبيقات مع جميع تفاصيل التنسيق تلقائياً.
تختلف قواعد الجمع أيضاً بشكل كبير عبر اللغات. الإنجليزية تميز بين "1 day" و"2 days". العربية لديها ستة أشكال جمع مختلفة حسب العدد. اليابانية تستخدم نفس الصيغة بغض النظر عن الكمية. تطبق واجهة برمجة التطبيقات Intl.RelativeTimeFormat قواعد الجمع الصحيحة لكل لغة.
واجهة برمجة التطبيقات Intl.RelativeTimeFormat
ينشئ المُنشئ Intl.RelativeTimeFormat مُنسِّقاً يحوّل القيم الرقمية ووحدات الوقت إلى نصوص محلية. تمرر معرّف اللغة المحلية كوسيط أول، ثم تستدعي الدالة format() مع قيمة ووحدة.
const rtf = new Intl.RelativeTimeFormat('en-US');
console.log(rtf.format(-1, 'day'));
// "1 day ago"
console.log(rtf.format(2, 'hour'));
// "in 2 hours"
تأخذ الدالة format() معاملين. الأول هو رقم يمثل مقدار الوقت. الثاني هو نص يحدد وحدة الوقت.
تشير الأرقام السالبة إلى الأوقات الماضية، بينما تشير الأرقام الموجبة إلى الأوقات المستقبلية. يجعل هذا الاصطلاح واجهة برمجة التطبيقات سهلة الاستخدام بمجرد فهم اصطلاح الإشارة.
تنسيق الأوقات الماضية والمستقبلية
تحدد إشارة القيمة ما إذا كان الوقت في الماضي أو المستقبل. تنتج القيم السالبة أزمنة ماضية، بينما تنتج القيم الموجبة أزمنة مستقبلية.
const rtf = new Intl.RelativeTimeFormat('en-US');
console.log(rtf.format(-5, 'minute'));
// "5 minutes ago"
console.log(rtf.format(5, 'minute'));
// "in 5 minutes"
console.log(rtf.format(-2, 'week'));
// "2 weeks ago"
console.log(rtf.format(2, 'week'));
// "in 2 weeks"
يعمل هذا النمط بشكل متسق عبر جميع وحدات الوقت وجميع اللغات. تختار واجهة برمجة التطبيقات تلقائياً البنية النحوية الصحيحة بناءً على ما إذا كانت القيمة موجبة أو سالبة.
وحدات الوقت المتاحة
تدعم واجهة برمجة التطبيقات ثماني وحدات زمنية تغطي معظم احتياجات تنسيق الوقت النسبي. يمكنك استخدام الصيغ المفردة أو الجمع، وكلاهما يعمل بشكل متطابق.
const rtf = new Intl.RelativeTimeFormat('en-US');
console.log(rtf.format(-30, 'second'));
// "30 seconds ago"
console.log(rtf.format(-15, 'minute'));
// "15 minutes ago"
console.log(rtf.format(-6, 'hour'));
// "6 hours ago"
console.log(rtf.format(-3, 'day'));
// "3 days ago"
console.log(rtf.format(-2, 'week'));
// "2 weeks ago"
console.log(rtf.format(-4, 'month'));
// "4 months ago"
console.log(rtf.format(-1, 'quarter'));
// "1 quarter ago"
console.log(rtf.format(-2, 'year'));
// "2 years ago"
تقبل واجهة برمجة التطبيقات الصيغ المفردة مثل day والصيغ الجمع مثل days. كلاهما ينتج مخرجات متطابقة. وحدة الربع مفيدة لتطبيقات الأعمال التي تعمل مع الفترات المالية.
استخدام اللغة الطبيعية مع numeric auto
يتحكم الخيار numeric في ما إذا كان المُنسِّق يستخدم الأرقام أو بدائل اللغة الطبيعية. القيمة الافتراضية هي always، والتي تعرض الأرقام دائماً.
const rtfAlways = new Intl.RelativeTimeFormat('en-US', {
numeric: 'always'
});
console.log(rtfAlways.format(-1, 'day'));
// "1 day ago"
console.log(rtfAlways.format(0, 'day'));
// "in 0 days"
console.log(rtfAlways.format(1, 'day'));
// "in 1 day"
تعيين numeric إلى auto ينتج صياغة أكثر طبيعية لقيم معينة.
const rtfAuto = new Intl.RelativeTimeFormat('en-US', {
numeric: 'auto'
});
console.log(rtfAuto.format(-1, 'day'));
// "yesterday"
console.log(rtfAuto.format(0, 'day'));
// "today"
console.log(rtfAuto.format(1, 'day'));
// "tomorrow"
يجعل هذا الخيار الواجهات تبدو أكثر حوارية. يرى المستخدمون "أمس" بدلاً من "منذ يوم واحد"، مما يُقرأ بشكل أكثر طبيعية. يعمل خيار auto عبر جميع وحدات الوقت وجميع اللغات، حيث توفر كل لغة بدائلها الاصطلاحية الخاصة.
اختيار نمط التنسيق
يتحكم خيار style في مستوى التفصيل في المخرجات. الأنماط الثلاثة المتاحة هي long وshort وnarrow.
const rtfLong = new Intl.RelativeTimeFormat('en-US', {
style: 'long'
});
console.log(rtfLong.format(-2, 'hour'));
// "2 hours ago"
const rtfShort = new Intl.RelativeTimeFormat('en-US', {
style: 'short'
});
console.log(rtfShort.format(-2, 'hour'));
// "2 hr. ago"
const rtfNarrow = new Intl.RelativeTimeFormat('en-US', {
style: 'narrow'
});
console.log(rtfNarrow.format(-2, 'hour'));
// "2h ago"
نمط long هو الافتراضي ويعمل بشكل جيد لمعظم الواجهات. يوفر نمط short مساحة في تخطيطات الهاتف المحمول أو الجداول. ينتج نمط narrow المخرجات الأكثر إيجازاً للتصاميم المقيدة للغاية بالمساحة.
حساب فروقات الوقت
تقوم واجهة برمجة التطبيقات Intl.RelativeTimeFormat بتنسيق القيم ولكنها لا تحسبها. يجب عليك حساب فرق الوقت بنفسك، ثم تمرير النتيجة إلى أداة التنسيق.
لحساب فرق الوقت، اطرح التاريخ المستهدف من التاريخ الحالي، ثم حوّل النتيجة من الميلي ثانية إلى الوحدة المطلوبة.
const rtf = new Intl.RelativeTimeFormat('en-US', { numeric: 'auto' });
function formatDaysAgo(date) {
const now = new Date();
const diffInMs = date - now;
const diffInDays = Math.round(diffInMs / (1000 * 60 * 60 * 24));
return rtf.format(diffInDays, 'day');
}
const yesterday = new Date();
yesterday.setDate(yesterday.getDate() - 1);
console.log(formatDaysAgo(yesterday));
// "yesterday"
const tomorrow = new Date();
tomorrow.setDate(tomorrow.getDate() + 1);
console.log(formatDaysAgo(tomorrow));
// "tomorrow"
تحسب هذه الدالة الفرق بالأيام بين التاريخ المستهدف والآن. يقسم الحساب الميلي ثانية على عدد الميلي ثانية في اليوم، ثم يقرّب إلى أقرب عدد صحيح.
ينتج الطرح date - now قيمة سالبة للتواريخ الماضية وقيمة موجبة للتواريخ المستقبلية. يتطابق هذا مع اصطلاح الإشارة المتوقع من قبل طريقة format().
بناء دالة أداة مساعدة كاملة
لإنشاء منسق وقت نسبي متعدد الأغراض، تحتاج إلى اختيار وحدة الوقت الأنسب بناءً على حجم الفرق الزمني.
const rtf = new Intl.RelativeTimeFormat('en-US', { numeric: 'auto' });
const units = {
year: 24 * 60 * 60 * 1000 * 365,
month: 24 * 60 * 60 * 1000 * 365 / 12,
week: 24 * 60 * 60 * 1000 * 7,
day: 24 * 60 * 60 * 1000,
hour: 60 * 60 * 1000,
minute: 60 * 1000,
second: 1000
};
function formatRelativeTime(date) {
const now = new Date();
const diffInMs = date - now;
const absDiff = Math.abs(diffInMs);
for (const [unit, msValue] of Object.entries(units)) {
if (absDiff >= msValue || unit === 'second') {
const value = Math.round(diffInMs / msValue);
return rtf.format(value, unit);
}
}
}
const fiveMinutesAgo = new Date(Date.now() - 5 * 60 * 1000);
console.log(formatRelativeTime(fiveMinutesAgo));
// "5 minutes ago"
const threeDaysAgo = new Date(Date.now() - 3 * 24 * 60 * 60 * 1000);
console.log(formatRelativeTime(threeDaysAgo));
// "3 days ago"
const tomorrow = new Date(Date.now() + 24 * 60 * 60 * 1000);
console.log(formatRelativeTime(tomorrow));
// "tomorrow"
تتكرر هذه الدالة عبر وحدات الوقت من الأكبر إلى الأصغر، وتختار أول وحدة يتجاوز فيها الفرق المطلق قيمة الوحدة بالميلي ثانية. يضمن الرجوع إلى الثواني أن تُرجع الدالة نتيجة دائماً.
تستخدم تعريفات الوحدات قيماً تقريبية. يتم حساب الأشهر على أنها 1/12 من السنة بدلاً من حساب أطوال الأشهر المختلفة. يعمل هذا التقريب بشكل جيد لعروض الوقت النسبي حيث تكون القيم التقريبية أكثر فائدة من الدقة المطلقة.
التنسيق حسب لغة المستخدم
بدلاً من تحديد لغة معينة بشكل ثابت، يمكنك استخدام اللغة المفضلة للمستخدم من المتصفح.
const userLocale = navigator.language;
const rtf = new Intl.RelativeTimeFormat(userLocale, { numeric: 'auto' });
const yesterday = new Date(Date.now() - 24 * 60 * 60 * 1000);
console.log(rtf.format(-1, 'day'));
// Output varies by user's locale
// For en-US: "yesterday"
// For es-ES: "ayer"
// For fr-FR: "hier"
// For de-DE: "gestern"
يعرض هذا النهج الأوقات النسبية وفقاً لتفضيلات اللغة لكل مستخدم دون الحاجة إلى اختيار اللغة يدوياً. يوفر المتصفح تفضيل اللغة، وتطبق واجهة برمجة التطبيقات اصطلاحات التنسيق المناسبة.
رؤية نفس الوقت بلغات مختلفة
تنتج نفس قيمة الوقت النسبي مخرجات مختلفة للغات مختلفة. تتبع كل لغة اصطلاحاتها الخاصة لترتيب الكلمات والقواعد النحوية والجمع.
const threeDaysAgo = -3;
const rtfEnglish = new Intl.RelativeTimeFormat('en-US');
console.log(rtfEnglish.format(threeDaysAgo, 'day'));
// "3 days ago"
const rtfSpanish = new Intl.RelativeTimeFormat('es-ES');
console.log(rtfSpanish.format(threeDaysAgo, 'day'));
// "hace 3 días"
const rtfFrench = new Intl.RelativeTimeFormat('fr-FR');
console.log(rtfFrench.format(threeDaysAgo, 'day'));
// "il y a 3 jours"
const rtfGerman = new Intl.RelativeTimeFormat('de-DE');
console.log(rtfGerman.format(threeDaysAgo, 'day'));
// "vor 3 Tagen"
const rtfJapanese = new Intl.RelativeTimeFormat('ja-JP');
console.log(rtfJapanese.format(threeDaysAgo, 'day'));
// "3 日前"
const rtfArabic = new Intl.RelativeTimeFormat('ar-SA');
console.log(rtfArabic.format(threeDaysAgo, 'day'));
// "قبل 3 أيام"
تنتج كل لغة مخرجات طبيعية يستخدمها المتحدثون الأصليون في المحادثة. تتعامل واجهة برمجة التطبيقات مع كل تعقيدات البنى النحوية المختلفة وأنظمة الكتابة المختلفة واتجاهات النص المختلفة.
إعادة استخدام المنسقات لتحسين الأداء
يتضمن إنشاء مثيل Intl.RelativeTimeFormat تحميل بيانات اللغة ومعالجة الخيارات. عند تنسيق طوابع زمنية متعددة، قم بإنشاء المنسق مرة واحدة وأعد استخدامه.
const rtf = new Intl.RelativeTimeFormat('en-US', { numeric: 'auto' });
const timestamps = [
new Date(Date.now() - 5 * 60 * 1000), // 5 minutes ago
new Date(Date.now() - 2 * 60 * 60 * 1000), // 2 hours ago
new Date(Date.now() - 24 * 60 * 60 * 1000) // 1 day ago
];
timestamps.forEach(date => {
const diffInMs = date - new Date();
const diffInMinutes = Math.round(diffInMs / (60 * 1000));
console.log(rtf.format(diffInMinutes, 'minute'));
});
هذا النهج أكثر كفاءة من إنشاء منسق جديد لكل طابع زمني. يصبح الفرق في الأداء كبيراً عند تنسيق مئات أو آلاف الطوابع الزمنية في موجزات النشاط أو سلاسل التعليقات.
استخدام الأوقات النسبية في الواجهات
يمكنك استخدام تنسيق الوقت النسبي في أي مكان تعرض فيه الطوابع الزمنية للمستخدمين. يشمل ذلك موجزات وسائل التواصل الاجتماعي، وأقسام التعليقات، وسجلات النشاط، وأنظمة الإشعارات، وأي واجهة يساعد فيها عرض المدة الزمنية منذ حدوث شيء ما المستخدمين على فهم السياق.
const rtf = new Intl.RelativeTimeFormat(navigator.language, {
numeric: 'auto'
});
function updateTimestamp(element, date) {
const now = new Date();
const diffInMs = date - now;
const diffInMinutes = Math.round(diffInMs / (60 * 1000));
element.textContent = rtf.format(diffInMinutes, 'minute');
}
const commentDate = new Date('2025-10-15T14:30:00');
const timestampElement = document.getElementById('comment-timestamp');
updateTimestamp(timestampElement, commentDate);
تعمل السلاسل النصية المنسقة مثل أي قيمة نصية أخرى. يمكنك إدراجها في محتوى نصي، أو سمات، أو أي سياق آخر تعرض فيه معلومات للمستخدمين.