Files
authentik/web/src/elements/ak-locale-context/ak-locale-context.ts
gcp-cherry-pick-bot[bot] f2a37e8c7c web/common: fix locale detection for user-set locale (cherry-pick #9436) (#9439)
web/common: fix locale detection for user-set locale (#9436)

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
Co-authored-by: Jens L <jens@goauthentik.io>
2024-04-25 22:37:56 +02:00

100 lines
3.6 KiB
TypeScript

import { EVENT_LOCALE_CHANGE, EVENT_LOCALE_REQUEST } from "@goauthentik/common/constants";
import { customEvent } from "@goauthentik/elements/utils/customEvents";
import { LitElement, html } from "lit";
import { customElement, property } from "lit/decorators.js";
import { WithBrandConfig } from "../Interface/brandProvider";
import { initializeLocalization } from "./configureLocale";
import type { LocaleGetter, LocaleSetter } from "./configureLocale";
import { DEFAULT_LOCALE, autoDetectLanguage, getBestMatchLocale } from "./helpers";
const LocaleContextBase = WithBrandConfig(LitElement);
/**
* A component to manage your locale settings.
*
* ## Details
*
* This component exists to take a locale setting from several different places, find the
* appropriate locale file in our catalog of locales, and set the lit-localization context
* appropriately. If that works, it sends off an event saying so.
*
* @element ak-locale-context
* @slot - The content which consumes this context
* @fires ak-locale-change - When a valid locale has been swapped in
*/
@customElement("ak-locale-context")
export class LocaleContext extends LocaleContextBase {
/// @attribute The text representation of the current locale */
@property({ attribute: true, type: String })
locale = DEFAULT_LOCALE;
/// @attribute The URL parameter to look for (if any)
@property({ attribute: true, type: String })
param = "locale";
getLocale: LocaleGetter;
setLocale: LocaleSetter;
constructor(code = DEFAULT_LOCALE) {
super();
this.notifyApplication = this.notifyApplication.bind(this);
this.updateLocaleHandler = this.updateLocaleHandler.bind(this);
try {
const [getLocale, setLocale] = initializeLocalization();
this.getLocale = getLocale;
this.setLocale = setLocale;
this.setLocale(code).then(() => {
window.setTimeout(this.notifyApplication, 0);
});
} catch (e) {
throw new Error(`Developer error: Must have only one locale context per session: ${e}`);
}
}
connectedCallback() {
super.connectedCallback();
this.updateLocale();
window.addEventListener(EVENT_LOCALE_REQUEST, this.updateLocaleHandler as EventListener);
}
disconnectedCallback() {
window.removeEventListener(EVENT_LOCALE_REQUEST, this.updateLocaleHandler as EventListener);
super.disconnectedCallback();
}
updateLocaleHandler(ev: CustomEvent<{ locale: string }>) {
console.debug("authentik/locale: Locale update request received.");
this.updateLocale(ev.detail.locale);
}
updateLocale(requestedLocale: string | undefined = undefined) {
const localeRequest = autoDetectLanguage(requestedLocale, this.brand?.defaultLocale);
const locale = getBestMatchLocale(localeRequest);
if (!locale) {
console.warn(`authentik/locale: failed to find locale for code ${localeRequest}`);
return;
}
locale.locale().then(() => {
console.debug(`Setting Locale to ... ${locale.label()} (${locale.code})`);
this.setLocale(locale.code).then(() => {
window.setTimeout(this.notifyApplication, 0);
});
});
}
notifyApplication() {
// You will almost never have cause to catch this event. Lit's own `@localized()` decorator
// works just fine for almost every use case.
this.dispatchEvent(customEvent(EVENT_LOCALE_CHANGE));
}
render() {
return html`<slot></slot>`;
}
}
export default LocaleContext;