import type { I18nString } from '@pikku/react' import arMessages from '../messages/ar.json' import bsMessages from '../messages/bs.json' import deMessages from '../messages/de.json' import enMessages from '../messages/en.json' import esMessages from '../messages/es.json' import filMessages from '../messages/fil.json' import hiMessages from '../messages/hi.json' import sqMessages from '../messages/sq.json' import trMessages from '../messages/tr.json' import ukMessages from '../messages/uk.json' import viMessages from '../messages/vi.json' import { defaultLocale, getLocale, maskI18n, type Locale } from './config' import { identOf } from './ident' type MessageCatalog = Record type MessageArgs = Record type MessageFn = (args?: MessageArgs) => I18nString const catalogs: Record = { ar: arMessages as MessageCatalog, bs: bsMessages as MessageCatalog, de: deMessages as MessageCatalog, en: enMessages as MessageCatalog, es: esMessages as MessageCatalog, fil: filMessages as MessageCatalog, hi: hiMessages as MessageCatalog, sq: sqMessages as MessageCatalog, tr: trMessages as MessageCatalog, uk: ukMessages as MessageCatalog, vi: viMessages as MessageCatalog, } const interpolate = (template: string, args?: MessageArgs) => template.replace(/\{\{\s*([\w.]+)\s*\}\}/g, (_match, key: string) => { const value = args?.[key] return value === undefined || value === null ? '' : String(value) }) const getMessageValue = (key: string, locale = getLocale()) => catalogs[locale]?.[key] ?? catalogs[defaultLocale]?.[key] const toI18n = (value: string) => maskI18n(value) as unknown as I18nString const parseListValue = (value: string): string[] => { try { const parsed = JSON.parse(value) as unknown if (Array.isArray(parsed)) { return parsed.map((item) => String(item)) } } catch { // Fall through to a permissive parser for malformed copied JSON. } return value .replace(/^\s*\[/, '') .replace(/\]\s*$/, '') .split(/","|"،\s*"|»,\s*«|",\s*"/) .map((item) => item.replace(/^["«\s]+|["»\s]+$/g, '').trim()) .filter(Boolean) } const getIndexedList = (keyPrefix: string): string[] => { const values: string[] = [] for (let index = 0; ; index += 1) { const value = getMessageValue(`${keyPrefix}_${index}`) if (!value) { break } values.push(value) } return values } export const mKey = (key: string, args?: MessageArgs): I18nString => { const value = getMessageValue(identOf(key)) if (!value) { if (typeof console !== 'undefined') { console.warn(`[i18n] missing message for key "${key}"`) } return toI18n(key) } return toI18n(interpolate(value, args)) } // Plain-string resolution in an explicit locale (no active-locale store). // For server-side, locale-parameterized text like SEO meta tags. export const mTextIn = ( locale: Locale, key: string, args?: MessageArgs, ): string => { const value = getMessageValue(identOf(key), locale) return value ? interpolate(value, args) : key } export const mList = (keyPrefix: string, args?: MessageArgs): I18nString[] => { const ident = identOf(keyPrefix) const indexedValues = getIndexedList(ident) const values = indexedValues.length > 0 ? indexedValues : (() => { const exactValue = getMessageValue(ident) return exactValue ? parseListValue(exactValue) : [] })() return values.map((value) => toI18n(interpolate(value, args))) } export const m = new Proxy( {}, { get: (_target, property) => { if (typeof property !== 'string') { return undefined } const fn: MessageFn = (args) => { const value = getMessageValue(property) return toI18n(interpolate(value ?? property, args)) } return fn }, }, ) as Record