diff --git a/src/__data__/languages.json b/src/__data__/languages.json
index c6be617..2ce307b 100644
--- a/src/__data__/languages.json
+++ b/src/__data__/languages.json
@@ -9,6 +9,7 @@
"nativeName": "Deutsch",
"country": "de",
"dayjsLocale": "de",
+ "timeagoLocale": "de",
"contributors": [
{
"name": "Lignum",
@@ -21,6 +22,7 @@
"nativeName": "Français",
"country": "fr",
"dayjsLocale": "fr",
+ "timeagoLocale": "fr",
"contributors": [
{
"name": "Anavrins",
@@ -33,6 +35,7 @@
"nativeName": "Nederlands",
"country": "nl",
"dayjsLocale": "nl",
+ "timeagoLocale": "nl",
"contributors": [
{
"name": "HydroNitrogen",
@@ -45,6 +48,7 @@
"nativeName": "Polski",
"country": "pl",
"dayjsLocale": "pl",
+ "timeagoLocale": "pl",
"contributors": [
{
"name": "Wojbie",
@@ -57,6 +61,7 @@
"nativeName": "Tiếng Việt",
"country": "vn",
"dayjsLocale": "vi",
+ "timeagoLocale": "vi",
"contributors": [
{
"name": "Boom",
diff --git a/src/components/DateTime.tsx b/src/components/DateTime.tsx
index 8f04988..7115e93 100644
--- a/src/components/DateTime.tsx
+++ b/src/components/DateTime.tsx
@@ -1,9 +1,11 @@
// Copyright (c) 2020-2021 Drew Lemmy
// This file is part of KristWeb 2 under GPL-3.0.
// Full details: https://github.com/tmpim/KristWeb2/blob/master/LICENSE.txt
+import { useContext } from "react";
import classNames from "classnames";
import { Tooltip } from "antd";
+import { TimeagoFormatterContext } from "@global/LocaleContext";
import { useBooleanSetting } from "@utils/settings";
import dayjs from "dayjs";
@@ -32,6 +34,9 @@
tooltip,
...props
}: Props): JSX.Element | null {
+ // Get the locale's formatter
+ const formatter = useContext(TimeagoFormatterContext);
+
const showRelativeDates = useBooleanSetting("showRelativeDates");
if (!date) return null;
@@ -49,7 +54,7 @@
const contents = (
{isTimeAgo
- ?
+ ?
: dayjs(realDate).format("YYYY/MM/DD HH:mm:ss")}
);
diff --git a/src/global/LocaleContext.tsx b/src/global/LocaleContext.tsx
index 2ad3dcf..ff85d2b 100644
--- a/src/global/LocaleContext.tsx
+++ b/src/global/LocaleContext.tsx
@@ -1,7 +1,7 @@
// Copyright (c) 2020-2021 Drew Lemmy
// This file is part of KristWeb 2 under GPL-3.0.
// Full details: https://github.com/tmpim/KristWeb2/blob/master/LICENSE.txt
-import { FC, useEffect } from "react";
+import { FC, createContext, useEffect, useState } from "react";
import { ConfigProvider } from "antd";
import { Locale } from "antd/lib/locale-provider";
import localeValues from "antd/lib/locale/default";
@@ -11,14 +11,21 @@
import dayjs from "dayjs";
+import { Formatter } from "react-timeago";
+import buildFormatter from "react-timeago/lib/formatters/buildFormatter";
+
import Debug from "debug";
const debug = Debug("kristweb:locale-context");
+export const TimeagoFormatterContext = createContext(undefined);
+
export const LocaleContext: FC = ({ children }): JSX.Element => {
const { t, i18n } = useTranslation();
const langCode = i18n.language;
const languages = getLanguages();
+ const [timeagoFormatter, setTimeagoFormatter] = useState<{ formatter: Formatter }>();
+
// Load the day.js locale if available
useEffect(() => {
if (!languages) return;
@@ -51,7 +58,38 @@
.catch(console.error);
}, [langCode, languages]);
- return
- {children}
- ;
+ // Load the timeago locale if available
+ useEffect(() => {
+ if (!languages) return;
+ const lang = languages[langCode];
+
+ // See if the language has a timeago locale set. If not, revert to default
+ const timeagoLocale = lang?.timeagoLocale;
+ if (!timeagoLocale) {
+ debug("language %s doesn't have a timeago locale, reverting to default", langCode);
+ setTimeagoFormatter(undefined);
+ return;
+ }
+
+ // Load the locale
+ debug("loading timeago locale %s for language %s", timeagoLocale, langCode);
+ import(
+ /* webpackInclude: /\.js$/ */
+ /* webpackMode: "lazy" */
+ /* webpackChunkName: "locale-timeago-[request]" */
+ `react-timeago/lib/language-strings/${timeagoLocale}`
+ )
+ .then(strings => {
+ debug("got timeagoLocale locale %s", timeagoLocale);
+ console.log(strings.default);
+ setTimeagoFormatter({ formatter: buildFormatter(strings.default) });
+ })
+ .catch(console.error);
+ }, [langCode, languages]);
+
+ return
+
+ {children}
+
+ ;
};
diff --git a/src/utils/i18n.ts b/src/utils/i18n.ts
index 530c774..de4c6bf 100644
--- a/src/utils/i18n.ts
+++ b/src/utils/i18n.ts
@@ -22,6 +22,7 @@
nativeName?: string;
country?: string;
dayjsLocale?: string;
+ timeagoLocale?: string;
contributors: Contributor[];
}
diff --git a/tsconfig.json b/tsconfig.json
index 95c888e..e6ab60a 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -21,9 +21,14 @@
"isolatedModules": true,
"noEmit": true,
"noImplicitAny": true,
- "jsx": "react-jsx"
+ "jsx": "react-jsx",
+ "typeRoots": [
+ "./node_modules/@types",
+ "./typings"
+ ]
},
"include": [
- "src"
+ "src",
+ "typings"
]
}
diff --git a/typings/react-timeago/lib/formatters/index.d.ts b/typings/react-timeago/lib/formatters/index.d.ts
new file mode 100644
index 0000000..753e289
--- /dev/null
+++ b/typings/react-timeago/lib/formatters/index.d.ts
@@ -0,0 +1,68 @@
+// Copyright (c) 2020-2021 Drew Lemmy
+// This file is part of KristWeb 2 under GPL-3.0.
+// Full details: https://github.com/tmpim/KristWeb2/blob/master/LICENSE.txt
+
+// TODO: PR this to DefinitelyTyped
+
+// Based off of the Flow types:
+// https://github.com/nmn/react-timeago/blob/master/src/formatters/buildFormatter.js
+
+type Unit =
+ | "second"
+ | "minute"
+ | "hour"
+ | "day"
+ | "week"
+ | "month"
+ | "year";
+
+type Suffix = "ago" | "from now";
+
+type Formatter = (
+ value: number,
+ unit: Unit,
+ suffix: Suffix,
+ epochMiliseconds: number,
+ nextFormatter?: Formatter
+) => React.ReactNode;
+
+type StringOrFn = string | ((value: number, millisDelta: number) => string);
+type NumberArray = [
+ string,
+ string,
+ string,
+ string,
+ string,
+ string,
+ string,
+ string,
+ string,
+ string,
+];
+
+interface L10nsStrings {
+ prefixAgo?: StringOrFn;
+ prefixFromNow?: StringOrFn;
+ suffixAgo?: StringOrFn;
+ suffixFromNow?: StringOrFn;
+ second?: StringOrFn;
+ seconds?: StringOrFn;
+ minute?: StringOrFn;
+ minutes?: StringOrFn;
+ hour?: StringOrFn;
+ hours?: StringOrFn;
+ day?: StringOrFn;
+ days?: StringOrFn;
+ week?: StringOrFn;
+ weeks?: StringOrFn;
+ month?: StringOrFn;
+ months?: StringOrFn;
+ year?: StringOrFn;
+ years?: StringOrFn;
+ wordSeparator?: string;
+ numbers?: NumberArray;
+}
+
+declare module "react-timeago/lib/formatters/*" {
+ export default function buildFormatter(strings: L10nsStrings): Formatter;
+}