mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-23 17:26:42 +00:00
Translations for core states (#575)
* Fix deeper nested translations build * Make fallback to message optional * Use translated state names * Remove unused switch cases * Use src en.json as fallback instead of downloaded * Use separate translations for badge states * Eliminate unnecessary StatesMixin * Remove now unused localize fallback parameter * Fix capitalization to match material guidelines * Move media player text generation back to model * Make localize args object * Change Mixin to use computed function * Revert to normal args spread for haLocalize * Rename to computeHaLocalize * Allow state to default for badge and media player * Denormalize en.json with Lokalise placeholders * Fix cleanups missed after master merge * Split zwave query stage states to separate keys * Throw error to fail gulp build * Fix zwave template and regression on general state
This commit is contained in:
parent
926c46b701
commit
056e9e0d74
@ -14,10 +14,10 @@ const outDir = 'build-translations';
|
||||
const tasks = [];
|
||||
|
||||
function recursiveFlatten(prefix, data) {
|
||||
var output = {};
|
||||
let output = {};
|
||||
Object.keys(data).forEach(function (key) {
|
||||
if (typeof (data[key]) === 'object') {
|
||||
output = Object.assign({}, output, recursiveFlatten(key + '.', data[key]));
|
||||
output = Object.assign({}, output, recursiveFlatten(prefix + key + '.', data[key]));
|
||||
} else {
|
||||
output[prefix + key] = data[key];
|
||||
}
|
||||
@ -29,16 +29,68 @@ function flatten(data) {
|
||||
return recursiveFlatten('', data);
|
||||
}
|
||||
|
||||
let taskName = 'build-merged-translations';
|
||||
/**
|
||||
* Replace Lokalise key placeholders with their actual values.
|
||||
*
|
||||
* We duplicate the behavior of Lokalise here so that placeholders can
|
||||
* be included in src/translations/en.json, but still be usable while
|
||||
* developing locally.
|
||||
*
|
||||
* @link https://docs.lokalise.co/article/KO5SZWLLsy-key-referencing
|
||||
*/
|
||||
const re_key_reference = /\[%key:([^%]+)%\]/;
|
||||
function lokalise_transform (data, original) {
|
||||
const output = {};
|
||||
Object.entries(data).forEach(([key, value]) => {
|
||||
if (value instanceof Object) {
|
||||
output[key] = lokalise_transform(value, original);
|
||||
} else {
|
||||
output[key] = value.replace(re_key_reference, (match, key) => {
|
||||
const replace = key.split('::').reduce((tr, k) => tr[k], original);
|
||||
if (typeof replace !== 'string') {
|
||||
throw Error(`Invalid key placeholder ${key} in src/translations/en.json`);
|
||||
}
|
||||
return replace;
|
||||
});
|
||||
}
|
||||
});
|
||||
return output;
|
||||
}
|
||||
|
||||
/**
|
||||
* This task will build a master translation file, to be used as the base for
|
||||
* all languages. This starts with src/translations/en.json, and replaces all
|
||||
* Lokalise key placeholders with their target values. Under normal circumstances,
|
||||
* this will be the same as translations/en.json However, we build it here to
|
||||
* facilitate both making changes in development mode, and to ensure that the
|
||||
* project is buildable immediately after merging new translation keys, since
|
||||
* the Lokalise update to translations/en.json will not happen immediately.
|
||||
*/
|
||||
let taskName = 'build-master-translation';
|
||||
gulp.task(taskName, function () {
|
||||
return gulp.src('src/translations/en.json')
|
||||
.pipe(transform(function(data, file) {
|
||||
return lokalise_transform(data, data);
|
||||
}))
|
||||
.pipe(rename('translation-master.json'))
|
||||
.pipe(gulp.dest(outDir));
|
||||
});
|
||||
tasks.push(taskName);
|
||||
|
||||
taskName = 'build-merged-translations';
|
||||
gulp.task(taskName, ['build-master-translation'], function () {
|
||||
return gulp.src(inDir + '/*.json')
|
||||
.pipe(foreach(function (stream, file) {
|
||||
// For each language generate a merged json file. It begins with en.json as
|
||||
// a failsafe for untranslated strings, and merges all parent tags into one
|
||||
// file for each specific subtag
|
||||
.pipe(foreach(function(stream, file) {
|
||||
// For each language generate a merged json file. It begins with the master
|
||||
// translation as a failsafe for untranslated strings, and merges all parent
|
||||
// tags into one file for each specific subtag
|
||||
//
|
||||
// TODO: This is a naive interpretation of BCP47 that should be improved.
|
||||
// Will be OK for now as long as we don't have anything more complicated
|
||||
// than a base translation + region.
|
||||
const tr = path.basename(file.history[0], '.json');
|
||||
const subtags = tr.split('-');
|
||||
const src = [inDir + '/en.json']; // Start with en as a fallback for missing translations
|
||||
const src = [outDir + '/translation-master.json'];
|
||||
for (let i = 1; i <= subtags.length; i++) {
|
||||
const lang = subtags.slice(0, i).join('-');
|
||||
src.push(inDir + '/' + lang + '.json');
|
||||
|
@ -153,8 +153,8 @@
|
||||
|
||||
<div class='caption'>
|
||||
[[computeStateName(stateObj)]]
|
||||
<div class='title'>[[playerObj.primaryText]]</div>
|
||||
[[playerObj.secondaryText]]<br />
|
||||
<div class='title'>[[computePrimaryText(haLocalize, playerObj)]]</div>
|
||||
[[playerObj.secondaryTitle]]<br />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -206,7 +206,8 @@
|
||||
</dom-module>
|
||||
|
||||
<script>
|
||||
class HaMediaPlayerCard extends window.hassMixins.EventsMixin(Polymer.Element) {
|
||||
class HaMediaPlayerCard extends
|
||||
window.hassMixins.LocalizeMixin(window.hassMixins.EventsMixin(Polymer.Element)) {
|
||||
static get is() { return 'ha-media_player-card'; }
|
||||
static get properties() {
|
||||
return {
|
||||
@ -309,6 +310,12 @@ class HaMediaPlayerCard extends window.hassMixins.EventsMixin(Polymer.Element) {
|
||||
return new window.MediaPlayerEntity(hass, stateObj);
|
||||
}
|
||||
|
||||
computePrimaryText(haLocalize, playerObj) {
|
||||
return playerObj.primaryTitle
|
||||
|| haLocalize('state.media_player', playerObj.stateObj.state)
|
||||
|| haLocalize('state.default', playerObj.stateObj.state) || playerObj.stateObj.state;
|
||||
}
|
||||
|
||||
computePlaybackControlIcon(playerObj) {
|
||||
if (playerObj.isPlaying) {
|
||||
return playerObj.supportsPause ? 'mdi:pause' : 'mdi:stop';
|
||||
|
@ -40,22 +40,24 @@
|
||||
value='[[computeValue(state)]]'
|
||||
icon='[[computeIcon(state)]]'
|
||||
image='[[computeImage(state)]]'
|
||||
label='[[computeLabel(state)]]'
|
||||
label='[[computeLabel(haLocalize, state)]]'
|
||||
description='[[computeDescription(state)]]'
|
||||
></ha-label-badge>
|
||||
</template>
|
||||
</dom-module>
|
||||
|
||||
<script>
|
||||
class HaStateLabelBadge extends window.hassMixins.EventsMixin(Polymer.Element) {
|
||||
/*
|
||||
* @appliesMixin window.hassMixins.LocalizeMixin
|
||||
* @appliesMixin window.hassMixins.EventsMixin
|
||||
*/
|
||||
class HaStateLabelBadge extends
|
||||
window.hassMixins.LocalizeMixin(window.hassMixins.EventsMixin(Polymer.Element)) {
|
||||
static get is() { return 'ha-state-label-badge'; }
|
||||
|
||||
static get properties() {
|
||||
return {
|
||||
hass: {
|
||||
type: Object,
|
||||
},
|
||||
|
||||
hass: Object,
|
||||
state: {
|
||||
type: Object,
|
||||
observer: 'stateChanged',
|
||||
@ -101,7 +103,7 @@ class HaStateLabelBadge extends window.hassMixins.EventsMixin(Polymer.Element) {
|
||||
if (state.state === 'unavailable') {
|
||||
return null;
|
||||
}
|
||||
var domain = window.hassUtil.computeDomain(state);
|
||||
const domain = window.hassUtil.computeDomain(state);
|
||||
switch (domain) {
|
||||
case 'alarm_control_panel':
|
||||
if (state.state === 'pending') {
|
||||
@ -131,26 +133,16 @@ class HaStateLabelBadge extends window.hassMixins.EventsMixin(Polymer.Element) {
|
||||
return state.attributes.entity_picture || null;
|
||||
}
|
||||
|
||||
computeLabel(state) {
|
||||
if (state.state === 'unavailable') {
|
||||
return 'unavai';
|
||||
}
|
||||
switch (window.hassUtil.computeDomain(state)) {
|
||||
case 'device_tracker':
|
||||
return state.state === 'not_home' ? 'Away' : state.state;
|
||||
case 'alarm_control_panel':
|
||||
if (state.state === 'pending') {
|
||||
return 'pend';
|
||||
} else if (state.state === 'armed_away' || state.state === 'armed_home') {
|
||||
return 'armed';
|
||||
} else if (state.state === 'triggered') {
|
||||
return 'trig';
|
||||
}
|
||||
// state == 'disarmed'
|
||||
return 'disarm';
|
||||
default:
|
||||
return state.attributes.unit_of_measurement || null;
|
||||
computeLabel(haLocalize, state) {
|
||||
const domain = window.hassUtil.computeDomain(state);
|
||||
if (state.state === 'unavailable' ||
|
||||
['device_tracker', 'alarm_control_panel'].includes(domain)) {
|
||||
// Localize the state with a special state_badge namespace, which has variations of
|
||||
// the state translations that are truncated to fit within the badge label. Translations
|
||||
// are only added for device_tracker and alarm_control_panel.
|
||||
return haLocalize(`state_badge.${domain}`, state.state) || haLocalize('state_badge.default', state.state) || state.state;
|
||||
}
|
||||
return state.attributes.unit_of_measurement || null;
|
||||
}
|
||||
|
||||
computeDescription(state) {
|
||||
|
@ -106,19 +106,19 @@
|
||||
<paper-listbox attr-for-selected='data-panel' selected='[[route.panel]]'>
|
||||
<paper-icon-item on-tap='menuClicked' data-panel='states'>
|
||||
<iron-icon slot="item-icon" icon='mdi:apps'></iron-icon>
|
||||
<span class='item-text'>{{localize('panel', 'states')}}</span>
|
||||
<span class='item-text'>[[haLocalize('panel', 'states')]]</span>
|
||||
</paper-icon-item>
|
||||
|
||||
<template is='dom-repeat' items='[[panels]]'>
|
||||
<paper-icon-item on-tap='menuClicked' data-panel$='[[item.url_path]]'>
|
||||
<iron-icon slot="item-icon" icon='[[item.icon]]'></iron-icon>
|
||||
<span class='item-text'>{{localize('panel', item.title)}}</span>
|
||||
<span class='item-text'>[[computePanelName(haLocalize, item)]]</span>
|
||||
</paper-icon-item>
|
||||
</template>
|
||||
|
||||
<paper-icon-item on-tap='menuClicked' data-panel='logout' class='logout'>
|
||||
<iron-icon slot="item-icon" icon='mdi:exit-to-app'></iron-icon>
|
||||
<span class='item-text'>{{localize('panel', 'log_out')}}</span>
|
||||
<span class='item-text'>[[haLocalize('panel', 'log_out')]]</span>
|
||||
</paper-icon-item>
|
||||
</paper-listbox>
|
||||
|
||||
@ -214,6 +214,10 @@ class HaSidebar extends
|
||||
return hass.config.core.components.indexOf('mqtt') !== -1;
|
||||
}
|
||||
|
||||
computePanelName(haLocalize, panel) {
|
||||
return haLocalize('panel', panel.title) || panel.title;
|
||||
}
|
||||
|
||||
computePanels(hass) {
|
||||
var panels = hass.config.panels;
|
||||
var sortValue = {
|
||||
|
@ -20,17 +20,18 @@
|
||||
|
||||
<div class='horizontal justified layout'>
|
||||
<state-info state-obj="[[stateObj]]" in-dialog='[[inDialog]]'></state-info>
|
||||
<div class='state'>[[computeStateDisplay(stateObj)]]</div>
|
||||
<div class='state'>[[computeStateDisplay(haLocalize, stateObj)]]</div>
|
||||
</div>
|
||||
</template>
|
||||
</dom-module>
|
||||
|
||||
<script>
|
||||
class StateCardDisplay extends Polymer.Element {
|
||||
class StateCardDisplay extends window.hassMixins.LocalizeMixin(Polymer.Element) {
|
||||
static get is() { return 'state-card-display'; }
|
||||
|
||||
static get properties() {
|
||||
return {
|
||||
hass: Object,
|
||||
stateObj: Object,
|
||||
inDialog: {
|
||||
type: Boolean,
|
||||
@ -39,8 +40,55 @@ class StateCardDisplay extends Polymer.Element {
|
||||
};
|
||||
}
|
||||
|
||||
computeStateDisplay(stateObj) {
|
||||
return window.hassUtil.computeStateState(stateObj);
|
||||
computeStateDisplay(haLocalize, stateObj) {
|
||||
if (!stateObj._stateDisplay) {
|
||||
const domain = window.hassUtil.computeDomain(stateObj);
|
||||
if (domain === 'binary_sensor') {
|
||||
// Try device class translation, then default binary sensor translation
|
||||
stateObj._stateDisplay =
|
||||
haLocalize(`state.${domain}.${stateObj.attributes.device_class}`, stateObj.state)
|
||||
|| haLocalize(`state.${domain}.default`, stateObj.state);
|
||||
} else if (stateObj.attributes.unit_of_measurement) {
|
||||
stateObj._stateDisplay = stateObj.state + ' ' + stateObj.attributes.unit_of_measurement;
|
||||
} else if (domain === 'input_datetime') {
|
||||
let date;
|
||||
if (!stateObj.attributes.has_time) {
|
||||
date = new Date(
|
||||
stateObj.attributes.year,
|
||||
stateObj.attributes.month - 1,
|
||||
stateObj.attributes.day
|
||||
);
|
||||
stateObj._stateDisplay = window.hassUtil.formatDate(date);
|
||||
} else if (!stateObj.attributes.has_date) {
|
||||
date = new Date(
|
||||
1970, 0, 1,
|
||||
stateObj.attributes.hour,
|
||||
stateObj.attributes.minute
|
||||
);
|
||||
stateObj._stateDisplay = window.hassUtil.formatTime(date);
|
||||
} else {
|
||||
date = new Date(
|
||||
stateObj.attributes.year, stateObj.attributes.month - 1,
|
||||
stateObj.attributes.day, stateObj.attributes.hour,
|
||||
stateObj.attributes.minute
|
||||
);
|
||||
stateObj._stateDisplay = window.hassUtil.formatDateTime(date);
|
||||
}
|
||||
} else if (domain === 'zwave') {
|
||||
if (['initializing', 'dead'].includes(stateObj.state)) {
|
||||
stateObj._stateDisplay = haLocalize('state.zwave.query_stage', stateObj.state, 'query_stage', stateObj.attributes.query_stage);
|
||||
} else {
|
||||
stateObj._stateDisplay = haLocalize('state.zwave.default', stateObj.state);
|
||||
}
|
||||
} else {
|
||||
stateObj._stateDisplay = haLocalize(`state.${domain}`, stateObj.state);
|
||||
}
|
||||
// Fall back to default or raw state if nothing else matches.
|
||||
stateObj._stateDisplay = stateObj._stateDisplay
|
||||
|| haLocalize('state.default', stateObj.state) || stateObj.state;
|
||||
}
|
||||
|
||||
return stateObj._stateDisplay;
|
||||
}
|
||||
}
|
||||
customElements.define(StateCardDisplay.is, StateCardDisplay);
|
||||
|
@ -38,15 +38,15 @@
|
||||
<div class='horizontal justified layout'>
|
||||
<state-info state-obj="[[stateObj]]" in-dialog='[[inDialog]]'></state-info>
|
||||
<div class='state'>
|
||||
<div class='main-text' take-height$='[[!playerObj.secondaryText]]'>[[playerObj.primaryText]]</div>
|
||||
<div class='secondary-text'>[[playerObj.secondaryText]]</div>
|
||||
<div class='main-text' take-height$='[[!playerObj.secondaryTitle]]'>[[computePrimaryText(haLocalize, playerObj)]]</div>
|
||||
<div class='secondary-text'>[[playerObj.secondaryTitle]]</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</dom-module>
|
||||
|
||||
<script>
|
||||
class StateCardMediaPlayer extends Polymer.Element {
|
||||
class StateCardMediaPlayer extends window.hassMixins.LocalizeMixin(Polymer.Element) {
|
||||
static get is() { return 'state-card-media_player'; }
|
||||
|
||||
static get properties() {
|
||||
@ -67,6 +67,12 @@ class StateCardMediaPlayer extends Polymer.Element {
|
||||
computePlayerObj(hass, stateObj) {
|
||||
return new window.MediaPlayerEntity(hass, stateObj);
|
||||
}
|
||||
|
||||
computePrimaryText(haLocalize, playerObj) {
|
||||
return playerObj.primaryTitle
|
||||
|| haLocalize('state.media_player', playerObj.stateObj.state)
|
||||
|| haLocalize('state.default', playerObj.stateObj.state) || playerObj.stateObj.state;
|
||||
}
|
||||
}
|
||||
customElements.define(StateCardMediaPlayer.is, StateCardMediaPlayer);
|
||||
</script>
|
||||
|
@ -8,5 +8,209 @@
|
||||
"log_out": "Log out",
|
||||
"mailbox": "Mailbox",
|
||||
"shopping_list": "Shopping list"
|
||||
},
|
||||
"state": {
|
||||
"default": {
|
||||
"off": "Off",
|
||||
"on": "On",
|
||||
"unknown": "Unknown",
|
||||
"unavailable": "Unavailable"
|
||||
},
|
||||
"alarm_control_panel": {
|
||||
"armed": "Armed",
|
||||
"disarmed": "Disarmed",
|
||||
"armed_home": "Armed home",
|
||||
"armed_away": "Armed away",
|
||||
"armed_night": "Armed night",
|
||||
"pending": "Pending",
|
||||
"arming": "Arming",
|
||||
"disarming": "Disarming",
|
||||
"triggered": "Triggered"
|
||||
},
|
||||
"automation": {
|
||||
"off": "[%key:state::default::off%]",
|
||||
"on": "[%key:state::default::on%]"
|
||||
},
|
||||
"binary_sensor": {
|
||||
"default": {
|
||||
"off": "[%key:state::default::off%]",
|
||||
"on": "[%key:state::default::on%]"
|
||||
},
|
||||
"moisture": {
|
||||
"off": "Dry",
|
||||
"on": "Wet"
|
||||
},
|
||||
"gas": {
|
||||
"off": "Clear",
|
||||
"on": "Detected"
|
||||
},
|
||||
"motion": {
|
||||
"off": "[%key:state::binary_sensor::gas::off%]",
|
||||
"on": "[%key:state::binary_sensor::gas::on%]"
|
||||
},
|
||||
"occupancy": {
|
||||
"off": "[%key:state::binary_sensor::gas::off%]",
|
||||
"on": "[%key:state::binary_sensor::gas::on%]"
|
||||
},
|
||||
"smoke": {
|
||||
"off": "[%key:state::binary_sensor::gas::off%]",
|
||||
"on": "[%key:state::binary_sensor::gas::on%]"
|
||||
},
|
||||
"sound": {
|
||||
"off": "[%key:state::binary_sensor::gas::off%]",
|
||||
"on": "[%key:state::binary_sensor::gas::on%]"
|
||||
},
|
||||
"vibration": {
|
||||
"off": "[%key:state::binary_sensor::gas::off%]",
|
||||
"on": "[%key:state::binary_sensor::gas::on%]"
|
||||
},
|
||||
"opening": {
|
||||
"off": "Closed",
|
||||
"on": "Open"
|
||||
},
|
||||
"safety": {
|
||||
"off": "Safe",
|
||||
"on": "Unsafe"
|
||||
}
|
||||
},
|
||||
"calendar": {
|
||||
"off": "[%key:state::default::off%]",
|
||||
"on": "[%key:state::default::on%]"
|
||||
},
|
||||
"camera": {
|
||||
"recording": "Recording",
|
||||
"streaming": "Streaming",
|
||||
"idle": "Idle"
|
||||
},
|
||||
"climate": {
|
||||
"off": "[%key:state::default::off%]",
|
||||
"on": "[%key:state::default::on%]",
|
||||
"heat": "Heat",
|
||||
"cool": "Cool",
|
||||
"idle": "Idle",
|
||||
"auto": "Auto",
|
||||
"dry": "Dry",
|
||||
"fan_only": "Fan only",
|
||||
"eco": "Eco",
|
||||
"electric": "Electric",
|
||||
"performance": "Performance",
|
||||
"high_demand": "High demand",
|
||||
"heat_pump": "Heat pump",
|
||||
"gas": "Gas"
|
||||
},
|
||||
"configurator": {
|
||||
"configure": "Configure",
|
||||
"configured": "Configured"
|
||||
},
|
||||
"cover": {
|
||||
"open": "Open",
|
||||
"opening": "Opening",
|
||||
"closed": "Closed",
|
||||
"closing": "Closing",
|
||||
"stopped": "Stopped"
|
||||
},
|
||||
"device_tracker": {
|
||||
"home": "Home",
|
||||
"not_home": "Away"
|
||||
},
|
||||
"fan": {
|
||||
"off": "[%key:state::default::off%]",
|
||||
"on": "[%key:state::default::on%]"
|
||||
},
|
||||
"group": {
|
||||
"off": "[%key:state::default::off%]",
|
||||
"on": "[%key:state::default::on%]",
|
||||
"home": "[%key:state::device_tracker::home%]",
|
||||
"not_home": "[%key:state::device_tracker::not_home%]",
|
||||
"open": "[%key:state::cover::open%]",
|
||||
"opening": "[%key:state::cover::opening%]",
|
||||
"closed": "[%key:state::cover::closed%]",
|
||||
"closing": "[%key:state::cover::closing%]",
|
||||
"stopped": "[%key:state::cover::stopped%]",
|
||||
"locked": "[%key:state::lock::locked%]",
|
||||
"unlocked": "[%key:state::lock::unlocked%]",
|
||||
"ok": "[%key:state::plant::ok%]",
|
||||
"problem": "[%key:state::plant::problem%]"
|
||||
},
|
||||
"input_boolean": {
|
||||
"off": "[%key:state::default::off%]",
|
||||
"on": "[%key:state::default::on%]"
|
||||
},
|
||||
"light": {
|
||||
"off": "[%key:state::default::off%]",
|
||||
"on": "[%key:state::default::on%]"
|
||||
},
|
||||
"lock": {
|
||||
"locked": "Locked",
|
||||
"unlocked": "Unlocked"
|
||||
},
|
||||
"media_player": {
|
||||
"off": "[%key:state::default::off%]",
|
||||
"on": "[%key:state::default::on%]",
|
||||
"playing": "Playing",
|
||||
"paused": "Paused",
|
||||
"idle": "Idle",
|
||||
"standby": "Standby"
|
||||
},
|
||||
"plant": {
|
||||
"ok": "OK",
|
||||
"problem": "Problem"
|
||||
},
|
||||
"remote": {
|
||||
"off": "[%key:state::default::off%]",
|
||||
"on": "[%key:state::default::on%]"
|
||||
},
|
||||
"scene": {
|
||||
"scening": "Scening"
|
||||
},
|
||||
"script": {
|
||||
"off": "[%key:state::default::off%]",
|
||||
"on": "[%key:state::default::on%]"
|
||||
},
|
||||
"sensor": {
|
||||
"off": "[%key:state::default::off%]",
|
||||
"on": "[%key:state::default::on%]"
|
||||
},
|
||||
"sun": {
|
||||
"above_horizon": "Above horizon",
|
||||
"below_horizon": "Below horizon"
|
||||
},
|
||||
"switch": {
|
||||
"off": "[%key:state::default::off%]",
|
||||
"on": "[%key:state::default::on%]"
|
||||
},
|
||||
"zwave": {
|
||||
"default": {
|
||||
"initializing": "Initializing",
|
||||
"dead": "Dead",
|
||||
"sleeping": "Sleeping",
|
||||
"ready": "Ready"
|
||||
},
|
||||
"query_stage": {
|
||||
"initializing": "[%key:state::zwave::default::initializing%] ({query_stage})",
|
||||
"dead": "[%key:state::zwave::default::dead%] ({query_stage})"
|
||||
}
|
||||
}
|
||||
},
|
||||
"state_badge": {
|
||||
"default": {
|
||||
"unknown": "Unk",
|
||||
"unavailable": "Unavai"
|
||||
},
|
||||
"alarm_control_panel": {
|
||||
"armed": "Armed",
|
||||
"disarmed": "Disarm",
|
||||
"armed_home": "Armed",
|
||||
"armed_away": "Armed",
|
||||
"armed_night": "Armed",
|
||||
"pending": "Pend",
|
||||
"arming": "Arming",
|
||||
"disarming": "Disarm",
|
||||
"triggered": "Trig"
|
||||
},
|
||||
"device_tracker": {
|
||||
"home": "[%key:state::device_tracker::home%]",
|
||||
"not_home": "[%key:state::device_tracker::not_home%]"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -82,9 +82,7 @@ window.hassMixins.LocalizeMixin = Polymer.dedupingMixin(superClass =>
|
||||
class extends Polymer.mixinBehaviors([Polymer.AppLocalizeBehavior], superClass) {
|
||||
static get properties() {
|
||||
return {
|
||||
hass: {
|
||||
type: Object,
|
||||
},
|
||||
hass: Object,
|
||||
language: {
|
||||
type: String,
|
||||
computed: 'computeLanguage(hass)',
|
||||
@ -93,6 +91,10 @@ window.hassMixins.LocalizeMixin = Polymer.dedupingMixin(superClass =>
|
||||
type: Object,
|
||||
computed: 'computeResources(hass)',
|
||||
},
|
||||
haLocalize: {
|
||||
type: Function,
|
||||
computed: 'computeHaLocalize(localize)',
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
@ -104,9 +106,8 @@ window.hassMixins.LocalizeMixin = Polymer.dedupingMixin(superClass =>
|
||||
return hass && hass.resources;
|
||||
}
|
||||
|
||||
localize(namespace, message, ...args) {
|
||||
// Return the input message if no translation is found
|
||||
return super.localize(namespace + '.' + message, ...args) || message;
|
||||
computeHaLocalize(localize) {
|
||||
return (namespace, message, ...args) => localize(namespace + '.' + message, ...args);
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -471,77 +471,6 @@ window.hassUtil.sortByName = function (entityA, entityB) {
|
||||
return 0;
|
||||
};
|
||||
|
||||
window.hassUtil.computeStateState = function (stateObj) {
|
||||
if (!stateObj._stateDisplay) {
|
||||
stateObj._stateDisplay = stateObj.state.replace(/_/g, ' ');
|
||||
const domain = window.hassUtil.computeDomain(stateObj);
|
||||
|
||||
if (stateObj.attributes.unit_of_measurement) {
|
||||
stateObj._stateDisplay += ' ' + stateObj.attributes.unit_of_measurement;
|
||||
}
|
||||
if (domain === 'binary_sensor') {
|
||||
switch (stateObj.attributes.device_class) {
|
||||
case 'moisture':
|
||||
stateObj._stateDisplay = (stateObj._stateDisplay === 'off') ? 'dry' : 'wet';
|
||||
break;
|
||||
case 'gas':
|
||||
case 'motion':
|
||||
case 'occupancy':
|
||||
case 'smoke':
|
||||
case 'sound':
|
||||
case 'vibration':
|
||||
stateObj._stateDisplay = (stateObj._stateDisplay === 'off') ? 'clear' : 'detected';
|
||||
break;
|
||||
case 'opening':
|
||||
stateObj._stateDisplay = (stateObj._stateDisplay === 'off') ? 'closed' : 'open';
|
||||
break;
|
||||
case 'safety':
|
||||
stateObj._stateDisplay = (stateObj._stateDisplay === 'off') ? 'safe' : 'unsafe';
|
||||
break;
|
||||
case 'cold':
|
||||
case 'connectivity':
|
||||
case 'heat':
|
||||
case 'light':
|
||||
case 'moving':
|
||||
case 'power':
|
||||
case 'plug':
|
||||
default:
|
||||
}
|
||||
} else if (domain === 'input_datetime') {
|
||||
let date;
|
||||
if (!stateObj.attributes.has_time) {
|
||||
date = new Date(
|
||||
stateObj.attributes.year,
|
||||
stateObj.attributes.month - 1,
|
||||
stateObj.attributes.day
|
||||
);
|
||||
stateObj._stateDisplay = window.hassUtil.formatDate(date);
|
||||
} else if (!stateObj.attributes.has_date) {
|
||||
date = new Date(
|
||||
1970, 0, 1,
|
||||
stateObj.attributes.hour,
|
||||
stateObj.attributes.minute
|
||||
);
|
||||
stateObj._stateDisplay = window.hassUtil.formatTime(date);
|
||||
} else {
|
||||
date = new Date(
|
||||
stateObj.attributes.year, stateObj.attributes.month - 1,
|
||||
stateObj.attributes.day, stateObj.attributes.hour,
|
||||
stateObj.attributes.minute
|
||||
);
|
||||
stateObj._stateDisplay = window.hassUtil.formatDateTime(date);
|
||||
}
|
||||
} else if (domain === 'zwave') {
|
||||
if (['initializing', 'dead'].includes(stateObj.state) && stateObj.attributes && 'query_stage' in stateObj.attributes) {
|
||||
return stateObj._stateDisplay + ' (' + stateObj.attributes.query_stage + ')';
|
||||
}
|
||||
return stateObj._stateDisplay;
|
||||
}
|
||||
}
|
||||
|
||||
return stateObj._stateDisplay;
|
||||
};
|
||||
|
||||
window.hassUtil.isComponentLoaded = function (hass, component) {
|
||||
return hass && hass.config.core.components.indexOf(component) !== -1;
|
||||
};
|
||||
|
@ -109,12 +109,11 @@
|
||||
|
||||
/* eslint-enable no-bitwise */
|
||||
|
||||
addGetter('primaryText', function () {
|
||||
return this.stateObj.attributes.media_title ||
|
||||
window.hassUtil.computeStateState(this.stateObj);
|
||||
addGetter('primaryTitle', function () {
|
||||
return this.stateObj.attributes.media_title;
|
||||
});
|
||||
|
||||
addGetter('secondaryText', function () {
|
||||
addGetter('secondaryTitle', function () {
|
||||
if (this.isMusic) {
|
||||
return this.stateObj.attributes.media_artist;
|
||||
} else if (this.isTVShow) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user