From 2703f1b4f247843812a358a5c071ea58d2f228d8 Mon Sep 17 00:00:00 2001 From: andreasbm Date: Fri, 22 Apr 2022 11:30:12 +0200 Subject: [PATCH] feat: reintroduced the langChanged directive --- src/demo/pages/demo-page.ts | 124 ++++++++++---------- src/lib/directives/lang-changed-base.ts | 62 ++++++++++ src/lib/directives/lang-changed.ts | 14 +++ src/lib/directives/translate-unsafe-html.ts | 21 ++-- src/lib/directives/translate.ts | 47 ++------ src/lib/index.ts | 2 + 6 files changed, 156 insertions(+), 114 deletions(-) create mode 100644 src/lib/directives/lang-changed-base.ts create mode 100644 src/lib/directives/lang-changed.ts diff --git a/src/demo/pages/demo-page.ts b/src/demo/pages/demo-page.ts index 0f55245..824d718 100644 --- a/src/demo/pages/demo-page.ts +++ b/src/demo/pages/demo-page.ts @@ -1,18 +1,18 @@ -import { html, LitElement, PropertyValues, TemplateResult } from "lit"; -import { customElement, eventOptions, property } from "lit/decorators.js"; -import { repeat } from "lit/directives/repeat.js"; -import { get, LanguageIdentifier, registerTranslateConfig, translate, translateUnsafeHTML, use } from "../../lib"; +import {html, LitElement, PropertyValues, TemplateResult} from "lit"; +import {customElement, eventOptions, property} from "lit/decorators.js"; +import {repeat} from "lit/directives/repeat.js"; +import {get, LanguageIdentifier, registerTranslateConfig, translate, translateUnsafeHTML, use} from "../../lib"; import styles from "./demo-page.scss"; const languages = [ - "en", - "da" + "en", + "da" ]; // Registers loader registerTranslateConfig({ - loader: (lang: LanguageIdentifier) => fetch(`assets/i18n/${lang}.json`).then(res => res.json()) + loader: (lang: LanguageIdentifier) => fetch(`assets/i18n/${lang}.json`).then(res => res.json()) }); // const testTranslateConfig: ITranslateConfig = { @@ -28,67 +28,67 @@ registerTranslateConfig({ @customElement("demo-page-component") export class DemoPageComponent extends LitElement { - @property() lang = languages[0]; - @property() thing = ""; + @property() lang = languages[0]; + @property() thing = ""; - // Defer the first update of the component until the strings has been loaded to avoid empty strings being shown - private hasLoadedStrings = false; + // Defer the first update of the component until the strings has been loaded to avoid empty strings being shown + private hasLoadedStrings = false; - protected shouldUpdate (changedProperties: PropertyValues) { - return this.hasLoadedStrings && super.shouldUpdate(changedProperties); - } + protected shouldUpdate(changedProperties: PropertyValues) { + return this.hasLoadedStrings && super.shouldUpdate(changedProperties); + } - // Load the initial language and mark that the strings has been loaded. - async connectedCallback () { - super.connectedCallback(); + // Load the initial language and mark that the strings has been loaded. + async connectedCallback() { + super.connectedCallback(); - await use(this.lang); - this.hasLoadedStrings = true; - this.requestUpdate(); + await use(this.lang); + this.hasLoadedStrings = true; + this.requestUpdate(); - // The below example is how parts of the strings could be lazy loaded - // listenForLangChanged(() => { - // setTimeout(async () => { - // const subpageStrings = await (await fetch(`./../assets/i18n/subpage-${translateConfig.lang}.json`) - // .then(d => d.json())); - // - // translateConfig.strings = {...translateConfig.strings, ...subpageStrings}; - // translateConfig.translationCache = {}; - // - // this.requestUpdate().then(); - // - // console.log(translateConfig, get("subpage.title")); - // }, 2000); - // }); - } + // The below example is how parts of the strings could be lazy loaded + // listenForLangChanged(() => { + // setTimeout(async () => { + // const subpageStrings = await (await fetch(`./../assets/i18n/subpage-${translateConfig.lang}.json`) + // .then(d => d.json())); + // + // translateConfig.strings = {...translateConfig.strings, ...subpageStrings}; + // translateConfig.translationCache = {}; + // + // this.requestUpdate().then(); + // + // console.log(translateConfig, get("subpage.title")); + // }, 2000); + // }); + } - @eventOptions({capture: true}) - private async onLanguageSelected (e: Event) { - this.lang = (e.target).value; - await use(this.lang).then(); - } + @eventOptions({capture: true}) + private async onLanguageSelected(e: Event) { + this.lang = (e.target).value; + await use(this.lang).then(); + } - protected render (): TemplateResult { - return html` - + protected render(): TemplateResult { + return html` + -
-

lit-translate

-

${translate("lang")}

-

${translate("app.title")}

-

${translate("app.subtitle", () => ({thing: this.thing || get("world")}))}

-

${translateUnsafeHTML("app.html")}

- - -
- View on Github - `; - } +
+

lit-translate

+

${translate("lang")}

+

${translate("app.title")}

+

${translate("app.subtitle", () => ({thing: this.thing || get("world")}))}

+

${translateUnsafeHTML("app.html")}

+ + +
+ View on Github + `; + } } diff --git a/src/lib/directives/lang-changed-base.ts b/src/lib/directives/lang-changed-base.ts new file mode 100644 index 0000000..679f9e9 --- /dev/null +++ b/src/lib/directives/lang-changed-base.ts @@ -0,0 +1,62 @@ +import {AsyncDirective} from "lit/async-directive.js"; +import {LangChangedEvent, LangChangedSubscription} from "../model"; +import {listenForLangChanged} from "../util"; + +/** + * An abstract lit directive that reacts when the language changes. + */ +export abstract class LangChangedDirectiveBase extends AsyncDirective { + protected langChangedSubscription: LangChangedSubscription | null = null; + protected getValue: ((e?: LangChangedEvent) => unknown) = (() => ""); + + /** + * Sets up the directive by setting the getValue property and subscribing. + * When subclassing LangChangedDirectiveBase this function should be call in the render function. + * @param getValue + */ + renderValue(getValue: ((e?: LangChangedEvent) => unknown)): unknown { + this.getValue = getValue; + this.subscribe(); + return this.getValue(); + } + + /** + * Called when the lang changed event is dispatched. + * @param e + */ + langChanged(e?: LangChangedEvent) { + this.setValue(this.getValue(e)); + } + + /** + * Subscribes to the lang changed event. + */ + subscribe() { + if (this.langChangedSubscription == null) { + this.langChangedSubscription = listenForLangChanged(this.langChanged.bind(this)); + } + } + + /** + * Unsubscribes from the lang changed event. + */ + unsubscribe() { + if (this.langChangedSubscription != null) { + this.langChangedSubscription(); + } + } + + /** + * Unsubscribes when disconnected. + */ + disconnected() { + this.unsubscribe(); + } + + /** + * Subscribes when reconnected. + */ + reconnected() { + this.subscribe(); + } +} \ No newline at end of file diff --git a/src/lib/directives/lang-changed.ts b/src/lib/directives/lang-changed.ts new file mode 100644 index 0000000..ecfe82e --- /dev/null +++ b/src/lib/directives/lang-changed.ts @@ -0,0 +1,14 @@ +import {directive} from "lit/directive.js"; +import {LangChangedEvent} from "../model"; +import {LangChangedDirectiveBase} from "./lang-changed-base"; + +/** + * A lit directive that reacts when the language changes and renders the getValue callback. + */ +export class LangChangedDirective extends LangChangedDirectiveBase { + render(getValue: ((e?: LangChangedEvent) => unknown)): unknown { + return this.renderValue(getValue); + } +} + +export const langChanged = directive(LangChangedDirective); \ No newline at end of file diff --git a/src/lib/directives/translate-unsafe-html.ts b/src/lib/directives/translate-unsafe-html.ts index e61420a..244e1b8 100644 --- a/src/lib/directives/translate-unsafe-html.ts +++ b/src/lib/directives/translate-unsafe-html.ts @@ -1,21 +1,16 @@ -import { directive } from "lit/directive.js"; -import { unsafeHTML } from "lit/directives/unsafe-html.js"; -import { ITranslateConfig, Values, ValuesCallback } from "../model"; -import { TranslateDirective } from "./translate"; +import {directive} from "lit/directive.js"; +import {unsafeHTML} from "lit/directives/unsafe-html.js"; +import {ITranslateConfig, Values, ValuesCallback} from "../model"; +import {TranslateDirective} from "./translate"; +import {get} from "../util"; /** * A lit directive that updates the translation as HTML when the language changes. */ export class TranslateUnsafeHTMLDirective extends TranslateDirective { - render (key: string, values?: Values | ValuesCallback, config?: ITranslateConfig) { - super.render(key, values, config); - return unsafeHTML(this.getTranslation()); - } - - updateTranslation () { - const translation = this.getTranslation(); - this.setValue(unsafeHTML(translation)); - } + render(key: string, values?: Values | ValuesCallback, config?: ITranslateConfig) { + return this.renderValue(() => unsafeHTML(get(key, values, config))); + } } export const translateUnsafeHTML = directive(TranslateUnsafeHTMLDirective); diff --git a/src/lib/directives/translate.ts b/src/lib/directives/translate.ts index 9bac4e9..67c0df7 100644 --- a/src/lib/directives/translate.ts +++ b/src/lib/directives/translate.ts @@ -1,46 +1,15 @@ -import { AsyncDirective } from "lit/async-directive.js"; -import { directive } from "lit/directive.js"; -import { ITranslateConfig, LangChangedSubscription, Translation, Values, ValuesCallback } from "../model"; -import { get, listenForLangChanged } from "../util"; +import {directive} from "lit/directive.js"; +import {ITranslateConfig, Values, ValuesCallback} from "../model"; +import {get} from "../util"; +import {LangChangedDirectiveBase} from "./lang-changed-base"; /** * A lit directive that updates the translation when the language changes. */ -export class TranslateDirective extends AsyncDirective { - protected langChangedSubscription: LangChangedSubscription | null = null; - protected getTranslation: (() => Translation) = (() => ""); - - render (key: string, values?: Values | ValuesCallback, config?: ITranslateConfig): unknown { - this.getTranslation = () => get(key, values, config); - this.subscribe(); - return this.getTranslation(); - } - - updateTranslation () { - const translation = this.getTranslation(); - this.setValue(translation); - } - - subscribe () { - if (this.langChangedSubscription == null) { - this.langChangedSubscription = listenForLangChanged(this.updateTranslation.bind(this)); - } - } - - unsubscribe () { - if (this.langChangedSubscription != null) { - this.langChangedSubscription(); - } - } - - disconnected () { - this.unsubscribe(); - } - - reconnected () { - this.subscribe(); - } +export class TranslateDirective extends LangChangedDirectiveBase { + render(key: string, values?: Values | ValuesCallback, config?: ITranslateConfig): unknown { + return this.renderValue(() => get(key, values, config)); + } } -// Create the directive function export const translate = directive(TranslateDirective); diff --git a/src/lib/index.ts b/src/lib/index.ts index 6ea4c5e..3b50cf6 100644 --- a/src/lib/index.ts +++ b/src/lib/index.ts @@ -3,3 +3,5 @@ export * from "./util"; export * from "./helpers"; export * from "./directives/translate"; export * from "./directives/translate-unsafe-html"; +export * from "./directives/lang-changed"; +export * from "./directives/lang-changed-base";