كيفية تنسيق الوقت النسبي في Next.js (موجه الصفحات) الإصدار 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 hook

تقوم دالة 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" ينشئ أشكالًا أقصر مثل "منذ شهرين" بدلاً من "منذ شهرين".