mirror of
https://github.com/goauthentik/authentik.git
synced 2026-06-17 19:09:11 +03:00
web/i18n: Fix stale flow locale, unsynchronized locale selector options (cherry-pick #23007 to version-2026.5) (#23148)
web/i18n: Fix stale flow locale, unsynchronized locale selector options (#23007) * Track local event, refresh on change. * Fix stale language selector value when switching between non-English entries. Co-authored-by: Teffen Ellis <592134+GirlBossRush@users.noreply.github.com>
This commit is contained in:
committed by
GitHub
parent
4b6482246b
commit
e95daf557a
@@ -196,6 +196,13 @@ export function formatLocaleDisplayNames(
|
||||
return entries.sort(createIntlCollator(activeLocaleTag, collatorOptions));
|
||||
}
|
||||
|
||||
/**
|
||||
* Format the display name for a single locale, using the same logic as the options list.
|
||||
*
|
||||
* @param languageTag The locale to format.
|
||||
* @param localizedDisplayName The localized display name for the locale
|
||||
* @param relativeDisplayName The relative display name for the locale.
|
||||
*/
|
||||
export function formatRelativeLocaleDisplayName(
|
||||
languageTag: TargetLanguageTag,
|
||||
localizedDisplayName: string,
|
||||
|
||||
@@ -3,6 +3,7 @@ import { formatLocaleDisplayNames } from "#common/ui/locale/format";
|
||||
import { setSessionLocale } from "#common/ui/locale/utils";
|
||||
|
||||
import { AKElement } from "#elements/Base";
|
||||
import { listen } from "#elements/decorators/listen";
|
||||
import Styles from "#elements/locale/ak-locale-select.css";
|
||||
import { LocaleOptions } from "#elements/locale/utils";
|
||||
import { WithCapabilitiesConfig } from "#elements/mixins/capabilities";
|
||||
@@ -12,8 +13,8 @@ import { CapabilitiesEnum } from "@goauthentik/api";
|
||||
|
||||
import { LOCALE_STATUS_EVENT, LocaleStatusEventDetail, msg } from "@lit/localize";
|
||||
import { html, PropertyValues } from "lit";
|
||||
import { guard } from "lit-html/directives/guard.js";
|
||||
import { customElement, state } from "lit/decorators.js";
|
||||
import { guard } from "lit/directives/guard.js";
|
||||
import { createRef, ref } from "lit/directives/ref.js";
|
||||
|
||||
@customElement("ak-locale-select")
|
||||
@@ -25,21 +26,52 @@ export class AKLocaleSelect extends WithLocale(WithCapabilitiesConfig(AKElement)
|
||||
|
||||
public static readonly styles = [Styles];
|
||||
|
||||
#previousActiveLanguageTag: TargetLanguageTag | null = null;
|
||||
|
||||
//#region Listeners
|
||||
|
||||
#localeChangeListener = (event: Event) => {
|
||||
/**
|
||||
* An event listener for when the user selects a different locale from the dropdown.
|
||||
*
|
||||
* Note that their choice may not be immediately reflected in the UI.
|
||||
*/
|
||||
protected localeChangeListener = (event: Event) => {
|
||||
const select = event.target as HTMLSelectElement;
|
||||
const locale = select.value as TargetLanguageTag;
|
||||
const nextActiveLanguageTag = select.value as TargetLanguageTag;
|
||||
|
||||
this.blur();
|
||||
|
||||
requestAnimationFrame(() => {
|
||||
this.activeLanguageTag = locale;
|
||||
setSessionLocale(locale);
|
||||
this.#previousActiveLanguageTag = this.activeLanguageTag;
|
||||
this.activeLanguageTag = nextActiveLanguageTag;
|
||||
|
||||
setSessionLocale(nextActiveLanguageTag);
|
||||
});
|
||||
};
|
||||
|
||||
#localeStatusListener = (event: CustomEvent<LocaleStatusEventDetail>) => {
|
||||
@listen(LOCALE_STATUS_EVENT, { target: window })
|
||||
protected localeStatusListener = (event: CustomEvent<LocaleStatusEventDetail>) => {
|
||||
if (!this.ready || event.detail.status !== "ready") {
|
||||
return;
|
||||
}
|
||||
|
||||
const { readyLocale } = event.detail;
|
||||
|
||||
this.requestUpdate(
|
||||
"activeLanguageTag",
|
||||
this.#previousActiveLanguageTag,
|
||||
undefined,
|
||||
true,
|
||||
readyLocale,
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* An event listener which only reacts to the locale being ready.
|
||||
* This is used to delay showing the select until the locale is loaded,
|
||||
* preventing a flash of unlocalized content and avoiding expensive localization operations during initial render.
|
||||
*/
|
||||
protected localeReadyStatusListener = (event: CustomEvent<LocaleStatusEventDetail>) => {
|
||||
if (event.detail.status !== "ready") {
|
||||
return;
|
||||
}
|
||||
@@ -90,7 +122,7 @@ export class AKLocaleSelect extends WithLocale(WithCapabilitiesConfig(AKElement)
|
||||
public override connectedCallback(): void {
|
||||
super.connectedCallback();
|
||||
|
||||
window.addEventListener(LOCALE_STATUS_EVENT, this.#localeStatusListener, {
|
||||
window.addEventListener(LOCALE_STATUS_EVENT, this.localeReadyStatusListener, {
|
||||
once: true,
|
||||
passive: true,
|
||||
});
|
||||
@@ -99,7 +131,7 @@ export class AKLocaleSelect extends WithLocale(WithCapabilitiesConfig(AKElement)
|
||||
public override disconnectedCallback(): void {
|
||||
super.disconnectedCallback();
|
||||
window.clearTimeout(this.#readyTimeout);
|
||||
window.removeEventListener(LOCALE_STATUS_EVENT, this.#localeStatusListener);
|
||||
window.removeEventListener(LOCALE_STATUS_EVENT, this.localeReadyStatusListener);
|
||||
}
|
||||
|
||||
public override firstUpdated(changed: PropertyValues<this>): void {
|
||||
@@ -108,7 +140,7 @@ export class AKLocaleSelect extends WithLocale(WithCapabilitiesConfig(AKElement)
|
||||
// Fallback to ready if the network is taking too long.
|
||||
this.#readyTimeout = window.setTimeout(() => {
|
||||
this.ready = true;
|
||||
window.removeEventListener(LOCALE_STATUS_EVENT, this.#localeStatusListener);
|
||||
window.removeEventListener(LOCALE_STATUS_EVENT, this.localeReadyStatusListener);
|
||||
}, 250);
|
||||
}
|
||||
|
||||
@@ -154,7 +186,7 @@ export class AKLocaleSelect extends WithLocale(WithCapabilitiesConfig(AKElement)
|
||||
${ref(this.#selectRef)}
|
||||
part="select"
|
||||
id="locale-selector"
|
||||
@change=${this.#localeChangeListener}
|
||||
@change=${this.localeChangeListener}
|
||||
class="ak-m-capitalize"
|
||||
name="locale"
|
||||
>
|
||||
|
||||
@@ -17,7 +17,7 @@ export interface LocaleOptionsProps {
|
||||
export const LocaleOptions: LitFC<LocaleOptionsProps> = ({ entries, activeLocaleTag }) => {
|
||||
return repeat(
|
||||
entries,
|
||||
([languageTag]) => languageTag,
|
||||
([languageTag]) => `${activeLocaleTag}-${languageTag}`,
|
||||
([languageTag, localizedDisplayName, relativeDisplayName]) => {
|
||||
const pseudo = languageTag === PseudoLanguageTag;
|
||||
|
||||
|
||||
@@ -38,6 +38,13 @@ export interface LocaleMixin {
|
||||
* The current locale language tag.
|
||||
*
|
||||
* @format BCP 47
|
||||
*
|
||||
* @remarks
|
||||
*
|
||||
* This may load asynchronously, which Lit will not know about.
|
||||
*
|
||||
* Use {@linkcode LOCALE_STATUS_EVENT} to listen for when the locale
|
||||
* is ready after setting a new language tag.
|
||||
*/
|
||||
activeLanguageTag: TargetLanguageTag;
|
||||
}
|
||||
|
||||
@@ -47,7 +47,7 @@ import {
|
||||
import { spread } from "@open-wc/lit-helpers";
|
||||
import { match, P } from "ts-pattern";
|
||||
|
||||
import { msg } from "@lit/localize";
|
||||
import { LOCALE_STATUS_EVENT, LocaleStatusEventDetail, msg } from "@lit/localize";
|
||||
import { CSSResult, html, nothing, PropertyValues } from "lit";
|
||||
import { customElement, property } from "lit/decorators.js";
|
||||
import { guard } from "lit/directives/guard.js";
|
||||
@@ -204,6 +204,13 @@ export class FlowExecutor extends WithBrandConfig(Interface) implements StageHos
|
||||
window.location.reload();
|
||||
};
|
||||
|
||||
@listen(LOCALE_STATUS_EVENT, { target: window })
|
||||
protected localeStatusListener = (event: CustomEvent<LocaleStatusEventDetail>) => {
|
||||
if (event.detail.status === "ready") {
|
||||
this.refresh();
|
||||
}
|
||||
};
|
||||
|
||||
private setFlowErrorChallenge(error: APIError) {
|
||||
this.challenge = {
|
||||
component: "ak-stage-flow-error",
|
||||
|
||||
Reference in New Issue
Block a user