From ae479326512fe93b392b3eeff4582a0e1b48c503 Mon Sep 17 00:00:00 2001 From: Jamie Benstead Date: Thu, 26 Jun 2025 13:09:26 +0100 Subject: [PATCH 1/7] Add translation to the last saved text --- src/components/SaveStatus/SaveStatus.jsx | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/src/components/SaveStatus/SaveStatus.jsx b/src/components/SaveStatus/SaveStatus.jsx index 04bd8099a..5e486256d 100644 --- a/src/components/SaveStatus/SaveStatus.jsx +++ b/src/components/SaveStatus/SaveStatus.jsx @@ -11,7 +11,20 @@ import CloudUploadIcon from "../../assets/icons/cloud_upload.svg"; import "../../assets/stylesheets/SaveStatus.scss"; const SaveStatus = ({ isMobile = false }) => { - const { t } = useTranslation(); + const { t, i18n } = useTranslation(); + const locale = i18n.language; + + const localeMap = { + "en-US": "en-US", + en: "en-GB", + "fr-FR": "fr", + "es-LA": "es", + }; + + const getLocales = (languageCode) => { + return localeMap[languageCode]; + }; + const lastSavedTime = useSelector((state) => state.editor.lastSavedTime); const saving = useSelector((state) => state.editor.saving); const [time, setTime] = useState(Date.now()); @@ -54,7 +67,10 @@ const SaveStatus = ({ isMobile = false }) => {
{t("saveStatus.saved")}{" "} - {intlFormatDistance(lastSavedTime, time, { style: "narrow" })} + {intlFormatDistance(lastSavedTime, time, { + style: "narrow", + locale: getLocales(locale), + })}
)} From 1d26128522cc0c6134023e6c183d3650b7fa4e83 Mon Sep 17 00:00:00 2001 From: Jamie Benstead Date: Fri, 27 Jun 2025 11:18:42 +0100 Subject: [PATCH 2/7] Move logic to own file, add in tests --- src/components/SaveStatus/SaveStatus.jsx | 19 +----- src/utils/formatRelativeTime.js | 16 +++++ src/utils/formatRelativeTime.test.js | 74 ++++++++++++++++++++++++ 3 files changed, 92 insertions(+), 17 deletions(-) create mode 100644 src/utils/formatRelativeTime.js create mode 100644 src/utils/formatRelativeTime.test.js diff --git a/src/components/SaveStatus/SaveStatus.jsx b/src/components/SaveStatus/SaveStatus.jsx index 5e486256d..32271115a 100644 --- a/src/components/SaveStatus/SaveStatus.jsx +++ b/src/components/SaveStatus/SaveStatus.jsx @@ -1,5 +1,3 @@ -import { intlFormatDistance } from "date-fns"; - import React, { useState, useEffect } from "react"; import { useSelector } from "react-redux"; import { useTranslation } from "react-i18next"; @@ -9,22 +7,12 @@ import CloudTickIcon from "../../assets/icons/cloud_tick.svg"; import CloudUploadIcon from "../../assets/icons/cloud_upload.svg"; import "../../assets/stylesheets/SaveStatus.scss"; +import { formatRelativeTime } from "../../utils/formatRelativeTime"; const SaveStatus = ({ isMobile = false }) => { const { t, i18n } = useTranslation(); const locale = i18n.language; - const localeMap = { - "en-US": "en-US", - en: "en-GB", - "fr-FR": "fr", - "es-LA": "es", - }; - - const getLocales = (languageCode) => { - return localeMap[languageCode]; - }; - const lastSavedTime = useSelector((state) => state.editor.lastSavedTime); const saving = useSelector((state) => state.editor.saving); const [time, setTime] = useState(Date.now()); @@ -67,10 +55,7 @@ const SaveStatus = ({ isMobile = false }) => {
{t("saveStatus.saved")}{" "} - {intlFormatDistance(lastSavedTime, time, { - style: "narrow", - locale: getLocales(locale), - })} + {formatRelativeTime(lastSavedTime, time, locale)}
)} diff --git a/src/utils/formatRelativeTime.js b/src/utils/formatRelativeTime.js new file mode 100644 index 000000000..9ba6ea9a7 --- /dev/null +++ b/src/utils/formatRelativeTime.js @@ -0,0 +1,16 @@ +import { intlFormatDistance } from "date-fns"; + +const localeMap = { + "en-US": "en-US", + en: "en-GB", + "fr-FR": "fr", + "es-LA": "es", +}; + +export const formatRelativeTime = (lastSavedTime, now, languageCode) => { + const locale = localeMap[languageCode]; + return intlFormatDistance(lastSavedTime, now, { + style: "narrow", + locale, + }); +}; diff --git a/src/utils/formatRelativeTime.test.js b/src/utils/formatRelativeTime.test.js new file mode 100644 index 000000000..13c044145 --- /dev/null +++ b/src/utils/formatRelativeTime.test.js @@ -0,0 +1,74 @@ +import { formatRelativeTime } from "./formatRelativeTime"; + +describe("formatRelativeTime", () => { + describe("formats the times for now in different locales", () => { + const now = Date.now(); + + test("formats relative time in en", () => { + const result = formatRelativeTime(now, now, "en"); + expect(result).toEqual("now"); + }); + + test("formats relative time in en-US", () => { + const result = formatRelativeTime(now, now, "en-US"); + expect(result).toEqual("now"); + }); + + test("formats relative time in fr-FR", () => { + const result = formatRelativeTime(now, now, "fr-FR"); + expect(result).toEqual("maintenant"); + }); + + test("formats relative time in es-LA", () => { + const result = formatRelativeTime(now, now, "es-LA"); + expect(result).toEqual("ahora"); + }); + }); + describe("formats the times for one minute ago in different locales", () => { + const oneMinuteAgo = new Date(Date.now() - 60 * 1000); // 1 minute ago + + test("formats relative time in en", () => { + const result = formatRelativeTime(oneMinuteAgo, Date.now(), "en"); + expect(result).toEqual("1 min ago"); + }); + + test("formats relative time in en-US", () => { + const result = formatRelativeTime(oneMinuteAgo, Date.now(), "en-US"); + expect(result).toEqual("1m ago"); + }); + + test("formats relative time in fr-FR", () => { + const result = formatRelativeTime(oneMinuteAgo, Date.now(), "fr-FR"); + expect(result).toEqual("-1 min"); + }); + + test("formats relative time in es-LA", () => { + const result = formatRelativeTime(oneMinuteAgo, Date.now(), "es-LA"); + expect(result).toEqual("hace 1 min"); + }); + }); + + describe("formats the times for one hour ago in different locales", () => { + const oneHourAgo = new Date(Date.now() - 60 * 60 * 1000); // 1 hour ago + + test("formats relative time in en", () => { + const result = formatRelativeTime(oneHourAgo, Date.now(), "en"); + expect(result).toEqual("1 hr ago"); + }); + + test("formats relative time in en-US", () => { + const result = formatRelativeTime(oneHourAgo, Date.now(), "en-US"); + expect(result).toEqual("1h ago"); + }); + + test("formats relative time in fr-FR", () => { + const result = formatRelativeTime(oneHourAgo, Date.now(), "fr-FR"); + expect(result).toEqual("-1 h"); + }); + + test("formats relative time in es-LA", () => { + const result = formatRelativeTime(oneHourAgo, Date.now(), "es-LA"); + expect(result).toEqual("hace 1 h"); + }); + }); +}); From fb3ae9b6b0bdb83d0b25a43d9100c3939baa2962 Mon Sep 17 00:00:00 2001 From: Jamie Benstead Date: Fri, 27 Jun 2025 11:35:43 +0100 Subject: [PATCH 3/7] Update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9b024f768..0687eccd4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), ## Changed - Improved status bar styling (#1221) +- Added method to translate last saved time (#1223) ## [0.30.1] - 2025-06-09 From 29f7b439eae7ff8ee1361d03a717eac7604723dc Mon Sep 17 00:00:00 2001 From: Jamie Benstead Date: Fri, 27 Jun 2025 15:17:41 +0100 Subject: [PATCH 4/7] Update version of date-fns --- package.json | 2 +- yarn.lock | 14 ++++++-------- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/package.json b/package.json index 8eba613a0..5ff4c4c5b 100644 --- a/package.json +++ b/package.json @@ -30,7 +30,7 @@ "classnames": "^2.3.2", "codemirror": "^6.0.1", "container-query-polyfill": "^1.0.2", - "date-fns": "^2.29.3", + "date-fns": "^4.1.0", "eslint-config-prettier": "^8.8.0", "file-saver": "^2.0.5", "fs-extra": "^9.0.1", diff --git a/yarn.lock b/yarn.lock index f800fb29e..f2520e018 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1611,7 +1611,7 @@ __metadata: languageName: node linkType: hard -"@babel/runtime@npm:^7.0.0, @babel/runtime@npm:^7.11.2, @babel/runtime@npm:^7.12.1, @babel/runtime@npm:^7.12.5, @babel/runtime@npm:^7.15.4, @babel/runtime@npm:^7.16.3, @babel/runtime@npm:^7.17.8, @babel/runtime@npm:^7.18.3, @babel/runtime@npm:^7.20.6, @babel/runtime@npm:^7.20.7, @babel/runtime@npm:^7.21.0, @babel/runtime@npm:^7.23.2, @babel/runtime@npm:^7.24.1, @babel/runtime@npm:^7.5.5, @babel/runtime@npm:^7.8.4, @babel/runtime@npm:^7.9.2": +"@babel/runtime@npm:^7.0.0, @babel/runtime@npm:^7.11.2, @babel/runtime@npm:^7.12.1, @babel/runtime@npm:^7.12.5, @babel/runtime@npm:^7.15.4, @babel/runtime@npm:^7.16.3, @babel/runtime@npm:^7.17.8, @babel/runtime@npm:^7.18.3, @babel/runtime@npm:^7.20.6, @babel/runtime@npm:^7.20.7, @babel/runtime@npm:^7.23.2, @babel/runtime@npm:^7.24.1, @babel/runtime@npm:^7.5.5, @babel/runtime@npm:^7.8.4, @babel/runtime@npm:^7.9.2": version: 7.25.7 resolution: "@babel/runtime@npm:7.25.7" dependencies: @@ -2792,7 +2792,7 @@ __metadata: css-loader: 4.3.0 curl: ^0.1.4 cypress: 12.12.0 - date-fns: ^2.29.3 + date-fns: ^4.1.0 dotenv: 8.2.0 dotenv-expand: 5.1.0 dotenv-webpack: 8.1.0 @@ -7171,12 +7171,10 @@ __metadata: languageName: node linkType: hard -"date-fns@npm:^2.29.3": - version: 2.30.0 - resolution: "date-fns@npm:2.30.0" - dependencies: - "@babel/runtime": ^7.21.0 - checksum: f7be01523282e9bb06c0cd2693d34f245247a29098527d4420628966a2d9aad154bd0e90a6b1cf66d37adcb769cd108cf8a7bd49d76db0fb119af5cdd13644f4 +"date-fns@npm:^4.1.0": + version: 4.1.0 + resolution: "date-fns@npm:4.1.0" + checksum: fb681b242cccabed45494468f64282a7d375ea970e0adbcc5dcc92dcb7aba49b2081c2c9739d41bf71ce89ed68dd73bebfe06ca35129490704775d091895710b languageName: node linkType: hard From 8012e38486fd196cb747fdc8663cdebe7dd71457 Mon Sep 17 00:00:00 2001 From: Jamie Benstead Date: Fri, 27 Jun 2025 15:37:06 +0100 Subject: [PATCH 5/7] Default to en if no match found --- src/utils/formatRelativeTime.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utils/formatRelativeTime.js b/src/utils/formatRelativeTime.js index 9ba6ea9a7..0f8f0900c 100644 --- a/src/utils/formatRelativeTime.js +++ b/src/utils/formatRelativeTime.js @@ -8,7 +8,7 @@ const localeMap = { }; export const formatRelativeTime = (lastSavedTime, now, languageCode) => { - const locale = localeMap[languageCode]; + const locale = localeMap[languageCode] || localeMap.en; // Default to English if no match found; return intlFormatDistance(lastSavedTime, now, { style: "narrow", locale, From 2dadcdb51510c86ed0022558123ba561ea5957a4 Mon Sep 17 00:00:00 2001 From: Lois Wells <88904316+loiswells97@users.noreply.github.com> Date: Tue, 1 Jul 2025 09:48:02 +0100 Subject: [PATCH 6/7] Change distance format from narrow to short --- src/utils/formatRelativeTime.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utils/formatRelativeTime.js b/src/utils/formatRelativeTime.js index 0f8f0900c..a489ee904 100644 --- a/src/utils/formatRelativeTime.js +++ b/src/utils/formatRelativeTime.js @@ -10,7 +10,7 @@ const localeMap = { export const formatRelativeTime = (lastSavedTime, now, languageCode) => { const locale = localeMap[languageCode] || localeMap.en; // Default to English if no match found; return intlFormatDistance(lastSavedTime, now, { - style: "narrow", + style: "short", locale, }); }; From 6b7188c5e6604698f179460a67adf2087865187a Mon Sep 17 00:00:00 2001 From: Lois Wells Date: Tue, 1 Jul 2025 10:15:46 +0100 Subject: [PATCH 7/7] test fixing --- src/utils/formatRelativeTime.test.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/utils/formatRelativeTime.test.js b/src/utils/formatRelativeTime.test.js index 13c044145..d5dbe5b88 100644 --- a/src/utils/formatRelativeTime.test.js +++ b/src/utils/formatRelativeTime.test.js @@ -34,12 +34,12 @@ describe("formatRelativeTime", () => { test("formats relative time in en-US", () => { const result = formatRelativeTime(oneMinuteAgo, Date.now(), "en-US"); - expect(result).toEqual("1m ago"); + expect(result).toEqual("1 min. ago"); }); test("formats relative time in fr-FR", () => { const result = formatRelativeTime(oneMinuteAgo, Date.now(), "fr-FR"); - expect(result).toEqual("-1 min"); + expect(result).toEqual("il y a 1\u00A0min"); }); test("formats relative time in es-LA", () => { @@ -58,12 +58,12 @@ describe("formatRelativeTime", () => { test("formats relative time in en-US", () => { const result = formatRelativeTime(oneHourAgo, Date.now(), "en-US"); - expect(result).toEqual("1h ago"); + expect(result).toEqual("1 hr. ago"); }); test("formats relative time in fr-FR", () => { const result = formatRelativeTime(oneHourAgo, Date.now(), "fr-FR"); - expect(result).toEqual("-1 h"); + expect(result).toEqual("il y a 1\u00A0h"); }); test("formats relative time in es-LA", () => {