Format datetimes using i18n lang
parent
7a1488fcd3
commit
311ffc3672
|
@ -130,13 +130,14 @@ export const hashCode = (s) => {
|
||||||
return hash;
|
return hash;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const formatShortDateTime = (timestamp) =>
|
export const formatShortDateTime = (timestamp, language) =>
|
||||||
new Intl.DateTimeFormat("default", {
|
new Intl.DateTimeFormat(language, {
|
||||||
dateStyle: "short",
|
dateStyle: "short",
|
||||||
timeStyle: "short",
|
timeStyle: "short",
|
||||||
}).format(new Date(timestamp * 1000));
|
}).format(new Date(timestamp * 1000));
|
||||||
|
|
||||||
export const formatShortDate = (timestamp) => new Intl.DateTimeFormat("default", { dateStyle: "short" }).format(new Date(timestamp * 1000));
|
export const formatShortDate = (timestamp, language) =>
|
||||||
|
new Intl.DateTimeFormat(language, { dateStyle: "short" }).format(new Date(timestamp * 1000));
|
||||||
|
|
||||||
export const formatBytes = (bytes, decimals = 2) => {
|
export const formatBytes = (bytes, decimals = 2) => {
|
||||||
if (bytes === 0) return "0 bytes";
|
if (bytes === 0) return "0 bytes";
|
||||||
|
|
|
@ -39,7 +39,6 @@ import EditIcon from "@mui/icons-material/Edit";
|
||||||
import { Trans, useTranslation } from "react-i18next";
|
import { Trans, useTranslation } from "react-i18next";
|
||||||
import DeleteOutlineIcon from "@mui/icons-material/DeleteOutline";
|
import DeleteOutlineIcon from "@mui/icons-material/DeleteOutline";
|
||||||
import InfoOutlinedIcon from "@mui/icons-material/InfoOutlined";
|
import InfoOutlinedIcon from "@mui/icons-material/InfoOutlined";
|
||||||
import i18n from "i18next";
|
|
||||||
import humanizeDuration from "humanize-duration";
|
import humanizeDuration from "humanize-duration";
|
||||||
import CelebrationIcon from "@mui/icons-material/Celebration";
|
import CelebrationIcon from "@mui/icons-material/Celebration";
|
||||||
import CloseIcon from "@mui/icons-material/Close";
|
import CloseIcon from "@mui/icons-material/Close";
|
||||||
|
@ -224,7 +223,7 @@ const ChangePasswordDialog = (props) => {
|
||||||
};
|
};
|
||||||
|
|
||||||
const AccountType = () => {
|
const AccountType = () => {
|
||||||
const { t } = useTranslation();
|
const { t, i18n } = useTranslation();
|
||||||
const { account } = useContext(AccountContext);
|
const { account } = useContext(AccountContext);
|
||||||
const [upgradeDialogKey, setUpgradeDialogKey] = useState(0);
|
const [upgradeDialogKey, setUpgradeDialogKey] = useState(0);
|
||||||
const [upgradeDialogOpen, setUpgradeDialogOpen] = useState(false);
|
const [upgradeDialogOpen, setUpgradeDialogOpen] = useState(false);
|
||||||
|
@ -283,7 +282,7 @@ const AccountType = () => {
|
||||||
{account.billing?.paid_until && !account.billing?.cancel_at && (
|
{account.billing?.paid_until && !account.billing?.cancel_at && (
|
||||||
<Tooltip
|
<Tooltip
|
||||||
title={t("account_basics_tier_paid_until", {
|
title={t("account_basics_tier_paid_until", {
|
||||||
date: formatShortDate(account.billing?.paid_until),
|
date: formatShortDate(account.billing?.paid_until, i18n.language),
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
<span>
|
<span>
|
||||||
|
@ -328,7 +327,7 @@ const AccountType = () => {
|
||||||
{account.billing?.cancel_at > 0 && (
|
{account.billing?.cancel_at > 0 && (
|
||||||
<Alert severity="warning" sx={{ mt: 1 }}>
|
<Alert severity="warning" sx={{ mt: 1 }}>
|
||||||
{t("account_basics_tier_canceled_subscription", {
|
{t("account_basics_tier_canceled_subscription", {
|
||||||
date: formatShortDate(account.billing.cancel_at),
|
date: formatShortDate(account.billing.cancel_at, i18n.language),
|
||||||
})}
|
})}
|
||||||
</Alert>
|
</Alert>
|
||||||
)}
|
)}
|
||||||
|
@ -556,7 +555,7 @@ const AddPhoneNumberDialog = (props) => {
|
||||||
};
|
};
|
||||||
|
|
||||||
const Stats = () => {
|
const Stats = () => {
|
||||||
const { t } = useTranslation();
|
const { t, i18n } = useTranslation();
|
||||||
const { account } = useContext(AccountContext);
|
const { account } = useContext(AccountContext);
|
||||||
|
|
||||||
if (!account) {
|
if (!account) {
|
||||||
|
@ -798,7 +797,7 @@ const Tokens = () => {
|
||||||
};
|
};
|
||||||
|
|
||||||
const TokensTable = (props) => {
|
const TokensTable = (props) => {
|
||||||
const { t } = useTranslation();
|
const { t, i18n } = useTranslation();
|
||||||
const [snackOpen, setSnackOpen] = useState(false);
|
const [snackOpen, setSnackOpen] = useState(false);
|
||||||
const [upsertDialogKey, setUpsertDialogKey] = useState(0);
|
const [upsertDialogKey, setUpsertDialogKey] = useState(0);
|
||||||
const [upsertDialogOpen, setUpsertDialogOpen] = useState(false);
|
const [upsertDialogOpen, setUpsertDialogOpen] = useState(false);
|
||||||
|
@ -872,11 +871,11 @@ const TokensTable = (props) => {
|
||||||
{token.token !== session.token() && (token.label || "-")}
|
{token.token !== session.token() && (token.label || "-")}
|
||||||
</TableCell>
|
</TableCell>
|
||||||
<TableCell sx={{ whiteSpace: "nowrap" }} aria-label={t("account_tokens_table_expires_header")}>
|
<TableCell sx={{ whiteSpace: "nowrap" }} aria-label={t("account_tokens_table_expires_header")}>
|
||||||
{token.expires ? formatShortDateTime(token.expires) : <em>{t("account_tokens_table_never_expires")}</em>}
|
{token.expires ? formatShortDateTime(token.expires, i18n.language) : <em>{t("account_tokens_table_never_expires")}</em>}
|
||||||
</TableCell>
|
</TableCell>
|
||||||
<TableCell sx={{ whiteSpace: "nowrap" }} aria-label={t("account_tokens_table_last_access_header")}>
|
<TableCell sx={{ whiteSpace: "nowrap" }} aria-label={t("account_tokens_table_last_access_header")}>
|
||||||
<div style={{ display: "flex", alignItems: "center" }}>
|
<div style={{ display: "flex", alignItems: "center" }}>
|
||||||
<span>{formatShortDateTime(token.last_access)}</span>
|
<span>{formatShortDateTime(token.last_access, i18n.language)}</span>
|
||||||
<Tooltip
|
<Tooltip
|
||||||
title={t("account_tokens_table_last_origin_tooltip", {
|
title={t("account_tokens_table_last_origin_tooltip", {
|
||||||
ip: token.last_origin,
|
ip: token.last_origin,
|
||||||
|
|
|
@ -160,10 +160,10 @@ const autolink = (s) => {
|
||||||
};
|
};
|
||||||
|
|
||||||
const NotificationItem = (props) => {
|
const NotificationItem = (props) => {
|
||||||
const { t } = useTranslation();
|
const { t, i18n } = useTranslation();
|
||||||
const { notification } = props;
|
const { notification } = props;
|
||||||
const { attachment } = notification;
|
const { attachment } = notification;
|
||||||
const date = formatShortDateTime(notification.time);
|
const date = formatShortDateTime(notification.time, i18n.language);
|
||||||
const otherTags = unmatchedTags(notification.tags);
|
const otherTags = unmatchedTags(notification.tags);
|
||||||
const tags = otherTags.length > 0 ? otherTags.join(", ") : null;
|
const tags = otherTags.length > 0 ? otherTags.join(", ") : null;
|
||||||
const handleDelete = async () => {
|
const handleDelete = async () => {
|
||||||
|
@ -277,7 +277,7 @@ const NotificationItem = (props) => {
|
||||||
};
|
};
|
||||||
|
|
||||||
const Attachment = (props) => {
|
const Attachment = (props) => {
|
||||||
const { t } = useTranslation();
|
const { t, i18n } = useTranslation();
|
||||||
const { attachment } = props;
|
const { attachment } = props;
|
||||||
const expired = attachment.expires && attachment.expires < Date.now() / 1000;
|
const expired = attachment.expires && attachment.expires < Date.now() / 1000;
|
||||||
const expires = attachment.expires && attachment.expires > Date.now() / 1000;
|
const expires = attachment.expires && attachment.expires > Date.now() / 1000;
|
||||||
|
@ -296,7 +296,7 @@ const Attachment = (props) => {
|
||||||
if (expires) {
|
if (expires) {
|
||||||
infos.push(
|
infos.push(
|
||||||
t("notifications_attachment_link_expires", {
|
t("notifications_attachment_link_expires", {
|
||||||
date: formatShortDateTime(attachment.expires),
|
date: formatShortDateTime(attachment.expires, i18n.language),
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -117,10 +117,16 @@ export const SubscriptionPopup = (props) => {
|
||||||
])[0];
|
])[0];
|
||||||
const nowSeconds = Math.round(Date.now() / 1000);
|
const nowSeconds = Math.round(Date.now() / 1000);
|
||||||
const message = shuffle([
|
const message = shuffle([
|
||||||
`Hello friend, this is a test notification from ntfy web. It's ${formatShortDateTime(nowSeconds)} right now. Is that early or late?`,
|
`Hello friend, this is a test notification from ntfy web. It's ${formatShortDateTime(
|
||||||
|
nowSeconds,
|
||||||
|
"en-US"
|
||||||
|
)} right now. Is that early or late?`,
|
||||||
`So I heard you like ntfy? If that's true, go to GitHub and star it, or to the Play store and rate it. Thanks! Oh yeah, this is a test notification.`,
|
`So I heard you like ntfy? If that's true, go to GitHub and star it, or to the Play store and rate it. Thanks! Oh yeah, this is a test notification.`,
|
||||||
`It's almost like you want to hear what I have to say. I'm not even a machine. I'm just a sentence that Phil typed on a random Thursday.`,
|
`It's almost like you want to hear what I have to say. I'm not even a machine. I'm just a sentence that Phil typed on a random Thursday.`,
|
||||||
`Alright then, it's ${formatShortDateTime(nowSeconds)} already. Boy oh boy, where did the time go? I hope you're alright, friend.`,
|
`Alright then, it's ${formatShortDateTime(
|
||||||
|
nowSeconds,
|
||||||
|
"en-US"
|
||||||
|
)} already. Boy oh boy, where did the time go? I hope you're alright, friend.`,
|
||||||
`There are nine million bicycles in Beijing That's a fact; It's a thing we can't deny. I wonder if that's true ...`,
|
`There are nine million bicycles in Beijing That's a fact; It's a thing we can't deny. I wonder if that's true ...`,
|
||||||
`I'm really excited that you're trying out ntfy. Did you know that there are a few public topics, such as ntfy.sh/stats and ntfy.sh/announcements.`,
|
`I'm really excited that you're trying out ntfy. Did you know that there are a few public topics, such as ntfy.sh/stats and ntfy.sh/announcements.`,
|
||||||
`It's interesting to hear what people use ntfy for. I've heard people talk about using it for so many cool things. What do you use it for?`,
|
`It's interesting to hear what people use ntfy for. I've heard people talk about using it for so many cool things. What do you use it for?`,
|
||||||
|
|
|
@ -62,7 +62,7 @@ const Banner = {
|
||||||
|
|
||||||
const UpgradeDialog = (props) => {
|
const UpgradeDialog = (props) => {
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
const { t } = useTranslation();
|
const { t, i18n } = useTranslation();
|
||||||
const { account } = useContext(AccountContext); // May be undefined!
|
const { account } = useContext(AccountContext); // May be undefined!
|
||||||
const [error, setError] = useState("");
|
const [error, setError] = useState("");
|
||||||
const [tiers, setTiers] = useState(null);
|
const [tiers, setTiers] = useState(null);
|
||||||
|
@ -233,7 +233,7 @@ const UpgradeDialog = (props) => {
|
||||||
<Trans
|
<Trans
|
||||||
i18nKey="account_upgrade_dialog_cancel_warning"
|
i18nKey="account_upgrade_dialog_cancel_warning"
|
||||||
values={{
|
values={{
|
||||||
date: formatShortDate(account?.billing?.paid_until || 0),
|
date: formatShortDate(account?.billing?.paid_until || 0, i18n.language),
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</Alert>
|
</Alert>
|
||||||
|
|
Loading…
Reference in New Issue