Compare commits

...

24 Commits

Author SHA1 Message Date
Bernd Storath 261b0d6b8f Bump version to 15.3.0-beta.3 2026-05-07 13:59:19 +02:00
Ming Mak f656d57d20 Translation: update Traditional Chinese (zh-HK) localization (#2603)
* Update Chinese (HK) translations for clarity and completion

* Fix spacing

* Update zh-HK.json

Taking reference from zh_TW, making awg clearer

* Remove duplicate 'search' entry in zh-HK.json

* Fix translation typos in zh-HK locale

Replaced "户" with "戶".
2026-05-07 13:51:37 +02:00
Bernd Storath 46074fea1c update packages 2026-05-05 10:57:30 +02:00
Felipe Cordova Huenupil 05c655ede9 fix(ui):Error pops up when enabling disabled client (#2594)
* fix(ui):Error pops up when enabling disabled client

Action is prevented and a clear message is displayed in Web UI

* fix formatting

* fix type issue

* fix formatting

---------

Co-authored-by: Bernd Storath <999999bst@gmail.com>
2026-05-04 09:21:18 +02:00
Bernd Storath ebcc42cc49 fix build 2026-04-27 09:07:21 +02:00
Evgeniy be8d24e492 Fix: Add trailing newline to Prometheus metrics output (#2573)
Fix prometheus metrics
2026-04-27 08:30:03 +02:00
Bernd Storath 9682dedea7 update packages 2026-04-27 08:28:17 +02:00
Bernd Storath 5eb80fe3c1 update packages 2026-04-13 14:16:05 +02:00
dependabot[bot] dd9da2a067 build(deps): bump pnpm/action-setup from 5 to 6 (#2574)
Bumps [pnpm/action-setup](https://github.com/pnpm/action-setup) from 5 to 6.
- [Release notes](https://github.com/pnpm/action-setup/releases)
- [Commits](https://github.com/pnpm/action-setup/compare/v5...v6)

---
updated-dependencies:
- dependency-name: pnpm/action-setup
  dependency-version: '6'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-04-13 13:35:40 +02:00
Bernd Storath 15111ecd62 update packages 2026-04-13 13:02:53 +02:00
dependabot[bot] e9f4b4650b build(deps): bump pnpm/action-setup from 4 to 5 (#2570)
Bumps [pnpm/action-setup](https://github.com/pnpm/action-setup) from 4 to 5.
- [Release notes](https://github.com/pnpm/action-setup/releases)
- [Commits](https://github.com/pnpm/action-setup/compare/v4...v5)

---
updated-dependencies:
- dependency-name: pnpm/action-setup
  dependency-version: '5'
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2026-04-08 16:06:15 +02:00
Bernd Storath e3e4049f8e update packages 2026-04-08 15:51:37 +02:00
Bernd Storath 3fb9adbf6f Bump version to 15.3.0-beta.2 2026-04-07 11:46:03 +02:00
Bernd Storath cd9db1563d fix: mobile UI (#2569)
* improve mobile ui

* general cleanup

* cleanup, improvements

* fix hydration mismatch
2026-04-07 11:34:49 +02:00
wuys b5c30f5dbe i18n: add Vietnamese language support (#2568)
* i18n: add Vietnamese translation

* i18n: fix lint

* i18n: import fix

---------

Co-authored-by: meow <meow@air.local>
2026-04-07 11:22:13 +02:00
adi82bdg 1eb9527175 Update Polish translations for various terms (#2566) 2026-04-02 13:25:55 +02:00
Nikolas cd890c1f0f Update uk.json (#2559) 2026-03-25 08:54:53 +01:00
Timothy Pillow 2a78b30aeb Config fix for #2208 : Document network interface fix for multi-network configuations (#2555)
* document fix for #2208

* typo fix

* prettier

* fix code block format

* fix indentation

---------

Co-authored-by: Timothy Pillow <timothy.pillow@swisscom.com>
Co-authored-by: Bernd Storath <999999bst@gmail.com>
Co-authored-by: Bernd Storath <32197462+kaaax0815@users.noreply.github.com>
2026-03-23 09:59:17 +01:00
Chiahong 9a843087c3 i18n(zh-tw): Update Traditional Chinese translation (#2558) 2026-03-23 07:49:12 +01:00
Bernd Storath 483b63bba6 update packages 2026-03-16 08:28:58 +01:00
Alexis-Loskoutoff 13942c97b2 i18n(fr): Update French translation (#2544) 2026-03-16 08:04:34 +01:00
MeCias 82c64e506e Lang(de): Added missing translations (#2543)
* Update de.json

Lang(de): Added missing translations

* Lang(de): Added missing translations and Comma

* Lang(de): Added missing translations and Comma and identations
2026-03-14 19:49:28 +01:00
Aarón Rosa Díaz 9b3d919168 i18n(es): Updated Spanish translation (#2540)
Updated Spanish translations for various UI elements

Updated and completed all remaining Spanish translations, including support for AmneziaWG 2.0. Following: https://wg-easy.github.io/wg-easy/v15.2/contributing/translation/
2026-03-13 07:47:09 +01:00
杨黄林 3eaf0d01dc i18n: improve Simplified Chinese translation (#2541)
* Fix zh-CN translate

* i18n: improve Simplified Chinese translation

---------

Co-authored-by: yanghuanglin <yanghuanglin@qq.com>
2026-03-13 07:46:25 +01:00
47 changed files with 3735 additions and 2649 deletions
+2 -2
View File
@@ -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
+6
View File
@@ -14,10 +14,16 @@ 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)
### 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
+6 -3
View File
@@ -23,6 +23,10 @@ RUN apk add linux-headers build-base go git && \
cd ../amneziawg-tools/src && \
make
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.
FROM docker.io/library/node:krypton-alpine
@@ -35,9 +39,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
+28
View File
@@ -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
View File
@@ -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@10.33.3"
}
+5 -5
View File
@@ -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
View File
@@ -1 +1 @@
setups.@nuxt/test-utils="4.0.0"
setups.@nuxt/test-utils="4.0.3"
+1 -1
View File
@@ -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>
+1 -1
View File
@@ -16,7 +16,7 @@
</template>
<script setup lang="ts">
import type { ApexOptions } from 'apexcharts';
import type { ApexChart, ApexOptions } from 'apexcharts';
defineProps<{
client: LocalClient;
+1 -1
View File
@@ -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 -3
View File
@@ -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>
+2 -4
View File
@@ -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>
+1 -1
View File
@@ -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>
+2 -2
View File
@@ -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 -1
View File
@@ -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"
+3 -6
View File
@@ -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>
+6 -14
View File
@@ -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>
+2 -2
View File
@@ -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>
+3 -3
View File
@@ -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>
+6 -14
View File
@@ -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>
+3 -1
View File
@@ -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 -1
View File
@@ -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"
+1 -1
View File
@@ -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">
+6 -4
View File
@@ -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 -1
View File
@@ -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 -1
View File
@@ -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>
+2 -8
View File
@@ -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>
+4 -2
View File
@@ -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
View File
@@ -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>
+3 -1
View File
@@ -2,7 +2,9 @@
<main v-if="data">
<Panel>
<PanelHead>
<PanelHeadTitle :text="data.name" />
<PanelHeadTitle>
{{ data.name }}
</PanelHeadTitle>
</PanelHead>
<PanelBody>
<FormElement @submit.prevent="submit">
+7 -3
View File
@@ -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>
+3 -1
View File
@@ -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">
+2
View File
@@ -19,6 +19,7 @@ import nb from './locales/nb.json';
import bg from './locales/bg.json';
import gl from './locales/gl.json';
import cs from './locales/cs.json';
import vi from './locales/vi.json';
export default defineI18nConfig(() => ({
legacy: false,
@@ -45,5 +46,6 @@ export default defineI18nConfig(() => ({
bg,
gl,
cs,
vi,
},
}));
+16 -5
View File
@@ -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",
+60 -4
View File
@@ -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
View File
@@ -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)",
+122 -65
View File
@@ -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ą łącz 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"
}
}
+15 -4
View File
@@ -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": "Ім'я користувача",
+297
View File
@@ -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"
}
}
+16 -5
View File
@@ -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": "用户名",
+68 -9
View File
@@ -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-150S1+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 混淆參數"
}
}
+15 -4
View File
@@ -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": "使用者名稱",
+5
View File
@@ -136,6 +136,11 @@ export default defineNuxtConfig({
language: 'gl-ES',
name: 'Galego',
},
{
code: 'vi',
language: 'vi-VN',
name: 'Tiếng Việt',
},
],
defaultLocale: 'en',
vueI18n: './i18n.config.ts',
+27 -27
View File
@@ -1,6 +1,6 @@
{
"name": "wg-easy",
"version": "15.3.0-beta.1",
"version": "15.3.0-beta.3",
"description": "The easiest way to run WireGuard VPN + Web-based Admin UI.",
"private": true,
"type": "module",
@@ -23,56 +23,56 @@
"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.3.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.10.6",
"argon2": "^0.44.0",
"cidr-tools": "^11.2.0",
"citty": "^0.2.1",
"cidr-tools": "^11.3.5",
"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": "^8.3.6",
"is-cidr": "^6.0.4",
"is-ip": "^5.0.1",
"js-sha256": "^0.11.1",
"nuxt": "^3.21.1",
"otpauth": "^9.5.0",
"nuxt": "^3.21.4",
"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",
"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/debug": "^4.1.13",
"@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.5",
"@vitest/ui": "^4.1.5",
"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",
"prettier": "^3.8.3",
"prettier-plugin-tailwindcss": "^0.8.0",
"tsx": "^4.21.0",
"typescript": "^5.9.3",
"vitest": "^4.0.18",
"vue-tsc": "^3.2.5"
"typescript": "^6.0.3",
"vitest": "^4.1.5",
"vue-tsc": "^3.2.8"
},
"packageManager": "pnpm@10.31.0"
"packageManager": "pnpm@10.33.3"
}
+2907 -2400
View File
File diff suppressed because it is too large Load Diff
@@ -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 };
@@ -62,6 +62,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');