// Bilingual i18n dictionary for app.html const APP_I18N = { en: { common: { search: "Search…", save: "Save", cancel: "Cancel", delete: "Delete", online: "online", offline: "offline", signOut: "Sign out", settings: "Settings", language: "Language", theme: "Theme", light: "Light", dark: "Dark", backToSite: "Back to site", upgrade: "Upgrade", }, roles: { owner: "Owner", editor: "Editor", reader: "Reader", }, plans: { free: "Basic", pro: "Pro", enterprise: "Enterprise" }, nav: { networks: "Network", support: "Support", }, networks: { title: "Networks", new: "New network", name: "Name", cidr: "CIDR", plan: "Plan", devices: "Devices", lastActivity: "Last activity", }, network: { devicesTab: "Devices", topologyTab: "Topology", performanceTab: "Performance", routesTab: "Routes", dnsTab: "MagicDNS", aclTab: "ACL", qosTab: "QoS", netflowTab: "Traffic", auditTab: "Audit", billingTab: "Billing", settingsTab: "Settings", ruleSrc: "src", ruleDst: "dst", ruleVia: "via", ruleNat: "NAT", ruleAction: "action", ruleKind: "kind", routesAdvTitle: "Route advertisements", routesAdvHelp: "Each node (node:xxx) advertises CIDRs it can reach inside the mesh. Nodes install accepted advertisements as system routes.", routesAdvBy: "advertised by", routesAdvType: "type", routesStatus: "status", routesCidr: "route", routesMasqTitle: "Masquerade rules", routesMasqHelp: "Pin out-of-mesh traffic to a specific egress node. Src is node:xxx or a CIDR. Dst is anything NOT covered by an advertisement — L3: external CIDR; L7: hostname (wildcard / regex). Toggle NAT on the via node if needed.", routesRule: "Rule", aclTitle: "ACL rules", aclRule: "Rule", aclHelp: "Filter traffic. Src is node:xxx or CIDR. Dst is node:xxx, CIDR, or hostname (wildcard / regex — L7 only). Default deny. Top-down evaluation; first match wins.", dnsHelp: "MagicDNS serves *.widewired hostnames from node gossip. No resolver config needed.", qosHelp: "QoS rules tag matching flows with DSCP and enforce rate limits at each node. Applied at egress on the sending node.", qosRules: "Rules", qosAdd: "Rule", qosMatch: "match", qosDscp: "DSCP", qosRate: "rate", qosPriority: "priority", netflowChart: "Throughput · last 60 min (Mbps)", netflowProto: "Protocol mix", netflowTop: "Top flows", netflowPair: "pair", netflowProtoCol: "proto/port", netflowBytes: "bytes", netflowFlows: "flows", netflowSearch: "Search flows…", netflowAllProto: "all protocols", netflowAllPeer: "all nodes", installCode: "Config code", installCopy: "Copy", installRegen: "Regenerate", installExpiry: "Expires in 14:52", auditTitle: "Audit log", auditAllActions: "all actions", auditTimestamp: "timestamp", auditAction: "action", auditSubject: "subject", auditActor: "actor", auditIp: "ip", devicesTitle: "Devices", exportCsv: "Export CSV", approve: "Approve", revoke: "Revoke", pending: "pending", deviceColumns: ["name", "ip", "os", "status", "last seen"], membersTitle: "Members", membersHelp: "Invite users to this network. Each member gets a per-network role: Owner manages billing & settings, Editor edits config, Reader has read-only access.", addressTitle: "Network CIDR", addressHelp: "The network CIDR defines the IP pool assigned to nodes. Changing the CIDR re-addresses every node on next handshake.", addressNetwork: "Network", addressUsable: "Usable", addressHosts: "hosts", addressUsed: "Assigned", settingsGeneral: "General", tokensTitle: "API tokens", deleteBody: "Deleting this network removes all devices, ACL, DNS, NetFlow history, and invoices. This cannot be undone.", }, topology: { graph: "Graph", }, matrix: { title: "Connectivity matrix", legend: ["direct", "user_relay", "managed_relay", "unreachable"], selected: "selected", rtt: "rtt", loss: "loss", path: "path", hint: "Click a cell to inspect the pair. Hover for RTT.", }, members: { invite: "Invite", member: "member", role: "Role", joined: "Joined", lastSeen: "Last seen", inviteEmail: "Email", inviteRole: "Role", sendInvite: "Send invite", }, billing: { invoices: "Invoices", invoiceDate: "Date", invoiceAmount: "Amount", invoiceItem: "Item", invoiceStatus: "Status", invoiceDownload: "PDF", current: "current", downgrade: "Downgrade", freeBlurb: "Up to 10 devices · community support", proBlurb: "Up to 100 devices · managed_relay · IPSec bridge", entBlurb: "Unlimited devices · SSO · audit export · SLA", infoTitle: "Billing information", company: "Company", taxId: "Tax ID / VAT", address1: "Street address", city: "City", postal: "Postal code", country: "Country", email: "Billing email", method: "Payment method", update: "Update", }, tokens: { accountHint: "Account-level token. Authenticates as your user across every network you can access. Treat it like a password.", networkHint: "Network-level token. Scoped to this network only — it cannot read or modify any other network.", add: "Token", revoke: "revoke", colName: "name", colToken: "token", colScopes: "scopes", colCreated: "created", colExpires: "expires", }, settings: { title: "Settings", account: "Account", name: "Name", email: "Email", mfa: "Multi-factor authentication", mfaOn: "Enabled", configure: "Configure", password: "Password", passwordHint: "Last changed 2026-02-04", changePassword: "Change password", dangerZone: "Danger zone", deleteBody: "Deleting your account removes you from every network. Networks you solely own will be archived. This cannot be undone.", deleteMe: "Delete my account", tokensTitle: "API tokens", }, support: { newTicket: "New ticket", opened: "opened", subject: "subject", state: "state", lastUpdate: "last update", }, }, zh: { common: { search: "搜索…", save: "保存", cancel: "取消", delete: "删除", online: "在线", offline: "离线", signOut: "退出登录", settings: "设置", language: "语言", theme: "主题", light: "浅色", dark: "深色", backToSite: "返回官网", upgrade: "升级", }, roles: { owner: "所有者", editor: "编辑", reader: "只读", }, plans: { free: "基础版", pro: "专业版", enterprise: "企业版" }, nav: { networks: "网络", support: "支持", }, networks: { title: "网络", new: "新建网络", name: "名称", cidr: "网段", plan: "计划", devices: "设备", lastActivity: "最近活动", }, network: { devicesTab: "设备", topologyTab: "拓扑", performanceTab: "性能", routesTab: "路由", dnsTab: "MagicDNS", aclTab: "ACL", qosTab: "QoS", netflowTab: "流量", auditTab: "审计", billingTab: "账单", settingsTab: "设置", ruleSrc: "来源", ruleDst: "目标", ruleVia: "出口", ruleNat: "NAT", ruleAction: "动作", ruleKind: "类型", routesAdvTitle: "路由宣告", routesAdvHelp: "每个节点(node:xxx)宣告它在网内可达的网段。被接受的宣告会作为系统路由安装到各 node。", routesAdvBy: "宣告设备", routesAdvType: "类型", routesStatus: "状态", routesCidr: "网段", routesMasqTitle: "伪装规则", routesMasqHelp: "将网外流量固定到指定出口节点。来源为 node:xxx 或 CIDR;目标为不在路由宣告范围内的对象 —— L3:外部网段;L7:域名(通配符或正则)。需要时在出口节点开启 NAT。", routesRule: "规则", aclTitle: "ACL 规则", aclRule: "规则", aclHelp: "过滤流量。来源为 node:xxx 或 CIDR;目标为 node:xxx、CIDR 或域名(通配符 / 正则,仅 L7)。默认拒绝;规则按顺序匹配,命中即停。", dnsHelp: "MagicDNS 通过 node gossip 服务 *.widewired 主机名,客户端无需配置解析器。", qosHelp: "QoS 规则为匹配的流打 DSCP 标记,并在每个 node 上执行速率限制。在发送端出方向生效。", qosRules: "规则", qosAdd: "规则", qosMatch: "匹配", qosDscp: "DSCP", qosRate: "速率", qosPriority: "优先级", netflowChart: "吞吐 · 近 60 分钟(Mbps)", netflowProto: "协议分布", netflowTop: "头部流量", netflowPair: "通信对", netflowProtoCol: "协议/端口", netflowBytes: "字节数", netflowFlows: "流数", netflowSearch: "搜索流量…", netflowAllProto: "全部协议", netflowAllPeer: "全部 node", installCode: "配置码", installCopy: "复制", installRegen: "重新生成", installExpiry: "14:52 后失效", auditTitle: "审计日志", auditAllActions: "全部动作", auditTimestamp: "时间", auditAction: "动作", auditSubject: "对象", auditActor: "操作人", auditIp: "IP", devicesTitle: "设备", exportCsv: "导出 CSV", approve: "批准", revoke: "撤销", pending: "待审批", deviceColumns: ["名称", "IP", "系统", "状态", "最后在线"], membersTitle: "成员", membersHelp: "邀请用户加入本网络。每位成员拥有网络内角色:所有者可管理账单与设置,编辑可修改配置,只读仅可查看。", addressTitle: "网络 CIDR", addressHelp: "网段定义了分配给 node 的 IP 池。修改网段后,各 node 将在下次握手时重新分配地址。", addressNetwork: "网络", addressUsable: "可用", addressHosts: "主机数", addressUsed: "已分配", settingsGeneral: "基本", tokensTitle: "API Token", deleteBody: "删除本网络将移除所有设备、ACL、DNS、NetFlow 历史与发票。此操作不可撤销。", }, topology: { graph: "拓扑图", }, matrix: { title: "连通矩阵", legend: ["直连", "自有中继", "托管中继", "不可达"], selected: "选中", rtt: "RTT", loss: "丢包", path: "路径", hint: "点击单元格查看详情。悬停查看 RTT。", }, members: { invite: "邀请", member: "成员", role: "角色", joined: "加入时间", lastSeen: "最后在线", inviteEmail: "邮箱", inviteRole: "角色", sendInvite: "发送邀请", }, billing: { invoices: "发票", invoiceDate: "日期", invoiceAmount: "金额", invoiceItem: "项目", invoiceStatus: "状态", invoiceDownload: "PDF", current: "当前", downgrade: "降级", freeBlurb: "最多 10 台设备 · 社区支持", proBlurb: "最多 100 台设备 · 托管中继 · IPSec 桥接", entBlurb: "无限设备 · SSO · 审计导出 · SLA", infoTitle: "账单信息", company: "公司名称", taxId: "税号 / VAT", address1: "详细地址", city: "城市", postal: "邮编", country: "国家 / 地区", email: "账单邮箱", method: "支付方式", update: "更新", }, tokens: { accountHint: "账号级 Token。以你账号身份访问所有可见网络,请像保管密码一样妥善保管。", networkHint: "网络级 Token。仅作用于本网络,无法读取或修改其他网络。", add: "Token", revoke: "撤销", colName: "名称", colToken: "Token", colScopes: "权限", colCreated: "创建时间", colExpires: "过期时间", }, settings: { title: "设置", account: "账号", name: "姓名", email: "邮箱", mfa: "多因素认证", mfaOn: "已启用", configure: "配置", password: "密码", passwordHint: "上次修改 2026-02-04", changePassword: "修改密码", dangerZone: "危险操作", deleteBody: "删除账号后你将被移出所有网络。由你独自拥有的网络将被归档。此操作不可撤销。", deleteMe: "删除我的账号", tokensTitle: "API Token", }, support: { newTicket: "新建工单", opened: "创建时间", subject: "主题", state: "状态", lastUpdate: "最近更新", }, }, }; window.APP_I18N = APP_I18N;