Compare commits

..

59 Commits

Author SHA1 Message Date
Louis Lam
aec80b53d5 Update to 1.19.2 2022-12-27 00:22:52 +08:00
Louis Lam
06852bbf0d Fix the UI broken after removed a monitor 2022-12-27 00:22:09 +08:00
Louis Lam
056d957c1e Update to 1.19.1 2022-12-26 23:49:20 +08:00
Louis Lam
e12225e595 Fix #2475 #2468 #2455, add Accept-Encoding only if encountered the abort error 2022-12-26 21:00:46 +08:00
Louis Lam
1b6c587cc9 Fix #2472 2022-12-26 14:46:29 +08:00
Louis Lam
4a1db336df Merge pull request #2465 from augustin64/patch-1
(fr) Fix typo
2022-12-25 19:18:46 +08:00
Augustin
9e9c5cd1d2 (fr) Fix typo 2022-12-24 19:41:55 +01:00
Louis Lam
1e689d99b4 Merge pull request #2393 from zImPatrick/discord-docker-fix
Fix discord notification not sending when docker container goes down
2022-12-24 14:26:53 +08:00
Louis Lam
14fffcf06b Globally fix if heartbeatJSON["msg"] is undefined 2022-12-24 14:23:50 +08:00
Louis Lam
6962e056ce Update to 1.19.0 2022-12-23 22:44:49 +08:00
Louis Lam
b7a898326e Merge pull request #2437 from MrEddX/bulgarian
Update bg-BG.js
2022-12-19 20:22:47 +08:00
MrEddX
a89be0e6d4 Update bg-BG.js
Translation Update
2022-12-19 13:37:42 +02:00
Louis Lam
b58b83541b Merge pull request #2428 from rbunpat/master
Update th-TH.js
2022-12-18 15:40:40 +08:00
Cyril59310
df4f91c20d Update EN language (#2429)
* Update EN language
2022-12-18 15:39:54 +08:00
Rachatat Bunpat
fc6b040a4e Update th-TH.js 2022-12-17 17:34:03 +07:00
Louis Lam
9838f36b50 Merge pull request #2418 from Johno95CZ/patch-1
Update cs-CZ.js
2022-12-17 17:44:55 +08:00
Louis Lam
a60072adbc Merge pull request #2423 from rbunpat/master
Update th-TH.js
2022-12-17 17:43:51 +08:00
Louis Lam
e7aeb6f6bf Merge pull request #2422 from Justman10000/master
Update
2022-12-17 17:43:25 +08:00
Rachatat Bunpat
06e570c52d Update th-TH.js 2022-12-16 19:15:14 +07:00
Justman10000
890b8f8333 Updated German 2022-12-16 10:42:41 +00:00
Louis Lam
df21f7da76 Check login for initServerTimezone 2022-12-16 12:56:40 +08:00
JohnoCZ
20c37a70f7 Update cs-CZ.js 2022-12-15 14:35:59 +01:00
Louis Lam
b75db27658 Fix lint 2022-12-15 13:57:28 +08:00
Louis Lam
765d8e1297 Fix #2318 2022-12-15 13:39:48 +08:00
Louis Lam
9dc2cc1f0d Copy timezone.js from dayjs 2022-12-15 13:05:04 +08:00
Louis Lam
2532becf61 Update to 1.19.0-beta.2 2022-12-14 23:37:00 +08:00
Louis Lam
6154776b34 Merge pull request #2409 from Justman10000/master
Update
2022-12-14 22:39:00 +08:00
Louis Lam
7e6b92203d Merge pull request #2406 from MrEddX/bulgarian
Bulgarian
2022-12-14 22:38:13 +08:00
Louis Lam
1da00d19fd Try to fix incorrect header check 2022-12-14 21:34:13 +08:00
Justman10000
da4bdab4f6 Updated german 2022-12-14 13:16:32 +00:00
MrEddX
86ab97ef56 Update bg-BG.js
Translation Update
2022-12-14 09:56:28 +02:00
MrEddX
345b0c1829 Update bg-BG.js
Fixed Style
2022-12-14 09:49:31 +02:00
MrEddX
2ac87fcea7 Update bg-BG.js
Fixed Typos
2022-12-14 09:26:43 +02:00
Cyril59310
4862bec965 Update Fr language + added variable for missing translation (#2395)
* Update FR language
2022-12-13 22:00:54 +08:00
Louis Lam
aa784fb3b2 Fix #2394 2022-12-13 16:48:23 +08:00
Louis Lam
466b403a96 Handle unexpected error of checkCertificate 2022-12-13 02:21:12 +08:00
zImPatrick
f32441e2f6 fix discord notification not sending when docker container is down 2022-12-12 18:05:10 +01:00
Louis Lam
39987ba9ac Init server timezone 2022-12-12 22:57:57 +08:00
Louis Lam
3b87209e26 Add configurable dns cache 2022-12-12 17:19:22 +08:00
Louis Lam
e6dc0a0293 Slightly improve maintenance page's css on mobile 2022-12-12 16:06:17 +08:00
Louis Lam
5c5a339a36 Add links for status pages and maintenance for mobile (Fix #2257) 2022-12-12 15:54:46 +08:00
Louis Lam
3040bd41d9 Speed up armv7 build time of healthcheck by using go compiler cross-build feature in the host 2022-12-12 15:42:00 +08:00
Louis Lam
3b58fd3b3c Cache uptime 2022-12-11 21:33:26 +08:00
Louis Lam
bc86f8bb5f Reset busy_timeout to default 2022-12-11 20:25:15 +08:00
Louis Lam
ab5f6dc82c Fix css 2022-12-11 18:52:24 +08:00
Louis Lam
5176fd02c1 Fix healthcheck do not check https 2022-12-10 23:30:32 +08:00
Louis Lam
02b5cae577 Fix #2371 by left join maintenance_timeslot 2022-12-09 21:03:12 +08:00
Louis Lam
54aa7d5dca Merge remote-tracking branch 'origin/master' 2022-12-08 23:22:09 +08:00
Louis Lam
4cd5b5563f Fix #1145 2022-12-08 23:21:55 +08:00
Louis Lam
f1c30204b6 Merge pull request #2373 from saw303/master
Fixed some typos in the German translations 🇩🇪🇨🇭
2022-12-08 23:01:48 +08:00
Louis Lam
e478084ff9 Fix Uptime Kuma cannot be stopped 2022-12-08 19:13:47 +08:00
Louis Lam
2dff7dd380 Make dockerfile slightly clear and improve the build flow 2022-12-08 18:29:17 +08:00
Louis Lam
9bfa43100b Compile healthcheck.go 2022-12-08 18:29:17 +08:00
Louis Lam
ad5e1957b1 Deprecate healthcheck.js 2022-12-08 18:29:17 +08:00
Louis Lam
cc68ebca39 Convert healthcheck.js into go-lang 2022-12-08 18:29:17 +08:00
Silvio Wangler
aa27d976c2 Fixed some typos in the German translations 🇩🇪🇨🇭 2022-12-07 09:10:05 +01:00
Louis Lam
ecbc0f0477 Merge pull request #2369 from saw303/master
Added new language German (Switzerland)
2022-12-07 15:14:52 +08:00
Silvio Wangler
92caec95fe Added new language German (Switzerland) 2022-12-06 13:43:37 +01:00
Louis Lam
2c3abdc146 [stale-bot] Do not close pr 2022-12-05 20:11:28 +08:00
48 changed files with 1713 additions and 183 deletions

View File

@@ -31,6 +31,9 @@ tsconfig.json
/tmp /tmp
/babel.config.js /babel.config.js
/ecosystem.config.js /ecosystem.config.js
/extra/healthcheck.exe
/extra/healthcheck
### .gitignore content (commented rules are duplicated) ### .gitignore content (commented rules are duplicated)

View File

@@ -19,3 +19,6 @@ indent_size = 2
[*.vue] [*.vue]
trim_trailing_whitespace = false trim_trailing_whitespace = false
[*.go]
indent_style = tab

View File

@@ -12,13 +12,11 @@ jobs:
- uses: actions/stale@v5 - uses: actions/stale@v5
with: with:
stale-issue-message: 'We are clearing up our old issues and your ticket has been open for 3 months with no activity. Remove stale label or comment or this will be closed in 2 days.' stale-issue-message: 'We are clearing up our old issues and your ticket has been open for 3 months with no activity. Remove stale label or comment or this will be closed in 2 days.'
stale-pr-message: 'We are clearing up our old Pull Requests and yours has been open for 3 months with no activity. Remove stale label or comment or this will be closed in 2 days.'
close-issue-message: 'This issue was closed because it has been stalled for 2 days with no activity.' close-issue-message: 'This issue was closed because it has been stalled for 2 days with no activity.'
close-pr-message: 'This PR was closed because it has been stalled for 2 days with no activity.'
days-before-stale: 90 days-before-stale: 90
days-before-close: 2 days-before-close: 2
days-before-pr-stale: 999999999
days-before-pr-close: 1
exempt-issue-labels: 'News,Medium,High,discussion,bug,doc,feature-request' exempt-issue-labels: 'News,Medium,High,discussion,bug,doc,feature-request'
exempt-pr-labels: 'awaiting-approval,work-in-progress,enhancement,feature-request'
exempt-issue-assignees: 'louislam' exempt-issue-assignees: 'louislam'
exempt-pr-assignees: 'louislam'
operations-per-run: 200 operations-per-run: 200

4
.gitignore vendored
View File

@@ -16,3 +16,7 @@ dist-ssr
cypress/videos cypress/videos
cypress/screenshots cypress/screenshots
/extra/healthcheck.exe
/extra/healthcheck
/extra/healthcheck-armv7

View File

@@ -1,30 +1,57 @@
############################################
# Build in Golang
# Run npm run build-healthcheck-armv7 in the host first, another it will be super slow where it is building the armv7 healthcheck
############################################
FROM golang:1.19.4-buster AS build_healthcheck
WORKDIR /app
ARG TARGETPLATFORM
COPY ./extra/ ./extra/
# Compile healthcheck.go
RUN apt update
RUN apt --yes --no-install-recommends install curl
RUN curl -sL https://deb.nodesource.com/setup_18.x | bash
RUN apt --yes --no-install-recommends install nodejs
RUN node -v
RUN node ./extra/build-healthcheck.js $TARGETPLATFORM
############################################
# Build in Node.js
############################################
FROM louislam/uptime-kuma:base-debian AS build FROM louislam/uptime-kuma:base-debian AS build
WORKDIR /app WORKDIR /app
ENV PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=1 ENV PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=1
COPY . . COPY . .
COPY --from=build_healthcheck /app/extra/healthcheck /app/extra/healthcheck
RUN npm ci --production && \ RUN npm ci --production && \
chmod +x /app/extra/entrypoint.sh chmod +x /app/extra/entrypoint.sh
############################################
# ⭐ Main Image
############################################
FROM louislam/uptime-kuma:base-debian AS release FROM louislam/uptime-kuma:base-debian AS release
WORKDIR /app WORKDIR /app
# Copy app files from build layer # Copy app files from build layer
COPY --from=build /app /app COPY --from=build /app /app
EXPOSE 3001 EXPOSE 3001
VOLUME ["/app/data"] VOLUME ["/app/data"]
HEALTHCHECK --interval=60s --timeout=30s --start-period=180s --retries=5 CMD node extra/healthcheck.js HEALTHCHECK --interval=60s --timeout=30s --start-period=180s --retries=5 CMD extra/healthcheck
ENTRYPOINT ["/usr/bin/dumb-init", "--", "extra/entrypoint.sh"] ENTRYPOINT ["/usr/bin/dumb-init", "--", "extra/entrypoint.sh"]
CMD ["node", "server/server.js"] CMD ["node", "server/server.js"]
############################################
# Mark as Nightly
############################################
FROM release AS nightly FROM release AS nightly
RUN npm run mark-as-nightly RUN npm run mark-as-nightly
############################################
# Build an image for testing pr # Build an image for testing pr
############################################
FROM louislam/uptime-kuma:base-debian AS pr-test FROM louislam/uptime-kuma:base-debian AS pr-test
WORKDIR /app WORKDIR /app
@@ -54,8 +81,9 @@ VOLUME ["/app/data"]
HEALTHCHECK --interval=60s --timeout=30s --start-period=180s --retries=5 CMD node extra/healthcheck.js HEALTHCHECK --interval=60s --timeout=30s --start-period=180s --retries=5 CMD node extra/healthcheck.js
CMD ["npm", "run", "start-pr-test"] CMD ["npm", "run", "start-pr-test"]
############################################
# Upload the artifact to Github # Upload the artifact to Github
############################################
FROM louislam/uptime-kuma:base-debian AS upload-artifact FROM louislam/uptime-kuma:base-debian AS upload-artifact
WORKDIR / WORKDIR /
RUN apt update && \ RUN apt update && \

View File

@@ -0,0 +1,27 @@
const childProcess = require("child_process");
const fs = require("fs");
const platform = process.argv[2];
if (!platform) {
console.error("No platform??");
process.exit(1);
}
if (platform === "linux/arm/v7") {
console.log("Arch: armv7");
if (fs.existsSync("./extra/healthcheck-armv7")) {
fs.renameSync("./extra/healthcheck-armv7", "./extra/healthcheck");
console.log("Already built in the host, skip.");
process.exit(0);
} else {
console.log("prebuilt not found, it will be slow! You should execute `npm run build-healthcheck-armv7` before build.");
}
} else {
if (fs.existsSync("./extra/healthcheck-armv7")) {
fs.rmSync("./extra/healthcheck-armv7");
}
}
const output = childProcess.execSync("go build -x -o ./extra/healthcheck ./extra/healthcheck.go").toString("utf8");
console.log(output);

77
extra/healthcheck.go Normal file
View File

@@ -0,0 +1,77 @@
package main
import (
"crypto/tls"
"io/ioutil"
"log"
"net/http"
"os"
"runtime"
"time"
)
func main() {
isFreeBSD := runtime.GOOS == "freebsd"
// process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
http.DefaultTransport.(*http.Transport).TLSClientConfig = &tls.Config{
InsecureSkipVerify: true,
}
client := http.Client{
Timeout: 28 * time.Second,
}
sslKey := os.Getenv("UPTIME_KUMA_SSL_KEY")
if len(sslKey) == 0 {
sslKey = os.Getenv("SSL_KEY")
}
sslCert := os.Getenv("UPTIME_KUMA_SSL_CERT")
if len(sslCert) == 0 {
sslCert = os.Getenv("SSL_CERT")
}
hostname := os.Getenv("UPTIME_KUMA_HOST")
if len(hostname) == 0 && !isFreeBSD {
hostname = os.Getenv("HOST")
}
if len(hostname) == 0 {
hostname = "127.0.0.1"
}
port := os.Getenv("UPTIME_KUMA_PORT")
if len(port) == 0 {
port = os.Getenv("PORT")
}
if len(port) == 0 {
port = "3001"
}
protocol := ""
if len(sslKey) != 0 && len(sslCert) != 0 {
protocol = "https"
} else {
protocol = "http"
}
url := protocol + "://" + hostname + ":" + port
log.Println("Checking " + url)
resp, err := client.Get(url)
if err != nil {
log.Fatalln(err)
}
defer resp.Body.Close()
_, err = ioutil.ReadAll(resp.Body)
if err != nil {
log.Fatalln(err)
}
log.Printf("Health Check OK [Res Code: %d]\n", resp.StatusCode)
}

View File

@@ -1,4 +1,5 @@
/* /*
* ⚠️ Deprecated: Changed to healthcheck.go, it will be deleted in the future.
* This script should be run after a period of time (180s), because the server may need some time to prepare. * This script should be run after a period of time (180s), because the server may need some time to prepare.
*/ */
const { FBSD } = require("../server/util-server"); const { FBSD } = require("../server/util-server");

4
package-lock.json generated
View File

@@ -1,12 +1,12 @@
{ {
"name": "uptime-kuma", "name": "uptime-kuma",
"version": "1.19.0-beta.0", "version": "1.19.0-beta.1",
"lockfileVersion": 2, "lockfileVersion": 2,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "uptime-kuma", "name": "uptime-kuma",
"version": "1.19.0-beta.0", "version": "1.19.0-beta.1",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@grpc/grpc-js": "~1.7.3", "@grpc/grpc-js": "~1.7.3",

View File

@@ -1,6 +1,6 @@
{ {
"name": "uptime-kuma", "name": "uptime-kuma",
"version": "1.19.0-beta.1", "version": "1.19.2",
"license": "MIT", "license": "MIT",
"repository": { "repository": {
"type": "git", "type": "git",
@@ -38,7 +38,7 @@
"build-docker-nightly-amd64": "docker buildx build -f docker/dockerfile --platform linux/amd64 -t louislam/uptime-kuma:nightly-amd64 --target nightly . --push --progress plain", "build-docker-nightly-amd64": "docker buildx build -f docker/dockerfile --platform linux/amd64 -t louislam/uptime-kuma:nightly-amd64 --target nightly . --push --progress plain",
"build-docker-pr-test": "docker buildx build -f docker/dockerfile --platform linux/amd64,linux/arm64 -t louislam/uptime-kuma:pr-test --target pr-test . --push", "build-docker-pr-test": "docker buildx build -f docker/dockerfile --platform linux/amd64,linux/arm64 -t louislam/uptime-kuma:pr-test --target pr-test . --push",
"upload-artifacts": "docker buildx build -f docker/dockerfile --platform linux/amd64 -t louislam/uptime-kuma:upload-artifact --build-arg VERSION --build-arg GITHUB_TOKEN --target upload-artifact . --progress plain", "upload-artifacts": "docker buildx build -f docker/dockerfile --platform linux/amd64 -t louislam/uptime-kuma:upload-artifact --build-arg VERSION --build-arg GITHUB_TOKEN --target upload-artifact . --progress plain",
"setup": "git checkout 1.18.5 && npm ci --production && npm run download-dist", "setup": "git checkout 1.19.2 && npm ci --production && npm run download-dist",
"download-dist": "node extra/download-dist.js", "download-dist": "node extra/download-dist.js",
"mark-as-nightly": "node extra/mark-as-nightly.js", "mark-as-nightly": "node extra/mark-as-nightly.js",
"reset-password": "node extra/reset-password.js", "reset-password": "node extra/reset-password.js",
@@ -60,7 +60,8 @@
"start-pr-test": "node extra/checkout-pr.js && npm install && npm run dev", "start-pr-test": "node extra/checkout-pr.js && npm install && npm run dev",
"cy:test": "node test/prepare-test-server.js && node server/server.js --port=3002 --data-dir=./data/test/ --e2e", "cy:test": "node test/prepare-test-server.js && node server/server.js --port=3002 --data-dir=./data/test/ --e2e",
"cy:run": "npx cypress run --browser chrome --headless --config-file ./config/cypress.config.js", "cy:run": "npx cypress run --browser chrome --headless --config-file ./config/cypress.config.js",
"cypress-open": "concurrently -k -r \"node test/prepare-test-server.js && node server/server.js --port=3002 --data-dir=./data/test/\" \"cypress open --config-file ./config/cypress.config.js\"" "cypress-open": "concurrently -k -r \"node test/prepare-test-server.js && node server/server.js --port=3002 --data-dir=./data/test/\" \"cypress open --config-file ./config/cypress.config.js\"",
"build-healthcheck-armv7": "cross-env GOOS=linux GOARCH=arm GOARM=7 go build -x -o ./extra/healthcheck-armv7 ./extra/healthcheck.go"
}, },
"dependencies": { "dependencies": {
"@grpc/grpc-js": "~1.7.3", "@grpc/grpc-js": "~1.7.3",

View File

@@ -1,6 +1,8 @@
const https = require("https"); const https = require("https");
const http = require("http"); const http = require("http");
const CacheableLookup = require("cacheable-lookup"); const CacheableLookup = require("cacheable-lookup");
const { Settings } = require("./settings");
const { log } = require("../src/util");
class CacheableDnsHttpAgent { class CacheableDnsHttpAgent {
@@ -9,12 +11,30 @@ class CacheableDnsHttpAgent {
static httpAgentList = {}; static httpAgentList = {};
static httpsAgentList = {}; static httpsAgentList = {};
static enable = false;
/** /**
* Register cacheable to global agents * Register/Disable cacheable to global agents
*/ */
static registerGlobalAgent() { static async update() {
this.cacheable.install(http.globalAgent); log.debug("CacheableDnsHttpAgent", "update");
this.cacheable.install(https.globalAgent); let isEnable = await Settings.get("dnsCache");
if (isEnable !== this.enable) {
log.debug("CacheableDnsHttpAgent", "value changed");
if (isEnable) {
log.debug("CacheableDnsHttpAgent", "enable");
this.cacheable.install(http.globalAgent);
this.cacheable.install(https.globalAgent);
} else {
log.debug("CacheableDnsHttpAgent", "disable");
this.cacheable.uninstall(http.globalAgent);
this.cacheable.uninstall(https.globalAgent);
}
}
this.enable = isEnable;
} }
static install(agent) { static install(agent) {
@@ -26,6 +46,10 @@ class CacheableDnsHttpAgent {
* @return {https.Agent} * @return {https.Agent}
*/ */
static getHttpsAgent(agentOptions) { static getHttpsAgent(agentOptions) {
if (!this.enable) {
return new https.Agent(agentOptions);
}
let key = JSON.stringify(agentOptions); let key = JSON.stringify(agentOptions);
if (!(key in this.httpsAgentList)) { if (!(key in this.httpsAgentList)) {
this.httpsAgentList[key] = new https.Agent(agentOptions); this.httpsAgentList[key] = new https.Agent(agentOptions);
@@ -39,6 +63,10 @@ class CacheableDnsHttpAgent {
* @return {https.Agents} * @return {https.Agents}
*/ */
static getHttpAgent(agentOptions) { static getHttpAgent(agentOptions) {
if (!this.enable) {
return new http.Agent(agentOptions);
}
let key = JSON.stringify(agentOptions); let key = JSON.stringify(agentOptions);
if (!(key in this.httpAgentList)) { if (!(key in this.httpAgentList)) {
this.httpAgentList[key] = new http.Agent(agentOptions); this.httpAgentList[key] = new http.Agent(agentOptions);

View File

@@ -152,9 +152,6 @@ class Database {
await R.exec("PRAGMA cache_size = -12000"); await R.exec("PRAGMA cache_size = -12000");
await R.exec("PRAGMA auto_vacuum = FULL"); await R.exec("PRAGMA auto_vacuum = FULL");
// Avoid error "SQLITE_BUSY: database is locked" by allowing SQLITE to wait up to 5 seconds to do a write
await R.exec("PRAGMA busy_timeout = 5000");
// This ensures that an operating system crash or power failure will not corrupt the database. // This ensures that an operating system crash or power failure will not corrupt the database.
// FULL synchronous is very safe, but it is also slower. // FULL synchronous is very safe, but it is also slower.
// Read more: https://sqlite.org/pragma.html#pragma_synchronous // Read more: https://sqlite.org/pragma.html#pragma_synchronous

View File

@@ -188,13 +188,13 @@ class Maintenance extends BeanModel {
*/ */
static getActiveMaintenanceSQLCondition() { static getActiveMaintenanceSQLCondition() {
return ` return `
(
(maintenance_timeslot.start_date <= DATETIME('now') (maintenance_timeslot.start_date <= DATETIME('now')
AND maintenance_timeslot.end_date >= DATETIME('now') AND maintenance_timeslot.end_date >= DATETIME('now')
AND maintenance.active = 1) AND maintenance.active = 1)
OR OR
(maintenance.strategy = 'manual' AND active = 1) (maintenance.strategy = 'manual' AND active = 1)
)
`; `;
} }
@@ -204,10 +204,12 @@ class Maintenance extends BeanModel {
*/ */
static getActiveAndFutureMaintenanceSQLCondition() { static getActiveAndFutureMaintenanceSQLCondition() {
return ` return `
((maintenance_timeslot.end_date >= DATETIME('now') (
AND maintenance.active = 1) ((maintenance_timeslot.end_date >= DATETIME('now')
OR AND maintenance.active = 1)
(maintenance.strategy = 'manual' AND active = 1)) OR
(maintenance.strategy = 'manual' AND active = 1))
)
`; `;
} }
} }

View File

@@ -2,7 +2,7 @@ const https = require("https");
const dayjs = require("dayjs"); const dayjs = require("dayjs");
const axios = require("axios"); const axios = require("axios");
const { Prometheus } = require("../prometheus"); const { Prometheus } = require("../prometheus");
const { log, UP, DOWN, PENDING, MAINTENANCE, flipStatus, TimeLogger } = require("../../src/util"); const { log, UP, DOWN, PENDING, MAINTENANCE, flipStatus, TimeLogger, MAX_INTERVAL_SECOND, MIN_INTERVAL_SECOND } = require("../../src/util");
const { tcping, ping, dnsResolve, checkCertificate, checkStatusCode, getTotalClientInRoom, setting, mssqlQuery, postgresQuery, mysqlQuery, mqttAsync, setSetting, httpNtlm, radius, grpcQuery } = require("../util-server"); const { tcping, ping, dnsResolve, checkCertificate, checkStatusCode, getTotalClientInRoom, setting, mssqlQuery, postgresQuery, mysqlQuery, mqttAsync, setSetting, httpNtlm, radius, grpcQuery } = require("../util-server");
const { R } = require("redbean-node"); const { R } = require("redbean-node");
const { BeanModel } = require("redbean-node/dist/bean-model"); const { BeanModel } = require("redbean-node/dist/bean-model");
@@ -15,6 +15,7 @@ const { UptimeKumaServer } = require("../uptime-kuma-server");
const { CacheableDnsHttpAgent } = require("../cacheable-dns-http-agent"); const { CacheableDnsHttpAgent } = require("../cacheable-dns-http-agent");
const { DockerHost } = require("../docker"); const { DockerHost } = require("../docker");
const Maintenance = require("./maintenance"); const Maintenance = require("./maintenance");
const { UptimeCacheList } = require("../uptime-cache-list");
/** /**
* status: * status:
@@ -274,15 +275,11 @@ class Monitor extends BeanModel {
...(this.body ? { data: JSON.parse(this.body) } : {}), ...(this.body ? { data: JSON.parse(this.body) } : {}),
timeout: this.interval * 1000 * 0.8, timeout: this.interval * 1000 * 0.8,
headers: { headers: {
// Fix #2253
// Read more: https://stackoverflow.com/questions/1759956/curl-error-18-transfer-closed-with-outstanding-read-data-remaining
"Accept-Encoding": "gzip, deflate",
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9", "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9",
"User-Agent": "Uptime-Kuma/" + version, "User-Agent": "Uptime-Kuma/" + version,
...(this.headers ? JSON.parse(this.headers) : {}), ...(this.headers ? JSON.parse(this.headers) : {}),
...(basicAuthHeader), ...(basicAuthHeader),
}, },
decompress: true,
maxRedirects: this.maxredirects, maxRedirects: this.maxredirects,
validateStatus: (status) => { validateStatus: (status) => {
return checkStatusCode(status, this.getAcceptedStatuscodes()); return checkStatusCode(status, this.getAcceptedStatuscodes());
@@ -310,20 +307,8 @@ class Monitor extends BeanModel {
log.debug("monitor", `[${this.name}] Axios Options: ${JSON.stringify(options)}`); log.debug("monitor", `[${this.name}] Axios Options: ${JSON.stringify(options)}`);
log.debug("monitor", `[${this.name}] Axios Request`); log.debug("monitor", `[${this.name}] Axios Request`);
let res; // Make Request
if (this.auth_method === "ntlm") { let res = await this.makeAxiosRequest(options);
options.httpsAgent.keepAlive = true;
res = await httpNtlm(options, {
username: this.basic_auth_user,
password: this.basic_auth_pass,
domain: this.authDomain,
workstation: this.authWorkstation ? this.authWorkstation : undefined
});
} else {
res = await axios.request(options);
}
bean.msg = `${res.status} - ${res.statusText}`; bean.msg = `${res.status} - ${res.statusText}`;
bean.ping = dayjs().valueOf() - startTime; bean.ping = dayjs().valueOf() - startTime;
@@ -714,6 +699,7 @@ class Monitor extends BeanModel {
} }
log.debug("monitor", `[${this.name}] Send to socket`); log.debug("monitor", `[${this.name}] Send to socket`);
UptimeCacheList.clearCache(this.id);
io.to(this.user_id).emit("heartbeat", bean.toJSON()); io.to(this.user_id).emit("heartbeat", bean.toJSON());
Monitor.sendStats(io, this.id, this.user_id); Monitor.sendStats(io, this.id, this.user_id);
@@ -760,6 +746,40 @@ class Monitor extends BeanModel {
} }
} }
async makeAxiosRequest(options, finalCall = false) {
try {
let res;
if (this.auth_method === "ntlm") {
options.httpsAgent.keepAlive = true;
res = await httpNtlm(options, {
username: this.basic_auth_user,
password: this.basic_auth_pass,
domain: this.authDomain,
workstation: this.authWorkstation ? this.authWorkstation : undefined
});
} else {
res = await axios.request(options);
}
return res;
} catch (e) {
// Fix #2253
// Read more: https://stackoverflow.com/questions/1759956/curl-error-18-transfer-closed-with-outstanding-read-data-remaining
if (!finalCall && typeof e.message === "string" && e.message.includes("maxContentLength size of -1 exceeded")) {
log.debug("monitor", "makeAxiosRequest with gzip");
options.headers["Accept-Encoding"] = "gzip, deflate";
return this.makeAxiosRequest(options, true);
} else {
if (typeof e.message === "string" && e.message.includes("maxContentLength size of -1 exceeded")) {
e.message = "response timeout: incomplete response within a interval";
}
throw e;
}
}
}
/** Stop monitor */ /** Stop monitor */
stop() { stop() {
clearTimeout(this.heartbeatInterval); clearTimeout(this.heartbeatInterval);
@@ -898,7 +918,15 @@ class Monitor extends BeanModel {
* @param {number} duration Hours * @param {number} duration Hours
* @param {number} monitorID ID of monitor to calculate * @param {number} monitorID ID of monitor to calculate
*/ */
static async calcUptime(duration, monitorID) { static async calcUptime(duration, monitorID, forceNoCache = false) {
if (!forceNoCache) {
let cachedUptime = UptimeCacheList.getUptime(monitorID, duration);
if (cachedUptime != null) {
return cachedUptime;
}
}
const timeLogger = new TimeLogger(); const timeLogger = new TimeLogger();
const startTime = R.isoDateTime(dayjs.utc().subtract(duration, "hour")); const startTime = R.isoDateTime(dayjs.utc().subtract(duration, "hour"));
@@ -957,6 +985,9 @@ class Monitor extends BeanModel {
} }
} }
// Cache
UptimeCacheList.addUptime(monitorID, duration, uptime);
return uptime; return uptime;
} }
@@ -1056,7 +1087,13 @@ class Monitor extends BeanModel {
for (let notification of notificationList) { for (let notification of notificationList) {
try { try {
await Notification.send(JSON.parse(notification.config), msg, await monitor.toJSON(false), bean.toJSON()); // Prevent if the msg is undefined, notifications such as Discord cannot send out.
const heartbeatJSON = bean.toJSON();
if (!heartbeatJSON["msg"]) {
heartbeatJSON["msg"] = "";
}
await Notification.send(JSON.parse(notification.config), msg, await monitor.toJSON(false), heartbeatJSON);
} catch (e) { } catch (e) {
log.error("monitor", "Cannot send notification to " + notification.name); log.error("monitor", "Cannot send notification to " + notification.name);
log.error("monitor", e); log.error("monitor", e);
@@ -1189,6 +1226,15 @@ class Monitor extends BeanModel {
LIMIT 1`, [ monitorID ]); LIMIT 1`, [ monitorID ]);
return maintenance.count !== 0; return maintenance.count !== 0;
} }
validate() {
if (this.interval > MAX_INTERVAL_SECOND) {
throw new Error(`Interval cannot be more than ${MAX_INTERVAL_SECOND} seconds`);
}
if (this.interval < MIN_INTERVAL_SECOND) {
throw new Error(`Interval cannot be less than ${MIN_INTERVAL_SECOND} seconds`);
}
}
} }
module.exports = Monitor; module.exports = Monitor;

View File

@@ -282,11 +282,13 @@ class StatusPage extends BeanModel {
let activeCondition = Maintenance.getActiveMaintenanceSQLCondition(); let activeCondition = Maintenance.getActiveMaintenanceSQLCondition();
let maintenanceBeanList = R.convertToBeans("maintenance", await R.getAll(` let maintenanceBeanList = R.convertToBeans("maintenance", await R.getAll(`
SELECT maintenance.* SELECT maintenance.*
FROM maintenance, maintenance_status_page msp, maintenance_timeslot FROM maintenance
WHERE msp.maintenance_id = maintenance.id JOIN maintenance_status_page
AND maintenance_timeslot.maintenance_id = maintenance.id ON maintenance_status_page.maintenance_id = maintenance.id
AND msp.status_page_id = ? AND maintenance_status_page.status_page_id = ?
AND ${activeCondition} LEFT JOIN maintenance_timeslot
ON maintenance_timeslot.maintenance_id = maintenance.id
WHERE ${activeCondition}
ORDER BY maintenance.end_date ORDER BY maintenance.end_date
`, [ statusPageId ])); `, [ statusPageId ]));

View File

@@ -0,0 +1,20 @@
import { PluginFunc, ConfigType } from 'dayjs'
declare const plugin: PluginFunc
export = plugin
declare module 'dayjs' {
interface Dayjs {
tz(timezone?: string, keepLocalTime?: boolean): Dayjs
offsetName(type?: 'short' | 'long'): string | undefined
}
interface DayjsTimezone {
(date: ConfigType, timezone?: string): Dayjs
(date: ConfigType, format: string, timezone?: string): Dayjs
guess(): string
setDefault(timezone?: string): void
}
const tz: DayjsTimezone
}

View File

@@ -0,0 +1,115 @@
/**
* Copy from node_modules/dayjs/plugin/timezone.js
* Try to fix https://github.com/louislam/uptime-kuma/issues/2318
* Source: https://github.com/iamkun/dayjs/tree/dev/src/plugin/utc
* License: MIT
*/
!function (t, e) {
// eslint-disable-next-line no-undef
typeof exports == "object" && typeof module != "undefined" ? module.exports = e() : typeof define == "function" && define.amd ? define(e) : (t = typeof globalThis != "undefined" ? globalThis : t || self).dayjs_plugin_timezone = e();
}(this, (function () {
"use strict";
let t = {
year: 0,
month: 1,
day: 2,
hour: 3,
minute: 4,
second: 5
};
let e = {};
return function (n, i, o) {
let r;
let a = function (t, n, i) {
void 0 === i && (i = {});
let o = new Date(t);
let r = function (t, n) {
void 0 === n && (n = {});
let i = n.timeZoneName || "short";
let o = t + "|" + i;
let r = e[o];
return r || (r = new Intl.DateTimeFormat("en-US", {
hour12: !1,
timeZone: t,
year: "numeric",
month: "2-digit",
day: "2-digit",
hour: "2-digit",
minute: "2-digit",
second: "2-digit",
timeZoneName: i
}), e[o] = r), r;
}(n, i);
return r.formatToParts(o);
};
let u = function (e, n) {
let i = a(e, n);
let r = [];
let u = 0;
for (; u < i.length; u += 1) {
let f = i[u];
let s = f.type;
let m = f.value;
let c = t[s];
c >= 0 && (r[c] = parseInt(m, 10));
}
let d = r[3];
let l = d === 24 ? 0 : d;
let v = r[0] + "-" + r[1] + "-" + r[2] + " " + l + ":" + r[4] + ":" + r[5] + ":000";
let h = +e;
return (o.utc(v).valueOf() - (h -= h % 1e3)) / 6e4;
};
let f = i.prototype;
f.tz = function (t, e) {
void 0 === t && (t = r);
let n = this.utcOffset();
let i = this.toDate();
let a = i.toLocaleString("en-US", { timeZone: t }).replace("\u202f", " ");
let u = Math.round((i - new Date(a)) / 1e3 / 60);
let f = o(a).$set("millisecond", this.$ms).utcOffset(15 * -Math.round(i.getTimezoneOffset() / 15) - u, !0);
if (e) {
let s = f.utcOffset();
f = f.add(n - s, "minute");
}
return f.$x.$timezone = t, f;
}, f.offsetName = function (t) {
let e = this.$x.$timezone || o.tz.guess();
let n = a(this.valueOf(), e, { timeZoneName: t }).find((function (t) {
return t.type.toLowerCase() === "timezonename";
}));
return n && n.value;
};
let s = f.startOf;
f.startOf = function (t, e) {
if (!this.$x || !this.$x.$timezone) {
return s.call(this, t, e);
}
let n = o(this.format("YYYY-MM-DD HH:mm:ss:SSS"));
return s.call(n, t, e).tz(this.$x.$timezone, !0);
}, o.tz = function (t, e, n) {
let i = n && e;
let a = n || e || r;
let f = u(+o(), a);
if (typeof t != "string") {
return o(t).tz(a);
}
let s = function (t, e, n) {
let i = t - 60 * e * 1e3;
let o = u(i, n);
if (e === o) {
return [ i, e ];
}
let r = u(i -= 60 * (o - e) * 1e3, n);
return o === r ? [ i, o ] : [ t - 60 * Math.min(o, r) * 1e3, Math.max(o, r) ];
}(o.utc(t, i).valueOf(), f, a);
let m = s[0];
let c = s[1];
let d = o(m).utcOffset(c);
return d.$x.$timezone = a, d;
}, o.tz.guess = function () {
return Intl.DateTimeFormat().resolvedOptions().timeZone;
}, o.tz.setDefault = function (t) {
r = t;
};
};
}));

View File

@@ -64,7 +64,7 @@ class Discord extends NotificationProvider {
}, },
{ {
name: "Error", name: "Error",
value: heartbeatJSON["msg"], value: heartbeatJSON["msg"] == null ? "N/A" : heartbeatJSON["msg"],
}, },
], ],
}], }],

View File

@@ -8,7 +8,7 @@ console.log("Welcome to Uptime Kuma");
// As the log function need to use dayjs, it should be very top // As the log function need to use dayjs, it should be very top
const dayjs = require("dayjs"); const dayjs = require("dayjs");
dayjs.extend(require("dayjs/plugin/utc")); dayjs.extend(require("dayjs/plugin/utc"));
dayjs.extend(require("dayjs/plugin/timezone")); dayjs.extend(require("./modules/dayjs/plugin/timezone"));
dayjs.extend(require("dayjs/plugin/customParseFormat")); dayjs.extend(require("dayjs/plugin/customParseFormat"));
// Check Node.js Version // Check Node.js Version
@@ -135,7 +135,9 @@ const { cloudflaredSocketHandler, autoStart: cloudflaredAutoStart, stop: cloudfl
const { proxySocketHandler } = require("./socket-handlers/proxy-socket-handler"); const { proxySocketHandler } = require("./socket-handlers/proxy-socket-handler");
const { dockerSocketHandler } = require("./socket-handlers/docker-socket-handler"); const { dockerSocketHandler } = require("./socket-handlers/docker-socket-handler");
const { maintenanceSocketHandler } = require("./socket-handlers/maintenance-socket-handler"); const { maintenanceSocketHandler } = require("./socket-handlers/maintenance-socket-handler");
const { generalSocketHandler } = require("./socket-handlers/general-socket-handler");
const { Settings } = require("./settings"); const { Settings } = require("./settings");
const { CacheableDnsHttpAgent } = require("./cacheable-dns-http-agent");
app.use(express.json()); app.use(express.json());
@@ -632,6 +634,9 @@ let needSetup = false;
bean.import(monitor); bean.import(monitor);
bean.user_id = socket.userID; bean.user_id = socket.userID;
bean.validate();
await R.store(bean); await R.store(bean);
await updateMonitorNotification(bean.id, notificationIDList); await updateMonitorNotification(bean.id, notificationIDList);
@@ -719,6 +724,8 @@ let needSetup = false;
bean.radiusCallingStationId = monitor.radiusCallingStationId; bean.radiusCallingStationId = monitor.radiusCallingStationId;
bean.radiusSecret = monitor.radiusSecret; bean.radiusSecret = monitor.radiusSecret;
bean.validate();
await R.store(bean); await R.store(bean);
await updateMonitorNotification(bean.id, monitor.notificationIDList); await updateMonitorNotification(bean.id, monitor.notificationIDList);
@@ -1109,6 +1116,8 @@ let needSetup = false;
await setSettings("general", data); await setSettings("general", data);
server.entryPage = data.entryPage; server.entryPage = data.entryPage;
await CacheableDnsHttpAgent.update();
// Also need to apply timezone globally // Also need to apply timezone globally
if (data.serverTimezone) { if (data.serverTimezone) {
await server.setTimezone(data.serverTimezone); await server.setTimezone(data.serverTimezone);
@@ -1480,6 +1489,7 @@ let needSetup = false;
proxySocketHandler(socket); proxySocketHandler(socket);
dockerSocketHandler(socket); dockerSocketHandler(socket);
maintenanceSocketHandler(socket); maintenanceSocketHandler(socket);
generalSocketHandler(socket, server);
log.debug("server", "added all socket handlers"); log.debug("server", "added all socket handlers");
@@ -1602,6 +1612,13 @@ async function afterLogin(socket, user) {
for (let monitorID in monitorList) { for (let monitorID in monitorList) {
await Monitor.sendStats(io, monitorID, user.id); await Monitor.sendStats(io, monitorID, user.id);
} }
// Set server timezone from client browser if not set
// It should be run once only
if (! await Settings.get("initServerTimezone")) {
log.debug("server", "emit initServerTimezone");
socket.emit("initServerTimezone");
}
} }
/** /**
@@ -1740,6 +1757,7 @@ async function shutdownFunction(signal) {
stopBackgroundJobs(); stopBackgroundJobs();
await cloudflaredStop(); await cloudflaredStop();
Settings.stopCacheCleaner();
} }
/** Final function called before application exits */ /** Final function called before application exits */

View File

@@ -158,6 +158,13 @@ class Settings {
delete Settings.cacheList[key]; delete Settings.cacheList[key];
} }
} }
static stopCacheCleaner() {
if (Settings.cacheCleaner) {
clearInterval(Settings.cacheCleaner);
Settings.cacheCleaner = null;
}
}
} }
module.exports = { module.exports = {

View File

@@ -1,6 +1,7 @@
const { checkLogin, setSetting, setting, doubleCheckPassword } = require("../util-server"); const { checkLogin, setSetting, setting, doubleCheckPassword } = require("../util-server");
const { CloudflaredTunnel } = require("node-cloudflared-tunnel"); const { CloudflaredTunnel } = require("node-cloudflared-tunnel");
const { UptimeKumaServer } = require("../uptime-kuma-server"); const { UptimeKumaServer } = require("../uptime-kuma-server");
const { log } = require("../../src/util");
const io = UptimeKumaServer.getInstance().io; const io = UptimeKumaServer.getInstance().io;
const prefix = "cloudflared_"; const prefix = "cloudflared_";
@@ -107,7 +108,7 @@ module.exports.autoStart = async (token) => {
/** Stop cloudflared */ /** Stop cloudflared */
module.exports.stop = async () => { module.exports.stop = async () => {
console.log("Stop cloudflared"); log.info("cloudflared", "Stop cloudflared");
if (cloudflared) { if (cloudflared) {
cloudflared.stop(); cloudflared.stop();
} }

View File

@@ -0,0 +1,20 @@
const { log } = require("../../src/util");
const { Settings } = require("../settings");
const { sendInfo } = require("../client");
const { checkLogin } = require("../util-server");
module.exports.generalSocketHandler = (socket, server) => {
socket.on("initServerTimezone", async (timezone) => {
try {
checkLogin(socket);
log.debug("generalSocketHandler", "Timezone: " + timezone);
await Settings.set("initServerTimezone", true);
await server.setTimezone(timezone);
await sendInfo(socket);
} catch (e) {
log.warn("initServerTimezone", e.message);
}
});
};

View File

@@ -0,0 +1,39 @@
const { log } = require("../src/util");
class UptimeCacheList {
/**
* list[monitorID][duration]
*/
static list = {};
/**
*
* @param monitorID
* @param duration
* @return number
*/
static getUptime(monitorID, duration) {
if (UptimeCacheList.list[monitorID] && UptimeCacheList.list[monitorID][duration]) {
log.debug("UptimeCacheList", "getUptime: " + monitorID + " " + duration);
return UptimeCacheList.list[monitorID][duration];
} else {
return null;
}
}
static addUptime(monitorID, duration, uptime) {
log.debug("UptimeCacheList", "addUptime: " + monitorID + " " + duration);
if (!UptimeCacheList.list[monitorID]) {
UptimeCacheList.list[monitorID] = {};
}
UptimeCacheList.list[monitorID][duration] = uptime;
}
static clearCache(monitorID) {
log.debug("UptimeCacheList", "clearCache: " + monitorID);
delete UptimeCacheList.list[monitorID];
}
}
module.exports = {
UptimeCacheList,
};

View File

@@ -83,12 +83,12 @@ class UptimeKumaServer {
} }
} }
CacheableDnsHttpAgent.registerGlobalAgent();
this.io = new Server(this.httpServer); this.io = new Server(this.httpServer);
} }
async initAfterDatabaseReady() { async initAfterDatabaseReady() {
await CacheableDnsHttpAgent.update();
process.env.TZ = await this.getTimezone(); process.env.TZ = await this.getTimezone();
dayjs.tz.setDefault(process.env.TZ); dayjs.tz.setDefault(process.env.TZ);
log.debug("DEBUG", "Timezone: " + process.env.TZ); log.debug("DEBUG", "Timezone: " + process.env.TZ);

View File

@@ -470,6 +470,10 @@ const parseCertificateInfo = function (info) {
* @returns {Object} Object containing certificate information * @returns {Object} Object containing certificate information
*/ */
exports.checkCertificate = function (res) { exports.checkCertificate = function (res) {
if (!res.request.res.socket) {
throw new Error("No socket found");
}
const info = res.request.res.socket.getPeerCertificate(true); const info = res.request.res.socket.getPeerCertificate(true);
const valid = res.request.res.socket.authorized || false; const valid = res.request.res.socket.authorized || false;

View File

@@ -213,7 +213,7 @@ export default {
transition: all ease-in-out 0.1s; transition: all ease-in-out 0.1s;
&:hover { &:hover {
color: white; opacity: 0.5;
} }
} }
} }

View File

@@ -1,6 +1,6 @@
<template> <template>
<div class="mb-3"> <div class="mb-3">
<label for="smsmanager-key" class="form-label">API Key</label> <label for="smsmanager-key" class="form-label">{{ $t("API Key") }}</label>
<div class="form-text"> <div class="form-text">
{{ $t("SMSManager API Docs") }} {{ $t("SMSManager API Docs") }}
<a href="https://smsmanager.cz/api/http#send" target="_blank">{{ $t("here") }}</a> <a href="https://smsmanager.cz/api/http#send" target="_blank">{{ $t("here") }}</a>
@@ -17,9 +17,9 @@
<div class="mb-3"> <div class="mb-3">
<label for="smsmanager-messageType" class="form-label">{{ $t("Gateway Type") }}</label> <label for="smsmanager-messageType" class="form-label">{{ $t("Gateway Type") }}</label>
<select id="smsmanager-messageType" v-model="$parent.notification.messageType" class="form-select"> <select id="smsmanager-messageType" v-model="$parent.notification.messageType" class="form-select">
<option value="economy">Economy</option> <option value="economy">{{ $t("Economy") }}</option>
<option value="lowcost">Lowcost</option> <option value="lowcost">{{ $t("Lowcost") }}</option>
<option value="high" selected>High</option> <option value="high" selected>{{ $t("High") }}</option>
</select> </select>
</div> </div>
<div class="mb-3"> <div class="mb-3">

View File

@@ -49,7 +49,7 @@
v-model="settings.searchEngineIndex" v-model="settings.searchEngineIndex"
class="form-check-input" class="form-check-input"
type="radio" type="radio"
name="flexRadioDefault" name="searchEngineIndex"
:value="true" :value="true"
required required
/> />
@@ -63,7 +63,7 @@
v-model="settings.searchEngineIndex" v-model="settings.searchEngineIndex"
class="form-check-input" class="form-check-input"
type="radio" type="radio"
name="flexRadioDefault" name="searchEngineIndex"
:value="false" :value="false"
required required
/> />
@@ -150,6 +150,46 @@
</div> </div>
</div> </div>
<!-- DNS Cache -->
<div class="mb-4">
<label class="form-label">
{{ $t("Enable DNS Cache") }}
<div class="form-text">
{{ $t("dnsCacheDescription") }}
</div>
</label>
<div class="form-check">
<input
id="dnsCacheEnable"
v-model="settings.dnsCache"
class="form-check-input"
type="radio"
name="dnsCache"
:value="true"
required
/>
<label class="form-check-label" for="dnsCacheEnable">
{{ $t("Enable") }}
</label>
</div>
<div class="form-check">
<input
id="dnsCacheDisable"
v-model="settings.dnsCache"
class="form-check-input"
type="radio"
name="dnsCache"
:value="false"
required
/>
<label class="form-check-label" for="dnsCacheDisable">
{{ $t("Disable") }}
</label>
</div>
</div>
<!-- Save Button --> <!-- Save Button -->
<div> <div>
<button class="btn btn-primary" type="submit"> <button class="btn btn-primary" type="submit">

View File

@@ -6,6 +6,7 @@ const languageList = {
"zh-HK": "繁體中文 (香港)", "zh-HK": "繁體中文 (香港)",
"bg-BG": "Български", "bg-BG": "Български",
"de-DE": "Deutsch (Deutschland)", "de-DE": "Deutsch (Deutschland)",
"de-CH": "Deutsch (Schweiz)",
"nl-NL": "Nederlands", "nl-NL": "Nederlands",
"nb-NO": "Norsk", "nb-NO": "Norsk",
"es-ES": "Español", "es-ES": "Español",

View File

@@ -2,8 +2,8 @@ export default {
languageName: "Български", languageName: "Български",
checkEverySecond: "Ще се извършва на всеки {0} секунди", checkEverySecond: "Ще се извършва на всеки {0} секунди",
retryCheckEverySecond: "Ще се извършва на всеки {0} секунди", retryCheckEverySecond: "Ще се извършва на всеки {0} секунди",
retriesDescription: "Максимакен брой опити преди маркиране на услугата като недостъпна и изпращане на известие", retriesDescription: "Максимален брой опити преди маркиране на услугата като недостъпна и изпращане на известие",
ignoreTLSError: "Игнорирай TLS/SSL грешки за HTTPS уебсайтове", ignoreTLSError: "Игнорирай TLS/SSL грешки за HTTPS уеб сайтове",
upsideDownModeDescription: "Обръща статуса от достъпен на недостъпен. Ако услугата е достъпна, ще се вижда като НЕДОСТЪПНА.", upsideDownModeDescription: "Обръща статуса от достъпен на недостъпен. Ако услугата е достъпна, ще се вижда като НЕДОСТЪПНА.",
maxRedirectDescription: "Максимален брой пренасочвания, които да бъдат следвани. Въведете 0 за да изключите пренасочване.", maxRedirectDescription: "Максимален брой пренасочвания, които да бъдат следвани. Въведете 0 за да изключите пренасочване.",
acceptedStatusCodesDescription: "Изберете статус кодове, които да се считат за успешен отговор.", acceptedStatusCodesDescription: "Изберете статус кодове, които да се считат за успешен отговор.",
@@ -95,7 +95,7 @@ export default {
"Repeat New Password": "Повторете новата парола", "Repeat New Password": "Повторете новата парола",
"Update Password": "Актуализирай паролата", "Update Password": "Актуализирай паролата",
"Disable Auth": "Изключи удостоверяване", "Disable Auth": "Изключи удостоверяване",
"Enable Auth": "Включи удостоверяване", "Enable Auth": "Активирай удостоверяване",
"disableauth.message1": "Сигурни ли сте, че желаете да <strong>изключите удостоверяването</strong>?", "disableauth.message1": "Сигурни ли сте, че желаете да <strong>изключите удостоверяването</strong>?",
"disableauth.message2": "Използва се в случаите, когато <strong>има настроен алтернативен метод за удостоверяване</strong> преди Uptime Kuma, например Cloudflare Access, Authelia или друг механизъм за удостоверяване.", "disableauth.message2": "Използва се в случаите, когато <strong>има настроен алтернативен метод за удостоверяване</strong> преди Uptime Kuma, например Cloudflare Access, Authelia или друг механизъм за удостоверяване.",
"Please use this option carefully!": "Моля, използвайте с повишено внимание.", "Please use this option carefully!": "Моля, използвайте с повишено внимание.",
@@ -126,7 +126,7 @@ export default {
Import: "Импорт", Import: "Импорт",
respTime: "Време за отговор (ms)", respTime: "Време за отговор (ms)",
notAvailableShort: "Няма", notAvailableShort: "Няма",
"Default enabled": "Включен по подразбиране", "Default enabled": "Активирано по подразбиране",
"Apply on all existing monitors": "Приложи върху всички съществуващи монитори", "Apply on all existing monitors": "Приложи върху всички съществуващи монитори",
Create: "Създай", Create: "Създай",
"Clear Data": "Изтрий данни", "Clear Data": "Изтрий данни",
@@ -145,8 +145,8 @@ export default {
"Keep both": "Запази двете", "Keep both": "Запази двете",
"Verify Token": "Провери токен код", "Verify Token": "Провери токен код",
"Setup 2FA": "Настройка 2FA", "Setup 2FA": "Настройка 2FA",
"Enable 2FA": "Включи 2FA", "Enable 2FA": "Активирай 2FA",
"Disable 2FA": "Изключи 2FA", "Disable 2FA": "Деактивирай 2FA",
"2FA Settings": "Настройка за 2FA", "2FA Settings": "Настройка за 2FA",
"Two Factor Authentication": "Двуфакторно удостоверяване", "Two Factor Authentication": "Двуфакторно удостоверяване",
Active: "Активно", Active: "Активно",
@@ -194,7 +194,7 @@ export default {
octopush: "Octopush", octopush: "Octopush",
promosms: "PromoSMS", promosms: "PromoSMS",
lunasea: "LunaSea", lunasea: "LunaSea",
apprise: "Apprise (Поддържа 50+ услуги за инвестяване)", apprise: "Apprise (Поддържа 50+ услуги за известяване)",
pushbullet: "Pushbullet", pushbullet: "Pushbullet",
line: "Line Messenger", line: "Line Messenger",
mattermost: "Mattermost", mattermost: "Mattermost",
@@ -281,19 +281,19 @@ export default {
wayToGetLineChannelToken: "Необходимо е първо да посетите {0}, за да създадете (Messaging API) за доставчик и канал, след което може да вземете токен кода за канал и потребителско ID от споменатите по-горе елементи на менюто.", wayToGetLineChannelToken: "Необходимо е първо да посетите {0}, за да създадете (Messaging API) за доставчик и канал, след което може да вземете токен кода за канал и потребителско ID от споменатите по-горе елементи на менюто.",
"Icon URL": "URL адрес за иконка", "Icon URL": "URL адрес за иконка",
aboutIconURL: "Може да предоставите линк към картинка в поле \"URL Адрес за иконка\" за да отмените картинката на профила по подразбиране. Няма да се използва, ако вече сте настроили емотикон.", aboutIconURL: "Може да предоставите линк към картинка в поле \"URL Адрес за иконка\" за да отмените картинката на профила по подразбиране. Няма да се използва, ако вече сте настроили емотикон.",
aboutMattermostChannelName: "Може да замените канала по подразбиране, към който публикува уеб куката, като въведете името на канала в полето \"Канал име\". Tрябва да бъде активирано в настройките за уеб кука на Mattermost. Например: #other-channel", aboutMattermostChannelName: "Може да замените канала по подразбиране, към който публикува уеб куката, като въведете името на канала в полето \"Канал име\". Трябва да бъде активирано в настройките за уеб кука на Mattermost. Например: #other-channel",
matrix: "Matrix", matrix: "Matrix",
promosmsTypeEco: "SMS ECO - евтин, но бавен. Често е претоварен. Само за получатели от Полша.", promosmsTypeEco: "SMS ECO - евтин, но бавен. Често е претоварен. Само за получатели от Полша.",
promosmsTypeFlash: "SMS FLASH - Съобщението автоматично се показва на устройството на получателя. Само за получатели от Полша.", promosmsTypeFlash: "SMS FLASH - Съобщението автоматично се показва на устройството на получателя. Само за получатели от Полша.",
promosmsTypeFull: "SMS FULL - Високо ниво на SMS услуга. Може да използвате Вашето име като подател (Необходимо е първо да регистрирате името). Надежден метод за съобщения тип тревога.", promosmsTypeFull: "SMS FULL - Високо ниво на SMS услуга. Може да използвате Вашето име като подател (Необходимо е първо да регистрирате името). Надежден метод за съобщения тип тревога.",
promosmsTypeSpeed: "SMS SPEED - Най-висок приоритет в системата. Много бърза и надеждна, но същвременно скъпа услуга. (Около два пъти по-висока цена в сравнение с SMS FULL).", promosmsTypeSpeed: "SMS SPEED - Най-висок приоритет в системата. Много бърза и надеждна, но същевременно скъпа услуга. (Около два пъти по-висока цена в сравнение с SMS FULL).",
promosmsPhoneNumber: "Телефонен номер (за получатели от Полша, може да пропуснете въвеждането на код за населено място)", promosmsPhoneNumber: "Телефонен номер (за получатели от Полша, може да пропуснете въвеждането на код за населено място)",
promosmsSMSSender: "SMS Подател име: Предварително регистрирано име или някое от имената по подразбиране: InfoSMS, SMS Info, MaxSMS, INFO, SMS", promosmsSMSSender: "SMS Подател име: Предварително регистрирано име или някое от имената по подразбиране: InfoSMS, SMS Info, MaxSMS, INFO, SMS",
"Feishu WebHookUrl": "Feishu URL адрес за уеб кука", "Feishu WebHookUrl": "Feishu URL адрес за уеб кука",
matrixHomeserverURL: "Сървър URL адрес (започва с http(s):// и порт по желание)", matrixHomeserverURL: "Сървър URL адрес (започва с http(s):// и порт по желание)",
"Internal Room Id": "ID на вътрешна стая", "Internal Room Id": "ID на вътрешна стая",
matrixDesc1: "Може да намерите \"ID на вътрешна стая\" в разширените настройки на стаята във вашия Matrix клиент. Примерен изглед: !QMdRCpUIfLwsfjxye6:home.server.", matrixDesc1: "Може да намерите \"ID на вътрешна стая\" в разширените настройки на стаята във вашия Matrix клиент. Примерен изглед: !QMdRCpUIfLwsfjxye6:home.server.",
matrixDesc2: "Силно препоръчваме да създадете НОВ потребител и да НЕ използвате токен кодът на вашия личен Matrix потребирел, т.к. той позволява пълен достъп до вашия акаунт и всички стаи към които сте се присъединили. Вместо това създайте нов потребител и го поканете само в стаята, където желаете да получавате известията. Токен код за достъп ще получите изпълнявайки {0}", matrixDesc2: "Силно препоръчваме да създадете НОВ потребител и да НЕ използвате токен кодът на вашия личен Matrix потребител, т.к. той позволява пълен достъп до вашия акаунт и всички стаи към които сте се присъединили. Вместо това създайте нов потребител и го поканете само в стаята, където желаете да получавате известията. Токен код за достъп ще получите изпълнявайки {0}",
Method: "Метод", Method: "Метод",
Body: "Съобщение", Body: "Съобщение",
Headers: "Хедъри", Headers: "Хедъри",
@@ -316,7 +316,7 @@ export default {
Security: "Сигурност", Security: "Сигурност",
"Steam API Key": "Steam API ключ", "Steam API Key": "Steam API ключ",
"Shrink Database": "Редуцирай базата данни", "Shrink Database": "Редуцирай базата данни",
"Pick a RR-Type...": "Изберете вида на ресурсния запис за мониторитане...", "Pick a RR-Type...": "Изберете вида на ресурсния запис за мониториране...",
"Pick Accepted Status Codes...": "Изберете статус кодове, които да се считат за успешен отговор...", "Pick Accepted Status Codes...": "Изберете статус кодове, които да се считат за успешен отговор...",
Default: "По подразбиране", Default: "По подразбиране",
"HTTP Options": "HTTP Опции", "HTTP Options": "HTTP Опции",
@@ -375,12 +375,12 @@ export default {
deleteStatusPageMsg: "Сигурни ли сте, че желаете да изтриете тази статус страница?", deleteStatusPageMsg: "Сигурни ли сте, че желаете да изтриете тази статус страница?",
Proxies: "Прокси", Proxies: "Прокси",
default: "По подразбиране", default: "По подразбиране",
enabled: "Включено", enabled: "Активирано",
setAsDefault: "Зададен по подразбиране", setAsDefault: "Зададен по подразбиране",
deleteProxyMsg: "Сигурни ли сте, че желаете да изтриете това прокси за всички монитори?", deleteProxyMsg: "Сигурни ли сте, че желаете да изтриете това прокси за всички монитори?",
proxyDescription: "За да функционират трябва да бъдат зададени към монитор.", proxyDescription: "За да функционират трябва да бъдат зададени към монитор.",
enableProxyDescription: "Това прокси няма да има ефект върху заявките за мониторинг, докато не бъде активирано. Може да контролирате временното деактивиране на проксито от всички монитори чрез статуса на активиране.", enableProxyDescription: "Това прокси няма да има ефект върху заявките за мониторинг, докато не бъде активирано. Може да контролирате временното деактивиране на проксито от всички монитори чрез статуса на активиране.",
setAsDefaultProxyDescription: "Това прокси ще бъде включено по подразбиране за новите монитори. Може да го изключите по отделно за всеки един монитор.", setAsDefaultProxyDescription: "Това прокси ще бъде активно по подразбиране за новите монитори. Може да го изключите по отделно за всеки един монитор.",
"Certificate Chain": "Верига на сертификата", "Certificate Chain": "Верига на сертификата",
Valid: "Валиден", Valid: "Валиден",
Invalid: "Невалиден", Invalid: "Невалиден",
@@ -432,7 +432,7 @@ export default {
Backup: "Архивиране", Backup: "Архивиране",
About: "Относно", About: "Относно",
wayToGetCloudflaredURL: "(Свалете \"cloudflared\" от {0})", wayToGetCloudflaredURL: "(Свалете \"cloudflared\" от {0})",
cloudflareWebsite: "Cloudflare уебсайт", cloudflareWebsite: "Cloudflare уеб сайт",
"Message:": "Съобщение:", "Message:": "Съобщение:",
"Don't know how to get the token? Please read the guide:": "Не знаете как да вземете токен? Моля, прочетете ръководството:", "Don't know how to get the token? Please read the guide:": "Не знаете как да вземете токен? Моля, прочетете ръководството:",
"The current connection may be lost if you are currently connecting via Cloudflare Tunnel. Are you sure want to stop it? Type your current password to confirm it.": "Текущата връзка може да прекъсне ако в момента сте свързани чрез \"Cloudflare Tunnel\". Сигурни ли сте, че желаете да го спрете? Въведете Вашата текуща парола за да потвърдите.", "The current connection may be lost if you are currently connecting via Cloudflare Tunnel. Are you sure want to stop it? Type your current password to confirm it.": "Текущата връзка може да прекъсне ако в момента сте свързани чрез \"Cloudflare Tunnel\". Сигурни ли сте, че желаете да го спрете? Въведете Вашата текуща парола за да потвърдите.",
@@ -644,4 +644,29 @@ export default {
smseagleEncoding: "Изпрати като Unicode", smseagleEncoding: "Изпрати като Unicode",
smseaglePriority: "Приоритет на съобщението (0-9, по подразбиране = 0)", smseaglePriority: "Приоритет на съобщението (0-9, по подразбиране = 0)",
IconUrl: "Икона URL адрес", IconUrl: "Икона URL адрес",
webhookAdditionalHeadersTitle: "Допълнителни хедъри",
webhookAdditionalHeadersDesc: "Задава допълнителни хедъри, изпратени с уеб куката.",
"Enable DNS Cache": "Активирай DNS кеширане",
Enable: "Активирай",
Disable: "Деактивирай",
dnsCacheDescription: "Възможно е да не работи в IPv6 среда - деактивирайте, ако срещнете проблеми.",
"Single Maintenance Window": "Единичен времеви интервал за поддръжка",
"Maintenance Time Window of a Day": "Времеви интервал от деня за поддръжка",
"Effective Date Range": "Интервал от дни на влизане в сила",
"Schedule Maintenance": "Планирай поддръжка",
"Date and Time": "Дата и час",
"DateTime Range": "Изтрий времеви интервал",
Strategy: "Стратегия",
"Free Mobile User Identifier": "Free Mobile потребителски идентификатор",
"Free Mobile API Key": "Free Mobile API ключ",
"Enable TLS": "Активирай TLS",
"Proto Service Name": "Proto име на услугата",
"Proto Method": "Proto метод",
"Proto Content": "Proto съдържание",
Economy: "Икономичен",
Lowcost: "Евтин",
high: "висок",
"General Monitor Type": "Общ тип монитор",
"Passive Monitor Type": "Пасивет тип монитор",
"Specific Monitor Type": "Специфичен тип монитор",
}; };

View File

@@ -582,4 +582,45 @@ export default {
goAlert: "GoAlert", goAlert: "GoAlert",
backupOutdatedWarning: "Zastaralé: V poslední době byla funkčnost aplikace značně rozšířena, nicméně součást pro zálohování nepokrývá všechny možnosti. Z tohoto důvodu není možné vygenerovat úplnou zálohu a zajistit obnovení všech dat.", backupOutdatedWarning: "Zastaralé: V poslední době byla funkčnost aplikace značně rozšířena, nicméně součást pro zálohování nepokrývá všechny možnosti. Z tohoto důvodu není možné vygenerovat úplnou zálohu a zajistit obnovení všech dat.",
backupRecommend: "Prosím, zálohujte si ručně celý svazek nebo datovou složku (./data/).", backupRecommend: "Prosím, zálohujte si ručně celý svazek nebo datovou složku (./data/).",
"Optional": "Volitelný",
squadcast: "Squadcast",
SendKey: "SendKey",
"SMSManager API Docs": "SMSManager API Docs ",
"Gateway Type": "Gateway Typ",
SMSManager: "SMSManager",
"You can divide numbers with": "Čísla můžete dělit pomocí",
"or": "nebo",
recurringInterval: "Interval",
"Recurring": "Recurring",
strategyManual: "Aktivní/Neaktivní Ručně",
warningTimezone: "Používá se časové pásmo serveru",
weekdayShortMon: "Po",
weekdayShortTue: "Út",
weekdayShortWed: "St",
weekdayShortThu: "Čt",
weekdayShortFri: "Pá",
weekdayShortSat: "So",
weekdayShortSun: "Ne",
dayOfWeek: "Den v týdnu",
dayOfMonth: "Den v měsíci",
lastDay: "Poslední den",
lastDay1: "1. poslední den v měsíci",
lastDay2: "2. poslední den v měsíci",
lastDay3: "3. poslední den v měsíci",
lastDay4: "4. poslední den v měsíci",
"No Maintenance": "Žádna údržba",
pauseMaintenanceMsg: "Jsi si jistý, že chceš pozastavit údržbu?",
"maintenanceStatus-under-maintenance": "Údržba",
"maintenanceStatus-inactive": "Neaktivní",
"maintenanceStatus-scheduled": "Naplánováno",
"maintenanceStatus-ended": "Ukončeno",
"maintenanceStatus-unknown": "Neznámý",
"Display Timezone": "Zobrazit časové pásmo",
"Server Timezone": "Časové pásmo serveru",
statusPageMaintenanceEndDate: "Konec",
IconUrl: "Adresa URL ikony",
"Enable DNS Cache": "Povolit DNS Cache",
"Enable": "Povolit",
"Disable": "Zakázat",
dnsCacheDescription: "V některých prostředích IPv6 nemusí fungovat. Pokud narazíte na nějaké problémy, vypněte jej.",
}; };

634
src/languages/de-CH.js Normal file
View File

@@ -0,0 +1,634 @@
export default {
languageName: "Deutsch (Schweiz)",
Settings: "Einstellungen",
Dashboard: "Dashboard",
"New Update": "Update verfügbar",
Language: "Sprache",
Appearance: "Erscheinungsbild",
Theme: "Erscheinungsbild",
General: "Allgemein",
Version: "Version",
"Check Update On GitHub": "Auf GitHub nach Updates suchen",
List: "Liste",
Add: "Hinzufügen",
"Add New Monitor": "Neuen Monitor hinzufügen",
"Quick Stats": "Übersicht",
Up: "Aktiv",
Down: "Inaktiv",
Pending: "Ausstehend",
Unknown: "Unbekannt",
Pause: "Pausieren",
pauseDashboardHome: "Pausiert",
Name: "Name",
Status: "Status",
DateTime: "Datum / Uhrzeit",
Message: "Nachricht",
"No important events": "Keine wichtigen Ereignisse",
Resume: "Fortsetzen",
Edit: "Bearbeiten",
Delete: "Löschen",
Current: "Aktuell",
Uptime: "Verfügbarkeit",
"Cert Exp.": "Zertifikatsablauf",
day: "Tag | Tage",
"-day": "-Tage",
hour: "Stunde",
"-hour": "-Stunden",
checkEverySecond: "Überprüfe alle {0} Sekunden",
Response: "Antwortzeit",
Ping: "Ping",
"Monitor Type": "Monitor-Typ",
Keyword: "Suchwort",
"Friendly Name": "Anzeigename",
URL: "URL",
Hostname: "Hostname",
Port: "Port",
"Heartbeat Interval": "Prüfintervall",
Retries: "Wiederholungen",
retriesDescription: "Maximale Anzahl von Wiederholungen, bevor der Dienst als inaktiv markiert und eine Benachrichtigung gesendet wird.",
Advanced: "Erweitert",
ignoreTLSError: "Ignoriere TLS-/SSL-Fehler von Webseiten",
"Upside Down Mode": "Umgekehrter Modus",
upsideDownModeDescription: "Im umgekehrten Modus wird der Dienst als inaktiv angezeigt, wenn er erreichbar ist.",
"Max. Redirects": "Max. Weiterleitungen",
maxRedirectDescription: "Maximale Anzahl von Weiterleitungen, denen gefolgt werden soll. Auf 0 setzen, um Weiterleitungen zu deaktivieren.",
"Accepted Status Codes": "Erlaubte HTTP-Statuscodes",
acceptedStatusCodesDescription: "Statuscodes auswählen, die als erfolgreiche Verbindung gelten sollen.",
Save: "Speichern",
Notifications: "Benachrichtigungen",
"Not available, please setup.": "Nicht verfügbar, bitte einrichten.",
"Setup Notification": "Benachrichtigung einrichten",
Light: "Hell",
Dark: "Dunkel",
Auto: "Auto",
"Theme - Heartbeat Bar": "Erscheinungsbild - Zeitleiste",
Normal: "Normal",
Bottom: "Unten",
None: "Keine",
Timezone: "Zeitzone",
"Search Engine Visibility": "Sichtbarkeit für Suchmaschinen",
"Allow indexing": "Indizierung zulassen",
"Discourage search engines from indexing site": "Suchmaschinen darum bitten, die Seite nicht zu indizieren",
"Change Password": "Passwort ändern",
"Current Password": "Aktuelles Passwort",
"New Password": "Neues Passwort",
"Repeat New Password": "Neues Passwort wiederholen",
passwordNotMatchMsg: "Passwörter stimmen nicht überein.",
"Update Password": "Passwort aktualisieren",
"Disable Auth": "Authentifizierung deaktivieren",
"Enable Auth": "Authentifizierung aktivieren",
"disableauth.message1": "Bist du sicher das du die <strong>Authentifizierung deaktivieren</strong> möchtest?",
"disableauth.message2": "Dies ist für Szenarien gedacht, <strong>in denen man eine externe Authentifizierung</strong> vor Uptime Kuma geschaltet hat, wie z.B. Cloudflare Access, Authelia oder andere Authentifizierungsmechanismen.",
"Please use this option carefully!": "Bitte mit Vorsicht nutzen.",
Logout: "Ausloggen",
notificationDescription: "Benachrichtigungen müssen einem Monitor zugewiesen werden, damit diese funktionieren.",
Leave: "Verlassen",
"I understand, please disable": "Ich verstehe, bitte deaktivieren",
Confirm: "Bestätigen",
Yes: "Ja",
No: "Nein",
Username: "Benutzername",
Password: "Passwort",
"Remember me": "Angemeldet bleiben",
Login: "Einloggen",
"No Monitors, please": "Keine Monitore, bitte",
"add one": "hinzufügen",
"Notification Type": "Benachrichtigungsdienst",
Email: "E-Mail",
Test: "Test",
"Certificate Info": "Zertifikatsinformation",
keywordDescription: "Ein Suchwort in der HTML- oder JSON-Ausgabe finden. Bitte beachte: es wird zwischen Gross-/Kleinschreibung unterschieden.",
deleteMonitorMsg: "Bist du sicher, dass du den Monitor löschen möchtest?",
deleteNotificationMsg: "Möchtest du diese Benachrichtigung wirklich für alle Monitore löschen?",
resolverserverDescription: "Cloudflare ist als der Standardserver festgelegt. Dieser kann jederzeit geändert werden.",
"Resolver Server": "Auflösungsserver",
rrtypeDescription: "Wähle den RR-Typ aus, welchen du überwachen möchtest.",
"Last Result": "Letztes Ergebnis",
pauseMonitorMsg: "Bist du sicher, dass du den Monitor pausieren möchtest?",
clearEventsMsg: "Bist du sicher, dass du alle Ereignisse für diesen Monitor löschen möchtest?",
clearHeartbeatsMsg: "Bist du sicher, dass du alle Statistiken für diesen Monitor löschen möchtest?",
"Clear Data": "Lösche Daten",
Events: "Ereignisse",
Heartbeats: "Statistiken",
confirmClearStatisticsMsg: "Bist du dir sicher, dass du ALLE Statistiken löschen möchtest?",
"Create your admin account": "Erstelle dein Admin-Konto",
"Repeat Password": "Passwort erneut eingeben",
"Resource Record Type": "Ressourcen Record Typ",
Export: "Export",
Import: "Import",
respTime: "Antw.-Zeit (ms)",
notAvailableShort: "N/A",
"Default enabled": "Standardmässig aktiviert",
"Apply on all existing monitors": "Auf alle existierenden Monitore anwenden",
enableDefaultNotificationDescription: "Für jeden neuen Monitor wird diese Benachrichtigung standardmässig aktiviert. Die Benachrichtigung kann weiterhin für jeden Monitor separat deaktiviert werden.",
Create: "Erstellen",
"Auto Get": "Auto Get",
backupDescription: "Es können alle Monitore und Benachrichtigungen in einer JSON-Datei gesichert werden.",
backupDescription2: "PS: Verlaufs- und Ereignisdaten sind nicht enthalten.",
backupDescription3: "Sensible Daten wie Benachrichtigungs-Token sind in der Exportdatei enthalten, bitte bewahre sie sorgfältig auf.",
alertNoFile: "Bitte wähle eine Datei zum Importieren aus.",
alertWrongFileType: "Bitte wähle eine JSON-Datei aus.",
"Clear all statistics": "Lösche alle Statistiken",
importHandleDescription: "Wähle 'Vorhandene überspringen' aus, wenn jeder Monitor oder jede Benachrichtigung mit demselben Namen übersprungen werden soll. 'Überschreiben' löscht jeden vorhandenen Monitor sowie Benachrichtigungen.",
"Skip existing": "Vorhandene überspringen",
Overwrite: "Überschreiben",
Options: "Optionen",
confirmImportMsg: "Möchtest du das Backup wirklich importieren? Bitte stelle sicher, dass die richtige Import-Option ausgewählt ist.",
"Keep both": "Beide behalten",
twoFAVerifyLabel: "Bitte trage deinen Token ein, um zu verifizieren, dass 2FA funktioniert",
"Verify Token": "Token verifizieren",
"Setup 2FA": "2FA einrichten",
"Enable 2FA": "2FA aktivieren",
"Disable 2FA": "2FA deaktivieren",
"2FA Settings": "2FA-Einstellungen",
confirmEnableTwoFAMsg: "Bist du sicher, dass du 2FA aktivieren möchtest?",
confirmDisableTwoFAMsg: "Bist du sicher, dass du 2FA deaktivieren möchtest?",
tokenValidSettingsMsg: "Token gültig! Du kannst jetzt die 2FA-Einstellungen speichern.",
"Two Factor Authentication": "Zwei-Faktor-Authentifizierung",
Active: "Aktiv",
Inactive: "Inaktiv",
Token: "Token",
"Show URI": "URI anzeigen",
Tags: "Tags",
"Add New below or Select...": "Einen bestehenden Tag auswählen oder neuen hinzufügen...",
"Tag with this name already exist.": "Ein Tag mit diesem Namen existiert bereits.",
"Tag with this value already exist.": "Ein Tag mit diesem Wert existiert bereits.",
color: "Farbe",
"value (optional)": "Wert (optional)",
Gray: "Grau",
Red: "Rot",
Orange: "Orange",
Green: "Grün",
Blue: "Blau",
Indigo: "Indigo",
Purple: "Lila",
Pink: "Pink",
"Search...": "Suchen...",
"Heartbeat Retry Interval": "Überprüfungsintervall",
"Resend Notification if Down X times consequently": "Benachrichtigung erneut senden, wenn Inaktiv X mal hintereinander",
retryCheckEverySecond: "Alle {0} Sekunden neu versuchen",
resendEveryXTimes: "Erneut versenden alle {0} mal",
resendDisabled: "Erneut versenden deaktiviert",
"Import Backup": "Backup importieren",
"Export Backup": "Backup exportieren",
"Avg. Ping": "Ping ø",
"Avg. Response": "Antwortzeit ø",
"Entry Page": "Einstiegsseite",
statusPageNothing: "Noch ist hier nichts. Bitte füge eine Gruppe oder einen Monitor hinzu.",
"No Services": "Keine Dienste",
"All Systems Operational": "Alle Systeme betriebsbereit",
"Partially Degraded Service": "Teilweise beeinträchtigter Dienst",
"Degraded Service": "Eingeschränkter Dienst",
"Add Group": "Gruppe hinzufügen",
"Add a monitor": "Monitor hinzufügen",
"Edit Status Page": "Bearbeite Status-Seite",
"Go to Dashboard": "Gehe zum Dashboard",
"Status Page": "Status-Seite",
"Status Pages": "Status-Seiten",
telegram: "Telegram",
webhook: "Webhook",
smtp: "E-Mail (SMTP)",
discord: "Discord",
teams: "Microsoft Teams",
signal: "Signal",
gotify: "Gotify",
slack: "Slack",
"rocket.chat": "Rocket.chat",
pushover: "Pushover",
pushy: "Pushy",
octopush: "Octopush",
promosms: "PromoSMS",
lunasea: "LunaSea",
apprise: "Apprise (Unterstützung für 50+ Benachrichtigungsdienste)",
GoogleChat: "Google Chat (nur Google Workspace)",
pushbullet: "Pushbullet",
line: "Line Messenger",
mattermost: "Mattermost",
"Primary Base URL": "Primär URL",
"Push URL": "Push URL",
needPushEvery: "Du solltest diese URL alle {0} Sekunden aufrufen",
pushOptionalParams: "Optionale Parameter: {0}",
defaultNotificationName: "Mein {notification} Alarm ({number})",
here: "hier",
Required: "Erforderlich",
"Bot Token": "Bot Token",
wayToGetTelegramToken: "Hier kannst du einen Token erhalten {0}.",
"Chat ID": "Chat ID",
supportTelegramChatID: "Unterstützt Direkt Chat / Gruppe / Kanal Chat-ID's",
wayToGetTelegramChatID: "Du kannst die Chat-ID erhalten, indem du eine Nachricht an den Bot sendest und zu dieser URL gehst, um die chat_id: zu sehen.",
"YOUR BOT TOKEN HERE": "HIER DEIN BOT TOKEN",
chatIDNotFound: "Chat-ID wurde nicht gefunden: bitte sende zuerst eine Nachricht an diesen Bot",
"Post URL": "Post URL",
"Content Type": "Content Type",
webhookJsonDesc: "{0} ist gut für alle modernen HTTP-Server, wie z.B. Express.js, geeignet",
webhookFormDataDesc: "{multipart} ist gut für PHP. Das JSON muss mit {decodeFunction} verarbeitet werden",
secureOptionNone: "Keine / STARTTLS (25, 587)",
secureOptionTLS: "TLS (465)",
"Ignore TLS Error": "TLS-Fehler ignorieren",
"From Email": "Absender E-Mail",
emailCustomSubject: "Benutzerdefinierter Betreff",
"To Email": "Empfänger E-Mail",
smtpCC: "CC",
smtpBCC: "BCC",
"Discord Webhook URL": "Discord Webhook URL",
wayToGetDiscordURL: "Du kannst diese erhalten, indem du zu den Servereinstellungen gehst -> Integrationen -> Neuer Webhook",
"Bot Display Name": "Bot-Anzeigename",
"Prefix Custom Message": "Benutzerdefinierter Nachrichten Präfix",
"Hello @everyone is...": "Hallo {'@'}everyone ist...",
"Webhook URL": "Webhook URL",
wayToGetTeamsURL: "Wie eine Webhook-URL erstellt werden kann, erfährst du {0}.",
Number: "Nummer",
Recipients: "Empfänger",
needSignalAPI: "Es wird ein Signal Client mit REST-API benötigt.",
wayToCheckSignalURL: "Du kannst diese URL aufrufen, um zu sehen, wie du eine einrichtest:",
signalImportant: "WICHTIG: Gruppen und Nummern können in Empfängern nicht gemischt werden!",
"Application Token": "Anwendungstoken",
"Server URL": "Server URL",
Priority: "Priorität",
"Icon Emoji": "Icon Emoji",
"Channel Name": "Kanalname",
"Uptime Kuma URL": "Uptime Kuma URL",
aboutWebhooks: "Weitere Informationen zu Webhooks auf: {0}",
aboutChannelName: "Gebe den Kanalnamen ein in {0} Feld Kanalname, falls du den Webhook-Kanal umgehen möchtest. Ex: #other-channel",
aboutKumaURL: "Wenn das Feld für die Uptime Kuma URL leer gelassen wird, wird standardmässig die GitHub Projekt Seite verwendet.",
emojiCheatSheet: "Emoji Cheat Sheet: {0}",
"User Key": "Benutzerschlüssel",
Device: "Gerät",
"Message Title": "Nachrichtentitel",
"Notification Sound": "Benachrichtigungston",
"More info on:": "Mehr Infos auf: {0}",
pushoverDesc1: "Notfallpriorität (2) hat standardmässig 30 Sekunden Auszeit zwischen den Versuchen und läuft nach 1 Stunde ab.",
pushoverDesc2: "Fülle das Geräte Feld aus, wenn du Benachrichtigungen an verschiedene Geräte senden möchtest.",
"SMS Type": "SMS Typ",
octopushTypePremium: "Premium (Schnell - zur Benachrichtigung empfohlen)",
octopushTypeLowCost: "Kostengünstig (Langsam - manchmal vom Betreiber gesperrt)",
checkPrice: "Prüfe {0} Preise:",
octopushLegacyHint: "Verwendest du die Legacy-Version von Octopush (2011-2020) oder die neue Version?",
"Check octopush prices": "Vergleiche die Oktopush Preise {0}.",
octopushPhoneNumber: "Telefonnummer (Internationales Format, z.B : +49612345678) ",
octopushSMSSender: "Name des SMS-Absenders : 3-11 alphanumerische Zeichen und Leerzeichen (a-zA-Z0-9)",
"LunaSea Device ID": "LunaSea Geräte ID",
"Apprise URL": "Apprise URL",
"Example:": "Beispiel: {0}",
"Read more:": "Weiterlesen: {0}",
"Status:": "Status: {0}",
"Read more": "Weiterlesen",
appriseInstalled: "Apprise ist installiert.",
appriseNotInstalled: "Apprise ist nicht installiert. {0}",
"Access Token": "Access Token",
"Channel access token": "Channel access token",
"Line Developers Console": "Line Developers Console",
lineDevConsoleTo: "Line Developers Console - {0}",
"Basic Settings": "Basic Settings",
"User ID": "User ID",
"Messaging API": "Messaging API",
wayToGetLineChannelToken: "Rufe zuerst {0} auf, erstelle dann einen Provider und Channel (Messaging API). Als nächstes kannst du den Channel access token und die User ID aus den oben genannten Menüpunkten abrufen.",
"Icon URL": "Icon URL",
aboutIconURL: "Du kannst einen Link zu einem Bild in 'Icon URL' übergeben um das Standardprofilbild zu überschreiben. Wird nicht verwendet, wenn ein Icon Emoji gesetzt ist.",
aboutMattermostChannelName: "Du kannst den Standardkanal, auf dem der Webhook gesendet wird überschreiben, indem der Kanalnamen in das Feld 'Channel Name' eingeben wird. Dies muss in den Mattermost Webhook-Einstellungen aktiviert werden. Ex: #other-channel",
matrix: "Matrix",
promosmsTypeEco: "SMS ECO - billig, aber langsam und oft überladen. Auf polnische Empfänger beschränkt.",
promosmsTypeFlash: "SMS FLASH - Die Nachricht wird automatisch auf dem Empfängergerät angezeigt. Auf polnische Empfänger beschränkt.",
promosmsTypeFull: "SMS FULL - Premium Stufe von SMS, es kann der Absendernamen verwendet werden (Der Name musst zuerst registriert werden). Zuverlässig für Warnungen.",
promosmsTypeSpeed: "SMS SPEED - Höchste Priorität im System. Sehr schnell und zuverlässig, aber teuer (Ungefähr das doppelte von SMS FULL).",
promosmsPhoneNumber: "Telefonnummer (für polnische Empfänger können die Vorwahlen übersprungen werden)",
promosmsSMSSender: "Name des SMS-Absenders : vorregistrierter Name oder einer der Standardwerte: InfoSMS, SMS Info, MaxSMS, INFO, SMS",
"Feishu WebHookUrl": "Feishu Webhook URL",
matrixHomeserverURL: "Heimserver URL (mit http(s):// und optionalen Ports)",
"Internal Room Id": "Interne Raum-ID",
matrixDesc1: "Die interne Raum-ID findest du im erweiterten Bereich der Raumeinstellungen im Matrix-Client. Es sollte aussehen wie z.B. !QMdRCpUIfLwsfjxye6:home.server.",
matrixDesc2: "Es wird dringend empfohlen einen neuen Benutzer anzulegen und nicht den Zugriffstoken deines eigenen Matrix-Benutzers zu verwenden. Anderenfalls ermöglicht es vollen Zugriff auf dein Konto und alle Räume, denen du beigetreten bist. Erstelle stattdessen einen neuen Benutzer und lade ihn nur in den Raum ein, in dem du die Benachrichtigung erhalten möchtest. Du kannst den Zugriffstoken erhalten, indem du Folgendes ausführst {0}",
Method: "Method",
Body: "Body",
Headers: "Headers",
PushUrl: "Push URL",
HeadersInvalidFormat: "Der Header ist kein gültiges JSON: ",
BodyInvalidFormat: "Der Body ist kein gültiges JSON: ",
"Monitor History": "Monitor Verlauf",
clearDataOlderThan: "Bewahre die Aufzeichnungsdaten für {0} Tage auf.",
PasswordsDoNotMatch: "Passwörter stimmen nicht überein.",
records: "Einträge",
"One record": "Ein Eintrag",
steamApiKeyDescription: "Um einen Steam Game Server zu überwachen, wird ein Steam Web-API-Schlüssel benötigt. Dieser kann hier registriert werden: ",
"Current User": "Aktueller Benutzer",
recent: "Letzte",
Done: "Fertig",
Info: "Info",
Security: "Sicherheit",
"Steam API Key": "Steam API Key",
"Shrink Database": "Datenbank verkleinern",
"Pick a RR-Type...": "Wähle ein RR-Typ aus...",
"Pick Accepted Status Codes...": "Wähle akzeptierte Statuscodes aus...",
Default: "Standard",
"HTTP Options": "HTTP Optionen",
"Create Incident": "Vorfall erstellen",
Title: "Titel",
Content: "Inhalt",
Style: "Stil",
info: "info",
warning: "warnung",
danger: "gefahr",
primary: "primär",
light: "hell",
dark: "dunkel",
Post: "Eintrag",
"Please input title and content": "Bitte Titel und Inhalt eingeben",
Created: "Erstellt",
"Last Updated": "Zuletzt aktualisiert",
Unpin: "Loslösen",
"Switch to Light Theme": "Zu hellem Thema wechseln",
"Switch to Dark Theme": "Zum dunklen Thema wechseln",
"Show Tags": "Tags anzeigen",
"Hide Tags": "Tags ausblenden",
Description: "Beschreibung",
"No monitors available.": "Keine Monitore verfügbar.",
"Add one": "Hinzufügen",
"No Monitors": "Keine Monitore",
"Untitled Group": "Gruppe ohne Titel",
Services: "Dienste",
Discard: "Verwerfen",
Cancel: "Abbrechen",
"Powered by": "Powered by",
shrinkDatabaseDescription: "Löse VACUUM für die SQLite Datenbank aus. Wenn die Datenbank nach 1.10.0 erstellt wurde, ist AUTO_VACUUM bereits aktiviert und diese Aktion ist nicht erforderlich.",
serwersms: "SerwerSMS.pl",
serwersmsAPIUser: "API Benutzername (inkl. webapi_ prefix)",
serwersmsAPIPassword: "API Passwort",
serwersmsPhoneNumber: "Telefonnummer",
serwersmsSenderName: "Name des SMS-Absenders (über Kundenportal registriert)",
stackfield: "Stackfield",
clicksendsms: "ClickSend SMS",
apiCredentials: "API Zugangsdaten",
smtpDkimSettings: "DKIM Einstellungen",
smtpDkimDesc: "Details zur Konfiguration sind in der Nodemailer DKIM {0} zu finden.",
documentation: "Dokumentation",
smtpDkimDomain: "Domain Name",
smtpDkimKeySelector: "Schlüssel Auswahl",
smtpDkimPrivateKey: "Privater Schlüssel",
smtpDkimHashAlgo: "Hash-Algorithmus (Optional)",
smtpDkimheaderFieldNames: "Zu validierende Header-Schlüssel (optional)",
smtpDkimskipFields: "Zu ignorierende Header Schlüssel (optional)",
PushByTechulus: "Push by Techulus",
gorush: "Gorush",
alerta: "Alerta",
alertaApiEndpoint: "API Endpunkt",
alertaEnvironment: "Umgebung",
alertaApiKey: "API Schlüssel",
alertaAlertState: "Alarmstatus",
alertaRecoverState: "Wiederherstellungsstatus",
deleteStatusPageMsg: "Bist du sicher, dass du diese Status-Seite löschen willst?",
Proxies: "Proxies",
default: "Standard",
enabled: "Aktiviert",
setAsDefault: "Als Standard setzen",
deleteProxyMsg: "Bist du sicher, dass du diesen Proxy für alle Monitore löschen willst?",
proxyDescription: "Proxies müssen einem Monitor zugewiesen werden, um zu funktionieren.",
enableProxyDescription: "Dieser Proxy wird keinen Effekt auf Monitor-Anfragen haben, bis er aktiviert ist. Du kannst ihn temporär von allen Monitoren nach Aktivierungsstatus deaktivieren.",
setAsDefaultProxyDescription: "Dieser Proxy wird standardmässig für alle neuen Monitore aktiviert sein. Du kannst den Proxy immer noch für jeden Monitor einzeln deaktivieren.",
"Certificate Chain": "Zertifikatskette",
Valid: "Gültig",
Invalid: "Ungültig",
AccessKeyId: "AccessKey ID",
SecretAccessKey: "AccessKey Secret",
PhoneNumbers: "Telefonnummern",
TemplateCode: "Vorlagencode",
SignName: "Signaturname",
"Sms template must contain parameters: ": "SMS Vorlage muss folgende Parameter enthalten: ",
"Bark Endpoint": "Bark Endpunkt",
WebHookUrl: "Webhook URL",
SecretKey: "Geheimer Schlüssel",
"For safety, must use secret key": "Zur Sicherheit muss ein geheimer Schlüssel verwendet werden",
"Device Token": "Gerätetoken",
Platform: "Platform",
iOS: "iOS",
Android: "Android",
Huawei: "Huawei",
High: "Hoch",
Retry: "Wiederholungen",
Topic: "Thema",
"WeCom Bot Key": "WeCom Bot Schlüssel",
"Setup Proxy": "Proxy einrichten",
"Proxy Protocol": "Proxy Protokoll",
"Proxy Server": "Proxy-Server",
"Proxy server has authentication": "Proxy-Server hat Authentifizierung",
User: "Benutzer",
Installed: "Installiert",
"Not installed": "Nicht installiert",
Running: "Läuft",
"Not running": "Gestoppt",
"Remove Token": "Token entfernen",
Start: "Start",
Stop: "Stop",
"Uptime Kuma": "Uptime Kuma",
"Add New Status Page": "Neue Status-Seite hinzufügen",
Slug: "Slug",
"Accept characters:": "Akzeptierte Zeichen:",
startOrEndWithOnly: "Nur mit {0} anfangen und enden",
"No consecutive dashes": "Keine aufeinanderfolgenden Bindestriche",
Next: "Weiter",
"The slug is already taken. Please choose another slug.": "Der Slug ist bereits in Verwendung. Bitte wähle einen anderen.",
"No Proxy": "Kein Proxy",
Authentication: "Authentifizierung",
"HTTP Basic Auth": "HTTP Basisauthentifizierung",
"New Status Page": "Neue Status-Seite",
"Page Not Found": "Seite nicht gefunden",
"Reverse Proxy": "Reverse Proxy",
Backup: "Sicherung",
About: "Über",
wayToGetCloudflaredURL: "(Lade Cloudflare von {0} herunter)",
cloudflareWebsite: "Cloudflare Website",
"Message:": "Nachricht:",
"Don't know how to get the token? Please read the guide:": "Du weisst nicht, wie man den Token bekommt? Lies die Anleitung dazu:",
"The current connection may be lost if you are currently connecting via Cloudflare Tunnel. Are you sure want to stop it? Type your current password to confirm it.": "Die aktuelle Verbindung kann unterbrochen werden, wenn du aktuell über Cloudflare Tunnel verbunden bist. Bist du sicher, dass du es stoppen willst? Gib zur Bestätigung dein aktuelles Passwort ein.",
"Other Software": "Andere Software",
"For example: nginx, Apache and Traefik.": "Zum Beispiel: nginx, Apache und Traefik.",
"Please read": "Bitte lesen",
"Subject:": "Betreff:",
"Valid To:": "Gültig bis:",
"Days Remaining:": "Tage verbleibend:",
"Issuer:": "Aussteller:",
"Fingerprint:": "Fingerabdruck:",
"No status pages": "Keine Status-Seiten",
"Domain Name Expiry Notification": "Benachrichtigung bei Ablauf des Domainnamens",
Customize: "Anpassen",
"Custom Footer": "Eigener Footer",
"Custom CSS": "Eigenes CSS",
"Footer Text": "Fusszeile",
"Show Powered By": "Zeige 'Powered By'",
"Date Created": "Erstellt am",
"Domain Names": "Domainnamen",
signedInDisp: "Angemeldet als {0}",
signedInDispDisabled: "Authentifizierung deaktiviert.",
dnsPortDescription: "DNS server port. Standard ist 53. Der Port kann jederzeit geändert werden.",
topic: "Thema",
topicExplanation: "MQTT Thema für den monitor",
successMessage: "Erfolgsnachricht",
successMessageExplanation: "MQTT Nachricht, die als Erfolg angesehen wird",
error: "Fehler",
critical: "kritisch",
wayToGetPagerDutyKey: "Dieser kann unter Service -> Service Directory -> (Select a service) -> Integrations -> Add integration gefunden werden. Hier muss nach \"Events API V2\" gesucht werden. Mehr informationen {0}",
"Integration Key": "Schlüssel der Integration",
"Integration URL": "URL der Integration",
"Auto resolve or acknowledged": "Automatisch lösen oder bestätigen",
"do nothing": "nichts tun",
"auto acknowledged": "automatisch bestätigen",
"auto resolve": "automatisch lösen",
"Bark Group": "Bark Gruppe",
"Bark Sound": "Bark Klang",
"HTTP Headers": "HTTP Kopfzeilen",
"Trust Proxy": "Vertrauenswürdiger Proxy",
Proxy: "Proxy",
HomeAssistant: "Home Assistant",
onebotHttpAddress: "OneBot HTTP Adresse",
onebotMessageType: "OneBot Nachrichtentyp",
onebotGroupMessage: "Gruppe",
onebotPrivateMessage: "Privat",
onebotUserOrGroupId: "Gruppe/Nutzer ID",
onebotSafetyTips: "Zur Sicherheit ein access token setzen",
"PushDeer Key": "PushDeer Schlüssel",
RadiusSecret: "Radius Geheimnis",
RadiusSecretDescription: "Geteiltes Geheimnis zwischen Client und Server",
RadiusCalledStationId: "ID der angesprochenen Station",
RadiusCalledStationIdDescription: "Identifikation des angesprochenen Geräts",
RadiusCallingStationId: "ID der ansprechenden Station",
RadiusCallingStationIdDescription: "Identifikation des ansprechenden Geräts",
"Certificate Expiry Notification": "Benachrichtigung ablaufendes Zertifikat",
"API Username": "API Nutzername",
"API Key": "API Schlüssel",
"Recipient Number": "Empfängernummer",
"From Name/Number": "Von Name/Nummer",
"Leave blank to use a shared sender number.": "Leer lassen um eine geteilte Absendernummer zu nutzen.",
"Octopush API Version": "Octopush API Version",
"Legacy Octopush-DM": "Legacy Octopush-DM",
endpoint: "Endpunkt",
octopushAPIKey: "\"API Schlüssel\" der HTTP API Zugangsdaten im control panel",
octopushLogin: "\"Login\" der HTTP API Zugangsdaten im control panel",
promosmsLogin: "API Login Name",
promosmsPassword: "API Password",
"pushoversounds pushover": "Pushover (Standard)",
"pushoversounds bike": "Fahrrad",
"pushoversounds bugle": "Signalhorn",
"pushoversounds cashregister": "Kasse",
"pushoversounds classical": "Klassisch",
"pushoversounds cosmic": "Kosmisch",
"pushoversounds falling": "Abfallend",
"pushoversounds gamelan": "Gamelan",
"pushoversounds incoming": "Eingang",
"pushoversounds intermission": "Pause",
"pushoversounds magic": "Magisch",
"pushoversounds mechanical": "Mechanisch",
"pushoversounds pianobar": "Piano Bar",
"pushoversounds siren": "Sirene",
"pushoversounds spacealarm": "Space Alarm",
"pushoversounds tugboat": "Schlepper Horn",
"pushoversounds alien": "Ausserirdisch (lang)",
"pushoversounds climb": "Ansteigende (lang)",
"pushoversounds persistent": "Hartnäckig (lang)",
"pushoversounds echo": "Pushover Echo (lang)",
"pushoversounds updown": "Auf und Ab (lang)",
"pushoversounds vibrate": "Nur vibrieren",
"pushoversounds none": "Nichts (Stille)",
pushyAPIKey: "Geheimer API Schlüssel",
pushyToken: "Gerätetoken",
"Show update if available": "Verfügbare Updates anzeigen",
"Also check beta release": "Auch nach beta Versionen schauen",
"Using a Reverse Proxy?": "Wird ein Reverse Proxy genutzt?",
"Check how to config it for WebSocket": "Prüfen, wie er für die Nutzung mit WebSocket konfiguriert wird",
"Steam Game Server": "Steam Game Server",
"Most likely causes:": "Wahrscheinliche Ursachen:",
"The resource is no longer available.": "Die Quelle ist nicht mehr verfügbar.",
"There might be a typing error in the address.": "Es gibt einen Tippfehler in der Adresse.",
"What you can try:": "Was du versuchen kannst:",
"Retype the address.": "Schreibe die Adresse erneut.",
"Go back to the previous page.": "Gehe zur vorigen Seite.",
"Coming Soon": "Kommt bald",
wayToGetClickSendSMSToken: "Du kannst einen API Nutzernamen und Schlüssel unter {0} erhalten.",
"Connection String": "Verbindungstext",
Query: "Abfrage",
settingsCertificateExpiry: "TLS Zertifikatsablauf",
certificationExpiryDescription: "HTTPS Monitore senden eine Benachrichtigung, wenn das Zertifikat abläuft in:",
"Setup Docker Host": "Docker Host einrichten",
"Connection Type": "Verbindungstyp",
"Docker Daemon": "Docker Daemon",
deleteDockerHostMsg: "Bist du sicher diesen docker host für alle Monitore zu löschen?",
socket: "Socket",
tcp: "TCP / HTTP",
"Docker Container": "Docker Container",
"Container Name / ID": "Container Name / ID",
"Docker Host": "Docker Host",
"Docker Hosts": "Docker Hosts",
"ntfy Topic": "ntfy Thema",
Domain: "Domain",
Workstation: "Workstation",
disableCloudflaredNoAuthMsg: "Du bist im nicht-authentifizieren Modus, ein Passwort wird nicht benötigt.",
trustProxyDescription: "Vertraue 'X-Forwarded-*' headern. Wenn man die richtige client IP haben möchte und Uptime Kuma hinter einem Proxy wie Nginx or Apache läuft, wollte dies aktiviert werden.",
wayToGetLineNotifyToken: "Du kannst hier ein Token erhalten: {0}",
Examples: "Beispiele",
"Home Assistant URL": "Home Assistant URL",
"Long-Lived Access Token": "Lange gültiges Access Token",
"Long-Lived Access Token can be created by clicking on your profile name (bottom left) and scrolling to the bottom then click Create Token. ": "Lange gültige Access Token können durch klicken auf den Profilnamen (unten links) und dann einen Klick auf Create Token am Ende erstellt werden. ",
"Notification Service": "Benachrichtigungsdienst",
"default: notify all devices": "standard: Alle Geräte benachrichtigen",
"A list of Notification Services can be found in Home Assistant under \"Developer Tools > Services\" search for \"notification\" to find your device/phone name.": "Eine Liste der Benachrichtigungsdienste kann im Home Assistant unter \"Developer Tools > Services\" gefunden werden, wnen man nach \"notification\" sucht um den Geräte-/Telefonnamen zu finden.",
"Automations can optionally be triggered in Home Assistant:": "Automatisierungen können optional im Home Assistant ausgelöst werden:",
"Trigger type:": "Auslöser:",
"Event type:": "Ereignistyp:",
"Event data:": "Ereignis daten:",
"Then choose an action, for example switch the scene to where an RGB light is red.": "Dann eine Aktion wählen, zum Beispiel eine Scene wählen in der ein RGB Licht rot ist.",
"Frontend Version": "Frontend Version",
"Frontend Version do not match backend version!": "Die Frontend Version stimmt nicht mit der backend version überein!",
Maintenance: "Wartung",
statusMaintenance: "Wartung",
"Schedule maintenance": "Geplante Wartung",
"Affected Monitors": "Betroffene Monitore",
"Pick Affected Monitors...": "Wähle betroffene Monitore...",
"Start of maintenance": "Beginn der Wartung",
"All Status Pages": "Alle Status Seiten",
"Select status pages...": "Wähle Status Seiten...",
recurringIntervalMessage: "einmal pro Tag ausgeführt | Wird alle {0} Tage ausgführt",
affectedMonitorsDescription: "Wähle alle Monitore die von der Wartung betroffen sind",
affectedStatusPages: "Zeige diese Nachricht auf ausgewählten Status Seiten",
atLeastOneMonitor: "Wähle mindestens einen Monitor",
deleteMaintenanceMsg: "Möchtest du diese Wartung löschen?",
"Base URL": "Basis URL",
goAlertInfo: "GoAlert ist eine Open-Source Applikation für Rufbereitschaftsplanung, automatische Eskalation und Benachrichtigung (z.B. SMS oder Telefonanrufe). Beauftragen Sie automatisch die richtige Person, auf die richtige Art und Weise und zum richtigen Zeitpunkt. {0}",
goAlertIntegrationKeyInfo: "Bekommt einen generischen API Schlüssel in folgenden Format \"aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee\". Normalerweise entspricht dies dem Wert des Token aus der URL.",
goAlert: "GoAlert",
backupOutdatedWarning: "Veraltet: Eine menge Neuerungen sind eingeflossen und diese Funktion wurde etwas vernachlässigt worden. Es kann kein vollständiges Backup erstellt oder eingespielt werden.",
backupRecommend: "Bitte Backup das Volume oder den Ordner (./ data /) selbst.",
Optional: "Optional",
squadcast: "Squadcast",
SendKey: "SendKey",
"SMSManager API Docs": "SMSManager API Dokumente",
"Gateway Type": "Gateway Type",
SMSManager: "SMSManager",
"You can divide numbers with": "Du kannst Zahlen teilen mit",
or: "oder",
recurringInterval: "Intervall",
Recurring: "Wiederkehrend",
strategyManual: "Active/Inactive Manually",
warningTimezone: "Es wird die Zeitzone des Servers genutzt",
weekdayShortMon: "Mo",
weekdayShortTue: "Di",
weekdayShortWed: "Mi",
weekdayShortThu: "Do",
weekdayShortFri: "Fr",
weekdayShortSat: "Sa",
weekdayShortSun: "So",
dayOfWeek: "Tag der Woche",
dayOfMonth: "Tag im Monat",
lastDay: "Letzter Tag",
lastDay1: "Letzter Tag im Monat",
lastDay2: "Vorletzer Tag im Monat",
lastDay3: "3. letzter Tag im Monat",
lastDay4: "4. letzter Tag im Monat",
"No Maintenance": "Keine Wartung",
pauseMaintenanceMsg: "Möchtest du wirklich pausieren?",
"maintenanceStatus-under-maintenance": "Unter Wartung",
"maintenanceStatus-inactive": "Inaktiv",
"maintenanceStatus-scheduled": "Geplant",
"maintenanceStatus-ended": "Ende",
"maintenanceStatus-unknown": "Unbekannt",
"Display Timezone": "Zeitzone anzeigen",
"Server Timezone": "Server Zeitzone",
statusPageMaintenanceEndDate: "Ende",
};

View File

@@ -96,7 +96,7 @@ export default {
"Notification Type": "Benachrichtigungsdienst", "Notification Type": "Benachrichtigungsdienst",
Email: "E-Mail", Email: "E-Mail",
Test: "Test", Test: "Test",
"Certificate Info": "Zertifikatsinfo", "Certificate Info": "Zertifikatsinformation",
keywordDescription: "Ein Suchwort in der HTML- oder JSON-Ausgabe finden. Bitte beachte: es wird zwischen Groß-/Kleinschreibung unterschieden.", keywordDescription: "Ein Suchwort in der HTML- oder JSON-Ausgabe finden. Bitte beachte: es wird zwischen Groß-/Kleinschreibung unterschieden.",
deleteMonitorMsg: "Bist du sicher, dass du den Monitor löschen möchtest?", deleteMonitorMsg: "Bist du sicher, dass du den Monitor löschen möchtest?",
deleteNotificationMsg: "Möchtest du diese Benachrichtigung wirklich für alle Monitore löschen?", deleteNotificationMsg: "Möchtest du diese Benachrichtigung wirklich für alle Monitore löschen?",
@@ -181,7 +181,7 @@ export default {
"Degraded Service": "Eingeschränkter Dienst", "Degraded Service": "Eingeschränkter Dienst",
"Add Group": "Gruppe hinzufügen", "Add Group": "Gruppe hinzufügen",
"Add a monitor": "Monitor hinzufügen", "Add a monitor": "Monitor hinzufügen",
"Edit Status Page": "Bearbeite Status-Seite", "Edit Status Page": "Statusseite bearbeiten",
"Go to Dashboard": "Gehe zum Dashboard", "Go to Dashboard": "Gehe zum Dashboard",
"Status Page": "Status-Seite", "Status Page": "Status-Seite",
"Status Pages": "Status-Seiten", "Status Pages": "Status-Seiten",
@@ -204,7 +204,7 @@ export default {
pushbullet: "Pushbullet", pushbullet: "Pushbullet",
line: "Line Messenger", line: "Line Messenger",
mattermost: "Mattermost", mattermost: "Mattermost",
"Primary Base URL": "Primär URL", "Primary Base URL": "Primäre Basis-URL",
"Push URL": "Push URL", "Push URL": "Push URL",
needPushEvery: "Du solltest diese URL alle {0} Sekunden aufrufen", needPushEvery: "Du solltest diese URL alle {0} Sekunden aufrufen",
pushOptionalParams: "Optionale Parameter: {0}", pushOptionalParams: "Optionale Parameter: {0}",
@@ -383,7 +383,7 @@ export default {
deleteProxyMsg: "Bist du sicher, dass du diesen Proxy für alle Monitore löschen willst?", deleteProxyMsg: "Bist du sicher, dass du diesen Proxy für alle Monitore löschen willst?",
proxyDescription: "Proxies müssen einem Monitor zugewiesen werden, um zu funktionieren.", proxyDescription: "Proxies müssen einem Monitor zugewiesen werden, um zu funktionieren.",
enableProxyDescription: "Dieser Proxy wird keinen Effekt auf Monitor-Anfragen haben, bis er aktiviert ist. Du kannst ihn temporär von allen Monitoren nach Aktivierungsstatus deaktivieren.", enableProxyDescription: "Dieser Proxy wird keinen Effekt auf Monitor-Anfragen haben, bis er aktiviert ist. Du kannst ihn temporär von allen Monitoren nach Aktivierungsstatus deaktivieren.",
setAsDefaultProxyDescription: "Dieser Proxy wird standardmäßig für alle neuen Monitore aktiviert sein. Du kannst den Proxy immernoch für jeden Monitor einzeln deaktivieren.", setAsDefaultProxyDescription: "Dieser Proxy wird standardmäßig für alle neuen Monitore aktiviert sein. Du kannst den Proxy immer noch für jeden Monitor einzeln deaktivieren.",
"Certificate Chain": "Zertifikatskette", "Certificate Chain": "Zertifikatskette",
Valid: "Gültig", Valid: "Gültig",
Invalid: "Ungültig", Invalid: "Ungültig",
@@ -496,7 +496,7 @@ export default {
"API Key": "API Schlüssel", "API Key": "API Schlüssel",
"Recipient Number": "Empfängernummer", "Recipient Number": "Empfängernummer",
"From Name/Number": "Von Name/Nummer", "From Name/Number": "Von Name/Nummer",
"Leave blank to use a shared sender number.": "Leer lassen um eine geteilte Sendernummer zu nutzen.", "Leave blank to use a shared sender number.": "Leer lassen um eine geteilte Absendernummer zu nutzen.",
"Octopush API Version": "Octopush API Version", "Octopush API Version": "Octopush API Version",
"Legacy Octopush-DM": "Legacy Octopush-DM", "Legacy Octopush-DM": "Legacy Octopush-DM",
endpoint: "Endpunkt", endpoint: "Endpunkt",
@@ -530,7 +530,7 @@ export default {
pushyAPIKey: "Geheimer API Schlüssel", pushyAPIKey: "Geheimer API Schlüssel",
pushyToken: "Gerätetoken", pushyToken: "Gerätetoken",
"Show update if available": "Verfügbare Updates anzeigen", "Show update if available": "Verfügbare Updates anzeigen",
"Also check beta release": "Auch nach beta Versionen schauen", "Also check beta release": "Auch nach Beta Versionen schauen",
"Using a Reverse Proxy?": "Wird ein Reverse Proxy genutzt?", "Using a Reverse Proxy?": "Wird ein Reverse Proxy genutzt?",
"Check how to config it for WebSocket": "Prüfen, wie er für die Nutzung mit WebSocket konfiguriert wird", "Check how to config it for WebSocket": "Prüfen, wie er für die Nutzung mit WebSocket konfiguriert wird",
"Steam Game Server": "Steam Game Server", "Steam Game Server": "Steam Game Server",
@@ -568,9 +568,9 @@ export default {
"Long-Lived Access Token can be created by clicking on your profile name (bottom left) and scrolling to the bottom then click Create Token. ": "Lange gültige Access Token können durch klicken auf den Profilnamen (unten links) und dann einen Klick auf Create Token am Ende erstellt werden. ", "Long-Lived Access Token can be created by clicking on your profile name (bottom left) and scrolling to the bottom then click Create Token. ": "Lange gültige Access Token können durch klicken auf den Profilnamen (unten links) und dann einen Klick auf Create Token am Ende erstellt werden. ",
"Notification Service": "Benachrichtigungsdienst", "Notification Service": "Benachrichtigungsdienst",
"default: notify all devices": "standard: Alle Geräte benachrichtigen", "default: notify all devices": "standard: Alle Geräte benachrichtigen",
"A list of Notification Services can be found in Home Assistant under \"Developer Tools > Services\" search for \"notification\" to find your device/phone name.": "Eine Liste der Benachrichtigungsdiesnte kann im Home Assistant unter \"Developer Tools > Services\" gefunden werden, wnen man nach \"notification\" sucht um den Geräte-/Telefonnamen zu finden.", "A list of Notification Services can be found in Home Assistant under \"Developer Tools > Services\" search for \"notification\" to find your device/phone name.": "Eine Liste der Benachrichtigungsdienste kann im Home Assistant unter \"Developer Tools > Services\" gefunden werden, wnen man nach \"notification\" sucht um den Geräte-/Telefonnamen zu finden.",
"Automations can optionally be triggered in Home Assistant:": "Automatisierungen können optional im Home Assistant ausgelöst werden:", "Automations can optionally be triggered in Home Assistant:": "Automatisierungen können optional im Home Assistant ausgelöst werden:",
"Trigger type:": "Auslösertyp:", "Trigger type:": "Auslöser:",
"Event type:": "Ereignistyp:", "Event type:": "Ereignistyp:",
"Event data:": "Ereignis daten:", "Event data:": "Ereignis daten:",
"Then choose an action, for example switch the scene to where an RGB light is red.": "Dann eine Aktion wählen, zum Beispiel eine Scene wählen in der ein RGB Licht rot ist.", "Then choose an action, for example switch the scene to where an RGB light is red.": "Dann eine Aktion wählen, zum Beispiel eine Scene wählen in der ein RGB Licht rot ist.",
@@ -583,18 +583,18 @@ export default {
"Pick Affected Monitors...": "Wähle betroffene Monitore...", "Pick Affected Monitors...": "Wähle betroffene Monitore...",
"Start of maintenance": "Beginn der Wartung", "Start of maintenance": "Beginn der Wartung",
"All Status Pages": "Alle Status Seiten", "All Status Pages": "Alle Status Seiten",
"Select status pages...": "Wähle Status Seiten...", "Select status pages...": "Statusseiten auswählen...",
recurringIntervalMessage: "einmal pro Tag ausgeführt | Wird alle {0} Tage ausgführt", recurringIntervalMessage: "Einmal pro Tag ausgeführt | Wird alle {0} Tage ausgführt",
affectedMonitorsDescription: "Wähle alle Monitore die von der Wartung betroffen sind", affectedMonitorsDescription: "Wähle Monitore aus, die von der aktuellen Wartung betroffen sind",
affectedStatusPages: "Zeige diese Nachricht auf ausgewählten Status Seiten", affectedStatusPages: "Diese Wartungsmeldung auf ausgewählten Statusseiten anzeigen",
atLeastOneMonitor: "Wähle mindestens einen Monitor", atLeastOneMonitor: "Wähle mindestens einen Monitor",
deleteMaintenanceMsg: "Möchtest du diese Wartung löschen?", deleteMaintenanceMsg: "Möchtest du diese Wartung löschen?",
"Base URL": "Basis URL", "Base URL": "Basis URL",
goAlertInfo: "GoAlert ist eine Open-Source Applikation für Rufbereitschaft Planung, automaitsche Esklaltion und Benachrichtigung (z.B. SMS oder Telefonanrufe). Beauftragen Sie automatisch die richtige Person, auf die richtige Art und Weise und zum richtigen Zeitpunkt! {0}", goAlertInfo: "GoAlert ist eine Open-Source Applikation für Rufbereitschaftsplanung, automatische Eskalation und Benachrichtigung (z.B. SMS oder Telefonanrufe). Beauftragen Sie automatisch die richtige Person, auf die richtige Art und Weise und zum richtigen Zeitpunkt. {0}",
goAlertIntegrationKeyInfo: "Bekomm einenen gernerischen API Schlüssel in folgeden Format \"aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee\". Normalerweise der Wert des Token aus der URL.", goAlertIntegrationKeyInfo: "Bekommt einen generischen API Schlüssel in folgenden Format \"aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee\". Normalerweise entspricht dies dem Wert des Token aus der URL.",
goAlert: "GoAlert", goAlert: "GoAlert",
backupOutdatedWarning: "Veraltet: Eine menge Neuerungen sind eingeflossen und diese Funktion wurde etwas vernachlässigt worden. Es kann kein vollständiges Backup erstellt oder eingspielt werden.", backupOutdatedWarning: "Veraltet: Da viele Funktionen hinzugefügt wurden und diese Sicherungsfunktion nicht mehr gepflegt wird, kann sie keine vollständige Sicherung erstellen oder wiederherstellen.",
backupRecommend: "Bitte Backup das Volume oder den Ordner (./ data /) selbst.", backupRecommend: "Bitte sichere stattdessen das Volume oder den Datenordner (./data/) direkt.",
Optional: "Optional", Optional: "Optional",
squadcast: "Squadcast", squadcast: "Squadcast",
SendKey: "SendKey", SendKey: "SendKey",
@@ -605,8 +605,11 @@ export default {
or: "oder", or: "oder",
recurringInterval: "Intervall", recurringInterval: "Intervall",
Recurring: "Wiederkehrend", Recurring: "Wiederkehrend",
strategyManual: "Active/Inactive Manually", "Single Maintenance Window": "Einzigartiges Wartungsfenster",
warningTimezone: "Es wird die Zeitzone des Servers genutzt", "Maintenance Time Window of a Day": "Zeitfenster für die Wartung",
"Effective Date Range": "Bereich der Wirksamkeitsdaten",
strategyManual: "Aktiv/Inaktiv Manuell",
warningTimezone: "Es wird die Zeitzone des Servers verwendet",
weekdayShortMon: "Mo", weekdayShortMon: "Mo",
weekdayShortTue: "Di", weekdayShortTue: "Di",
weekdayShortWed: "Mi", weekdayShortWed: "Mi",
@@ -622,6 +625,7 @@ export default {
lastDay3: "3. letzter Tag im Monat", lastDay3: "3. letzter Tag im Monat",
lastDay4: "4. letzter Tag im Monat", lastDay4: "4. letzter Tag im Monat",
"No Maintenance": "Keine Wartung", "No Maintenance": "Keine Wartung",
"Schedule Maintenance": "Wartung planen",
pauseMaintenanceMsg: "Möchtest du wirklich pausieren?", pauseMaintenanceMsg: "Möchtest du wirklich pausieren?",
"maintenanceStatus-under-maintenance": "Unter Wartung", "maintenanceStatus-under-maintenance": "Unter Wartung",
"maintenanceStatus-inactive": "Inaktiv", "maintenanceStatus-inactive": "Inaktiv",
@@ -630,5 +634,8 @@ export default {
"maintenanceStatus-unknown": "Unbekannt", "maintenanceStatus-unknown": "Unbekannt",
"Display Timezone": "Zeitzone anzeigen", "Display Timezone": "Zeitzone anzeigen",
"Server Timezone": "Server Zeitzone", "Server Timezone": "Server Zeitzone",
"Date and Time": "Datum und Zeit",
"DateTime Range": "Datums- und Zeitbereich",
Strategy: "Strategie",
statusPageMaintenanceEndDate: "Ende", statusPageMaintenanceEndDate: "Ende",
}; };

View File

@@ -609,16 +609,16 @@ export default {
goAlert: "GoAlert", goAlert: "GoAlert",
backupOutdatedWarning: "Deprecated: Since a lot of features added and this backup feature is a bit unmaintained, it cannot generate or restore a complete backup.", backupOutdatedWarning: "Deprecated: Since a lot of features added and this backup feature is a bit unmaintained, it cannot generate or restore a complete backup.",
backupRecommend: "Please backup the volume or the data folder (./data/) directly instead.", backupRecommend: "Please backup the volume or the data folder (./data/) directly instead.",
"Optional": "Optional", Optional: "Optional",
squadcast: "Squadcast", squadcast: "Squadcast",
SendKey: "SendKey", SendKey: "SendKey",
"SMSManager API Docs": "SMSManager API Docs ", "SMSManager API Docs": "SMSManager API Docs ",
"Gateway Type": "Gateway Type", "Gateway Type": "Gateway Type",
SMSManager: "SMSManager", SMSManager: "SMSManager",
"You can divide numbers with": "You can divide numbers with", "You can divide numbers with": "You can divide numbers with",
"or": "or", or: "or",
recurringInterval: "Interval", recurringInterval: "Interval",
"Recurring": "Recurring", Recurring: "Recurring",
strategyManual: "Active/Inactive Manually", strategyManual: "Active/Inactive Manually",
warningTimezone: "It is using the server's timezone", warningTimezone: "It is using the server's timezone",
weekdayShortMon: "Mon", weekdayShortMon: "Mon",
@@ -646,4 +646,27 @@ export default {
"Server Timezone": "Server Timezone", "Server Timezone": "Server Timezone",
statusPageMaintenanceEndDate: "End", statusPageMaintenanceEndDate: "End",
IconUrl: "Icon URL", IconUrl: "Icon URL",
"Enable DNS Cache": "Enable DNS Cache",
Enable: "Enable",
Disable: "Disable",
dnsCacheDescription: "It may be not working in some IPv6 environments, disable it if you encounter any issues.",
"Single Maintenance Window": "Single Maintenance Window",
"Maintenance Time Window of a Day": "Maintenance Time Window of a Day",
"Effective Date Range": "Effective Date Range",
"Schedule Maintenance": "Schedule Maintenance",
"Date and Time": "Date and Time",
"DateTime Range": "DateTime Range",
Strategy: "Strategy",
"Free Mobile User Identifier": "Free Mobile User Identifier",
"Free Mobile API Key": "Free Mobile API Key",
"Enable TLS": "Enable TLS",
"Proto Service Name": "Proto Service Name",
"Proto Method": "Proto Method",
"Proto Content": "Proto Content",
Economy: "Economy",
Lowcost: "Lowcost",
high: "high",
"General Monitor Type": "General Monitor Type",
"Passive Monitor Type": "Passive Monitor Type",
"Specific Monitor Type": "Specific Monitor Type",
}; };

View File

@@ -186,7 +186,7 @@ export default {
startOrEndWithOnly: "Commence uniquement par {0}", startOrEndWithOnly: "Commence uniquement par {0}",
"No consecutive dashes": "Pas de double tirets", "No consecutive dashes": "Pas de double tirets",
Next: "Continuer", Next: "Continuer",
"Setup Proxy": "Configuer Proxy", "Setup Proxy": "Configurer Proxy",
defaultNotificationName: "Ma notification {notification} numéro ({number})", defaultNotificationName: "Ma notification {notification} numéro ({number})",
here: "ici", here: "ici",
Required: "Requis", Required: "Requis",
@@ -334,10 +334,10 @@ export default {
Security: "Sécurité", Security: "Sécurité",
"Steam API Key": "Clé API Steam", "Steam API Key": "Clé API Steam",
"Shrink Database": "Réduire la base de données", "Shrink Database": "Réduire la base de données",
"Pick a RR-Type...": "Pick a RR-Type...", "Pick a RR-Type...": "Choisissez un type d'enregistrement...",
"Pick Accepted Status Codes...": "Pick Accepted Status Codes...", "Pick Accepted Status Codes...": "Choisissez les codes de statut acceptés...",
Default: "Défaut", Default: "Défaut",
"HTTP Options": "HTTP Options", "HTTP Options": "Options HTTP ",
"Create Incident": "Créer un incident", "Create Incident": "Créer un incident",
Title: "Titre", Title: "Titre",
Content: "Contenu", Content: "Contenu",
@@ -503,7 +503,7 @@ export default {
RadiusCallingStationIdDescription: "Identifiant de l'appareil appelant", RadiusCallingStationIdDescription: "Identifiant de l'appareil appelant",
"Certificate Expiry Notification": "Notification d'expiration du certificat", "Certificate Expiry Notification": "Notification d'expiration du certificat",
"API Username": "Nom d'utilisateur de l'API", "API Username": "Nom d'utilisateur de l'API",
"API Key": "clé API", "API Key": "Clé API",
"Recipient Number": "Numéro du destinataire", "Recipient Number": "Numéro du destinataire",
"From Name/Number": "De Nom/Numéro", "From Name/Number": "De Nom/Numéro",
"Leave blank to use a shared sender number.": "Laisser vide pour utiliser un numéro d'expéditeur partagé.", "Leave blank to use a shared sender number.": "Laisser vide pour utiliser un numéro d'expéditeur partagé.",
@@ -570,6 +570,7 @@ export default {
lastDay3: "3ème dernier jour du mois", lastDay3: "3ème dernier jour du mois",
lastDay4: "4ème dernier jour du mois", lastDay4: "4ème dernier jour du mois",
"No Maintenance": "Aucune Maintenance", "No Maintenance": "Aucune Maintenance",
"Schedule Maintenance": "Crée une Maintenance",
pauseMaintenanceMsg: "Voulez-vous vraiment mettre en pause ?", pauseMaintenanceMsg: "Voulez-vous vraiment mettre en pause ?",
"maintenanceStatus-under-maintenance": "En maintenance", "maintenanceStatus-under-maintenance": "En maintenance",
"maintenanceStatus-inactive": "Inactif", "maintenanceStatus-inactive": "Inactif",
@@ -584,4 +585,36 @@ export default {
statusPageMaintenanceEndDate: "Fin", statusPageMaintenanceEndDate: "Fin",
"Free Mobile User Identifier": "Identifiant d'utilisateur Free Mobile", "Free Mobile User Identifier": "Identifiant d'utilisateur Free Mobile",
"Free Mobile API Key": "Clé API Free Mobile", "Free Mobile API Key": "Clé API Free Mobile",
enableGRPCTls: "Autoriser l'envoi d'une requête gRPC avec une connexion TLS",
grpcMethodDescription: "Le nom de la méthode est converti au format cammelCase tel que sayHello, check, etc.",
smseagleTo: "Numéro(s) de téléphone",
smseagleGroup: "Nom(s) de groupe(s) de répertoire",
smseagleContact: "Nom(s) de contact du répertoire",
smseagleRecipientType: "Type de destinataire",
smseagleRecipient: "Destinataire(s) (les multiples doivent être séparés par une virgule)",
smseagleToken: "Jeton d'accès à l'API",
smseagleUrl: "L'URL de votre appareil SMSEagle",
smseagleEncoding: "Envoyer en Unicode",
smseaglePriority: "Priorité des messages (0-9, par défaut = 0)",
"Proxy Server": "Serveur proxy",
promosmsLogin: "Nom de connexion API",
promosmsPassword: "Mot de passe API",
"SMSManager API Docs": "Documentations d'API SMSManager ",
"Gateway Type": "Type de passerelle",
webhookAdditionalHeadersTitle: "En-têtes supplémentaires",
webhookAdditionalHeadersDesc: "Définit des en-têtes supplémentaires envoyés avec le webhook.",
"Enable TLS": "Activer le TLS",
"Proto Service Name": "Nom du service proto",
"Proto Method": "Méthode Proto",
"Proto Content": "Contenu proto",
"Enable DNS Cache": "Activer le cache DNS",
dnsCacheDescription: "Il peut ne pas fonctionner dans certains environnements IPv6, désactivez-le si vous rencontrez des problèmes.",
Enable: "Activer",
Disable: "Désactiver",
"Economy": "économique",
"Lowcost": "Faible coût",
"high": "Haute",
"General Monitor Type": "Type de moniteur général",
"Passive Monitor Type": "Type de moniteur passif",
"Specific Monitor Type": "Type de moniteur spécifique",
}; };

View File

@@ -5,7 +5,7 @@ export default {
retriesDescription: "จำนวนครั้งสูงสุดที่จะลองก่อนบริการถูกระบุว่าไม่สามารถใช้งานได้และส่งการแจ้งเตือน", retriesDescription: "จำนวนครั้งสูงสุดที่จะลองก่อนบริการถูกระบุว่าไม่สามารถใช้งานได้และส่งการแจ้งเตือน",
ignoreTLSError: "ไม่สนใจข้อผิดพลาด TLS/SSL สำหรับเว็บไซต์ HTTPS", ignoreTLSError: "ไม่สนใจข้อผิดพลาด TLS/SSL สำหรับเว็บไซต์ HTTPS",
upsideDownModeDescription: "กลับด้านสถานะ เช่น ถ้าบริการสามารถใช้งานได้จะถูกเปลี่ยนเป็นใช้งานไม่ได้", upsideDownModeDescription: "กลับด้านสถานะ เช่น ถ้าบริการสามารถใช้งานได้จะถูกเปลี่ยนเป็นใช้งานไม่ได้",
maxRedirectDescription: "จำนวนครั้งสูงสุดที่จะเปลี่ยนเส้นทาง, ตังเป็น 0 เพื่อปิดการเปลี่ยนเส้นทาง", maxRedirectDescription: "จำนวนครั้งสูงสุดที่จะเปลี่ยนเส้นทาง, ตังเป็น 0 เพื่อปิดการเปลี่ยนเส้นทาง",
acceptedStatusCodesDescription: "เลือกรหัสสถานะที่ถือว่าการตอบกลับสำเร็จ", acceptedStatusCodesDescription: "เลือกรหัสสถานะที่ถือว่าการตอบกลับสำเร็จ",
passwordNotMatchMsg: "รหัสผ่านไม่ตรงกัน", passwordNotMatchMsg: "รหัสผ่านไม่ตรงกัน",
notificationDescription: "การแจ้งเตือนต้องกำหนดให้มอนิเตอร์เพื่อให้สามารถใช้งานได้", notificationDescription: "การแจ้งเตือนต้องกำหนดให้มอนิเตอร์เพื่อให้สามารถใช้งานได้",
@@ -16,7 +16,7 @@ export default {
resolverserverDescription: "Cloudflare เป็นเซิร์ฟเวอร์ค้นหาเริ่มต้น, คุณสามารถเปลี่ยนเซิร์ฟเวอร์ได้ตลอดเวลา", resolverserverDescription: "Cloudflare เป็นเซิร์ฟเวอร์ค้นหาเริ่มต้น, คุณสามารถเปลี่ยนเซิร์ฟเวอร์ได้ตลอดเวลา",
rrtypeDescription: "เลือกประเภท DNS Record ที่คุณต้องการจะมอนิเตอร์", rrtypeDescription: "เลือกประเภท DNS Record ที่คุณต้องการจะมอนิเตอร์",
pauseMonitorMsg: "คุณแน่ใจหรือไม่ที่จะหยุดมอนิเตอร์ชั่วคราว?", pauseMonitorMsg: "คุณแน่ใจหรือไม่ที่จะหยุดมอนิเตอร์ชั่วคราว?",
enableDefaultNotificationDescription: "การแจ้งเตือนนี้จะถูกเปิดโดค่าเริ่มต้นสำหรับมอนิเตอร์ใหม่, คุณสามารถปิดการแจ้งเตือนสำหรับแต่ละมอนิเตอร์ได้", enableDefaultNotificationDescription: "การแจ้งเตือนนี้จะถูกเปิดโดค่าเริ่มต้นสำหรับมอนิเตอร์ใหม่, คุณสามารถปิดการแจ้งเตือนสำหรับแต่ละมอนิเตอร์ได้",
clearEventsMsg: "คุณแน่ใจหรือไม่ที่จะลบเหตุการณ์ทั้งหมดสำหรับมอนิเตอร์นี้?", clearEventsMsg: "คุณแน่ใจหรือไม่ที่จะลบเหตุการณ์ทั้งหมดสำหรับมอนิเตอร์นี้?",
clearHeartbeatsMsg: "คุณแน่ใจหรือไม่ที่จะลบประวัติการตรวจสอบทั้งหมดสำหรับมอนิเตอร์นี้?", clearHeartbeatsMsg: "คุณแน่ใจหรือไม่ที่จะลบประวัติการตรวจสอบทั้งหมดสำหรับมอนิเตอร์นี้?",
confirmClearStatisticsMsg: "คุณแน่ใจหรือไม่ที่จะลบสถิติทั้งหมด?", confirmClearStatisticsMsg: "คุณแน่ใจหรือไม่ที่จะลบสถิติทั้งหมด?",
@@ -49,12 +49,12 @@ export default {
Status: "สถานะ", Status: "สถานะ",
DateTime: "วันที่และเวลา", DateTime: "วันที่และเวลา",
Message: "ข้อความ", Message: "ข้อความ",
"No important events": "ไม่มีกิจกรรมที่สำคัญ", "No important events": "ไม่มีเหตการณ์ที่สำคัญ",
Resume: "ดำเนินการต่อ", Resume: "ดำเนินการต่อ",
Edit: "แก้ไข", Edit: "แก้ไข",
Delete: "ลบ", Delete: "ลบ",
Current: "ปัจจุบัน", Current: "ปัจจุบัน",
Uptime: "เวลาที่ใช้งาน", Uptime: "เวลาที่ใช้งานได้",
"Cert Exp.": "วันหมดอายุใบรับรอง", "Cert Exp.": "วันหมดอายุใบรับรอง",
days: "วัน", days: "วัน",
day: "วัน", day: "วัน",
@@ -69,7 +69,7 @@ export default {
URL: "URL", URL: "URL",
Hostname: "ชื่อโฮสต์", Hostname: "ชื่อโฮสต์",
Port: "พอร์ต", Port: "พอร์ต",
"Heartbeat Interval": "ระยะห่างระหว่างการทดสอบ", "Heartbeat Interval": "ระยะเวลาระหว่างการทดสอบ",
Retries: "จำนวนครั้งที่จะลองใหม่", Retries: "จำนวนครั้งที่จะลองใหม่",
"Heartbeat Retry Interval": "ระยะห่างระหว่างการทดสอบใหม่หลังจากไม่สำเร็จ", "Heartbeat Retry Interval": "ระยะห่างระหว่างการทดสอบใหม่หลังจากไม่สำเร็จ",
Advanced: "ขั้นสูง", Advanced: "ขั้นสูง",
@@ -112,7 +112,7 @@ export default {
No: "ไม่", No: "ไม่",
Username: "ชื่อผู้ใช้", Username: "ชื่อผู้ใช้",
Password: "รหัสผ่าน", Password: "รหัสผ่าน",
"Remember me": "คงอยู่ในระบบ", "Remember me": "จดจำฉันไว้",
Login: "เข้าสู่ระบบ", Login: "เข้าสู่ระบบ",
"No Monitors, please": "ไม่มีมอนิเตอร์, กรุณา", "No Monitors, please": "ไม่มีมอนิเตอร์, กรุณา",
"add one": "สร้าง", "add one": "สร้าง",
@@ -120,7 +120,7 @@ export default {
Email: "อีเมล", Email: "อีเมล",
Test: "ทดสอบ", Test: "ทดสอบ",
"Certificate Info": "ข้อมูลใบรับรอง", "Certificate Info": "ข้อมูลใบรับรอง",
"Resolver Server": "เซิร์ฟเวอร์ทีค้นหา", "Resolver Server": "เซิร์ฟเวอร์ทีค้นหา",
"Resource Record Type": "ประเภท DNS Record", "Resource Record Type": "ประเภท DNS Record",
"Last Result": "ผลล่าสุด", "Last Result": "ผลล่าสุด",
"Create your admin account": "สร้างบัญชีผู้ดูแลระบบ", "Create your admin account": "สร้างบัญชีผู้ดูแลระบบ",
@@ -138,8 +138,8 @@ export default {
Events: "เหตุการณ์", Events: "เหตุการณ์",
Heartbeats: "ประวัติการตรวจสอบ", Heartbeats: "ประวัติการตรวจสอบ",
"Auto Get": "ดึงอัตโนมัติ", "Auto Get": "ดึงอัตโนมัติ",
backupDescription: "คุณสามารถสำรองข้อมูลการแจ้งเตือนและมอนิเตอร์ทั้งหมดได้ในไฟล์ JSON", backupDescription: "คุณสามารถสำรองข้อมูลการแจ้งเตือนและมอนิเตอร์ทั้งหมดไว้ได้ในไฟล์ JSON",
backupDescription2: "หมายเหตุ : ประวัติและข้อมูลกิจกรรมจะไม่ถูกสำรอง", backupDescription2: "หมายเหตุ : ประวัติและข้อมูลเหตการณ์จะไม่ถูกสำรอง",
backupDescription3: "ข้อมูลที่ละเอียดอ่อนเช่นกุญแจการแจ้งเตือนจะรวมอยู่ในไฟล์ข้อมูลสำรอง, โปรดเก็บข้อมูลสำรองอย่างปลอดภัย", backupDescription3: "ข้อมูลที่ละเอียดอ่อนเช่นกุญแจการแจ้งเตือนจะรวมอยู่ในไฟล์ข้อมูลสำรอง, โปรดเก็บข้อมูลสำรองอย่างปลอดภัย",
alertNoFile: "กรุณาเลือกไฟล์ที่จะใช้งาน", alertNoFile: "กรุณาเลือกไฟล์ที่จะใช้งาน",
alertWrongFileType: "กรุณาเลือกไฟล์ที่เป็น JSON", alertWrongFileType: "กรุณาเลือกไฟล์ที่เป็น JSON",
@@ -153,7 +153,7 @@ export default {
"Enable 2FA": "เปิดใช้งาน 2FA", "Enable 2FA": "เปิดใช้งาน 2FA",
"Disable 2FA": "ปิดใช้งาน 2FA", "Disable 2FA": "ปิดใช้งาน 2FA",
"2FA Settings": "ตั้งค่า 2FA", "2FA Settings": "ตั้งค่า 2FA",
"Two Factor Authentication": "การตรวจสอบสิทธิ์สองปัจจัย", "Two Factor Authentication": "การยืนยันตัวตนแบบสองขั้นตอน",
Active: "ใช้งาน", Active: "ใช้งาน",
Inactive: "ไม่ใช้งาน", Inactive: "ไม่ใช้งาน",
Token: "กุญแจ", Token: "กุญแจ",
@@ -189,7 +189,7 @@ export default {
"Status Pages": "หน้าสถานะ", "Status Pages": "หน้าสถานะ",
defaultNotificationName: "การแจ้งเตือน {notification} ของฉัน ({number})", defaultNotificationName: "การแจ้งเตือน {notification} ของฉัน ({number})",
here: "ที่นี่", here: "ที่นี่",
Required: "ต้องการ", Required: "จำเป็น",
telegram: "Telegram", telegram: "Telegram",
"Bot Token": "กุญแจของบอท", "Bot Token": "กุญแจของบอท",
wayToGetTelegramToken: "คุณสามารถรับกุญแจได้จาก {0}.", wayToGetTelegramToken: "คุณสามารถรับกุญแจได้จาก {0}.",
@@ -202,7 +202,7 @@ export default {
"Post URL": "URL โพสต์", "Post URL": "URL โพสต์",
"Content Type": "ประเภทเนื้อหา", "Content Type": "ประเภทเนื้อหา",
webhookJsonDesc: "{0} ดีสำหรับเซิร์ฟเวอร์ HTTP สมัยใหม่เช่น Express.js", webhookJsonDesc: "{0} ดีสำหรับเซิร์ฟเวอร์ HTTP สมัยใหม่เช่น Express.js",
webhookFormDataDesc: "{multipart} ดีสำหรับ PHP, JSON จะต้องถูกประมวลผลด้วย {decodeFunction}", webhookFormDataDesc: "{multipart} ดีสำหรับ PHP, ข้อมูล JSON จะต้องถูกประมวลผลด้วย {decodeFunction}",
smtp: "Email (SMTP)", smtp: "Email (SMTP)",
secureOptionNone: "None / STARTTLS (25, 587)", secureOptionNone: "None / STARTTLS (25, 587)",
secureOptionTLS: "TLS (465)", secureOptionTLS: "TLS (465)",
@@ -224,7 +224,7 @@ export default {
signal: "Signal", signal: "Signal",
Number: "หมายเลข", Number: "หมายเลข",
Recipients: "ผู้รับ", Recipients: "ผู้รับ",
needSignalAPI: "คุณต้องมี Signal Client ที่มี Rest APIl", needSignalAPI: "คุณต้องมี Signal Client ที่มี Rest API",
wayToCheckSignalURL: "คุณสามารถตรวจสอบ URL นี้เพื่อดูวิธีตั้งค่า :", wayToCheckSignalURL: "คุณสามารถตรวจสอบ URL นี้เพื่อดูวิธีตั้งค่า :",
signalImportant: "สำคัญ: คุณไม่สามารถผสมกลุ่มและตัวเลขในผู้รับได้!", signalImportant: "สำคัญ: คุณไม่สามารถผสมกลุ่มและตัวเลขในผู้รับได้!",
gotify: "Gotify", gotify: "Gotify",
@@ -236,7 +236,7 @@ export default {
"Channel Name": "ชื่อห้อง", "Channel Name": "ชื่อห้อง",
"Uptime Kuma URL": "Uptime Kuma URL", "Uptime Kuma URL": "Uptime Kuma URL",
aboutWebhooks: "ข้อมูลเพิ่มเติมสำหรับ Webhooks : {0}", aboutWebhooks: "ข้อมูลเพิ่มเติมสำหรับ Webhooks : {0}",
aboutChannelName: "ใส่ชื่อห้องน {0} ในช่องชื่อห้องถ้าต้องการที่จะข้าม Webhook, เช่น: #ช่องอื่นๆ", aboutChannelName: "ใส่ชื่อห้องน {0} ในช่องชื่อห้องถ้าต้องการที่จะข้าม Webhook, เช่น: #ช่องอื่นๆ",
aboutKumaURL: "ถ้าคุณไม่ใส่ข้อมูลในช่อง Uptime Kuma URL ค่าเริ่มต้นจะเป็นจะเป็น Uptime Kuma Github", aboutKumaURL: "ถ้าคุณไม่ใส่ข้อมูลในช่อง Uptime Kuma URL ค่าเริ่มต้นจะเป็นจะเป็น Uptime Kuma Github",
emojiCheatSheet: "ตาราง Emoji : {0}", emojiCheatSheet: "ตาราง Emoji : {0}",
"rocket.chat": "Rocket.Chat", "rocket.chat": "Rocket.Chat",
@@ -248,7 +248,7 @@ export default {
clicksendsms: "ClickSend SMS", clicksendsms: "ClickSend SMS",
lunasea: "LunaSea", lunasea: "LunaSea",
apprise: "Apprise (รองรับการแจ้งเตือนมากกว่า 50 บริการ)", apprise: "Apprise (รองรับการแจ้งเตือนมากกว่า 50 บริการ)",
GoogleChat: "Google Chat (Google Workspace only)", GoogleChat: "Google Chat (สำหรับ Google Workspace เท่านั้น)",
pushbullet: "Pushbullet", pushbullet: "Pushbullet",
line: "Line Messenger", line: "Line Messenger",
mattermost: "Mattermost", mattermost: "Mattermost",
@@ -257,8 +257,8 @@ export default {
"Message Title": "หัวข้อข้อความ", "Message Title": "หัวข้อข้อความ",
"Notification Sound": "เสียงแจ้งเตือน", "Notification Sound": "เสียงแจ้งเตือน",
"More info on:": "ข้อมูลเพิ่มเติม : {0}", "More info on:": "ข้อมูลเพิ่มเติม : {0}",
pushoverDesc1: "ลำดับความสำคญฉุกเฉิน (2) มีการหมดเวลาเริ่มต้น 30 วินาทีระหว่างลองใหม่และจะหมดอายุหลังจาก 1 ชั่วโมง", pushoverDesc1: "ลำดับความสำคญฉุกเฉิน (2) มีการหมดเวลาเริ่มต้น 30 วินาทีระหว่างการลองใหม่และจะหมดอายุหลังจาก 1 ชั่วโมง",
pushoverDesc2: "ถ้าคุณต้องการจะส่งการแจ้งเตือนไปยังอุปกรณ์อื่น ๆ สามารถกำหนดได้ที่ช่องอุปกรณ์", pushoverDesc2: "ถ้าคุณต้องการจะส่งการแจ้งเตือนไปยังอุปกรณ์อื่นๆ สามารถกำหนดได้ที่ช่องอุปกรณ์",
"SMS Type": "ประเภท SMS", "SMS Type": "ประเภท SMS",
octopushTypePremium: "พรีเมี่ยม (เร็ว - แนะนำสำหรับการแจ้งเตือน)", octopushTypePremium: "พรีเมี่ยม (เร็ว - แนะนำสำหรับการแจ้งเตือน)",
octopushTypeLowCost: "ต้นทุนต่ำ (ช้า - บางครั้งจะถูกบล็อกโดยผู้ให้บริการ)", octopushTypeLowCost: "ต้นทุนต่ำ (ช้า - บางครั้งจะถูกบล็อกโดยผู้ให้บริการ)",
@@ -274,8 +274,8 @@ export default {
"Read more:": "อ่านเพิ่มเติม : {0}", "Read more:": "อ่านเพิ่มเติม : {0}",
"Status:": "สถานะ : {0}", "Status:": "สถานะ : {0}",
"Read more": "อ่านเพิ่มเติม", "Read more": "อ่านเพิ่มเติม",
appriseInstalled: "Apprise ถูกติดตังแล้ว", appriseInstalled: "Apprise ถูกติดตังแล้ว",
appriseNotInstalled: "Apprise ยังไม่ถูกติดตัง {0}", appriseNotInstalled: "Apprise ยังไม่ถูกติดตัง {0}",
"Access Token": "กุญแจการเข้าถึง", "Access Token": "กุญแจการเข้าถึง",
"Channel access token": "กุญแจการเข้าถึงของช่อง", "Channel access token": "กุญแจการเข้าถึงของช่อง",
"Line Developers Console": "Line Developers Console", "Line Developers Console": "Line Developers Console",
@@ -285,11 +285,11 @@ export default {
"Messaging API": "Messaging API", "Messaging API": "Messaging API",
wayToGetLineChannelToken: "ขั้นแรกให้เข้า {0} สร้างผู้ให้บริการและช่องทาง (Messaging API) จากนั้นคุณจะได้รับกุญแจการเข้าถึงช่องและไอดีผู้ใช้จากรายการเมนูที่กล่าวถึงข้างต้น", wayToGetLineChannelToken: "ขั้นแรกให้เข้า {0} สร้างผู้ให้บริการและช่องทาง (Messaging API) จากนั้นคุณจะได้รับกุญแจการเข้าถึงช่องและไอดีผู้ใช้จากรายการเมนูที่กล่าวถึงข้างต้น",
"Icon URL": "Icon URL", "Icon URL": "Icon URL",
aboutIconURL: "คุณสามารถระบุลิงก์ไปยังรูปภาพใน \"URL ไอคอน\" เพื่อแทนที่รูปภาพโปรไฟล์เริ่มต้น จะไม่ถูกใช้หากมีการตั้งค่า Icon Emoji", aboutIconURL: "คุณสามารถระบุลิงก์รูปภาพใน \"URL ไอคอน\" เพื่อแทนที่รูปภาพโปรไฟล์เริ่มต้น จะไม่ถูกใช้หากมีการตั้งค่า Icon Emoji",
aboutMattermostChannelName: "คุณลบล้างช่องเริ่มต้นที่ Webhook โพสต์ได้ด้วยการป้อนชื่อช่องลงในช่อง \"ชื่อช่อง\" ต้องเปิดใช้งานในการตั้งค่า Mattermost Webhook เช่น #ช่องอื่นๆ", aboutMattermostChannelName: "คุณลบช่องเริ่มต้นที่ Webhook โพสต์ได้ด้วยการป้อนชื่อช่องลงในช่อง \"ชื่อช่อง\" ต้องเปิดใช้งานในการตั้งค่า Mattermost Webhook เช่น #ช่องอื่นๆ",
matrix: "Matrix", matrix: "Matrix",
promosmsTypeEco: "SMS ECO - ราคาถูก แต่ช้าและมักจะโอเวอร์โหลด จำกัดเฉพาะผู้รับโปแลนด์", promosmsTypeEco: "SMS ECO - ราคาถูก แต่ช้าและมักจะโอเวอร์โหลด จำกัดเฉพาะผู้รับในโปแลนด์",
promosmsTypeFlash: "SMS FLASH - ข้อความจะแสดงบนอุปกรณ์ของผู้รับโดยอัตโนมัติ จำกัดเฉพาะผู้รับโปแลนด์", promosmsTypeFlash: "SMS FLASH - ข้อความจะแสดงบนอุปกรณ์ของผู้รับโดยอัตโนมัติ จำกัดเฉพาะผู้รับในโปแลนด์",
promosmsTypeFull: "SMS FULL - SMS ระดับพรีเมียม คุณสามารถใช้ชื่อผู้ส่งของคุณได้ (คุณต้องลงทะเบียนชื่อก่อน) เชื่อถือได้สำหรับการแจ้งเตือน", promosmsTypeFull: "SMS FULL - SMS ระดับพรีเมียม คุณสามารถใช้ชื่อผู้ส่งของคุณได้ (คุณต้องลงทะเบียนชื่อก่อน) เชื่อถือได้สำหรับการแจ้งเตือน",
promosmsTypeSpeed: "SMS SPEED - ลำดับความสำคัญสูงสุดในระบบ รวดเร็วและเชื่อถือได้ แต่มีค่าใช้จ่ายสูง (ประมาณสองเท่าของราคาเต็ม SMS)", promosmsTypeSpeed: "SMS SPEED - ลำดับความสำคัญสูงสุดในระบบ รวดเร็วและเชื่อถือได้ แต่มีค่าใช้จ่ายสูง (ประมาณสองเท่าของราคาเต็ม SMS)",
promosmsPhoneNumber: "หมายเลขโทรศัพท์ (สำหรับผู้รับโปแลนด์ คุณสามารถข้ามรหัสพื้นที่ได้)", promosmsPhoneNumber: "หมายเลขโทรศัพท์ (สำหรับผู้รับโปแลนด์ คุณสามารถข้ามรหัสพื้นที่ได้)",
@@ -298,7 +298,7 @@ export default {
matrixHomeserverURL: "URL ของโฮมเซิร์ฟเวอร์ (พร้อม http(s):// และพอร์ตเสริม)", matrixHomeserverURL: "URL ของโฮมเซิร์ฟเวอร์ (พร้อม http(s):// และพอร์ตเสริม)",
"Internal Room Id": "รหัสห้องภายใน", "Internal Room Id": "รหัสห้องภายใน",
matrixDesc1: "คุณค้นหารหัสห้องภายในได้โดยดูในส่วนขั้นสูงของการตั้งค่าห้องในไคลเอ็นต์ Matrix มันควรจะมีลักษณะเช่น !PMdRCpsIfLwsfjIye6:kiznick.server.", matrixDesc1: "คุณค้นหารหัสห้องภายในได้โดยดูในส่วนขั้นสูงของการตั้งค่าห้องในไคลเอ็นต์ Matrix มันควรจะมีลักษณะเช่น !PMdRCpsIfLwsfjIye6:kiznick.server.",
matrixDesc2: "ขอแนะนำเป็นอย่างยิ่งให้คุณสร้างผู้ใช้ใหม่และอย่าใช้โทเค็นการเข้าถึงของผู้ใช้ Matrix ของคุณเอง เนื่องจากจะทำให้สามารถเข้าถึงบัญชีของคุณและห้องทั้งหมดที่คุณเข้าร่วมได้อย่างเต็มที่ ให้สร้างผู้ใช้ใหม่และเชิญเฉพาะห้องที่คุณต้องการรับการแจ้งเตือนแทน คุณสามารถรับโทเค็นเพื่อการเข้าถึงได้โดยเรียกใช้ {0}", matrixDesc2: "ขอแนะนำเป็นอย่างยิ่งให้คุณสร้างผู้ใช้ใหม่และอย่าใช้โทเค็นการเข้าถึงของผู้ใช้ Matrix ของคุณเอง เนื่องจากจะทำให้สามารถเข้าถึงบัญชีของคุณและห้องทั้งหมดที่คุณเข้าร่วม ให้สร้างผู้ใช้ใหม่และเชิญเฉพาะห้องที่คุณต้องการรับการแจ้งเตือนแทน คุณสามารถรับโทเค็นเพื่อการเข้าถึงได้โดยเรียกใช้ {0}",
Method: "วิธี", Method: "วิธี",
Body: "เนื้อหา", Body: "เนื้อหา",
Headers: "ส่วนหัว", Headers: "ส่วนหัว",
@@ -310,12 +310,12 @@ export default {
PasswordsDoNotMatch: "รหัสผ่านไม่ตรงกัน", PasswordsDoNotMatch: "รหัสผ่านไม่ตรงกัน",
records: "บันทึก", records: "บันทึก",
"One record": "หนึ่งบันทึก", "One record": "หนึ่งบันทึก",
steamApiKeyDescription: "สำหรับการมอนิเตอร์ Steam Game Server คุณต้องมี Steam Web-API key, คุณสามารถสมัครได้จากที่นี่ : ", steamApiKeyDescription: "สำหรับการมอนิเตอร์ Steam Game Server คุณต้องมี Steam Web-API key, คุณสามารถสมัครได้จากที่นี่ : ",
"Current User": "ผู้ใช้ปัจจุบัน", "Current User": "ผู้ใช้ปัจจุบัน",
topic: "หัวข้อ", topic: "หัวข้อ",
topicExplanation: "MQTT หัวข้อที่จะมอนิเตอร์", topicExplanation: "หัวข้อ MQTT ที่จะมอนิเตอร์",
successMessage: "ข้อความที่จะถือว่าประสบความสำเร็จ", successMessage: "ข้อความที่จะถือว่าประสบความสำเร็จ",
successMessageExplanation: "MQTT ข้อความที่จะถือว่าประสบความสำเร็จ", successMessageExplanation: "ข้อความ MQTT ที่จะถือว่าประสบความสำเร็จ",
recent: "ล่าสุด", recent: "ล่าสุด",
Done: "สำเร็จ", Done: "สำเร็จ",
Info: "ข้อมูล", Info: "ข้อมูล",
@@ -354,7 +354,7 @@ export default {
Discard: "ทิ้ง", Discard: "ทิ้ง",
Cancel: "ยกเลิก", Cancel: "ยกเลิก",
"Powered by": "ขับเคลื่อนโดย", "Powered by": "ขับเคลื่อนโดย",
shrinkDatabaseDescription: "ทริกเกอร์ฐานข้อมูล VACUUM สำหรับ SQLite หากฐานข้อมูลของคุณถูกสร้างขึ้นหลังจาก 1.10.0 แสดงว่า AUTO_VACUUM เปิดใช้งานอยู่แล้วและไม่จำเป็นต้องดำเนินการนี้", shrinkDatabaseDescription: "ทริกเกอร์ฐานข้อมูล VACUUM สำหรับ SQLite หากฐานข้อมูลของคุณถูกสร้างขึ้นหลังจากเวอร์ชั่น 1.10.0 แสดงว่า AUTO_VACUUM เปิดใช้งานอยู่แล้วและไม่จำเป็นต้องดำเนินการนี้",
serwersms: "SerwerSMS.pl", serwersms: "SerwerSMS.pl",
serwersmsAPIUser: "API Username (incl. webapi_ prefix)", serwersmsAPIUser: "API Username (incl. webapi_ prefix)",
serwersmsAPIPassword: "API Password", serwersmsAPIPassword: "API Password",
@@ -364,14 +364,14 @@ export default {
Customize: "ปรับแต่ง", Customize: "ปรับแต่ง",
"Custom Footer": "ส่วนท้ายที่กำหนดเอง", "Custom Footer": "ส่วนท้ายที่กำหนดเอง",
"Custom CSS": "CSS ที่กำหนดเอง", "Custom CSS": "CSS ที่กำหนดเอง",
smtpDkimSettings: "ตั้งค่า DKIM", smtpDkimSettings: "การตั้งค่า DKIM",
smtpDkimDesc: "โปรดดู Nodemailer DKIM {0} สำหรับการใช้งาน", smtpDkimDesc: "โปรดดู Nodemailer DKIM {0} สำหรับการใช้งาน",
documentation: "อการ", documentation: "คู่มือการใช้งาน",
smtpDkimDomain: "ชื่อโดเมน", smtpDkimDomain: "ชื่อโดเมน",
smtpDkimKeySelector: "Key Selector", smtpDkimKeySelector: "Key Selector",
smtpDkimPrivateKey: "Private Key", smtpDkimPrivateKey: "Private Key",
smtpDkimHashAlgo: "อัลกอริทึมแฮช (ไม่บังคับ)", smtpDkimHashAlgo: "อัลกอริทึมแฮช (ไม่บังคับ)",
smtpDkimheaderFieldNames: "คีย์ส่วนหัวเพื่อลงชื่อ (ไม่บังคับ)", smtpDkimheaderFieldNames: "คีย์ส่วนหัวสำหรับลงชื่อ (ไม่บังคับ)",
smtpDkimskipFields: "Header Keys ไม่ต้องเซ็น (ไม่บังคับ)", smtpDkimskipFields: "Header Keys ไม่ต้องเซ็น (ไม่บังคับ)",
gorush: "Gorush", gorush: "Gorush",
alerta: "Alerta", alerta: "Alerta",
@@ -383,11 +383,11 @@ export default {
deleteStatusPageMsg: "คุณแน่ใจหรือไม่ว่าต้องการลบหน้าสถานะนี้", deleteStatusPageMsg: "คุณแน่ใจหรือไม่ว่าต้องการลบหน้าสถานะนี้",
Proxies: "พร็อกซี", Proxies: "พร็อกซี",
default: "ค่าเริ่มต้น", default: "ค่าเริ่มต้น",
enabled: "เปิดใช้งาน", enabled: "เปิดใช้งานแล้ว",
setAsDefault: "ตังเป็นค่าเริ่มต้น", setAsDefault: "ตังเป็นค่าเริ่มต้น",
deleteProxyMsg: "คุณแน่ใจหรือไม่ว่าต้องการลบพร็อกซีสำหรับมอนิเตอร์ทั้งหมด?", deleteProxyMsg: "คุณแน่ใจหรือไม่ว่าต้องการลบพร็อกซีสำหรับมอนิเตอร์ทั้งหมด?",
proxyDescription: "พร็อกซีจะต้องตั้งค่าให้มอนิเตอร์เพื่อให้ใช้งานได้", proxyDescription: "ต้องตั้งค่ามอนิเตอร์ให้ใช้พร็อกซีเพื่อให้ใช้งานได้",
enableProxyDescription: "พร็อกซีนี้จะไม่ส่งผลต่อมอนิเตอร์จนกว่าจะเปิดใช้งาน คุณสามารถควบคุมการปิดใช้งานพร็อกซีชั่วคราวจากมอนิเตอร์ทั้งหมดได้โดยสถานะการเปิดใช้งาน", enableProxyDescription: "พร็อกซีนี้จะไม่ส่งผลต่อมอนิเตอร์จนกว่าจะเปิดใช้งาน คุณสามารถควบคุมการปิดใช้งานพร็อกซีชั่วคราวจากมอนิเตอร์ทั้งหมดได้ที่ส่วนสถานะการเปิดใช้งาน",
setAsDefaultProxyDescription: "พร็อกซีนี้จะถูกเปิดโดนค่าเริ่มต้นสำหรับมอนิเตอร์ใหม่, คุณสามารถปิดการแจ้งเตือนสำหรับแต่ละมอนิเตอร์ได้", setAsDefaultProxyDescription: "พร็อกซีนี้จะถูกเปิดโดนค่าเริ่มต้นสำหรับมอนิเตอร์ใหม่, คุณสามารถปิดการแจ้งเตือนสำหรับแต่ละมอนิเตอร์ได้",
"Certificate Chain": "ห่วงโซ่ใบรับรอง", "Certificate Chain": "ห่วงโซ่ใบรับรอง",
Valid: "ถูกต้อง", Valid: "ถูกต้อง",
@@ -413,7 +413,7 @@ export default {
"WeCom Bot Key": "WeCom Bot Key", "WeCom Bot Key": "WeCom Bot Key",
"Setup Proxy": "ติดตั้งพร็อกซี่", "Setup Proxy": "ติดตั้งพร็อกซี่",
"Proxy Protocol": "โปรโตคอลพร็อกซี่", "Proxy Protocol": "โปรโตคอลพร็อกซี่",
"Proxy Server": "พร็อกซีเซิร์ฟ", "Proxy Server": "เซิร์ฟเวอร์พร็อกซี",
"Proxy server has authentication": "พร็อกซีเซิร์ฟเวอร์มีการตรวจสอบสิทธิ์", "Proxy server has authentication": "พร็อกซีเซิร์ฟเวอร์มีการตรวจสอบสิทธิ์",
User: "ผู้ใช้", User: "ผู้ใช้",
Installed: "ติดตั้งแล้ว", Installed: "ติดตั้งแล้ว",
@@ -430,29 +430,29 @@ export default {
startOrEndWithOnly: "เริ่มหรือจบด้วย {0} เท่านั้น", startOrEndWithOnly: "เริ่มหรือจบด้วย {0} เท่านั้น",
"No consecutive dashes": "ไม่มีขีดกลางติดต่อกัน", "No consecutive dashes": "ไม่มีขีดกลางติดต่อกัน",
Next: "ต่อไป", Next: "ต่อไป",
"The slug is already taken. Please choose another slug.": "ชื่อนี้ถูกใช้งานไปแล้ว กรุณาใช้ชื่ออื่น", "The slug is already taken. Please choose another slug.": "ชื่อนี้ถูกใช้งานแล้ว กรุณาใช้ชื่ออื่น",
"No Proxy": "ไม่มีพร็อกซี่", "No Proxy": "ไม่มีพร็อกซี่",
"HTTP Basic Auth": "HTTP Basic Auth", "HTTP Basic Auth": "HTTP Basic Auth",
"New Status Page": "หน้าสถานะใหม่", "New Status Page": "หน้าสถานะใหม่",
"Page Not Found": "ไม่พบหน้านี้", "Page Not Found": "ไม่พบหน้านี้",
"Reverse Proxy": "พร็อกซีย้อนกลับ", "Reverse Proxy": "พร็อกซีย้อนกลับ",
Backup: "สำรอง", Backup: "สำรองข้อมูล",
About: "เกี่ยวกับ", About: "เกี่ยวกับ",
wayToGetCloudflaredURL: "(ดาวโหลด cloudflared จาก {0})", wayToGetCloudflaredURL: "(ดาวโหลด cloudflared จาก {0})",
cloudflareWebsite: "เว็บไซต์ Cloudflare", cloudflareWebsite: "เว็บไซต์ Cloudflare",
"Message:": "ข้อความ :", "Message:": "ข้อความ :",
"Don't know how to get the token? Please read the guide:": "ไม่รู้วิธีการรับกุญแจ?, กรุณาอ่านคู่มือ", "Don't know how to get the token? Please read the guide:": "ไม่รู้วิธีการรับกุญแจ?, กรุณาอ่านคู่มือ",
"The current connection may be lost if you are currently connecting via Cloudflare Tunnel. Are you sure want to stop it? Type your current password to confirm it.": "การเชื่อมต่อปัจุบันอาจขาดหายหากคุณกำลังเชื่อมต่อ Cloudflare Tunnel คุณแน่ใจหรือไม่ที่จะหยุด, พิมรหัสผ่านของคุณเพื่อยืนยัน", "The current connection may be lost if you are currently connecting via Cloudflare Tunnel. Are you sure want to stop it? Type your current password to confirm it.": "การเชื่อมต่อปัจุบันอาจขาดหายหากคุณกำลังเชื่อมต่อ Cloudflare Tunnel คุณแน่ใจหรือไม่ที่จะหยุด, พิมรหัสผ่านของคุณเพื่อยืนยัน",
"Other Software": "ซอฟต์แวร์อื่น ๆ ", "Other Software": "ซอฟต์แวร์อื่นๆ ",
"For example: nginx, Apache and Traefik.": "เช่น: nginx, Apache และ Traefik", "For example: nginx, Apache and Traefik.": "เช่น: nginx, Apache และ Traefik",
"Please read": "กรุณาอ่าน", "Please read": "กรุณาอ่าน",
"Subject:": "เรื่อง :", "Subject:": "เรื่อง :",
"Valid To:": "ถูกต้องถึง :", "Valid To:": "ใช้ได้ถึง :",
"Days Remaining:": "จำนวนวันที่เหลือ :", "Days Remaining:": "จำนวนวันที่เหลือ :",
"Issuer:": "ผู้ออก :", "Issuer:": "ผู้ออก :",
"Fingerprint:": "ลายนิ้วมือ :", "Fingerprint:": "ลายนิ้วมือ :",
"No status pages": "ไม่มีหน้าสถานะ", "No status pages": "ไม่มีหน้าสถานะ",
"Domain Name Expiry Notification": "แจ้งเตือนการหมดอายุโดเมน", "Domain Name Expiry Notification": "แจ้งเตือนการหมดอายุของโดเมน",
Proxy: "Proxy", Proxy: "Proxy",
"Date Created": "วันที่สร้าง", "Date Created": "วันที่สร้าง",
onebotHttpAddress: "ที่อยู่ HTTP OneBot ", onebotHttpAddress: "ที่อยู่ HTTP OneBot ",
@@ -466,8 +466,8 @@ export default {
"Show Powered By": "แสดงข้อความ \"ขับเคลื่อนโดย\"", "Show Powered By": "แสดงข้อความ \"ขับเคลื่อนโดย\"",
"Domain Names": "Domain Names", "Domain Names": "Domain Names",
signedInDisp: "เข้าใช้งานในฐานะ {0}", signedInDisp: "เข้าใช้งานในฐานะ {0}",
signedInDispDisabled: "ปิดการตรวจสอบสิทธิ์", signedInDispDisabled: "ปิดการยืนยันตัวตน",
"Certificate Expiry Notification": "แจ้งเตือนการรับรองหมดอายุ", "Certificate Expiry Notification": "แจ้งเตือนใบรับรองหมดอายุ",
"API Username": "API Username", "API Username": "API Username",
"API Key": "API Key", "API Key": "API Key",
"Recipient Number": "หมายเลขผู้รับ", "Recipient Number": "หมายเลขผู้รับ",
@@ -476,8 +476,8 @@ export default {
"Octopush API Version": "Octopush API Version", "Octopush API Version": "Octopush API Version",
"Legacy Octopush-DM": "Legacy Octopush-DM", "Legacy Octopush-DM": "Legacy Octopush-DM",
endpoint: "endpoint", endpoint: "endpoint",
octopushAPIKey: "\"API key\" จากข้อมูลรับรอง HTTP API ในแผงควบคุม", octopushAPIKey: "\"API key\" จากข้อมูลยืนยันตัวตน HTTP API ในแผงควบคุม",
octopushLogin: "\"Login\" จากข้อมูลรับรอง HTTP API ในแผงควบคุม", octopushLogin: "\"Login\" จากข้อมูลยืนยันตัวตน HTTP API ในแผงควบคุม",
promosmsLogin: "API Login Name", promosmsLogin: "API Login Name",
promosmsPassword: "API Password", promosmsPassword: "API Password",
"pushoversounds pushover": "Pushover (default)", "pushoversounds pushover": "Pushover (default)",
@@ -507,16 +507,16 @@ export default {
pushyToken: "Device token", pushyToken: "Device token",
"Show update if available": "แสดงการอัปเดตถ้ามี", "Show update if available": "แสดงการอัปเดตถ้ามี",
"Also check beta release": "ตรวจสอบรุ่นเบต้า", "Also check beta release": "ตรวจสอบรุ่นเบต้า",
"Using a Reverse Proxy?": "ใช้ Reverse Proxy?", "Using a Reverse Proxy?": "ใช้ Reverse Proxy อยู่ใช่มั้ย?",
"Check how to config it for WebSocket": "ตรวจสอบวิธีการตั้งค่าสำหรับ WebSocket", "Check how to config it for WebSocket": "ตรวจสอบวิธีการตั้งค่าสำหรับ WebSocket",
"Steam Game Server": "Steam Game Server", "Steam Game Server": "Steam Game Server",
"Most likely causes:": "สาเหตุที่เป็นไปได้มากที่สุด :", "Most likely causes:": "สาเหตุที่เป็นไปได้มากที่สุด :",
"The resource is no longer available.": "ทรัพยากรไม่สามารถใช้งานได้อีกต่อไป", "The resource is no longer available.": "ทรัพยากรไม่สามารถใช้งานได้อีกต่อไป",
"There might be a typing error in the address.": "อาจมีข้อผิดพลาดในการพิมพ์ที่อยู่", "There might be a typing error in the address.": "อาจมีข้อผิดพลาดในการพิมพ์ที่อยู่",
"What you can try:": "สิ่งที่คุณสามารถลอง :", "What you can try:": "สิ่งที่คุณสามารถลองทำ :",
"Retype the address.": "พิมพ์ที่อยู่อีกครั้ง", "Retype the address.": "พิมพ์ที่อยู่อีกครั้ง",
"Go back to the previous page.": "กลับไปที่หน้าก่อนหน้า", "Go back to the previous page.": "กลับไปหน้าที่แล้ว",
"Coming Soon": "เร็ว ๆ นี้", "Coming Soon": "เร็วๆ นี้",
wayToGetClickSendSMSToken: "คุณสามารถรับ API Username และ API Key ได้จาก {0}", wayToGetClickSendSMSToken: "คุณสามารถรับ API Username และ API Key ได้จาก {0}",
wayToGetLineNotifyToken: "คุณสามารถรับ access token ได้จาก {0}", wayToGetLineNotifyToken: "คุณสามารถรับ access token ได้จาก {0}",
resendEveryXTimes: "ส่งซ้ำทุก {0} ครั้ง", resendEveryXTimes: "ส่งซ้ำทุก {0} ครั้ง",
@@ -525,7 +525,7 @@ export default {
"Resend Notification if Down X times consequently": "ส่งการแจ้งเตือนซ้ำถ้าออฟไลน์ครบ X ครั้ง", "Resend Notification if Down X times consequently": "ส่งการแจ้งเตือนซ้ำถ้าออฟไลน์ครบ X ครั้ง",
error: "เกิดข้อผิดพลาด", error: "เกิดข้อผิดพลาด",
critical: "วิกฤต", critical: "วิกฤต",
wayToGetPagerDutyKey: "คุณสามารถรับได้โดยการไปที่ Service -> Service Directory -> (Select a service) -> Integrations -> Add integration, และค้นหา \"Events API V2\", สำหรับข้อมูลเพิ่มเติม {0}", wayToGetPagerDutyKey: "คุณสามารถรับคีย์ได้โดยการไปที่ Service -> Service Directory -> (Select a service) -> Integrations -> Add integration, และค้นหา \"Events API V2\", สำหรับข้อมูลเพิ่มเติม {0}",
"Integration Key": "Integration Key", "Integration Key": "Integration Key",
"Integration URL": "Integration URL", "Integration URL": "Integration URL",
"Auto resolve or acknowledged": "แก้ไขอัตโนมัติหรือยอมรับ", "Auto resolve or acknowledged": "แก้ไขอัตโนมัติหรือยอมรับ",
@@ -539,16 +539,16 @@ export default {
"Trust Proxy": "Trust Proxy", "Trust Proxy": "Trust Proxy",
HomeAssistant: "Home Assistant", HomeAssistant: "Home Assistant",
RadiusSecret: "Radius Secret", RadiusSecret: "Radius Secret",
RadiusSecretDescription: "แบ่งปันข้อมูลลับระหว่างผู้ใช้งานและเซิร์ฟเวอร์", RadiusSecretDescription: "แบ่งปันคีย์ลับระหว่างผู้ใช้งานและเซิร์ฟเวอร์",
RadiusCalledStationId: "Called Station Id", RadiusCalledStationId: "Called Station Id",
RadiusCalledStationIdDescription: "Identifier of the called device", RadiusCalledStationIdDescription: "Identifier of the called device",
RadiusCallingStationId: "Calling Station Id", RadiusCallingStationId: "Calling Station Id",
RadiusCallingStationIdDescription: "Identifier of the calling device", RadiusCallingStationIdDescription: "Identifier of the calling device",
"Connection String": "Connection String", "Connection String": "Connection String",
Query: "Query", Query: "Query",
settingsCertificateExpiry: "วันหมดอายุใบรับรอง TLS", settingsCertificateExpiry: "วันหมดอายุของใบรับรอง TLS",
certificationExpiryDescription: "การตรวจสอบ HTTPS แจ้งเตือนใบอนุญาติ TLS จะหมดอายุใน:", certificationExpiryDescription: "การตรวจสอบ HTTPS จะแจ้งเตือนถ้าใบอนุญาติ TLS จะหมดอายุใน:",
"Setup Docker Host": "Setup Docker Host", "Setup Docker Host": "ติดตั้ง Docker Host",
"Connection Type": "ประเภทการเชื่อมต่อ", "Connection Type": "ประเภทการเชื่อมต่อ",
"Docker Daemon": "Docker Daemon", "Docker Daemon": "Docker Daemon",
deleteDockerHostMsg: "คุณแน่ใจหรือไม่ที่จะลบ Docker host นี้สำหรับการมอนิเตอร์ทั้งหมด?", deleteDockerHostMsg: "คุณแน่ใจหรือไม่ที่จะลบ Docker host นี้สำหรับการมอนิเตอร์ทั้งหมด?",
@@ -565,14 +565,14 @@ export default {
trustProxyDescription: "เชื่อ Header 'X-Forwarded-*' ถ้าคุณต้องการไอพีที่ถูกต้องและ Uptime Kuma อยู่ข้างหลัง Nginx หรือ Apache, คุณควรเปิดใช้งาน", trustProxyDescription: "เชื่อ Header 'X-Forwarded-*' ถ้าคุณต้องการไอพีที่ถูกต้องและ Uptime Kuma อยู่ข้างหลัง Nginx หรือ Apache, คุณควรเปิดใช้งาน",
Examples: "ตัวอย่าง", Examples: "ตัวอย่าง",
"Home Assistant URL": "Home Assistant URL", "Home Assistant URL": "Home Assistant URL",
"Long-Lived Access Token": "Access Token แบบมีอายุ", "Long-Lived Access Token": "Access Token แบบมีอายุนาน",
"Long-Lived Access Token can be created by clicking on your profile name (bottom left) and scrolling to the bottom then click Create Token. ": "Access Token แบบมีอายุนานสามารถสร้างได้โดยคลิกชื่อบนโปรไฟล์ (ล่างซ้าย) และเลื่อนไปข้างล่างจากนั้นคลิก \"Create Token\"", "Long-Lived Access Token can be created by clicking on your profile name (bottom left) and scrolling to the bottom then click Create Token. ": "Access Token แบบมีอายุนานสามารถสร้างได้โดยคลิกชื่อบนโปรไฟล์ (ล่างซ้าย) และเลื่อนไปข้างล่างจากนั้นคลิก \"Create Token\"",
"Notification Service": "บริการแจ้งเตือน", "Notification Service": "บริการแจ้งเตือน",
"default: notify all devices": "ค่าเริ่มต้น: แจ้งเตือนทุกอุปกรณ์", "default: notify all devices": "ค่าเริ่มต้น: แจ้งเตือนทุกอุปกรณ์",
"A list of Notification Services can be found in Home Assistant under \"Developer Tools > Services\" search for \"notification\" to find your device/phone name.": "รายการแจ้งเตือนสามารถหาได้ใน Home Assistant ในเมนู \"Developer Tools > Services\" ค้นหา \"notification\" เพื่อหาชื่ออุปกรณ์หรือชื่อโทรศัพท์", "A list of Notification Services can be found in Home Assistant under \"Developer Tools > Services\" search for \"notification\" to find your device/phone name.": "รายการแจ้งเตือนสามารถหาได้ใน Home Assistant ในเมนู \"Developer Tools > Services\" แล้วค้นหา \"notification\" เพื่อหาชื่ออุปกรณ์หรือชื่อโทรศัพท์",
"Automations can optionally be triggered in Home Assistant:": "สามารถเลือกสั่งงานระบบอัตโนมัติได้ใน Home Assistant:", "Automations can optionally be triggered in Home Assistant:": "สามารถเลือกสั่งงานระบบอัตโนมัติได้ใน Home Assistant:",
"Trigger type:": "ชนิดสิ่งกระตุ้น:", "Trigger type:": "ชนิดสิ่งกระตุ้น:",
"Event type:": "ชนิดกิจกรรม:", "Event type:": "ชนิดเหตการณ์:",
"Event data:": "ข้อมูลกิจกรรม:", "Event data:": "ข้อมูลกิจกรรม:",
"Then choose an action, for example switch the scene to where an RGB light is red.": "จากนั้นเลือกการกระทำ, ตัวอย่าง เช่น เปลี่ยนเป็นไฟสีแดง", "Then choose an action, for example switch the scene to where an RGB light is red.": "จากนั้นเลือกการกระทำ, ตัวอย่าง เช่น เปลี่ยนเป็นไฟสีแดง",
"Frontend Version": "เวอร์ชั่น Frontend", "Frontend Version": "เวอร์ชั่น Frontend",

View File

@@ -382,4 +382,7 @@ export default {
setAsDefaultProxyDescription: "預設情況下,新監測器將啟用此代理伺服器。您仍可分別停用各監測器的代理伺服器。", setAsDefaultProxyDescription: "預設情況下,新監測器將啟用此代理伺服器。您仍可分別停用各監測器的代理伺服器。",
Maintenance: "維護", Maintenance: "維護",
statusMaintenance: "維護中", statusMaintenance: "維護中",
"Enable DNS Cache": "啟用 DNS 快取",
"Enable": "啟用",
"Disable": "停用",
}; };

View File

@@ -93,7 +93,7 @@
<nav v-if="$root.isMobile && $root.loggedIn" class="bottom-nav"> <nav v-if="$root.isMobile && $root.loggedIn" class="bottom-nav">
<router-link to="/dashboard" class="nav-link"> <router-link to="/dashboard" class="nav-link">
<div><font-awesome-icon icon="tachometer-alt" /></div> <div><font-awesome-icon icon="tachometer-alt" /></div>
{{ $t("Dashboard") }} {{ $t("Home") }}
</router-link> </router-link>
<router-link to="/list" class="nav-link"> <router-link to="/list" class="nav-link">

View File

@@ -17,7 +17,7 @@ import lang from "./mixins/lang";
import { router } from "./router"; import { router } from "./router";
import { appName } from "./util.ts"; import { appName } from "./util.ts";
import dayjs from "dayjs"; import dayjs from "dayjs";
import timezone from "dayjs/plugin/timezone"; import timezone from "./modules/dayjs/plugin/timezone";
import utc from "dayjs/plugin/utc"; import utc from "dayjs/plugin/utc";
import relativeTime from "dayjs/plugin/relativeTime"; import relativeTime from "dayjs/plugin/relativeTime";
dayjs.extend(utc); dayjs.extend(utc);

View File

@@ -2,6 +2,7 @@ import { io } from "socket.io-client";
import { useToast } from "vue-toastification"; import { useToast } from "vue-toastification";
import jwtDecode from "jwt-decode"; import jwtDecode from "jwt-decode";
import Favico from "favico.js"; import Favico from "favico.js";
import dayjs from "dayjs";
const toast = useToast(); const toast = useToast();
let socket; let socket;
@@ -271,6 +272,10 @@ export default {
socket.on("cloudflared_message", (res) => this.cloudflared.message = res); socket.on("cloudflared_message", (res) => this.cloudflared.message = res);
socket.on("cloudflared_errorMessage", (res) => this.cloudflared.errorMessage = res); socket.on("cloudflared_errorMessage", (res) => this.cloudflared.errorMessage = res);
socket.on("cloudflared_token", (res) => this.cloudflared.cloudflareTunnelToken = res); socket.on("cloudflared_token", (res) => this.cloudflared.cloudflareTunnelToken = res);
socket.on("initServerTimezone", () => {
socket.emit("initServerTimezone", dayjs.tz.guess());
});
}, },
/** /**
@@ -585,7 +590,7 @@ export default {
for (let monitorID in this.lastHeartbeatList) { for (let monitorID in this.lastHeartbeatList) {
let lastHeartBeat = this.lastHeartbeatList[monitorID]; let lastHeartBeat = this.lastHeartbeatList[monitorID];
if (this.monitorList[monitorID].maintenance) { if (this.monitorList[monitorID] && this.monitorList[monitorID].maintenance) {
result[monitorID] = { result[monitorID] = {
text: this.$t("statusMaintenance"), text: this.$t("statusMaintenance"),
color: "maintenance", color: "maintenance",

View File

@@ -0,0 +1,25 @@
export let SECONDS_A_MINUTE = 60;
export let SECONDS_A_HOUR = SECONDS_A_MINUTE * 60;
export let SECONDS_A_DAY = SECONDS_A_HOUR * 24;
export let SECONDS_A_WEEK = SECONDS_A_DAY * 7;
export let MILLISECONDS_A_SECOND = 1e3;
export let MILLISECONDS_A_MINUTE = SECONDS_A_MINUTE * MILLISECONDS_A_SECOND;
export let MILLISECONDS_A_HOUR = SECONDS_A_HOUR * MILLISECONDS_A_SECOND;
export let MILLISECONDS_A_DAY = SECONDS_A_DAY * MILLISECONDS_A_SECOND;
export let MILLISECONDS_A_WEEK = SECONDS_A_WEEK * MILLISECONDS_A_SECOND; // English locales
export let MS = "millisecond";
export let S = "second";
export let MIN = "minute";
export let H = "hour";
export let D = "day";
export let W = "week";
export let M = "month";
export let Q = "quarter";
export let Y = "year";
export let DATE = "date";
export let FORMAT_DEFAULT = "YYYY-MM-DDTHH:mm:ssZ";
export let INVALID_DATE_STRING = "Invalid Date"; // regex
export let REGEX_PARSE = /^(\d{4})[-/]?(\d{1,2})?[-/]?(\d{0,2})[Tt\s]*(\d{1,2})?:?(\d{1,2})?:?(\d{1,2})?[.:]?(\d+)?$/;
export let REGEX_FORMAT = /\[([^\]]+)]|Y{1,4}|M{1,4}|D{1,2}|d{1,4}|H{1,2}|h{1,2}|a|A|m{1,2}|s{1,2}|Z{1,2}|SSS/g;

View File

@@ -0,0 +1,20 @@
import { PluginFunc, ConfigType } from 'dayjs/esm'
declare const plugin: PluginFunc
export = plugin
declare module 'dayjs/esm' {
interface Dayjs {
tz(timezone?: string, keepLocalTime?: boolean): Dayjs
offsetName(type?: 'short' | 'long'): string | undefined
}
interface DayjsTimezone {
(date: ConfigType, timezone?: string): Dayjs
(date: ConfigType, format: string, timezone?: string): Dayjs
guess(): string
setDefault(timezone?: string): void
}
const tz: DayjsTimezone
}

View File

@@ -0,0 +1,188 @@
/**
* Copy from node_modules/dayjs/plugin/timezone.js
* Try to fix https://github.com/louislam/uptime-kuma/issues/2318
* Source: https://github.com/iamkun/dayjs/tree/dev/src/plugin/utc
* License: MIT
*/
import { MIN, MS } from "../../constant";
let typeToPos = {
year: 0,
month: 1,
day: 2,
hour: 3,
minute: 4,
second: 5
}; // Cache time-zone lookups from Intl.DateTimeFormat,
// as it is a *very* slow method.
let dtfCache = {};
let getDateTimeFormat = function getDateTimeFormat(timezone, options) {
if (options === void 0) {
options = {};
}
let timeZoneName = options.timeZoneName || "short";
let key = timezone + "|" + timeZoneName;
let dtf = dtfCache[key];
if (!dtf) {
dtf = new Intl.DateTimeFormat("en-US", {
hour12: false,
timeZone: timezone,
year: "numeric",
month: "2-digit",
day: "2-digit",
hour: "2-digit",
minute: "2-digit",
second: "2-digit",
timeZoneName: timeZoneName
});
dtfCache[key] = dtf;
}
return dtf;
};
export default (function (o, c, d) {
let defaultTimezone;
let makeFormatParts = function makeFormatParts(timestamp, timezone, options) {
if (options === void 0) {
options = {};
}
let date = new Date(timestamp);
let dtf = getDateTimeFormat(timezone, options);
return dtf.formatToParts(date);
};
let tzOffset = function tzOffset(timestamp, timezone) {
let formatResult = makeFormatParts(timestamp, timezone);
let filled = [];
for (let i = 0; i < formatResult.length; i += 1) {
let _formatResult$i = formatResult[i];
let type = _formatResult$i.type;
let value = _formatResult$i.value;
let pos = typeToPos[type];
if (pos >= 0) {
filled[pos] = parseInt(value, 10);
}
}
let hour = filled[3]; // Workaround for the same behavior in different node version
// https://github.com/nodejs/node/issues/33027
/* istanbul ignore next */
let fixedHour = hour === 24 ? 0 : hour;
let utcString = filled[0] + "-" + filled[1] + "-" + filled[2] + " " + fixedHour + ":" + filled[4] + ":" + filled[5] + ":000";
let utcTs = d.utc(utcString).valueOf();
let asTS = +timestamp;
let over = asTS % 1000;
asTS -= over;
return (utcTs - asTS) / (60 * 1000);
}; // find the right offset a given local time. The o input is our guess, which determines which
// offset we'll pick in ambiguous cases (e.g. there are two 3 AMs b/c Fallback DST)
// https://github.com/moment/luxon/blob/master/src/datetime.js#L76
let fixOffset = function fixOffset(localTS, o0, tz) {
// Our UTC time is just a guess because our offset is just a guess
let utcGuess = localTS - o0 * 60 * 1000; // Test whether the zone matches the offset for this ts
let o2 = tzOffset(utcGuess, tz); // If so, offset didn't change and we're done
if (o0 === o2) {
return [ utcGuess, o0 ];
} // If not, change the ts by the difference in the offset
utcGuess -= (o2 - o0) * 60 * 1000; // If that gives us the local time we want, we're done
let o3 = tzOffset(utcGuess, tz);
if (o2 === o3) {
return [ utcGuess, o2 ];
} // If it's different, we're in a hole time.
// The offset has changed, but the we don't adjust the time
return [ localTS - Math.min(o2, o3) * 60 * 1000, Math.max(o2, o3) ];
};
let proto = c.prototype;
proto.tz = function (timezone, keepLocalTime) {
if (timezone === void 0) {
timezone = defaultTimezone;
}
let oldOffset = this.utcOffset();
let date = this.toDate();
let target = date.toLocaleString("en-US", {
timeZone: timezone
}).replace("\u202f", " ");
let diff = Math.round((date - new Date(target)) / 1000 / 60);
let ins = d(target).$set(MS, this.$ms).utcOffset(-Math.round(date.getTimezoneOffset() / 15) * 15 - diff, true);
if (keepLocalTime) {
let newOffset = ins.utcOffset();
ins = ins.add(oldOffset - newOffset, MIN);
}
ins.$x.$timezone = timezone;
return ins;
};
proto.offsetName = function (type) {
// type: short(default) / long
let zone = this.$x.$timezone || d.tz.guess();
let result = makeFormatParts(this.valueOf(), zone, {
timeZoneName: type
}).find(function (m) {
return m.type.toLowerCase() === "timezonename";
});
return result && result.value;
};
let oldStartOf = proto.startOf;
proto.startOf = function (units, startOf) {
if (!this.$x || !this.$x.$timezone) {
return oldStartOf.call(this, units, startOf);
}
let withoutTz = d(this.format("YYYY-MM-DD HH:mm:ss:SSS"));
let startOfWithoutTz = oldStartOf.call(withoutTz, units, startOf);
return startOfWithoutTz.tz(this.$x.$timezone, true);
};
d.tz = function (input, arg1, arg2) {
let parseFormat = arg2 && arg1;
let timezone = arg2 || arg1 || defaultTimezone;
let previousOffset = tzOffset(+d(), timezone);
if (typeof input !== "string") {
// timestamp number || js Date || Day.js
return d(input).tz(timezone);
}
let localTs = d.utc(input, parseFormat).valueOf();
let _fixOffset = fixOffset(localTs, previousOffset, timezone);
let targetTs = _fixOffset[0];
let targetOffset = _fixOffset[1];
let ins = d(targetTs).utcOffset(targetOffset);
ins.$x.$timezone = timezone;
return ins;
};
d.tz.guess = function () {
return Intl.DateTimeFormat().resolvedOptions().timeZone;
};
d.tz.setDefault = function (timezone) {
defaultTimezone = timezone;
};
});

View File

@@ -11,7 +11,7 @@
<div class="my-3"> <div class="my-3">
<label for="type" class="form-label">{{ $t("Monitor Type") }}</label> <label for="type" class="form-label">{{ $t("Monitor Type") }}</label>
<select id="type" v-model="monitor.type" class="form-select"> <select id="type" v-model="monitor.type" class="form-select">
<optgroup label="General Monitor Type"> <optgroup :label="$t('General Monitor Type')">
<option value="http"> <option value="http">
HTTP(s) HTTP(s)
</option> </option>
@@ -35,13 +35,13 @@
</option> </option>
</optgroup> </optgroup>
<optgroup label="Passive Monitor Type"> <optgroup :label="$t('Passive Monitor Type')">
<option value="push"> <option value="push">
Push Push
</option> </option>
</optgroup> </optgroup>
<optgroup label="Specific Monitor Type"> <optgroup :label="$t('Specific Monitor Type')">
<option value="steam"> <option value="steam">
{{ $t("Steam Game Server") }} {{ $t("Steam Game Server") }}
</option> </option>
@@ -271,7 +271,7 @@
<!-- Interval --> <!-- Interval -->
<div class="my-3"> <div class="my-3">
<label for="interval" class="form-label">{{ $t("Heartbeat Interval") }} ({{ $t("checkEverySecond", [ monitor.interval ]) }})</label> <label for="interval" class="form-label">{{ $t("Heartbeat Interval") }} ({{ $t("checkEverySecond", [ monitor.interval ]) }})</label>
<input id="interval" v-model="monitor.interval" type="number" class="form-control" required min="20" step="1"> <input id="interval" v-model="monitor.interval" type="number" class="form-control" required :min="minInterval" step="1" :max="maxInterval">
</div> </div>
<div class="my-3"> <div class="my-3">
@@ -287,7 +287,7 @@
{{ $t("Heartbeat Retry Interval") }} {{ $t("Heartbeat Retry Interval") }}
<span>({{ $t("retryCheckEverySecond", [ monitor.retryInterval ]) }})</span> <span>({{ $t("retryCheckEverySecond", [ monitor.retryInterval ]) }})</span>
</label> </label>
<input id="retry-interval" v-model="monitor.retryInterval" type="number" class="form-control" required min="20" step="1"> <input id="retry-interval" v-model="monitor.retryInterval" type="number" class="form-control" required :min="minInterval" step="1">
</div> </div>
<div class="my-3"> <div class="my-3">
@@ -575,7 +575,7 @@ import NotificationDialog from "../components/NotificationDialog.vue";
import DockerHostDialog from "../components/DockerHostDialog.vue"; import DockerHostDialog from "../components/DockerHostDialog.vue";
import ProxyDialog from "../components/ProxyDialog.vue"; import ProxyDialog from "../components/ProxyDialog.vue";
import TagsManager from "../components/TagsManager.vue"; import TagsManager from "../components/TagsManager.vue";
import { genSecret, isDev } from "../util.ts"; import { genSecret, isDev, MAX_INTERVAL_SECOND, MIN_INTERVAL_SECOND } from "../util.ts";
const toast = useToast(); const toast = useToast();
@@ -591,6 +591,8 @@ export default {
data() { data() {
return { return {
minInterval: MIN_INTERVAL_SECOND,
maxInterval: MAX_INTERVAL_SECOND,
processing: false, processing: false,
monitor: { monitor: {
notificationIDList: {}, notificationIDList: {},

View File

@@ -185,6 +185,14 @@ export default {
<style lang="scss" scoped> <style lang="scss" scoped>
@import "../assets/vars.scss"; @import "../assets/vars.scss";
.mobile {
.item {
flex-direction: column;
align-items: flex-start;
margin-bottom: 20px;
}
}
.item { .item {
display: flex; display: flex;
align-items: center; align-items: center;
@@ -267,6 +275,11 @@ export default {
.buttons { .buttons {
display: flex; display: flex;
gap: 8px; gap: 8px;
flex-direction: row-reverse;
.btn-group {
width: 310px;
}
} }
} }

View File

@@ -1,10 +1,19 @@
<template> <template>
<div> <div>
<div v-if="$root.isMobile" class="shadow-box mb-3">
<router-link to="/manage-status-page" class="nav-link">
<font-awesome-icon icon="stream" /> {{ $t("Status Pages") }}
</router-link>
<router-link to="/maintenance" class="nav-link">
<font-awesome-icon icon="wrench" /> {{ $t("Maintenance") }}
</router-link>
</div>
<h1 v-show="show" class="mb-3"> <h1 v-show="show" class="mb-3">
{{ $t("Settings") }} {{ $t("Settings") }}
</h1> </h1>
<div class="shadow-box"> <div class="shadow-box shadow-box-settings">
<div class="row"> <div class="row">
<div v-if="showSubMenu" class="settings-menu col-lg-3 col-md-5"> <div v-if="showSubMenu" class="settings-menu col-lg-3 col-md-5">
<router-link <router-link
@@ -148,6 +157,10 @@ export default {
this.settings.entryPage = "dashboard"; this.settings.entryPage = "dashboard";
} }
if (this.settings.dnsCache === undefined) {
this.settings.dnsCache = false;
}
if (this.settings.keepDataPeriodDays === undefined) { if (this.settings.keepDataPeriodDays === undefined) {
this.settings.keepDataPeriodDays = 180; this.settings.keepDataPeriodDays = 180;
} }
@@ -192,7 +205,7 @@ export default {
<style lang="scss" scoped> <style lang="scss" scoped>
@import "../assets/vars.scss"; @import "../assets/vars.scss";
.shadow-box { .shadow-box-settings {
padding: 20px; padding: 20px;
min-height: calc(100vh - 155px); min-height: calc(100vh - 155px);
} }

View File

@@ -7,7 +7,7 @@
// Backend uses the compiled file util.js // Backend uses the compiled file util.js
// Frontend uses util.ts // Frontend uses util.ts
Object.defineProperty(exports, "__esModule", { value: true }); Object.defineProperty(exports, "__esModule", { value: true });
exports.localToUTC = exports.utcToLocal = exports.utcToISODateTime = exports.isoToUTCDateTime = exports.parseTimeFromTimeObject = exports.parseTimeObject = exports.getMaintenanceRelativeURL = exports.getMonitorRelativeURL = exports.genSecret = exports.getCryptoRandomInt = exports.getRandomInt = exports.getRandomArbitrary = exports.TimeLogger = exports.polyfill = exports.log = exports.debug = exports.ucfirst = exports.sleep = exports.flipStatus = exports.SQL_DATETIME_FORMAT_WITHOUT_SECOND = exports.SQL_DATETIME_FORMAT = exports.SQL_DATE_FORMAT = exports.STATUS_PAGE_MAINTENANCE = exports.STATUS_PAGE_PARTIAL_DOWN = exports.STATUS_PAGE_ALL_UP = exports.STATUS_PAGE_ALL_DOWN = exports.MAINTENANCE = exports.PENDING = exports.UP = exports.DOWN = exports.appName = exports.isDev = void 0; exports.localToUTC = exports.utcToLocal = exports.utcToISODateTime = exports.isoToUTCDateTime = exports.parseTimeFromTimeObject = exports.parseTimeObject = exports.getMaintenanceRelativeURL = exports.getMonitorRelativeURL = exports.genSecret = exports.getCryptoRandomInt = exports.getRandomInt = exports.getRandomArbitrary = exports.TimeLogger = exports.polyfill = exports.log = exports.debug = exports.ucfirst = exports.sleep = exports.flipStatus = exports.MIN_INTERVAL_SECOND = exports.MAX_INTERVAL_SECOND = exports.SQL_DATETIME_FORMAT_WITHOUT_SECOND = exports.SQL_DATETIME_FORMAT = exports.SQL_DATE_FORMAT = exports.STATUS_PAGE_MAINTENANCE = exports.STATUS_PAGE_PARTIAL_DOWN = exports.STATUS_PAGE_ALL_UP = exports.STATUS_PAGE_ALL_DOWN = exports.MAINTENANCE = exports.PENDING = exports.UP = exports.DOWN = exports.appName = exports.isDev = void 0;
const dayjs = require("dayjs"); const dayjs = require("dayjs");
exports.isDev = process.env.NODE_ENV === "development"; exports.isDev = process.env.NODE_ENV === "development";
exports.appName = "Uptime Kuma"; exports.appName = "Uptime Kuma";
@@ -22,6 +22,8 @@ exports.STATUS_PAGE_MAINTENANCE = 3;
exports.SQL_DATE_FORMAT = "YYYY-MM-DD"; exports.SQL_DATE_FORMAT = "YYYY-MM-DD";
exports.SQL_DATETIME_FORMAT = "YYYY-MM-DD HH:mm:ss"; exports.SQL_DATETIME_FORMAT = "YYYY-MM-DD HH:mm:ss";
exports.SQL_DATETIME_FORMAT_WITHOUT_SECOND = "YYYY-MM-DD HH:mm"; exports.SQL_DATETIME_FORMAT_WITHOUT_SECOND = "YYYY-MM-DD HH:mm";
exports.MAX_INTERVAL_SECOND = 2073600; // 24 days
exports.MIN_INTERVAL_SECOND = 20; // 20 seconds
/** Flip the status of s */ /** Flip the status of s */
function flipStatus(s) { function flipStatus(s) {
if (s === exports.UP) { if (s === exports.UP) {
@@ -99,12 +101,18 @@ class Logger {
* @param level Log level. One of INFO, WARN, ERROR, DEBUG or can be customized. * @param level Log level. One of INFO, WARN, ERROR, DEBUG or can be customized.
*/ */
log(module, msg, level) { log(module, msg, level) {
if (this.hideLog[level] && this.hideLog[level].includes(module)) { if (this.hideLog[level] && this.hideLog[level].includes(module.toLowerCase())) {
return; return;
} }
module = module.toUpperCase(); module = module.toUpperCase();
level = level.toUpperCase(); level = level.toUpperCase();
const now = dayjs.tz(new Date()).format(); let now;
if (dayjs.tz) {
now = dayjs.tz(new Date()).format();
}
else {
now = dayjs().format();
}
const formattedMessage = (typeof msg === "string") ? `${now} [${module}] ${level}: ${msg}` : msg; const formattedMessage = (typeof msg === "string") ? `${now} [${module}] ${level}: ${msg}` : msg;
if (level === "INFO") { if (level === "INFO") {
console.info(formattedMessage); console.info(formattedMessage);

View File

@@ -26,6 +26,9 @@ export const SQL_DATE_FORMAT = "YYYY-MM-DD";
export const SQL_DATETIME_FORMAT = "YYYY-MM-DD HH:mm:ss"; export const SQL_DATETIME_FORMAT = "YYYY-MM-DD HH:mm:ss";
export const SQL_DATETIME_FORMAT_WITHOUT_SECOND = "YYYY-MM-DD HH:mm"; export const SQL_DATETIME_FORMAT_WITHOUT_SECOND = "YYYY-MM-DD HH:mm";
export const MAX_INTERVAL_SECOND = 2073600; // 24 days
export const MIN_INTERVAL_SECOND = 20; // 20 seconds
/** Flip the status of s */ /** Flip the status of s */
export function flipStatus(s: number) { export function flipStatus(s: number) {
if (s === UP) { if (s === UP) {
@@ -112,14 +115,19 @@ class Logger {
* @param level Log level. One of INFO, WARN, ERROR, DEBUG or can be customized. * @param level Log level. One of INFO, WARN, ERROR, DEBUG or can be customized.
*/ */
log(module: string, msg: any, level: string) { log(module: string, msg: any, level: string) {
if (this.hideLog[level] && this.hideLog[level].includes(module)) { if (this.hideLog[level] && this.hideLog[level].includes(module.toLowerCase())) {
return; return;
} }
module = module.toUpperCase(); module = module.toUpperCase();
level = level.toUpperCase(); level = level.toUpperCase();
const now = dayjs.tz(new Date()).format(); let now;
if (dayjs.tz) {
now = dayjs.tz(new Date()).format();
} else {
now = dayjs().format();
}
const formattedMessage = (typeof msg === "string") ? `${now} [${module}] ${level}: ${msg}` : msg; const formattedMessage = (typeof msg === "string") ? `${now} [${module}] ${level}: ${msg}` : msg;
if (level === "INFO") { if (level === "INFO") {