كيفية تنسيق الوقت النسبي في React Router v7
تنسيق الطوابع الزمنية كعبارات 'منذ يومين'
المشكلة
عرض الطوابع الزمنية كعبارات وقت نسبي مثل "منذ يومين" أو "خلال 3 ساعات" يجعل المحتوى يبدو فورياً وسياقياً. ومع ذلك، تتبع هذه العبارات قواعد نحوية معقدة تختلف بشكل كبير عبر اللغات. تضع الإنجليزية "ago" بعد الكميات الماضية و"in" قبل الكميات المستقبلية، لكن اللغات الأخرى قد تصرّف وحدة الوقت نفسها، أو تعيد ترتيب الكلمات، أو تستخدم هياكل نحوية مختلفة تماماً. إنشاء هذه العبارات يدوياً باستخدام دمج النصوص ينتج مخرجات غير صحيحة في كل لغة باستثناء اللغة التي قمت بترميزها بشكل ثابت، مما يكسر تجربة المستخدم للجماهير الدولية.
الحل
استخدم تنسيق الوقت النسبي الواعي بالإعدادات المحلية لتحويل فروقات الطوابع الزمنية إلى عبارات صحيحة نحوياً. احسب الفرق الزمني بين طابع زمني معين واللحظة الحالية، ثم قم بتنسيق هذا الفرق باستخدام قواعد الإعدادات المحلية للمستخدم. يضمن هذا أن تعبيرات الوقت الماضي والمستقبل تتبع القواعد النحوية الصحيحة، وترتيب الكلمات، وأنماط التصريف لكل لغة دون معالجة يدوية للنصوص.
الخطوات
1. إنشاء دالة مساعدة لحساب قيم الوقت النسبي
يتطلب مكون FormattedRelativeTime قيمة رقمية value وخاصية unit. قم ببناء دالة مساعدة تحسب الفرق الزمني وتختار وحدة مناسبة.
export function getRelativeTimeValue(date: Date | number) {
const now = Date.now();
const timestamp = typeof date === "number" ? date : date.getTime();
const diffInSeconds = Math.round((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: 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. إنشاء مكون وقت نسبي باستخدام FormattedRelativeTime
استخدم مكون FormattedRelativeTime من react-intl، والذي يعرض الوقت النسبي المنسق ويمكنه التحديث بشكل اختياري على فترات زمنية.
import { FormattedRelativeTime } from "react-intl";
import { getRelativeTimeValue } from "./getRelativeTimeValue";
interface RelativeTimeProps {
date: Date | number;
updateIntervalInSeconds?: number;
}
export function RelativeTime({
date,
updateIntervalInSeconds,
}: RelativeTimeProps) {
const { value, unit } = getRelativeTimeValue(date);
return (
<FormattedRelativeTime
value={value}
unit={unit}
numeric="auto"
updateIntervalInSeconds={updateIntervalInSeconds}
/>
);
}
يتيح خيار numeric="auto" للمنسق استخدام عبارات مثل "أمس" بدلاً من "منذ يوم واحد" عند الاقتضاء. تتحكم خاصية updateIntervalInSeconds الاختيارية في عدد مرات إعادة عرض المكون للحفاظ على تحديث الوقت النسبي.
3. استخدم المكون في مسار React Router
اعرض مكون الوقت النسبي في أي مكون مسار حيث تحتاج إلى عرض الطوابع الزمنية.
import { RelativeTime } from "./RelativeTime";
interface Post {
id: string;
title: string;
content: string;
createdAt: number;
}
export function PostDetail({ post }: { post: Post }) {
return (
<article>
<h1>{post.title}</h1>
<time dateTime={new Date(post.createdAt).toISOString()}>
<RelativeTime date={post.createdAt} />
</time>
<p>{post.content}</p>
</article>
);
}
ينسق المكون الطابع الزمني تلقائياً وفقاً للغة المستخدم، منتجاً عبارات مثل "منذ يومين" بالعربية، أو "2 days ago" بالإنجليزية، أو "il y a 2 jours" بالفرنسية، أو "hace 2 días" بالإسبانية.
4. نسق الوقت النسبي بشكل إجرائي باستخدام useIntl
في الحالات التي تحتاج فيها إلى السلسلة المنسقة مباشرة (مثل تعيين سمات العناصر)، استخدم دالة formatRelativeTime من خطاف useIntl.
import { useIntl } from "react-intl";
import { getRelativeTimeValue } from "./getRelativeTimeValue";
interface CommentProps {
author: string;
text: string;
timestamp: number;
}
export function Comment({ author, text, timestamp }: CommentProps) {
const intl = useIntl();
const { value, unit } = getRelativeTimeValue(timestamp);
const relativeTime = intl.formatRelativeTime(value, unit, {
numeric: "auto",
});
return (
<div aria-label={`Comment by ${author}, posted ${relativeTime}`}>
<strong>{author}</strong>
<p>{text}</p>
</div>
);
}
يمنحك هذا النهج سلسلة منسقة يمكنك استخدامها في السمات، أو دمجها مع نص آخر، أو تمريرها إلى واجهات برمجة تطبيقات غير React مع الحفاظ على الدعم الكامل للغة.