diff --git a/messages/en-US.json b/messages/en-US.json
index 41937e61e..b8cf7d592 100644
--- a/messages/en-US.json
+++ b/messages/en-US.json
@@ -2388,6 +2388,23 @@
"sidebarRemoteExitNodes": "Remote Nodes",
"remoteExitNodeId": "ID",
"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. 10.0.0.0/8) 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": {
"title": "Create Remote Node",
"description": "Create a new self-hosted remote relay and proxy server node",
diff --git a/src/app/[orgId]/settings/(private)/remote-exit-nodes/[remoteExitNodeId]/networking/page.tsx b/src/app/[orgId]/settings/(private)/remote-exit-nodes/[remoteExitNodeId]/networking/page.tsx
index a0da030ff..abac12488 100644
--- a/src/app/[orgId]/settings/(private)/remote-exit-nodes/[remoteExitNodeId]/networking/page.tsx
+++ b/src/app/[orgId]/settings/(private)/remote-exit-nodes/[remoteExitNodeId]/networking/page.tsx
@@ -27,11 +27,14 @@ import type { ListRemoteExitNodeResourcesResponse } from "@server/private/router
import type { SetRemoteExitNodeResourcesResponse } from "@server/private/routers/remoteExitNode/setRemoteExitNodeResources";
import type { ListRemoteExitNodePreferenceLabelsResponse } from "@server/private/routers/remoteExitNode/listRemoteExitNodePreferenceLabels";
import type { SetRemoteExitNodePreferenceLabelsResponse } from "@server/private/routers/remoteExitNode/setRemoteExitNodePreferenceLabels";
+import { useTranslations } from "next-intl";
+import { ExternalLink } from "lucide-react";
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]))$/;
export default function NetworkingPage() {
+ const t = useTranslations();
const { env } = useEnvContext();
const api = createApiClient({ env });
const { orgId } = useParams<{
@@ -91,9 +94,10 @@ export default function NetworkingPage() {
} catch (error) {
toast({
variant: "destructive",
- title: "Error",
+ title: t("error"),
description:
- formatAxiosError(error) || "Failed to load subnets"
+ formatAxiosError(error) ||
+ t("remoteExitNodeNetworkingSubnetsLoadError")
});
} finally {
setLoadingSubnets(false);
@@ -117,9 +121,10 @@ export default function NetworkingPage() {
} catch (error) {
toast({
variant: "destructive",
- title: "Error",
+ title: t("error"),
description:
- formatAxiosError(error) || "Failed to load labels"
+ formatAxiosError(error) ||
+ t("remoteExitNodeNetworkingLabelsLoadError")
});
} finally {
setLoadingLabels(false);
@@ -138,14 +143,18 @@ export default function NetworkingPage() {
{ destinations: subnets.map((s) => s.text) }
);
toast({
- title: "Subnets saved",
- description: "Remote subnets have been updated successfully."
+ title: t("remoteExitNodeNetworkingSubnetsSaveSuccessTitle"),
+ description: t(
+ "remoteExitNodeNetworkingSubnetsSaveSuccessDescription"
+ )
});
} catch (error) {
toast({
variant: "destructive",
- title: "Error",
- description: formatAxiosError(error) || "Failed to save subnets"
+ title: t("error"),
+ description:
+ formatAxiosError(error) ||
+ t("remoteExitNodeNetworkingSubnetsSaveError")
});
} finally {
setSavingSubnets(false);
@@ -162,14 +171,18 @@ export default function NetworkingPage() {
{ labelIds: selectedLabels.map((l) => parseInt(l.id)) }
);
toast({
- title: "Labels saved",
- description: "Preference labels have been updated successfully."
+ title: t("remoteExitNodeNetworkingLabelsSaveSuccessTitle"),
+ description: t(
+ "remoteExitNodeNetworkingLabelsSaveSuccessDescription"
+ )
});
} catch (error) {
toast({
variant: "destructive",
- title: "Error",
- description: formatAxiosError(error) || "Failed to save labels"
+ title: t("error"),
+ description:
+ formatAxiosError(error) ||
+ t("remoteExitNodeNetworkingLabelsSaveError")
});
} finally {
setSavingLabels(false);
@@ -180,18 +193,31 @@ export default function NetworkingPage() {
- Remote Subnets
+
+ {t("remoteExitNodeNetworkingSubnetsTitle")}
+
- Define the CIDR ranges that this remote exit node will
- route traffic to. Type a valid CIDR (e.g.{" "}
- 10.0.0.0/8) and press Enter to add.
+ {t.rich("remoteExitNodeNetworkingSubnetsDescription", {
+ code: (chunks) => {chunks}
+ })}{" "}
+
+ {t("learnMore")}
+
+
cidrRegex.test(tag.trim())}
activeTagIndex={activeTagIndex}
setActiveTagIndex={setActiveTagIndex}
@@ -202,7 +228,7 @@ export default function NetworkingPage() {
@@ -210,11 +236,10 @@ export default function NetworkingPage() {
- Preference Labels
+ {t("remoteExitNodeNetworkingLabelsTitle")}
- Sites with these labels will be enforced to connect
- through this remote exit node.
+ {t("remoteExitNodeNetworkingLabelsDescription")}
@@ -225,13 +250,17 @@ export default function NetworkingPage() {
onSearch={setLabelSearchQuery}
searchQuery={labelSearchQuery}
disabled={loadingLabels}
- buttonText="Select labels..."
- searchPlaceholder="Search labels..."
+ buttonText={t(
+ "remoteExitNodeNetworkingLabelsButtonText"
+ )}
+ searchPlaceholder={t(
+ "remoteExitNodeNetworkingLabelsSearchPlaceholder"
+ )}
/>