mirror of
https://github.com/fosrl/pangolin.git
synced 2026-09-08 04:02:54 +02:00
Properly translate
This commit is contained in:
@@ -2388,6 +2388,23 @@
|
|||||||
"sidebarRemoteExitNodes": "Remote Nodes",
|
"sidebarRemoteExitNodes": "Remote Nodes",
|
||||||
"remoteExitNodeId": "ID",
|
"remoteExitNodeId": "ID",
|
||||||
"remoteExitNodeSecretKey": "Secret",
|
"remoteExitNodeSecretKey": "Secret",
|
||||||
|
"remoteExitNodeNetworkingSubnetsTitle": "Remote Subnets",
|
||||||
|
"remoteExitNodeNetworkingSubnetsDescription": "Define the CIDR ranges that this remote exit node will route traffic to. Type a valid CIDR (e.g. <code>10.0.0.0/8</code>) and press Enter to add.",
|
||||||
|
"remoteExitNodeNetworkingSubnetsPlaceholder": "Add a CIDR range (e.g. 10.0.0.0/8)",
|
||||||
|
"remoteExitNodeNetworkingSubnetsSave": "Save Subnets",
|
||||||
|
"remoteExitNodeNetworkingSubnetsSaveSuccessTitle": "Subnets saved",
|
||||||
|
"remoteExitNodeNetworkingSubnetsSaveSuccessDescription": "Remote subnets have been updated successfully.",
|
||||||
|
"remoteExitNodeNetworkingSubnetsLoadError": "Failed to load subnets",
|
||||||
|
"remoteExitNodeNetworkingSubnetsSaveError": "Failed to save subnets",
|
||||||
|
"remoteExitNodeNetworkingLabelsTitle": "Preference Labels",
|
||||||
|
"remoteExitNodeNetworkingLabelsDescription": "Sites with these labels will be enforced to connect through this remote exit node.",
|
||||||
|
"remoteExitNodeNetworkingLabelsButtonText": "Select labels...",
|
||||||
|
"remoteExitNodeNetworkingLabelsSearchPlaceholder": "Search labels...",
|
||||||
|
"remoteExitNodeNetworkingLabelsSave": "Save Labels",
|
||||||
|
"remoteExitNodeNetworkingLabelsSaveSuccessTitle": "Labels saved",
|
||||||
|
"remoteExitNodeNetworkingLabelsSaveSuccessDescription": "Preference labels have been updated successfully.",
|
||||||
|
"remoteExitNodeNetworkingLabelsLoadError": "Failed to load labels",
|
||||||
|
"remoteExitNodeNetworkingLabelsSaveError": "Failed to save labels",
|
||||||
"remoteExitNodeCreate": {
|
"remoteExitNodeCreate": {
|
||||||
"title": "Create Remote Node",
|
"title": "Create Remote Node",
|
||||||
"description": "Create a new self-hosted remote relay and proxy server node",
|
"description": "Create a new self-hosted remote relay and proxy server node",
|
||||||
|
|||||||
+53
-24
@@ -27,11 +27,14 @@ import type { ListRemoteExitNodeResourcesResponse } from "@server/private/router
|
|||||||
import type { SetRemoteExitNodeResourcesResponse } from "@server/private/routers/remoteExitNode/setRemoteExitNodeResources";
|
import type { SetRemoteExitNodeResourcesResponse } from "@server/private/routers/remoteExitNode/setRemoteExitNodeResources";
|
||||||
import type { ListRemoteExitNodePreferenceLabelsResponse } from "@server/private/routers/remoteExitNode/listRemoteExitNodePreferenceLabels";
|
import type { ListRemoteExitNodePreferenceLabelsResponse } from "@server/private/routers/remoteExitNode/listRemoteExitNodePreferenceLabels";
|
||||||
import type { SetRemoteExitNodePreferenceLabelsResponse } from "@server/private/routers/remoteExitNode/setRemoteExitNodePreferenceLabels";
|
import type { SetRemoteExitNodePreferenceLabelsResponse } from "@server/private/routers/remoteExitNode/setRemoteExitNodePreferenceLabels";
|
||||||
|
import { useTranslations } from "next-intl";
|
||||||
|
import { ExternalLink } from "lucide-react";
|
||||||
|
|
||||||
const cidrRegex =
|
const cidrRegex =
|
||||||
/^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\/([0-9]|[1-2][0-9]|3[0-2]))$|^(([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]+|::(ffff(:0{1,4})?:)?((25[0-5]|(2[0-4]|1?[0-9])?[0-9])\.){3}(25[0-5]|(2[0-4]|1?[0-9])?[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1?[0-9])?[0-9])\.){3}(25[0-5]|(2[0-4]|1?[0-9])?[0-9]))(\/([0-9]|[1-9][0-9]|1[0-1][0-9]|12[0-8]))$/;
|
/^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\/([0-9]|[1-2][0-9]|3[0-2]))$|^(([0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]+|::(ffff(:0{1,4})?:)?((25[0-5]|(2[0-4]|1?[0-9])?[0-9])\.){3}(25[0-5]|(2[0-4]|1?[0-9])?[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1?[0-9])?[0-9])\.){3}(25[0-5]|(2[0-4]|1?[0-9])?[0-9]))(\/([0-9]|[1-9][0-9]|1[0-1][0-9]|12[0-8]))$/;
|
||||||
|
|
||||||
export default function NetworkingPage() {
|
export default function NetworkingPage() {
|
||||||
|
const t = useTranslations();
|
||||||
const { env } = useEnvContext();
|
const { env } = useEnvContext();
|
||||||
const api = createApiClient({ env });
|
const api = createApiClient({ env });
|
||||||
const { orgId } = useParams<{
|
const { orgId } = useParams<{
|
||||||
@@ -91,9 +94,10 @@ export default function NetworkingPage() {
|
|||||||
} catch (error) {
|
} catch (error) {
|
||||||
toast({
|
toast({
|
||||||
variant: "destructive",
|
variant: "destructive",
|
||||||
title: "Error",
|
title: t("error"),
|
||||||
description:
|
description:
|
||||||
formatAxiosError(error) || "Failed to load subnets"
|
formatAxiosError(error) ||
|
||||||
|
t("remoteExitNodeNetworkingSubnetsLoadError")
|
||||||
});
|
});
|
||||||
} finally {
|
} finally {
|
||||||
setLoadingSubnets(false);
|
setLoadingSubnets(false);
|
||||||
@@ -117,9 +121,10 @@ export default function NetworkingPage() {
|
|||||||
} catch (error) {
|
} catch (error) {
|
||||||
toast({
|
toast({
|
||||||
variant: "destructive",
|
variant: "destructive",
|
||||||
title: "Error",
|
title: t("error"),
|
||||||
description:
|
description:
|
||||||
formatAxiosError(error) || "Failed to load labels"
|
formatAxiosError(error) ||
|
||||||
|
t("remoteExitNodeNetworkingLabelsLoadError")
|
||||||
});
|
});
|
||||||
} finally {
|
} finally {
|
||||||
setLoadingLabels(false);
|
setLoadingLabels(false);
|
||||||
@@ -138,14 +143,18 @@ export default function NetworkingPage() {
|
|||||||
{ destinations: subnets.map((s) => s.text) }
|
{ destinations: subnets.map((s) => s.text) }
|
||||||
);
|
);
|
||||||
toast({
|
toast({
|
||||||
title: "Subnets saved",
|
title: t("remoteExitNodeNetworkingSubnetsSaveSuccessTitle"),
|
||||||
description: "Remote subnets have been updated successfully."
|
description: t(
|
||||||
|
"remoteExitNodeNetworkingSubnetsSaveSuccessDescription"
|
||||||
|
)
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
toast({
|
toast({
|
||||||
variant: "destructive",
|
variant: "destructive",
|
||||||
title: "Error",
|
title: t("error"),
|
||||||
description: formatAxiosError(error) || "Failed to save subnets"
|
description:
|
||||||
|
formatAxiosError(error) ||
|
||||||
|
t("remoteExitNodeNetworkingSubnetsSaveError")
|
||||||
});
|
});
|
||||||
} finally {
|
} finally {
|
||||||
setSavingSubnets(false);
|
setSavingSubnets(false);
|
||||||
@@ -162,14 +171,18 @@ export default function NetworkingPage() {
|
|||||||
{ labelIds: selectedLabels.map((l) => parseInt(l.id)) }
|
{ labelIds: selectedLabels.map((l) => parseInt(l.id)) }
|
||||||
);
|
);
|
||||||
toast({
|
toast({
|
||||||
title: "Labels saved",
|
title: t("remoteExitNodeNetworkingLabelsSaveSuccessTitle"),
|
||||||
description: "Preference labels have been updated successfully."
|
description: t(
|
||||||
|
"remoteExitNodeNetworkingLabelsSaveSuccessDescription"
|
||||||
|
)
|
||||||
});
|
});
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
toast({
|
toast({
|
||||||
variant: "destructive",
|
variant: "destructive",
|
||||||
title: "Error",
|
title: t("error"),
|
||||||
description: formatAxiosError(error) || "Failed to save labels"
|
description:
|
||||||
|
formatAxiosError(error) ||
|
||||||
|
t("remoteExitNodeNetworkingLabelsSaveError")
|
||||||
});
|
});
|
||||||
} finally {
|
} finally {
|
||||||
setSavingLabels(false);
|
setSavingLabels(false);
|
||||||
@@ -180,18 +193,31 @@ export default function NetworkingPage() {
|
|||||||
<SettingsContainer>
|
<SettingsContainer>
|
||||||
<SettingsSection>
|
<SettingsSection>
|
||||||
<SettingsSectionHeader>
|
<SettingsSectionHeader>
|
||||||
<SettingsSectionTitle>Remote Subnets</SettingsSectionTitle>
|
<SettingsSectionTitle>
|
||||||
|
{t("remoteExitNodeNetworkingSubnetsTitle")}
|
||||||
|
</SettingsSectionTitle>
|
||||||
<SettingsSectionDescription>
|
<SettingsSectionDescription>
|
||||||
Define the CIDR ranges that this remote exit node will
|
{t.rich("remoteExitNodeNetworkingSubnetsDescription", {
|
||||||
route traffic to. Type a valid CIDR (e.g.{" "}
|
code: (chunks) => <code>{chunks}</code>
|
||||||
<code>10.0.0.0/8</code>) and press Enter to add.
|
})}{" "}
|
||||||
|
<a
|
||||||
|
href="https://docs.pangolin.net/placeholder"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
className="text-primary hover:underline inline-flex items-center gap-1"
|
||||||
|
>
|
||||||
|
{t("learnMore")}
|
||||||
|
<ExternalLink className="size-3.5 shrink-0" />
|
||||||
|
</a>
|
||||||
</SettingsSectionDescription>
|
</SettingsSectionDescription>
|
||||||
</SettingsSectionHeader>
|
</SettingsSectionHeader>
|
||||||
<SettingsSectionBody>
|
<SettingsSectionBody>
|
||||||
<TagInput
|
<TagInput
|
||||||
tags={subnets}
|
tags={subnets}
|
||||||
setTags={setSubnets}
|
setTags={setSubnets}
|
||||||
placeholder="Add a CIDR range (e.g. 10.0.0.0/8)"
|
placeholder={t(
|
||||||
|
"remoteExitNodeNetworkingSubnetsPlaceholder"
|
||||||
|
)}
|
||||||
validateTag={(tag) => cidrRegex.test(tag.trim())}
|
validateTag={(tag) => cidrRegex.test(tag.trim())}
|
||||||
activeTagIndex={activeTagIndex}
|
activeTagIndex={activeTagIndex}
|
||||||
setActiveTagIndex={setActiveTagIndex}
|
setActiveTagIndex={setActiveTagIndex}
|
||||||
@@ -202,7 +228,7 @@ export default function NetworkingPage() {
|
|||||||
</SettingsSectionBody>
|
</SettingsSectionBody>
|
||||||
<SettingsSectionFooter>
|
<SettingsSectionFooter>
|
||||||
<Button onClick={handleSaveSubnets} loading={savingSubnets}>
|
<Button onClick={handleSaveSubnets} loading={savingSubnets}>
|
||||||
Save Subnets
|
{t("remoteExitNodeNetworkingSubnetsSave")}
|
||||||
</Button>
|
</Button>
|
||||||
</SettingsSectionFooter>
|
</SettingsSectionFooter>
|
||||||
</SettingsSection>
|
</SettingsSection>
|
||||||
@@ -210,11 +236,10 @@ export default function NetworkingPage() {
|
|||||||
<SettingsSection>
|
<SettingsSection>
|
||||||
<SettingsSectionHeader>
|
<SettingsSectionHeader>
|
||||||
<SettingsSectionTitle>
|
<SettingsSectionTitle>
|
||||||
Preference Labels
|
{t("remoteExitNodeNetworkingLabelsTitle")}
|
||||||
</SettingsSectionTitle>
|
</SettingsSectionTitle>
|
||||||
<SettingsSectionDescription>
|
<SettingsSectionDescription>
|
||||||
Sites with these labels will be enforced to connect
|
{t("remoteExitNodeNetworkingLabelsDescription")}
|
||||||
through this remote exit node.
|
|
||||||
</SettingsSectionDescription>
|
</SettingsSectionDescription>
|
||||||
</SettingsSectionHeader>
|
</SettingsSectionHeader>
|
||||||
<SettingsSectionBody>
|
<SettingsSectionBody>
|
||||||
@@ -225,13 +250,17 @@ export default function NetworkingPage() {
|
|||||||
onSearch={setLabelSearchQuery}
|
onSearch={setLabelSearchQuery}
|
||||||
searchQuery={labelSearchQuery}
|
searchQuery={labelSearchQuery}
|
||||||
disabled={loadingLabels}
|
disabled={loadingLabels}
|
||||||
buttonText="Select labels..."
|
buttonText={t(
|
||||||
searchPlaceholder="Search labels..."
|
"remoteExitNodeNetworkingLabelsButtonText"
|
||||||
|
)}
|
||||||
|
searchPlaceholder={t(
|
||||||
|
"remoteExitNodeNetworkingLabelsSearchPlaceholder"
|
||||||
|
)}
|
||||||
/>
|
/>
|
||||||
</SettingsSectionBody>
|
</SettingsSectionBody>
|
||||||
<SettingsSectionFooter>
|
<SettingsSectionFooter>
|
||||||
<Button onClick={handleSaveLabels} loading={savingLabels}>
|
<Button onClick={handleSaveLabels} loading={savingLabels}>
|
||||||
Save Labels
|
{t("remoteExitNodeNetworkingLabelsSave")}
|
||||||
</Button>
|
</Button>
|
||||||
</SettingsSectionFooter>
|
</SettingsSectionFooter>
|
||||||
</SettingsSection>
|
</SettingsSection>
|
||||||
|
|||||||
Reference in New Issue
Block a user