このコミットが含まれているのは:
@@ -35,6 +35,17 @@ export const localeFromPath = (pathname: string): LocaleCode | null => {
|
||||
}
|
||||
|
||||
|
||||
export const resolveViewingLocale = (
|
||||
pathname: string,
|
||||
routeLocale?: unknown,
|
||||
): LocaleCode =>
|
||||
isLocaleCode (routeLocale) ? routeLocale : localeFromPath (pathname) ?? 'ja'
|
||||
|
||||
|
||||
export const currentViewingLocale = (): LocaleCode =>
|
||||
resolveViewingLocale (typeof window === 'undefined' ? '' : window.location.pathname)
|
||||
|
||||
|
||||
export const unlocalisedPath = (pathname: string): string => {
|
||||
const locale = localeFromPath (pathname)
|
||||
return locale == null ? pathname : pathname.slice (locale.length + 1) || '/'
|
||||
|
||||
@@ -118,8 +118,9 @@ const prefetchWikiPageShow: Prefetcher = async (qc, url, locale) => {
|
||||
|
||||
if (wikiPage?.body)
|
||||
{
|
||||
const language = wikiPage.languageCode
|
||||
const contentLanguage = wikiPage.languageCode
|
||||
?? (wikiPage.resourceType === 'tag_description' ? localeLanguage (locale) : 'und')
|
||||
const language = contentLanguage === 'und' ? 'ja' : contentLanguage
|
||||
await qc.prefetchQuery ({
|
||||
queryKey: wikiKeys.autolinkCandidates (language, locale),
|
||||
queryFn: () => fetchWikiAutolinkCandidates (language, locale) })
|
||||
|
||||
@@ -60,11 +60,11 @@ export const tagsKeys = {
|
||||
nicoIndex: (
|
||||
p: FetchNicoTagsParams,
|
||||
locale: LocaleCode = 'ja',
|
||||
) => ['tags', locale, 'nico', 'index', p] as const,
|
||||
) => ['tags', 'nico', locale, 'index', p] as const,
|
||||
externalShow: (
|
||||
id: string,
|
||||
locale: LocaleCode = 'ja',
|
||||
) => ['tags', locale, 'nico', id] as const,
|
||||
) => ['tags', 'nico', locale, id] as const,
|
||||
show: (
|
||||
name: string,
|
||||
locale: LocaleCode = 'ja',
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import type { Content, Parent, Root, RootContent } from 'mdast'
|
||||
|
||||
import type { WikiAutolinkCandidate } from '@/types'
|
||||
import type { LocaleCode } from '@/lib/locales'
|
||||
|
||||
const escapeForRegExp = (s: string) => s.replace (/[.*+?^${}()|[\]\\]/g, '\\$&')
|
||||
|
||||
@@ -34,12 +35,14 @@ const edgeCharacter = (node: Content, first: boolean): string => {
|
||||
const remarkWikiAutoLink = (
|
||||
candidates: WikiAutolinkCandidate[],
|
||||
language: string,
|
||||
locale: LocaleCode,
|
||||
): ((tree: Root) => void) => {
|
||||
const targets = new Map<string, WikiAutolinkCandidate> ()
|
||||
const ambiguous = new Set<string> ()
|
||||
for (const candidate of candidates)
|
||||
{
|
||||
if (candidate.languageCode !== language || candidate.name.length === 0)
|
||||
if (candidate.languageCode !== language || candidate.localeCode !== locale
|
||||
|| candidate.name.length === 0)
|
||||
continue
|
||||
const previous = targets.get (candidate.name)
|
||||
if (previous != null
|
||||
@@ -89,7 +92,7 @@ const remarkWikiAutoLink = (
|
||||
parts.push ({ type: 'text', value: value.slice (last, start) })
|
||||
parts.push ({
|
||||
type: 'link',
|
||||
url: `/${candidate.localeCode}/wiki/${encodeURIComponent (candidate.resourceId)}`,
|
||||
url: `/${locale}/wiki/${encodeURIComponent (candidate.resourceId)}`,
|
||||
title: null,
|
||||
children: [{ type: 'text', value: match[0] }],
|
||||
data: { hProperties: { 'data-wiki': '1' } } })
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { useCallback } from 'react'
|
||||
import { useLocation, useNavigate, useParams } from 'react-router-dom'
|
||||
|
||||
import { isLocaleCode, localeFromPath, localiseTo } from '@/lib/locales'
|
||||
import { localiseTo, resolveViewingLocale } from '@/lib/locales'
|
||||
|
||||
import type { NavigateFunction, NavigateOptions, To } from 'react-router-dom'
|
||||
|
||||
@@ -11,7 +11,7 @@ import type { LocaleCode } from '@/lib/locales'
|
||||
export const useLocale = (): LocaleCode => {
|
||||
const { locale } = useParams ()
|
||||
const location = useLocation ()
|
||||
return isLocaleCode (locale) ? locale : localeFromPath (location.pathname) ?? 'ja'
|
||||
return resolveViewingLocale (location.pathname, locale)
|
||||
}
|
||||
|
||||
|
||||
|
||||
+42
-25
@@ -2,6 +2,7 @@ import { clsx } from 'clsx'
|
||||
import { twMerge } from 'tailwind-merge'
|
||||
|
||||
import { i18n } from '@/lib/i18n'
|
||||
import { currentViewingLocale } from '@/lib/locales'
|
||||
|
||||
import type { ClassValue } from 'clsx'
|
||||
|
||||
@@ -14,37 +15,39 @@ 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',
|
||||
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 })
|
||||
|
||||
|
||||
export const localisedDateString = (
|
||||
value: string | Date,
|
||||
locale: LocaleCode,
|
||||
unknown: Parameters<typeof dateString>[1] = null,
|
||||
): string => {
|
||||
if (locale === 'ja')
|
||||
return dateString (value, unknown)
|
||||
|
||||
const date = toDate (value)
|
||||
if (Number.isNaN (date.getTime ()))
|
||||
return dateString (value, unknown)
|
||||
|
||||
const parts = new Intl.DateTimeFormat ('en-CA', {
|
||||
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',
|
||||
hour: '2-digit', minute: '2-digit', second: '2-digit',
|
||||
hourCycle: 'h23' }).formatToParts (date)
|
||||
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'),
|
||||
@@ -60,6 +63,20 @@ export const localisedDateString = (
|
||||
}
|
||||
|
||||
|
||||
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,
|
||||
|
||||
新しいイシューから参照
ユーザーをブロックする