From b05f0d1d248376515a5337d7f2e163ab1da1e254 Mon Sep 17 00:00:00 2001 From: Kibi Kelburton Date: Wed, 6 May 2026 05:28:13 +0200 Subject: [PATCH] displaying "years" correcty in abyss for old items --- public/s/js/scroller.js | 16 +++---- src/inc/lib.mjs | 10 ++-- src/inc/routeinc/f0cklib.mjs | 4 +- src/inc/routes/index.mjs | 5 +- src/inc/routes/scroller.mjs | 2 +- views/scroller.html | 93 +++++++++++++++++++----------------- 6 files changed, 71 insertions(+), 59 deletions(-) diff --git a/public/s/js/scroller.js b/public/s/js/scroller.js index 0655a60..95b4141 100644 --- a/public/s/js/scroller.js +++ b/public/s/js/scroller.js @@ -212,21 +212,21 @@ function timeAgo(iso) { const s = Math.floor((Date.now() - new Date(iso)) / 1000); const i = window.f0ckI18n || {}; - const fmt = (tpl, n) => (tpl || '{n}').replace('{n}', n); + const fmt = (tpl, n, unit) => (tpl || `{n} ${unit}${n !== 1 ? 's' : ''}`).replace('{n}', n); const ago = (t) => (i.ta_ago || '{t} ago').replace('{t}', t); - if (s < 60) return i.ta_just_now || i.just_now || 'just now'; + if (s < 60) return i.ta_just_now || 'just now'; const m = Math.floor(s / 60); - if (m < 60) return ago(fmt(m === 1 ? i.ta_minute : i.ta_minutes, m)); + if (m < 60) return ago(fmt(m === 1 ? i.ta_minute : i.ta_minutes, m, 'minute')); const h = Math.floor(s / 3600); - if (h < 24) return ago(fmt(h === 1 ? i.ta_hour : i.ta_hours, h)); + if (h < 24) return ago(fmt(h === 1 ? i.ta_hour : i.ta_hours, h, 'hour')); const d = Math.floor(s / 86400); - if (d < 7) return ago(fmt(d === 1 ? i.ta_day : i.ta_days, d)); + if (d < 7) return ago(fmt(d === 1 ? i.ta_day : i.ta_days, d, 'day')); const w = Math.floor(d / 7); - if (d < 30) return ago(fmt(w === 1 ? i.ta_week : i.ta_weeks, w)); + if (d < 30) return ago(fmt(w === 1 ? i.ta_week : i.ta_weeks, w, 'week')); const mo = Math.floor(d / 30); - if (d < 365) return ago(fmt(mo === 1 ? i.ta_month : i.ta_months, mo)); + if (d < 365) return ago(fmt(mo === 1 ? i.ta_month : i.ta_months, mo, 'month')); const y = Math.floor(d / 365); - return ago(fmt(y === 1 ? i.ta_year : i.ta_years, y)); + return ago(fmt(y === 1 ? i.ta_year : i.ta_years, y, 'year')); } function hashId() { // Strip the leading '#' and allow numeric IDs or board/postid format diff --git a/src/inc/lib.mjs b/src/inc/lib.mjs index c512498..893840a 100644 --- a/src/inc/lib.mjs +++ b/src/inc/lib.mjs @@ -3,6 +3,7 @@ import util from "util"; import db from "./sql.mjs"; import cfg from "./config.mjs"; +import { createI18n } from "./i18n.mjs"; @@ -43,11 +44,14 @@ export default new class { calcSpeed(b, s) { return (Math.round((b * 8 / s / 1e6) * 1e4) / 1e4); }; - timeAgo(date) { + timeAgo(date, lang = 'en') { + const { t } = createI18n(lang); const duration = getDuration(~~((new Date() - new Date(date)) / 1e3)); - if (!duration) return "just now"; + if (!duration) return t('timeago.just_now'); const { interval, epoch } = duration; - return `${interval} ${epoch}${interval === 1 ? "" : "s"} ago`; + const unitKey = interval === 1 ? `timeago.${epoch}` : `timeago.${epoch}s`; + const timeStr = t(unitKey, { n: interval }); + return t('timeago.ago', { t: timeStr }); }; md5(str) { return crypto.createHash('md5').update(str).digest("hex"); diff --git a/src/inc/routeinc/f0cklib.mjs b/src/inc/routeinc/f0cklib.mjs index b082848..22d8bd1 100644 --- a/src/inc/routeinc/f0cklib.mjs +++ b/src/inc/routeinc/f0cklib.mjs @@ -290,7 +290,7 @@ export default { view_mode: fav ? 'favs' : 'uploads' }; }, - getf0ck: async ({ user: rawUser, tag: rawTag, hall: rawHall, mime: rawMime, itemid: rawItemid, mode, session, strict, exclude, user_id, fav, random, userHall: rawUserHall, userHallOwner: rawUserHallOwner } = {}) => { + getf0ck: async ({ user: rawUser, tag: rawTag, hall: rawHall, mime: rawMime, itemid: rawItemid, mode, session, strict, exclude, user_id, fav, random, userHall: rawUserHall, userHallOwner: rawUserHallOwner, lang } = {}) => { const user = rawUser ? lib.escapeLike(decodeURI(rawUser)) : null; const tag = lib.parseTag(rawTag ?? null); let hall = rawHall ?? null; @@ -614,7 +614,7 @@ export default { mime: actitem.mime, size: lib.formatSize(actitem.size), timestamp: { - timeago: lib.timeAgo(new Date(actitem.stamp * 1e3).toISOString()), + timeago: lib.timeAgo(new Date(actitem.stamp * 1e3).toISOString(), lang), timefull: new Date(actitem.stamp * 1e3).toISOString() }, favorites: favorites, diff --git a/src/inc/routes/index.mjs b/src/inc/routes/index.mjs index 3714926..2c513d0 100644 --- a/src/inc/routes/index.mjs +++ b/src/inc/routes/index.mjs @@ -136,7 +136,7 @@ export default (router, tpl) => { } userData.timestamp = { - timeago: lib.timeAgo(userData.created_at), + timeago: lib.timeAgo(userData.created_at, req.lang), timefull: userData.created_at }; userData.age_days = Math.floor((Date.now() - new Date(userData.created_at).getTime()) / 86400000); @@ -228,7 +228,8 @@ export default (router, tpl) => { strict: !!(req.query?.strict || req.url.qs?.strict || req.session?.strict_mode), explicitStrict: !!(req.query?.strict || req.url.qs?.strict), random: req.cookies.random_mode === '1', - minXdScore: req.params.itemid ? 0 : (req.url.qs?.min_xd !== undefined ? +req.url.qs.min_xd : (req.session?.min_xd_score || 0)) + minXdScore: req.params.itemid ? 0 : (req.url.qs?.min_xd !== undefined ? +req.url.qs.min_xd : (req.session?.min_xd_score || 0)), + lang: req.lang }); console.log(`[DEBUG] Checking strict mode: query=${req.query?.strict}, session=${req.session?.strict_mode}, effective=${!!(req.query?.strict || req.url.qs?.strict || req.session?.strict_mode)}`); console.log(`[${new Date().toISOString()}] [ROUTE] Data fetch complete in ${Date.now() - tRouteStart}ms`); diff --git a/src/inc/routes/scroller.mjs b/src/inc/routes/scroller.mjs index 8d3f98d..1c45c7e 100644 --- a/src/inc/routes/scroller.mjs +++ b/src/inc/routes/scroller.mjs @@ -285,7 +285,7 @@ export default (router, tpl) => { avatar: row.avatar_file ? `/a/${row.avatar_file}` : (row.avatar ? `/t/${row.avatar}.webp` : '/a/default.png'), username_color: row.username_color || null, stamp: row.stamp, - timeago: lib.timeAgo(new Date(row.stamp * 1e3).toISOString()), + timeago: lib.timeAgo(new Date(row.stamp * 1e3).toISOString(), req.lang), tags: row.tag_list || '', is_oc: row.is_oc || false, is_faved: row.is_faved || false, diff --git a/views/scroller.html b/views/scroller.html index 8509a3c..345bc61 100644 --- a/views/scroller.html +++ b/views/scroller.html @@ -923,49 +923,8 @@ window.f0ckAllowedImages = {{ allowed_comment_images_json }}; window.scrollerPublic = {{ private_society ? 'false' : 'true' }}; window.scrollerMimeCats = {{ JSON.stringify(scroller_mime_cats) }}; - @if(typeof session !== 'undefined' && session) - window.scrollerUsername = "{{ session.user || '' }}"; - window.scrollerDisplayName = "{{ session.display_name || session.user || '' }}"; - window.scrollerUserAvatar = "{{ session.avatar_file ? '/a/' + session.avatar_file : (session.avatar ? '/t/' + session.avatar + '.webp' : '/a/default.png') }}"; window.f0ckI18n = { - // notifications - notif_upload_approved: "{{ t('notifications.upload_approved_short') }}", - notif_upload_pending: "{{ t('notifications.upload_pending_short') }}", - notif_new_report: "{{ t('notifications.new_report_short') }}", - notif_upload_denied: "{{ t('notifications.upload_denied_short') }}", - notif_upload_deleted: "{{ t('notifications.upload_deleted_short') }}", - notif_upload_success: "{{ t('notifications.upload_success') }}", - notif_upload_error: "{{ t('notifications.upload_error') }}", - notif_replied: "{{ t('notifications.replied_short') }}", - notif_subscribed: "{{ t('notifications.subscribed_short') }}", - notif_mentioned: "{{ t('notifications.mentioned_short') }}", - notif_commented: "{{ t('notifications.commented') }}", - notif_system: "{{ t('notifications.system') }}", - notif_admin: "{{ t('notifications.admin') }}", - notif_moderation: "{{ t('notifications.moderation') }}", - notif_tab_user: "{{ t('nav.notif_tab_user') }}", - notif_tab_system: "{{ t('nav.notif_tab_system') }}", - no_notifications: "{{ t('nav.no_notifications') }}", - // scroller - just_now: "{{ t('scroller.just_now') }}", - add: "{{ t('scroller.add') }}", - update_preset: "{{ t('scroller.update_preset') }}", - update_preset_sub: "{{ t('scroller.update_preset_sub') }}", - no_presets: "{{ t('scroller.no_presets') }}", - copy_clipboard: "{{ t('scroller.copy_clipboard') }}", - copied: "{{ t('scroller.copied') }}", - recent: "{{ t('scroller.recent') }}", - nothing_found: "{{ t('scroller.nothing_found') }}", - adjust_filters: "{{ t('scroller.adjust_filters') }}", - failed_load_comments: "{{ t('scroller.failed_load_comments') }}", - no_custom_emojis: "{{ t('scroller.no_custom_emojis') }}", - login_required: "{{ t('scroller.login_required') }}", - rehost_failed: "{{ t('scroller.rehost_failed') }}", - chan_load_failed: "{{ t('scroller.chan_load_failed') }}", - fetch_failed: "{{ t('scroller.fetch_failed') }}", - invalid_chan_url: "{{ t('scroller.invalid_chan_url') }}", - chan_catalog_failed: "{{ t('scroller.chan_catalog_failed') }}", - anonymous: "{{ t('scroller.anonymous') }}", + lang: "{{ lang }}", // timeago ta_just_now: "{{ t('timeago.just_now') }}", ta_second: "{{ t('timeago.second') }}", @@ -997,8 +956,56 @@ add_to_site_first: "{{ t('scroller.add_to_site_first') }}", // reply replying_to: "{{ t('scroller.replying_to') }}", - reply: "{{ t('scroller.reply') }}" + reply: "{{ t('scroller.reply') }}", + // scroller labels + just_now: "{{ t('scroller.just_now') }}", + failed_load_comments: "{{ t('scroller.failed_load_comments') }}", + no_comments: "{{ t('scroller.no_comments') }}", + write_comment: "{{ t('scroller.write_comment') }}", + login_required: "{{ t('scroller.login_required') }}", + login_to_comment: "{{ t('scroller.login_to_comment') }}" }; + @if(typeof session !== 'undefined' && session) + window.scrollerUsername = "{{ session.user || '' }}"; + window.scrollerDisplayName = "{{ session.display_name || session.user || '' }}"; + window.scrollerUserAvatar = "{{ session.avatar_file ? '/a/' + session.avatar_file : (session.avatar ? '/t/' + session.avatar + '.webp' : '/a/default.png') }}"; + Object.assign(window.f0ckI18n, { + // notifications + notif_upload_approved: "{{ t('notifications.upload_approved_short') }}", + notif_upload_pending: "{{ t('notifications.upload_pending_short') }}", + notif_new_report: "{{ t('notifications.new_report_short') }}", + notif_upload_denied: "{{ t('notifications.upload_denied_short') }}", + notif_upload_deleted: "{{ t('notifications.upload_deleted_short') }}", + notif_upload_success: "{{ t('notifications.upload_success') }}", + notif_upload_error: "{{ t('notifications.upload_error') }}", + notif_replied: "{{ t('notifications.replied_short') }}", + notif_subscribed: "{{ t('notifications.subscribed_short') }}", + notif_mentioned: "{{ t('notifications.mentioned_short') }}", + notif_commented: "{{ t('notifications.commented') }}", + notif_system: "{{ t('notifications.system') }}", + notif_admin: "{{ t('notifications.admin') }}", + notif_moderation: "{{ t('notifications.moderation') }}", + notif_tab_user: "{{ t('nav.notif_tab_user') }}", + notif_tab_system: "{{ t('nav.notif_tab_system') }}", + no_notifications: "{{ t('nav.no_notifications') }}", + // scroller + add: "{{ t('scroller.add') }}", + update_preset: "{{ t('scroller.update_preset') }}", + update_preset_sub: "{{ t('scroller.update_preset_sub') }}", + no_presets: "{{ t('scroller.no_presets') }}", + copy_clipboard: "{{ t('scroller.copy_clipboard') }}", + copied: "{{ t('scroller.copied') }}", + recent: "{{ t('scroller.recent') }}", + nothing_found: "{{ t('scroller.nothing_found') }}", + adjust_filters: "{{ t('scroller.adjust_filters') }}", + no_custom_emojis: "{{ t('scroller.no_custom_emojis') }}", + rehost_failed: "{{ t('scroller.rehost_failed') }}", + chan_load_failed: "{{ t('scroller.chan_load_failed') }}", + fetch_failed: "{{ t('scroller.fetch_failed') }}", + invalid_chan_url: "{{ t('scroller.invalid_chan_url') }}", + chan_catalog_failed: "{{ t('scroller.chan_catalog_failed') }}", + anonymous: "{{ t('scroller.anonymous') }}" + }); @endif