Merge branch 'dev'

This commit is contained in:
shamoon
2026-03-27 15:17:33 -07:00
99 changed files with 2699 additions and 1820 deletions

View File

@@ -8,8 +8,12 @@ updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "daily"
interval: "weekly"
cooldown:
default-days: 7
- package-ecosystem: "npm"
directory: "/"
schedule:
interval: "monthly"
cooldown:
default-days: 7

87
.github/release-drafter.yml vendored Normal file
View File

@@ -0,0 +1,87 @@
name-template: 'v$RESOLVED_VERSION'
tag-template: 'v$RESOLVED_VERSION'
change-template: '- $TITLE (#$NUMBER) @$AUTHOR'
change-title-escapes: '\\<*_&'
version-resolver:
major:
labels:
- 'major'
- 'breaking-change'
minor:
labels:
- 'enhancement'
- 'feature'
patch:
labels:
- 'bug'
- 'fix'
- 'dependencies'
- 'translation'
- 'documentation'
default: patch
categories:
- title: '⚠️ Breaking Changes'
labels:
- 'major'
- 'breaking-change'
- title: '🚀 Features'
labels:
- 'enhancement'
- 'feature'
- title: '🐛 Fixes'
labels:
- 'bug'
- 'fix'
- title: '🧰 Maintenance'
labels:
- 'dependencies'
- 'ci'
- 'chore'
- title: '🌐 Translations'
labels:
- 'translation'
- title: '📚 Documentation'
labels:
- 'documentation'
autolabeler:
- label: 'documentation'
files:
- 'docs/**'
- '*.md'
- '.github/**/*.md'
- label: 'ci'
files:
- '.github/workflows/**'
- label: 'dependencies'
files:
- 'package.json'
- 'pnpm-lock.yaml'
- 'pyproject.toml'
- 'uv.lock'
- label: 'feature'
files:
- 'src/components/**'
- 'src/widgets/**'
- 'src/pages/**'
- 'src/utils/**'
- label: 'chore'
files:
- 'Dockerfile*'
- 'docker-entrypoint.sh'
- 'k3d/**'
- label: 'translation'
files:
- 'public/locales/**'
template: |
## What's Changed
$CHANGES

View File

@@ -25,6 +25,7 @@ jobs:
download_translations: true
crowdin_branch_name: dev
localization_branch_name: l10n_dev
pull_request_labels: translation
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
CROWDIN_PROJECT_ID: ${{ secrets.CROWDIN_PROJECT_ID }}

View File

@@ -33,7 +33,7 @@ jobs:
uses: pre-commit/action@v3.0.1
- name: Install pnpm
uses: pnpm/action-setup@v4
uses: pnpm/action-setup@v5
with:
version: 10
run_install: false
@@ -41,7 +41,7 @@ jobs:
- name: Setup Node.js
uses: actions/setup-node@v6
with:
node-version: 20
node-version: 24
cache: 'pnpm'
- name: Install dependencies
@@ -53,7 +53,7 @@ jobs:
build:
name: Docker Build & Push
if: github.repository == 'gethomepage/homepage'
runs-on: self-hosted
runs-on: ubuntu-22.04
needs: [ pre-commit ]
permissions:
contents: read
@@ -92,7 +92,7 @@ jobs:
nextjs-${{ runner.os }}-${{ hashFiles('pnpm-lock.yaml') }}
- name: Install pnpm
uses: pnpm/action-setup@v4
uses: pnpm/action-setup@v5
with:
version: 10
run_install: false
@@ -100,7 +100,7 @@ jobs:
- name: Setup Node.js
uses: actions/setup-node@v6
with:
node-version: 20
node-version: 24
cache: 'pnpm'
- name: Install dependencies

54
.github/workflows/release-drafter.yml vendored Normal file
View File

@@ -0,0 +1,54 @@
name: Release Drafter
on:
push:
branches:
- dev
pull_request_target:
types: [opened, reopened, synchronize]
workflow_dispatch:
inputs:
version:
description: "Optional explicit version override (for example: 2.0.0)"
required: false
type: string
permissions:
contents: read
jobs:
update_release_draft:
name: Update Release Draft
if: github.event_name == 'push' || github.event_name == 'workflow_dispatch'
permissions:
contents: write
pull-requests: read
runs-on: ubuntu-latest
steps:
- if: github.event_name == 'workflow_dispatch' && github.event.inputs.version != ''
uses: release-drafter/release-drafter@v7
with:
config-name: release-drafter.yml
version: ${{ github.event.inputs.version }}
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- if: github.event_name != 'workflow_dispatch' || github.event.inputs.version == ''
uses: release-drafter/release-drafter@v7
with:
config-name: release-drafter.yml
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
auto_label:
name: Auto Label PR
if: github.event_name == 'pull_request_target'
permissions:
contents: read
pull-requests: write
runs-on: ubuntu-latest
steps:
- uses: release-drafter/release-drafter/autolabeler@ebb69bb56f1b0ebd19897745035726b19bef973e
with:
config-name: release-drafter.yml
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

View File

@@ -15,7 +15,7 @@ jobs:
steps:
- uses: actions/checkout@v6
- uses: pnpm/action-setup@v4
- uses: pnpm/action-setup@v5
with:
version: 9

1
.vscode/launch.json vendored
View File

@@ -3,6 +3,7 @@
{
"name": "Debug homepage",
"type": "node",
"preLaunchTask": "pnpm install",
"request": "launch",
"runtimeExecutable": "pnpm",
"runtimeArgs": ["run", "dev"],

21
.vscode/tasks.json vendored Normal file
View File

@@ -0,0 +1,21 @@
{
"version": "2.0.0",
"tasks": [
{
"type": "shell",
"label": "pnpm install",
"command": "pnpm install",
"group": {
"kind": "build",
"isDefault": true
},
"presentation": {
"clear": true,
"panel": "shared",
"showReuseMessage": false
},
"problemMatcher": []
}
]
}

View File

@@ -27,13 +27,6 @@
<a href="https://paypal.me/phelpsben" title="Donate"><img alt="GitHub Sponsors" src="https://img.shields.io/github/sponsors/benphelps"></a>
</p>
<p align="center">
<a href="https://www.digitalocean.com/?refcode=df14bcb7c016&utm_campaign=Referral_Invite&utm_medium=Referral_Program&utm_source=badge"><img src="https://web-platforms.sfo2.cdn.digitaloceanspaces.com/WWW/Badge%201.svg" alt="DigitalOcean Referral Badge" /></a>
</p>
<p align="center">
<em>Homepage builds are kindly powered by DigitalOcean.</em>
</p>
# Features
With features like quick search, bookmarks, weather support, a wide range of integrations and widgets, an elegant and modern design, and a focus on performance, Homepage is your ideal start to the day and a handy companion throughout it.

View File

@@ -20,13 +20,13 @@ helm install my-release jameswynn/homepage
Set the `mode` in the `kubernetes.yaml` to `cluster`.
```yaml
mode: default
mode: cluster
```
To enable Kubernetes gateway-api compatibility, set `route` to `gateway`.
To enable Kubernetes gateway-api compatibility, set `gateway` to `true`.
```yaml
route: gateway
gateway: true
```
## Widgets

View File

@@ -5,7 +5,12 @@ const nextConfig = {
reactStrictMode: true,
output: "standalone",
images: {
domains: ["cdn.jsdelivr.net"],
remotePatterns: [
{
protocol: "https",
hostname: "cdn.jsdelivr.net",
},
],
unoptimized: true,
},
i18n,

View File

@@ -5,7 +5,7 @@
"scripts": {
"preinstall": "npx only-allow pnpm",
"dev": "next dev",
"build": "next build",
"build": "next build --webpack",
"start": "next start",
"lint": "eslint .",
"test": "vitest run",
@@ -28,7 +28,7 @@
"luxon": "^3.6.1",
"memory-cache": "^0.2.0",
"minecraftstatuspinger": "^1.2.2",
"next": "^15.5.11",
"next": "^16.1.7",
"next-i18next": "^15.4.3",
"ping": "^0.4.4",
"pretty-bytes": "^7.1.0",
@@ -36,12 +36,12 @@
"react": "^19.2.4",
"react-dom": "^19.2.4",
"react-i18next": "^15.5.3",
"react-icons": "^5.5.0",
"react-icons": "^5.6.0",
"recharts": "^3.1.2",
"swr": "^2.4.0",
"systeminformation": "^5.27.11",
"swr": "^2.4.1",
"systeminformation": "^5.30.8",
"tough-cookie": "^6.0.0",
"urbackup-server-api": "^0.91.0",
"urbackup-server-api": "^0.92.2",
"winston": "^3.19.0",
"ws": "^8.18.3",
"xml-js": "^1.6.11"
@@ -60,7 +60,7 @@
"eslint-config-prettier": "^10.1.8",
"eslint-plugin-import": "^2.32.0",
"eslint-plugin-jsx-a11y": "^6.10.2",
"eslint-plugin-prettier": "^5.5.4",
"eslint-plugin-prettier": "^5.5.5",
"eslint-plugin-react": "^7.37.4",
"eslint-plugin-react-hooks": "^5.2.0",
"jsdom": "^28.1.0",

542
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@@ -108,14 +108,14 @@
"songs": "Liedjies"
},
"jellyfin": {
"playing": "Playing",
"transcoding": "Transcoding",
"bitrate": "Bitrate",
"no_active": "No Active Streams",
"playing": "Speel",
"transcoding": "Transkodering",
"bitrate": "Bistempo",
"no_active": "Geen Aktiewe Strome",
"movies": "Movies",
"series": "Series",
"episodes": "Episodes",
"songs": "Songs"
"series": "Reekse",
"episodes": "Episode",
"songs": "Liedjies"
},
"esphome": {
"offline": "Vanlyn af",
@@ -184,6 +184,13 @@
"no_active": "Geen aktiewe strome nie",
"plex_connection_error": "Gaan Plex-verbinding Na"
},
"tracearr": {
"no_active": "Geen Aktiewe Strome",
"streams": "Uitsendings",
"transcodes": "Transkodering",
"directplay": "Direkte Speel",
"bitrate": "Bistempo"
},
"omada": {
"connectedAp": "Gekoppelde APs",
"activeUser": "Aktiewe toestelle",
@@ -282,17 +289,13 @@
"approved": "Goedgekeur",
"available": "Beskikbaar"
},
"jellyseerr": {
"seerr": {
"pending": "Afwagtend",
"approved": "Goedgekeur",
"available": "Beskikbaar",
"issues": "Oop Kwessies"
},
"overseerr": {
"pending": "Afwagtend",
"completed": "Afgehandel",
"processing": "Verwerking",
"approved": "Goedgekeur",
"available": "Beskikbaar"
"issues": "Oop Kwessies"
},
"netalertx": {
"total": "Totaal",
@@ -1152,11 +1155,11 @@
"artists": "Kunstenaars"
},
"arcane": {
"containers": "Containers",
"images": "Images",
"image_updates": "Image Updates",
"images_unused": "Unused",
"environment_required": "Environment ID Required"
"containers": "Houers",
"images": "Beelde",
"image_updates": "Beeldopdaterings",
"images_unused": "Ongebruik",
"environment_required": "Omgewings-ID Vereis"
},
"dockhand": {
"running": "Lopend",
@@ -1171,5 +1174,11 @@
"paused": "Onderbreek",
"total": "Totaal",
"environment_not_found": "Omgewing Nie Gevind Nie"
},
"sparkyfitness": {
"eaten": "Geëet",
"burned": "Verbrand",
"remaining": "Oorblywende",
"steps": "Stappe"
}
}

View File

@@ -184,6 +184,13 @@
"no_active": "No Active Streams",
"plex_connection_error": "تحقق من الاتصال بـ Plex"
},
"tracearr": {
"no_active": "No Active Streams",
"streams": "Streams",
"transcodes": "Transcodes",
"directplay": "Direct Play",
"bitrate": "Bitrate"
},
"omada": {
"connectedAp": "المتصلة APs",
"activeUser": "الأجهزة النشطة",
@@ -282,18 +289,14 @@
"approved": "مصدق",
"available": "متاح"
},
"jellyseerr": {
"seerr": {
"pending": "Pending",
"approved": "Approved",
"available": "Available",
"completed": "Completed",
"processing": "Processing",
"issues": "Open Issues"
},
"overseerr": {
"pending": "Pending",
"processing": "معالجة",
"approved": "Approved",
"available": "Available"
},
"netalertx": {
"total": "Total",
"connected": "Connected",
@@ -1171,5 +1174,11 @@
"paused": "Paused",
"total": "Total",
"environment_not_found": "Environment Not Found"
},
"sparkyfitness": {
"eaten": "Eaten",
"burned": "Burned",
"remaining": "Remaining",
"steps": "Steps"
}
}

View File

@@ -184,6 +184,13 @@
"no_active": "Няма активни потоци",
"plex_connection_error": "Провери връзка с Plex"
},
"tracearr": {
"no_active": "No Active Streams",
"streams": "Streams",
"transcodes": "Transcodes",
"directplay": "Direct Play",
"bitrate": "Bitrate"
},
"omada": {
"connectedAp": "Свързани точки",
"activeUser": "Активни устройства",
@@ -282,17 +289,13 @@
"approved": "Одобрен",
"available": "Наличен"
},
"jellyseerr": {
"seerr": {
"pending": "Pending",
"approved": "Approved",
"available": "Available",
"issues": "Open Issues"
},
"overseerr": {
"pending": "Pending",
"completed": "Completed",
"processing": "Processing",
"approved": "Approved",
"available": "Available"
"issues": "Open Issues"
},
"netalertx": {
"total": "Total",
@@ -1171,5 +1174,11 @@
"paused": "Paused",
"total": "Total",
"environment_not_found": "Environment Not Found"
},
"sparkyfitness": {
"eaten": "Eaten",
"burned": "Burned",
"remaining": "Remaining",
"steps": "Steps"
}
}

View File

@@ -61,7 +61,7 @@
"wlan_devices": "Dispositius WLAN",
"lan_users": "Usuaris LAN",
"wlan_users": "Usuaris WLAN",
"up": "UP",
"up": "ACTIU",
"down": "INACTIU",
"wait": "Si us plau espera",
"empty_data": "Estat del subsistema desconegut"
@@ -93,8 +93,8 @@
"http_status": "Estat HTTP",
"error": "Error",
"response": "Resposta",
"down": "Down",
"up": "Up",
"down": "Inactiu",
"up": "Actiu",
"not_available": "No disponible"
},
"emby": {
@@ -108,21 +108,21 @@
"songs": "Cançons"
},
"jellyfin": {
"playing": "Playing",
"transcoding": "Transcoding",
"bitrate": "Bitrate",
"no_active": "No Active Streams",
"movies": "Movies",
"series": "Series",
"episodes": "Episodes",
"songs": "Songs"
"playing": "Reproduïnt",
"transcoding": "Transcodificant",
"bitrate": "Taxa de bits",
"no_active": "Sense reproduccions actives",
"movies": "Pel·lícules",
"series": "Sèries",
"episodes": "Episodis",
"songs": "Cançons"
},
"esphome": {
"offline": "Offline",
"offline_alt": "Offline",
"offline": "Desconnectat",
"offline_alt": "Desconnectat",
"online": "En línia",
"total": "Total",
"unknown": "Unknown"
"unknown": "Desconegut"
},
"evcc": {
"pv_power": "Producció",
@@ -143,7 +143,7 @@
"unread": "Sense llegir"
},
"fritzbox": {
"connectionStatus": "Status",
"connectionStatus": "Estat",
"connectionStatusUnconfigured": "Sense configurar",
"connectionStatusConnecting": "Connectant",
"connectionStatusAuthenticating": "Autenticant",
@@ -151,11 +151,11 @@
"connectionStatusDisconnecting": "Desconnectant",
"connectionStatusDisconnected": "Desconnectat",
"connectionStatusConnected": "Connectat",
"uptime": "Uptime",
"uptime": "Temps en funcionament",
"maxDown": "Màx. Descàrrega",
"maxUp": "Màx. Càrrega",
"down": "Down",
"up": "Up",
"down": "Inactiu",
"up": "Actiu",
"received": "Rebuts",
"sent": "Enviats",
"externalIPAddress": "IP ext.",
@@ -178,17 +178,24 @@
"passes": "Aprovat"
},
"tautulli": {
"playing": "Playing",
"transcoding": "Transcoding",
"bitrate": "Bitrate",
"no_active": "No Active Streams",
"playing": "Reproduïnt",
"transcoding": "Transcodificant",
"bitrate": "Taxa de bits",
"no_active": "Sense reproduccions actives",
"plex_connection_error": "Comprova la connexió de Plex"
},
"tracearr": {
"no_active": "Sense reproduccions actives",
"streams": "Transmissions",
"transcodes": "Transcodificacions",
"directplay": "Reproducció directa",
"bitrate": "Taxa de bits"
},
"omada": {
"connectedAp": "AP connectats",
"activeUser": "Dispositius actius",
"alerts": "Alertes",
"connectedGateways": "Connected gateways",
"connectedGateways": "Pasarel·les connectades",
"connectedSwitches": "Conmutadors connectats"
},
"nzbget": {
@@ -199,24 +206,24 @@
"plex": {
"streams": "Transmissions actives",
"albums": "Àlbums",
"movies": "Movies",
"movies": "Pel·lícules",
"tv": "Sèries"
},
"sabnzbd": {
"rate": "Rate",
"rate": "Taxa",
"queue": "Cua",
"timeleft": "Temps restant"
},
"rutorrent": {
"active": "Actiu",
"upload": "Upload",
"download": "Download"
"upload": "Pujada",
"download": "Baixada"
},
"transmission": {
"download": "Download",
"upload": "Upload",
"leech": "Leech",
"seed": "Seed"
"download": "Baixada",
"upload": "Pujada",
"leech": "Sangonera",
"seed": "Sembrat"
},
"qbittorrent": {
"download": "Download",
@@ -282,18 +289,14 @@
"approved": "Aprovat",
"available": "Disponible"
},
"jellyseerr": {
"seerr": {
"pending": "Pending",
"approved": "Approved",
"available": "Available",
"completed": "Completed",
"processing": "Processing",
"issues": "Open Issues"
},
"overseerr": {
"pending": "Pending",
"processing": "Processant",
"approved": "Approved",
"available": "Available"
},
"netalertx": {
"total": "Total",
"connected": "Connected",
@@ -323,10 +326,10 @@
"total": "Total"
},
"suwayomi": {
"download": "Downloaded",
"download": "Descarregat",
"nondownload": "No descarregat",
"read": "Read",
"unread": "Unread",
"read": "Llegits",
"unread": "No llegits",
"downloadedread": "Descarregat i llegit",
"downloadedunread": "Descarregat i per llegir",
"nondownloadedread": "No descarregat i llegit",
@@ -347,7 +350,7 @@
"ago": "Fa {{value}}"
},
"technitium": {
"totalQueries": "Queries",
"totalQueries": "Consultes",
"totalNoError": "Èxits",
"totalServerFailure": "Fallades",
"totalNxDomain": "Dominis NX",
@@ -355,12 +358,12 @@
"totalAuthoritative": "Autoritatiu",
"totalRecursive": "Recursiu",
"totalCached": "A la memòria cau",
"totalBlocked": "Blocked",
"totalBlocked": "Bloquejats",
"totalDropped": "Abandonat",
"totalClients": "Clients"
},
"tdarr": {
"queue": "Queue",
"queue": "Cua",
"processed": "Processat",
"errored": "Error",
"saved": "Estalviat"
@@ -371,13 +374,13 @@
"middleware": "Intermediari"
},
"trilium": {
"version": "Version",
"version": "Versió",
"notesCount": "Notes",
"dbSize": "Database Size",
"unknown": "Unknown"
"dbSize": "Tamany de la base de dades",
"unknown": "Desconegut"
},
"navidrome": {
"nothing_streaming": "No Active Streams",
"nothing_streaming": "Sense reproduccions actives",
"please_wait": "Espereu si us plau"
},
"npm": {
@@ -400,43 +403,43 @@
"prowlarr": {
"enableIndexers": "Indexadors",
"numberOfGrabs": "Captures",
"numberOfQueries": "Queries",
"numberOfQueries": "Consultes",
"numberOfFailGrabs": "Captures fallides",
"numberOfFailQueries": "Consultes fallides"
},
"jackett": {
"configured": "Configurat",
"errored": "Errored"
"errored": "Errors"
},
"strelaysrv": {
"numActiveSessions": "Sessions",
"numConnections": "Connexions",
"dataRelayed": "Transmès",
"transferRate": "Rate"
"transferRate": "Taxa"
},
"mastodon": {
"user_count": "Users",
"user_count": "Usuaris",
"status_count": "Publicacions",
"domain_count": "Dominis"
},
"medusa": {
"wanted": "Wanted",
"queued": "Queued",
"series": "Series"
"wanted": "Volguts",
"queued": "Encuat",
"series": "Sèries"
},
"minecraft": {
"players": "Jugadors",
"version": "Versió",
"status": "Status",
"up": "Online",
"down": "Offline"
"status": "Estat",
"up": "En línia",
"down": "Fora de línia"
},
"miniflux": {
"read": "Llegit",
"unread": "Unread"
"unread": "No llegits"
},
"authentik": {
"users": "Users",
"users": "Usuaris",
"loginsLast24H": "Inicis de sessió (24h)",
"failedLoginsLast24H": "Errors d'inici de sessió (24h)"
},
@@ -448,19 +451,19 @@
},
"glances": {
"cpu": "CPU",
"load": "Load",
"wait": "Please wait",
"load": "Càrrega",
"wait": "Si us plau espera",
"temp": "TEMP",
"_temp": "Temp",
"warn": "Avís",
"uptime": "UP",
"uptime": "ACTIU",
"total": "Total",
"free": "Free",
"used": "Used",
"free": "Lliure",
"used": "Utilitzat",
"days": "d",
"hours": "h",
"crit": "Crític",
"read": "Read",
"read": "Lectura",
"write": "Escriptura",
"gpu": "GPU",
"mem": "Mem",
@@ -481,25 +484,25 @@
"1-day": "Majorment assolellat",
"1-night": "Majorment clar",
"2-day": "Parcialment ennuvolat",
"2-night": "Partly Cloudy",
"2-night": "Parcialment ennuvolat",
"3-day": "Ennuvolat",
"3-night": "Cloudy",
"3-night": "Ennuvolat",
"45-day": "Boirós",
"45-night": "Foggy",
"48-day": "Foggy",
"48-night": "Foggy",
"45-night": "Emboirat",
"48-day": "Boirós",
"48-night": "Emboirat",
"51-day": "Ruixats lleugers",
"51-night": "Light Drizzle",
"51-night": "Plugim lleuger",
"53-day": "Ruixat",
"53-night": "Drizzle",
"53-night": "Plugim",
"55-day": "Ruixat intens",
"55-night": "Heavy Drizzle",
"55-night": "Plovisqueig intens",
"56-day": "Lleuger ruixat gelat",
"56-night": "Light Freezing Drizzle",
"56-night": "Lleuger ruixat gelat",
"57-day": "Ruixat gelat",
"57-night": "Freezing Drizzle",
"57-night": "Plugim gelat",
"61-day": "Pluja lleugera",
"61-night": "Light Rain",
"61-night": "Pluja lleugera",
"63-day": "Pluja",
"63-night": "Rain",
"65-day": "Pluja intensa",
@@ -634,12 +637,12 @@
"mikrotik": {
"cpuLoad": "Càrrega de CPU",
"memoryUsed": "Memoria en ús",
"uptime": "Uptime",
"uptime": "Temps en funcionament",
"numberOfLeases": "IPs assignades"
},
"xteve": {
"streams_all": "Tots els streams",
"streams_active": "Active Streams",
"streams_active": "Transmissions actives",
"streams_xepg": "Canals XEPG"
},
"opendtu": {
@@ -649,7 +652,7 @@
"limit": "Límit"
},
"opnsense": {
"cpu": "CPU Load",
"cpu": "Càrrega de CPU",
"memory": "Memòria activa",
"wanUpload": "Pujada WAN",
"wanDownload": "Baixada WAN"
@@ -661,21 +664,21 @@
"layers": "Capes"
},
"octoprint": {
"printer_state": "Status",
"printer_state": "Estat",
"temp_tool": "Temperatura capçal",
"temp_bed": "Temperatura llit",
"job_completion": "Finalització"
},
"cloudflared": {
"origin_ip": "IP Origen",
"status": "Status"
"status": "Estat"
},
"pfsense": {
"load": "Càrrega mitjana",
"memory": "Ús Memòria",
"wanStatus": "Estat WAN",
"up": "Up",
"down": "Down",
"up": "Actiu",
"down": "Inactiu",
"temp": "Temp",
"disk": "Ús Disc",
"wanIP": "IP WAN"
@@ -687,58 +690,58 @@
"memory_usage": "Memòria"
},
"immich": {
"users": "Users",
"users": "Usuaris",
"photos": "Fotos",
"videos": "Videos",
"videos": "Vídeos",
"storage": "Emmagatzematge"
},
"uptimekuma": {
"up": "Actius",
"down": "Caiguts",
"uptime": "Uptime",
"uptime": "Temps en funcionament",
"incident": "Incidència",
"m": "m"
},
"atsumeru": {
"series": "Series",
"series": "Sèries",
"archives": "Arxius",
"chapters": "Capítols",
"categories": "Categories"
},
"komga": {
"libraries": "Biblioteques",
"series": "Series",
"books": "Books"
"series": "Sèries",
"books": "Llibres"
},
"diskstation": {
"days": "Days",
"uptime": "Uptime",
"volumeAvailable": "Available"
"days": "Dies",
"uptime": "Temps en funcionament",
"volumeAvailable": "Disponible"
},
"dispatcharr": {
"channels": "Channels",
"streams": "Streams"
"channels": "Canals",
"streams": "Transmissions"
},
"mylar": {
"series": "Series",
"series": "Sèries",
"issues": "Problemes",
"wanted": "Wanted"
"wanted": "Volguts"
},
"photoprism": {
"albums": "Albums",
"photos": "Photos",
"videos": "Videos",
"albums": "Àlbums",
"photos": "Fotos",
"videos": "Vídeos",
"people": "Gent"
},
"fileflows": {
"queue": "Queue",
"processing": "Processing",
"processed": "Processed",
"queue": "Cua",
"processing": "Processant",
"processed": "Processat",
"time": "Temps"
},
"firefly": {
"networth": "Net Worth",
"budget": "Budget"
"networth": "Valor Net",
"budget": "Pressupost"
},
"grafana": {
"dashboards": "Taulells",
@@ -755,11 +758,11 @@
"numshares": "Elements compartits"
},
"kopia": {
"status": "Status",
"status": "Estat",
"size": "Mida",
"lastrun": "Darrera execució",
"nextrun": "Següent execució",
"failed": "Failed"
"failed": "Error"
},
"unmanic": {
"active_workers": "Treballadors actius",
@@ -776,21 +779,21 @@
"targets_total": "Objectius Totals"
},
"gatus": {
"up": "Sites Up",
"down": "Sites Down",
"uptime": "Uptime"
"up": "Actius",
"down": "Caiguts",
"uptime": "Temps en funcionament"
},
"ghostfolio": {
"gross_percent_today": "Today",
"gross_percent_today": "Avui",
"gross_percent_1y": "Un any",
"gross_percent_max": "Sempre",
"net_worth": "Net Worth"
"net_worth": "Valor Net"
},
"audiobookshelf": {
"podcasts": "Pòdcasts",
"books": "Books",
"books": "Llibres",
"podcastsDuration": "Durada",
"booksDuration": "Duration"
"booksDuration": "Durada"
},
"homeassistant": {
"people_home": "Gent a casa",
@@ -799,23 +802,23 @@
},
"whatsupdocker": {
"monitoring": "Supervisió",
"updates": "Updates"
"updates": "Actualitzacions"
},
"calibreweb": {
"books": "Books",
"books": "Llibres",
"authors": "Autors",
"categories": "Categories",
"series": "Series"
"series": "Sèries"
},
"booklore": {
"libraries": "Libraries",
"books": "Books",
"reading": "Reading",
"finished": "Finished"
"libraries": "Biblioteques",
"books": "Llibres",
"reading": "Llegint",
"finished": "Acabats"
},
"jdownloader": {
"downloadCount": "Queue",
"downloadBytesRemaining": "Remaining",
"downloadCount": "Cua",
"downloadBytesRemaining": "Restant",
"downloadTotalBytes": "Size",
"downloadSpeed": "Speed"
},
@@ -987,17 +990,17 @@
},
"frigate": {
"cameras": "Càmeres",
"uptime": "Uptime",
"version": "Version"
"uptime": "Temps en funcionament",
"version": "Versió"
},
"linkwarden": {
"links": "Enllaços",
"collections": "Col·leccions",
"tags": "Tags"
"tags": "Etiquetes"
},
"zabbix": {
"unclassified": "No classificat",
"information": "Information",
"information": "Informació",
"warning": "Avís",
"average": "Mitjana",
"high": "Alt",
@@ -1018,22 +1021,22 @@
"tasksInProgress": "Tasques en marxa"
},
"headscale": {
"name": "Name",
"address": "Address",
"last_seen": "Last Seen",
"status": "Status",
"online": "Online",
"offline": "Offline"
"name": "Nom",
"address": "Adreça",
"last_seen": "Vist per darrera vegada",
"status": "Estat",
"online": "En línia",
"offline": "Desconnectat"
},
"beszel": {
"name": "Name",
"name": "Nom",
"systems": "Sistemes",
"up": "Up",
"down": "Down",
"paused": "Paused",
"pending": "Pending",
"status": "Status",
"updated": "Updated",
"up": "Actiu",
"down": "Inactiu",
"paused": "Pausat",
"pending": "Pendent",
"status": "Estat",
"updated": "Actualitzat",
"cpu": "CPU",
"memory": "MEM",
"disk": "Disc",
@@ -1043,34 +1046,34 @@
"apps": "Apps",
"synced": "Sincronitzats",
"outOfSync": "Dessincronitzats",
"healthy": "Healthy",
"healthy": "Sa",
"degraded": "Degradats",
"progressing": "Progressant",
"missing": "Missing",
"missing": "Falten",
"suspended": "Suspesos"
},
"spoolman": {
"loading": "Loading"
"loading": "Carregant"
},
"gitlab": {
"groups": "Grups",
"issues": "Issues",
"issues": "Problemes",
"merges": "Merge Requests",
"projects": "Projectes"
},
"apcups": {
"status": "Status",
"load": "Load",
"bcharge": "Battery Charge",
"timeleft": "Time Left"
"status": "Estat",
"load": "Càrrega",
"bcharge": "Càrrega de la bateria",
"timeleft": "Temps restant"
},
"karakeep": {
"bookmarks": "Bookmarks",
"favorites": "Favorites",
"archived": "Archived",
"highlights": "Highlights",
"lists": "Lists",
"tags": "Tags"
"bookmarks": "Marcadors",
"favorites": "Preferits",
"archived": "Arxivats",
"highlights": "Destacats",
"lists": "Llistes",
"tags": "Etiquetes"
},
"slskd": {
"slskStatus": "Network",
@@ -1171,5 +1174,11 @@
"paused": "Paused",
"total": "Total",
"environment_not_found": "Environment Not Found"
},
"sparkyfitness": {
"eaten": "Eaten",
"burned": "Burned",
"remaining": "Remaining",
"steps": "Steps"
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -184,6 +184,13 @@
"no_active": "No Active Streams",
"plex_connection_error": "Tjek Plex-forbindelse"
},
"tracearr": {
"no_active": "No Active Streams",
"streams": "Streams",
"transcodes": "Transcodes",
"directplay": "Direct Play",
"bitrate": "Bitrate"
},
"omada": {
"connectedAp": "Forbundne APs",
"activeUser": "Aktive enheder",
@@ -282,18 +289,14 @@
"approved": "Godkendt",
"available": "Tilgængelig"
},
"jellyseerr": {
"seerr": {
"pending": "Pending",
"approved": "Approved",
"available": "Available",
"completed": "Completed",
"processing": "Processing",
"issues": "Open Issues"
},
"overseerr": {
"pending": "Pending",
"processing": "Behandler",
"approved": "Approved",
"available": "Available"
},
"netalertx": {
"total": "Total",
"connected": "Connected",
@@ -1171,5 +1174,11 @@
"paused": "Paused",
"total": "Total",
"environment_not_found": "Environment Not Found"
},
"sparkyfitness": {
"eaten": "Eaten",
"burned": "Burned",
"remaining": "Remaining",
"steps": "Steps"
}
}

View File

@@ -108,7 +108,7 @@
"songs": "Songs"
},
"jellyfin": {
"playing": "Playing",
"playing": "Wiedergabe",
"transcoding": "Transkodierung",
"bitrate": "Bitrate",
"no_active": "Keine aktiven Streams",
@@ -184,6 +184,13 @@
"no_active": "Keine aktiven Streams",
"plex_connection_error": "Prüfe Plex-Verbindung"
},
"tracearr": {
"no_active": "No Active Streams",
"streams": "Streams",
"transcodes": "Transcodes",
"directplay": "Direct Play",
"bitrate": "Bitrate"
},
"omada": {
"connectedAp": "Verbundene APs",
"activeUser": "Aktive Geräte",
@@ -282,17 +289,13 @@
"approved": "Genehmigt",
"available": "Verfügbar"
},
"jellyseerr": {
"pending": "Wartend",
"approved": "Genehmigt",
"available": "Verfügbar",
"issues": "Offene Issues"
},
"overseerr": {
"pending": "Wartend",
"processing": "Wird verarbeitet",
"approved": "Genehmigt",
"available": "Verfügbar"
"seerr": {
"pending": "Pending",
"approved": "Approved",
"available": "Available",
"completed": "Completed",
"processing": "Processing",
"issues": "Open Issues"
},
"netalertx": {
"total": "Total",
@@ -1159,17 +1162,23 @@
"environment_required": "Environment ID Required"
},
"dockhand": {
"running": "Running",
"stopped": "Stopped",
"running": "Wird ausgeführt",
"stopped": "Gestoppt",
"cpu": "CPU",
"memory": "Memory",
"memory": "RAM",
"images": "Images",
"volumes": "Volumes",
"events_today": "Heutige Ereignisse",
"pending_updates": "Ausstehende Updates",
"stacks": "Stacks",
"paused": "Pausiert",
"total": "Total",
"total": "Gesamt",
"environment_not_found": "Umgebung nicht gefunden"
},
"sparkyfitness": {
"eaten": "Eaten",
"burned": "Burned",
"remaining": "Remaining",
"steps": "Steps"
}
}

View File

@@ -184,6 +184,13 @@
"no_active": "No Active Streams",
"plex_connection_error": "Έλεγχος Σύνδεσης με Plex"
},
"tracearr": {
"no_active": "No Active Streams",
"streams": "Streams",
"transcodes": "Transcodes",
"directplay": "Direct Play",
"bitrate": "Bitrate"
},
"omada": {
"connectedAp": "Συνδεδεμένα APs",
"activeUser": "Ενεργές συσκευές",
@@ -282,18 +289,14 @@
"approved": "Εγκρίθηκε",
"available": "Διαθέσιμο"
},
"jellyseerr": {
"seerr": {
"pending": "Pending",
"approved": "Approved",
"available": "Available",
"completed": "Completed",
"processing": "Processing",
"issues": "Open Issues"
},
"overseerr": {
"pending": "Pending",
"processing": "Σε επεξεργασία",
"approved": "Approved",
"available": "Available"
},
"netalertx": {
"total": "Total",
"connected": "Connected",
@@ -1171,5 +1174,11 @@
"paused": "Paused",
"total": "Total",
"environment_not_found": "Environment Not Found"
},
"sparkyfitness": {
"eaten": "Eaten",
"burned": "Burned",
"remaining": "Remaining",
"steps": "Steps"
}
}

View File

@@ -184,6 +184,13 @@
"no_active": "No Active Streams",
"plex_connection_error": "Check Plex Connection"
},
"tracearr": {
"no_active": "No Active Streams",
"streams": "Streams",
"transcodes": "Transcodes",
"directplay": "Direct Play",
"bitrate": "Bitrate"
},
"omada": {
"connectedAp": "Connected APs",
"activeUser": "Active devices",
@@ -282,17 +289,13 @@
"approved": "Aprobita",
"available": "Havebla"
},
"jellyseerr": {
"seerr": {
"pending": "Pending",
"approved": "Approved",
"available": "Available",
"issues": "Open Issues"
},
"overseerr": {
"pending": "Pending",
"completed": "Completed",
"processing": "Processing",
"approved": "Approved",
"available": "Available"
"issues": "Open Issues"
},
"netalertx": {
"total": "Total",
@@ -1171,5 +1174,11 @@
"paused": "Paused",
"total": "Total",
"environment_not_found": "Environment Not Found"
},
"sparkyfitness": {
"eaten": "Eaten",
"burned": "Burned",
"remaining": "Remaining",
"steps": "Steps"
}
}

View File

@@ -184,6 +184,13 @@
"no_active": "Sin transmisiones activas",
"plex_connection_error": "Comprueba la conexión a Plex"
},
"tracearr": {
"no_active": "No Active Streams",
"streams": "Streams",
"transcodes": "Transcodes",
"directplay": "Direct Play",
"bitrate": "Bitrate"
},
"omada": {
"connectedAp": "AP conectados",
"activeUser": "Dispositivos activos",
@@ -282,17 +289,13 @@
"approved": "Aprobado",
"available": "Disponible"
},
"jellyseerr": {
"pending": "Pendiente",
"approved": "Aprobado",
"available": "Disponible",
"issues": "Issues Abiertos"
},
"overseerr": {
"pending": "Pendiente",
"processing": "Procesando",
"approved": "Aprobado",
"available": "Disponible"
"seerr": {
"pending": "Pending",
"approved": "Approved",
"available": "Available",
"completed": "Completed",
"processing": "Processing",
"issues": "Open Issues"
},
"netalertx": {
"total": "Total",
@@ -1171,5 +1174,11 @@
"paused": "En Pausa",
"total": "Total",
"environment_not_found": "Entorno no encontrado"
},
"sparkyfitness": {
"eaten": "Eaten",
"burned": "Burned",
"remaining": "Remaining",
"steps": "Steps"
}
}

View File

@@ -184,6 +184,13 @@
"no_active": "No Active Streams",
"plex_connection_error": "Check Plex Connection"
},
"tracearr": {
"no_active": "No Active Streams",
"streams": "Streams",
"transcodes": "Transcodes",
"directplay": "Direct Play",
"bitrate": "Bitrate"
},
"omada": {
"connectedAp": "Connected APs",
"activeUser": "Active devices",
@@ -282,17 +289,13 @@
"approved": "Approved",
"available": "Available"
},
"jellyseerr": {
"seerr": {
"pending": "Pending",
"approved": "Approved",
"available": "Available",
"issues": "Open Issues"
},
"overseerr": {
"pending": "Pending",
"completed": "Completed",
"processing": "Processing",
"approved": "Approved",
"available": "Available"
"issues": "Open Issues"
},
"netalertx": {
"total": "Total",
@@ -1171,5 +1174,11 @@
"paused": "Paused",
"total": "Total",
"environment_not_found": "Environment Not Found"
},
"sparkyfitness": {
"eaten": "Eaten",
"burned": "Burned",
"remaining": "Remaining",
"steps": "Steps"
}
}

View File

@@ -184,6 +184,13 @@
"no_active": "No Active Streams",
"plex_connection_error": "Check Plex Connection"
},
"tracearr": {
"no_active": "No Active Streams",
"streams": "Streams",
"transcodes": "Transcodes",
"directplay": "Direct Play",
"bitrate": "Bitrate"
},
"omada": {
"connectedAp": "Connected APs",
"activeUser": "Active devices",
@@ -282,17 +289,13 @@
"approved": "Hyväksytty",
"available": "Saatavilla"
},
"jellyseerr": {
"seerr": {
"pending": "Pending",
"approved": "Approved",
"available": "Available",
"issues": "Open Issues"
},
"overseerr": {
"pending": "Pending",
"completed": "Completed",
"processing": "Processing",
"approved": "Approved",
"available": "Available"
"issues": "Open Issues"
},
"netalertx": {
"total": "Total",
@@ -1171,5 +1174,11 @@
"paused": "Paused",
"total": "Total",
"environment_not_found": "Environment Not Found"
},
"sparkyfitness": {
"eaten": "Eaten",
"burned": "Burned",
"remaining": "Remaining",
"steps": "Steps"
}
}

View File

@@ -108,8 +108,8 @@
"songs": "Morceaux"
},
"jellyfin": {
"playing": "Playing",
"transcoding": "Transcoding",
"playing": "En cours",
"transcoding": "En cours d'encodage",
"bitrate": "Bitrate",
"no_active": "No Active Streams",
"movies": "Movies",
@@ -184,6 +184,13 @@
"no_active": "Aucune lecture en cours",
"plex_connection_error": "Vérifier la connexion à Plex"
},
"tracearr": {
"no_active": "No Active Streams",
"streams": "Streams",
"transcodes": "Transcodes",
"directplay": "Direct Play",
"bitrate": "Bitrate"
},
"omada": {
"connectedAp": "APs connectées",
"activeUser": "Périphériques actifs",
@@ -282,17 +289,13 @@
"approved": "Approuvé",
"available": "Disponible"
},
"jellyseerr": {
"pending": "En attente",
"approved": "Approuvé",
"available": "Disponible",
"issues": "Problèmes non résolus"
},
"overseerr": {
"pending": "En attente",
"processing": "En cours de traitement",
"approved": "Approuvé",
"available": "Disponible"
"seerr": {
"pending": "Pending",
"approved": "Approved",
"available": "Available",
"completed": "Completed",
"processing": "Processing",
"issues": "Open Issues"
},
"netalertx": {
"total": "Total",
@@ -613,9 +616,9 @@
"pangolin": {
"orgs": "Orgs",
"sites": "Sites",
"resources": "Resources",
"targets": "Targets",
"traffic": "Traffic",
"resources": "Ressources",
"targets": "Cibles",
"traffic": "Trafique",
"in": "In",
"out": "Out"
},
@@ -712,7 +715,7 @@
},
"diskstation": {
"days": "Jours",
"uptime": "Disponibilité",
"uptime": "Démarré depuis",
"volumeAvailable": "Disponible"
},
"dispatcharr": {
@@ -743,7 +746,7 @@
"grafana": {
"dashboards": "Tableau de bord",
"datasources": "Sources données",
"totalalerts": "Total alertes",
"totalalerts": "Alertes totales",
"alertstriggered": "Alertes déclenchées"
},
"nextcloud": {
@@ -942,7 +945,7 @@
"studios": "Studios",
"movies": "Films",
"tags": "Tags",
"oCount": "0 Compte"
"oCount": "O-mètre"
},
"tandoor": {
"users": "Utilisateurs",
@@ -1171,5 +1174,11 @@
"paused": "Paused",
"total": "Total",
"environment_not_found": "Environment Not Found"
},
"sparkyfitness": {
"eaten": "Eaten",
"burned": "Burned",
"remaining": "Remaining",
"steps": "Steps"
}
}

View File

@@ -184,6 +184,13 @@
"no_active": "אין הזרמות פעילות",
"plex_connection_error": "בדוק חיבור ל-Plex"
},
"tracearr": {
"no_active": "No Active Streams",
"streams": "Streams",
"transcodes": "Transcodes",
"directplay": "Direct Play",
"bitrate": "Bitrate"
},
"omada": {
"connectedAp": "נקודות גישה מחוברות",
"activeUser": "מכשירים פעילים",
@@ -282,18 +289,14 @@
"approved": "מאושר",
"available": "זמין"
},
"jellyseerr": {
"pending": "ממתין לאישור",
"approved": "מאושר",
"available": "זמין",
"seerr": {
"pending": "Pending",
"approved": "Approved",
"available": "Available",
"completed": "Completed",
"processing": "Processing",
"issues": "Open Issues"
},
"overseerr": {
"pending": "ממתין לאישור",
"processing": "מעבד",
"approved": "מאושר",
"available": "זמין"
},
"netalertx": {
"total": "סה\"כ",
"connected": "מחובר",
@@ -1171,5 +1174,11 @@
"paused": "Paused",
"total": "Total",
"environment_not_found": "Environment Not Found"
},
"sparkyfitness": {
"eaten": "Eaten",
"burned": "Burned",
"remaining": "Remaining",
"steps": "Steps"
}
}

View File

@@ -184,6 +184,13 @@
"no_active": "No Active Streams",
"plex_connection_error": "Check Plex Connection"
},
"tracearr": {
"no_active": "No Active Streams",
"streams": "Streams",
"transcodes": "Transcodes",
"directplay": "Direct Play",
"bitrate": "Bitrate"
},
"omada": {
"connectedAp": "Connected APs",
"activeUser": "Active devices",
@@ -282,17 +289,13 @@
"approved": "Approved",
"available": "Available"
},
"jellyseerr": {
"seerr": {
"pending": "Pending",
"approved": "Approved",
"available": "Available",
"issues": "Open Issues"
},
"overseerr": {
"pending": "Pending",
"completed": "Completed",
"processing": "Processing",
"approved": "Approved",
"available": "Available"
"issues": "Open Issues"
},
"netalertx": {
"total": "Total",
@@ -1171,5 +1174,11 @@
"paused": "Paused",
"total": "Total",
"environment_not_found": "Environment Not Found"
},
"sparkyfitness": {
"eaten": "Eaten",
"burned": "Burned",
"remaining": "Remaining",
"steps": "Steps"
}
}

View File

@@ -108,14 +108,14 @@
"songs": "Pjesme"
},
"jellyfin": {
"playing": "Playing",
"transcoding": "Transcoding",
"bitrate": "Bitrate",
"playing": "Reprodukcija u tijeku",
"transcoding": "Prekodiranje",
"bitrate": "Stopa bitova",
"no_active": "No Active Streams",
"movies": "Movies",
"series": "Series",
"episodes": "Episodes",
"songs": "Songs"
"movies": "Filmovi",
"series": "Serije",
"episodes": "Epizode",
"songs": "Pjesme"
},
"esphome": {
"offline": "Offline",
@@ -184,6 +184,13 @@
"no_active": "Nema aktivnih prijenosa",
"plex_connection_error": "Provjeri Plex vezu"
},
"tracearr": {
"no_active": "No Active Streams",
"streams": "Streams",
"transcodes": "Prekodiranja",
"directplay": "Izravna reprodukcija",
"bitrate": "Stopa bitova"
},
"omada": {
"connectedAp": "Povezani AP-ovi",
"activeUser": "Aktivni uređaji",
@@ -282,17 +289,13 @@
"approved": "Odobreno",
"available": "Dostupno"
},
"jellyseerr": {
"pending": "U tijeku",
"seerr": {
"pending": "Na čekanju",
"approved": "Odobreno",
"available": "Dostupno",
"issues": "Otvoreni problemi"
},
"overseerr": {
"pending": "U tijeku",
"completed": "Dovršeno",
"processing": "Obrada",
"approved": "Odobreno",
"available": "Dostupno"
"issues": "Otvoreni problemi"
},
"netalertx": {
"total": "Ukupno",
@@ -543,7 +546,7 @@
"up": "Aktivno",
"pending": "U tijeku",
"down": "Neaktivno",
"ok": "Ok"
"ok": "U redu"
},
"healthchecks": {
"new": "Novo",
@@ -611,11 +614,11 @@
"total": "Ukupno"
},
"pangolin": {
"orgs": "Orgs",
"sites": "Sites",
"resources": "Resources",
"targets": "Targets",
"traffic": "Traffic",
"orgs": "Organizacije",
"sites": "Web-stranice",
"resources": "Resursi",
"targets": "Ciljevi",
"traffic": "Promet",
"in": "In",
"out": "Out"
},
@@ -716,7 +719,7 @@
"volumeAvailable": "Dostupno"
},
"dispatcharr": {
"channels": "Channels",
"channels": "Kanali",
"streams": "Streams"
},
"mylar": {
@@ -808,10 +811,10 @@
"series": "Serije"
},
"booklore": {
"libraries": "Libraries",
"books": "Books",
"reading": "Reading",
"finished": "Finished"
"libraries": "Knjižnice",
"books": "Knjige",
"reading": "Čitanje",
"finished": "Završeno"
},
"jdownloader": {
"downloadCount": "Red čekanja",
@@ -1152,24 +1155,30 @@
"artists": "Izvođači"
},
"arcane": {
"containers": "Containers",
"images": "Images",
"image_updates": "Image Updates",
"images_unused": "Unused",
"environment_required": "Environment ID Required"
"containers": "Kontejneri",
"images": "Slike",
"image_updates": "Aktualizirane slike",
"images_unused": "Nekorišteno",
"environment_required": "ID okruženja se mora navesti"
},
"dockhand": {
"running": "Running",
"stopped": "Stopped",
"running": "Pokreće se",
"stopped": "Zaustavljeno",
"cpu": "CPU",
"memory": "Memory",
"images": "Images",
"volumes": "Volumes",
"events_today": "Events Today",
"pending_updates": "Pending Updates",
"memory": "Memorija",
"images": "Slike",
"volumes": "Jedinice memorije",
"events_today": "Događanja danas",
"pending_updates": "Aktualiziranja na čekanju",
"stacks": "Stacks",
"paused": "Paused",
"total": "Total",
"environment_not_found": "Environment Not Found"
"paused": "Pauzirano",
"total": "Ukupno",
"environment_not_found": "Okruženje nije pronađeno"
},
"sparkyfitness": {
"eaten": "Pojedeno",
"burned": "Potrošeno",
"remaining": "Preostalo",
"steps": "Koraci"
}
}

View File

@@ -184,6 +184,13 @@
"no_active": "Nincs aktív lejátszás",
"plex_connection_error": "Plex kapcsolat ellenőrzése"
},
"tracearr": {
"no_active": "No Active Streams",
"streams": "Streams",
"transcodes": "Transcodes",
"directplay": "Direct Play",
"bitrate": "Bitrate"
},
"omada": {
"connectedAp": "Csatlakoztatott AP-k",
"activeUser": "Aktív eszközök",
@@ -282,17 +289,13 @@
"approved": "Engedélyezett",
"available": "Elérhető"
},
"jellyseerr": {
"pending": "Függőben lévő",
"approved": "Jóváhagyott",
"available": "Elérhető",
"issues": "Nyitott problémák"
},
"overseerr": {
"pending": "Függőben lévő",
"processing": "Feldolgozás",
"approved": "Jóváhagyott",
"available": "Elérhető"
"seerr": {
"pending": "Pending",
"approved": "Approved",
"available": "Available",
"completed": "Completed",
"processing": "Processing",
"issues": "Open Issues"
},
"netalertx": {
"total": "Összes",
@@ -1171,5 +1174,11 @@
"paused": "Paused",
"total": "Total",
"environment_not_found": "Environment Not Found"
},
"sparkyfitness": {
"eaten": "Eaten",
"burned": "Burned",
"remaining": "Remaining",
"steps": "Steps"
}
}

View File

@@ -184,6 +184,13 @@
"no_active": "No Active Streams",
"plex_connection_error": "Cek Koneksi ke Plex"
},
"tracearr": {
"no_active": "No Active Streams",
"streams": "Streams",
"transcodes": "Transcodes",
"directplay": "Direct Play",
"bitrate": "Bitrate"
},
"omada": {
"connectedAp": "AP Tersambung",
"activeUser": "Perangakat yang Aktif",
@@ -282,18 +289,14 @@
"approved": "Tersetujui",
"available": "Tersedia"
},
"jellyseerr": {
"seerr": {
"pending": "Pending",
"approved": "Approved",
"available": "Available",
"completed": "Completed",
"processing": "Processing",
"issues": "Open Issues"
},
"overseerr": {
"pending": "Pending",
"processing": "Memproses",
"approved": "Approved",
"available": "Available"
},
"netalertx": {
"total": "Total",
"connected": "Connected",
@@ -1171,5 +1174,11 @@
"paused": "Paused",
"total": "Total",
"environment_not_found": "Environment Not Found"
},
"sparkyfitness": {
"eaten": "Eaten",
"burned": "Burned",
"remaining": "Remaining",
"steps": "Steps"
}
}

View File

@@ -113,7 +113,7 @@
"bitrate": "Bitrate",
"no_active": "No Active Streams",
"movies": "Movies",
"series": "Series",
"series": "Serie",
"episodes": "Episodes",
"songs": "Songs"
},
@@ -184,6 +184,13 @@
"no_active": "No Active Streams",
"plex_connection_error": "Controllare la connessione a Plex"
},
"tracearr": {
"no_active": "No Active Streams",
"streams": "Streams",
"transcodes": "Transcodes",
"directplay": "Direct Play",
"bitrate": "Bitrate"
},
"omada": {
"connectedAp": "AP Connessi",
"activeUser": "Dispositivi attivi",
@@ -282,18 +289,14 @@
"approved": "Approvati",
"available": "Disponibili"
},
"jellyseerr": {
"seerr": {
"pending": "Pending",
"approved": "Approved",
"available": "Available",
"completed": "Completed",
"processing": "Processing",
"issues": "Open Issues"
},
"overseerr": {
"pending": "Pending",
"processing": "In lavorazione",
"approved": "Approved",
"available": "Available"
},
"netalertx": {
"total": "Total",
"connected": "Connected",
@@ -318,7 +321,7 @@
"ping": "Ping"
},
"portainer": {
"running": "Running",
"running": "In esecuzione",
"stopped": "Fermati",
"total": "Total"
},
@@ -713,7 +716,7 @@
"diskstation": {
"days": "Days",
"uptime": "Uptime",
"volumeAvailable": "Available"
"volumeAvailable": "Disponibili"
},
"dispatcharr": {
"channels": "Channels",
@@ -1084,9 +1087,9 @@
"sharedFiles": "Files"
},
"jellystat": {
"songs": "Songs",
"movies": "Movies",
"episodes": "Episodes",
"songs": "Brani",
"movies": "Film",
"episodes": "Episodi",
"other": "Altro"
},
"checkmk": {
@@ -1110,11 +1113,11 @@
"total": "Total"
},
"wallos": {
"activeSubscriptions": "Subscriptions",
"thisMonthlyCost": "This Month",
"nextMonthlyCost": "Next Month",
"activeSubscriptions": "Abbonamenti",
"thisMonthlyCost": "Questo Mese",
"nextMonthlyCost": "Mese Prossimo",
"previousMonthlyCost": "Prev. Month",
"nextRenewingSubscription": "Next Payment"
"nextRenewingSubscription": ""
},
"unraid": {
"STARTED": "Started",
@@ -1171,5 +1174,11 @@
"paused": "Paused",
"total": "Total",
"environment_not_found": "Environment Not Found"
},
"sparkyfitness": {
"eaten": "Eaten",
"burned": "Burned",
"remaining": "Remaining",
"steps": "Steps"
}
}

View File

@@ -184,6 +184,13 @@
"no_active": "No Active Streams",
"plex_connection_error": "Plex接続の確認"
},
"tracearr": {
"no_active": "No Active Streams",
"streams": "Streams",
"transcodes": "Transcodes",
"directplay": "Direct Play",
"bitrate": "Bitrate"
},
"omada": {
"connectedAp": "接続されたAP",
"activeUser": "アクティブデバイス",
@@ -282,18 +289,14 @@
"approved": "承認済",
"available": "利用可"
},
"jellyseerr": {
"seerr": {
"pending": "Pending",
"approved": "Approved",
"available": "Available",
"completed": "Completed",
"processing": "Processing",
"issues": "Open Issues"
},
"overseerr": {
"pending": "Pending",
"processing": "処理中",
"approved": "Approved",
"available": "Available"
},
"netalertx": {
"total": "Total",
"connected": "Connected",
@@ -1171,5 +1174,11 @@
"paused": "Paused",
"total": "Total",
"environment_not_found": "Environment Not Found"
},
"sparkyfitness": {
"eaten": "Eaten",
"burned": "Burned",
"remaining": "Remaining",
"steps": "Steps"
}
}

View File

@@ -184,6 +184,13 @@
"no_active": "활성 스트림 없음",
"plex_connection_error": "Plex 연결 확인"
},
"tracearr": {
"no_active": "No Active Streams",
"streams": "Streams",
"transcodes": "Transcodes",
"directplay": "Direct Play",
"bitrate": "Bitrate"
},
"omada": {
"connectedAp": "연결된 AP",
"activeUser": "활성 장치",
@@ -282,17 +289,13 @@
"approved": "승인됨",
"available": "이용 가능"
},
"jellyseerr": {
"pending": "대기 중",
"approved": "승인됨",
"available": "이용 가능",
"issues": "열린 이슈"
},
"overseerr": {
"pending": "대기 중",
"processing": "처리 중",
"approved": "승인됨",
"available": "이용 가능"
"seerr": {
"pending": "Pending",
"approved": "Approved",
"available": "Available",
"completed": "Completed",
"processing": "Processing",
"issues": "Open Issues"
},
"netalertx": {
"total": "전체",
@@ -1171,5 +1174,11 @@
"paused": "Paused",
"total": "Total",
"environment_not_found": "Environment Not Found"
},
"sparkyfitness": {
"eaten": "Eaten",
"burned": "Burned",
"remaining": "Remaining",
"steps": "Steps"
}
}

View File

@@ -184,6 +184,13 @@
"no_active": "No Active Streams",
"plex_connection_error": "Check Plex Connection"
},
"tracearr": {
"no_active": "No Active Streams",
"streams": "Streams",
"transcodes": "Transcodes",
"directplay": "Direct Play",
"bitrate": "Bitrate"
},
"omada": {
"connectedAp": "Savienotie piekļuves punkti",
"activeUser": "Aktīvās ierīces",
@@ -282,17 +289,13 @@
"approved": "Approved",
"available": "Available"
},
"jellyseerr": {
"seerr": {
"pending": "Pending",
"approved": "Approved",
"available": "Available",
"issues": "Open Issues"
},
"overseerr": {
"pending": "Pending",
"completed": "Completed",
"processing": "Processing",
"approved": "Approved",
"available": "Available"
"issues": "Open Issues"
},
"netalertx": {
"total": "Total",
@@ -1171,5 +1174,11 @@
"paused": "Paused",
"total": "Total",
"environment_not_found": "Environment Not Found"
},
"sparkyfitness": {
"eaten": "Eaten",
"burned": "Burned",
"remaining": "Remaining",
"steps": "Steps"
}
}

View File

@@ -184,6 +184,13 @@
"no_active": "No Active Streams",
"plex_connection_error": "Check Plex Connection"
},
"tracearr": {
"no_active": "No Active Streams",
"streams": "Streams",
"transcodes": "Transcodes",
"directplay": "Direct Play",
"bitrate": "Bitrate"
},
"omada": {
"connectedAp": "Connected APs",
"activeUser": "Peranti aktif",
@@ -282,17 +289,13 @@
"approved": "Lulus",
"available": "Sudah Ada"
},
"jellyseerr": {
"seerr": {
"pending": "Pending",
"approved": "Approved",
"available": "Available",
"issues": "Open Issues"
},
"overseerr": {
"pending": "Pending",
"completed": "Completed",
"processing": "Processing",
"approved": "Approved",
"available": "Available"
"issues": "Open Issues"
},
"netalertx": {
"total": "Total",
@@ -1171,5 +1174,11 @@
"paused": "Paused",
"total": "Total",
"environment_not_found": "Environment Not Found"
},
"sparkyfitness": {
"eaten": "Eaten",
"burned": "Burned",
"remaining": "Remaining",
"steps": "Steps"
}
}

View File

@@ -184,6 +184,13 @@
"no_active": "Geen Actieve Streams",
"plex_connection_error": "Controleer Plex Connectie"
},
"tracearr": {
"no_active": "No Active Streams",
"streams": "Streams",
"transcodes": "Transcodes",
"directplay": "Direct Play",
"bitrate": "Bitrate"
},
"omada": {
"connectedAp": "Verbonden APs",
"activeUser": "Actieve apparaten",
@@ -282,18 +289,14 @@
"approved": "Goedgekeurd",
"available": "Beschikbaar"
},
"jellyseerr": {
"pending": "In afwachting",
"approved": "Goedgekeurd",
"available": "Beschikbaar",
"seerr": {
"pending": "Pending",
"approved": "Approved",
"available": "Available",
"completed": "Completed",
"processing": "Processing",
"issues": "Open Issues"
},
"overseerr": {
"pending": "In afwachting",
"processing": "Verwerken",
"approved": "Goedgekeurd",
"available": "Beschikbaar"
},
"netalertx": {
"total": "Totaal",
"connected": "Verbonden",
@@ -1171,5 +1174,11 @@
"paused": "Paused",
"total": "Total",
"environment_not_found": "Environment Not Found"
},
"sparkyfitness": {
"eaten": "Eaten",
"burned": "Burned",
"remaining": "Remaining",
"steps": "Steps"
}
}

View File

@@ -184,6 +184,13 @@
"no_active": "No Active Streams",
"plex_connection_error": "Kontroller Plex tilkoblingen"
},
"tracearr": {
"no_active": "No Active Streams",
"streams": "Streams",
"transcodes": "Transcodes",
"directplay": "Direct Play",
"bitrate": "Bitrate"
},
"omada": {
"connectedAp": "Tilkoblede AP'er",
"activeUser": "Aktive enheter",
@@ -282,18 +289,14 @@
"approved": "Godkjent",
"available": "Tilgjengelig"
},
"jellyseerr": {
"seerr": {
"pending": "Pending",
"approved": "Approved",
"available": "Available",
"completed": "Completed",
"processing": "Processing",
"issues": "Open Issues"
},
"overseerr": {
"pending": "Pending",
"processing": "Behandler",
"approved": "Approved",
"available": "Available"
},
"netalertx": {
"total": "Total",
"connected": "Connected",
@@ -1171,5 +1174,11 @@
"paused": "Paused",
"total": "Total",
"environment_not_found": "Environment Not Found"
},
"sparkyfitness": {
"eaten": "Eaten",
"burned": "Burned",
"remaining": "Remaining",
"steps": "Steps"
}
}

View File

@@ -108,14 +108,14 @@
"songs": "Piosenki"
},
"jellyfin": {
"playing": "Playing",
"transcoding": "Transcoding",
"playing": "Odtwarza",
"transcoding": "Transkoduje",
"bitrate": "Bitrate",
"no_active": "No Active Streams",
"movies": "Movies",
"series": "Series",
"episodes": "Episodes",
"songs": "Songs"
"no_active": "Brak aktywnych strumieni",
"movies": "Filmy",
"series": "Seriale",
"episodes": "Odcinki",
"songs": "Piosenki"
},
"esphome": {
"offline": "Offline",
@@ -184,6 +184,13 @@
"no_active": "Brak aktywnych strumieni",
"plex_connection_error": "Sprawdź połączenie z Plex"
},
"tracearr": {
"no_active": "Brak aktywnych strumieni",
"streams": "Strumienie",
"transcodes": "Transkodowania",
"directplay": "Odtwarzanie bezpośrednie",
"bitrate": "Bitrate"
},
"omada": {
"connectedAp": "Połączone punkty dostępowe",
"activeUser": "Aktywne urządzenia",
@@ -282,17 +289,13 @@
"approved": "Zaakceptowane",
"available": "Dostępne"
},
"jellyseerr": {
"seerr": {
"pending": "Oczekujące",
"approved": "Zaakceptowane",
"available": "Dostępne",
"issues": "Otwarte zgłoszenia"
},
"overseerr": {
"pending": "Oczekujące",
"completed": "Ukończone",
"processing": "Przetwarzane",
"approved": "Zaakceptowane",
"available": "Dostępne"
"issues": "Otwarte zgłoszenia"
},
"netalertx": {
"total": "Razem",
@@ -716,8 +719,8 @@
"volumeAvailable": "Dostępne"
},
"dispatcharr": {
"channels": "Channels",
"streams": "Streams"
"channels": "Kanały",
"streams": "Strumienie"
},
"mylar": {
"series": "Seriale",
@@ -1152,11 +1155,11 @@
"artists": "Wykonawcy"
},
"arcane": {
"containers": "Containers",
"images": "Images",
"image_updates": "Image Updates",
"images_unused": "Unused",
"environment_required": "Environment ID Required"
"containers": "Kontenery",
"images": "Obrazy",
"image_updates": "Aktualizacje obrazów",
"images_unused": "Nieużywane",
"environment_required": "Wymagane ID środowiska"
},
"dockhand": {
"running": "Działające",
@@ -1171,5 +1174,11 @@
"paused": "Wstrzymane",
"total": "Razem",
"environment_not_found": "Środowisko nie znalezione"
},
"sparkyfitness": {
"eaten": "Zjedzone",
"burned": "Spalone",
"remaining": "Pozostało",
"steps": "Kroki"
}
}

View File

@@ -184,6 +184,13 @@
"no_active": "No Active Streams",
"plex_connection_error": "Verifique a conexão do Plex"
},
"tracearr": {
"no_active": "No Active Streams",
"streams": "Streams",
"transcodes": "Transcodes",
"directplay": "Direct Play",
"bitrate": "Bitrate"
},
"omada": {
"connectedAp": "APs Ligados",
"activeUser": "Dispositivos activos",
@@ -282,18 +289,14 @@
"approved": "Aprovado",
"available": "Disponível"
},
"jellyseerr": {
"seerr": {
"pending": "Pending",
"approved": "Approved",
"available": "Available",
"completed": "Completed",
"processing": "Processing",
"issues": "Open Issues"
},
"overseerr": {
"pending": "Pending",
"processing": "A Processar",
"approved": "Approved",
"available": "Available"
},
"netalertx": {
"total": "Total",
"connected": "Connected",
@@ -1171,5 +1174,11 @@
"paused": "Paused",
"total": "Total",
"environment_not_found": "Environment Not Found"
},
"sparkyfitness": {
"eaten": "Eaten",
"burned": "Burned",
"remaining": "Remaining",
"steps": "Steps"
}
}

View File

@@ -184,6 +184,13 @@
"no_active": "Sem Streams Ativos",
"plex_connection_error": "Verifique a conexão do Plex"
},
"tracearr": {
"no_active": "No Active Streams",
"streams": "Streams",
"transcodes": "Transcodes",
"directplay": "Direct Play",
"bitrate": "Bitrate"
},
"omada": {
"connectedAp": "APs Ligados",
"activeUser": "Dispositivos ativos",
@@ -282,17 +289,13 @@
"approved": "Aprovada",
"available": "Disponível"
},
"jellyseerr": {
"pending": "Pendente",
"approved": "Aprovado",
"available": "Disponível",
"issues": "Incidentes Abertos"
},
"overseerr": {
"pending": "Pendente",
"processing": "Processando",
"approved": "Aprovado",
"available": "Disponível"
"seerr": {
"pending": "Pending",
"approved": "Approved",
"available": "Available",
"completed": "Completed",
"processing": "Processing",
"issues": "Open Issues"
},
"netalertx": {
"total": "Total",
@@ -1171,5 +1174,11 @@
"paused": "Paused",
"total": "Total",
"environment_not_found": "Environment Not Found"
},
"sparkyfitness": {
"eaten": "Eaten",
"burned": "Burned",
"remaining": "Remaining",
"steps": "Steps"
}
}

View File

@@ -184,6 +184,13 @@
"no_active": "No Active Streams",
"plex_connection_error": "Check Plex Connection"
},
"tracearr": {
"no_active": "No Active Streams",
"streams": "Streams",
"transcodes": "Transcodes",
"directplay": "Direct Play",
"bitrate": "Bitrate"
},
"omada": {
"connectedAp": "Connected APs",
"activeUser": "Dispozitive active",
@@ -282,18 +289,14 @@
"approved": "Aprobate",
"available": "Disponibile"
},
"jellyseerr": {
"seerr": {
"pending": "Pending",
"approved": "Approved",
"available": "Available",
"completed": "Completed",
"processing": "Processing",
"issues": "Open Issues"
},
"overseerr": {
"pending": "Pending",
"processing": "Procesare",
"approved": "Approved",
"available": "Available"
},
"netalertx": {
"total": "Total",
"connected": "Connected",
@@ -1171,5 +1174,11 @@
"paused": "Paused",
"total": "Total",
"environment_not_found": "Environment Not Found"
},
"sparkyfitness": {
"eaten": "Eaten",
"burned": "Burned",
"remaining": "Remaining",
"steps": "Steps"
}
}

View File

@@ -108,14 +108,14 @@
"songs": "Песни"
},
"jellyfin": {
"playing": "Playing",
"transcoding": "Transcoding",
"bitrate": "Bitrate",
"no_active": "No Active Streams",
"movies": "Movies",
"series": "Series",
"episodes": "Episodes",
"songs": "Songs"
"playing": "Воспроизводится",
"transcoding": "Перекодирование",
"bitrate": "Битрейт",
"no_active": "Нет активных потоков",
"movies": "Фильмы",
"series": "Сериалы",
"episodes": "Эпизоды",
"songs": "Песни"
},
"esphome": {
"offline": "Не в сети",
@@ -184,6 +184,13 @@
"no_active": "Нет активных стримов",
"plex_connection_error": "Проверка соединения Plex"
},
"tracearr": {
"no_active": "Нет активных потоков",
"streams": "Потоки",
"transcodes": "Transcodes",
"directplay": "Прямое воспроизведение",
"bitrate": "Битрейт"
},
"omada": {
"connectedAp": "Подключенные точки доступа",
"activeUser": "Активные устройства",
@@ -282,17 +289,13 @@
"approved": "Одобрено",
"available": "Доступно"
},
"jellyseerr": {
"pending": "Ожидают",
"seerr": {
"pending": "Pending",
"approved": "Одобрено",
"available": "Доступно",
"issues": "Open Issues"
},
"overseerr": {
"pending": "Ожидают",
"processing": "В процессе",
"approved": "Одобрено",
"available": "Доступно"
"completed": "Завершено",
"processing": "Обработка",
"issues": "Открытые задачи"
},
"netalertx": {
"total": "Всего",
@@ -1130,8 +1133,8 @@
"NO_DATA_DISKS": "No Data Disks",
"notifications": "Уведомления",
"status": "Статус",
"cpu": "CPU",
"memoryUsed": "Memory Used",
"cpu": "ЦП",
"memoryUsed": "Использовано ОЗУ",
"memoryAvailable": "Memory Available",
"arrayUsed": "Array Used",
"arrayFree": "Array Free",
@@ -1141,14 +1144,14 @@
"backrest": {
"num_plans": "Plans",
"num_success_30": "Successes",
"num_failure_30": "Failures",
"num_failure_30": "Ошибки",
"num_success_latest": "Succeeding",
"num_failure_latest": "Failing",
"bytes_added_30": "Bytes Added"
},
"yourspotify": {
"songs": "Songs",
"time": "Time",
"time": "Время",
"artists": "Artists"
},
"arcane": {
@@ -1170,6 +1173,12 @@
"stacks": "Stacks",
"paused": "Paused",
"total": "Total",
"environment_not_found": "Environment Not Found"
"environment_not_found": "Среда не найдена"
},
"sparkyfitness": {
"eaten": "Eaten",
"burned": "Burned",
"remaining": "Remaining",
"steps": "Steps"
}
}

View File

@@ -93,7 +93,7 @@
"http_status": "HTTP stavový kód",
"error": "Chyba",
"response": "Odpoveď",
"down": "Down",
"down": "Nedostupné",
"up": "Beží",
"not_available": "Nedostupné"
},
@@ -108,18 +108,18 @@
"songs": "Skladby"
},
"jellyfin": {
"playing": "Playing",
"transcoding": "Transcoding",
"bitrate": "Bitrate",
"no_active": "No Active Streams",
"movies": "Movies",
"series": "Series",
"episodes": "Episodes",
"songs": "Songs"
"playing": "Prehráva sa",
"transcoding": "Prebieha prekódovanie",
"bitrate": "Prenosová rýchlosť",
"no_active": "Žiadne aktívne vysielania",
"movies": "Filmov",
"series": "Seriálov",
"episodes": "Epizód",
"songs": "Skladieb"
},
"esphome": {
"offline": "Offline",
"offline_alt": "Offline",
"offline": "Nedostupné",
"offline_alt": "Nedostupné",
"online": "Online",
"total": "Celkom",
"unknown": "Neznáme"
@@ -154,7 +154,7 @@
"uptime": "Dostupnosť",
"maxDown": "Max. sťahovanie",
"maxUp": "Max. nahrávanie",
"down": "Down",
"down": "Nedostupné",
"up": "Beží",
"received": "Prijaté",
"sent": "Odoslané",
@@ -178,12 +178,19 @@
"passes": "Odvysielané"
},
"tautulli": {
"playing": "Playing",
"playing": "Prehráva sa",
"transcoding": "Transcoding",
"bitrate": "Bitrate",
"bitrate": "Prenosová rýchlosť",
"no_active": "No Active Streams",
"plex_connection_error": "Skontroluj spojenie s Plex"
},
"tracearr": {
"no_active": "No Active Streams",
"streams": "Streams",
"transcodes": "Transcodes",
"directplay": "Direct Play",
"bitrate": "Prenosová rýchlosť"
},
"omada": {
"connectedAp": "Pripojené prístupové body",
"activeUser": "Aktívne zariadenia",
@@ -282,18 +289,14 @@
"approved": "Schválené",
"available": "Dostupné"
},
"jellyseerr": {
"pending": "Čakajúce",
"approved": "Schválené",
"available": "Dostupné",
"seerr": {
"pending": "Pending",
"approved": "Approved",
"available": "Available",
"completed": "Completed",
"processing": "Processing",
"issues": "Open Issues"
},
"overseerr": {
"pending": "Čakajúce",
"processing": "Spracovávané",
"approved": "Schválené",
"available": "Dostupné"
},
"netalertx": {
"total": "Celkom",
"connected": "Pripojené",
@@ -429,7 +432,7 @@
"version": "Verzia",
"status": "Stav",
"up": "Online",
"down": "Offline"
"down": "Nedostupné"
},
"miniflux": {
"read": "Prečítané",
@@ -450,7 +453,7 @@
"cpu": "CPU",
"load": "Záťaž",
"wait": "Čakajte, prosím",
"temp": "TEMP",
"temp": "TEPL",
"_temp": "Teplota",
"warn": "Upozornení",
"uptime": "BEŽÍ",
@@ -491,13 +494,13 @@
"51-day": "Mierne mrholenie",
"51-night": "Slabé mrholenie",
"53-day": "Mrholenie",
"53-night": "Drizzle",
"53-night": "Mrholenie",
"55-day": "Silné mrholenie",
"55-night": "Silné mrholenie",
"56-day": "Mierne mrazivé mrholenie",
"56-night": "Light Freezing Drizzle",
"56-night": "Jemné mrznúce mrholenie",
"57-day": "Mrazivé mrholenie",
"57-night": "Freezing Drizzle",
"57-night": "Mrznúce mrholenie",
"61-day": "Slabý dážď",
"61-night": "Slabý dážď",
"63-day": "Dážď",
@@ -542,14 +545,14 @@
"child_bridges_status": "{{ok}}/{{total}}",
"up": "Beží",
"pending": "Čakajúce",
"down": "Down",
"down": "Nedostupné",
"ok": "Ok"
},
"healthchecks": {
"new": "Nový",
"up": "Beží",
"grace": "V dodatočnej lehote",
"down": "Down",
"down": "Nedostupné",
"paused": "Pozastavené",
"status": "Stav",
"last_ping": "Poslendný ping",
@@ -675,7 +678,7 @@
"memory": "Využitie pamäte",
"wanStatus": "Stav WAN",
"up": "Beží",
"down": "Down",
"down": "Nedostupné",
"temp": "Temp",
"disk": "Využitie disku",
"wanIP": "IP adresa WAN"
@@ -776,8 +779,8 @@
"targets_total": "Cieľov spolu"
},
"gatus": {
"up": "Sites Up",
"down": "Sites Down",
"up": "Dostupné stránky",
"down": "Nedostupné stránky",
"uptime": "Dostupnosť"
},
"ghostfolio": {
@@ -799,7 +802,7 @@
},
"whatsupdocker": {
"monitoring": "Monitoring",
"updates": "Updates"
"updates": "Aktualizácie"
},
"calibreweb": {
"books": "Books",
@@ -872,7 +875,7 @@
"uptime": "Dostupnosť",
"cpuLoad": "Záťaž CPU priem. (5m)",
"up": "Beží",
"down": "Down",
"down": "Nedostupné",
"bytesTx": "Prenesených",
"bytesRx": "Prijaté"
},
@@ -881,13 +884,13 @@
"uptime": "Dostupnosť",
"lastDown": "Posledný čas nedostupnosti",
"downDuration": "Trvanie nedostupnosti",
"sitesUp": "Sites Up",
"sitesDown": "Sites Down",
"sitesUp": "Dostupné stránky",
"sitesDown": "Nedostupné stránky",
"paused": "Pozastavené",
"notyetchecked": "Neskontrolované",
"up": "Beží",
"seemsdown": "Javí sa nedostupný",
"down": "Down",
"down": "Nedostupné",
"unknown": "Neznáme"
},
"calendar": {
@@ -1023,17 +1026,17 @@
"last_seen": "Last Seen",
"status": "Stav",
"online": "Online",
"offline": "Offline"
"offline": "Nedostupné"
},
"beszel": {
"name": "Name",
"systems": "Systems",
"up": "Beží",
"down": "Down",
"down": "Nedostupné",
"paused": "Pozastavené",
"pending": "Čakajúce",
"status": "Stav",
"updated": "Updated",
"updated": "Aktualizované",
"cpu": "CPU",
"memory": "RAM",
"disk": "Disk",
@@ -1078,7 +1081,7 @@
"disconnected": "Odpojené",
"updateStatus": "Update",
"update_yes": "Dostupné",
"update_no": "Up to Date",
"update_no": "Aktuálne",
"downloads": "Downloads",
"uploads": "Uploads",
"sharedFiles": "Files"
@@ -1097,7 +1100,7 @@
"total": "Celkom",
"running": "Beží",
"stopped": "Zastavené",
"down": "Down",
"down": "Nedostupné",
"unhealthy": "Nezdravý",
"unknown": "Neznáme",
"servers": "Servery",
@@ -1171,5 +1174,11 @@
"paused": "Paused",
"total": "Total",
"environment_not_found": "Environment Not Found"
},
"sparkyfitness": {
"eaten": "Eaten",
"burned": "Burned",
"remaining": "Remaining",
"steps": "Steps"
}
}

View File

@@ -184,6 +184,13 @@
"no_active": "No Active Streams",
"plex_connection_error": "Preveri Plex povezavo"
},
"tracearr": {
"no_active": "No Active Streams",
"streams": "Streams",
"transcodes": "Transcodes",
"directplay": "Direct Play",
"bitrate": "Bitrate"
},
"omada": {
"connectedAp": "Povezanih AP",
"activeUser": "Aktivne naprave",
@@ -282,18 +289,14 @@
"approved": "Odobreno",
"available": "Na voljo"
},
"jellyseerr": {
"seerr": {
"pending": "Pending",
"approved": "Approved",
"available": "Available",
"completed": "Completed",
"processing": "Processing",
"issues": "Open Issues"
},
"overseerr": {
"pending": "Pending",
"processing": "Procesiram",
"approved": "Approved",
"available": "Available"
},
"netalertx": {
"total": "Total",
"connected": "Connected",
@@ -1171,5 +1174,11 @@
"paused": "Paused",
"total": "Total",
"environment_not_found": "Environment Not Found"
},
"sparkyfitness": {
"eaten": "Eaten",
"burned": "Burned",
"remaining": "Remaining",
"steps": "Steps"
}
}

View File

@@ -108,14 +108,14 @@
"songs": "Песме"
},
"jellyfin": {
"playing": "Playing",
"transcoding": "Transcoding",
"bitrate": "Bitrate",
"no_active": "No Active Streams",
"movies": "Movies",
"series": "Series",
"episodes": "Episodes",
"songs": "Songs"
"playing": "Репродукција",
"transcoding": "Транскодирање",
"bitrate": "Проток",
"no_active": "Нема активних стримова",
"movies": "Филмови",
"series": "Серије",
"episodes": "Епизоде",
"songs": "Песме"
},
"esphome": {
"offline": "Није на мрежи",
@@ -184,6 +184,13 @@
"no_active": "Нема активних стримова",
"plex_connection_error": "Провери везу са Plex-ом"
},
"tracearr": {
"no_active": "Нема активних стримова",
"streams": "Стримови",
"transcodes": "Транскодирање",
"directplay": "Директно репродуковање",
"bitrate": "Проток"
},
"omada": {
"connectedAp": "Повезани АПи",
"activeUser": "Активни уређаји",
@@ -282,17 +289,13 @@
"approved": "Одобрено",
"available": "Доступно"
},
"jellyseerr": {
"seerr": {
"pending": "На чекању",
"approved": "Одобрено",
"available": "Доступно",
"issues": "Отворених питања"
},
"overseerr": {
"pending": "На чекању",
"completed": "Завршено",
"processing": "Обрада",
"approved": "Одобрено",
"available": "Доступно"
"issues": "Отворених питања"
},
"netalertx": {
"total": "Укупно",
@@ -543,7 +546,7 @@
"up": "Горе",
"pending": "На чекању",
"down": "Доле",
"ok": "Ok"
"ok": "Ок"
},
"healthchecks": {
"new": "Сада",
@@ -716,8 +719,8 @@
"volumeAvailable": "Доступно"
},
"dispatcharr": {
"channels": "Channels",
"streams": "Streams"
"channels": "Канали",
"streams": "Стримови"
},
"mylar": {
"series": "Серије",
@@ -808,10 +811,10 @@
"series": "Серије"
},
"booklore": {
"libraries": "Libraries",
"books": "Books",
"reading": "Reading",
"finished": "Finished"
"libraries": "Библиотеке",
"books": "Књиге",
"reading": "Читање",
"finished": "Завршено"
},
"jdownloader": {
"downloadCount": "Ред",
@@ -1152,24 +1155,30 @@
"artists": "Извођачи"
},
"arcane": {
"containers": "Containers",
"images": "Images",
"image_updates": "Image Updates",
"images_unused": "Unused",
"environment_required": "Environment ID Required"
"containers": "Контејнера",
"images": "Слике",
"image_updates": "Ажурирања слика",
"images_unused": "Неискоришћено",
"environment_required": "ИД окружења је обавезан"
},
"dockhand": {
"running": "Running",
"stopped": "Stopped",
"cpu": "CPU",
"memory": "Memory",
"images": "Images",
"volumes": "Volumes",
"events_today": "Events Today",
"pending_updates": "Pending Updates",
"stacks": "Stacks",
"paused": "Paused",
"total": "Total",
"environment_not_found": "Environment Not Found"
"running": "Покренуто",
"stopped": "Заустављено",
"cpu": "Процесор",
"memory": "Меморија",
"images": "Слике",
"volumes": "Јачине звука",
"events_today": "Данашњи догађаји",
"pending_updates": "Ажурирања на чекању",
"stacks": "Стекови",
"paused": "Паузирано",
"total": "Укупно",
"environment_not_found": "Окружење није пронађено"
},
"sparkyfitness": {
"eaten": "Eaten",
"burned": "Burned",
"remaining": "Remaining",
"steps": "Steps"
}
}

View File

@@ -184,6 +184,13 @@
"no_active": "No Active Streams",
"plex_connection_error": "Check Plex Connection"
},
"tracearr": {
"no_active": "No Active Streams",
"streams": "Streams",
"transcodes": "Transcodes",
"directplay": "Direct Play",
"bitrate": "Bitrate"
},
"omada": {
"connectedAp": "Connected APs",
"activeUser": "Active devices",
@@ -282,17 +289,13 @@
"approved": "Godkända",
"available": "Tillgänglig"
},
"jellyseerr": {
"seerr": {
"pending": "Pending",
"approved": "Approved",
"available": "Available",
"issues": "Open Issues"
},
"overseerr": {
"pending": "Pending",
"completed": "Completed",
"processing": "Processing",
"approved": "Approved",
"available": "Available"
"issues": "Open Issues"
},
"netalertx": {
"total": "Total",
@@ -1171,5 +1174,11 @@
"paused": "Paused",
"total": "Total",
"environment_not_found": "Environment Not Found"
},
"sparkyfitness": {
"eaten": "Eaten",
"burned": "Burned",
"remaining": "Remaining",
"steps": "Steps"
}
}

View File

@@ -184,6 +184,13 @@
"no_active": "No Active Streams",
"plex_connection_error": "Check Plex Connection"
},
"tracearr": {
"no_active": "No Active Streams",
"streams": "Streams",
"transcodes": "Transcodes",
"directplay": "Direct Play",
"bitrate": "Bitrate"
},
"omada": {
"connectedAp": "Connected APs",
"activeUser": "Active devices",
@@ -282,17 +289,13 @@
"approved": "ఆమోదించబడింది",
"available": "అందుబాటులో వున్నవి"
},
"jellyseerr": {
"seerr": {
"pending": "Pending",
"approved": "Approved",
"available": "Available",
"issues": "Open Issues"
},
"overseerr": {
"pending": "Pending",
"completed": "Completed",
"processing": "Processing",
"approved": "Approved",
"available": "Available"
"issues": "Open Issues"
},
"netalertx": {
"total": "Total",
@@ -1171,5 +1174,11 @@
"paused": "Paused",
"total": "Total",
"environment_not_found": "Environment Not Found"
},
"sparkyfitness": {
"eaten": "Eaten",
"burned": "Burned",
"remaining": "Remaining",
"steps": "Steps"
}
}

View File

@@ -184,6 +184,13 @@
"no_active": "No Active Streams",
"plex_connection_error": "Check Plex Connection"
},
"tracearr": {
"no_active": "No Active Streams",
"streams": "Streams",
"transcodes": "Transcodes",
"directplay": "Direct Play",
"bitrate": "Bitrate"
},
"omada": {
"connectedAp": "Connected APs",
"activeUser": "Active devices",
@@ -282,17 +289,13 @@
"approved": "Approved",
"available": "Available"
},
"jellyseerr": {
"seerr": {
"pending": "Pending",
"approved": "Approved",
"available": "Available",
"issues": "Open Issues"
},
"overseerr": {
"pending": "Pending",
"completed": "Completed",
"processing": "Processing",
"approved": "Approved",
"available": "Available"
"issues": "Open Issues"
},
"netalertx": {
"total": "Total",
@@ -1171,5 +1174,11 @@
"paused": "Paused",
"total": "Total",
"environment_not_found": "Environment Not Found"
},
"sparkyfitness": {
"eaten": "Eaten",
"burned": "Burned",
"remaining": "Remaining",
"steps": "Steps"
}
}

View File

@@ -40,7 +40,7 @@
},
"resources": {
"cpu": "İşlemci",
"mem": "MEM",
"mem": "Bellek",
"total": "Toplam",
"free": "Boş",
"used": "Kullanımda",
@@ -80,7 +80,7 @@
"unhealthy": "Sağlıksız",
"not_found": "Bulunamadı",
"exited": "Kapandı",
"partial": "Parçalı"
"partial": "Kısmi"
},
"ping": {
"error": "Hata",
@@ -93,29 +93,29 @@
"http_status": "HTTPS durumu",
"error": "Hata",
"response": "Yanıt",
"down": "Çalışmayan",
"down": "İndirme",
"up": "Çalışıyor",
"not_available": "Uygun değil"
},
"emby": {
"playing": "Oynatılıyor",
"transcoding": "Dönüştürülüyor",
"bitrate": "Bit Oranı",
"bitrate": "Bit Hızı",
"no_active": "Etkin akış yok",
"movies": "Filmler",
"series": "Diziler",
"episodes": "Bölümler",
"songs": "Şarkılar"
"movies": "Film",
"series": "Dizi",
"episodes": "Bölüm",
"songs": "Şarkı"
},
"jellyfin": {
"playing": "Playing",
"transcoding": "Transcoding",
"bitrate": "Bitrate",
"no_active": "No Active Streams",
"movies": "Movies",
"series": "Series",
"episodes": "Episodes",
"songs": "Songs"
"playing": "Oynatılıyor",
"transcoding": "Dönüştürülüyor",
"bitrate": "Bit Hızı",
"no_active": "Aktif Yayın Yok",
"movies": "Film",
"series": "Dizi",
"episodes": "Bölüm",
"songs": "Şarkı"
},
"esphome": {
"offline": "Çevrimdışı",
@@ -135,8 +135,8 @@
"flood": {
"download": "İndirme",
"upload": "Yükleme",
"leech": "Tüketici",
"seed": "Sağlayıcı"
"leech": "İndirilen",
"seed": "Gönderilen"
},
"freshrss": {
"subscriptions": "Abonelikler",
@@ -152,10 +152,10 @@
"connectionStatusDisconnected": "Bağlı değil",
"connectionStatusConnected": "Bağlı",
"uptime": "Çalışma Süresi",
"maxDown": "Max. Indirme",
"maxUp": "Max. Gönderme",
"down": "Çalışmayan",
"up": "Çalışıyor",
"maxDown": "Maks. İndirme",
"maxUp": "Maks. Gönderme",
"down": "İndirme",
"up": "Yükleme",
"received": "Alınan",
"sent": "Gönderilen",
"externalIPAddress": "Harici IP",
@@ -180,10 +180,17 @@
"tautulli": {
"playing": "Oynatılıyor",
"transcoding": "Dönüştürülüyor",
"bitrate": "Bit Oranı",
"bitrate": "Bit Hızı",
"no_active": "Etkin akış yok",
"plex_connection_error": "Plex Bağlantısı Kontrol Ediliyor"
},
"tracearr": {
"no_active": "No Active Streams",
"streams": "Streams",
"transcodes": "Transcodes",
"directplay": "Direct Play",
"bitrate": "Bitrate"
},
"omada": {
"connectedAp": "Bağlı AP'ler",
"activeUser": "Etkin aygıtlar",
@@ -199,7 +206,7 @@
"plex": {
"streams": "Etkin akış",
"albums": "Albümler",
"movies": "Filmler",
"movies": "Film",
"tv": "TV Showları"
},
"sabnzbd": {
@@ -209,20 +216,20 @@
},
"rutorrent": {
"active": "Etkin",
"upload": "Yükleme",
"upload": "Gönderme",
"download": "İndirme"
},
"transmission": {
"download": "İndirme",
"upload": "Yükleme",
"leech": "Tüketici",
"seed": "Sağlayıcı"
"upload": "Gönderme",
"leech": "İndirilen",
"seed": "Gönderilen"
},
"qbittorrent": {
"download": "İndirme",
"upload": "Yükleme",
"leech": "Tüketici",
"seed": "Sağlayıcı"
"upload": "Gönderme",
"leech": "İndirilen",
"seed": "Gönderilen"
},
"qnap": {
"cpuUsage": "İşlemci Kullanımı",
@@ -234,9 +241,9 @@
},
"deluge": {
"download": "İndirme",
"upload": "Yükleme",
"leech": "Leech",
"seed": "Seed"
"upload": "Gönderme",
"leech": "İndirilen",
"seed": "Gönderilen"
},
"develancacheui": {
"cachehitbytes": "Önbellek İsabetli Byte",
@@ -244,14 +251,14 @@
},
"downloadstation": {
"download": "İndirme",
"upload": "Yükleme",
"leech": "Tüketici",
"seed": "Sağlayıcı"
"upload": "Gönderme",
"leech": "İndirilen",
"seed": "Gönderilen"
},
"sonarr": {
"wanted": "İstendi",
"queued": "Kuyrukta",
"series": "Seriler",
"series": "Diziler",
"queue": "Kuyruk",
"unknown": "Bilinmeyen"
},
@@ -259,7 +266,7 @@
"wanted": "İstendi",
"missing": "Eksik",
"queued": "Kuyrukta",
"movies": "Filmler",
"movies": "Film",
"queue": "Kuyruk",
"unknown": "Bilinmeyen"
},
@@ -282,17 +289,13 @@
"approved": "Onaylı",
"available": "Kullanılabilir"
},
"jellyseerr": {
"pending": "Bekleyen",
"approved": "Onaylı",
"available": "Uygun",
"issues": "Open Issues"
},
"overseerr": {
"seerr": {
"pending": "Pending",
"processing": "İşleniyor",
"approved": "Onaylı",
"available": "Uygun"
"approved": "Approved",
"available": "Available",
"completed": "Completed",
"processing": "Processing",
"issues": "Open Issues"
},
"netalertx": {
"total": "Toplam",
@@ -307,7 +310,7 @@
"gravity": "Gravity"
},
"adguard": {
"queries": "Queries",
"queries": "Sorgular",
"blocked": "Engellenen",
"filtered": "Filtrelendi",
"latency": "Gecikme"
@@ -448,9 +451,9 @@
},
"glances": {
"cpu": "İşlemci",
"load": "Load",
"load": "Yük",
"wait": "Lütfen bekleyin",
"temp": "TEMP",
"temp": "Sıcaklık",
"_temp": "Sıcaklık",
"warn": "Uyarı",
"uptime": "ÇALIŞIYOR",
@@ -463,7 +466,7 @@
"read": "Okundu",
"write": "Yazma",
"gpu": "GPU",
"mem": "Hafıza",
"mem": "Bellek",
"swap": "Swap"
},
"quicklaunch": {
@@ -543,7 +546,7 @@
"up": "Çalışıyor",
"pending": "Bekleyen",
"down": "Çalışmayan",
"ok": "Ok"
"ok": "Tamam"
},
"healthchecks": {
"new": "Yeni",
@@ -598,7 +601,7 @@
"signalStrength": "Sağlamlık",
"signalQuality": "Kalite",
"symbolQuality": "Kalite",
"networkRate": "Bit Oranı",
"networkRate": "Bit Hızı",
"clientIP": "Alıcı"
},
"scrutiny": {
@@ -611,13 +614,13 @@
"total": "Toplam"
},
"pangolin": {
"orgs": "Orgs",
"sites": "Sites",
"resources": "Resources",
"targets": "Targets",
"traffic": "Traffic",
"in": "In",
"out": "Out"
"orgs": "Kuruluşlar",
"sites": "Siteler",
"resources": "Kaynaklar",
"targets": "Hedefler",
"traffic": "Trafik",
"in": "Gelen",
"out": "Giden"
},
"peanut": {
"battery_charge": "Pil Yüzdesi",
@@ -676,7 +679,7 @@
"wanStatus": "WAN Durumu",
"up": "Çalışıyor",
"down": "Çalışmayan",
"temp": "Temp",
"temp": "Sıcaklık",
"disk": "Disk Kullanımı",
"wanIP": "WAN IP"
},
@@ -697,7 +700,7 @@
"down": "Çalışmayan site",
"uptime": "Çalışma süresi",
"incident": "Olay",
"m": "m"
"m": "dk"
},
"atsumeru": {
"series": "Diziler",
@@ -716,8 +719,8 @@
"volumeAvailable": "Uygun"
},
"dispatcharr": {
"channels": "Channels",
"streams": "Streams"
"channels": "Kanallar",
"streams": "Akışlar"
},
"mylar": {
"series": "Diziler",
@@ -771,12 +774,12 @@
"nodes": "Düğümler"
},
"prometheus": {
"targets_up": "Hedef Çalışıyor",
"targets_up": "Çalışan Hedef",
"targets_down": "Çalışmayan hedef",
"targets_total": "Toplam Hedef"
},
"gatus": {
"up": "Sites Up",
"up": "Çalışan Siteler",
"down": "Çalışmayan site",
"uptime": "Çalışma süresi"
},
@@ -784,7 +787,7 @@
"gross_percent_today": "Bugün",
"gross_percent_1y": "Bir yıl",
"gross_percent_max": "Tüm zaman",
"net_worth": "Net Worth"
"net_worth": "Net Değer"
},
"audiobookshelf": {
"podcasts": "Podcast",
@@ -805,13 +808,13 @@
"books": "Kitaplar",
"authors": "Yazarlar",
"categories": "Kategoriler",
"series": "Seriler"
"series": "Diziler"
},
"booklore": {
"libraries": "Libraries",
"books": "Books",
"reading": "Reading",
"finished": "Finished"
"libraries": "Kütüphaneler",
"books": "Kitaplar",
"reading": "Okunuyor",
"finished": "Bitti"
},
"jdownloader": {
"downloadCount": "Kuyruk",
@@ -820,7 +823,7 @@
"downloadSpeed": "Hız"
},
"kavita": {
"seriesCount": "Seriler",
"seriesCount": "Diziler",
"totalFiles": "Dosyalar"
},
"azuredevops": {
@@ -865,7 +868,7 @@
"total": "Toplam",
"running": "Çalışıyor",
"stopped": "Durdu",
"passed": "Passed",
"passed": "Başarılı",
"failed": "Başarısız"
},
"openwrt": {
@@ -874,7 +877,7 @@
"up": "Çalışıyor",
"down": "Çalışmayan",
"bytesTx": "İletilen",
"bytesRx": "Received"
"bytesRx": "Alınan"
},
"uptimerobot": {
"status": "Durum",
@@ -924,7 +927,7 @@
},
"gitea": {
"notifications": "Bildirimler",
"issues": "Issues",
"issues": "Sorunlar",
"pulls": "Değişiklik İstekleri",
"repositories": "Depolar"
},
@@ -1006,21 +1009,21 @@
"lubelogger": {
"vehicle": "Taşıt",
"vehicles": "Taşıtlar",
"serviceRecords": "Service Records",
"serviceRecords": "Servis Kayıtları",
"reminders": "Hatırlatıcılar",
"nextReminder": "Sonraki hatırlatıcı",
"none": "None"
"none": "Hiçbiri"
},
"vikunja": {
"projects": "Etkin projeler",
"tasks7d": "Bitişi Bu Hafta Olan Görevler",
"tasksOverdue": "Overdue Tasks",
"tasksInProgress": "Tasks In Progress"
"tasksOverdue": "Gecikmiş Görevler",
"tasksInProgress": "Devam Eden Görevler"
},
"headscale": {
"name": "Ad",
"address": "Adres",
"last_seen": "Last Seen",
"last_seen": "Son Görülme",
"status": "Durum",
"online": "Çevrimiçi",
"offline": "Çevrimdışı"
@@ -1031,21 +1034,21 @@
"up": "Çalışıyor",
"down": "Çalışmayan",
"paused": "Durduruldu",
"pending": "Pending",
"pending": "Beklemede",
"status": "Durum",
"updated": "Güncellendi",
"cpu": "İşlemci",
"memory": "Bellek",
"disk": "Disk",
"disk": "Depolama",
"network": "NET"
},
"argocd": {
"apps": "Uygulamalar",
"synced": "Synced",
"outOfSync": "Out Of Sync",
"synced": "Senkron",
"outOfSync": "Senkron Değil",
"healthy": "Sağlıklı",
"degraded": "Degraded",
"progressing": "Progressing",
"degraded": "Sorunlu",
"progressing": "Uygulanıyor",
"missing": "Eksik",
"suspended": "Askıya Alındı"
},
@@ -1053,22 +1056,22 @@
"loading": "Yükleniyor"
},
"gitlab": {
"groups": "Groups",
"issues": "Issues",
"merges": "Merge Requests",
"projects": "Projects"
"groups": "Gruplar",
"issues": "Sorunlar",
"merges": "Birleştirme İstekleri",
"projects": "Projeler"
},
"apcups": {
"status": "Durum",
"load": "Load",
"bcharge": "Battery Charge",
"load": "Yük",
"bcharge": "Pil Yüzdesi",
"timeleft": "Kalan zaman"
},
"karakeep": {
"bookmarks": "Yer imleri",
"favorites": "Gözdeler",
"archived": "Archived",
"highlights": "Highlights",
"archived": "Arşivlenen",
"highlights": "Öne Çıkanlar",
"lists": "Listeler",
"tags": "Etiketler"
},
@@ -1084,14 +1087,14 @@
"sharedFiles": "Dosyalar"
},
"jellystat": {
"songs": "Şarkılar",
"movies": "Filmler",
"episodes": "Bölümler",
"songs": "Şarkı",
"movies": "Film",
"episodes": "Bölüm",
"other": "Diğer"
},
"checkmk": {
"serviceErrors": "Service issues",
"hostErrors": "Host issues"
"serviceErrors": "Hizmet Sorunları",
"hostErrors": "Sunucu Sorunları"
},
"komodo": {
"total": "Toplam",
@@ -1101,8 +1104,8 @@
"unhealthy": "Sağlıksız",
"unknown": "Bilinmeyen",
"servers": "Sunucular",
"stacks": "Stacks",
"containers": "Containers"
"stacks": "Yığınlar",
"containers": "Konteynerler"
},
"filebrowser": {
"available": "Uygun",
@@ -1120,11 +1123,11 @@
"STARTED": "Başladı",
"STOPPED": "Durdu",
"NEW_ARRAY": "Yeni dizi",
"RECON_DISK": "Reconstructing Disk",
"RECON_DISK": "Disk Yeniden Oluşturuluyor",
"DISABLE_DISK": "Disk devre dışı",
"SWAP_DSBL": "Swap devre dışı",
"INVALID_EXPANSION": "Invalid Expansion",
"PARITY_NOT_BIGGEST": "Parity Not Biggest",
"INVALID_EXPANSION": "Geçersiz Genişletme",
"PARITY_NOT_BIGGEST": "Parity En Büyük Disk Değil",
"TOO_MANY_MISSING_DISKS": "Çok fazla disk eksik",
"NEW_DISK_TOO_SMALL": "Yeni disk çok küçük",
"NO_DATA_DISKS": "Veri diski yok",
@@ -1139,37 +1142,43 @@
"poolFree": "{{pool}} boş"
},
"backrest": {
"num_plans": "Plans",
"num_success_30": "Successes",
"num_failure_30": "Failures",
"num_success_latest": "Succeeding",
"num_failure_latest": "Failing",
"bytes_added_30": "Bytes Added"
"num_plans": "Planlar",
"num_success_30": "Başarılılar",
"num_failure_30": "Başarısızlıklar",
"num_success_latest": "Başarılı",
"num_failure_latest": "Başarısız",
"bytes_added_30": "Eklenen Veri"
},
"yourspotify": {
"songs": "Songs",
"time": "Time",
"artists": "Artists"
"songs": "Şarkılar",
"time": "Zaman",
"artists": "Sanatçılar"
},
"arcane": {
"containers": "Containers",
"images": "Images",
"image_updates": "Image Updates",
"images_unused": "Unused",
"environment_required": "Environment ID Required"
"containers": "Konteynerler",
"images": "İmajlar",
"image_updates": "İmaj Güncellemeleri",
"images_unused": "Kullanılmayan İmajlar",
"environment_required": "Ortam Kimliği Gerekli"
},
"dockhand": {
"running": "Running",
"stopped": "Stopped",
"cpu": "CPU",
"memory": "Memory",
"images": "Images",
"volumes": "Volumes",
"events_today": "Events Today",
"pending_updates": "Pending Updates",
"stacks": "Stacks",
"paused": "Paused",
"total": "Total",
"environment_not_found": "Environment Not Found"
"running": "Çalışan",
"stopped": "Durdurulan",
"cpu": "İşlemci",
"memory": "Bellek",
"images": "İmajlar",
"volumes": "Birimler",
"events_today": "Bugünkü Olaylar",
"pending_updates": "Bekleyen Güncellemeler",
"stacks": "Yığınlar",
"paused": "Duraklatılan",
"total": "Toplam",
"environment_not_found": "Ortam Bulunamadı"
},
"sparkyfitness": {
"eaten": "Eaten",
"burned": "Burned",
"remaining": "Remaining",
"steps": "Steps"
}
}

View File

@@ -184,6 +184,13 @@
"no_active": "Немає активних потоків",
"plex_connection_error": "Перевірте з'єднання Plex"
},
"tracearr": {
"no_active": "No Active Streams",
"streams": "Streams",
"transcodes": "Transcodes",
"directplay": "Direct Play",
"bitrate": "Bitrate"
},
"omada": {
"connectedAp": "Підключені точки доступу",
"activeUser": "Активні пристрої",
@@ -282,17 +289,13 @@
"approved": "Затверджено",
"available": "Доступно"
},
"jellyseerr": {
"pending": "Очікує",
"approved": "Схвалено",
"available": "Доступно",
"issues": "Проблеми до усунення"
},
"overseerr": {
"pending": "Очікує",
"processing": "Обробка",
"approved": "Схвалено",
"available": "Доступно"
"seerr": {
"pending": "Pending",
"approved": "Approved",
"available": "Available",
"completed": "Completed",
"processing": "Processing",
"issues": "Open Issues"
},
"netalertx": {
"total": "Усього",
@@ -1171,5 +1174,11 @@
"paused": "Paused",
"total": "Total",
"environment_not_found": "Environment Not Found"
},
"sparkyfitness": {
"eaten": "Eaten",
"burned": "Burned",
"remaining": "Remaining",
"steps": "Steps"
}
}

View File

@@ -184,6 +184,13 @@
"no_active": "No Active Streams",
"plex_connection_error": "Check Plex Connection"
},
"tracearr": {
"no_active": "No Active Streams",
"streams": "Streams",
"transcodes": "Transcodes",
"directplay": "Direct Play",
"bitrate": "Bitrate"
},
"omada": {
"connectedAp": "Connected APs",
"activeUser": "Active devices",
@@ -282,17 +289,13 @@
"approved": "Đã duyệt",
"available": "Available"
},
"jellyseerr": {
"seerr": {
"pending": "Pending",
"approved": "Approved",
"available": "Available",
"issues": "Open Issues"
},
"overseerr": {
"pending": "Pending",
"completed": "Completed",
"processing": "Processing",
"approved": "Approved",
"available": "Available"
"issues": "Open Issues"
},
"netalertx": {
"total": "Total",
@@ -1171,5 +1174,11 @@
"paused": "Paused",
"total": "Total",
"environment_not_found": "Environment Not Found"
},
"sparkyfitness": {
"eaten": "Eaten",
"burned": "Burned",
"remaining": "Remaining",
"steps": "Steps"
}
}

View File

@@ -108,14 +108,14 @@
"songs": "曲目"
},
"jellyfin": {
"playing": "Playing",
"transcoding": "Transcoding",
"bitrate": "Bitrate",
"no_active": "No Active Streams",
"movies": "Movies",
"series": "Series",
"episodes": "Episodes",
"songs": "Songs"
"playing": "正在播放",
"transcoding": "轉碼",
"bitrate": "位元率",
"no_active": "無播放活動",
"movies": "電影",
"series": "系列",
"episodes": "劇集",
"songs": "曲目"
},
"esphome": {
"offline": "Offline",
@@ -184,6 +184,13 @@
"no_active": "No Active Streams",
"plex_connection_error": "檢查Plex的連接狀態"
},
"tracearr": {
"no_active": "No Active Streams",
"streams": "Streams",
"transcodes": "Transcodes",
"directplay": "Direct Play",
"bitrate": "Bitrate"
},
"omada": {
"connectedAp": "已連接的存取點",
"activeUser": "在線裝置",
@@ -282,18 +289,14 @@
"approved": "批准",
"available": "可用"
},
"jellyseerr": {
"seerr": {
"pending": "Pending",
"approved": "Approved",
"available": "Available",
"completed": "Completed",
"processing": "Processing",
"issues": "Open Issues"
},
"overseerr": {
"pending": "Pending",
"processing": "處理中",
"approved": "Approved",
"available": "Available"
},
"netalertx": {
"total": "Total",
"connected": "Connected",
@@ -318,9 +321,9 @@
"ping": "Ping"
},
"portainer": {
"running": "Running",
"running": "執行中",
"stopped": "暫停",
"total": "Total"
"total": "全部"
},
"suwayomi": {
"download": "Downloaded",
@@ -383,7 +386,7 @@
"npm": {
"enabled": "啟用",
"disabled": "停用咗",
"total": "Total"
"total": "全部"
},
"coinmarketcap": {
"configure": "配置一個或多個加密貨幣以進行跟蹤",
@@ -448,19 +451,19 @@
},
"glances": {
"cpu": "CPU",
"load": "Load",
"wait": "Please wait",
"temp": "TEMP",
"load": "負載",
"wait": "請稍候",
"temp": "溫度",
"_temp": "溫度",
"warn": "警告",
"uptime": "UP",
"total": "Total",
"free": "Free",
"used": "Used",
"days": "d",
"hours": "h",
"uptime": "運作時間",
"total": "全部",
"free": "剩餘",
"used": "已使用",
"days": "",
"hours": "",
"crit": "重大的",
"read": "Read",
"read": "已讀",
"write": "寫入",
"gpu": "GPU",
"mem": "記憶體",
@@ -1084,10 +1087,10 @@
"sharedFiles": "Files"
},
"jellystat": {
"songs": "Songs",
"movies": "Movies",
"episodes": "Episodes",
"other": "Other"
"songs": "曲目",
"movies": "電影",
"episodes": "劇集",
"other": "其它"
},
"checkmk": {
"serviceErrors": "Service issues",
@@ -1171,5 +1174,11 @@
"paused": "Paused",
"total": "Total",
"environment_not_found": "Environment Not Found"
},
"sparkyfitness": {
"eaten": "Eaten",
"burned": "Burned",
"remaining": "Remaining",
"steps": "Steps"
}
}

View File

@@ -61,7 +61,7 @@
"wlan_devices": "无线局域网设备",
"lan_users": "局域网用户",
"wlan_users": "无线局域网用户",
"up": "UP",
"up": "在线",
"down": "离线",
"wait": "请稍候",
"empty_data": "子系统状态未知"
@@ -108,21 +108,21 @@
"songs": "歌曲"
},
"jellyfin": {
"playing": "Playing",
"transcoding": "Transcoding",
"bitrate": "Bitrate",
"no_active": "No Active Streams",
"movies": "Movies",
"series": "Series",
"episodes": "Episodes",
"songs": "Songs"
"playing": "播放中",
"transcoding": "转码",
"bitrate": "比特率",
"no_active": "暂无播放",
"movies": "电影",
"series": "系列",
"episodes": "剧集",
"songs": "歌曲"
},
"esphome": {
"offline": "离线",
"offline_alt": "离线",
"online": "在线的",
"total": "Total",
"unknown": "Unknown"
"total": "总计",
"unknown": "未知"
},
"evcc": {
"pv_power": "正式环境",
@@ -143,7 +143,7 @@
"unread": "未读"
},
"fritzbox": {
"connectionStatus": "Status",
"connectionStatus": "状态",
"connectionStatusUnconfigured": "未配置",
"connectionStatusConnecting": "连接中",
"connectionStatusAuthenticating": "认证中",
@@ -151,11 +151,11 @@
"connectionStatusDisconnecting": "正在断开连接",
"connectionStatusDisconnected": "未连接",
"connectionStatusConnected": "已连接",
"uptime": "Uptime",
"uptime": "运行时间",
"maxDown": "最大下载速度",
"maxUp": "最大上传速度",
"down": "Down",
"up": "Up",
"down": "离线",
"up": "在线",
"received": "已接收",
"sent": "已发送",
"externalIPAddress": "外部IP",
@@ -178,17 +178,24 @@
"passes": "通行证"
},
"tautulli": {
"playing": "Playing",
"transcoding": "Transcoding",
"bitrate": "Bitrate",
"no_active": "No Active Streams",
"playing": "播放中",
"transcoding": "转码",
"bitrate": "比特率",
"no_active": "暂无播放",
"plex_connection_error": "Check Plex Connection"
},
"tracearr": {
"no_active": "暂无播放",
"streams": "Streams",
"transcodes": "Transcodes",
"directplay": "Direct Play",
"bitrate": "比特率"
},
"omada": {
"connectedAp": "连接中的AP",
"activeUser": "活跃设备",
"alerts": "警报",
"connectedGateways": "Connected gateways",
"connectedGateways": "已连接网关",
"connectedSwitches": "已连接开关"
},
"nzbget": {
@@ -203,13 +210,13 @@
"tv": "电视节目"
},
"sabnzbd": {
"rate": "Rate",
"rate": "速率",
"queue": "队列",
"timeleft": "剩余时间"
},
"rutorrent": {
"active": "活动中",
"upload": "Upload",
"upload": "上传",
"download": "下载"
},
"transmission": {
@@ -226,7 +233,7 @@
},
"qnap": {
"cpuUsage": "处理器",
"memUsage": "内存",
"memUsage": "内存使用",
"systemTempC": "系统温度",
"poolUsage": "存储池",
"volumeUsage": "Volume Usage",
@@ -245,7 +252,7 @@
"downloadstation": {
"download": "Download",
"upload": "Upload",
"leech": "Leech",
"leech": "",
"seed": "做种"
},
"sonarr": {
@@ -282,18 +289,14 @@
"approved": "已批准",
"available": "可用"
},
"jellyseerr": {
"pending": "待办的",
"seerr": {
"pending": "Pending",
"approved": "Approved",
"available": "Available",
"completed": "Completed",
"processing": "Processing",
"issues": "Open Issues"
},
"overseerr": {
"pending": "Pending",
"processing": "处理中",
"approved": "Approved",
"available": "Available"
},
"netalertx": {
"total": "Total",
"connected": "Connected",
@@ -318,9 +321,9 @@
"ping": "Ping"
},
"portainer": {
"running": "Running",
"running": "运行中",
"stopped": "停止",
"total": "Total"
"total": "总计"
},
"suwayomi": {
"download": "Downloaded",
@@ -377,13 +380,13 @@
"unknown": "未知"
},
"navidrome": {
"nothing_streaming": "",
"nothing_streaming": "暂无播放",
"please_wait": "请等待"
},
"npm": {
"enabled": "已启用",
"disabled": "禁用",
"total": "Total"
"total": "总计"
},
"coinmarketcap": {
"configure": "配置一个或多个需要追踪的加密",
@@ -406,7 +409,7 @@
},
"jackett": {
"configured": "已配置",
"errored": "Errored"
"errored": "出错"
},
"strelaysrv": {
"numActiveSessions": "会话",
@@ -420,7 +423,7 @@
"domain_count": "域"
},
"medusa": {
"wanted": "Wanted",
"wanted": "",
"queued": "Queued",
"series": "Series"
},
@@ -441,7 +444,7 @@
"failedLoginsLast24H": "登录失败 (24h)"
},
"proxmox": {
"mem": "MEM",
"mem": "内存",
"cpu": "CPU",
"lxc": "容器",
"vms": "虚拟机"
@@ -450,7 +453,7 @@
"cpu": "CPU",
"load": "负载",
"wait": "请稍候",
"temp": "温度",
"temp": "转速",
"_temp": "Temp",
"warn": "Warn",
"uptime": "运行时间",
@@ -460,7 +463,7 @@
"days": "日",
"hours": "时",
"crit": "Crit",
"read": "Read",
"read": "读取",
"write": "写入",
"gpu": "GPU",
"mem": "Mem",
@@ -481,57 +484,57 @@
"1-day": "主要是晴天",
"1-night": "大部晴朗",
"2-day": "多云",
"2-night": "Partly Cloudy",
"2-night": "多云",
"3-day": "阴天",
"3-night": "Cloudy",
"3-night": "阴天",
"45-day": "有雾",
"45-night": "Foggy",
"48-day": "Foggy",
"48-night": "Foggy",
"45-night": "",
"48-day": "",
"48-night": "",
"51-day": "小雨",
"51-night": "Light Drizzle",
"51-night": "小细雨",
"53-day": "小雨",
"53-night": "Drizzle",
"53-night": "细雨",
"55-day": "毛毛雨",
"55-night": "Heavy Drizzle",
"55-night": "大细雨",
"56-day": "小冻毛雨",
"56-night": "Light Freezing Drizzle",
"56-night": "小冻毛雨",
"57-day": "冻毛雨",
"57-night": "Freezing Drizzle",
"57-night": "冻毛雨",
"61-day": "小雨",
"61-night": "Light Rain",
"61-night": "小雨",
"63-day": "雨",
"63-night": "Rain",
"63-night": "雨天",
"65-day": "大雨",
"65-night": "Heavy Rain",
"65-night": "大雨",
"66-day": "冻雨",
"66-night": "Freezing Rain",
"67-day": "Freezing Rain",
"67-night": "Freezing Rain",
"66-night": "冻雨",
"67-day": "冻雨",
"67-night": "冻雨",
"71-day": "小雪",
"71-night": "Light Snow",
"71-night": "小雪",
"73-day": "中雪",
"73-night": "Snow",
"73-night": "中雪",
"75-day": "大雪",
"75-night": "Heavy Snow",
"75-night": "大雪",
"77-day": "雪粒",
"77-night": "Snow Grains",
"77-night": "雪粒",
"80-day": "微阵雨",
"80-night": "Light Showers",
"80-night": "小阵雨",
"81-day": "阵雨",
"81-night": "Showers",
"81-night": "阵雨",
"82-day": "强阵雨",
"82-night": "Heavy Showers",
"82-night": "强阵雨",
"85-day": "阵雪",
"85-night": "Snow Showers",
"86-day": "Snow Showers",
"86-night": "Snow Showers",
"85-night": "阵雪",
"86-day": "阵雪",
"86-night": "阵雪",
"95-day": "雷雨",
"95-night": "Thunderstorm",
"95-night": "雷雨",
"96-day": "雷雨伴随冰雹",
"96-night": "Thunderstorm With Hail",
"99-day": "Thunderstorm With Hail",
"99-night": "Thunderstorm With Hail"
"96-night": "雷雨伴随冰雹",
"99-day": "雷雨伴随冰雹",
"99-night": "雷雨伴随冰雹"
},
"homebridge": {
"available_update": "System",
@@ -687,9 +690,9 @@
"memory_usage": "内存"
},
"immich": {
"users": "Users",
"users": "用户",
"photos": "照片",
"videos": "Videos",
"videos": "影片",
"storage": "储存空间"
},
"uptimekuma": {
@@ -987,8 +990,8 @@
},
"frigate": {
"cameras": "摄像头",
"uptime": "Uptime",
"version": "Version"
"uptime": "运行时间",
"version": "版本"
},
"linkwarden": {
"links": "链接",
@@ -1035,7 +1038,7 @@
"status": "Status",
"updated": "Updated",
"cpu": "CPU",
"memory": "MEM",
"memory": "内存",
"disk": "磁盘",
"network": "网络"
},
@@ -1059,10 +1062,10 @@
"projects": "项目"
},
"apcups": {
"status": "Status",
"load": "Load",
"bcharge": "Battery Charge",
"timeleft": "Time Left"
"status": "状态",
"load": "负载",
"bcharge": "电池电量",
"timeleft": "剩余供电时间"
},
"karakeep": {
"bookmarks": "书签",
@@ -1084,9 +1087,9 @@
"sharedFiles": "Files"
},
"jellystat": {
"songs": "Songs",
"movies": "Movies",
"episodes": "Episodes",
"songs": "歌曲",
"movies": "电影",
"episodes": "剧集",
"other": "其他"
},
"checkmk": {
@@ -1131,8 +1134,8 @@
"notifications": "Notifications",
"status": "Status",
"cpu": "CPU",
"memoryUsed": "Memory Used",
"memoryAvailable": "Memory Available",
"memoryUsed": "已用内存",
"memoryAvailable": "可用内存",
"arrayUsed": "Array Used",
"arrayFree": "Array Free",
"poolUsed": "{{pool}} Used",
@@ -1159,11 +1162,11 @@
"environment_required": "Environment ID Required"
},
"dockhand": {
"running": "Running",
"stopped": "Stopped",
"running": "运行中",
"stopped": "停止",
"cpu": "CPU",
"memory": "Memory",
"images": "Images",
"memory": "内存",
"images": "图片",
"volumes": "Volumes",
"events_today": "Events Today",
"pending_updates": "Pending Updates",
@@ -1171,5 +1174,11 @@
"paused": "Paused",
"total": "Total",
"environment_not_found": "Environment Not Found"
},
"sparkyfitness": {
"eaten": "Eaten",
"burned": "Burned",
"remaining": "Remaining",
"steps": "Steps"
}
}

View File

@@ -108,14 +108,14 @@
"songs": "曲目"
},
"jellyfin": {
"playing": "Playing",
"transcoding": "Transcoding",
"bitrate": "Bitrate",
"no_active": "No Active Streams",
"movies": "Movies",
"series": "Series",
"episodes": "Episodes",
"songs": "Songs"
"playing": "正在播放",
"transcoding": "轉碼",
"bitrate": "位元率",
"no_active": "無播放活動",
"movies": "電影",
"series": "系列",
"episodes": "劇集",
"songs": "曲目"
},
"esphome": {
"offline": "Offline",
@@ -184,6 +184,13 @@
"no_active": "No Active Streams",
"plex_connection_error": "檢查Plex的連線狀態"
},
"tracearr": {
"no_active": "No Active Streams",
"streams": "Streams",
"transcodes": "Transcodes",
"directplay": "Direct Play",
"bitrate": "Bitrate"
},
"omada": {
"connectedAp": "已連線的無線網路",
"activeUser": "上線裝置",
@@ -282,18 +289,14 @@
"approved": "已核准",
"available": "可觀看"
},
"jellyseerr": {
"seerr": {
"pending": "Pending",
"approved": "Approved",
"available": "Available",
"completed": "Completed",
"processing": "Processing",
"issues": "Open Issues"
},
"overseerr": {
"pending": "Pending",
"processing": "處理中",
"approved": "Approved",
"available": "Available"
},
"netalertx": {
"total": "Total",
"connected": "Connected",
@@ -318,9 +321,9 @@
"ping": "Ping"
},
"portainer": {
"running": "Running",
"running": "執行中",
"stopped": "已停止",
"total": "Total"
"total": "全部"
},
"suwayomi": {
"download": "Downloaded",
@@ -383,7 +386,7 @@
"npm": {
"enabled": "已啟用",
"disabled": "已停用",
"total": "Total"
"total": "全部"
},
"coinmarketcap": {
"configure": "請設定一個或多個欲追蹤的加密貨幣",
@@ -448,19 +451,19 @@
},
"glances": {
"cpu": "CPU",
"load": "Load",
"wait": "Please wait",
"temp": "TEMP",
"load": "負載",
"wait": "請稍候",
"temp": "溫度",
"_temp": "溫度",
"warn": "警告",
"uptime": "UP",
"total": "Total",
"free": "Free",
"used": "Used",
"days": "d",
"hours": "h",
"uptime": "運作時間",
"total": "全部",
"free": "剩餘",
"used": "已使用",
"days": "",
"hours": "",
"crit": "重大的",
"read": "Read",
"read": "已讀",
"write": "寫入",
"gpu": "GPU",
"mem": "記憶體",
@@ -1084,10 +1087,10 @@
"sharedFiles": "Files"
},
"jellystat": {
"songs": "Songs",
"movies": "Movies",
"episodes": "Episodes",
"other": "Other"
"songs": "曲目",
"movies": "電影",
"episodes": "劇集",
"other": "其它"
},
"checkmk": {
"serviceErrors": "Service issues",
@@ -1171,5 +1174,11 @@
"paused": "Paused",
"total": "Total",
"environment_not_found": "Environment Not Found"
},
"sparkyfitness": {
"eaten": "Eaten",
"burned": "Burned",
"remaining": "Remaining",
"steps": "Steps"
}
}

View File

@@ -6,7 +6,7 @@ import { BlockHighlightContext } from "./highlight-context";
import { evaluateHighlight, getHighlightClass } from "utils/highlights";
export default function Block({ value, label, field }) {
export default function Block({ value, highlightValue, label, field }) {
const { t } = useTranslation();
const highlightConfig = useContext(BlockHighlightContext);
@@ -20,12 +20,12 @@ export default function Block({ value, label, field }) {
}
for (const candidate of candidates) {
const result = evaluateHighlight(candidate, value, highlightConfig);
const result = evaluateHighlight(candidate, highlightValue ?? value, highlightConfig);
if (result) return result;
}
return null;
}, [field, label, value, highlightConfig]);
}, [field, label, value, highlightValue, highlightConfig]);
const highlightClass = useMemo(() => {
if (!highlight?.level) return undefined;

View File

@@ -38,4 +38,27 @@ describe("components/services/widget/block", () => {
expect(el.getAttribute("data-highlight-level")).toBe("danger");
expect(el.className).toContain("danger-class");
});
it("prefers highlightValue over the rendered value for numeric highlighting", () => {
const highlightConfig = {
levels: { warn: "warn-class" },
fields: {
foo: {
numeric: { when: "gt", value: 5, level: "warn" },
},
},
};
const { container } = renderWithProviders(
<BlockHighlightContext.Provider value={highlightConfig}>
<Block label="foo.label" field="foo" value="5.791 ms" highlightValue={5.791} />
</BlockHighlightContext.Provider>,
{ settings: {} },
);
const el = container.querySelector(".service-block");
expect(el).not.toBeNull();
expect(el.getAttribute("data-highlight-level")).toBe("warn");
expect(el.className).toContain("warn-class");
});
});

View File

@@ -619,7 +619,19 @@ export function cleanServiceGroups(groups) {
if (refreshInterval) widget.refreshInterval = refreshInterval;
}
if (type === "calendar") {
if (integrations) widget.integrations = integrations;
if (integrations) {
if (Array.isArray(integrations)) {
widget.integrations = integrations.map((integration) => {
if (!integration || typeof integration !== "object") {
return integration;
}
const { url, ...integrationWithoutUrl } = integration;
return integrationWithoutUrl;
});
} else {
widget.integrations = integrations;
}
}
if (firstDayInWeek) widget.firstDayInWeek = firstDayInWeek;
if (view) widget.view = view;
if (maxEvents) widget.maxEvents = maxEvents;

View File

@@ -369,6 +369,47 @@ describe("utils/config/service-helpers", () => {
expect(widgets.find((w) => w.type === "lubelogger")).toEqual(expect.objectContaining({ vehicleID: 12 }));
});
it("cleanServiceGroups removes calendar integration urls from frontend widget payload", async () => {
const mod = await import("./service-helpers");
const { cleanServiceGroups } = mod;
const rawGroups = [
{
name: "Core",
services: [
{
name: "Calendar",
weight: 100,
widgets: [
{
type: "calendar",
integrations: [
{
type: "ical",
name: "EPL Fixtures",
url: "https://calendar.google.com/calendar/ical/example/public/basic.ics",
color: "purple",
},
],
},
],
},
],
groups: [],
},
];
const cleaned = cleanServiceGroups(rawGroups);
const calendarWidget = cleaned[0].services[0].widgets[0];
expect(calendarWidget.integrations).toEqual([
{
type: "ical",
name: "EPL Fixtures",
color: "purple",
},
]);
});
it("findGroupByName deep-searches and annotates parent", async () => {
const mod = await import("./service-helpers");
const { findGroupByName } = mod;

View File

@@ -0,0 +1,116 @@
import cache from "memory-cache";
import createLogger from "utils/logger";
import { formatApiCall } from "utils/proxy/api-helpers";
import { addCookieToJar, setCookieHeader } from "utils/proxy/cookie-jar";
import { httpProxy } from "utils/proxy/http";
import widgets from "widgets/widgets";
function isSuccessfulLoginResponse(data) {
const json = JSON.parse(data.toString());
return json?.meta?.rc === "ok" || json?.login_time || json?.update_time;
}
async function login({ widget, api, endpoint, csrfToken }) {
const loginUrl = new URL(formatApiCall(api.replace("{prefix}", ""), { endpoint, ...widget }));
const headers = { "Content-Type": "application/json" };
if (csrfToken) {
headers["X-CSRF-TOKEN"] = csrfToken;
}
return httpProxy(loginUrl, {
method: "POST",
body: JSON.stringify({ username: widget.username, password: widget.password, remember: true, rememberMe: true }),
headers,
});
}
export default function createUnifiProxyHandler({
proxyName,
resolveWidget,
resolveRequestContext,
getLoginEndpoint = () => "auth/login",
shouldAttemptLogin = ({ widget }) => !widget.key,
}) {
const prefixCacheKey = `${proxyName}__prefix`;
const logger = createLogger(proxyName);
return async function unifiProxyHandler(req, res) {
const widget = await resolveWidget(req, logger);
const { service, endpoint } = req.query;
if (!widget) {
return res.status(400).json({ error: "Invalid proxy service type" });
}
const api = widgets?.[widget.type]?.api;
if (!api) {
return res.status(403).json({ error: "Service does not support API calls" });
}
const cachedPrefix = cache.get(`${prefixCacheKey}.${service}`);
const {
prefix,
headers = {},
csrfToken: initialCsrfToken,
} = await resolveRequestContext({
cachedPrefix,
logger,
req,
service,
widget,
});
let csrfToken = initialCsrfToken;
cache.put(`${prefixCacheKey}.${service}`, prefix);
widget.prefix = prefix;
const url = new URL(formatApiCall(api, { endpoint, ...widget }));
const params = { method: "GET", headers };
setCookieHeader(url, params);
let [status, contentType, data, responseHeaders] = await httpProxy(url, params);
if (status === 401 && shouldAttemptLogin({ widget, req, responseHeaders })) {
logger.debug("UniFi request was rejected, attempting login.");
if (responseHeaders?.["x-csrf-token"]) {
csrfToken = responseHeaders["x-csrf-token"];
}
[status, contentType, data, responseHeaders] = await login({
api,
csrfToken,
endpoint: getLoginEndpoint({ prefix, req, widget }),
widget,
});
if (status !== 200) {
logger.error("HTTP %d logging in to UniFi. Data: %s", status, data);
return res.status(status).json({ error: { message: `HTTP Error ${status}`, url, data } });
}
if (!isSuccessfulLoginResponse(data)) {
logger.error("Error logging in to UniFi: Data: %s", data);
return res.status(401).end(data);
}
addCookieToJar(url, responseHeaders);
setCookieHeader(url, params);
[status, contentType, data, responseHeaders] = await httpProxy(url, params);
}
if (status !== 200) {
logger.error("HTTP %d getting data from UniFi endpoint %s. Data: %s", status, url.href, data);
return res.status(status).json({ error: { message: `HTTP Error ${status}`, url, data } });
}
if (contentType) {
res.setHeader("Content-Type", contentType);
}
return res.status(status).send(data);
};
}

View File

@@ -37,6 +37,7 @@ export default function Component({ service }) {
<Block
label="adguard.latency"
value={t("common.ms", { value: adguardData.avg_processing_time * 1000, style: "unit", unit: "millisecond" })}
highlightValue={adguardData.avg_processing_time * 1000}
/>
</Container>
);

View File

@@ -51,12 +51,25 @@ export default function Component({ service }) {
<Block label="beszel.name" value={system.name} />
<Block label="beszel.status" value={t(`beszel.${system.status}`)} />
<Block label="beszel.updated" value={t("common.relativeDate", { value: system.updated })} />
<Block label="beszel.cpu" value={t("common.percent", { value: system.info.cpu, maximumFractionDigits: 2 })} />
<Block label="beszel.memory" value={t("common.percent", { value: system.info.mp, maximumFractionDigits: 2 })} />
<Block label="beszel.disk" value={t("common.percent", { value: system.info.dp, maximumFractionDigits: 2 })} />
<Block
label="beszel.cpu"
value={t("common.percent", { value: system.info.cpu, maximumFractionDigits: 2 })}
highlightValue={system.info.cpu}
/>
<Block
label="beszel.memory"
value={t("common.percent", { value: system.info.mp, maximumFractionDigits: 2 })}
highlightValue={system.info.mp}
/>
<Block
label="beszel.disk"
value={t("common.percent", { value: system.info.dp, maximumFractionDigits: 2 })}
highlightValue={system.info.dp}
/>
<Block
label="beszel.network"
value={t("common.byterate", { value: system.info.bb, maximumFractionDigits: 2 })}
highlightValue={system.info.bb}
/>
</Container>
);

View File

@@ -73,7 +73,13 @@ export default function Component({ service }) {
?.filter((integration) => integration?.type)
.map((integration) => ({
// Include the extension so Vite/Vitest can statically validate the import base.
service: dynamic(() => import(`./integrations/${integration.type}.jsx`)),
service: dynamic(
() =>
import(
/* webpackExclude: /\.test\.jsx$/ */
`./integrations/${integration.type}.jsx`
),
),
widget: { ...widget, ...integration },
})) ?? [],
[widget],

View File

@@ -52,9 +52,9 @@ export default function Component({ service }) {
<>
<Container service={service}>
<Block label="deluge.leech" value={t("common.number", { value: leech })} />
<Block label="deluge.download" value={t("common.byterate", { value: rateDl })} />
<Block label="deluge.download" value={t("common.byterate", { value: rateDl })} highlightValue={rateDl} />
<Block label="deluge.seed" value={t("common.number", { value: completed })} />
<Block label="deluge.upload" value={t("common.byterate", { value: rateUl })} />
<Block label="deluge.upload" value={t("common.byterate", { value: rateUl })} highlightValue={rateUl} />
</Container>
{widget?.enableLeechProgress &&
leechTorrents.map((queueEntry) => (

View File

@@ -41,17 +41,19 @@ export default function Component({ service }) {
}
const { rxBytes, txBytes } = calculateThroughput(statsData.stats);
const cpuPercent = calculateCPUPercent(statsData.stats);
const usedMemory = calculateUsedMemory(statsData.stats);
return (
<Container service={service}>
<Block label="docker.cpu" value={t("common.percent", { value: calculateCPUPercent(statsData.stats) })} />
<Block label="docker.cpu" value={t("common.percent", { value: cpuPercent })} highlightValue={cpuPercent} />
{statsData.stats.memory_stats.usage && (
<Block label="docker.mem" value={t("common.bytes", { value: calculateUsedMemory(statsData.stats) })} />
<Block label="docker.mem" value={t("common.bytes", { value: usedMemory })} highlightValue={usedMemory} />
)}
{statsData.stats.networks && (
<>
<Block label="docker.rx" value={t("common.bytes", { value: rxBytes })} />
<Block label="docker.tx" value={t("common.bytes", { value: txBytes })} />
<Block label="docker.rx" value={t("common.bytes", { value: rxBytes })} highlightValue={rxBytes} />
<Block label="docker.tx" value={t("common.bytes", { value: txBytes })} highlightValue={txBytes} />
</>
)}
</Container>

View File

@@ -105,8 +105,16 @@ export default function Component({ service }) {
<Block label="dockhand.paused" value={t("common.number", { value: paused ?? 0 })} />
<Block label="dockhand.pending_updates" value={t("common.number", { value: pendingUpdates ?? 0 })} />
<Block label="dockhand.total" value={t("common.number", { value: totalContainers })} />
<Block label="dockhand.cpu" value={t("common.percent", { value: cpuPercent, maximumFractionDigits: 1 })} />
<Block label="dockhand.memory" value={t("common.percent", { value: memoryPercent, maximumFractionDigits: 1 })} />
<Block
label="dockhand.cpu"
value={t("common.percent", { value: cpuPercent, maximumFractionDigits: 1 })}
highlightValue={cpuPercent}
/>
<Block
label="dockhand.memory"
value={t("common.percent", { value: memoryPercent, maximumFractionDigits: 1 })}
highlightValue={memoryPercent}
/>
<Block label="dockhand.images" value={t("common.number", { value: imagesTotal ?? 0 })} />
<Block label="dockhand.volumes" value={t("common.number", { value: volumesTotal ?? 0 })} />
<Block

View File

@@ -33,9 +33,9 @@ export default function Component({ service }) {
return (
<Container service={service}>
<Block label="downloadstation.leech" value={t("common.number", { value: leech })} />
<Block label="downloadstation.download" value={t("common.byterate", { value: rateDl })} />
<Block label="downloadstation.download" value={t("common.byterate", { value: rateDl })} highlightValue={rateDl} />
<Block label="downloadstation.seed" value={t("common.number", { value: completed })} />
<Block label="downloadstation.upload" value={t("common.byterate", { value: rateUl })} />
<Block label="downloadstation.upload" value={t("common.byterate", { value: rateUl })} highlightValue={rateUl} />
</Container>
);
}

View File

@@ -25,14 +25,21 @@ export default function Component({ service }) {
);
}
const available = (usage?.total ?? 0) - (usage?.used ?? 0);
return (
<Container service={service}>
<Block label="filebrowser.available" value={t("common.bytes", { value: available })} highlightValue={available} />
<Block
label="filebrowser.available"
value={t("common.bytes", { value: (usage?.total ?? 0) - (usage?.used ?? 0) })}
label="filebrowser.used"
value={t("common.bytes", { value: usage?.used ?? 0 })}
highlightValue={usage?.used ?? 0}
/>
<Block
label="filebrowser.total"
value={t("common.bytes", { value: usage?.total ?? 0 })}
highlightValue={usage?.total ?? 0}
/>
<Block label="filebrowser.used" value={t("common.bytes", { value: usage?.used ?? 0 })} />
<Block label="filebrowser.total" value={t("common.bytes", { value: usage?.total ?? 0 })} />
</Container>
);
}

View File

@@ -45,9 +45,9 @@ export default function Component({ service }) {
return (
<Container service={service}>
<Block label="flood.leech" value={t("common.number", { value: leech })} />
<Block label="flood.download" value={t("common.byterate", { value: rateDl })} />
<Block label="flood.download" value={t("common.byterate", { value: rateDl })} highlightValue={rateDl} />
<Block label="flood.seed" value={t("common.number", { value: completed })} />
<Block label="flood.upload" value={t("common.byterate", { value: rateUl })} />
<Block label="flood.upload" value={t("common.byterate", { value: rateUl })} highlightValue={rateUl} />
</Container>
);
}

View File

@@ -47,12 +47,36 @@ export default function Component({ service }) {
<Container service={service}>
<Block label="fritzbox.connectionStatus" value={t(`fritzbox.connectionStatus${fritzboxData.connectionStatus}`)} />
<Block label="fritzbox.uptime" value={t("common.duration", { value: fritzboxData.uptime })} />
<Block label="fritzbox.maxDown" value={t("common.byterate", { value: fritzboxData.maxDown / 8, decimals: 1 })} />
<Block label="fritzbox.maxUp" value={t("common.byterate", { value: fritzboxData.maxUp / 8, decimals: 1 })} />
<Block label="fritzbox.down" value={t("common.byterate", { value: fritzboxData.down, decimals: 1 })} />
<Block label="fritzbox.up" value={t("common.byterate", { value: fritzboxData.up, decimals: 1 })} />
<Block label="fritzbox.received" value={t("common.bytes", { value: fritzboxData.received })} />
<Block label="fritzbox.sent" value={t("common.bytes", { value: fritzboxData.sent })} />
<Block
label="fritzbox.maxDown"
value={t("common.byterate", { value: fritzboxData.maxDown / 8, decimals: 1 })}
highlightValue={fritzboxData.maxDown / 8}
/>
<Block
label="fritzbox.maxUp"
value={t("common.byterate", { value: fritzboxData.maxUp / 8, decimals: 1 })}
highlightValue={fritzboxData.maxUp / 8}
/>
<Block
label="fritzbox.down"
value={t("common.byterate", { value: fritzboxData.down, decimals: 1 })}
highlightValue={fritzboxData.down}
/>
<Block
label="fritzbox.up"
value={t("common.byterate", { value: fritzboxData.up, decimals: 1 })}
highlightValue={fritzboxData.up}
/>
<Block
label="fritzbox.received"
value={t("common.bytes", { value: fritzboxData.received })}
highlightValue={fritzboxData.received}
/>
<Block
label="fritzbox.sent"
value={t("common.bytes", { value: fritzboxData.sent })}
highlightValue={fritzboxData.sent}
/>
<Block label="fritzbox.externalIPAddress" value={fritzboxData.externalIPAddress} />
<Block label="fritzbox.externalIPv6Address" value={fritzboxData.externalIPv6Address} />
<Block label="fritzbox.externalIPv6Prefix" value={fritzboxData.externalIPv6Prefix} />

View File

@@ -58,7 +58,7 @@ export default function Component({ service }) {
<Block label="gamedig.players" value={players} />
<Block label="gamedig.maxPlayers" value={maxPlayers} />
<Block label="gamedig.bots" value={bots} />
<Block label="gamedig.ping" value={ping} />
<Block label="gamedig.ping" value={ping} highlightValue={serverData.online ? serverData.ping : undefined} />
</Container>
);
}

View File

@@ -45,7 +45,7 @@ export default function Component({ service }) {
<Container service={service}>
<Block label="gatus.up" value={t("common.number", { value: sitesUp })} />
<Block label="gatus.down" value={t("common.number", { value: sitesDown })} />
<Block label="gatus.uptime" value={t("common.percent", { value: uptime })} />
<Block label="gatus.uptime" value={t("common.percent", { value: uptime })} highlightValue={Number(uptime)} />
</Container>
);
}

View File

@@ -31,12 +31,21 @@ export default function Component({ service }) {
return (
<Container service={service}>
<Block label="jdownloader.downloadCount" value={t("common.number", { value: jdownloaderData.downloadCount })} />
<Block label="jdownloader.downloadTotalBytes" value={t("common.bytes", { value: jdownloaderData.totalBytes })} />
<Block
label="jdownloader.downloadTotalBytes"
value={t("common.bytes", { value: jdownloaderData.totalBytes })}
highlightValue={jdownloaderData.totalBytes}
/>
<Block
label="jdownloader.downloadBytesRemaining"
value={t("common.bytes", { value: jdownloaderData.bytesRemaining })}
highlightValue={jdownloaderData.bytesRemaining}
/>
<Block
label="jdownloader.downloadSpeed"
value={t("common.byterate", { value: jdownloaderData.totalSpeed })}
highlightValue={jdownloaderData.totalSpeed}
/>
<Block label="jdownloader.downloadSpeed" value={t("common.byterate", { value: jdownloaderData.totalSpeed })} />
</Container>
);
}

View File

@@ -43,14 +43,23 @@ export default function Component({ service }) {
return (
<Container service={service}>
{(statsData.stats.cpuLimit && (
<Block label="docker.cpu" value={t("common.percent", { value: statsData.stats.cpuUsage })} />
<Block
label="docker.cpu"
value={t("common.percent", { value: statsData.stats.cpuUsage })}
highlightValue={statsData.stats.cpuUsage}
/>
)) || (
<Block
label="docker.cpu"
value={t("common.number", { value: statsData.stats.cpu, maximumFractionDigits: 4 })}
highlightValue={statsData.stats.cpu}
/>
)}
<Block label="docker.mem" value={t("common.bytes", { value: statsData.stats.mem })} />
<Block
label="docker.mem"
value={t("common.bytes", { value: statsData.stats.mem })}
highlightValue={statsData.stats.mem}
/>
</Container>
);
}

View File

@@ -35,8 +35,16 @@ export default function Component({ service }) {
return (
<Container service={service}>
<Block label="mikrotik.uptime" value={statsData.uptime} />
<Block label="mikrotik.cpuLoad" value={t("common.percent", { value: statsData["cpu-load"] })} />
<Block label="mikrotik.memoryUsed" value={t("common.percent", { value: memoryUsed })} />
<Block
label="mikrotik.cpuLoad"
value={t("common.percent", { value: statsData["cpu-load"] })}
highlightValue={statsData["cpu-load"]}
/>
<Block
label="mikrotik.memoryUsed"
value={t("common.percent", { value: memoryUsed })}
highlightValue={memoryUsed}
/>
<Block label="mikrotik.numberOfLeases" value={t("common.number", { value: numberOfLeases })} />
</Container>
);

View File

@@ -54,6 +54,7 @@ export default function Component({ service }) {
style: "unit",
unit: "millisecond",
})}
highlightValue={data[0].ping}
/>
</Container>
);

View File

@@ -56,12 +56,23 @@ export default function Component({ service }) {
return (
<Container service={service}>
{showCpuLoad && (
<Block label="nextcloud.cpuload" value={t("common.percent", { value: nextcloudInfo.system.cpuload[0] })} />
<Block
label="nextcloud.cpuload"
value={t("common.percent", { value: nextcloudInfo.system.cpuload[0] })}
highlightValue={nextcloudInfo.system.cpuload[0]}
/>
)}
{showMemoryUsage && (
<Block
label="nextcloud.memoryusage"
value={t("common.percent", { value: memoryUsage })}
highlightValue={memoryUsage}
/>
)}
{showMemoryUsage && <Block label="nextcloud.memoryusage" value={t("common.percent", { value: memoryUsage })} />}
<Block
label="nextcloud.freespace"
value={t("common.bbytes", { value: nextcloudInfo.system.freespace, maximumFractionDigits: 1 })}
highlightValue={nextcloudInfo.system.freespace}
/>
<Block label="nextcloud.activeusers" value={t("common.number", { value: activeUsers.last24hours })} />
<Block label="nextcloud.numfiles" value={t("common.number", { value: nextcloudInfo.storage.num_files })} />

View File

@@ -27,11 +27,20 @@ export default function Component({ service }) {
return (
<Container service={service}>
<Block label="nzbget.rate" value={t("common.byterate", { value: statusData.DownloadRate })} />
<Block label="nzbget.remaining" value={t("common.bytes", { value: statusData.RemainingSizeMB * 1024 * 1024 })} />
<Block
label="nzbget.rate"
value={t("common.byterate", { value: statusData.DownloadRate })}
highlightValue={statusData.DownloadRate}
/>
<Block
label="nzbget.remaining"
value={t("common.bytes", { value: statusData.RemainingSizeMB * 1024 * 1024 })}
highlightValue={statusData.RemainingSizeMB * 1024 * 1024}
/>
<Block
label="nzbget.downloaded"
value={t("common.bytes", { value: statusData.DownloadedSizeMB * 1024 * 1024 })}
highlightValue={statusData.DownloadedSizeMB * 1024 * 1024}
/>
</Container>
);

View File

@@ -21,8 +21,8 @@ export default function Component({ service }) {
return (
<Container service={service}>
<Block label="widget.status" value={up ? t("openwrt.up") : t("openwrt.down")} />
<Block label="openwrt.bytesTx" value={t("common.bytes", { value: bytesTx })} />
<Block label="openwrt.bytesRx" value={t("common.bytes", { value: bytesRx })} />
<Block label="openwrt.bytesTx" value={t("common.bytes", { value: bytesTx })} highlightValue={bytesTx} />
<Block label="openwrt.bytesRx" value={t("common.bytes", { value: bytesRx })} highlightValue={bytesRx} />
</Container>
);
}

View File

@@ -36,10 +36,22 @@ export default function Component({ service }) {
return (
<Container service={service}>
<Block label="opnsense.cpu" value={t("common.percent", { value: cpu.toFixed(2) })} />
<Block label="opnsense.cpu" value={t("common.percent", { value: cpu.toFixed(2) })} highlightValue={cpu} />
<Block label="opnsense.memory" value={memory} />
{wan && <Block label="opnsense.wanUpload" value={t("common.bytes", { value: wan["bytes transmitted"] })} />}
{wan && <Block label="opnsense.wanDownload" value={t("common.bytes", { value: wan["bytes received"] })} />}
{wan && (
<Block
label="opnsense.wanUpload"
value={t("common.bytes", { value: wan["bytes transmitted"] })}
highlightValue={wan["bytes transmitted"]}
/>
)}
{wan && (
<Block
label="opnsense.wanDownload"
value={t("common.bytes", { value: wan["bytes received"] })}
highlightValue={wan["bytes received"]}
/>
)}
</Container>
);
}

View File

@@ -52,8 +52,16 @@ export default function Component({ service }) {
return (
<Container service={service}>
<Block label="peanut.battery_charge" value={t("common.percent", { value: upsData.battery_charge })} />
<Block label="peanut.ups_load" value={t("common.percent", { value: upsData.ups_load })} />
<Block
label="peanut.battery_charge"
value={t("common.percent", { value: upsData.battery_charge })}
highlightValue={upsData.battery_charge}
/>
<Block
label="peanut.ups_load"
value={t("common.percent", { value: upsData.ups_load })}
highlightValue={upsData.ups_load}
/>
<Block label="peanut.ups_status" value={status} />
</Container>
);

View File

@@ -51,14 +51,25 @@ export default function Component({ service }) {
label="pfsense.load"
value={version === 1 ? systemData.data.load_avg[0] : systemData.data.cpu_load_avg[0]}
/>
<Block label="pfsense.memory" value={t("common.percent", { value: memUsage.toFixed(2) })} />
<Block
label="pfsense.memory"
value={t("common.percent", { value: memUsage.toFixed(2) })}
highlightValue={memUsage}
/>
<Block
label="pfsense.temp"
value={t("common.number", { value: systemData.data.temp_c, style: "unit", unit: "celsius" })}
highlightValue={systemData.data.temp_c}
/>
<Block label="pfsense.wanStatus" value={wan.status === "up" ? t("pfsense.up") : t("pfsense.down")} />
{showWanIP && <Block label="pfsense.wanIP" value={wan.ipaddr} />}
{showDiskUsage && <Block label="pfsense.disk" value={t("common.percent", { value: diskUsage.toFixed(2) })} />}
{showDiskUsage && (
<Block
label="pfsense.disk"
value={t("common.percent", { value: diskUsage.toFixed(2) })}
highlightValue={diskUsage}
/>
)}
</Container>
);
}

View File

@@ -67,8 +67,16 @@ export default function Component({ service }) {
<Container service={service}>
<Block label="proxmox.vms" value={`${runningVMs} / ${vms.length}`} />
<Block label="proxmox.lxc" value={`${runningLXC} / ${lxc.length}`} />
<Block label="resources.cpu" value={t("common.percent", { value: (usedCpu / maxCpu) * 100 })} />
<Block label="resources.mem" value={t("common.percent", { value: (usedMemory / maxMemory) * 100 })} />
<Block
label="resources.cpu"
value={t("common.percent", { value: (usedCpu / maxCpu) * 100 })}
highlightValue={(usedCpu / maxCpu) * 100}
/>
<Block
label="resources.mem"
value={t("common.percent", { value: (usedMemory / maxMemory) * 100 })}
highlightValue={(usedMemory / maxMemory) * 100}
/>
</Container>
);
}

View File

@@ -47,10 +47,22 @@ export default function Component({ service }) {
return (
<Container service={service}>
<Block label="proxmoxbackupserver.datastore_usage" value={t("common.percent", { value: datastoreUsage })} />
<Block
label="proxmoxbackupserver.datastore_usage"
value={t("common.percent", { value: datastoreUsage })}
highlightValue={datastoreUsage}
/>
<Block label="proxmoxbackupserver.failed_tasks_24h" value={failedTasks} />
<Block label="proxmoxbackupserver.cpu_usage" value={t("common.percent", { value: cpuUsage })} />
<Block label="proxmoxbackupserver.memory_usage" value={t("common.percent", { value: memoryUsage })} />
<Block
label="proxmoxbackupserver.cpu_usage"
value={t("common.percent", { value: cpuUsage })}
highlightValue={cpuUsage}
/>
<Block
label="proxmoxbackupserver.memory_usage"
value={t("common.percent", { value: memoryUsage })}
highlightValue={memoryUsage}
/>
</Container>
);
}

View File

@@ -25,8 +25,12 @@ export default function ProxmoxVM({ service }) {
return (
<Container service={service}>
<Block label="resources.cpu" value={t("common.percent", { value: data.cpu * 100 })} />
<Block label="resources.mem" value={t("common.bytes", { value: data.mem })} />
<Block
label="resources.cpu"
value={t("common.percent", { value: data.cpu * 100 })}
highlightValue={data.cpu * 100}
/>
<Block label="resources.mem" value={t("common.bytes", { value: data.mem })} highlightValue={data.mem} />
</Container>
);
}

View File

@@ -26,7 +26,11 @@ export default function Component({ service }) {
return (
<Container service={service}>
<Block label="pyload.speed" value={t("common.byterate", { value: pyloadData.speed })} />
<Block
label="pyload.speed"
value={t("common.byterate", { value: pyloadData.speed })}
highlightValue={pyloadData.speed}
/>
<Block label="pyload.active" value={t("common.number", { value: pyloadData.active })} />
<Block label="pyload.queue" value={t("common.number", { value: pyloadData.queue })} />
<Block label="pyload.total" value={t("common.number", { value: pyloadData.total })} />

View File

@@ -10,28 +10,13 @@ export default function Component({ service }) {
const { t } = useTranslation();
const { widget } = service;
const { data: transferData, error: transferError } = useWidgetAPI(widget, "transfer");
const { data: totalCountData, error: totalCountError } = useWidgetAPI(widget, "torrentCount");
const { data: completedCountData, error: completedCountError } = useWidgetAPI(widget, "torrentCount", {
filter: "completed",
});
const { data: leechTorrentData, error: leechTorrentError } = useWidgetAPI(
widget,
widget?.enableLeechProgress ? "torrents" : "",
widget?.enableLeechProgress ? { filter: "downloading" } : undefined,
);
const { data: torrentData, error: torrentError } = useWidgetAPI(widget, "torrents");
const apiError = transferError || totalCountError || completedCountError || leechTorrentError;
if (apiError) {
return <Container service={service} error={apiError} />;
if (torrentError) {
return <Container service={service} error={torrentError} />;
}
if (
!transferData ||
totalCountData === undefined ||
completedCountData === undefined ||
(widget?.enableLeechProgress && !leechTorrentData)
) {
if (!torrentData) {
return (
<Container service={service}>
<Block label="qbittorrent.leech" />
@@ -42,15 +27,24 @@ export default function Component({ service }) {
);
}
const rateDl = Number(transferData?.dl_info_speed ?? 0);
const rateUl = Number(transferData?.up_info_speed ?? 0);
const totalCount = Number(totalCountData?.all ?? totalCountData?.count ?? totalCountData ?? 0);
const completedCount = Number(
completedCountData?.completed ?? completedCountData?.count ?? completedCountData?.all ?? completedCountData ?? 0,
);
const leech = Math.max(0, totalCount - completedCount);
let rateDl = 0;
let rateUl = 0;
let completed = 0;
const leechTorrents = [];
const leechTorrents = Array.isArray(leechTorrentData) ? [...leechTorrentData] : [];
for (let i = 0; i < torrentData.length; i += 1) {
const torrent = torrentData[i];
rateDl += torrent.dlspeed;
rateUl += torrent.upspeed;
if (torrent.progress === 1) {
completed += 1;
}
if (torrent.state.includes("DL") || torrent.state === "downloading") {
leechTorrents.push(torrent);
}
}
const leech = torrentData.length - completed;
const statePriority = [
"downloading",
"forcedDL",
@@ -74,9 +68,17 @@ export default function Component({ service }) {
<>
<Container service={service}>
<Block label="qbittorrent.leech" value={t("common.number", { value: leech })} />
<Block label="qbittorrent.download" value={t("common.bibyterate", { value: rateDl, decimals: 1 })} />
<Block label="qbittorrent.seed" value={t("common.number", { value: completedCount })} />
<Block label="qbittorrent.upload" value={t("common.bibyterate", { value: rateUl, decimals: 1 })} />
<Block
label="qbittorrent.download"
value={t("common.bibyterate", { value: rateDl, decimals: 1 })}
highlightValue={rateDl}
/>
<Block label="qbittorrent.seed" value={t("common.number", { value: completed })} />
<Block
label="qbittorrent.upload"
value={t("common.bibyterate", { value: rateUl, decimals: 1 })}
highlightValue={rateUl}
/>
</Container>
{widget?.enableLeechProgress &&
leechTorrents.map((queueEntry) => (

View File

@@ -34,33 +34,13 @@ describe("widgets/qbittorrent/component", () => {
expect(screen.getByText("qbittorrent.upload")).toBeInTheDocument();
});
it("uses lightweight endpoints for counts/rates and filtered torrents for leech progress", () => {
useWidgetAPI.mockImplementation((_widget, endpoint, query) => {
if (endpoint === "transfer") {
return { data: { dl_info_speed: 15, up_info_speed: 3 }, error: undefined };
}
if (endpoint === "torrentCount" && !query) {
return { data: 2, error: undefined };
}
if (endpoint === "torrentCount" && query?.filter === "completed") {
return { data: 1, error: undefined };
}
if (endpoint === "torrents" && query?.filter === "downloading") {
return {
data: [
{
name: "B",
progress: 0.5,
state: "downloading",
eta: 60,
size: 100,
amount_left: 50,
},
],
error: undefined,
};
}
return { data: undefined, error: undefined };
it("computes leech/seed counts and upload/download rates, and can render leech progress entries", () => {
useWidgetAPI.mockReturnValue({
data: [
{ name: "A", dlspeed: 10, upspeed: 1, progress: 1, state: "uploading" },
{ name: "B", dlspeed: 5, upspeed: 2, progress: 0.5, state: "downloading", eta: 60, size: 100, amount_left: 50 },
],
error: undefined,
});
const service = { widget: { type: "qbittorrent", enableLeechProgress: true } };

View File

@@ -4,16 +4,8 @@ const widget = {
proxyHandler: qbittorrentProxyHandler,
mappings: {
transfer: {
endpoint: "transfer/info",
},
torrentCount: {
endpoint: "torrents/count",
optionalParams: ["filter"],
},
torrents: {
endpoint: "torrents/info",
optionalParams: ["filter"],
},
},
};

View File

@@ -34,8 +34,8 @@ export default function Component({ service }) {
return (
<Container service={service}>
<Block label="rutorrent.active" value={active.length} />
<Block label="rutorrent.upload" value={t("common.byterate", { value: upload })} />
<Block label="rutorrent.download" value={t("common.byterate", { value: download })} />
<Block label="rutorrent.upload" value={t("common.byterate", { value: upload })} highlightValue={upload} />
<Block label="rutorrent.download" value={t("common.byterate", { value: download })} highlightValue={download} />
</Container>
);
}

View File

@@ -54,6 +54,7 @@ export default function Component({ service }) {
style: "unit",
unit: "millisecond",
})}
highlightValue={speedtestData.data.ping}
/>
</Container>
);

View File

@@ -29,10 +29,15 @@ export default function Component({ service }) {
<Container service={service}>
<Block label="strelaysrv.numActiveSessions" value={t("common.number", { value: statsData.numActiveSessions })} />
<Block label="strelaysrv.numConnections" value={t("common.number", { value: statsData.numConnections })} />
<Block label="strelaysrv.dataRelayed" value={t("common.bytes", { value: statsData.bytesProxied })} />
<Block
label="strelaysrv.dataRelayed"
value={t("common.bytes", { value: statsData.bytesProxied })}
highlightValue={statsData.bytesProxied}
/>
<Block
label="strelaysrv.transferRate"
value={t("common.bitrate", { value: statsData.kbps10s1m5m15m30m60m[5] })}
highlightValue={statsData.kbps10s1m5m15m30m60m[5]}
/>
</Container>
);

View File

@@ -46,7 +46,7 @@ export default function Component({ service }) {
<Block label="tdarr.queue" value={t("common.number", { value: queue })} />
<Block label="tdarr.processed" value={t("common.number", { value: processed })} />
<Block label="tdarr.errored" value={t("common.number", { value: errored })} />
<Block label="tdarr.saved" value={t("common.bytes", { value: saved })} />
<Block label="tdarr.saved" value={t("common.bytes", { value: saved })} highlightValue={saved} />
</Container>
);
}

View File

@@ -36,9 +36,9 @@ export default function Component({ service }) {
return (
<Container service={service}>
<Block label="transmission.leech" value={t("common.number", { value: leech })} />
<Block label="transmission.download" value={t("common.byterate", { value: rateDl })} />
<Block label="transmission.download" value={t("common.byterate", { value: rateDl })} highlightValue={rateDl} />
<Block label="transmission.seed" value={t("common.number", { value: completed })} />
<Block label="transmission.upload" value={t("common.byterate", { value: rateUl })} />
<Block label="transmission.upload" value={t("common.byterate", { value: rateUl })} highlightValue={rateUl} />
</Container>
);
}

View File

@@ -1,19 +1,11 @@
import cache from "memory-cache";
import getServiceWidget from "utils/config/service-helpers";
import { getPrivateWidgetOptions } from "utils/config/widget-helpers";
import createLogger from "utils/logger";
import { formatApiCall } from "utils/proxy/api-helpers";
import { addCookieToJar, setCookieHeader } from "utils/proxy/cookie-jar";
import createUnifiProxyHandler from "utils/proxy/handlers/unifi";
import { httpProxy } from "utils/proxy/http";
import widgets from "widgets/widgets";
const udmpPrefix = "/proxy/network";
const proxyName = "unifiProxyHandler";
const prefixCacheKey = `${proxyName}__prefix`;
const logger = createLogger(proxyName);
async function getWidget(req) {
async function getWidget(req, logger) {
const { group, service, index } = req.query;
let widget = null;
@@ -43,100 +35,36 @@ async function getWidget(req) {
return widget;
}
async function login(widget, csrfToken) {
const endpoint = widget.prefix === udmpPrefix ? "auth/login" : "login";
const api = widgets?.[widget.type]?.api?.replace("{prefix}", ""); // no prefix for login url
const loginUrl = new URL(formatApiCall(api, { endpoint, ...widget }));
const loginBody = { username: widget.username, password: widget.password, remember: true, rememberMe: true };
const headers = { "Content-Type": "application/json" };
if (csrfToken) {
headers["X-CSRF-TOKEN"] = csrfToken;
}
const [status, contentType, data, responseHeaders] = await httpProxy(loginUrl, {
method: "POST",
body: JSON.stringify(loginBody),
headers,
});
return [status, contentType, data, responseHeaders];
}
export default async function unifiProxyHandler(req, res) {
const widget = await getWidget(req);
const { service } = req.query;
if (!widget) {
return res.status(400).json({ error: "Invalid proxy service type" });
}
const api = widgets?.[widget.type]?.api;
if (!api) {
return res.status(403).json({ error: "Service does not support API calls" });
}
let [status, contentType, data, responseHeaders] = [];
let prefix = cache.get(`${prefixCacheKey}.${service}`);
let csrfToken;
async function resolveRequestContext({ cachedPrefix, widget }) {
const headers = {};
if (widget.key) {
prefix = udmpPrefix;
headers["X-API-KEY"] = widget.key;
headers["Accept"] = "application/json";
} else if (prefix === null) {
// auto detect if we're talking to a UDM Pro or Network API device, and cache the result
// so that we don't make two requests each time data from Unifi is required
[status, contentType, data, responseHeaders] = await httpProxy(widget.url);
prefix = "";
if (responseHeaders?.["x-csrf-token"]) {
// Unifi OS < 3.2.5 passes & requires csrf-token
prefix = udmpPrefix;
csrfToken = responseHeaders["x-csrf-token"];
} else if (
responseHeaders?.["access-control-expose-headers"] ||
responseHeaders?.["Access-Control-Expose-Headers"]
) {
// Unifi OS ≥ 3.2.5 doesnt pass csrf token but still uses different endpoint, same with Network API
prefix = udmpPrefix;
}
}
cache.put(`${prefixCacheKey}.${service}`, prefix);
widget.prefix = prefix;
const { endpoint } = req.query;
const url = new URL(formatApiCall(api, { endpoint, ...widget }));
const params = { method: "GET", headers };
setCookieHeader(url, params);
[status, contentType, data, responseHeaders] = await httpProxy(url, params);
if (status === 401 && !widget.key) {
logger.debug("Unifi isn't logged in or rejected the reqeust, attempting login.");
if (responseHeaders?.["x-csrf-token"]) {
csrfToken = responseHeaders["x-csrf-token"];
}
[status, contentType, data, responseHeaders] = await login(widget, csrfToken);
if (status !== 200) {
logger.error("HTTP %d logging in to Unifi. Data: %s", status, data);
return res.status(status).json({ error: { message: `HTTP Error ${status}`, url, data } });
}
const json = JSON.parse(data.toString());
if (!(json?.meta?.rc === "ok" || json?.login_time || json?.update_time)) {
logger.error("Error logging in to Unifi: Data: %s", data);
return res.status(401).end(data);
}
addCookieToJar(url, responseHeaders);
setCookieHeader(url, params);
logger.debug("Retrying Unifi request after login.");
[status, contentType, data, responseHeaders] = await httpProxy(url, params);
headers.Accept = "application/json";
return { headers, prefix: udmpPrefix };
}
if (status !== 200) {
logger.error("HTTP %d getting data from Unifi endpoint %s. Data: %s", status, url.href, data);
return res.status(status).json({ error: { message: `HTTP Error ${status}`, url, data } });
if (cachedPrefix !== null) {
return { headers, prefix: cachedPrefix };
}
if (contentType) res.setHeader("Content-Type", contentType);
return res.status(status).send(data);
const [, , , responseHeaders] = await httpProxy(widget.url);
let prefix = "";
let csrfToken;
if (responseHeaders?.["x-csrf-token"]) {
prefix = udmpPrefix;
csrfToken = responseHeaders["x-csrf-token"];
} else if (responseHeaders?.["access-control-expose-headers"] || responseHeaders?.["Access-Control-Expose-Headers"]) {
prefix = udmpPrefix;
}
return { csrfToken, headers, prefix };
}
export default createUnifiProxyHandler({
proxyName: "unifiProxyHandler",
resolveWidget: getWidget,
resolveRequestContext,
getLoginEndpoint: ({ prefix }) => (prefix === udmpPrefix ? "auth/login" : "login"),
});

View File

@@ -89,4 +89,58 @@ describe("widgets/unifi/proxy", () => {
expect(res.statusCode).toBe(200);
expect(res.body).toEqual(Buffer.from("data"));
});
it("uses unifi_console private widget config for the info widget path", async () => {
getPrivateWidgetOptions.mockResolvedValue({
url: "http://console",
username: "u",
password: "p",
});
httpProxy
.mockResolvedValueOnce([200, "text/html", Buffer.from(""), { "x-csrf-token": "csrf" }])
.mockResolvedValueOnce([200, "application/json", Buffer.from("data"), {}]);
const req = {
query: {
group: "unifi_console",
service: "unifi_console",
endpoint: "self",
query: JSON.stringify({ index: 2 }),
},
};
const res = createMockRes();
await unifiProxyHandler(req, res);
expect(getPrivateWidgetOptions).toHaveBeenCalledWith("unifi_console", 2);
expect(httpProxy.mock.calls[1][0].toString()).toContain("/proxy/network/api/self");
expect(res.statusCode).toBe(200);
});
it("uses the API key flow without attempting login", async () => {
getServiceWidget.mockResolvedValue({
type: "unifi",
key: "secret",
url: "http://unifi",
});
httpProxy.mockResolvedValueOnce([200, "application/json", Buffer.from("data"), {}]);
const req = { query: { group: "g", service: "svc", endpoint: "self", index: "0" } };
const res = createMockRes();
await unifiProxyHandler(req, res);
expect(httpProxy).toHaveBeenCalledTimes(1);
expect(httpProxy.mock.calls[0][0].toString()).toContain("/proxy/network/api/self");
expect(httpProxy.mock.calls[0][1]).toMatchObject({
headers: {
Accept: "application/json",
"X-API-KEY": "secret",
},
method: "GET",
});
expect(res.statusCode).toBe(200);
});
});

View File

@@ -58,35 +58,59 @@ export default function Component({ service }) {
return (
<Container service={service}>
<Block label="unraid.status" value={t(`unraid.${data.arrayState}`)} />
<Block label="unraid.memoryAvailable" value={t("common.bbytes", { value: data.memoryAvailable })} />
<Block label="unraid.memoryUsed" value={t("common.bbytes", { value: data.memoryUsed })} />
<Block
label="unraid.memoryAvailable"
value={t("common.bbytes", { value: data.memoryAvailable })}
highlightValue={data.memoryAvailable}
/>
<Block
label="unraid.memoryUsed"
value={t("common.bbytes", { value: data.memoryUsed })}
highlightValue={data.memoryUsed}
/>
<Block
field="unraid.memoryPercent"
label="unraid.memoryUsed"
value={t("common.percent", { value: data.memoryUsedPercent })}
highlightValue={data.memoryUsedPercent}
/>
<Block
label="unraid.cpu"
value={t("common.percent", { value: data.cpuPercent })}
highlightValue={data.cpuPercent}
/>
<Block label="unraid.cpu" value={t("common.percent", { value: data.cpuPercent })} />
<Block label="unraid.notifications" value={t("common.number", { value: data.unreadNotifications })} />
<Block
field="unraid.arrayUsedSpace"
label="unraid.arrayUsed"
value={t("common.bytes", { value: data.arrayUsed })}
highlightValue={data.arrayUsed}
/>
<Block
label="unraid.arrayFree"
value={t("common.bytes", { value: data.arrayFree })}
highlightValue={data.arrayFree}
/>
<Block label="unraid.arrayFree" value={t("common.bytes", { value: data.arrayFree })} />
<Block
field="unraid.arrayUsedPercent"
label="unraid.arrayUsed"
value={t("common.percent", { value: data.arrayUsedPercent })}
highlightValue={data.arrayUsedPercent}
/>
{...POOLS.flatMap((pool) =>
POOL_FIELDS.map(({ param, label, valueKey, valueType }) => (
<Block
key={`${pool}-${param}`}
field={`unraid.${pool}${param}`}
label={t(`unraid.${label}`, { pool: widget?.[pool] || pool })}
value={t(valueType, { value: data.caches?.[widget?.[pool]]?.[valueKey] || "-" })}
/>
)),
POOL_FIELDS.map(({ param, label, valueKey, valueType }) => {
const poolValue = data.caches?.[widget?.[pool]]?.[valueKey] || "-";
return (
<Block
key={`${pool}-${param}`}
field={`unraid.${pool}${param}`}
label={t(`unraid.${label}`, { pool: widget?.[pool] || pool })}
value={t(valueType, { value: poolValue })}
highlightValue={poolValue}
/>
);
}),
)}
</Container>
);

View File

@@ -50,7 +50,7 @@ export default function Component({ service }) {
<Container service={service}>
<Block label="uptimekuma.up" value={t("common.number", { value: sitesUp })} />
<Block label="uptimekuma.down" value={t("common.number", { value: sitesDown })} />
<Block label="uptimekuma.uptime" value={t("common.percent", { value: uptime })} />
<Block label="uptimekuma.uptime" value={t("common.percent", { value: uptime })} highlightValue={Number(uptime)} />
{incidentTime && (
<Block
label="uptimekuma.incident"

View File

@@ -18,7 +18,7 @@ export default function Component({ service }) {
if (!watchData) {
return (
<Container service={service}>
<Block label="watchtower.containers_scanned " />
<Block label="watchtower.containers_scanned" />
<Block label="watchtower.containers_updated" />
<Block label="watchtower.containers_failed" />
</Container>