Quellcode durchsuchen

Merge pull request #10490 from growilabs/imprv/173926-add-timestamp-transdlations

imprv: Add translations for timestamps
Yuki Takei vor 4 Monaten
Ursprung
Commit
aef9f962c9

+ 12 - 5
apps/app/src/client/components/RecentActivity/ActivityListItem.tsx

@@ -1,6 +1,7 @@
 import { formatDistanceToNow } from 'date-fns';
 import { useTranslation } from 'next-i18next';
-
+import { type Locale } from 'date-fns/locale';
+import { getLocale } from '~/server/util/locale-utils';
 import type { ActivityHasUserId, SupportedActivityActionType } from '~/interfaces/activity';
 import { ActivityLogActions } from '~/interfaces/activity';
 
@@ -43,15 +44,21 @@ const setIcon = (action: SupportedActivityActionType): string => {
   return IconActivityTranslationMap[action] || 'question_mark';
 };
 
-const calculateTimePassed = (date: Date): string => {
-  const timePassed = formatDistanceToNow(date, { addSuffix: true });
+const calculateTimePassed = (date: Date, locale: Locale): string => {
+  const timePassed = formatDistanceToNow(date, {
+    addSuffix: true,
+    locale,
+  });
 
   return timePassed;
 };
 
 
 export const ActivityListItem = ({ activity }: { activity: ActivityHasUserId }): JSX.Element => {
-  const { t } = useTranslation();
+  const { t, i18n } = useTranslation();
+  const currentLangCode = i18n.language;
+  const dateFnsLocale = getLocale(currentLangCode);
+
   const action = activity.action as SupportedActivityActionType;
   const keyToTranslate = translateAction(action);
   const fullKeyPath = `user_home_page.${keyToTranslate}`;
@@ -66,7 +73,7 @@ export const ActivityListItem = ({ activity }: { activity: ActivityHasUserId }):
         </span>
 
         <span className="text-secondary small ms-3">
-          {calculateTimePassed(activity.createdAt)}
+          {calculateTimePassed(activity.createdAt, dateFnsLocale)}
         </span>
       </p>
     </div>

+ 39 - 0
apps/app/src/server/util/locale-utils.ts

@@ -1,4 +1,5 @@
 import { Lang } from '@growi/core/dist/interfaces';
+import { enUS, fr, ja, ko, type Locale, zhCN } from 'date-fns/locale';
 import type { IncomingHttpHeaders } from 'http';
 
 import * as i18nextConfig from '^/config/i18next.config';
@@ -11,6 +12,44 @@ const ACCEPT_LANG_MAP = {
   ko: Lang.ko_KR,
 };
 
+const DATE_FNS_LOCALE_MAP: Record<string, Locale | undefined> = {
+  en: enUS,
+  'en-US': enUS,
+  en_US: enUS,
+
+  ja: ja,
+  'ja-JP': ja,
+  ja_JP: ja,
+
+  fr: fr,
+  'fr-FR': fr,
+  fr_FR: fr,
+
+  ko: ko,
+  'ko-KR': ko,
+  ko_KR: ko,
+
+  zh: zhCN,
+  'zh-CN': zhCN,
+  zh_CN: zhCN,
+};
+
+/**
+ * Gets the corresponding date-fns Locale object from an i18next language code.
+ * @param langCode The i18n language code (e.g., 'ja_JP').
+ * @returns The date-fns Locale object, defaulting to enUS if not found.
+ */
+export const getLocale = (langCode: string): Locale => {
+  let locale = DATE_FNS_LOCALE_MAP[langCode];
+
+  if (!locale) {
+    const baseCode = langCode.split(/[-_]/)[0];
+    locale = DATE_FNS_LOCALE_MAP[baseCode];
+  }
+
+  return locale ?? enUS;
+};
+
 /**
  * It return the first language that matches ACCEPT_LANG_MAP keys from sorted accept languages array
  * @param sortedAcceptLanguagesArray