From 0878f5bfb43bdc52d72968cbd7bf343e2ec6460d Mon Sep 17 00:00:00 2001 From: marcin mikołajczak Date: Tue, 13 Aug 2024 19:39:26 +0200 Subject: Inform users that Smithereen public polls are public MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: marcin mikołajczak --- src/i18n/en.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'src/i18n') diff --git a/src/i18n/en.json b/src/i18n/en.json index 3f7ea282..875d756d 100644 --- a/src/i18n/en.json +++ b/src/i18n/en.json @@ -229,7 +229,9 @@ "expiry": "Poll age", "expires_in": "Poll ends in {0}", "expired": "Poll ended {0} ago", - "not_enough_options": "Too few unique options in poll" + "not_enough_options": "Too few unique options in poll", + "non_anonymous": "Public poll", + "non_anonymous_title": "Other instances may display the options you voted for" }, "emoji": { "stickers": "Stickers", -- cgit v1.2.3-70-g09d2 From b14ba1725612ee5ddaa40626c4fcd32212f0cc7f Mon Sep 17 00:00:00 2001 From: tusooa Date: Sat, 14 Sep 2024 00:00:18 -0400 Subject: Support displaying time in absolute format This adds two config items: useAbsoluteTimeFormat (boolean) and absoluteTimeFormatMinAge (string, number + unit ('d'|'h'|'m'|'s')). When `useAbsoluteTimeFormat` is true, the Timeago component will display absolute time if the time is at least `absoluteTimeFormatMinAge` from now. If `longFormat` prop is true, the fully formatted time is displayed. Otherwise, the format is determined by the `time` prop: (1) if `time` is on the same day of now, display hour and minute; (2) if `time` is in the same month of now, display day and hour; (3) if `time` is in the same year of now, display month and day; (4) otherwise, display year and month. If it should display relative time, the format is the same as before. --- changelog.d/date-absolute.add | 1 + src/components/settings_modal/tabs/general_tab.vue | 23 +++++++++ src/components/timeago/timeago.vue | 57 ++++++++++++++++++++-- src/i18n/en.json | 2 + src/modules/config.js | 4 +- src/modules/instance.js | 2 + src/services/date_utils/date_utils.js | 43 +++++++++++++++- 7 files changed, 124 insertions(+), 8 deletions(-) create mode 100644 changelog.d/date-absolute.add (limited to 'src/i18n') diff --git a/changelog.d/date-absolute.add b/changelog.d/date-absolute.add new file mode 100644 index 00000000..d9365f46 --- /dev/null +++ b/changelog.d/date-absolute.add @@ -0,0 +1 @@ +Support displaying time in absolute format diff --git a/src/components/settings_modal/tabs/general_tab.vue b/src/components/settings_modal/tabs/general_tab.vue index 4ece6cf4..82d5da89 100644 --- a/src/components/settings_modal/tabs/general_tab.vue +++ b/src/components/settings_modal/tabs/general_tab.vue @@ -217,6 +217,29 @@ {{ $t('settings.no_rich_text_description') }} +
  • + + {{ $t('settings.absolute_time_format') }} + +
  • +
      +
    • + + {{ $t('settings.absolute_time_format_min_age') }} + +
    • +

    {{ $t('settings.attachments') }}

  • - {{ relativeTimeString }} + {{ relativeOrAbsoluteTimeString }} @@ -16,16 +16,28 @@ export default { props: ['time', 'autoUpdate', 'longFormat', 'nowThreshold', 'templateKey'], data () { return { + relativeTimeMs: 0, relativeTime: { key: 'time.now', num: 0 }, interval: null } }, computed: { - localeDateString () { - const browserLocale = localeService.internalToBrowserLocale(this.$i18n.locale) + shouldUseAbsoluteTimeFormat () { + if (!this.$store.getters.mergedConfig.useAbsoluteTimeFormat) { + return false + } + return DateUtils.durationStrToMs(this.$store.getters.mergedConfig.absoluteTimeFormatMinAge) <= this.relativeTimeMs + }, + browserLocale () { + return localeService.internalToBrowserLocale(this.$i18n.locale) + }, + timeAsDate () { return typeof this.time === 'string' - ? new Date(Date.parse(this.time)).toLocaleString(browserLocale) - : this.time.toLocaleString(browserLocale) + ? new Date(Date.parse(this.time)) + : this.time + }, + localeDateString () { + return this.timeAsDate.toLocaleString(this.browserLocale) }, relativeTimeString () { const timeString = this.$i18n.tc(this.relativeTime.key, this.relativeTime.num, [this.relativeTime.num]) @@ -35,6 +47,40 @@ export default { } return timeString + }, + absoluteTimeString () { + if (this.longFormat) { + return this.localeDateString + } + const now = new Date() + const formatter = (() => { + if (DateUtils.isSameDay(this.timeAsDate, now)) { + return new Intl.DateTimeFormat(this.browserLocale, { + minute: 'numeric', + hour: 'numeric' + }) + } else if (DateUtils.isSameMonth(this.timeAsDate, now)) { + return new Intl.DateTimeFormat(this.browserLocale, { + hour: 'numeric', + day: 'numeric' + }) + } else if (DateUtils.isSameYear(this.timeAsDate, now)) { + return new Intl.DateTimeFormat(this.browserLocale, { + month: 'short', + day: 'numeric' + }) + } else { + return new Intl.DateTimeFormat(this.browserLocale, { + year: 'numeric', + month: 'short' + }) + } + })() + + return formatter.format(this.timeAsDate) + }, + relativeOrAbsoluteTimeString () { + return this.shouldUseAbsoluteTimeFormat ? this.absoluteTimeString : this.relativeTimeString } }, watch: { @@ -54,6 +100,7 @@ export default { methods: { refreshRelativeTimeObject () { const nowThreshold = typeof this.nowThreshold === 'number' ? this.nowThreshold : 1 + this.relativeTimeMs = DateUtils.relativeTimeMs(this.time) this.relativeTime = this.longFormat ? DateUtils.relativeTime(this.time, nowThreshold) : DateUtils.relativeTimeShort(this.time, nowThreshold) diff --git a/src/i18n/en.json b/src/i18n/en.json index 3f7ea282..0ed481c0 100644 --- a/src/i18n/en.json +++ b/src/i18n/en.json @@ -506,6 +506,8 @@ "autocomplete_select_first": "Automatically select the first candidate when autocomplete results are available", "emoji_reactions_on_timeline": "Show emoji reactions on timeline", "emoji_reactions_scale": "Reactions scale factor", + "absolute_time_format": "Use absolute time format", + "absolute_time_format_min_age": "Only use for time older than this amount of time", "export_theme": "Save preset", "filtering": "Filtering", "wordfilter": "Wordfilter", diff --git a/src/modules/config.js b/src/modules/config.js index cf84234a..835dcce4 100644 --- a/src/modules/config.js +++ b/src/modules/config.js @@ -180,7 +180,9 @@ export const defaultState = { autocompleteSelect: undefined, // instance default closingDrawerMarksAsSeen: undefined, // instance default unseenAtTop: undefined, // instance default - ignoreInactionableSeen: undefined // instance default + ignoreInactionableSeen: undefined, // instance default + useAbsoluteTimeFormat: undefined, // instance defualt + absoluteTimeFormatMinAge: undefined // instance default } // caching the instance default properties diff --git a/src/modules/instance.js b/src/modules/instance.js index 99b8b5d5..994f60a5 100644 --- a/src/modules/instance.js +++ b/src/modules/instance.js @@ -119,6 +119,8 @@ const defaultState = { closingDrawerMarksAsSeen: true, unseenAtTop: false, ignoreInactionableSeen: false, + useAbsoluteTimeFormat: false, + absoluteTimeFormatMinAge: '0d', // Nasty stuff customEmoji: [], diff --git a/src/services/date_utils/date_utils.js b/src/services/date_utils/date_utils.js index ed8e1417..69398c0c 100644 --- a/src/services/date_utils/date_utils.js +++ b/src/services/date_utils/date_utils.js @@ -6,10 +6,13 @@ export const WEEK = 7 * DAY export const MONTH = 30 * DAY export const YEAR = 365.25 * DAY -export const relativeTime = (date, nowThreshold = 1) => { +export const relativeTimeMs = (date) => { if (typeof date === 'string') date = Date.parse(date) + return Math.abs(Date.now() - date) +} +export const relativeTime = (date, nowThreshold = 1) => { const round = Date.now() > date ? Math.floor : Math.ceil - const d = Math.abs(Date.now() - date) + const d = relativeTimeMs(date) const r = { num: round(d / YEAR), key: 'time.unit.years' } if (d < nowThreshold * SECOND) { r.num = 0 @@ -57,3 +60,39 @@ export const secondsToUnit = (unit, amount) => { case 'days': return (1000 * amount) / DAY } } + +export const isSameYear = (a, b) => { + return a.getFullYear() === b.getFullYear() +} + +export const isSameMonth = (a, b) => { + return a.getFullYear() === b.getFullYear() && + a.getMonth() === b.getMonth() +} + +export const isSameDay = (a, b) => { + return a.getFullYear() === b.getFullYear() && + a.getMonth() === b.getMonth() && + a.getDate() === b.getDate() +} + +export const durationStrToMs = (str) => { + if (typeof str !== 'string') { + return 0 + } + + const unit = str.replace(/[0-9,.]+/, '') + const value = str.replace(/[^0-9,.]+/, '') + switch (unit) { + case 'd': + return value * DAY + case 'h': + return value * HOUR + case 'm': + return value * MINUTE + case 's': + return value * SECOND + default: + return 0 + } +} -- cgit v1.2.3-70-g09d2 From 6335a205c80336c70f4ac4d68e6f3ec305994070 Mon Sep 17 00:00:00 2001 From: Kian-ting Tan Date: Wed, 11 Sep 2024 12:34:58 +0000 Subject: Translated using Weblate (Chinese (Min Nan) (nan_TW)) Currently translated at 91.6% (1093 of 1193 strings) Translation: Pleroma/Pleroma-FE Translate-URL: https://translate.pleroma.social/projects/pleroma/pleroma-fe/nan_TW/ --- src/i18n/nan-TW.json | 43 +++++++++++++++++++++++++++++++++++++------ 1 file changed, 37 insertions(+), 6 deletions(-) (limited to 'src/i18n') diff --git a/src/i18n/nan-TW.json b/src/i18n/nan-TW.json index 782a75f5..44a693dd 100644 --- a/src/i18n/nan-TW.json +++ b/src/i18n/nan-TW.json @@ -190,7 +190,8 @@ "mobile_notifications_close": "關掉通知", "announcements": "公告", "search": "Tshuē", - "mobile_notifications_mark_as_seen": "Lóng 標做有讀" + "mobile_notifications_mark_as_seen": "Lóng 標做有讀", + "quotes": "引用" }, "notifications": { "broken_favorite": "狀態毋知影,leh tshiau-tshuē……", @@ -212,7 +213,8 @@ "unread_follow_requests": "{num}ê新ê跟tuè請求", "configuration_tip": "用{theSettings},lí通自訂siánn物佇tsia顯示。{dismiss}", "configuration_tip_settings": "設定", - "configuration_tip_dismiss": "Mài koh顯示" + "configuration_tip_dismiss": "Mài koh顯示", + "subscribed_status": "有發送ê" }, "polls": { "add_poll": "開投票", @@ -252,7 +254,8 @@ }, "load_all_hint": "載入頭前 {saneAmount} ê 繪文字,規个攏載入效能可能 ē khah 食力。", "load_all": "Kā {emojiAmount} ê 繪文字攏載入", - "regional_indicator": "地區指引 {letter}" + "regional_indicator": "地區指引 {letter}", + "hide_custom_emoji": "Khàm掉自訂ê繪文字" }, "errors": { "storage_unavailable": "Pleroma buē-tàng the̍h 著瀏覽器儲存 ê。Lí ê 登入狀態抑是局部設定 buē 儲存,mā 凡勢 tú 著意料外 ê 問題。拍開 cookie 看māi。" @@ -263,7 +266,8 @@ "emoji_reactions": "繪文字 ê 反應", "reports": "檢舉", "moves": "用者 ê 移民", - "load_older": "載入 koh khah 早 ê 互動" + "load_older": "載入 koh khah 早 ê 互動", + "statuses": "訂ê" }, "post_status": { "edit_status": "編輯狀態", @@ -935,7 +939,34 @@ "notification_extra_chats": "顯示bô讀ê開講", "notification_extra_announcements": "顯示bô讀ê公告", "notification_extra_follow_requests": "顯示新ê跟tuè請求", - "notification_extra_tip": "顯示自訂其他通知ê撇步" + "notification_extra_tip": "顯示自訂其他通知ê撇步", + "confirm_new_setting": "Lí敢確認新ê設定?", + "text_size_tip": "用 {0} 做絕對值,{1} ē根據瀏覽器ê標準文字sài-suh放大縮小。", + "theme_debug": "佇處理透明ê時,顯示背景主題ia̋n-jín 所假使ê(DEBUG)", + "units": { + "time": { + "s": "秒鐘", + "m": "分鐘", + "h": "點鐘", + "d": "工" + } + }, + "actor_type": "Tsit ê口座是:", + "actor_type_Person": "一般ê用者", + "actor_type_description": "標記lí ê口座做群組,ē hōo自動轉送提起伊ê狀態。", + "actor_type_Group": "群組", + "actor_type_Service": "機器lâng", + "appearance": "外觀", + "confirm_new_question": "Tse看起來kám好?設定ē佇10秒鐘後改轉去。", + "revert": "改轉去", + "confirm": "確認", + "text_size": "文字kap界面ê sài-suh", + "text_size_tip2": "毋是 {0} ê值可能ē破壞一寡物件kap主題", + "emoji_size": "繪文字ê sài-suh", + "navbar_size": "頂 liâu-á êsài-suh", + "panel_header_size": "面pang標題ê sài-suh", + "visual_tweaks": "細細ê外觀調整", + "scale_and_layout": "界面ê sài-suh kap排列" }, "status": { "favorites": "收藏", @@ -1001,7 +1032,7 @@ "show_only_conversation_under_this": "Kan-ta顯示tsit ê狀態ê回應", "status_history": "狀態ê歷史", "reaction_count_label": "{num}ê lâng用表情反應", - "hide_quote": "Khàm條引用ê狀態", + "hide_quote": "Khàm掉引用ê狀態", "display_quote": "顯示引用ê狀態", "invisible_quote": "引用ê狀態bē當用:{link}", "more_actions": "佇tsit ê狀態ê其他動作" -- cgit v1.2.3-70-g09d2