mirror of
https://github.com/NginxProxyManager/nginx-proxy-manager.git
synced 2026-01-21 19:25:43 +00:00
Compare commits
37 Commits
dependabot
...
develop
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7747db994d | ||
|
|
9ffced265b | ||
|
|
131e5fea4f | ||
|
|
4e412f18bb | ||
|
|
bb0a50eccb | ||
|
|
4185665570 | ||
|
|
9ea6fee3ce | ||
|
|
7ee9a3c9f0 | ||
|
|
afb196e5b6 | ||
|
|
0b464ac9fd | ||
|
|
7b3c1fd061 | ||
|
|
ee42202348 | ||
|
|
c1ad7788f1 | ||
|
|
d33bb02c74 | ||
|
|
462c134751 | ||
|
|
b7dfaddbb1 | ||
|
|
11ee4f0820 | ||
|
|
19970a4220 | ||
|
|
3e3396ba9a | ||
|
|
6c0ea835ce | ||
|
|
f0c0b465d9 | ||
|
|
6c2f6a9d39 | ||
|
|
2f6e3ad804 | ||
|
|
c9f453714b | ||
|
|
7fe5070337 | ||
|
|
073ee95e56 | ||
|
|
168078eb40 | ||
|
|
2c9f8f4d64 | ||
|
|
8403a0c761 | ||
|
|
927e57257b | ||
|
|
56875bba52 | ||
|
|
b55f51bd63 | ||
|
|
86b7394620 | ||
|
|
91a1f39c02 | ||
|
|
5c114e9db7 | ||
|
|
fec9bffe29 | ||
|
|
847c58b170 |
@@ -1,7 +1,7 @@
|
|||||||
<p align="center">
|
<p align="center">
|
||||||
<img src="https://nginxproxymanager.com/github.png">
|
<img src="https://nginxproxymanager.com/github.png">
|
||||||
<br><br>
|
<br><br>
|
||||||
<img src="https://img.shields.io/badge/version-2.13.5-green.svg?style=for-the-badge">
|
<img src="https://img.shields.io/badge/version-2.13.6-green.svg?style=for-the-badge">
|
||||||
<a href="https://hub.docker.com/repository/docker/jc21/nginx-proxy-manager">
|
<a href="https://hub.docker.com/repository/docker/jc21/nginx-proxy-manager">
|
||||||
<img src="https://img.shields.io/docker/stars/jc21/nginx-proxy-manager.svg?style=for-the-badge">
|
<img src="https://img.shields.io/docker/stars/jc21/nginx-proxy-manager.svg?style=for-the-badge">
|
||||||
</a>
|
</a>
|
||||||
|
|||||||
@@ -74,7 +74,7 @@
|
|||||||
"cloudns": {
|
"cloudns": {
|
||||||
"name": "ClouDNS",
|
"name": "ClouDNS",
|
||||||
"package_name": "certbot-dns-cloudns",
|
"package_name": "certbot-dns-cloudns",
|
||||||
"version": "~=0.6.0",
|
"version": "~=0.7.0",
|
||||||
"dependencies": "",
|
"dependencies": "",
|
||||||
"credentials": "# Target user ID (see https://www.cloudns.net/api-settings/)\n\tdns_cloudns_auth_id=1234\n\t# Alternatively, one of the following two options can be set:\n\t# dns_cloudns_sub_auth_id=1234\n\t# dns_cloudns_sub_auth_user=foobar\n\n\t# API password\n\tdns_cloudns_auth_password=password1",
|
"credentials": "# Target user ID (see https://www.cloudns.net/api-settings/)\n\tdns_cloudns_auth_id=1234\n\t# Alternatively, one of the following two options can be set:\n\t# dns_cloudns_sub_auth_id=1234\n\t# dns_cloudns_sub_auth_user=foobar\n\n\t# API password\n\tdns_cloudns_auth_password=password1",
|
||||||
"full_plugin_name": "dns-cloudns"
|
"full_plugin_name": "dns-cloudns"
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
import bcrypt from "bcrypt";
|
|
||||||
import crypto from "node:crypto";
|
import crypto from "node:crypto";
|
||||||
|
import bcrypt from "bcrypt";
|
||||||
import { authenticator } from "otplib";
|
import { authenticator } from "otplib";
|
||||||
import authModel from "../models/auth.js";
|
|
||||||
import userModel from "../models/user.js";
|
|
||||||
import errs from "../lib/error.js";
|
import errs from "../lib/error.js";
|
||||||
|
import authModel from "../models/auth.js";
|
||||||
|
import internalUser from "./user.js";
|
||||||
|
|
||||||
const APP_NAME = "Nginx Proxy Manager";
|
const APP_NAME = "Nginx Proxy Manager";
|
||||||
const BACKUP_CODE_COUNT = 8;
|
const BACKUP_CODE_COUNT = 8;
|
||||||
@@ -26,38 +26,7 @@ const generateBackupCodes = async () => {
|
|||||||
return { plain, hashed };
|
return { plain, hashed };
|
||||||
};
|
};
|
||||||
|
|
||||||
export default {
|
const internal2fa = {
|
||||||
/**
|
|
||||||
* Generate a new TOTP secret
|
|
||||||
* @returns {string}
|
|
||||||
*/
|
|
||||||
generateSecret: () => {
|
|
||||||
return authenticator.generateSecret();
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Generate otpauth URL for QR code
|
|
||||||
* @param {string} email
|
|
||||||
* @param {string} secret
|
|
||||||
* @returns {string}
|
|
||||||
*/
|
|
||||||
generateOTPAuthURL: (email, secret) => {
|
|
||||||
return authenticator.keyuri(email, APP_NAME, secret);
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Verify a TOTP code
|
|
||||||
* @param {string} secret
|
|
||||||
* @param {string} code
|
|
||||||
* @returns {boolean}
|
|
||||||
*/
|
|
||||||
verifyCode: (secret, code) => {
|
|
||||||
try {
|
|
||||||
return authenticator.verify({ token: code, secret });
|
|
||||||
} catch {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if user has 2FA enabled
|
* Check if user has 2FA enabled
|
||||||
@@ -65,94 +34,85 @@ export default {
|
|||||||
* @returns {Promise<boolean>}
|
* @returns {Promise<boolean>}
|
||||||
*/
|
*/
|
||||||
isEnabled: async (userId) => {
|
isEnabled: async (userId) => {
|
||||||
const auth = await authModel
|
const auth = await internal2fa.getUserPasswordAuth(userId);
|
||||||
.query()
|
return auth?.meta?.totp_enabled === true;
|
||||||
.where("user_id", userId)
|
|
||||||
.where("type", "password")
|
|
||||||
.first();
|
|
||||||
|
|
||||||
if (!auth || !auth.meta) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return auth.meta.totp_enabled === true;
|
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get 2FA status for user
|
* Get 2FA status for user
|
||||||
* @param {number} userId
|
* @param {Access} access
|
||||||
* @returns {Promise<{enabled: boolean, backupCodesRemaining: number}>}
|
* @param {number} userId
|
||||||
|
* @returns {Promise<{enabled: boolean, backup_codes_remaining: number}>}
|
||||||
*/
|
*/
|
||||||
getStatus: async (userId) => {
|
getStatus: async (access, userId) => {
|
||||||
const auth = await authModel
|
await access.can("users:password", userId);
|
||||||
.query()
|
await internalUser.get(access, { id: userId });
|
||||||
.where("user_id", userId)
|
const auth = await internal2fa.getUserPasswordAuth(userId);
|
||||||
.where("type", "password")
|
const enabled = auth?.meta?.totp_enabled === true;
|
||||||
.first();
|
let backup_codes_remaining = 0;
|
||||||
|
|
||||||
if (!auth || !auth.meta || !auth.meta.totp_enabled) {
|
if (enabled) {
|
||||||
return { enabled: false, backupCodesRemaining: 0 };
|
const backupCodes = auth.meta.backup_codes || [];
|
||||||
|
backup_codes_remaining = backupCodes.length;
|
||||||
}
|
}
|
||||||
|
|
||||||
const backupCodes = auth.meta.backup_codes || [];
|
|
||||||
return {
|
return {
|
||||||
enabled: true,
|
enabled,
|
||||||
backupCodesRemaining: backupCodes.length,
|
backup_codes_remaining,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Start 2FA setup - store pending secret
|
* Start 2FA setup - store pending secret
|
||||||
* @param {number} userId
|
*
|
||||||
* @returns {Promise<{secret: string, otpauthUrl: string}>}
|
* @param {Access} access
|
||||||
|
* @param {number} userId
|
||||||
|
* @returns {Promise<{secret: string, otpauth_url: string}>}
|
||||||
*/
|
*/
|
||||||
startSetup: async (userId) => {
|
startSetup: async (access, userId) => {
|
||||||
const user = await userModel.query().where("id", userId).first();
|
await access.can("users:password", userId);
|
||||||
if (!user) {
|
const user = await internalUser.get(access, { id: userId });
|
||||||
throw new errs.ItemNotFoundError("User not found");
|
|
||||||
}
|
|
||||||
|
|
||||||
const secret = authenticator.generateSecret();
|
const secret = authenticator.generateSecret();
|
||||||
const otpauthUrl = authenticator.keyuri(user.email, APP_NAME, secret);
|
const otpauth_url = authenticator.keyuri(user.email, APP_NAME, secret);
|
||||||
|
const auth = await internal2fa.getUserPasswordAuth(userId);
|
||||||
|
|
||||||
const auth = await authModel
|
// ensure user isn't already setup for 2fa
|
||||||
.query()
|
const enabled = auth?.meta?.totp_enabled === true;
|
||||||
.where("user_id", userId)
|
if (enabled) {
|
||||||
.where("type", "password")
|
throw new errs.ValidationError("2FA is already enabled");
|
||||||
.first();
|
|
||||||
|
|
||||||
if (!auth) {
|
|
||||||
throw new errs.ItemNotFoundError("Auth record not found");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const meta = auth.meta || {};
|
const meta = auth.meta || {};
|
||||||
meta.totp_pending_secret = secret;
|
meta.totp_pending_secret = secret;
|
||||||
|
|
||||||
await authModel.query().where("id", auth.id).patch({ meta });
|
await authModel.query()
|
||||||
|
.where("id", auth.id)
|
||||||
|
.andWhere("user_id", userId)
|
||||||
|
.andWhere("type", "password")
|
||||||
|
.patch({ meta });
|
||||||
|
|
||||||
return { secret, otpauthUrl };
|
return { secret, otpauth_url };
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Enable 2FA after verifying code
|
* Enable 2FA after verifying code
|
||||||
* @param {number} userId
|
*
|
||||||
* @param {string} code
|
* @param {Access} access
|
||||||
* @returns {Promise<{backupCodes: string[]}>}
|
* @param {number} userId
|
||||||
|
* @param {string} code
|
||||||
|
* @returns {Promise<{backup_codes: string[]}>}
|
||||||
*/
|
*/
|
||||||
enable: async (userId, code) => {
|
enable: async (access, userId, code) => {
|
||||||
const auth = await authModel
|
await access.can("users:password", userId);
|
||||||
.query()
|
await internalUser.get(access, { id: userId });
|
||||||
.where("user_id", userId)
|
const auth = await internal2fa.getUserPasswordAuth(userId);
|
||||||
.where("type", "password")
|
const secret = auth?.meta?.totp_pending_secret || false;
|
||||||
.first();
|
|
||||||
|
|
||||||
if (!auth || !auth.meta || !auth.meta.totp_pending_secret) {
|
if (!secret) {
|
||||||
throw new errs.ValidationError("No pending 2FA setup found");
|
throw new errs.ValidationError("No pending 2FA setup found");
|
||||||
}
|
}
|
||||||
|
|
||||||
const secret = auth.meta.totp_pending_secret;
|
|
||||||
const valid = authenticator.verify({ token: code, secret });
|
const valid = authenticator.verify({ token: code, secret });
|
||||||
|
|
||||||
if (!valid) {
|
if (!valid) {
|
||||||
throw new errs.ValidationError("Invalid verification code");
|
throw new errs.ValidationError("Invalid verification code");
|
||||||
}
|
}
|
||||||
@@ -168,25 +128,31 @@ export default {
|
|||||||
};
|
};
|
||||||
delete meta.totp_pending_secret;
|
delete meta.totp_pending_secret;
|
||||||
|
|
||||||
await authModel.query().where("id", auth.id).patch({ meta });
|
await authModel
|
||||||
|
.query()
|
||||||
|
.where("id", auth.id)
|
||||||
|
.andWhere("user_id", userId)
|
||||||
|
.andWhere("type", "password")
|
||||||
|
.patch({ meta });
|
||||||
|
|
||||||
return { backupCodes: plain };
|
return { backup_codes: plain };
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Disable 2FA
|
* Disable 2FA
|
||||||
* @param {number} userId
|
*
|
||||||
* @param {string} code
|
* @param {Access} access
|
||||||
|
* @param {number} userId
|
||||||
|
* @param {string} code
|
||||||
* @returns {Promise<void>}
|
* @returns {Promise<void>}
|
||||||
*/
|
*/
|
||||||
disable: async (userId, code) => {
|
disable: async (access, userId, code) => {
|
||||||
const auth = await authModel
|
await access.can("users:password", userId);
|
||||||
.query()
|
await internalUser.get(access, { id: userId });
|
||||||
.where("user_id", userId)
|
const auth = await internal2fa.getUserPasswordAuth(userId);
|
||||||
.where("type", "password")
|
|
||||||
.first();
|
|
||||||
|
|
||||||
if (!auth || !auth.meta || !auth.meta.totp_enabled) {
|
const enabled = auth?.meta?.totp_enabled === true;
|
||||||
|
if (!enabled) {
|
||||||
throw new errs.ValidationError("2FA is not enabled");
|
throw new errs.ValidationError("2FA is not enabled");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -196,7 +162,7 @@ export default {
|
|||||||
});
|
});
|
||||||
|
|
||||||
if (!valid) {
|
if (!valid) {
|
||||||
throw new errs.ValidationError("Invalid verification code");
|
throw new errs.AuthError("Invalid verification code");
|
||||||
}
|
}
|
||||||
|
|
||||||
const meta = { ...auth.meta };
|
const meta = { ...auth.meta };
|
||||||
@@ -205,30 +171,33 @@ export default {
|
|||||||
delete meta.totp_enabled_at;
|
delete meta.totp_enabled_at;
|
||||||
delete meta.backup_codes;
|
delete meta.backup_codes;
|
||||||
|
|
||||||
await authModel.query().where("id", auth.id).patch({ meta });
|
await authModel
|
||||||
|
.query()
|
||||||
|
.where("id", auth.id)
|
||||||
|
.andWhere("user_id", userId)
|
||||||
|
.andWhere("type", "password")
|
||||||
|
.patch({ meta });
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Verify 2FA code for login
|
* Verify 2FA code for login
|
||||||
* @param {number} userId
|
*
|
||||||
* @param {string} code
|
* @param {number} userId
|
||||||
|
* @param {string} token
|
||||||
* @returns {Promise<boolean>}
|
* @returns {Promise<boolean>}
|
||||||
*/
|
*/
|
||||||
verifyForLogin: async (userId, code) => {
|
verifyForLogin: async (userId, token) => {
|
||||||
const auth = await authModel
|
const auth = await internal2fa.getUserPasswordAuth(userId);
|
||||||
.query()
|
const secret = auth?.meta?.totp_secret || false;
|
||||||
.where("user_id", userId)
|
|
||||||
.where("type", "password")
|
|
||||||
.first();
|
|
||||||
|
|
||||||
if (!auth || !auth.meta || !auth.meta.totp_secret) {
|
if (!secret) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try TOTP code first
|
// Try TOTP code first
|
||||||
const valid = authenticator.verify({
|
const valid = authenticator.verify({
|
||||||
token: code,
|
token,
|
||||||
secret: auth.meta.totp_secret,
|
secret,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (valid) {
|
if (valid) {
|
||||||
@@ -236,7 +205,7 @@ export default {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Try backup codes
|
// Try backup codes
|
||||||
const backupCodes = auth.meta.backup_codes || [];
|
const backupCodes = auth?.meta?.backup_codes || [];
|
||||||
for (let i = 0; i < backupCodes.length; i++) {
|
for (let i = 0; i < backupCodes.length; i++) {
|
||||||
const match = await bcrypt.compare(code.toUpperCase(), backupCodes[i]);
|
const match = await bcrypt.compare(code.toUpperCase(), backupCodes[i]);
|
||||||
if (match) {
|
if (match) {
|
||||||
@@ -244,7 +213,12 @@ export default {
|
|||||||
const updatedCodes = [...backupCodes];
|
const updatedCodes = [...backupCodes];
|
||||||
updatedCodes.splice(i, 1);
|
updatedCodes.splice(i, 1);
|
||||||
const meta = { ...auth.meta, backup_codes: updatedCodes };
|
const meta = { ...auth.meta, backup_codes: updatedCodes };
|
||||||
await authModel.query().where("id", auth.id).patch({ meta });
|
await authModel
|
||||||
|
.query()
|
||||||
|
.where("id", auth.id)
|
||||||
|
.andWhere("user_id", userId)
|
||||||
|
.andWhere("type", "password")
|
||||||
|
.patch({ meta });
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -254,24 +228,29 @@ export default {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Regenerate backup codes
|
* Regenerate backup codes
|
||||||
* @param {number} userId
|
*
|
||||||
* @param {string} code
|
* @param {Access} access
|
||||||
* @returns {Promise<{backupCodes: string[]}>}
|
* @param {number} userId
|
||||||
|
* @param {string} token
|
||||||
|
* @returns {Promise<{backup_codes: string[]}>}
|
||||||
*/
|
*/
|
||||||
regenerateBackupCodes: async (userId, code) => {
|
regenerateBackupCodes: async (access, userId, token) => {
|
||||||
const auth = await authModel
|
await access.can("users:password", userId);
|
||||||
.query()
|
await internalUser.get(access, { id: userId });
|
||||||
.where("user_id", userId)
|
const auth = await internal2fa.getUserPasswordAuth(userId);
|
||||||
.where("type", "password")
|
const enabled = auth?.meta?.totp_enabled === true;
|
||||||
.first();
|
const secret = auth?.meta?.totp_secret || false;
|
||||||
|
|
||||||
if (!auth || !auth.meta || !auth.meta.totp_enabled) {
|
if (!enabled) {
|
||||||
throw new errs.ValidationError("2FA is not enabled");
|
throw new errs.ValidationError("2FA is not enabled");
|
||||||
}
|
}
|
||||||
|
if (!secret) {
|
||||||
|
throw new errs.ValidationError("No 2FA secret found");
|
||||||
|
}
|
||||||
|
|
||||||
const valid = authenticator.verify({
|
const valid = authenticator.verify({
|
||||||
token: code,
|
token,
|
||||||
secret: auth.meta.totp_secret,
|
secret,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!valid) {
|
if (!valid) {
|
||||||
@@ -281,8 +260,29 @@ export default {
|
|||||||
const { plain, hashed } = await generateBackupCodes();
|
const { plain, hashed } = await generateBackupCodes();
|
||||||
|
|
||||||
const meta = { ...auth.meta, backup_codes: hashed };
|
const meta = { ...auth.meta, backup_codes: hashed };
|
||||||
await authModel.query().where("id", auth.id).patch({ meta });
|
await authModel
|
||||||
|
.query()
|
||||||
|
.where("id", auth.id)
|
||||||
|
.andWhere("user_id", userId)
|
||||||
|
.andWhere("type", "password")
|
||||||
|
.patch({ meta });
|
||||||
|
|
||||||
return { backupCodes: plain };
|
return { backup_codes: plain };
|
||||||
|
},
|
||||||
|
|
||||||
|
getUserPasswordAuth: async (userId) => {
|
||||||
|
const auth = await authModel
|
||||||
|
.query()
|
||||||
|
.where("user_id", userId)
|
||||||
|
.andWhere("type", "password")
|
||||||
|
.first();
|
||||||
|
|
||||||
|
if (!auth) {
|
||||||
|
throw new errs.ItemNotFoundError("Auth not found");
|
||||||
|
}
|
||||||
|
|
||||||
|
return auth;
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export default internal2fa;
|
||||||
|
|||||||
@@ -66,16 +66,7 @@ router
|
|||||||
*/
|
*/
|
||||||
.post(async (req, res, next) => {
|
.post(async (req, res, next) => {
|
||||||
try {
|
try {
|
||||||
const { challenge_token, code } = req.body;
|
const { challenge_token, code } = await apiValidator(getValidationSchema("/tokens/2fa", "post"), req.body);
|
||||||
|
|
||||||
if (!challenge_token || !code) {
|
|
||||||
return res.status(400).json({
|
|
||||||
error: {
|
|
||||||
message: "Missing challenge_token or code",
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
const result = await internalToken.verify2FA(challenge_token, code);
|
const result = await internalToken.verify2FA(challenge_token, code);
|
||||||
res.status(200).send(result);
|
res.status(200).send(result);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
|||||||
@@ -339,6 +339,21 @@ router
|
|||||||
.all(jwtdecode())
|
.all(jwtdecode())
|
||||||
.all(userIdFromMe)
|
.all(userIdFromMe)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* POST /api/users/123/2fa
|
||||||
|
*
|
||||||
|
* Start 2FA setup, returns QR code URL
|
||||||
|
*/
|
||||||
|
.post(async (req, res, next) => {
|
||||||
|
try {
|
||||||
|
const result = await internal2FA.startSetup(res.locals.access, req.params.user_id);
|
||||||
|
res.status(200).send(result);
|
||||||
|
} catch (err) {
|
||||||
|
debug(logger, `${req.method.toUpperCase()} ${req.path}: ${err}`);
|
||||||
|
next(err);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* GET /api/users/123/2fa
|
* GET /api/users/123/2fa
|
||||||
*
|
*
|
||||||
@@ -346,15 +361,7 @@ router
|
|||||||
*/
|
*/
|
||||||
.get(async (req, res, next) => {
|
.get(async (req, res, next) => {
|
||||||
try {
|
try {
|
||||||
const userId = Number.parseInt(req.params.user_id, 10);
|
const status = await internal2FA.getStatus(res.locals.access, req.params.user_id);
|
||||||
const access = res.locals.access;
|
|
||||||
|
|
||||||
// Users can only view their own 2FA status
|
|
||||||
if (access.token.getUserId() !== userId && !access.token.hasScope("admin")) {
|
|
||||||
throw new errs.PermissionError("Cannot view 2FA status for other users");
|
|
||||||
}
|
|
||||||
|
|
||||||
const status = await internal2FA.getStatus(userId);
|
|
||||||
res.status(200).send(status);
|
res.status(200).send(status);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
debug(logger, `${req.method.toUpperCase()} ${req.path}: ${err}`);
|
debug(logger, `${req.method.toUpperCase()} ${req.path}: ${err}`);
|
||||||
@@ -363,63 +370,18 @@ router
|
|||||||
})
|
})
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* DELETE /api/users/123/2fa
|
* DELETE /api/users/123/2fa?code=XXXXXX
|
||||||
*
|
*
|
||||||
* Disable 2FA for a user
|
* Disable 2FA for a user
|
||||||
*/
|
*/
|
||||||
.delete(async (req, res, next) => {
|
.delete(async (req, res, next) => {
|
||||||
try {
|
try {
|
||||||
const userId = Number.parseInt(req.params.user_id, 10);
|
const code = typeof req.query.code === "string" ? req.query.code : null;
|
||||||
const access = res.locals.access;
|
|
||||||
|
|
||||||
// Users can only disable their own 2FA
|
|
||||||
if (access.token.getUserId() !== userId && !access.token.hasScope("admin")) {
|
|
||||||
throw new errs.PermissionError("Cannot disable 2FA for other users");
|
|
||||||
}
|
|
||||||
|
|
||||||
const { code } = req.body;
|
|
||||||
if (!code) {
|
if (!code) {
|
||||||
throw new errs.ValidationError("Verification code is required");
|
throw new errs.ValidationError("Missing required parameter: code");
|
||||||
}
|
}
|
||||||
|
await internal2FA.disable(res.locals.access, req.params.user_id, code);
|
||||||
await internal2FA.disable(userId, code);
|
res.status(200).send(true);
|
||||||
res.status(200).send({ success: true });
|
|
||||||
} catch (err) {
|
|
||||||
debug(logger, `${req.method.toUpperCase()} ${req.path}: ${err}`);
|
|
||||||
next(err);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
/**
|
|
||||||
* User 2FA setup
|
|
||||||
*
|
|
||||||
* /api/users/123/2fa/setup
|
|
||||||
*/
|
|
||||||
router
|
|
||||||
.route("/:user_id/2fa/setup")
|
|
||||||
.options((_, res) => {
|
|
||||||
res.sendStatus(204);
|
|
||||||
})
|
|
||||||
.all(jwtdecode())
|
|
||||||
.all(userIdFromMe)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* POST /api/users/123/2fa/setup
|
|
||||||
*
|
|
||||||
* Start 2FA setup, returns QR code URL
|
|
||||||
*/
|
|
||||||
.post(async (req, res, next) => {
|
|
||||||
try {
|
|
||||||
const userId = Number.parseInt(req.params.user_id, 10);
|
|
||||||
const access = res.locals.access;
|
|
||||||
|
|
||||||
// Users can only setup their own 2FA
|
|
||||||
if (access.token.getUserId() !== userId) {
|
|
||||||
throw new errs.PermissionError("Cannot setup 2FA for other users");
|
|
||||||
}
|
|
||||||
|
|
||||||
const result = await internal2FA.startSetup(userId);
|
|
||||||
res.status(200).send(result);
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
debug(logger, `${req.method.toUpperCase()} ${req.path}: ${err}`);
|
debug(logger, `${req.method.toUpperCase()} ${req.path}: ${err}`);
|
||||||
next(err);
|
next(err);
|
||||||
@@ -440,26 +402,17 @@ router
|
|||||||
.all(userIdFromMe)
|
.all(userIdFromMe)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* PUT /api/users/123/2fa/enable
|
* POST /api/users/123/2fa/enable
|
||||||
*
|
*
|
||||||
* Verify code and enable 2FA
|
* Verify code and enable 2FA
|
||||||
*/
|
*/
|
||||||
.put(async (req, res, next) => {
|
.post(async (req, res, next) => {
|
||||||
try {
|
try {
|
||||||
const userId = Number.parseInt(req.params.user_id, 10);
|
const { code } = await apiValidator(
|
||||||
const access = res.locals.access;
|
getValidationSchema("/users/{userID}/2fa/enable", "post"),
|
||||||
|
req.body,
|
||||||
// Users can only enable their own 2FA
|
);
|
||||||
if (access.token.getUserId() !== userId) {
|
const result = await internal2FA.enable(res.locals.access, req.params.user_id, code);
|
||||||
throw new errs.PermissionError("Cannot enable 2FA for other users");
|
|
||||||
}
|
|
||||||
|
|
||||||
const { code } = req.body;
|
|
||||||
if (!code) {
|
|
||||||
throw new errs.ValidationError("Verification code is required");
|
|
||||||
}
|
|
||||||
|
|
||||||
const result = await internal2FA.enable(userId, code);
|
|
||||||
res.status(200).send(result);
|
res.status(200).send(result);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
debug(logger, `${req.method.toUpperCase()} ${req.path}: ${err}`);
|
debug(logger, `${req.method.toUpperCase()} ${req.path}: ${err}`);
|
||||||
@@ -487,20 +440,11 @@ router
|
|||||||
*/
|
*/
|
||||||
.post(async (req, res, next) => {
|
.post(async (req, res, next) => {
|
||||||
try {
|
try {
|
||||||
const userId = Number.parseInt(req.params.user_id, 10);
|
const { code } = await apiValidator(
|
||||||
const access = res.locals.access;
|
getValidationSchema("/users/{userID}/2fa/backup-codes", "post"),
|
||||||
|
req.body,
|
||||||
// Users can only regenerate their own backup codes
|
);
|
||||||
if (access.token.getUserId() !== userId) {
|
const result = await internal2FA.regenerateBackupCodes(res.locals.access, req.params.user_id, code);
|
||||||
throw new errs.PermissionError("Cannot regenerate backup codes for other users");
|
|
||||||
}
|
|
||||||
|
|
||||||
const { code } = req.body;
|
|
||||||
if (!code) {
|
|
||||||
throw new errs.ValidationError("Verification code is required");
|
|
||||||
}
|
|
||||||
|
|
||||||
const result = await internal2FA.regenerateBackupCodes(userId, code);
|
|
||||||
res.status(200).send(result);
|
res.status(200).send(result);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
debug(logger, `${req.method.toUpperCase()} ${req.path}: ${err}`);
|
debug(logger, `${req.method.toUpperCase()} ${req.path}: ${err}`);
|
||||||
|
|||||||
18
backend/schema/components/token-challenge.json
Normal file
18
backend/schema/components/token-challenge.json
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
{
|
||||||
|
"type": "object",
|
||||||
|
"description": "Token object",
|
||||||
|
"required": ["requires_2fa", "challenge_token"],
|
||||||
|
"additionalProperties": false,
|
||||||
|
"properties": {
|
||||||
|
"requires_2fa": {
|
||||||
|
"description": "Whether this token request requires two-factor authentication",
|
||||||
|
"example": true,
|
||||||
|
"type": "boolean"
|
||||||
|
},
|
||||||
|
"challenge_token": {
|
||||||
|
"description": "Challenge Token used in subsequent 2FA verification",
|
||||||
|
"example": "eyJhbGciOiJSUzUxMiIsInR5cCI6IkpXVCJ9.ey...xaHKYr3Kk6MvkUjcC4",
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
55
backend/schema/paths/tokens/2fa/post.json
Normal file
55
backend/schema/paths/tokens/2fa/post.json
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
{
|
||||||
|
"operationId": "loginWith2FA",
|
||||||
|
"summary": "Verify 2FA code and get full token",
|
||||||
|
"tags": ["tokens"],
|
||||||
|
"requestBody": {
|
||||||
|
"description": "2fa Challenge Payload",
|
||||||
|
"required": true,
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"additionalProperties": false,
|
||||||
|
"properties": {
|
||||||
|
"challenge_token": {
|
||||||
|
"minLength": 1,
|
||||||
|
"type": "string",
|
||||||
|
"example": "eyJhbGciOiJSUzUxMiIsInR5cCI6IkpXVCJ9.ey...xaHKYr3Kk6MvkUjcC4"
|
||||||
|
},
|
||||||
|
"code": {
|
||||||
|
"minLength": 6,
|
||||||
|
"maxLength": 6,
|
||||||
|
"type": "string",
|
||||||
|
"example": "012345"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": ["challenge_token", "code"],
|
||||||
|
"type": "object"
|
||||||
|
},
|
||||||
|
"example": {
|
||||||
|
"challenge_token": "eyJhbGciOiJSUzUxMiIsInR5cCI6IkpXVCJ9.ey...xaHKYr3Kk6MvkUjcC4",
|
||||||
|
"code": "012345"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"examples": {
|
||||||
|
"default": {
|
||||||
|
"value": {
|
||||||
|
"expires": "2025-02-04T20:40:46.340Z",
|
||||||
|
"token": "eyJhbGciOiJSUzUxMiIsInR5cCI6IkpXVCJ9.ey...xaHKYr3Kk6MvkUjcC4"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"schema": {
|
||||||
|
"$ref": "../../../components/token-object.json"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"description": "200 response"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -50,7 +50,14 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"schema": {
|
"schema": {
|
||||||
"$ref": "../../components/token-object.json"
|
"oneOf": [
|
||||||
|
{
|
||||||
|
"$ref": "../../components/token-object.json"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"$ref": "../../components/token-challenge.json"
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|||||||
92
backend/schema/paths/users/userID/2fa/backup-codes/post.json
Normal file
92
backend/schema/paths/users/userID/2fa/backup-codes/post.json
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
{
|
||||||
|
"operationId": "regenUser2faCodes",
|
||||||
|
"summary": "Regenerate 2FA backup codes",
|
||||||
|
"tags": ["users"],
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"in": "path",
|
||||||
|
"name": "userID",
|
||||||
|
"schema": {
|
||||||
|
"type": "integer",
|
||||||
|
"minimum": 1
|
||||||
|
},
|
||||||
|
"required": true,
|
||||||
|
"description": "User ID",
|
||||||
|
"example": 2
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"requestBody": {
|
||||||
|
"description": "Verififcation Payload",
|
||||||
|
"required": true,
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"additionalProperties": false,
|
||||||
|
"properties": {
|
||||||
|
"code": {
|
||||||
|
"minLength": 6,
|
||||||
|
"maxLength": 6,
|
||||||
|
"type": "string",
|
||||||
|
"example": "123456"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": ["code"],
|
||||||
|
"type": "object"
|
||||||
|
},
|
||||||
|
"example": {
|
||||||
|
"code": "123456"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"examples": {
|
||||||
|
"default": {
|
||||||
|
"value": {
|
||||||
|
"backup_codes": [
|
||||||
|
"6CD7CB06",
|
||||||
|
"495302F3",
|
||||||
|
"D8037852",
|
||||||
|
"A6FFC956",
|
||||||
|
"BC1A1851",
|
||||||
|
"A05E644F",
|
||||||
|
"A406D2E8",
|
||||||
|
"0AE3C522"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"schema": {
|
||||||
|
"type": "object",
|
||||||
|
"required": ["backup_codes"],
|
||||||
|
"additionalProperties": false,
|
||||||
|
"properties": {
|
||||||
|
"backup_codes": {
|
||||||
|
"description": "Backup codes",
|
||||||
|
"example": [
|
||||||
|
"6CD7CB06",
|
||||||
|
"495302F3",
|
||||||
|
"D8037852",
|
||||||
|
"A6FFC956",
|
||||||
|
"BC1A1851",
|
||||||
|
"A05E644F",
|
||||||
|
"A406D2E8",
|
||||||
|
"0AE3C522"
|
||||||
|
],
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "6CD7CB06"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"description": "200 response"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
48
backend/schema/paths/users/userID/2fa/delete.json
Normal file
48
backend/schema/paths/users/userID/2fa/delete.json
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
{
|
||||||
|
"operationId": "disableUser2fa",
|
||||||
|
"summary": "Disable 2fa for user",
|
||||||
|
"tags": ["users"],
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"in": "path",
|
||||||
|
"name": "userID",
|
||||||
|
"schema": {
|
||||||
|
"type": "integer",
|
||||||
|
"minimum": 1
|
||||||
|
},
|
||||||
|
"required": true,
|
||||||
|
"description": "User ID",
|
||||||
|
"example": 2
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"in": "query",
|
||||||
|
"name": "code",
|
||||||
|
"schema": {
|
||||||
|
"type": "string",
|
||||||
|
"minLength": 6,
|
||||||
|
"maxLength": 6,
|
||||||
|
"example": "012345"
|
||||||
|
},
|
||||||
|
"required": true,
|
||||||
|
"description": "2fa Code",
|
||||||
|
"example": "012345"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"examples": {
|
||||||
|
"default": {
|
||||||
|
"value": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"schema": {
|
||||||
|
"type": "boolean"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"description": "200 response"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
92
backend/schema/paths/users/userID/2fa/enable/post.json
Normal file
92
backend/schema/paths/users/userID/2fa/enable/post.json
Normal file
@@ -0,0 +1,92 @@
|
|||||||
|
{
|
||||||
|
"operationId": "enableUser2fa",
|
||||||
|
"summary": "Verify code and enable 2FA",
|
||||||
|
"tags": ["users"],
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"in": "path",
|
||||||
|
"name": "userID",
|
||||||
|
"schema": {
|
||||||
|
"type": "integer",
|
||||||
|
"minimum": 1
|
||||||
|
},
|
||||||
|
"required": true,
|
||||||
|
"description": "User ID",
|
||||||
|
"example": 2
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"requestBody": {
|
||||||
|
"description": "Verififcation Payload",
|
||||||
|
"required": true,
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"schema": {
|
||||||
|
"additionalProperties": false,
|
||||||
|
"properties": {
|
||||||
|
"code": {
|
||||||
|
"minLength": 6,
|
||||||
|
"maxLength": 6,
|
||||||
|
"type": "string",
|
||||||
|
"example": "123456"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"required": ["code"],
|
||||||
|
"type": "object"
|
||||||
|
},
|
||||||
|
"example": {
|
||||||
|
"code": "123456"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"examples": {
|
||||||
|
"default": {
|
||||||
|
"value": {
|
||||||
|
"backup_codes": [
|
||||||
|
"6CD7CB06",
|
||||||
|
"495302F3",
|
||||||
|
"D8037852",
|
||||||
|
"A6FFC956",
|
||||||
|
"BC1A1851",
|
||||||
|
"A05E644F",
|
||||||
|
"A406D2E8",
|
||||||
|
"0AE3C522"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"schema": {
|
||||||
|
"type": "object",
|
||||||
|
"required": ["backup_codes"],
|
||||||
|
"additionalProperties": false,
|
||||||
|
"properties": {
|
||||||
|
"backup_codes": {
|
||||||
|
"description": "Backup codes",
|
||||||
|
"example": [
|
||||||
|
"6CD7CB06",
|
||||||
|
"495302F3",
|
||||||
|
"D8037852",
|
||||||
|
"A6FFC956",
|
||||||
|
"BC1A1851",
|
||||||
|
"A05E644F",
|
||||||
|
"A406D2E8",
|
||||||
|
"0AE3C522"
|
||||||
|
],
|
||||||
|
"type": "array",
|
||||||
|
"items": {
|
||||||
|
"type": "string",
|
||||||
|
"example": "6CD7CB06"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"description": "200 response"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
57
backend/schema/paths/users/userID/2fa/get.json
Normal file
57
backend/schema/paths/users/userID/2fa/get.json
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
{
|
||||||
|
"operationId": "getUser2faStatus",
|
||||||
|
"summary": "Get user 2fa Status",
|
||||||
|
"tags": ["users"],
|
||||||
|
"security": [
|
||||||
|
{
|
||||||
|
"bearerAuth": []
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"in": "path",
|
||||||
|
"name": "userID",
|
||||||
|
"schema": {
|
||||||
|
"type": "integer",
|
||||||
|
"minimum": 1
|
||||||
|
},
|
||||||
|
"required": true,
|
||||||
|
"description": "User ID",
|
||||||
|
"example": 2
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"description": "200 response",
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"examples": {
|
||||||
|
"default": {
|
||||||
|
"value": {
|
||||||
|
"enabled": false,
|
||||||
|
"backup_codes_remaining": 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"schema": {
|
||||||
|
"type": "object",
|
||||||
|
"additionalProperties": false,
|
||||||
|
"required": ["enabled", "backup_codes_remaining"],
|
||||||
|
"properties": {
|
||||||
|
"enabled": {
|
||||||
|
"type": "boolean",
|
||||||
|
"description": "Is 2FA enabled for this user",
|
||||||
|
"example": true
|
||||||
|
},
|
||||||
|
"backup_codes_remaining": {
|
||||||
|
"type": "integer",
|
||||||
|
"description": "Number of remaining backup codes for this user",
|
||||||
|
"example": 5
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
52
backend/schema/paths/users/userID/2fa/post.json
Normal file
52
backend/schema/paths/users/userID/2fa/post.json
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
{
|
||||||
|
"operationId": "setupUser2fa",
|
||||||
|
"summary": "Start 2FA setup, returns QR code URL",
|
||||||
|
"tags": ["users"],
|
||||||
|
"parameters": [
|
||||||
|
{
|
||||||
|
"in": "path",
|
||||||
|
"name": "userID",
|
||||||
|
"schema": {
|
||||||
|
"type": "integer",
|
||||||
|
"minimum": 1
|
||||||
|
},
|
||||||
|
"required": true,
|
||||||
|
"description": "User ID",
|
||||||
|
"example": 2
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"responses": {
|
||||||
|
"200": {
|
||||||
|
"content": {
|
||||||
|
"application/json": {
|
||||||
|
"examples": {
|
||||||
|
"default": {
|
||||||
|
"value": {
|
||||||
|
"secret": "JZYCEBIEEJYUGPQM",
|
||||||
|
"otpauth_url": "otpauth://totp/Nginx%20Proxy%20Manager:jc%40jc21.com?secret=JZYCEBIEEJYUGPQM&period=30&digits=6&algorithm=SHA1&issuer=Nginx%20Proxy%20Manager"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"schema": {
|
||||||
|
"type": "object",
|
||||||
|
"required": ["secret", "otpauth_url"],
|
||||||
|
"additionalProperties": false,
|
||||||
|
"properties": {
|
||||||
|
"secret": {
|
||||||
|
"description": "TOTP Secret",
|
||||||
|
"example": "JZYCEBIEEJYUGPQM",
|
||||||
|
"type": "string"
|
||||||
|
},
|
||||||
|
"otpauth_url": {
|
||||||
|
"description": "OTP Auth URL for QR Code generation",
|
||||||
|
"example": "otpauth://totp/Nginx%20Proxy%20Manager:jc%40jc21.com?secret=JZYCEBIEEJYUGPQM&period=30&digits=6&algorithm=SHA1&issuer=Nginx%20Proxy%20Manager",
|
||||||
|
"type": "string"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"description": "200 response"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -293,6 +293,11 @@
|
|||||||
"$ref": "./paths/tokens/post.json"
|
"$ref": "./paths/tokens/post.json"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"/tokens/2fa": {
|
||||||
|
"post": {
|
||||||
|
"$ref": "./paths/tokens/2fa/post.json"
|
||||||
|
}
|
||||||
|
},
|
||||||
"/version/check": {
|
"/version/check": {
|
||||||
"get": {
|
"get": {
|
||||||
"$ref": "./paths/version/check/get.json"
|
"$ref": "./paths/version/check/get.json"
|
||||||
@@ -317,6 +322,27 @@
|
|||||||
"$ref": "./paths/users/userID/delete.json"
|
"$ref": "./paths/users/userID/delete.json"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"/users/{userID}/2fa": {
|
||||||
|
"post": {
|
||||||
|
"$ref": "./paths/users/userID/2fa/post.json"
|
||||||
|
},
|
||||||
|
"get": {
|
||||||
|
"$ref": "./paths/users/userID/2fa/get.json"
|
||||||
|
},
|
||||||
|
"delete": {
|
||||||
|
"$ref": "./paths/users/userID/2fa/delete.json"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/users/{userID}/2fa/enable": {
|
||||||
|
"post": {
|
||||||
|
"$ref": "./paths/users/userID/2fa/enable/post.json"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"/users/{userID}/2fa/backup-codes": {
|
||||||
|
"post": {
|
||||||
|
"$ref": "./paths/users/userID/2fa/backup-codes/post.json"
|
||||||
|
}
|
||||||
|
},
|
||||||
"/users/{userID}/auth": {
|
"/users/{userID}/auth": {
|
||||||
"put": {
|
"put": {
|
||||||
"$ref": "./paths/users/userID/auth/put.json"
|
"$ref": "./paths/users/userID/auth/put.json"
|
||||||
|
|||||||
@@ -1,176 +0,0 @@
|
|||||||
# Two-Factor Authentication Implementation
|
|
||||||
|
|
||||||
> **Note:** This document should be deleted after PR approval. It serves as a reference for reviewers to understand the scope of the contribution.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
**Acknowledgments**
|
|
||||||
|
|
||||||
Thanks to all contributors and authors from the Inte.Team for the great work on Nginx Proxy Manager. It saves us time and effort, and we're happy to contribute back to the project.
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Overview
|
|
||||||
|
|
||||||
Add TOTP-based two-factor authentication to the login flow. Users can enable 2FA from their profile settings, scan a QR code with any authenticator app (Google Authenticator, Authy, etc.), and will be required to enter a 6-digit code on login.
|
|
||||||
|
|
||||||
## Current Authentication Flow
|
|
||||||
|
|
||||||
```
|
|
||||||
POST /tokens {identity, secret}
|
|
||||||
-> Validate user exists and is not disabled
|
|
||||||
-> Verify password against auth.secret
|
|
||||||
-> Return JWT token
|
|
||||||
```
|
|
||||||
|
|
||||||
## Proposed 2FA Flow
|
|
||||||
|
|
||||||
```
|
|
||||||
POST /tokens {identity, secret}
|
|
||||||
-> Validate user exists and is not disabled
|
|
||||||
-> Verify password against auth.secret
|
|
||||||
-> If 2FA enabled:
|
|
||||||
Return {requires_2fa: true, challenge_token: <short-lived JWT>}
|
|
||||||
-> Else:
|
|
||||||
Return {token: <JWT>, expires: <timestamp>}
|
|
||||||
|
|
||||||
POST /tokens/2fa {challenge_token, code}
|
|
||||||
-> Validate challenge_token
|
|
||||||
-> Verify TOTP code against user's secret
|
|
||||||
-> Return {token: <JWT>, expires: <timestamp>}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Database Changes
|
|
||||||
|
|
||||||
Extend the existing `auth.meta` JSON column to store 2FA data:
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"totp_secret": "<encrypted-secret>",
|
|
||||||
"totp_enabled": true,
|
|
||||||
"totp_enabled_at": "<timestamp>",
|
|
||||||
"backup_codes": ["<hashed-code-1>", "<hashed-code-2>", ...]
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
No new tables required. The `auth.meta` column is already designed for this purpose.
|
|
||||||
|
|
||||||
## Backend Changes
|
|
||||||
|
|
||||||
### New Files
|
|
||||||
|
|
||||||
1. `backend/internal/2fa.js` - Core 2FA logic
|
|
||||||
- `generateSecret()` - Generate TOTP secret
|
|
||||||
- `generateQRCodeURL(user, secret)` - Generate otpauth URL
|
|
||||||
- `verifyCode(secret, code)` - Verify TOTP code
|
|
||||||
- `generateBackupCodes()` - Generate 8 backup codes
|
|
||||||
- `verifyBackupCode(user, code)` - Verify and consume backup code
|
|
||||||
|
|
||||||
2. `backend/routes/2fa.js` - 2FA management endpoints
|
|
||||||
- `GET /users/:id/2fa` - Get 2FA status
|
|
||||||
- `POST /users/:id/2fa/setup` - Start 2FA setup, return QR code
|
|
||||||
- `PUT /users/:id/2fa/enable` - Verify code and enable 2FA
|
|
||||||
- `DELETE /users/:id/2fa` - Disable 2FA (requires code)
|
|
||||||
- `GET /users/:id/2fa/backup-codes` - View remaining backup codes count
|
|
||||||
- `POST /users/:id/2fa/backup-codes` - Regenerate backup codes
|
|
||||||
|
|
||||||
### Modified Files
|
|
||||||
|
|
||||||
1. `backend/internal/token.js`
|
|
||||||
- Update `getTokenFromEmail()` to check for 2FA
|
|
||||||
- Add `verifyTwoFactorChallenge()` function
|
|
||||||
- Add `createChallengeToken()` for short-lived 2FA tokens
|
|
||||||
|
|
||||||
2. `backend/routes/tokens.js`
|
|
||||||
- Add `POST /tokens/2fa` endpoint
|
|
||||||
|
|
||||||
3. `backend/index.js`
|
|
||||||
- Register new 2FA routes
|
|
||||||
|
|
||||||
### Dependencies
|
|
||||||
|
|
||||||
Add to `package.json`:
|
|
||||||
```json
|
|
||||||
"otplib": "^12.0.1"
|
|
||||||
```
|
|
||||||
|
|
||||||
## Frontend Changes
|
|
||||||
|
|
||||||
### New Files
|
|
||||||
|
|
||||||
1. `frontend/src/pages/Login2FA/index.tsx` - 2FA code entry page
|
|
||||||
2. `frontend/src/modals/TwoFactorSetupModal.tsx` - Setup wizard modal
|
|
||||||
3. `frontend/src/api/backend/twoFactor.ts` - 2FA API functions
|
|
||||||
4. `frontend/src/api/backend/verify2FA.ts` - Token verification
|
|
||||||
|
|
||||||
### Modified Files
|
|
||||||
|
|
||||||
1. `frontend/src/api/backend/responseTypes.ts`
|
|
||||||
- Add `TwoFactorChallengeResponse` type
|
|
||||||
- Add `TwoFactorStatusResponse` type
|
|
||||||
|
|
||||||
2. `frontend/src/context/AuthContext.tsx`
|
|
||||||
- Add `twoFactorRequired` state
|
|
||||||
- Add `challengeToken` state
|
|
||||||
- Update `login()` to handle 2FA response
|
|
||||||
- Add `verify2FA()` function
|
|
||||||
|
|
||||||
3. `frontend/src/pages/Login/index.tsx`
|
|
||||||
- Handle 2FA challenge response
|
|
||||||
- Redirect to 2FA entry when required
|
|
||||||
|
|
||||||
4. `frontend/src/pages/Settings/` (or user profile)
|
|
||||||
- Add 2FA enable/disable section
|
|
||||||
|
|
||||||
### Dependencies
|
|
||||||
|
|
||||||
Add to `package.json`:
|
|
||||||
```json
|
|
||||||
"qrcode.react": "^3.1.0"
|
|
||||||
```
|
|
||||||
|
|
||||||
## API Endpoints Summary
|
|
||||||
|
|
||||||
| Method | Endpoint | Auth | Description |
|
|
||||||
|--------|----------|------|-------------|
|
|
||||||
| POST | /tokens | No | Login (returns challenge if 2FA) |
|
|
||||||
| POST | /tokens/2fa | Challenge | Complete 2FA login |
|
|
||||||
| GET | /users/:id/2fa | JWT | Get 2FA status |
|
|
||||||
| POST | /users/:id/2fa/setup | JWT | Start setup, get QR code |
|
|
||||||
| PUT | /users/:id/2fa/enable | JWT | Verify and enable |
|
|
||||||
| DELETE | /users/:id/2fa | JWT | Disable (requires code) |
|
|
||||||
| GET | /users/:id/2fa/backup-codes | JWT | Get backup codes count |
|
|
||||||
| POST | /users/:id/2fa/backup-codes | JWT | Regenerate codes |
|
|
||||||
|
|
||||||
## Security Considerations
|
|
||||||
|
|
||||||
1. Challenge tokens expire in 5 minutes
|
|
||||||
2. TOTP secrets encrypted at rest
|
|
||||||
3. Backup codes hashed with bcrypt
|
|
||||||
4. Rate limit on 2FA attempts (5 attempts, 15 min lockout)
|
|
||||||
5. Backup codes single-use only
|
|
||||||
6. 2FA disable requires valid TOTP code
|
|
||||||
|
|
||||||
## Implementation Order
|
|
||||||
|
|
||||||
1. Backend: Add `otplib` dependency
|
|
||||||
2. Backend: Create `internal/2fa.js` module
|
|
||||||
3. Backend: Update `internal/token.js` for challenge flow
|
|
||||||
4. Backend: Add `POST /tokens/2fa` route
|
|
||||||
5. Backend: Create `routes/2fa.js` for management
|
|
||||||
6. Frontend: Add `qrcode.react` dependency
|
|
||||||
7. Frontend: Update API types and functions
|
|
||||||
8. Frontend: Update AuthContext for 2FA state
|
|
||||||
9. Frontend: Create Login2FA page
|
|
||||||
10. Frontend: Update Login to handle 2FA
|
|
||||||
11. Frontend: Add 2FA settings UI
|
|
||||||
|
|
||||||
## Testing
|
|
||||||
|
|
||||||
1. Enable 2FA for user
|
|
||||||
2. Login with password only - should get challenge
|
|
||||||
3. Submit correct TOTP - should get token
|
|
||||||
4. Submit wrong TOTP - should fail
|
|
||||||
5. Use backup code - should work once
|
|
||||||
6. Disable 2FA - should require valid code
|
|
||||||
7. Login after disable - should work without 2FA
|
|
||||||
@@ -10,6 +10,7 @@ const allLocales = [
|
|||||||
["en", "en-US"],
|
["en", "en-US"],
|
||||||
["de", "de-DE"],
|
["de", "de-DE"],
|
||||||
["es", "es-ES"],
|
["es", "es-ES"],
|
||||||
|
["fr", "fr-FR"],
|
||||||
["it", "it-IT"],
|
["it", "it-IT"],
|
||||||
["ja", "ja-JP"],
|
["ja", "ja-JP"],
|
||||||
["nl", "nl-NL"],
|
["nl", "nl-NL"],
|
||||||
@@ -21,6 +22,7 @@ const allLocales = [
|
|||||||
["ko", "ko-KR"],
|
["ko", "ko-KR"],
|
||||||
["bg", "bg-BG"],
|
["bg", "bg-BG"],
|
||||||
["id", "id-ID"],
|
["id", "id-ID"],
|
||||||
|
["tr", "tr-TR"],
|
||||||
];
|
];
|
||||||
|
|
||||||
const ignoreUnused = [
|
const ignoreUnused = [
|
||||||
|
|||||||
@@ -156,7 +156,6 @@ export async function del({ url, params }: DeleteArgs, abortController?: AbortCo
|
|||||||
const method = "DELETE";
|
const method = "DELETE";
|
||||||
const headers = {
|
const headers = {
|
||||||
...buildAuthHeader(),
|
...buildAuthHeader(),
|
||||||
[contentTypeHeader]: "application/json",
|
|
||||||
};
|
};
|
||||||
const signal = abortController?.signal;
|
const signal = abortController?.signal;
|
||||||
const response = await fetch(apiUrl, { method, headers, signal });
|
const response = await fetch(apiUrl, { method, headers, signal });
|
||||||
|
|||||||
@@ -1,11 +1,5 @@
|
|||||||
import { camelizeKeys, decamelizeKeys } from "humps";
|
|
||||||
import AuthStore from "src/modules/AuthStore";
|
|
||||||
import type {
|
|
||||||
TwoFactorEnableResponse,
|
|
||||||
TwoFactorSetupResponse,
|
|
||||||
TwoFactorStatusResponse,
|
|
||||||
} from "./responseTypes";
|
|
||||||
import * as api from "./base";
|
import * as api from "./base";
|
||||||
|
import type { TwoFactorEnableResponse, TwoFactorSetupResponse, TwoFactorStatusResponse } from "./responseTypes";
|
||||||
|
|
||||||
export async function get2FAStatus(userId: number | "me"): Promise<TwoFactorStatusResponse> {
|
export async function get2FAStatus(userId: number | "me"): Promise<TwoFactorStatusResponse> {
|
||||||
return await api.get({
|
return await api.get({
|
||||||
@@ -15,42 +9,27 @@ export async function get2FAStatus(userId: number | "me"): Promise<TwoFactorStat
|
|||||||
|
|
||||||
export async function start2FASetup(userId: number | "me"): Promise<TwoFactorSetupResponse> {
|
export async function start2FASetup(userId: number | "me"): Promise<TwoFactorSetupResponse> {
|
||||||
return await api.post({
|
return await api.post({
|
||||||
url: `/users/${userId}/2fa/setup`,
|
url: `/users/${userId}/2fa`,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function enable2FA(userId: number | "me", code: string): Promise<TwoFactorEnableResponse> {
|
export async function enable2FA(userId: number | "me", code: string): Promise<TwoFactorEnableResponse> {
|
||||||
return await api.put({
|
return await api.post({
|
||||||
url: `/users/${userId}/2fa/enable`,
|
url: `/users/${userId}/2fa/enable`,
|
||||||
data: { code },
|
data: { code },
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function disable2FA(userId: number | "me", code: string): Promise<{ success: boolean }> {
|
export async function disable2FA(userId: number | "me", code: string): Promise<boolean> {
|
||||||
const headers: Record<string, string> = {
|
return await api.del({
|
||||||
"Content-Type": "application/json",
|
url: `/users/${userId}/2fa`,
|
||||||
};
|
params: {
|
||||||
if (AuthStore.token) {
|
code,
|
||||||
headers.Authorization = `Bearer ${AuthStore.token.token}`;
|
},
|
||||||
}
|
|
||||||
|
|
||||||
const response = await fetch(`/api/users/${userId}/2fa`, {
|
|
||||||
method: "DELETE",
|
|
||||||
headers,
|
|
||||||
body: JSON.stringify(decamelizeKeys({ code })),
|
|
||||||
});
|
});
|
||||||
|
|
||||||
const payload = await response.json();
|
|
||||||
if (!response.ok) {
|
|
||||||
throw new Error(payload.error?.messageI18n || payload.error?.message || "Failed to disable 2FA");
|
|
||||||
}
|
|
||||||
return camelizeKeys(payload) as { success: boolean };
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function regenerateBackupCodes(
|
export async function regenerateBackupCodes(userId: number | "me", code: string): Promise<TwoFactorEnableResponse> {
|
||||||
userId: number | "me",
|
|
||||||
code: string,
|
|
||||||
): Promise<TwoFactorEnableResponse> {
|
|
||||||
return await api.post({
|
return await api.post({
|
||||||
url: `/users/${userId}/2fa/backup-codes`,
|
url: `/users/${userId}/2fa/backup-codes`,
|
||||||
data: { code },
|
data: { code },
|
||||||
|
|||||||
@@ -1,19 +1,22 @@
|
|||||||
import { createIntl, createIntlCache } from "react-intl";
|
import { createIntl, createIntlCache } from "react-intl";
|
||||||
|
import langBg from "./lang/bg.json";
|
||||||
import langDe from "./lang/de.json";
|
import langDe from "./lang/de.json";
|
||||||
import langEn from "./lang/en.json";
|
import langEn from "./lang/en.json";
|
||||||
import langEs from "./lang/es.json";
|
import langEs from "./lang/es.json";
|
||||||
|
import langFr from "./lang/fr.json";
|
||||||
|
import langGa from "./lang/ga.json";
|
||||||
|
import langId from "./lang/id.json";
|
||||||
import langIt from "./lang/it.json";
|
import langIt from "./lang/it.json";
|
||||||
import langJa from "./lang/ja.json";
|
import langJa from "./lang/ja.json";
|
||||||
import langList from "./lang/lang-list.json";
|
import langKo from "./lang/ko.json";
|
||||||
import langNl from "./lang/nl.json";
|
import langNl from "./lang/nl.json";
|
||||||
import langPl from "./lang/pl.json";
|
import langPl from "./lang/pl.json";
|
||||||
import langRu from "./lang/ru.json";
|
import langRu from "./lang/ru.json";
|
||||||
import langSk from "./lang/sk.json";
|
import langSk from "./lang/sk.json";
|
||||||
import langVi from "./lang/vi.json";
|
import langVi from "./lang/vi.json";
|
||||||
import langZh from "./lang/zh.json";
|
import langZh from "./lang/zh.json";
|
||||||
import langKo from "./lang/ko.json";
|
import langTr from "./lang/tr.json";
|
||||||
import langBg from "./lang/bg.json";
|
import langList from "./lang/lang-list.json";
|
||||||
import langId from "./lang/id.json";
|
|
||||||
|
|
||||||
// first item of each array should be the language code,
|
// first item of each array should be the language code,
|
||||||
// not the country code
|
// not the country code
|
||||||
@@ -22,6 +25,8 @@ const localeOptions = [
|
|||||||
["en", "en-US", langEn],
|
["en", "en-US", langEn],
|
||||||
["de", "de-DE", langDe],
|
["de", "de-DE", langDe],
|
||||||
["es", "es-ES", langEs],
|
["es", "es-ES", langEs],
|
||||||
|
["fr", "fr-FR", langFr],
|
||||||
|
["ga", "ga-IE", langGa],
|
||||||
["ja", "ja-JP", langJa],
|
["ja", "ja-JP", langJa],
|
||||||
["it", "it-IT", langIt],
|
["it", "it-IT", langIt],
|
||||||
["nl", "nl-NL", langNl],
|
["nl", "nl-NL", langNl],
|
||||||
@@ -33,6 +38,7 @@ const localeOptions = [
|
|||||||
["ko", "ko-KR", langKo],
|
["ko", "ko-KR", langKo],
|
||||||
["bg", "bg-BG", langBg],
|
["bg", "bg-BG", langBg],
|
||||||
["id", "id-ID", langId],
|
["id", "id-ID", langId],
|
||||||
|
["tr", "tr-TR", langTr],
|
||||||
];
|
];
|
||||||
|
|
||||||
const loadMessages = (locale?: string): typeof langList & typeof langEn => {
|
const loadMessages = (locale?: string): typeof langList & typeof langEn => {
|
||||||
@@ -121,6 +127,6 @@ const T = ({
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
console.log("L:", localeOptions);
|
//console.log("L:", localeOptions);
|
||||||
|
|
||||||
export { localeOptions, getFlagCodeForLocale, getLocale, createIntl, changeLocale, intl, T };
|
export { localeOptions, getFlagCodeForLocale, getLocale, createIntl, changeLocale, intl, T };
|
||||||
|
|||||||
69
frontend/src/locale/scripts/locale-sort.cjs
Normal file
69
frontend/src/locale/scripts/locale-sort.cjs
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
#!/usr/bin/env node
|
||||||
|
|
||||||
|
const fs = require("fs");
|
||||||
|
const path = require("path");
|
||||||
|
|
||||||
|
const DIR = path.resolve(__dirname, "../src");
|
||||||
|
|
||||||
|
// Function to sort object keys recursively
|
||||||
|
function sortKeys(obj) {
|
||||||
|
if (obj === null || typeof obj !== "object" || obj instanceof Array) {
|
||||||
|
return obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
const sorted = {};
|
||||||
|
const keys = Object.keys(obj).sort();
|
||||||
|
for (const key of keys) {
|
||||||
|
const value = obj[key];
|
||||||
|
if (typeof value === "object" && value !== null && !(value instanceof Array)) {
|
||||||
|
sorted[key] = sortKeys(value);
|
||||||
|
} else {
|
||||||
|
sorted[key] = value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return sorted;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get all JSON files in the directory
|
||||||
|
const files = fs.readdirSync(DIR).filter((file) => {
|
||||||
|
return file.endsWith(".json") && file !== "lang-list.json";
|
||||||
|
});
|
||||||
|
|
||||||
|
files.forEach((file) => {
|
||||||
|
const filePath = path.join(DIR, file);
|
||||||
|
const stats = fs.statSync(filePath);
|
||||||
|
|
||||||
|
if (!stats.isFile()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (stats.size === 0) {
|
||||||
|
console.log(`Skipping empty file ${file}`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Read original content
|
||||||
|
const originalContent = fs.readFileSync(filePath, "utf8");
|
||||||
|
const originalJson = JSON.parse(originalContent);
|
||||||
|
|
||||||
|
// Sort keys
|
||||||
|
const sortedJson = sortKeys(originalJson);
|
||||||
|
|
||||||
|
// Convert back to string with tabs
|
||||||
|
const sortedContent = JSON.stringify(sortedJson, null, "\t") + "\n";
|
||||||
|
|
||||||
|
// Compare (normalize whitespace)
|
||||||
|
if (originalContent.trim() === sortedContent.trim()) {
|
||||||
|
console.log(`${file} is already sorted`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write sorted content
|
||||||
|
fs.writeFileSync(filePath, sortedContent, "utf8");
|
||||||
|
console.log(`Sorted ${file}`);
|
||||||
|
} catch (error) {
|
||||||
|
console.error(`Error processing ${file}:`, error.message);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
7
frontend/src/locale/src/HelpDoc/fr/AccessLists.md
Normal file
7
frontend/src/locale/src/HelpDoc/fr/AccessLists.md
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
## Qu'est-ce qu'une liste d'accès ?
|
||||||
|
|
||||||
|
Les listes d'accès permettent de définir une liste noire ou une liste blanche d'adresses IP clientes spécifiques, ainsi que l'authentification des Hôtes Proxy via l'authentification HTTP de base.
|
||||||
|
|
||||||
|
Vous pouvez configurer plusieurs règles client, noms d'utilisateur et mots de passe pour une même liste d'accès, puis l'appliquer à un ou plusieurs Hôtes Proxy.
|
||||||
|
|
||||||
|
Ceci est particulièrement utile pour les services web redirigés qui ne disposent pas de mécanismes d'authentification intégrés ou lorsque vous souhaitez vous protéger contre les clients inconnus.
|
||||||
23
frontend/src/locale/src/HelpDoc/fr/Certificates.md
Normal file
23
frontend/src/locale/src/HelpDoc/fr/Certificates.md
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
## Aide concernant les certificats
|
||||||
|
|
||||||
|
### Certificat HTTP
|
||||||
|
|
||||||
|
Un certificat HTTP validé signifie que les serveurs de Let's Encrypt testeront d'accéder à vos domaines via HTTP (et non HTTPS !). En cas de succès, ils émettront votre certificat.
|
||||||
|
|
||||||
|
Pour cette méthode, vous devrez créer un Hôte Proxy pour votre ou vos domaines. Cet Hôte Proxy devra être accessible via HTTP et pointer vers cette installation Nginx. Une fois le certificat émis, vous pourrez modifier l'Hôte Proxy pour qu'il utilise également ce certificat pour les connexions HTTPS. Cependant, l'Hôte Proxy devra toujours être configuré pour l'accès HTTP afin que le certificat puisse être renouvelé.
|
||||||
|
|
||||||
|
Ce processus ne prend pas en charge les domaines génériques.
|
||||||
|
|
||||||
|
### Certificat DNS
|
||||||
|
|
||||||
|
Un certificat DNS validé nécessite l'utilisation du plugin Fournisseur DNS. Fournisseur DNS créera des enregistrements temporaires sur votre domaine. Let's Encrypt interrogera ensuite ces enregistrements pour vérifier que vous en êtes bien le propriétaire. En cas de succès, votre certificat sera émis.
|
||||||
|
|
||||||
|
Il n'est pas nécessaire de créer un Hôte Proxy avant de demander ce type de certificat.
|
||||||
|
|
||||||
|
Il n'est pas non plus nécessaire de configurer votre Hôte Proxy pour l'accès HTTP.
|
||||||
|
|
||||||
|
Ce processus prend en charge les domaines génériques.
|
||||||
|
|
||||||
|
## Certificat personnalisé
|
||||||
|
|
||||||
|
Utilisez cette option pour importer votre propre certificat SSL, fourni par votre autorité de certification.
|
||||||
7
frontend/src/locale/src/HelpDoc/fr/DeadHosts.md
Normal file
7
frontend/src/locale/src/HelpDoc/fr/DeadHosts.md
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
## Qu'est-ce qu'un serveur 404 ?
|
||||||
|
|
||||||
|
Un Hôte 404 est simplement un hôte configuré pour afficher une page 404.
|
||||||
|
|
||||||
|
Cela peut s'avérer utile lorsque votre domaine est indexé par les moteurs de recherche et que vous souhaitez fournir une page d'erreur plus conviviale ou, plus précisément, indiquer aux moteurs de recherche que les pages du domaine n'existent plus.
|
||||||
|
|
||||||
|
Un autre avantage de cet hôte est la possibilité de suivre les journaux et de consulter les sites référenceurs.
|
||||||
7
frontend/src/locale/src/HelpDoc/fr/ProxyHosts.md
Normal file
7
frontend/src/locale/src/HelpDoc/fr/ProxyHosts.md
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
## Qu'est-ce qu'un hôte proxy ?
|
||||||
|
|
||||||
|
Un Hôte Proxy est le point de terminaison entrant d'un service web que vous souhaitez rediriger.
|
||||||
|
|
||||||
|
Il assure la terminaison SSL optionnelle pour votre service qui ne prend pas en charge SSL nativement.
|
||||||
|
|
||||||
|
Les Hôtes Proxy constituent l'utilisation la plus courante du Nginx Proxy Manager.
|
||||||
5
frontend/src/locale/src/HelpDoc/fr/RedirectionHosts.md
Normal file
5
frontend/src/locale/src/HelpDoc/fr/RedirectionHosts.md
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
## Qu'est-ce qu'un serveur de redirection ?
|
||||||
|
|
||||||
|
Un Hôte de Redirection redirige les requêtes provenant du domaine entrant vers un autre domaine.
|
||||||
|
|
||||||
|
On utilise généralement ce type d'hôte lorsque votre site web change de domaine, mais que des liens provenant des moteurs de recherche ou des sites référenceurs pointent toujours vers l'ancien domaine.
|
||||||
5
frontend/src/locale/src/HelpDoc/fr/Streams.md
Normal file
5
frontend/src/locale/src/HelpDoc/fr/Streams.md
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
## Qu'est-ce qu'un Stream ?
|
||||||
|
|
||||||
|
Fonctionnalité relativement récente de Nginx, un Stream permet de rediriger le trafic TCP/UDP directement vers un autre ordinateur du réseau.
|
||||||
|
|
||||||
|
Si vous gérez des serveurs de jeux, FTP ou SSH, cela peut s'avérer très utile.
|
||||||
6
frontend/src/locale/src/HelpDoc/fr/index.ts
Normal file
6
frontend/src/locale/src/HelpDoc/fr/index.ts
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
export * as AccessLists from "./AccessLists.md";
|
||||||
|
export * as Certificates from "./Certificates.md";
|
||||||
|
export * as DeadHosts from "./DeadHosts.md";
|
||||||
|
export * as ProxyHosts from "./ProxyHosts.md";
|
||||||
|
export * as RedirectionHosts from "./RedirectionHosts.md";
|
||||||
|
export * as Streams from "./Streams.md";
|
||||||
7
frontend/src/locale/src/HelpDoc/ga/AccessLists.md
Normal file
7
frontend/src/locale/src/HelpDoc/ga/AccessLists.md
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
## Cad is Liosta Rochtana ann?
|
||||||
|
|
||||||
|
Soláthraíonn Liostaí Rochtana liosta dubh nó liosta bán de sheoltaí IP cliant ar leith mar aon le fíordheimhniú do na hÓstaigh Seachfhreastalaí trí Fhíordheimhniú Bunúsach HTTP.
|
||||||
|
|
||||||
|
Is féidir leat rialacha cliant, ainmneacha úsáideora agus pasfhocail iolracha a chumrú le haghaidh Liosta Rochtana aonair agus ansin iad sin a chur i bhfeidhm ar _Óstach Seachfhreastalaí_ amháin nó níos mó.
|
||||||
|
|
||||||
|
Tá sé seo an-úsáideach i gcás seirbhísí gréasáin atreoraithe nach bhfuil meicníochtaí fíordheimhnithe ionsuite iontu nó nuair is mian leat cosaint a dhéanamh ar chliaint anaithnide.
|
||||||
21
frontend/src/locale/src/HelpDoc/ga/Certificates.md
Normal file
21
frontend/src/locale/src/HelpDoc/ga/Certificates.md
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
## Cabhair le Deimhnithe
|
||||||
|
|
||||||
|
### Teastas HTTP
|
||||||
|
|
||||||
|
Ciallaíonn deimhniú bailíochtaithe HTTP go ndéanfaidh freastalaithe Let's Encrypt iarracht teacht ar do fhearainn thar HTTP (ní HTTPS!) agus má éiríonn leo, eiseoidh siad do theastas.
|
||||||
|
|
||||||
|
Chun an modh seo a dhéanamh, beidh ort _Óstach Proxy_ a chruthú do do fhearainn(eanna) atá inrochtana le HTTP agus ag pointeáil chuig an suiteáil Nginx seo. Tar éis deimhniú a thabhairt, is féidir leat an _Óstach Proxy_ a mhodhnú chun an deimhniú seo a úsáid le haghaidh naisc HTTPS freisin. Mar sin féin, beidh ort an _Óstach Proxy_ a chumrú fós le haghaidh rochtain HTTP chun go ndéanfar an deimhniú a athnuachan.
|
||||||
|
|
||||||
|
_Ní thacaíonn_ an próiseas seo le fearainn fiáine.
|
||||||
|
|
||||||
|
### Teastas DNS
|
||||||
|
|
||||||
|
Éilíonn deimhniú bailíochtaithe DNS ort breiseán Soláthraí DNS a úsáid. Úsáidfear an Soláthraí DNS seo chun taifid shealadacha a chruthú ar do fhearann agus ansin déanfaidh Let's Encrypt fiosrúchán ar na taifid sin lena chinntiú gurb tusa an t-úinéir agus má éiríonn leo, eiseoidh siad do theastas.
|
||||||
|
|
||||||
|
Ní gá duit _Óstach Proxy_ a chruthú sula n-iarrann tú an cineál seo teastais. Ní gá duit do _Óstach Proxy_ a chumrú le haghaidh rochtana HTTP ach an oiread.
|
||||||
|
|
||||||
|
_Tacaíonn_ an próiseas seo le fearainn fiáine.
|
||||||
|
|
||||||
|
### Teastas Saincheaptha
|
||||||
|
|
||||||
|
Úsáid an rogha seo chun do Theastas SSL féin a uaslódáil, mar a sholáthraíonn d'Údarás Deimhnithe féin é.
|
||||||
7
frontend/src/locale/src/HelpDoc/ga/DeadHosts.md
Normal file
7
frontend/src/locale/src/HelpDoc/ga/DeadHosts.md
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
## Cad is Óstach 404 ann?
|
||||||
|
|
||||||
|
Is socrú óstach a thaispeánann leathanach 404 é Óstach 404.
|
||||||
|
|
||||||
|
Is féidir leis seo a bheith úsáideach nuair a bhíonn do fhearann liostaithe in innill chuardaigh agus más mian leat leathanach earráide níos deise a sholáthar nó a chur in iúl do na hinnéacsóirí cuardaigh go sonrach nach bhfuil na leathanaigh fearainn ann a thuilleadh.
|
||||||
|
|
||||||
|
Buntáiste eile a bhaineann leis an óstach seo a bheith agat ná go bhfeictear na logaí le haghaidh amas agus go bhfeictear na tagairtí.
|
||||||
7
frontend/src/locale/src/HelpDoc/ga/ProxyHosts.md
Normal file
7
frontend/src/locale/src/HelpDoc/ga/ProxyHosts.md
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
## Cad is Óstach Seachfhreastalaí ann?
|
||||||
|
|
||||||
|
Is é Óstach Seachfhreastalaí an críochphointe isteach do sheirbhís ghréasáin ar mhaith leat a atreorú.
|
||||||
|
|
||||||
|
Soláthraíonn sé foirceannadh SSL roghnach do do sheirbhís nach bhfuil tacaíocht SSL ionsuite inti b'fhéidir.
|
||||||
|
|
||||||
|
Is iad Óstaigh Seachfhreastalaí an úsáid is coitianta a bhaintear as Bainisteoir Seachfhreastalaí Nginx.
|
||||||
5
frontend/src/locale/src/HelpDoc/ga/RedirectionHosts.md
Normal file
5
frontend/src/locale/src/HelpDoc/ga/RedirectionHosts.md
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
## Cad is Óstach Athsheolta ann?
|
||||||
|
|
||||||
|
Déanfaidh Óstach Athsheolta iarratais a atreorú ón bhfearann ag teacht isteach agus an breathnóir a bhrú chuig fearann eile.
|
||||||
|
|
||||||
|
Is é an chúis is coitianta le húsáid a bhaint as an gcineál seo óstála ná nuair a athraíonn do shuíomh Gréasáin fearainn ach go bhfuil naisc innill chuardaigh nó atreoraithe agat fós ag tagairt don seanfhearann.
|
||||||
5
frontend/src/locale/src/HelpDoc/ga/Streams.md
Normal file
5
frontend/src/locale/src/HelpDoc/ga/Streams.md
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
## Cad is Sruth ann?
|
||||||
|
|
||||||
|
Gné réasúnta nua do Nginx is ea Sruth a sheolfaidh trácht TCP/UDP go díreach chuig ríomhaire eile ar an líonra.
|
||||||
|
|
||||||
|
Más freastalaithe cluichí, freastalaithe FTP nó SSH atá á rith agat, d’fhéadfadh sé seo a bheith úsáideach.
|
||||||
6
frontend/src/locale/src/HelpDoc/ga/index.ts
Normal file
6
frontend/src/locale/src/HelpDoc/ga/index.ts
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
export * as AccessLists from "./AccessLists.md";
|
||||||
|
export * as Certificates from "./Certificates.md";
|
||||||
|
export * as DeadHosts from "./DeadHosts.md";
|
||||||
|
export * as ProxyHosts from "./ProxyHosts.md";
|
||||||
|
export * as RedirectionHosts from "./RedirectionHosts.md";
|
||||||
|
export * as Streams from "./Streams.md";
|
||||||
@@ -1,33 +1,30 @@
|
|||||||
|
import * as bg from "./bg/index";
|
||||||
import * as de from "./de/index";
|
import * as de from "./de/index";
|
||||||
import * as en from "./en/index";
|
import * as en from "./en/index";
|
||||||
|
import * as es from "./es/index";
|
||||||
|
import * as fr from "./fr/index";
|
||||||
|
import * as ga from "./ga/index";
|
||||||
|
import * as id from "./id/index";
|
||||||
import * as it from "./it/index";
|
import * as it from "./it/index";
|
||||||
import * as ja from "./ja/index";
|
import * as ja from "./ja/index";
|
||||||
|
import * as ko from "./ko/index";
|
||||||
import * as nl from "./nl/index";
|
import * as nl from "./nl/index";
|
||||||
import * as pl from "./pl/index";
|
import * as pl from "./pl/index";
|
||||||
import * as ru from "./ru/index";
|
import * as ru from "./ru/index";
|
||||||
import * as sk from "./sk/index";
|
import * as sk from "./sk/index";
|
||||||
import * as vi from "./vi/index";
|
import * as vi from "./vi/index";
|
||||||
import * as zh from "./zh/index";
|
import * as zh from "./zh/index";
|
||||||
import * as ko from "./ko/index";
|
import * as tr from "./tr/index";
|
||||||
import * as bg from "./bg/index";
|
const items: any = { en, de, es, ja, sk, zh, pl, ru, it, vi, nl, bg, ko, ga, id, fr, tr };
|
||||||
import * as id from "./id/index";
|
|
||||||
|
|
||||||
const items: any = { en, de, ja, sk, zh, pl, ru, it, vi, nl, bg, ko, id };
|
|
||||||
|
|
||||||
const fallbackLang = "en";
|
const fallbackLang = "en";
|
||||||
|
|
||||||
export const getHelpFile = (lang: string, section: string): string => {
|
export const getHelpFile = (lang: string, section: string): string => {
|
||||||
if (
|
if (typeof items[lang] !== "undefined" && typeof items[lang][section] !== "undefined") {
|
||||||
typeof items[lang] !== "undefined" &&
|
|
||||||
typeof items[lang][section] !== "undefined"
|
|
||||||
) {
|
|
||||||
return items[lang][section].default;
|
return items[lang][section].default;
|
||||||
}
|
}
|
||||||
// Fallback to English
|
// Fallback to English
|
||||||
if (
|
if (typeof items[fallbackLang] !== "undefined" && typeof items[fallbackLang][section] !== "undefined") {
|
||||||
typeof items[fallbackLang] !== "undefined" &&
|
|
||||||
typeof items[fallbackLang][section] !== "undefined"
|
|
||||||
) {
|
|
||||||
return items[fallbackLang][section].default;
|
return items[fallbackLang][section].default;
|
||||||
}
|
}
|
||||||
throw new Error(`Cannot load help doc for ${lang}-${section}`);
|
throw new Error(`Cannot load help doc for ${lang}-${section}`);
|
||||||
|
|||||||
8
frontend/src/locale/src/HelpDoc/tr/AccessLists.md
Normal file
8
frontend/src/locale/src/HelpDoc/tr/AccessLists.md
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
## Erişim Listesi Nedir?
|
||||||
|
|
||||||
|
Erişim Listeleri, Temel HTTP Kimlik Doğrulama aracılığıyla Proxy Host'lar için belirli istemci IP adreslerinin kara listesi veya beyaz listesini ve kimlik doğrulamasını sağlar.
|
||||||
|
|
||||||
|
Tek bir Erişim Listesi için birden fazla istemci kuralı, kullanıcı adı ve şifre yapılandırabilir ve bunu bir veya daha fazla _Proxy Host_'a uygulayabilirsiniz.
|
||||||
|
|
||||||
|
Bu, yerleşik kimlik doğrulama mekanizmaları olmayan veya bilinmeyen istemcilerden korunmak istediğinizde iletilen web hizmetleri için en kullanışlıdır.
|
||||||
|
|
||||||
29
frontend/src/locale/src/HelpDoc/tr/Certificates.md
Normal file
29
frontend/src/locale/src/HelpDoc/tr/Certificates.md
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
## Sertifika Yardımı
|
||||||
|
|
||||||
|
### HTTP Sertifikası
|
||||||
|
|
||||||
|
Bir HTTP doğrulanmış sertifika, Let's Encrypt sunucularının
|
||||||
|
alan adlarınıza HTTP (HTTPS değil!) üzerinden ulaşmaya çalışacağı ve başarılı olursa,
|
||||||
|
sertifikanızı verecekleri anlamına gelir.
|
||||||
|
|
||||||
|
Bu yöntem için, alan adlarınız için HTTP ile erişilebilir ve bu Nginx kurulumuna işaret eden bir _Proxy Host_ oluşturulmuş olmalıdır. Bir sertifika
|
||||||
|
verildikten sonra, _Proxy Host_'u HTTPS
|
||||||
|
bağlantıları için de bu sertifikayı kullanacak şekilde değiştirebilirsiniz. Ancak, sertifikanın yenilenmesi için _Proxy Host_'un hala HTTP erişimi için yapılandırılmış olması gerekecektir.
|
||||||
|
|
||||||
|
Bu işlem joker karakter alan adlarını _desteklemez_.
|
||||||
|
|
||||||
|
### DNS Sertifikası
|
||||||
|
|
||||||
|
Bir DNS doğrulanmış sertifika, bir DNS Sağlayıcı eklentisi kullanmanızı gerektirir. Bu DNS
|
||||||
|
Sağlayıcı, alan adınızda geçici kayıtlar oluşturmak için kullanılacak ve ardından Let's
|
||||||
|
Encrypt bu kayıtları sorgulayarak sahibi olduğunuzdan emin olacak ve başarılı olursa,
|
||||||
|
sertifikanızı verecektir.
|
||||||
|
|
||||||
|
Bu tür bir sertifika talep etmeden önce bir _Proxy Host_ oluşturulmasına gerek yoktur. Ayrıca _Proxy Host_'unuzun HTTP erişimi için yapılandırılmasına da gerek yoktur.
|
||||||
|
|
||||||
|
Bu işlem joker karakter alan adlarını _destekler_.
|
||||||
|
|
||||||
|
### Özel Sertifika
|
||||||
|
|
||||||
|
Kendi Sertifika Otoriteniz tarafından sağlanan kendi SSL Sertifikanızı yüklemek için bu seçeneği kullanın.
|
||||||
|
|
||||||
10
frontend/src/locale/src/HelpDoc/tr/DeadHosts.md
Normal file
10
frontend/src/locale/src/HelpDoc/tr/DeadHosts.md
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
## 404 Host Nedir?
|
||||||
|
|
||||||
|
404 Host, basitçe bir 404 sayfası gösteren bir host kurulumudur.
|
||||||
|
|
||||||
|
Bu, alan adınız arama motorlarında listelendiğinde ve daha güzel bir hata sayfası sağlamak veya özellikle arama dizinleyicilerine
|
||||||
|
alan adı sayfalarının artık mevcut olmadığını söylemek istediğinizde yararlı olabilir.
|
||||||
|
|
||||||
|
Bu host'un bir başka faydası da, ona yapılan isteklerin loglarını takip etmek ve
|
||||||
|
referansları görüntülemektir.
|
||||||
|
|
||||||
8
frontend/src/locale/src/HelpDoc/tr/ProxyHosts.md
Normal file
8
frontend/src/locale/src/HelpDoc/tr/ProxyHosts.md
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
## Proxy Host Nedir?
|
||||||
|
|
||||||
|
Proxy Host, iletilmek istediğiniz bir web hizmeti için gelen uç noktadır.
|
||||||
|
|
||||||
|
SSL desteği yerleşik olmayan hizmetiniz için isteğe bağlı SSL sonlandırma sağlar.
|
||||||
|
|
||||||
|
Proxy Host'lar, Nginx Proxy Manager'ın en yaygın kullanımıdır.
|
||||||
|
|
||||||
8
frontend/src/locale/src/HelpDoc/tr/RedirectionHosts.md
Normal file
8
frontend/src/locale/src/HelpDoc/tr/RedirectionHosts.md
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
## Yönlendirme Host'u Nedir?
|
||||||
|
|
||||||
|
Yönlendirme Host'u, gelen alan adından gelen istekleri yönlendirir ve
|
||||||
|
görüntüleyiciyi başka bir alan adına yönlendirir.
|
||||||
|
|
||||||
|
Bu tür bir host kullanmanın en yaygın nedeni, web sitenizin alan adı değiştiğinde
|
||||||
|
ancak hala eski alan adına işaret eden arama motoru veya referans bağlantılarınız olduğunda ortaya çıkar.
|
||||||
|
|
||||||
7
frontend/src/locale/src/HelpDoc/tr/Streams.md
Normal file
7
frontend/src/locale/src/HelpDoc/tr/Streams.md
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
## Akış Nedir?
|
||||||
|
|
||||||
|
Nginx için nispeten yeni bir özellik olan Akış, TCP/UDP
|
||||||
|
trafiğini doğrudan ağdaki başka bir bilgisayara iletmek için hizmet edecektir.
|
||||||
|
|
||||||
|
Oyun sunucuları, FTP veya SSH sunucuları çalıştırıyorsanız bu işinize yarayabilir.
|
||||||
|
|
||||||
7
frontend/src/locale/src/HelpDoc/tr/index.ts
Normal file
7
frontend/src/locale/src/HelpDoc/tr/index.ts
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
export * as AccessLists from "./AccessLists.md";
|
||||||
|
export * as Certificates from "./Certificates.md";
|
||||||
|
export * as DeadHosts from "./DeadHosts.md";
|
||||||
|
export * as ProxyHosts from "./ProxyHosts.md";
|
||||||
|
export * as RedirectionHosts from "./RedirectionHosts.md";
|
||||||
|
export * as Streams from "./Streams.md";
|
||||||
|
|
||||||
@@ -30,13 +30,13 @@
|
|||||||
"defaultMessage": "{users} {users, plural, one {User} other {Users}}, {rules} {rules, plural, one {Regel} other {Regeln}} - Erstellt: {date}"
|
"defaultMessage": "{users} {users, plural, one {User} other {Users}}, {rules} {rules, plural, one {Regel} other {Regeln}} - Erstellt: {date}"
|
||||||
},
|
},
|
||||||
"access-lists": {
|
"access-lists": {
|
||||||
"defaultMessage": "Zugrifflisten"
|
"defaultMessage": "Zugriffslisten"
|
||||||
},
|
},
|
||||||
"action.add": {
|
"action.add": {
|
||||||
"defaultMessage": "Hinzufügen"
|
"defaultMessage": "Hinzufügen"
|
||||||
},
|
},
|
||||||
"action.add-location": {
|
"action.add-location": {
|
||||||
"defaultMessage": "Pfad Hinzufügen"
|
"defaultMessage": "Pfad hinzufügen"
|
||||||
},
|
},
|
||||||
"action.close": {
|
"action.close": {
|
||||||
"defaultMessage": "Schließen"
|
"defaultMessage": "Schließen"
|
||||||
@@ -60,13 +60,13 @@
|
|||||||
"defaultMessage": "Berechtigungen"
|
"defaultMessage": "Berechtigungen"
|
||||||
},
|
},
|
||||||
"action.renew": {
|
"action.renew": {
|
||||||
"defaultMessage": "Erneuert"
|
"defaultMessage": "Erneuern"
|
||||||
},
|
},
|
||||||
"action.view-details": {
|
"action.view-details": {
|
||||||
"defaultMessage": "Details"
|
"defaultMessage": "Details anzeigen"
|
||||||
},
|
},
|
||||||
"auditlogs": {
|
"auditlogs": {
|
||||||
"defaultMessage": "Protokoll"
|
"defaultMessage": "Protokolle"
|
||||||
},
|
},
|
||||||
"cancel": {
|
"cancel": {
|
||||||
"defaultMessage": "Abbrechen"
|
"defaultMessage": "Abbrechen"
|
||||||
@@ -81,7 +81,7 @@
|
|||||||
"defaultMessage": "Privater Schlüssel"
|
"defaultMessage": "Privater Schlüssel"
|
||||||
},
|
},
|
||||||
"certificate.custom-intermediate": {
|
"certificate.custom-intermediate": {
|
||||||
"defaultMessage": "Zwischen Zertifikat"
|
"defaultMessage": "Zwischenzertifikat"
|
||||||
},
|
},
|
||||||
"certificate.in-use": {
|
"certificate.in-use": {
|
||||||
"defaultMessage": "In Benutzung"
|
"defaultMessage": "In Benutzung"
|
||||||
@@ -120,7 +120,7 @@
|
|||||||
"defaultMessage": "Diese Daten werden als Klartext in der Datenbank und in einer Datei gespeichert!"
|
"defaultMessage": "Diese Daten werden als Klartext in der Datenbank und in einer Datei gespeichert!"
|
||||||
},
|
},
|
||||||
"certificates.dns.propagation-seconds": {
|
"certificates.dns.propagation-seconds": {
|
||||||
"defaultMessage": "Wartzeit in Sekunden"
|
"defaultMessage": "Wartezeit in Sekunden"
|
||||||
},
|
},
|
||||||
"certificates.dns.propagation-seconds-note": {
|
"certificates.dns.propagation-seconds-note": {
|
||||||
"defaultMessage": "Leer lassen um die Standardwartezeit des Plugins zu nutzen"
|
"defaultMessage": "Leer lassen um die Standardwartezeit des Plugins zu nutzen"
|
||||||
@@ -150,7 +150,7 @@
|
|||||||
"defaultMessage": "Unter dieser Domain wurde ein Server gefunden, der jedoch unerwartete Daten zurückgegeben hat. Handelt es sich um den NPM-Server? Bitte stellen Sie sicher, dass Ihre Domain auf die IP-Adresse verweist, unter der Ihre NPM-Instanz ausgeführt wird."
|
"defaultMessage": "Unter dieser Domain wurde ein Server gefunden, der jedoch unerwartete Daten zurückgegeben hat. Handelt es sich um den NPM-Server? Bitte stellen Sie sicher, dass Ihre Domain auf die IP-Adresse verweist, unter der Ihre NPM-Instanz ausgeführt wird."
|
||||||
},
|
},
|
||||||
"certificates.http.test-results": {
|
"certificates.http.test-results": {
|
||||||
"defaultMessage": "Test Ergeniss"
|
"defaultMessage": "Testergebnisse"
|
||||||
},
|
},
|
||||||
"certificates.http.warning": {
|
"certificates.http.warning": {
|
||||||
"defaultMessage": "Diese Domänen müssen bereits so konfiguriert sein, dass sie auf diese Installation verweisen."
|
"defaultMessage": "Diese Domänen müssen bereits so konfiguriert sein, dass sie auf diese Installation verweisen."
|
||||||
@@ -183,7 +183,7 @@
|
|||||||
"defaultMessage": "Genehmigungen"
|
"defaultMessage": "Genehmigungen"
|
||||||
},
|
},
|
||||||
"column.custom-locations": {
|
"column.custom-locations": {
|
||||||
"defaultMessage": "Benutzerdefinierte Pfad"
|
"defaultMessage": "Benutzerdefinierte Pfade"
|
||||||
},
|
},
|
||||||
"column.destination": {
|
"column.destination": {
|
||||||
"defaultMessage": "Ziel"
|
"defaultMessage": "Ziel"
|
||||||
@@ -192,7 +192,7 @@
|
|||||||
"defaultMessage": "Details"
|
"defaultMessage": "Details"
|
||||||
},
|
},
|
||||||
"column.email": {
|
"column.email": {
|
||||||
"defaultMessage": "Email"
|
"defaultMessage": "E-Mail"
|
||||||
},
|
},
|
||||||
"column.event": {
|
"column.event": {
|
||||||
"defaultMessage": "Ereignis"
|
"defaultMessage": "Ereignis"
|
||||||
@@ -291,7 +291,7 @@
|
|||||||
"defaultMessage": "Nutze DNS Challenge"
|
"defaultMessage": "Nutze DNS Challenge"
|
||||||
},
|
},
|
||||||
"email-address": {
|
"email-address": {
|
||||||
"defaultMessage": "Email Addresse"
|
"defaultMessage": "E-Mail-Adresse"
|
||||||
},
|
},
|
||||||
"empty-search": {
|
"empty-search": {
|
||||||
"defaultMessage": "Keine Ergebnisse gefunden"
|
"defaultMessage": "Keine Ergebnisse gefunden"
|
||||||
@@ -384,7 +384,7 @@
|
|||||||
"defaultMessage": "Laden…"
|
"defaultMessage": "Laden…"
|
||||||
},
|
},
|
||||||
"login.title": {
|
"login.title": {
|
||||||
"defaultMessage": "Account Login"
|
"defaultMessage": "Anmelden"
|
||||||
},
|
},
|
||||||
"nginx-config.label": {
|
"nginx-config.label": {
|
||||||
"defaultMessage": "Benutzerdefinierte Nginx Konfiguration"
|
"defaultMessage": "Benutzerdefinierte Nginx Konfiguration"
|
||||||
@@ -399,7 +399,7 @@
|
|||||||
"defaultMessage": "Take me home"
|
"defaultMessage": "Take me home"
|
||||||
},
|
},
|
||||||
"notfound.content": {
|
"notfound.content": {
|
||||||
"defaultMessage": "We are sorry but the page you are looking for was not found"
|
"defaultMessage": "Es tut uns leid, aber die gesuchte Seite wurde nicht gefunden"
|
||||||
},
|
},
|
||||||
"notfound.title": {
|
"notfound.title": {
|
||||||
"defaultMessage": "Oops… You just found an error page"
|
"defaultMessage": "Oops… You just found an error page"
|
||||||
@@ -495,7 +495,7 @@
|
|||||||
"defaultMessage": "Alle Elemente"
|
"defaultMessage": "Alle Elemente"
|
||||||
},
|
},
|
||||||
"permissions.visibility.title": {
|
"permissions.visibility.title": {
|
||||||
"defaultMessage": "Objekt Sichtbarkeit"
|
"defaultMessage": "Objektsichtbarkeit"
|
||||||
},
|
},
|
||||||
"permissions.visibility.user": {
|
"permissions.visibility.user": {
|
||||||
"defaultMessage": "Nur erstellte Elemente"
|
"defaultMessage": "Nur erstellte Elemente"
|
||||||
@@ -534,7 +534,7 @@
|
|||||||
"defaultMessage": "Administrator"
|
"defaultMessage": "Administrator"
|
||||||
},
|
},
|
||||||
"role.standard-user": {
|
"role.standard-user": {
|
||||||
"defaultMessage": "Standard User"
|
"defaultMessage": "Standardbenutzer"
|
||||||
},
|
},
|
||||||
"save": {
|
"save": {
|
||||||
"defaultMessage": "Speichern"
|
"defaultMessage": "Speichern"
|
||||||
@@ -546,7 +546,7 @@
|
|||||||
"defaultMessage": "Einstellungen"
|
"defaultMessage": "Einstellungen"
|
||||||
},
|
},
|
||||||
"settings.default-site": {
|
"settings.default-site": {
|
||||||
"defaultMessage": "Standard Seite"
|
"defaultMessage": "Standardseite"
|
||||||
},
|
},
|
||||||
"settings.default-site.404": {
|
"settings.default-site.404": {
|
||||||
"defaultMessage": "404 Page"
|
"defaultMessage": "404 Page"
|
||||||
@@ -579,7 +579,7 @@
|
|||||||
"defaultMessage": "Login"
|
"defaultMessage": "Login"
|
||||||
},
|
},
|
||||||
"ssl-certificate": {
|
"ssl-certificate": {
|
||||||
"defaultMessage": "SSL Zertifikate"
|
"defaultMessage": "SSL-Zertifikate"
|
||||||
},
|
},
|
||||||
"stream": {
|
"stream": {
|
||||||
"defaultMessage": "Stream"
|
"defaultMessage": "Stream"
|
||||||
@@ -645,7 +645,7 @@
|
|||||||
"defaultMessage": "Zum Dark Mode wechseln"
|
"defaultMessage": "Zum Dark Mode wechseln"
|
||||||
},
|
},
|
||||||
"user.switch-light": {
|
"user.switch-light": {
|
||||||
"defaultMessage": "Zum Light Mode wechslen"
|
"defaultMessage": "Zum Light Mode wechseln"
|
||||||
},
|
},
|
||||||
"username": {
|
"username": {
|
||||||
"defaultMessage": "Benutzername"
|
"defaultMessage": "Benutzername"
|
||||||
|
|||||||
647
frontend/src/locale/src/fr.json
Normal file
647
frontend/src/locale/src/fr.json
Normal file
@@ -0,0 +1,647 @@
|
|||||||
|
{
|
||||||
|
"access-list": {
|
||||||
|
"defaultMessage": "Liste d'accès"
|
||||||
|
},
|
||||||
|
"access-list.access-count": {
|
||||||
|
"defaultMessage": "{count} {count, plural, one {Règle} other {Règles}}"
|
||||||
|
},
|
||||||
|
"access-list.auth-count": {
|
||||||
|
"defaultMessage": "{count} {count, plural, one {Utilisateur} other {Utilisateurs}}"
|
||||||
|
},
|
||||||
|
"access-list.help-rules-last": {
|
||||||
|
"defaultMessage": "S'il existe au moins une règle, cette règle de refuser tout sera ajoutée en dernier."
|
||||||
|
},
|
||||||
|
"access-list.help.rules-order": {
|
||||||
|
"defaultMessage": "Notez que les directives autoriser et refuser seront appliquées dans l'ordre où elles sont définies."
|
||||||
|
},
|
||||||
|
"access-list.pass-auth": {
|
||||||
|
"defaultMessage": "Transmettre l'authentification au serveur en amont"
|
||||||
|
},
|
||||||
|
"access-list.public": {
|
||||||
|
"defaultMessage": "Accessible au public"
|
||||||
|
},
|
||||||
|
"access-list.public.subtitle": {
|
||||||
|
"defaultMessage": "Aucune authentification de base requise"
|
||||||
|
},
|
||||||
|
"access-list.satisfy-any": {
|
||||||
|
"defaultMessage": "Valide n'importe quelle règle"
|
||||||
|
},
|
||||||
|
"access-list.subtitle": {
|
||||||
|
"defaultMessage": "{utilisateurs} {utilisateurs, plural, one {Utilisateur} other {Utilisateurs}}, {règles} {règles, plural, one {Règle} other {Règles}} - Crée : {date}"
|
||||||
|
},
|
||||||
|
"access-lists": {
|
||||||
|
"defaultMessage": "Listes d'accès"
|
||||||
|
},
|
||||||
|
"action.add": {
|
||||||
|
"defaultMessage": "Ajouter"
|
||||||
|
},
|
||||||
|
"action.add-location": {
|
||||||
|
"defaultMessage": "Ajouter localisation"
|
||||||
|
},
|
||||||
|
"action.close": {
|
||||||
|
"defaultMessage": "Fermer"
|
||||||
|
},
|
||||||
|
"action.delete": {
|
||||||
|
"defaultMessage": "Supprimer"
|
||||||
|
},
|
||||||
|
"action.disable": {
|
||||||
|
"defaultMessage": "Désactiver"
|
||||||
|
},
|
||||||
|
"action.download": {
|
||||||
|
"defaultMessage": "Télécharger"
|
||||||
|
},
|
||||||
|
"action.edit": {
|
||||||
|
"defaultMessage": "Modifier"
|
||||||
|
},
|
||||||
|
"action.enable": {
|
||||||
|
"defaultMessage": "Activer"
|
||||||
|
},
|
||||||
|
"action.permissions": {
|
||||||
|
"defaultMessage": "Permissions"
|
||||||
|
},
|
||||||
|
"action.renew": {
|
||||||
|
"defaultMessage": "Renouveler"
|
||||||
|
},
|
||||||
|
"action.view-details": {
|
||||||
|
"defaultMessage": "Voir les Détails"
|
||||||
|
},
|
||||||
|
"auditlogs": {
|
||||||
|
"defaultMessage": "Journaux d'audit"
|
||||||
|
},
|
||||||
|
"cancel": {
|
||||||
|
"defaultMessage": "Annuler"
|
||||||
|
},
|
||||||
|
"certificate": {
|
||||||
|
"defaultMessage": "Certificat"
|
||||||
|
},
|
||||||
|
"certificate.custom-certificate": {
|
||||||
|
"defaultMessage": "Certificat"
|
||||||
|
},
|
||||||
|
"certificate.custom-certificate-key": {
|
||||||
|
"defaultMessage": "Clé du Certificat"
|
||||||
|
},
|
||||||
|
"certificate.custom-intermediate": {
|
||||||
|
"defaultMessage": "Certificat intermédiaire"
|
||||||
|
},
|
||||||
|
"certificate.in-use": {
|
||||||
|
"defaultMessage": "Utilisé"
|
||||||
|
},
|
||||||
|
"certificate.none.subtitle": {
|
||||||
|
"defaultMessage": "Aucun certificat assigné"
|
||||||
|
},
|
||||||
|
"certificate.none.subtitle.for-http": {
|
||||||
|
"defaultMessage": "Cet hôte n'utilisera pas le HTTPS"
|
||||||
|
},
|
||||||
|
"certificate.none.title": {
|
||||||
|
"defaultMessage": "Aucun"
|
||||||
|
},
|
||||||
|
"certificate.not-in-use": {
|
||||||
|
"defaultMessage": "Non utilisé"
|
||||||
|
},
|
||||||
|
"certificate.renew": {
|
||||||
|
"defaultMessage": "Renouveler Certificat"
|
||||||
|
},
|
||||||
|
"certificates": {
|
||||||
|
"defaultMessage": "Certificats"
|
||||||
|
},
|
||||||
|
"certificates.custom": {
|
||||||
|
"defaultMessage": "Certificat personnalisé"
|
||||||
|
},
|
||||||
|
"certificates.custom.warning": {
|
||||||
|
"defaultMessage": "Les fichiers de clé protégés par une passphrase ne sont pas acceptés."
|
||||||
|
},
|
||||||
|
"certificates.dns.credentials": {
|
||||||
|
"defaultMessage": "Contenu du fichier d'identifiants"
|
||||||
|
},
|
||||||
|
"certificates.dns.credentials-note": {
|
||||||
|
"defaultMessage": "Ce plugin nécessite un fichier de configuration contenant un jeton d'API ou d'autres informations d'identification pour votre fournisseur."
|
||||||
|
},
|
||||||
|
"certificates.dns.credentials-warning": {
|
||||||
|
"defaultMessage": "Ces données seront stockées en clair dans la base de données et dans un fichier !"
|
||||||
|
},
|
||||||
|
"certificates.dns.propagation-seconds": {
|
||||||
|
"defaultMessage": "Propagation Seconds"
|
||||||
|
},
|
||||||
|
"certificates.dns.propagation-seconds-note": {
|
||||||
|
"defaultMessage": "Laisser vide pour utiliser la valeur par défaut du plugin. Nombre de secondes à attendre pour la propagation DNS."
|
||||||
|
},
|
||||||
|
"certificates.dns.provider": {
|
||||||
|
"defaultMessage": "Fournisseur DNS"
|
||||||
|
},
|
||||||
|
"certificates.dns.warning": {
|
||||||
|
"defaultMessage": "Cette section requiert une certaine connaissance de Certbot et de ses plugins DNS. Veuillez consulter la documentation des plugins correspondants."
|
||||||
|
},
|
||||||
|
"certificates.http.reachability-404": {
|
||||||
|
"defaultMessage": "Un serveur a été trouvé sur ce domaine, mais il ne semble pas s'agir de Nginx Proxy Manager. Veuillez vérifier que votre domaine pointe bien vers l'adresse IP où votre instance NPM est exécutée."
|
||||||
|
},
|
||||||
|
"certificates.http.reachability-failed-to-check": {
|
||||||
|
"defaultMessage": "Impossible de vérifier l'accessibilité en raison d'une erreur de communication avec site24x7.com."
|
||||||
|
},
|
||||||
|
"certificates.http.reachability-not-resolved": {
|
||||||
|
"defaultMessage": "Aucun serveur n'est disponible pour ce domaine. Veuillez vérifier que votre domaine existe et pointe vers l'adresse IP où votre instance NPM est exécutée. Si nécessaire, le port 80 est ouvert dans votre routeur."
|
||||||
|
},
|
||||||
|
"certificates.http.reachability-ok": {
|
||||||
|
"defaultMessage": "Votre serveur est accessible et la création de certificats devrait être possible."
|
||||||
|
},
|
||||||
|
"certificates.http.reachability-other": {
|
||||||
|
"defaultMessage": "Un serveur a été trouvé sur ce domaine, mais il a renvoyé un code d'état inattendu {code}. S'agit-il du serveur NPM ? Veuillez vérifier que votre domaine pointe bien vers l'adresse IP où votre instance NPM est exécutée."
|
||||||
|
},
|
||||||
|
"certificates.http.reachability-wrong-data": {
|
||||||
|
"defaultMessage": "Un serveur a été trouvé sur ce domaine, mais il a renvoyé des données inattendues. S'agit-il du serveur NPM ? Veuillez vérifier que votre domaine pointe bien vers l'adresse IP où votre instance NPM est exécutée."
|
||||||
|
},
|
||||||
|
"certificates.http.test-results": {
|
||||||
|
"defaultMessage": "Résultats du test"
|
||||||
|
},
|
||||||
|
"certificates.http.warning": {
|
||||||
|
"defaultMessage": "Ces domaines doivent déjà être configurés pour pointer vers cette installation."
|
||||||
|
},
|
||||||
|
"certificates.request.subtitle": {
|
||||||
|
"defaultMessage": "avec Let's Encrypt"
|
||||||
|
},
|
||||||
|
"certificates.request.title": {
|
||||||
|
"defaultMessage": "Demander un nouveau certificat"
|
||||||
|
},
|
||||||
|
"column.access": {
|
||||||
|
"defaultMessage": "Accès"
|
||||||
|
},
|
||||||
|
"column.authorization": {
|
||||||
|
"defaultMessage": "Autorisation"
|
||||||
|
},
|
||||||
|
"column.authorizations": {
|
||||||
|
"defaultMessage": "Autorisations"
|
||||||
|
},
|
||||||
|
"column.custom-locations": {
|
||||||
|
"defaultMessage": "Emplacement personnalisé"
|
||||||
|
},
|
||||||
|
"column.destination": {
|
||||||
|
"defaultMessage": "Destination"
|
||||||
|
},
|
||||||
|
"column.details": {
|
||||||
|
"defaultMessage": "Détails"
|
||||||
|
},
|
||||||
|
"column.email": {
|
||||||
|
"defaultMessage": "eMail"
|
||||||
|
},
|
||||||
|
"column.event": {
|
||||||
|
"defaultMessage": "Évènement"
|
||||||
|
},
|
||||||
|
"column.expires": {
|
||||||
|
"defaultMessage": "Expire"
|
||||||
|
},
|
||||||
|
"column.http-code": {
|
||||||
|
"defaultMessage": "Code HTTP"
|
||||||
|
},
|
||||||
|
"column.incoming-port": {
|
||||||
|
"defaultMessage": "Port entrant"
|
||||||
|
},
|
||||||
|
"column.name": {
|
||||||
|
"defaultMessage": "Nom"
|
||||||
|
},
|
||||||
|
"column.protocol": {
|
||||||
|
"defaultMessage": "Protocole"
|
||||||
|
},
|
||||||
|
"column.provider": {
|
||||||
|
"defaultMessage": "Fournisseur"
|
||||||
|
},
|
||||||
|
"column.roles": {
|
||||||
|
"defaultMessage": "Rôles"
|
||||||
|
},
|
||||||
|
"column.rules": {
|
||||||
|
"defaultMessage": "Règles"
|
||||||
|
},
|
||||||
|
"column.satisfy": {
|
||||||
|
"defaultMessage": "Valide"
|
||||||
|
},
|
||||||
|
"column.satisfy-all": {
|
||||||
|
"defaultMessage": "All"
|
||||||
|
},
|
||||||
|
"column.satisfy-any": {
|
||||||
|
"defaultMessage": "Any"
|
||||||
|
},
|
||||||
|
"column.scheme": {
|
||||||
|
"defaultMessage": "Schéma"
|
||||||
|
},
|
||||||
|
"column.source": {
|
||||||
|
"defaultMessage": "Source"
|
||||||
|
},
|
||||||
|
"column.ssl": {
|
||||||
|
"defaultMessage": "SSL"
|
||||||
|
},
|
||||||
|
"column.status": {
|
||||||
|
"defaultMessage": "Statut"
|
||||||
|
},
|
||||||
|
"created-on": {
|
||||||
|
"defaultMessage": "Créé : {date}"
|
||||||
|
},
|
||||||
|
"dashboard": {
|
||||||
|
"defaultMessage": "Tableau de bord"
|
||||||
|
},
|
||||||
|
"dead-host": {
|
||||||
|
"defaultMessage": "Hôte 404"
|
||||||
|
},
|
||||||
|
"dead-hosts": {
|
||||||
|
"defaultMessage": "Hôtes 404"
|
||||||
|
},
|
||||||
|
"dead-hosts.count": {
|
||||||
|
"defaultMessage": "{count} {count, plural, one {Hôte 404} other {Hôtes 404}}"
|
||||||
|
},
|
||||||
|
"disabled": {
|
||||||
|
"defaultMessage": "Désactivé"
|
||||||
|
},
|
||||||
|
"domain-names": {
|
||||||
|
"defaultMessage": "Noms de domaine"
|
||||||
|
},
|
||||||
|
"domain-names.max": {
|
||||||
|
"defaultMessage": "{count} noms de domaine au maximum"
|
||||||
|
},
|
||||||
|
"domain-names.placeholder": {
|
||||||
|
"defaultMessage": "Commencez à écrire pour ajouter un domaine…"
|
||||||
|
},
|
||||||
|
"domain-names.wildcards-not-permitted": {
|
||||||
|
"defaultMessage": "Les Wildcards ne sont pas permises dans ce cas"
|
||||||
|
},
|
||||||
|
"domain-names.wildcards-not-supported": {
|
||||||
|
"defaultMessage": "Les Wildcards ne sont pas prises en charge par cette autorité de certification."
|
||||||
|
},
|
||||||
|
"domains.force-ssl": {
|
||||||
|
"defaultMessage": "Forcer SSL"
|
||||||
|
},
|
||||||
|
"domains.hsts-enabled": {
|
||||||
|
"defaultMessage": "HSTS activé"
|
||||||
|
},
|
||||||
|
"domains.hsts-subdomains": {
|
||||||
|
"defaultMessage": "Sous-domaines HSTS"
|
||||||
|
},
|
||||||
|
"domains.http2-support": {
|
||||||
|
"defaultMessage": "Prise en charge de HTTP/2"
|
||||||
|
},
|
||||||
|
"domains.use-dns": {
|
||||||
|
"defaultMessage": "Utiliser le challenge DNS"
|
||||||
|
},
|
||||||
|
"email-address": {
|
||||||
|
"defaultMessage": "Adresse eMail"
|
||||||
|
},
|
||||||
|
"empty-search": {
|
||||||
|
"defaultMessage": "Aucun résultat trouvé"
|
||||||
|
},
|
||||||
|
"empty-subtitle": {
|
||||||
|
"defaultMessage": "Pourquoi n'en créez-vous pas un ?"
|
||||||
|
},
|
||||||
|
"enabled": {
|
||||||
|
"defaultMessage": "Activé"
|
||||||
|
},
|
||||||
|
"error.access.at-least-one": {
|
||||||
|
"defaultMessage": "Une autorisation ou une règle d'accès est requise."
|
||||||
|
},
|
||||||
|
"error.access.duplicate-usernames": {
|
||||||
|
"defaultMessage": "Les noms d'utilisateurs autorisés doivent être uniques"
|
||||||
|
},
|
||||||
|
"error.invalid-auth": {
|
||||||
|
"defaultMessage": "Adresse eMail ou mot de passe invalide"
|
||||||
|
},
|
||||||
|
"error.invalid-domain": {
|
||||||
|
"defaultMessage": "Domaine invalide : {domain}"
|
||||||
|
},
|
||||||
|
"error.invalid-email": {
|
||||||
|
"defaultMessage": "Adresse eMail invalide"
|
||||||
|
},
|
||||||
|
"error.max-character-length": {
|
||||||
|
"defaultMessage": "La longueur maximale est {max} caractère{max, plural, one {} other {s}}"
|
||||||
|
},
|
||||||
|
"error.max-domains": {
|
||||||
|
"defaultMessage": "Trop de domaines, le maximum est {max}"
|
||||||
|
},
|
||||||
|
"error.maximum": {
|
||||||
|
"defaultMessage": "Le maximum est {max}"
|
||||||
|
},
|
||||||
|
"error.min-character-length": {
|
||||||
|
"defaultMessage": "La longueur minimale est {min} caractère{min, plural, one {} other {s}}"
|
||||||
|
},
|
||||||
|
"error.minimum": {
|
||||||
|
"defaultMessage": "Le minimum est {min}"
|
||||||
|
},
|
||||||
|
"error.passwords-must-match": {
|
||||||
|
"defaultMessage": "Les mots de passe doivent correspondre"
|
||||||
|
},
|
||||||
|
"error.required": {
|
||||||
|
"defaultMessage": "Ceci est obligatoire"
|
||||||
|
},
|
||||||
|
"expires.on": {
|
||||||
|
"defaultMessage": "Expire : {date}"
|
||||||
|
},
|
||||||
|
"footer.github-fork": {
|
||||||
|
"defaultMessage": "Forkez-moi sur Github"
|
||||||
|
},
|
||||||
|
"host.flags.block-exploits": {
|
||||||
|
"defaultMessage": "Bloquer les exploits courants"
|
||||||
|
},
|
||||||
|
"host.flags.cache-assets": {
|
||||||
|
"defaultMessage": "Ressources du cache"
|
||||||
|
},
|
||||||
|
"host.flags.preserve-path": {
|
||||||
|
"defaultMessage": "Préserver le chemin"
|
||||||
|
},
|
||||||
|
"host.flags.protocols": {
|
||||||
|
"defaultMessage": "Protocoles"
|
||||||
|
},
|
||||||
|
"host.flags.websockets-upgrade": {
|
||||||
|
"defaultMessage": "Prise en charge de Websockets"
|
||||||
|
},
|
||||||
|
"host.forward-port": {
|
||||||
|
"defaultMessage": "Port de redirection"
|
||||||
|
},
|
||||||
|
"host.forward-scheme": {
|
||||||
|
"defaultMessage": "Schéma"
|
||||||
|
},
|
||||||
|
"hosts": {
|
||||||
|
"defaultMessage": "Hôtes"
|
||||||
|
},
|
||||||
|
"http-only": {
|
||||||
|
"defaultMessage": "HTTP uniquement"
|
||||||
|
},
|
||||||
|
"lets-encrypt": {
|
||||||
|
"defaultMessage": "Let's Encrypt"
|
||||||
|
},
|
||||||
|
"lets-encrypt-via-dns": {
|
||||||
|
"defaultMessage": "Let's Encrypt via DNS"
|
||||||
|
},
|
||||||
|
"lets-encrypt-via-http": {
|
||||||
|
"defaultMessage": "Let's Encrypt via HTTP"
|
||||||
|
},
|
||||||
|
"loading": {
|
||||||
|
"defaultMessage": "Chargement…"
|
||||||
|
},
|
||||||
|
"login.title": {
|
||||||
|
"defaultMessage": "Connectez-vous à votre compte"
|
||||||
|
},
|
||||||
|
"nginx-config.label": {
|
||||||
|
"defaultMessage": "Configuration Nginx personnalisée"
|
||||||
|
},
|
||||||
|
"nginx-config.placeholder": {
|
||||||
|
"defaultMessage": "# Mettez ici votre configuration Nginx personnalisé à vos risques et périls !"
|
||||||
|
},
|
||||||
|
"no-permission-error": {
|
||||||
|
"defaultMessage": "Vous n'avez pas la permission de voir ce contenu."
|
||||||
|
},
|
||||||
|
"notfound.action": {
|
||||||
|
"defaultMessage": "Ramenez-moi à l'accueil"
|
||||||
|
},
|
||||||
|
"notfound.content": {
|
||||||
|
"defaultMessage": "Nous sommes désolés, mais la page que vous cherchez est introuvable"
|
||||||
|
},
|
||||||
|
"notfound.title": {
|
||||||
|
"defaultMessage": "Oops… Vous avez découvert une page d'erreur"
|
||||||
|
},
|
||||||
|
"notification.error": {
|
||||||
|
"defaultMessage": "Erreur"
|
||||||
|
},
|
||||||
|
"notification.object-deleted": {
|
||||||
|
"defaultMessage": "{object} a été supprimé"
|
||||||
|
},
|
||||||
|
"notification.object-disabled": {
|
||||||
|
"defaultMessage": "{object} a été désactivé"
|
||||||
|
},
|
||||||
|
"notification.object-enabled": {
|
||||||
|
"defaultMessage": "{object} a été activé"
|
||||||
|
},
|
||||||
|
"notification.object-renewed": {
|
||||||
|
"defaultMessage": "{object} a été renouvelé"
|
||||||
|
},
|
||||||
|
"notification.object-saved": {
|
||||||
|
"defaultMessage": "{object} a été enregistré"
|
||||||
|
},
|
||||||
|
"notification.success": {
|
||||||
|
"defaultMessage": "Réussi"
|
||||||
|
},
|
||||||
|
"object.actions-title": {
|
||||||
|
"defaultMessage": "{object} #{id}"
|
||||||
|
},
|
||||||
|
"object.add": {
|
||||||
|
"defaultMessage": "Ajouter {object}"
|
||||||
|
},
|
||||||
|
"object.delete": {
|
||||||
|
"defaultMessage": "Supprimer {object}"
|
||||||
|
},
|
||||||
|
"object.delete.content": {
|
||||||
|
"defaultMessage": "Êtes-vous sûr de vouloir supprimer {object} ?"
|
||||||
|
},
|
||||||
|
"object.edit": {
|
||||||
|
"defaultMessage": "Modifier {object}"
|
||||||
|
},
|
||||||
|
"object.empty": {
|
||||||
|
"defaultMessage": "Il n'y a aucun {objects}"
|
||||||
|
},
|
||||||
|
"object.event.created": {
|
||||||
|
"defaultMessage": "{object} créé"
|
||||||
|
},
|
||||||
|
"object.event.deleted": {
|
||||||
|
"defaultMessage": "{object} supprimé"
|
||||||
|
},
|
||||||
|
"object.event.disabled": {
|
||||||
|
"defaultMessage": "{object} désactivé"
|
||||||
|
},
|
||||||
|
"object.event.enabled": {
|
||||||
|
"defaultMessage": "{object} activé"
|
||||||
|
},
|
||||||
|
"object.event.renewed": {
|
||||||
|
"defaultMessage": "{object} renouvelé"
|
||||||
|
},
|
||||||
|
"object.event.updated": {
|
||||||
|
"defaultMessage": "{object} mis à jour"
|
||||||
|
},
|
||||||
|
"offline": {
|
||||||
|
"defaultMessage": "Hors ligne"
|
||||||
|
},
|
||||||
|
"online": {
|
||||||
|
"defaultMessage": "En ligne"
|
||||||
|
},
|
||||||
|
"options": {
|
||||||
|
"defaultMessage": "Options"
|
||||||
|
},
|
||||||
|
"password": {
|
||||||
|
"defaultMessage": "Mot de passe"
|
||||||
|
},
|
||||||
|
"password.generate": {
|
||||||
|
"defaultMessage": "Générer un mot de passe aléatoire"
|
||||||
|
},
|
||||||
|
"password.hide": {
|
||||||
|
"defaultMessage": "Masquer le mot de passe"
|
||||||
|
},
|
||||||
|
"password.show": {
|
||||||
|
"defaultMessage": "Afficher le mot de passe"
|
||||||
|
},
|
||||||
|
"permissions.hidden": {
|
||||||
|
"defaultMessage": "Masquer"
|
||||||
|
},
|
||||||
|
"permissions.manage": {
|
||||||
|
"defaultMessage": "Gérer"
|
||||||
|
},
|
||||||
|
"permissions.view": {
|
||||||
|
"defaultMessage": "Voir uniquement"
|
||||||
|
},
|
||||||
|
"permissions.visibility.all": {
|
||||||
|
"defaultMessage": "Tous les éléments"
|
||||||
|
},
|
||||||
|
"permissions.visibility.title": {
|
||||||
|
"defaultMessage": "Éléments visibles"
|
||||||
|
},
|
||||||
|
"permissions.visibility.user": {
|
||||||
|
"defaultMessage": "Éléments créés uniquement"
|
||||||
|
},
|
||||||
|
"proxy-host": {
|
||||||
|
"defaultMessage": "Hôte proxy"
|
||||||
|
},
|
||||||
|
"proxy-host.forward-host": {
|
||||||
|
"defaultMessage": "Nom d'hôte de redirection / IP"
|
||||||
|
},
|
||||||
|
"proxy-hosts": {
|
||||||
|
"defaultMessage": "Hôtes proxy"
|
||||||
|
},
|
||||||
|
"proxy-hosts.count": {
|
||||||
|
"defaultMessage": "{count} {count, plural, one {Hôte proxy} other {Hôtes proxy}}"
|
||||||
|
},
|
||||||
|
"public": {
|
||||||
|
"defaultMessage": "Publique"
|
||||||
|
},
|
||||||
|
"redirection-host": {
|
||||||
|
"defaultMessage": "Hôte de redirection"
|
||||||
|
},
|
||||||
|
"redirection-host.forward-domain": {
|
||||||
|
"defaultMessage": "Domaine de redirection"
|
||||||
|
},
|
||||||
|
"redirection-host.forward-http-code": {
|
||||||
|
"defaultMessage": "Code HTTP"
|
||||||
|
},
|
||||||
|
"redirection-hosts": {
|
||||||
|
"defaultMessage": "Hôtes de redirection"
|
||||||
|
},
|
||||||
|
"redirection-hosts.count": {
|
||||||
|
"defaultMessage": "{count} {count, plural, one {Hôte de redirection} other {Hôtes de redirection}}"
|
||||||
|
},
|
||||||
|
"role.admin": {
|
||||||
|
"defaultMessage": "Administrateur"
|
||||||
|
},
|
||||||
|
"role.standard-user": {
|
||||||
|
"defaultMessage": "Utilisateur standard"
|
||||||
|
},
|
||||||
|
"save": {
|
||||||
|
"defaultMessage": "Enregistrer"
|
||||||
|
},
|
||||||
|
"setting": {
|
||||||
|
"defaultMessage": "Paramètre"
|
||||||
|
},
|
||||||
|
"settings": {
|
||||||
|
"defaultMessage": "Paramètres"
|
||||||
|
},
|
||||||
|
"settings.default-site": {
|
||||||
|
"defaultMessage": "Site par défaut"
|
||||||
|
},
|
||||||
|
"settings.default-site.404": {
|
||||||
|
"defaultMessage": "Page 404"
|
||||||
|
},
|
||||||
|
"settings.default-site.444": {
|
||||||
|
"defaultMessage": "Aucune réponse (444)"
|
||||||
|
},
|
||||||
|
"settings.default-site.congratulations": {
|
||||||
|
"defaultMessage": "Page de félicitations"
|
||||||
|
},
|
||||||
|
"settings.default-site.description": {
|
||||||
|
"defaultMessage": "ce qu'il faut afficher lorsqu'un hôte inconnu est détecté par Nginx"
|
||||||
|
},
|
||||||
|
"settings.default-site.html": {
|
||||||
|
"defaultMessage": "HTML personnalisé"
|
||||||
|
},
|
||||||
|
"settings.default-site.html.placeholder": {
|
||||||
|
"defaultMessage": "<!-- Mettez votre contenu HTML personnalisé ici -->"
|
||||||
|
},
|
||||||
|
"settings.default-site.redirect": {
|
||||||
|
"defaultMessage": "Redirection"
|
||||||
|
},
|
||||||
|
"setup.preamble": {
|
||||||
|
"defaultMessage": "Commencez par créer votre compte administrateur."
|
||||||
|
},
|
||||||
|
"setup.title": {
|
||||||
|
"defaultMessage": "Bienvenue !"
|
||||||
|
},
|
||||||
|
"sign-in": {
|
||||||
|
"defaultMessage": "Se connecter"
|
||||||
|
},
|
||||||
|
"ssl-certificate": {
|
||||||
|
"defaultMessage": "Certificat SSL"
|
||||||
|
},
|
||||||
|
"stream": {
|
||||||
|
"defaultMessage": "Stream"
|
||||||
|
},
|
||||||
|
"stream.forward-host": {
|
||||||
|
"defaultMessage": "Hôte destinataire"
|
||||||
|
},
|
||||||
|
"stream.incoming-port": {
|
||||||
|
"defaultMessage": "Port d'entrée"
|
||||||
|
},
|
||||||
|
"streams": {
|
||||||
|
"defaultMessage": "Streams"
|
||||||
|
},
|
||||||
|
"streams.count": {
|
||||||
|
"defaultMessage": "{count} {count, plural, one {Stream} other {Streams}}"
|
||||||
|
},
|
||||||
|
"streams.tcp": {
|
||||||
|
"defaultMessage": "TCP"
|
||||||
|
},
|
||||||
|
"streams.udp": {
|
||||||
|
"defaultMessage": "UDP"
|
||||||
|
},
|
||||||
|
"test": {
|
||||||
|
"defaultMessage": "Test"
|
||||||
|
},
|
||||||
|
"update-available": {
|
||||||
|
"defaultMessage": "Mise à jour disponible : {latestVersion}"
|
||||||
|
},
|
||||||
|
"user": {
|
||||||
|
"defaultMessage": "Utilisateur"
|
||||||
|
},
|
||||||
|
"user.change-password": {
|
||||||
|
"defaultMessage": "Modifier le mot de passe"
|
||||||
|
},
|
||||||
|
"user.confirm-password": {
|
||||||
|
"defaultMessage": "Confirmer le mot de passe"
|
||||||
|
},
|
||||||
|
"user.current-password": {
|
||||||
|
"defaultMessage": "Mot de passe actuel"
|
||||||
|
},
|
||||||
|
"user.edit-profile": {
|
||||||
|
"defaultMessage": "Modifier le profil"
|
||||||
|
},
|
||||||
|
"user.full-name": {
|
||||||
|
"defaultMessage": "Nom complet"
|
||||||
|
},
|
||||||
|
"user.login-as": {
|
||||||
|
"defaultMessage": "Se connecter en tant que {name}"
|
||||||
|
},
|
||||||
|
"user.logout": {
|
||||||
|
"defaultMessage": "Déconnexion"
|
||||||
|
},
|
||||||
|
"user.new-password": {
|
||||||
|
"defaultMessage": "Nouveau mot de passe"
|
||||||
|
},
|
||||||
|
"user.nickname": {
|
||||||
|
"defaultMessage": "Pseudonyme"
|
||||||
|
},
|
||||||
|
"user.set-password": {
|
||||||
|
"defaultMessage": "Définir le mot de passe"
|
||||||
|
},
|
||||||
|
"user.set-permissions": {
|
||||||
|
"defaultMessage": "Définir les autorisations pour {name}"
|
||||||
|
},
|
||||||
|
"user.switch-dark": {
|
||||||
|
"defaultMessage": "Passer au mode Sombre"
|
||||||
|
},
|
||||||
|
"user.switch-light": {
|
||||||
|
"defaultMessage": "Passer au mode Lumineux"
|
||||||
|
},
|
||||||
|
"username": {
|
||||||
|
"defaultMessage": "Nom d'utilisateur"
|
||||||
|
},
|
||||||
|
"users": {
|
||||||
|
"defaultMessage": "Utilisateurs"
|
||||||
|
}
|
||||||
|
}
|
||||||
683
frontend/src/locale/src/ga.json
Normal file
683
frontend/src/locale/src/ga.json
Normal file
@@ -0,0 +1,683 @@
|
|||||||
|
{
|
||||||
|
"access-list": {
|
||||||
|
"defaultMessage": "Liosta Rochtana"
|
||||||
|
},
|
||||||
|
"access-list.access-count": {
|
||||||
|
"defaultMessage": "{count} {count, plural, one {Rial} other {Rialacha}}"
|
||||||
|
},
|
||||||
|
"access-list.auth-count": {
|
||||||
|
"defaultMessage": "{count} {count, plural, one {Úsáideoir} other {Úsáideoirí}}"
|
||||||
|
},
|
||||||
|
"access-list.help-rules-last": {
|
||||||
|
"defaultMessage": "Nuair a bhíonn riail amháin ar a laghad ann, cuirfear an riail seo chun gach rud a dhiúltú leis an gceann deireanach."
|
||||||
|
},
|
||||||
|
"access-list.help.rules-order": {
|
||||||
|
"defaultMessage": "Tabhair faoi deara go gcuirfear na treoracha ceadaigh agus diúltaigh i bhfeidhm san ord a shainmhínítear iad."
|
||||||
|
},
|
||||||
|
"access-list.pass-auth": {
|
||||||
|
"defaultMessage": "Tabhair Údarú chuig an Sruth Uachtarach"
|
||||||
|
},
|
||||||
|
"access-list.public": {
|
||||||
|
"defaultMessage": "Inrochtana don Phobal"
|
||||||
|
},
|
||||||
|
"access-list.public.subtitle": {
|
||||||
|
"defaultMessage": "Níl aon údarú bunúsach ag teastáil"
|
||||||
|
},
|
||||||
|
"access-list.rule-source.placeholder": {
|
||||||
|
"defaultMessage": "192.168.1.100 nó 192.168.1.0/24 nó 2001:0db8::/32"
|
||||||
|
},
|
||||||
|
"access-list.satisfy-any": {
|
||||||
|
"defaultMessage": "Sásaigh Aon"
|
||||||
|
},
|
||||||
|
"access-list.subtitle": {
|
||||||
|
"defaultMessage": "{users} {users, plural, one {Úsáideoir} other {Úsáideoirí}}, {rules} {rules, plural, one {Riail} other {Rialacha}} - Cruthaithe: {date}"
|
||||||
|
},
|
||||||
|
"access-lists": {
|
||||||
|
"defaultMessage": "Liostaí Rochtana"
|
||||||
|
},
|
||||||
|
"action.add": {
|
||||||
|
"defaultMessage": "Cuir leis"
|
||||||
|
},
|
||||||
|
"action.add-location": {
|
||||||
|
"defaultMessage": "Cuir Suíomh leis"
|
||||||
|
},
|
||||||
|
"action.allow": {
|
||||||
|
"defaultMessage": "Ceadaigh"
|
||||||
|
},
|
||||||
|
"action.close": {
|
||||||
|
"defaultMessage": "Dún"
|
||||||
|
},
|
||||||
|
"action.delete": {
|
||||||
|
"defaultMessage": "Scrios"
|
||||||
|
},
|
||||||
|
"action.deny": {
|
||||||
|
"defaultMessage": "Diúltaigh"
|
||||||
|
},
|
||||||
|
"action.disable": {
|
||||||
|
"defaultMessage": "Díchumasaigh"
|
||||||
|
},
|
||||||
|
"action.download": {
|
||||||
|
"defaultMessage": "Íoslódáil"
|
||||||
|
},
|
||||||
|
"action.edit": {
|
||||||
|
"defaultMessage": "Cuir in Eagar"
|
||||||
|
},
|
||||||
|
"action.enable": {
|
||||||
|
"defaultMessage": "Cumasaigh"
|
||||||
|
},
|
||||||
|
"action.permissions": {
|
||||||
|
"defaultMessage": "Ceadanna"
|
||||||
|
},
|
||||||
|
"action.renew": {
|
||||||
|
"defaultMessage": "Athnuachan"
|
||||||
|
},
|
||||||
|
"action.view-details": {
|
||||||
|
"defaultMessage": "Féach Sonraí"
|
||||||
|
},
|
||||||
|
"auditlogs": {
|
||||||
|
"defaultMessage": "Logaí Iniúchta"
|
||||||
|
},
|
||||||
|
"auto": {
|
||||||
|
"defaultMessage": "Uath"
|
||||||
|
},
|
||||||
|
"cancel": {
|
||||||
|
"defaultMessage": "Cealaigh"
|
||||||
|
},
|
||||||
|
"certificate": {
|
||||||
|
"defaultMessage": "Teastas"
|
||||||
|
},
|
||||||
|
"certificate.custom-certificate": {
|
||||||
|
"defaultMessage": "Teastas"
|
||||||
|
},
|
||||||
|
"certificate.custom-certificate-key": {
|
||||||
|
"defaultMessage": "Eochair Teastais"
|
||||||
|
},
|
||||||
|
"certificate.custom-intermediate": {
|
||||||
|
"defaultMessage": "Teastas Idirmheánach"
|
||||||
|
},
|
||||||
|
"certificate.in-use": {
|
||||||
|
"defaultMessage": "In Úsáid"
|
||||||
|
},
|
||||||
|
"certificate.none.subtitle": {
|
||||||
|
"defaultMessage": "Níor sannadh aon deimhniú"
|
||||||
|
},
|
||||||
|
"certificate.none.subtitle.for-http": {
|
||||||
|
"defaultMessage": "Ní úsáidfidh an t-óstach seo HTTPS"
|
||||||
|
},
|
||||||
|
"certificate.none.title": {
|
||||||
|
"defaultMessage": "Dada"
|
||||||
|
},
|
||||||
|
"certificate.not-in-use": {
|
||||||
|
"defaultMessage": "Níor Úsáideadh"
|
||||||
|
},
|
||||||
|
"certificate.renew": {
|
||||||
|
"defaultMessage": "Athnuachan an Teastais"
|
||||||
|
},
|
||||||
|
"certificates": {
|
||||||
|
"defaultMessage": "Teastais"
|
||||||
|
},
|
||||||
|
"certificates.custom": {
|
||||||
|
"defaultMessage": "Teastas Saincheaptha"
|
||||||
|
},
|
||||||
|
"certificates.custom.warning": {
|
||||||
|
"defaultMessage": "Ní thacaítear le comhaid eochair atá cosanta le frása faire."
|
||||||
|
},
|
||||||
|
"certificates.dns.credentials": {
|
||||||
|
"defaultMessage": "Ábhar Comhaid Dintiúir"
|
||||||
|
},
|
||||||
|
"certificates.dns.credentials-note": {
|
||||||
|
"defaultMessage": "Éilíonn an breiseán seo comhad cumraíochta ina bhfuil comhartha API nó dintiúir eile do do sholáthraí."
|
||||||
|
},
|
||||||
|
"certificates.dns.credentials-warning": {
|
||||||
|
"defaultMessage": "Stórálfar an fhaisnéis seo mar théacs simplí sa bhunachar sonraí agus i gcomhad!"
|
||||||
|
},
|
||||||
|
"certificates.dns.propagation-seconds": {
|
||||||
|
"defaultMessage": "Soicindí Iolraithe"
|
||||||
|
},
|
||||||
|
"certificates.dns.propagation-seconds-note": {
|
||||||
|
"defaultMessage": "Fág folamh chun luach réamhshocraithe na mbreiseán a úsáid. Líon na soicindí le fanacht le haghaidh iomadú DNS."
|
||||||
|
},
|
||||||
|
"certificates.dns.provider": {
|
||||||
|
"defaultMessage": "Soláthraí DNS"
|
||||||
|
},
|
||||||
|
"certificates.dns.provider.placeholder": {
|
||||||
|
"defaultMessage": "Roghnaigh Soláthraí..."
|
||||||
|
},
|
||||||
|
"certificates.dns.warning": {
|
||||||
|
"defaultMessage": "Éilíonn an chuid seo roinnt eolais faoi Certbot agus a bhreiseáin DNS. Féach ar dhoiciméadacht na mbreiseán faoi seach, le do thoil."
|
||||||
|
},
|
||||||
|
"certificates.http.reachability-404": {
|
||||||
|
"defaultMessage": "Tá freastalaí aimsithe ag an bhfearann seo ach ní cosúil gur Bainisteoir Proxy Nginx atá ann. Déan cinnte go bhfuil do fhearann ag pointeáil chuig an seoladh IP ina bhfuil d'eispéireas NPM ag rith."
|
||||||
|
},
|
||||||
|
"certificates.http.reachability-failed-to-check": {
|
||||||
|
"defaultMessage": "Theip ar sheiceáil an inrochtaineachta mar gheall ar earráid chumarsáide le site24x7.com."
|
||||||
|
},
|
||||||
|
"certificates.http.reachability-not-resolved": {
|
||||||
|
"defaultMessage": "Níl aon fhreastalaí ar fáil ag an bhfearann seo. Cinntigh le do thoil go bhfuil do fhearann ann agus go bhfuil sé ag pointeáil chuig an seoladh IP ina bhfuil d'eispéireas NPM ag rith agus más gá, go bhfuil port 80 curtha ar aghaidh i do ródaire."
|
||||||
|
},
|
||||||
|
"certificates.http.reachability-ok": {
|
||||||
|
"defaultMessage": "Tá rochtain ar do fhreastalaí agus ba cheart go mbeadh sé indéanta deimhnithe a chruthú."
|
||||||
|
},
|
||||||
|
"certificates.http.reachability-other": {
|
||||||
|
"defaultMessage": "Tá freastalaí aimsithe ag an bhfearann seo ach thug sé cód stádais gan choinne {code} ar ais. An é an freastalaí NPM atá ann? Déan cinnte go bhfuil do fhearann ag pointeáil chuig an seoladh IP ina bhfuil d'eispéireas NPM ag rith."
|
||||||
|
},
|
||||||
|
"certificates.http.reachability-wrong-data": {
|
||||||
|
"defaultMessage": "Tá freastalaí aimsithe ag an bhfearann seo ach thug sé sonraí gan choinne ar ais. An é an freastalaí NPM atá ann? Déan cinnte go bhfuil do fhearann ag pointeáil chuig an seoladh IP ina bhfuil d'eispéireas NPM ag rith."
|
||||||
|
},
|
||||||
|
"certificates.http.test-results": {
|
||||||
|
"defaultMessage": "Torthaí Tástála"
|
||||||
|
},
|
||||||
|
"certificates.http.warning": {
|
||||||
|
"defaultMessage": "Ní mór na fearainn seo a bheith cumraithe cheana féin chun pointeáil chuig an suiteáil seo."
|
||||||
|
},
|
||||||
|
"certificates.request.subtitle": {
|
||||||
|
"defaultMessage": "le Let's Encrypt"
|
||||||
|
},
|
||||||
|
"certificates.request.title": {
|
||||||
|
"defaultMessage": "Iarr Teastas nua"
|
||||||
|
},
|
||||||
|
"column.access": {
|
||||||
|
"defaultMessage": "Rochtain"
|
||||||
|
},
|
||||||
|
"column.authorization": {
|
||||||
|
"defaultMessage": "Údarú"
|
||||||
|
},
|
||||||
|
"column.authorizations": {
|
||||||
|
"defaultMessage": "Údaruithe"
|
||||||
|
},
|
||||||
|
"column.custom-locations": {
|
||||||
|
"defaultMessage": "Suíomhanna Saincheaptha"
|
||||||
|
},
|
||||||
|
"column.destination": {
|
||||||
|
"defaultMessage": "Ceann Scríbe"
|
||||||
|
},
|
||||||
|
"column.details": {
|
||||||
|
"defaultMessage": "Sonraí"
|
||||||
|
},
|
||||||
|
"column.email": {
|
||||||
|
"defaultMessage": "Ríomhphost"
|
||||||
|
},
|
||||||
|
"column.event": {
|
||||||
|
"defaultMessage": "Imeacht"
|
||||||
|
},
|
||||||
|
"column.expires": {
|
||||||
|
"defaultMessage": "Éagaíonn"
|
||||||
|
},
|
||||||
|
"column.http-code": {
|
||||||
|
"defaultMessage": "Cód HTTP"
|
||||||
|
},
|
||||||
|
"column.incoming-port": {
|
||||||
|
"defaultMessage": "Port Isteach"
|
||||||
|
},
|
||||||
|
"column.name": {
|
||||||
|
"defaultMessage": "Ainm"
|
||||||
|
},
|
||||||
|
"column.protocol": {
|
||||||
|
"defaultMessage": "Prótacal"
|
||||||
|
},
|
||||||
|
"column.provider": {
|
||||||
|
"defaultMessage": "Soláthraí"
|
||||||
|
},
|
||||||
|
"column.roles": {
|
||||||
|
"defaultMessage": "Róil"
|
||||||
|
},
|
||||||
|
"column.rules": {
|
||||||
|
"defaultMessage": "Rialacha"
|
||||||
|
},
|
||||||
|
"column.satisfy": {
|
||||||
|
"defaultMessage": "Sásamh"
|
||||||
|
},
|
||||||
|
"column.satisfy-all": {
|
||||||
|
"defaultMessage": "Gach"
|
||||||
|
},
|
||||||
|
"column.satisfy-any": {
|
||||||
|
"defaultMessage": "Aon"
|
||||||
|
},
|
||||||
|
"column.scheme": {
|
||||||
|
"defaultMessage": "Scéim"
|
||||||
|
},
|
||||||
|
"column.source": {
|
||||||
|
"defaultMessage": "Foinse"
|
||||||
|
},
|
||||||
|
"column.ssl": {
|
||||||
|
"defaultMessage": "SSL"
|
||||||
|
},
|
||||||
|
"column.status": {
|
||||||
|
"defaultMessage": "Stádas"
|
||||||
|
},
|
||||||
|
"created-on": {
|
||||||
|
"defaultMessage": "Cruthaithe: {date}"
|
||||||
|
},
|
||||||
|
"dashboard": {
|
||||||
|
"defaultMessage": "Painéal Rialaithe"
|
||||||
|
},
|
||||||
|
"dead-host": {
|
||||||
|
"defaultMessage": "Óstach 404"
|
||||||
|
},
|
||||||
|
"dead-hosts": {
|
||||||
|
"defaultMessage": "404 Óstaigh"
|
||||||
|
},
|
||||||
|
"dead-hosts.count": {
|
||||||
|
"defaultMessage": "{count} {count, plural, one {Óstach 404} other {Óstaigh 404}}"
|
||||||
|
},
|
||||||
|
"disabled": {
|
||||||
|
"defaultMessage": "Míchumasaithe"
|
||||||
|
},
|
||||||
|
"domain-names": {
|
||||||
|
"defaultMessage": "Ainmneacha Fearainn"
|
||||||
|
},
|
||||||
|
"domain-names.max": {
|
||||||
|
"defaultMessage": "Uasmhéid d'ainmneacha fearainn: {count}"
|
||||||
|
},
|
||||||
|
"domain-names.placeholder": {
|
||||||
|
"defaultMessage": "Tosaigh ag clóscríobh chun fearann a chur leis..."
|
||||||
|
},
|
||||||
|
"domain-names.wildcards-not-permitted": {
|
||||||
|
"defaultMessage": "Ní cheadaítear cártaí fiáine don chineál seo"
|
||||||
|
},
|
||||||
|
"domain-names.wildcards-not-supported": {
|
||||||
|
"defaultMessage": "Ní thacaítear le cártaí fiáine don ÚD seo"
|
||||||
|
},
|
||||||
|
"domains.force-ssl": {
|
||||||
|
"defaultMessage": "Fórsáil SSL"
|
||||||
|
},
|
||||||
|
"domains.hsts-enabled": {
|
||||||
|
"defaultMessage": "Cumasaithe HSTS"
|
||||||
|
},
|
||||||
|
"domains.hsts-subdomains": {
|
||||||
|
"defaultMessage": "Fo-fhearainn HSTS"
|
||||||
|
},
|
||||||
|
"domains.http2-support": {
|
||||||
|
"defaultMessage": "Tacaíocht HTTP/2"
|
||||||
|
},
|
||||||
|
"domains.use-dns": {
|
||||||
|
"defaultMessage": "Úsáid Dúshlán DNS"
|
||||||
|
},
|
||||||
|
"email-address": {
|
||||||
|
"defaultMessage": "Seoladh ríomhphoist"
|
||||||
|
},
|
||||||
|
"empty-search": {
|
||||||
|
"defaultMessage": "Níor aimsíodh aon torthaí"
|
||||||
|
},
|
||||||
|
"empty-subtitle": {
|
||||||
|
"defaultMessage": "Cén fáth nach gcruthaíonn tú ceann?"
|
||||||
|
},
|
||||||
|
"enabled": {
|
||||||
|
"defaultMessage": "Cumasaithe"
|
||||||
|
},
|
||||||
|
"error.access.at-least-one": {
|
||||||
|
"defaultMessage": "Tá Údarú amháin nó Riail Rochtana amháin ag teastáil"
|
||||||
|
},
|
||||||
|
"error.access.duplicate-usernames": {
|
||||||
|
"defaultMessage": "Ní mór d’ainmneacha úsáideora údaraithe a bheith uathúil"
|
||||||
|
},
|
||||||
|
"error.invalid-auth": {
|
||||||
|
"defaultMessage": "Ríomhphost nó pasfhocal neamhbhailí"
|
||||||
|
},
|
||||||
|
"error.invalid-domain": {
|
||||||
|
"defaultMessage": "Fearann neamhbhailí: {domain}"
|
||||||
|
},
|
||||||
|
"error.invalid-email": {
|
||||||
|
"defaultMessage": "Seoladh ríomhphoist neamhbhailí"
|
||||||
|
},
|
||||||
|
"error.max-character-length": {
|
||||||
|
"defaultMessage": "Is é an fad uasta ná {max} carachtar{max, plural, one {} other {anna}}"
|
||||||
|
},
|
||||||
|
"error.max-domains": {
|
||||||
|
"defaultMessage": "An iomarca fearainn, is é {max} an t-uasmhéid"
|
||||||
|
},
|
||||||
|
"error.maximum": {
|
||||||
|
"defaultMessage": "Is é {max} an t-uasmhéid"
|
||||||
|
},
|
||||||
|
"error.min-character-length": {
|
||||||
|
"defaultMessage": "Is é an fad íosta ná {min} carachtar{min, plural, one {} other {anna}}"
|
||||||
|
},
|
||||||
|
"error.minimum": {
|
||||||
|
"defaultMessage": "Is é {min} an t-íosmhéid"
|
||||||
|
},
|
||||||
|
"error.passwords-must-match": {
|
||||||
|
"defaultMessage": "Ní mór pasfhocail a bheith mar a chéile"
|
||||||
|
},
|
||||||
|
"error.required": {
|
||||||
|
"defaultMessage": "Tá sé seo riachtanach"
|
||||||
|
},
|
||||||
|
"expires.on": {
|
||||||
|
"defaultMessage": "Éagaíonn: {date}"
|
||||||
|
},
|
||||||
|
"footer.github-fork": {
|
||||||
|
"defaultMessage": "Forc mé ar Github"
|
||||||
|
},
|
||||||
|
"host.flags.block-exploits": {
|
||||||
|
"defaultMessage": "Blocáil Easnaimh Choitianta"
|
||||||
|
},
|
||||||
|
"host.flags.cache-assets": {
|
||||||
|
"defaultMessage": "Sócmhainní Taisce"
|
||||||
|
},
|
||||||
|
"host.flags.preserve-path": {
|
||||||
|
"defaultMessage": "Cosán a Chaomhnú"
|
||||||
|
},
|
||||||
|
"host.flags.protocols": {
|
||||||
|
"defaultMessage": "Prótacail"
|
||||||
|
},
|
||||||
|
"host.flags.websockets-upgrade": {
|
||||||
|
"defaultMessage": "Tacaíocht Websockets"
|
||||||
|
},
|
||||||
|
"host.forward-port": {
|
||||||
|
"defaultMessage": "Port Ar Aghaidh"
|
||||||
|
},
|
||||||
|
"host.forward-scheme": {
|
||||||
|
"defaultMessage": "Scéim"
|
||||||
|
},
|
||||||
|
"hosts": {
|
||||||
|
"defaultMessage": "Óstaigh"
|
||||||
|
},
|
||||||
|
"http-only": {
|
||||||
|
"defaultMessage": "HTTP Amháin"
|
||||||
|
},
|
||||||
|
"lets-encrypt": {
|
||||||
|
"defaultMessage": "Let's Encrypt"
|
||||||
|
},
|
||||||
|
"lets-encrypt-via-dns": {
|
||||||
|
"defaultMessage": "Let's Encrypt trí DNS"
|
||||||
|
},
|
||||||
|
"lets-encrypt-via-http": {
|
||||||
|
"defaultMessage": "Let's Encrypt trí HTTP"
|
||||||
|
},
|
||||||
|
"loading": {
|
||||||
|
"defaultMessage": "Ag lódáil…"
|
||||||
|
},
|
||||||
|
"login.title": {
|
||||||
|
"defaultMessage": "Logáil isteach i do chuntas"
|
||||||
|
},
|
||||||
|
"nginx-config.label": {
|
||||||
|
"defaultMessage": "Cumraíocht Nginx Saincheaptha"
|
||||||
|
},
|
||||||
|
"nginx-config.placeholder": {
|
||||||
|
"defaultMessage": "# Cuir isteach do chumraíocht saincheaptha Nginx anseo ar do phriacal féin!"
|
||||||
|
},
|
||||||
|
"no-permission-error": {
|
||||||
|
"defaultMessage": "Níl rochtain agat chun seo a fheiceáil."
|
||||||
|
},
|
||||||
|
"notfound.action": {
|
||||||
|
"defaultMessage": "Tabhair abhaile mé"
|
||||||
|
},
|
||||||
|
"notfound.content": {
|
||||||
|
"defaultMessage": "Tá brón orainn ach níor aimsíodh an leathanach atá á lorg agat"
|
||||||
|
},
|
||||||
|
"notfound.title": {
|
||||||
|
"defaultMessage": "Úps… Fuair tú leathanach earráide díreach anois."
|
||||||
|
},
|
||||||
|
"notification.error": {
|
||||||
|
"defaultMessage": "Earráid"
|
||||||
|
},
|
||||||
|
"notification.object-deleted": {
|
||||||
|
"defaultMessage": "Scriosadh {object}"
|
||||||
|
},
|
||||||
|
"notification.object-disabled": {
|
||||||
|
"defaultMessage": "Tá {object} díchumasaithe"
|
||||||
|
},
|
||||||
|
"notification.object-enabled": {
|
||||||
|
"defaultMessage": "Tá {object} cumasaithe"
|
||||||
|
},
|
||||||
|
"notification.object-renewed": {
|
||||||
|
"defaultMessage": "Tá {object} athnuaite"
|
||||||
|
},
|
||||||
|
"notification.object-saved": {
|
||||||
|
"defaultMessage": "Tá {object} sábháilte"
|
||||||
|
},
|
||||||
|
"notification.success": {
|
||||||
|
"defaultMessage": "Rath"
|
||||||
|
},
|
||||||
|
"object.actions-title": {
|
||||||
|
"defaultMessage": "{object} #{id}"
|
||||||
|
},
|
||||||
|
"object.add": {
|
||||||
|
"defaultMessage": "Cuir {object} leis"
|
||||||
|
},
|
||||||
|
"object.delete": {
|
||||||
|
"defaultMessage": "Scrios {object}"
|
||||||
|
},
|
||||||
|
"object.delete.content": {
|
||||||
|
"defaultMessage": "An bhfuil tú cinnte gur mian leat an {object} seo a scriosadh?"
|
||||||
|
},
|
||||||
|
"object.edit": {
|
||||||
|
"defaultMessage": "Cuir in eagar {object}"
|
||||||
|
},
|
||||||
|
"object.empty": {
|
||||||
|
"defaultMessage": "Níl aon {objects} ann"
|
||||||
|
},
|
||||||
|
"object.event.created": {
|
||||||
|
"defaultMessage": "Cruthaithe {object}"
|
||||||
|
},
|
||||||
|
"object.event.deleted": {
|
||||||
|
"defaultMessage": "Scriosadh {object}"
|
||||||
|
},
|
||||||
|
"object.event.disabled": {
|
||||||
|
"defaultMessage": "Díchumasaithe {object}"
|
||||||
|
},
|
||||||
|
"object.event.enabled": {
|
||||||
|
"defaultMessage": "Cumasaithe {object}"
|
||||||
|
},
|
||||||
|
"object.event.renewed": {
|
||||||
|
"defaultMessage": "Athnuaite {object}"
|
||||||
|
},
|
||||||
|
"object.event.updated": {
|
||||||
|
"defaultMessage": "Nuashonraithe {object}"
|
||||||
|
},
|
||||||
|
"offline": {
|
||||||
|
"defaultMessage": "As líne"
|
||||||
|
},
|
||||||
|
"online": {
|
||||||
|
"defaultMessage": "Ar líne"
|
||||||
|
},
|
||||||
|
"options": {
|
||||||
|
"defaultMessage": "Roghanna"
|
||||||
|
},
|
||||||
|
"password": {
|
||||||
|
"defaultMessage": "Pasfhocal"
|
||||||
|
},
|
||||||
|
"password.generate": {
|
||||||
|
"defaultMessage": "Gin pasfhocal randamach"
|
||||||
|
},
|
||||||
|
"password.hide": {
|
||||||
|
"defaultMessage": "Folaigh Pasfhocal"
|
||||||
|
},
|
||||||
|
"password.show": {
|
||||||
|
"defaultMessage": "Taispeáin Pasfhocal"
|
||||||
|
},
|
||||||
|
"permissions.hidden": {
|
||||||
|
"defaultMessage": "I bhfolach"
|
||||||
|
},
|
||||||
|
"permissions.manage": {
|
||||||
|
"defaultMessage": "Bainistigh"
|
||||||
|
},
|
||||||
|
"permissions.view": {
|
||||||
|
"defaultMessage": "Amharc Amháin"
|
||||||
|
},
|
||||||
|
"permissions.visibility.all": {
|
||||||
|
"defaultMessage": "Gach Míreanna"
|
||||||
|
},
|
||||||
|
"permissions.visibility.title": {
|
||||||
|
"defaultMessage": "Infheictheacht Míre"
|
||||||
|
},
|
||||||
|
"permissions.visibility.user": {
|
||||||
|
"defaultMessage": "Míreanna Cruthaithe Amháin"
|
||||||
|
},
|
||||||
|
"proxy-host": {
|
||||||
|
"defaultMessage": "Óstach Seachfhreastalaí"
|
||||||
|
},
|
||||||
|
"proxy-host.forward-host": {
|
||||||
|
"defaultMessage": "Ainm Óstach / IP Ar Aghaidh"
|
||||||
|
},
|
||||||
|
"proxy-hosts": {
|
||||||
|
"defaultMessage": "Óstaigh Seachfhreastalaí"
|
||||||
|
},
|
||||||
|
"proxy-hosts.count": {
|
||||||
|
"defaultMessage": "{count} {count, plural, one {Óstach Seachfhreastalaí} other {Óstaigh Seachfhreastalaí}}"
|
||||||
|
},
|
||||||
|
"public": {
|
||||||
|
"defaultMessage": "Poiblí"
|
||||||
|
},
|
||||||
|
"redirection-host": {
|
||||||
|
"defaultMessage": "Óstach Athsheolta"
|
||||||
|
},
|
||||||
|
"redirection-host.forward-domain": {
|
||||||
|
"defaultMessage": "Fearann Ar Aghaidh"
|
||||||
|
},
|
||||||
|
"redirection-host.forward-http-code": {
|
||||||
|
"defaultMessage": "Cód HTTP"
|
||||||
|
},
|
||||||
|
"redirection-hosts": {
|
||||||
|
"defaultMessage": "Óstaigh Athsheolta"
|
||||||
|
},
|
||||||
|
"redirection-hosts.count": {
|
||||||
|
"defaultMessage": "{count} {count, plural, one {Athsheoladh Óstach} other {Athsheoladh Óstaigh}}"
|
||||||
|
},
|
||||||
|
"redirection-hosts.http-code.300": {
|
||||||
|
"defaultMessage": "300 Rogha Ilghnéitheach"
|
||||||
|
},
|
||||||
|
"redirection-hosts.http-code.301": {
|
||||||
|
"defaultMessage": "301 Bogtha go buan"
|
||||||
|
},
|
||||||
|
"redirection-hosts.http-code.302": {
|
||||||
|
"defaultMessage": "302 Bogtha go sealadach"
|
||||||
|
},
|
||||||
|
"redirection-hosts.http-code.303": {
|
||||||
|
"defaultMessage": "303 Féach eile"
|
||||||
|
},
|
||||||
|
"redirection-hosts.http-code.307": {
|
||||||
|
"defaultMessage": "307 Atreorú sealadach"
|
||||||
|
},
|
||||||
|
"redirection-hosts.http-code.308": {
|
||||||
|
"defaultMessage": "308 Athsheoladh buan"
|
||||||
|
},
|
||||||
|
"role.admin": {
|
||||||
|
"defaultMessage": "Riarthóir"
|
||||||
|
},
|
||||||
|
"role.standard-user": {
|
||||||
|
"defaultMessage": "Úsáideoir Caighdeánach"
|
||||||
|
},
|
||||||
|
"save": {
|
||||||
|
"defaultMessage": "Sábháil"
|
||||||
|
},
|
||||||
|
"setting": {
|
||||||
|
"defaultMessage": "Socrú"
|
||||||
|
},
|
||||||
|
"settings": {
|
||||||
|
"defaultMessage": "Socruithe"
|
||||||
|
},
|
||||||
|
"settings.default-site": {
|
||||||
|
"defaultMessage": "Suíomh Réamhshocraithe"
|
||||||
|
},
|
||||||
|
"settings.default-site.404": {
|
||||||
|
"defaultMessage": "Leathanach 404"
|
||||||
|
},
|
||||||
|
"settings.default-site.444": {
|
||||||
|
"defaultMessage": "Gan Freagra (444)"
|
||||||
|
},
|
||||||
|
"settings.default-site.congratulations": {
|
||||||
|
"defaultMessage": "Leathanach Comhghairdeas"
|
||||||
|
},
|
||||||
|
"settings.default-site.description": {
|
||||||
|
"defaultMessage": "Cad atá le taispeáint nuair a bhuaileann óstach anaithnid Nginx"
|
||||||
|
},
|
||||||
|
"settings.default-site.html": {
|
||||||
|
"defaultMessage": "HTML saincheaptha"
|
||||||
|
},
|
||||||
|
"settings.default-site.html.placeholder": {
|
||||||
|
"defaultMessage": "<!-- Cuir isteach d’ábhar HTML saincheaptha anseo -->"
|
||||||
|
},
|
||||||
|
"settings.default-site.redirect": {
|
||||||
|
"defaultMessage": "Atreorú"
|
||||||
|
},
|
||||||
|
"setup.preamble": {
|
||||||
|
"defaultMessage": "Tosaigh trí do chuntas riarthóra a chruthú."
|
||||||
|
},
|
||||||
|
"setup.title": {
|
||||||
|
"defaultMessage": "Fáilte!"
|
||||||
|
},
|
||||||
|
"sign-in": {
|
||||||
|
"defaultMessage": "Sínigh isteach"
|
||||||
|
},
|
||||||
|
"ssl-certificate": {
|
||||||
|
"defaultMessage": "Teastas SSL"
|
||||||
|
},
|
||||||
|
"stream": {
|
||||||
|
"defaultMessage": "Sruth"
|
||||||
|
},
|
||||||
|
"stream.forward-host": {
|
||||||
|
"defaultMessage": "Óstach Ar Aghaidh"
|
||||||
|
},
|
||||||
|
"stream.forward-host.placeholder": {
|
||||||
|
"defaultMessage": "example.com nó 10.0.0.1 nó 2001:db8:3333:4444:5555:6666:7777:8888"
|
||||||
|
},
|
||||||
|
"stream.incoming-port": {
|
||||||
|
"defaultMessage": "Port Isteach"
|
||||||
|
},
|
||||||
|
"streams": {
|
||||||
|
"defaultMessage": "Sruthanna"
|
||||||
|
},
|
||||||
|
"streams.count": {
|
||||||
|
"defaultMessage": "{count} {count, plural, one {Sruth} other {Sruthanna}}"
|
||||||
|
},
|
||||||
|
"streams.tcp": {
|
||||||
|
"defaultMessage": "TCP"
|
||||||
|
},
|
||||||
|
"streams.udp": {
|
||||||
|
"defaultMessage": "UDP"
|
||||||
|
},
|
||||||
|
"test": {
|
||||||
|
"defaultMessage": "Tástáil"
|
||||||
|
},
|
||||||
|
"update-available": {
|
||||||
|
"defaultMessage": "Nuashonrú ar Fáil: {latestVersion}"
|
||||||
|
},
|
||||||
|
"user": {
|
||||||
|
"defaultMessage": "Úsáideoir"
|
||||||
|
},
|
||||||
|
"user.change-password": {
|
||||||
|
"defaultMessage": "Athraigh Pasfhocal"
|
||||||
|
},
|
||||||
|
"user.confirm-password": {
|
||||||
|
"defaultMessage": "Deimhnigh Pasfhocal"
|
||||||
|
},
|
||||||
|
"user.current-password": {
|
||||||
|
"defaultMessage": "Pasfhocal Reatha"
|
||||||
|
},
|
||||||
|
"user.edit-profile": {
|
||||||
|
"defaultMessage": "Cuir Próifíl in Eagar"
|
||||||
|
},
|
||||||
|
"user.full-name": {
|
||||||
|
"defaultMessage": "Ainm Iomlán"
|
||||||
|
},
|
||||||
|
"user.login-as": {
|
||||||
|
"defaultMessage": "Sínigh isteach mar {name}"
|
||||||
|
},
|
||||||
|
"user.logout": {
|
||||||
|
"defaultMessage": "Logáil Amach"
|
||||||
|
},
|
||||||
|
"user.new-password": {
|
||||||
|
"defaultMessage": "Pasfhocal Nua"
|
||||||
|
},
|
||||||
|
"user.nickname": {
|
||||||
|
"defaultMessage": "Leasainm"
|
||||||
|
},
|
||||||
|
"user.set-password": {
|
||||||
|
"defaultMessage": "Socraigh Pasfhocal"
|
||||||
|
},
|
||||||
|
"user.set-permissions": {
|
||||||
|
"defaultMessage": "Socraigh Ceadanna do {name}"
|
||||||
|
},
|
||||||
|
"user.switch-dark": {
|
||||||
|
"defaultMessage": "Athraigh go Mód Dorcha"
|
||||||
|
},
|
||||||
|
"user.switch-light": {
|
||||||
|
"defaultMessage": "Athraigh go mód Solais"
|
||||||
|
},
|
||||||
|
"username": {
|
||||||
|
"defaultMessage": "Ainm úsáideora"
|
||||||
|
},
|
||||||
|
"users": {
|
||||||
|
"defaultMessage": "Úsáideoirí"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -441,7 +441,7 @@
|
|||||||
"defaultMessage": "Modifica {object}"
|
"defaultMessage": "Modifica {object}"
|
||||||
},
|
},
|
||||||
"object.empty": {
|
"object.empty": {
|
||||||
"defaultMessage": "Nessun {objects} presente"
|
"defaultMessage": "Non ci sono {objects} presenti"
|
||||||
},
|
},
|
||||||
"object.event.created": {
|
"object.event.created": {
|
||||||
"defaultMessage": "{object} creato"
|
"defaultMessage": "{object} creato"
|
||||||
|
|||||||
@@ -1,12 +1,57 @@
|
|||||||
{
|
{
|
||||||
"locale-en-US": {
|
"locale-en-US": {
|
||||||
"defaultMessage": "English"
|
"defaultMessage": "English"
|
||||||
},
|
},
|
||||||
|
"locale-es-ES": {
|
||||||
|
"defaultMessage": "Español"
|
||||||
|
},
|
||||||
|
"locale-ie-GA": {
|
||||||
|
"defaultMessage": "Gaeilge"
|
||||||
|
},
|
||||||
|
"locale-de-DE": {
|
||||||
|
"defaultMessage": "German"
|
||||||
|
},
|
||||||
|
"locale-fr-FR": {
|
||||||
|
"defaultMessage": "Français"
|
||||||
|
},
|
||||||
|
"locale-id-ID": {
|
||||||
|
"defaultMessage": "Bahasa Indonesia"
|
||||||
|
},
|
||||||
|
"locale-ja-JP": {
|
||||||
|
"defaultMessage": "日本語"
|
||||||
|
},
|
||||||
|
"locale-ru-RU": {
|
||||||
|
"defaultMessage": "Русский"
|
||||||
|
},
|
||||||
|
"locale-sk-SK": {
|
||||||
|
"defaultMessage": "Slovenčina"
|
||||||
|
},
|
||||||
|
"locale-zh-CN": {
|
||||||
|
"defaultMessage": "中文"
|
||||||
|
},
|
||||||
|
"locale-pl-PL": {
|
||||||
|
"defaultMessage": "Polski"
|
||||||
|
},
|
||||||
|
"locale-it-IT": {
|
||||||
|
"defaultMessage": "Italiano"
|
||||||
|
},
|
||||||
|
"locale-vi-VN": {
|
||||||
|
"defaultMessage": "Tiếng Việt"
|
||||||
|
},
|
||||||
|
"locale-nl-NL": {
|
||||||
|
"defaultMessage": "Nederlands"
|
||||||
|
},
|
||||||
|
"locale-ko-KR": {
|
||||||
|
"defaultMessage": "한국어"
|
||||||
|
},
|
||||||
|
"locale-bg-BG": {
|
||||||
|
"defaultMessage": "Български"
|
||||||
|
},
|
||||||
"locale-es-ES": {
|
"locale-es-ES": {
|
||||||
"defaultMessage": "Español"
|
"defaultMessage": "Español"
|
||||||
},
|
},
|
||||||
"locale-de-DE": {
|
"locale-de-DE": {
|
||||||
"defaultMessage": "Deutsch"
|
"defaultMessage": "German"
|
||||||
},
|
},
|
||||||
"locale-ja-JP": {
|
"locale-ja-JP": {
|
||||||
"defaultMessage": "日本語"
|
"defaultMessage": "日本語"
|
||||||
@@ -38,7 +83,7 @@
|
|||||||
"locale-bg-BG": {
|
"locale-bg-BG": {
|
||||||
"defaultMessage": "Български"
|
"defaultMessage": "Български"
|
||||||
},
|
},
|
||||||
"locale-id-ID": {
|
"locale-tr-TR": {
|
||||||
"defaultMessage": "Bahasa Indonesia"
|
"defaultMessage": "Türkçe"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"access-list": {
|
"access-list": {
|
||||||
"defaultMessage": "Lista dostępu"
|
"defaultMessage": "wpis listy dostępu"
|
||||||
},
|
},
|
||||||
"access-list.access-count": {
|
"access-list.access-count": {
|
||||||
"defaultMessage": "{count} {count, plural, one {Reguła} few {Reguły} other {Reguł}}"
|
"defaultMessage": "{count} {count, plural, one {Reguła} few {Reguły} other {Reguł}}"
|
||||||
},
|
},
|
||||||
"access-list.auth-count": {
|
"access-list.auth-count": {
|
||||||
"defaultMessage": "{count} {count, plural, one {Użytkownik} few {Użytkowników} other {Użytkowników}}"
|
"defaultMessage": "{count} {count, plural, one {Użytkownik} few {Użytkownicy} other {Użytkowników}}"
|
||||||
},
|
},
|
||||||
"access-list.help-rules-last": {
|
"access-list.help-rules-last": {
|
||||||
"defaultMessage": "Gdy istnieje co najmniej 1 reguła, ta reguła blokująca wszystko zostanie dodana na końcu"
|
"defaultMessage": "Gdy istnieje co najmniej 1 reguła, ta reguła blokująca wszystko zostanie dodana na końcu"
|
||||||
@@ -38,12 +38,18 @@
|
|||||||
"action.add-location": {
|
"action.add-location": {
|
||||||
"defaultMessage": "Dodaj lokalizację"
|
"defaultMessage": "Dodaj lokalizację"
|
||||||
},
|
},
|
||||||
|
"action.allow": {
|
||||||
|
"defaultMessage": "Zezwól"
|
||||||
|
},
|
||||||
"action.close": {
|
"action.close": {
|
||||||
"defaultMessage": "Zamknij"
|
"defaultMessage": "Zamknij"
|
||||||
},
|
},
|
||||||
"action.delete": {
|
"action.delete": {
|
||||||
"defaultMessage": "Usuń"
|
"defaultMessage": "Usuń"
|
||||||
},
|
},
|
||||||
|
"action.deny": {
|
||||||
|
"defaultMessage": "Odrzuć"
|
||||||
|
},
|
||||||
"action.disable": {
|
"action.disable": {
|
||||||
"defaultMessage": "Wyłącz"
|
"defaultMessage": "Wyłącz"
|
||||||
},
|
},
|
||||||
@@ -66,13 +72,13 @@
|
|||||||
"defaultMessage": "Pokaż szczegóły"
|
"defaultMessage": "Pokaż szczegóły"
|
||||||
},
|
},
|
||||||
"auditlogs": {
|
"auditlogs": {
|
||||||
"defaultMessage": "Logi audytu"
|
"defaultMessage": "Logi"
|
||||||
},
|
},
|
||||||
"cancel": {
|
"cancel": {
|
||||||
"defaultMessage": "Anuluj"
|
"defaultMessage": "Anuluj"
|
||||||
},
|
},
|
||||||
"certificate": {
|
"certificate": {
|
||||||
"defaultMessage": "Certyfikat"
|
"defaultMessage": "certyfikat"
|
||||||
},
|
},
|
||||||
"certificate.custom-certificate": {
|
"certificate.custom-certificate": {
|
||||||
"defaultMessage": "Certyfikat"
|
"defaultMessage": "Certyfikat"
|
||||||
@@ -105,7 +111,7 @@
|
|||||||
"defaultMessage": "Certyfikaty"
|
"defaultMessage": "Certyfikaty"
|
||||||
},
|
},
|
||||||
"certificates.custom": {
|
"certificates.custom": {
|
||||||
"defaultMessage": "Certyfikat własny"
|
"defaultMessage": "Własny certyfikat"
|
||||||
},
|
},
|
||||||
"certificates.custom.warning": {
|
"certificates.custom.warning": {
|
||||||
"defaultMessage": "Pliki kluczy chronione hasłem nie są obsługiwane."
|
"defaultMessage": "Pliki kluczy chronione hasłem nie są obsługiwane."
|
||||||
@@ -153,7 +159,7 @@
|
|||||||
"defaultMessage": "Wyniki testu"
|
"defaultMessage": "Wyniki testu"
|
||||||
},
|
},
|
||||||
"certificates.http.warning": {
|
"certificates.http.warning": {
|
||||||
"defaultMessage": "Te domeny muszą być już skonfigurowane tak, aby wskazywały na ten serwer www"
|
"defaultMessage": "Te domeny muszą być już skonfigurowane tak, aby wskazywały na ten serwer"
|
||||||
},
|
},
|
||||||
"certificates.key-type": {
|
"certificates.key-type": {
|
||||||
"defaultMessage": "Typ klucza"
|
"defaultMessage": "Typ klucza"
|
||||||
@@ -171,7 +177,7 @@
|
|||||||
"defaultMessage": "z Let's Encrypt"
|
"defaultMessage": "z Let's Encrypt"
|
||||||
},
|
},
|
||||||
"certificates.request.title": {
|
"certificates.request.title": {
|
||||||
"defaultMessage": "Zamów nowy certyfikat"
|
"defaultMessage": "Wygeneruj nowy certyfikat"
|
||||||
},
|
},
|
||||||
"column.access": {
|
"column.access": {
|
||||||
"defaultMessage": "Dostęp"
|
"defaultMessage": "Dostęp"
|
||||||
@@ -183,7 +189,7 @@
|
|||||||
"defaultMessage": "Autoryzacje"
|
"defaultMessage": "Autoryzacje"
|
||||||
},
|
},
|
||||||
"column.custom-locations": {
|
"column.custom-locations": {
|
||||||
"defaultMessage": "Własne lokalizacje"
|
"defaultMessage": "Własne ustawienia lokalizacji"
|
||||||
},
|
},
|
||||||
"column.destination": {
|
"column.destination": {
|
||||||
"defaultMessage": "Cel"
|
"defaultMessage": "Cel"
|
||||||
@@ -249,13 +255,13 @@
|
|||||||
"defaultMessage": "Panel"
|
"defaultMessage": "Panel"
|
||||||
},
|
},
|
||||||
"dead-host": {
|
"dead-host": {
|
||||||
"defaultMessage": "Host 404"
|
"defaultMessage": "host 404"
|
||||||
},
|
},
|
||||||
"dead-hosts": {
|
"dead-hosts": {
|
||||||
"defaultMessage": "Hosty 404"
|
"defaultMessage": "404"
|
||||||
},
|
},
|
||||||
"dead-hosts.count": {
|
"dead-hosts.count": {
|
||||||
"defaultMessage": "{count} {count, plural, one {Host 404} few {Hosty 404} other {Hostów 404}}"
|
"defaultMessage": "{count} {count, plural, one {host 404} few {hosty 404} other {hostów 404}}"
|
||||||
},
|
},
|
||||||
"disabled": {
|
"disabled": {
|
||||||
"defaultMessage": "Wyłączone"
|
"defaultMessage": "Wyłączone"
|
||||||
@@ -279,7 +285,7 @@
|
|||||||
"defaultMessage": "Wymuś SSL"
|
"defaultMessage": "Wymuś SSL"
|
||||||
},
|
},
|
||||||
"domains.hsts-enabled": {
|
"domains.hsts-enabled": {
|
||||||
"defaultMessage": "HSTS włączone"
|
"defaultMessage": "Włącz HSTS "
|
||||||
},
|
},
|
||||||
"domains.hsts-subdomains": {
|
"domains.hsts-subdomains": {
|
||||||
"defaultMessage": "HSTS dla subdomen"
|
"defaultMessage": "HSTS dla subdomen"
|
||||||
@@ -348,7 +354,7 @@
|
|||||||
"defaultMessage": "Blokuj typowe exploity"
|
"defaultMessage": "Blokuj typowe exploity"
|
||||||
},
|
},
|
||||||
"host.flags.cache-assets": {
|
"host.flags.cache-assets": {
|
||||||
"defaultMessage": "Buforuj zasoby"
|
"defaultMessage": "Buforuj zasoby statyczne (ang. cache)"
|
||||||
},
|
},
|
||||||
"host.flags.preserve-path": {
|
"host.flags.preserve-path": {
|
||||||
"defaultMessage": "Zachowaj ścieżkę"
|
"defaultMessage": "Zachowaj ścieżkę"
|
||||||
@@ -360,7 +366,7 @@
|
|||||||
"defaultMessage": "Obsługa WebSockets"
|
"defaultMessage": "Obsługa WebSockets"
|
||||||
},
|
},
|
||||||
"host.forward-port": {
|
"host.forward-port": {
|
||||||
"defaultMessage": "Port przekierowania"
|
"defaultMessage": "Port docelowy"
|
||||||
},
|
},
|
||||||
"host.forward-scheme": {
|
"host.forward-scheme": {
|
||||||
"defaultMessage": "Schemat"
|
"defaultMessage": "Schemat"
|
||||||
@@ -501,22 +507,22 @@
|
|||||||
"defaultMessage": "Tylko utworzone elementy"
|
"defaultMessage": "Tylko utworzone elementy"
|
||||||
},
|
},
|
||||||
"proxy-host": {
|
"proxy-host": {
|
||||||
"defaultMessage": "Host proxy"
|
"defaultMessage": "host proxy"
|
||||||
},
|
},
|
||||||
"proxy-host.forward-host": {
|
"proxy-host.forward-host": {
|
||||||
"defaultMessage": "Przekieruj na hostname / IP"
|
"defaultMessage": "Przekieruj na hostname / IP"
|
||||||
},
|
},
|
||||||
"proxy-hosts": {
|
"proxy-hosts": {
|
||||||
"defaultMessage": "Hosty proxy"
|
"defaultMessage": "Proxy"
|
||||||
},
|
},
|
||||||
"proxy-hosts.count": {
|
"proxy-hosts.count": {
|
||||||
"defaultMessage": "{count} {count, plural, one {Host proxy} few {Hosty proxy} other {Hostów proxy}}"
|
"defaultMessage": "{count} {count, plural, one {host proxy} few {hosty proxy} many {hostów proxy} other {hostów proxy}}"
|
||||||
},
|
},
|
||||||
"public": {
|
"public": {
|
||||||
"defaultMessage": "Publiczne"
|
"defaultMessage": "Publiczne"
|
||||||
},
|
},
|
||||||
"redirection-host": {
|
"redirection-host": {
|
||||||
"defaultMessage": "Host przekierowania"
|
"defaultMessage": "adres przekierowania"
|
||||||
},
|
},
|
||||||
"redirection-host.forward-domain": {
|
"redirection-host.forward-domain": {
|
||||||
"defaultMessage": "Domena docelowa"
|
"defaultMessage": "Domena docelowa"
|
||||||
@@ -525,10 +531,10 @@
|
|||||||
"defaultMessage": "Kod HTTP"
|
"defaultMessage": "Kod HTTP"
|
||||||
},
|
},
|
||||||
"redirection-hosts": {
|
"redirection-hosts": {
|
||||||
"defaultMessage": "Hosty przekierowań"
|
"defaultMessage": "Przekierowania"
|
||||||
},
|
},
|
||||||
"redirection-hosts.count": {
|
"redirection-hosts.count": {
|
||||||
"defaultMessage": "{count} {count, plural, one {Host przekierowania} few {Hosty przekierowań} other {Hostów przekierowań}}"
|
"defaultMessage": "{count} {count, plural, one {przekierowanie} few {przekierowania} many {przekierowań} other {przekierowań}}"
|
||||||
},
|
},
|
||||||
"role.admin": {
|
"role.admin": {
|
||||||
"defaultMessage": "Administrator"
|
"defaultMessage": "Administrator"
|
||||||
@@ -582,7 +588,7 @@
|
|||||||
"defaultMessage": "Certyfikat SSL"
|
"defaultMessage": "Certyfikat SSL"
|
||||||
},
|
},
|
||||||
"stream": {
|
"stream": {
|
||||||
"defaultMessage": "Strumień"
|
"defaultMessage": "strumień"
|
||||||
},
|
},
|
||||||
"stream.forward-host": {
|
"stream.forward-host": {
|
||||||
"defaultMessage": "Host docelowy"
|
"defaultMessage": "Host docelowy"
|
||||||
@@ -594,7 +600,7 @@
|
|||||||
"defaultMessage": "Strumienie"
|
"defaultMessage": "Strumienie"
|
||||||
},
|
},
|
||||||
"streams.count": {
|
"streams.count": {
|
||||||
"defaultMessage": "{count} {count, plural, one {Strumień} few {Strumienie} other {Strumieni}}"
|
"defaultMessage": "{count} {count, plural, one {strumień} few {strumienie} many {strumieni} other {strumieni}}"
|
||||||
},
|
},
|
||||||
"streams.tcp": {
|
"streams.tcp": {
|
||||||
"defaultMessage": "TCP"
|
"defaultMessage": "TCP"
|
||||||
@@ -606,13 +612,13 @@
|
|||||||
"defaultMessage": "Test"
|
"defaultMessage": "Test"
|
||||||
},
|
},
|
||||||
"user": {
|
"user": {
|
||||||
"defaultMessage": "Użytkownik"
|
"defaultMessage": "użytkownik"
|
||||||
},
|
},
|
||||||
"user.change-password": {
|
"user.change-password": {
|
||||||
"defaultMessage": "Zmień hasło"
|
"defaultMessage": "Zmień hasło"
|
||||||
},
|
},
|
||||||
"user.confirm-password": {
|
"user.confirm-password": {
|
||||||
"defaultMessage": "Potwierdź hasło"
|
"defaultMessage": "Potwierdź nowe hasło"
|
||||||
},
|
},
|
||||||
"user.current-password": {
|
"user.current-password": {
|
||||||
"defaultMessage": "Aktualne hasło"
|
"defaultMessage": "Aktualne hasło"
|
||||||
@@ -621,7 +627,7 @@
|
|||||||
"defaultMessage": "Edytuj profil"
|
"defaultMessage": "Edytuj profil"
|
||||||
},
|
},
|
||||||
"user.full-name": {
|
"user.full-name": {
|
||||||
"defaultMessage": "Pełne imię i nazwisko"
|
"defaultMessage": "Imię / Nazwisko"
|
||||||
},
|
},
|
||||||
"user.login-as": {
|
"user.login-as": {
|
||||||
"defaultMessage": "Zaloguj jako {name}"
|
"defaultMessage": "Zaloguj jako {name}"
|
||||||
|
|||||||
683
frontend/src/locale/src/tr.json
Normal file
683
frontend/src/locale/src/tr.json
Normal file
@@ -0,0 +1,683 @@
|
|||||||
|
{
|
||||||
|
"access-list": {
|
||||||
|
"defaultMessage": "Erişim Listesi"
|
||||||
|
},
|
||||||
|
"access-list.access-count": {
|
||||||
|
"defaultMessage": "{count} {count, plural, one {Kural} other {Kural}}"
|
||||||
|
},
|
||||||
|
"access-list.auth-count": {
|
||||||
|
"defaultMessage": "{count} {count, plural, one {Kullanıcı} other {Kullanıcı}}"
|
||||||
|
},
|
||||||
|
"access-list.help-rules-last": {
|
||||||
|
"defaultMessage": "En az 1 kural mevcut olduğunda, bu tümünü reddet kuralı en son eklenir"
|
||||||
|
},
|
||||||
|
"access-list.help.rules-order": {
|
||||||
|
"defaultMessage": "İzin ver ve reddet direktiflerinin tanımlandıkları sırayla uygulanacağını unutmayın."
|
||||||
|
},
|
||||||
|
"access-list.pass-auth": {
|
||||||
|
"defaultMessage": "Kimlik Doğrulamayı Yukarı Akışa İlet"
|
||||||
|
},
|
||||||
|
"access-list.public": {
|
||||||
|
"defaultMessage": "Herkese Açık"
|
||||||
|
},
|
||||||
|
"access-list.public.subtitle": {
|
||||||
|
"defaultMessage": "Temel kimlik doğrulama gerekmez"
|
||||||
|
},
|
||||||
|
"access-list.rule-source.placeholder": {
|
||||||
|
"defaultMessage": "192.168.1.100 veya 192.168.1.0/24 veya 2001:0db8::/32"
|
||||||
|
},
|
||||||
|
"access-list.satisfy-any": {
|
||||||
|
"defaultMessage": "Herhangi Birini Karşıla"
|
||||||
|
},
|
||||||
|
"access-list.subtitle": {
|
||||||
|
"defaultMessage": "{users} {users, plural, one {Kullanıcı} other {Kullanıcı}}, {rules} {rules, plural, one {Kural} other {Kural}} - Oluşturuldu: {date}"
|
||||||
|
},
|
||||||
|
"access-lists": {
|
||||||
|
"defaultMessage": "Erişim Listeleri"
|
||||||
|
},
|
||||||
|
"action.add": {
|
||||||
|
"defaultMessage": "Ekle"
|
||||||
|
},
|
||||||
|
"action.add-location": {
|
||||||
|
"defaultMessage": "Konum Ekle"
|
||||||
|
},
|
||||||
|
"action.allow": {
|
||||||
|
"defaultMessage": "İzin Ver"
|
||||||
|
},
|
||||||
|
"action.close": {
|
||||||
|
"defaultMessage": "Kapat"
|
||||||
|
},
|
||||||
|
"action.delete": {
|
||||||
|
"defaultMessage": "Sil"
|
||||||
|
},
|
||||||
|
"action.deny": {
|
||||||
|
"defaultMessage": "Reddet"
|
||||||
|
},
|
||||||
|
"action.disable": {
|
||||||
|
"defaultMessage": "Devre Dışı Bırak"
|
||||||
|
},
|
||||||
|
"action.download": {
|
||||||
|
"defaultMessage": "İndir"
|
||||||
|
},
|
||||||
|
"action.edit": {
|
||||||
|
"defaultMessage": "Düzenle"
|
||||||
|
},
|
||||||
|
"action.enable": {
|
||||||
|
"defaultMessage": "Etkinleştir"
|
||||||
|
},
|
||||||
|
"action.permissions": {
|
||||||
|
"defaultMessage": "İzinler"
|
||||||
|
},
|
||||||
|
"action.renew": {
|
||||||
|
"defaultMessage": "Yenile"
|
||||||
|
},
|
||||||
|
"action.view-details": {
|
||||||
|
"defaultMessage": "Detayları Görüntüle"
|
||||||
|
},
|
||||||
|
"auditlogs": {
|
||||||
|
"defaultMessage": "Denetim Kayıtları"
|
||||||
|
},
|
||||||
|
"auto": {
|
||||||
|
"defaultMessage": "Otomatik"
|
||||||
|
},
|
||||||
|
"cancel": {
|
||||||
|
"defaultMessage": "İptal"
|
||||||
|
},
|
||||||
|
"certificate": {
|
||||||
|
"defaultMessage": "Sertifika"
|
||||||
|
},
|
||||||
|
"certificate.custom-certificate": {
|
||||||
|
"defaultMessage": "Sertifika"
|
||||||
|
},
|
||||||
|
"certificate.custom-certificate-key": {
|
||||||
|
"defaultMessage": "Sertifika Anahtarı"
|
||||||
|
},
|
||||||
|
"certificate.custom-intermediate": {
|
||||||
|
"defaultMessage": "Ara Sertifika"
|
||||||
|
},
|
||||||
|
"certificate.in-use": {
|
||||||
|
"defaultMessage": "Kullanımda"
|
||||||
|
},
|
||||||
|
"certificate.none.subtitle": {
|
||||||
|
"defaultMessage": "Sertifika atanmamış"
|
||||||
|
},
|
||||||
|
"certificate.none.subtitle.for-http": {
|
||||||
|
"defaultMessage": "Bu host HTTPS kullanmayacak"
|
||||||
|
},
|
||||||
|
"certificate.none.title": {
|
||||||
|
"defaultMessage": "Yok"
|
||||||
|
},
|
||||||
|
"certificate.not-in-use": {
|
||||||
|
"defaultMessage": "Kullanılmıyor"
|
||||||
|
},
|
||||||
|
"certificate.renew": {
|
||||||
|
"defaultMessage": "Sertifikayı Yenile"
|
||||||
|
},
|
||||||
|
"certificates": {
|
||||||
|
"defaultMessage": "Sertifikalar"
|
||||||
|
},
|
||||||
|
"certificates.custom": {
|
||||||
|
"defaultMessage": "Özel Sertifika"
|
||||||
|
},
|
||||||
|
"certificates.custom.warning": {
|
||||||
|
"defaultMessage": "Parola ile korumalı anahtar dosyaları desteklenmiyor."
|
||||||
|
},
|
||||||
|
"certificates.dns.credentials": {
|
||||||
|
"defaultMessage": "Kimlik Bilgileri Dosya İçeriği"
|
||||||
|
},
|
||||||
|
"certificates.dns.credentials-note": {
|
||||||
|
"defaultMessage": "Bu eklenti, sağlayıcınız için bir API token'ı veya diğer kimlik bilgilerini içeren bir yapılandırma dosyası gerektirir"
|
||||||
|
},
|
||||||
|
"certificates.dns.credentials-warning": {
|
||||||
|
"defaultMessage": "Bu veriler veritabanında ve bir dosyada düz metin olarak saklanacak!"
|
||||||
|
},
|
||||||
|
"certificates.dns.propagation-seconds": {
|
||||||
|
"defaultMessage": "Yayılma Saniyesi"
|
||||||
|
},
|
||||||
|
"certificates.dns.propagation-seconds-note": {
|
||||||
|
"defaultMessage": "Eklentinin varsayılan değerini kullanmak için boş bırakın. DNS yayılması için beklenilecek saniye sayısı."
|
||||||
|
},
|
||||||
|
"certificates.dns.provider": {
|
||||||
|
"defaultMessage": "DNS Sağlayıcı"
|
||||||
|
},
|
||||||
|
"certificates.dns.provider.placeholder": {
|
||||||
|
"defaultMessage": "Bir Sağlayıcı Seçin..."
|
||||||
|
},
|
||||||
|
"certificates.dns.warning": {
|
||||||
|
"defaultMessage": "Bu bölüm Certbot ve DNS eklentileri hakkında bazı bilgiler gerektirir. Lütfen ilgili eklenti dokümantasyonuna bakın."
|
||||||
|
},
|
||||||
|
"certificates.http.reachability-404": {
|
||||||
|
"defaultMessage": "Bu alan adında bir sunucu bulundu ancak Nginx Proxy Manager gibi görünmüyor. Lütfen alan adınızın NPM örneğinizin çalıştığı IP'ye işaret ettiğinden emin olun."
|
||||||
|
},
|
||||||
|
"certificates.http.reachability-failed-to-check": {
|
||||||
|
"defaultMessage": "site24x7.com ile iletişim hatası nedeniyle erişilebilirlik kontrolü başarısız oldu."
|
||||||
|
},
|
||||||
|
"certificates.http.reachability-not-resolved": {
|
||||||
|
"defaultMessage": "Bu alan adında kullanılabilir bir sunucu yok. Lütfen alan adınızın mevcut olduğundan ve NPM örneğinizin çalıştığı IP'ye işaret ettiğinden ve gerekirse yönlendiricinizde 80 portunun yönlendirildiğinden emin olun."
|
||||||
|
},
|
||||||
|
"certificates.http.reachability-ok": {
|
||||||
|
"defaultMessage": "Sunucunuz erişilebilir ve sertifika oluşturma mümkün olmalı."
|
||||||
|
},
|
||||||
|
"certificates.http.reachability-other": {
|
||||||
|
"defaultMessage": "Bu alan adında bir sunucu bulundu ancak beklenmeyen bir durum kodu döndürdü {code}. Bu NPM sunucusu mu? Lütfen alan adınızın NPM örneğinizin çalıştığı IP'ye işaret ettiğinden emin olun."
|
||||||
|
},
|
||||||
|
"certificates.http.reachability-wrong-data": {
|
||||||
|
"defaultMessage": "Bu alan adında bir sunucu bulundu ancak beklenmeyen veri döndürdü. Bu NPM sunucusu mu? Lütfen alan adınızın NPM örneğinizin çalıştığı IP'ye işaret ettiğinden emin olun."
|
||||||
|
},
|
||||||
|
"certificates.http.test-results": {
|
||||||
|
"defaultMessage": "Test Sonuçları"
|
||||||
|
},
|
||||||
|
"certificates.http.warning": {
|
||||||
|
"defaultMessage": "Bu alan adları zaten bu kuruluma işaret edecek şekilde yapılandırılmış olmalıdır."
|
||||||
|
},
|
||||||
|
"certificates.request.subtitle": {
|
||||||
|
"defaultMessage": "Let's Encrypt ile"
|
||||||
|
},
|
||||||
|
"certificates.request.title": {
|
||||||
|
"defaultMessage": "Yeni Sertifika İste"
|
||||||
|
},
|
||||||
|
"column.access": {
|
||||||
|
"defaultMessage": "Erişim"
|
||||||
|
},
|
||||||
|
"column.authorization": {
|
||||||
|
"defaultMessage": "Yetkilendirme"
|
||||||
|
},
|
||||||
|
"column.authorizations": {
|
||||||
|
"defaultMessage": "Yetkilendirmeler"
|
||||||
|
},
|
||||||
|
"column.custom-locations": {
|
||||||
|
"defaultMessage": "Özel Konumlar"
|
||||||
|
},
|
||||||
|
"column.destination": {
|
||||||
|
"defaultMessage": "Hedef"
|
||||||
|
},
|
||||||
|
"column.details": {
|
||||||
|
"defaultMessage": "Detaylar"
|
||||||
|
},
|
||||||
|
"column.email": {
|
||||||
|
"defaultMessage": "E-posta"
|
||||||
|
},
|
||||||
|
"column.event": {
|
||||||
|
"defaultMessage": "Olay"
|
||||||
|
},
|
||||||
|
"column.expires": {
|
||||||
|
"defaultMessage": "Sona Erer"
|
||||||
|
},
|
||||||
|
"column.http-code": {
|
||||||
|
"defaultMessage": "HTTP Kodu"
|
||||||
|
},
|
||||||
|
"column.incoming-port": {
|
||||||
|
"defaultMessage": "Gelen Port"
|
||||||
|
},
|
||||||
|
"column.name": {
|
||||||
|
"defaultMessage": "Ad"
|
||||||
|
},
|
||||||
|
"column.protocol": {
|
||||||
|
"defaultMessage": "Protokol"
|
||||||
|
},
|
||||||
|
"column.provider": {
|
||||||
|
"defaultMessage": "Sağlayıcı"
|
||||||
|
},
|
||||||
|
"column.roles": {
|
||||||
|
"defaultMessage": "Roller"
|
||||||
|
},
|
||||||
|
"column.rules": {
|
||||||
|
"defaultMessage": "Kurallar"
|
||||||
|
},
|
||||||
|
"column.satisfy": {
|
||||||
|
"defaultMessage": "Karşıla"
|
||||||
|
},
|
||||||
|
"column.satisfy-all": {
|
||||||
|
"defaultMessage": "Tümü"
|
||||||
|
},
|
||||||
|
"column.satisfy-any": {
|
||||||
|
"defaultMessage": "Herhangi Biri"
|
||||||
|
},
|
||||||
|
"column.scheme": {
|
||||||
|
"defaultMessage": "Şema"
|
||||||
|
},
|
||||||
|
"column.source": {
|
||||||
|
"defaultMessage": "Kaynak"
|
||||||
|
},
|
||||||
|
"column.ssl": {
|
||||||
|
"defaultMessage": "SSL"
|
||||||
|
},
|
||||||
|
"column.status": {
|
||||||
|
"defaultMessage": "Durum"
|
||||||
|
},
|
||||||
|
"created-on": {
|
||||||
|
"defaultMessage": "Oluşturuldu: {date}"
|
||||||
|
},
|
||||||
|
"dashboard": {
|
||||||
|
"defaultMessage": "Kontrol Paneli"
|
||||||
|
},
|
||||||
|
"dead-host": {
|
||||||
|
"defaultMessage": "404 Host"
|
||||||
|
},
|
||||||
|
"dead-hosts": {
|
||||||
|
"defaultMessage": "404 Host'lar"
|
||||||
|
},
|
||||||
|
"dead-hosts.count": {
|
||||||
|
"defaultMessage": "{count} {count, plural, one {404 Host} other {404 Host}}"
|
||||||
|
},
|
||||||
|
"disabled": {
|
||||||
|
"defaultMessage": "Devre Dışı"
|
||||||
|
},
|
||||||
|
"domain-names": {
|
||||||
|
"defaultMessage": "Alan Adları"
|
||||||
|
},
|
||||||
|
"domain-names.max": {
|
||||||
|
"defaultMessage": "Maksimum {count} alan adı"
|
||||||
|
},
|
||||||
|
"domain-names.placeholder": {
|
||||||
|
"defaultMessage": "Alan adı eklemek için yazmaya başlayın..."
|
||||||
|
},
|
||||||
|
"domain-names.wildcards-not-permitted": {
|
||||||
|
"defaultMessage": "Bu tür için joker karakterler izin verilmez"
|
||||||
|
},
|
||||||
|
"domain-names.wildcards-not-supported": {
|
||||||
|
"defaultMessage": "Bu CA için joker karakterler desteklenmiyor"
|
||||||
|
},
|
||||||
|
"domains.force-ssl": {
|
||||||
|
"defaultMessage": "SSL'i Zorla"
|
||||||
|
},
|
||||||
|
"domains.hsts-enabled": {
|
||||||
|
"defaultMessage": "HSTS Etkin"
|
||||||
|
},
|
||||||
|
"domains.hsts-subdomains": {
|
||||||
|
"defaultMessage": "HSTS Alt Alan Adları"
|
||||||
|
},
|
||||||
|
"domains.http2-support": {
|
||||||
|
"defaultMessage": "HTTP/2 Desteği"
|
||||||
|
},
|
||||||
|
"domains.use-dns": {
|
||||||
|
"defaultMessage": "DNS Challenge Kullan"
|
||||||
|
},
|
||||||
|
"email-address": {
|
||||||
|
"defaultMessage": "E-posta adresi"
|
||||||
|
},
|
||||||
|
"empty-search": {
|
||||||
|
"defaultMessage": "Sonuç bulunamadı"
|
||||||
|
},
|
||||||
|
"empty-subtitle": {
|
||||||
|
"defaultMessage": "Neden bir tane oluşturmuyorsunuz?"
|
||||||
|
},
|
||||||
|
"enabled": {
|
||||||
|
"defaultMessage": "Etkin"
|
||||||
|
},
|
||||||
|
"error.access.at-least-one": {
|
||||||
|
"defaultMessage": "Ya bir Yetkilendirme ya da bir Erişim Kuralı gereklidir"
|
||||||
|
},
|
||||||
|
"error.access.duplicate-usernames": {
|
||||||
|
"defaultMessage": "Yetkilendirme Kullanıcı Adları benzersiz olmalıdır"
|
||||||
|
},
|
||||||
|
"error.invalid-auth": {
|
||||||
|
"defaultMessage": "Geçersiz e-posta veya şifre"
|
||||||
|
},
|
||||||
|
"error.invalid-domain": {
|
||||||
|
"defaultMessage": "Geçersiz alan adı: {domain}"
|
||||||
|
},
|
||||||
|
"error.invalid-email": {
|
||||||
|
"defaultMessage": "Geçersiz e-posta adresi"
|
||||||
|
},
|
||||||
|
"error.max-character-length": {
|
||||||
|
"defaultMessage": "Maksimum uzunluk {max} karakter{max, plural, one {} other {}}"
|
||||||
|
},
|
||||||
|
"error.max-domains": {
|
||||||
|
"defaultMessage": "Çok fazla alan adı, maksimum {max}"
|
||||||
|
},
|
||||||
|
"error.maximum": {
|
||||||
|
"defaultMessage": "Maksimum {max}"
|
||||||
|
},
|
||||||
|
"error.min-character-length": {
|
||||||
|
"defaultMessage": "Minimum uzunluk {min} karakter{min, plural, one {} other {}}"
|
||||||
|
},
|
||||||
|
"error.minimum": {
|
||||||
|
"defaultMessage": "Minimum {min}"
|
||||||
|
},
|
||||||
|
"error.passwords-must-match": {
|
||||||
|
"defaultMessage": "Şifreler eşleşmelidir"
|
||||||
|
},
|
||||||
|
"error.required": {
|
||||||
|
"defaultMessage": "Bu gereklidir"
|
||||||
|
},
|
||||||
|
"expires.on": {
|
||||||
|
"defaultMessage": "Sona Erer: {date}"
|
||||||
|
},
|
||||||
|
"footer.github-fork": {
|
||||||
|
"defaultMessage": "Github'da Fork Yap"
|
||||||
|
},
|
||||||
|
"host.flags.block-exploits": {
|
||||||
|
"defaultMessage": "Yaygın Saldırıları Engelle"
|
||||||
|
},
|
||||||
|
"host.flags.cache-assets": {
|
||||||
|
"defaultMessage": "Varlıkları Önbelleğe Al"
|
||||||
|
},
|
||||||
|
"host.flags.preserve-path": {
|
||||||
|
"defaultMessage": "Yolu Koru"
|
||||||
|
},
|
||||||
|
"host.flags.protocols": {
|
||||||
|
"defaultMessage": "Protokoller"
|
||||||
|
},
|
||||||
|
"host.flags.websockets-upgrade": {
|
||||||
|
"defaultMessage": "Websockets Desteği"
|
||||||
|
},
|
||||||
|
"host.forward-port": {
|
||||||
|
"defaultMessage": "İletme Portu"
|
||||||
|
},
|
||||||
|
"host.forward-scheme": {
|
||||||
|
"defaultMessage": "Şema"
|
||||||
|
},
|
||||||
|
"hosts": {
|
||||||
|
"defaultMessage": "Host'lar"
|
||||||
|
},
|
||||||
|
"http-only": {
|
||||||
|
"defaultMessage": "Sadece HTTP"
|
||||||
|
},
|
||||||
|
"lets-encrypt": {
|
||||||
|
"defaultMessage": "Let's Encrypt"
|
||||||
|
},
|
||||||
|
"lets-encrypt-via-dns": {
|
||||||
|
"defaultMessage": "DNS ile Let's Encrypt"
|
||||||
|
},
|
||||||
|
"lets-encrypt-via-http": {
|
||||||
|
"defaultMessage": "HTTP ile Let's Encrypt"
|
||||||
|
},
|
||||||
|
"loading": {
|
||||||
|
"defaultMessage": "Yükleniyor…"
|
||||||
|
},
|
||||||
|
"login.title": {
|
||||||
|
"defaultMessage": "Hesabınıza giriş yapın"
|
||||||
|
},
|
||||||
|
"nginx-config.label": {
|
||||||
|
"defaultMessage": "Özel Nginx Yapılandırması"
|
||||||
|
},
|
||||||
|
"nginx-config.placeholder": {
|
||||||
|
"defaultMessage": "# Kendi riskinizle özel Nginx yapılandırmanızı buraya girin!"
|
||||||
|
},
|
||||||
|
"no-permission-error": {
|
||||||
|
"defaultMessage": "Bunu görüntüleme erişiminiz yok."
|
||||||
|
},
|
||||||
|
"notfound.action": {
|
||||||
|
"defaultMessage": "Ana sayfaya götür"
|
||||||
|
},
|
||||||
|
"notfound.content": {
|
||||||
|
"defaultMessage": "Üzgünüz, aradığınız sayfa bulunamadı"
|
||||||
|
},
|
||||||
|
"notfound.title": {
|
||||||
|
"defaultMessage": "Hata… Bir hata sayfası buldunuz"
|
||||||
|
},
|
||||||
|
"notification.error": {
|
||||||
|
"defaultMessage": "Hata"
|
||||||
|
},
|
||||||
|
"notification.object-deleted": {
|
||||||
|
"defaultMessage": "{object} silindi"
|
||||||
|
},
|
||||||
|
"notification.object-disabled": {
|
||||||
|
"defaultMessage": "{object} devre dışı bırakıldı"
|
||||||
|
},
|
||||||
|
"notification.object-enabled": {
|
||||||
|
"defaultMessage": "{object} etkinleştirildi"
|
||||||
|
},
|
||||||
|
"notification.object-renewed": {
|
||||||
|
"defaultMessage": "{object} yenilendi"
|
||||||
|
},
|
||||||
|
"notification.object-saved": {
|
||||||
|
"defaultMessage": "{object} kaydedildi"
|
||||||
|
},
|
||||||
|
"notification.success": {
|
||||||
|
"defaultMessage": "Başarılı"
|
||||||
|
},
|
||||||
|
"object.actions-title": {
|
||||||
|
"defaultMessage": "{object} #{id}"
|
||||||
|
},
|
||||||
|
"object.add": {
|
||||||
|
"defaultMessage": "{object} Ekle"
|
||||||
|
},
|
||||||
|
"object.delete": {
|
||||||
|
"defaultMessage": "{object} Sil"
|
||||||
|
},
|
||||||
|
"object.delete.content": {
|
||||||
|
"defaultMessage": "Bu {object} öğesini silmek istediğinizden emin misiniz?"
|
||||||
|
},
|
||||||
|
"object.edit": {
|
||||||
|
"defaultMessage": "{object} Düzenle"
|
||||||
|
},
|
||||||
|
"object.empty": {
|
||||||
|
"defaultMessage": "Hiç {objects} yok"
|
||||||
|
},
|
||||||
|
"object.event.created": {
|
||||||
|
"defaultMessage": "{object} oluşturuldu"
|
||||||
|
},
|
||||||
|
"object.event.deleted": {
|
||||||
|
"defaultMessage": "{object} silindi"
|
||||||
|
},
|
||||||
|
"object.event.disabled": {
|
||||||
|
"defaultMessage": "{object} devre dışı bırakıldı"
|
||||||
|
},
|
||||||
|
"object.event.enabled": {
|
||||||
|
"defaultMessage": "{object} etkinleştirildi"
|
||||||
|
},
|
||||||
|
"object.event.renewed": {
|
||||||
|
"defaultMessage": "{object} yenilendi"
|
||||||
|
},
|
||||||
|
"object.event.updated": {
|
||||||
|
"defaultMessage": "{object} güncellendi"
|
||||||
|
},
|
||||||
|
"offline": {
|
||||||
|
"defaultMessage": "Çevrimdışı"
|
||||||
|
},
|
||||||
|
"online": {
|
||||||
|
"defaultMessage": "Çevrimiçi"
|
||||||
|
},
|
||||||
|
"options": {
|
||||||
|
"defaultMessage": "Seçenekler"
|
||||||
|
},
|
||||||
|
"password": {
|
||||||
|
"defaultMessage": "Şifre"
|
||||||
|
},
|
||||||
|
"password.generate": {
|
||||||
|
"defaultMessage": "Rastgele şifre oluştur"
|
||||||
|
},
|
||||||
|
"password.hide": {
|
||||||
|
"defaultMessage": "Şifreyi Gizle"
|
||||||
|
},
|
||||||
|
"password.show": {
|
||||||
|
"defaultMessage": "Şifreyi Göster"
|
||||||
|
},
|
||||||
|
"permissions.hidden": {
|
||||||
|
"defaultMessage": "Gizli"
|
||||||
|
},
|
||||||
|
"permissions.manage": {
|
||||||
|
"defaultMessage": "Yönet"
|
||||||
|
},
|
||||||
|
"permissions.view": {
|
||||||
|
"defaultMessage": "Sadece Görüntüle"
|
||||||
|
},
|
||||||
|
"permissions.visibility.all": {
|
||||||
|
"defaultMessage": "Tüm Öğeler"
|
||||||
|
},
|
||||||
|
"permissions.visibility.title": {
|
||||||
|
"defaultMessage": "Öğe Görünürlüğü"
|
||||||
|
},
|
||||||
|
"permissions.visibility.user": {
|
||||||
|
"defaultMessage": "Sadece Oluşturulan Öğeler"
|
||||||
|
},
|
||||||
|
"proxy-host": {
|
||||||
|
"defaultMessage": "Proxy Host"
|
||||||
|
},
|
||||||
|
"proxy-host.forward-host": {
|
||||||
|
"defaultMessage": "İletme Host Adı / IP"
|
||||||
|
},
|
||||||
|
"proxy-hosts": {
|
||||||
|
"defaultMessage": "Proxy Host'lar"
|
||||||
|
},
|
||||||
|
"proxy-hosts.count": {
|
||||||
|
"defaultMessage": "{count} {count, plural, one {Proxy Host} other {Proxy Host}}"
|
||||||
|
},
|
||||||
|
"public": {
|
||||||
|
"defaultMessage": "Herkese Açık"
|
||||||
|
},
|
||||||
|
"redirection-host": {
|
||||||
|
"defaultMessage": "Yönlendirme Host'u"
|
||||||
|
},
|
||||||
|
"redirection-host.forward-domain": {
|
||||||
|
"defaultMessage": "İletme Alan Adı"
|
||||||
|
},
|
||||||
|
"redirection-host.forward-http-code": {
|
||||||
|
"defaultMessage": "HTTP Kodu"
|
||||||
|
},
|
||||||
|
"redirection-hosts": {
|
||||||
|
"defaultMessage": "Yönlendirme Host'ları"
|
||||||
|
},
|
||||||
|
"redirection-hosts.count": {
|
||||||
|
"defaultMessage": "{count} {count, plural, one {Yönlendirme Host'u} other {Yönlendirme Host'u}}"
|
||||||
|
},
|
||||||
|
"redirection-hosts.http-code.300": {
|
||||||
|
"defaultMessage": "300 Çoklu Seçenek"
|
||||||
|
},
|
||||||
|
"redirection-hosts.http-code.301": {
|
||||||
|
"defaultMessage": "301 Kalıcı olarak taşındı"
|
||||||
|
},
|
||||||
|
"redirection-hosts.http-code.302": {
|
||||||
|
"defaultMessage": "302 Geçici olarak taşındı"
|
||||||
|
},
|
||||||
|
"redirection-hosts.http-code.303": {
|
||||||
|
"defaultMessage": "303 Diğerini gör"
|
||||||
|
},
|
||||||
|
"redirection-hosts.http-code.307": {
|
||||||
|
"defaultMessage": "307 Geçici yönlendirme"
|
||||||
|
},
|
||||||
|
"redirection-hosts.http-code.308": {
|
||||||
|
"defaultMessage": "308 Kalıcı yönlendirme"
|
||||||
|
},
|
||||||
|
"role.admin": {
|
||||||
|
"defaultMessage": "Yönetici"
|
||||||
|
},
|
||||||
|
"role.standard-user": {
|
||||||
|
"defaultMessage": "Standart Kullanıcı"
|
||||||
|
},
|
||||||
|
"save": {
|
||||||
|
"defaultMessage": "Kaydet"
|
||||||
|
},
|
||||||
|
"setting": {
|
||||||
|
"defaultMessage": "Ayar"
|
||||||
|
},
|
||||||
|
"settings": {
|
||||||
|
"defaultMessage": "Ayarlar"
|
||||||
|
},
|
||||||
|
"settings.default-site": {
|
||||||
|
"defaultMessage": "Varsayılan Site"
|
||||||
|
},
|
||||||
|
"settings.default-site.404": {
|
||||||
|
"defaultMessage": "404 Sayfası"
|
||||||
|
},
|
||||||
|
"settings.default-site.444": {
|
||||||
|
"defaultMessage": "Yanıt Yok (444)"
|
||||||
|
},
|
||||||
|
"settings.default-site.congratulations": {
|
||||||
|
"defaultMessage": "Tebrikler Sayfası"
|
||||||
|
},
|
||||||
|
"settings.default-site.description": {
|
||||||
|
"defaultMessage": "Nginx bilinmeyen bir Host ile karşılaştığında ne gösterilecek"
|
||||||
|
},
|
||||||
|
"settings.default-site.html": {
|
||||||
|
"defaultMessage": "Özel HTML"
|
||||||
|
},
|
||||||
|
"settings.default-site.html.placeholder": {
|
||||||
|
"defaultMessage": "<!-- Özel HTML içeriğinizi buraya girin -->"
|
||||||
|
},
|
||||||
|
"settings.default-site.redirect": {
|
||||||
|
"defaultMessage": "Yönlendir"
|
||||||
|
},
|
||||||
|
"setup.preamble": {
|
||||||
|
"defaultMessage": "Yönetici hesabınızı oluşturarak başlayın."
|
||||||
|
},
|
||||||
|
"setup.title": {
|
||||||
|
"defaultMessage": "Hoş Geldiniz!"
|
||||||
|
},
|
||||||
|
"sign-in": {
|
||||||
|
"defaultMessage": "Giriş yap"
|
||||||
|
},
|
||||||
|
"ssl-certificate": {
|
||||||
|
"defaultMessage": "SSL Sertifikası"
|
||||||
|
},
|
||||||
|
"stream": {
|
||||||
|
"defaultMessage": "Akış"
|
||||||
|
},
|
||||||
|
"stream.forward-host": {
|
||||||
|
"defaultMessage": "İletme Host'u"
|
||||||
|
},
|
||||||
|
"stream.forward-host.placeholder": {
|
||||||
|
"defaultMessage": "example.com veya 10.0.0.1 veya 2001:db8:3333:4444:5555:6666:7777:8888"
|
||||||
|
},
|
||||||
|
"stream.incoming-port": {
|
||||||
|
"defaultMessage": "Gelen Port"
|
||||||
|
},
|
||||||
|
"streams": {
|
||||||
|
"defaultMessage": "Akışlar"
|
||||||
|
},
|
||||||
|
"streams.count": {
|
||||||
|
"defaultMessage": "{count} {count, plural, one {Akış} other {Akış}}"
|
||||||
|
},
|
||||||
|
"streams.tcp": {
|
||||||
|
"defaultMessage": "TCP"
|
||||||
|
},
|
||||||
|
"streams.udp": {
|
||||||
|
"defaultMessage": "UDP"
|
||||||
|
},
|
||||||
|
"test": {
|
||||||
|
"defaultMessage": "Test"
|
||||||
|
},
|
||||||
|
"update-available": {
|
||||||
|
"defaultMessage": "Güncelleme Mevcut: {latestVersion}"
|
||||||
|
},
|
||||||
|
"user": {
|
||||||
|
"defaultMessage": "Kullanıcı"
|
||||||
|
},
|
||||||
|
"user.change-password": {
|
||||||
|
"defaultMessage": "Şifreyi Değiştir"
|
||||||
|
},
|
||||||
|
"user.confirm-password": {
|
||||||
|
"defaultMessage": "Şifreyi Onayla"
|
||||||
|
},
|
||||||
|
"user.current-password": {
|
||||||
|
"defaultMessage": "Mevcut Şifre"
|
||||||
|
},
|
||||||
|
"user.edit-profile": {
|
||||||
|
"defaultMessage": "Profili Düzenle"
|
||||||
|
},
|
||||||
|
"user.full-name": {
|
||||||
|
"defaultMessage": "Ad Soyad"
|
||||||
|
},
|
||||||
|
"user.login-as": {
|
||||||
|
"defaultMessage": "{name} olarak giriş yap"
|
||||||
|
},
|
||||||
|
"user.logout": {
|
||||||
|
"defaultMessage": "Çıkış Yap"
|
||||||
|
},
|
||||||
|
"user.new-password": {
|
||||||
|
"defaultMessage": "Yeni Şifre"
|
||||||
|
},
|
||||||
|
"user.nickname": {
|
||||||
|
"defaultMessage": "Takma Ad"
|
||||||
|
},
|
||||||
|
"user.set-password": {
|
||||||
|
"defaultMessage": "Şifre Belirle"
|
||||||
|
},
|
||||||
|
"user.set-permissions": {
|
||||||
|
"defaultMessage": "{name} için İzinleri Belirle"
|
||||||
|
},
|
||||||
|
"user.switch-dark": {
|
||||||
|
"defaultMessage": "Karanlık moda geç"
|
||||||
|
},
|
||||||
|
"user.switch-light": {
|
||||||
|
"defaultMessage": "Açık moda geç"
|
||||||
|
},
|
||||||
|
"username": {
|
||||||
|
"defaultMessage": "Kullanıcı Adı"
|
||||||
|
},
|
||||||
|
"users": {
|
||||||
|
"defaultMessage": "Kullanıcılar"
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user