一片一片 a2fd094b40
fix(i18n): survive a malformed locale cookie (#7553)
* fix(i18n): survive a malformed locale cookie

getLocaleFromCookie decoded the raw cookie value without a guard, so a
malformed percent-encoding threw URIError during locale bootstrap and in
formatTimeAgo. It also split the cookie on every "=", truncating values
that contain one. Decode defensively and split on the first "=" only.

* fix(i18n): normalize the cookie locale in formatTimeAgo

The second caller of getLocaleFromCookie cast the raw value to Locale, so a
malformed-but-known-prefixed cookie skipped normalization. Normalize it like
useI18n does, and cover the malformed and valid cookie paths.

---------

Co-authored-by: 一片一片 <192845873+gdut4140@users.noreply.github.com>
2026-10-26 23:37:38 +08:00

35 lines
1.2 KiB
TypeScript

import { formatDistanceToNow } from "date-fns";
import { enUS as dateFnsEnUS, zhCN as dateFnsZhCN } from "date-fns/locale";
import { detectLocale, normalizeLocale, type Locale } from "@/core/i18n";
import { getLocaleFromCookie } from "@/core/i18n/cookies";
function getDateFnsLocale(locale: Locale) {
switch (locale) {
case "zh-CN":
return dateFnsZhCN;
case "en-US":
default:
return dateFnsEnUS;
}
}
export function formatTimeAgo(date: Date | string | number, locale?: Locale) {
const savedLocale = locale ?? getLocaleFromCookie();
const effectiveLocale =
(savedLocale ? normalizeLocale(savedLocale) : null) ??
// Fallback when cookie is missing (or on first render)
detectLocale();
// Guard against invalid/empty timestamps (e.g. a backend returning "" for
// lastUpdated when there are no memories) -- date-fns would throw
// "Invalid time value" on `new Date("")`. Return a neutral placeholder.
const parsed = date instanceof Date ? date : new Date(date);
if (Number.isNaN(parsed.getTime())) {
return "-";
}
return formatDistanceToNow(parsed, {
addSuffix: true,
locale: getDateFnsLocale(effectiveLocale),
});
}