كيفية تنسيق الوقت النسبي في Next.js (Pages Router) الإصدار 16

تنسيق الطوابع الزمنية كعبارات 'منذ يومين'

المشكلة

عرض الطوابع الزمنية كعبارات وقت نسبي مثل "منذ يومين" أو "خلال 3 ساعات" يجعل المحتوى يبدو فوريًا وسياقيًا. ومع ذلك، تتبع هذه العبارات أنماطًا نحوية معقدة تختلف بشكل كبير عبر اللغات. تضع الإنجليزية "ago" بعد الكميات الماضية و"in" قبل الكميات المستقبلية، لكن اللغات الأخرى قد تستخدم ترتيبات كلمات مختلفة، أو تصرّف وحدات الوقت بناءً على الكمية، أو تستخدم هياكل نحوية مختلفة تمامًا. إنشاء هذه العبارات يدويًا باستخدام دمج النصوص ينتج مخرجات غير صحيحة في كل لغة باستثناء اللغة التي كُتبت بها، مما يكسر تجربة المستخدم للجماهير الدولية.

الحل

استخدم تنسيق الوقت النسبي في react-intl لتحويل فروقات الوقت الرقمية إلى عبارات صحيحة نحويًا للغة المستخدم. احسب فرق الوقت بين طابع زمني واللحظة الحالية، حدد الوحدة المناسبة (ثوانٍ، دقائق، ساعات، أيام)، ومرر كلا القيمتين إلى واجهات برمجة التطبيقات الخاصة بالتنسيق في react-intl. تتعامل واجهة برمجة التطبيقات الأساسية Intl.RelativeTimeFormat مع القواعد النحوية الخاصة باللغة، وترتيب الكلمات، وقواعد التصريف تلقائيًا.

الخطوات

1. إنشاء دالة مساعدة لحساب قيم الوقت النسبي

يجب تحويل فرق الوقت إلى قيمة رقمية ووحدة مناسبة. قم ببناء دالة تقارن طابعًا زمنيًا بالوقت الحالي وتختار أفضل وحدة.

export function getRelativeTimeValue(date: Date | number) {
  const now = Date.now();
  const timestamp = typeof date === "number" ? date : date.getTime();
  const diffInSeconds = (timestamp - now) / 1000;

  const minute = 60;
  const hour = minute * 60;
  const day = hour * 24;
  const week = day * 7;
  const month = day * 30;
  const year = day * 365;

  const absDiff = Math.abs(diffInSeconds);

  if (absDiff < minute) {
    return { value: Math.round(diffInSeconds), unit: "second" as const };
  } else if (absDiff < hour) {
    return {
      value: Math.round(diffInSeconds / minute),
      unit: "minute" as const,
    };
  } else if (absDiff < day) {
    return { value: Math.round(diffInSeconds / hour), unit: "hour" as const };
  } else if (absDiff < week) {
    return { value: Math.round(diffInSeconds / day), unit: "day" as const };
  } else if (absDiff < month) {
    return { value: Math.round(diffInSeconds / week), unit: "week" as const };
  } else if (absDiff < year) {
    return { value: Math.round(diffInSeconds / month), unit: "month" as const };
  } else {
    return { value: Math.round(diffInSeconds / year), unit: "year" as const };
  }
}

تُرجع هذه الدالة قيمة رقمية موقّعة (سالبة للماضي، موجبة للمستقبل) والوحدة الأكثر ملاءمة بناءً على حجم الفرق.

2. تنسيق الوقت النسبي باستخدام خطاف useIntl

تُرجع دالة formatRelativeTime نص وقت نسبي منسق وتتوقع قيمة رقمية ووحدة وخيارات تتوافق مع Intl.RelativeTimeFormatOptions. استخدم الدالة المساعدة من الخطوة 1 للحصول على القيمة والوحدة، ثم قم بتنسيقها.

import { useIntl } from "react-intl";
import { getRelativeTimeValue } from "@/lib/relative-time";

export default function CommentTimestamp({ date }: { date: Date }) {
  const intl = useIntl();
  const { value, unit } = getRelativeTimeValue(date);

  return (
    <time dateTime={date.toISOString()}>
      {intl.formatRelativeTime(value, unit)}
    </time>
  );
}

تنتج طريقة formatRelativeTime عبارات مناسبة للغة مثل "منذ يومين" بالعربية أو "2 days ago" بالإنجليزية أو "il y a 2 jours" بالفرنسية.

3. استخدام FormattedRelativeTime للتنسيق التصريحي

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

import { FormattedRelativeTime } from "react-intl";
import { getRelativeTimeValue } from "@/lib/relative-time";

export default function LiveTimestamp({ date }: { date: Date }) {
  const { value, unit } = getRelativeTimeValue(date);

  return (
    <time dateTime={date.toISOString()}>
      <FormattedRelativeTime
        value={value}
        unit={unit}
        numeric="auto"
        updateIntervalInSeconds={10}
      />
    </time>
  );
}

تتحكم خاصية updateIntervalInSeconds في عدد مرات إعادة عرض المكون، مما يحافظ على تحديث العبارة المعروضة مع مرور الوقت.

4. تخصيص نمط التنسيق

يقبل المكون RelativeTimeFormatOptions بما في ذلك خصائص numeric وstyle. اضبط هذه الخيارات للتحكم في تنسيق الإخراج.

import { FormattedRelativeTime } from "react-intl";
import { getRelativeTimeValue } from "@/lib/relative-time";

export default function CompactTimestamp({ date }: { date: Date }) {
  const { value, unit } = getRelativeTimeValue(date);

  return (
    <FormattedRelativeTime
      value={value}
      unit={unit}
      numeric="auto"
      style="narrow"
    />
  );
}

يؤدي تعيين numeric="auto" إلى إنتاج عبارات مثل "أمس" بدلاً من "منذ يوم واحد" عند الاقتضاء، ويُنشئ style="narrow" أشكالاً أقصر مثل "منذ شهرين" بدلاً من "منذ شهرين".