アイヌ語追加 (#428) (#433)

Reviewed-on: #433
Co-authored-by: miteruzo <miteruzo@naver.com>
このコミットはプルリクエスト #433 でマージされました。
このコミットが含まれているのは:
2026-10-20 20:44:14 +09:00
committed by みてるぞ
コミット 084a090cab
294個のファイルの変更、13978行の追加、3461行の削除
+79 -19
ファイルの表示
@@ -1,8 +1,13 @@
import { clsx } from 'clsx'
import { twMerge } from 'tailwind-merge'
import { i18n } from '@/lib/i18n'
import { currentViewingLocale } from '@/lib/locales'
import type { ClassValue } from 'clsx'
import type { LocaleCode } from '@/lib/locales'
export const toDate = (d: string | Date): Date => typeof d === 'string' ? new Date (d) : d
@@ -10,64 +15,119 @@ export const toDate = (d: string | Date): Date => typeof d === 'string' ? new Da
export const cn = (...inputs: ClassValue[]) => twMerge (clsx (...inputs))
export const dateString = (
d: string | Date,
unknown: 'month' | 'day' | 'hour' | 'minute' | 'second' | null = null): string =>
toDate (d).toLocaleString (
'ja-JP-u-ca-japanese',
{ era: 'long',
year: 'numeric',
month: (unknown === 'month' ? undefined : 'long'),
type DatePrecision = 'month' | 'day' | 'hour' | 'minute' | 'second' | null
const dateFormatters = new Map<DatePrecision, Intl.DateTimeFormat> ()
let ainuDateFormatter: Intl.DateTimeFormat | null = null
const formatDateString = (
date: Date,
unknown: DatePrecision,
locale: LocaleCode,
): string => {
if (Number.isNaN (date.getTime ()))
return date.toString ()
if (locale === 'ja')
{
if (!dateFormatters.has (unknown))
{
dateFormatters.set (unknown, new Intl.DateTimeFormat ('ja-JP-u-ca-japanese', {
era: 'long', year: 'numeric',
timeZone: 'Asia/Tokyo',
month: unknown === 'month' ? undefined : 'long',
day: unknown != null && ['month', 'day'].includes (unknown) ? undefined : 'numeric',
weekday: unknown != null && ['month', 'day'].includes (unknown) ? undefined : 'short',
hour: unknown == null || ['second', 'minute'].includes (unknown) ? 'numeric' : undefined,
minute: unknown == null || unknown === 'second' ? 'numeric' : undefined,
second: unknown == null ? 'numeric' : undefined })
second: unknown == null ? 'numeric' : undefined }))
}
return dateFormatters.get (unknown)!.format (date)
}
ainuDateFormatter ??= new Intl.DateTimeFormat ('en-CA', {
year: 'numeric', month: '2-digit', day: '2-digit',
timeZone: 'Asia/Tokyo',
hour: '2-digit', minute: '2-digit', second: '2-digit',
hourCycle: 'h23' })
const parts = ainuDateFormatter.formatToParts (date)
const part = (type: string) => parts.find (entry => entry.type === type)?.value ?? ''
const omitDay = unknown != null && ['month', 'day'].includes (unknown)
const dateParts = [part ('year'),
...(unknown === 'month' ? [] : [part ('month')]),
...(omitDay ? [] : [part ('day')])]
const dateText = dateParts.join ('-')
if (unknown != null && ['month', 'day', 'hour'].includes (unknown))
return dateText
const timeParts = [part ('hour'),
...(unknown === 'minute' ? [] : [part ('minute')]),
...(unknown == null ? [part ('second')] : [])]
return `${dateText}\u3000${timeParts.join (':')}`
}
export const dateString = (
value: string | Date,
unknown: DatePrecision = null,
locale?: LocaleCode,
): string => formatDateString (toDate (value), unknown, locale ?? currentViewingLocale ())
export const localisedDateString = (
value: string | Date,
locale: LocaleCode,
unknown: DatePrecision = null,
): string => dateString (value, unknown, locale)
export const originalCreatedAtString = (
f: string | Date | null,
b: string | Date | null): string => {
b: string | Date | null,
locale: LocaleCode = 'ja',
): string => {
const from = f ? toDate (f) : null
const before = b ? toDate (b) : null
const format = (value: Date, unknown: Parameters<typeof dateString>[1]) =>
localisedDateString (value, locale, unknown)
const unknownLabel = (key: string) => i18n.t (`history:${key}`, { lng: locale })
const space = locale === 'ja' ? ' ' : '\u3000'
if (from && before)
{
const diff = before.getTime () - from.getTime ()
if (diff <= 60_000 /* 1 分 */)
return dateString (from, 'second')
return format (from, 'second')
if (from.getMinutes () === 0 && before.getMinutes () === 0)
{
if (Math.abs (diff - 3_600_000 /* 1 時間 */) < 60_000)
return dateString (from, 'minute') + ' (分不詳)'
return `${format (from, 'minute')}${space}(${unknownLabel ('unknownMinute')})`
if (from.getHours () === 0 && before.getHours () === 0)
{
if (Math.abs (diff - 86_400_000 /* 1 日 */) < 60_000)
return dateString (from, 'hour') + ' (時刻不詳)'
return `${format (from, 'hour')}${space}(${unknownLabel ('unknownTime')})`
if (from.getDate () === 1 && before.getDate () === 1)
{
if (2_332_800_000 /* 27 日 */ < diff && diff < 2_764_800_000 /* 32 日 */)
return dateString (from, 'day') + ' (日不詳)'
return `${format (from, 'day')}${space}(${unknownLabel ('unknownDay')})`
if (from.getMonth () === 0 && before.getMonth () === 0
&& (31_449_600_000 /* 364 日 */ <= diff
&& diff < 31_708_800_000 /* 367 日 */))
return dateString (from, 'month') + ' (月日不詳)'
return `${format (from, 'month')}${space}(${unknownLabel ('unknownMonthDay')})`
}
}
}
}
const rtn = ([from ? `${ dateString (from, 'second') }` : '',
const rtn = ([from ? format (from, 'second') : '',
'〜',
before ? `${ dateString (new Date (before.getTime () - 60_000), 'second') }` : '']
before ? format (new Date (before.getTime () - 60_000), 'second') : '']
.filter (Boolean)
.join (' '))
return rtn === '〜' ? '年月日不詳' : rtn
.join (space))
return rtn === '〜' ? unknownLabel ('unknownDate') : rtn
}