fix(i18n): numbers, units, dates and order in the UI language, and after a switch (E30 S3)
Every locale formatter takes the language as an argument. Under the React
Compiler a formatter that read the i18n singleton was memoized on its other
arguments, so a card kept "2 hr 4 min" after a switch to Hungarian; plexLang()
had the same flaw and left Plex queries in the old language. Components now
take the language from useTranslation, and the signature makes forgetting it
a type error.
- ratings, file sizes, stream stats: the language's decimal mark ("8,3")
- view and subscriber counts compact in the language ("1,2 E")
- seconds as the language's unit ("6 mp") in the sliders and the stats
- a person's birth and death dates as dates, not ISO strings
- A-Z lists by the shown name in the language's alphabet (compareText),
the tag catalog re-sorted by its translated names
- lint local/locale-format (was date-format) also refuses Intl.NumberFormat
outside lib/format.ts, localeCompare, and a component reading the language
off the i18n singleton
This commit is contained in:
@@ -103,7 +103,8 @@ export default function AdminUsers() {
|
||||
}
|
||||
|
||||
function UsersRoles({ me }: { me: Me }) {
|
||||
const { t } = useTranslation();
|
||||
const { t, i18n } = useTranslation();
|
||||
const lang = i18n.language;
|
||||
const qc = useQueryClient();
|
||||
const confirm = useConfirm();
|
||||
const q = useQuery({ queryKey: qk.adminUsers(), queryFn: api.adminUsers });
|
||||
@@ -336,14 +337,14 @@ function UsersRoles({ me }: { me: Me }) {
|
||||
<Tooltip
|
||||
hint={
|
||||
u.last_login_at
|
||||
? t("users.roles.lastLogin", { time: formatDateTime(u.last_login_at) })
|
||||
? t("users.roles.lastLogin", { time: formatDateTime(u.last_login_at, lang) })
|
||||
: u.is_demo
|
||||
? t("users.roles.lastLoginDemo")
|
||||
: t("users.roles.lastLoginNone")
|
||||
}
|
||||
>
|
||||
<span className="relative hidden sm:inline-block w-20 shrink-0 text-right text-2xs text-muted tabular-nums">
|
||||
{u.last_login_at ? relativeTime(u.last_login_at) : "—"}
|
||||
{u.last_login_at ? relativeTime(u.last_login_at, lang) : "—"}
|
||||
</span>
|
||||
</Tooltip>
|
||||
</div>
|
||||
@@ -440,7 +441,8 @@ function PendingAccessRowView({
|
||||
onActivate: () => void;
|
||||
onResend: () => void;
|
||||
}) {
|
||||
const { t } = useTranslation();
|
||||
const { t, i18n } = useTranslation();
|
||||
const lang = i18n.language;
|
||||
return (
|
||||
<div className={`${SURFACE.card} flex items-center gap-2 p-2.5`}>
|
||||
<div className="min-w-0 flex-1">
|
||||
@@ -449,7 +451,7 @@ function PendingAccessRowView({
|
||||
{row.created_at && (
|
||||
<span>
|
||||
{t("users.pendingAccess.signedUp", {
|
||||
time: formatDateTime(row.created_at),
|
||||
time: formatDateTime(row.created_at, lang),
|
||||
})}
|
||||
</span>
|
||||
)}
|
||||
@@ -536,6 +538,7 @@ function InviteLangPicker({
|
||||
|
||||
function AdminInvites() {
|
||||
const { t, i18n } = useTranslation();
|
||||
const lang = i18n.language;
|
||||
const qc = useQueryClient();
|
||||
const confirm = useConfirm();
|
||||
const me = useMe();
|
||||
@@ -640,7 +643,7 @@ function AdminInvites() {
|
||||
: "settings.invites.inviteConfirm",
|
||||
{
|
||||
email: inv.email,
|
||||
time: formatDateTime(inv.invited_at ?? new Date(0).toISOString()),
|
||||
time: formatDateTime(inv.invited_at ?? new Date(0).toISOString(), lang),
|
||||
},
|
||||
)}
|
||||
</p>
|
||||
@@ -744,7 +747,7 @@ function AdminInvites() {
|
||||
hint={
|
||||
i.invited_at
|
||||
? t("settings.invites.invitedAt", {
|
||||
time: formatDateTime(i.invited_at),
|
||||
time: formatDateTime(i.invited_at, lang),
|
||||
})
|
||||
: t("settings.invites.inviteHint")
|
||||
}
|
||||
@@ -931,7 +934,8 @@ function InviteRow({
|
||||
onDelete: () => void;
|
||||
busy: boolean;
|
||||
}) {
|
||||
const { t } = useTranslation();
|
||||
const { t, i18n } = useTranslation();
|
||||
const lang = i18n.language;
|
||||
return (
|
||||
<div className={`${SURFACE.card} flex items-center gap-2 p-2.5`}>
|
||||
<div className="min-w-0 flex-1">
|
||||
@@ -939,7 +943,7 @@ function InviteRow({
|
||||
{inv.requested_at && (
|
||||
<div className="text-2xs text-muted">
|
||||
{t("settings.invites.requested", {
|
||||
time: formatDateTime(inv.requested_at),
|
||||
time: formatDateTime(inv.requested_at, lang),
|
||||
})}
|
||||
</div>
|
||||
)}
|
||||
|
||||
Reference in New Issue
Block a user