mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-13 12:26:35 +00:00
🌐 Add MVP for translation in the Supervisor panel (#8425)
Co-authored-by: Bram Kragten <mail@bramkragten.nl>
This commit is contained in:
parent
5ae10e8516
commit
bea20d0495
@ -85,6 +85,11 @@ gulp.task("copy-translations-app", async () => {
|
||||
copyTranslations(staticDir);
|
||||
});
|
||||
|
||||
gulp.task("copy-translations-supervisor", async () => {
|
||||
const staticDir = paths.hassio_output_static;
|
||||
copyTranslations(staticDir);
|
||||
});
|
||||
|
||||
gulp.task("copy-static-app", async () => {
|
||||
const staticDir = paths.app_output_static;
|
||||
// Basic static files
|
||||
|
@ -10,6 +10,8 @@ require("./gen-icons-json.js");
|
||||
require("./webpack.js");
|
||||
require("./compress.js");
|
||||
require("./rollup.js");
|
||||
require("./gather-static.js");
|
||||
require("./translations.js");
|
||||
|
||||
gulp.task(
|
||||
"develop-hassio",
|
||||
@ -20,6 +22,8 @@ gulp.task(
|
||||
"clean-hassio",
|
||||
"gen-icons-json",
|
||||
"gen-index-hassio-dev",
|
||||
"build-supervisor-translations",
|
||||
"copy-translations-supervisor",
|
||||
env.useRollup() ? "rollup-watch-hassio" : "webpack-watch-hassio"
|
||||
)
|
||||
);
|
||||
@ -32,6 +36,8 @@ gulp.task(
|
||||
},
|
||||
"clean-hassio",
|
||||
"gen-icons-json",
|
||||
"build-supervisor-translations",
|
||||
"copy-translations-supervisor",
|
||||
env.useRollup() ? "rollup-prod-hassio" : "webpack-prod-hassio",
|
||||
"gen-index-hassio-prod",
|
||||
...// Don't compress running tests
|
||||
|
@ -266,6 +266,7 @@ gulp.task(taskName, function () {
|
||||
TRANSLATION_FRAGMENTS.forEach((fragment) => {
|
||||
delete data.ui.panel[fragment];
|
||||
});
|
||||
delete data.supervisor;
|
||||
return data;
|
||||
})
|
||||
)
|
||||
@ -342,6 +343,62 @@ gulp.task(
|
||||
}
|
||||
);
|
||||
|
||||
gulp.task("build-translation-fragment-supervisor", function () {
|
||||
return gulp
|
||||
.src(fullDir + "/*.json")
|
||||
.pipe(transform((data) => data.supervisor))
|
||||
.pipe(gulp.dest(workDir + "/supervisor"));
|
||||
});
|
||||
|
||||
gulp.task("build-translation-flatten-supervisor", function () {
|
||||
return gulp
|
||||
.src(workDir + "/supervisor/*.json")
|
||||
.pipe(
|
||||
transform(function (data) {
|
||||
// Polymer.AppLocalizeBehavior requires flattened json
|
||||
return flatten(data);
|
||||
})
|
||||
)
|
||||
.pipe(gulp.dest(outDir));
|
||||
});
|
||||
|
||||
gulp.task("build-translation-write-metadata", function writeMetadata() {
|
||||
return gulp
|
||||
.src(
|
||||
[
|
||||
path.join(paths.translations_src, "translationMetadata.json"),
|
||||
workDir + "/testMetadata.json",
|
||||
workDir + "/translationFingerprints.json",
|
||||
],
|
||||
{ allowEmpty: true }
|
||||
)
|
||||
.pipe(merge({}))
|
||||
.pipe(
|
||||
transform(function (data) {
|
||||
const newData = {};
|
||||
Object.entries(data).forEach(([key, value]) => {
|
||||
// Filter out translations without native name.
|
||||
if (value.nativeName) {
|
||||
newData[key] = value;
|
||||
} else {
|
||||
console.warn(
|
||||
`Skipping language ${key}. Native name was not translated.`
|
||||
);
|
||||
}
|
||||
});
|
||||
return newData;
|
||||
})
|
||||
)
|
||||
.pipe(
|
||||
transform((data) => ({
|
||||
fragments: TRANSLATION_FRAGMENTS,
|
||||
translations: data,
|
||||
}))
|
||||
)
|
||||
.pipe(rename("translationMetadata.json"))
|
||||
.pipe(gulp.dest(workDir));
|
||||
});
|
||||
|
||||
gulp.task(
|
||||
"build-translations",
|
||||
gulp.series(
|
||||
@ -353,41 +410,20 @@ gulp.task(
|
||||
gulp.parallel(...splitTasks),
|
||||
"build-flattened-translations",
|
||||
"build-translation-fingerprints",
|
||||
function writeMetadata() {
|
||||
return gulp
|
||||
.src(
|
||||
[
|
||||
path.join(paths.translations_src, "translationMetadata.json"),
|
||||
workDir + "/testMetadata.json",
|
||||
workDir + "/translationFingerprints.json",
|
||||
],
|
||||
{ allowEmpty: true }
|
||||
)
|
||||
.pipe(merge({}))
|
||||
.pipe(
|
||||
transform(function (data) {
|
||||
const newData = {};
|
||||
Object.entries(data).forEach(([key, value]) => {
|
||||
// Filter out translations without native name.
|
||||
if (value.nativeName) {
|
||||
newData[key] = value;
|
||||
} else {
|
||||
console.warn(
|
||||
`Skipping language ${key}. Native name was not translated.`
|
||||
);
|
||||
}
|
||||
});
|
||||
return newData;
|
||||
})
|
||||
)
|
||||
.pipe(
|
||||
transform((data) => ({
|
||||
fragments: TRANSLATION_FRAGMENTS,
|
||||
translations: data,
|
||||
}))
|
||||
)
|
||||
.pipe(rename("translationMetadata.json"))
|
||||
.pipe(gulp.dest(workDir));
|
||||
}
|
||||
"build-translation-write-metadata"
|
||||
)
|
||||
);
|
||||
|
||||
gulp.task(
|
||||
"build-supervisor-translations",
|
||||
gulp.series(
|
||||
"clean-translations",
|
||||
"ensure-translations-build-dir",
|
||||
"build-master-translation",
|
||||
"build-merged-translations",
|
||||
"build-translation-fragment-supervisor",
|
||||
"build-translation-flatten-supervisor",
|
||||
"build-translation-fingerprints",
|
||||
"build-translation-write-metadata"
|
||||
)
|
||||
);
|
||||
|
@ -137,7 +137,12 @@ gulp.task("webpack-watch-hassio", () => {
|
||||
isProdBuild: false,
|
||||
latestBuild: true,
|
||||
})
|
||||
).watch({}, doneHandler());
|
||||
).watch({ ignored: /build-translations/ }, doneHandler());
|
||||
|
||||
gulp.watch(
|
||||
path.join(paths.translations_src, "en.json"),
|
||||
gulp.series("build-supervisor-translations", "copy-translations-supervisor")
|
||||
);
|
||||
});
|
||||
|
||||
gulp.task("webpack-prod-hassio", () =>
|
||||
|
@ -34,6 +34,7 @@ module.exports = {
|
||||
|
||||
hassio_dir: path.resolve(__dirname, "../hassio"),
|
||||
hassio_output_root: path.resolve(__dirname, "../hassio/build"),
|
||||
hassio_output_static: path.resolve(__dirname, "../hassio/build/static"),
|
||||
hassio_output_latest: path.resolve(
|
||||
__dirname,
|
||||
"../hassio/build/frontend_latest"
|
||||
|
@ -77,13 +77,16 @@ class HassioAddonStore extends LitElement {
|
||||
return html`
|
||||
<hass-tabs-subpage
|
||||
.hass=${this.hass}
|
||||
.localizeFunc=${this.supervisor.localize}
|
||||
.narrow=${this.narrow}
|
||||
.route=${this.route}
|
||||
hassio
|
||||
main-page
|
||||
.tabs=${supervisorTabs}
|
||||
main-page
|
||||
supervisor
|
||||
>
|
||||
<span slot="header">Add-on Store</span>
|
||||
<span slot="header">
|
||||
${this.supervisor.localize("panel.store")}
|
||||
</span>
|
||||
<ha-button-menu
|
||||
corner="BOTTOM_START"
|
||||
slot="toolbar-icon"
|
||||
|
@ -62,6 +62,15 @@ class HassioAddonConfig extends LitElement {
|
||||
|
||||
@query("ha-yaml-editor") private _editor?: HaYamlEditor;
|
||||
|
||||
public computeLabel = (entry: HaFormSchema): string => {
|
||||
return (
|
||||
this.addon.translations[this.hass.language]?.configuration?.[entry.name]
|
||||
?.name ||
|
||||
this.addon.translations.en?.configuration?.[entry.name].name ||
|
||||
entry.name
|
||||
);
|
||||
};
|
||||
|
||||
private _filteredShchema = memoizeOne(
|
||||
(options: Record<string, unknown>, schema: HaFormSchema[]) => {
|
||||
return schema.filter((entry) => entry.name in options || entry.required);
|
||||
@ -102,6 +111,7 @@ class HassioAddonConfig extends LitElement {
|
||||
? html`<ha-form
|
||||
.data=${this._options!}
|
||||
@value-changed=${this._configChanged}
|
||||
.computeLabel=${this.computeLabel}
|
||||
.schema=${this._showOptional
|
||||
? this.addon.schema!
|
||||
: this._filteredShchema(
|
||||
|
@ -80,6 +80,7 @@ class HassioAddonDashboard extends LitElement {
|
||||
const addonTabs: PageNavigation[] = [
|
||||
{
|
||||
name: "Info",
|
||||
translationKey: "addon.panel.info",
|
||||
path: `/hassio/addon/${this.addon.slug}/info`,
|
||||
iconPath: mdiInformationVariant,
|
||||
},
|
||||
@ -88,6 +89,7 @@ class HassioAddonDashboard extends LitElement {
|
||||
if (this.addon.documentation) {
|
||||
addonTabs.push({
|
||||
name: "Documentation",
|
||||
translationKey: "addon.panel.documentation",
|
||||
path: `/hassio/addon/${this.addon.slug}/documentation`,
|
||||
iconPath: mdiFileDocument,
|
||||
});
|
||||
@ -97,11 +99,13 @@ class HassioAddonDashboard extends LitElement {
|
||||
addonTabs.push(
|
||||
{
|
||||
name: "Configuration",
|
||||
translationKey: "addon.panel.configuration",
|
||||
path: `/hassio/addon/${this.addon.slug}/config`,
|
||||
iconPath: mdiCogs,
|
||||
},
|
||||
{
|
||||
name: "Log",
|
||||
translationKey: "addon.panel.log",
|
||||
path: `/hassio/addon/${this.addon.slug}/logs`,
|
||||
iconPath: mdiMathLog,
|
||||
}
|
||||
@ -113,11 +117,12 @@ class HassioAddonDashboard extends LitElement {
|
||||
return html`
|
||||
<hass-tabs-subpage
|
||||
.hass=${this.hass}
|
||||
.localizeFunc=${this.supervisor.localize}
|
||||
.narrow=${this.narrow}
|
||||
.backPath=${this.addon.version ? "/hassio/dashboard" : "/hassio/store"}
|
||||
.route=${route}
|
||||
hassio
|
||||
.tabs=${addonTabs}
|
||||
supervisor
|
||||
>
|
||||
<span slot="header">${this.addon.name}</span>
|
||||
<hassio-addon-router
|
||||
|
@ -27,17 +27,15 @@ class HassioAddons extends LitElement {
|
||||
protected render(): TemplateResult {
|
||||
return html`
|
||||
<div class="content">
|
||||
<h1>Add-ons</h1>
|
||||
<h1>${this.supervisor.localize("dashboard.addons")}</h1>
|
||||
<div class="card-group">
|
||||
${!this.supervisor.supervisor.addons?.length
|
||||
? html`
|
||||
<ha-card>
|
||||
<div class="card-content">
|
||||
You don't have any add-ons installed yet. Head over to
|
||||
<button class="link" @click=${this._openStore}>
|
||||
the add-on store
|
||||
${this.supervisor.localize("dashboard.no_addons")}
|
||||
</button>
|
||||
to get started!
|
||||
</div>
|
||||
</ha-card>
|
||||
`
|
||||
@ -58,10 +56,16 @@ class HassioAddons extends LitElement {
|
||||
? mdiArrowUpBoldCircle
|
||||
: mdiPuzzle}
|
||||
.iconTitle=${addon.state !== "started"
|
||||
? "Add-on is stopped"
|
||||
? this.supervisor.localize(
|
||||
"dashboard.addon_stopped"
|
||||
)
|
||||
: addon.update_available!
|
||||
? "New version available"
|
||||
: "Add-on is running"}
|
||||
? this.supervisor.localize(
|
||||
"dashboard.addon_new_version"
|
||||
)
|
||||
: this.supervisor.localize(
|
||||
"dashboard.addon_running"
|
||||
)}
|
||||
.iconClass=${addon.update_available
|
||||
? addon.state === "started"
|
||||
? "update"
|
||||
|
@ -29,13 +29,16 @@ class HassioDashboard extends LitElement {
|
||||
return html`
|
||||
<hass-tabs-subpage
|
||||
.hass=${this.hass}
|
||||
.localizeFunc=${this.supervisor.localize}
|
||||
.narrow=${this.narrow}
|
||||
hassio
|
||||
main-page
|
||||
.route=${this.route}
|
||||
.tabs=${supervisorTabs}
|
||||
main-page
|
||||
supervisor
|
||||
>
|
||||
<span slot="header">Dashboard</span>
|
||||
<span slot="header">
|
||||
${this.supervisor.localize("panel.dashboard")}
|
||||
</span>
|
||||
<div class="content">
|
||||
<hassio-update
|
||||
.hass=${this.hass}
|
||||
|
@ -10,9 +10,11 @@ import {
|
||||
TemplateResult,
|
||||
} from "lit-element";
|
||||
import memoizeOne from "memoize-one";
|
||||
import { atLeastVersion } from "../../../src/common/config/version";
|
||||
import { fireEvent } from "../../../src/common/dom/fire_event";
|
||||
import "../../../src/components/buttons/ha-progress-button";
|
||||
import "../../../src/components/ha-card";
|
||||
import "../../../src/components/ha-settings-row";
|
||||
import "../../../src/components/ha-svg-icon";
|
||||
import {
|
||||
extractApiErrorMessage,
|
||||
@ -24,7 +26,10 @@ import {
|
||||
HassioHomeAssistantInfo,
|
||||
HassioSupervisorInfo,
|
||||
} from "../../../src/data/hassio/supervisor";
|
||||
import { Supervisor } from "../../../src/data/supervisor/supervisor";
|
||||
import {
|
||||
Supervisor,
|
||||
supervisorApiWsRequest,
|
||||
} from "../../../src/data/supervisor/supervisor";
|
||||
import {
|
||||
showAlertDialog,
|
||||
showConfirmationDialog,
|
||||
@ -34,6 +39,10 @@ import { HomeAssistant } from "../../../src/types";
|
||||
import { showDialogSupervisorCoreUpdate } from "../dialogs/core/show-dialog-core-update";
|
||||
import { hassioStyle } from "../resources/hassio-style";
|
||||
|
||||
const computeVersion = (key: string, version: string): string => {
|
||||
return key === "os" ? version : `${key}-${version}`;
|
||||
};
|
||||
|
||||
@customElement("hassio-update")
|
||||
export class HassioUpdate extends LitElement {
|
||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||
@ -59,9 +68,12 @@ export class HassioUpdate extends LitElement {
|
||||
return html`
|
||||
<div class="content">
|
||||
<h1>
|
||||
${updatesAvailable > 1
|
||||
? "Updates Available 🎉"
|
||||
: "Update Available 🎉"}
|
||||
${this.supervisor.localize(
|
||||
"dashboard.update_available",
|
||||
"count",
|
||||
updatesAvailable
|
||||
)}
|
||||
🎉
|
||||
</h1>
|
||||
<div class="card-group">
|
||||
${this._renderUpdateCard(
|
||||
@ -110,14 +122,30 @@ export class HassioUpdate extends LitElement {
|
||||
<div class="icon">
|
||||
<ha-svg-icon .path=${mdiHomeAssistant}></ha-svg-icon>
|
||||
</div>
|
||||
<div class="update-heading">${name} ${object.version_latest}</div>
|
||||
<div class="warning">
|
||||
You are currently running version ${object.version}
|
||||
</div>
|
||||
<div class="update-heading">${name}</div>
|
||||
<ha-settings-row two-line>
|
||||
<span slot="heading">
|
||||
${this.supervisor.localize("common.version")}
|
||||
</span>
|
||||
<span slot="description">
|
||||
${computeVersion(key, object.version!)}
|
||||
</span>
|
||||
</ha-settings-row>
|
||||
|
||||
<ha-settings-row two-line>
|
||||
<span slot="heading">
|
||||
${this.supervisor.localize("common.newest_version")}
|
||||
</span>
|
||||
<span slot="description">
|
||||
${computeVersion(key, object.version_latest!)}
|
||||
</span>
|
||||
</ha-settings-row>
|
||||
</div>
|
||||
<div class="card-actions">
|
||||
<a href="${releaseNotesUrl}" target="_blank" rel="noreferrer">
|
||||
<mwc-button>Release notes</mwc-button>
|
||||
<mwc-button>
|
||||
${this.supervisor.localize("common.release_notes")}
|
||||
</mwc-button>
|
||||
</a>
|
||||
<ha-progress-button
|
||||
.apiPath=${apiPath}
|
||||
@ -126,7 +154,7 @@ export class HassioUpdate extends LitElement {
|
||||
.version=${object.version_latest}
|
||||
@click=${this._confirmUpdate}
|
||||
>
|
||||
Update
|
||||
${this.supervisor.localize("common.update")}
|
||||
</ha-progress-button>
|
||||
</div>
|
||||
</ha-card>
|
||||
@ -141,10 +169,20 @@ export class HassioUpdate extends LitElement {
|
||||
}
|
||||
item.progress = true;
|
||||
const confirmed = await showConfirmationDialog(this, {
|
||||
title: `Update ${item.name}`,
|
||||
text: `Are you sure you want to update ${item.name} to version ${item.version}?`,
|
||||
confirmText: "update",
|
||||
dismissText: "cancel",
|
||||
title: this.supervisor.localize(
|
||||
"confirm.update.title",
|
||||
"name",
|
||||
item.name
|
||||
),
|
||||
text: this.supervisor.localize(
|
||||
"confirm.update.text",
|
||||
"name",
|
||||
item.name,
|
||||
"version",
|
||||
computeVersion(item.key, item.version)
|
||||
),
|
||||
confirmText: this.supervisor.localize("common.update"),
|
||||
dismissText: this.supervisor.localize("common.cancel"),
|
||||
});
|
||||
|
||||
if (!confirmed) {
|
||||
@ -152,7 +190,15 @@ export class HassioUpdate extends LitElement {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
await this.hass.callApi<HassioResponse<void>>("POST", item.apiPath);
|
||||
if (atLeastVersion(this.hass.config.version, 2021, 2, 4)) {
|
||||
await supervisorApiWsRequest(this.hass.connection, {
|
||||
method: "post",
|
||||
endpoint: item.apiPath.replace("hassio", ""),
|
||||
timeout: null,
|
||||
});
|
||||
} else {
|
||||
await this.hass.callApi<HassioResponse<void>>("POST", item.apiPath);
|
||||
}
|
||||
fireEvent(this, "supervisor-colllection-refresh", {
|
||||
colllection: item.key,
|
||||
});
|
||||
@ -165,7 +211,7 @@ export class HassioUpdate extends LitElement {
|
||||
!ignoredStatusCodes.has(err.status_code)
|
||||
) {
|
||||
showAlertDialog(this, {
|
||||
title: "Update failed",
|
||||
title: this.supervisor.localize("error.update_failed"),
|
||||
text: extractApiErrorMessage(err),
|
||||
});
|
||||
}
|
||||
@ -190,9 +236,6 @@ export class HassioUpdate extends LitElement {
|
||||
margin-bottom: 0.5em;
|
||||
color: var(--primary-text-color);
|
||||
}
|
||||
.warning {
|
||||
color: var(--secondary-text-color);
|
||||
}
|
||||
.card-content {
|
||||
height: calc(100% - 47px);
|
||||
box-sizing: border-box;
|
||||
@ -200,13 +243,13 @@ export class HassioUpdate extends LitElement {
|
||||
.card-actions {
|
||||
text-align: right;
|
||||
}
|
||||
.errors {
|
||||
color: var(--error-color);
|
||||
padding: 16px;
|
||||
}
|
||||
a {
|
||||
text-decoration: none;
|
||||
}
|
||||
ha-settings-row {
|
||||
padding: 0;
|
||||
--paper-item-body-two-line-min-height: 32px;
|
||||
}
|
||||
`,
|
||||
];
|
||||
}
|
||||
|
@ -3,7 +3,7 @@ import { atLeastVersion } from "../../src/common/config/version";
|
||||
import { applyThemesOnElement } from "../../src/common/dom/apply_themes_on_element";
|
||||
import { fireEvent } from "../../src/common/dom/fire_event";
|
||||
import { HassioPanelInfo } from "../../src/data/hassio/supervisor";
|
||||
import { supervisorCollection } from "../../src/data/supervisor/supervisor";
|
||||
import { Supervisor } from "../../src/data/supervisor/supervisor";
|
||||
import { makeDialogManager } from "../../src/dialogs/make-dialog-manager";
|
||||
import "../../src/layouts/hass-loading-screen";
|
||||
import { HomeAssistant, Route } from "../../src/types";
|
||||
@ -14,6 +14,8 @@ import { SupervisorBaseElement } from "./supervisor-base-element";
|
||||
export class HassioMain extends SupervisorBaseElement {
|
||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||
|
||||
@property({ attribute: false }) public supervisor!: Supervisor;
|
||||
|
||||
@property({ attribute: false }) public panel!: HassioPanelInfo;
|
||||
|
||||
@property({ type: Boolean }) public narrow!: boolean;
|
||||
@ -72,18 +74,6 @@ export class HassioMain extends SupervisorBaseElement {
|
||||
}
|
||||
|
||||
protected render() {
|
||||
if (!this.supervisor || !this.hass) {
|
||||
return html`<hass-loading-screen></hass-loading-screen>`;
|
||||
}
|
||||
|
||||
if (
|
||||
Object.keys(supervisorCollection).some(
|
||||
(colllection) => !this.supervisor![colllection]
|
||||
)
|
||||
) {
|
||||
return html`<hass-loading-screen></hass-loading-screen>`;
|
||||
}
|
||||
|
||||
return html`
|
||||
<hassio-router
|
||||
.hass=${this.hass}
|
||||
|
@ -7,7 +7,10 @@ import {
|
||||
property,
|
||||
TemplateResult,
|
||||
} from "lit-element";
|
||||
import { Supervisor } from "../../src/data/supervisor/supervisor";
|
||||
import {
|
||||
Supervisor,
|
||||
supervisorCollection,
|
||||
} from "../../src/data/supervisor/supervisor";
|
||||
import { HomeAssistant, Route } from "../../src/types";
|
||||
import "./hassio-panel-router";
|
||||
|
||||
@ -22,6 +25,17 @@ class HassioPanel extends LitElement {
|
||||
@property({ attribute: false }) public route!: Route;
|
||||
|
||||
protected render(): TemplateResult {
|
||||
if (!this.hass) {
|
||||
return html`<hass-loading-screen></hass-loading-screen>`;
|
||||
}
|
||||
|
||||
if (
|
||||
Object.keys(supervisorCollection).some(
|
||||
(colllection) => !this.supervisor[colllection]
|
||||
)
|
||||
) {
|
||||
return html`<hass-loading-screen></hass-loading-screen>`;
|
||||
}
|
||||
return html`
|
||||
<hassio-panel-router
|
||||
.hass=${this.hass}
|
||||
|
@ -3,22 +3,22 @@ import type { PageNavigation } from "../../src/layouts/hass-tabs-subpage";
|
||||
|
||||
export const supervisorTabs: PageNavigation[] = [
|
||||
{
|
||||
name: "Dashboard",
|
||||
translationKey: "panel.dashboard",
|
||||
path: `/hassio/dashboard`,
|
||||
iconPath: mdiViewDashboard,
|
||||
},
|
||||
{
|
||||
name: "Add-on Store",
|
||||
translationKey: "panel.store",
|
||||
path: `/hassio/store`,
|
||||
iconPath: mdiStore,
|
||||
},
|
||||
{
|
||||
name: "Snapshots",
|
||||
translationKey: "panel.snapshots",
|
||||
path: `/hassio/snapshots`,
|
||||
iconPath: mdiBackupRestore,
|
||||
},
|
||||
{
|
||||
name: "System",
|
||||
translationKey: "panel.system",
|
||||
path: `/hassio/system`,
|
||||
iconPath: mdiCogs,
|
||||
},
|
||||
|
@ -104,13 +104,16 @@ class HassioSnapshots extends LitElement {
|
||||
return html`
|
||||
<hass-tabs-subpage
|
||||
.hass=${this.hass}
|
||||
.localizeFunc=${this.supervisor.localize}
|
||||
.narrow=${this.narrow}
|
||||
hassio
|
||||
main-page
|
||||
.route=${this.route}
|
||||
.tabs=${supervisorTabs}
|
||||
main-page
|
||||
supervisor
|
||||
>
|
||||
<span slot="header">Snapshots</span>
|
||||
<span slot="header">
|
||||
${this.supervisor.localize("panel.snapshots")}
|
||||
</span>
|
||||
<ha-button-menu
|
||||
corner="BOTTOM_START"
|
||||
slot="toolbar-icon"
|
||||
|
@ -6,6 +6,7 @@ import {
|
||||
PropertyValues,
|
||||
} from "lit-element";
|
||||
import { atLeastVersion } from "../../src/common/config/version";
|
||||
import { computeLocalize } from "../../src/common/translations/localize";
|
||||
import { fetchHassioAddonsInfo } from "../../src/data/hassio/addon";
|
||||
import { HassioResponse } from "../../src/data/hassio/common";
|
||||
import {
|
||||
@ -29,6 +30,7 @@ import {
|
||||
} from "../../src/data/supervisor/supervisor";
|
||||
import { ProvideHassLitMixin } from "../../src/mixins/provide-hass-lit-mixin";
|
||||
import { urlSyncMixin } from "../../src/state/url-sync-mixin";
|
||||
import { getTranslation } from "../../src/util/common-translation";
|
||||
|
||||
declare global {
|
||||
interface HASSDomEvents {
|
||||
@ -40,7 +42,9 @@ declare global {
|
||||
export class SupervisorBaseElement extends urlSyncMixin(
|
||||
ProvideHassLitMixin(LitElement)
|
||||
) {
|
||||
@property({ attribute: false }) public supervisor?: Supervisor;
|
||||
@property({ attribute: false }) public supervisor: Partial<Supervisor> = {
|
||||
localize: () => "",
|
||||
};
|
||||
|
||||
@internalProperty() private _unsubs: Record<string, UnsubscribeFunc> = {};
|
||||
|
||||
@ -49,6 +53,15 @@ export class SupervisorBaseElement extends urlSyncMixin(
|
||||
Collection<unknown>
|
||||
> = {};
|
||||
|
||||
@internalProperty() private _resources?: Record<string, any>;
|
||||
|
||||
@internalProperty() private _language = "en";
|
||||
|
||||
public connectedCallback(): void {
|
||||
super.connectedCallback();
|
||||
this._initializeLocalize();
|
||||
}
|
||||
|
||||
public disconnectedCallback() {
|
||||
super.disconnectedCallback();
|
||||
Object.keys(this._unsubs).forEach((unsub) => {
|
||||
@ -56,15 +69,50 @@ export class SupervisorBaseElement extends urlSyncMixin(
|
||||
});
|
||||
}
|
||||
|
||||
protected updated(changedProperties: PropertyValues) {
|
||||
super.updated(changedProperties);
|
||||
|
||||
if (changedProperties.has("_language")) {
|
||||
if (changedProperties.get("_language") !== this._language) {
|
||||
this._initializeLocalize();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected _updateSupervisor(obj: Partial<Supervisor>): void {
|
||||
this.supervisor = { ...this.supervisor!, ...obj };
|
||||
this.supervisor = { ...this.supervisor, ...obj };
|
||||
}
|
||||
|
||||
protected firstUpdated(changedProps: PropertyValues): void {
|
||||
super.firstUpdated(changedProps);
|
||||
if (this._language !== this.hass.language) {
|
||||
this._language = this.hass.language;
|
||||
}
|
||||
this._initializeLocalize();
|
||||
this._initSupervisor();
|
||||
}
|
||||
|
||||
private async _initializeLocalize() {
|
||||
const { language, data } = await getTranslation(
|
||||
null,
|
||||
this._language,
|
||||
"/api/hassio/app/static/translations"
|
||||
);
|
||||
|
||||
this._resources = {
|
||||
[language]: data,
|
||||
};
|
||||
|
||||
this.supervisor = {
|
||||
...this.supervisor,
|
||||
localize: await computeLocalize(
|
||||
this.constructor.prototype,
|
||||
this._language,
|
||||
this._resources
|
||||
),
|
||||
};
|
||||
}
|
||||
|
||||
private async _handleSupervisorStoreRefreshEvent(ev) {
|
||||
const colllection = ev.detail.colllection;
|
||||
if (atLeastVersion(this.hass.config.version, 2021, 2, 4)) {
|
||||
@ -104,52 +152,54 @@ export class SupervisorBaseElement extends urlSyncMixin(
|
||||
}
|
||||
});
|
||||
|
||||
if (this.supervisor === undefined) {
|
||||
Object.keys(this._collections).forEach((collection) =>
|
||||
Object.keys(this._collections).forEach((collection) => {
|
||||
if (
|
||||
this.supervisor === undefined ||
|
||||
this.supervisor[collection] === undefined
|
||||
) {
|
||||
this._updateSupervisor({
|
||||
[collection]: this._collections[collection].state,
|
||||
})
|
||||
);
|
||||
}
|
||||
return;
|
||||
});
|
||||
}
|
||||
});
|
||||
} else {
|
||||
const [
|
||||
addon,
|
||||
supervisor,
|
||||
host,
|
||||
core,
|
||||
info,
|
||||
os,
|
||||
network,
|
||||
resolution,
|
||||
store,
|
||||
] = await Promise.all([
|
||||
fetchHassioAddonsInfo(this.hass),
|
||||
fetchHassioSupervisorInfo(this.hass),
|
||||
fetchHassioHostInfo(this.hass),
|
||||
fetchHassioHomeAssistantInfo(this.hass),
|
||||
fetchHassioInfo(this.hass),
|
||||
fetchHassioHassOsInfo(this.hass),
|
||||
fetchNetworkInfo(this.hass),
|
||||
fetchHassioResolution(this.hass),
|
||||
fetchSupervisorStore(this.hass),
|
||||
]);
|
||||
|
||||
this.supervisor = {
|
||||
addon,
|
||||
supervisor,
|
||||
host,
|
||||
core,
|
||||
info,
|
||||
os,
|
||||
network,
|
||||
resolution,
|
||||
store,
|
||||
};
|
||||
|
||||
this.addEventListener("supervisor-update", (ev) =>
|
||||
this._updateSupervisor(ev.detail)
|
||||
);
|
||||
}
|
||||
|
||||
const [
|
||||
addon,
|
||||
supervisor,
|
||||
host,
|
||||
core,
|
||||
info,
|
||||
os,
|
||||
network,
|
||||
resolution,
|
||||
store,
|
||||
] = await Promise.all([
|
||||
fetchHassioAddonsInfo(this.hass),
|
||||
fetchHassioSupervisorInfo(this.hass),
|
||||
fetchHassioHostInfo(this.hass),
|
||||
fetchHassioHomeAssistantInfo(this.hass),
|
||||
fetchHassioInfo(this.hass),
|
||||
fetchHassioHassOsInfo(this.hass),
|
||||
fetchNetworkInfo(this.hass),
|
||||
fetchHassioResolution(this.hass),
|
||||
fetchSupervisorStore(this.hass),
|
||||
]);
|
||||
|
||||
this.supervisor = {
|
||||
addon,
|
||||
supervisor,
|
||||
host,
|
||||
core,
|
||||
info,
|
||||
os,
|
||||
network,
|
||||
resolution,
|
||||
store,
|
||||
};
|
||||
|
||||
this.addEventListener("supervisor-update", (ev) =>
|
||||
this._updateSupervisor(ev.detail)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -32,13 +32,16 @@ class HassioSystem extends LitElement {
|
||||
return html`
|
||||
<hass-tabs-subpage
|
||||
.hass=${this.hass}
|
||||
.localizeFunc=${this.supervisor.localize}
|
||||
.narrow=${this.narrow}
|
||||
hassio
|
||||
main-page
|
||||
.route=${this.route}
|
||||
.tabs=${supervisorTabs}
|
||||
main-page
|
||||
supervisor
|
||||
>
|
||||
<span slot="header">System</span>
|
||||
<span slot="header">
|
||||
${this.supervisor.localize("panel.system")}
|
||||
</span>
|
||||
<div class="content">
|
||||
<div class="card-group">
|
||||
<hassio-core-info
|
||||
|
@ -8,9 +8,10 @@ export const atLeastVersion = (
|
||||
|
||||
return (
|
||||
Number(haMajor) > major ||
|
||||
(Number(haMajor) === major && (patch === undefined
|
||||
? Number(haMinor) >= minor
|
||||
: Number(haMinor) > minor)) ||
|
||||
(Number(haMajor) === major &&
|
||||
(patch === undefined
|
||||
? Number(haMinor) >= minor
|
||||
: Number(haMinor) > minor)) ||
|
||||
(patch !== undefined &&
|
||||
Number(haMajor) === major &&
|
||||
Number(haMinor) === minor &&
|
||||
|
@ -16,6 +16,10 @@ export type AddonStartup =
|
||||
export type AddonState = "started" | "stopped" | null;
|
||||
export type AddonRepository = "core" | "local" | string;
|
||||
|
||||
interface AddonTranslations {
|
||||
[key: string]: Record<string, Record<string, Record<string, string>>>;
|
||||
}
|
||||
|
||||
export interface HassioAddonInfo {
|
||||
advanced: boolean;
|
||||
available: boolean;
|
||||
@ -82,6 +86,7 @@ export interface HassioAddonDetails extends HassioAddonInfo {
|
||||
slug: string;
|
||||
startup: AddonStartup;
|
||||
stdin: boolean;
|
||||
translations: AddonTranslations;
|
||||
watchdog: null | boolean;
|
||||
webui: null | string;
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
import { Connection, getCollection } from "home-assistant-js-websocket";
|
||||
import { Store } from "home-assistant-js-websocket/dist/store";
|
||||
import { LocalizeFunc } from "../../common/translations/localize";
|
||||
import { HomeAssistant } from "../../types";
|
||||
import { HassioAddonsInfo } from "../hassio/addon";
|
||||
import { HassioHassOSInfo, HassioHostInfo } from "../hassio/host";
|
||||
@ -46,6 +47,7 @@ interface supervisorApiRequest {
|
||||
method?: "get" | "post" | "delete" | "put";
|
||||
force_rest?: boolean;
|
||||
data?: any;
|
||||
timeout?: number | null;
|
||||
}
|
||||
|
||||
export interface SupervisorEvent {
|
||||
@ -65,6 +67,7 @@ export interface Supervisor {
|
||||
os: HassioHassOSInfo;
|
||||
addon: HassioAddonsInfo;
|
||||
store: SupervisorStore;
|
||||
localize: LocalizeFunc;
|
||||
}
|
||||
|
||||
export const supervisorApiWsRequest = <T>(
|
||||
|
@ -7,7 +7,7 @@ import { computeLocalize } from "../common/translations/localize";
|
||||
import { DEFAULT_PANEL } from "../data/panel";
|
||||
import { translationMetadata } from "../resources/translations-metadata";
|
||||
import { HomeAssistant } from "../types";
|
||||
import { getLocalLanguage, getTranslation } from "../util/hass-translation";
|
||||
import { getTranslation, getLocalLanguage } from "../util/hass-translation";
|
||||
import { demoConfig } from "./demo_config";
|
||||
import { demoPanels } from "./demo_panels";
|
||||
import { demoServices } from "./demo_services";
|
||||
|
@ -16,6 +16,7 @@ import memoizeOne from "memoize-one";
|
||||
import { isComponentLoaded } from "../common/config/is_component_loaded";
|
||||
import { restoreScroll } from "../common/decorators/restore-scroll";
|
||||
import { navigate } from "../common/navigate";
|
||||
import { LocalizeFunc } from "../common/translations/localize";
|
||||
import { computeRTL } from "../common/util/compute_rtl";
|
||||
import "../components/ha-icon";
|
||||
import "../components/ha-icon-button-arrow-prev";
|
||||
@ -40,7 +41,9 @@ export interface PageNavigation {
|
||||
class HassTabsSubpage extends LitElement {
|
||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||
|
||||
@property({ type: Boolean }) public hassio = false;
|
||||
@property({ type: Boolean }) public supervisor = false;
|
||||
|
||||
@property({ attribute: false }) public localizeFunc?: LocalizeFunc;
|
||||
|
||||
@property({ type: String, attribute: "back-path" }) public backPath?: string;
|
||||
|
||||
@ -48,9 +51,9 @@ class HassTabsSubpage extends LitElement {
|
||||
|
||||
@property({ type: Boolean, attribute: "main-page" }) public mainPage = false;
|
||||
|
||||
@property() public route!: Route;
|
||||
@property({ attribute: false }) public route!: Route;
|
||||
|
||||
@property() public tabs!: PageNavigation[];
|
||||
@property({ attribute: false }) public tabs!: PageNavigation[];
|
||||
|
||||
@property({ type: Boolean, reflect: true }) public narrow = false;
|
||||
|
||||
@ -71,7 +74,8 @@ class HassTabsSubpage extends LitElement {
|
||||
showAdvanced: boolean | undefined,
|
||||
_components,
|
||||
_language,
|
||||
_narrow
|
||||
_narrow,
|
||||
localizeFunc
|
||||
) => {
|
||||
const shownTabs = tabs.filter(
|
||||
(page) =>
|
||||
@ -91,7 +95,7 @@ class HassTabsSubpage extends LitElement {
|
||||
.active=${page === activeTab}
|
||||
.narrow=${this.narrow}
|
||||
.name=${page.translationKey
|
||||
? this.hass.localize(page.translationKey)
|
||||
? localizeFunc(page.translationKey)
|
||||
: page.name}
|
||||
>
|
||||
${page.iconPath
|
||||
@ -130,7 +134,8 @@ class HassTabsSubpage extends LitElement {
|
||||
this.hass.userData?.showAdvanced,
|
||||
this.hass.config.components,
|
||||
this.hass.language,
|
||||
this.narrow
|
||||
this.narrow,
|
||||
this.localizeFunc || this.hass.localize
|
||||
);
|
||||
const showTabs = tabs.length > 1 || !this.narrow;
|
||||
return html`
|
||||
@ -138,7 +143,7 @@ class HassTabsSubpage extends LitElement {
|
||||
${this.mainPage
|
||||
? html`
|
||||
<ha-menu-button
|
||||
.hassio=${this.hassio}
|
||||
.hassio=${this.supervisor}
|
||||
.hass=${this.hass}
|
||||
.narrow=${this.narrow}
|
||||
></ha-menu-button>
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { LitElement, property, PropertyValues } from "lit-element";
|
||||
import { computeLocalize, LocalizeFunc } from "../common/translations/localize";
|
||||
import { Constructor, Resources } from "../types";
|
||||
import { getLocalLanguage, getTranslation } from "../util/hass-translation";
|
||||
import { getTranslation, getLocalLanguage } from "../util/hass-translation";
|
||||
|
||||
const empty = () => "";
|
||||
|
||||
|
@ -161,8 +161,8 @@ export class HaConfigDevicePage extends LitElement {
|
||||
const batteryState = batteryEntity
|
||||
? this.hass.states[batteryEntity.entity_id]
|
||||
: undefined;
|
||||
const batteryIsBinary = batteryState
|
||||
&& computeStateDomain(batteryState) === "binary_sensor";
|
||||
const batteryIsBinary =
|
||||
batteryState && computeStateDomain(batteryState) === "binary_sensor";
|
||||
const batteryChargingState = batteryChargingEntity
|
||||
? this.hass.states[batteryChargingEntity.entity_id]
|
||||
: undefined;
|
||||
|
@ -1,7 +1,7 @@
|
||||
import "@material/mwc-button";
|
||||
import {
|
||||
mdiInformationOutline,
|
||||
mdiClipboardTextMultipleOutline
|
||||
mdiClipboardTextMultipleOutline,
|
||||
} from "@mdi/js";
|
||||
import "@polymer/paper-checkbox/paper-checkbox";
|
||||
import "@polymer/paper-input/paper-input";
|
||||
@ -169,7 +169,10 @@ class HaPanelDevState extends EventsMixin(LocalizeMixin(PolymerElement)) {
|
||||
<th>[[localize('ui.panel.developer-tools.tabs.states.state')]]</th>
|
||||
<th hidden$="[[narrow]]">
|
||||
[[localize('ui.panel.developer-tools.tabs.states.attributes')]]
|
||||
<paper-checkbox checked="{{_showAttributes}}" on-change="{{saveAttributeCheckboxState}}"></paper-checkbox>
|
||||
<paper-checkbox
|
||||
checked="{{_showAttributes}}"
|
||||
on-change="{{saveAttributeCheckboxState}}"
|
||||
></paper-checkbox>
|
||||
</th>
|
||||
</tr>
|
||||
<tr>
|
||||
@ -285,7 +288,9 @@ class HaPanelDevState extends EventsMixin(LocalizeMixin(PolymerElement)) {
|
||||
|
||||
_showAttributes: {
|
||||
type: Boolean,
|
||||
value: JSON.parse(localStorage.getItem("devToolsShowAttributes") || true),
|
||||
value: JSON.parse(
|
||||
localStorage.getItem("devToolsShowAttributes") || true
|
||||
),
|
||||
},
|
||||
|
||||
_entities: {
|
||||
|
@ -199,7 +199,10 @@ class HuiPictureEntityCard extends LitElement implements LovelaceCard {
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background-color: var(--ha-picture-card-background-color, rgba(0, 0, 0, 0.3));
|
||||
background-color: var(
|
||||
--ha-picture-card-background-color,
|
||||
rgba(0, 0, 0, 0.3)
|
||||
);
|
||||
padding: 16px;
|
||||
font-size: 16px;
|
||||
line-height: 16px;
|
||||
|
@ -314,7 +314,10 @@ class HuiPictureGlanceCard extends LitElement implements LovelaceCard {
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
background-color: var(--ha-picture-card-background-color, rgba(0, 0, 0, 0.3));
|
||||
background-color: var(
|
||||
--ha-picture-card-background-color,
|
||||
rgba(0, 0, 0, 0.3)
|
||||
);
|
||||
padding: 4px 8px;
|
||||
font-size: 16px;
|
||||
line-height: 40px;
|
||||
|
@ -12,8 +12,8 @@ import { translationMetadata } from "../resources/translations-metadata";
|
||||
import { Constructor, HomeAssistant } from "../types";
|
||||
import { storeState } from "../util/ha-pref-storage";
|
||||
import {
|
||||
getLocalLanguage,
|
||||
getTranslation,
|
||||
getLocalLanguage,
|
||||
getUserLanguage,
|
||||
} from "../util/hass-translation";
|
||||
import { HassBaseEl } from "./hass-base-mixin";
|
||||
|
@ -3417,5 +3417,46 @@
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"supervisor": {
|
||||
"addon": {
|
||||
"panel": {
|
||||
"configuration": "Configuration",
|
||||
"documentation": "Documentation",
|
||||
"info": "Info",
|
||||
"log": "Log"
|
||||
}
|
||||
},
|
||||
"common": {
|
||||
"cancel": "Cancel",
|
||||
"newest_version": "Newest Version",
|
||||
"release_notes": "Release notes",
|
||||
"update": "Update",
|
||||
"version": "Version"
|
||||
},
|
||||
"confirm": {
|
||||
"update": {
|
||||
"title": "Update ${name}",
|
||||
"text": "Are you sure you want to update {name} to version {version}?"
|
||||
}
|
||||
},
|
||||
"dashboard": {
|
||||
"addon_new_version": "New version available",
|
||||
"addon_running": "Add-on is running",
|
||||
"addon_stopped": "Add-on is stopped",
|
||||
"addons": "Add-ons",
|
||||
"no_addons": "You don't have any add-ons installed yet. Head over to the add-on store to get started!",
|
||||
"update_available": "{count, plural,\n one {Update}\n other {{count} Updates}\n} pending"
|
||||
},
|
||||
"error": {
|
||||
"unknown": "Unknown error",
|
||||
"update_failed": "Update failed"
|
||||
},
|
||||
"panel": {
|
||||
"dashboard": "Dashboard",
|
||||
"snapshots": "Snapshots",
|
||||
"store": "Add-on Store",
|
||||
"system": "System"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
56
src/util/common-translation.ts
Normal file
56
src/util/common-translation.ts
Normal file
@ -0,0 +1,56 @@
|
||||
import { translationMetadata } from "../resources/translations-metadata";
|
||||
|
||||
const DEFAULT_BASE_URL = "/static/translations";
|
||||
|
||||
// Store loaded translations in memory so translations are available immediately
|
||||
// when DOM is created in Polymer. Even a cache lookup creates noticeable latency.
|
||||
const translations = {};
|
||||
|
||||
async function fetchTranslation(fingerprint: string, base_url: string) {
|
||||
const response = await fetch(`${base_url}/${fingerprint}`, {
|
||||
credentials: "same-origin",
|
||||
});
|
||||
if (!response.ok) {
|
||||
throw new Error(
|
||||
`Fail to fetch translation ${fingerprint}: HTTP response status is ${response.status}`
|
||||
);
|
||||
}
|
||||
return response.json();
|
||||
}
|
||||
|
||||
export async function getTranslation(
|
||||
fragment: string | null,
|
||||
language: string,
|
||||
base_url?: string
|
||||
) {
|
||||
const metadata = translationMetadata.translations[language];
|
||||
if (!metadata) {
|
||||
if (language !== "en") {
|
||||
return getTranslation(fragment, "en", base_url);
|
||||
}
|
||||
throw new Error("Language en is not found in metadata");
|
||||
}
|
||||
|
||||
// nl-abcd.jon or logbook/nl-abcd.json
|
||||
const fingerprint = `${fragment ? fragment + "/" : ""}${language}-${
|
||||
metadata.hash
|
||||
}.json`;
|
||||
|
||||
// Fetch translation from the server
|
||||
if (!translations[fingerprint]) {
|
||||
translations[fingerprint] = fetchTranslation(
|
||||
fingerprint,
|
||||
base_url || DEFAULT_BASE_URL
|
||||
)
|
||||
.then((data) => ({ language, data }))
|
||||
.catch((error) => {
|
||||
delete translations[fingerprint];
|
||||
if (language !== "en") {
|
||||
// Couldn't load selected translation. Try a fall back to en before failing.
|
||||
return getTranslation(fragment, "en", base_url);
|
||||
}
|
||||
return Promise.reject(error);
|
||||
});
|
||||
}
|
||||
return translations[fingerprint];
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
import { fetchTranslationPreferences } from "../data/translation";
|
||||
import { translationMetadata } from "../resources/translations-metadata";
|
||||
import { HomeAssistant } from "../types";
|
||||
import { getTranslation as commonGetTranslation } from "./common-translation";
|
||||
|
||||
const STORAGE = window.localStorage || {};
|
||||
|
||||
@ -93,55 +94,13 @@ export function getLocalLanguage() {
|
||||
return "en";
|
||||
}
|
||||
|
||||
// Store loaded translations in memory so translations are available immediately
|
||||
// when DOM is created in Polymer. Even a cache lookup creates noticeable latency.
|
||||
const translations = {};
|
||||
|
||||
async function fetchTranslation(fingerprint) {
|
||||
const response = await fetch(`/static/translations/${fingerprint}`, {
|
||||
credentials: "same-origin",
|
||||
});
|
||||
if (!response.ok) {
|
||||
throw new Error(
|
||||
`Fail to fetch translation ${fingerprint}: HTTP response status is ${response.status}`
|
||||
);
|
||||
}
|
||||
return response.json();
|
||||
}
|
||||
|
||||
export async function getTranslation(
|
||||
fragment: string | null,
|
||||
language: string
|
||||
) {
|
||||
const metadata = translationMetadata.translations[language];
|
||||
if (!metadata) {
|
||||
if (language !== "en") {
|
||||
return getTranslation(fragment, "en");
|
||||
}
|
||||
throw new Error("Language en is not found in metadata");
|
||||
}
|
||||
|
||||
// nl-abcd.jon or logbook/nl-abcd.json
|
||||
const fingerprint = `${fragment ? fragment + "/" : ""}${language}-${
|
||||
metadata.hash
|
||||
}.json`;
|
||||
|
||||
// Fetch translation from the server
|
||||
if (!translations[fingerprint]) {
|
||||
translations[fingerprint] = fetchTranslation(fingerprint)
|
||||
.then((data) => ({ language, data }))
|
||||
.catch((error) => {
|
||||
delete translations[fingerprint];
|
||||
if (language !== "en") {
|
||||
// Couldn't load selected translation. Try a fall back to en before failing.
|
||||
return getTranslation(fragment, "en");
|
||||
}
|
||||
return Promise.reject(error);
|
||||
});
|
||||
}
|
||||
return translations[fingerprint];
|
||||
return commonGetTranslation(fragment, language);
|
||||
}
|
||||
|
||||
// Load selected translation into memory immediately so it is ready when Polymer
|
||||
// initializes.
|
||||
getTranslation(null, getLocalLanguage());
|
||||
commonGetTranslation(null, getLocalLanguage());
|
||||
|
Loading…
x
Reference in New Issue
Block a user