refactor(i18n): about locales (#30336)

Co-authored-by: yyh <yuanyouhuilyz@gmail.com>
This commit is contained in:
Stephen Zhou
2025-12-30 14:38:23 +08:00
committed by GitHub
parent 3505516e8e
commit 2399d00d86
70 changed files with 273 additions and 320 deletions
+21 -23
View File
@@ -14,15 +14,13 @@ import type { Mock } from 'vitest'
*/
import { renderHook } from '@testing-library/react'
// Import after mock to get the mocked version
import { useI18N } from '@/context/i18n'
import { useLocale } from '@/context/i18n'
import { useFormatTimeFromNow } from './use-format-time-from-now'
// Mock the i18n context
vi.mock('@/context/i18n', () => ({
useI18N: vi.fn(() => ({
locale: 'en-US',
})),
useLocale: vi.fn(() => 'en-US'),
}))
describe('useFormatTimeFromNow', () => {
@@ -47,7 +45,7 @@ describe('useFormatTimeFromNow', () => {
* Should return human-readable relative time strings
*/
it('should format time from now in English', () => {
;(useI18N as Mock).mockReturnValue({ locale: 'en-US' })
;(useLocale as Mock).mockReturnValue('en-US')
const { result } = renderHook(() => useFormatTimeFromNow())
@@ -65,7 +63,7 @@ describe('useFormatTimeFromNow', () => {
* Very recent timestamps should show seconds
*/
it('should format very recent times', () => {
;(useI18N as Mock).mockReturnValue({ locale: 'en-US' })
;(useLocale as Mock).mockReturnValue('en-US')
const { result } = renderHook(() => useFormatTimeFromNow())
@@ -81,7 +79,7 @@ describe('useFormatTimeFromNow', () => {
* Should handle day-level granularity
*/
it('should format times from days ago', () => {
;(useI18N as Mock).mockReturnValue({ locale: 'en-US' })
;(useLocale as Mock).mockReturnValue('en-US')
const { result } = renderHook(() => useFormatTimeFromNow())
@@ -98,7 +96,7 @@ describe('useFormatTimeFromNow', () => {
* dayjs fromNow also supports future times (e.g., "in 2 hours")
*/
it('should format future times', () => {
;(useI18N as Mock).mockReturnValue({ locale: 'en-US' })
;(useLocale as Mock).mockReturnValue('en-US')
const { result } = renderHook(() => useFormatTimeFromNow())
@@ -117,7 +115,7 @@ describe('useFormatTimeFromNow', () => {
* Should use Chinese characters for time units
*/
it('should format time in Chinese (Simplified)', () => {
;(useI18N as Mock).mockReturnValue({ locale: 'zh-Hans' })
;(useLocale as Mock).mockReturnValue('zh-Hans')
const { result } = renderHook(() => useFormatTimeFromNow())
@@ -134,7 +132,7 @@ describe('useFormatTimeFromNow', () => {
* Should use Spanish words for relative time
*/
it('should format time in Spanish', () => {
;(useI18N as Mock).mockReturnValue({ locale: 'es-ES' })
;(useLocale as Mock).mockReturnValue('es-ES')
const { result } = renderHook(() => useFormatTimeFromNow())
@@ -151,7 +149,7 @@ describe('useFormatTimeFromNow', () => {
* Should use French words for relative time
*/
it('should format time in French', () => {
;(useI18N as Mock).mockReturnValue({ locale: 'fr-FR' })
;(useLocale as Mock).mockReturnValue('fr-FR')
const { result } = renderHook(() => useFormatTimeFromNow())
@@ -168,7 +166,7 @@ describe('useFormatTimeFromNow', () => {
* Should use Japanese characters
*/
it('should format time in Japanese', () => {
;(useI18N as Mock).mockReturnValue({ locale: 'ja-JP' })
;(useLocale as Mock).mockReturnValue('ja-JP')
const { result } = renderHook(() => useFormatTimeFromNow())
@@ -185,7 +183,7 @@ describe('useFormatTimeFromNow', () => {
* Should use pt-br locale mapping
*/
it('should format time in Portuguese (Brazil)', () => {
;(useI18N as Mock).mockReturnValue({ locale: 'pt-BR' })
;(useLocale as Mock).mockReturnValue('pt-BR')
const { result } = renderHook(() => useFormatTimeFromNow())
@@ -202,7 +200,7 @@ describe('useFormatTimeFromNow', () => {
* Unknown locales should default to English
*/
it('should fallback to English for unsupported locale', () => {
;(useI18N as Mock).mockReturnValue({ locale: 'xx-XX' as any })
;(useLocale as Mock).mockReturnValue('xx-XX' as any)
const { result } = renderHook(() => useFormatTimeFromNow())
@@ -222,7 +220,7 @@ describe('useFormatTimeFromNow', () => {
* Should format as a very old date
*/
it('should handle timestamp 0', () => {
;(useI18N as Mock).mockReturnValue({ locale: 'en-US' })
;(useLocale as Mock).mockReturnValue('en-US')
const { result } = renderHook(() => useFormatTimeFromNow())
@@ -238,7 +236,7 @@ describe('useFormatTimeFromNow', () => {
* Should handle dates far in the future
*/
it('should handle very large timestamps', () => {
;(useI18N as Mock).mockReturnValue({ locale: 'en-US' })
;(useLocale as Mock).mockReturnValue('en-US')
const { result } = renderHook(() => useFormatTimeFromNow())
@@ -260,12 +258,12 @@ describe('useFormatTimeFromNow', () => {
const oneHourAgo = now - (60 * 60 * 1000)
// First render with English
;(useI18N as Mock).mockReturnValue({ locale: 'en-US' })
;(useLocale as Mock).mockReturnValue('en-US')
rerender()
const englishResult = result.current.formatTimeFromNow(oneHourAgo)
// Second render with Spanish
;(useI18N as Mock).mockReturnValue({ locale: 'es-ES' })
;(useLocale as Mock).mockReturnValue('es-ES')
rerender()
const spanishResult = result.current.formatTimeFromNow(oneHourAgo)
@@ -280,7 +278,7 @@ describe('useFormatTimeFromNow', () => {
* dayjs should automatically choose the appropriate unit
*/
it('should use appropriate time units for different durations', () => {
;(useI18N as Mock).mockReturnValue({ locale: 'en-US' })
;(useLocale as Mock).mockReturnValue('en-US')
const { result } = renderHook(() => useFormatTimeFromNow())
@@ -342,7 +340,7 @@ describe('useFormatTimeFromNow', () => {
const oneHourAgo = now - (60 * 60 * 1000)
locales.forEach((locale) => {
;(useI18N as Mock).mockReturnValue({ locale })
;(useLocale as Mock).mockReturnValue(locale)
const { result } = renderHook(() => useFormatTimeFromNow())
const formatted = result.current.formatTimeFromNow(oneHourAgo)
@@ -360,7 +358,7 @@ describe('useFormatTimeFromNow', () => {
* The formatTimeFromNow function should be memoized with useCallback
*/
it('should memoize formatTimeFromNow function', () => {
;(useI18N as Mock).mockReturnValue({ locale: 'en-US' })
;(useLocale as Mock).mockReturnValue('en-US')
const { result, rerender } = renderHook(() => useFormatTimeFromNow())
@@ -379,11 +377,11 @@ describe('useFormatTimeFromNow', () => {
it('should create new function when locale changes', () => {
const { result, rerender } = renderHook(() => useFormatTimeFromNow())
;(useI18N as Mock).mockReturnValue({ locale: 'en-US' })
;(useLocale as Mock).mockReturnValue('en-US')
rerender()
const englishFunction = result.current.formatTimeFromNow
;(useI18N as Mock).mockReturnValue({ locale: 'es-ES' })
;(useLocale as Mock).mockReturnValue('es-ES')
rerender()
const spanishFunction = result.current.formatTimeFromNow
+2 -2
View File
@@ -1,7 +1,7 @@
import dayjs from 'dayjs'
import relativeTime from 'dayjs/plugin/relativeTime'
import { useCallback } from 'react'
import { useI18N } from '@/context/i18n'
import { useLocale } from '@/context/i18n'
import { localeMap } from '@/i18n-config/language'
import 'dayjs/locale/de'
import 'dayjs/locale/es'
@@ -27,7 +27,7 @@ import 'dayjs/locale/zh-tw'
dayjs.extend(relativeTime)
export const useFormatTimeFromNow = () => {
const { locale } = useI18N()
const locale = useLocale()
const formatTimeFromNow = useCallback((time: number) => {
const dayjsLocale = localeMap[locale] ?? 'en'
return dayjs(time).locale(dayjsLocale).fromNow()