From 46f7c86f05de5189ba9aa320d2d3f8c92f3caf1f Mon Sep 17 00:00:00 2001 From: YUCLing Date: Fri, 27 Sep 2024 23:25:01 +0800 Subject: [PATCH 01/20] chore: humanTime improvements --- framework/core/js/src/common/utils/humanTime.ts | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/framework/core/js/src/common/utils/humanTime.ts b/framework/core/js/src/common/utils/humanTime.ts index 870153ae28..bcaf681fe3 100644 --- a/framework/core/js/src/common/utils/humanTime.ts +++ b/framework/core/js/src/common/utils/humanTime.ts @@ -15,14 +15,12 @@ export default function humanTime(time: dayjs.ConfigType): string { d = now; } - const day = 864e5; - const diff = d.diff(dayjs()); let ago: string; // If this date was more than a month ago, we'll show the name of the month // in the string. If it wasn't this year, we'll show the year as well. - if (diff < -30 * day) { - if (d.year() === dayjs().year()) { + if (d.diff(now, 'day') < -30) { + if (d.isSame(now, 'year')) { ago = d.format('D MMM'); } else { ago = d.format('ll'); From eefb7cbcb3effb7dd2e683d674825127cdb63b35 Mon Sep 17 00:00:00 2001 From: YUCLing Date: Fri, 27 Sep 2024 23:25:45 +0800 Subject: [PATCH 02/20] chore: correct liveHumanTimes comment --- framework/core/js/src/common/utils/liveHumanTimes.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/framework/core/js/src/common/utils/liveHumanTimes.ts b/framework/core/js/src/common/utils/liveHumanTimes.ts index cea16fde59..bcb0d53754 100644 --- a/framework/core/js/src/common/utils/liveHumanTimes.ts +++ b/framework/core/js/src/common/utils/liveHumanTimes.ts @@ -10,7 +10,7 @@ function updateHumanTimes() { } /** - * The `liveHumanTimes` initializer sets up a loop every 1 second to update + * The `liveHumanTimes` initializer sets up a loop every 10 seconds to update * timestamps rendered with the `humanTime` helper. */ export default function liveHumanTimes() { From 57c2a7377d2f25108ef04d4730766602976404c9 Mon Sep 17 00:00:00 2001 From: YUCLing Date: Fri, 27 Sep 2024 23:26:32 +0800 Subject: [PATCH 03/20] add: flarum customized time formats --- framework/core/js/src/common/index.ts | 2 ++ .../core/js/src/common/utils/dayjsPlugins.ts | 21 +++++++++++++++++++ .../core/js/src/common/utils/humanTime.ts | 2 +- .../js/src/forum/components/PostStream.js | 2 +- 4 files changed, 25 insertions(+), 2 deletions(-) create mode 100644 framework/core/js/src/common/utils/dayjsPlugins.ts diff --git a/framework/core/js/src/common/index.ts b/framework/core/js/src/common/index.ts index 0b7deb7004..ddb1b16e2e 100644 --- a/framework/core/js/src/common/index.ts +++ b/framework/core/js/src/common/index.ts @@ -11,9 +11,11 @@ import 'jquery.hotkeys/jquery.hotkeys'; import relativeTime from 'dayjs/plugin/relativeTime'; import localizedFormat from 'dayjs/plugin/localizedFormat'; +import { customFormats } from './utils/dayjsPlugins'; dayjs.extend(relativeTime); dayjs.extend(localizedFormat); +dayjs.extend(customFormats); import './registry'; diff --git a/framework/core/js/src/common/utils/dayjsPlugins.ts b/framework/core/js/src/common/utils/dayjsPlugins.ts new file mode 100644 index 0000000000..f999b05dab --- /dev/null +++ b/framework/core/js/src/common/utils/dayjsPlugins.ts @@ -0,0 +1,21 @@ +export const customFormats: import('dayjs').PluginFunc = function (_option, c, _factory) { + const proto = c.prototype; + const oldFormat = proto.format; + + const t = (format?: string) => + format?.replace(/(\[[^\]]+])|(MMMM|MM|DD|dddd)/g, (_, a, b) => a || b.slice(1)) + + const englishFormats: Record = { + F: "DD MMMM", + FF: "MMMM YYYY" + }; + + proto.format = function(template) { + const { formats = {} } = (this as any).$locale(); + const result = template?.replace(/(\[[^\]]+])|(f{1,2}|F{1,2})/g, (_, a, b) => { + const B = b && b.toUpperCase(); + return a || formats[b] || englishFormats[b] || t(formats[B]); + }); + return oldFormat.call(this, result); + } +} \ No newline at end of file diff --git a/framework/core/js/src/common/utils/humanTime.ts b/framework/core/js/src/common/utils/humanTime.ts index bcaf681fe3..d450c7df4c 100644 --- a/framework/core/js/src/common/utils/humanTime.ts +++ b/framework/core/js/src/common/utils/humanTime.ts @@ -21,7 +21,7 @@ export default function humanTime(time: dayjs.ConfigType): string { // in the string. If it wasn't this year, we'll show the year as well. if (d.diff(now, 'day') < -30) { if (d.isSame(now, 'year')) { - ago = d.format('D MMM'); + ago = d.format('f'); } else { ago = d.format('ll'); } diff --git a/framework/core/js/src/forum/components/PostStream.js b/framework/core/js/src/forum/components/PostStream.js index cb8fd302dc..78251423a4 100644 --- a/framework/core/js/src/forum/components/PostStream.js +++ b/framework/core/js/src/forum/components/PostStream.js @@ -270,7 +270,7 @@ export default class PostStream extends Component { // set the index to the last post. this.stream.index = indexFromViewPort !== null ? indexFromViewPort + 1 : this.stream.count(); this.stream.visible = visible; - if (period) this.stream.description = dayjs(period).format('MMMM YYYY'); + if (period) this.stream.description = dayjs(period).format('FF'); } /** From f5eba9fe36b6051d9cabd78ead3c15c023c8a9f1 Mon Sep 17 00:00:00 2001 From: YUCLing Date: Fri, 27 Sep 2024 23:50:17 +0800 Subject: [PATCH 04/20] chore: quote styles --- framework/core/js/src/common/utils/dayjsPlugins.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/framework/core/js/src/common/utils/dayjsPlugins.ts b/framework/core/js/src/common/utils/dayjsPlugins.ts index f999b05dab..4ccbea4623 100644 --- a/framework/core/js/src/common/utils/dayjsPlugins.ts +++ b/framework/core/js/src/common/utils/dayjsPlugins.ts @@ -6,8 +6,8 @@ export const customFormats: import('dayjs').PluginFunc = function (_option, c, _ format?.replace(/(\[[^\]]+])|(MMMM|MM|DD|dddd)/g, (_, a, b) => a || b.slice(1)) const englishFormats: Record = { - F: "DD MMMM", - FF: "MMMM YYYY" + F: 'DD MMMM', + FF: 'MMMM YYYY' }; proto.format = function(template) { From 9712a645d833a4b4f6e85f69366f3bdf8d9fc3d8 Mon Sep 17 00:00:00 2001 From: YUCLing Date: Fri, 27 Sep 2024 23:52:59 +0800 Subject: [PATCH 05/20] add: fallback for uppercased formats --- framework/core/js/src/common/utils/dayjsPlugins.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/framework/core/js/src/common/utils/dayjsPlugins.ts b/framework/core/js/src/common/utils/dayjsPlugins.ts index 4ccbea4623..07079a1469 100644 --- a/framework/core/js/src/common/utils/dayjsPlugins.ts +++ b/framework/core/js/src/common/utils/dayjsPlugins.ts @@ -14,7 +14,7 @@ export const customFormats: import('dayjs').PluginFunc = function (_option, c, _ const { formats = {} } = (this as any).$locale(); const result = template?.replace(/(\[[^\]]+])|(f{1,2}|F{1,2})/g, (_, a, b) => { const B = b && b.toUpperCase(); - return a || formats[b] || englishFormats[b] || t(formats[B]); + return a || formats[b] || englishFormats[b] || t(formats[B]) || t(englishFormats[B]); }); return oldFormat.call(this, result); } From 5262b7204188b1d33ac3442bd319eb80c3f3d17b Mon Sep 17 00:00:00 2001 From: YUCLing Date: Sat, 28 Sep 2024 00:47:51 +0800 Subject: [PATCH 06/20] chore: fix code style --- .../core/js/src/common/utils/dayjsPlugins.ts | 33 +++++++++---------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/framework/core/js/src/common/utils/dayjsPlugins.ts b/framework/core/js/src/common/utils/dayjsPlugins.ts index 07079a1469..5fc04ec19c 100644 --- a/framework/core/js/src/common/utils/dayjsPlugins.ts +++ b/framework/core/js/src/common/utils/dayjsPlugins.ts @@ -1,21 +1,20 @@ export const customFormats: import('dayjs').PluginFunc = function (_option, c, _factory) { - const proto = c.prototype; - const oldFormat = proto.format; + const proto = c.prototype; + const oldFormat = proto.format; - const t = (format?: string) => - format?.replace(/(\[[^\]]+])|(MMMM|MM|DD|dddd)/g, (_, a, b) => a || b.slice(1)) + const t = (format?: string) => format?.replace(/(\[[^\]]+])|(MMMM|MM|DD|dddd)/g, (_, a, b) => a || b.slice(1)); - const englishFormats: Record = { - F: 'DD MMMM', - FF: 'MMMM YYYY' - }; + const englishFormats: Record = { + F: 'DD MMMM', + FF: 'MMMM YYYY', + }; - proto.format = function(template) { - const { formats = {} } = (this as any).$locale(); - const result = template?.replace(/(\[[^\]]+])|(f{1,2}|F{1,2})/g, (_, a, b) => { - const B = b && b.toUpperCase(); - return a || formats[b] || englishFormats[b] || t(formats[B]) || t(englishFormats[B]); - }); - return oldFormat.call(this, result); - } -} \ No newline at end of file + proto.format = function (template) { + const { formats = {} } = (this as any).$locale(); + const result = template?.replace(/(\[[^\]]+])|(f{1,2}|F{1,2})/g, (_, a, b) => { + const B = b && b.toUpperCase(); + return a || formats[b] || englishFormats[b] || t(formats[B]) || t(englishFormats[B]); + }); + return oldFormat.call(this, result); + }; +}; From 8517f48aa8721096a9ff04342cff3cb977b9a065 Mon Sep 17 00:00:00 2001 From: YUCLing Date: Sat, 28 Sep 2024 02:30:57 +0800 Subject: [PATCH 07/20] fix: dayjsPlugins cannot be added to reg --- framework/core/js/src/common/index.ts | 4 ++-- framework/core/js/src/common/utils/dayjsPlugins.ts | 6 +++++- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/framework/core/js/src/common/index.ts b/framework/core/js/src/common/index.ts index ddb1b16e2e..0f64e66739 100644 --- a/framework/core/js/src/common/index.ts +++ b/framework/core/js/src/common/index.ts @@ -11,11 +11,11 @@ import 'jquery.hotkeys/jquery.hotkeys'; import relativeTime from 'dayjs/plugin/relativeTime'; import localizedFormat from 'dayjs/plugin/localizedFormat'; -import { customFormats } from './utils/dayjsPlugins'; +import dayjsPlugins from './utils/dayjsPlugins'; dayjs.extend(relativeTime); dayjs.extend(localizedFormat); -dayjs.extend(customFormats); +dayjs.extend(dayjsPlugins.customFormats); import './registry'; diff --git a/framework/core/js/src/common/utils/dayjsPlugins.ts b/framework/core/js/src/common/utils/dayjsPlugins.ts index 5fc04ec19c..27787d81ac 100644 --- a/framework/core/js/src/common/utils/dayjsPlugins.ts +++ b/framework/core/js/src/common/utils/dayjsPlugins.ts @@ -1,4 +1,4 @@ -export const customFormats: import('dayjs').PluginFunc = function (_option, c, _factory) { +const customFormats: import('dayjs').PluginFunc = function (_option, c, _factory) { const proto = c.prototype; const oldFormat = proto.format; @@ -18,3 +18,7 @@ export const customFormats: import('dayjs').PluginFunc = function (_option, c, _ return oldFormat.call(this, result); }; }; + +export default { + customFormats +}; \ No newline at end of file From 55326845527d03f55a851c32b7242da4f18c22ff Mon Sep 17 00:00:00 2001 From: YUCLing Date: Sat, 28 Sep 2024 02:36:58 +0800 Subject: [PATCH 08/20] chore: code style formatting --- framework/core/js/src/common/utils/dayjsPlugins.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/framework/core/js/src/common/utils/dayjsPlugins.ts b/framework/core/js/src/common/utils/dayjsPlugins.ts index 27787d81ac..8a1da4974c 100644 --- a/framework/core/js/src/common/utils/dayjsPlugins.ts +++ b/framework/core/js/src/common/utils/dayjsPlugins.ts @@ -20,5 +20,5 @@ const customFormats: import('dayjs').PluginFunc = function (_option, c, _factory }; export default { - customFormats -}; \ No newline at end of file + customFormats, +}; From 67826368aafdacba72b5557051bd45223ee33b0d Mon Sep 17 00:00:00 2001 From: YUCLing Date: Sun, 29 Sep 2024 23:31:48 +0800 Subject: [PATCH 09/20] refactor: make the plugin extendable chore: fetch format from translator --- framework/core/js/src/common/index.ts | 7 +- .../core/js/src/common/utils/dayjsPlugins.ts | 24 ------ .../js/src/common/utils/localizedFormat.ts | 84 +++++++++++++++++++ 3 files changed, 87 insertions(+), 28 deletions(-) delete mode 100644 framework/core/js/src/common/utils/dayjsPlugins.ts create mode 100644 framework/core/js/src/common/utils/localizedFormat.ts diff --git a/framework/core/js/src/common/index.ts b/framework/core/js/src/common/index.ts index 0f64e66739..f3308c7dfc 100644 --- a/framework/core/js/src/common/index.ts +++ b/framework/core/js/src/common/index.ts @@ -10,15 +10,14 @@ import 'bootstrap/js/transition'; import 'jquery.hotkeys/jquery.hotkeys'; import relativeTime from 'dayjs/plugin/relativeTime'; -import localizedFormat from 'dayjs/plugin/localizedFormat'; -import dayjsPlugins from './utils/dayjsPlugins'; dayjs.extend(relativeTime); -dayjs.extend(localizedFormat); -dayjs.extend(dayjsPlugins.customFormats); import './registry'; +import { customFormats } from './utils/localizedFormat'; +dayjs.extend(customFormats); + import patchMithril from './utils/patchMithril'; patchMithril(window); diff --git a/framework/core/js/src/common/utils/dayjsPlugins.ts b/framework/core/js/src/common/utils/dayjsPlugins.ts deleted file mode 100644 index 8a1da4974c..0000000000 --- a/framework/core/js/src/common/utils/dayjsPlugins.ts +++ /dev/null @@ -1,24 +0,0 @@ -const customFormats: import('dayjs').PluginFunc = function (_option, c, _factory) { - const proto = c.prototype; - const oldFormat = proto.format; - - const t = (format?: string) => format?.replace(/(\[[^\]]+])|(MMMM|MM|DD|dddd)/g, (_, a, b) => a || b.slice(1)); - - const englishFormats: Record = { - F: 'DD MMMM', - FF: 'MMMM YYYY', - }; - - proto.format = function (template) { - const { formats = {} } = (this as any).$locale(); - const result = template?.replace(/(\[[^\]]+])|(f{1,2}|F{1,2})/g, (_, a, b) => { - const B = b && b.toUpperCase(); - return a || formats[b] || englishFormats[b] || t(formats[B]) || t(englishFormats[B]); - }); - return oldFormat.call(this, result); - }; -}; - -export default { - customFormats, -}; diff --git a/framework/core/js/src/common/utils/localizedFormat.ts b/framework/core/js/src/common/utils/localizedFormat.ts new file mode 100644 index 0000000000..937a578814 --- /dev/null +++ b/framework/core/js/src/common/utils/localizedFormat.ts @@ -0,0 +1,84 @@ +import app from '../../common/app'; +import ItemList from './ItemList'; + +export type LocalizedFormat = { + /** Regexes that matches the formats. */ + regexes: string[]; + /** The map that turns matched localized formats to original DayJS formats. */ + formats: Record +} + +const defaultFormats = new ItemList(); + +defaultFormats.add("flarum-date-formats", { + regexes: ["f{1,2}", "F{1,2}"], + formats: { + F: "DD MMMM", + FF: "MMMM YYYY" + } +}, 10); + +defaultFormats.add("dayjs-formats", { + regexes: ["LTS?", "l{1,4}", "L{1,4}"], + formats: { + LTS: 'h:mm:ss A', + LT: 'h:mm A', + L: 'MM/DD/YYYY', + LL: 'MMMM D, YYYY', + LLL: 'MMMM D, YYYY h:mm A', + LLLL: 'dddd, MMMM D, YYYY h:mm A' + } +}, 20); + +const exports = { + /** + * Returns a list of regexes that matches all localized formats and a map that maps the format to the original DayJS format. + */ + formatList: function() { + const formats = new ItemList(); + formats.merge(defaultFormats); + return formats; + } +}; + +/** + * Flarum's localized format plugin. + * @see https://day.js.org/docs/en/plugin/plugin + */ +export const customFormats: import('dayjs').PluginFunc = function (_option, c, _factory) { + const proto = c.prototype; + const oldFormat = proto.format; + + /** Converts the long date to short date. */ + const t = (format?: string) => format?.replace(/(\[[^\]]+])|(MMMM|MM|DD|dddd)/g, (_, a, b) => a || b.slice(1)); + + proto.format = function (template) { + const { formats = {} } = (this as any).$locale(); + + const config = exports.formatList().toArray(); + const regexes: string[] = []; + let defFormats: Record = {}; + config.forEach((v) => { + regexes.push(...v.regexes); + defFormats = { ...defFormats, ...v.formats }; + }); + + const result = template?.replace(new RegExp(`(\\[[^\\]]+])|(${regexes.join("|")})`, "g"), (_, a, b) => { + const B = b && b.toUpperCase(); + // The format is fetched in the following order: Translator > DayJS locale > formatList. + console.log(regexes, defFormats); + return a || + // short dates + app.translator.translations[`core.forum.date-format.${b}`] || + formats[b] || + defFormats[b] || + // long dates + t(app.translator.translations[`core.forum.date-format.${B}`]) || + t(formats[B]) || + t(defFormats[B]); + }); + return oldFormat.call(this, result); + }; +}; + +export default exports; \ No newline at end of file From 8db78fe7d7fa7a897953b3f9613d346abb7301df Mon Sep 17 00:00:00 2001 From: YUCLing Date: Wed, 2 Oct 2024 14:20:49 +0800 Subject: [PATCH 10/20] refactor: use locale for all time formats --- framework/core/js/src/common/Translator.tsx | 13 +++ framework/core/js/src/common/index.ts | 5 +- .../core/js/src/common/utils/humanTime.ts | 5 +- .../js/src/common/utils/localizedFormat.ts | 84 ------------------- .../js/src/forum/components/PostStream.js | 2 +- framework/core/locale/core.yml | 6 ++ 6 files changed, 25 insertions(+), 90 deletions(-) delete mode 100644 framework/core/js/src/common/utils/localizedFormat.ts diff --git a/framework/core/js/src/common/Translator.tsx b/framework/core/js/src/common/Translator.tsx index 29498fb3a5..3aee69c72d 100644 --- a/framework/core/js/src/common/Translator.tsx +++ b/framework/core/js/src/common/Translator.tsx @@ -1,3 +1,4 @@ +import type { Dayjs } from 'dayjs'; import { RichMessageFormatter, mithrilRichHandler, NestedStringArray } from '@askvortsov/rich-icu-message-formatter'; import { pluralTypeHandler, selectTypeHandler } from '@ultraq/icu-message-formatter'; import username from './helpers/username'; @@ -88,4 +89,16 @@ export default class Translator { return id; } + + /** + * Formats the time. + * + * The format of the time will be chosen by the following order: + * - The format ID defined in current locale. + * - The provided fallback format. + * - DayJS default format. + */ + format(time: Dayjs, id?: string, fallback?: string): string { + return time.format(id && (this.translations[id] ?? fallback)); + } } diff --git a/framework/core/js/src/common/index.ts b/framework/core/js/src/common/index.ts index f3308c7dfc..c3bff0978d 100644 --- a/framework/core/js/src/common/index.ts +++ b/framework/core/js/src/common/index.ts @@ -10,14 +10,13 @@ import 'bootstrap/js/transition'; import 'jquery.hotkeys/jquery.hotkeys'; import relativeTime from 'dayjs/plugin/relativeTime'; +import localizedFormat from "dayjs/plugin/localizedFormat"; dayjs.extend(relativeTime); +dayjs.extend(localizedFormat); import './registry'; -import { customFormats } from './utils/localizedFormat'; -dayjs.extend(customFormats); - import patchMithril from './utils/patchMithril'; patchMithril(window); diff --git a/framework/core/js/src/common/utils/humanTime.ts b/framework/core/js/src/common/utils/humanTime.ts index d450c7df4c..0ecb8614be 100644 --- a/framework/core/js/src/common/utils/humanTime.ts +++ b/framework/core/js/src/common/utils/humanTime.ts @@ -1,3 +1,4 @@ +import app from '../app'; import dayjs from 'dayjs'; /** @@ -21,9 +22,9 @@ export default function humanTime(time: dayjs.ConfigType): string { // in the string. If it wasn't this year, we'll show the year as well. if (d.diff(now, 'day') < -30) { if (d.isSame(now, 'year')) { - ago = d.format('f'); + ago = app.translator.format(d, 'core.lib.datetime_formats.human_time_short'); } else { - ago = d.format('ll'); + ago = app.translator.format(d, 'core.lib.datetime_formats.human_time_full'); } } else { ago = d.fromNow(); diff --git a/framework/core/js/src/common/utils/localizedFormat.ts b/framework/core/js/src/common/utils/localizedFormat.ts deleted file mode 100644 index 937a578814..0000000000 --- a/framework/core/js/src/common/utils/localizedFormat.ts +++ /dev/null @@ -1,84 +0,0 @@ -import app from '../../common/app'; -import ItemList from './ItemList'; - -export type LocalizedFormat = { - /** Regexes that matches the formats. */ - regexes: string[]; - /** The map that turns matched localized formats to original DayJS formats. */ - formats: Record -} - -const defaultFormats = new ItemList(); - -defaultFormats.add("flarum-date-formats", { - regexes: ["f{1,2}", "F{1,2}"], - formats: { - F: "DD MMMM", - FF: "MMMM YYYY" - } -}, 10); - -defaultFormats.add("dayjs-formats", { - regexes: ["LTS?", "l{1,4}", "L{1,4}"], - formats: { - LTS: 'h:mm:ss A', - LT: 'h:mm A', - L: 'MM/DD/YYYY', - LL: 'MMMM D, YYYY', - LLL: 'MMMM D, YYYY h:mm A', - LLLL: 'dddd, MMMM D, YYYY h:mm A' - } -}, 20); - -const exports = { - /** - * Returns a list of regexes that matches all localized formats and a map that maps the format to the original DayJS format. - */ - formatList: function() { - const formats = new ItemList(); - formats.merge(defaultFormats); - return formats; - } -}; - -/** - * Flarum's localized format plugin. - * @see https://day.js.org/docs/en/plugin/plugin - */ -export const customFormats: import('dayjs').PluginFunc = function (_option, c, _factory) { - const proto = c.prototype; - const oldFormat = proto.format; - - /** Converts the long date to short date. */ - const t = (format?: string) => format?.replace(/(\[[^\]]+])|(MMMM|MM|DD|dddd)/g, (_, a, b) => a || b.slice(1)); - - proto.format = function (template) { - const { formats = {} } = (this as any).$locale(); - - const config = exports.formatList().toArray(); - const regexes: string[] = []; - let defFormats: Record = {}; - config.forEach((v) => { - regexes.push(...v.regexes); - defFormats = { ...defFormats, ...v.formats }; - }); - - const result = template?.replace(new RegExp(`(\\[[^\\]]+])|(${regexes.join("|")})`, "g"), (_, a, b) => { - const B = b && b.toUpperCase(); - // The format is fetched in the following order: Translator > DayJS locale > formatList. - console.log(regexes, defFormats); - return a || - // short dates - app.translator.translations[`core.forum.date-format.${b}`] || - formats[b] || - defFormats[b] || - // long dates - t(app.translator.translations[`core.forum.date-format.${B}`]) || - t(formats[B]) || - t(defFormats[B]); - }); - return oldFormat.call(this, result); - }; -}; - -export default exports; \ No newline at end of file diff --git a/framework/core/js/src/forum/components/PostStream.js b/framework/core/js/src/forum/components/PostStream.js index 78251423a4..cdb66128eb 100644 --- a/framework/core/js/src/forum/components/PostStream.js +++ b/framework/core/js/src/forum/components/PostStream.js @@ -270,7 +270,7 @@ export default class PostStream extends Component { // set the index to the last post. this.stream.index = indexFromViewPort !== null ? indexFromViewPort + 1 : this.stream.count(); this.stream.visible = visible; - if (period) this.stream.description = dayjs(period).format('FF'); + if (period) this.stream.description = app.translator.format(dayjs(period), 'core.lib.datetime_formats.post_stream_scrubber'); } /** diff --git a/framework/core/locale/core.yml b/framework/core/locale/core.yml index edb62d0d72..4d424a8ccd 100644 --- a/framework/core/locale/core.yml +++ b/framework/core/locale/core.yml @@ -843,6 +843,12 @@ core: username: deleted_text: "[deleted]" + # These are DayJS formats used in core. + datetime_formats: + human_time_short: D MMM + human_time_full: ll + post_stream_scrubber: MMMM YYYY + # Translations in this namespace are used in views other than Flarum's normal JS client. views: # Translations in this namespace are displayed by the basic HTML admin index. From 7f336dc4c4a1ae1cc9fa98e8a50d03f48af62296 Mon Sep 17 00:00:00 2001 From: YUCLing Date: Thu, 3 Oct 2024 00:54:16 +0800 Subject: [PATCH 11/20] add: support for custom time formats --- framework/core/js/src/common/Translator.tsx | 14 +++++++++++++- framework/core/js/src/common/utils/humanTime.ts | 4 ++-- .../core/js/src/forum/components/PostStream.js | 2 +- 3 files changed, 16 insertions(+), 4 deletions(-) diff --git a/framework/core/js/src/common/Translator.tsx b/framework/core/js/src/common/Translator.tsx index 3aee69c72d..31e2040eba 100644 --- a/framework/core/js/src/common/Translator.tsx +++ b/framework/core/js/src/common/Translator.tsx @@ -5,9 +5,11 @@ import username from './helpers/username'; import User from './models/User'; import extract from './utils/extract'; import extractText from './utils/extractText'; +import ItemList from './utils/ItemList'; type Translations = Record; type TranslatorParameters = Record; +type DateTimeFormatCallback = (fallback?: string) => string | void; export default class Translator { /** @@ -15,6 +17,11 @@ export default class Translator { */ translations: Translations = {}; + /** + * A item list of date time format callbacks. + */ + dateTimeFormats: ItemList = new ItemList(); + /** * The underlying ICU MessageFormatter util. */ @@ -98,7 +105,12 @@ export default class Translator { * - The provided fallback format. * - DayJS default format. */ - format(time: Dayjs, id?: string, fallback?: string): string { + formatDateTime(time: Dayjs, id?: string, fallback?: string): string { + const formatCallback = (id && this.dateTimeFormats.has(id)) && this.dateTimeFormats.get(id); + if (formatCallback) { + const result = formatCallback(fallback); + if (result) return result; + } return time.format(id && (this.translations[id] ?? fallback)); } } diff --git a/framework/core/js/src/common/utils/humanTime.ts b/framework/core/js/src/common/utils/humanTime.ts index 0ecb8614be..869f72eb43 100644 --- a/framework/core/js/src/common/utils/humanTime.ts +++ b/framework/core/js/src/common/utils/humanTime.ts @@ -22,9 +22,9 @@ export default function humanTime(time: dayjs.ConfigType): string { // in the string. If it wasn't this year, we'll show the year as well. if (d.diff(now, 'day') < -30) { if (d.isSame(now, 'year')) { - ago = app.translator.format(d, 'core.lib.datetime_formats.human_time_short'); + ago = app.translator.formatDateTime(d, 'core.lib.datetime_formats.human_time_short'); } else { - ago = app.translator.format(d, 'core.lib.datetime_formats.human_time_full'); + ago = app.translator.formatDateTime(d, 'core.lib.datetime_formats.human_time_full'); } } else { ago = d.fromNow(); diff --git a/framework/core/js/src/forum/components/PostStream.js b/framework/core/js/src/forum/components/PostStream.js index cdb66128eb..3fccfcf59b 100644 --- a/framework/core/js/src/forum/components/PostStream.js +++ b/framework/core/js/src/forum/components/PostStream.js @@ -270,7 +270,7 @@ export default class PostStream extends Component { // set the index to the last post. this.stream.index = indexFromViewPort !== null ? indexFromViewPort + 1 : this.stream.count(); this.stream.visible = visible; - if (period) this.stream.description = app.translator.format(dayjs(period), 'core.lib.datetime_formats.post_stream_scrubber'); + if (period) this.stream.description = app.translator.formatDateTime(dayjs(period), 'core.lib.datetime_formats.post_stream_scrubber'); } /** From b6bf4d02428377cc3766d116c99293870e0804ef Mon Sep 17 00:00:00 2001 From: YUCLing Date: Thu, 3 Oct 2024 01:02:04 +0800 Subject: [PATCH 12/20] fix: code format --- framework/core/js/src/common/Translator.tsx | 4 ++-- framework/core/js/src/common/index.ts | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/framework/core/js/src/common/Translator.tsx b/framework/core/js/src/common/Translator.tsx index 31e2040eba..951830fb79 100644 --- a/framework/core/js/src/common/Translator.tsx +++ b/framework/core/js/src/common/Translator.tsx @@ -99,14 +99,14 @@ export default class Translator { /** * Formats the time. - * + * * The format of the time will be chosen by the following order: * - The format ID defined in current locale. * - The provided fallback format. * - DayJS default format. */ formatDateTime(time: Dayjs, id?: string, fallback?: string): string { - const formatCallback = (id && this.dateTimeFormats.has(id)) && this.dateTimeFormats.get(id); + const formatCallback = id && this.dateTimeFormats.has(id) && this.dateTimeFormats.get(id); if (formatCallback) { const result = formatCallback(fallback); if (result) return result; diff --git a/framework/core/js/src/common/index.ts b/framework/core/js/src/common/index.ts index c3bff0978d..0b7deb7004 100644 --- a/framework/core/js/src/common/index.ts +++ b/framework/core/js/src/common/index.ts @@ -10,7 +10,7 @@ import 'bootstrap/js/transition'; import 'jquery.hotkeys/jquery.hotkeys'; import relativeTime from 'dayjs/plugin/relativeTime'; -import localizedFormat from "dayjs/plugin/localizedFormat"; +import localizedFormat from 'dayjs/plugin/localizedFormat'; dayjs.extend(relativeTime); dayjs.extend(localizedFormat); From 2921372eed0eee2ee80eb24217f99eef6b5e2b9c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=9B=A8?= Date: Thu, 3 Oct 2024 09:49:08 +0800 Subject: [PATCH 13/20] remove: fallback parameter Co-authored-by: Sami Mazouz --- framework/core/js/src/common/Translator.tsx | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/framework/core/js/src/common/Translator.tsx b/framework/core/js/src/common/Translator.tsx index 951830fb79..4de8db5d2f 100644 --- a/framework/core/js/src/common/Translator.tsx +++ b/framework/core/js/src/common/Translator.tsx @@ -101,16 +101,16 @@ export default class Translator { * Formats the time. * * The format of the time will be chosen by the following order: - * - The format ID defined in current locale. - * - The provided fallback format. + * - Custom format defined in the item list. + * - The format defined in current locale. * - DayJS default format. */ - formatDateTime(time: Dayjs, id?: string, fallback?: string): string { + formatDateTime(time: Dayjs, id?: string): string { const formatCallback = id && this.dateTimeFormats.has(id) && this.dateTimeFormats.get(id); if (formatCallback) { const result = formatCallback(fallback); if (result) return result; } - return time.format(id && (this.translations[id] ?? fallback)); + return time.format(id && (this.translations[id] ?? id)); } } From 5325305ec27e94e85433ac13f4956b3f5b05533f Mon Sep 17 00:00:00 2001 From: YUCLing Date: Thu, 3 Oct 2024 13:47:31 +0800 Subject: [PATCH 14/20] add: pass format to date time callback --- framework/core/js/src/common/Translator.tsx | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/framework/core/js/src/common/Translator.tsx b/framework/core/js/src/common/Translator.tsx index 4de8db5d2f..cd5e2ff33f 100644 --- a/framework/core/js/src/common/Translator.tsx +++ b/framework/core/js/src/common/Translator.tsx @@ -9,7 +9,7 @@ import ItemList from './utils/ItemList'; type Translations = Record; type TranslatorParameters = Record; -type DateTimeFormatCallback = (fallback?: string) => string | void; +type DateTimeFormatCallback = (format?: string) => string | void; export default class Translator { /** @@ -106,11 +106,12 @@ export default class Translator { * - DayJS default format. */ formatDateTime(time: Dayjs, id?: string): string { + const format = id && (this.translations[id] ?? id); const formatCallback = id && this.dateTimeFormats.has(id) && this.dateTimeFormats.get(id); if (formatCallback) { - const result = formatCallback(fallback); + const result = formatCallback(format); if (result) return result; } - return time.format(id && (this.translations[id] ?? id)); + return time.format(format); } } From f89ab96aad507b071f956f19c831644eaabbcbdd Mon Sep 17 00:00:00 2001 From: YUCLing Date: Fri, 4 Oct 2024 00:44:59 +0800 Subject: [PATCH 15/20] add: this arg for date time format callback --- framework/core/js/src/common/Translator.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/framework/core/js/src/common/Translator.tsx b/framework/core/js/src/common/Translator.tsx index cd5e2ff33f..233f6f514e 100644 --- a/framework/core/js/src/common/Translator.tsx +++ b/framework/core/js/src/common/Translator.tsx @@ -109,7 +109,7 @@ export default class Translator { const format = id && (this.translations[id] ?? id); const formatCallback = id && this.dateTimeFormats.has(id) && this.dateTimeFormats.get(id); if (formatCallback) { - const result = formatCallback(format); + const result = formatCallback.apply(this, [format]); if (result) return result; } return time.format(format); From cd880d7a651eff69fc281e37092bc3a7c0d828ec Mon Sep 17 00:00:00 2001 From: YUCLing Date: Fri, 4 Oct 2024 13:35:03 +0800 Subject: [PATCH 16/20] add: full time format --- framework/core/js/src/common/helpers/fullTime.tsx | 3 ++- framework/core/js/src/common/helpers/humanTime.tsx | 3 ++- framework/core/locale/core.yml | 1 + 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/framework/core/js/src/common/helpers/fullTime.tsx b/framework/core/js/src/common/helpers/fullTime.tsx index efde8faf45..b4d1655cd5 100644 --- a/framework/core/js/src/common/helpers/fullTime.tsx +++ b/framework/core/js/src/common/helpers/fullTime.tsx @@ -1,5 +1,6 @@ import dayjs from 'dayjs'; import type Mithril from 'mithril'; +import app from "../app"; /** * The `fullTime` helper displays a formatted time string wrapped in a