Compare commits
44 Commits
v15.3.0-beta.1
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| 8c70c24205 | |||
| c70ad1d08b | |||
| d0566a1df9 | |||
| bc95a2851f | |||
| e03d743307 | |||
| 99357848e5 | |||
| c41ae0d4c5 | |||
| 66f8bde206 | |||
| b3afb9ac1b | |||
| 9581e6eacb | |||
| 90e2bbe0a6 | |||
| 7b5ba95938 | |||
| da90d67cc0 | |||
| a52da67b38 | |||
| e513090074 | |||
| 2dc8ba7792 | |||
| 4e8cccb4c7 | |||
| e57b0977d3 | |||
| b8be53c3f7 | |||
| 0794413191 | |||
| 261b0d6b8f | |||
| f656d57d20 | |||
| 46074fea1c | |||
| 05c655ede9 | |||
| ebcc42cc49 | |||
| be8d24e492 | |||
| 9682dedea7 | |||
| 5eb80fe3c1 | |||
| dd9da2a067 | |||
| 15111ecd62 | |||
| e9f4b4650b | |||
| e3e4049f8e | |||
| 3fb9adbf6f | |||
| cd9db1563d | |||
| b5c30f5dbe | |||
| 1eb9527175 | |||
| cd890c1f0f | |||
| 2a78b30aeb | |||
| 9a843087c3 | |||
| 483b63bba6 | |||
| 13942c97b2 | |||
| 82c64e506e | |||
| 9b3d919168 | |||
| 3eaf0d01dc |
@@ -5,13 +5,3 @@ updates:
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
rebase-strategy: "auto"
|
||||
- package-ecosystem: "npm"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
rebase-strategy: "auto"
|
||||
- package-ecosystem: "npm"
|
||||
directory: "/src/"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
rebase-strategy: "auto"
|
||||
|
||||
@@ -16,7 +16,7 @@ jobs:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- uses: pnpm/action-setup@v4
|
||||
- uses: pnpm/action-setup@v6
|
||||
name: Install pnpm
|
||||
with:
|
||||
run_install: false
|
||||
@@ -49,7 +49,7 @@ jobs:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- uses: pnpm/action-setup@v4
|
||||
- uses: pnpm/action-setup@v6
|
||||
name: Install pnpm
|
||||
with:
|
||||
run_install: false
|
||||
|
||||
@@ -14,10 +14,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
- CLI: Show QR code (https://github.com/wg-easy/wg-easy/pull/2518)
|
||||
- Copy QR code to clipboard / save as png (https://github.com/wg-easy/wg-easy/pull/2521)
|
||||
|
||||
### Fixed
|
||||
|
||||
- Add trailing newline to Prometheus metrics output (https://github.com/wg-easy/wg-easy/pull/2573)
|
||||
- Correctly use DEBUG env var (https://github.com/wg-easy/wg-easy/pull/2619)
|
||||
|
||||
### Changed
|
||||
|
||||
- Hooks are now Textareas (https://github.com/wg-easy/wg-easy/pull/2522)
|
||||
- Update to Node Krypton (24) (https://github.com/wg-easy/wg-easy/pull/2536)
|
||||
- Mobile UI (https://github.com/wg-easy/wg-easy/pull/2569)
|
||||
- Prevent enabling client when expired (https://github.com/wg-easy/wg-easy/pull/2594)
|
||||
|
||||
## [15.2.2] - 2026-02-06
|
||||
|
||||
|
||||
+12
-7
@@ -7,7 +7,7 @@ RUN npm install --global corepack@latest
|
||||
RUN corepack enable pnpm
|
||||
|
||||
# Copy Web UI
|
||||
COPY src/package.json src/pnpm-lock.yaml ./
|
||||
COPY src/package.json src/pnpm-lock.yaml src/pnpm-workspace.yaml ./
|
||||
RUN pnpm install
|
||||
|
||||
# Build UI
|
||||
@@ -21,7 +21,12 @@ RUN apk add linux-headers build-base go git && \
|
||||
cd amneziawg-go && \
|
||||
make && \
|
||||
cd ../amneziawg-tools/src && \
|
||||
make
|
||||
make && \
|
||||
sed -i 's|\[\[ $proto == -4 \]\] && cmd sysctl -q net\.ipv4\.conf\.all\.src_valid_mark=1|[[ $proto == -4 ]] \&\& [[ $(sysctl -n net.ipv4.conf.all.src_valid_mark) != 1 ]] \&\& cmd sysctl -q net.ipv4.conf.all.src_valid_mark=1|' ./wg-quick/linux.bash
|
||||
|
||||
FROM docker.io/library/node:krypton-alpine AS build-libsql
|
||||
WORKDIR /app
|
||||
RUN npm install --no-save --omit=dev libsql
|
||||
|
||||
# Copy build result to a new image.
|
||||
# This saves a lot of disk space.
|
||||
@@ -35,9 +40,8 @@ COPY --from=build /app/.output /app
|
||||
# Copy migrations
|
||||
COPY --from=build /app/server/database/migrations /app/server/database/migrations
|
||||
# libsql (https://github.com/nitrojs/nitro/issues/3328)
|
||||
RUN cd /app/server && \
|
||||
npm install --no-save --omit=dev libsql && \
|
||||
npm cache clean --force
|
||||
COPY --from=build-libsql /app/node_modules /app/server/node_modules
|
||||
|
||||
# cli
|
||||
COPY --from=build /app/cli/cli.sh /usr/local/bin/cli
|
||||
RUN chmod +x /usr/local/bin/cli
|
||||
@@ -59,7 +63,8 @@ RUN apk add --no-cache \
|
||||
kmod \
|
||||
iptables-legacy \
|
||||
wireguard-go \
|
||||
wireguard-tools
|
||||
wireguard-tools && \
|
||||
sed -i 's|\[\[ $proto == -4 \]\] && cmd sysctl -q net\.ipv4\.conf\.all\.src_valid_mark=1|[[ $proto == -4 ]] \&\& [[ $(sysctl -n net.ipv4.conf.all.src_valid_mark) != 1 ]] \&\& cmd sysctl -q net.ipv4.conf.all.src_valid_mark=1|' /usr/bin/wg-quick
|
||||
|
||||
RUN mkdir -p /etc/amnezia
|
||||
RUN ln -s /etc/wireguard /etc/amnezia/amneziawg
|
||||
@@ -69,7 +74,7 @@ RUN update-alternatives --install /usr/sbin/iptables iptables /usr/sbin/iptables
|
||||
RUN update-alternatives --install /usr/sbin/ip6tables ip6tables /usr/sbin/ip6tables-legacy 10 --slave /usr/sbin/ip6tables-restore ip6tables-restore /usr/sbin/ip6tables-legacy-restore --slave /usr/sbin/ip6tables-save ip6tables-save /usr/sbin/ip6tables-legacy-save
|
||||
|
||||
# Set Environment
|
||||
ENV DEBUG=Server,WireGuard,Database,CMD
|
||||
ENV DEBUG=Server,WireGuard,Database,CMD,Firewall
|
||||
ENV PORT=51821
|
||||
ENV HOST=0.0.0.0
|
||||
ENV INSECURE=false
|
||||
|
||||
+2
-2
@@ -24,7 +24,7 @@ RUN update-alternatives --install /usr/sbin/iptables iptables /usr/sbin/iptables
|
||||
RUN update-alternatives --install /usr/sbin/ip6tables ip6tables /usr/sbin/ip6tables-legacy 10 --slave /usr/sbin/ip6tables-restore ip6tables-restore /usr/sbin/ip6tables-legacy-restore --slave /usr/sbin/ip6tables-save ip6tables-save /usr/sbin/ip6tables-legacy-save
|
||||
|
||||
# Set Environment
|
||||
ENV DEBUG=Server,WireGuard,Database,CMD
|
||||
ENV DEBUG=Server,WireGuard,Database,CMD,Firewall
|
||||
ENV PORT=51821
|
||||
ENV HOST=0.0.0.0
|
||||
ENV INSECURE=true
|
||||
@@ -32,7 +32,7 @@ ENV INIT_ENABLED=false
|
||||
ENV DISABLE_IPV6=false
|
||||
|
||||
# Install Dependencies
|
||||
COPY src/package.json src/pnpm-lock.yaml ./
|
||||
COPY src/package.json src/pnpm-lock.yaml src/pnpm-workspace.yaml ./
|
||||
RUN pnpm install
|
||||
|
||||
# Copy Project
|
||||
|
||||
@@ -1,16 +1,14 @@
|
||||
# WireGuard Easy
|
||||
|
||||
[](https://github.com/wg-easy/wg-easy/actions/workflows/deploy.yml)
|
||||
[](https://github.com/wg-easy/wg-easy/actions/workflows/deploy.yml)
|
||||
[](https://github.com/wg-easy/wg-easy/actions/workflows/lint.yml)
|
||||
[](https://github.com/wg-easy/wg-easy/stargazers)
|
||||
[](LICENSE)
|
||||
[](https://github.com/wg-easy/wg-easy/releases/latest)
|
||||
[](https://github.com/wg-easy/wg-easy/pkgs/container/wg-easy)
|
||||
[](https://github.com/wg-easy/wg-easy/pkgs/container/wg-easy)
|
||||
|
||||
You have found the easiest way to install & manage WireGuard on any Linux host!
|
||||
|
||||
<!-- TOOD: update screenshot -->
|
||||
|
||||
<p align="center">
|
||||
<img src="./assets/screenshot.png" width="802" alt="wg-easy Screenshot" />
|
||||
</p>
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 13 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 33 KiB |
@@ -0,0 +1,63 @@
|
||||
{
|
||||
"fill" : {
|
||||
"automatic-gradient" : "display-p3:0.48853,0.13220,0.12335,1.00000"
|
||||
},
|
||||
"groups" : [
|
||||
{
|
||||
"layers" : [
|
||||
{
|
||||
"fill" : {
|
||||
"automatic-gradient" : "srgb:1.00000,1.00000,1.00000,1.00000"
|
||||
},
|
||||
"image-name" : "wireguard-logo.png",
|
||||
"name" : "wireguard-logo",
|
||||
"position" : {
|
||||
"scale" : 0.5,
|
||||
"translation-in-points" : [
|
||||
255.828125,
|
||||
-225.5
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"fill-specializations" : [
|
||||
{
|
||||
"value" : {
|
||||
"automatic-gradient" : "srgb:1.00000,1.00000,1.00000,1.00000"
|
||||
}
|
||||
},
|
||||
{
|
||||
"appearance" : "dark",
|
||||
"value" : {
|
||||
"automatic-gradient" : "display-p3:0.48853,0.13220,0.12335,1.00000"
|
||||
}
|
||||
}
|
||||
],
|
||||
"image-name" : "ticket.png",
|
||||
"name" : "ticket",
|
||||
"position" : {
|
||||
"scale" : 1.2,
|
||||
"translation-in-points" : [
|
||||
-119.91562499999998,
|
||||
165.65625
|
||||
]
|
||||
}
|
||||
}
|
||||
],
|
||||
"shadow" : {
|
||||
"kind" : "neutral",
|
||||
"opacity" : 0.5
|
||||
},
|
||||
"translucency" : {
|
||||
"enabled" : true,
|
||||
"value" : 0.5
|
||||
}
|
||||
}
|
||||
],
|
||||
"supported-platforms" : {
|
||||
"circles" : [
|
||||
"watchOS"
|
||||
],
|
||||
"squares" : "shared"
|
||||
}
|
||||
}
|
||||
@@ -4,12 +4,13 @@ title: Optional Configuration
|
||||
|
||||
You can set these environment variables to configure the container. They are not required, but can be useful in some cases.
|
||||
|
||||
| Env | Default | Example | Description |
|
||||
| -------------- | --------- | ----------- | ---------------------------------- |
|
||||
| `PORT` | `51821` | `6789` | TCP port for Web UI. |
|
||||
| `HOST` | `0.0.0.0` | `localhost` | IP address web UI binds to. |
|
||||
| `INSECURE` | `false` | `true` | If access over http is allowed |
|
||||
| `DISABLE_IPV6` | `false` | `true` | If IPv6 support should be disabled |
|
||||
| Env | Default | Example | Description |
|
||||
| ----------------------- | --------- | ----------- | --------------------------------------- |
|
||||
| `PORT` | `51821` | `6789` | TCP port for Web UI. |
|
||||
| `HOST` | `0.0.0.0` | `localhost` | IP address web UI binds to. |
|
||||
| `INSECURE` | `false` | `true` | If access over http is allowed |
|
||||
| `DISABLE_IPV6` | `false` | `true` | If IPv6 support should be disabled |
|
||||
| `DISABLE_VERSION_CHECK` | `false` | `true` | If wg-easy should check for new updates |
|
||||
|
||||
/// note | IPv6 Caveats
|
||||
|
||||
|
||||
@@ -109,3 +109,31 @@ To resolve this issue, you can try the following steps:
|
||||
```shell
|
||||
echo "ip6table_filter" | sudo tee -a /etc/modules
|
||||
```
|
||||
|
||||
## Clients lose connectivity after restarting the container when using multiple networks?
|
||||
|
||||
When you attach multiple Docker networks (e.g., `wg` and a reverse proxy network like `traefik` or `nginx`) to the `wg-easy` container, Docker might assign the network interfaces randomly (e.g., swapping `eth0` and `eth1`). Since `wg-easy` expects the wireguard interface to act as `eth0` and configures `POSTROUTING` rules for it, connectivity will break if the interfaces are swapped upon container restart.
|
||||
|
||||
To solve this, specify the `interface_name` and `gw_priority` explicitly in your `docker-compose.yml` file to guarantee that the `wg` network always binds to `eth0` and acts as the default gateway.
|
||||
|
||||
**Example `docker-compose.yml`:**
|
||||
|
||||
```yaml
|
||||
services:
|
||||
wg-easy:
|
||||
# ... other configuration ...
|
||||
networks:
|
||||
wg:
|
||||
interface_name: eth0
|
||||
gw_priority: 1
|
||||
ipv4_address: 10.42.42.42
|
||||
nginx:
|
||||
interface_name: eth1
|
||||
gw_priority: 0
|
||||
|
||||
networks:
|
||||
wg:
|
||||
# ... wg network config ...
|
||||
nginx:
|
||||
external: true
|
||||
```
|
||||
|
||||
+2
-2
@@ -11,7 +11,7 @@
|
||||
"format:check:docs": "prettier --check docs"
|
||||
},
|
||||
"devDependencies": {
|
||||
"prettier": "^3.8.1"
|
||||
"prettier": "^3.8.3"
|
||||
},
|
||||
"packageManager": "pnpm@10.31.0"
|
||||
"packageManager": "pnpm@11.5.0"
|
||||
}
|
||||
|
||||
Generated
+5
-5
@@ -9,16 +9,16 @@ importers:
|
||||
.:
|
||||
devDependencies:
|
||||
prettier:
|
||||
specifier: ^3.8.1
|
||||
version: 3.8.1
|
||||
specifier: ^3.8.3
|
||||
version: 3.8.3
|
||||
|
||||
packages:
|
||||
|
||||
prettier@3.8.1:
|
||||
resolution: {integrity: sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg==}
|
||||
prettier@3.8.3:
|
||||
resolution: {integrity: sha512-7igPTM53cGHMW8xWuVTydi2KO233VFiTNyF5hLJqpilHfmn8C8gPf+PS7dUT64YcXFbiMGZxS9pCSxL/Dxm/Jw==}
|
||||
engines: {node: '>=14'}
|
||||
hasBin: true
|
||||
|
||||
snapshots:
|
||||
|
||||
prettier@3.8.1: {}
|
||||
prettier@3.8.3: {}
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
setups.@nuxt/test-utils="4.0.0"
|
||||
setups.@nuxt/test-utils="4.0.3"
|
||||
@@ -18,7 +18,7 @@
|
||||
>
|
||||
<slot name="description" />
|
||||
</DialogDescription>
|
||||
<div class="mt-6 flex justify-end gap-2">
|
||||
<div class="mt-6 flex flex-wrap justify-end gap-2">
|
||||
<slot name="actions" />
|
||||
</div>
|
||||
</DialogContent>
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import type { ApexOptions } from 'apexcharts';
|
||||
import type { ApexChart, ApexOptions } from 'apexcharts';
|
||||
|
||||
defineProps<{
|
||||
client: LocalClient;
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
<div class="flex flex-grow flex-col gap-1">
|
||||
<ClientCardName :client="client" />
|
||||
<div
|
||||
class="flex flex-col pb-1 text-xs text-gray-500 md:inline-block md:pb-0 dark:text-neutral-400"
|
||||
class="flex flex-col text-xs text-gray-500 dark:text-neutral-400"
|
||||
>
|
||||
<div>
|
||||
<ClientCardAddress :client="client" />
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
<template>
|
||||
<div
|
||||
class="block pb-1 text-xs text-gray-500 md:inline-block md:pb-0 dark:text-neutral-400"
|
||||
>
|
||||
<div class="block text-xs text-gray-500 dark:text-neutral-400">
|
||||
<span class="inline-block">{{ expiredDateFormat(client.expiresAt) }}</span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -1,11 +1,9 @@
|
||||
<template>
|
||||
<div
|
||||
class="text-sm text-gray-700 md:text-base dark:text-neutral-200"
|
||||
class="break-all text-sm text-gray-700 md:text-base dark:text-neutral-200"
|
||||
:title="$t('client.createdOn') + $d(new Date(client.createdAt))"
|
||||
>
|
||||
<span class="border-b-2 border-t-2 border-transparent">
|
||||
{{ client.name }}
|
||||
</span>
|
||||
{{ client.name }}
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -14,10 +14,11 @@ const props = defineProps<{ client: LocalClient }>();
|
||||
const clientsStore = useClientsStore();
|
||||
|
||||
const _showOneTimeLink = useSubmit(
|
||||
`/api/client/${props.client.id}/generateOneTimeLink`,
|
||||
{
|
||||
method: 'post',
|
||||
},
|
||||
(data) =>
|
||||
$fetch(`/api/client/${props.client.id}/generateOneTimeLink`, {
|
||||
method: 'post',
|
||||
body: data,
|
||||
}),
|
||||
{
|
||||
revert: async () => {
|
||||
await clientsStore.refresh();
|
||||
|
||||
@@ -18,10 +18,11 @@ const enabled = ref(props.client.enabled);
|
||||
const clientsStore = useClientsStore();
|
||||
|
||||
const _disableClient = useSubmit(
|
||||
`/api/client/${props.client.id}/disable`,
|
||||
{
|
||||
method: 'post',
|
||||
},
|
||||
(data) =>
|
||||
$fetch(`/api/client/${props.client.id}/disable`, {
|
||||
method: 'post',
|
||||
body: data,
|
||||
}),
|
||||
{
|
||||
revert: async () => {
|
||||
await clientsStore.refresh();
|
||||
@@ -31,10 +32,11 @@ const _disableClient = useSubmit(
|
||||
);
|
||||
|
||||
const _enableClient = useSubmit(
|
||||
`/api/client/${props.client.id}/enable`,
|
||||
{
|
||||
method: 'post',
|
||||
},
|
||||
(data) =>
|
||||
$fetch(`/api/client/${props.client.id}/enable`, {
|
||||
method: 'post',
|
||||
body: data,
|
||||
}),
|
||||
{
|
||||
revert: async () => {
|
||||
await clientsStore.refresh();
|
||||
|
||||
@@ -43,10 +43,11 @@ function createClient() {
|
||||
}
|
||||
|
||||
const _createClient = useSubmit(
|
||||
'/api/client',
|
||||
{
|
||||
method: 'post',
|
||||
},
|
||||
(data) =>
|
||||
$fetch('/api/client', {
|
||||
method: 'post',
|
||||
body: data,
|
||||
}),
|
||||
{
|
||||
revert: () => clientsStore.refresh(),
|
||||
successMsg: t('client.created'),
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
{{ $t('client.empty') }}<br /><br />
|
||||
<ClientsCreateDialog>
|
||||
<BaseSecondaryButton as="span">
|
||||
<IconsPlus class="w-4 md:mr-2" />
|
||||
<IconsPlus class="mr-2 w-4" />
|
||||
<span class="text-sm">{{ $t('client.new') }}</span>
|
||||
</BaseSecondaryButton>
|
||||
</ClientsCreateDialog>
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
<template>
|
||||
<ClientsCreateDialog>
|
||||
<BaseSecondaryButton as="span">
|
||||
<IconsPlus class="w-4 md:mr-2" />
|
||||
<span class="text-sm max-md:hidden">{{ $t('client.newShort') }}</span>
|
||||
<IconsPlus class="mr-2 w-4" />
|
||||
<span class="text-sm">{{ $t('client.newShort') }}</span>
|
||||
</BaseSecondaryButton>
|
||||
</ClientsCreateDialog>
|
||||
</template>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="relative w-60 md:mr-2">
|
||||
<div class="relative">
|
||||
<div class="relative flex h-full items-center">
|
||||
<IconsMagnifyingGlass
|
||||
class="absolute left-2.5 h-4 w-4 text-gray-400 dark:text-neutral-500"
|
||||
|
||||
@@ -1,11 +1,8 @@
|
||||
<template>
|
||||
<BasePrimaryButton @click="toggleSort">
|
||||
<IconsArrowDown
|
||||
v-if="globalStore.sortClient === true"
|
||||
class="w-4 md:mr-2"
|
||||
/>
|
||||
<IconsArrowUp v-else class="w-4 md:mr-2" />
|
||||
<span class="text-sm max-md:hidden"> {{ $t('client.sort') }}</span>
|
||||
<IconsArrowDown v-if="globalStore.sortClient === true" class="mr-2 w-4" />
|
||||
<IconsArrowUp v-else class="mr-2 w-4" />
|
||||
<span class="text-sm">{{ $t('client.sort') }}</span>
|
||||
</BasePrimaryButton>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -12,23 +12,15 @@
|
||||
class="rounded-lg border-2 border-gray-100 text-gray-500 focus:border-red-800 focus:outline-0 focus:ring-0 dark:border-neutral-800 dark:bg-neutral-700 dark:text-neutral-200 dark:placeholder:text-neutral-400"
|
||||
@input="update($event, i)"
|
||||
/>
|
||||
<BaseSecondaryButton
|
||||
as="input"
|
||||
type="button"
|
||||
class="rounded-lg"
|
||||
value="-"
|
||||
@click="del(i)"
|
||||
/>
|
||||
<BaseSecondaryButton type="button" class="rounded-lg" @click="del(i)">
|
||||
{{ '-' }}
|
||||
</BaseSecondaryButton>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-2">
|
||||
<BasePrimaryButton
|
||||
as="input"
|
||||
type="button"
|
||||
class="rounded-lg"
|
||||
:value="$t('form.add')"
|
||||
@click="add"
|
||||
/>
|
||||
<BasePrimaryButton type="button" class="rounded-lg" @click="add">
|
||||
{{ $t('form.add') }}
|
||||
</BasePrimaryButton>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
<template>
|
||||
<h4 class="col-span-full flex items-center py-6 text-2xl">
|
||||
<h3 class="col-span-full flex items-center py-6 text-2xl">
|
||||
<slot />
|
||||
<BaseTooltip v-if="description" :text="description">
|
||||
<IconsInfo class="size-4" />
|
||||
</BaseTooltip>
|
||||
</h4>
|
||||
</h3>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<RLabel :for="props.for" class="md:align-middle md:leading-10"
|
||||
><slot
|
||||
/></RLabel>
|
||||
<RLabel :for="props.for" class="md:leading-[2.75rem]">
|
||||
<slot />
|
||||
</RLabel>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
|
||||
@@ -12,23 +12,15 @@
|
||||
class="rounded-lg border-2 border-gray-100 text-gray-500 focus:border-red-800 focus:outline-0 focus:ring-0 dark:border-neutral-800 dark:bg-neutral-700 dark:text-neutral-200 dark:placeholder:text-neutral-400"
|
||||
@input="update($event, i)"
|
||||
/>
|
||||
<BaseSecondaryButton
|
||||
as="input"
|
||||
type="button"
|
||||
class="rounded-lg"
|
||||
value="-"
|
||||
@click="del(i)"
|
||||
/>
|
||||
<BaseSecondaryButton type="button" class="rounded-lg" @click="del(i)">
|
||||
{{ '-' }}
|
||||
</BaseSecondaryButton>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mt-2">
|
||||
<BasePrimaryButton
|
||||
as="input"
|
||||
type="button"
|
||||
class="rounded-lg"
|
||||
:value="$t('form.add')"
|
||||
@click="add"
|
||||
/>
|
||||
<BasePrimaryButton type="button" class="rounded-lg" @click="add">
|
||||
{{ $t('form.add') }}
|
||||
</BasePrimaryButton>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -7,7 +7,9 @@
|
||||
<IconsInfo class="size-4" />
|
||||
</BaseTooltip>
|
||||
</div>
|
||||
<BaseSwitch :id="id" v-model="data" />
|
||||
<div class="my-auto">
|
||||
<BaseSwitch :id="id" v-model="data" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts" setup>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<NuxtLink to="/" class="mb-4">
|
||||
<NuxtLink to="/" class="max-sm:mb-4">
|
||||
<h1 class="text-4xl font-medium dark:text-neutral-200">
|
||||
<img
|
||||
src="/logo.png"
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
authStore.userData &&
|
||||
hasPermissions(authStore.userData, 'admin', 'any')
|
||||
"
|
||||
class="font-small mb-10 rounded-md bg-red-800 p-4 text-sm text-white shadow-lg dark:bg-red-100 dark:text-red-600"
|
||||
class="font-small rounded-md bg-red-800 p-4 text-sm text-white shadow-lg dark:bg-red-100 dark:text-red-600"
|
||||
:title="`v${globalStore.information.currentRelease} → v${globalStore.information.latestRelease.version}`"
|
||||
>
|
||||
<div class="container mx-auto flex flex-auto flex-row items-center">
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
<template>
|
||||
<div
|
||||
class="container mx-auto max-w-3xl overflow-hidden rounded-lg bg-white px-3 text-gray-700 shadow-md md:px-0 dark:bg-neutral-700 dark:text-neutral-200"
|
||||
>
|
||||
<slot />
|
||||
<div class="container mx-auto max-w-3xl">
|
||||
<div
|
||||
class="mx-3 overflow-hidden rounded-lg bg-white text-gray-700 shadow-md dark:bg-neutral-700 dark:text-neutral-200"
|
||||
>
|
||||
<slot />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="flex flex-shrink-0 items-center space-x-2">
|
||||
<div class="flex flex-shrink-0 flex-col items-center gap-2 sm:flex-row">
|
||||
<slot />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div
|
||||
class="flex flex-auto flex-grow flex-row items-center border-b-2 border-gray-100 p-3 px-5 dark:border-neutral-600"
|
||||
class="flex flex-col items-center gap-2 border-b-2 border-gray-100 p-3 px-5 sm:flex-row dark:border-neutral-600"
|
||||
>
|
||||
<slot />
|
||||
</div>
|
||||
|
||||
@@ -1,11 +1,5 @@
|
||||
<template>
|
||||
<h2 class="flex-1 text-2xl font-medium">
|
||||
{{ text }}
|
||||
<h2 class="flex-1 break-all text-2xl font-medium">
|
||||
<slot />
|
||||
</h2>
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
const { text } = defineProps<{
|
||||
text: string;
|
||||
}>();
|
||||
</script>
|
||||
|
||||
@@ -70,10 +70,11 @@ const authStore = useAuthStore();
|
||||
const toggleState = ref(false);
|
||||
|
||||
const _submit = useSubmit(
|
||||
'/api/session',
|
||||
{
|
||||
method: 'delete',
|
||||
},
|
||||
(data) =>
|
||||
$fetch('/api/session', {
|
||||
method: 'delete',
|
||||
body: data,
|
||||
}),
|
||||
{
|
||||
revert: async () => {
|
||||
await navigateTo('/login');
|
||||
|
||||
@@ -1,49 +1,24 @@
|
||||
import type {
|
||||
NitroFetchRequest,
|
||||
NitroFetchOptions,
|
||||
TypedInternalResponse,
|
||||
ExtractedRouteMethod,
|
||||
} from 'nitropack/types';
|
||||
import { FetchError } from 'ofetch';
|
||||
|
||||
type RevertFn<
|
||||
R extends NitroFetchRequest,
|
||||
T = unknown,
|
||||
O extends NitroFetchOptions<R> = NitroFetchOptions<R>,
|
||||
> = (
|
||||
success: boolean,
|
||||
data:
|
||||
| TypedInternalResponse<
|
||||
R,
|
||||
T,
|
||||
NitroFetchOptions<R> extends O ? 'get' : ExtractedRouteMethod<R, O>
|
||||
>
|
||||
| undefined
|
||||
) => Promise<void>;
|
||||
type RevertFn<T> = (success: boolean, data: T | undefined) => Promise<void>;
|
||||
|
||||
type SubmitOpts<
|
||||
R extends NitroFetchRequest,
|
||||
T = unknown,
|
||||
O extends NitroFetchOptions<R> = NitroFetchOptions<R>,
|
||||
> = {
|
||||
revert: RevertFn<R, T, O>;
|
||||
type SubmitOpts<T> = {
|
||||
revert: RevertFn<T>;
|
||||
successMsg?: string;
|
||||
noSuccessToast?: boolean;
|
||||
};
|
||||
|
||||
export function useSubmit<
|
||||
R extends NitroFetchRequest,
|
||||
O extends NitroFetchOptions<R> & { body?: never },
|
||||
T = unknown,
|
||||
>(url: R, options: O, opts: SubmitOpts<R, T, O>) {
|
||||
type Body = Record<string, unknown> | null | undefined;
|
||||
|
||||
export function useSubmit<T>(
|
||||
fetcher: (data: Body) => Promise<T>,
|
||||
opts: SubmitOpts<T>
|
||||
) {
|
||||
const toast = useToast();
|
||||
|
||||
return async (data: unknown) => {
|
||||
return async (data: Body) => {
|
||||
try {
|
||||
const res = await $fetch(url, {
|
||||
...options,
|
||||
body: data,
|
||||
});
|
||||
const res = await fetcher(data);
|
||||
|
||||
if (!opts.noSuccessToast) {
|
||||
toast.showToast({
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
<template>
|
||||
<div>
|
||||
<header class="mx-auto mt-4 flex max-w-3xl flex-col justify-center">
|
||||
<header
|
||||
class="mx-auto my-4 flex max-w-3xl flex-col justify-center max-md:px-3"
|
||||
>
|
||||
<div
|
||||
class="mb-5 w-full"
|
||||
:class="
|
||||
@@ -17,7 +19,7 @@
|
||||
<UiUserMenu v-if="loggedIn" />
|
||||
</div>
|
||||
</div>
|
||||
<HeaderUpdate class="mt-4" />
|
||||
<HeaderUpdate class="my-4" />
|
||||
</header>
|
||||
<slot />
|
||||
<UiFooter />
|
||||
|
||||
+36
-24
@@ -2,35 +2,47 @@
|
||||
<div>
|
||||
<div class="container mx-auto p-4">
|
||||
<div class="flex flex-col gap-4 lg:flex-row">
|
||||
<div class="rounded-lg bg-white p-4 lg:w-64 dark:bg-neutral-700">
|
||||
<NuxtLink to="/admin">
|
||||
<h2 class="mb-4 text-xl font-bold dark:text-neutral-200">
|
||||
{{ t('pages.admin.panel') }}
|
||||
</h2>
|
||||
</NuxtLink>
|
||||
<div class="flex flex-col space-y-2">
|
||||
<NuxtLink
|
||||
v-for="(item, index) in menuItems"
|
||||
:key="index"
|
||||
:to="`/admin/${item.id}`"
|
||||
class="group rounded"
|
||||
active-class="bg-red-800 active"
|
||||
>
|
||||
<BaseSecondaryButton
|
||||
as="span"
|
||||
class="w-full font-medium group-[.active]:text-white"
|
||||
<div
|
||||
class="overflow-hidden rounded-lg bg-white text-gray-700 shadow-md lg:w-64 dark:bg-neutral-700 dark:text-neutral-200"
|
||||
>
|
||||
<PanelHead>
|
||||
<PanelHeadTitle>
|
||||
<NuxtLink to="/admin">
|
||||
{{ t('pages.admin.panel') }}
|
||||
</NuxtLink>
|
||||
</PanelHeadTitle>
|
||||
</PanelHead>
|
||||
<PanelBody>
|
||||
<nav class="flex flex-col gap-2">
|
||||
<NuxtLink
|
||||
v-for="(item, index) in menuItems"
|
||||
:key="index"
|
||||
:to="`/admin/${item.id}`"
|
||||
class="group rounded"
|
||||
active-class="bg-red-800 active"
|
||||
>
|
||||
{{ item.name }}
|
||||
</BaseSecondaryButton>
|
||||
</NuxtLink>
|
||||
</div>
|
||||
<BaseSecondaryButton
|
||||
as="span"
|
||||
class="w-full font-medium group-[.active]:text-white"
|
||||
>
|
||||
{{ item.name }}
|
||||
</BaseSecondaryButton>
|
||||
</NuxtLink>
|
||||
</nav>
|
||||
</PanelBody>
|
||||
</div>
|
||||
|
||||
<div
|
||||
class="flex-1 rounded-lg bg-white p-6 dark:bg-neutral-700 dark:text-neutral-200"
|
||||
class="flex-1 overflow-hidden rounded-lg bg-white text-gray-700 shadow-md dark:bg-neutral-700 dark:text-neutral-200"
|
||||
>
|
||||
<h1 class="mb-6 text-3xl font-bold">{{ activeMenuItem.name }}</h1>
|
||||
<NuxtPage />
|
||||
<PanelHead>
|
||||
<PanelHeadTitle>
|
||||
{{ activeMenuItem.name }}
|
||||
</PanelHeadTitle>
|
||||
</PanelHead>
|
||||
<PanelBody>
|
||||
<NuxtPage />
|
||||
</PanelBody>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -121,10 +121,11 @@ const { data: _data, refresh } = await useFetch(`/api/admin/userconfig`, {
|
||||
const data = toRef(_data.value);
|
||||
|
||||
const _submit = useSubmit(
|
||||
`/api/admin/userconfig`,
|
||||
{
|
||||
method: 'post',
|
||||
},
|
||||
(data) =>
|
||||
$fetch(`/api/admin/userconfig`, {
|
||||
method: 'post',
|
||||
body: data,
|
||||
}),
|
||||
{ revert }
|
||||
);
|
||||
|
||||
|
||||
@@ -46,10 +46,11 @@ const { data: _data, refresh } = await useFetch(`/api/admin/general`, {
|
||||
const data = toRef(_data.value);
|
||||
|
||||
const _submit = useSubmit(
|
||||
`/api/admin/general`,
|
||||
{
|
||||
method: 'post',
|
||||
},
|
||||
(data) =>
|
||||
$fetch(`/api/admin/general`, {
|
||||
method: 'post',
|
||||
body: data,
|
||||
}),
|
||||
{ revert }
|
||||
);
|
||||
|
||||
|
||||
@@ -40,10 +40,11 @@ const { data: _data, refresh } = await useFetch(`/api/admin/hooks`, {
|
||||
const data = toRef(_data.value);
|
||||
|
||||
const _submit = useSubmit(
|
||||
`/api/admin/hooks`,
|
||||
{
|
||||
method: 'post',
|
||||
},
|
||||
(data) =>
|
||||
$fetch(`/api/admin/hooks`, {
|
||||
method: 'post',
|
||||
body: data,
|
||||
}),
|
||||
{ revert }
|
||||
);
|
||||
|
||||
|
||||
@@ -176,10 +176,11 @@ const { data: _data, refresh } = await useFetch(`/api/admin/interface`, {
|
||||
const data = toRef(_data.value);
|
||||
|
||||
const _submit = useSubmit(
|
||||
`/api/admin/interface`,
|
||||
{
|
||||
method: 'post',
|
||||
},
|
||||
(data) =>
|
||||
$fetch(`/api/admin/interface`, {
|
||||
method: 'post',
|
||||
body: data,
|
||||
}),
|
||||
{
|
||||
revert: async (success) => {
|
||||
await revert();
|
||||
@@ -201,10 +202,11 @@ async function revert() {
|
||||
}
|
||||
|
||||
const _changeCidr = useSubmit(
|
||||
`/api/admin/interface/cidr`,
|
||||
{
|
||||
method: 'post',
|
||||
},
|
||||
(data) =>
|
||||
$fetch(`/api/admin/interface/cidr`, {
|
||||
method: 'post',
|
||||
body: data,
|
||||
}),
|
||||
{
|
||||
revert,
|
||||
successMsg: t('admin.interface.cidrSuccess'),
|
||||
@@ -216,10 +218,11 @@ async function changeCidr(ipv4Cidr: string, ipv6Cidr: string) {
|
||||
}
|
||||
|
||||
const _restartInterface = useSubmit(
|
||||
`/api/admin/interface/restart`,
|
||||
{
|
||||
method: 'post',
|
||||
},
|
||||
(data) =>
|
||||
$fetch(`/api/admin/interface/restart`, {
|
||||
method: 'post',
|
||||
body: data,
|
||||
}),
|
||||
{
|
||||
revert,
|
||||
successMsg: t('admin.interface.restartSuccess'),
|
||||
|
||||
@@ -2,7 +2,9 @@
|
||||
<main v-if="data">
|
||||
<Panel>
|
||||
<PanelHead>
|
||||
<PanelHeadTitle :text="data.name" />
|
||||
<PanelHeadTitle>
|
||||
{{ data.name }}
|
||||
</PanelHeadTitle>
|
||||
</PanelHead>
|
||||
<PanelBody>
|
||||
<FormElement @submit.prevent="submit">
|
||||
@@ -223,10 +225,11 @@ const { data: _data, refresh } = await useFetch(`/api/client/${id}`, {
|
||||
const data = toRef(_data.value);
|
||||
|
||||
const _submit = useSubmit(
|
||||
`/api/client/${id}`,
|
||||
{
|
||||
method: 'post',
|
||||
},
|
||||
(data) =>
|
||||
$fetch(`/api/client/${id}`, {
|
||||
method: 'post',
|
||||
body: data,
|
||||
}),
|
||||
{
|
||||
revert: async (success) => {
|
||||
if (success) {
|
||||
@@ -248,10 +251,11 @@ async function revert() {
|
||||
}
|
||||
|
||||
const _deleteClient = useSubmit(
|
||||
`/api/client/${id}`,
|
||||
{
|
||||
method: 'delete',
|
||||
},
|
||||
(data) =>
|
||||
$fetch(`/api/client/${id}`, {
|
||||
method: 'delete',
|
||||
body: data,
|
||||
}),
|
||||
{
|
||||
revert: async () => {
|
||||
await navigateTo('/');
|
||||
|
||||
@@ -2,11 +2,15 @@
|
||||
<main>
|
||||
<Panel>
|
||||
<PanelHead>
|
||||
<PanelHeadTitle :text="$t('pages.clients')" />
|
||||
<PanelHeadTitle>
|
||||
{{ $t('pages.clients') }}
|
||||
</PanelHeadTitle>
|
||||
<PanelHeadBoat>
|
||||
<ClientsSearch />
|
||||
<ClientsSort />
|
||||
<ClientsNew />
|
||||
<div class="flex gap-2">
|
||||
<ClientsSort />
|
||||
<ClientsNew />
|
||||
</div>
|
||||
</PanelHeadBoat>
|
||||
</PanelHead>
|
||||
|
||||
|
||||
@@ -78,10 +78,11 @@ const totpRequired = ref(false);
|
||||
const totp = ref<string>('');
|
||||
|
||||
const _submit = useSubmit(
|
||||
'/api/session',
|
||||
{
|
||||
method: 'post',
|
||||
},
|
||||
(data) =>
|
||||
$fetch('/api/session', {
|
||||
method: 'post',
|
||||
body: data,
|
||||
}),
|
||||
{
|
||||
revert: async (success, data) => {
|
||||
if (success) {
|
||||
|
||||
+28
-21
@@ -2,7 +2,9 @@
|
||||
<main>
|
||||
<Panel>
|
||||
<PanelHead>
|
||||
<PanelHeadTitle :text="$t('pages.me')" />
|
||||
<PanelHeadTitle>
|
||||
{{ $t('pages.me') }}
|
||||
</PanelHeadTitle>
|
||||
</PanelHead>
|
||||
<PanelBody class="dark:text-neutral-200">
|
||||
<FormElement @submit.prevent="submit">
|
||||
@@ -125,10 +127,11 @@ const name = ref(authStore.userData?.name);
|
||||
const email = ref(authStore.userData?.email);
|
||||
|
||||
const _submit = useSubmit(
|
||||
`/api/me`,
|
||||
{
|
||||
method: 'post',
|
||||
},
|
||||
(data) =>
|
||||
$fetch(`/api/me`, {
|
||||
method: 'post',
|
||||
body: data,
|
||||
}),
|
||||
{
|
||||
revert: () => {
|
||||
return authStore.update();
|
||||
@@ -145,10 +148,11 @@ const newPassword = ref('');
|
||||
const confirmPassword = ref('');
|
||||
|
||||
const _updatePassword = useSubmit(
|
||||
`/api/me/password`,
|
||||
{
|
||||
method: 'post',
|
||||
},
|
||||
(data) =>
|
||||
$fetch(`/api/me/password`, {
|
||||
method: 'post',
|
||||
body: data,
|
||||
}),
|
||||
{
|
||||
revert: async () => {
|
||||
currentPassword.value = '';
|
||||
@@ -169,10 +173,11 @@ function updatePassword() {
|
||||
const twofa = ref<{ key: string; qrcode: string } | null>(null);
|
||||
|
||||
const _setup2fa = useSubmit(
|
||||
`/api/me/totp`,
|
||||
{
|
||||
method: 'post',
|
||||
},
|
||||
(data) =>
|
||||
$fetch(`/api/me/totp`, {
|
||||
method: 'post',
|
||||
body: data,
|
||||
}),
|
||||
{
|
||||
revert: async (success, data) => {
|
||||
if (success && data?.type === 'setup') {
|
||||
@@ -197,10 +202,11 @@ async function setup2fa() {
|
||||
const code = ref<string>('');
|
||||
|
||||
const _enable2fa = useSubmit(
|
||||
`/api/me/totp`,
|
||||
{
|
||||
method: 'post',
|
||||
},
|
||||
(data) =>
|
||||
$fetch(`/api/me/totp`, {
|
||||
method: 'post',
|
||||
body: data,
|
||||
}),
|
||||
{
|
||||
revert: async (success, data) => {
|
||||
if (success && data?.type === 'created') {
|
||||
@@ -222,10 +228,11 @@ async function enable2fa() {
|
||||
const disable2faPassword = ref('');
|
||||
|
||||
const _disable2fa = useSubmit(
|
||||
`/api/me/totp`,
|
||||
{
|
||||
method: 'post',
|
||||
},
|
||||
(data) =>
|
||||
$fetch(`/api/me/totp`, {
|
||||
method: 'post',
|
||||
body: data,
|
||||
}),
|
||||
{
|
||||
revert: async (success, data) => {
|
||||
if (success && data?.type === 'deleted') {
|
||||
|
||||
@@ -50,10 +50,11 @@ const password = ref<string>('');
|
||||
const confirmPassword = ref<string>('');
|
||||
|
||||
const _submit = useSubmit(
|
||||
'/api/setup/2',
|
||||
{
|
||||
method: 'post',
|
||||
},
|
||||
(data) =>
|
||||
$fetch('/api/setup/2', {
|
||||
method: 'post',
|
||||
body: data,
|
||||
}),
|
||||
{
|
||||
revert: async (success) => {
|
||||
if (success) {
|
||||
|
||||
@@ -43,10 +43,11 @@ const host = ref<null | string>(null);
|
||||
const port = ref<number>(51820);
|
||||
|
||||
const _submit = useSubmit(
|
||||
'/api/setup/4',
|
||||
{
|
||||
method: 'post',
|
||||
},
|
||||
(data) =>
|
||||
$fetch('/api/setup/4', {
|
||||
method: 'post',
|
||||
body: data,
|
||||
}),
|
||||
{
|
||||
revert: async (success) => {
|
||||
if (success) {
|
||||
|
||||
@@ -36,10 +36,11 @@ function onChangeFile(evt: Event) {
|
||||
}
|
||||
|
||||
const _submit = useSubmit(
|
||||
'/api/setup/migrate',
|
||||
{
|
||||
method: 'post',
|
||||
},
|
||||
(data) =>
|
||||
$fetch('/api/setup/migrate', {
|
||||
method: 'post',
|
||||
body: data,
|
||||
}),
|
||||
{
|
||||
revert: async (success) => {
|
||||
if (success) {
|
||||
|
||||
@@ -4,6 +4,7 @@ import uk from './locales/uk.json';
|
||||
import fr from './locales/fr.json';
|
||||
import de from './locales/de.json';
|
||||
import it from './locales/it.json';
|
||||
import ja from './locales/ja.json';
|
||||
import ru from './locales/ru.json';
|
||||
import zhhk from './locales/zh-HK.json';
|
||||
import zhcn from './locales/zh-CN.json';
|
||||
@@ -17,8 +18,10 @@ import id from './locales/id.json';
|
||||
import nl from './locales/nl.json';
|
||||
import nb from './locales/nb.json';
|
||||
import bg from './locales/bg.json';
|
||||
import hi from './locales/hi.json';
|
||||
import gl from './locales/gl.json';
|
||||
import cs from './locales/cs.json';
|
||||
import vi from './locales/vi.json';
|
||||
|
||||
export default defineI18nConfig(() => ({
|
||||
legacy: false,
|
||||
@@ -30,6 +33,7 @@ export default defineI18nConfig(() => ({
|
||||
fr,
|
||||
de,
|
||||
it,
|
||||
ja,
|
||||
ru,
|
||||
'zh-HK': zhhk,
|
||||
'zh-CN': zhcn,
|
||||
@@ -43,7 +47,9 @@ export default defineI18nConfig(() => ({
|
||||
nl,
|
||||
nb,
|
||||
bg,
|
||||
hi,
|
||||
gl,
|
||||
cs,
|
||||
vi,
|
||||
},
|
||||
}));
|
||||
|
||||
@@ -88,6 +88,7 @@
|
||||
"name": "Name",
|
||||
"expireDate": "Ablaufdatum",
|
||||
"expireDateDesc": "Datum, an dem der Client deaktiviert wird. Leer lassen für dauerhaft aktiv.",
|
||||
"delete": "Löschen",
|
||||
"deleteClient": "Client löschen",
|
||||
"deleteDialog1": "Sind Sie sicher, dass Sie diesen Client löschen möchten",
|
||||
"deleteDialog2": "Diese Aktion kann nicht rückgängig gemacht werden.",
|
||||
@@ -114,13 +115,16 @@
|
||||
"hooksDescription": "Hooks funktionieren nur mit wg-quick",
|
||||
"hooksLeaveEmpty": "Nur für wg-quick. Andernfalls leer lassen",
|
||||
"dnsDesc": "DNS-Server, den die Clients benutzen (überschreibt die globale Konfiguration)",
|
||||
"delete": "Löschen",
|
||||
"notConnected": "Client nicht verbunden",
|
||||
"endpoint": "Endpunkt",
|
||||
"endpointDesc": "IP-Adresse des Clients, von dem aus die WireGuard-Verbindung hergestellt wird",
|
||||
"search": "Suche Clients...",
|
||||
"config": "Konfiguration",
|
||||
"viewConfig": "Konfiguration anzeigen"
|
||||
"viewConfig": "Konfiguration anzeigen",
|
||||
"firewallIps": "Firewall erlaubte IPs",
|
||||
"firewallIpsDesc": "Ziel-IPs/CIDRs, auf die dieser Client zugreifen darf (serverseitig erzwingen). Lassen Sie das Feld leer, um die Liste der zugelassenen IPs zu verwenden. Unterstützt optionale Port- und Protokollfilterung. Die Syntax finden Sie in der Dokumentation.",
|
||||
"downloadPng": "Herunterladen PNG",
|
||||
"copyPng": "Kopieren PNG"
|
||||
},
|
||||
"dialog": {
|
||||
"change": "Ändern",
|
||||
@@ -130,7 +134,8 @@
|
||||
"toast": {
|
||||
"success": "Erfolg",
|
||||
"saved": "Gespeichert",
|
||||
"error": "Fehler"
|
||||
"error": "Fehler",
|
||||
"unknown": "Unbekannter Fehler. Weitere Informationen finden Sie in der Konsole."
|
||||
},
|
||||
"form": {
|
||||
"actions": "Aktionen",
|
||||
@@ -175,7 +180,10 @@
|
||||
"restart": "Interface neu starten",
|
||||
"restartDesc": "Das WireGuard-Interface neu starten",
|
||||
"restartWarn": "Sind Sie sicher, dass Sie das Interface neu starten möchten? Dies wird die Verbindungen aller Clients trennen.",
|
||||
"restartSuccess": "Interface neu gestartet"
|
||||
"restartSuccess": "Interface neu gestartet",
|
||||
"firewall": "Datenverkehr Filterung",
|
||||
"firewallEnabled": "Firewall pro Client aktivieren",
|
||||
"firewallEnabledDesc": "Beschränken Sie den Client-Datenverkehr mithilfe von iptables auf bestimmte Ziel-IP-Adressen. Bei Aktivierung kann für jeden Client eine Liste der zulässigen Ziele konfiguriert werden."
|
||||
},
|
||||
"introText": "Willkommen in der Admin-Konsole.\n\nHier können Sie die allgemeinen Einstellungen, die Konfiguration, die Schnittstelleneinstellungen und die Hooks verwalten.\n\nBeginnen Sie, indem Sie einen der Bereiche in der Seitenleiste auswählen."
|
||||
},
|
||||
@@ -183,6 +191,7 @@
|
||||
"generic": {
|
||||
"required": "{0} ist erforderlich",
|
||||
"validNumber": "{0} muss eine Zahl sein",
|
||||
"validNumberRange": "{0} muss eine gültige Zahl oder ein gültiger Zahlenbereich sein",
|
||||
"validString": "{0} muss eine Zeichenkette sein",
|
||||
"validBoolean": "{0} muss ein Wahrheitswert sein",
|
||||
"validArray": "{0} muss eine Liste sein",
|
||||
@@ -195,7 +204,9 @@
|
||||
"expiresAt": "Läuft ab am",
|
||||
"address4": "IPv4-Adresse",
|
||||
"address6": "IPv6-Adresse",
|
||||
"serverAllowedIps": "Serverseitig erlaubte IP-Adressen"
|
||||
"serverAllowedIps": "Serverseitig erlaubte IP-Adressen",
|
||||
"firewallIps": "Von der Firewall zugelassene IP-Adressen",
|
||||
"firewallIpsInvalid": "Ungültiger IP-Eintrag in der Firewall. Informationen zur unterstützten Syntax finden Sie in der Dokumentation."
|
||||
},
|
||||
"user": {
|
||||
"username": "Benutzername",
|
||||
|
||||
@@ -116,7 +116,14 @@
|
||||
"dnsDesc": "Servidor DNS que usarán los clientes (anula la configuración global)",
|
||||
"notConnected": "Cliente no conectado",
|
||||
"endpoint": "Punto de conexión",
|
||||
"endpointDesc": "IP del cliente desde donde se establece la conexión WireGuard"
|
||||
"endpointDesc": "IP del cliente desde donde se establece la conexión WireGuard",
|
||||
"search": "Buscar clientes...",
|
||||
"config": "Configuración",
|
||||
"viewConfig": "Ver configuración",
|
||||
"firewallIps": "IPs permitidas del cortafuegos",
|
||||
"firewallIpsDesc": "IPs/CIDRs de destino a las que este cliente puede acceder (aplicado en el servidor). Deja vacío para usar IPs permitidas. Admite filtrado opcional de puertos y protocolos. Consulta la documentación para la sintaxis.",
|
||||
"downloadPng": "Descargar PNG",
|
||||
"copyPng": "Copiar PNG"
|
||||
},
|
||||
"dialog": {
|
||||
"change": "Cambiar",
|
||||
@@ -126,7 +133,8 @@
|
||||
"toast": {
|
||||
"success": "Éxito",
|
||||
"saved": "Guardado",
|
||||
"error": "Error"
|
||||
"error": "Error",
|
||||
"unknown": "Error desconocido. Revisa la consola para más detalles"
|
||||
},
|
||||
"form": {
|
||||
"actions": "Acciones",
|
||||
@@ -171,7 +179,10 @@
|
||||
"restart": "Reiniciar interfaz",
|
||||
"restartDesc": "Reiniciar la interfaz de WireGuard",
|
||||
"restartWarn": "¿Estás seguro de reiniciar la interfaz? Esto desconectará a todos los clientes.",
|
||||
"restartSuccess": "Interfaz reiniciada"
|
||||
"restartSuccess": "Interfaz reiniciada",
|
||||
"firewall": "Filtrado de tráfico",
|
||||
"firewallEnabled": "Habilitar cortafuegos por cliente",
|
||||
"firewallEnabledDesc": "Restringe el tráfico del cliente a IPs de destino específicas usando iptables. Cuando está activado, cada cliente puede configurarse con destinos permitidos."
|
||||
},
|
||||
"introText": "Bienvenido al panel de administración.\n\nAquí puedes gestionar los ajustes generales, la configuración, la interfaz y los hooks.\n\nEmpieza eligiendo una de las secciones en la barra lateral."
|
||||
},
|
||||
@@ -179,6 +190,7 @@
|
||||
"generic": {
|
||||
"required": "{0} es obligatorio",
|
||||
"validNumber": "{0} debe ser un número válido",
|
||||
"validNumberRange": "{0} debe ser un número válido o un rango de números",
|
||||
"validString": "{0} debe ser una cadena válida",
|
||||
"validBoolean": "{0} debe ser un booleano válido",
|
||||
"validArray": "{0} debe ser una lista válida",
|
||||
@@ -191,7 +203,9 @@
|
||||
"expiresAt": "Expira el",
|
||||
"address4": "Dirección IPv4",
|
||||
"address6": "Dirección IPv6",
|
||||
"serverAllowedIps": "IPs permitidas del servidor"
|
||||
"serverAllowedIps": "IPs permitidas del servidor",
|
||||
"firewallIps": "IPs permitidas del cortafuegos",
|
||||
"firewallIpsInvalid": "Entrada de IP de cortafuegos no válida. Consulta la documentación para la sintaxis compatible."
|
||||
},
|
||||
"user": {
|
||||
"username": "Usuario",
|
||||
@@ -236,5 +250,47 @@
|
||||
"postUp": "PostUp",
|
||||
"preDown": "PreDown",
|
||||
"postDown": "PostDown"
|
||||
},
|
||||
"copy": {
|
||||
"notSupported": "La copia no es compatible",
|
||||
"copied": "¡Copiado!",
|
||||
"failed": "Error al copiar",
|
||||
"copy": "Copiar"
|
||||
},
|
||||
"awg": {
|
||||
"jCLabel": "Número de paquetes basura (Jc)",
|
||||
"jCDescription": "Número de paquetes basura a enviar (1-128, recomendado: 4-12)",
|
||||
"jMinLabel": "Tamaño mínimo de paquete basura (Jmin)",
|
||||
"jMinDescription": "Tamaño mínimo de los paquetes basura (0-1279*, recomendado: 8, debe ser < Jmax)",
|
||||
"jMaxLabel": "Tamaño máximo de paquete basura (Jmax)",
|
||||
"jMaxDescription": "Tamaño máximo de los paquetes basura (1-1280*, recomendado: 80, debe ser > Jmin)",
|
||||
"s1Label": "Tamaño de basura del paquete Init (S1)",
|
||||
"s1Description": "Tamaño de basura del paquete Init (0-1132[1280* - 148 = 1132], recomendado: 15-150, S1+56 ≠ S2)",
|
||||
"s2Label": "Tamaño de basura del paquete de respuesta (S2)",
|
||||
"s2Description": "Tamaño de basura del paquete de respuesta (0-1188[1280* - 92 = 1188], recomendado: 15-150)",
|
||||
"s3Label": "Tamaño de basura del paquete de respuesta de cookie (S3)",
|
||||
"s3Description": "Tamaño de basura del paquete de respuesta de cookie",
|
||||
"s4Label": "Tamaño de basura del paquete de transporte (S4)",
|
||||
"s4Description": "Tamaño de basura del paquete de transporte",
|
||||
"h1Label": "Cabecera mágica Init (H1)",
|
||||
"h1Description": "Valor o rango de cabecera del paquete Init (X o X-Y, donde X<Y. Mín 5, máx 2147483647. El valor o rango no debe solaparse con otras cabeceras)",
|
||||
"h2Label": "Cabecera mágica de respuesta (H2)",
|
||||
"h2Description": "Valor o rango de cabecera del paquete de respuesta (X o X-Y, donde X<Y. Mín 5, máx 2147483647. El valor o rango no debe solaparse con otras cabeceras)",
|
||||
"h3Label": "Cabecera mágica de respuesta de cookie (H3)",
|
||||
"h3Description": "Valor o rango de cabecera del paquete de respuesta de cookie (X o X-Y, donde X<Y. Mín 5, máx 2147483647. El valor o rango no debe solaparse con otras cabeceras)",
|
||||
"h4Label": "Cabecera mágica de transporte (H4)",
|
||||
"h4Description": "Valor o rango de cabecera del paquete de transporte (X o X-Y, donde X<Y. Mín 5, máx 2147483647. El valor o rango no debe solaparse con otras cabeceras)",
|
||||
"i1Label": "Paquete basura especial 1 (I1)",
|
||||
"i1Description": "Paquete que imita protocolo en formato hex: <b 0x...>",
|
||||
"i2Label": "Paquete basura especial 2 (I2)",
|
||||
"i2Description": "Paquete que imita protocolo en formato hex: <b 0x...>",
|
||||
"i3Label": "Paquete basura especial 3 (I3)",
|
||||
"i3Description": "Paquete que imita protocolo en formato hex: <b 0x...>",
|
||||
"i4Label": "Paquete basura especial 4 (I4)",
|
||||
"i4Description": "Paquete que imita protocolo en formato hex: <b 0x...>",
|
||||
"i5Label": "Paquete basura especial 5 (I5)",
|
||||
"i5Description": "Paquete que imita protocolo en formato hex: <b 0x...>",
|
||||
"mtuNote": "Los valores dependen de la MTU",
|
||||
"obfuscationParameters": "Parámetros de ofuscación AmneziaWG"
|
||||
}
|
||||
}
|
||||
|
||||
+23
-12
@@ -51,7 +51,7 @@
|
||||
"setupConfigDesc": "Veuillez saisir les informations relatives à l'hôte et au port. Ceci sera utilisé pour la configuration du client lors de la mise en place de WireGuard sur les appareils.",
|
||||
"setupMigrationDesc": "Veuillez fournir le fichier de sauvegarde si vous souhaitez migrer vos données de la version précédente de wg-easy vers votre nouvelle installation.",
|
||||
"upload": "Téléverser",
|
||||
"migration": "Restaurer la sauvegarde:",
|
||||
"migration": "Restaurer la sauvegarde :",
|
||||
"createAccount": "Créer un compte",
|
||||
"successful": "Installation réussie",
|
||||
"hostDesc": "Nom d'hôte public auquel les clients se connecteront",
|
||||
@@ -88,18 +88,19 @@
|
||||
"name": "Nom",
|
||||
"expireDate": "Date d'expiration",
|
||||
"expireDateDesc": "Date à laquelle le client sera désactivé. Vide pour permanent",
|
||||
"delete": "Supprimer",
|
||||
"deleteClient": "Supprimer le client",
|
||||
"deleteDialog1": "Êtes-vous sûr de vouloir supprimer",
|
||||
"deleteDialog2": "Cette action ne peut être annulée.",
|
||||
"enabled": "Activé",
|
||||
"address": "Adresse",
|
||||
"serverAllowedIps": "Serveur IPs autorisées",
|
||||
"serverAllowedIps": "IPs autorisées par le serveur",
|
||||
"otlDesc": "Générer un lien court et unique",
|
||||
"permanent": "Permanent",
|
||||
"createdOn": "Créé le ",
|
||||
"lastSeen": "Dernière visite le ",
|
||||
"totalDownload": "Téléchargement total: ",
|
||||
"totalUpload": "Téléversement total: ",
|
||||
"totalDownload": "Téléchargement total : ",
|
||||
"totalUpload": "Téléversement total : ",
|
||||
"newClient": "Nouveau client",
|
||||
"disableClient": "Désactiver le client",
|
||||
"enableClient": "Activer le client",
|
||||
@@ -120,7 +121,10 @@
|
||||
"search": "Rechercher des clients...",
|
||||
"config": "Configuration",
|
||||
"viewConfig": "Voir la configuration",
|
||||
"delete": "Supprimer"
|
||||
"firewallIps": "IPs autorisées par le pare-feu",
|
||||
"firewallIpsDesc": "IPs/CIDRs de destination auxquels ce client peut accéder (application côté serveur). Laissez vide pour utiliser les IPs autorisées. Prend en charge le filtrage optionnel par port et protocole. Voir la documentation pour la syntaxe.",
|
||||
"downloadPng": "Télécharger le PNG",
|
||||
"copyPng": "Copier le PNG"
|
||||
},
|
||||
"dialog": {
|
||||
"change": "Modifier",
|
||||
@@ -130,7 +134,8 @@
|
||||
"toast": {
|
||||
"success": "Réussite",
|
||||
"saved": "Sauvegardé",
|
||||
"error": "Erreur"
|
||||
"error": "Erreur",
|
||||
"unknown": "Erreur inconnue. Consultez la console pour plus de détails"
|
||||
},
|
||||
"form": {
|
||||
"actions": "Actions",
|
||||
@@ -175,7 +180,10 @@
|
||||
"restart": "Redémarrer l'interface",
|
||||
"restartDesc": "Redémarre l'interface WireGuard",
|
||||
"restartWarn": "Êtes-vous sûr de redémarrer l'interface ? Cela déconnectera tous les clients.",
|
||||
"restartSuccess": "Interface redémarrée"
|
||||
"restartSuccess": "Interface redémarrée",
|
||||
"firewall": "Filtrage du trafic",
|
||||
"firewallEnabled": "Activer le pare-feu par client",
|
||||
"firewallEnabledDesc": "Restreindre le trafic des clients à des IPs de destination spécifiques via iptables. Lorsqu'il est activé, chaque client peut être configuré avec des destinations autorisées."
|
||||
},
|
||||
"introText": "Bienvenue dans le panel d'administration.\n\nVous pouvez y gérer les paramètres généraux, la configuration, les paramètres de l'interface et les hooks.\n\nCommencez par choisir l'une des sections de la barre latérale."
|
||||
},
|
||||
@@ -183,6 +191,7 @@
|
||||
"generic": {
|
||||
"required": "{0} est requis",
|
||||
"validNumber": "{0} doit être un nombre valide",
|
||||
"validNumberRange": "{0} doit être un nombre ou une plage de nombres valide",
|
||||
"validString": "{0} doit être une chaîne de caractères valide",
|
||||
"validBoolean": "{0} doit être un booléen valide",
|
||||
"validArray": "{0} doit être un tableau valide",
|
||||
@@ -195,7 +204,9 @@
|
||||
"expiresAt": "Expire le",
|
||||
"address4": "Adresse IPv4",
|
||||
"address6": "Adresse IPv6",
|
||||
"serverAllowedIps": "Serveur IPs autorisées"
|
||||
"serverAllowedIps": "IPs autorisées par le serveur",
|
||||
"firewallIps": "IPs autorisées par le pare-feu",
|
||||
"firewallIpsInvalid": "Entrée d'IP de pare-feu invalide. Voir la documentation pour la syntaxe supportée."
|
||||
},
|
||||
"user": {
|
||||
"username": "Nom d'utilisateur",
|
||||
@@ -263,13 +274,13 @@
|
||||
"s4Label": "Taille parasite du paquet transport (S4)",
|
||||
"s4Description": "Taille parasite du paquet de transport",
|
||||
"h1Label": "En-tête magique init (H1)",
|
||||
"h1Description": "Valeur d'en-tête du paquet init (5-2147483647, doit être unique par rapport à H2-H4)",
|
||||
"h1Description": "Valeur ou plage de l'en-tête du paquet init (X ou X-Y, où X<Y. Min 5, max 2147483647. La valeur ou la plage ne doit pas chevaucher les autres en-têtes)",
|
||||
"h2Label": "En-tête magique réponse (H2)",
|
||||
"h2Description": "Valeur d'en-tête du paquet réponse (5-2147483647, doit être unique par rapport à H1, H3, H4)",
|
||||
"h2Description": "Valeur ou plage de l'en-tête du paquet réponse (X ou X-Y, où X<Y. Min 5, max 2147483647. La valeur ou la plage ne doit pas chevaucher les autres en-têtes)",
|
||||
"h3Label": "En-tête magique cookie reply (H3)",
|
||||
"h3Description": "Valeur d'en-tête du paquet cookie reply (5-2147483647, doit être unique par rapport à H1, H2, H4)",
|
||||
"h3Description": "Valeur ou plage de l'en-tête du paquet cookie reply (X ou X-Y, où X<Y. Min 5, max 2147483647. La valeur ou la plage ne doit pas chevaucher les autres en-têtes)",
|
||||
"h4Label": "En-tête magique transport (H4)",
|
||||
"h4Description": "Valeur d'en-tête du paquet transport (5-2147483647, doit être unique par rapport à H1-H3)",
|
||||
"h4Description": "Valeur ou plage de l'en-tête du paquet transport (X ou X-Y, où X<Y. Min 5, max 2147483647. La valeur ou la plage ne doit pas chevaucher les autres en-têtes)",
|
||||
"i1Label": "Paquet parasite spécial 1 (I1)",
|
||||
"i1Description": "Paquet de simulation de protocole en format hexadécimal : <b 0x...>",
|
||||
"i2Label": "Paquet parasite spécial 2 (I2)",
|
||||
|
||||
+152
-1
@@ -120,7 +120,11 @@
|
||||
"endpointDesc": "IP do cliente desde a que se establece a conexión WireGuard",
|
||||
"search": "Buscar clientes...",
|
||||
"config": "Configuración",
|
||||
"viewConfig": "Ver configuración"
|
||||
"viewConfig": "Ver configuración",
|
||||
"firewallIps": "IPs permitidas do cortalumes",
|
||||
"firewallIpsDesc": "IPs/CIDRs de destino aos que este cliente pode acceder (aplicado no lado do servidor). Déixao baleiro para usar as IPs permitidas. Admite filtrado opcional por porto e protocolo. Consulta a documentación para a sintaxe.",
|
||||
"downloadPng": "Descargar PNG",
|
||||
"copyPng": "Copiar PNG"
|
||||
},
|
||||
"dialog": {
|
||||
"change": "Cambiar",
|
||||
@@ -141,5 +145,152 @@
|
||||
"noItems": "Sen elementos",
|
||||
"nullNoItems": "Sen elementos. Usando a configuración global",
|
||||
"add": "Engadir"
|
||||
},
|
||||
"admin": {
|
||||
"general": {
|
||||
"sessionTimeout": "Tempo límite da sesión",
|
||||
"sessionTimeoutDesc": "Duración da sesión para Lembrarme (segundos)",
|
||||
"metrics": "Métricas",
|
||||
"metricsPassword": "Contrasinal",
|
||||
"metricsPasswordDesc": "Contrasinal Bearer para o endpoint de métricas (contrasinal ou hash argon2)",
|
||||
"json": "JSON",
|
||||
"jsonDesc": "Ruta para as métricas en formato JSON",
|
||||
"prometheus": "Prometheus",
|
||||
"prometheusDesc": "Ruta para as métricas de Prometheus"
|
||||
},
|
||||
"config": {
|
||||
"connection": "Conexión",
|
||||
"hostDesc": "Nome de host público ao que se conectarán os clientes (invalida a configuración)",
|
||||
"portDesc": "Porto UDP público ao que se conectarán os clientes (invalida a configuración; probablemente tamén queiras cambiar o Porto da interface)",
|
||||
"allowedIpsDesc": "IPs permitidas que usarán os clientes (configuración global)",
|
||||
"dnsDesc": "Servidor DNS que usarán os clientes (configuración global)",
|
||||
"mtuDesc": "MTU que usarán os clientes (só para clientes novos)",
|
||||
"persistentKeepaliveDesc": "Intervalo en segundos para enviar keepalives ao servidor. 0 = desactivado (só para clientes novos)",
|
||||
"suggest": "Suxerir",
|
||||
"suggestDesc": "Escolle un enderezo IP ou nome de host para o campo Host"
|
||||
},
|
||||
"interface": {
|
||||
"cidrSuccess": "CIDR cambiado",
|
||||
"device": "Dispositivo",
|
||||
"deviceDesc": "Dispositivo Ethernet polo que se redirixirá o tráfico de WireGuard",
|
||||
"mtuDesc": "MTU que usará WireGuard",
|
||||
"portDesc": "Porto UDP no que WireGuard escoitará (probablemente tamén queiras cambiar o Porto da configuración)",
|
||||
"changeCidr": "Cambiar CIDR",
|
||||
"restart": "Reiniciar interface",
|
||||
"restartDesc": "Reiniciar a interface de WireGuard",
|
||||
"restartWarn": "Seguro que queres reiniciar a interface? Isto desconectará todos os clientes.",
|
||||
"restartSuccess": "Interface reiniciada",
|
||||
"firewall": "Filtrado de tráfico",
|
||||
"firewallEnabled": "Activar devasa por cliente",
|
||||
"firewallEnabledDesc": "Restrinxir o tráfico dos clientes a IPs de destino específicas usando iptables. Cando está activado, cada cliente pode configurarse con destinos permitidos."
|
||||
},
|
||||
"introText": "Benvido ao panel de administración.\n\nAquí podes xestionar a configuración xeral, a configuración, os axustes da interface e os hooks.\n\nComeza escollendo unha das seccións na barra lateral."
|
||||
},
|
||||
"zod": {
|
||||
"generic": {
|
||||
"required": "{0} é obrigatorio",
|
||||
"validNumber": "{0} debe ser un número válido",
|
||||
"validNumberRange": "{0} debe ser un número válido ou un rango de números",
|
||||
"validString": "{0} debe ser unha cadea válida",
|
||||
"validBoolean": "{0} debe ser un booleano válido",
|
||||
"validArray": "{0} debe ser un array válido",
|
||||
"stringMin": "{0} debe ter polo menos {1} carácter",
|
||||
"numberMin": "{0} debe ser polo menos {1}"
|
||||
},
|
||||
"client": {
|
||||
"id": "ID do cliente",
|
||||
"name": "Nome",
|
||||
"expiresAt": "Caduca o",
|
||||
"address4": "Enderezo IPv4",
|
||||
"address6": "Enderezo IPv6",
|
||||
"serverAllowedIps": "IPs permitidas do servidor",
|
||||
"firewallIps": "IPs permitidas da devasa",
|
||||
"firewallIpsInvalid": "Entrada de IP da devasa non válida. Consulta a documentación para a sintaxe admitida."
|
||||
},
|
||||
"user": {
|
||||
"username": "Nome de usuario",
|
||||
"password": "Contrasinal",
|
||||
"remember": "Lembrar",
|
||||
"name": "Nome",
|
||||
"email": "Correo electrónico",
|
||||
"emailInvalid": "O correo electrónico debe ser válido",
|
||||
"passwordMatch": "Os contrasinais deben coincidir",
|
||||
"totpEnable": "Activar TOTP",
|
||||
"totpEnableTrue": "Activar TOTP debe ser verdadeiro",
|
||||
"totpCode": "Código TOTP"
|
||||
},
|
||||
"userConfig": {
|
||||
"host": "Host"
|
||||
},
|
||||
"general": {
|
||||
"sessionTimeout": "Tempo límite da sesión",
|
||||
"metricsEnabled": "Métricas",
|
||||
"metricsPassword": "Contrasinal das métricas"
|
||||
},
|
||||
"interface": {
|
||||
"cidr": "CIDR",
|
||||
"device": "Dispositivo",
|
||||
"cidrValid": "O CIDR debe ser válido"
|
||||
},
|
||||
"otl": "Ligazón dun só uso",
|
||||
"stringMalformed": "A cadea está mal formada",
|
||||
"body": "O corpo debe ser un obxecto válido",
|
||||
"hook": "Hook",
|
||||
"enabled": "Activado",
|
||||
"mtu": "MTU",
|
||||
"port": "Porto",
|
||||
"persistentKeepalive": "Keepalive persistente",
|
||||
"address": "Enderezo IP",
|
||||
"dns": "DNS",
|
||||
"allowedIps": "IPs permitidas",
|
||||
"file": "Ficheiro"
|
||||
},
|
||||
"hooks": {
|
||||
"preUp": "PreUp",
|
||||
"postUp": "PostUp",
|
||||
"preDown": "PreDown",
|
||||
"postDown": "PostDown"
|
||||
},
|
||||
"copy": {
|
||||
"notSupported": "Copiar non é compatible",
|
||||
"copied": "Copiado!",
|
||||
"failed": "Erro ao copiar",
|
||||
"copy": "Copiar"
|
||||
},
|
||||
"awg": {
|
||||
"jCLabel": "Número de paquetes lixo (Jc)",
|
||||
"jCDescription": "Número de paquetes lixo para enviar (1-128, recomendado: 4-12)",
|
||||
"jMinLabel": "Tamaño mínimo dos paquetes lixo (Jmin)",
|
||||
"jMinDescription": "Tamaño mínimo dos paquetes lixo (0-1279*, recomendado: 8, debe ser < Jmax)",
|
||||
"jMaxLabel": "Tamaño máximo dos paquetes lixo (Jmax)",
|
||||
"jMaxDescription": "Tamaño máximo dos paquetes lixo (1-1280*, recomendado: 80, debe ser > Jmin)",
|
||||
"s1Label": "Tamaño lixo do paquete de inicio (S1)",
|
||||
"s1Description": "Tamaño lixo do paquete de inicio (0-1132[1280* - 148 = 1132], recomendado: 15-150, S1+56 ≠ S2)",
|
||||
"s2Label": "Tamaño lixo do paquete de resposta (S2)",
|
||||
"s2Description": "Tamaño lixo do paquete de resposta (0-1188[1280* - 92 = 1188], recomendado: 15-150)",
|
||||
"s3Label": "Tamaño lixo do paquete de resposta cookie (S3)",
|
||||
"s3Description": "Tamaño lixo do paquete de resposta cookie",
|
||||
"s4Label": "Tamaño lixo do paquete de transporte (S4)",
|
||||
"s4Description": "Tamaño lixo do paquete de transporte",
|
||||
"h1Label": "Cabeceira máxica de inicio (H1)",
|
||||
"h1Description": "Valor ou rango da cabeceira do paquete de inicio (X ou X-Y, onde X<Y. Mín 5, máx 2147483647. O valor ou rango non debe solaparse con outras cabeceiras)",
|
||||
"h2Label": "Cabeceira máxica de resposta (H2)",
|
||||
"h2Description": "Valor ou rango da cabeceira do paquete de resposta (X ou X-Y, onde X<Y. Mín 5, máx 2147483647. O valor ou rango non debe solaparse con outras cabeceiras)",
|
||||
"h3Label": "Cabeceira máxica da resposta cookie (H3)",
|
||||
"h3Description": "Valor ou rango da cabeceira do paquete de resposta cookie (X ou X-Y, onde X<Y. Mín 5, máx 2147483647. O valor ou rango non debe solaparse con outras cabeceiras)",
|
||||
"h4Label": "Cabeceira máxica de transporte (H4)",
|
||||
"h4Description": "Valor ou rango da cabeceira do paquete de transporte (X ou X-Y, onde X<Y. Mín 5, máx 2147483647. O valor ou rango non debe solaparse con outras cabeceiras)",
|
||||
"i1Label": "Paquete lixo especial 1 (I1)",
|
||||
"i1Description": "Paquete de simulación de protocolo en formato hexadecimal: <b 0x...>",
|
||||
"i2Label": "Paquete lixo especial 2 (I2)",
|
||||
"i2Description": "Paquete de simulación de protocolo en formato hexadecimal: <b 0x...>",
|
||||
"i3Label": "Paquete lixo especial 3 (I3)",
|
||||
"i3Description": "Paquete de simulación de protocolo en formato hexadecimal: <b 0x...>",
|
||||
"i4Label": "Paquete lixo especial 4 (I4)",
|
||||
"i4Description": "Paquete de simulación de protocolo en formato hexadecimal: <b 0x...>",
|
||||
"i5Label": "Paquete lixo especial 5 (I5)",
|
||||
"i5Description": "Paquete de simulación de protocolo en formato hexadecimal: <b 0x...>",
|
||||
"mtuNote": "Os valores dependen da MTU",
|
||||
"obfuscationParameters": "Parámetros de ofuscación de AmneziaWG"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,297 @@
|
||||
{
|
||||
"pages": {
|
||||
"me": "खाता",
|
||||
"clients": "क्लाइंट",
|
||||
"admin": {
|
||||
"panel": "एडमिन पैनल",
|
||||
"general": "सामान्य",
|
||||
"config": "कॉन्फ़िगरेशन",
|
||||
"interface": "इंटरफ़ेस",
|
||||
"hooks": "हुक्स"
|
||||
}
|
||||
},
|
||||
"user": {
|
||||
"email": "ई-मेल"
|
||||
},
|
||||
"me": {
|
||||
"currentPassword": "वर्तमान पासवर्ड",
|
||||
"enable2fa": "दो-कारक प्रमाणीकरण सक्षम करें",
|
||||
"enable2faDesc": "अपने प्रमाणक ऐप से QR कोड स्कैन करें या कुंजी मैन्युअल रूप से दर्ज करें।",
|
||||
"2faKey": "TOTP कुंजी",
|
||||
"2faCodeDesc": "अपने प्रमाणक ऐप से कोड दर्ज करें।",
|
||||
"disable2fa": "दो-कारक प्रमाणीकरण अक्षम करें",
|
||||
"disable2faDesc": "दो-कारक प्रमाणीकरण अक्षम करने के लिए अपना पासवर्ड दर्ज करें।"
|
||||
},
|
||||
"general": {
|
||||
"name": "नाम",
|
||||
"username": "उपयोगकर्ता नाम",
|
||||
"password": "पासवर्ड",
|
||||
"newPassword": "नया पासवर्ड",
|
||||
"updatePassword": "पासवर्ड अपडेट करें",
|
||||
"mtu": "MTU",
|
||||
"allowedIps": "अनुमत IPs",
|
||||
"dns": "DNS",
|
||||
"persistentKeepalive": "स्थायी कीपअलाइव",
|
||||
"logout": "लॉगआउट",
|
||||
"continue": "जारी रखें",
|
||||
"host": "होस्ट",
|
||||
"port": "पोर्ट",
|
||||
"yes": "हाँ",
|
||||
"no": "नहीं",
|
||||
"confirmPassword": "पासवर्ड की पुष्टि करें",
|
||||
"loading": "लोड हो रहा है...",
|
||||
"2fa": "दो-कारक प्रमाणीकरण",
|
||||
"2faCode": "TOTP कोड"
|
||||
},
|
||||
"setup": {
|
||||
"welcome": "wg-easy की प्रारंभिक सेटअप में आपका स्वागत है",
|
||||
"welcomeDesc": "आपने किसी भी Linux होस्ट पर WireGuard इंस्टॉल और प्रबंधित करने का सबसे आसान तरीका खोज लिया है",
|
||||
"existingSetup": "क्या आपके पास पहले से कोई सेटअप है?",
|
||||
"createAdminDesc": "कृपया पहले एडमिन उपयोगकर्ता नाम और एक मज़बूत सुरक्षित पासवर्ड दर्ज करें। इस जानकारी का उपयोग प्रशासन पैनल में लॉग इन करने के लिए किया जाएगा।",
|
||||
"setupConfigDesc": "कृपया होस्ट और पोर्ट जानकारी दर्ज करें। इसका उपयोग उनके डिवाइस पर WireGuard सेटअप करते समय क्लाइंट कॉन्फ़िगरेशन के लिए किया जाएगा।",
|
||||
"setupMigrationDesc": "यदि आप अपने पिछले wg-easy संस्करण से डेटा माइग्रेट करना चाहते हैं तो कृपया बैकअप फ़ाइल प्रदान करें।",
|
||||
"upload": "अपलोड",
|
||||
"migration": "बैकअप से पुनर्स्थापित करें:",
|
||||
"createAccount": "खाता बनाएं",
|
||||
"successful": "सेटअप सफल रहा",
|
||||
"hostDesc": "सार्वजनिक होस्टनाम जिससे क्लाइंट कनेक्ट होंगे",
|
||||
"portDesc": "सार्वजनिक UDP पोर्ट जिससे क्लाइंट कनेक्ट होंगे और WireGuard सुनेगा"
|
||||
},
|
||||
"update": {
|
||||
"updateAvailable": "एक अपडेट उपलब्ध है!",
|
||||
"update": "अपडेट करें"
|
||||
},
|
||||
"theme": {
|
||||
"dark": "डार्क थीम",
|
||||
"light": "लाइट थीम",
|
||||
"system": "सिस्टम थीम"
|
||||
},
|
||||
"layout": {
|
||||
"toggleCharts": "चार्ट दिखाएं/छिपाएं",
|
||||
"donate": "दान करें"
|
||||
},
|
||||
"login": {
|
||||
"signIn": "साइन इन",
|
||||
"rememberMe": "मुझे याद रखें",
|
||||
"rememberMeDesc": "ब्राउज़र बंद करने के बाद भी लॉग इन रहें",
|
||||
"insecure": "आप असुरक्षित कनेक्शन से लॉग इन नहीं कर सकते। HTTPS का उपयोग करें।",
|
||||
"2faRequired": "दो-कारक प्रमाणीकरण आवश्यक है",
|
||||
"2faWrong": "दो-कारक प्रमाणीकरण गलत है"
|
||||
},
|
||||
"client": {
|
||||
"empty": "अभी तक कोई क्लाइंट नहीं है।",
|
||||
"newShort": "नया",
|
||||
"sort": "क्रमबद्ध करें",
|
||||
"create": "क्लाइंट बनाएं",
|
||||
"created": "क्लाइंट बनाया गया",
|
||||
"new": "नया क्लाइंट",
|
||||
"name": "नाम",
|
||||
"expireDate": "समाप्ति तिथि",
|
||||
"expireDateDesc": "वह तिथि जिसके बाद क्लाइंट अक्षम हो जाएगा। स्थायी के लिए खाली छोड़ें",
|
||||
"delete": "हटाएं",
|
||||
"deleteClient": "क्लाइंट हटाएं",
|
||||
"deleteDialog1": "क्या आप वाकई हटाना चाहते हैं",
|
||||
"deleteDialog2": "यह क्रिया पूर्ववत नहीं की जा सकती।",
|
||||
"enabled": "सक्षम",
|
||||
"address": "पता",
|
||||
"serverAllowedIps": "सर्वर द्वारा अनुमत IPs",
|
||||
"otlDesc": "छोटा एकबारगी लिंक उत्पन्न करें",
|
||||
"permanent": "स्थायी",
|
||||
"createdOn": "बनाया गया ",
|
||||
"lastSeen": "अंतिम बार देखा गया ",
|
||||
"totalDownload": "कुल डाउनलोड: ",
|
||||
"totalUpload": "कुल अपलोड: ",
|
||||
"newClient": "नया क्लाइंट",
|
||||
"disableClient": "क्लाइंट अक्षम करें",
|
||||
"enableClient": "क्लाइंट सक्षम करें",
|
||||
"noPrivKey": "इस क्लाइंट की कोई ज्ञात निजी कुंजी नहीं है। कॉन्फ़िगरेशन नहीं बना सकते।",
|
||||
"showQR": "QR कोड दिखाएं",
|
||||
"downloadConfig": "कॉन्फ़िगरेशन डाउनलोड करें",
|
||||
"allowedIpsDesc": "कौन से IPs VPN के माध्यम से रूट होंगे (वैश्विक कॉन्फ़िगरेशन को ओवरराइड करता है)",
|
||||
"serverAllowedIpsDesc": "कौन से IPs सर्वर क्लाइंट को रूट करेगा",
|
||||
"mtuDesc": "VPN टनल के लिए अधिकतम ट्रांसमिशन इकाई (पैकेट आकार) सेट करता है",
|
||||
"persistentKeepaliveDesc": "कीप-अलाइव पैकेट के लिए अंतराल (सेकंड में) सेट करता है। 0 इसे अक्षम करता है",
|
||||
"hooks": "हुक्स",
|
||||
"hooksDescription": "हुक्स केवल wg-quick के साथ काम करते हैं",
|
||||
"hooksLeaveEmpty": "केवल wg-quick के लिए। अन्यथा, खाली छोड़ें",
|
||||
"dnsDesc": "DNS सर्वर जिसे क्लाइंट उपयोग करेंगे (वैश्विक कॉन्फ़िगरेशन को ओवरराइड करता है)",
|
||||
"notConnected": "क्लाइंट कनेक्ट नहीं है",
|
||||
"endpoint": "एंडपॉइंट",
|
||||
"endpointDesc": "क्लाइंट का IP पता जहाँ से WireGuard कनेक्शन स्थापित होता है",
|
||||
"search": "क्लाइंट खोजें...",
|
||||
"config": "कॉन्फ़िगरेशन",
|
||||
"viewConfig": "कॉन्फ़िगरेशन देखें",
|
||||
"firewallIps": "फ़ायरवॉल द्वारा अनुमत IPs",
|
||||
"firewallIpsDesc": "गंतव्य IPs/CIDRs जिन तक यह क्लाइंट पहुँच सकता है (सर्वर-साइड नियंत्रण)। अनुमत IPs उपयोग करने के लिए खाली छोड़ें। वैकल्पिक पोर्ट और प्रोटोकॉल फ़िल्टरिंग का समर्थन करता है। सिंटैक्स के लिए दस्तावेज़ देखें।",
|
||||
"downloadPng": "PNG डाउनलोड करें",
|
||||
"copyPng": "PNG कॉपी करें"
|
||||
},
|
||||
"dialog": {
|
||||
"change": "बदलें",
|
||||
"cancel": "रद्द करें",
|
||||
"create": "बनाएं"
|
||||
},
|
||||
"toast": {
|
||||
"success": "सफल",
|
||||
"saved": "सहेजा गया",
|
||||
"error": "त्रुटि",
|
||||
"unknown": "अज्ञात त्रुटि। अधिक जानकारी के लिए कंसोल देखें"
|
||||
},
|
||||
"form": {
|
||||
"actions": "क्रियाएं",
|
||||
"save": "सहेजें",
|
||||
"revert": "पूर्ववत करें",
|
||||
"sectionGeneral": "सामान्य",
|
||||
"sectionAdvanced": "उन्नत",
|
||||
"noItems": "कोई आइटम नहीं",
|
||||
"nullNoItems": "कोई आइटम नहीं। वैश्विक कॉन्फ़िगरेशन उपयोग में है",
|
||||
"add": "जोड़ें"
|
||||
},
|
||||
"admin": {
|
||||
"general": {
|
||||
"sessionTimeout": "सत्र समय समाप्ति",
|
||||
"sessionTimeoutDesc": "रिमेम्बर मी के लिए सत्र अवधि (सेकंड में)",
|
||||
"metrics": "मेट्रिक्स",
|
||||
"metricsPassword": "पासवर्ड",
|
||||
"metricsPasswordDesc": "मेट्रिक्स एंडपॉइंट के लिए बियरर पासवर्ड (पासवर्ड या argon2 हैश)",
|
||||
"json": "JSON",
|
||||
"jsonDesc": "JSON फ़ॉर्मेट में मेट्रिक्स का मार्ग",
|
||||
"prometheus": "Prometheus",
|
||||
"prometheusDesc": "Prometheus मेट्रिक्स का मार्ग"
|
||||
},
|
||||
"config": {
|
||||
"connection": "कनेक्शन",
|
||||
"hostDesc": "सार्वजनिक होस्टनाम जिससे क्लाइंट कनेक्ट होंगे (कॉन्फ़िगरेशन को अमान्य करता है)",
|
||||
"portDesc": "सार्वजनिक UDP पोर्ट जिससे क्लाइंट कनेक्ट होंगे (कॉन्फ़िगरेशन को अमान्य करता है, शायद आप इंटरफ़ेस पोर्ट भी बदलना चाहें)",
|
||||
"allowedIpsDesc": "क्लाइंट द्वारा उपयोग किए जाने वाले अनुमत IPs (वैश्विक कॉन्फ़िगरेशन)",
|
||||
"dnsDesc": "क्लाइंट द्वारा उपयोग किया जाने वाला DNS सर्वर (वैश्विक कॉन्फ़िगरेशन)",
|
||||
"mtuDesc": "क्लाइंट द्वारा उपयोग किया जाने वाला MTU (केवल नए क्लाइंट के लिए)",
|
||||
"persistentKeepaliveDesc": "सर्वर को कीपअलाइव भेजने का अंतराल सेकंड में। 0 = अक्षम (केवल नए क्लाइंट के लिए)",
|
||||
"suggest": "सुझाएं",
|
||||
"suggestDesc": "होस्ट फ़ील्ड के लिए IP पता या होस्टनाम चुनें"
|
||||
},
|
||||
"interface": {
|
||||
"cidrSuccess": "CIDR बदला गया",
|
||||
"device": "डिवाइस",
|
||||
"deviceDesc": "ईथरनेट डिवाइस जिसके माध्यम से WireGuard ट्रैफ़िक फ़ॉरवर्ड किया जाना चाहिए",
|
||||
"mtuDesc": "MTU जिसे WireGuard उपयोग करेगा",
|
||||
"portDesc": "UDP पोर्ट जिस पर WireGuard सुनेगा (शायद आप कॉन्फ़िग पोर्ट भी बदलना चाहें)",
|
||||
"changeCidr": "CIDR बदलें",
|
||||
"restart": "इंटरफ़ेस रीस्टार्ट करें",
|
||||
"restartDesc": "WireGuard इंटरफ़ेस को रीस्टार्ट करें",
|
||||
"restartWarn": "क्या आप वाकई इंटरफ़ेस रीस्टार्ट करना चाहते हैं? इससे सभी क्लाइंट डिस्कनेक्ट हो जाएंगे।",
|
||||
"restartSuccess": "इंटरफ़ेस रीस्टार्ट हो गया",
|
||||
"firewall": "ट्रैफ़िक फ़िल्टरिंग",
|
||||
"firewallEnabled": "प्रति-क्लाइंट फ़ायरवॉल सक्षम करें",
|
||||
"firewallEnabledDesc": "iptables का उपयोग करके क्लाइंट ट्रैफ़िक को विशिष्ट गंतव्य IPs तक सीमित करें। सक्षम होने पर, प्रत्येक क्लाइंट को अनुमत गंतव्यों के साथ कॉन्फ़िगर किया जा सकता है।"
|
||||
},
|
||||
"introText": "एडमिन पैनल में आपका स्वागत है।\n\nयहाँ आप सामान्य सेटिंग्स, कॉन्फ़िगरेशन, इंटरफ़ेस सेटिंग्स और हुक्स प्रबंधित कर सकते हैं।\n\nसाइडबार में किसी एक अनुभाग को चुनकर शुरू करें।"
|
||||
},
|
||||
"zod": {
|
||||
"generic": {
|
||||
"required": "{0} आवश्यक है",
|
||||
"validNumber": "{0} एक वैध संख्या होनी चाहिए",
|
||||
"validNumberRange": "{0} एक वैध संख्या या संख्या श्रेणी होनी चाहिए",
|
||||
"validString": "{0} एक वैध स्ट्रिंग होनी चाहिए",
|
||||
"validBoolean": "{0} एक वैध बूलियन होना चाहिए",
|
||||
"validArray": "{0} एक वैध ऐरे होना चाहिए",
|
||||
"stringMin": "{0} कम से कम {1} अक्षर का होना चाहिए",
|
||||
"numberMin": "{0} कम से कम {1} होना चाहिए"
|
||||
},
|
||||
"client": {
|
||||
"id": "क्लाइंट ID",
|
||||
"name": "नाम",
|
||||
"expiresAt": "समाप्ति तिथि",
|
||||
"address4": "IPv4 पता",
|
||||
"address6": "IPv6 पता",
|
||||
"serverAllowedIps": "सर्वर द्वारा अनुमत IPs",
|
||||
"firewallIps": "फ़ायरवॉल द्वारा अनुमत IPs",
|
||||
"firewallIpsInvalid": "अमान्य फ़ायरवॉल IP प्रविष्टि। समर्थित सिंटैक्स के लिए दस्तावेज़ देखें।"
|
||||
},
|
||||
"user": {
|
||||
"username": "उपयोगकर्ता नाम",
|
||||
"password": "पासवर्ड",
|
||||
"remember": "याद रखें",
|
||||
"name": "नाम",
|
||||
"email": "ई-मेल",
|
||||
"emailInvalid": "ई-मेल एक वैध ईमेल होनी चाहिए",
|
||||
"passwordMatch": "पासवर्ड मेल खाने चाहिए",
|
||||
"totpEnable": "TOTP सक्षम करें",
|
||||
"totpEnableTrue": "TOTP सक्षम सत्य होना चाहिए",
|
||||
"totpCode": "TOTP कोड"
|
||||
},
|
||||
"userConfig": {
|
||||
"host": "होस्ट"
|
||||
},
|
||||
"general": {
|
||||
"sessionTimeout": "सत्र समय समाप्ति",
|
||||
"metricsEnabled": "मेट्रिक्स",
|
||||
"metricsPassword": "मेट्रिक्स पासवर्ड"
|
||||
},
|
||||
"interface": {
|
||||
"cidr": "CIDR",
|
||||
"device": "डिवाइस",
|
||||
"cidrValid": "CIDR वैध होना चाहिए"
|
||||
},
|
||||
"otl": "एकबारगी लिंक",
|
||||
"stringMalformed": "स्ट्रिंग विकृत है",
|
||||
"body": "बॉडी एक वैध ऑब्जेक्ट होनी चाहिए",
|
||||
"hook": "हुक",
|
||||
"enabled": "सक्षम",
|
||||
"mtu": "MTU",
|
||||
"port": "पोर्ट",
|
||||
"persistentKeepalive": "स्थायी कीपअलाइव",
|
||||
"address": "IP पता",
|
||||
"dns": "DNS",
|
||||
"allowedIps": "अनुमत IPs",
|
||||
"file": "फ़ाइल"
|
||||
},
|
||||
"hooks": {
|
||||
"preUp": "PreUp",
|
||||
"postUp": "PostUp",
|
||||
"preDown": "PreDown",
|
||||
"postDown": "PostDown"
|
||||
},
|
||||
"copy": {
|
||||
"notSupported": "कॉपी समर्थित नहीं है",
|
||||
"copied": "कॉपी हो गया!",
|
||||
"failed": "कॉपी विफल रहा",
|
||||
"copy": "कॉपी करें"
|
||||
},
|
||||
"awg": {
|
||||
"jCLabel": "जंक पैकेट गणना (Jc)",
|
||||
"jCDescription": "भेजे जाने वाले जंक पैकेट की संख्या (1-128, अनुशंसित: 4-12)",
|
||||
"jMinLabel": "जंक पैकेट न्यूनतम आकार (Jmin)",
|
||||
"jMinDescription": "जंक पैकेट का न्यूनतम आकार (0-1279*, अनुशंसित: 8, Jmax से कम होना चाहिए)",
|
||||
"jMaxLabel": "जंक पैकेट अधिकतम आकार (Jmax)",
|
||||
"jMaxDescription": "जंक पैकेट का अधिकतम आकार (1-1280*, अनुशंसित: 80, Jmin से अधिक होना चाहिए)",
|
||||
"s1Label": "इनिट पैकेट जंक आकार (S1)",
|
||||
"s1Description": "इनिट पैकेट जंक आकार (0-1132[1280* - 148 = 1132], अनुशंसित: 15-150, S1+56 ≠ S2)",
|
||||
"s2Label": "रिस्पॉन्स पैकेट जंक आकार (S2)",
|
||||
"s2Description": "रिस्पॉन्स पैकेट जंक आकार (0-1188[1280* - 92 = 1188], अनुशंसित: 15-150)",
|
||||
"s3Label": "कुकी रिप्लाई पैकेट जंक आकार (S3)",
|
||||
"s3Description": "कुकी रिप्लाई पैकेट जंक आकार",
|
||||
"s4Label": "ट्रांसपोर्ट पैकेट जंक आकार (S4)",
|
||||
"s4Description": "ट्रांसपोर्ट पैकेट जंक आकार",
|
||||
"h1Label": "इनिट मैजिक हेडर (H1)",
|
||||
"h1Description": "इनिट पैकेट हेडर मान या श्रेणी (X या X-Y, जहाँ X<Y। न्यूनतम 5, अधिकतम 2147483647। मान या श्रेणी अन्य हेडर से ओवरलैप नहीं होनी चाहिए)",
|
||||
"h2Label": "रिस्पॉन्स मैजिक हेडर (H2)",
|
||||
"h2Description": "रिस्पॉन्स पैकेट हेडर मान या श्रेणी (X या X-Y, जहाँ X<Y। न्यूनतम 5, अधिकतम 2147483647। मान या श्रेणी अन्य हेडर से ओवरलैप नहीं होनी चाहिए)",
|
||||
"h3Label": "कुकी रिप्लाई मैजिक हेडर (H3)",
|
||||
"h3Description": "कुकी रिप्लाई पैकेट हेडर मान या श्रेणी (X या X-Y, जहाँ X<Y। न्यूनतम 5, अधिकतम 2147483647। मान या श्रेणी अन्य हेडर से ओवरलैप नहीं होनी चाहिए)",
|
||||
"h4Label": "ट्रांसपोर्ट मैजिक हेडर (H4)",
|
||||
"h4Description": "ट्रांसपोर्ट पैकेट हेडर मान या श्रेणी (X या X-Y, जहाँ X<Y। न्यूनतम 5, अधिकतम 2147483647। मान या श्रेणी अन्य हेडर से ओवरलैप नहीं होनी चाहिए)",
|
||||
"i1Label": "विशेष जंक पैकेट 1 (I1)",
|
||||
"i1Description": "hex फ़ॉर्मेट में प्रोटोकॉल मिमिक पैकेट: <b 0x...>",
|
||||
"i2Label": "विशेष जंक पैकेट 2 (I2)",
|
||||
"i2Description": "hex फ़ॉर्मेट में प्रोटोकॉल मिमिक पैकेट: <b 0x...>",
|
||||
"i3Label": "विशेष जंक पैकेट 3 (I3)",
|
||||
"i3Description": "hex फ़ॉर्मेट में प्रोटोकॉल मिमिक पैकेट: <b 0x...>",
|
||||
"i4Label": "विशेष जंक पैकेट 4 (I4)",
|
||||
"i4Description": "hex फ़ॉर्मेट में प्रोटोकॉल मिमिक पैकेट: <b 0x...>",
|
||||
"i5Label": "विशेष जंक पैकेट 5 (I5)",
|
||||
"i5Description": "hex फ़ॉर्मेट में प्रोटोकॉल मिमिक पैकेट: <b 0x...>",
|
||||
"mtuNote": "मान MTU पर निर्भर करते हैं",
|
||||
"obfuscationParameters": "AmneziaWG ऑबफस्केशन पैरामीटर"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,297 @@
|
||||
{
|
||||
"pages": {
|
||||
"me": "アカウント",
|
||||
"clients": "クライアント",
|
||||
"admin": {
|
||||
"panel": "管理パネル",
|
||||
"general": "一般",
|
||||
"config": "構成",
|
||||
"interface": "インターフェイス",
|
||||
"hooks": "フック"
|
||||
}
|
||||
},
|
||||
"user": {
|
||||
"email": "メール"
|
||||
},
|
||||
"me": {
|
||||
"currentPassword": "現在のパスワード",
|
||||
"enable2fa": "二要素認証を有効化",
|
||||
"enable2faDesc": "QRコードを認証アプリでスキャンするか、キーを手動で入力してください。",
|
||||
"2faKey": "TOTPキー",
|
||||
"2faCodeDesc": "認証アプリのコードを入力してください。",
|
||||
"disable2fa": "二要素認証を無効化",
|
||||
"disable2faDesc": "二要素認証を無効にするにはパスワードを入力してください。"
|
||||
},
|
||||
"general": {
|
||||
"name": "名前",
|
||||
"username": "ユーザー名",
|
||||
"password": "パスワード",
|
||||
"newPassword": "新しいパスワード",
|
||||
"updatePassword": "パスワードを更新",
|
||||
"mtu": "MTU",
|
||||
"allowedIps": "許可 IP",
|
||||
"dns": "DNS",
|
||||
"persistentKeepalive": "永続的 Keepalive",
|
||||
"logout": "ログアウト",
|
||||
"continue": "続行",
|
||||
"host": "ホスト",
|
||||
"port": "ポート",
|
||||
"yes": "はい",
|
||||
"no": "いいえ",
|
||||
"confirmPassword": "パスワードの確認",
|
||||
"loading": "読み込み中...",
|
||||
"2fa": "二要素認証",
|
||||
"2faCode": "TOTPコード"
|
||||
},
|
||||
"setup": {
|
||||
"welcome": "wg-easy の初期セットアップへようこそ",
|
||||
"welcomeDesc": "Linux ホストで WireGuard をインストールして管理する最も簡単な方法です",
|
||||
"existingSetup": "既存のセットアップがありますか?",
|
||||
"createAdminDesc": "まず管理者ユーザー名と強力で安全なパスワードを入力してください。この情報は管理パネルへのログインに使用されます。",
|
||||
"setupConfigDesc": "ホストとポート情報を入力してください。これは各デバイスで WireGuard を設定するときのクライアント構成に使用されます。",
|
||||
"setupMigrationDesc": "新しいセットアップへ以前の wg-easy バージョンからデータを移行する場合は、バックアップファイルを指定してください。",
|
||||
"upload": "アップロード",
|
||||
"migration": "バックアップを復元:",
|
||||
"createAccount": "アカウントを作成",
|
||||
"successful": "セットアップが完了しました",
|
||||
"hostDesc": "クライアントが接続する公開ホスト名",
|
||||
"portDesc": "クライアントが接続し、WireGuard が待ち受ける公開 UDP ポート"
|
||||
},
|
||||
"update": {
|
||||
"updateAvailable": "利用可能な更新があります!",
|
||||
"update": "更新"
|
||||
},
|
||||
"theme": {
|
||||
"dark": "ダークテーマ",
|
||||
"light": "ライトテーマ",
|
||||
"system": "システムテーマ"
|
||||
},
|
||||
"layout": {
|
||||
"toggleCharts": "グラフの表示/非表示",
|
||||
"donate": "寄付"
|
||||
},
|
||||
"login": {
|
||||
"signIn": "サインイン",
|
||||
"rememberMe": "ログイン状態を保持",
|
||||
"rememberMeDesc": "ブラウザーを閉じた後もログイン状態を保持します",
|
||||
"insecure": "安全でない接続ではログインできません。HTTPS を使用してください。",
|
||||
"2faRequired": "二要素認証が必要です",
|
||||
"2faWrong": "二要素認証が正しくありません"
|
||||
},
|
||||
"client": {
|
||||
"empty": "まだクライアントはありません。",
|
||||
"newShort": "新規",
|
||||
"sort": "並べ替え",
|
||||
"create": "クライアントを作成",
|
||||
"created": "クライアントを作成しました",
|
||||
"new": "新しいクライアント",
|
||||
"name": "名前",
|
||||
"expireDate": "有効期限",
|
||||
"expireDateDesc": "この日にクライアントが無効化されます。空欄の場合は無期限です",
|
||||
"delete": "削除",
|
||||
"deleteClient": "クライアントを削除",
|
||||
"deleteDialog1": "削除してもよろしいですか",
|
||||
"deleteDialog2": "この操作は元に戻せません。",
|
||||
"enabled": "有効",
|
||||
"address": "アドレス",
|
||||
"serverAllowedIps": "サーバー許可 IP",
|
||||
"otlDesc": "短いワンタイムリンクを生成",
|
||||
"permanent": "無期限",
|
||||
"createdOn": "作成日: ",
|
||||
"lastSeen": "最終接続: ",
|
||||
"totalDownload": "総ダウンロード: ",
|
||||
"totalUpload": "総アップロード: ",
|
||||
"newClient": "新しいクライアント",
|
||||
"disableClient": "クライアントを無効化",
|
||||
"enableClient": "クライアントを有効化",
|
||||
"noPrivKey": "このクライアントの秘密鍵は不明です。構成を作成できません。",
|
||||
"showQR": "QRコードを表示",
|
||||
"downloadConfig": "構成をダウンロード",
|
||||
"allowedIpsDesc": "VPN 経由でルーティングされる IP (グローバル設定を上書き)",
|
||||
"serverAllowedIpsDesc": "サーバーがこのクライアントへルーティングする IP",
|
||||
"mtuDesc": "VPN トンネルの最大転送単位 (パケットサイズ) を設定します",
|
||||
"persistentKeepaliveDesc": "Keepalive パケットを送信する間隔 (秒) を設定します。0 で無効化します",
|
||||
"hooks": "フック",
|
||||
"hooksDescription": "フックは wg-quick でのみ動作します",
|
||||
"hooksLeaveEmpty": "wg-quick 専用です。それ以外の場合は空のままにしてください",
|
||||
"dnsDesc": "クライアントが使用する DNS サーバー (グローバル設定を上書き)",
|
||||
"notConnected": "クライアントは接続されていません",
|
||||
"endpoint": "エンドポイント",
|
||||
"endpointDesc": "WireGuard 接続が確立されているクライアントの IP",
|
||||
"search": "クライアントを検索...",
|
||||
"config": "構成",
|
||||
"viewConfig": "構成を表示",
|
||||
"firewallIps": "ファイアウォール許可 IP",
|
||||
"firewallIpsDesc": "このクライアントがアクセスできる宛先 IP/CIDR (サーバー側で強制)。空欄の場合は Allowed IPs を使用します。任意のポートとプロトコルによるフィルタリングに対応しています。構文はドキュメントを参照してください。",
|
||||
"downloadPng": "PNG をダウンロード",
|
||||
"copyPng": "PNG をコピー"
|
||||
},
|
||||
"dialog": {
|
||||
"change": "変更",
|
||||
"cancel": "キャンセル",
|
||||
"create": "作成"
|
||||
},
|
||||
"toast": {
|
||||
"success": "成功",
|
||||
"saved": "保存しました",
|
||||
"error": "エラー",
|
||||
"unknown": "不明なエラーです。詳細はコンソールを確認してください"
|
||||
},
|
||||
"form": {
|
||||
"actions": "アクション",
|
||||
"save": "保存",
|
||||
"revert": "元に戻す",
|
||||
"sectionGeneral": "一般",
|
||||
"sectionAdvanced": "詳細",
|
||||
"noItems": "項目なし",
|
||||
"nullNoItems": "項目なし。グローバル設定を使用しています",
|
||||
"add": "追加"
|
||||
},
|
||||
"admin": {
|
||||
"general": {
|
||||
"sessionTimeout": "セッションタイムアウト",
|
||||
"sessionTimeoutDesc": "ログイン状態を保持する場合のセッション期間 (秒)",
|
||||
"metrics": "メトリクス",
|
||||
"metricsPassword": "パスワード",
|
||||
"metricsPasswordDesc": "メトリクスエンドポイント用の Bearer パスワード (パスワードまたは argon2 ハッシュ)",
|
||||
"json": "JSON",
|
||||
"jsonDesc": "JSON 形式のメトリクスルート",
|
||||
"prometheus": "Prometheus",
|
||||
"prometheusDesc": "Prometheus メトリクスのルート"
|
||||
},
|
||||
"config": {
|
||||
"connection": "接続",
|
||||
"hostDesc": "クライアントが接続する公開ホスト名 (構成が無効化されます)",
|
||||
"portDesc": "クライアントが接続する公開 UDP ポート (構成が無効化されます。通常はインターフェイスのポートも変更します)",
|
||||
"allowedIpsDesc": "クライアントが使用する許可 IP (グローバル設定)",
|
||||
"dnsDesc": "クライアントが使用する DNS サーバー (グローバル設定)",
|
||||
"mtuDesc": "クライアントが使用する MTU (新規クライアントのみ)",
|
||||
"persistentKeepaliveDesc": "サーバーへ Keepalive を送信する間隔 (秒)。0 = 無効 (新規クライアントのみ)",
|
||||
"suggest": "候補",
|
||||
"suggestDesc": "ホスト欄に使用する IP アドレスまたはホスト名を選択してください"
|
||||
},
|
||||
"interface": {
|
||||
"cidrSuccess": "CIDR を変更しました",
|
||||
"device": "デバイス",
|
||||
"deviceDesc": "WireGuard トラフィックを転送する Ethernet デバイス",
|
||||
"mtuDesc": "WireGuard が使用する MTU",
|
||||
"portDesc": "WireGuard が待ち受ける UDP ポート (通常は構成ポートも変更します)",
|
||||
"changeCidr": "CIDR を変更",
|
||||
"restart": "インターフェイスを再起動",
|
||||
"restartDesc": "WireGuard インターフェイスを再起動します",
|
||||
"restartWarn": "インターフェイスを再起動してもよろしいですか?すべてのクライアントが切断されます。",
|
||||
"restartSuccess": "インターフェイスを再起動しました",
|
||||
"firewall": "トラフィックフィルタリング",
|
||||
"firewallEnabled": "クライアントごとのファイアウォールを有効化",
|
||||
"firewallEnabledDesc": "iptables を使用して、クライアントのトラフィックを特定の宛先 IP に制限します。有効にすると、クライアントごとに許可する宛先を設定できます。"
|
||||
},
|
||||
"introText": "管理パネルへようこそ。\n\nここでは一般設定、構成、インターフェイス設定、フックを管理できます。\n\nまずサイドバーからセクションを選択してください。"
|
||||
},
|
||||
"zod": {
|
||||
"generic": {
|
||||
"required": "{0} は必須です",
|
||||
"validNumber": "{0} は有効な数値である必要があります",
|
||||
"validNumberRange": "{0} は有効な数値または数値範囲である必要があります",
|
||||
"validString": "{0} は有効な文字列である必要があります",
|
||||
"validBoolean": "{0} は有効な真偽値である必要があります",
|
||||
"validArray": "{0} は有効な配列である必要があります",
|
||||
"stringMin": "{0} は {1} 文字以上である必要があります",
|
||||
"numberMin": "{0} は {1} 以上である必要があります"
|
||||
},
|
||||
"client": {
|
||||
"id": "クライアント ID",
|
||||
"name": "名前",
|
||||
"expiresAt": "有効期限",
|
||||
"address4": "IPv4 アドレス",
|
||||
"address6": "IPv6 アドレス",
|
||||
"serverAllowedIps": "サーバー許可 IP",
|
||||
"firewallIps": "ファイアウォール許可 IP",
|
||||
"firewallIpsInvalid": "ファイアウォール IP の指定が無効です。対応している構文はドキュメントを参照してください。"
|
||||
},
|
||||
"user": {
|
||||
"username": "ユーザー名",
|
||||
"password": "パスワード",
|
||||
"remember": "ログイン状態を保持",
|
||||
"name": "名前",
|
||||
"email": "メール",
|
||||
"emailInvalid": "メールは有効なメールアドレスである必要があります",
|
||||
"passwordMatch": "パスワードが一致しません",
|
||||
"totpEnable": "TOTP 有効化",
|
||||
"totpEnableTrue": "TOTP 有効化は true である必要があります",
|
||||
"totpCode": "TOTPコード"
|
||||
},
|
||||
"userConfig": {
|
||||
"host": "ホスト"
|
||||
},
|
||||
"general": {
|
||||
"sessionTimeout": "セッションタイムアウト",
|
||||
"metricsEnabled": "メトリクス",
|
||||
"metricsPassword": "メトリクスパスワード"
|
||||
},
|
||||
"interface": {
|
||||
"cidr": "CIDR",
|
||||
"device": "デバイス",
|
||||
"cidrValid": "CIDR は有効である必要があります"
|
||||
},
|
||||
"otl": "ワンタイムリンク",
|
||||
"stringMalformed": "文字列の形式が正しくありません",
|
||||
"body": "本文は有効なオブジェクトである必要があります",
|
||||
"hook": "フック",
|
||||
"enabled": "有効",
|
||||
"mtu": "MTU",
|
||||
"port": "ポート",
|
||||
"persistentKeepalive": "永続的 Keepalive",
|
||||
"address": "IP アドレス",
|
||||
"dns": "DNS",
|
||||
"allowedIps": "許可 IP",
|
||||
"file": "ファイル"
|
||||
},
|
||||
"hooks": {
|
||||
"preUp": "PreUp",
|
||||
"postUp": "PostUp",
|
||||
"preDown": "PreDown",
|
||||
"postDown": "PostDown"
|
||||
},
|
||||
"copy": {
|
||||
"notSupported": "コピーはサポートされていません",
|
||||
"copied": "コピーしました!",
|
||||
"failed": "コピーに失敗しました",
|
||||
"copy": "コピー"
|
||||
},
|
||||
"awg": {
|
||||
"jCLabel": "ジャンクパケット数 (Jc)",
|
||||
"jCDescription": "送信するジャンクパケット数 (1-128、推奨: 4-12)",
|
||||
"jMinLabel": "ジャンクパケット最小サイズ (Jmin)",
|
||||
"jMinDescription": "ジャンクパケットの最小サイズ (0-1279*、推奨: 8、Jmax 未満)",
|
||||
"jMaxLabel": "ジャンクパケット最大サイズ (Jmax)",
|
||||
"jMaxDescription": "ジャンクパケットの最大サイズ (1-1280*、推奨: 80、Jmin より大きい)",
|
||||
"s1Label": "初期化パケットのジャンクサイズ (S1)",
|
||||
"s1Description": "初期化パケットのジャンクサイズ (0-1132[1280* - 148 = 1132]、推奨: 15-150、S1+56 ≠ S2)",
|
||||
"s2Label": "応答パケットのジャンクサイズ (S2)",
|
||||
"s2Description": "応答パケットのジャンクサイズ (0-1188[1280* - 92 = 1188]、推奨: 15-150)",
|
||||
"s3Label": "Cookie 応答パケットのジャンクサイズ (S3)",
|
||||
"s3Description": "Cookie 応答パケットのジャンクサイズ",
|
||||
"s4Label": "トランスポートパケットのジャンクサイズ (S4)",
|
||||
"s4Description": "トランスポートパケットのジャンクサイズ",
|
||||
"h1Label": "初期化マジックヘッダー (H1)",
|
||||
"h1Description": "初期化パケットのヘッダー値または範囲 (X または X-Y、X<Y。最小 5、最大 2147483647。値または範囲は他のヘッダーと重複してはいけません)",
|
||||
"h2Label": "応答マジックヘッダー (H2)",
|
||||
"h2Description": "応答パケットのヘッダー値または範囲 (X または X-Y、X<Y。最小 5、最大 2147483647。値または範囲は他のヘッダーと重複してはいけません)",
|
||||
"h3Label": "Cookie 応答マジックヘッダー (H3)",
|
||||
"h3Description": "Cookie 応答パケットのヘッダー値または範囲 (X または X-Y、X<Y。最小 5、最大 2147483647。値または範囲は他のヘッダーと重複してはいけません)",
|
||||
"h4Label": "トランスポートマジックヘッダー (H4)",
|
||||
"h4Description": "トランスポートパケットのヘッダー値または範囲 (X または X-Y、X<Y。最小 5、最大 2147483647。値または範囲は他のヘッダーと重複してはいけません)",
|
||||
"i1Label": "特殊ジャンクパケット 1 (I1)",
|
||||
"i1Description": "16進数形式のプロトコル模倣パケット: <b 0x...>",
|
||||
"i2Label": "特殊ジャンクパケット 2 (I2)",
|
||||
"i2Description": "16進数形式のプロトコル模倣パケット: <b 0x...>",
|
||||
"i3Label": "特殊ジャンクパケット 3 (I3)",
|
||||
"i3Description": "16進数形式のプロトコル模倣パケット: <b 0x...>",
|
||||
"i4Label": "特殊ジャンクパケット 4 (I4)",
|
||||
"i4Description": "16進数形式のプロトコル模倣パケット: <b 0x...>",
|
||||
"i5Label": "特殊ジャンクパケット 5 (I5)",
|
||||
"i5Description": "16進数形式のプロトコル模倣パケット: <b 0x...>",
|
||||
"mtuNote": "値は MTU に依存します",
|
||||
"obfuscationParameters": "AmneziaWG 難読化パラメーター"
|
||||
}
|
||||
}
|
||||
+122
-65
@@ -1,9 +1,9 @@
|
||||
{
|
||||
"pages": {
|
||||
"me": "Konto",
|
||||
"clients": "Konta",
|
||||
"clients": "Klienci",
|
||||
"admin": {
|
||||
"panel": "Panel administracyjny",
|
||||
"panel": "Panel administratora",
|
||||
"general": "Ogólne",
|
||||
"config": "Konfiguracja",
|
||||
"interface": "Interfejs",
|
||||
@@ -16,22 +16,22 @@
|
||||
"me": {
|
||||
"currentPassword": "Aktualne hasło",
|
||||
"enable2fa": "Włącz uwierzytelnianie dwuskładnikowe",
|
||||
"enable2faDesc": "Zeskanuj kod QR w aplikacji uwierzytelniającej lub wprowadź klucz ręcznie.",
|
||||
"enable2faDesc": "Zeskanuj kod QR aplikacją uwierzytelniającą lub wprowadź klucz ręcznie.",
|
||||
"2faKey": "Klucz TOTP",
|
||||
"2faCodeDesc": "Wprowadź kod z aplikacji uwierzytelniającej.",
|
||||
"disable2fa": "Wyłącz uwierzytelnianie dwuskładnikowe",
|
||||
"disable2faDesc": "Wprowadź swoje hasło, aby wyłączyć uwierzytelnianie dwuskładnikowe."
|
||||
"disable2faDesc": "Wprowadź hasło, aby wyłączyć uwierzytelnianie dwuskładnikowe."
|
||||
},
|
||||
"general": {
|
||||
"name": "Nazwa",
|
||||
"username": "Nazwa użytkownika",
|
||||
"password": "Hasło",
|
||||
"newPassword": "Nowe hasło",
|
||||
"updatePassword": "Zmień hasło",
|
||||
"updatePassword": "Aktualizuj hasło",
|
||||
"mtu": "MTU",
|
||||
"allowedIps": "Dozwolone adresy IP",
|
||||
"dns": "DNS",
|
||||
"persistentKeepalive": "Stałe utrzymywanie połączenia",
|
||||
"persistentKeepalive": "Utrzymywanie połączenia (Keepalive)",
|
||||
"logout": "Wyloguj",
|
||||
"continue": "Kontynuuj",
|
||||
"host": "Host",
|
||||
@@ -44,42 +44,42 @@
|
||||
"2faCode": "Kod TOTP"
|
||||
},
|
||||
"setup": {
|
||||
"welcome": "Witamy w pierwszej konfiguracji wg-easy",
|
||||
"welcomeDesc": "Znalazłeś najprostszy sposób na instalację i zarządzanie WireGuard na dowolnym serwerze Linux",
|
||||
"existingSetup": "Masz już istniejącą konfigurację?",
|
||||
"createAdminDesc": "Podaj nazwę użytkownika administratora oraz silne, bezpieczne hasło. Informacje te będą używane do logowania w panelu administracyjnym.",
|
||||
"setupConfigDesc": "Podaj informacje o hoście i porcie. Będą one używane w konfiguracji klienta podczas uruchamiania WireGuard na jego urządzeniach.",
|
||||
"setupMigrationDesc": "Podaj plik kopii zapasowej, jeśli chcesz przenieść dane ze starszej wersji wg-easy do nowej instalacji.",
|
||||
"welcome": "Witaj w pierwszej konfiguracji wg-easy",
|
||||
"welcomeDesc": "Znalazłeś najłatwiejszy sposób na instalację i zarządzanie WireGuard na dowolnym hoście Linux",
|
||||
"existingSetup": "Czy masz już istniejącą konfigurację?",
|
||||
"createAdminDesc": "Najpierw wprowadź nazwę użytkownika administratora i silne hasło. Dane te będą używane do logowania się do panelu administracyjnego.",
|
||||
"setupConfigDesc": "Wprowadź informacje o hoście i porcie. Zostaną one użyte do konfiguracji klientów podczas ustawiania WireGuard na ich urządzeniach.",
|
||||
"setupMigrationDesc": "Wskaż plik kopii zapasowej, jeśli chcesz przenieść dane z poprzedniej wersji wg-easy do nowej konfiguracji.",
|
||||
"upload": "Prześlij",
|
||||
"migration": "Przywróć kopię zapasową:",
|
||||
"createAccount": "Utwórz konto",
|
||||
"successful": "Konfiguracja zakończona sukcesem",
|
||||
"hostDesc": "Publiczny host, do którego będą łączyć się klienci",
|
||||
"portDesc": "Publiczny port UDP, na którym WireGuard będzie nasłuchiwał i do którego będą łączyć się klienci"
|
||||
"hostDesc": "Publiczna nazwa hosta, z którą będą łączyć się klienci",
|
||||
"portDesc": "Publiczny port UDP, na którym WireGuard będzie nasłuchiwać i z którym połączą się klienci"
|
||||
},
|
||||
"update": {
|
||||
"updateAvailable": "Dostępna jest aktualizacja!",
|
||||
"update": "Aktualizuj"
|
||||
},
|
||||
"theme": {
|
||||
"dark": "Motyw ciemny",
|
||||
"light": "Motyw jasny",
|
||||
"dark": "Ciemny motyw",
|
||||
"light": "Jasny motyw",
|
||||
"system": "Motyw systemowy"
|
||||
},
|
||||
"layout": {
|
||||
"toggleCharts": "Pokaż/ukryj wykresy",
|
||||
"donate": "Wesprzyj"
|
||||
"donate": "Dotacja"
|
||||
},
|
||||
"login": {
|
||||
"signIn": "Zaloguj się",
|
||||
"rememberMe": "Zapamiętaj mnie",
|
||||
"rememberMeDesc": "Pozostań zalogowany po zamknięciu przeglądarki",
|
||||
"insecure": "Nie możesz się zalogować przez niezabezpieczone połączenie. Użyj HTTPS.",
|
||||
"2faRequired": "Wymagane uwierzytelnianie dwuskładnikowe",
|
||||
"2faWrong": "Nieprawidłowy kod uwierzytelniania dwuskładnikowego"
|
||||
"insecure": "Nie możesz zalogować się przez niezabezpieczone połączenie. Użyj HTTPS.",
|
||||
"2faRequired": "Wymagane jest uwierzytelnianie dwuskładnikowe",
|
||||
"2faWrong": "Błędny kod uwierzytelniania dwuskładnikowego"
|
||||
},
|
||||
"client": {
|
||||
"empty": "Brak klientów.",
|
||||
"empty": "Nie ma jeszcze żadnych klientów.",
|
||||
"newShort": "Nowy",
|
||||
"sort": "Sortuj",
|
||||
"create": "Utwórz klienta",
|
||||
@@ -87,36 +87,44 @@
|
||||
"new": "Nowy klient",
|
||||
"name": "Nazwa",
|
||||
"expireDate": "Data wygaśnięcia",
|
||||
"expireDateDesc": "Data, po której klient zostanie wyłączony. Puste = na stałe",
|
||||
"expireDateDesc": "Data, w której klient zostanie wyłączony. Pozostaw puste dla bezterminowego dostępu",
|
||||
"delete": "Usuń",
|
||||
"deleteClient": "Usuń klienta",
|
||||
"deleteDialog1": "Czy na pewno chcesz usunąć",
|
||||
"deleteDialog2": "Tej akcji nie można cofnąć.",
|
||||
"deleteDialog1": "Czy na pewno chcesz usunąć klienta",
|
||||
"deleteDialog2": "Tej operacji nie można cofnąć.",
|
||||
"enabled": "Włączony",
|
||||
"address": "Adres",
|
||||
"serverAllowedIps": "Dozwolone adresy IP serwera",
|
||||
"otlDesc": "Wygeneruj jednorazowy krótki link",
|
||||
"otlDesc": "Generuj krótki link jednorazowy",
|
||||
"permanent": "Stały",
|
||||
"createdOn": "Utworzony ",
|
||||
"lastSeen": "Ostatnio widziany ",
|
||||
"totalDownload": "Łączne pobieranie: ",
|
||||
"totalUpload": "Łączne wysyłanie: ",
|
||||
"createdOn": "Utworzono: ",
|
||||
"lastSeen": "Ostatnio widziany: ",
|
||||
"totalDownload": "Pobieranie łącznie: ",
|
||||
"totalUpload": "Wysyłanie łącznie: ",
|
||||
"newClient": "Nowy klient",
|
||||
"disableClient": "Wyłącz klienta",
|
||||
"enableClient": "Włącz klienta",
|
||||
"noPrivKey": "Ten klient nie ma znanego klucza prywatnego. Nie można utworzyć konfiguracji.",
|
||||
"noPrivKey": "Ten klient nie posiada klucza prywatnego. Nie można utworzyć konfiguracji.",
|
||||
"showQR": "Pokaż kod QR",
|
||||
"downloadConfig": "Pobierz konfigurację",
|
||||
"allowedIpsDesc": "Które adresy IP będą kierowane przez VPN (nadpisuje konfigurację globalną)",
|
||||
"serverAllowedIpsDesc": "Które adresy IP serwer będzie kierował do klienta",
|
||||
"mtuDesc": "Ustawia maksymalny rozmiar pakietu (MTU) dla tunelu VPN",
|
||||
"persistentKeepaliveDesc": "Ustawia interwał (w sekundach) wysyłania pakietów keep-alive. 0 = wyłączone",
|
||||
"allowedIpsDesc": "Adresy IP kierowane przez VPN (nadpisuje konfigurację globalną)",
|
||||
"serverAllowedIpsDesc": "Adresy IP, które serwer będzie kierował do klienta",
|
||||
"mtuDesc": "Ustawia maksymalną jednostkę transmisji (rozmiar pakietu) dla tunelu VPN",
|
||||
"persistentKeepaliveDesc": "Ustawia interwał (w sekundach) dla pakietów utrzymujących połączenie. 0 wyłącza.",
|
||||
"hooks": "Hooki",
|
||||
"hooksDescription": "Hooki działają tylko z wg-quick",
|
||||
"hooksLeaveEmpty": "Tylko dla wg-quick. W innym przypadku pozostaw puste",
|
||||
"dnsDesc": "Serwer DNS, którego będą używać klienci (nadpisuje konfigurację globalną)",
|
||||
"notConnected": "Klient nie jest połączony",
|
||||
"hooksLeaveEmpty": "Tylko dla wg-quick. W przeciwnym razie pozostaw puste",
|
||||
"dnsDesc": "Serwer DNS dla klientów (nadpisuje konfigurację globalną)",
|
||||
"notConnected": "Klient niepołączony",
|
||||
"endpoint": "Punkt końcowy",
|
||||
"endpointDesc": "Adres IP klienta, z którego ustanawiane jest połączenie WireGuard"
|
||||
"endpointDesc": "Adres IP klienta, z którego ustanowiono połączenie WireGuard",
|
||||
"search": "Szukaj klientów...",
|
||||
"config": "Konfiguracja",
|
||||
"viewConfig": "Zobacz konfigurację",
|
||||
"firewallIps": "Dozwolone IP zapory",
|
||||
"firewallIpsDesc": "Docelowe adresy IP/CIDR, do których ten klient ma dostęp (wymuszane po stronie serwera). Pozostaw puste, aby użyć Dozwolonych IP. Obsługuje opcjonalne filtrowanie portów i protokołów. Zobacz dokumentację dla składni.",
|
||||
"downloadPng": "Pobierz PNG",
|
||||
"copyPng": "Kopiuj PNG"
|
||||
},
|
||||
"dialog": {
|
||||
"change": "Zmień",
|
||||
@@ -126,7 +134,8 @@
|
||||
"toast": {
|
||||
"success": "Sukces",
|
||||
"saved": "Zapisano",
|
||||
"error": "Błąd"
|
||||
"error": "Błąd",
|
||||
"unknown": "Nieznany błąd. Sprawdź konsolę, aby uzyskać więcej szczegółów"
|
||||
},
|
||||
"form": {
|
||||
"actions": "Akcje",
|
||||
@@ -135,16 +144,16 @@
|
||||
"sectionGeneral": "Ogólne",
|
||||
"sectionAdvanced": "Zaawansowane",
|
||||
"noItems": "Brak elementów",
|
||||
"nullNoItems": "Brak elementów. Używana konfiguracja globalna",
|
||||
"nullNoItems": "Brak elementów. Używanie konfiguracji globalnej",
|
||||
"add": "Dodaj"
|
||||
},
|
||||
"admin": {
|
||||
"general": {
|
||||
"sessionTimeout": "Limit czasu sesji",
|
||||
"sessionTimeoutDesc": "Czas trwania sesji dla opcji Zapamiętaj mnie (w sekundach)",
|
||||
"sessionTimeoutDesc": "Czas trwania sesji dla 'Zapamiętaj mnie' (w sekundach)",
|
||||
"metrics": "Metryki",
|
||||
"metricsPassword": "Hasło",
|
||||
"metricsPasswordDesc": "Hasło Bearer dla endpointu metryk (hasło lub hash argon2)",
|
||||
"metricsPasswordDesc": "Hasło Bearer dla punktu końcowego metryk (hasło lub hash argon2)",
|
||||
"json": "JSON",
|
||||
"jsonDesc": "Ścieżka dla metryk w formacie JSON",
|
||||
"prometheus": "Prometheus",
|
||||
@@ -152,57 +161,63 @@
|
||||
},
|
||||
"config": {
|
||||
"connection": "Połączenie",
|
||||
"hostDesc": "Publiczny host, do którego będą łączyć się klienci (unieważnia konfigurację)",
|
||||
"portDesc": "Publiczny port UDP, do którego będą łączyć się klienci (unieważnia konfigurację, prawdopodobnie należy też zmienić port interfejsu)",
|
||||
"hostDesc": "Publiczna nazwa hosta, z którą będą łączyć się klienci (unieważnia konfigurację)",
|
||||
"portDesc": "Publiczny port UDP klientów (unieważnia konfigurację; zaleca się także zmianę Portu Interfejsu)",
|
||||
"allowedIpsDesc": "Dozwolone adresy IP klientów (konfiguracja globalna)",
|
||||
"dnsDesc": "Serwer DNS klientów (konfiguracja globalna)",
|
||||
"mtuDesc": "MTU klientów (tylko dla nowych klientów)",
|
||||
"persistentKeepaliveDesc": "Interwał w sekundach dla keepalive do serwera. 0 = wyłączone (tylko dla nowych klientów)",
|
||||
"persistentKeepaliveDesc": "Interwał wysyłania pakietów keepalive do serwera (sekundy). 0 = wyłączone (tylko dla nowych klientów)",
|
||||
"suggest": "Sugeruj",
|
||||
"suggestDesc": "Wybierz adres IP lub nazwę hosta dla pola Host"
|
||||
},
|
||||
"interface": {
|
||||
"cidrSuccess": "Zmieniono CIDR",
|
||||
"device": "Urządzenie",
|
||||
"deviceDesc": "Urządzenie sieciowe, przez które ma być przekazywany ruch WireGuard",
|
||||
"mtuDesc": "MTU używane przez WireGuard",
|
||||
"portDesc": "Port UDP, na którym WireGuard będzie nasłuchiwał (prawdopodobnie trzeba też zmienić port w konfiguracji)",
|
||||
"deviceDesc": "Interfejs sieciowy, przez który ma być przekazywany ruch WireGuard",
|
||||
"mtuDesc": "MTU, którego będzie używać WireGuard",
|
||||
"portDesc": "Port UDP, na którym będzie nasłuchiwać WireGuard (zaleca się także zmianę Portu Konfiguracji)",
|
||||
"changeCidr": "Zmień CIDR",
|
||||
"restart": "Restart interfejsu",
|
||||
"restart": "Restartuj interfejs",
|
||||
"restartDesc": "Zrestartuj interfejs WireGuard",
|
||||
"restartWarn": "Czy na pewno chcesz zrestartować interfejs? Wszyscy klienci zostaną rozłączeni.",
|
||||
"restartSuccess": "Interfejs zrestartowany"
|
||||
"restartWarn": "Czy na pewno chcesz zrestartować interfejs? Spowoduje to rozłączenie wszystkich klientów.",
|
||||
"restartSuccess": "Interfejs zrestartowany",
|
||||
"firewall": "Filtrowanie ruchu",
|
||||
"firewallEnabled": "Włącz zaporę per-klient",
|
||||
"firewallEnabledDesc": "Ogranicz ruch klienta do określonych docelowych adresów IP za pomocą iptables. Gdy włączone, każdy klient może mieć skonfigurowane dozwolone cele."
|
||||
},
|
||||
"introText": "Witamy w panelu administracyjnym.\n\nTutaj możesz zarządzać ustawieniami ogólnymi, konfiguracją, interfejsem i hookami.\n\nZacznij od wybrania jednej z sekcji w pasku bocznym."
|
||||
"introText": "Witaj w panelu administratora.\n\nTutaj możesz zarządzać ustawieniami ogólnymi, konfiguracją, ustawieniami interfejsu i hookami.\n\nZacznij od wybrania jednej z sekcji na pasku bocznym."
|
||||
},
|
||||
"zod": {
|
||||
"generic": {
|
||||
"required": "{0} jest wymagane",
|
||||
"validNumber": "{0} musi być prawidłową liczbą",
|
||||
"validString": "{0} musi być prawidłowym tekstem",
|
||||
"validNumberRange": "{0} musi być prawidłową liczbą lub zakresem liczb",
|
||||
"validString": "{0} musi być prawidłowym ciągiem znaków",
|
||||
"validBoolean": "{0} musi być prawidłową wartością logiczną",
|
||||
"validArray": "{0} musi być prawidłową tablicą",
|
||||
"stringMin": "{0} musi mieć co najmniej {1} znaków",
|
||||
"numberMin": "{0} musi być co najmniej {1}"
|
||||
"numberMin": "{0} musi wynosić co najmniej {1}"
|
||||
},
|
||||
"client": {
|
||||
"id": "ID klienta",
|
||||
"name": "Nazwa",
|
||||
"expiresAt": "Wygasa",
|
||||
"expiresAt": "Wygasa dnia",
|
||||
"address4": "Adres IPv4",
|
||||
"address6": "Adres IPv6",
|
||||
"serverAllowedIps": "Dozwolone adresy IP serwera"
|
||||
"serverAllowedIps": "Dozwolone IP serwerowe",
|
||||
"firewallIps": "Dozwolone IP zapory",
|
||||
"firewallIpsInvalid": "Nieprawidłowy wpis IP zapory. Zobacz dokumentację dla obsługiwanej składni."
|
||||
},
|
||||
"user": {
|
||||
"username": "Nazwa użytkownika",
|
||||
"password": "Hasło",
|
||||
"remember": "Zapamiętaj",
|
||||
"name": "Imię",
|
||||
"name": "Nazwa",
|
||||
"email": "E-mail",
|
||||
"emailInvalid": "E-mail musi być prawidłowy",
|
||||
"emailInvalid": "E-mail musi być prawidłowym adresem",
|
||||
"passwordMatch": "Hasła muszą się zgadzać",
|
||||
"totpEnable": "Włącz TOTP",
|
||||
"totpEnableTrue": "TOTP musi być włączone",
|
||||
"totpEnableTrue": "Włączenie TOTP musi mieć wartość prawda",
|
||||
"totpCode": "Kod TOTP"
|
||||
},
|
||||
"userConfig": {
|
||||
@@ -211,24 +226,24 @@
|
||||
"general": {
|
||||
"sessionTimeout": "Limit czasu sesji",
|
||||
"metricsEnabled": "Metryki",
|
||||
"metricsPassword": "Hasło do metryk"
|
||||
"metricsPassword": "Hasło metryk"
|
||||
},
|
||||
"interface": {
|
||||
"cidr": "CIDR",
|
||||
"device": "Urządzenie",
|
||||
"cidrValid": "CIDR musi być prawidłowy"
|
||||
},
|
||||
"otl": "Jednorazowy link",
|
||||
"stringMalformed": "Nieprawidłowy format tekstu",
|
||||
"body": "Treść musi być prawidłowym obiektem",
|
||||
"otl": "Link jednorazowy",
|
||||
"stringMalformed": "Ciąg znaków jest zniekształcony",
|
||||
"body": "Body musi być prawidłowym obiektem",
|
||||
"hook": "Hook",
|
||||
"enabled": "Włączone",
|
||||
"mtu": "MTU",
|
||||
"port": "Port",
|
||||
"persistentKeepalive": "Stałe utrzymywanie połączenia",
|
||||
"persistentKeepalive": "Utrzymywanie połączenia",
|
||||
"address": "Adres IP",
|
||||
"dns": "DNS",
|
||||
"allowedIps": "Dozwolone adresy IP",
|
||||
"allowedIps": "Dozwolone IP",
|
||||
"file": "Plik"
|
||||
},
|
||||
"hooks": {
|
||||
@@ -236,5 +251,47 @@
|
||||
"postUp": "PostUp",
|
||||
"preDown": "PreDown",
|
||||
"postDown": "PostDown"
|
||||
},
|
||||
"copy": {
|
||||
"notSupported": "Kopiowanie nie jest obsługiwane",
|
||||
"copied": "Skopiowano!",
|
||||
"failed": "Kopiowanie nieudane",
|
||||
"copy": "Kopiuj"
|
||||
},
|
||||
"awg": {
|
||||
"jCLabel": "Liczba pakietów śmieci (Jc)",
|
||||
"jCDescription": "Liczba pakietów śmieci do wysłania (1-128, zalecane: 4-12)",
|
||||
"jMinLabel": "Minimalny rozmiar pakietu śmieci (Jmin)",
|
||||
"jMinDescription": "Minimalny rozmiar pakietów śmieci (0-1279*, zalecane: 8, musi być < Jmax)",
|
||||
"jMaxLabel": "Maksymalny rozmiar pakietu śmieci (Jmax)",
|
||||
"jMaxDescription": "Maksymalny rozmiar pakietów śmieci (1-1280*, zalecane: 80, musi być > Jmin)",
|
||||
"s1Label": "Rozmiar śmieci pakietu inicjującego (S1)",
|
||||
"s1Description": "Rozmiar śmieci pakietu inicjującego (0-1132, zalecane: 15-150, S1+56 ≠ S2)",
|
||||
"s2Label": "Rozmiar śmieci pakietu odpowiedzi (S2)",
|
||||
"s2Description": "Rozmiar śmieci pakietu odpowiedzi (0-1188, zalecane: 15-150)",
|
||||
"s3Label": "Rozmiar śmieci pakietu odpowiedzi cookie (S3)",
|
||||
"s3Description": "Rozmiar śmieci pakietu odpowiedzi cookie",
|
||||
"s4Label": "Rozmiar śmieci pakietu transportowego (S4)",
|
||||
"s4Description": "Rozmiar śmieci pakietu transportowego",
|
||||
"h1Label": "Magiczny nagłówek inicjujący (H1)",
|
||||
"h1Description": "Wartość lub zakres nagłówka pakietu inicjującego (X lub X-Y, gdzie X < Y. Min 5, max 2147483647. Wartości nie mogą nakładać się na inne nagłówki)",
|
||||
"h2Label": "Magiczny nagłówek odpowiedzi (H2)",
|
||||
"h2Description": "Wartość lub zakres nagłówka pakietu odpowiedzi (X lub X-Y, gdzie X < Y. Min 5, max 2147483647. Wartości nie mogą nakładać się na inne nagłówki)",
|
||||
"h3Label": "Magiczny nagłówek odpowiedzi cookie (H3)",
|
||||
"h3Description": "Wartość lub zakres nagłówka pakietu odpowiedzi cookie (X lub X-Y, gdzie X < Y. Min 5, max 2147483647. Wartości nie mogą nakładać się na inne nagłówki)",
|
||||
"h4Label": "Magiczny nagłówek transportowy (H4)",
|
||||
"h4Description": "Wartość lub zakres nagłówka pakietu transportowego (X lub X-Y, gdzie X < Y. Min 5, max 2147483647. Wartości nie mogą nakładać się na inne nagłówki)",
|
||||
"i1Label": "Specjalny pakiet śmieci 1 (I1)",
|
||||
"i1Description": "Pakiet imitujący protokół w formacie hex: <b 0x...>",
|
||||
"i2Label": "Specjalny pakiet śmieci 2 (I2)",
|
||||
"i2Description": "Pakiet imitujący protokół w formacie hex: <b 0x...>",
|
||||
"i3Label": "Specjalny pakiet śmieci 3 (I3)",
|
||||
"i3Description": "Pakiet imitujący protokół w formacie hex: <b 0x...>",
|
||||
"i4Label": "Specjalny pakiet śmieci 4 (I4)",
|
||||
"i4Description": "Pakiet imitujący protokół w formacie hex: <b 0x...>",
|
||||
"i5Label": "Specjalny pakiet śmieci 5 (I5)",
|
||||
"i5Description": "Pakiet imitujący protokół w formacie hex: <b 0x...>",
|
||||
"mtuNote": "Wartości zależą od MTU",
|
||||
"obfuscationParameters": "Parametry maskowania AmneziaWG"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -120,7 +120,11 @@
|
||||
"endpointDesc": "IP-адреса клієнта, з якої встановлюється з’єднання WireGuard",
|
||||
"search": "Пошук клієнтів...",
|
||||
"config": "Конфігурація",
|
||||
"viewConfig": "Переглянути конфігурацію"
|
||||
"viewConfig": "Переглянути конфігурацію",
|
||||
"firewallIps": "Дозволені IP-адреси брандмауера",
|
||||
"firewallIpsDesc": "IP-адреси/ CIDR призначення, до яких цей клієнт має доступ (контроль на стороні сервера). Залиште порожнім, щоб використовувати дозволені IP-адреси. Підтримує необов’язкову фільтрацію за портом і протоколом. Див. документацію щодо синтаксису.",
|
||||
"downloadPng": "Завантажити PNG",
|
||||
"copyPng": "Скопіювати PNG"
|
||||
},
|
||||
"dialog": {
|
||||
"change": "Змінити",
|
||||
@@ -130,7 +134,8 @@
|
||||
"toast": {
|
||||
"success": "Успіх",
|
||||
"saved": "Збережено",
|
||||
"error": "Помилка"
|
||||
"error": "Помилка",
|
||||
"unknown": "Невідома помилка. Дивіться консоль для отримання додаткових деталей"
|
||||
},
|
||||
"form": {
|
||||
"actions": "Дії",
|
||||
@@ -175,7 +180,10 @@
|
||||
"restart": "Перезавантажити інтерфейс",
|
||||
"restartDesc": "Перезавантажити інтерфейс WireGuard",
|
||||
"restartWarn": "Ви впевнені, що бажаєте перезавантажити інтерфейс? Це призведе до відключення всіх клієнтів.",
|
||||
"restartSuccess": "Інтерфейс перезавантажено"
|
||||
"restartSuccess": "Інтерфейс перезавантажено",
|
||||
"firewall": "Фільтрація трафіку",
|
||||
"firewallEnabled": "Увімкнути брандмауер для кожного клієнта",
|
||||
"firewallEnabledDesc": "Обмежити трафік клієнта до певних IP-адрес призначення за допомогою iptables. Коли увімкнено, для кожного клієнта можна налаштувати дозволені адреси призначення."
|
||||
},
|
||||
"introText": "Ласкаво просимо до панелі адміністратора.\n\nТут ви можете керувати загальними налаштуваннями, конфігурацією, налаштуваннями інтерфейсу та перехоплювачами.\n\nПочніть з вибору одного з розділів на боковій панелі."
|
||||
},
|
||||
@@ -183,6 +191,7 @@
|
||||
"generic": {
|
||||
"required": "{0} обов'язковий",
|
||||
"validNumber": "{0} має бути дійсним числом",
|
||||
"validNumberRange": "{0} має бути коректним числом або діапазоном чисел",
|
||||
"validString": "{0} має бути дійсним рядком",
|
||||
"validBoolean": "{0} має бути дійсним логічним значенням",
|
||||
"validArray": "{0} має бути дійсним масивом",
|
||||
@@ -195,7 +204,9 @@
|
||||
"expiresAt": "Термін дії закінчується о",
|
||||
"address4": "IPv4-адреса",
|
||||
"address6": "IPv6-адреса",
|
||||
"serverAllowedIps": "Дозволені IP-адреси сервера"
|
||||
"serverAllowedIps": "Дозволені IP-адреси сервера",
|
||||
"firewallIps": "Дозволені IP-адреси брандмауера",
|
||||
"firewallIpsInvalid": "Некоректний запис IP для брандмауера. Дивіться документацію щодо підтримуваного синтаксису."
|
||||
},
|
||||
"user": {
|
||||
"username": "Ім'я користувача",
|
||||
|
||||
@@ -0,0 +1,297 @@
|
||||
{
|
||||
"pages": {
|
||||
"me": "Tài khoản",
|
||||
"clients": "Người dùng",
|
||||
"admin": {
|
||||
"panel": "Bảng quản trị",
|
||||
"general": "Chung",
|
||||
"config": "Cấu hình",
|
||||
"interface": "Giao diện mạng",
|
||||
"hooks": "Hooks"
|
||||
}
|
||||
},
|
||||
"user": {
|
||||
"email": "E-Mail"
|
||||
},
|
||||
"me": {
|
||||
"currentPassword": "Mật khẩu hiện tại",
|
||||
"enable2fa": "Bật xác thực hai yếu tố",
|
||||
"enable2faDesc": "Quét mã QR bằng ứng dụng xác thực của bạn hoặc nhập khóa thủ công.",
|
||||
"2faKey": "Khóa TOTP",
|
||||
"2faCodeDesc": "Nhập mã từ ứng dụng xác thực của bạn.",
|
||||
"disable2fa": "Tắt xác thực hai yếu tố",
|
||||
"disable2faDesc": "Nhập mật khẩu để tắt xác thực hai yếu tố."
|
||||
},
|
||||
"general": {
|
||||
"name": "Tên",
|
||||
"username": "Tên đăng nhập",
|
||||
"password": "Mật khẩu",
|
||||
"newPassword": "Mật khẩu mới",
|
||||
"updatePassword": "Cập nhật mật khẩu",
|
||||
"mtu": "MTU",
|
||||
"allowedIps": "IP được phép",
|
||||
"dns": "DNS",
|
||||
"persistentKeepalive": "Persistent Keepalive",
|
||||
"logout": "Đăng xuất",
|
||||
"continue": "Tiếp tục",
|
||||
"host": "Host",
|
||||
"port": "Cổng",
|
||||
"yes": "Có",
|
||||
"no": "Chưa",
|
||||
"confirmPassword": "Xác nhận mật khẩu",
|
||||
"loading": "Đang tải...",
|
||||
"2fa": "Xác thực hai yếu tố",
|
||||
"2faCode": "Mã TOTP"
|
||||
},
|
||||
"setup": {
|
||||
"welcome": "Chào mừng đến với thiết lập đầu tiên của wg-easy",
|
||||
"welcomeDesc": "Bạn đã tìm thấy cách dễ nhất để cài đặt và quản lý WireGuard trên bất kỳ máy chủ Linux nào",
|
||||
"existingSetup": "Bạn có hệ thống được cài đặt trước đây chưa?",
|
||||
"createAdminDesc": "Vui lòng nhập tên đăng nhập quản trị viên và mật khẩu mạnh. Thông tin này sẽ được sử dụng để đăng nhập vào bảng quản trị của bạn.",
|
||||
"setupConfigDesc": "Vui lòng cung cấp host và cổng. Những thông tin này sẽ được sử dụng để cấu hình WireGuard cho người dùng trên thiết bị của họ.",
|
||||
"setupMigrationDesc": "Vui lòng cung cấp tệp sao lưu nếu bạn muốn chuyển dữ liệu từ phiên bản wg-easy trước sang cài đặt mới.",
|
||||
"upload": "Tải lên",
|
||||
"migration": "Khôi phục bản sao lưu:",
|
||||
"createAccount": "Tạo tài khoản",
|
||||
"successful": "Thiết lập thành công",
|
||||
"hostDesc": "Tên miền công khai mà thiết bị sẽ kết nối tới",
|
||||
"portDesc": "Cổng UDP công khai mà thiết bị sẽ kết nối và WireGuard sẽ sử dụng"
|
||||
},
|
||||
"update": {
|
||||
"updateAvailable": "Có bản cập nhật mới!",
|
||||
"update": "Cập nhật"
|
||||
},
|
||||
"theme": {
|
||||
"dark": "Giao diện tối",
|
||||
"light": "Giao diện sáng",
|
||||
"system": "Giao diện hệ thống"
|
||||
},
|
||||
"layout": {
|
||||
"toggleCharts": "Hiện/ẩn biểu đồ",
|
||||
"donate": "Ủng hộ"
|
||||
},
|
||||
"login": {
|
||||
"signIn": "Đăng nhập",
|
||||
"rememberMe": "Duy trì đăng nhập",
|
||||
"rememberMeDesc": "Duy trì trạng thái đăng nhập sau khi đóng trình duyệt",
|
||||
"insecure": "Bạn không thể đăng nhập qua kết nối không bảo mật. Hãy dùng HTTPS.",
|
||||
"2faRequired": "Yêu cầu xác thực hai yếu tố",
|
||||
"2faWrong": "Mã xác thực hai yếu tố không đúng"
|
||||
},
|
||||
"client": {
|
||||
"empty": "Chưa có người dùng nào.",
|
||||
"newShort": "Mới",
|
||||
"sort": "Sắp xếp",
|
||||
"create": "Tạo người dùng",
|
||||
"created": "Đã tạo người dùng",
|
||||
"new": "Người dùng mới",
|
||||
"name": "Tên",
|
||||
"expireDate": "Ngày hết hạn",
|
||||
"expireDateDesc": "Ngày người dùng sẽ bị vô hiệu hóa. Để trống nếu dùng vĩnh viễn",
|
||||
"delete": "Xóa",
|
||||
"deleteClient": "Xóa người dùng",
|
||||
"deleteDialog1": "Bạn có chắc rằng muốn xóa",
|
||||
"deleteDialog2": "Hành động này không thể hoàn tác.",
|
||||
"enabled": "Đã bật",
|
||||
"address": "Địa chỉ",
|
||||
"serverAllowedIps": "IP được phép phía máy chủ",
|
||||
"otlDesc": "Tạo liên kết dùng một lần",
|
||||
"permanent": "Vĩnh viễn",
|
||||
"createdOn": "Được tạo vào ",
|
||||
"lastSeen": "Lần cuối trực tuyến ",
|
||||
"totalDownload": "Tổng tải về: ",
|
||||
"totalUpload": "Tổng tải lên: ",
|
||||
"newClient": "Người dùng mới",
|
||||
"disableClient": "Vô hiệu hóa người dùng",
|
||||
"enableClient": "Kích hoạt người dùng",
|
||||
"noPrivKey": "Người dùng này không có khóa riêng tư. Không thể tạo cấu hình.",
|
||||
"showQR": "Hiển thị mã QR",
|
||||
"downloadConfig": "Tải cấu hình",
|
||||
"allowedIpsDesc": "Các IP sẽ được định tuyến qua VPN (ghi đè cấu hình chung)",
|
||||
"serverAllowedIpsDesc": "Các IP mà máy chủ sẽ định tuyến đến người dùng",
|
||||
"mtuDesc": "Đặt đơn vị truyền tải tối đa - MTU (kích thước gói tin) cho VPN",
|
||||
"persistentKeepaliveDesc": "Đặt khoảng thời gian (giây) gửi gói tin keep-alive. 0 để tắt",
|
||||
"hooks": "Hooks",
|
||||
"hooksDescription": "Hooks chỉ hoạt động với wg-quick",
|
||||
"hooksLeaveEmpty": "Chỉ dùng cho wg-quick. Nếu không, để trống",
|
||||
"dnsDesc": "Máy chủ DNS mà người dùng sử dụng (ghi đè cấu hình chung)",
|
||||
"notConnected": "Người dùng chưa kết nối",
|
||||
"endpoint": "Điểm cuối",
|
||||
"endpointDesc": "IP của người dùng dùng để thiết lập kết nối WireGuard",
|
||||
"search": "Tìm kiếm người dùng...",
|
||||
"config": "Cấu hình",
|
||||
"viewConfig": "Xem cấu hình",
|
||||
"firewallIps": "IP được phép qua tường lửa",
|
||||
"firewallIpsDesc": "Địa chỉ IP/CIDR đích mà người dùng này có thể truy cập (kiểm soát phía máy chủ). Để trống để dùng giá trị IP được phép. Hỗ trợ lọc theo cổng và giao thức tùy chọn. Xem tài liệu để hiểu cú pháp.",
|
||||
"downloadPng": "Tải PNG",
|
||||
"copyPng": "Sao chép PNG"
|
||||
},
|
||||
"dialog": {
|
||||
"change": "Thay đổi",
|
||||
"cancel": "Hủy",
|
||||
"create": "Tạo"
|
||||
},
|
||||
"toast": {
|
||||
"success": "Thành công",
|
||||
"saved": "Đã lưu",
|
||||
"error": "Lỗi",
|
||||
"unknown": "Lỗi không xác định. Xem console để biết thêm chi tiết"
|
||||
},
|
||||
"form": {
|
||||
"actions": "Thao tác",
|
||||
"save": "Lưu",
|
||||
"revert": "Hoàn tác",
|
||||
"sectionGeneral": "Chung",
|
||||
"sectionAdvanced": "Nâng cao",
|
||||
"noItems": "Không có mục nào",
|
||||
"nullNoItems": "Không có mục nào. Sử dụng cấu hình chung",
|
||||
"add": "Thêm"
|
||||
},
|
||||
"admin": {
|
||||
"general": {
|
||||
"sessionTimeout": "Thời gian hết phiên",
|
||||
"sessionTimeoutDesc": "Thời lượng phiên cho tính năng Duy trì đăng nhập (giây)",
|
||||
"metrics": "Metrics",
|
||||
"metricsPassword": "Mật khẩu",
|
||||
"metricsPasswordDesc": "Mật khẩu Bearer cho đường dẫn metrics (mật khẩu hoặc hash argon2)",
|
||||
"json": "JSON",
|
||||
"jsonDesc": "Đường dẫn metrics định dạng JSON",
|
||||
"prometheus": "Prometheus",
|
||||
"prometheusDesc": "Đường dẫn metrics Prometheus"
|
||||
},
|
||||
"config": {
|
||||
"connection": "Kết nối",
|
||||
"hostDesc": "Tên miền công khai mà người dùng sẽ kết nối tới (làm mất hiệu lực cấu hình)",
|
||||
"portDesc": "Cổng UDP công khai mà người dùng sẽ kết nối tới (làm mất hiệu lực cấu hình, bạn cũng cần thay đổi cổng giao diện mạng)",
|
||||
"allowedIpsDesc": "Các IP được cho phép mà người dùng sẽ sử dụng (cấu hình chung)",
|
||||
"dnsDesc": "Máy chủ DNS mà người dùng sẽ sử dụng (cấu hình chung)",
|
||||
"mtuDesc": "MTU mà người dùng sẽ sử dụng (chỉ áp dụng cho người dùng mới)",
|
||||
"persistentKeepaliveDesc": "Khoảng thời gian (giây) gửi keepalive đến máy chủ. 0 = tắt (chỉ áp dụng cho người dùng mới)",
|
||||
"suggest": "Gợi ý",
|
||||
"suggestDesc": "Chọn địa chỉ IP hoặc tên miền cho trường Host"
|
||||
},
|
||||
"interface": {
|
||||
"cidrSuccess": "Đã thay đổi CIDR",
|
||||
"device": "Card mạng",
|
||||
"deviceDesc": "Card mạng mà lưu lượng WireGuard sẽ được chuyển tiếp qua",
|
||||
"mtuDesc": "MTU mà WireGuard sẽ sử dụng",
|
||||
"portDesc": "Cổng UDP mà WireGuard sẽ sử dụng (bạn cũng cần thay đổi cổng cấu hình)",
|
||||
"changeCidr": "Thay đổi CIDR",
|
||||
"restart": "Khởi động lại giao diện mạng",
|
||||
"restartDesc": "Khởi động lại giao diện mạng WireGuard",
|
||||
"restartWarn": "Bạn có chắc muốn khởi động lại giao diện mạng? Điều này sẽ ngắt kết nối tất cả người dùng.",
|
||||
"restartSuccess": "Đã khởi động lại giao diện mạng",
|
||||
"firewall": "Lọc lưu lượng",
|
||||
"firewallEnabled": "Bật tường lửa theo từng người dùng",
|
||||
"firewallEnabledDesc": "Áp dụng iptables để giới hạn người dùng chỉ truy cập các IP đích xác định. Sau khi kích hoạt, cho phép cấu hình điểm đến riêng cho từng người dùng."
|
||||
},
|
||||
"introText": "Chào mừng đến bảng quản trị.\n\nTại đây bạn có thể quản lý cài đặt chung, cấu hình, cài đặt giao diện mạng và hooks.\n\nBắt đầu bằng cách chọn một trong các mục trong thanh bên."
|
||||
},
|
||||
"zod": {
|
||||
"generic": {
|
||||
"required": "{0} không được để trống",
|
||||
"validNumber": "{0} phải là số hợp lệ",
|
||||
"validNumberRange": "{0} phải là số hoặc khoảng số hợp lệ",
|
||||
"validString": "{0} phải là chuỗi hợp lệ",
|
||||
"validBoolean": "{0} phải là giá trị boolean hợp lệ",
|
||||
"validArray": "{0} phải là mảng hợp lệ",
|
||||
"stringMin": "{0} phải có ít nhất {1} ký tự",
|
||||
"numberMin": "{0} phải có giá trị ít nhất là {1}"
|
||||
},
|
||||
"client": {
|
||||
"id": "ID thiết bị",
|
||||
"name": "Tên",
|
||||
"expiresAt": "Hết hạn lúc",
|
||||
"address4": "Địa chỉ IPv4",
|
||||
"address6": "Địa chỉ IPv6",
|
||||
"serverAllowedIps": "IP được phép phía máy chủ",
|
||||
"firewallIps": "IP được phép qua tường lửa",
|
||||
"firewallIpsInvalid": "IP tường lửa không hợp lệ. Xem tài liệu để biết cú pháp được hỗ trợ."
|
||||
},
|
||||
"user": {
|
||||
"username": "Tên đăng nhập",
|
||||
"password": "Mật khẩu",
|
||||
"remember": "Ghi nhớ",
|
||||
"name": "Tên",
|
||||
"email": "Email",
|
||||
"emailInvalid": "Email phải có định dạng hợp lệ",
|
||||
"passwordMatch": "Mật khẩu phải khớp nhau",
|
||||
"totpEnable": "Bật TOTP",
|
||||
"totpEnableTrue": "Bật TOTP phải là true",
|
||||
"totpCode": "Mã TOTP"
|
||||
},
|
||||
"userConfig": {
|
||||
"host": "Host"
|
||||
},
|
||||
"general": {
|
||||
"sessionTimeout": "Thời gian hết phiên",
|
||||
"metricsEnabled": "Số liệu",
|
||||
"metricsPassword": "Mật khẩu số liệu"
|
||||
},
|
||||
"interface": {
|
||||
"cidr": "CIDR",
|
||||
"device": "Thiết bị mạng",
|
||||
"cidrValid": "CIDR phải hợp lệ"
|
||||
},
|
||||
"otl": "Liên kết dùng một lần",
|
||||
"stringMalformed": "Chuỗi không đúng định dạng",
|
||||
"body": "Body phải là đối tượng hợp lệ",
|
||||
"hook": "Hook",
|
||||
"enabled": "Đã bật",
|
||||
"mtu": "MTU",
|
||||
"port": "Cổng",
|
||||
"persistentKeepalive": "Persistent Keepalive",
|
||||
"address": "Địa chỉ IP",
|
||||
"dns": "DNS",
|
||||
"allowedIps": "Các IP được phép",
|
||||
"file": "Tệp"
|
||||
},
|
||||
"hooks": {
|
||||
"preUp": "PreUp",
|
||||
"postUp": "PostUp",
|
||||
"preDown": "PreDown",
|
||||
"postDown": "PostDown"
|
||||
},
|
||||
"copy": {
|
||||
"notSupported": "Không hỗ trợ sao chép",
|
||||
"copied": "Đã sao chép!",
|
||||
"failed": "Sao chép thất bại",
|
||||
"copy": "Sao chép"
|
||||
},
|
||||
"awg": {
|
||||
"jCLabel": "Số lượng gói tin rác (Jc)",
|
||||
"jCDescription": "Số gói tin rác cần gửi (1-128, khuyến nghị: 4-12)",
|
||||
"jMinLabel": "Kích thước tối thiểu gói tin rác (Jmin)",
|
||||
"jMinDescription": "Kích thước tối thiểu của gói tin rác (0-1279*, khuyến nghị: 8, phải nhỏ hơn Jmax)",
|
||||
"jMaxLabel": "Kích thước tối đa gói tin rác (Jmax)",
|
||||
"jMaxDescription": "Kích thước tối đa của gói tin rác (1-1280*, khuyến nghị: 80, phải lớn hơn Jmin)",
|
||||
"s1Label": "Kích thước rác gói tin khởi tạo (S1)",
|
||||
"s1Description": "Kích thước rác gói tin khởi tạo (0-1132[1280* - 148 = 1132], khuyến nghị: 15-150, S1+56 ≠ S2)",
|
||||
"s2Label": "Kích thước rác gói tin phản hồi (S2)",
|
||||
"s2Description": "Kích thước rác gói tin phản hồi (0-1188[1280* - 92 = 1188], khuyến nghị: 15-150)",
|
||||
"s3Label": "Kích thước rác gói tin cookie reply (S3)",
|
||||
"s3Description": "Kích thước rác gói tin cookie reply",
|
||||
"s4Label": "Kích thước rác gói tin vận chuyển (S4)",
|
||||
"s4Description": "Kích thước rác gói tin vận chuyển",
|
||||
"h1Label": "Header khởi tạo (H1)",
|
||||
"h1Description": "Giá trị hoặc khoảng header gói tin khởi tạo (X hoặc X-Y, với X<Y. Tối thiểu 5, tối đa 2147483647. Giá trị hoặc khoảng không được trùng với các header khác)",
|
||||
"h2Label": "Header phản hồi (H2)",
|
||||
"h2Description": "Giá trị hoặc khoảng header gói tin phản hồi (X hoặc X-Y, với X<Y. Tối thiểu 5, tối đa 2147483647. Giá trị hoặc khoảng không được trùng với các header khác)",
|
||||
"h3Label": "Header cookie reply (H3)",
|
||||
"h3Description": "Giá trị hoặc khoảng header gói tin cookie reply (X hoặc X-Y, với X<Y. Tối thiểu 5, tối đa 2147483647. Giá trị hoặc khoảng không được trùng với các header khác)",
|
||||
"h4Label": "Header vận chuyển (H4)",
|
||||
"h4Description": "Giá trị hoặc khoảng header gói tin vận chuyển (X hoặc X-Y, với X<Y. Tối thiểu 5, tối đa 2147483647. Giá trị hoặc khoảng không được trùng với các header khác)",
|
||||
"i1Label": "Gói tin rác đặc biệt 1 (I1)",
|
||||
"i1Description": "Gói tin giả lập giao thức định dạng hex: <b 0x...>",
|
||||
"i2Label": "Gói tin rác đặc biệt 2 (I2)",
|
||||
"i2Description": "Gói tin giả lập giao thức định dạng hex: <b 0x...>",
|
||||
"i3Label": "Gói tin rác đặc biệt 3 (I3)",
|
||||
"i3Description": "Gói tin giả lập giao thức định dạng hex: <b 0x...>",
|
||||
"i4Label": "Gói tin rác đặc biệt 4 (I4)",
|
||||
"i4Description": "Gói tin giả lập giao thức định dạng hex: <b 0x...>",
|
||||
"i5Label": "Gói tin rác đặc biệt 5 (I5)",
|
||||
"i5Description": "Gói tin giả lập giao thức định dạng hex: <b 0x...>",
|
||||
"mtuNote": "Các giá trị phụ thuộc vào MTU",
|
||||
"obfuscationParameters": "Tham số làm rối AmneziaWG"
|
||||
}
|
||||
}
|
||||
@@ -120,17 +120,22 @@
|
||||
"endpointDesc": "建立 WireGuard 连接时客户端的 IP 地址",
|
||||
"search": "搜索客户端...",
|
||||
"config": "配置",
|
||||
"viewConfig": "查看配置文本"
|
||||
"viewConfig": "查看配置文本",
|
||||
"firewallIps": "防火墙允许的IP",
|
||||
"firewallIpsDesc": "客户端可访问的目标 IP/CIDR 范围(由服务器端进行限制)。留空时将使用 服务端允许的IP 设置。支持按 端口 和 协议 进行过滤。具体语法请查看文档。",
|
||||
"downloadPng": "下载图片",
|
||||
"copyPng": "复制图片"
|
||||
},
|
||||
"dialog": {
|
||||
"change": "确认修改",
|
||||
"change": "修改",
|
||||
"cancel": "取消",
|
||||
"create": "创建"
|
||||
},
|
||||
"toast": {
|
||||
"success": "操作成功",
|
||||
"saved": "保存成功",
|
||||
"error": "发生错误"
|
||||
"error": "发生错误",
|
||||
"unknown": "未知错误。查看控制台获取更详细信息"
|
||||
},
|
||||
"form": {
|
||||
"actions": "操作",
|
||||
@@ -175,7 +180,10 @@
|
||||
"restart": "重启接口",
|
||||
"restartDesc": "重新启动WireGuard接口",
|
||||
"restartWarn": "确定要重启接口吗?这将断开所有客户端的连接。",
|
||||
"restartSuccess": "接口重启成功"
|
||||
"restartSuccess": "接口重启成功",
|
||||
"firewall": "流量过滤",
|
||||
"firewallEnabled": "启用客户端防火墙",
|
||||
"firewallEnabledDesc": "通过 iptables 限制客户端只能访问指定的目标 IP。启用后,可以为每个客户端单独配置允许访问的目标地址列表。"
|
||||
},
|
||||
"introText": "欢迎使用管理控制台。\n\n您可以在这里管理通用设置、网络配置、接口配置和钩子脚本。\n\n请从侧边栏选择一个功能模块开始。"
|
||||
},
|
||||
@@ -183,6 +191,7 @@
|
||||
"generic": {
|
||||
"required": "{0}是必填项",
|
||||
"validNumber": "{0}必须是有效数字",
|
||||
"validNumberRange": "{0}必须是有效的数字或数字范围",
|
||||
"validString": "{0}必须是有效文本",
|
||||
"validBoolean": "{0}必须是是/否选项",
|
||||
"validArray": "{0}必须是有效数组",
|
||||
@@ -195,7 +204,9 @@
|
||||
"expiresAt": "过期时间",
|
||||
"address4": "IPv4地址",
|
||||
"address6": "IPv6地址",
|
||||
"serverAllowedIps": "服务端允许的IP"
|
||||
"serverAllowedIps": "服务端允许的IP",
|
||||
"firewallIps": "防火墙允许的IP",
|
||||
"firewallIpsInvalid": "IP格式错误。请查看相关文档获取支持的写法。"
|
||||
},
|
||||
"user": {
|
||||
"username": "用户名",
|
||||
|
||||
@@ -45,9 +45,9 @@
|
||||
},
|
||||
"setup": {
|
||||
"welcome": "歡迎首次設定wg-easy",
|
||||
"welcomeDesc": "這是最簡單的方法讓你在任何Linux主機上安裝及管理WireGuard",
|
||||
"welcomeDesc": "這是在任何Linux主機上安裝與管理WireGuard最簡單的方法。",
|
||||
"existingSetup": "你有現存設定嗎?",
|
||||
"createAdminDesc": "請輸入管理員用戶名及一個高強度密碼。這些資料將用於登入管理員版面。",
|
||||
"createAdminDesc": "請輸入管理員用戶名及高強度密碼。這些資料將用於登入管理員版面。",
|
||||
"setupConfigDesc": "請輸入主機及連接埠資料。這將用於客戶端設定,以便在他們的裝置上設定WireGuard。",
|
||||
"setupMigrationDesc": "如果你想將舊版wg-easy的資料轉移到新設定,請提供備份檔案。",
|
||||
"upload": "上傳",
|
||||
@@ -88,6 +88,7 @@
|
||||
"name": "名稱",
|
||||
"expireDate": "有效期",
|
||||
"expireDateDesc": "客戶端將於此日期停用。留空則為永久有效",
|
||||
"delete": "刪除",
|
||||
"deleteClient": "刪除客戶端",
|
||||
"deleteDialog1": "你確定要刪除",
|
||||
"deleteDialog2": "此操作無法還原。",
|
||||
@@ -114,21 +115,31 @@
|
||||
"hooksDescription": "掛鉤僅適用於wg-quick",
|
||||
"hooksLeaveEmpty": "僅適用於wg-quick,否則請留空",
|
||||
"dnsDesc": "客戶端使用的域名系統伺服器(取代全局配置)",
|
||||
"search": "搜尋客戶端..."
|
||||
"notConnected": "客戶端尚未連接",
|
||||
"endpoint": "端點",
|
||||
"endpointDesc": "建立WireGuard連線的客戶端IP地址",
|
||||
"search": "搜尋客戶端...",
|
||||
"config": "配置",
|
||||
"viewConfig": "檢視配置",
|
||||
"firewallIps": "防火牆IP白名單",
|
||||
"firewallIpsDesc": "此客戶端可存取的目的地IP/CIDR(伺服器端強制執行)。留空則使用「IP白名單」。支援選填的連接埠及協定過濾,語法請參閱說明文件。",
|
||||
"downloadPng": "正在下載PNG",
|
||||
"copyPng": "複製PNG"
|
||||
},
|
||||
"dialog": {
|
||||
"change": "更改",
|
||||
"cancel": "取消",
|
||||
"create": "創建"
|
||||
"create": "建立"
|
||||
},
|
||||
"toast": {
|
||||
"success": "成功",
|
||||
"saved": "已保存",
|
||||
"error": "錯誤"
|
||||
"saved": "已儲存",
|
||||
"error": "錯誤",
|
||||
"unknown": "未知錯誤。詳情請參閱主控台。"
|
||||
},
|
||||
"form": {
|
||||
"actions": "操作",
|
||||
"save": "保存",
|
||||
"save": "儲存",
|
||||
"revert": "重置",
|
||||
"sectionGeneral": "一般設定",
|
||||
"sectionAdvanced": "進階",
|
||||
@@ -169,7 +180,10 @@
|
||||
"restart": "重啟介面",
|
||||
"restartDesc": "重啟WireGuard介面",
|
||||
"restartWarn": "你確定要重新啟動介面嗎?這將中斷所有客戶端連線。",
|
||||
"restartSuccess": "介面已重啟"
|
||||
"restartSuccess": "介面已重啟",
|
||||
"firewall": "流量過濾",
|
||||
"firewallEnabled": "啟用獨立客戶端防火牆",
|
||||
"firewallEnabledDesc": "使用iptables以限制客戶端流量至特定的目的地IP。啟用後,即可為每個客戶端單獨設定允許目的地。"
|
||||
},
|
||||
"introText": "歡迎來到管理員版面。\n\n你可以在側邊欄中管理一般、配置、介面和掛鉤設定。"
|
||||
},
|
||||
@@ -177,6 +191,7 @@
|
||||
"generic": {
|
||||
"required": "{0}為必填項",
|
||||
"validNumber": "{0}必須是有效的數字",
|
||||
"validNumberRange": "{0}必須是有效的數字或數字範圍",
|
||||
"validString": "{0}必須是有效的字串",
|
||||
"validBoolean": "{0}必須是有效的布林值",
|
||||
"validArray": "{0}必須是有效的陣列",
|
||||
@@ -189,7 +204,9 @@
|
||||
"expiresAt": "到期於",
|
||||
"address4": "IPv4地址",
|
||||
"address6": "IPv6地址",
|
||||
"serverAllowedIps": "伺服器IP白名單"
|
||||
"serverAllowedIps": "伺服器IP白名單",
|
||||
"firewallIps": "防火牆IP白名單",
|
||||
"firewallIpsInvalid": "防火牆IP輸入格式無效。請參閱說明文件以查看支援語法。"
|
||||
},
|
||||
"user": {
|
||||
"username": "用戶名",
|
||||
@@ -234,5 +251,47 @@
|
||||
"postUp": "PostUp",
|
||||
"preDown": "PreDown",
|
||||
"postDown": "PostDown"
|
||||
},
|
||||
"copy": {
|
||||
"notSupported": "不支援複製",
|
||||
"copied": "已複製!",
|
||||
"failed": "複製失敗",
|
||||
"copy": "複製"
|
||||
},
|
||||
"awg": {
|
||||
"jCLabel": "填充封包數量 (Jc)",
|
||||
"jCDescription": "要傳送的填充封包數量 (1-128,建議: 4-12)",
|
||||
"jMinLabel": "填充封包最小大小 (Jmin)",
|
||||
"jMinDescription": "填充封包的最小大小 (0-1279*,建議: 8,必須<Jmax)",
|
||||
"jMaxLabel": "填充封包最大大小 (Jmax)",
|
||||
"jMaxDescription": "填充封包的最大大小 (1-1280*,建議: 80,必須>Jmin)",
|
||||
"s1Label": "初始封包填充大小 (S1)",
|
||||
"s1Description": "初始封包填充大小 (0-1132 [1280* - 148 = 1132],建議: 15-150,S1+56 ≠ S2)",
|
||||
"s2Label": "回應封包填充大小 (S2)",
|
||||
"s2Description": "回應封包填充大小 (0-1188 [1280* - 92 = 1188],建議: 15-150)",
|
||||
"s3Label": "Cookie 回覆封包填充大小 (S3)",
|
||||
"s3Description": "Cookie 回覆封包填充大小",
|
||||
"s4Label": "傳輸封包填充大小 (S4)",
|
||||
"s4Description": "傳輸封包填充大小",
|
||||
"h1Label": "初始特徵標頭 (H1)",
|
||||
"h1Description": "初始封包標頭值 (5-2147483647,必須與 H2-H4 不同)",
|
||||
"h2Label": "回應特徵標頭 (H2)",
|
||||
"h2Description": "回應封包標頭值 (5-2147483647,必須與 H1、H3、H4 不同)",
|
||||
"h3Label": "Cookie 回覆特徵標頭 (H3)",
|
||||
"h3Description": "Cookie 回覆封包標頭值 (5-2147483647,必須與 H1、H2、H4 不同)",
|
||||
"h4Label": "傳輸特徵標頭 (H4)",
|
||||
"h4Description": "傳輸封包標頭值 (5-2147483647,必須與 H1-H3 不同)",
|
||||
"i1Label": "特殊填充封包 1 (I1)",
|
||||
"i1Description": "協定模仿封包 (16 進位格式): <b 0x...>",
|
||||
"i2Label": "特殊填充封包 2 (I2)",
|
||||
"i2Description": "協定模仿封包 (16 進位格式): <b 0x...>",
|
||||
"i3Label": "特殊填充封包 3 (I3)",
|
||||
"i3Description": "協定模仿封包 (16 進位格式): <b 0x...>",
|
||||
"i4Label": "特殊填充封包 4 (I4)",
|
||||
"i4Description": "協定模仿封包 (16 進位格式): <b 0x...>",
|
||||
"i5Label": "特殊填充封包 5 (I5)",
|
||||
"i5Description": "協定模仿封包 (16 進位格式): <b 0x...>",
|
||||
"mtuNote": "數值取決於 MTU",
|
||||
"obfuscationParameters": "AmneziaWG 混淆參數"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -120,7 +120,11 @@
|
||||
"endpointDesc": "用戶端建立 WireGuard 連線的來源 IP",
|
||||
"search": "搜尋用戶端...",
|
||||
"config": "組態設定",
|
||||
"viewConfig": "檢視組態設定"
|
||||
"viewConfig": "檢視組態設定",
|
||||
"firewallIps": "防火牆允許的 IP",
|
||||
"firewallIpsDesc": "此用戶端可存取的目標 IP/CIDR (由伺服器端強制執行),留白則使用「允許的 IP」中的設定。支援選用的連接埠與協定篩選,語法請參閱說明文件。",
|
||||
"downloadPng": "下載 PNG",
|
||||
"copyPng": "複製 PNG"
|
||||
},
|
||||
"dialog": {
|
||||
"change": "變更",
|
||||
@@ -130,7 +134,8 @@
|
||||
"toast": {
|
||||
"success": "成功",
|
||||
"saved": "已儲存",
|
||||
"error": "錯誤"
|
||||
"error": "錯誤",
|
||||
"unknown": "發生未知錯誤。請檢視主控台 (console) 以了解更多詳細資訊。"
|
||||
},
|
||||
"form": {
|
||||
"actions": "操作",
|
||||
@@ -175,7 +180,10 @@
|
||||
"restart": "重新啟動介面",
|
||||
"restartDesc": "重新啟動 WireGuard 介面",
|
||||
"restartWarn": "您確定要重新啟動介面嗎? 所有用戶端將被中斷連線。",
|
||||
"restartSuccess": "介面已重新啟動"
|
||||
"restartSuccess": "介面已重新啟動",
|
||||
"firewall": "流量過濾",
|
||||
"firewallEnabled": "啟用個別用戶端防火牆",
|
||||
"firewallEnabledDesc": "使用 iptables 限制用戶端流量僅能存取特定 IP。啟用後,可針對每個用戶端設定其允許的存取範圍。"
|
||||
},
|
||||
"introText": "歡迎使用管理面板。\n\n您可在此管理一般、組態、介面與 Hook 設定。\n\n請從側邊欄選擇任一項目開始。"
|
||||
},
|
||||
@@ -183,6 +191,7 @@
|
||||
"generic": {
|
||||
"required": "{0} 為必填項目",
|
||||
"validNumber": "{0} 必須為有效的數字",
|
||||
"validNumberRange": "{0} 必須為有效的數字或範圍",
|
||||
"validString": "{0} 必須為有效的字串",
|
||||
"validBoolean": "{0} 必須為有效的布林值",
|
||||
"validArray": "{0} 必須為有效的陣列",
|
||||
@@ -195,7 +204,9 @@
|
||||
"expiresAt": "到期時間",
|
||||
"address4": "IPv4 位址",
|
||||
"address6": "IPv6 位址",
|
||||
"serverAllowedIps": "伺服器允許的 IP"
|
||||
"serverAllowedIps": "伺服器允許的 IP",
|
||||
"firewallIps": "防火牆允許的 IP",
|
||||
"firewallIpsInvalid": "防火牆 IP 格式無效。請參閱說明文件以了解支援的語法。"
|
||||
},
|
||||
"user": {
|
||||
"username": "使用者名稱",
|
||||
|
||||
@@ -51,6 +51,11 @@ export default defineNuxtConfig({
|
||||
language: 'it-IT',
|
||||
name: 'Italiano',
|
||||
},
|
||||
{
|
||||
code: 'ja',
|
||||
language: 'ja-JP',
|
||||
name: '日本語',
|
||||
},
|
||||
{
|
||||
code: 'fr',
|
||||
language: 'fr-FR',
|
||||
@@ -131,11 +136,21 @@ export default defineNuxtConfig({
|
||||
language: 'bg-BG',
|
||||
name: 'Български',
|
||||
},
|
||||
{
|
||||
code: 'hi',
|
||||
language: 'hi-IN',
|
||||
name: 'हिन्दी',
|
||||
},
|
||||
{
|
||||
code: 'gl',
|
||||
language: 'gl-ES',
|
||||
name: 'Galego',
|
||||
},
|
||||
{
|
||||
code: 'vi',
|
||||
language: 'vi-VN',
|
||||
name: 'Tiếng Việt',
|
||||
},
|
||||
],
|
||||
defaultLocale: 'en',
|
||||
vueI18n: './i18n.config.ts',
|
||||
|
||||
+29
-30
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "wg-easy",
|
||||
"version": "15.3.0-beta.1",
|
||||
"version": "15.3.0",
|
||||
"description": "The easiest way to run WireGuard VPN + Web-based Admin UI.",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
@@ -23,56 +23,55 @@
|
||||
"dependencies": {
|
||||
"@eschricht/nuxt-color-mode": "^1.2.0",
|
||||
"@heroicons/vue": "^2.2.0",
|
||||
"@libsql/client": "^0.17.0",
|
||||
"@nuxtjs/i18n": "^10.2.3",
|
||||
"@libsql/client": "^0.17.3",
|
||||
"@nuxtjs/i18n": "^10.4.0",
|
||||
"@nuxtjs/tailwindcss": "^6.14.0",
|
||||
"@phc/format": "^1.0.0",
|
||||
"@pinia/nuxt": "^0.11.3",
|
||||
"@tailwindcss/forms": "^0.5.11",
|
||||
"@vueuse/core": "^14.2.1",
|
||||
"@vueuse/nuxt": "^14.2.1",
|
||||
"apexcharts": "^5.10.3",
|
||||
"@vueuse/core": "^14.3.0",
|
||||
"@vueuse/nuxt": "^14.3.0",
|
||||
"apexcharts": "^5.13.0",
|
||||
"argon2": "^0.44.0",
|
||||
"cidr-tools": "^11.2.0",
|
||||
"citty": "^0.2.1",
|
||||
"cidr-tools": "^12.0.2",
|
||||
"citty": "^0.2.2",
|
||||
"consola": "^3.4.2",
|
||||
"crc-32": "^1.2.2",
|
||||
"debug": "^4.4.3",
|
||||
"drizzle-orm": "^0.45.1",
|
||||
"ip-bigint": "^8.2.10",
|
||||
"is-cidr": "^6.0.3",
|
||||
"drizzle-orm": "^0.45.2",
|
||||
"ip-bigint": "^9.0.5",
|
||||
"is-cidr": "^7.0.0",
|
||||
"is-ip": "^5.0.1",
|
||||
"js-sha256": "^0.11.1",
|
||||
"nuxt": "^3.21.1",
|
||||
"otpauth": "^9.5.0",
|
||||
"nuxt": "^3.21.6",
|
||||
"obug": "^2.1.1",
|
||||
"otpauth": "^9.5.1",
|
||||
"pinia": "^3.0.4",
|
||||
"qr": "^0.5.5",
|
||||
"qr": "^0.6.0",
|
||||
"radix-vue": "^1.9.17",
|
||||
"semver": "^7.7.4",
|
||||
"semver": "^7.8.1",
|
||||
"tailwindcss": "^3.4.19",
|
||||
"timeago.js": "^4.0.2",
|
||||
"vue": "latest",
|
||||
"vue3-apexcharts": "^1.11.1",
|
||||
"zod": "^4.3.6"
|
||||
"zod": "^4.4.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@nuxt/eslint": "^1.15.2",
|
||||
"@nuxt/test-utils": "^4.0.0",
|
||||
"@types/debug": "^4.1.12",
|
||||
"@nuxt/test-utils": "^4.0.3",
|
||||
"@types/phc__format": "^1.0.1",
|
||||
"@types/semver": "^7.7.1",
|
||||
"@vitest/coverage-v8": "^4.0.18",
|
||||
"@vitest/ui": "4.0.18",
|
||||
"drizzle-kit": "^0.31.9",
|
||||
"esbuild": "^0.27.3",
|
||||
"@vitest/coverage-v8": "^4.1.7",
|
||||
"@vitest/ui": "^4.1.7",
|
||||
"drizzle-kit": "^0.31.10",
|
||||
"esbuild": "^0.28.0",
|
||||
"eslint": "^9.39.4",
|
||||
"eslint-config-prettier": "^10.1.8",
|
||||
"prettier": "^3.8.1",
|
||||
"prettier-plugin-tailwindcss": "^0.7.2",
|
||||
"tsx": "^4.21.0",
|
||||
"typescript": "^5.9.3",
|
||||
"vitest": "^4.0.18",
|
||||
"vue-tsc": "^3.2.5"
|
||||
"prettier": "^3.8.3",
|
||||
"prettier-plugin-tailwindcss": "^0.8.0",
|
||||
"tsx": "^4.22.3",
|
||||
"typescript": "^6.0.3",
|
||||
"vitest": "^4.1.7",
|
||||
"vue-tsc": "^3.3.3"
|
||||
},
|
||||
"packageManager": "pnpm@10.31.0"
|
||||
"packageManager": "pnpm@11.5.0"
|
||||
}
|
||||
|
||||
Generated
+3694
-3131
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,8 @@
|
||||
allowBuilds:
|
||||
'@parcel/watcher': false
|
||||
argon2: false
|
||||
esbuild: false
|
||||
unrs-resolver: false
|
||||
vue-demi: false
|
||||
|
||||
minimumReleaseAgeStrict: true
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 2.9 KiB After Width: | Height: | Size: 663 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 3.0 KiB After Width: | Height: | Size: 1.9 MiB |
@@ -12,6 +12,19 @@ export default definePermissionEventHandler(
|
||||
const client = await Database.clients.get(clientId);
|
||||
checkPermissions(client);
|
||||
|
||||
if (
|
||||
client &&
|
||||
client.expiresAt !== null &&
|
||||
new Date() > new Date(client.expiresAt)
|
||||
) {
|
||||
throw createError({
|
||||
statusCode: 422,
|
||||
statusMessage:
|
||||
'Client is expired. Please update the expiration date first.',
|
||||
message: 'Client is expired. Please update the expiration date first.',
|
||||
});
|
||||
}
|
||||
|
||||
await Database.clients.toggle(clientId, true);
|
||||
await WireGuard.saveConfig();
|
||||
return { success: true };
|
||||
|
||||
@@ -18,9 +18,9 @@ export default defineEventHandler(async (event) => {
|
||||
statusMessage: 'Invalid username or password',
|
||||
});
|
||||
case 'TOTP_REQUIRED':
|
||||
return { status: 'TOTP_REQUIRED' };
|
||||
return { status: 'TOTP_REQUIRED' as const };
|
||||
case 'INVALID_TOTP_CODE':
|
||||
return { status: 'INVALID_TOTP_CODE' };
|
||||
return { status: 'INVALID_TOTP_CODE' as const };
|
||||
case 'USER_DISABLED':
|
||||
throw createError({
|
||||
statusCode: 401,
|
||||
@@ -47,5 +47,5 @@ export default defineEventHandler(async (event) => {
|
||||
|
||||
SERVER_DEBUG(`New Session: ${data.id} for ${user.id} (${user.username})`);
|
||||
|
||||
return { status: 'success' };
|
||||
return { status: 'success' as const };
|
||||
});
|
||||
|
||||
@@ -58,6 +58,17 @@ export class UserService {
|
||||
this.#statements = createPreparedStatement(db);
|
||||
}
|
||||
|
||||
#createTotp(user: { username: string; totpKey: string }) {
|
||||
return new TOTP({
|
||||
issuer: 'wg-easy',
|
||||
label: user.username,
|
||||
algorithm: 'SHA1',
|
||||
digits: 6,
|
||||
period: 30,
|
||||
secret: user.totpKey,
|
||||
});
|
||||
}
|
||||
|
||||
async getAll() {
|
||||
return this.#statements.findAll.execute();
|
||||
}
|
||||
@@ -156,22 +167,13 @@ export class UserService {
|
||||
if (!code) {
|
||||
return { success: false, error: 'TOTP_REQUIRED' };
|
||||
} else {
|
||||
if (!txUser.totpKey) {
|
||||
const totpKey = txUser.totpKey;
|
||||
if (!totpKey) {
|
||||
return { success: false, error: 'UNEXPECTED_ERROR' };
|
||||
}
|
||||
|
||||
const totp = new TOTP({
|
||||
issuer: 'wg-easy',
|
||||
label: txUser.username,
|
||||
algorithm: 'SHA1',
|
||||
digits: 6,
|
||||
period: 30,
|
||||
secret: txUser.totpKey,
|
||||
});
|
||||
|
||||
const valid = totp.validate({ token: code, window: 1 });
|
||||
|
||||
if (valid === null) {
|
||||
const totp = this.#createTotp({ username: txUser.username, totpKey });
|
||||
if (totp.validate({ token: code, window: 1 }) === null) {
|
||||
return { success: false, error: 'INVALID_TOTP_CODE' };
|
||||
}
|
||||
}
|
||||
@@ -195,22 +197,13 @@ export class UserService {
|
||||
throw new Error('User not found');
|
||||
}
|
||||
|
||||
if (!txUser.totpKey) {
|
||||
const totpKey = txUser.totpKey;
|
||||
if (!totpKey) {
|
||||
throw new Error('TOTP key is not set');
|
||||
}
|
||||
|
||||
const totp = new TOTP({
|
||||
issuer: 'wg-easy',
|
||||
label: txUser.username,
|
||||
algorithm: 'SHA1',
|
||||
digits: 6,
|
||||
period: 30,
|
||||
secret: txUser.totpKey,
|
||||
});
|
||||
|
||||
const valid = totp.validate({ token: code, window: 1 });
|
||||
|
||||
if (valid === null) {
|
||||
const totp = this.#createTotp({ username: txUser.username, totpKey });
|
||||
if (totp.validate({ token: code, window: 1 }) === null) {
|
||||
throw new Error('Invalid TOTP code');
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { drizzle } from 'drizzle-orm/libsql';
|
||||
import { migrate as drizzleMigrate } from 'drizzle-orm/libsql/migrator';
|
||||
import { createClient } from '@libsql/client';
|
||||
import debug from 'debug';
|
||||
import { createDebug } from 'obug';
|
||||
import { eq } from 'drizzle-orm';
|
||||
|
||||
import * as schema from './schema';
|
||||
@@ -13,7 +13,7 @@ import { InterfaceService } from './repositories/interface/service';
|
||||
import { HooksService } from './repositories/hooks/service';
|
||||
import { OneTimeLinkService } from './repositories/oneTimeLink/service';
|
||||
|
||||
const DB_DEBUG = debug('Database');
|
||||
const DB_DEBUG = createDebug('Database');
|
||||
|
||||
const client = createClient({ url: 'file:/etc/wireguard/wg-easy.db' });
|
||||
const db = drizzle({ client, schema });
|
||||
|
||||
@@ -6,14 +6,12 @@ export default defineMetricsHandler('prometheus', async ({ event }) => {
|
||||
async function getPrometheusResponse() {
|
||||
const wgInterface = await Database.interfaces.get();
|
||||
const clients = await WireGuard.getAllClients();
|
||||
let wireguardPeerCount = 0;
|
||||
let wireguardEnabledPeersCount = 0;
|
||||
let wireguardConnectedPeersCount = 0;
|
||||
const wireguardSentBytes = [];
|
||||
const wireguardReceivedBytes = [];
|
||||
const wireguardLatestHandshakeSeconds = [];
|
||||
for (const client of clients) {
|
||||
wireguardPeerCount++;
|
||||
if (client.enabled === true) {
|
||||
wireguardEnabledPeersCount++;
|
||||
}
|
||||
@@ -41,7 +39,7 @@ async function getPrometheusResponse() {
|
||||
const returnText = [
|
||||
'# HELP wireguard_configured_peers',
|
||||
'# TYPE wireguard_configured_peers gauge',
|
||||
`wireguard_configured_peers{${id}} ${wireguardPeerCount}`,
|
||||
`wireguard_configured_peers{${id}} ${clients.length}`,
|
||||
'',
|
||||
'# HELP wireguard_enabled_peers',
|
||||
'# TYPE wireguard_enabled_peers gauge',
|
||||
@@ -62,6 +60,7 @@ async function getPrometheusResponse() {
|
||||
'# HELP wireguard_latest_handshake_seconds UNIX timestamp seconds of the last handshake',
|
||||
'# TYPE wireguard_latest_handshake_seconds gauge',
|
||||
`${wireguardLatestHandshakeSeconds.join('\n')}`,
|
||||
'',
|
||||
];
|
||||
|
||||
return returnText.join('\n');
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import fs from 'node:fs/promises';
|
||||
import debug from 'debug';
|
||||
import { createDebug } from 'obug';
|
||||
import type { InterfaceType } from '#db/repositories/interface/types';
|
||||
|
||||
const WG_DEBUG = debug('WireGuard');
|
||||
const WG_DEBUG = createDebug('WireGuard');
|
||||
|
||||
const generateRandomHeaderValue = () =>
|
||||
Math.floor(Math.random() * 2147483642) + 5;
|
||||
|
||||
@@ -6,7 +6,7 @@ type Opts = {
|
||||
};
|
||||
|
||||
/**
|
||||
* Cache function for 1 hour
|
||||
* Cache the result of a function for the given expiry time in milliseconds
|
||||
*/
|
||||
export function cacheFunction<T>(fn: () => T, { expiry }: Opts): () => T {
|
||||
let cache: { value: T; expiry: number } | null = null;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import childProcess from 'child_process';
|
||||
import debug from 'debug';
|
||||
import { createDebug } from 'obug';
|
||||
|
||||
const CMD_DEBUG = debug('CMD');
|
||||
const CMD_DEBUG = createDebug('CMD');
|
||||
|
||||
export function exec(
|
||||
cmd: string,
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import debug from 'debug';
|
||||
import { createDebug } from 'obug';
|
||||
import packageJson from '@@/package.json';
|
||||
|
||||
export const RELEASE = 'v' + packageJson.version;
|
||||
|
||||
export const SERVER_DEBUG = debug('Server');
|
||||
export const SERVER_DEBUG = createDebug('Server');
|
||||
|
||||
export const OLD_ENV = {
|
||||
/** @deprecated Only for migration purposes */
|
||||
@@ -38,6 +38,7 @@ export const WG_ENV = {
|
||||
/** If IPv6 should be disabled */
|
||||
DISABLE_IPV6: process.env.DISABLE_IPV6 === 'true',
|
||||
WG_EXECUTABLE: await detectAwg(),
|
||||
DISABLE_VERSION_CHECK: process.env.DISABLE_VERSION_CHECK === 'true',
|
||||
};
|
||||
|
||||
export const WG_INITIAL_ENV = {
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import debug from 'debug';
|
||||
import { createDebug } from 'obug';
|
||||
import { isIPv6 } from 'is-ip';
|
||||
|
||||
import type { ClientType } from '#db/repositories/client/types';
|
||||
import type { InterfaceType } from '#db/repositories/interface/types';
|
||||
import type { UserConfigType } from '#db/repositories/userConfig/types';
|
||||
|
||||
const FW_DEBUG = debug('Firewall');
|
||||
const FW_DEBUG = createDebug('Firewall');
|
||||
const CHAIN_NAME = 'WG_CLIENTS';
|
||||
|
||||
// Mutex to prevent concurrent rule rebuilds
|
||||
|
||||
@@ -4,6 +4,13 @@ type GithubRelease = {
|
||||
};
|
||||
|
||||
async function fetchLatestRelease() {
|
||||
if (WG_ENV.DISABLE_VERSION_CHECK) {
|
||||
return {
|
||||
version: RELEASE,
|
||||
changelog: '',
|
||||
};
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await $fetch<GithubRelease>(
|
||||
'https://api.github.com/repos/wg-easy/wg-easy/releases/latest',
|
||||
|
||||
Reference in New Issue
Block a user