diff --git a/web/src/admin/admin-overview/cards/SystemStatusCard.ts b/web/src/admin/admin-overview/cards/SystemStatusCard.ts index 5ff99b3a2..c82e6fcde 100644 --- a/web/src/admin/admin-overview/cards/SystemStatusCard.ts +++ b/web/src/admin/admin-overview/cards/SystemStatusCard.ts @@ -15,7 +15,6 @@ import { AdminApi, OutpostsApi, System } from "@goauthentik/api"; export class SystemStatusCard extends AdminStatusCard { now?: Date; - header = t`System status`; icon = "pf-icon pf-icon-server"; @state() @@ -82,6 +81,10 @@ export class SystemStatusCard extends AdminStatusCard { }); } + renderHeader(): TemplateResult { + return html`${t`System status`}`; + } + renderValue(): TemplateResult { return html`${this.statusSummary}`; } diff --git a/web/src/admin/admin-overview/cards/VersionStatusCard.ts b/web/src/admin/admin-overview/cards/VersionStatusCard.ts index c21b7bb8c..a2af888ad 100644 --- a/web/src/admin/admin-overview/cards/VersionStatusCard.ts +++ b/web/src/admin/admin-overview/cards/VersionStatusCard.ts @@ -13,7 +13,6 @@ import { AdminApi, Version } from "@goauthentik/api"; @customElement("ak-admin-status-version") export class VersionStatusCard extends AdminStatusCard { - header = t`Version`; headerLink = "https://goauthentik.io/docs/releases"; icon = "pf-icon pf-icon-bundle"; @@ -40,6 +39,10 @@ export class VersionStatusCard extends AdminStatusCard { }); } + renderHeader(): TemplateResult { + return html`${t`Version`}`; + } + renderValue(): TemplateResult { if (this.value?.buildHash) { return html` diff --git a/web/src/admin/admin-overview/cards/WorkerStatusCard.ts b/web/src/admin/admin-overview/cards/WorkerStatusCard.ts index 1740fd3a2..7981ff209 100644 --- a/web/src/admin/admin-overview/cards/WorkerStatusCard.ts +++ b/web/src/admin/admin-overview/cards/WorkerStatusCard.ts @@ -6,14 +6,13 @@ import { DEFAULT_CONFIG } from "@goauthentik/common/api/config"; import { t } from "@lingui/macro"; -import { html } from "lit"; +import { TemplateResult, html } from "lit"; import { customElement } from "lit/decorators.js"; import { AdminApi } from "@goauthentik/api"; @customElement("ak-admin-status-card-workers") export class WorkersStatusCard extends AdminStatusCard { - header = t`Workers`; icon = "pf-icon pf-icon-server"; getPrimaryValue(): Promise { @@ -22,6 +21,10 @@ export class WorkersStatusCard extends AdminStatusCard { }); } + renderHeader(): TemplateResult { + return html`${t`Workers`}`; + } + getStatus(value: number): Promise { if (value < 1) { return Promise.resolve({ diff --git a/web/src/common/ui/locale.ts b/web/src/common/ui/locale.ts index de3733de5..eb68cee97 100644 --- a/web/src/common/ui/locale.ts +++ b/web/src/common/ui/locale.ts @@ -1,9 +1,11 @@ import { EVENT_LOCALE_CHANGE } from "@goauthentik/common/constants"; import { globalAK } from "@goauthentik/common/global"; +import { messages as enLocale } from "@goauthentik/locales/en"; import { PluralCategory } from "make-plural"; +import { en } from "make-plural/plurals"; import { Messages, i18n } from "@lingui/core"; -import { detect, fromNavigator, fromUrl } from "@lingui/detect-locale"; +import { fromNavigator, fromUrl } from "@lingui/detect-locale"; import { t } from "@lingui/macro"; interface Locale { @@ -21,8 +23,8 @@ export const LOCALES: { label: t`English`, locale: async () => { return { - locale: (await import("@goauthentik/locales/en")).messages, - plurals: (await import("make-plural/plurals")).en, + locale: enLocale, + plurals: en, }; }, }, @@ -32,7 +34,7 @@ export const LOCALES: { locale: async () => { return { locale: (await import("@goauthentik/locales/pseudo-LOCALE")).messages, - plurals: (await import("make-plural/plurals")).en, + plurals: en, }; }, }, @@ -121,23 +123,35 @@ export const LOCALES: { const DEFAULT_FALLBACK = () => "en"; export function autoDetectLanguage() { - const detected = - detect( - () => { - return globalAK()?.locale; - }, - fromUrl("locale"), - fromNavigator(), - DEFAULT_FALLBACK, - ) || DEFAULT_FALLBACK(); - const locales = [detected]; - // For now we only care about the first locale part - if (detected.includes("_")) { - locales.push(detected.split("_")[0]); - } - if (detected.includes("-")) { - locales.push(detected.split("-")[0]); - } + // Always load en locale at the start so we have something and don't error + i18n.loadLocaleData("en", { plurals: en }); + i18n.load("en", enLocale); + i18n.activate("en"); + + const locales: string[] = []; + // Get all locales we can, in order + // - Global authentik settings (contains user settings) + // - URL parameter + // - Navigator + // - Fallback (en) + // Remove any invalid values, add broader locales (fr-FR becomes fr) + // Remove any duplicate values + [globalAK()?.locale || "", fromUrl("locale"), fromNavigator(), DEFAULT_FALLBACK()] + .filter((v) => v && v !== "") + .map((locale) => { + locales.push(locale); + // For now we only care about the first locale part + if (locale.includes("_")) { + locales.push(locale.split("_")[0]); + } + if (locale.includes("-")) { + locales.push(locale.split("-")[0]); + } + }) + .filter((v, idx, arr) => { + return arr.indexOf(v) === idx; + }); + console.debug(`authentik/local: Locales to try: ${locales}`); for (const tryLocale of locales) { if (LOCALES.find((locale) => locale.code === tryLocale)) { console.debug(`authentik/locale: Activating detected locale '${tryLocale}'`); @@ -150,6 +164,7 @@ export function autoDetectLanguage() { console.debug(`authentik/locale: No locale for '${locales}', falling back to en`); activateLocale(DEFAULT_FALLBACK()); } + export function activateLocale(code: string) { const urlLocale = fromUrl("locale"); if (urlLocale !== null && urlLocale !== "") { @@ -161,6 +176,10 @@ export function activateLocale(code: string) { return; } locale.locale().then((localeData) => { + console.debug(`authentik/locale: Loaded locale '${code}'`); + if (i18n.locale === code) { + return; + } i18n.loadLocaleData(locale.code, { plurals: localeData.plurals }); i18n.load(locale.code, localeData.locale); i18n.activate(locale.code); diff --git a/web/src/elements/Base.ts b/web/src/elements/Base.ts index 95c1cc4a4..d8343bb9e 100644 --- a/web/src/elements/Base.ts +++ b/web/src/elements/Base.ts @@ -50,10 +50,14 @@ export class AKElement extends LitElement { get activeTheme(): UiThemeEnum | undefined { return this._activeTheme; } + private _handleLocaleChange: () => void; constructor() { super(); - this.addEventListener(EVENT_LOCALE_CHANGE, this._handleLocaleChange); + this._handleLocaleChange = (() => { + this.requestUpdate(); + }).bind(this); + window.addEventListener(EVENT_LOCALE_CHANGE, this._handleLocaleChange); } protected createRenderRoot(): ShadowRoot | Element { @@ -147,11 +151,7 @@ export class AKElement extends LitElement { disconnectedCallback() { super.disconnectedCallback(); - this.removeEventListener(EVENT_LOCALE_CHANGE, this._handleLocaleChange); - } - - private _handleLocaleChange() { - this.requestUpdate(); + window.removeEventListener(EVENT_LOCALE_CHANGE, this._handleLocaleChange); } } diff --git a/web/src/elements/cards/AggregateCard.ts b/web/src/elements/cards/AggregateCard.ts index 8eec5f0c4..58534ce9c 100644 --- a/web/src/elements/cards/AggregateCard.ts +++ b/web/src/elements/cards/AggregateCard.ts @@ -66,11 +66,15 @@ export class AggregateCard extends AKElement { : ""}`; } + renderHeader(): TemplateResult { + return html`${this.header ? this.header : ""}`; + } + render(): TemplateResult { return html`
-  ${this.header ? this.header : ""} +  ${this.renderHeader()}
${this.renderHeaderLink()}