test(ci): add exporter heading levels and a11y typography smoke; update MAIN_PLAN

This commit is contained in:
2025-11-14 16:40:45 +09:00
parent aaa624a046
commit a9bbc357e7
92 changed files with 8370 additions and 13 deletions
+8
View File
@@ -0,0 +1,8 @@
import 'server-only'
import { locales, type AppLocale } from '@/lib/i18n/locales'
export async function getMessages(locale: AppLocale) {
const loc = locales.includes(locale) ? locale : 'en'
const messages = (await import(`@/messages/${loc}.json`)).default
return messages as Record<string, string>
}
+25
View File
@@ -0,0 +1,25 @@
import { describe, it, expect } from 'vitest'
import { createI18n } from '@/lib/i18n'
describe('i18n util', () => {
const i18n = createI18n({
defaultLocale: 'en',
messages: {
en: { hello: 'Hello {name}', onlyEn: 'Only EN' },
ko: { hello: '안녕하세요 {name}' },
},
})
it('로케일별 번역과 변수 치환을 지원한다', () => {
expect(i18n.t('en', 'hello', { name: 'Jay' })).toBe('Hello Jay')
expect(i18n.t('ko', 'hello', { name: '제이' })).toBe('안녕하세요 제이')
})
it('키가 없으면 기본 로케일로 폴백한다', () => {
expect(i18n.t('ko', 'onlyEn')).toBe('Only EN')
})
it('완전히 없는 키는 키 그대로 반환한다', () => {
expect(i18n.t('en', 'missing.key')).toBe('missing.key')
})
})
+23
View File
@@ -0,0 +1,23 @@
type Messages = Record<string, Record<string, string>>
export function createI18n({ defaultLocale, messages }: { defaultLocale: string; messages: Messages }) {
function format(template: string, params?: Record<string, string | number>) {
if (!params) return template
return template.replace(/\{(\w+)\}/g, (_, k) => (params[k] !== undefined ? String(params[k]) : `{${k}}`))
}
function getMessage(locale: string, key: string): string | undefined {
const m = messages[locale] || {}
if (m[key] !== undefined) return m[key]
const base = messages[defaultLocale] || {}
return base[key]
}
function t(locale: string, key: string, params?: Record<string, string | number>): string {
const msg = getMessage(locale, key)
if (typeof msg === 'string') return format(msg, params)
return key
}
return { t }
}
+3
View File
@@ -0,0 +1,3 @@
export const locales = ['en', 'ko'] as const
export type AppLocale = typeof locales[number]
export const defaultLocale: AppLocale = 'en'