cc-haha/desktop/src/lib/formatMessageTimestamp.test.ts
tw199501 f02ea93018 feat(desktop): add Japanese, Korean, and Traditional Chinese locales
Add jp / kr / zh-TW translations and wire them into the i18n runtime so the
desktop app can switch among English, Simplified Chinese, Traditional Chinese,
Japanese, and Korean.

- new locale files jp.ts / kr.ts / zh-TW.ts with full TranslationKey coverage
- register the locales in the i18n index and extend the Locale union
- accept the new codes in settingsStore.getStoredLocale (default stays zh)
- add language-switcher entries (简体中文 / 繁體中文 / 日本語 / 한국어)
- localize chat message timestamps: Han 年月日 for zh/zh-TW/jp, Intl ko-KR for kr
- extend the DATE_LOCALES map in ActivitySettings (ja-JP / ko-KR / zh-TW)
- tests: formatMessageTimestamp locale branches + i18n locale resolution

Korean terminology follows the Microsoft Korean localization style guide
(새로 고침 / 사용·사용 안 함 / 이름 바꾸기, 합니다-style sentences).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-03 09:55:38 +08:00

60 lines
2.5 KiB
TypeScript

import { describe, expect, it } from 'vitest'
import { translate, type Locale } from '../i18n'
import { formatMessageTimestamp } from './formatMessageTimestamp'
const t = (locale: Locale) => (
key: Parameters<typeof translate>[1],
params?: Parameters<typeof translate>[2],
) => translate(locale, key, params)
describe('formatMessageTimestamp', () => {
const now = new Date(2026, 4, 29, 16, 0).getTime()
it('uses relative labels for recent messages', () => {
expect(formatMessageTimestamp(now - 5 * 60_000, t('zh'), 'zh', now)).toBe('5分钟前')
expect(formatMessageTimestamp(now - 2 * 60 * 60_000, t('en'), 'en', now)).toBe('2h ago')
})
it('uses weekday and clock time for recent history', () => {
const value = new Date(2026, 4, 24, 15, 50).getTime()
expect(formatMessageTimestamp(value, t('zh'), 'zh', now)).toBe('星期日15:50')
})
it('includes the calendar date for older messages', () => {
const value = new Date(2026, 3, 20, 9, 30).getTime()
expect(formatMessageTimestamp(value, t('zh'), 'zh', now)).toBe('4月20日 09:30')
})
it('formats Japanese history with Han year/month/day characters', () => {
const weekday = new Date(2026, 4, 24, 15, 50).getTime()
expect(formatMessageTimestamp(weekday, t('jp'), 'jp', now)).toContain('15:50')
const monthDay = new Date(2026, 3, 20, 9, 30).getTime()
expect(formatMessageTimestamp(monthDay, t('jp'), 'jp', now)).toBe('4月20日 09:30')
const yearMonthDay = new Date(2025, 11, 15, 9, 30).getTime()
expect(formatMessageTimestamp(yearMonthDay, t('jp'), 'jp', now)).toBe('2025年12月15日 09:30')
expect(formatMessageTimestamp(now - 5 * 60_000, t('jp'), 'jp', now)).toBe('5 分前')
})
it('formats Traditional Chinese history with Han year/month/day characters', () => {
const monthDay = new Date(2026, 3, 20, 9, 30).getTime()
expect(formatMessageTimestamp(monthDay, t('zh-TW'), 'zh-TW', now)).toBe('4月20日 09:30')
const yearMonthDay = new Date(2025, 11, 15, 9, 30).getTime()
expect(formatMessageTimestamp(yearMonthDay, t('zh-TW'), 'zh-TW', now)).toBe('2025年12月15日 09:30')
})
it('formats Korean history via Intl (ko-KR) without Han characters', () => {
const monthDay = new Date(2026, 3, 20, 9, 30).getTime()
const out = formatMessageTimestamp(monthDay, t('kr'), 'kr', now)
expect(out).toContain('09:30')
expect(out).not.toContain('月') // Korean uses 월, never the Han 月
expect(formatMessageTimestamp(now - 5 * 60_000, t('kr'), 'kr', now)).toBe('5분 전')
})
})