You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
svelte-kit-vice/src/arts/sium/engine-resolver.ts

101 lines
3.4 KiB

import {
LANG_ID_FALLBACK_SEPARATOR,
parseLangRef,
type LangParams,
type SupportedLocale
} from '$libs/langs';
import type { EngineLangs } from '$langs';
import { SIUM_DIAGNOSTIC_EVENTS } from './consts';
import { emitSiumDiagnostic, type SiumDiagnostics } from './diagnostics';
import { resolve as resolveFallbackTemplate } from './langs';
import type { Issue } from './core';
export interface SiumResolver {
readonly resolve: (message: string, params?: LangParams, locale?: SupportedLocale) => string;
readonly resolveIssue: (issue: Issue, locale?: SupportedLocale) => string;
readonly resolveIssues: (issues: ReadonlyArray<Issue>, locale?: SupportedLocale) => string[];
}
/**
* Duck-typed shape: when Sium is wired to `ActiveLangs` (which exposes a
* runtime `getLocale()`), the resolver follows the active locale lazily.
* `EngineLangs` does not expose this getter, so consumers wired to the
* pure engine still use the captured construction-time default.
*/
interface ActiveLocaleSource {
readonly getLocale: () => SupportedLocale;
}
interface SiumResolverOptions {
readonly langs?: EngineLangs;
/**
* Locale used when neither the caller passes one nor `langs.getLocale`
* exists. When `langs` is wired through `ActiveLangs`, the resolver
* reads `langs.getLocale()` on every call so a runtime
* `Lang.setLocale(...)` takes effect immediately.
*/
readonly defaultLocale: SupportedLocale;
readonly diagnostics: SiumDiagnostics;
}
function hasActiveLocaleSource(
langs: EngineLangs | undefined
): langs is EngineLangs & ActiveLocaleSource {
return (
langs !== undefined &&
typeof (langs as Partial<ActiveLocaleSource>).getLocale === 'function'
);
}
function composeLangPath(message: string): string | undefined {
const parsed = parseLangRef(message);
if (parsed === null) return undefined;
if (parsed.fallback === undefined) return parsed.path;
return `${parsed.path}${LANG_ID_FALLBACK_SEPARATOR}${parsed.fallback}`;
}
function fallbackMessage(message: string, params?: LangParams): string {
const parsed = parseLangRef(message);
return resolveFallbackTemplate(parsed?.fallback ?? parsed?.path ?? message, params);
}
export function createSiumResolver(options: SiumResolverOptions): SiumResolver {
const { langs, defaultLocale, diagnostics } = options;
function effectiveLocale(explicit: SupportedLocale | undefined): SupportedLocale {
if (explicit !== undefined) return explicit;
// Read langs' current locale lazily when available so a runtime
// `setLocale()` is honored. EngineLangs has no `getLocale()`; for
// that path we fall back to the construction-time default.
if (hasActiveLocaleSource(langs)) return langs.getLocale();
return defaultLocale;
}
const resolve: SiumResolver['resolve'] = (message, params, locale) => {
const langPath = composeLangPath(message);
if (langs === undefined || langPath === undefined) {
return fallbackMessage(message, params);
}
try {
return langs.t(langPath, params, effectiveLocale(locale));
} catch (error) {
emitSiumDiagnostic(diagnostics, SIUM_DIAGNOSTIC_EVENTS.RESOLVE_FALLBACK, {
message,
error
});
return fallbackMessage(message, params);
}
};
const resolveIssue: SiumResolver['resolveIssue'] = (entry, locale) => {
return resolve(entry.message, entry.params, locale);
};
const resolveIssues: SiumResolver['resolveIssues'] = (issues, locale) => {
return issues.map((entry) => resolveIssue(entry, locale));
};
return { resolve, resolveIssue, resolveIssues };
}

Powered by TurnKey Linux.