mirror of
https://github.com/fosrl/pangolin.git
synced 2026-01-28 22:00:51 +00:00
Merge branch 'dev' of github.com:fosrl/pangolin into dev
This commit is contained in:
22
.github/dependabot.yml
vendored
22
.github/dependabot.yml
vendored
@@ -38,3 +38,25 @@ updates:
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
|
||||
- package-ecosystem: "gomod"
|
||||
directory: "/install"
|
||||
schedule:
|
||||
interval: "daily"
|
||||
groups:
|
||||
dev-patch-updates:
|
||||
dependency-type: "development"
|
||||
update-types:
|
||||
- "patch"
|
||||
dev-minor-updates:
|
||||
dependency-type: "development"
|
||||
update-types:
|
||||
- "minor"
|
||||
prod-patch-updates:
|
||||
dependency-type: "production"
|
||||
update-types:
|
||||
- "patch"
|
||||
prod-minor-updates:
|
||||
dependency-type: "production"
|
||||
update-types:
|
||||
- "minor"
|
||||
2
.github/workflows/cicd.yml
vendored
2
.github/workflows/cicd.yml
vendored
@@ -30,7 +30,7 @@ jobs:
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: 1.23.0
|
||||
go-version: 1.24
|
||||
|
||||
- name: Update version in package.json
|
||||
run: |
|
||||
|
||||
@@ -4,7 +4,7 @@ Contributions are welcome!
|
||||
|
||||
Please see the contribution and local development guide on the docs page before getting started:
|
||||
|
||||
https://docs.fossorial.io/development
|
||||
https://docs.digpangolin.com/development/contributing
|
||||
|
||||
### Licensing Considerations
|
||||
|
||||
@@ -17,4 +17,4 @@ By creating this pull request, I grant the project maintainers an unlimited,
|
||||
perpetual license to use, modify, and redistribute these contributions under any terms they
|
||||
choose, including both the AGPLv3 and the Fossorial Commercial license terms. I
|
||||
represent that I have the right to grant this license for all contributed content.
|
||||
```
|
||||
```
|
||||
|
||||
@@ -20,7 +20,7 @@ _Pangolin tunnels your services to the internet so you can access anything from
|
||||
Website
|
||||
</a>
|
||||
<span> | </span>
|
||||
<a href="https://docs.fossorial.io/Getting%20Started/quick-install">
|
||||
<a href="https://docs.digpangolin.com/self-host/quick-install">
|
||||
Install Guide
|
||||
</a>
|
||||
<span> | </span>
|
||||
@@ -104,7 +104,7 @@ Pangolin is a self-hosted tunneled reverse proxy server with identity and access
|
||||
|
||||
### Fully Self Hosted
|
||||
|
||||
Host the full application on your own server or on the cloud with a VPS. Take a look at the [documentation](https://docs.fossorial.io/Getting%20Started/quick-install) to get started.
|
||||
Host the full application on your own server or on the cloud with a VPS. Take a look at the [documentation](https://docs.digpangolin.com/self-host/quick-install) to get started.
|
||||
|
||||
> Many of our users have had a great experience with [RackNerd](https://my.racknerd.com/aff.php?aff=13788). Depending on promotions, you can get a [**VPS with 1 vCPU, 1GB RAM, and ~20GB SSD for just around $12/year**](https://my.racknerd.com/aff.php?aff=13788&pid=912). That's a great deal!
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# To see all available options, please visit the docs:
|
||||
# https://docs.fossorial.io/Pangolin/Configuration/config
|
||||
# https://docs.digpangolin.com/self-host/advanced/config-file
|
||||
|
||||
app:
|
||||
dashboard_url: "http://localhost:3002"
|
||||
|
||||
@@ -36,7 +36,7 @@ services:
|
||||
- 80:80 # Port for traefik because of the network_mode
|
||||
|
||||
traefik:
|
||||
image: traefik:v3.4.0
|
||||
image: traefik:v3.5
|
||||
container_name: traefik
|
||||
restart: unless-stopped
|
||||
network_mode: service:gerbil # Ports appear on the gerbil service
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# To see all available options, please visit the docs:
|
||||
# https://docs.fossorial.io/Pangolin/Configuration/config
|
||||
# https://docs.digpangolin.com/self-host/dns-and-networking
|
||||
|
||||
app:
|
||||
dashboard_url: "https://{{.DashboardDomain}}"
|
||||
|
||||
@@ -16,7 +16,7 @@ experimental:
|
||||
version: "{{.BadgerVersion}}"
|
||||
crowdsec: # CrowdSec plugin configuration added
|
||||
moduleName: "github.com/maxlerebourg/crowdsec-bouncer-traefik-plugin"
|
||||
version: "v1.4.2"
|
||||
version: "v1.4.4"
|
||||
|
||||
log:
|
||||
level: "INFO"
|
||||
|
||||
@@ -36,7 +36,7 @@ services:
|
||||
- 80:80 # Port for traefik because of the network_mode
|
||||
{{end}}
|
||||
traefik:
|
||||
image: docker.io/traefik:v3.4.1
|
||||
image: docker.io/traefik:v3.5
|
||||
container_name: traefik
|
||||
restart: unless-stopped
|
||||
{{if .InstallGerbil}}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
module installer
|
||||
|
||||
go 1.23.0
|
||||
go 1.24
|
||||
|
||||
require (
|
||||
golang.org/x/term v0.28.0
|
||||
golang.org/x/term v0.33.0
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
)
|
||||
|
||||
require golang.org/x/sys v0.29.0 // indirect
|
||||
require golang.org/x/sys v0.34.0 // indirect
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
golang.org/x/sys v0.29.0 h1:TPYlXGxvx1MGTn2GiZDhnjPA9wZzZeGKHHmKhHYvgaU=
|
||||
golang.org/x/sys v0.29.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||
golang.org/x/term v0.28.0 h1:/Ts8HFuMR2E6IP/jlo7QVLZHggjKQbhu/7H0LJFr3Gg=
|
||||
golang.org/x/term v0.28.0/go.mod h1:Sw/lC2IAUZ92udQNf3WodGtn4k/XoLyZoh8v/8uiwek=
|
||||
golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA=
|
||||
golang.org/x/sys v0.34.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
|
||||
golang.org/x/term v0.33.0 h1:NuFncQrRcaRvVmgRkvM3j/F00gWIAlcmlB8ACEKmGIg=
|
||||
golang.org/x/term v0.33.0/go.mod h1:s18+ql9tYWp1IfpV9DmCtQDDSRBUjKaw9M1eAv5UeF0=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
|
||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||
|
||||
@@ -70,7 +70,7 @@ func main() {
|
||||
fmt.Println("- Open TCP ports 80 and 443 and UDP ports 51820 and 21820 on your VPS and firewall.")
|
||||
fmt.Println("- Point your domain to the VPS IP with A records.")
|
||||
fmt.Println("")
|
||||
fmt.Println("http://docs.fossorial.io/Getting%20Started/dns-networking")
|
||||
fmt.Println("https://docs.digpangolin.com/self-host/dns-and-networking")
|
||||
fmt.Println("")
|
||||
fmt.Println("Lets get started!")
|
||||
fmt.Println("")
|
||||
|
||||
1327
messages/bg-BG.json
Normal file
1327
messages/bg-BG.json
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1022,6 +1022,11 @@
|
||||
"actionDeleteIdpOrg": "Delete IDP Org Policy",
|
||||
"actionListIdpOrgs": "List IDP Orgs",
|
||||
"actionUpdateIdpOrg": "Update IDP Org",
|
||||
"actionCreateClient": "Create Client",
|
||||
"actionDeleteClient": "Delete Client",
|
||||
"actionUpdateClient": "Update Client",
|
||||
"actionListClients": "List Clients",
|
||||
"actionGetClient": "Get Client",
|
||||
"noneSelected": "None selected",
|
||||
"orgNotFound2": "No organizations found.",
|
||||
"searchProgress": "Search...",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"setupCreate": "Erstelle eine Organisation, Site und Ressourcen",
|
||||
"setupCreate": "Erstelle eine Organisation, einen Standort und Ressourcen",
|
||||
"setupNewOrg": "Neue Organisation",
|
||||
"setupCreateOrg": "Organisation erstellen",
|
||||
"setupCreateResources": "Ressource erstellen",
|
||||
@@ -16,7 +16,7 @@
|
||||
"componentsMember": "Du bist Mitglied von {count, plural, =0 {keiner Organisation} one {einer Organisation} other {# Organisationen}}.",
|
||||
"componentsInvalidKey": "Ungültige oder abgelaufene Lizenzschlüssel erkannt. Beachte die Lizenzbedingungen, um alle Funktionen weiterhin zu nutzen.",
|
||||
"dismiss": "Verwerfen",
|
||||
"componentsLicenseViolation": "Lizenzverstoß: Dieser Server benutzt {usedSites} Sites, die das Lizenzlimit der {maxSites} Sites überschreiten. Beachte die Lizenzbedingungen, um alle Funktionen weiterhin zu nutzen.",
|
||||
"componentsLicenseViolation": "Lizenzverstoß: Dieser Server benutzt {usedSites} Standorte, was das Lizenzlimit von {maxSites} Standorten überschreitet. Beachte die Lizenzbedingungen, um alle Funktionen weiterhin zu nutzen.",
|
||||
"componentsSupporterMessage": "Vielen Dank für die Unterstützung von Pangolin als {tier}!",
|
||||
"inviteErrorNotValid": "Es tut uns leid, aber es sieht so aus, als wäre die Einladung, auf die du zugreifen möchtest, entweder nicht angenommen worden oder nicht mehr gültig.",
|
||||
"inviteErrorUser": "Es tut uns leid, aber es scheint, als sei die Einladung, auf die du zugreifen möchtest, nicht für diesen Benutzer bestimmt.",
|
||||
@@ -38,25 +38,25 @@
|
||||
"name": "Name",
|
||||
"online": "Online",
|
||||
"offline": "Offline",
|
||||
"site": "Seite",
|
||||
"site": "Standort",
|
||||
"dataIn": "Daten eingehend",
|
||||
"dataOut": "Daten ausgehend",
|
||||
"connectionType": "Verbindungstyp",
|
||||
"tunnelType": "Tunneltyp",
|
||||
"local": "Lokal",
|
||||
"edit": "Bearbeiten",
|
||||
"siteConfirmDelete": "Site löschen bestätigen",
|
||||
"siteDelete": "Site löschen",
|
||||
"siteMessageRemove": "Sobald diese Seite entfernt ist, wird sie nicht mehr zugänglich sein. Alle Ressourcen und Ziele, die mit der Site verbunden sind, werden ebenfalls entfernt.",
|
||||
"siteMessageConfirm": "Um zu bestätigen, gib den Namen der Site ein.",
|
||||
"siteQuestionRemove": "Bist du sicher, dass Sie die Site {selectedSite} aus der Organisation entfernt werden soll?",
|
||||
"siteManageSites": "Sites verwalten",
|
||||
"siteConfirmDelete": "Standort löschen bestätigen",
|
||||
"siteDelete": "Standort löschen",
|
||||
"siteMessageRemove": "Sobald dieser Standort entfernt ist, wird er nicht mehr zugänglich sein. Alle Ressourcen und Ziele, die mit diesem Standort verbunden sind, werden ebenfalls entfernt.",
|
||||
"siteMessageConfirm": "Um zu bestätigen, gib den Namen des Standortes unten ein.",
|
||||
"siteQuestionRemove": "Bist du sicher, dass der Standort {selectedSite} aus der Organisation entfernt werden soll?",
|
||||
"siteManageSites": "Standorte verwalten",
|
||||
"siteDescription": "Verbindung zum Netzwerk durch sichere Tunnel erlauben",
|
||||
"siteCreate": "Site erstellen",
|
||||
"siteCreateDescription2": "Folge den nachfolgenden Schritten, um eine neue Site zu erstellen und zu verbinden",
|
||||
"siteCreateDescription": "Erstelle eine neue Site, um Ressourcen zu verbinden",
|
||||
"siteCreate": "Standort erstellen",
|
||||
"siteCreateDescription2": "Folge den nachfolgenden Schritten, um einen neuen Standort zu erstellen und zu verbinden",
|
||||
"siteCreateDescription": "Erstelle einen neuen Standort, um Ressourcen zu verbinden",
|
||||
"close": "Schließen",
|
||||
"siteErrorCreate": "Fehler beim Erstellen der Site",
|
||||
"siteErrorCreate": "Fehler beim Erstellen des Standortes",
|
||||
"siteErrorCreateKeyPair": "Schlüsselpaar oder Standardwerte nicht gefunden",
|
||||
"siteErrorCreateDefaults": "Standardwerte der Site nicht gefunden",
|
||||
"method": "Methode",
|
||||
@@ -70,8 +70,8 @@
|
||||
"dockerRun": "Docker Run",
|
||||
"siteLearnLocal": "Mehr Infos zu lokalen Sites",
|
||||
"siteConfirmCopy": "Ich habe die Konfiguration kopiert",
|
||||
"searchSitesProgress": "Sites durchsuchen...",
|
||||
"siteAdd": "Site hinzufügen",
|
||||
"searchSitesProgress": "Standorte durchsuchen...",
|
||||
"siteAdd": "Standort hinzufügen",
|
||||
"siteInstallNewt": "Newt installieren",
|
||||
"siteInstallNewtDescription": "Installiere Newt auf deinem System.",
|
||||
"WgConfiguration": "WireGuard Konfiguration",
|
||||
@@ -82,26 +82,26 @@
|
||||
"siteNewtDescription": "Nutze Newt für die beste Benutzererfahrung. Newt verwendet WireGuard as Basis und erlaubt Ihnen, Ihre privaten Ressourcen über ihre LAN-Adresse in Ihrem privaten Netzwerk aus dem Pangolin-Dashboard heraus zu adressieren.",
|
||||
"siteRunsInDocker": "Läuft in Docker",
|
||||
"siteRunsInShell": "Läuft in der Konsole auf macOS, Linux und Windows",
|
||||
"siteErrorDelete": "Fehler beim Löschen der Site",
|
||||
"siteErrorUpdate": "Fehler beim Aktualisieren der Site",
|
||||
"siteErrorUpdateDescription": "Beim Aktualisieren der Site ist ein Fehler aufgetreten.",
|
||||
"siteUpdated": "Site aktualisiert",
|
||||
"siteUpdatedDescription": "Die Site wurde aktualisiert.",
|
||||
"siteGeneralDescription": "Allgemeine Einstellungen für diese Site konfigurieren",
|
||||
"siteSettingDescription": "Konfigurieren der Site Einstellungen",
|
||||
"siteErrorDelete": "Fehler beim Löschen des Standortes",
|
||||
"siteErrorUpdate": "Fehler beim Aktualisieren des Standortes",
|
||||
"siteErrorUpdateDescription": "Beim Aktualisieren des Standortes ist ein Fehler aufgetreten.",
|
||||
"siteUpdated": "Standort aktualisiert",
|
||||
"siteUpdatedDescription": "Der Standort wurde aktualisiert.",
|
||||
"siteGeneralDescription": "Allgemeine Einstellungen für diesen Standort konfigurieren",
|
||||
"siteSettingDescription": "Konfigurieren der Standort Einstellungen",
|
||||
"siteSetting": "{siteName} Einstellungen",
|
||||
"siteNewtTunnel": "Newt-Tunnel (empfohlen)",
|
||||
"siteNewtTunnelDescription": "Einfachster Weg, einen Zugriffspunkt zu deinem Netzwerk zu erstellen. Keine zusätzliche Einrichtung erforderlich.",
|
||||
"siteWg": "Einfacher WireGuard Tunnel",
|
||||
"siteWgDescription": "Verwende jeden WireGuard-Client, um einen Tunnel einzurichten. Manuelles NAT-Setup erforderlich.",
|
||||
"siteLocalDescription": "Nur lokale Ressourcen. Kein Tunneling.",
|
||||
"siteSeeAll": "Alle Sites anzeigen",
|
||||
"siteTunnelDescription": "Lege fest, wie du dich mit deiner Site verbinden möchtest",
|
||||
"siteSeeAll": "Alle Standorte anzeigen",
|
||||
"siteTunnelDescription": "Lege fest, wie du dich mit deinem Standort verbinden möchtest",
|
||||
"siteNewtCredentials": "Neue Newt Zugangsdaten",
|
||||
"siteNewtCredentialsDescription": "So wird sich Newt mit dem Server authentifizieren",
|
||||
"siteCredentialsSave": "Ihre Zugangsdaten speichern",
|
||||
"siteCredentialsSaveDescription": "Du kannst das nur einmal sehen. Stelle sicher, dass du es an einen sicheren Ort kopierst.",
|
||||
"siteInfo": "Site-Informationen",
|
||||
"siteInfo": "Standort-Informationen",
|
||||
"status": "Status",
|
||||
"shareTitle": "Links zum Teilen verwalten",
|
||||
"shareDescription": "Erstellen Sie teilbare Links, um temporären oder permanenten Zugriff auf Ihre Ressourcen zu gewähren",
|
||||
@@ -163,10 +163,10 @@
|
||||
"resourceSeeAll": "Alle Ressourcen anzeigen",
|
||||
"resourceInfo": "Ressourcen-Informationen",
|
||||
"resourceNameDescription": "Dies ist der Anzeigename für die Ressource.",
|
||||
"siteSelect": "Site auswählen",
|
||||
"siteSearch": "Website durchsuchen",
|
||||
"siteNotFound": "Keine Site gefunden.",
|
||||
"siteSelectionDescription": "Diese Seite wird die Verbindung zu der Ressource herstellen.",
|
||||
"siteSelect": "Standort auswählen",
|
||||
"siteSearch": "Standorte durchsuchen",
|
||||
"siteNotFound": "Keinen Standort gefunden.",
|
||||
"siteSelectionDescription": "Dieser Standort wird die Verbindung zu der Ressource herstellen.",
|
||||
"resourceType": "Ressourcentyp",
|
||||
"resourceTypeDescription": "Legen Sie fest, wie Sie auf Ihre Ressource zugreifen möchten",
|
||||
"resourceHTTPSSettings": "HTTPS-Einstellungen",
|
||||
@@ -302,7 +302,7 @@
|
||||
"userQuestionRemove": "Sind Sie sicher, dass Sie {selectedUser} dauerhaft vom Server löschen möchten?",
|
||||
"licenseKey": "Lizenzschlüssel",
|
||||
"valid": "Gültig",
|
||||
"numberOfSites": "Anzahl der Sites",
|
||||
"numberOfSites": "Anzahl der Standorte",
|
||||
"licenseKeySearch": "Lizenzschlüssel suchen...",
|
||||
"licenseKeyAdd": "Lizenzschlüssel hinzufügen",
|
||||
"type": "Typ",
|
||||
@@ -342,16 +342,16 @@
|
||||
"licensedNot": "Nicht lizenziert",
|
||||
"hostId": "Host-ID",
|
||||
"licenseReckeckAll": "Überprüfe alle Schlüssel",
|
||||
"licenseSiteUsage": "Website-Nutzung",
|
||||
"licenseSiteUsageDecsription": "Sehen Sie sich die Anzahl der Sites an, die diese Lizenz verwenden.",
|
||||
"licenseNoSiteLimit": "Die Anzahl der Sites, die einen nicht lizenzierten Host verwenden, ist unbegrenzt.",
|
||||
"licenseSiteUsage": "Standort-Nutzung",
|
||||
"licenseSiteUsageDecsription": "Sehen Sie sich die Anzahl der Standorte an, die diese Lizenz verwenden.",
|
||||
"licenseNoSiteLimit": "Die Anzahl der Standorte, die einen nicht lizenzierten Host verwenden, ist unbegrenzt.",
|
||||
"licensePurchase": "Lizenz kaufen",
|
||||
"licensePurchaseSites": "Zusätzliche Seiten kaufen",
|
||||
"licenseSitesUsedMax": "{usedSites} der {maxSites} Seiten verwendet",
|
||||
"licenseSitesUsed": "{count, plural, =0 {# Seiten} one {# Seite} other {# Seiten}} im System.",
|
||||
"licensePurchaseSites": "Zusätzliche Standorte kaufen\n",
|
||||
"licenseSitesUsedMax": "{usedSites} von {maxSites} Standorten verwendet",
|
||||
"licenseSitesUsed": "{count, plural, =0 {# Standorte} one {# Standort} other {# Standorte}} im System.",
|
||||
"licensePurchaseDescription": "Wähle aus, für wieviele Seiten du möchtest {selectedMode, select, license {kaufe eine Lizenz. Du kannst später immer weitere Seiten hinzufügen.} other {Füge zu deiner bestehenden Lizenz hinzu.}}",
|
||||
"licenseFee": "Lizenzgebühr",
|
||||
"licensePriceSite": "Preis pro Seite",
|
||||
"licensePriceSite": "Preis pro Standort",
|
||||
"total": "Gesamt",
|
||||
"licenseContinuePayment": "Weiter zur Zahlung",
|
||||
"pricingPage": "Preisseite",
|
||||
@@ -467,7 +467,7 @@
|
||||
"targetErrorDuplicate": "Doppeltes Ziel",
|
||||
"targetErrorDuplicateDescription": "Ein Ziel mit diesen Einstellungen existiert bereits",
|
||||
"targetWireGuardErrorInvalidIp": "Ungültige Ziel-IP",
|
||||
"targetWireGuardErrorInvalidIpDescription": "Die Ziel-IP muss innerhalb des Site-Subnets liegen",
|
||||
"targetWireGuardErrorInvalidIpDescription": "Die Ziel-IP muss innerhalb des Standort-Subnets liegen",
|
||||
"targetsUpdated": "Ziele aktualisiert",
|
||||
"targetsUpdatedDescription": "Ziele und Einstellungen erfolgreich aktualisiert",
|
||||
"targetsErrorUpdate": "Fehler beim Aktualisieren der Ziele",
|
||||
@@ -558,8 +558,8 @@
|
||||
"resourceErrorCreateDescription": "Beim Erstellen der Ressource ist ein Fehler aufgetreten",
|
||||
"resourceErrorCreateMessage": "Fehler beim Erstellen der Ressource:",
|
||||
"resourceErrorCreateMessageDescription": "Ein unerwarteter Fehler ist aufgetreten",
|
||||
"sitesErrorFetch": "Fehler beim Abrufen der Sites",
|
||||
"sitesErrorFetchDescription": "Beim Abrufen der Sites ist ein Fehler aufgetreten",
|
||||
"sitesErrorFetch": "Fehler beim Abrufen der Standorte",
|
||||
"sitesErrorFetchDescription": "Beim Abrufen der Standorte ist ein Fehler aufgetreten",
|
||||
"domainsErrorFetch": "Fehler beim Abrufen der Domains",
|
||||
"domainsErrorFetchDescription": "Beim Abrufen der Domains ist ein Fehler aufgetreten",
|
||||
"none": "Keine",
|
||||
@@ -677,10 +677,10 @@
|
||||
"resourceGeneralDescription": "Konfigurieren Sie die allgemeinen Einstellungen für diese Ressource",
|
||||
"resourceEnable": "Ressource aktivieren",
|
||||
"resourceTransfer": "Ressource übertragen",
|
||||
"resourceTransferDescription": "Diese Ressource auf eine andere Site übertragen",
|
||||
"resourceTransferDescription": "Diese Ressource auf einen anderen Standort übertragen",
|
||||
"resourceTransferSubmit": "Ressource übertragen",
|
||||
"siteDestination": "Zielsite",
|
||||
"searchSites": "Sites durchsuchen",
|
||||
"siteDestination": "Zielort",
|
||||
"searchSites": "Standorte durchsuchen",
|
||||
"accessRoleCreate": "Rolle erstellen",
|
||||
"accessRoleCreateDescription": "Erstellen Sie eine neue Rolle, um Benutzer zu gruppieren und ihre Berechtigungen zu verwalten.",
|
||||
"accessRoleCreateSubmit": "Rolle erstellen",
|
||||
@@ -700,7 +700,7 @@
|
||||
"accessRoleRemovedDescription": "Die Rolle wurde erfolgreich entfernt.",
|
||||
"accessRoleRequiredRemove": "Bevor Sie diese Rolle löschen, wählen Sie bitte eine neue Rolle aus, zu der die bestehenden Mitglieder übertragen werden sollen.",
|
||||
"manage": "Verwalten",
|
||||
"sitesNotFound": "Keine Sites gefunden.",
|
||||
"sitesNotFound": "Keine Standorte gefunden.",
|
||||
"pangolinServerAdmin": "Server-Admin - Pangolin",
|
||||
"licenseTierProfessional": "Professional Lizenz",
|
||||
"licenseTierEnterprise": "Enterprise Lizenz",
|
||||
@@ -708,10 +708,10 @@
|
||||
"licensed": "Lizenziert",
|
||||
"yes": "Ja",
|
||||
"no": "Nein",
|
||||
"sitesAdditional": "Zusätzliche Sites",
|
||||
"sitesAdditional": "Zusätzliche Standorte",
|
||||
"licenseKeys": "Lizenzschlüssel",
|
||||
"sitestCountDecrease": "Anzahl der Sites verringern",
|
||||
"sitestCountIncrease": "Anzahl der Sites erhöhen",
|
||||
"sitestCountDecrease": "Anzahl der Standorte verringern",
|
||||
"sitestCountIncrease": "Anzahl der Standorte erhöhen",
|
||||
"idpManage": "Identitätsanbieter verwalten",
|
||||
"idpManageDescription": "Identitätsanbieter im System anzeigen und verwalten",
|
||||
"idpDeletedDescription": "Identitätsanbieter erfolgreich gelöscht",
|
||||
@@ -963,12 +963,12 @@
|
||||
"actionGetUser": "Benutzer abrufen",
|
||||
"actionGetOrgUser": "Organisationsbenutzer abrufen",
|
||||
"actionListOrgDomains": "Organisationsdomänen auflisten",
|
||||
"actionCreateSite": "Site erstellen",
|
||||
"actionDeleteSite": "Site löschen",
|
||||
"actionGetSite": "Site abrufen",
|
||||
"actionListSites": "Sites auflisten",
|
||||
"actionUpdateSite": "Site aktualisieren",
|
||||
"actionListSiteRoles": "Erlaubte Site-Rollen auflisten",
|
||||
"actionCreateSite": "Standort erstellen",
|
||||
"actionDeleteSite": "Standort löschen",
|
||||
"actionGetSite": "Standort abrufen",
|
||||
"actionListSites": "Standorte auflisten",
|
||||
"actionUpdateSite": "Standorte aktualisieren",
|
||||
"actionListSiteRoles": "Erlaubte Standort-Rollen auflisten",
|
||||
"actionCreateResource": "Ressource erstellen",
|
||||
"actionDeleteResource": "Ressource löschen",
|
||||
"actionGetResource": "Ressource abrufen",
|
||||
@@ -1022,6 +1022,11 @@
|
||||
"actionDeleteIdpOrg": "IDP-Organisationsrichtlinie löschen",
|
||||
"actionListIdpOrgs": "IDP-Organisationen auflisten",
|
||||
"actionUpdateIdpOrg": "IDP-Organisation aktualisieren",
|
||||
"actionCreateClient": "Kunde erstellen",
|
||||
"actionDeleteClient": "Kunde löschen",
|
||||
"actionUpdateClient": "Kunde aktualisieren",
|
||||
"actionListClients": "Kunden auflisten",
|
||||
"actionGetClient": "Kunde holen",
|
||||
"noneSelected": "Keine ausgewählt",
|
||||
"orgNotFound2": "Keine Organisationen gefunden.",
|
||||
"searchProgress": "Suche...",
|
||||
@@ -1073,7 +1078,7 @@
|
||||
"language": "Sprache",
|
||||
"verificationCodeRequired": "Code ist erforderlich",
|
||||
"userErrorNoUpdate": "Kein Benutzer zum Aktualisieren",
|
||||
"siteErrorNoUpdate": "Keine Site zum Aktualisieren",
|
||||
"siteErrorNoUpdate": "Keine Standorte zum Aktualisieren",
|
||||
"resourceErrorNoUpdate": "Keine Ressource zum Aktualisieren",
|
||||
"authErrorNoUpdate": "Keine Auth-Informationen zum Aktualisieren",
|
||||
"orgErrorNoUpdate": "Keine Organisation zum Aktualisieren",
|
||||
@@ -1081,7 +1086,7 @@
|
||||
"apiKeysErrorNoUpdate": "Kein API-Schlüssel zum Aktualisieren",
|
||||
"sidebarOverview": "Übersicht",
|
||||
"sidebarHome": "Zuhause",
|
||||
"sidebarSites": "Seiten",
|
||||
"sidebarSites": "Standorte",
|
||||
"sidebarResources": "Ressourcen",
|
||||
"sidebarAccessControl": "Zugriffskontrolle",
|
||||
"sidebarUsers": "Benutzer",
|
||||
@@ -1280,21 +1285,21 @@
|
||||
"and": "und",
|
||||
"privacyPolicy": "Datenschutzrichtlinie"
|
||||
},
|
||||
"siteRequired": "Site ist erforderlich.",
|
||||
"siteRequired": "Standort ist erforderlich.",
|
||||
"olmTunnel": "Olm Tunnel",
|
||||
"olmTunnelDescription": "Nutzen Sie Olm für die Kundenverbindung",
|
||||
"errorCreatingClient": "Fehler beim Erstellen des Clients",
|
||||
"clientDefaultsNotFound": "Kundenvorgaben nicht gefunden",
|
||||
"createClient": "Client erstellen",
|
||||
"createClientDescription": "Erstellen Sie einen neuen Client für die Verbindung zu Ihren Sites.",
|
||||
"createClientDescription": "Erstellen Sie einen neuen Client für die Verbindung zu Ihren Standorten.",
|
||||
"seeAllClients": "Alle Clients anzeigen",
|
||||
"clientInformation": "Kundeninformationen",
|
||||
"clientNamePlaceholder": "Kundenname",
|
||||
"address": "Adresse",
|
||||
"subnetPlaceholder": "Subnetz",
|
||||
"addressDescription": "Die Adresse, die dieser Client für die Verbindung verwenden wird.",
|
||||
"selectSites": "Sites auswählen",
|
||||
"sitesDescription": "Der Client wird zu den ausgewählten Sites eine Verbindung haben.",
|
||||
"selectSites": "Standorte auswählen",
|
||||
"sitesDescription": "Der Client wird zu den ausgewählten Standorten eine Verbindung haben.",
|
||||
"clientInstallOlm": "Olm installieren",
|
||||
"clientInstallOlmDescription": "Olm auf Ihrem System zum Laufen bringen",
|
||||
"clientOlmCredentials": "Olm-Zugangsdaten",
|
||||
@@ -1309,13 +1314,13 @@
|
||||
"clientUpdatedDescription": "Der Client wurde aktualisiert.",
|
||||
"clientUpdateFailed": "Fehler beim Aktualisieren des Clients",
|
||||
"clientUpdateError": "Beim Aktualisieren des Clients ist ein Fehler aufgetreten.",
|
||||
"sitesFetchFailed": "Fehler beim Abrufen von Sites",
|
||||
"sitesFetchError": "Beim Abrufen von Sites ist ein Fehler aufgetreten.",
|
||||
"sitesFetchFailed": "Fehler beim Abrufen von Standorten",
|
||||
"sitesFetchError": "Beim Abrufen von Standorten ist ein Fehler aufgetreten.",
|
||||
"olmErrorFetchReleases": "Beim Abrufen von Olm-Veröffentlichungen ist ein Fehler aufgetreten.",
|
||||
"olmErrorFetchLatest": "Beim Abrufen der neuesten Olm-Veröffentlichung ist ein Fehler aufgetreten.",
|
||||
"remoteSubnets": "Remote-Subnetze",
|
||||
"enterCidrRange": "Geben Sie den CIDR-Bereich ein",
|
||||
"remoteSubnetsDescription": "Fügen Sie CIDR-Bereiche hinzu, die aus der Ferne auf diese Site zugreifen können. Verwenden Sie das Format wie 10.0.0.0/24 oder 192.168.1.0/24.",
|
||||
"remoteSubnetsDescription": "Fügen Sie CIDR-Bereiche hinzu, die aus der Ferne auf diesen Standort zugreifen können. Verwenden Sie das Format wie 10.0.0.0/24 oder 192.168.1.0/24.",
|
||||
"resourceEnableProxy": "Öffentlichen Proxy aktivieren",
|
||||
"resourceEnableProxyDescription": "Ermöglichen Sie öffentliches Proxieren zu dieser Ressource. Dies ermöglicht den Zugriff auf die Ressource von außerhalb des Netzwerks durch die Cloud über einen offenen Port. Erfordert Traefik-Config.",
|
||||
"externalProxyEnabled": "Externer Proxy aktiviert"
|
||||
|
||||
@@ -1022,6 +1022,11 @@
|
||||
"actionDeleteIdpOrg": "Eliminar política de IDP Org",
|
||||
"actionListIdpOrgs": "Listar Orgs IDP",
|
||||
"actionUpdateIdpOrg": "Actualizar IDP Org",
|
||||
"actionCreateClient": "Crear cliente",
|
||||
"actionDeleteClient": "Eliminar cliente",
|
||||
"actionUpdateClient": "Actualizar cliente",
|
||||
"actionListClients": "Listar clientes",
|
||||
"actionGetClient": "Obtener cliente",
|
||||
"noneSelected": "Ninguno seleccionado",
|
||||
"orgNotFound2": "No se encontraron organizaciones.",
|
||||
"searchProgress": "Buscar...",
|
||||
|
||||
@@ -1022,6 +1022,11 @@
|
||||
"actionDeleteIdpOrg": "Supprimer une politique d'organisation IDP",
|
||||
"actionListIdpOrgs": "Lister les organisations IDP",
|
||||
"actionUpdateIdpOrg": "Mettre à jour une organisation IDP",
|
||||
"actionCreateClient": "Créer un client",
|
||||
"actionDeleteClient": "Supprimer le client",
|
||||
"actionUpdateClient": "Mettre à jour le client",
|
||||
"actionListClients": "Liste des clients",
|
||||
"actionGetClient": "Obtenir le client",
|
||||
"noneSelected": "Aucune sélection",
|
||||
"orgNotFound2": "Aucune organisation trouvée.",
|
||||
"searchProgress": "Rechercher...",
|
||||
|
||||
@@ -1022,6 +1022,11 @@
|
||||
"actionDeleteIdpOrg": "Elimina Politica Org IDP",
|
||||
"actionListIdpOrgs": "Elenca Org IDP",
|
||||
"actionUpdateIdpOrg": "Aggiorna Org IDP",
|
||||
"actionCreateClient": "Crea Client",
|
||||
"actionDeleteClient": "Elimina Client",
|
||||
"actionUpdateClient": "Aggiorna Client",
|
||||
"actionListClients": "Elenco Clienti",
|
||||
"actionGetClient": "Ottieni Client",
|
||||
"noneSelected": "Nessuna selezione",
|
||||
"orgNotFound2": "Nessuna organizzazione trovata.",
|
||||
"searchProgress": "Ricerca...",
|
||||
|
||||
@@ -1022,6 +1022,11 @@
|
||||
"actionDeleteIdpOrg": "IDP 조직 정책 삭제",
|
||||
"actionListIdpOrgs": "IDP 조직 목록",
|
||||
"actionUpdateIdpOrg": "IDP 조직 업데이트",
|
||||
"actionCreateClient": "Create Client",
|
||||
"actionDeleteClient": "Delete Client",
|
||||
"actionUpdateClient": "Update Client",
|
||||
"actionListClients": "List Clients",
|
||||
"actionGetClient": "Get Client",
|
||||
"noneSelected": "선택된 항목 없음",
|
||||
"orgNotFound2": "조직이 없습니다.",
|
||||
"searchProgress": "검색...",
|
||||
|
||||
@@ -1022,6 +1022,11 @@
|
||||
"actionDeleteIdpOrg": "Verwijder IDP Org Beleid",
|
||||
"actionListIdpOrgs": "Toon IDP Orgs",
|
||||
"actionUpdateIdpOrg": "IDP-org bijwerken",
|
||||
"actionCreateClient": "Client aanmaken",
|
||||
"actionDeleteClient": "Verwijder klant",
|
||||
"actionUpdateClient": "Klant bijwerken",
|
||||
"actionListClients": "Lijst klanten",
|
||||
"actionGetClient": "Client ophalen",
|
||||
"noneSelected": "Niet geselecteerd",
|
||||
"orgNotFound2": "Geen organisaties gevonden.",
|
||||
"searchProgress": "Zoeken...",
|
||||
|
||||
@@ -1022,6 +1022,11 @@
|
||||
"actionDeleteIdpOrg": "Usuń politykę organizacji IDP",
|
||||
"actionListIdpOrgs": "Lista organizacji IDP",
|
||||
"actionUpdateIdpOrg": "Aktualizuj organizację IDP",
|
||||
"actionCreateClient": "Utwórz klienta",
|
||||
"actionDeleteClient": "Usuń klienta",
|
||||
"actionUpdateClient": "Aktualizuj klienta",
|
||||
"actionListClients": "Lista klientów",
|
||||
"actionGetClient": "Pobierz klienta",
|
||||
"noneSelected": "Nie wybrano",
|
||||
"orgNotFound2": "Nie znaleziono organizacji.",
|
||||
"searchProgress": "Szukaj...",
|
||||
|
||||
@@ -1022,6 +1022,11 @@
|
||||
"actionDeleteIdpOrg": "Eliminar Política de Organização IDP",
|
||||
"actionListIdpOrgs": "Listar Organizações IDP",
|
||||
"actionUpdateIdpOrg": "Atualizar Organização IDP",
|
||||
"actionCreateClient": "Criar Cliente",
|
||||
"actionDeleteClient": "Excluir Cliente",
|
||||
"actionUpdateClient": "Atualizar Cliente",
|
||||
"actionListClients": "Listar Clientes",
|
||||
"actionGetClient": "Obter Cliente",
|
||||
"noneSelected": "Nenhum selecionado",
|
||||
"orgNotFound2": "Nenhuma organização encontrada.",
|
||||
"searchProgress": "Pesquisar...",
|
||||
|
||||
@@ -925,74 +925,74 @@
|
||||
"supportKeyInvalid": "Недействительный ключ",
|
||||
"supportKeyInvalidDescription": "Ваш ключ поддержки недействителен.",
|
||||
"supportKeyValid": "Действительный ключ",
|
||||
"supportKeyValidDescription": "Your supporter key has been validated. Thank you for your support!",
|
||||
"supportKeyErrorValidationDescription": "Failed to validate supporter key.",
|
||||
"supportKey": "Support Development and Adopt a Pangolin!",
|
||||
"supportKeyValidDescription": "Ваш ключ поддержки был проверен. Спасибо за поддержку!",
|
||||
"supportKeyErrorValidationDescription": "Не удалось проверить ключ поддержки.",
|
||||
"supportKey": "Поддержите разработку и усыновите Панголина!",
|
||||
"supportKeyDescription": "Приобретите ключ поддержки, чтобы помочь нам продолжать разработку Pangolin для сообщества. Ваш вклад позволяет нам уделять больше времени поддержке и добавлению новых функций в приложение для всех. Мы никогда не будем использовать это для платного доступа к функциям. Это отдельно от любой коммерческой версии.",
|
||||
"supportKeyPet": "You will also get to adopt and meet your very own pet Pangolin!",
|
||||
"supportKeyPurchase": "Payments are processed via GitHub. Afterward, you can retrieve your key on",
|
||||
"supportKeyPurchaseLink": "our website",
|
||||
"supportKeyPurchase2": "and redeem it here.",
|
||||
"supportKeyLearnMore": "Learn more.",
|
||||
"supportKeyOptions": "Please select the option that best suits you.",
|
||||
"supportKetOptionFull": "Full Supporter",
|
||||
"forWholeServer": "For the whole server",
|
||||
"lifetimePurchase": "Lifetime purchase",
|
||||
"supporterStatus": "Supporter status",
|
||||
"buy": "Buy",
|
||||
"supportKeyOptionLimited": "Limited Supporter",
|
||||
"forFiveUsers": "For 5 or less users",
|
||||
"supportKeyRedeem": "Redeem Supporter Key",
|
||||
"supportKeyHideSevenDays": "Hide for 7 days",
|
||||
"supportKeyEnter": "Enter Supporter Key",
|
||||
"supportKeyEnterDescription": "Meet your very own pet Pangolin!",
|
||||
"githubUsername": "GitHub Username",
|
||||
"supportKeyInput": "Supporter Key",
|
||||
"supportKeyBuy": "Buy Supporter Key",
|
||||
"logoutError": "Error logging out",
|
||||
"signingAs": "Signed in as",
|
||||
"serverAdmin": "Server Admin",
|
||||
"otpEnable": "Enable Two-factor",
|
||||
"otpDisable": "Disable Two-factor",
|
||||
"logout": "Log Out",
|
||||
"licenseTierProfessionalRequired": "Professional Edition Required",
|
||||
"supportKeyPet": "Вы также сможете усыновить и встретить вашего собственного питомца Панголина!",
|
||||
"supportKeyPurchase": "Платежи обрабатываются через GitHub. После этого вы сможете получить свой ключ на",
|
||||
"supportKeyPurchaseLink": "нашем сайте",
|
||||
"supportKeyPurchase2": "и активировать его здесь.",
|
||||
"supportKeyLearnMore": "Узнать больше.",
|
||||
"supportKeyOptions": "Пожалуйста, выберите подходящий вам вариант.",
|
||||
"supportKetOptionFull": "Полная поддержка",
|
||||
"forWholeServer": "За весь сервер",
|
||||
"lifetimePurchase": "Пожизненная покупка",
|
||||
"supporterStatus": "Статус поддержки",
|
||||
"buy": "Купить",
|
||||
"supportKeyOptionLimited": "Лимитированная поддержка",
|
||||
"forFiveUsers": "За 5 или меньше пользователей",
|
||||
"supportKeyRedeem": "Использовать ключ Поддержки",
|
||||
"supportKeyHideSevenDays": "Скрыть на 7 дней",
|
||||
"supportKeyEnter": "Введите ключ поддержки",
|
||||
"supportKeyEnterDescription": "Встречайте своего питомца Панголина!",
|
||||
"githubUsername": "Имя пользователя Github",
|
||||
"supportKeyInput": "Ключ поддержки",
|
||||
"supportKeyBuy": "Ключ поддержки",
|
||||
"logoutError": "Ошибка при выходе",
|
||||
"signingAs": "Вы вошли как",
|
||||
"serverAdmin": "Администратор сервера",
|
||||
"otpEnable": "Включить Двухфакторную Аутентификацию",
|
||||
"otpDisable": "Отключить двухфакторную аутентификацию",
|
||||
"logout": "Выйти",
|
||||
"licenseTierProfessionalRequired": "Требуется профессиональная версия",
|
||||
"licenseTierProfessionalRequiredDescription": "Эта функция доступна только в профессиональной версии.",
|
||||
"actionGetOrg": "Get Organization",
|
||||
"actionUpdateOrg": "Update Organization",
|
||||
"actionUpdateUser": "Update User",
|
||||
"actionGetUser": "Get User",
|
||||
"actionGetOrgUser": "Get Organization User",
|
||||
"actionListOrgDomains": "List Organization Domains",
|
||||
"actionCreateSite": "Create Site",
|
||||
"actionDeleteSite": "Delete Site",
|
||||
"actionGetSite": "Get Site",
|
||||
"actionListSites": "List Sites",
|
||||
"actionUpdateSite": "Update Site",
|
||||
"actionListSiteRoles": "List Allowed Site Roles",
|
||||
"actionCreateResource": "Create Resource",
|
||||
"actionDeleteResource": "Delete Resource",
|
||||
"actionGetResource": "Get Resource",
|
||||
"actionListResource": "List Resources",
|
||||
"actionUpdateResource": "Update Resource",
|
||||
"actionListResourceUsers": "List Resource Users",
|
||||
"actionSetResourceUsers": "Set Resource Users",
|
||||
"actionSetAllowedResourceRoles": "Set Allowed Resource Roles",
|
||||
"actionListAllowedResourceRoles": "List Allowed Resource Roles",
|
||||
"actionSetResourcePassword": "Set Resource Password",
|
||||
"actionSetResourcePincode": "Set Resource Pincode",
|
||||
"actionGetOrg": "Получить организацию",
|
||||
"actionUpdateOrg": "Обновить организацию",
|
||||
"actionUpdateUser": "Обновить пользователя",
|
||||
"actionGetUser": "Получить пользователя",
|
||||
"actionGetOrgUser": "Получить пользователя организации",
|
||||
"actionListOrgDomains": "Список доменов организации",
|
||||
"actionCreateSite": "Создать сайт",
|
||||
"actionDeleteSite": "Удалить сайт",
|
||||
"actionGetSite": "Получить сайт",
|
||||
"actionListSites": "Список сайтов",
|
||||
"actionUpdateSite": "Обновить сайт",
|
||||
"actionListSiteRoles": "Список разрешенных ролей сайта",
|
||||
"actionCreateResource": "Создать ресурс",
|
||||
"actionDeleteResource": "Удалить ресурс",
|
||||
"actionGetResource": "Получить ресурсы",
|
||||
"actionListResource": "Список ресурсов",
|
||||
"actionUpdateResource": "Обновить ресурс",
|
||||
"actionListResourceUsers": "Список пользователей ресурсов",
|
||||
"actionSetResourceUsers": "Список пользователей ресурсов",
|
||||
"actionSetAllowedResourceRoles": "Набор разрешенных ролей ресурсов",
|
||||
"actionListAllowedResourceRoles": "Список разрешенных ролей сайта",
|
||||
"actionSetResourcePassword": "Задать пароль ресурса",
|
||||
"actionSetResourcePincode": "Установить ПИН-код ресурса",
|
||||
"actionSetResourceEmailWhitelist": "Set Resource Email Whitelist",
|
||||
"actionGetResourceEmailWhitelist": "Get Resource Email Whitelist",
|
||||
"actionCreateTarget": "Create Target",
|
||||
"actionDeleteTarget": "Delete Target",
|
||||
"actionGetTarget": "Get Target",
|
||||
"actionListTargets": "List Targets",
|
||||
"actionUpdateTarget": "Update Target",
|
||||
"actionCreateRole": "Create Role",
|
||||
"actionDeleteRole": "Delete Role",
|
||||
"actionGetRole": "Get Role",
|
||||
"actionListRole": "List Roles",
|
||||
"actionUpdateRole": "Update Role",
|
||||
"actionListAllowedRoleResources": "List Allowed Role Resources",
|
||||
"actionCreateTarget": "Создать цель",
|
||||
"actionDeleteTarget": "Удалить цель",
|
||||
"actionGetTarget": "Получить цель",
|
||||
"actionListTargets": "Список целей",
|
||||
"actionUpdateTarget": "Обновить цель",
|
||||
"actionCreateRole": "Создать роль",
|
||||
"actionDeleteRole": "Удалить роль",
|
||||
"actionGetRole": "Получить Роль",
|
||||
"actionListRole": "Список ролей",
|
||||
"actionUpdateRole": "Обновить роль",
|
||||
"actionListAllowedRoleResources": "Список разрешенных ролей сайта",
|
||||
"actionInviteUser": "Пригласить пользователя",
|
||||
"actionRemoveUser": "Удалить пользователя",
|
||||
"actionListUsers": "Список пользователей",
|
||||
@@ -1022,6 +1022,11 @@
|
||||
"actionDeleteIdpOrg": "Удалить политику IDP организации",
|
||||
"actionListIdpOrgs": "Список организаций IDP",
|
||||
"actionUpdateIdpOrg": "Обновить организацию IDP",
|
||||
"actionCreateClient": "Создать Клиента",
|
||||
"actionDeleteClient": "Удалить Клиента",
|
||||
"actionUpdateClient": "Обновить Клиента",
|
||||
"actionListClients": "Список Клиентов",
|
||||
"actionGetClient": "Получить Клиента",
|
||||
"noneSelected": "Ничего не выбрано",
|
||||
"orgNotFound2": "Организации не найдены.",
|
||||
"searchProgress": "Поиск...",
|
||||
@@ -1093,8 +1098,8 @@
|
||||
"sidebarAllUsers": "Все пользователи",
|
||||
"sidebarIdentityProviders": "Поставщики удостоверений",
|
||||
"sidebarLicense": "Лицензия",
|
||||
"sidebarClients": "Clients (Beta)",
|
||||
"sidebarDomains": "Domains",
|
||||
"sidebarClients": "Клиенты (бета)",
|
||||
"sidebarDomains": "Домены",
|
||||
"enableDockerSocket": "Включить Docker Socket",
|
||||
"enableDockerSocketDescription": "Включить обнаружение Docker Socket для заполнения информации о контейнерах. Путь к сокету должен быть предоставлен Newt.",
|
||||
"enableDockerSocketLink": "Узнать больше",
|
||||
@@ -1134,36 +1139,36 @@
|
||||
"dark": "тёмная",
|
||||
"system": "системная",
|
||||
"theme": "Тема",
|
||||
"subnetRequired": "Subnet is required",
|
||||
"subnetRequired": "Требуется подсеть",
|
||||
"initialSetupTitle": "Начальная настройка сервера",
|
||||
"initialSetupDescription": "Создайте первоначальную учётную запись администратора сервера. Может существовать только один администратор сервера. Вы всегда можете изменить эти учётные данные позже.",
|
||||
"createAdminAccount": "Создать учётную запись администратора",
|
||||
"setupErrorCreateAdmin": "Произошла ошибка при создании учётной записи администратора сервера.",
|
||||
"certificateStatus": "Certificate Status",
|
||||
"loading": "Loading",
|
||||
"restart": "Restart",
|
||||
"domains": "Domains",
|
||||
"domainsDescription": "Manage domains for your organization",
|
||||
"domainsSearch": "Search domains...",
|
||||
"domainAdd": "Add Domain",
|
||||
"domainAddDescription": "Register a new domain with your organization",
|
||||
"domainCreate": "Create Domain",
|
||||
"domainCreatedDescription": "Domain created successfully",
|
||||
"domainDeletedDescription": "Domain deleted successfully",
|
||||
"domainQuestionRemove": "Are you sure you want to remove the domain {domain} from your account?",
|
||||
"domainMessageRemove": "Once removed, the domain will no longer be associated with your account.",
|
||||
"domainMessageConfirm": "To confirm, please type the domain name below.",
|
||||
"domainConfirmDelete": "Confirm Delete Domain",
|
||||
"domainDelete": "Delete Domain",
|
||||
"domain": "Domain",
|
||||
"selectDomainTypeNsName": "Domain Delegation (NS)",
|
||||
"selectDomainTypeNsDescription": "This domain and all its subdomains. Use this when you want to control an entire domain zone.",
|
||||
"selectDomainTypeCnameName": "Single Domain (CNAME)",
|
||||
"selectDomainTypeCnameDescription": "Just this specific domain. Use this for individual subdomains or specific domain entries.",
|
||||
"certificateStatus": "Статус сертификата",
|
||||
"loading": "Загрузка",
|
||||
"restart": "Перезагрузка",
|
||||
"domains": "Домены",
|
||||
"domainsDescription": "Управление доменами для вашей организации",
|
||||
"domainsSearch": "Поиск доменов...",
|
||||
"domainAdd": "Добавить Домен",
|
||||
"domainAddDescription": "Зарегистрировать новый домен в вашей организации",
|
||||
"domainCreate": "Создать Домен",
|
||||
"domainCreatedDescription": "Домен успешно создан",
|
||||
"domainDeletedDescription": "Домен успешно удален",
|
||||
"domainQuestionRemove": "Вы уверены, что хотите удалить домен {domain} из вашего аккаунта?",
|
||||
"domainMessageRemove": "После удаления домен больше не будет связан с вашей учетной записью.",
|
||||
"domainMessageConfirm": "Для подтверждения введите ниже имя домена.",
|
||||
"domainConfirmDelete": "Подтвердить удаление домена",
|
||||
"domainDelete": "Удалить Домен",
|
||||
"domain": "Домен",
|
||||
"selectDomainTypeNsName": "Делегация домена (NS)",
|
||||
"selectDomainTypeNsDescription": "Этот домен и все его субдомены. Используйте это, когда вы хотите управлять всей доменной зоной.",
|
||||
"selectDomainTypeCnameName": "Одиночный домен (CNAME)",
|
||||
"selectDomainTypeCnameDescription": "Только этот конкретный домен. Используйте это для отдельных субдоменов или отдельных записей домена.",
|
||||
"selectDomainTypeWildcardName": "Wildcard Domain",
|
||||
"selectDomainTypeWildcardDescription": "This domain and its subdomains.",
|
||||
"domainDelegation": "Single Domain",
|
||||
"selectType": "Select a type",
|
||||
"selectDomainTypeWildcardDescription": "Этот домен и его субдомены.",
|
||||
"domainDelegation": "Единый домен",
|
||||
"selectType": "Выберите тип",
|
||||
"actions": "Actions",
|
||||
"refresh": "Refresh",
|
||||
"refreshError": "Failed to refresh data",
|
||||
@@ -1268,19 +1273,19 @@
|
||||
"createDomainARecords": "A Records",
|
||||
"createDomainRecordNumber": "Record {number}",
|
||||
"createDomainTxtRecords": "TXT Records",
|
||||
"createDomainSaveTheseRecords": "Save These Records",
|
||||
"createDomainSaveTheseRecordsDescription": "Make sure to save these DNS records as you will not see them again.",
|
||||
"createDomainDnsPropagation": "DNS Propagation",
|
||||
"createDomainDnsPropagationDescription": "DNS changes may take some time to propagate across the internet. This can take anywhere from a few minutes to 48 hours, depending on your DNS provider and TTL settings.",
|
||||
"resourcePortRequired": "Port number is required for non-HTTP resources",
|
||||
"resourcePortNotAllowed": "Port number should not be set for HTTP resources",
|
||||
"createDomainSaveTheseRecords": "Сохранить эти записи",
|
||||
"createDomainSaveTheseRecordsDescription": "Обязательно сохраните эти DNS записи, так как вы их больше не увидите.",
|
||||
"createDomainDnsPropagation": "Распространение DNS",
|
||||
"createDomainDnsPropagationDescription": "Изменения DNS могут занять некоторое время для распространения через интернет. Это может занять от нескольких минут до 48 часов в зависимости от вашего DNS провайдера и настроек TTL.",
|
||||
"resourcePortRequired": "Номер порта необходим для не-HTTP ресурсов",
|
||||
"resourcePortNotAllowed": "Номер порта не должен быть установлен для HTTP ресурсов",
|
||||
"signUpTerms": {
|
||||
"IAgreeToThe": "I agree to the",
|
||||
"termsOfService": "terms of service",
|
||||
"and": "and",
|
||||
"privacyPolicy": "privacy policy"
|
||||
"IAgreeToThe": "Я согласен с",
|
||||
"termsOfService": "условия использования",
|
||||
"and": "и",
|
||||
"privacyPolicy": "политика конфиденциальности"
|
||||
},
|
||||
"siteRequired": "Site is required.",
|
||||
"siteRequired": "Необходимо указать сайт.",
|
||||
"olmTunnel": "Olm Tunnel",
|
||||
"olmTunnelDescription": "Use Olm for client connectivity",
|
||||
"errorCreatingClient": "Error creating client",
|
||||
|
||||
@@ -1022,6 +1022,11 @@
|
||||
"actionDeleteIdpOrg": "Kimlik Sağlayıcı Organizasyon Politikasını Sil",
|
||||
"actionListIdpOrgs": "Kimlik Sağlayıcı Organizasyonları Listele",
|
||||
"actionUpdateIdpOrg": "Kimlik Sağlayıcı Organizasyonu Güncelle",
|
||||
"actionCreateClient": "Müşteri Oluştur",
|
||||
"actionDeleteClient": "Müşteri Sil",
|
||||
"actionUpdateClient": "Müşteri Güncelle",
|
||||
"actionListClients": "Müşterileri Listele",
|
||||
"actionGetClient": "Müşteriyi Al",
|
||||
"noneSelected": "Hiçbiri seçili değil",
|
||||
"orgNotFound2": "Hiçbir organizasyon bulunamadı.",
|
||||
"searchProgress": "Ara...",
|
||||
|
||||
@@ -1022,6 +1022,11 @@
|
||||
"actionDeleteIdpOrg": "删除 IDP组织策略",
|
||||
"actionListIdpOrgs": "列出 IDP组织",
|
||||
"actionUpdateIdpOrg": "更新 IDP组织",
|
||||
"actionCreateClient": "创建客户端",
|
||||
"actionDeleteClient": "删除客户端",
|
||||
"actionUpdateClient": "更新客户端",
|
||||
"actionListClients": "列出客户端",
|
||||
"actionGetClient": "获取客户端",
|
||||
"noneSelected": "未选择",
|
||||
"orgNotFound2": "未找到组织。",
|
||||
"searchProgress": "搜索中...",
|
||||
|
||||
@@ -88,7 +88,7 @@ export const WelcomeQuickStart = ({
|
||||
To learn how to use Newt, including more
|
||||
installation methods, visit the{" "}
|
||||
<a
|
||||
href="https://docs.fossorial.io"
|
||||
href="https://docs.digpangolin.com/manage/sites/install-site"
|
||||
className="underline"
|
||||
>
|
||||
docs
|
||||
|
||||
@@ -30,12 +30,6 @@ export class Config {
|
||||
throw new Error(`Invalid configuration file: ${errors}`);
|
||||
}
|
||||
|
||||
if (process.env.APP_BASE_DOMAIN) {
|
||||
console.log(
|
||||
"WARNING: You're using deprecated environment variables. Transition to the configuration file. https://docs.fossorial.io/"
|
||||
);
|
||||
}
|
||||
|
||||
if (
|
||||
// @ts-ignore
|
||||
parsedConfig.users ||
|
||||
|
||||
@@ -287,7 +287,7 @@ export function readConfigFile() {
|
||||
|
||||
if (!environment) {
|
||||
throw new Error(
|
||||
"No configuration file found. Please create one. https://docs.fossorial.io/"
|
||||
"No configuration file found. Please create one. https://docs.digpangolin.com/self-host/advanced/config-file"
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -35,6 +35,11 @@ export async function verifyApiKeyApiKeyAccess(
|
||||
);
|
||||
}
|
||||
|
||||
if (callerApiKey.isRoot) {
|
||||
// Root keys can access any key in any org
|
||||
return next();
|
||||
}
|
||||
|
||||
const [callerApiKeyOrg] = await db
|
||||
.select()
|
||||
.from(apiKeyOrg)
|
||||
|
||||
@@ -28,6 +28,11 @@ export async function verifyApiKeyClientAccess(
|
||||
);
|
||||
}
|
||||
|
||||
if (apiKey.isRoot) {
|
||||
// Root keys can access any key in any org
|
||||
return next();
|
||||
}
|
||||
|
||||
const client = await db
|
||||
.select()
|
||||
.from(clients)
|
||||
|
||||
@@ -27,6 +27,11 @@ export async function verifyApiKeyOrgAccess(
|
||||
);
|
||||
}
|
||||
|
||||
if (req.apiKey?.isRoot) {
|
||||
// Root keys can access any key in any org
|
||||
return next();
|
||||
}
|
||||
|
||||
if (!req.apiKeyOrg) {
|
||||
const apiKeyOrgRes = await db
|
||||
.select()
|
||||
|
||||
@@ -37,6 +37,11 @@ export async function verifyApiKeyResourceAccess(
|
||||
);
|
||||
}
|
||||
|
||||
if (apiKey.isRoot) {
|
||||
// Root keys can access any key in any org
|
||||
return next();
|
||||
}
|
||||
|
||||
if (!resource.orgId) {
|
||||
return next(
|
||||
createHttpError(
|
||||
|
||||
@@ -45,6 +45,11 @@ export async function verifyApiKeyRoleAccess(
|
||||
);
|
||||
}
|
||||
|
||||
if (apiKey.isRoot) {
|
||||
// Root keys can access any key in any org
|
||||
return next();
|
||||
}
|
||||
|
||||
const orgIds = new Set(rolesData.map((role) => role.orgId));
|
||||
|
||||
for (const role of rolesData) {
|
||||
|
||||
@@ -32,6 +32,11 @@ export async function verifyApiKeySetResourceUsers(
|
||||
return next(createHttpError(HttpCode.BAD_REQUEST, "Invalid user IDs"));
|
||||
}
|
||||
|
||||
if (apiKey.isRoot) {
|
||||
// Root keys can access any key in any org
|
||||
return next();
|
||||
}
|
||||
|
||||
if (userIds.length === 0) {
|
||||
return next();
|
||||
}
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
import { Request, Response, NextFunction } from "express";
|
||||
import { db } from "@server/db";
|
||||
import {
|
||||
sites,
|
||||
apiKeyOrg
|
||||
} from "@server/db";
|
||||
import { sites, apiKeyOrg } from "@server/db";
|
||||
import { and, eq, or } from "drizzle-orm";
|
||||
import createHttpError from "http-errors";
|
||||
import HttpCode from "@server/types/HttpCode";
|
||||
@@ -31,6 +28,11 @@ export async function verifyApiKeySiteAccess(
|
||||
);
|
||||
}
|
||||
|
||||
if (apiKey.isRoot) {
|
||||
// Root keys can access any key in any org
|
||||
return next();
|
||||
}
|
||||
|
||||
const site = await db
|
||||
.select()
|
||||
.from(sites)
|
||||
|
||||
@@ -66,6 +66,11 @@ export async function verifyApiKeyTargetAccess(
|
||||
);
|
||||
}
|
||||
|
||||
if (apiKey.isRoot) {
|
||||
// Root keys can access any key in any org
|
||||
return next();
|
||||
}
|
||||
|
||||
if (!resource.orgId) {
|
||||
return next(
|
||||
createHttpError(
|
||||
|
||||
@@ -27,6 +27,11 @@ export async function verifyApiKeyUserAccess(
|
||||
);
|
||||
}
|
||||
|
||||
if (apiKey.isRoot) {
|
||||
// Root keys can access any key in any org
|
||||
return next();
|
||||
}
|
||||
|
||||
if (!req.apiKeyOrg || !req.apiKeyOrg.orgId) {
|
||||
return next(
|
||||
createHttpError(
|
||||
|
||||
@@ -63,15 +63,6 @@ export async function createRootApiKey(
|
||||
lastChars,
|
||||
isRoot: true
|
||||
});
|
||||
|
||||
const allOrgs = await trx.select().from(orgs);
|
||||
|
||||
for (const org of allOrgs) {
|
||||
await trx.insert(apiKeyOrg).values({
|
||||
apiKeyId,
|
||||
orgId: org.orgId
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
try {
|
||||
|
||||
@@ -52,20 +52,26 @@ export async function exchangeSession(
|
||||
|
||||
try {
|
||||
const { requestToken, host, requestIp } = parsedBody.data;
|
||||
let cleanHost = host;
|
||||
// if the host ends with :port
|
||||
if (cleanHost.match(/:[0-9]{1,5}$/)) {
|
||||
let matched = ''+cleanHost.match(/:[0-9]{1,5}$/);
|
||||
cleanHost = cleanHost.slice(0, -1*matched.length);
|
||||
}
|
||||
|
||||
const clientIp = requestIp?.split(":")[0];
|
||||
|
||||
const [resource] = await db
|
||||
.select()
|
||||
.from(resources)
|
||||
.where(eq(resources.fullDomain, host))
|
||||
.where(eq(resources.fullDomain, cleanHost))
|
||||
.limit(1);
|
||||
|
||||
if (!resource) {
|
||||
return next(
|
||||
createHttpError(
|
||||
HttpCode.NOT_FOUND,
|
||||
`Resource with host ${host} not found`
|
||||
`Resource with host ${cleanHost} not found`
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@@ -121,11 +121,10 @@ export async function verifyResourceSession(
|
||||
logger.debug("Client IP:", { clientIp });
|
||||
|
||||
let cleanHost = host;
|
||||
// if the host ends with :443 or :80 remove it
|
||||
if (cleanHost.endsWith(":443")) {
|
||||
cleanHost = cleanHost.slice(0, -4);
|
||||
} else if (cleanHost.endsWith(":80")) {
|
||||
cleanHost = cleanHost.slice(0, -3);
|
||||
// if the host ends with :port, strip it
|
||||
if (cleanHost.match(/:[0-9]{1,5}$/)) {
|
||||
let matched = ''+cleanHost.match(/:[0-9]{1,5}$/);
|
||||
cleanHost = cleanHost.slice(0, -1*matched.length);
|
||||
}
|
||||
|
||||
const resourceCacheKey = `resource:${cleanHost}`;
|
||||
|
||||
@@ -215,7 +215,7 @@ export async function createOrg(
|
||||
orgId: newOrg[0].orgId,
|
||||
roleId: roleId,
|
||||
isOwner: true
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
const memberRole = await trx
|
||||
@@ -234,18 +234,6 @@ export async function createOrg(
|
||||
orgId
|
||||
}))
|
||||
);
|
||||
|
||||
const rootApiKeys = await trx
|
||||
.select()
|
||||
.from(apiKeys)
|
||||
.where(eq(apiKeys.isRoot, true));
|
||||
|
||||
for (const apiKey of rootApiKeys) {
|
||||
await trx.insert(apiKeyOrg).values({
|
||||
apiKeyId: apiKey.apiKeyId,
|
||||
orgId: newOrg[0].orgId
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
if (!org) {
|
||||
|
||||
@@ -78,7 +78,7 @@ export default async function migration() {
|
||||
fs.writeFileSync(filePath, updatedYaml, "utf8");
|
||||
} catch (e) {
|
||||
console.log(
|
||||
`Failed to add resource_session_request_param to config. Please add it manually. https://docs.fossorial.io/Pangolin/Configuration/config`
|
||||
`Failed to add resource_session_request_param to config. Please add it manually. https://docs.digpangolin.com/self-host/advanced/config-file`
|
||||
);
|
||||
trx.rollback();
|
||||
return;
|
||||
|
||||
@@ -63,7 +63,7 @@ export default async function migration() {
|
||||
console.log(`Added new config option: resource_access_token_headers`);
|
||||
} catch (e) {
|
||||
console.log(
|
||||
`Unable to add new config option: resource_access_token_headers. Please add it manually. https://docs.fossorial.io/Pangolin/Configuration/config`
|
||||
`Unable to add new config option: resource_access_token_headers. Please add it manually. https://docs.digpangolin.com/self-host/advanced/config-file`
|
||||
);
|
||||
console.error(e);
|
||||
}
|
||||
|
||||
@@ -734,7 +734,7 @@ export default function Page() {
|
||||
|
||||
<Link
|
||||
className="text-sm text-primary flex items-center gap-1"
|
||||
href="https://docs.fossorial.io/Pangolin/tcp-udp"
|
||||
href="https://docs.digpangolin.com/manage/resources/tcp-udp-resources"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
|
||||
@@ -64,7 +64,7 @@ export const SitesSplashCard = () => {
|
||||
|
||||
<div className="mt-4">
|
||||
<Link
|
||||
href="https://docs.fossorial.io/Newt/install"
|
||||
href="https://docs.digpangolin.com/manage/sites/install-site"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
>
|
||||
|
||||
@@ -65,7 +65,7 @@ export default function GeneralPage() {
|
||||
defaultValues: {
|
||||
name: site?.name,
|
||||
dockerSocketEnabled: site?.dockerSocketEnabled ?? false,
|
||||
remoteSubnets: site?.remoteSubnets
|
||||
remoteSubnets: site?.remoteSubnets
|
||||
? site.remoteSubnets.split(',').map((subnet, index) => ({
|
||||
id: subnet.trim(),
|
||||
text: subnet.trim()
|
||||
@@ -144,7 +144,7 @@ export default function GeneralPage() {
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
|
||||
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="remoteSubnets"
|
||||
@@ -208,7 +208,7 @@ export default function GeneralPage() {
|
||||
"enableDockerSocketDescription"
|
||||
)}{" "}
|
||||
<Link
|
||||
href="https://docs.fossorial.io/Newt/overview#docker-socket-integration"
|
||||
href="https://docs.digpangolin.com/manage/sites/configure-site#docker-socket-integration"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="text-primary hover:underline inline-flex items-center"
|
||||
|
||||
@@ -326,7 +326,7 @@ export default function PoliciesPage() {
|
||||
{/*TODO(vlalx): Validate replacing */}
|
||||
{t('orgPoliciesAboutDescription')}{" "}
|
||||
<Link
|
||||
href="https://docs.fossorial.io/Pangolin/Identity%20Providers/auto-provision"
|
||||
href="https://docs.digpangolin.com/manage/identity-providers/auto-provisioning"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="text-primary hover:underline"
|
||||
|
||||
@@ -59,9 +59,14 @@ export default async function ResourceAuthPage(props: {
|
||||
try {
|
||||
const serverResourceHost = new URL(authInfo.url).host;
|
||||
const redirectHost = new URL(searchParams.redirect).host;
|
||||
const redirectPort = new URL(searchParams.redirect).port;
|
||||
const serverResourceHostWithPort = `${serverResourceHost}:${redirectPort}`;
|
||||
|
||||
|
||||
if (serverResourceHost === redirectHost) {
|
||||
redirectUrl = searchParams.redirect;
|
||||
} else if ( serverResourceHostWithPort === redirectHost ) {
|
||||
redirectUrl = searchParams.redirect;
|
||||
}
|
||||
} catch (e) {}
|
||||
}
|
||||
|
||||
@@ -126,7 +126,7 @@ export function LayoutSidebar({
|
||||
</div>
|
||||
<div className="text-xs text-muted-foreground ">
|
||||
<Link
|
||||
href="https://docs.fossorial.io/"
|
||||
href="https://docs.digpangolin.com/"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="flex items-center justify-center gap-1"
|
||||
|
||||
@@ -219,7 +219,7 @@ export default function SupporterStatus({ isCollapsed = false }: SupporterStatus
|
||||
</Link>{" "}
|
||||
{t('supportKeyPurchase2')}{" "}
|
||||
<Link
|
||||
href="https://docs.fossorial.io/supporter-program"
|
||||
href="https://docs.digpangolin.com/self-host/supporter-program"
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="underline"
|
||||
|
||||
@@ -1,16 +1,36 @@
|
||||
'use server';
|
||||
|
||||
import {cookies} from 'next/headers';
|
||||
import {Locale, defaultLocale} from '@/i18n/config';
|
||||
import { cookies, headers } from 'next/headers';
|
||||
import { Locale, defaultLocale, locales } from '@/i18n/config';
|
||||
|
||||
// In this example the locale is read from a cookie. You could alternatively
|
||||
// also read it from a database, backend service, or any other source.
|
||||
const COOKIE_NAME = 'NEXT_LOCALE';
|
||||
|
||||
export async function getUserLocale() {
|
||||
return (await cookies()).get(COOKIE_NAME)?.value || defaultLocale;
|
||||
export async function getUserLocale(): Promise<Locale> {
|
||||
const cookieLocale = (await cookies()).get(COOKIE_NAME)?.value;
|
||||
|
||||
if (cookieLocale && locales.includes(cookieLocale as Locale)) {
|
||||
return cookieLocale as Locale;
|
||||
}
|
||||
|
||||
const headerList = await headers();
|
||||
const acceptLang = headerList.get('accept-language');
|
||||
|
||||
if (acceptLang) {
|
||||
const browserLang = acceptLang.split(',')[0];
|
||||
const matched = locales.find((locale) =>
|
||||
browserLang.toLowerCase().startsWith(locale.split('-')[0].toLowerCase())
|
||||
);
|
||||
if (matched) {
|
||||
return matched;
|
||||
}
|
||||
}
|
||||
|
||||
return defaultLocale;
|
||||
}
|
||||
|
||||
|
||||
export async function setUserLocale(locale: Locale) {
|
||||
(await cookies()).set(COOKIE_NAME, locale);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user