mirror of
https://github.com/home-assistant/frontend.git
synced 2025-07-27 11:16:35 +00:00
Merge pull request #8826 from home-assistant/dev
This commit is contained in:
commit
6393072e68
2
setup.py
2
setup.py
@ -2,7 +2,7 @@ from setuptools import setup, find_packages
|
|||||||
|
|
||||||
setup(
|
setup(
|
||||||
name="home-assistant-frontend",
|
name="home-assistant-frontend",
|
||||||
version="20210402.1",
|
version="20210406.0",
|
||||||
description="The Home Assistant frontend",
|
description="The Home Assistant frontend",
|
||||||
url="https://github.com/home-assistant/home-assistant-polymer",
|
url="https://github.com/home-assistant/home-assistant-polymer",
|
||||||
author="The Home Assistant Authors",
|
author="The Home Assistant Authors",
|
||||||
|
@ -68,8 +68,12 @@ export const computeStateDisplay = (
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// `counter` and `number` domains do not have a unit of measurement but should still use `formatNumber`
|
// `counter` `number` and `input_number` domains do not have a unit of measurement but should still use `formatNumber`
|
||||||
if (domain === "counter" || domain === "number") {
|
if (
|
||||||
|
domain === "counter" ||
|
||||||
|
domain === "number" ||
|
||||||
|
domain === "input_number"
|
||||||
|
) {
|
||||||
return formatNumber(compareState, locale);
|
return formatNumber(compareState, locale);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,14 +34,12 @@ const _maxLen = 128;
|
|||||||
|
|
||||||
function initTable() {
|
function initTable() {
|
||||||
const table: number[][] = [];
|
const table: number[][] = [];
|
||||||
const row: number[] = [0];
|
const row: number[] = [];
|
||||||
for (let i = 1; i <= _maxLen; i++) {
|
for (let i = 0; i <= _maxLen; i++) {
|
||||||
row.push(-i);
|
row[i] = 0;
|
||||||
}
|
}
|
||||||
for (let i = 0; i <= _maxLen; i++) {
|
for (let i = 0; i <= _maxLen; i++) {
|
||||||
const thisRow = row.slice(0);
|
table.push(row.slice(0));
|
||||||
thisRow[0] = -i;
|
|
||||||
table.push(thisRow);
|
|
||||||
}
|
}
|
||||||
return table;
|
return table;
|
||||||
}
|
}
|
||||||
@ -50,7 +48,7 @@ function isSeparatorAtPos(value: string, index: number): boolean {
|
|||||||
if (index < 0 || index >= value.length) {
|
if (index < 0 || index >= value.length) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
const code = value.charCodeAt(index);
|
const code = value.codePointAt(index);
|
||||||
switch (code) {
|
switch (code) {
|
||||||
case CharCode.Underline:
|
case CharCode.Underline:
|
||||||
case CharCode.Dash:
|
case CharCode.Dash:
|
||||||
@ -62,8 +60,16 @@ function isSeparatorAtPos(value: string, index: number): boolean {
|
|||||||
case CharCode.DoubleQuote:
|
case CharCode.DoubleQuote:
|
||||||
case CharCode.Colon:
|
case CharCode.Colon:
|
||||||
case CharCode.DollarSign:
|
case CharCode.DollarSign:
|
||||||
|
case CharCode.LessThan:
|
||||||
|
case CharCode.OpenParen:
|
||||||
|
case CharCode.OpenSquareBracket:
|
||||||
return true;
|
return true;
|
||||||
|
case undefined:
|
||||||
|
return false;
|
||||||
default:
|
default:
|
||||||
|
if (isEmojiImprecise(code)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -92,10 +98,15 @@ function isPatternInWord(
|
|||||||
patternLen: number,
|
patternLen: number,
|
||||||
wordLow: string,
|
wordLow: string,
|
||||||
wordPos: number,
|
wordPos: number,
|
||||||
wordLen: number
|
wordLen: number,
|
||||||
|
fillMinWordPosArr = false
|
||||||
): boolean {
|
): boolean {
|
||||||
while (patternPos < patternLen && wordPos < wordLen) {
|
while (patternPos < patternLen && wordPos < wordLen) {
|
||||||
if (patternLow[patternPos] === wordLow[wordPos]) {
|
if (patternLow[patternPos] === wordLow[wordPos]) {
|
||||||
|
if (fillMinWordPosArr) {
|
||||||
|
// Remember the min word position for each pattern position
|
||||||
|
_minWordMatchPos[patternPos] = wordPos;
|
||||||
|
}
|
||||||
patternPos += 1;
|
patternPos += 1;
|
||||||
}
|
}
|
||||||
wordPos += 1;
|
wordPos += 1;
|
||||||
@ -104,42 +115,22 @@ function isPatternInWord(
|
|||||||
}
|
}
|
||||||
|
|
||||||
enum Arrow {
|
enum Arrow {
|
||||||
Top = 0b1,
|
Diag = 1,
|
||||||
Diag = 0b10,
|
Left = 2,
|
||||||
Left = 0b100,
|
LeftLeft = 3,
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A tuple of three values.
|
* An array representating a fuzzy match.
|
||||||
|
*
|
||||||
* 0. the score
|
* 0. the score
|
||||||
* 1. the matches encoded as bitmask (2^53)
|
* 1. the offset at which matching started
|
||||||
* 2. the offset at which matching started
|
* 2. `<match_pos_N>`
|
||||||
|
* 3. `<match_pos_1>`
|
||||||
|
* 4. `<match_pos_0>` etc
|
||||||
*/
|
*/
|
||||||
export type FuzzyScore = [number, number, number];
|
// export type FuzzyScore = [score: number, wordStart: number, ...matches: number[]];// [number, number, number];
|
||||||
|
export type FuzzyScore = Array<number>;
|
||||||
interface FilterGlobals {
|
|
||||||
_matchesCount: number;
|
|
||||||
_topMatch2: number;
|
|
||||||
_topScore: number;
|
|
||||||
_wordStart: number;
|
|
||||||
_firstMatchCanBeWeak: boolean;
|
|
||||||
_table: number[][];
|
|
||||||
_scores: number[][];
|
|
||||||
_arrows: Arrow[][];
|
|
||||||
}
|
|
||||||
|
|
||||||
function initGlobals(): FilterGlobals {
|
|
||||||
return {
|
|
||||||
_matchesCount: 0,
|
|
||||||
_topMatch2: 0,
|
|
||||||
_topScore: 0,
|
|
||||||
_wordStart: 0,
|
|
||||||
_firstMatchCanBeWeak: false,
|
|
||||||
_table: initTable(),
|
|
||||||
_scores: initTable(),
|
|
||||||
_arrows: <Arrow[][]>initTable(),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function fuzzyScore(
|
export function fuzzyScore(
|
||||||
pattern: string,
|
pattern: string,
|
||||||
@ -150,7 +141,6 @@ export function fuzzyScore(
|
|||||||
wordStart: number,
|
wordStart: number,
|
||||||
firstMatchCanBeWeak: boolean
|
firstMatchCanBeWeak: boolean
|
||||||
): FuzzyScore | undefined {
|
): FuzzyScore | undefined {
|
||||||
const globals = initGlobals();
|
|
||||||
const patternLen = pattern.length > _maxLen ? _maxLen : pattern.length;
|
const patternLen = pattern.length > _maxLen ? _maxLen : pattern.length;
|
||||||
const wordLen = word.length > _maxLen ? _maxLen : word.length;
|
const wordLen = word.length > _maxLen ? _maxLen : word.length;
|
||||||
|
|
||||||
@ -172,18 +162,30 @@ export function fuzzyScore(
|
|||||||
patternLen,
|
patternLen,
|
||||||
wordLow,
|
wordLow,
|
||||||
wordStart,
|
wordStart,
|
||||||
wordLen
|
wordLen,
|
||||||
|
true
|
||||||
)
|
)
|
||||||
) {
|
) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Find the max matching word position for each pattern position
|
||||||
|
// NOTE: the min matching word position was filled in above, in the `isPatternInWord` call
|
||||||
|
_fillInMaxWordMatchPos(
|
||||||
|
patternLen,
|
||||||
|
wordLen,
|
||||||
|
patternStart,
|
||||||
|
wordStart,
|
||||||
|
patternLow,
|
||||||
|
wordLow
|
||||||
|
);
|
||||||
|
|
||||||
let row = 1;
|
let row = 1;
|
||||||
let column = 1;
|
let column = 1;
|
||||||
let patternPos = patternStart;
|
let patternPos = patternStart;
|
||||||
let wordPos = wordStart;
|
let wordPos = wordStart;
|
||||||
|
|
||||||
let hasStrongFirstMatch = false;
|
const hasStrongFirstMatch = [false];
|
||||||
|
|
||||||
// There will be a match, fill in tables
|
// There will be a match, fill in tables
|
||||||
for (
|
for (
|
||||||
@ -191,83 +193,146 @@ export function fuzzyScore(
|
|||||||
patternPos < patternLen;
|
patternPos < patternLen;
|
||||||
row++, patternPos++
|
row++, patternPos++
|
||||||
) {
|
) {
|
||||||
|
// Reduce search space to possible matching word positions and to possible access from next row
|
||||||
|
const minWordMatchPos = _minWordMatchPos[patternPos];
|
||||||
|
const maxWordMatchPos = _maxWordMatchPos[patternPos];
|
||||||
|
const nextMaxWordMatchPos =
|
||||||
|
patternPos + 1 < patternLen ? _maxWordMatchPos[patternPos + 1] : wordLen;
|
||||||
|
|
||||||
for (
|
for (
|
||||||
column = 1, wordPos = wordStart;
|
column = minWordMatchPos - wordStart + 1, wordPos = minWordMatchPos;
|
||||||
wordPos < wordLen;
|
wordPos < nextMaxWordMatchPos;
|
||||||
column++, wordPos++
|
column++, wordPos++
|
||||||
) {
|
) {
|
||||||
const score = _doScore(
|
let score = Number.MIN_SAFE_INTEGER;
|
||||||
pattern,
|
let canComeDiag = false;
|
||||||
patternLow,
|
|
||||||
patternPos,
|
|
||||||
patternStart,
|
|
||||||
word,
|
|
||||||
wordLow,
|
|
||||||
wordPos
|
|
||||||
);
|
|
||||||
|
|
||||||
if (patternPos === patternStart && score > 1) {
|
if (wordPos <= maxWordMatchPos) {
|
||||||
hasStrongFirstMatch = true;
|
score = _doScore(
|
||||||
|
pattern,
|
||||||
|
patternLow,
|
||||||
|
patternPos,
|
||||||
|
patternStart,
|
||||||
|
word,
|
||||||
|
wordLow,
|
||||||
|
wordPos,
|
||||||
|
wordLen,
|
||||||
|
wordStart,
|
||||||
|
_diag[row - 1][column - 1] === 0,
|
||||||
|
hasStrongFirstMatch
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
globals._scores[row][column] = score;
|
let diagScore = 0;
|
||||||
|
if (score !== Number.MAX_SAFE_INTEGER) {
|
||||||
|
canComeDiag = true;
|
||||||
|
diagScore = score + _table[row - 1][column - 1];
|
||||||
|
}
|
||||||
|
|
||||||
const diag =
|
const canComeLeft = wordPos > minWordMatchPos;
|
||||||
globals._table[row - 1][column - 1] + (score > 1 ? 1 : score);
|
const leftScore = canComeLeft
|
||||||
const top = globals._table[row - 1][column] + -1;
|
? _table[row][column - 1] + (_diag[row][column - 1] > 0 ? -5 : 0)
|
||||||
const left = globals._table[row][column - 1] + -1;
|
: 0; // penalty for a gap start
|
||||||
|
|
||||||
if (left >= top) {
|
const canComeLeftLeft =
|
||||||
// left or diag
|
wordPos > minWordMatchPos + 1 && _diag[row][column - 1] > 0;
|
||||||
if (left > diag) {
|
const leftLeftScore = canComeLeftLeft
|
||||||
globals._table[row][column] = left;
|
? _table[row][column - 2] + (_diag[row][column - 2] > 0 ? -5 : 0)
|
||||||
globals._arrows[row][column] = Arrow.Left;
|
: 0; // penalty for a gap start
|
||||||
} else if (left === diag) {
|
|
||||||
globals._table[row][column] = left;
|
if (
|
||||||
globals._arrows[row][column] = Arrow.Left || Arrow.Diag;
|
canComeLeftLeft &&
|
||||||
} else {
|
(!canComeLeft || leftLeftScore >= leftScore) &&
|
||||||
globals._table[row][column] = diag;
|
(!canComeDiag || leftLeftScore >= diagScore)
|
||||||
globals._arrows[row][column] = Arrow.Diag;
|
) {
|
||||||
}
|
// always prefer choosing left left to jump over a diagonal because that means a match is earlier in the word
|
||||||
} else if (top > diag) {
|
_table[row][column] = leftLeftScore;
|
||||||
globals._table[row][column] = top;
|
_arrows[row][column] = Arrow.LeftLeft;
|
||||||
globals._arrows[row][column] = Arrow.Top;
|
_diag[row][column] = 0;
|
||||||
} else if (top === diag) {
|
} else if (canComeLeft && (!canComeDiag || leftScore >= diagScore)) {
|
||||||
globals._table[row][column] = top;
|
// always prefer choosing left since that means a match is earlier in the word
|
||||||
globals._arrows[row][column] = Arrow.Top || Arrow.Diag;
|
_table[row][column] = leftScore;
|
||||||
|
_arrows[row][column] = Arrow.Left;
|
||||||
|
_diag[row][column] = 0;
|
||||||
|
} else if (canComeDiag) {
|
||||||
|
_table[row][column] = diagScore;
|
||||||
|
_arrows[row][column] = Arrow.Diag;
|
||||||
|
_diag[row][column] = _diag[row - 1][column - 1] + 1;
|
||||||
} else {
|
} else {
|
||||||
globals._table[row][column] = diag;
|
throw new Error(`not possible`);
|
||||||
globals._arrows[row][column] = Arrow.Diag;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_debug) {
|
if (_debug) {
|
||||||
printTables(pattern, patternStart, word, wordStart, globals);
|
printTables(pattern, patternStart, word, wordStart);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!hasStrongFirstMatch && !firstMatchCanBeWeak) {
|
if (!hasStrongFirstMatch[0] && !firstMatchCanBeWeak) {
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
globals._matchesCount = 0;
|
row--;
|
||||||
globals._topScore = -100;
|
column--;
|
||||||
globals._wordStart = wordStart;
|
|
||||||
globals._firstMatchCanBeWeak = firstMatchCanBeWeak;
|
|
||||||
|
|
||||||
_findAllMatches2(
|
const result: FuzzyScore = [_table[row][column], wordStart];
|
||||||
row - 1,
|
|
||||||
column - 1,
|
let backwardsDiagLength = 0;
|
||||||
patternLen === wordLen ? 1 : 0,
|
let maxMatchColumn = 0;
|
||||||
0,
|
|
||||||
false,
|
while (row >= 1) {
|
||||||
globals
|
// Find the column where we go diagonally up
|
||||||
);
|
let diagColumn = column;
|
||||||
if (globals._matchesCount === 0) {
|
do {
|
||||||
return undefined;
|
const arrow = _arrows[row][diagColumn];
|
||||||
|
if (arrow === Arrow.LeftLeft) {
|
||||||
|
diagColumn -= 2;
|
||||||
|
} else if (arrow === Arrow.Left) {
|
||||||
|
diagColumn -= 1;
|
||||||
|
} else {
|
||||||
|
// found the diagonal
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} while (diagColumn >= 1);
|
||||||
|
|
||||||
|
// Overturn the "forwards" decision if keeping the "backwards" diagonal would give a better match
|
||||||
|
if (
|
||||||
|
backwardsDiagLength > 1 && // only if we would have a contiguous match of 3 characters
|
||||||
|
patternLow[patternStart + row - 1] === wordLow[wordStart + column - 1] && // only if we can do a contiguous match diagonally
|
||||||
|
!isUpperCaseAtPos(diagColumn + wordStart - 1, word, wordLow) && // only if the forwards chose diagonal is not an uppercase
|
||||||
|
backwardsDiagLength + 1 > _diag[row][diagColumn] // only if our contiguous match would be longer than the "forwards" contiguous match
|
||||||
|
) {
|
||||||
|
diagColumn = column;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (diagColumn === column) {
|
||||||
|
// this is a contiguous match
|
||||||
|
backwardsDiagLength++;
|
||||||
|
} else {
|
||||||
|
backwardsDiagLength = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!maxMatchColumn) {
|
||||||
|
// remember the last matched column
|
||||||
|
maxMatchColumn = diagColumn;
|
||||||
|
}
|
||||||
|
|
||||||
|
row--;
|
||||||
|
column = diagColumn - 1;
|
||||||
|
result.push(column);
|
||||||
}
|
}
|
||||||
|
|
||||||
return [globals._topScore, globals._topMatch2, wordStart];
|
if (wordLen === patternLen) {
|
||||||
|
// the word matches the pattern with all characters!
|
||||||
|
// giving the score a total match boost (to come up ahead other words)
|
||||||
|
result[0] += 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add 1 penalty for each skipped character in the word
|
||||||
|
const skippedCharsCount = maxMatchColumn - patternLen;
|
||||||
|
result[0] -= skippedCharsCount;
|
||||||
|
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
function _doScore(
|
function _doScore(
|
||||||
@ -277,50 +342,81 @@ function _doScore(
|
|||||||
patternStart: number,
|
patternStart: number,
|
||||||
word: string,
|
word: string,
|
||||||
wordLow: string,
|
wordLow: string,
|
||||||
wordPos: number
|
wordPos: number,
|
||||||
) {
|
wordLen: number,
|
||||||
|
wordStart: number,
|
||||||
|
newMatchStart: boolean,
|
||||||
|
outFirstMatchStrong: boolean[]
|
||||||
|
): number {
|
||||||
if (patternLow[patternPos] !== wordLow[wordPos]) {
|
if (patternLow[patternPos] !== wordLow[wordPos]) {
|
||||||
return -1;
|
return Number.MIN_SAFE_INTEGER;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let score = 1;
|
||||||
|
let isGapLocation = false;
|
||||||
if (wordPos === patternPos - patternStart) {
|
if (wordPos === patternPos - patternStart) {
|
||||||
// common prefix: `foobar <-> foobaz`
|
// common prefix: `foobar <-> foobaz`
|
||||||
// ^^^^^
|
// ^^^^^
|
||||||
if (pattern[patternPos] === word[wordPos]) {
|
score = pattern[patternPos] === word[wordPos] ? 7 : 5;
|
||||||
return 7;
|
} else if (
|
||||||
}
|
|
||||||
return 5;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
|
||||||
isUpperCaseAtPos(wordPos, word, wordLow) &&
|
isUpperCaseAtPos(wordPos, word, wordLow) &&
|
||||||
(wordPos === 0 || !isUpperCaseAtPos(wordPos - 1, word, wordLow))
|
(wordPos === 0 || !isUpperCaseAtPos(wordPos - 1, word, wordLow))
|
||||||
) {
|
) {
|
||||||
// hitting upper-case: `foo <-> forOthers`
|
// hitting upper-case: `foo <-> forOthers`
|
||||||
// ^^ ^
|
// ^^ ^
|
||||||
if (pattern[patternPos] === word[wordPos]) {
|
score = pattern[patternPos] === word[wordPos] ? 7 : 5;
|
||||||
return 7;
|
isGapLocation = true;
|
||||||
}
|
} else if (
|
||||||
return 5;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
|
||||||
isSeparatorAtPos(wordLow, wordPos) &&
|
isSeparatorAtPos(wordLow, wordPos) &&
|
||||||
(wordPos === 0 || !isSeparatorAtPos(wordLow, wordPos - 1))
|
(wordPos === 0 || !isSeparatorAtPos(wordLow, wordPos - 1))
|
||||||
) {
|
) {
|
||||||
// hitting a separator: `. <-> foo.bar`
|
// hitting a separator: `. <-> foo.bar`
|
||||||
// ^
|
// ^
|
||||||
return 5;
|
score = 5;
|
||||||
}
|
} else if (
|
||||||
|
|
||||||
if (
|
|
||||||
isSeparatorAtPos(wordLow, wordPos - 1) ||
|
isSeparatorAtPos(wordLow, wordPos - 1) ||
|
||||||
isWhitespaceAtPos(wordLow, wordPos - 1)
|
isWhitespaceAtPos(wordLow, wordPos - 1)
|
||||||
) {
|
) {
|
||||||
// post separator: `foo <-> bar_foo`
|
// post separator: `foo <-> bar_foo`
|
||||||
// ^^^
|
// ^^^
|
||||||
return 5;
|
score = 5;
|
||||||
|
isGapLocation = true;
|
||||||
}
|
}
|
||||||
return 1;
|
|
||||||
|
if (score > 1 && patternPos === patternStart) {
|
||||||
|
outFirstMatchStrong[0] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isGapLocation) {
|
||||||
|
isGapLocation =
|
||||||
|
isUpperCaseAtPos(wordPos, word, wordLow) ||
|
||||||
|
isSeparatorAtPos(wordLow, wordPos - 1) ||
|
||||||
|
isWhitespaceAtPos(wordLow, wordPos - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
if (patternPos === patternStart) {
|
||||||
|
// first character in pattern
|
||||||
|
if (wordPos > wordStart) {
|
||||||
|
// the first pattern character would match a word character that is not at the word start
|
||||||
|
// so introduce a penalty to account for the gap preceding this match
|
||||||
|
score -= isGapLocation ? 3 : 5;
|
||||||
|
}
|
||||||
|
} else if (newMatchStart) {
|
||||||
|
// this would be the beginning of a new match (i.e. there would be a gap before this location)
|
||||||
|
score += isGapLocation ? 2 : 0;
|
||||||
|
} else {
|
||||||
|
// this is part of a contiguous match, so give it a slight bonus, but do so only if it would not be a prefered gap location
|
||||||
|
score += isGapLocation ? 0 : 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (wordPos + 1 === wordLen) {
|
||||||
|
// we always penalize gaps, but this gives unfair advantages to a match that would match the last character in the word
|
||||||
|
// so pretend there is a gap after the last character in the word to normalize things
|
||||||
|
score -= isGapLocation ? 3 : 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
return score;
|
||||||
}
|
}
|
||||||
|
|
||||||
function printTable(
|
function printTable(
|
||||||
@ -360,104 +456,96 @@ function printTables(
|
|||||||
pattern: string,
|
pattern: string,
|
||||||
patternStart: number,
|
patternStart: number,
|
||||||
word: string,
|
word: string,
|
||||||
wordStart: number,
|
wordStart: number
|
||||||
globals: FilterGlobals
|
|
||||||
): void {
|
): void {
|
||||||
pattern = pattern.substr(patternStart);
|
pattern = pattern.substr(patternStart);
|
||||||
word = word.substr(wordStart);
|
word = word.substr(wordStart);
|
||||||
console.log(
|
console.log(printTable(_table, pattern, pattern.length, word, word.length));
|
||||||
printTable(globals._table, pattern, pattern.length, word, word.length)
|
console.log(printTable(_arrows, pattern, pattern.length, word, word.length));
|
||||||
);
|
console.log(printTable(_diag, pattern, pattern.length, word, word.length));
|
||||||
console.log(
|
|
||||||
printTable(globals._arrows, pattern, pattern.length, word, word.length)
|
|
||||||
);
|
|
||||||
console.log(
|
|
||||||
printTable(globals._scores, pattern, pattern.length, word, word.length)
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function _findAllMatches2(
|
const _minWordMatchPos = initArr(2 * _maxLen); // min word position for a certain pattern position
|
||||||
row: number,
|
const _maxWordMatchPos = initArr(2 * _maxLen); // max word position for a certain pattern position
|
||||||
column: number,
|
const _diag = initTable(); // the length of a contiguous diagonal match
|
||||||
total: number,
|
const _table = initTable();
|
||||||
matches: number,
|
const _arrows = <Arrow[][]>initTable();
|
||||||
lastMatched: boolean,
|
|
||||||
globals: FilterGlobals
|
function initArr(maxLen: number) {
|
||||||
): void {
|
const row: number[] = [];
|
||||||
if (globals._matchesCount >= 10 || total < -25) {
|
for (let i = 0; i <= maxLen; i++) {
|
||||||
// stop when having already 10 results, or
|
row[i] = 0;
|
||||||
// when a potential alignment as already 5 gaps
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
return row;
|
||||||
|
}
|
||||||
|
|
||||||
let simpleMatchCount = 0;
|
function _fillInMaxWordMatchPos(
|
||||||
|
patternLen: number,
|
||||||
|
wordLen: number,
|
||||||
|
patternStart: number,
|
||||||
|
wordStart: number,
|
||||||
|
patternLow: string,
|
||||||
|
wordLow: string
|
||||||
|
) {
|
||||||
|
let patternPos = patternLen - 1;
|
||||||
|
let wordPos = wordLen - 1;
|
||||||
|
while (patternPos >= patternStart && wordPos >= wordStart) {
|
||||||
|
if (patternLow[patternPos] === wordLow[wordPos]) {
|
||||||
|
_maxWordMatchPos[patternPos] = wordPos;
|
||||||
|
patternPos--;
|
||||||
|
}
|
||||||
|
wordPos--;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
while (row > 0 && column > 0) {
|
export interface FuzzyScorer {
|
||||||
const score = globals._scores[row][column];
|
(
|
||||||
const arrow = globals._arrows[row][column];
|
pattern: string,
|
||||||
|
lowPattern: string,
|
||||||
|
patternPos: number,
|
||||||
|
word: string,
|
||||||
|
lowWord: string,
|
||||||
|
wordPos: number,
|
||||||
|
firstMatchCanBeWeak: boolean
|
||||||
|
): FuzzyScore | undefined;
|
||||||
|
}
|
||||||
|
|
||||||
if (arrow === Arrow.Left) {
|
export function createMatches(score: undefined | FuzzyScore): Match[] {
|
||||||
// left -> no match, skip a word character
|
if (typeof score === "undefined") {
|
||||||
column -= 1;
|
return [];
|
||||||
if (lastMatched) {
|
}
|
||||||
total -= 5; // new gap penalty
|
const res: Match[] = [];
|
||||||
} else if (matches !== 0) {
|
const wordPos = score[1];
|
||||||
total -= 1; // gap penalty after first match
|
for (let i = score.length - 1; i > 1; i--) {
|
||||||
}
|
const pos = score[i] + wordPos;
|
||||||
lastMatched = false;
|
const last = res[res.length - 1];
|
||||||
simpleMatchCount = 0;
|
if (last && last.end === pos) {
|
||||||
} else if (arrow && Arrow.Diag) {
|
last.end = pos + 1;
|
||||||
if (arrow && Arrow.Left) {
|
|
||||||
// left
|
|
||||||
_findAllMatches2(
|
|
||||||
row,
|
|
||||||
column - 1,
|
|
||||||
matches !== 0 ? total - 1 : total, // gap penalty after first match
|
|
||||||
matches,
|
|
||||||
lastMatched,
|
|
||||||
globals
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// diag
|
|
||||||
total += score;
|
|
||||||
row -= 1;
|
|
||||||
column -= 1;
|
|
||||||
lastMatched = true;
|
|
||||||
|
|
||||||
// match -> set a 1 at the word pos
|
|
||||||
matches += 2 ** (column + globals._wordStart);
|
|
||||||
|
|
||||||
// count simple matches and boost a row of
|
|
||||||
// simple matches when they yield in a
|
|
||||||
// strong match.
|
|
||||||
if (score === 1) {
|
|
||||||
simpleMatchCount += 1;
|
|
||||||
|
|
||||||
if (row === 0 && !globals._firstMatchCanBeWeak) {
|
|
||||||
// when the first match is a weak
|
|
||||||
// match we discard it
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// boost
|
|
||||||
total += 1 + simpleMatchCount * (score - 1);
|
|
||||||
simpleMatchCount = 0;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
return;
|
res.push({ start: pos, end: pos + 1 });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return res;
|
||||||
total -= column >= 3 ? 9 : column * 3; // late start penalty
|
|
||||||
|
|
||||||
// dynamically keep track of the current top score
|
|
||||||
// and insert the current best score at head, the rest at tail
|
|
||||||
globals._matchesCount += 1;
|
|
||||||
if (total > globals._topScore) {
|
|
||||||
globals._topScore = total;
|
|
||||||
globals._topMatch2 = matches;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// #endregion
|
/**
|
||||||
|
* A fast function (therefore imprecise) to check if code points are emojis.
|
||||||
|
* Generated using https://github.com/alexdima/unicode-utils/blob/master/generate-emoji-test.js
|
||||||
|
*/
|
||||||
|
export function isEmojiImprecise(x: number): boolean {
|
||||||
|
return (
|
||||||
|
(x >= 0x1f1e6 && x <= 0x1f1ff) ||
|
||||||
|
x === 8986 ||
|
||||||
|
x === 8987 ||
|
||||||
|
x === 9200 ||
|
||||||
|
x === 9203 ||
|
||||||
|
(x >= 9728 && x <= 10175) ||
|
||||||
|
x === 11088 ||
|
||||||
|
x === 11093 ||
|
||||||
|
(x >= 127744 && x <= 128591) ||
|
||||||
|
(x >= 128640 && x <= 128764) ||
|
||||||
|
(x >= 128992 && x <= 129003) ||
|
||||||
|
(x >= 129280 && x <= 129535) ||
|
||||||
|
(x >= 129648 && x <= 129750)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
@ -11,7 +11,7 @@ import { fuzzyScore } from "./filter";
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
export const fuzzySequentialMatch = (filter: string, ...words: string[]) => {
|
export const fuzzySequentialMatch = (filter: string, ...words: string[]) => {
|
||||||
let topScore = 0;
|
let topScore = Number.NEGATIVE_INFINITY;
|
||||||
|
|
||||||
for (const word of words) {
|
for (const word of words) {
|
||||||
const scores = fuzzyScore(
|
const scores = fuzzyScore(
|
||||||
@ -28,15 +28,24 @@ export const fuzzySequentialMatch = (filter: string, ...words: string[]) => {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// The VS Code implementation of filter treats a score of "0" as just barely a match
|
// The VS Code implementation of filter returns a:
|
||||||
// But we will typically use this matcher in a .filter(), which interprets 0 as a failure.
|
// - Negative score for a good match that starts in the middle of the string
|
||||||
// By shifting all scores up by 1, we allow "0" matches, while retaining score precedence
|
// - Positive score if the match starts at the beginning of the string
|
||||||
const score = scores[0] + 1;
|
// - 0 if the filter string is just barely a match
|
||||||
|
// - undefined for no match
|
||||||
|
// The "0" return is problematic since .filter() will remove that match, even though a 0 == good match.
|
||||||
|
// So, if we encounter a 0 return, set it to 1 so the match will be included, and still respect ordering.
|
||||||
|
const score = scores[0] === 0 ? 1 : scores[0];
|
||||||
|
|
||||||
if (score > topScore) {
|
if (score > topScore) {
|
||||||
topScore = score;
|
topScore = score;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (topScore === Number.NEGATIVE_INFINITY) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
return topScore;
|
return topScore;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -59,7 +68,7 @@ export const fuzzyFilterSort: FuzzyFilterSort = (filter, items) => {
|
|||||||
: fuzzySequentialMatch(filter, item.filterText);
|
: fuzzySequentialMatch(filter, item.filterText);
|
||||||
return item;
|
return item;
|
||||||
})
|
})
|
||||||
.filter((item) => item.score !== undefined && item.score > 0)
|
.filter((item) => item.score !== undefined)
|
||||||
.sort(({ score: scoreA = 0 }, { score: scoreB = 0 }) =>
|
.sort(({ score: scoreA = 0 }, { score: scoreB = 0 }) =>
|
||||||
scoreA > scoreB ? -1 : scoreA < scoreB ? 1 : 0
|
scoreA > scoreB ? -1 : scoreA < scoreB ? 1 : 0
|
||||||
);
|
);
|
||||||
|
@ -100,7 +100,7 @@ export class HaDevicePicker extends SubscribeMixin(LitElement) {
|
|||||||
public excludeDomains?: string[];
|
public excludeDomains?: string[];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Show only deviced with entities of these device classes.
|
* Show only devices with entities of these device classes.
|
||||||
* @type {Array}
|
* @type {Array}
|
||||||
* @attr include-device-classes
|
* @attr include-device-classes
|
||||||
*/
|
*/
|
||||||
|
@ -1,62 +1,61 @@
|
|||||||
import "@vaadin/vaadin-date-picker/theme/material/vaadin-date-picker";
|
import "@vaadin/vaadin-date-picker/theme/material/vaadin-date-picker-light";
|
||||||
|
import {
|
||||||
|
css,
|
||||||
|
CSSResult,
|
||||||
|
customElement,
|
||||||
|
html,
|
||||||
|
LitElement,
|
||||||
|
property,
|
||||||
|
PropertyValues,
|
||||||
|
query,
|
||||||
|
} from "lit-element";
|
||||||
|
import "@polymer/paper-input/paper-input";
|
||||||
|
import { fireEvent } from "../common/dom/fire_event";
|
||||||
|
import { mdiCalendar } from "@mdi/js";
|
||||||
|
import "./ha-svg-icon";
|
||||||
|
|
||||||
const VaadinDatePicker = customElements.get("vaadin-date-picker");
|
const i18n = {
|
||||||
|
monthNames: [
|
||||||
const documentContainer = document.createElement("template");
|
"January",
|
||||||
documentContainer.setAttribute("style", "display: none;");
|
"February",
|
||||||
documentContainer.innerHTML = `
|
"March",
|
||||||
<dom-module id="ha-date-input-styles" theme-for="vaadin-text-field">
|
"April",
|
||||||
<template>
|
"May",
|
||||||
<style>
|
"June",
|
||||||
[part="input-field"] {
|
"July",
|
||||||
top: 2px;
|
"August",
|
||||||
height: 30px;
|
"September",
|
||||||
color: var(--primary-text-color);
|
"October",
|
||||||
}
|
"November",
|
||||||
[part="value"] {
|
"December",
|
||||||
text-align: center;
|
],
|
||||||
}
|
weekdays: [
|
||||||
</style>
|
"Sunday",
|
||||||
</template>
|
"Monday",
|
||||||
</dom-module>
|
"Tuesday",
|
||||||
`;
|
"Wednesday",
|
||||||
document.head.appendChild(documentContainer.content);
|
"Thursday",
|
||||||
|
"Friday",
|
||||||
export class HaDateInput extends VaadinDatePicker {
|
"Saturday",
|
||||||
constructor() {
|
],
|
||||||
super();
|
weekdaysShort: ["Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"],
|
||||||
|
firstDayOfWeek: 0,
|
||||||
this.i18n.formatDate = this._formatISODate;
|
week: "Week",
|
||||||
this.i18n.parseDate = this._parseISODate;
|
calendar: "Calendar",
|
||||||
}
|
clear: "Clear",
|
||||||
|
today: "Today",
|
||||||
ready() {
|
cancel: "Cancel",
|
||||||
super.ready();
|
formatTitle: (monthName, fullYear) => {
|
||||||
const styleEl = document.createElement("style");
|
return monthName + " " + fullYear;
|
||||||
styleEl.innerHTML = `
|
},
|
||||||
:host {
|
formatDate: (d: { day: number; month: number; year: number }) => {
|
||||||
width: 12ex;
|
|
||||||
margin-top: -6px;
|
|
||||||
--material-body-font-size: 16px;
|
|
||||||
--_material-text-field-input-line-background-color: var(--primary-text-color);
|
|
||||||
--_material-text-field-input-line-opacity: 1;
|
|
||||||
--material-primary-color: var(--primary-text-color);
|
|
||||||
}
|
|
||||||
`;
|
|
||||||
this.shadowRoot.appendChild(styleEl);
|
|
||||||
this._inputElement.querySelector("[part='toggle-button']").style.display =
|
|
||||||
"none";
|
|
||||||
}
|
|
||||||
|
|
||||||
private _formatISODate(d) {
|
|
||||||
return [
|
return [
|
||||||
("0000" + String(d.year)).slice(-4),
|
("0000" + String(d.year)).slice(-4),
|
||||||
("0" + String(d.month + 1)).slice(-2),
|
("0" + String(d.month + 1)).slice(-2),
|
||||||
("0" + String(d.day)).slice(-2),
|
("0" + String(d.day)).slice(-2),
|
||||||
].join("-");
|
].join("-");
|
||||||
}
|
},
|
||||||
|
parseDate: (text: string) => {
|
||||||
private _parseISODate(text) {
|
|
||||||
const parts = text.split("-");
|
const parts = text.split("-");
|
||||||
const today = new Date();
|
const today = new Date();
|
||||||
let date;
|
let date;
|
||||||
@ -80,11 +79,73 @@ export class HaDateInput extends VaadinDatePicker {
|
|||||||
return { day: date, month, year };
|
return { day: date, month, year };
|
||||||
}
|
}
|
||||||
return undefined;
|
return undefined;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
@customElement("ha-date-input")
|
||||||
|
export class HaDateInput extends LitElement {
|
||||||
|
@property() public value?: string;
|
||||||
|
|
||||||
|
@property({ type: Boolean }) public disabled = false;
|
||||||
|
|
||||||
|
@property() public label?: string;
|
||||||
|
|
||||||
|
@query("vaadin-date-picker-light", true) private _datePicker;
|
||||||
|
|
||||||
|
private _inited = false;
|
||||||
|
|
||||||
|
updated(changedProps: PropertyValues) {
|
||||||
|
if (changedProps.has("value")) {
|
||||||
|
this._datePicker.value = this.value;
|
||||||
|
this._inited = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return html`<vaadin-date-picker-light
|
||||||
|
.disabled=${this.disabled}
|
||||||
|
@value-changed=${this._valueChanged}
|
||||||
|
attr-for-value="value"
|
||||||
|
.i18n=${i18n}
|
||||||
|
>
|
||||||
|
<paper-input .label=${this.label} no-label-float>
|
||||||
|
<ha-svg-icon slot="suffix" .path=${mdiCalendar}></ha-svg-icon>
|
||||||
|
</paper-input>
|
||||||
|
</vaadin-date-picker-light>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
private _valueChanged(ev: CustomEvent) {
|
||||||
|
if (
|
||||||
|
!this.value ||
|
||||||
|
(this._inited && !this._compareStringDates(ev.detail.value, this.value))
|
||||||
|
) {
|
||||||
|
fireEvent(this, "value-changed", { value: ev.detail.value });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private _compareStringDates(a: string, b: string): boolean {
|
||||||
|
const aParts = a.split("-");
|
||||||
|
const bParts = b.split("-");
|
||||||
|
let i = 0;
|
||||||
|
for (const aPart of aParts) {
|
||||||
|
if (Number(aPart) !== Number(bParts[i])) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static get styles(): CSSResult {
|
||||||
|
return css`
|
||||||
|
paper-input {
|
||||||
|
width: 110px;
|
||||||
|
}
|
||||||
|
ha-svg-icon {
|
||||||
|
color: var(--secondary-text-color);
|
||||||
|
}
|
||||||
|
`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
customElements.define("ha-date-input", HaDateInput as any);
|
|
||||||
|
|
||||||
declare global {
|
declare global {
|
||||||
interface HTMLElementTagNameMap {
|
interface HTMLElementTagNameMap {
|
||||||
"ha-date-input": HaDateInput;
|
"ha-date-input": HaDateInput;
|
||||||
|
@ -350,6 +350,7 @@ export class HaTargetPicker extends SubscribeMixin(LitElement) {
|
|||||||
.includeDeviceClasses=${this.includeDeviceClasses}
|
.includeDeviceClasses=${this.includeDeviceClasses}
|
||||||
.includeDomains=${this.includeDomains}
|
.includeDomains=${this.includeDomains}
|
||||||
@value-changed=${this._targetPicked}
|
@value-changed=${this._targetPicked}
|
||||||
|
allow-custom-entity
|
||||||
></ha-entity-picker>`;
|
></ha-entity-picker>`;
|
||||||
}
|
}
|
||||||
return html``;
|
return html``;
|
||||||
|
@ -10,6 +10,8 @@ export class HatGraphNode extends LitElement {
|
|||||||
|
|
||||||
@property({ reflect: true, type: Boolean }) graphstart?: boolean;
|
@property({ reflect: true, type: Boolean }) graphstart?: boolean;
|
||||||
|
|
||||||
|
@property({ reflect: true, type: Boolean }) spacer?: boolean;
|
||||||
|
|
||||||
@property({ reflect: true, type: Boolean }) nofocus?: boolean;
|
@property({ reflect: true, type: Boolean }) nofocus?: boolean;
|
||||||
|
|
||||||
@property({ reflect: true, type: Number }) badge?: number;
|
@property({ reflect: true, type: Number }) badge?: number;
|
||||||
@ -25,6 +27,12 @@ export class HatGraphNode extends LitElement {
|
|||||||
if (!svgEl) {
|
if (!svgEl) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
if (this.spacer) {
|
||||||
|
svgEl.setAttribute("width", "10px");
|
||||||
|
svgEl.setAttribute("height", "41px");
|
||||||
|
svgEl.setAttribute("viewBox", "-5 -40 10 26");
|
||||||
|
return;
|
||||||
|
}
|
||||||
const bbox = svgEl.getBBox();
|
const bbox = svgEl.getBBox();
|
||||||
const extra_height = this.graphstart ? 2 : 1;
|
const extra_height = this.graphstart ? 2 : 1;
|
||||||
const extra_width = SPACING;
|
const extra_width = SPACING;
|
||||||
@ -50,7 +58,11 @@ export class HatGraphNode extends LitElement {
|
|||||||
<path
|
<path
|
||||||
class="connector"
|
class="connector"
|
||||||
d="
|
d="
|
||||||
M 0 ${-SPACING - NODE_SIZE / 2}
|
M 0 ${
|
||||||
|
this.spacer
|
||||||
|
? -SPACING * 2 - NODE_SIZE
|
||||||
|
: -SPACING - NODE_SIZE / 2
|
||||||
|
}
|
||||||
L 0 0
|
L 0 0
|
||||||
"
|
"
|
||||||
line-caps="round"
|
line-caps="round"
|
||||||
@ -58,11 +70,15 @@ export class HatGraphNode extends LitElement {
|
|||||||
`
|
`
|
||||||
}
|
}
|
||||||
<g class="node">
|
<g class="node">
|
||||||
<circle
|
${
|
||||||
|
!this.spacer
|
||||||
|
? svg`<circle
|
||||||
cx="0"
|
cx="0"
|
||||||
cy="0"
|
cy="0"
|
||||||
r="${NODE_SIZE / 2}"
|
r="${NODE_SIZE / 2}"
|
||||||
/>
|
/>`
|
||||||
|
: ""
|
||||||
|
}
|
||||||
${
|
${
|
||||||
this.badge
|
this.badge
|
||||||
? svg`
|
? svg`
|
||||||
@ -133,7 +149,7 @@ export class HatGraphNode extends LitElement {
|
|||||||
|
|
||||||
:host([nofocus]):host-context(.active),
|
:host([nofocus]):host-context(.active),
|
||||||
:host([nofocus]):host-context(:focus) {
|
:host([nofocus]):host-context(:focus) {
|
||||||
--stroke-clr: var(--active-clr);
|
--circle-clr: var(--active-clr);
|
||||||
--icon-clr: var(--default-icon-clr);
|
--icon-clr: var(--default-icon-clr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -208,12 +208,6 @@ export class HatGraph extends LitElement {
|
|||||||
:host([disabled]) path.line {
|
:host([disabled]) path.line {
|
||||||
stroke: var(--disabled-clr);
|
stroke: var(--disabled-clr);
|
||||||
}
|
}
|
||||||
:host(.active) #top path.line {
|
|
||||||
stroke: var(--active-clr);
|
|
||||||
}
|
|
||||||
:host(:focus) #top path.line {
|
|
||||||
stroke: var(--active-clr);
|
|
||||||
}
|
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -108,7 +108,7 @@ class HatScriptGraph extends LitElement {
|
|||||||
})}
|
})}
|
||||||
.track_start=${[track_path]}
|
.track_start=${[track_path]}
|
||||||
.track_end=${[track_path]}
|
.track_end=${[track_path]}
|
||||||
tabindex=${trace === undefined ? "-1" : "0"}
|
tabindex=${trace ? "-1" : "0"}
|
||||||
short
|
short
|
||||||
>
|
>
|
||||||
<hat-graph-node
|
<hat-graph-node
|
||||||
@ -168,13 +168,21 @@ class HatScriptGraph extends LitElement {
|
|||||||
|
|
||||||
${config.choose.map((branch, i) => {
|
${config.choose.map((branch, i) => {
|
||||||
const branch_path = `${path}/choose/${i}`;
|
const branch_path = `${path}/choose/${i}`;
|
||||||
|
const track_this =
|
||||||
|
trace !== undefined && trace[0].result?.choice === i;
|
||||||
|
if (track_this) {
|
||||||
|
this.trackedNodes[branch_path] = { config, path: branch_path };
|
||||||
|
}
|
||||||
return html`
|
return html`
|
||||||
<hat-graph>
|
<hat-graph>
|
||||||
<hat-graph-node
|
<hat-graph-node
|
||||||
.iconPath=${mdiCheckBoxOutline}
|
.iconPath=${!trace || track_this
|
||||||
nofocus
|
? mdiCheckBoxOutline
|
||||||
|
: mdiCheckboxBlankOutline}
|
||||||
|
@focus=${this.selectNode(config, branch_path)}
|
||||||
class=${classMap({
|
class=${classMap({
|
||||||
track: trace !== undefined && trace[0].result?.choice === i,
|
active: this.selected === branch_path,
|
||||||
|
track: track_this,
|
||||||
})}
|
})}
|
||||||
></hat-graph-node>
|
></hat-graph-node>
|
||||||
${ensureArray(branch.sequence).map((action, j) =>
|
${ensureArray(branch.sequence).map((action, j) =>
|
||||||
@ -185,8 +193,8 @@ class HatScriptGraph extends LitElement {
|
|||||||
})}
|
})}
|
||||||
<hat-graph>
|
<hat-graph>
|
||||||
<hat-graph-node
|
<hat-graph-node
|
||||||
.iconPath=${mdiCheckboxBlankOutline}
|
|
||||||
nofocus
|
nofocus
|
||||||
|
spacer
|
||||||
class=${classMap({
|
class=${classMap({
|
||||||
track:
|
track:
|
||||||
trace !== undefined && trace[0].result?.choice === "default",
|
trace !== undefined && trace[0].result?.choice === "default",
|
||||||
@ -410,7 +418,6 @@ class HatScriptGraph extends LitElement {
|
|||||||
|
|
||||||
protected render() {
|
protected render() {
|
||||||
const paths = Object.keys(this.trackedNodes);
|
const paths = Object.keys(this.trackedNodes);
|
||||||
|
|
||||||
const manual_triggered = this.trace && "trigger" in this.trace.trace;
|
const manual_triggered = this.trace && "trigger" in this.trace.trace;
|
||||||
let track_path = manual_triggered ? undefined : [0];
|
let track_path = manual_triggered ? undefined : [0];
|
||||||
const trigger_nodes = ensureArray(this.trace.config.trigger).map(
|
const trigger_nodes = ensureArray(this.trace.config.trigger).map(
|
||||||
|
@ -3,7 +3,14 @@ import type { List } from "@material/mwc-list/mwc-list";
|
|||||||
import { SingleSelectedEvent } from "@material/mwc-list/mwc-list-foundation";
|
import { SingleSelectedEvent } from "@material/mwc-list/mwc-list-foundation";
|
||||||
import "@material/mwc-list/mwc-list-item";
|
import "@material/mwc-list/mwc-list-item";
|
||||||
import type { ListItem } from "@material/mwc-list/mwc-list-item";
|
import type { ListItem } from "@material/mwc-list/mwc-list-item";
|
||||||
import { mdiConsoleLine, mdiEarth, mdiReload, mdiServerNetwork } from "@mdi/js";
|
import {
|
||||||
|
mdiClose,
|
||||||
|
mdiConsoleLine,
|
||||||
|
mdiEarth,
|
||||||
|
mdiMagnify,
|
||||||
|
mdiReload,
|
||||||
|
mdiServerNetwork,
|
||||||
|
} from "@mdi/js";
|
||||||
import {
|
import {
|
||||||
css,
|
css,
|
||||||
customElement,
|
customElement,
|
||||||
@ -11,7 +18,6 @@ import {
|
|||||||
internalProperty,
|
internalProperty,
|
||||||
LitElement,
|
LitElement,
|
||||||
property,
|
property,
|
||||||
PropertyValues,
|
|
||||||
query,
|
query,
|
||||||
} from "lit-element";
|
} from "lit-element";
|
||||||
import { ifDefined } from "lit-html/directives/if-defined";
|
import { ifDefined } from "lit-html/directives/if-defined";
|
||||||
@ -85,8 +91,6 @@ export class QuickBar extends LitElement {
|
|||||||
|
|
||||||
@internalProperty() private _entityItems?: EntityItem[];
|
@internalProperty() private _entityItems?: EntityItem[];
|
||||||
|
|
||||||
@internalProperty() private _items?: QuickBarItem[] = [];
|
|
||||||
|
|
||||||
@internalProperty() private _filter = "";
|
@internalProperty() private _filter = "";
|
||||||
|
|
||||||
@internalProperty() private _search = "";
|
@internalProperty() private _search = "";
|
||||||
@ -97,7 +101,7 @@ export class QuickBar extends LitElement {
|
|||||||
|
|
||||||
@internalProperty() private _done = false;
|
@internalProperty() private _done = false;
|
||||||
|
|
||||||
@query("search-input", false) private _filterInputField?: HTMLElement;
|
@query("paper-input", false) private _filterInputField?: HTMLElement;
|
||||||
|
|
||||||
private _focusSet = false;
|
private _focusSet = false;
|
||||||
|
|
||||||
@ -113,25 +117,22 @@ export class QuickBar extends LitElement {
|
|||||||
this._focusSet = false;
|
this._focusSet = false;
|
||||||
this._filter = "";
|
this._filter = "";
|
||||||
this._search = "";
|
this._search = "";
|
||||||
this._items = [];
|
|
||||||
fireEvent(this, "dialog-closed", { dialog: this.localName });
|
fireEvent(this, "dialog-closed", { dialog: this.localName });
|
||||||
}
|
}
|
||||||
|
|
||||||
protected updated(changedProperties: PropertyValues) {
|
|
||||||
if (
|
|
||||||
this._opened &&
|
|
||||||
(changedProperties.has("_filter") ||
|
|
||||||
changedProperties.has("_commandMode"))
|
|
||||||
) {
|
|
||||||
this._setFilteredItems();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected render() {
|
protected render() {
|
||||||
if (!this._opened) {
|
if (!this._opened) {
|
||||||
return html``;
|
return html``;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let items: QuickBarItem[] | undefined = this._commandMode
|
||||||
|
? this._commandItems
|
||||||
|
: this._entityItems;
|
||||||
|
|
||||||
|
if (items && this._filter && this._filter !== " ") {
|
||||||
|
items = this._filterItems(items || [], this._filter);
|
||||||
|
}
|
||||||
|
|
||||||
return html`
|
return html`
|
||||||
<ha-dialog
|
<ha-dialog
|
||||||
.heading=${true}
|
.heading=${true}
|
||||||
@ -140,7 +141,7 @@ export class QuickBar extends LitElement {
|
|||||||
@closed=${this.closeDialog}
|
@closed=${this.closeDialog}
|
||||||
hideActions
|
hideActions
|
||||||
>
|
>
|
||||||
<search-input
|
<paper-input
|
||||||
dialogInitialFocus
|
dialogInitialFocus
|
||||||
no-label-float
|
no-label-float
|
||||||
slot="heading"
|
slot="heading"
|
||||||
@ -149,7 +150,7 @@ export class QuickBar extends LitElement {
|
|||||||
.label=${this.hass.localize(
|
.label=${this.hass.localize(
|
||||||
"ui.dialogs.quick-bar.filter_placeholder"
|
"ui.dialogs.quick-bar.filter_placeholder"
|
||||||
)}
|
)}
|
||||||
.filter=${this._commandMode ? `>${this._search}` : this._search}
|
.value=${this._commandMode ? `>${this._search}` : this._search}
|
||||||
@keydown=${this._handleInputKeyDown}
|
@keydown=${this._handleInputKeyDown}
|
||||||
@focus=${this._setFocusFirstListItem}
|
@focus=${this._setFocusFirstListItem}
|
||||||
>
|
>
|
||||||
@ -159,9 +160,23 @@ export class QuickBar extends LitElement {
|
|||||||
class="prefix"
|
class="prefix"
|
||||||
.path=${mdiConsoleLine}
|
.path=${mdiConsoleLine}
|
||||||
></ha-svg-icon>`
|
></ha-svg-icon>`
|
||||||
: ""}
|
: html`<ha-svg-icon
|
||||||
</search-input>
|
slot="prefix"
|
||||||
${!this._items
|
class="prefix"
|
||||||
|
.path=${mdiMagnify}
|
||||||
|
></ha-svg-icon>`}
|
||||||
|
${this._search &&
|
||||||
|
html`
|
||||||
|
<mwc-icon-button
|
||||||
|
slot="suffix"
|
||||||
|
@click=${this._clearSearch}
|
||||||
|
title="Clear"
|
||||||
|
>
|
||||||
|
<ha-svg-icon .path=${mdiClose}></ha-svg-icon>
|
||||||
|
</mwc-icon-button>
|
||||||
|
`}
|
||||||
|
</paper-input>
|
||||||
|
${!items
|
||||||
? html`<ha-circular-progress
|
? html`<ha-circular-progress
|
||||||
size="small"
|
size="small"
|
||||||
active
|
active
|
||||||
@ -172,13 +187,13 @@ export class QuickBar extends LitElement {
|
|||||||
@selected=${this._handleSelected}
|
@selected=${this._handleSelected}
|
||||||
style=${styleMap({
|
style=${styleMap({
|
||||||
height: `${Math.min(
|
height: `${Math.min(
|
||||||
this._items.length * (this._commandMode ? 56 : 72) + 26,
|
items.length * (this._commandMode ? 56 : 72) + 26,
|
||||||
this._done ? 500 : 0
|
this._done ? 500 : 0
|
||||||
)}px`,
|
)}px`,
|
||||||
})}
|
})}
|
||||||
>
|
>
|
||||||
${scroll({
|
${scroll({
|
||||||
items: this._items,
|
items,
|
||||||
renderItem: (item: QuickBarItem, index?: number) =>
|
renderItem: (item: QuickBarItem, index?: number) =>
|
||||||
this._renderItem(item, index),
|
this._renderItem(item, index),
|
||||||
})}
|
})}
|
||||||
@ -196,7 +211,6 @@ export class QuickBar extends LitElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private _handleOpened() {
|
private _handleOpened() {
|
||||||
this._setFilteredItems();
|
|
||||||
this.updateComplete.then(() => {
|
this.updateComplete.then(() => {
|
||||||
this._done = true;
|
this._done = true;
|
||||||
});
|
});
|
||||||
@ -302,11 +316,11 @@ export class QuickBar extends LitElement {
|
|||||||
|
|
||||||
private _handleInputKeyDown(ev: KeyboardEvent) {
|
private _handleInputKeyDown(ev: KeyboardEvent) {
|
||||||
if (ev.code === "Enter") {
|
if (ev.code === "Enter") {
|
||||||
if (!this._items?.length) {
|
const firstItem = this._getItemAtIndex(0);
|
||||||
|
if (!firstItem || firstItem.style.display === "none") {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
this.processItemAndCloseDialog((firstItem as any).item, 0);
|
||||||
this.processItemAndCloseDialog(this._items[0], 0);
|
|
||||||
} else if (ev.code === "ArrowDown") {
|
} else if (ev.code === "ArrowDown") {
|
||||||
ev.preventDefault();
|
ev.preventDefault();
|
||||||
this._getItemAtIndex(0)?.focus();
|
this._getItemAtIndex(0)?.focus();
|
||||||
@ -338,16 +352,20 @@ export class QuickBar extends LitElement {
|
|||||||
this._search = newFilter;
|
this._search = newFilter;
|
||||||
}
|
}
|
||||||
|
|
||||||
this._debouncedSetFilter(this._search);
|
|
||||||
|
|
||||||
if (oldCommandMode !== this._commandMode) {
|
if (oldCommandMode !== this._commandMode) {
|
||||||
this._items = undefined;
|
|
||||||
this._focusSet = false;
|
this._focusSet = false;
|
||||||
|
|
||||||
this._initializeItemsIfNeeded();
|
this._initializeItemsIfNeeded();
|
||||||
|
this._filter = this._search;
|
||||||
|
} else {
|
||||||
|
this._debouncedSetFilter(this._search);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private _clearSearch() {
|
||||||
|
this._search = "";
|
||||||
|
this._filter = "";
|
||||||
|
}
|
||||||
|
|
||||||
private _debouncedSetFilter = debounce((filter: string) => {
|
private _debouncedSetFilter = debounce((filter: string) => {
|
||||||
this._filter = filter;
|
this._filter = filter;
|
||||||
}, 100);
|
}, 100);
|
||||||
@ -553,16 +571,10 @@ export class QuickBar extends LitElement {
|
|||||||
return this._opened ? !this._commandMode : false;
|
return this._opened ? !this._commandMode : false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private _setFilteredItems() {
|
|
||||||
const items = this._commandMode ? this._commandItems : this._entityItems;
|
|
||||||
this._items = this._filter
|
|
||||||
? this._filterItems(items || [], this._filter)
|
|
||||||
: items;
|
|
||||||
}
|
|
||||||
|
|
||||||
private _filterItems = memoizeOne(
|
private _filterItems = memoizeOne(
|
||||||
(items: QuickBarItem[], filter: string): QuickBarItem[] =>
|
(items: QuickBarItem[], filter: string): QuickBarItem[] => {
|
||||||
fuzzyFilterSort<QuickBarItem>(filter.trimLeft(), items)
|
return fuzzyFilterSort<QuickBarItem>(filter.trimLeft(), items);
|
||||||
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
static get styles() {
|
static get styles() {
|
||||||
@ -598,27 +610,26 @@ export class QuickBar extends LitElement {
|
|||||||
color: var(--primary-text-color);
|
color: var(--primary-text-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
span.command-category {
|
paper-input mwc-icon-button {
|
||||||
font-weight: bold;
|
--mdc-icon-button-size: 24px;
|
||||||
padding: 3px;
|
color: var(--primary-text-color);
|
||||||
display: inline-flex;
|
}
|
||||||
border-radius: 6px;
|
|
||||||
color: black;
|
.command-category {
|
||||||
|
--ha-chip-icon-color: #585858;
|
||||||
|
--ha-chip-text-color: #212121;
|
||||||
}
|
}
|
||||||
|
|
||||||
.command-category.reload {
|
.command-category.reload {
|
||||||
--ha-chip-background-color: #cddc39;
|
--ha-chip-background-color: #cddc39;
|
||||||
--ha-chip-text-color: black;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.command-category.navigation {
|
.command-category.navigation {
|
||||||
--ha-chip-background-color: var(--light-primary-color);
|
--ha-chip-background-color: var(--light-primary-color);
|
||||||
--ha-chip-text-color: black;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.command-category.server_control {
|
.command-category.server_control {
|
||||||
--ha-chip-background-color: var(--warning-color);
|
--ha-chip-background-color: var(--warning-color);
|
||||||
--ha-chip-text-color: black;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
span.command-text {
|
span.command-text {
|
||||||
|
@ -28,7 +28,7 @@ class HassErrorScreen extends LitElement {
|
|||||||
return html`
|
return html`
|
||||||
${this.toolbar
|
${this.toolbar
|
||||||
? html`<div class="toolbar">
|
? html`<div class="toolbar">
|
||||||
${this.rootnav
|
${this.rootnav || history.state?.root
|
||||||
? html`
|
? html`
|
||||||
<ha-menu-button
|
<ha-menu-button
|
||||||
.hass=${this.hass}
|
.hass=${this.hass}
|
||||||
|
@ -30,7 +30,7 @@ class HassLoadingScreen extends LitElement {
|
|||||||
${this.noToolbar
|
${this.noToolbar
|
||||||
? ""
|
? ""
|
||||||
: html`<div class="toolbar">
|
: html`<div class="toolbar">
|
||||||
${this.rootnav
|
${this.rootnav || history.state?.root
|
||||||
? html`
|
? html`
|
||||||
<ha-menu-button
|
<ha-menu-button
|
||||||
.hass=${this.hass}
|
.hass=${this.hass}
|
||||||
|
@ -8,7 +8,6 @@ import {
|
|||||||
property,
|
property,
|
||||||
TemplateResult,
|
TemplateResult,
|
||||||
} from "lit-element";
|
} from "lit-element";
|
||||||
import { classMap } from "lit-html/directives/class-map";
|
|
||||||
import { restoreScroll } from "../common/decorators/restore-scroll";
|
import { restoreScroll } from "../common/decorators/restore-scroll";
|
||||||
import "../components/ha-icon-button-arrow-prev";
|
import "../components/ha-icon-button-arrow-prev";
|
||||||
import "../components/ha-menu-button";
|
import "../components/ha-menu-button";
|
||||||
@ -20,9 +19,11 @@ class HassSubpage extends LitElement {
|
|||||||
|
|
||||||
@property() public header?: string;
|
@property() public header?: string;
|
||||||
|
|
||||||
@property({ type: Boolean }) public showBackButton = true;
|
@property({ type: Boolean, attribute: "main-page" }) public mainPage = false;
|
||||||
|
|
||||||
@property({ type: Boolean }) public hassio = false;
|
@property({ type: Boolean, reflect: true }) public narrow = false;
|
||||||
|
|
||||||
|
@property({ type: Boolean }) public supervisor = false;
|
||||||
|
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
@restoreScroll(".content") private _savedScrollPos?: number;
|
@restoreScroll(".content") private _savedScrollPos?: number;
|
||||||
@ -30,11 +31,20 @@ class HassSubpage extends LitElement {
|
|||||||
protected render(): TemplateResult {
|
protected render(): TemplateResult {
|
||||||
return html`
|
return html`
|
||||||
<div class="toolbar">
|
<div class="toolbar">
|
||||||
<ha-icon-button-arrow-prev
|
${this.mainPage || history.state?.root
|
||||||
.hass=${this.hass}
|
? html`
|
||||||
@click=${this._backTapped}
|
<ha-menu-button
|
||||||
class=${classMap({ hidden: !this.showBackButton })}
|
.hassio=${this.supervisor}
|
||||||
></ha-icon-button-arrow-prev>
|
.hass=${this.hass}
|
||||||
|
.narrow=${this.narrow}
|
||||||
|
></ha-menu-button>
|
||||||
|
`
|
||||||
|
: html`
|
||||||
|
<ha-icon-button-arrow-prev
|
||||||
|
.hass=${this.hass}
|
||||||
|
@click=${this._backTapped}
|
||||||
|
></ha-icon-button-arrow-prev>
|
||||||
|
`}
|
||||||
|
|
||||||
<div class="main-title">${this.header}</div>
|
<div class="main-title">${this.header}</div>
|
||||||
<slot name="toolbar-icon"></slot>
|
<slot name="toolbar-icon"></slot>
|
||||||
|
@ -140,7 +140,7 @@ class HassTabsSubpage extends LitElement {
|
|||||||
const showTabs = tabs.length > 1 || !this.narrow;
|
const showTabs = tabs.length > 1 || !this.narrow;
|
||||||
return html`
|
return html`
|
||||||
<div class="toolbar">
|
<div class="toolbar">
|
||||||
${this.mainPage
|
${this.mainPage || history.state?.root
|
||||||
? html`
|
? html`
|
||||||
<ha-menu-button
|
<ha-menu-button
|
||||||
.hassio=${this.supervisor}
|
.hassio=${this.supervisor}
|
||||||
|
@ -11,12 +11,11 @@ import {
|
|||||||
TemplateResult,
|
TemplateResult,
|
||||||
} from "lit-element";
|
} from "lit-element";
|
||||||
import { HomeAssistant } from "../types";
|
import { HomeAssistant } from "../types";
|
||||||
import "./hass-subpage";
|
|
||||||
import "../resources/ha-style";
|
import "../resources/ha-style";
|
||||||
import "../resources/roboto";
|
|
||||||
import { haStyle } from "../resources/styles";
|
import { haStyle } from "../resources/styles";
|
||||||
import { applyThemesOnElement } from "../common/dom/apply_themes_on_element";
|
import { applyThemesOnElement } from "../common/dom/apply_themes_on_element";
|
||||||
import { atLeastVersion } from "../common/config/version";
|
import { atLeastVersion } from "../common/config/version";
|
||||||
|
import "./hass-subpage";
|
||||||
|
|
||||||
@customElement("supervisor-error-screen")
|
@customElement("supervisor-error-screen")
|
||||||
class SupervisorErrorScreen extends LitElement {
|
class SupervisorErrorScreen extends LitElement {
|
||||||
@ -41,21 +40,15 @@ class SupervisorErrorScreen extends LitElement {
|
|||||||
|
|
||||||
protected render(): TemplateResult {
|
protected render(): TemplateResult {
|
||||||
return html`
|
return html`
|
||||||
<div class="toolbar">
|
<hass-subpage
|
||||||
<ha-icon-button-arrow-prev
|
.hass=${this.hass}
|
||||||
.hass=${this.hass}
|
.header=${this.hass.localize("ui.errors.supervisor.title")}
|
||||||
@click=${this._handleBack}
|
>
|
||||||
></ha-icon-button-arrow-prev>
|
|
||||||
</div>
|
|
||||||
<div class="content">
|
|
||||||
<div class="title">
|
|
||||||
${this.hass.localize("ui.panel.error.supervisor.title")}
|
|
||||||
</div>
|
|
||||||
<ha-card header="Troubleshooting">
|
<ha-card header="Troubleshooting">
|
||||||
<div class="card-content">
|
<div class="card-content">
|
||||||
<ol>
|
<ol>
|
||||||
<li>
|
<li>
|
||||||
${this.hass.localize("ui.panel.error.supervisor.wait")}
|
${this.hass.localize("ui.errors.supervisor.wait")}
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<a
|
<a
|
||||||
@ -64,17 +57,15 @@ class SupervisorErrorScreen extends LitElement {
|
|||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noreferrer"
|
rel="noreferrer"
|
||||||
>
|
>
|
||||||
${this.hass.localize("ui.panel.error.supervisor.observer")}
|
${this.hass.localize("ui.errors.supervisor.observer")}
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
${this.hass.localize("ui.panel.error.supervisor.reboot")}
|
${this.hass.localize("ui.errors.supervisor.reboot")}
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<a href="/config/info" target="_parent">
|
<a href="/config/info" target="_parent">
|
||||||
${this.hass.localize(
|
${this.hass.localize("ui.errors.supervisor.system_health")}
|
||||||
"ui.panel.error.supervisor.system_health"
|
|
||||||
)}
|
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
@ -83,13 +74,13 @@ class SupervisorErrorScreen extends LitElement {
|
|||||||
target="_blank"
|
target="_blank"
|
||||||
rel="noreferrer"
|
rel="noreferrer"
|
||||||
>
|
>
|
||||||
${this.hass.localize("ui.panel.error.supervisor.ask")}
|
${this.hass.localize("ui.errors.supervisor.ask")}
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
</ol>
|
</ol>
|
||||||
</div>
|
</div>
|
||||||
</ha-card>
|
</ha-card>
|
||||||
</div>
|
</hass-subpage>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -125,50 +116,17 @@ class SupervisorErrorScreen extends LitElement {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private _handleBack(): void {
|
|
||||||
history.back();
|
|
||||||
}
|
|
||||||
|
|
||||||
static get styles(): CSSResultArray {
|
static get styles(): CSSResultArray {
|
||||||
return [
|
return [
|
||||||
haStyle,
|
haStyle,
|
||||||
css`
|
css`
|
||||||
.toolbar {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
font-size: 20px;
|
|
||||||
height: var(--header-height);
|
|
||||||
padding: 0 16px;
|
|
||||||
pointer-events: none;
|
|
||||||
background-color: var(--app-header-background-color);
|
|
||||||
font-weight: 400;
|
|
||||||
box-sizing: border-box;
|
|
||||||
}
|
|
||||||
ha-icon-button-arrow-prev {
|
|
||||||
pointer-events: auto;
|
|
||||||
}
|
|
||||||
.content {
|
|
||||||
color: var(--primary-text-color);
|
|
||||||
display: flex;
|
|
||||||
padding: 16px;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
flex-direction: column;
|
|
||||||
}
|
|
||||||
.title {
|
|
||||||
font-size: 24px;
|
|
||||||
font-weight: 400;
|
|
||||||
line-height: 32px;
|
|
||||||
padding-bottom: 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
a {
|
a {
|
||||||
color: var(--mdc-theme-primary);
|
color: var(--mdc-theme-primary);
|
||||||
}
|
}
|
||||||
|
|
||||||
ha-card {
|
ha-card {
|
||||||
width: 600px;
|
width: 600px;
|
||||||
margin: 16px;
|
margin: auto;
|
||||||
padding: 8px;
|
padding: 8px;
|
||||||
}
|
}
|
||||||
@media all and (max-width: 500px) {
|
@media all and (max-width: 500px) {
|
||||||
|
@ -103,7 +103,6 @@ export class HaAutomationTrace extends LitElement {
|
|||||||
.hass=${this.hass}
|
.hass=${this.hass}
|
||||||
.narrow=${this.narrow}
|
.narrow=${this.narrow}
|
||||||
.route=${this.route}
|
.route=${this.route}
|
||||||
.backCallback=${() => this._backTapped()}
|
|
||||||
.tabs=${configSections.automation}
|
.tabs=${configSections.automation}
|
||||||
>
|
>
|
||||||
${this.narrow
|
${this.narrow
|
||||||
@ -388,10 +387,6 @@ export class HaAutomationTrace extends LitElement {
|
|||||||
this._trace = trace;
|
this._trace = trace;
|
||||||
}
|
}
|
||||||
|
|
||||||
private _backTapped(): void {
|
|
||||||
history.back();
|
|
||||||
}
|
|
||||||
|
|
||||||
private _downloadTrace() {
|
private _downloadTrace() {
|
||||||
const aEl = document.createElement("a");
|
const aEl = document.createElement("a");
|
||||||
aEl.download = `trace ${this._entityId} ${
|
aEl.download = `trace ${this._entityId} ${
|
||||||
|
@ -22,9 +22,17 @@ export const traceTabStyles = css`
|
|||||||
border-bottom: 2px solid transparent;
|
border-bottom: 2px solid transparent;
|
||||||
user-select: none;
|
user-select: none;
|
||||||
background: none;
|
background: none;
|
||||||
|
color: var(--primary-text-color);
|
||||||
|
outline: none;
|
||||||
|
transition: background 15ms linear;
|
||||||
}
|
}
|
||||||
|
|
||||||
.tabs > *.active {
|
.tabs > *.active {
|
||||||
border-bottom-color: var(--accent-color);
|
border-bottom-color: var(--accent-color);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.tabs > *:focus,
|
||||||
|
.tabs > *:hover {
|
||||||
|
background: var(--secondary-background-color);
|
||||||
|
}
|
||||||
`;
|
`;
|
||||||
|
@ -214,9 +214,9 @@ class CloudAlexa extends LitElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return html`
|
return html`
|
||||||
<hass-subpage .hass=${this.hass} header="${this.hass!.localize(
|
<hass-subpage .hass=${this.hass} .narrow=${
|
||||||
"ui.panel.config.cloud.alexa.title"
|
this.narrow
|
||||||
)}">
|
} .header=${this.hass!.localize("ui.panel.config.cloud.alexa.title")}>
|
||||||
${
|
${
|
||||||
emptyFilter
|
emptyFilter
|
||||||
? html`
|
? html`
|
||||||
|
@ -239,7 +239,8 @@ class CloudGoogleAssistant extends LitElement {
|
|||||||
return html`
|
return html`
|
||||||
<hass-subpage
|
<hass-subpage
|
||||||
.hass=${this.hass}
|
.hass=${this.hass}
|
||||||
.header=${this.hass!.localize("ui.panel.config.cloud.google.title")}>
|
.header=${this.hass!.localize("ui.panel.config.cloud.google.title")}
|
||||||
|
.narrow=${this.narrow}>
|
||||||
${
|
${
|
||||||
emptyFilter
|
emptyFilter
|
||||||
? html`
|
? html`
|
||||||
|
@ -23,6 +23,8 @@ import "./mqtt-subscribe-card";
|
|||||||
class HaPanelDevMqtt extends LitElement {
|
class HaPanelDevMqtt extends LitElement {
|
||||||
@property({ attribute: false }) public hass!: HomeAssistant;
|
@property({ attribute: false }) public hass!: HomeAssistant;
|
||||||
|
|
||||||
|
@property({ type: Boolean }) public narrow!: boolean;
|
||||||
|
|
||||||
@internalProperty() private topic = "";
|
@internalProperty() private topic = "";
|
||||||
|
|
||||||
@internalProperty() private payload = "";
|
@internalProperty() private payload = "";
|
||||||
@ -41,7 +43,7 @@ class HaPanelDevMqtt extends LitElement {
|
|||||||
|
|
||||||
protected render(): TemplateResult {
|
protected render(): TemplateResult {
|
||||||
return html`
|
return html`
|
||||||
<hass-subpage .hass=${this.hass}>
|
<hass-subpage .narrow=${this.narrow} .hass=${this.hass}>
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<ha-card header="MQTT settings">
|
<ha-card header="MQTT settings">
|
||||||
<div class="card-actions">
|
<div class="card-actions">
|
||||||
|
@ -197,7 +197,7 @@ class ZWaveJSNodeConfig extends SubscribeMixin(LitElement) {
|
|||||||
|
|
||||||
// Numeric entries with a min value of 0 and max of 1 are considered boolean
|
// Numeric entries with a min value of 0 and max of 1 are considered boolean
|
||||||
if (
|
if (
|
||||||
(item.configuration_value_type === "range" &&
|
(item.configuration_value_type === "manual_entry" &&
|
||||||
item.metadata.min === 0 &&
|
item.metadata.min === 0 &&
|
||||||
item.metadata.max === 1) ||
|
item.metadata.max === 1) ||
|
||||||
this._isEnumeratedBool(item)
|
this._isEnumeratedBool(item)
|
||||||
@ -217,7 +217,7 @@ class ZWaveJSNodeConfig extends SubscribeMixin(LitElement) {
|
|||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (item.configuration_value_type === "range") {
|
if (item.configuration_value_type === "manual_entry") {
|
||||||
return html`${labelAndDescription}
|
return html`${labelAndDescription}
|
||||||
<paper-input
|
<paper-input
|
||||||
type="number"
|
type="number"
|
||||||
|
@ -255,13 +255,11 @@ class HuiPictureGlanceCard extends LitElement implements LovelaceCard {
|
|||||||
"state-on": !STATES_OFF.has(stateObj.state),
|
"state-on": !STATES_OFF.has(stateObj.state),
|
||||||
})}
|
})}
|
||||||
.icon=${entityConf.icon || stateIcon(stateObj)}
|
.icon=${entityConf.icon || stateIcon(stateObj)}
|
||||||
title=${`
|
title=${`${computeStateName(stateObj)} : ${computeStateDisplay(
|
||||||
${computeStateName(stateObj)} : ${computeStateDisplay(
|
|
||||||
this.hass!.localize,
|
this.hass!.localize,
|
||||||
stateObj,
|
stateObj,
|
||||||
this.hass!.locale
|
this.hass!.locale
|
||||||
)}
|
)}`}
|
||||||
`}
|
|
||||||
></ha-icon-button>
|
></ha-icon-button>
|
||||||
${this._config!.show_state !== true && entityConf.show_state !== true
|
${this._config!.show_state !== true && entityConf.show_state !== true
|
||||||
? html`<div class="state"></div>`
|
? html`<div class="state"></div>`
|
||||||
|
@ -63,9 +63,9 @@ class HuiInputDatetimeEntityRow extends LitElement implements LovelaceRow {
|
|||||||
<ha-date-input
|
<ha-date-input
|
||||||
.disabled=${UNAVAILABLE_STATES.includes(stateObj.state)}
|
.disabled=${UNAVAILABLE_STATES.includes(stateObj.state)}
|
||||||
.value=${`${stateObj.attributes.year}-${stateObj.attributes.month}-${stateObj.attributes.day}`}
|
.value=${`${stateObj.attributes.year}-${stateObj.attributes.month}-${stateObj.attributes.day}`}
|
||||||
@change=${this._selectedValueChanged}
|
@value-changed=${this._selectedValueChanged}
|
||||||
@click=${this._stopEventPropagation}
|
>
|
||||||
></ha-date-input>
|
</ha-date-input>
|
||||||
${stateObj.attributes.has_time ? "," : ""}
|
${stateObj.attributes.has_time ? "," : ""}
|
||||||
`
|
`
|
||||||
: ``}
|
: ``}
|
||||||
@ -103,9 +103,7 @@ class HuiInputDatetimeEntityRow extends LitElement implements LovelaceRow {
|
|||||||
|
|
||||||
const date = this._dateInputEl ? this._dateInputEl.value : undefined;
|
const date = this._dateInputEl ? this._dateInputEl.value : undefined;
|
||||||
|
|
||||||
if (time !== stateObj.state) {
|
setInputDateTimeValue(this.hass!, stateObj.entity_id, time, date);
|
||||||
setInputDateTimeValue(this.hass!, stateObj.entity_id, time, date);
|
|
||||||
}
|
|
||||||
|
|
||||||
ev.target.blur();
|
ev.target.blur();
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,7 @@ import {
|
|||||||
PropertyValues,
|
PropertyValues,
|
||||||
TemplateResult,
|
TemplateResult,
|
||||||
} from "lit-element";
|
} from "lit-element";
|
||||||
import { formatNumber } from "../../../common/string/format_number";
|
import { computeStateDisplay } from "../../../common/entity/compute_state_display";
|
||||||
import { computeRTLDirection } from "../../../common/util/compute_rtl";
|
import { computeRTLDirection } from "../../../common/util/compute_rtl";
|
||||||
import "../../../components/ha-slider";
|
import "../../../components/ha-slider";
|
||||||
import { UNAVAILABLE_STATES } from "../../../data/entity";
|
import { UNAVAILABLE_STATES } from "../../../data/entity";
|
||||||
@ -89,8 +89,12 @@ class HuiInputNumberEntityRow extends LitElement implements LovelaceRow {
|
|||||||
id="input"
|
id="input"
|
||||||
></ha-slider>
|
></ha-slider>
|
||||||
<span class="state">
|
<span class="state">
|
||||||
${formatNumber(Number(stateObj.state), this.hass.locale)}
|
${computeStateDisplay(
|
||||||
${stateObj.attributes.unit_of_measurement}
|
this.hass.localize,
|
||||||
|
stateObj,
|
||||||
|
this.hass.locale,
|
||||||
|
stateObj.state
|
||||||
|
)}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
`
|
`
|
||||||
|
@ -19,6 +19,7 @@ import { hasConfigOrEntityChanged } from "../common/has-changed";
|
|||||||
import "../components/hui-generic-entity-row";
|
import "../components/hui-generic-entity-row";
|
||||||
import { EntityConfig, LovelaceRow } from "./types";
|
import { EntityConfig, LovelaceRow } from "./types";
|
||||||
import { createEntityNotFoundWarning } from "../components/hui-warning";
|
import { createEntityNotFoundWarning } from "../components/hui-warning";
|
||||||
|
import { computeStateDisplay } from "../../../common/entity/compute_state_display";
|
||||||
|
|
||||||
@customElement("hui-number-entity-row")
|
@customElement("hui-number-entity-row")
|
||||||
class HuiNumberEntityRow extends LitElement implements LovelaceRow {
|
class HuiNumberEntityRow extends LitElement implements LovelaceRow {
|
||||||
@ -88,8 +89,12 @@ class HuiNumberEntityRow extends LitElement implements LovelaceRow {
|
|||||||
id="input"
|
id="input"
|
||||||
></ha-slider>
|
></ha-slider>
|
||||||
<span class="state">
|
<span class="state">
|
||||||
${Number(stateObj.state)}
|
${computeStateDisplay(
|
||||||
${stateObj.attributes.unit_of_measurement}
|
this.hass.localize,
|
||||||
|
stateObj,
|
||||||
|
this.hass.locale,
|
||||||
|
stateObj.state
|
||||||
|
)}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
`
|
`
|
||||||
|
@ -1,103 +0,0 @@
|
|||||||
const documentContainer = document.createElement("template");
|
|
||||||
documentContainer.setAttribute("style", "display: none;");
|
|
||||||
|
|
||||||
documentContainer.innerHTML = `
|
|
||||||
<dom-module id="ha-date-picker-text-field-styles" theme-for="vaadin-text-field">
|
|
||||||
<template>
|
|
||||||
<style>
|
|
||||||
:host {
|
|
||||||
padding: 8px 0 11px 0;
|
|
||||||
margin: 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
[part~="label"] {
|
|
||||||
top: 6px;
|
|
||||||
font-size: var(--paper-font-subhead_-_font-size);
|
|
||||||
color: var(--paper-input-container-color, var(--secondary-text-color));
|
|
||||||
}
|
|
||||||
|
|
||||||
:host([focused]) [part~="label"] {
|
|
||||||
color: var(--paper-input-container-focus-color, var(--primary-color));
|
|
||||||
}
|
|
||||||
|
|
||||||
[part~="input-field"] {
|
|
||||||
color: var(--primary-text-color);
|
|
||||||
top: 3px;
|
|
||||||
}
|
|
||||||
|
|
||||||
[part~="input-field"]::before, [part~="input-field"]::after {
|
|
||||||
background-color: var(--paper-input-container-color, var(--secondary-text-color));
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
:host([focused]) [part~="input-field"]::before, :host([focused]) [part~="input-field"]::after {
|
|
||||||
background-color: var(--paper-input-container-focus-color, var(--primary-color));
|
|
||||||
}
|
|
||||||
|
|
||||||
[part~="value"] {
|
|
||||||
font-size: var(--paper-font-subhead_-_font-size);
|
|
||||||
height: 24px;
|
|
||||||
padding-top: 4px;
|
|
||||||
padding-bottom: 0;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
</template>
|
|
||||||
</dom-module>
|
|
||||||
<dom-module id="ha-date-picker-button-styles" theme-for="vaadin-button">
|
|
||||||
<template>
|
|
||||||
<style>
|
|
||||||
:host([part~="today-button"]) [part~="button"]::before {
|
|
||||||
content: "⦿";
|
|
||||||
color: var(--primary-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
[part~="button"] {
|
|
||||||
font-family: inherit;
|
|
||||||
font-size: var(--paper-font-subhead_-_font-size);
|
|
||||||
border: none;
|
|
||||||
background: transparent;
|
|
||||||
cursor: pointer;
|
|
||||||
min-height: var(--paper-item-min-height, 48px);
|
|
||||||
padding: 0px 16px;
|
|
||||||
color: inherit;
|
|
||||||
}
|
|
||||||
|
|
||||||
[part~="button"]:focus {
|
|
||||||
outline: none;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
</template>
|
|
||||||
</dom-module>
|
|
||||||
<dom-module id="ha-date-picker-overlay-styles" theme-for="vaadin-date-picker-overlay">
|
|
||||||
<template>
|
|
||||||
<style include="vaadin-date-picker-overlay-default-theme">
|
|
||||||
[part~="toolbar"] {
|
|
||||||
padding: 0.3em;
|
|
||||||
background-color: var(--secondary-background-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
[part="years"] {
|
|
||||||
background-color: var(--secondary-text-color);
|
|
||||||
--material-body-text-color: var(--primary-background-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
[part="overlay"] {
|
|
||||||
background-color: var(--primary-background-color);
|
|
||||||
--material-body-text-color: var(--secondary-text-color);
|
|
||||||
}
|
|
||||||
|
|
||||||
</style>
|
|
||||||
</template>
|
|
||||||
</dom-module>
|
|
||||||
<dom-module id="ha-date-picker-month-styles" theme-for="vaadin-month-calendar">
|
|
||||||
<template>
|
|
||||||
<style include="vaadin-month-calendar-default-theme">
|
|
||||||
[part="date"][today] {
|
|
||||||
color: var(--primary-color);
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
</template>
|
|
||||||
</dom-module>
|
|
||||||
`;
|
|
||||||
|
|
||||||
document.head.appendChild(documentContainer.content);
|
|
@ -5,6 +5,7 @@ import { mixinBehaviors } from "@polymer/polymer/lib/legacy/class";
|
|||||||
import { html } from "@polymer/polymer/lib/utils/html-tag";
|
import { html } from "@polymer/polymer/lib/utils/html-tag";
|
||||||
/* eslint-plugin-disable lit */
|
/* eslint-plugin-disable lit */
|
||||||
import { PolymerElement } from "@polymer/polymer/polymer-element";
|
import { PolymerElement } from "@polymer/polymer/polymer-element";
|
||||||
|
import { computeStateDisplay } from "../common/entity/compute_state_display";
|
||||||
import "../components/entity/state-info";
|
import "../components/entity/state-info";
|
||||||
import "../components/ha-slider";
|
import "../components/ha-slider";
|
||||||
|
|
||||||
@ -75,7 +76,7 @@ class StateCardInputNumber extends mixinBehaviors(
|
|||||||
class="state sliderstate"
|
class="state sliderstate"
|
||||||
hidden="[[hiddenslider]]"
|
hidden="[[hiddenslider]]"
|
||||||
>
|
>
|
||||||
[[value]] [[stateObj.attributes.unit_of_measurement]]
|
[[formattedState]]
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
@ -138,6 +139,7 @@ class StateCardInputNumber extends mixinBehaviors(
|
|||||||
},
|
},
|
||||||
step: Number,
|
step: Number,
|
||||||
value: Number,
|
value: Number,
|
||||||
|
formattedState: String,
|
||||||
mode: String,
|
mode: String,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -159,6 +161,12 @@ class StateCardInputNumber extends mixinBehaviors(
|
|||||||
max: Number(newVal.attributes.max),
|
max: Number(newVal.attributes.max),
|
||||||
step: Number(newVal.attributes.step),
|
step: Number(newVal.attributes.step),
|
||||||
value: Number(newVal.state),
|
value: Number(newVal.state),
|
||||||
|
formattedState: computeStateDisplay(
|
||||||
|
this.hass.localize,
|
||||||
|
newVal,
|
||||||
|
this.hass.locale,
|
||||||
|
newVal.state
|
||||||
|
),
|
||||||
mode: String(newVal.attributes.mode),
|
mode: String(newVal.attributes.mode),
|
||||||
maxlength: String(newVal.attributes.max).length,
|
maxlength: String(newVal.attributes.max).length,
|
||||||
hiddenbox: newVal.attributes.mode !== "box",
|
hiddenbox: newVal.attributes.mode !== "box",
|
||||||
|
@ -25,6 +25,9 @@ export const urlSyncMixin = <
|
|||||||
|
|
||||||
public connectedCallback(): void {
|
public connectedCallback(): void {
|
||||||
super.connectedCallback();
|
super.connectedCallback();
|
||||||
|
if (history.length === 1) {
|
||||||
|
history.replaceState({ ...history.state, root: true }, "");
|
||||||
|
}
|
||||||
window.addEventListener("popstate", this._popstateChangeListener);
|
window.addEventListener("popstate", this._popstateChangeListener);
|
||||||
this.addEventListener("dialog-closed", this._dialogClosedListener);
|
this.addEventListener("dialog-closed", this._dialogClosedListener);
|
||||||
}
|
}
|
||||||
|
@ -823,6 +823,14 @@
|
|||||||
"key_not_expected": "Key \"{key}\" is not expected or not supported by the visual editor.",
|
"key_not_expected": "Key \"{key}\" is not expected or not supported by the visual editor.",
|
||||||
"key_wrong_type": "The provided value for \"{key}\" is not supported by the visual editor. We support ({type_correct}) but received ({type_wrong}).",
|
"key_wrong_type": "The provided value for \"{key}\" is not supported by the visual editor. We support ({type_correct}) but received ({type_wrong}).",
|
||||||
"no_template_editor_support": "Templates not supported in visual editor"
|
"no_template_editor_support": "Templates not supported in visual editor"
|
||||||
|
},
|
||||||
|
"supervisor": {
|
||||||
|
"title": "Could not load the Supervisor panel!",
|
||||||
|
"wait": "If you just started, make sure you have given the Supervisor enough time to start.",
|
||||||
|
"ask": "Ask for help",
|
||||||
|
"reboot": "Try a reboot of the host",
|
||||||
|
"observer": "Check the Observer",
|
||||||
|
"system_health": "Check System Health"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"login-form": {
|
"login-form": {
|
||||||
@ -3521,17 +3529,6 @@
|
|||||||
"complete_access": "It will have access to all data in Home Assistant.",
|
"complete_access": "It will have access to all data in Home Assistant.",
|
||||||
"hide_message": "Check docs for the panel_custom component to hide this message"
|
"hide_message": "Check docs for the panel_custom component to hide this message"
|
||||||
}
|
}
|
||||||
},
|
|
||||||
"error": {
|
|
||||||
"go_back": "Go back",
|
|
||||||
"supervisor": {
|
|
||||||
"title": "Could not load the Supervisor panel!",
|
|
||||||
"wait": "If you just started, make sure you have given the supervisor enough time to start.",
|
|
||||||
"ask": "Ask for help",
|
|
||||||
"reboot": "Try a reboot of the host",
|
|
||||||
"observer": "Check the Observer",
|
|
||||||
"system_health": "Check System Health"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -20,25 +20,25 @@ describe("fuzzySequentialMatch", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
const shouldMatchEntity = [
|
const shouldMatchEntity = [
|
||||||
createExpectation("automation.ticker", 138),
|
createExpectation("automation.ticker", 131),
|
||||||
createExpectation("automation.ticke", 129),
|
createExpectation("automation.ticke", 121),
|
||||||
createExpectation("automation.", 89),
|
createExpectation("automation.", 82),
|
||||||
createExpectation("au", 17),
|
createExpectation("au", 10),
|
||||||
createExpectation("automationticker", 107),
|
createExpectation("automationticker", 85),
|
||||||
createExpectation("tion.tick", 18),
|
createExpectation("tion.tick", 8),
|
||||||
createExpectation("ticker", 1),
|
createExpectation("ticker", -4),
|
||||||
createExpectation("automation.r", 89),
|
createExpectation("automation.r", 73),
|
||||||
createExpectation("tick", 1),
|
createExpectation("tick", -8),
|
||||||
createExpectation("aumatick", 15),
|
createExpectation("aumatick", 9),
|
||||||
createExpectation("aion.tck", 14),
|
createExpectation("aion.tck", 4),
|
||||||
createExpectation("ioticker", 19),
|
createExpectation("ioticker", -4),
|
||||||
createExpectation("atmto.ikr", 1),
|
createExpectation("atmto.ikr", -34),
|
||||||
createExpectation("uoaintce", 1),
|
createExpectation("uoaintce", -39),
|
||||||
createExpectation("au.tce", 17),
|
createExpectation("au.tce", -3),
|
||||||
createExpectation("tomaontkr", 9),
|
createExpectation("tomaontkr", -19),
|
||||||
createExpectation("s", 7),
|
createExpectation("s", 1),
|
||||||
createExpectation("stocks", 48),
|
createExpectation("stocks", 42),
|
||||||
createExpectation("sks", 7),
|
createExpectation("sks", -5),
|
||||||
];
|
];
|
||||||
|
|
||||||
const shouldNotMatchEntity = [
|
const shouldNotMatchEntity = [
|
||||||
@ -72,7 +72,7 @@ describe("fuzzySequentialMatch", () => {
|
|||||||
entity.entity_id,
|
entity.entity_id,
|
||||||
entity.friendly_name
|
entity.friendly_name
|
||||||
);
|
);
|
||||||
assert.equal(res, 0);
|
assert.equal(res, undefined);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -80,24 +80,45 @@ describe("fuzzySequentialMatch", () => {
|
|||||||
|
|
||||||
describe("fuzzyFilterSort", () => {
|
describe("fuzzyFilterSort", () => {
|
||||||
const filter = "ticker";
|
const filter = "ticker";
|
||||||
const item1 = {
|
const automationTicker = {
|
||||||
filterText: "automation.ticker",
|
filterText: "automation.ticker",
|
||||||
altText: "Stocks",
|
altText: "Stocks",
|
||||||
score: 0,
|
score: 0,
|
||||||
};
|
};
|
||||||
const item2 = { filterText: "sensor.ticker", altText: "Stocks up", score: 0 };
|
const ticker = {
|
||||||
const item3 = {
|
filterText: "ticker",
|
||||||
|
altText: "Just ticker",
|
||||||
|
score: 0,
|
||||||
|
};
|
||||||
|
const sensorTicker = {
|
||||||
|
filterText: "sensor.ticker",
|
||||||
|
altText: "Stocks up",
|
||||||
|
score: 0,
|
||||||
|
};
|
||||||
|
const timerCheckRouter = {
|
||||||
filterText: "automation.check_router",
|
filterText: "automation.check_router",
|
||||||
altText: "Timer Check Router",
|
altText: "Timer Check Router",
|
||||||
score: 0,
|
score: 0,
|
||||||
};
|
};
|
||||||
const itemsBeforeFilter = [item1, item2, item3];
|
const badMatch = {
|
||||||
|
filterText: "light.chandelier",
|
||||||
|
altText: "Chandelier",
|
||||||
|
score: 0,
|
||||||
|
};
|
||||||
|
const itemsBeforeFilter = [
|
||||||
|
automationTicker,
|
||||||
|
sensorTicker,
|
||||||
|
timerCheckRouter,
|
||||||
|
ticker,
|
||||||
|
badMatch,
|
||||||
|
];
|
||||||
|
|
||||||
it(`sorts correctly`, () => {
|
it(`filters and sorts correctly`, () => {
|
||||||
const expectedItemsAfterFilter = [
|
const expectedItemsAfterFilter = [
|
||||||
{ ...item2, score: 23 },
|
{ ...ticker, score: 44 },
|
||||||
{ ...item3, score: 12 },
|
{ ...sensorTicker, score: 1 },
|
||||||
{ ...item1, score: 1 },
|
{ ...automationTicker, score: -4 },
|
||||||
|
{ ...timerCheckRouter, score: -8 },
|
||||||
];
|
];
|
||||||
|
|
||||||
const res = fuzzyFilterSort(filter, itemsBeforeFilter);
|
const res = fuzzyFilterSort(filter, itemsBeforeFilter);
|
||||||
|
@ -364,7 +364,7 @@
|
|||||||
"change_hostname": "Промяна в името на хоста",
|
"change_hostname": "Промяна в името на хоста",
|
||||||
"confirm_reboot": "Сигурни ли сте, че искате да рестартирате хоста?",
|
"confirm_reboot": "Сигурни ли сте, че искате да рестартирате хоста?",
|
||||||
"confirm_shutdown": "Сигурни ли сте, че искате да изключите хоста?",
|
"confirm_shutdown": "Сигурни ли сте, че искате да изключите хоста?",
|
||||||
"docker_version": "Docker версия",
|
"docker_version": "Версия на Docker",
|
||||||
"failed_to_get_hardware_list": "Неуспешно получаване на списъка с хардуер",
|
"failed_to_get_hardware_list": "Неуспешно получаване на списъка с хардуер",
|
||||||
"failed_to_import_from_usb": "Неуспешно импортиране от USB",
|
"failed_to_import_from_usb": "Неуспешно импортиране от USB",
|
||||||
"failed_to_reboot": "Неуспешно рестартиране на хоста",
|
"failed_to_reboot": "Неуспешно рестартиране на хоста",
|
||||||
@ -640,6 +640,7 @@
|
|||||||
"today": "Днес"
|
"today": "Днес"
|
||||||
},
|
},
|
||||||
"data-table": {
|
"data-table": {
|
||||||
|
"clear": "Изчистване",
|
||||||
"filtering_by": "Филтриране по",
|
"filtering_by": "Филтриране по",
|
||||||
"hidden": "{number} скрити",
|
"hidden": "{number} скрити",
|
||||||
"no-data": "Няма данни",
|
"no-data": "Няма данни",
|
||||||
@ -750,8 +751,10 @@
|
|||||||
"related-filter-menu": {
|
"related-filter-menu": {
|
||||||
"filter_by_area": "Филтриране по област",
|
"filter_by_area": "Филтриране по област",
|
||||||
"filter_by_device": "Филтриране по устройство",
|
"filter_by_device": "Филтриране по устройство",
|
||||||
|
"filter_by_entity": "Филтриране по обект",
|
||||||
"filtered_by_area": "област: {area_name}",
|
"filtered_by_area": "област: {area_name}",
|
||||||
"filtered_by_device": "устройство: {device_name}"
|
"filtered_by_device": "устройство: {device_name}",
|
||||||
|
"filtered_by_entity": "обект: {entity_name}"
|
||||||
},
|
},
|
||||||
"related-items": {
|
"related-items": {
|
||||||
"area": "Област",
|
"area": "Област",
|
||||||
@ -1024,12 +1027,14 @@
|
|||||||
"zha_device_info": {
|
"zha_device_info": {
|
||||||
"buttons": {
|
"buttons": {
|
||||||
"add": "Добавете устройства чрез това устройство",
|
"add": "Добавете устройства чрез това устройство",
|
||||||
|
"clusters": "Управление на клъстери",
|
||||||
"remove": "Премахване на устройство",
|
"remove": "Премахване на устройство",
|
||||||
"zigbee_information": "Подпис на Zigbee устройството"
|
"zigbee_information": "Подпис на Zigbee устройството"
|
||||||
},
|
},
|
||||||
"confirmations": {
|
"confirmations": {
|
||||||
"remove": "Сигурни ли сте, че искате да премахнете устройството?"
|
"remove": "Сигурни ли сте, че искате да премахнете устройството?"
|
||||||
},
|
},
|
||||||
|
"device_signature": "Подпис на Zigbee устройството",
|
||||||
"last_seen": "Последно видян",
|
"last_seen": "Последно видян",
|
||||||
"manuf": "от {manufacturer}",
|
"manuf": "от {manufacturer}",
|
||||||
"no_area": "Без област",
|
"no_area": "Без област",
|
||||||
@ -1492,10 +1497,12 @@
|
|||||||
"title": "Alexa"
|
"title": "Alexa"
|
||||||
},
|
},
|
||||||
"connected": "Свързан",
|
"connected": "Свързан",
|
||||||
|
"connection_status": "Състояние на връзката с облака",
|
||||||
"google": {
|
"google": {
|
||||||
"config_documentation": "Документация за конфигурацията",
|
"config_documentation": "Документация за конфигурацията",
|
||||||
"devices_pin": "ПИН код за Устройства за защита",
|
"devices_pin": "ПИН код за Устройства за защита",
|
||||||
"enter_pin_hint": "Въведете ПИН за използване на устройства за защита",
|
"enter_pin_hint": "Въведете ПИН за използване на устройства за защита",
|
||||||
|
"not_configured_text": "Преди да можете да използвате Google Assistant, трябва да активирате умението Home Assistant Cloud за Google Assistant в приложението Google Home.",
|
||||||
"not_configured_title": "Google Assistant не е активиран",
|
"not_configured_title": "Google Assistant не е активиран",
|
||||||
"security_devices": "Устройства за защита",
|
"security_devices": "Устройства за защита",
|
||||||
"title": "Google Assistant"
|
"title": "Google Assistant"
|
||||||
@ -1507,9 +1514,11 @@
|
|||||||
"not_connected": "Не е свързан",
|
"not_connected": "Не е свързан",
|
||||||
"remote": {
|
"remote": {
|
||||||
"certificate_info": "Информация за сертификата",
|
"certificate_info": "Информация за сертификата",
|
||||||
|
"link_learn_how_it_works": "Научете как работи",
|
||||||
"title": "Дистанционен контрол"
|
"title": "Дистанционен контрол"
|
||||||
},
|
},
|
||||||
"sign_out": "Отписване",
|
"sign_out": "Отписване",
|
||||||
|
"thank_you_note": "Благодарим Ви, че сте част от Home Assistant Cloud. Именно заради хора като вас ние сме в състояние да направим страхотно изживяване при автоматизацията на дома за всички. Благодарим Ви!",
|
||||||
"tts": {
|
"tts": {
|
||||||
"default_language": "Език по подразбиране за използване",
|
"default_language": "Език по подразбиране за използване",
|
||||||
"dialog": {
|
"dialog": {
|
||||||
@ -1632,6 +1641,9 @@
|
|||||||
"description": "Споделяйте доклади за сривове и диагностична информация",
|
"description": "Споделяйте доклади за сривове и диагностична информация",
|
||||||
"title": "Диагностика"
|
"title": "Диагностика"
|
||||||
},
|
},
|
||||||
|
"statistics": {
|
||||||
|
"title": "Статистика за употребата"
|
||||||
|
},
|
||||||
"usage_supervisor": {
|
"usage_supervisor": {
|
||||||
"title": "Използвани интеграции и добавки"
|
"title": "Използвани интеграции и добавки"
|
||||||
},
|
},
|
||||||
@ -1732,7 +1744,7 @@
|
|||||||
"filter": "Филтър",
|
"filter": "Филтър",
|
||||||
"hidden_devices": "{number} скрити {number, plural,\n one {устройство}\n other {устройства}\n}",
|
"hidden_devices": "{number} скрити {number, plural,\n one {устройство}\n other {устройства}\n}",
|
||||||
"show_all": "Покажи всички",
|
"show_all": "Покажи всички",
|
||||||
"show_disabled": "Показване на деактивирани устройства"
|
"show_disabled": "Показване на деактивираните устройства"
|
||||||
},
|
},
|
||||||
"search": "Търсене на устройства"
|
"search": "Търсене на устройства"
|
||||||
},
|
},
|
||||||
@ -1766,7 +1778,11 @@
|
|||||||
},
|
},
|
||||||
"filter": {
|
"filter": {
|
||||||
"filter": "Филтър",
|
"filter": "Филтър",
|
||||||
"show_all": "Покажи всички"
|
"hidden_entities": "{number} скрити {number, plural,\n one {обект}\n other {обекта}\n}",
|
||||||
|
"show_all": "Покажи всички",
|
||||||
|
"show_disabled": "Показване на деактивираните обекти",
|
||||||
|
"show_readonly": "Показване на обектите само за четене",
|
||||||
|
"show_unavailable": "Показване на недостъпните обекти"
|
||||||
},
|
},
|
||||||
"header": "Обекти",
|
"header": "Обекти",
|
||||||
"headers": {
|
"headers": {
|
||||||
@ -1794,6 +1810,9 @@
|
|||||||
"filtering_by": "Филтриране по",
|
"filtering_by": "Филтриране по",
|
||||||
"show": "Покажи"
|
"show": "Покажи"
|
||||||
},
|
},
|
||||||
|
"hassio": {
|
||||||
|
"button": "Конфигуриране"
|
||||||
|
},
|
||||||
"header": "Конфигуриране на Home Assistant",
|
"header": "Конфигуриране на Home Assistant",
|
||||||
"helpers": {
|
"helpers": {
|
||||||
"description": "Елементи, които помагат за изграждането на автоматизации",
|
"description": "Елементи, които помагат за изграждането на автоматизации",
|
||||||
@ -1815,6 +1834,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"info": {
|
"info": {
|
||||||
|
"built_using": "Изграден с използване на",
|
||||||
"caption": "Информация",
|
"caption": "Информация",
|
||||||
"description": "Версия, състояние на системата и връзки към документация",
|
"description": "Версия, състояние на системата и връзки към документация",
|
||||||
"documentation": "Документация",
|
"documentation": "Документация",
|
||||||
@ -1858,6 +1878,7 @@
|
|||||||
"hub": "Свързан чрез",
|
"hub": "Свързан чрез",
|
||||||
"manuf": "от {manufacturer}",
|
"manuf": "от {manufacturer}",
|
||||||
"no_area": "Без област",
|
"no_area": "Без област",
|
||||||
|
"not_loaded": "Не е зареден, проверете {logs_link}",
|
||||||
"options": "Настройки",
|
"options": "Настройки",
|
||||||
"reload": "Презареждане",
|
"reload": "Презареждане",
|
||||||
"reload_confirm": "Интеграцията беше презаредена",
|
"reload_confirm": "Интеграцията беше презаредена",
|
||||||
@ -1887,6 +1908,7 @@
|
|||||||
"disable": {
|
"disable": {
|
||||||
"disabled_integrations": "{number} деактивирани",
|
"disabled_integrations": "{number} деактивирани",
|
||||||
"hide_disabled": "Скриване на деактивираните интеграции",
|
"hide_disabled": "Скриване на деактивираните интеграции",
|
||||||
|
"show": "Покажи",
|
||||||
"show_disabled": "Показване на деактивираните интеграции"
|
"show_disabled": "Показване на деактивираните интеграции"
|
||||||
},
|
},
|
||||||
"discovered": "Открити",
|
"discovered": "Открити",
|
||||||
@ -2114,6 +2136,7 @@
|
|||||||
"header": "Скрипт: {name}",
|
"header": "Скрипт: {name}",
|
||||||
"icon": "Икона",
|
"icon": "Икона",
|
||||||
"id_already_exists": "Това ID вече съществува",
|
"id_already_exists": "Това ID вече съществува",
|
||||||
|
"id_already_exists_save_error": "Не можете да запазите този скрипт, защото идентификаторът не е уникален, изберете друг идентификатор или го оставете празен, за да се генерира автоматично.",
|
||||||
"introduction": "Използвайте скриптове за изпълнение на последователност от действия.",
|
"introduction": "Използвайте скриптове за изпълнение на последователност от действия.",
|
||||||
"link_available_actions": "Научете повече за наличните действия.",
|
"link_available_actions": "Научете повече за наличните действия.",
|
||||||
"modes": {
|
"modes": {
|
||||||
@ -2123,6 +2146,7 @@
|
|||||||
"restart": "Рестарт",
|
"restart": "Рестарт",
|
||||||
"single": "Еднократно (по подразбиране)"
|
"single": "Еднократно (по подразбиране)"
|
||||||
},
|
},
|
||||||
|
"save_script": "Запазване на скрипта",
|
||||||
"sequence": "Последователност",
|
"sequence": "Последователност",
|
||||||
"sequence_sentence": "Последователността на действията на този скрипт."
|
"sequence_sentence": "Последователността на действията на този скрипт."
|
||||||
},
|
},
|
||||||
@ -2135,6 +2159,7 @@
|
|||||||
"name": "Име"
|
"name": "Име"
|
||||||
},
|
},
|
||||||
"learn_more": "Научете повече за скриптовете",
|
"learn_more": "Научете повече за скриптовете",
|
||||||
|
"run_script": "Изпълнете скрипта",
|
||||||
"show_info": "Показване на информация за скрипта"
|
"show_info": "Показване на информация за скрипта"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -2412,6 +2437,7 @@
|
|||||||
"developer-tools": {
|
"developer-tools": {
|
||||||
"tabs": {
|
"tabs": {
|
||||||
"events": {
|
"events": {
|
||||||
|
"available_events": "Налични събития",
|
||||||
"count_listeners": "({count} слушатели)",
|
"count_listeners": "({count} слушатели)",
|
||||||
"title": "Събития"
|
"title": "Събития"
|
||||||
},
|
},
|
||||||
@ -2675,7 +2701,8 @@
|
|||||||
"name": "Вертикална колона"
|
"name": "Вертикална колона"
|
||||||
},
|
},
|
||||||
"weather-forecast": {
|
"weather-forecast": {
|
||||||
"name": "Прогноза за времето"
|
"name": "Прогноза за времето",
|
||||||
|
"show_forecast": "Показване на прогноза"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"cardpicker": {
|
"cardpicker": {
|
||||||
@ -2707,6 +2734,7 @@
|
|||||||
"move_before": "Преместване на картата преди",
|
"move_before": "Преместване на картата преди",
|
||||||
"options": "Още опции",
|
"options": "Още опции",
|
||||||
"pick_card": "Изберете картата, която искате да добавите.",
|
"pick_card": "Изберете картата, която искате да добавите.",
|
||||||
|
"pick_card_view_title": "Коя карта бихте искали да добавите към изгледа си {name}?",
|
||||||
"search_cards": "Търсене на карти",
|
"search_cards": "Търсене на карти",
|
||||||
"show_code_editor": "Редактирайте кода",
|
"show_code_editor": "Редактирайте кода",
|
||||||
"show_visual_editor": "Показване на визуален редактор",
|
"show_visual_editor": "Показване на визуален редактор",
|
||||||
@ -2768,6 +2796,7 @@
|
|||||||
"raw_editor": {
|
"raw_editor": {
|
||||||
"confirm_remove_config_text": "Ние автоматично ще генерираме вашите изгледи на потребителския интерфейс на Lovelace с вашите области и устройства, ако премахнете вашата конфигурация на потребителския интерфейс на Lovelace.",
|
"confirm_remove_config_text": "Ние автоматично ще генерираме вашите изгледи на потребителския интерфейс на Lovelace с вашите области и устройства, ако премахнете вашата конфигурация на потребителския интерфейс на Lovelace.",
|
||||||
"confirm_remove_config_title": "Наистина ли искате да премахнете вашата конфигурация на потребителския интерфейс на Lovelace?",
|
"confirm_remove_config_title": "Наистина ли искате да премахнете вашата конфигурация на потребителския интерфейс на Lovelace?",
|
||||||
|
"confirm_unsaved_changes": "Имате незапазени промени. Наистина ли искате да излезете?",
|
||||||
"confirm_unsaved_comments": "Вашата конфигурация може да съдържа коментар(и), те няма да бъдат запазени. Искате ли да продължите?",
|
"confirm_unsaved_comments": "Вашата конфигурация може да съдържа коментар(и), те няма да бъдат запазени. Искате ли да продължите?",
|
||||||
"error_invalid_config": "Вашата конфигурация не е валидна: {error}",
|
"error_invalid_config": "Вашата конфигурация не е валидна: {error}",
|
||||||
"error_remove": "Конфигурацията не може да бъде премахната: {error}",
|
"error_remove": "Конфигурацията не може да бъде премахната: {error}",
|
||||||
@ -3004,6 +3033,7 @@
|
|||||||
},
|
},
|
||||||
"intro": "Готови ли сте да събудите дома си, да отвоювате независимостта си и да се присъедините към световна общност от хора автоматизиращи домовете си?",
|
"intro": "Готови ли сте да събудите дома си, да отвоювате независимостта си и да се присъедините към световна общност от хора автоматизиращи домовете си?",
|
||||||
"restore": {
|
"restore": {
|
||||||
|
"description": "Като алтернатива можете да възстановите от предишна моментна снимка.",
|
||||||
"in_progress": "Възстановяването е в ход"
|
"in_progress": "Възстановяването е в ход"
|
||||||
},
|
},
|
||||||
"user": {
|
"user": {
|
||||||
|
@ -231,7 +231,7 @@
|
|||||||
},
|
},
|
||||||
"watchdog": {
|
"watchdog": {
|
||||||
"description": "Això farà que s'iniciï el complement en cas de que falli",
|
"description": "Això farà que s'iniciï el complement en cas de que falli",
|
||||||
"title": "Gos vigilant"
|
"title": "Gos guardià"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"protection_mode": {
|
"protection_mode": {
|
||||||
@ -843,8 +843,10 @@
|
|||||||
"related-filter-menu": {
|
"related-filter-menu": {
|
||||||
"filter_by_area": "Filtra per àrea",
|
"filter_by_area": "Filtra per àrea",
|
||||||
"filter_by_device": "Filtra per dispositiu",
|
"filter_by_device": "Filtra per dispositiu",
|
||||||
|
"filter_by_entity": "Filtra per entitat",
|
||||||
"filtered_by_area": "àrea: {area_name}",
|
"filtered_by_area": "àrea: {area_name}",
|
||||||
"filtered_by_device": "dispositiu: {device_name}"
|
"filtered_by_device": "dispositiu: {device_name}",
|
||||||
|
"filtered_by_entity": "entitat: {entity_name}"
|
||||||
},
|
},
|
||||||
"related-items": {
|
"related-items": {
|
||||||
"area": "Àrea",
|
"area": "Àrea",
|
||||||
|
@ -843,8 +843,10 @@
|
|||||||
"related-filter-menu": {
|
"related-filter-menu": {
|
||||||
"filter_by_area": "Filtrovat dle oblasti",
|
"filter_by_area": "Filtrovat dle oblasti",
|
||||||
"filter_by_device": "Filtrovat dle zařízení",
|
"filter_by_device": "Filtrovat dle zařízení",
|
||||||
|
"filter_by_entity": "Filtrovat dle entity",
|
||||||
"filtered_by_area": "oblasti: {area_name}",
|
"filtered_by_area": "oblasti: {area_name}",
|
||||||
"filtered_by_device": "zařízení: {device_name}"
|
"filtered_by_device": "zařízení: {device_name}",
|
||||||
|
"filtered_by_entity": "entita: {entity_name}"
|
||||||
},
|
},
|
||||||
"related-items": {
|
"related-items": {
|
||||||
"area": "Oblast",
|
"area": "Oblast",
|
||||||
|
@ -721,6 +721,9 @@
|
|||||||
"today": "Heute"
|
"today": "Heute"
|
||||||
},
|
},
|
||||||
"data-table": {
|
"data-table": {
|
||||||
|
"clear": "Leeren",
|
||||||
|
"filtering_by": "Filtern nach",
|
||||||
|
"hidden": "{number} ausgeblendet",
|
||||||
"no-data": "Keine Daten",
|
"no-data": "Keine Daten",
|
||||||
"search": "Suche"
|
"search": "Suche"
|
||||||
},
|
},
|
||||||
@ -835,6 +838,14 @@
|
|||||||
"label": "Bild",
|
"label": "Bild",
|
||||||
"unsupported_format": "Nicht unterstütztes Format, bitte wähle ein JPEG-, PNG- oder GIF-Bild."
|
"unsupported_format": "Nicht unterstütztes Format, bitte wähle ein JPEG-, PNG- oder GIF-Bild."
|
||||||
},
|
},
|
||||||
|
"related-filter-menu": {
|
||||||
|
"filter_by_area": "Nach Bereich filtern",
|
||||||
|
"filter_by_device": "Nach Gerät filtern",
|
||||||
|
"filter_by_entity": "Nach Entität filtern",
|
||||||
|
"filtered_by_area": "Bereich: {area_name}",
|
||||||
|
"filtered_by_device": "Gerät: {device_name}",
|
||||||
|
"filtered_by_entity": "Entität: {entity_name}"
|
||||||
|
},
|
||||||
"related-items": {
|
"related-items": {
|
||||||
"area": "Bereich",
|
"area": "Bereich",
|
||||||
"automation": "Teil der folgenden Automatisierungen",
|
"automation": "Teil der folgenden Automatisierungen",
|
||||||
@ -1094,37 +1105,37 @@
|
|||||||
"zone": "Zonen"
|
"zone": "Zonen"
|
||||||
},
|
},
|
||||||
"reload": {
|
"reload": {
|
||||||
"automation": "Automatisierungen neu laden",
|
"automation": "Automatisierungen",
|
||||||
"command_line": "Komandozeilenentätien neu laden",
|
"command_line": "Kommandozeilen-Entitäten",
|
||||||
"core": "Positionsdaten und Anpassungen neu laden",
|
"core": "Positionsdaten & Anpassungen",
|
||||||
"filesize": "Dateigröße-Entitäten neu laden",
|
"filesize": "Dateigröße-Entitäten",
|
||||||
"filter": "Filterentitäten neu laden",
|
"filter": "Filter-Entitäten",
|
||||||
"generic": "Allgemeine IP-Kamera-Entitäten neu laden",
|
"generic": "Allgemeine IP-Kamera Entitäten",
|
||||||
"generic_thermostat": "Allgemeine Thermostat-Entitäten neu laden",
|
"generic_thermostat": "Generische Thermostatentitäten",
|
||||||
"group": "Gruppen, Gruppenentitäten und Benachrichtigungsservices neu laden",
|
"group": "Gruppen, Gruppenentitäten und Benachrichtigungsservices",
|
||||||
"history_stats": "Verlaufsstatistiken neu laden",
|
"history_stats": "Verlaufsstatistik-Entitäten",
|
||||||
"homekit": "HomeKit neu laden",
|
"homekit": "HomeKit",
|
||||||
"input_boolean": "Input-Booleans neu laden",
|
"input_boolean": "Eingabe-Booleans",
|
||||||
"input_datetime": "Input-Datum/Zeit neu laden",
|
"input_datetime": "Eingabe-Datums- und Zeitfelder",
|
||||||
"input_number": "Input-Numern neu laden",
|
"input_number": "Eingabenummern",
|
||||||
"input_select": "Input-Selektionen neu laden",
|
"input_select": "Eingabe-Auswahl",
|
||||||
"input_text": "Input-Texte neu laden",
|
"input_text": "Eingabetexte",
|
||||||
"min_max": "Min/Max-Entitäten neu laden",
|
"min_max": "Min/Max-Entitäten",
|
||||||
"mqtt": "MQTT-Entitäten neu laden",
|
"mqtt": "Manuell konfigurierte MQTT-Entitäten",
|
||||||
"person": "Personen neu laden",
|
"person": "Personen",
|
||||||
"ping": "Binäre-Ping-Entitäten neu laden",
|
"ping": "Binäre Ping-Sensorentitäten",
|
||||||
"reload": "{domain} neu laden",
|
"reload": "{domain}",
|
||||||
"rest": "REST-Entitäten und Benachrichtigunsdienste neu laden",
|
"rest": "Rest-Entitäten und Benachrichtigungsdienste",
|
||||||
"rpi_gpio": "Raspberry Pi GPIO Entitäten neu laden",
|
"rpi_gpio": "Raspberry Pi GPIO Entitäten",
|
||||||
"scene": "Szenen neu laden",
|
"scene": "Szenen",
|
||||||
"script": "Skripte neu laden",
|
"script": "Skripte",
|
||||||
"smtp": "SMTP-Benachrichtigungsdienst neu laden",
|
"smtp": "SMTP-Benachrichtigungsdienste",
|
||||||
"statistics": "Statistikentitäten neu laden",
|
"statistics": "Statistik-Entitäten",
|
||||||
"telegram": "Telegram-Benachrichtigungsdienst neu laden",
|
"telegram": "Telegram-Benachrichtigungsdienste",
|
||||||
"template": "Template-Entitäten neu laden",
|
"template": "Template-Entitäten",
|
||||||
"trend": "Trend-Entitäten neu laden",
|
"trend": "Trend-Entitäten",
|
||||||
"universal": "Universelle Medien-Player-Entitäten neu laden",
|
"universal": "Universelle Media Player-Entitäten",
|
||||||
"zone": "Zonen neu laden"
|
"zone": "Zonen"
|
||||||
},
|
},
|
||||||
"server_control": {
|
"server_control": {
|
||||||
"perform_action": "Server {action}",
|
"perform_action": "Server {action}",
|
||||||
@ -1177,6 +1188,9 @@
|
|||||||
"zha_device_card": {
|
"zha_device_card": {
|
||||||
"device_name_placeholder": "Gerätename ändern"
|
"device_name_placeholder": "Gerätename ändern"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"zha_reconfigure_device": {
|
||||||
|
"heading": "Gerät neu konfigurieren"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"duration": {
|
"duration": {
|
||||||
@ -1305,6 +1319,7 @@
|
|||||||
"extra_fields": {
|
"extra_fields": {
|
||||||
"brightness_pct": "Helligkeit",
|
"brightness_pct": "Helligkeit",
|
||||||
"code": "Code",
|
"code": "Code",
|
||||||
|
"flash": "Blinken",
|
||||||
"humidity": "Luftfeuchtigkeit",
|
"humidity": "Luftfeuchtigkeit",
|
||||||
"message": "Nachricht",
|
"message": "Nachricht",
|
||||||
"mode": "Modus",
|
"mode": "Modus",
|
||||||
@ -1344,9 +1359,9 @@
|
|||||||
"label": "Dienst ausführen"
|
"label": "Dienst ausführen"
|
||||||
},
|
},
|
||||||
"wait_for_trigger": {
|
"wait_for_trigger": {
|
||||||
"continue_timeout": "Bei Zeitüberschreitung fortfahren",
|
"continue_timeout": "Bei Timeout fortsetzen",
|
||||||
"label": "Auf Auslöser warten",
|
"label": "Auf Auslöser warten",
|
||||||
"timeout": "Zeitüberschreitung (optional)"
|
"timeout": "Timeout (optional)"
|
||||||
},
|
},
|
||||||
"wait_template": {
|
"wait_template": {
|
||||||
"continue_timeout": "Bei Timeout fortsetzen",
|
"continue_timeout": "Bei Timeout fortsetzen",
|
||||||
@ -1470,6 +1485,7 @@
|
|||||||
"move_down": "Runterschieben",
|
"move_down": "Runterschieben",
|
||||||
"move_up": "Hochschieben",
|
"move_up": "Hochschieben",
|
||||||
"save": "Speichern",
|
"save": "Speichern",
|
||||||
|
"show_trace": "Trace anzeigen",
|
||||||
"triggers": {
|
"triggers": {
|
||||||
"add": "Auslöser hinzufügen",
|
"add": "Auslöser hinzufügen",
|
||||||
"delete": "Löschen",
|
"delete": "Löschen",
|
||||||
@ -1678,6 +1694,7 @@
|
|||||||
"info": "Mit der Google Assistant-Integration für Home Assistant Cloud kannst du alle deine Home Assistant-Geräte über jedes Google Assistant-fähige Gerät steuern.",
|
"info": "Mit der Google Assistant-Integration für Home Assistant Cloud kannst du alle deine Home Assistant-Geräte über jedes Google Assistant-fähige Gerät steuern.",
|
||||||
"info_state_reporting": "Wenn die Statusberichterstellung aktiviert wird, sendet Home Assistant alle Statusänderungen exponierter Entitäten an Google. So wird in der Google-App immer der neueste Status angezeigt.",
|
"info_state_reporting": "Wenn die Statusberichterstellung aktiviert wird, sendet Home Assistant alle Statusänderungen exponierter Entitäten an Google. So wird in der Google-App immer der neueste Status angezeigt.",
|
||||||
"manage_entities": "Entitäten verwalten",
|
"manage_entities": "Entitäten verwalten",
|
||||||
|
"not_configured_title": "Google Assistant ist nicht aktiviert",
|
||||||
"security_devices": "Sicherheitsgeräte",
|
"security_devices": "Sicherheitsgeräte",
|
||||||
"sync_entities": "Entitäten mit Google synchronisieren",
|
"sync_entities": "Entitäten mit Google synchronisieren",
|
||||||
"sync_entities_404_message": "Fehler beim Synchronisieren deiner Entitäten mit Google. Bitte Google, \"Hey Google, synchronisiere meine Geräte\", deine Entitäten zu synchronisieren.",
|
"sync_entities_404_message": "Fehler beim Synchronisieren deiner Entitäten mit Google. Bitte Google, \"Hey Google, synchronisiere meine Geräte\", deine Entitäten zu synchronisieren.",
|
||||||
@ -1840,6 +1857,36 @@
|
|||||||
"description": "Mengeneinheiten, Standort, Zeitzone & andere allgemeine Parameter",
|
"description": "Mengeneinheiten, Standort, Zeitzone & andere allgemeine Parameter",
|
||||||
"section": {
|
"section": {
|
||||||
"core": {
|
"core": {
|
||||||
|
"analytics": {
|
||||||
|
"documentation": "Bevor du dies aktivierst, stelle sicher, dass du die Statistikdokumentationsseite {link} besuchst, um zu verstehen, was gesendet und gespeichert wird.",
|
||||||
|
"header": "Statistiken",
|
||||||
|
"instance_id": "Instanz-ID: {huuid}",
|
||||||
|
"introduction": "Teile Statistiken aus deiner Instanz. Diese Daten werden öffentlich verfügbar sein unter {link}",
|
||||||
|
"learn_more": "Erfahre mehr darüber, wie deine Daten verarbeitet werden.",
|
||||||
|
"needs_base": "Du musst die Basisstatistiken aktivieren, damit diese Option verfügbar ist",
|
||||||
|
"preference": {
|
||||||
|
"base": {
|
||||||
|
"description": "Dies umfasst die Instanz-ID, die Version und den Installationstyp",
|
||||||
|
"title": "Grundlegende Statistiken"
|
||||||
|
},
|
||||||
|
"diagnostics": {
|
||||||
|
"description": "Teile Absturzberichte und Diagnoseinformationen",
|
||||||
|
"title": "Diagnoseinformationen"
|
||||||
|
},
|
||||||
|
"statistics": {
|
||||||
|
"description": "Dies umfasst die Anzahl von Elementen in deiner Installation. Eine vollständige Liste findest du in der Dokumentation",
|
||||||
|
"title": "Nutzungsstatistiken"
|
||||||
|
},
|
||||||
|
"usage_supervisor": {
|
||||||
|
"description": "Dies umfasst die Namen und Funktionen deiner Integrationen und Add-ons",
|
||||||
|
"title": "Verwendete Integrationen und Add-ons"
|
||||||
|
},
|
||||||
|
"usage": {
|
||||||
|
"description": "Dies umfasst die Namen deiner Integrationen",
|
||||||
|
"title": "Verwendete Integrationen"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"core_config": {
|
"core_config": {
|
||||||
"edit_requires_storage": "Editor deaktiviert, da die Konfiguration in configuration.yaml gespeichert ist.",
|
"edit_requires_storage": "Editor deaktiviert, da die Konfiguration in configuration.yaml gespeichert ist.",
|
||||||
"elevation": "Höhe",
|
"elevation": "Höhe",
|
||||||
@ -2027,6 +2074,9 @@
|
|||||||
"filtering_by": "Filtern nach",
|
"filtering_by": "Filtern nach",
|
||||||
"show": "Anzeigen"
|
"show": "Anzeigen"
|
||||||
},
|
},
|
||||||
|
"hassio": {
|
||||||
|
"button": "Konfigurieren"
|
||||||
|
},
|
||||||
"header": "Home Assistant konfigurieren",
|
"header": "Home Assistant konfigurieren",
|
||||||
"helpers": {
|
"helpers": {
|
||||||
"caption": "Helfer",
|
"caption": "Helfer",
|
||||||
@ -2113,8 +2163,10 @@
|
|||||||
"entity_unavailable": "Entität nicht verfügbar",
|
"entity_unavailable": "Entität nicht verfügbar",
|
||||||
"firmware": "Firmware: {version}",
|
"firmware": "Firmware: {version}",
|
||||||
"hub": "Verbunden über",
|
"hub": "Verbunden über",
|
||||||
|
"logs": "Logs",
|
||||||
"manuf": "von {manufacturer}",
|
"manuf": "von {manufacturer}",
|
||||||
"no_area": "Kein Bereich",
|
"no_area": "Kein Bereich",
|
||||||
|
"not_loaded": "Nicht geladen, prüfe den {logs_link}",
|
||||||
"options": "Optionen",
|
"options": "Optionen",
|
||||||
"reload": "Neu laden",
|
"reload": "Neu laden",
|
||||||
"reload_confirm": "Die Integration wurde neu geladen",
|
"reload_confirm": "Die Integration wurde neu geladen",
|
||||||
@ -2140,6 +2192,7 @@
|
|||||||
"finish": "Fertig",
|
"finish": "Fertig",
|
||||||
"loading_first_time": "Bitte warten, während die Integration installiert wird",
|
"loading_first_time": "Bitte warten, während die Integration installiert wird",
|
||||||
"not_all_required_fields": "Nicht alle Pflichtfelder sind ausgefüllt.",
|
"not_all_required_fields": "Nicht alle Pflichtfelder sind ausgefüllt.",
|
||||||
|
"not_loaded": "Die Integration konnte nicht geladen werden. Versuche Home Assistant neu zu starten.",
|
||||||
"pick_flow_step": {
|
"pick_flow_step": {
|
||||||
"new_flow": "Nein, richte eine andere Instanz von {integration} ein",
|
"new_flow": "Nein, richte eine andere Instanz von {integration} ein",
|
||||||
"title": "Wir haben diese entdeckt, willst du sie einrichten?"
|
"title": "Wir haben diese entdeckt, willst du sie einrichten?"
|
||||||
@ -2154,6 +2207,7 @@
|
|||||||
"disable": {
|
"disable": {
|
||||||
"disabled_integrations": "{number} deaktiviert",
|
"disabled_integrations": "{number} deaktiviert",
|
||||||
"hide_disabled": "Deaktivierte Integrationen ausblenden",
|
"hide_disabled": "Deaktivierte Integrationen ausblenden",
|
||||||
|
"show": "Anzeigen",
|
||||||
"show_disabled": "Deaktivierte Integrationen anzeigen"
|
"show_disabled": "Deaktivierte Integrationen anzeigen"
|
||||||
},
|
},
|
||||||
"discovered": "Entdeckt",
|
"discovered": "Entdeckt",
|
||||||
@ -2189,6 +2243,13 @@
|
|||||||
"clear": "Leeren",
|
"clear": "Leeren",
|
||||||
"description": "Home Assistant Logs einsehen",
|
"description": "Home Assistant Logs einsehen",
|
||||||
"details": "Protokolldetails ({level})",
|
"details": "Protokolldetails ({level})",
|
||||||
|
"level": {
|
||||||
|
"critical": "KRITISCH",
|
||||||
|
"debug": "DEBUG",
|
||||||
|
"error": "FEHLER",
|
||||||
|
"info": "INFO",
|
||||||
|
"warning": "WARNUNG"
|
||||||
|
},
|
||||||
"load_full_log": "Vollständiges Home Assistant-Protokoll laden",
|
"load_full_log": "Vollständiges Home Assistant-Protokoll laden",
|
||||||
"loading_log": "Fehlerprotokoll wird geladen...",
|
"loading_log": "Fehlerprotokoll wird geladen...",
|
||||||
"multiple_messages": "Die Nachricht ist zum ersten Mal um {time} aufgetreten und erscheint {counter} mal",
|
"multiple_messages": "Die Nachricht ist zum ersten Mal um {time} aufgetreten und erscheint {counter} mal",
|
||||||
@ -2279,7 +2340,7 @@
|
|||||||
"description_publish": "Ein Paket veröffentlichen",
|
"description_publish": "Ein Paket veröffentlichen",
|
||||||
"listening_to": "Anhören von",
|
"listening_to": "Anhören von",
|
||||||
"message_received": "Nachricht {id} empfangen auf {topic} um {time}:",
|
"message_received": "Nachricht {id} empfangen auf {topic} um {time}:",
|
||||||
"payload": "Payload (Vorlage erlaubt)",
|
"payload": "Payload (Template erlaubt)",
|
||||||
"publish": "Veröffentlichen",
|
"publish": "Veröffentlichen",
|
||||||
"start_listening": "Anfangen zuzuhören",
|
"start_listening": "Anfangen zuzuhören",
|
||||||
"stop_listening": "Aufhören zuzuhören",
|
"stop_listening": "Aufhören zuzuhören",
|
||||||
@ -2533,39 +2594,39 @@
|
|||||||
"description": "Neustarten und Stoppen des Home Assistant Servers",
|
"description": "Neustarten und Stoppen des Home Assistant Servers",
|
||||||
"section": {
|
"section": {
|
||||||
"reloading": {
|
"reloading": {
|
||||||
"automation": "Automatisierungen neu laden",
|
"automation": "Automatisierungen",
|
||||||
"command_line": "Kommandozeilen-Entitäten neu laden",
|
"command_line": "Kommandozeilen-Entitäten",
|
||||||
"core": "Ort & Anpassungen neu laden",
|
"core": "Ort & Anpassungen",
|
||||||
"filesize": "Dateigröße-Entitäten neu laden",
|
"filesize": "Dateigröße-Entitäten",
|
||||||
"filter": "Filter-Entitäten neu laden",
|
"filter": "Filter-Entitäten",
|
||||||
"generic": "Allgemeine IP-Kamera Entitäten neu laden",
|
"generic": "Allgemeine IP-Kamera Entitäten",
|
||||||
"generic_thermostat": "Generische Thermostatentitäten neu laden",
|
"generic_thermostat": "Generische Thermostatentitäten",
|
||||||
"group": "Gruppen, Gruppenentitäten und Benachrichtigungsdienste neu laden",
|
"group": "Gruppen, Gruppenentitäten und Benachrichtigungsdienste",
|
||||||
"heading": "Neuladen der YAML-Konfiguration",
|
"heading": "Neuladen der YAML-Konfiguration",
|
||||||
"history_stats": "Verlaufsstatistik-Entitäten neu laden",
|
"history_stats": "Verlaufsstatistik-Entitäten",
|
||||||
"homekit": "HomeKit neu laden",
|
"homekit": "HomeKit",
|
||||||
"input_boolean": "Eingabe-Booleans neu laden",
|
"input_boolean": "Eingabe-Booleans",
|
||||||
"input_datetime": "Eingabe-Datums- und Zeitfelder neu laden",
|
"input_datetime": "Eingabe-Datums- und Zeitfelder",
|
||||||
"input_number": "Eingabenummern neu laden",
|
"input_number": "Eingabenummern",
|
||||||
"input_select": "Eingabe-Auswahl neu laden",
|
"input_select": "Eingabe-Auswahl",
|
||||||
"input_text": "Eingabetexte neu laden",
|
"input_text": "Eingabetexte",
|
||||||
"introduction": "Einige Komponenten von Home Assistant können ohne einen Neustart neu geladen werden. \"Neu laden\" entlädt dabei die aktuelle Konfiguration und lädt die neue Konfiguration.",
|
"introduction": "Einige Komponenten von Home Assistant können ohne einen Neustart neu geladen werden. \"Neu laden\" entlädt dabei die aktuelle Konfiguration und lädt die neue Konfiguration.",
|
||||||
"min_max": "Min/Max-Entitäten neu laden",
|
"min_max": "Min/Max-Entitäten",
|
||||||
"mqtt": "Lade manuell konfigurierte MQTT-Entitäten neu",
|
"mqtt": "Manuell konfigurierte MQTT-Entitäten",
|
||||||
"person": "Personen neu laden",
|
"person": "Personen",
|
||||||
"ping": "Binäre Ping-Sensorentitäten neu laden",
|
"ping": "Binäre Ping-Sensorentitäten",
|
||||||
"reload": "{domain} neu laden",
|
"reload": "{domain}",
|
||||||
"rest": "Rest-Entitäten und Benachrichtigungsdienste neu laden",
|
"rest": "Rest-Entitäten und Benachrichtigungsdienste",
|
||||||
"rpi_gpio": "Raspberry Pi GPIO Entitäten neu laden",
|
"rpi_gpio": "Raspberry Pi GPIO Entitäten",
|
||||||
"scene": "Szenen neu laden",
|
"scene": "Szenen",
|
||||||
"script": "Skripte neu laden",
|
"script": "Skripte",
|
||||||
"smtp": "SMTP-Benachrichtigungsdienste neu laden",
|
"smtp": "SMTP-Benachrichtigungsdienste",
|
||||||
"statistics": "Statistik-Entitäten neu laden",
|
"statistics": "Statistik-Entitäten",
|
||||||
"telegram": "Telegram-Benachrichtigungsdienste neu laden",
|
"telegram": "Telegram-Benachrichtigungsdienste",
|
||||||
"template": "Template-Entitäten neu laden",
|
"template": "Template-Entitäten",
|
||||||
"trend": "Trend-Entitäten neu laden",
|
"trend": "Trend-Entitäten",
|
||||||
"universal": "Universelle Media Player-Entitäten neu laden",
|
"universal": "Universelle Media Player-Entitäten",
|
||||||
"zone": "Zonen neu laden"
|
"zone": "Zonen"
|
||||||
},
|
},
|
||||||
"server_management": {
|
"server_management": {
|
||||||
"confirm_restart": "Möchtest du Home Assistant wirklich neu starten?",
|
"confirm_restart": "Möchtest du Home Assistant wirklich neu starten?",
|
||||||
@ -2985,6 +3046,7 @@
|
|||||||
"column_parameter": "Parameter",
|
"column_parameter": "Parameter",
|
||||||
"description": "Mit dem Dienstentwicklungstool kannst du jeden verfügbaren Dienst in Home Assistant aufrufen.",
|
"description": "Mit dem Dienstentwicklungstool kannst du jeden verfügbaren Dienst in Home Assistant aufrufen.",
|
||||||
"fill_example_data": "Mit Beispieldaten füllen",
|
"fill_example_data": "Mit Beispieldaten füllen",
|
||||||
|
"no_template_ui_support": "Die Benutzeroberfläche unterstützt keine Templates. Du kannst aber weiterhin den YAML-Editor verwenden.",
|
||||||
"title": "Dienste",
|
"title": "Dienste",
|
||||||
"ui_mode": "Zum UI Modus",
|
"ui_mode": "Zum UI Modus",
|
||||||
"yaml_mode": "Zum YAML Modus",
|
"yaml_mode": "Zum YAML Modus",
|
||||||
@ -3012,7 +3074,7 @@
|
|||||||
},
|
},
|
||||||
"templates": {
|
"templates": {
|
||||||
"all_listeners": "Dieses Template überwacht alle Zustandsänderungsereignisse.",
|
"all_listeners": "Dieses Template überwacht alle Zustandsänderungsereignisse.",
|
||||||
"description": "Vorlagen werden durch die Jinja2-Template-Engine mit einigen für Home Assistant spezifischen Erweiterungen gerendert.",
|
"description": "Templates werden durch die Jinja2-Template-Engine mit einigen für Home Assistant spezifischen Erweiterungen gerendert.",
|
||||||
"domain": "Domain",
|
"domain": "Domain",
|
||||||
"editor": "Template-Editor",
|
"editor": "Template-Editor",
|
||||||
"entity": "Entität",
|
"entity": "Entität",
|
||||||
@ -3684,6 +3746,10 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"page-onboarding": {
|
"page-onboarding": {
|
||||||
|
"analytics": {
|
||||||
|
"finish": "Weiter",
|
||||||
|
"intro": "Teile Statistiken aus deiner Instanz. Diese Daten werden unter {link}"
|
||||||
|
},
|
||||||
"core-config": {
|
"core-config": {
|
||||||
"button_detect": "Erkennen",
|
"button_detect": "Erkennen",
|
||||||
"finish": "Weiter",
|
"finish": "Weiter",
|
||||||
@ -3693,12 +3759,14 @@
|
|||||||
"location_name": "Name deiner Home Assistant Installation",
|
"location_name": "Name deiner Home Assistant Installation",
|
||||||
"location_name_default": "Home"
|
"location_name_default": "Home"
|
||||||
},
|
},
|
||||||
|
"finish": "Fertig",
|
||||||
"integration": {
|
"integration": {
|
||||||
"finish": "Fertig",
|
"finish": "Fertig",
|
||||||
"intro": "Geräte und Dienste werden in Home Assistant als Integrationen dargestellt. Sie können jetzt oder später über die Konfigurationsseite eingerichtet werden.",
|
"intro": "Geräte und Dienste werden in Home Assistant als Integrationen dargestellt. Sie können jetzt oder später über die Konfigurationsseite eingerichtet werden.",
|
||||||
"more_integrations": "Mehr"
|
"more_integrations": "Mehr"
|
||||||
},
|
},
|
||||||
"intro": "Sind Sie bereit, dein Zuhause zu wecken, Ihre Privatsphäre zurückzugewinnen und einer weltweiten Gemeinschaft von Tüftlern beizutreten?",
|
"intro": "Sind Sie bereit, dein Zuhause zu wecken, Ihre Privatsphäre zurückzugewinnen und einer weltweiten Gemeinschaft von Tüftlern beizutreten?",
|
||||||
|
"next": "Weiter",
|
||||||
"restore": {
|
"restore": {
|
||||||
"description": "Alternativ kannst du von einem vorherigen Snapshot wiederherstellen.",
|
"description": "Alternativ kannst du von einem vorherigen Snapshot wiederherstellen.",
|
||||||
"hide_log": "Vollständiges Protokoll ausblenden",
|
"hide_log": "Vollständiges Protokoll ausblenden",
|
||||||
@ -3793,6 +3861,15 @@
|
|||||||
"enable": "Aktivieren",
|
"enable": "Aktivieren",
|
||||||
"header": "Multi-Faktor-Authentifizierungsmodul"
|
"header": "Multi-Faktor-Authentifizierungsmodul"
|
||||||
},
|
},
|
||||||
|
"number_format": {
|
||||||
|
"description": "Wähle aus, wie Zahlen formatiert werden sollen.",
|
||||||
|
"dropdown_label": "Zahlenformat",
|
||||||
|
"formats": {
|
||||||
|
"language": "Auto (Spracheinstellung verwenden)",
|
||||||
|
"none": "Keine"
|
||||||
|
},
|
||||||
|
"header": "Zahlenformat"
|
||||||
|
},
|
||||||
"push_notifications": {
|
"push_notifications": {
|
||||||
"add_device_prompt": {
|
"add_device_prompt": {
|
||||||
"input_label": "Gerätename",
|
"input_label": "Gerätename",
|
||||||
|
@ -843,8 +843,10 @@
|
|||||||
"related-filter-menu": {
|
"related-filter-menu": {
|
||||||
"filter_by_area": "Filter by area",
|
"filter_by_area": "Filter by area",
|
||||||
"filter_by_device": "Filter by device",
|
"filter_by_device": "Filter by device",
|
||||||
|
"filter_by_entity": "Filter by entity",
|
||||||
"filtered_by_area": "area: {area_name}",
|
"filtered_by_area": "area: {area_name}",
|
||||||
"filtered_by_device": "device: {device_name}"
|
"filtered_by_device": "device: {device_name}",
|
||||||
|
"filtered_by_entity": "entity: {entity_name}"
|
||||||
},
|
},
|
||||||
"related-items": {
|
"related-items": {
|
||||||
"area": "Area",
|
"area": "Area",
|
||||||
|
@ -843,8 +843,10 @@
|
|||||||
"related-filter-menu": {
|
"related-filter-menu": {
|
||||||
"filter_by_area": "Filtrar por área",
|
"filter_by_area": "Filtrar por área",
|
||||||
"filter_by_device": "Filtrar por dispositivo",
|
"filter_by_device": "Filtrar por dispositivo",
|
||||||
|
"filter_by_entity": "Filtrar por entidad",
|
||||||
"filtered_by_area": "área: {area_name}",
|
"filtered_by_area": "área: {area_name}",
|
||||||
"filtered_by_device": "dispositivo: {device_name}"
|
"filtered_by_device": "dispositivo: {device_name}",
|
||||||
|
"filtered_by_entity": "entidad: {entity_name}"
|
||||||
},
|
},
|
||||||
"related-items": {
|
"related-items": {
|
||||||
"area": "Área",
|
"area": "Área",
|
||||||
|
@ -843,8 +843,10 @@
|
|||||||
"related-filter-menu": {
|
"related-filter-menu": {
|
||||||
"filter_by_area": "Filtreeri ala järgi",
|
"filter_by_area": "Filtreeri ala järgi",
|
||||||
"filter_by_device": "Filtreeri seadmete järgi",
|
"filter_by_device": "Filtreeri seadmete järgi",
|
||||||
|
"filter_by_entity": "Filtreeri olemi järgi",
|
||||||
"filtered_by_area": "ala: {area_name}",
|
"filtered_by_area": "ala: {area_name}",
|
||||||
"filtered_by_device": "seade: {device_name}"
|
"filtered_by_device": "seade: {device_name}",
|
||||||
|
"filtered_by_entity": "olem: {entity_name}"
|
||||||
},
|
},
|
||||||
"related-items": {
|
"related-items": {
|
||||||
"area": "Ala",
|
"area": "Ala",
|
||||||
|
@ -99,6 +99,11 @@
|
|||||||
"unknown": "نامشخص"
|
"unknown": "نامشخص"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"supervisor": {
|
||||||
|
"common": {
|
||||||
|
"close": "بستن"
|
||||||
|
}
|
||||||
|
},
|
||||||
"ui": {
|
"ui": {
|
||||||
"auth_store": {
|
"auth_store": {
|
||||||
"ask": "ميخواي وارد سیستم بموني؟",
|
"ask": "ميخواي وارد سیستم بموني؟",
|
||||||
@ -312,6 +317,10 @@
|
|||||||
"play": "پخش",
|
"play": "پخش",
|
||||||
"play-media": "پخش رسانه ها"
|
"play-media": "پخش رسانه ها"
|
||||||
},
|
},
|
||||||
|
"related-filter-menu": {
|
||||||
|
"filtered_by_area": "ناحیه: {area_name}",
|
||||||
|
"filtered_by_device": "دستگاه : {device_name}"
|
||||||
|
},
|
||||||
"related-items": {
|
"related-items": {
|
||||||
"area": "Zona",
|
"area": "Zona",
|
||||||
"device": "Dispozitiv",
|
"device": "Dispozitiv",
|
||||||
@ -450,6 +459,9 @@
|
|||||||
"server_control": "کنترل های سرور",
|
"server_control": "کنترل های سرور",
|
||||||
"users": "کاربران",
|
"users": "کاربران",
|
||||||
"zone": "مناطق"
|
"zone": "مناطق"
|
||||||
|
},
|
||||||
|
"types": {
|
||||||
|
"server_control": "سرور"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -472,6 +484,9 @@
|
|||||||
"zha_device_card": {
|
"zha_device_card": {
|
||||||
"device_name_placeholder": "Prenume utilizator"
|
"device_name_placeholder": "Prenume utilizator"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"zha_reconfigure_device": {
|
||||||
|
"heading": "پیکربندی مجدد دستگاه"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"duration": {
|
"duration": {
|
||||||
@ -891,6 +906,9 @@
|
|||||||
"description": "سیستم واحد ، مکان ، منطقه زمانی و سایر پارامترهای کلی",
|
"description": "سیستم واحد ، مکان ، منطقه زمانی و سایر پارامترهای کلی",
|
||||||
"section": {
|
"section": {
|
||||||
"core": {
|
"core": {
|
||||||
|
"analytics": {
|
||||||
|
"learn_more": "درباره نحوه پردازش داده های خود بیشتر بیاموزید."
|
||||||
|
},
|
||||||
"core_config": {
|
"core_config": {
|
||||||
"edit_requires_storage": "ویرایشگر غیرفعال شده است چون پیکربندی ذخیره شده در configuration.yaml.",
|
"edit_requires_storage": "ویرایشگر غیرفعال شده است چون پیکربندی ذخیره شده در configuration.yaml.",
|
||||||
"elevation": "ارتفاع",
|
"elevation": "ارتفاع",
|
||||||
@ -1031,6 +1049,9 @@
|
|||||||
"clear": "پاک کردن",
|
"clear": "پاک کردن",
|
||||||
"filtering_by": "فیلتر کردن با"
|
"filtering_by": "فیلتر کردن با"
|
||||||
},
|
},
|
||||||
|
"hassio": {
|
||||||
|
"button": "پیکربندی"
|
||||||
|
},
|
||||||
"header": "پیکربندی HOME ASSistant",
|
"header": "پیکربندی HOME ASSistant",
|
||||||
"helpers": {
|
"helpers": {
|
||||||
"caption": "Ajutoare",
|
"caption": "Ajutoare",
|
||||||
@ -1120,6 +1141,13 @@
|
|||||||
},
|
},
|
||||||
"introduction": "در اینجا می توانید اجزای خود و صفحه اصلی دستیار را پیکربندی کنید.فعلا ویرایش همه چیز از طریق ویرایش بصری امکان پذیر نیست ، اما ما داریم روی اون کار می کنیم.",
|
"introduction": "در اینجا می توانید اجزای خود و صفحه اصلی دستیار را پیکربندی کنید.فعلا ویرایش همه چیز از طریق ویرایش بصری امکان پذیر نیست ، اما ما داریم روی اون کار می کنیم.",
|
||||||
"logs": {
|
"logs": {
|
||||||
|
"level": {
|
||||||
|
"critical": "بحرانی",
|
||||||
|
"debug": "اشکال زدایی",
|
||||||
|
"error": "خطا",
|
||||||
|
"info": "اطلاعات",
|
||||||
|
"warning": "هشدار"
|
||||||
|
},
|
||||||
"refresh": "تازه کن"
|
"refresh": "تازه کن"
|
||||||
},
|
},
|
||||||
"lovelace": {
|
"lovelace": {
|
||||||
|
@ -3489,12 +3489,14 @@
|
|||||||
"location_name": "Home Assistant -asennuksen nimi",
|
"location_name": "Home Assistant -asennuksen nimi",
|
||||||
"location_name_default": "Koti"
|
"location_name_default": "Koti"
|
||||||
},
|
},
|
||||||
|
"finish": "Valmis",
|
||||||
"integration": {
|
"integration": {
|
||||||
"finish": "Valmis",
|
"finish": "Valmis",
|
||||||
"intro": "Laitteet ja palvelut on esitetty Home Assistantissa integraatioina. Voit määrittää ne nyt tai tehdä sen myöhemmin asetus valikosta.",
|
"intro": "Laitteet ja palvelut on esitetty Home Assistantissa integraatioina. Voit määrittää ne nyt tai tehdä sen myöhemmin asetus valikosta.",
|
||||||
"more_integrations": "Lisää"
|
"more_integrations": "Lisää"
|
||||||
},
|
},
|
||||||
"intro": "Oletko valmis herättämään kotisi eloon, palauttamaan yksityisyytesi ja liittymään maailmanlaajuiseen nikkarien joukkoon?",
|
"intro": "Oletko valmis herättämään kotisi eloon, palauttamaan yksityisyytesi ja liittymään maailmanlaajuiseen nikkarien joukkoon?",
|
||||||
|
"next": "Seuraava",
|
||||||
"restore": {
|
"restore": {
|
||||||
"description": "Vaihtoehtoisesti voit palauttaa aiemmasta varmuuskopiosta.",
|
"description": "Vaihtoehtoisesti voit palauttaa aiemmasta varmuuskopiosta.",
|
||||||
"hide_log": "Piilota koko loki",
|
"hide_log": "Piilota koko loki",
|
||||||
|
@ -723,6 +723,9 @@
|
|||||||
"today": "Aujourd'hui"
|
"today": "Aujourd'hui"
|
||||||
},
|
},
|
||||||
"data-table": {
|
"data-table": {
|
||||||
|
"clear": "Effacer",
|
||||||
|
"filtering_by": "Filtrer par",
|
||||||
|
"hidden": "{number} masqué",
|
||||||
"no-data": "Pas de données",
|
"no-data": "Pas de données",
|
||||||
"search": "Chercher"
|
"search": "Chercher"
|
||||||
},
|
},
|
||||||
@ -837,6 +840,14 @@
|
|||||||
"label": "Image",
|
"label": "Image",
|
||||||
"unsupported_format": "Format non pris en charge, veuillez choisir une image JPEG, PNG ou GIF."
|
"unsupported_format": "Format non pris en charge, veuillez choisir une image JPEG, PNG ou GIF."
|
||||||
},
|
},
|
||||||
|
"related-filter-menu": {
|
||||||
|
"filter_by_area": "Filtrer par zone",
|
||||||
|
"filter_by_device": "Filtrer par appareil",
|
||||||
|
"filter_by_entity": "Filtrer par entité",
|
||||||
|
"filtered_by_area": "zone: {area_name}",
|
||||||
|
"filtered_by_device": "appareil: {device_name}",
|
||||||
|
"filtered_by_entity": "entité: {entity_name}"
|
||||||
|
},
|
||||||
"related-items": {
|
"related-items": {
|
||||||
"area": "Pièce",
|
"area": "Pièce",
|
||||||
"automation": "Partie des automatisations suivantes",
|
"automation": "Partie des automatisations suivantes",
|
||||||
@ -1132,6 +1143,11 @@
|
|||||||
"perform_action": "{action} Serveur",
|
"perform_action": "{action} Serveur",
|
||||||
"restart": "Redémarrer",
|
"restart": "Redémarrer",
|
||||||
"stop": "Arrêter"
|
"stop": "Arrêter"
|
||||||
|
},
|
||||||
|
"types": {
|
||||||
|
"navigation": "Naviguer",
|
||||||
|
"reload": "Recharger",
|
||||||
|
"server_control": "Serveur"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"filter_placeholder": "Filtre d'entité"
|
"filter_placeholder": "Filtre d'entité"
|
||||||
@ -1174,6 +1190,9 @@
|
|||||||
"zha_device_card": {
|
"zha_device_card": {
|
||||||
"device_name_placeholder": "Nom personnalisé"
|
"device_name_placeholder": "Nom personnalisé"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"zha_reconfigure_device": {
|
||||||
|
"heading": "Reconfigurer l'appareil"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"duration": {
|
"duration": {
|
||||||
@ -1468,6 +1487,7 @@
|
|||||||
"move_down": "Déplacer vers le bas",
|
"move_down": "Déplacer vers le bas",
|
||||||
"move_up": "Déplacer vers le haut",
|
"move_up": "Déplacer vers le haut",
|
||||||
"save": "Sauvegarder",
|
"save": "Sauvegarder",
|
||||||
|
"show_trace": "Afficher la trace",
|
||||||
"triggers": {
|
"triggers": {
|
||||||
"add": "Ajouter un déclencheur",
|
"add": "Ajouter un déclencheur",
|
||||||
"delete": "Supprimer",
|
"delete": "Supprimer",
|
||||||
@ -1676,6 +1696,8 @@
|
|||||||
"info": "Grâce à l'intégration de Google Assistant pour Home Assistant Cloud, vous pourrez contrôler tous vos appareils Home Assistant via n'importe quel appareil compatible avec Google Assistant.",
|
"info": "Grâce à l'intégration de Google Assistant pour Home Assistant Cloud, vous pourrez contrôler tous vos appareils Home Assistant via n'importe quel appareil compatible avec Google Assistant.",
|
||||||
"info_state_reporting": "Si vous activez le rapport d'état, Home Assistant envoie tous les changements d'état des entités exposées à Google. Cela vous permet de toujours voir les derniers états de l'application Google.",
|
"info_state_reporting": "Si vous activez le rapport d'état, Home Assistant envoie tous les changements d'état des entités exposées à Google. Cela vous permet de toujours voir les derniers états de l'application Google.",
|
||||||
"manage_entities": "Gérer les entités",
|
"manage_entities": "Gérer les entités",
|
||||||
|
"not_configured_text": "Avant de pouvoir utiliser Google Assistant, vous devez activer l'action Home Assistant Cloud pour Google Assistant dans l'application Google Home.",
|
||||||
|
"not_configured_title": "Google Assistant n'est pas activé",
|
||||||
"security_devices": "Dispositif de sécurité",
|
"security_devices": "Dispositif de sécurité",
|
||||||
"sync_entities": "Synchroniser les entités vers Google",
|
"sync_entities": "Synchroniser les entités vers Google",
|
||||||
"sync_entities_404_message": "Échec de la synchronisation de vos entités avec Google, demandez à Google \"Hey Google, synchronise mes appareils\" de synchroniser vos entités.",
|
"sync_entities_404_message": "Échec de la synchronisation de vos entités avec Google, demandez à Google \"Hey Google, synchronise mes appareils\" de synchroniser vos entités.",
|
||||||
@ -1838,6 +1860,23 @@
|
|||||||
"description": "Unités de mesure, emplacement, fuseau horaire et autres paramètres généraux",
|
"description": "Unités de mesure, emplacement, fuseau horaire et autres paramètres généraux",
|
||||||
"section": {
|
"section": {
|
||||||
"core": {
|
"core": {
|
||||||
|
"analytics": {
|
||||||
|
"documentation": "Avant d'activer cette fonction, prenez soin de visiter la page de documentation {link} afin de comprendre ce que vous envoyez et comment cela est conservé.",
|
||||||
|
"instance_id": "ID de l'instance: {huuid}",
|
||||||
|
"learn_more": "En appendre plus sur le traitement de vos données",
|
||||||
|
"preference": {
|
||||||
|
"diagnostics": {
|
||||||
|
"description": "Partager les rapports d'accident et les informations de diagnostic",
|
||||||
|
"title": "Diagnostiques"
|
||||||
|
},
|
||||||
|
"statistics": {
|
||||||
|
"title": "Statistiques d'utilisation"
|
||||||
|
},
|
||||||
|
"usage": {
|
||||||
|
"title": "Intégrations utilisées"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"core_config": {
|
"core_config": {
|
||||||
"edit_requires_storage": "L'éditeur est désactivé car la configuration est stockée dans configuration.yaml.",
|
"edit_requires_storage": "L'éditeur est désactivé car la configuration est stockée dans configuration.yaml.",
|
||||||
"elevation": "Élévation",
|
"elevation": "Élévation",
|
||||||
@ -2025,6 +2064,9 @@
|
|||||||
"filtering_by": "Filtrage par",
|
"filtering_by": "Filtrage par",
|
||||||
"show": "Montrer"
|
"show": "Montrer"
|
||||||
},
|
},
|
||||||
|
"hassio": {
|
||||||
|
"button": "Configurer"
|
||||||
|
},
|
||||||
"header": "Configurer Home Assistant",
|
"header": "Configurer Home Assistant",
|
||||||
"helpers": {
|
"helpers": {
|
||||||
"caption": "Entrées",
|
"caption": "Entrées",
|
||||||
@ -2111,6 +2153,7 @@
|
|||||||
"entity_unavailable": "Entité indisponible",
|
"entity_unavailable": "Entité indisponible",
|
||||||
"firmware": "Firmware: {version}",
|
"firmware": "Firmware: {version}",
|
||||||
"hub": "Connecté via",
|
"hub": "Connecté via",
|
||||||
|
"logs": "journaux",
|
||||||
"manuf": "par {manufacturer}",
|
"manuf": "par {manufacturer}",
|
||||||
"no_area": "Pas de zone",
|
"no_area": "Pas de zone",
|
||||||
"options": "Options",
|
"options": "Options",
|
||||||
@ -2138,6 +2181,7 @@
|
|||||||
"finish": "Terminer",
|
"finish": "Terminer",
|
||||||
"loading_first_time": "Veuillez patienter pendant que l'intégration est en cours d'installation",
|
"loading_first_time": "Veuillez patienter pendant que l'intégration est en cours d'installation",
|
||||||
"not_all_required_fields": "Tous les champs obligatoires ne sont pas renseignés.",
|
"not_all_required_fields": "Tous les champs obligatoires ne sont pas renseignés.",
|
||||||
|
"not_loaded": "Cette intégration ne peut être chargée, essayez de redémarrer Home Assistant",
|
||||||
"pick_flow_step": {
|
"pick_flow_step": {
|
||||||
"new_flow": "Non, configurez une autre instance de {integration}",
|
"new_flow": "Non, configurez une autre instance de {integration}",
|
||||||
"title": "Nous les avons découverts, vous voulez les mettre en place?"
|
"title": "Nous les avons découverts, vous voulez les mettre en place?"
|
||||||
@ -2152,6 +2196,7 @@
|
|||||||
"disable": {
|
"disable": {
|
||||||
"disabled_integrations": "{number} désactivé",
|
"disabled_integrations": "{number} désactivé",
|
||||||
"hide_disabled": "Masquer les intégrations désactivées",
|
"hide_disabled": "Masquer les intégrations désactivées",
|
||||||
|
"show": "Montrer",
|
||||||
"show_disabled": "Afficher les intégrations désactivées"
|
"show_disabled": "Afficher les intégrations désactivées"
|
||||||
},
|
},
|
||||||
"discovered": "Découvert",
|
"discovered": "Découvert",
|
||||||
@ -2187,6 +2232,12 @@
|
|||||||
"clear": "Nettoyer",
|
"clear": "Nettoyer",
|
||||||
"description": "Afficher les journaux de Home Assistant",
|
"description": "Afficher les journaux de Home Assistant",
|
||||||
"details": "Détails du journal ( {level} )",
|
"details": "Détails du journal ( {level} )",
|
||||||
|
"level": {
|
||||||
|
"critical": "CRITIQUE",
|
||||||
|
"error": "ERREUR",
|
||||||
|
"info": "INFO",
|
||||||
|
"warning": "ATTENTION"
|
||||||
|
},
|
||||||
"load_full_log": "Charger le journal complet de Home Assistant",
|
"load_full_log": "Charger le journal complet de Home Assistant",
|
||||||
"loading_log": "Chargement du journal des erreurs…",
|
"loading_log": "Chargement du journal des erreurs…",
|
||||||
"multiple_messages": "message survenu pour la première fois à {time} et apparu {counter} fois.",
|
"multiple_messages": "message survenu pour la première fois à {time} et apparu {counter} fois.",
|
||||||
@ -3682,6 +3733,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"page-onboarding": {
|
"page-onboarding": {
|
||||||
|
"analytics": {
|
||||||
|
"finish": "Suivant"
|
||||||
|
},
|
||||||
"core-config": {
|
"core-config": {
|
||||||
"button_detect": "Détecter",
|
"button_detect": "Détecter",
|
||||||
"finish": "Suivant",
|
"finish": "Suivant",
|
||||||
@ -3691,12 +3745,14 @@
|
|||||||
"location_name": "Nom de votre installation Home Assistant",
|
"location_name": "Nom de votre installation Home Assistant",
|
||||||
"location_name_default": "Maison"
|
"location_name_default": "Maison"
|
||||||
},
|
},
|
||||||
|
"finish": "Terminer",
|
||||||
"integration": {
|
"integration": {
|
||||||
"finish": "Terminer",
|
"finish": "Terminer",
|
||||||
"intro": "Les appareils et les services sont représentés dans Home Assistant sous forme d’intégrations. Vous pouvez les configurer maintenant ou le faire plus tard à partir de l'écran de configuration.",
|
"intro": "Les appareils et les services sont représentés dans Home Assistant sous forme d’intégrations. Vous pouvez les configurer maintenant ou le faire plus tard à partir de l'écran de configuration.",
|
||||||
"more_integrations": "Plus"
|
"more_integrations": "Plus"
|
||||||
},
|
},
|
||||||
"intro": "Êtes-vous prêt à réveiller votre maison, à récupérer votre vie privée et à rejoindre une communauté mondiale de bricoleurs?",
|
"intro": "Êtes-vous prêt à réveiller votre maison, à récupérer votre vie privée et à rejoindre une communauté mondiale de bricoleurs?",
|
||||||
|
"next": "Suivant",
|
||||||
"restore": {
|
"restore": {
|
||||||
"description": "Vous pouvez également restaurer à partir d'un instantané précédent.",
|
"description": "Vous pouvez également restaurer à partir d'un instantané précédent.",
|
||||||
"hide_log": "Masquer le journal",
|
"hide_log": "Masquer le journal",
|
||||||
@ -3791,6 +3847,12 @@
|
|||||||
"enable": "Activer",
|
"enable": "Activer",
|
||||||
"header": "Modules d'authentification multi-facteurs"
|
"header": "Modules d'authentification multi-facteurs"
|
||||||
},
|
},
|
||||||
|
"number_format": {
|
||||||
|
"description": "Définir le formatage des nombres",
|
||||||
|
"formats": {
|
||||||
|
"none": "Aucun"
|
||||||
|
}
|
||||||
|
},
|
||||||
"push_notifications": {
|
"push_notifications": {
|
||||||
"add_device_prompt": {
|
"add_device_prompt": {
|
||||||
"input_label": "Nom de l'appareil",
|
"input_label": "Nom de l'appareil",
|
||||||
|
@ -165,6 +165,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"common": {
|
"common": {
|
||||||
|
"cancel": "Cancelar",
|
||||||
"close": "Pechar",
|
"close": "Pechar",
|
||||||
"description": "Descrición",
|
"description": "Descrición",
|
||||||
"error": {
|
"error": {
|
||||||
@ -175,8 +176,10 @@
|
|||||||
"failed_to_update_name": "Non se puido actualizar {name}",
|
"failed_to_update_name": "Non se puido actualizar {name}",
|
||||||
"learn_more": "Aprender máis",
|
"learn_more": "Aprender máis",
|
||||||
"new_version_available": "Nova versión dispoñible",
|
"new_version_available": "Nova versión dispoñible",
|
||||||
|
"newest_version": "Versión máis nova",
|
||||||
"no": "Non",
|
"no": "Non",
|
||||||
"refresh": "Actualizar",
|
"refresh": "Actualizar",
|
||||||
|
"release_notes": "Notas de lanzamento",
|
||||||
"reload": "Recargar",
|
"reload": "Recargar",
|
||||||
"reset_defaults": "Restablecer os valores predeterminados",
|
"reset_defaults": "Restablecer os valores predeterminados",
|
||||||
"reset_options": "Restablecer as opcións",
|
"reset_options": "Restablecer as opcións",
|
||||||
@ -185,6 +188,7 @@
|
|||||||
"running_version": "Actualmente estás executando a versión {version}",
|
"running_version": "Actualmente estás executando a versión {version}",
|
||||||
"save": "Gardar",
|
"save": "Gardar",
|
||||||
"show_more": "Amosar máis información sobre isto",
|
"show_more": "Amosar máis información sobre isto",
|
||||||
|
"update": "Actualización",
|
||||||
"update_available": "{count, plural,\n one {actualización pendente}\n other {{count} actualizacións pendentes}\n}",
|
"update_available": "{count, plural,\n one {actualización pendente}\n other {{count} actualizacións pendentes}\n}",
|
||||||
"version": "Versión",
|
"version": "Versión",
|
||||||
"yes": "Si"
|
"yes": "Si"
|
||||||
@ -387,7 +391,11 @@
|
|||||||
"ui": {
|
"ui": {
|
||||||
"card": {
|
"card": {
|
||||||
"fan": {
|
"fan": {
|
||||||
"direction": "Enderezo"
|
"direction": "Enderezo",
|
||||||
|
"preset_mode": "Modo predefinido"
|
||||||
|
},
|
||||||
|
"script": {
|
||||||
|
"run": "Executar"
|
||||||
},
|
},
|
||||||
"weather": {
|
"weather": {
|
||||||
"attributes": {
|
"attributes": {
|
||||||
@ -441,7 +449,9 @@
|
|||||||
"show_areas": "Amosar áreas"
|
"show_areas": "Amosar áreas"
|
||||||
},
|
},
|
||||||
"data-table": {
|
"data-table": {
|
||||||
"clear": "Elim"
|
"clear": "Elim",
|
||||||
|
"filtering_by": "Filtrando por",
|
||||||
|
"hidden": "{number} oculto"
|
||||||
},
|
},
|
||||||
"device-picker": {
|
"device-picker": {
|
||||||
"show_devices": "Amosar dispositivos"
|
"show_devices": "Amosar dispositivos"
|
||||||
@ -461,11 +471,23 @@
|
|||||||
},
|
},
|
||||||
"show_trace": "Amosar rastro"
|
"show_trace": "Amosar rastro"
|
||||||
},
|
},
|
||||||
|
"media-browser": {
|
||||||
|
"class": {
|
||||||
|
"url": "URL"
|
||||||
|
}
|
||||||
|
},
|
||||||
"related-filter-menu": {
|
"related-filter-menu": {
|
||||||
"filter_by_area": "Filtrar por área",
|
"filter_by_area": "Filtrar por área",
|
||||||
"filter_by_device": "Filtrar por dispositivo",
|
"filter_by_device": "Filtrar por dispositivo",
|
||||||
|
"filter_by_entity": "Filtrar por entidade",
|
||||||
"filtered_by_area": "área: {area_name}",
|
"filtered_by_area": "área: {area_name}",
|
||||||
"filtered_by_device": "dispositivo: {device_name}"
|
"filtered_by_device": "dispositivo: {device_name}",
|
||||||
|
"filtered_by_entity": "entidade: {entity_name}"
|
||||||
|
},
|
||||||
|
"service-control": {
|
||||||
|
"required": "Este campo é necesario",
|
||||||
|
"service_data": "Datos do servizo",
|
||||||
|
"target": "Obxectivos"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"dialogs": {
|
"dialogs": {
|
||||||
@ -496,10 +518,18 @@
|
|||||||
"view_in_visualization": "Ver en Visualización"
|
"view_in_visualization": "Ver en Visualización"
|
||||||
},
|
},
|
||||||
"device_children": "Dispositivos Zigbee fillos"
|
"device_children": "Dispositivos Zigbee fillos"
|
||||||
|
},
|
||||||
|
"zha_reconfigure_device": {
|
||||||
|
"heading": "Reconfiguración do dispositivo"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"errors": {
|
"errors": {
|
||||||
"config": {
|
"config": {
|
||||||
|
"edit_in_yaml_supported": "Aínda podes editar a túa configuración en YAML.",
|
||||||
|
"editor_not_available": "Non hai editor visual dispoñible para o tipo \" {type} \".",
|
||||||
|
"editor_not_supported": "O editor visual non é compatible con esta configuración",
|
||||||
|
"key_missing": "Falta a clave requirida \" {key} \".",
|
||||||
|
"key_wrong_type": "O editor visual non admite o valor proporcionado para \" {key} Admitimos ( {type_correct} ) pero recibimos ( {type_wrong} ).",
|
||||||
"no_template_editor_support": "Os modelos non son compatibles co editor visual"
|
"no_template_editor_support": "Os modelos non son compatibles co editor visual"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -569,6 +599,16 @@
|
|||||||
"google": {
|
"google": {
|
||||||
"not_configured_text": "Antes de usar o Asistente de Google, debes activar a skill Home Assistant Cloud para Google Assistant na aplicación Google Home.",
|
"not_configured_text": "Antes de usar o Asistente de Google, debes activar a skill Home Assistant Cloud para Google Assistant na aplicación Google Home.",
|
||||||
"not_configured_title": "Google Assistant non está activado"
|
"not_configured_title": "Google Assistant non está activado"
|
||||||
|
},
|
||||||
|
"tts": {
|
||||||
|
"dialog": {
|
||||||
|
"example_message": "Ola {name} , podes reproducir calquera texto en calquera reprodutor multimedia compatible.",
|
||||||
|
"header": "Proba Texto a voz",
|
||||||
|
"play": "Reproducir",
|
||||||
|
"target": "Obxectivo",
|
||||||
|
"target_browser": "Navegador"
|
||||||
|
},
|
||||||
|
"try": "Probar"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"forgot_password": {
|
"forgot_password": {
|
||||||
@ -602,6 +642,7 @@
|
|||||||
"title": "Estatísticas de uso"
|
"title": "Estatísticas de uso"
|
||||||
},
|
},
|
||||||
"usage_supervisor": {
|
"usage_supervisor": {
|
||||||
|
"description": "Isto inclúe os nomes e as capacidades das súas integracións e complementos",
|
||||||
"title": "Integracións e complementos usados"
|
"title": "Integracións e complementos usados"
|
||||||
},
|
},
|
||||||
"usage": {
|
"usage": {
|
||||||
@ -614,6 +655,7 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"devices": {
|
"devices": {
|
||||||
|
"confirm_disable_config_entry": "Non hai máis dispositivos para a entrada de configuración {entry_name} . Queres deshabilitar a entrada de configuración?",
|
||||||
"enabled_description": "Os dispositivos desactivados non se amosarán e as entidades que pertencen ao dispositivo desactivaranse e non se engadirán ao Asistente doméstico.",
|
"enabled_description": "Os dispositivos desactivados non se amosarán e as entidades que pertencen ao dispositivo desactivaranse e non se engadirán ao Asistente doméstico.",
|
||||||
"picker": {
|
"picker": {
|
||||||
"filter": {
|
"filter": {
|
||||||
@ -635,15 +677,39 @@
|
|||||||
"filtering": {
|
"filtering": {
|
||||||
"show": "Amosar"
|
"show": "Amosar"
|
||||||
},
|
},
|
||||||
|
"hassio": {
|
||||||
|
"button": "Configurar"
|
||||||
|
},
|
||||||
"integrations": {
|
"integrations": {
|
||||||
"config_entry": {
|
"config_entry": {
|
||||||
|
"disable_restart_confirm": "Reinicie o Home Assistant para rematar de desactivar esta integración",
|
||||||
|
"disable": {
|
||||||
|
"disable_confirm": "Seguro que queres desactivar esta entrada de configuración? Os seus dispositivos e entidades estarán desactivados.",
|
||||||
|
"disabled": "Desactivado",
|
||||||
|
"disabled_by": {
|
||||||
|
"device": "dispositivo",
|
||||||
|
"integration": "integración",
|
||||||
|
"user": "usuario"
|
||||||
|
},
|
||||||
|
"disabled_cause": "Desactivado por {cause}"
|
||||||
|
},
|
||||||
|
"enable_restart_confirm": "Reinicie o Home Assistant para rematar de habilitar esta integración",
|
||||||
"logs": "rexistros",
|
"logs": "rexistros",
|
||||||
"not_loaded": "Non cargado, comproba o {logs_link}"
|
"not_loaded": "Non cargado, comproba o {logs_link}"
|
||||||
},
|
},
|
||||||
"config_flow": {
|
"config_flow": {
|
||||||
"not_loaded": "Non se puido cargar a integración. Tenta reiniciar Home Assistant."
|
"could_not_load": "Non se puido cargar o fluxo de configuración",
|
||||||
|
"error": "Erro",
|
||||||
|
"not_loaded": "Non se puido cargar a integración. Tenta reiniciar Home Assistant.",
|
||||||
|
"pick_flow_step": {
|
||||||
|
"new_flow": "Non, configura outra instancia de {integration}",
|
||||||
|
"title": "Descubrimos estes, queres montalos?"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
|
"confirm_new": "¿Queres configurar {integration} ?",
|
||||||
"disable": {
|
"disable": {
|
||||||
|
"disabled_integrations": "{number} desactivado",
|
||||||
|
"hide_disabled": "Ocultar integracións desactivadas",
|
||||||
"show": "Amosar",
|
"show": "Amosar",
|
||||||
"show_disabled": "Amosar as integracións desactivadas"
|
"show_disabled": "Amosar as integracións desactivadas"
|
||||||
},
|
},
|
||||||
@ -689,9 +755,23 @@
|
|||||||
"show_info": "Amosar información sobre o script"
|
"show_info": "Amosar información sobre o script"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"server_control": {
|
||||||
|
"section": {
|
||||||
|
"reloading": {
|
||||||
|
"filesize": "Entidades de tamaño de ficheiro",
|
||||||
|
"mqtt": "Entidades MQTT configuradas manualmente",
|
||||||
|
"ping": "Ping a entidades binarias do sensor",
|
||||||
|
"reload": "{domain}",
|
||||||
|
"rpi_gpio": "Entidades GPIO de Raspberry Pi",
|
||||||
|
"smtp": "Servizos de notificación SMTP",
|
||||||
|
"trend": "Entidades de tendencia"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"users": {
|
"users": {
|
||||||
"editor": {
|
"editor": {
|
||||||
"name": "Nome de visualización"
|
"name": "Nome de visualización",
|
||||||
|
"password_changed": "O contrasinal cambiouse correctamente"
|
||||||
},
|
},
|
||||||
"picker": {
|
"picker": {
|
||||||
"headers": {
|
"headers": {
|
||||||
@ -720,6 +800,12 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"zwave": {
|
"zwave": {
|
||||||
|
"migration": {
|
||||||
|
"ozw": {
|
||||||
|
"header": "Migrar a OpenZWave",
|
||||||
|
"introduction": "Este asistente axudarache a migrar da integración herdada de Z-Wave á integración OpenZWave que está actualmente en versión beta."
|
||||||
|
}
|
||||||
|
},
|
||||||
"ozw_log": {
|
"ozw_log": {
|
||||||
"introduction": "Ver o rexistro. 0 é o mínimo (carga todo o rexistro) e 1000 é o máximo. Load amosará un rexistro estático e a cola actualizarase automaticamente co último número de liñas especificado no rexistro."
|
"introduction": "Ver o rexistro. 0 é o mínimo (carga todo o rexistro) e 1000 é o máximo. Load amosará un rexistro estático e a cola actualizarase automaticamente co último número de liñas especificado no rexistro."
|
||||||
}
|
}
|
||||||
@ -728,9 +814,18 @@
|
|||||||
"developer-tools": {
|
"developer-tools": {
|
||||||
"tabs": {
|
"tabs": {
|
||||||
"services": {
|
"services": {
|
||||||
"no_template_ui_support": "A interface de usuario non admite modelos, máis podes usar o editor YAML."
|
"accepts_target": "Este servizo acepta un destino, por exemplo: `entity_id: light.bed_light`",
|
||||||
|
"all_parameters": "Todos os parámetros dispoñibles",
|
||||||
|
"no_template_ui_support": "A interface de usuario non admite modelos, máis podes usar o editor YAML.",
|
||||||
|
"ui_mode": "Ir ao modo de interface de usuario",
|
||||||
|
"yaml_mode": "Ir ao modo YAML",
|
||||||
|
"yaml_parameters": "Os parámetros só están dispoñibles no modo YAML"
|
||||||
|
},
|
||||||
|
"states": {
|
||||||
|
"copy_id": "Copia a identificación ao portapapeis"
|
||||||
},
|
},
|
||||||
"templates": {
|
"templates": {
|
||||||
|
"no_listeners": "Este modelo non escoita ningún evento e non se actualizará automaticamente.",
|
||||||
"unknown_error_template": "Erro descoñecido ao amosar o modelo"
|
"unknown_error_template": "Erro descoñecido ao amosar o modelo"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -886,6 +981,10 @@
|
|||||||
"show_visual_editor": "Amosar editor visual",
|
"show_visual_editor": "Amosar editor visual",
|
||||||
"typed_header": "Configuración da tarxeta {type}"
|
"typed_header": "Configuración da tarxeta {type}"
|
||||||
},
|
},
|
||||||
|
"menu": {
|
||||||
|
"manage_dashboards": "Xestionar paneis",
|
||||||
|
"manage_resources": "Xestionar recursos"
|
||||||
|
},
|
||||||
"migrate": {
|
"migrate": {
|
||||||
"para_migrate": "Home Assistant pode engadir identificacións a todas as súas tarxetas e vistas automaticamente premendo o botón \"Migrar configuración\"."
|
"para_migrate": "Home Assistant pode engadir identificacións a todas as súas tarxetas e vistas automaticamente premendo o botón \"Migrar configuración\"."
|
||||||
},
|
},
|
||||||
@ -917,12 +1016,15 @@
|
|||||||
"my": {
|
"my": {
|
||||||
"component_not_loaded": "Esta redirección non é compatible coa túa instancia de Home Assistant. Necesitas a integración {integration} para usar esta redirección.",
|
"component_not_loaded": "Esta redirección non é compatible coa túa instancia de Home Assistant. Necesitas a integración {integration} para usar esta redirección.",
|
||||||
"documentation": "documentación",
|
"documentation": "documentación",
|
||||||
|
"error": "Produciuse un erro descoñecido",
|
||||||
|
"faq_link": "Preguntas máis frecuentes sobre o meu Home Assistant",
|
||||||
"no_supervisor": "Esta redirección non é compatible coa instalación do teu Home Assistant. Precísase o sistema operativo Home Assistant ou o método de instalación do Home Assistant supervisado. Para obter máis información, consulte o {docs_link} .",
|
"no_supervisor": "Esta redirección non é compatible coa instalación do teu Home Assistant. Precísase o sistema operativo Home Assistant ou o método de instalación do Home Assistant supervisado. Para obter máis información, consulte o {docs_link} .",
|
||||||
"not_supported": "Esta redirección non é compatible coa túa instancia de Home Assistant. Comprobe a {link} para coñecer as redireccións compatibles e a versión na que se introduciron."
|
"not_supported": "Esta redirección non é compatible coa túa instancia de Home Assistant. Comprobe a {link} para coñecer as redireccións compatibles e a versión na que se introduciron."
|
||||||
},
|
},
|
||||||
"page-onboarding": {
|
"page-onboarding": {
|
||||||
"analytics": {
|
"analytics": {
|
||||||
"finish": "Seguinte"
|
"finish": "Seguinte",
|
||||||
|
"intro": "Comparte análises desde a túa instancia. Estes datos estarán dispoñibles publicamente en {link}"
|
||||||
},
|
},
|
||||||
"core-config": {
|
"core-config": {
|
||||||
"intro_location": "Gustaríanos saber onde vives. Esta información axudará a amosar información e configurar automatismos baseados no sol. Estes datos nunca se comparten fóra da túa rede."
|
"intro_location": "Gustaríanos saber onde vives. Esta información axudará a amosar información e configurar automatismos baseados no sol. Estes datos nunca se comparten fóra da túa rede."
|
||||||
|
@ -245,7 +245,7 @@
|
|||||||
"start": "avvia",
|
"start": "avvia",
|
||||||
"stop": "arresta",
|
"stop": "arresta",
|
||||||
"uninstall": "disinstalla",
|
"uninstall": "disinstalla",
|
||||||
"visit_addon_page": "Visita la pagina con {name} per maggiori dettagli"
|
"visit_addon_page": "Visita la pagina di {name} per maggiori dettagli"
|
||||||
},
|
},
|
||||||
"documentation": {
|
"documentation": {
|
||||||
"get_documentation": "Impossibile ottenere la documentazione del componente aggiuntivo, {error}"
|
"get_documentation": "Impossibile ottenere la documentazione del componente aggiuntivo, {error}"
|
||||||
@ -843,8 +843,10 @@
|
|||||||
"related-filter-menu": {
|
"related-filter-menu": {
|
||||||
"filter_by_area": "Filtra per area",
|
"filter_by_area": "Filtra per area",
|
||||||
"filter_by_device": "Filtra per dispositivo",
|
"filter_by_device": "Filtra per dispositivo",
|
||||||
|
"filter_by_entity": "Filtra per entità",
|
||||||
"filtered_by_area": "area: {area_name}",
|
"filtered_by_area": "area: {area_name}",
|
||||||
"filtered_by_device": "dispositivo: {device_name}"
|
"filtered_by_device": "dispositivo: {device_name}",
|
||||||
|
"filtered_by_entity": "entità: {entity_name}"
|
||||||
},
|
},
|
||||||
"related-items": {
|
"related-items": {
|
||||||
"area": "Area",
|
"area": "Area",
|
||||||
@ -1293,7 +1295,7 @@
|
|||||||
"delete_confirm": "Sei sicuro di voler eliminare questo?",
|
"delete_confirm": "Sei sicuro di voler eliminare questo?",
|
||||||
"duplicate": "Duplica",
|
"duplicate": "Duplica",
|
||||||
"header": "Azioni",
|
"header": "Azioni",
|
||||||
"introduction": "Le Azioni sono ciò che Home Assistant eseguirà quando un'attivazione (o trigger) avvia un'automazione.",
|
"introduction": "Le Azioni sono ciò che Home Assistant eseguirà quando un'Attivazione (o Trigger) avvia un'Automazione.",
|
||||||
"learn_more": "Per saperne di più sulle azioni",
|
"learn_more": "Per saperne di più sulle azioni",
|
||||||
"name": "Azione",
|
"name": "Azione",
|
||||||
"type_select": "Tipo di azione",
|
"type_select": "Tipo di azione",
|
||||||
@ -1385,7 +1387,7 @@
|
|||||||
"delete_confirm": "Sei sicuro di voler eliminare questo?",
|
"delete_confirm": "Sei sicuro di voler eliminare questo?",
|
||||||
"duplicate": "Duplica",
|
"duplicate": "Duplica",
|
||||||
"header": "Condizioni",
|
"header": "Condizioni",
|
||||||
"introduction": "Le Condizioni sono facoltative e impediranno l'esecuzione dell'automazione a meno che non siano soddisfatte tutte.",
|
"introduction": "Le Condizioni sono facoltative e impediranno l'esecuzione dell'Automazione a meno che non siano soddisfatte tutte.",
|
||||||
"learn_more": "Per saperne di più sulle condizioni",
|
"learn_more": "Per saperne di più sulle condizioni",
|
||||||
"name": "Condizione",
|
"name": "Condizione",
|
||||||
"type_select": "Tipo di condizione",
|
"type_select": "Tipo di condizione",
|
||||||
@ -1475,7 +1477,7 @@
|
|||||||
},
|
},
|
||||||
"modes": {
|
"modes": {
|
||||||
"description": "La Modalità controlla cosa succede quando l'automazione viene attivata mentre le azioni sono ancora in esecuzione da una attivazione precedente. Controllare la {documentation_link} per maggiori informazioni.",
|
"description": "La Modalità controlla cosa succede quando l'automazione viene attivata mentre le azioni sono ancora in esecuzione da una attivazione precedente. Controllare la {documentation_link} per maggiori informazioni.",
|
||||||
"documentation": "documentazione di automazione",
|
"documentation": "documentazione sull'automazione",
|
||||||
"label": "Modalità",
|
"label": "Modalità",
|
||||||
"parallel": "Parallelo",
|
"parallel": "Parallelo",
|
||||||
"queued": "In coda",
|
"queued": "In coda",
|
||||||
@ -1563,12 +1565,12 @@
|
|||||||
},
|
},
|
||||||
"time_pattern": {
|
"time_pattern": {
|
||||||
"hours": "Ore",
|
"hours": "Ore",
|
||||||
"label": "Pattern temporale",
|
"label": "Ricorrenza temporale",
|
||||||
"minutes": "Minuti",
|
"minutes": "Minuti",
|
||||||
"seconds": "Secondi"
|
"seconds": "Secondi"
|
||||||
},
|
},
|
||||||
"time": {
|
"time": {
|
||||||
"at": "Al tempo",
|
"at": "Al momento",
|
||||||
"label": "Ora",
|
"label": "Ora",
|
||||||
"type_input": "Valore di un aiutante data/ora",
|
"type_input": "Valore di un aiutante data/ora",
|
||||||
"type_value": "Tempo fisso"
|
"type_value": "Tempo fisso"
|
||||||
@ -1592,7 +1594,7 @@
|
|||||||
},
|
},
|
||||||
"picker": {
|
"picker": {
|
||||||
"add_automation": "Aggiungi Automazione",
|
"add_automation": "Aggiungi Automazione",
|
||||||
"delete_automation": "Cancellare l'automazione",
|
"delete_automation": "Elimina automazione",
|
||||||
"delete_confirm": "Sei sicuro di voler eliminare questa automazione?",
|
"delete_confirm": "Sei sicuro di voler eliminare questa automazione?",
|
||||||
"dev_automation": "Debug dell'automazione",
|
"dev_automation": "Debug dell'automazione",
|
||||||
"dev_only_editable": "È possibile eseguire il debug solo delle automazioni definite in automations.yaml.",
|
"dev_only_editable": "È possibile eseguire il debug solo delle automazioni definite in automations.yaml.",
|
||||||
@ -1622,7 +1624,7 @@
|
|||||||
"error_unsupported": "Non siamo riusciti a creare un'automazione per questo (ancora?).",
|
"error_unsupported": "Non siamo riusciti a creare un'automazione per questo (ancora?).",
|
||||||
"for_example": "Per esempio:",
|
"for_example": "Per esempio:",
|
||||||
"header": "Crea una nuova automazione",
|
"header": "Crea una nuova automazione",
|
||||||
"introduction": "Digitare sotto ciò che questa automazione dovrebbe fare, e proveremo a convertirlo in un'automazione Home Assistant.",
|
"introduction": "Scrivi qui sotto cosa dovrebbe fare questa automazione, e noi cercheremo di convertirla in un'automazione di Home Assistant.",
|
||||||
"language_note": "Nota: per il momento è supportato solo l'inglese."
|
"language_note": "Nota: per il momento è supportato solo l'inglese."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1946,7 +1948,7 @@
|
|||||||
"unknown_condition": "Condizione sconosciuta"
|
"unknown_condition": "Condizione sconosciuta"
|
||||||
},
|
},
|
||||||
"create": "Crea l'automazione con il dispositivo",
|
"create": "Crea l'automazione con il dispositivo",
|
||||||
"create_disable": "Non è possibile creare automazione con un dispositivo disabilitato",
|
"create_disable": "Non è possibile creare una automazione con un dispositivo disabilitato",
|
||||||
"no_automations": "Nessuna automazione",
|
"no_automations": "Nessuna automazione",
|
||||||
"no_device_automations": "Non ci sono Automazioni disponibili per questo dispositivo.",
|
"no_device_automations": "Non ci sono Automazioni disponibili per questo dispositivo.",
|
||||||
"triggers": {
|
"triggers": {
|
||||||
@ -2837,7 +2839,7 @@
|
|||||||
"edit_home_zone_narrow": "Il raggio della zona Casa non può ancora essere modificato dal frontend. La posizione può essere modificata dalla configurazione generale.",
|
"edit_home_zone_narrow": "Il raggio della zona Casa non può ancora essere modificato dal frontend. La posizione può essere modificata dalla configurazione generale.",
|
||||||
"go_to_core_config": "Passare alla configurazione generale?",
|
"go_to_core_config": "Passare alla configurazione generale?",
|
||||||
"home_zone_core_config": "La posizione della zona Casa è modificabile dalla pagina di configurazione generale. Il raggio della zona iniziale non può ancora essere modificato dal frontend. Vuoi andare alla configurazione generale?",
|
"home_zone_core_config": "La posizione della zona Casa è modificabile dalla pagina di configurazione generale. Il raggio della zona iniziale non può ancora essere modificato dal frontend. Vuoi andare alla configurazione generale?",
|
||||||
"introduction": "Le Zone consentono di specificare determinate regioni sulla Terra. Quando una persona si trova all'interno di una Zona, nel suo Stato ci sarà il nome dalla Zona. Le Zone possono anche essere utilizzate come Attivazioni (o Trigger) o Condizioni all'interno delle impostazioni di Automazione.",
|
"introduction": "Le Zone consentono di specificare determinate regioni sulla Terra. Quando una persona si trova all'interno di una Zona, nel suo stato apparirà il nome dalla Zona. Le Zone possono anche essere utilizzate come Attivazioni (o Trigger) o Condizioni all'interno delle impostazioni di una Automazione.",
|
||||||
"no_zones_created_yet": "Sembra che tu non abbia ancora creato nessuna zona."
|
"no_zones_created_yet": "Sembra che tu non abbia ancora creato nessuna zona."
|
||||||
},
|
},
|
||||||
"zwave_js": {
|
"zwave_js": {
|
||||||
|
@ -843,8 +843,10 @@
|
|||||||
"related-filter-menu": {
|
"related-filter-menu": {
|
||||||
"filter_by_area": "영역별 필터",
|
"filter_by_area": "영역별 필터",
|
||||||
"filter_by_device": "기기별 필터",
|
"filter_by_device": "기기별 필터",
|
||||||
|
"filter_by_entity": "구성요소별 필터",
|
||||||
"filtered_by_area": "영역: {area_name}",
|
"filtered_by_area": "영역: {area_name}",
|
||||||
"filtered_by_device": "기기: {device_name}"
|
"filtered_by_device": "기기: {device_name}",
|
||||||
|
"filtered_by_entity": "구성요소: {entity_name}"
|
||||||
},
|
},
|
||||||
"related-items": {
|
"related-items": {
|
||||||
"area": "영역",
|
"area": "영역",
|
||||||
|
@ -843,8 +843,10 @@
|
|||||||
"related-filter-menu": {
|
"related-filter-menu": {
|
||||||
"filter_by_area": "Filter op gebied",
|
"filter_by_area": "Filter op gebied",
|
||||||
"filter_by_device": "Filter op apparaat",
|
"filter_by_device": "Filter op apparaat",
|
||||||
|
"filter_by_entity": "Filter op entiteit",
|
||||||
"filtered_by_area": "gebied: {area_name}",
|
"filtered_by_area": "gebied: {area_name}",
|
||||||
"filtered_by_device": "apparaat: {device_name}"
|
"filtered_by_device": "apparaat: {device_name}",
|
||||||
|
"filtered_by_entity": "entiteit: {entity_name}"
|
||||||
},
|
},
|
||||||
"related-items": {
|
"related-items": {
|
||||||
"area": "Gebied",
|
"area": "Gebied",
|
||||||
@ -1105,37 +1107,37 @@
|
|||||||
"zone": "Zones"
|
"zone": "Zones"
|
||||||
},
|
},
|
||||||
"reload": {
|
"reload": {
|
||||||
"automation": "Herlaad automatiseringen",
|
"automation": "Automatiseringen",
|
||||||
"command_line": "Herlaad commandline entiteiten",
|
"command_line": "Opdrachtregel-entiteiten",
|
||||||
"core": "Herlaad locatie & aanpassingen",
|
"core": "Locatie en aanpassingen",
|
||||||
"filesize": "Herlaad bestandsgroote entiteiten",
|
"filesize": "Bestandsgrootte entiteiten",
|
||||||
"filter": "Herlaad filter entiteiten",
|
"filter": "Filter-entiteiten",
|
||||||
"generic": "Herlaad",
|
"generic": "Generieke IP camera entiteiten",
|
||||||
"generic_thermostat": "Herlaad",
|
"generic_thermostat": "Generieke thermostaat entiteiten",
|
||||||
"group": "Herlaad groepen, groepsentiteiten en notificatieservices",
|
"group": "Groepen, groepsentiteiten en notify services",
|
||||||
"history_stats": "Herlaad historische statistieken entiteiten",
|
"history_stats": "Historische statistieken entiteiten",
|
||||||
"homekit": "Herlaad HomeKit",
|
"homekit": "HomeKit",
|
||||||
"input_boolean": "Herlaad input booleans",
|
"input_boolean": "Input booleans",
|
||||||
"input_datetime": "Herlaad input datatijd",
|
"input_datetime": "Input date times",
|
||||||
"input_number": "Herlaad input nummers",
|
"input_number": "Input numbers",
|
||||||
"input_select": "Herlaad input selecties",
|
"input_select": "Input selects",
|
||||||
"input_text": "Herlaad input teksten",
|
"input_text": "Input texts",
|
||||||
"min_max": "Laad min/max entiteiten opnieuw",
|
"min_max": "Laad min/max entiteiten opnieuw",
|
||||||
"mqtt": "Herlaad mqtt entiteiten",
|
"mqtt": "Handmatig geconfigureerde MQTT-entiteiten",
|
||||||
"person": "Herlaad personen",
|
"person": "Personen",
|
||||||
"ping": "Herlaad binaire ping-sensorentiteiten",
|
"ping": "Ping binaire sensor entiteiten",
|
||||||
"reload": "Herlaad {domain}",
|
"reload": "{domain}",
|
||||||
"rest": "Herlaad rest entiteiten en notificatieservices",
|
"rest": "Rest-entiteiten en notify-services",
|
||||||
"rpi_gpio": "Herlaad Raspberry PI GPIO entiteiten",
|
"rpi_gpio": "Raspberry Pi GPIO-entiteiten",
|
||||||
"scene": "Scenes",
|
"scene": "Scenes",
|
||||||
"script": "Herlaad scripts",
|
"script": "Scripts",
|
||||||
"smtp": "Herlaad smtp notificatie services",
|
"smtp": "SMTP notify services",
|
||||||
"statistics": "Herlaad statistieken entiteiten",
|
"statistics": "Statistische entiteiten",
|
||||||
"telegram": "Herlaad telegram notificatie services",
|
"telegram": "Telegram notify services",
|
||||||
"template": "Herlaad template entiteiten",
|
"template": "Template entiteiten",
|
||||||
"trend": "Herlaad trend entiteiten",
|
"trend": "Trend-entiteiten",
|
||||||
"universal": "Herlaad universele mediaplayer entiteiten",
|
"universal": "Universele mediaspeler entiteiten",
|
||||||
"zone": "Herlaad zones"
|
"zone": "Zones"
|
||||||
},
|
},
|
||||||
"server_control": {
|
"server_control": {
|
||||||
"perform_action": "{action} Server",
|
"perform_action": "{action} Server",
|
||||||
@ -2613,17 +2615,17 @@
|
|||||||
"input_text": "Input texts",
|
"input_text": "Input texts",
|
||||||
"introduction": "Sommige delen van Home Assistant kunnen opnieuw worden geladen zonder dat een herstart vereist is. Als je herladen gebruikt, wordt de huidige configuratie leeggemaakt en wordt de nieuwe geladen.",
|
"introduction": "Sommige delen van Home Assistant kunnen opnieuw worden geladen zonder dat een herstart vereist is. Als je herladen gebruikt, wordt de huidige configuratie leeggemaakt en wordt de nieuwe geladen.",
|
||||||
"min_max": "Min/max entiteiten",
|
"min_max": "Min/max entiteiten",
|
||||||
"mqtt": "Herlaad handmatig geconfigureerde MQTT-entiteiten",
|
"mqtt": "Handmatig geconfigureerde MQTT-entiteiten",
|
||||||
"person": "Personen",
|
"person": "Personen",
|
||||||
"ping": "Ping binaire sensor entiteiten",
|
"ping": "Ping binaire sensor entiteiten",
|
||||||
"reload": "Herlaad {domain}",
|
"reload": "{domain}",
|
||||||
"rest": "Rest-entiteiten en notify-services",
|
"rest": "Rest-entiteiten en notify-services",
|
||||||
"rpi_gpio": "Herlaad Raspberry Pi GPIO-entiteiten",
|
"rpi_gpio": "Raspberry Pi GPIO-entiteiten",
|
||||||
"scene": "Scenes",
|
"scene": "Scenes",
|
||||||
"script": "Scripts",
|
"script": "Scripts",
|
||||||
"smtp": "Herlaad de SMTP notify services",
|
"smtp": "SMTP notify services",
|
||||||
"statistics": "Statistische entiteiten",
|
"statistics": "Statistische entiteiten",
|
||||||
"telegram": "Herlaad telegram notify services",
|
"telegram": "Telegram notify services",
|
||||||
"template": "Template entiteiten",
|
"template": "Template entiteiten",
|
||||||
"trend": "Trend-entiteiten",
|
"trend": "Trend-entiteiten",
|
||||||
"universal": "Universele mediaspeler entiteiten",
|
"universal": "Universele mediaspeler entiteiten",
|
||||||
|
@ -457,7 +457,7 @@
|
|||||||
"leave_beta_action": "Opuść kanał beta",
|
"leave_beta_action": "Opuść kanał beta",
|
||||||
"leave_beta_description": "Pobieraj stabilne aktualizacje dla Home Assistanta, Supervisora i hosta",
|
"leave_beta_description": "Pobieraj stabilne aktualizacje dla Home Assistanta, Supervisora i hosta",
|
||||||
"ram_usage": "Zużycie pamięci przez Supervisora",
|
"ram_usage": "Zużycie pamięci przez Supervisora",
|
||||||
"reload_supervisor": "Wczytaj ponownie Supervisora",
|
"reload_supervisor": "Wczytaj ponownie Supervisor",
|
||||||
"share_diagnostics": "Udostępnij dane diagnostyczne",
|
"share_diagnostics": "Udostępnij dane diagnostyczne",
|
||||||
"share_diagnostics_description": "Udostępniaj raporty o awariach i informacje diagnostyczne.",
|
"share_diagnostics_description": "Udostępniaj raporty o awariach i informacje diagnostyczne.",
|
||||||
"share_diagonstics_description": "Czy chcesz automatycznie udostępniać raporty o awariach i informacje diagnostyczne, gdy Supervisor napotka nieoczekiwane błędy? {line_break} Pozwoli nam to rozwiązać problemy, informacje są dostępne tylko dla głównego zespołu Home Assistant Core i nie będą udostępniane innym. {line_break} Dane nie zawierają żadnych prywatnych/wrażliwych informacji i możesz to wyłączyć w ustawieniach w dowolnym momencie.",
|
"share_diagonstics_description": "Czy chcesz automatycznie udostępniać raporty o awariach i informacje diagnostyczne, gdy Supervisor napotka nieoczekiwane błędy? {line_break} Pozwoli nam to rozwiązać problemy, informacje są dostępne tylko dla głównego zespołu Home Assistant Core i nie będą udostępniane innym. {line_break} Dane nie zawierają żadnych prywatnych/wrażliwych informacji i możesz to wyłączyć w ustawieniach w dowolnym momencie.",
|
||||||
@ -2071,6 +2071,9 @@
|
|||||||
"filtering_by": "Filtrowanie przez",
|
"filtering_by": "Filtrowanie przez",
|
||||||
"show": "Pokaż"
|
"show": "Pokaż"
|
||||||
},
|
},
|
||||||
|
"hassio": {
|
||||||
|
"button": "Konfiguruj"
|
||||||
|
},
|
||||||
"header": "Konfiguruj Home Assistanta",
|
"header": "Konfiguruj Home Assistanta",
|
||||||
"helpers": {
|
"helpers": {
|
||||||
"caption": "Pomocnicy",
|
"caption": "Pomocnicy",
|
||||||
|
@ -279,7 +279,7 @@
|
|||||||
"failed_to_update_name": "Не удалось обновить {name}",
|
"failed_to_update_name": "Не удалось обновить {name}",
|
||||||
"learn_more": "Узнать больше",
|
"learn_more": "Узнать больше",
|
||||||
"new_version_available": "Доступна новая версия",
|
"new_version_available": "Доступна новая версия",
|
||||||
"newest_version": "Последняя версия",
|
"newest_version": "Доступная версия",
|
||||||
"no": "Нет",
|
"no": "Нет",
|
||||||
"refresh": "Обновить",
|
"refresh": "Обновить",
|
||||||
"release_notes": "Список изменений",
|
"release_notes": "Список изменений",
|
||||||
@ -843,8 +843,10 @@
|
|||||||
"related-filter-menu": {
|
"related-filter-menu": {
|
||||||
"filter_by_area": "Фильтр по помещениям",
|
"filter_by_area": "Фильтр по помещениям",
|
||||||
"filter_by_device": "Фильтр по устройствам",
|
"filter_by_device": "Фильтр по устройствам",
|
||||||
|
"filter_by_entity": "Фильтр по объектам",
|
||||||
"filtered_by_area": "помещению: {area_name}",
|
"filtered_by_area": "помещению: {area_name}",
|
||||||
"filtered_by_device": "устройству: {device_name}"
|
"filtered_by_device": "устройству: {device_name}",
|
||||||
|
"filtered_by_entity": "объекту: {entity_name}"
|
||||||
},
|
},
|
||||||
"related-items": {
|
"related-items": {
|
||||||
"area": "Помещение",
|
"area": "Помещение",
|
||||||
|
@ -840,6 +840,14 @@
|
|||||||
"label": "图片",
|
"label": "图片",
|
||||||
"unsupported_format": "格式不受支持,请选择 JPEG、PNG 或 GIF 图像。"
|
"unsupported_format": "格式不受支持,请选择 JPEG、PNG 或 GIF 图像。"
|
||||||
},
|
},
|
||||||
|
"related-filter-menu": {
|
||||||
|
"filter_by_area": "按区域",
|
||||||
|
"filter_by_device": "按设备",
|
||||||
|
"filter_by_entity": "按实体",
|
||||||
|
"filtered_by_area": "区域: {area_name}",
|
||||||
|
"filtered_by_device": "设备: {device_name}",
|
||||||
|
"filtered_by_entity": "实体: {entity_name}"
|
||||||
|
},
|
||||||
"related-items": {
|
"related-items": {
|
||||||
"area": "区域",
|
"area": "区域",
|
||||||
"automation": "以下自动化的一部分",
|
"automation": "以下自动化的一部分",
|
||||||
@ -1182,6 +1190,9 @@
|
|||||||
"zha_device_card": {
|
"zha_device_card": {
|
||||||
"device_name_placeholder": "更改设备名称"
|
"device_name_placeholder": "更改设备名称"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"zha_reconfigure_device": {
|
||||||
|
"heading": "重新配置设备"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"duration": {
|
"duration": {
|
||||||
@ -1685,6 +1696,7 @@
|
|||||||
"info": "通过 Home Assistant Cloud 的 Google Assistant 集成,您将可以通过任何启用了 Google Assistant 的设备来控制所有 Home Assistant 设备。",
|
"info": "通过 Home Assistant Cloud 的 Google Assistant 集成,您将可以通过任何启用了 Google Assistant 的设备来控制所有 Home Assistant 设备。",
|
||||||
"info_state_reporting": "如果启用状态报告,则 Home Assistant 会将公开实体的所有状态变化发送给 Google。这样您就可以始终在 Google 应用中看到最新状态。",
|
"info_state_reporting": "如果启用状态报告,则 Home Assistant 会将公开实体的所有状态变化发送给 Google。这样您就可以始终在 Google 应用中看到最新状态。",
|
||||||
"manage_entities": "管理实体",
|
"manage_entities": "管理实体",
|
||||||
|
"not_configured_text": "在使用 Google Assistant 之前,需要在 Google Home 应用中激活 Google Assistant 的 Home Assistant Cloud 技能。",
|
||||||
"not_configured_title": "Google Assistant 未激活",
|
"not_configured_title": "Google Assistant 未激活",
|
||||||
"security_devices": "安全设备",
|
"security_devices": "安全设备",
|
||||||
"sync_entities": "同步实体到 Google",
|
"sync_entities": "同步实体到 Google",
|
||||||
@ -1849,9 +1861,11 @@
|
|||||||
"section": {
|
"section": {
|
||||||
"core": {
|
"core": {
|
||||||
"analytics": {
|
"analytics": {
|
||||||
|
"documentation": "在启用此功能之前,请确保您已阅读了分析文档页面 {link},以了解将发送的内容及其存储方式。",
|
||||||
"header": "分析",
|
"header": "分析",
|
||||||
"instance_id": "实例ID: {huuid}",
|
"instance_id": "实例ID: {huuid}",
|
||||||
"introduction": "共享实例的分析。此数据将在 {link} 公开。",
|
"introduction": "共享实例的分析。此数据将在 {link} 公开。",
|
||||||
|
"learn_more": "详细了解您的数据将被如何处理。",
|
||||||
"needs_base": "需要启用基础分析才能启用此选项",
|
"needs_base": "需要启用基础分析才能启用此选项",
|
||||||
"preference": {
|
"preference": {
|
||||||
"base": {
|
"base": {
|
||||||
@ -1863,6 +1877,7 @@
|
|||||||
"title": "诊断"
|
"title": "诊断"
|
||||||
},
|
},
|
||||||
"statistics": {
|
"statistics": {
|
||||||
|
"description": "包括安装的元素数量,完整列表请参阅文档",
|
||||||
"title": "使用情况统计"
|
"title": "使用情况统计"
|
||||||
},
|
},
|
||||||
"usage_supervisor": {
|
"usage_supervisor": {
|
||||||
@ -2062,6 +2077,9 @@
|
|||||||
"filtering_by": "正在筛选:",
|
"filtering_by": "正在筛选:",
|
||||||
"show": "显示"
|
"show": "显示"
|
||||||
},
|
},
|
||||||
|
"hassio": {
|
||||||
|
"button": "配置"
|
||||||
|
},
|
||||||
"header": "配置 Home Assistant",
|
"header": "配置 Home Assistant",
|
||||||
"helpers": {
|
"helpers": {
|
||||||
"caption": "辅助元素",
|
"caption": "辅助元素",
|
||||||
@ -2148,8 +2166,10 @@
|
|||||||
"entity_unavailable": "实体不可用",
|
"entity_unavailable": "实体不可用",
|
||||||
"firmware": "固件:{version}",
|
"firmware": "固件:{version}",
|
||||||
"hub": "连接于",
|
"hub": "连接于",
|
||||||
|
"logs": "日志",
|
||||||
"manuf": "by {manufacturer}",
|
"manuf": "by {manufacturer}",
|
||||||
"no_area": "没有区域",
|
"no_area": "没有区域",
|
||||||
|
"not_loaded": "未加载,请检查{logs_link}",
|
||||||
"options": "选项",
|
"options": "选项",
|
||||||
"reload": "重载",
|
"reload": "重载",
|
||||||
"reload_confirm": "集成已重新加载",
|
"reload_confirm": "集成已重新加载",
|
||||||
@ -2175,6 +2195,7 @@
|
|||||||
"finish": "完成",
|
"finish": "完成",
|
||||||
"loading_first_time": "正在安装集成,请稍候",
|
"loading_first_time": "正在安装集成,请稍候",
|
||||||
"not_all_required_fields": "请填写所有必填字段",
|
"not_all_required_fields": "请填写所有必填字段",
|
||||||
|
"not_loaded": "集成未能加载,请尝试重启 Home Assistant。",
|
||||||
"pick_flow_step": {
|
"pick_flow_step": {
|
||||||
"new_flow": "否,设置另一个 {integration} 实例",
|
"new_flow": "否,设置另一个 {integration} 实例",
|
||||||
"title": "已发现以下集成,要设置它们吗?"
|
"title": "已发现以下集成,要设置它们吗?"
|
||||||
@ -2225,10 +2246,17 @@
|
|||||||
"clear": "清除",
|
"clear": "清除",
|
||||||
"description": "查看 Home Assistant 日志",
|
"description": "查看 Home Assistant 日志",
|
||||||
"details": "日志详细信息( {level} )",
|
"details": "日志详细信息( {level} )",
|
||||||
|
"level": {
|
||||||
|
"critical": "CRITICAL",
|
||||||
|
"debug": "DEBUG",
|
||||||
|
"error": "ERROR",
|
||||||
|
"info": "INFO",
|
||||||
|
"warning": "WARNING"
|
||||||
|
},
|
||||||
"load_full_log": "加载完整 Home Assistant 日志",
|
"load_full_log": "加载完整 Home Assistant 日志",
|
||||||
"loading_log": "正在加载错误日志...",
|
"loading_log": "正在加载错误日志...",
|
||||||
"multiple_messages": "消息首次出现在 {time},显示了 {counter} 次",
|
"multiple_messages": "消息首次出现在 {time},显示了 {counter} 次",
|
||||||
"no_errors": "未报告任何错误。",
|
"no_errors": "未报告任何错误",
|
||||||
"no_issues": "没有新问题!",
|
"no_issues": "没有新问题!",
|
||||||
"refresh": "刷新"
|
"refresh": "刷新"
|
||||||
},
|
},
|
||||||
@ -3721,6 +3749,10 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"page-onboarding": {
|
"page-onboarding": {
|
||||||
|
"analytics": {
|
||||||
|
"finish": "下一步",
|
||||||
|
"intro": "共享实例的分析。此数据将在 {link} 公开。"
|
||||||
|
},
|
||||||
"core-config": {
|
"core-config": {
|
||||||
"button_detect": "自动检测",
|
"button_detect": "自动检测",
|
||||||
"finish": "下一步",
|
"finish": "下一步",
|
||||||
@ -3730,12 +3762,14 @@
|
|||||||
"location_name": "Home Assistant 安装的名称",
|
"location_name": "Home Assistant 安装的名称",
|
||||||
"location_name_default": "我的家"
|
"location_name_default": "我的家"
|
||||||
},
|
},
|
||||||
|
"finish": "完成",
|
||||||
"integration": {
|
"integration": {
|
||||||
"finish": "完成",
|
"finish": "完成",
|
||||||
"intro": "设备和服务在 Home Assistant 中表示为集成。您可以立即设置它们,也可以稍后在配置屏幕进行设置。",
|
"intro": "设备和服务在 Home Assistant 中表示为集成。您可以立即设置它们,也可以稍后在配置屏幕进行设置。",
|
||||||
"more_integrations": "更多"
|
"more_integrations": "更多"
|
||||||
},
|
},
|
||||||
"intro": "准备好唤醒你的家、找回你的隐私,并加入世界级的极客社区了吗?",
|
"intro": "准备好唤醒你的家、找回你的隐私,并加入世界级的极客社区了吗?",
|
||||||
|
"next": "下一步",
|
||||||
"restore": {
|
"restore": {
|
||||||
"description": "或者,您也可以从以前的快照还原。",
|
"description": "或者,您也可以从以前的快照还原。",
|
||||||
"hide_log": "隐藏完整日志",
|
"hide_log": "隐藏完整日志",
|
||||||
|
@ -843,8 +843,10 @@
|
|||||||
"related-filter-menu": {
|
"related-filter-menu": {
|
||||||
"filter_by_area": "依區域篩選",
|
"filter_by_area": "依區域篩選",
|
||||||
"filter_by_device": "依裝置篩選",
|
"filter_by_device": "依裝置篩選",
|
||||||
|
"filter_by_entity": "依實體篩選",
|
||||||
"filtered_by_area": "區域:{area_name}",
|
"filtered_by_area": "區域:{area_name}",
|
||||||
"filtered_by_device": "裝置:{device_name}"
|
"filtered_by_device": "裝置:{device_name}",
|
||||||
|
"filtered_by_entity": "實體:{entity_name}"
|
||||||
},
|
},
|
||||||
"related-items": {
|
"related-items": {
|
||||||
"area": "分區",
|
"area": "分區",
|
||||||
|
Loading…
x
Reference in New Issue
Block a user