Merge remote-tracking branch 'origin/master' into theS1LV3R_master

pull/1827/head
Louis Lam 2 years ago
commit a07f54f35b

@ -8,6 +8,7 @@
"declaration-empty-line-before": null,
"alpha-value-notation": "number",
"color-function-notation": "legacy",
"shorthand-property-no-redundant-values": null
"shorthand-property-no-redundant-values": null,
"color-hex-length": null,
}
}

@ -151,9 +151,9 @@ You can discuss or ask for help in [issues](https://github.com/louislam/uptime-k
### Subreddit
My Reddit account: louislamlam
My Reddit account: [u/louislamlam](https://reddit.com/u/louislamlam).
You can mention me if you ask a question on Reddit.
https://www.reddit.com/r/UptimeKuma/
[r/Uptime kuma](https://www.reddit.com/r/UptimeKuma/)
## Contribute

@ -11,6 +11,9 @@ const viteCompressionFilter = /\.(js|mjs|json|css|html|svg)$/i;
// https://vitejs.dev/config/
export default defineConfig({
define: {
"FRONTEND_VERSION": JSON.stringify(process.env.npm_package_version),
},
plugins: [
vue(),
legacy({

@ -0,0 +1,5 @@
-- You should not modify if this have pushed to Github, unless it does serious wrong with the db.
BEGIN TRANSACTION;
ALTER TABLE monitor_group
ADD send_url BOOLEAN DEFAULT 0 NOT NULL;
COMMIT;

@ -4,5 +4,5 @@ WORKDIR /app
# Install apprise, iputils for non-root ping, setpriv
RUN apk add --no-cache iputils setpriv dumb-init python3 py3-cryptography py3-pip py3-six py3-yaml py3-click py3-markdown py3-requests py3-requests-oauthlib && \
pip3 --no-cache-dir install apprise==0.9.8.3 && \
pip3 --no-cache-dir install apprise==0.9.9 && \
rm -rf /root/.cache

@ -11,7 +11,7 @@ WORKDIR /app
RUN apt update && \
apt --yes --no-install-recommends install python3 python3-pip python3-cryptography python3-six python3-yaml python3-click python3-markdown python3-requests python3-requests-oauthlib \
sqlite3 iputils-ping util-linux dumb-init && \
pip3 --no-cache-dir install apprise==0.9.8.3 && \
pip3 --no-cache-dir install apprise==0.9.9 && \
rm -rf /var/lib/apt/lists/* && \
apt --yes autoremove

@ -1,4 +1,4 @@
# Simple docker-composer.yml
# Simple docker-compose.yml
# You can change your port or volume location
version: '3.3'

11883
package-lock.json generated

File diff suppressed because it is too large Load Diff

@ -61,22 +61,15 @@
"build-dist-and-restart": "npm run build && npm run start-server-dev"
},
"dependencies": {
"@fortawesome/fontawesome-svg-core": "~1.2.36",
"@fortawesome/free-regular-svg-icons": "~5.15.4",
"@fortawesome/free-solid-svg-icons": "~5.15.4",
"@fortawesome/vue-fontawesome": "~3.0.0-5",
"@louislam/sqlite3": "~15.0.6",
"@popperjs/core": "~2.10.2",
"args-parser": "~1.3.0",
"axios": "~0.26.1",
"axios-ntlm": "^1.3.0",
"badge-maker": "^3.3.1",
"bcryptjs": "~2.4.3",
"bootstrap": "5.1.3",
"bree": "~7.1.5",
"cacheable-lookup": "~6.0.4",
"chardet": "^1.3.0",
"chart.js": "~3.6.2",
"chartjs-adapter-dayjs": "~1.0.0",
"check-password-strength": "^2.0.5",
"cheerio": "^1.0.0-rc.10",
"chroma-js": "^2.1.2",
@ -87,7 +80,6 @@
"express": "~4.17.3",
"express-basic-auth": "~1.2.1",
"express-static-gzip": "^2.1.7",
"favico.js": "^0.3.10",
"form-data": "~4.0.0",
"http-graceful-shutdown": "~3.1.7",
"http-proxy-agent": "^5.0.0",
@ -102,62 +94,72 @@
"nodemailer": "~6.6.5",
"notp": "~2.0.3",
"password-hash": "~1.2.2",
"postcss-rtlcss": "~3.4.1",
"postcss-scss": "~4.0.3",
"prismjs": "^1.27.0",
"pg": "^8.7.3",
"pg-connection-string": "^2.5.0",
"prom-client": "~13.2.0",
"prometheus-api-metrics": "~3.2.1",
"qrcode": "~1.5.0",
"redbean-node": "0.1.4",
"socket.io": "~4.4.1",
"socket.io-client": "~4.4.1",
"socks-proxy-agent": "^6.1.1",
"socks-proxy-agent": "6.1.1",
"tar": "^6.1.11",
"tcp-ping": "~0.1.1",
"thirty-two": "~1.0.2",
"timezones-list": "~3.0.1",
"v-pagination-3": "~0.1.7",
"vue": "next",
"vue-chart-3": "3.0.9",
"vue-confirm-dialog": "~1.0.2",
"vue-contenteditable": "~3.0.4",
"vue-i18n": "~9.1.9",
"vue-image-crop-upload": "~3.0.3",
"vue-multiselect": "~3.0.0-alpha.2",
"vue-prism-editor": "^2.0.0-alpha.2",
"vue-qrcode": "~1.0.0",
"vue-router": "~4.0.14",
"vue-toastification": "~2.0.0-rc.5",
"vuedraggable": "~4.1.0"
"thirty-two": "~1.0.2"
},
"devDependencies": {
"@actions/github": "~5.0.1",
"@babel/eslint-parser": "~7.17.0",
"@babel/preset-env": "^7.15.8",
"@fortawesome/fontawesome-svg-core": "~1.2.36",
"@fortawesome/free-regular-svg-icons": "~5.15.4",
"@fortawesome/free-solid-svg-icons": "~5.15.4",
"@fortawesome/vue-fontawesome": "~3.0.0-5",
"@popperjs/core": "~2.10.2",
"@types/bootstrap": "~5.1.9",
"@vitejs/plugin-legacy": "~1.8.2",
"@vitejs/plugin-vue": "~2.3.3",
"@vue/compiler-sfc": "~3.2.36",
"aedes": "^0.46.3",
"babel-plugin-rewire": "~1.2.0",
"bootstrap": "5.1.3",
"chart.js": "~3.6.2",
"chartjs-adapter-dayjs": "~1.0.0",
"concurrently": "^7.1.0",
"core-js": "~3.18.3",
"cross-env": "~7.0.3",
"dns2": "~2.0.1",
"eslint": "~8.14.0",
"eslint-plugin-vue": "~8.7.1",
"favico.js": "^0.3.10",
"jest": "~27.2.5",
"jest-puppeteer": "~6.0.3",
"npm-check-updates": "^12.5.9",
"postcss-html": "^1.3.1",
"postcss-rtlcss": "~3.4.1",
"postcss-scss": "~4.0.3",
"prismjs": "^1.27.0",
"puppeteer": "~13.1.3",
"qrcode": "~1.5.0",
"rollup-plugin-visualizer": "^5.6.0",
"sass": "~1.42.1",
"stylelint": "~14.7.1",
"stylelint-config-standard": "~25.0.0",
"timezones-list": "~3.0.1",
"typescript": "~4.4.4",
"v-pagination-3": "~0.1.7",
"vite": "~2.9.9",
"vite-plugin-compression": "^0.5.1",
"vue": "next",
"vue-chart-3": "3.0.9",
"vue-confirm-dialog": "~1.0.2",
"vue-contenteditable": "~3.0.4",
"vue-i18n": "~9.1.9",
"vue-image-crop-upload": "~3.0.3",
"vue-multiselect": "~3.0.0-alpha.2",
"vue-prism-editor": "^2.0.0-alpha.2",
"vue-qrcode": "~1.0.0",
"vue-router": "~4.0.14",
"vue-toastification": "~2.0.0-rc.5",
"vuedraggable": "~4.1.0",
"wait-on": "^6.0.1"
}
}

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 6.4 KiB

After

Width:  |  Height:  |  Size: 893 B

@ -0,0 +1,54 @@
const https = require("https");
const http = require("http");
const CacheableLookup = require("cacheable-lookup");
class CacheableDnsHttpAgent {
static cacheable = new CacheableLookup();
static httpAgentList = {};
static httpsAgentList = {};
/**
* Register cacheable to global agents
*/
static registerGlobalAgent() {
this.cacheable.install(http.globalAgent);
this.cacheable.install(https.globalAgent);
}
static install(agent) {
this.cacheable.install(agent);
}
/**
* @var {https.AgentOptions} agentOptions
* @return {https.Agent}
*/
static getHttpsAgent(agentOptions) {
let key = JSON.stringify(agentOptions);
if (!(key in this.httpsAgentList)) {
this.httpsAgentList[key] = new https.Agent(agentOptions);
this.cacheable.install(this.httpsAgentList[key]);
}
return this.httpsAgentList[key];
}
/**
* @var {http.AgentOptions} agentOptions
* @return {https.Agents}
*/
static getHttpAgent(agentOptions) {
let key = JSON.stringify(agentOptions);
if (!(key in this.httpAgentList)) {
this.httpAgentList[key] = new http.Agent(agentOptions);
this.cacheable.install(this.httpAgentList[key]);
}
return this.httpAgentList[key];
}
}
module.exports = {
CacheableDnsHttpAgent,
};

@ -58,6 +58,7 @@ class Database {
"patch-monitor-expiry-notification.sql": true,
"patch-status-page-footer-css.sql": true,
"patch-added-mqtt-monitor.sql": true,
"patch-add-clickable-status-page-link.sql": true,
"patch-add-sqlserver-monitor.sql": true,
"patch-add-other-auth.sql": { parents: [ "patch-monitor-basic-auth.sql" ] },
};
@ -177,7 +178,13 @@ class Database {
} else {
log.info("db", "Database patch is needed");
this.backup(version);
try {
this.backup(version);
} catch (e) {
log.error("db", e);
log.error("db", "Unable to create a backup before patching the database. Please make sure you have enough space and permission.");
process.exit(1);
}
// Try catch anything here, if gone wrong, restore the backup
try {
@ -445,6 +452,23 @@ class Database {
this.backupWalPath = walPath + ".bak" + version;
fs.copyFileSync(walPath, this.backupWalPath);
}
// Double confirm if all files actually backup
if (!fs.existsSync(this.backupPath)) {
throw new Error("Backup failed! " + this.backupPath);
}
if (fs.existsSync(shmPath)) {
if (!fs.existsSync(this.backupShmPath)) {
throw new Error("Backup failed! " + this.backupShmPath);
}
}
if (fs.existsSync(walPath)) {
if (!fs.existsSync(this.backupWalPath)) {
throw new Error("Backup failed! " + this.backupWalPath);
}
}
}
}

@ -31,7 +31,7 @@ class Group extends BeanModel {
*/
async getMonitorList() {
return R.convertToBeans("monitor", await R.getAll(`
SELECT monitor.* FROM monitor, monitor_group
SELECT monitor.*, monitor_group.send_url FROM monitor, monitor_group
WHERE monitor.id = monitor_group.monitor_id
AND group_id = ?
ORDER BY monitor_group.weight

@ -7,7 +7,7 @@ dayjs.extend(timezone);
const axios = require("axios");
const { Prometheus } = require("../prometheus");
const { log, UP, DOWN, PENDING, flipStatus, TimeLogger } = require("../../src/util");
const { tcping, ping, dnsResolve, checkCertificate, checkStatusCode, getTotalClientInRoom, setting, mssqlQuery, mqttAsync, setSetting, httpNtlm } = require("../util-server");
const { tcping, ping, dnsResolve, checkCertificate, checkStatusCode, getTotalClientInRoom, setting, mssqlQuery, postgresQuery, mqttAsync, setSetting, httpNtlm } = require("../util-server");
const { R } = require("redbean-node");
const { BeanModel } = require("redbean-node/dist/bean-model");
const { Notification } = require("../notification");
@ -16,6 +16,7 @@ const { demoMode } = require("../config");
const version = require("../../package.json").version;
const apicache = require("../modules/apicache");
const { UptimeKumaServer } = require("../uptime-kuma-server");
const { CacheableDnsHttpAgent } = require("../cacheable-dns-http-agent");
/**
* status:
@ -34,7 +35,13 @@ class Monitor extends BeanModel {
let obj = {
id: this.id,
name: this.name,
sendUrl: this.sendUrl,
};
if (this.sendUrl) {
obj.url = this.url;
}
if (showTags) {
obj.tags = await this.getTags();
}
@ -434,10 +441,13 @@ class Monitor extends BeanModel {
"Accept": "*/*",
"User-Agent": "Uptime-Kuma/" + version,
},
httpsAgent: new https.Agent({
httpsAgent: CacheableDnsHttpAgent.getHttpsAgent({
maxCachedSessions: 0, // Use Custom agent to disable session reuse (https://github.com/nodejs/node/issues/3940)
rejectUnauthorized: !this.getIgnoreTls(),
}),
httpAgent: CacheableDnsHttpAgent.getHttpAgent({
maxCachedSessions: 0,
}),
maxRedirects: this.maxredirects,
validateStatus: (status) => {
return checkStatusCode(status, this.getAcceptedStatuscodes());
@ -471,6 +481,14 @@ class Monitor extends BeanModel {
await mssqlQuery(this.databaseConnectionString, this.databaseQuery);
bean.msg = "";
bean.status = UP;
bean.ping = dayjs().valueOf() - startTime;
} else if (this.type === "postgres") {
let startTime = dayjs().valueOf();
await postgresQuery(this.databaseConnectionString, this.databaseQuery);
bean.msg = "";
bean.status = UP;
bean.ping = dayjs().valueOf() - startTime;

@ -45,6 +45,8 @@ class StatusPage extends BeanModel {
$("link[rel=icon]")
.attr("href", statusPage.icon)
.removeAttr("type");
$("link[rel=apple-touch-icon]").remove();
}
const head = $("head");
@ -61,6 +63,9 @@ class StatusPage extends BeanModel {
</script>
`);
// manifest.json
$("link[rel=manifest]").attr("href", `/api/status-page/${statusPage.slug}/manifest.json`);
return $.root().html();
}

@ -0,0 +1,50 @@
const NotificationProvider = require("./notification-provider");
const axios = require("axios");
const { setting } = require("../util-server");
const { getMonitorRelativeURL, UP, DOWN } = require("../../src/util");
class AlertNow extends NotificationProvider {
name = "AlertNow";
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
let okMsg = "Sent Successfully.";
try {
let textMsg = "";
let status = "open";
let eventType = "ERROR";
let eventId = new Date().toISOString().slice(0, 10).replace(/-/g, "");
if (heartbeatJSON && heartbeatJSON.status === UP) {
textMsg = `[${heartbeatJSON.name}] ✅ Application is back online`;
status = "close";
eventType = "INFO";
eventId += `_${heartbeatJSON.name.replace(/\s/g, "")}`;
} else if (heartbeatJSON && heartbeatJSON.status === DOWN) {
textMsg = `[${heartbeatJSON.name}] 🔴 Application went down`;
}
textMsg += ` - ${msg}`;
const baseURL = await setting("primaryBaseURL");
if (baseURL && monitorJSON) {
textMsg += ` >> ${baseURL + getMonitorRelativeURL(monitorJSON.id)}`;
}
const data = {
"summary": textMsg,
"status": status,
"event_type": eventType,
"event_id": eventId,
};
await axios.post(notification.alertNowWebhookURL, data);
return okMsg;
} catch (error) {
this.throwGeneralAxiosError(error);
}
}
}
module.exports = AlertNow;

@ -0,0 +1,43 @@
const NotificationProvider = require("./notification-provider");
const axios = require("axios");
const qs = require("qs");
const { DOWN, UP } = require("../../src/util");
class LineNotify extends NotificationProvider {
name = "LineNotify";
async send(notification, msg, monitorJSON = null, heartbeatJSON = null) {
let okMsg = "Sent Successfully.";
try {
let lineAPIUrl = "https://notify-api.line.me/api/notify";
let config = {
headers: {
"Content-Type": "application/x-www-form-urlencoded",
"Authorization": "Bearer " + notification.lineNotifyAccessToken
}
};
if (heartbeatJSON == null) {
let testMessage = {
"message": msg,
};
await axios.post(lineAPIUrl, qs.stringify(testMessage), config);
} else if (heartbeatJSON["status"] === DOWN) {
let downMessage = {
"message": "\n[🔴 Down]\n" + "Name: " + monitorJSON["name"] + " \n" + heartbeatJSON["msg"] + "\nTime (UTC): " + heartbeatJSON["time"]
};
await axios.post(lineAPIUrl, qs.stringify(downMessage), config);
} else if (heartbeatJSON["status"] === UP) {
let upMessage = {
"message": "\n[✅ Up]\n" + "Name: " + monitorJSON["name"] + " \n" + heartbeatJSON["msg"] + "\nTime (UTC): " + heartbeatJSON["time"]
};
await axios.post(lineAPIUrl, qs.stringify(upMessage), config);
}
return okMsg;
} catch (error) {
this.throwGeneralAxiosError(error);
}
}
}
module.exports = LineNotify;

@ -1,40 +1,42 @@
const { R } = require("redbean-node");
const { log } = require("../src/util");
const Alerta = require("./notification-providers/alerta");
const AlertNow = require("./notification-providers/alertnow");
const AliyunSms = require("./notification-providers/aliyun-sms");
const Apprise = require("./notification-providers/apprise");
const Bark = require("./notification-providers/bark");
const ClickSendSMS = require("./notification-providers/clicksendsms");
const DingDing = require("./notification-providers/dingding");
const Discord = require("./notification-providers/discord");
const Feishu = require("./notification-providers/feishu");
const GoogleChat = require("./notification-providers/google-chat");
const Gorush = require("./notification-providers/gorush");
const Gotify = require("./notification-providers/gotify");
const Ntfy = require("./notification-providers/ntfy");
const Line = require("./notification-providers/line");
const LineNotify = require("./notification-providers/linenotify");
const LunaSea = require("./notification-providers/lunasea");
const Mattermost = require("./notification-providers/mattermost");
const Matrix = require("./notification-providers/matrix");
const Mattermost = require("./notification-providers/mattermost");
const Ntfy = require("./notification-providers/ntfy");
const Octopush = require("./notification-providers/octopush");
const OneBot = require("./notification-providers/onebot");
const PagerDuty = require("./notification-providers/pagerduty");
const PromoSMS = require("./notification-providers/promosms");
const ClickSendSMS = require("./notification-providers/clicksendsms");
const Pushbullet = require("./notification-providers/pushbullet");
const PushDeer = require("./notification-providers/pushdeer");
const Pushover = require("./notification-providers/pushover");
const Pushy = require("./notification-providers/pushy");
const TechulusPush = require("./notification-providers/techulus-push");
const RocketChat = require("./notification-providers/rocket-chat");
const SerwerSMS = require("./notification-providers/serwersms");
const Signal = require("./notification-providers/signal");
const Slack = require("./notification-providers/slack");
const SMTP = require("./notification-providers/smtp");
const Stackfield = require("./notification-providers/stackfield");
const Teams = require("./notification-providers/teams");
const TechulusPush = require("./notification-providers/techulus-push");
const Telegram = require("./notification-providers/telegram");
const Webhook = require("./notification-providers/webhook");
const Feishu = require("./notification-providers/feishu");
const AliyunSms = require("./notification-providers/aliyun-sms");
const DingDing = require("./notification-providers/dingding");
const Bark = require("./notification-providers/bark");
const { log } = require("../src/util");
const SerwerSMS = require("./notification-providers/serwersms");
const Stackfield = require("./notification-providers/stackfield");
const WeCom = require("./notification-providers/wecom");
const GoogleChat = require("./notification-providers/google-chat");
const PagerDuty = require("./notification-providers/pagerduty");
const Gorush = require("./notification-providers/gorush");
const Alerta = require("./notification-providers/alerta");
const OneBot = require("./notification-providers/onebot");
const PushDeer = require("./notification-providers/pushdeer");
class Notification {
@ -47,41 +49,43 @@ class Notification {
this.providerList = {};
const list = [
new Apprise(),
new Alerta(),
new AlertNow(),
new AliyunSms(),
new Apprise(),
new Bark(),
new ClickSendSMS(),
new DingDing(),
new Discord(),
new Teams(),
new Feishu(),
new GoogleChat(),
new Gorush(),
new Gotify(),
new Ntfy(),
new Line(),
new LineNotify(),
new LunaSea(),
new Feishu(),
new Mattermost(),
new Matrix(),
new Mattermost(),
new Ntfy(),
new Octopush(),
new OneBot(),
new PagerDuty(),
new PromoSMS(),
new ClickSendSMS(),
new Pushbullet(),
new PushDeer(),
new Pushover(),
new Pushy(),
new TechulusPush(),
new RocketChat(),
new SerwerSMS(),
new Signal(),
new Slack(),
new SMTP(),
new Stackfield(),
new Teams(),
new TechulusPush(),
new Telegram(),
new Webhook(),
new Bark(),
new SerwerSMS(),
new Stackfield(),
new WeCom(),
new GoogleChat(),
new PagerDuty(),
new Gorush(),
new Alerta(),
new OneBot(),
new PushDeer(),
];
for (let item of list) {

@ -107,4 +107,42 @@ router.get("/api/status-page/heartbeat/:slug", cache("1 minutes"), async (reques
}
});
// Status page's manifest.json
router.get("/api/status-page/:slug/manifest.json", cache("1440 minutes"), async (request, response) => {
allowDevAllOrigin(response);
let slug = request.params.slug;
try {
// Get Status Page
let statusPage = await R.findOne("status_page", " slug = ? ", [
slug
]);
if (!statusPage) {
response.statusCode = 404;
response.json({
msg: "Not Found"
});
return;
}
// Response
response.json({
"name": statusPage.title,
"start_url": "/status/" + statusPage.slug,
"display": "standalone",
"icons": [
{
"src": statusPage.icon,
"sizes": "128x128",
"type": "image/png"
}
]
});
} catch (error) {
send403(response, error.message);
}
});
module.exports = router;

@ -164,12 +164,20 @@ let needSetup = false;
// Entry Page
app.get("/", async (request, response) => {
log.debug("entry", `Request Domain: ${request.hostname}`);
let hostname = request.hostname;
if (await setting("trustProxy")) {
const proxy = request.headers["x-forwarded-host"];
if (proxy) {
hostname = proxy;
}
}
log.debug("entry", `Request Domain: ${hostname}`);
if (request.hostname in StatusPage.domainMappingList) {
if (hostname in StatusPage.domainMappingList) {
log.debug("entry", "This is a status page domain");
let slug = StatusPage.domainMappingList[request.hostname];
let slug = StatusPage.domainMappingList[hostname];
await StatusPage.handleStatusPageResponse(response, server.indexHTML, slug);
} else if (exports.entryPage && exports.entryPage.startsWith("statusPage-")) {

@ -0,0 +1,165 @@
const { R } = require("redbean-node");
const { log } = require("../src/util");
class Settings {
/**
* Example:
* {
* key1: {
* value: "value2",
* timestamp: 12345678
* },
* key2: {
* value: 2,
* timestamp: 12345678
* },
* }
* @type {{}}
*/
static cacheList = {
};
static cacheCleaner = null;
/**
* Retrieve value of setting based on key
* @param {string} key Key of setting to retrieve
* @returns {Promise<any>} Value
*/
static async get(key) {
// Start cache clear if not started yet
if (!Settings.cacheCleaner) {
Settings.cacheCleaner = setInterval(() => {
log.debug("settings", "Cache Cleaner is just started.");
for (key in Settings.cacheList) {
if (Date.now() - Settings.cacheList[key].timestamp > 60 * 1000) {
log.debug("settings", "Cache Cleaner deleted: " + key);
delete Settings.cacheList[key];
}
}
}, 60 * 1000);
}
// Query from cache
if (key in Settings.cacheList) {
const v = Settings.cacheList[key].value;
log.debug("settings", `Get Setting (cache): ${key}: ${v}`);
return v;
}
let value = await R.getCell("SELECT `value` FROM setting WHERE `key` = ? ", [
key,
]);
try {
const v = JSON.parse(value);
log.debug("settings", `Get Setting: ${key}: ${v}`);
Settings.cacheList[key] = {
value: v,
timestamp: Date.now()
};
return v;
} catch (e) {
return value;
}
}
/**
* Sets the specified setting to specified value
* @param {string} key Key of setting to set
* @param {any} value Value to set to
* @param {?string} type Type of setting
* @returns {Promise<void>}
*/
static async set(key, value, type = null) {
let bean = await R.findOne("setting", " `key` = ? ", [
key,
]);
if (!bean) {
bean = R.dispense("setting");
bean.key = key;
}
bean.type = type;
bean.value = JSON.stringify(value);
await R.store(bean);
Settings.deleteCache([ key ]);
}
/**
* Get settings based on type
* @param {string} type The type of setting
* @returns {Promise<Bean>}
*/
static async getSettings(type) {
let list = await R.getAll("SELECT `key`, `value` FROM setting WHERE `type` = ? ", [
type,
]);
let result = {};
for (let row of list) {
try {
result[row.key] = JSON.parse(row.value);
} catch (e) {
result[row.key] = row.value;
}
}
return result;
}
/**
* Set settings based on type
* @param {string} type Type of settings to set
* @param {Object} data Values of settings
* @returns {Promise<void>}
*/
static async setSettings(type, data) {
let keyList = Object.keys(data);
let promiseList = [];
for (let key of keyList) {
let bean = await R.findOne("setting", " `key` = ? ", [
key
]);
if (bean == null) {
bean = R.dispense("setting");
bean.type = type;
bean.key = key;
}
if (bean.type === type) {
bean.value = JSON.stringify(data[key]);
promiseList.push(R.store(bean));
}
}
await Promise.all(promiseList);
Settings.deleteCache(keyList);
}
/**
*
* @param {string[]} keyList
*/
static deleteCache(keyList) {
for (let key of keyList) {
delete Settings.cacheList[key];
}
}
}
module.exports = {
Settings,
};

@ -202,6 +202,11 @@ module.exports.statusPageSocketHandler = (socket) => {
relationBean.weight = monitorOrder++;
relationBean.group_id = groupBean.id;
relationBean.monitor_id = monitor.id;
if (monitor.sendUrl !== undefined) {
relationBean.send_url = monitor.sendUrl;
}
await R.store(relationBean);
}

@ -7,6 +7,7 @@ const { R } = require("redbean-node");
const { log } = require("../src/util");
const Database = require("./database");
const util = require("util");
const { CacheableDnsHttpAgent } = require("./cacheable-dns-http-agent");
/**
* `module.exports` (alias: `server`) should be inside this class, in order to avoid circular dependency issue.
@ -49,7 +50,6 @@ class UptimeKumaServer {
log.info("server", "Creating express and socket.io instance");
this.app = express();
if (sslKey && sslCert) {
log.info("server", "Server Type: HTTPS");
this.httpServer = https.createServer({
@ -71,6 +71,8 @@ class UptimeKumaServer {
}
}
CacheableDnsHttpAgent.registerGlobalAgent();
this.io = new Server(this.httpServer);
}

@ -11,7 +11,10 @@ const mqtt = require("mqtt");
const chroma = require("chroma-js");
const { badgeConstants } = require("./config");
const mssql = require("mssql");
const { Client } = require("pg");
const postgresConParse = require("pg-connection-string").parse;
const { NtlmClient } = require("axios-ntlm");
const { Settings } = require("./settings");
// From ping-lite
exports.WIN = /^win/.test(process.platform);
@ -237,10 +240,6 @@ exports.dnsResolve = function (hostname, resolverServer, resolverPort, rrtype) {
*/
exports.mssqlQuery = function (connectionString, query) {
return new Promise((resolve, reject) => {
mssql.on("error", err => {
reject(err);
});
mssql.connect(connectionString).then(pool => {
return pool.request()
.query(query);
@ -254,23 +253,45 @@ exports.mssqlQuery = function (connectionString, query) {
});
};
/**
* Run a query on Postgres
* @param {string} connectionString The database connection string
* @param {string} query The query to validate the database with
* @returns {Promise<(string[]|Object[]|Object)>}
*/
exports.postgresQuery = function (connectionString, query) {
return new Promise((resolve, reject) => {
const config = postgresConParse(connectionString);
if (config.password === "") {
// See https://github.com/brianc/node-postgres/issues/1927
return reject(new Error("Password is undefined."));
}
const client = new Client({ connectionString });
client.connect();
return client.query(query)
.then(res => {
resolve(res);
})
.catch(err => {
reject(err);
})
.finally(() => {
client.end();
});
});
};
/**
* Retrieve value of setting based on key
* @param {string} key Key of setting to retrieve
* @returns {Promise<any>} Value
*/
exports.setting = async function (key) {
let value = await R.getCell("SELECT `value` FROM setting WHERE `key` = ? ", [
key,
]);
try {
const v = JSON.parse(value);
log.debug("util", `Get Setting: ${key}: ${v}`);
return v;
} catch (e) {
return value;
}
return await Settings.get(key);
};
/**
@ -281,70 +302,26 @@ exports.setting = async function (key) {
* @returns {Promise<void>}
*/
exports.setSetting = async function (key, value, type = null) {
let bean = await R.findOne("setting", " `key` = ? ", [
key,
]);
if (!bean) {
bean = R.dispense("setting");
bean.key = key;
}
bean.type = type;
bean.value = JSON.stringify(value);
await R.store(bean);
await Settings.set(key, value, type);
};
/**
* Get settings based on type
* @param {?string} type The type of setting
* @param {string} type The type of setting
* @returns {Promise<Bean>}
*/
exports.getSettings = async function (type) {
let list = await R.getAll("SELECT `key`, `value` FROM setting WHERE `type` = ? ", [
type,
]);
let result = {};
for (let row of list) {
try {
result[row.key] = JSON.parse(row.value);
} catch (e) {
result[row.key] = row.value;
}
}
return result;
return await Settings.getSettings(type);
};
/**
* Set settings based on type
* @param {?string} type Type of settings to set
* @param {string} type Type of settings to set
* @param {Object} data Values of settings
* @returns {Promise<void>}
*/
exports.setSettings = async function (type, data) {
let keyList = Object.keys(data);
let promiseList = [];
for (let key of keyList) {
let bean = await R.findOne("setting", " `key` = ? ", [
key
]);
if (bean == null) {
bean = R.dispense("setting");
bean.type = type;
bean.key = key;
}
if (bean.type === type) {
bean.value = JSON.stringify(data[key]);
promiseList.push(R.store(bean));
}
}
await Promise.all(promiseList);
await Settings.setSettings(type, data);
};
// ssl-checker by @dyaa
@ -437,7 +414,7 @@ exports.checkCertificate = function (res) {
/**
* Check if the provided status code is within the accepted ranges
* @param {string} status The status code to check
* @param {number} status The status code to check
* @param {string[]} acceptedCodes An array of accepted status codes
* @returns {boolean} True if status code within range, false otherwise
* @throws {Error} Will throw an error if the provided status code is not a valid range string or code string

@ -39,7 +39,27 @@
<font-awesome-icon v-if="editMode" icon="times" class="action remove me-3" @click="removeMonitor(group.index, monitor.index)" />
<Uptime :monitor="monitor.element" type="24" :pill="true" />
{{ monitor.element.name }}
<a
v-if="showLink(monitor)"
:href="monitor.element.url"
class="item-name"
target="_blank"
>
{{ monitor.element.name }}
</a>
<p v-else class="item-name"> {{ monitor.element.name }} </p>
<span
v-if="showLink(monitor, true)"
title="Toggle Clickable Link"
>
<font-awesome-icon
v-if="editMode"
:class="{'link-active': monitor.element.sendUrl, 'btn-link': true}"
icon="link" class="action me-3"
@click="toggleLink(group.index, monitor.index)"
/>
</span>
</div>
<div v-if="showTags" class="tags">
<Tag v-for="tag in monitor.element.tags" :key="tag" :item="tag" :size="'sm'" />
@ -113,6 +133,33 @@ export default {
removeMonitor(groupIndex, index) {
this.$root.publicGroupList[groupIndex].monitorList.splice(index, 1);
},
/**
* Toggle the value of sendUrl
* @param {number} groupIndex Index of group monitor is member of
* @param {number} index Index of monitor within group
*/
toggleLink(groupIndex, index) {
this.$root.publicGroupList[groupIndex].monitorList[index].sendUrl = !this.$root.publicGroupList[groupIndex].monitorList[index].sendUrl;
},
/**
* Should a link to the monitor be shown?
* Attempts to guess if a link should be shown based upon if
* sendUrl is set and if the URL is default or not.
* @param {Object} monitor Monitor to check
* @param {boolean} [ignoreSendUrl=false] Should the presence of the sendUrl
* property be ignored. This will only work in edit mode.
* @returns {boolean}
*/
showLink(monitor, ignoreSendUrl = false) {
// We must check if there are any elements in monitorList to
// prevent undefined errors if it hasn't been loaded yet
if (this.$parent.editMode && ignoreSendUrl && Object.keys(this.$root.monitorList).length) {
return this.$root.monitorList[monitor.element.id].type === "http" || this.$root.monitorList[monitor.element.id].type === "keyword";
}
return monitor.element.sendUrl && monitor.element.url && monitor.element.url !== "https://" && !this.editMode;
},
}
};
</script>
@ -131,6 +178,22 @@ export default {
min-height: 46px;
}
.item-name {
padding-left: 5px;
padding-right: 5px;
margin: 0;
display: inline-block;
}
.btn-link {
color: #bbbbbb;
margin-left: 5px;
}
.link-active {
color: $primary;
}
.flip-list-move {
transition: transform 0.5s;
}

@ -0,0 +1,13 @@
<template>
<div class="mb-3">
<label for="alertnow-webhook-url" class="form-label">{{ $t("Webhook URL") }}<span style="color: red;"><sup>*</sup></span></label>
<input id="alertnow-webhook-url" v-model="$parent.notification.alertNowWebhookURL" type="text" class="form-control" required>
<div class="form-text">
<span style="color: red;"><sup>*</sup></span>{{ $t("Required") }}
<i18n-t tag="p" keypath="aboutWebhooks" style="margin-top: 8px;">
<a href="https://service.opsnow.com/docs/alertnow/en/user-guide-alertnow-en.html#standard" target="_blank">{{ $t("here") }}</a>
</i18n-t>
</div>
</div>
</template>

@ -0,0 +1,9 @@
<template>
<div class="mb-3">
<label for="line-notify-access-token" class="form-label">{{ $t("Access Token") }}</label>
<input id="line-notify-access-token" v-model="$parent.notification.lineNotifyAccessToken" type="text" class="form-control" :required="true">
</div>
<i18n-t tag="div" keypath="wayToGetLineNotifyToken" class="form-text" style="margin-top: 8px;">
<a href="https://notify-bot.line.me/" target="_blank">https://notify-bot.line.me/</a>
</i18n-t>
</template>

@ -1,38 +1,40 @@
import STMP from "./SMTP.vue";
import Telegram from "./Telegram.vue";
import Alerta from "./Alerta.vue";
import AlertNow from "./AlertNow.vue";
import AliyunSMS from "./AliyunSms.vue";
import Apprise from "./Apprise.vue";
import Bark from "./Bark.vue";
import ClickSendSMS from "./ClickSendSMS.vue";
import DingDing from "./DingDing.vue";
import Discord from "./Discord.vue";
import Webhook from "./Webhook.vue";
import Signal from "./Signal.vue";
import Feishu from "./Feishu.vue";
import GoogleChat from "./GoogleChat.vue";
import Gorush from "./Gorush.vue";
import Gotify from "./Gotify.vue";
import Line from "./Line.vue";
import LineNotify from "./LineNotify.vue";
import LunaSea from "./LunaSea.vue";
import Matrix from "./Matrix.vue";
import Mattermost from "./Mattermost.vue";
import Ntfy from "./Ntfy.vue";
import Slack from "./Slack.vue";
import RocketChat from "./RocketChat.vue";
import Teams from "./Teams.vue";
import Pushover from "./Pushover.vue";
import Pushy from "./Pushy.vue";
import TechulusPush from "./TechulusPush.vue";
import Octopush from "./Octopush.vue";
import OneBot from "./OneBot.vue";
import PagerDuty from "./PagerDuty.vue";
import PromoSMS from "./PromoSMS.vue";
import ClickSendSMS from "./ClickSendSMS.vue";
import LunaSea from "./LunaSea.vue";
import Feishu from "./Feishu.vue";
import Apprise from "./Apprise.vue";
import Pushbullet from "./Pushbullet.vue";
import Line from "./Line.vue";
import Mattermost from "./Mattermost.vue";
import Matrix from "./Matrix.vue";
import AliyunSMS from "./AliyunSms.vue";
import DingDing from "./DingDing.vue";
import Bark from "./Bark.vue";
import PushDeer from "./PushDeer.vue";
import Pushover from "./Pushover.vue";
import Pushy from "./Pushy.vue";
import RocketChat from "./RocketChat.vue";
import SerwerSMS from "./SerwerSMS.vue";
import Signal from "./Signal.vue";
import Slack from "./Slack.vue";
import Stackfield from "./Stackfield.vue";
import STMP from "./SMTP.vue";
import Teams from "./Teams.vue";
import TechulusPush from "./TechulusPush.vue";
import Telegram from "./Telegram.vue";
import Webhook from "./Webhook.vue";
import WeCom from "./WeCom.vue";
import GoogleChat from "./GoogleChat.vue";
import PagerDuty from "./PagerDuty.vue";
import Gorush from "./Gorush.vue";
import Alerta from "./Alerta.vue";
import OneBot from "./OneBot.vue";
import PushDeer from "./PushDeer.vue";
/**
* Manage all notification form.
@ -40,41 +42,43 @@ import PushDeer from "./PushDeer.vue";
* @type { Record<string, any> }
*/
const NotificationFormList = {
"telegram": Telegram,
"webhook": Webhook,
"smtp": STMP,
"alerta": Alerta,
"AlertNow": AlertNow,
"AliyunSMS": AliyunSMS,
"apprise": Apprise,
"Bark": Bark,
"clicksendsms": ClickSendSMS,
"DingDing": DingDing,
"discord": Discord,
"teams": Teams,
"signal": Signal,
"Feishu": Feishu,
"GoogleChat": GoogleChat,
"gorush": Gorush,
"gotify": Gotify,
"line": Line,
"LineNotify": LineNotify,
"lunasea": LunaSea,
"matrix": Matrix,
"mattermost": Mattermost,
"ntfy": Ntfy,
"slack": Slack,
"rocket.chat": RocketChat,
"pushover": Pushover,
"pushy": Pushy,
"PushByTechulus": TechulusPush,
"octopush": Octopush,
"OneBot": OneBot,
"PagerDuty": PagerDuty,
"promosms": PromoSMS,
"clicksendsms": ClickSendSMS,
"lunasea": LunaSea,
"Feishu": Feishu,
"AliyunSMS": AliyunSMS,
"apprise": Apprise,
"pushbullet": Pushbullet,
"line": Line,
"mattermost": Mattermost,
"matrix": Matrix,
"DingDing": DingDing,
"Bark": Bark,
"PushByTechulus": TechulusPush,
"PushDeer": PushDeer,
"pushover": Pushover,
"pushy": Pushy,
"rocket.chat": RocketChat,
"serwersms": SerwerSMS,
"signal": Signal,
"slack": Slack,
"smtp": STMP,
"stackfield": Stackfield,
"teams": Teams,
"telegram": Telegram,
"webhook": Webhook,
"WeCom": WeCom,
"GoogleChat": GoogleChat,
"PagerDuty": PagerDuty,
"gorush": Gorush,
"alerta": Alerta,
"OneBot": OneBot,
"PushDeer": PushDeer,
};
export default NotificationFormList;

@ -4,6 +4,11 @@
<object class="my-4" width="200" height="200" data="/icon.svg" />
<div class="fs-4 fw-bold">Uptime Kuma</div>
<div>{{ $t("Version") }}: {{ $root.info.version }}</div>
<div class="frontend-version">{{ $t("Frontend Version") }}: {{ $root.frontendVersion }}</div>
<div v-if="!$root.isFrontendBackendVersionMatched" class="alert alert-warning mt-4" role="alert">
{{ $t("Frontend Version do not match backend version!") }}
</div>
<div class="my-3 update-link"><a href="https://github.com/louislam/uptime-kuma/releases" target="_blank" rel="noopener">{{ $t("Check Update On GitHub") }}</a></div>
@ -46,6 +51,16 @@ export default {
}
.update-link {
font-size: 0.8em;
}
.frontend-version {
font-size: 0.9em;
color: #cccccc;
.dark & {
color: #333333;
}
}
</style>

@ -91,6 +91,51 @@
{{ $t("For example: nginx, Apache and Traefik.") }} <br />
{{ $t("Please read") }} <a href="https://github.com/louislam/uptime-kuma/wiki/Reverse-Proxy" target="_blank">https://github.com/louislam/uptime-kuma/wiki/Reverse-Proxy</a>.
</div>
<h4 class="my-4">{{ $t("HTTP Headers") }}</h4>
<div class="my-3">
<label class="form-label">
{{ $t("Trust Proxy") }}
</label>
<div class="form-check">
<input
id="trustProxyYes"
v-model="settings.trustProxy"
class="form-check-input"
type="radio"
name="trustProxyYes"
:value="true"
required
/>
<label class="form-check-label" for="trustProxyYes">
{{ $t("Yes") }}
</label>
</div>
<div class="form-check">
<input
id="trustProxyNo"
v-model="settings.trustProxy"
class="form-check-input"
type="radio"
name="flexRadioDefault"
:value="false"
required
/>
<label class="form-check-label" for="trustProxyNo">
{{ $t("No") }}
</label>
</div>
<div class="form-text">
{{ $t("trustProxyDescription") }}
</div>
</div>
<div>
<button class="btn btn-primary" type="submit" @click="saveSettings()">
{{ $t("Save") }}
</button>
</div>
</div>
</template>
@ -113,6 +158,12 @@ export default {
settings() {
return this.$parent.$parent.$parent.settings;
},
saveSettings() {
return this.$parent.$parent.$parent.saveSettings;
},
settingsLoaded() {
return this.$parent.$parent.$parent.settingsLoaded;
},
},
watch: {

@ -9,7 +9,9 @@ const languageList = {
"nl-NL": "Nederlands",
"nb-NO": "Norsk",
"es-ES": "Español",
"eu": "Euskara",
"fa": "Farsi",
"pt-PT": "Português (Portugal)",
"pt-BR": "Português (Brasileiro)",
"fr-FR": "Français (France)",
"hu": "Magyar",

@ -81,6 +81,7 @@ library.add(
faUndo,
faPlusCircle,
faAngleDown,
faLink,
);
export { FontAwesomeIcon };

@ -536,4 +536,5 @@ export default {
Domain: "Домейн",
Workstation: "Работна станция",
disableCloudflaredNoAuthMsg: "Тъй като сте в режим \"No Auth mode\", парола не се изисква.",
wayToGetLineNotifyToken: "Може да получите токен код за достъп от {0}",
};

@ -453,6 +453,8 @@ export default {
"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.": "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.",
"HTTP Headers": "HTTP Headers",
"Trust Proxy": "Trust Proxy",
"Other Software": "Other Software",
"For example: nginx, Apache and Traefik.": "For example: nginx, Apache and Traefik.",
"Please read": "Please read",
@ -536,4 +538,6 @@ export default {
"Domain": "Domain",
"Workstation": "Workstation",
disableCloudflaredNoAuthMsg: "You are in No Auth mode, password is not require.",
trustProxyDescription: "Trust 'X-Forwarded-*' headers. If you want to get the correct client IP and your Uptime Kuma is behind such as Nginx or Apache, you should enable this.",
wayToGetLineNotifyToken: "You can get an access token from {0}",
};

@ -7,8 +7,8 @@ export default {
maxRedirectDescription: "Número máximo de direcciones a seguir. Establecer a 0 para deshabilitar.",
acceptedStatusCodesDescription: "Seleccionar los códigos de estado que se consideran como respuesta exitosa.",
passwordNotMatchMsg: "La contraseña repetida no coincide.",
notificationDescription: "Por favor asigne una notificación a el/los monitor(es) para hacerlos funcional(es).",
keywordDescription: "Palabra clave en HTML plano o respuesta JSON y es sensible a mayúsculas",
notificationDescription: "Por favor asigna una notificación a el/los monitor(es) para hacerlos funcional(es).",
keywordDescription: "Palabra clave en HTML plano o respuesta JSON, es sensible a mayúsculas",
pauseDashboardHome: "Pausado",
deleteMonitorMsg: "¿Seguro que quieres eliminar este monitor?",
deleteNotificationMsg: "¿Seguro que quieres eliminar esta notificación para todos los monitores?",
@ -35,7 +35,7 @@ export default {
Pause: "Pausar",
Name: "Nombre",
Status: "Estado",
DateTime: "Fecha y Hora",
DateTime: "Fecha y hora",
Message: "Mensaje",
"No important events": "No hay eventos importantes",
Resume: "Reanudar",
@ -50,7 +50,7 @@ export default {
"-hour": "-hora",
Response: "Respuesta",
Ping: "Ping",
"Monitor Type": "Tipo de Monitor",
"Monitor Type": "Tipo de monitor",
Keyword: "Palabra clave",
"Friendly Name": "Nombre sencillo",
URL: "URL",
@ -60,11 +60,11 @@ export default {
Retries: "Reintentos",
Advanced: "Avanzado",
"Upside Down Mode": "Modo invertido",
"Max. Redirects": "Redirecciones Máximas",
"Max. Redirects": "Redirecciones máximas",
"Accepted Status Codes": "Códigos de estado aceptados",
Save: "Guardar",
Notifications: "Notificaciones",
"Not available, please setup.": "No disponible, por favor configúrelo.",
"Not available, please setup.": "No disponible, por favor configúralo.",
"Setup Notification": "Configurar notificación",
Light: "Claro",
Dark: "Oscuro",
@ -82,8 +82,8 @@ export default {
"New Password": "Nueva contraseña",
"Repeat New Password": "Repetir nueva contraseña",
"Update Password": "Actualizar contraseña",
"Disable Auth": "Deshabilitar Autenticación",
"Enable Auth": "Habilitar Autenticación",
"Disable Auth": "Deshabilitar autenticación",
"Enable Auth": "Habilitar autenticación",
"disableauth.message1": "Seguro que deseas <strong>deshabilitar la autenticación</strong>?",
"disableauth.message2": "Es para <strong>quien implementa autenticación de terceros</strong> ante Uptime Kuma como por ejemplo Cloudflare Access.",
"Please use this option carefully!": "Por favor usar con cuidado.",
@ -104,32 +104,32 @@ export default {
Test: "Test",
"Certificate Info": "Información del certificado",
"Resolver Server": "Servidor de resolución",
"Resource Record Type": "Tipo de Registro",
"Resource Record Type": "Tipo de registro",
"Last Result": "Último resultado",
"Create your admin account": "Crea tu cuenta de administrador",
"Repeat Password": "Repetir contraseña",
respTime: "Tiempo de resp. (ms)",
notAvailableShort: "N/A",
Create: "Crear",
clearEventsMsg: "¿Está seguro de que desea eliminar todos los eventos de este monitor?",
clearHeartbeatsMsg: "¿Está seguro de que desea eliminar todos los latidos de este monitor?",
confirmClearStatisticsMsg: "¿Está seguro de que desea eliminar TODAS las estadísticas?",
"Clear Data": "Borrar Datos",
clearEventsMsg: "¿Estás seguro de que deseas eliminar todos los eventos de este monitor?",
clearHeartbeatsMsg: "¿Estás seguro de que deseas eliminar todos los latidos de este monitor?",
confirmClearStatisticsMsg: "¿Estás seguro de que deseas eliminar TODAS las estadísticas?",
"Clear Data": "Borrar datos",
Events: "Eventos",
Heartbeats: "Latidos",
"Auto Get": "Obtener automáticamente",
enableDefaultNotificationDescription: "Para cada nuevo monitor, esta notificación estará habilitada de forma predeterminada. Aún puede deshabilitar la notificación por separado para cada monitor.",
enableDefaultNotificationDescription: "Para cada nuevo monitor, esta notificación estará habilitada de forma predeterminada. Aún puedes deshabilitar la notificación por separado para cada monitor.",
"Default enabled": "Habilitado por defecto",
"Also apply to existing monitors": "También se aplica a monitores existentes",
Export: "Exportar",
Import: "Importar",
backupDescription: "Puede hacer una copia de seguridad de todos los monitores y todas las notificaciones en un archivo JSON.",
backupDescription: "Puedes hacer una copia de seguridad de todos los monitores y todas las notificaciones en un archivo JSON.",
backupDescription2: "PD: el historial y los datos de eventos no están incluidos.",
backupDescription3: "Los datos confidenciales, como los tokens de notificación, se incluyen en el archivo de exportación. Guárdelo con cuidado.",
alertNoFile: "Seleccione un archivo para importar.",
alertWrongFileType: "Seleccione un archivo JSON.",
twoFAVerifyLabel: "Ingrese su token para verificar que 2FA está funcionando",
tokenValidSettingsMsg: "¡El token es válido! Ahora puede guardar la configuración de 2FA.",
backupDescription3: "Los datos confidenciales, como los tokens de notificación, se incluyen en el archivo de exportación. Guárdalo con cuidado.",
alertNoFile: "Selecciona un archivo para importar.",
alertWrongFileType: "Selecciona un archivo JSON.",
twoFAVerifyLabel: "Ingresa tu token para verificar que 2FA está funcionando",
tokenValidSettingsMsg: "¡El token es válido! Ahora puedes guardar la configuración de 2FA.",
confirmEnableTwoFAMsg: "¿Estás seguro de que quieres habilitar 2FA?",
confirmDisableTwoFAMsg: "¿Estás seguro de que quieres desactivar 2FA?",
"Apply on all existing monitors": "Aplicar en todos los monitores existentes",
@ -145,19 +145,19 @@ export default {
"Show URI": "Mostrar URI",
"Clear all statistics": "Borrar todas las estadísticas",
retryCheckEverySecond: "Reintentar cada {0} segundo.",
importHandleDescription: "Elija 'Omitir existente' si desea omitir todos los monitores o notificaciones con el mismo nombre. 'Sobrescribir' eliminará todos los monitores y notificaciones existentes.",
confirmImportMsg: "¿Estás seguro de importar la copia de seguridad? Asegúrese de haber seleccionado la opción de importación correcta.",
importHandleDescription: "Elige 'Omitir existente' si deseas omitir todos los monitores o notificaciones con el mismo nombre. 'Sobrescribir' eliminará todos los monitores y notificaciones existentes.",
confirmImportMsg: "¿Estás seguro de importar la copia de seguridad? Asegúrate de haber seleccionado la opción de importación correcta.",
"Heartbeat Retry Interval": "Intervalo de reintento de latido",
"Import Backup": "Importar copia de seguridad",
"Export Backup": "Exportar copia de seguridad",
"Skip existing": "Omitir existente",
Overwrite: "Sobrescribir",
Options: "Opciones",
"Keep both": "Mantén ambos",
"Keep both": "Manténer ambos",
Tags: "Etiquetas",
"Add New below or Select...": "Agregar nuevo a continuación o Seleccionar...",
"Tag with this name already exist.": "La etiqueta con este nombre ya existe.",
"Tag with this value already exist.": "La etiqueta con este valor ya existe.",
"Add New below or Select...": "Agregar nuevo a continuación o seleccionar...",
"Tag with this name already exist.": "Una etiqueta con este nombre ya existe.",
"Tag with this value already exist.": "Una etiqueta con este valor ya existe.",
color: "color",
"value (optional)": "valor (opcional)",
Gray: "Gris",
@ -172,17 +172,17 @@ export default {
"Avg. Ping": "Ping promedio",
"Avg. Response": "Respuesta promedio",
"Entry Page": "Página de entrada",
statusPageNothing: "No hay nada aquí, agregue un grupo o un monitor.",
statusPageNothing: "No hay nada aquí, agrega un grupo o un monitor.",
"No Services": "Sin servicio",
"All Systems Operational": "Todos los sistemas están operativos",
"Partially Degraded Service": "Servicio parcialmente degradado",
"Degraded Service": "Servicio degradado",
"Add Group": "Agregar Grupo",
"Add Group": "Agregar grupo",
"Add a monitor": "Agregar un monitor",
"Edit Status Page": "Editar página de estado",
"Go to Dashboard": "Ir al panel de control",
"Status Page": "Página de estado",
"Status Pages": "Página de estado",
"Status Pages": "Páginas de estado",
telegram: "Telegram",
webhook: "Webhook",
smtp: "Email (SMTP)",
@ -205,5 +205,5 @@ export default {
clearDataOlderThan: "Mantener los datos del historial del monitor durante {0} días.",
records: "registros",
"One record": "Un registro",
steamApiKeyDescription: "Para monitorear un servidor de juegos de Steam, necesita una clave Steam Web-API. Puede registrar su clave API aquí: ",
steamApiKeyDescription: "Para monitorear un servidor de juegos de Steam, necesitas una clave Steam Web-API. Puedes registrar tu clave API aquí: ",
};

@ -0,0 +1,539 @@
export default {
languageName: "Euskara",
checkEverySecond: "Egiaztatu {0} segunduro",
retryCheckEverySecond: "Errepikatu {0} segunduro",
retriesDescription: "Zerbitzua erorita markatu eta jakinarazpena bidali aurretik egindako saiakera kopuru maximoa",
ignoreTLSError: "Ezikusiarena egin TLS/SSL erroreei HTTPS webguneetan",
upsideDownModeDescription: "Alderantzizkatu erortze egoera. Zerbitzua martxan badago, ERORITA markatuko du.",
maxRedirectDescription: "Jarraitu beharreko berbideratze kopuru maximoa. Jarri 0 berbideratzeak desgaitzeko.",
acceptedStatusCodesDescription: "Hautatu erantzun ona kontsideratzen diren egoera kodeak.",
passwordNotMatchMsg: "Errepikatutako pasahitza ez dator bat.",
notificationDescription: "Jakinarazpenak monitorizazio funtzio bati asignatu behar zaizkio.",
keywordDescription: "Bilatu gako-hitza HTML edo JSON erantzunean. Bilaketan maiuskulak kontuan hartzen dira.",
pauseDashboardHome: "Gelditu",
deleteMonitorMsg: "Ziur zaude monitorizazio hau ezabatu nahi duzula?",
deleteNotificationMsg: "Ziur zaude jakinarazpen hau monitorizazio guztientzat ezabatu nahi duzula?",
dnsPortDescription: "DNS zerbitzari portua. Defektuz 53. Nahi duzunean aldatu dezakezu portua.",
resolverserverDescription: "Cloudflare zerbitzari lehenetsia da. Edozein unetan alda dezakezu ebazteko zerbitzaria.",
rrtypeDescription: "Hautatu kontrolatu nahi duzun RR mota",
enableDefaultNotificationDescription: "Jakinarazpen hau monitore berrientzat gaituko da defektuz. Baina monitorizazio bakoitzarentzat jakinarazpena desgaitu dezakezu.",
pauseMonitorMsg: "Ziur zaude gelditu egin nahi duzula?",
clearEventsMsg: "Ziur zaude monitorizazio honen gertaera guztiak ezabatu nahi dituzula?",
clearHeartbeatsMsg: "Ziur zaude monitorizazio honen pultsu guztiak ezabatu nahi dituzula?",
confirmClearStatisticsMsg: "Ziur zaude estatistika GUZTIAK ezabatu nahi dituzula?",
importHandleDescription: "Aukeratu 'existitzen bada', izen bereko monitore edo jakinarazpen bakoitza saltatu nahi baduzu. Lehendik dauden kontrol eta jakinarazpen guztiak ezabatuko ditu 'Gainidatzi' aukerak.",
confirmImportMsg: "Ziur zaude segurtasun-kopia inportatu nahi duzula? Egiaztatu inportatzeko aukera zuzena hautatu duzula.",
twoFAVerifyLabel: "Sartu zure tokena 2FA egiaztatzeko:",
tokenValidSettingsMsg: "Tokenak balio du! Orain 2FA konfigurazioa gorde dezakezu.",
confirmEnableTwoFAMsg: "Ziur zaude 2FA gaitu nahi duzula?",
confirmDisableTwoFAMsg: "Ziur zaude 2FA desgaitu nahi duzula?",
Settings: "Ezarpenak",
Dashboard: "Arbela",
"New Update": "Eguneraketa berria",
Language: "Hizkuntza",
Appearance: "Itxura",
Theme: "Gaia",
General: "Orokorra",
"Primary Base URL": "Oinarrizkoa URL",
Version: "Bertsioa",
"Check Update On GitHub": "Egiaztatu eguneraketa GitHuben",
List: "Zerrenda",
Add: "Gehitu",
"Add New Monitor": "Gehitu monitorizazio berria",
"Quick Stats": "Estatistika azkarrak",
Up: "Erabilgarri",
Down: "Erorita",
Pending: "Zain",
Unknown: "Ezezaguna",
Pause: "Gelditu",
Name: "Izena",
Status: "Egoera",
DateTime: "Data eta ordua",
Message: "Mezua",
"No important events": "Gertaera garrantzitsurik ez",
Resume: "Jarraitu",
Edit: "Editatu",
Delete: "Ezabatu",
Current: "Unekoa",
Uptime: "Martxan",
"Cert Exp.": "Ziurtagiri iraun.",
day: "egun | egun",
"-day": "-egun",
hour: "ordua",
"-hour": "-ordu",
Response: "Erantzuna",
Ping: "Ping",
"Monitor Type": "Monitorizazio mota",
Keyword: "Gakohitza",
"Friendly Name": "Izen xumea",
URL: "URLa",
Hostname: "Ostalari izena",
Port: "Portua",
"Heartbeat Interval": "Pultsu interbaloak",
Retries: "Errepikapenak",
"Heartbeat Retry Interval": "Pultsu errepikatze interbaloak",
Advanced: "Aurreratua",
"Upside Down Mode": "Alderantzizkako modua",
"Max. Redirects": "Berbideratze max.",
"Accepted Status Codes": "Onartutako egoera kodeak",
"Push URL": "Push URLa",
needPushEvery: "URL hau {0} segunduro deitu beharko zenuke.",
pushOptionalParams: "Hautazko parametroak: {0}",
Save: "Gorde",
Notifications: "Jakinarazpenak",
"Not available, please setup.": "Ez dago eskuragarri, ezarri mesedez.",
"Setup Notification": "Ezarri jakinarazpenak",
Light: "Argia",
Dark: "Iluna",
Auto: "Auto",
"Theme - Heartbeat Bar": "Gaia - Pultsu barra",
Normal: "Normala",
Bottom: "Behean",
None: "Bat ere ez",
Timezone: "Timezone",
"Search Engine Visibility": "Bilatzaile ikurgarritasuna",
"Allow indexing": "Onartu indexatzea",
"Discourage search engines from indexing site": "Discourage search engines from indexing site",
"Change Password": "Aldatu pasahitza",
"Current Password": "Uneko pasahitza",
"New Password": "Pasahitz berria",
"Repeat New Password": "Errepikatu pasahitz berria",
"Update Password": "Eguneratu pasahitza",
"Disable Auth": "Desgaitu Auth",
"Enable Auth": "Gaitu Auth",
"disableauth.message1": "Ziur zaude <strong>autentifikazioa desgaitu</strong> nahi duzula?",
"disableauth.message2": "Egoera jakin batzuetarako diseinatuta dago, Uptime Kumaren <strong>aurrean hirugarrengo autentifikazio batzuek jartzeko</strong> (Cloudflare Access, Authelia edo beste autentifikazio-mekanismo batzuk).",
"Please use this option carefully!": "Mesedez, kontuz erabili aukera hau!",
Logout: "Saioa amaitu",
Leave: "Utzi",
"I understand, please disable": "Ulertzen dut, mesedez desgaitu",
Confirm: "Baieztatu",
Yes: "Bai",
No: "Ez",
Username: "Erabiltzailea",
Password: "Pasahitza",
"Remember me": "Gogora nazazu",
Login: "Saioa hasi",
"No Monitors, please": "Monitorizaziorik ez, mesedez",
"add one": "gehitu bat",
"Notification Type": "Jakinarazpen mota",
Email: "Emaila",
Test: "Testa",
"Certificate Info": "Ziurtagiri informazioa",
"Resolver Server": "Ebazpen-zerbitzaria",
"Resource Record Type": "Baliabideen erregistro mota",
"Last Result": "Azken emaitza",
"Create your admin account": "Sortu zure admin kontua",
"Repeat Password": "Errepikatu pasahitza",
"Import Backup": "segurtasun-kopia inportatu",
"Export Backup": "segurtasun-kopia esportatu",
Export: "Esportatu",
Import: "Inportatu",
respTime: "Erantz. denbora (ms)",
notAvailableShort: "N/A",
"Default enabled": "Lehenetsia gaituta",
"Apply on all existing monitors": "Aplikatu existitzen diren monitorizazio guztietan",
Create: "Sortu",
"Clear Data": "Garbitu datuak",
Events: "Gertaerak",
Heartbeats: "Pultsuak",
"Auto Get": "Auto Get",
backupDescription: "Monitore eta jakinarazpen guztien segurtasun-kopiak egin ditzakezu JSON fitxategi batean.",
backupDescription2: "Oharra: ez dira historia eta gertaeren datuak sartzen.",
backupDescription3: "Datu sentikorrak, hala nola jakinarazpen tokenak, esportazio-fitxategian sartzen dira; mesedez, gorde esportazioa modu seguruan.",
alertNoFile: "Mesedez hautatu inportatzeko fitxategia.",
alertWrongFileType: "Mesedez hautatu JSON fitxategia.",
"Clear all statistics": "Garbitu estatistika guztiak",
"Skip existing": "Saltatu existitzen bada",
Overwrite: "Gainidatzi",
Options: "Aukerak",
"Keep both": "Biak mantendu",
"Verify Token": "Egiaztatu Tokena",
"Setup 2FA": "Ezarri 2FA",
"Enable 2FA": "Gaitu 2FA",
"Disable 2FA": "Desgaitu 2FA",
"2FA Settings": "2FA ezarpenak",
"Two Factor Authentication": "Bi aldetako autentifikazioa (2FA)",
Active: "Aktibo",
Inactive: "Inaktibo",
Token: "Tokena",
"Show URI": "Erakutsi URIa",
Tags: "Etiketak",
"Add New below or Select...": "Gehitu beste bat behean edo hautatu...",
"Tag with this name already exist.": "Izen hau duen etiketa dagoeneko badago.",
"Tag with this value already exist.": "Balio hau duen etiketa dagoeneko badago.",
color: "kolorea",
"value (optional)": "balioa (hautazkoa)",
Gray: "Grisa",
Red: "Gorria",
Orange: "Naranja",
Green: "Berdea",
Blue: "Urdina",
Indigo: "Indigo",
Purple: "Morea",
Pink: "Arrosa",
"Search...": "Bilatu...",
"Avg. Ping": "Batazbesteko Pinga",
"Avg. Response": "Batazbesteko erantzuna",
"Entry Page": "Sarrera orria",
statusPageNothing: "Ezer ere ez hemen, mesedez gehitu taldea edo monitorizazioa.",
"No Services": "Zerbitzurik ez",
"All Systems Operational": "Sistema guztiak martxan",
"Partially Degraded Service": "Zerbitzu partzialki degradatua",
"Degraded Service": "Zerbitzu degradatua",
"Add Group": "Gehitu taldea",
"Add a monitor": "Gehitu monitorizazioa",
"Edit Status Page": "Editatu egoera orria",
"Go to Dashboard": "Joan arbelera",
"Status Page": "Egoera orria",
"Status Pages": "Egoera orriak",
defaultNotificationName: "Nire {notification} Alerta ({number})",
here: "Hemen",
Required: "Beharrezkoa",
telegram: "Telegram",
"Bot Token": "Bot Tokena",
wayToGetTelegramToken: "You can get a token from {0}.",
"Chat ID": "Txat IDa",
supportTelegramChatID: "Support Direct Chat / Group / Channel's Chat ID",
wayToGetTelegramChatID: "You can get your chat ID by sending a message to the bot and going to this URL to view the chat_id:",
"YOUR BOT TOKEN HERE": "YOUR BOT TOKEN HERE",
chatIDNotFound: "Chat ID is not found; please send a message to this bot first",
webhook: "Webhook",
"Post URL": "Bidalketa URLa",
"Content Type": "Eduki mota",
webhookJsonDesc: "{0} is good for any modern HTTP servers such as Express.js",
webhookFormDataDesc: "{multipart} is good for PHP. The JSON will need to be parsed with {decodeFunction}",
smtp: "Emaila (SMTP)",
secureOptionNone: "Bat ere ez / STARTTLS (25, 587)",
secureOptionTLS: "TLS (465)",
"Ignore TLS Error": "Ignore TLS Error",
"From Email": "Email honetatik",
emailCustomSubject: "Pertsonalizatutako gaia",
"To Email": "Email honetara",
smtpCC: "CC",
smtpBCC: "BCC",
discord: "Discord",
"Discord Webhook URL": "Discord Webhook URL",
wayToGetDiscordURL: "You can get this by going to Server Settings -> Integrations -> Create Webhook",
"Bot Display Name": "Bot Display Name",
"Prefix Custom Message": "Prefix Custom Message",
"Hello @everyone is...": "Hello {'@'}everyone is...",
teams: "Microsoft Teams",
"Webhook URL": "Webhook URL",
wayToGetTeamsURL: "You can learn how to create a webhook URL {0}.",
signal: "Signal",
Number: "Zenbakia",
Recipients: "Recipients",
needSignalAPI: "You need to have a signal client with REST API.",
wayToCheckSignalURL: "You can check this URL to view how to set one up:",
signalImportant: "IMPORTANT: You cannot mix groups and numbers in recipients!",
gotify: "Gotify",
"Application Token": "Aplikazio tokena",
"Server URL": "Zerbitzari URLa",
Priority: "Lehentasuna",
slack: "Slack",
"Icon Emoji": "Emoji ikonoa",
"Channel Name": "Kanalaren izena",
"Uptime Kuma URL": "Uptime Kuma URL",
aboutWebhooks: "More info about Webhooks on: {0}",
aboutChannelName: "Enter the channel name on {0} Channel Name field if you want to bypass the Webhook channel. Ex: #other-channel",
aboutKumaURL: "If you leave the Uptime Kuma URL field blank, it will default to the Project GitHub page.",
emojiCheatSheet: "Emoji cheat sheet: {0}",
"rocket.chat": "Rocket.Chat",
pushover: "Pushover",
pushy: "Pushy",
PushByTechulus: "Push by Techulus",
octopush: "Octopush",
promosms: "PromoSMS",
clicksendsms: "ClickSend SMS",
lunasea: "LunaSea",
apprise: "Apprise (Support 50+ Notification services)",
GoogleChat: "Google Chat (Google Workspace only)",
pushbullet: "Pushbullet",
line: "Line Messenger",
mattermost: "Mattermost",
"User Key": "Erabiltzaile gakoa",
Device: "Gailua",
"Message Title": "Mezuaren izenburua",
"Notification Sound": "Jakinarazpen soinua",
"More info on:": "More info on: {0}",
pushoverDesc1: "Emergency priority (2) has default 30 second timeout between retries and will expire after 1 hour.",
pushoverDesc2: "If you want to send notifications to different devices, fill out Device field.",
"SMS Type": "SMS mota",
octopushTypePremium: "Premium (Fast - recommended for alerting)",
octopushTypeLowCost: "Low Cost (Slow - sometimes blocked by operator)",
checkPrice: "Check {0} prices:",
apiCredentials: "API credentials",
octopushLegacyHint: "Do you use the legacy version of Octopush (2011-2020) or the new version?",
"Check octopush prices": "Check octopush prices {0}.",
octopushPhoneNumber: "Phone number (intl format, eg : +33612345678) ",
octopushSMSSender: "SMS Sender Name : 3-11 alphanumeric characters and space (a-zA-Z0-9)",
"LunaSea Device ID": "LunaSea Device ID",
"Apprise URL": "Apprise URL",
"Example:": "Adibidez: {0}",
"Read more:": "Irakurri gehiago: {0}",
"Status:": "Egoera: {0}",
"Read more": "Irakurri gehiago",
appriseInstalled: "Apprise instalatuta.",
appriseNotInstalled: "Apprise ez dago instalatuta. {0}",
"Access Token": "Access Token",
"Channel access token": "Channel access token",
"Line Developers Console": "Line Developers Console",
lineDevConsoleTo: "Line Developers Console - {0}",
"Basic Settings": "Oinarrizko ezarpenak",
"User ID": "Erabiltzaile ID",
"Messaging API": "Messaging API",
wayToGetLineChannelToken: "First access the {0}, create a provider and channel (Messaging API), then you can get the channel access token and user ID from the above mentioned menu items.",
"Icon URL": "Ikono URL",
aboutIconURL: "You can provide a link to a picture in \"Icon URL\" to override the default profile picture. Will not be used if Icon Emoji is set.",
aboutMattermostChannelName: "You can override the default channel that the Webhook posts to by entering the channel name into \"Channel Name\" field. This needs to be enabled in the Mattermost Webhook settings. Ex: #other-channel",
matrix: "Matrix",
promosmsTypeEco: "SMS ECO - cheap but slow and often overloaded. Limited only to Polish recipients.",
promosmsTypeFlash: "SMS FLASH - Message will automatically show on recipient device. Limited only to Polish recipients.",
promosmsTypeFull: "SMS FULL - Premium tier of SMS, You can use your Sender Name (You need to register name first). Reliable for alerts.",
promosmsTypeSpeed: "SMS SPEED - Highest priority in system. Very quick and reliable but costly (about twice of SMS FULL price).",
promosmsPhoneNumber: "Phone number (for Polish recipient You can skip area codes)",
promosmsSMSSender: "SMS Sender Name : Pre-registred name or one of defaults: InfoSMS, SMS Info, MaxSMS, INFO, SMS",
"Feishu WebHookUrl": "Feishu WebHookURL",
matrixHomeserverURL: "Hasiera zerbitzari URL (with http(s):// and optionally port)",
"Internal Room Id": "Internal Room ID",
matrixDesc1: "You can find the internal room ID by looking in the advanced section of the room settings in your Matrix client. It should look like !QMdRCpUIfLwsfjxye6:home.server.",
matrixDesc2: "It is highly recommended you create a new user and do not use your own Matrix user's access token as it will allow full access to your account and all the rooms you joined. Instead, create a new user and only invite it to the room that you want to receive the notification in. You can get the access token by running {0}",
Method: "Metodoa",
Body: "Gorputza",
Headers: "Goiburuak",
PushUrl: "Push URL",
HeadersInvalidFormat: "The request headers are not valid JSON: ",
BodyInvalidFormat: "The request body is not valid JSON: ",
"Monitor History": "Monitorizazio Historia",
clearDataOlderThan: "Keep monitor history data for {0} days.",
PasswordsDoNotMatch: "Pasahitzak ez datoz bat.",
records: "records",
"One record": "One record",
steamApiKeyDescription: "For monitoring a Steam Game Server you need a Steam Web-API key. You can register your API key here: ",
"Current User": "Uneko erabiltzailea",
topic: "Topic",
topicExplanation: "MQTT topic to monitor",
successMessage: "Arrakasta mezua",
successMessageExplanation: "MQTT message that will be considered as success",
recent: "Duela gutxikoa",
Done: "Egina",
Info: "Info",
Security: "Segurtasuna",
"Steam API Key": "Steam API Giltza",
"Shrink Database": "Shrink Datubasea",
"Pick a RR-Type...": "Pick a RR-Type...",
"Pick Accepted Status Codes...": "Hautatu onartutako egoera kodeak...",
Default: "Lehenetsia",
"HTTP Options": "HTTP Aukerak",
"Create Incident": "Sortu inzidentzia",
Title: "Titulua",
Content: "Edukia",
Style: "Estiloa",
info: "info",
warning: "kontuz",
danger: "arriskua",
error: "errorea",
critical: "kritikoa",
primary: "oinarrizkoa",
light: "argia",
dark: "iluna",
Post: "Post",
"Please input title and content": "Mesedez sartu titulua eta edukia",
Created: "Sortuta",
"Last Updated": "Azken eguneratzea",
Unpin: "Unpin",
"Switch to Light Theme": "Aldatu gai argira",
"Switch to Dark Theme": "Aldatu gai ilunera",
"Show Tags": "Erakutsi etiketak",
"Hide Tags": "Ezkutatu etiketak",
Description: "Deskribapena",
"No monitors available.": "Monitorizaziorik eskuragarri ez.",
"Add one": "Gehitu bat",
"No Monitors": "Monitorizaziorik ez",
"Untitled Group": "Titulurik gabeko taldea",
Services: "Zerbitzuak",
Discard: "Baztertu",
Cancel: "Ezeztatu",
"Powered by": "Honekin egina:",
shrinkDatabaseDescription: "Trigger database VACUUM for SQLite. If your database is created after 1.10.0, AUTO_VACUUM is already enabled and this action is not needed.",
serwersms: "SerwerSMS.pl",
serwersmsAPIUser: "API erabiltzailea (webapi_ aurre-hizkia barne)",
serwersmsAPIPassword: "API pasahitza",
serwersmsPhoneNumber: "Telefono zenbakia",
serwersmsSenderName: "SMS bidaltzaile izena (registered via customer portal)",
stackfield: "Stackfield",
Customize: "Pertsonalizatu",
"Custom Footer": "Oin pertsonalizatua",
"Custom CSS": "CSS pertsonalizatua",
smtpDkimSettings: "DKIM ezarpenak",
smtpDkimDesc: "Please refer to the Nodemailer DKIM {0} for usage.",
documentation: "dokumentazioa",
smtpDkimDomain: "Domeinu izena",
smtpDkimKeySelector: "Gako hautatzailea",
smtpDkimPrivateKey: "Gako pribatua",
smtpDkimHashAlgo: "Hash algoritmoa (hautazkoa)",
smtpDkimheaderFieldNames: "Header Keys to sign (Optional)",
smtpDkimskipFields: "Header Keys not to sign (Optional)",
wayToGetPagerDutyKey: "You can get this by going to Service -> Service Directory -> (Select a service) -> Integrations -> Add integration. Here you can search for \"Events API V2\". More info {0}",
"Integration Key": "Integration Key",
"Integration URL": "Integrazio URLa",
"Auto resolve or acknowledged": "Auto resolve or acknowledged",
"do nothing": "ez egin ezer",
"auto acknowledged": "auto acknowledged",
"auto resolve": "auto resolve",
gorush: "Gorush",
alerta: "Alerta",
alertaApiEndpoint: "API Endpoint",
alertaEnvironment: "Ingurunea",
alertaApiKey: "API Key",
alertaAlertState: "Alerta egoera",
alertaRecoverState: "Berreskuratze egoera",
deleteStatusPageMsg: "Ziur zaude egoera orri hau ezabatu nahi duzula?",
Proxies: "Proxiak",
default: "Lehenetsia",
enabled: "Gaituta",
setAsDefault: "Ezarri lehenetsitzat",
deleteProxyMsg: "Are you sure want to delete this proxy for all monitors?",
proxyDescription: "Proxies must be assigned to a monitor to function.",
enableProxyDescription: "This proxy will not effect on monitor requests until it is activated. You can control temporarily disable the proxy from all monitors by activation status.",
setAsDefaultProxyDescription: "This proxy will be enabled by default for new monitors. You can still disable the proxy separately for each monitor.",
"Certificate Chain": "Certificate Chain",
Valid: "Baliozkoa",
Invalid: "Baliogabea",
AccessKeyId: "AccessKey ID",
SecretAccessKey: "AccessKey Secret",
PhoneNumbers: "TelefonoZenbakiak",
TemplateCode: "TemplateCode",
SignName: "SignName",
"Sms template must contain parameters: ": "Sms txantiloiak parametroak eduki behar ditu: ",
"Bark Endpoint": "Bark Endpoint",
WebHookUrl: "WebHookUrl",
SecretKey: "SecretKey",
"For safety, must use secret key": "For safety, must use secret key",
"Device Token": "Gailu tokena",
Platform: "Plataforma",
iOS: "iOS",
Android: "Android",
Huawei: "Huawei",
High: "Altua",
Retry: "Errepikatu",
Topic: "Gaia",
"WeCom Bot Key": "WeCom Bot Key",
"Setup Proxy": "Ezarri Proxya",
"Proxy Protocol": "Proxy protokoloa",
"Proxy Server": "Proxy zerbitzaria",
"Proxy server has authentication": "Proxy zerbitzariak autentifikazioa dauka",
User: "Erabiltzailea",
Installed: "Instalatuta",
"Not installed": "Instalatu gabe",
Running: "Martxan",
"Not running": "Ez martxan",
"Remove Token": "Ezabatu Tokena",
Start: "Hasi",
Stop: "Gelditu",
"Uptime Kuma": "Uptime Kuma",
"Add New Status Page": "Gehitu egoera orri berria",
Slug: "Sluga",
"Accept characters:": "Onartu karaktereak:",
startOrEndWithOnly: "Start or end with {0} only",
"No consecutive dashes": "No consecutive dashes",
Next: "Hurrengoa",
"The slug is already taken. Please choose another slug.": "Sluga dagoeneko hartuta dago. Mesedez beste bat hautatu.",
"No Proxy": "Proxyrik ez",
Authentication: "Authentication",
"HTTP Basic Auth": "HTTP oinarrizko Auth",
"New Status Page": "Egoera orri berria",
"Page Not Found": "Orria ez da aurkitu",
"Reverse Proxy": "Alderantzizkako Proxya",
Backup: "Backup",
About: "Honi buruz",
wayToGetCloudflaredURL: "(Download cloudflared from {0})",
cloudflareWebsite: "Cloudflare webgunea",
"Message:": "Mezua:",
"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.": "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.",
"Other Software": "Beste softwarea",
"For example: nginx, Apache and Traefik.": "Adibidez: nginx, Apache and Traefik.",
"Please read": "Mesedez irakurri",
"Subject:": "Gaia:",
"Valid To:": "Balio-epea:",
"Days Remaining:": "Egun faltan:",
"Issuer:": "Issuer:",
"Fingerprint:": "Hatzmarka:",
"No status pages": "Egoera orririk ez",
"Domain Name Expiry Notification": "Domeinu izen iraungitze jakinarazpena",
Proxy: "Proxya",
"Date Created": "Data sortuta",
onebotHttpAddress: "OneBot HTTP helbidea",
onebotMessageType: "OneBot mezu mota",
onebotGroupMessage: "Taldea",
onebotPrivateMessage: "Pribatua",
onebotUserOrGroupId: "Talde/Erabiltzaile IDa",
onebotSafetyTips: "For safety, must set access token",
"PushDeer Key": "PushDeer Key",
"Footer Text": "Oineko testua",
"Show Powered By": "Erakutsi Honekin egina:",
"Domain Names": "Domeinu izenak",
signedInDisp: "Signed in as {0}",
signedInDispDisabled: "Auth desgaituta.",
"Certificate Expiry Notification": "Zertifikatu iraungitze jakinarazpena",
"API Username": "API Erabiltzailea",
"API Key": "API Gakoa",
"Recipient Number": "Recipient Number",
"From Name/Number": "From Name/Number",
"Leave blank to use a shared sender number.": "Leave blank to use a shared sender number.",
"Octopush API Version": "Octopush API Version",
"Legacy Octopush-DM": "Legacy Octopush-DM",
endpoint: "endpoint",
octopushAPIKey: "\"API key\" from HTTP API credentials in control panel",
octopushLogin: "\"Login\" from HTTP API credentials in control panel",
promosmsLogin: "API Saio haste izena",
promosmsPassword: "API Pasahitza",
"pushoversounds pushover": "Pushover (defektuz)",
"pushoversounds bike": "Bizikleta",
"pushoversounds bugle": "Bugle",
"pushoversounds cashregister": "Cash Register",
"pushoversounds classical": "Klasikoa",
"pushoversounds cosmic": "Kosmikoa",
"pushoversounds falling": "Erortzen",
"pushoversounds gamelan": "Gamelan",
"pushoversounds incoming": "Incoming",
"pushoversounds intermission": "Intermission",
"pushoversounds magic": "Magia",
"pushoversounds mechanical": "Mekanikoa",
"pushoversounds pianobar": "Piano Bar",
"pushoversounds siren": "Sirena",
"pushoversounds spacealarm": "Espazio Alarma",
"pushoversounds tugboat": "Tug Boat",
"pushoversounds alien": "Alien Alarm (long)",
"pushoversounds climb": "Climb (long)",
"pushoversounds persistent": "Persistent (long)",
"pushoversounds echo": "Pushover Echo (long)",
"pushoversounds updown": "Up Down (long)",
"pushoversounds vibrate": "Bibrazioa soilik",
"pushoversounds none": "Bat ere ez (isilik)",
pushyAPIKey: "Secret API giltza",
pushyToken: "Gailu tokena",
"Show update if available": "Erakutsi eguneratzea eskuragarri badago",
"Also check beta release": "Beta bertsioak ere egiaztatu",
"Using a Reverse Proxy?": "Proxy alderantzizkako zerbitzaria erabiltzen?",
"Check how to config it for WebSocket": "Check how to config it for WebSocket",
"Steam Game Server": "Steam joko zerbitzaria",
"Most likely causes:": "Arrazoi probableenak:",
"The resource is no longer available.": "Baliabidea ez dago erabilgarri.",
"There might be a typing error in the address.": "Idazketa-akats bat egon daiteke helbidean.",
"What you can try:": "Probatu dezakezuna:",
"Retype the address.": "Berridatzi helbidea.",
"Go back to the previous page.": "Itzuli aurreko orrialdera",
"Coming Soon": "Laster",
wayToGetClickSendSMSToken: "API erabiltzailea and API giltza hemendik lortu ditzakezu: {0} .",
"Connection String": "Konexio katea",
Query: "Kontsulta",
settingsCertificateExpiry: "TLS irungitze zertifikatua",
certificationExpiryDescription: "HTTPS Monitorizazio jakinarazpena martxan jarri TLS zertifikatua iraungitzeko hau falta denean:",
"ntfy Topic": "ntfy Topic",
Domain: "Domeinua",
Workstation: "Lan gunea",
disableCloudflaredNoAuthMsg: "Ez Auth moduan zaude, pasahitza ez da beharrezkoa.",
};

@ -3,7 +3,7 @@ export default {
checkEverySecond: "{0}초마다 확인해요.",
retryCheckEverySecond: "{0}초마다 다시 확인해요.",
retriesDescription: "서비스가 중단된 후 알림을 보내기 전 최대 재시도 횟수",
ignoreTLSError: "HTTPS 웹사이트에서 TLS/SSL 에러 무시하기",
ignoreTLSError: "HTTPS 웹사이트에서 TLS/SSL 오류 무시하기",
upsideDownModeDescription: "서버 상태를 반대로 표시해요. 서버가 작동하면 오프라인으로 표시할 거예요.",
maxRedirectDescription: "최대 리다이렉트 횟수예요. 0을 입력하면 리다이렉트를 꺼요.",
acceptedStatusCodesDescription: "응답 성공으로 간주할 상태 코드를 정해요.",
@ -30,7 +30,7 @@ export default {
Dashboard: "대시보드",
"New Update": "새로운 업데이트",
Language: "언어",
Appearance: "외형",
Appearance: "디스플레이",
Theme: "테마",
General: "일반",
Version: "버전",
@ -78,7 +78,7 @@ export default {
Notifications: "알림",
"Not available, please setup.": "존재하지 않아요, 새로운 거 하나 만드는 건 어때요?",
"Setup Notification": "알림 설정",
Light: "이트",
Light: "이트",
Dark: "다크",
Auto: "자동",
"Theme - Heartbeat Bar": "테마 - 하트비트 바",
@ -91,7 +91,7 @@ export default {
"Discourage search engines from indexing site": "검색 엔진 인덱싱 거부",
"Change Password": "비밀번호 변경",
"Current Password": "기존 비밀번호",
"New Password": "새로운 비밀번호",
"New Password": "새 비밀번호",
"Repeat New Password": "새로운 비밀번호 재입력",
"Update Password": "비밀번호 변경",
"Disable Auth": "인증 비활성화",
@ -109,14 +109,14 @@ export default {
Password: "비밀번호",
"Remember me": "비밀번호 기억하기",
Login: "로그인",
"No Monitors, please": "모니터링이 없어요,",
"add one": "하나 추가해봐요",
"No Monitors, please": "모니터링이 현재 없어요,",
"add one": "한번 추가해보실레요?",
"Notification Type": "알림 종류",
Email: "이메일",
Test: "테스트",
"Certificate Info": "인증서 정보",
"Resolver Server": "Resolver 서버",
"Resource Record Type": "자원 레코드 유형",
"Resource Record Type": "리소스 레코드 유형",
"Last Result": "최근 결과",
"Create your admin account": "관리자 계정 만들기",
"Repeat Password": "비밀번호 재입력",
@ -208,19 +208,19 @@ export default {
smtpBCC: "숨은 참조",
discord: "Discord",
"Discord Webhook URL": "Discord Webhook URL",
wayToGetDiscordURL: "서버 설정 -> 연동 -> 웹후크 보기 -> 새 웹후크에서 얻을 수 있어요.",
wayToGetDiscordURL: "서버 설정 -> 연동 -> 웹후크 보기 -> 새 웹후크에서 얻을 수 있어요!",
"Bot Display Name": "표시 이름",
"Prefix Custom Message": "접두사 메시지",
"Hello @everyone is...": "{'@'}everyone 서버 상태 알림이에요...",
teams: "Microsoft Teams",
"Webhook URL": "Webhook URL",
wayToGetTeamsURL: "{0}에서 Webhook을 어떻게 만드는지 알아봐요.",
wayToGetTeamsURL: "{0}에서 Webhook을 어떻게 만드는지 알아보세요!",
signal: "Signal",
Number: "숫자",
Recipients: "받는 사람",
needSignalAPI: "REST API를 사용하는 Signal 클라이언트가 있어야 해요.",
wayToCheckSignalURL: "밑에 URL을 확인해 URL 설정 방법을 볼 수 있어요.",
signalImportant: "중요: 받는 사람의 그룹과 숫자는 섞을 수 없어요!",
signalImportant: "경고: 받는 사람의 그룹과 숫자는 섞을 수 없어요!",
gotify: "Gotify",
"Application Token": "애플리케이션 토큰",
"Server URL": "서버 URL",
@ -230,8 +230,8 @@ export default {
"Channel Name": "채널 이름",
"Uptime Kuma URL": "Uptime Kuma URL",
aboutWebhooks: "Webhook에 대한 설명: {0}",
aboutChannelName: "Webhook 채널을 우회하려면 {0} 채널 이름칸에 채널 이름을 입력해주세요. 예: #기타-채널",
aboutKumaURL: "Uptime Kuma URL칸을 공백으로 두면 기본적으로 Project Github 페이지로 설정해요.",
aboutChannelName: "Webhook 채널을 무시하려면 {0} 채널 이름칸에 채널 이름을 입력해주세요. 예: #기타-채널",
aboutKumaURL: "Uptime Kuma URL칸을 공백으로 두면 기본적으로 Github Project 페이지로 설정해요.",
emojiCheatSheet: "이모지 목록 시트: {0}",
"rocket.chat": "Rocket.chat",
pushover: "Pushover",
@ -243,8 +243,8 @@ export default {
pushbullet: "Pushbullet",
line: "Line Messenger",
mattermost: "Mattermost",
"User Key": "사용자 키",
Device: "장치",
"User Key": "유저 키",
Device: "디바이스",
"Message Title": "메시지 제목",
"Notification Sound": "알림음",
"More info on:": "자세한 정보: {0}",
@ -254,7 +254,7 @@ export default {
octopushTypePremium: "프리미엄 (빠름) - 알림 기능에 적합해요)",
octopushTypeLowCost: "저렴한 요금 (느림) - 가끔 차단될 수 있어요)",
"Check octopush prices": "{0}에서 Octopush 가격을 확인할 수 있어요.",
octopushPhoneNumber: "휴대전화 번호 (intl format, eg : +33612345678) ",
octopushPhoneNumber: "휴대전화 번호 (intl format, 예시: +821023456789) ",
octopushSMSSender: "보내는 사람 이름 : 3-11개의 영숫자 및 여백공간 (a-z, A-Z, 0-9)",
"LunaSea Device ID": "LunaSea 장치 ID",
"Apprise URL": "Apprise URL",
@ -324,17 +324,17 @@ export default {
Content: "내용",
Style: "스타일",
info: "정보",
warning: "경고",
danger: "위험",
warning: "주의",
danger: "경고",
primary: "기본",
light: "이트",
light: "이트",
dark: "다크",
Post: "올리기",
Post: "게시",
"Please input title and content": "제목과 내용을 작성해주세요.",
Created: "생성 날짜",
"Last Updated": "마지막 업데이트",
Unpin: "제거",
"Switch to Light Theme": "이트 테마로 전환",
"Switch to Light Theme": "이트 테마로 전환",
"Switch to Dark Theme": "다크 테마로 전환",
"Show Tags": "태그 보이기",
"Hide Tags": "태그 숨기기",
@ -361,8 +361,8 @@ export default {
topicExplanation: "모니터링할 MQTT Topic",
successMessage: "성공 메시지",
successMessageExplanation: "성공으로 간주되는 MQTT 메시지",
error: "error",
critical: "critical",
error: "오류",
critical: "크리티컬",
Customize: "커스터마이즈",
"Custom Footer": "커스텀 Footer",
"Custom CSS": "커스텀 CSS",
@ -406,7 +406,7 @@ export default {
PhoneNumbers: "휴대전화 번호",
TemplateCode: "템플릿 코드",
SignName: "SignName",
"Sms template must contain parameters: ": "Sms 템플릿은 다음과 같은 파라미터가 포함되어야 해요:",
"Sms template must contain parameters: ": "SMS 템플릿은 다음과 같은 파라미터가 포함되어야 해요:",
"Bark Endpoint": "Bark Endpoint",
WebHookUrl: "웹훅 URL",
SecretKey: "Secret Key",
@ -518,14 +518,14 @@ export default {
"Show update if available": "사용 가능한 경우에 업데이트 표시",
"Also check beta release": "베타 릴리즈 확인",
"Using a Reverse Proxy?": "리버스 프록시를 사용하시나요?",
"Check how to config it for WebSocket": "웹소켓 대한 설정 방법 확인",
"Check how to config it for WebSocket": "웹소켓 대한 설정 방법",
"Steam Game Server": "스팀 게임 서버",
"Most likely causes:": "원인:",
"The resource is no longer available.": "더이상 사용할 수 없어요.",
"The resource is no longer available.": "더 이상 사용할 수 없어요...",
"There might be a typing error in the address.": "주소에 오탈자가 있을 수 있어요.",
"What you can try:": "해결 방법:",
"Retype the address.": "주소 다시 입력하기",
"Go back to the previous page.": "이전 페이지로 돌아가기",
"Coming Soon": "Coming Soon",
"Coming Soon": "Coming Soon...",
wayToGetClickSendSMSToken: "{0}에서 API 사용자 이름과 키를 얻을 수 있어요.",
};

@ -90,8 +90,11 @@ export default {
"New Password": "Nieuw wachtwoord",
"Repeat New Password": "Herhaal nieuw wachtwoord",
"Update Password": "Vernieuw wachtwoord",
"Disable Auth": "Autorisatie uitschakelen",
"Enable Auth": "Autorisatie inschakelen",
"Disable Auth": "Authenticatie uitschakelen",
"Enable Auth": "Authenticatie inschakelen",
"disableauth.message1": "Weet je zeker dat je <strong>authenticatie wilt uitschakelen</strong>?",
"disableauth.message2": "Er zijn omstandigheden waarbij je <strong>authenticatie door derden wilt implementeren</strong> voor Uptime Kuma, zoals Cloudflare Access, Authelia of andere authenticatiemechanismen.",
"Please use this option carefully!": "Gebruik deze optie zorgvuldig!",
Logout: "Uitloggen",
Leave: "Vertrekken",
"I understand, please disable": "Ik begrijp het, schakel a.u.b. uit",
@ -351,7 +354,7 @@ export default {
Discard: "Weggooien",
Cancel: "Annuleren",
"Powered by": "Mogelijk gemaakt door",
shrinkDatabaseDescription: "Trigger database VACUUM voor SQLite. Als de database na 1.10.0 gemaakt is, dan is AUTO_VACUUM al aangezet en deze actie niet nodig.",
shrinkDatabaseDescription: "Activeer database VACUUM voor SQLite. Als de database na 1.10.0 aangemaakt is, dan staat AUTO_VACUUM al aan en is deze actie niet nodig.",
serwersms: "SerwerSMS.pl",
serwersmsAPIUser: "API Gebruikersnaam (incl. webapi_ prefix)",
serwersmsAPIPassword: "API Wachtwoord",
@ -386,7 +389,7 @@ export default {
proxyDescription: "Proxies moeten worden toegewezen aan een monitor om te functioneren.",
enableProxyDescription: "Deze proxy heeft geen effect op monitor verzoeken totdat het is geactiveerd. Je kunt tijdelijk de proxy uitschakelen voor alle monitors voor activatie status.",
setAsDefaultProxyDescription: "Deze proxy wordt standaard aangezet voor alle nieuwe monitors. Je kunt nog steeds de proxy apart uitschakelen voor elke monitor.",
"Certificate Chain": "Certificaat Chain",
"Certificate Chain": "Certificaatketen",
Valid: "Geldig",
Invalid: "Ongeldig",
AccessKeyId: "AccessKey ID",
@ -407,7 +410,7 @@ export default {
High: "Hoog",
Retry: "Opnieuw",
Topic: "Onderwerp",
"WeCom Bot Key": "WeCom Bot Sleutel",
"WeCom Bot Key": "WeCom Bot Key",
"Setup Proxy": "Proxy instellen",
"Proxy Protocol": "Proxy Protocol",
"Proxy Server": "Proxy Server",
@ -449,7 +452,6 @@ export default {
"Issuer:": "Uitgever:",
"Fingerprint:": "Vingerafruk:",
"No status pages": "Geen status pagina's",
"Domain Name Expiry Notification": "Domein Naam Verloop Notificatie",
Proxy: "Proxy",
"Date Created": "Datum Aangemaakt",
onebotHttpAddress: "OneBot HTTP Adres",
@ -460,6 +462,70 @@ export default {
onebotSafetyTips: "Voor de veiligheid moet een toegangssleutel worden ingesteld",
"PushDeer Key": "PushDeer Key",
"Footer Text": "Footer Tekst",
"Show Powered By": "Laat 'Mogeljik gemaakt door' zien",
"Show Powered By": "Laat \"Mogeljik gemaakt door\" zien",
"Domain Names": "Domein Namen",
"pushoversounds pushover": "Pushover (default)",
"pushoversounds bike": "Bike",
"pushoversounds bugle": "Bugle",
"pushoversounds cashregister": "Cash Register",
"pushoversounds classical": "Classical",
"pushoversounds cosmic": "Cosmic",
"pushoversounds falling": "Falling",
"pushoversounds gamelan": "Gamelan",
"pushoversounds incoming": "Incoming",
"pushoversounds intermission": "Intermission",
"pushoversounds magic": "Magic",
"pushoversounds mechanical": "Mechanical",
"pushoversounds pianobar": "Piano Bar",
"pushoversounds siren": "Siren",
"pushoversounds spacealarm": "Space Alarm",
"pushoversounds tugboat": "Tug Boat",
"pushoversounds alien": "Alien Alarm (long)",
"pushoversounds climb": "Climb (long)",
"pushoversounds persistent": "Persistent (long)",
"pushoversounds echo": "Pushover Echo (long)",
"pushoversounds updown": "Up Down (long)",
"pushoversounds vibrate": "Vibrate Only",
"pushoversounds none": "None (silent)",
dnsPortDescription: "DNS-serverpoort. Standaard ingesteld op 53. Je kunt de poort op elk moment wijzigen.",
error: "fout",
critical: "kritisch",
wayToGetPagerDutyKey: "Je kunt dit krijgen door naar Service -> Service Directory -> (Selecteer een service) -> Integraties -> Integratie toevoegen te gaan. Hier kunt u zoeken naar \"Events API V2\". Meer informatie {0}",
"Integration Key": "Integration Key",
"Integration URL": "Integration URL",
"Auto resolve or acknowledged": "Automatisch oplossen of bevestigen",
"do nothing": "niets doen",
"auto acknowledged": "automatisch bevestigen",
"auto resolve": "automatisch oplossen",
Authentication: "authenticatie",
signedInDisp: "Aangemeld als {0}",
signedInDispDisabled: "Authenticatie uitgeschakeld.",
"Certificate Expiry Notification": "Melding over verlopen certificaat",
"Recipient Number": "Nummer ontvanger",
"From Name/Number": "Van naam/nummer",
"Leave blank to use a shared sender number.": "Laat leeg om een gedeeld afzendernummer te gebruiken.",
endpoint: "endpoint",
pushyAPIKey: "Secret API Key",
pushyToken: "Device token",
"Show update if available": "Update weergeven indien beschikbaar",
"Also check beta release": "Controleer ook de bètaversies",
"Using a Reverse Proxy?": "Een reverse proxy gebruiken?",
"Check how to config it for WebSocket": "Controleer hoe je het configureert voor een WebSocket",
"Steam Game Server": "Steam gameserver",
"Most likely causes:": "Meest waarschijnlijke oorzaken:",
"The resource is no longer available.": "De paginabron is niet langer beschikbaar.",
"There might be a typing error in the address.": "Er zit een typefout in het de URL.",
"What you can try:": "Wat je kan proberen:",
"Retype the address.": "De URL controleren en/of opnnieuw typen.",
"Go back to the previous page.": "Terug naar de vorige pagina.",
"Coming Soon": "Binnenkort beschikbaar",
wayToGetClickSendSMSToken: "Je kan een API Username en API Key krijgen vanuit {0} .",
"Connection String": "Connection String",
Query: "Query",
settingsCertificateExpiry: "TLS Certificate Expiry",
certificationExpiryDescription: "HTTPS Monitors trigger notification when TLS certificate expires in:",
"ntfy Topic": "ntfy Topic",
Domain: "Domein",
Workstation: "Werkstation",
disableCloudflaredNoAuthMsg: "De \"Geen authenticatie\" modus staat aan, wachtwoord is niet vereist.",
};

@ -0,0 +1,203 @@
export default {
languageName: "Português (Portugal)",
checkEverySecond: "Verificar a cada {0} segundos.",
retryCheckEverySecond: "Tentar novamente a cada {0} segundos.",
retriesDescription: "Máximo de tentativas antes que o serviço seja marcado como inativo e uma notificação seja enviada",
ignoreTLSError: "Ignorar erros TLS/SSL para sites HTTPS",
upsideDownModeDescription: "Inverte o status de cabeça para baixo. Se o serviço estiver acessível, ele está OFFLINE.",
maxRedirectDescription: "Número máximo de redirecionamentos a seguir. Define como 0 para desativar redirecionamentos.",
acceptedStatusCodesDescription: "Seleciona os códigos de status que são considerados uma resposta bem-sucedida.",
passwordNotMatchMsg: "A senha repetida não corresponde.",
notificationDescription: "Atribuir uma notificação ao (s) monitor (es) para que funcione.",
keywordDescription: "Pesquisa a palavra-chave em HTML simples ou resposta JSON e diferencia maiúsculas de minúsculas",
pauseDashboardHome: "Pausa",
deleteMonitorMsg: "Tens a certeza de que queres excluir este monitor?",
deleteNotificationMsg: "Tens a certeza de que queres excluir esta notificação para todos os monitores?",
resolverserverDescription: "A Cloudflare é o servidor padrão, podes alterar o servidor 'resolvedor' a qualquer momento.",
rrtypeDescription: "Seleciona o RR-Type que queres monitorizar",
pauseMonitorMsg: "Tens a certeza que queres fazer uma pausa?",
enableDefaultNotificationDescription: "Para cada monitor novo esta notificação vai estar activa por padrão. Podes também desativar a notificação separadamente para cada monitor.",
clearEventsMsg: "Tens a certeza que queres excluir todos os eventos deste monitor?",
clearHeartbeatsMsg: "Tens a certeza de que queres excluir todos os heartbeats deste monitor?",
confirmClearStatisticsMsg: "Tens a certeza que queres excluir TODAS as estatísticas?",
importHandleDescription: "Escolhe 'Ignorar existente' se quiseres ignorar todos os monitores ou notificações com o mesmo nome. 'Substituir' excluirá todos os monitores e notificações existentes.",
confirmImportMsg: "Tens a certeza que queres importar o backup? Certifica-te que selecionaste a opção de importação correta.",
twoFAVerifyLabel: "Insire o teu token para verificares se o 2FA está a funcionar",
tokenValidSettingsMsg: "O token é válido! Agora podes salvar as configurações do 2FA.",
confirmEnableTwoFAMsg: "Tens a certeza de que queres habilitar 2FA?",
confirmDisableTwoFAMsg: "Tens a certeza de que queres desativar 2FA?",
Settings: "Configurações",
Dashboard: "Dashboard",
"New Update": "Nova Atualização",
Language: "Linguagem",
Appearance: "Aparência",
Theme: "Tema",
General: "Geral",
Version: "Versão",
"Check Update On GitHub": "Verificar atualização no Github",
List: "Lista",
Add: "Adicionar",
"Add New Monitor": "Adicionar novo monitor",
"Quick Stats": "Estatísticas rápidas",
Up: "On",
Down: "Off",
Pending: "Pendente",
Unknown: "Desconhecido",
Pause: "Pausa",
Name: "Nome",
Status: "Status",
DateTime: "Data hora",
Message: "Mensagem",
"No important events": "Nenhum evento importante",
Resume: "Resumo",
Edit: "Editar",
Delete: "Apagar",
Current: "Atual",
Uptime: "Tempo de atividade",
"Cert Exp.": "Cert Exp.",
day: "dia | dias",
"-day": "-dia",
hour: "hora",
"-hour": "-hora",
Response: "Resposta",
Ping: "Ping",
"Monitor Type": "Tipo de Monitor",
Keyword: "Palavra-Chave",
"Friendly Name": "Nome Amigável",
URL: "URL",
Hostname: "Hostname",
Port: "Porta",
"Heartbeat Interval": "Intervalo de Heartbeats",
Retries: "Novas tentativas",
"Heartbeat Retry Interval": "Intervalo de repetição de Heartbeats",
Advanced: "Avançado",
"Upside Down Mode": "Modo de cabeça para baixo",
"Max. Redirects": "Redirecionamento Máx.",
"Accepted Status Codes": "Status Code Aceitáveis",
Save: "Guardar",
Notifications: "Notificações",
"Not available, please setup.": "Não disponível, por favor configura.",
"Setup Notification": "Configurar Notificação",
Light: "Claro",
Dark: "Escuro",
Auto: "Auto",
"Theme - Heartbeat Bar": "Tema - Barra de Heartbeat",
Normal: "Normal",
Bottom: "Inferior",
None: "Nenhum",
Timezone: "Fuso horário",
"Search Engine Visibility": "Visibilidade do mecanismo de pesquisa",
"Allow indexing": "Permitir Indexação",
"Discourage search engines from indexing site": "Desencorajar que motores de busca indexem o site",
"Change Password": "Mudar senha",
"Current Password": "Senha atual",
"New Password": "Nova Senha",
"Repeat New Password": "Repetir Nova Senha",
"Update Password": "Atualizar Senha",
"Disable Auth": "Desativar Autenticação",
"Enable Auth": "Ativar Autenticação",
"disableauth.message1": "Tens a certeza que queres <strong>desativar a autenticação</strong>?",
"disableauth.message2": "Isso é para <strong>alguém que tem autenticação de terceiros</strong> em frente ao 'UpTime Kuma' como o Cloudflare Access.",
"Please use this option carefully!": "Por favor, utiliza esta opção com cuidado.",
Logout: "Logout",
Leave: "Sair",
"I understand, please disable": "Eu entendo, por favor desativa.",
Confirm: "Confirmar",
Yes: "Sim",
No: "Não",
Username: "Utilizador",
Password: "Senha",
"Remember me": "Lembra-me",
Login: "Autenticar",
"No Monitors, please": "Nenhum monitor, por favor",
"add one": "adicionar um",
"Notification Type": "Tipo de Notificação",
Email: "Email",
Test: "Testar",
"Certificate Info": "Info. do Certificado ",
"Resolver Server": "Resolver Servidor",
"Resource Record Type": "Tipo de registro de aplicação",
"Last Result": "Último resultado",
"Create your admin account": "Cria a tua conta de admin",
"Repeat Password": "Repete a senha",
"Import Backup": "Importar Backup",
"Export Backup": "Exportar Backup",
Export: "Exportar",
Import: "Importar",
respTime: "Tempo de Resp. (ms)",
notAvailableShort: "N/A",
"Default enabled": "Padrão habilitado",
"Apply on all existing monitors": "Aplicar em todos os monitores existentes",
Create: "Criar",
"Clear Data": "Limpar Dados",
Events: "Eventos",
Heartbeats: "Heartbeats",
"Auto Get": "Obter Automático",
backupDescription: "Podes fazer backup de todos os monitores e todas as notificações num arquivo JSON.",
backupDescription2: "OBS: Os dados do histórico e do evento não estão incluídos.",
backupDescription3: "Dados confidenciais, como tokens de notificação, estão incluídos no arquivo de exportação, mantem-no com cuidado.",
alertNoFile: "Seleciona um arquivo para importar.",
alertWrongFileType: "Seleciona um arquivo JSON.",
"Clear all statistics": "Limpar todas as estatísticas",
"Skip existing": "Saltar existente",
Overwrite: "Sobrescrever",
Options: "Opções",
"Keep both": "Manter os dois",
"Verify Token": "Verificar Token",
"Setup 2FA": "Configurar 2FA",
"Enable 2FA": "Ativar 2FA",
"Disable 2FA": "Desativar 2FA",
"2FA Settings": "Configurações do 2FA ",
"Two Factor Authentication": "Autenticação de Dois Fatores",
Active: "Ativo",
Inactive: "Inativo",
Token: "Token",
"Show URI": "Mostrar URI",
Tags: "Tag",
"Add New below or Select...": "Adicionar Novo abaixo ou Selecionar ...",
"Tag with this name already exist.": "Já existe uma etiqueta com este nome.",
"Tag with this value already exist.": "Já existe uma etiqueta com este valor.",
color: "cor",
"value (optional)": "valor (opcional)",
Gray: "Cinza",
Red: "Vermelho",
Orange: "Laranja",
Green: "Verde",
Blue: "Azul",
Indigo: "Índigo",
Purple: "Roxo",
Pink: "Rosa",
"Search...": "Pesquisa...",
"Avg. Ping": "Ping Médio.",
"Avg. Response": "Resposta Média. ",
"Status Page": "Página de Status",
"Status Pages": "Página de Status",
"Entry Page": "Página de entrada",
statusPageNothing: "Nada aqui, por favor, adiciona um grupo ou monitor.",
"No Services": "Nenhum Serviço",
"All Systems Operational": "Todos os Serviços Operacionais",
"Partially Degraded Service": "Serviço parcialmente degradados",
"Degraded Service": "Serviço Degradado",
"Add Group": "Adicionar Grupo",
"Add a monitor": "Adicionar um monitor",
"Edit Status Page": "Editar Página de Status",
"Go to Dashboard": "Ir para o dashboard",
telegram: "Telegram",
webhook: "Webhook",
smtp: "Email (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 (Support 50+ Notification services)",
pushbullet: "Pushbullet",
line: "Line Messenger",
mattermost: "Mattermost",
};

@ -184,8 +184,8 @@ export default {
"Add a monitor": "Dodaj monitor",
"Edit Status Page": "Uredi statusno stran",
"Go to Dashboard": "Pojdi na nadzorno ploščo",
"Status Page": "Página de Status",
"Status Pages": "Página de Status",
"Status Page": "Statusna stran",
"Status Pages": "Statusne strani",
defaultNotificationName: "Moje {notification} Obvestilo ({number})",
here: "tukaj",
Required: "Obvezno",

@ -518,4 +518,5 @@ export default {
"Go back to the previous page.": "กลับไปที่หน้าก่อนหน้า",
"Coming Soon": "เร็ว ๆ นี้",
wayToGetClickSendSMSToken: "คุณสามารถรับ API Username และ API Key ได้จาก {0}",
wayToGetLineNotifyToken: "คุณสามารถรับ access token ได้จาก {0}",
};

@ -1,5 +1,5 @@
export default {
languageName: "Український",
languageName: "Українська",
checkEverySecond: "Перевірка кожні {0} секунд",
retriesDescription: "Максимальна кількість спроб перед позначенням сервісу як недоступного та надсиланням повідомлення",
ignoreTLSError: "Ігнорувати помилку TLS/SSL для сайтів HTTPS",
@ -7,11 +7,11 @@ export default {
maxRedirectDescription: "Максимальна кількість перенаправлень. Поставте 0, щоб вимкнути перенаправлення.",
acceptedStatusCodesDescription: "Виберіть коди статусів для визначення доступності сервісу.",
passwordNotMatchMsg: "Повторення паролю не збігається.",
notificationDescription: "Прив'яжіть повідомлення до моніторів.",
notificationDescription: "Прив'яжіть сповіщення до моніторів.",
keywordDescription: "Пошук слова в чистому HTML або JSON-відповіді (чутливо до регістру)",
pauseDashboardHome: "Пауза",
deleteMonitorMsg: "Ви дійсно хочете видалити цей монітор?",
deleteNotificationMsg: "Ви дійсно хочете видалити це повідомлення для всіх моніторів?",
deleteNotificationMsg: "Ви дійсно хочете видалити це сповіщення для всіх моніторів?",
resolverserverDescription: "Cloudflare є сервером за замовчуванням. Ви завжди можете змінити цей сервер.",
rrtypeDescription: "Виберіть тип ресурсного запису, який ви хочете відстежувати",
pauseMonitorMsg: "Ви дійсно хочете поставити на паузу?",
@ -54,7 +54,7 @@ export default {
Keyword: "Ключове слово",
"Friendly Name": "Ім'я",
URL: "URL",
Hostname: "Ім'я хоста",
Hostname: "Адреса хоста",
Port: "Порт",
"Heartbeat Interval": "Частота опитування",
Retries: "Спроб",
@ -63,7 +63,7 @@ export default {
"Max. Redirects": "Макс. кількість перенаправлень",
"Accepted Status Codes": "Припустимі коди статусу",
Save: "Зберегти",
Notifications: "Повідомлення",
Notifications: "Сповіщення",
"Not available, please setup.": "Доступних сповіщень немає, необхідно створити.",
"Setup Notification": "Створити сповіщення",
Light: "Світла",
@ -100,7 +100,7 @@ export default {
"No Monitors, please": "Моніторів немає, будь ласка",
"No Monitors": "Монітори відсутні",
"add one": "створіть новий",
"Notification Type": "Тип повідомлення",
"Notification Type": "Тип сповіщення",
Email: "Пошта",
Test: "Перевірка",
"Certificate Info": "Інформація про сертифікат",
@ -119,7 +119,7 @@ export default {
Events: "Події",
Heartbeats: "Опитування",
"Auto Get": "Авто-отримання",
enableDefaultNotificationDescription: "Для кожного нового монітора це повідомлення буде включено за замовчуванням. Ви все ще можете відключити повідомлення в кожному моніторі окремо.",
enableDefaultNotificationDescription: "Для кожного нового монітора це сповіщення буде включено за замовчуванням. Ви все ще можете відключити сповіщення в кожному моніторі окремо.",
"Default enabled": "Використовувати за промовчанням",
"Also apply to existing monitors": "Застосувати до існуючих моніторів",
Export: "Експорт",
@ -170,7 +170,7 @@ export default {
Purple: "Пурпурний",
Pink: "Рожевий",
"Search...": "Пошук...",
"Avg. Ping": "Середнє значення пінгу",
"Avg. Ping": "Середній пінг",
"Avg. Response": "Середній час відповіді",
"Entry Page": "Головна сторінка",
statusPageNothing: "Тут порожньо. Додайте групу або монітор.",
@ -210,7 +210,7 @@ export default {
"Push URL": "URL пуша",
needPushEvery: "До цієї URL необхідно звертатися кожні {0} секунд",
pushOptionalParams: "Опціональні параметри: {0}",
defaultNotificationName: "Моє повідомлення {notification} ({number})",
defaultNotificationName: "Моє сповіщення {notification} ({number})",
here: "тут",
Required: "Потрібно",
"Bot Token": "Токен бота",
@ -257,7 +257,7 @@ export default {
"User Key": "Ключ користувача",
Device: "Пристрій",
"Message Title": "Заголовок повідомлення",
"Notification Sound": "Звук повідомлення",
"Notification Sound": "Звук сповіщення",
"More info on:": "Більше інформації: {0}",
pushoverDesc1: "Екстренний пріоритет (2) має таймуут повтору за замовчуванням 30 секунд і закінчується через 1 годину.",
pushoverDesc2: "Якщо ви бажаєте надсилати повідомлення різним пристроям, необхідно заповнити поле Пристрій.",
@ -354,7 +354,7 @@ export default {
"No consecutive dashes --": "Заборонено використовувати тире --",
"HTTP Options": "HTTP Опції",
Authentication: "Аутентифікація",
"HTTP Basic Auth": "HTTP Авторизація",
"HTTP Basic Auth": "Базова HTTP",
PushByTechulus: "Push by Techulus",
clicksendsms: "ClickSend SMS",
GoogleChat: "Google Chat (тільки Google Workspace)",
@ -392,4 +392,139 @@ export default {
alertaAlertState: "Стан алерту",
alertaRecoverState: "Стан відновлення",
deleteStatusPageMsg: "Дійсно хочете видалити цю сторінку статусів?",
Proxies: "Проксі",
default: "За замовчуванням",
enabled: "Активно",
setAsDefault: "Встановити за замовчуванням",
deleteProxyMsg: "Ви впевнені, що хочете видалити цей проксі для всіх моніторів?",
proxyDescription: "Щоб функціонувати, монітору потрібно призначити проксі.",
enableProxyDescription: "Цей проксі не впливатиме на запити моніторингу, доки його не буде активовано. Ви можете контролювати тимчасове відключення проксі з усіх моніторів за статусом активації.",
setAsDefaultProxyDescription: "Цей проксі буде ввімкнено за умовчанням для нових моніторів. Ви все одно можете вимкнути проксі окремо для кожного монітора.",
Invalid: "Недійсний",
AccessKeyId: "AccessKey ID",
SecretAccessKey: "AccessKey Secret",
PhoneNumbers: "PhoneNumbers",
TemplateCode: "TemplateCode",
SignName: "SignName",
"Sms template must contain parameters: ": "Шаблон смс повинен містити параметри: ",
"Bark Endpoint": "Bark Endpoint",
WebHookUrl: "WebHookUrl",
SecretKey: "SecretKey",
"For safety, must use secret key": "Для безпеки необхідно використовувати секретний ключ",
"Device Token": "Токен пристрою",
Platform: "Платформа",
iOS: "iOS",
Android: "Android",
Huawei: "Huawei",
High: "Високий",
Retry: "Повтор",
Topic: "Тема",
"WeCom Bot Key": "WeCom Bot ключ",
"Setup Proxy": "Налаштувати проксі",
"Proxy Protocol": "Протокол проксі",
"Proxy Server": "Проксі-сервер",
"Proxy server has authentication": "Проксі-сервер має аутентифікацію",
User: "Користувач",
Installed: "Встановлено",
"Not installed": "Не встановлено",
Running: "Запущено",
"Not running": "Не запущено",
"Remove Token": "Видалити токен",
Start: "Запустити",
Stop: "Зупинити",
"Uptime Kuma": "Uptime Kuma",
Slug: "Slug",
"Accept characters:": "Прийняти символи:",
startOrEndWithOnly: "Починається або закінчується лише {0}",
"No consecutive dashes": "Немає послідовних тире",
"The slug is already taken. Please choose another slug.": "The slug is already taken. Please choose another slug.",
"No Proxy": "Без проксі",
"Page Not Found": "Сторінку не знайдено",
"Reverse Proxy": "Реверсивний проксі",
wayToGetCloudflaredURL: "(Завантажити Cloudflare з {0})",
cloudflareWebsite: "Веб-сайт Cloudflare",
"Message:": "Повідомлення:",
"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. Ви дійсно хочете зробити це? Для підтвердження введіть поточний пароль.",
"Other Software": "Інше програмне забезпечення",
"For example: nginx, Apache and Traefik.": "Наприклад: nginx, Apache and Traefik.",
"Please read": "Будь ласка, прочитайте",
"Subject:": "Тема:",
"Valid To:": "Дійсний до:",
"Days Remaining:": "Залишилось днів:",
"Issuer:": "Емітент:",
"Fingerprint:": "Відбиток:",
"No status pages": "Немає сторінок статусу",
"Domain Name Expiry Notification": "Сповіщення про закінчення терміну дії доменного імені",
Proxy: "Проксі",
"Date Created": "Дата створення",
onebotHttpAddress: "OneBot адреса HTTP",
onebotMessageType: "OneBot тип повідомлення",
onebotGroupMessage: "Група",
onebotPrivateMessage: "Приватне",
onebotUserOrGroupId: "Група/Користувач ID",
onebotSafetyTips: "Для безпеки необхідно встановити маркер доступу",
"PushDeer Key": "PushDeer ключ",
"Footer Text": "Текст нижнього колонтитула",
"Show Powered By": "Показувати платформу",
"Domain Names": "Доменні імена",
signedInDisp: "Ви ввійшли як {0}",
signedInDispDisabled: "Авторизація вимкнена.",
"Certificate Expiry Notification": "Сповіщення про закінчення терміну дії сертифіката",
"API Username": "Користувач API",
"API Key": "Ключ API",
"Recipient Number": "Номер одержувача",
"From Name/Number": "Від Ім'я/Номер",
"Leave blank to use a shared sender number.": "Залиште поле порожнім, щоб використовувати спільний номер відправника.",
"Octopush API Version": "Octopush API версія",
"Legacy Octopush-DM": "Legacy Octopush-DM",
"endpoint": "кінцева точка",
octopushAPIKey: "\"Ключ API\" з облікових даних HTTP API в панелі керування",
octopushLogin: "\"Ім'я користувача\" з облікових даних HTTP API на панелі керування",
promosmsLogin: "API Логін",
promosmsPassword: "API Пароль",
"pushoversounds pushover": "Pushover (по замовчуванню)",
"pushoversounds bike": "Bike",
"pushoversounds bugle": "Bugle",
"pushoversounds cashregister": "Cash Register",
"pushoversounds classical": "Classical",
"pushoversounds cosmic": "Cosmic",
"pushoversounds falling": "Falling",
"pushoversounds gamelan": "Gamelan",
"pushoversounds incoming": "Incoming",
"pushoversounds intermission": "Intermission",
"pushoversounds magic": "Magic",
"pushoversounds mechanical": "Mechanical",
"pushoversounds pianobar": "Piano Bar",
"pushoversounds siren": "Siren",
"pushoversounds spacealarm": "Space Alarm",
"pushoversounds tugboat": "Tug Boat",
"pushoversounds alien": "Alien Alarm (long)",
"pushoversounds climb": "Climb (long)",
"pushoversounds persistent": "Persistent (long)",
"pushoversounds echo": "Pushover Echo (long)",
"pushoversounds updown": "Up Down (long)",
"pushoversounds vibrate": "Vibrate Only",
"pushoversounds none": "None (silent)",
pushyAPIKey: "Секретний ключ API",
pushyToken: "Токен пристрою",
"Using a Reverse Proxy?": "Використовувати зворотній проксі?",
"Check how to config it for WebSocket": "Перевірте, як налаштувати його для WebSocket",
"Steam Game Server": "Ігровий сервер Steam",
"Most likely causes:": "Найімовірніші причини:",
"The resource is no longer available.": "Ресурс більше не доступний.",
"There might be a typing error in the address.": "Можливо, в адресі є помилка.",
"What you can try:": "Що ви можете спробувати:",
"Retype the address.": "Повторно введіть адресу.",
"Go back to the previous page.": "Повернутися на попередню сторінку.",
"Coming Soon": "Незабаром",
wayToGetClickSendSMSToken: "Ви можете отримати ім’я користувача API та ключ API з {0} .",
"Connection String": "Рядок підключення",
"Query": "Запит",
settingsCertificateExpiry: "Закінчення терміну дії сертифіката TLS",
certificationExpiryDescription: "Запуск сповіщення для HTTPS моніторів коли до закінчення терміну дії TLS сертифіката:",
"ntfy Topic": "ntfy Тема",
"Domain": "Домен",
"Workstation": "Робоча станція",
disableCloudflaredNoAuthMsg: "Ви перебуваєте в режимі без авторизації, пароль не потрібен.",
};

@ -13,6 +13,7 @@ export default {
pauseDashboardHome: "暫停",
deleteMonitorMsg: "您確定要刪除此監測器嗎?",
deleteNotificationMsg: "您確定要為所有監測器刪除此通知嗎?",
dnsPortDescription: "DNS 伺服器連接埠。預設為 53。您可以隨時變更連接埠。",
resolverserverDescription: "Cloudflare 為預設伺服器。您可以隨時更換解析伺服器。",
rrtypeDescription: "選擇您想要監測的資源記錄類型",
pauseMonitorMsg: "您確定要暫停嗎?",
@ -332,6 +333,8 @@ export default {
info: "資訊",
warning: "警告",
danger: "危險",
error: "錯誤",
critical: "嚴重",
primary: "主要",
light: "淺色",
dark: "暗色",
@ -372,6 +375,13 @@ export default {
smtpDkimHashAlgo: "雜湊演算法 (選填)",
smtpDkimheaderFieldNames: "要簽署的郵件標頭 (選填)",
smtpDkimskipFields: "不簽署的郵件標頭 (選填)",
wayToGetPagerDutyKey: "您可以前往服務 -> 服務目錄 -> (選取服務) -> 整合 -> 新增整合以取得。您可以搜尋 \"Events API V2\"。詳細資訊 {0}",
"Integration Key": "整合金鑰",
"Integration URL": "整合網址",
"Auto resolve or acknowledged": "自動解決或認可",
"do nothing": "不進行任何操作",
"auto acknowledged": "自動認可",
"auto resolve": "自動解決",
gorush: "Gorush",
alerta: "Alerta",
alertaApiEndpoint: "API 端點",
@ -465,4 +475,65 @@ export default {
"Footer Text": "頁尾文字",
"Show Powered By": "顯示技術支援文字",
"Domain Names": "網域名稱",
signedInDisp: "以 {0} 身分登入",
signedInDispDisabled: "驗證已停用。",
"Certificate Expiry Notification": "憑證到期通知",
"API Username": "API 使用者名稱",
"API Key": "API 金鑰",
"Recipient Number": "收件者號碼",
"From Name/Number": "來自名字/號碼",
"Leave blank to use a shared sender number.": "留空以使用共享寄件人號碼。",
"Octopush API Version": "Octopush API 版本",
"Legacy Octopush-DM": "舊版 Octopush-DM",
"endpoint": "端",
octopushAPIKey: "\"API key\" from HTTP API credentials in control panel",
octopushLogin: "\"Login\" from HTTP API credentials in control panel",
promosmsLogin: "API 登入名稱",
promosmsPassword: "API 密碼",
"pushoversounds pushover": "Pushover (預設)",
"pushoversounds bike": "車鈴",
"pushoversounds bugle": "號角",
"pushoversounds cashregister": "收銀機",
"pushoversounds classical": "古典",
"pushoversounds cosmic": "宇宙",
"pushoversounds falling": "下落",
"pushoversounds gamelan": "甘美朗",
"pushoversounds incoming": "來電",
"pushoversounds intermission": "中場休息",
"pushoversounds magic": "魔法",
"pushoversounds mechanical": "機械",
"pushoversounds pianobar": "Piano Bar",
"pushoversounds siren": "Siren",
"pushoversounds spacealarm": "Space Alarm",
"pushoversounds tugboat": "汽笛",
"pushoversounds alien": "外星鬧鐘 (長)",
"pushoversounds climb": "爬升 (長)",
"pushoversounds persistent": "持續 (長)",
"pushoversounds echo": "Pushover 回音 (長)",
"pushoversounds updown": "上下 (長)",
"pushoversounds vibrate": "僅震動",
"pushoversounds none": "無 (靜音)",
pushyAPIKey: "API 密鑰",
pushyToken: "裝置權杖",
"Show update if available": "顯示可用更新",
"Also check beta release": "檢查 Beta 版",
"Using a Reverse Proxy?": "正在使用反向代理?",
"Check how to config it for WebSocket": "查看如何為 WebSocket 設定",
"Steam Game Server": "Steam 遊戲伺服器",
"Most likely causes:": "可能原因:",
"The resource is no longer available.": "資源已不可用。",
"There might be a typing error in the address.": "網址可能有誤。",
"What you can try:": "您可以嘗試:",
"Retype the address.": "重新輸入網址。",
"Go back to the previous page.": "返回上一頁。",
"Coming Soon": "即將推出",
wayToGetClickSendSMSToken: "您可以從 {0} 取得 API 使用者名稱和金鑰。",
"Connection String": "連線字串",
"Query": "查詢",
settingsCertificateExpiry: "TLS 憑證到期",
certificationExpiryDescription: "TLS 將於 X 天後到期時觸發 HTTPS 監測器通知:",
"ntfy Topic": "ntfy 主題",
"Domain": "網域",
"Workstation": "工作站",
disableCloudflaredNoAuthMsg: "您處於無驗證模式。無須輸入密碼。",
};

@ -77,7 +77,7 @@
<!-- Mobile Only -->
<div v-if="$root.isMobile" style="width: 100%; height: 60px;" />
<nav v-if="$root.isMobile" class="bottom-nav">
<nav v-if="$root.isMobile && $root.loggedIn" class="bottom-nav">
<router-link to="/dashboard" class="nav-link">
<div><font-awesome-icon icon="tachometer-alt" /></div>
{{ $t("Dashboard") }}

@ -601,6 +601,28 @@ export default {
return result;
},
/**
* Frontend Version
* It should be compiled to a static value while building the frontend.
* Please see ./config/vite.config.js, it is defined via vite.js
* @returns {string}
*/
frontendVersion() {
// eslint-disable-next-line no-undef
return FRONTEND_VERSION;
},
/**
* Are both frontend and backend in the same version?
* @returns {boolean}
*/
isFrontendBackendVersionMatched() {
if (!this.info.version) {
return true;
}
return this.info.version === this.frontendVersion;
}
},
watch: {

@ -45,6 +45,9 @@
<option value="sqlserver">
SQL Server
</option>
<option value="postgres">
PostgreSQL
</option>
</optgroup>
</select>
</div>
@ -168,15 +171,21 @@
</div>
</template>
<!-- SQL Server -->
<template v-if="monitor.type === 'sqlserver'">
<!-- SQL Server and PostgreSQL -->
<template v-if="monitor.type === 'sqlserver' || monitor.type === 'postgres'">
<div class="my-3">
<label for="sqlserverConnectionString" class="form-label">SQL Server {{ $t("Connection String") }}</label>
<input id="sqlserverConnectionString" v-model="monitor.databaseConnectionString" type="text" class="form-control">
<label for="sqlConnectionString" class="form-label">{{ $t("Connection String") }}</label>
<template v-if="monitor.type === 'sqlserver'">
<input id="sqlConnectionString" v-model="monitor.databaseConnectionString" type="text" class="form-control" placeholder="Server=<hostname>,<port>;Database=<your database>;User Id=<your user id>;Password=<your password>;Encrypt=<true/false>;TrustServerCertificate=<Yes/No>;Connection Timeout=<int>">
</template>
<template v-if="monitor.type === 'postgres'">
<input id="sqlConnectionString" v-model="monitor.databaseConnectionString" type="text" class="form-control" placeholder="postgres://username:password@host:port/database">
</template>
</div>
<div class="my-3">
<label for="sqlserverQuery" class="form-label">SQL Server {{ $t("Query") }}</label>
<textarea id="sqlserverQuery" v-model="monitor.databaseQuery" class="form-control" placeholder="Example: select getdate()"></textarea>
<label for="sqlQuery" class="form-label">{{ $t("Query") }}</label>
<textarea id="sqlQuery" v-model="monitor.databaseQuery" class="form-control" placeholder="Example: select getdate()"></textarea>
</div>
</template>
@ -584,7 +593,6 @@ export default {
method: "GET",
interval: 60,
retryInterval: this.interval,
databaseConnectionString: "Server=<hostname>,<port>;Database=<your database>;User Id=<your user id>;Password=<your password>;Encrypt=<true/false>;TrustServerCertificate=<Yes/No>;Connection Timeout=<int>",
maxretries: 0,
notificationIDList: {},
ignoreTls: false,

@ -153,6 +153,10 @@ export default {
this.settings.tlsExpiryNotifyDays = [ 7, 14, 21 ];
}
if (this.settings.trustProxy === undefined) {
this.settings.trustProxy = false;
}
this.settingsLoaded = true;
});
},

Loading…
Cancel
Save