Compare commits

..

1 Commits

Author SHA1 Message Date
Crowdin Bot
0da75124c6 New Crowdin translations by GitHub Action 2025-12-04 00:37:10 +00:00
7 changed files with 67 additions and 86 deletions

View File

@@ -159,19 +159,6 @@ Widgets can tint their metric block text automatically based on rules defined al
Supported numeric operators for the `when` property are `gt`, `gte`, `lt`, `lte`, `eq`, `ne`, `between`, and `outside`. String rules support `equals`, `includes`, `startsWith`, `endsWith`, and `regex`. Each rule can be inverted with `negate: true`, and string rules may pass `caseSensitive: true` or custom regex `flags`. The highlight engine does its best to coerce formatted values, but you will get the most reliable results when you pass plain numbers or strings into `<Block>`.
#### Value Only Highlighting
You can optionally apply highlighting only to the value portion of a block (not the label) by setting `valueOnly: true` on the field configuration. This keeps the label visible while highlighting only the metric value itself.
```yaml
- Sonarr:
...
highlight:
queued:
valueOnly: true
...
```
## Descriptions
Services may have descriptions,

View File

@@ -193,7 +193,7 @@
"tv": "Сериалы"
},
"sabnzbd": {
"rate": "",
"rate": "Rate",
"queue": "Очередь",
"timeleft": "Осталось"
},

View File

@@ -63,14 +63,14 @@
"wlan_users": "WLAN користувачі",
"up": "UP",
"down": "Завантаження",
"wait": "Будь ласка, зачекайте",
"wait": "Please wait",
"empty_data": "Статус підсистеми невідомий"
},
"docker": {
"rx": "RX",
"tx": "TX",
"mem": "Пам'ять",
"cpu": "Процесор",
"mem": "MEM",
"cpu": "CPU",
"running": "Запущено",
"offline": "Офлайн",
"error": "Помилка",
@@ -83,7 +83,7 @@
"partial": "Частковий"
},
"ping": {
"error": "Помилка",
"error": "Error",
"ping": "Пінг",
"down": "Офлайн",
"up": "Онлайн",
@@ -91,11 +91,11 @@
},
"siteMonitor": {
"http_status": "HTTP статус",
"error": "Помилка",
"error": "Error",
"response": "Відповідь",
"down": "Офлайн",
"up": "Онлайн",
"not_available": "Не доступний"
"down": "Down",
"up": "Up",
"not_available": "Not Available"
},
"emby": {
"playing": "Відтворення",
@@ -108,10 +108,10 @@
"songs": "Пісні"
},
"esphome": {
"offline": "Офлайн",
"offline_alt": "Офлайн",
"offline": "Offline",
"offline_alt": "Offline",
"online": "Онлайн",
"total": "Усього",
"total": "Total",
"unknown": "Невідомо"
},
"evcc": {
@@ -133,7 +133,7 @@
"unread": "Не прочитано"
},
"fritzbox": {
"connectionStatus": "Стан",
"connectionStatus": "Status",
"connectionStatusUnconfigured": "Не налаштовано",
"connectionStatusConnecting": "Підключення",
"connectionStatusAuthenticating": "Автентифікація",
@@ -141,11 +141,11 @@
"connectionStatusDisconnecting": "Відключення",
"connectionStatusDisconnected": "Відключено",
"connectionStatusConnected": "З'єднано",
"uptime": "Час роботи",
"uptime": "Uptime",
"maxDown": "Макс. завантаження",
"maxUp": "Макс. віддача",
"down": "Офлайн",
"up": "Онлайн",
"down": "Down",
"up": "Up",
"received": "Отримано",
"sent": "Надіслано",
"externalIPAddress": "Зовнішній IP",
@@ -168,10 +168,10 @@
"passes": "Пропуски"
},
"tautulli": {
"playing": "Грає",
"transcoding": "Транскодування",
"bitrate": "Бітрейт",
"no_active": "Немає активних потоків",
"playing": "Playing",
"transcoding": "Transcoding",
"bitrate": "Bitrate",
"no_active": "No Active Streams",
"plex_connection_error": "Перевірте з'єднання Plex"
},
"omada": {
@@ -189,30 +189,30 @@
"plex": {
"streams": "Активні потоки",
"albums": "Альбоми",
"movies": "Фільми",
"movies": "Movies",
"tv": "TБ шоу"
},
"sabnzbd": {
"rate": "Швидкість",
"rate": "Rate",
"queue": "Черга",
"timeleft": "Залишилось"
},
"rutorrent": {
"active": "Активний",
"upload": "Вивантаж.",
"download": "Завантажено"
"upload": "Upload",
"download": "Download"
},
"transmission": {
"download": "Завантажено",
"upload": "Вивантаж.",
"leech": "Ліч",
"seed": "Сід"
"download": "Download",
"upload": "Upload",
"leech": "Leech",
"seed": "Seed"
},
"qbittorrent": {
"download": "Завантажити",
"upload": "Вивантаж.",
"leech": "Ліч",
"seed": "Сід"
"download": "Download",
"upload": "Upload",
"leech": "Leech",
"seed": "Seed"
},
"qnap": {
"cpuUsage": "Використання CPU",
@@ -225,8 +225,8 @@
"deluge": {
"download": "Download",
"upload": "Upload",
"leech": "Ліч",
"seed": "Сід"
"leech": "Leech",
"seed": "Seed"
},
"develancacheui": {
"cachehitbytes": "Кеш-хіт байт",
@@ -234,33 +234,33 @@
},
"downloadstation": {
"download": "Download",
"upload": "Вивантаж.",
"leech": "Ліч",
"seed": "Сід"
"upload": "Upload",
"leech": "Leech",
"seed": "Seed"
},
"sonarr": {
"wanted": "Розшукується",
"queued": "У черзі",
"series": "Серіали",
"queue": "Черга",
"unknown": "Невідомо"
"series": "Series",
"queue": "Queue",
"unknown": "Unknown"
},
"radarr": {
"wanted": "У бажаних",
"wanted": "Wanted",
"missing": "Відсутній",
"queued": "У черзі",
"movies": "Фільми",
"queue": "Черга",
"unknown": "Невідомо"
"queued": "Queued",
"movies": "Movies",
"queue": "Queue",
"unknown": "Unknown"
},
"lidarr": {
"wanted": "У бажаних",
"queued": "У черзі",
"wanted": "Wanted",
"queued": "Queued",
"artists": "Виконавці"
},
"readarr": {
"wanted": "У бажаних",
"queued": "У черзі",
"wanted": "Wanted",
"queued": "Queued",
"books": "Книжки"
},
"bazarr": {
@@ -273,20 +273,20 @@
"available": "Доступно"
},
"jellyseerr": {
"pending": "Очікує",
"approved": "Схвалено",
"available": "Доступно",
"issues": "Проблеми до усунення"
"pending": "Pending",
"approved": "Approved",
"available": "Available",
"issues": "Open Issues"
},
"overseerr": {
"pending": "Очікує",
"pending": "Pending",
"processing": "Обробка",
"approved": "Схвалено",
"available": "Доступно"
"approved": "Approved",
"available": "Available"
},
"netalertx": {
"total": "Усього",
"connected": "З'єднано",
"total": "Total",
"connected": "Connected",
"new_devices": "Нові пристрої",
"down_alerts": "Сповіщення про падіння"
},
@@ -297,13 +297,13 @@
"gravity": "Доменів в списку"
},
"adguard": {
"queries": "Запити",
"blocked": "Заблоковано",
"queries": "Queries",
"blocked": "Blocked",
"filtered": "Відфільтровано",
"latency": "Затримка"
},
"speedtest": {
"upload": "Вивантаж.",
"upload": "Upload",
"download": "Download",
"ping": "Ping"
},

View File

@@ -32,8 +32,6 @@ export default function Block({ value, label, field }) {
return getHighlightClass(highlight.level, highlightConfig);
}, [highlight, highlightConfig]);
const applyToValueOnly = highlight?.valueOnly === true;
return (
<div
className={classNames(
@@ -46,11 +44,7 @@ export default function Block({ value, label, field }) {
data-highlight-source={highlight?.source}
>
<div className="font-thin text-sm">{value === undefined || value === null ? "-" : value}</div>
<div
className={classNames("font-bold text-xs uppercase", applyToValueOnly && "text-theme-700 dark:text-theme-200")}
>
{t(label)}
</div>
<div className="font-bold text-xs uppercase">{t(label)}</div>
</div>
);
}

View File

@@ -111,7 +111,7 @@ export async function servicesFromDocker() {
};
}
let substitutedVal = substituteEnvironmentVars(containerLabels[label]);
if (value === "widget.version" || /^widgets\[\d+\]\.version$/.test(value)) {
if (value === "widget.version") {
substitutedVal = parseInt(substitutedVal, 10);
}
shvl.set(constructedService, value, substitutedVal);

View File

@@ -200,7 +200,7 @@ const ensureArray = (value) => {
};
const findHighlightLevel = (ruleSet, numericValue, stringValue) => {
const { numeric, string, valueOnly } = ruleSet;
const { numeric, string } = ruleSet;
if (numeric && numericValue !== undefined) {
const numericRules = ensureArray(numeric);
@@ -208,7 +208,7 @@ const findHighlightLevel = (ruleSet, numericValue, stringValue) => {
for (const candidate of numericCandidates) {
for (const rule of numericRules) {
if (rule?.level && evaluateNumericRule(candidate, rule)) {
return { level: rule.level, source: "numeric", rule, valueOnly };
return { level: rule.level, source: "numeric", rule };
}
}
}
@@ -218,7 +218,7 @@ const findHighlightLevel = (ruleSet, numericValue, stringValue) => {
const stringRules = ensureArray(string);
for (const rule of stringRules) {
if (rule?.level && evaluateStringRule(stringValue, rule)) {
return { level: rule.level, source: "string", rule, valueOnly };
return { level: rule.level, source: "string", rule };
}
}
}

View File

@@ -111,7 +111,7 @@ export async function cachedRequest(url, duration = 5, ua = "homepage") {
export async function httpProxy(url, params = {}) {
const constructedUrl = new URL(url);
const disableIpv6 = process.env.HOMEPAGE_PROXY_DISABLE_IPV6 === "true";
const agentOptions = disableIpv6 ? { family: 4, autoSelectFamily: false } : { autoSelectFamilyAttemptTimeout: 500 };
const agentOptions = disableIpv6 ? { family: 4, autoSelectFamily: false } : {};
let request = null;
if (constructedUrl.protocol === "https:") {