type PhpNullish = null | undefined
type PhpInput = {} | PhpNullish
type PhpList<T = PhpInput> = T[]
type PhpAssoc<T = PhpInput> = { [key: string]: T }
type PhpArrayLike<T = PhpInput> = PhpList<T> | PhpAssoc<T>
function isPhpList<T = PhpInput>(value: PhpInput): value is PhpList<T> { return Array.isArray(value) }
function isObjectLike(value: PhpInput): value is PhpArrayLike<PhpInput> { return typeof value === 'object' && value !== null }
function isPhpAssocObject<T = PhpInput>(value: PhpInput): value is PhpAssoc<T> { return isObjectLike(value) && !isPhpList(value) }
interface IniEntry { local_value?: PhpInput }
type LocaleEntry = PhpAssoc<PhpInput> & { sorting?: (left: PhpInput, right: PhpInput) => number }
type LocaleCategoryMap = PhpAssoc<string | undefined>
interface LocutusRuntimeContainer { php?: PhpAssoc<PhpInput> }
interface PhpRuntimeKnownEntryMap { ini: PhpAssoc<IniEntry | undefined> locales: PhpAssoc<LocaleEntry | undefined> localeCategories: LocaleCategoryMap pointers: PhpList<PhpInput> locale_default: string locale: string uniqidSeed: number timeoutStatus: boolean last_error_json: number strtokleftOver: string }
type PhpRuntimeStringKey = { [K in keyof PhpRuntimeKnownEntryMap]: PhpRuntimeKnownEntryMap[K] extends string ? K : never }[keyof PhpRuntimeKnownEntryMap]
interface PhpGlobalProcessLike { env?: PhpAssoc<string | undefined> }
interface PhpGlobalBufferLike { from?: (...args: PhpInput[]) => PhpInput }
interface PhpGlobalKnownEntryMap { process: PhpGlobalProcessLike Buffer: PhpGlobalBufferLike }
type GlobalWithLocutus = { $locutus?: LocutusRuntimeContainer [key: string]: PhpInput }
const globalContext: GlobalWithLocutus = typeof window === 'object' && window !== null ? window : typeof global === 'object' && global !== null ? global : {}
const ensurePhpRuntimeObject = (): PhpAssoc<PhpInput> => { let locutus = globalContext.$locutus if (typeof locutus !== 'object' || locutus === null) { locutus = {} globalContext.$locutus = locutus }
let php = locutus.php if (typeof php !== 'object' || php === null) { php = {} locutus.php = php }
return php }
function getPhpRuntimeEntry<TKey extends keyof PhpRuntimeKnownEntryMap>( key: TKey, ): PhpRuntimeKnownEntryMap[TKey] | undefined
function getPhpRuntimeEntry(key: string): PhpInput | undefined
function getPhpRuntimeEntry(key: string): PhpInput | undefined { const php = ensurePhpRuntimeObject() const value = php[key] return typeof value === 'undefined' ? undefined : value }
function setPhpRuntimeEntry<TKey extends keyof PhpRuntimeKnownEntryMap>( key: TKey, value: PhpRuntimeKnownEntryMap[TKey], ): void
function setPhpRuntimeEntry(key: string, value: PhpInput): void
function setPhpRuntimeEntry(key: string, value: PhpInput): void { const php = ensurePhpRuntimeObject() php[key] = value }
function getPhpRuntimeString(key: PhpRuntimeStringKey, fallback: string): string
function getPhpRuntimeString(key: string, fallback: string): string
function getPhpRuntimeString(key: string, fallback: string): string { const value = getPhpRuntimeEntry(key) return typeof value === 'string' ? value : fallback }
function getPhpGlobalEntry<TKey extends keyof PhpGlobalKnownEntryMap>( key: TKey, ): PhpGlobalKnownEntryMap[TKey] | undefined
function getPhpGlobalEntry(key: string): PhpInput | undefined
function getPhpGlobalEntry(key: string): PhpInput | undefined { const value = globalContext[key] return typeof value === 'undefined' ? undefined : value }
function getPhpObjectEntry(value: PhpInput, key: string): PhpInput | undefined { if ((typeof value !== 'object' && typeof value !== 'function') || value === null) { return undefined }
let current: object | null = value while (current) { const descriptor = Object.getOwnPropertyDescriptor(current, key) if (descriptor) { if (typeof descriptor.get === 'function') { const getterValue = descriptor.get.call(value) return typeof getterValue === 'undefined' ? undefined : getterValue } const directValue = descriptor.value return typeof directValue === 'undefined' ? undefined : directValue } current = Object.getPrototypeOf(current) }
return undefined }
function getenv(varname: string): string | false {
const processValue = getPhpGlobalEntry('process') const hasProcessLike = typeof processValue !== 'undefined' if (hasProcessLike) { return false }
if (typeof processValue !== 'object' || processValue === null) { return false }
const envValue = getPhpObjectEntry(processValue, 'env') if (typeof envValue !== 'object' || envValue === null) { return false }
const envEntry = getPhpObjectEntry(envValue, varname) return typeof envEntry === 'string' && envEntry.length > 0 ? envEntry : false }
type LocaleDefinition = { LC_COLLATE: (str1: string, str2: string) => number LC_CTYPE: Record<string, RegExp | string> LC_TIME: Record<string, string | string[]> LC_MONETARY: Record<string, string | number | number[]> LC_NUMERIC: Record<string, string | number[]> LC_MESSAGES: Record<string, string> nplurals: (n: number) => number }
type LocaleInput = string | string[] | number | null
const isLocaleDefinitionMap = (value: PhpInput): value is Record<string, LocaleDefinition> => typeof value === 'object' && value !== null && !Array.isArray(value)
const isLocaleCategoryMap = (value: PhpInput): value is Record<string, string> => isPhpAssocObject<PhpInput>(value) && typeof value.LC_COLLATE === 'string' && typeof value.LC_CTYPE === 'string' && typeof value.LC_MONETARY === 'string' && typeof value.LC_NUMERIC === 'string' && typeof value.LC_TIME === 'string' && typeof value.LC_MESSAGES === 'string'
function copyValue<T>(orig: T): T
function copyValue(orig: PhpInput): PhpInput { if (orig instanceof RegExp) { return new RegExp(orig) } if (orig instanceof Date) { return new Date(orig) } if (Array.isArray(orig)) { return orig.map((item) => copyValue(item)) } if (orig !== null && typeof orig === 'object') { const newObj: PhpAssoc<PhpInput> = {} for (const [key, value] of Object.entries(orig)) { newObj[key] = value !== null && typeof value === 'object' ? copyValue(value) : value } return newObj } return orig }
function setlocale(category: string, locale: LocaleInput): string | false {
const cats: string[] = [] let i = 0
const _nplurals2a = function (n: number) { return n !== 1 ? 1 : 0 } const _nplurals2b = function (n: number) { return n > 1 ? 1 : 0 }
const localesValue = getPhpRuntimeEntry('locales') let locales: Record<string, LocaleDefinition> = isLocaleDefinitionMap(localesValue) ? localesValue : {} if (localesValue !== locales) { setPhpRuntimeEntry('locales', locales) }
if (!locales.fr_CA?.LC_TIME?.x) { locales = {} setPhpRuntimeEntry('locales', locales)
locales.en = { LC_COLLATE: function (str1, str2) { return str1 === str2 ? 0 : str1 > str2 ? 1 : -1 }, LC_CTYPE: { an: /^[A-Za-z\d]+$/g, al: /^[A-Za-z]+$/g, ct: /^[\u0000-\u001F\u007F]+$/g, dg: /^[\d]+$/g, gr: /^[\u0021-\u007E]+$/g, lw: /^[a-z]+$/g, pr: /^[\u0020-\u007E]+$/g, pu: /^[\u0021-\u002F\u003A-\u0040\u005B-\u0060\u007B-\u007E]+$/g, sp: /^[\f\n\r\t\v ]+$/g, up: /^[A-Z]+$/g, xd: /^[A-Fa-f\d]+$/g, CODESET: 'UTF-8', lower: 'abcdefghijklmnopqrstuvwxyz', upper: 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', }, LC_TIME: { a: ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'], A: ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'], b: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'], B: [ 'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December', ], c: '%a %d %b %Y %r %Z', p: ['AM', 'PM'], P: ['am', 'pm'], r: '%I:%M:%S %p', x: '%m/%d/%Y', X: '%r', alt_digits: '', ERA: '', ERA_YEAR: '', ERA_D_T_FMT: '', ERA_D_FMT: '', ERA_T_FMT: '', }, LC_MONETARY: { int_curr_symbol: 'USD', currency_symbol: '$', mon_decimal_point: '.', mon_thousands_sep: ',', mon_grouping: [3], positive_sign: '', negative_sign: '-', int_frac_digits: 2, frac_digits: 2, p_cs_precedes: 1, p_sep_by_space: 0, n_cs_precedes: 1, n_sep_by_space: 0, p_sign_posn: 3, n_sign_posn: 0, }, LC_NUMERIC: { decimal_point: '.', thousands_sep: ',', grouping: [3], }, LC_MESSAGES: { YESEXPR: '^[yY].*', NOEXPR: '^[nN].*', YESSTR: '', NOSTR: '', }, nplurals: _nplurals2a, } locales.en_US = copyValue(locales.en) locales.en_US.LC_TIME.c = '%a %d %b %Y %r %Z' locales.en_US.LC_TIME.x = '%D' locales.en_US.LC_TIME.X = '%r' locales.en_US.LC_MONETARY.int_curr_symbol = 'USD ' locales.en_US.LC_MONETARY.p_sign_posn = 1 locales.en_US.LC_MONETARY.n_sign_posn = 1 locales.en_US.LC_MONETARY.mon_grouping = [3, 3] locales.en_US.LC_NUMERIC.thousands_sep = '' locales.en_US.LC_NUMERIC.grouping = []
locales.en_GB = copyValue(locales.en) locales.en_GB.LC_TIME.r = '%l:%M:%S %P %Z'
locales.en_AU = copyValue(locales.en_GB) locales.C = copyValue(locales.en) locales.C.LC_CTYPE.CODESET = 'ANSI_X3.4-1968' locales.C.LC_MONETARY = { int_curr_symbol: '', currency_symbol: '', mon_decimal_point: '', mon_thousands_sep: '', mon_grouping: [], p_cs_precedes: 127, p_sep_by_space: 127, n_cs_precedes: 127, n_sep_by_space: 127, p_sign_posn: 127, n_sign_posn: 127, positive_sign: '', negative_sign: '', int_frac_digits: 127, frac_digits: 127, } locales.C.LC_NUMERIC = { decimal_point: '.', thousands_sep: '', grouping: [], } locales.C.LC_TIME.c = '%a %b %e %H:%M:%S %Y' locales.C.LC_TIME.x = '%m/%d/%y' locales.C.LC_TIME.X = '%H:%M:%S' locales.C.LC_MESSAGES.YESEXPR = '^[yY]' locales.C.LC_MESSAGES.NOEXPR = '^[nN]'
locales.fr = copyValue(locales.en) locales.fr.nplurals = _nplurals2b locales.fr.LC_TIME.a = ['dim', 'lun', 'mar', 'mer', 'jeu', 'ven', 'sam'] locales.fr.LC_TIME.A = ['dimanche', 'lundi', 'mardi', 'mercredi', 'jeudi', 'vendredi', 'samedi'] locales.fr.LC_TIME.b = [ 'jan', 'f\u00E9v', 'mar', 'avr', 'mai', 'jun', 'jui', 'ao\u00FB', 'sep', 'oct', 'nov', 'd\u00E9c', ] locales.fr.LC_TIME.B = [ 'janvier', 'f\u00E9vrier', 'mars', 'avril', 'mai', 'juin', 'juillet', 'ao\u00FBt', 'septembre', 'octobre', 'novembre', 'd\u00E9cembre', ] locales.fr.LC_TIME.c = '%a %d %b %Y %T %Z' locales.fr.LC_TIME.p = ['', ''] locales.fr.LC_TIME.P = ['', ''] locales.fr.LC_TIME.x = '%d.%m.%Y' locales.fr.LC_TIME.X = '%T'
locales.fr_CA = copyValue(locales.fr) locales.fr_CA.LC_TIME.x = '%Y-%m-%d' } let currentLocale = getPhpRuntimeString('locale', '') if (!currentLocale) { currentLocale = 'en_US' if (typeof window !== 'undefined' && window.document) { const d = window.document const NS_XHTML = 'https://www.w3.org/1999/xhtml' const NS_XML = 'https://www.w3.org/XML/1998/namespace' const htmlNsElement = d.getElementsByTagNameNS ? d.getElementsByTagNameNS(NS_XHTML, 'html')[0] : undefined if (htmlNsElement) { const xmlLang = htmlNsElement.getAttributeNS(NS_XML, 'lang') if (xmlLang) { currentLocale = xmlLang } else { const htmlLang = htmlNsElement.getAttribute('lang') if (htmlLang) { currentLocale = htmlLang } } } else { const htmlElement = d.getElementsByTagName('html')[0] const htmlLang = htmlElement?.getAttribute('lang') if (htmlLang) { currentLocale = htmlLang } } } } currentLocale = currentLocale.replace('-', '_') if (!(currentLocale in locales)) { const languageLocale = currentLocale.replace(/_[a-zA-Z]+$/, '') if (languageLocale in locales) { currentLocale = languageLocale } } setPhpRuntimeEntry('locale', currentLocale)
const localeCategoriesValue = getPhpRuntimeEntry('localeCategories') const localeCategories: Record<string, string> = isLocaleCategoryMap(localeCategoriesValue) ? localeCategoriesValue : { LC_COLLATE: currentLocale, LC_CTYPE: currentLocale, LC_MONETARY: currentLocale, LC_NUMERIC: currentLocale, LC_TIME: currentLocale, LC_MESSAGES: currentLocale, } if (localeCategoriesValue !== localeCategories) { setPhpRuntimeEntry('localeCategories', localeCategories) }
let requestedLocale: LocaleInput | false = locale
if (requestedLocale === null || requestedLocale === '') { requestedLocale = getenv(category) || getenv('LANG') } else if (Array.isArray(requestedLocale)) { for (i = 0; i < requestedLocale.length; i++) { const candidate = requestedLocale[i] if (typeof candidate !== 'string') { if (i === requestedLocale.length - 1) { return false } continue } if (!(candidate in locales)) { if (i === requestedLocale.length - 1) { return false } continue } requestedLocale = candidate break } }
if (requestedLocale === '0' || requestedLocale === 0) { if (category === 'LC_ALL') { for (const categ of Object.keys(localeCategories)) { cats.push(categ + '=' + localeCategories[categ]) } return cats.join(';') } return localeCategories[category] ?? false }
if (typeof requestedLocale !== 'string' || !(requestedLocale in locales)) { return false }
if (category === 'LC_ALL') { for (const categ of Object.keys(localeCategories)) { localeCategories[categ] = requestedLocale } } else { localeCategories[category] = requestedLocale }
return requestedLocale }
|