mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-15 13:26:34 +00:00
parent
3e1c22edcd
commit
0a09eabce3
@ -1,4 +1,4 @@
|
|||||||
import { LocalizeFunc } from "../../mixins/localize-base-mixin";
|
import { LocalizeFunc } from "../translations/localize";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Calculate a string representing a date object as relative time from now.
|
* Calculate a string representing a date object as relative time from now.
|
||||||
|
@ -3,7 +3,7 @@ import computeStateDomain from "./compute_state_domain";
|
|||||||
import formatDateTime from "../datetime/format_date_time";
|
import formatDateTime from "../datetime/format_date_time";
|
||||||
import formatDate from "../datetime/format_date";
|
import formatDate from "../datetime/format_date";
|
||||||
import formatTime from "../datetime/format_time";
|
import formatTime from "../datetime/format_time";
|
||||||
import { LocalizeFunc } from "../../mixins/localize-base-mixin";
|
import { LocalizeFunc } from "../translations/localize";
|
||||||
|
|
||||||
export default (
|
export default (
|
||||||
localize: LocalizeFunc,
|
localize: LocalizeFunc,
|
||||||
|
81
src/common/translations/localize.ts
Normal file
81
src/common/translations/localize.ts
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
import IntlMessageFormat from "intl-messageformat/src/main";
|
||||||
|
import { Resources } from "../../types";
|
||||||
|
|
||||||
|
export type LocalizeFunc = (key: string, ...args: any[]) => string;
|
||||||
|
|
||||||
|
interface FormatType {
|
||||||
|
[format: string]: any;
|
||||||
|
}
|
||||||
|
export interface FormatsType {
|
||||||
|
number: FormatType;
|
||||||
|
date: FormatType;
|
||||||
|
time: FormatType;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adapted from Polymer app-localize-behavior.
|
||||||
|
*
|
||||||
|
* Copyright (c) 2016 The Polymer Project Authors. All rights reserved.
|
||||||
|
* This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
|
||||||
|
* The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
|
||||||
|
* The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
|
||||||
|
* Code distributed by Google as part of the polymer project is also
|
||||||
|
* subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Optional dictionary of user defined formats, as explained here:
|
||||||
|
* http://formatjs.io/guides/message-syntax/#custom-formats
|
||||||
|
*
|
||||||
|
* For example, a valid dictionary of formats would be:
|
||||||
|
* this.formats = {
|
||||||
|
* number: { USD: { style: 'currency', currency: 'USD' } }
|
||||||
|
* }
|
||||||
|
*/
|
||||||
|
|
||||||
|
export const computeLocalize = (
|
||||||
|
cache: any,
|
||||||
|
language: string,
|
||||||
|
resources: Resources,
|
||||||
|
formats?: FormatsType
|
||||||
|
): LocalizeFunc => {
|
||||||
|
// Everytime any of the parameters change, invalidate the strings cache.
|
||||||
|
cache._localizationCache = {};
|
||||||
|
|
||||||
|
return (key, ...args) => {
|
||||||
|
if (!key || !resources || !language || !resources[language]) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cache the key/value pairs for the same language, so that we don't
|
||||||
|
// do extra work if we're just reusing strings across an application.
|
||||||
|
const translatedValue = resources[language][key];
|
||||||
|
|
||||||
|
if (!translatedValue) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
const messageKey = key + translatedValue;
|
||||||
|
let translatedMessage = cache._localizationCache[messageKey];
|
||||||
|
|
||||||
|
if (!translatedMessage) {
|
||||||
|
translatedMessage = new (IntlMessageFormat as any)(
|
||||||
|
translatedValue,
|
||||||
|
language,
|
||||||
|
formats
|
||||||
|
);
|
||||||
|
cache._localizationCache[messageKey] = translatedMessage;
|
||||||
|
}
|
||||||
|
|
||||||
|
const argObject = {};
|
||||||
|
for (let i = 0; i < args.length; i += 2) {
|
||||||
|
argObject[args[i]] = args[i + 1];
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
return translatedMessage.format(argObject);
|
||||||
|
} catch (err) {
|
||||||
|
return "Translation " + err;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
@ -15,7 +15,7 @@ import stateIcon from "../../common/entity/state_icon";
|
|||||||
import timerTimeRemaining from "../../common/entity/timer_time_remaining";
|
import timerTimeRemaining from "../../common/entity/timer_time_remaining";
|
||||||
import secondsToDuration from "../../common/datetime/seconds_to_duration";
|
import secondsToDuration from "../../common/datetime/seconds_to_duration";
|
||||||
import { fireEvent } from "../../common/dom/fire_event";
|
import { fireEvent } from "../../common/dom/fire_event";
|
||||||
import { hassLocalizeLitMixin } from "../../mixins/lit-localize-mixin";
|
import { HomeAssistant } from "../../types";
|
||||||
|
|
||||||
import "../ha-label-badge";
|
import "../ha-label-badge";
|
||||||
|
|
||||||
@ -23,7 +23,8 @@ import "../ha-label-badge";
|
|||||||
* @appliesMixin LocalizeMixin
|
* @appliesMixin LocalizeMixin
|
||||||
* @appliesMixin EventsMixin
|
* @appliesMixin EventsMixin
|
||||||
*/
|
*/
|
||||||
export class HaStateLabelBadge extends hassLocalizeLitMixin(LitElement) {
|
export class HaStateLabelBadge extends LitElement {
|
||||||
|
public hass?: HomeAssistant;
|
||||||
public state?: HassEntity;
|
public state?: HassEntity;
|
||||||
private _connected?: boolean;
|
private _connected?: boolean;
|
||||||
private _updateRemaining?: number;
|
private _updateRemaining?: number;
|
||||||
@ -108,7 +109,7 @@ export class HaStateLabelBadge extends hassLocalizeLitMixin(LitElement) {
|
|||||||
default:
|
default:
|
||||||
return state.state === "unknown"
|
return state.state === "unknown"
|
||||||
? "-"
|
? "-"
|
||||||
: this.localize(`component.${domain}.state.${state.state}`) ||
|
: this.hass!.localize(`component.${domain}.state.${state.state}`) ||
|
||||||
state.state;
|
state.state;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -163,8 +164,8 @@ export class HaStateLabelBadge extends hassLocalizeLitMixin(LitElement) {
|
|||||||
// the state translations that are truncated to fit within the badge label. Translations
|
// the state translations that are truncated to fit within the badge label. Translations
|
||||||
// are only added for device_tracker and alarm_control_panel.
|
// are only added for device_tracker and alarm_control_panel.
|
||||||
return (
|
return (
|
||||||
this.localize(`state_badge.${domain}.${state.state}`) ||
|
this.hass!.localize(`state_badge.${domain}.${state.state}`) ||
|
||||||
this.localize(`state_badge.default.${state.state}`) ||
|
this.hass!.localize(`state_badge.default.${state.state}`) ||
|
||||||
state.state
|
state.state
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -6,8 +6,8 @@ import {
|
|||||||
LineChartUnit,
|
LineChartUnit,
|
||||||
} from "./history";
|
} from "./history";
|
||||||
import { HomeAssistant } from "../types";
|
import { HomeAssistant } from "../types";
|
||||||
import { LocalizeFunc } from "../mixins/localize-base-mixin";
|
|
||||||
import { HassEntity } from "home-assistant-js-websocket";
|
import { HassEntity } from "home-assistant-js-websocket";
|
||||||
|
import { LocalizeFunc } from "../common/translations/localize";
|
||||||
|
|
||||||
interface CacheConfig {
|
interface CacheConfig {
|
||||||
refresh: number;
|
refresh: number;
|
||||||
|
@ -2,8 +2,8 @@ import computeStateName from "../common/entity/compute_state_name";
|
|||||||
import computeStateDomain from "../common/entity/compute_state_domain";
|
import computeStateDomain from "../common/entity/compute_state_domain";
|
||||||
import computeStateDisplay from "../common/entity/compute_state_display";
|
import computeStateDisplay from "../common/entity/compute_state_display";
|
||||||
import { HassEntity } from "home-assistant-js-websocket";
|
import { HassEntity } from "home-assistant-js-websocket";
|
||||||
import { LocalizeFunc } from "../mixins/localize-base-mixin";
|
|
||||||
import { HomeAssistant } from "../types";
|
import { HomeAssistant } from "../types";
|
||||||
|
import { LocalizeFunc } from "../common/translations/localize";
|
||||||
|
|
||||||
const DOMAINS_USE_LAST_UPDATED = ["climate", "water_heater"];
|
const DOMAINS_USE_LAST_UPDATED = ["climate", "water_heater"];
|
||||||
const LINE_ATTRIBUTES_TO_KEEP = [
|
const LINE_ATTRIBUTES_TO_KEEP = [
|
||||||
|
@ -136,6 +136,7 @@ export const provideHass = (
|
|||||||
|
|
||||||
language: getActiveTranslation(),
|
language: getActiveTranslation(),
|
||||||
resources: null as any,
|
resources: null as any,
|
||||||
|
localize: () => "",
|
||||||
|
|
||||||
translationMetadata: translationMetadata as any,
|
translationMetadata: translationMetadata as any,
|
||||||
dockedSidebar: false,
|
dockedSidebar: false,
|
||||||
|
@ -53,6 +53,7 @@ export default (superClass) =>
|
|||||||
language: getActiveTranslation(),
|
language: getActiveTranslation(),
|
||||||
// If resources are already loaded, don't discard them
|
// If resources are already loaded, don't discard them
|
||||||
resources: (this.hass && this.hass.resources) || null,
|
resources: (this.hass && this.hass.resources) || null,
|
||||||
|
localize: () => "",
|
||||||
|
|
||||||
translationMetadata: translationMetadata,
|
translationMetadata: translationMetadata,
|
||||||
dockedSidebar: false,
|
dockedSidebar: false,
|
||||||
|
@ -25,13 +25,7 @@ export default (superClass: Constructor<LitElement & HassBaseEl>) =>
|
|||||||
if (!this._discToast) {
|
if (!this._discToast) {
|
||||||
const el = document.createElement("ha-toast");
|
const el = document.createElement("ha-toast");
|
||||||
el.duration = 0;
|
el.duration = 0;
|
||||||
// Temp. Somehow the localize func is not getting recalculated for
|
el.text = this.hass!.localize("ui.notification_toast.connection_lost");
|
||||||
// this class. Manually generating one. Will be fixed when we move
|
|
||||||
// the localize function to the hass object.
|
|
||||||
const { language, resources } = this.hass!;
|
|
||||||
el.text = (this as any).__computeLocalize(language, resources)(
|
|
||||||
"ui.notification_toast.connection_lost"
|
|
||||||
);
|
|
||||||
this._discToast = el;
|
this._discToast = el;
|
||||||
this.shadowRoot!.appendChild(el as any);
|
this.shadowRoot!.appendChild(el as any);
|
||||||
}
|
}
|
||||||
|
@ -1,14 +1,17 @@
|
|||||||
import { translationMetadata } from "../../resources/translations-metadata";
|
import { translationMetadata } from "../../resources/translations-metadata";
|
||||||
import { getTranslation } from "../../util/hass-translation";
|
import { getTranslation } from "../../util/hass-translation";
|
||||||
import { storeState } from "../../util/ha-pref-storage";
|
import { storeState } from "../../util/ha-pref-storage";
|
||||||
|
import { Constructor, LitElement } from "lit-element";
|
||||||
|
import { HassBaseEl } from "./hass-base-mixin";
|
||||||
|
import { computeLocalize } from "../../common/translations/localize";
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* superClass needs to contain `this.hass` and `this._updateHass`.
|
* superClass needs to contain `this.hass` and `this._updateHass`.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export default (superClass) =>
|
export default (superClass: Constructor<LitElement & HassBaseEl>) =>
|
||||||
class extends superClass {
|
class extends superClass {
|
||||||
firstUpdated(changedProps) {
|
protected firstUpdated(changedProps) {
|
||||||
super.firstUpdated(changedProps);
|
super.firstUpdated(changedProps);
|
||||||
this.addEventListener("hass-language-select", (e) =>
|
this.addEventListener("hass-language-select", (e) =>
|
||||||
this._selectLanguage(e)
|
this._selectLanguage(e)
|
||||||
@ -16,71 +19,78 @@ export default (superClass) =>
|
|||||||
this._loadResources();
|
this._loadResources();
|
||||||
}
|
}
|
||||||
|
|
||||||
hassConnected() {
|
protected hassConnected() {
|
||||||
super.hassConnected();
|
super.hassConnected();
|
||||||
this._loadBackendTranslations();
|
this._loadBackendTranslations();
|
||||||
}
|
}
|
||||||
|
|
||||||
hassReconnected() {
|
protected hassReconnected() {
|
||||||
super.hassReconnected();
|
super.hassReconnected();
|
||||||
this._loadBackendTranslations();
|
this._loadBackendTranslations();
|
||||||
}
|
}
|
||||||
|
|
||||||
panelUrlChanged(newPanelUrl) {
|
protected panelUrlChanged(newPanelUrl) {
|
||||||
super.panelUrlChanged(newPanelUrl);
|
super.panelUrlChanged(newPanelUrl);
|
||||||
this._loadTranslationFragment(newPanelUrl);
|
this._loadTranslationFragment(newPanelUrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
async _loadBackendTranslations() {
|
private async _loadBackendTranslations() {
|
||||||
if (!this.hass.language) return;
|
const hass = this.hass;
|
||||||
|
if (!hass || !hass.language) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const language = this.hass.selectedLanguage || this.hass.language;
|
const language = hass.selectedLanguage || hass.language;
|
||||||
|
|
||||||
const { resources } = await this.hass.callWS({
|
const { resources } = await hass.callWS({
|
||||||
type: "frontend/get_translations",
|
type: "frontend/get_translations",
|
||||||
language,
|
language,
|
||||||
});
|
});
|
||||||
|
|
||||||
// If we've switched selected languages just ignore this response
|
// If we've switched selected languages just ignore this response
|
||||||
if ((this.hass.selectedLanguage || this.hass.language) !== language)
|
if ((hass.selectedLanguage || hass.language) !== language) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
this._updateResources(language, resources);
|
this._updateResources(language, resources);
|
||||||
}
|
}
|
||||||
|
|
||||||
_loadTranslationFragment(panelUrl) {
|
private _loadTranslationFragment(panelUrl) {
|
||||||
if (translationMetadata.fragments.includes(panelUrl)) {
|
if (translationMetadata.fragments.includes(panelUrl)) {
|
||||||
this._loadResources(panelUrl);
|
this._loadResources(panelUrl);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async _loadResources(fragment) {
|
private async _loadResources(fragment?) {
|
||||||
const result = await getTranslation(fragment);
|
const result = await getTranslation(fragment);
|
||||||
this._updateResources(result.language, result.data);
|
this._updateResources(result.language, result.data);
|
||||||
}
|
}
|
||||||
|
|
||||||
_updateResources(language, data) {
|
private _updateResources(language, data) {
|
||||||
// Update the language in hass, and update the resources with the newly
|
// Update the language in hass, and update the resources with the newly
|
||||||
// loaded resources. This merges the new data on top of the old data for
|
// loaded resources. This merges the new data on top of the old data for
|
||||||
// this language, so that the full translation set can be loaded across
|
// this language, so that the full translation set can be loaded across
|
||||||
// multiple fragments.
|
// multiple fragments.
|
||||||
this._updateHass({
|
const resources = {
|
||||||
language: language,
|
[language]: {
|
||||||
resources: {
|
...(this.hass &&
|
||||||
[language]: Object.assign(
|
this.hass.resources &&
|
||||||
{},
|
this.hass.resources[language]),
|
||||||
this.hass && this.hass.resources && this.hass.resources[language],
|
...data,
|
||||||
data
|
|
||||||
),
|
|
||||||
},
|
},
|
||||||
|
};
|
||||||
|
this._updateHass({
|
||||||
|
language,
|
||||||
|
resources,
|
||||||
|
localize: computeLocalize(this, language, resources),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
_selectLanguage(event) {
|
private _selectLanguage(event) {
|
||||||
this._updateHass({ selectedLanguage: event.detail.language });
|
this._updateHass({ selectedLanguage: event.detail.language });
|
||||||
storeState(this.hass);
|
storeState(this.hass);
|
||||||
this._loadResources();
|
this._loadResources();
|
||||||
this._loadBackendTranslations();
|
this._loadBackendTranslations();
|
||||||
this._loadTranslationFragment(this.hass.panelUrl);
|
this._loadTranslationFragment(this.hass!.panelUrl);
|
||||||
}
|
}
|
||||||
};
|
};
|
@ -4,10 +4,10 @@ import {
|
|||||||
PropertyDeclarations,
|
PropertyDeclarations,
|
||||||
PropertyValues,
|
PropertyValues,
|
||||||
} from "lit-element";
|
} from "lit-element";
|
||||||
import { HomeAssistant } from "../types";
|
|
||||||
import { getActiveTranslation } from "../util/hass-translation";
|
import { getActiveTranslation } from "../util/hass-translation";
|
||||||
import { LocalizeFunc, LocalizeMixin } from "./localize-base-mixin";
|
|
||||||
import { localizeLiteBaseMixin } from "./localize-lite-base-mixin";
|
import { localizeLiteBaseMixin } from "./localize-lite-base-mixin";
|
||||||
|
import { computeLocalize } from "../common/translations/localize";
|
||||||
|
import { LocalizeMixin } from "../types";
|
||||||
|
|
||||||
const empty = () => "";
|
const empty = () => "";
|
||||||
|
|
||||||
@ -22,12 +22,8 @@ export const litLocalizeLiteMixin = <T extends LitElement>(
|
|||||||
): Constructor<T & LocalizeMixin & LitLocalizeLiteMixin> =>
|
): Constructor<T & LocalizeMixin & LitLocalizeLiteMixin> =>
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
class extends localizeLiteBaseMixin(superClass) {
|
class extends localizeLiteBaseMixin(superClass) {
|
||||||
protected hass?: HomeAssistant;
|
|
||||||
protected localize!: LocalizeFunc;
|
|
||||||
|
|
||||||
static get properties(): PropertyDeclarations {
|
static get properties(): PropertyDeclarations {
|
||||||
return {
|
return {
|
||||||
hass: {},
|
|
||||||
localize: {},
|
localize: {},
|
||||||
language: {},
|
language: {},
|
||||||
resources: {},
|
resources: {},
|
||||||
@ -45,7 +41,11 @@ export const litLocalizeLiteMixin = <T extends LitElement>(
|
|||||||
public connectedCallback(): void {
|
public connectedCallback(): void {
|
||||||
super.connectedCallback();
|
super.connectedCallback();
|
||||||
this._initializeLocalizeLite();
|
this._initializeLocalizeLite();
|
||||||
this.localize = this.__computeLocalize(this.language, this.resources);
|
this.localize = computeLocalize(
|
||||||
|
this.constructor.prototype,
|
||||||
|
this.language,
|
||||||
|
this.resources
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
public updated(changedProperties: PropertyValues) {
|
public updated(changedProperties: PropertyValues) {
|
||||||
@ -54,7 +54,11 @@ export const litLocalizeLiteMixin = <T extends LitElement>(
|
|||||||
changedProperties.has("language") ||
|
changedProperties.has("language") ||
|
||||||
changedProperties.has("resources")
|
changedProperties.has("resources")
|
||||||
) {
|
) {
|
||||||
this.localize = this.__computeLocalize(this.language, this.resources);
|
this.localize = computeLocalize(
|
||||||
|
this.constructor.prototype,
|
||||||
|
this.language,
|
||||||
|
this.resources
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -1,15 +1,5 @@
|
|||||||
import {
|
import { Constructor, LitElement } from "lit-element";
|
||||||
Constructor,
|
import { HomeAssistant, LocalizeMixin } from "../types";
|
||||||
LitElement,
|
|
||||||
PropertyDeclarations,
|
|
||||||
PropertyValues,
|
|
||||||
} from "lit-element";
|
|
||||||
import { HomeAssistant } from "../types";
|
|
||||||
import {
|
|
||||||
localizeBaseMixin,
|
|
||||||
LocalizeFunc,
|
|
||||||
LocalizeMixin,
|
|
||||||
} from "./localize-base-mixin";
|
|
||||||
|
|
||||||
const empty = () => "";
|
const empty = () => "";
|
||||||
|
|
||||||
@ -17,61 +7,10 @@ export const hassLocalizeLitMixin = <T extends LitElement>(
|
|||||||
superClass: Constructor<T>
|
superClass: Constructor<T>
|
||||||
): Constructor<T & LocalizeMixin> =>
|
): Constructor<T & LocalizeMixin> =>
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
class extends localizeBaseMixin(superClass) {
|
class extends superClass {
|
||||||
protected hass?: HomeAssistant;
|
public hass?: HomeAssistant;
|
||||||
protected localize!: LocalizeFunc;
|
|
||||||
|
|
||||||
static get properties(): PropertyDeclarations {
|
get localize() {
|
||||||
return {
|
return this.hass ? this.hass.localize : empty;
|
||||||
hass: {},
|
|
||||||
localize: {},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
constructor() {
|
|
||||||
super();
|
|
||||||
// This will prevent undefined errors if called before connected to DOM.
|
|
||||||
this.localize = empty;
|
|
||||||
}
|
|
||||||
|
|
||||||
public connectedCallback(): void {
|
|
||||||
super.connectedCallback();
|
|
||||||
|
|
||||||
if (this.localize === empty) {
|
|
||||||
let language;
|
|
||||||
let resources;
|
|
||||||
if (this.hass) {
|
|
||||||
language = this.hass.language;
|
|
||||||
resources = this.hass.resources;
|
|
||||||
}
|
|
||||||
this.localize = this.__computeLocalize(language, resources);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public updated(changedProperties: PropertyValues) {
|
|
||||||
super.updated(changedProperties);
|
|
||||||
|
|
||||||
if (!changedProperties.has("hass")) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let oldLanguage;
|
|
||||||
let oldResources;
|
|
||||||
const hass = changedProperties.get("hass") as HomeAssistant;
|
|
||||||
if (hass) {
|
|
||||||
oldLanguage = hass.language;
|
|
||||||
oldResources = hass.resources;
|
|
||||||
}
|
|
||||||
|
|
||||||
let language;
|
|
||||||
let resources;
|
|
||||||
if (this.hass) {
|
|
||||||
language = this.hass.language;
|
|
||||||
resources = this.hass.resources;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (oldLanguage !== language || oldResources !== resources) {
|
|
||||||
this.localize = this.__computeLocalize(language, resources);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -1,114 +0,0 @@
|
|||||||
import IntlMessageFormat from "intl-messageformat/src/main";
|
|
||||||
import { HomeAssistant } from "../types";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Adapted from Polymer app-localize-behavior.
|
|
||||||
*
|
|
||||||
* Copyright (c) 2016 The Polymer Project Authors. All rights reserved.
|
|
||||||
* This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
|
|
||||||
* The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
|
|
||||||
* The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
|
|
||||||
* Code distributed by Google as part of the polymer project is also
|
|
||||||
* subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Optional dictionary of user defined formats, as explained here:
|
|
||||||
* http://formatjs.io/guides/message-syntax/#custom-formats
|
|
||||||
*
|
|
||||||
* For example, a valid dictionary of formats would be:
|
|
||||||
* this.formats = {
|
|
||||||
* number: { USD: { style: 'currency', currency: 'USD' } }
|
|
||||||
* }
|
|
||||||
*/
|
|
||||||
interface FormatType {
|
|
||||||
[format: string]: any;
|
|
||||||
}
|
|
||||||
export interface FormatsType {
|
|
||||||
number: FormatType;
|
|
||||||
date: FormatType;
|
|
||||||
time: FormatType;
|
|
||||||
}
|
|
||||||
|
|
||||||
export type LocalizeFunc = (key: string, ...args: any[]) => string;
|
|
||||||
|
|
||||||
export interface LocalizeMixin {
|
|
||||||
hass?: HomeAssistant;
|
|
||||||
localize: LocalizeFunc;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const localizeBaseMixin = (superClass) =>
|
|
||||||
class extends superClass {
|
|
||||||
/**
|
|
||||||
* Returns a computed `localize` method, based on the current `language`.
|
|
||||||
*/
|
|
||||||
public __computeLocalize(
|
|
||||||
language: string,
|
|
||||||
resources: string,
|
|
||||||
formats?: FormatsType
|
|
||||||
): LocalizeFunc {
|
|
||||||
const proto = this.constructor.prototype;
|
|
||||||
|
|
||||||
// Check if localCache exist just in case.
|
|
||||||
this.__checkLocalizationCache(proto);
|
|
||||||
|
|
||||||
// Everytime any of the parameters change, invalidate the strings cache.
|
|
||||||
if (!proto.__localizationCache) {
|
|
||||||
proto.__localizationCache = {
|
|
||||||
messages: {},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
proto.__localizationCache.messages = {};
|
|
||||||
|
|
||||||
return (key, ...args) => {
|
|
||||||
if (!key || !resources || !language || !resources[language]) {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
// Cache the key/value pairs for the same language, so that we don't
|
|
||||||
// do extra work if we're just reusing strings across an application.
|
|
||||||
const translatedValue = resources[language][key];
|
|
||||||
|
|
||||||
if (!translatedValue) {
|
|
||||||
return this.useKeyIfMissing ? key : "";
|
|
||||||
}
|
|
||||||
|
|
||||||
const messageKey = key + translatedValue;
|
|
||||||
let translatedMessage = proto.__localizationCache.messages[messageKey];
|
|
||||||
|
|
||||||
if (!translatedMessage) {
|
|
||||||
translatedMessage = new (IntlMessageFormat as any)(
|
|
||||||
translatedValue,
|
|
||||||
language,
|
|
||||||
formats
|
|
||||||
);
|
|
||||||
proto.__localizationCache.messages[messageKey] = translatedMessage;
|
|
||||||
}
|
|
||||||
|
|
||||||
const argObject = {};
|
|
||||||
for (let i = 0; i < args.length; i += 2) {
|
|
||||||
argObject[args[i]] = args[i + 1];
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
return translatedMessage.format(argObject);
|
|
||||||
} catch (err) {
|
|
||||||
return "Translation " + err;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
public __checkLocalizationCache(proto) {
|
|
||||||
// do nothing if proto is undefined.
|
|
||||||
if (proto === undefined) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// In the event proto not have __localizationCache object, create it.
|
|
||||||
if (proto.__localizationCache === undefined) {
|
|
||||||
proto.__localizationCache = {
|
|
||||||
messages: {},
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
@ -1,14 +1,13 @@
|
|||||||
/**
|
/**
|
||||||
* Lite base mixin to add localization without depending on the Hass object.
|
* Lite base mixin to add localization without depending on the Hass object.
|
||||||
*/
|
*/
|
||||||
import { localizeBaseMixin } from "./localize-base-mixin";
|
|
||||||
import { getTranslation } from "../util/hass-translation";
|
import { getTranslation } from "../util/hass-translation";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @polymerMixin
|
* @polymerMixin
|
||||||
*/
|
*/
|
||||||
export const localizeLiteBaseMixin = (superClass) =>
|
export const localizeLiteBaseMixin = (superClass) =>
|
||||||
class extends localizeBaseMixin(superClass) {
|
class extends superClass {
|
||||||
protected _initializeLocalizeLite() {
|
protected _initializeLocalizeLite() {
|
||||||
if (this.resources) {
|
if (this.resources) {
|
||||||
return;
|
return;
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
import { dedupingMixin } from "@polymer/polymer/lib/utils/mixin";
|
import { dedupingMixin } from "@polymer/polymer/lib/utils/mixin";
|
||||||
import { getActiveTranslation } from "../util/hass-translation";
|
import { getActiveTranslation } from "../util/hass-translation";
|
||||||
import { localizeLiteBaseMixin } from "./localize-lite-base-mixin";
|
import { localizeLiteBaseMixin } from "./localize-lite-base-mixin";
|
||||||
|
import { computeLocalize } from "../common/translations/localize";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @polymerMixin
|
* @polymerMixin
|
||||||
@ -36,5 +37,14 @@ export const localizeLiteMixin = dedupingMixin(
|
|||||||
super.ready();
|
super.ready();
|
||||||
this._initializeLocalizeLite();
|
this._initializeLocalizeLite();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected __computeLocalize(language, resources, formats?) {
|
||||||
|
return computeLocalize(
|
||||||
|
this.constructor.prototype,
|
||||||
|
language,
|
||||||
|
resources,
|
||||||
|
formats
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import { dedupingMixin } from "@polymer/polymer/lib/utils/mixin";
|
import { dedupingMixin } from "@polymer/polymer/lib/utils/mixin";
|
||||||
import { localizeBaseMixin } from "./localize-base-mixin";
|
|
||||||
/**
|
/**
|
||||||
* Polymer Mixin to enable a localize function powered by language/resources from hass object.
|
* Polymer Mixin to enable a localize function powered by language/resources from hass object.
|
||||||
*
|
*
|
||||||
@ -7,7 +6,7 @@ import { localizeBaseMixin } from "./localize-base-mixin";
|
|||||||
*/
|
*/
|
||||||
export default dedupingMixin(
|
export default dedupingMixin(
|
||||||
(superClass) =>
|
(superClass) =>
|
||||||
class extends localizeBaseMixin(superClass) {
|
class extends superClass {
|
||||||
static get properties() {
|
static get properties() {
|
||||||
return {
|
return {
|
||||||
hass: Object,
|
hass: Object,
|
||||||
@ -19,10 +18,13 @@ export default dedupingMixin(
|
|||||||
*/
|
*/
|
||||||
localize: {
|
localize: {
|
||||||
type: Function,
|
type: Function,
|
||||||
computed:
|
computed: "__computeLocalize(hass.localize)",
|
||||||
"__computeLocalize(hass.language, hass.resources, formats)",
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
__computeLocalize(localize) {
|
||||||
|
return localize;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -11,10 +11,10 @@ import computeStateName from "../../../common/entity/compute_state_name";
|
|||||||
import splitByGroups from "../../../common/entity/split_by_groups";
|
import splitByGroups from "../../../common/entity/split_by_groups";
|
||||||
import computeObjectId from "../../../common/entity/compute_object_id";
|
import computeObjectId from "../../../common/entity/compute_object_id";
|
||||||
import computeStateDomain from "../../../common/entity/compute_state_domain";
|
import computeStateDomain from "../../../common/entity/compute_state_domain";
|
||||||
import { LocalizeFunc } from "../../../mixins/localize-base-mixin";
|
|
||||||
import computeDomain from "../../../common/entity/compute_domain";
|
import computeDomain from "../../../common/entity/compute_domain";
|
||||||
import { EntityRowConfig, WeblinkConfig } from "../entity-rows/types";
|
import { EntityRowConfig, WeblinkConfig } from "../entity-rows/types";
|
||||||
import { EntitiesCardConfig } from "../cards/hui-entities-card";
|
import { EntitiesCardConfig } from "../cards/hui-entities-card";
|
||||||
|
import { LocalizeFunc } from "../../../common/translations/localize";
|
||||||
|
|
||||||
const DEFAULT_VIEW_ENTITY_ID = "group.default_view";
|
const DEFAULT_VIEW_ENTITY_ID = "group.default_view";
|
||||||
const DOMAINS_BADGES = [
|
const DOMAINS_BADGES = [
|
||||||
|
17
src/types.ts
17
src/types.ts
@ -8,6 +8,7 @@ import {
|
|||||||
HassEntityAttributeBase,
|
HassEntityAttributeBase,
|
||||||
HassServices,
|
HassServices,
|
||||||
} from "home-assistant-js-websocket";
|
} from "home-assistant-js-websocket";
|
||||||
|
import { LocalizeFunc } from "./common/translations/localize";
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
var __DEV__: boolean;
|
var __DEV__: boolean;
|
||||||
@ -92,6 +93,10 @@ export interface Notification {
|
|||||||
created_at: string;
|
created_at: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface Resources {
|
||||||
|
[language: string]: { [key: string]: string };
|
||||||
|
}
|
||||||
|
|
||||||
export interface HomeAssistant {
|
export interface HomeAssistant {
|
||||||
auth: Auth;
|
auth: Auth;
|
||||||
connection: Connection;
|
connection: Connection;
|
||||||
@ -103,14 +108,19 @@ export interface HomeAssistant {
|
|||||||
selectedTheme?: string | null;
|
selectedTheme?: string | null;
|
||||||
panels: Panels;
|
panels: Panels;
|
||||||
panelUrl: string;
|
panelUrl: string;
|
||||||
|
|
||||||
|
// i18n
|
||||||
language: string;
|
language: string;
|
||||||
resources: { [key: string]: any };
|
selectedLanguage?: string;
|
||||||
|
resources: Resources;
|
||||||
|
localize: LocalizeFunc;
|
||||||
translationMetadata: {
|
translationMetadata: {
|
||||||
fragments: string[];
|
fragments: string[];
|
||||||
translations: {
|
translations: {
|
||||||
[lang: string]: Translation;
|
[lang: string]: Translation;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
dockedSidebar: boolean;
|
dockedSidebar: boolean;
|
||||||
moreInfoEntityId: string;
|
moreInfoEntityId: string;
|
||||||
user: User;
|
user: User;
|
||||||
@ -196,3 +206,8 @@ export interface PanelElement extends HTMLElement {
|
|||||||
route?: Route | null;
|
route?: Route | null;
|
||||||
panel?: Panel;
|
panel?: Panel;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface LocalizeMixin {
|
||||||
|
hass?: HomeAssistant;
|
||||||
|
localize: LocalizeFunc;
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user