diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 000000000..f6bbf6bab --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,13 @@ +{ + "name": "meshtastic-web", + "image": "mcr.microsoft.com/devcontainers/typescript-node:1-22-bookworm", + "features": { + "ghcr.io/r3dpoint/devcontainer-features/tailwindcss-standalone-cli:1": { + "version": "latest" + }, + "ghcr.io/devcontainers-extra/features/pnpm:2": { + "version": "latest" + } + } +} + diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 129022510..bf7c51ba7 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -40,7 +40,7 @@ jobs: set -euo pipefail # List packages to exclude (full paths under repo root) - EXCLUDED_DIRS=("packages/protobufs" "packages/transport-deno") + EXCLUDED_DIRS=("packages/protobufs" "packages/transport-deno" "packages/ui" "pacakges/web") is_excluded() { local dir="$1" diff --git a/.github/workflows/inactive-issue.yml b/.github/workflows/inactive-issue.yml new file mode 100644 index 000000000..7e23f4212 --- /dev/null +++ b/.github/workflows/inactive-issue.yml @@ -0,0 +1,24 @@ +name: Close inactive issues +on: + schedule: + - cron: "0 */4 * * *" # every 4 hours + workflow_dispatch: # allow manual runs +jobs: + close-issues: + runs-on: ubuntu-latest + permissions: + issues: write + pull-requests: write + steps: + - uses: actions/stale@v10 + with: + repo-token: ${{ secrets.GITHUB_TOKEN }} + days-before-issue-stale: 60 + days-before-issue-close: 14 + stale-issue-label: "stale" + stale-issue-message: "This issue is stale because it has been open for 60 days with no activity." + close-issue-message: "This issue was closed because it has been inactive for 14 days since being marked as stale." + days-before-pr-stale: -1 + days-before-pr-close: -1 + only-issue-labels: "Bug" + remove-stale-when-updated: true diff --git a/.github/workflows/nightly.yml b/.github/workflows/nightly.yml index 2780db93d..807e86003 100644 --- a/.github/workflows/nightly.yml +++ b/.github/workflows/nightly.yml @@ -97,7 +97,7 @@ jobs: ${{ steps.meta.outputs.moving_tag }} ${{ steps.meta.outputs.immutable_tag }} oci: true - platforms: linux/amd64,linux/arm64 + platforms: linux/amd64,linux/arm64,linux/arm/v7 labels: | org.opencontainers.image.source=${{ github.repository }} org.opencontainers.image.revision=${{ github.sha }} diff --git a/.github/workflows/release-web.yml b/.github/workflows/release-web.yml index f8dbb8632..28c69ff7c 100644 --- a/.github/workflows/release-web.yml +++ b/.github/workflows/release-web.yml @@ -135,7 +135,7 @@ jobs: with: context: . file: ./packages/web/infra/Containerfile - platforms: linux/amd64,linux/arm64 + platforms: linux/amd64,linux/arm64,linux/arm/v7 push: ${{ github.event_name == 'release' || (github.event_name == 'workflow_dispatch' && inputs.tag_name != '') }} tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} diff --git a/.github/workflows/update-stable-from-master.yml b/.github/workflows/update-stable-from-master.yml index 39bda8e6e..3de8f0cc3 100644 --- a/.github/workflows/update-stable-from-master.yml +++ b/.github/workflows/update-stable-from-master.yml @@ -15,59 +15,81 @@ jobs: update-stable-branch: name: Update stable from latest release source runs-on: ubuntu-latest - steps: - name: Checkout repository uses: actions/checkout@v4 with: - fetch-depth: 0 # need full history for reset/push + fetch-depth: 0 + fetch-tags: true # IMPORTANT: we need tags to resolve the release commit - name: Configure Git author run: | git config user.name "github-actions[bot]" git config user.email "github-actions[bot]@users.noreply.github.com" - - name: Determine source ref & SHA + - name: Determine source SHA (prefer tag) id: meta shell: bash run: | set -euo pipefail - SRC="${{ github.event.release.target_commitish }}" - if [ -z "$SRC" ] || ! git ls-remote --exit-code origin "refs/heads/$SRC" >/dev/null 2>&1; then - # Fallback to main if target_commitish is empty or not a branch - SRC="main" + + TAG="${{ github.event.release.tag_name }}" + TARGET="${{ github.event.release.target_commitish || '' }}" + + # Always ensure we have latest remote heads/tags + git fetch --tags --prune origin + + SHA="" + SRC_DESC="" + + # 1) Prefer the release tag commit + if [ -n "${TAG}" ] && git rev-parse -q --verify "refs/tags/${TAG}" >/dev/null; then + SHA="$(git rev-list -n1 "${TAG}")" + SRC_DESC="tag:${TAG}" fi - echo "Using source branch: $SRC" - git fetch origin "$SRC":"refs/remotes/origin/$SRC" --prune - SHA="$(git rev-parse "origin/$SRC")" - echo "sha=$SHA" >> "$GITHUB_OUTPUT" - echo "src=$SRC" >> "$GITHUB_OUTPUT" + # 2) Fall back to target_commitish if it points to a branch on origin + if [ -z "${SHA}" ] && [ -n "${TARGET}" ] && git ls-remote --exit-code --heads origin "${TARGET}" >/dev/null 2>&1; then + git fetch origin "${TARGET}:${TARGET}" --prune + SHA="$(git rev-parse "${TARGET}^{commit}")" + SRC_DESC="branch:${TARGET}" + fi + + # 3) Fall back to main if present + if [ -z "${SHA}" ] && git ls-remote --exit-code --heads origin "main" >/dev/null 2>&1; then + git fetch origin "main:main" --prune + SHA="$(git rev-parse "main^{commit}")" + SRC_DESC="branch:main" + fi - - name: Prepare local stable branch + if [ -z "${SHA}" ]; then + echo "::error::Unable to resolve source commit from tag (${TAG}), target_commitish (${TARGET}), or main." + exit 1 + fi + + echo "Using source: ${SRC_DESC}" + echo "sha=${SHA}" >> "$GITHUB_OUTPUT" + echo "source=${SRC_DESC}" >> "$GITHUB_OUTPUT" + + - name: Create/reset local stable to SHA shell: bash run: | set -euo pipefail - # Ensure we have the remote stable ref if it exists + # Make sure we know if remote stable exists (non-fatal if not) git fetch origin stable:refs/remotes/origin/stable || true - if git show-ref --verify --quiet refs/heads/stable; then - echo "Local stable exists." - elif git show-ref --verify --quiet refs/remotes/origin/stable; then - echo "Creating local stable tracking branch from remote." - git checkout -b stable --track origin/stable - else - echo "Creating new local stable branch at source SHA." - git checkout -b stable "${{ steps.meta.outputs.sha }}" - fi - - - name: Reset stable to source SHA - run: | - git checkout stable - git reset --hard "${{ steps.meta.outputs.sha }}" + # Create or reset local stable in one command + git checkout -B stable "${{ steps.meta.outputs.sha }}" git status --short --branch - name: Push stable (force-with-lease) run: | - # Safer than --force; refuses if remote moved unexpectedly - git push origin stable --force-with-lease + # Safer than --force; refuses if remote moved unexpectedly (protects against races) + REMOTE_STABLE_SHA="$(git rev-parse refs/remotes/origin/stable || echo '')" + if [ -z "$REMOTE_STABLE_SHA" ]; then + # If remote stable doesn't exist, just use --force-with-lease=stable (no SHA) + git push origin stable:stable --force-with-lease=stable + else + # Use the specific SHA for maximum safety + git push origin stable:stable --force-with-lease=stable:$REMOTE_STABLE_SHA + fi diff --git a/.gitignore b/.gitignore index cb8f36f4f..7c03ebef4 100644 --- a/.gitignore +++ b/.gitignore @@ -9,5 +9,12 @@ __screenshots__* npm/ .idea **/LICENSE +.DS_Store packages/protobufs/packages/ts/dist +.pnpm-store/ + +# Local dev certs +*.pem +*.crt +*.key diff --git a/README.md b/README.md index 654c216fc..0791b1a41 100644 --- a/README.md +++ b/README.md @@ -12,6 +12,9 @@ This monorepo consolidates the official [Meshtastic](https://meshtastic.org) web interface and its supporting JavaScript libraries. It aims to provide a unified development experience for interacting with Meshtastic devices. +> [!NOTE] +> You can find the main Meshtastic documentation at https://meshtastic.org/docs/introduction/. + ### Projects within this Monorepo (`packages/`) All projects are located within the `packages/` directory: @@ -33,7 +36,7 @@ All `Meshtastic JS` packages (core and transports) are published both to --- -## Stats +## Repository activity | Project | Repobeats | | :------------- | :-------------------------------------------------------------------------------------------------------------------- | @@ -74,6 +77,9 @@ Follow the installation instructions on their home page. ``` This command installs all necessary dependencies for all packages within the monorepo. +3. **Install the Buf CLI** + Required for building `packages/protobufs` + https://buf.build/docs/cli/installation/ ### Running Projects @@ -87,28 +93,18 @@ If you encounter any issues, please report them in our [issues tracker](https://github.com/meshtastic/web/issues). Your feedback helps improve the stability of future releases -### Contributing - -We welcome contributions! Here’s how the deployment flow works for pull -requests: - -- **Preview Deployments:**\ - Every pull request automatically generates a preview deployment on Vercel. - This allows you and reviewers to easily preview changes before merging. +## Star history -- **Staging Environment (`client-test`):**\ - Once your PR is merged, your changes will be available on our staging site: - [client-test.meshtastic.org](https://client-test.meshtastic.org/).\ - This environment supports rapid feature iteration and testing without - impacting the production site. + + + + + Star History Chart + + -- **Production Releases:**\ - At regular intervals, stable and fully tested releases are promoted to our - production site: [client.meshtastic.org](https://client.meshtastic.org/).\ - This is the primary interface used by the public to connect with their - Meshtastic nodes. +## Contributors -Please review our -[Contribution Guidelines](https://github.com/meshtastic/web/blob/main/CONTRIBUTING.md) -before submitting a pull request. We appreciate your help in making the project -better! + + + diff --git a/biome.json b/biome.json index bfe66739d..eb286f6cb 100644 --- a/biome.json +++ b/biome.json @@ -4,10 +4,13 @@ "**/*.ts", "**/*.tsx", "!npm_modules", - "!dist", + "!**/dist", + "!**/protobufs", + "!**/.*", "!npm", "**/*.json", - "!**/locales/*-*/*.json" + "!**/locales/*-*/*.json", + "!**/packages/ui/" ], "ignoreUnknown": false }, @@ -21,7 +24,7 @@ }, "linter": { "enabled": true, - "includes": ["**", "!test/**"], + "includes": ["**", "!test/**", "!**/dist/**"], "rules": { "recommended": true, "suspicious": { diff --git a/package.json b/package.json index 276c9eeb7..6f0e13b17 100644 --- a/package.json +++ b/package.json @@ -35,14 +35,15 @@ "tslog": "^4.9.3" }, "devDependencies": { - "@types/node": "^24.3.1", "@biomejs/biome": "2.2.4", + "@types/node": "^24.3.1", "tsdown": "^0.15.0", "typescript": "^5.9.2", "vitest": "^3.2.4" }, "pnpm": { "onlyBuiltDependencies": [ + "@serialport/bindings-cpp", "@tailwindcss/oxide", "core-js", "esbuild", diff --git a/packages/core/package.json b/packages/core/package.json index c44910cf5..da9343432 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -12,6 +12,7 @@ "license": "GPL-3.0-only", "tsdown": { "entry": "mod.ts", + "platform": "browser", "dts": true, "format": [ "esm" diff --git a/packages/core/src/types.ts b/packages/core/src/types.ts index 751f4a6c0..8f055d671 100644 --- a/packages/core/src/types.ts +++ b/packages/core/src/types.ts @@ -46,6 +46,7 @@ export enum DeviceStatusEnum { DeviceConnected = 5, DeviceConfiguring = 6, DeviceConfigured = 7, + DeviceError = 8, } export type LogEventPacket = LogEvent & { date: Date }; diff --git a/packages/core/src/utils/eventSystem.ts b/packages/core/src/utils/eventSystem.ts index 81b24d341..f139c0d94 100644 --- a/packages/core/src/utils/eventSystem.ts +++ b/packages/core/src/utils/eventSystem.ts @@ -387,4 +387,12 @@ export class EventSystem { */ public readonly onQueueStatus: SimpleEventDispatcher = new SimpleEventDispatcher(); + + /** + * Fires when a configCompleteId message is received from the device + * + * @event onConfigComplete + */ + public readonly onConfigComplete: SimpleEventDispatcher = + new SimpleEventDispatcher(); } diff --git a/packages/core/src/utils/transform/decodePacket.ts b/packages/core/src/utils/transform/decodePacket.ts index 257ff0bf5..068964039 100644 --- a/packages/core/src/utils/transform/decodePacket.ts +++ b/packages/core/src/utils/transform/decodePacket.ts @@ -135,21 +135,27 @@ export const decodePacket = (device: MeshDevice) => } case "configCompleteId": { - if (decodedMessage.payloadVariant.value !== device.configId) { - device.log.error( - Types.Emitter[Types.Emitter.HandleFromRadio], - `❌ Invalid config id received from device, expected ${device.configId} but received ${decodedMessage.payloadVariant.value}`, - ); - } - device.log.info( Types.Emitter[Types.Emitter.HandleFromRadio], - `⚙️ Valid config id received from device: ${device.configId}`, + `⚙️ Received config complete id: ${decodedMessage.payloadVariant.value}`, ); - device.updateDeviceStatus( - Types.DeviceStatusEnum.DeviceConfigured, + // Emit the configCompleteId event for MeshService to handle two-stage flow + device.events.onConfigComplete.dispatch( + decodedMessage.payloadVariant.value, ); + + // For backward compatibility: if configId matches, update device status + // MeshService will override this behavior for two-stage flow + if (decodedMessage.payloadVariant.value === device.configId) { + device.log.info( + Types.Emitter[Types.Emitter.HandleFromRadio], + `⚙️ Config id matches device.configId: ${device.configId}`, + ); + device.updateDeviceStatus( + Types.DeviceStatusEnum.DeviceConfigured, + ); + } break; } diff --git a/packages/ui/components.json b/packages/ui/components.json new file mode 100644 index 000000000..3e90654ec --- /dev/null +++ b/packages/ui/components.json @@ -0,0 +1,22 @@ +{ + "$schema": "https://ui.shadcn.com/schema.json", + "style": "new-york", + "rsc": false, + "tsx": true, + "tailwind": { + "config": "", + "css": "src/base.css", + "baseColor": "slate", + "cssVariables": true, + "prefix": "" + }, + "iconLibrary": "lucide", + "aliases": { + "components": "@/components", + "utils": "@/lib/utils", + "ui": "@/components/ui", + "lib": "@/lib", + "hooks": "@/hooks" + }, + "registries": {} +} diff --git a/packages/ui/package.json b/packages/ui/package.json new file mode 100644 index 000000000..f12f10e1a --- /dev/null +++ b/packages/ui/package.json @@ -0,0 +1,76 @@ +{ + "name": "@meshtastic/ui", + "version": "0.1.0", + "license": "GPL-3.0-only", + "repository": { + "type": "git", + "url": "git+https://github.com/meshtastic/web.git" + }, + "type": "module", + "files": [ + "dist", + "!dist/**/*.test.*" + ], + "sideEffects": [ + "**/*.css" + ], + "exports": { + ".": { + "types": "./dist/index.d.ts", + "default": "./dist/index.js" + }, + "./theme/default.css": "./dist/theme/default.css" + }, + "main": "./dist/index.js", + "module": "./dist/index.js", + "types": "./dist/index.d.ts", + "scripts": { + "start": "npm run dev", + "dev": "vite dev", + "watch": "vite build --watch", + "build": "vite build && publint", + "typecheck": "tsc -p tsconfig.json --noEmit", + "preview": "vite preview", + "lint": "eslint . --max-warnings 0", + "lint:fix": "npm run lint -- --fix", + "format": "prettier --check .", + "format:fix": "prettier --write .", + "test": "vitest" + }, + "peerDependencies": { + "@radix-ui/react-slot": ">=1.0.2", + "class-variance-authority": ">=0.7.0", + "react": ">=19", + "react-dom": ">=19", + "tailwind-merge": ">=2.5.0", + "tailwindcss": "^4.1.7" + }, + "dependencies": { + "@radix-ui/react-collapsible": "^1.1.12", + "@radix-ui/react-dialog": "^1.1.15", + "@radix-ui/react-dropdown-menu": "^2.1.16", + "@radix-ui/react-separator": "^1.1.7", + "@radix-ui/react-slot": "^1.2.3", + "@radix-ui/react-tooltip": "^1.2.8", + "@tanstack/react-router": "^1.132.47", + "class-variance-authority": "^0.7.1", + "clsx": "^2.1.1", + "lucide-react": "^0.545.0", + "tailwind-merge": "^2.6.0" + }, + "devDependencies": { + "@tailwindcss/postcss": "^4.1.7", + "@tailwindcss/vite": "^4.1.14", + "@types/react": "^18.3.5", + "@types/react-dom": "^18.3.0", + "@vitejs/plugin-react": "^4.3.4", + "publint": "^0.3.14", + "tailwindcss": "^4.1.14", + "tw-animate-css": "^1.4.0", + "typescript": "^5.6.3", + "vite": "^7.0.0", + "vite-plugin-dts": "^4.5.4", + "vite-plugin-static-copy": "^3.1.4", + "vitest": "^3.0.0" + } +} diff --git a/packages/ui/src/app.css b/packages/ui/src/app.css new file mode 100644 index 000000000..33a766b1a --- /dev/null +++ b/packages/ui/src/app.css @@ -0,0 +1,7 @@ +body.dark { + color-scheme: dark; +} + +body:not(.dark) { + color-scheme: light; +} \ No newline at end of file diff --git a/packages/ui/src/components/theme-provider.tsx b/packages/ui/src/components/theme-provider.tsx new file mode 100644 index 000000000..c63f43c20 --- /dev/null +++ b/packages/ui/src/components/theme-provider.tsx @@ -0,0 +1,77 @@ +import { createContext, useContext, useEffect, useState } from "react"; + +type Theme = "dark" | "light" | "system"; + +type ThemeProviderProps = { + children: React.ReactNode; + defaultTheme?: Theme; + storageKey?: string; +}; + +type ThemeProviderState = { + theme: Theme; + setTheme: (theme: Theme) => void; +}; + +const initialState: ThemeProviderState = { + theme: "system", + setTheme: () => null, +}; + +const ThemeProviderContext = createContext(initialState); + +export function ThemeProvider({ + children, + defaultTheme = "system", + storageKey = "vite-ui-theme", + ...props +}: ThemeProviderProps) { + const [theme, setTheme] = useState( + () => (localStorage.getItem(storageKey) as Theme) || defaultTheme, + ); + + useEffect(() => { + const root = window.document.documentElement; + + root.classList.remove("light", "dark"); + + if (theme === "system") { + const systemTheme = window.matchMedia("(prefers-color-scheme: dark)") + .matches + ? "dark" + : "light"; + + root.classList.add(systemTheme); + return; + } + + root.classList.add(theme); + }, [theme]); + + const value = { + theme, + setTheme: (theme: Theme) => { + localStorage.setItem(storageKey, theme); + setTheme(theme); + }, + }; + + return ( + + {children} + + ); +} + +export const useTheme = () => { + const context = useContext(ThemeProviderContext); + + // If the provider is missing, context will be initialState (setTheme is a no-op) + if (context.setTheme === initialState.setTheme) { + throw new Error( + "useTheme must be used within a ThemeProvider: provider is missing", + ); + } + + return context; +}; diff --git a/packages/ui/src/components/ui/badge.tsx b/packages/ui/src/components/ui/badge.tsx new file mode 100644 index 000000000..d9ebd4afc --- /dev/null +++ b/packages/ui/src/components/ui/badge.tsx @@ -0,0 +1,46 @@ +import { Slot } from "@radix-ui/react-slot"; +import { cva, type VariantProps } from "class-variance-authority"; +import type * as React from "react"; + +import { cn } from "@/lib/utils"; + +const badgeVariants = cva( + "inline-flex items-center justify-center rounded-md border px-2 py-0.5 text-xs font-medium w-fit whitespace-nowrap shrink-0 [&>svg]:size-3 gap-1 [&>svg]:pointer-events-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive transition-[color,box-shadow] overflow-hidden", + { + variants: { + variant: { + default: + "border-transparent bg-primary text-primary-foreground [a&]:hover:bg-primary/90", + secondary: + "border-transparent bg-secondary text-secondary-foreground [a&]:hover:bg-secondary/90", + destructive: + "border-transparent bg-destructive text-white [a&]:hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60", + outline: + "text-foreground [a&]:hover:bg-accent [a&]:hover:text-accent-foreground", + }, + }, + defaultVariants: { + variant: "default", + }, + }, +); + +function Badge({ + className, + variant, + asChild = false, + ...props +}: React.ComponentProps<"span"> & + VariantProps & { asChild?: boolean }) { + const Comp = asChild ? Slot : "span"; + + return ( + + ); +} + +export { Badge, badgeVariants }; diff --git a/packages/ui/src/components/ui/button.tsx b/packages/ui/src/components/ui/button.tsx new file mode 100644 index 000000000..c6f2d89e2 --- /dev/null +++ b/packages/ui/src/components/ui/button.tsx @@ -0,0 +1,60 @@ +import { Slot } from "@radix-ui/react-slot"; +import { cva, type VariantProps } from "class-variance-authority"; +import type * as React from "react"; + +import { cn } from "@/lib/utils"; + +const buttonVariants = cva( + "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-all disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 shrink-0 [&_svg]:shrink-0 outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive", + { + variants: { + variant: { + default: "bg-primary text-primary-foreground hover:bg-primary/90", + destructive: + "bg-destructive text-white hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60", + outline: + "border bg-background shadow-xs hover:bg-accent hover:text-accent-foreground dark:bg-input/30 dark:border-input dark:hover:bg-input/50", + secondary: + "bg-secondary text-secondary-foreground hover:bg-secondary/80", + ghost: + "hover:bg-accent hover:text-accent-foreground dark:hover:bg-accent/50", + link: "text-primary underline-offset-4 hover:underline", + }, + size: { + default: "h-9 px-4 py-2 has-[>svg]:px-3", + sm: "h-8 rounded-md gap-1.5 px-3 has-[>svg]:px-2.5", + lg: "h-10 rounded-md px-6 has-[>svg]:px-4", + icon: "size-9", + "icon-sm": "size-8", + "icon-lg": "size-10", + }, + }, + defaultVariants: { + variant: "default", + size: "default", + }, + }, +); + +function Button({ + className, + variant, + size, + asChild = false, + ...props +}: React.ComponentProps<"button"> & + VariantProps & { + asChild?: boolean; + }) { + const Comp = asChild ? Slot : "button"; + + return ( + + ); +} + +export { Button, buttonVariants }; diff --git a/packages/ui/src/components/ui/collapsible.tsx b/packages/ui/src/components/ui/collapsible.tsx new file mode 100644 index 000000000..849e7b66f --- /dev/null +++ b/packages/ui/src/components/ui/collapsible.tsx @@ -0,0 +1,31 @@ +import * as CollapsiblePrimitive from "@radix-ui/react-collapsible"; + +function Collapsible({ + ...props +}: React.ComponentProps) { + return ; +} + +function CollapsibleTrigger({ + ...props +}: React.ComponentProps) { + return ( + + ); +} + +function CollapsibleContent({ + ...props +}: React.ComponentProps) { + return ( + + ); +} + +export { Collapsible, CollapsibleTrigger, CollapsibleContent }; diff --git a/packages/ui/src/components/ui/dropdown-menu.tsx b/packages/ui/src/components/ui/dropdown-menu.tsx new file mode 100644 index 000000000..a7a316565 --- /dev/null +++ b/packages/ui/src/components/ui/dropdown-menu.tsx @@ -0,0 +1,255 @@ +import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu"; +import { CheckIcon, ChevronRightIcon, CircleIcon } from "lucide-react"; +import type * as React from "react"; + +import { cn } from "@/lib/utils"; + +function DropdownMenu({ + ...props +}: React.ComponentProps) { + return ; +} + +function DropdownMenuPortal({ + ...props +}: React.ComponentProps) { + return ( + + ); +} + +function DropdownMenuTrigger({ + ...props +}: React.ComponentProps) { + return ( + + ); +} + +function DropdownMenuContent({ + className, + sideOffset = 4, + ...props +}: React.ComponentProps) { + return ( + + + + ); +} + +function DropdownMenuGroup({ + ...props +}: React.ComponentProps) { + return ( + + ); +} + +function DropdownMenuItem({ + className, + inset, + variant = "default", + ...props +}: React.ComponentProps & { + inset?: boolean; + variant?: "default" | "destructive"; +}) { + return ( + + ); +} + +function DropdownMenuCheckboxItem({ + className, + children, + checked, + ...props +}: React.ComponentProps) { + return ( + + + + + + + {children} + + ); +} + +function DropdownMenuRadioGroup({ + ...props +}: React.ComponentProps) { + return ( + + ); +} + +function DropdownMenuRadioItem({ + className, + children, + ...props +}: React.ComponentProps) { + return ( + + + + + + + {children} + + ); +} + +function DropdownMenuLabel({ + className, + inset, + ...props +}: React.ComponentProps & { + inset?: boolean; +}) { + return ( + + ); +} + +function DropdownMenuSeparator({ + className, + ...props +}: React.ComponentProps) { + return ( + + ); +} + +function DropdownMenuShortcut({ + className, + ...props +}: React.ComponentProps<"span">) { + return ( + + ); +} + +function DropdownMenuSub({ + ...props +}: React.ComponentProps) { + return ; +} + +function DropdownMenuSubTrigger({ + className, + inset, + children, + ...props +}: React.ComponentProps & { + inset?: boolean; +}) { + return ( + + {children} + + + ); +} + +function DropdownMenuSubContent({ + className, + ...props +}: React.ComponentProps) { + return ( + + ); +} + +export { + DropdownMenu, + DropdownMenuPortal, + DropdownMenuTrigger, + DropdownMenuContent, + DropdownMenuGroup, + DropdownMenuLabel, + DropdownMenuItem, + DropdownMenuCheckboxItem, + DropdownMenuRadioGroup, + DropdownMenuRadioItem, + DropdownMenuSeparator, + DropdownMenuShortcut, + DropdownMenuSub, + DropdownMenuSubTrigger, + DropdownMenuSubContent, +}; diff --git a/packages/ui/src/components/ui/input.tsx b/packages/ui/src/components/ui/input.tsx new file mode 100644 index 000000000..73ea8679a --- /dev/null +++ b/packages/ui/src/components/ui/input.tsx @@ -0,0 +1,21 @@ +import type * as React from "react"; + +import { cn } from "@/lib/utils"; + +function Input({ className, type, ...props }: React.ComponentProps<"input">) { + return ( + + ); +} + +export { Input }; diff --git a/packages/ui/src/components/ui/separator.tsx b/packages/ui/src/components/ui/separator.tsx new file mode 100644 index 000000000..434a10e83 --- /dev/null +++ b/packages/ui/src/components/ui/separator.tsx @@ -0,0 +1,26 @@ +import * as SeparatorPrimitive from "@radix-ui/react-separator"; +import type * as React from "react"; + +import { cn } from "@/lib/utils"; + +function Separator({ + className, + orientation = "horizontal", + decorative = true, + ...props +}: React.ComponentProps) { + return ( + + ); +} + +export { Separator }; diff --git a/packages/ui/src/components/ui/sheet.tsx b/packages/ui/src/components/ui/sheet.tsx new file mode 100644 index 000000000..577a724e2 --- /dev/null +++ b/packages/ui/src/components/ui/sheet.tsx @@ -0,0 +1,139 @@ +"use client"; + +import * as SheetPrimitive from "@radix-ui/react-dialog"; +import { XIcon } from "lucide-react"; +import type * as React from "react"; + +import { cn } from "@/lib/utils"; + +function Sheet({ ...props }: React.ComponentProps) { + return ; +} + +function SheetTrigger({ + ...props +}: React.ComponentProps) { + return ; +} + +function SheetClose({ + ...props +}: React.ComponentProps) { + return ; +} + +function SheetPortal({ + ...props +}: React.ComponentProps) { + return ; +} + +function SheetOverlay({ + className, + ...props +}: React.ComponentProps) { + return ( + + ); +} + +function SheetContent({ + className, + children, + side = "right", + ...props +}: React.ComponentProps & { + side?: "top" | "right" | "bottom" | "left"; +}) { + return ( + + + + {children} + + + Close + + + + ); +} + +function SheetHeader({ className, ...props }: React.ComponentProps<"div">) { + return ( +
+ ); +} + +function SheetFooter({ className, ...props }: React.ComponentProps<"div">) { + return ( +
+ ); +} + +function SheetTitle({ + className, + ...props +}: React.ComponentProps) { + return ( + + ); +} + +function SheetDescription({ + className, + ...props +}: React.ComponentProps) { + return ( + + ); +} + +export { + Sheet, + SheetTrigger, + SheetClose, + SheetContent, + SheetHeader, + SheetFooter, + SheetTitle, + SheetDescription, +}; diff --git a/packages/ui/src/components/ui/sidebar.tsx b/packages/ui/src/components/ui/sidebar.tsx new file mode 100644 index 000000000..bf103684a --- /dev/null +++ b/packages/ui/src/components/ui/sidebar.tsx @@ -0,0 +1,726 @@ +"use client"; + +import { Slot } from "@radix-ui/react-slot"; +import { cva, type VariantProps } from "class-variance-authority"; +import { PanelLeftIcon } from "lucide-react"; +import * as React from "react"; +import { Button } from "@/components/ui/button"; +import { Input } from "@/components/ui/input"; +import { Separator } from "@/components/ui/separator"; +import { + Sheet, + SheetContent, + SheetDescription, + SheetHeader, + SheetTitle, +} from "@/components/ui/sheet"; +import { Skeleton } from "@/components/ui/skeleton"; +import { + Tooltip, + TooltipContent, + TooltipProvider, + TooltipTrigger, +} from "@/components/ui/tooltip"; +import { useIsMobile } from "@/hooks/use-mobile"; +import { cn } from "@/lib/utils"; + +const SIDEBAR_COOKIE_NAME = "sidebar_state"; +const SIDEBAR_COOKIE_MAX_AGE = 60 * 60 * 24 * 7; +const SIDEBAR_WIDTH = "16rem"; +const SIDEBAR_WIDTH_MOBILE = "18rem"; +const SIDEBAR_WIDTH_ICON = "3rem"; +const SIDEBAR_KEYBOARD_SHORTCUT = "b"; + +type SidebarContextProps = { + state: "expanded" | "collapsed"; + open: boolean; + setOpen: (open: boolean) => void; + openMobile: boolean; + setOpenMobile: (open: boolean) => void; + isMobile: boolean; + toggleSidebar: () => void; +}; + +const SidebarContext = React.createContext(null); + +function useSidebar() { + const context = React.useContext(SidebarContext); + if (!context) { + throw new Error("useSidebar must be used within a SidebarProvider."); + } + + return context; +} + +function SidebarProvider({ + defaultOpen = true, + open: openProp, + onOpenChange: setOpenProp, + className, + style, + children, + ...props +}: React.ComponentProps<"div"> & { + defaultOpen?: boolean; + open?: boolean; + onOpenChange?: (open: boolean) => void; +}) { + const isMobile = useIsMobile(); + const [openMobile, setOpenMobile] = React.useState(false); + + // This is the internal state of the sidebar. + // We use openProp and setOpenProp for control from outside the component. + const [_open, _setOpen] = React.useState(defaultOpen); + const open = openProp ?? _open; + const setOpen = React.useCallback( + (value: boolean | ((value: boolean) => boolean)) => { + const openState = typeof value === "function" ? value(open) : value; + if (setOpenProp) { + setOpenProp(openState); + } else { + _setOpen(openState); + } + + // This sets the cookie to keep the sidebar state. + // biome-ignore lint/suspicious/noDocumentCookie: this was from a shadcn template + document.cookie = `${SIDEBAR_COOKIE_NAME}=${openState}; path=/; max-age=${SIDEBAR_COOKIE_MAX_AGE}`; + }, + [setOpenProp, open], + ); + + // Helper to toggle the sidebar. + const toggleSidebar = React.useCallback(() => { + return isMobile ? setOpenMobile((open) => !open) : setOpen((open) => !open); + }, [isMobile, setOpen]); + + // Adds a keyboard shortcut to toggle the sidebar. + React.useEffect(() => { + const handleKeyDown = (event: KeyboardEvent) => { + if ( + event.key === SIDEBAR_KEYBOARD_SHORTCUT && + (event.metaKey || event.ctrlKey) + ) { + event.preventDefault(); + toggleSidebar(); + } + }; + + window.addEventListener("keydown", handleKeyDown); + return () => window.removeEventListener("keydown", handleKeyDown); + }, [toggleSidebar]); + + // We add a state so that we can do data-state="expanded" or "collapsed". + // This makes it easier to style the sidebar with Tailwind classes. + const state = open ? "expanded" : "collapsed"; + + const contextValue = React.useMemo( + () => ({ + state, + open, + setOpen, + isMobile, + openMobile, + setOpenMobile, + toggleSidebar, + }), + [state, open, setOpen, isMobile, openMobile, toggleSidebar], + ); + + return ( + + +
+ {children} +
+
+
+ ); +} + +function Sidebar({ + side = "left", + variant = "sidebar", + collapsible = "offcanvas", + className, + children, + ...props +}: React.ComponentProps<"div"> & { + side?: "left" | "right"; + variant?: "sidebar" | "floating" | "inset"; + collapsible?: "offcanvas" | "icon" | "none"; +}) { + const { isMobile, state, openMobile, setOpenMobile } = useSidebar(); + + if (collapsible === "none") { + return ( +
+ {children} +
+ ); + } + + if (isMobile) { + return ( + + + + Sidebar + Displays the mobile sidebar. + +
{children}
+
+
+ ); + } + + return ( +
+ {/* This is what handles the sidebar gap on desktop */} +
+ +
+ ); +} + +function SidebarTrigger({ + className, + onClick, + ...props +}: React.ComponentProps) { + const { toggleSidebar } = useSidebar(); + + return ( + + ); +} + +function SidebarRail({ className, ...props }: React.ComponentProps<"button">) { + const { toggleSidebar } = useSidebar(); + + return ( + + + + setTheme("light")}> + Light + + setTheme("dark")}> + Dark + + setTheme("system")}> + System + + + + ); +} diff --git a/packages/ui/src/lib/theme/default.css b/packages/ui/src/lib/theme/default.css new file mode 100644 index 000000000..4bc2c75f0 --- /dev/null +++ b/packages/ui/src/lib/theme/default.css @@ -0,0 +1,124 @@ +@import "tailwindcss"; +@import "tw-animate-css"; + +@custom-variant dark (&:is(.dark *)); + +:root { + --background: oklch(1 0 0); + --foreground: oklch(0.145 0 0); + --card: oklch(1 0 0); + --card-foreground: oklch(0.145 0 0); + --popover: oklch(1 0 0); + --popover-foreground: oklch(0.145 0 0); + --primary: oklch(0.205 0 0); + --primary-foreground: oklch(0.985 0 0); + --secondary: oklch(0.97 0 0); + --secondary-foreground: oklch(0.205 0 0); + --muted: oklch(0.97 0 0); + --muted-foreground: oklch(0.556 0 0); + --accent: oklch(0.97 0 0); + --accent-foreground: oklch(0.205 0 0); + --destructive: oklch(0.577 0.245 27.325); + --destructive-foreground: oklch(0.577 0.245 27.325); + --border: oklch(0.922 0 0); + --input: oklch(0.922 0 0); + --ring: oklch(0.708 0 0); + --chart-1: oklch(0.646 0.222 41.116); + --chart-2: oklch(0.6 0.118 184.704); + --chart-3: oklch(0.398 0.07 227.392); + --chart-4: oklch(0.828 0.189 84.429); + --chart-5: oklch(0.769 0.188 70.08); + --radius: 0.625rem; + --sidebar: oklch(0.985 0 0); + --sidebar-foreground: oklch(0.145 0 0); + --sidebar-primary: oklch(0.205 0 0); + --sidebar-primary-foreground: oklch(0.985 0 0); + --sidebar-accent: oklch(0.97 0 0); + --sidebar-accent-foreground: oklch(0.205 0 0); + --sidebar-border: oklch(0.922 0 0); + --sidebar-ring: oklch(0.708 0 0); +} + +.dark { + --background: oklch(0.145 0 0); + --foreground: oklch(0.985 0 0); + --card: oklch(0.145 0 0); + --card-foreground: oklch(0.985 0 0); + --popover: oklch(0.145 0 0); + --popover-foreground: oklch(0.985 0 0); + --primary: oklch(0.985 0 0); + --primary-foreground: oklch(0.205 0 0); + --secondary: oklch(0.269 0 0); + --secondary-foreground: oklch(0.985 0 0); + --muted: oklch(0.269 0 0); + --muted-foreground: oklch(0.708 0 0); + --accent: oklch(0.269 0 0); + --accent-foreground: oklch(0.985 0 0); + --destructive: oklch(0.396 0.141 25.723); + --destructive-foreground: oklch(0.637 0.237 25.331); + --border: oklch(0.269 0 0); + --input: oklch(0.269 0 0); + --ring: oklch(0.439 0 0); + --chart-1: oklch(0.488 0.243 264.376); + --chart-2: oklch(0.696 0.17 162.48); + --chart-3: oklch(0.769 0.188 70.08); + --chart-4: oklch(0.627 0.265 303.9); + --chart-5: oklch(0.645 0.246 16.439); + --sidebar: oklch(0.205 0 0); + --sidebar-foreground: oklch(0.985 0 0); + --sidebar-primary: oklch(0.488 0.243 264.376); + --sidebar-primary-foreground: oklch(0.985 0 0); + --sidebar-accent: oklch(0.269 0 0); + --sidebar-accent-foreground: oklch(0.985 0 0); + --sidebar-border: oklch(0.269 0 0); + --sidebar-ring: oklch(0.439 0 0); +} + +@theme inline { + --color-background: var(--background); + --color-foreground: var(--foreground); + --color-card: var(--card); + --color-card-foreground: var(--card-foreground); + --color-popover: var(--popover); + --color-popover-foreground: var(--popover-foreground); + --color-primary: var(--primary); + --color-primary-foreground: var(--primary-foreground); + --color-secondary: var(--secondary); + --color-secondary-foreground: var(--secondary-foreground); + --color-muted: var(--muted); + --color-muted-foreground: var(--muted-foreground); + --color-accent: var(--accent); + --color-accent-foreground: var(--accent-foreground); + --color-destructive: var(--destructive); + --color-destructive-foreground: var(--destructive-foreground); + --color-border: var(--border); + --color-input: var(--input); + --color-ring: var(--ring); + --color-chart-1: var(--chart-1); + --color-chart-2: var(--chart-2); + --color-chart-3: var(--chart-3); + --color-chart-4: var(--chart-4); + --color-chart-5: var(--chart-5); + --radius-sm: calc(var(--radius) - 4px); + --radius-md: calc(var(--radius) - 2px); + --radius-lg: var(--radius); + --radius-xl: calc(var(--radius) + 4px); + --color-sidebar: var(--sidebar); + --color-sidebar-foreground: var(--sidebar-foreground); + --color-sidebar-primary: var(--sidebar-primary); + --color-sidebar-primary-foreground: var(--sidebar-primary-foreground); + --color-sidebar-accent: var(--sidebar-accent); + --color-sidebar-accent-foreground: var(--sidebar-accent-foreground); + --color-sidebar-border: var(--sidebar-border); + --color-sidebar-ring: var(--sidebar-ring); +} + +@layer base { + * { + @apply border-border outline-ring/50; + } + + body { + @apply bg-background text-foreground; + } +} \ No newline at end of file diff --git a/packages/ui/src/lib/utils.ts b/packages/ui/src/lib/utils.ts new file mode 100644 index 000000000..365058ceb --- /dev/null +++ b/packages/ui/src/lib/utils.ts @@ -0,0 +1,6 @@ +import { type ClassValue, clsx } from "clsx"; +import { twMerge } from "tailwind-merge"; + +export function cn(...inputs: ClassValue[]) { + return twMerge(clsx(inputs)); +} diff --git a/packages/ui/tsconfig.json b/packages/ui/tsconfig.json new file mode 100644 index 000000000..1ab3219aa --- /dev/null +++ b/packages/ui/tsconfig.json @@ -0,0 +1,25 @@ +{ + "extends": "../../tsconfig.json", + "compilerOptions": { + "target": "ES2021", + "lib": ["ES2021", "DOM"], + "jsx": "react-jsx", + "module": "ESNext", + "moduleResolution": "Bundler", + "skipLibCheck": true, + "declaration": true, + "declarationMap": true, + "emitDeclarationOnly": false, + "noUncheckedIndexedAccess": true, + "erasableSyntaxOnly": true, + "outDir": "dist", + "rootDir": "src", + "strict": true, + "types": ["react", "react-dom"], + "baseUrl": ".", + "paths": { + "@/*": ["./src/*"] + } + }, + "include": ["src"] +} diff --git a/packages/ui/vite.config.ts b/packages/ui/vite.config.ts new file mode 100644 index 000000000..e7e4bcdb0 --- /dev/null +++ b/packages/ui/vite.config.ts @@ -0,0 +1,53 @@ +import path from "node:path"; +import tailwindcss from "@tailwindcss/vite"; +import react from "@vitejs/plugin-react"; +import { defineConfig } from "vite"; +import dts from "vite-plugin-dts"; +import { viteStaticCopy } from "vite-plugin-static-copy"; + +export default defineConfig({ + plugins: [ + react(), + tailwindcss(), + dts({ + entryRoot: "src", + outDir: "dist", + insertTypesEntry: true, + copyDtsFiles: true, + }), + viteStaticCopy({ + targets: [ + { + src: "src/lib/theme/default.css", + dest: "theme", + }, + ], + }), + ], + resolve: { + alias: { + "@": path.resolve(__dirname, "./src"), + }, + }, + build: { + emptyOutDir: true, + lib: { + entry: "src/index.ts", + name: "MeshtasticUI", + formats: ["es"], + fileName: () => "index.js", + }, + rollupOptions: { + external: [ + "react", + "react-dom", + "tailwindcss", + "class-variance-authority", + "tailwind-merge", + "@radix-ui/react-slot", + ], + }, + sourcemap: true, + target: "es2021", + }, +}); diff --git a/packages/web/index.html b/packages/web/index.html index 1b3afa718..30ad400c1 100644 --- a/packages/web/index.html +++ b/packages/web/index.html @@ -11,16 +11,6 @@ - - - - - Created with Fabric.js 4.6.0 - - - - - - - - - - - diff --git a/packages/web/public/Logo_Black.svg b/packages/web/public/Logo_Black.svg deleted file mode 100644 index 3568d3001..000000000 --- a/packages/web/public/Logo_Black.svg +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - - - - - - diff --git a/packages/web/public/Logo_White.svg b/packages/web/public/Logo_White.svg deleted file mode 100644 index 7c5417ed9..000000000 --- a/packages/web/public/Logo_White.svg +++ /dev/null @@ -1,28 +0,0 @@ - - - - - - - - - - - - diff --git a/packages/web/public/fonts/InterVariable-Italic.woff2 b/packages/web/public/fonts/InterVariable-Italic.woff2 new file mode 100644 index 000000000..b3530f3f5 Binary files /dev/null and b/packages/web/public/fonts/InterVariable-Italic.woff2 differ diff --git a/packages/web/public/fonts/InterVariable.woff2 b/packages/web/public/fonts/InterVariable.woff2 new file mode 100644 index 000000000..5a8d3e72a Binary files /dev/null and b/packages/web/public/fonts/InterVariable.woff2 differ diff --git a/packages/web/public/i18n/locales/be-BY/channels.json b/packages/web/public/i18n/locales/be-BY/channels.json index 95f64b16a..8f2b390d6 100644 --- a/packages/web/public/i18n/locales/be-BY/channels.json +++ b/packages/web/public/i18n/locales/be-BY/channels.json @@ -1,69 +1,71 @@ { - "page": { - "sectionLabel": "Channels", - "channelName": "Channel: {{channelName}}", - "broadcastLabel": "Primary", - "channelIndex": "Ch {{index}}" - }, - "validation": { - "pskInvalid": "Please enter a valid {{bits}} bit PSK." - }, - "settings": { - "label": "Channel Settings", - "description": "Crypto, MQTT & misc settings" - }, - "role": { - "label": "Role", - "description": "Device telemetry is sent over PRIMARY. Only one PRIMARY allowed", - "options": { - "primary": "PRIMARY", - "disabled": "DISABLED", - "secondary": "SECONDARY" - } - }, - "psk": { - "label": "Pre-Shared Key", - "description": "Supported PSK lengths: 256-bit, 128-bit, 8-bit, Empty (0-bit)", - "generate": "Generate" - }, - "name": { - "label": "Name", - "description": "A unique name for the channel <12 bytes, leave blank for default" - }, - "uplinkEnabled": { - "label": "Uplink Enabled", - "description": "Send messages from the local mesh to MQTT" - }, - "downlinkEnabled": { - "label": "Downlink Enabled", - "description": "Send messages from MQTT to the local mesh" - }, - "positionPrecision": { - "label": "Location", - "description": "The precision of the location to share with the channel. Can be disabled.", - "options": { - "none": "Do not share location", - "precise": "Precise Location", - "metric_km23": "Within 23 kilometers", - "metric_km12": "Within 12 kilometers", - "metric_km5_8": "Within 5.8 kilometers", - "metric_km2_9": "Within 2.9 kilometers", - "metric_km1_5": "Within 1.5 kilometers", - "metric_m700": "Within 700 meters", - "metric_m350": "Within 350 meters", - "metric_m200": "Within 200 meters", - "metric_m90": "Within 90 meters", - "metric_m50": "Within 50 meters", - "imperial_mi15": "Within 15 miles", - "imperial_mi7_3": "Within 7.3 miles", - "imperial_mi3_6": "Within 3.6 miles", - "imperial_mi1_8": "Within 1.8 miles", - "imperial_mi0_9": "Within 0.9 miles", - "imperial_mi0_5": "Within 0.5 miles", - "imperial_mi0_2": "Within 0.2 miles", - "imperial_ft600": "Within 600 feet", - "imperial_ft300": "Within 300 feet", - "imperial_ft150": "Within 150 feet" - } - } + "page": { + "sectionLabel": "Channels", + "channelName": "Channel: {{channelName}}", + "broadcastLabel": "Primary", + "channelIndex": "Ch {{index}}", + "import": "Import", + "export": "Export" + }, + "validation": { + "pskInvalid": "Please enter a valid {{bits}} bit PSK." + }, + "settings": { + "label": "Channel Settings", + "description": "Crypto, MQTT & misc settings" + }, + "role": { + "label": "Role", + "description": "Device telemetry is sent over PRIMARY. Only one PRIMARY allowed", + "options": { + "primary": "PRIMARY", + "disabled": "DISABLED", + "secondary": "SECONDARY" + } + }, + "psk": { + "label": "Pre-Shared Key", + "description": "Supported PSK lengths: 256-bit, 128-bit, 8-bit, Empty (0-bit)", + "generate": "Generate" + }, + "name": { + "label": "Name", + "description": "A unique name for the channel <12 bytes, leave blank for default" + }, + "uplinkEnabled": { + "label": "Uplink Enabled", + "description": "Send messages from the local mesh to MQTT" + }, + "downlinkEnabled": { + "label": "Downlink Enabled", + "description": "Send messages from MQTT to the local mesh" + }, + "positionPrecision": { + "label": "Location", + "description": "The precision of the location to share with the channel. Can be disabled.", + "options": { + "none": "Do not share location", + "precise": "Precise Location", + "metric_km23": "Within 23 kilometers", + "metric_km12": "Within 12 kilometers", + "metric_km5_8": "Within 5.8 kilometers", + "metric_km2_9": "Within 2.9 kilometers", + "metric_km1_5": "Within 1.5 kilometers", + "metric_m700": "Within 700 meters", + "metric_m350": "Within 350 meters", + "metric_m200": "Within 200 meters", + "metric_m90": "Within 90 meters", + "metric_m50": "Within 50 meters", + "imperial_mi15": "Within 15 miles", + "imperial_mi7_3": "Within 7.3 miles", + "imperial_mi3_6": "Within 3.6 miles", + "imperial_mi1_8": "Within 1.8 miles", + "imperial_mi0_9": "Within 0.9 miles", + "imperial_mi0_5": "Within 0.5 miles", + "imperial_mi0_2": "Within 0.2 miles", + "imperial_ft600": "Within 600 feet", + "imperial_ft300": "Within 300 feet", + "imperial_ft150": "Within 150 feet" + } + } } diff --git a/packages/web/public/i18n/locales/be-BY/commandPalette.json b/packages/web/public/i18n/locales/be-BY/commandPalette.json index 8c267e29f..d12b783fb 100644 --- a/packages/web/public/i18n/locales/be-BY/commandPalette.json +++ b/packages/web/public/i18n/locales/be-BY/commandPalette.json @@ -15,7 +15,6 @@ "messages": "Messages", "map": "Map", "config": "Config", - "channels": "Channels", "nodes": "Nodes" } }, @@ -45,7 +44,8 @@ "label": "Debug", "command": { "reconfigure": "Reconfigure", - "clearAllStoredMessages": "Clear All Stored Message" + "clearAllStoredMessages": "Clear All Stored Message", + "clearAllStores": "Clear All Local Storage" } } } diff --git a/packages/web/public/i18n/locales/be-BY/common.json b/packages/web/public/i18n/locales/be-BY/common.json index e0fe5bc91..ab66f2f5f 100644 --- a/packages/web/public/i18n/locales/be-BY/common.json +++ b/packages/web/public/i18n/locales/be-BY/common.json @@ -1,142 +1,165 @@ { - "button": { - "apply": "Apply", - "backupKey": "Backup Key", - "cancel": "Cancel", - "clearMessages": "Clear Messages", - "close": "Close", - "confirm": "Confirm", - "delete": "Delete", - "dismiss": "Dismiss", - "download": "Download", - "export": "Export", - "generate": "Generate", - "regenerate": "Regenerate", - "import": "Import", - "message": "Message", - "now": "Now", - "ok": "OK", - "print": "Print", - "remove": "Remove", - "requestNewKeys": "Request New Keys", - "requestPosition": "Request Position", - "reset": "Reset", - "save": "Save", - "scanQr": "Scan QR Code", - "traceRoute": "Trace Route", - "submit": "Submit" - }, - "app": { - "title": "Meshtastic", - "fullTitle": "Meshtastic Web Client" - }, - "loading": "Loading...", - "unit": { - "cps": "CPS", - "dbm": "dBm", - "hertz": "Hz", - "hop": { - "one": "Hop", - "plural": "Hops" - }, - "hopsAway": { - "one": "{{count}} hop away", - "plural": "{{count}} hops away", - "unknown": "Unknown hops away" - }, - "megahertz": "MHz", - "raw": "raw", - "meter": { - "one": "Meter", - "plural": "Meters", - "suffix": "m" - }, - "minute": { - "one": "Minute", - "plural": "Minutes" - }, - "hour": { - "one": "Hour", - "plural": "Hours" - }, - "millisecond": { - "one": "Millisecond", - "plural": "Milliseconds", - "suffix": "ms" - }, - "second": { - "one": "Second", - "plural": "Seconds" - }, - "day": { - "one": "Day", - "plural": "Days" - }, - "month": { - "one": "Month", - "plural": "Months" - }, - "year": { - "one": "Year", - "plural": "Years" - }, - "snr": "SNR", - "volt": { - "one": "Volt", - "plural": "Volts", - "suffix": "V" - }, - "record": { - "one": "Records", - "plural": "Records" - } - }, - "security": { - "0bit": "Empty", - "8bit": "8 bit", - "128bit": "128 bit", - "256bit": "256 bit" - }, - "unknown": { - "longName": "Unknown", - "shortName": "UNK", - "notAvailable": "N/A", - "num": "??" - }, - "nodeUnknownPrefix": "!", - "unset": "UNSET", - "fallbackName": "Meshtastic {{last4}}", - "node": "Node", - "formValidation": { - "unsavedChanges": "Unsaved changes", - "tooBig": { - "string": "Too long, expected less than or equal to {{maximum}} characters.", - "number": "Too big, expected a number smaller than or equal to {{maximum}}.", - "bytes": "Too big, expected less than or equal to {{params.maximum}} bytes." - }, - "tooSmall": { - "string": "Too short, expected more than or equal to {{minimum}} characters.", - "number": "Too small, expected a number larger than or equal to {{minimum}}." - }, - "invalidFormat": { - "ipv4": "Invalid format, expected an IPv4 address.", - "key": "Invalid format, expected a Base64 encoded pre-shared key (PSK)." - }, - "invalidType": { - "number": "Invalid type, expected a number." - }, - "pskLength": { - "0bit": "Key is required to be empty.", - "8bit": "Key is required to be an 8 bit pre-shared key (PSK).", - "128bit": "Key is required to be a 128 bit pre-shared key (PSK).", - "256bit": "Key is required to be a 256 bit pre-shared key (PSK)." - }, - "required": { - "generic": "This field is required.", - "managed": "At least one admin key is requred if the node is managed.", - "key": "Key is required." - } - }, - "yes": "Yes", - "no": "No" + "button": { + "apply": "Apply", + "addConnection": "Add Connection", + "saveConnection": "Save connection", + "backupKey": "Backup Key", + "cancel": "Cancel", + "connect": "Connect", + "clearMessages": "Clear Messages", + "close": "Close", + "confirm": "Confirm", + "delete": "Delete", + "dismiss": "Dismiss", + "download": "Download", + "disconnect": "Disconnect", + "export": "Export", + "generate": "Generate", + "regenerate": "Regenerate", + "import": "Import", + "message": "Message", + "now": "Now", + "ok": "OK", + "print": "Print", + "remove": "Remove", + "requestNewKeys": "Request New Keys", + "requestPosition": "Request Position", + "reset": "Reset", + "retry": "Retry", + "save": "Save", + "setDefault": "Set as default", + "unsetDefault": "Unset default", + "scanQr": "Scan QR Code", + "traceRoute": "Trace Route", + "submit": "Submit" + }, + "app": { + "title": "Meshtastic", + "fullTitle": "Meshtastic Web Client" + }, + "loading": "Loading...", + "unit": { + "cps": "CPS", + "dbm": "dBm", + "hertz": "Hz", + "hop": { + "one": "Hop", + "plural": "Hops" + }, + "hopsAway": { + "one": "{{count}} hop away", + "plural": "{{count}} hops away", + "unknown": "Unknown hops away" + }, + "megahertz": "MHz", + "kilohertz": "kHz", + "raw": "raw", + "meter": { + "one": "Meter", + "plural": "Meters", + "suffix": "m" + }, + "kilometer": { + "one": "Kilometer", + "plural": "Kilometers", + "suffix": "km" + }, + "minute": { + "one": "Minute", + "plural": "Minutes" + }, + "hour": { + "one": "Hour", + "plural": "Hours" + }, + "millisecond": { + "one": "Millisecond", + "plural": "Milliseconds", + "suffix": "ms" + }, + "second": { + "one": "Second", + "plural": "Seconds" + }, + "day": { + "one": "Day", + "plural": "Days", + "today": "Today", + "yesterday": "Yesterday" + }, + "month": { + "one": "Month", + "plural": "Months" + }, + "year": { + "one": "Year", + "plural": "Years" + }, + "snr": "SNR", + "volt": { + "one": "Volt", + "plural": "Volts", + "suffix": "V" + }, + "record": { + "one": "Records", + "plural": "Records" + }, + "degree": { + "one": "Degree", + "plural": "Degrees", + "suffix": "°" + } + }, + "security": { + "0bit": "Empty", + "8bit": "8 bit", + "128bit": "128 bit", + "256bit": "256 bit" + }, + "unknown": { + "longName": "Unknown", + "shortName": "UNK", + "notAvailable": "N/A", + "num": "??" + }, + "nodeUnknownPrefix": "!", + "unset": "UNSET", + "fallbackName": "Meshtastic {{last4}}", + "node": "Node", + "formValidation": { + "unsavedChanges": "Unsaved changes", + "tooBig": { + "string": "Too long, expected less than or equal to {{maximum}} characters.", + "number": "Too big, expected a number smaller than or equal to {{maximum}}.", + "bytes": "Too big, expected less than or equal to {{params.maximum}} bytes." + }, + "tooSmall": { + "string": "Too short, expected more than or equal to {{minimum}} characters.", + "number": "Too small, expected a number larger than or equal to {{minimum}}." + }, + "invalidFormat": { + "ipv4": "Invalid format, expected an IPv4 address.", + "key": "Invalid format, expected a Base64 encoded pre-shared key (PSK)." + }, + "invalidType": { + "number": "Invalid type, expected a number." + }, + "pskLength": { + "0bit": "Key is required to be empty.", + "8bit": "Key is required to be an 8 bit pre-shared key (PSK).", + "128bit": "Key is required to be a 128 bit pre-shared key (PSK).", + "256bit": "Key is required to be a 256 bit pre-shared key (PSK)." + }, + "required": { + "generic": "This field is required.", + "managed": "At least one admin key is requred if the node is managed.", + "key": "Key is required." + }, + "invalidOverrideFreq": { + "number": "Invalid format, expected a value in the range 410-930 MHz or 0 (use default)." + } + }, + "yes": "Yes", + "no": "No" } diff --git a/packages/web/public/i18n/locales/en/deviceConfig.json b/packages/web/public/i18n/locales/be-BY/config.json similarity index 89% rename from packages/web/public/i18n/locales/en/deviceConfig.json rename to packages/web/public/i18n/locales/be-BY/config.json index 193c54946..4cd59f18d 100644 --- a/packages/web/public/i18n/locales/en/deviceConfig.json +++ b/packages/web/public/i18n/locales/be-BY/config.json @@ -1,17 +1,19 @@ { "page": { - "title": "Configuration", + "title": "Settings", + "tabUser": "Карыстальнік", + "tabChannels": "Каналы", "tabBluetooth": "Bluetooth", - "tabDevice": "Device", - "tabDisplay": "Display", + "tabDevice": "Прылада", + "tabDisplay": "Экран", "tabLora": "LoRa", - "tabNetwork": "Network", - "tabPosition": "Position", + "tabNetwork": "Сетка", + "tabPosition": "Месцазнаходжанне", "tabPower": "Power", - "tabSecurity": "Security" + "tabSecurity": "Бяспека" }, "sidebar": { - "label": "Modules" + "label": "Configuration" }, "device": { "title": "Device Settings", @@ -59,7 +61,7 @@ "note": "Note: Some devices (ESP32) cannot use both Bluetooth and WiFi at the same time.", "enabled": { "description": "Enable or disable Bluetooth", - "label": "Enabled" + "label": "Уключана" }, "pairingMode": { "description": "Pin selection behaviour.", @@ -122,7 +124,7 @@ "title": "Mesh Settings", "description": "Settings for the LoRa mesh", "bandwidth": { - "description": "Channel bandwidth in MHz", + "description": "Channel bandwidth in kHz", "label": "Bandwidth" }, "boostedRxGain": { @@ -167,7 +169,7 @@ }, "region": { "description": "Sets the region for your node", - "label": "Region" + "label": "Рэгіён" }, "spreadingFactor": { "description": "Indicates the number of chirps per symbol", @@ -212,7 +214,7 @@ }, "ethernetEnabled": { "description": "Enable or disable the Ethernet port", - "label": "Enabled" + "label": "Уключана" }, "gateway": { "description": "Default Gateway", @@ -236,7 +238,7 @@ }, "wifiEnabled": { "description": "Enable or disable the WiFi radio", - "label": "Enabled" + "label": "Уключана" }, "meshViaUdp": { "label": "Mesh via UDP" @@ -424,5 +426,33 @@ "description": "Settings for Logging", "label": "Logging Settings" } + }, + "user": { + "title": "User Settings", + "description": "Configure your device name and identity settings", + "longName": { + "label": "Long Name", + "description": "Your full display name (1-40 characters)", + "validation": { + "min": "Long name must be at least 1 character", + "max": "Long name must be at most 40 characters" + } + }, + "shortName": { + "label": "Short Name", + "description": "Your abbreviated name (2-4 characters)", + "validation": { + "min": "Short name must be at least 2 characters", + "max": "Short name must be at most 4 characters" + } + }, + "isUnmessageable": { + "label": "Unmessageable", + "description": "Used to identify unmonitored or infrastructure nodes so that messaging is not available to nodes that will never respond." + }, + "isLicensed": { + "label": "Licensed amateur radio (HAM)", + "description": "Enable if you are a licensed amateur radio operator, enabling this option disables encryption and is not compatible with the default Meshtastic network." + } } } diff --git a/packages/web/public/i18n/locales/be-BY/connections.json b/packages/web/public/i18n/locales/be-BY/connections.json new file mode 100644 index 000000000..6d24fa19d --- /dev/null +++ b/packages/web/public/i18n/locales/be-BY/connections.json @@ -0,0 +1,34 @@ +{ + "page": { + "title": "Connect to a Meshtastic device", + "description": "Add a device connection via HTTP, Bluetooth, or Serial. Your saved connections will be saved in your browser." + }, + "connectionType_ble": "BLE", + "connectionType_serial": "Serial", + "connectionType_network": "Сетка", + "deleteConnection": "Delete connection", + "areYouSure": "This will remove {{name}}. You canot undo this action.", + "moreActions": "More actions", + "noConnections": { + "title": "No connections yet.", + "description": "Create your first connection. It will connect immediately and be saved for later." + }, + "lastConnectedAt": "Last connected: {{date}}", + "neverConnected": "Never connected", + "toasts": { + "connected": "Злучаны", + "nowConnected": "{{name}} is now connected", + "nowDisconnected": "{{name}} are now disconnecte", + "disconnected": "Адлучана", + "failed": "Failed to connect", + "checkConnetion": "Check your device or settings and try again", + "defaultSet": "Default set", + "defaultConnection": "Default connection is now {{nameisconnected}}", + "deleted": "Deleted", + "deletedByName": "{{name}} was removed", + "pickConnectionAgain": "Could not connect. You may need to reselect the device/port.", + "added": "Connection added", + "savedByName": "{{name}} saved.", + "savedCantConnect": "The connection was saved but could not connect." + } +} diff --git a/packages/web/public/i18n/locales/be-BY/dashboard.json b/packages/web/public/i18n/locales/be-BY/dashboard.json deleted file mode 100644 index 8ec375283..000000000 --- a/packages/web/public/i18n/locales/be-BY/dashboard.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "dashboard": { - "title": "Connected Devices", - "description": "Manage your connected Meshtastic devices.", - "connectionType_ble": "BLE", - "connectionType_serial": "Serial", - "connectionType_network": "Network", - "noDevicesTitle": "No devices connected", - "noDevicesDescription": "Connect a new device to get started.", - "button_newConnection": "New Connection" - } -} diff --git a/packages/web/public/i18n/locales/be-BY/deviceConfig.json b/packages/web/public/i18n/locales/be-BY/deviceConfig.json index 25319f53a..8c4a50a04 100644 --- a/packages/web/public/i18n/locales/be-BY/deviceConfig.json +++ b/packages/web/public/i18n/locales/be-BY/deviceConfig.json @@ -122,7 +122,7 @@ "title": "Mesh Settings", "description": "Settings for the LoRa mesh", "bandwidth": { - "description": "Channel bandwidth in MHz", + "description": "Channel bandwidth in kHz", "label": "Bandwidth" }, "boostedRxGain": { diff --git a/packages/web/public/i18n/locales/be-BY/dialog.json b/packages/web/public/i18n/locales/be-BY/dialog.json index b97f117a6..daaa7436c 100644 --- a/packages/web/public/i18n/locales/be-BY/dialog.json +++ b/packages/web/public/i18n/locales/be-BY/dialog.json @@ -1,193 +1,238 @@ { - "deleteMessages": { - "description": "This action will clear all message history. This cannot be undone. Are you sure you want to continue?", - "title": "Clear All Messages" - }, - "deviceName": { - "description": "The Device will restart once the config is saved.", - "longName": "Long Name", - "shortName": "Short Name", - "title": "Change Device Name", - "validation": { - "longNameMax": "Long name must not be more than 40 characters", - "shortNameMax": "Short name must not be more than 4 characters", - "longNameMin": "Long name must have at least 1 character", - "shortNameMin": "Short name must have at least 1 character" - } - }, - "import": { - "description": "The current LoRa configuration will be overridden.", - "error": { - "invalidUrl": "Invalid Meshtastic URL" - }, - "channelPrefix": "Channel: ", - "channelSetUrl": "Channel Set/QR Code URL", - "channels": "Channels:", - "usePreset": "Use Preset?", - "title": "Import Channel Set" - }, - "locationResponse": { - "title": "Location: {{identifier}}", - "altitude": "Altitude: ", - "coordinates": "Coordinates: ", - "noCoordinates": "No Coordinates" - }, - "pkiRegenerateDialog": { - "title": "Regenerate Pre-Shared Key?", - "description": "Are you sure you want to regenerate the pre-shared key?", - "regenerate": "Regenerate" - }, - "newDeviceDialog": { - "title": "Connect New Device", - "https": "https", - "http": "http", - "tabHttp": "HTTP", - "tabBluetooth": "Bluetooth", - "tabSerial": "Serial", - "useHttps": "Use HTTPS", - "connecting": "Connecting...", - "connect": "Connect", - "connectionFailedAlert": { - "title": "Connection Failed", - "descriptionPrefix": "Could not connect to the device. ", - "httpsHint": "If using HTTPS, you may need to accept a self-signed certificate first. ", - "openLinkPrefix": "Please open ", - "openLinkSuffix": " in a new tab", - "acceptTlsWarningSuffix": ", accept any TLS warnings if prompted, then try again", - "learnMoreLink": "Learn more" - }, - "httpConnection": { - "label": "IP Address/Hostname", - "placeholder": "000.000.000.000 / meshtastic.local" - }, - "serialConnection": { - "noDevicesPaired": "No devices paired yet.", - "newDeviceButton": "New device", - "deviceIdentifier": "# {{index}} - {{vendorId}} - {{productId}}" - }, - "bluetoothConnection": { - "noDevicesPaired": "No devices paired yet.", - "newDeviceButton": "New device", - "connectionFailed": "Connection failed", - "deviceDisconnected": "Device disconnected", - "unknownDevice": "Unknown Device", - "errorLoadingDevices": "Error loading devices", - "unknownErrorLoadingDevices": "Unknown error loading devices" - }, - "validation": { - "requiresWebBluetooth": "This connection type requires <0>Web Bluetooth. Please use a supported browser, like Chrome or Edge.", - "requiresWebSerial": "This connection type requires <0>Web Serial. Please use a supported browser, like Chrome or Edge.", - "requiresSecureContext": "This application requires a <0>secure context. Please connect using HTTPS or localhost.", - "additionallyRequiresSecureContext": "Additionally, it requires a <0>secure context. Please connect using HTTPS or localhost." - } - }, - "nodeDetails": { - "message": "Message", - "requestPosition": "Request Position", - "traceRoute": "Trace Route", - "airTxUtilization": "Air TX utilization", - "allRawMetrics": "All Raw Metrics:", - "batteryLevel": "Battery level", - "channelUtilization": "Channel utilization", - "details": "Details:", - "deviceMetrics": "Device Metrics:", - "hardware": "Hardware: ", - "lastHeard": "Last Heard: ", - "nodeHexPrefix": "Node Hex: ", - "nodeNumber": "Node Number: ", - "position": "Position:", - "role": "Role: ", - "uptime": "Uptime: ", - "voltage": "Voltage", - "title": "Node Details for {{identifier}}", - "ignoreNode": "Ignore node", - "removeNode": "Remove node", - "unignoreNode": "Unignore node", - "security": "Security:", - "publicKey": "Public Key: ", - "messageable": "Messageable: ", - "KeyManuallyVerifiedTrue": "Public Key has been manually verified", - "KeyManuallyVerifiedFalse": "Public Key is not manually verified" - }, - "pkiBackup": { - "loseKeysWarning": "If you lose your keys, you will need to reset your device.", - "secureBackup": "Its important to backup your public and private keys and store your backup securely!", - "footer": "=== END OF KEYS ===", - "header": "=== MESHTASTIC KEYS FOR {{longName}} ({{shortName}}) ===", - "privateKey": "Private Key:", - "publicKey": "Public Key:", - "fileName": "meshtastic_keys_{{longName}}_{{shortName}}.txt", - "title": "Backup Keys" - }, - "pkiBackupReminder": { - "description": "We recommend backing up your key data regularly. Would you like to back up now?", - "title": "Backup Reminder", - "remindLaterPrefix": "Remind me in", - "remindNever": "Never remind me", - "backupNow": "Back up now" - }, - "pkiRegenerate": { - "description": "Are you sure you want to regenerate key pair?", - "title": "Regenerate Key Pair" - }, - "qr": { - "addChannels": "Add Channels", - "replaceChannels": "Replace Channels", - "description": "The current LoRa configuration will also be shared.", - "sharableUrl": "Sharable URL", - "title": "Generate QR Code" - }, - "reboot": { - "title": "Reboot device", - "description": "Reboot now or schedule a reboot of the connected node. Optionally, you can choose to reboot into OTA (Over-the-Air) mode.", - "ota": "Reboot into OTA mode", - "enterDelay": "Enter delay", - "scheduled": "Reboot has been scheduled", - "schedule": "Schedule reboot", - "now": "Reboot now", - "cancel": "Cancel scheduled reboot" - }, - "refreshKeys": { - "description": { - "acceptNewKeys": "This will remove the node from device and request new keys.", - "keyMismatchReasonSuffix": ". This is due to the remote node's current public key does not match the previously stored key for this node.", - "unableToSendDmPrefix": "Your node is unable to send a direct message to node: " - }, - "acceptNewKeys": "Accept New Keys", - "title": "Keys Mismatch - {{identifier}}" - }, - "removeNode": { - "description": "Are you sure you want to remove this Node?", - "title": "Remove Node?" - }, - "shutdown": { - "title": "Schedule Shutdown", - "description": "Turn off the connected node after x minutes." - }, - "traceRoute": { - "routeToDestination": "Route to destination:", - "routeBack": "Route back:" - }, - "tracerouteResponse": { - "title": "Traceroute: {{identifier}}" - }, - "unsafeRoles": { - "confirmUnderstanding": "Yes, I know what I'm doing", - "conjunction": " and the blog post about ", - "postamble": " and understand the implications of changing the role.", - "preamble": "I have read the ", - "choosingRightDeviceRole": "Choosing The Right Device Role", - "deviceRoleDocumentation": "Device Role Documentation", - "title": "Are you sure?" - }, - "managedMode": { - "confirmUnderstanding": "Yes, I know what I'm doing", - "title": "Are you sure?", - "description": "Enabling Managed Mode blocks client applications (including the web client) from writing configurations to a radio. Once enabled, radio configurations can only be changed through Remote Admin messages. This setting is not required for remote node administration." - }, - "clientNotification": { - "title": "Client Notification", - "TraceRoute can only be sent once every 30 seconds": "TraceRoute can only be sent once every 30 seconds", - "Compromised keys were detected and regenerated.": "Compromised keys were detected and regenerated." - } + "deleteMessages": { + "description": "This action will clear all message history. This cannot be undone. Are you sure you want to continue?", + "title": "Clear All Messages" + }, + "import": { + "description": "The current LoRa configuration will be overridden.", + "error": { + "invalidUrl": "Invalid Meshtastic URL" + }, + "channelPrefix": "Channel: ", + "primary": "Primary ", + "doNotImport": "No not import", + "channelName": "Назва", + "channelSlot": "Slot", + "channelSetUrl": "Channel Set/QR Code URL", + "useLoraConfig": "Import LoRa Config", + "presetDescription": "The current LoRa Config will be replaced.", + "title": "Import Channel Set" + }, + "locationResponse": { + "title": "Location: {{identifier}}", + "altitude": "Altitude: ", + "coordinates": "Coordinates: ", + "noCoordinates": "No Coordinates" + }, + "pkiRegenerateDialog": { + "title": "Regenerate Pre-Shared Key?", + "description": "Are you sure you want to regenerate the pre-shared key?", + "regenerate": "Regenerate" + }, + "addConnection": { + "title": "Add connection", + "description": "Choose a connection type and fill in the details", + "validation": { + "requiresWebBluetooth": "This connection type requires <0>Web Bluetooth. Please use a supported browser, like Chrome or Edge.", + "requiresWebSerial": "This connection type requires <0>Web Serial. Please use a supported browser, like Chrome or Edge.", + "requiresSecureContext": "This application requires a <0>secure context. Please connect using HTTPS or localhost.", + "additionallyRequiresSecureContext": "Additionally, it requires a <0>secure context. Please connect using HTTPS or localhost." + }, + "bluetoothConnection": { + "namePlaceholder": "My Bluetooth Node", + "supported": { + "title": "Web Bluetooth supported" + }, + "notSupported": { + "title": "Web Bluetooth not supported", + "description": "Your browser or device does not support Web Bluetooth" + }, + "short": "BT: {{deviceName}}", + "long": "Bluetooth Device", + "device": "Прылада", + "selectDevice": "Select device", + "selected": "Bluetooth device selected", + "notSelected": "No device selected", + "helperText": "Uses the Meshtastic Bluetooth service for discovery." + }, + "serialConnection": { + "namePlaceholder": "My Serial Node", + "helperText": "Selecting a port grants permission so the app can open it to connect.", + "supported": { + "title": "Web Serial supported" + }, + "notSupported": { + "title": "Web Serial not supported", + "description": "Your browser or device does not support Web Serial" + }, + "portSelected": { + "title": "Serial port selected", + "description": "Port permissions granted." + }, + "port": "Port", + "selectPort": "Select port", + "deviceName": "USB {{vendorId}}:{{productId}}", + "notSelected": "No port selected" + }, + "httpConnection": { + "namePlaceholder": "My HTTP Node", + "inputPlaceholder": "192.168.1.10 or meshtastic.local", + "heading": "URL or IP", + "useHttps": "Use HTTTPS", + "invalidUrl": { + "title": "Invalid URL", + "description": "Please enter a valid HTTP or HTTPS URL." + }, + "connectionTest": { + "description": "Test the connetion before saving to verify the device is reachable.", + "button": { + "loading": "Testing...", + "label": "Test connection" + }, + "reachable": "Reachable", + "notReachable": "Not reachable", + "success": { + "title": "Connection test successful", + "description": "The device appears to be reachable." + }, + "failure": { + "title": "Connection test failed", + "description": "Could not reach the device. Check the URL and try again." + } + } + } + }, + "nodeDetails": { + "message": "Message", + "requestPosition": "Request Position", + "traceRoute": "Trace Route", + "airTxUtilization": "Air TX utilization", + "allRawMetrics": "All Raw Metrics:", + "batteryLevel": "Battery level", + "channelUtilization": "Channel utilization", + "details": "Details:", + "deviceMetrics": "Device Metrics:", + "hardware": "Hardware: ", + "lastHeard": "Last Heard: ", + "nodeHexPrefix": "Node Hex: ", + "nodeNumber": "Node Number: ", + "position": "Position:", + "role": "Role: ", + "uptime": "Uptime: ", + "voltage": "Voltage", + "title": "Node Details for {{identifier}}", + "ignoreNode": "Ignore node", + "removeNode": "Remove node", + "unignoreNode": "Unignore node", + "security": "Security:", + "publicKey": "Public Key: ", + "messageable": "Messageable: ", + "KeyManuallyVerifiedTrue": "Public Key has been manually verified", + "KeyManuallyVerifiedFalse": "Public Key is not manually verified" + }, + "pkiBackup": { + "loseKeysWarning": "If you lose your keys, you will need to reset your device.", + "secureBackup": "Its important to backup your public and private keys and store your backup securely!", + "footer": "=== END OF KEYS ===", + "header": "=== MESHTASTIC KEYS FOR {{longName}} ({{shortName}}) ===", + "privateKey": "Private Key:", + "publicKey": "Public Key:", + "fileName": "meshtastic_keys_{{longName}}_{{shortName}}.txt", + "title": "Backup Keys" + }, + "pkiBackupReminder": { + "description": "We recommend backing up your key data regularly. Would you like to back up now?", + "title": "Backup Reminder", + "remindLaterPrefix": "Remind me in", + "remindNever": "Never remind me", + "backupNow": "Back up now" + }, + "pkiRegenerate": { + "description": "Are you sure you want to regenerate key pair?", + "title": "Regenerate Key Pair" + }, + "qr": { + "addChannels": "Add Channels", + "replaceChannels": "Replace Channels", + "description": "The current LoRa configuration will also be shared.", + "sharableUrl": "Sharable URL", + "title": "Generate QR Code" + }, + "reboot": { + "title": "Reboot device", + "description": "Reboot now or schedule a reboot of the connected node. Optionally, you can choose to reboot into OTA (Over-the-Air) mode.", + "ota": "Reboot into OTA mode", + "enterDelay": "Enter delay", + "scheduled": "Reboot has been scheduled", + "schedule": "Schedule reboot", + "now": "Reboot now", + "cancel": "Cancel scheduled reboot" + }, + "refreshKeys": { + "description": { + "acceptNewKeys": "This will remove the node from device and request new keys.", + "keyMismatchReasonSuffix": ". This is due to the remote node's current public key does not match the previously stored key for this node.", + "unableToSendDmPrefix": "Your node is unable to send a direct message to node: " + }, + "acceptNewKeys": "Accept New Keys", + "title": "Keys Mismatch - {{identifier}}" + }, + "removeNode": { + "description": "Are you sure you want to remove this Node?", + "title": "Remove Node?" + }, + "shutdown": { + "title": "Schedule Shutdown", + "description": "Turn off the connected node after x minutes." + }, + "traceRoute": { + "routeToDestination": "Route to destination:", + "routeBack": "Route back:" + }, + "tracerouteResponse": { + "title": "Traceroute: {{identifier}}" + }, + "unsafeRoles": { + "confirmUnderstanding": "Yes, I know what I'm doing", + "conjunction": " and the blog post about ", + "postamble": " and understand the implications of changing the role.", + "preamble": "I have read the ", + "choosingRightDeviceRole": "Choosing The Right Device Role", + "deviceRoleDocumentation": "Device Role Documentation", + "title": "Are you sure?" + }, + "managedMode": { + "confirmUnderstanding": "Yes, I know what I'm doing", + "title": "Are you sure?", + "description": "Enabling Managed Mode blocks client applications (including the web client) from writing configurations to a radio. Once enabled, radio configurations can only be changed through Remote Admin messages. This setting is not required for remote node administration." + }, + "clientNotification": { + "title": "Client Notification", + "TraceRoute can only be sent once every 30 seconds": "TraceRoute can only be sent once every 30 seconds", + "Compromised keys were detected and regenerated.": "Compromised keys were detected and regenerated." + }, + "resetNodeDb": { + "title": "Reset Node Database", + "description": "This will clear all nodes from the connected device's node database and clear all message history in the client. This cannot be undone. Are you sure you want to continue?", + "confirm": "Reset Node Database", + "failedTitle": "There was an error resetting the Node DB. Please try again." + }, + "clearAllStores": { + "title": "Clear All Local Storage", + "description": "This will clear all locally stored data, including message history and node databases for all previously connected devices. This will require you to reconnect to your node once complete and cannot be undone. Are you sure you want to continue?", + "confirm": "Clear all local storage", + "failedTitle": "There was an error clearing local storage. Please try again." + }, + "factoryResetDevice": { + "title": "Factory Reset Device", + "description": "This will factory reset the connected device, erasing all configurations and data on the device as well as all nodes and messages saved in the client. This cannot be undone. Are you sure you want to continue?", + "confirm": "Factory Reset Device", + "failedTitle": "There was an error performing the factory reset. Please try again." + }, + "factoryResetConfig": { + "title": "Factory Reset Config", + "description": "This will factory reset the configuration on the connected device, erasing all configurations on the device. This cannot be undone. Are you sure you want to continue?", + "confirm": "Factory Reset Config", + "failedTitle": "There was an error performing the factory reset. Please try again." + } } diff --git a/packages/web/public/i18n/locales/be-BY/map.json b/packages/web/public/i18n/locales/be-BY/map.json new file mode 100644 index 000000000..887b0d296 --- /dev/null +++ b/packages/web/public/i18n/locales/be-BY/map.json @@ -0,0 +1,38 @@ +{ + "maplibre": { + "GeolocateControl.FindMyLocation": "Find my location", + "NavigationControl.ZoomIn": "Zoom in", + "NavigationControl.ZoomOut": "Zoom out", + "CooperativeGesturesHandler.WindowsHelpText": "Use Ctrl + scroll to zoom the map", + "CooperativeGesturesHandler.MacHelpText": "Use ⌘ + scroll to zoom the map", + "CooperativeGesturesHandler.MobileHelpText": "Use two fingers to move the map" + }, + "layerTool": { + "nodeMarkers": "Show nodes", + "directNeighbors": "Show direct connections", + "remoteNeighbors": "Show remote connections", + "positionPrecision": "Show position precision", + "traceroutes": "Show traceroutes", + "waypoints": "Show waypoints" + }, + "mapMenu": { + "locateAria": "Locate my node", + "layersAria": "Change map style" + }, + "waypointDetail": { + "edit": "Змяніць", + "description": "Description:", + "createdBy": "Edited by:", + "createdDate": "Created:", + "updated": "Updated:", + "expires": "Expires:", + "distance": "Distance:", + "bearing": "Absolute bearing:", + "lockedTo": "Locked by:", + "latitude": "Latitude:", + "longitude": "Longitude:" + }, + "myNode": { + "tooltip": "This device" + } +} diff --git a/packages/web/public/i18n/locales/be-BY/messages.json b/packages/web/public/i18n/locales/be-BY/messages.json index 7a50b569a..3b7dbeb48 100644 --- a/packages/web/public/i18n/locales/be-BY/messages.json +++ b/packages/web/public/i18n/locales/be-BY/messages.json @@ -1,39 +1,39 @@ { - "page": { - "title": "Messages: {{chatName}}", - "placeholder": "Enter Message" - }, - "emptyState": { - "title": "Select a Chat", - "text": "No messages yet." - }, - "selectChatPrompt": { - "text": "Select a channel or node to start messaging." - }, - "sendMessage": { - "placeholder": "Enter your message here...", - "sendButton": "Send" - }, - "actionsMenu": { - "addReactionLabel": "Add Reaction", - "replyLabel": "Reply" - }, - "deliveryStatus": { - "delivered": { - "label": "Message delivered", - "displayText": "Message delivered" - }, - "failed": { - "label": "Message delivery failed", - "displayText": "Delivery failed" - }, - "unknown": { - "label": "Message status unknown", - "displayText": "Unknown state" - }, - "waiting": { - "label": "Sending message", - "displayText": "Waiting for delivery" - } - } + "page": { + "title": "Messages: {{chatName}}", + "placeholder": "Enter Message" + }, + "emptyState": { + "title": "Select a Chat", + "text": "No messages yet." + }, + "selectChatPrompt": { + "text": "Select a channel or node to start messaging." + }, + "sendMessage": { + "placeholder": "Enter your message here...", + "sendButton": "Send" + }, + "actionsMenu": { + "addReactionLabel": "Add Reaction", + "replyLabel": "Reply" + }, + "deliveryStatus": { + "delivered": { + "label": "Message delivered", + "displayText": "Message delivered" + }, + "failed": { + "label": "Message delivery failed", + "displayText": "Delivery failed" + }, + "unknown": { + "label": "Message status unknown", + "displayText": "Unknown state" + }, + "waiting": { + "label": "Sending message", + "displayText": "Waiting for delivery" + } + } } diff --git a/packages/web/public/i18n/locales/be-BY/moduleConfig.json b/packages/web/public/i18n/locales/be-BY/moduleConfig.json index 88066772b..f35995984 100644 --- a/packages/web/public/i18n/locales/be-BY/moduleConfig.json +++ b/packages/web/public/i18n/locales/be-BY/moduleConfig.json @@ -1,448 +1,448 @@ { - "page": { - "tabAmbientLighting": "Ambient Lighting", - "tabAudio": "Audio", - "tabCannedMessage": "Canned", - "tabDetectionSensor": "Detection Sensor", - "tabExternalNotification": "Ext Notif", - "tabMqtt": "MQTT", - "tabNeighborInfo": "Neighbor Info", - "tabPaxcounter": "Paxcounter", - "tabRangeTest": "Range Test", - "tabSerial": "Serial", - "tabStoreAndForward": "S&F", - "tabTelemetry": "Telemetry" - }, - "ambientLighting": { - "title": "Ambient Lighting Settings", - "description": "Settings for the Ambient Lighting module", - "ledState": { - "label": "LED State", - "description": "Sets LED to on or off" - }, - "current": { - "label": "Current", - "description": "Sets the current for the LED output. Default is 10" - }, - "red": { - "label": "Red", - "description": "Sets the red LED level. Values are 0-255" - }, - "green": { - "label": "Green", - "description": "Sets the green LED level. Values are 0-255" - }, - "blue": { - "label": "Blue", - "description": "Sets the blue LED level. Values are 0-255" - } - }, - "audio": { - "title": "Audio Settings", - "description": "Settings for the Audio module", - "codec2Enabled": { - "label": "Codec 2 Enabled", - "description": "Enable Codec 2 audio encoding" - }, - "pttPin": { - "label": "PTT Pin", - "description": "GPIO pin to use for PTT" - }, - "bitrate": { - "label": "Bitrate", - "description": "Bitrate to use for audio encoding" - }, - "i2sWs": { - "label": "i2S WS", - "description": "GPIO pin to use for i2S WS" - }, - "i2sSd": { - "label": "i2S SD", - "description": "GPIO pin to use for i2S SD" - }, - "i2sDin": { - "label": "i2S DIN", - "description": "GPIO pin to use for i2S DIN" - }, - "i2sSck": { - "label": "i2S SCK", - "description": "GPIO pin to use for i2S SCK" - } - }, - "cannedMessage": { - "title": "Canned Message Settings", - "description": "Settings for the Canned Message module", - "moduleEnabled": { - "label": "Module Enabled", - "description": "Enable Canned Message" - }, - "rotary1Enabled": { - "label": "Rotary Encoder #1 Enabled", - "description": "Enable the rotary encoder" - }, - "inputbrokerPinA": { - "label": "Encoder Pin A", - "description": "GPIO Pin Value (1-39) For encoder port A" - }, - "inputbrokerPinB": { - "label": "Encoder Pin B", - "description": "GPIO Pin Value (1-39) For encoder port B" - }, - "inputbrokerPinPress": { - "label": "Encoder Pin Press", - "description": "GPIO Pin Value (1-39) For encoder Press" - }, - "inputbrokerEventCw": { - "label": "Clockwise event", - "description": "Select input event." - }, - "inputbrokerEventCcw": { - "label": "Counter Clockwise event", - "description": "Select input event." - }, - "inputbrokerEventPress": { - "label": "Press event", - "description": "Select input event" - }, - "updown1Enabled": { - "label": "Up Down enabled", - "description": "Enable the up / down encoder" - }, - "allowInputSource": { - "label": "Allow Input Source", - "description": "Select from: '_any', 'rotEnc1', 'upDownEnc1', 'cardkb'" - }, - "sendBell": { - "label": "Send Bell", - "description": "Sends a bell character with each message" - } - }, - "detectionSensor": { - "title": "Detection Sensor Settings", - "description": "Settings for the Detection Sensor module", - "enabled": { - "label": "Enabled", - "description": "Enable or disable Detection Sensor Module" - }, - "minimumBroadcastSecs": { - "label": "Minimum Broadcast Seconds", - "description": "The interval in seconds of how often we can send a message to the mesh when a state change is detected" - }, - "stateBroadcastSecs": { - "label": "State Broadcast Seconds", - "description": "The interval in seconds of how often we should send a message to the mesh with the current state regardless of changes" - }, - "sendBell": { - "label": "Send Bell", - "description": "Send ASCII bell with alert message" - }, - "name": { - "label": "Friendly Name", - "description": "Used to format the message sent to mesh, max 20 Characters" - }, - "monitorPin": { - "label": "Monitor Pin", - "description": "The GPIO pin to monitor for state changes" - }, - "detectionTriggerType": { - "label": "Detection Triggered Type", - "description": "The type of trigger event to be used" - }, - "usePullup": { - "label": "Use Pullup", - "description": "Whether or not use INPUT_PULLUP mode for GPIO pin" - } - }, - "externalNotification": { - "title": "External Notification Settings", - "description": "Configure the external notification module", - "enabled": { - "label": "Module Enabled", - "description": "Enable External Notification" - }, - "outputMs": { - "label": "Output MS", - "description": "Output MS" - }, - "output": { - "label": "Output", - "description": "Output" - }, - "outputVibra": { - "label": "Output Vibrate", - "description": "Output Vibrate" - }, - "outputBuzzer": { - "label": "Output Buzzer", - "description": "Output Buzzer" - }, - "active": { - "label": "Active", - "description": "Active" - }, - "alertMessage": { - "label": "Alert Message", - "description": "Alert Message" - }, - "alertMessageVibra": { - "label": "Alert Message Vibrate", - "description": "Alert Message Vibrate" - }, - "alertMessageBuzzer": { - "label": "Alert Message Buzzer", - "description": "Alert Message Buzzer" - }, - "alertBell": { - "label": "Alert Bell", - "description": "Should an alert be triggered when receiving an incoming bell?" - }, - "alertBellVibra": { - "label": "Alert Bell Vibrate", - "description": "Alert Bell Vibrate" - }, - "alertBellBuzzer": { - "label": "Alert Bell Buzzer", - "description": "Alert Bell Buzzer" - }, - "usePwm": { - "label": "Use PWM", - "description": "Use PWM" - }, - "nagTimeout": { - "label": "Nag Timeout", - "description": "Nag Timeout" - }, - "useI2sAsBuzzer": { - "label": "Use I²S Pin as Buzzer", - "description": "Designate I²S Pin as Buzzer Output" - } - }, - "mqtt": { - "title": "MQTT Settings", - "description": "Settings for the MQTT module", - "enabled": { - "label": "Enabled", - "description": "Enable or disable MQTT" - }, - "address": { - "label": "MQTT Server Address", - "description": "MQTT server address to use for default/custom servers" - }, - "username": { - "label": "MQTT Username", - "description": "MQTT username to use for default/custom servers" - }, - "password": { - "label": "MQTT Password", - "description": "MQTT password to use for default/custom servers" - }, - "encryptionEnabled": { - "label": "Encryption Enabled", - "description": "Enable or disable MQTT encryption. Note: All messages are sent to the MQTT broker unencrypted if this option is not enabled, even when your uplink channels have encryption keys set. This includes position data." - }, - "jsonEnabled": { - "label": "JSON Enabled", - "description": "Whether to send/consume JSON packets on MQTT" - }, - "tlsEnabled": { - "label": "TLS Enabled", - "description": "Enable or disable TLS" - }, - "root": { - "label": "Root topic", - "description": "MQTT root topic to use for default/custom servers" - }, - "proxyToClientEnabled": { - "label": "MQTT Client Proxy Enabled", - "description": "Utilizes the network connection to proxy MQTT messages to the client." - }, - "mapReportingEnabled": { - "label": "Map Reporting Enabled", - "description": "Your node will periodically send an unencrypted map report packet to the configured MQTT server, this includes id, short and long name, approximate location, hardware model, role, firmware version, LoRa region, modem preset and primary channel name." - }, - "mapReportSettings": { - "publishIntervalSecs": { - "label": "Map Report Publish Interval (s)", - "description": "Interval in seconds to publish map reports" - }, - "positionPrecision": { - "label": "Approximate Location", - "description": "Position shared will be accurate within this distance", - "options": { - "metric_km23": "Within 23 km", - "metric_km12": "Within 12 km", - "metric_km5_8": "Within 5.8 km", - "metric_km2_9": "Within 2.9 km", - "metric_km1_5": "Within 1.5 km", - "metric_m700": "Within 700 m", - "metric_m350": "Within 350 m", - "metric_m200": "Within 200 m", - "metric_m90": "Within 90 m", - "metric_m50": "Within 50 m", - "imperial_mi15": "Within 15 miles", - "imperial_mi7_3": "Within 7.3 miles", - "imperial_mi3_6": "Within 3.6 miles", - "imperial_mi1_8": "Within 1.8 miles", - "imperial_mi0_9": "Within 0.9 miles", - "imperial_mi0_5": "Within 0.5 miles", - "imperial_mi0_2": "Within 0.2 miles", - "imperial_ft600": "Within 600 feet", - "imperial_ft300": "Within 300 feet", - "imperial_ft150": "Within 150 feet" - } - } - } - }, - "neighborInfo": { - "title": "Neighbor Info Settings", - "description": "Settings for the Neighbor Info module", - "enabled": { - "label": "Enabled", - "description": "Enable or disable Neighbor Info Module" - }, - "updateInterval": { - "label": "Update Interval", - "description": "Interval in seconds of how often we should try to send our Neighbor Info to the mesh" - } - }, - "paxcounter": { - "title": "Paxcounter Settings", - "description": "Settings for the Paxcounter module", - "enabled": { - "label": "Module Enabled", - "description": "Enable Paxcounter" - }, - "paxcounterUpdateInterval": { - "label": "Update Interval (seconds)", - "description": "How long to wait between sending paxcounter packets" - }, - "wifiThreshold": { - "label": "WiFi RSSI Threshold", - "description": "At what WiFi RSSI level should the counter increase. Defaults to -80." - }, - "bleThreshold": { - "label": "BLE RSSI Threshold", - "description": "At what BLE RSSI level should the counter increase. Defaults to -80." - } - }, - "rangeTest": { - "title": "Range Test Settings", - "description": "Settings for the Range Test module", - "enabled": { - "label": "Module Enabled", - "description": "Enable Range Test" - }, - "sender": { - "label": "Message Interval", - "description": "How long to wait between sending test packets" - }, - "save": { - "label": "Save CSV to storage", - "description": "ESP32 Only" - } - }, - "serial": { - "title": "Serial Settings", - "description": "Settings for the Serial module", - "enabled": { - "label": "Module Enabled", - "description": "Enable Serial output" - }, - "echo": { - "label": "Echo", - "description": "Any packets you send will be echoed back to your device" - }, - "rxd": { - "label": "Receive Pin", - "description": "Set the GPIO pin to the RXD pin you have set up." - }, - "txd": { - "label": "Transmit Pin", - "description": "Set the GPIO pin to the TXD pin you have set up." - }, - "baud": { - "label": "Baud Rate", - "description": "The serial baud rate" - }, - "timeout": { - "label": "Timeout", - "description": "Seconds to wait before we consider your packet as 'done'" - }, - "mode": { - "label": "Mode", - "description": "Select Mode" - }, - "overrideConsoleSerialPort": { - "label": "Override Console Serial Port", - "description": "If you have a serial port connected to the console, this will override it." - } - }, - "storeForward": { - "title": "Store & Forward Settings", - "description": "Settings for the Store & Forward module", - "enabled": { - "label": "Module Enabled", - "description": "Enable Store & Forward" - }, - "heartbeat": { - "label": "Heartbeat Enabled", - "description": "Enable Store & Forward heartbeat" - }, - "records": { - "label": "Number of records", - "description": "Number of records to store" - }, - "historyReturnMax": { - "label": "History return max", - "description": "Max number of records to return" - }, - "historyReturnWindow": { - "label": "History return window", - "description": "Max number of records to return" - } - }, - "telemetry": { - "title": "Telemetry Settings", - "description": "Settings for the Telemetry module", - "deviceUpdateInterval": { - "label": "Device Metrics", - "description": "Device metrics update interval (seconds)" - }, - "environmentUpdateInterval": { - "label": "Environment metrics update interval (seconds)", - "description": "" - }, - "environmentMeasurementEnabled": { - "label": "Module Enabled", - "description": "Enable the Environment Telemetry" - }, - "environmentScreenEnabled": { - "label": "Displayed on Screen", - "description": "Show the Telemetry Module on the OLED" - }, - "environmentDisplayFahrenheit": { - "label": "Display Fahrenheit", - "description": "Display temp in Fahrenheit" - }, - "airQualityEnabled": { - "label": "Air Quality Enabled", - "description": "Enable the Air Quality Telemetry" - }, - "airQualityInterval": { - "label": "Air Quality Update Interval", - "description": "How often to send Air Quality data over the mesh" - }, - "powerMeasurementEnabled": { - "label": "Power Measurement Enabled", - "description": "Enable the Power Measurement Telemetry" - }, - "powerUpdateInterval": { - "label": "Power Update Interval", - "description": "How often to send Power data over the mesh" - }, - "powerScreenEnabled": { - "label": "Power Screen Enabled", - "description": "Enable the Power Telemetry Screen" - } - } + "page": { + "tabAmbientLighting": "Ambient Lighting", + "tabAudio": "Audio", + "tabCannedMessage": "Canned", + "tabDetectionSensor": "Detection Sensor", + "tabExternalNotification": "Ext Notif", + "tabMqtt": "MQTT", + "tabNeighborInfo": "Neighbor Info", + "tabPaxcounter": "Paxcounter", + "tabRangeTest": "Range Test", + "tabSerial": "Serial", + "tabStoreAndForward": "S&F", + "tabTelemetry": "Telemetry" + }, + "ambientLighting": { + "title": "Ambient Lighting Settings", + "description": "Settings for the Ambient Lighting module", + "ledState": { + "label": "LED State", + "description": "Sets LED to on or off" + }, + "current": { + "label": "Current", + "description": "Sets the current for the LED output. Default is 10" + }, + "red": { + "label": "Red", + "description": "Sets the red LED level. Values are 0-255" + }, + "green": { + "label": "Green", + "description": "Sets the green LED level. Values are 0-255" + }, + "blue": { + "label": "Blue", + "description": "Sets the blue LED level. Values are 0-255" + } + }, + "audio": { + "title": "Audio Settings", + "description": "Settings for the Audio module", + "codec2Enabled": { + "label": "Codec 2 Enabled", + "description": "Enable Codec 2 audio encoding" + }, + "pttPin": { + "label": "PTT Pin", + "description": "GPIO pin to use for PTT" + }, + "bitrate": { + "label": "Bitrate", + "description": "Bitrate to use for audio encoding" + }, + "i2sWs": { + "label": "i2S WS", + "description": "GPIO pin to use for i2S WS" + }, + "i2sSd": { + "label": "i2S SD", + "description": "GPIO pin to use for i2S SD" + }, + "i2sDin": { + "label": "i2S DIN", + "description": "GPIO pin to use for i2S DIN" + }, + "i2sSck": { + "label": "i2S SCK", + "description": "GPIO pin to use for i2S SCK" + } + }, + "cannedMessage": { + "title": "Canned Message Settings", + "description": "Settings for the Canned Message module", + "moduleEnabled": { + "label": "Module Enabled", + "description": "Enable Canned Message" + }, + "rotary1Enabled": { + "label": "Rotary Encoder #1 Enabled", + "description": "Enable the rotary encoder" + }, + "inputbrokerPinA": { + "label": "Encoder Pin A", + "description": "GPIO Pin Value (1-39) For encoder port A" + }, + "inputbrokerPinB": { + "label": "Encoder Pin B", + "description": "GPIO Pin Value (1-39) For encoder port B" + }, + "inputbrokerPinPress": { + "label": "Encoder Pin Press", + "description": "GPIO Pin Value (1-39) For encoder Press" + }, + "inputbrokerEventCw": { + "label": "Clockwise event", + "description": "Select input event." + }, + "inputbrokerEventCcw": { + "label": "Counter Clockwise event", + "description": "Select input event." + }, + "inputbrokerEventPress": { + "label": "Press event", + "description": "Select input event" + }, + "updown1Enabled": { + "label": "Up Down enabled", + "description": "Enable the up / down encoder" + }, + "allowInputSource": { + "label": "Allow Input Source", + "description": "Select from: '_any', 'rotEnc1', 'upDownEnc1', 'cardkb'" + }, + "sendBell": { + "label": "Send Bell", + "description": "Sends a bell character with each message" + } + }, + "detectionSensor": { + "title": "Detection Sensor Settings", + "description": "Settings for the Detection Sensor module", + "enabled": { + "label": "Enabled", + "description": "Enable or disable Detection Sensor Module" + }, + "minimumBroadcastSecs": { + "label": "Minimum Broadcast Seconds", + "description": "The interval in seconds of how often we can send a message to the mesh when a state change is detected" + }, + "stateBroadcastSecs": { + "label": "State Broadcast Seconds", + "description": "The interval in seconds of how often we should send a message to the mesh with the current state regardless of changes" + }, + "sendBell": { + "label": "Send Bell", + "description": "Send ASCII bell with alert message" + }, + "name": { + "label": "Friendly Name", + "description": "Used to format the message sent to mesh, max 20 Characters" + }, + "monitorPin": { + "label": "Monitor Pin", + "description": "The GPIO pin to monitor for state changes" + }, + "detectionTriggerType": { + "label": "Detection Triggered Type", + "description": "The type of trigger event to be used" + }, + "usePullup": { + "label": "Use Pullup", + "description": "Whether or not use INPUT_PULLUP mode for GPIO pin" + } + }, + "externalNotification": { + "title": "External Notification Settings", + "description": "Configure the external notification module", + "enabled": { + "label": "Module Enabled", + "description": "Enable External Notification" + }, + "outputMs": { + "label": "Output MS", + "description": "Output MS" + }, + "output": { + "label": "Output", + "description": "Output" + }, + "outputVibra": { + "label": "Output Vibrate", + "description": "Output Vibrate" + }, + "outputBuzzer": { + "label": "Output Buzzer", + "description": "Output Buzzer" + }, + "active": { + "label": "Active", + "description": "Active" + }, + "alertMessage": { + "label": "Alert Message", + "description": "Alert Message" + }, + "alertMessageVibra": { + "label": "Alert Message Vibrate", + "description": "Alert Message Vibrate" + }, + "alertMessageBuzzer": { + "label": "Alert Message Buzzer", + "description": "Alert Message Buzzer" + }, + "alertBell": { + "label": "Alert Bell", + "description": "Should an alert be triggered when receiving an incoming bell?" + }, + "alertBellVibra": { + "label": "Alert Bell Vibrate", + "description": "Alert Bell Vibrate" + }, + "alertBellBuzzer": { + "label": "Alert Bell Buzzer", + "description": "Alert Bell Buzzer" + }, + "usePwm": { + "label": "Use PWM", + "description": "Use PWM" + }, + "nagTimeout": { + "label": "Nag Timeout", + "description": "Nag Timeout" + }, + "useI2sAsBuzzer": { + "label": "Use I²S Pin as Buzzer", + "description": "Designate I²S Pin as Buzzer Output" + } + }, + "mqtt": { + "title": "MQTT Settings", + "description": "Settings for the MQTT module", + "enabled": { + "label": "Enabled", + "description": "Enable or disable MQTT" + }, + "address": { + "label": "MQTT Server Address", + "description": "MQTT server address to use for default/custom servers" + }, + "username": { + "label": "MQTT Username", + "description": "MQTT username to use for default/custom servers" + }, + "password": { + "label": "MQTT Password", + "description": "MQTT password to use for default/custom servers" + }, + "encryptionEnabled": { + "label": "Encryption Enabled", + "description": "Enable or disable MQTT encryption. Note: All messages are sent to the MQTT broker unencrypted if this option is not enabled, even when your uplink channels have encryption keys set. This includes position data." + }, + "jsonEnabled": { + "label": "JSON Enabled", + "description": "Whether to send/consume JSON packets on MQTT" + }, + "tlsEnabled": { + "label": "TLS Enabled", + "description": "Enable or disable TLS" + }, + "root": { + "label": "Root topic", + "description": "MQTT root topic to use for default/custom servers" + }, + "proxyToClientEnabled": { + "label": "MQTT Client Proxy Enabled", + "description": "Utilizes the network connection to proxy MQTT messages to the client." + }, + "mapReportingEnabled": { + "label": "Map Reporting Enabled", + "description": "Your node will periodically send an unencrypted map report packet to the configured MQTT server, this includes id, short and long name, approximate location, hardware model, role, firmware version, LoRa region, modem preset and primary channel name." + }, + "mapReportSettings": { + "publishIntervalSecs": { + "label": "Map Report Publish Interval (s)", + "description": "Interval in seconds to publish map reports" + }, + "positionPrecision": { + "label": "Approximate Location", + "description": "Position shared will be accurate within this distance", + "options": { + "metric_km23": "Within 23 km", + "metric_km12": "Within 12 km", + "metric_km5_8": "Within 5.8 km", + "metric_km2_9": "Within 2.9 km", + "metric_km1_5": "Within 1.5 km", + "metric_m700": "Within 700 m", + "metric_m350": "Within 350 m", + "metric_m200": "Within 200 m", + "metric_m90": "Within 90 m", + "metric_m50": "Within 50 m", + "imperial_mi15": "Within 15 miles", + "imperial_mi7_3": "Within 7.3 miles", + "imperial_mi3_6": "Within 3.6 miles", + "imperial_mi1_8": "Within 1.8 miles", + "imperial_mi0_9": "Within 0.9 miles", + "imperial_mi0_5": "Within 0.5 miles", + "imperial_mi0_2": "Within 0.2 miles", + "imperial_ft600": "Within 600 feet", + "imperial_ft300": "Within 300 feet", + "imperial_ft150": "Within 150 feet" + } + } + } + }, + "neighborInfo": { + "title": "Neighbor Info Settings", + "description": "Settings for the Neighbor Info module", + "enabled": { + "label": "Enabled", + "description": "Enable or disable Neighbor Info Module" + }, + "updateInterval": { + "label": "Update Interval", + "description": "Interval in seconds of how often we should try to send our Neighbor Info to the mesh" + } + }, + "paxcounter": { + "title": "Paxcounter Settings", + "description": "Settings for the Paxcounter module", + "enabled": { + "label": "Module Enabled", + "description": "Enable Paxcounter" + }, + "paxcounterUpdateInterval": { + "label": "Update Interval (seconds)", + "description": "How long to wait between sending paxcounter packets" + }, + "wifiThreshold": { + "label": "WiFi RSSI Threshold", + "description": "At what WiFi RSSI level should the counter increase. Defaults to -80." + }, + "bleThreshold": { + "label": "BLE RSSI Threshold", + "description": "At what BLE RSSI level should the counter increase. Defaults to -80." + } + }, + "rangeTest": { + "title": "Range Test Settings", + "description": "Settings for the Range Test module", + "enabled": { + "label": "Module Enabled", + "description": "Enable Range Test" + }, + "sender": { + "label": "Message Interval", + "description": "How long to wait between sending test packets" + }, + "save": { + "label": "Save CSV to storage", + "description": "ESP32 Only" + } + }, + "serial": { + "title": "Serial Settings", + "description": "Settings for the Serial module", + "enabled": { + "label": "Module Enabled", + "description": "Enable Serial output" + }, + "echo": { + "label": "Echo", + "description": "Any packets you send will be echoed back to your device" + }, + "rxd": { + "label": "Receive Pin", + "description": "Set the GPIO pin to the RXD pin you have set up." + }, + "txd": { + "label": "Transmit Pin", + "description": "Set the GPIO pin to the TXD pin you have set up." + }, + "baud": { + "label": "Baud Rate", + "description": "The serial baud rate" + }, + "timeout": { + "label": "Timeout", + "description": "Seconds to wait before we consider your packet as 'done'" + }, + "mode": { + "label": "Mode", + "description": "Select Mode" + }, + "overrideConsoleSerialPort": { + "label": "Override Console Serial Port", + "description": "If you have a serial port connected to the console, this will override it." + } + }, + "storeForward": { + "title": "Store & Forward Settings", + "description": "Settings for the Store & Forward module", + "enabled": { + "label": "Module Enabled", + "description": "Enable Store & Forward" + }, + "heartbeat": { + "label": "Heartbeat Enabled", + "description": "Enable Store & Forward heartbeat" + }, + "records": { + "label": "Number of records", + "description": "Number of records to store" + }, + "historyReturnMax": { + "label": "History return max", + "description": "Max number of records to return" + }, + "historyReturnWindow": { + "label": "History return window", + "description": "Return records from this time window (minutes)" + } + }, + "telemetry": { + "title": "Telemetry Settings", + "description": "Settings for the Telemetry module", + "deviceUpdateInterval": { + "label": "Device Metrics", + "description": "Device metrics update interval (seconds)" + }, + "environmentUpdateInterval": { + "label": "Environment metrics update interval (seconds)", + "description": "" + }, + "environmentMeasurementEnabled": { + "label": "Module Enabled", + "description": "Enable the Environment Telemetry" + }, + "environmentScreenEnabled": { + "label": "Displayed on Screen", + "description": "Show the Telemetry Module on the OLED" + }, + "environmentDisplayFahrenheit": { + "label": "Display Fahrenheit", + "description": "Display temp in Fahrenheit" + }, + "airQualityEnabled": { + "label": "Air Quality Enabled", + "description": "Enable the Air Quality Telemetry" + }, + "airQualityInterval": { + "label": "Air Quality Update Interval", + "description": "How often to send Air Quality data over the mesh" + }, + "powerMeasurementEnabled": { + "label": "Power Measurement Enabled", + "description": "Enable the Power Measurement Telemetry" + }, + "powerUpdateInterval": { + "label": "Power Update Interval", + "description": "How often to send Power data over the mesh" + }, + "powerScreenEnabled": { + "label": "Power Screen Enabled", + "description": "Enable the Power Telemetry Screen" + } + } } diff --git a/packages/web/public/i18n/locales/be-BY/nodes.json b/packages/web/public/i18n/locales/be-BY/nodes.json index c85a5587a..9e18417fa 100644 --- a/packages/web/public/i18n/locales/be-BY/nodes.json +++ b/packages/web/public/i18n/locales/be-BY/nodes.json @@ -1,63 +1,59 @@ { - "nodeDetail": { - "publicKeyEnabled": { - "label": "Public Key Enabled" - }, - "noPublicKey": { - "label": "No Public Key" - }, - "directMessage": { - "label": "Direct Message {{shortName}}" - }, - "favorite": { - "label": "Favorite", - "tooltip": "Add or remove this node from your favorites" - }, - "notFavorite": { - "label": "Not a Favorite" - }, - "error": { - "label": "Error", - "text": "An error occurred while fetching node details. Please try again later." - }, - "status": { - "heard": "Heard", - "mqtt": "MQTT" - }, - "elevation": { - "label": "Elevation" - }, - "channelUtil": { - "label": "Channel Util" - }, - "airtimeUtil": { - "label": "Airtime Util" - } - }, - "nodesTable": { - "headings": { - "longName": "Long Name", - "connection": "Connection", - "lastHeard": "Last Heard", - "encryption": "Encryption", - "model": "Model", - "macAddress": "MAC Address" - }, - "connectionStatus": { - "direct": "Direct", - "away": "away", - "unknown": "-", - "viaMqtt": ", via MQTT" - }, - "lastHeardStatus": { - "never": "Never" - } - }, - "actions": { - "added": "Added", - "removed": "Removed", - "ignoreNode": "Ignore Node", - "unignoreNode": "Unignore Node", - "requestPosition": "Request Position" - } + "nodeDetail": { + "publicKeyEnabled": { + "label": "Public Key Enabled" + }, + "noPublicKey": { + "label": "No Public Key" + }, + "directMessage": { + "label": "Direct Message {{shortName}}" + }, + "favorite": { + "label": "Favorite", + "tooltip": "Add or remove this node from your favorites" + }, + "notFavorite": { + "label": "Not a Favorite" + }, + "error": { + "label": "Error", + "text": "An error occurred while fetching node details. Please try again later." + }, + "status": { + "heard": "Heard", + "mqtt": "MQTT" + }, + "elevation": { + "label": "Elevation" + }, + "channelUtil": { + "label": "Channel Util" + }, + "airtimeUtil": { + "label": "Airtime Util" + } + }, + "nodesTable": { + "headings": { + "longName": "Long Name", + "connection": "Connection", + "lastHeard": "Last Heard", + "encryption": "Encryption", + "model": "Model", + "macAddress": "MAC Address" + }, + "connectionStatus": { + "direct": "Direct", + "away": "away", + "viaMqtt": ", via MQTT" + } + }, + "actions": { + "added": "Added", + "removed": "Removed", + "ignoreNode": "Ignore Node", + "unignoreNode": "Unignore Node", + "requestPosition": "Request Position" + } } diff --git a/packages/web/public/i18n/locales/be-BY/ui.json b/packages/web/public/i18n/locales/be-BY/ui.json index 25f062579..c8460b9f6 100644 --- a/packages/web/public/i18n/locales/be-BY/ui.json +++ b/packages/web/public/i18n/locales/be-BY/ui.json @@ -1,228 +1,230 @@ { - "navigation": { - "title": "Navigation", - "messages": "Messages", - "map": "Map", - "config": "Config", - "radioConfig": "Radio Config", - "moduleConfig": "Module Config", - "channels": "Channels", - "nodes": "Nodes" - }, - "app": { - "title": "Meshtastic", - "logo": "Meshtastic Logo" - }, - "sidebar": { - "collapseToggle": { - "button": { - "open": "Open sidebar", - "close": "Close sidebar" - } - }, - "deviceInfo": { - "volts": "{{voltage}} volts", - "firmware": { - "title": "Firmware", - "version": "v{{version}}", - "buildDate": "Build date: {{date}}" - }, - "deviceName": { - "title": "Device Name", - "changeName": "Change Device Name", - "placeholder": "Enter device name" - }, - "editDeviceName": "Edit device name" - } - }, - "batteryStatus": { - "charging": "{{level}}% charging", - "pluggedIn": "Plugged in", - "title": "Battery" - }, - "search": { - "nodes": "Search nodes...", - "channels": "Search channels...", - "commandPalette": "Search commands..." - }, - "toast": { - "positionRequestSent": { - "title": "Position request sent." - }, - "requestingPosition": { - "title": "Requesting position, please wait..." - }, - "sendingTraceroute": { - "title": "Sending Traceroute, please wait..." - }, - "tracerouteSent": { - "title": "Traceroute sent." - }, - "savedChannel": { - "title": "Saved Channel: {{channelName}}" - }, - "messages": { - "pkiEncryption": { - "title": "Chat is using PKI encryption." - }, - "pskEncryption": { - "title": "Chat is using PSK encryption." - } - }, - "configSaveError": { - "title": "Error Saving Config", - "description": "An error occurred while saving the configuration." - }, - "validationError": { - "title": "Config Errors Exist", - "description": "Please fix the configuration errors before saving." - }, - "saveSuccess": { - "title": "Saving Config", - "description": "The configuration change {{case}} has been saved." - }, - "favoriteNode": { - "title": "{{action}} {{nodeName}} {{direction}} favorites.", - "action": { - "added": "Added", - "removed": "Removed", - "to": "to", - "from": "from" - } - }, - "ignoreNode": { - "title": "{{action}} {{nodeName}} {{direction}} ignore list", - "action": { - "added": "Added", - "removed": "Removed", - "to": "to", - "from": "from" - } - } - }, - "notifications": { - "copied": { - "label": "Copied!" - }, - "copyToClipboard": { - "label": "Copy to clipboard" - }, - "hidePassword": { - "label": "Hide password" - }, - "showPassword": { - "label": "Show password" - }, - "deliveryStatus": { - "delivered": "Delivered", - "failed": "Delivery Failed", - "waiting": "Waiting", - "unknown": "Unknown" - } - }, - "general": { - "label": "General" - }, - "hardware": { - "label": "Hardware" - }, - "metrics": { - "label": "Metrics" - }, - "role": { - "label": "Role" - }, - "filter": { - "label": "Filter" - }, - "advanced": { - "label": "Advanced" - }, - "clearInput": { - "label": "Clear input" - }, - "resetFilters": { - "label": "Reset Filters" - }, - "nodeName": { - "label": "Node name/number", - "placeholder": "Meshtastic 1234" - }, - "airtimeUtilization": { - "label": "Airtime Utilization (%)" - }, - "batteryLevel": { - "label": "Battery level (%)", - "labelText": "Battery level (%): {{value}}" - }, - "batteryVoltage": { - "label": "Battery voltage (V)", - "title": "Voltage" - }, - "channelUtilization": { - "label": "Channel Utilization (%)" - }, - "hops": { - "direct": "Direct", - "label": "Number of hops", - "text": "Number of hops: {{value}}" - }, - "lastHeard": { - "label": "Last heard", - "labelText": "Last heard: {{value}}", - "nowLabel": "Now" - }, - "snr": { - "label": "SNR (db)" - }, - "favorites": { - "label": "Favorites" - }, - "hide": { - "label": "Hide" - }, - "showOnly": { - "label": "Show Only" - }, - "viaMqtt": { - "label": "Connected via MQTT" - }, - "hopsUnknown": { - "label": "Unknown number of hops" - }, - "showUnheard": { - "label": "Never heard" - }, - "language": { - "label": "Language", - "changeLanguage": "Change Language" - }, - "theme": { - "dark": "Dark", - "light": "Light", - "system": "Automatic", - "changeTheme": "Change Color Scheme" - }, - "errorPage": { - "title": "This is a little embarrassing...", - "description1": "We are really sorry but an error occurred in the web client that caused it to crash.
This is not supposed to happen, and we are working hard to fix it.", - "description2": "The best way to prevent this from happening again to you or anyone else is to report the issue to us.", - "reportInstructions": "Please include the following information in your report:", - "reportSteps": { - "step1": "What you were doing when the error occurred", - "step2": "What you expected to happen", - "step3": "What actually happened", - "step4": "Any other relevant information" - }, - "reportLink": "You can report the issue to our <0>GitHub", - "dashboardLink": "Return to the <0>dashboard", - "detailsSummary": "Error Details", - "errorMessageLabel": "Error message:", - "stackTraceLabel": "Stack trace:", - "fallbackError": "{{error}}" - }, - "footer": { - "text": "Powered by <0>▲ Vercel | Meshtastic® is a registered trademark of Meshtastic LLC. | <1>Legal Information", - "commitSha": "Commit SHA: {{sha}}" - } + "navigation": { + "title": "Navigation", + "messages": "Messages", + "map": "Map", + "settings": "Settings", + "channels": "Channels", + "radioConfig": "Radio Config", + "deviceConfig": "Device Config", + "moduleConfig": "Module Config", + "manageConnections": "Manage Connections", + "nodes": "Nodes" + }, + "app": { + "title": "Meshtastic", + "logo": "Meshtastic Logo" + }, + "sidebar": { + "collapseToggle": { + "button": { + "open": "Open sidebar", + "close": "Close sidebar" + } + }, + "deviceInfo": { + "volts": "{{voltage}} volts", + "firmware": { + "title": "Firmware", + "version": "v{{version}}", + "buildDate": "Build date: {{date}}" + } + } + }, + "batteryStatus": { + "charging": "{{level}}% charging", + "pluggedIn": "Plugged in", + "title": "Battery" + }, + "search": { + "nodes": "Search nodes...", + "channels": "Search channels...", + "commandPalette": "Search commands..." + }, + "toast": { + "positionRequestSent": { + "title": "Position request sent." + }, + "requestingPosition": { + "title": "Requesting position, please wait..." + }, + "sendingTraceroute": { + "title": "Sending Traceroute, please wait..." + }, + "tracerouteSent": { + "title": "Traceroute sent." + }, + "savedChannel": { + "title": "Saved Channel: {{channelName}}" + }, + "messages": { + "pkiEncryption": { + "title": "Chat is using PKI encryption." + }, + "pskEncryption": { + "title": "Chat is using PSK encryption." + } + }, + "configSaveError": { + "title": "Error Saving Config", + "description": "An error occurred while saving the configuration." + }, + "validationError": { + "title": "Config Errors Exist", + "description": "Please fix the configuration errors before saving." + }, + "saveSuccess": { + "title": "Saving Config", + "description": "The configuration change {{case}} has been saved." + }, + "saveAllSuccess": { + "title": "Saved", + "description": "All configuration changes have been saved." + }, + "favoriteNode": { + "title": "{{action}} {{nodeName}} {{direction}} favorites.", + "action": { + "added": "Added", + "removed": "Removed", + "to": "to", + "from": "from" + } + }, + "ignoreNode": { + "title": "{{action}} {{nodeName}} {{direction}} ignore list", + "action": { + "added": "Added", + "removed": "Removed", + "to": "to", + "from": "from" + } + } + }, + "notifications": { + "copied": { + "label": "Copied!" + }, + "copyToClipboard": { + "label": "Copy to clipboard" + }, + "hidePassword": { + "label": "Hide password" + }, + "showPassword": { + "label": "Show password" + }, + "deliveryStatus": { + "delivered": "Delivered", + "failed": "Delivery Failed", + "waiting": "Waiting", + "unknown": "Unknown" + } + }, + "general": { + "label": "General" + }, + "hardware": { + "label": "Hardware" + }, + "metrics": { + "label": "Metrics" + }, + "role": { + "label": "Role" + }, + "filter": { + "label": "Filter" + }, + "advanced": { + "label": "Advanced" + }, + "clearInput": { + "label": "Clear input" + }, + "resetFilters": { + "label": "Reset Filters" + }, + "nodeName": { + "label": "Node name/number", + "placeholder": "Meshtastic 1234" + }, + "airtimeUtilization": { + "label": "Airtime Utilization (%)", + "short": "Airtime Util. (%)" + }, + "batteryLevel": { + "label": "Battery level (%)", + "labelText": "Battery level (%): {{value}}" + }, + "batteryVoltage": { + "label": "Battery voltage (V)", + "title": "Voltage" + }, + "channelUtilization": { + "label": "Channel Utilization (%)", + "short": "Channel Util. (%)" + }, + "hops": { + "direct": "Direct", + "label": "Number of hops", + "text": "Number of hops: {{value}}" + }, + "lastHeard": { + "label": "Last heard", + "labelText": "Last heard: {{value}}", + "nowLabel": "Now" + }, + "snr": { + "label": "SNR (db)" + }, + "favorites": { + "label": "Favorites" + }, + "hide": { + "label": "Hide" + }, + "showOnly": { + "label": "Show Only" + }, + "viaMqtt": { + "label": "Connected via MQTT" + }, + "hopsUnknown": { + "label": "Unknown number of hops" + }, + "showUnheard": { + "label": "Never heard" + }, + "language": { + "label": "Language", + "changeLanguage": "Change Language" + }, + "theme": { + "dark": "Dark", + "light": "Light", + "system": "Automatic", + "changeTheme": "Change Color Scheme" + }, + "errorPage": { + "title": "This is a little embarrassing...", + "description1": "We are really sorry but an error occurred in the web client that caused it to crash.
This is not supposed to happen, and we are working hard to fix it.", + "description2": "The best way to prevent this from happening again to you or anyone else is to report the issue to us.", + "reportInstructions": "Please include the following information in your report:", + "reportSteps": { + "step1": "What you were doing when the error occurred", + "step2": "What you expected to happen", + "step3": "What actually happened", + "step4": "Any other relevant information" + }, + "reportLink": "You can report the issue to our <0>GitHub", + "connectionsLink": "Return to the <0>connections", + "detailsSummary": "Error Details", + "errorMessageLabel": "Error message:", + "stackTraceLabel": "Stack trace:", + "fallbackError": "{{error}}" + }, + "footer": { + "text": "Powered by <0>▲ Vercel | Meshtastic® is a registered trademark of Meshtastic LLC. | <1>Legal Information", + "commitSha": "Commit SHA: {{sha}}" + } } diff --git a/packages/web/public/i18n/locales/bg-BG/channels.json b/packages/web/public/i18n/locales/bg-BG/channels.json index 48291a726..32a59114c 100644 --- a/packages/web/public/i18n/locales/bg-BG/channels.json +++ b/packages/web/public/i18n/locales/bg-BG/channels.json @@ -1,69 +1,71 @@ { - "page": { - "sectionLabel": "Канали", - "channelName": "Канал: {{channelName}}", - "broadcastLabel": "Първичен", - "channelIndex": "Ch {{index}}" - }, - "validation": { - "pskInvalid": "Моля, въведете валиден {{bits}} bit PSK." - }, - "settings": { - "label": "Настройки на канала", - "description": "Крипто, MQTT и други настройки" - }, - "role": { - "label": "Роля", - "description": "Телеметрията на устройството се изпраща през ПЪРВИЧЕН. Разрешен е само един ПЪРВИЧЕН.", - "options": { - "primary": "ПЪРВИЧЕН", - "disabled": "ДЕЗАКТИВИРАН", - "secondary": "ВТОРИЧЕН" - } - }, - "psk": { - "label": "Предварително споделен ключ", - "description": "Поддържани дължини на PSK: 256-битова, 128-битова, 8-битова, празна (0-битова)", - "generate": "Генериране" - }, - "name": { - "label": "Име", - "description": "Уникално име за канала <12 байта, оставете празно за подразбиране" - }, - "uplinkEnabled": { - "label": "Uplink Enabled", - "description": "Изпращане на съобщения от локалната mesh към MQTT" - }, - "downlinkEnabled": { - "label": "Downlink Enabled", - "description": "Изпращане на съобщения от MQTT към локалната mesh" - }, - "positionPrecision": { - "label": "Местоположение", - "description": "Точността на местоположението, което да се споделя с канала. Може да бъде дезактивирано.", - "options": { - "none": "Да не се споделя местоположението", - "precise": "Точно местоположение", - "metric_km23": "В рамките на 23 километра", - "metric_km12": "В рамките на 12 километра", - "metric_km5_8": "В рамките на 5.8 километра", - "metric_km2_9": "В рамките на 2.9 километра", - "metric_km1_5": "В рамките на 1.5 километра", - "metric_m700": "В рамките на 700 метра", - "metric_m350": "В рамките на 350 метра", - "metric_m200": "В рамките на 200 метра", - "metric_m90": "В рамките на 90 метра", - "metric_m50": "В рамките на 50 метра", - "imperial_mi15": "В рамките на 15 мили", - "imperial_mi7_3": "В рамките на 7.3 мили", - "imperial_mi3_6": "В рамките на 3.6 мили", - "imperial_mi1_8": "В рамките на 1.8 мили", - "imperial_mi0_9": "В рамките на 0.9 мили", - "imperial_mi0_5": "В рамките на 0.5 мили", - "imperial_mi0_2": "В рамките на 0.2 мили", - "imperial_ft600": "В рамките на 600 фута", - "imperial_ft300": "В рамките на 300 фута", - "imperial_ft150": "В рамките на 150 фута" - } - } + "page": { + "sectionLabel": "Канали", + "channelName": "Канал: {{channelName}}", + "broadcastLabel": "Първичен", + "channelIndex": "К {{index}}", + "import": "Импортиране", + "export": "Експортиране" + }, + "validation": { + "pskInvalid": "Моля, въведете валиден {{bits}} bit PSK." + }, + "settings": { + "label": "Настройки на канала", + "description": "Крипто, MQTT и други настройки" + }, + "role": { + "label": "Роля", + "description": "Телеметрията на устройството се изпраща през ПЪРВИЧЕН. Разрешен е само един ПЪРВИЧЕН.", + "options": { + "primary": "ПЪРВИЧЕН", + "disabled": "ДЕЗАКТИВИРАН", + "secondary": "ВТОРИЧЕН" + } + }, + "psk": { + "label": "Предварително споделен ключ", + "description": "Поддържани дължини на PSK: 256-битова, 128-битова, 8-битова, празна (0-битова)", + "generate": "Генериране" + }, + "name": { + "label": "Име", + "description": "Уникално име за канала <12 байта, оставете празно за подразбиране" + }, + "uplinkEnabled": { + "label": "Uplink е активиран", + "description": "Изпращане на съобщения от локалната mesh към MQTT" + }, + "downlinkEnabled": { + "label": "Downlink е активиран", + "description": "Изпращане на съобщения от MQTT към локалната mesh" + }, + "positionPrecision": { + "label": "Местоположение", + "description": "Точността на местоположението, което да се споделя с канала. Може да бъде дезактивирано.", + "options": { + "none": "Да не се споделя местоположението", + "precise": "Точно местоположение", + "metric_km23": "В рамките на 23 километра", + "metric_km12": "В рамките на 12 километра", + "metric_km5_8": "В рамките на 5.8 километра", + "metric_km2_9": "В рамките на 2.9 километра", + "metric_km1_5": "В рамките на 1.5 километра", + "metric_m700": "В рамките на 700 метра", + "metric_m350": "В рамките на 350 метра", + "metric_m200": "В рамките на 200 метра", + "metric_m90": "В рамките на 90 метра", + "metric_m50": "В рамките на 50 метра", + "imperial_mi15": "В рамките на 15 мили", + "imperial_mi7_3": "В рамките на 7.3 мили", + "imperial_mi3_6": "В рамките на 3.6 мили", + "imperial_mi1_8": "В рамките на 1.8 мили", + "imperial_mi0_9": "В рамките на 0.9 мили", + "imperial_mi0_5": "В рамките на 0.5 мили", + "imperial_mi0_2": "В рамките на 0.2 мили", + "imperial_ft600": "В рамките на 600 фута", + "imperial_ft300": "В рамките на 300 фута", + "imperial_ft150": "В рамките на 150 фута" + } + } } diff --git a/packages/web/public/i18n/locales/bg-BG/commandPalette.json b/packages/web/public/i18n/locales/bg-BG/commandPalette.json index f3e771ff0..b2f051360 100644 --- a/packages/web/public/i18n/locales/bg-BG/commandPalette.json +++ b/packages/web/public/i18n/locales/bg-BG/commandPalette.json @@ -15,7 +15,6 @@ "messages": "Съобщения", "map": "Карта", "config": "Конфигурация", - "channels": "Канали", "nodes": "Възли" } }, @@ -45,7 +44,8 @@ "label": "Отстраняване на грешки", "command": { "reconfigure": "Преконфигуриране", - "clearAllStoredMessages": "Изчистване на всички съхранени съобщения" + "clearAllStoredMessages": "Изчистване на всички съхранени съобщения", + "clearAllStores": "Clear All Local Storage" } } } diff --git a/packages/web/public/i18n/locales/bg-BG/common.json b/packages/web/public/i18n/locales/bg-BG/common.json index b1c78a235..18df84c07 100644 --- a/packages/web/public/i18n/locales/bg-BG/common.json +++ b/packages/web/public/i18n/locales/bg-BG/common.json @@ -1,142 +1,165 @@ { - "button": { - "apply": "Приложи", - "backupKey": "Резервно копие на ключа", - "cancel": "Отказ", - "clearMessages": "Изчистване на съобщенията", - "close": "Затвори", - "confirm": "Потвърждаване", - "delete": "Изтриване", - "dismiss": "Отхвърляне", - "download": "Изтегляне", - "export": "Експортиране", - "generate": "Генериране", - "regenerate": "Регенериране", - "import": "Импортиране", - "message": "Съобщение", - "now": "Сега", - "ok": "Добре", - "print": "Отпечатване", - "remove": "Изтрий", - "requestNewKeys": "Заявка за нови ключове", - "requestPosition": "Request Position", - "reset": "Нулиране", - "save": "Запис", - "scanQr": "Сканиране на QR кода", - "traceRoute": "Trace Route", - "submit": "Изпращане" - }, - "app": { - "title": "Meshtastic", - "fullTitle": "Meshtastic Web клиент" - }, - "loading": "Зареждане...", - "unit": { - "cps": "CPS", - "dbm": "dBm", - "hertz": "Hz", - "hop": { - "one": "Хоп", - "plural": "Хопа" - }, - "hopsAway": { - "one": "{{count}} hop away", - "plural": "{{count}} hops away", - "unknown": "Unknown hops away" - }, - "megahertz": "MHz", - "raw": "raw", - "meter": { - "one": "Метър", - "plural": "Метри", - "suffix": "m" - }, - "minute": { - "one": "Минута", - "plural": "Минути" - }, - "hour": { - "one": "Час", - "plural": "Часа" - }, - "millisecond": { - "one": "Милисекунда", - "plural": "Милисекунди", - "suffix": "ms" - }, - "second": { - "one": "Секунда", - "plural": "Секунди" - }, - "day": { - "one": "Ден", - "plural": "Дни" - }, - "month": { - "one": "Месец", - "plural": "Месеца" - }, - "year": { - "one": "Година", - "plural": "Години" - }, - "snr": "SNR", - "volt": { - "one": "Волт", - "plural": "Волта", - "suffix": "V" - }, - "record": { - "one": "Записи", - "plural": "Записи" - } - }, - "security": { - "0bit": "Празен", - "8bit": "8 bit", - "128bit": "128 bit", - "256bit": "256 bit" - }, - "unknown": { - "longName": "Неизвестно", - "shortName": "НЕИЗВ.", - "notAvailable": "N/A", - "num": "??" - }, - "nodeUnknownPrefix": "!", - "unset": "НЕЗАДАДЕН", - "fallbackName": "Meshtastic {{last4}}", - "node": "Възел", - "formValidation": { - "unsavedChanges": "Незапазени промени", - "tooBig": { - "string": "Твърде дълъг, очаква се по-малко или равно на {{maximum}} знака.", - "number": "Твърде голям, очаква се число по-малко или равно на {{maximum}}.", - "bytes": "Твърде голям, очаква се по-малък или равен на {{params.maximum}} байта." - }, - "tooSmall": { - "string": "Твърде кратък, очаква се повече или равно на {{minimum}} знака.", - "number": "Твърде малък, очаква се число, по-голямо или равно на {{minimum}}." - }, - "invalidFormat": { - "ipv4": "Невалиден формат, очаква се IPv4 адрес.", - "key": "Невалиден формат, очаква се предварително споделен ключ (PSK), кодиран с Base64." - }, - "invalidType": { - "number": "Невалиден тип, очаква се число." - }, - "pskLength": { - "0bit": "Ключът трябва да е празен.", - "8bit": "Ключът трябва да бъде 8-битов предварително споделен ключ (PSK).", - "128bit": "Ключът трябва да бъде 128-битов предварително споделен ключ (PSK).", - "256bit": "Ключът трябва да бъде 256-битов предварително споделен ключ (PSK)." - }, - "required": { - "generic": "Това поле е задължително.", - "managed": "Изисква се поне един администраторски ключ, ако възелът е управляван.", - "key": "Ключът е задължителен." - } - }, - "yes": "Да", - "no": "Не" + "button": { + "apply": "Приложи", + "addConnection": "Добавяне на връзка", + "saveConnection": "Запазване на връзката", + "backupKey": "Резервно копие на ключа", + "cancel": "Отказ", + "connect": "Свързване", + "clearMessages": "Изчистване на съобщенията", + "close": "Затвори", + "confirm": "Потвърждаване", + "delete": "Изтриване", + "dismiss": "Отхвърляне", + "download": "Изтегляне", + "disconnect": "Прекъсване на връзката", + "export": "Експортиране", + "generate": "Генериране", + "regenerate": "Регенериране", + "import": "Импортиране", + "message": "Съобщение", + "now": "Сега", + "ok": "Добре", + "print": "Отпечатване", + "remove": "Изтрий", + "requestNewKeys": "Заявка за нови ключове", + "requestPosition": "Request Position", + "reset": "Нулиране", + "retry": "Retry", + "save": "Запис", + "setDefault": "Задаване по подразбиране", + "unsetDefault": "Unset default", + "scanQr": "Сканиране на QR кода", + "traceRoute": "Trace Route", + "submit": "Изпращане" + }, + "app": { + "title": "Meshtastic", + "fullTitle": "Meshtastic Web клиент" + }, + "loading": "Зареждане...", + "unit": { + "cps": "CPS", + "dbm": "dBm", + "hertz": "Hz", + "hop": { + "one": "Хоп", + "plural": "Хопа" + }, + "hopsAway": { + "one": "{{count}} hop away", + "plural": "{{count}} hops away", + "unknown": "Unknown hops away" + }, + "megahertz": "MHz", + "kilohertz": "kHz", + "raw": "raw", + "meter": { + "one": "Метър", + "plural": "Метри", + "suffix": "m" + }, + "kilometer": { + "one": "Километър", + "plural": "Километри", + "suffix": "км" + }, + "minute": { + "one": "Минута", + "plural": "Минути" + }, + "hour": { + "one": "Час", + "plural": "Часа" + }, + "millisecond": { + "one": "Милисекунда", + "plural": "Милисекунди", + "suffix": "ms" + }, + "second": { + "one": "Секунда", + "plural": "Секунди" + }, + "day": { + "one": "Ден", + "plural": "Дни", + "today": "Днес", + "yesterday": "Вчера" + }, + "month": { + "one": "Месец", + "plural": "Месеца" + }, + "year": { + "one": "Година", + "plural": "Години" + }, + "snr": "SNR", + "volt": { + "one": "Волт", + "plural": "Волта", + "suffix": "V" + }, + "record": { + "one": "Записи", + "plural": "Записи" + }, + "degree": { + "one": "Градус", + "plural": "Градуса", + "suffix": "°" + } + }, + "security": { + "0bit": "Празен", + "8bit": "8 bit", + "128bit": "128 bit", + "256bit": "256 bit" + }, + "unknown": { + "longName": "Неизвестно", + "shortName": "НЕИЗВ.", + "notAvailable": "N/A", + "num": "??" + }, + "nodeUnknownPrefix": "!", + "unset": "НЕЗАДАДЕН", + "fallbackName": "Meshtastic {{last4}}", + "node": "Възел", + "formValidation": { + "unsavedChanges": "Незапазени промени", + "tooBig": { + "string": "Твърде дълъг, очаква се по-малко или равно на {{maximum}} знака.", + "number": "Твърде голям, очаква се число по-малко или равно на {{maximum}}.", + "bytes": "Твърде голям, очаква се по-малък или равен на {{params.maximum}} байта." + }, + "tooSmall": { + "string": "Твърде кратък, очаква се повече или равно на {{minimum}} знака.", + "number": "Твърде малък, очаква се число, по-голямо или равно на {{minimum}}." + }, + "invalidFormat": { + "ipv4": "Невалиден формат, очаква се IPv4 адрес.", + "key": "Невалиден формат, очаква се предварително споделен ключ (PSK), кодиран с Base64." + }, + "invalidType": { + "number": "Невалиден тип, очаква се число." + }, + "pskLength": { + "0bit": "Ключът трябва да е празен.", + "8bit": "Ключът трябва да бъде 8-битов предварително споделен ключ (PSK).", + "128bit": "Ключът трябва да бъде 128-битов предварително споделен ключ (PSK).", + "256bit": "Ключът трябва да бъде 256-битов предварително споделен ключ (PSK)." + }, + "required": { + "generic": "Това поле е задължително.", + "managed": "Изисква се поне един администраторски ключ, ако възелът е управляван.", + "key": "Ключът е задължителен." + }, + "invalidOverrideFreq": { + "number": "Невалиден формат, очаквана е стойност в диапазона 410-930 MHz или 0 (използвайте стойността по подразбиране)." + } + }, + "yes": "Да", + "no": "Не" } diff --git a/packages/web/public/i18n/locales/bg-BG/config.json b/packages/web/public/i18n/locales/bg-BG/config.json new file mode 100644 index 000000000..b1d8c370a --- /dev/null +++ b/packages/web/public/i18n/locales/bg-BG/config.json @@ -0,0 +1,458 @@ +{ + "page": { + "title": "Настройки", + "tabUser": "Потребител", + "tabChannels": "Канали", + "tabBluetooth": "Bluetooth", + "tabDevice": "Устройство", + "tabDisplay": "Дисплей", + "tabLora": "LoRa", + "tabNetwork": "Мрежа", + "tabPosition": "Позиция", + "tabPower": "Захранване", + "tabSecurity": "Сигурност" + }, + "sidebar": { + "label": "Конфигурация" + }, + "device": { + "title": "Настройки на устройството", + "description": "Настройки за устройството", + "buttonPin": { + "description": "Button pin override", + "label": "Пин за бутон" + }, + "buzzerPin": { + "description": "Buzzer pin override", + "label": "Пин за зумер" + }, + "disableTripleClick": { + "description": "Дезактивиране на трикратното щракване", + "label": "Дезактивиране на трикратното щракване" + }, + "doubleTapAsButtonPress": { + "description": "Treat double tap as button press", + "label": "Double Tap as Button Press" + }, + "ledHeartbeatDisabled": { + "description": "Дезактивиране на мигащия светодиод по подразбиране", + "label": "LED Heartbeat Disabled" + }, + "nodeInfoBroadcastInterval": { + "description": "How often to broadcast node info", + "label": "Node Info Broadcast Interval" + }, + "posixTimezone": { + "description": "The POSIX timezone string for the device", + "label": "POSIX часова зона" + }, + "rebroadcastMode": { + "description": "How to handle rebroadcasting", + "label": "Режим на препредаване" + }, + "role": { + "description": "Каква роля изпълнява устройството в mesh", + "label": "Роля" + } + }, + "bluetooth": { + "title": "Настройки за Bluetooth", + "description": "Настройки за Bluetooth модула", + "note": "Забележка: Някои устройства (ESP32) не могат да използват едновременно Bluetooth и WiFi.", + "enabled": { + "description": "Активиране или дезактивиране на Bluetooth", + "label": "Активиран" + }, + "pairingMode": { + "description": "Поведение при избор на ПИН.", + "label": "Режим на сдвояване" + }, + "pin": { + "description": "Pin to use when pairing", + "label": "ПИН" + } + }, + "display": { + "description": "Настройки за дисплея на устройството", + "title": "Настройки на дисплея", + "headingBold": { + "description": "Bolden the heading text", + "label": "Удебелен заглавен шрифт" + }, + "carouselDelay": { + "description": "Колко бързо да се превключва между прозорците", + "label": "Carousel Delay" + }, + "compassNorthTop": { + "description": "Фиксиране на север към горната част на компаса", + "label": "Север на компаса отгоре" + }, + "displayMode": { + "description": "Screen layout variant", + "label": "Display Mode" + }, + "displayUnits": { + "description": "Показване на метрични или имперски мерни единици", + "label": "Display Units" + }, + "flipScreen": { + "description": "Обръщане на дисплея на 180 градуса", + "label": "Обръщане на дисплея" + }, + "gpsDisplayUnits": { + "description": "Coordinate display format", + "label": "GPS Display Units" + }, + "oledType": { + "description": "Тип на OLED екрана, прикрепен към устройството", + "label": "Тип OLED" + }, + "screenTimeout": { + "description": "Turn off the display after this long", + "label": "Screen Timeout" + }, + "twelveHourClock": { + "description": "Използване на 12-часов формат на часовника", + "label": "12-часов часовник" + }, + "wakeOnTapOrMotion": { + "description": "Събуждане на устройството при докосване или движение", + "label": "Събуждане при докосване или движение" + } + }, + "lora": { + "title": "Настройки на Mesh", + "description": "Настройки за LoRa mesh", + "bandwidth": { + "description": "Широчина на канала в kHz", + "label": "Широчина на честотната лента" + }, + "boostedRxGain": { + "description": "Boosted RX gain", + "label": "Boosted RX Gain" + }, + "codingRate": { + "description": "The denominator of the coding rate", + "label": "Coding Rate" + }, + "frequencyOffset": { + "description": "Frequency offset to correct for crystal calibration errors", + "label": "Отместване на честотата" + }, + "frequencySlot": { + "description": "Номер на LoRa честотен канал", + "label": "Честотен слот" + }, + "hopLimit": { + "description": "Максимален брой хопове", + "label": "Лимит на хопове" + }, + "ignoreMqtt": { + "description": "Да не се препращат MQTT съобщения през mesh", + "label": "Игнориране на MQTT" + }, + "modemPreset": { + "description": "Използване на предварително настроен модем", + "label": "Предварително настроен модем" + }, + "okToMqtt": { + "description": "When set to true, this configuration indicates that the user approves the packet to be uploaded to MQTT. If set to false, remote nodes are requested not to forward packets to MQTT", + "label": "OK to MQTT" + }, + "overrideDutyCycle": { + "description": "Override Duty Cycle", + "label": "Override Duty Cycle" + }, + "overrideFrequency": { + "description": "Override frequency", + "label": "Override Frequency" + }, + "region": { + "description": "Задаване на региона за вашия възел", + "label": "Регион" + }, + "spreadingFactor": { + "description": "Indicates the number of chirps per symbol", + "label": "Spreading Factor" + }, + "transmitEnabled": { + "description": "Активиране/дезактивиране на предаването (TX) от LoRa радиото", + "label": "Предаването е активирано" + }, + "transmitPower": { + "description": "Максимална мощност на предаване", + "label": "Мощност на предаване" + }, + "usePreset": { + "description": "Използване на една от предварително зададените настройки на модема", + "label": "Използване на предварително зададени настройки" + }, + "meshSettings": { + "description": "Настройки за LoRa mesh", + "label": "Настройки на Mesh" + }, + "waveformSettings": { + "description": "Settings for the LoRa waveform", + "label": "Waveform Settings" + }, + "radioSettings": { + "label": "Настройки на радиото", + "description": "Настройки за LoRa радиото" + } + }, + "network": { + "title": "Конфигурация на WiFi", + "description": "Конфигурация на WiFi радиото", + "note": "Забележка: Някои устройства (ESP32) не могат да използват едновременно Bluetooth и WiFi.", + "addressMode": { + "description": "Address assignment selection", + "label": "Режим на адреса" + }, + "dns": { + "description": "DNS сървър", + "label": "DNS" + }, + "ethernetEnabled": { + "description": "Активиране или дезактивиране на Ethernet порта", + "label": "Активиран" + }, + "gateway": { + "description": "Шлюз по подразбиране", + "label": "Шлюз" + }, + "ip": { + "description": "IP адрес", + "label": "IP" + }, + "psk": { + "description": "Парола за мрежата", + "label": "PSK" + }, + "ssid": { + "description": "Име на мрежата", + "label": "SSID" + }, + "subnet": { + "description": "Подмрежова маска", + "label": "Подмрежа" + }, + "wifiEnabled": { + "description": "Активиране или дезактивиране на WiFi радиото", + "label": "Активиран" + }, + "meshViaUdp": { + "label": "Mesh чрез UDP" + }, + "ntpServer": { + "label": "NTP сървър" + }, + "rsyslogServer": { + "label": "Сървър Rsyslog" + }, + "ethernetConfigSettings": { + "description": "Конфигуриране на Ethernet порта", + "label": "Конфигурация на Ethernet " + }, + "ipConfigSettings": { + "description": "Конфигуриране на IP", + "label": "Конфигурация на IP" + }, + "ntpConfigSettings": { + "description": "Конфигуриране на NTP", + "label": "Конфигурация на NTP" + }, + "rsyslogConfigSettings": { + "description": "Конфигуриране на Rsyslog", + "label": "Конфиг. на Rsyslog" + }, + "udpConfigSettings": { + "description": "Конфигуриране на UDP през Mesh", + "label": "Конфигуриране на UDP" + } + }, + "position": { + "title": "Настройки на позицията", + "description": "Настройки за модула за позиция", + "broadcastInterval": { + "description": "How often your position is sent out over the mesh", + "label": "Интервал на излъчване" + }, + "enablePin": { + "description": "GPS module enable pin override", + "label": "Активиране на пин" + }, + "fixedPosition": { + "description": "Да не се докладва GPS позиция, а ръчно зададена такава", + "label": "Фиксирана позиция" + }, + "gpsMode": { + "description": "Конфигуриране дали GPS на устройството е активиран, деактивиран или липсва", + "label": "Режим на GPS" + }, + "gpsUpdateInterval": { + "description": "Колко често трябва да се получава GPS сигнал", + "label": "Интервал на актуализиране на GPS" + }, + "positionFlags": { + "description": "Optional fields to include when assembling position messages. The more fields are selected, the larger the message will be leading to longer airtime usage and a higher risk of packet loss.", + "label": "Position Flags" + }, + "receivePin": { + "description": "GPS module RX pin override", + "label": "Receive Pin" + }, + "smartPositionEnabled": { + "description": "Only send position when there has been a meaningful change in location", + "label": "Enable Smart Position" + }, + "smartPositionMinDistance": { + "description": "Минималното разстояние (в метри), което трябва да се измине, преди да се изпрати актуализация на местоположението", + "label": "Минимално разстояние за интелигентна позиция" + }, + "smartPositionMinInterval": { + "description": "Minimum interval (in seconds) that must pass before a position update is sent", + "label": "Smart Position Minimum Interval" + }, + "transmitPin": { + "description": "GPS module TX pin override", + "label": "Transmit Pin" + }, + "intervalsSettings": { + "description": "Колко често да се изпращат актуализации на позицията", + "label": "Интервали" + }, + "flags": { + "placeholder": "Select position flags...", + "altitude": "Надморска височина", + "altitudeGeoidalSeparation": "Altitude Geoidal Separation", + "altitudeMsl": "Altitude is Mean Sea Level", + "dop": "Dilution of precision (DOP) PDOP used by default", + "hdopVdop": "If DOP is set, use HDOP / VDOP values instead of PDOP", + "numSatellites": "Брой сателити", + "sequenceNumber": "Пореден номер", + "timestamp": "Времево клеймо", + "unset": "Не е зададен", + "vehicleHeading": "Посока на движение на превозното средство", + "vehicleSpeed": "Скорост на превозното средство" + } + }, + "power": { + "adcMultiplierOverride": { + "description": "Използва се за настройване на отчитането на напрежението на батерията", + "label": "ADC Multiplier Override ratio" + }, + "ina219Address": { + "description": "Address of the INA219 battery monitor", + "label": "INA219 адрес" + }, + "lightSleepDuration": { + "description": "Колко дълго устройството ще бъде в лек сън", + "label": "Продължителност на лекия сън" + }, + "minimumWakeTime": { + "description": "Минималното време, през което устройството ще остане активно след получаване на пакет", + "label": "Минимално време за събуждане" + }, + "noConnectionBluetoothDisabled": { + "description": "If the device does not receive a Bluetooth connection, the BLE radio will be disabled after this long", + "label": "Няма връзка Bluetooth е дезактивиран" + }, + "powerSavingEnabled": { + "description": "Изберете, ако се захранва от източник с малък ток (напр. слънчева енергия), за да се намали максимално консумацията на енергия.", + "label": "Активиране на енергоспестяващ режим" + }, + "shutdownOnBatteryDelay": { + "description": "Automatically shutdown node after this long when on battery, 0 for indefinite", + "label": "Shutdown on battery delay" + }, + "superDeepSleepDuration": { + "description": "Колко дълго устройството ще бъде в супер дълбок сън", + "label": "Продължителност на супер дълбокия сън" + }, + "powerConfigSettings": { + "description": "Настройки за захранващия модул", + "label": "Конфигуриране на захранването" + }, + "sleepSettings": { + "description": "Настройки за спящ режим за захранващия модул", + "label": "Настройки за сън" + } + }, + "security": { + "description": "Настройки за конфигурацията за сигурност", + "title": "Насртойки на сигурността", + "button_backupKey": "Резервно копие на ключа", + "adminChannelEnabled": { + "description": "Allow incoming device control over the insecure legacy admin channel", + "label": "Allow Legacy Admin" + }, + "enableDebugLogApi": { + "description": "Output live debug logging over serial, view and export position-redacted device logs over Bluetooth", + "label": "Enable Debug Log API" + }, + "managed": { + "description": "Ако е активирана, опциите за конфигурация на устройството могат да се променят дистанционно само от възел за отдалечено администриране чрез администраторски съобщения. Не активирайте тази опция, освен ако не е настроен поне един подходящ възел за отдалечено администриране и публичният ключ е съхранен в едно от полетата по-горе.", + "label": "Управлява се" + }, + "privateKey": { + "description": "Използва се за създаване на споделен ключ с отдалечено устройство", + "label": "Частен ключ" + }, + "publicKey": { + "description": "Изпраща се до други възли в mesh, за да им позволи да изчислят споделения секретен ключ", + "label": "Публичен ключ" + }, + "primaryAdminKey": { + "description": "Основният публичен ключ, оторизиран за изпращане на администраторски съобщения до този възел", + "label": "Основен администраторски ключ" + }, + "secondaryAdminKey": { + "description": "Вторичният публичен ключ, оторизиран за изпращане на администраторски съобщения до този възел.", + "label": "Вторичен администраторски ключ" + }, + "serialOutputEnabled": { + "description": "Serial Console over the Stream API", + "label": "Serial Output Enabled" + }, + "tertiaryAdminKey": { + "description": "Третичният публичен ключ, оторизиран за изпращане на администраторски съобщения до този възел", + "label": "Третичен администраторски ключ" + }, + "adminSettings": { + "description": "Настройки за Admin", + "label": "Администраторски настройки" + }, + "loggingSettings": { + "description": "Settings for Logging", + "label": "Logging Settings" + } + }, + "user": { + "title": "User Settings", + "description": "Configure your device name and identity settings", + "longName": { + "label": "Дълго име", + "description": "Your full display name (1-40 characters)", + "validation": { + "min": "Long name must be at least 1 character", + "max": "Long name must be at most 40 characters" + } + }, + "shortName": { + "label": "Кратко име", + "description": "Your abbreviated name (2-4 characters)", + "validation": { + "min": "Short name must be at least 2 characters", + "max": "Short name must be at most 4 characters" + } + }, + "isUnmessageable": { + "label": "Без съобщения", + "description": "Used to identify unmonitored or infrastructure nodes so that messaging is not available to nodes that will never respond." + }, + "isLicensed": { + "label": "Лицензиран радиолюбител (HAM)", + "description": "Enable if you are a licensed amateur radio operator, enabling this option disables encryption and is not compatible with the default Meshtastic network." + } + } +} diff --git a/packages/web/public/i18n/locales/bg-BG/connections.json b/packages/web/public/i18n/locales/bg-BG/connections.json new file mode 100644 index 000000000..c3ce42e14 --- /dev/null +++ b/packages/web/public/i18n/locales/bg-BG/connections.json @@ -0,0 +1,34 @@ +{ + "page": { + "title": "Свързване с устройство Meshtastic", + "description": "Добавете връзка с устройството чрез HTTP, Bluetooth или сериен порт. Запазените ви връзки ще бъдат запазени във вашия браузър." + }, + "connectionType_ble": "BLE", + "connectionType_serial": "Серийна", + "connectionType_network": "Мрежа", + "deleteConnection": "Изтриване на връзката", + "areYouSure": "Това ще премахне {{name}}. Не можете да отмените това действие.", + "moreActions": "Още действия", + "noConnections": { + "title": "Все още няма връзки.", + "description": "Създайте първата си връзка. Тя ще се свърже веднага и ще бъде запазена за по-късно." + }, + "lastConnectedAt": "Последно свързване: {{date}}", + "neverConnected": "Никога не е бил свързан", + "toasts": { + "connected": "Свързано", + "nowConnected": "{{name}} е свързан сега", + "nowDisconnected": "{{name}} are now disconnecte", + "disconnected": "Прекъсната връзка", + "failed": "Свързването не е успешно", + "checkConnetion": "Проверете устройството или настройките си и опитайте отново", + "defaultSet": "Default set", + "defaultConnection": "Default connection is now {{nameisconnected}}", + "deleted": "Изтрит", + "deletedByName": "{{name}} беше премахнат", + "pickConnectionAgain": "Не можа да се свърже. Може да се наложи да изберете отново устройството/порта.", + "added": "Връзката е добавена", + "savedByName": "{{name}} е запазен.", + "savedCantConnect": "Връзката беше запазена, но не можа да се осъществи свързване." + } +} diff --git a/packages/web/public/i18n/locales/bg-BG/dashboard.json b/packages/web/public/i18n/locales/bg-BG/dashboard.json deleted file mode 100644 index f59f4eb45..000000000 --- a/packages/web/public/i18n/locales/bg-BG/dashboard.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "dashboard": { - "title": "Свързани устройства", - "description": "Управлявайте свързаните си устройства Meshtastic.", - "connectionType_ble": "BLE", - "connectionType_serial": "Серийна", - "connectionType_network": "Мрежа", - "noDevicesTitle": "Няма свързани устройства", - "noDevicesDescription": "Свържете ново устройство, за да започнете.", - "button_newConnection": "Нова връзка" - } -} diff --git a/packages/web/public/i18n/locales/bg-BG/deviceConfig.json b/packages/web/public/i18n/locales/bg-BG/deviceConfig.json index ad8a7338a..d4e1b8510 100644 --- a/packages/web/public/i18n/locales/bg-BG/deviceConfig.json +++ b/packages/web/public/i18n/locales/bg-BG/deviceConfig.json @@ -122,7 +122,7 @@ "title": "Настройки на Mesh", "description": "Настройки за LoRa mesh", "bandwidth": { - "description": "Широчина на канала в MHz", + "description": "Широчина на канала в kHz", "label": "Широчина на честотната лента" }, "boostedRxGain": { diff --git a/packages/web/public/i18n/locales/bg-BG/dialog.json b/packages/web/public/i18n/locales/bg-BG/dialog.json index 1940890bc..d1244fdfc 100644 --- a/packages/web/public/i18n/locales/bg-BG/dialog.json +++ b/packages/web/public/i18n/locales/bg-BG/dialog.json @@ -1,193 +1,238 @@ { - "deleteMessages": { - "description": "Това действие ще изчисти цялата история на съобщенията. Това не може да бъде отменено. Сигурни ли сте, че искате да продължите?", - "title": "Изчистване на всички съобщения" - }, - "deviceName": { - "description": "Устройството ще се рестартира, след като конфигурацията бъде запазена.", - "longName": "Дълго име", - "shortName": "Кратко име", - "title": "Промяна на името на устройството", - "validation": { - "longNameMax": "Дългото име не трябва да е повече от 40 знака", - "shortNameMax": "Краткото име не трябва да е повече от 4 знака", - "longNameMin": "Дългото име трябва да съдържа поне 1 символ", - "shortNameMin": "Краткото име трябва да съдържа поне 1 символ" - } - }, - "import": { - "description": "Текущата конфигурация на LoRa ще бъде презаписана.", - "error": { - "invalidUrl": "Невалиден Meshtastic URL" - }, - "channelPrefix": "Канал: ", - "channelSetUrl": "Channel Set/QR Code URL", - "channels": "Канали:", - "usePreset": "Използване на предварително зададени настройки?", - "title": "Import Channel Set" - }, - "locationResponse": { - "title": "Местоположение: {{identifier}}", - "altitude": "Надморска височина: ", - "coordinates": "Координати:", - "noCoordinates": "Няма координати" - }, - "pkiRegenerateDialog": { - "title": "Регенериране на предварително споделения ключ?", - "description": "Сигурни ли сте, че искате да регенерирате предварително споделения ключ?", - "regenerate": "Регенериране" - }, - "newDeviceDialog": { - "title": "Свързване на ново устройство", - "https": "https", - "http": "http", - "tabHttp": "HTTP", - "tabBluetooth": "Bluetooth", - "tabSerial": "Серийна", - "useHttps": "Използване на HTTPS", - "connecting": "Свързване...", - "connect": "Свързване", - "connectionFailedAlert": { - "title": "Връзката е неуспешна", - "descriptionPrefix": "Не може да се свърже с устройството.", - "httpsHint": "Ако използвате HTTPS, може да се наложи първо да приемете самоподписан сертификат. ", - "openLinkPrefix": "Моля, отворете", - "openLinkSuffix": "в нов раздел", - "acceptTlsWarningSuffix": ", accept any TLS warnings if prompted, then try again", - "learnMoreLink": "Научете повече" - }, - "httpConnection": { - "label": "IP адрес/Име на хост", - "placeholder": "000.000.000.000 / meshtastic.local" - }, - "serialConnection": { - "noDevicesPaired": "Все още няма сдвоени устройства.", - "newDeviceButton": "Ново устройство", - "deviceIdentifier": "# {{index}} - {{vendorId}} - {{productId}}" - }, - "bluetoothConnection": { - "noDevicesPaired": "Все още няма сдвоени устройства.", - "newDeviceButton": "Ново устройство", - "connectionFailed": "Връзката е неуспешна", - "deviceDisconnected": "Устройството не е свързано", - "unknownDevice": "Неизвестно устройство", - "errorLoadingDevices": "Грешка при зареждане на устройствата", - "unknownErrorLoadingDevices": "Неизвестна грешка при зареждане на устройствата" - }, - "validation": { - "requiresWebBluetooth": "Този тип връзка изисква <0>Web Bluetooth. Моля, използвайте поддържан браузър, като Chrome или Edge.", - "requiresWebSerial": "Този тип връзка изисква <0>Web Serial. Моля, използвайте поддържан браузър, като Chrome или Edge.", - "requiresSecureContext": "Това приложение изисква <0>secure context. Моля, свържете се чрез HTTPS или localhost.", - "additionallyRequiresSecureContext": "Освен това, изисква <0>secure context. Моля, свържете се чрез HTTPS или localhost." - } - }, - "nodeDetails": { - "message": "Съобщение", - "requestPosition": "Request Position", - "traceRoute": "Trace Route", - "airTxUtilization": "Air TX utilization", - "allRawMetrics": "All Raw Metrics:", - "batteryLevel": "Ниво на батерията", - "channelUtilization": "Използване на канала", - "details": "Подробности:", - "deviceMetrics": "Device Metrics:", - "hardware": "Хардуер: ", - "lastHeard": "Последно чут: ", - "nodeHexPrefix": "Node Hex: ", - "nodeNumber": "Номер на възела: ", - "position": "Позиция:", - "role": "Роля: ", - "uptime": "Време на работа: ", - "voltage": "Напрежение", - "title": "Подробности за възел за {{identifier}}", - "ignoreNode": "Игнориране на възела", - "removeNode": "Премахване на възела", - "unignoreNode": "Премахване на игнорирането на възела", - "security": "Сигурност:", - "publicKey": "Public Key: ", - "messageable": "Messageable: ", - "KeyManuallyVerifiedTrue": "Публичният ключ е проверен ръчно", - "KeyManuallyVerifiedFalse": "Публичният ключ не е проверен ръчно" - }, - "pkiBackup": { - "loseKeysWarning": "Ако загубите ключовете си, ще трябва да нулирате устройството си.", - "secureBackup": "Важно е да направите резервно копие на публичните и частните си ключове и да съхранявате резервното си копие сигурно!", - "footer": "=== КРАЙ НА КЛЮЧОВЕТЕ ===", - "header": "=== MESHTASTIC КЛЮЧОВЕ ЗА {{longName}} ({{shortName}}) ===", - "privateKey": "Частен ключ:", - "publicKey": "Публичен ключ:", - "fileName": "meshtastic_keys_{{longName}}_{{shortName}}.txt", - "title": "Backup Keys" - }, - "pkiBackupReminder": { - "description": "Препоръчваме редовно да правите резервни копия на данните с вашите ключове. Искате ли да направите резервно копие сега?", - "title": "Напомняне за резервно копие", - "remindLaterPrefix": "Напомни ми в", - "remindNever": "Никога не ми напомняй", - "backupNow": "Създаване на резервно копие сега" - }, - "pkiRegenerate": { - "description": "Сигурни ли сте, че искате да регенерирате двойката ключове?", - "title": "Регенериране на двойката ключове" - }, - "qr": { - "addChannels": "Добавяне на канали", - "replaceChannels": "Замяна на канали", - "description": "Текущата конфигурация на LoRa също ще бъде споделена.", - "sharableUrl": "Sharable URL", - "title": "Генериране на QR код" - }, - "reboot": { - "title": "Рестартиране на устройството", - "description": "Reboot now or schedule a reboot of the connected node. Optionally, you can choose to reboot into OTA (Over-the-Air) mode.", - "ota": "Reboot into OTA mode", - "enterDelay": "Въведете забавяне", - "scheduled": "Насрочено е рестартиране", - "schedule": "Планиране на рестартиране", - "now": "Рестартиране сега", - "cancel": "Cancel scheduled reboot" - }, - "refreshKeys": { - "description": { - "acceptNewKeys": "This will remove the node from device and request new keys.", - "keyMismatchReasonSuffix": ". This is due to the remote node's current public key does not match the previously stored key for this node.", - "unableToSendDmPrefix": "Your node is unable to send a direct message to node: " - }, - "acceptNewKeys": "риемане на нови ключове", - "title": "Keys Mismatch - {{identifier}}" - }, - "removeNode": { - "description": "Сигурни ли сте, че искате да премахнете този възел?", - "title": "Премахване на възела?" - }, - "shutdown": { - "title": "Планирано изключване", - "description": "Изключване на свързания възел след x минути." - }, - "traceRoute": { - "routeToDestination": "Route to destination:", - "routeBack": "Route back:" - }, - "tracerouteResponse": { - "title": "Traceroute: {{identifier}}" - }, - "unsafeRoles": { - "confirmUnderstanding": "Да, знам какво правя", - "conjunction": "и публикацията в блога за ", - "postamble": " и разберам последиците от промяната на ролята.", - "preamble": "Аз прочетох ", - "choosingRightDeviceRole": "Избор на правилната роля на устройството", - "deviceRoleDocumentation": "Документация за ролите на устройството", - "title": "Сигурни ли сте?" - }, - "managedMode": { - "confirmUnderstanding": "Да, знам какво правя", - "title": "Сигурни ли сте?", - "description": "Enabling Managed Mode blocks client applications (including the web client) from writing configurations to a radio. Once enabled, radio configurations can only be changed through Remote Admin messages. This setting is not required for remote node administration." - }, - "clientNotification": { - "title": "Client Notification", - "TraceRoute can only be sent once every 30 seconds": "TraceRoute can only be sent once every 30 seconds", - "Compromised keys were detected and regenerated.": "Бяха открити и регенерирани компрометирани ключове." - } + "deleteMessages": { + "description": "Това действие ще изчисти цялата история на съобщенията. Това не може да бъде отменено. Сигурни ли сте, че искате да продължите?", + "title": "Изчистване на всички съобщения" + }, + "import": { + "description": "Текущата конфигурация на LoRa ще бъде презаписана.", + "error": { + "invalidUrl": "Невалиден Meshtastic URL" + }, + "channelPrefix": "Канал: ", + "primary": "Първичен ", + "doNotImport": "No not import", + "channelName": "Име", + "channelSlot": "Слот", + "channelSetUrl": "Channel Set/QR Code URL", + "useLoraConfig": "Импортиране на конфигурация на LoRa", + "presetDescription": "Текущата конфигурация na LoRa ще бъде заменена.", + "title": "Import Channel Set" + }, + "locationResponse": { + "title": "Местоположение: {{identifier}}", + "altitude": "Надморска височина: ", + "coordinates": "Координати:", + "noCoordinates": "Няма координати" + }, + "pkiRegenerateDialog": { + "title": "Регенериране на предварително споделения ключ?", + "description": "Сигурни ли сте, че искате да регенерирате предварително споделения ключ?", + "regenerate": "Регенериране" + }, + "addConnection": { + "title": "Добавяне на връзка", + "description": "Изберете тип връзка и попълнете данните", + "validation": { + "requiresWebBluetooth": "Този тип връзка изисква <0>Web Bluetooth. Моля, използвайте поддържан браузър, като Chrome или Edge.", + "requiresWebSerial": "Този тип връзка изисква <0>Web Serial. Моля, използвайте поддържан браузър, като Chrome или Edge.", + "requiresSecureContext": "Това приложение изисква <0>secure context. Моля, свържете се чрез HTTPS или localhost.", + "additionallyRequiresSecureContext": "Освен това, изисква <0>secure context. Моля, свържете се чрез HTTPS или localhost." + }, + "bluetoothConnection": { + "namePlaceholder": "Моят Bluetooth възел", + "supported": { + "title": "Поддържа се Web Bluetooth" + }, + "notSupported": { + "title": "Не се поддържа Web Bluetooth", + "description": "Вашият браузър или устройство не поддържа Web Bluetooth" + }, + "short": "BT: {{deviceName}}", + "long": "Bluetooth устройство", + "device": "Устройство", + "selectDevice": "Изберете устройство", + "selected": "Избрано Bluetooth устройство", + "notSelected": "Няма избрано устройство", + "helperText": "Използва услугата Meshtastic Bluetooth за откриване." + }, + "serialConnection": { + "namePlaceholder": "Моят сериен възел", + "helperText": "Selecting a port grants permission so the app can open it to connect.", + "supported": { + "title": "Web Serial supported" + }, + "notSupported": { + "title": "Web Serial not supported", + "description": "Your browser or device does not support Web Serial" + }, + "portSelected": { + "title": "Serial port selected", + "description": "Port permissions granted." + }, + "port": "Порт", + "selectPort": "Изберете порт", + "deviceName": "USB {{vendorId}}:{{productId}}", + "notSelected": "Няма избран порт" + }, + "httpConnection": { + "namePlaceholder": "Моят HTTP възел", + "inputPlaceholder": "192.168.1.10 или meshtastic.local", + "heading": "URL или IP", + "useHttps": "Използване на HTTPS", + "invalidUrl": { + "title": "Невалиден URL", + "description": "Моля, въведете валиден HTTP или HTTPS URL." + }, + "connectionTest": { + "description": "Тествайте връзката, преди да я запазите, за да се уверите, че устройството е достъпно.", + "button": { + "loading": "Тестване...", + "label": "Тестване на връзката" + }, + "reachable": "Достъпно", + "notReachable": "Не е достъпно", + "success": { + "title": "Тестът на връзката е успешен", + "description": "Устройството изглежда е достъпно." + }, + "failure": { + "title": "Тестът на връзката не е успешен", + "description": "Не можа да се осъществи връзка с устройството. Проверете URL-а и опитайте отново." + } + } + } + }, + "nodeDetails": { + "message": "Съобщение", + "requestPosition": "Request Position", + "traceRoute": "Trace Route", + "airTxUtilization": "Air TX utilization", + "allRawMetrics": "All Raw Metrics:", + "batteryLevel": "Ниво на батерията", + "channelUtilization": "Използване на канала", + "details": "Подробности:", + "deviceMetrics": "Device Metrics:", + "hardware": "Хардуер: ", + "lastHeard": "Последно чут: ", + "nodeHexPrefix": "Node Hex: ", + "nodeNumber": "Номер на възела: ", + "position": "Позиция:", + "role": "Роля: ", + "uptime": "Време на работа: ", + "voltage": "Напрежение", + "title": "Подробности за възел за {{identifier}}", + "ignoreNode": "Игнориране на възела", + "removeNode": "Премахване на възела", + "unignoreNode": "Премахване на игнорирането на възела", + "security": "Сигурност:", + "publicKey": "Публичен ключ:", + "messageable": "Messageable: ", + "KeyManuallyVerifiedTrue": "Публичният ключ е проверен ръчно", + "KeyManuallyVerifiedFalse": "Публичният ключ не е проверен ръчно" + }, + "pkiBackup": { + "loseKeysWarning": "Ако загубите ключовете си, ще трябва да нулирате устройството си.", + "secureBackup": "Важно е да направите резервно копие на публичните и частните си ключове и да съхранявате резервното си копие сигурно!", + "footer": "=== КРАЙ НА КЛЮЧОВЕТЕ ===", + "header": "=== MESHTASTIC КЛЮЧОВЕ ЗА {{longName}} ({{shortName}}) ===", + "privateKey": "Частен ключ:", + "publicKey": "Публичен ключ:", + "fileName": "meshtastic_keys_{{longName}}_{{shortName}}.txt", + "title": "Backup Keys" + }, + "pkiBackupReminder": { + "description": "Препоръчваме редовно да правите резервни копия на данните с вашите ключове. Искате ли да направите резервно копие сега?", + "title": "Напомняне за резервно копие", + "remindLaterPrefix": "Напомни ми в", + "remindNever": "Никога не ми напомняй", + "backupNow": "Създаване на резервно копие сега" + }, + "pkiRegenerate": { + "description": "Сигурни ли сте, че искате да регенерирате двойката ключове?", + "title": "Регенериране на двойката ключове" + }, + "qr": { + "addChannels": "Добавяне на канали", + "replaceChannels": "Замяна на канали", + "description": "Текущата конфигурация на LoRa също ще бъде споделена.", + "sharableUrl": "Sharable URL", + "title": "Генериране на QR код" + }, + "reboot": { + "title": "Рестартиране на устройството", + "description": "Reboot now or schedule a reboot of the connected node. Optionally, you can choose to reboot into OTA (Over-the-Air) mode.", + "ota": "Reboot into OTA mode", + "enterDelay": "Въведете забавяне", + "scheduled": "Насрочено е рестартиране", + "schedule": "Планиране на рестартиране", + "now": "Рестартиране сега", + "cancel": "Cancel scheduled reboot" + }, + "refreshKeys": { + "description": { + "acceptNewKeys": "This will remove the node from device and request new keys.", + "keyMismatchReasonSuffix": ". This is due to the remote node's current public key does not match the previously stored key for this node.", + "unableToSendDmPrefix": "Вашият възел не може да изпрати директно съобщение до възел:" + }, + "acceptNewKeys": "риемане на нови ключове", + "title": "Keys Mismatch - {{identifier}}" + }, + "removeNode": { + "description": "Сигурни ли сте, че искате да премахнете този възел?", + "title": "Премахване на възела?" + }, + "shutdown": { + "title": "Планирано изключване", + "description": "Изключване на свързания възел след x минути." + }, + "traceRoute": { + "routeToDestination": "Route to destination:", + "routeBack": "Route back:" + }, + "tracerouteResponse": { + "title": "Traceroute: {{identifier}}" + }, + "unsafeRoles": { + "confirmUnderstanding": "Да, знам какво правя", + "conjunction": "и публикацията в блога за ", + "postamble": " и разберам последиците от промяната на ролята.", + "preamble": "Аз прочетох ", + "choosingRightDeviceRole": "Избор на правилната роля на устройството", + "deviceRoleDocumentation": "Документация за ролите на устройството", + "title": "Сигурни ли сте?" + }, + "managedMode": { + "confirmUnderstanding": "Да, знам какво правя", + "title": "Сигурни ли сте?", + "description": "Enabling Managed Mode blocks client applications (including the web client) from writing configurations to a radio. Once enabled, radio configurations can only be changed through Remote Admin messages. This setting is not required for remote node administration." + }, + "clientNotification": { + "title": "Client Notification", + "TraceRoute can only be sent once every 30 seconds": "TraceRoute can only be sent once every 30 seconds", + "Compromised keys were detected and regenerated.": "Бяха открити и регенерирани компрометирани ключове." + }, + "resetNodeDb": { + "title": "Reset Node Database", + "description": "This will clear all nodes from the connected device's node database and clear all message history in the client. This cannot be undone. Are you sure you want to continue?", + "confirm": "Reset Node Database", + "failedTitle": "There was an error resetting the Node DB. Please try again." + }, + "clearAllStores": { + "title": "Clear All Local Storage", + "description": "This will clear all locally stored data, including message history and node databases for all previously connected devices. This will require you to reconnect to your node once complete and cannot be undone. Are you sure you want to continue?", + "confirm": "Clear all local storage", + "failedTitle": "There was an error clearing local storage. Please try again." + }, + "factoryResetDevice": { + "title": "Фабрично нулиране на устройството", + "description": "This will factory reset the connected device, erasing all configurations and data on the device as well as all nodes and messages saved in the client. This cannot be undone. Are you sure you want to continue?", + "confirm": "Фабрично нулиране на устройството", + "failedTitle": "There was an error performing the factory reset. Please try again." + }, + "factoryResetConfig": { + "title": "Фабрично нулиране на конфигурацията", + "description": "This will factory reset the configuration on the connected device, erasing all configurations on the device. This cannot be undone. Are you sure you want to continue?", + "confirm": "Фабрично нулиране на конфигурацията", + "failedTitle": "There was an error performing the factory reset. Please try again." + } } diff --git a/packages/web/public/i18n/locales/bg-BG/map.json b/packages/web/public/i18n/locales/bg-BG/map.json new file mode 100644 index 000000000..775c0da21 --- /dev/null +++ b/packages/web/public/i18n/locales/bg-BG/map.json @@ -0,0 +1,38 @@ +{ + "maplibre": { + "GeolocateControl.FindMyLocation": "Намиране на местоположението ми", + "NavigationControl.ZoomIn": "Увеличаване", + "NavigationControl.ZoomOut": "Намаляване", + "CooperativeGesturesHandler.WindowsHelpText": "Use Ctrl + scroll to zoom the map", + "CooperativeGesturesHandler.MacHelpText": "Use ⌘ + scroll to zoom the map", + "CooperativeGesturesHandler.MobileHelpText": "Използвайте два пръста, за да местите картата" + }, + "layerTool": { + "nodeMarkers": "Показване на възли", + "directNeighbors": "Показване на директни връзки", + "remoteNeighbors": "Показване на отдалечени връзки", + "positionPrecision": "Show position precision", + "traceroutes": "Show traceroutes", + "waypoints": "Show waypoints" + }, + "mapMenu": { + "locateAria": "Locate my node", + "layersAria": "Промяна на стила на картата" + }, + "waypointDetail": { + "edit": "Редактирай", + "description": "Описание:", + "createdBy": "Редактирано от:", + "createdDate": "Създадено:", + "updated": "Актуализирано:", + "expires": "Изтича:", + "distance": "Разстояние:", + "bearing": "Absolute bearing:", + "lockedTo": "Заключено от:", + "latitude": "Географска ширина:", + "longitude": "Географска дължина:" + }, + "myNode": { + "tooltip": "Това устройство" + } +} diff --git a/packages/web/public/i18n/locales/bg-BG/messages.json b/packages/web/public/i18n/locales/bg-BG/messages.json index 9e9c68fea..e9189926c 100644 --- a/packages/web/public/i18n/locales/bg-BG/messages.json +++ b/packages/web/public/i18n/locales/bg-BG/messages.json @@ -1,39 +1,39 @@ { - "page": { - "title": "Съобщения: {{chatName}}", - "placeholder": "Въведете съобщение" - }, - "emptyState": { - "title": "Изберете чат", - "text": "Все още няма съобщения." - }, - "selectChatPrompt": { - "text": "Изберете канал или възел, за да стартирате съобщения." - }, - "sendMessage": { - "placeholder": "Въведете Вашето съобщение тук...", - "sendButton": "Изпрати" - }, - "actionsMenu": { - "addReactionLabel": "Добавяне на реакция", - "replyLabel": "Отговор" - }, - "deliveryStatus": { - "delivered": { - "label": "Съобщението е доставено", - "displayText": "Съобщението е доставено" - }, - "failed": { - "label": "Доставката на съобщението не е успешна", - "displayText": "Неуспешна доставка" - }, - "unknown": { - "label": "Статусът на съобщението е неизвестен", - "displayText": "Неизвестно състояние" - }, - "waiting": { - "label": "Изпращане на съобщение", - "displayText": "Чака доставка" - } - } + "page": { + "title": "Съобщения: {{chatName}}", + "placeholder": "Въведете съобщение" + }, + "emptyState": { + "title": "Изберете чат", + "text": "Все още няма съобщения." + }, + "selectChatPrompt": { + "text": "Изберете канал или възел, за да стартирате съобщения." + }, + "sendMessage": { + "placeholder": "Въведете Вашето съобщение тук...", + "sendButton": "Изпрати" + }, + "actionsMenu": { + "addReactionLabel": "Добавяне на реакция", + "replyLabel": "Отговор" + }, + "deliveryStatus": { + "delivered": { + "label": "Съобщението е доставено", + "displayText": "Съобщението е доставено" + }, + "failed": { + "label": "Доставката на съобщението не е успешна", + "displayText": "Неуспешна доставка" + }, + "unknown": { + "label": "Статусът на съобщението е неизвестен", + "displayText": "Неизвестно състояние" + }, + "waiting": { + "label": "Изпращане на съобщение", + "displayText": "Чака доставка" + } + } } diff --git a/packages/web/public/i18n/locales/bg-BG/moduleConfig.json b/packages/web/public/i18n/locales/bg-BG/moduleConfig.json index 674a28ac4..07d2a9ace 100644 --- a/packages/web/public/i18n/locales/bg-BG/moduleConfig.json +++ b/packages/web/public/i18n/locales/bg-BG/moduleConfig.json @@ -1,448 +1,448 @@ { - "page": { - "tabAmbientLighting": "Ambient Lighting", - "tabAudio": "Аудио", - "tabCannedMessage": "Canned", - "tabDetectionSensor": "Detection Sensor", - "tabExternalNotification": "Ext Notif", - "tabMqtt": "MQTT", - "tabNeighborInfo": "Neighbor Info", - "tabPaxcounter": "Paxcounter", - "tabRangeTest": "Тест на обхвата", - "tabSerial": "Серийна", - "tabStoreAndForward": "S&F", - "tabTelemetry": "Телеметрия" - }, - "ambientLighting": { - "title": "Ambient Lighting Settings", - "description": "Settings for the Ambient Lighting module", - "ledState": { - "label": "LED State", - "description": "Sets LED to on or off" - }, - "current": { - "label": "Текущ", - "description": "Sets the current for the LED output. Default is 10" - }, - "red": { - "label": "Червен", - "description": "Sets the red LED level. Values are 0-255" - }, - "green": { - "label": "Зелен", - "description": "Sets the green LED level. Values are 0-255" - }, - "blue": { - "label": "Син", - "description": "Sets the blue LED level. Values are 0-255" - } - }, - "audio": { - "title": "Настройки на аудиото", - "description": "Настройки за аудио модула", - "codec2Enabled": { - "label": "Codec 2 е активиран", - "description": "Enable Codec 2 audio encoding" - }, - "pttPin": { - "label": "Пин за РТТ", - "description": "GPIO пин, който да се използва за PTT" - }, - "bitrate": { - "label": "Bitrate", - "description": "Bitrate to use for audio encoding" - }, - "i2sWs": { - "label": "i2S WS", - "description": "GPIO pin to use for i2S WS" - }, - "i2sSd": { - "label": "i2S SD", - "description": "GPIO pin to use for i2S SD" - }, - "i2sDin": { - "label": "i2S DIN", - "description": "GPIO pin to use for i2S DIN" - }, - "i2sSck": { - "label": "i2S SCK", - "description": "GPIO pin to use for i2S SCK" - } - }, - "cannedMessage": { - "title": "Canned Message Settings", - "description": "Settings for the Canned Message module", - "moduleEnabled": { - "label": "Модулът е активиран", - "description": "Enable Canned Message" - }, - "rotary1Enabled": { - "label": "Ротационен енкодер #1 е активиран", - "description": "Активиране на ротационния енкодер" - }, - "inputbrokerPinA": { - "label": "Encoder Pin A", - "description": "GPIO Pin Value (1-39) For encoder port A" - }, - "inputbrokerPinB": { - "label": "Encoder Pin B", - "description": "GPIO Pin Value (1-39) For encoder port B" - }, - "inputbrokerPinPress": { - "label": "Encoder Pin Press", - "description": "GPIO Pin Value (1-39) For encoder Press" - }, - "inputbrokerEventCw": { - "label": "Clockwise event", - "description": "Select input event." - }, - "inputbrokerEventCcw": { - "label": "Counter Clockwise event", - "description": "Select input event." - }, - "inputbrokerEventPress": { - "label": "Press event", - "description": "Select input event" - }, - "updown1Enabled": { - "label": "Up Down enabled", - "description": "Enable the up / down encoder" - }, - "allowInputSource": { - "label": "Allow Input Source", - "description": "Изберете от: '_any', 'rotEnc1', 'upDownEnc1', 'cardkb'" - }, - "sendBell": { - "label": "Send Bell", - "description": "Sends a bell character with each message" - } - }, - "detectionSensor": { - "title": "Detection Sensor Settings", - "description": "Settings for the Detection Sensor module", - "enabled": { - "label": "Активиран", - "description": "Enable or disable Detection Sensor Module" - }, - "minimumBroadcastSecs": { - "label": "Minimum Broadcast Seconds", - "description": "The interval in seconds of how often we can send a message to the mesh when a state change is detected" - }, - "stateBroadcastSecs": { - "label": "State Broadcast Seconds", - "description": "The interval in seconds of how often we should send a message to the mesh with the current state regardless of changes" - }, - "sendBell": { - "label": "Send Bell", - "description": "Send ASCII bell with alert message" - }, - "name": { - "label": "Приятелско име", - "description": "Използва се за форматиране на съобщението, изпратено до mesh, максимум 20 знака" - }, - "monitorPin": { - "label": "Monitor Pin", - "description": "The GPIO pin to monitor for state changes" - }, - "detectionTriggerType": { - "label": "Detection Triggered Type", - "description": "The type of trigger event to be used" - }, - "usePullup": { - "label": "Use Pullup", - "description": "Whether or not use INPUT_PULLUP mode for GPIO pin" - } - }, - "externalNotification": { - "title": "External Notification Settings", - "description": "Configure the external notification module", - "enabled": { - "label": "Модулът е активиран", - "description": "Enable External Notification" - }, - "outputMs": { - "label": "Output MS", - "description": "Output MS" - }, - "output": { - "label": "Output", - "description": "Output" - }, - "outputVibra": { - "label": "Output Vibrate", - "description": "Output Vibrate" - }, - "outputBuzzer": { - "label": "Output Buzzer", - "description": "Output Buzzer" - }, - "active": { - "label": "Активно", - "description": "Активно" - }, - "alertMessage": { - "label": "Предупредително съобщение", - "description": "Предупредително съобщение" - }, - "alertMessageVibra": { - "label": "Alert Message Vibrate", - "description": "Alert Message Vibrate" - }, - "alertMessageBuzzer": { - "label": "Alert Message Buzzer", - "description": "Alert Message Buzzer" - }, - "alertBell": { - "label": "Alert Bell", - "description": "Should an alert be triggered when receiving an incoming bell?" - }, - "alertBellVibra": { - "label": "Alert Bell Vibrate", - "description": "Alert Bell Vibrate" - }, - "alertBellBuzzer": { - "label": "Alert Bell Buzzer", - "description": "Alert Bell Buzzer" - }, - "usePwm": { - "label": "Use PWM", - "description": "Use PWM" - }, - "nagTimeout": { - "label": "Nag Timeout", - "description": "Nag Timeout" - }, - "useI2sAsBuzzer": { - "label": "Use I²S Pin as Buzzer", - "description": "Designate I²S Pin as Buzzer Output" - } - }, - "mqtt": { - "title": "Настройки на MQTT", - "description": "Настройки за MQTT модула", - "enabled": { - "label": "Активиран", - "description": "Активиране или дезактивиране на MQTT" - }, - "address": { - "label": "Адрес на MQTT сървъра", - "description": "Адрес на MQTT сървъра, който да се използва за сървъри по подразбиране/персонализирани сървъри" - }, - "username": { - "label": "Потребителско име за MQTT", - "description": "Потребителско име за MQTT, което да се използва за сървъри по подразбиране/персонализирани сървъри" - }, - "password": { - "label": "Парола за MQTT", - "description": "Парола за MQTT, която да се използва за сървъри по подразбиране/персонализирани сървъри" - }, - "encryptionEnabled": { - "label": "Криптирането е активирано", - "description": "Enable or disable MQTT encryption. Note: All messages are sent to the MQTT broker unencrypted if this option is not enabled, even when your uplink channels have encryption keys set. This includes position data." - }, - "jsonEnabled": { - "label": "JSON е активиран", - "description": "Whether to send/consume JSON packets on MQTT" - }, - "tlsEnabled": { - "label": "TLS е активиран", - "description": "Активиране или дезактивиране на TLS" - }, - "root": { - "label": "Root topic", - "description": "MQTT root topic to use for default/custom servers" - }, - "proxyToClientEnabled": { - "label": "MQTT Client Proxy Enabled", - "description": "Utilizes the network connection to proxy MQTT messages to the client." - }, - "mapReportingEnabled": { - "label": "Map Reporting Enabled", - "description": "Your node will periodically send an unencrypted map report packet to the configured MQTT server, this includes id, short and long name, approximate location, hardware model, role, firmware version, LoRa region, modem preset and primary channel name." - }, - "mapReportSettings": { - "publishIntervalSecs": { - "label": "Map Report Publish Interval (s)", - "description": "Interval in seconds to publish map reports" - }, - "positionPrecision": { - "label": "Приблизително местоположение", - "description": "Position shared will be accurate within this distance", - "options": { - "metric_km23": "В рамките на 23 км", - "metric_km12": "В рамките на 12 км", - "metric_km5_8": "В рамките на 5.8 км", - "metric_km2_9": "В рамките на 2.9 км", - "metric_km1_5": "В рамките на 1.5 км", - "metric_m700": "В рамките на 700 м", - "metric_m350": "В рамките на 350 м", - "metric_m200": "В рамките на 200 м", - "metric_m90": "В рамките на 90 м", - "metric_m50": "В рамките на 50 м", - "imperial_mi15": "В рамките на 15 мили", - "imperial_mi7_3": "В рамките на 7.3 мили", - "imperial_mi3_6": "В рамките на 3.6 мили", - "imperial_mi1_8": "В рамките на 1.8 мили", - "imperial_mi0_9": "В рамките на 0.9 мили", - "imperial_mi0_5": "В рамките на 0.5 мили", - "imperial_mi0_2": "В рамките на 0.2 мили", - "imperial_ft600": "В рамките на 600 фута", - "imperial_ft300": "В рамките на 300 фута", - "imperial_ft150": "В рамките на 150 фута" - } - } - } - }, - "neighborInfo": { - "title": "Neighbor Info Settings", - "description": "Settings for the Neighbor Info module", - "enabled": { - "label": "Активиран", - "description": "Enable or disable Neighbor Info Module" - }, - "updateInterval": { - "label": "Интервал на актуализиране", - "description": "Interval in seconds of how often we should try to send our Neighbor Info to the mesh" - } - }, - "paxcounter": { - "title": "Paxcounter Settings", - "description": "Настройки за модула Paxcounter", - "enabled": { - "label": "Модулът е активиран", - "description": "Активиране на Paxcounter" - }, - "paxcounterUpdateInterval": { - "label": "Интервал на актуализиране (секунди)", - "description": "How long to wait between sending paxcounter packets" - }, - "wifiThreshold": { - "label": "WiFi RSSI Threshold", - "description": "At what WiFi RSSI level should the counter increase. Defaults to -80." - }, - "bleThreshold": { - "label": "BLE RSSI Threshold", - "description": "At what BLE RSSI level should the counter increase. Defaults to -80." - } - }, - "rangeTest": { - "title": "Настройки за тест на обхвата", - "description": "Настройки на модула за тестване на обхвата", - "enabled": { - "label": "Модулът е активиран", - "description": "Enable Range Test" - }, - "sender": { - "label": "Интервал на съобщенията", - "description": "Колко време да се чака между изпращането на тестови пакети" - }, - "save": { - "label": "Запазване на CSV в хранилището", - "description": "Само ESP32" - } - }, - "serial": { - "title": "Серийни настройки", - "description": "Настройки на серийния модул", - "enabled": { - "label": "Модулът е активиран", - "description": "Активиране на сериен изход" - }, - "echo": { - "label": "Echo", - "description": "Any packets you send will be echoed back to your device" - }, - "rxd": { - "label": "Receive Pin", - "description": "Set the GPIO pin to the RXD pin you have set up." - }, - "txd": { - "label": "Transmit Pin", - "description": "Set the GPIO pin to the TXD pin you have set up." - }, - "baud": { - "label": "Baud Rate", - "description": "The serial baud rate" - }, - "timeout": { - "label": "Timeout", - "description": "Seconds to wait before we consider your packet as 'done'" - }, - "mode": { - "label": "Режим", - "description": "Избор на режим" - }, - "overrideConsoleSerialPort": { - "label": "Override Console Serial Port", - "description": "If you have a serial port connected to the console, this will override it." - } - }, - "storeForward": { - "title": "Store & Forward Settings", - "description": "Settings for the Store & Forward module", - "enabled": { - "label": "Модулът е активиран", - "description": "Enable Store & Forward" - }, - "heartbeat": { - "label": "Heartbeat Enabled", - "description": "Enable Store & Forward heartbeat" - }, - "records": { - "label": "Брой записи", - "description": "Number of records to store" - }, - "historyReturnMax": { - "label": "History return max", - "description": "Max number of records to return" - }, - "historyReturnWindow": { - "label": "History return window", - "description": "Max number of records to return" - } - }, - "telemetry": { - "title": "Настройки на телеметрията", - "description": "Настройки за модула за телеметрия", - "deviceUpdateInterval": { - "label": "Метрики на устройството", - "description": "Интервал на актуализиране на показателите на устройството (секунди)" - }, - "environmentUpdateInterval": { - "label": "Интервал на актуализиране на показателите на околната среда (секунди)", - "description": "" - }, - "environmentMeasurementEnabled": { - "label": "Модулът е активиран", - "description": "Enable the Environment Telemetry" - }, - "environmentScreenEnabled": { - "label": "Показва се на екрана", - "description": "Show the Telemetry Module on the OLED" - }, - "environmentDisplayFahrenheit": { - "label": "Показване на Фаренхайт", - "description": "Показване на температурата във Фаренхайт" - }, - "airQualityEnabled": { - "label": "Качество на въздуха е активирано", - "description": "Активиране на телеметрията за качеството на въздуха" - }, - "airQualityInterval": { - "label": "Air Quality Update Interval", - "description": "How often to send Air Quality data over the mesh" - }, - "powerMeasurementEnabled": { - "label": "Power Measurement Enabled", - "description": "Enable the Power Measurement Telemetry" - }, - "powerUpdateInterval": { - "label": "Power Update Interval", - "description": "How often to send Power data over the mesh" - }, - "powerScreenEnabled": { - "label": "Power Screen Enabled", - "description": "Enable the Power Telemetry Screen" - } - } + "page": { + "tabAmbientLighting": "Ambient Lighting", + "tabAudio": "Аудио", + "tabCannedMessage": "Canned", + "tabDetectionSensor": "Detection Sensor", + "tabExternalNotification": "Ext Notif", + "tabMqtt": "MQTT", + "tabNeighborInfo": "Neighbor Info", + "tabPaxcounter": "Paxcounter", + "tabRangeTest": "Тест на обхвата", + "tabSerial": "Серийна", + "tabStoreAndForward": "S&F", + "tabTelemetry": "Телеметрия" + }, + "ambientLighting": { + "title": "Ambient Lighting Settings", + "description": "Settings for the Ambient Lighting module", + "ledState": { + "label": "LED State", + "description": "Sets LED to on or off" + }, + "current": { + "label": "Текущ", + "description": "Sets the current for the LED output. Default is 10" + }, + "red": { + "label": "Червен", + "description": "Sets the red LED level. Values are 0-255" + }, + "green": { + "label": "Зелен", + "description": "Sets the green LED level. Values are 0-255" + }, + "blue": { + "label": "Син", + "description": "Sets the blue LED level. Values are 0-255" + } + }, + "audio": { + "title": "Настройки на аудиото", + "description": "Настройки за аудио модула", + "codec2Enabled": { + "label": "Codec 2 е активиран", + "description": "Enable Codec 2 audio encoding" + }, + "pttPin": { + "label": "Пин за РТТ", + "description": "GPIO пин, който да се използва за PTT" + }, + "bitrate": { + "label": "Bitrate", + "description": "Bitrate to use for audio encoding" + }, + "i2sWs": { + "label": "i2S WS", + "description": "GPIO pin to use for i2S WS" + }, + "i2sSd": { + "label": "i2S SD", + "description": "GPIO pin to use for i2S SD" + }, + "i2sDin": { + "label": "i2S DIN", + "description": "GPIO pin to use for i2S DIN" + }, + "i2sSck": { + "label": "i2S SCK", + "description": "GPIO pin to use for i2S SCK" + } + }, + "cannedMessage": { + "title": "Canned Message Settings", + "description": "Settings for the Canned Message module", + "moduleEnabled": { + "label": "Модулът е активиран", + "description": "Enable Canned Message" + }, + "rotary1Enabled": { + "label": "Ротационен енкодер #1 е активиран", + "description": "Активиране на ротационния енкодер" + }, + "inputbrokerPinA": { + "label": "Encoder Pin A", + "description": "GPIO Pin Value (1-39) For encoder port A" + }, + "inputbrokerPinB": { + "label": "Encoder Pin B", + "description": "GPIO Pin Value (1-39) For encoder port B" + }, + "inputbrokerPinPress": { + "label": "Encoder Pin Press", + "description": "GPIO Pin Value (1-39) For encoder Press" + }, + "inputbrokerEventCw": { + "label": "Clockwise event", + "description": "Select input event." + }, + "inputbrokerEventCcw": { + "label": "Counter Clockwise event", + "description": "Select input event." + }, + "inputbrokerEventPress": { + "label": "Press event", + "description": "Select input event" + }, + "updown1Enabled": { + "label": "Up Down enabled", + "description": "Enable the up / down encoder" + }, + "allowInputSource": { + "label": "Allow Input Source", + "description": "Изберете от: '_any', 'rotEnc1', 'upDownEnc1', 'cardkb'" + }, + "sendBell": { + "label": "Send Bell", + "description": "Sends a bell character with each message" + } + }, + "detectionSensor": { + "title": "Detection Sensor Settings", + "description": "Settings for the Detection Sensor module", + "enabled": { + "label": "Активиран", + "description": "Enable or disable Detection Sensor Module" + }, + "minimumBroadcastSecs": { + "label": "Minimum Broadcast Seconds", + "description": "The interval in seconds of how often we can send a message to the mesh when a state change is detected" + }, + "stateBroadcastSecs": { + "label": "State Broadcast Seconds", + "description": "The interval in seconds of how often we should send a message to the mesh with the current state regardless of changes" + }, + "sendBell": { + "label": "Send Bell", + "description": "Send ASCII bell with alert message" + }, + "name": { + "label": "Приятелско име", + "description": "Използва се за форматиране на съобщението, изпратено до mesh, максимум 20 знака" + }, + "monitorPin": { + "label": "Monitor Pin", + "description": "The GPIO pin to monitor for state changes" + }, + "detectionTriggerType": { + "label": "Detection Triggered Type", + "description": "The type of trigger event to be used" + }, + "usePullup": { + "label": "Use Pullup", + "description": "Whether or not use INPUT_PULLUP mode for GPIO pin" + } + }, + "externalNotification": { + "title": "External Notification Settings", + "description": "Configure the external notification module", + "enabled": { + "label": "Модулът е активиран", + "description": "Enable External Notification" + }, + "outputMs": { + "label": "Output MS", + "description": "Output MS" + }, + "output": { + "label": "Output", + "description": "Output" + }, + "outputVibra": { + "label": "Output Vibrate", + "description": "Output Vibrate" + }, + "outputBuzzer": { + "label": "Output Buzzer", + "description": "Output Buzzer" + }, + "active": { + "label": "Активно", + "description": "Активно" + }, + "alertMessage": { + "label": "Предупредително съобщение", + "description": "Предупредително съобщение" + }, + "alertMessageVibra": { + "label": "Alert Message Vibrate", + "description": "Alert Message Vibrate" + }, + "alertMessageBuzzer": { + "label": "Alert Message Buzzer", + "description": "Alert Message Buzzer" + }, + "alertBell": { + "label": "Alert Bell", + "description": "Should an alert be triggered when receiving an incoming bell?" + }, + "alertBellVibra": { + "label": "Alert Bell Vibrate", + "description": "Alert Bell Vibrate" + }, + "alertBellBuzzer": { + "label": "Alert Bell Buzzer", + "description": "Alert Bell Buzzer" + }, + "usePwm": { + "label": "Use PWM", + "description": "Use PWM" + }, + "nagTimeout": { + "label": "Nag Timeout", + "description": "Nag Timeout" + }, + "useI2sAsBuzzer": { + "label": "Use I²S Pin as Buzzer", + "description": "Designate I²S Pin as Buzzer Output" + } + }, + "mqtt": { + "title": "Настройки на MQTT", + "description": "Настройки за MQTT модула", + "enabled": { + "label": "Активиран", + "description": "Активиране или дезактивиране на MQTT" + }, + "address": { + "label": "Адрес на MQTT сървъра", + "description": "Адрес на MQTT сървъра, който да се използва за сървъри по подразбиране/персонализирани сървъри" + }, + "username": { + "label": "Потребителско име за MQTT", + "description": "Потребителско име за MQTT, което да се използва за сървъри по подразбиране/персонализирани сървъри" + }, + "password": { + "label": "Парола за MQTT", + "description": "Парола за MQTT, която да се използва за сървъри по подразбиране/персонализирани сървъри" + }, + "encryptionEnabled": { + "label": "Криптирането е активирано", + "description": "Enable or disable MQTT encryption. Note: All messages are sent to the MQTT broker unencrypted if this option is not enabled, even when your uplink channels have encryption keys set. This includes position data." + }, + "jsonEnabled": { + "label": "JSON е активиран", + "description": "Whether to send/consume JSON packets on MQTT" + }, + "tlsEnabled": { + "label": "TLS е активиран", + "description": "Активиране или дезактивиране на TLS" + }, + "root": { + "label": "Root topic", + "description": "MQTT root topic to use for default/custom servers" + }, + "proxyToClientEnabled": { + "label": "MQTT Client Proxy Enabled", + "description": "Utilizes the network connection to proxy MQTT messages to the client." + }, + "mapReportingEnabled": { + "label": "Map Reporting Enabled", + "description": "Your node will periodically send an unencrypted map report packet to the configured MQTT server, this includes id, short and long name, approximate location, hardware model, role, firmware version, LoRa region, modem preset and primary channel name." + }, + "mapReportSettings": { + "publishIntervalSecs": { + "label": "Map Report Publish Interval (s)", + "description": "Interval in seconds to publish map reports" + }, + "positionPrecision": { + "label": "Приблизително местоположение", + "description": "Position shared will be accurate within this distance", + "options": { + "metric_km23": "В рамките на 23 км", + "metric_km12": "В рамките на 12 км", + "metric_km5_8": "В рамките на 5.8 км", + "metric_km2_9": "В рамките на 2.9 км", + "metric_km1_5": "В рамките на 1.5 км", + "metric_m700": "В рамките на 700 м", + "metric_m350": "В рамките на 350 м", + "metric_m200": "В рамките на 200 м", + "metric_m90": "В рамките на 90 м", + "metric_m50": "В рамките на 50 м", + "imperial_mi15": "В рамките на 15 мили", + "imperial_mi7_3": "В рамките на 7.3 мили", + "imperial_mi3_6": "В рамките на 3.6 мили", + "imperial_mi1_8": "В рамките на 1.8 мили", + "imperial_mi0_9": "В рамките на 0.9 мили", + "imperial_mi0_5": "В рамките на 0.5 мили", + "imperial_mi0_2": "В рамките на 0.2 мили", + "imperial_ft600": "В рамките на 600 фута", + "imperial_ft300": "В рамките на 300 фута", + "imperial_ft150": "В рамките на 150 фута" + } + } + } + }, + "neighborInfo": { + "title": "Neighbor Info Settings", + "description": "Settings for the Neighbor Info module", + "enabled": { + "label": "Активиран", + "description": "Enable or disable Neighbor Info Module" + }, + "updateInterval": { + "label": "Интервал на актуализиране", + "description": "Interval in seconds of how often we should try to send our Neighbor Info to the mesh" + } + }, + "paxcounter": { + "title": "Paxcounter Settings", + "description": "Настройки за модула Paxcounter", + "enabled": { + "label": "Модулът е активиран", + "description": "Активиране на Paxcounter" + }, + "paxcounterUpdateInterval": { + "label": "Интервал на актуализиране (секунди)", + "description": "How long to wait between sending paxcounter packets" + }, + "wifiThreshold": { + "label": "WiFi RSSI Threshold", + "description": "At what WiFi RSSI level should the counter increase. Defaults to -80." + }, + "bleThreshold": { + "label": "BLE RSSI Threshold", + "description": "At what BLE RSSI level should the counter increase. Defaults to -80." + } + }, + "rangeTest": { + "title": "Настройки за тест на обхвата", + "description": "Настройки на модула за тестване на обхвата", + "enabled": { + "label": "Модулът е активиран", + "description": "Enable Range Test" + }, + "sender": { + "label": "Интервал на съобщенията", + "description": "Колко време да се чака между изпращането на тестови пакети" + }, + "save": { + "label": "Запазване на CSV в хранилището", + "description": "Само ESP32" + } + }, + "serial": { + "title": "Серийни настройки", + "description": "Настройки на серийния модул", + "enabled": { + "label": "Модулът е активиран", + "description": "Активиране на сериен изход" + }, + "echo": { + "label": "Echo", + "description": "Any packets you send will be echoed back to your device" + }, + "rxd": { + "label": "Receive Pin", + "description": "Set the GPIO pin to the RXD pin you have set up." + }, + "txd": { + "label": "Transmit Pin", + "description": "Set the GPIO pin to the TXD pin you have set up." + }, + "baud": { + "label": "Baud Rate", + "description": "The serial baud rate" + }, + "timeout": { + "label": "Timeout", + "description": "Seconds to wait before we consider your packet as 'done'" + }, + "mode": { + "label": "Режим", + "description": "Избор на режим" + }, + "overrideConsoleSerialPort": { + "label": "Override Console Serial Port", + "description": "If you have a serial port connected to the console, this will override it." + } + }, + "storeForward": { + "title": "Store & Forward Settings", + "description": "Settings for the Store & Forward module", + "enabled": { + "label": "Модулът е активиран", + "description": "Enable Store & Forward" + }, + "heartbeat": { + "label": "Heartbeat Enabled", + "description": "Enable Store & Forward heartbeat" + }, + "records": { + "label": "Брой записи", + "description": "Number of records to store" + }, + "historyReturnMax": { + "label": "History return max", + "description": "Max number of records to return" + }, + "historyReturnWindow": { + "label": "History return window", + "description": "Return records from this time window (minutes)" + } + }, + "telemetry": { + "title": "Настройки на телеметрията", + "description": "Настройки за модула за телеметрия", + "deviceUpdateInterval": { + "label": "Метрики на устройството", + "description": "Интервал на актуализиране на показателите на устройството (секунди)" + }, + "environmentUpdateInterval": { + "label": "Интервал на актуализиране на показателите на околната среда (секунди)", + "description": "" + }, + "environmentMeasurementEnabled": { + "label": "Модулът е активиран", + "description": "Enable the Environment Telemetry" + }, + "environmentScreenEnabled": { + "label": "Показва се на екрана", + "description": "Show the Telemetry Module on the OLED" + }, + "environmentDisplayFahrenheit": { + "label": "Показване на Фаренхайт", + "description": "Показване на температурата във Фаренхайт" + }, + "airQualityEnabled": { + "label": "Качество на въздуха е активирано", + "description": "Активиране на телеметрията за качеството на въздуха" + }, + "airQualityInterval": { + "label": "Air Quality Update Interval", + "description": "How often to send Air Quality data over the mesh" + }, + "powerMeasurementEnabled": { + "label": "Power Measurement Enabled", + "description": "Enable the Power Measurement Telemetry" + }, + "powerUpdateInterval": { + "label": "Power Update Interval", + "description": "How often to send Power data over the mesh" + }, + "powerScreenEnabled": { + "label": "Power Screen Enabled", + "description": "Enable the Power Telemetry Screen" + } + } } diff --git a/packages/web/public/i18n/locales/bg-BG/nodes.json b/packages/web/public/i18n/locales/bg-BG/nodes.json index e3a88804d..2fd3ed41e 100644 --- a/packages/web/public/i18n/locales/bg-BG/nodes.json +++ b/packages/web/public/i18n/locales/bg-BG/nodes.json @@ -1,63 +1,59 @@ { - "nodeDetail": { - "publicKeyEnabled": { - "label": "Публичният ключ е активиран" - }, - "noPublicKey": { - "label": "Няма публичен ключ" - }, - "directMessage": { - "label": "Директно съобщение {{shortName}}" - }, - "favorite": { - "label": "Любим", - "tooltip": "Добавяне или премахване на този възел от любимите ви" - }, - "notFavorite": { - "label": "Не е любим" - }, - "error": { - "label": "Грешка", - "text": "Възникна грешка при извличането на подробности за възела. Моля, опитайте отново по-късно." - }, - "status": { - "heard": "Heard", - "mqtt": "MQTT" - }, - "elevation": { - "label": "Височина" - }, - "channelUtil": { - "label": "Използване на канала" - }, - "airtimeUtil": { - "label": "Използване на ефирно време" - } - }, - "nodesTable": { - "headings": { - "longName": "Дълго име", - "connection": "Connection", - "lastHeard": "Последно чут", - "encryption": "Криптиране", - "model": "Модел", - "macAddress": "MAC адрес" - }, - "connectionStatus": { - "direct": "Директно", - "away": "away", - "unknown": "-", - "viaMqtt": ", чрез MQTT" - }, - "lastHeardStatus": { - "never": "Никога" - } - }, - "actions": { - "added": "Добавен", - "removed": "Премахнат", - "ignoreNode": "Игнориране на възела", - "unignoreNode": "Премахване на игнорирането на възела", - "requestPosition": "Request Position" - } + "nodeDetail": { + "publicKeyEnabled": { + "label": "Публичният ключ е активиран" + }, + "noPublicKey": { + "label": "Няма публичен ключ" + }, + "directMessage": { + "label": "Директно съобщение {{shortName}}" + }, + "favorite": { + "label": "Любим", + "tooltip": "Добавяне или премахване на този възел от любимите ви" + }, + "notFavorite": { + "label": "Не е любим" + }, + "error": { + "label": "Грешка", + "text": "Възникна грешка при извличането на подробности за възела. Моля, опитайте отново по-късно." + }, + "status": { + "heard": "Heard", + "mqtt": "MQTT" + }, + "elevation": { + "label": "Височина" + }, + "channelUtil": { + "label": "Използване на канала" + }, + "airtimeUtil": { + "label": "Използване на ефирно време" + } + }, + "nodesTable": { + "headings": { + "longName": "Дълго име", + "connection": "Connection", + "lastHeard": "Последно чут", + "encryption": "Криптиране", + "model": "Модел", + "macAddress": "MAC адрес" + }, + "connectionStatus": { + "direct": "Директно", + "away": "away", + "viaMqtt": ", чрез MQTT" + } + }, + "actions": { + "added": "Добавен", + "removed": "Премахнат", + "ignoreNode": "Игнориране на възела", + "unignoreNode": "Премахване на игнорирането на възела", + "requestPosition": "Request Position" + } } diff --git a/packages/web/public/i18n/locales/bg-BG/ui.json b/packages/web/public/i18n/locales/bg-BG/ui.json index 1c24da28a..a58b34aed 100644 --- a/packages/web/public/i18n/locales/bg-BG/ui.json +++ b/packages/web/public/i18n/locales/bg-BG/ui.json @@ -1,228 +1,230 @@ { - "navigation": { - "title": "Навигация", - "messages": "Съобщения", - "map": "Карта", - "config": "Конфигурация", - "radioConfig": "Конфигурация на радиото", - "moduleConfig": "Конфигурация на модула", - "channels": "Канали", - "nodes": "Възли" - }, - "app": { - "title": "Meshtastic", - "logo": "Лого на Meshtastic" - }, - "sidebar": { - "collapseToggle": { - "button": { - "open": "Отваряне на страничната лента", - "close": "Затваряне на страничната лента" - } - }, - "deviceInfo": { - "volts": "{{voltage}} волта", - "firmware": { - "title": "Фърмуер", - "version": "v{{version}}", - "buildDate": "Дата на компилация: {{date}}" - }, - "deviceName": { - "title": "Име на устройството", - "changeName": "Промяна на името на устройството", - "placeholder": "Въвеждане на име на устройството" - }, - "editDeviceName": "Редактиране на името на устройство" - } - }, - "batteryStatus": { - "charging": "{{level}}% зареждане", - "pluggedIn": "Включен в ел. мрежа", - "title": "Батерия" - }, - "search": { - "nodes": "Търсене на възли...", - "channels": "Търсене на канали...", - "commandPalette": "Търсене на команди..." - }, - "toast": { - "positionRequestSent": { - "title": "Position request sent." - }, - "requestingPosition": { - "title": "Requesting position, please wait..." - }, - "sendingTraceroute": { - "title": "Sending Traceroute, please wait..." - }, - "tracerouteSent": { - "title": "Traceroute sent." - }, - "savedChannel": { - "title": "Запазен канал: {{channelName}}" - }, - "messages": { - "pkiEncryption": { - "title": "Чатът използва PKI криптиране." - }, - "pskEncryption": { - "title": "Чатът използва PSK криптиране." - } - }, - "configSaveError": { - "title": "Грешка при запазване на конфигурацията", - "description": "Възникна грешка при запазване на конфигурацията." - }, - "validationError": { - "title": "Съществуват грешки в конфигурацията", - "description": "Моля, коригирайте грешките в конфигурацията, преди да я запазите." - }, - "saveSuccess": { - "title": "Запазване на конфигурацията", - "description": "Промяната в конфигурацията {{case}} е запазена." - }, - "favoriteNode": { - "title": "{{action}} {{nodeName}} {{direction}} любими.", - "action": { - "added": "Добавен", - "removed": "Премахнат", - "to": "в", - "from": "от" - } - }, - "ignoreNode": { - "title": "{{action}} {{nodeName}} {{direction}} списък с игнорирани", - "action": { - "added": "Добавен", - "removed": "Премахнат", - "to": "в", - "from": "от" - } - } - }, - "notifications": { - "copied": { - "label": "Копирано!" - }, - "copyToClipboard": { - "label": "Копиране в клипборда" - }, - "hidePassword": { - "label": "Скриване на паролата" - }, - "showPassword": { - "label": "Показване на паролата" - }, - "deliveryStatus": { - "delivered": "Доставено", - "failed": "Неуспешна доставка", - "waiting": "Изчакване", - "unknown": "Неизвестно" - } - }, - "general": { - "label": "General" - }, - "hardware": { - "label": "Хардуер" - }, - "metrics": { - "label": "Метрики" - }, - "role": { - "label": "Роля" - }, - "filter": { - "label": "Филтър" - }, - "advanced": { - "label": "Разширени" - }, - "clearInput": { - "label": "Clear input" - }, - "resetFilters": { - "label": "Нулиране на филтрите" - }, - "nodeName": { - "label": "Име/номер на възел", - "placeholder": "Meshtastic 1234" - }, - "airtimeUtilization": { - "label": "Използване на ефира (%)" - }, - "batteryLevel": { - "label": "Ниво на батерията (%)", - "labelText": "Ниво на батерията (%): {{value}}" - }, - "batteryVoltage": { - "label": "Напрежение на батерията (V)", - "title": "Напрежение" - }, - "channelUtilization": { - "label": "Използване на канала (%)" - }, - "hops": { - "direct": "Директно", - "label": "Брой хопове", - "text": "Брой хопове: {{value}}" - }, - "lastHeard": { - "label": "Последно чут", - "labelText": "Последно чут: {{value}}", - "nowLabel": "Сега" - }, - "snr": { - "label": "SNR (db)" - }, - "favorites": { - "label": "Любими" - }, - "hide": { - "label": "Скриване" - }, - "showOnly": { - "label": "Показване само" - }, - "viaMqtt": { - "label": "Свързан чрез MQTT" - }, - "hopsUnknown": { - "label": "Неизвестен брой хопове" - }, - "showUnheard": { - "label": "Никога не е чуван" - }, - "language": { - "label": "Език", - "changeLanguage": "Промяна на езика" - }, - "theme": { - "dark": "Тъмна", - "light": "Светла", - "system": "Автоматично", - "changeTheme": "Промяна на цветовата схема" - }, - "errorPage": { - "title": "Това е малко смущаващо...", - "description1": "Наистина съжаляваме, но възникна грешка в web клиента, която доведе до срив.
Това не би трябвало да се случва и работим усилено, за да го поправим.", - "description2": "Най-добрият начин да предотвратите това да се случи отново с вас или с някой друг е да ни съобщите за проблема.", - "reportInstructions": "Моля, включете следната информация в доклада си:", - "reportSteps": { - "step1": "Какво правехте, когато възникна грешката", - "step2": "Какво очаквахте да се случи", - "step3": "Какво всъщност се случи", - "step4": "Всяка друга подходяща информация" - }, - "reportLink": "Можете да съобщите за проблема в нашия <0>GitHub", - "dashboardLink": "Връщане към <0>таблото", - "detailsSummary": "Подробности за грешката", - "errorMessageLabel": "Съобщение за грешка:", - "stackTraceLabel": "Stack trace:", - "fallbackError": "{{error}}" - }, - "footer": { - "text": "Задвижвано от <0>▲ Vercel | Meshtastic® е регистрирана търговска марка на Meshtastic LLC. | <1>Правна информация", - "commitSha": "Commit SHA: {{sha}}" - } + "navigation": { + "title": "Навигация", + "messages": "Съобщения", + "map": "Карта", + "settings": "Настройки", + "channels": "Канали", + "radioConfig": "Конфигурация на радиото", + "deviceConfig": "Конфигуриране на устройството", + "moduleConfig": "Конфигурация на модула", + "manageConnections": "Управление на връзките", + "nodes": "Възли" + }, + "app": { + "title": "Meshtastic", + "logo": "Лого на Meshtastic" + }, + "sidebar": { + "collapseToggle": { + "button": { + "open": "Отваряне на страничната лента", + "close": "Затваряне на страничната лента" + } + }, + "deviceInfo": { + "volts": "{{voltage}} волта", + "firmware": { + "title": "Фърмуер", + "version": "v{{version}}", + "buildDate": "Дата на компилация: {{date}}" + } + } + }, + "batteryStatus": { + "charging": "{{level}}% зареждане", + "pluggedIn": "Включен в ел. мрежа", + "title": "Батерия" + }, + "search": { + "nodes": "Търсене на възли...", + "channels": "Търсене на канали...", + "commandPalette": "Търсене на команди..." + }, + "toast": { + "positionRequestSent": { + "title": "Заявката за позиция е изпратена." + }, + "requestingPosition": { + "title": "Запитване за позиция, моля изчакайте..." + }, + "sendingTraceroute": { + "title": "Sending Traceroute, please wait..." + }, + "tracerouteSent": { + "title": "Traceroute sent." + }, + "savedChannel": { + "title": "Запазен канал: {{channelName}}" + }, + "messages": { + "pkiEncryption": { + "title": "Чатът използва PKI криптиране." + }, + "pskEncryption": { + "title": "Чатът използва PSK криптиране." + } + }, + "configSaveError": { + "title": "Грешка при запазване на конфигурацията", + "description": "Възникна грешка при запазване на конфигурацията." + }, + "validationError": { + "title": "Съществуват грешки в конфигурацията", + "description": "Моля, коригирайте грешките в конфигурацията, преди да я запазите." + }, + "saveSuccess": { + "title": "Запазване на конфигурацията", + "description": "Промяната в конфигурацията {{case}} е запазена." + }, + "saveAllSuccess": { + "title": "Запазено", + "description": "Всички промени в конфигурацията са запазени." + }, + "favoriteNode": { + "title": "{{action}} {{nodeName}} {{direction}} любими.", + "action": { + "added": "Добавен", + "removed": "Премахнат", + "to": "в", + "from": "от" + } + }, + "ignoreNode": { + "title": "{{action}} {{nodeName}} {{direction}} списък с игнорирани", + "action": { + "added": "Добавен", + "removed": "Премахнат", + "to": "в", + "from": "от" + } + } + }, + "notifications": { + "copied": { + "label": "Копирано!" + }, + "copyToClipboard": { + "label": "Копиране в клипборда" + }, + "hidePassword": { + "label": "Скриване на паролата" + }, + "showPassword": { + "label": "Показване на паролата" + }, + "deliveryStatus": { + "delivered": "Доставено", + "failed": "Неуспешна доставка", + "waiting": "Изчакване", + "unknown": "Неизвестно" + } + }, + "general": { + "label": "General" + }, + "hardware": { + "label": "Хардуер" + }, + "metrics": { + "label": "Метрики" + }, + "role": { + "label": "Роля" + }, + "filter": { + "label": "Филтър" + }, + "advanced": { + "label": "Разширени" + }, + "clearInput": { + "label": "Clear input" + }, + "resetFilters": { + "label": "Нулиране на филтрите" + }, + "nodeName": { + "label": "Име/номер на възел", + "placeholder": "Meshtastic 1234" + }, + "airtimeUtilization": { + "label": "Използване на ефира (%)", + "short": "Airtime Util. (%)" + }, + "batteryLevel": { + "label": "Ниво на батерията (%)", + "labelText": "Ниво на батерията (%): {{value}}" + }, + "batteryVoltage": { + "label": "Напрежение на батерията (V)", + "title": "Напрежение" + }, + "channelUtilization": { + "label": "Използване на канала (%)", + "short": "Channel Util. (%)" + }, + "hops": { + "direct": "Директно", + "label": "Брой хопове", + "text": "Брой хопове: {{value}}" + }, + "lastHeard": { + "label": "Последно чут", + "labelText": "Последно чут: {{value}}", + "nowLabel": "Сега" + }, + "snr": { + "label": "SNR (db)" + }, + "favorites": { + "label": "Любими" + }, + "hide": { + "label": "Скриване" + }, + "showOnly": { + "label": "Показване само" + }, + "viaMqtt": { + "label": "Свързан чрез MQTT" + }, + "hopsUnknown": { + "label": "Неизвестен брой хопове" + }, + "showUnheard": { + "label": "Никога не е чуван" + }, + "language": { + "label": "Език", + "changeLanguage": "Промяна на езика" + }, + "theme": { + "dark": "Тъмна", + "light": "Светла", + "system": "Автоматично", + "changeTheme": "Промяна на цветовата схема" + }, + "errorPage": { + "title": "Това е малко смущаващо...", + "description1": "Наистина съжаляваме, но възникна грешка в web клиента, която доведе до срив.
Това не би трябвало да се случва и работим усилено, за да го поправим.", + "description2": "Най-добрият начин да предотвратите това да се случи отново с вас или с някой друг е да ни съобщите за проблема.", + "reportInstructions": "Моля, включете следната информация в доклада си:", + "reportSteps": { + "step1": "Какво правехте, когато възникна грешката", + "step2": "Какво очаквахте да се случи", + "step3": "Какво всъщност се случи", + "step4": "Всяка друга подходяща информация" + }, + "reportLink": "Можете да съобщите за проблема в нашия <0>GitHub", + "connectionsLink": "Return to the <0>connections", + "detailsSummary": "Подробности за грешката", + "errorMessageLabel": "Съобщение за грешка:", + "stackTraceLabel": "Stack trace:", + "fallbackError": "{{error}}" + }, + "footer": { + "text": "Задвижвано от <0>▲ Vercel | Meshtastic® е регистрирана търговска марка на Meshtastic LLC. | <1>Правна информация", + "commitSha": "Commit SHA: {{sha}}" + } } diff --git a/packages/web/public/i18n/locales/cs-CZ/channels.json b/packages/web/public/i18n/locales/cs-CZ/channels.json index 21fc1eb50..adc897cf0 100644 --- a/packages/web/public/i18n/locales/cs-CZ/channels.json +++ b/packages/web/public/i18n/locales/cs-CZ/channels.json @@ -1,69 +1,71 @@ { - "page": { - "sectionLabel": "Kanály", - "channelName": "Channel: {{channelName}}", - "broadcastLabel": "Primární", - "channelIndex": "Ch {{index}}" - }, - "validation": { - "pskInvalid": "Please enter a valid {{bits}} bit PSK." - }, - "settings": { - "label": "Nastavení kanálu", - "description": "Crypto, MQTT & misc settings" - }, - "role": { - "label": "Role", - "description": "Device telemetry is sent over PRIMARY. Only one PRIMARY allowed", - "options": { - "primary": "PRIMARY", - "disabled": "DISABLED", - "secondary": "SECONDARY" - } - }, - "psk": { - "label": "Pre-Shared Key", - "description": "Supported PSK lengths: 256-bit, 128-bit, 8-bit, Empty (0-bit)", - "generate": "Generate" - }, - "name": { - "label": "Jméno", - "description": "A unique name for the channel <12 bytes, leave blank for default" - }, - "uplinkEnabled": { - "label": "Uplink Enabled", - "description": "Send messages from the local mesh to MQTT" - }, - "downlinkEnabled": { - "label": "Downlink Enabled", - "description": "Send messages from MQTT to the local mesh" - }, - "positionPrecision": { - "label": "Location", - "description": "The precision of the location to share with the channel. Can be disabled.", - "options": { - "none": "Do not share location", - "precise": "Precise Location", - "metric_km23": "Within 23 kilometers", - "metric_km12": "Within 12 kilometers", - "metric_km5_8": "Within 5.8 kilometers", - "metric_km2_9": "Within 2.9 kilometers", - "metric_km1_5": "Within 1.5 kilometers", - "metric_m700": "Within 700 meters", - "metric_m350": "Within 350 meters", - "metric_m200": "Within 200 meters", - "metric_m90": "Within 90 meters", - "metric_m50": "Within 50 meters", - "imperial_mi15": "Within 15 miles", - "imperial_mi7_3": "Within 7.3 miles", - "imperial_mi3_6": "Within 3.6 miles", - "imperial_mi1_8": "Within 1.8 miles", - "imperial_mi0_9": "Within 0.9 miles", - "imperial_mi0_5": "Within 0.5 miles", - "imperial_mi0_2": "Within 0.2 miles", - "imperial_ft600": "Within 600 feet", - "imperial_ft300": "Within 300 feet", - "imperial_ft150": "Within 150 feet" - } - } + "page": { + "sectionLabel": "Kanály", + "channelName": "Kanál: {{channelName}}", + "broadcastLabel": "Primární", + "channelIndex": "K {{index}}", + "import": "Import", + "export": "Export" + }, + "validation": { + "pskInvalid": "Prosím zadejte platný {{bits}} bit PSK." + }, + "settings": { + "label": "Nastavení kanálu", + "description": "Krypto, MQTT a další nastavení" + }, + "role": { + "label": "Role", + "description": "Telemetrie zařízení je posílána přes PRIMÁRNÍ. Je povolena pouze jedna PRIMÁRNÍ", + "options": { + "primary": "PRIMÁRNÍ", + "disabled": "VYPNUTO", + "secondary": "SEKUNDÁRNÍ" + } + }, + "psk": { + "label": "Sdílený klíč", + "description": "Podporované délky PSK: 256-bit, 128-bit, 8-bit, prázdné (0-bit)", + "generate": "Generovat" + }, + "name": { + "label": "Jméno", + "description": "Jedinečný název kanálu <12 bytů, ponechte prázdné pro výchozí" + }, + "uplinkEnabled": { + "label": "Odesílání povoleno", + "description": "Odesílat zprávy z místní sítě do MQTT" + }, + "downlinkEnabled": { + "label": "Stahování povoleno", + "description": "Odesílat zprávy z MQTT do místní sítě" + }, + "positionPrecision": { + "label": "Poloha", + "description": "Přesnost umístění, které chcete sdílet s kanálem. Může být vypnuto.", + "options": { + "none": "Nesdílet polohu", + "precise": "Přesná poloha", + "metric_km23": "Okruh 23 kilometrů", + "metric_km12": "Okruh 12 kilometrů", + "metric_km5_8": "Okruh 5,8 kilometrů", + "metric_km2_9": "Okruh 2,9 kilometrů", + "metric_km1_5": "Okruh 1,5 kilometru", + "metric_m700": "Okruh 700 metrů", + "metric_m350": "Okruh 350 metrů", + "metric_m200": "Okruh 200 metrů", + "metric_m90": "Okruh 90 metrů", + "metric_m50": "Okruh 50 metrů", + "imperial_mi15": "Okruh 15 mil", + "imperial_mi7_3": "Okruh 7,3 mil", + "imperial_mi3_6": "Okruh 3,6 mil", + "imperial_mi1_8": "Okruh 1,8 mil", + "imperial_mi0_9": "Okruh 0,9 míle", + "imperial_mi0_5": "Okruh 0,5 míle", + "imperial_mi0_2": "Okruh 0,2 míle", + "imperial_ft600": "Okruh 600 stop", + "imperial_ft300": "Okruh 300 stop", + "imperial_ft150": "Okruh 150 stop" + } + } } diff --git a/packages/web/public/i18n/locales/cs-CZ/commandPalette.json b/packages/web/public/i18n/locales/cs-CZ/commandPalette.json index 8b8c0101d..91fcf66bd 100644 --- a/packages/web/public/i18n/locales/cs-CZ/commandPalette.json +++ b/packages/web/public/i18n/locales/cs-CZ/commandPalette.json @@ -15,7 +15,6 @@ "messages": "Zprávy", "map": "Mapa", "config": "Config", - "channels": "Kanály", "nodes": "Uzly" } }, @@ -45,7 +44,8 @@ "label": "Debug", "command": { "reconfigure": "Reconfigure", - "clearAllStoredMessages": "Clear All Stored Message" + "clearAllStoredMessages": "Clear All Stored Message", + "clearAllStores": "Clear All Local Storage" } } } diff --git a/packages/web/public/i18n/locales/cs-CZ/common.json b/packages/web/public/i18n/locales/cs-CZ/common.json index 6e1f2d1e3..8f93f171c 100644 --- a/packages/web/public/i18n/locales/cs-CZ/common.json +++ b/packages/web/public/i18n/locales/cs-CZ/common.json @@ -1,142 +1,165 @@ { - "button": { - "apply": "Použít", - "backupKey": "Backup Key", - "cancel": "Zrušit", - "clearMessages": "Clear Messages", - "close": "Zavřít", - "confirm": "Confirm", - "delete": "Smazat", - "dismiss": "Dismiss", - "download": "Download", - "export": "Export", - "generate": "Generate", - "regenerate": "Regenerate", - "import": "Import", - "message": "Zpráva", - "now": "Now", - "ok": "OK", - "print": "Print", - "remove": "Odstranit", - "requestNewKeys": "Request New Keys", - "requestPosition": "Request Position", - "reset": "Reset", - "save": "Uložit", - "scanQr": "Naskenovat QR kód", - "traceRoute": "Trace Route", - "submit": "Submit" - }, - "app": { - "title": "Meshtastic", - "fullTitle": "Meshtastic Web Client" - }, - "loading": "Loading...", - "unit": { - "cps": "CPS", - "dbm": "dBm", - "hertz": "Hz", - "hop": { - "one": "Hop", - "plural": "Hops" - }, - "hopsAway": { - "one": "{{count}} hop away", - "plural": "{{count}} hops away", - "unknown": "Unknown hops away" - }, - "megahertz": "MHz", - "raw": "raw", - "meter": { - "one": "Meter", - "plural": "Meters", - "suffix": "m" - }, - "minute": { - "one": "Minute", - "plural": "Minutes" - }, - "hour": { - "one": "Hour", - "plural": "Hours" - }, - "millisecond": { - "one": "Millisecond", - "plural": "Milliseconds", - "suffix": "ms" - }, - "second": { - "one": "Second", - "plural": "Seconds" - }, - "day": { - "one": "Day", - "plural": "Days" - }, - "month": { - "one": "Month", - "plural": "Months" - }, - "year": { - "one": "Year", - "plural": "Years" - }, - "snr": "SNR", - "volt": { - "one": "Volt", - "plural": "Volts", - "suffix": "V" - }, - "record": { - "one": "Records", - "plural": "Records" - } - }, - "security": { - "0bit": "Empty", - "8bit": "8 bit", - "128bit": "128 bit", - "256bit": "256 bit" - }, - "unknown": { - "longName": "Unknown", - "shortName": "UNK", - "notAvailable": "N/A", - "num": "??" - }, - "nodeUnknownPrefix": "!", - "unset": "UNSET", - "fallbackName": "Meshtastic {{last4}}", - "node": "Node", - "formValidation": { - "unsavedChanges": "Unsaved changes", - "tooBig": { - "string": "Too long, expected less than or equal to {{maximum}} characters.", - "number": "Too big, expected a number smaller than or equal to {{maximum}}.", - "bytes": "Too big, expected less than or equal to {{params.maximum}} bytes." - }, - "tooSmall": { - "string": "Too short, expected more than or equal to {{minimum}} characters.", - "number": "Too small, expected a number larger than or equal to {{minimum}}." - }, - "invalidFormat": { - "ipv4": "Invalid format, expected an IPv4 address.", - "key": "Invalid format, expected a Base64 encoded pre-shared key (PSK)." - }, - "invalidType": { - "number": "Invalid type, expected a number." - }, - "pskLength": { - "0bit": "Key is required to be empty.", - "8bit": "Key is required to be an 8 bit pre-shared key (PSK).", - "128bit": "Key is required to be a 128 bit pre-shared key (PSK).", - "256bit": "Key is required to be a 256 bit pre-shared key (PSK)." - }, - "required": { - "generic": "This field is required.", - "managed": "At least one admin key is requred if the node is managed.", - "key": "Key is required." - } - }, - "yes": "Ano", - "no": "Ne" + "button": { + "apply": "Použít", + "addConnection": "Add Connection", + "saveConnection": "Save connection", + "backupKey": "Backup Key", + "cancel": "Zrušit", + "connect": "Připojit", + "clearMessages": "Clear Messages", + "close": "Zavřít", + "confirm": "Confirm", + "delete": "Smazat", + "dismiss": "Dismiss", + "download": "Download", + "disconnect": "Odpojit", + "export": "Export", + "generate": "Generate", + "regenerate": "Regenerate", + "import": "Import", + "message": "Zpráva", + "now": "Now", + "ok": "OK", + "print": "Print", + "remove": "Odstranit", + "requestNewKeys": "Request New Keys", + "requestPosition": "Request Position", + "reset": "Reset", + "retry": "Retry", + "save": "Uložit", + "setDefault": "Set as default", + "unsetDefault": "Unset default", + "scanQr": "Naskenovat QR kód", + "traceRoute": "Trace Route", + "submit": "Submit" + }, + "app": { + "title": "Meshtastic", + "fullTitle": "Meshtastic Web Client" + }, + "loading": "Loading...", + "unit": { + "cps": "CPS", + "dbm": "dBm", + "hertz": "Hz", + "hop": { + "one": "Hop", + "plural": "Hops" + }, + "hopsAway": { + "one": "{{count}} hop away", + "plural": "{{count}} hops away", + "unknown": "Unknown hops away" + }, + "megahertz": "MHz", + "kilohertz": "kHz", + "raw": "raw", + "meter": { + "one": "Meter", + "plural": "Meters", + "suffix": "m" + }, + "kilometer": { + "one": "Kilometer", + "plural": "Kilometers", + "suffix": "km" + }, + "minute": { + "one": "Minute", + "plural": "Minutes" + }, + "hour": { + "one": "Hour", + "plural": "Hours" + }, + "millisecond": { + "one": "Millisecond", + "plural": "Milliseconds", + "suffix": "ms" + }, + "second": { + "one": "Second", + "plural": "Seconds" + }, + "day": { + "one": "Day", + "plural": "Days", + "today": "Today", + "yesterday": "Yesterday" + }, + "month": { + "one": "Month", + "plural": "Months" + }, + "year": { + "one": "Year", + "plural": "Years" + }, + "snr": "SNR", + "volt": { + "one": "Volt", + "plural": "Volts", + "suffix": "V" + }, + "record": { + "one": "Records", + "plural": "Records" + }, + "degree": { + "one": "Degree", + "plural": "Degrees", + "suffix": "°" + } + }, + "security": { + "0bit": "Empty", + "8bit": "8 bit", + "128bit": "128 bit", + "256bit": "256 bit" + }, + "unknown": { + "longName": "Unknown", + "shortName": "UNK", + "notAvailable": "N/A", + "num": "??" + }, + "nodeUnknownPrefix": "!", + "unset": "UNSET", + "fallbackName": "Meshtastic {{last4}}", + "node": "Node", + "formValidation": { + "unsavedChanges": "Unsaved changes", + "tooBig": { + "string": "Too long, expected less than or equal to {{maximum}} characters.", + "number": "Too big, expected a number smaller than or equal to {{maximum}}.", + "bytes": "Too big, expected less than or equal to {{params.maximum}} bytes." + }, + "tooSmall": { + "string": "Too short, expected more than or equal to {{minimum}} characters.", + "number": "Too small, expected a number larger than or equal to {{minimum}}." + }, + "invalidFormat": { + "ipv4": "Invalid format, expected an IPv4 address.", + "key": "Invalid format, expected a Base64 encoded pre-shared key (PSK)." + }, + "invalidType": { + "number": "Invalid type, expected a number." + }, + "pskLength": { + "0bit": "Key is required to be empty.", + "8bit": "Key is required to be an 8 bit pre-shared key (PSK).", + "128bit": "Key is required to be a 128 bit pre-shared key (PSK).", + "256bit": "Key is required to be a 256 bit pre-shared key (PSK)." + }, + "required": { + "generic": "This field is required.", + "managed": "At least one admin key is requred if the node is managed.", + "key": "Key is required." + }, + "invalidOverrideFreq": { + "number": "Invalid format, expected a value in the range 410-930 MHz or 0 (use default)." + } + }, + "yes": "Ano", + "no": "Ne" } diff --git a/packages/web/public/i18n/locales/cs-CZ/config.json b/packages/web/public/i18n/locales/cs-CZ/config.json new file mode 100644 index 000000000..ec83e0a6d --- /dev/null +++ b/packages/web/public/i18n/locales/cs-CZ/config.json @@ -0,0 +1,458 @@ +{ + "page": { + "title": "Nastavení", + "tabUser": "Uživatel", + "tabChannels": "Kanály", + "tabBluetooth": "Bluetooth", + "tabDevice": "Zařízení", + "tabDisplay": "Obrazovka", + "tabLora": "LoRa", + "tabNetwork": "Síť", + "tabPosition": "Pozice", + "tabPower": "Napájení", + "tabSecurity": "Zabezpečení" + }, + "sidebar": { + "label": "Configuration" + }, + "device": { + "title": "Device Settings", + "description": "Settings for the device", + "buttonPin": { + "description": "Button pin override", + "label": "Button Pin" + }, + "buzzerPin": { + "description": "Buzzer pin override", + "label": "Buzzer Pin" + }, + "disableTripleClick": { + "description": "Disable triple click", + "label": "Disable Triple Click" + }, + "doubleTapAsButtonPress": { + "description": "Treat double tap as button press", + "label": "Dvojité klepnutí jako stisk tlačítka" + }, + "ledHeartbeatDisabled": { + "description": "Disable default blinking LED", + "label": "LED Heartbeat Disabled" + }, + "nodeInfoBroadcastInterval": { + "description": "How often to broadcast node info", + "label": "Interval vysílání NodeInfo (v sekundách)" + }, + "posixTimezone": { + "description": "The POSIX timezone string for the device", + "label": "POSIX časové pásmo" + }, + "rebroadcastMode": { + "description": "How to handle rebroadcasting", + "label": "Režim opětovného vysílání" + }, + "role": { + "description": "What role the device performs on the mesh", + "label": "Role" + } + }, + "bluetooth": { + "title": "Nastavení Bluetooth", + "description": "Settings for the Bluetooth module", + "note": "Note: Some devices (ESP32) cannot use both Bluetooth and WiFi at the same time.", + "enabled": { + "description": "Enable or disable Bluetooth", + "label": "Povoleno" + }, + "pairingMode": { + "description": "Pin selection behaviour.", + "label": "Režim párování" + }, + "pin": { + "description": "Pin to use when pairing", + "label": "Pin" + } + }, + "display": { + "description": "Settings for the device display", + "title": "Display Settings", + "headingBold": { + "description": "Bolden the heading text", + "label": "Tučný nadpis" + }, + "carouselDelay": { + "description": "How fast to cycle through windows", + "label": "Carousel Delay" + }, + "compassNorthTop": { + "description": "Fix north to the top of compass", + "label": "Compass North Top" + }, + "displayMode": { + "description": "Screen layout variant", + "label": "Display Mode" + }, + "displayUnits": { + "description": "Display metric or imperial units", + "label": "Display Units" + }, + "flipScreen": { + "description": "Flip display 180 degrees", + "label": "Flip Screen" + }, + "gpsDisplayUnits": { + "description": "Coordinate display format", + "label": "GPS Display Units" + }, + "oledType": { + "description": "Type of OLED screen attached to the device", + "label": "OLED Type" + }, + "screenTimeout": { + "description": "Turn off the display after this long", + "label": "Screen Timeout" + }, + "twelveHourClock": { + "description": "Use 12-hour clock format", + "label": "12-Hour Clock" + }, + "wakeOnTapOrMotion": { + "description": "Wake the device on tap or motion", + "label": "Wake on Tap or Motion" + } + }, + "lora": { + "title": "Mesh Settings", + "description": "Settings for the LoRa mesh", + "bandwidth": { + "description": "Channel bandwidth in kHz", + "label": "Šířka pásma" + }, + "boostedRxGain": { + "description": "Boosted RX gain", + "label": "Boosted RX Gain" + }, + "codingRate": { + "description": "The denominator of the coding rate", + "label": "Coding Rate" + }, + "frequencyOffset": { + "description": "Frequency offset to correct for crystal calibration errors", + "label": "Frequency Offset" + }, + "frequencySlot": { + "description": "LoRa frequency channel number", + "label": "Frekvenční slot" + }, + "hopLimit": { + "description": "Maximum number of hops", + "label": "Hop Limit" + }, + "ignoreMqtt": { + "description": "Don't forward MQTT messages over the mesh", + "label": "Ignorovat MQTT" + }, + "modemPreset": { + "description": "Modem preset to use", + "label": "Předvolba modemu" + }, + "okToMqtt": { + "description": "When set to true, this configuration indicates that the user approves the packet to be uploaded to MQTT. If set to false, remote nodes are requested not to forward packets to MQTT", + "label": "OK do MQTT" + }, + "overrideDutyCycle": { + "description": "Přepsat střídu", + "label": "Přepsat střídu" + }, + "overrideFrequency": { + "description": "Override frequency", + "label": "Override Frequency" + }, + "region": { + "description": "Sets the region for your node", + "label": "Region" + }, + "spreadingFactor": { + "description": "Indicates the number of chirps per symbol", + "label": "Spreading Factor" + }, + "transmitEnabled": { + "description": "Enable/Disable transmit (TX) from the LoRa radio", + "label": "Vysílání povoleno" + }, + "transmitPower": { + "description": "Max transmit power", + "label": "Vysílací výkon" + }, + "usePreset": { + "description": "Use one of the predefined modem presets", + "label": "Použít předvolbu" + }, + "meshSettings": { + "description": "Settings for the LoRa mesh", + "label": "Mesh Settings" + }, + "waveformSettings": { + "description": "Settings for the LoRa waveform", + "label": "Waveform Settings" + }, + "radioSettings": { + "label": "Radio Settings", + "description": "Settings for the LoRa radio" + } + }, + "network": { + "title": "WiFi Config", + "description": "WiFi radio configuration", + "note": "Note: Some devices (ESP32) cannot use both Bluetooth and WiFi at the same time.", + "addressMode": { + "description": "Address assignment selection", + "label": "Address Mode" + }, + "dns": { + "description": "DNS Server", + "label": "DNS" + }, + "ethernetEnabled": { + "description": "Enable or disable the Ethernet port", + "label": "Povoleno" + }, + "gateway": { + "description": "Default Gateway", + "label": "Gateway/Brána" + }, + "ip": { + "description": "IP Address", + "label": "IP adresa" + }, + "psk": { + "description": "Network password", + "label": "PSK" + }, + "ssid": { + "description": "Network name", + "label": "SSID" + }, + "subnet": { + "description": "Subnet Mask", + "label": "Podsíť" + }, + "wifiEnabled": { + "description": "Enable or disable the WiFi radio", + "label": "Povoleno" + }, + "meshViaUdp": { + "label": "Mesh via UDP" + }, + "ntpServer": { + "label": "NTP Server" + }, + "rsyslogServer": { + "label": "Rsyslog Server" + }, + "ethernetConfigSettings": { + "description": "Ethernet port configuration", + "label": "Ethernet Config" + }, + "ipConfigSettings": { + "description": "IP configuration", + "label": "IP Config" + }, + "ntpConfigSettings": { + "description": "NTP configuration", + "label": "NTP Config" + }, + "rsyslogConfigSettings": { + "description": "Rsyslog configuration", + "label": "Rsyslog Config" + }, + "udpConfigSettings": { + "description": "UDP over Mesh configuration", + "label": "UDP Konfigurace" + } + }, + "position": { + "title": "Position Settings", + "description": "Settings for the position module", + "broadcastInterval": { + "description": "How often your position is sent out over the mesh", + "label": "Interval vysílání" + }, + "enablePin": { + "description": "GPS module enable pin override", + "label": "Enable Pin" + }, + "fixedPosition": { + "description": "Don't report GPS position, but a manually-specified one", + "label": "Pevná poloha" + }, + "gpsMode": { + "description": "Configure whether device GPS is Enabled, Disabled, or Not Present", + "label": "GPS Mode" + }, + "gpsUpdateInterval": { + "description": "How often a GPS fix should be acquired", + "label": "GPS Update Interval" + }, + "positionFlags": { + "description": "Optional fields to include when assembling position messages. The more fields are selected, the larger the message will be leading to longer airtime usage and a higher risk of packet loss.", + "label": "Příznaky polohy" + }, + "receivePin": { + "description": "GPS module RX pin override", + "label": "Receive Pin" + }, + "smartPositionEnabled": { + "description": "Only send position when there has been a meaningful change in location", + "label": "Enable Smart Position" + }, + "smartPositionMinDistance": { + "description": "Minimum distance (in meters) that must be traveled before a position update is sent", + "label": "Smart Position Minimum Distance" + }, + "smartPositionMinInterval": { + "description": "Minimum interval (in seconds) that must pass before a position update is sent", + "label": "Smart Position Minimum Interval" + }, + "transmitPin": { + "description": "GPS module TX pin override", + "label": "Transmit Pin" + }, + "intervalsSettings": { + "description": "How often to send position updates", + "label": "Intervals" + }, + "flags": { + "placeholder": "Select position flags...", + "altitude": "Altitude", + "altitudeGeoidalSeparation": "Altitude Geoidal Separation", + "altitudeMsl": "Altitude is Mean Sea Level", + "dop": "Dilution of precision (DOP) PDOP used by default", + "hdopVdop": "If DOP is set, use HDOP / VDOP values instead of PDOP", + "numSatellites": "Number of satellites", + "sequenceNumber": "Sequence number", + "timestamp": "Časová značka", + "unset": "Zrušit nastavení", + "vehicleHeading": "Vehicle heading", + "vehicleSpeed": "Vehicle speed" + } + }, + "power": { + "adcMultiplierOverride": { + "description": "Used for tweaking battery voltage reading", + "label": "ADC Multiplier Override ratio" + }, + "ina219Address": { + "description": "Address of the INA219 battery monitor", + "label": "INA219 Address" + }, + "lightSleepDuration": { + "description": "How long the device will be in light sleep for", + "label": "Light Sleep Duration" + }, + "minimumWakeTime": { + "description": "Minimum amount of time the device will stay awake for after receiving a packet", + "label": "Minimum Wake Time" + }, + "noConnectionBluetoothDisabled": { + "description": "If the device does not receive a Bluetooth connection, the BLE radio will be disabled after this long", + "label": "No Connection Bluetooth Disabled" + }, + "powerSavingEnabled": { + "description": "Select if powered from a low-current source (i.e. solar), to minimize power consumption as much as possible.", + "label": "Povolit úsporný režim" + }, + "shutdownOnBatteryDelay": { + "description": "Automatically shutdown node after this long when on battery, 0 for indefinite", + "label": "Shutdown on battery delay" + }, + "superDeepSleepDuration": { + "description": "How long the device will be in super deep sleep for", + "label": "Super Deep Sleep Duration" + }, + "powerConfigSettings": { + "description": "Settings for the power module", + "label": "Nastavení napájení" + }, + "sleepSettings": { + "description": "Sleep settings for the power module", + "label": "Sleep Settings" + } + }, + "security": { + "description": "Settings for the Security configuration", + "title": "Security Settings", + "button_backupKey": "Backup Key", + "adminChannelEnabled": { + "description": "Allow incoming device control over the insecure legacy admin channel", + "label": "Allow Legacy Admin" + }, + "enableDebugLogApi": { + "description": "Output live debug logging over serial, view and export position-redacted device logs over Bluetooth", + "label": "Enable Debug Log API" + }, + "managed": { + "description": "If enabled, device configuration options are only able to be changed remotely by a Remote Admin node via admin messages. Do not enable this option unless at least one suitable Remote Admin node has been setup, and the public key is stored in one of the fields above.", + "label": "Managed" + }, + "privateKey": { + "description": "Used to create a shared key with a remote device", + "label": "Soukromý klíč" + }, + "publicKey": { + "description": "Sent out to other nodes on the mesh to allow them to compute a shared secret key", + "label": "Veřejný klíč" + }, + "primaryAdminKey": { + "description": "The primary public key authorized to send admin messages to this node", + "label": "Primary Admin Key" + }, + "secondaryAdminKey": { + "description": "The secondary public key authorized to send admin messages to this node", + "label": "Secondary Admin Key" + }, + "serialOutputEnabled": { + "description": "Serial Console over the Stream API", + "label": "Serial Output Enabled" + }, + "tertiaryAdminKey": { + "description": "The tertiary public key authorized to send admin messages to this node", + "label": "Tertiary Admin Key" + }, + "adminSettings": { + "description": "Settings for Admin", + "label": "Admin Settings" + }, + "loggingSettings": { + "description": "Settings for Logging", + "label": "Logging Settings" + } + }, + "user": { + "title": "User Settings", + "description": "Configure your device name and identity settings", + "longName": { + "label": "Dlouhé jméno", + "description": "Your full display name (1-40 characters)", + "validation": { + "min": "Long name must be at least 1 character", + "max": "Long name must be at most 40 characters" + } + }, + "shortName": { + "label": "Krátké jméno", + "description": "Your abbreviated name (2-4 characters)", + "validation": { + "min": "Short name must be at least 2 characters", + "max": "Short name must be at most 4 characters" + } + }, + "isUnmessageable": { + "label": "Nepřijímá zprávy", + "description": "Used to identify unmonitored or infrastructure nodes so that messaging is not available to nodes that will never respond." + }, + "isLicensed": { + "label": "Licencované amatérské rádio (HAM)", + "description": "Enable if you are a licensed amateur radio operator, enabling this option disables encryption and is not compatible with the default Meshtastic network." + } + } +} diff --git a/packages/web/public/i18n/locales/cs-CZ/connections.json b/packages/web/public/i18n/locales/cs-CZ/connections.json new file mode 100644 index 000000000..6e23864ee --- /dev/null +++ b/packages/web/public/i18n/locales/cs-CZ/connections.json @@ -0,0 +1,34 @@ +{ + "page": { + "title": "Connect to a Meshtastic device", + "description": "Add a device connection via HTTP, Bluetooth, or Serial. Your saved connections will be saved in your browser." + }, + "connectionType_ble": "BLE", + "connectionType_serial": "Sériový", + "connectionType_network": "Síť", + "deleteConnection": "Delete connection", + "areYouSure": "This will remove {{name}}. You canot undo this action.", + "moreActions": "More actions", + "noConnections": { + "title": "No connections yet.", + "description": "Create your first connection. It will connect immediately and be saved for later." + }, + "lastConnectedAt": "Last connected: {{date}}", + "neverConnected": "Never connected", + "toasts": { + "connected": "Připojeno", + "nowConnected": "{{name}} is now connected", + "nowDisconnected": "{{name}} are now disconnecte", + "disconnected": "Odpojeno", + "failed": "Failed to connect", + "checkConnetion": "Check your device or settings and try again", + "defaultSet": "Default set", + "defaultConnection": "Default connection is now {{nameisconnected}}", + "deleted": "Deleted", + "deletedByName": "{{name}} was removed", + "pickConnectionAgain": "Could not connect. You may need to reselect the device/port.", + "added": "Connection added", + "savedByName": "{{name}} saved.", + "savedCantConnect": "The connection was saved but could not connect." + } +} diff --git a/packages/web/public/i18n/locales/cs-CZ/dashboard.json b/packages/web/public/i18n/locales/cs-CZ/dashboard.json deleted file mode 100644 index 22c36f4d3..000000000 --- a/packages/web/public/i18n/locales/cs-CZ/dashboard.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "dashboard": { - "title": "Connected Devices", - "description": "Manage your connected Meshtastic devices.", - "connectionType_ble": "BLE", - "connectionType_serial": "Sériový", - "connectionType_network": "Síť", - "noDevicesTitle": "No devices connected", - "noDevicesDescription": "Connect a new device to get started.", - "button_newConnection": "New Connection" - } -} diff --git a/packages/web/public/i18n/locales/cs-CZ/deviceConfig.json b/packages/web/public/i18n/locales/cs-CZ/deviceConfig.json index 4c0a47f2d..819792d72 100644 --- a/packages/web/public/i18n/locales/cs-CZ/deviceConfig.json +++ b/packages/web/public/i18n/locales/cs-CZ/deviceConfig.json @@ -122,7 +122,7 @@ "title": "Mesh Settings", "description": "Settings for the LoRa mesh", "bandwidth": { - "description": "Channel bandwidth in MHz", + "description": "Channel bandwidth in kHz", "label": "Šířka pásma" }, "boostedRxGain": { diff --git a/packages/web/public/i18n/locales/cs-CZ/dialog.json b/packages/web/public/i18n/locales/cs-CZ/dialog.json index 6711f3b7e..077947e8d 100644 --- a/packages/web/public/i18n/locales/cs-CZ/dialog.json +++ b/packages/web/public/i18n/locales/cs-CZ/dialog.json @@ -1,193 +1,238 @@ { - "deleteMessages": { - "description": "This action will clear all message history. This cannot be undone. Are you sure you want to continue?", - "title": "Clear All Messages" - }, - "deviceName": { - "description": "The Device will restart once the config is saved.", - "longName": "Long Name", - "shortName": "Short Name", - "title": "Change Device Name", - "validation": { - "longNameMax": "Long name must not be more than 40 characters", - "shortNameMax": "Short name must not be more than 4 characters", - "longNameMin": "Long name must have at least 1 character", - "shortNameMin": "Short name must have at least 1 character" - } - }, - "import": { - "description": "The current LoRa configuration will be overridden.", - "error": { - "invalidUrl": "Invalid Meshtastic URL" - }, - "channelPrefix": "Channel: ", - "channelSetUrl": "Channel Set/QR Code URL", - "channels": "Channels:", - "usePreset": "Use Preset?", - "title": "Import Channel Set" - }, - "locationResponse": { - "title": "Location: {{identifier}}", - "altitude": "Altitude: ", - "coordinates": "Coordinates: ", - "noCoordinates": "No Coordinates" - }, - "pkiRegenerateDialog": { - "title": "Regenerate Pre-Shared Key?", - "description": "Are you sure you want to regenerate the pre-shared key?", - "regenerate": "Regenerate" - }, - "newDeviceDialog": { - "title": "Connect New Device", - "https": "https", - "http": "http", - "tabHttp": "HTTP", - "tabBluetooth": "Bluetooth", - "tabSerial": "Sériový", - "useHttps": "Use HTTPS", - "connecting": "Connecting...", - "connect": "Connect", - "connectionFailedAlert": { - "title": "Connection Failed", - "descriptionPrefix": "Could not connect to the device. ", - "httpsHint": "If using HTTPS, you may need to accept a self-signed certificate first. ", - "openLinkPrefix": "Please open ", - "openLinkSuffix": " in a new tab", - "acceptTlsWarningSuffix": ", accept any TLS warnings if prompted, then try again", - "learnMoreLink": "Learn more" - }, - "httpConnection": { - "label": "IP Address/Hostname", - "placeholder": "000.000.000.000 / meshtastic.local" - }, - "serialConnection": { - "noDevicesPaired": "No devices paired yet.", - "newDeviceButton": "New device", - "deviceIdentifier": "# {{index}} - {{vendorId}} - {{productId}}" - }, - "bluetoothConnection": { - "noDevicesPaired": "No devices paired yet.", - "newDeviceButton": "New device", - "connectionFailed": "Connection failed", - "deviceDisconnected": "Device disconnected", - "unknownDevice": "Unknown Device", - "errorLoadingDevices": "Error loading devices", - "unknownErrorLoadingDevices": "Unknown error loading devices" - }, - "validation": { - "requiresWebBluetooth": "This connection type requires <0>Web Bluetooth. Please use a supported browser, like Chrome or Edge.", - "requiresWebSerial": "This connection type requires <0>Web Serial. Please use a supported browser, like Chrome or Edge.", - "requiresSecureContext": "This application requires a <0>secure context. Please connect using HTTPS or localhost.", - "additionallyRequiresSecureContext": "Additionally, it requires a <0>secure context. Please connect using HTTPS or localhost." - } - }, - "nodeDetails": { - "message": "Zpráva", - "requestPosition": "Request Position", - "traceRoute": "Trace Route", - "airTxUtilization": "Air TX utilization", - "allRawMetrics": "All Raw Metrics:", - "batteryLevel": "Battery level", - "channelUtilization": "Channel utilization", - "details": "Details:", - "deviceMetrics": "Device Metrics:", - "hardware": "Hardware: ", - "lastHeard": "Last Heard: ", - "nodeHexPrefix": "Node Hex: ", - "nodeNumber": "Node Number: ", - "position": "Position:", - "role": "Role: ", - "uptime": "Uptime: ", - "voltage": "Napětí", - "title": "Node Details for {{identifier}}", - "ignoreNode": "Ignore node", - "removeNode": "Remove node", - "unignoreNode": "Unignore node", - "security": "Security:", - "publicKey": "Public Key: ", - "messageable": "Messageable: ", - "KeyManuallyVerifiedTrue": "Public Key has been manually verified", - "KeyManuallyVerifiedFalse": "Public Key is not manually verified" - }, - "pkiBackup": { - "loseKeysWarning": "If you lose your keys, you will need to reset your device.", - "secureBackup": "Its important to backup your public and private keys and store your backup securely!", - "footer": "=== END OF KEYS ===", - "header": "=== MESHTASTIC KEYS FOR {{longName}} ({{shortName}}) ===", - "privateKey": "Private Key:", - "publicKey": "Public Key:", - "fileName": "meshtastic_keys_{{longName}}_{{shortName}}.txt", - "title": "Backup Keys" - }, - "pkiBackupReminder": { - "description": "We recommend backing up your key data regularly. Would you like to back up now?", - "title": "Backup Reminder", - "remindLaterPrefix": "Remind me in", - "remindNever": "Never remind me", - "backupNow": "Back up now" - }, - "pkiRegenerate": { - "description": "Are you sure you want to regenerate key pair?", - "title": "Regenerate Key Pair" - }, - "qr": { - "addChannels": "Add Channels", - "replaceChannels": "Replace Channels", - "description": "The current LoRa configuration will also be shared.", - "sharableUrl": "Sharable URL", - "title": "Generate QR Code" - }, - "reboot": { - "title": "Reboot device", - "description": "Reboot now or schedule a reboot of the connected node. Optionally, you can choose to reboot into OTA (Over-the-Air) mode.", - "ota": "Reboot into OTA mode", - "enterDelay": "Enter delay", - "scheduled": "Reboot has been scheduled", - "schedule": "Schedule reboot", - "now": "Reboot now", - "cancel": "Cancel scheduled reboot" - }, - "refreshKeys": { - "description": { - "acceptNewKeys": "This will remove the node from device and request new keys.", - "keyMismatchReasonSuffix": ". This is due to the remote node's current public key does not match the previously stored key for this node.", - "unableToSendDmPrefix": "Your node is unable to send a direct message to node: " - }, - "acceptNewKeys": "Accept New Keys", - "title": "Keys Mismatch - {{identifier}}" - }, - "removeNode": { - "description": "Are you sure you want to remove this Node?", - "title": "Remove Node?" - }, - "shutdown": { - "title": "Schedule Shutdown", - "description": "Turn off the connected node after x minutes." - }, - "traceRoute": { - "routeToDestination": "Route to destination:", - "routeBack": "Route back:" - }, - "tracerouteResponse": { - "title": "Traceroute: {{identifier}}" - }, - "unsafeRoles": { - "confirmUnderstanding": "Yes, I know what I'm doing", - "conjunction": " and the blog post about ", - "postamble": " and understand the implications of changing the role.", - "preamble": "I have read the ", - "choosingRightDeviceRole": "Choosing The Right Device Role", - "deviceRoleDocumentation": "Device Role Documentation", - "title": "Jste si jistý?" - }, - "managedMode": { - "confirmUnderstanding": "Yes, I know what I'm doing", - "title": "Jste si jistý?", - "description": "Enabling Managed Mode blocks client applications (including the web client) from writing configurations to a radio. Once enabled, radio configurations can only be changed through Remote Admin messages. This setting is not required for remote node administration." - }, - "clientNotification": { - "title": "Oznámení klienta", - "TraceRoute can only be sent once every 30 seconds": "TraceRoute can only be sent once every 30 seconds", - "Compromised keys were detected and regenerated.": "Compromised keys were detected and regenerated." - } + "deleteMessages": { + "description": "This action will clear all message history. This cannot be undone. Are you sure you want to continue?", + "title": "Clear All Messages" + }, + "import": { + "description": "The current LoRa configuration will be overridden.", + "error": { + "invalidUrl": "Invalid Meshtastic URL" + }, + "channelPrefix": "Channel: ", + "primary": "Primary ", + "doNotImport": "No not import", + "channelName": "Jméno", + "channelSlot": "Slot", + "channelSetUrl": "Channel Set/QR Code URL", + "useLoraConfig": "Import LoRa Config", + "presetDescription": "The current LoRa Config will be replaced.", + "title": "Import Channel Set" + }, + "locationResponse": { + "title": "Location: {{identifier}}", + "altitude": "Altitude: ", + "coordinates": "Coordinates: ", + "noCoordinates": "No Coordinates" + }, + "pkiRegenerateDialog": { + "title": "Regenerate Pre-Shared Key?", + "description": "Are you sure you want to regenerate the pre-shared key?", + "regenerate": "Regenerate" + }, + "addConnection": { + "title": "Add connection", + "description": "Choose a connection type and fill in the details", + "validation": { + "requiresWebBluetooth": "This connection type requires <0>Web Bluetooth. Please use a supported browser, like Chrome or Edge.", + "requiresWebSerial": "This connection type requires <0>Web Serial. Please use a supported browser, like Chrome or Edge.", + "requiresSecureContext": "This application requires a <0>secure context. Please connect using HTTPS or localhost.", + "additionallyRequiresSecureContext": "Additionally, it requires a <0>secure context. Please connect using HTTPS or localhost." + }, + "bluetoothConnection": { + "namePlaceholder": "My Bluetooth Node", + "supported": { + "title": "Web Bluetooth supported" + }, + "notSupported": { + "title": "Web Bluetooth not supported", + "description": "Your browser or device does not support Web Bluetooth" + }, + "short": "BT: {{deviceName}}", + "long": "Bluetooth Device", + "device": "Zařízení", + "selectDevice": "Select device", + "selected": "Bluetooth device selected", + "notSelected": "No device selected", + "helperText": "Uses the Meshtastic Bluetooth service for discovery." + }, + "serialConnection": { + "namePlaceholder": "My Serial Node", + "helperText": "Selecting a port grants permission so the app can open it to connect.", + "supported": { + "title": "Web Serial supported" + }, + "notSupported": { + "title": "Web Serial not supported", + "description": "Your browser or device does not support Web Serial" + }, + "portSelected": { + "title": "Serial port selected", + "description": "Port permissions granted." + }, + "port": "Port", + "selectPort": "Select port", + "deviceName": "USB {{vendorId}}:{{productId}}", + "notSelected": "No port selected" + }, + "httpConnection": { + "namePlaceholder": "My HTTP Node", + "inputPlaceholder": "192.168.1.10 or meshtastic.local", + "heading": "URL or IP", + "useHttps": "Use HTTTPS", + "invalidUrl": { + "title": "Invalid URL", + "description": "Please enter a valid HTTP or HTTPS URL." + }, + "connectionTest": { + "description": "Test the connetion before saving to verify the device is reachable.", + "button": { + "loading": "Testing...", + "label": "Test connection" + }, + "reachable": "Reachable", + "notReachable": "Not reachable", + "success": { + "title": "Connection test successful", + "description": "The device appears to be reachable." + }, + "failure": { + "title": "Connection test failed", + "description": "Could not reach the device. Check the URL and try again." + } + } + } + }, + "nodeDetails": { + "message": "Zpráva", + "requestPosition": "Request Position", + "traceRoute": "Trace Route", + "airTxUtilization": "Air TX utilization", + "allRawMetrics": "All Raw Metrics:", + "batteryLevel": "Battery level", + "channelUtilization": "Channel utilization", + "details": "Details:", + "deviceMetrics": "Device Metrics:", + "hardware": "Hardware: ", + "lastHeard": "Last Heard: ", + "nodeHexPrefix": "Node Hex: ", + "nodeNumber": "Node Number: ", + "position": "Position:", + "role": "Role: ", + "uptime": "Uptime: ", + "voltage": "Napětí", + "title": "Node Details for {{identifier}}", + "ignoreNode": "Ignore node", + "removeNode": "Remove node", + "unignoreNode": "Unignore node", + "security": "Security:", + "publicKey": "Public Key: ", + "messageable": "Messageable: ", + "KeyManuallyVerifiedTrue": "Public Key has been manually verified", + "KeyManuallyVerifiedFalse": "Public Key is not manually verified" + }, + "pkiBackup": { + "loseKeysWarning": "If you lose your keys, you will need to reset your device.", + "secureBackup": "Its important to backup your public and private keys and store your backup securely!", + "footer": "=== END OF KEYS ===", + "header": "=== MESHTASTIC KEYS FOR {{longName}} ({{shortName}}) ===", + "privateKey": "Private Key:", + "publicKey": "Public Key:", + "fileName": "meshtastic_keys_{{longName}}_{{shortName}}.txt", + "title": "Backup Keys" + }, + "pkiBackupReminder": { + "description": "We recommend backing up your key data regularly. Would you like to back up now?", + "title": "Backup Reminder", + "remindLaterPrefix": "Remind me in", + "remindNever": "Never remind me", + "backupNow": "Back up now" + }, + "pkiRegenerate": { + "description": "Are you sure you want to regenerate key pair?", + "title": "Regenerate Key Pair" + }, + "qr": { + "addChannels": "Add Channels", + "replaceChannels": "Replace Channels", + "description": "The current LoRa configuration will also be shared.", + "sharableUrl": "Sharable URL", + "title": "Generate QR Code" + }, + "reboot": { + "title": "Reboot device", + "description": "Reboot now or schedule a reboot of the connected node. Optionally, you can choose to reboot into OTA (Over-the-Air) mode.", + "ota": "Reboot into OTA mode", + "enterDelay": "Enter delay", + "scheduled": "Reboot has been scheduled", + "schedule": "Schedule reboot", + "now": "Reboot now", + "cancel": "Cancel scheduled reboot" + }, + "refreshKeys": { + "description": { + "acceptNewKeys": "This will remove the node from device and request new keys.", + "keyMismatchReasonSuffix": ". This is due to the remote node's current public key does not match the previously stored key for this node.", + "unableToSendDmPrefix": "Your node is unable to send a direct message to node: " + }, + "acceptNewKeys": "Accept New Keys", + "title": "Keys Mismatch - {{identifier}}" + }, + "removeNode": { + "description": "Are you sure you want to remove this Node?", + "title": "Remove Node?" + }, + "shutdown": { + "title": "Schedule Shutdown", + "description": "Turn off the connected node after x minutes." + }, + "traceRoute": { + "routeToDestination": "Route to destination:", + "routeBack": "Route back:" + }, + "tracerouteResponse": { + "title": "Traceroute: {{identifier}}" + }, + "unsafeRoles": { + "confirmUnderstanding": "Yes, I know what I'm doing", + "conjunction": " and the blog post about ", + "postamble": " and understand the implications of changing the role.", + "preamble": "I have read the ", + "choosingRightDeviceRole": "Choosing The Right Device Role", + "deviceRoleDocumentation": "Device Role Documentation", + "title": "Jste si jistý?" + }, + "managedMode": { + "confirmUnderstanding": "Yes, I know what I'm doing", + "title": "Jste si jistý?", + "description": "Enabling Managed Mode blocks client applications (including the web client) from writing configurations to a radio. Once enabled, radio configurations can only be changed through Remote Admin messages. This setting is not required for remote node administration." + }, + "clientNotification": { + "title": "Oznámení klienta", + "TraceRoute can only be sent once every 30 seconds": "TraceRoute can only be sent once every 30 seconds", + "Compromised keys were detected and regenerated.": "Compromised keys were detected and regenerated." + }, + "resetNodeDb": { + "title": "Reset Node Database", + "description": "This will clear all nodes from the connected device's node database and clear all message history in the client. This cannot be undone. Are you sure you want to continue?", + "confirm": "Reset Node Database", + "failedTitle": "There was an error resetting the Node DB. Please try again." + }, + "clearAllStores": { + "title": "Clear All Local Storage", + "description": "This will clear all locally stored data, including message history and node databases for all previously connected devices. This will require you to reconnect to your node once complete and cannot be undone. Are you sure you want to continue?", + "confirm": "Clear all local storage", + "failedTitle": "There was an error clearing local storage. Please try again." + }, + "factoryResetDevice": { + "title": "Factory Reset Device", + "description": "This will factory reset the connected device, erasing all configurations and data on the device as well as all nodes and messages saved in the client. This cannot be undone. Are you sure you want to continue?", + "confirm": "Factory Reset Device", + "failedTitle": "There was an error performing the factory reset. Please try again." + }, + "factoryResetConfig": { + "title": "Factory Reset Config", + "description": "This will factory reset the configuration on the connected device, erasing all configurations on the device. This cannot be undone. Are you sure you want to continue?", + "confirm": "Factory Reset Config", + "failedTitle": "There was an error performing the factory reset. Please try again." + } } diff --git a/packages/web/public/i18n/locales/cs-CZ/map.json b/packages/web/public/i18n/locales/cs-CZ/map.json new file mode 100644 index 000000000..231b868ff --- /dev/null +++ b/packages/web/public/i18n/locales/cs-CZ/map.json @@ -0,0 +1,38 @@ +{ + "maplibre": { + "GeolocateControl.FindMyLocation": "Find my location", + "NavigationControl.ZoomIn": "Zoom in", + "NavigationControl.ZoomOut": "Zoom out", + "CooperativeGesturesHandler.WindowsHelpText": "Use Ctrl + scroll to zoom the map", + "CooperativeGesturesHandler.MacHelpText": "Use ⌘ + scroll to zoom the map", + "CooperativeGesturesHandler.MobileHelpText": "Use two fingers to move the map" + }, + "layerTool": { + "nodeMarkers": "Show nodes", + "directNeighbors": "Show direct connections", + "remoteNeighbors": "Show remote connections", + "positionPrecision": "Show position precision", + "traceroutes": "Show traceroutes", + "waypoints": "Show waypoints" + }, + "mapMenu": { + "locateAria": "Locate my node", + "layersAria": "Change map style" + }, + "waypointDetail": { + "edit": "Upravit", + "description": "Description:", + "createdBy": "Edited by:", + "createdDate": "Created:", + "updated": "Updated:", + "expires": "Expires:", + "distance": "Distance:", + "bearing": "Absolute bearing:", + "lockedTo": "Locked by:", + "latitude": "Latitude:", + "longitude": "Longitude:" + }, + "myNode": { + "tooltip": "This device" + } +} diff --git a/packages/web/public/i18n/locales/cs-CZ/messages.json b/packages/web/public/i18n/locales/cs-CZ/messages.json index 58688d9fd..e4ddb17d0 100644 --- a/packages/web/public/i18n/locales/cs-CZ/messages.json +++ b/packages/web/public/i18n/locales/cs-CZ/messages.json @@ -1,39 +1,39 @@ { - "page": { - "title": "Messages: {{chatName}}", - "placeholder": "Enter Message" - }, - "emptyState": { - "title": "Select a Chat", - "text": "No messages yet." - }, - "selectChatPrompt": { - "text": "Select a channel or node to start messaging." - }, - "sendMessage": { - "placeholder": "Enter your message here...", - "sendButton": "Odeslat" - }, - "actionsMenu": { - "addReactionLabel": "Add Reaction", - "replyLabel": "Reply" - }, - "deliveryStatus": { - "delivered": { - "label": "Message delivered", - "displayText": "Message delivered" - }, - "failed": { - "label": "Message delivery failed", - "displayText": "Delivery failed" - }, - "unknown": { - "label": "Message status unknown", - "displayText": "Unknown state" - }, - "waiting": { - "label": "Sending message", - "displayText": "Waiting for delivery" - } - } + "page": { + "title": "Messages: {{chatName}}", + "placeholder": "Enter Message" + }, + "emptyState": { + "title": "Select a Chat", + "text": "No messages yet." + }, + "selectChatPrompt": { + "text": "Select a channel or node to start messaging." + }, + "sendMessage": { + "placeholder": "Enter your message here...", + "sendButton": "Odeslat" + }, + "actionsMenu": { + "addReactionLabel": "Add Reaction", + "replyLabel": "Reply" + }, + "deliveryStatus": { + "delivered": { + "label": "Message delivered", + "displayText": "Message delivered" + }, + "failed": { + "label": "Message delivery failed", + "displayText": "Delivery failed" + }, + "unknown": { + "label": "Message status unknown", + "displayText": "Unknown state" + }, + "waiting": { + "label": "Sending message", + "displayText": "Waiting for delivery" + } + } } diff --git a/packages/web/public/i18n/locales/cs-CZ/moduleConfig.json b/packages/web/public/i18n/locales/cs-CZ/moduleConfig.json index 2893feef0..a8774916d 100644 --- a/packages/web/public/i18n/locales/cs-CZ/moduleConfig.json +++ b/packages/web/public/i18n/locales/cs-CZ/moduleConfig.json @@ -1,448 +1,448 @@ { - "page": { - "tabAmbientLighting": "Ambientní osvětlení", - "tabAudio": "Zvuk", - "tabCannedMessage": "Canned", - "tabDetectionSensor": "Detekční senzor", - "tabExternalNotification": "Ext Notif", - "tabMqtt": "MQTT", - "tabNeighborInfo": "Informace o sousedech", - "tabPaxcounter": "Paxcounter", - "tabRangeTest": "Zkouška dosahu", - "tabSerial": "Sériový", - "tabStoreAndForward": "S&F", - "tabTelemetry": "Telemetrie" - }, - "ambientLighting": { - "title": "Ambient Lighting Settings", - "description": "Settings for the Ambient Lighting module", - "ledState": { - "label": "LED State", - "description": "Sets LED to on or off" - }, - "current": { - "label": "Proud", - "description": "Sets the current for the LED output. Default is 10" - }, - "red": { - "label": "Červená", - "description": "Sets the red LED level. Values are 0-255" - }, - "green": { - "label": "Zelená", - "description": "Sets the green LED level. Values are 0-255" - }, - "blue": { - "label": "Modrá", - "description": "Sets the blue LED level. Values are 0-255" - } - }, - "audio": { - "title": "Audio Settings", - "description": "Settings for the Audio module", - "codec2Enabled": { - "label": "Codec 2 Enabled", - "description": "Enable Codec 2 audio encoding" - }, - "pttPin": { - "label": "PTT Pin", - "description": "GPIO pin to use for PTT" - }, - "bitrate": { - "label": "Bitrate", - "description": "Bitrate to use for audio encoding" - }, - "i2sWs": { - "label": "i2S WS", - "description": "GPIO pin to use for i2S WS" - }, - "i2sSd": { - "label": "i2S SD", - "description": "GPIO pin to use for i2S SD" - }, - "i2sDin": { - "label": "i2S DIN", - "description": "GPIO pin to use for i2S DIN" - }, - "i2sSck": { - "label": "i2S SCK", - "description": "GPIO pin to use for i2S SCK" - } - }, - "cannedMessage": { - "title": "Canned Message Settings", - "description": "Settings for the Canned Message module", - "moduleEnabled": { - "label": "Module Enabled", - "description": "Enable Canned Message" - }, - "rotary1Enabled": { - "label": "Rotary Encoder #1 Enabled", - "description": "Enable the rotary encoder" - }, - "inputbrokerPinA": { - "label": "Encoder Pin A", - "description": "GPIO Pin Value (1-39) For encoder port A" - }, - "inputbrokerPinB": { - "label": "Encoder Pin B", - "description": "GPIO Pin Value (1-39) For encoder port B" - }, - "inputbrokerPinPress": { - "label": "Encoder Pin Press", - "description": "GPIO Pin Value (1-39) For encoder Press" - }, - "inputbrokerEventCw": { - "label": "Clockwise event", - "description": "Select input event." - }, - "inputbrokerEventCcw": { - "label": "Counter Clockwise event", - "description": "Select input event." - }, - "inputbrokerEventPress": { - "label": "Press event", - "description": "Select input event" - }, - "updown1Enabled": { - "label": "Up Down enabled", - "description": "Enable the up / down encoder" - }, - "allowInputSource": { - "label": "Allow Input Source", - "description": "Select from: '_any', 'rotEnc1', 'upDownEnc1', 'cardkb'" - }, - "sendBell": { - "label": "Send Bell", - "description": "Sends a bell character with each message" - } - }, - "detectionSensor": { - "title": "Detection Sensor Settings", - "description": "Settings for the Detection Sensor module", - "enabled": { - "label": "Povoleno", - "description": "Enable or disable Detection Sensor Module" - }, - "minimumBroadcastSecs": { - "label": "Minimum Broadcast Seconds", - "description": "The interval in seconds of how often we can send a message to the mesh when a state change is detected" - }, - "stateBroadcastSecs": { - "label": "State Broadcast Seconds", - "description": "The interval in seconds of how often we should send a message to the mesh with the current state regardless of changes" - }, - "sendBell": { - "label": "Send Bell", - "description": "Send ASCII bell with alert message" - }, - "name": { - "label": "Friendly Name", - "description": "Used to format the message sent to mesh, max 20 Characters" - }, - "monitorPin": { - "label": "Monitor Pin", - "description": "The GPIO pin to monitor for state changes" - }, - "detectionTriggerType": { - "label": "Detection Triggered Type", - "description": "The type of trigger event to be used" - }, - "usePullup": { - "label": "Use Pullup", - "description": "Whether or not use INPUT_PULLUP mode for GPIO pin" - } - }, - "externalNotification": { - "title": "External Notification Settings", - "description": "Configure the external notification module", - "enabled": { - "label": "Module Enabled", - "description": "Enable External Notification" - }, - "outputMs": { - "label": "Output MS", - "description": "Output MS" - }, - "output": { - "label": "Output", - "description": "Output" - }, - "outputVibra": { - "label": "Output Vibrate", - "description": "Output Vibrate" - }, - "outputBuzzer": { - "label": "Output Buzzer", - "description": "Output Buzzer" - }, - "active": { - "label": "Active", - "description": "Active" - }, - "alertMessage": { - "label": "Alert Message", - "description": "Alert Message" - }, - "alertMessageVibra": { - "label": "Alert Message Vibrate", - "description": "Alert Message Vibrate" - }, - "alertMessageBuzzer": { - "label": "Alert Message Buzzer", - "description": "Alert Message Buzzer" - }, - "alertBell": { - "label": "Alert Bell", - "description": "Should an alert be triggered when receiving an incoming bell?" - }, - "alertBellVibra": { - "label": "Alert Bell Vibrate", - "description": "Alert Bell Vibrate" - }, - "alertBellBuzzer": { - "label": "Alert Bell Buzzer", - "description": "Alert Bell Buzzer" - }, - "usePwm": { - "label": "Use PWM", - "description": "Use PWM" - }, - "nagTimeout": { - "label": "Nag Timeout", - "description": "Nag Timeout" - }, - "useI2sAsBuzzer": { - "label": "Use I²S Pin as Buzzer", - "description": "Designate I²S Pin as Buzzer Output" - } - }, - "mqtt": { - "title": "MQTT Settings", - "description": "Settings for the MQTT module", - "enabled": { - "label": "Povoleno", - "description": "Enable or disable MQTT" - }, - "address": { - "label": "MQTT Server Address", - "description": "MQTT server address to use for default/custom servers" - }, - "username": { - "label": "MQTT Username", - "description": "MQTT username to use for default/custom servers" - }, - "password": { - "label": "MQTT Password", - "description": "MQTT password to use for default/custom servers" - }, - "encryptionEnabled": { - "label": "Encryption Enabled", - "description": "Enable or disable MQTT encryption. Note: All messages are sent to the MQTT broker unencrypted if this option is not enabled, even when your uplink channels have encryption keys set. This includes position data." - }, - "jsonEnabled": { - "label": "JSON Enabled", - "description": "Whether to send/consume JSON packets on MQTT" - }, - "tlsEnabled": { - "label": "TLS povoleno", - "description": "Enable or disable TLS" - }, - "root": { - "label": "Kořenové téma", - "description": "MQTT root topic to use for default/custom servers" - }, - "proxyToClientEnabled": { - "label": "MQTT Client Proxy Enabled", - "description": "Utilizes the network connection to proxy MQTT messages to the client." - }, - "mapReportingEnabled": { - "label": "Map Reporting Enabled", - "description": "Your node will periodically send an unencrypted map report packet to the configured MQTT server, this includes id, short and long name, approximate location, hardware model, role, firmware version, LoRa region, modem preset and primary channel name." - }, - "mapReportSettings": { - "publishIntervalSecs": { - "label": "Map Report Publish Interval (s)", - "description": "Interval in seconds to publish map reports" - }, - "positionPrecision": { - "label": "Approximate Location", - "description": "Position shared will be accurate within this distance", - "options": { - "metric_km23": "Within 23 km", - "metric_km12": "Within 12 km", - "metric_km5_8": "Within 5.8 km", - "metric_km2_9": "Within 2.9 km", - "metric_km1_5": "Within 1.5 km", - "metric_m700": "Within 700 m", - "metric_m350": "Within 350 m", - "metric_m200": "Within 200 m", - "metric_m90": "Within 90 m", - "metric_m50": "Within 50 m", - "imperial_mi15": "Within 15 miles", - "imperial_mi7_3": "Within 7.3 miles", - "imperial_mi3_6": "Within 3.6 miles", - "imperial_mi1_8": "Within 1.8 miles", - "imperial_mi0_9": "Within 0.9 miles", - "imperial_mi0_5": "Within 0.5 miles", - "imperial_mi0_2": "Within 0.2 miles", - "imperial_ft600": "Within 600 feet", - "imperial_ft300": "Within 300 feet", - "imperial_ft150": "Within 150 feet" - } - } - } - }, - "neighborInfo": { - "title": "Neighbor Info Settings", - "description": "Settings for the Neighbor Info module", - "enabled": { - "label": "Povoleno", - "description": "Enable or disable Neighbor Info Module" - }, - "updateInterval": { - "label": "Update Interval", - "description": "Interval in seconds of how often we should try to send our Neighbor Info to the mesh" - } - }, - "paxcounter": { - "title": "Paxcounter Settings", - "description": "Settings for the Paxcounter module", - "enabled": { - "label": "Module Enabled", - "description": "Enable Paxcounter" - }, - "paxcounterUpdateInterval": { - "label": "Update Interval (seconds)", - "description": "How long to wait between sending paxcounter packets" - }, - "wifiThreshold": { - "label": "WiFi RSSI Threshold", - "description": "At what WiFi RSSI level should the counter increase. Defaults to -80." - }, - "bleThreshold": { - "label": "BLE RSSI Threshold", - "description": "At what BLE RSSI level should the counter increase. Defaults to -80." - } - }, - "rangeTest": { - "title": "Range Test Settings", - "description": "Settings for the Range Test module", - "enabled": { - "label": "Module Enabled", - "description": "Enable Range Test" - }, - "sender": { - "label": "Message Interval", - "description": "How long to wait between sending test packets" - }, - "save": { - "label": "Save CSV to storage", - "description": "ESP32 Only" - } - }, - "serial": { - "title": "Serial Settings", - "description": "Settings for the Serial module", - "enabled": { - "label": "Module Enabled", - "description": "Enable Serial output" - }, - "echo": { - "label": "Echo", - "description": "Any packets you send will be echoed back to your device" - }, - "rxd": { - "label": "Receive Pin", - "description": "Set the GPIO pin to the RXD pin you have set up." - }, - "txd": { - "label": "Transmit Pin", - "description": "Set the GPIO pin to the TXD pin you have set up." - }, - "baud": { - "label": "Baud Rate", - "description": "The serial baud rate" - }, - "timeout": { - "label": "Vypršel čas spojení", - "description": "Seconds to wait before we consider your packet as 'done'" - }, - "mode": { - "label": "Mode", - "description": "Select Mode" - }, - "overrideConsoleSerialPort": { - "label": "Override Console Serial Port", - "description": "If you have a serial port connected to the console, this will override it." - } - }, - "storeForward": { - "title": "Store & Forward Settings", - "description": "Settings for the Store & Forward module", - "enabled": { - "label": "Module Enabled", - "description": "Enable Store & Forward" - }, - "heartbeat": { - "label": "Heartbeat Enabled", - "description": "Enable Store & Forward heartbeat" - }, - "records": { - "label": "Počet záznamů", - "description": "Number of records to store" - }, - "historyReturnMax": { - "label": "History return max", - "description": "Max number of records to return" - }, - "historyReturnWindow": { - "label": "History return window", - "description": "Max number of records to return" - } - }, - "telemetry": { - "title": "Telemetry Settings", - "description": "Settings for the Telemetry module", - "deviceUpdateInterval": { - "label": "Device Metrics", - "description": "Interval aktualizace metrik zařízení (v sekundách)" - }, - "environmentUpdateInterval": { - "label": "Interval aktualizace metrik životního prostředí (v sekundách)", - "description": "" - }, - "environmentMeasurementEnabled": { - "label": "Module Enabled", - "description": "Enable the Environment Telemetry" - }, - "environmentScreenEnabled": { - "label": "Displayed on Screen", - "description": "Show the Telemetry Module on the OLED" - }, - "environmentDisplayFahrenheit": { - "label": "Display Fahrenheit", - "description": "Display temp in Fahrenheit" - }, - "airQualityEnabled": { - "label": "Air Quality Enabled", - "description": "Enable the Air Quality Telemetry" - }, - "airQualityInterval": { - "label": "Air Quality Update Interval", - "description": "How often to send Air Quality data over the mesh" - }, - "powerMeasurementEnabled": { - "label": "Power Measurement Enabled", - "description": "Enable the Power Measurement Telemetry" - }, - "powerUpdateInterval": { - "label": "Power Update Interval", - "description": "How often to send Power data over the mesh" - }, - "powerScreenEnabled": { - "label": "Power Screen Enabled", - "description": "Enable the Power Telemetry Screen" - } - } + "page": { + "tabAmbientLighting": "Ambientní osvětlení", + "tabAudio": "Zvuk", + "tabCannedMessage": "Canned", + "tabDetectionSensor": "Detekční senzor", + "tabExternalNotification": "Ext Notif", + "tabMqtt": "MQTT", + "tabNeighborInfo": "Informace o sousedech", + "tabPaxcounter": "Paxcounter", + "tabRangeTest": "Zkouška dosahu", + "tabSerial": "Sériový", + "tabStoreAndForward": "S&F", + "tabTelemetry": "Telemetrie" + }, + "ambientLighting": { + "title": "Ambient Lighting Settings", + "description": "Settings for the Ambient Lighting module", + "ledState": { + "label": "LED State", + "description": "Sets LED to on or off" + }, + "current": { + "label": "Proud", + "description": "Sets the current for the LED output. Default is 10" + }, + "red": { + "label": "Červená", + "description": "Sets the red LED level. Values are 0-255" + }, + "green": { + "label": "Zelená", + "description": "Sets the green LED level. Values are 0-255" + }, + "blue": { + "label": "Modrá", + "description": "Sets the blue LED level. Values are 0-255" + } + }, + "audio": { + "title": "Audio Settings", + "description": "Settings for the Audio module", + "codec2Enabled": { + "label": "Codec 2 Enabled", + "description": "Enable Codec 2 audio encoding" + }, + "pttPin": { + "label": "PTT Pin", + "description": "GPIO pin to use for PTT" + }, + "bitrate": { + "label": "Bitrate", + "description": "Bitrate to use for audio encoding" + }, + "i2sWs": { + "label": "i2S WS", + "description": "GPIO pin to use for i2S WS" + }, + "i2sSd": { + "label": "i2S SD", + "description": "GPIO pin to use for i2S SD" + }, + "i2sDin": { + "label": "i2S DIN", + "description": "GPIO pin to use for i2S DIN" + }, + "i2sSck": { + "label": "i2S SCK", + "description": "GPIO pin to use for i2S SCK" + } + }, + "cannedMessage": { + "title": "Canned Message Settings", + "description": "Settings for the Canned Message module", + "moduleEnabled": { + "label": "Module Enabled", + "description": "Enable Canned Message" + }, + "rotary1Enabled": { + "label": "Rotary Encoder #1 Enabled", + "description": "Enable the rotary encoder" + }, + "inputbrokerPinA": { + "label": "Encoder Pin A", + "description": "GPIO Pin Value (1-39) For encoder port A" + }, + "inputbrokerPinB": { + "label": "Encoder Pin B", + "description": "GPIO Pin Value (1-39) For encoder port B" + }, + "inputbrokerPinPress": { + "label": "Encoder Pin Press", + "description": "GPIO Pin Value (1-39) For encoder Press" + }, + "inputbrokerEventCw": { + "label": "Clockwise event", + "description": "Select input event." + }, + "inputbrokerEventCcw": { + "label": "Counter Clockwise event", + "description": "Select input event." + }, + "inputbrokerEventPress": { + "label": "Press event", + "description": "Select input event" + }, + "updown1Enabled": { + "label": "Up Down enabled", + "description": "Enable the up / down encoder" + }, + "allowInputSource": { + "label": "Allow Input Source", + "description": "Select from: '_any', 'rotEnc1', 'upDownEnc1', 'cardkb'" + }, + "sendBell": { + "label": "Send Bell", + "description": "Sends a bell character with each message" + } + }, + "detectionSensor": { + "title": "Detection Sensor Settings", + "description": "Settings for the Detection Sensor module", + "enabled": { + "label": "Povoleno", + "description": "Enable or disable Detection Sensor Module" + }, + "minimumBroadcastSecs": { + "label": "Minimum Broadcast Seconds", + "description": "The interval in seconds of how often we can send a message to the mesh when a state change is detected" + }, + "stateBroadcastSecs": { + "label": "State Broadcast Seconds", + "description": "The interval in seconds of how often we should send a message to the mesh with the current state regardless of changes" + }, + "sendBell": { + "label": "Send Bell", + "description": "Send ASCII bell with alert message" + }, + "name": { + "label": "Friendly Name", + "description": "Used to format the message sent to mesh, max 20 Characters" + }, + "monitorPin": { + "label": "Monitor Pin", + "description": "The GPIO pin to monitor for state changes" + }, + "detectionTriggerType": { + "label": "Detection Triggered Type", + "description": "The type of trigger event to be used" + }, + "usePullup": { + "label": "Use Pullup", + "description": "Whether or not use INPUT_PULLUP mode for GPIO pin" + } + }, + "externalNotification": { + "title": "External Notification Settings", + "description": "Configure the external notification module", + "enabled": { + "label": "Module Enabled", + "description": "Enable External Notification" + }, + "outputMs": { + "label": "Output MS", + "description": "Output MS" + }, + "output": { + "label": "Output", + "description": "Output" + }, + "outputVibra": { + "label": "Output Vibrate", + "description": "Output Vibrate" + }, + "outputBuzzer": { + "label": "Output Buzzer", + "description": "Output Buzzer" + }, + "active": { + "label": "Active", + "description": "Active" + }, + "alertMessage": { + "label": "Alert Message", + "description": "Alert Message" + }, + "alertMessageVibra": { + "label": "Alert Message Vibrate", + "description": "Alert Message Vibrate" + }, + "alertMessageBuzzer": { + "label": "Alert Message Buzzer", + "description": "Alert Message Buzzer" + }, + "alertBell": { + "label": "Alert Bell", + "description": "Should an alert be triggered when receiving an incoming bell?" + }, + "alertBellVibra": { + "label": "Alert Bell Vibrate", + "description": "Alert Bell Vibrate" + }, + "alertBellBuzzer": { + "label": "Alert Bell Buzzer", + "description": "Alert Bell Buzzer" + }, + "usePwm": { + "label": "Use PWM", + "description": "Use PWM" + }, + "nagTimeout": { + "label": "Nag Timeout", + "description": "Nag Timeout" + }, + "useI2sAsBuzzer": { + "label": "Use I²S Pin as Buzzer", + "description": "Designate I²S Pin as Buzzer Output" + } + }, + "mqtt": { + "title": "MQTT Settings", + "description": "Settings for the MQTT module", + "enabled": { + "label": "Povoleno", + "description": "Enable or disable MQTT" + }, + "address": { + "label": "MQTT Server Address", + "description": "MQTT server address to use for default/custom servers" + }, + "username": { + "label": "MQTT Username", + "description": "MQTT username to use for default/custom servers" + }, + "password": { + "label": "MQTT Password", + "description": "MQTT password to use for default/custom servers" + }, + "encryptionEnabled": { + "label": "Encryption Enabled", + "description": "Enable or disable MQTT encryption. Note: All messages are sent to the MQTT broker unencrypted if this option is not enabled, even when your uplink channels have encryption keys set. This includes position data." + }, + "jsonEnabled": { + "label": "JSON Enabled", + "description": "Whether to send/consume JSON packets on MQTT" + }, + "tlsEnabled": { + "label": "TLS povoleno", + "description": "Enable or disable TLS" + }, + "root": { + "label": "Kořenové téma", + "description": "MQTT root topic to use for default/custom servers" + }, + "proxyToClientEnabled": { + "label": "MQTT Client Proxy Enabled", + "description": "Utilizes the network connection to proxy MQTT messages to the client." + }, + "mapReportingEnabled": { + "label": "Map Reporting Enabled", + "description": "Your node will periodically send an unencrypted map report packet to the configured MQTT server, this includes id, short and long name, approximate location, hardware model, role, firmware version, LoRa region, modem preset and primary channel name." + }, + "mapReportSettings": { + "publishIntervalSecs": { + "label": "Map Report Publish Interval (s)", + "description": "Interval in seconds to publish map reports" + }, + "positionPrecision": { + "label": "Approximate Location", + "description": "Position shared will be accurate within this distance", + "options": { + "metric_km23": "Within 23 km", + "metric_km12": "Within 12 km", + "metric_km5_8": "Within 5.8 km", + "metric_km2_9": "Within 2.9 km", + "metric_km1_5": "Within 1.5 km", + "metric_m700": "Within 700 m", + "metric_m350": "Within 350 m", + "metric_m200": "Within 200 m", + "metric_m90": "Within 90 m", + "metric_m50": "Within 50 m", + "imperial_mi15": "Within 15 miles", + "imperial_mi7_3": "Within 7.3 miles", + "imperial_mi3_6": "Within 3.6 miles", + "imperial_mi1_8": "Within 1.8 miles", + "imperial_mi0_9": "Within 0.9 miles", + "imperial_mi0_5": "Within 0.5 miles", + "imperial_mi0_2": "Within 0.2 miles", + "imperial_ft600": "Within 600 feet", + "imperial_ft300": "Within 300 feet", + "imperial_ft150": "Within 150 feet" + } + } + } + }, + "neighborInfo": { + "title": "Neighbor Info Settings", + "description": "Settings for the Neighbor Info module", + "enabled": { + "label": "Povoleno", + "description": "Enable or disable Neighbor Info Module" + }, + "updateInterval": { + "label": "Update Interval", + "description": "Interval in seconds of how often we should try to send our Neighbor Info to the mesh" + } + }, + "paxcounter": { + "title": "Paxcounter Settings", + "description": "Settings for the Paxcounter module", + "enabled": { + "label": "Module Enabled", + "description": "Enable Paxcounter" + }, + "paxcounterUpdateInterval": { + "label": "Update Interval (seconds)", + "description": "How long to wait between sending paxcounter packets" + }, + "wifiThreshold": { + "label": "WiFi RSSI Threshold", + "description": "At what WiFi RSSI level should the counter increase. Defaults to -80." + }, + "bleThreshold": { + "label": "BLE RSSI Threshold", + "description": "At what BLE RSSI level should the counter increase. Defaults to -80." + } + }, + "rangeTest": { + "title": "Range Test Settings", + "description": "Settings for the Range Test module", + "enabled": { + "label": "Module Enabled", + "description": "Enable Range Test" + }, + "sender": { + "label": "Message Interval", + "description": "How long to wait between sending test packets" + }, + "save": { + "label": "Save CSV to storage", + "description": "ESP32 Only" + } + }, + "serial": { + "title": "Serial Settings", + "description": "Settings for the Serial module", + "enabled": { + "label": "Module Enabled", + "description": "Enable Serial output" + }, + "echo": { + "label": "Echo", + "description": "Any packets you send will be echoed back to your device" + }, + "rxd": { + "label": "Receive Pin", + "description": "Set the GPIO pin to the RXD pin you have set up." + }, + "txd": { + "label": "Transmit Pin", + "description": "Set the GPIO pin to the TXD pin you have set up." + }, + "baud": { + "label": "Baud Rate", + "description": "The serial baud rate" + }, + "timeout": { + "label": "Vypršel čas spojení", + "description": "Seconds to wait before we consider your packet as 'done'" + }, + "mode": { + "label": "Mode", + "description": "Select Mode" + }, + "overrideConsoleSerialPort": { + "label": "Override Console Serial Port", + "description": "If you have a serial port connected to the console, this will override it." + } + }, + "storeForward": { + "title": "Store & Forward Settings", + "description": "Settings for the Store & Forward module", + "enabled": { + "label": "Module Enabled", + "description": "Enable Store & Forward" + }, + "heartbeat": { + "label": "Heartbeat Enabled", + "description": "Enable Store & Forward heartbeat" + }, + "records": { + "label": "Počet záznamů", + "description": "Number of records to store" + }, + "historyReturnMax": { + "label": "History return max", + "description": "Max number of records to return" + }, + "historyReturnWindow": { + "label": "History return window", + "description": "Return records from this time window (minutes)" + } + }, + "telemetry": { + "title": "Telemetry Settings", + "description": "Settings for the Telemetry module", + "deviceUpdateInterval": { + "label": "Device Metrics", + "description": "Interval aktualizace metrik zařízení (v sekundách)" + }, + "environmentUpdateInterval": { + "label": "Interval aktualizace metrik životního prostředí (v sekundách)", + "description": "" + }, + "environmentMeasurementEnabled": { + "label": "Module Enabled", + "description": "Enable the Environment Telemetry" + }, + "environmentScreenEnabled": { + "label": "Displayed on Screen", + "description": "Show the Telemetry Module on the OLED" + }, + "environmentDisplayFahrenheit": { + "label": "Display Fahrenheit", + "description": "Display temp in Fahrenheit" + }, + "airQualityEnabled": { + "label": "Air Quality Enabled", + "description": "Enable the Air Quality Telemetry" + }, + "airQualityInterval": { + "label": "Air Quality Update Interval", + "description": "How often to send Air Quality data over the mesh" + }, + "powerMeasurementEnabled": { + "label": "Power Measurement Enabled", + "description": "Enable the Power Measurement Telemetry" + }, + "powerUpdateInterval": { + "label": "Power Update Interval", + "description": "How often to send Power data over the mesh" + }, + "powerScreenEnabled": { + "label": "Power Screen Enabled", + "description": "Enable the Power Telemetry Screen" + } + } } diff --git a/packages/web/public/i18n/locales/cs-CZ/nodes.json b/packages/web/public/i18n/locales/cs-CZ/nodes.json index 53a6d1d2c..09c13ef67 100644 --- a/packages/web/public/i18n/locales/cs-CZ/nodes.json +++ b/packages/web/public/i18n/locales/cs-CZ/nodes.json @@ -1,63 +1,59 @@ { - "nodeDetail": { - "publicKeyEnabled": { - "label": "Public Key Enabled" - }, - "noPublicKey": { - "label": "No Public Key" - }, - "directMessage": { - "label": "Direct Message {{shortName}}" - }, - "favorite": { - "label": "Oblíbené", - "tooltip": "Add or remove this node from your favorites" - }, - "notFavorite": { - "label": "Not a Favorite" - }, - "error": { - "label": "Chyba", - "text": "An error occurred while fetching node details. Please try again later." - }, - "status": { - "heard": "Heard", - "mqtt": "MQTT" - }, - "elevation": { - "label": "Elevation" - }, - "channelUtil": { - "label": "Channel Util" - }, - "airtimeUtil": { - "label": "Airtime Util" - } - }, - "nodesTable": { - "headings": { - "longName": "Long Name", - "connection": "Connection", - "lastHeard": "Last Heard", - "encryption": "Encryption", - "model": "Model", - "macAddress": "MAC Address" - }, - "connectionStatus": { - "direct": "Přímý", - "away": "away", - "unknown": "-", - "viaMqtt": ", via MQTT" - }, - "lastHeardStatus": { - "never": "Never" - } - }, - "actions": { - "added": "Added", - "removed": "Removed", - "ignoreNode": "Ignore Node", - "unignoreNode": "Unignore Node", - "requestPosition": "Request Position" - } + "nodeDetail": { + "publicKeyEnabled": { + "label": "Public Key Enabled" + }, + "noPublicKey": { + "label": "No Public Key" + }, + "directMessage": { + "label": "Direct Message {{shortName}}" + }, + "favorite": { + "label": "Oblíbené", + "tooltip": "Add or remove this node from your favorites" + }, + "notFavorite": { + "label": "Not a Favorite" + }, + "error": { + "label": "Chyba", + "text": "An error occurred while fetching node details. Please try again later." + }, + "status": { + "heard": "Heard", + "mqtt": "MQTT" + }, + "elevation": { + "label": "Elevation" + }, + "channelUtil": { + "label": "Channel Util" + }, + "airtimeUtil": { + "label": "Airtime Util" + } + }, + "nodesTable": { + "headings": { + "longName": "Long Name", + "connection": "Connection", + "lastHeard": "Last Heard", + "encryption": "Encryption", + "model": "Model", + "macAddress": "MAC Address" + }, + "connectionStatus": { + "direct": "Přímý", + "away": "away", + "viaMqtt": ", via MQTT" + } + }, + "actions": { + "added": "Added", + "removed": "Removed", + "ignoreNode": "Ignore Node", + "unignoreNode": "Unignore Node", + "requestPosition": "Request Position" + } } diff --git a/packages/web/public/i18n/locales/cs-CZ/ui.json b/packages/web/public/i18n/locales/cs-CZ/ui.json index 6386e4eef..bc4862d89 100644 --- a/packages/web/public/i18n/locales/cs-CZ/ui.json +++ b/packages/web/public/i18n/locales/cs-CZ/ui.json @@ -1,228 +1,230 @@ { - "navigation": { - "title": "Navigation", - "messages": "Zprávy", - "map": "Mapa", - "config": "Config", - "radioConfig": "Radio Config", - "moduleConfig": "Module Config", - "channels": "Kanály", - "nodes": "Uzly" - }, - "app": { - "title": "Meshtastic", - "logo": "Meshtastic Logo" - }, - "sidebar": { - "collapseToggle": { - "button": { - "open": "Open sidebar", - "close": "Close sidebar" - } - }, - "deviceInfo": { - "volts": "{{voltage}} volts", - "firmware": { - "title": "Firmware", - "version": "v{{version}}", - "buildDate": "Build date: {{date}}" - }, - "deviceName": { - "title": "Device Name", - "changeName": "Change Device Name", - "placeholder": "Enter device name" - }, - "editDeviceName": "Edit device name" - } - }, - "batteryStatus": { - "charging": "{{level}}% charging", - "pluggedIn": "Plugged in", - "title": "Baterie" - }, - "search": { - "nodes": "Search nodes...", - "channels": "Search channels...", - "commandPalette": "Search commands..." - }, - "toast": { - "positionRequestSent": { - "title": "Position request sent." - }, - "requestingPosition": { - "title": "Requesting position, please wait..." - }, - "sendingTraceroute": { - "title": "Sending Traceroute, please wait..." - }, - "tracerouteSent": { - "title": "Traceroute sent." - }, - "savedChannel": { - "title": "Saved Channel: {{channelName}}" - }, - "messages": { - "pkiEncryption": { - "title": "Chat is using PKI encryption." - }, - "pskEncryption": { - "title": "Chat is using PSK encryption." - } - }, - "configSaveError": { - "title": "Error Saving Config", - "description": "An error occurred while saving the configuration." - }, - "validationError": { - "title": "Config Errors Exist", - "description": "Please fix the configuration errors before saving." - }, - "saveSuccess": { - "title": "Saving Config", - "description": "The configuration change {{case}} has been saved." - }, - "favoriteNode": { - "title": "{{action}} {{nodeName}} {{direction}} favorites.", - "action": { - "added": "Added", - "removed": "Removed", - "to": "to", - "from": "from" - } - }, - "ignoreNode": { - "title": "{{action}} {{nodeName}} {{direction}} ignore list", - "action": { - "added": "Added", - "removed": "Removed", - "to": "to", - "from": "from" - } - } - }, - "notifications": { - "copied": { - "label": "Copied!" - }, - "copyToClipboard": { - "label": "Copy to clipboard" - }, - "hidePassword": { - "label": "Skrýt heslo" - }, - "showPassword": { - "label": "Zobrazit heslo" - }, - "deliveryStatus": { - "delivered": "Delivered", - "failed": "Delivery Failed", - "waiting": "Waiting", - "unknown": "Unknown" - } - }, - "general": { - "label": "General" - }, - "hardware": { - "label": "Hardware" - }, - "metrics": { - "label": "Metriky" - }, - "role": { - "label": "Role" - }, - "filter": { - "label": "Filtr" - }, - "advanced": { - "label": "Advanced" - }, - "clearInput": { - "label": "Clear input" - }, - "resetFilters": { - "label": "Reset Filters" - }, - "nodeName": { - "label": "Node name/number", - "placeholder": "Meshtastic 1234" - }, - "airtimeUtilization": { - "label": "Airtime Utilization (%)" - }, - "batteryLevel": { - "label": "Battery level (%)", - "labelText": "Battery level (%): {{value}}" - }, - "batteryVoltage": { - "label": "Battery voltage (V)", - "title": "Napětí" - }, - "channelUtilization": { - "label": "Channel Utilization (%)" - }, - "hops": { - "direct": "Přímý", - "label": "Number of hops", - "text": "Number of hops: {{value}}" - }, - "lastHeard": { - "label": "Naposledy slyšen", - "labelText": "Last heard: {{value}}", - "nowLabel": "Now" - }, - "snr": { - "label": "SNR (db)" - }, - "favorites": { - "label": "Favorites" - }, - "hide": { - "label": "Hide" - }, - "showOnly": { - "label": "Show Only" - }, - "viaMqtt": { - "label": "Connected via MQTT" - }, - "hopsUnknown": { - "label": "Unknown number of hops" - }, - "showUnheard": { - "label": "Never heard" - }, - "language": { - "label": "Jazyk", - "changeLanguage": "Change Language" - }, - "theme": { - "dark": "Tmavý", - "light": "Světlý", - "system": "Automatic", - "changeTheme": "Change Color Scheme" - }, - "errorPage": { - "title": "This is a little embarrassing...", - "description1": "We are really sorry but an error occurred in the web client that caused it to crash.
This is not supposed to happen, and we are working hard to fix it.", - "description2": "The best way to prevent this from happening again to you or anyone else is to report the issue to us.", - "reportInstructions": "Please include the following information in your report:", - "reportSteps": { - "step1": "What you were doing when the error occurred", - "step2": "What you expected to happen", - "step3": "What actually happened", - "step4": "Any other relevant information" - }, - "reportLink": "You can report the issue to our <0>GitHub", - "dashboardLink": "Return to the <0>dashboard", - "detailsSummary": "Error Details", - "errorMessageLabel": "Error message:", - "stackTraceLabel": "Stack trace:", - "fallbackError": "{{error}}" - }, - "footer": { - "text": "Powered by <0>▲ Vercel | Meshtastic® is a registered trademark of Meshtastic LLC. | <1>Legal Information", - "commitSha": "Commit SHA: {{sha}}" - } + "navigation": { + "title": "Navigation", + "messages": "Zprávy", + "map": "Mapa", + "settings": "Nastavení", + "channels": "Kanály", + "radioConfig": "Radio Config", + "deviceConfig": "Nastavení zařízení", + "moduleConfig": "Module Config", + "manageConnections": "Manage Connections", + "nodes": "Uzly" + }, + "app": { + "title": "Meshtastic", + "logo": "Meshtastic Logo" + }, + "sidebar": { + "collapseToggle": { + "button": { + "open": "Open sidebar", + "close": "Close sidebar" + } + }, + "deviceInfo": { + "volts": "{{voltage}} volts", + "firmware": { + "title": "Firmware", + "version": "v{{version}}", + "buildDate": "Build date: {{date}}" + } + } + }, + "batteryStatus": { + "charging": "{{level}}% charging", + "pluggedIn": "Plugged in", + "title": "Baterie" + }, + "search": { + "nodes": "Search nodes...", + "channels": "Search channels...", + "commandPalette": "Search commands..." + }, + "toast": { + "positionRequestSent": { + "title": "Position request sent." + }, + "requestingPosition": { + "title": "Requesting position, please wait..." + }, + "sendingTraceroute": { + "title": "Sending Traceroute, please wait..." + }, + "tracerouteSent": { + "title": "Traceroute sent." + }, + "savedChannel": { + "title": "Saved Channel: {{channelName}}" + }, + "messages": { + "pkiEncryption": { + "title": "Chat is using PKI encryption." + }, + "pskEncryption": { + "title": "Chat is using PSK encryption." + } + }, + "configSaveError": { + "title": "Error Saving Config", + "description": "An error occurred while saving the configuration." + }, + "validationError": { + "title": "Config Errors Exist", + "description": "Please fix the configuration errors before saving." + }, + "saveSuccess": { + "title": "Saving Config", + "description": "The configuration change {{case}} has been saved." + }, + "saveAllSuccess": { + "title": "Saved", + "description": "All configuration changes have been saved." + }, + "favoriteNode": { + "title": "{{action}} {{nodeName}} {{direction}} favorites.", + "action": { + "added": "Added", + "removed": "Removed", + "to": "to", + "from": "from" + } + }, + "ignoreNode": { + "title": "{{action}} {{nodeName}} {{direction}} ignore list", + "action": { + "added": "Added", + "removed": "Removed", + "to": "to", + "from": "from" + } + } + }, + "notifications": { + "copied": { + "label": "Copied!" + }, + "copyToClipboard": { + "label": "Copy to clipboard" + }, + "hidePassword": { + "label": "Skrýt heslo" + }, + "showPassword": { + "label": "Zobrazit heslo" + }, + "deliveryStatus": { + "delivered": "Delivered", + "failed": "Delivery Failed", + "waiting": "Waiting", + "unknown": "Unknown" + } + }, + "general": { + "label": "General" + }, + "hardware": { + "label": "Hardware" + }, + "metrics": { + "label": "Metriky" + }, + "role": { + "label": "Role" + }, + "filter": { + "label": "Filtr" + }, + "advanced": { + "label": "Advanced" + }, + "clearInput": { + "label": "Clear input" + }, + "resetFilters": { + "label": "Reset Filters" + }, + "nodeName": { + "label": "Node name/number", + "placeholder": "Meshtastic 1234" + }, + "airtimeUtilization": { + "label": "Airtime Utilization (%)", + "short": "Airtime Util. (%)" + }, + "batteryLevel": { + "label": "Battery level (%)", + "labelText": "Battery level (%): {{value}}" + }, + "batteryVoltage": { + "label": "Battery voltage (V)", + "title": "Napětí" + }, + "channelUtilization": { + "label": "Channel Utilization (%)", + "short": "Channel Util. (%)" + }, + "hops": { + "direct": "Přímý", + "label": "Number of hops", + "text": "Number of hops: {{value}}" + }, + "lastHeard": { + "label": "Naposledy slyšen", + "labelText": "Last heard: {{value}}", + "nowLabel": "Now" + }, + "snr": { + "label": "SNR (db)" + }, + "favorites": { + "label": "Favorites" + }, + "hide": { + "label": "Hide" + }, + "showOnly": { + "label": "Show Only" + }, + "viaMqtt": { + "label": "Connected via MQTT" + }, + "hopsUnknown": { + "label": "Unknown number of hops" + }, + "showUnheard": { + "label": "Never heard" + }, + "language": { + "label": "Jazyk", + "changeLanguage": "Change Language" + }, + "theme": { + "dark": "Tmavý", + "light": "Světlý", + "system": "Automatic", + "changeTheme": "Change Color Scheme" + }, + "errorPage": { + "title": "This is a little embarrassing...", + "description1": "We are really sorry but an error occurred in the web client that caused it to crash.
This is not supposed to happen, and we are working hard to fix it.", + "description2": "The best way to prevent this from happening again to you or anyone else is to report the issue to us.", + "reportInstructions": "Please include the following information in your report:", + "reportSteps": { + "step1": "What you were doing when the error occurred", + "step2": "What you expected to happen", + "step3": "What actually happened", + "step4": "Any other relevant information" + }, + "reportLink": "You can report the issue to our <0>GitHub", + "connectionsLink": "Return to the <0>connections", + "detailsSummary": "Error Details", + "errorMessageLabel": "Error message:", + "stackTraceLabel": "Stack trace:", + "fallbackError": "{{error}}" + }, + "footer": { + "text": "Powered by <0>▲ Vercel | Meshtastic® is a registered trademark of Meshtastic LLC. | <1>Legal Information", + "commitSha": "Commit SHA: {{sha}}" + } } diff --git a/packages/web/public/i18n/locales/de-DE/channels.json b/packages/web/public/i18n/locales/de-DE/channels.json index 170b23a56..1e664d7fd 100644 --- a/packages/web/public/i18n/locales/de-DE/channels.json +++ b/packages/web/public/i18n/locales/de-DE/channels.json @@ -1,69 +1,71 @@ { - "page": { - "sectionLabel": "Kanäle", - "channelName": "Kanal {{channelName}}", - "broadcastLabel": "Primär", - "channelIndex": "Kanal {{index}}" - }, - "validation": { - "pskInvalid": "Bitte geben Sie einen gültigen {{bits}} Bit PSK Schlüssel ein." - }, - "settings": { - "label": "Kanaleinstellungen", - "description": "Verschlüsselung, MQTT & sonstige Einstellungen" - }, - "role": { - "label": "Rolle", - "description": "Gerätetelemetrie wird über den PRIMÄR Kanal gesendet. Nur ein PRIMÄR Kanal ist erlaubt.", - "options": { - "primary": "PRIMÄR", - "disabled": "DEAKTIVIERT", - "secondary": "SEKUNDÄR" - } - }, - "psk": { - "label": "Vorher verteilter Schlüssel", - "description": "Unterstützte PSK-Längen: 256-Bit, 128-Bit, 8-Bit, leer (0-Bit)", - "generate": "Erzeugen" - }, - "name": { - "label": "Name", - "description": "Ein eindeutiger Name für den Kanal <12 Bytes. Leer lassen für Standard." - }, - "uplinkEnabled": { - "label": "Uplink aktiviert", - "description": "Nachrichten vom lokalen Netz über MQTT versenden" - }, - "downlinkEnabled": { - "label": "Downlink aktiviert", - "description": "Nachrichten von MQTT im lokalen Netz versenden" - }, - "positionPrecision": { - "label": "Standort", - "description": "Die Genauigkeit des Standorts, die in diesem Kanal geteilt werden soll. Kann deaktiviert werden.", - "options": { - "none": "Standort nicht freigeben", - "precise": "Genauer Standort", - "metric_km23": "Innerhalb von 23 Kilometern", - "metric_km12": "Innerhalb von 12 Kilometern", - "metric_km5_8": "Innerhalb von 5,8 Kilometern", - "metric_km2_9": "Innerhalb von 2,9 Kilometern", - "metric_km1_5": "Innerhalb von 1,5 Kilometern", - "metric_m700": "Innerhalb von 700 Metern", - "metric_m350": "Innerhalb von 350 Metern", - "metric_m200": "Innerhalb von 200 Metern", - "metric_m90": "Innerhalb von 90 Metern", - "metric_m50": "Innerhalb von 50 Metern", - "imperial_mi15": "Innerhalb von 15 Meilen", - "imperial_mi7_3": "Innerhalb von 7,3 Meilen", - "imperial_mi3_6": "Innerhalb von 3,6 Meilen", - "imperial_mi1_8": "Innerhalb von 1,8 Meilen", - "imperial_mi0_9": "Innerhalb von 0,9 Meilen", - "imperial_mi0_5": "Innerhalb von 0,5 Meilen", - "imperial_mi0_2": "Innerhalb von 0,2 Meilen", - "imperial_ft600": "Innerhalb von 600 Fuß", - "imperial_ft300": "Innerhalb von 300 Fuß", - "imperial_ft150": "Innerhalb von 150 Fuß" - } - } + "page": { + "sectionLabel": "Kanäle", + "channelName": "Kanal {{channelName}}", + "broadcastLabel": "Primär", + "channelIndex": "Kanal {{index}}", + "import": "Importieren", + "export": "Exportieren" + }, + "validation": { + "pskInvalid": "Bitte geben Sie einen gültigen {{bits}} Bit PSK Schlüssel ein." + }, + "settings": { + "label": "Kanaleinstellungen", + "description": "Verschlüsselung, MQTT & sonstige Einstellungen" + }, + "role": { + "label": "Rolle", + "description": "Gerätetelemetrie wird über den PRIMÄR Kanal gesendet. Nur ein PRIMÄR Kanal ist erlaubt.", + "options": { + "primary": "PRIMÄR", + "disabled": "DEAKTIVIERT", + "secondary": "SEKUNDÄR" + } + }, + "psk": { + "label": "Vorher verteilter Schlüssel", + "description": "Unterstützte PSK-Längen: 256-Bit, 128-Bit, 8-Bit, leer (0-Bit)", + "generate": "Erzeugen" + }, + "name": { + "label": "Name", + "description": "Ein eindeutiger Name für den Kanal <12 Bytes. Leer lassen für Standard." + }, + "uplinkEnabled": { + "label": "Uplink aktiviert", + "description": "Nachrichten vom lokalen Netz über MQTT versenden" + }, + "downlinkEnabled": { + "label": "Downlink aktiviert", + "description": "Nachrichten von MQTT im lokalen Netz versenden" + }, + "positionPrecision": { + "label": "Standort", + "description": "Die Genauigkeit des Standorts, die in diesem Kanal geteilt werden soll. Kann deaktiviert werden.", + "options": { + "none": "Standort nicht freigeben", + "precise": "Genauer Standort", + "metric_km23": "Innerhalb von 23 Kilometern", + "metric_km12": "Innerhalb von 12 Kilometern", + "metric_km5_8": "Innerhalb von 5,8 Kilometern", + "metric_km2_9": "Innerhalb von 2,9 Kilometern", + "metric_km1_5": "Innerhalb von 1,5 Kilometern", + "metric_m700": "Innerhalb von 700 Metern", + "metric_m350": "Innerhalb von 350 Metern", + "metric_m200": "Innerhalb von 200 Metern", + "metric_m90": "Innerhalb von 90 Metern", + "metric_m50": "Innerhalb von 50 Metern", + "imperial_mi15": "Innerhalb von 15 Meilen", + "imperial_mi7_3": "Innerhalb von 7,3 Meilen", + "imperial_mi3_6": "Innerhalb von 3,6 Meilen", + "imperial_mi1_8": "Innerhalb von 1,8 Meilen", + "imperial_mi0_9": "Innerhalb von 0,9 Meilen", + "imperial_mi0_5": "Innerhalb von 0,5 Meilen", + "imperial_mi0_2": "Innerhalb von 0,2 Meilen", + "imperial_ft600": "Innerhalb von 600 Fuß", + "imperial_ft300": "Innerhalb von 300 Fuß", + "imperial_ft150": "Innerhalb von 150 Fuß" + } + } } diff --git a/packages/web/public/i18n/locales/de-DE/commandPalette.json b/packages/web/public/i18n/locales/de-DE/commandPalette.json index 637a01b3e..ecc93c48e 100644 --- a/packages/web/public/i18n/locales/de-DE/commandPalette.json +++ b/packages/web/public/i18n/locales/de-DE/commandPalette.json @@ -15,7 +15,6 @@ "messages": "Nachrichten", "map": "Karte", "config": "Einstellungen", - "channels": "Kanäle", "nodes": "Knoten" } }, @@ -45,7 +44,8 @@ "label": "Debug", "command": { "reconfigure": "Neu einrichten", - "clearAllStoredMessages": "Alle gespeicherten Nachrichten löschen" + "clearAllStoredMessages": "Alle gespeicherten Nachrichten löschen", + "clearAllStores": "Lösche den gesamten lokalen Speicher" } } } diff --git a/packages/web/public/i18n/locales/de-DE/common.json b/packages/web/public/i18n/locales/de-DE/common.json index 272f56522..746eb87e2 100644 --- a/packages/web/public/i18n/locales/de-DE/common.json +++ b/packages/web/public/i18n/locales/de-DE/common.json @@ -1,142 +1,165 @@ { - "button": { - "apply": "Anwenden", - "backupKey": "Schlüssel sichern", - "cancel": "Abbrechen", - "clearMessages": "Nachrichten löschen", - "close": "Schließen", - "confirm": "Bestätigen", - "delete": "Löschen", - "dismiss": "Tastatur ausblenden", - "download": "Herunterladen", - "export": "Exportieren", - "generate": "Erzeugen", - "regenerate": "Neu erzeugen", - "import": "Importieren", - "message": "Nachricht", - "now": "Jetzt", - "ok": "Ok", - "print": "Drucken", - "remove": "Entfernen", - "requestNewKeys": "Neue Schlüssel anfordern", - "requestPosition": "Standort anfordern", - "reset": "Zurücksetzen", - "save": "Speichern", - "scanQr": "QR Code scannen", - "traceRoute": "Route verfolgen", - "submit": "Absenden" - }, - "app": { - "title": "Meshtastic", - "fullTitle": "Meshtastic Web-Applikation" - }, - "loading": "Wird geladen...", - "unit": { - "cps": "CPS", - "dbm": "dBm", - "hertz": "Hz", - "hop": { - "one": "Sprung", - "plural": "Sprünge" - }, - "hopsAway": { - "one": "{{count}} Sprung entfernt", - "plural": "{{count}} Sprünge entfernt", - "unknown": "Sprungweite unbekannt" - }, - "megahertz": "MHz", - "raw": "Einheitslos", - "meter": { - "one": "Meter", - "plural": "Meter", - "suffix": "m" - }, - "minute": { - "one": "Minute", - "plural": "Minuten" - }, - "hour": { - "one": "Stunde", - "plural": "Stunden" - }, - "millisecond": { - "one": "Millisekunde", - "plural": "Millisekunden", - "suffix": "ms" - }, - "second": { - "one": "Sekunde", - "plural": "Sekunden" - }, - "day": { - "one": "Tag", - "plural": "Tage" - }, - "month": { - "one": "Monat", - "plural": "Monate" - }, - "year": { - "one": "Jahr", - "plural": "Jahre" - }, - "snr": "SNR", - "volt": { - "one": "Volt", - "plural": "Volt", - "suffix": "V" - }, - "record": { - "one": "Datensatz", - "plural": "Datensätze" - } - }, - "security": { - "0bit": "Leer", - "8bit": "8 Bit", - "128bit": "128 Bit", - "256bit": "256 Bit" - }, - "unknown": { - "longName": "Unbekannt", - "shortName": "UNB", - "notAvailable": "Keine Angaben", - "num": "???" - }, - "nodeUnknownPrefix": "!", - "unset": "NICHT GESETZT", - "fallbackName": "Meshtastic {{last4}}", - "node": "Knoten", - "formValidation": { - "unsavedChanges": "Ungespeicherte Änderungen", - "tooBig": { - "string": "Zu lang, erwarte maximal {{maximum}} Zeichen.", - "number": "Zu groß, erwartete eine Zahl kleiner oder gleich {{maximum}}.", - "bytes": "Zu groß, erwarte maximal {{params.maximum}} Bytes." - }, - "tooSmall": { - "string": "Zu kurz, erwartete mindestens {{minimum}} Zeichen.", - "number": "Zu klein, erwartete eine Zahl größer oder gleich {{minimum}}." - }, - "invalidFormat": { - "ipv4": "Ungültiges Format, erwartete eine IPv4 Adresse.", - "key": "Ungültiges Format, erwartet einen Base64-kodierten vor verteilten Schlüssel (PSK)." - }, - "invalidType": { - "number": "Ungültiger Typ, erwartete eine Zahl." - }, - "pskLength": { - "0bit": "Der Schlüssel muss leer sein.", - "8bit": "Der administrative Schlüssel muss ein vor verteilter 8 Bit Schlüssel (PSK) sein.", - "128bit": "Der administrative Schlüssel muss ein vor verteilter 128 Bit Schlüssel (PSK) sein.", - "256bit": "Der administrative Schlüssel muss ein vor verteilter 256 Bit Schlüssel (PSK) sein." - }, - "required": { - "generic": "Dies ist ein Pflichtfeld.", - "managed": "Mindestens ein administrativer Schlüssel wird benötigt, um diesen Knoten zu verwalten", - "key": "Schlüssel erforderlich." - } - }, - "yes": "Ja", - "no": "Nein" + "button": { + "apply": "Anwenden", + "addConnection": "Verbindung hinzufügen", + "saveConnection": "Verbindung speichern", + "backupKey": "Schlüssel sichern", + "cancel": "Abbrechen", + "connect": "Verbindung herstellen", + "clearMessages": "Nachrichten löschen", + "close": "Schließen", + "confirm": "Bestätigen", + "delete": "Löschen", + "dismiss": "Tastatur ausblenden", + "download": "Herunterladen", + "disconnect": "Verbindung trennen", + "export": "Exportieren", + "generate": "Erzeugen", + "regenerate": "Neu erzeugen", + "import": "Importieren", + "message": "Nachricht", + "now": "Jetzt", + "ok": "Ok", + "print": "Drucken", + "remove": "Entfernen", + "requestNewKeys": "Neue Schlüssel anfordern", + "requestPosition": "Standort anfordern", + "reset": "Zurücksetzen", + "retry": "Erneut versuchen", + "save": "Speichern", + "setDefault": "Als Standard festlegen", + "unsetDefault": "Standard entfernen", + "scanQr": "QR Code scannen", + "traceRoute": "Route verfolgen", + "submit": "Absenden" + }, + "app": { + "title": "Meshtastic", + "fullTitle": "Meshtastic Web-Applikation" + }, + "loading": "Wird geladen...", + "unit": { + "cps": "CPS", + "dbm": "dBm", + "hertz": "Hz", + "hop": { + "one": "Sprung", + "plural": "Sprünge" + }, + "hopsAway": { + "one": "{{count}} Sprung entfernt", + "plural": "{{count}} Sprünge entfernt", + "unknown": "Sprungweite unbekannt" + }, + "megahertz": "MHz", + "kilohertz": "kHz", + "raw": "Einheitslos", + "meter": { + "one": "Meter", + "plural": "Meter", + "suffix": "m" + }, + "kilometer": { + "one": "Kilometer", + "plural": "Kilometer", + "suffix": "km" + }, + "minute": { + "one": "Minute", + "plural": "Minuten" + }, + "hour": { + "one": "Stunde", + "plural": "Stunden" + }, + "millisecond": { + "one": "Millisekunde", + "plural": "Millisekunden", + "suffix": "ms" + }, + "second": { + "one": "Sekunde", + "plural": "Sekunden" + }, + "day": { + "one": "Tag", + "plural": "Tage", + "today": "Heute", + "yesterday": "Gestern" + }, + "month": { + "one": "Monat", + "plural": "Monate" + }, + "year": { + "one": "Jahr", + "plural": "Jahre" + }, + "snr": "SNR", + "volt": { + "one": "Volt", + "plural": "Volt", + "suffix": "V" + }, + "record": { + "one": "Datensatz", + "plural": "Datensätze" + }, + "degree": { + "one": "Grad", + "plural": "Grad", + "suffix": "°" + } + }, + "security": { + "0bit": "Leer", + "8bit": "8 Bit", + "128bit": "128 Bit", + "256bit": "256 Bit" + }, + "unknown": { + "longName": "Unbekannt", + "shortName": "UNB", + "notAvailable": "Keine Angaben", + "num": "???" + }, + "nodeUnknownPrefix": "!", + "unset": "NICHT GESETZT", + "fallbackName": "Meshtastic {{last4}}", + "node": "Knoten", + "formValidation": { + "unsavedChanges": "Ungespeicherte Änderungen", + "tooBig": { + "string": "Zu lang, erwarte maximal {{maximum}} Zeichen.", + "number": "Zu groß, erwartete eine Zahl kleiner oder gleich {{maximum}}.", + "bytes": "Zu groß, erwarte maximal {{params.maximum}} Bytes." + }, + "tooSmall": { + "string": "Zu kurz, erwartete mindestens {{minimum}} Zeichen.", + "number": "Zu klein, erwartete eine Zahl größer oder gleich {{minimum}}." + }, + "invalidFormat": { + "ipv4": "Ungültiges Format, erwartete eine IPv4 Adresse.", + "key": "Ungültiges Format, erwartet einen Base64-kodierten vor verteilten Schlüssel (PSK)." + }, + "invalidType": { + "number": "Ungültiger Typ, erwartete eine Zahl." + }, + "pskLength": { + "0bit": "Der Schlüssel muss leer sein.", + "8bit": "Der administrative Schlüssel muss ein vor verteilter 8 Bit Schlüssel (PSK) sein.", + "128bit": "Der administrative Schlüssel muss ein vor verteilter 128 Bit Schlüssel (PSK) sein.", + "256bit": "Der administrative Schlüssel muss ein vor verteilter 256 Bit Schlüssel (PSK) sein." + }, + "required": { + "generic": "Dies ist ein Pflichtfeld.", + "managed": "Mindestens ein administrativer Schlüssel wird benötigt, um diesen Knoten zu verwalten", + "key": "Schlüssel erforderlich." + }, + "invalidOverrideFreq": { + "number": "Ungültiges Format, erwartet wurde ein Wert im Bereich 410–930 MHz oder 0 (Standard verwenden)." + } + }, + "yes": "Ja", + "no": "Nein" } diff --git a/packages/web/public/i18n/locales/de-DE/config.json b/packages/web/public/i18n/locales/de-DE/config.json new file mode 100644 index 000000000..6b474d7b9 --- /dev/null +++ b/packages/web/public/i18n/locales/de-DE/config.json @@ -0,0 +1,458 @@ +{ + "page": { + "title": "Einstellungen", + "tabUser": "Benutzer", + "tabChannels": "Kanäle", + "tabBluetooth": "Bluetooth", + "tabDevice": "Gerät", + "tabDisplay": "Display", + "tabLora": "LoRa", + "tabNetwork": "Netzwerk", + "tabPosition": "Standort", + "tabPower": "Leistung", + "tabSecurity": "Sicherheit" + }, + "sidebar": { + "label": "Einstellungen" + }, + "device": { + "title": "Geräteeinstellungen", + "description": "Einstellungen für dieses Gerät", + "buttonPin": { + "description": "GPIO für Taste überschreiben", + "label": "GPIO Taste" + }, + "buzzerPin": { + "description": "GPIO für Summer überschreiben", + "label": "GPIO Summer" + }, + "disableTripleClick": { + "description": "Dreifachklick deaktivieren", + "label": "Dreifachklick deaktivieren" + }, + "doubleTapAsButtonPress": { + "description": "Doppeltes Tippen als Taste verwenden", + "label": "Doppelklick als Tastendruck" + }, + "ledHeartbeatDisabled": { + "description": "Puls LED deaktivieren", + "label": "Herzschlag LED deaktivieren" + }, + "nodeInfoBroadcastInterval": { + "description": "Häufigkeit der Übertragung von Knoteninformationen", + "label": "Knoteninfo Übertragungsintervall" + }, + "posixTimezone": { + "description": "Zeichenfolge der POSIX Zeitzone für dieses Gerät", + "label": "POSIX Zeitzone" + }, + "rebroadcastMode": { + "description": "Wie Weiterleitungen behandelt werden", + "label": "Weiterleitungsmodus" + }, + "role": { + "description": "In welcher Rolle das Gerät im Netz arbeitet", + "label": "Rolle" + } + }, + "bluetooth": { + "title": "Bluetooth Einstellungen", + "description": "Einstellungen für das Bluetooth Modul", + "note": "Hinweis: Einige Geräte (ESP32) können nicht gleichzeitig Bluetooth und WLAN verwenden.", + "enabled": { + "description": "Bluetooth aktivieren oder deaktivieren", + "label": "Aktiviert" + }, + "pairingMode": { + "description": "PIN Nummer Auswahlverhalten", + "label": "Kopplungsmodus" + }, + "pin": { + "description": "PIN Nummer zum Verbinden verwenden", + "label": "PIN Nummer" + } + }, + "display": { + "description": "Einstellungen für die Geräteanzeige", + "title": "Anzeigeeinstellungen", + "headingBold": { + "description": "Überschrifttext fett darstellen", + "label": "Fette Überschrift" + }, + "carouselDelay": { + "description": "Bestimmt wie schnell die Fenster durch gewechselt werden", + "label": "Karussellintervall" + }, + "compassNorthTop": { + "description": "Norden im Kompass immer oben anzeigen", + "label": "Kompass Norden oben" + }, + "displayMode": { + "description": "Variante des Anzeigelayout", + "label": "Anzeigemodus" + }, + "displayUnits": { + "description": "Zeige metrische oder imperiale Einheiten", + "label": "Anzeigeeinheiten" + }, + "flipScreen": { + "description": "Anzeige um 180 Grad drehen", + "label": "Anzeige drehen" + }, + "gpsDisplayUnits": { + "description": "Anzeigeformat der Koordinaten", + "label": "GPS Anzeigeformat" + }, + "oledType": { + "description": "Art des OLED Anzeige, die an dem Gerät angeschlossen ist", + "label": "OLED Typ" + }, + "screenTimeout": { + "description": "Anzeige nach dieser Zeit automatisch ausschalten", + "label": "Anzeigeabschaltung" + }, + "twelveHourClock": { + "description": "12-Stunden Format benutzen", + "label": "12-Stunden Uhr" + }, + "wakeOnTapOrMotion": { + "description": "Gerät durch Tippen oder Bewegung aufwecken", + "label": "Aufwachen durch Tippen oder Bewegung" + } + }, + "lora": { + "title": "Netzeinstellungen", + "description": "Einstellungen für das LoRa Netz", + "bandwidth": { + "description": "Kanalbandbreite in kHz", + "label": "Bandbreite" + }, + "boostedRxGain": { + "description": "Erhöhte Empfangsverstärkung", + "label": "Erhöhte Empfangsverstärkung" + }, + "codingRate": { + "description": "Kodierrate", + "label": "Fehlerkorrektur" + }, + "frequencyOffset": { + "description": "Frequenzversatz zur Kalibrierung von Oszillatorfehlern", + "label": "Frequenzversatz" + }, + "frequencySlot": { + "description": "LoRa Frequenzschlitz", + "label": "Frequenzschlitz" + }, + "hopLimit": { + "description": "Maximale Sprungweite", + "label": "Sprungweite" + }, + "ignoreMqtt": { + "description": "MQTT Nachrichten nicht über das Netz weiterleiten", + "label": "MQTT ignorieren" + }, + "modemPreset": { + "description": "Modem Voreinstellung die verwendet wird", + "label": "Modem Voreinstellungen" + }, + "okToMqtt": { + "description": "Wenn auf aktiviert, zeigt diese Einstellung an, dass der Benutzer das Weiterleiten von Nachrichten über MQTT akzeptiert. Wenn deaktiviert, werden entfernte Knoten aufgefordert, Nachrichten nicht über MQTT weiterzuleiten", + "label": "OK für MQTT" + }, + "overrideDutyCycle": { + "description": "Duty-Cycle überschreiben", + "label": "Duty-Cycle überschreiben" + }, + "overrideFrequency": { + "description": "Sendefrequenz überschreiben (MHz)", + "label": "Sendefrequenz überschreiben" + }, + "region": { + "description": "Legt die Region für Ihren Knoten fest", + "label": "Region" + }, + "spreadingFactor": { + "description": "Anzahl der Symbole zur Kodierung der Nutzdaten", + "label": "Spreizfaktor" + }, + "transmitEnabled": { + "description": "Sender (TX) des LoRa Funkgerätes aktivieren/deaktivieren", + "label": "Senden aktiviert" + }, + "transmitPower": { + "description": "Maximale Sendeleistung", + "label": "Sendeleistung" + }, + "usePreset": { + "description": "Eine der vordefinierten Modem Voreinstellungen verwenden", + "label": "Voreinstellung verwenden" + }, + "meshSettings": { + "description": "Einstellungen für das LoRa Netz", + "label": "Netzeinstellungen" + }, + "waveformSettings": { + "description": "Einstellungen für die LoRa Wellenform", + "label": "Einstellungen der Wellenform" + }, + "radioSettings": { + "label": "Funkeinstellungen", + "description": "Einstellungen für das LoRa Funkgerät" + } + }, + "network": { + "title": "WLAN Einstellungen", + "description": "WLAN Funkeinstellungen", + "note": "Hinweis: Einige Geräte (ESP32) können nicht gleichzeitig Bluetooth und WLAN verwenden.", + "addressMode": { + "description": "Auswahl der IP Adressenzuweisung", + "label": "IP Adressenmodus" + }, + "dns": { + "description": "DNS Server", + "label": "DNS" + }, + "ethernetEnabled": { + "description": "Aktivieren oder deaktivieren sie den Ethernet Anschluss", + "label": "Aktiviert" + }, + "gateway": { + "description": "Standard Gateway", + "label": "Gateway" + }, + "ip": { + "description": "IP Adresse", + "label": "IP" + }, + "psk": { + "description": "Netzwerkpasswort", + "label": "PSK" + }, + "ssid": { + "description": "Netzwerkname", + "label": "SSID" + }, + "subnet": { + "description": "Subnetzmaske", + "label": "Subnetz" + }, + "wifiEnabled": { + "description": "Aktivieren oder deaktivieren Sie die WLAN Übertragung", + "label": "Aktiviert" + }, + "meshViaUdp": { + "label": "Netz über UDP" + }, + "ntpServer": { + "label": "NTP Server" + }, + "rsyslogServer": { + "label": "Rsyslog Server" + }, + "ethernetConfigSettings": { + "description": "Einstellung des Ethernet Ports", + "label": "Ethernet Einstellung" + }, + "ipConfigSettings": { + "description": "Einstellung der IP Adresse", + "label": "IP Adresseinstellungen" + }, + "ntpConfigSettings": { + "description": "NTP Server Einstellungen", + "label": "NTP Einstellungen" + }, + "rsyslogConfigSettings": { + "description": "Rsyslog Einstellung", + "label": "Rsyslog Einstellung" + }, + "udpConfigSettings": { + "description": "UDP über Netz Einstellung", + "label": "UDP Konfiguration" + } + }, + "position": { + "title": "Standorteinstellung", + "description": "Einstellungen für das Standortmodul", + "broadcastInterval": { + "description": "Wie oft Ihr Standort über das Netz gesendet wird", + "label": "Übertragungsintervall" + }, + "enablePin": { + "description": "Überschreiben des GPIO der das GPS-Modul aktiviert", + "label": "GPIO GPS aktivieren" + }, + "fixedPosition": { + "description": "GPS Standort nicht senden, sondern manuell angegeben", + "label": "Fester Standort" + }, + "gpsMode": { + "description": "Einstellung, ob GPS des Geräts aktiviert, deaktiviert oder nicht vorhanden ist", + "label": "GPS Modus" + }, + "gpsUpdateInterval": { + "description": "Wie oft ein GPS Standort ermittelt werden soll", + "label": "GPS Aktualisierungsintervall" + }, + "positionFlags": { + "description": "Optionalen, die bei der Zusammenstellung von Standortnachrichten enthalten sein sollen. Je mehr Optionen ausgewählt werden, desto größer wird die Nachricht und die längere Übertragungszeit erhöht das Risiko für einen Nachrichtenverlust.", + "label": "Standort Optionen" + }, + "receivePin": { + "description": "GPIO Pin für serielles Empfangen (RX) des GPS-Moduls überschreiben", + "label": "GPIO Empfangen" + }, + "smartPositionEnabled": { + "description": "Standort nur verschicken, wenn eine sinnvolle Standortänderung stattgefunden hat", + "label": "Intelligenten Standort aktivieren" + }, + "smartPositionMinDistance": { + "description": "Mindestabstand (in Meter), die vor dem Senden einer Standortaktualisierung zurückgelegt werden muss", + "label": "Minimale Entfernung für intelligenten Standort" + }, + "smartPositionMinInterval": { + "description": "Minimales Intervall (in Sekunden), das vor dem Senden einer Standortaktualisierung vergangen sein muss", + "label": "Minimales Intervall für intelligenten Standort" + }, + "transmitPin": { + "description": "GPIO Pin für serielles Senden (TX) des GPS-Moduls überschreiben", + "label": "GPIO Senden" + }, + "intervalsSettings": { + "description": "Wie oft Standortaktualisierungen gesendet werden", + "label": "Intervalle" + }, + "flags": { + "placeholder": "Standort Optionen auswählen", + "altitude": "Höhe", + "altitudeGeoidalSeparation": "Geoidale Höhentrennung", + "altitudeMsl": "Höhe in Bezug auf Meeresspiegel", + "dop": "Dilution of Präzision (DOP) PDOP standardmäßig verwenden", + "hdopVdop": "Wenn DOP gesetzt ist, wird HDOP / VDOP anstelle von PDOP verwendet", + "numSatellites": "Anzahl Satelliten", + "sequenceNumber": "Sequenznummer", + "timestamp": "Zeitstempel", + "unset": "Nicht konfiguriert", + "vehicleHeading": "Fahrzeugsteuerkurs", + "vehicleSpeed": "Fahrzeuggeschwindigkeit" + } + }, + "power": { + "adcMultiplierOverride": { + "description": "Zur Optimierung der Genauigkeit bei der Akkuspannungsmessung", + "label": "ADC Multiplikationsfaktor" + }, + "ina219Address": { + "description": "Adresse des INA219 Stromsensors", + "label": "INA219 Adresse" + }, + "lightSleepDuration": { + "description": "Wie lange das Gerät im leichten Schlafmodus ist", + "label": "Dauer leichter Schlafmodus" + }, + "minimumWakeTime": { + "description": "Minimale Zeitspanne für die das Gerät aktiv bleibt, nachdem es eine Nachricht empfangen hat", + "label": "Minimale Aufwachzeit" + }, + "noConnectionBluetoothDisabled": { + "description": "Wenn das Gerät keine Bluetooth-Verbindung erhält, wird BLE nach dieser Zeit deaktiviert", + "label": "Keine Verbindung, Bluetooth deaktiviert" + }, + "powerSavingEnabled": { + "description": "Auswählen, wenn aus einer Stromquelle mit niedriger Kapazität (z.B. Solar) betrieben wird, um den Stromverbrauch so weit wie möglich zu minimieren.", + "label": "Energiesparmodus aktivieren" + }, + "shutdownOnBatteryDelay": { + "description": "Verzögerung bis zum Abschalten der Knoten sich im Akkubetrieb befindet. 0 für unbegrenzt", + "label": "Verzögerung Akkuabschaltung" + }, + "superDeepSleepDuration": { + "description": "Wie lange das Gerät im supertiefen Schlafmodus ist", + "label": "Dauer Supertiefschlaf" + }, + "powerConfigSettings": { + "description": "Einstellungen für das Energiemodul", + "label": "Energie Einstellungen" + }, + "sleepSettings": { + "description": "Einstellungen Ruhezustand für das Energiemodul", + "label": "Einstellung Ruhezustand" + } + }, + "security": { + "description": "Sicherheitseinstellungen", + "title": "Sicherheitseinstellungen", + "button_backupKey": "Schlüssel sichern", + "adminChannelEnabled": { + "description": "Erlaubt die Gerätesteuerung über den unsicheren, veralteten administrativen Kanal", + "label": "Veraltete Administrierung erlauben" + }, + "enableDebugLogApi": { + "description": "Ausgabe von Fehlerprotokollen in Echtzeit über die serielle Schnittstelle, Anzeige und Export von Standort reduzierten Geräteprotokollen über Bluetooth", + "label": "Debug-Protokoll API aktivieren" + }, + "managed": { + "description": "Wenn aktiviert, können die Geräteeinstellungen nur von einem entfernten Administratorknoten über administrative Nachrichten geändert werden. Aktivieren Sie diese Option nur, wenn mindestens ein geeigneter Administratorknoten eingerichtet wurde, und dessen öffentlicher Schlüssel in einem der obigen Felder gespeichert wurde.\n", + "label": "Verwaltet" + }, + "privateKey": { + "description": "Wird verwendet, um einen gemeinsamen Schlüssel mit einem entfernten Gerät zu erstellen", + "label": "Privater Schlüssel" + }, + "publicKey": { + "description": "Wird an andere Knoten im Netz gesendet, damit diese einen gemeinsamen geheimen Schlüssel berechnen können", + "label": "Öffentlicher Schlüssel" + }, + "primaryAdminKey": { + "description": "Erster öffentlicher Schlüssel, der berechtigt ist, administrative Nachrichten an diesen Knoten zu senden", + "label": "Erster Admin-Schlüssel" + }, + "secondaryAdminKey": { + "description": "Zweiter öffentlicher Schlüssel, der berechtigt ist, administrative Nachrichten an diesen Knoten zu senden", + "label": "Zweiter Admin-Schlüssel" + }, + "serialOutputEnabled": { + "description": "Serielle Konsole über die Stream-API", + "label": "Serielle Ausgabe aktiviert" + }, + "tertiaryAdminKey": { + "description": "Dritter öffentlicher Schlüssel, der berechtigt ist, administrative Nachrichten an diesen Knoten zu senden", + "label": "Dritter Admin-Schlüssel" + }, + "adminSettings": { + "description": "Administrator Einstellungen", + "label": "Administrator Einstellungen" + }, + "loggingSettings": { + "description": "Einstellungen für die Protokollierung", + "label": "Protokolleinstellungen" + } + }, + "user": { + "title": "Benutzereinstellungen", + "description": "Konfigurieren Sie Ihren Gerätenamen und Identitätseinstellungen", + "longName": { + "label": "Langer Name", + "description": "Ihr vollständiger Anzeigename (1-40 Zeichen)", + "validation": { + "min": "Langer Name muss mindestens 1 Zeichen lang sein", + "max": "Langer Name muss mindestens 40 Zeichen lang sein" + } + }, + "shortName": { + "label": "Kurzname", + "description": "Ihr abgekürzter Name (2-4 Zeichen)", + "validation": { + "min": "Kurzname muss mindestens 2 Zeichen lang sein", + "max": "Kurzname muss mindestens 4 Zeichen lang sein" + } + }, + "isUnmessageable": { + "label": "Nicht erreichbar", + "description": "Wird verwendet, um nicht überwachte Knoten oder Infrastrukturknoten zu identifizieren, sodass Nachrichten nicht an Knoten gesendet werden können, die niemals antworten." + }, + "isLicensed": { + "label": "Amateurfunk lizenziert", + "description": "Aktivieren Sie diese Option, wenn Sie ein lizenzierter Amateurfunker sind. Durch Aktivieren dieser Option wird die Verschlüsselung deaktiviert und sie ist nicht mit dem standardmäßigen Meshtastic Netzwerk kompatibel." + } + } +} diff --git a/packages/web/public/i18n/locales/de-DE/connections.json b/packages/web/public/i18n/locales/de-DE/connections.json new file mode 100644 index 000000000..510f3d292 --- /dev/null +++ b/packages/web/public/i18n/locales/de-DE/connections.json @@ -0,0 +1,34 @@ +{ + "page": { + "title": "Mit einem Meshtastic Gerät verbinden", + "description": "Fügen Sie eine Geräteverbindung über HTTP, Bluetooth oder serielle Schnittstelle hinzu. Ihre gespeicherten Verbindungen werden in Ihrem Browser gespeichert." + }, + "connectionType_ble": "BLE", + "connectionType_serial": "Seriell", + "connectionType_network": "Netzwerk", + "deleteConnection": "Verbindung löschen", + "areYouSure": "Dies entfernt {{name}}. Sie können diese Aktion nicht rückgängig machen.", + "moreActions": "Weitere Aktionen", + "noConnections": { + "title": "Noch keine Verbindungen.", + "description": "Erstellen Sie Ihre erste Verbindung. Sie wird sofort verbunden und später gespeichert." + }, + "lastConnectedAt": "Letzte Verbindung: {{date}}", + "neverConnected": "Nie verbunden", + "toasts": { + "connected": "Verbunden", + "nowConnected": "{{name}} ist jetzt verbunden", + "nowDisconnected": "{{name}} ist jetzt getrennt", + "disconnected": "Verbindung getrennt", + "failed": "Verbindung fehlgeschlagen", + "checkConnetion": "Überprüfen Sie Ihr Gerät oder Ihre Einstellungen und versuchen Sie es erneut", + "defaultSet": "Standard festgelegt", + "defaultConnection": "Standardverbindung ist jetzt {{nameisconnected}}", + "deleted": "Gelöscht", + "deletedByName": "{{name}} wurde entfernt", + "pickConnectionAgain": "Verbindung fehlgeschlagen. Eventuell müssen Sie das Gerät/den Anschluss neu wählen.", + "added": "Verbindung hinzugefügt", + "savedByName": "{{name}} gespeichert.", + "savedCantConnect": "Die Verbindung wurde gespeichert, konnte sich aber nicht verbinden." + } +} diff --git a/packages/web/public/i18n/locales/de-DE/dashboard.json b/packages/web/public/i18n/locales/de-DE/dashboard.json deleted file mode 100644 index 2ee805ec9..000000000 --- a/packages/web/public/i18n/locales/de-DE/dashboard.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "dashboard": { - "title": "Verbundene Geräte", - "description": "Verwalten Sie Ihre verbundenen Meshtastic Geräte.", - "connectionType_ble": "BLE", - "connectionType_serial": "Seriell", - "connectionType_network": "Netzwerk", - "noDevicesTitle": "Keine Geräte verbunden", - "noDevicesDescription": "Verbinden Sie ein neues Gerät, um zu beginnen.", - "button_newConnection": "Neue Verbindung" - } -} diff --git a/packages/web/public/i18n/locales/de-DE/deviceConfig.json b/packages/web/public/i18n/locales/de-DE/deviceConfig.json index 4d11204cd..e49a0866d 100644 --- a/packages/web/public/i18n/locales/de-DE/deviceConfig.json +++ b/packages/web/public/i18n/locales/de-DE/deviceConfig.json @@ -122,7 +122,7 @@ "title": "Netzeinstellungen", "description": "Einstellungen für das LoRa Netz", "bandwidth": { - "description": "Kanalbandbreite in MHz", + "description": "Kanalbandbreite in kHz", "label": "Bandbreite" }, "boostedRxGain": { diff --git a/packages/web/public/i18n/locales/de-DE/dialog.json b/packages/web/public/i18n/locales/de-DE/dialog.json index aef1c254f..bee7cf986 100644 --- a/packages/web/public/i18n/locales/de-DE/dialog.json +++ b/packages/web/public/i18n/locales/de-DE/dialog.json @@ -1,193 +1,238 @@ { - "deleteMessages": { - "description": "Diese Aktion wird den Nachrichtenverlauf löschen. Dies kann nicht rückgängig gemacht werden. Sind Sie sicher, dass Sie fortfahren möchten?", - "title": "Alle Nachrichten löschen" - }, - "deviceName": { - "description": "Das Gerät wird neu gestartet, sobald die Einstellung gespeichert ist.", - "longName": "Langer Name", - "shortName": "Kurzname", - "title": "Gerätename ändern", - "validation": { - "longNameMax": "Lange Name darf nicht mehr als 40 Zeichen lang sein", - "shortNameMax": "Kurzname darf nicht mehr als 4 Zeichen lang sein", - "longNameMin": "Langer Name muss mindestens 1 Zeichen lang sein", - "shortNameMin": "Kurzname muss mindestens 1 Zeichen lang sein" - } - }, - "import": { - "description": "Die aktuelle LoRa Einstellung wird überschrieben.", - "error": { - "invalidUrl": "Ungültige Meshtastic URL" - }, - "channelPrefix": "Kanal: ", - "channelSetUrl": "Kanalsammlung / QR-Code URL", - "channels": "Kanäle:", - "usePreset": "Voreinstellung verwenden?", - "title": "Kanalsammlung importieren" - }, - "locationResponse": { - "title": "Standort: {{identifier}}", - "altitude": "Höhe: ", - "coordinates": "Koordinaten: ", - "noCoordinates": "Keine Koordinaten" - }, - "pkiRegenerateDialog": { - "title": "Vorab verteilten Schlüssel (PSK) neu erstellen?", - "description": "Sind Sie sicher, dass Sie den vorab verteilten Schlüssel neu erstellen möchten?", - "regenerate": "Neu erstellen" - }, - "newDeviceDialog": { - "title": "Neues Gerät verbinden", - "https": "https", - "http": "http", - "tabHttp": "HTTP", - "tabBluetooth": "Bluetooth", - "tabSerial": "Seriell", - "useHttps": "HTTPS verwenden", - "connecting": "Wird verbunden...", - "connect": "Verbindung herstellen", - "connectionFailedAlert": { - "title": "Verbindung fehlgeschlagen", - "descriptionPrefix": "Verbindung zum Gerät fehlgeschlagen. ", - "httpsHint": "Wenn Sie HTTPS verwenden, müssen Sie möglicherweise zuerst ein selbstsigniertes Zertifikat akzeptieren. ", - "openLinkPrefix": "Öffnen Sie ", - "openLinkSuffix": "in einem neuen Tab", - "acceptTlsWarningSuffix": ", akzeptieren Sie alle TLS-Warnungen, wenn Sie dazu aufgefordert werden, dann versuchen Sie es erneut", - "learnMoreLink": "Mehr erfahren" - }, - "httpConnection": { - "label": "IP Adresse/Hostname", - "placeholder": "000.000.000.000 / meshtastic.local" - }, - "serialConnection": { - "noDevicesPaired": "Noch keine Geräte gekoppelt.", - "newDeviceButton": "Neues Gerät", - "deviceIdentifier": "# {{index}} - {{vendorId}} - {{productId}}" - }, - "bluetoothConnection": { - "noDevicesPaired": "Noch keine Geräte gekoppelt.", - "newDeviceButton": "Neues Gerät", - "connectionFailed": "Verbindung fehlgeschlagen", - "deviceDisconnected": "Verbindung getrennt", - "unknownDevice": "Unbekanntes Gerät", - "errorLoadingDevices": "Fehler beim Laden der Geräte", - "unknownErrorLoadingDevices": "Unbekannter Fehler beim Laden der Geräte" - }, - "validation": { - "requiresWebBluetooth": "Dieser Verbindungstyp erfordert <0>Bluetooth im Browser. Bitte verwenden Sie einen unterstützten Browser, wie Chrome oder Edge.", - "requiresWebSerial": "Dieser Verbindungstyp erfordert <0>Serielle Schnittstelle im Browser. Bitte verwenden Sie einen unterstützten Browser, wie Chrome oder Edge.", - "requiresSecureContext": "Diese Anwendung erfordert einen <0>sicheren Kontext. Bitte verbinden Sie sich über HTTPS oder localhost.", - "additionallyRequiresSecureContext": "Zusätzlich erfordert es einen <0>sicheren Kontext. Bitte verbinden Sie sich über HTTPS oder localhost." - } - }, - "nodeDetails": { - "message": "Nachricht", - "requestPosition": "Standort anfordern", - "traceRoute": "Route verfolgen", - "airTxUtilization": "Auslastung Sendezeit", - "allRawMetrics": "Alle Rohdaten", - "batteryLevel": "Akkustand", - "channelUtilization": "Kanalauslastung", - "details": "Details:", - "deviceMetrics": "Gerätekennzahlen:", - "hardware": "Hardware: ", - "lastHeard": "Zuletzt gehört: ", - "nodeHexPrefix": "Knoten ID:", - "nodeNumber": "Knotennummer: ", - "position": "Standort:", - "role": "Rolle: ", - "uptime": "Laufzeit: ", - "voltage": "Spannung", - "title": "Knotendetails für {{identifier}}", - "ignoreNode": "Knoten ignorieren", - "removeNode": "Knoten entfernen", - "unignoreNode": "Knoten akzeptieren", - "security": "Sicherheit:", - "publicKey": "Öffentlicher Schlüssel:", - "messageable": "Ansprechbar:", - "KeyManuallyVerifiedTrue": "Öffentlicher Schlüssel wurde manuell geprüft", - "KeyManuallyVerifiedFalse": "Öffentlicher Schlüssel ist nicht manuell geprüft" - }, - "pkiBackup": { - "loseKeysWarning": "Wenn Sie Ihre Schlüssel verlieren, müssen Sie Ihr Gerät zurücksetzen.", - "secureBackup": "Es ist wichtig, dass Sie Ihre öffentlichen und privaten Schlüssel sichern und diese sicher speichern!", - "footer": "=== END OF KEYS ===", - "header": "=== MESHTASTIC KEYS FOR {{longName}} ({{shortName}}) ===", - "privateKey": "Privater Schlüssel:", - "publicKey": "Öffentlicher Schlüssel:", - "fileName": "meshtastic_keys_{{longName}}_{{shortName}}.txt", - "title": "Schlüssel sichern" - }, - "pkiBackupReminder": { - "description": "Wir empfehlen die regelmäßige Sicherung Ihrer Schlüsseldaten. Möchten Sie jetzt sicheren?", - "title": "Erinnerungen für Sicherungen", - "remindLaterPrefix": "Erinnerung in:", - "remindNever": "Nie erinnern", - "backupNow": "Jetzt sichern" - }, - "pkiRegenerate": { - "description": "Sind Sie sicher, dass Sie Schlüsselpaar neu erstellen möchten?", - "title": "Schlüsselpaar neu erstellen" - }, - "qr": { - "addChannels": "Kanäle hinzufügen", - "replaceChannels": "Kanäle ersetzen", - "description": "Die aktuelle LoRa Einstellung wird ebenfalls geteilt.", - "sharableUrl": "Teilbare URL", - "title": "QR Code Erzeugen" - }, - "reboot": { - "title": "Gerät neustarten", - "description": "Starten Sie jetzt neu oder planen Sie einen Neustart des verbundenen Knotens. Optional können Sie einen Neustart in den OTA (Over-the-Air) Modus wählen.", - "ota": "Neustart in den OTA Modus", - "enterDelay": "Verzögerung eingeben", - "scheduled": "Neustart wurde geplant", - "schedule": "Neustart planen", - "now": "Jetzt neustarten", - "cancel": "Geplanten Neustart abbrechen" - }, - "refreshKeys": { - "description": { - "acceptNewKeys": "Dies entfernt den Knoten vom Gerät und fordert neue Schlüssel an.", - "keyMismatchReasonSuffix": ". Dies liegt daran, dass der aktuelle öffentliche Schlüssel des entfernten Knotens nicht mit dem zuvor gespeicherten Schlüssel für diesen Knoten übereinstimmt.", - "unableToSendDmPrefix": "Ihr Knoten kann keine Direktnachricht an folgenden Knoten senden: " - }, - "acceptNewKeys": "Neue Schlüssel akzeptieren", - "title": "Schlüsselfehler - {{identifier}}" - }, - "removeNode": { - "description": "Sind Sie sicher, dass Sie diesen Knoten entfernen möchten?", - "title": "Knoten entfernen?" - }, - "shutdown": { - "title": "Herunterfahren planen", - "description": "Schaltet den verbundenen Knoten nach x Minuten aus." - }, - "traceRoute": { - "routeToDestination": "Route zum Ziel:", - "routeBack": "Route zurück:" - }, - "tracerouteResponse": { - "title": "Traceroute: {{identifier}}" - }, - "unsafeRoles": { - "confirmUnderstanding": "Ja, ich weiß, was ich tue!", - "conjunction": " und der Blog-Beitrag über ", - "postamble": " und verstehen die Auswirkungen einer Veränderung der Rolle.", - "preamble": "Ich habe die", - "choosingRightDeviceRole": "Wahl der richtigen Geräterolle", - "deviceRoleDocumentation": "Dokumentation der Geräterolle", - "title": "Sind Sie sicher?" - }, - "managedMode": { - "confirmUnderstanding": "Ja, ich weiß, was ich tue!", - "title": "Sind Sie sicher?", - "description": "Das Aktivieren des verwalteten Modus blockiert das Schreiben der Einstellungen in das Funkgerät durch alle Anwendungen (einschließlich der Webanwendung). Einmal aktiviert, können die Einstellungen nur durch administrative Nachrichten geändert werden. Diese Einstellung ist für die Fernverwaltung von abgesetzten Knoten nicht erforderlich." - }, - "clientNotification": { - "title": "Warnmeldung", - "TraceRoute can only be sent once every 30 seconds": "TraceRoute kann nur einmal alle 30 Sekunden versendet werden.", - "Compromised keys were detected and regenerated.": "Kompromittierte Schlüssel wurden erkannt und neu generiert." - } + "deleteMessages": { + "description": "Diese Aktion wird den Nachrichtenverlauf löschen. Dies kann nicht rückgängig gemacht werden. Sind Sie sicher, dass Sie fortfahren möchten?", + "title": "Alle Nachrichten löschen" + }, + "import": { + "description": "Die aktuelle LoRa Einstellung wird überschrieben.", + "error": { + "invalidUrl": "Ungültige Meshtastic URL" + }, + "channelPrefix": "Kanal: ", + "primary": "Primär ", + "doNotImport": "Nicht importieren", + "channelName": "Name", + "channelSlot": "Position", + "channelSetUrl": "Kanalsammlung / QR-Code URL", + "useLoraConfig": "LoRa Konfiguration importieren", + "presetDescription": "Die aktuelle LoRa Konfiguration wird ersetzt.", + "title": "Kanalsammlung importieren" + }, + "locationResponse": { + "title": "Standort: {{identifier}}", + "altitude": "Höhe: ", + "coordinates": "Koordinaten: ", + "noCoordinates": "Keine Koordinaten" + }, + "pkiRegenerateDialog": { + "title": "Vorab verteilten Schlüssel (PSK) neu erstellen?", + "description": "Sind Sie sicher, dass Sie den vorab verteilten Schlüssel neu erstellen möchten?", + "regenerate": "Neu erstellen" + }, + "addConnection": { + "title": "Verbindung hinzufügen", + "description": "Wählen Sie einen Verbindungstyp aus und geben Sie die Details ein", + "validation": { + "requiresWebBluetooth": "Dieser Verbindungstyp erfordert <0>Bluetooth im Browser. Bitte verwenden Sie einen unterstützten Browser, wie Chrome oder Edge.", + "requiresWebSerial": "Dieser Verbindungstyp erfordert <0>Serielle Schnittstelle im Browser. Bitte verwenden Sie einen unterstützten Browser, wie Chrome oder Edge.", + "requiresSecureContext": "Diese Anwendung erfordert einen <0>sicheren Kontext. Bitte verbinden Sie sich über HTTPS oder localhost.", + "additionallyRequiresSecureContext": "Zusätzlich erfordert es einen <0>sicheren Kontext. Bitte verbinden Sie sich über HTTPS oder localhost." + }, + "bluetoothConnection": { + "namePlaceholder": "Mein Bluetooth Knoten", + "supported": { + "title": "Web Bluetooth wird unterstützt" + }, + "notSupported": { + "title": "Web Bluetooth wird nicht unterstützt", + "description": "Ihr Browser oder Ihr Gerät unterstützt kein Bluetooth im Web" + }, + "short": "BT: {{deviceName}}", + "long": "Bluetooth Gerät", + "device": "Gerät", + "selectDevice": "Gerät auswählen", + "selected": "Bluetooth Gerät ausgewählt", + "notSelected": "Kein Gerät ausgewählt", + "helperText": "Verwendet den Meshtastic Bluetooth Dienst zur Erkennung." + }, + "serialConnection": { + "namePlaceholder": "Mein serieller Knoten", + "helperText": "Die Auswahl eines Anschlusses erteilt der App die Berechtigung, diesen zu öffnen und eine Verbindung herzustellen.", + "supported": { + "title": "Web Seriell unterstützt" + }, + "notSupported": { + "title": "Web Seriell nicht unterstützt", + "description": "Ihr Browser oder Ihr Gerät unterstützt kein Web Seriell" + }, + "portSelected": { + "title": "Serieller Anschluss ausgewählt", + "description": "Anschlussberechtigungen gewährt." + }, + "port": "Anschluss", + "selectPort": "Anschluss auswählen", + "deviceName": "USB {{vendorId}}:{{productId}}", + "notSelected": "Kein Anschluss ausgewählt" + }, + "httpConnection": { + "namePlaceholder": "Mein HTTP Knoten", + "inputPlaceholder": "192.168.1.10 oder meshtastic.local", + "heading": "URL oder IP", + "useHttps": "HTTPS verwenden", + "invalidUrl": { + "title": "Ungültige URL", + "description": "Bitte geben Sie eine gültige HTTP oder HTTPS URL ein." + }, + "connectionTest": { + "description": "Testen Sie die Verbindung, bevor Sie speichern um zu überprüfen, dass das Gerät erreichbar ist.", + "button": { + "loading": "Wird getestet...", + "label": "Verbindung testen" + }, + "reachable": "Erreichbar", + "notReachable": "Nicht erreichbar", + "success": { + "title": "Verbindungstest erfolgreich", + "description": "Das Gerät scheint erreichbar zu sein." + }, + "failure": { + "title": "Verbindungstest fehlgeschlagen", + "description": "Das Gerät konnte nicht erreicht werden. Überprüfen Sie die URL und versuchen Sie es erneut." + } + } + } + }, + "nodeDetails": { + "message": "Nachricht", + "requestPosition": "Standort anfordern", + "traceRoute": "Route verfolgen", + "airTxUtilization": "Auslastung Sendezeit", + "allRawMetrics": "Alle Rohdaten", + "batteryLevel": "Akkustand", + "channelUtilization": "Kanalauslastung", + "details": "Details:", + "deviceMetrics": "Gerätekennzahlen:", + "hardware": "Hardware: ", + "lastHeard": "Zuletzt gehört: ", + "nodeHexPrefix": "Knoten ID:", + "nodeNumber": "Knotennummer: ", + "position": "Standort:", + "role": "Rolle: ", + "uptime": "Laufzeit: ", + "voltage": "Spannung", + "title": "Knotendetails für {{identifier}}", + "ignoreNode": "Knoten ignorieren", + "removeNode": "Knoten entfernen", + "unignoreNode": "Knoten akzeptieren", + "security": "Sicherheit:", + "publicKey": "Öffentlicher Schlüssel:", + "messageable": "Ansprechbar:", + "KeyManuallyVerifiedTrue": "Öffentlicher Schlüssel wurde manuell geprüft", + "KeyManuallyVerifiedFalse": "Öffentlicher Schlüssel ist nicht manuell geprüft" + }, + "pkiBackup": { + "loseKeysWarning": "Wenn Sie Ihre Schlüssel verlieren, müssen Sie Ihr Gerät zurücksetzen.", + "secureBackup": "Es ist wichtig, dass Sie Ihre öffentlichen und privaten Schlüssel sichern und diese sicher speichern!", + "footer": "=== END OF KEYS ===", + "header": "=== MESHTASTIC KEYS FOR {{longName}} ({{shortName}}) ===", + "privateKey": "Privater Schlüssel:", + "publicKey": "Öffentlicher Schlüssel:", + "fileName": "meshtastic_keys_{{longName}}_{{shortName}}.txt", + "title": "Schlüssel sichern" + }, + "pkiBackupReminder": { + "description": "Wir empfehlen die regelmäßige Sicherung Ihrer Schlüsseldaten. Möchten Sie jetzt sicheren?", + "title": "Erinnerungen für Sicherungen", + "remindLaterPrefix": "Erinnerung in:", + "remindNever": "Nie erinnern", + "backupNow": "Jetzt sichern" + }, + "pkiRegenerate": { + "description": "Sind Sie sicher, dass Sie Schlüsselpaar neu erstellen möchten?", + "title": "Schlüsselpaar neu erstellen" + }, + "qr": { + "addChannels": "Kanäle hinzufügen", + "replaceChannels": "Kanäle ersetzen", + "description": "Die aktuelle LoRa Einstellung wird ebenfalls geteilt.", + "sharableUrl": "Teilbare URL", + "title": "QR Code Erzeugen" + }, + "reboot": { + "title": "Gerät neustarten", + "description": "Starten Sie jetzt neu oder planen Sie einen Neustart des verbundenen Knotens. Optional können Sie einen Neustart in den OTA (Over-the-Air) Modus wählen.", + "ota": "Neustart in den OTA Modus", + "enterDelay": "Verzögerung eingeben", + "scheduled": "Neustart wurde geplant", + "schedule": "Neustart planen", + "now": "Jetzt neustarten", + "cancel": "Geplanten Neustart abbrechen" + }, + "refreshKeys": { + "description": { + "acceptNewKeys": "Dies entfernt den Knoten vom Gerät und fordert neue Schlüssel an.", + "keyMismatchReasonSuffix": ". Dies liegt daran, dass der aktuelle öffentliche Schlüssel des entfernten Knotens nicht mit dem zuvor gespeicherten Schlüssel für diesen Knoten übereinstimmt.", + "unableToSendDmPrefix": "Ihr Knoten kann keine Direktnachricht an folgenden Knoten senden: " + }, + "acceptNewKeys": "Neue Schlüssel akzeptieren", + "title": "Schlüsselfehler - {{identifier}}" + }, + "removeNode": { + "description": "Sind Sie sicher, dass Sie diesen Knoten entfernen möchten?", + "title": "Knoten entfernen?" + }, + "shutdown": { + "title": "Herunterfahren planen", + "description": "Schaltet den verbundenen Knoten nach x Minuten aus." + }, + "traceRoute": { + "routeToDestination": "Route zum Ziel:", + "routeBack": "Route zurück:" + }, + "tracerouteResponse": { + "title": "Traceroute: {{identifier}}" + }, + "unsafeRoles": { + "confirmUnderstanding": "Ja, ich weiß, was ich tue!", + "conjunction": " und der Blog-Beitrag über ", + "postamble": " und verstehen die Auswirkungen einer Veränderung der Rolle.", + "preamble": "Ich habe die", + "choosingRightDeviceRole": "Wahl der richtigen Geräterolle", + "deviceRoleDocumentation": "Dokumentation der Geräterolle", + "title": "Sind Sie sicher?" + }, + "managedMode": { + "confirmUnderstanding": "Ja, ich weiß, was ich tue!", + "title": "Sind Sie sicher?", + "description": "Das Aktivieren des verwalteten Modus blockiert das Schreiben der Einstellungen in das Funkgerät durch alle Anwendungen (einschließlich der Webanwendung). Einmal aktiviert, können die Einstellungen nur durch administrative Nachrichten geändert werden. Diese Einstellung ist für die Fernverwaltung von abgesetzten Knoten nicht erforderlich." + }, + "clientNotification": { + "title": "Warnmeldung", + "TraceRoute can only be sent once every 30 seconds": "TraceRoute kann nur einmal alle 30 Sekunden versendet werden.", + "Compromised keys were detected and regenerated.": "Kompromittierte Schlüssel wurden erkannt und neu generiert." + }, + "resetNodeDb": { + "title": "Knotendatenbank zurücksetzen", + "description": "Dadurch werden alle Knoten aus der Knotendatenbank des verbundenen Geräts und der gesamte Nachrichtenverlauf im Client gelöscht. Dieser Vorgang kann nicht rückgängig gemacht werden. Möchten Sie wirklich fortfahren?", + "confirm": "Knotendatenbank zurücksetzen", + "failedTitle": "Beim Zurücksetzen der Knoten-Datenbank ist ein Fehler aufgetreten. Bitte versuchen Sie es erneut." + }, + "clearAllStores": { + "title": "Lösche den gesamten lokalen Speicher", + "description": "Dadurch werden alle lokal gespeicherten Daten gelöscht, einschließlich des Nachrichtenverlaufs und der Knotendatenbanken aller zuvor verbundenen Geräte. Nach Abschluss des Vorgangs müssen Sie die Verbindung zu Ihrem Knoten erneut herstellen. Dieser Vorgang kann nicht rückgängig gemacht werden. Möchten Sie wirklich fortfahren?", + "confirm": "Lösche den gesamten lokalen Speicher", + "failedTitle": "Beim Löschen des lokalen Speichers ist ein Fehler aufgetreten. Bitte versuchen Sie es erneut." + }, + "factoryResetDevice": { + "title": "Gerät auf Werkseinstellungen zurücksetzen", + "description": "Dadurch wird das verbundene Gerät auf die Werkseinstellungen zurückgesetzt. Alle Konfigurationen und Daten auf dem Gerät sowie alle im Client gespeicherten Knoten und Nachrichten werden gelöscht. Dieser Vorgang kann nicht rückgängig gemacht werden. Möchten Sie wirklich fortfahren?", + "confirm": "Gerät auf Werkseinstellungen zurücksetzen", + "failedTitle": "Beim Zurücksetzen auf die Werkseinstellungen ist ein Fehler aufgetreten. Bitte versuchen Sie es erneut." + }, + "factoryResetConfig": { + "title": "Auf Werkseinstellungen zurücksetzen", + "description": "Dadurch wird die Konfiguration des verbundenen Geräts auf die Werkseinstellungen zurückgesetzt und alle Konfigurationen auf dem Gerät gelöscht. Dieser Vorgang kann nicht rückgängig gemacht werden. Möchten Sie wirklich fortfahren?", + "confirm": "Auf Werkseinstellungen zurücksetzen", + "failedTitle": "Beim Zurücksetzen auf die Werkseinstellungen ist ein Fehler aufgetreten. Bitte versuchen Sie es erneut." + } } diff --git a/packages/web/public/i18n/locales/de-DE/map.json b/packages/web/public/i18n/locales/de-DE/map.json new file mode 100644 index 000000000..12991419a --- /dev/null +++ b/packages/web/public/i18n/locales/de-DE/map.json @@ -0,0 +1,38 @@ +{ + "maplibre": { + "GeolocateControl.FindMyLocation": "Meinen Standort ermitteln", + "NavigationControl.ZoomIn": "Vergrößern", + "NavigationControl.ZoomOut": "Verkleinern", + "CooperativeGesturesHandler.WindowsHelpText": "Verwenden Sie STRG + Scrollen zum Zoomen der Karte", + "CooperativeGesturesHandler.MacHelpText": "Verwenden Sie ⌘ + Scrollen zum Zoomen der Karte", + "CooperativeGesturesHandler.MobileHelpText": "Verwenden Sie zwei Finger, um die Karte zu bewegen." + }, + "layerTool": { + "nodeMarkers": "Zeige Knoten", + "directNeighbors": "Direkte Verbindungen anzeigen", + "remoteNeighbors": "Entfernte Verbindungen anzeigen", + "positionPrecision": "Positionsgenauigkeit anzeigen", + "traceroutes": "Traceroutes anzeigen", + "waypoints": "Wegpunkte anzeigen" + }, + "mapMenu": { + "locateAria": "Meinen Knoten suchen", + "layersAria": "Kartenformat ändern" + }, + "waypointDetail": { + "edit": "Bearbeiten", + "description": "Beschreibung:", + "createdBy": "Bearbeitet:", + "createdDate": "Erstellt:", + "updated": "Aktualisiert:", + "expires": "Gültig bis:", + "distance": "Entfernung:", + "bearing": "Absolute Peilung:", + "lockedTo": "Gesperrt:", + "latitude": "Breitengrad:", + "longitude": "Längengrad:" + }, + "myNode": { + "tooltip": "Dieses Gerät" + } +} diff --git a/packages/web/public/i18n/locales/de-DE/messages.json b/packages/web/public/i18n/locales/de-DE/messages.json index 188071bab..02f1435cc 100644 --- a/packages/web/public/i18n/locales/de-DE/messages.json +++ b/packages/web/public/i18n/locales/de-DE/messages.json @@ -1,39 +1,39 @@ { - "page": { - "title": "Nachrichten: {{chatName}}", - "placeholder": "Nachricht eingeben" - }, - "emptyState": { - "title": "Einen Chat auswählen", - "text": "Noch keine Nachrichten." - }, - "selectChatPrompt": { - "text": "Wählen Sie einen Kanal oder Knoten, um Nachrichten zu schreiben." - }, - "sendMessage": { - "placeholder": "Geben Sie hier Ihre Nachricht ein...", - "sendButton": "Senden" - }, - "actionsMenu": { - "addReactionLabel": "Reaktion hinzufügen", - "replyLabel": "Antworten" - }, - "deliveryStatus": { - "delivered": { - "label": "Nachricht zugestellt", - "displayText": "Nachricht zugestellt" - }, - "failed": { - "label": "Nachrichtenübermittlung fehlgeschlagen", - "displayText": "Zustellung fehlgeschlagen" - }, - "unknown": { - "label": "Nachrichtenstatus unbekannt", - "displayText": "Unbekannter Status" - }, - "waiting": { - "label": "Nachricht wird gesendet", - "displayText": "Warte auf Zustellung" - } - } + "page": { + "title": "Nachrichten: {{chatName}}", + "placeholder": "Nachricht eingeben" + }, + "emptyState": { + "title": "Einen Chat auswählen", + "text": "Noch keine Nachrichten." + }, + "selectChatPrompt": { + "text": "Wählen Sie einen Kanal oder Knoten, um Nachrichten zu schreiben." + }, + "sendMessage": { + "placeholder": "Geben Sie hier Ihre Nachricht ein...", + "sendButton": "Senden" + }, + "actionsMenu": { + "addReactionLabel": "Reaktion hinzufügen", + "replyLabel": "Antworten" + }, + "deliveryStatus": { + "delivered": { + "label": "Nachricht zugestellt", + "displayText": "Nachricht zugestellt" + }, + "failed": { + "label": "Nachrichtenübermittlung fehlgeschlagen", + "displayText": "Zustellung fehlgeschlagen" + }, + "unknown": { + "label": "Nachrichtenstatus unbekannt", + "displayText": "Unbekannter Status" + }, + "waiting": { + "label": "Nachricht wird gesendet", + "displayText": "Warte auf Zustellung" + } + } } diff --git a/packages/web/public/i18n/locales/de-DE/moduleConfig.json b/packages/web/public/i18n/locales/de-DE/moduleConfig.json index cb4c4c534..76e41cfb4 100644 --- a/packages/web/public/i18n/locales/de-DE/moduleConfig.json +++ b/packages/web/public/i18n/locales/de-DE/moduleConfig.json @@ -1,448 +1,448 @@ { - "page": { - "tabAmbientLighting": "Umgebungslicht", - "tabAudio": "Audio", - "tabCannedMessage": "Vordefinierte Nachrichten", - "tabDetectionSensor": "Erkennungssensor", - "tabExternalNotification": "Externe Benachrichtigung", - "tabMqtt": "MQTT", - "tabNeighborInfo": "Nachbarinformation", - "tabPaxcounter": "Pax Zähler", - "tabRangeTest": "Reichweitentest", - "tabSerial": "Seriell", - "tabStoreAndForward": "Speichern&Weiterleiten", - "tabTelemetry": "Telemetrie" - }, - "ambientLighting": { - "title": "Einstellung Umgebungsbeleuchtung", - "description": "Einstellungen für das Modul Umgebungsbeleuchtung", - "ledState": { - "label": "LED Status", - "description": "Setzt die LED auf ein oder aus" - }, - "current": { - "label": "Stromstärke", - "description": "Legt den Strom für den LED Ausgang fest. Standard ist 10" - }, - "red": { - "label": "Rot", - "description": "Legt den roten LED Wert fest. Bereich 0-255" - }, - "green": { - "label": "Grün", - "description": "Legt den grünen LED Wert fest. Bereich 0-255" - }, - "blue": { - "label": "Blau", - "description": "Legt den blauen LED Wert fest. Bereich 0-255" - } - }, - "audio": { - "title": "Audioeinstellungen", - "description": "Einstellungen für das Audiomodul", - "codec2Enabled": { - "label": "Codec 2 aktiviert", - "description": "Codec 2 Audiokodierung aktivieren" - }, - "pttPin": { - "label": "GPIO PTT", - "description": "Für PTT verwendeter GPIO Pin" - }, - "bitrate": { - "label": "Bitrate", - "description": "Bitrate zur Audiokodierung" - }, - "i2sWs": { - "label": "i2S WS", - "description": "GPIO Pin für i2S WS" - }, - "i2sSd": { - "label": "i2S SD", - "description": "GPIO Pin für i2S SD" - }, - "i2sDin": { - "label": "i2S DIN", - "description": "GPIO Pin für i2S DIN" - }, - "i2sSck": { - "label": "i2S SCK", - "description": "GPIO Pin für i2S SCK" - } - }, - "cannedMessage": { - "title": "Einstellungen für vordefinierte Nachrichten", - "description": "Einstellungen für das Modul vordefinierte Nachrichten", - "moduleEnabled": { - "label": "Modul aktiviert", - "description": "Vordefinierte Nachrichten aktivieren" - }, - "rotary1Enabled": { - "label": "Drehgeber #1 aktiviert", - "description": "Drehgeber aktivieren" - }, - "inputbrokerPinA": { - "label": "Drehgeber Pin A", - "description": "GPIO Pin Wert (1-39) für Drehgeber Pin A" - }, - "inputbrokerPinB": { - "label": "Drehgeber Pin B", - "description": "GPIO Pin Wert (1-39) für Drehgeber Pin B" - }, - "inputbrokerPinPress": { - "label": "Drehgeber Pin Taste", - "description": "GPIO Pin Wert (1-39) für Drehgeber Pin Taste" - }, - "inputbrokerEventCw": { - "label": "Ereignis im Uhrzeigersinn", - "description": "Eingabeereignis auswählen." - }, - "inputbrokerEventCcw": { - "label": "Ereignis gegen Uhrzeigersinn", - "description": "Eingabeereignis auswählen." - }, - "inputbrokerEventPress": { - "label": "Ereignis Tastendruck", - "description": "Eingabeereignis auswählen." - }, - "updown1Enabled": { - "label": "Geber Hoch/Runter aktiviert", - "description": "Aktiviere Geber Hoch/Runter" - }, - "allowInputSource": { - "label": "Eingabequelle zulassen", - "description": "Wählen Sie aus: '_any', 'rotEnc1', 'upDownEnc1', 'cardkb'" - }, - "sendBell": { - "label": "Sende Glocke", - "description": "Sendet ein Klingelzeichen (Glocke) mit jeder Nachricht" - } - }, - "detectionSensor": { - "title": "Sensoreinstellungen für Erkennung", - "description": "Einstellungen für das Erkennungssensormodul", - "enabled": { - "label": "Aktiviert", - "description": "Erkennungssensormodul aktivieren oder deaktivieren" - }, - "minimumBroadcastSecs": { - "label": "Minimale Übertragungszeit alle Sekunden", - "description": "Das Intervall in Sekunden, wie oft eine Nachricht an das Netz gesendet wird, wenn eine Statusänderung erkannt wurde" - }, - "stateBroadcastSecs": { - "label": "Statusübertragung alle Sekunden", - "description": "Das Intervall in Sekunden, wie oft eine Nachricht mit dem aktuellen Status an das Netz gesendet wird, unabhängig von Änderungen" - }, - "sendBell": { - "label": "Sende Glocke", - "description": "ASCII-Glocke mit Warnmeldung senden" - }, - "name": { - "label": "Anzeigename", - "description": "Formatierte Nachricht die an das Netz gesendet wird, maximal 20 Zeichen" - }, - "monitorPin": { - "label": "GPIO Pin überwachen", - "description": "Der GPIO Pin zur Überwachung von Statusänderungen" - }, - "detectionTriggerType": { - "label": "Auslösetyp der Erkennung", - "description": "Die Art des zu verwendenden Auslöseereignisses" - }, - "usePullup": { - "label": "Pullup verwenden", - "description": "Gibt an, ob der INPUT_PULLUP Modus für GPIO Pin verwendet wird oder nicht" - } - }, - "externalNotification": { - "title": "Einstellungen für externe Benachrichtigungen", - "description": "Einstellung für das Modul externe Benachrichtigung", - "enabled": { - "label": "Modul aktiviert", - "description": "Externe Benachrichtigung aktivieren" - }, - "outputMs": { - "label": "Ausgabe MS", - "description": "Ausgabe MS" - }, - "output": { - "label": "Ausgabe", - "description": "Ausgabe" - }, - "outputVibra": { - "label": "Ausgabe Vibration", - "description": "Ausgabe Vibration" - }, - "outputBuzzer": { - "label": "Ausgabe Summer", - "description": "Ausgabe Summer" - }, - "active": { - "label": "Aktiv", - "description": "Aktiv" - }, - "alertMessage": { - "label": "Warnmeldung", - "description": "Warnmeldung" - }, - "alertMessageVibra": { - "label": "Vibration bei Warnmeldung", - "description": "Vibration bei Warnmeldung" - }, - "alertMessageBuzzer": { - "label": "Summer bei Warnmeldung", - "description": "Summer bei Warnmeldung" - }, - "alertBell": { - "label": "Warnglocke", - "description": "Soll beim Empfang eines eingehenden Klingelzeichens (Glocke) eine Warnung ausgelöst werden?" - }, - "alertBellVibra": { - "label": "Vibration bei Klingelzeichen", - "description": "Vibration bei Klingelzeichen" - }, - "alertBellBuzzer": { - "label": "Summer bei Klingelzeichen", - "description": "Summer bei Klingelzeichen" - }, - "usePwm": { - "label": "PWM verwenden", - "description": "PWM verwenden" - }, - "nagTimeout": { - "label": "Nervige Verzögerung", - "description": "Nervige Verzögerung" - }, - "useI2sAsBuzzer": { - "label": "I2S GPIO Pin als Summer verwenden", - "description": "I2S GPIO Pin als Summerausgang definieren" - } - }, - "mqtt": { - "title": "MQTT Einstellungen", - "description": "Einstellungen für das MQTT Modul", - "enabled": { - "label": "Aktiviert", - "description": "MQTT aktivieren oder deaktivieren" - }, - "address": { - "label": "MQTT Server Adresse", - "description": "MQTT Serveradresse für Standard/benutzerdefinierte Server" - }, - "username": { - "label": "MQTT Benutzername", - "description": "MQTT Benutzername für Standard/benutzerdefinierte Server" - }, - "password": { - "label": "MQTT Passwort", - "description": "MQTT Passwort für Standard/benutzerdefinierte Server" - }, - "encryptionEnabled": { - "label": "Verschlüsselung aktiviert", - "description": "MQTT-Verschlüsselung aktivieren oder deaktivieren. Hinweis: Alle Nachrichten werden unverschlüsselt an den MQTT-Broker gesendet, wenn diese Option nicht aktiviert ist. Unabhängig von der eingestellten Kanalverschlüsselung. Einschließlich der Standortdaten." - }, - "jsonEnabled": { - "label": "JSON aktiviert", - "description": "Gibt an, ob JSON Nachrichten über MQTT gesendet oder empfangen werden sollen" - }, - "tlsEnabled": { - "label": "TLS aktiviert", - "description": "TLS aktivieren oder deaktivieren" - }, - "root": { - "label": "Hauptthema", - "description": "MQTT Hauptthema für Standard/Benutzerdefinierte Server" - }, - "proxyToClientEnabled": { - "label": "MQTT Client Proxy aktiviert", - "description": "Verwendet die Netzwerkverbindung zum Austausch von MQTT Nachrichten mit dem Client." - }, - "mapReportingEnabled": { - "label": "Kartenberichte aktiviert", - "description": "Ihr Knoten sendet in regelmäßigen Abständen eine unverschlüsselte Nachricht mit Kartenbericht an den konfigurierten MQTT-Server. Einschließlich ID, langen und kurzen Namen, ungefährer Standort, Hardwaremodell, Geräterolle, Firmware-Version, LoRa Region, Modem-Voreinstellung und Name des Primärkanal." - }, - "mapReportSettings": { - "publishIntervalSecs": { - "label": "Veröffentlichungsintervall Kartenbericht (s)", - "description": "Intervall in Sekunden, um Kartenberichte zu veröffentlichen" - }, - "positionPrecision": { - "label": "Ungefährer Standort", - "description": "Der geteilte Standort mit einer Genauigkeit innerhalb dieser Entfernung", - "options": { - "metric_km23": "Innerhalb von 23 km", - "metric_km12": "Innerhalb von 12 km", - "metric_km5_8": "Innerhalb von 5,8 km", - "metric_km2_9": "Innerhalb von 2,9 km", - "metric_km1_5": "Innerhalb von 1,5 km", - "metric_m700": "Innerhalb von 700 m", - "metric_m350": "Innerhalb von 350 m", - "metric_m200": "Innerhalb von 200 m", - "metric_m90": "Innerhalb von 90 m", - "metric_m50": "Innerhalb von 50 m", - "imperial_mi15": "Innerhalb von 15 Meilen", - "imperial_mi7_3": "Innerhalb von 7,3 Meilen", - "imperial_mi3_6": "Innerhalb von 3,6 Meilen", - "imperial_mi1_8": "Innerhalb von 1,8 Meilen", - "imperial_mi0_9": "Innerhalb von 0,9 Meilen", - "imperial_mi0_5": "Innerhalb von 0,5 Meilen", - "imperial_mi0_2": "Innerhalb von 0,2 Meilen", - "imperial_ft600": "Innerhalb von 600 Fuß", - "imperial_ft300": "Innerhalb von 300 Fuß", - "imperial_ft150": "Innerhalb von 150 Fuß" - } - } - } - }, - "neighborInfo": { - "title": "Einstellung Nachbarinformation", - "description": "Einstellungen für das Modul Nachbarinformation", - "enabled": { - "label": "Aktiviert", - "description": "Nachbarinformation Modul aktivieren oder deaktivieren" - }, - "updateInterval": { - "label": "Aktualisierungsintervall", - "description": "Intervall in Sekunden, wie oft die Nachbarinformation an das Netz gesendet wird" - } - }, - "paxcounter": { - "title": "Einstellung für Pax Zähler", - "description": "Einstellungen für das Modul Pax Zähler", - "enabled": { - "label": "Modul aktiviert", - "description": "Aktiviere Pax Zähler" - }, - "paxcounterUpdateInterval": { - "label": "Aktualisierungsintervall (Sekunden)", - "description": "Wie lange soll zwischen dem Senden von Pax Zählernachrichten gewartet werden" - }, - "wifiThreshold": { - "label": "WLAN RSSI Grenzwert", - "description": "Bei welchem WLAN RSSI Grenzwert sollte der Zähler erhöht werden. Standardwert -80" - }, - "bleThreshold": { - "label": "BLE RSSI Grenzwert", - "description": "Bei welchem BLE RSSI Grenzwert sollte der Zähler erhöht werden. Standardwert -80" - } - }, - "rangeTest": { - "title": "Einstellung Reichweitentest", - "description": "Einstellungen für das Modul Reichweitentest", - "enabled": { - "label": "Modul aktiviert", - "description": "Reichweitentest aktivieren" - }, - "sender": { - "label": "Nachrichtenintervall", - "description": "Wie lange soll zwischen dem Senden von Testnachrichten gewartet werden" - }, - "save": { - "label": "CSV im internen Speicher abspeichern", - "description": "Nur für ESP32" - } - }, - "serial": { - "title": "Serielle Einstellungen", - "description": "Einstellungen für das serielle Modul", - "enabled": { - "label": "Modul aktiviert", - "description": "Serielle Ausgabe aktivieren" - }, - "echo": { - "label": "Echo", - "description": "Wenn aktiviert, werden alle Nachrichten, die Sie senden, an Ihr Gerät zurückgesendet" - }, - "rxd": { - "label": "GPIO Empfangen", - "description": "Setzen Sie den GPIO Pin, den Sie eingerichtet haben, als RXD Pin." - }, - "txd": { - "label": "GPIO Senden", - "description": "Setzen Sie den GPIO Pin, den Sie eingerichtet haben, als TXD Pin." - }, - "baud": { - "label": "Baudrate", - "description": "Serielle Baudrate" - }, - "timeout": { - "label": "Zeitlimit erreicht", - "description": "Wartezeit in Sekunden bis eine Nachricht als gesendet angenommen wird" - }, - "mode": { - "label": "Betriebsmodus", - "description": "Modus auswählen" - }, - "overrideConsoleSerialPort": { - "label": "Seriellen Port der Konsole überschreiben", - "description": "Wenn Sie einen seriellen Port an die Konsole angeschlossen haben, wird diese überschrieben." - } - }, - "storeForward": { - "title": "Speichern & Weiterleiten Einstellungen", - "description": "Einstellungen für das Modul Speichern & Weiterleiten", - "enabled": { - "label": "Modul aktiviert", - "description": "Speichern & Weiterleiten aktivieren" - }, - "heartbeat": { - "label": "Herzschlag aktiviert", - "description": "Herzschlag für Speichern & Weiterleiten aktivieren" - }, - "records": { - "label": "Anzahl Einträge", - "description": "Anzahl der zu speichernden Datensätze" - }, - "historyReturnMax": { - "label": "Verlauf Rückgabewert maximal", - "description": "Maximale Anzahl an zurückzugebenden Datensätzen" - }, - "historyReturnWindow": { - "label": "Zeitraum Rückgabewert", - "description": "Maximale Anzahl an zurückzugebenden Datensätzen" - } - }, - "telemetry": { - "title": "Telemetrieeinstellungen", - "description": "Einstellungen für das Telemetriemodul", - "deviceUpdateInterval": { - "label": "Gerätekennzahlen", - "description": "Aktualisierungsintervall für Gerätekennzahlen (Sekunden)" - }, - "environmentUpdateInterval": { - "label": "Aktualisierungsintervall für Umweltdaten (Sekunden)", - "description": "" - }, - "environmentMeasurementEnabled": { - "label": "Modul aktiviert", - "description": "Aktiviert die Telemetrie für Umweltdaten" - }, - "environmentScreenEnabled": { - "label": "OLED Anzeige aktivieren", - "description": "Zeige das Telemetriemodul auf der OLED Anzeige" - }, - "environmentDisplayFahrenheit": { - "label": "Temperatur in Fahrenheit", - "description": "Temperatur in Fahrenheit anzeigen" - }, - "airQualityEnabled": { - "label": "Luftqualität aktiviert", - "description": "Telemetrie für Luftqualität aktivieren" - }, - "airQualityInterval": { - "label": "Aktualisierungsintervall Luftqualität", - "description": "Wie oft werden Luftqualitätsdaten über das Netz gesendet" - }, - "powerMeasurementEnabled": { - "label": "Energiemessung aktiviert", - "description": "Aktiviere die Telemetrie für die Energiemessung" - }, - "powerUpdateInterval": { - "label": "Aktualisierungsintervall Energie", - "description": "Wie oft werden Energiedaten an das Netz gesendet" - }, - "powerScreenEnabled": { - "label": "Energieanzeige aktiviert", - "description": "Aktiviere die Anzeige für Energietelemetrie" - } - } + "page": { + "tabAmbientLighting": "Umgebungslicht", + "tabAudio": "Audio", + "tabCannedMessage": "Vordefinierte Nachrichten", + "tabDetectionSensor": "Erkennungssensor", + "tabExternalNotification": "Externe Benachrichtigung", + "tabMqtt": "MQTT", + "tabNeighborInfo": "Nachbarinformation", + "tabPaxcounter": "Pax Zähler", + "tabRangeTest": "Reichweitentest", + "tabSerial": "Seriell", + "tabStoreAndForward": "Speichern&Weiterleiten", + "tabTelemetry": "Telemetrie" + }, + "ambientLighting": { + "title": "Einstellung Umgebungsbeleuchtung", + "description": "Einstellungen für das Modul Umgebungsbeleuchtung", + "ledState": { + "label": "LED Status", + "description": "Setzt die LED auf ein oder aus" + }, + "current": { + "label": "Stromstärke", + "description": "Legt den Strom für den LED Ausgang fest. Standard ist 10" + }, + "red": { + "label": "Rot", + "description": "Legt den roten LED Wert fest. Bereich 0-255" + }, + "green": { + "label": "Grün", + "description": "Legt den grünen LED Wert fest. Bereich 0-255" + }, + "blue": { + "label": "Blau", + "description": "Legt den blauen LED Wert fest. Bereich 0-255" + } + }, + "audio": { + "title": "Audioeinstellungen", + "description": "Einstellungen für das Audiomodul", + "codec2Enabled": { + "label": "Codec 2 aktiviert", + "description": "Codec 2 Audiokodierung aktivieren" + }, + "pttPin": { + "label": "GPIO PTT", + "description": "Für PTT verwendeter GPIO Pin" + }, + "bitrate": { + "label": "Bitrate", + "description": "Bitrate zur Audiokodierung" + }, + "i2sWs": { + "label": "i2S WS", + "description": "GPIO Pin für i2S WS" + }, + "i2sSd": { + "label": "i2S SD", + "description": "GPIO Pin für i2S SD" + }, + "i2sDin": { + "label": "i2S DIN", + "description": "GPIO Pin für i2S DIN" + }, + "i2sSck": { + "label": "i2S SCK", + "description": "GPIO Pin für i2S SCK" + } + }, + "cannedMessage": { + "title": "Einstellungen für vordefinierte Nachrichten", + "description": "Einstellungen für das Modul vordefinierte Nachrichten", + "moduleEnabled": { + "label": "Modul aktiviert", + "description": "Vordefinierte Nachrichten aktivieren" + }, + "rotary1Enabled": { + "label": "Drehgeber #1 aktiviert", + "description": "Drehgeber aktivieren" + }, + "inputbrokerPinA": { + "label": "Drehgeber Pin A", + "description": "GPIO Pin Wert (1-39) für Drehgeber Pin A" + }, + "inputbrokerPinB": { + "label": "Drehgeber Pin B", + "description": "GPIO Pin Wert (1-39) für Drehgeber Pin B" + }, + "inputbrokerPinPress": { + "label": "Drehgeber Pin Taste", + "description": "GPIO Pin Wert (1-39) für Drehgeber Pin Taste" + }, + "inputbrokerEventCw": { + "label": "Ereignis im Uhrzeigersinn", + "description": "Eingabeereignis auswählen." + }, + "inputbrokerEventCcw": { + "label": "Ereignis gegen Uhrzeigersinn", + "description": "Eingabeereignis auswählen." + }, + "inputbrokerEventPress": { + "label": "Ereignis Tastendruck", + "description": "Eingabeereignis auswählen." + }, + "updown1Enabled": { + "label": "Geber Hoch/Runter aktiviert", + "description": "Aktiviere Geber Hoch/Runter" + }, + "allowInputSource": { + "label": "Eingabequelle zulassen", + "description": "Wählen Sie aus: '_any', 'rotEnc1', 'upDownEnc1', 'cardkb'" + }, + "sendBell": { + "label": "Sende Glocke", + "description": "Sendet ein Klingelzeichen (Glocke) mit jeder Nachricht" + } + }, + "detectionSensor": { + "title": "Sensoreinstellungen für Erkennung", + "description": "Einstellungen für das Erkennungssensormodul", + "enabled": { + "label": "Aktiviert", + "description": "Erkennungssensormodul aktivieren oder deaktivieren" + }, + "minimumBroadcastSecs": { + "label": "Minimale Übertragungszeit alle Sekunden", + "description": "Das Intervall in Sekunden, wie oft eine Nachricht an das Netz gesendet wird, wenn eine Statusänderung erkannt wurde" + }, + "stateBroadcastSecs": { + "label": "Statusübertragung alle Sekunden", + "description": "Das Intervall in Sekunden, wie oft eine Nachricht mit dem aktuellen Status an das Netz gesendet wird, unabhängig von Änderungen" + }, + "sendBell": { + "label": "Sende Glocke", + "description": "ASCII-Glocke mit Warnmeldung senden" + }, + "name": { + "label": "Anzeigename", + "description": "Formatierte Nachricht die an das Netz gesendet wird, maximal 20 Zeichen" + }, + "monitorPin": { + "label": "GPIO Pin überwachen", + "description": "Der GPIO Pin zur Überwachung von Statusänderungen" + }, + "detectionTriggerType": { + "label": "Auslösetyp der Erkennung", + "description": "Die Art des zu verwendenden Auslöseereignisses" + }, + "usePullup": { + "label": "Pullup verwenden", + "description": "Gibt an, ob der INPUT_PULLUP Modus für GPIO Pin verwendet wird oder nicht" + } + }, + "externalNotification": { + "title": "Einstellungen für externe Benachrichtigungen", + "description": "Einstellung für das Modul externe Benachrichtigung", + "enabled": { + "label": "Modul aktiviert", + "description": "Externe Benachrichtigung aktivieren" + }, + "outputMs": { + "label": "Ausgabe MS", + "description": "Ausgabe MS" + }, + "output": { + "label": "Ausgabe", + "description": "Ausgabe" + }, + "outputVibra": { + "label": "Ausgabe Vibration", + "description": "Ausgabe Vibration" + }, + "outputBuzzer": { + "label": "Ausgabe Summer", + "description": "Ausgabe Summer" + }, + "active": { + "label": "Aktiv", + "description": "Aktiv" + }, + "alertMessage": { + "label": "Warnmeldung", + "description": "Warnmeldung" + }, + "alertMessageVibra": { + "label": "Vibration bei Warnmeldung", + "description": "Vibration bei Warnmeldung" + }, + "alertMessageBuzzer": { + "label": "Summer bei Warnmeldung", + "description": "Summer bei Warnmeldung" + }, + "alertBell": { + "label": "Warnglocke", + "description": "Soll beim Empfang eines eingehenden Klingelzeichens (Glocke) eine Warnung ausgelöst werden?" + }, + "alertBellVibra": { + "label": "Vibration bei Klingelzeichen", + "description": "Vibration bei Klingelzeichen" + }, + "alertBellBuzzer": { + "label": "Summer bei Klingelzeichen", + "description": "Summer bei Klingelzeichen" + }, + "usePwm": { + "label": "PWM verwenden", + "description": "PWM verwenden" + }, + "nagTimeout": { + "label": "Nervige Verzögerung", + "description": "Nervige Verzögerung" + }, + "useI2sAsBuzzer": { + "label": "I2S GPIO Pin als Summer verwenden", + "description": "I2S GPIO Pin als Summerausgang definieren" + } + }, + "mqtt": { + "title": "MQTT Einstellungen", + "description": "Einstellungen für das MQTT Modul", + "enabled": { + "label": "Aktiviert", + "description": "MQTT aktivieren oder deaktivieren" + }, + "address": { + "label": "MQTT Server Adresse", + "description": "MQTT Serveradresse für Standard/benutzerdefinierte Server" + }, + "username": { + "label": "MQTT Benutzername", + "description": "MQTT Benutzername für Standard/benutzerdefinierte Server" + }, + "password": { + "label": "MQTT Passwort", + "description": "MQTT Passwort für Standard/benutzerdefinierte Server" + }, + "encryptionEnabled": { + "label": "Verschlüsselung aktiviert", + "description": "MQTT-Verschlüsselung aktivieren oder deaktivieren. Hinweis: Alle Nachrichten werden unverschlüsselt an den MQTT-Broker gesendet, wenn diese Option nicht aktiviert ist. Unabhängig von der eingestellten Kanalverschlüsselung. Einschließlich der Standortdaten." + }, + "jsonEnabled": { + "label": "JSON aktiviert", + "description": "Gibt an, ob JSON Nachrichten über MQTT gesendet oder empfangen werden sollen" + }, + "tlsEnabled": { + "label": "TLS aktiviert", + "description": "TLS aktivieren oder deaktivieren" + }, + "root": { + "label": "Hauptthema", + "description": "MQTT Hauptthema für Standard/Benutzerdefinierte Server" + }, + "proxyToClientEnabled": { + "label": "MQTT Client Proxy aktiviert", + "description": "Verwendet die Netzwerkverbindung zum Austausch von MQTT Nachrichten mit dem Client." + }, + "mapReportingEnabled": { + "label": "Kartenberichte aktiviert", + "description": "Ihr Knoten sendet in regelmäßigen Abständen eine unverschlüsselte Nachricht mit Kartenbericht an den konfigurierten MQTT-Server. Einschließlich ID, langen und kurzen Namen, ungefährer Standort, Hardwaremodell, Geräterolle, Firmware-Version, LoRa Region, Modem-Voreinstellung und Name des Primärkanal." + }, + "mapReportSettings": { + "publishIntervalSecs": { + "label": "Veröffentlichungsintervall Kartenbericht (s)", + "description": "Intervall in Sekunden, um Kartenberichte zu veröffentlichen" + }, + "positionPrecision": { + "label": "Ungefährer Standort", + "description": "Der geteilte Standort mit einer Genauigkeit innerhalb dieser Entfernung", + "options": { + "metric_km23": "Innerhalb von 23 km", + "metric_km12": "Innerhalb von 12 km", + "metric_km5_8": "Innerhalb von 5,8 km", + "metric_km2_9": "Innerhalb von 2,9 km", + "metric_km1_5": "Innerhalb von 1,5 km", + "metric_m700": "Innerhalb von 700 m", + "metric_m350": "Innerhalb von 350 m", + "metric_m200": "Innerhalb von 200 m", + "metric_m90": "Innerhalb von 90 m", + "metric_m50": "Innerhalb von 50 m", + "imperial_mi15": "Innerhalb von 15 Meilen", + "imperial_mi7_3": "Innerhalb von 7,3 Meilen", + "imperial_mi3_6": "Innerhalb von 3,6 Meilen", + "imperial_mi1_8": "Innerhalb von 1,8 Meilen", + "imperial_mi0_9": "Innerhalb von 0,9 Meilen", + "imperial_mi0_5": "Innerhalb von 0,5 Meilen", + "imperial_mi0_2": "Innerhalb von 0,2 Meilen", + "imperial_ft600": "Innerhalb von 600 Fuß", + "imperial_ft300": "Innerhalb von 300 Fuß", + "imperial_ft150": "Innerhalb von 150 Fuß" + } + } + } + }, + "neighborInfo": { + "title": "Einstellung Nachbarinformation", + "description": "Einstellungen für das Modul Nachbarinformation", + "enabled": { + "label": "Aktiviert", + "description": "Nachbarinformation Modul aktivieren oder deaktivieren" + }, + "updateInterval": { + "label": "Aktualisierungsintervall", + "description": "Intervall in Sekunden, wie oft die Nachbarinformation an das Netz gesendet wird" + } + }, + "paxcounter": { + "title": "Einstellung für Pax Zähler", + "description": "Einstellungen für das Modul Pax Zähler", + "enabled": { + "label": "Modul aktiviert", + "description": "Aktiviere Pax Zähler" + }, + "paxcounterUpdateInterval": { + "label": "Aktualisierungsintervall (Sekunden)", + "description": "Wie lange soll zwischen dem Senden von Pax Zählernachrichten gewartet werden" + }, + "wifiThreshold": { + "label": "WLAN RSSI Grenzwert", + "description": "Bei welchem WLAN RSSI Grenzwert sollte der Zähler erhöht werden. Standardwert -80" + }, + "bleThreshold": { + "label": "BLE RSSI Grenzwert", + "description": "Bei welchem BLE RSSI Grenzwert sollte der Zähler erhöht werden. Standardwert -80" + } + }, + "rangeTest": { + "title": "Einstellung Reichweitentest", + "description": "Einstellungen für das Modul Reichweitentest", + "enabled": { + "label": "Modul aktiviert", + "description": "Reichweitentest aktivieren" + }, + "sender": { + "label": "Nachrichtenintervall", + "description": "Wie lange soll zwischen dem Senden von Testnachrichten gewartet werden" + }, + "save": { + "label": "CSV im internen Speicher abspeichern", + "description": "Nur für ESP32" + } + }, + "serial": { + "title": "Serielle Einstellungen", + "description": "Einstellungen für das serielle Modul", + "enabled": { + "label": "Modul aktiviert", + "description": "Serielle Ausgabe aktivieren" + }, + "echo": { + "label": "Echo", + "description": "Wenn aktiviert, werden alle Nachrichten, die Sie senden, an Ihr Gerät zurückgesendet" + }, + "rxd": { + "label": "GPIO Empfangen", + "description": "Setzen Sie den GPIO Pin, den Sie eingerichtet haben, als RXD Pin." + }, + "txd": { + "label": "GPIO Senden", + "description": "Setzen Sie den GPIO Pin, den Sie eingerichtet haben, als TXD Pin." + }, + "baud": { + "label": "Baudrate", + "description": "Serielle Baudrate" + }, + "timeout": { + "label": "Zeitlimit erreicht", + "description": "Wartezeit in Sekunden bis eine Nachricht als gesendet angenommen wird" + }, + "mode": { + "label": "Betriebsmodus", + "description": "Modus auswählen" + }, + "overrideConsoleSerialPort": { + "label": "Seriellen Port der Konsole überschreiben", + "description": "Wenn Sie einen seriellen Port an die Konsole angeschlossen haben, wird diese überschrieben." + } + }, + "storeForward": { + "title": "Speichern & Weiterleiten Einstellungen", + "description": "Einstellungen für das Modul Speichern & Weiterleiten", + "enabled": { + "label": "Modul aktiviert", + "description": "Speichern & Weiterleiten aktivieren" + }, + "heartbeat": { + "label": "Herzschlag aktiviert", + "description": "Herzschlag für Speichern & Weiterleiten aktivieren" + }, + "records": { + "label": "Anzahl Einträge", + "description": "Anzahl der zu speichernden Datensätze" + }, + "historyReturnMax": { + "label": "Verlauf Rückgabewert maximal", + "description": "Maximale Anzahl an zurückzugebenden Datensätzen" + }, + "historyReturnWindow": { + "label": "Zeitraum Rückgabewert", + "description": "Datensätze aus diesem Zeitfenster zurückgeben (Minuten)" + } + }, + "telemetry": { + "title": "Telemetrieeinstellungen", + "description": "Einstellungen für das Telemetriemodul", + "deviceUpdateInterval": { + "label": "Gerätekennzahlen", + "description": "Aktualisierungsintervall für Gerätekennzahlen (Sekunden)" + }, + "environmentUpdateInterval": { + "label": "Aktualisierungsintervall für Umweltdaten (Sekunden)", + "description": "" + }, + "environmentMeasurementEnabled": { + "label": "Modul aktiviert", + "description": "Aktiviert die Telemetrie für Umweltdaten" + }, + "environmentScreenEnabled": { + "label": "OLED Anzeige aktivieren", + "description": "Zeige das Telemetriemodul auf der OLED Anzeige" + }, + "environmentDisplayFahrenheit": { + "label": "Temperatur in Fahrenheit", + "description": "Temperatur in Fahrenheit anzeigen" + }, + "airQualityEnabled": { + "label": "Luftqualität aktiviert", + "description": "Telemetrie für Luftqualität aktivieren" + }, + "airQualityInterval": { + "label": "Aktualisierungsintervall Luftqualität", + "description": "Wie oft werden Luftqualitätsdaten über das Netz gesendet" + }, + "powerMeasurementEnabled": { + "label": "Energiemessung aktiviert", + "description": "Aktiviere die Telemetrie für die Energiemessung" + }, + "powerUpdateInterval": { + "label": "Aktualisierungsintervall Energie", + "description": "Wie oft werden Energiedaten an das Netz gesendet" + }, + "powerScreenEnabled": { + "label": "Energieanzeige aktiviert", + "description": "Aktiviere die Anzeige für Energietelemetrie" + } + } } diff --git a/packages/web/public/i18n/locales/de-DE/nodes.json b/packages/web/public/i18n/locales/de-DE/nodes.json index 969d6fbe3..5995c8412 100644 --- a/packages/web/public/i18n/locales/de-DE/nodes.json +++ b/packages/web/public/i18n/locales/de-DE/nodes.json @@ -1,63 +1,59 @@ { - "nodeDetail": { - "publicKeyEnabled": { - "label": "Öffentlicher Schlüssel aktiviert" - }, - "noPublicKey": { - "label": "Kein öffentlicher Schlüssel" - }, - "directMessage": { - "label": "Direktnachricht {{shortName}}" - }, - "favorite": { - "label": "Favorit", - "tooltip": "Diesen Knoten zu Favoriten hinzufügen oder entfernen" - }, - "notFavorite": { - "label": "Kein Favorit" - }, - "error": { - "label": "Fehler", - "text": "Beim Abrufen der Knotendetails ist ein Fehler aufgetreten. Bitte versuchen Sie es später erneut." - }, - "status": { - "heard": "Gehört", - "mqtt": "MQTT" - }, - "elevation": { - "label": "Höhe" - }, - "channelUtil": { - "label": "Kanal-Auslastung" - }, - "airtimeUtil": { - "label": "Sendezeit-Auslastung" - } - }, - "nodesTable": { - "headings": { - "longName": "Langer Name", - "connection": "Verbindung", - "lastHeard": "Zuletzt gehört", - "encryption": "Verschlüsselung", - "model": "Modell", - "macAddress": "MAC Adresse" - }, - "connectionStatus": { - "direct": "Direkt", - "away": "entfernt", - "unknown": "-", - "viaMqtt": ", über MQTT" - }, - "lastHeardStatus": { - "never": "Nie" - } - }, - "actions": { - "added": "Hinzugefügt", - "removed": "Entfernt", - "ignoreNode": "Knoten ignorieren", - "unignoreNode": "Knoten akzeptieren", - "requestPosition": "Standort anfordern" - } + "nodeDetail": { + "publicKeyEnabled": { + "label": "Öffentlicher Schlüssel aktiviert" + }, + "noPublicKey": { + "label": "Kein öffentlicher Schlüssel" + }, + "directMessage": { + "label": "Direktnachricht {{shortName}}" + }, + "favorite": { + "label": "Favorit", + "tooltip": "Diesen Knoten zu Favoriten hinzufügen oder entfernen" + }, + "notFavorite": { + "label": "Kein Favorit" + }, + "error": { + "label": "Fehler", + "text": "Beim Abrufen der Knotendetails ist ein Fehler aufgetreten. Bitte versuchen Sie es später erneut." + }, + "status": { + "heard": "Gehört", + "mqtt": "MQTT" + }, + "elevation": { + "label": "Höhe" + }, + "channelUtil": { + "label": "Kanal-Auslastung" + }, + "airtimeUtil": { + "label": "Sendezeit-Auslastung" + } + }, + "nodesTable": { + "headings": { + "longName": "Langer Name", + "connection": "Verbindung", + "lastHeard": "Zuletzt gehört", + "encryption": "Verschlüsselung", + "model": "Modell", + "macAddress": "MAC Adresse" + }, + "connectionStatus": { + "direct": "Direkt", + "away": "entfernt", + "viaMqtt": ", über MQTT" + } + }, + "actions": { + "added": "Hinzugefügt", + "removed": "Entfernt", + "ignoreNode": "Knoten ignorieren", + "unignoreNode": "Knoten akzeptieren", + "requestPosition": "Standort anfordern" + } } diff --git a/packages/web/public/i18n/locales/de-DE/ui.json b/packages/web/public/i18n/locales/de-DE/ui.json index ccd788200..43670beeb 100644 --- a/packages/web/public/i18n/locales/de-DE/ui.json +++ b/packages/web/public/i18n/locales/de-DE/ui.json @@ -1,228 +1,230 @@ { - "navigation": { - "title": "Navigation", - "messages": "Nachrichten", - "map": "Karte", - "config": "Einstellungen", - "radioConfig": "Funkgerätekonfiguration", - "moduleConfig": "Moduleinstellungen", - "channels": "Kanäle", - "nodes": "Knoten" - }, - "app": { - "title": "Meshtastic", - "logo": "Meshtastic Logo" - }, - "sidebar": { - "collapseToggle": { - "button": { - "open": "Seitenleiste öffnen", - "close": "Seitenleiste schließen" - } - }, - "deviceInfo": { - "volts": "{{voltage}} Volt", - "firmware": { - "title": "Firmware", - "version": "v{{version}}", - "buildDate": "Erstelldatum: {{date}}" - }, - "deviceName": { - "title": "Gerätename", - "changeName": "Gerätenamen ändern", - "placeholder": "Gerätenamen eingeben" - }, - "editDeviceName": "Gerätenamen bearbeiten" - } - }, - "batteryStatus": { - "charging": "{{level}}% Ladung", - "pluggedIn": "Wird geladen", - "title": "Batterie" - }, - "search": { - "nodes": "Knoten suchen...", - "channels": "Kanäle suchen...", - "commandPalette": "Befehle suchen..." - }, - "toast": { - "positionRequestSent": { - "title": "Standortanfrage gesendet." - }, - "requestingPosition": { - "title": "Standort wird angefordert, bitte warten..." - }, - "sendingTraceroute": { - "title": "Sende Traceroute, bitte warten..." - }, - "tracerouteSent": { - "title": "Traceroute gesendet." - }, - "savedChannel": { - "title": "Gespeicherter Kanal: {{channelName}}" - }, - "messages": { - "pkiEncryption": { - "title": "Der Chat verwendet PKI-Verschlüsselung." - }, - "pskEncryption": { - "title": "Chat verwendet PSK-Verschlüsselung." - } - }, - "configSaveError": { - "title": "Fehler beim Speichern von Einstellung", - "description": "Beim Speichern der Einstellungen ist ein Fehler aufgetreten." - }, - "validationError": { - "title": "Einstellungsfehler vorhanden", - "description": "Bitte korrigieren Sie die Einstellungsfehler vor dem Speichern." - }, - "saveSuccess": { - "title": "Einstellungen speichern", - "description": "Die Einstellungsänderung {{case}} wurde gespeichert." - }, - "favoriteNode": { - "title": "{{action}} {{nodeName}} {{direction}} Favoriten.", - "action": { - "added": "Hinzugefügt", - "removed": "Entfernt", - "to": "bis", - "from": "von" - } - }, - "ignoreNode": { - "title": "{{action}} {{nodeName}} {{direction}} Ignorierliste", - "action": { - "added": "Hinzugefügt", - "removed": "Entfernt", - "to": "bis", - "from": "von" - } - } - }, - "notifications": { - "copied": { - "label": "Kopiert!" - }, - "copyToClipboard": { - "label": "In die Zwischenablage kopieren" - }, - "hidePassword": { - "label": "Passwort verbergen" - }, - "showPassword": { - "label": "Passwort anzeigen" - }, - "deliveryStatus": { - "delivered": "Zugestellt", - "failed": "Zustellung fehlgeschlagen", - "waiting": "Warte...", - "unknown": "Unbekannt" - } - }, - "general": { - "label": "Allgemein" - }, - "hardware": { - "label": "Hardware" - }, - "metrics": { - "label": "Messgrößen" - }, - "role": { - "label": "Rolle" - }, - "filter": { - "label": "Filter" - }, - "advanced": { - "label": "Fortgeschritten" - }, - "clearInput": { - "label": "Eingabe löschen" - }, - "resetFilters": { - "label": "Filter zurücksetzen" - }, - "nodeName": { - "label": "Knotenname/-nummer", - "placeholder": "Meshtastic 1234" - }, - "airtimeUtilization": { - "label": "Sendezeit-Auslastung (%)" - }, - "batteryLevel": { - "label": "Akkustand (%)", - "labelText": "Akkustand (%): {{value}}" - }, - "batteryVoltage": { - "label": "Batteriespannung (V)", - "title": "Spannung" - }, - "channelUtilization": { - "label": "Kanalauslastung (%)" - }, - "hops": { - "direct": "Direkt", - "label": "Anzahl Hops", - "text": "Sprungweite: {{value}}" - }, - "lastHeard": { - "label": "Zuletzt gehört", - "labelText": "Zuletzt gehört: {{value}}", - "nowLabel": "Jetzt" - }, - "snr": { - "label": "SNR (dB)" - }, - "favorites": { - "label": "Favoriten" - }, - "hide": { - "label": "Ausblenden" - }, - "showOnly": { - "label": "Zeige nur" - }, - "viaMqtt": { - "label": "Über MQTT verbunden" - }, - "hopsUnknown": { - "label": "Unbekannte Sprungweite" - }, - "showUnheard": { - "label": "Nie gehört" - }, - "language": { - "label": "Sprache", - "changeLanguage": "Sprache ändern" - }, - "theme": { - "dark": "Dunkel", - "light": "Hell", - "system": "Automatisch", - "changeTheme": "Farbschema ändern" - }, - "errorPage": { - "title": "Das ist ein wenig peinlich...", - "description1": "Es tut uns wirklich leid, aber im Webclient ist ein Fehler aufgetreten, der es zum Absturz gebracht hat.
Das soll nicht passieren, und wir arbeiten hart daran, es zu beheben.", - "description2": "Der beste Weg, um zu verhindern, dass sich dies Ihnen oder irgendjemand anderem wiederholt, besteht darin, uns über dieses Problem zu berichten.", - "reportInstructions": "Bitte fügen Sie folgende Informationen in Ihren Bericht ein:", - "reportSteps": { - "step1": "Was haben Sie getan, als der Fehler aufgetreten ist", - "step2": "Was haben Sie erwartet", - "step3": "Was tatsächlich passiert ist", - "step4": "Sonstige relevante Informationen" - }, - "reportLink": "Sie können das Problem auf unserem <0>GitHub melden", - "dashboardLink": "Zurück zum <0>Dashboard", - "detailsSummary": "Fehlerdetails", - "errorMessageLabel": "Fehlermeldungen:", - "stackTraceLabel": "Stapelabzug:", - "fallbackError": "{{error}}" - }, - "footer": { - "text": "Powered by <0>▲ Vercel | Meshtastic®️ ist eine eingetragene Marke der Meshtastic LLC. | <1>Rechtliche Informationen", - "commitSha": "Commit SHA: {{sha}}" - } + "navigation": { + "title": "Navigation", + "messages": "Nachrichten", + "map": "Karte", + "settings": "Einstellungen", + "channels": "Kanäle", + "radioConfig": "Funkgerätekonfiguration", + "deviceConfig": "Geräteeinstellungen", + "moduleConfig": "Moduleinstellungen", + "manageConnections": "Verbindungen verwalten", + "nodes": "Knoten" + }, + "app": { + "title": "Meshtastic", + "logo": "Meshtastic Logo" + }, + "sidebar": { + "collapseToggle": { + "button": { + "open": "Seitenleiste öffnen", + "close": "Seitenleiste schließen" + } + }, + "deviceInfo": { + "volts": "{{voltage}} Volt", + "firmware": { + "title": "Firmware", + "version": "v{{version}}", + "buildDate": "Erstelldatum: {{date}}" + } + } + }, + "batteryStatus": { + "charging": "{{level}}% Ladung", + "pluggedIn": "Wird geladen", + "title": "Batterie" + }, + "search": { + "nodes": "Knoten suchen...", + "channels": "Kanäle suchen...", + "commandPalette": "Befehle suchen..." + }, + "toast": { + "positionRequestSent": { + "title": "Standortanfrage gesendet." + }, + "requestingPosition": { + "title": "Standort wird angefordert, bitte warten..." + }, + "sendingTraceroute": { + "title": "Sende Traceroute, bitte warten..." + }, + "tracerouteSent": { + "title": "Traceroute gesendet." + }, + "savedChannel": { + "title": "Gespeicherter Kanal: {{channelName}}" + }, + "messages": { + "pkiEncryption": { + "title": "Der Chat verwendet PKI-Verschlüsselung." + }, + "pskEncryption": { + "title": "Chat verwendet PSK-Verschlüsselung." + } + }, + "configSaveError": { + "title": "Fehler beim Speichern von Einstellung", + "description": "Beim Speichern der Einstellungen ist ein Fehler aufgetreten." + }, + "validationError": { + "title": "Einstellungsfehler vorhanden", + "description": "Bitte korrigieren Sie die Einstellungsfehler vor dem Speichern." + }, + "saveSuccess": { + "title": "Einstellungen speichern", + "description": "Die Einstellungsänderung {{case}} wurde gespeichert." + }, + "saveAllSuccess": { + "title": "Gespeichert", + "description": "Alle Einstellungsänderungen wurden gespeichert." + }, + "favoriteNode": { + "title": "{{action}} {{nodeName}} {{direction}} Favoriten.", + "action": { + "added": "Hinzugefügt", + "removed": "Entfernt", + "to": "bis", + "from": "von" + } + }, + "ignoreNode": { + "title": "{{action}} {{nodeName}} {{direction}} Ignorierliste", + "action": { + "added": "Hinzugefügt", + "removed": "Entfernt", + "to": "bis", + "from": "von" + } + } + }, + "notifications": { + "copied": { + "label": "Kopiert!" + }, + "copyToClipboard": { + "label": "In die Zwischenablage kopieren" + }, + "hidePassword": { + "label": "Passwort verbergen" + }, + "showPassword": { + "label": "Passwort anzeigen" + }, + "deliveryStatus": { + "delivered": "Zugestellt", + "failed": "Zustellung fehlgeschlagen", + "waiting": "Warte...", + "unknown": "Unbekannt" + } + }, + "general": { + "label": "Allgemein" + }, + "hardware": { + "label": "Hardware" + }, + "metrics": { + "label": "Messgrößen" + }, + "role": { + "label": "Rolle" + }, + "filter": { + "label": "Filter" + }, + "advanced": { + "label": "Fortgeschritten" + }, + "clearInput": { + "label": "Eingabe löschen" + }, + "resetFilters": { + "label": "Filter zurücksetzen" + }, + "nodeName": { + "label": "Knotenname/-nummer", + "placeholder": "Meshtastic 1234" + }, + "airtimeUtilization": { + "label": "Sendezeit-Auslastung (%)", + "short": "Sendezeit-Auslastung. (%)" + }, + "batteryLevel": { + "label": "Akkustand (%)", + "labelText": "Akkustand (%): {{value}}" + }, + "batteryVoltage": { + "label": "Batteriespannung (V)", + "title": "Spannung" + }, + "channelUtilization": { + "label": "Kanalauslastung (%)", + "short": "Kanal-Auslastung. (%)" + }, + "hops": { + "direct": "Direkt", + "label": "Anzahl Hops", + "text": "Sprungweite: {{value}}" + }, + "lastHeard": { + "label": "Zuletzt gehört", + "labelText": "Zuletzt gehört: {{value}}", + "nowLabel": "Jetzt" + }, + "snr": { + "label": "SNR (dB)" + }, + "favorites": { + "label": "Favoriten" + }, + "hide": { + "label": "Ausblenden" + }, + "showOnly": { + "label": "Zeige nur" + }, + "viaMqtt": { + "label": "Über MQTT verbunden" + }, + "hopsUnknown": { + "label": "Unbekannte Sprungweite" + }, + "showUnheard": { + "label": "Nie gehört" + }, + "language": { + "label": "Sprache", + "changeLanguage": "Sprache ändern" + }, + "theme": { + "dark": "Dunkel", + "light": "Hell", + "system": "Automatisch", + "changeTheme": "Farbschema ändern" + }, + "errorPage": { + "title": "Das ist ein wenig peinlich...", + "description1": "Es tut uns wirklich leid, aber im Webclient ist ein Fehler aufgetreten, der es zum Absturz gebracht hat.
Das soll nicht passieren, und wir arbeiten hart daran, es zu beheben.", + "description2": "Der beste Weg, um zu verhindern, dass sich dies Ihnen oder irgendjemand anderem wiederholt, besteht darin, uns über dieses Problem zu berichten.", + "reportInstructions": "Bitte fügen Sie folgende Informationen in Ihren Bericht ein:", + "reportSteps": { + "step1": "Was haben Sie getan, als der Fehler aufgetreten ist", + "step2": "Was haben Sie erwartet", + "step3": "Was tatsächlich passiert ist", + "step4": "Sonstige relevante Informationen" + }, + "reportLink": "Sie können das Problem auf unserem <0>GitHub melden", + "connectionsLink": "Zurück zu den <0>Verbindungen", + "detailsSummary": "Fehlerdetails", + "errorMessageLabel": "Fehlermeldungen:", + "stackTraceLabel": "Stapelabzug:", + "fallbackError": "{{error}}" + }, + "footer": { + "text": "Powered by <0>▲ Vercel | Meshtastic®️ ist eine eingetragene Marke der Meshtastic LLC. | <1>Rechtliche Informationen", + "commitSha": "Commit SHA: {{sha}}" + } } diff --git a/packages/web/public/i18n/locales/en/common.json b/packages/web/public/i18n/locales/en/common.json index 6c25fc9f1..a3959dca6 100644 --- a/packages/web/public/i18n/locales/en/common.json +++ b/packages/web/public/i18n/locales/en/common.json @@ -1,14 +1,18 @@ { "button": { "apply": "Apply", + "addConnection": "Add Connection", + "saveConnection": "Save connection", "backupKey": "Backup Key", "cancel": "Cancel", + "connect": "Connect", "clearMessages": "Clear Messages", "close": "Close", "confirm": "Confirm", "delete": "Delete", "dismiss": "Dismiss", "download": "Download", + "disconnect": "Disconnect", "export": "Export", "generate": "Generate", "regenerate": "Regenerate", @@ -21,7 +25,10 @@ "requestNewKeys": "Request New Keys", "requestPosition": "Request Position", "reset": "Reset", + "retry": "Retry", "save": "Save", + "setDefault": "Set as default", + "unsetDefault": "Unset default", "scanQr": "Scan QR Code", "traceRoute": "Trace Route", "submit": "Submit" @@ -45,6 +52,7 @@ "unknown": "Unknown hops away" }, "megahertz": "MHz", + "kilohertz": "kHz", "raw": "raw", "meter": { "one": "Meter", "plural": "Meters", "suffix": "m" }, "kilometer": { "one": "Kilometer", "plural": "Kilometers", "suffix": "km" }, diff --git a/packages/web/public/i18n/locales/en/config.json b/packages/web/public/i18n/locales/en/config.json new file mode 100644 index 000000000..dd1ba678a --- /dev/null +++ b/packages/web/public/i18n/locales/en/config.json @@ -0,0 +1,470 @@ +{ + "page": { + "title": "Settings", + "tabUser": "User", + "tabChannels": "Channels", + "tabBluetooth": "Bluetooth", + "tabDevice": "Device", + "tabDisplay": "Display", + "tabLora": "LoRa", + "tabNetwork": "Network", + "tabPosition": "Position", + "tabPower": "Power", + "tabSecurity": "Security" + }, + "sidebar": { + "label": "Configuration" + }, + "device": { + "title": "Device Settings", + "description": "Settings for the device", + "buttonPin": { + "description": "Button pin override", + "label": "Button Pin" + }, + "buzzerPin": { + "description": "Buzzer pin override", + "label": "Buzzer Pin" + }, + "disableTripleClick": { + "description": "Disable triple click", + "label": "Disable Triple Click" + }, + "doubleTapAsButtonPress": { + "description": "Treat double tap as button press", + "label": "Double Tap as Button Press" + }, + "ledHeartbeatDisabled": { + "description": "Disable default blinking LED", + "label": "LED Heartbeat Disabled" + }, + "nodeInfoBroadcastInterval": { + "description": "How often to broadcast node info", + "label": "Node Info Broadcast Interval" + }, + "posixTimezone": { + "description": "The POSIX timezone string for the device", + "label": "POSIX Timezone" + }, + "rebroadcastMode": { + "description": "How to handle rebroadcasting", + "label": "Rebroadcast Mode" + }, + "role": { + "description": "What role the device performs on the mesh", + "label": "Role" + } + }, + "bluetooth": { + "title": "Bluetooth Settings", + "description": "Settings for the Bluetooth module", + "note": "Note: Some devices (ESP32) cannot use both Bluetooth and WiFi at the same time.", + "enabled": { + "description": "Enable or disable Bluetooth", + "label": "Enabled" + }, + "pairingMode": { + "description": "Pin selection behaviour.", + "label": "Pairing mode" + }, + "pin": { + "description": "Pin to use when pairing", + "label": "Pin" + } + }, + "display": { + "description": "Settings for the device display", + "title": "Display Settings", + "headingBold": { + "description": "Bolden the heading text", + "label": "Bold Heading" + }, + "carouselDelay": { + "description": "How fast to cycle through windows", + "label": "Carousel Delay" + }, + "compassNorthTop": { + "description": "Fix north to the top of compass", + "label": "Compass North Top" + }, + "displayMode": { + "description": "Screen layout variant", + "label": "Display Mode" + }, + "displayUnits": { + "description": "Display metric or imperial units", + "label": "Display Units" + }, + "flipScreen": { + "description": "Flip display 180 degrees", + "label": "Flip Screen" + }, + "gpsDisplayUnits": { + "description": "Coordinate display format", + "label": "GPS Display Units" + }, + "oledType": { + "description": "Type of OLED screen attached to the device", + "label": "OLED Type" + }, + "screenTimeout": { + "description": "Turn off the display after this long", + "label": "Screen Timeout" + }, + "twelveHourClock": { + "description": "Use 12-hour clock format", + "label": "12-Hour Clock" + }, + "wakeOnTapOrMotion": { + "description": "Wake the device on tap or motion", + "label": "Wake on Tap or Motion" + } + }, + "lora": { + "title": "Mesh Settings", + "description": "Settings for the LoRa mesh", + "bandwidth": { + "description": "Channel bandwidth in kHz", + "label": "Bandwidth" + }, + "boostedRxGain": { + "description": "Boosted RX gain", + "label": "Boosted RX Gain" + }, + "codingRate": { + "description": "The denominator of the coding rate", + "label": "Coding Rate" + }, + "frequencyOffset": { + "description": "Frequency offset to correct for crystal calibration errors", + "label": "Frequency Offset" + }, + "frequencySlot": { + "description": "LoRa frequency channel number", + "label": "Frequency Slot" + }, + "hopLimit": { + "description": "Maximum number of hops", + "label": "Hop Limit" + }, + "ignoreMqtt": { + "description": "Don't forward MQTT messages over the mesh", + "label": "Ignore MQTT" + }, + "modemPreset": { + "description": "Modem preset to use", + "label": "Modem Preset" + }, + "okToMqtt": { + "description": "When set to true, this configuration indicates that the user approves the packet to be uploaded to MQTT. If set to false, remote nodes are requested not to forward packets to MQTT", + "label": "OK to MQTT" + }, + "overrideDutyCycle": { + "description": "Override Duty Cycle", + "label": "Override Duty Cycle" + }, + "overrideFrequency": { + "description": "Override frequency", + "label": "Override Frequency" + }, + "region": { + "description": "Sets the region for your node", + "label": "Region" + }, + "spreadingFactor": { + "description": "Indicates the number of chirps per symbol", + "label": "Spreading Factor" + }, + "transmitEnabled": { + "description": "Enable/Disable transmit (TX) from the LoRa radio", + "label": "Transmit Enabled" + }, + "transmitPower": { + "description": "Max transmit power", + "label": "Transmit Power" + }, + "usePreset": { + "description": "Use one of the predefined modem presets", + "label": "Use Preset" + }, + "meshSettings": { + "description": "Settings for the LoRa mesh", + "label": "Mesh Settings" + }, + "waveformSettings": { + "description": "Settings for the LoRa waveform", + "label": "Waveform Settings" + }, + "radioSettings": { + "label": "Radio Settings", + "description": "Settings for the LoRa radio" + } + }, + "network": { + "title": "WiFi Config", + "description": "WiFi radio configuration", + "note": "Note: Some devices (ESP32) cannot use both Bluetooth and WiFi at the same time.", + "addressMode": { + "description": "Address assignment selection", + "label": "Address Mode" + }, + "dns": { + "description": "DNS Server", + "label": "DNS" + }, + "ethernetEnabled": { + "description": "Enable or disable the Ethernet port", + "label": "Enabled" + }, + "gateway": { + "description": "Default Gateway", + "label": "Gateway" + }, + "ip": { + "description": "IP Address", + "label": "IP" + }, + "psk": { + "description": "Network password", + "label": "PSK" + }, + "ssid": { + "description": "Network name", + "label": "SSID" + }, + "subnet": { + "description": "Subnet Mask", + "label": "Subnet" + }, + "wifiEnabled": { + "description": "Enable or disable the WiFi radio", + "label": "Enabled" + }, + "meshViaUdp": { + "label": "Mesh via UDP" + }, + "ntpServer": { + "label": "NTP Server" + }, + "rsyslogServer": { + "label": "Rsyslog Server" + }, + "ethernetConfigSettings": { + "description": "Ethernet port configuration", + "label": "Ethernet Config" + }, + "ipConfigSettings": { + "description": "IP configuration", + "label": "IP Config" + }, + "ntpConfigSettings": { + "description": "NTP configuration", + "label": "NTP Config" + }, + "rsyslogConfigSettings": { + "description": "Rsyslog configuration", + "label": "Rsyslog Config" + }, + "udpConfigSettings": { + "description": "UDP over Mesh configuration", + "label": "UDP Config" + } + }, + "position": { + "title": "Position Settings", + "description": "Settings for the position module", + "broadcastInterval": { + "description": "How often your position is sent out over the mesh", + "label": "Broadcast Interval" + }, + "enablePin": { + "description": "GPS module enable pin override", + "label": "Enable Pin" + }, + "fixedPosition": { + "description": "Don't report GPS position, but a manually-specified one", + "label": "Fixed Position", + "latitude": { + "label": "Latitude", + "description": "Decimal degrees between -90 and 90 (e.g., 37.7749)" + }, + "longitude": { + "label": "Longitude", + "description": "Decimal degrees between -180 and 180 (e.g., -122.4194)" + }, + "altitude": { + "label": "Altitude", + "description": "Optional — enter the altitude in {{unit}} above sea level (e.g., 100). Leave blank if unknown or add extra height for antennas/masts." + } + }, + "gpsMode": { + "description": "Configure whether device GPS is Enabled, Disabled, or Not Present", + "label": "GPS Mode" + }, + "gpsUpdateInterval": { + "description": "How often a GPS fix should be acquired", + "label": "GPS Update Interval" + }, + "positionFlags": { + "description": "Optional fields to include when assembling position messages. The more fields are selected, the larger the message will be leading to longer airtime usage and a higher risk of packet loss.", + "label": "Position Flags" + }, + "receivePin": { + "description": "GPS module RX pin override", + "label": "Receive Pin" + }, + "smartPositionEnabled": { + "description": "Only send position when there has been a meaningful change in location", + "label": "Enable Smart Position" + }, + "smartPositionMinDistance": { + "description": "Minimum distance (in meters) that must be traveled before a position update is sent", + "label": "Smart Position Minimum Distance" + }, + "smartPositionMinInterval": { + "description": "Minimum interval (in seconds) that must pass before a position update is sent", + "label": "Smart Position Minimum Interval" + }, + "transmitPin": { + "description": "GPS module TX pin override", + "label": "Transmit Pin" + }, + "intervalsSettings": { + "description": "How often to send position updates", + "label": "Intervals" + }, + "flags": { + "placeholder": "Select position flags...", + "altitude": "Altitude", + "altitudeGeoidalSeparation": "Altitude Geoidal Separation", + "altitudeMsl": "Altitude is Mean Sea Level", + "dop": "Dilution of precision (DOP) PDOP used by default", + "hdopVdop": "If DOP is set, use HDOP / VDOP values instead of PDOP", + "numSatellites": "Number of satellites", + "sequenceNumber": "Sequence number", + "timestamp": "Timestamp", + "unset": "Unset", + "vehicleHeading": "Vehicle heading", + "vehicleSpeed": "Vehicle speed" + } + }, + "power": { + "adcMultiplierOverride": { + "description": "Used for tweaking battery voltage reading", + "label": "ADC Multiplier Override ratio" + }, + "ina219Address": { + "description": "Address of the INA219 battery monitor", + "label": "INA219 Address" + }, + "lightSleepDuration": { + "description": "How long the device will be in light sleep for", + "label": "Light Sleep Duration" + }, + "minimumWakeTime": { + "description": "Minimum amount of time the device will stay awake for after receiving a packet", + "label": "Minimum Wake Time" + }, + "noConnectionBluetoothDisabled": { + "description": "If the device does not receive a Bluetooth connection, the BLE radio will be disabled after this long", + "label": "No Connection Bluetooth Disabled" + }, + "powerSavingEnabled": { + "description": "Select if powered from a low-current source (i.e. solar), to minimize power consumption as much as possible.", + "label": "Enable power saving mode" + }, + "shutdownOnBatteryDelay": { + "description": "Automatically shutdown node after this long when on battery, 0 for indefinite", + "label": "Shutdown on battery delay" + }, + "superDeepSleepDuration": { + "description": "How long the device will be in super deep sleep for", + "label": "Super Deep Sleep Duration" + }, + "powerConfigSettings": { + "description": "Settings for the power module", + "label": "Power Config" + }, + "sleepSettings": { + "description": "Sleep settings for the power module", + "label": "Sleep Settings" + } + }, + "security": { + "description": "Settings for the Security configuration", + "title": "Security Settings", + "button_backupKey": "Backup Key", + "adminChannelEnabled": { + "description": "Allow incoming device control over the insecure legacy admin channel", + "label": "Allow Legacy Admin" + }, + "enableDebugLogApi": { + "description": "Output live debug logging over serial, view and export position-redacted device logs over Bluetooth", + "label": "Enable Debug Log API" + }, + "managed": { + "description": "If enabled, device configuration options are only able to be changed remotely by a Remote Admin node via admin messages. Do not enable this option unless at least one suitable Remote Admin node has been setup, and the public key is stored in one of the fields above.", + "label": "Managed" + }, + "privateKey": { + "description": "Used to create a shared key with a remote device", + "label": "Private Key" + }, + "publicKey": { + "description": "Sent out to other nodes on the mesh to allow them to compute a shared secret key", + "label": "Public Key" + }, + "primaryAdminKey": { + "description": "The primary public key authorized to send admin messages to this node", + "label": "Primary Admin Key" + }, + "secondaryAdminKey": { + "description": "The secondary public key authorized to send admin messages to this node", + "label": "Secondary Admin Key" + }, + "serialOutputEnabled": { + "description": "Serial Console over the Stream API", + "label": "Serial Output Enabled" + }, + "tertiaryAdminKey": { + "description": "The tertiary public key authorized to send admin messages to this node", + "label": "Tertiary Admin Key" + }, + "adminSettings": { + "description": "Settings for Admin", + "label": "Admin Settings" + }, + "loggingSettings": { + "description": "Settings for Logging", + "label": "Logging Settings" + } + }, + "user": { + "title": "User Settings", + "description": "Configure your device name and identity settings", + "longName": { + "label": "Long Name", + "description": "Your full display name (1-40 characters)", + "validation": { + "min": "Long name must be at least 1 character", + "max": "Long name must be at most 40 characters" + } + }, + "shortName": { + "label": "Short Name", + "description": "Your abbreviated name (2-4 characters)", + "validation": { + "min": "Short name must be at least 2 characters", + "max": "Short name must be at most 4 characters" + } + }, + "isUnmessageable": { + "label": "Unmessageable", + "description": "Used to identify unmonitored or infrastructure nodes so that messaging is not available to nodes that will never respond." + }, + "isLicensed": { + "label": "Licensed amateur radio (HAM)", + "description": "Enable if you are a licensed amateur radio operator, enabling this option disables encryption and is not compatible with the default Meshtastic network." + } + } +} diff --git a/packages/web/public/i18n/locales/en/connections.json b/packages/web/public/i18n/locales/en/connections.json new file mode 100644 index 000000000..de1b6b067 --- /dev/null +++ b/packages/web/public/i18n/locales/en/connections.json @@ -0,0 +1,34 @@ +{ + "page": { + "title": "Connect to a Meshtastic device", + "description": "Add a device connection via HTTP, Bluetooth, or Serial. Your saved connections will be saved in your browser." + }, + "connectionType_ble": "BLE", + "connectionType_serial": "Serial", + "connectionType_network": "Network", + "deleteConnection": "Delete connection", + "areYouSure": "This will remove {{name}}. You canot undo this action.", + "moreActions": "More actions", + "noConnections": { + "title": "No connections yet.", + "description": "Create your first connection. It will connect immediately and be saved for later." + }, + "lastConnectedAt": "Last connected: {{date}}", + "neverConnected": "Never connected", + "toasts": { + "connected": "Connected", + "nowConnected": "{{name}} is now connected", + "nowDisconnected": "{{name}} is now disconnected", + "disconnected": "Disconnected", + "failed": "Failed to connect", + "checkConnection": "Check your device or settings and try again", + "defaultSet": "Default set", + "defaultConnection": "Default connection is now {{nameisconnected}}", + "deleted": "Deleted", + "deletedByName": "{{name}} was removed", + "pickConnectionAgain": "Could not connect. You may need to reselect the device/port.", + "added": "Connection added", + "savedByName": "{{name}} saved.", + "savedCantConnect": "The connection was saved but could not connect." + } +} diff --git a/packages/web/public/i18n/locales/en/dashboard.json b/packages/web/public/i18n/locales/en/dashboard.json deleted file mode 100644 index 3a3cd869c..000000000 --- a/packages/web/public/i18n/locales/en/dashboard.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "dashboard": { - "title": "Connected Devices", - "description": "Manage your connected Meshtastic devices.", - "connectionType_ble": "BLE", - "connectionType_serial": "Serial", - "connectionType_network": "Network", - "noDevicesTitle": "No devices connected", - "noDevicesDescription": "Connect a new device to get started.", - "button_newConnection": "New Connection" - } -} diff --git a/packages/web/public/i18n/locales/en/dialog.json b/packages/web/public/i18n/locales/en/dialog.json index 4ffc3ac21..12d3bb1a3 100644 --- a/packages/web/public/i18n/locales/en/dialog.json +++ b/packages/web/public/i18n/locales/en/dialog.json @@ -3,18 +3,6 @@ "description": "This action will clear all message history. This cannot be undone. Are you sure you want to continue?", "title": "Clear All Messages" }, - "deviceName": { - "description": "The Device will restart once the config is saved.", - "longName": "Long Name", - "shortName": "Short Name", - "title": "Change Device Name", - "validation": { - "longNameMax": "Long name must not be more than 40 characters", - "shortNameMax": "Short name must not be more than 4 characters", - "longNameMin": "Long name must have at least 1 character", - "shortNameMin": "Short name must have at least 1 character" - } - }, "import": { "description": "Import a Channel Set from a Meshtastic URL.
Valid Meshtasic URLs start with \"https://meshtastic.org/e/...\"", "error": { @@ -41,49 +29,77 @@ "description": "Are you sure you want to regenerate the pre-shared key?", "regenerate": "Regenerate" }, - "newDeviceDialog": { - "title": "Connect New Device", - "https": "https", - "http": "http", - "tabHttp": "HTTP", - "tabBluetooth": "Bluetooth", - "tabSerial": "Serial", - - "useHttps": "Use HTTPS", - "connecting": "Connecting...", - "connect": "Connect", - "connectionFailedAlert": { - "title": "Connection Failed", - "descriptionPrefix": "Could not connect to the device. ", - "httpsHint": "If using HTTPS, you may need to accept a self-signed certificate first. ", - "openLinkPrefix": "Please open ", - "openLinkSuffix": " in a new tab", - "acceptTlsWarningSuffix": ", accept any TLS warnings if prompted, then try again", - "learnMoreLink": "Learn more" - }, - "httpConnection": { - "label": "IP Address/Hostname", - "placeholder": "000.000.000.000 / meshtastic.local" - }, - "serialConnection": { - "noDevicesPaired": "No devices paired yet.", - "newDeviceButton": "New device", - "deviceIdentifier": "# {{index}} - {{vendorId}} - {{productId}}" - }, - "bluetoothConnection": { - "noDevicesPaired": "No devices paired yet.", - "newDeviceButton": "New device", - "connectionFailed": "Connection failed", - "deviceDisconnected": "Device disconnected", - "unknownDevice": "Unknown Device", - "errorLoadingDevices": "Error loading devices", - "unknownErrorLoadingDevices": "Unknown error loading devices" - }, + "addConnection": { + "title": "Add connection", + "description": "Choose a connection type and fill in the details", "validation": { "requiresWebBluetooth": "This connection type requires <0>Web Bluetooth. Please use a supported browser, like Chrome or Edge.", "requiresWebSerial": "This connection type requires <0>Web Serial. Please use a supported browser, like Chrome or Edge.", "requiresSecureContext": "This application requires a <0>secure context. Please connect using HTTPS or localhost.", "additionallyRequiresSecureContext": "Additionally, it requires a <0>secure context. Please connect using HTTPS or localhost." + }, + "bluetoothConnection": { + "namePlaceholder": "My Bluetooth Node", + "supported": { + "title": "Web Bluetooth supported" + }, + "notSupported": { + "title": "Web Bluetooth not supported", + "description": "Your browser or device does not support Web Bluetooth" + }, + "short": "BT: {{deviceName}}", + "long": "Bluetooth Device", + "device": "Device", + "selectDevice": "Select device", + "selected": "Bluetooth device selected", + "notSelected": "No device selected", + "helperText": "Uses the Meshtastic Bluetooth service for discovery." + }, + "serialConnection": { + "namePlaceholder": "My Serial Node", + "helperText": "Selecting a port grants permission so the app can open it to connect.", + "supported": { + "title": "Web Serial supported" + }, + "notSupported": { + "title": "Web Serial not supported", + "description": "Your browser or device does not support Web Serial" + }, + "portSelected": { + "title": "Serial port selected", + "description": "Port permissions granted." + }, + "port": "Port", + "selectPort": "Select port", + "deviceName": "USB {{vendorId}}:{{productId}}", + "notSelected": "No port selected" + }, + "httpConnection": { + "namePlaceholder": "My HTTP Node", + "inputPlaceholder": "192.168.1.10 or meshtastic.local", + "heading": "URL or IP", + "useHttps": "Use HTTPS", + "invalidUrl": { + "title": "Invalid URL", + "description": "Please enter a valid HTTP or HTTPS URL." + }, + "connectionTest": { + "description": "Test the connection before saving to verify the device is reachable.", + "button": { + "loading": "Testing...", + "label": "Test connection" + }, + "reachable": "Reachable", + "notReachable": "Not reachable", + "success": { + "title": "Connection test successful", + "description": "The device appears to be reachable." + }, + "failure": { + "title": "Connection test failed", + "description": "Could not reach the device. Check the URL and try again." + } + } } }, "nodeDetails": { diff --git a/packages/web/public/i18n/locales/en/map.json b/packages/web/public/i18n/locales/en/map.json index c17f38b25..c1cf0f63d 100644 --- a/packages/web/public/i18n/locales/en/map.json +++ b/packages/web/public/i18n/locales/en/map.json @@ -13,7 +13,9 @@ "remoteNeighbors": "Show remote connections", "positionPrecision": "Show position precision", "traceroutes": "Show traceroutes", - "waypoints": "Show waypoints" + "waypoints": "Show waypoints", + "heatmap": "Show heatmap", + "density": "Density" }, "mapMenu": { "locateAria": "Locate my node", diff --git a/packages/web/public/i18n/locales/en/moduleConfig.json b/packages/web/public/i18n/locales/en/moduleConfig.json index caacbe177..f35995984 100644 --- a/packages/web/public/i18n/locales/en/moduleConfig.json +++ b/packages/web/public/i18n/locales/en/moduleConfig.json @@ -398,7 +398,7 @@ }, "historyReturnWindow": { "label": "History return window", - "description": "Max number of records to return" + "description": "Return records from this time window (minutes)" } }, "telemetry": { diff --git a/packages/web/public/i18n/locales/en/nodes.json b/packages/web/public/i18n/locales/en/nodes.json index 3968ffc19..16db3f953 100644 --- a/packages/web/public/i18n/locales/en/nodes.json +++ b/packages/web/public/i18n/locales/en/nodes.json @@ -47,6 +47,9 @@ "direct": "Direct", "away": "away", "viaMqtt": ", via MQTT" + }, + "lastHeardStatus": { + "never": "Never" } }, diff --git a/packages/web/public/i18n/locales/en/ui.json b/packages/web/public/i18n/locales/en/ui.json index 694e8982d..721050dde 100644 --- a/packages/web/public/i18n/locales/en/ui.json +++ b/packages/web/public/i18n/locales/en/ui.json @@ -3,11 +3,12 @@ "title": "Navigation", "messages": "Messages", "map": "Map", - "config": "Config", + "settings": "Settings", "channels": "Channels", "radioConfig": "Radio Config", + "deviceConfig": "Device Config", "moduleConfig": "Module Config", - "channelConfig": "Channel Config", + "manageConnections": "Manage Connections", "nodes": "Nodes" }, "app": { @@ -27,13 +28,7 @@ "title": "Firmware", "version": "v{{version}}", "buildDate": "Build date: {{date}}" - }, - "deviceName": { - "title": "Device Name", - "changeName": "Change Device Name", - "placeholder": "Enter device name" - }, - "editDeviceName": "Edit device name" + } } }, "batteryStatus": { @@ -186,7 +181,7 @@ "showUnheard": { "label": "Unknown last heard" }, - "language": { + "languagePicker": { "label": "Language", "changeLanguage": "Change Language" }, @@ -208,7 +203,7 @@ "step4": "Any other relevant information" }, "reportLink": "You can report the issue to our <0>GitHub", - "dashboardLink": "Return to the <0>dashboard", + "connectionsLink": "Return to the <0>connections", "detailsSummary": "Error Details", "errorMessageLabel": "Error message:", "stackTraceLabel": "Stack trace:", diff --git a/packages/web/public/i18n/locales/es-ES/channels.json b/packages/web/public/i18n/locales/es-ES/channels.json index bd3366766..1b531ad29 100644 --- a/packages/web/public/i18n/locales/es-ES/channels.json +++ b/packages/web/public/i18n/locales/es-ES/channels.json @@ -1,69 +1,71 @@ { - "page": { - "sectionLabel": "Canales", - "channelName": "Canal: {{channelName}}", - "broadcastLabel": "Primario", - "channelIndex": "Cnl {{index}}" - }, - "validation": { - "pskInvalid": "Por favor, introduzca un PSK de {{bits}} bit válido." - }, - "settings": { - "label": "Ajustes del canal", - "description": "Criptografía, MQTT y otros ajustes" - }, - "role": { - "label": "Rol", - "description": "La telemetría del dispositivo se envía sobre PRIMARY. Solo se permite un PRIMARIO", - "options": { - "primary": "PRIMARIO", - "disabled": "DESHABILITADO", - "secondary": "SECUNDARIO" - } - }, - "psk": { - "label": "Clave pre-compartida", - "description": "Longitudes PSK soportadas: 256-bit, 128-bit, 8-bit, Vacío (0-bit)", - "generate": "Generar Nombre" - }, - "name": { - "label": "Nombre", - "description": "Un nombre único para el canal <12 bytes, dejar en blanco por defecto" - }, - "uplinkEnabled": { - "label": "Subida de Paquetes Permitida", - "description": "Enviar mensajes de la malla local a MQTT" - }, - "downlinkEnabled": { - "label": "Baja de Paquetes Permitida", - "description": "Enviar mensajes de MQTT a la malla local" - }, - "positionPrecision": { - "label": "Ubicación", - "description": "La precisión de la ubicación a compartir con el canal. Se puede desactivar.", - "options": { - "none": "No compartir la ubicación", - "precise": "Ubicación precisa", - "metric_km23": "En 23 kilómetros", - "metric_km12": "En 12 kilómetros", - "metric_km5_8": "En 5,8 kilómetros", - "metric_km2_9": "En 2.9 kilómetros", - "metric_km1_5": "En 1,5 kilómetros", - "metric_m700": "En 700 metros", - "metric_m350": "En 350 metros", - "metric_m200": "En 200 metros", - "metric_m90": "En 90 metros", - "metric_m50": "En 50 metros", - "imperial_mi15": "En 15 millas", - "imperial_mi7_3": "En 7.3 millas", - "imperial_mi3_6": "En 3.6 millas", - "imperial_mi1_8": "En 1.8 millas", - "imperial_mi0_9": "En 0.9 millas", - "imperial_mi0_5": "En 0.5 millas", - "imperial_mi0_2": "En 0.2 millas", - "imperial_ft600": "En 600 pies", - "imperial_ft300": "En 300 pies", - "imperial_ft150": "En 150 pies" - } - } + "page": { + "sectionLabel": "Canales", + "channelName": "Canal: {{channelName}}", + "broadcastLabel": "Primario", + "channelIndex": "Cnl {{index}}", + "import": "Importar", + "export": "Exportar" + }, + "validation": { + "pskInvalid": "Por favor, introduzca un PSK de {{bits}} bit válido." + }, + "settings": { + "label": "Ajustes del canal", + "description": "Criptografía, MQTT y otros ajustes" + }, + "role": { + "label": "Rol", + "description": "La telemetría del dispositivo se envía sobre PRIMARY. Solo se permite un PRIMARIO", + "options": { + "primary": "PRIMARIO", + "disabled": "DESHABILITADO", + "secondary": "SECUNDARIO" + } + }, + "psk": { + "label": "Clave pre-compartida", + "description": "Longitudes PSK soportadas: 256-bit, 128-bit, 8-bit, Vacío (0-bit)", + "generate": "Generar Nombre" + }, + "name": { + "label": "Nombre", + "description": "Un nombre único para el canal <12 bytes, dejar en blanco por defecto" + }, + "uplinkEnabled": { + "label": "Subida de Paquetes Permitida", + "description": "Enviar mensajes de la malla local a MQTT" + }, + "downlinkEnabled": { + "label": "Baja de Paquetes Permitida", + "description": "Enviar mensajes de MQTT a la malla local" + }, + "positionPrecision": { + "label": "Ubicación", + "description": "La precisión de la ubicación a compartir con el canal. Se puede desactivar.", + "options": { + "none": "No compartir la ubicación", + "precise": "Ubicación precisa", + "metric_km23": "En 23 kilómetros", + "metric_km12": "En 12 kilómetros", + "metric_km5_8": "En 5,8 kilómetros", + "metric_km2_9": "En 2.9 kilómetros", + "metric_km1_5": "En 1,5 kilómetros", + "metric_m700": "En 700 metros", + "metric_m350": "En 350 metros", + "metric_m200": "En 200 metros", + "metric_m90": "En 90 metros", + "metric_m50": "En 50 metros", + "imperial_mi15": "En 15 millas", + "imperial_mi7_3": "En 7.3 millas", + "imperial_mi3_6": "En 3.6 millas", + "imperial_mi1_8": "En 1.8 millas", + "imperial_mi0_9": "En 0.9 millas", + "imperial_mi0_5": "En 0.5 millas", + "imperial_mi0_2": "En 0.2 millas", + "imperial_ft600": "En 600 pies", + "imperial_ft300": "En 300 pies", + "imperial_ft150": "En 150 pies" + } + } } diff --git a/packages/web/public/i18n/locales/es-ES/commandPalette.json b/packages/web/public/i18n/locales/es-ES/commandPalette.json index dc3b9c0c9..50d7813a2 100644 --- a/packages/web/public/i18n/locales/es-ES/commandPalette.json +++ b/packages/web/public/i18n/locales/es-ES/commandPalette.json @@ -15,7 +15,6 @@ "messages": "Mensajes", "map": "Mapa", "config": "Configuración", - "channels": "Canales", "nodes": "Nodos" } }, @@ -45,7 +44,8 @@ "label": "Depuración", "command": { "reconfigure": "Volver a configurar", - "clearAllStoredMessages": "Borrar mensajes guardados" + "clearAllStoredMessages": "Borrar mensajes guardados", + "clearAllStores": "Clear All Local Storage" } } } diff --git a/packages/web/public/i18n/locales/es-ES/common.json b/packages/web/public/i18n/locales/es-ES/common.json index f9c86c94f..6d99ef80e 100644 --- a/packages/web/public/i18n/locales/es-ES/common.json +++ b/packages/web/public/i18n/locales/es-ES/common.json @@ -1,142 +1,165 @@ { - "button": { - "apply": "Aplique", - "backupKey": "Clave de la copia de seguridad", - "cancel": "Cancelar", - "clearMessages": "Borrar mensajes", - "close": "Cerrar", - "confirm": "Confirmar", - "delete": "Eliminar", - "dismiss": "Descartar", - "download": "Descarga", - "export": "Exportar", - "generate": "Generar", - "regenerate": "Regenerar", - "import": "Importar", - "message": "Mensaje", - "now": "Ahora", - "ok": "Vale", - "print": "Imprimir", - "remove": "Quitar", - "requestNewKeys": "Solicitar nuevas claves", - "requestPosition": "Solicitar ubicación", - "reset": "Reiniciar", - "save": "Guardar", - "scanQr": "Escanear el código QR", - "traceRoute": "Trazar ruta", - "submit": "Enviar" - }, - "app": { - "title": "Meshtastic", - "fullTitle": "Cliente Web Meshtastic" - }, - "loading": "Cargando...", - "unit": { - "cps": "CPS", - "dbm": "dBm", - "hertz": "Hz", - "hop": { - "one": "Salto", - "plural": "Saltos" - }, - "hopsAway": { - "one": "{{count}} salto lejos", - "plural": "{{count}} saltos lejos", - "unknown": "Saltos desconocidos" - }, - "megahertz": "MHz", - "raw": "bruto", - "meter": { - "one": "Metro", - "plural": "Metros", - "suffix": "m" - }, - "minute": { - "one": "Minuto", - "plural": "Minutos" - }, - "hour": { - "one": "Hora", - "plural": "Horas" - }, - "millisecond": { - "one": "Milisegundo", - "plural": "Milisegundos", - "suffix": " ms" - }, - "second": { - "one": "Segundo", - "plural": "Segundos" - }, - "day": { - "one": "Día", - "plural": "Días" - }, - "month": { - "one": "Mes", - "plural": "Meses" - }, - "year": { - "one": "Año", - "plural": "Años" - }, - "snr": "SNR", - "volt": { - "one": "Voltio", - "plural": "Voltios", - "suffix": "V" - }, - "record": { - "one": "Registros", - "plural": "Registros" - } - }, - "security": { - "0bit": "Vacío", - "8bit": "8 bits", - "128bit": "128 bits", - "256bit": "256 bits" - }, - "unknown": { - "longName": "Desconocido", - "shortName": "UNK", - "notAvailable": "N/A", - "num": "??" - }, - "nodeUnknownPrefix": "!", - "unset": "No Configurado", - "fallbackName": "Meshtastic {{last4}}", - "node": "Nodo", - "formValidation": { - "unsavedChanges": "Cambios no guardados", - "tooBig": { - "string": "Demasiado largo, se esperaba menos o igual a {{maximum}} caracteres.", - "number": "Demasiado grande, se esperaba un número menor que o igual a {{maximum}}.", - "bytes": "Demasiado grande, se esperaba menos o igual a los bytes {{params.maximum}}." - }, - "tooSmall": { - "string": "Demasiado corto, se esperaba más o igual a {{minimum}}. carácteres.", - "number": "Demasiado pequeño, esperaba un número mayor o igual a {{minimum}}." - }, - "invalidFormat": { - "ipv4": "Formato no válido, se esperaba una dirección IPv4.", - "key": "Formato no válido, se esperaba una clave pre-compartida codificada en Base64 (PSK)." - }, - "invalidType": { - "number": "Carácter no válido, se espera un número." - }, - "pskLength": { - "0bit": "Es necesario que la clave esté vacía.", - "8bit": "Se requiere que la clave sea una clave pre-compartida de 8 bits (PSK).", - "128bit": "Se requiere que la clave sea una clave pre-compartida de 128 bits (PSK).", - "256bit": "Se requiere que la clave sea una clave pre-compartida de 256 bits (PSK)." - }, - "required": { - "generic": "Este campo es obligatorio.", - "managed": "Se solicita al menos una clave de administración si se administra el nodo.", - "key": "Se requiere clave." - } - }, - "yes": "Sí", - "no": "No" + "button": { + "apply": "Aplique", + "addConnection": "Add Connection", + "saveConnection": "Save connection", + "backupKey": "Clave de la copia de seguridad", + "cancel": "Cancelar", + "connect": "Conectar", + "clearMessages": "Borrar mensajes", + "close": "Cerrar", + "confirm": "Confirmar", + "delete": "Eliminar", + "dismiss": "Descartar", + "download": "Descarga", + "disconnect": "Desconectar", + "export": "Exportar", + "generate": "Generar", + "regenerate": "Regenerar", + "import": "Importar", + "message": "Mensaje", + "now": "Ahora", + "ok": "Vale", + "print": "Imprimir", + "remove": "Quitar", + "requestNewKeys": "Solicitar nuevas claves", + "requestPosition": "Solicitar ubicación", + "reset": "Reiniciar", + "retry": "Retry", + "save": "Guardar", + "setDefault": "Set as default", + "unsetDefault": "Unset default", + "scanQr": "Escanear el código QR", + "traceRoute": "Trazar ruta", + "submit": "Enviar" + }, + "app": { + "title": "Meshtastic", + "fullTitle": "Cliente Web Meshtastic" + }, + "loading": "Cargando...", + "unit": { + "cps": "CPS", + "dbm": "dBm", + "hertz": "Hz", + "hop": { + "one": "Salto", + "plural": "Saltos" + }, + "hopsAway": { + "one": "{{count}} salto lejos", + "plural": "{{count}} saltos lejos", + "unknown": "Saltos desconocidos" + }, + "megahertz": "MHz", + "kilohertz": "kHz", + "raw": "bruto", + "meter": { + "one": "Metro", + "plural": "Metros", + "suffix": "m" + }, + "kilometer": { + "one": "Kilometer", + "plural": "Kilometers", + "suffix": "km" + }, + "minute": { + "one": "Minuto", + "plural": "Minutos" + }, + "hour": { + "one": "Hora", + "plural": "Horas" + }, + "millisecond": { + "one": "Milisegundo", + "plural": "Milisegundos", + "suffix": " ms" + }, + "second": { + "one": "Segundo", + "plural": "Segundos" + }, + "day": { + "one": "Día", + "plural": "Días", + "today": "Today", + "yesterday": "Yesterday" + }, + "month": { + "one": "Mes", + "plural": "Meses" + }, + "year": { + "one": "Año", + "plural": "Años" + }, + "snr": "SNR", + "volt": { + "one": "Voltio", + "plural": "Voltios", + "suffix": "V" + }, + "record": { + "one": "Registros", + "plural": "Registros" + }, + "degree": { + "one": "Degree", + "plural": "Degrees", + "suffix": "°" + } + }, + "security": { + "0bit": "Vacío", + "8bit": "8 bits", + "128bit": "128 bits", + "256bit": "256 bits" + }, + "unknown": { + "longName": "Desconocido", + "shortName": "UNK", + "notAvailable": "N/A", + "num": "??" + }, + "nodeUnknownPrefix": "!", + "unset": "No Configurado", + "fallbackName": "Meshtastic {{last4}}", + "node": "Nodo", + "formValidation": { + "unsavedChanges": "Cambios no guardados", + "tooBig": { + "string": "Demasiado largo, se esperaba menos o igual a {{maximum}} caracteres.", + "number": "Demasiado grande, se esperaba un número menor que o igual a {{maximum}}.", + "bytes": "Demasiado grande, se esperaba menos o igual a los bytes {{params.maximum}}." + }, + "tooSmall": { + "string": "Demasiado corto, se esperaba más o igual a {{minimum}}. carácteres.", + "number": "Demasiado pequeño, esperaba un número mayor o igual a {{minimum}}." + }, + "invalidFormat": { + "ipv4": "Formato no válido, se esperaba una dirección IPv4.", + "key": "Formato no válido, se esperaba una clave pre-compartida codificada en Base64 (PSK)." + }, + "invalidType": { + "number": "Carácter no válido, se espera un número." + }, + "pskLength": { + "0bit": "Es necesario que la clave esté vacía.", + "8bit": "Se requiere que la clave sea una clave pre-compartida de 8 bits (PSK).", + "128bit": "Se requiere que la clave sea una clave pre-compartida de 128 bits (PSK).", + "256bit": "Se requiere que la clave sea una clave pre-compartida de 256 bits (PSK)." + }, + "required": { + "generic": "Este campo es obligatorio.", + "managed": "Se solicita al menos una clave de administración si se administra el nodo.", + "key": "Se requiere clave." + }, + "invalidOverrideFreq": { + "number": "Invalid format, expected a value in the range 410-930 MHz or 0 (use default)." + } + }, + "yes": "Sí", + "no": "No" } diff --git a/packages/web/public/i18n/locales/es-ES/config.json b/packages/web/public/i18n/locales/es-ES/config.json new file mode 100644 index 000000000..97a9cc97f --- /dev/null +++ b/packages/web/public/i18n/locales/es-ES/config.json @@ -0,0 +1,458 @@ +{ + "page": { + "title": "Ajustes", + "tabUser": "Usuario", + "tabChannels": "Canales", + "tabBluetooth": "Bluetooth", + "tabDevice": "Dispositivo", + "tabDisplay": "Pantalla", + "tabLora": "LoRa", + "tabNetwork": "Conexión Red", + "tabPosition": "Posición", + "tabPower": "Consumo", + "tabSecurity": "Seguridad" + }, + "sidebar": { + "label": "Configuración" + }, + "device": { + "title": "Ajustes del dispositivo", + "description": "Ajustes del dispositivo", + "buttonPin": { + "description": "Sobrescribir pin de botón", + "label": "Pin del botón" + }, + "buzzerPin": { + "description": "Sobrescribir pin del zumbador", + "label": "Pin del zumbador" + }, + "disableTripleClick": { + "description": "Deshabilitar clic triple", + "label": "Deshabilitar clic triple" + }, + "doubleTapAsButtonPress": { + "description": "Tratar doble toque como botón presionado", + "label": "Doble toque como botón presionado" + }, + "ledHeartbeatDisabled": { + "description": "Deshabilitar parpadeo del LED predeterminado", + "label": "Deshabilitar LED de estado" + }, + "nodeInfoBroadcastInterval": { + "description": "Cada cuanto se transmite la información del nodo", + "label": "Intervalo de transmisión de información del nodo" + }, + "posixTimezone": { + "description": "La zona horaria para el dispositivo en formato de cadena POSIX", + "label": "Zona horaria POSIX" + }, + "rebroadcastMode": { + "description": "Cómo manejar la retransmisión", + "label": "Modo de retransmisión" + }, + "role": { + "description": "Qué role realiza el dispositivo en la malla", + "label": "Rol" + } + }, + "bluetooth": { + "title": "Ajustes de Bluetooth", + "description": "Ajustes del módulo de Bluetooth", + "note": "Nota: Algunos dispositivos (ESP32) no pueden usar Bluetooth y Wifi al mismo tiempo.", + "enabled": { + "description": "Habilitar o deshabilitar Bluetooth", + "label": "Habilitado" + }, + "pairingMode": { + "description": "Selección del comportamiento del Pin.", + "label": "Modo de emparejamiento" + }, + "pin": { + "description": "Pin a usar al emparejar", + "label": "Pin" + } + }, + "display": { + "description": "Ajustes de la pantalla del dispositivo", + "title": "Ajustes de pantalla", + "headingBold": { + "description": "Negrita en el texto del encabezado", + "label": "Encabezado en negrita" + }, + "carouselDelay": { + "description": "Que tan rápido cambiar entre pantallas", + "label": "Retraso del carrusel" + }, + "compassNorthTop": { + "description": "Fijar el norte en la parte superior de la brújula", + "label": "Norte arriba de la brújula" + }, + "displayMode": { + "description": "Variante del diseño de la pantalla", + "label": "Modo de visualización" + }, + "displayUnits": { + "description": "Mostrar unidades de medidas métricas o imperiales", + "label": "Unidades de medidas" + }, + "flipScreen": { + "description": "Rotar pantalla 180 grados", + "label": "Rotar pantalla" + }, + "gpsDisplayUnits": { + "description": "Formato de visualización de las coordenadas", + "label": "Unidades de visualización del GPS" + }, + "oledType": { + "description": "Tipo de pantalla OLED conectada al dispositivo", + "label": "Tipo de OLED" + }, + "screenTimeout": { + "description": "Apagar la pantalla después de este tiempo", + "label": "Tiempo de espera de la pantalla" + }, + "twelveHourClock": { + "description": "Usar reloj con formato de 12 horas", + "label": "Reloj de 12 horas" + }, + "wakeOnTapOrMotion": { + "description": "Despertar dispositivo al tocar o mover", + "label": "Despertar al mover o tocar" + } + }, + "lora": { + "title": "Ajustes de la Red", + "description": "Opciones de la malla LoRa", + "bandwidth": { + "description": "Ancho de banda de canal en kHz", + "label": "Ancho de Banda" + }, + "boostedRxGain": { + "description": "Aumentada la ganancia RX", + "label": "Aumentada la ganancia RX" + }, + "codingRate": { + "description": "El denominador de la tasa de codificación", + "label": "Tasa de codificación" + }, + "frequencyOffset": { + "description": "Desplazamiento de frecuencia para corregir los errores de calibración del cristal", + "label": "Desplazamiento de la Frecuencia" + }, + "frequencySlot": { + "description": "Número de canal de frecuencia LoRa", + "label": "Slot de frecuencia" + }, + "hopLimit": { + "description": "Número máximo de saltos", + "label": "Límite de Saltos" + }, + "ignoreMqtt": { + "description": "No reenviar mensajes MQTT sobre la malla", + "label": "Ignorar Paquetes MQTT" + }, + "modemPreset": { + "description": "Modem predefinido para usar", + "label": "Modem predefinido" + }, + "okToMqtt": { + "description": "Cuando se establece en true, esta configuración indica que el usuario aprueba el paquete para ser subido a MQTT. Si se establece a false, los nodos remotos son solicitados no reenviar paquetes a MQTT", + "label": "Permitir Subir Paquetes al MQTT" + }, + "overrideDutyCycle": { + "description": "Sobreescribir el Tiempo de Trabajo", + "label": "Sobreescribir el Tiempo de Trabajo" + }, + "overrideFrequency": { + "description": "Reemplazar frecuencia", + "label": "Reemplazar frecuencia" + }, + "region": { + "description": "Establece la región para su nodo", + "label": "Región" + }, + "spreadingFactor": { + "description": "Indica el número de chirps por símbolo", + "label": "Factor de dispersión" + }, + "transmitEnabled": { + "description": "Activar/Desactivar transmisión (TX) desde la radio LoRa", + "label": "Transmisión Activa" + }, + "transmitPower": { + "description": "Máxima potencia de transmisión", + "label": "Potencia de transmisión" + }, + "usePreset": { + "description": "Utilice uno de los ajustes predefinidos del módem", + "label": "Usar predefinido" + }, + "meshSettings": { + "description": "Opciones de la malla LoRa", + "label": "Ajustes de la Red" + }, + "waveformSettings": { + "description": "Configuración de la forma de onda LoRa", + "label": "Ajustes de forma de onda" + }, + "radioSettings": { + "label": "Ajustes de radio", + "description": "Configuración para LoRa radio" + } + }, + "network": { + "title": "Configuración WiFi", + "description": "Configuración de radio WiFi", + "note": "Nota: Algunos dispositivos (ESP32) no pueden usar Bluetooth y Wifi al mismo tiempo.", + "addressMode": { + "description": "Selección de asignación de dirección", + "label": "Modo de dirección" + }, + "dns": { + "description": "Servidor DNS", + "label": "DNS" + }, + "ethernetEnabled": { + "description": "Activar o desactivar el puerto Ethernet", + "label": "Habilitado" + }, + "gateway": { + "description": "Puerta de Entrada Predeterminada", + "label": "Puerta enlace" + }, + "ip": { + "description": "Dirección IP", + "label": "IP" + }, + "psk": { + "description": "Contraseña de red", + "label": "PSK (Contraseña)" + }, + "ssid": { + "description": "Nombre de red", + "label": "SSID (Nombre la Red)" + }, + "subnet": { + "description": "Máscara de subred", + "label": "Subred" + }, + "wifiEnabled": { + "description": "Activar o desactivar la radio WiFi", + "label": "Habilitado" + }, + "meshViaUdp": { + "label": "Malla via UDP" + }, + "ntpServer": { + "label": "Servidor NTP" + }, + "rsyslogServer": { + "label": "Servidor Rsyslog" + }, + "ethernetConfigSettings": { + "description": "Configuración del puerto Ethernet", + "label": "Configuración Ethernet" + }, + "ipConfigSettings": { + "description": "Configuración de IP", + "label": "Configuración de IP" + }, + "ntpConfigSettings": { + "description": "Configuración NTP", + "label": "Configuración NTP" + }, + "rsyslogConfigSettings": { + "description": "Configuración Rsyslog", + "label": "Configuración Rsyslog" + }, + "udpConfigSettings": { + "description": "Configuración de UDP sobre Malla", + "label": "Configuración UDP" + } + }, + "position": { + "title": "Ajustes de posición", + "description": "Configuración del módulo de posición", + "broadcastInterval": { + "description": "Con qué frecuencia se envía tu posición sobre la malla", + "label": "Intervalo de transmisión" + }, + "enablePin": { + "description": "Módulo GPS activar anulación de pin", + "label": "Activar pin" + }, + "fixedPosition": { + "description": "No informar de la posición del GPS, pero una especificada manualmente", + "label": "Posición Fijada" + }, + "gpsMode": { + "description": "Configurar si el dispositivo GPS está activado, desactivado o no está presente", + "label": "Modo del GPS" + }, + "gpsUpdateInterval": { + "description": "Con qué frecuencia debe adquirirse una posición GPS", + "label": "Intervalo de actualización GPS" + }, + "positionFlags": { + "description": "Campos opcionales para incluir al ensamblar mensajes de posición. Cuantos más campos se seleccionen, más grande será el mensaje que llevará a un mayor uso del tiempo de aire y un mayor riesgo de pérdida de paquetes.", + "label": "Marcas de posición" + }, + "receivePin": { + "description": "Módulo RX del GPS ignorar Pin", + "label": "Recibir Pin" + }, + "smartPositionEnabled": { + "description": "Sólo enviar posición cuando haya habido un cambio significativo en la ubicación", + "label": "Habilitar posición inteligente" + }, + "smartPositionMinDistance": { + "description": "Distancia mínima (en metros) que debe ser recorrida antes de que se envíe una actualización de posición", + "label": "Distancia mínima de posición inteligente" + }, + "smartPositionMinInterval": { + "description": "Intervalo mínimo (en s.) que debe pasar antes de enviar una actualización de posición", + "label": "Intervalo Mínimo de Posición Inteligente" + }, + "transmitPin": { + "description": "Módulo TX del GPS ignorar Pin", + "label": "Transmitir Pin" + }, + "intervalsSettings": { + "description": "Con qué frecuencia enviar actualizaciones de posición", + "label": "Intervalos" + }, + "flags": { + "placeholder": "Seleccionar marcadores de posición...", + "altitude": "Altitud", + "altitudeGeoidalSeparation": "Separación Geoidal de Altitud", + "altitudeMsl": "Altitud es Nivel Medio del Mar", + "dop": "Dilución de precisión (DOP) PDOP usada por defecto", + "hdopVdop": "Si DOP está definido, usar valores HDOP / VDOP en lugar de PDOP", + "numSatellites": "Cantidad de satélites", + "sequenceNumber": "Número de secuencia", + "timestamp": "Fecha", + "unset": "Sin configurar", + "vehicleHeading": "Rumbo del vehículo", + "vehicleSpeed": "Velocidad de vehículo" + } + }, + "power": { + "adcMultiplierOverride": { + "description": "Utilizado para ajustar la lectura del voltaje de la batería", + "label": "Ratio de sobrescritura del multiplicador ADC" + }, + "ina219Address": { + "description": "Dirección del monitor de la batería INA219", + "label": "Dirección INA219" + }, + "lightSleepDuration": { + "description": "How long the device will be in light sleep for", + "label": "Duración de la " + }, + "minimumWakeTime": { + "description": "Cantidad mínima de tiempo que el dispositivo permanecerá despierto después de recibir un paquete", + "label": "Tiempo mínimo activo" + }, + "noConnectionBluetoothDisabled": { + "description": "Si el dispositivo no recibe una conexión Bluetooth, la radio BLE se desactivará después de este tiempo", + "label": "No hay conexión Bluetooth desactivado" + }, + "powerSavingEnabled": { + "description": "Seleccione si está alimentado de una fuente de corriente de poca potencia (es decir, solar), para minimizar el consumo de energía tanto como sea posible.", + "label": "Activar el modo ahorro de energía" + }, + "shutdownOnBatteryDelay": { + "description": "Apagar automáticamente el nodo después de este largo durante la batería, 0 para indefinido", + "label": "Apagado en retraso de batería" + }, + "superDeepSleepDuration": { + "description": "Cuánto tiempo durará el dispositivo en suspensión profunda", + "label": "Duración de suspensión superprofunda" + }, + "powerConfigSettings": { + "description": "Configuración del módulo de alimentación", + "label": "Configuración de elecenergía " + }, + "sleepSettings": { + "description": "Configuración de suspensión para el módulo de alimentación", + "label": "Ajustes de suspensión" + } + }, + "security": { + "description": "Ajustes para la configuración de seguridad", + "title": "Configuraciones de Seguridad", + "button_backupKey": "Clave de la copia de seguridad", + "adminChannelEnabled": { + "description": "Permitir el control del dispositivo entrante mediante el canal inseguro de administración legado", + "label": "Permitir Administrador Legado" + }, + "enableDebugLogApi": { + "description": "Output live debug logging over serial, view and export position-redacted device logs over Bluetooth", + "label": "Habilitar API de registro de depuración" + }, + "managed": { + "description": "If enabled, device configuration options are only able to be changed remotely by a Remote Admin node via admin messages. Do not enable this option unless at least one suitable Remote Admin node has been setup, and the public key is stored in one of the fields above.", + "label": "Administrado" + }, + "privateKey": { + "description": "Utilizado para crear una clave compartida con un dispositivo remoto", + "label": "Clave privada" + }, + "publicKey": { + "description": "Sent out to other nodes on the mesh to allow them to compute a shared secret key", + "label": "Clave Pública" + }, + "primaryAdminKey": { + "description": "The primary public key authorized to send admin messages to this node", + "label": "Clave principal de administrador" + }, + "secondaryAdminKey": { + "description": "The secondary public key authorized to send admin messages to this node", + "label": "Secondary Admin Key" + }, + "serialOutputEnabled": { + "description": "Serial Console over the Stream API", + "label": "Salida Serial Activada" + }, + "tertiaryAdminKey": { + "description": "The tertiary public key authorized to send admin messages to this node", + "label": "Tertiary Admin Key" + }, + "adminSettings": { + "description": "Opciones para administradores", + "label": "Ajustes de administrador" + }, + "loggingSettings": { + "description": "Settings for Logging", + "label": "Logging Settings" + } + }, + "user": { + "title": "User Settings", + "description": "Configure your device name and identity settings", + "longName": { + "label": "Nombre largo", + "description": "Your full display name (1-40 characters)", + "validation": { + "min": "Long name must be at least 1 character", + "max": "Long name must be at most 40 characters" + } + }, + "shortName": { + "label": "Nombre Corto", + "description": "Your abbreviated name (2-4 characters)", + "validation": { + "min": "Short name must be at least 2 characters", + "max": "Short name must be at most 4 characters" + } + }, + "isUnmessageable": { + "label": "No se puede enviar mensajes", + "description": "Used to identify unmonitored or infrastructure nodes so that messaging is not available to nodes that will never respond." + }, + "isLicensed": { + "label": "Licencia de radioaficionado (no necesaria)", + "description": "Enable if you are a licensed amateur radio operator, enabling this option disables encryption and is not compatible with the default Meshtastic network." + } + } +} diff --git a/packages/web/public/i18n/locales/es-ES/connections.json b/packages/web/public/i18n/locales/es-ES/connections.json new file mode 100644 index 000000000..6b2dc2e60 --- /dev/null +++ b/packages/web/public/i18n/locales/es-ES/connections.json @@ -0,0 +1,34 @@ +{ + "page": { + "title": "Connect to a Meshtastic device", + "description": "Add a device connection via HTTP, Bluetooth, or Serial. Your saved connections will be saved in your browser." + }, + "connectionType_ble": "BLE", + "connectionType_serial": "Conexión Serial", + "connectionType_network": "Conexión Red", + "deleteConnection": "Delete connection", + "areYouSure": "This will remove {{name}}. You canot undo this action.", + "moreActions": "More actions", + "noConnections": { + "title": "No connections yet.", + "description": "Create your first connection. It will connect immediately and be saved for later." + }, + "lastConnectedAt": "Last connected: {{date}}", + "neverConnected": "Never connected", + "toasts": { + "connected": "Conectado", + "nowConnected": "{{name}} is now connected", + "nowDisconnected": "{{name}} are now disconnecte", + "disconnected": "Desconectado", + "failed": "Failed to connect", + "checkConnetion": "Check your device or settings and try again", + "defaultSet": "Default set", + "defaultConnection": "Default connection is now {{nameisconnected}}", + "deleted": "Deleted", + "deletedByName": "{{name}} was removed", + "pickConnectionAgain": "Could not connect. You may need to reselect the device/port.", + "added": "Connection added", + "savedByName": "{{name}} saved.", + "savedCantConnect": "The connection was saved but could not connect." + } +} diff --git a/packages/web/public/i18n/locales/es-ES/dashboard.json b/packages/web/public/i18n/locales/es-ES/dashboard.json deleted file mode 100644 index 74aaebf6d..000000000 --- a/packages/web/public/i18n/locales/es-ES/dashboard.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "dashboard": { - "title": "Dispositivos conectados", - "description": "Administra tus dispositivos Meshtastic conectados.", - "connectionType_ble": "BLE", - "connectionType_serial": "Conexión Serial", - "connectionType_network": "Conexión Red", - "noDevicesTitle": "No hay dispositivos conectados", - "noDevicesDescription": "Conecta un nuevo dispositivo para empezar.", - "button_newConnection": "Conexión Nueva" - } -} diff --git a/packages/web/public/i18n/locales/es-ES/deviceConfig.json b/packages/web/public/i18n/locales/es-ES/deviceConfig.json index ba5a0cde8..6accf8ae5 100644 --- a/packages/web/public/i18n/locales/es-ES/deviceConfig.json +++ b/packages/web/public/i18n/locales/es-ES/deviceConfig.json @@ -122,7 +122,7 @@ "title": "Ajustes de la Red", "description": "Opciones de la malla LoRa", "bandwidth": { - "description": "Ancho de banda de canal en MHz", + "description": "Ancho de banda de canal en kHz", "label": "Ancho de Banda" }, "boostedRxGain": { diff --git a/packages/web/public/i18n/locales/es-ES/dialog.json b/packages/web/public/i18n/locales/es-ES/dialog.json index b7bf6acda..e04352079 100644 --- a/packages/web/public/i18n/locales/es-ES/dialog.json +++ b/packages/web/public/i18n/locales/es-ES/dialog.json @@ -1,193 +1,238 @@ { - "deleteMessages": { - "description": "This action will clear all message history. This cannot be undone. Are you sure you want to continue?", - "title": "Borrar todos los mensajes" - }, - "deviceName": { - "description": "El dispositivo se reiniciará una vez que se guarde la configuración.", - "longName": "Nombre largo", - "shortName": "Nombre Corto", - "title": "Cambiar nombre del dispositivo", - "validation": { - "longNameMax": "El nombre largo no debe tener más de 40 caracteres", - "shortNameMax": "El nombre corto no debe tener más de 4 caracteres", - "longNameMin": "El nombre largo debe tener al menos 1 carácter", - "shortNameMin": "El nombre corto debe tener al menos 1 carácter" - } - }, - "import": { - "description": "Se anulará la configuración actual de LoRa.", - "error": { - "invalidUrl": "URL Meshtastic no válida" - }, - "channelPrefix": "Channel: ", - "channelSetUrl": "Fijar canal/código QR URL", - "channels": "Channels:", - "usePreset": "Use Preset?", - "title": "Import Channel Set" - }, - "locationResponse": { - "title": "Location: {{identifier}}", - "altitude": "Altitude: ", - "coordinates": "Coordinates: ", - "noCoordinates": "No Coordinates" - }, - "pkiRegenerateDialog": { - "title": "Regenerate Pre-Shared Key?", - "description": "Are you sure you want to regenerate the pre-shared key?", - "regenerate": "Regenerate" - }, - "newDeviceDialog": { - "title": "Connect New Device", - "https": "https", - "http": "http", - "tabHttp": "HTTP", - "tabBluetooth": "Bluetooth", - "tabSerial": "Conexión Serial", - "useHttps": "Use HTTPS", - "connecting": "Connecting...", - "connect": "Conectar", - "connectionFailedAlert": { - "title": "Connection Failed", - "descriptionPrefix": "Could not connect to the device. ", - "httpsHint": "If using HTTPS, you may need to accept a self-signed certificate first. ", - "openLinkPrefix": "Please open ", - "openLinkSuffix": " in a new tab", - "acceptTlsWarningSuffix": ", accept any TLS warnings if prompted, then try again", - "learnMoreLink": "Learn more" - }, - "httpConnection": { - "label": "IP Address/Hostname", - "placeholder": "000.000.000.000 / meshtastic.local" - }, - "serialConnection": { - "noDevicesPaired": "No devices paired yet.", - "newDeviceButton": "New device", - "deviceIdentifier": "# {{index}} - {{vendorId}} - {{productId}}" - }, - "bluetoothConnection": { - "noDevicesPaired": "No devices paired yet.", - "newDeviceButton": "New device", - "connectionFailed": "Connection failed", - "deviceDisconnected": "Device disconnected", - "unknownDevice": "Unknown Device", - "errorLoadingDevices": "Error loading devices", - "unknownErrorLoadingDevices": "Unknown error loading devices" - }, - "validation": { - "requiresWebBluetooth": "This connection type requires <0>Web Bluetooth. Please use a supported browser, like Chrome or Edge.", - "requiresWebSerial": "This connection type requires <0>Web Serial. Please use a supported browser, like Chrome or Edge.", - "requiresSecureContext": "This application requires a <0>secure context. Please connect using HTTPS or localhost.", - "additionallyRequiresSecureContext": "Additionally, it requires a <0>secure context. Please connect using HTTPS or localhost." - } - }, - "nodeDetails": { - "message": "Mensaje", - "requestPosition": "Request Position", - "traceRoute": "Trace Route", - "airTxUtilization": "Air TX utilization", - "allRawMetrics": "All Raw Metrics:", - "batteryLevel": "Battery level", - "channelUtilization": "Channel utilization", - "details": "Details:", - "deviceMetrics": "Device Metrics:", - "hardware": "Hardware: ", - "lastHeard": "Last Heard: ", - "nodeHexPrefix": "Node Hex: ", - "nodeNumber": "Node Number: ", - "position": "Position:", - "role": "Role: ", - "uptime": "Uptime: ", - "voltage": "Tensión", - "title": "Node Details for {{identifier}}", - "ignoreNode": "Ignore node", - "removeNode": "Remove node", - "unignoreNode": "Unignore node", - "security": "Security:", - "publicKey": "Public Key: ", - "messageable": "Messageable: ", - "KeyManuallyVerifiedTrue": "Public Key has been manually verified", - "KeyManuallyVerifiedFalse": "Public Key is not manually verified" - }, - "pkiBackup": { - "loseKeysWarning": "If you lose your keys, you will need to reset your device.", - "secureBackup": "Its important to backup your public and private keys and store your backup securely!", - "footer": "=== END OF KEYS ===", - "header": "=== MESHTASTIC KEYS FOR {{longName}} ({{shortName}}) ===", - "privateKey": "Private Key:", - "publicKey": "Public Key:", - "fileName": "meshtastic_keys_{{longName}}_{{shortName}}.txt", - "title": "Backup Keys" - }, - "pkiBackupReminder": { - "description": "We recommend backing up your key data regularly. Would you like to back up now?", - "title": "Backup Reminder", - "remindLaterPrefix": "Remind me in", - "remindNever": "Never remind me", - "backupNow": "Back up now" - }, - "pkiRegenerate": { - "description": "Are you sure you want to regenerate key pair?", - "title": "Regenerate Key Pair" - }, - "qr": { - "addChannels": "Add Channels", - "replaceChannels": "Replace Channels", - "description": "The current LoRa configuration will also be shared.", - "sharableUrl": "Sharable URL", - "title": "Generate QR Code" - }, - "reboot": { - "title": "Reboot device", - "description": "Reboot now or schedule a reboot of the connected node. Optionally, you can choose to reboot into OTA (Over-the-Air) mode.", - "ota": "Reboot into OTA mode", - "enterDelay": "Enter delay", - "scheduled": "Reboot has been scheduled", - "schedule": "Schedule reboot", - "now": "Reboot now", - "cancel": "Cancel scheduled reboot" - }, - "refreshKeys": { - "description": { - "acceptNewKeys": "This will remove the node from device and request new keys.", - "keyMismatchReasonSuffix": ". This is due to the remote node's current public key does not match the previously stored key for this node.", - "unableToSendDmPrefix": "Your node is unable to send a direct message to node: " - }, - "acceptNewKeys": "Accept New Keys", - "title": "Keys Mismatch - {{identifier}}" - }, - "removeNode": { - "description": "Are you sure you want to remove this Node?", - "title": "Remove Node?" - }, - "shutdown": { - "title": "Schedule Shutdown", - "description": "Turn off the connected node after x minutes." - }, - "traceRoute": { - "routeToDestination": "Route to destination:", - "routeBack": "Route back:" - }, - "tracerouteResponse": { - "title": "Traceroute: {{identifier}}" - }, - "unsafeRoles": { - "confirmUnderstanding": "Yes, I know what I'm doing", - "conjunction": " and the blog post about ", - "postamble": " and understand the implications of changing the role.", - "preamble": "I have read the ", - "choosingRightDeviceRole": "Choosing The Right Device Role", - "deviceRoleDocumentation": "Device Role Documentation", - "title": "¿Estás seguro?" - }, - "managedMode": { - "confirmUnderstanding": "Yes, I know what I'm doing", - "title": "¿Estás seguro?", - "description": "Enabling Managed Mode blocks client applications (including the web client) from writing configurations to a radio. Once enabled, radio configurations can only be changed through Remote Admin messages. This setting is not required for remote node administration." - }, - "clientNotification": { - "title": "Client Notification", - "TraceRoute can only be sent once every 30 seconds": "TraceRoute can only be sent once every 30 seconds", - "Compromised keys were detected and regenerated.": "Compromised keys were detected and regenerated." - } + "deleteMessages": { + "description": "This action will clear all message history. This cannot be undone. Are you sure you want to continue?", + "title": "Borrar todos los mensajes" + }, + "import": { + "description": "Se anulará la configuración actual de LoRa.", + "error": { + "invalidUrl": "URL Meshtastic no válida" + }, + "channelPrefix": "Channel: ", + "primary": "Primary ", + "doNotImport": "No not import", + "channelName": "Nombre", + "channelSlot": "Ranura", + "channelSetUrl": "Fijar canal/código QR URL", + "useLoraConfig": "Import LoRa Config", + "presetDescription": "The current LoRa Config will be replaced.", + "title": "Import Channel Set" + }, + "locationResponse": { + "title": "Location: {{identifier}}", + "altitude": "Altitude: ", + "coordinates": "Coordinates: ", + "noCoordinates": "No Coordinates" + }, + "pkiRegenerateDialog": { + "title": "Regenerate Pre-Shared Key?", + "description": "Are you sure you want to regenerate the pre-shared key?", + "regenerate": "Regenerate" + }, + "addConnection": { + "title": "Add connection", + "description": "Choose a connection type and fill in the details", + "validation": { + "requiresWebBluetooth": "This connection type requires <0>Web Bluetooth. Please use a supported browser, like Chrome or Edge.", + "requiresWebSerial": "This connection type requires <0>Web Serial. Please use a supported browser, like Chrome or Edge.", + "requiresSecureContext": "This application requires a <0>secure context. Please connect using HTTPS or localhost.", + "additionallyRequiresSecureContext": "Additionally, it requires a <0>secure context. Please connect using HTTPS or localhost." + }, + "bluetoothConnection": { + "namePlaceholder": "My Bluetooth Node", + "supported": { + "title": "Web Bluetooth supported" + }, + "notSupported": { + "title": "Web Bluetooth not supported", + "description": "Your browser or device does not support Web Bluetooth" + }, + "short": "BT: {{deviceName}}", + "long": "Bluetooth Device", + "device": "Dispositivo", + "selectDevice": "Select device", + "selected": "Bluetooth device selected", + "notSelected": "No device selected", + "helperText": "Uses the Meshtastic Bluetooth service for discovery." + }, + "serialConnection": { + "namePlaceholder": "My Serial Node", + "helperText": "Selecting a port grants permission so the app can open it to connect.", + "supported": { + "title": "Web Serial supported" + }, + "notSupported": { + "title": "Web Serial not supported", + "description": "Your browser or device does not support Web Serial" + }, + "portSelected": { + "title": "Serial port selected", + "description": "Port permissions granted." + }, + "port": "Port", + "selectPort": "Select port", + "deviceName": "USB {{vendorId}}:{{productId}}", + "notSelected": "No port selected" + }, + "httpConnection": { + "namePlaceholder": "My HTTP Node", + "inputPlaceholder": "192.168.1.10 or meshtastic.local", + "heading": "URL or IP", + "useHttps": "Use HTTTPS", + "invalidUrl": { + "title": "Invalid URL", + "description": "Please enter a valid HTTP or HTTPS URL." + }, + "connectionTest": { + "description": "Test the connetion before saving to verify the device is reachable.", + "button": { + "loading": "Testing...", + "label": "Test connection" + }, + "reachable": "Reachable", + "notReachable": "Not reachable", + "success": { + "title": "Connection test successful", + "description": "The device appears to be reachable." + }, + "failure": { + "title": "Connection test failed", + "description": "Could not reach the device. Check the URL and try again." + } + } + } + }, + "nodeDetails": { + "message": "Mensaje", + "requestPosition": "Request Position", + "traceRoute": "Trace Route", + "airTxUtilization": "Air TX utilization", + "allRawMetrics": "All Raw Metrics:", + "batteryLevel": "Battery level", + "channelUtilization": "Channel utilization", + "details": "Details:", + "deviceMetrics": "Device Metrics:", + "hardware": "Hardware: ", + "lastHeard": "Last Heard: ", + "nodeHexPrefix": "Node Hex: ", + "nodeNumber": "Node Number: ", + "position": "Position:", + "role": "Role: ", + "uptime": "Uptime: ", + "voltage": "Tensión", + "title": "Node Details for {{identifier}}", + "ignoreNode": "Ignore node", + "removeNode": "Remove node", + "unignoreNode": "Unignore node", + "security": "Security:", + "publicKey": "Public Key: ", + "messageable": "Messageable: ", + "KeyManuallyVerifiedTrue": "Public Key has been manually verified", + "KeyManuallyVerifiedFalse": "Public Key is not manually verified" + }, + "pkiBackup": { + "loseKeysWarning": "If you lose your keys, you will need to reset your device.", + "secureBackup": "Its important to backup your public and private keys and store your backup securely!", + "footer": "=== END OF KEYS ===", + "header": "=== MESHTASTIC KEYS FOR {{longName}} ({{shortName}}) ===", + "privateKey": "Private Key:", + "publicKey": "Public Key:", + "fileName": "meshtastic_keys_{{longName}}_{{shortName}}.txt", + "title": "Backup Keys" + }, + "pkiBackupReminder": { + "description": "We recommend backing up your key data regularly. Would you like to back up now?", + "title": "Backup Reminder", + "remindLaterPrefix": "Remind me in", + "remindNever": "Never remind me", + "backupNow": "Back up now" + }, + "pkiRegenerate": { + "description": "Are you sure you want to regenerate key pair?", + "title": "Regenerate Key Pair" + }, + "qr": { + "addChannels": "Add Channels", + "replaceChannels": "Replace Channels", + "description": "The current LoRa configuration will also be shared.", + "sharableUrl": "Sharable URL", + "title": "Generate QR Code" + }, + "reboot": { + "title": "Reboot device", + "description": "Reboot now or schedule a reboot of the connected node. Optionally, you can choose to reboot into OTA (Over-the-Air) mode.", + "ota": "Reboot into OTA mode", + "enterDelay": "Enter delay", + "scheduled": "Reboot has been scheduled", + "schedule": "Schedule reboot", + "now": "Reboot now", + "cancel": "Cancel scheduled reboot" + }, + "refreshKeys": { + "description": { + "acceptNewKeys": "This will remove the node from device and request new keys.", + "keyMismatchReasonSuffix": ". This is due to the remote node's current public key does not match the previously stored key for this node.", + "unableToSendDmPrefix": "Your node is unable to send a direct message to node: " + }, + "acceptNewKeys": "Accept New Keys", + "title": "Keys Mismatch - {{identifier}}" + }, + "removeNode": { + "description": "Are you sure you want to remove this Node?", + "title": "Remove Node?" + }, + "shutdown": { + "title": "Schedule Shutdown", + "description": "Turn off the connected node after x minutes." + }, + "traceRoute": { + "routeToDestination": "Route to destination:", + "routeBack": "Route back:" + }, + "tracerouteResponse": { + "title": "Traceroute: {{identifier}}" + }, + "unsafeRoles": { + "confirmUnderstanding": "Yes, I know what I'm doing", + "conjunction": " and the blog post about ", + "postamble": " and understand the implications of changing the role.", + "preamble": "I have read the ", + "choosingRightDeviceRole": "Choosing The Right Device Role", + "deviceRoleDocumentation": "Device Role Documentation", + "title": "¿Estás seguro?" + }, + "managedMode": { + "confirmUnderstanding": "Yes, I know what I'm doing", + "title": "¿Estás seguro?", + "description": "Enabling Managed Mode blocks client applications (including the web client) from writing configurations to a radio. Once enabled, radio configurations can only be changed through Remote Admin messages. This setting is not required for remote node administration." + }, + "clientNotification": { + "title": "Client Notification", + "TraceRoute can only be sent once every 30 seconds": "TraceRoute can only be sent once every 30 seconds", + "Compromised keys were detected and regenerated.": "Compromised keys were detected and regenerated." + }, + "resetNodeDb": { + "title": "Reset Node Database", + "description": "This will clear all nodes from the connected device's node database and clear all message history in the client. This cannot be undone. Are you sure you want to continue?", + "confirm": "Reset Node Database", + "failedTitle": "There was an error resetting the Node DB. Please try again." + }, + "clearAllStores": { + "title": "Clear All Local Storage", + "description": "This will clear all locally stored data, including message history and node databases for all previously connected devices. This will require you to reconnect to your node once complete and cannot be undone. Are you sure you want to continue?", + "confirm": "Clear all local storage", + "failedTitle": "There was an error clearing local storage. Please try again." + }, + "factoryResetDevice": { + "title": "Reiniciar dispositivo de fábrica", + "description": "This will factory reset the connected device, erasing all configurations and data on the device as well as all nodes and messages saved in the client. This cannot be undone. Are you sure you want to continue?", + "confirm": "Reiniciar dispositivo de fábrica", + "failedTitle": "There was an error performing the factory reset. Please try again." + }, + "factoryResetConfig": { + "title": "Configuración de reinicio de fábrica", + "description": "This will factory reset the configuration on the connected device, erasing all configurations on the device. This cannot be undone. Are you sure you want to continue?", + "confirm": "Configuración de reinicio de fábrica", + "failedTitle": "There was an error performing the factory reset. Please try again." + } } diff --git a/packages/web/public/i18n/locales/es-ES/map.json b/packages/web/public/i18n/locales/es-ES/map.json new file mode 100644 index 000000000..fc2b7c4f2 --- /dev/null +++ b/packages/web/public/i18n/locales/es-ES/map.json @@ -0,0 +1,38 @@ +{ + "maplibre": { + "GeolocateControl.FindMyLocation": "Find my location", + "NavigationControl.ZoomIn": "Zoom in", + "NavigationControl.ZoomOut": "Zoom out", + "CooperativeGesturesHandler.WindowsHelpText": "Use Ctrl + scroll to zoom the map", + "CooperativeGesturesHandler.MacHelpText": "Use ⌘ + scroll to zoom the map", + "CooperativeGesturesHandler.MobileHelpText": "Use two fingers to move the map" + }, + "layerTool": { + "nodeMarkers": "Show nodes", + "directNeighbors": "Show direct connections", + "remoteNeighbors": "Show remote connections", + "positionPrecision": "Show position precision", + "traceroutes": "Show traceroutes", + "waypoints": "Show waypoints" + }, + "mapMenu": { + "locateAria": "Locate my node", + "layersAria": "Change map style" + }, + "waypointDetail": { + "edit": "Editar", + "description": "Description:", + "createdBy": "Edited by:", + "createdDate": "Created:", + "updated": "Updated:", + "expires": "Expires:", + "distance": "Distance:", + "bearing": "Absolute bearing:", + "lockedTo": "Locked by:", + "latitude": "Latitude:", + "longitude": "Longitude:" + }, + "myNode": { + "tooltip": "This device" + } +} diff --git a/packages/web/public/i18n/locales/es-ES/messages.json b/packages/web/public/i18n/locales/es-ES/messages.json index 71238ea1c..c4c622f18 100644 --- a/packages/web/public/i18n/locales/es-ES/messages.json +++ b/packages/web/public/i18n/locales/es-ES/messages.json @@ -1,39 +1,39 @@ { - "page": { - "title": "Messages: {{chatName}}", - "placeholder": "Enter Message" - }, - "emptyState": { - "title": "Select a Chat", - "text": "No messages yet." - }, - "selectChatPrompt": { - "text": "Select a channel or node to start messaging." - }, - "sendMessage": { - "placeholder": "Enter your message here...", - "sendButton": "Enviar" - }, - "actionsMenu": { - "addReactionLabel": "Add Reaction", - "replyLabel": "Respuesta" - }, - "deliveryStatus": { - "delivered": { - "label": "Message delivered", - "displayText": "Message delivered" - }, - "failed": { - "label": "Message delivery failed", - "displayText": "Delivery failed" - }, - "unknown": { - "label": "Message status unknown", - "displayText": "Unknown state" - }, - "waiting": { - "label": "Sending message", - "displayText": "Waiting for delivery" - } - } + "page": { + "title": "Messages: {{chatName}}", + "placeholder": "Enter Message" + }, + "emptyState": { + "title": "Select a Chat", + "text": "No messages yet." + }, + "selectChatPrompt": { + "text": "Select a channel or node to start messaging." + }, + "sendMessage": { + "placeholder": "Enter your message here...", + "sendButton": "Enviar" + }, + "actionsMenu": { + "addReactionLabel": "Add Reaction", + "replyLabel": "Respuesta" + }, + "deliveryStatus": { + "delivered": { + "label": "Message delivered", + "displayText": "Message delivered" + }, + "failed": { + "label": "Message delivery failed", + "displayText": "Delivery failed" + }, + "unknown": { + "label": "Message status unknown", + "displayText": "Unknown state" + }, + "waiting": { + "label": "Sending message", + "displayText": "Waiting for delivery" + } + } } diff --git a/packages/web/public/i18n/locales/es-ES/moduleConfig.json b/packages/web/public/i18n/locales/es-ES/moduleConfig.json index 54e11bea1..35edc9019 100644 --- a/packages/web/public/i18n/locales/es-ES/moduleConfig.json +++ b/packages/web/public/i18n/locales/es-ES/moduleConfig.json @@ -1,448 +1,448 @@ { - "page": { - "tabAmbientLighting": "Luz Ambiental", - "tabAudio": "Audio", - "tabCannedMessage": "Canned", - "tabDetectionSensor": "Sensor de Presencia", - "tabExternalNotification": "Ext Notif", - "tabMqtt": "MQTT", - "tabNeighborInfo": "Información de Vecinos", - "tabPaxcounter": "Contador de Paquetes", - "tabRangeTest": "Test de Alcance", - "tabSerial": "Conexión Serial", - "tabStoreAndForward": "S&F", - "tabTelemetry": "Telemetría" - }, - "ambientLighting": { - "title": "Ambient Lighting Settings", - "description": "Settings for the Ambient Lighting module", - "ledState": { - "label": "LED State", - "description": "Sets LED to on or off" - }, - "current": { - "label": "Intensidad", - "description": "Sets the current for the LED output. Default is 10" - }, - "red": { - "label": "Rojo", - "description": "Sets the red LED level. Values are 0-255" - }, - "green": { - "label": "Verde", - "description": "Sets the green LED level. Values are 0-255" - }, - "blue": { - "label": "Azul", - "description": "Sets the blue LED level. Values are 0-255" - } - }, - "audio": { - "title": "Audio Settings", - "description": "Settings for the Audio module", - "codec2Enabled": { - "label": "Codec 2 Enabled", - "description": "Enable Codec 2 audio encoding" - }, - "pttPin": { - "label": "PTT Pin", - "description": "GPIO pin to use for PTT" - }, - "bitrate": { - "label": "Bitrate", - "description": "Bitrate to use for audio encoding" - }, - "i2sWs": { - "label": "i2S WS", - "description": "GPIO pin to use for i2S WS" - }, - "i2sSd": { - "label": "i2S SD", - "description": "GPIO pin to use for i2S SD" - }, - "i2sDin": { - "label": "i2S DIN", - "description": "GPIO pin to use for i2S DIN" - }, - "i2sSck": { - "label": "i2S SCK", - "description": "GPIO pin to use for i2S SCK" - } - }, - "cannedMessage": { - "title": "Canned Message Settings", - "description": "Settings for the Canned Message module", - "moduleEnabled": { - "label": "Module Enabled", - "description": "Enable Canned Message" - }, - "rotary1Enabled": { - "label": "Rotary Encoder #1 Enabled", - "description": "Enable the rotary encoder" - }, - "inputbrokerPinA": { - "label": "Encoder Pin A", - "description": "GPIO Pin Value (1-39) For encoder port A" - }, - "inputbrokerPinB": { - "label": "Encoder Pin B", - "description": "GPIO Pin Value (1-39) For encoder port B" - }, - "inputbrokerPinPress": { - "label": "Encoder Pin Press", - "description": "GPIO Pin Value (1-39) For encoder Press" - }, - "inputbrokerEventCw": { - "label": "Clockwise event", - "description": "Select input event." - }, - "inputbrokerEventCcw": { - "label": "Counter Clockwise event", - "description": "Select input event." - }, - "inputbrokerEventPress": { - "label": "Press event", - "description": "Select input event" - }, - "updown1Enabled": { - "label": "Up Down enabled", - "description": "Enable the up / down encoder" - }, - "allowInputSource": { - "label": "Allow Input Source", - "description": "Select from: '_any', 'rotEnc1', 'upDownEnc1', 'cardkb'" - }, - "sendBell": { - "label": "Send Bell", - "description": "Sends a bell character with each message" - } - }, - "detectionSensor": { - "title": "Detection Sensor Settings", - "description": "Settings for the Detection Sensor module", - "enabled": { - "label": "Habilitado", - "description": "Enable or disable Detection Sensor Module" - }, - "minimumBroadcastSecs": { - "label": "Minimum Broadcast Seconds", - "description": "The interval in seconds of how often we can send a message to the mesh when a state change is detected" - }, - "stateBroadcastSecs": { - "label": "State Broadcast Seconds", - "description": "The interval in seconds of how often we should send a message to the mesh with the current state regardless of changes" - }, - "sendBell": { - "label": "Send Bell", - "description": "Send ASCII bell with alert message" - }, - "name": { - "label": "Friendly Name", - "description": "Used to format the message sent to mesh, max 20 Characters" - }, - "monitorPin": { - "label": "Monitor Pin", - "description": "The GPIO pin to monitor for state changes" - }, - "detectionTriggerType": { - "label": "Detection Triggered Type", - "description": "The type of trigger event to be used" - }, - "usePullup": { - "label": "Use Pullup", - "description": "Whether or not use INPUT_PULLUP mode for GPIO pin" - } - }, - "externalNotification": { - "title": "External Notification Settings", - "description": "Configure the external notification module", - "enabled": { - "label": "Module Enabled", - "description": "Enable External Notification" - }, - "outputMs": { - "label": "Output MS", - "description": "Output MS" - }, - "output": { - "label": "Output", - "description": "Output" - }, - "outputVibra": { - "label": "Output Vibrate", - "description": "Output Vibrate" - }, - "outputBuzzer": { - "label": "Output Buzzer", - "description": "Output Buzzer" - }, - "active": { - "label": "Active", - "description": "Active" - }, - "alertMessage": { - "label": "Alert Message", - "description": "Alert Message" - }, - "alertMessageVibra": { - "label": "Alert Message Vibrate", - "description": "Alert Message Vibrate" - }, - "alertMessageBuzzer": { - "label": "Alert Message Buzzer", - "description": "Alert Message Buzzer" - }, - "alertBell": { - "label": "Alert Bell", - "description": "Should an alert be triggered when receiving an incoming bell?" - }, - "alertBellVibra": { - "label": "Alert Bell Vibrate", - "description": "Alert Bell Vibrate" - }, - "alertBellBuzzer": { - "label": "Alert Bell Buzzer", - "description": "Alert Bell Buzzer" - }, - "usePwm": { - "label": "Use PWM", - "description": "Use PWM" - }, - "nagTimeout": { - "label": "Nag Timeout", - "description": "Nag Timeout" - }, - "useI2sAsBuzzer": { - "label": "Use I²S Pin as Buzzer", - "description": "Designate I²S Pin as Buzzer Output" - } - }, - "mqtt": { - "title": "MQTT Settings", - "description": "Settings for the MQTT module", - "enabled": { - "label": "Habilitado", - "description": "Enable or disable MQTT" - }, - "address": { - "label": "MQTT Server Address", - "description": "MQTT server address to use for default/custom servers" - }, - "username": { - "label": "MQTT Username", - "description": "MQTT username to use for default/custom servers" - }, - "password": { - "label": "MQTT Password", - "description": "MQTT password to use for default/custom servers" - }, - "encryptionEnabled": { - "label": "Encryption Enabled", - "description": "Enable or disable MQTT encryption. Note: All messages are sent to the MQTT broker unencrypted if this option is not enabled, even when your uplink channels have encryption keys set. This includes position data." - }, - "jsonEnabled": { - "label": "JSON Enabled", - "description": "Whether to send/consume JSON packets on MQTT" - }, - "tlsEnabled": { - "label": "TLS Enabled", - "description": "Enable or disable TLS" - }, - "root": { - "label": "Root topic", - "description": "MQTT root topic to use for default/custom servers" - }, - "proxyToClientEnabled": { - "label": "MQTT Client Proxy Enabled", - "description": "Utilizes the network connection to proxy MQTT messages to the client." - }, - "mapReportingEnabled": { - "label": "Map Reporting Enabled", - "description": "Your node will periodically send an unencrypted map report packet to the configured MQTT server, this includes id, short and long name, approximate location, hardware model, role, firmware version, LoRa region, modem preset and primary channel name." - }, - "mapReportSettings": { - "publishIntervalSecs": { - "label": "Map Report Publish Interval (s)", - "description": "Interval in seconds to publish map reports" - }, - "positionPrecision": { - "label": "Approximate Location", - "description": "Position shared will be accurate within this distance", - "options": { - "metric_km23": "Within 23 km", - "metric_km12": "Within 12 km", - "metric_km5_8": "Within 5.8 km", - "metric_km2_9": "Within 2.9 km", - "metric_km1_5": "Within 1.5 km", - "metric_m700": "Within 700 m", - "metric_m350": "Within 350 m", - "metric_m200": "Within 200 m", - "metric_m90": "Within 90 m", - "metric_m50": "Within 50 m", - "imperial_mi15": "Within 15 miles", - "imperial_mi7_3": "Within 7.3 miles", - "imperial_mi3_6": "Within 3.6 miles", - "imperial_mi1_8": "Within 1.8 miles", - "imperial_mi0_9": "Within 0.9 miles", - "imperial_mi0_5": "Within 0.5 miles", - "imperial_mi0_2": "Within 0.2 miles", - "imperial_ft600": "Within 600 feet", - "imperial_ft300": "Within 300 feet", - "imperial_ft150": "Within 150 feet" - } - } - } - }, - "neighborInfo": { - "title": "Neighbor Info Settings", - "description": "Settings for the Neighbor Info module", - "enabled": { - "label": "Habilitado", - "description": "Enable or disable Neighbor Info Module" - }, - "updateInterval": { - "label": "Update Interval", - "description": "Interval in seconds of how often we should try to send our Neighbor Info to the mesh" - } - }, - "paxcounter": { - "title": "Paxcounter Settings", - "description": "Settings for the Paxcounter module", - "enabled": { - "label": "Module Enabled", - "description": "Enable Paxcounter" - }, - "paxcounterUpdateInterval": { - "label": "Update Interval (seconds)", - "description": "How long to wait between sending paxcounter packets" - }, - "wifiThreshold": { - "label": "WiFi RSSI Threshold", - "description": "At what WiFi RSSI level should the counter increase. Defaults to -80." - }, - "bleThreshold": { - "label": "BLE RSSI Threshold", - "description": "At what BLE RSSI level should the counter increase. Defaults to -80." - } - }, - "rangeTest": { - "title": "Range Test Settings", - "description": "Settings for the Range Test module", - "enabled": { - "label": "Module Enabled", - "description": "Enable Range Test" - }, - "sender": { - "label": "Message Interval", - "description": "How long to wait between sending test packets" - }, - "save": { - "label": "Save CSV to storage", - "description": "ESP32 Only" - } - }, - "serial": { - "title": "Serial Settings", - "description": "Settings for the Serial module", - "enabled": { - "label": "Module Enabled", - "description": "Enable Serial output" - }, - "echo": { - "label": "Echo", - "description": "Any packets you send will be echoed back to your device" - }, - "rxd": { - "label": "Receive Pin", - "description": "Set the GPIO pin to the RXD pin you have set up." - }, - "txd": { - "label": "Transmit Pin", - "description": "Set the GPIO pin to the TXD pin you have set up." - }, - "baud": { - "label": "Baud Rate", - "description": "The serial baud rate" - }, - "timeout": { - "label": "Tiempo agotado", - "description": "Seconds to wait before we consider your packet as 'done'" - }, - "mode": { - "label": "Mode", - "description": "Select Mode" - }, - "overrideConsoleSerialPort": { - "label": "Override Console Serial Port", - "description": "If you have a serial port connected to the console, this will override it." - } - }, - "storeForward": { - "title": "Store & Forward Settings", - "description": "Settings for the Store & Forward module", - "enabled": { - "label": "Module Enabled", - "description": "Enable Store & Forward" - }, - "heartbeat": { - "label": "Heartbeat Enabled", - "description": "Enable Store & Forward heartbeat" - }, - "records": { - "label": "Número de registros", - "description": "Number of records to store" - }, - "historyReturnMax": { - "label": "Historial máximo devuelto", - "description": "Max number of records to return" - }, - "historyReturnWindow": { - "label": "History return window", - "description": "Max number of records to return" - } - }, - "telemetry": { - "title": "Telemetry Settings", - "description": "Settings for the Telemetry module", - "deviceUpdateInterval": { - "label": "Device Metrics", - "description": "Periodo entre las actualizaciones de las medidas del dispositivo (segundos) " - }, - "environmentUpdateInterval": { - "label": "Periodo de refresco para las medidas del entorno", - "description": "" - }, - "environmentMeasurementEnabled": { - "label": "Module Enabled", - "description": "Enable the Environment Telemetry" - }, - "environmentScreenEnabled": { - "label": "Displayed on Screen", - "description": "Show the Telemetry Module on the OLED" - }, - "environmentDisplayFahrenheit": { - "label": "Display Fahrenheit", - "description": "Display temp in Fahrenheit" - }, - "airQualityEnabled": { - "label": "Air Quality Enabled", - "description": "Enable the Air Quality Telemetry" - }, - "airQualityInterval": { - "label": "Air Quality Update Interval", - "description": "How often to send Air Quality data over the mesh" - }, - "powerMeasurementEnabled": { - "label": "Power Measurement Enabled", - "description": "Enable the Power Measurement Telemetry" - }, - "powerUpdateInterval": { - "label": "Power Update Interval", - "description": "How often to send Power data over the mesh" - }, - "powerScreenEnabled": { - "label": "Power Screen Enabled", - "description": "Enable the Power Telemetry Screen" - } - } + "page": { + "tabAmbientLighting": "Luz Ambiental", + "tabAudio": "Audio", + "tabCannedMessage": "Canned", + "tabDetectionSensor": "Sensor de Presencia", + "tabExternalNotification": "Ext Notif", + "tabMqtt": "MQTT", + "tabNeighborInfo": "Información de Vecinos", + "tabPaxcounter": "Contador de Paquetes", + "tabRangeTest": "Test de Alcance", + "tabSerial": "Conexión Serial", + "tabStoreAndForward": "S&F", + "tabTelemetry": "Telemetría" + }, + "ambientLighting": { + "title": "Ambient Lighting Settings", + "description": "Settings for the Ambient Lighting module", + "ledState": { + "label": "LED State", + "description": "Sets LED to on or off" + }, + "current": { + "label": "Intensidad", + "description": "Sets the current for the LED output. Default is 10" + }, + "red": { + "label": "Rojo", + "description": "Sets the red LED level. Values are 0-255" + }, + "green": { + "label": "Verde", + "description": "Sets the green LED level. Values are 0-255" + }, + "blue": { + "label": "Azul", + "description": "Sets the blue LED level. Values are 0-255" + } + }, + "audio": { + "title": "Audio Settings", + "description": "Settings for the Audio module", + "codec2Enabled": { + "label": "Codec 2 Enabled", + "description": "Enable Codec 2 audio encoding" + }, + "pttPin": { + "label": "PTT Pin", + "description": "GPIO pin to use for PTT" + }, + "bitrate": { + "label": "Bitrate", + "description": "Bitrate to use for audio encoding" + }, + "i2sWs": { + "label": "i2S WS", + "description": "GPIO pin to use for i2S WS" + }, + "i2sSd": { + "label": "i2S SD", + "description": "GPIO pin to use for i2S SD" + }, + "i2sDin": { + "label": "i2S DIN", + "description": "GPIO pin to use for i2S DIN" + }, + "i2sSck": { + "label": "i2S SCK", + "description": "GPIO pin to use for i2S SCK" + } + }, + "cannedMessage": { + "title": "Canned Message Settings", + "description": "Settings for the Canned Message module", + "moduleEnabled": { + "label": "Module Enabled", + "description": "Enable Canned Message" + }, + "rotary1Enabled": { + "label": "Rotary Encoder #1 Enabled", + "description": "Enable the rotary encoder" + }, + "inputbrokerPinA": { + "label": "Encoder Pin A", + "description": "GPIO Pin Value (1-39) For encoder port A" + }, + "inputbrokerPinB": { + "label": "Encoder Pin B", + "description": "GPIO Pin Value (1-39) For encoder port B" + }, + "inputbrokerPinPress": { + "label": "Encoder Pin Press", + "description": "GPIO Pin Value (1-39) For encoder Press" + }, + "inputbrokerEventCw": { + "label": "Clockwise event", + "description": "Select input event." + }, + "inputbrokerEventCcw": { + "label": "Counter Clockwise event", + "description": "Select input event." + }, + "inputbrokerEventPress": { + "label": "Press event", + "description": "Select input event" + }, + "updown1Enabled": { + "label": "Up Down enabled", + "description": "Enable the up / down encoder" + }, + "allowInputSource": { + "label": "Allow Input Source", + "description": "Select from: '_any', 'rotEnc1', 'upDownEnc1', 'cardkb'" + }, + "sendBell": { + "label": "Send Bell", + "description": "Sends a bell character with each message" + } + }, + "detectionSensor": { + "title": "Detection Sensor Settings", + "description": "Settings for the Detection Sensor module", + "enabled": { + "label": "Habilitado", + "description": "Enable or disable Detection Sensor Module" + }, + "minimumBroadcastSecs": { + "label": "Minimum Broadcast Seconds", + "description": "The interval in seconds of how often we can send a message to the mesh when a state change is detected" + }, + "stateBroadcastSecs": { + "label": "State Broadcast Seconds", + "description": "The interval in seconds of how often we should send a message to the mesh with the current state regardless of changes" + }, + "sendBell": { + "label": "Send Bell", + "description": "Send ASCII bell with alert message" + }, + "name": { + "label": "Friendly Name", + "description": "Used to format the message sent to mesh, max 20 Characters" + }, + "monitorPin": { + "label": "Monitor Pin", + "description": "The GPIO pin to monitor for state changes" + }, + "detectionTriggerType": { + "label": "Detection Triggered Type", + "description": "The type of trigger event to be used" + }, + "usePullup": { + "label": "Use Pullup", + "description": "Whether or not use INPUT_PULLUP mode for GPIO pin" + } + }, + "externalNotification": { + "title": "External Notification Settings", + "description": "Configure the external notification module", + "enabled": { + "label": "Module Enabled", + "description": "Enable External Notification" + }, + "outputMs": { + "label": "Output MS", + "description": "Output MS" + }, + "output": { + "label": "Output", + "description": "Output" + }, + "outputVibra": { + "label": "Output Vibrate", + "description": "Output Vibrate" + }, + "outputBuzzer": { + "label": "Output Buzzer", + "description": "Output Buzzer" + }, + "active": { + "label": "Active", + "description": "Active" + }, + "alertMessage": { + "label": "Alert Message", + "description": "Alert Message" + }, + "alertMessageVibra": { + "label": "Alert Message Vibrate", + "description": "Alert Message Vibrate" + }, + "alertMessageBuzzer": { + "label": "Alert Message Buzzer", + "description": "Alert Message Buzzer" + }, + "alertBell": { + "label": "Alert Bell", + "description": "Should an alert be triggered when receiving an incoming bell?" + }, + "alertBellVibra": { + "label": "Alert Bell Vibrate", + "description": "Alert Bell Vibrate" + }, + "alertBellBuzzer": { + "label": "Alert Bell Buzzer", + "description": "Alert Bell Buzzer" + }, + "usePwm": { + "label": "Use PWM", + "description": "Use PWM" + }, + "nagTimeout": { + "label": "Nag Timeout", + "description": "Nag Timeout" + }, + "useI2sAsBuzzer": { + "label": "Use I²S Pin as Buzzer", + "description": "Designate I²S Pin as Buzzer Output" + } + }, + "mqtt": { + "title": "MQTT Settings", + "description": "Settings for the MQTT module", + "enabled": { + "label": "Habilitado", + "description": "Enable or disable MQTT" + }, + "address": { + "label": "MQTT Server Address", + "description": "MQTT server address to use for default/custom servers" + }, + "username": { + "label": "MQTT Username", + "description": "MQTT username to use for default/custom servers" + }, + "password": { + "label": "MQTT Password", + "description": "MQTT password to use for default/custom servers" + }, + "encryptionEnabled": { + "label": "Encryption Enabled", + "description": "Enable or disable MQTT encryption. Note: All messages are sent to the MQTT broker unencrypted if this option is not enabled, even when your uplink channels have encryption keys set. This includes position data." + }, + "jsonEnabled": { + "label": "JSON Enabled", + "description": "Whether to send/consume JSON packets on MQTT" + }, + "tlsEnabled": { + "label": "TLS Enabled", + "description": "Enable or disable TLS" + }, + "root": { + "label": "Root topic", + "description": "MQTT root topic to use for default/custom servers" + }, + "proxyToClientEnabled": { + "label": "MQTT Client Proxy Enabled", + "description": "Utilizes the network connection to proxy MQTT messages to the client." + }, + "mapReportingEnabled": { + "label": "Map Reporting Enabled", + "description": "Your node will periodically send an unencrypted map report packet to the configured MQTT server, this includes id, short and long name, approximate location, hardware model, role, firmware version, LoRa region, modem preset and primary channel name." + }, + "mapReportSettings": { + "publishIntervalSecs": { + "label": "Map Report Publish Interval (s)", + "description": "Interval in seconds to publish map reports" + }, + "positionPrecision": { + "label": "Approximate Location", + "description": "Position shared will be accurate within this distance", + "options": { + "metric_km23": "Within 23 km", + "metric_km12": "Within 12 km", + "metric_km5_8": "Within 5.8 km", + "metric_km2_9": "Within 2.9 km", + "metric_km1_5": "Within 1.5 km", + "metric_m700": "Within 700 m", + "metric_m350": "Within 350 m", + "metric_m200": "Within 200 m", + "metric_m90": "Within 90 m", + "metric_m50": "Within 50 m", + "imperial_mi15": "Within 15 miles", + "imperial_mi7_3": "Within 7.3 miles", + "imperial_mi3_6": "Within 3.6 miles", + "imperial_mi1_8": "Within 1.8 miles", + "imperial_mi0_9": "Within 0.9 miles", + "imperial_mi0_5": "Within 0.5 miles", + "imperial_mi0_2": "Within 0.2 miles", + "imperial_ft600": "Within 600 feet", + "imperial_ft300": "Within 300 feet", + "imperial_ft150": "Within 150 feet" + } + } + } + }, + "neighborInfo": { + "title": "Neighbor Info Settings", + "description": "Settings for the Neighbor Info module", + "enabled": { + "label": "Habilitado", + "description": "Enable or disable Neighbor Info Module" + }, + "updateInterval": { + "label": "Update Interval", + "description": "Interval in seconds of how often we should try to send our Neighbor Info to the mesh" + } + }, + "paxcounter": { + "title": "Paxcounter Settings", + "description": "Settings for the Paxcounter module", + "enabled": { + "label": "Module Enabled", + "description": "Enable Paxcounter" + }, + "paxcounterUpdateInterval": { + "label": "Update Interval (seconds)", + "description": "How long to wait between sending paxcounter packets" + }, + "wifiThreshold": { + "label": "WiFi RSSI Threshold", + "description": "At what WiFi RSSI level should the counter increase. Defaults to -80." + }, + "bleThreshold": { + "label": "BLE RSSI Threshold", + "description": "At what BLE RSSI level should the counter increase. Defaults to -80." + } + }, + "rangeTest": { + "title": "Range Test Settings", + "description": "Settings for the Range Test module", + "enabled": { + "label": "Module Enabled", + "description": "Enable Range Test" + }, + "sender": { + "label": "Message Interval", + "description": "How long to wait between sending test packets" + }, + "save": { + "label": "Save CSV to storage", + "description": "ESP32 Only" + } + }, + "serial": { + "title": "Serial Settings", + "description": "Settings for the Serial module", + "enabled": { + "label": "Module Enabled", + "description": "Enable Serial output" + }, + "echo": { + "label": "Echo", + "description": "Any packets you send will be echoed back to your device" + }, + "rxd": { + "label": "Receive Pin", + "description": "Set the GPIO pin to the RXD pin you have set up." + }, + "txd": { + "label": "Transmit Pin", + "description": "Set the GPIO pin to the TXD pin you have set up." + }, + "baud": { + "label": "Baud Rate", + "description": "The serial baud rate" + }, + "timeout": { + "label": "Tiempo agotado", + "description": "Seconds to wait before we consider your packet as 'done'" + }, + "mode": { + "label": "Mode", + "description": "Select Mode" + }, + "overrideConsoleSerialPort": { + "label": "Override Console Serial Port", + "description": "If you have a serial port connected to the console, this will override it." + } + }, + "storeForward": { + "title": "Store & Forward Settings", + "description": "Settings for the Store & Forward module", + "enabled": { + "label": "Module Enabled", + "description": "Enable Store & Forward" + }, + "heartbeat": { + "label": "Heartbeat Enabled", + "description": "Enable Store & Forward heartbeat" + }, + "records": { + "label": "Número de registros", + "description": "Number of records to store" + }, + "historyReturnMax": { + "label": "Historial máximo devuelto", + "description": "Max number of records to return" + }, + "historyReturnWindow": { + "label": "History return window", + "description": "Devolver registros de esta ventana de tiempo (minutos)" + } + }, + "telemetry": { + "title": "Telemetry Settings", + "description": "Settings for the Telemetry module", + "deviceUpdateInterval": { + "label": "Device Metrics", + "description": "Periodo entre las actualizaciones de las medidas del dispositivo (segundos) " + }, + "environmentUpdateInterval": { + "label": "Periodo de refresco para las medidas del entorno", + "description": "" + }, + "environmentMeasurementEnabled": { + "label": "Module Enabled", + "description": "Enable the Environment Telemetry" + }, + "environmentScreenEnabled": { + "label": "Displayed on Screen", + "description": "Show the Telemetry Module on the OLED" + }, + "environmentDisplayFahrenheit": { + "label": "Display Fahrenheit", + "description": "Display temp in Fahrenheit" + }, + "airQualityEnabled": { + "label": "Air Quality Enabled", + "description": "Enable the Air Quality Telemetry" + }, + "airQualityInterval": { + "label": "Air Quality Update Interval", + "description": "How often to send Air Quality data over the mesh" + }, + "powerMeasurementEnabled": { + "label": "Power Measurement Enabled", + "description": "Enable the Power Measurement Telemetry" + }, + "powerUpdateInterval": { + "label": "Power Update Interval", + "description": "How often to send Power data over the mesh" + }, + "powerScreenEnabled": { + "label": "Power Screen Enabled", + "description": "Enable the Power Telemetry Screen" + } + } } diff --git a/packages/web/public/i18n/locales/es-ES/nodes.json b/packages/web/public/i18n/locales/es-ES/nodes.json index 81caebf14..a24977daf 100644 --- a/packages/web/public/i18n/locales/es-ES/nodes.json +++ b/packages/web/public/i18n/locales/es-ES/nodes.json @@ -1,63 +1,59 @@ { - "nodeDetail": { - "publicKeyEnabled": { - "label": "Public Key Enabled" - }, - "noPublicKey": { - "label": "No Public Key" - }, - "directMessage": { - "label": "Direct Message {{shortName}}" - }, - "favorite": { - "label": "Favorito", - "tooltip": "Add or remove this node from your favorites" - }, - "notFavorite": { - "label": "Not a Favorite" - }, - "error": { - "label": "Error", - "text": "An error occurred while fetching node details. Please try again later." - }, - "status": { - "heard": "Heard", - "mqtt": "MQTT" - }, - "elevation": { - "label": "Elevation" - }, - "channelUtil": { - "label": "Channel Util" - }, - "airtimeUtil": { - "label": "Airtime Util" - } - }, - "nodesTable": { - "headings": { - "longName": "Long Name", - "connection": "Connection", - "lastHeard": "Last Heard", - "encryption": "Encryption", - "model": "Model", - "macAddress": "MAC Address" - }, - "connectionStatus": { - "direct": "Directo", - "away": "away", - "unknown": "-", - "viaMqtt": ", via MQTT" - }, - "lastHeardStatus": { - "never": "Never" - } - }, - "actions": { - "added": "Added", - "removed": "Removed", - "ignoreNode": "Ignore Node", - "unignoreNode": "Unignore Node", - "requestPosition": "Request Position" - } + "nodeDetail": { + "publicKeyEnabled": { + "label": "Public Key Enabled" + }, + "noPublicKey": { + "label": "No Public Key" + }, + "directMessage": { + "label": "Direct Message {{shortName}}" + }, + "favorite": { + "label": "Favorito", + "tooltip": "Add or remove this node from your favorites" + }, + "notFavorite": { + "label": "Not a Favorite" + }, + "error": { + "label": "Error", + "text": "An error occurred while fetching node details. Please try again later." + }, + "status": { + "heard": "Heard", + "mqtt": "MQTT" + }, + "elevation": { + "label": "Elevation" + }, + "channelUtil": { + "label": "Channel Util" + }, + "airtimeUtil": { + "label": "Airtime Util" + } + }, + "nodesTable": { + "headings": { + "longName": "Long Name", + "connection": "Connection", + "lastHeard": "Last Heard", + "encryption": "Cifrado", + "model": "Model", + "macAddress": "MAC Address" + }, + "connectionStatus": { + "direct": "Directo", + "away": "away", + "viaMqtt": ", via MQTT" + } + }, + "actions": { + "added": "Added", + "removed": "Removed", + "ignoreNode": "Ignore Node", + "unignoreNode": "Unignore Node", + "requestPosition": "Request Position" + } } diff --git a/packages/web/public/i18n/locales/es-ES/ui.json b/packages/web/public/i18n/locales/es-ES/ui.json index e7a1b9594..bcf133989 100644 --- a/packages/web/public/i18n/locales/es-ES/ui.json +++ b/packages/web/public/i18n/locales/es-ES/ui.json @@ -1,228 +1,230 @@ { - "navigation": { - "title": "Navigation", - "messages": "Mensajes", - "map": "Mapa", - "config": "Config", - "radioConfig": "Radio Config", - "moduleConfig": "Module Config", - "channels": "Canales", - "nodes": "Nodos" - }, - "app": { - "title": "Meshtastic", - "logo": "Meshtastic Logo" - }, - "sidebar": { - "collapseToggle": { - "button": { - "open": "Open sidebar", - "close": "Close sidebar" - } - }, - "deviceInfo": { - "volts": "{{voltage}} volts", - "firmware": { - "title": "Software", - "version": "v{{version}}", - "buildDate": "Build date: {{date}}" - }, - "deviceName": { - "title": "Device Name", - "changeName": "Change Device Name", - "placeholder": "Enter device name" - }, - "editDeviceName": "Edit device name" - } - }, - "batteryStatus": { - "charging": "{{level}}% charging", - "pluggedIn": "Plugged in", - "title": "Batería" - }, - "search": { - "nodes": "Search nodes...", - "channels": "Search channels...", - "commandPalette": "Search commands..." - }, - "toast": { - "positionRequestSent": { - "title": "Position request sent." - }, - "requestingPosition": { - "title": "Requesting position, please wait..." - }, - "sendingTraceroute": { - "title": "Sending Traceroute, please wait..." - }, - "tracerouteSent": { - "title": "Traceroute sent." - }, - "savedChannel": { - "title": "Saved Channel: {{channelName}}" - }, - "messages": { - "pkiEncryption": { - "title": "Chat is using PKI encryption." - }, - "pskEncryption": { - "title": "Chat is using PSK encryption." - } - }, - "configSaveError": { - "title": "Error Saving Config", - "description": "An error occurred while saving the configuration." - }, - "validationError": { - "title": "Config Errors Exist", - "description": "Please fix the configuration errors before saving." - }, - "saveSuccess": { - "title": "Saving Config", - "description": "The configuration change {{case}} has been saved." - }, - "favoriteNode": { - "title": "{{action}} {{nodeName}} {{direction}} favorites.", - "action": { - "added": "Added", - "removed": "Removed", - "to": "to", - "from": "from" - } - }, - "ignoreNode": { - "title": "{{action}} {{nodeName}} {{direction}} ignore list", - "action": { - "added": "Added", - "removed": "Removed", - "to": "to", - "from": "from" - } - } - }, - "notifications": { - "copied": { - "label": "Copied!" - }, - "copyToClipboard": { - "label": "Copy to clipboard" - }, - "hidePassword": { - "label": "Ocultar contraseña" - }, - "showPassword": { - "label": "Mostrar contraseña" - }, - "deliveryStatus": { - "delivered": "Delivered", - "failed": "Delivery Failed", - "waiting": "Waiting", - "unknown": "Unknown" - } - }, - "general": { - "label": "General" - }, - "hardware": { - "label": "Hardware" - }, - "metrics": { - "label": "Metrics" - }, - "role": { - "label": "Rol" - }, - "filter": { - "label": "Filtro" - }, - "advanced": { - "label": "Advanced" - }, - "clearInput": { - "label": "Clear input" - }, - "resetFilters": { - "label": "Reset Filters" - }, - "nodeName": { - "label": "Node name/number", - "placeholder": "Meshtastic 1234" - }, - "airtimeUtilization": { - "label": "Airtime Utilization (%)" - }, - "batteryLevel": { - "label": "Battery level (%)", - "labelText": "Battery level (%): {{value}}" - }, - "batteryVoltage": { - "label": "Battery voltage (V)", - "title": "Tensión" - }, - "channelUtilization": { - "label": "Channel Utilization (%)" - }, - "hops": { - "direct": "Directo", - "label": "Number of hops", - "text": "Number of hops: {{value}}" - }, - "lastHeard": { - "label": "Última escucha", - "labelText": "Last heard: {{value}}", - "nowLabel": "Now" - }, - "snr": { - "label": "SNR (db)" - }, - "favorites": { - "label": "Favorites" - }, - "hide": { - "label": "Hide" - }, - "showOnly": { - "label": "Show Only" - }, - "viaMqtt": { - "label": "Connected via MQTT" - }, - "hopsUnknown": { - "label": "Unknown number of hops" - }, - "showUnheard": { - "label": "Never heard" - }, - "language": { - "label": "Idioma", - "changeLanguage": "Change Language" - }, - "theme": { - "dark": "Oscuro", - "light": "Claro", - "system": "Automatic", - "changeTheme": "Change Color Scheme" - }, - "errorPage": { - "title": "This is a little embarrassing...", - "description1": "We are really sorry but an error occurred in the web client that caused it to crash.
This is not supposed to happen, and we are working hard to fix it.", - "description2": "The best way to prevent this from happening again to you or anyone else is to report the issue to us.", - "reportInstructions": "Please include the following information in your report:", - "reportSteps": { - "step1": "What you were doing when the error occurred", - "step2": "What you expected to happen", - "step3": "What actually happened", - "step4": "Any other relevant information" - }, - "reportLink": "You can report the issue to our <0>GitHub", - "dashboardLink": "Return to the <0>dashboard", - "detailsSummary": "Error Details", - "errorMessageLabel": "Error message:", - "stackTraceLabel": "Stack trace:", - "fallbackError": "{{error}}" - }, - "footer": { - "text": "Powered by <0>▲ Vercel | Meshtastic® is a registered trademark of Meshtastic LLC. | <1>Legal Information", - "commitSha": "Commit SHA: {{sha}}" - } + "navigation": { + "title": "Navigation", + "messages": "Mensajes", + "map": "Mapa", + "settings": "Ajustes", + "channels": "Canales", + "radioConfig": "Radio Config", + "deviceConfig": "Configuración del dispositivo", + "moduleConfig": "Module Config", + "manageConnections": "Manage Connections", + "nodes": "Nodos" + }, + "app": { + "title": "Meshtastic", + "logo": "Meshtastic Logo" + }, + "sidebar": { + "collapseToggle": { + "button": { + "open": "Open sidebar", + "close": "Close sidebar" + } + }, + "deviceInfo": { + "volts": "{{voltage}} volts", + "firmware": { + "title": "Software", + "version": "v{{version}}", + "buildDate": "Build date: {{date}}" + } + } + }, + "batteryStatus": { + "charging": "{{level}}% charging", + "pluggedIn": "Plugged in", + "title": "Batería" + }, + "search": { + "nodes": "Search nodes...", + "channels": "Search channels...", + "commandPalette": "Search commands..." + }, + "toast": { + "positionRequestSent": { + "title": "Position request sent." + }, + "requestingPosition": { + "title": "Requesting position, please wait..." + }, + "sendingTraceroute": { + "title": "Sending Traceroute, please wait..." + }, + "tracerouteSent": { + "title": "Traceroute sent." + }, + "savedChannel": { + "title": "Saved Channel: {{channelName}}" + }, + "messages": { + "pkiEncryption": { + "title": "Chat is using PKI encryption." + }, + "pskEncryption": { + "title": "Chat is using PSK encryption." + } + }, + "configSaveError": { + "title": "Error Saving Config", + "description": "An error occurred while saving the configuration." + }, + "validationError": { + "title": "Config Errors Exist", + "description": "Please fix the configuration errors before saving." + }, + "saveSuccess": { + "title": "Saving Config", + "description": "The configuration change {{case}} has been saved." + }, + "saveAllSuccess": { + "title": "Saved", + "description": "All configuration changes have been saved." + }, + "favoriteNode": { + "title": "{{action}} {{nodeName}} {{direction}} favorites.", + "action": { + "added": "Added", + "removed": "Removed", + "to": "to", + "from": "from" + } + }, + "ignoreNode": { + "title": "{{action}} {{nodeName}} {{direction}} ignore list", + "action": { + "added": "Added", + "removed": "Removed", + "to": "to", + "from": "from" + } + } + }, + "notifications": { + "copied": { + "label": "Copied!" + }, + "copyToClipboard": { + "label": "Copy to clipboard" + }, + "hidePassword": { + "label": "Ocultar contraseña" + }, + "showPassword": { + "label": "Mostrar contraseña" + }, + "deliveryStatus": { + "delivered": "Delivered", + "failed": "Delivery Failed", + "waiting": "Waiting", + "unknown": "Unknown" + } + }, + "general": { + "label": "General" + }, + "hardware": { + "label": "Hardware" + }, + "metrics": { + "label": "Metrics" + }, + "role": { + "label": "Rol" + }, + "filter": { + "label": "Filtro" + }, + "advanced": { + "label": "Advanced" + }, + "clearInput": { + "label": "Clear input" + }, + "resetFilters": { + "label": "Reset Filters" + }, + "nodeName": { + "label": "Node name/number", + "placeholder": "Meshtastic 1234" + }, + "airtimeUtilization": { + "label": "Airtime Utilization (%)", + "short": "Airtime Util. (%)" + }, + "batteryLevel": { + "label": "Battery level (%)", + "labelText": "Battery level (%): {{value}}" + }, + "batteryVoltage": { + "label": "Battery voltage (V)", + "title": "Tensión" + }, + "channelUtilization": { + "label": "Channel Utilization (%)", + "short": "Channel Util. (%)" + }, + "hops": { + "direct": "Directo", + "label": "Number of hops", + "text": "Number of hops: {{value}}" + }, + "lastHeard": { + "label": "Última escucha", + "labelText": "Last heard: {{value}}", + "nowLabel": "Now" + }, + "snr": { + "label": "SNR (db)" + }, + "favorites": { + "label": "Favorites" + }, + "hide": { + "label": "Hide" + }, + "showOnly": { + "label": "Show Only" + }, + "viaMqtt": { + "label": "Connected via MQTT" + }, + "hopsUnknown": { + "label": "Unknown number of hops" + }, + "showUnheard": { + "label": "Never heard" + }, + "language": { + "label": "Idioma", + "changeLanguage": "Change Language" + }, + "theme": { + "dark": "Oscuro", + "light": "Claro", + "system": "Automatic", + "changeTheme": "Change Color Scheme" + }, + "errorPage": { + "title": "This is a little embarrassing...", + "description1": "We are really sorry but an error occurred in the web client that caused it to crash.
This is not supposed to happen, and we are working hard to fix it.", + "description2": "The best way to prevent this from happening again to you or anyone else is to report the issue to us.", + "reportInstructions": "Please include the following information in your report:", + "reportSteps": { + "step1": "What you were doing when the error occurred", + "step2": "What you expected to happen", + "step3": "What actually happened", + "step4": "Any other relevant information" + }, + "reportLink": "You can report the issue to our <0>GitHub", + "connectionsLink": "Return to the <0>connections", + "detailsSummary": "Error Details", + "errorMessageLabel": "Error message:", + "stackTraceLabel": "Stack trace:", + "fallbackError": "{{error}}" + }, + "footer": { + "text": "Powered by <0>▲ Vercel | Meshtastic® is a registered trademark of Meshtastic LLC. | <1>Legal Information", + "commitSha": "Commit SHA: {{sha}}" + } } diff --git a/packages/web/public/i18n/locales/fi-FI/channels.json b/packages/web/public/i18n/locales/fi-FI/channels.json index 50026bfe8..0ac9180a3 100644 --- a/packages/web/public/i18n/locales/fi-FI/channels.json +++ b/packages/web/public/i18n/locales/fi-FI/channels.json @@ -1,69 +1,71 @@ { - "page": { - "sectionLabel": "Kanavat", - "channelName": "Kanava: {{channelName}}", - "broadcastLabel": "Ensisijainen", - "channelIndex": "Ch {{index}}" - }, - "validation": { - "pskInvalid": "Syötä kelvollinen {{bits}} bittinen PSK." - }, - "settings": { - "label": "Kanava-asetukset", - "description": "Crypto, MQTT ja muut asetukset" - }, - "role": { - "label": "Rooli", - "description": "Laitteen telemetriatiedot lähetetään ENSISIJAISEN kanavan kautta. Vain yksi ENSISIJAINEN kanava sallitaan", - "options": { - "primary": "ENSISIJAISEN", - "disabled": "POIS KÄYTÖSTÄ", - "secondary": "TOISIJAINEN" - } - }, - "psk": { - "label": "Esijaettu avain", - "description": "Tuetut PSK-pituudet: 256-bit, 128-bit, 8-bit, tyhjät (0-bit)", - "generate": "Luo" - }, - "name": { - "label": "Nimi", - "description": "Kanavan yksilöllinen nimi (alle 12 merkkiä), jätä tyhjäksi käyttääksesi oletusta" - }, - "uplinkEnabled": { - "label": "Lähetys käytössä", - "description": "Lähetä viestejä paikallisesta verkosta MQTT-verkkoon" - }, - "downlinkEnabled": { - "label": "Vastaanotto käytössä", - "description": "Lähetä viestejä MQTT:stä paikalliseen verkkoon" - }, - "positionPrecision": { - "label": "Sijainti", - "description": "Kanavalle jaettavan sijainnin tarkkuus. Voi poistaa käytöstä.", - "options": { - "none": "Älä jaa sijaintia", - "precise": "Tarkka Sijainti", - "metric_km23": "23 kilometrin säteellä", - "metric_km12": "12 kilometrin säteellä", - "metric_km5_8": "5,8 kilometrin säteellä", - "metric_km2_9": "2,9 kilometrin säteellä", - "metric_km1_5": "1,5 kilometrin säteellä", - "metric_m700": "700 metrin säteellä", - "metric_m350": "350 metrin säteellä", - "metric_m200": "200 metrin säteellä", - "metric_m90": "90 metrin säteellä", - "metric_m50": "50 metrin säteellä", - "imperial_mi15": "15 mailin säteellä", - "imperial_mi7_3": "7,3 mailin säteellä", - "imperial_mi3_6": "3,6 mailin säteellä", - "imperial_mi1_8": "1,8 mailin säteellä", - "imperial_mi0_9": "0,9 mailin säteellä", - "imperial_mi0_5": "0,5 mailin säteellä", - "imperial_mi0_2": "0,2 mailin säteellä", - "imperial_ft600": "600 jalan säteellä", - "imperial_ft300": "300 jalan säteellä", - "imperial_ft150": "150 jalan säteellä" - } - } + "page": { + "sectionLabel": "Kanavat", + "channelName": "Kanava: {{channelName}}", + "broadcastLabel": "Ensisijainen", + "channelIndex": "Ch {{index}}", + "import": "Tuo", + "export": "Vie" + }, + "validation": { + "pskInvalid": "Syötä kelvollinen {{bits}} bittinen PSK." + }, + "settings": { + "label": "Kanava-asetukset", + "description": "Crypto, MQTT ja muut asetukset" + }, + "role": { + "label": "Rooli", + "description": "Laitteen telemetriatiedot lähetetään ENSISIJAISEN kanavan kautta. Vain yksi ENSISIJAINEN kanava sallitaan", + "options": { + "primary": "ENSISIJAISEN", + "disabled": "POIS KÄYTÖSTÄ", + "secondary": "TOISIJAINEN" + } + }, + "psk": { + "label": "Esijaettu avain", + "description": "Tuetut PSK-pituudet: 256-bit, 128-bit, 8-bit, tyhjät (0-bit)", + "generate": "Luo" + }, + "name": { + "label": "Nimi", + "description": "Kanavan yksilöllinen nimi (alle 12 merkkiä), jätä tyhjäksi käyttääksesi oletusta" + }, + "uplinkEnabled": { + "label": "Lähetys käytössä", + "description": "Lähetä viestejä paikallisesta verkosta MQTT-verkkoon" + }, + "downlinkEnabled": { + "label": "Vastaanotto käytössä", + "description": "Lähetä viestejä MQTT:stä paikalliseen verkkoon" + }, + "positionPrecision": { + "label": "Sijainti", + "description": "Kanavalle jaettavan sijainnin tarkkuus. Voi poistaa käytöstä.", + "options": { + "none": "Älä jaa sijaintia", + "precise": "Tarkka Sijainti", + "metric_km23": "23 kilometrin säteellä", + "metric_km12": "12 kilometrin säteellä", + "metric_km5_8": "5,8 kilometrin säteellä", + "metric_km2_9": "2,9 kilometrin säteellä", + "metric_km1_5": "1,5 kilometrin säteellä", + "metric_m700": "700 metrin säteellä", + "metric_m350": "350 metrin säteellä", + "metric_m200": "200 metrin säteellä", + "metric_m90": "90 metrin säteellä", + "metric_m50": "50 metrin säteellä", + "imperial_mi15": "15 mailin säteellä", + "imperial_mi7_3": "7,3 mailin säteellä", + "imperial_mi3_6": "3,6 mailin säteellä", + "imperial_mi1_8": "1,8 mailin säteellä", + "imperial_mi0_9": "0,9 mailin säteellä", + "imperial_mi0_5": "0,5 mailin säteellä", + "imperial_mi0_2": "0,2 mailin säteellä", + "imperial_ft600": "600 jalan säteellä", + "imperial_ft300": "300 jalan säteellä", + "imperial_ft150": "150 jalan säteellä" + } + } } diff --git a/packages/web/public/i18n/locales/fi-FI/commandPalette.json b/packages/web/public/i18n/locales/fi-FI/commandPalette.json index 4b8e8e832..66cacaa22 100644 --- a/packages/web/public/i18n/locales/fi-FI/commandPalette.json +++ b/packages/web/public/i18n/locales/fi-FI/commandPalette.json @@ -15,7 +15,6 @@ "messages": "Viestit", "map": "Kartta", "config": "Asetukset", - "channels": "Kanavat", "nodes": "Laitteet" } }, @@ -45,7 +44,8 @@ "label": "Vianetsintä", "command": { "reconfigure": "Määritä uudelleen", - "clearAllStoredMessages": "Tyhjennä kaikki tallennetut viesti" + "clearAllStoredMessages": "Tyhjennä kaikki tallennetut viesti", + "clearAllStores": "Tyhjennä kaikki paikallisesta tallennustilasta" } } } diff --git a/packages/web/public/i18n/locales/fi-FI/common.json b/packages/web/public/i18n/locales/fi-FI/common.json index f1f77c0e8..f44163edf 100644 --- a/packages/web/public/i18n/locales/fi-FI/common.json +++ b/packages/web/public/i18n/locales/fi-FI/common.json @@ -1,142 +1,165 @@ { - "button": { - "apply": "Hyväksy", - "backupKey": "Varmuuskopioi avain", - "cancel": "Peruuta", - "clearMessages": "Tyhjennä viestit", - "close": "Sulje", - "confirm": "Vahvista", - "delete": "Poista", - "dismiss": "Hylkää", - "download": "Lataa", - "export": "Vie", - "generate": "Luo", - "regenerate": "Luo uudelleen", - "import": "Tuo", - "message": "Viesti", - "now": "Nyt", - "ok": "OK", - "print": "Tulosta", - "remove": "Poista", - "requestNewKeys": "Pyydä uudet avaimet", - "requestPosition": "Pyydä sijaintia", - "reset": "Palauta", - "save": "Tallenna", - "scanQr": "Skannaa QR-koodi", - "traceRoute": "Reitinselvitys", - "submit": "Lähetä" - }, - "app": { - "title": "Meshtastic", - "fullTitle": "Meshtastic Web Client" - }, - "loading": "Ladataan...", - "unit": { - "cps": "CPS", - "dbm": "dBm", - "hertz": "Hz", - "hop": { - "one": "Hyppy", - "plural": "Hyppyä" - }, - "hopsAway": { - "one": "{{count}} hypyn päässä", - "plural": "{{count}} hypyn päässä", - "unknown": "Hyppyjen määrä tuntematon" - }, - "megahertz": "MHz", - "raw": "raakatieto", - "meter": { - "one": "Metri", - "plural": "Metriä", - "suffix": "m" - }, - "minute": { - "one": "Minuutti", - "plural": "Minuuttia" - }, - "hour": { - "one": "Tunti", - "plural": "Tuntia" - }, - "millisecond": { - "one": "Millisekunti", - "plural": "Millisekuntia", - "suffix": "ms" - }, - "second": { - "one": "Sekunti", - "plural": "Sekuntia" - }, - "day": { - "one": "Päivä", - "plural": "Päivää" - }, - "month": { - "one": "Kuukausi", - "plural": "Kuukautta" - }, - "year": { - "one": "Vuosi", - "plural": "Vuotta" - }, - "snr": "SNR", - "volt": { - "one": "Voltti", - "plural": "Voltit", - "suffix": "V" - }, - "record": { - "one": "Tiedot", - "plural": "Tiedot" - } - }, - "security": { - "0bit": "Tyhjä", - "8bit": "8-bittiä", - "128bit": "128-bittiä", - "256bit": "256 bittiä" - }, - "unknown": { - "longName": "Tuntematon", - "shortName": "UNK", - "notAvailable": "N/A", - "num": "??" - }, - "nodeUnknownPrefix": "!", - "unset": "EI ASETETTU", - "fallbackName": "Meshtastic {{last4}}", - "node": "Laite", - "formValidation": { - "unsavedChanges": "Tallentamattomat muutokset", - "tooBig": { - "string": "Teksti on liian pitkä – sallittu enimmäispituus on {{maximum}} merkkiä.", - "number": "Arvo on liian suuri – sallittu enimmäisarvo on {{maximum}}.", - "bytes": "Liian suuri koko – sallittu enimmäismäärä on {{params.maximum}} tavua." - }, - "tooSmall": { - "string": "Teksti on liian lyhyt – vähimmäispituus on {{minimum}} merkkiä.", - "number": "Arvo on liian pieni – pienin sallittu arvo on {{minimum}}." - }, - "invalidFormat": { - "ipv4": "Virheellinen muoto – odotettu muoto on IPv4-osoite.", - "key": "Virheellinen muoto – odotettu muoto on Base64-koodattu jaettu avain (PSK)." - }, - "invalidType": { - "number": "Virheellinen tyyppi – arvon tulee olla numero." - }, - "pskLength": { - "0bit": "Avainkentän on oltava tyhjä.", - "8bit": "Avaimen on oltava 8-bittinen jaettu avain (PSK).", - "128bit": "Avaimen on oltava 128-bittinen jaettu avain (PSK).", - "256bit": "Avaimen on oltava 256-bittinen jaettu avain (PSK)." - }, - "required": { - "generic": "Tämä kenttä on pakollinen.", - "managed": "Vähintään yksi hallinta-avain vaaditaan, jos laitetta hallitaan.", - "key": "Avain on pakollinen." - } - }, - "yes": "Kyllä", - "no": "Ei" + "button": { + "apply": "Hyväksy", + "addConnection": "Lisää yhteys", + "saveConnection": "Tallenna yhteys", + "backupKey": "Varmuuskopioi avain", + "cancel": "Peruuta", + "connect": "Yhdistä", + "clearMessages": "Tyhjennä viestit", + "close": "Sulje", + "confirm": "Vahvista", + "delete": "Poista", + "dismiss": "Hylkää", + "download": "Lataa", + "disconnect": "Katkaise yhteys", + "export": "Vie", + "generate": "Luo", + "regenerate": "Luo uudelleen", + "import": "Tuo", + "message": "Viesti", + "now": "Nyt", + "ok": "OK", + "print": "Tulosta", + "remove": "Poista", + "requestNewKeys": "Pyydä uudet avaimet", + "requestPosition": "Pyydä sijaintia", + "reset": "Palauta", + "retry": "Yritä uudelleen", + "save": "Tallenna", + "setDefault": "Aseta oletukseksi", + "unsetDefault": "Poista oletusasetus", + "scanQr": "Skannaa QR-koodi", + "traceRoute": "Reitinselvitys", + "submit": "Lähetä" + }, + "app": { + "title": "Meshtastic", + "fullTitle": "Meshtastic Web Client" + }, + "loading": "Ladataan...", + "unit": { + "cps": "CPS", + "dbm": "dBm", + "hertz": "Hz", + "hop": { + "one": "Hyppy", + "plural": "Hyppyä" + }, + "hopsAway": { + "one": "{{count}} hypyn päässä", + "plural": "{{count}} hypyn päässä", + "unknown": "Hyppyjen määrä tuntematon" + }, + "megahertz": "MHz", + "kilohertz": "kHz", + "raw": "raakatieto", + "meter": { + "one": "Metri", + "plural": "Metriä", + "suffix": "m" + }, + "kilometer": { + "one": "Kilometri", + "plural": "Kilometriä", + "suffix": "km" + }, + "minute": { + "one": "Minuutti", + "plural": "Minuuttia" + }, + "hour": { + "one": "Tunti", + "plural": "Tuntia" + }, + "millisecond": { + "one": "Millisekunti", + "plural": "Millisekuntia", + "suffix": "ms" + }, + "second": { + "one": "Sekunti", + "plural": "Sekuntia" + }, + "day": { + "one": "Päivä", + "plural": "Päivää", + "today": "Tänään", + "yesterday": "Eilen" + }, + "month": { + "one": "Kuukausi", + "plural": "Kuukautta" + }, + "year": { + "one": "Vuosi", + "plural": "Vuotta" + }, + "snr": "SNR", + "volt": { + "one": "Voltti", + "plural": "Voltit", + "suffix": "V" + }, + "record": { + "one": "Tiedot", + "plural": "Tiedot" + }, + "degree": { + "one": "Aste", + "plural": "Astetta", + "suffix": "°" + } + }, + "security": { + "0bit": "Tyhjä", + "8bit": "8-bittiä", + "128bit": "128-bittiä", + "256bit": "256 bittiä" + }, + "unknown": { + "longName": "Tuntematon", + "shortName": "UNK", + "notAvailable": "N/A", + "num": "??" + }, + "nodeUnknownPrefix": "!", + "unset": "EI ASETETTU", + "fallbackName": "Meshtastic {{last4}}", + "node": "Laite", + "formValidation": { + "unsavedChanges": "Tallentamattomat muutokset", + "tooBig": { + "string": "Teksti on liian pitkä – sallittu enimmäispituus on {{maximum}} merkkiä.", + "number": "Arvo on liian suuri – sallittu enimmäisarvo on {{maximum}}.", + "bytes": "Liian suuri koko – sallittu enimmäismäärä on {{params.maximum}} tavua." + }, + "tooSmall": { + "string": "Teksti on liian lyhyt – vähimmäispituus on {{minimum}} merkkiä.", + "number": "Arvo on liian pieni – pienin sallittu arvo on {{minimum}}." + }, + "invalidFormat": { + "ipv4": "Virheellinen muoto – odotettu muoto on IPv4-osoite.", + "key": "Virheellinen muoto – odotettu muoto on Base64-koodattu jaettu avain (PSK)." + }, + "invalidType": { + "number": "Virheellinen tyyppi – arvon tulee olla numero." + }, + "pskLength": { + "0bit": "Avainkentän on oltava tyhjä.", + "8bit": "Avaimen on oltava 8-bittinen jaettu avain (PSK).", + "128bit": "Avaimen on oltava 128-bittinen jaettu avain (PSK).", + "256bit": "Avaimen on oltava 256-bittinen jaettu avain (PSK)." + }, + "required": { + "generic": "Tämä kenttä on pakollinen.", + "managed": "Vähintään yksi hallinta-avain vaaditaan, jos laitetta hallitaan.", + "key": "Avain on pakollinen." + }, + "invalidOverrideFreq": { + "number": "Virheellinen arvo, odotetaan taajuutta väliltä 410–930 MHz tai arvoa 0 (käytä oletusta)." + } + }, + "yes": "Kyllä", + "no": "Ei" } diff --git a/packages/web/public/i18n/locales/fi-FI/config.json b/packages/web/public/i18n/locales/fi-FI/config.json new file mode 100644 index 000000000..9afdf90fa --- /dev/null +++ b/packages/web/public/i18n/locales/fi-FI/config.json @@ -0,0 +1,458 @@ +{ + "page": { + "title": "Asetukset", + "tabUser": "Käyttäjä", + "tabChannels": "Kanavat", + "tabBluetooth": "Bluetooth", + "tabDevice": "Laite", + "tabDisplay": "Näyttö", + "tabLora": "LoRa", + "tabNetwork": "Verkko", + "tabPosition": "Sijainti", + "tabPower": "Virta", + "tabSecurity": "Turvallisuus" + }, + "sidebar": { + "label": "Asetukset" + }, + "device": { + "title": "Laitteen asetukset", + "description": "Laitteen asetukset", + "buttonPin": { + "description": "Painikkeen pinnin ohitus", + "label": "Painikkeen pinni" + }, + "buzzerPin": { + "description": "Summerin pinnin ohitus", + "label": "Summerin pinni" + }, + "disableTripleClick": { + "description": "Poista kolmoisklikkaus käytöstä", + "label": "Poista kolmoisklikkaus käytöstä" + }, + "doubleTapAsButtonPress": { + "description": "Käsittele kaksoisnapautus painikkeen painalluksena", + "label": "Kaksoisnapautus painikkeen painalluksena" + }, + "ledHeartbeatDisabled": { + "description": "Poista ledin vilkkuminen käytöstä", + "label": "Ledin vilkkuminen poistettu käytöstä" + }, + "nodeInfoBroadcastInterval": { + "description": "Kuinka usein laitteen tiedot lähetetään verkkoon", + "label": "Laitteen tietojen lähetyksen aikaväli" + }, + "posixTimezone": { + "description": "POSIX-aikavyöhykkeen merkkijono laitetta varten", + "label": "POSIX-aikavyöhyke" + }, + "rebroadcastMode": { + "description": "Kuinka uudelleenlähetyksiä käsitellään", + "label": "Uudelleenlähetyksen tila" + }, + "role": { + "description": "Mikä rooli laitteella on mesh-verkossa", + "label": "Rooli" + } + }, + "bluetooth": { + "title": "Bluetooth asetukset", + "description": "Bluetooth moduulin asetukset", + "note": "Huomautus: Jotkin laitteet (ESP32) eivät voi käyttää bluetoothia sekä WiFiä samanaikaisesti.", + "enabled": { + "description": "Ota Bluetooth käyttöön tai poista käytöstä", + "label": "Käytössä" + }, + "pairingMode": { + "description": "PIN-koodin valinnan käyttäytyminen.", + "label": "Paritustila" + }, + "pin": { + "description": "Bluetooth PIN-koodi, jota käytetään pariliitettäessä", + "label": "PIN" + } + }, + "display": { + "description": "Laitteen näytön asetukset", + "title": "Näyttöasetukset", + "headingBold": { + "description": "Lihavoi otsikkoteksti", + "label": "Lihavoitu otsikko" + }, + "carouselDelay": { + "description": "Kuinka nopeasti ikkunat kulkevat", + "label": "Karusellin Viive" + }, + "compassNorthTop": { + "description": "Kiinnitä pohjoinen kompassin yläreunaan", + "label": "Kompassin pohjoinen ylhäällä" + }, + "displayMode": { + "description": "Näytön asettelun vaihtoehdot", + "label": "Näyttötila" + }, + "displayUnits": { + "description": "Näytä metriset tai imperiaaliset yksiköt", + "label": "Näyttöyksiköt" + }, + "flipScreen": { + "description": "Käännä näyttöä 180 astetta", + "label": "Käännä näyttö" + }, + "gpsDisplayUnits": { + "description": "Koordinaattien näyttömuoto", + "label": "GPS näyttöyksiköt" + }, + "oledType": { + "description": "Laitteeseen liitetyn OLED-näytön tyyppi", + "label": "OLED-tyyppi" + }, + "screenTimeout": { + "description": "Sammuta näyttö tämän ajan jälkeen", + "label": "Näytön aikakatkaisu" + }, + "twelveHourClock": { + "description": "Käytä 12 tunnin kelloa", + "label": "12 tunnin kello" + }, + "wakeOnTapOrMotion": { + "description": "Herätä laite napauttamalla tai liikkeestä", + "label": "Herätä napauttamalla tai liikkeellä" + } + }, + "lora": { + "title": "Mesh-verkon asetukset", + "description": "LoRa-verkon asetukset", + "bandwidth": { + "description": "Kanavan kaistanleveys kHz", + "label": "Kaistanleveys" + }, + "boostedRxGain": { + "description": "RX tehostettu vahvistus", + "label": "RX tehostettu vahvistus" + }, + "codingRate": { + "description": "Koodausnopeuden nimittäjä", + "label": "Koodausnopeus" + }, + "frequencyOffset": { + "description": "Taajuuskorjaus kalibrointivirheiden korjaamiseksi", + "label": "Taajuuspoikkeama" + }, + "frequencySlot": { + "description": "LoRa-taajuuden kanavanumero", + "label": "Taajuuspaikka" + }, + "hopLimit": { + "description": "Maksimimäärä hyppyjä", + "label": "Hyppyraja" + }, + "ignoreMqtt": { + "description": "Älä välitä MQTT-viestejä mesh-verkon yli", + "label": "Ohita MQTT" + }, + "modemPreset": { + "description": "Käytössä olevan modeemin esiasetus", + "label": "Modeemin esiasetus" + }, + "okToMqtt": { + "description": "Kun asetetaan arvoksi true, tämä asetus tarkoittaa, että käyttäjä hyväksyy paketin lähettämisen MQTT:lle. Jos asetetaan arvoksi false, etälaitteita pyydetään olemaan välittämättä paketteja MQTT:lle", + "label": "MQTT päällä" + }, + "overrideDutyCycle": { + "description": "Ohita käyttöaste (Duty Cycle)", + "label": "Ohita käyttöaste (Duty Cycle)" + }, + "overrideFrequency": { + "description": "Käytä mukautettua taajuutta", + "label": "Mukautettu taajuus" + }, + "region": { + "description": "Asettaa alueen laitteelle", + "label": "Alue" + }, + "spreadingFactor": { + "description": "Ilmaisee symbolia kohden lähetettävien taajuuksien määrän", + "label": "Levennyskerroin" + }, + "transmitEnabled": { + "description": "LoRa-radion lähetyksen (TX) käyttöönotto tai poiskytkentä", + "label": "Lähetys käytössä" + }, + "transmitPower": { + "description": "Suurin lähetysteho", + "label": "Lähetysteho" + }, + "usePreset": { + "description": "Käytä ennalta määriteltyä modeemin esiasetusta", + "label": "Käytä esiasetusta" + }, + "meshSettings": { + "description": "LoRa-verkon asetukset", + "label": "Mesh-verkon asetukset" + }, + "waveformSettings": { + "description": "LoRa-aaltomuodon asetukset", + "label": "Signaalimuodon asetukset" + }, + "radioSettings": { + "label": "Radioasetukset", + "description": "LoRa-laitteen asetukset" + } + }, + "network": { + "title": "WiFi-asetukset", + "description": "WiFi-radion asetukset", + "note": "Huomautus: Jotkin laitteet (ESP32) eivät voi käyttää sekä Bluetoothia että WiFiä samanaikaisesti.", + "addressMode": { + "description": "Osoitteen määrityksen valinta", + "label": "Osoitetila" + }, + "dns": { + "description": "DNS-palvelin", + "label": "DNS" + }, + "ethernetEnabled": { + "description": "Ota käyttöön tai poista käytöstä ethernet-portti", + "label": "Käytössä" + }, + "gateway": { + "description": "Oletusyhdyskäytävä", + "label": "Yhdyskäytävä" + }, + "ip": { + "description": "IP-osoite", + "label": "IP" + }, + "psk": { + "description": "Verkon salasana", + "label": "PSK" + }, + "ssid": { + "description": "Verkon nimi", + "label": "SSID" + }, + "subnet": { + "description": "Aliverkon peite", + "label": "Aliverkko" + }, + "wifiEnabled": { + "description": "Ota WiFi käyttöön tai poista se käytöstä", + "label": "Käytössä" + }, + "meshViaUdp": { + "label": "Mesh UDP:n kautta" + }, + "ntpServer": { + "label": "NTP-palvelin" + }, + "rsyslogServer": { + "label": "Rsyslog-palvelin" + }, + "ethernetConfigSettings": { + "description": "Ethernet-portin asetukset", + "label": "Ethernet-asetukset" + }, + "ipConfigSettings": { + "description": "IP-osoitteen asetukset", + "label": "IP-osoitteen asetukset" + }, + "ntpConfigSettings": { + "description": "NTP-asetukset", + "label": "NTP-asetukset" + }, + "rsyslogConfigSettings": { + "description": "Rsyslog määritykset", + "label": "Rsyslog määritykset" + }, + "udpConfigSettings": { + "description": "UDP-yhdeyden asetukset", + "label": "UDP-asetukset" + } + }, + "position": { + "title": "Sijainnin asetukset", + "description": "Sijaintimoduulin asetukset", + "broadcastInterval": { + "description": "Kuinka usein sijainti lähetetään mesh-verkon yli", + "label": "Lähetyksen aikaväli" + }, + "enablePin": { + "description": "GPS-moduulin käyttöönottopinnin korvaus", + "label": "Ota pinni käytöön" + }, + "fixedPosition": { + "description": "Älä raportoi GPS-sijaintia, vaan käytä manuaalisesti määritettyä sijaintia", + "label": "Kiinteä sijainti" + }, + "gpsMode": { + "description": "Määritä, onko laitteen GPS käytössä, pois päältä vai puuttuuko se kokonaan", + "label": "GSP-tila" + }, + "gpsUpdateInterval": { + "description": "Kuinka usein GPS-paikannus suoritetaan", + "label": "GPS-päivitysväli" + }, + "positionFlags": { + "description": "Valinnaiset kentät, jotka voidaan sisällyttää sijaintiviesteihin. Mitä enemmän kenttiä valitaan, sitä suurempi viesti on, mikä johtaa pidempään lähetysaikaan ja suurempaan pakettihäviöriskiin.", + "label": "Sijaintimerkinnät" + }, + "receivePin": { + "description": "GPS-moduulin käyttöönottopinnin korvaus", + "label": "Vastaanoton pinni" + }, + "smartPositionEnabled": { + "description": "Lähetä sijainti vain, kun sijainnissa on tapahtunut merkittävä muutos", + "label": "Ota älykäs sijainti käyttöön" + }, + "smartPositionMinDistance": { + "description": "Vähimmäisetäisyys (metreinä), joka on kuljettava ennen sijaintipäivityksen lähettämistä", + "label": "Älykkään sijainnin minimietäisyys" + }, + "smartPositionMinInterval": { + "description": "Lyhin aikaväli (sekunteina), joka on kuluttava ennen sijaintipäivityksen lähettämistä", + "label": "Älykkään sijainnin vähimmäisetäisyys" + }, + "transmitPin": { + "description": "GPS-moduulin käyttöönottopinnin korvaus", + "label": "Lähetyksen pinni" + }, + "intervalsSettings": { + "description": "Kuinka usein sijaintipäivitykset lähetetään", + "label": "Aikaväli" + }, + "flags": { + "placeholder": "Valitse sijaintiasetukset...", + "altitude": "Korkeus", + "altitudeGeoidalSeparation": "Korkeuden geoidinen erotus", + "altitudeMsl": "Korkeus on mitattu merenpinnan tasosta", + "dop": "Tarkkuuden heikkenemä (DOP), oletuksena käytetään PDOP-arvoa", + "hdopVdop": "Jos DOP on asetettu, käytä HDOP- ja VDOP-arvoja PDOP:n sijaan", + "numSatellites": "Satelliittien määrä", + "sequenceNumber": "Sekvenssinumero", + "timestamp": "Aikaleima", + "unset": "Ei yhdistetty", + "vehicleHeading": "Ajoneuvon suunta", + "vehicleSpeed": "Ajoneuvon nopeus" + } + }, + "power": { + "adcMultiplierOverride": { + "description": "Käytetään akun jännitteen lukeman säätämiseen", + "label": "Korvaava AD-muuntimen kerroin" + }, + "ina219Address": { + "description": "Akkunäytön INA219 osoite", + "label": "INA219 Osoite" + }, + "lightSleepDuration": { + "description": "Kuinka kauan laite on kevyessä lepotilassa", + "label": "Kevyen lepotilan kesto" + }, + "minimumWakeTime": { + "description": "Vähimmäisaika, jonka laite pysyy hereillä paketin vastaanoton jälkeen", + "label": "Minimi heräämisaika" + }, + "noConnectionBluetoothDisabled": { + "description": "Jos laite ei saa Bluetooth-yhteyttä, BLE-radio poistetaan käytöstä tämän ajan kuluttua", + "label": "Ei yhteyttä. Bluetooth on pois käytöstä" + }, + "powerSavingEnabled": { + "description": "Valitse, jos laite saa virtaa matalavirtalähteestä (esim. aurinkopaneeli), jolloin virrankulutusta minimoidaan mahdollisimman paljon.", + "label": "Ota virransäästötila käyttöön" + }, + "shutdownOnBatteryDelay": { + "description": "Sammuta laite automaattisesti tämän ajan kuluttua akkukäytöllä, 0 tarkoittaa toistaiseksi päällä", + "label": "Viive laitteen sammuttamisessa akkukäytöllä" + }, + "superDeepSleepDuration": { + "description": "Kuinka pitkään laite on supersyvässä lepotilassa", + "label": "Supersyvän lepotilan kesto" + }, + "powerConfigSettings": { + "description": "Virtamoduulin asetukset", + "label": "Virran asetukset" + }, + "sleepSettings": { + "description": "Virtamoduulin lepotila-asetukset", + "label": "Lepotilan asetukset" + } + }, + "security": { + "description": "Turvallisuuskokoonpanon asetukset", + "title": "Turvallisuusasetukset", + "button_backupKey": "Varmuuskopioi avain", + "adminChannelEnabled": { + "description": "Salli saapuva laitteen ohjaus suojaamattoman vanhan admin-kanavan kautta", + "label": "Salli vanha admin ylläpitäjä" + }, + "enableDebugLogApi": { + "description": "Lähetä reaaliaikainen debug-loki sarjaportin kautta, katso ja vie laitteen lokitiedostot, joista sijaintitiedot on poistettu, Bluetoothin kautta", + "label": "Ota käyttöön virheenkorjauslokin API-rajapinta" + }, + "managed": { + "description": "Jos tämä on käytössä, laitteen asetuksia voi muuttaa vain etäadmin-laitteen hallintaviestien kautta. Älä ota tätä käyttöön, ellei vähintään yhtä sopivaa etäadmin-laitetta ole määritetty ja julkinen avain ei ole tallennettu johonkin yllä olevista kentistä.", + "label": "Hallinnoitu" + }, + "privateKey": { + "description": "Käytetään jaetun avaimen luomiseen etälaitteen kanssa", + "label": "Yksityinen avain" + }, + "publicKey": { + "description": "Lähetetään muille mesh-verkon laitteille, jotta ne voivat laskea jaetun salaisen avaimen", + "label": "Julkinen avain" + }, + "primaryAdminKey": { + "description": "Ensisijainen julkinen avain, jolla on oikeus lähettää hallintaviestejä tälle laitteelle", + "label": "Ensisijainen järjestelmänvalvojan avain" + }, + "secondaryAdminKey": { + "description": "Toissijainen julkinen avain, jolla on oikeus lähettää hallintaviestejä tälle laitteelle", + "label": "Toissijainen järjestelmänvalvojan avain" + }, + "serialOutputEnabled": { + "description": "Sarjakonsoli Stream API:n yli", + "label": "Sarjaulostulo Käytössä" + }, + "tertiaryAdminKey": { + "description": "Kolmas julkinen avain, jolla on oikeus lähettää hallintaviestejä tälle laitteelle", + "label": "Kolmas järjestelmänvalvojan hallinta-avain" + }, + "adminSettings": { + "description": "Järjestelmänvalvojan asetukset", + "label": "Ylläpitäjän asetukset" + }, + "loggingSettings": { + "description": "Kirjautumisen asetukset", + "label": "Kirjautumisen asetukset" + } + }, + "user": { + "title": "Käyttäjäasetukset", + "description": "Aseta laitteen nimi ja tunnistetiedot", + "longName": { + "label": "Pitkä nimi", + "description": "Koko näyttönimi (1–40 merkkiä)", + "validation": { + "min": "Pitkässä nimessä on oltava vähintään 1 merkki", + "max": "Pitkässä nimessä saa olla enintään 40 merkkiä" + } + }, + "shortName": { + "label": "Lyhytnimi", + "description": "Lyhytnimesi (2–4 merkkiä)", + "validation": { + "min": "Lyhytnimen on oltava vähintään 2 merkkiä pitkä", + "max": "Lyhytnimessä saa olla enintään 4 merkkiä" + } + }, + "isUnmessageable": { + "label": "Ei vastaanota viestejä", + "description": "Käytetään tunnistamaan valvomattomat tai infrastruktuurilaitteet, jotta viestintä ei olisi käytettävissä laitteille, jotka eivät koskaan vastaa." + }, + "isLicensed": { + "label": "Lisensoitu radioamatööri (HAM)", + "description": "Ota käyttöön, jos olet luvanvarainen radioamatööri. Tämän asetuksen käyttöönotto poistaa salauksen käytöstä, eikä se ole yhteensopiva oletusarvoisen Meshtastic-verkon kanssa." + } + } +} diff --git a/packages/web/public/i18n/locales/fi-FI/connections.json b/packages/web/public/i18n/locales/fi-FI/connections.json new file mode 100644 index 000000000..a0a12cd8b --- /dev/null +++ b/packages/web/public/i18n/locales/fi-FI/connections.json @@ -0,0 +1,34 @@ +{ + "page": { + "title": "Yhdistä Meshtastic-laitteeseen", + "description": "Lisää laiteyhteys HTTP:n, Bluetoothin tai sarjaportin kautta. Tallennetut yhteydet tallennetaan selaimeesi." + }, + "connectionType_ble": "BLE", + "connectionType_serial": "Sarjaliitäntä", + "connectionType_network": "Verkko", + "deleteConnection": "Poista yhteys", + "areYouSure": "Tämä poistaa kohteen {{name}}. Tätä toimintoa ei voi perua.", + "moreActions": "Lisää toimintoja", + "noConnections": { + "title": "Ei yhteyksiä vielä.", + "description": "Luo ensimmäinen yhteytesi. Yhteys muodostetaan heti ja tallennetaan myöhempää käyttöä varten." + }, + "lastConnectedAt": "Viimeksi yhdistetty: {{date}}", + "neverConnected": "Ei koskaan yhdistetty", + "toasts": { + "connected": "Yhdistetty", + "nowConnected": "{{name}} on nyt yhdistetty", + "nowDisconnected": "{{name}} ei ole enää yhteydessä", + "disconnected": "Ei yhdistetty", + "failed": "Yhteyden muodostaminen epäonnistui", + "checkConnetion": "Tarkista laitteesi tai asetukset ja yritä uudelleen", + "defaultSet": "Asetettu oletukseksi", + "defaultConnection": "Oletusyhteys on nyt {{nameisconnected}}", + "deleted": "Poistettu", + "deletedByName": "{{name}} poistettiin", + "pickConnectionAgain": "Yhteyttä ei voitu muodostaa. Saatat joutua valitsemaan laitteen tai portin uudelleen.", + "added": "Yhteys lisätty", + "savedByName": "{{name}} tallennettu.", + "savedCantConnect": "Yhteys tallennettiin, mutta siihen ei voitu yhdistää." + } +} diff --git a/packages/web/public/i18n/locales/fi-FI/dashboard.json b/packages/web/public/i18n/locales/fi-FI/dashboard.json deleted file mode 100644 index 99ba7db3d..000000000 --- a/packages/web/public/i18n/locales/fi-FI/dashboard.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "dashboard": { - "title": "Yhdistetyt laitteet", - "description": "Hallitse yhdistettyjä Meshtastic laitteitasi.", - "connectionType_ble": "BLE", - "connectionType_serial": "Sarjaliitäntä", - "connectionType_network": "Verkko", - "noDevicesTitle": "Ei laitteita yhdistettynä", - "noDevicesDescription": "Yhdistä uusi laite aloittaaksesi.", - "button_newConnection": "Uusi yhteys" - } -} diff --git a/packages/web/public/i18n/locales/fi-FI/deviceConfig.json b/packages/web/public/i18n/locales/fi-FI/deviceConfig.json index cdbfde2f0..6b9a77275 100644 --- a/packages/web/public/i18n/locales/fi-FI/deviceConfig.json +++ b/packages/web/public/i18n/locales/fi-FI/deviceConfig.json @@ -122,7 +122,7 @@ "title": "Mesh-verkon asetukset", "description": "LoRa-verkon asetukset", "bandwidth": { - "description": "Kanavan kaistanleveys MHz", + "description": "Kanavan kaistanleveys kHz", "label": "Kaistanleveys" }, "boostedRxGain": { diff --git a/packages/web/public/i18n/locales/fi-FI/dialog.json b/packages/web/public/i18n/locales/fi-FI/dialog.json index 7f33bec24..6f4ab5ed1 100644 --- a/packages/web/public/i18n/locales/fi-FI/dialog.json +++ b/packages/web/public/i18n/locales/fi-FI/dialog.json @@ -1,193 +1,238 @@ { - "deleteMessages": { - "description": "Tämä toiminto poistaa kaiken viestihistorian. Toimintoa ei voi perua. Haluatko varmasti jatkaa?", - "title": "Tyhjennä kaikki viestit" - }, - "deviceName": { - "description": "Laite käynnistyy uudelleen, kun asetus on tallennettu.", - "longName": "Pitkä nimi", - "shortName": "Lyhytnimi", - "title": "Vaihda laitteen nimi", - "validation": { - "longNameMax": "Pitkässä nimessä saa olla enintään 40 merkkiä", - "shortNameMax": "Lyhytnimessä ei saa olla enempää kuin 4 merkkiä", - "longNameMin": "Pitkässä nimessä täytyy olla vähintään yksi merkki", - "shortNameMin": "Lyhytnimessä täytyy olla vähintään ykis merkki" - } - }, - "import": { - "description": "Nykyinen LoRa-asetus ylikirjoitetaan.", - "error": { - "invalidUrl": "Virheellinen Meshtastic verkko-osoite" - }, - "channelPrefix": "Kanava: ", - "channelSetUrl": "Kanavan asetus / QR-koodin URL-osoite", - "channels": "Kanavat:", - "usePreset": "Käytä esiasetusta?", - "title": "Tuo kanava-asetukset" - }, - "locationResponse": { - "title": "Sijainti: {{identifier}}", - "altitude": "Korkeus: ", - "coordinates": "Koordinaatit: ", - "noCoordinates": "Ei koordinaatteja" - }, - "pkiRegenerateDialog": { - "title": "Luodaanko ennalta jaettu avain uudelleen?", - "description": "Haluatko varmasti luoda ennalta jaetun avaimen uudelleen?", - "regenerate": "Luo uudelleen" - }, - "newDeviceDialog": { - "title": "Yhdistä uuteen laitteeseen", - "https": "https", - "http": "http", - "tabHttp": "HTTP", - "tabBluetooth": "Bluetooth", - "tabSerial": "Sarjaliitäntä", - "useHttps": "Käytä HTTPS", - "connecting": "Yhdistetään...", - "connect": "Yhdistä", - "connectionFailedAlert": { - "title": "Yhteys epäonnistui", - "descriptionPrefix": "Laitteeseen ei saatu yhteyttä. ", - "httpsHint": "Jos käytät HTTPS:ää, sinun on ehkä ensin hyväksyttävä itse allekirjoitettu varmenne. ", - "openLinkPrefix": "Avaa ", - "openLinkSuffix": " uuteen välilehteen", - "acceptTlsWarningSuffix": ", hyväksy mahdolliset TLS-varoitukset, jos niitä ilmenee ja yritä sitten uudelleen.", - "learnMoreLink": "Lue lisää" - }, - "httpConnection": { - "label": "IP-osoite / isäntänimi", - "placeholder": "000.000.000 / meshtastinen.paikallinen" - }, - "serialConnection": { - "noDevicesPaired": "Yhtään laitetta ei ole vielä yhdistetty.", - "newDeviceButton": "Uusi laite", - "deviceIdentifier": "# {{index}} - {{vendorId}} - {{productId}}" - }, - "bluetoothConnection": { - "noDevicesPaired": "Yhtään laitetta ei ole vielä yhdistetty.", - "newDeviceButton": "Uusi laite", - "connectionFailed": "Yhdistäminen epäonnistui", - "deviceDisconnected": "Yhteys laitteeseen katkaistu", - "unknownDevice": "Tuntematon laite", - "errorLoadingDevices": "Virhe ladattaessa laitteita", - "unknownErrorLoadingDevices": "Tuntematon virhe laitteita ladattaessa" - }, - "validation": { - "requiresWebBluetooth": "Tämä yhteystyyppi vaatii <0>Web-sarjaportti bluetooth -tuen. Käytä tuettua selainta, kuten Chromea tai Edgeä.", - "requiresWebSerial": "Tämä yhteystyyppi vaatii <0>Web-sarjaportti -tuen. Käytä tuettua selainta, kuten Chromea tai Edgeä.", - "requiresSecureContext": "Tämä sovellus vaatii <0>suojatun yhteyden. Yhdistä käyttämällä HTTPS:ää tai localhostia.", - "additionallyRequiresSecureContext": "Lisäksi se vaatii <0>suojatun yhteyden. Yhdistä käyttämällä HTTPS:ää tai localhostia." - } - }, - "nodeDetails": { - "message": "Viesti", - "requestPosition": "Pyydä sijaintia", - "traceRoute": "Reitinselvitys", - "airTxUtilization": "Ilmatien TX käyttöaste", - "allRawMetrics": "Kaikki raakatiedot:", - "batteryLevel": "Akun varaus", - "channelUtilization": "Kanavan käyttöaste", - "details": "Tiedot:", - "deviceMetrics": "Laitteen mittausloki:", - "hardware": "Laitteisto: ", - "lastHeard": "Viimeksi kuultu: ", - "nodeHexPrefix": "Laitteen Hex: ", - "nodeNumber": "Laitteen numero: ", - "position": "Sijainti:", - "role": "Rooli: ", - "uptime": "Käyttöaika: ", - "voltage": "Jännite", - "title": "Tiedot laitteelle {{identifier}}", - "ignoreNode": "Älä huomioi laitetta", - "removeNode": "Poista laite", - "unignoreNode": "Poista laitteen ohitus käytöstä", - "security": "Turvallisuus:", - "publicKey": "Julkinen avain: ", - "messageable": "Viestittävissä: ", - "KeyManuallyVerifiedTrue": "Julkinen avain on vahvistettu manuaalisesti", - "KeyManuallyVerifiedFalse": "Julkista avainta ei ole vahvistettu manuaalisesti" - }, - "pkiBackup": { - "loseKeysWarning": "Jos menetät avaimesi, sinun täytyy palauttaa laite tehdasasetuksiin.", - "secureBackup": "On tärkeää varmuuskopioida julkiset ja yksityiset avaimet ja säilyttää niiden varmuuskopioita turvallisesti!", - "footer": "=== AVAIMIEN LOPPU ===", - "header": "=== MESHTASTIC AVAIMET {{longName}} ({{shortName}}) LAITTEELLE ===", - "privateKey": "Yksityinen avain:", - "publicKey": "Julkinen avain:", - "fileName": "meshtastic_avaimet_{{longName}}_{{shortName}}.txt", - "title": "Varmuuskopioi avaimet" - }, - "pkiBackupReminder": { - "description": "Suosittelemme avaintietojen säännöllistä varmuuskopiointia. Haluatko varmuuskopioida nyt?", - "title": "Varmuuskopion Muistutus", - "remindLaterPrefix": "Muistuta minua", - "remindNever": "Älä muistuta minua koskaan", - "backupNow": "Varmuuskopioi nyt" - }, - "pkiRegenerate": { - "description": "Haluatko varmasti luoda avainparin uudelleen?", - "title": "Luo avainpari uudelleen" - }, - "qr": { - "addChannels": "Lisää kanavia", - "replaceChannels": "Korvaa kanavia", - "description": "Nykyinen LoRa-kokoonpano tullaan myös jakamaan.", - "sharableUrl": "Jaettava URL", - "title": "Generoi QR-koodi" - }, - "reboot": { - "title": "Käynnistä laite uudelleen", - "description": "Käynnistä laite uudelleen heti tai ajasta sen uudelleenkäynnistys. Halutessasi voit valita käynnistyksen OTA-tilaan (Over-the-Air ohjelmistopäivitystilaan).", - "ota": "Käynnistä uudelleen OTA-tilaan", - "enterDelay": "Aseta viive", - "scheduled": "Uudelleenkäynnistys on ajastettu", - "schedule": "Ajasta uudelleen käynnistys", - "now": "Uudelleen käynnistä nyt", - "cancel": "Peruuta ajastettu uudelleen käynnistys" - }, - "refreshKeys": { - "description": { - "acceptNewKeys": "Tämä poistaa laitteen laitteesta ja pyytää uusia avaimia.", - "keyMismatchReasonSuffix": ". Tämä johtuu siitä, että etälaitteen nykyinen julkinen avain ei vastaa aiemmin tallennettua avainta tälle laitteelle.", - "unableToSendDmPrefix": "Laitteesi ei pysty lähettämään suoraa viestiä laitteelle: " - }, - "acceptNewKeys": "Hyväksy uudet avaimet", - "title": "Avaimet eivät täsmää - {{identifier}}" - }, - "removeNode": { - "description": "Haluatko varmasti poistaa tämän laitteen?", - "title": "Poista laite?" - }, - "shutdown": { - "title": "Ajasta sammutus", - "description": "Sammuta yhdistetty laite x minuutin päästä." - }, - "traceRoute": { - "routeToDestination": "Reitin määränpää:", - "routeBack": "Reitti takaisin:" - }, - "tracerouteResponse": { - "title": "Reitinselvitys: {{identifier}}" - }, - "unsafeRoles": { - "confirmUnderstanding": "Kyllä, tiedän mitä teen", - "conjunction": " ja blogikirjoitukset ", - "postamble": " ja ymmärrän roolin muuttamisen vaikutukset.", - "preamble": "Olen lukenut ", - "choosingRightDeviceRole": "Valitse laitteelle oikea rooli", - "deviceRoleDocumentation": "Roolien dokumentaatio laitteelle", - "title": "Oletko varma?" - }, - "managedMode": { - "confirmUnderstanding": "Kyllä, tiedän mitä teen", - "title": "Oletko varma?", - "description": "Hallintatilan käyttöönotto estää asiakassovelluksia (mukaan lukien verkkoselain) tekemästä muutoksia laitteen asetuksiin. Kun hallintatila on käytössä, laitteen asetuksia voidaan muuttaa ainoastaan etähallintaviesteillä (Remote Admin). Tämä asetus ei ole pakollinen etähallintaan." - }, - "clientNotification": { - "title": "Sovellusilmoitukset", - "TraceRoute can only be sent once every 30 seconds": "Reitinselvityksen voi tehdä kerran 30:ssä sekunnissa", - "Compromised keys were detected and regenerated.": "Turvallisuudeltaan vaarantuneet avaimet havaittiin ja ne generoitiin uudestaan." - } + "deleteMessages": { + "description": "Tämä toiminto poistaa kaiken viestihistorian. Toimintoa ei voi perua. Haluatko varmasti jatkaa?", + "title": "Tyhjennä kaikki viestit" + }, + "import": { + "description": "Nykyinen LoRa-asetus ylikirjoitetaan.", + "error": { + "invalidUrl": "Virheellinen Meshtastic verkko-osoite" + }, + "channelPrefix": "Kanava: ", + "primary": "Ensisijainen ", + "doNotImport": "Tuonti ei onnistu", + "channelName": "Nimi", + "channelSlot": "Paikka", + "channelSetUrl": "Kanavan asetus / QR-koodin URL-osoite", + "useLoraConfig": "Tuo LoRa-asetukset", + "presetDescription": "Nykyiset LoRa-asetukset korvataan uusilla.", + "title": "Tuo kanava-asetukset" + }, + "locationResponse": { + "title": "Sijainti: {{identifier}}", + "altitude": "Korkeus: ", + "coordinates": "Koordinaatit: ", + "noCoordinates": "Ei koordinaatteja" + }, + "pkiRegenerateDialog": { + "title": "Luodaanko ennalta jaettu avain uudelleen?", + "description": "Haluatko varmasti luoda ennalta jaetun avaimen uudelleen?", + "regenerate": "Luo uudelleen" + }, + "addConnection": { + "title": "Lisää yhteys", + "description": "Valitse yhteystyyppi ja täytä tiedot", + "validation": { + "requiresWebBluetooth": "Tämä yhteystyyppi vaatii <0>Web-sarjaportti bluetooth -tuen. Käytä tuettua selainta, kuten Chromea tai Edgeä.", + "requiresWebSerial": "Tämä yhteystyyppi vaatii <0>Web-sarjaportti -tuen. Käytä tuettua selainta, kuten Chromea tai Edgeä.", + "requiresSecureContext": "Tämä sovellus vaatii <0>suojatun yhteyden. Yhdistä käyttämällä HTTPS:ää tai localhostia.", + "additionallyRequiresSecureContext": "Lisäksi se vaatii <0>suojatun yhteyden. Yhdistä käyttämällä HTTPS:ää tai localhostia." + }, + "bluetoothConnection": { + "namePlaceholder": "Bluetoothilla yhdistetty laite", + "supported": { + "title": "Verkkoselaimen Bluetooth-tuettu" + }, + "notSupported": { + "title": "Verkkoselaimen Bluetooth ei ole tuettu", + "description": "Selaimesi tai laitteesi ei tue Web Bluetooth -toimintoa" + }, + "short": "BT: {{deviceName}}", + "long": "Bluetooth-laite", + "device": "Laite", + "selectDevice": "Valitse laite", + "selected": "Bluetooth-laite valittu", + "notSelected": "Ei laitetta valittuna", + "helperText": "Käyttää Meshtasticin Bluetooth-palvelua laitteiden etsintään." + }, + "serialConnection": { + "namePlaceholder": "Sarjaliitännällä yhdistetty laite", + "helperText": "Portin valitseminen antaa sovellukselle luvan avata sen yhteyden muodostamista varten.", + "supported": { + "title": "Verkkoselaimen sarjaliitäntä tuettu" + }, + "notSupported": { + "title": "Verkkoselaimen sarjaliitäntä ei ole tuettu", + "description": "Selaimesi tai laitteesi ei tue Web Serial -toimintoa" + }, + "portSelected": { + "title": "Sarjaportti valittu", + "description": "Porttioikeudet myönnetty." + }, + "port": "Portti", + "selectPort": "Valitse portti", + "deviceName": "USB {{vendorId}}:{{productId}}", + "notSelected": "Ei porttia valittuna" + }, + "httpConnection": { + "namePlaceholder": "HTTP-yhteydellä toimiva laite", + "inputPlaceholder": "192.168.1.10 tai meshtastic.local", + "heading": "URL tai IP", + "useHttps": "Käytä HTTTPS", + "invalidUrl": { + "title": "Virheellinen URL-osoite", + "description": "Anna kelvollinen HTTP- tai HTTPS-osoite." + }, + "connectionTest": { + "description": "Testaa yhteys ennen tallennusta varmistaaksesi, että laite on tavoitettavissa.", + "button": { + "loading": "Testataan...", + "label": "Testaa yhteys" + }, + "reachable": "Yhteys toimii", + "notReachable": "Yhteys ei toimi", + "success": { + "title": "Yhteystesti onnistui", + "description": "Laite vaikuttaa olevan tavoitettavissa." + }, + "failure": { + "title": "Yhteystesti epäonnistui", + "description": "Laitetta ei voitu tavoittaa. Tarkista URL-osoite ja yritä uudelleen." + } + } + } + }, + "nodeDetails": { + "message": "Viesti", + "requestPosition": "Pyydä sijaintia", + "traceRoute": "Reitinselvitys", + "airTxUtilization": "Ilmatien TX käyttöaste", + "allRawMetrics": "Kaikki raakatiedot:", + "batteryLevel": "Akun varaus", + "channelUtilization": "Kanavan käyttöaste", + "details": "Tiedot:", + "deviceMetrics": "Laitteen mittausloki:", + "hardware": "Laitteisto: ", + "lastHeard": "Viimeksi kuultu: ", + "nodeHexPrefix": "Laitteen Hex: ", + "nodeNumber": "Laitteen numero: ", + "position": "Sijainti:", + "role": "Rooli: ", + "uptime": "Käyttöaika: ", + "voltage": "Jännite", + "title": "Tiedot laitteelle {{identifier}}", + "ignoreNode": "Älä huomioi laitetta", + "removeNode": "Poista laite", + "unignoreNode": "Poista laitteen ohitus käytöstä", + "security": "Turvallisuus:", + "publicKey": "Julkinen avain: ", + "messageable": "Viestittävissä: ", + "KeyManuallyVerifiedTrue": "Julkinen avain on vahvistettu manuaalisesti", + "KeyManuallyVerifiedFalse": "Julkista avainta ei ole vahvistettu manuaalisesti" + }, + "pkiBackup": { + "loseKeysWarning": "Jos menetät avaimesi, sinun täytyy palauttaa laite tehdasasetuksiin.", + "secureBackup": "On tärkeää varmuuskopioida julkiset ja yksityiset avaimet ja säilyttää niiden varmuuskopioita turvallisesti!", + "footer": "=== AVAIMIEN LOPPU ===", + "header": "=== MESHTASTIC AVAIMET {{longName}} ({{shortName}}) LAITTEELLE ===", + "privateKey": "Yksityinen avain:", + "publicKey": "Julkinen avain:", + "fileName": "meshtastic_avaimet_{{longName}}_{{shortName}}.txt", + "title": "Varmuuskopioi avaimet" + }, + "pkiBackupReminder": { + "description": "Suosittelemme avaintietojen säännöllistä varmuuskopiointia. Haluatko varmuuskopioida nyt?", + "title": "Varmuuskopion Muistutus", + "remindLaterPrefix": "Muistuta minua", + "remindNever": "Älä muistuta minua koskaan", + "backupNow": "Varmuuskopioi nyt" + }, + "pkiRegenerate": { + "description": "Haluatko varmasti luoda avainparin uudelleen?", + "title": "Luo avainpari uudelleen" + }, + "qr": { + "addChannels": "Lisää kanavia", + "replaceChannels": "Korvaa kanavia", + "description": "Nykyinen LoRa-kokoonpano tullaan myös jakamaan.", + "sharableUrl": "Jaettava URL", + "title": "Generoi QR-koodi" + }, + "reboot": { + "title": "Käynnistä laite uudelleen", + "description": "Käynnistä laite uudelleen heti tai ajasta sen uudelleenkäynnistys. Halutessasi voit valita käynnistyksen OTA-tilaan (Over-the-Air ohjelmistopäivitystilaan).", + "ota": "Käynnistä uudelleen OTA-tilaan", + "enterDelay": "Aseta viive", + "scheduled": "Uudelleenkäynnistys on ajastettu", + "schedule": "Ajasta uudelleen käynnistys", + "now": "Uudelleen käynnistä nyt", + "cancel": "Peruuta ajastettu uudelleen käynnistys" + }, + "refreshKeys": { + "description": { + "acceptNewKeys": "Tämä poistaa laitteen laitteesta ja pyytää uusia avaimia.", + "keyMismatchReasonSuffix": ". Tämä johtuu siitä, että etälaitteen nykyinen julkinen avain ei vastaa aiemmin tallennettua avainta tälle laitteelle.", + "unableToSendDmPrefix": "Laitteesi ei pysty lähettämään suoraa viestiä laitteelle: " + }, + "acceptNewKeys": "Hyväksy uudet avaimet", + "title": "Avaimet eivät täsmää - {{identifier}}" + }, + "removeNode": { + "description": "Haluatko varmasti poistaa tämän laitteen?", + "title": "Poista laite?" + }, + "shutdown": { + "title": "Ajasta sammutus", + "description": "Sammuta yhdistetty laite x minuutin päästä." + }, + "traceRoute": { + "routeToDestination": "Reitin määränpää:", + "routeBack": "Reitti takaisin:" + }, + "tracerouteResponse": { + "title": "Reitinselvitys: {{identifier}}" + }, + "unsafeRoles": { + "confirmUnderstanding": "Kyllä, tiedän mitä teen", + "conjunction": " ja blogikirjoitukset ", + "postamble": " ja ymmärrän roolin muuttamisen vaikutukset.", + "preamble": "Olen lukenut ", + "choosingRightDeviceRole": "Valitse laitteelle oikea rooli", + "deviceRoleDocumentation": "Roolien dokumentaatio laitteelle", + "title": "Oletko varma?" + }, + "managedMode": { + "confirmUnderstanding": "Kyllä, tiedän mitä teen", + "title": "Oletko varma?", + "description": "Hallintatilan käyttöönotto estää asiakassovelluksia (mukaan lukien verkkoselain) tekemästä muutoksia laitteen asetuksiin. Kun hallintatila on käytössä, laitteen asetuksia voidaan muuttaa ainoastaan etähallintaviesteillä (Remote Admin). Tämä asetus ei ole pakollinen etähallintaan." + }, + "clientNotification": { + "title": "Sovellusilmoitukset", + "TraceRoute can only be sent once every 30 seconds": "Reitinselvityksen voi tehdä kerran 30:ssä sekunnissa", + "Compromised keys were detected and regenerated.": "Turvallisuudeltaan vaarantuneet avaimet havaittiin ja ne generoitiin uudestaan." + }, + "resetNodeDb": { + "title": "Nollaa laitteen tietokanta", + "description": "Tämä poistaa kaikki laitteet tietokannasta ja tyhjentää kaiken viestihistorian päätelaitteen sovelluksesta. Tätä toimintoa ei voi perua. Haluatko varmasti jatkaa?", + "confirm": "Nollaa laitteen tietokanta", + "failedTitle": "Tietokannan nollaamisessa tapahtui virhe. Yritä uudelleen." + }, + "clearAllStores": { + "title": "Tyhjennä kaikki paikallisesta tallennustilasta", + "description": "Tämä poistaa kaiken paikallisesti tallennetun tiedon, mukaan lukien viestihistorian ja laitetietokannat kaikilta aiemmin yhdistetyiltä laitteilta. Toiminnon jälkeen sinun on muodostettava yhteys omaan laitteeseesi uudelleen. Tätä toimintoa ei voi perua. Haluatko varmasti jatkaa?", + "confirm": "Tyhjennä kaikki paikallisesta tallennustilasta", + "failedTitle": "Paikallisen tallennustilan tyhjentämisessä tapahtui virhe. Yritä uudelleen." + }, + "factoryResetDevice": { + "title": "Palauta tehdasasetukset", + "description": "Tämä palauttaa yhdistetyn laitteen tehdasasetuksiin ja poistaa kaikki laitteen asetukset, tiedot, laitteet ja viestit, jotka on tallennettu asiakasohjelmaan. Tätä toimintoa ei voi perua. Haluatko varmasti jatkaa?", + "confirm": "Palauta tehdasasetukset", + "failedTitle": "Tehdasasetusten palauttamisessa tapahtui virhe. Yritä uudelleen." + }, + "factoryResetConfig": { + "title": "Tehdasasetusten palautusasetukset", + "description": "Tämä palauttaa yhdistetyn laitteen asetukset tehdasasetuksiin ja poistaa kaikki laitteen nykyiset asetukset. Tätä toimintoa ei voi perua. Haluatko varmasti jatkaa?", + "confirm": "Tehdasasetusten palautusasetukset", + "failedTitle": "Tehdasasetusten palauttamisessa tapahtui virhe. Yritä uudelleen." + } } diff --git a/packages/web/public/i18n/locales/fi-FI/map.json b/packages/web/public/i18n/locales/fi-FI/map.json new file mode 100644 index 000000000..c1e843955 --- /dev/null +++ b/packages/web/public/i18n/locales/fi-FI/map.json @@ -0,0 +1,38 @@ +{ + "maplibre": { + "GeolocateControl.FindMyLocation": "Paikanna sijaintini", + "NavigationControl.ZoomIn": "Suurenna", + "NavigationControl.ZoomOut": "Pienennä", + "CooperativeGesturesHandler.WindowsHelpText": "Pidä Ctrl-näppäin painettuna ja rullaa hiirellä suurentaaksesi tai pienentääksesi karttaa", + "CooperativeGesturesHandler.MacHelpText": "Pidä ⌘-näppäin painettuna ja rullaa hiirellä suurentaaksesi tai pienentääksesi karttaa", + "CooperativeGesturesHandler.MobileHelpText": "Käytä kahta sormea siirtääksesi karttaa" + }, + "layerTool": { + "nodeMarkers": "Näytä laitteet", + "directNeighbors": "Näytä suorat yhteydet", + "remoteNeighbors": "Näytä etäyhteydet", + "positionPrecision": "Näytä sijainnin tarkkuus", + "traceroutes": "Näytä reititykset", + "waypoints": "Näytä reittipisteet" + }, + "mapMenu": { + "locateAria": "Paikanna laitteeni", + "layersAria": "Vaihda kartan tyyliä" + }, + "waypointDetail": { + "edit": "Muokkaa", + "description": "Kuvaus:", + "createdBy": "Muokannut:", + "createdDate": "Luotu:", + "updated": "Päivitetty:", + "expires": "Vanhenee:", + "distance": "Etäisyys:", + "bearing": "Kompassisuunta kohteeseen:", + "lockedTo": "Lukinnut:", + "latitude": "Leveysaste:", + "longitude": "Pituusaste:" + }, + "myNode": { + "tooltip": "Tämä laite" + } +} diff --git a/packages/web/public/i18n/locales/fi-FI/messages.json b/packages/web/public/i18n/locales/fi-FI/messages.json index 7852a8df8..7fc4247fb 100644 --- a/packages/web/public/i18n/locales/fi-FI/messages.json +++ b/packages/web/public/i18n/locales/fi-FI/messages.json @@ -1,39 +1,39 @@ { - "page": { - "title": "Viestit: {{chatName}}", - "placeholder": "Kirjoita viesti" - }, - "emptyState": { - "title": "Valitse keskustelu", - "text": "Ei vielä viestejä." - }, - "selectChatPrompt": { - "text": "Valitse kanava tai laite aloittaaksesi viestinnän." - }, - "sendMessage": { - "placeholder": "Kirjoita viesti tähän...", - "sendButton": "Lähetä" - }, - "actionsMenu": { - "addReactionLabel": "Lisää reaktio", - "replyLabel": "Vastaa" - }, - "deliveryStatus": { - "delivered": { - "label": "Viesti toimitettu", - "displayText": "Viesti toimitettu" - }, - "failed": { - "label": "Viestin toimitus epäonnistui", - "displayText": "Toimitus epäonnistui" - }, - "unknown": { - "label": "Viestin tila tuntematon", - "displayText": "Tuntematon tila" - }, - "waiting": { - "label": "Lähetetään viestiä", - "displayText": "Odottaa toimitusta" - } - } + "page": { + "title": "Viestit: {{chatName}}", + "placeholder": "Kirjoita viesti" + }, + "emptyState": { + "title": "Valitse keskustelu", + "text": "Ei vielä viestejä." + }, + "selectChatPrompt": { + "text": "Valitse kanava tai laite aloittaaksesi viestinnän." + }, + "sendMessage": { + "placeholder": "Kirjoita viesti tähän...", + "sendButton": "Lähetä" + }, + "actionsMenu": { + "addReactionLabel": "Lisää reaktio", + "replyLabel": "Vastaa" + }, + "deliveryStatus": { + "delivered": { + "label": "Viesti toimitettu", + "displayText": "Viesti toimitettu" + }, + "failed": { + "label": "Viestin toimitus epäonnistui", + "displayText": "Toimitus epäonnistui" + }, + "unknown": { + "label": "Viestin tila tuntematon", + "displayText": "Tuntematon tila" + }, + "waiting": { + "label": "Lähetetään viestiä", + "displayText": "Odottaa toimitusta" + } + } } diff --git a/packages/web/public/i18n/locales/fi-FI/moduleConfig.json b/packages/web/public/i18n/locales/fi-FI/moduleConfig.json index 01bfa09d2..b72fd520d 100644 --- a/packages/web/public/i18n/locales/fi-FI/moduleConfig.json +++ b/packages/web/public/i18n/locales/fi-FI/moduleConfig.json @@ -1,448 +1,448 @@ { - "page": { - "tabAmbientLighting": "Ympäristövalaistus", - "tabAudio": "Ääni", - "tabCannedMessage": "Ennalta asetettu", - "tabDetectionSensor": "Havaitsemisanturi", - "tabExternalNotification": "Ext-ilmoitus", - "tabMqtt": "MQTT", - "tabNeighborInfo": "Naapuritieto", - "tabPaxcounter": "PAX-laskuri", - "tabRangeTest": "Kuuluvuustesti", - "tabSerial": "Sarjaliitäntä", - "tabStoreAndForward": "S&V", - "tabTelemetry": "Telemetria" - }, - "ambientLighting": { - "title": "Ympäristövalaistuksen asetukset", - "description": "Ympäristövalaistuksen moduulin asetukset", - "ledState": { - "label": "Ledin tila", - "description": "Aseta ledi päälle tai pois päältä" - }, - "current": { - "label": "Virta", - "description": "Asettaa nykyisen ledin ulostulon. Oletus on 10" - }, - "red": { - "label": "Punainen", - "description": "Asettaa punaisen ledin tason. Arvot ovat 0-255" - }, - "green": { - "label": "Vihreä", - "description": "Asettaa vihreän ledin tason. Arvot ovat 0-255" - }, - "blue": { - "label": "Sininen", - "description": "Asettaa sinisen ledin tason. Arvot ovat 0-255" - } - }, - "audio": { - "title": "Ääniasetukset", - "description": "Äänimoduulin asetukset", - "codec2Enabled": { - "label": "Codec 2 käytössä", - "description": "Ota Codec 2 äänenkoodaus käyttöön" - }, - "pttPin": { - "label": "PTT pinni", - "description": "PTT:lle käytettävä GPIO-pinni" - }, - "bitrate": { - "label": "Tiedonsiirtonopeus", - "description": "Tiedonsiirtonopeus äänenkoodaukselle" - }, - "i2sWs": { - "label": "i2S WS", - "description": "GPIO-pinni jota käytetään i2S WS:ssä" - }, - "i2sSd": { - "label": "i2S SD", - "description": "GPIO-pinni jota käytetään i2S SD:ssä" - }, - "i2sDin": { - "label": "i2S DIN", - "description": "GPIO-pinni jota käytetään i2S DIN:ssä" - }, - "i2sSck": { - "label": "i2S SD", - "description": "GPIO-pinni jota käytetään i2S SCK:ssa" - } - }, - "cannedMessage": { - "title": "Välitettyjen viestien asetukset", - "description": "Asetukset välitettyjen viestien moduulissa", - "moduleEnabled": { - "label": "Moduuli Käytössä", - "description": "Ota käyttöön välitetyt viestit" - }, - "rotary1Enabled": { - "label": "Kiertovalitsin #1 käytössä", - "description": "Ota kiertovalitsimen kooderi käyttöön" - }, - "inputbrokerPinA": { - "label": "Kooderin pinni A", - "description": "GPIO-pinni (1–39) kooderin portille A" - }, - "inputbrokerPinB": { - "label": "Kooderin pinni B", - "description": "GPIO-pinni (1–39) kooderin portille B" - }, - "inputbrokerPinPress": { - "label": "Kooderin pinni painallukselle", - "description": "GPIO-pinni (1–39) kooderin painallukselle" - }, - "inputbrokerEventCw": { - "label": "Myötäpäiväinen liike", - "description": "Valitse syöttötapahtuma." - }, - "inputbrokerEventCcw": { - "label": "Myötäpäiväisen liikkeen laskuri", - "description": "Valitse syöttötapahtuma." - }, - "inputbrokerEventPress": { - "label": "Painamisen tapahtuma", - "description": "Valitse syöttötapahtuma" - }, - "updown1Enabled": { - "label": "Ylös alas käytössä", - "description": "Ota käyttöön ylös / alas-suuntaa tunnistava kooderi" - }, - "allowInputSource": { - "label": "Salli syöttölaitteen lähde", - "description": "Valitse '_any', 'rotEnc1', 'upDownEnc1', 'cardkb'" - }, - "sendBell": { - "label": "Lähetä äänimerkki", - "description": "Lähettää äänimerkkimerkin jokaisen viestin mukana" - } - }, - "detectionSensor": { - "title": "Tunnistinsensorin asetukset", - "description": "Tunnistinsensori-moduulin asetukset", - "enabled": { - "label": "Käytössä", - "description": "Ota käyttöön tai poista käytöstä tunnistinsensorin moduuli" - }, - "minimumBroadcastSecs": { - "label": "Minimilähetys (sekuntia)", - "description": "Aikaväli sekunteina kuinka usein viestejä voi lähettää mesh-verkkoon tilamuutoksen havaitsemisen jälkeen" - }, - "stateBroadcastSecs": { - "label": "Tilatiedon lähetys (sekuntia)", - "description": "Kuinka usein sekunteina lähetetään viesti mesh-verkkoon nykytilasta, vaikka tilassa ei olisi muutoksia" - }, - "sendBell": { - "label": "Lähetä äänimerkki", - "description": "Lähetä ASCII-äänimerkki hälytyssanoman mukana" - }, - "name": { - "label": "Käyttäjäystävälinen nimi", - "description": "Käytetään muotoilemaan mesh-verkkoon lähetettävä viesti, enintään 20 merkkiä" - }, - "monitorPin": { - "label": "Valvonta pinni", - "description": "GPIO-pinni valvonnan tilan muutoksien seurantaan" - }, - "detectionTriggerType": { - "label": "Tunnistuksen havaintotyyppi", - "description": "Käytettävän tunnistustapahtuman tyyppi" - }, - "usePullup": { - "label": "Käytä vetokytkintä (pullup)", - "description": "Käytetäänkö GPIO-pinnin INPUT_PULLUP-tilaa" - } - }, - "externalNotification": { - "title": "Ulkoisten ilmoituksien asetukset", - "description": "Määritä ulkoisten ilmoitusten moduulin asetukset", - "enabled": { - "label": "Moduuli käytössä", - "description": "Ota ulkoiset ilmoitukset käyttöön" - }, - "outputMs": { - "label": "Ulostulo MS", - "description": "Ulostulo MS" - }, - "output": { - "label": "Ulostulo", - "description": "Ulostulo" - }, - "outputVibra": { - "label": "Värinän ulostulo", - "description": "Värinän ulostulo" - }, - "outputBuzzer": { - "label": "Summerin ulostulo", - "description": "Summerin ulostulo" - }, - "active": { - "label": "Käytössä", - "description": "Käytössä" - }, - "alertMessage": { - "label": "Hälytysviesti", - "description": "Hälytysviesti" - }, - "alertMessageVibra": { - "label": "Hälytysviestin värinä", - "description": "Hälytysviestin värinä" - }, - "alertMessageBuzzer": { - "label": "Hälytysviestin summeri", - "description": "Hälytysviestin summeri" - }, - "alertBell": { - "label": "Hälytysääni", - "description": "Pitäisikö hälytyksen aktivoitua, kun vastaanotetaan äänimerkki?" - }, - "alertBellVibra": { - "label": "Hälytysäänen värinä", - "description": "Hälytysäänen värinä" - }, - "alertBellBuzzer": { - "label": "Hälytysäänen summeri", - "description": "Hälytysäänen summeri" - }, - "usePwm": { - "label": "Käytä PWM", - "description": "Käytä PWM" - }, - "nagTimeout": { - "label": "Toistokehotuksen aikakatkaisu", - "description": "Toistokehotuksen aikakatkaisu" - }, - "useI2sAsBuzzer": { - "label": "Use I²S pinniä summerille", - "description": "Määritä I²S-pinni summerin ulostuloon" - } - }, - "mqtt": { - "title": "MQTT-asetukset", - "description": "MQTT-moduulin asetukset", - "enabled": { - "label": "Käytössä", - "description": "Ota MQTT käyttöön tai poista se käytöstä" - }, - "address": { - "label": "MQTT-palvelimen osoite", - "description": "MQTT-palvelimen osoite, jota käytetään oletus- tai mukautetuissa palvelimissa" - }, - "username": { - "label": "MQTT käyttäjänimi", - "description": "MQTT käyttäjänimi, jota käytetään oletus- tai mukautetuissa palvelimissa" - }, - "password": { - "label": "MQTT salasana", - "description": "MQTT salasana, jota käytetään oletus- tai mukautetuissa palvelimissa" - }, - "encryptionEnabled": { - "label": "Salaus käytössä", - "description": "Ota MQTT-salaus käyttöön tai pois käytöstä. Huom: Jos tämä asetus ei ole käytössä, kaikki viestit lähetetään MQTT-välittäjälle salaamattomina, vaikka lähetyskanavillasi olisi salausavaimet asetettuna. Tämä koskee myös sijaintitietoja." - }, - "jsonEnabled": { - "label": "JSON käytössä", - "description": "Lähetetäänkö / otetaanko vastaan JSON-paketteja MQTT:llä" - }, - "tlsEnabled": { - "label": "TLS käytössä", - "description": "Ota TLS käyttöön tai poista se käytöstä" - }, - "root": { - "label": "Palvelimen osoite (root topic)", - "description": "MQTT-palvelimen osoite, jota käytetään oletus- tai mukautetuissa palvelimissa" - }, - "proxyToClientEnabled": { - "label": "MQTT-välityspalvelin käytössä", - "description": "Käyttää verkkoyhteyttä välittämään MQTT-viestejä asiakkaalle." - }, - "mapReportingEnabled": { - "label": "Karttaraportointi käytössä", - "description": "Laitteesi lähettää säännöllisin väliajoin salaamattoman karttaraporttipaketin määritettyyn MQTT-palvelimeen. Paketti sisältää tunnisteen, lyhyen ja pitkän nimen, likimääräisen sijainnin, laitteistomallin, roolin, laiteohjelmistoversion, LoRa-alueen, modeemin esiasetukset sekä ensisijaisen kanavan nimen." - }, - "mapReportSettings": { - "publishIntervalSecs": { - "label": "Karttaraportoinnin aikaväli (s)", - "description": "Aikaväli sekunneissa karttaraporttien julkaisemiseksi" - }, - "positionPrecision": { - "label": "Arvioitu sijainti", - "description": "Jaetun sijainnin tarkkuus on tämän etäisyyden rajoissa", - "options": { - "metric_km23": "23 kilometrin säteellä", - "metric_km12": "12 kilometrin säteellä", - "metric_km5_8": "5,8 kilometrin säteellä", - "metric_km2_9": "2,9 kilometrin säteellä", - "metric_km1_5": "1,5 kilometrin säteellä", - "metric_m700": "700 metrin säteellä", - "metric_m350": "350 metrin säteellä", - "metric_m200": "200 metrin säteellä", - "metric_m90": "90 metrin säteellä", - "metric_m50": "50 metrin säteellä", - "imperial_mi15": "15 mailin säteellä", - "imperial_mi7_3": "7,3 mailin säteellä", - "imperial_mi3_6": "3,6 mailin säteellä", - "imperial_mi1_8": "1,8 mailin säteellä", - "imperial_mi0_9": "0,9 mailin säteellä", - "imperial_mi0_5": "0,5 mailin säteellä", - "imperial_mi0_2": "0,2 mailin säteellä", - "imperial_ft600": "600 jalan säteellä", - "imperial_ft300": "300 jalan säteellä", - "imperial_ft150": "150 jalan säteellä" - } - } - } - }, - "neighborInfo": { - "title": "Naapuritiedon asetukset", - "description": "Naapuritietojen moduulin asetukset", - "enabled": { - "label": "Käytössä", - "description": "Ota käyttöön tai poista käytöstä naapuruustietomoduuli" - }, - "updateInterval": { - "label": "Päivitysväli", - "description": "Aikaväli sekunneissa siitä, kuinka usein mesh-verkossa lähetetään naapuritietoja verkkoon" - } - }, - "paxcounter": { - "title": "Pax-laskurin asetukset", - "description": "Pax-laskurin moduulin asetukset", - "enabled": { - "label": "Moduuli käytössä", - "description": "Ota pax-laskuri käyttöön" - }, - "paxcounterUpdateInterval": { - "label": "Päivityksen aikaväli (sekuntia)", - "description": "Kuinka kauan odotetaan pax-laskurin pakettien lähettämisen välillä" - }, - "wifiThreshold": { - "label": "WiFi-RSSI kynnysarvo", - "description": "Millä WiFi RSSI tasolla laskurin täytyisi kasvaa. Oletus on -80." - }, - "bleThreshold": { - "label": "WiFi-RSSI kynnysarvo", - "description": "Millä BLE RSSI-arvolla laskuri kasvaa. Oletus: -80." - } - }, - "rangeTest": { - "title": "Kuuluvuustestin asetukset", - "description": "Kuuluvuustesti moduulin asetukset", - "enabled": { - "label": "Moduuli käytössä", - "description": "Ota kuuluvuustesti käytöön" - }, - "sender": { - "label": "Viestin aikaväli", - "description": "Kuinka kauan odotetaan testipakettien lähettämisen välillä" - }, - "save": { - "label": "Tallenna CSV tallennustilaan", - "description": "Vain ESP32" - } - }, - "serial": { - "title": "Sarjaliitännän asetukset", - "description": "Sarjaliitäntä-moduulin asetukset", - "enabled": { - "label": "Sarjaliitäntä käytössä", - "description": "Ota sarjaliitäntä käyttöön" - }, - "echo": { - "label": "Toista", - "description": "Kaikki lähettämäsi paketit toistetaan takaisin laitteellesi" - }, - "rxd": { - "label": "Vastaanota PIN-koodi", - "description": "Määritä GPIO-pinni käyttämään aiemmin asetettua RXD-pinniä." - }, - "txd": { - "label": "Lähetä PIN-koodi", - "description": "Määritä GPIO-pinni käyttämään aiemmin asetettua TXD-pinniä." - }, - "baud": { - "label": "Baud-siirtonopeus", - "description": "Sarjaliitännän baud-siirtonopeus" - }, - "timeout": { - "label": "Aikakatkaisu", - "description": "Kuinka monta sekuntia odotetaan, ennen kuin paketti merkitään valmiiksi" - }, - "mode": { - "label": "Tila", - "description": "Valitse tila" - }, - "overrideConsoleSerialPort": { - "label": "Ohita konsolin sarjaliitännän portti", - "description": "Jos sinulla on sarjaportti kytkettynä konsoliin, tämä ohittaa sen." - } - }, - "storeForward": { - "title": "Varastoi & välitä asetukset", - "description": "Varastoi & välitä moduulin asetukset", - "enabled": { - "label": "Moduuli käytössä", - "description": "Ota varastoi & välitä käyttöön" - }, - "heartbeat": { - "label": "Heartbeat käytössä", - "description": "Ota varastoi & välitä heartbeat käyttöön" - }, - "records": { - "label": "Kirjausten määrä", - "description": "Tallennettavien tietueiden määrä" - }, - "historyReturnMax": { - "label": "Historian maksimimäärä", - "description": "Enimmäismäärä tietueita palautettaviksi" - }, - "historyReturnWindow": { - "label": "Historian aikamäärä", - "description": "Enimmäismäärä tietueita palautettaviksi" - } - }, - "telemetry": { - "title": "Telemetrian asetukset", - "description": "Telemetria-moduulin asetukset", - "deviceUpdateInterval": { - "label": "Laitteen mittausloki", - "description": "Laitteen mittaustietojen päivitysväli (sekuntia)" - }, - "environmentUpdateInterval": { - "label": "Ympäristötietojen päivitysväli (sekuntia)", - "description": "" - }, - "environmentMeasurementEnabled": { - "label": "Moduuli käytössä", - "description": "Ota käyttöön ympäristön telemetria" - }, - "environmentScreenEnabled": { - "label": "Näytetään näytöllä", - "description": "Näytä moduulin telemetriatiedot OLED-näytöllä" - }, - "environmentDisplayFahrenheit": { - "label": "Näytä fahrenheitissa", - "description": "Näytä lämpötila fahrenheitissa" - }, - "airQualityEnabled": { - "label": "Ilmanlaatu käytössä", - "description": "Ota ilmanlaadun telemetria käyttöön" - }, - "airQualityInterval": { - "label": "Ilmanlaadun päivitysväli", - "description": "Kuinka usein ilmanlaadun tiedot lähetetään mesh-verkon kautta" - }, - "powerMeasurementEnabled": { - "label": "Tehomittaus käytössä", - "description": "Ota tehomittauksen telemetria käyttöön" - }, - "powerUpdateInterval": { - "label": "Tehomittauksen päivitysväli", - "description": "Kuinka usein tehomittauksen tiedot lähetetään mesh-verkon kautta" - }, - "powerScreenEnabled": { - "label": "Tehomittauksen näyttö käytössä", - "description": "Ota tehomittauksen telemetrian näyttö käyttöön" - } - } + "page": { + "tabAmbientLighting": "Ympäristövalaistus", + "tabAudio": "Ääni", + "tabCannedMessage": "Ennalta asetettu", + "tabDetectionSensor": "Havaitsemisanturi", + "tabExternalNotification": "Ext-ilmoitus", + "tabMqtt": "MQTT", + "tabNeighborInfo": "Naapuritieto", + "tabPaxcounter": "PAX-laskuri", + "tabRangeTest": "Kuuluvuustesti", + "tabSerial": "Sarjaliitäntä", + "tabStoreAndForward": "S&V", + "tabTelemetry": "Telemetria" + }, + "ambientLighting": { + "title": "Ympäristövalaistuksen asetukset", + "description": "Ympäristövalaistuksen moduulin asetukset", + "ledState": { + "label": "Ledin tila", + "description": "Aseta ledi päälle tai pois päältä" + }, + "current": { + "label": "Virta", + "description": "Asettaa nykyisen ledin ulostulon. Oletus on 10" + }, + "red": { + "label": "Punainen", + "description": "Asettaa punaisen ledin tason. Arvot ovat 0-255" + }, + "green": { + "label": "Vihreä", + "description": "Asettaa vihreän ledin tason. Arvot ovat 0-255" + }, + "blue": { + "label": "Sininen", + "description": "Asettaa sinisen ledin tason. Arvot ovat 0-255" + } + }, + "audio": { + "title": "Ääniasetukset", + "description": "Äänimoduulin asetukset", + "codec2Enabled": { + "label": "Codec 2 käytössä", + "description": "Ota Codec 2 äänenkoodaus käyttöön" + }, + "pttPin": { + "label": "PTT pinni", + "description": "PTT:lle käytettävä GPIO-pinni" + }, + "bitrate": { + "label": "Tiedonsiirtonopeus", + "description": "Tiedonsiirtonopeus äänenkoodaukselle" + }, + "i2sWs": { + "label": "i2S WS", + "description": "GPIO-pinni jota käytetään i2S WS:ssä" + }, + "i2sSd": { + "label": "i2S SD", + "description": "GPIO-pinni jota käytetään i2S SD:ssä" + }, + "i2sDin": { + "label": "i2S DIN", + "description": "GPIO-pinni jota käytetään i2S DIN:ssä" + }, + "i2sSck": { + "label": "i2S SD", + "description": "GPIO-pinni jota käytetään i2S SCK:ssa" + } + }, + "cannedMessage": { + "title": "Välitettyjen viestien asetukset", + "description": "Asetukset välitettyjen viestien moduulissa", + "moduleEnabled": { + "label": "Moduuli Käytössä", + "description": "Ota käyttöön välitetyt viestit" + }, + "rotary1Enabled": { + "label": "Kiertovalitsin #1 käytössä", + "description": "Ota kiertovalitsimen kooderi käyttöön" + }, + "inputbrokerPinA": { + "label": "Kooderin pinni A", + "description": "GPIO-pinni (1–39) kooderin portille A" + }, + "inputbrokerPinB": { + "label": "Kooderin pinni B", + "description": "GPIO-pinni (1–39) kooderin portille B" + }, + "inputbrokerPinPress": { + "label": "Kooderin pinni painallukselle", + "description": "GPIO-pinni (1–39) kooderin painallukselle" + }, + "inputbrokerEventCw": { + "label": "Myötäpäiväinen liike", + "description": "Valitse syöttötapahtuma." + }, + "inputbrokerEventCcw": { + "label": "Myötäpäiväisen liikkeen laskuri", + "description": "Valitse syöttötapahtuma." + }, + "inputbrokerEventPress": { + "label": "Painamisen tapahtuma", + "description": "Valitse syöttötapahtuma" + }, + "updown1Enabled": { + "label": "Ylös alas käytössä", + "description": "Ota käyttöön ylös / alas-suuntaa tunnistava kooderi" + }, + "allowInputSource": { + "label": "Salli syöttölaitteen lähde", + "description": "Valitse '_any', 'rotEnc1', 'upDownEnc1', 'cardkb'" + }, + "sendBell": { + "label": "Lähetä äänimerkki", + "description": "Lähettää äänimerkkimerkin jokaisen viestin mukana" + } + }, + "detectionSensor": { + "title": "Tunnistinsensorin asetukset", + "description": "Tunnistinsensori-moduulin asetukset", + "enabled": { + "label": "Käytössä", + "description": "Ota käyttöön tai poista käytöstä tunnistinsensorin moduuli" + }, + "minimumBroadcastSecs": { + "label": "Minimilähetys (sekuntia)", + "description": "Aikaväli sekunteina kuinka usein viestejä voi lähettää mesh-verkkoon tilamuutoksen havaitsemisen jälkeen" + }, + "stateBroadcastSecs": { + "label": "Tilatiedon lähetys (sekuntia)", + "description": "Kuinka usein sekunteina lähetetään viesti mesh-verkkoon nykytilasta, vaikka tilassa ei olisi muutoksia" + }, + "sendBell": { + "label": "Lähetä äänimerkki", + "description": "Lähetä ASCII-äänimerkki hälytyssanoman mukana" + }, + "name": { + "label": "Käyttäjäystävälinen nimi", + "description": "Käytetään muotoilemaan mesh-verkkoon lähetettävä viesti, enintään 20 merkkiä" + }, + "monitorPin": { + "label": "Valvonta pinni", + "description": "GPIO-pinni valvonnan tilan muutoksien seurantaan" + }, + "detectionTriggerType": { + "label": "Tunnistuksen havaintotyyppi", + "description": "Käytettävän tunnistustapahtuman tyyppi" + }, + "usePullup": { + "label": "Käytä vetokytkintä (pullup)", + "description": "Käytetäänkö GPIO-pinnin INPUT_PULLUP-tilaa" + } + }, + "externalNotification": { + "title": "Ulkoisten ilmoituksien asetukset", + "description": "Määritä ulkoisten ilmoitusten moduulin asetukset", + "enabled": { + "label": "Moduuli käytössä", + "description": "Ota ulkoiset ilmoitukset käyttöön" + }, + "outputMs": { + "label": "Ulostulo MS", + "description": "Ulostulo MS" + }, + "output": { + "label": "Ulostulo", + "description": "Ulostulo" + }, + "outputVibra": { + "label": "Värinän ulostulo", + "description": "Värinän ulostulo" + }, + "outputBuzzer": { + "label": "Summerin ulostulo", + "description": "Summerin ulostulo" + }, + "active": { + "label": "Käytössä", + "description": "Käytössä" + }, + "alertMessage": { + "label": "Hälytysviesti", + "description": "Hälytysviesti" + }, + "alertMessageVibra": { + "label": "Hälytysviestin värinä", + "description": "Hälytysviestin värinä" + }, + "alertMessageBuzzer": { + "label": "Hälytysviestin summeri", + "description": "Hälytysviestin summeri" + }, + "alertBell": { + "label": "Hälytysääni", + "description": "Pitäisikö hälytyksen aktivoitua, kun vastaanotetaan äänimerkki?" + }, + "alertBellVibra": { + "label": "Hälytysäänen värinä", + "description": "Hälytysäänen värinä" + }, + "alertBellBuzzer": { + "label": "Hälytysäänen summeri", + "description": "Hälytysäänen summeri" + }, + "usePwm": { + "label": "Käytä PWM", + "description": "Käytä PWM" + }, + "nagTimeout": { + "label": "Toistokehotuksen aikakatkaisu", + "description": "Toistokehotuksen aikakatkaisu" + }, + "useI2sAsBuzzer": { + "label": "Use I²S pinniä summerille", + "description": "Määritä I²S-pinni summerin ulostuloon" + } + }, + "mqtt": { + "title": "MQTT-asetukset", + "description": "MQTT-moduulin asetukset", + "enabled": { + "label": "Käytössä", + "description": "Ota MQTT käyttöön tai poista se käytöstä" + }, + "address": { + "label": "MQTT-palvelimen osoite", + "description": "MQTT-palvelimen osoite, jota käytetään oletus- tai mukautetuissa palvelimissa" + }, + "username": { + "label": "MQTT käyttäjänimi", + "description": "MQTT käyttäjänimi, jota käytetään oletus- tai mukautetuissa palvelimissa" + }, + "password": { + "label": "MQTT salasana", + "description": "MQTT salasana, jota käytetään oletus- tai mukautetuissa palvelimissa" + }, + "encryptionEnabled": { + "label": "Salaus käytössä", + "description": "Ota MQTT-salaus käyttöön tai pois käytöstä. Huom: Jos tämä asetus ei ole käytössä, kaikki viestit lähetetään MQTT-välittäjälle salaamattomina, vaikka lähetyskanavillasi olisi salausavaimet asetettuna. Tämä koskee myös sijaintitietoja." + }, + "jsonEnabled": { + "label": "JSON käytössä", + "description": "Lähetetäänkö / otetaanko vastaan JSON-paketteja MQTT:llä" + }, + "tlsEnabled": { + "label": "TLS käytössä", + "description": "Ota TLS käyttöön tai poista se käytöstä" + }, + "root": { + "label": "Palvelimen osoite (root topic)", + "description": "MQTT-palvelimen osoite, jota käytetään oletus- tai mukautetuissa palvelimissa" + }, + "proxyToClientEnabled": { + "label": "MQTT-välityspalvelin käytössä", + "description": "Käyttää verkkoyhteyttä välittämään MQTT-viestejä asiakkaalle." + }, + "mapReportingEnabled": { + "label": "Karttaraportointi käytössä", + "description": "Laitteesi lähettää säännöllisin väliajoin salaamattoman karttaraporttipaketin määritettyyn MQTT-palvelimeen. Paketti sisältää tunnisteen, lyhyen ja pitkän nimen, likimääräisen sijainnin, laitteistomallin, roolin, laiteohjelmistoversion, LoRa-alueen, modeemin esiasetukset sekä ensisijaisen kanavan nimen." + }, + "mapReportSettings": { + "publishIntervalSecs": { + "label": "Karttaraportoinnin aikaväli (s)", + "description": "Aikaväli sekunneissa karttaraporttien julkaisemiseksi" + }, + "positionPrecision": { + "label": "Arvioitu sijainti", + "description": "Jaetun sijainnin tarkkuus on tämän etäisyyden rajoissa", + "options": { + "metric_km23": "23 kilometrin säteellä", + "metric_km12": "12 kilometrin säteellä", + "metric_km5_8": "5,8 kilometrin säteellä", + "metric_km2_9": "2,9 kilometrin säteellä", + "metric_km1_5": "1,5 kilometrin säteellä", + "metric_m700": "700 metrin säteellä", + "metric_m350": "350 metrin säteellä", + "metric_m200": "200 metrin säteellä", + "metric_m90": "90 metrin säteellä", + "metric_m50": "50 metrin säteellä", + "imperial_mi15": "15 mailin säteellä", + "imperial_mi7_3": "7,3 mailin säteellä", + "imperial_mi3_6": "3,6 mailin säteellä", + "imperial_mi1_8": "1,8 mailin säteellä", + "imperial_mi0_9": "0,9 mailin säteellä", + "imperial_mi0_5": "0,5 mailin säteellä", + "imperial_mi0_2": "0,2 mailin säteellä", + "imperial_ft600": "600 jalan säteellä", + "imperial_ft300": "300 jalan säteellä", + "imperial_ft150": "150 jalan säteellä" + } + } + } + }, + "neighborInfo": { + "title": "Naapuritiedon asetukset", + "description": "Naapuritietojen moduulin asetukset", + "enabled": { + "label": "Käytössä", + "description": "Ota käyttöön tai poista käytöstä naapuruustietomoduuli" + }, + "updateInterval": { + "label": "Päivitysväli", + "description": "Aikaväli sekunneissa siitä, kuinka usein mesh-verkossa lähetetään naapuritietoja verkkoon" + } + }, + "paxcounter": { + "title": "Pax-laskurin asetukset", + "description": "Pax-laskurin moduulin asetukset", + "enabled": { + "label": "Moduuli käytössä", + "description": "Ota pax-laskuri käyttöön" + }, + "paxcounterUpdateInterval": { + "label": "Päivityksen aikaväli (sekuntia)", + "description": "Kuinka kauan odotetaan pax-laskurin pakettien lähettämisen välillä" + }, + "wifiThreshold": { + "label": "WiFi-RSSI kynnysarvo", + "description": "Millä WiFi RSSI tasolla laskurin täytyisi kasvaa. Oletus on -80." + }, + "bleThreshold": { + "label": "WiFi-RSSI kynnysarvo", + "description": "Millä BLE RSSI-arvolla laskuri kasvaa. Oletus: -80." + } + }, + "rangeTest": { + "title": "Kuuluvuustestin asetukset", + "description": "Kuuluvuustesti moduulin asetukset", + "enabled": { + "label": "Moduuli käytössä", + "description": "Ota kuuluvuustesti käytöön" + }, + "sender": { + "label": "Viestin aikaväli", + "description": "Kuinka kauan odotetaan testipakettien lähettämisen välillä" + }, + "save": { + "label": "Tallenna CSV tallennustilaan", + "description": "Vain ESP32" + } + }, + "serial": { + "title": "Sarjaliitännän asetukset", + "description": "Sarjaliitäntä-moduulin asetukset", + "enabled": { + "label": "Sarjaliitäntä käytössä", + "description": "Ota sarjaliitäntä käyttöön" + }, + "echo": { + "label": "Toista", + "description": "Kaikki lähettämäsi paketit toistetaan takaisin laitteellesi" + }, + "rxd": { + "label": "Vastaanota PIN-koodi", + "description": "Määritä GPIO-pinni käyttämään aiemmin asetettua RXD-pinniä." + }, + "txd": { + "label": "Lähetä PIN-koodi", + "description": "Määritä GPIO-pinni käyttämään aiemmin asetettua TXD-pinniä." + }, + "baud": { + "label": "Baud-siirtonopeus", + "description": "Sarjaliitännän baud-siirtonopeus" + }, + "timeout": { + "label": "Aikakatkaisu", + "description": "Kuinka monta sekuntia odotetaan, ennen kuin paketti merkitään valmiiksi" + }, + "mode": { + "label": "Tila", + "description": "Valitse tila" + }, + "overrideConsoleSerialPort": { + "label": "Ohita konsolin sarjaliitännän portti", + "description": "Jos sinulla on sarjaportti kytkettynä konsoliin, tämä ohittaa sen." + } + }, + "storeForward": { + "title": "Varastoi & välitä asetukset", + "description": "Varastoi & välitä moduulin asetukset", + "enabled": { + "label": "Moduuli käytössä", + "description": "Ota varastoi & välitä käyttöön" + }, + "heartbeat": { + "label": "Heartbeat käytössä", + "description": "Ota varastoi & välitä heartbeat käyttöön" + }, + "records": { + "label": "Kirjausten määrä", + "description": "Tallennettavien tietueiden määrä" + }, + "historyReturnMax": { + "label": "Historian maksimimäärä", + "description": "Enimmäismäärä tietueita palautettaviksi" + }, + "historyReturnWindow": { + "label": "Historian aikamäärä", + "description": "Palauta tietueet tästä aikaikkunasta (minuutit)" + } + }, + "telemetry": { + "title": "Telemetrian asetukset", + "description": "Telemetria-moduulin asetukset", + "deviceUpdateInterval": { + "label": "Laitteen mittausloki", + "description": "Laitteen mittaustietojen päivitysväli (sekuntia)" + }, + "environmentUpdateInterval": { + "label": "Ympäristötietojen päivitysväli (sekuntia)", + "description": "" + }, + "environmentMeasurementEnabled": { + "label": "Moduuli käytössä", + "description": "Ota käyttöön ympäristön telemetria" + }, + "environmentScreenEnabled": { + "label": "Näytetään näytöllä", + "description": "Näytä moduulin telemetriatiedot OLED-näytöllä" + }, + "environmentDisplayFahrenheit": { + "label": "Näytä fahrenheitissa", + "description": "Näytä lämpötila fahrenheitissa" + }, + "airQualityEnabled": { + "label": "Ilmanlaatu käytössä", + "description": "Ota ilmanlaadun telemetria käyttöön" + }, + "airQualityInterval": { + "label": "Ilmanlaadun päivitysväli", + "description": "Kuinka usein ilmanlaadun tiedot lähetetään mesh-verkon kautta" + }, + "powerMeasurementEnabled": { + "label": "Tehomittaus käytössä", + "description": "Ota tehomittauksen telemetria käyttöön" + }, + "powerUpdateInterval": { + "label": "Tehomittauksen päivitysväli", + "description": "Kuinka usein tehomittauksen tiedot lähetetään mesh-verkon kautta" + }, + "powerScreenEnabled": { + "label": "Tehomittauksen näyttö käytössä", + "description": "Ota tehomittauksen telemetrian näyttö käyttöön" + } + } } diff --git a/packages/web/public/i18n/locales/fi-FI/nodes.json b/packages/web/public/i18n/locales/fi-FI/nodes.json index 3f0ed0c2a..b198204bc 100644 --- a/packages/web/public/i18n/locales/fi-FI/nodes.json +++ b/packages/web/public/i18n/locales/fi-FI/nodes.json @@ -1,63 +1,59 @@ { - "nodeDetail": { - "publicKeyEnabled": { - "label": "Julkinen avain käytössä" - }, - "noPublicKey": { - "label": "Ei julkinen avain" - }, - "directMessage": { - "label": "Suora Viesti {{shortName}}" - }, - "favorite": { - "label": "Suosikki", - "tooltip": "Lisää tai poista tämä laite suosikeistasi" - }, - "notFavorite": { - "label": "Ei suosikki" - }, - "error": { - "label": "Virhe", - "text": "Tapahtui virhe haettaessa laitteen tietoja. Yritä uudelleen myöhemmin." - }, - "status": { - "heard": "Kuultu", - "mqtt": "MQTT" - }, - "elevation": { - "label": "Korkeus" - }, - "channelUtil": { - "label": "Kanavan käyttö" - }, - "airtimeUtil": { - "label": "Lähetysajan käyttö" - } - }, - "nodesTable": { - "headings": { - "longName": "Pitkä nimi", - "connection": "Yhteys", - "lastHeard": "Viimeksi kuultu", - "encryption": "Salaus", - "model": "Malli", - "macAddress": "MAC-osoite" - }, - "connectionStatus": { - "direct": "Suora", - "away": "poissa", - "unknown": "-", - "viaMqtt": ", MQTT välityksellä" - }, - "lastHeardStatus": { - "never": "Ei koskaan" - } - }, - "actions": { - "added": "Lisätty", - "removed": "Poistettu", - "ignoreNode": "Älä huomioi laitetta", - "unignoreNode": "Huomioi laite uudelleen", - "requestPosition": "Pyydä sijaintia" - } + "nodeDetail": { + "publicKeyEnabled": { + "label": "Julkinen avain käytössä" + }, + "noPublicKey": { + "label": "Ei julkinen avain" + }, + "directMessage": { + "label": "Suora Viesti {{shortName}}" + }, + "favorite": { + "label": "Suosikki", + "tooltip": "Lisää tai poista tämä laite suosikeistasi" + }, + "notFavorite": { + "label": "Ei suosikki" + }, + "error": { + "label": "Virhe", + "text": "Tapahtui virhe haettaessa laitteen tietoja. Yritä uudelleen myöhemmin." + }, + "status": { + "heard": "Kuultu", + "mqtt": "MQTT" + }, + "elevation": { + "label": "Korkeus" + }, + "channelUtil": { + "label": "Kanavan käyttö" + }, + "airtimeUtil": { + "label": "Lähetysajan käyttö" + } + }, + "nodesTable": { + "headings": { + "longName": "Pitkä nimi", + "connection": "Yhteys", + "lastHeard": "Viimeksi kuultu", + "encryption": "Salaus", + "model": "Malli", + "macAddress": "MAC-osoite" + }, + "connectionStatus": { + "direct": "Suora", + "away": "poissa", + "viaMqtt": ", MQTT välityksellä" + } + }, + "actions": { + "added": "Lisätty", + "removed": "Poistettu", + "ignoreNode": "Älä huomioi laitetta", + "unignoreNode": "Huomioi laite uudelleen", + "requestPosition": "Pyydä sijaintia" + } } diff --git a/packages/web/public/i18n/locales/fi-FI/ui.json b/packages/web/public/i18n/locales/fi-FI/ui.json index d77363e7d..9c59a3d91 100644 --- a/packages/web/public/i18n/locales/fi-FI/ui.json +++ b/packages/web/public/i18n/locales/fi-FI/ui.json @@ -1,228 +1,230 @@ { - "navigation": { - "title": "Navigointi", - "messages": "Viestit", - "map": "Kartta", - "config": "Asetukset", - "radioConfig": "Radion asetukset", - "moduleConfig": "Moduulin asetukset", - "channels": "Kanavat", - "nodes": "Laitteet" - }, - "app": { - "title": "Meshtastic", - "logo": "Meshtastic Logo" - }, - "sidebar": { - "collapseToggle": { - "button": { - "open": "Avaa sivupalkki", - "close": "Sulje sivupalkki" - } - }, - "deviceInfo": { - "volts": "{{voltage}} volttia", - "firmware": { - "title": "Laiteohjelmisto", - "version": "v{{version}}", - "buildDate": "Koontipäivä: {{date}}" - }, - "deviceName": { - "title": "Laitteen nimi", - "changeName": "Vaihda laitteen nimi", - "placeholder": "Anna laitteelle nimi" - }, - "editDeviceName": "Muokkaa laitteen nimeä" - } - }, - "batteryStatus": { - "charging": "{{level}} % latauksessa", - "pluggedIn": "Kytketty verkkovirtaan", - "title": "Akku" - }, - "search": { - "nodes": "Etsi laitteita...", - "channels": "Etsi kanavia...", - "commandPalette": "Etsi komentoja..." - }, - "toast": { - "positionRequestSent": { - "title": "Sijaintipyyntö lähetetty." - }, - "requestingPosition": { - "title": "Pyydetään sijaintia, odota..." - }, - "sendingTraceroute": { - "title": "Reitinselvitys lähetetty, odota..." - }, - "tracerouteSent": { - "title": "Reitinselvitys lähetetty." - }, - "savedChannel": { - "title": "Tallennettu Kanava: {{channelName}}" - }, - "messages": { - "pkiEncryption": { - "title": "Keskustelu käyttää PKI-salausta." - }, - "pskEncryption": { - "title": "Keskustelu käyttää PKI-salausta." - } - }, - "configSaveError": { - "title": "Virhe asetusten tallentamisessa", - "description": "Asetusten tallennuksessa tapahtui virhe." - }, - "validationError": { - "title": "Asetuksissa on virheitä", - "description": "Ole hyvä ja korjaa asetusvirheet ennen tallentamista." - }, - "saveSuccess": { - "title": "Tallennetaan asetukset", - "description": "Asetuksien muutos {{case}} on tallennettu." - }, - "favoriteNode": { - "title": "{{action}} {{nodeName}} {{direction}} suosikit.", - "action": { - "added": "Lisätty", - "removed": "Poistettu", - "to": "saakka", - "from": "alkaen" - } - }, - "ignoreNode": { - "title": "{{action}} {{nodeName}} {{direction}} estolista", - "action": { - "added": "Lisätty", - "removed": "Poistettu", - "to": "saakka", - "from": "alkaen" - } - } - }, - "notifications": { - "copied": { - "label": "Kopioitu!" - }, - "copyToClipboard": { - "label": "Kopioi leikepöydälle" - }, - "hidePassword": { - "label": "Piilota salasana" - }, - "showPassword": { - "label": "Näytä salasana" - }, - "deliveryStatus": { - "delivered": "Toimitettu", - "failed": "Toimitus epäonnistui", - "waiting": "Odottaa", - "unknown": "Tuntematon" - } - }, - "general": { - "label": "Yleinen" - }, - "hardware": { - "label": "Laite" - }, - "metrics": { - "label": "Mittaustiedot" - }, - "role": { - "label": "Rooli" - }, - "filter": { - "label": "Suodatus" - }, - "advanced": { - "label": "Lisäasetukset" - }, - "clearInput": { - "label": "Tyhjennä kenttä" - }, - "resetFilters": { - "label": "Tyhjennä suodattimet" - }, - "nodeName": { - "label": "Laitteen nimi tai numero", - "placeholder": "Meshtastic 1234" - }, - "airtimeUtilization": { - "label": "Ajan käyttöaste (%)" - }, - "batteryLevel": { - "label": "Akun varaus (%)", - "labelText": "Akun varaus (%): {{value}}" - }, - "batteryVoltage": { - "label": "Akun jännite (V)", - "title": "Jännite" - }, - "channelUtilization": { - "label": "Kanavan käyttö (%)" - }, - "hops": { - "direct": "Suora", - "label": "Hyppyjen määrä", - "text": "Hyppyjen määrä: {{value}}" - }, - "lastHeard": { - "label": "Viimeksi kuultu", - "labelText": "Viimeksi kuultu: {{value}}", - "nowLabel": "Nyt" - }, - "snr": { - "label": "SNR (db)" - }, - "favorites": { - "label": "Suosikit" - }, - "hide": { - "label": "Piilota" - }, - "showOnly": { - "label": "Näytä pelkästään" - }, - "viaMqtt": { - "label": "Yhdistetty MQTT-yhteydellä" - }, - "hopsUnknown": { - "label": "Tuntematon määrä hyppyjä" - }, - "showUnheard": { - "label": "Ei koskaan kuultu" - }, - "language": { - "label": "Kieli", - "changeLanguage": "Vaihda kieli" - }, - "theme": { - "dark": "Tumma", - "light": "Vaalea", - "system": "Automaattinen", - "changeTheme": "Vaihda väriteema" - }, - "errorPage": { - "title": "Tämä on hieman noloa...", - "description1": "Pahoittelemme, mutta verkkosovelluksessa tapahtui virhe, joka aiheutti kaatumisen.
\nTällaista ei pitäisi tapahtua ja me työskentelemme ahkerasti ongelman korjaamiseksi.", - "description2": "Paras tapa estää tämän tapahtuminen uudelleen sinulle tai kenellekään muulle, on ilmoittaa meille ongelmasta.", - "reportInstructions": "Lisääthän raporttiisi seuraavat tiedot:", - "reportSteps": { - "step1": "Mitä olit tekemässä virheen tapahtuessa", - "step2": "Mitä odotit tapahtuvan", - "step3": "Mitä todellisuudessa tapahtui", - "step4": "Muut mahdollisesti oleelliset tiedot" - }, - "reportLink": "Voit raportoida ongelmasta <0>GitHubissa", - "dashboardLink": "Palaa takaisin <0>hallintapaneeliin", - "detailsSummary": "Virheen tiedot", - "errorMessageLabel": "Virheilmoitus:", - "stackTraceLabel": "Virheen jäljityslista:", - "fallbackError": "{{error}}" - }, - "footer": { - "text": "Powered by <0>▲ Vercel | Meshtastic® on Meshtastic LLC:n rekisteröity tavaramerkki. | <1>Oikeudelliset tiedot", - "commitSha": "Ohjelmistokehitysversion SHA-tunniste: {{sha}}" - } + "navigation": { + "title": "Navigointi", + "messages": "Viestit", + "map": "Kartta", + "settings": "Asetukset", + "channels": "Kanavat", + "radioConfig": "Radion asetukset", + "deviceConfig": "Laitteen asetukset", + "moduleConfig": "Moduulin asetukset", + "manageConnections": "Hallinnoi yhteyksiä", + "nodes": "Laitteet" + }, + "app": { + "title": "Meshtastic", + "logo": "Meshtastic Logo" + }, + "sidebar": { + "collapseToggle": { + "button": { + "open": "Avaa sivupalkki", + "close": "Sulje sivupalkki" + } + }, + "deviceInfo": { + "volts": "{{voltage}} volttia", + "firmware": { + "title": "Laiteohjelmisto", + "version": "v{{version}}", + "buildDate": "Koontipäivä: {{date}}" + } + } + }, + "batteryStatus": { + "charging": "{{level}} % latauksessa", + "pluggedIn": "Kytketty verkkovirtaan", + "title": "Akku" + }, + "search": { + "nodes": "Etsi laitteita...", + "channels": "Etsi kanavia...", + "commandPalette": "Etsi komentoja..." + }, + "toast": { + "positionRequestSent": { + "title": "Sijaintipyyntö lähetetty." + }, + "requestingPosition": { + "title": "Pyydetään sijaintia, odota..." + }, + "sendingTraceroute": { + "title": "Reitinselvitys lähetetty, odota..." + }, + "tracerouteSent": { + "title": "Reitinselvitys lähetetty." + }, + "savedChannel": { + "title": "Tallennettu Kanava: {{channelName}}" + }, + "messages": { + "pkiEncryption": { + "title": "Keskustelu käyttää PKI-salausta." + }, + "pskEncryption": { + "title": "Keskustelu käyttää PKI-salausta." + } + }, + "configSaveError": { + "title": "Virhe asetusten tallentamisessa", + "description": "Asetusten tallennuksessa tapahtui virhe." + }, + "validationError": { + "title": "Asetuksissa on virheitä", + "description": "Ole hyvä ja korjaa asetusvirheet ennen tallentamista." + }, + "saveSuccess": { + "title": "Tallennetaan asetukset", + "description": "Asetuksien muutos {{case}} on tallennettu." + }, + "saveAllSuccess": { + "title": "Tallennettu", + "description": "Kaikki asetukset on tallennettu." + }, + "favoriteNode": { + "title": "{{action}} {{nodeName}} {{direction}} suosikit.", + "action": { + "added": "Lisätty", + "removed": "Poistettu", + "to": "saakka", + "from": "alkaen" + } + }, + "ignoreNode": { + "title": "{{action}} {{nodeName}} {{direction}} estolista", + "action": { + "added": "Lisätty", + "removed": "Poistettu", + "to": "saakka", + "from": "alkaen" + } + } + }, + "notifications": { + "copied": { + "label": "Kopioitu!" + }, + "copyToClipboard": { + "label": "Kopioi leikepöydälle" + }, + "hidePassword": { + "label": "Piilota salasana" + }, + "showPassword": { + "label": "Näytä salasana" + }, + "deliveryStatus": { + "delivered": "Toimitettu", + "failed": "Toimitus epäonnistui", + "waiting": "Odottaa", + "unknown": "Tuntematon" + } + }, + "general": { + "label": "Yleinen" + }, + "hardware": { + "label": "Laite" + }, + "metrics": { + "label": "Mittaustiedot" + }, + "role": { + "label": "Rooli" + }, + "filter": { + "label": "Suodatus" + }, + "advanced": { + "label": "Lisäasetukset" + }, + "clearInput": { + "label": "Tyhjennä kenttä" + }, + "resetFilters": { + "label": "Tyhjennä suodattimet" + }, + "nodeName": { + "label": "Laitteen nimi tai numero", + "placeholder": "Meshtastic 1234" + }, + "airtimeUtilization": { + "label": "Ajan käyttöaste (%)", + "short": "Lähetysaika­käyttö (%)" + }, + "batteryLevel": { + "label": "Akun varaus (%)", + "labelText": "Akun varaus (%): {{value}}" + }, + "batteryVoltage": { + "label": "Akun jännite (V)", + "title": "Jännite" + }, + "channelUtilization": { + "label": "Kanavan käyttö (%)", + "short": "Kanavan käyttöaste (%)" + }, + "hops": { + "direct": "Suora", + "label": "Hyppyjen määrä", + "text": "Hyppyjen määrä: {{value}}" + }, + "lastHeard": { + "label": "Viimeksi kuultu", + "labelText": "Viimeksi kuultu: {{value}}", + "nowLabel": "Nyt" + }, + "snr": { + "label": "SNR (db)" + }, + "favorites": { + "label": "Suosikit" + }, + "hide": { + "label": "Piilota" + }, + "showOnly": { + "label": "Näytä pelkästään" + }, + "viaMqtt": { + "label": "Yhdistetty MQTT-yhteydellä" + }, + "hopsUnknown": { + "label": "Tuntematon määrä hyppyjä" + }, + "showUnheard": { + "label": "Ei koskaan kuultu" + }, + "language": { + "label": "Kieli", + "changeLanguage": "Vaihda kieli" + }, + "theme": { + "dark": "Tumma", + "light": "Vaalea", + "system": "Automaattinen", + "changeTheme": "Vaihda väriteema" + }, + "errorPage": { + "title": "Tämä on hieman noloa...", + "description1": "Pahoittelemme, mutta verkkosovelluksessa tapahtui virhe, joka aiheutti kaatumisen.
\nTällaista ei pitäisi tapahtua ja me työskentelemme ahkerasti ongelman korjaamiseksi.", + "description2": "Paras tapa estää tämän tapahtuminen uudelleen sinulle tai kenellekään muulle, on ilmoittaa meille ongelmasta.", + "reportInstructions": "Lisääthän raporttiisi seuraavat tiedot:", + "reportSteps": { + "step1": "Mitä olit tekemässä virheen tapahtuessa", + "step2": "Mitä odotit tapahtuvan", + "step3": "Mitä todellisuudessa tapahtui", + "step4": "Muut mahdollisesti oleelliset tiedot" + }, + "reportLink": "Voit raportoida ongelmasta <0>GitHubissa", + "connectionsLink": "Palaa <0>yhteyksiin", + "detailsSummary": "Virheen tiedot", + "errorMessageLabel": "Virheilmoitus:", + "stackTraceLabel": "Virheen jäljityslista:", + "fallbackError": "{{error}}" + }, + "footer": { + "text": "Powered by <0>▲ Vercel | Meshtastic® on Meshtastic LLC:n rekisteröity tavaramerkki. | <1>Oikeudelliset tiedot", + "commitSha": "Ohjelmistokehitysversion SHA-tunniste: {{sha}}" + } } diff --git a/packages/web/public/i18n/locales/fr-FR/channels.json b/packages/web/public/i18n/locales/fr-FR/channels.json index 25545492d..cc918e8d8 100644 --- a/packages/web/public/i18n/locales/fr-FR/channels.json +++ b/packages/web/public/i18n/locales/fr-FR/channels.json @@ -1,69 +1,71 @@ { - "page": { - "sectionLabel": "Canaux", - "channelName": "Canal {{channelName}}", - "broadcastLabel": "Principal", - "channelIndex": "Ca {{index}}" - }, - "validation": { - "pskInvalid": "Veuillez entrer une clé PSK valide de {{bits}} bits." - }, - "settings": { - "label": "Paramètres du canal", - "description": "Paramètres Crypto, MQTT et divers" - }, - "role": { - "label": "Rôle", - "description": "La télémétrie de l’appareil est envoyée via le canal PRINCIPAL. Un seul canal PRINCIPAL est autorisé.", - "options": { - "primary": "PRINCIPAL", - "disabled": "DÉSACTIVÉ", - "secondary": "SECONDAIRE" - } - }, - "psk": { - "label": "Clé partagée", - "description": "Longueurs de clé PSK prises en charge : 256 bits, 128 bits, 8 bits, vide (0 bit)", - "generate": "Générer" - }, - "name": { - "label": "Nom", - "description": "Un nom unique pour le canal (<12 octets), laisser vide pour utiliser la valeur par défaut" - }, - "uplinkEnabled": { - "label": "Liaison montante activée", - "description": "Envoyer les messages du maillage local vers MQTT" - }, - "downlinkEnabled": { - "label": "Liaison descendante activée", - "description": "Envoyer les messages de MQTT vers le maillage local" - }, - "positionPrecision": { - "label": "Position", - "description": "La précision de la position à partager avec le canal. Peut être désactivée.", - "options": { - "none": "Ne pas partager la position", - "precise": "Position précise", - "metric_km23": "À moins de 23 kilomètres", - "metric_km12": "À moins de 12 kilomètres", - "metric_km5_8": "À moins de 5,8 kilomètres", - "metric_km2_9": "À moins de 2,9 kilomètres", - "metric_km1_5": "À moins de 1,5 kilomètres", - "metric_m700": "À moins de 700 mètres", - "metric_m350": "À moins de 350 mètres", - "metric_m200": "À moins de 200 mètres", - "metric_m90": "À moins de 90 mètres", - "metric_m50": "À moins de 50 mètres", - "imperial_mi15": "À moins de 15 miles", - "imperial_mi7_3": "À moins de 7,3 miles", - "imperial_mi3_6": "À moins de 3,6 miles", - "imperial_mi1_8": "À moins de 1,8 miles", - "imperial_mi0_9": "À moins de 0,9 miles", - "imperial_mi0_5": "À moins de 0,5 miles", - "imperial_mi0_2": "À moins de 0,2 miles", - "imperial_ft600": "À moins de 600 pieds", - "imperial_ft300": "À moins de 300 pieds", - "imperial_ft150": "À moins de 150 pieds" - } - } + "page": { + "sectionLabel": "Canaux", + "channelName": "Canal {{channelName}}", + "broadcastLabel": "Principal", + "channelIndex": "Ca {{index}}", + "import": "Importer", + "export": "Exporter" + }, + "validation": { + "pskInvalid": "Veuillez entrer une clé PSK valide de {{bits}} bits." + }, + "settings": { + "label": "Paramètres du canal", + "description": "Paramètres Crypto, MQTT et divers" + }, + "role": { + "label": "Rôle", + "description": "La télémétrie de l’appareil est envoyée via le canal PRINCIPAL. Un seul canal PRINCIPAL est autorisé.", + "options": { + "primary": "PRINCIPAL", + "disabled": "DÉSACTIVÉ", + "secondary": "SECONDAIRE" + } + }, + "psk": { + "label": "Clé partagée", + "description": "Longueurs de clé PSK prises en charge : 256 bits, 128 bits, 8 bits, vide (0 bit)", + "generate": "Générer" + }, + "name": { + "label": "Nom", + "description": "Un nom unique pour le canal (<12 octets), laisser vide pour utiliser la valeur par défaut" + }, + "uplinkEnabled": { + "label": "Liaison montante activée", + "description": "Envoyer les messages du maillage local vers MQTT" + }, + "downlinkEnabled": { + "label": "Liaison descendante activée", + "description": "Envoyer les messages de MQTT vers le maillage local" + }, + "positionPrecision": { + "label": "Position", + "description": "La précision de la position à partager avec le canal. Peut être désactivée.", + "options": { + "none": "Ne pas partager la position", + "precise": "Position précise", + "metric_km23": "À moins de 23 kilomètres", + "metric_km12": "À moins de 12 kilomètres", + "metric_km5_8": "À moins de 5,8 kilomètres", + "metric_km2_9": "À moins de 2,9 kilomètres", + "metric_km1_5": "À moins de 1,5 kilomètres", + "metric_m700": "À moins de 700 mètres", + "metric_m350": "À moins de 350 mètres", + "metric_m200": "À moins de 200 mètres", + "metric_m90": "À moins de 90 mètres", + "metric_m50": "À moins de 50 mètres", + "imperial_mi15": "À moins de 15 miles", + "imperial_mi7_3": "À moins de 7,3 miles", + "imperial_mi3_6": "À moins de 3,6 miles", + "imperial_mi1_8": "À moins de 1,8 miles", + "imperial_mi0_9": "À moins de 0,9 miles", + "imperial_mi0_5": "À moins de 0,5 miles", + "imperial_mi0_2": "À moins de 0,2 miles", + "imperial_ft600": "À moins de 600 pieds", + "imperial_ft300": "À moins de 300 pieds", + "imperial_ft150": "À moins de 150 pieds" + } + } } diff --git a/packages/web/public/i18n/locales/fr-FR/commandPalette.json b/packages/web/public/i18n/locales/fr-FR/commandPalette.json index ef6cbec9c..88ef1dd7d 100644 --- a/packages/web/public/i18n/locales/fr-FR/commandPalette.json +++ b/packages/web/public/i18n/locales/fr-FR/commandPalette.json @@ -15,7 +15,6 @@ "messages": "Messages", "map": "Carte", "config": "Config", - "channels": "Canaux", "nodes": "Noeuds" } }, @@ -45,7 +44,8 @@ "label": "Debug", "command": { "reconfigure": "Reconfigurer", - "clearAllStoredMessages": "Effacer tous les messages stockés" + "clearAllStoredMessages": "Effacer tous les messages stockés", + "clearAllStores": "Clear All Local Storage" } } } diff --git a/packages/web/public/i18n/locales/fr-FR/common.json b/packages/web/public/i18n/locales/fr-FR/common.json index 9eb510630..cea555a9f 100644 --- a/packages/web/public/i18n/locales/fr-FR/common.json +++ b/packages/web/public/i18n/locales/fr-FR/common.json @@ -1,142 +1,165 @@ { - "button": { - "apply": "Appliquer", - "backupKey": "Clé de sauvegarde", - "cancel": "Annuler", - "clearMessages": "Effacer les messages", - "close": "Fermer", - "confirm": "Confirmer", - "delete": "Effacer", - "dismiss": "Annuler", - "download": "Télécharger", - "export": "Exporter", - "generate": "Générer", - "regenerate": "Regénérer", - "import": "Importer", - "message": "Message", - "now": "Maintenant", - "ok": "D'accord", - "print": "Imprimer", - "remove": "Supprimer", - "requestNewKeys": "Demander de nouvelles clés", - "requestPosition": "Demander la position", - "reset": "Réinitialiser", - "save": "Sauvegarder", - "scanQr": "Scanner le code QR", - "traceRoute": "Analyse du trajet réseau", - "submit": "Envoyer" - }, - "app": { - "title": "Meshtastic", - "fullTitle": "Client Web Meshtastic" - }, - "loading": "Chargement...", - "unit": { - "cps": "CPS", - "dbm": "dBm", - "hertz": "Hz", - "hop": { - "one": "Saut", - "plural": "Sauts" - }, - "hopsAway": { - "one": "À {{count}} saut", - "plural": "À {{count}} sauts", - "unknown": "Nombre de sauts inconnu" - }, - "megahertz": "MHz", - "raw": "brute", - "meter": { - "one": "Mètre", - "plural": "Mètres", - "suffix": "m" - }, - "minute": { - "one": "Minute", - "plural": "Minutes" - }, - "hour": { - "one": "Heure", - "plural": "Heures" - }, - "millisecond": { - "one": "Milliseconde", - "plural": "Millisecondes", - "suffix": "ms" - }, - "second": { - "one": "Seconde", - "plural": "Secondes" - }, - "day": { - "one": "Jour", - "plural": "Jours" - }, - "month": { - "one": "Mois", - "plural": "Mois" - }, - "year": { - "one": "Année", - "plural": "Années" - }, - "snr": "SNR", - "volt": { - "one": "Volt", - "plural": "Volts", - "suffix": "V" - }, - "record": { - "one": "Enregistrement", - "plural": "Enregistrements" - } - }, - "security": { - "0bit": "Vide", - "8bit": "8 bits", - "128bit": "128 bits", - "256bit": "256 bits" - }, - "unknown": { - "longName": "Inconnu", - "shortName": "UNK", - "notAvailable": "Indisponible", - "num": "??" - }, - "nodeUnknownPrefix": "!", - "unset": "DÉSACTIVER", - "fallbackName": "Meshtastic {{last4}}", - "node": "Noeud", - "formValidation": { - "unsavedChanges": "Modifications non enregistrées", - "tooBig": { - "string": "Trop long : {{maximum}} caractères maximum autorisés.", - "number": "Trop grand, un nombre inférieur ou égal à {{maximum}} est attendu.", - "bytes": "Taille trop grand : maximum {{params.maximum}} octets autorisés." - }, - "tooSmall": { - "string": "Trop court : au moins {{minimum}} caractères requis.", - "number": "Valeur trop basse : minimum {{minimum}} requis." - }, - "invalidFormat": { - "ipv4": "Format invalide, adresse IPv4 attendue.", - "key": "Format incorrect, la clé PSK doit être encodée en Base64." - }, - "invalidType": { - "number": "Type incorrect, nombre attendu." - }, - "pskLength": { - "0bit": "La clé doit être vide.", - "8bit": "La clé doit être une clé pré-partagée (PSK) de 8 bits.", - "128bit": "La clé doit être une clé pré-partagée (PSK) de 128 bits.", - "256bit": "La clé doit être une clé pré-partagée (PSK) de 256 bits." - }, - "required": { - "generic": "Ce champ est obligatoire.", - "managed": "Au moins une clé d’administration est requise si le nœud est géré.", - "key": "Clé requise." - } - }, - "yes": "Oui", - "no": "Non" + "button": { + "apply": "Appliquer", + "addConnection": "Add Connection", + "saveConnection": "Save connection", + "backupKey": "Clé de sauvegarde", + "cancel": "Annuler", + "connect": "Connecter", + "clearMessages": "Effacer les messages", + "close": "Fermer", + "confirm": "Confirmer", + "delete": "Effacer", + "dismiss": "Annuler", + "download": "Télécharger", + "disconnect": "Déconnecter", + "export": "Exporter", + "generate": "Générer", + "regenerate": "Regénérer", + "import": "Importer", + "message": "Message", + "now": "Maintenant", + "ok": "D'accord", + "print": "Imprimer", + "remove": "Supprimer", + "requestNewKeys": "Demander de nouvelles clés", + "requestPosition": "Demander la position", + "reset": "Réinitialiser", + "retry": "Retry", + "save": "Sauvegarder", + "setDefault": "Set as default", + "unsetDefault": "Unset default", + "scanQr": "Scanner le code QR", + "traceRoute": "Analyse du trajet réseau", + "submit": "Envoyer" + }, + "app": { + "title": "Meshtastic", + "fullTitle": "Client Web Meshtastic" + }, + "loading": "Chargement...", + "unit": { + "cps": "CPS", + "dbm": "dBm", + "hertz": "Hz", + "hop": { + "one": "Saut", + "plural": "Sauts" + }, + "hopsAway": { + "one": "À {{count}} saut", + "plural": "À {{count}} sauts", + "unknown": "Nombre de sauts inconnu" + }, + "megahertz": "MHz", + "kilohertz": "kHz", + "raw": "brute", + "meter": { + "one": "Mètre", + "plural": "Mètres", + "suffix": "m" + }, + "kilometer": { + "one": "Kilometer", + "plural": "Kilometers", + "suffix": "km" + }, + "minute": { + "one": "Minute", + "plural": "Minutes" + }, + "hour": { + "one": "Heure", + "plural": "Heures" + }, + "millisecond": { + "one": "Milliseconde", + "plural": "Millisecondes", + "suffix": "ms" + }, + "second": { + "one": "Seconde", + "plural": "Secondes" + }, + "day": { + "one": "Jour", + "plural": "Jours", + "today": "Today", + "yesterday": "Yesterday" + }, + "month": { + "one": "Mois", + "plural": "Mois" + }, + "year": { + "one": "Année", + "plural": "Années" + }, + "snr": "SNR", + "volt": { + "one": "Volt", + "plural": "Volts", + "suffix": "V" + }, + "record": { + "one": "Enregistrement", + "plural": "Enregistrements" + }, + "degree": { + "one": "Degree", + "plural": "Degrees", + "suffix": "°" + } + }, + "security": { + "0bit": "Vide", + "8bit": "8 bits", + "128bit": "128 bits", + "256bit": "256 bits" + }, + "unknown": { + "longName": "Inconnu", + "shortName": "UNK", + "notAvailable": "Indisponible", + "num": "??" + }, + "nodeUnknownPrefix": "!", + "unset": "DÉSACTIVER", + "fallbackName": "Meshtastic {{last4}}", + "node": "Noeud", + "formValidation": { + "unsavedChanges": "Modifications non enregistrées", + "tooBig": { + "string": "Trop long : {{maximum}} caractères maximum autorisés.", + "number": "Trop grand, un nombre inférieur ou égal à {{maximum}} est attendu.", + "bytes": "Taille trop grand : maximum {{params.maximum}} octets autorisés." + }, + "tooSmall": { + "string": "Trop court : au moins {{minimum}} caractères requis.", + "number": "Valeur trop basse : minimum {{minimum}} requis." + }, + "invalidFormat": { + "ipv4": "Format invalide, adresse IPv4 attendue.", + "key": "Format incorrect, la clé PSK doit être encodée en Base64." + }, + "invalidType": { + "number": "Type incorrect, nombre attendu." + }, + "pskLength": { + "0bit": "La clé doit être vide.", + "8bit": "La clé doit être une clé pré-partagée (PSK) de 8 bits.", + "128bit": "La clé doit être une clé pré-partagée (PSK) de 128 bits.", + "256bit": "La clé doit être une clé pré-partagée (PSK) de 256 bits." + }, + "required": { + "generic": "Ce champ est obligatoire.", + "managed": "Au moins une clé d’administration est requise si le nœud est géré.", + "key": "Clé requise." + }, + "invalidOverrideFreq": { + "number": "Invalid format, expected a value in the range 410-930 MHz or 0 (use default)." + } + }, + "yes": "Oui", + "no": "Non" } diff --git a/packages/web/public/i18n/locales/fr-FR/config.json b/packages/web/public/i18n/locales/fr-FR/config.json new file mode 100644 index 000000000..d253f7551 --- /dev/null +++ b/packages/web/public/i18n/locales/fr-FR/config.json @@ -0,0 +1,458 @@ +{ + "page": { + "title": "Réglages", + "tabUser": "Utilisateur", + "tabChannels": "Canaux", + "tabBluetooth": "Bluetooth", + "tabDevice": "Appareil", + "tabDisplay": "Écran", + "tabLora": "LoRa", + "tabNetwork": "Réseau", + "tabPosition": "Position", + "tabPower": "Alimentation", + "tabSecurity": "Sécurité" + }, + "sidebar": { + "label": "Configuration" + }, + "device": { + "title": "Paramètres de l'appareil", + "description": "Paramètres de l'appareil", + "buttonPin": { + "description": "Redéfinition de la broche du bouton", + "label": "Broche du bouton" + }, + "buzzerPin": { + "description": "Redéfinition de la broche du buzzer", + "label": "Broche du buzzer" + }, + "disableTripleClick": { + "description": "Désactiver le triple clic", + "label": "Désactiver le triple clic" + }, + "doubleTapAsButtonPress": { + "description": "Considérer le double tapotement comme un appui sur le bouton", + "label": "Double tapotement comme appui bouton" + }, + "ledHeartbeatDisabled": { + "description": "Désactiver le clignotement LED par défaut", + "label": "Clignotement LED désactivé" + }, + "nodeInfoBroadcastInterval": { + "description": "Fréquence de diffusion des informations du nœud", + "label": "Intervalle de diffusion des infos nœud" + }, + "posixTimezone": { + "description": "Chaîne de fuseau horaire POSIX pour l'appareil", + "label": "Zone horaire POSIX" + }, + "rebroadcastMode": { + "description": "Mode de réémission des messages", + "label": "Mode de réémission" + }, + "role": { + "description": "Rôle de l'appareil dans le réseau mesh", + "label": "Rôle" + } + }, + "bluetooth": { + "title": "Paramètres Bluetooth", + "description": "Paramètres du module Bluetooth", + "note": "Note: Certains appareils (ESP32) ne peuvent pas utiliser à la fois Bluetooth et WiFi en même temps.", + "enabled": { + "description": "Activer ou désactiver le Bluetooth", + "label": "Activé" + }, + "pairingMode": { + "description": "Titre en gras", + "label": "Mode d'appariement" + }, + "pin": { + "description": "Broche utilisée pour l'appairage", + "label": "Broche" + } + }, + "display": { + "description": "Paramètres d'affichage de l'appareil", + "title": "Paramètres d'affichage", + "headingBold": { + "description": "Mettre le titre en gras", + "label": "Titre en gras" + }, + "carouselDelay": { + "description": "Vitesse de défilement des fenêtres", + "label": "Délai du carrousel" + }, + "compassNorthTop": { + "description": "Fixer le nord en haut de la boussole", + "label": "Nord en haut de la boussole" + }, + "displayMode": { + "description": "Variante de disposition d'affichage", + "label": "Mode d'affichage" + }, + "displayUnits": { + "description": "Afficher en unités métriques ou impériales", + "label": "Unités affichées" + }, + "flipScreen": { + "description": "Faire pivoter l'affichage de 180 degrés", + "label": "Faire pivoter l'écran" + }, + "gpsDisplayUnits": { + "description": "Format d'affichage des coordonnées", + "label": "Unités GPS" + }, + "oledType": { + "description": "Type d'écran OLED connecté à l'appareil", + "label": "Type d'OLED" + }, + "screenTimeout": { + "description": "Temps avant extinction de l'écran", + "label": "Délai d'extinction de l'écran" + }, + "twelveHourClock": { + "description": "Utiliser le format horaire 12 heures", + "label": "Horloge 12 h" + }, + "wakeOnTapOrMotion": { + "description": "Réveiller l'appareil en cas de tapotement ou de mouvement", + "label": "Réveil par tapotement ou mouvement" + } + }, + "lora": { + "title": "Paramètres maillage", + "description": "Paramètres du réseau maillé LoRa", + "bandwidth": { + "description": "Largeur de bande du canal en kHz", + "label": "Bande Passante" + }, + "boostedRxGain": { + "description": "Gain de réception amplifié", + "label": "Gain RX amplifié" + }, + "codingRate": { + "description": "Dénominateur du taux de codage", + "label": "Taux de codage" + }, + "frequencyOffset": { + "description": "Décalage de fréquence pour corriger les erreurs d'étalonnage du cristal", + "label": "Décalage de fréquence" + }, + "frequencySlot": { + "description": "Numéro du canal de fréquence LoRa", + "label": "Slot de fréquence" + }, + "hopLimit": { + "description": "Nombre maximum de sauts", + "label": "Limite de sauts" + }, + "ignoreMqtt": { + "description": "Ne pas transférer les messages MQTT sur le maillage", + "label": "Ignorer MQTT" + }, + "modemPreset": { + "description": "Préréglage du modem à utiliser", + "label": "Préréglage du modem" + }, + "okToMqtt": { + "description": "Si activé, permet la publication du paquet sur MQTT. Sinon, les nœuds distants ne doivent pas relayer les paquets vers MQTT.", + "label": "OK vers MQTT" + }, + "overrideDutyCycle": { + "description": "Ne pas prendre en compte la limite d'utilisation", + "label": "Ne pas prendre en compte la limite d'utilisation" + }, + "overrideFrequency": { + "description": "Remplacement de la fréquence", + "label": "Fréquence personnalisée" + }, + "region": { + "description": "Définit la région pour votre nœud", + "label": "Région" + }, + "spreadingFactor": { + "description": "Nombre de chirps par symbole", + "label": "Facteur d'étalement" + }, + "transmitEnabled": { + "description": "Activer/désactiver l'émission (TX) depuis la radio LoRa", + "label": "Transmission activée" + }, + "transmitPower": { + "description": "Puissance maximale d'émission", + "label": "Puissance d'émission" + }, + "usePreset": { + "description": "Utiliser un des préréglages prédéfinis du modem", + "label": "Utiliser un préréglage" + }, + "meshSettings": { + "description": "Paramètres du maillage LoRa", + "label": "Paramètres du maillage" + }, + "waveformSettings": { + "description": "Paramètres de la forme d’onde LoRa", + "label": "Paramètres de l’onde" + }, + "radioSettings": { + "label": "Paramètres radio", + "description": "Paramètres de la radio LoRa" + } + }, + "network": { + "title": "Configuration WiFi", + "description": "Configuration de la radio WiFi", + "note": "Remarque : certains appareils (ESP32) ne peuvent pas utiliser simultanément Bluetooth et WiFi.", + "addressMode": { + "description": "Sélection du mode d’attribution d’adresse", + "label": "Mode d’adressage" + }, + "dns": { + "description": "Serveur DNS", + "label": "DNS" + }, + "ethernetEnabled": { + "description": "Activer ou désactiver le port Ethernet", + "label": "Activé" + }, + "gateway": { + "description": "Passerelle par défaut", + "label": "Passerelle" + }, + "ip": { + "description": "Adresse IP", + "label": "IP" + }, + "psk": { + "description": "Mot de passe du réseau", + "label": "PSK" + }, + "ssid": { + "description": "Nom du réseau", + "label": "SSID" + }, + "subnet": { + "description": "Masque de sous-réseau", + "label": "Sous-réseau" + }, + "wifiEnabled": { + "description": "Activer ou désactiver la radio WiFi", + "label": "Activé" + }, + "meshViaUdp": { + "label": "Réseau maillé via UDP" + }, + "ntpServer": { + "label": "Serveur NTP" + }, + "rsyslogServer": { + "label": "Serveur Rsyslog" + }, + "ethernetConfigSettings": { + "description": "Paramètres du port Ethernet", + "label": "Configuration Ethernet" + }, + "ipConfigSettings": { + "description": "Paramètres IP", + "label": "Configuration IP" + }, + "ntpConfigSettings": { + "description": "Configuration NTP", + "label": "Configuration NTP" + }, + "rsyslogConfigSettings": { + "description": "Paramètres Rsyslog", + "label": "Configuration Rsyslog" + }, + "udpConfigSettings": { + "description": "Configuration du réseau maillé via UDP", + "label": "Configuration UDP" + } + }, + "position": { + "title": "Paramètres de position", + "description": "Paramètres du module de position", + "broadcastInterval": { + "description": "Fréquence d’envoi de votre position sur le réseau maillé", + "label": "Intervalle de diffusion" + }, + "enablePin": { + "description": "Redéfinition de la broche d’activation du module GPS", + "label": "Broche d’activation" + }, + "fixedPosition": { + "description": "Ne pas envoyer la position GPS mais une position saisie manuellement", + "label": "Position fixe" + }, + "gpsMode": { + "description": "Configuration du GPS : activé, désactivé ou non présent", + "label": "Mode GPS" + }, + "gpsUpdateInterval": { + "description": "Fréquence d’acquisition d’une position GPS", + "label": "Intervalle de mise à jour GPS" + }, + "positionFlags": { + "description": "Champs optionnels à inclure dans les messages de position. Plus il y en a, plus le message est grand, augmentant le risque de perte.", + "label": "Champs de position" + }, + "receivePin": { + "description": "Redéfinition de la broche RX du module GPS", + "label": "Broche de réception" + }, + "smartPositionEnabled": { + "description": "N’envoyer la position qu’en cas de changement significatif", + "label": "Activer la position intelligente" + }, + "smartPositionMinDistance": { + "description": "Distance minimale (en mètres) à parcourir avant envoi de la nouvelle position", + "label": "Distance minimale pour mise à jour" + }, + "smartPositionMinInterval": { + "description": "Délai minimal (en secondes) entre deux envois de position", + "label": "Intervalle minimal de mise à jour" + }, + "transmitPin": { + "description": "Redéfinition de la broche TX du module GPS", + "label": "Broche de transmission" + }, + "intervalsSettings": { + "description": "Fréquence d’envoi des mises à jour de position", + "label": "Intervalles" + }, + "flags": { + "placeholder": "Sélectionner les champs de position...", + "altitude": "Altitude", + "altitudeGeoidalSeparation": "Séparation géoïdale de l’altitude", + "altitudeMsl": "Altitude au-dessus du niveau moyen de la mer", + "dop": "DOP (Dilution de la précision), PDOP utilisé par défaut", + "hdopVdop": "Si DOP est activé, utiliser HDOP / VDOP au lieu de PDOP", + "numSatellites": "Nombre de satellites", + "sequenceNumber": "Numéro de séquence", + "timestamp": "Horodatage", + "unset": "Désactivé", + "vehicleHeading": "Cap du véhicule", + "vehicleSpeed": "Vitesse du véhicule" + } + }, + "power": { + "adcMultiplierOverride": { + "description": "Utilisé pour ajuster la lecture de la tension batterie", + "label": "Coefficient de correction ADC" + }, + "ina219Address": { + "description": "Adresse du moniteur de batterie INA219", + "label": "Adresse INA219" + }, + "lightSleepDuration": { + "description": "Durée pendant laquelle l'appareil reste en veille légère", + "label": "Durée de veille légère" + }, + "minimumWakeTime": { + "description": "Temps minimal pendant lequel l'appareil reste éveillé après réception d’un paquet", + "label": "Temps d’éveil minimal" + }, + "noConnectionBluetoothDisabled": { + "description": "Si aucune connexion Bluetooth n’est reçue, la radio BLE sera désactivée après ce délai", + "label": "Bluetooth désactivé si non connecté" + }, + "powerSavingEnabled": { + "description": "À activer si l’appareil est alimenté par une source à faible courant (ex. : panneau solaire)..", + "label": "Activer le mode économie d'énergie" + }, + "shutdownOnBatteryDelay": { + "description": "Éteindre automatiquement le nœud après ce délai sur batterie, 0 pour indéfini", + "label": "Délai d’extinction sur batterie" + }, + "superDeepSleepDuration": { + "description": "Durée pendant laquelle l’appareil reste en super veille", + "label": "Durée de veille profonde" + }, + "powerConfigSettings": { + "description": "Paramètres du module d’alimentation", + "label": "Configuration de l'alimentation" + }, + "sleepSettings": { + "description": "Paramètres de veille du module d’alimentation", + "label": "Paramètres de veille" + } + }, + "security": { + "description": "Paramètres de configuration de la sécurité", + "title": "Paramètres de sécurité", + "button_backupKey": "Clé de sauvegarde", + "adminChannelEnabled": { + "description": "Autoriser le contrôle distant via le canal d’administration hérité non sécurisé", + "label": "Autoriser l’administration héritée" + }, + "enableDebugLogApi": { + "description": "Afficher en direct les journaux de débogage via le port série, consulter/exporter les journaux sans position via Bluetooth", + "label": "Activer l’API des journaux de debug" + }, + "managed": { + "description": "Si cette option est activée, les options de configuration de l'appareil ne peuvent être modifiées à distance que par un nœud d'administration distante via des messages d'administration. N'activez cette option que si au moins un nœud d'administration distant approprié a été configuré et que la clé publique est stockée dans l'un des champs ci-dessus.", + "label": "Géré" + }, + "privateKey": { + "description": "Utilisée pour créer une clé partagée avec un appareil distant", + "label": "Clé privée" + }, + "publicKey": { + "description": "Envoyée aux autres nœuds pour générer une clé secrète partagée", + "label": "Clé publique" + }, + "primaryAdminKey": { + "description": "Clé publique principale autorisée à envoyer des messages d’administration", + "label": "Clé Admin principale" + }, + "secondaryAdminKey": { + "description": "Clé publique secondaire autorisée à envoyer des messages d’administration", + "label": "Clé Admin secondaire" + }, + "serialOutputEnabled": { + "description": "Console série via l’API de flux", + "label": "Sortie série activée" + }, + "tertiaryAdminKey": { + "description": "Clé publique tertiaire autorisée à envoyer des messages d’administration", + "label": "Clé Admin tertiaire" + }, + "adminSettings": { + "description": "Paramètres liés à l’administration", + "label": "Paramètres administrateur" + }, + "loggingSettings": { + "description": "Paramètres liés aux journaux", + "label": "Paramètres de journalisation" + } + }, + "user": { + "title": "User Settings", + "description": "Configure your device name and identity settings", + "longName": { + "label": "Nom long", + "description": "Your full display name (1-40 characters)", + "validation": { + "min": "Long name must be at least 1 character", + "max": "Long name must be at most 40 characters" + } + }, + "shortName": { + "label": "Nom court", + "description": "Your abbreviated name (2-4 characters)", + "validation": { + "min": "Short name must be at least 2 characters", + "max": "Short name must be at most 4 characters" + } + }, + "isUnmessageable": { + "label": "Non joignable par message", + "description": "Used to identify unmonitored or infrastructure nodes so that messaging is not available to nodes that will never respond." + }, + "isLicensed": { + "label": "Radioamateur licencié (HAM)", + "description": "Enable if you are a licensed amateur radio operator, enabling this option disables encryption and is not compatible with the default Meshtastic network." + } + } +} diff --git a/packages/web/public/i18n/locales/fr-FR/connections.json b/packages/web/public/i18n/locales/fr-FR/connections.json new file mode 100644 index 000000000..996e1fe22 --- /dev/null +++ b/packages/web/public/i18n/locales/fr-FR/connections.json @@ -0,0 +1,34 @@ +{ + "page": { + "title": "Connect to a Meshtastic device", + "description": "Add a device connection via HTTP, Bluetooth, or Serial. Your saved connections will be saved in your browser." + }, + "connectionType_ble": "BLE", + "connectionType_serial": "Série", + "connectionType_network": "Réseau", + "deleteConnection": "Delete connection", + "areYouSure": "This will remove {{name}}. You canot undo this action.", + "moreActions": "More actions", + "noConnections": { + "title": "No connections yet.", + "description": "Create your first connection. It will connect immediately and be saved for later." + }, + "lastConnectedAt": "Last connected: {{date}}", + "neverConnected": "Never connected", + "toasts": { + "connected": "Connecté", + "nowConnected": "{{name}} is now connected", + "nowDisconnected": "{{name}} are now disconnecte", + "disconnected": "Déconnecté", + "failed": "Failed to connect", + "checkConnetion": "Check your device or settings and try again", + "defaultSet": "Default set", + "defaultConnection": "Default connection is now {{nameisconnected}}", + "deleted": "Deleted", + "deletedByName": "{{name}} was removed", + "pickConnectionAgain": "Could not connect. You may need to reselect the device/port.", + "added": "Connection added", + "savedByName": "{{name}} saved.", + "savedCantConnect": "The connection was saved but could not connect." + } +} diff --git a/packages/web/public/i18n/locales/fr-FR/dashboard.json b/packages/web/public/i18n/locales/fr-FR/dashboard.json deleted file mode 100644 index b398ae492..000000000 --- a/packages/web/public/i18n/locales/fr-FR/dashboard.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "dashboard": { - "title": "Appareils connectés", - "description": "Gérez vos périphériques Meshtastic connectés.", - "connectionType_ble": "BLE", - "connectionType_serial": "Série", - "connectionType_network": "Réseau", - "noDevicesTitle": "Aucun appareil connecté", - "noDevicesDescription": "Connectez un nouvel appareil pour commencer.", - "button_newConnection": "Nouvelle connexion" - } -} diff --git a/packages/web/public/i18n/locales/fr-FR/deviceConfig.json b/packages/web/public/i18n/locales/fr-FR/deviceConfig.json index baaedbc79..86d13a66f 100644 --- a/packages/web/public/i18n/locales/fr-FR/deviceConfig.json +++ b/packages/web/public/i18n/locales/fr-FR/deviceConfig.json @@ -122,7 +122,7 @@ "title": "Paramètres maillage", "description": "Paramètres du réseau maillé LoRa", "bandwidth": { - "description": "Largeur de bande du canal en MHz", + "description": "Largeur de bande du canal en kHz", "label": "Bande Passante" }, "boostedRxGain": { diff --git a/packages/web/public/i18n/locales/fr-FR/dialog.json b/packages/web/public/i18n/locales/fr-FR/dialog.json index 3d795cf2a..1d1ec587e 100644 --- a/packages/web/public/i18n/locales/fr-FR/dialog.json +++ b/packages/web/public/i18n/locales/fr-FR/dialog.json @@ -1,193 +1,238 @@ { - "deleteMessages": { - "description": "Cette action effacera tout l’historique des messages. Cette opération est irréversible. Voulez-vous vraiment continuer ?", - "title": "Supprimer tous les messages" - }, - "deviceName": { - "description": "L’appareil redémarrera une fois la configuration enregistrée.", - "longName": "Nom long", - "shortName": "Nom court", - "title": "Changer le nom de l’appareil", - "validation": { - "longNameMax": "Le nom long ne doit pas contenir plus de 40 caractères", - "shortNameMax": "Le nom court ne doit pas contenir plus de 4 caractères", - "longNameMin": "Le nom long doit contenir au moins 1 caractère", - "shortNameMin": "Le nom court doit contenir au moins 1 caractère" - } - }, - "import": { - "description": "La configuration LoRa actuelle sera écrasée.", - "error": { - "invalidUrl": "URL Meshtastic invalide" - }, - "channelPrefix": "Canal: ", - "channelSetUrl": "URL du set de canaux ou du QR code", - "channels": "Canaux:", - "usePreset": "Utiliser un préréglage?", - "title": "Importer un ensemble de canaux" - }, - "locationResponse": { - "title": "Position : {{identifier}}", - "altitude": "Altitude: ", - "coordinates": "Coordonnées : ", - "noCoordinates": "Pas de coordonnées" - }, - "pkiRegenerateDialog": { - "title": "Régénérer la clé pré-partagée ?", - "description": "Êtes-vous sûr de vouloir régénérer la clé pré-partagée ?", - "regenerate": "Régénérer" - }, - "newDeviceDialog": { - "title": "Connecter un nouvel appareil", - "https": "https", - "http": "http", - "tabHttp": "HTTP", - "tabBluetooth": "Bluetooth", - "tabSerial": "Série", - "useHttps": "Utiliser HTTPS", - "connecting": "Connexion...", - "connect": "Connecter", - "connectionFailedAlert": { - "title": "Échec de la connexion", - "descriptionPrefix": "Vous ne pouvez pas connecter l'appareil. ", - "httpsHint": "Si vous utilisez HTTPS, vous devrez peut-être accepter un certificat auto-signé. ", - "openLinkPrefix": "Veuillez ouvrir ", - "openLinkSuffix": " dans un nouvel onglet", - "acceptTlsWarningSuffix": ", acceptez les avertissements TLS si vous y êtes invité, puis réessayez", - "learnMoreLink": "En savoir plus" - }, - "httpConnection": { - "label": "Adresse IP / nom d'hôte", - "placeholder": "000.000.000.000 / meshtastic.local" - }, - "serialConnection": { - "noDevicesPaired": "Aucun appareil appairé pour l’instant.", - "newDeviceButton": "Nouvel appareil", - "deviceIdentifier": "# {{index}} - {{vendorId}} - {{productId}}" - }, - "bluetoothConnection": { - "noDevicesPaired": "Aucun appareil appairé pour l’instant.", - "newDeviceButton": "Nouvel appareil", - "connectionFailed": "Échec de la connexion", - "deviceDisconnected": "Périphérique déconnecté", - "unknownDevice": "Périphérique inconnu", - "errorLoadingDevices": "Erreur lors du chargement des périphériques", - "unknownErrorLoadingDevices": "Erreur inconnue lors du chargement des périphériques" - }, - "validation": { - "requiresWebBluetooth": "Ce type de connexion nécessite <0>Web Bluetooth. Veuillez utiliser un navigateur compatible, comme Chrome ou Edge.<0>", - "requiresWebSerial": "Ce type de connexion nécessite <0>Web Serial. Veuillez utiliser un navigateur compatible, comme Chrome ou Edge.", - "requiresSecureContext": "Cette application nécessite un <0>contexte sécurisé. Veuillez vous connecter via HTTPS ou localhost.", - "additionallyRequiresSecureContext": "Elle nécessite également un <0>contexte sécurisé. Veuillez vous connecter via HTTPS ou localhost." - } - }, - "nodeDetails": { - "message": "Message", - "requestPosition": "Demander la position", - "traceRoute": "Tracer la route", - "airTxUtilization": "Utilisation TX sur l’air", - "allRawMetrics": "Toutes les métriques brutes :", - "batteryLevel": "Niveau de batterie", - "channelUtilization": "Utilisation du canal", - "details": "Détails :", - "deviceMetrics": "Métriques de l’appareil :", - "hardware": "Matériel : ", - "lastHeard": "Dernière écoute: ", - "nodeHexPrefix": "Hex du nœud: ", - "nodeNumber": "Numéro de nœud: ", - "position": "Position:", - "role": "Rôle: ", - "uptime": "Temps de fonctionnement :", - "voltage": "Tension", - "title": "Détails du nœud pour {{identifier}}", - "ignoreNode": "Ignorer le nœud", - "removeNode": "Supprimer le nœud", - "unignoreNode": "Ne plus ignorer le nœud", - "security": "Sécurité:", - "publicKey": "Clé publique: ", - "messageable": "Messageable ", - "KeyManuallyVerifiedTrue": "La clé publique a été vérifiée manuellement", - "KeyManuallyVerifiedFalse": "La clé publique n'est pas vérifiée manuellement" - }, - "pkiBackup": { - "loseKeysWarning": "Si vous perdez vos clés, vous devrez réinitialiser votre appareil.", - "secureBackup": "Il est important de sauvegarder vos clés publique et privée, et de stocker cette sauvegarde en lieu sûr !", - "footer": "=== FIN DES CLÉS ===", - "header": "=== CLÉS MESHTASTIC POUR {{longName}} ({{shortName}}) ===", - "privateKey": "Clé privée :", - "publicKey": "Clé publique :", - "fileName": "meshtastic_cles_{{longName}}_{{shortName}}.txt", - "title": "Sauvegarder les clés" - }, - "pkiBackupReminder": { - "description": "Nous vous recommandons de sauvegarder régulièrement vos clés. Souhaitez-vous effectuer une sauvegarde maintenant ?", - "title": "Rappel de sauvegarde", - "remindLaterPrefix": "Me le rappeler dans", - "remindNever": "Ne plus me le rappeler", - "backupNow": "Sauvegarder maintenant" - }, - "pkiRegenerate": { - "description": "Êtes-vous sûr de vouloir régénérer la paire de clés ?", - "title": "Régénérer la paire de clés" - }, - "qr": { - "addChannels": "Ajouter des canaux", - "replaceChannels": "Remplacer les canaux", - "description": "La configuration LoRa actuelle sera également partagée.", - "sharableUrl": "URL partageable", - "title": "Générer un QR Code" - }, - "reboot": { - "title": "Redémarrer l'appareil", - "description": "Redémarrez maintenant ou programmez un redémarrage du nœud connecté. Vous pouvez éventuellement choisir de redémarrer en mode OTA (Over-the-Air).", - "ota": "Redémarrer en mode OTA", - "enterDelay": "Entrez le délai", - "scheduled": "Le redémarrage a été programmé", - "schedule": "Programmer le redémarrage", - "now": "Redémarrer maintenant", - "cancel": "Annuler le redémarrage planifié" - }, - "refreshKeys": { - "description": { - "acceptNewKeys": "Cela supprimera le nœud de l’appareil et demandera de nouvelles clés.", - "keyMismatchReasonSuffix": ". Cela est dû au fait que la clé publique actuelle du nœud distant ne correspond pas à celle précédemment enregistrée pour ce nœud.", - "unableToSendDmPrefix": "Accepter les nouvelles clés" - }, - "acceptNewKeys": "Accepter les nouvelles clés", - "title": "Clés non concordantes – {{identifier}}" - }, - "removeNode": { - "description": "Êtes-vous sûr de vouloir supprimer ce nœud ?", - "title": "Supprimer le nœud ?" - }, - "shutdown": { - "title": "Programmer un arrêt", - "description": "Éteindre le nœud connecté après x minutes." - }, - "traceRoute": { - "routeToDestination": "Route vers la destination :", - "routeBack": "Route de retour :" - }, - "tracerouteResponse": { - "title": "Traceroute : {{identifier}}" - }, - "unsafeRoles": { - "confirmUnderstanding": "Oui, je sais ce que je fais", - "conjunction": " et l’article de blog sur le ", - "postamble": " et je comprends les implications du changement de rôle.", - "preamble": "J'ai lu les", - "choosingRightDeviceRole": "Choisir le rôle d’appareil approprié", - "deviceRoleDocumentation": "Documentation sur les rôles d’appareil", - "title": "Êtes-vous sûr ?" - }, - "managedMode": { - "confirmUnderstanding": "Oui, je sais ce que je fais", - "title": "Êtes-vous sûr ?", - "description": "Activer le mode géré empêche les applications clientes (y compris l’interface web) de modifier la configuration d’une radio. Une fois activé, la configuration ne peut être changée que via des messages d’administration à distance. Ce paramètre n’est pas nécessaire pour l’administration distante des nœuds." - }, - "clientNotification": { - "title": "Notification client", - "TraceRoute can only be sent once every 30 seconds": "TraceRoute ne peut être envoyée qu'une fois toutes les 30 secondes", - "Compromised keys were detected and regenerated.": "Les clés compromises ont été détectées et régénérées." - } + "deleteMessages": { + "description": "Cette action effacera tout l’historique des messages. Cette opération est irréversible. Voulez-vous vraiment continuer ?", + "title": "Supprimer tous les messages" + }, + "import": { + "description": "La configuration LoRa actuelle sera écrasée.", + "error": { + "invalidUrl": "URL Meshtastic invalide" + }, + "channelPrefix": "Canal: ", + "primary": "Primary ", + "doNotImport": "No not import", + "channelName": "Nom", + "channelSlot": "Emplacement", + "channelSetUrl": "URL du set de canaux ou du QR code", + "useLoraConfig": "Import LoRa Config", + "presetDescription": "The current LoRa Config will be replaced.", + "title": "Importer un ensemble de canaux" + }, + "locationResponse": { + "title": "Position : {{identifier}}", + "altitude": "Altitude: ", + "coordinates": "Coordonnées : ", + "noCoordinates": "Pas de coordonnées" + }, + "pkiRegenerateDialog": { + "title": "Régénérer la clé pré-partagée ?", + "description": "Êtes-vous sûr de vouloir régénérer la clé pré-partagée ?", + "regenerate": "Régénérer" + }, + "addConnection": { + "title": "Add connection", + "description": "Choose a connection type and fill in the details", + "validation": { + "requiresWebBluetooth": "Ce type de connexion nécessite <0>Web Bluetooth. Veuillez utiliser un navigateur compatible, comme Chrome ou Edge.<0>", + "requiresWebSerial": "Ce type de connexion nécessite <0>Web Serial. Veuillez utiliser un navigateur compatible, comme Chrome ou Edge.", + "requiresSecureContext": "Cette application nécessite un <0>contexte sécurisé. Veuillez vous connecter via HTTPS ou localhost.", + "additionallyRequiresSecureContext": "Elle nécessite également un <0>contexte sécurisé. Veuillez vous connecter via HTTPS ou localhost." + }, + "bluetoothConnection": { + "namePlaceholder": "My Bluetooth Node", + "supported": { + "title": "Web Bluetooth supported" + }, + "notSupported": { + "title": "Web Bluetooth not supported", + "description": "Your browser or device does not support Web Bluetooth" + }, + "short": "BT: {{deviceName}}", + "long": "Bluetooth Device", + "device": "Appareil", + "selectDevice": "Select device", + "selected": "Bluetooth device selected", + "notSelected": "No device selected", + "helperText": "Uses the Meshtastic Bluetooth service for discovery." + }, + "serialConnection": { + "namePlaceholder": "My Serial Node", + "helperText": "Selecting a port grants permission so the app can open it to connect.", + "supported": { + "title": "Web Serial supported" + }, + "notSupported": { + "title": "Web Serial not supported", + "description": "Your browser or device does not support Web Serial" + }, + "portSelected": { + "title": "Serial port selected", + "description": "Port permissions granted." + }, + "port": "Port", + "selectPort": "Select port", + "deviceName": "USB {{vendorId}}:{{productId}}", + "notSelected": "No port selected" + }, + "httpConnection": { + "namePlaceholder": "My HTTP Node", + "inputPlaceholder": "192.168.1.10 or meshtastic.local", + "heading": "URL or IP", + "useHttps": "Use HTTTPS", + "invalidUrl": { + "title": "Invalid URL", + "description": "Please enter a valid HTTP or HTTPS URL." + }, + "connectionTest": { + "description": "Test the connetion before saving to verify the device is reachable.", + "button": { + "loading": "Testing...", + "label": "Test connection" + }, + "reachable": "Reachable", + "notReachable": "Not reachable", + "success": { + "title": "Connection test successful", + "description": "The device appears to be reachable." + }, + "failure": { + "title": "Connection test failed", + "description": "Could not reach the device. Check the URL and try again." + } + } + } + }, + "nodeDetails": { + "message": "Message", + "requestPosition": "Demander la position", + "traceRoute": "Tracer la route", + "airTxUtilization": "Utilisation TX sur l’air", + "allRawMetrics": "Toutes les métriques brutes :", + "batteryLevel": "Niveau de batterie", + "channelUtilization": "Utilisation du canal", + "details": "Détails :", + "deviceMetrics": "Métriques de l’appareil :", + "hardware": "Matériel : ", + "lastHeard": "Dernière écoute: ", + "nodeHexPrefix": "Hex du nœud: ", + "nodeNumber": "Numéro de nœud: ", + "position": "Position:", + "role": "Rôle: ", + "uptime": "Temps de fonctionnement :", + "voltage": "Tension", + "title": "Détails du nœud pour {{identifier}}", + "ignoreNode": "Ignorer le nœud", + "removeNode": "Supprimer le nœud", + "unignoreNode": "Ne plus ignorer le nœud", + "security": "Sécurité:", + "publicKey": "Clé publique: ", + "messageable": "Messageable ", + "KeyManuallyVerifiedTrue": "La clé publique a été vérifiée manuellement", + "KeyManuallyVerifiedFalse": "La clé publique n'est pas vérifiée manuellement" + }, + "pkiBackup": { + "loseKeysWarning": "Si vous perdez vos clés, vous devrez réinitialiser votre appareil.", + "secureBackup": "Il est important de sauvegarder vos clés publique et privée, et de stocker cette sauvegarde en lieu sûr !", + "footer": "=== FIN DES CLÉS ===", + "header": "=== CLÉS MESHTASTIC POUR {{longName}} ({{shortName}}) ===", + "privateKey": "Clé privée :", + "publicKey": "Clé publique :", + "fileName": "meshtastic_cles_{{longName}}_{{shortName}}.txt", + "title": "Sauvegarder les clés" + }, + "pkiBackupReminder": { + "description": "Nous vous recommandons de sauvegarder régulièrement vos clés. Souhaitez-vous effectuer une sauvegarde maintenant ?", + "title": "Rappel de sauvegarde", + "remindLaterPrefix": "Me le rappeler dans", + "remindNever": "Ne plus me le rappeler", + "backupNow": "Sauvegarder maintenant" + }, + "pkiRegenerate": { + "description": "Êtes-vous sûr de vouloir régénérer la paire de clés ?", + "title": "Régénérer la paire de clés" + }, + "qr": { + "addChannels": "Ajouter des canaux", + "replaceChannels": "Remplacer les canaux", + "description": "La configuration LoRa actuelle sera également partagée.", + "sharableUrl": "URL partageable", + "title": "Générer un QR Code" + }, + "reboot": { + "title": "Redémarrer l'appareil", + "description": "Redémarrez maintenant ou programmez un redémarrage du nœud connecté. Vous pouvez éventuellement choisir de redémarrer en mode OTA (Over-the-Air).", + "ota": "Redémarrer en mode OTA", + "enterDelay": "Entrez le délai", + "scheduled": "Le redémarrage a été programmé", + "schedule": "Programmer le redémarrage", + "now": "Redémarrer maintenant", + "cancel": "Annuler le redémarrage planifié" + }, + "refreshKeys": { + "description": { + "acceptNewKeys": "Cela supprimera le nœud de l’appareil et demandera de nouvelles clés.", + "keyMismatchReasonSuffix": ". Cela est dû au fait que la clé publique actuelle du nœud distant ne correspond pas à celle précédemment enregistrée pour ce nœud.", + "unableToSendDmPrefix": "Accepter les nouvelles clés" + }, + "acceptNewKeys": "Accepter les nouvelles clés", + "title": "Clés non concordantes – {{identifier}}" + }, + "removeNode": { + "description": "Êtes-vous sûr de vouloir supprimer ce nœud ?", + "title": "Supprimer le nœud ?" + }, + "shutdown": { + "title": "Programmer un arrêt", + "description": "Éteindre le nœud connecté après x minutes." + }, + "traceRoute": { + "routeToDestination": "Route vers la destination :", + "routeBack": "Route de retour :" + }, + "tracerouteResponse": { + "title": "Traceroute : {{identifier}}" + }, + "unsafeRoles": { + "confirmUnderstanding": "Oui, je sais ce que je fais", + "conjunction": " et l’article de blog sur le ", + "postamble": " et je comprends les implications du changement de rôle.", + "preamble": "J'ai lu les", + "choosingRightDeviceRole": "Choisir le rôle d’appareil approprié", + "deviceRoleDocumentation": "Documentation sur les rôles d’appareil", + "title": "Êtes-vous sûr ?" + }, + "managedMode": { + "confirmUnderstanding": "Oui, je sais ce que je fais", + "title": "Êtes-vous sûr ?", + "description": "Activer le mode géré empêche les applications clientes (y compris l’interface web) de modifier la configuration d’une radio. Une fois activé, la configuration ne peut être changée que via des messages d’administration à distance. Ce paramètre n’est pas nécessaire pour l’administration distante des nœuds." + }, + "clientNotification": { + "title": "Notification client", + "TraceRoute can only be sent once every 30 seconds": "TraceRoute ne peut être envoyée qu'une fois toutes les 30 secondes", + "Compromised keys were detected and regenerated.": "Les clés compromises ont été détectées et régénérées." + }, + "resetNodeDb": { + "title": "Reset Node Database", + "description": "This will clear all nodes from the connected device's node database and clear all message history in the client. This cannot be undone. Are you sure you want to continue?", + "confirm": "Reset Node Database", + "failedTitle": "There was an error resetting the Node DB. Please try again." + }, + "clearAllStores": { + "title": "Clear All Local Storage", + "description": "This will clear all locally stored data, including message history and node databases for all previously connected devices. This will require you to reconnect to your node once complete and cannot be undone. Are you sure you want to continue?", + "confirm": "Clear all local storage", + "failedTitle": "There was an error clearing local storage. Please try again." + }, + "factoryResetDevice": { + "title": "Réinitialisation d'usine de l'appareil", + "description": "This will factory reset the connected device, erasing all configurations and data on the device as well as all nodes and messages saved in the client. This cannot be undone. Are you sure you want to continue?", + "confirm": "Réinitialisation d'usine de l'appareil", + "failedTitle": "There was an error performing the factory reset. Please try again." + }, + "factoryResetConfig": { + "title": "Réinitialisation d'usine de la config", + "description": "This will factory reset the configuration on the connected device, erasing all configurations on the device. This cannot be undone. Are you sure you want to continue?", + "confirm": "Réinitialisation d'usine de la config", + "failedTitle": "There was an error performing the factory reset. Please try again." + } } diff --git a/packages/web/public/i18n/locales/fr-FR/map.json b/packages/web/public/i18n/locales/fr-FR/map.json new file mode 100644 index 000000000..427bff1ef --- /dev/null +++ b/packages/web/public/i18n/locales/fr-FR/map.json @@ -0,0 +1,38 @@ +{ + "maplibre": { + "GeolocateControl.FindMyLocation": "Find my location", + "NavigationControl.ZoomIn": "Zoom in", + "NavigationControl.ZoomOut": "Zoom out", + "CooperativeGesturesHandler.WindowsHelpText": "Use Ctrl + scroll to zoom the map", + "CooperativeGesturesHandler.MacHelpText": "Use ⌘ + scroll to zoom the map", + "CooperativeGesturesHandler.MobileHelpText": "Use two fingers to move the map" + }, + "layerTool": { + "nodeMarkers": "Show nodes", + "directNeighbors": "Show direct connections", + "remoteNeighbors": "Show remote connections", + "positionPrecision": "Show position precision", + "traceroutes": "Show traceroutes", + "waypoints": "Show waypoints" + }, + "mapMenu": { + "locateAria": "Locate my node", + "layersAria": "Change map style" + }, + "waypointDetail": { + "edit": "Modifier", + "description": "Description:", + "createdBy": "Edited by:", + "createdDate": "Created:", + "updated": "Updated:", + "expires": "Expires:", + "distance": "Distance:", + "bearing": "Absolute bearing:", + "lockedTo": "Locked by:", + "latitude": "Latitude:", + "longitude": "Longitude:" + }, + "myNode": { + "tooltip": "This device" + } +} diff --git a/packages/web/public/i18n/locales/fr-FR/messages.json b/packages/web/public/i18n/locales/fr-FR/messages.json index 73710fce4..4071ee4e1 100644 --- a/packages/web/public/i18n/locales/fr-FR/messages.json +++ b/packages/web/public/i18n/locales/fr-FR/messages.json @@ -1,39 +1,39 @@ { - "page": { - "title": "Messages: {{chatName}}", - "placeholder": "Saisir message" - }, - "emptyState": { - "title": "Sélectionnez un chat", - "text": "Aucun message pour le moment." - }, - "selectChatPrompt": { - "text": "Sélectionnez un canal ou un nœud pour commencer à envoyer des messages." - }, - "sendMessage": { - "placeholder": "Entrez votre message ici...", - "sendButton": "Envoyer" - }, - "actionsMenu": { - "addReactionLabel": "Ajouter une réaction", - "replyLabel": "Répondre" - }, - "deliveryStatus": { - "delivered": { - "label": "Message délivré", - "displayText": "Message délivré" - }, - "failed": { - "label": "La transmission du message a échoué", - "displayText": "Échec de l'envoi" - }, - "unknown": { - "label": "Statut du message inconnu", - "displayText": "Statut inconnu" - }, - "waiting": { - "label": "Envoi du message", - "displayText": "En attente de réception" - } - } + "page": { + "title": "Messages: {{chatName}}", + "placeholder": "Saisir message" + }, + "emptyState": { + "title": "Sélectionnez un chat", + "text": "Aucun message pour le moment." + }, + "selectChatPrompt": { + "text": "Sélectionnez un canal ou un nœud pour commencer à envoyer des messages." + }, + "sendMessage": { + "placeholder": "Entrez votre message ici...", + "sendButton": "Envoyer" + }, + "actionsMenu": { + "addReactionLabel": "Ajouter une réaction", + "replyLabel": "Répondre" + }, + "deliveryStatus": { + "delivered": { + "label": "Message délivré", + "displayText": "Message délivré" + }, + "failed": { + "label": "La transmission du message a échoué", + "displayText": "Échec de l'envoi" + }, + "unknown": { + "label": "Statut du message inconnu", + "displayText": "Statut inconnu" + }, + "waiting": { + "label": "Envoi du message", + "displayText": "En attente de réception" + } + } } diff --git a/packages/web/public/i18n/locales/fr-FR/moduleConfig.json b/packages/web/public/i18n/locales/fr-FR/moduleConfig.json index 9642e2b0f..e3ac5e4c8 100644 --- a/packages/web/public/i18n/locales/fr-FR/moduleConfig.json +++ b/packages/web/public/i18n/locales/fr-FR/moduleConfig.json @@ -1,448 +1,448 @@ { - "page": { - "tabAmbientLighting": "Lumière ambiante", - "tabAudio": "Audio", - "tabCannedMessage": "Message pré-enregistré", - "tabDetectionSensor": "Capteur de détection", - "tabExternalNotification": "Notification externe", - "tabMqtt": "MQTT", - "tabNeighborInfo": "Informations sur les voisins", - "tabPaxcounter": "Paxcounter", - "tabRangeTest": "Test de portée", - "tabSerial": "Série", - "tabStoreAndForward": "Stocker & Relayer", - "tabTelemetry": "Télémetrie (Capteurs)" - }, - "ambientLighting": { - "title": "Paramètres de l’éclairage ambiant", - "description": "Paramètres du module d’éclairage ambiant", - "ledState": { - "label": "État des LED", - "description": "Définit les LED sur allumées ou éteintes" - }, - "current": { - "label": "Actif", - "description": "Définit le courant de sortie des LED. Par défaut : 10" - }, - "red": { - "label": "Rouge", - "description": "Définit le niveau de LED rouge (valeurs 0–255)" - }, - "green": { - "label": "Vert", - "description": "Définit le niveau de LED vert (valeurs 0–255)" - }, - "blue": { - "label": "Bleu", - "description": "Définit le niveau de LED bleu (valeurs 0–255)" - } - }, - "audio": { - "title": "Paramètres audio", - "description": "Paramètres du module audio", - "codec2Enabled": { - "label": "Codec 2 activé", - "description": "Active l'encodage audio Codec 2" - }, - "pttPin": { - "label": "Broche PTT", - "description": "Broche GPIO utilisée pour le PTT" - }, - "bitrate": { - "label": "Débit", - "description": "Débit utilisé pour l’encodage audio" - }, - "i2sWs": { - "label": "i2S WS", - "description": "Broche GPIO utilisée pour i2S WS" - }, - "i2sSd": { - "label": "i2S SD", - "description": "Broche GPIO utilisée pour i2S SD" - }, - "i2sDin": { - "label": "i2S DIN", - "description": "Broche GPIO utilisée pour i2S DIN" - }, - "i2sSck": { - "label": "i2S SCK", - "description": "Broche GPIO utilisée pour i2S SCK" - } - }, - "cannedMessage": { - "title": "Paramètres des messages pré-enregistrés", - "description": "Paramètres du module de messages pré-enregistrés\n", - "moduleEnabled": { - "label": "Module activé", - "description": "Active les messages pré-enregistrés" - }, - "rotary1Enabled": { - "label": "Encodeur rotatif #1 activé", - "description": "Active l’encodeur rotatif" - }, - "inputbrokerPinA": { - "label": "Broche A de l’encodeur", - "description": "Valeur GPIO (1-39) pour le port A de l’encodeur" - }, - "inputbrokerPinB": { - "label": "Broche B de l’encodeur", - "description": "Valeur GPIO (1-39) pour le port B de l’encodeur" - }, - "inputbrokerPinPress": { - "label": "Broche de pression de l’encodeur", - "description": "Valeur GPIO (1-39) pour la pression sur l’encodeur" - }, - "inputbrokerEventCw": { - "label": "Événement horaire", - "description": "Sélectionner l’événement d’entrée" - }, - "inputbrokerEventCcw": { - "label": "Événement antihoraire", - "description": "Sélectionner l’événement d’entrée" - }, - "inputbrokerEventPress": { - "label": "Événement pression", - "description": "Sélectionner l’événement d’entrée" - }, - "updown1Enabled": { - "label": "Encodeur haut/bas activé", - "description": "Active l’encodeur haut/bas" - }, - "allowInputSource": { - "label": "Autoriser la source d’entrée", - "description": "Sélectionner parmi : '_any', 'rotEnc1', 'upDownEnc1', 'cardkb'" - }, - "sendBell": { - "label": "Envoyer un bip", - "description": "Envoie un caractère de cloche avec chaque message" - } - }, - "detectionSensor": { - "title": "Paramètres du capteur de détection", - "description": "Paramètres du module de capteur de détection", - "enabled": { - "label": "Activé", - "description": "Activer ou désactiver le module de détection" - }, - "minimumBroadcastSecs": { - "label": "Intervalle minimum d’émission (s)", - "description": "L'intervalle en secondes de la fréquence à laquelle nous pouvons envoyer un message au maillage quand un changement d'état est détecté" - }, - "stateBroadcastSecs": { - "label": "Intervalle d’état (s)", - "description": "Temps entre deux messages d’état envoyés, même sans changement" - }, - "sendBell": { - "label": "Envoyer un bip", - "description": "Envoyer un caractère ASCII 'bell' avec le message d’alerte" - }, - "name": { - "label": "Nom convivial", - "description": "Utilisé pour formater le message envoyé au réseau, max. 20 caractères" - }, - "monitorPin": { - "label": "Broche de monitoring", - "description": "Broche GPIO pour surveiller les changements d'état" - }, - "detectionTriggerType": { - "label": "Type du déclencheur de détection", - "description": "Le type d'événement déclencheur à utiliser" - }, - "usePullup": { - "label": "Utiliser Pullup", - "description": "Utiliser ou non le mode INPUT_PULLUP pour la broche GPIO" - } - }, - "externalNotification": { - "title": "Paramètres de la notification extérieure", - "description": "Configurer le module de notification externe", - "enabled": { - "label": "Module activé", - "description": "Activer les notifications externes" - }, - "outputMs": { - "label": "Sortie MS", - "description": "Sortie MS" - }, - "output": { - "label": "Sortie", - "description": "Sortie" - }, - "outputVibra": { - "label": "Sortie vibreur", - "description": "Sortie vibreur" - }, - "outputBuzzer": { - "label": "Sortie buzzer", - "description": "Sortie buzzer" - }, - "active": { - "label": "Actif", - "description": "Actif" - }, - "alertMessage": { - "label": "Message d'alerte", - "description": "Message d'alerte" - }, - "alertMessageVibra": { - "label": "Message d'alerte vibreur", - "description": "Message d'alerte vibreur" - }, - "alertMessageBuzzer": { - "label": "Message d'alerte buzzer", - "description": "Message d'alerte buzzer" - }, - "alertBell": { - "label": "Bip d'alerte", - "description": "Une alerte doit-elle être déclenchée lors de la réception d'un bip entrant ?" - }, - "alertBellVibra": { - "label": "Bip d'alerte vibreur", - "description": "Bip d'alerte vibreur" - }, - "alertBellBuzzer": { - "label": "Bip d'alerte buzzer", - "description": "Bip d'alerte buzzer" - }, - "usePwm": { - "label": "Utiliser PWM", - "description": "Utiliser PWM" - }, - "nagTimeout": { - "label": "Délai d'expiration du message", - "description": "Délai d'expiration du message" - }, - "useI2sAsBuzzer": { - "label": "Utiliser la broche I2S comme Buzzer", - "description": "Désigner la broche I2S comme sortie Buzzer" - } - }, - "mqtt": { - "title": "Paramètres MQTT", - "description": "Paramètres du module MQTT", - "enabled": { - "label": "Activé", - "description": "Activer ou désactiver MQTT" - }, - "address": { - "label": "Adresse du serveur MQTT", - "description": "Adresse du serveur MQTT à utiliser pour les serveurs par défaut/personnalisés" - }, - "username": { - "label": "Nom d'utilisateur MQTT", - "description": "Nom d'utilisateur MQTT à utiliser pour les serveurs par défaut/personnalisés" - }, - "password": { - "label": "Mot de passe MQTT", - "description": "Mot de passe MQTT à utiliser pour les serveurs par défaut/personnalisés" - }, - "encryptionEnabled": { - "label": "Chiffrement activé", - "description": "Activer ou désactiver le chiffrement MQTT. Remarque : Tous les messages sont envoyés au broker MQTT non chiffré si cette option n'est pas activée, même si vos canaux uplink ont des clés de chiffrement. Cela inclut les données de position." - }, - "jsonEnabled": { - "label": "JSON activé", - "description": "S'il faut envoyer/consommer des paquets JSON sur MQTT" - }, - "tlsEnabled": { - "label": "TLS activé", - "description": "Activer ou désactiver TLS" - }, - "root": { - "label": "Sujet principal", - "description": "Sujet racine MQTT à utiliser pour les serveurs par défaut/personnalisés" - }, - "proxyToClientEnabled": { - "label": "Proxy client MQTT activé", - "description": "Utilise la connexion réseau pour transmettre les messages MQTT au client." - }, - "mapReportingEnabled": { - "label": "Rapport cartographique activé", - "description": "Votre nœud enverra périodiquement un paquet de rapport de position non chiffré au serveur MQTT configuré. Ce paquet inclut l'identifiant, les noms long et court, la position approximative, le modèle matériel, le rôle, la version du micrologiciel, la région LoRa, le préréglage du modem et le nom du canal principal." - }, - "mapReportSettings": { - "publishIntervalSecs": { - "label": "Intervalles de publication du rapport de carte", - "description": "Intervalle en secondes pour publier les rapports de carte" - }, - "positionPrecision": { - "label": "Position approximative", - "description": "La position partagée sera précise dans cette distance", - "options": { - "metric_km23": "A moins de 23 km", - "metric_km12": "A moins de 12 km", - "metric_km5_8": "A moins de 5.8 km", - "metric_km2_9": "A moins de 2.9 km", - "metric_km1_5": "A moins de 1.5 km", - "metric_m700": "A moins de 700 m", - "metric_m350": "A moins de 350 m", - "metric_m200": "À moins de 200 m", - "metric_m90": "A moins de 90 m", - "metric_m50": "A moins de 50 m", - "imperial_mi15": "À moins de 15 miles", - "imperial_mi7_3": "À moins de 7,3 miles", - "imperial_mi3_6": "À moins de 3,6 miles", - "imperial_mi1_8": "À moins de 1,8 miles", - "imperial_mi0_9": "À moins de 0,9 miles", - "imperial_mi0_5": "À moins de 0,5 miles", - "imperial_mi0_2": "À moins de 0,2 miles", - "imperial_ft600": "À moins de 600 pieds", - "imperial_ft300": "À moins de 300 pieds", - "imperial_ft150": "À moins de 150 pieds" - } - } - } - }, - "neighborInfo": { - "title": "Paramètres des informations du voisinage", - "description": "Paramètres pour le module informations du voisinage", - "enabled": { - "label": "Activé", - "description": "Activer ou désactiver le module informations du voisinage" - }, - "updateInterval": { - "label": "Intervalle de mise à jour", - "description": "Intervalle en secondes de la fréquence à laquelle nous devrions essayer d'envoyer nos informations de Voisinage au maillage" - } - }, - "paxcounter": { - "title": "Paramètres Paxcounter", - "description": "Paramètres du module Paxcounter", - "enabled": { - "label": "Module activé", - "description": "Activer Paxcounter" - }, - "paxcounterUpdateInterval": { - "label": "Intervalle de mise à jour (secondes)", - "description": "Durée d'attente entre l'envoi de paquets paxcounter" - }, - "wifiThreshold": { - "label": "Seuil RSSI WiFi", - "description": "A quel niveau de WiFi RSSI devrait augmenter le compteur. Par défaut, -80." - }, - "bleThreshold": { - "label": "Seuil RSSI BLE", - "description": "A quel niveau de BLE RSSI devrait augmenter le compteur. Par défaut, -80." - } - }, - "rangeTest": { - "title": "Paramètres de test de portée", - "description": "Paramètres du module de test de portée", - "enabled": { - "label": "Module activé", - "description": "Activer le test de portée" - }, - "sender": { - "label": "Intervalle de message", - "description": "Durée d'attente entre l'envoi de paquets de test" - }, - "save": { - "label": "Enregistrer le CSV dans le stockage", - "description": "ESP32 seulement" - } - }, - "serial": { - "title": "Paramètres série", - "description": "Paramètres du module série", - "enabled": { - "label": "Module activé", - "description": "Activer la sortie série" - }, - "echo": { - "label": "Écho", - "description": "Tous les paquets que vous envoyez seront renvoyés vers votre appareil" - }, - "rxd": { - "label": "Broche de réception", - "description": "Réglez la broche GPIO sur la broche RXD que vous avez configurée." - }, - "txd": { - "label": "Broche de transmission", - "description": "Réglez la broche GPIO sur la broche TXD que vous avez configurée." - }, - "baud": { - "label": "Vitesse en bauds", - "description": "Vitesse de transmission série" - }, - "timeout": { - "label": "Délai d'expiration", - "description": "Secondes à attendre avant de considérer votre paquet comme \"fini\"" - }, - "mode": { - "label": "Mode", - "description": "Sélection de mode" - }, - "overrideConsoleSerialPort": { - "label": "Outrepasser le port série de la console", - "description": "Si vous avez un port série connecté à la console, cela va le remplacer." - } - }, - "storeForward": { - "title": "Paramètres de stockage et transfert", - "description": "Paramètres du module stockage et transfert", - "enabled": { - "label": "Module activé", - "description": "Activer stockage et transfert" - }, - "heartbeat": { - "label": "Pulsations activées", - "description": "Activer les pulsations stockage et transfert" - }, - "records": { - "label": "Nombre d'enregistrements", - "description": "Nombre d'enregistrements à stocker" - }, - "historyReturnMax": { - "label": "Limite d’historique renvoyé", - "description": "Nombre maximum d'enregistrements à retourner" - }, - "historyReturnWindow": { - "label": "Fenêtre de retour d’historique", - "description": "Nombre maximum d'enregistrements à retourner" - } - }, - "telemetry": { - "title": "Paramètres de télémétrie", - "description": "Paramètres du module télémétrie", - "deviceUpdateInterval": { - "label": "Métriques de l’appareil", - "description": "Intervalle de mise à jour des métriques de l'appareil (secondes)" - }, - "environmentUpdateInterval": { - "label": "Intervalle de mise à jour des métriques d'environnement (secondes)", - "description": "" - }, - "environmentMeasurementEnabled": { - "label": "Module activé", - "description": "Activer la télémétrie d'environnement" - }, - "environmentScreenEnabled": { - "label": "Affiché à l'écran", - "description": "Afficher le module de télémétrie sur OLED" - }, - "environmentDisplayFahrenheit": { - "label": "Afficher en Fahrenheit", - "description": "Afficher la température en Fahrenheit" - }, - "airQualityEnabled": { - "label": "Qualité de l'air activée", - "description": "Activer la télémétrie de qualité de l'air" - }, - "airQualityInterval": { - "label": "Intervalle de mise à jour de la qualité de l'air", - "description": "Fréquence d'envoi des données de qualité de l'air sur le maillage" - }, - "powerMeasurementEnabled": { - "label": "Mesure de puissance activée", - "description": "Activer la télémétrie de mesure d'énergie" - }, - "powerUpdateInterval": { - "label": "Intervalle de mise à jour de l'alimentation", - "description": "Fréquence d'envoi de données d'alimentation sur le maillage" - }, - "powerScreenEnabled": { - "label": "Écran d'alimentation activé", - "description": "Activer l'écran de télémétrie d'alimentation" - } - } + "page": { + "tabAmbientLighting": "Lumière ambiante", + "tabAudio": "Audio", + "tabCannedMessage": "Message pré-enregistré", + "tabDetectionSensor": "Capteur de détection", + "tabExternalNotification": "Notification externe", + "tabMqtt": "MQTT", + "tabNeighborInfo": "Informations sur les voisins", + "tabPaxcounter": "Paxcounter", + "tabRangeTest": "Test de portée", + "tabSerial": "Série", + "tabStoreAndForward": "Stocker & Relayer", + "tabTelemetry": "Télémetrie (Capteurs)" + }, + "ambientLighting": { + "title": "Paramètres de l’éclairage ambiant", + "description": "Paramètres du module d’éclairage ambiant", + "ledState": { + "label": "État des LED", + "description": "Définit les LED sur allumées ou éteintes" + }, + "current": { + "label": "Actif", + "description": "Définit le courant de sortie des LED. Par défaut : 10" + }, + "red": { + "label": "Rouge", + "description": "Définit le niveau de LED rouge (valeurs 0–255)" + }, + "green": { + "label": "Vert", + "description": "Définit le niveau de LED vert (valeurs 0–255)" + }, + "blue": { + "label": "Bleu", + "description": "Définit le niveau de LED bleu (valeurs 0–255)" + } + }, + "audio": { + "title": "Paramètres audio", + "description": "Paramètres du module audio", + "codec2Enabled": { + "label": "Codec 2 activé", + "description": "Active l'encodage audio Codec 2" + }, + "pttPin": { + "label": "Broche PTT", + "description": "Broche GPIO utilisée pour le PTT" + }, + "bitrate": { + "label": "Débit", + "description": "Débit utilisé pour l’encodage audio" + }, + "i2sWs": { + "label": "i2S WS", + "description": "Broche GPIO utilisée pour i2S WS" + }, + "i2sSd": { + "label": "i2S SD", + "description": "Broche GPIO utilisée pour i2S SD" + }, + "i2sDin": { + "label": "i2S DIN", + "description": "Broche GPIO utilisée pour i2S DIN" + }, + "i2sSck": { + "label": "i2S SCK", + "description": "Broche GPIO utilisée pour i2S SCK" + } + }, + "cannedMessage": { + "title": "Paramètres des messages pré-enregistrés", + "description": "Paramètres du module de messages pré-enregistrés\n", + "moduleEnabled": { + "label": "Module activé", + "description": "Active les messages pré-enregistrés" + }, + "rotary1Enabled": { + "label": "Encodeur rotatif #1 activé", + "description": "Active l’encodeur rotatif" + }, + "inputbrokerPinA": { + "label": "Broche A de l’encodeur", + "description": "Valeur GPIO (1-39) pour le port A de l’encodeur" + }, + "inputbrokerPinB": { + "label": "Broche B de l’encodeur", + "description": "Valeur GPIO (1-39) pour le port B de l’encodeur" + }, + "inputbrokerPinPress": { + "label": "Broche de pression de l’encodeur", + "description": "Valeur GPIO (1-39) pour la pression sur l’encodeur" + }, + "inputbrokerEventCw": { + "label": "Événement horaire", + "description": "Sélectionner l’événement d’entrée" + }, + "inputbrokerEventCcw": { + "label": "Événement antihoraire", + "description": "Sélectionner l’événement d’entrée" + }, + "inputbrokerEventPress": { + "label": "Événement pression", + "description": "Sélectionner l’événement d’entrée" + }, + "updown1Enabled": { + "label": "Encodeur haut/bas activé", + "description": "Active l’encodeur haut/bas" + }, + "allowInputSource": { + "label": "Autoriser la source d’entrée", + "description": "Sélectionner parmi : '_any', 'rotEnc1', 'upDownEnc1', 'cardkb'" + }, + "sendBell": { + "label": "Envoyer un bip", + "description": "Envoie un caractère de cloche avec chaque message" + } + }, + "detectionSensor": { + "title": "Paramètres du capteur de détection", + "description": "Paramètres du module de capteur de détection", + "enabled": { + "label": "Activé", + "description": "Activer ou désactiver le module de détection" + }, + "minimumBroadcastSecs": { + "label": "Intervalle minimum d’émission (s)", + "description": "L'intervalle en secondes de la fréquence à laquelle nous pouvons envoyer un message au maillage quand un changement d'état est détecté" + }, + "stateBroadcastSecs": { + "label": "Intervalle d’état (s)", + "description": "Temps entre deux messages d’état envoyés, même sans changement" + }, + "sendBell": { + "label": "Envoyer un bip", + "description": "Envoyer un caractère ASCII 'bell' avec le message d’alerte" + }, + "name": { + "label": "Nom convivial", + "description": "Utilisé pour formater le message envoyé au réseau, max. 20 caractères" + }, + "monitorPin": { + "label": "Broche de monitoring", + "description": "Broche GPIO pour surveiller les changements d'état" + }, + "detectionTriggerType": { + "label": "Type du déclencheur de détection", + "description": "Le type d'événement déclencheur à utiliser" + }, + "usePullup": { + "label": "Utiliser Pullup", + "description": "Utiliser ou non le mode INPUT_PULLUP pour la broche GPIO" + } + }, + "externalNotification": { + "title": "Paramètres de la notification extérieure", + "description": "Configurer le module de notification externe", + "enabled": { + "label": "Module activé", + "description": "Activer les notifications externes" + }, + "outputMs": { + "label": "Sortie MS", + "description": "Sortie MS" + }, + "output": { + "label": "Sortie", + "description": "Sortie" + }, + "outputVibra": { + "label": "Sortie vibreur", + "description": "Sortie vibreur" + }, + "outputBuzzer": { + "label": "Sortie buzzer", + "description": "Sortie buzzer" + }, + "active": { + "label": "Actif", + "description": "Actif" + }, + "alertMessage": { + "label": "Message d'alerte", + "description": "Message d'alerte" + }, + "alertMessageVibra": { + "label": "Message d'alerte vibreur", + "description": "Message d'alerte vibreur" + }, + "alertMessageBuzzer": { + "label": "Message d'alerte buzzer", + "description": "Message d'alerte buzzer" + }, + "alertBell": { + "label": "Bip d'alerte", + "description": "Une alerte doit-elle être déclenchée lors de la réception d'un bip entrant ?" + }, + "alertBellVibra": { + "label": "Bip d'alerte vibreur", + "description": "Bip d'alerte vibreur" + }, + "alertBellBuzzer": { + "label": "Bip d'alerte buzzer", + "description": "Bip d'alerte buzzer" + }, + "usePwm": { + "label": "Utiliser PWM", + "description": "Utiliser PWM" + }, + "nagTimeout": { + "label": "Délai d'expiration du message", + "description": "Délai d'expiration du message" + }, + "useI2sAsBuzzer": { + "label": "Utiliser la broche I2S comme Buzzer", + "description": "Désigner la broche I2S comme sortie Buzzer" + } + }, + "mqtt": { + "title": "Paramètres MQTT", + "description": "Paramètres du module MQTT", + "enabled": { + "label": "Activé", + "description": "Activer ou désactiver MQTT" + }, + "address": { + "label": "Adresse du serveur MQTT", + "description": "Adresse du serveur MQTT à utiliser pour les serveurs par défaut/personnalisés" + }, + "username": { + "label": "Nom d'utilisateur MQTT", + "description": "Nom d'utilisateur MQTT à utiliser pour les serveurs par défaut/personnalisés" + }, + "password": { + "label": "Mot de passe MQTT", + "description": "Mot de passe MQTT à utiliser pour les serveurs par défaut/personnalisés" + }, + "encryptionEnabled": { + "label": "Chiffrement activé", + "description": "Activer ou désactiver le chiffrement MQTT. Remarque : Tous les messages sont envoyés au broker MQTT non chiffré si cette option n'est pas activée, même si vos canaux uplink ont des clés de chiffrement. Cela inclut les données de position." + }, + "jsonEnabled": { + "label": "JSON activé", + "description": "S'il faut envoyer/consommer des paquets JSON sur MQTT" + }, + "tlsEnabled": { + "label": "TLS activé", + "description": "Activer ou désactiver TLS" + }, + "root": { + "label": "Sujet principal", + "description": "Sujet racine MQTT à utiliser pour les serveurs par défaut/personnalisés" + }, + "proxyToClientEnabled": { + "label": "Proxy client MQTT activé", + "description": "Utilise la connexion réseau pour transmettre les messages MQTT au client." + }, + "mapReportingEnabled": { + "label": "Rapport cartographique activé", + "description": "Votre nœud enverra périodiquement un paquet de rapport de position non chiffré au serveur MQTT configuré. Ce paquet inclut l'identifiant, les noms long et court, la position approximative, le modèle matériel, le rôle, la version du micrologiciel, la région LoRa, le préréglage du modem et le nom du canal principal." + }, + "mapReportSettings": { + "publishIntervalSecs": { + "label": "Intervalles de publication du rapport de carte", + "description": "Intervalle en secondes pour publier les rapports de carte" + }, + "positionPrecision": { + "label": "Position approximative", + "description": "La position partagée sera précise dans cette distance", + "options": { + "metric_km23": "A moins de 23 km", + "metric_km12": "A moins de 12 km", + "metric_km5_8": "A moins de 5.8 km", + "metric_km2_9": "A moins de 2.9 km", + "metric_km1_5": "A moins de 1.5 km", + "metric_m700": "A moins de 700 m", + "metric_m350": "A moins de 350 m", + "metric_m200": "À moins de 200 m", + "metric_m90": "A moins de 90 m", + "metric_m50": "A moins de 50 m", + "imperial_mi15": "À moins de 15 miles", + "imperial_mi7_3": "À moins de 7,3 miles", + "imperial_mi3_6": "À moins de 3,6 miles", + "imperial_mi1_8": "À moins de 1,8 miles", + "imperial_mi0_9": "À moins de 0,9 miles", + "imperial_mi0_5": "À moins de 0,5 miles", + "imperial_mi0_2": "À moins de 0,2 miles", + "imperial_ft600": "À moins de 600 pieds", + "imperial_ft300": "À moins de 300 pieds", + "imperial_ft150": "À moins de 150 pieds" + } + } + } + }, + "neighborInfo": { + "title": "Paramètres des informations du voisinage", + "description": "Paramètres pour le module informations du voisinage", + "enabled": { + "label": "Activé", + "description": "Activer ou désactiver le module informations du voisinage" + }, + "updateInterval": { + "label": "Intervalle de mise à jour", + "description": "Intervalle en secondes de la fréquence à laquelle nous devrions essayer d'envoyer nos informations de Voisinage au maillage" + } + }, + "paxcounter": { + "title": "Paramètres Paxcounter", + "description": "Paramètres du module Paxcounter", + "enabled": { + "label": "Module activé", + "description": "Activer Paxcounter" + }, + "paxcounterUpdateInterval": { + "label": "Intervalle de mise à jour (secondes)", + "description": "Durée d'attente entre l'envoi de paquets paxcounter" + }, + "wifiThreshold": { + "label": "Seuil RSSI WiFi", + "description": "A quel niveau de WiFi RSSI devrait augmenter le compteur. Par défaut, -80." + }, + "bleThreshold": { + "label": "Seuil RSSI BLE", + "description": "A quel niveau de BLE RSSI devrait augmenter le compteur. Par défaut, -80." + } + }, + "rangeTest": { + "title": "Paramètres de test de portée", + "description": "Paramètres du module de test de portée", + "enabled": { + "label": "Module activé", + "description": "Activer le test de portée" + }, + "sender": { + "label": "Intervalle de message", + "description": "Durée d'attente entre l'envoi de paquets de test" + }, + "save": { + "label": "Enregistrer le CSV dans le stockage", + "description": "ESP32 seulement" + } + }, + "serial": { + "title": "Paramètres série", + "description": "Paramètres du module série", + "enabled": { + "label": "Module activé", + "description": "Activer la sortie série" + }, + "echo": { + "label": "Écho", + "description": "Tous les paquets que vous envoyez seront renvoyés vers votre appareil" + }, + "rxd": { + "label": "Broche de réception", + "description": "Réglez la broche GPIO sur la broche RXD que vous avez configurée." + }, + "txd": { + "label": "Broche de transmission", + "description": "Réglez la broche GPIO sur la broche TXD que vous avez configurée." + }, + "baud": { + "label": "Vitesse en bauds", + "description": "Vitesse de transmission série" + }, + "timeout": { + "label": "Délai d'expiration", + "description": "Secondes à attendre avant de considérer votre paquet comme \"fini\"" + }, + "mode": { + "label": "Mode", + "description": "Sélection de mode" + }, + "overrideConsoleSerialPort": { + "label": "Outrepasser le port série de la console", + "description": "Si vous avez un port série connecté à la console, cela va le remplacer." + } + }, + "storeForward": { + "title": "Paramètres de stockage et transfert", + "description": "Paramètres du module stockage et transfert", + "enabled": { + "label": "Module activé", + "description": "Activer stockage et transfert" + }, + "heartbeat": { + "label": "Pulsations activées", + "description": "Activer les pulsations stockage et transfert" + }, + "records": { + "label": "Nombre d'enregistrements", + "description": "Nombre d'enregistrements à stocker" + }, + "historyReturnMax": { + "label": "Limite d’historique renvoyé", + "description": "Nombre maximum d'enregistrements à retourner" + }, + "historyReturnWindow": { + "label": "Fenêtre de retour d'historique", + "description": "Retourner les enregistrements de cette fenêtre de temps (minutes)" + } + }, + "telemetry": { + "title": "Paramètres de télémétrie", + "description": "Paramètres du module télémétrie", + "deviceUpdateInterval": { + "label": "Métriques de l’appareil", + "description": "Intervalle de mise à jour des métriques de l'appareil (secondes)" + }, + "environmentUpdateInterval": { + "label": "Intervalle de mise à jour des métriques d'environnement (secondes)", + "description": "" + }, + "environmentMeasurementEnabled": { + "label": "Module activé", + "description": "Activer la télémétrie d'environnement" + }, + "environmentScreenEnabled": { + "label": "Affiché à l'écran", + "description": "Afficher le module de télémétrie sur OLED" + }, + "environmentDisplayFahrenheit": { + "label": "Afficher en Fahrenheit", + "description": "Afficher la température en Fahrenheit" + }, + "airQualityEnabled": { + "label": "Qualité de l'air activée", + "description": "Activer la télémétrie de qualité de l'air" + }, + "airQualityInterval": { + "label": "Intervalle de mise à jour de la qualité de l'air", + "description": "Fréquence d'envoi des données de qualité de l'air sur le maillage" + }, + "powerMeasurementEnabled": { + "label": "Mesure de puissance activée", + "description": "Activer la télémétrie de mesure d'énergie" + }, + "powerUpdateInterval": { + "label": "Intervalle de mise à jour de l'alimentation", + "description": "Fréquence d'envoi de données d'alimentation sur le maillage" + }, + "powerScreenEnabled": { + "label": "Écran d'alimentation activé", + "description": "Activer l'écran de télémétrie d'alimentation" + } + } } diff --git a/packages/web/public/i18n/locales/fr-FR/nodes.json b/packages/web/public/i18n/locales/fr-FR/nodes.json index 604aec64a..f8b2e3806 100644 --- a/packages/web/public/i18n/locales/fr-FR/nodes.json +++ b/packages/web/public/i18n/locales/fr-FR/nodes.json @@ -1,63 +1,59 @@ { - "nodeDetail": { - "publicKeyEnabled": { - "label": "Clé publique activée" - }, - "noPublicKey": { - "label": "Aucune clé publique" - }, - "directMessage": { - "label": "Message direct à {{shortName}}" - }, - "favorite": { - "label": "Favoris", - "tooltip": "Ajouter ou retirer ce nœud de vos favoris" - }, - "notFavorite": { - "label": "Non favori" - }, - "error": { - "label": "Erreur", - "text": "Une erreur est survenue lors du chargement des détails du nœud. Veuillez réessayer." - }, - "status": { - "heard": "Capté", - "mqtt": "MQTT" - }, - "elevation": { - "label": "Altitude" - }, - "channelUtil": { - "label": "Utilisation du canal" - }, - "airtimeUtil": { - "label": "Utilisation du temps d’antenne" - } - }, - "nodesTable": { - "headings": { - "longName": "Nom long", - "connection": "Connexion", - "lastHeard": "Dernière écoute", - "encryption": "Chiffrement", - "model": "Modèle", - "macAddress": "Adresse MAC" - }, - "connectionStatus": { - "direct": "Direk", - "away": "distant", - "unknown": "-", - "viaMqtt": ", via MQTT" - }, - "lastHeardStatus": { - "never": "Jamais" - } - }, - "actions": { - "added": "Ajouté", - "removed": "Supprimé", - "ignoreNode": "Ignorer le nœud", - "unignoreNode": "Ne plus ignorer le nœud", - "requestPosition": "Demander la position" - } + "nodeDetail": { + "publicKeyEnabled": { + "label": "Clé publique activée" + }, + "noPublicKey": { + "label": "Aucune clé publique" + }, + "directMessage": { + "label": "Message direct à {{shortName}}" + }, + "favorite": { + "label": "Favoris", + "tooltip": "Ajouter ou retirer ce nœud de vos favoris" + }, + "notFavorite": { + "label": "Non favori" + }, + "error": { + "label": "Erreur", + "text": "Une erreur est survenue lors du chargement des détails du nœud. Veuillez réessayer." + }, + "status": { + "heard": "Capté", + "mqtt": "MQTT" + }, + "elevation": { + "label": "Altitude" + }, + "channelUtil": { + "label": "Utilisation du canal" + }, + "airtimeUtil": { + "label": "Utilisation du temps d’antenne" + } + }, + "nodesTable": { + "headings": { + "longName": "Nom long", + "connection": "Connexion", + "lastHeard": "Dernière écoute", + "encryption": "Chiffrement", + "model": "Modèle", + "macAddress": "Adresse MAC" + }, + "connectionStatus": { + "direct": "Direk", + "away": "distant", + "viaMqtt": ", via MQTT" + } + }, + "actions": { + "added": "Ajouté", + "removed": "Supprimé", + "ignoreNode": "Ignorer le nœud", + "unignoreNode": "Ne plus ignorer le nœud", + "requestPosition": "Demander la position" + } } diff --git a/packages/web/public/i18n/locales/fr-FR/ui.json b/packages/web/public/i18n/locales/fr-FR/ui.json index 5b5f99c44..4d6f16225 100644 --- a/packages/web/public/i18n/locales/fr-FR/ui.json +++ b/packages/web/public/i18n/locales/fr-FR/ui.json @@ -1,228 +1,230 @@ { - "navigation": { - "title": "Navigation", - "messages": "Messages", - "map": "Carte", - "config": "Configuration", - "radioConfig": "Configuration radio", - "moduleConfig": "Configuration du module", - "channels": "Canaux", - "nodes": "Noeuds" - }, - "app": { - "title": "Meshtastic", - "logo": "Logo Meshtastic" - }, - "sidebar": { - "collapseToggle": { - "button": { - "open": "Ouvrir la barre latérale", - "close": "Fermer la barre latérale" - } - }, - "deviceInfo": { - "volts": "{{voltage}} volts", - "firmware": { - "title": "Micrologiciel", - "version": "v{{version}}", - "buildDate": "Date de compilation : {{date}}" - }, - "deviceName": { - "title": "Nom de l'appareil", - "changeName": "Changer le nom de l'appareil", - "placeholder": "Saisissez le nom de l'appareil" - }, - "editDeviceName": "Éditer le nom de l'appareil" - } - }, - "batteryStatus": { - "charging": "{{level}}% en charge", - "pluggedIn": "Branché", - "title": "Batterie" - }, - "search": { - "nodes": "Recherche de nœuds...", - "channels": "Rechercher des canaux...", - "commandPalette": "Rechercher des commandes..." - }, - "toast": { - "positionRequestSent": { - "title": "Requête de position envoyée." - }, - "requestingPosition": { - "title": "Requête de position en cours, veuillez patienter..." - }, - "sendingTraceroute": { - "title": "Envoi du traceroute en cours, veuillez patienter..." - }, - "tracerouteSent": { - "title": "Traceroute envoyé." - }, - "savedChannel": { - "title": "Canal enregistré : {{channelName}}" - }, - "messages": { - "pkiEncryption": { - "title": "La discussion utilise un chiffrement PKI." - }, - "pskEncryption": { - "title": "La discussion utilise un chiffrement PSK." - } - }, - "configSaveError": { - "title": "Erreur lors de l’enregistrement", - "description": "Une erreur est survenue lors de l’enregistrement de la configuration." - }, - "validationError": { - "title": "Des erreurs de configuration existent", - "description": "Veuillez corriger les erreurs de configuration avant d’enregistrer." - }, - "saveSuccess": { - "title": "Configuration enregistrée", - "description": "Le changement de configuration {{case}} a été enregistré." - }, - "favoriteNode": { - "title": "{{action}} {{nodeName}} {{direction}} des favoris.", - "action": { - "added": "Ajouté", - "removed": "Supprimé", - "to": "à", - "from": "de" - } - }, - "ignoreNode": { - "title": "{{action}} {{nodeName}} {{direction}} de la liste d’ignorés", - "action": { - "added": "Ajouté", - "removed": "Supprimé", - "to": "à", - "from": "de" - } - } - }, - "notifications": { - "copied": { - "label": "Copié !" - }, - "copyToClipboard": { - "label": "Copier dans le presse-papiers" - }, - "hidePassword": { - "label": "Masquer le mot de passe" - }, - "showPassword": { - "label": "Afficher le mot de passe" - }, - "deliveryStatus": { - "delivered": "Distribué", - "failed": "Échec de l'envoi", - "waiting": "En attente . . .", - "unknown": "Inconnu" - } - }, - "general": { - "label": "Général" - }, - "hardware": { - "label": "Matériel" - }, - "metrics": { - "label": "Métriques" - }, - "role": { - "label": "Rôle" - }, - "filter": { - "label": "Filtre" - }, - "advanced": { - "label": "Avancé" - }, - "clearInput": { - "label": "Effacer la saisie" - }, - "resetFilters": { - "label": "Réinitialiser les filtres" - }, - "nodeName": { - "label": "Nom/numéro de nœud", - "placeholder": "Meshtastic 1234" - }, - "airtimeUtilization": { - "label": "Utilisation du temps d’antenne (%)" - }, - "batteryLevel": { - "label": "Niveau de batterie (%)", - "labelText": "Niveau de batterie (%) : {{value}}" - }, - "batteryVoltage": { - "label": "Tension de batterie (V)", - "title": "Tension" - }, - "channelUtilization": { - "label": "Utilisation du canal (%)" - }, - "hops": { - "direct": "Direk", - "label": "Nombre de sauts", - "text": "Nombre de sauts : {{value}}" - }, - "lastHeard": { - "label": "Dernière écoute", - "labelText": "Dernier signal reçu : {{value}}", - "nowLabel": "Maintenant" - }, - "snr": { - "label": "SNR (db)" - }, - "favorites": { - "label": "Favoris" - }, - "hide": { - "label": "Masquer" - }, - "showOnly": { - "label": "Montrer seulement" - }, - "viaMqtt": { - "label": "Connecté via MQTT" - }, - "hopsUnknown": { - "label": "Nombre de sauts inconnu" - }, - "showUnheard": { - "label": "Jamais entendu" - }, - "language": { - "label": "Langue", - "changeLanguage": "Changer la langue" - }, - "theme": { - "dark": "Sombre", - "light": "Clair", - "system": "Automatique", - "changeTheme": "Changer le schéma de couleurs" - }, - "errorPage": { - "title": "C'est un peu embarrassant...", - "description1": "Nous sommes vraiment désolés mais une erreur est survenue dans le client web qui l'a fait planter.
Ce n'est pas censé se produire, et nous travaillons dur pour le corriger.", - "description2": "La meilleure façon d'éviter que cela ne se reproduise à vous ou à qui que ce soit d'autre consiste à nous signaler le problème.", - "reportInstructions": "Veuillez inclure les informations suivantes dans votre rapport :", - "reportSteps": { - "step1": "Ce que vous faisiez lorsque l'erreur s'est produite", - "step2": "Ce que vous vous attendiez à se produire", - "step3": "Ce qui s'est réellement passé", - "step4": "Toute autre information pertinente" - }, - "reportLink": "Vous pouvez signaler le problème à notre <0>GitHub", - "dashboardLink": "Retourner au <0>tableau de bord", - "detailsSummary": "Détails de l'erreur", - "errorMessageLabel": "Message d'erreur :", - "stackTraceLabel": "État de la pile :", - "fallbackError": "{{error}}" - }, - "footer": { - "text": "Propulsé par <0>▲ Vercel | Meshtastic® est une marque déposée de Meshtastic LLC. | <1>Informations légales", - "commitSha": "SHA : {{sha}}" - } + "navigation": { + "title": "Navigation", + "messages": "Messages", + "map": "Carte", + "settings": "Réglages", + "channels": "Canaux", + "radioConfig": "Configuration radio", + "deviceConfig": "Configuration de l'appareil", + "moduleConfig": "Configuration du module", + "manageConnections": "Manage Connections", + "nodes": "Noeuds" + }, + "app": { + "title": "Meshtastic", + "logo": "Logo Meshtastic" + }, + "sidebar": { + "collapseToggle": { + "button": { + "open": "Ouvrir la barre latérale", + "close": "Fermer la barre latérale" + } + }, + "deviceInfo": { + "volts": "{{voltage}} volts", + "firmware": { + "title": "Micrologiciel", + "version": "v{{version}}", + "buildDate": "Date de compilation : {{date}}" + } + } + }, + "batteryStatus": { + "charging": "{{level}}% en charge", + "pluggedIn": "Branché", + "title": "Batterie" + }, + "search": { + "nodes": "Recherche de nœuds...", + "channels": "Rechercher des canaux...", + "commandPalette": "Rechercher des commandes..." + }, + "toast": { + "positionRequestSent": { + "title": "Requête de position envoyée." + }, + "requestingPosition": { + "title": "Requête de position en cours, veuillez patienter..." + }, + "sendingTraceroute": { + "title": "Envoi du traceroute en cours, veuillez patienter..." + }, + "tracerouteSent": { + "title": "Traceroute envoyé." + }, + "savedChannel": { + "title": "Canal enregistré : {{channelName}}" + }, + "messages": { + "pkiEncryption": { + "title": "La discussion utilise un chiffrement PKI." + }, + "pskEncryption": { + "title": "La discussion utilise un chiffrement PSK." + } + }, + "configSaveError": { + "title": "Erreur lors de l’enregistrement", + "description": "Une erreur est survenue lors de l’enregistrement de la configuration." + }, + "validationError": { + "title": "Des erreurs de configuration existent", + "description": "Veuillez corriger les erreurs de configuration avant d’enregistrer." + }, + "saveSuccess": { + "title": "Configuration enregistrée", + "description": "Le changement de configuration {{case}} a été enregistré." + }, + "saveAllSuccess": { + "title": "Saved", + "description": "All configuration changes have been saved." + }, + "favoriteNode": { + "title": "{{action}} {{nodeName}} {{direction}} des favoris.", + "action": { + "added": "Ajouté", + "removed": "Supprimé", + "to": "à", + "from": "de" + } + }, + "ignoreNode": { + "title": "{{action}} {{nodeName}} {{direction}} de la liste d’ignorés", + "action": { + "added": "Ajouté", + "removed": "Supprimé", + "to": "à", + "from": "de" + } + } + }, + "notifications": { + "copied": { + "label": "Copié !" + }, + "copyToClipboard": { + "label": "Copier dans le presse-papiers" + }, + "hidePassword": { + "label": "Masquer le mot de passe" + }, + "showPassword": { + "label": "Afficher le mot de passe" + }, + "deliveryStatus": { + "delivered": "Distribué", + "failed": "Échec de l'envoi", + "waiting": "En attente . . .", + "unknown": "Inconnu" + } + }, + "general": { + "label": "Général" + }, + "hardware": { + "label": "Matériel" + }, + "metrics": { + "label": "Métriques" + }, + "role": { + "label": "Rôle" + }, + "filter": { + "label": "Filtre" + }, + "advanced": { + "label": "Avancé" + }, + "clearInput": { + "label": "Effacer la saisie" + }, + "resetFilters": { + "label": "Réinitialiser les filtres" + }, + "nodeName": { + "label": "Nom/numéro de nœud", + "placeholder": "Meshtastic 1234" + }, + "airtimeUtilization": { + "label": "Utilisation du temps d’antenne (%)", + "short": "Airtime Util. (%)" + }, + "batteryLevel": { + "label": "Niveau de batterie (%)", + "labelText": "Niveau de batterie (%) : {{value}}" + }, + "batteryVoltage": { + "label": "Tension de batterie (V)", + "title": "Tension" + }, + "channelUtilization": { + "label": "Utilisation du canal (%)", + "short": "Channel Util. (%)" + }, + "hops": { + "direct": "Direk", + "label": "Nombre de sauts", + "text": "Nombre de sauts : {{value}}" + }, + "lastHeard": { + "label": "Dernière écoute", + "labelText": "Dernier signal reçu : {{value}}", + "nowLabel": "Maintenant" + }, + "snr": { + "label": "SNR (db)" + }, + "favorites": { + "label": "Favoris" + }, + "hide": { + "label": "Masquer" + }, + "showOnly": { + "label": "Montrer seulement" + }, + "viaMqtt": { + "label": "Connecté via MQTT" + }, + "hopsUnknown": { + "label": "Nombre de sauts inconnu" + }, + "showUnheard": { + "label": "Jamais entendu" + }, + "language": { + "label": "Langue", + "changeLanguage": "Changer la langue" + }, + "theme": { + "dark": "Sombre", + "light": "Clair", + "system": "Automatique", + "changeTheme": "Changer le schéma de couleurs" + }, + "errorPage": { + "title": "C'est un peu embarrassant...", + "description1": "Nous sommes vraiment désolés mais une erreur est survenue dans le client web qui l'a fait planter.
Ce n'est pas censé se produire, et nous travaillons dur pour le corriger.", + "description2": "La meilleure façon d'éviter que cela ne se reproduise à vous ou à qui que ce soit d'autre consiste à nous signaler le problème.", + "reportInstructions": "Veuillez inclure les informations suivantes dans votre rapport :", + "reportSteps": { + "step1": "Ce que vous faisiez lorsque l'erreur s'est produite", + "step2": "Ce que vous vous attendiez à se produire", + "step3": "Ce qui s'est réellement passé", + "step4": "Toute autre information pertinente" + }, + "reportLink": "Vous pouvez signaler le problème à notre <0>GitHub", + "connectionsLink": "Return to the <0>connections", + "detailsSummary": "Détails de l'erreur", + "errorMessageLabel": "Message d'erreur :", + "stackTraceLabel": "État de la pile :", + "fallbackError": "{{error}}" + }, + "footer": { + "text": "Propulsé par <0>▲ Vercel | Meshtastic® est une marque déposée de Meshtastic LLC. | <1>Informations légales", + "commitSha": "SHA : {{sha}}" + } } diff --git a/packages/web/public/i18n/locales/hu-HU/channels.json b/packages/web/public/i18n/locales/hu-HU/channels.json index 37ec6deff..7144a0d55 100644 --- a/packages/web/public/i18n/locales/hu-HU/channels.json +++ b/packages/web/public/i18n/locales/hu-HU/channels.json @@ -1,69 +1,71 @@ { - "page": { - "sectionLabel": "Csatornák", - "channelName": "Csatorna: {{channelName}}", - "broadcastLabel": "Elsődleges", - "channelIndex": "Csat. {{index}}" - }, - "validation": { - "pskInvalid": "Adj meg egy érvényes {{bits}} bites PSK-t." - }, - "settings": { - "label": "Csatorna beállítások", - "description": "Titkosítás, MQTT és egyéb beállítások" - }, - "role": { - "label": "Szerepkör", - "description": "Az eszköz telemetriája az ELSŐDLEGES (PRIMARY) csatornán keresztül küldhető. Csak egy ELSŐDLEGES engedélyezett", - "options": { - "primary": "ELSŐDLEGES", - "disabled": "LETILTOTT", - "secondary": "MÁSODLAGOS" - } - }, - "psk": { - "label": "Előre megosztott kulcs (PSK)", - "description": "Támogatott PSK hossz: 256 bit, 128 bit, 8 bit, üres (0 bit)", - "generate": "Generálás" - }, - "name": { - "label": "Név", - "description": "Egyedi csatornanév (<12 bájt); hagyd üresen az alapértelmezett névhez" - }, - "uplinkEnabled": { - "label": "Feltöltés engedélyezve", - "description": "Üzenetek küldése a helyi mesh hálózatból az MQTT felé" - }, - "downlinkEnabled": { - "label": "Letöltés engedélyezve", - "description": "Üzenetek fogadása az MQTT-ről a helyi mesh hálózatba" - }, - "positionPrecision": { - "label": "Helyzet", - "description": "A csatornával megosztott helyzet pontossága. Kikapcsolható.", - "options": { - "none": "Helyzet megosztásának letiltása", - "precise": "Pontos helyzet", - "metric_km23": "23 kilométeren belül", - "metric_km12": "12 kilométeren belül", - "metric_km5_8": "5.8 kilométeren belül", - "metric_km2_9": "2.9 kilométeren belül", - "metric_km1_5": "1.5 kilométeren belül", - "metric_m700": "700 méteren belül", - "metric_m350": "350 méteren belül", - "metric_m200": "200 méteren belül", - "metric_m90": "90 méteren belül", - "metric_m50": "50 méteren belül", - "imperial_mi15": "15 mérföldön belül", - "imperial_mi7_3": "7.3 mérföldön belül", - "imperial_mi3_6": "3.6 mérföldön belül", - "imperial_mi1_8": "1.8 mérföldön belül", - "imperial_mi0_9": "0.9 mérföldön belül", - "imperial_mi0_5": "0.5 mérföldön belül", - "imperial_mi0_2": "0.2 mérföldön belül", - "imperial_ft600": "600 lábon belül", - "imperial_ft300": "300 lábon belül", - "imperial_ft150": "150 lábon belül" - } - } + "page": { + "sectionLabel": "Csatornák", + "channelName": "Csatorna: {{channelName}}", + "broadcastLabel": "Elsődleges", + "channelIndex": "Csat. {{index}}", + "import": "Importálás", + "export": "Exportálás" + }, + "validation": { + "pskInvalid": "Adj meg egy érvényes {{bits}} bites PSK-t." + }, + "settings": { + "label": "Csatorna beállítások", + "description": "Titkosítás, MQTT és egyéb beállítások" + }, + "role": { + "label": "Szerepkör", + "description": "Az eszköz telemetriája az ELSŐDLEGES (PRIMARY) csatornán keresztül küldhető. Csak egy ELSŐDLEGES engedélyezett", + "options": { + "primary": "ELSŐDLEGES", + "disabled": "LETILTOTT", + "secondary": "MÁSODLAGOS" + } + }, + "psk": { + "label": "Előre megosztott kulcs (PSK)", + "description": "Támogatott PSK hossz: 256 bit, 128 bit, 8 bit, üres (0 bit)", + "generate": "Generálás" + }, + "name": { + "label": "Név", + "description": "Egyedi csatornanév (<12 bájt); hagyd üresen az alapértelmezett névhez" + }, + "uplinkEnabled": { + "label": "Feltöltés engedélyezve", + "description": "Üzenetek küldése a helyi mesh hálózatból az MQTT felé" + }, + "downlinkEnabled": { + "label": "Letöltés engedélyezve", + "description": "Üzenetek fogadása az MQTT-ről a helyi mesh hálózatba" + }, + "positionPrecision": { + "label": "Helyzet", + "description": "A csatornával megosztott helyzet pontossága. Kikapcsolható.", + "options": { + "none": "Helyzet megosztásának letiltása", + "precise": "Pontos helyzet", + "metric_km23": "23 kilométeren belül", + "metric_km12": "12 kilométeren belül", + "metric_km5_8": "5.8 kilométeren belül", + "metric_km2_9": "2.9 kilométeren belül", + "metric_km1_5": "1.5 kilométeren belül", + "metric_m700": "700 méteren belül", + "metric_m350": "350 méteren belül", + "metric_m200": "200 méteren belül", + "metric_m90": "90 méteren belül", + "metric_m50": "50 méteren belül", + "imperial_mi15": "15 mérföldön belül", + "imperial_mi7_3": "7.3 mérföldön belül", + "imperial_mi3_6": "3.6 mérföldön belül", + "imperial_mi1_8": "1.8 mérföldön belül", + "imperial_mi0_9": "0.9 mérföldön belül", + "imperial_mi0_5": "0.5 mérföldön belül", + "imperial_mi0_2": "0.2 mérföldön belül", + "imperial_ft600": "600 lábon belül", + "imperial_ft300": "300 lábon belül", + "imperial_ft150": "150 lábon belül" + } + } } diff --git a/packages/web/public/i18n/locales/hu-HU/commandPalette.json b/packages/web/public/i18n/locales/hu-HU/commandPalette.json index 57b5c8759..672ca36f9 100644 --- a/packages/web/public/i18n/locales/hu-HU/commandPalette.json +++ b/packages/web/public/i18n/locales/hu-HU/commandPalette.json @@ -1,51 +1,51 @@ { - "emptyState": "No results found.", + "emptyState": "Nincs találat.", "page": { - "title": "Command Menu" + "title": "Parancsmenü" }, "pinGroup": { - "label": "Pin command group" + "label": "Parancscsoport rögzítése" }, "unpinGroup": { - "label": "Unpin command group" + "label": "Parancscsoport feloldása" }, "goto": { - "label": "Goto", + "label": "Ugrás", "command": { "messages": "Üzenetek", "map": "Térkép", - "config": "Config", - "channels": "Csatornák", + "config": "Konfiguráció", "nodes": "Csomópontok" } }, "manage": { - "label": "Manage", + "label": "Kezelés", "command": { - "switchNode": "Switch Node", - "connectNewNode": "Connect New Node" + "switchNode": "Csomópont váltása", + "connectNewNode": "Új csomópont csatlakoztatása" } }, "contextual": { - "label": "Contextual", + "label": "Kontextusos", "command": { - "qrCode": "QR Code", - "qrGenerator": "Generator", + "qrCode": "QR-kód", + "qrGenerator": "Generátor", "qrImport": "Importálás", - "scheduleShutdown": "Schedule Shutdown", - "scheduleReboot": "Reboot Device", - "resetNodeDb": "Reset Node DB", - "dfuMode": "Enter DFU Mode", - "factoryResetDevice": "Factory Reset Device", - "factoryResetConfig": "Factory Reset Config", + "scheduleShutdown": "Leállítás ütemezése", + "scheduleReboot": "Eszköz újraindítása", + "resetNodeDb": "Csomópont-adatbázis visszaállítása", + "dfuMode": "DFU módba lépés", + "factoryResetDevice": "Gyári visszaállítás (eszköz)", + "factoryResetConfig": "Gyári visszaállítás (konfiguráció)", "disconnect": "Leválasztás" } }, "debug": { - "label": "Debug", + "label": "Hibakeresés", "command": { - "reconfigure": "Reconfigure", - "clearAllStoredMessages": "Clear All Stored Message" + "reconfigure": "Újrakonfigurálás", + "clearAllStoredMessages": "Összes tárolt üzenet törlése", + "clearAllStores": "Összes helyi tár törlése" } } } diff --git a/packages/web/public/i18n/locales/hu-HU/common.json b/packages/web/public/i18n/locales/hu-HU/common.json index a8adfc29a..c4c217312 100644 --- a/packages/web/public/i18n/locales/hu-HU/common.json +++ b/packages/web/public/i18n/locales/hu-HU/common.json @@ -1,142 +1,165 @@ { - "button": { - "apply": "Alkalmaz", - "backupKey": "Backup Key", - "cancel": "Megszakítani", - "clearMessages": "Clear Messages", - "close": "Bezárás", - "confirm": "Megerősítés", - "delete": "Törlés", - "dismiss": "Bezárás", - "download": "Letöltés", - "export": "Exportálás", - "generate": "Generálás", - "regenerate": "Újragenerálás", - "import": "Importálás", - "message": "Üzenet", - "now": "Most", - "ok": "OK", - "print": "Print", - "remove": "Törlés", - "requestNewKeys": "Request New Keys", - "requestPosition": "Pozíció kérése", - "reset": "Újraindítás", - "save": "Mentés", - "scanQr": "QR-kód beolvasása", - "traceRoute": "Trace Route", - "submit": "Mentés" - }, - "app": { - "title": "Meshtastic", - "fullTitle": "Meshtastic Web Kliens" - }, - "loading": "Töltés...", - "unit": { - "cps": "CPS", - "dbm": "dBm", - "hertz": "Hz", - "hop": { - "one": "Ugrás", - "plural": "Ugrások" - }, - "hopsAway": { - "one": "{{count}} hop away", - "plural": "{{count}} hops away", - "unknown": "Unknown hops away" - }, - "megahertz": "MHz", - "raw": "nyers", - "meter": { - "one": "Méter", - "plural": "Méter", - "suffix": "m" - }, - "minute": { - "one": "Perc", - "plural": "Percek" - }, - "hour": { - "one": "Óra", - "plural": "Hours" - }, - "millisecond": { - "one": "Millisecond", - "plural": "Milliseconds", - "suffix": "ms" - }, - "second": { - "one": "Másodperc", - "plural": "Másodpercek" - }, - "day": { - "one": "Nap", - "plural": "Napok" - }, - "month": { - "one": "Hónap", - "plural": "Hónapok" - }, - "year": { - "one": "Év", - "plural": "Évek" - }, - "snr": "SNR", - "volt": { - "one": "Volt", - "plural": "Volts", - "suffix": "V" - }, - "record": { - "one": "Bejegyzések", - "plural": "Bejegyzések" - } - }, - "security": { - "0bit": "Üres", - "8bit": "8 bit", - "128bit": "128 bit", - "256bit": "256 bit" - }, - "unknown": { - "longName": "Ismeretlen", - "shortName": "UNK", - "notAvailable": "Nincs adat", - "num": "??" - }, - "nodeUnknownPrefix": "!", - "unset": "NEM BEÁLLÍTOTT", - "fallbackName": "Meshtastic {{last4}}", - "node": "Csomópont", - "formValidation": { - "unsavedChanges": "Nem mentett módosítások", - "tooBig": { - "string": "Too long, expected less than or equal to {{maximum}} characters.", - "number": "Too big, expected a number smaller than or equal to {{maximum}}.", - "bytes": "Too big, expected less than or equal to {{params.maximum}} bytes." - }, - "tooSmall": { - "string": "Too short, expected more than or equal to {{minimum}} characters.", - "number": "Too small, expected a number larger than or equal to {{minimum}}." - }, - "invalidFormat": { - "ipv4": "Invalid format, expected an IPv4 address.", - "key": "Invalid format, expected a Base64 encoded pre-shared key (PSK)." - }, - "invalidType": { - "number": "Invalid type, expected a number." - }, - "pskLength": { - "0bit": "Key is required to be empty.", - "8bit": "Key is required to be an 8 bit pre-shared key (PSK).", - "128bit": "Key is required to be a 128 bit pre-shared key (PSK).", - "256bit": "Key is required to be a 256 bit pre-shared key (PSK)." - }, - "required": { - "generic": "A mező kitöltése kötelező.", - "managed": "At least one admin key is requred if the node is managed.", - "key": "Kulcs megadása kötelező." - } - }, - "yes": "Igen", - "no": "Nem" + "button": { + "apply": "Alkalmaz", + "addConnection": "Add Connection", + "saveConnection": "Save connection", + "backupKey": "Kulcs biztonsági mentése", + "cancel": "Megszakítani", + "connect": "Csatlakozás", + "clearMessages": "Üzenetek törlése", + "close": "Bezárás", + "confirm": "Megerősítés", + "delete": "Törlés", + "dismiss": "Bezárás", + "download": "Letöltés", + "disconnect": "Leválasztás", + "export": "Exportálás", + "generate": "Generálás", + "regenerate": "Újragenerálás", + "import": "Importálás", + "message": "Üzenet", + "now": "Most", + "ok": "OK", + "print": "Nyomtatás", + "remove": "Törlés", + "requestNewKeys": "Új kulcsok kérése", + "requestPosition": "Pozíció kérése", + "reset": "Újraindítás", + "retry": "Retry", + "save": "Mentés", + "setDefault": "Set as default", + "unsetDefault": "Unset default", + "scanQr": "QR-kód beolvasása", + "traceRoute": "Traceroute", + "submit": "Mentés" + }, + "app": { + "title": "Meshtastic", + "fullTitle": "Meshtastic Web Kliens" + }, + "loading": "Töltés...", + "unit": { + "cps": "CPS", + "dbm": "dBm", + "hertz": "Hz", + "hop": { + "one": "Ugrás", + "plural": "Ugrások" + }, + "hopsAway": { + "one": "{{count}} ugrásnyira", + "plural": "{{count}} ugrásnyira", + "unknown": "Ismeretlen ugrásszám távolság" + }, + "megahertz": "MHz", + "kilohertz": "kHz", + "raw": "nyers", + "meter": { + "one": "Méter", + "plural": "Méter", + "suffix": "m" + }, + "kilometer": { + "one": "Kilométer", + "plural": "Kilométerek", + "suffix": "km" + }, + "minute": { + "one": "Perc", + "plural": "Percek" + }, + "hour": { + "one": "Óra", + "plural": "Óra" + }, + "millisecond": { + "one": "Milliszekundum", + "plural": "Milliszekundumok", + "suffix": "ms" + }, + "second": { + "one": "Másodperc", + "plural": "Másodpercek" + }, + "day": { + "one": "Nap", + "plural": "Napok", + "today": "Ma", + "yesterday": "Tegnap" + }, + "month": { + "one": "Hónap", + "plural": "Hónapok" + }, + "year": { + "one": "Év", + "plural": "Évek" + }, + "snr": "SNR", + "volt": { + "one": "Volt", + "plural": "Volt", + "suffix": "V" + }, + "record": { + "one": "Bejegyzések", + "plural": "Bejegyzések" + }, + "degree": { + "one": "Fok", + "plural": "Fok", + "suffix": "°" + } + }, + "security": { + "0bit": "Üres", + "8bit": "8 bit", + "128bit": "128 bit", + "256bit": "256 bit" + }, + "unknown": { + "longName": "Ismeretlen", + "shortName": "UNK", + "notAvailable": "Nincs adat", + "num": "??" + }, + "nodeUnknownPrefix": "!", + "unset": "NEM BEÁLLÍTOTT", + "fallbackName": "Meshtastic {{last4}}", + "node": "Csomópont", + "formValidation": { + "unsavedChanges": "Nem mentett módosítások", + "tooBig": { + "string": "Túl hosszú, legfeljebb {{maximum}} karakter engedélyezett.", + "number": "Túl nagy, legfeljebb {{maximum}} értékű szám engedélyezett.", + "bytes": "Túl nagy, legfeljebb {{params.maximum}} bájt engedélyezett." + }, + "tooSmall": { + "string": "Túl rövid, legalább {{minimum}} karakter szükséges.", + "number": "Túl kicsi, legalább {{minimum}} értékű szám szükséges." + }, + "invalidFormat": { + "ipv4": "Érvénytelen formátum, IPv4-címet várunk.", + "key": "Érvénytelen formátum, Base64-kódolt előre megosztott kulcsot (PSK) várunk." + }, + "invalidType": { + "number": "Érvénytelen típus, számot várunk." + }, + "pskLength": { + "0bit": "A kulcsnak üresnek kell lennie.", + "8bit": "A kulcsnak 8 bites előre megosztott kulcsnak (PSK) kell lennie.", + "128bit": "A kulcsnak 128 bites előre megosztott kulcsnak (PSK) kell lennie.", + "256bit": "A kulcsnak 256 bites előre megosztott kulcsnak (PSK) kell lennie." + }, + "required": { + "generic": "A mező kitöltése kötelező.", + "managed": "Legalább egy admin kulcs szükséges, ha a csomópont kezelt.", + "key": "Kulcs megadása kötelező." + }, + "invalidOverrideFreq": { + "number": "Érvénytelen formátum, 410–930 MHz közötti értéket vagy 0-t (alapértelmezett) várunk." + } + }, + "yes": "Igen", + "no": "Nem" } diff --git a/packages/web/public/i18n/locales/hu-HU/config.json b/packages/web/public/i18n/locales/hu-HU/config.json new file mode 100644 index 000000000..f56fb4f60 --- /dev/null +++ b/packages/web/public/i18n/locales/hu-HU/config.json @@ -0,0 +1,458 @@ +{ + "page": { + "title": "Beállítások", + "tabUser": "Felhasználó", + "tabChannels": "Csatornák", + "tabBluetooth": "Bluetooth", + "tabDevice": "Eszköz", + "tabDisplay": "Kijelző", + "tabLora": "LoRa", + "tabNetwork": "Hálózat", + "tabPosition": "Pozíció", + "tabPower": "Energia", + "tabSecurity": "Biztonság" + }, + "sidebar": { + "label": "Configuration" + }, + "device": { + "title": "Device Settings", + "description": "Settings for the device", + "buttonPin": { + "description": "Button pin override", + "label": "Button Pin" + }, + "buzzerPin": { + "description": "Buzzer pin override", + "label": "Buzzer Pin" + }, + "disableTripleClick": { + "description": "Disable triple click", + "label": "Disable Triple Click" + }, + "doubleTapAsButtonPress": { + "description": "Treat double tap as button press", + "label": "Double Tap as Button Press" + }, + "ledHeartbeatDisabled": { + "description": "Disable default blinking LED", + "label": "LED Heartbeat Disabled" + }, + "nodeInfoBroadcastInterval": { + "description": "How often to broadcast node info", + "label": "Node Info Broadcast Interval" + }, + "posixTimezone": { + "description": "The POSIX timezone string for the device", + "label": "POSIX időzóna" + }, + "rebroadcastMode": { + "description": "How to handle rebroadcasting", + "label": "Rebroadcast Mode" + }, + "role": { + "description": "What role the device performs on the mesh", + "label": "Szerepkör" + } + }, + "bluetooth": { + "title": "Bluetooth Settings", + "description": "Settings for the Bluetooth module", + "note": "Note: Some devices (ESP32) cannot use both Bluetooth and WiFi at the same time.", + "enabled": { + "description": "Enable or disable Bluetooth", + "label": "Enabled" + }, + "pairingMode": { + "description": "Pin selection behaviour.", + "label": "Párosítási mód" + }, + "pin": { + "description": "Pin to use when pairing", + "label": "Pin" + } + }, + "display": { + "description": "Settings for the device display", + "title": "Display Settings", + "headingBold": { + "description": "Bolden the heading text", + "label": "Bold Heading" + }, + "carouselDelay": { + "description": "How fast to cycle through windows", + "label": "Carousel Delay" + }, + "compassNorthTop": { + "description": "Fix north to the top of compass", + "label": "Compass North Top" + }, + "displayMode": { + "description": "Screen layout variant", + "label": "Display Mode" + }, + "displayUnits": { + "description": "Display metric or imperial units", + "label": "Display Units" + }, + "flipScreen": { + "description": "Flip display 180 degrees", + "label": "Flip Screen" + }, + "gpsDisplayUnits": { + "description": "Coordinate display format", + "label": "GPS Display Units" + }, + "oledType": { + "description": "Type of OLED screen attached to the device", + "label": "OLED Type" + }, + "screenTimeout": { + "description": "Turn off the display after this long", + "label": "Screen Timeout" + }, + "twelveHourClock": { + "description": "Use 12-hour clock format", + "label": "12-Hour Clock" + }, + "wakeOnTapOrMotion": { + "description": "Wake the device on tap or motion", + "label": "Wake on Tap or Motion" + } + }, + "lora": { + "title": "Mesh Settings", + "description": "Settings for the LoRa mesh", + "bandwidth": { + "description": "Channel bandwidth in kHz", + "label": "Sávszélesség" + }, + "boostedRxGain": { + "description": "Boosted RX gain", + "label": "Boosted RX Gain" + }, + "codingRate": { + "description": "The denominator of the coding rate", + "label": "Coding Rate" + }, + "frequencyOffset": { + "description": "Frequency offset to correct for crystal calibration errors", + "label": "Frequency Offset" + }, + "frequencySlot": { + "description": "LoRa frequency channel number", + "label": "Frequency Slot" + }, + "hopLimit": { + "description": "Maximum number of hops", + "label": "Hop Limit" + }, + "ignoreMqtt": { + "description": "Don't forward MQTT messages over the mesh", + "label": "MQTT figyelmen kívül hagyása" + }, + "modemPreset": { + "description": "Modem preset to use", + "label": "Modem-előbeállítás" + }, + "okToMqtt": { + "description": "When set to true, this configuration indicates that the user approves the packet to be uploaded to MQTT. If set to false, remote nodes are requested not to forward packets to MQTT", + "label": "MQTT jóváhagyás" + }, + "overrideDutyCycle": { + "description": "Duty Cycle felülbírálása", + "label": "Duty Cycle felülbírálása" + }, + "overrideFrequency": { + "description": "Override frequency", + "label": "Override Frequency" + }, + "region": { + "description": "Sets the region for your node", + "label": "Régió" + }, + "spreadingFactor": { + "description": "Indicates the number of chirps per symbol", + "label": "Spreading Factor" + }, + "transmitEnabled": { + "description": "Enable/Disable transmit (TX) from the LoRa radio", + "label": "Transmit Enabled" + }, + "transmitPower": { + "description": "Max transmit power", + "label": "Transmit Power" + }, + "usePreset": { + "description": "Use one of the predefined modem presets", + "label": "Use Preset" + }, + "meshSettings": { + "description": "Settings for the LoRa mesh", + "label": "Mesh Settings" + }, + "waveformSettings": { + "description": "Settings for the LoRa waveform", + "label": "Waveform Settings" + }, + "radioSettings": { + "label": "Radio Settings", + "description": "Settings for the LoRa radio" + } + }, + "network": { + "title": "WiFi Config", + "description": "WiFi radio configuration", + "note": "Note: Some devices (ESP32) cannot use both Bluetooth and WiFi at the same time.", + "addressMode": { + "description": "Address assignment selection", + "label": "Address Mode" + }, + "dns": { + "description": "DNS Server", + "label": "DNS" + }, + "ethernetEnabled": { + "description": "Enable or disable the Ethernet port", + "label": "Enabled" + }, + "gateway": { + "description": "Default Gateway", + "label": "Átjáró" + }, + "ip": { + "description": "IP Address", + "label": "IP" + }, + "psk": { + "description": "Network password", + "label": "PSK" + }, + "ssid": { + "description": "Network name", + "label": "SSID" + }, + "subnet": { + "description": "Subnet Mask", + "label": "Alhálózat" + }, + "wifiEnabled": { + "description": "Enable or disable the WiFi radio", + "label": "Enabled" + }, + "meshViaUdp": { + "label": "Mesh via UDP" + }, + "ntpServer": { + "label": "NTP Server" + }, + "rsyslogServer": { + "label": "Rsyslog Server" + }, + "ethernetConfigSettings": { + "description": "Ethernet port configuration", + "label": "Ethernet Config" + }, + "ipConfigSettings": { + "description": "IP configuration", + "label": "IP Config" + }, + "ntpConfigSettings": { + "description": "NTP configuration", + "label": "NTP Config" + }, + "rsyslogConfigSettings": { + "description": "Rsyslog configuration", + "label": "Rsyslog Config" + }, + "udpConfigSettings": { + "description": "UDP over Mesh configuration", + "label": "UDP-beállítások" + } + }, + "position": { + "title": "Position Settings", + "description": "Settings for the position module", + "broadcastInterval": { + "description": "How often your position is sent out over the mesh", + "label": "Broadcast Interval" + }, + "enablePin": { + "description": "GPS module enable pin override", + "label": "Enable Pin" + }, + "fixedPosition": { + "description": "Don't report GPS position, but a manually-specified one", + "label": "Fixed Position" + }, + "gpsMode": { + "description": "Configure whether device GPS is Enabled, Disabled, or Not Present", + "label": "GPS Mode" + }, + "gpsUpdateInterval": { + "description": "How often a GPS fix should be acquired", + "label": "GPS Update Interval" + }, + "positionFlags": { + "description": "Optional fields to include when assembling position messages. The more fields are selected, the larger the message will be leading to longer airtime usage and a higher risk of packet loss.", + "label": "Position Flags" + }, + "receivePin": { + "description": "GPS module RX pin override", + "label": "Receive Pin" + }, + "smartPositionEnabled": { + "description": "Only send position when there has been a meaningful change in location", + "label": "Enable Smart Position" + }, + "smartPositionMinDistance": { + "description": "Minimum distance (in meters) that must be traveled before a position update is sent", + "label": "Smart Position Minimum Distance" + }, + "smartPositionMinInterval": { + "description": "Minimum interval (in seconds) that must pass before a position update is sent", + "label": "Smart Position Minimum Interval" + }, + "transmitPin": { + "description": "GPS module TX pin override", + "label": "Transmit Pin" + }, + "intervalsSettings": { + "description": "How often to send position updates", + "label": "Intervals" + }, + "flags": { + "placeholder": "Select position flags...", + "altitude": "Altitude", + "altitudeGeoidalSeparation": "Altitude Geoidal Separation", + "altitudeMsl": "Altitude is Mean Sea Level", + "dop": "Dilution of precision (DOP) PDOP used by default", + "hdopVdop": "If DOP is set, use HDOP / VDOP values instead of PDOP", + "numSatellites": "Number of satellites", + "sequenceNumber": "Sequence number", + "timestamp": "Időbélyeg", + "unset": "Nincs beállítva", + "vehicleHeading": "Vehicle heading", + "vehicleSpeed": "Vehicle speed" + } + }, + "power": { + "adcMultiplierOverride": { + "description": "Used for tweaking battery voltage reading", + "label": "ADC Multiplier Override ratio" + }, + "ina219Address": { + "description": "Address of the INA219 battery monitor", + "label": "INA219 Address" + }, + "lightSleepDuration": { + "description": "How long the device will be in light sleep for", + "label": "Light Sleep Duration" + }, + "minimumWakeTime": { + "description": "Minimum amount of time the device will stay awake for after receiving a packet", + "label": "Minimum Wake Time" + }, + "noConnectionBluetoothDisabled": { + "description": "If the device does not receive a Bluetooth connection, the BLE radio will be disabled after this long", + "label": "No Connection Bluetooth Disabled" + }, + "powerSavingEnabled": { + "description": "Select if powered from a low-current source (i.e. solar), to minimize power consumption as much as possible.", + "label": "Energiatakarékos mód engedélyezése" + }, + "shutdownOnBatteryDelay": { + "description": "Automatically shutdown node after this long when on battery, 0 for indefinite", + "label": "Shutdown on battery delay" + }, + "superDeepSleepDuration": { + "description": "How long the device will be in super deep sleep for", + "label": "Super Deep Sleep Duration" + }, + "powerConfigSettings": { + "description": "Settings for the power module", + "label": "Energia-beállítások" + }, + "sleepSettings": { + "description": "Sleep settings for the power module", + "label": "Sleep Settings" + } + }, + "security": { + "description": "Settings for the Security configuration", + "title": "Security Settings", + "button_backupKey": "Backup Key", + "adminChannelEnabled": { + "description": "Allow incoming device control over the insecure legacy admin channel", + "label": "Allow Legacy Admin" + }, + "enableDebugLogApi": { + "description": "Output live debug logging over serial, view and export position-redacted device logs over Bluetooth", + "label": "Enable Debug Log API" + }, + "managed": { + "description": "If enabled, device configuration options are only able to be changed remotely by a Remote Admin node via admin messages. Do not enable this option unless at least one suitable Remote Admin node has been setup, and the public key is stored in one of the fields above.", + "label": "Managed" + }, + "privateKey": { + "description": "Used to create a shared key with a remote device", + "label": "Privát kulcs" + }, + "publicKey": { + "description": "Sent out to other nodes on the mesh to allow them to compute a shared secret key", + "label": "Nyilvános kulcs" + }, + "primaryAdminKey": { + "description": "The primary public key authorized to send admin messages to this node", + "label": "Primary Admin Key" + }, + "secondaryAdminKey": { + "description": "The secondary public key authorized to send admin messages to this node", + "label": "Secondary Admin Key" + }, + "serialOutputEnabled": { + "description": "Serial Console over the Stream API", + "label": "Serial Output Enabled" + }, + "tertiaryAdminKey": { + "description": "The tertiary public key authorized to send admin messages to this node", + "label": "Tertiary Admin Key" + }, + "adminSettings": { + "description": "Settings for Admin", + "label": "Admin Settings" + }, + "loggingSettings": { + "description": "Settings for Logging", + "label": "Logging Settings" + } + }, + "user": { + "title": "User Settings", + "description": "Configure your device name and identity settings", + "longName": { + "label": "Long Name", + "description": "Your full display name (1-40 characters)", + "validation": { + "min": "Long name must be at least 1 character", + "max": "Long name must be at most 40 characters" + } + }, + "shortName": { + "label": "Short Name", + "description": "Your abbreviated name (2-4 characters)", + "validation": { + "min": "Short name must be at least 2 characters", + "max": "Short name must be at most 4 characters" + } + }, + "isUnmessageable": { + "label": "Nem üzenetképes", + "description": "Used to identify unmonitored or infrastructure nodes so that messaging is not available to nodes that will never respond." + }, + "isLicensed": { + "label": "Engedélyezett amatőrrádió (HAM)", + "description": "Enable if you are a licensed amateur radio operator, enabling this option disables encryption and is not compatible with the default Meshtastic network." + } + } +} diff --git a/packages/web/public/i18n/locales/hu-HU/connections.json b/packages/web/public/i18n/locales/hu-HU/connections.json new file mode 100644 index 000000000..379b5486d --- /dev/null +++ b/packages/web/public/i18n/locales/hu-HU/connections.json @@ -0,0 +1,34 @@ +{ + "page": { + "title": "Connect to a Meshtastic device", + "description": "Add a device connection via HTTP, Bluetooth, or Serial. Your saved connections will be saved in your browser." + }, + "connectionType_ble": "BLE", + "connectionType_serial": "Soros port", + "connectionType_network": "Hálózat", + "deleteConnection": "Delete connection", + "areYouSure": "This will remove {{name}}. You canot undo this action.", + "moreActions": "More actions", + "noConnections": { + "title": "No connections yet.", + "description": "Create your first connection. It will connect immediately and be saved for later." + }, + "lastConnectedAt": "Last connected: {{date}}", + "neverConnected": "Never connected", + "toasts": { + "connected": "Csatlakoztatva", + "nowConnected": "{{name}} is now connected", + "nowDisconnected": "{{name}} are now disconnecte", + "disconnected": "Szétkapcsolva", + "failed": "Failed to connect", + "checkConnetion": "Check your device or settings and try again", + "defaultSet": "Default set", + "defaultConnection": "Default connection is now {{nameisconnected}}", + "deleted": "Deleted", + "deletedByName": "{{name}} was removed", + "pickConnectionAgain": "Could not connect. You may need to reselect the device/port.", + "added": "Connection added", + "savedByName": "{{name}} saved.", + "savedCantConnect": "The connection was saved but could not connect." + } +} diff --git a/packages/web/public/i18n/locales/hu-HU/dashboard.json b/packages/web/public/i18n/locales/hu-HU/dashboard.json deleted file mode 100644 index 2fdff99ff..000000000 --- a/packages/web/public/i18n/locales/hu-HU/dashboard.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "dashboard": { - "title": "Connected Devices", - "description": "Manage your connected Meshtastic devices.", - "connectionType_ble": "BLE", - "connectionType_serial": "Soros port", - "connectionType_network": "Hálózat", - "noDevicesTitle": "No devices connected", - "noDevicesDescription": "Connect a new device to get started.", - "button_newConnection": "New Connection" - } -} diff --git a/packages/web/public/i18n/locales/hu-HU/deviceConfig.json b/packages/web/public/i18n/locales/hu-HU/deviceConfig.json index e743f9ac2..9aac53597 100644 --- a/packages/web/public/i18n/locales/hu-HU/deviceConfig.json +++ b/packages/web/public/i18n/locales/hu-HU/deviceConfig.json @@ -122,7 +122,7 @@ "title": "Mesh Settings", "description": "Settings for the LoRa mesh", "bandwidth": { - "description": "Channel bandwidth in MHz", + "description": "Channel bandwidth in kHz", "label": "Sávszélesség" }, "boostedRxGain": { diff --git a/packages/web/public/i18n/locales/hu-HU/dialog.json b/packages/web/public/i18n/locales/hu-HU/dialog.json index 1ecad7d78..beae8ae74 100644 --- a/packages/web/public/i18n/locales/hu-HU/dialog.json +++ b/packages/web/public/i18n/locales/hu-HU/dialog.json @@ -1,193 +1,238 @@ { - "deleteMessages": { - "description": "This action will clear all message history. This cannot be undone. Are you sure you want to continue?", - "title": "Clear All Messages" - }, - "deviceName": { - "description": "The Device will restart once the config is saved.", - "longName": "Long Name", - "shortName": "Short Name", - "title": "Change Device Name", - "validation": { - "longNameMax": "Long name must not be more than 40 characters", - "shortNameMax": "Short name must not be more than 4 characters", - "longNameMin": "Long name must have at least 1 character", - "shortNameMin": "Short name must have at least 1 character" - } - }, - "import": { - "description": "The current LoRa configuration will be overridden.", - "error": { - "invalidUrl": "Invalid Meshtastic URL" - }, - "channelPrefix": "Channel: ", - "channelSetUrl": "Channel Set/QR Code URL", - "channels": "Channels:", - "usePreset": "Use Preset?", - "title": "Import Channel Set" - }, - "locationResponse": { - "title": "Location: {{identifier}}", - "altitude": "Altitude: ", - "coordinates": "Coordinates: ", - "noCoordinates": "No Coordinates" - }, - "pkiRegenerateDialog": { - "title": "Regenerate Pre-Shared Key?", - "description": "Are you sure you want to regenerate the pre-shared key?", - "regenerate": "Regenerate" - }, - "newDeviceDialog": { - "title": "Connect New Device", - "https": "https", - "http": "http", - "tabHttp": "HTTP", - "tabBluetooth": "Bluetooth", - "tabSerial": "Soros port", - "useHttps": "Use HTTPS", - "connecting": "Connecting...", - "connect": "Connect", - "connectionFailedAlert": { - "title": "Connection Failed", - "descriptionPrefix": "Could not connect to the device. ", - "httpsHint": "If using HTTPS, you may need to accept a self-signed certificate first. ", - "openLinkPrefix": "Please open ", - "openLinkSuffix": " in a new tab", - "acceptTlsWarningSuffix": ", accept any TLS warnings if prompted, then try again", - "learnMoreLink": "Learn more" - }, - "httpConnection": { - "label": "IP Address/Hostname", - "placeholder": "000.000.000.000 / meshtastic.local" - }, - "serialConnection": { - "noDevicesPaired": "No devices paired yet.", - "newDeviceButton": "New device", - "deviceIdentifier": "# {{index}} - {{vendorId}} - {{productId}}" - }, - "bluetoothConnection": { - "noDevicesPaired": "No devices paired yet.", - "newDeviceButton": "New device", - "connectionFailed": "Connection failed", - "deviceDisconnected": "Device disconnected", - "unknownDevice": "Unknown Device", - "errorLoadingDevices": "Error loading devices", - "unknownErrorLoadingDevices": "Unknown error loading devices" - }, - "validation": { - "requiresWebBluetooth": "This connection type requires <0>Web Bluetooth. Please use a supported browser, like Chrome or Edge.", - "requiresWebSerial": "This connection type requires <0>Web Serial. Please use a supported browser, like Chrome or Edge.", - "requiresSecureContext": "This application requires a <0>secure context. Please connect using HTTPS or localhost.", - "additionallyRequiresSecureContext": "Additionally, it requires a <0>secure context. Please connect using HTTPS or localhost." - } - }, - "nodeDetails": { - "message": "Üzenet", - "requestPosition": "Request Position", - "traceRoute": "Trace Route", - "airTxUtilization": "Air TX utilization", - "allRawMetrics": "All Raw Metrics:", - "batteryLevel": "Battery level", - "channelUtilization": "Channel utilization", - "details": "Details:", - "deviceMetrics": "Device Metrics:", - "hardware": "Hardware: ", - "lastHeard": "Last Heard: ", - "nodeHexPrefix": "Node Hex: ", - "nodeNumber": "Node Number: ", - "position": "Position:", - "role": "Role: ", - "uptime": "Uptime: ", - "voltage": "Feszültség", - "title": "Node Details for {{identifier}}", - "ignoreNode": "Ignore node", - "removeNode": "Remove node", - "unignoreNode": "Unignore node", - "security": "Security:", - "publicKey": "Public Key: ", - "messageable": "Messageable: ", - "KeyManuallyVerifiedTrue": "Public Key has been manually verified", - "KeyManuallyVerifiedFalse": "Public Key is not manually verified" - }, - "pkiBackup": { - "loseKeysWarning": "If you lose your keys, you will need to reset your device.", - "secureBackup": "Its important to backup your public and private keys and store your backup securely!", - "footer": "=== END OF KEYS ===", - "header": "=== MESHTASTIC KEYS FOR {{longName}} ({{shortName}}) ===", - "privateKey": "Private Key:", - "publicKey": "Public Key:", - "fileName": "meshtastic_keys_{{longName}}_{{shortName}}.txt", - "title": "Backup Keys" - }, - "pkiBackupReminder": { - "description": "We recommend backing up your key data regularly. Would you like to back up now?", - "title": "Backup Reminder", - "remindLaterPrefix": "Remind me in", - "remindNever": "Never remind me", - "backupNow": "Back up now" - }, - "pkiRegenerate": { - "description": "Are you sure you want to regenerate key pair?", - "title": "Regenerate Key Pair" - }, - "qr": { - "addChannels": "Add Channels", - "replaceChannels": "Replace Channels", - "description": "The current LoRa configuration will also be shared.", - "sharableUrl": "Sharable URL", - "title": "Generate QR Code" - }, - "reboot": { - "title": "Reboot device", - "description": "Reboot now or schedule a reboot of the connected node. Optionally, you can choose to reboot into OTA (Over-the-Air) mode.", - "ota": "Reboot into OTA mode", - "enterDelay": "Enter delay", - "scheduled": "Reboot has been scheduled", - "schedule": "Schedule reboot", - "now": "Reboot now", - "cancel": "Cancel scheduled reboot" - }, - "refreshKeys": { - "description": { - "acceptNewKeys": "This will remove the node from device and request new keys.", - "keyMismatchReasonSuffix": ". This is due to the remote node's current public key does not match the previously stored key for this node.", - "unableToSendDmPrefix": "Your node is unable to send a direct message to node: " - }, - "acceptNewKeys": "Accept New Keys", - "title": "Keys Mismatch - {{identifier}}" - }, - "removeNode": { - "description": "Are you sure you want to remove this Node?", - "title": "Remove Node?" - }, - "shutdown": { - "title": "Schedule Shutdown", - "description": "Turn off the connected node after x minutes." - }, - "traceRoute": { - "routeToDestination": "Route to destination:", - "routeBack": "Route back:" - }, - "tracerouteResponse": { - "title": "Traceroute: {{identifier}}" - }, - "unsafeRoles": { - "confirmUnderstanding": "Yes, I know what I'm doing", - "conjunction": " and the blog post about ", - "postamble": " and understand the implications of changing the role.", - "preamble": "I have read the ", - "choosingRightDeviceRole": "Choosing The Right Device Role", - "deviceRoleDocumentation": "Device Role Documentation", - "title": "Biztos vagy benne?" - }, - "managedMode": { - "confirmUnderstanding": "Yes, I know what I'm doing", - "title": "Biztos vagy benne?", - "description": "Enabling Managed Mode blocks client applications (including the web client) from writing configurations to a radio. Once enabled, radio configurations can only be changed through Remote Admin messages. This setting is not required for remote node administration." - }, - "clientNotification": { - "title": "Kliens értesítés", - "TraceRoute can only be sent once every 30 seconds": "TraceRoute can only be sent once every 30 seconds", - "Compromised keys were detected and regenerated.": "Compromised keys were detected and regenerated." - } + "deleteMessages": { + "description": "This action will clear all message history. This cannot be undone. Are you sure you want to continue?", + "title": "Clear All Messages" + }, + "import": { + "description": "The current LoRa configuration will be overridden.", + "error": { + "invalidUrl": "Invalid Meshtastic URL" + }, + "channelPrefix": "Channel: ", + "primary": "Primary ", + "doNotImport": "No not import", + "channelName": "Név", + "channelSlot": "Sávhely", + "channelSetUrl": "Channel Set/QR Code URL", + "useLoraConfig": "Import LoRa Config", + "presetDescription": "The current LoRa Config will be replaced.", + "title": "Import Channel Set" + }, + "locationResponse": { + "title": "Location: {{identifier}}", + "altitude": "Altitude: ", + "coordinates": "Coordinates: ", + "noCoordinates": "No Coordinates" + }, + "pkiRegenerateDialog": { + "title": "Regenerate Pre-Shared Key?", + "description": "Are you sure you want to regenerate the pre-shared key?", + "regenerate": "Regenerate" + }, + "addConnection": { + "title": "Add connection", + "description": "Choose a connection type and fill in the details", + "validation": { + "requiresWebBluetooth": "This connection type requires <0>Web Bluetooth. Please use a supported browser, like Chrome or Edge.", + "requiresWebSerial": "This connection type requires <0>Web Serial. Please use a supported browser, like Chrome or Edge.", + "requiresSecureContext": "This application requires a <0>secure context. Please connect using HTTPS or localhost.", + "additionallyRequiresSecureContext": "Additionally, it requires a <0>secure context. Please connect using HTTPS or localhost." + }, + "bluetoothConnection": { + "namePlaceholder": "My Bluetooth Node", + "supported": { + "title": "Web Bluetooth supported" + }, + "notSupported": { + "title": "Web Bluetooth not supported", + "description": "Your browser or device does not support Web Bluetooth" + }, + "short": "BT: {{deviceName}}", + "long": "Bluetooth Device", + "device": "Eszköz", + "selectDevice": "Select device", + "selected": "Bluetooth device selected", + "notSelected": "No device selected", + "helperText": "Uses the Meshtastic Bluetooth service for discovery." + }, + "serialConnection": { + "namePlaceholder": "My Serial Node", + "helperText": "Selecting a port grants permission so the app can open it to connect.", + "supported": { + "title": "Web Serial supported" + }, + "notSupported": { + "title": "Web Serial not supported", + "description": "Your browser or device does not support Web Serial" + }, + "portSelected": { + "title": "Serial port selected", + "description": "Port permissions granted." + }, + "port": "Port", + "selectPort": "Select port", + "deviceName": "USB {{vendorId}}:{{productId}}", + "notSelected": "No port selected" + }, + "httpConnection": { + "namePlaceholder": "My HTTP Node", + "inputPlaceholder": "192.168.1.10 or meshtastic.local", + "heading": "URL or IP", + "useHttps": "Use HTTTPS", + "invalidUrl": { + "title": "Invalid URL", + "description": "Please enter a valid HTTP or HTTPS URL." + }, + "connectionTest": { + "description": "Test the connetion before saving to verify the device is reachable.", + "button": { + "loading": "Testing...", + "label": "Test connection" + }, + "reachable": "Reachable", + "notReachable": "Not reachable", + "success": { + "title": "Connection test successful", + "description": "The device appears to be reachable." + }, + "failure": { + "title": "Connection test failed", + "description": "Could not reach the device. Check the URL and try again." + } + } + } + }, + "nodeDetails": { + "message": "Üzenet", + "requestPosition": "Request Position", + "traceRoute": "Trace Route", + "airTxUtilization": "Air TX utilization", + "allRawMetrics": "All Raw Metrics:", + "batteryLevel": "Battery level", + "channelUtilization": "Channel utilization", + "details": "Details:", + "deviceMetrics": "Device Metrics:", + "hardware": "Hardware: ", + "lastHeard": "Last Heard: ", + "nodeHexPrefix": "Node Hex: ", + "nodeNumber": "Node Number: ", + "position": "Position:", + "role": "Role: ", + "uptime": "Uptime: ", + "voltage": "Feszültség", + "title": "Node Details for {{identifier}}", + "ignoreNode": "Ignore node", + "removeNode": "Remove node", + "unignoreNode": "Unignore node", + "security": "Security:", + "publicKey": "Public Key: ", + "messageable": "Messageable: ", + "KeyManuallyVerifiedTrue": "Public Key has been manually verified", + "KeyManuallyVerifiedFalse": "Public Key is not manually verified" + }, + "pkiBackup": { + "loseKeysWarning": "If you lose your keys, you will need to reset your device.", + "secureBackup": "Its important to backup your public and private keys and store your backup securely!", + "footer": "=== END OF KEYS ===", + "header": "=== MESHTASTIC KEYS FOR {{longName}} ({{shortName}}) ===", + "privateKey": "Private Key:", + "publicKey": "Public Key:", + "fileName": "meshtastic_keys_{{longName}}_{{shortName}}.txt", + "title": "Backup Keys" + }, + "pkiBackupReminder": { + "description": "We recommend backing up your key data regularly. Would you like to back up now?", + "title": "Backup Reminder", + "remindLaterPrefix": "Remind me in", + "remindNever": "Never remind me", + "backupNow": "Back up now" + }, + "pkiRegenerate": { + "description": "Are you sure you want to regenerate key pair?", + "title": "Regenerate Key Pair" + }, + "qr": { + "addChannels": "Add Channels", + "replaceChannels": "Replace Channels", + "description": "The current LoRa configuration will also be shared.", + "sharableUrl": "Sharable URL", + "title": "Generate QR Code" + }, + "reboot": { + "title": "Reboot device", + "description": "Reboot now or schedule a reboot of the connected node. Optionally, you can choose to reboot into OTA (Over-the-Air) mode.", + "ota": "Reboot into OTA mode", + "enterDelay": "Enter delay", + "scheduled": "Reboot has been scheduled", + "schedule": "Schedule reboot", + "now": "Reboot now", + "cancel": "Cancel scheduled reboot" + }, + "refreshKeys": { + "description": { + "acceptNewKeys": "This will remove the node from device and request new keys.", + "keyMismatchReasonSuffix": ". This is due to the remote node's current public key does not match the previously stored key for this node.", + "unableToSendDmPrefix": "Your node is unable to send a direct message to node: " + }, + "acceptNewKeys": "Accept New Keys", + "title": "Keys Mismatch - {{identifier}}" + }, + "removeNode": { + "description": "Are you sure you want to remove this Node?", + "title": "Remove Node?" + }, + "shutdown": { + "title": "Schedule Shutdown", + "description": "Turn off the connected node after x minutes." + }, + "traceRoute": { + "routeToDestination": "Route to destination:", + "routeBack": "Route back:" + }, + "tracerouteResponse": { + "title": "Traceroute: {{identifier}}" + }, + "unsafeRoles": { + "confirmUnderstanding": "Yes, I know what I'm doing", + "conjunction": " and the blog post about ", + "postamble": " and understand the implications of changing the role.", + "preamble": "I have read the ", + "choosingRightDeviceRole": "Choosing The Right Device Role", + "deviceRoleDocumentation": "Device Role Documentation", + "title": "Biztos vagy benne?" + }, + "managedMode": { + "confirmUnderstanding": "Yes, I know what I'm doing", + "title": "Biztos vagy benne?", + "description": "Enabling Managed Mode blocks client applications (including the web client) from writing configurations to a radio. Once enabled, radio configurations can only be changed through Remote Admin messages. This setting is not required for remote node administration." + }, + "clientNotification": { + "title": "Kliens értesítés", + "TraceRoute can only be sent once every 30 seconds": "TraceRoute can only be sent once every 30 seconds", + "Compromised keys were detected and regenerated.": "Compromised keys were detected and regenerated." + }, + "resetNodeDb": { + "title": "Reset Node Database", + "description": "This will clear all nodes from the connected device's node database and clear all message history in the client. This cannot be undone. Are you sure you want to continue?", + "confirm": "Reset Node Database", + "failedTitle": "There was an error resetting the Node DB. Please try again." + }, + "clearAllStores": { + "title": "Clear All Local Storage", + "description": "This will clear all locally stored data, including message history and node databases for all previously connected devices. This will require you to reconnect to your node once complete and cannot be undone. Are you sure you want to continue?", + "confirm": "Clear all local storage", + "failedTitle": "There was an error clearing local storage. Please try again." + }, + "factoryResetDevice": { + "title": "Factory Reset Device", + "description": "This will factory reset the connected device, erasing all configurations and data on the device as well as all nodes and messages saved in the client. This cannot be undone. Are you sure you want to continue?", + "confirm": "Factory Reset Device", + "failedTitle": "There was an error performing the factory reset. Please try again." + }, + "factoryResetConfig": { + "title": "Factory Reset Config", + "description": "This will factory reset the configuration on the connected device, erasing all configurations on the device. This cannot be undone. Are you sure you want to continue?", + "confirm": "Factory Reset Config", + "failedTitle": "There was an error performing the factory reset. Please try again." + } } diff --git a/packages/web/public/i18n/locales/hu-HU/map.json b/packages/web/public/i18n/locales/hu-HU/map.json new file mode 100644 index 000000000..a533be1b0 --- /dev/null +++ b/packages/web/public/i18n/locales/hu-HU/map.json @@ -0,0 +1,38 @@ +{ + "maplibre": { + "GeolocateControl.FindMyLocation": "Find my location", + "NavigationControl.ZoomIn": "Zoom in", + "NavigationControl.ZoomOut": "Zoom out", + "CooperativeGesturesHandler.WindowsHelpText": "Use Ctrl + scroll to zoom the map", + "CooperativeGesturesHandler.MacHelpText": "Use ⌘ + scroll to zoom the map", + "CooperativeGesturesHandler.MobileHelpText": "Use two fingers to move the map" + }, + "layerTool": { + "nodeMarkers": "Show nodes", + "directNeighbors": "Show direct connections", + "remoteNeighbors": "Show remote connections", + "positionPrecision": "Show position precision", + "traceroutes": "Show traceroutes", + "waypoints": "Show waypoints" + }, + "mapMenu": { + "locateAria": "Locate my node", + "layersAria": "Change map style" + }, + "waypointDetail": { + "edit": "Szerkesztés", + "description": "Description:", + "createdBy": "Edited by:", + "createdDate": "Created:", + "updated": "Updated:", + "expires": "Expires:", + "distance": "Distance:", + "bearing": "Absolute bearing:", + "lockedTo": "Locked by:", + "latitude": "Latitude:", + "longitude": "Longitude:" + }, + "myNode": { + "tooltip": "This device" + } +} diff --git a/packages/web/public/i18n/locales/hu-HU/messages.json b/packages/web/public/i18n/locales/hu-HU/messages.json index a98b60467..f1d65c73e 100644 --- a/packages/web/public/i18n/locales/hu-HU/messages.json +++ b/packages/web/public/i18n/locales/hu-HU/messages.json @@ -1,39 +1,39 @@ { - "page": { - "title": "Messages: {{chatName}}", - "placeholder": "Enter Message" - }, - "emptyState": { - "title": "Select a Chat", - "text": "No messages yet." - }, - "selectChatPrompt": { - "text": "Select a channel or node to start messaging." - }, - "sendMessage": { - "placeholder": "Enter your message here...", - "sendButton": "Küldeni" - }, - "actionsMenu": { - "addReactionLabel": "Add Reaction", - "replyLabel": "Válasz" - }, - "deliveryStatus": { - "delivered": { - "label": "Message delivered", - "displayText": "Message delivered" - }, - "failed": { - "label": "Message delivery failed", - "displayText": "Delivery failed" - }, - "unknown": { - "label": "Message status unknown", - "displayText": "Unknown state" - }, - "waiting": { - "label": "Sending message", - "displayText": "Waiting for delivery" - } - } + "page": { + "title": "Messages: {{chatName}}", + "placeholder": "Enter Message" + }, + "emptyState": { + "title": "Select a Chat", + "text": "No messages yet." + }, + "selectChatPrompt": { + "text": "Select a channel or node to start messaging." + }, + "sendMessage": { + "placeholder": "Enter your message here...", + "sendButton": "Küldeni" + }, + "actionsMenu": { + "addReactionLabel": "Add Reaction", + "replyLabel": "Válasz" + }, + "deliveryStatus": { + "delivered": { + "label": "Message delivered", + "displayText": "Message delivered" + }, + "failed": { + "label": "Message delivery failed", + "displayText": "Delivery failed" + }, + "unknown": { + "label": "Message status unknown", + "displayText": "Unknown state" + }, + "waiting": { + "label": "Sending message", + "displayText": "Waiting for delivery" + } + } } diff --git a/packages/web/public/i18n/locales/hu-HU/moduleConfig.json b/packages/web/public/i18n/locales/hu-HU/moduleConfig.json index 13542ad68..dad63d8d2 100644 --- a/packages/web/public/i18n/locales/hu-HU/moduleConfig.json +++ b/packages/web/public/i18n/locales/hu-HU/moduleConfig.json @@ -1,448 +1,448 @@ { - "page": { - "tabAmbientLighting": "Környezeti fény", - "tabAudio": "Hang", - "tabCannedMessage": "Canned", - "tabDetectionSensor": "Érzékelő szenzor", - "tabExternalNotification": "Ext Notif", - "tabMqtt": "MQTT", - "tabNeighborInfo": "Szomszéd-információ", - "tabPaxcounter": "PaxCounter", - "tabRangeTest": "Hatótáv-teszt", - "tabSerial": "Soros port", - "tabStoreAndForward": "S&F", - "tabTelemetry": "Telemetria" - }, - "ambientLighting": { - "title": "Ambient Lighting Settings", - "description": "Settings for the Ambient Lighting module", - "ledState": { - "label": "LED State", - "description": "Sets LED to on or off" - }, - "current": { - "label": "Áramerősség", - "description": "Sets the current for the LED output. Default is 10" - }, - "red": { - "label": "Piros", - "description": "Sets the red LED level. Values are 0-255" - }, - "green": { - "label": "Zöld", - "description": "Sets the green LED level. Values are 0-255" - }, - "blue": { - "label": "Kék", - "description": "Sets the blue LED level. Values are 0-255" - } - }, - "audio": { - "title": "Audio Settings", - "description": "Settings for the Audio module", - "codec2Enabled": { - "label": "Codec 2 Enabled", - "description": "Enable Codec 2 audio encoding" - }, - "pttPin": { - "label": "PTT Pin", - "description": "GPIO pin to use for PTT" - }, - "bitrate": { - "label": "Bitrate", - "description": "Bitrate to use for audio encoding" - }, - "i2sWs": { - "label": "i2S WS", - "description": "GPIO pin to use for i2S WS" - }, - "i2sSd": { - "label": "i2S SD", - "description": "GPIO pin to use for i2S SD" - }, - "i2sDin": { - "label": "i2S DIN", - "description": "GPIO pin to use for i2S DIN" - }, - "i2sSck": { - "label": "i2S SCK", - "description": "GPIO pin to use for i2S SCK" - } - }, - "cannedMessage": { - "title": "Canned Message Settings", - "description": "Settings for the Canned Message module", - "moduleEnabled": { - "label": "Module Enabled", - "description": "Enable Canned Message" - }, - "rotary1Enabled": { - "label": "Rotary Encoder #1 Enabled", - "description": "Enable the rotary encoder" - }, - "inputbrokerPinA": { - "label": "Encoder Pin A", - "description": "GPIO Pin Value (1-39) For encoder port A" - }, - "inputbrokerPinB": { - "label": "Encoder Pin B", - "description": "GPIO Pin Value (1-39) For encoder port B" - }, - "inputbrokerPinPress": { - "label": "Encoder Pin Press", - "description": "GPIO Pin Value (1-39) For encoder Press" - }, - "inputbrokerEventCw": { - "label": "Clockwise event", - "description": "Select input event." - }, - "inputbrokerEventCcw": { - "label": "Counter Clockwise event", - "description": "Select input event." - }, - "inputbrokerEventPress": { - "label": "Press event", - "description": "Select input event" - }, - "updown1Enabled": { - "label": "Up Down enabled", - "description": "Enable the up / down encoder" - }, - "allowInputSource": { - "label": "Allow Input Source", - "description": "Select from: '_any', 'rotEnc1', 'upDownEnc1', 'cardkb'" - }, - "sendBell": { - "label": "Send Bell", - "description": "Sends a bell character with each message" - } - }, - "detectionSensor": { - "title": "Detection Sensor Settings", - "description": "Settings for the Detection Sensor module", - "enabled": { - "label": "Enabled", - "description": "Enable or disable Detection Sensor Module" - }, - "minimumBroadcastSecs": { - "label": "Minimum Broadcast Seconds", - "description": "The interval in seconds of how often we can send a message to the mesh when a state change is detected" - }, - "stateBroadcastSecs": { - "label": "State Broadcast Seconds", - "description": "The interval in seconds of how often we should send a message to the mesh with the current state regardless of changes" - }, - "sendBell": { - "label": "Send Bell", - "description": "Send ASCII bell with alert message" - }, - "name": { - "label": "Friendly Name", - "description": "Used to format the message sent to mesh, max 20 Characters" - }, - "monitorPin": { - "label": "Monitor Pin", - "description": "The GPIO pin to monitor for state changes" - }, - "detectionTriggerType": { - "label": "Detection Triggered Type", - "description": "The type of trigger event to be used" - }, - "usePullup": { - "label": "Use Pullup", - "description": "Whether or not use INPUT_PULLUP mode for GPIO pin" - } - }, - "externalNotification": { - "title": "External Notification Settings", - "description": "Configure the external notification module", - "enabled": { - "label": "Module Enabled", - "description": "Enable External Notification" - }, - "outputMs": { - "label": "Output MS", - "description": "Output MS" - }, - "output": { - "label": "Output", - "description": "Output" - }, - "outputVibra": { - "label": "Output Vibrate", - "description": "Output Vibrate" - }, - "outputBuzzer": { - "label": "Output Buzzer", - "description": "Output Buzzer" - }, - "active": { - "label": "Active", - "description": "Active" - }, - "alertMessage": { - "label": "Alert Message", - "description": "Alert Message" - }, - "alertMessageVibra": { - "label": "Alert Message Vibrate", - "description": "Alert Message Vibrate" - }, - "alertMessageBuzzer": { - "label": "Alert Message Buzzer", - "description": "Alert Message Buzzer" - }, - "alertBell": { - "label": "Alert Bell", - "description": "Should an alert be triggered when receiving an incoming bell?" - }, - "alertBellVibra": { - "label": "Alert Bell Vibrate", - "description": "Alert Bell Vibrate" - }, - "alertBellBuzzer": { - "label": "Alert Bell Buzzer", - "description": "Alert Bell Buzzer" - }, - "usePwm": { - "label": "Use PWM", - "description": "Use PWM" - }, - "nagTimeout": { - "label": "Nag Timeout", - "description": "Nag Timeout" - }, - "useI2sAsBuzzer": { - "label": "Use I²S Pin as Buzzer", - "description": "Designate I²S Pin as Buzzer Output" - } - }, - "mqtt": { - "title": "MQTT Settings", - "description": "Settings for the MQTT module", - "enabled": { - "label": "Enabled", - "description": "Enable or disable MQTT" - }, - "address": { - "label": "MQTT Server Address", - "description": "MQTT server address to use for default/custom servers" - }, - "username": { - "label": "MQTT Username", - "description": "MQTT username to use for default/custom servers" - }, - "password": { - "label": "MQTT Password", - "description": "MQTT password to use for default/custom servers" - }, - "encryptionEnabled": { - "label": "Encryption Enabled", - "description": "Enable or disable MQTT encryption. Note: All messages are sent to the MQTT broker unencrypted if this option is not enabled, even when your uplink channels have encryption keys set. This includes position data." - }, - "jsonEnabled": { - "label": "JSON Enabled", - "description": "Whether to send/consume JSON packets on MQTT" - }, - "tlsEnabled": { - "label": "TLS Enabled", - "description": "Enable or disable TLS" - }, - "root": { - "label": "Gyökér téma", - "description": "MQTT root topic to use for default/custom servers" - }, - "proxyToClientEnabled": { - "label": "MQTT Client Proxy Enabled", - "description": "Utilizes the network connection to proxy MQTT messages to the client." - }, - "mapReportingEnabled": { - "label": "Map Reporting Enabled", - "description": "Your node will periodically send an unencrypted map report packet to the configured MQTT server, this includes id, short and long name, approximate location, hardware model, role, firmware version, LoRa region, modem preset and primary channel name." - }, - "mapReportSettings": { - "publishIntervalSecs": { - "label": "Map Report Publish Interval (s)", - "description": "Interval in seconds to publish map reports" - }, - "positionPrecision": { - "label": "Approximate Location", - "description": "Position shared will be accurate within this distance", - "options": { - "metric_km23": "Within 23 km", - "metric_km12": "Within 12 km", - "metric_km5_8": "Within 5.8 km", - "metric_km2_9": "Within 2.9 km", - "metric_km1_5": "Within 1.5 km", - "metric_m700": "Within 700 m", - "metric_m350": "Within 350 m", - "metric_m200": "Within 200 m", - "metric_m90": "Within 90 m", - "metric_m50": "Within 50 m", - "imperial_mi15": "Within 15 miles", - "imperial_mi7_3": "Within 7.3 miles", - "imperial_mi3_6": "Within 3.6 miles", - "imperial_mi1_8": "Within 1.8 miles", - "imperial_mi0_9": "Within 0.9 miles", - "imperial_mi0_5": "Within 0.5 miles", - "imperial_mi0_2": "Within 0.2 miles", - "imperial_ft600": "Within 600 feet", - "imperial_ft300": "Within 300 feet", - "imperial_ft150": "Within 150 feet" - } - } - } - }, - "neighborInfo": { - "title": "Neighbor Info Settings", - "description": "Settings for the Neighbor Info module", - "enabled": { - "label": "Enabled", - "description": "Enable or disable Neighbor Info Module" - }, - "updateInterval": { - "label": "Update Interval", - "description": "Interval in seconds of how often we should try to send our Neighbor Info to the mesh" - } - }, - "paxcounter": { - "title": "Paxcounter Settings", - "description": "Settings for the Paxcounter module", - "enabled": { - "label": "Module Enabled", - "description": "Enable Paxcounter" - }, - "paxcounterUpdateInterval": { - "label": "Update Interval (seconds)", - "description": "How long to wait between sending paxcounter packets" - }, - "wifiThreshold": { - "label": "WiFi RSSI Threshold", - "description": "At what WiFi RSSI level should the counter increase. Defaults to -80." - }, - "bleThreshold": { - "label": "BLE RSSI Threshold", - "description": "At what BLE RSSI level should the counter increase. Defaults to -80." - } - }, - "rangeTest": { - "title": "Range Test Settings", - "description": "Settings for the Range Test module", - "enabled": { - "label": "Module Enabled", - "description": "Enable Range Test" - }, - "sender": { - "label": "Message Interval", - "description": "How long to wait between sending test packets" - }, - "save": { - "label": "Save CSV to storage", - "description": "ESP32 Only" - } - }, - "serial": { - "title": "Serial Settings", - "description": "Settings for the Serial module", - "enabled": { - "label": "Module Enabled", - "description": "Enable Serial output" - }, - "echo": { - "label": "Echo", - "description": "Any packets you send will be echoed back to your device" - }, - "rxd": { - "label": "Receive Pin", - "description": "Set the GPIO pin to the RXD pin you have set up." - }, - "txd": { - "label": "Transmit Pin", - "description": "Set the GPIO pin to the TXD pin you have set up." - }, - "baud": { - "label": "Baud Rate", - "description": "The serial baud rate" - }, - "timeout": { - "label": "Időtúllépés", - "description": "Seconds to wait before we consider your packet as 'done'" - }, - "mode": { - "label": "Mode", - "description": "Select Mode" - }, - "overrideConsoleSerialPort": { - "label": "Override Console Serial Port", - "description": "If you have a serial port connected to the console, this will override it." - } - }, - "storeForward": { - "title": "Store & Forward Settings", - "description": "Settings for the Store & Forward module", - "enabled": { - "label": "Module Enabled", - "description": "Enable Store & Forward" - }, - "heartbeat": { - "label": "Heartbeat Enabled", - "description": "Enable Store & Forward heartbeat" - }, - "records": { - "label": "Rekordok száma", - "description": "Number of records to store" - }, - "historyReturnMax": { - "label": "Előzmény-visszaadás maximum", - "description": "Max number of records to return" - }, - "historyReturnWindow": { - "label": "Előzmény-visszaadás időablak", - "description": "Max number of records to return" - } - }, - "telemetry": { - "title": "Telemetry Settings", - "description": "Settings for the Telemetry module", - "deviceUpdateInterval": { - "label": "Device Metrics", - "description": "Eszközmetrikák frissítési intervalluma (másodperc)" - }, - "environmentUpdateInterval": { - "label": "Környezeti metrikák frissítési intervalluma (másodperc)", - "description": "" - }, - "environmentMeasurementEnabled": { - "label": "Module Enabled", - "description": "Enable the Environment Telemetry" - }, - "environmentScreenEnabled": { - "label": "Displayed on Screen", - "description": "Show the Telemetry Module on the OLED" - }, - "environmentDisplayFahrenheit": { - "label": "Display Fahrenheit", - "description": "Display temp in Fahrenheit" - }, - "airQualityEnabled": { - "label": "Air Quality Enabled", - "description": "Enable the Air Quality Telemetry" - }, - "airQualityInterval": { - "label": "Air Quality Update Interval", - "description": "How often to send Air Quality data over the mesh" - }, - "powerMeasurementEnabled": { - "label": "Power Measurement Enabled", - "description": "Enable the Power Measurement Telemetry" - }, - "powerUpdateInterval": { - "label": "Power Update Interval", - "description": "How often to send Power data over the mesh" - }, - "powerScreenEnabled": { - "label": "Power Screen Enabled", - "description": "Enable the Power Telemetry Screen" - } - } + "page": { + "tabAmbientLighting": "Környezeti fény", + "tabAudio": "Hang", + "tabCannedMessage": "Canned", + "tabDetectionSensor": "Érzékelő szenzor", + "tabExternalNotification": "Ext Notif", + "tabMqtt": "MQTT", + "tabNeighborInfo": "Szomszéd-információ", + "tabPaxcounter": "PaxCounter", + "tabRangeTest": "Hatótáv-teszt", + "tabSerial": "Soros port", + "tabStoreAndForward": "S&F", + "tabTelemetry": "Telemetria" + }, + "ambientLighting": { + "title": "Ambient Lighting Settings", + "description": "Settings for the Ambient Lighting module", + "ledState": { + "label": "LED State", + "description": "Sets LED to on or off" + }, + "current": { + "label": "Áramerősség", + "description": "Sets the current for the LED output. Default is 10" + }, + "red": { + "label": "Piros", + "description": "Sets the red LED level. Values are 0-255" + }, + "green": { + "label": "Zöld", + "description": "Sets the green LED level. Values are 0-255" + }, + "blue": { + "label": "Kék", + "description": "Sets the blue LED level. Values are 0-255" + } + }, + "audio": { + "title": "Audio Settings", + "description": "Settings for the Audio module", + "codec2Enabled": { + "label": "Codec 2 Enabled", + "description": "Enable Codec 2 audio encoding" + }, + "pttPin": { + "label": "PTT Pin", + "description": "GPIO pin to use for PTT" + }, + "bitrate": { + "label": "Bitrate", + "description": "Bitrate to use for audio encoding" + }, + "i2sWs": { + "label": "i2S WS", + "description": "GPIO pin to use for i2S WS" + }, + "i2sSd": { + "label": "i2S SD", + "description": "GPIO pin to use for i2S SD" + }, + "i2sDin": { + "label": "i2S DIN", + "description": "GPIO pin to use for i2S DIN" + }, + "i2sSck": { + "label": "i2S SCK", + "description": "GPIO pin to use for i2S SCK" + } + }, + "cannedMessage": { + "title": "Canned Message Settings", + "description": "Settings for the Canned Message module", + "moduleEnabled": { + "label": "Module Enabled", + "description": "Enable Canned Message" + }, + "rotary1Enabled": { + "label": "Rotary Encoder #1 Enabled", + "description": "Enable the rotary encoder" + }, + "inputbrokerPinA": { + "label": "Encoder Pin A", + "description": "GPIO Pin Value (1-39) For encoder port A" + }, + "inputbrokerPinB": { + "label": "Encoder Pin B", + "description": "GPIO Pin Value (1-39) For encoder port B" + }, + "inputbrokerPinPress": { + "label": "Encoder Pin Press", + "description": "GPIO Pin Value (1-39) For encoder Press" + }, + "inputbrokerEventCw": { + "label": "Clockwise event", + "description": "Select input event." + }, + "inputbrokerEventCcw": { + "label": "Counter Clockwise event", + "description": "Select input event." + }, + "inputbrokerEventPress": { + "label": "Press event", + "description": "Select input event" + }, + "updown1Enabled": { + "label": "Up Down enabled", + "description": "Enable the up / down encoder" + }, + "allowInputSource": { + "label": "Allow Input Source", + "description": "Select from: '_any', 'rotEnc1', 'upDownEnc1', 'cardkb'" + }, + "sendBell": { + "label": "Send Bell", + "description": "Sends a bell character with each message" + } + }, + "detectionSensor": { + "title": "Detection Sensor Settings", + "description": "Settings for the Detection Sensor module", + "enabled": { + "label": "Enabled", + "description": "Enable or disable Detection Sensor Module" + }, + "minimumBroadcastSecs": { + "label": "Minimum Broadcast Seconds", + "description": "The interval in seconds of how often we can send a message to the mesh when a state change is detected" + }, + "stateBroadcastSecs": { + "label": "State Broadcast Seconds", + "description": "The interval in seconds of how often we should send a message to the mesh with the current state regardless of changes" + }, + "sendBell": { + "label": "Send Bell", + "description": "Send ASCII bell with alert message" + }, + "name": { + "label": "Friendly Name", + "description": "Used to format the message sent to mesh, max 20 Characters" + }, + "monitorPin": { + "label": "Monitor Pin", + "description": "The GPIO pin to monitor for state changes" + }, + "detectionTriggerType": { + "label": "Detection Triggered Type", + "description": "The type of trigger event to be used" + }, + "usePullup": { + "label": "Use Pullup", + "description": "Whether or not use INPUT_PULLUP mode for GPIO pin" + } + }, + "externalNotification": { + "title": "External Notification Settings", + "description": "Configure the external notification module", + "enabled": { + "label": "Module Enabled", + "description": "Enable External Notification" + }, + "outputMs": { + "label": "Output MS", + "description": "Output MS" + }, + "output": { + "label": "Output", + "description": "Output" + }, + "outputVibra": { + "label": "Output Vibrate", + "description": "Output Vibrate" + }, + "outputBuzzer": { + "label": "Output Buzzer", + "description": "Output Buzzer" + }, + "active": { + "label": "Active", + "description": "Active" + }, + "alertMessage": { + "label": "Alert Message", + "description": "Alert Message" + }, + "alertMessageVibra": { + "label": "Alert Message Vibrate", + "description": "Alert Message Vibrate" + }, + "alertMessageBuzzer": { + "label": "Alert Message Buzzer", + "description": "Alert Message Buzzer" + }, + "alertBell": { + "label": "Alert Bell", + "description": "Should an alert be triggered when receiving an incoming bell?" + }, + "alertBellVibra": { + "label": "Alert Bell Vibrate", + "description": "Alert Bell Vibrate" + }, + "alertBellBuzzer": { + "label": "Alert Bell Buzzer", + "description": "Alert Bell Buzzer" + }, + "usePwm": { + "label": "Use PWM", + "description": "Use PWM" + }, + "nagTimeout": { + "label": "Nag Timeout", + "description": "Nag Timeout" + }, + "useI2sAsBuzzer": { + "label": "Use I²S Pin as Buzzer", + "description": "Designate I²S Pin as Buzzer Output" + } + }, + "mqtt": { + "title": "MQTT Settings", + "description": "Settings for the MQTT module", + "enabled": { + "label": "Enabled", + "description": "Enable or disable MQTT" + }, + "address": { + "label": "MQTT Server Address", + "description": "MQTT server address to use for default/custom servers" + }, + "username": { + "label": "MQTT Username", + "description": "MQTT username to use for default/custom servers" + }, + "password": { + "label": "MQTT Password", + "description": "MQTT password to use for default/custom servers" + }, + "encryptionEnabled": { + "label": "Encryption Enabled", + "description": "Enable or disable MQTT encryption. Note: All messages are sent to the MQTT broker unencrypted if this option is not enabled, even when your uplink channels have encryption keys set. This includes position data." + }, + "jsonEnabled": { + "label": "JSON Enabled", + "description": "Whether to send/consume JSON packets on MQTT" + }, + "tlsEnabled": { + "label": "TLS Enabled", + "description": "Enable or disable TLS" + }, + "root": { + "label": "Gyökér téma", + "description": "MQTT root topic to use for default/custom servers" + }, + "proxyToClientEnabled": { + "label": "MQTT Client Proxy Enabled", + "description": "Utilizes the network connection to proxy MQTT messages to the client." + }, + "mapReportingEnabled": { + "label": "Map Reporting Enabled", + "description": "Your node will periodically send an unencrypted map report packet to the configured MQTT server, this includes id, short and long name, approximate location, hardware model, role, firmware version, LoRa region, modem preset and primary channel name." + }, + "mapReportSettings": { + "publishIntervalSecs": { + "label": "Map Report Publish Interval (s)", + "description": "Interval in seconds to publish map reports" + }, + "positionPrecision": { + "label": "Approximate Location", + "description": "Position shared will be accurate within this distance", + "options": { + "metric_km23": "Within 23 km", + "metric_km12": "Within 12 km", + "metric_km5_8": "Within 5.8 km", + "metric_km2_9": "Within 2.9 km", + "metric_km1_5": "Within 1.5 km", + "metric_m700": "Within 700 m", + "metric_m350": "Within 350 m", + "metric_m200": "Within 200 m", + "metric_m90": "Within 90 m", + "metric_m50": "Within 50 m", + "imperial_mi15": "Within 15 miles", + "imperial_mi7_3": "Within 7.3 miles", + "imperial_mi3_6": "Within 3.6 miles", + "imperial_mi1_8": "Within 1.8 miles", + "imperial_mi0_9": "Within 0.9 miles", + "imperial_mi0_5": "Within 0.5 miles", + "imperial_mi0_2": "Within 0.2 miles", + "imperial_ft600": "Within 600 feet", + "imperial_ft300": "Within 300 feet", + "imperial_ft150": "Within 150 feet" + } + } + } + }, + "neighborInfo": { + "title": "Neighbor Info Settings", + "description": "Settings for the Neighbor Info module", + "enabled": { + "label": "Enabled", + "description": "Enable or disable Neighbor Info Module" + }, + "updateInterval": { + "label": "Update Interval", + "description": "Interval in seconds of how often we should try to send our Neighbor Info to the mesh" + } + }, + "paxcounter": { + "title": "Paxcounter Settings", + "description": "Settings for the Paxcounter module", + "enabled": { + "label": "Module Enabled", + "description": "Enable Paxcounter" + }, + "paxcounterUpdateInterval": { + "label": "Update Interval (seconds)", + "description": "How long to wait between sending paxcounter packets" + }, + "wifiThreshold": { + "label": "WiFi RSSI Threshold", + "description": "At what WiFi RSSI level should the counter increase. Defaults to -80." + }, + "bleThreshold": { + "label": "BLE RSSI Threshold", + "description": "At what BLE RSSI level should the counter increase. Defaults to -80." + } + }, + "rangeTest": { + "title": "Range Test Settings", + "description": "Settings for the Range Test module", + "enabled": { + "label": "Module Enabled", + "description": "Enable Range Test" + }, + "sender": { + "label": "Message Interval", + "description": "How long to wait between sending test packets" + }, + "save": { + "label": "Save CSV to storage", + "description": "ESP32 Only" + } + }, + "serial": { + "title": "Serial Settings", + "description": "Settings for the Serial module", + "enabled": { + "label": "Module Enabled", + "description": "Enable Serial output" + }, + "echo": { + "label": "Echo", + "description": "Any packets you send will be echoed back to your device" + }, + "rxd": { + "label": "Receive Pin", + "description": "Set the GPIO pin to the RXD pin you have set up." + }, + "txd": { + "label": "Transmit Pin", + "description": "Set the GPIO pin to the TXD pin you have set up." + }, + "baud": { + "label": "Baud Rate", + "description": "The serial baud rate" + }, + "timeout": { + "label": "Időtúllépés", + "description": "Seconds to wait before we consider your packet as 'done'" + }, + "mode": { + "label": "Mode", + "description": "Select Mode" + }, + "overrideConsoleSerialPort": { + "label": "Override Console Serial Port", + "description": "If you have a serial port connected to the console, this will override it." + } + }, + "storeForward": { + "title": "Store & Forward Settings", + "description": "Settings for the Store & Forward module", + "enabled": { + "label": "Module Enabled", + "description": "Enable Store & Forward" + }, + "heartbeat": { + "label": "Heartbeat Enabled", + "description": "Enable Store & Forward heartbeat" + }, + "records": { + "label": "Rekordok száma", + "description": "Number of records to store" + }, + "historyReturnMax": { + "label": "Előzmény-visszaadás maximum", + "description": "Max number of records to return" + }, + "historyReturnWindow": { + "label": "Előzmény-visszaadás időablak", + "description": "Return records from this time window (minutes)" + } + }, + "telemetry": { + "title": "Telemetry Settings", + "description": "Settings for the Telemetry module", + "deviceUpdateInterval": { + "label": "Device Metrics", + "description": "Eszközmetrikák frissítési intervalluma (másodperc)" + }, + "environmentUpdateInterval": { + "label": "Környezeti metrikák frissítési intervalluma (másodperc)", + "description": "" + }, + "environmentMeasurementEnabled": { + "label": "Module Enabled", + "description": "Enable the Environment Telemetry" + }, + "environmentScreenEnabled": { + "label": "Displayed on Screen", + "description": "Show the Telemetry Module on the OLED" + }, + "environmentDisplayFahrenheit": { + "label": "Display Fahrenheit", + "description": "Display temp in Fahrenheit" + }, + "airQualityEnabled": { + "label": "Air Quality Enabled", + "description": "Enable the Air Quality Telemetry" + }, + "airQualityInterval": { + "label": "Air Quality Update Interval", + "description": "How often to send Air Quality data over the mesh" + }, + "powerMeasurementEnabled": { + "label": "Power Measurement Enabled", + "description": "Enable the Power Measurement Telemetry" + }, + "powerUpdateInterval": { + "label": "Power Update Interval", + "description": "How often to send Power data over the mesh" + }, + "powerScreenEnabled": { + "label": "Power Screen Enabled", + "description": "Enable the Power Telemetry Screen" + } + } } diff --git a/packages/web/public/i18n/locales/hu-HU/nodes.json b/packages/web/public/i18n/locales/hu-HU/nodes.json index e72d8df47..1bb186b60 100644 --- a/packages/web/public/i18n/locales/hu-HU/nodes.json +++ b/packages/web/public/i18n/locales/hu-HU/nodes.json @@ -1,63 +1,59 @@ { - "nodeDetail": { - "publicKeyEnabled": { - "label": "Public Key Enabled" - }, - "noPublicKey": { - "label": "No Public Key" - }, - "directMessage": { - "label": "Direct Message {{shortName}}" - }, - "favorite": { - "label": "Kedvenc", - "tooltip": "Add or remove this node from your favorites" - }, - "notFavorite": { - "label": "Not a Favorite" - }, - "error": { - "label": "Hiba", - "text": "An error occurred while fetching node details. Please try again later." - }, - "status": { - "heard": "Heard", - "mqtt": "MQTT" - }, - "elevation": { - "label": "Elevation" - }, - "channelUtil": { - "label": "Channel Util" - }, - "airtimeUtil": { - "label": "Airtime Util" - } - }, - "nodesTable": { - "headings": { - "longName": "Long Name", - "connection": "Kapcsolat", - "lastHeard": "Last Heard", - "encryption": "Encryption", - "model": "Model", - "macAddress": "MAC Address" - }, - "connectionStatus": { - "direct": "Közvetlen", - "away": "away", - "unknown": "-", - "viaMqtt": ", via MQTT" - }, - "lastHeardStatus": { - "never": "Never" - } - }, - "actions": { - "added": "Added", - "removed": "Removed", - "ignoreNode": "Ignore Node", - "unignoreNode": "Unignore Node", - "requestPosition": "Request Position" - } + "nodeDetail": { + "publicKeyEnabled": { + "label": "Public Key Enabled" + }, + "noPublicKey": { + "label": "No Public Key" + }, + "directMessage": { + "label": "Direct Message {{shortName}}" + }, + "favorite": { + "label": "Kedvenc", + "tooltip": "Add or remove this node from your favorites" + }, + "notFavorite": { + "label": "Not a Favorite" + }, + "error": { + "label": "Hiba", + "text": "An error occurred while fetching node details. Please try again later." + }, + "status": { + "heard": "Heard", + "mqtt": "MQTT" + }, + "elevation": { + "label": "Elevation" + }, + "channelUtil": { + "label": "Channel Util" + }, + "airtimeUtil": { + "label": "Airtime Util" + } + }, + "nodesTable": { + "headings": { + "longName": "Long Name", + "connection": "Kapcsolat", + "lastHeard": "Last Heard", + "encryption": "Encryption", + "model": "Model", + "macAddress": "MAC Address" + }, + "connectionStatus": { + "direct": "Közvetlen", + "away": "away", + "viaMqtt": ", via MQTT" + } + }, + "actions": { + "added": "Added", + "removed": "Removed", + "ignoreNode": "Ignore Node", + "unignoreNode": "Unignore Node", + "requestPosition": "Request Position" + } } diff --git a/packages/web/public/i18n/locales/hu-HU/ui.json b/packages/web/public/i18n/locales/hu-HU/ui.json index 567ac7a29..8ea0a0ee3 100644 --- a/packages/web/public/i18n/locales/hu-HU/ui.json +++ b/packages/web/public/i18n/locales/hu-HU/ui.json @@ -1,228 +1,230 @@ { - "navigation": { - "title": "Navigation", - "messages": "Üzenetek", - "map": "Térkép", - "config": "Config", - "radioConfig": "Radio Config", - "moduleConfig": "Module Config", - "channels": "Csatornák", - "nodes": "Csomópontok" - }, - "app": { - "title": "Meshtastic", - "logo": "Meshtastic Logo" - }, - "sidebar": { - "collapseToggle": { - "button": { - "open": "Open sidebar", - "close": "Close sidebar" - } - }, - "deviceInfo": { - "volts": "{{voltage}} volts", - "firmware": { - "title": "Firmware", - "version": "v{{version}}", - "buildDate": "Build date: {{date}}" - }, - "deviceName": { - "title": "Device Name", - "changeName": "Change Device Name", - "placeholder": "Enter device name" - }, - "editDeviceName": "Edit device name" - } - }, - "batteryStatus": { - "charging": "{{level}}% charging", - "pluggedIn": "Plugged in", - "title": "Akkumulátor" - }, - "search": { - "nodes": "Search nodes...", - "channels": "Search channels...", - "commandPalette": "Search commands..." - }, - "toast": { - "positionRequestSent": { - "title": "Position request sent." - }, - "requestingPosition": { - "title": "Requesting position, please wait..." - }, - "sendingTraceroute": { - "title": "Sending Traceroute, please wait..." - }, - "tracerouteSent": { - "title": "Traceroute sent." - }, - "savedChannel": { - "title": "Saved Channel: {{channelName}}" - }, - "messages": { - "pkiEncryption": { - "title": "Chat is using PKI encryption." - }, - "pskEncryption": { - "title": "Chat is using PSK encryption." - } - }, - "configSaveError": { - "title": "Error Saving Config", - "description": "An error occurred while saving the configuration." - }, - "validationError": { - "title": "Config Errors Exist", - "description": "Please fix the configuration errors before saving." - }, - "saveSuccess": { - "title": "Saving Config", - "description": "The configuration change {{case}} has been saved." - }, - "favoriteNode": { - "title": "{{action}} {{nodeName}} {{direction}} favorites.", - "action": { - "added": "Added", - "removed": "Removed", - "to": "to", - "from": "from" - } - }, - "ignoreNode": { - "title": "{{action}} {{nodeName}} {{direction}} ignore list", - "action": { - "added": "Added", - "removed": "Removed", - "to": "to", - "from": "from" - } - } - }, - "notifications": { - "copied": { - "label": "Copied!" - }, - "copyToClipboard": { - "label": "Copy to clipboard" - }, - "hidePassword": { - "label": "Jelszó elrejtése" - }, - "showPassword": { - "label": "Jelszó megjelenítése" - }, - "deliveryStatus": { - "delivered": "Delivered", - "failed": "Delivery Failed", - "waiting": "Waiting", - "unknown": "Ismeretlen" - } - }, - "general": { - "label": "General" - }, - "hardware": { - "label": "Hardver" - }, - "metrics": { - "label": "Metrics" - }, - "role": { - "label": "Szerepkör" - }, - "filter": { - "label": "Filter" - }, - "advanced": { - "label": "Haladó" - }, - "clearInput": { - "label": "Clear input" - }, - "resetFilters": { - "label": "Reset Filters" - }, - "nodeName": { - "label": "Node name/number", - "placeholder": "Meshtastic 1234" - }, - "airtimeUtilization": { - "label": "Airtime Utilization (%)" - }, - "batteryLevel": { - "label": "Battery level (%)", - "labelText": "Battery level (%): {{value}}" - }, - "batteryVoltage": { - "label": "Battery voltage (V)", - "title": "Feszültség" - }, - "channelUtilization": { - "label": "Channel Utilization (%)" - }, - "hops": { - "direct": "Közvetlen", - "label": "Number of hops", - "text": "Number of hops: {{value}}" - }, - "lastHeard": { - "label": "Utoljára hallott", - "labelText": "Last heard: {{value}}", - "nowLabel": "Now" - }, - "snr": { - "label": "SNR (db)" - }, - "favorites": { - "label": "Favorites" - }, - "hide": { - "label": "Hide" - }, - "showOnly": { - "label": "Show Only" - }, - "viaMqtt": { - "label": "Connected via MQTT" - }, - "hopsUnknown": { - "label": "Unknown number of hops" - }, - "showUnheard": { - "label": "Never heard" - }, - "language": { - "label": "Nyelv", - "changeLanguage": "Change Language" - }, - "theme": { - "dark": "Sötét", - "light": "Világos", - "system": "Automatic", - "changeTheme": "Change Color Scheme" - }, - "errorPage": { - "title": "This is a little embarrassing...", - "description1": "We are really sorry but an error occurred in the web client that caused it to crash.
This is not supposed to happen, and we are working hard to fix it.", - "description2": "The best way to prevent this from happening again to you or anyone else is to report the issue to us.", - "reportInstructions": "Please include the following information in your report:", - "reportSteps": { - "step1": "What you were doing when the error occurred", - "step2": "What you expected to happen", - "step3": "What actually happened", - "step4": "Any other relevant information" - }, - "reportLink": "You can report the issue to our <0>GitHub", - "dashboardLink": "Return to the <0>dashboard", - "detailsSummary": "Error Details", - "errorMessageLabel": "Error message:", - "stackTraceLabel": "Stack trace:", - "fallbackError": "{{error}}" - }, - "footer": { - "text": "Powered by <0>▲ Vercel | Meshtastic® is a registered trademark of Meshtastic LLC. | <1>Legal Information", - "commitSha": "Commit SHA: {{sha}}" - } + "navigation": { + "title": "Navigation", + "messages": "Üzenetek", + "map": "Térkép", + "settings": "Beállítások", + "channels": "Csatornák", + "radioConfig": "Radio Config", + "deviceConfig": "Eszközbeállítások", + "moduleConfig": "Module Config", + "manageConnections": "Manage Connections", + "nodes": "Csomópontok" + }, + "app": { + "title": "Meshtastic", + "logo": "Meshtastic Logo" + }, + "sidebar": { + "collapseToggle": { + "button": { + "open": "Open sidebar", + "close": "Close sidebar" + } + }, + "deviceInfo": { + "volts": "{{voltage}} volts", + "firmware": { + "title": "Firmware", + "version": "v{{version}}", + "buildDate": "Build date: {{date}}" + } + } + }, + "batteryStatus": { + "charging": "{{level}}% charging", + "pluggedIn": "Plugged in", + "title": "Akkumulátor" + }, + "search": { + "nodes": "Search nodes...", + "channels": "Search channels...", + "commandPalette": "Search commands..." + }, + "toast": { + "positionRequestSent": { + "title": "Position request sent." + }, + "requestingPosition": { + "title": "Requesting position, please wait..." + }, + "sendingTraceroute": { + "title": "Sending Traceroute, please wait..." + }, + "tracerouteSent": { + "title": "Traceroute sent." + }, + "savedChannel": { + "title": "Saved Channel: {{channelName}}" + }, + "messages": { + "pkiEncryption": { + "title": "Chat is using PKI encryption." + }, + "pskEncryption": { + "title": "Chat is using PSK encryption." + } + }, + "configSaveError": { + "title": "Error Saving Config", + "description": "An error occurred while saving the configuration." + }, + "validationError": { + "title": "Config Errors Exist", + "description": "Please fix the configuration errors before saving." + }, + "saveSuccess": { + "title": "Saving Config", + "description": "The configuration change {{case}} has been saved." + }, + "saveAllSuccess": { + "title": "Saved", + "description": "All configuration changes have been saved." + }, + "favoriteNode": { + "title": "{{action}} {{nodeName}} {{direction}} favorites.", + "action": { + "added": "Added", + "removed": "Removed", + "to": "to", + "from": "from" + } + }, + "ignoreNode": { + "title": "{{action}} {{nodeName}} {{direction}} ignore list", + "action": { + "added": "Added", + "removed": "Removed", + "to": "to", + "from": "from" + } + } + }, + "notifications": { + "copied": { + "label": "Copied!" + }, + "copyToClipboard": { + "label": "Copy to clipboard" + }, + "hidePassword": { + "label": "Jelszó elrejtése" + }, + "showPassword": { + "label": "Jelszó megjelenítése" + }, + "deliveryStatus": { + "delivered": "Delivered", + "failed": "Delivery Failed", + "waiting": "Waiting", + "unknown": "Ismeretlen" + } + }, + "general": { + "label": "General" + }, + "hardware": { + "label": "Hardver" + }, + "metrics": { + "label": "Metrics" + }, + "role": { + "label": "Szerepkör" + }, + "filter": { + "label": "Filter" + }, + "advanced": { + "label": "Haladó" + }, + "clearInput": { + "label": "Clear input" + }, + "resetFilters": { + "label": "Reset Filters" + }, + "nodeName": { + "label": "Node name/number", + "placeholder": "Meshtastic 1234" + }, + "airtimeUtilization": { + "label": "Airtime Utilization (%)", + "short": "Airtime Util. (%)" + }, + "batteryLevel": { + "label": "Battery level (%)", + "labelText": "Battery level (%): {{value}}" + }, + "batteryVoltage": { + "label": "Battery voltage (V)", + "title": "Feszültség" + }, + "channelUtilization": { + "label": "Channel Utilization (%)", + "short": "Channel Util. (%)" + }, + "hops": { + "direct": "Közvetlen", + "label": "Number of hops", + "text": "Number of hops: {{value}}" + }, + "lastHeard": { + "label": "Utoljára hallott", + "labelText": "Last heard: {{value}}", + "nowLabel": "Now" + }, + "snr": { + "label": "SNR (db)" + }, + "favorites": { + "label": "Favorites" + }, + "hide": { + "label": "Hide" + }, + "showOnly": { + "label": "Show Only" + }, + "viaMqtt": { + "label": "Connected via MQTT" + }, + "hopsUnknown": { + "label": "Unknown number of hops" + }, + "showUnheard": { + "label": "Never heard" + }, + "language": { + "label": "Nyelv", + "changeLanguage": "Change Language" + }, + "theme": { + "dark": "Sötét", + "light": "Világos", + "system": "Automatic", + "changeTheme": "Change Color Scheme" + }, + "errorPage": { + "title": "This is a little embarrassing...", + "description1": "We are really sorry but an error occurred in the web client that caused it to crash.
This is not supposed to happen, and we are working hard to fix it.", + "description2": "The best way to prevent this from happening again to you or anyone else is to report the issue to us.", + "reportInstructions": "Please include the following information in your report:", + "reportSteps": { + "step1": "What you were doing when the error occurred", + "step2": "What you expected to happen", + "step3": "What actually happened", + "step4": "Any other relevant information" + }, + "reportLink": "You can report the issue to our <0>GitHub", + "connectionsLink": "Return to the <0>connections", + "detailsSummary": "Error Details", + "errorMessageLabel": "Error message:", + "stackTraceLabel": "Stack trace:", + "fallbackError": "{{error}}" + }, + "footer": { + "text": "Powered by <0>▲ Vercel | Meshtastic® is a registered trademark of Meshtastic LLC. | <1>Legal Information", + "commitSha": "Commit SHA: {{sha}}" + } } diff --git a/packages/web/public/i18n/locales/it-IT/channels.json b/packages/web/public/i18n/locales/it-IT/channels.json index 168490fd8..a61e63fee 100644 --- a/packages/web/public/i18n/locales/it-IT/channels.json +++ b/packages/web/public/i18n/locales/it-IT/channels.json @@ -1,69 +1,71 @@ { - "page": { - "sectionLabel": "Canali", - "channelName": "Canale {{channelName}}", - "broadcastLabel": "Principale", - "channelIndex": "Ch {{index}}" - }, - "validation": { - "pskInvalid": "Per favore inserisci un PSK valido di {{bits}} bit." - }, - "settings": { - "label": "Impostazioni Canale", - "description": "Impostazioni di Crypto, MQTT e varie" - }, - "role": { - "label": "Ruolo", - "description": "La telemetria del dispositivo è inviata su PRIMARIO. Solo un PRIMARIO è consentito", - "options": { - "primary": "PRIMARIO", - "disabled": "DISABILITATO", - "secondary": "SECONDARIO" - } - }, - "psk": { - "label": "Chiave Pre-Condivisa", - "description": "Lunghezze PSK supportate: 256-bit, 128-bit, 8-bit, Vuoto (0-bit)", - "generate": "Genera" - }, - "name": { - "label": "Nome", - "description": "Un nome univoco per il canale <12 byte, lascia vuoto per default" - }, - "uplinkEnabled": { - "label": "Uplink Abilitato", - "description": "Invia messaggi dalla mesh locale a MQTT" - }, - "downlinkEnabled": { - "label": "Uplink Abilitato", - "description": "Invia messaggi da MQTT alla mesh locale" - }, - "positionPrecision": { - "label": "Posizione", - "description": "La precisione della posizione da condividere con il canale. Può essere disabilitata.", - "options": { - "none": "Non condividere la posizione", - "precise": "Posizione precisa", - "metric_km23": "Entro 23 chilometri", - "metric_km12": "Entro 12 chilometri", - "metric_km5_8": "Entro 5,8 chilometri", - "metric_km2_9": "Entro 2,9 chilometri", - "metric_km1_5": "Entro 1,5 chilometri", - "metric_m700": "Entro 700 metri", - "metric_m350": "Entro 350 metri", - "metric_m200": "Entro 200 metri", - "metric_m90": "Entro 90 metri", - "metric_m50": "Entro 50 metri", - "imperial_mi15": "Entro 15 miglia", - "imperial_mi7_3": "Entro 7,3 miglia", - "imperial_mi3_6": "Entro 3,6 miglia", - "imperial_mi1_8": "Entro 1,8 miglia", - "imperial_mi0_9": "Entro 0,9 miglia", - "imperial_mi0_5": "Entro 0,5 miglia", - "imperial_mi0_2": "Entro 0,2 miglia", - "imperial_ft600": "Entro 600 piedi", - "imperial_ft300": "Entro 300 piedi", - "imperial_ft150": "Entro 150 piedi" - } - } + "page": { + "sectionLabel": "Canali", + "channelName": "Canale {{channelName}}", + "broadcastLabel": "Principale", + "channelIndex": "Ch {{index}}", + "import": "Importa", + "export": "Esporta" + }, + "validation": { + "pskInvalid": "Per favore inserisci un PSK valido di {{bits}} bit." + }, + "settings": { + "label": "Impostazioni Canale", + "description": "Impostazioni di Crypto, MQTT e varie" + }, + "role": { + "label": "Ruolo", + "description": "La telemetria del dispositivo è inviata su PRIMARIO. Solo un PRIMARIO è consentito", + "options": { + "primary": "PRIMARIO", + "disabled": "DISABILITATO", + "secondary": "SECONDARIO" + } + }, + "psk": { + "label": "Chiave Pre-Condivisa", + "description": "Lunghezze PSK supportate: 256-bit, 128-bit, 8-bit, Vuoto (0-bit)", + "generate": "Genera" + }, + "name": { + "label": "Nome", + "description": "Un nome univoco per il canale <12 byte, lascia vuoto per default" + }, + "uplinkEnabled": { + "label": "Uplink Abilitato", + "description": "Invia messaggi dalla mesh locale a MQTT" + }, + "downlinkEnabled": { + "label": "Uplink Abilitato", + "description": "Invia messaggi da MQTT alla mesh locale" + }, + "positionPrecision": { + "label": "Posizione", + "description": "La precisione della posizione da condividere con il canale. Può essere disabilitata.", + "options": { + "none": "Non condividere la posizione", + "precise": "Posizione precisa", + "metric_km23": "Entro 23 chilometri", + "metric_km12": "Entro 12 chilometri", + "metric_km5_8": "Entro 5,8 chilometri", + "metric_km2_9": "Entro 2,9 chilometri", + "metric_km1_5": "Entro 1,5 chilometri", + "metric_m700": "Entro 700 metri", + "metric_m350": "Entro 350 metri", + "metric_m200": "Entro 200 metri", + "metric_m90": "Entro 90 metri", + "metric_m50": "Entro 50 metri", + "imperial_mi15": "Entro 15 miglia", + "imperial_mi7_3": "Entro 7,3 miglia", + "imperial_mi3_6": "Entro 3,6 miglia", + "imperial_mi1_8": "Entro 1,8 miglia", + "imperial_mi0_9": "Entro 0,9 miglia", + "imperial_mi0_5": "Entro 0,5 miglia", + "imperial_mi0_2": "Entro 0,2 miglia", + "imperial_ft600": "Entro 600 piedi", + "imperial_ft300": "Entro 300 piedi", + "imperial_ft150": "Entro 150 piedi" + } + } } diff --git a/packages/web/public/i18n/locales/it-IT/commandPalette.json b/packages/web/public/i18n/locales/it-IT/commandPalette.json index 9c48bf15f..4daa31229 100644 --- a/packages/web/public/i18n/locales/it-IT/commandPalette.json +++ b/packages/web/public/i18n/locales/it-IT/commandPalette.json @@ -15,7 +15,6 @@ "messages": "Messaggi", "map": "Mappa", "config": "Configurazione", - "channels": "Canali", "nodes": "Nodi" } }, @@ -45,7 +44,8 @@ "label": "Debug", "command": { "reconfigure": "Riconfigura", - "clearAllStoredMessages": "Cancella Tutti i Messaggi Memorizzati" + "clearAllStoredMessages": "Cancella Tutti i Messaggi Memorizzati", + "clearAllStores": "Clear All Local Storage" } } } diff --git a/packages/web/public/i18n/locales/it-IT/common.json b/packages/web/public/i18n/locales/it-IT/common.json index aa0ae3b07..91d2d8aa1 100644 --- a/packages/web/public/i18n/locales/it-IT/common.json +++ b/packages/web/public/i18n/locales/it-IT/common.json @@ -1,142 +1,165 @@ { - "button": { - "apply": "Applica", - "backupKey": "Backup della chiave", - "cancel": "Annulla", - "clearMessages": "Cancella Messaggi", - "close": "Chiudi", - "confirm": "Conferma", - "delete": "Elimina", - "dismiss": "Annulla", - "download": "Scarica", - "export": "Esporta", - "generate": "Genera", - "regenerate": "Rigenera", - "import": "Importa", - "message": "Messaggio", - "now": "Adesso", - "ok": "Ok", - "print": "Stampa", - "remove": "Elimina", - "requestNewKeys": "Richiedi Nuove Chiavi", - "requestPosition": "Richiedi posizione", - "reset": "Reset", - "save": "Salva", - "scanQr": "Scansiona codice QR", - "traceRoute": "Trace Route", - "submit": "Submit" - }, - "app": { - "title": "Meshtastic", - "fullTitle": "Meshtastic Web Client" - }, - "loading": "Caricamento in corso...", - "unit": { - "cps": "CPS", - "dbm": "dBm", - "hertz": "Hz", - "hop": { - "one": "Hop", - "plural": "Hops" - }, - "hopsAway": { - "one": "A {{count}} hop di distanza", - "plural": "A {{count}} hop di distanza", - "unknown": "Hop sconosciuti" - }, - "megahertz": "MHz", - "raw": "grezzo", - "meter": { - "one": "Metro", - "plural": "Metri", - "suffix": "m" - }, - "minute": { - "one": "Minuto", - "plural": "Minuti" - }, - "hour": { - "one": "Hour", - "plural": "Hours" - }, - "millisecond": { - "one": "Millisecondo", - "plural": "Millisecondi", - "suffix": "ms" - }, - "second": { - "one": "Secondo", - "plural": "Secondi" - }, - "day": { - "one": "Day", - "plural": "Days" - }, - "month": { - "one": "Month", - "plural": "Months" - }, - "year": { - "one": "Year", - "plural": "Years" - }, - "snr": "SNR", - "volt": { - "one": "Volt", - "plural": "Volt", - "suffix": "V" - }, - "record": { - "one": "Record", - "plural": "Record" - } - }, - "security": { - "0bit": "Empty", - "8bit": "8 bit", - "128bit": "128 bit", - "256bit": "256 bit" - }, - "unknown": { - "longName": "Sconosciuto", - "shortName": "SCON", - "notAvailable": "N/D", - "num": "??" - }, - "nodeUnknownPrefix": "!", - "unset": "ANNULLA", - "fallbackName": "Meshtastic {{last4}}", - "node": "Node", - "formValidation": { - "unsavedChanges": "Unsaved changes", - "tooBig": { - "string": "Troppo lungo, atteso minore o uguale a {{maximum}} caratteri.", - "number": "Troppo grande, ci si aspetta un numero minore o uguale a {{maximum}}.", - "bytes": "Troppo grande, atteso inferiore o uguale a {{params.maximum}} byte." - }, - "tooSmall": { - "string": "Troppo breve, atteso più di o uguale a {{minimum}} caratteri.", - "number": "Troppo piccolo, atteso un numero maggiore o uguale a {{minimum}}." - }, - "invalidFormat": { - "ipv4": "Formato non valido, previsto un indirizzo IPv4.", - "key": "Formato non valido, prevista una chiave pre-condivisa codificata Base64 (PSK)." - }, - "invalidType": { - "number": "Tipo non valido, atteso un numero." - }, - "pskLength": { - "0bit": "La chiave deve essere vuota.", - "8bit": "La chiave deve essere una chiave pre-condivisa a 8 bit (PSK).", - "128bit": "La chiave deve essere una chiave pre-condivisa a 128 bit (PSK).", - "256bit": "La chiave deve essere una chiave pre-condivisa a 256 bit (PSK)." - }, - "required": { - "generic": "Questo campo è obbligatorio.", - "managed": "Se il nodo è gestito, è richiesta almeno una chiave amministrativa.", - "key": "La chiave è obbligatoria." - } - }, - "yes": "Sì", - "no": "No" + "button": { + "apply": "Applica", + "addConnection": "Add Connection", + "saveConnection": "Save connection", + "backupKey": "Backup della chiave", + "cancel": "Annulla", + "connect": "Connetti", + "clearMessages": "Cancella Messaggi", + "close": "Chiudi", + "confirm": "Conferma", + "delete": "Elimina", + "dismiss": "Annulla", + "download": "Scarica", + "disconnect": "Disconnetti", + "export": "Esporta", + "generate": "Genera", + "regenerate": "Rigenera", + "import": "Importa", + "message": "Messaggio", + "now": "Adesso", + "ok": "Ok", + "print": "Stampa", + "remove": "Elimina", + "requestNewKeys": "Richiedi Nuove Chiavi", + "requestPosition": "Richiedi posizione", + "reset": "Reset", + "retry": "Retry", + "save": "Salva", + "setDefault": "Set as default", + "unsetDefault": "Unset default", + "scanQr": "Scansiona codice QR", + "traceRoute": "Trace Route", + "submit": "Submit" + }, + "app": { + "title": "Meshtastic", + "fullTitle": "Meshtastic Web Client" + }, + "loading": "Caricamento in corso...", + "unit": { + "cps": "CPS", + "dbm": "dBm", + "hertz": "Hz", + "hop": { + "one": "Hop", + "plural": "Hops" + }, + "hopsAway": { + "one": "A {{count}} hop di distanza", + "plural": "A {{count}} hop di distanza", + "unknown": "Hop sconosciuti" + }, + "megahertz": "MHz", + "kilohertz": "kHz", + "raw": "grezzo", + "meter": { + "one": "Metro", + "plural": "Metri", + "suffix": "m" + }, + "kilometer": { + "one": "Kilometer", + "plural": "Kilometers", + "suffix": "km" + }, + "minute": { + "one": "Minuto", + "plural": "Minuti" + }, + "hour": { + "one": "Hour", + "plural": "Hours" + }, + "millisecond": { + "one": "Millisecondo", + "plural": "Millisecondi", + "suffix": "ms" + }, + "second": { + "one": "Secondo", + "plural": "Secondi" + }, + "day": { + "one": "Day", + "plural": "Days", + "today": "Today", + "yesterday": "Yesterday" + }, + "month": { + "one": "Month", + "plural": "Months" + }, + "year": { + "one": "Year", + "plural": "Years" + }, + "snr": "SNR", + "volt": { + "one": "Volt", + "plural": "Volt", + "suffix": "V" + }, + "record": { + "one": "Record", + "plural": "Record" + }, + "degree": { + "one": "Degree", + "plural": "Degrees", + "suffix": "°" + } + }, + "security": { + "0bit": "Empty", + "8bit": "8 bit", + "128bit": "128 bit", + "256bit": "256 bit" + }, + "unknown": { + "longName": "Sconosciuto", + "shortName": "SCON", + "notAvailable": "N/D", + "num": "??" + }, + "nodeUnknownPrefix": "!", + "unset": "ANNULLA", + "fallbackName": "Meshtastic {{last4}}", + "node": "Node", + "formValidation": { + "unsavedChanges": "Unsaved changes", + "tooBig": { + "string": "Troppo lungo, atteso minore o uguale a {{maximum}} caratteri.", + "number": "Troppo grande, ci si aspetta un numero minore o uguale a {{maximum}}.", + "bytes": "Troppo grande, atteso inferiore o uguale a {{params.maximum}} byte." + }, + "tooSmall": { + "string": "Troppo breve, atteso più di o uguale a {{minimum}} caratteri.", + "number": "Troppo piccolo, atteso un numero maggiore o uguale a {{minimum}}." + }, + "invalidFormat": { + "ipv4": "Formato non valido, previsto un indirizzo IPv4.", + "key": "Formato non valido, prevista una chiave pre-condivisa codificata Base64 (PSK)." + }, + "invalidType": { + "number": "Tipo non valido, atteso un numero." + }, + "pskLength": { + "0bit": "La chiave deve essere vuota.", + "8bit": "La chiave deve essere una chiave pre-condivisa a 8 bit (PSK).", + "128bit": "La chiave deve essere una chiave pre-condivisa a 128 bit (PSK).", + "256bit": "La chiave deve essere una chiave pre-condivisa a 256 bit (PSK)." + }, + "required": { + "generic": "Questo campo è obbligatorio.", + "managed": "Se il nodo è gestito, è richiesta almeno una chiave amministrativa.", + "key": "La chiave è obbligatoria." + }, + "invalidOverrideFreq": { + "number": "Invalid format, expected a value in the range 410-930 MHz or 0 (use default)." + } + }, + "yes": "Sì", + "no": "No" } diff --git a/packages/web/public/i18n/locales/it-IT/config.json b/packages/web/public/i18n/locales/it-IT/config.json new file mode 100644 index 000000000..2fe77c300 --- /dev/null +++ b/packages/web/public/i18n/locales/it-IT/config.json @@ -0,0 +1,458 @@ +{ + "page": { + "title": "Impostazioni", + "tabUser": "Utente", + "tabChannels": "Canali", + "tabBluetooth": "Bluetooth", + "tabDevice": "Dispositivo", + "tabDisplay": "Schermo", + "tabLora": "LoRa", + "tabNetwork": "Rete", + "tabPosition": "Posizione", + "tabPower": "Alimentazione", + "tabSecurity": "Sicurezza" + }, + "sidebar": { + "label": "Configurazione" + }, + "device": { + "title": "Impostazioni del dispositivo", + "description": "Le impostazioni del dispositivo", + "buttonPin": { + "description": "Sovrascrivi pin pulsante", + "label": "Pulsante Pin" + }, + "buzzerPin": { + "description": "Sovrascrivi pin buzzer", + "label": "Pin Buzzer" + }, + "disableTripleClick": { + "description": "Disabilita triplo-click", + "label": "Disabilita triplo-click" + }, + "doubleTapAsButtonPress": { + "description": "Tratta il doppio tocco come pressione pulsante", + "label": "Doppio tocco come pressione pulsante" + }, + "ledHeartbeatDisabled": { + "description": "Disabilita il LED lampeggiante predefinito", + "label": "LED Heartbeat Disabilitato" + }, + "nodeInfoBroadcastInterval": { + "description": "Quante volte trasmettere informazioni sul nodo", + "label": "Intervallo Di Trasmissione Info Nodo" + }, + "posixTimezone": { + "description": "La stringa di fuso orario POSIX per il dispositivo", + "label": "POSIX Timezone" + }, + "rebroadcastMode": { + "description": "Come gestire il rebroadcasting", + "label": "Modalità Rebroadcast" + }, + "role": { + "description": "Quale ruolo il dispositivo svolge sulla mesh", + "label": "Ruolo" + } + }, + "bluetooth": { + "title": "Impostazioni Bluetooth", + "description": "Impostazioni per il modulo Bluetooth", + "note": "Nota: alcuni dispositivi (ESP32) non possono utilizzare contemporaneamente Bluetooth e WiFi.", + "enabled": { + "description": "Abilita o disabilita Bluetooth", + "label": "Abilitato" + }, + "pairingMode": { + "description": "Comportamento di selezione pin.", + "label": "Modalità abbinamento" + }, + "pin": { + "description": "Pin da usare durante l'abbinamento", + "label": "Pin" + } + }, + "display": { + "description": "Impostazioni per il display del dispositivo", + "title": "Impostazioni Display", + "headingBold": { + "description": "Metti in grassetto il testo dell'intestazione", + "label": "Intestazione in grassetto" + }, + "carouselDelay": { + "description": "Quanto velocemente scorrere attraverso le finestre", + "label": "Ritardo Carosello" + }, + "compassNorthTop": { + "description": "Fissare il nord fino alla parte superiore della bussola", + "label": "Bussola Nord In Alto" + }, + "displayMode": { + "description": "Variante layout schermo", + "label": "Modalità di visualizzazione" + }, + "displayUnits": { + "description": "Mostra unità metriche o imperiali", + "label": "Mostra Unità" + }, + "flipScreen": { + "description": "Rifletti la visualizzazione di 180 gradi", + "label": "Capovolgi schermo" + }, + "gpsDisplayUnits": { + "description": "Formato coordinate", + "label": "Unità Display GPS" + }, + "oledType": { + "description": "Tipo di schermo OLED collegato al dispositivo", + "label": "Tipo OLED" + }, + "screenTimeout": { + "description": "Spegni lo schermo dopo questo lungo periodo", + "label": "Timeout Schermo" + }, + "twelveHourClock": { + "description": "Usa formato orologio 12 ore", + "label": "Orologio 12 Ore" + }, + "wakeOnTapOrMotion": { + "description": "Risveglia il dispositivo al tocco o al movimento", + "label": "Sveglia al tocco o al movimento" + } + }, + "lora": { + "title": "Impostazioni Mesh", + "description": "Impostazioni per la mesh LoRa", + "bandwidth": { + "description": "Larghezza di banda del canale in kHz", + "label": "Larghezza di banda" + }, + "boostedRxGain": { + "description": "Guadagno RX potenziato", + "label": "Guadagno RX potenziato" + }, + "codingRate": { + "description": "Il denominatore della velocità di codifica", + "label": "Velocità di codifica" + }, + "frequencyOffset": { + "description": "Offset di frequenza per correggere gli errori di calibrazione del cristallo", + "label": "Offset Di Frequenza" + }, + "frequencySlot": { + "description": "Numero canale di frequenza LoRa", + "label": "Slot di frequenza" + }, + "hopLimit": { + "description": "Numero massimo di hop", + "label": "Limite di hop" + }, + "ignoreMqtt": { + "description": "Non inoltrare i messaggi MQTT sulla mesh", + "label": "Ignora MQTT" + }, + "modemPreset": { + "description": "Preimpostazione modem da usare", + "label": "Configurazione Modem" + }, + "okToMqtt": { + "description": "Quando impostato su true, questa configurazione indica che l'utente approva il caricamento del pacchetto su MQTT. Se impostato su false, ai nodi remoti viene richiesto di non inoltrare i pacchetti a MQTT", + "label": "OK per MQTT" + }, + "overrideDutyCycle": { + "description": "Ignora limite di Duty Cycle", + "label": "Ignora limite di Duty Cycle" + }, + "overrideFrequency": { + "description": "Sovrascrivi frequenza", + "label": "Sovrascrivi frequenza" + }, + "region": { + "description": "Imposta la regione del tuo nodo", + "label": "Regione" + }, + "spreadingFactor": { + "description": "Indica il numero di chirp per simbolo", + "label": "Spreading Factor" + }, + "transmitEnabled": { + "description": "Abilita/Disabilita la trasmissione (TX) dalla radio LoRa", + "label": "Trasmissione Abilitata" + }, + "transmitPower": { + "description": "Potenza massima di trasmissione", + "label": "Potenza Di Trasmissione" + }, + "usePreset": { + "description": "Usa una delle preimpostazioni predefinite del modem", + "label": "Utilizza il preset" + }, + "meshSettings": { + "description": "Impostazioni per la mesh LoRa", + "label": "Impostazioni Mesh" + }, + "waveformSettings": { + "description": "Impostazioni per la forma d'onda LoRa", + "label": "Impostazioni Forma d'onda" + }, + "radioSettings": { + "label": "Impostazioni Radio", + "description": "Impostazioni per la radio LoRa" + } + }, + "network": { + "title": "Configurazione WiFi", + "description": "Configurazione radio WiFi", + "note": "Nota: alcuni dispositivi (ESP32) non possono utilizzare contemporaneamente Bluetooth e WiFi.", + "addressMode": { + "description": "Selezione assegnazione indirizzo", + "label": "Modalità Indirizzo" + }, + "dns": { + "description": "Server DNS", + "label": "DNS" + }, + "ethernetEnabled": { + "description": "Abilita o disabilita la porta Ethernet", + "label": "Abilitato" + }, + "gateway": { + "description": "Gateway predefinito", + "label": "Gateway" + }, + "ip": { + "description": "Indirizzo IP", + "label": "IP" + }, + "psk": { + "description": "Password di rete", + "label": "PSK" + }, + "ssid": { + "description": "Nome rete", + "label": "SSID" + }, + "subnet": { + "description": "Subnet mask", + "label": "Subnet" + }, + "wifiEnabled": { + "description": "Abilita o disabilita la radio WiFi", + "label": "Abilitato" + }, + "meshViaUdp": { + "label": "Mesh via UDP" + }, + "ntpServer": { + "label": "Server NTP" + }, + "rsyslogServer": { + "label": "Server rsyslog" + }, + "ethernetConfigSettings": { + "description": "Configurazione porta Ethernet", + "label": "Configurazione Ethernet" + }, + "ipConfigSettings": { + "description": "Configurazione IP", + "label": "Configurazione IP" + }, + "ntpConfigSettings": { + "description": "Configurazione NTP", + "label": "Configurazione NTP" + }, + "rsyslogConfigSettings": { + "description": "Configurazione di Rsyslog", + "label": "Configurazione di Rsyslog" + }, + "udpConfigSettings": { + "description": "Configurazione UDP over Mesh", + "label": "Configurazione UDP" + } + }, + "position": { + "title": "Impostazioni Posizione", + "description": "Impostazioni per il modulo di posizione", + "broadcastInterval": { + "description": "Quante volte la tua posizione viene inviata attraverso la mesh", + "label": "Intervallo Di Trasmissione" + }, + "enablePin": { + "description": "Modulo GPS abilita pin override", + "label": "Abilita Pin" + }, + "fixedPosition": { + "description": "Non segnalare la posizione GPS, ma specificane una manualmente", + "label": "Posizione Fissa" + }, + "gpsMode": { + "description": "Configura se il GPS del dispositivo è abilitato, disabilitato o non presente", + "label": "Modalità GPS" + }, + "gpsUpdateInterval": { + "description": "Quante volte una correzione GPS dovrebbe essere acquisita", + "label": "Intervallo di aggiornamento GPS" + }, + "positionFlags": { + "description": "Campi opzionali da includere quando si assemblano messaggi di posizione. Più i campi sono selezionati, più grande sarà il messaggio porterà a un utilizzo più lungo del tempo di volo e un rischio più elevato di perdite dei pacchetti.", + "label": "Flag Di Posizione" + }, + "receivePin": { + "description": "Sovrascrivi RX pin del Modulo GPS", + "label": "Pin di ricezione" + }, + "smartPositionEnabled": { + "description": "Invia posizione solo quando c'è stato un cambiamento significativo nella posizione", + "label": "Abilita Posizione Intelligente" + }, + "smartPositionMinDistance": { + "description": "Distanza minima (in metri) che deve essere percorsa prima di inviare un aggiornamento di posizione", + "label": "Distanza Minima Posizione Intelligente" + }, + "smartPositionMinInterval": { + "description": "Intervallo minimo (in secondi) che deve passare prima di inviare un aggiornamento della posizione", + "label": "Intervallo Minimo Posizione Intelligente" + }, + "transmitPin": { + "description": "Sovrascrivi TX pin del Modulo GPS", + "label": "Pin di trasmissione" + }, + "intervalsSettings": { + "description": "Quante volte inviare aggiornamenti di posizione", + "label": "Intervalli" + }, + "flags": { + "placeholder": "Seleziona flag di posizione...", + "altitude": "Altitudine", + "altitudeGeoidalSeparation": "Altitudine Separazione Geoidale", + "altitudeMsl": "L'altitudine è riferita al livello medio del mare", + "dop": "Diluizione del PDOP di precisione (DOP) utilizzato per impostazione predefinita", + "hdopVdop": "Se DOP è impostato, usa i valori HDOP / VDOP invece di PDOP", + "numSatellites": "Numero di satelliti", + "sequenceNumber": "Numero sequenza", + "timestamp": "Data e ora", + "unset": "Non impostato", + "vehicleHeading": "Direzione del veicolo", + "vehicleSpeed": "Velocità del veicolo" + } + }, + "power": { + "adcMultiplierOverride": { + "description": "Utilizzato per modificare la lettura della tensione della batteria", + "label": "Sovrascrivi rapporto moltiplicatore ADC" + }, + "ina219Address": { + "description": "Indirizzo del monitor batteria INA219", + "label": "Indirizzo INA219" + }, + "lightSleepDuration": { + "description": "Per quanto tempo il dispositivo sarà in light sleep", + "label": "Durata light sleep" + }, + "minimumWakeTime": { + "description": "Quantità minima di tempo che il dispositivo rimarrà attivo per dopo aver ricevuto un pacchetto", + "label": "Tempo Di Risveglio Minimo" + }, + "noConnectionBluetoothDisabled": { + "description": "Se il dispositivo non riceve una connessione Bluetooth, la radio BLE sarà disattivata dopo questo lungo periodo", + "label": "Nessuna Connessione Bluetooth Disabilitata" + }, + "powerSavingEnabled": { + "description": "Selezionare se alimentato da una fonte a bassa corrente (cioè solare) per minimizzare il consumo energetico il più possibile.", + "label": "Abilita modalità risparmio energetico" + }, + "shutdownOnBatteryDelay": { + "description": "Spegnimento automatico del nodo dopo questo lungo quando la batteria, 0 per indefinito", + "label": "Arresto in ritardo della batteria" + }, + "superDeepSleepDuration": { + "description": "Per quanto tempo il dispositivo sarà in deep sleep", + "label": "Durata Super Deep Sleep" + }, + "powerConfigSettings": { + "description": "Impostazioni per il modulo di alimentazione", + "label": "Configurazione Alimentazione" + }, + "sleepSettings": { + "description": "Impostazioni di sospensione per il modulo di alimentazione", + "label": "Impostazioni Sleep" + } + }, + "security": { + "description": "Impostazioni per la configurazione di sicurezza", + "title": "Impostazioni di Sicurezza", + "button_backupKey": "Chiave Di Backup", + "adminChannelEnabled": { + "description": "Consenti il controllo del dispositivo in arrivo sul canale di amministrazione ereditato insicuro", + "label": "Consenti Amministrazione Legacy" + }, + "enableDebugLogApi": { + "description": "Output live debug logging su seriale, visualizza ed esporta i log di posizione dei dispositivi redatti su Bluetooth", + "label": "Abilita Debug Log API" + }, + "managed": { + "description": "Se abilitata, le opzioni di configurazione del dispositivo possono essere modificate solo in remoto da un nodo di amministrazione remota tramite messaggi amministratori. Non abilitare questa opzione a meno che non sia stato configurato almeno un nodo Admin Remoto adatto, e la chiave pubblica è memorizzata in uno dei campi precedenti.", + "label": "Gestito" + }, + "privateKey": { + "description": "Usato per creare una chiave condivisa con un dispositivo remoto", + "label": "Chiave Privata" + }, + "publicKey": { + "description": "Inviato ad altri nodi sulla mesh per consentire loro di calcolare una chiave segreta condivisa", + "label": "Chiave Pubblica" + }, + "primaryAdminKey": { + "description": "La chiave pubblica primaria autorizzata a inviare messaggi di amministrazione a questo nodo", + "label": "Chiave Primaria Dell'Amministratore" + }, + "secondaryAdminKey": { + "description": "La chiave pubblica secondaria autorizzata a inviare messaggi di amministrazione a questo nodo", + "label": "Chiave Secondaria Dell'Amministratore" + }, + "serialOutputEnabled": { + "description": "Console seriale attraverso la Stream API", + "label": "Output Seriale Abilitato" + }, + "tertiaryAdminKey": { + "description": "La chiave pubblica terziaria autorizzata a inviare messaggi di amministrazione a questo nodo", + "label": "Chiave Di Amministrazione Terziaria" + }, + "adminSettings": { + "description": "Impostazioni per Amministratore", + "label": "Impostazioni Amministratore" + }, + "loggingSettings": { + "description": "Impostazioni per il logging", + "label": "Impostazioni Di Logging" + } + }, + "user": { + "title": "User Settings", + "description": "Configure your device name and identity settings", + "longName": { + "label": "Nome Lungo", + "description": "Your full display name (1-40 characters)", + "validation": { + "min": "Long name must be at least 1 character", + "max": "Long name must be at most 40 characters" + } + }, + "shortName": { + "label": "Nome Breve", + "description": "Your abbreviated name (2-4 characters)", + "validation": { + "min": "Short name must be at least 2 characters", + "max": "Short name must be at most 4 characters" + } + }, + "isUnmessageable": { + "label": "Non messaggabile", + "description": "Used to identify unmonitored or infrastructure nodes so that messaging is not available to nodes that will never respond." + }, + "isLicensed": { + "label": "Radioamatori con licenza (HAM)", + "description": "Enable if you are a licensed amateur radio operator, enabling this option disables encryption and is not compatible with the default Meshtastic network." + } + } +} diff --git a/packages/web/public/i18n/locales/it-IT/connections.json b/packages/web/public/i18n/locales/it-IT/connections.json new file mode 100644 index 000000000..07796f3b6 --- /dev/null +++ b/packages/web/public/i18n/locales/it-IT/connections.json @@ -0,0 +1,34 @@ +{ + "page": { + "title": "Connect to a Meshtastic device", + "description": "Add a device connection via HTTP, Bluetooth, or Serial. Your saved connections will be saved in your browser." + }, + "connectionType_ble": "BLE", + "connectionType_serial": "Seriale", + "connectionType_network": "Rete", + "deleteConnection": "Delete connection", + "areYouSure": "This will remove {{name}}. You canot undo this action.", + "moreActions": "More actions", + "noConnections": { + "title": "No connections yet.", + "description": "Create your first connection. It will connect immediately and be saved for later." + }, + "lastConnectedAt": "Last connected: {{date}}", + "neverConnected": "Never connected", + "toasts": { + "connected": "Connesso", + "nowConnected": "{{name}} is now connected", + "nowDisconnected": "{{name}} are now disconnecte", + "disconnected": "Disconnesso", + "failed": "Failed to connect", + "checkConnetion": "Check your device or settings and try again", + "defaultSet": "Default set", + "defaultConnection": "Default connection is now {{nameisconnected}}", + "deleted": "Deleted", + "deletedByName": "{{name}} was removed", + "pickConnectionAgain": "Could not connect. You may need to reselect the device/port.", + "added": "Connection added", + "savedByName": "{{name}} saved.", + "savedCantConnect": "The connection was saved but could not connect." + } +} diff --git a/packages/web/public/i18n/locales/it-IT/dashboard.json b/packages/web/public/i18n/locales/it-IT/dashboard.json deleted file mode 100644 index e92dc5adc..000000000 --- a/packages/web/public/i18n/locales/it-IT/dashboard.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "dashboard": { - "title": "Dispositivi Connessi", - "description": "Gestisci i tuoi dispositivi Meshtastic collegati.", - "connectionType_ble": "BLE", - "connectionType_serial": "Seriale", - "connectionType_network": "Rete", - "noDevicesTitle": "Nessun dispositivo connesso", - "noDevicesDescription": "Connetti un nuovo dispositivo per iniziare.", - "button_newConnection": "Nuova connessione" - } -} diff --git a/packages/web/public/i18n/locales/it-IT/deviceConfig.json b/packages/web/public/i18n/locales/it-IT/deviceConfig.json index 24ad462b0..3978782b7 100644 --- a/packages/web/public/i18n/locales/it-IT/deviceConfig.json +++ b/packages/web/public/i18n/locales/it-IT/deviceConfig.json @@ -122,7 +122,7 @@ "title": "Impostazioni Mesh", "description": "Impostazioni per la mesh LoRa", "bandwidth": { - "description": "Larghezza di banda del canale in MHz", + "description": "Larghezza di banda del canale in kHz", "label": "Larghezza di banda" }, "boostedRxGain": { diff --git a/packages/web/public/i18n/locales/it-IT/dialog.json b/packages/web/public/i18n/locales/it-IT/dialog.json index f7bac97aa..9124b0dcf 100644 --- a/packages/web/public/i18n/locales/it-IT/dialog.json +++ b/packages/web/public/i18n/locales/it-IT/dialog.json @@ -1,193 +1,238 @@ { - "deleteMessages": { - "description": "Questa azione cancellerà tutta la cronologia dei messaggi. Non può essere annullata. Sei sicuro di voler continuare?", - "title": "Cancella Tutti I Messaggi" - }, - "deviceName": { - "description": "Il dispositivo verrà riavviato una volta salvata la configurazione.", - "longName": "Nome Lungo", - "shortName": "Nome Breve", - "title": "Cambia Nome Dispositivo", - "validation": { - "longNameMax": "Long name must not be more than 40 characters", - "shortNameMax": "Short name must not be more than 4 characters", - "longNameMin": "Long name must have at least 1 character", - "shortNameMin": "Short name must have at least 1 character" - } - }, - "import": { - "description": "La configurazione attuale di LoRa sarà sovrascritta.", - "error": { - "invalidUrl": "URL Meshtastic non valido" - }, - "channelPrefix": "Canale: ", - "channelSetUrl": "URL del Set di Canali/Codice QR", - "channels": "Canali:", - "usePreset": "Utilizza il preset?", - "title": "Importa Set Canale" - }, - "locationResponse": { - "title": "Posizione: {{identifier}}", - "altitude": "Altitudine: ", - "coordinates": "Coordinate: ", - "noCoordinates": "No Coordinates" - }, - "pkiRegenerateDialog": { - "title": "Rigenerare La Chiave Pre-Condivisa?", - "description": "Sei sicuro di voler rigenerare la chiave pre-condivisa?", - "regenerate": "Rigenera" - }, - "newDeviceDialog": { - "title": "Connetti Nuovo Dispositivo", - "https": "https", - "http": "http", - "tabHttp": "HTTP", - "tabBluetooth": "Bluetooth", - "tabSerial": "Seriale", - "useHttps": "Usa HTTPS", - "connecting": "Connessione in corso...", - "connect": "Connetti", - "connectionFailedAlert": { - "title": "Connessione fallita", - "descriptionPrefix": "Impossibile connettersi al dispositivo.", - "httpsHint": "Se si utilizza HTTPS, potrebbe essere necessario prima accettare un certificato autofirmato. ", - "openLinkPrefix": "Apri per favore ", - "openLinkSuffix": " in una nuova scheda", - "acceptTlsWarningSuffix": ", accetta eventuali avvisi TLS se richiesto, quindi riprova", - "learnMoreLink": "Maggiori informazioni" - }, - "httpConnection": { - "label": "Indirizzo IP/Hostname", - "placeholder": "000.000.000.000 / meshtastic.local" - }, - "serialConnection": { - "noDevicesPaired": "Nessun dispositivo ancora abbinato.", - "newDeviceButton": "Nuovo dispositivo", - "deviceIdentifier": "# {{index}} - {{vendorId}} - {{productId}}" - }, - "bluetoothConnection": { - "noDevicesPaired": "Nessun dispositivo ancora abbinato.", - "newDeviceButton": "Nuovo dispositivo", - "connectionFailed": "Connection failed", - "deviceDisconnected": "Device disconnected", - "unknownDevice": "Unknown Device", - "errorLoadingDevices": "Error loading devices", - "unknownErrorLoadingDevices": "Unknown error loading devices" - }, - "validation": { - "requiresWebBluetooth": "This connection type requires <0>Web Bluetooth. Please use a supported browser, like Chrome or Edge.", - "requiresWebSerial": "This connection type requires <0>Web Serial. Please use a supported browser, like Chrome or Edge.", - "requiresSecureContext": "Questa applicazione richiede un <0>contesto sicuro. Si prega di connettersi utilizzando HTTPS o localhost.", - "additionallyRequiresSecureContext": "Inoltre, richiede un <0>contesto sicuro. Si prega di connettersi utilizzando HTTPS o localhost." - } - }, - "nodeDetails": { - "message": "Messaggio", - "requestPosition": "Richiedi posizione", - "traceRoute": "Trace Route", - "airTxUtilization": "Tempo di Trasmissione Utilizzato", - "allRawMetrics": "Tutte Le Metriche Grezze:", - "batteryLevel": "Livello batteria", - "channelUtilization": "Utilizzo Canale", - "details": "Dettagli:", - "deviceMetrics": "Metriche Dispositivo:", - "hardware": "Hardware: ", - "lastHeard": "Ultimo Contatto: ", - "nodeHexPrefix": "Node Hex: ", - "nodeNumber": "Numero Nodo: ", - "position": "Posizione:", - "role": "Ruolo: ", - "uptime": "Tempo di attività: ", - "voltage": "Tensione", - "title": "Dettagli nodo per {{identifier}}", - "ignoreNode": "Ignora nodo", - "removeNode": "Rimuovi Nodo", - "unignoreNode": "Non ignorare più nodo", - "security": "Security:", - "publicKey": "Public Key: ", - "messageable": "Messageable: ", - "KeyManuallyVerifiedTrue": "Public Key has been manually verified", - "KeyManuallyVerifiedFalse": "Public Key is not manually verified" - }, - "pkiBackup": { - "loseKeysWarning": "Se perdi le tue chiavi, dovrai reimpostare il tuo dispositivo.", - "secureBackup": "È importante eseguire il backup delle chiavi pubbliche e private e memorizzare il backup in modo sicuro!", - "footer": "=== END OF KEYS ===", - "header": "=== MESHTASTIC KEYS FOR {{longName}} ({{shortName}}) ===", - "privateKey": "Chiave Privata:", - "publicKey": "Chiave Pubblica:", - "fileName": "meshtastic_keys_{{longName}}_{{shortName}}.txt", - "title": "Backup chiavi" - }, - "pkiBackupReminder": { - "description": "Ti consigliamo di eseguire regolarmente il backup delle tue chiavi. Vuoi eseguire un backup?", - "title": "Backup Reminder", - "remindLaterPrefix": "Remind me in", - "remindNever": "Never remind me", - "backupNow": "Back up now" - }, - "pkiRegenerate": { - "description": "Sei sicuro di voler rigenerare la coppia di chiavi?", - "title": "Rigenera Coppia Chiavi" - }, - "qr": { - "addChannels": "Aggiungi canali", - "replaceChannels": "Sostituisci Canali", - "description": "Anche l'attuale configurazione di LoRa verrà condivisa.", - "sharableUrl": "URL Condivisibile", - "title": "Genera codice QR" - }, - "reboot": { - "title": "Reboot device", - "description": "Reboot now or schedule a reboot of the connected node. Optionally, you can choose to reboot into OTA (Over-the-Air) mode.", - "ota": "Reboot into OTA mode", - "enterDelay": "Enter delay", - "scheduled": "Il riavvio è stato pianificato", - "schedule": "Schedule reboot", - "now": "Reboot now", - "cancel": "Cancel scheduled reboot" - }, - "refreshKeys": { - "description": { - "acceptNewKeys": "Questo rimuoverà il nodo dal dispositivo e richiederà nuove chiavi.", - "keyMismatchReasonSuffix": ". Ciò è dovuto alla chiave pubblica corrente del nodo remoto che non corrisponde alla chiave precedentemente memorizzata per questo nodo.", - "unableToSendDmPrefix": "Il nodo non è in grado di inviare un messaggio diretto al nodo: " - }, - "acceptNewKeys": "Accetta Nuove Chiavi", - "title": "Chiavi Non Corrispondenti - {{identifier}}" - }, - "removeNode": { - "description": "Sei sicuro di voler rimuovere questo nodo?", - "title": "Rimuovi Nodo?" - }, - "shutdown": { - "title": "Pianifica Spegnimento", - "description": "Spegni il nodo connesso dopo x minuti." - }, - "traceRoute": { - "routeToDestination": "Percorso di destinazione:", - "routeBack": "Percorso indietro:" - }, - "tracerouteResponse": { - "title": "Traceroute: {{identifier}}" - }, - "unsafeRoles": { - "confirmUnderstanding": "Sì, so cosa sto facendo", - "conjunction": " e il blog post su ", - "postamble": " e capisco le implicazioni di un cambiamento di ruolo.", - "preamble": "Dichiaro di aver letto i ", - "choosingRightDeviceRole": "Scegliere il ruolo corretto del dispositivo", - "deviceRoleDocumentation": "Documentazione sul ruolo del dispositivo", - "title": "Sei sicuro?" - }, - "managedMode": { - "confirmUnderstanding": "Sì, so cosa sto facendo", - "title": "Sei sicuro?", - "description": "Enabling Managed Mode blocks client applications (including the web client) from writing configurations to a radio. Once enabled, radio configurations can only be changed through Remote Admin messages. This setting is not required for remote node administration." - }, - "clientNotification": { - "title": "Notifiche Client", - "TraceRoute can only be sent once every 30 seconds": "TraceRoute can only be sent once every 30 seconds", - "Compromised keys were detected and regenerated.": "Compromised keys were detected and regenerated." - } + "deleteMessages": { + "description": "Questa azione cancellerà tutta la cronologia dei messaggi. Non può essere annullata. Sei sicuro di voler continuare?", + "title": "Cancella Tutti I Messaggi" + }, + "import": { + "description": "La configurazione attuale di LoRa sarà sovrascritta.", + "error": { + "invalidUrl": "URL Meshtastic non valido" + }, + "channelPrefix": "Canale: ", + "primary": "Primary ", + "doNotImport": "No not import", + "channelName": "Nome", + "channelSlot": "Slot", + "channelSetUrl": "URL del Set di Canali/Codice QR", + "useLoraConfig": "Import LoRa Config", + "presetDescription": "The current LoRa Config will be replaced.", + "title": "Importa Set Canale" + }, + "locationResponse": { + "title": "Posizione: {{identifier}}", + "altitude": "Altitudine: ", + "coordinates": "Coordinate: ", + "noCoordinates": "No Coordinates" + }, + "pkiRegenerateDialog": { + "title": "Rigenerare La Chiave Pre-Condivisa?", + "description": "Sei sicuro di voler rigenerare la chiave pre-condivisa?", + "regenerate": "Rigenera" + }, + "addConnection": { + "title": "Add connection", + "description": "Choose a connection type and fill in the details", + "validation": { + "requiresWebBluetooth": "This connection type requires <0>Web Bluetooth. Please use a supported browser, like Chrome or Edge.", + "requiresWebSerial": "This connection type requires <0>Web Serial. Please use a supported browser, like Chrome or Edge.", + "requiresSecureContext": "Questa applicazione richiede un <0>contesto sicuro. Si prega di connettersi utilizzando HTTPS o localhost.", + "additionallyRequiresSecureContext": "Inoltre, richiede un <0>contesto sicuro. Si prega di connettersi utilizzando HTTPS o localhost." + }, + "bluetoothConnection": { + "namePlaceholder": "My Bluetooth Node", + "supported": { + "title": "Web Bluetooth supported" + }, + "notSupported": { + "title": "Web Bluetooth not supported", + "description": "Your browser or device does not support Web Bluetooth" + }, + "short": "BT: {{deviceName}}", + "long": "Bluetooth Device", + "device": "Dispositivo", + "selectDevice": "Select device", + "selected": "Bluetooth device selected", + "notSelected": "No device selected", + "helperText": "Uses the Meshtastic Bluetooth service for discovery." + }, + "serialConnection": { + "namePlaceholder": "My Serial Node", + "helperText": "Selecting a port grants permission so the app can open it to connect.", + "supported": { + "title": "Web Serial supported" + }, + "notSupported": { + "title": "Web Serial not supported", + "description": "Your browser or device does not support Web Serial" + }, + "portSelected": { + "title": "Serial port selected", + "description": "Port permissions granted." + }, + "port": "Port", + "selectPort": "Select port", + "deviceName": "USB {{vendorId}}:{{productId}}", + "notSelected": "No port selected" + }, + "httpConnection": { + "namePlaceholder": "My HTTP Node", + "inputPlaceholder": "192.168.1.10 or meshtastic.local", + "heading": "URL or IP", + "useHttps": "Use HTTTPS", + "invalidUrl": { + "title": "Invalid URL", + "description": "Please enter a valid HTTP or HTTPS URL." + }, + "connectionTest": { + "description": "Test the connetion before saving to verify the device is reachable.", + "button": { + "loading": "Testing...", + "label": "Test connection" + }, + "reachable": "Reachable", + "notReachable": "Not reachable", + "success": { + "title": "Connection test successful", + "description": "The device appears to be reachable." + }, + "failure": { + "title": "Connection test failed", + "description": "Could not reach the device. Check the URL and try again." + } + } + } + }, + "nodeDetails": { + "message": "Messaggio", + "requestPosition": "Richiedi posizione", + "traceRoute": "Trace Route", + "airTxUtilization": "Tempo di Trasmissione Utilizzato", + "allRawMetrics": "Tutte Le Metriche Grezze:", + "batteryLevel": "Livello batteria", + "channelUtilization": "Utilizzo Canale", + "details": "Dettagli:", + "deviceMetrics": "Metriche Dispositivo:", + "hardware": "Hardware: ", + "lastHeard": "Ultimo Contatto: ", + "nodeHexPrefix": "Node Hex: ", + "nodeNumber": "Numero Nodo: ", + "position": "Posizione:", + "role": "Ruolo: ", + "uptime": "Tempo di attività: ", + "voltage": "Tensione", + "title": "Dettagli nodo per {{identifier}}", + "ignoreNode": "Ignora nodo", + "removeNode": "Rimuovi Nodo", + "unignoreNode": "Non ignorare più nodo", + "security": "Security:", + "publicKey": "Public Key: ", + "messageable": "Messageable: ", + "KeyManuallyVerifiedTrue": "Public Key has been manually verified", + "KeyManuallyVerifiedFalse": "Public Key is not manually verified" + }, + "pkiBackup": { + "loseKeysWarning": "Se perdi le tue chiavi, dovrai reimpostare il tuo dispositivo.", + "secureBackup": "È importante eseguire il backup delle chiavi pubbliche e private e memorizzare il backup in modo sicuro!", + "footer": "=== END OF KEYS ===", + "header": "=== MESHTASTIC KEYS FOR {{longName}} ({{shortName}}) ===", + "privateKey": "Chiave Privata:", + "publicKey": "Chiave Pubblica:", + "fileName": "meshtastic_keys_{{longName}}_{{shortName}}.txt", + "title": "Backup chiavi" + }, + "pkiBackupReminder": { + "description": "Ti consigliamo di eseguire regolarmente il backup delle tue chiavi. Vuoi eseguire un backup?", + "title": "Backup Reminder", + "remindLaterPrefix": "Remind me in", + "remindNever": "Never remind me", + "backupNow": "Back up now" + }, + "pkiRegenerate": { + "description": "Sei sicuro di voler rigenerare la coppia di chiavi?", + "title": "Rigenera Coppia Chiavi" + }, + "qr": { + "addChannels": "Aggiungi canali", + "replaceChannels": "Sostituisci Canali", + "description": "Anche l'attuale configurazione di LoRa verrà condivisa.", + "sharableUrl": "URL Condivisibile", + "title": "Genera codice QR" + }, + "reboot": { + "title": "Reboot device", + "description": "Reboot now or schedule a reboot of the connected node. Optionally, you can choose to reboot into OTA (Over-the-Air) mode.", + "ota": "Reboot into OTA mode", + "enterDelay": "Enter delay", + "scheduled": "Il riavvio è stato pianificato", + "schedule": "Schedule reboot", + "now": "Reboot now", + "cancel": "Cancel scheduled reboot" + }, + "refreshKeys": { + "description": { + "acceptNewKeys": "Questo rimuoverà il nodo dal dispositivo e richiederà nuove chiavi.", + "keyMismatchReasonSuffix": ". Ciò è dovuto alla chiave pubblica corrente del nodo remoto che non corrisponde alla chiave precedentemente memorizzata per questo nodo.", + "unableToSendDmPrefix": "Il nodo non è in grado di inviare un messaggio diretto al nodo: " + }, + "acceptNewKeys": "Accetta Nuove Chiavi", + "title": "Chiavi Non Corrispondenti - {{identifier}}" + }, + "removeNode": { + "description": "Sei sicuro di voler rimuovere questo nodo?", + "title": "Rimuovi Nodo?" + }, + "shutdown": { + "title": "Pianifica Spegnimento", + "description": "Spegni il nodo connesso dopo x minuti." + }, + "traceRoute": { + "routeToDestination": "Percorso di destinazione:", + "routeBack": "Percorso indietro:" + }, + "tracerouteResponse": { + "title": "Traceroute: {{identifier}}" + }, + "unsafeRoles": { + "confirmUnderstanding": "Sì, so cosa sto facendo", + "conjunction": " e il blog post su ", + "postamble": " e capisco le implicazioni di un cambiamento di ruolo.", + "preamble": "Dichiaro di aver letto i ", + "choosingRightDeviceRole": "Scegliere il ruolo corretto del dispositivo", + "deviceRoleDocumentation": "Documentazione sul ruolo del dispositivo", + "title": "Sei sicuro?" + }, + "managedMode": { + "confirmUnderstanding": "Sì, so cosa sto facendo", + "title": "Sei sicuro?", + "description": "Enabling Managed Mode blocks client applications (including the web client) from writing configurations to a radio. Once enabled, radio configurations can only be changed through Remote Admin messages. This setting is not required for remote node administration." + }, + "clientNotification": { + "title": "Notifiche Client", + "TraceRoute can only be sent once every 30 seconds": "TraceRoute can only be sent once every 30 seconds", + "Compromised keys were detected and regenerated.": "Compromised keys were detected and regenerated." + }, + "resetNodeDb": { + "title": "Reset Node Database", + "description": "This will clear all nodes from the connected device's node database and clear all message history in the client. This cannot be undone. Are you sure you want to continue?", + "confirm": "Reset Node Database", + "failedTitle": "There was an error resetting the Node DB. Please try again." + }, + "clearAllStores": { + "title": "Clear All Local Storage", + "description": "This will clear all locally stored data, including message history and node databases for all previously connected devices. This will require you to reconnect to your node once complete and cannot be undone. Are you sure you want to continue?", + "confirm": "Clear all local storage", + "failedTitle": "There was an error clearing local storage. Please try again." + }, + "factoryResetDevice": { + "title": "Factory reset dispositivo", + "description": "This will factory reset the connected device, erasing all configurations and data on the device as well as all nodes and messages saved in the client. This cannot be undone. Are you sure you want to continue?", + "confirm": "Factory reset dispositivo", + "failedTitle": "There was an error performing the factory reset. Please try again." + }, + "factoryResetConfig": { + "title": "Factory reset impostazioni", + "description": "This will factory reset the configuration on the connected device, erasing all configurations on the device. This cannot be undone. Are you sure you want to continue?", + "confirm": "Factory reset impostazioni", + "failedTitle": "There was an error performing the factory reset. Please try again." + } } diff --git a/packages/web/public/i18n/locales/it-IT/map.json b/packages/web/public/i18n/locales/it-IT/map.json new file mode 100644 index 000000000..810ce272c --- /dev/null +++ b/packages/web/public/i18n/locales/it-IT/map.json @@ -0,0 +1,38 @@ +{ + "maplibre": { + "GeolocateControl.FindMyLocation": "Find my location", + "NavigationControl.ZoomIn": "Zoom in", + "NavigationControl.ZoomOut": "Zoom out", + "CooperativeGesturesHandler.WindowsHelpText": "Use Ctrl + scroll to zoom the map", + "CooperativeGesturesHandler.MacHelpText": "Use ⌘ + scroll to zoom the map", + "CooperativeGesturesHandler.MobileHelpText": "Use two fingers to move the map" + }, + "layerTool": { + "nodeMarkers": "Show nodes", + "directNeighbors": "Show direct connections", + "remoteNeighbors": "Show remote connections", + "positionPrecision": "Show position precision", + "traceroutes": "Show traceroutes", + "waypoints": "Show waypoints" + }, + "mapMenu": { + "locateAria": "Locate my node", + "layersAria": "Change map style" + }, + "waypointDetail": { + "edit": "Modifica", + "description": "Description:", + "createdBy": "Edited by:", + "createdDate": "Created:", + "updated": "Updated:", + "expires": "Expires:", + "distance": "Distance:", + "bearing": "Absolute bearing:", + "lockedTo": "Locked by:", + "latitude": "Latitude:", + "longitude": "Longitude:" + }, + "myNode": { + "tooltip": "This device" + } +} diff --git a/packages/web/public/i18n/locales/it-IT/messages.json b/packages/web/public/i18n/locales/it-IT/messages.json index 645c22dfb..7a8cd6bd4 100644 --- a/packages/web/public/i18n/locales/it-IT/messages.json +++ b/packages/web/public/i18n/locales/it-IT/messages.json @@ -1,39 +1,39 @@ { - "page": { - "title": "Messaggi: {{chatName}}", - "placeholder": "Enter Message" - }, - "emptyState": { - "title": "Seleziona una chat", - "text": "Ancora nessun messaggio." - }, - "selectChatPrompt": { - "text": "Selezionare un canale o un nodo per iniziare a messaggiare." - }, - "sendMessage": { - "placeholder": "Enter your message here...", - "sendButton": "Invia" - }, - "actionsMenu": { - "addReactionLabel": "Aggiungi una Reazione", - "replyLabel": "Rispondi" - }, - "deliveryStatus": { - "delivered": { - "label": "Messaggio inviato", - "displayText": "Messaggio inviato" - }, - "failed": { - "label": "Invio messaggio non riuscito", - "displayText": "Invio fallito" - }, - "unknown": { - "label": "Stato messaggio sconosciuto", - "displayText": "Stato sconosciuto" - }, - "waiting": { - "label": "Inviando il messaggio...", - "displayText": "In attesa della consegna" - } - } + "page": { + "title": "Messaggi: {{chatName}}", + "placeholder": "Enter Message" + }, + "emptyState": { + "title": "Seleziona una chat", + "text": "Ancora nessun messaggio." + }, + "selectChatPrompt": { + "text": "Selezionare un canale o un nodo per iniziare a messaggiare." + }, + "sendMessage": { + "placeholder": "Enter your message here...", + "sendButton": "Invia" + }, + "actionsMenu": { + "addReactionLabel": "Aggiungi una Reazione", + "replyLabel": "Rispondi" + }, + "deliveryStatus": { + "delivered": { + "label": "Messaggio inviato", + "displayText": "Messaggio inviato" + }, + "failed": { + "label": "Invio messaggio non riuscito", + "displayText": "Invio fallito" + }, + "unknown": { + "label": "Stato messaggio sconosciuto", + "displayText": "Stato sconosciuto" + }, + "waiting": { + "label": "Inviando il messaggio...", + "displayText": "In attesa della consegna" + } + } } diff --git a/packages/web/public/i18n/locales/it-IT/moduleConfig.json b/packages/web/public/i18n/locales/it-IT/moduleConfig.json index 0c0e5d384..78052629e 100644 --- a/packages/web/public/i18n/locales/it-IT/moduleConfig.json +++ b/packages/web/public/i18n/locales/it-IT/moduleConfig.json @@ -1,448 +1,448 @@ { - "page": { - "tabAmbientLighting": "Luce Ambientale", - "tabAudio": "Audio", - "tabCannedMessage": "Predefiniti", - "tabDetectionSensor": "Sensore Di Rilevamento", - "tabExternalNotification": "Notifica Esterna", - "tabMqtt": "MQTT", - "tabNeighborInfo": "Informazioni Vicinato", - "tabPaxcounter": "Paxcounter", - "tabRangeTest": "Test Distanza", - "tabSerial": "Seriale", - "tabStoreAndForward": "S&I", - "tabTelemetry": "Telemetria" - }, - "ambientLighting": { - "title": "Configurazione Illuminazione Ambientale", - "description": "Impostazioni per il modulo Illuminazione Ambientale", - "ledState": { - "label": "Stato LED", - "description": "Imposta LED su acceso o spento" - }, - "current": { - "label": "Attuale", - "description": "Imposta la corrente per l'uscita LED. Il valore predefinito è 10" - }, - "red": { - "label": "Rosso", - "description": "Imposta il livello rosso del LED. I valori sono 0-255" - }, - "green": { - "label": "Verde", - "description": "Imposta il livello verde del LED. I valori sono 0-255" - }, - "blue": { - "label": "Blu", - "description": "Imposta il livello blu del LED. I valori sono 0-255" - } - }, - "audio": { - "title": "Impostazioni audio", - "description": "Impostazioni per il modulo audio", - "codec2Enabled": { - "label": "Codec 2 Abilitato", - "description": "Abilita la codifica audio Codec 2" - }, - "pttPin": { - "label": "Pin PTT", - "description": "GPIO pin da utilizzare per PTT" - }, - "bitrate": { - "label": "Bitrate", - "description": "Bitrate da usare per la codifica audio" - }, - "i2sWs": { - "label": "i2S WS", - "description": "GPIO pin da usare per i2S WS" - }, - "i2sSd": { - "label": "i2S SD", - "description": "GPIO pin da usare per i2S SD" - }, - "i2sDin": { - "label": "i2S DIN", - "description": "GPIO pin da usare per i2S DIN" - }, - "i2sSck": { - "label": "i2S SCK", - "description": "GPIO pin da usare per i2S SCK" - } - }, - "cannedMessage": { - "title": "Impostazioni Messaggi Predefiniti", - "description": "Impostazioni per i Messaggi Predefiniti", - "moduleEnabled": { - "label": "Modulo abilitato", - "description": "Abilita Messaggi Predefiniti" - }, - "rotary1Enabled": { - "label": "Encoder Rotativo #1 Abilitato", - "description": "Abilita l'encoder rotativo" - }, - "inputbrokerPinA": { - "label": "Encoder Pin A", - "description": "Valore Pin GPIO (1-39) Per porta encoder A" - }, - "inputbrokerPinB": { - "label": "Encoder Pin B", - "description": "Valore Pin GPIO (1-39) Per porta encoder B" - }, - "inputbrokerPinPress": { - "label": "Pin Pressione Encoder", - "description": "Valore Pin GPIO (1-39) Per la pressione dell'encoder" - }, - "inputbrokerEventCw": { - "label": "Evento in senso orario", - "description": "Seleziona evento in ingresso." - }, - "inputbrokerEventCcw": { - "label": "Evento in senso antiorario", - "description": "Seleziona evento in ingresso." - }, - "inputbrokerEventPress": { - "label": "Evento pressione", - "description": "Seleziona evento in ingresso" - }, - "updown1Enabled": { - "label": "Su Giù abilitato", - "description": "Abilita l'encoder su / giù" - }, - "allowInputSource": { - "label": "Consenti sorgente di input", - "description": "Seleziona da: '_any', 'rotEnc1', 'upDownEnc1', 'cardkb'" - }, - "sendBell": { - "label": "Invia Campanella", - "description": "Invia un carattere campanella con ogni messaggio" - } - }, - "detectionSensor": { - "title": "Configurazione Sensore Rilevamento", - "description": "Impostazioni per il modulo sensore di rilevamento", - "enabled": { - "label": "Abilitato", - "description": "Abilita o disabilita il modulo del sensore di rilevamento" - }, - "minimumBroadcastSecs": { - "label": "Secondi Di Trasmissione Minimi", - "description": "L'intervallo in secondi di quanto spesso possiamo inviare un messaggio alla mesh quando viene rilevato un cambiamento di stato" - }, - "stateBroadcastSecs": { - "label": "Secondi Trasmissione di Stato", - "description": "L'intervallo in secondi di quanto spesso dovremmo inviare un messaggio alla mesh con lo stato attuale indipendentemente dai cambiamenti" - }, - "sendBell": { - "label": "Invia Campanella", - "description": "Invia campanella ASCII con messaggio di avviso" - }, - "name": { - "label": "Nome Descrittivo", - "description": "Usato per formattare il messaggio inviato a mesh, max 20 Caratteri" - }, - "monitorPin": { - "label": "Pin Monitor", - "description": "Il pin GPIO da monitorare per i cambiamenti di stato" - }, - "detectionTriggerType": { - "label": "Tipo di trigger di rilevamento", - "description": "Il tipo di evento di trigger da usare" - }, - "usePullup": { - "label": "Usa Pullup", - "description": "Indica se usare o meno la modalità INPUT_PULLUP per il pin GPIO" - } - }, - "externalNotification": { - "title": "Configurazione Notifiche Esterne", - "description": "Configura il modulo notifiche esterno", - "enabled": { - "label": "Modulo abilitato", - "description": "Abilita Notifiche Esterne" - }, - "outputMs": { - "label": "Output MS", - "description": "Output MS" - }, - "output": { - "label": "Output", - "description": "Output" - }, - "outputVibra": { - "label": "Vibrazione Output", - "description": "Vibrazione Output" - }, - "outputBuzzer": { - "label": "Buzzer Output", - "description": "Buzzer Output" - }, - "active": { - "label": "Attivo", - "description": "Attivo" - }, - "alertMessage": { - "label": "Messaggio di allerta", - "description": "Messaggio di allerta" - }, - "alertMessageVibra": { - "label": "Vibrazione Messaggio Di Allerta", - "description": "Vibrazione Messaggio Di Allerta" - }, - "alertMessageBuzzer": { - "label": "Buzzer Messaggio Di Allerta", - "description": "Buzzer Messaggio Di Allerta" - }, - "alertBell": { - "label": "Campanella Di Allarme", - "description": "Occorre attivare una segnalazione quando si riceve un campanello in entrata?" - }, - "alertBellVibra": { - "label": "Vibrazione campanella di allarme", - "description": "Vibrazione campanella di allarme" - }, - "alertBellBuzzer": { - "label": "Buzzer campanella di allarme", - "description": "Buzzer campanella di allarme" - }, - "usePwm": { - "label": "Usa PWM", - "description": "Usa PWM" - }, - "nagTimeout": { - "label": "Nag Timeout", - "description": "Nag Timeout" - }, - "useI2sAsBuzzer": { - "label": "Usa I2S come buzzer", - "description": "Designa il Pin I²S come Uscita Buzzer" - } - }, - "mqtt": { - "title": "Impostazioni MQTT", - "description": "Impostazioni per il modulo MQTT", - "enabled": { - "label": "Abilitato", - "description": "Abilita o disabilita MQTT" - }, - "address": { - "label": "Indirizzo Server MQTT", - "description": "Indirizzo server MQTT da usare per i server predefiniti/personalizzati" - }, - "username": { - "label": "Username MQTT", - "description": "Username MQTT da usare per i server predefiniti/personalizzati" - }, - "password": { - "label": "Password MQTT", - "description": "Password MQTT da usare per server predefiniti/personalizzati" - }, - "encryptionEnabled": { - "label": "Crittografia Abilitata", - "description": "Abilita o disabilita la crittografia MQTT. Nota: Tutti i messaggi sono inviati al broker MQTT non cifrati se questa opzione non è abilitata, anche quando i canali uplink hanno chiavi di crittografia impostate. Ciò include i dati di posizione." - }, - "jsonEnabled": { - "label": "JSON Abilitato", - "description": "Indica se inviare/consumare pacchetti JSON su MQTT" - }, - "tlsEnabled": { - "label": "TLS abilitato", - "description": "Abilita o disabilita MQTT" - }, - "root": { - "label": "Root topic", - "description": "Topic root MQTT da utilizzare per server predefiniti/personalizzati" - }, - "proxyToClientEnabled": { - "label": "Proxy Client MQTT Abilitato", - "description": "Utilizza la connessione di rete per fare da proxy ai messaggi MQTT verso il client." - }, - "mapReportingEnabled": { - "label": "Segnalazione sulla Mappa Abilitata", - "description": "Il tuo nodo invierà periodicamente un pacchetto di segnalazione mappa non criptato al server MQTT configurato, questo include id, nome breve e lungo, posizione approssimativa, modello hardware, ruolo, versione del firmware, regione LoRa, preset del modem e nome del canale primario." - }, - "mapReportSettings": { - "publishIntervalSecs": { - "label": "Intervallo di Pubblicazione Segnalazione Mappa (s)", - "description": "Intervallo in secondi per pubblicare le segnalazioni mappa" - }, - "positionPrecision": { - "label": "Posizione Approssimativa", - "description": "La posizione condivisa sarà accurata entro questa distanza", - "options": { - "metric_km23": "Entro 23 km", - "metric_km12": "Entro 12 km", - "metric_km5_8": "Entro 5,8 km", - "metric_km2_9": "Entro 2,9 km", - "metric_km1_5": "Entro 1,5 km", - "metric_m700": "Entro 700 m", - "metric_m350": "Entro 350 m", - "metric_m200": "Entro 200 m", - "metric_m90": "Entro 90 m", - "metric_m50": "Entro 50 m", - "imperial_mi15": "Entro 15 miglia", - "imperial_mi7_3": "Entro 7,3 miglia", - "imperial_mi3_6": "Entro 3,6 miglia", - "imperial_mi1_8": "Entro 1,8 miglia", - "imperial_mi0_9": "Entro 0,9 miglia", - "imperial_mi0_5": "Entro 0,5 miglia", - "imperial_mi0_2": "Entro 0,2 miglia", - "imperial_ft600": "Entro 600 piedi", - "imperial_ft300": "Entro 300 piedi", - "imperial_ft150": "Entro 150 piedi" - } - } - } - }, - "neighborInfo": { - "title": "Impostazioni Informazioni Vicini", - "description": "Impostazioni per il modulo Informazioni Vicini", - "enabled": { - "label": "Abilitato", - "description": "Abilita o disabilita Modulo Info Vicini" - }, - "updateInterval": { - "label": "Intervallo di Aggiornamento", - "description": "Intervallo in secondi di quanto spesso dovremmo cercare di inviare le nostre Info Vicini alla mesh" - } - }, - "paxcounter": { - "title": "Impostazioni Paxcounter", - "description": "Impostazioni per il modulo Paxcounter", - "enabled": { - "label": "Modulo abilitato", - "description": "Abilita Paxcounter" - }, - "paxcounterUpdateInterval": { - "label": "Intervallo di aggiornamento (secondi)", - "description": "Per quanto tempo attendere tra l'invio di pacchetti paxcounter" - }, - "wifiThreshold": { - "label": "Soglia RSSI WiFi", - "description": "A quale livello RSSI WiFi dovrebbe aumentare il contatore. Predefinito a -80." - }, - "bleThreshold": { - "label": "Soglia RSSI BLE", - "description": "A quale livello RSSI BLE dovrebbe aumentare il contatore. Predefinito a -80." - } - }, - "rangeTest": { - "title": "Impostazioni Di Range Test", - "description": "Impostazioni per il modulo Range Test", - "enabled": { - "label": "Modulo abilitato", - "description": "Abilita Range Test" - }, - "sender": { - "label": "Intervallo Dei Messaggi", - "description": "Per quanto tempo attendere tra l'invio dei pacchetti di test" - }, - "save": { - "label": "Salva CSV nella memoria", - "description": "Solo ESP32" - } - }, - "serial": { - "title": "Impostazioni Seriale", - "description": "Impostazioni per il modulo seriale", - "enabled": { - "label": "Modulo abilitato", - "description": "Abilita output seriale" - }, - "echo": { - "label": "Echo", - "description": "Tutti i pacchetti che invii verranno rimandati indietro al tuo dispositivo" - }, - "rxd": { - "label": "Pin di ricezione", - "description": "Imposta il pin GPIO al pin RXD che hai configurato." - }, - "txd": { - "label": "Pin di trasmissione", - "description": "Imposta il pin GPIO al pin TXD che hai configurato." - }, - "baud": { - "label": "Baud rate", - "description": "La velocità di trasmissione seriale" - }, - "timeout": { - "label": "Timeout", - "description": "Secondi da attesa prima di considerare il tuo pacchetto come 'fatto'" - }, - "mode": { - "label": "Modalità", - "description": "Seleziona modalità" - }, - "overrideConsoleSerialPort": { - "label": "Sovrascrivi La Porta Seriale Della Console", - "description": "Se si dispone di una porta seriale collegata alla console, questa verrà sostituita." - } - }, - "storeForward": { - "title": "Configurazione Salva & Inoltra", - "description": "Impostazioni per il modulo Salva & Inoltra", - "enabled": { - "label": "Modulo abilitato", - "description": "Abilita Salva & Inoltra" - }, - "heartbeat": { - "label": "Heartbeat Abilitato", - "description": "Abilita heartbeat Store & Forward" - }, - "records": { - "label": "Numero di record", - "description": "Numero di record da memorizzare" - }, - "historyReturnMax": { - "label": "Cronologia ritorno max", - "description": "Numero massimo di record da restituire" - }, - "historyReturnWindow": { - "label": "Finestra di ritorno cronologia", - "description": "Numero massimo di record da restituire" - } - }, - "telemetry": { - "title": "Impostazioni Telemetria", - "description": "Impostazioni per il modulo Telemetria", - "deviceUpdateInterval": { - "label": "Metriche Dispositivo", - "description": "Intervallo aggiornamento metriche dispositivo (secondi)" - }, - "environmentUpdateInterval": { - "label": "Intervallo aggiornamento metriche ambientali (secondi)", - "description": "" - }, - "environmentMeasurementEnabled": { - "label": "Modulo abilitato", - "description": "Abilita la telemetria Ambiente" - }, - "environmentScreenEnabled": { - "label": "Visualizzato sullo schermo", - "description": "Mostra il modulo di telemetria sull'OLED" - }, - "environmentDisplayFahrenheit": { - "label": "Mostra Fahrenheit", - "description": "Mostra la temperatura in Fahrenheit" - }, - "airQualityEnabled": { - "label": "Qualità Dell'Aria Abilitata", - "description": "Abilita la telemetria della qualità dell'aria" - }, - "airQualityInterval": { - "label": "Intervallo Di Aggiornamento Qualità Dell'Aria", - "description": "Quanto spesso inviare dati sulla qualità dell'aria sulla mesh" - }, - "powerMeasurementEnabled": { - "label": "Misurazione Alimentazione Abilitata", - "description": "Abilita la telemetria di misura della alimentazione" - }, - "powerUpdateInterval": { - "label": "Intervallo Di Aggiornamento Alimentazione", - "description": "Quanto spesso inviare i dati di alimentazione sulla mesh" - }, - "powerScreenEnabled": { - "label": "Schermo Di Alimentazione Abilitato", - "description": "Abilita lo schermo di Telemetria di alimentazione" - } - } + "page": { + "tabAmbientLighting": "Luce Ambientale", + "tabAudio": "Audio", + "tabCannedMessage": "Predefiniti", + "tabDetectionSensor": "Sensore Di Rilevamento", + "tabExternalNotification": "Notifica Esterna", + "tabMqtt": "MQTT", + "tabNeighborInfo": "Informazioni Vicinato", + "tabPaxcounter": "Paxcounter", + "tabRangeTest": "Test Distanza", + "tabSerial": "Seriale", + "tabStoreAndForward": "S&I", + "tabTelemetry": "Telemetria" + }, + "ambientLighting": { + "title": "Configurazione Illuminazione Ambientale", + "description": "Impostazioni per il modulo Illuminazione Ambientale", + "ledState": { + "label": "Stato LED", + "description": "Imposta LED su acceso o spento" + }, + "current": { + "label": "Attuale", + "description": "Imposta la corrente per l'uscita LED. Il valore predefinito è 10" + }, + "red": { + "label": "Rosso", + "description": "Imposta il livello rosso del LED. I valori sono 0-255" + }, + "green": { + "label": "Verde", + "description": "Imposta il livello verde del LED. I valori sono 0-255" + }, + "blue": { + "label": "Blu", + "description": "Imposta il livello blu del LED. I valori sono 0-255" + } + }, + "audio": { + "title": "Impostazioni audio", + "description": "Impostazioni per il modulo audio", + "codec2Enabled": { + "label": "Codec 2 Abilitato", + "description": "Abilita la codifica audio Codec 2" + }, + "pttPin": { + "label": "Pin PTT", + "description": "GPIO pin da utilizzare per PTT" + }, + "bitrate": { + "label": "Bitrate", + "description": "Bitrate da usare per la codifica audio" + }, + "i2sWs": { + "label": "i2S WS", + "description": "GPIO pin da usare per i2S WS" + }, + "i2sSd": { + "label": "i2S SD", + "description": "GPIO pin da usare per i2S SD" + }, + "i2sDin": { + "label": "i2S DIN", + "description": "GPIO pin da usare per i2S DIN" + }, + "i2sSck": { + "label": "i2S SCK", + "description": "GPIO pin da usare per i2S SCK" + } + }, + "cannedMessage": { + "title": "Impostazioni Messaggi Predefiniti", + "description": "Impostazioni per i Messaggi Predefiniti", + "moduleEnabled": { + "label": "Modulo abilitato", + "description": "Abilita Messaggi Predefiniti" + }, + "rotary1Enabled": { + "label": "Encoder Rotativo #1 Abilitato", + "description": "Abilita l'encoder rotativo" + }, + "inputbrokerPinA": { + "label": "Encoder Pin A", + "description": "Valore Pin GPIO (1-39) Per porta encoder A" + }, + "inputbrokerPinB": { + "label": "Encoder Pin B", + "description": "Valore Pin GPIO (1-39) Per porta encoder B" + }, + "inputbrokerPinPress": { + "label": "Pin Pressione Encoder", + "description": "Valore Pin GPIO (1-39) Per la pressione dell'encoder" + }, + "inputbrokerEventCw": { + "label": "Evento in senso orario", + "description": "Seleziona evento in ingresso." + }, + "inputbrokerEventCcw": { + "label": "Evento in senso antiorario", + "description": "Seleziona evento in ingresso." + }, + "inputbrokerEventPress": { + "label": "Evento pressione", + "description": "Seleziona evento in ingresso" + }, + "updown1Enabled": { + "label": "Su Giù abilitato", + "description": "Abilita l'encoder su / giù" + }, + "allowInputSource": { + "label": "Consenti sorgente di input", + "description": "Seleziona da: '_any', 'rotEnc1', 'upDownEnc1', 'cardkb'" + }, + "sendBell": { + "label": "Invia Campanella", + "description": "Invia un carattere campanella con ogni messaggio" + } + }, + "detectionSensor": { + "title": "Configurazione Sensore Rilevamento", + "description": "Impostazioni per il modulo sensore di rilevamento", + "enabled": { + "label": "Abilitato", + "description": "Abilita o disabilita il modulo del sensore di rilevamento" + }, + "minimumBroadcastSecs": { + "label": "Secondi Di Trasmissione Minimi", + "description": "L'intervallo in secondi di quanto spesso possiamo inviare un messaggio alla mesh quando viene rilevato un cambiamento di stato" + }, + "stateBroadcastSecs": { + "label": "Secondi Trasmissione di Stato", + "description": "L'intervallo in secondi di quanto spesso dovremmo inviare un messaggio alla mesh con lo stato attuale indipendentemente dai cambiamenti" + }, + "sendBell": { + "label": "Invia Campanella", + "description": "Invia campanella ASCII con messaggio di avviso" + }, + "name": { + "label": "Nome Descrittivo", + "description": "Usato per formattare il messaggio inviato a mesh, max 20 Caratteri" + }, + "monitorPin": { + "label": "Pin Monitor", + "description": "Il pin GPIO da monitorare per i cambiamenti di stato" + }, + "detectionTriggerType": { + "label": "Tipo di trigger di rilevamento", + "description": "Il tipo di evento di trigger da usare" + }, + "usePullup": { + "label": "Usa Pullup", + "description": "Indica se usare o meno la modalità INPUT_PULLUP per il pin GPIO" + } + }, + "externalNotification": { + "title": "Configurazione Notifiche Esterne", + "description": "Configura il modulo notifiche esterno", + "enabled": { + "label": "Modulo abilitato", + "description": "Abilita Notifiche Esterne" + }, + "outputMs": { + "label": "Output MS", + "description": "Output MS" + }, + "output": { + "label": "Output", + "description": "Output" + }, + "outputVibra": { + "label": "Vibrazione Output", + "description": "Vibrazione Output" + }, + "outputBuzzer": { + "label": "Buzzer Output", + "description": "Buzzer Output" + }, + "active": { + "label": "Attivo", + "description": "Attivo" + }, + "alertMessage": { + "label": "Messaggio di allerta", + "description": "Messaggio di allerta" + }, + "alertMessageVibra": { + "label": "Vibrazione Messaggio Di Allerta", + "description": "Vibrazione Messaggio Di Allerta" + }, + "alertMessageBuzzer": { + "label": "Buzzer Messaggio Di Allerta", + "description": "Buzzer Messaggio Di Allerta" + }, + "alertBell": { + "label": "Campanella Di Allarme", + "description": "Occorre attivare una segnalazione quando si riceve un campanello in entrata?" + }, + "alertBellVibra": { + "label": "Vibrazione campanella di allarme", + "description": "Vibrazione campanella di allarme" + }, + "alertBellBuzzer": { + "label": "Buzzer campanella di allarme", + "description": "Buzzer campanella di allarme" + }, + "usePwm": { + "label": "Usa PWM", + "description": "Usa PWM" + }, + "nagTimeout": { + "label": "Nag Timeout", + "description": "Nag Timeout" + }, + "useI2sAsBuzzer": { + "label": "Usa I2S come buzzer", + "description": "Designa il Pin I²S come Uscita Buzzer" + } + }, + "mqtt": { + "title": "Impostazioni MQTT", + "description": "Impostazioni per il modulo MQTT", + "enabled": { + "label": "Abilitato", + "description": "Abilita o disabilita MQTT" + }, + "address": { + "label": "Indirizzo Server MQTT", + "description": "Indirizzo server MQTT da usare per i server predefiniti/personalizzati" + }, + "username": { + "label": "Username MQTT", + "description": "Username MQTT da usare per i server predefiniti/personalizzati" + }, + "password": { + "label": "Password MQTT", + "description": "Password MQTT da usare per server predefiniti/personalizzati" + }, + "encryptionEnabled": { + "label": "Crittografia Abilitata", + "description": "Abilita o disabilita la crittografia MQTT. Nota: Tutti i messaggi sono inviati al broker MQTT non cifrati se questa opzione non è abilitata, anche quando i canali uplink hanno chiavi di crittografia impostate. Ciò include i dati di posizione." + }, + "jsonEnabled": { + "label": "JSON Abilitato", + "description": "Indica se inviare/consumare pacchetti JSON su MQTT" + }, + "tlsEnabled": { + "label": "TLS abilitato", + "description": "Abilita o disabilita MQTT" + }, + "root": { + "label": "Root topic", + "description": "Topic root MQTT da utilizzare per server predefiniti/personalizzati" + }, + "proxyToClientEnabled": { + "label": "Proxy Client MQTT Abilitato", + "description": "Utilizza la connessione di rete per fare da proxy ai messaggi MQTT verso il client." + }, + "mapReportingEnabled": { + "label": "Segnalazione sulla Mappa Abilitata", + "description": "Il tuo nodo invierà periodicamente un pacchetto di segnalazione mappa non criptato al server MQTT configurato, questo include id, nome breve e lungo, posizione approssimativa, modello hardware, ruolo, versione del firmware, regione LoRa, preset del modem e nome del canale primario." + }, + "mapReportSettings": { + "publishIntervalSecs": { + "label": "Intervallo di Pubblicazione Segnalazione Mappa (s)", + "description": "Intervallo in secondi per pubblicare le segnalazioni mappa" + }, + "positionPrecision": { + "label": "Posizione Approssimativa", + "description": "La posizione condivisa sarà accurata entro questa distanza", + "options": { + "metric_km23": "Entro 23 km", + "metric_km12": "Entro 12 km", + "metric_km5_8": "Entro 5,8 km", + "metric_km2_9": "Entro 2,9 km", + "metric_km1_5": "Entro 1,5 km", + "metric_m700": "Entro 700 m", + "metric_m350": "Entro 350 m", + "metric_m200": "Entro 200 m", + "metric_m90": "Entro 90 m", + "metric_m50": "Entro 50 m", + "imperial_mi15": "Entro 15 miglia", + "imperial_mi7_3": "Entro 7,3 miglia", + "imperial_mi3_6": "Entro 3,6 miglia", + "imperial_mi1_8": "Entro 1,8 miglia", + "imperial_mi0_9": "Entro 0,9 miglia", + "imperial_mi0_5": "Entro 0,5 miglia", + "imperial_mi0_2": "Entro 0,2 miglia", + "imperial_ft600": "Entro 600 piedi", + "imperial_ft300": "Entro 300 piedi", + "imperial_ft150": "Entro 150 piedi" + } + } + } + }, + "neighborInfo": { + "title": "Impostazioni Informazioni Vicini", + "description": "Impostazioni per il modulo Informazioni Vicini", + "enabled": { + "label": "Abilitato", + "description": "Abilita o disabilita Modulo Info Vicini" + }, + "updateInterval": { + "label": "Intervallo di Aggiornamento", + "description": "Intervallo in secondi di quanto spesso dovremmo cercare di inviare le nostre Info Vicini alla mesh" + } + }, + "paxcounter": { + "title": "Impostazioni Paxcounter", + "description": "Impostazioni per il modulo Paxcounter", + "enabled": { + "label": "Modulo abilitato", + "description": "Abilita Paxcounter" + }, + "paxcounterUpdateInterval": { + "label": "Intervallo di aggiornamento (secondi)", + "description": "Per quanto tempo attendere tra l'invio di pacchetti paxcounter" + }, + "wifiThreshold": { + "label": "Soglia RSSI WiFi", + "description": "A quale livello RSSI WiFi dovrebbe aumentare il contatore. Predefinito a -80." + }, + "bleThreshold": { + "label": "Soglia RSSI BLE", + "description": "A quale livello RSSI BLE dovrebbe aumentare il contatore. Predefinito a -80." + } + }, + "rangeTest": { + "title": "Impostazioni Di Range Test", + "description": "Impostazioni per il modulo Range Test", + "enabled": { + "label": "Modulo abilitato", + "description": "Abilita Range Test" + }, + "sender": { + "label": "Intervallo Dei Messaggi", + "description": "Per quanto tempo attendere tra l'invio dei pacchetti di test" + }, + "save": { + "label": "Salva CSV nella memoria", + "description": "Solo ESP32" + } + }, + "serial": { + "title": "Impostazioni Seriale", + "description": "Impostazioni per il modulo seriale", + "enabled": { + "label": "Modulo abilitato", + "description": "Abilita output seriale" + }, + "echo": { + "label": "Echo", + "description": "Tutti i pacchetti che invii verranno rimandati indietro al tuo dispositivo" + }, + "rxd": { + "label": "Pin di ricezione", + "description": "Imposta il pin GPIO al pin RXD che hai configurato." + }, + "txd": { + "label": "Pin di trasmissione", + "description": "Imposta il pin GPIO al pin TXD che hai configurato." + }, + "baud": { + "label": "Baud rate", + "description": "La velocità di trasmissione seriale" + }, + "timeout": { + "label": "Timeout", + "description": "Secondi da attesa prima di considerare il tuo pacchetto come 'fatto'" + }, + "mode": { + "label": "Modalità", + "description": "Seleziona modalità" + }, + "overrideConsoleSerialPort": { + "label": "Sovrascrivi La Porta Seriale Della Console", + "description": "Se si dispone di una porta seriale collegata alla console, questa verrà sostituita." + } + }, + "storeForward": { + "title": "Configurazione Salva & Inoltra", + "description": "Impostazioni per il modulo Salva & Inoltra", + "enabled": { + "label": "Modulo abilitato", + "description": "Abilita Salva & Inoltra" + }, + "heartbeat": { + "label": "Heartbeat Abilitato", + "description": "Abilita heartbeat Store & Forward" + }, + "records": { + "label": "Numero di record", + "description": "Numero di record da memorizzare" + }, + "historyReturnMax": { + "label": "Cronologia ritorno max", + "description": "Numero massimo di record da restituire" + }, + "historyReturnWindow": { + "label": "Finestra di ritorno cronologia", + "description": "Return records from this time window (minutes)" + } + }, + "telemetry": { + "title": "Impostazioni Telemetria", + "description": "Impostazioni per il modulo Telemetria", + "deviceUpdateInterval": { + "label": "Metriche Dispositivo", + "description": "Intervallo aggiornamento metriche dispositivo (secondi)" + }, + "environmentUpdateInterval": { + "label": "Intervallo aggiornamento metriche ambientali (secondi)", + "description": "" + }, + "environmentMeasurementEnabled": { + "label": "Modulo abilitato", + "description": "Abilita la telemetria Ambiente" + }, + "environmentScreenEnabled": { + "label": "Visualizzato sullo schermo", + "description": "Mostra il modulo di telemetria sull'OLED" + }, + "environmentDisplayFahrenheit": { + "label": "Mostra Fahrenheit", + "description": "Mostra la temperatura in Fahrenheit" + }, + "airQualityEnabled": { + "label": "Qualità Dell'Aria Abilitata", + "description": "Abilita la telemetria della qualità dell'aria" + }, + "airQualityInterval": { + "label": "Intervallo Di Aggiornamento Qualità Dell'Aria", + "description": "Quanto spesso inviare dati sulla qualità dell'aria sulla mesh" + }, + "powerMeasurementEnabled": { + "label": "Misurazione Alimentazione Abilitata", + "description": "Abilita la telemetria di misura della alimentazione" + }, + "powerUpdateInterval": { + "label": "Intervallo Di Aggiornamento Alimentazione", + "description": "Quanto spesso inviare i dati di alimentazione sulla mesh" + }, + "powerScreenEnabled": { + "label": "Schermo Di Alimentazione Abilitato", + "description": "Abilita lo schermo di Telemetria di alimentazione" + } + } } diff --git a/packages/web/public/i18n/locales/it-IT/nodes.json b/packages/web/public/i18n/locales/it-IT/nodes.json index ee0fd6e1f..9346dd703 100644 --- a/packages/web/public/i18n/locales/it-IT/nodes.json +++ b/packages/web/public/i18n/locales/it-IT/nodes.json @@ -1,63 +1,59 @@ { - "nodeDetail": { - "publicKeyEnabled": { - "label": "Chiave Pubblica Abilitata" - }, - "noPublicKey": { - "label": "Nessuna Chiave Pubblica" - }, - "directMessage": { - "label": "Messaggio Diretto {{shortName}}" - }, - "favorite": { - "label": "Preferito", - "tooltip": "Add or remove this node from your favorites" - }, - "notFavorite": { - "label": "Non è un preferito" - }, - "error": { - "label": "Errori", - "text": "An error occurred while fetching node details. Please try again later." - }, - "status": { - "heard": "Sentito", - "mqtt": "MQTT" - }, - "elevation": { - "label": "Altezza" - }, - "channelUtil": { - "label": "Utilizzo Canale" - }, - "airtimeUtil": { - "label": "Utilizzo Airtime" - } - }, - "nodesTable": { - "headings": { - "longName": "Nome Lungo", - "connection": "Connessione", - "lastHeard": "Ultimo Contatto", - "encryption": "Crittografia", - "model": "Modello", - "macAddress": "Indirizzo MAC" - }, - "connectionStatus": { - "direct": "Diretto", - "away": "assente", - "unknown": "-", - "viaMqtt": ", tramite MQTT" - }, - "lastHeardStatus": { - "never": "Mai" - } - }, - "actions": { - "added": "Added", - "removed": "Removed", - "ignoreNode": "Ignore Node", - "unignoreNode": "Unignore Node", - "requestPosition": "Richiedi posizione" - } + "nodeDetail": { + "publicKeyEnabled": { + "label": "Chiave Pubblica Abilitata" + }, + "noPublicKey": { + "label": "Nessuna Chiave Pubblica" + }, + "directMessage": { + "label": "Messaggio Diretto {{shortName}}" + }, + "favorite": { + "label": "Preferito", + "tooltip": "Add or remove this node from your favorites" + }, + "notFavorite": { + "label": "Non è un preferito" + }, + "error": { + "label": "Errori", + "text": "An error occurred while fetching node details. Please try again later." + }, + "status": { + "heard": "Sentito", + "mqtt": "MQTT" + }, + "elevation": { + "label": "Altezza" + }, + "channelUtil": { + "label": "Utilizzo Canale" + }, + "airtimeUtil": { + "label": "Utilizzo Airtime" + } + }, + "nodesTable": { + "headings": { + "longName": "Nome Lungo", + "connection": "Connessione", + "lastHeard": "Ultimo Contatto", + "encryption": "Crittografia", + "model": "Modello", + "macAddress": "Indirizzo MAC" + }, + "connectionStatus": { + "direct": "Diretto", + "away": "assente", + "viaMqtt": ", tramite MQTT" + } + }, + "actions": { + "added": "Added", + "removed": "Removed", + "ignoreNode": "Ignore Node", + "unignoreNode": "Unignore Node", + "requestPosition": "Richiedi posizione" + } } diff --git a/packages/web/public/i18n/locales/it-IT/ui.json b/packages/web/public/i18n/locales/it-IT/ui.json index f5d925cdb..2f8960ee5 100644 --- a/packages/web/public/i18n/locales/it-IT/ui.json +++ b/packages/web/public/i18n/locales/it-IT/ui.json @@ -1,228 +1,230 @@ { - "navigation": { - "title": "Navigazione", - "messages": "Messaggi", - "map": "Mappa", - "config": "Configurazione", - "radioConfig": "Configurazione Radio", - "moduleConfig": "Configurazione Modulo", - "channels": "Canali", - "nodes": "Nodi" - }, - "app": { - "title": "Meshtastic", - "logo": "Logo Meshtastic" - }, - "sidebar": { - "collapseToggle": { - "button": { - "open": "Apri barra laterale", - "close": "Chiudi barra laterale" - } - }, - "deviceInfo": { - "volts": "{{voltage}} volt", - "firmware": { - "title": "Firmware", - "version": "v{{version}}", - "buildDate": "Data di build: {{date}}" - }, - "deviceName": { - "title": "Nome del dispositivo", - "changeName": "Cambia Nome Del Dispositivo", - "placeholder": "Inserisci il nome del dispositivo" - }, - "editDeviceName": "Modifica il nome del dispositivo" - } - }, - "batteryStatus": { - "charging": "{{level}}% in carica", - "pluggedIn": "Alimentato", - "title": "Batteria" - }, - "search": { - "nodes": "Cerca nodi...", - "channels": "Cerca canali...", - "commandPalette": "Cerca comandi..." - }, - "toast": { - "positionRequestSent": { - "title": "Richiesta di posizione inviata." - }, - "requestingPosition": { - "title": "Richiesta di posizione, attendere prego..." - }, - "sendingTraceroute": { - "title": "Invio di Traceroute, attendere prego..." - }, - "tracerouteSent": { - "title": "Traceroute inviato." - }, - "savedChannel": { - "title": "Canale Salvato: {{channelName}}" - }, - "messages": { - "pkiEncryption": { - "title": "La chat sta usando la crittografia PKI." - }, - "pskEncryption": { - "title": "La chat sta usando la crittografia PSK." - } - }, - "configSaveError": { - "title": "Errore Salvataggio Configurazione", - "description": "Si è verificato un errore durante il salvataggio di questa configurazione." - }, - "validationError": { - "title": "Esistono errori di configurazione", - "description": "Correggi gli errori di configurazione prima di salvare." - }, - "saveSuccess": { - "title": "Salvataggio Configurazione", - "description": "La modifica di configurazione {{case}} è stata salvata." - }, - "favoriteNode": { - "title": "{{action}} {{nodeName}} {{direction}} favorites.", - "action": { - "added": "Added", - "removed": "Removed", - "to": "to", - "from": "from" - } - }, - "ignoreNode": { - "title": "{{action}} {{nodeName}} {{direction}} ignore list", - "action": { - "added": "Added", - "removed": "Removed", - "to": "to", - "from": "from" - } - } - }, - "notifications": { - "copied": { - "label": "Copiato!" - }, - "copyToClipboard": { - "label": "Copia negli appunti" - }, - "hidePassword": { - "label": "Nascondi password" - }, - "showPassword": { - "label": "Visualizza password" - }, - "deliveryStatus": { - "delivered": "Consegnato", - "failed": "Consegna Fallita", - "waiting": "In attesa", - "unknown": "Sconosciuto" - } - }, - "general": { - "label": "Generale" - }, - "hardware": { - "label": "Hardware" - }, - "metrics": { - "label": "Statistiche" - }, - "role": { - "label": "Ruolo" - }, - "filter": { - "label": "Filtro" - }, - "advanced": { - "label": "Advanced" - }, - "clearInput": { - "label": "Cancella input" - }, - "resetFilters": { - "label": "Ripristina Filtri" - }, - "nodeName": { - "label": "Nome/numero del nodo", - "placeholder": "Meshtastic 1234" - }, - "airtimeUtilization": { - "label": "Tempo di Trasmissione Utilizzato (%)" - }, - "batteryLevel": { - "label": "Livello batteria (%)", - "labelText": "Livello batteria (%): {{value}}" - }, - "batteryVoltage": { - "label": "Tensione della Batteria (V)", - "title": "Tensione" - }, - "channelUtilization": { - "label": "Utilizzo Canale (%)" - }, - "hops": { - "direct": "Diretto", - "label": "Numero di hop", - "text": "Numero di hop: {{value}}" - }, - "lastHeard": { - "label": "Ricevuto più di recente", - "labelText": "Ultimo contatto: {{value}}", - "nowLabel": "Adesso" - }, - "snr": { - "label": "SNR (dB)" - }, - "favorites": { - "label": "Preferiti" - }, - "hide": { - "label": "Nascondi" - }, - "showOnly": { - "label": "Mostra Solo" - }, - "viaMqtt": { - "label": "Connesso tramite MQTT" - }, - "hopsUnknown": { - "label": "Unknown number of hops" - }, - "showUnheard": { - "label": "Never heard" - }, - "language": { - "label": "Lingua", - "changeLanguage": "Cambia Lingua" - }, - "theme": { - "dark": "Scuro", - "light": "Chiaro", - "system": "Automatico", - "changeTheme": "Modifica lo schema dei colori" - }, - "errorPage": { - "title": "Questo è un po' imbarazzante...", - "description1": "Siamo davvero spiacenti, ma si è verificato un errore nel client web che ha causato il crash.
Questo non dovrebbe accadere e stiamo lavorando duramente per risolverlo.", - "description2": "Il modo migliore per evitare che ciò accada di nuovo a voi o a chiunque altro è quello di riferire la questione a noi.", - "reportInstructions": "Per favore includi le seguenti informazioni nel tuo report:", - "reportSteps": { - "step1": "Cosa stavi facendo quando si è verificato l'errore", - "step2": "Cosa ti aspettavi succedesse", - "step3": "Quello che è successo realmente", - "step4": "Altre informazioni rilevanti" - }, - "reportLink": "Puoi segnalare il problema al nostro <0>GitHub", - "dashboardLink": "Ritorna alla <0>dashboard", - "detailsSummary": "Dettagli Errore", - "errorMessageLabel": "Messaggio di errore:", - "stackTraceLabel": "Stack trace:", - "fallbackError": "{{error}}" - }, - "footer": { - "text": "Powered by <0>▲ Vercel | Meshtastic® è un marchio registrato di Meshtastic LLC. | <1>Informazioni Legali", - "commitSha": "Commit SHA: {{sha}}" - } + "navigation": { + "title": "Navigazione", + "messages": "Messaggi", + "map": "Mappa", + "settings": "Impostazioni", + "channels": "Canali", + "radioConfig": "Configurazione Radio", + "deviceConfig": "Configurazione Dispositivo", + "moduleConfig": "Configurazione Modulo", + "manageConnections": "Manage Connections", + "nodes": "Nodi" + }, + "app": { + "title": "Meshtastic", + "logo": "Logo Meshtastic" + }, + "sidebar": { + "collapseToggle": { + "button": { + "open": "Apri barra laterale", + "close": "Chiudi barra laterale" + } + }, + "deviceInfo": { + "volts": "{{voltage}} volt", + "firmware": { + "title": "Firmware", + "version": "v{{version}}", + "buildDate": "Data di build: {{date}}" + } + } + }, + "batteryStatus": { + "charging": "{{level}}% in carica", + "pluggedIn": "Alimentato", + "title": "Batteria" + }, + "search": { + "nodes": "Cerca nodi...", + "channels": "Cerca canali...", + "commandPalette": "Cerca comandi..." + }, + "toast": { + "positionRequestSent": { + "title": "Richiesta di posizione inviata." + }, + "requestingPosition": { + "title": "Richiesta di posizione, attendere prego..." + }, + "sendingTraceroute": { + "title": "Invio di Traceroute, attendere prego..." + }, + "tracerouteSent": { + "title": "Traceroute inviato." + }, + "savedChannel": { + "title": "Canale Salvato: {{channelName}}" + }, + "messages": { + "pkiEncryption": { + "title": "La chat sta usando la crittografia PKI." + }, + "pskEncryption": { + "title": "La chat sta usando la crittografia PSK." + } + }, + "configSaveError": { + "title": "Errore Salvataggio Configurazione", + "description": "Si è verificato un errore durante il salvataggio di questa configurazione." + }, + "validationError": { + "title": "Esistono errori di configurazione", + "description": "Correggi gli errori di configurazione prima di salvare." + }, + "saveSuccess": { + "title": "Salvataggio Configurazione", + "description": "La modifica di configurazione {{case}} è stata salvata." + }, + "saveAllSuccess": { + "title": "Saved", + "description": "All configuration changes have been saved." + }, + "favoriteNode": { + "title": "{{action}} {{nodeName}} {{direction}} favorites.", + "action": { + "added": "Added", + "removed": "Removed", + "to": "to", + "from": "from" + } + }, + "ignoreNode": { + "title": "{{action}} {{nodeName}} {{direction}} ignore list", + "action": { + "added": "Added", + "removed": "Removed", + "to": "to", + "from": "from" + } + } + }, + "notifications": { + "copied": { + "label": "Copiato!" + }, + "copyToClipboard": { + "label": "Copia negli appunti" + }, + "hidePassword": { + "label": "Nascondi password" + }, + "showPassword": { + "label": "Visualizza password" + }, + "deliveryStatus": { + "delivered": "Consegnato", + "failed": "Consegna Fallita", + "waiting": "In attesa", + "unknown": "Sconosciuto" + } + }, + "general": { + "label": "Generale" + }, + "hardware": { + "label": "Hardware" + }, + "metrics": { + "label": "Statistiche" + }, + "role": { + "label": "Ruolo" + }, + "filter": { + "label": "Filtro" + }, + "advanced": { + "label": "Advanced" + }, + "clearInput": { + "label": "Cancella input" + }, + "resetFilters": { + "label": "Ripristina Filtri" + }, + "nodeName": { + "label": "Nome/numero del nodo", + "placeholder": "Meshtastic 1234" + }, + "airtimeUtilization": { + "label": "Tempo di Trasmissione Utilizzato (%)", + "short": "Airtime Util. (%)" + }, + "batteryLevel": { + "label": "Livello batteria (%)", + "labelText": "Livello batteria (%): {{value}}" + }, + "batteryVoltage": { + "label": "Tensione della Batteria (V)", + "title": "Tensione" + }, + "channelUtilization": { + "label": "Utilizzo Canale (%)", + "short": "Channel Util. (%)" + }, + "hops": { + "direct": "Diretto", + "label": "Numero di hop", + "text": "Numero di hop: {{value}}" + }, + "lastHeard": { + "label": "Ricevuto più di recente", + "labelText": "Ultimo contatto: {{value}}", + "nowLabel": "Adesso" + }, + "snr": { + "label": "SNR (dB)" + }, + "favorites": { + "label": "Preferiti" + }, + "hide": { + "label": "Nascondi" + }, + "showOnly": { + "label": "Mostra Solo" + }, + "viaMqtt": { + "label": "Connesso tramite MQTT" + }, + "hopsUnknown": { + "label": "Unknown number of hops" + }, + "showUnheard": { + "label": "Never heard" + }, + "language": { + "label": "Lingua", + "changeLanguage": "Cambia Lingua" + }, + "theme": { + "dark": "Scuro", + "light": "Chiaro", + "system": "Automatico", + "changeTheme": "Modifica lo schema dei colori" + }, + "errorPage": { + "title": "Questo è un po' imbarazzante...", + "description1": "Siamo davvero spiacenti, ma si è verificato un errore nel client web che ha causato il crash.
Questo non dovrebbe accadere e stiamo lavorando duramente per risolverlo.", + "description2": "Il modo migliore per evitare che ciò accada di nuovo a voi o a chiunque altro è quello di riferire la questione a noi.", + "reportInstructions": "Per favore includi le seguenti informazioni nel tuo report:", + "reportSteps": { + "step1": "Cosa stavi facendo quando si è verificato l'errore", + "step2": "Cosa ti aspettavi succedesse", + "step3": "Quello che è successo realmente", + "step4": "Altre informazioni rilevanti" + }, + "reportLink": "Puoi segnalare il problema al nostro <0>GitHub", + "connectionsLink": "Return to the <0>connections", + "detailsSummary": "Dettagli Errore", + "errorMessageLabel": "Messaggio di errore:", + "stackTraceLabel": "Stack trace:", + "fallbackError": "{{error}}" + }, + "footer": { + "text": "Powered by <0>▲ Vercel | Meshtastic® è un marchio registrato di Meshtastic LLC. | <1>Informazioni Legali", + "commitSha": "Commit SHA: {{sha}}" + } } diff --git a/packages/web/public/i18n/locales/ja-JP/channels.json b/packages/web/public/i18n/locales/ja-JP/channels.json index 594dc7ad2..79991430b 100644 --- a/packages/web/public/i18n/locales/ja-JP/channels.json +++ b/packages/web/public/i18n/locales/ja-JP/channels.json @@ -1,69 +1,71 @@ { - "page": { - "sectionLabel": "チャンネル", - "channelName": "Channel: {{channelName}}", - "broadcastLabel": "プライマリ", - "channelIndex": "Ch {{index}}" - }, - "validation": { - "pskInvalid": "Please enter a valid {{bits}} bit PSK." - }, - "settings": { - "label": "チャンネル設定", - "description": "Crypto, MQTT & misc settings" - }, - "role": { - "label": "役割", - "description": "Device telemetry is sent over PRIMARY. Only one PRIMARY allowed", - "options": { - "primary": "PRIMARY", - "disabled": "DISABLED", - "secondary": "SECONDARY" - } - }, - "psk": { - "label": "Pre-Shared Key", - "description": "Supported PSK lengths: 256-bit, 128-bit, 8-bit, Empty (0-bit)", - "generate": "Generate" - }, - "name": { - "label": "名前", - "description": "A unique name for the channel <12 bytes, leave blank for default" - }, - "uplinkEnabled": { - "label": "Uplink Enabled", - "description": "Send messages from the local mesh to MQTT" - }, - "downlinkEnabled": { - "label": "Downlink Enabled", - "description": "Send messages from MQTT to the local mesh" - }, - "positionPrecision": { - "label": "Location", - "description": "The precision of the location to share with the channel. Can be disabled.", - "options": { - "none": "Do not share location", - "precise": "Precise Location", - "metric_km23": "Within 23 kilometers", - "metric_km12": "Within 12 kilometers", - "metric_km5_8": "Within 5.8 kilometers", - "metric_km2_9": "Within 2.9 kilometers", - "metric_km1_5": "Within 1.5 kilometers", - "metric_m700": "Within 700 meters", - "metric_m350": "Within 350 meters", - "metric_m200": "Within 200 meters", - "metric_m90": "Within 90 meters", - "metric_m50": "Within 50 meters", - "imperial_mi15": "Within 15 miles", - "imperial_mi7_3": "Within 7.3 miles", - "imperial_mi3_6": "Within 3.6 miles", - "imperial_mi1_8": "Within 1.8 miles", - "imperial_mi0_9": "Within 0.9 miles", - "imperial_mi0_5": "Within 0.5 miles", - "imperial_mi0_2": "Within 0.2 miles", - "imperial_ft600": "Within 600 feet", - "imperial_ft300": "Within 300 feet", - "imperial_ft150": "Within 150 feet" - } - } + "page": { + "sectionLabel": "チャンネル", + "channelName": "Channel: {{channelName}}", + "broadcastLabel": "プライマリ", + "channelIndex": "Ch {{index}}", + "import": "インポート", + "export": "Export" + }, + "validation": { + "pskInvalid": "Please enter a valid {{bits}} bit PSK." + }, + "settings": { + "label": "チャンネル設定", + "description": "Crypto, MQTT & misc settings" + }, + "role": { + "label": "役割", + "description": "Device telemetry is sent over PRIMARY. Only one PRIMARY allowed", + "options": { + "primary": "PRIMARY", + "disabled": "DISABLED", + "secondary": "SECONDARY" + } + }, + "psk": { + "label": "Pre-Shared Key", + "description": "Supported PSK lengths: 256-bit, 128-bit, 8-bit, Empty (0-bit)", + "generate": "Generate" + }, + "name": { + "label": "名前", + "description": "A unique name for the channel <12 bytes, leave blank for default" + }, + "uplinkEnabled": { + "label": "Uplink Enabled", + "description": "Send messages from the local mesh to MQTT" + }, + "downlinkEnabled": { + "label": "Downlink Enabled", + "description": "Send messages from MQTT to the local mesh" + }, + "positionPrecision": { + "label": "Location", + "description": "The precision of the location to share with the channel. Can be disabled.", + "options": { + "none": "Do not share location", + "precise": "Precise Location", + "metric_km23": "Within 23 kilometers", + "metric_km12": "Within 12 kilometers", + "metric_km5_8": "Within 5.8 kilometers", + "metric_km2_9": "Within 2.9 kilometers", + "metric_km1_5": "Within 1.5 kilometers", + "metric_m700": "Within 700 meters", + "metric_m350": "Within 350 meters", + "metric_m200": "Within 200 meters", + "metric_m90": "Within 90 meters", + "metric_m50": "Within 50 meters", + "imperial_mi15": "Within 15 miles", + "imperial_mi7_3": "Within 7.3 miles", + "imperial_mi3_6": "Within 3.6 miles", + "imperial_mi1_8": "Within 1.8 miles", + "imperial_mi0_9": "Within 0.9 miles", + "imperial_mi0_5": "Within 0.5 miles", + "imperial_mi0_2": "Within 0.2 miles", + "imperial_ft600": "Within 600 feet", + "imperial_ft300": "Within 300 feet", + "imperial_ft150": "Within 150 feet" + } + } } diff --git a/packages/web/public/i18n/locales/ja-JP/commandPalette.json b/packages/web/public/i18n/locales/ja-JP/commandPalette.json index 8f8b06fc5..aa0c2e65b 100644 --- a/packages/web/public/i18n/locales/ja-JP/commandPalette.json +++ b/packages/web/public/i18n/locales/ja-JP/commandPalette.json @@ -15,7 +15,6 @@ "messages": "メッセージ", "map": "地図", "config": "Config", - "channels": "チャンネル", "nodes": "ノード" } }, @@ -45,7 +44,8 @@ "label": "Debug", "command": { "reconfigure": "Reconfigure", - "clearAllStoredMessages": "Clear All Stored Message" + "clearAllStoredMessages": "Clear All Stored Message", + "clearAllStores": "Clear All Local Storage" } } } diff --git a/packages/web/public/i18n/locales/ja-JP/common.json b/packages/web/public/i18n/locales/ja-JP/common.json index 2dfbfefed..c97e8fad1 100644 --- a/packages/web/public/i18n/locales/ja-JP/common.json +++ b/packages/web/public/i18n/locales/ja-JP/common.json @@ -1,142 +1,165 @@ { - "button": { - "apply": "適用", - "backupKey": "Backup Key", - "cancel": "キャンセル", - "clearMessages": "Clear Messages", - "close": "終了", - "confirm": "Confirm", - "delete": "削除", - "dismiss": "Dismiss", - "download": "Download", - "export": "Export", - "generate": "Generate", - "regenerate": "Regenerate", - "import": "インポート", - "message": "メッセージ", - "now": "Now", - "ok": "OK", - "print": "Print", - "remove": "削除", - "requestNewKeys": "Request New Keys", - "requestPosition": "Request Position", - "reset": "リセット", - "save": "保存", - "scanQr": "QRコードをスキャン", - "traceRoute": "Trace Route", - "submit": "Submit" - }, - "app": { - "title": "Meshtastic", - "fullTitle": "Meshtastic Web Client" - }, - "loading": "Loading...", - "unit": { - "cps": "CPS", - "dbm": "dBm", - "hertz": "Hz", - "hop": { - "one": "Hop", - "plural": "Hops" - }, - "hopsAway": { - "one": "{{count}} hop away", - "plural": "{{count}} hops away", - "unknown": "Unknown hops away" - }, - "megahertz": "MHz", - "raw": "raw", - "meter": { - "one": "Meter", - "plural": "Meters", - "suffix": "m" - }, - "minute": { - "one": "Minute", - "plural": "Minutes" - }, - "hour": { - "one": "Hour", - "plural": "Hours" - }, - "millisecond": { - "one": "Millisecond", - "plural": "Milliseconds", - "suffix": "ms" - }, - "second": { - "one": "Second", - "plural": "Seconds" - }, - "day": { - "one": "Day", - "plural": "Days" - }, - "month": { - "one": "Month", - "plural": "Months" - }, - "year": { - "one": "Year", - "plural": "Years" - }, - "snr": "SN比", - "volt": { - "one": "Volt", - "plural": "Volts", - "suffix": "V" - }, - "record": { - "one": "Records", - "plural": "Records" - } - }, - "security": { - "0bit": "Empty", - "8bit": "8 bit", - "128bit": "128 bit", - "256bit": "256 bit" - }, - "unknown": { - "longName": "Unknown", - "shortName": "UNK", - "notAvailable": "N/A", - "num": "??" - }, - "nodeUnknownPrefix": "!", - "unset": "UNSET", - "fallbackName": "Meshtastic {{last4}}", - "node": "Node", - "formValidation": { - "unsavedChanges": "Unsaved changes", - "tooBig": { - "string": "Too long, expected less than or equal to {{maximum}} characters.", - "number": "Too big, expected a number smaller than or equal to {{maximum}}.", - "bytes": "Too big, expected less than or equal to {{params.maximum}} bytes." - }, - "tooSmall": { - "string": "Too short, expected more than or equal to {{minimum}} characters.", - "number": "Too small, expected a number larger than or equal to {{minimum}}." - }, - "invalidFormat": { - "ipv4": "Invalid format, expected an IPv4 address.", - "key": "Invalid format, expected a Base64 encoded pre-shared key (PSK)." - }, - "invalidType": { - "number": "Invalid type, expected a number." - }, - "pskLength": { - "0bit": "Key is required to be empty.", - "8bit": "Key is required to be an 8 bit pre-shared key (PSK).", - "128bit": "Key is required to be a 128 bit pre-shared key (PSK).", - "256bit": "Key is required to be a 256 bit pre-shared key (PSK)." - }, - "required": { - "generic": "This field is required.", - "managed": "At least one admin key is requred if the node is managed.", - "key": "Key is required." - } - }, - "yes": "Yes", - "no": "No" + "button": { + "apply": "適用", + "addConnection": "Add Connection", + "saveConnection": "Save connection", + "backupKey": "Backup Key", + "cancel": "キャンセル", + "connect": "Connect", + "clearMessages": "Clear Messages", + "close": "終了", + "confirm": "Confirm", + "delete": "削除", + "dismiss": "Dismiss", + "download": "Download", + "disconnect": "Disconnect", + "export": "Export", + "generate": "Generate", + "regenerate": "Regenerate", + "import": "インポート", + "message": "メッセージ", + "now": "Now", + "ok": "OK", + "print": "Print", + "remove": "削除", + "requestNewKeys": "Request New Keys", + "requestPosition": "Request Position", + "reset": "リセット", + "retry": "Retry", + "save": "保存", + "setDefault": "Set as default", + "unsetDefault": "Unset default", + "scanQr": "QRコードをスキャン", + "traceRoute": "Trace Route", + "submit": "Submit" + }, + "app": { + "title": "Meshtastic", + "fullTitle": "Meshtastic Web Client" + }, + "loading": "Loading...", + "unit": { + "cps": "CPS", + "dbm": "dBm", + "hertz": "Hz", + "hop": { + "one": "Hop", + "plural": "Hops" + }, + "hopsAway": { + "one": "{{count}} hop away", + "plural": "{{count}} hops away", + "unknown": "Unknown hops away" + }, + "megahertz": "MHz", + "kilohertz": "kHz", + "raw": "raw", + "meter": { + "one": "Meter", + "plural": "Meters", + "suffix": "m" + }, + "kilometer": { + "one": "Kilometer", + "plural": "Kilometers", + "suffix": "km" + }, + "minute": { + "one": "Minute", + "plural": "Minutes" + }, + "hour": { + "one": "Hour", + "plural": "Hours" + }, + "millisecond": { + "one": "Millisecond", + "plural": "Milliseconds", + "suffix": "ms" + }, + "second": { + "one": "Second", + "plural": "Seconds" + }, + "day": { + "one": "Day", + "plural": "Days", + "today": "Today", + "yesterday": "Yesterday" + }, + "month": { + "one": "Month", + "plural": "Months" + }, + "year": { + "one": "Year", + "plural": "Years" + }, + "snr": "SN比", + "volt": { + "one": "Volt", + "plural": "Volts", + "suffix": "V" + }, + "record": { + "one": "Records", + "plural": "Records" + }, + "degree": { + "one": "Degree", + "plural": "Degrees", + "suffix": "°" + } + }, + "security": { + "0bit": "Empty", + "8bit": "8 bit", + "128bit": "128 bit", + "256bit": "256 bit" + }, + "unknown": { + "longName": "Unknown", + "shortName": "UNK", + "notAvailable": "N/A", + "num": "??" + }, + "nodeUnknownPrefix": "!", + "unset": "UNSET", + "fallbackName": "Meshtastic {{last4}}", + "node": "Node", + "formValidation": { + "unsavedChanges": "Unsaved changes", + "tooBig": { + "string": "Too long, expected less than or equal to {{maximum}} characters.", + "number": "Too big, expected a number smaller than or equal to {{maximum}}.", + "bytes": "Too big, expected less than or equal to {{params.maximum}} bytes." + }, + "tooSmall": { + "string": "Too short, expected more than or equal to {{minimum}} characters.", + "number": "Too small, expected a number larger than or equal to {{minimum}}." + }, + "invalidFormat": { + "ipv4": "Invalid format, expected an IPv4 address.", + "key": "Invalid format, expected a Base64 encoded pre-shared key (PSK)." + }, + "invalidType": { + "number": "Invalid type, expected a number." + }, + "pskLength": { + "0bit": "Key is required to be empty.", + "8bit": "Key is required to be an 8 bit pre-shared key (PSK).", + "128bit": "Key is required to be a 128 bit pre-shared key (PSK).", + "256bit": "Key is required to be a 256 bit pre-shared key (PSK)." + }, + "required": { + "generic": "This field is required.", + "managed": "At least one admin key is requred if the node is managed.", + "key": "Key is required." + }, + "invalidOverrideFreq": { + "number": "Invalid format, expected a value in the range 410-930 MHz or 0 (use default)." + } + }, + "yes": "Yes", + "no": "No" } diff --git a/packages/web/public/i18n/locales/ja-JP/config.json b/packages/web/public/i18n/locales/ja-JP/config.json new file mode 100644 index 000000000..384881546 --- /dev/null +++ b/packages/web/public/i18n/locales/ja-JP/config.json @@ -0,0 +1,458 @@ +{ + "page": { + "title": "設定", + "tabUser": "ユーザー", + "tabChannels": "チャンネル", + "tabBluetooth": "Bluetooth", + "tabDevice": "接続するデバイスを選択", + "tabDisplay": "表示", + "tabLora": "LoRa", + "tabNetwork": "ネットワーク", + "tabPosition": "位置", + "tabPower": "電源", + "tabSecurity": "セキュリティ" + }, + "sidebar": { + "label": "Configuration" + }, + "device": { + "title": "Device Settings", + "description": "Settings for the device", + "buttonPin": { + "description": "Button pin override", + "label": "Button Pin" + }, + "buzzerPin": { + "description": "Buzzer pin override", + "label": "Buzzer Pin" + }, + "disableTripleClick": { + "description": "Disable triple click", + "label": "Disable Triple Click" + }, + "doubleTapAsButtonPress": { + "description": "Treat double tap as button press", + "label": "Double Tap as Button Press" + }, + "ledHeartbeatDisabled": { + "description": "Disable default blinking LED", + "label": "LED Heartbeat Disabled" + }, + "nodeInfoBroadcastInterval": { + "description": "How often to broadcast node info", + "label": "Node Info Broadcast Interval" + }, + "posixTimezone": { + "description": "The POSIX timezone string for the device", + "label": "POSIX 時間帯" + }, + "rebroadcastMode": { + "description": "How to handle rebroadcasting", + "label": "Rebroadcast Mode" + }, + "role": { + "description": "What role the device performs on the mesh", + "label": "役割" + } + }, + "bluetooth": { + "title": "Bluetooth Settings", + "description": "Settings for the Bluetooth module", + "note": "Note: Some devices (ESP32) cannot use both Bluetooth and WiFi at the same time.", + "enabled": { + "description": "Enable or disable Bluetooth", + "label": "Enabled" + }, + "pairingMode": { + "description": "Pin selection behaviour.", + "label": "ペアリングモード" + }, + "pin": { + "description": "Pin to use when pairing", + "label": "Pin" + } + }, + "display": { + "description": "Settings for the device display", + "title": "Display Settings", + "headingBold": { + "description": "Bolden the heading text", + "label": "Bold Heading" + }, + "carouselDelay": { + "description": "How fast to cycle through windows", + "label": "Carousel Delay" + }, + "compassNorthTop": { + "description": "Fix north to the top of compass", + "label": "Compass North Top" + }, + "displayMode": { + "description": "Screen layout variant", + "label": "Display Mode" + }, + "displayUnits": { + "description": "Display metric or imperial units", + "label": "Display Units" + }, + "flipScreen": { + "description": "Flip display 180 degrees", + "label": "Flip Screen" + }, + "gpsDisplayUnits": { + "description": "Coordinate display format", + "label": "GPS Display Units" + }, + "oledType": { + "description": "Type of OLED screen attached to the device", + "label": "OLED Type" + }, + "screenTimeout": { + "description": "Turn off the display after this long", + "label": "Screen Timeout" + }, + "twelveHourClock": { + "description": "Use 12-hour clock format", + "label": "12-Hour Clock" + }, + "wakeOnTapOrMotion": { + "description": "Wake the device on tap or motion", + "label": "Wake on Tap or Motion" + } + }, + "lora": { + "title": "Mesh Settings", + "description": "Settings for the LoRa mesh", + "bandwidth": { + "description": "Channel bandwidth in kHz", + "label": "帯域" + }, + "boostedRxGain": { + "description": "Boosted RX gain", + "label": "Boosted RX Gain" + }, + "codingRate": { + "description": "The denominator of the coding rate", + "label": "Coding Rate" + }, + "frequencyOffset": { + "description": "Frequency offset to correct for crystal calibration errors", + "label": "Frequency Offset" + }, + "frequencySlot": { + "description": "LoRa frequency channel number", + "label": "Frequency Slot" + }, + "hopLimit": { + "description": "Maximum number of hops", + "label": "Hop Limit" + }, + "ignoreMqtt": { + "description": "Don't forward MQTT messages over the mesh", + "label": "MQTT を無視" + }, + "modemPreset": { + "description": "Modem preset to use", + "label": "モデムプリセット" + }, + "okToMqtt": { + "description": "When set to true, this configuration indicates that the user approves the packet to be uploaded to MQTT. If set to false, remote nodes are requested not to forward packets to MQTT", + "label": "MQTTを許可" + }, + "overrideDutyCycle": { + "description": "デューティサイクルを上書き", + "label": "デューティサイクルを上書き" + }, + "overrideFrequency": { + "description": "Override frequency", + "label": "Override Frequency" + }, + "region": { + "description": "Sets the region for your node", + "label": "リージョン" + }, + "spreadingFactor": { + "description": "Indicates the number of chirps per symbol", + "label": "Spreading Factor" + }, + "transmitEnabled": { + "description": "Enable/Disable transmit (TX) from the LoRa radio", + "label": "Transmit Enabled" + }, + "transmitPower": { + "description": "Max transmit power", + "label": "Transmit Power" + }, + "usePreset": { + "description": "Use one of the predefined modem presets", + "label": "Use Preset" + }, + "meshSettings": { + "description": "Settings for the LoRa mesh", + "label": "Mesh Settings" + }, + "waveformSettings": { + "description": "Settings for the LoRa waveform", + "label": "Waveform Settings" + }, + "radioSettings": { + "label": "Radio Settings", + "description": "Settings for the LoRa radio" + } + }, + "network": { + "title": "WiFi Config", + "description": "WiFi radio configuration", + "note": "Note: Some devices (ESP32) cannot use both Bluetooth and WiFi at the same time.", + "addressMode": { + "description": "Address assignment selection", + "label": "Address Mode" + }, + "dns": { + "description": "DNS Server", + "label": "DNS" + }, + "ethernetEnabled": { + "description": "Enable or disable the Ethernet port", + "label": "Enabled" + }, + "gateway": { + "description": "Default Gateway", + "label": "ゲートウェイ" + }, + "ip": { + "description": "IP Address", + "label": "IP" + }, + "psk": { + "description": "Network password", + "label": "PSK" + }, + "ssid": { + "description": "Network name", + "label": "SSID" + }, + "subnet": { + "description": "Subnet Mask", + "label": "サブネット" + }, + "wifiEnabled": { + "description": "Enable or disable the WiFi radio", + "label": "Enabled" + }, + "meshViaUdp": { + "label": "Mesh via UDP" + }, + "ntpServer": { + "label": "NTP Server" + }, + "rsyslogServer": { + "label": "Rsyslog Server" + }, + "ethernetConfigSettings": { + "description": "Ethernet port configuration", + "label": "Ethernet Config" + }, + "ipConfigSettings": { + "description": "IP configuration", + "label": "IP Config" + }, + "ntpConfigSettings": { + "description": "NTP configuration", + "label": "NTP Config" + }, + "rsyslogConfigSettings": { + "description": "Rsyslog configuration", + "label": "Rsyslog Config" + }, + "udpConfigSettings": { + "description": "UDP over Mesh configuration", + "label": "UDP Config" + } + }, + "position": { + "title": "Position Settings", + "description": "Settings for the position module", + "broadcastInterval": { + "description": "How often your position is sent out over the mesh", + "label": "Broadcast Interval" + }, + "enablePin": { + "description": "GPS module enable pin override", + "label": "Enable Pin" + }, + "fixedPosition": { + "description": "Don't report GPS position, but a manually-specified one", + "label": "Fixed Position" + }, + "gpsMode": { + "description": "Configure whether device GPS is Enabled, Disabled, or Not Present", + "label": "GPS Mode" + }, + "gpsUpdateInterval": { + "description": "How often a GPS fix should be acquired", + "label": "GPS Update Interval" + }, + "positionFlags": { + "description": "Optional fields to include when assembling position messages. The more fields are selected, the larger the message will be leading to longer airtime usage and a higher risk of packet loss.", + "label": "Position Flags" + }, + "receivePin": { + "description": "GPS module RX pin override", + "label": "Receive Pin" + }, + "smartPositionEnabled": { + "description": "Only send position when there has been a meaningful change in location", + "label": "Enable Smart Position" + }, + "smartPositionMinDistance": { + "description": "Minimum distance (in meters) that must be traveled before a position update is sent", + "label": "Smart Position Minimum Distance" + }, + "smartPositionMinInterval": { + "description": "Minimum interval (in seconds) that must pass before a position update is sent", + "label": "Smart Position Minimum Interval" + }, + "transmitPin": { + "description": "GPS module TX pin override", + "label": "Transmit Pin" + }, + "intervalsSettings": { + "description": "How often to send position updates", + "label": "Intervals" + }, + "flags": { + "placeholder": "Select position flags...", + "altitude": "Altitude", + "altitudeGeoidalSeparation": "Altitude Geoidal Separation", + "altitudeMsl": "Altitude is Mean Sea Level", + "dop": "Dilution of precision (DOP) PDOP used by default", + "hdopVdop": "If DOP is set, use HDOP / VDOP values instead of PDOP", + "numSatellites": "Number of satellites", + "sequenceNumber": "Sequence number", + "timestamp": "タイムスタンプ", + "unset": "削除", + "vehicleHeading": "Vehicle heading", + "vehicleSpeed": "Vehicle speed" + } + }, + "power": { + "adcMultiplierOverride": { + "description": "Used for tweaking battery voltage reading", + "label": "ADC Multiplier Override ratio" + }, + "ina219Address": { + "description": "Address of the INA219 battery monitor", + "label": "INA219 Address" + }, + "lightSleepDuration": { + "description": "How long the device will be in light sleep for", + "label": "Light Sleep Duration" + }, + "minimumWakeTime": { + "description": "Minimum amount of time the device will stay awake for after receiving a packet", + "label": "Minimum Wake Time" + }, + "noConnectionBluetoothDisabled": { + "description": "If the device does not receive a Bluetooth connection, the BLE radio will be disabled after this long", + "label": "No Connection Bluetooth Disabled" + }, + "powerSavingEnabled": { + "description": "Select if powered from a low-current source (i.e. solar), to minimize power consumption as much as possible.", + "label": "省電力モードを有効化" + }, + "shutdownOnBatteryDelay": { + "description": "Automatically shutdown node after this long when on battery, 0 for indefinite", + "label": "Shutdown on battery delay" + }, + "superDeepSleepDuration": { + "description": "How long the device will be in super deep sleep for", + "label": "Super Deep Sleep Duration" + }, + "powerConfigSettings": { + "description": "Settings for the power module", + "label": "電源設定" + }, + "sleepSettings": { + "description": "Sleep settings for the power module", + "label": "Sleep Settings" + } + }, + "security": { + "description": "Settings for the Security configuration", + "title": "Security Settings", + "button_backupKey": "Backup Key", + "adminChannelEnabled": { + "description": "Allow incoming device control over the insecure legacy admin channel", + "label": "Allow Legacy Admin" + }, + "enableDebugLogApi": { + "description": "Output live debug logging over serial, view and export position-redacted device logs over Bluetooth", + "label": "Enable Debug Log API" + }, + "managed": { + "description": "If enabled, device configuration options are only able to be changed remotely by a Remote Admin node via admin messages. Do not enable this option unless at least one suitable Remote Admin node has been setup, and the public key is stored in one of the fields above.", + "label": "Managed" + }, + "privateKey": { + "description": "Used to create a shared key with a remote device", + "label": "秘密鍵" + }, + "publicKey": { + "description": "Sent out to other nodes on the mesh to allow them to compute a shared secret key", + "label": "公開鍵" + }, + "primaryAdminKey": { + "description": "The primary public key authorized to send admin messages to this node", + "label": "Primary Admin Key" + }, + "secondaryAdminKey": { + "description": "The secondary public key authorized to send admin messages to this node", + "label": "Secondary Admin Key" + }, + "serialOutputEnabled": { + "description": "Serial Console over the Stream API", + "label": "Serial Output Enabled" + }, + "tertiaryAdminKey": { + "description": "The tertiary public key authorized to send admin messages to this node", + "label": "Tertiary Admin Key" + }, + "adminSettings": { + "description": "Settings for Admin", + "label": "Admin Settings" + }, + "loggingSettings": { + "description": "Settings for Logging", + "label": "Logging Settings" + } + }, + "user": { + "title": "User Settings", + "description": "Configure your device name and identity settings", + "longName": { + "label": "Long Name", + "description": "Your full display name (1-40 characters)", + "validation": { + "min": "Long name must be at least 1 character", + "max": "Long name must be at most 40 characters" + } + }, + "shortName": { + "label": "Short Name", + "description": "Your abbreviated name (2-4 characters)", + "validation": { + "min": "Short name must be at least 2 characters", + "max": "Short name must be at most 4 characters" + } + }, + "isUnmessageable": { + "label": "メッセージ不可", + "description": "Used to identify unmonitored or infrastructure nodes so that messaging is not available to nodes that will never respond." + }, + "isLicensed": { + "label": "アマチュア無線免許所持者向け (HAM)", + "description": "Enable if you are a licensed amateur radio operator, enabling this option disables encryption and is not compatible with the default Meshtastic network." + } + } +} diff --git a/packages/web/public/i18n/locales/ja-JP/connections.json b/packages/web/public/i18n/locales/ja-JP/connections.json new file mode 100644 index 000000000..3393425a2 --- /dev/null +++ b/packages/web/public/i18n/locales/ja-JP/connections.json @@ -0,0 +1,34 @@ +{ + "page": { + "title": "Connect to a Meshtastic device", + "description": "Add a device connection via HTTP, Bluetooth, or Serial. Your saved connections will be saved in your browser." + }, + "connectionType_ble": "BLE", + "connectionType_serial": "シリアル", + "connectionType_network": "ネットワーク", + "deleteConnection": "Delete connection", + "areYouSure": "This will remove {{name}}. You canot undo this action.", + "moreActions": "More actions", + "noConnections": { + "title": "No connections yet.", + "description": "Create your first connection. It will connect immediately and be saved for later." + }, + "lastConnectedAt": "Last connected: {{date}}", + "neverConnected": "Never connected", + "toasts": { + "connected": "Connected", + "nowConnected": "{{name}} is now connected", + "nowDisconnected": "{{name}} are now disconnecte", + "disconnected": "切断", + "failed": "Failed to connect", + "checkConnetion": "Check your device or settings and try again", + "defaultSet": "Default set", + "defaultConnection": "Default connection is now {{nameisconnected}}", + "deleted": "Deleted", + "deletedByName": "{{name}} was removed", + "pickConnectionAgain": "Could not connect. You may need to reselect the device/port.", + "added": "Connection added", + "savedByName": "{{name}} saved.", + "savedCantConnect": "The connection was saved but could not connect." + } +} diff --git a/packages/web/public/i18n/locales/ja-JP/dashboard.json b/packages/web/public/i18n/locales/ja-JP/dashboard.json deleted file mode 100644 index eda0d5924..000000000 --- a/packages/web/public/i18n/locales/ja-JP/dashboard.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "dashboard": { - "title": "Connected Devices", - "description": "Manage your connected Meshtastic devices.", - "connectionType_ble": "BLE", - "connectionType_serial": "シリアル", - "connectionType_network": "ネットワーク", - "noDevicesTitle": "No devices connected", - "noDevicesDescription": "Connect a new device to get started.", - "button_newConnection": "New Connection" - } -} diff --git a/packages/web/public/i18n/locales/ja-JP/deviceConfig.json b/packages/web/public/i18n/locales/ja-JP/deviceConfig.json index dea227ee3..35d47aa86 100644 --- a/packages/web/public/i18n/locales/ja-JP/deviceConfig.json +++ b/packages/web/public/i18n/locales/ja-JP/deviceConfig.json @@ -122,7 +122,7 @@ "title": "Mesh Settings", "description": "Settings for the LoRa mesh", "bandwidth": { - "description": "Channel bandwidth in MHz", + "description": "Channel bandwidth in kHz", "label": "帯域" }, "boostedRxGain": { diff --git a/packages/web/public/i18n/locales/ja-JP/dialog.json b/packages/web/public/i18n/locales/ja-JP/dialog.json index da289ba39..48bac99b6 100644 --- a/packages/web/public/i18n/locales/ja-JP/dialog.json +++ b/packages/web/public/i18n/locales/ja-JP/dialog.json @@ -1,193 +1,238 @@ { - "deleteMessages": { - "description": "This action will clear all message history. This cannot be undone. Are you sure you want to continue?", - "title": "Clear All Messages" - }, - "deviceName": { - "description": "The Device will restart once the config is saved.", - "longName": "Long Name", - "shortName": "Short Name", - "title": "Change Device Name", - "validation": { - "longNameMax": "Long name must not be more than 40 characters", - "shortNameMax": "Short name must not be more than 4 characters", - "longNameMin": "Long name must have at least 1 character", - "shortNameMin": "Short name must have at least 1 character" - } - }, - "import": { - "description": "The current LoRa configuration will be overridden.", - "error": { - "invalidUrl": "Invalid Meshtastic URL" - }, - "channelPrefix": "Channel: ", - "channelSetUrl": "Channel Set/QR Code URL", - "channels": "Channels:", - "usePreset": "Use Preset?", - "title": "Import Channel Set" - }, - "locationResponse": { - "title": "Location: {{identifier}}", - "altitude": "Altitude: ", - "coordinates": "Coordinates: ", - "noCoordinates": "No Coordinates" - }, - "pkiRegenerateDialog": { - "title": "Regenerate Pre-Shared Key?", - "description": "Are you sure you want to regenerate the pre-shared key?", - "regenerate": "Regenerate" - }, - "newDeviceDialog": { - "title": "Connect New Device", - "https": "https", - "http": "http", - "tabHttp": "HTTP", - "tabBluetooth": "Bluetooth", - "tabSerial": "シリアル", - "useHttps": "Use HTTPS", - "connecting": "Connecting...", - "connect": "Connect", - "connectionFailedAlert": { - "title": "Connection Failed", - "descriptionPrefix": "Could not connect to the device. ", - "httpsHint": "If using HTTPS, you may need to accept a self-signed certificate first. ", - "openLinkPrefix": "Please open ", - "openLinkSuffix": " in a new tab", - "acceptTlsWarningSuffix": ", accept any TLS warnings if prompted, then try again", - "learnMoreLink": "Learn more" - }, - "httpConnection": { - "label": "IP Address/Hostname", - "placeholder": "000.000.000.000 / meshtastic.local" - }, - "serialConnection": { - "noDevicesPaired": "No devices paired yet.", - "newDeviceButton": "New device", - "deviceIdentifier": "# {{index}} - {{vendorId}} - {{productId}}" - }, - "bluetoothConnection": { - "noDevicesPaired": "No devices paired yet.", - "newDeviceButton": "New device", - "connectionFailed": "Connection failed", - "deviceDisconnected": "Device disconnected", - "unknownDevice": "Unknown Device", - "errorLoadingDevices": "Error loading devices", - "unknownErrorLoadingDevices": "Unknown error loading devices" - }, - "validation": { - "requiresWebBluetooth": "This connection type requires <0>Web Bluetooth. Please use a supported browser, like Chrome or Edge.", - "requiresWebSerial": "This connection type requires <0>Web Serial. Please use a supported browser, like Chrome or Edge.", - "requiresSecureContext": "This application requires a <0>secure context. Please connect using HTTPS or localhost.", - "additionallyRequiresSecureContext": "Additionally, it requires a <0>secure context. Please connect using HTTPS or localhost." - } - }, - "nodeDetails": { - "message": "メッセージ", - "requestPosition": "Request Position", - "traceRoute": "Trace Route", - "airTxUtilization": "Air TX utilization", - "allRawMetrics": "All Raw Metrics:", - "batteryLevel": "Battery level", - "channelUtilization": "Channel utilization", - "details": "Details:", - "deviceMetrics": "Device Metrics:", - "hardware": "Hardware: ", - "lastHeard": "Last Heard: ", - "nodeHexPrefix": "Node Hex: ", - "nodeNumber": "Node Number: ", - "position": "Position:", - "role": "Role: ", - "uptime": "Uptime: ", - "voltage": "電圧", - "title": "Node Details for {{identifier}}", - "ignoreNode": "Ignore node", - "removeNode": "Remove node", - "unignoreNode": "Unignore node", - "security": "Security:", - "publicKey": "Public Key: ", - "messageable": "Messageable: ", - "KeyManuallyVerifiedTrue": "Public Key has been manually verified", - "KeyManuallyVerifiedFalse": "Public Key is not manually verified" - }, - "pkiBackup": { - "loseKeysWarning": "If you lose your keys, you will need to reset your device.", - "secureBackup": "Its important to backup your public and private keys and store your backup securely!", - "footer": "=== END OF KEYS ===", - "header": "=== MESHTASTIC KEYS FOR {{longName}} ({{shortName}}) ===", - "privateKey": "Private Key:", - "publicKey": "Public Key:", - "fileName": "meshtastic_keys_{{longName}}_{{shortName}}.txt", - "title": "Backup Keys" - }, - "pkiBackupReminder": { - "description": "We recommend backing up your key data regularly. Would you like to back up now?", - "title": "Backup Reminder", - "remindLaterPrefix": "Remind me in", - "remindNever": "Never remind me", - "backupNow": "Back up now" - }, - "pkiRegenerate": { - "description": "Are you sure you want to regenerate key pair?", - "title": "Regenerate Key Pair" - }, - "qr": { - "addChannels": "Add Channels", - "replaceChannels": "Replace Channels", - "description": "The current LoRa configuration will also be shared.", - "sharableUrl": "Sharable URL", - "title": "Generate QR Code" - }, - "reboot": { - "title": "Reboot device", - "description": "Reboot now or schedule a reboot of the connected node. Optionally, you can choose to reboot into OTA (Over-the-Air) mode.", - "ota": "Reboot into OTA mode", - "enterDelay": "Enter delay", - "scheduled": "Reboot has been scheduled", - "schedule": "Schedule reboot", - "now": "Reboot now", - "cancel": "Cancel scheduled reboot" - }, - "refreshKeys": { - "description": { - "acceptNewKeys": "This will remove the node from device and request new keys.", - "keyMismatchReasonSuffix": ". This is due to the remote node's current public key does not match the previously stored key for this node.", - "unableToSendDmPrefix": "Your node is unable to send a direct message to node: " - }, - "acceptNewKeys": "Accept New Keys", - "title": "Keys Mismatch - {{identifier}}" - }, - "removeNode": { - "description": "Are you sure you want to remove this Node?", - "title": "Remove Node?" - }, - "shutdown": { - "title": "Schedule Shutdown", - "description": "Turn off the connected node after x minutes." - }, - "traceRoute": { - "routeToDestination": "Route to destination:", - "routeBack": "Route back:" - }, - "tracerouteResponse": { - "title": "Traceroute: {{identifier}}" - }, - "unsafeRoles": { - "confirmUnderstanding": "Yes, I know what I'm doing", - "conjunction": " and the blog post about ", - "postamble": " and understand the implications of changing the role.", - "preamble": "I have read the ", - "choosingRightDeviceRole": "Choosing The Right Device Role", - "deviceRoleDocumentation": "Device Role Documentation", - "title": "よろしいですか?" - }, - "managedMode": { - "confirmUnderstanding": "Yes, I know what I'm doing", - "title": "よろしいですか?", - "description": "Enabling Managed Mode blocks client applications (including the web client) from writing configurations to a radio. Once enabled, radio configurations can only be changed through Remote Admin messages. This setting is not required for remote node administration." - }, - "clientNotification": { - "title": "Client Notification", - "TraceRoute can only be sent once every 30 seconds": "TraceRoute can only be sent once every 30 seconds", - "Compromised keys were detected and regenerated.": "Compromised keys were detected and regenerated." - } + "deleteMessages": { + "description": "This action will clear all message history. This cannot be undone. Are you sure you want to continue?", + "title": "Clear All Messages" + }, + "import": { + "description": "The current LoRa configuration will be overridden.", + "error": { + "invalidUrl": "Invalid Meshtastic URL" + }, + "channelPrefix": "Channel: ", + "primary": "Primary ", + "doNotImport": "No not import", + "channelName": "名前", + "channelSlot": "スロット", + "channelSetUrl": "Channel Set/QR Code URL", + "useLoraConfig": "Import LoRa Config", + "presetDescription": "The current LoRa Config will be replaced.", + "title": "Import Channel Set" + }, + "locationResponse": { + "title": "Location: {{identifier}}", + "altitude": "Altitude: ", + "coordinates": "Coordinates: ", + "noCoordinates": "No Coordinates" + }, + "pkiRegenerateDialog": { + "title": "Regenerate Pre-Shared Key?", + "description": "Are you sure you want to regenerate the pre-shared key?", + "regenerate": "Regenerate" + }, + "addConnection": { + "title": "Add connection", + "description": "Choose a connection type and fill in the details", + "validation": { + "requiresWebBluetooth": "This connection type requires <0>Web Bluetooth. Please use a supported browser, like Chrome or Edge.", + "requiresWebSerial": "This connection type requires <0>Web Serial. Please use a supported browser, like Chrome or Edge.", + "requiresSecureContext": "This application requires a <0>secure context. Please connect using HTTPS or localhost.", + "additionallyRequiresSecureContext": "Additionally, it requires a <0>secure context. Please connect using HTTPS or localhost." + }, + "bluetoothConnection": { + "namePlaceholder": "My Bluetooth Node", + "supported": { + "title": "Web Bluetooth supported" + }, + "notSupported": { + "title": "Web Bluetooth not supported", + "description": "Your browser or device does not support Web Bluetooth" + }, + "short": "BT: {{deviceName}}", + "long": "Bluetooth Device", + "device": "接続するデバイスを選択", + "selectDevice": "Select device", + "selected": "Bluetooth device selected", + "notSelected": "No device selected", + "helperText": "Uses the Meshtastic Bluetooth service for discovery." + }, + "serialConnection": { + "namePlaceholder": "My Serial Node", + "helperText": "Selecting a port grants permission so the app can open it to connect.", + "supported": { + "title": "Web Serial supported" + }, + "notSupported": { + "title": "Web Serial not supported", + "description": "Your browser or device does not support Web Serial" + }, + "portSelected": { + "title": "Serial port selected", + "description": "Port permissions granted." + }, + "port": "Port", + "selectPort": "Select port", + "deviceName": "USB {{vendorId}}:{{productId}}", + "notSelected": "No port selected" + }, + "httpConnection": { + "namePlaceholder": "My HTTP Node", + "inputPlaceholder": "192.168.1.10 or meshtastic.local", + "heading": "URL or IP", + "useHttps": "Use HTTTPS", + "invalidUrl": { + "title": "Invalid URL", + "description": "Please enter a valid HTTP or HTTPS URL." + }, + "connectionTest": { + "description": "Test the connetion before saving to verify the device is reachable.", + "button": { + "loading": "Testing...", + "label": "Test connection" + }, + "reachable": "Reachable", + "notReachable": "Not reachable", + "success": { + "title": "Connection test successful", + "description": "The device appears to be reachable." + }, + "failure": { + "title": "Connection test failed", + "description": "Could not reach the device. Check the URL and try again." + } + } + } + }, + "nodeDetails": { + "message": "メッセージ", + "requestPosition": "Request Position", + "traceRoute": "Trace Route", + "airTxUtilization": "Air TX utilization", + "allRawMetrics": "All Raw Metrics:", + "batteryLevel": "Battery level", + "channelUtilization": "Channel utilization", + "details": "Details:", + "deviceMetrics": "Device Metrics:", + "hardware": "Hardware: ", + "lastHeard": "Last Heard: ", + "nodeHexPrefix": "Node Hex: ", + "nodeNumber": "Node Number: ", + "position": "Position:", + "role": "Role: ", + "uptime": "Uptime: ", + "voltage": "電圧", + "title": "Node Details for {{identifier}}", + "ignoreNode": "Ignore node", + "removeNode": "Remove node", + "unignoreNode": "Unignore node", + "security": "Security:", + "publicKey": "Public Key: ", + "messageable": "Messageable: ", + "KeyManuallyVerifiedTrue": "Public Key has been manually verified", + "KeyManuallyVerifiedFalse": "Public Key is not manually verified" + }, + "pkiBackup": { + "loseKeysWarning": "If you lose your keys, you will need to reset your device.", + "secureBackup": "Its important to backup your public and private keys and store your backup securely!", + "footer": "=== END OF KEYS ===", + "header": "=== MESHTASTIC KEYS FOR {{longName}} ({{shortName}}) ===", + "privateKey": "Private Key:", + "publicKey": "Public Key:", + "fileName": "meshtastic_keys_{{longName}}_{{shortName}}.txt", + "title": "Backup Keys" + }, + "pkiBackupReminder": { + "description": "We recommend backing up your key data regularly. Would you like to back up now?", + "title": "Backup Reminder", + "remindLaterPrefix": "Remind me in", + "remindNever": "Never remind me", + "backupNow": "Back up now" + }, + "pkiRegenerate": { + "description": "Are you sure you want to regenerate key pair?", + "title": "Regenerate Key Pair" + }, + "qr": { + "addChannels": "Add Channels", + "replaceChannels": "Replace Channels", + "description": "The current LoRa configuration will also be shared.", + "sharableUrl": "Sharable URL", + "title": "Generate QR Code" + }, + "reboot": { + "title": "Reboot device", + "description": "Reboot now or schedule a reboot of the connected node. Optionally, you can choose to reboot into OTA (Over-the-Air) mode.", + "ota": "Reboot into OTA mode", + "enterDelay": "Enter delay", + "scheduled": "Reboot has been scheduled", + "schedule": "Schedule reboot", + "now": "Reboot now", + "cancel": "Cancel scheduled reboot" + }, + "refreshKeys": { + "description": { + "acceptNewKeys": "This will remove the node from device and request new keys.", + "keyMismatchReasonSuffix": ". This is due to the remote node's current public key does not match the previously stored key for this node.", + "unableToSendDmPrefix": "Your node is unable to send a direct message to node: " + }, + "acceptNewKeys": "Accept New Keys", + "title": "Keys Mismatch - {{identifier}}" + }, + "removeNode": { + "description": "Are you sure you want to remove this Node?", + "title": "Remove Node?" + }, + "shutdown": { + "title": "Schedule Shutdown", + "description": "Turn off the connected node after x minutes." + }, + "traceRoute": { + "routeToDestination": "Route to destination:", + "routeBack": "Route back:" + }, + "tracerouteResponse": { + "title": "Traceroute: {{identifier}}" + }, + "unsafeRoles": { + "confirmUnderstanding": "Yes, I know what I'm doing", + "conjunction": " and the blog post about ", + "postamble": " and understand the implications of changing the role.", + "preamble": "I have read the ", + "choosingRightDeviceRole": "Choosing The Right Device Role", + "deviceRoleDocumentation": "Device Role Documentation", + "title": "よろしいですか?" + }, + "managedMode": { + "confirmUnderstanding": "Yes, I know what I'm doing", + "title": "よろしいですか?", + "description": "Enabling Managed Mode blocks client applications (including the web client) from writing configurations to a radio. Once enabled, radio configurations can only be changed through Remote Admin messages. This setting is not required for remote node administration." + }, + "clientNotification": { + "title": "Client Notification", + "TraceRoute can only be sent once every 30 seconds": "TraceRoute can only be sent once every 30 seconds", + "Compromised keys were detected and regenerated.": "Compromised keys were detected and regenerated." + }, + "resetNodeDb": { + "title": "Reset Node Database", + "description": "This will clear all nodes from the connected device's node database and clear all message history in the client. This cannot be undone. Are you sure you want to continue?", + "confirm": "Reset Node Database", + "failedTitle": "There was an error resetting the Node DB. Please try again." + }, + "clearAllStores": { + "title": "Clear All Local Storage", + "description": "This will clear all locally stored data, including message history and node databases for all previously connected devices. This will require you to reconnect to your node once complete and cannot be undone. Are you sure you want to continue?", + "confirm": "Clear all local storage", + "failedTitle": "There was an error clearing local storage. Please try again." + }, + "factoryResetDevice": { + "title": "Factory Reset Device", + "description": "This will factory reset the connected device, erasing all configurations and data on the device as well as all nodes and messages saved in the client. This cannot be undone. Are you sure you want to continue?", + "confirm": "Factory Reset Device", + "failedTitle": "There was an error performing the factory reset. Please try again." + }, + "factoryResetConfig": { + "title": "Factory Reset Config", + "description": "This will factory reset the configuration on the connected device, erasing all configurations on the device. This cannot be undone. Are you sure you want to continue?", + "confirm": "Factory Reset Config", + "failedTitle": "There was an error performing the factory reset. Please try again." + } } diff --git a/packages/web/public/i18n/locales/ja-JP/map.json b/packages/web/public/i18n/locales/ja-JP/map.json new file mode 100644 index 000000000..2dd589753 --- /dev/null +++ b/packages/web/public/i18n/locales/ja-JP/map.json @@ -0,0 +1,38 @@ +{ + "maplibre": { + "GeolocateControl.FindMyLocation": "Find my location", + "NavigationControl.ZoomIn": "Zoom in", + "NavigationControl.ZoomOut": "Zoom out", + "CooperativeGesturesHandler.WindowsHelpText": "Use Ctrl + scroll to zoom the map", + "CooperativeGesturesHandler.MacHelpText": "Use ⌘ + scroll to zoom the map", + "CooperativeGesturesHandler.MobileHelpText": "Use two fingers to move the map" + }, + "layerTool": { + "nodeMarkers": "Show nodes", + "directNeighbors": "Show direct connections", + "remoteNeighbors": "Show remote connections", + "positionPrecision": "Show position precision", + "traceroutes": "Show traceroutes", + "waypoints": "Show waypoints" + }, + "mapMenu": { + "locateAria": "Locate my node", + "layersAria": "Change map style" + }, + "waypointDetail": { + "edit": "編集", + "description": "Description:", + "createdBy": "Edited by:", + "createdDate": "Created:", + "updated": "Updated:", + "expires": "Expires:", + "distance": "Distance:", + "bearing": "Absolute bearing:", + "lockedTo": "Locked by:", + "latitude": "Latitude:", + "longitude": "Longitude:" + }, + "myNode": { + "tooltip": "This device" + } +} diff --git a/packages/web/public/i18n/locales/ja-JP/messages.json b/packages/web/public/i18n/locales/ja-JP/messages.json index 859a75fd1..62ae8df70 100644 --- a/packages/web/public/i18n/locales/ja-JP/messages.json +++ b/packages/web/public/i18n/locales/ja-JP/messages.json @@ -1,39 +1,39 @@ { - "page": { - "title": "Messages: {{chatName}}", - "placeholder": "Enter Message" - }, - "emptyState": { - "title": "Select a Chat", - "text": "No messages yet." - }, - "selectChatPrompt": { - "text": "Select a channel or node to start messaging." - }, - "sendMessage": { - "placeholder": "Enter your message here...", - "sendButton": "送信" - }, - "actionsMenu": { - "addReactionLabel": "Add Reaction", - "replyLabel": "返信" - }, - "deliveryStatus": { - "delivered": { - "label": "Message delivered", - "displayText": "Message delivered" - }, - "failed": { - "label": "Message delivery failed", - "displayText": "Delivery failed" - }, - "unknown": { - "label": "Message status unknown", - "displayText": "Unknown state" - }, - "waiting": { - "label": "Sending message", - "displayText": "Waiting for delivery" - } - } + "page": { + "title": "Messages: {{chatName}}", + "placeholder": "Enter Message" + }, + "emptyState": { + "title": "Select a Chat", + "text": "No messages yet." + }, + "selectChatPrompt": { + "text": "Select a channel or node to start messaging." + }, + "sendMessage": { + "placeholder": "Enter your message here...", + "sendButton": "送信" + }, + "actionsMenu": { + "addReactionLabel": "Add Reaction", + "replyLabel": "返信" + }, + "deliveryStatus": { + "delivered": { + "label": "Message delivered", + "displayText": "Message delivered" + }, + "failed": { + "label": "Message delivery failed", + "displayText": "Delivery failed" + }, + "unknown": { + "label": "Message status unknown", + "displayText": "Unknown state" + }, + "waiting": { + "label": "Sending message", + "displayText": "Waiting for delivery" + } + } } diff --git a/packages/web/public/i18n/locales/ja-JP/moduleConfig.json b/packages/web/public/i18n/locales/ja-JP/moduleConfig.json index 85ccea960..5b384651b 100644 --- a/packages/web/public/i18n/locales/ja-JP/moduleConfig.json +++ b/packages/web/public/i18n/locales/ja-JP/moduleConfig.json @@ -1,448 +1,448 @@ { - "page": { - "tabAmbientLighting": "環境照明", - "tabAudio": "オーディオ", - "tabCannedMessage": "Canned", - "tabDetectionSensor": "検出センサー", - "tabExternalNotification": "Ext Notif", - "tabMqtt": "MQTT", - "tabNeighborInfo": "隣接ノード情報", - "tabPaxcounter": "Paxcounter", - "tabRangeTest": "レンジテスト", - "tabSerial": "シリアル", - "tabStoreAndForward": "S&F", - "tabTelemetry": "テレメトリー" - }, - "ambientLighting": { - "title": "Ambient Lighting Settings", - "description": "Settings for the Ambient Lighting module", - "ledState": { - "label": "LED State", - "description": "Sets LED to on or off" - }, - "current": { - "label": "電流", - "description": "Sets the current for the LED output. Default is 10" - }, - "red": { - "label": "赤", - "description": "Sets the red LED level. Values are 0-255" - }, - "green": { - "label": "緑", - "description": "Sets the green LED level. Values are 0-255" - }, - "blue": { - "label": "青", - "description": "Sets the blue LED level. Values are 0-255" - } - }, - "audio": { - "title": "Audio Settings", - "description": "Settings for the Audio module", - "codec2Enabled": { - "label": "Codec 2 Enabled", - "description": "Enable Codec 2 audio encoding" - }, - "pttPin": { - "label": "PTT Pin", - "description": "GPIO pin to use for PTT" - }, - "bitrate": { - "label": "Bitrate", - "description": "Bitrate to use for audio encoding" - }, - "i2sWs": { - "label": "i2S WS", - "description": "GPIO pin to use for i2S WS" - }, - "i2sSd": { - "label": "i2S SD", - "description": "GPIO pin to use for i2S SD" - }, - "i2sDin": { - "label": "i2S DIN", - "description": "GPIO pin to use for i2S DIN" - }, - "i2sSck": { - "label": "i2S SCK", - "description": "GPIO pin to use for i2S SCK" - } - }, - "cannedMessage": { - "title": "Canned Message Settings", - "description": "Settings for the Canned Message module", - "moduleEnabled": { - "label": "Module Enabled", - "description": "Enable Canned Message" - }, - "rotary1Enabled": { - "label": "Rotary Encoder #1 Enabled", - "description": "Enable the rotary encoder" - }, - "inputbrokerPinA": { - "label": "Encoder Pin A", - "description": "GPIO Pin Value (1-39) For encoder port A" - }, - "inputbrokerPinB": { - "label": "Encoder Pin B", - "description": "GPIO Pin Value (1-39) For encoder port B" - }, - "inputbrokerPinPress": { - "label": "Encoder Pin Press", - "description": "GPIO Pin Value (1-39) For encoder Press" - }, - "inputbrokerEventCw": { - "label": "Clockwise event", - "description": "Select input event." - }, - "inputbrokerEventCcw": { - "label": "Counter Clockwise event", - "description": "Select input event." - }, - "inputbrokerEventPress": { - "label": "Press event", - "description": "Select input event" - }, - "updown1Enabled": { - "label": "Up Down enabled", - "description": "Enable the up / down encoder" - }, - "allowInputSource": { - "label": "Allow Input Source", - "description": "Select from: '_any', 'rotEnc1', 'upDownEnc1', 'cardkb'" - }, - "sendBell": { - "label": "Send Bell", - "description": "Sends a bell character with each message" - } - }, - "detectionSensor": { - "title": "Detection Sensor Settings", - "description": "Settings for the Detection Sensor module", - "enabled": { - "label": "Enabled", - "description": "Enable or disable Detection Sensor Module" - }, - "minimumBroadcastSecs": { - "label": "Minimum Broadcast Seconds", - "description": "The interval in seconds of how often we can send a message to the mesh when a state change is detected" - }, - "stateBroadcastSecs": { - "label": "State Broadcast Seconds", - "description": "The interval in seconds of how often we should send a message to the mesh with the current state regardless of changes" - }, - "sendBell": { - "label": "Send Bell", - "description": "Send ASCII bell with alert message" - }, - "name": { - "label": "Friendly Name", - "description": "Used to format the message sent to mesh, max 20 Characters" - }, - "monitorPin": { - "label": "Monitor Pin", - "description": "The GPIO pin to monitor for state changes" - }, - "detectionTriggerType": { - "label": "Detection Triggered Type", - "description": "The type of trigger event to be used" - }, - "usePullup": { - "label": "Use Pullup", - "description": "Whether or not use INPUT_PULLUP mode for GPIO pin" - } - }, - "externalNotification": { - "title": "External Notification Settings", - "description": "Configure the external notification module", - "enabled": { - "label": "Module Enabled", - "description": "Enable External Notification" - }, - "outputMs": { - "label": "Output MS", - "description": "Output MS" - }, - "output": { - "label": "Output", - "description": "Output" - }, - "outputVibra": { - "label": "Output Vibrate", - "description": "Output Vibrate" - }, - "outputBuzzer": { - "label": "Output Buzzer", - "description": "Output Buzzer" - }, - "active": { - "label": "Active", - "description": "Active" - }, - "alertMessage": { - "label": "Alert Message", - "description": "Alert Message" - }, - "alertMessageVibra": { - "label": "Alert Message Vibrate", - "description": "Alert Message Vibrate" - }, - "alertMessageBuzzer": { - "label": "Alert Message Buzzer", - "description": "Alert Message Buzzer" - }, - "alertBell": { - "label": "Alert Bell", - "description": "Should an alert be triggered when receiving an incoming bell?" - }, - "alertBellVibra": { - "label": "Alert Bell Vibrate", - "description": "Alert Bell Vibrate" - }, - "alertBellBuzzer": { - "label": "Alert Bell Buzzer", - "description": "Alert Bell Buzzer" - }, - "usePwm": { - "label": "Use PWM", - "description": "Use PWM" - }, - "nagTimeout": { - "label": "Nag Timeout", - "description": "Nag Timeout" - }, - "useI2sAsBuzzer": { - "label": "Use I²S Pin as Buzzer", - "description": "Designate I²S Pin as Buzzer Output" - } - }, - "mqtt": { - "title": "MQTT Settings", - "description": "Settings for the MQTT module", - "enabled": { - "label": "Enabled", - "description": "Enable or disable MQTT" - }, - "address": { - "label": "MQTT Server Address", - "description": "MQTT server address to use for default/custom servers" - }, - "username": { - "label": "MQTT Username", - "description": "MQTT username to use for default/custom servers" - }, - "password": { - "label": "MQTT Password", - "description": "MQTT password to use for default/custom servers" - }, - "encryptionEnabled": { - "label": "Encryption Enabled", - "description": "Enable or disable MQTT encryption. Note: All messages are sent to the MQTT broker unencrypted if this option is not enabled, even when your uplink channels have encryption keys set. This includes position data." - }, - "jsonEnabled": { - "label": "JSON Enabled", - "description": "Whether to send/consume JSON packets on MQTT" - }, - "tlsEnabled": { - "label": "TLS Enabled", - "description": "Enable or disable TLS" - }, - "root": { - "label": "ルート トピック", - "description": "MQTT root topic to use for default/custom servers" - }, - "proxyToClientEnabled": { - "label": "MQTT Client Proxy Enabled", - "description": "Utilizes the network connection to proxy MQTT messages to the client." - }, - "mapReportingEnabled": { - "label": "Map Reporting Enabled", - "description": "Your node will periodically send an unencrypted map report packet to the configured MQTT server, this includes id, short and long name, approximate location, hardware model, role, firmware version, LoRa region, modem preset and primary channel name." - }, - "mapReportSettings": { - "publishIntervalSecs": { - "label": "Map Report Publish Interval (s)", - "description": "Interval in seconds to publish map reports" - }, - "positionPrecision": { - "label": "Approximate Location", - "description": "Position shared will be accurate within this distance", - "options": { - "metric_km23": "Within 23 km", - "metric_km12": "Within 12 km", - "metric_km5_8": "Within 5.8 km", - "metric_km2_9": "Within 2.9 km", - "metric_km1_5": "Within 1.5 km", - "metric_m700": "Within 700 m", - "metric_m350": "Within 350 m", - "metric_m200": "Within 200 m", - "metric_m90": "Within 90 m", - "metric_m50": "Within 50 m", - "imperial_mi15": "Within 15 miles", - "imperial_mi7_3": "Within 7.3 miles", - "imperial_mi3_6": "Within 3.6 miles", - "imperial_mi1_8": "Within 1.8 miles", - "imperial_mi0_9": "Within 0.9 miles", - "imperial_mi0_5": "Within 0.5 miles", - "imperial_mi0_2": "Within 0.2 miles", - "imperial_ft600": "Within 600 feet", - "imperial_ft300": "Within 300 feet", - "imperial_ft150": "Within 150 feet" - } - } - } - }, - "neighborInfo": { - "title": "Neighbor Info Settings", - "description": "Settings for the Neighbor Info module", - "enabled": { - "label": "Enabled", - "description": "Enable or disable Neighbor Info Module" - }, - "updateInterval": { - "label": "Update Interval", - "description": "Interval in seconds of how often we should try to send our Neighbor Info to the mesh" - } - }, - "paxcounter": { - "title": "Paxcounter Settings", - "description": "Settings for the Paxcounter module", - "enabled": { - "label": "Module Enabled", - "description": "Enable Paxcounter" - }, - "paxcounterUpdateInterval": { - "label": "Update Interval (seconds)", - "description": "How long to wait between sending paxcounter packets" - }, - "wifiThreshold": { - "label": "WiFi RSSI Threshold", - "description": "At what WiFi RSSI level should the counter increase. Defaults to -80." - }, - "bleThreshold": { - "label": "BLE RSSI Threshold", - "description": "At what BLE RSSI level should the counter increase. Defaults to -80." - } - }, - "rangeTest": { - "title": "Range Test Settings", - "description": "Settings for the Range Test module", - "enabled": { - "label": "Module Enabled", - "description": "Enable Range Test" - }, - "sender": { - "label": "Message Interval", - "description": "How long to wait between sending test packets" - }, - "save": { - "label": "Save CSV to storage", - "description": "ESP32 Only" - } - }, - "serial": { - "title": "Serial Settings", - "description": "Settings for the Serial module", - "enabled": { - "label": "Module Enabled", - "description": "Enable Serial output" - }, - "echo": { - "label": "Echo", - "description": "Any packets you send will be echoed back to your device" - }, - "rxd": { - "label": "Receive Pin", - "description": "Set the GPIO pin to the RXD pin you have set up." - }, - "txd": { - "label": "Transmit Pin", - "description": "Set the GPIO pin to the TXD pin you have set up." - }, - "baud": { - "label": "Baud Rate", - "description": "The serial baud rate" - }, - "timeout": { - "label": "タイムアウト", - "description": "Seconds to wait before we consider your packet as 'done'" - }, - "mode": { - "label": "Mode", - "description": "Select Mode" - }, - "overrideConsoleSerialPort": { - "label": "Override Console Serial Port", - "description": "If you have a serial port connected to the console, this will override it." - } - }, - "storeForward": { - "title": "Store & Forward Settings", - "description": "Settings for the Store & Forward module", - "enabled": { - "label": "Module Enabled", - "description": "Enable Store & Forward" - }, - "heartbeat": { - "label": "Heartbeat Enabled", - "description": "Enable Store & Forward heartbeat" - }, - "records": { - "label": "サーバーの最大保管レコード数 (デフォルト 約11,000レコード)", - "description": "Number of records to store" - }, - "historyReturnMax": { - "label": "リクエスト可能な最大の履歴件数", - "description": "Max number of records to return" - }, - "historyReturnWindow": { - "label": "リクエスト可能な履歴の期間 (分)", - "description": "Max number of records to return" - } - }, - "telemetry": { - "title": "Telemetry Settings", - "description": "Settings for the Telemetry module", - "deviceUpdateInterval": { - "label": "Device Metrics", - "description": "デバイスのメトリック更新間隔 (秒)" - }, - "environmentUpdateInterval": { - "label": "環境メトリック更新間隔 (秒)", - "description": "" - }, - "environmentMeasurementEnabled": { - "label": "Module Enabled", - "description": "Enable the Environment Telemetry" - }, - "environmentScreenEnabled": { - "label": "Displayed on Screen", - "description": "Show the Telemetry Module on the OLED" - }, - "environmentDisplayFahrenheit": { - "label": "Display Fahrenheit", - "description": "Display temp in Fahrenheit" - }, - "airQualityEnabled": { - "label": "Air Quality Enabled", - "description": "Enable the Air Quality Telemetry" - }, - "airQualityInterval": { - "label": "Air Quality Update Interval", - "description": "How often to send Air Quality data over the mesh" - }, - "powerMeasurementEnabled": { - "label": "Power Measurement Enabled", - "description": "Enable the Power Measurement Telemetry" - }, - "powerUpdateInterval": { - "label": "Power Update Interval", - "description": "How often to send Power data over the mesh" - }, - "powerScreenEnabled": { - "label": "Power Screen Enabled", - "description": "Enable the Power Telemetry Screen" - } - } + "page": { + "tabAmbientLighting": "環境照明", + "tabAudio": "オーディオ", + "tabCannedMessage": "Canned", + "tabDetectionSensor": "検出センサー", + "tabExternalNotification": "Ext Notif", + "tabMqtt": "MQTT", + "tabNeighborInfo": "隣接ノード情報", + "tabPaxcounter": "Paxcounter", + "tabRangeTest": "レンジテスト", + "tabSerial": "シリアル", + "tabStoreAndForward": "S&F", + "tabTelemetry": "テレメトリー" + }, + "ambientLighting": { + "title": "Ambient Lighting Settings", + "description": "Settings for the Ambient Lighting module", + "ledState": { + "label": "LED State", + "description": "Sets LED to on or off" + }, + "current": { + "label": "電流", + "description": "Sets the current for the LED output. Default is 10" + }, + "red": { + "label": "赤", + "description": "Sets the red LED level. Values are 0-255" + }, + "green": { + "label": "緑", + "description": "Sets the green LED level. Values are 0-255" + }, + "blue": { + "label": "青", + "description": "Sets the blue LED level. Values are 0-255" + } + }, + "audio": { + "title": "Audio Settings", + "description": "Settings for the Audio module", + "codec2Enabled": { + "label": "Codec 2 Enabled", + "description": "Enable Codec 2 audio encoding" + }, + "pttPin": { + "label": "PTT Pin", + "description": "GPIO pin to use for PTT" + }, + "bitrate": { + "label": "Bitrate", + "description": "Bitrate to use for audio encoding" + }, + "i2sWs": { + "label": "i2S WS", + "description": "GPIO pin to use for i2S WS" + }, + "i2sSd": { + "label": "i2S SD", + "description": "GPIO pin to use for i2S SD" + }, + "i2sDin": { + "label": "i2S DIN", + "description": "GPIO pin to use for i2S DIN" + }, + "i2sSck": { + "label": "i2S SCK", + "description": "GPIO pin to use for i2S SCK" + } + }, + "cannedMessage": { + "title": "Canned Message Settings", + "description": "Settings for the Canned Message module", + "moduleEnabled": { + "label": "Module Enabled", + "description": "Enable Canned Message" + }, + "rotary1Enabled": { + "label": "Rotary Encoder #1 Enabled", + "description": "Enable the rotary encoder" + }, + "inputbrokerPinA": { + "label": "Encoder Pin A", + "description": "GPIO Pin Value (1-39) For encoder port A" + }, + "inputbrokerPinB": { + "label": "Encoder Pin B", + "description": "GPIO Pin Value (1-39) For encoder port B" + }, + "inputbrokerPinPress": { + "label": "Encoder Pin Press", + "description": "GPIO Pin Value (1-39) For encoder Press" + }, + "inputbrokerEventCw": { + "label": "Clockwise event", + "description": "Select input event." + }, + "inputbrokerEventCcw": { + "label": "Counter Clockwise event", + "description": "Select input event." + }, + "inputbrokerEventPress": { + "label": "Press event", + "description": "Select input event" + }, + "updown1Enabled": { + "label": "Up Down enabled", + "description": "Enable the up / down encoder" + }, + "allowInputSource": { + "label": "Allow Input Source", + "description": "Select from: '_any', 'rotEnc1', 'upDownEnc1', 'cardkb'" + }, + "sendBell": { + "label": "Send Bell", + "description": "Sends a bell character with each message" + } + }, + "detectionSensor": { + "title": "Detection Sensor Settings", + "description": "Settings for the Detection Sensor module", + "enabled": { + "label": "Enabled", + "description": "Enable or disable Detection Sensor Module" + }, + "minimumBroadcastSecs": { + "label": "Minimum Broadcast Seconds", + "description": "The interval in seconds of how often we can send a message to the mesh when a state change is detected" + }, + "stateBroadcastSecs": { + "label": "State Broadcast Seconds", + "description": "The interval in seconds of how often we should send a message to the mesh with the current state regardless of changes" + }, + "sendBell": { + "label": "Send Bell", + "description": "Send ASCII bell with alert message" + }, + "name": { + "label": "Friendly Name", + "description": "Used to format the message sent to mesh, max 20 Characters" + }, + "monitorPin": { + "label": "Monitor Pin", + "description": "The GPIO pin to monitor for state changes" + }, + "detectionTriggerType": { + "label": "Detection Triggered Type", + "description": "The type of trigger event to be used" + }, + "usePullup": { + "label": "Use Pullup", + "description": "Whether or not use INPUT_PULLUP mode for GPIO pin" + } + }, + "externalNotification": { + "title": "External Notification Settings", + "description": "Configure the external notification module", + "enabled": { + "label": "Module Enabled", + "description": "Enable External Notification" + }, + "outputMs": { + "label": "Output MS", + "description": "Output MS" + }, + "output": { + "label": "Output", + "description": "Output" + }, + "outputVibra": { + "label": "Output Vibrate", + "description": "Output Vibrate" + }, + "outputBuzzer": { + "label": "Output Buzzer", + "description": "Output Buzzer" + }, + "active": { + "label": "Active", + "description": "Active" + }, + "alertMessage": { + "label": "Alert Message", + "description": "Alert Message" + }, + "alertMessageVibra": { + "label": "Alert Message Vibrate", + "description": "Alert Message Vibrate" + }, + "alertMessageBuzzer": { + "label": "Alert Message Buzzer", + "description": "Alert Message Buzzer" + }, + "alertBell": { + "label": "Alert Bell", + "description": "Should an alert be triggered when receiving an incoming bell?" + }, + "alertBellVibra": { + "label": "Alert Bell Vibrate", + "description": "Alert Bell Vibrate" + }, + "alertBellBuzzer": { + "label": "Alert Bell Buzzer", + "description": "Alert Bell Buzzer" + }, + "usePwm": { + "label": "Use PWM", + "description": "Use PWM" + }, + "nagTimeout": { + "label": "Nag Timeout", + "description": "Nag Timeout" + }, + "useI2sAsBuzzer": { + "label": "Use I²S Pin as Buzzer", + "description": "Designate I²S Pin as Buzzer Output" + } + }, + "mqtt": { + "title": "MQTT Settings", + "description": "Settings for the MQTT module", + "enabled": { + "label": "Enabled", + "description": "Enable or disable MQTT" + }, + "address": { + "label": "MQTT Server Address", + "description": "MQTT server address to use for default/custom servers" + }, + "username": { + "label": "MQTT Username", + "description": "MQTT username to use for default/custom servers" + }, + "password": { + "label": "MQTT Password", + "description": "MQTT password to use for default/custom servers" + }, + "encryptionEnabled": { + "label": "Encryption Enabled", + "description": "Enable or disable MQTT encryption. Note: All messages are sent to the MQTT broker unencrypted if this option is not enabled, even when your uplink channels have encryption keys set. This includes position data." + }, + "jsonEnabled": { + "label": "JSON Enabled", + "description": "Whether to send/consume JSON packets on MQTT" + }, + "tlsEnabled": { + "label": "TLS Enabled", + "description": "Enable or disable TLS" + }, + "root": { + "label": "ルート トピック", + "description": "MQTT root topic to use for default/custom servers" + }, + "proxyToClientEnabled": { + "label": "MQTT Client Proxy Enabled", + "description": "Utilizes the network connection to proxy MQTT messages to the client." + }, + "mapReportingEnabled": { + "label": "Map Reporting Enabled", + "description": "Your node will periodically send an unencrypted map report packet to the configured MQTT server, this includes id, short and long name, approximate location, hardware model, role, firmware version, LoRa region, modem preset and primary channel name." + }, + "mapReportSettings": { + "publishIntervalSecs": { + "label": "Map Report Publish Interval (s)", + "description": "Interval in seconds to publish map reports" + }, + "positionPrecision": { + "label": "Approximate Location", + "description": "Position shared will be accurate within this distance", + "options": { + "metric_km23": "Within 23 km", + "metric_km12": "Within 12 km", + "metric_km5_8": "Within 5.8 km", + "metric_km2_9": "Within 2.9 km", + "metric_km1_5": "Within 1.5 km", + "metric_m700": "Within 700 m", + "metric_m350": "Within 350 m", + "metric_m200": "Within 200 m", + "metric_m90": "Within 90 m", + "metric_m50": "Within 50 m", + "imperial_mi15": "Within 15 miles", + "imperial_mi7_3": "Within 7.3 miles", + "imperial_mi3_6": "Within 3.6 miles", + "imperial_mi1_8": "Within 1.8 miles", + "imperial_mi0_9": "Within 0.9 miles", + "imperial_mi0_5": "Within 0.5 miles", + "imperial_mi0_2": "Within 0.2 miles", + "imperial_ft600": "Within 600 feet", + "imperial_ft300": "Within 300 feet", + "imperial_ft150": "Within 150 feet" + } + } + } + }, + "neighborInfo": { + "title": "Neighbor Info Settings", + "description": "Settings for the Neighbor Info module", + "enabled": { + "label": "Enabled", + "description": "Enable or disable Neighbor Info Module" + }, + "updateInterval": { + "label": "Update Interval", + "description": "Interval in seconds of how often we should try to send our Neighbor Info to the mesh" + } + }, + "paxcounter": { + "title": "Paxcounter Settings", + "description": "Settings for the Paxcounter module", + "enabled": { + "label": "Module Enabled", + "description": "Enable Paxcounter" + }, + "paxcounterUpdateInterval": { + "label": "Update Interval (seconds)", + "description": "How long to wait between sending paxcounter packets" + }, + "wifiThreshold": { + "label": "WiFi RSSI Threshold", + "description": "At what WiFi RSSI level should the counter increase. Defaults to -80." + }, + "bleThreshold": { + "label": "BLE RSSI Threshold", + "description": "At what BLE RSSI level should the counter increase. Defaults to -80." + } + }, + "rangeTest": { + "title": "Range Test Settings", + "description": "Settings for the Range Test module", + "enabled": { + "label": "Module Enabled", + "description": "Enable Range Test" + }, + "sender": { + "label": "Message Interval", + "description": "How long to wait between sending test packets" + }, + "save": { + "label": "Save CSV to storage", + "description": "ESP32 Only" + } + }, + "serial": { + "title": "Serial Settings", + "description": "Settings for the Serial module", + "enabled": { + "label": "Module Enabled", + "description": "Enable Serial output" + }, + "echo": { + "label": "Echo", + "description": "Any packets you send will be echoed back to your device" + }, + "rxd": { + "label": "Receive Pin", + "description": "Set the GPIO pin to the RXD pin you have set up." + }, + "txd": { + "label": "Transmit Pin", + "description": "Set the GPIO pin to the TXD pin you have set up." + }, + "baud": { + "label": "Baud Rate", + "description": "The serial baud rate" + }, + "timeout": { + "label": "タイムアウト", + "description": "Seconds to wait before we consider your packet as 'done'" + }, + "mode": { + "label": "Mode", + "description": "Select Mode" + }, + "overrideConsoleSerialPort": { + "label": "Override Console Serial Port", + "description": "If you have a serial port connected to the console, this will override it." + } + }, + "storeForward": { + "title": "Store & Forward Settings", + "description": "Settings for the Store & Forward module", + "enabled": { + "label": "Module Enabled", + "description": "Enable Store & Forward" + }, + "heartbeat": { + "label": "Heartbeat Enabled", + "description": "Enable Store & Forward heartbeat" + }, + "records": { + "label": "サーバーの最大保管レコード数 (デフォルト 約11,000レコード)", + "description": "Number of records to store" + }, + "historyReturnMax": { + "label": "リクエスト可能な最大の履歴件数", + "description": "Max number of records to return" + }, + "historyReturnWindow": { + "label": "リクエスト可能な履歴の期間 (分)", + "description": "この時間枠内の記録を返す(分)" + } + }, + "telemetry": { + "title": "Telemetry Settings", + "description": "Settings for the Telemetry module", + "deviceUpdateInterval": { + "label": "Device Metrics", + "description": "デバイスのメトリック更新間隔 (秒)" + }, + "environmentUpdateInterval": { + "label": "環境メトリック更新間隔 (秒)", + "description": "" + }, + "environmentMeasurementEnabled": { + "label": "Module Enabled", + "description": "Enable the Environment Telemetry" + }, + "environmentScreenEnabled": { + "label": "Displayed on Screen", + "description": "Show the Telemetry Module on the OLED" + }, + "environmentDisplayFahrenheit": { + "label": "Display Fahrenheit", + "description": "Display temp in Fahrenheit" + }, + "airQualityEnabled": { + "label": "Air Quality Enabled", + "description": "Enable the Air Quality Telemetry" + }, + "airQualityInterval": { + "label": "Air Quality Update Interval", + "description": "How often to send Air Quality data over the mesh" + }, + "powerMeasurementEnabled": { + "label": "Power Measurement Enabled", + "description": "Enable the Power Measurement Telemetry" + }, + "powerUpdateInterval": { + "label": "Power Update Interval", + "description": "How often to send Power data over the mesh" + }, + "powerScreenEnabled": { + "label": "Power Screen Enabled", + "description": "Enable the Power Telemetry Screen" + } + } } diff --git a/packages/web/public/i18n/locales/ja-JP/nodes.json b/packages/web/public/i18n/locales/ja-JP/nodes.json index ef598446b..e1aa6ae81 100644 --- a/packages/web/public/i18n/locales/ja-JP/nodes.json +++ b/packages/web/public/i18n/locales/ja-JP/nodes.json @@ -1,63 +1,59 @@ { - "nodeDetail": { - "publicKeyEnabled": { - "label": "Public Key Enabled" - }, - "noPublicKey": { - "label": "No Public Key" - }, - "directMessage": { - "label": "Direct Message {{shortName}}" - }, - "favorite": { - "label": "お気に入り", - "tooltip": "Add or remove this node from your favorites" - }, - "notFavorite": { - "label": "Not a Favorite" - }, - "error": { - "label": "エラー", - "text": "An error occurred while fetching node details. Please try again later." - }, - "status": { - "heard": "Heard", - "mqtt": "MQTT" - }, - "elevation": { - "label": "Elevation" - }, - "channelUtil": { - "label": "Channel Util" - }, - "airtimeUtil": { - "label": "Airtime Util" - } - }, - "nodesTable": { - "headings": { - "longName": "Long Name", - "connection": "Connection", - "lastHeard": "Last Heard", - "encryption": "Encryption", - "model": "Model", - "macAddress": "MAC Address" - }, - "connectionStatus": { - "direct": "直接", - "away": "away", - "unknown": "-", - "viaMqtt": ", via MQTT" - }, - "lastHeardStatus": { - "never": "Never" - } - }, - "actions": { - "added": "Added", - "removed": "Removed", - "ignoreNode": "Ignore Node", - "unignoreNode": "Unignore Node", - "requestPosition": "Request Position" - } + "nodeDetail": { + "publicKeyEnabled": { + "label": "Public Key Enabled" + }, + "noPublicKey": { + "label": "No Public Key" + }, + "directMessage": { + "label": "Direct Message {{shortName}}" + }, + "favorite": { + "label": "お気に入り", + "tooltip": "Add or remove this node from your favorites" + }, + "notFavorite": { + "label": "Not a Favorite" + }, + "error": { + "label": "エラー", + "text": "An error occurred while fetching node details. Please try again later." + }, + "status": { + "heard": "Heard", + "mqtt": "MQTT" + }, + "elevation": { + "label": "Elevation" + }, + "channelUtil": { + "label": "Channel Util" + }, + "airtimeUtil": { + "label": "Airtime Util" + } + }, + "nodesTable": { + "headings": { + "longName": "Long Name", + "connection": "Connection", + "lastHeard": "Last Heard", + "encryption": "Encryption", + "model": "Model", + "macAddress": "MAC Address" + }, + "connectionStatus": { + "direct": "直接", + "away": "away", + "viaMqtt": ", via MQTT" + } + }, + "actions": { + "added": "Added", + "removed": "Removed", + "ignoreNode": "Ignore Node", + "unignoreNode": "Unignore Node", + "requestPosition": "Request Position" + } } diff --git a/packages/web/public/i18n/locales/ja-JP/ui.json b/packages/web/public/i18n/locales/ja-JP/ui.json index 64648e5d5..6afb22e05 100644 --- a/packages/web/public/i18n/locales/ja-JP/ui.json +++ b/packages/web/public/i18n/locales/ja-JP/ui.json @@ -1,228 +1,230 @@ { - "navigation": { - "title": "Navigation", - "messages": "メッセージ", - "map": "地図", - "config": "Config", - "radioConfig": "Radio Config", - "moduleConfig": "Module Config", - "channels": "チャンネル", - "nodes": "ノード" - }, - "app": { - "title": "Meshtastic", - "logo": "Meshtastic Logo" - }, - "sidebar": { - "collapseToggle": { - "button": { - "open": "Open sidebar", - "close": "Close sidebar" - } - }, - "deviceInfo": { - "volts": "{{voltage}} volts", - "firmware": { - "title": "ファームウェア", - "version": "v{{version}}", - "buildDate": "Build date: {{date}}" - }, - "deviceName": { - "title": "Device Name", - "changeName": "Change Device Name", - "placeholder": "Enter device name" - }, - "editDeviceName": "Edit device name" - } - }, - "batteryStatus": { - "charging": "{{level}}% charging", - "pluggedIn": "Plugged in", - "title": "バッテリー" - }, - "search": { - "nodes": "Search nodes...", - "channels": "Search channels...", - "commandPalette": "Search commands..." - }, - "toast": { - "positionRequestSent": { - "title": "Position request sent." - }, - "requestingPosition": { - "title": "Requesting position, please wait..." - }, - "sendingTraceroute": { - "title": "Sending Traceroute, please wait..." - }, - "tracerouteSent": { - "title": "Traceroute sent." - }, - "savedChannel": { - "title": "Saved Channel: {{channelName}}" - }, - "messages": { - "pkiEncryption": { - "title": "Chat is using PKI encryption." - }, - "pskEncryption": { - "title": "Chat is using PSK encryption." - } - }, - "configSaveError": { - "title": "Error Saving Config", - "description": "An error occurred while saving the configuration." - }, - "validationError": { - "title": "Config Errors Exist", - "description": "Please fix the configuration errors before saving." - }, - "saveSuccess": { - "title": "Saving Config", - "description": "The configuration change {{case}} has been saved." - }, - "favoriteNode": { - "title": "{{action}} {{nodeName}} {{direction}} favorites.", - "action": { - "added": "Added", - "removed": "Removed", - "to": "to", - "from": "from" - } - }, - "ignoreNode": { - "title": "{{action}} {{nodeName}} {{direction}} ignore list", - "action": { - "added": "Added", - "removed": "Removed", - "to": "to", - "from": "from" - } - } - }, - "notifications": { - "copied": { - "label": "Copied!" - }, - "copyToClipboard": { - "label": "Copy to clipboard" - }, - "hidePassword": { - "label": "パスワードを非表示" - }, - "showPassword": { - "label": "パスワードを表示" - }, - "deliveryStatus": { - "delivered": "Delivered", - "failed": "Delivery Failed", - "waiting": "Waiting", - "unknown": "Unknown" - } - }, - "general": { - "label": "General" - }, - "hardware": { - "label": "ハードウェア" - }, - "metrics": { - "label": "Metrics" - }, - "role": { - "label": "役割" - }, - "filter": { - "label": "絞り込み" - }, - "advanced": { - "label": "Advanced" - }, - "clearInput": { - "label": "Clear input" - }, - "resetFilters": { - "label": "Reset Filters" - }, - "nodeName": { - "label": "Node name/number", - "placeholder": "Meshtastic 1234" - }, - "airtimeUtilization": { - "label": "Airtime Utilization (%)" - }, - "batteryLevel": { - "label": "Battery level (%)", - "labelText": "Battery level (%): {{value}}" - }, - "batteryVoltage": { - "label": "Battery voltage (V)", - "title": "電圧" - }, - "channelUtilization": { - "label": "Channel Utilization (%)" - }, - "hops": { - "direct": "直接", - "label": "Number of hops", - "text": "Number of hops: {{value}}" - }, - "lastHeard": { - "label": "最後の通信", - "labelText": "Last heard: {{value}}", - "nowLabel": "Now" - }, - "snr": { - "label": "SNR (db)" - }, - "favorites": { - "label": "Favorites" - }, - "hide": { - "label": "Hide" - }, - "showOnly": { - "label": "Show Only" - }, - "viaMqtt": { - "label": "Connected via MQTT" - }, - "hopsUnknown": { - "label": "Unknown number of hops" - }, - "showUnheard": { - "label": "Never heard" - }, - "language": { - "label": "言語設定", - "changeLanguage": "Change Language" - }, - "theme": { - "dark": "ダーク", - "light": "ライト", - "system": "Automatic", - "changeTheme": "Change Color Scheme" - }, - "errorPage": { - "title": "This is a little embarrassing...", - "description1": "We are really sorry but an error occurred in the web client that caused it to crash.
This is not supposed to happen, and we are working hard to fix it.", - "description2": "The best way to prevent this from happening again to you or anyone else is to report the issue to us.", - "reportInstructions": "Please include the following information in your report:", - "reportSteps": { - "step1": "What you were doing when the error occurred", - "step2": "What you expected to happen", - "step3": "What actually happened", - "step4": "Any other relevant information" - }, - "reportLink": "You can report the issue to our <0>GitHub", - "dashboardLink": "Return to the <0>dashboard", - "detailsSummary": "Error Details", - "errorMessageLabel": "Error message:", - "stackTraceLabel": "Stack trace:", - "fallbackError": "{{error}}" - }, - "footer": { - "text": "Powered by <0>▲ Vercel | Meshtastic® is a registered trademark of Meshtastic LLC. | <1>Legal Information", - "commitSha": "Commit SHA: {{sha}}" - } + "navigation": { + "title": "Navigation", + "messages": "メッセージ", + "map": "地図", + "settings": "設定", + "channels": "チャンネル", + "radioConfig": "Radio Config", + "deviceConfig": "デバイスの設定", + "moduleConfig": "Module Config", + "manageConnections": "Manage Connections", + "nodes": "ノード" + }, + "app": { + "title": "Meshtastic", + "logo": "Meshtastic Logo" + }, + "sidebar": { + "collapseToggle": { + "button": { + "open": "Open sidebar", + "close": "Close sidebar" + } + }, + "deviceInfo": { + "volts": "{{voltage}} volts", + "firmware": { + "title": "ファームウェア", + "version": "v{{version}}", + "buildDate": "Build date: {{date}}" + } + } + }, + "batteryStatus": { + "charging": "{{level}}% charging", + "pluggedIn": "Plugged in", + "title": "バッテリー" + }, + "search": { + "nodes": "Search nodes...", + "channels": "Search channels...", + "commandPalette": "Search commands..." + }, + "toast": { + "positionRequestSent": { + "title": "Position request sent." + }, + "requestingPosition": { + "title": "Requesting position, please wait..." + }, + "sendingTraceroute": { + "title": "Sending Traceroute, please wait..." + }, + "tracerouteSent": { + "title": "Traceroute sent." + }, + "savedChannel": { + "title": "Saved Channel: {{channelName}}" + }, + "messages": { + "pkiEncryption": { + "title": "Chat is using PKI encryption." + }, + "pskEncryption": { + "title": "Chat is using PSK encryption." + } + }, + "configSaveError": { + "title": "Error Saving Config", + "description": "An error occurred while saving the configuration." + }, + "validationError": { + "title": "Config Errors Exist", + "description": "Please fix the configuration errors before saving." + }, + "saveSuccess": { + "title": "Saving Config", + "description": "The configuration change {{case}} has been saved." + }, + "saveAllSuccess": { + "title": "Saved", + "description": "All configuration changes have been saved." + }, + "favoriteNode": { + "title": "{{action}} {{nodeName}} {{direction}} favorites.", + "action": { + "added": "Added", + "removed": "Removed", + "to": "to", + "from": "from" + } + }, + "ignoreNode": { + "title": "{{action}} {{nodeName}} {{direction}} ignore list", + "action": { + "added": "Added", + "removed": "Removed", + "to": "to", + "from": "from" + } + } + }, + "notifications": { + "copied": { + "label": "Copied!" + }, + "copyToClipboard": { + "label": "Copy to clipboard" + }, + "hidePassword": { + "label": "パスワードを非表示" + }, + "showPassword": { + "label": "パスワードを表示" + }, + "deliveryStatus": { + "delivered": "Delivered", + "failed": "Delivery Failed", + "waiting": "Waiting", + "unknown": "Unknown" + } + }, + "general": { + "label": "General" + }, + "hardware": { + "label": "ハードウェア" + }, + "metrics": { + "label": "Metrics" + }, + "role": { + "label": "役割" + }, + "filter": { + "label": "絞り込み" + }, + "advanced": { + "label": "Advanced" + }, + "clearInput": { + "label": "Clear input" + }, + "resetFilters": { + "label": "Reset Filters" + }, + "nodeName": { + "label": "Node name/number", + "placeholder": "Meshtastic 1234" + }, + "airtimeUtilization": { + "label": "Airtime Utilization (%)", + "short": "Airtime Util. (%)" + }, + "batteryLevel": { + "label": "Battery level (%)", + "labelText": "Battery level (%): {{value}}" + }, + "batteryVoltage": { + "label": "Battery voltage (V)", + "title": "電圧" + }, + "channelUtilization": { + "label": "Channel Utilization (%)", + "short": "Channel Util. (%)" + }, + "hops": { + "direct": "直接", + "label": "Number of hops", + "text": "Number of hops: {{value}}" + }, + "lastHeard": { + "label": "最後の通信", + "labelText": "Last heard: {{value}}", + "nowLabel": "Now" + }, + "snr": { + "label": "SNR (db)" + }, + "favorites": { + "label": "Favorites" + }, + "hide": { + "label": "Hide" + }, + "showOnly": { + "label": "Show Only" + }, + "viaMqtt": { + "label": "Connected via MQTT" + }, + "hopsUnknown": { + "label": "Unknown number of hops" + }, + "showUnheard": { + "label": "Never heard" + }, + "language": { + "label": "言語設定", + "changeLanguage": "Change Language" + }, + "theme": { + "dark": "ダーク", + "light": "ライト", + "system": "Automatic", + "changeTheme": "Change Color Scheme" + }, + "errorPage": { + "title": "This is a little embarrassing...", + "description1": "We are really sorry but an error occurred in the web client that caused it to crash.
This is not supposed to happen, and we are working hard to fix it.", + "description2": "The best way to prevent this from happening again to you or anyone else is to report the issue to us.", + "reportInstructions": "Please include the following information in your report:", + "reportSteps": { + "step1": "What you were doing when the error occurred", + "step2": "What you expected to happen", + "step3": "What actually happened", + "step4": "Any other relevant information" + }, + "reportLink": "You can report the issue to our <0>GitHub", + "connectionsLink": "Return to the <0>connections", + "detailsSummary": "Error Details", + "errorMessageLabel": "Error message:", + "stackTraceLabel": "Stack trace:", + "fallbackError": "{{error}}" + }, + "footer": { + "text": "Powered by <0>▲ Vercel | Meshtastic® is a registered trademark of Meshtastic LLC. | <1>Legal Information", + "commitSha": "Commit SHA: {{sha}}" + } } diff --git a/packages/web/public/i18n/locales/ko-KR/channels.json b/packages/web/public/i18n/locales/ko-KR/channels.json index cbb0a1ab7..45cabb52b 100644 --- a/packages/web/public/i18n/locales/ko-KR/channels.json +++ b/packages/web/public/i18n/locales/ko-KR/channels.json @@ -1,69 +1,71 @@ { - "page": { - "sectionLabel": "채널", - "channelName": "채널 {{channelName}}", - "broadcastLabel": "주 채널", - "channelIndex": "Ch {{index}}" - }, - "validation": { - "pskInvalid": "유효한 {{bits}} bit PSK를 입력해 주세요." - }, - "settings": { - "label": "채널 설정", - "description": "암호화, MQTT 및 기타 설정" - }, - "role": { - "label": "역할", - "description": "장치 텔레메트리 데이터는 주 채널을 통해 전송됩니다. 주 채널은 하나만 허용됩니다", - "options": { - "primary": "주 채널", - "disabled": "비활성화", - "secondary": "보조 채널" - } - }, - "psk": { - "label": "사전 공유 키", - "description": "지원되는 PSK 길이: 256-bit, 128-bit, 8-bit, Empty (0-bit)", - "generate": "생성" - }, - "name": { - "label": "이름", - "description": "채널의 고유 이름 12 바이트 미만, 기본 값을 사용하려면 빈칸으로 두세요" - }, - "uplinkEnabled": { - "label": "업링크 활성화", - "description": "로컬 메쉬에서 MQTT로 메시지를 전송합니다" - }, - "downlinkEnabled": { - "label": "다운링크 활성화", - "description": "MQTT를 통해 로컬 메쉬로 메시지를 전송합니다" - }, - "positionPrecision": { - "label": "위치", - "description": "채널에 공유할 위치 정확도. 비활성화 할 수 있습니다.", - "options": { - "none": "위치를 공유하지 않습니다", - "precise": "정확한 위치", - "metric_km23": "23 km 이내", - "metric_km12": "12 km 이내", - "metric_km5_8": "5.8 km 이내", - "metric_km2_9": "2.9 km 이내", - "metric_km1_5": "1.5 km 이내", - "metric_m700": "700 m 이내", - "metric_m350": "350 m 이내", - "metric_m200": "200 m 이내", - "metric_m90": "90 m 이내", - "metric_m50": "50 m 이내", - "imperial_mi15": "15 miles 이내", - "imperial_mi7_3": "7.3 miles 이내", - "imperial_mi3_6": "3.6 miles 이내", - "imperial_mi1_8": "1.8 miles 이내", - "imperial_mi0_9": "0.9 miles 이내", - "imperial_mi0_5": "0.5 miles 이내", - "imperial_mi0_2": "0.2 miles 이내", - "imperial_ft600": "600 feet 이내", - "imperial_ft300": "300 feet 이내", - "imperial_ft150": "150 feet 이내" - } - } + "page": { + "sectionLabel": "채널", + "channelName": "채널 {{channelName}}", + "broadcastLabel": "주 채널", + "channelIndex": "Ch {{index}}", + "import": "불러오기", + "export": "내보내기" + }, + "validation": { + "pskInvalid": "유효한 {{bits}} bit PSK를 입력해 주세요." + }, + "settings": { + "label": "채널 설정", + "description": "암호화, MQTT 및 기타 설정" + }, + "role": { + "label": "역할", + "description": "장치 텔레메트리 데이터는 주 채널을 통해 전송됩니다. 주 채널은 하나만 허용됩니다", + "options": { + "primary": "주 채널", + "disabled": "비활성화", + "secondary": "보조 채널" + } + }, + "psk": { + "label": "사전 공유 키", + "description": "지원되는 PSK 길이: 256-bit, 128-bit, 8-bit, Empty (0-bit)", + "generate": "생성" + }, + "name": { + "label": "이름", + "description": "채널의 고유 이름 12 바이트 미만, 기본 값을 사용하려면 빈칸으로 두세요" + }, + "uplinkEnabled": { + "label": "업링크 활성화", + "description": "로컬 메쉬에서 MQTT로 메시지를 전송합니다" + }, + "downlinkEnabled": { + "label": "다운링크 활성화", + "description": "MQTT를 통해 로컬 메쉬로 메시지를 전송합니다" + }, + "positionPrecision": { + "label": "위치", + "description": "채널에 공유할 위치 정확도. 비활성화 할 수 있습니다.", + "options": { + "none": "위치를 공유하지 않습니다", + "precise": "정확한 위치", + "metric_km23": "23 km 이내", + "metric_km12": "12 km 이내", + "metric_km5_8": "5.8 km 이내", + "metric_km2_9": "2.9 km 이내", + "metric_km1_5": "1.5 km 이내", + "metric_m700": "700 m 이내", + "metric_m350": "350 m 이내", + "metric_m200": "200 m 이내", + "metric_m90": "90 m 이내", + "metric_m50": "50 m 이내", + "imperial_mi15": "15 miles 이내", + "imperial_mi7_3": "7.3 miles 이내", + "imperial_mi3_6": "3.6 miles 이내", + "imperial_mi1_8": "1.8 miles 이내", + "imperial_mi0_9": "0.9 miles 이내", + "imperial_mi0_5": "0.5 miles 이내", + "imperial_mi0_2": "0.2 miles 이내", + "imperial_ft600": "600 feet 이내", + "imperial_ft300": "300 feet 이내", + "imperial_ft150": "150 feet 이내" + } + } } diff --git a/packages/web/public/i18n/locales/ko-KR/commandPalette.json b/packages/web/public/i18n/locales/ko-KR/commandPalette.json index b23b47d92..3d113e3dc 100644 --- a/packages/web/public/i18n/locales/ko-KR/commandPalette.json +++ b/packages/web/public/i18n/locales/ko-KR/commandPalette.json @@ -15,7 +15,6 @@ "messages": "메시지기기", "map": "지도", "config": "설정", - "channels": "채널", "nodes": "노드" } }, @@ -45,7 +44,8 @@ "label": "디버그", "command": { "reconfigure": "재설정", - "clearAllStoredMessages": "저장된 모든 메시지 삭제" + "clearAllStoredMessages": "저장된 모든 메시지 삭제", + "clearAllStores": "Clear All Local Storage" } } } diff --git a/packages/web/public/i18n/locales/ko-KR/common.json b/packages/web/public/i18n/locales/ko-KR/common.json index 3febcacf4..9323739ed 100644 --- a/packages/web/public/i18n/locales/ko-KR/common.json +++ b/packages/web/public/i18n/locales/ko-KR/common.json @@ -1,142 +1,165 @@ { - "button": { - "apply": "적용", - "backupKey": "백업 키", - "cancel": "취소", - "clearMessages": "메시지 삭제", - "close": "닫기", - "confirm": "확인", - "delete": "삭제", - "dismiss": "취소", - "download": "다운로드", - "export": "내보내기", - "generate": "생성", - "regenerate": "재생성", - "import": "불러오기", - "message": "메시지", - "now": "지금", - "ok": "확인", - "print": "인쇄", - "remove": "지우기", - "requestNewKeys": "새로운 키 요청", - "requestPosition": "위치 요청", - "reset": "초기화", - "save": "저장", - "scanQr": " QR코드 스캔", - "traceRoute": "추적 루트", - "submit": "제출" - }, - "app": { - "title": "Meshtastic", - "fullTitle": "Meshtastic 웹 클라이언트" - }, - "loading": "로딩 중...", - "unit": { - "cps": "CPS", - "dbm": "dBm", - "hertz": "Hz", - "hop": { - "one": "Hop", - "plural": "Hops" - }, - "hopsAway": { - "one": "{{count}} hop 떨어짐", - "plural": "{{count}} hops 떨어짐", - "unknown": "알 수 없는 hops 떨어짐" - }, - "megahertz": "MHz", - "raw": "raw", - "meter": { - "one": "미터", - "plural": "미터", - "suffix": "m" - }, - "minute": { - "one": "분", - "plural": "분" - }, - "hour": { - "one": "시", - "plural": "시" - }, - "millisecond": { - "one": "밀리초", - "plural": "밀리초", - "suffix": "ms" - }, - "second": { - "one": "초", - "plural": "초" - }, - "day": { - "one": "일", - "plural": "일" - }, - "month": { - "one": "월", - "plural": "달" - }, - "year": { - "one": "년", - "plural": "년" - }, - "snr": "SNR", - "volt": { - "one": "볼트", - "plural": "볼트", - "suffix": "V" - }, - "record": { - "one": "레코드", - "plural": "레코드" - } - }, - "security": { - "0bit": "Empty", - "8bit": "8 bit", - "128bit": "128 bit", - "256bit": "256 bit" - }, - "unknown": { - "longName": "알 수 없는", - "shortName": "UNK", - "notAvailable": "N/A", - "num": "??" - }, - "nodeUnknownPrefix": "!", - "unset": "UNSET", - "fallbackName": "Meshtastic {{last4}}", - "node": "노드", - "formValidation": { - "unsavedChanges": "변경 내용이 저장되지 않았습니다", - "tooBig": { - "string": "너무 깁니다. {{maximum}} 문자 이하", - "number": "너무 큽니다. {{maximum}} 이하", - "bytes": "너무 큽니다. {{params.maximum}} 바이트 이하" - }, - "tooSmall": { - "string": "너무 짧습니다. {{minimum}} 이상", - "number": "너무 작습니다. {{minimum}} 이상" - }, - "invalidFormat": { - "ipv4": "잘못된 형식입니다. IPv4 주소", - "key": "잘못된 형식입니다. Base64로 인코딩된 사전 공유키 (PSK)" - }, - "invalidType": { - "number": "잘못된 타입입니다. 숫자" - }, - "pskLength": { - "0bit": "키는 비어있어야 합니다.", - "8bit": "8 bit 사전공유키 (PSK) 가 필요합니다.", - "128bit": "128 bit 사전공유키 (PSK) 가 필요합니다.", - "256bit": "256 bit 사전공유키 (PSK) 가 필요합니다." - }, - "required": { - "generic": "필수 입력 사항입니다.", - "managed": "노드 관리를 위해 최소 한 개의 관리자 키가 필요합니다.", - "key": "키가 필요합니다." - } - }, - "yes": "Yes", - "no": "No" + "button": { + "apply": "적용", + "addConnection": "Add Connection", + "saveConnection": "Save connection", + "backupKey": "백업 키", + "cancel": "취소", + "connect": "연결", + "clearMessages": "메시지 삭제", + "close": "닫기", + "confirm": "확인", + "delete": "삭제", + "dismiss": "취소", + "download": "다운로드", + "disconnect": "연결 끊기", + "export": "내보내기", + "generate": "생성", + "regenerate": "재생성", + "import": "불러오기", + "message": "메시지", + "now": "지금", + "ok": "확인", + "print": "인쇄", + "remove": "지우기", + "requestNewKeys": "새로운 키 요청", + "requestPosition": "위치 요청", + "reset": "초기화", + "retry": "Retry", + "save": "저장", + "setDefault": "Set as default", + "unsetDefault": "Unset default", + "scanQr": " QR코드 스캔", + "traceRoute": "추적 루트", + "submit": "제출" + }, + "app": { + "title": "Meshtastic", + "fullTitle": "Meshtastic 웹 클라이언트" + }, + "loading": "로딩 중...", + "unit": { + "cps": "CPS", + "dbm": "dBm", + "hertz": "Hz", + "hop": { + "one": "Hop", + "plural": "Hops" + }, + "hopsAway": { + "one": "{{count}} hop 떨어짐", + "plural": "{{count}} hops 떨어짐", + "unknown": "알 수 없는 hops 떨어짐" + }, + "megahertz": "MHz", + "kilohertz": "kHz", + "raw": "raw", + "meter": { + "one": "미터", + "plural": "미터", + "suffix": "m" + }, + "kilometer": { + "one": "Kilometer", + "plural": "Kilometers", + "suffix": "km" + }, + "minute": { + "one": "분", + "plural": "분" + }, + "hour": { + "one": "시", + "plural": "시" + }, + "millisecond": { + "one": "밀리초", + "plural": "밀리초", + "suffix": "ms" + }, + "second": { + "one": "초", + "plural": "초" + }, + "day": { + "one": "일", + "plural": "일", + "today": "Today", + "yesterday": "Yesterday" + }, + "month": { + "one": "월", + "plural": "달" + }, + "year": { + "one": "년", + "plural": "년" + }, + "snr": "SNR", + "volt": { + "one": "볼트", + "plural": "볼트", + "suffix": "V" + }, + "record": { + "one": "레코드", + "plural": "레코드" + }, + "degree": { + "one": "Degree", + "plural": "Degrees", + "suffix": "°" + } + }, + "security": { + "0bit": "Empty", + "8bit": "8 bit", + "128bit": "128 bit", + "256bit": "256 bit" + }, + "unknown": { + "longName": "알 수 없는", + "shortName": "UNK", + "notAvailable": "N/A", + "num": "??" + }, + "nodeUnknownPrefix": "!", + "unset": "UNSET", + "fallbackName": "Meshtastic {{last4}}", + "node": "노드", + "formValidation": { + "unsavedChanges": "변경 내용이 저장되지 않았습니다", + "tooBig": { + "string": "너무 깁니다. {{maximum}} 문자 이하", + "number": "너무 큽니다. {{maximum}} 이하", + "bytes": "너무 큽니다. {{params.maximum}} 바이트 이하" + }, + "tooSmall": { + "string": "너무 짧습니다. {{minimum}} 이상", + "number": "너무 작습니다. {{minimum}} 이상" + }, + "invalidFormat": { + "ipv4": "잘못된 형식입니다. IPv4 주소", + "key": "잘못된 형식입니다. Base64로 인코딩된 사전 공유키 (PSK)" + }, + "invalidType": { + "number": "잘못된 타입입니다. 숫자" + }, + "pskLength": { + "0bit": "키는 비어있어야 합니다.", + "8bit": "8 bit 사전공유키 (PSK) 가 필요합니다.", + "128bit": "128 bit 사전공유키 (PSK) 가 필요합니다.", + "256bit": "256 bit 사전공유키 (PSK) 가 필요합니다." + }, + "required": { + "generic": "필수 입력 사항입니다.", + "managed": "노드 관리를 위해 최소 한 개의 관리자 키가 필요합니다.", + "key": "키가 필요합니다." + }, + "invalidOverrideFreq": { + "number": "Invalid format, expected a value in the range 410-930 MHz or 0 (use default)." + } + }, + "yes": "Yes", + "no": "No" } diff --git a/packages/web/public/i18n/locales/ko-KR/config.json b/packages/web/public/i18n/locales/ko-KR/config.json new file mode 100644 index 000000000..358f671ff --- /dev/null +++ b/packages/web/public/i18n/locales/ko-KR/config.json @@ -0,0 +1,458 @@ +{ + "page": { + "title": "설정", + "tabUser": "사용자", + "tabChannels": "채널", + "tabBluetooth": "블루투스", + "tabDevice": "장치", + "tabDisplay": "화면", + "tabLora": "LoRa", + "tabNetwork": "네트워크", + "tabPosition": "위치", + "tabPower": "전원", + "tabSecurity": "보안" + }, + "sidebar": { + "label": "설정" + }, + "device": { + "title": "장치 설정", + "description": "장치 설정", + "buttonPin": { + "description": "버튼 핀 오버라이드", + "label": "버튼 핀" + }, + "buzzerPin": { + "description": "부저 핀 오버라이드", + "label": "부저 핀" + }, + "disableTripleClick": { + "description": "세 번 클릭 끄기", + "label": "세 번 클릭 끄기" + }, + "doubleTapAsButtonPress": { + "description": "더블 탭하여 버튼 누름", + "label": "더블 탭하여 버튼 누름" + }, + "ledHeartbeatDisabled": { + "description": "기본 깜빡이는 LED를 비활성화", + "label": "LED 깜빡임 비활성화" + }, + "nodeInfoBroadcastInterval": { + "description": "노드 정보의 발송 주기를 설정", + "label": "노드 정보 발송 주기" + }, + "posixTimezone": { + "description": "장치의 Posix Timezone String 입력", + "label": "POSIX 시간대" + }, + "rebroadcastMode": { + "description": "중계를 처리하는 방법 설정", + "label": "중계 모드" + }, + "role": { + "description": "해당 장치가 메쉬에서 수행하는 역할을 설정", + "label": "역할" + } + }, + "bluetooth": { + "title": "블루투스 설정", + "description": "블루투스 설정", + "note": "참고: 일부 장치(ESP32)는 블루투스와 와이파이를 동시에 사용할 수 없습니다.", + "enabled": { + "description": "블루투스를 켜거나 끕니다.", + "label": "활성화" + }, + "pairingMode": { + "description": "핀 선택", + "label": "페어링 모드" + }, + "pin": { + "description": "페어링에 사용할 핀", + "label": "핀" + } + }, + "display": { + "description": "장치의 디스플레이 설정", + "title": "디스플레이 설정", + "headingBold": { + "description": "상태표시줄 볼드체 적용하기", + "label": "상태표시줄 볼드체" + }, + "carouselDelay": { + "description": "화면 전환 사이클 시간을 입력", + "label": "전환 시간" + }, + "compassNorthTop": { + "description": "나침반 상단을 북쪽으로 고정", + "label": "나침반 북쪽 고정" + }, + "displayMode": { + "description": "스크린 레이아웃 변형", + "label": "디스플레이 모드" + }, + "displayUnits": { + "description": "단위 표시 형식", + "label": "단위 표시" + }, + "flipScreen": { + "description": "화면 180도 뒤집기", + "label": "화면 뒤집기" + }, + "gpsDisplayUnits": { + "description": "좌표 표시 형식", + "label": "GPS 표시 단위" + }, + "oledType": { + "description": "장치에 부착된 OLED 화면의 유형", + "label": "OLED 타입" + }, + "screenTimeout": { + "description": "디스플레이가 꺼지기까지 걸리는 시간", + "label": "화면 끄기 시간" + }, + "twelveHourClock": { + "description": "12시간제 보기", + "label": "12시간제" + }, + "wakeOnTapOrMotion": { + "description": "탭하거나 모션으로 깨우기", + "label": "탭하거나 모션으로 깨우기" + } + }, + "lora": { + "title": "Mesh 설정", + "description": "LoRa mesh 설정", + "bandwidth": { + "description": "채널 대역폭 kHz", + "label": "대역폭" + }, + "boostedRxGain": { + "description": "수신 부스트 gain", + "label": "수신 부스트 Gain" + }, + "codingRate": { + "description": "Coding rate의 분모", + "label": "Coding rate" + }, + "frequencyOffset": { + "description": "크리스탈 교정 오차를 보정하기 위한 주파수 오프셋", + "label": "주파수 오프셋" + }, + "frequencySlot": { + "description": "LoRa 주파수 채널 번호", + "label": "주파수 슬롯" + }, + "hopLimit": { + "description": "최고 hops 수", + "label": "Hop 제한" + }, + "ignoreMqtt": { + "description": "MQTT로 부터 mesh로 메시지를를 전달하지 않습니다", + "label": "MQTT로 부터 수신 무시" + }, + "modemPreset": { + "description": "모뎀 프리셋 사용", + "label": "모뎀 프리셋" + }, + "okToMqtt": { + "description": "이 설정을 true로 하면 사용자가 패킷을 MQTT에 업로드하는 것을 허용하고, false 이면 원격 노드들은 패킷을 MQTT로 전달하지 않도록 요청됩니다", + "label": "MQTT로 전송 허용" + }, + "overrideDutyCycle": { + "description": "Duty Cycle 무시", + "label": "Duty Cycle 무시" + }, + "overrideFrequency": { + "description": "해당 주파수 강제 설정", + "label": "주파수 오버라이드" + }, + "region": { + "description": "당신의 노드의 지역을 설정하세요", + "label": "지역" + }, + "spreadingFactor": { + "description": "Indicates the number of chirps per symbol", + "label": "Spread factor" + }, + "transmitEnabled": { + "description": "LoRa 전송(TX)을 활성화/비활성화합니다", + "label": "전송 활성화" + }, + "transmitPower": { + "description": "최대 전송 출력", + "label": "전송 출력" + }, + "usePreset": { + "description": "사전 정의된 모뎀프리셋을 사용하세요", + "label": "프리셋 사용" + }, + "meshSettings": { + "description": "LoRa mesh 설정", + "label": "Mesh 설정" + }, + "waveformSettings": { + "description": "LoRa 파형 설정", + "label": "파형 설정" + }, + "radioSettings": { + "label": "무선 설정", + "description": "LoRa 무선 설정" + } + }, + "network": { + "title": "WiFi 설정", + "description": "WiFi 설정", + "note": "참고: 일부 장치(ESP32)는 블루투스와 와이파이를 동시에 사용할 수 없습니다.", + "addressMode": { + "description": "주소 할당 선택", + "label": "주소 모드" + }, + "dns": { + "description": "DNS 서버", + "label": "DNS" + }, + "ethernetEnabled": { + "description": "이더넷 포트 활성화하거나 비활성화", + "label": "활성화" + }, + "gateway": { + "description": "기본 게이트웨이", + "label": "게이트웨이" + }, + "ip": { + "description": "IP 주소", + "label": "IP" + }, + "psk": { + "description": "네트워크 암호", + "label": "PSK" + }, + "ssid": { + "description": "네트워크 이름", + "label": "SSID" + }, + "subnet": { + "description": "서브넷 마스크", + "label": "서브넷" + }, + "wifiEnabled": { + "description": "WiFi를 활성화하거나 비활성화", + "label": "활성화" + }, + "meshViaUdp": { + "label": "UDP를 통한 Mesh" + }, + "ntpServer": { + "label": "NTP 서버" + }, + "rsyslogServer": { + "label": "Rsyslog 서버" + }, + "ethernetConfigSettings": { + "description": "이더넷 포트 설정", + "label": "이더넷 설정" + }, + "ipConfigSettings": { + "description": "IP 설정", + "label": "IP 설정" + }, + "ntpConfigSettings": { + "description": "NTP 설정", + "label": "NTP 설정" + }, + "rsyslogConfigSettings": { + "description": "Rsyslog 설정", + "label": "Rsyslog 설정" + }, + "udpConfigSettings": { + "description": "UDP over Mesh 설정", + "label": "UDP 설정" + } + }, + "position": { + "title": "위치 설정", + "description": "위치 설정", + "broadcastInterval": { + "description": "메쉬를 통해 당신의 위치 정보가 전송되는 빈도", + "label": "전송 간격" + }, + "enablePin": { + "description": "GPS module enable pin override", + "label": "Enable Pin" + }, + "fixedPosition": { + "description": "Don't report GPS position, but a manually-specified one", + "label": "Fixed Position" + }, + "gpsMode": { + "description": "Configure whether device GPS is Enabled, Disabled, or Not Present", + "label": "GPS Mode" + }, + "gpsUpdateInterval": { + "description": "How often a GPS fix should be acquired", + "label": "GPS Update Interval" + }, + "positionFlags": { + "description": "Optional fields to include when assembling position messages. The more fields are selected, the larger the message will be leading to longer airtime usage and a higher risk of packet loss.", + "label": "Position Flags" + }, + "receivePin": { + "description": "GPS module RX pin override", + "label": "Receive Pin" + }, + "smartPositionEnabled": { + "description": "Only send position when there has been a meaningful change in location", + "label": "Enable Smart Position" + }, + "smartPositionMinDistance": { + "description": "Minimum distance (in meters) that must be traveled before a position update is sent", + "label": "Smart Position Minimum Distance" + }, + "smartPositionMinInterval": { + "description": "Minimum interval (in seconds) that must pass before a position update is sent", + "label": "Smart Position Minimum Interval" + }, + "transmitPin": { + "description": "GPS module TX pin override", + "label": "Transmit Pin" + }, + "intervalsSettings": { + "description": "How often to send position updates", + "label": "Intervals" + }, + "flags": { + "placeholder": "Select position flags...", + "altitude": "Altitude", + "altitudeGeoidalSeparation": "Altitude Geoidal Separation", + "altitudeMsl": "Altitude is Mean Sea Level", + "dop": "Dilution of precision (DOP) PDOP used by default", + "hdopVdop": "If DOP is set, use HDOP / VDOP values instead of PDOP", + "numSatellites": "Number of satellites", + "sequenceNumber": "Sequence number", + "timestamp": "타임스탬프", + "unset": "해제", + "vehicleHeading": "Vehicle heading", + "vehicleSpeed": "Vehicle speed" + } + }, + "power": { + "adcMultiplierOverride": { + "description": "Used for tweaking battery voltage reading", + "label": "ADC Multiplier Override ratio" + }, + "ina219Address": { + "description": "Address of the INA219 battery monitor", + "label": "INA219 Address" + }, + "lightSleepDuration": { + "description": "How long the device will be in light sleep for", + "label": "Light Sleep Duration" + }, + "minimumWakeTime": { + "description": "Minimum amount of time the device will stay awake for after receiving a packet", + "label": "Minimum Wake Time" + }, + "noConnectionBluetoothDisabled": { + "description": "If the device does not receive a Bluetooth connection, the BLE radio will be disabled after this long", + "label": "No Connection Bluetooth Disabled" + }, + "powerSavingEnabled": { + "description": "Select if powered from a low-current source (i.e. solar), to minimize power consumption as much as possible.", + "label": "저전력 모드 설정" + }, + "shutdownOnBatteryDelay": { + "description": "Automatically shutdown node after this long when on battery, 0 for indefinite", + "label": "Shutdown on battery delay" + }, + "superDeepSleepDuration": { + "description": "How long the device will be in super deep sleep for", + "label": "Super Deep Sleep Duration" + }, + "powerConfigSettings": { + "description": "Settings for the power module", + "label": "전원 설정" + }, + "sleepSettings": { + "description": "Sleep settings for the power module", + "label": "Sleep Settings" + } + }, + "security": { + "description": "Settings for the Security configuration", + "title": "Security Settings", + "button_backupKey": "백업 키", + "adminChannelEnabled": { + "description": "Allow incoming device control over the insecure legacy admin channel", + "label": "Allow Legacy Admin" + }, + "enableDebugLogApi": { + "description": "Output live debug logging over serial, view and export position-redacted device logs over Bluetooth", + "label": "Enable Debug Log API" + }, + "managed": { + "description": "If enabled, device configuration options are only able to be changed remotely by a Remote Admin node via admin messages. Do not enable this option unless at least one suitable Remote Admin node has been setup, and the public key is stored in one of the fields above.", + "label": "Managed" + }, + "privateKey": { + "description": "Used to create a shared key with a remote device", + "label": "개인 키" + }, + "publicKey": { + "description": "Sent out to other nodes on the mesh to allow them to compute a shared secret key", + "label": "공개 키" + }, + "primaryAdminKey": { + "description": "The primary public key authorized to send admin messages to this node", + "label": "Primary Admin Key" + }, + "secondaryAdminKey": { + "description": "The secondary public key authorized to send admin messages to this node", + "label": "Secondary Admin Key" + }, + "serialOutputEnabled": { + "description": "Serial Console over the Stream API", + "label": "Serial Output Enabled" + }, + "tertiaryAdminKey": { + "description": "The tertiary public key authorized to send admin messages to this node", + "label": "Tertiary Admin Key" + }, + "adminSettings": { + "description": "Settings for Admin", + "label": "Admin Settings" + }, + "loggingSettings": { + "description": "Settings for Logging", + "label": "Logging Settings" + } + }, + "user": { + "title": "User Settings", + "description": "Configure your device name and identity settings", + "longName": { + "label": "긴 이름", + "description": "Your full display name (1-40 characters)", + "validation": { + "min": "Long name must be at least 1 character", + "max": "Long name must be at most 40 characters" + } + }, + "shortName": { + "label": "짧은 이름", + "description": "Your abbreviated name (2-4 characters)", + "validation": { + "min": "Short name must be at least 2 characters", + "max": "Short name must be at most 4 characters" + } + }, + "isUnmessageable": { + "label": "메시지 제한", + "description": "Used to identify unmonitored or infrastructure nodes so that messaging is not available to nodes that will never respond." + }, + "isLicensed": { + "label": "아마추어무선 자격 보유 (HAM)", + "description": "Enable if you are a licensed amateur radio operator, enabling this option disables encryption and is not compatible with the default Meshtastic network." + } + } +} diff --git a/packages/web/public/i18n/locales/ko-KR/connections.json b/packages/web/public/i18n/locales/ko-KR/connections.json new file mode 100644 index 000000000..298176cb5 --- /dev/null +++ b/packages/web/public/i18n/locales/ko-KR/connections.json @@ -0,0 +1,34 @@ +{ + "page": { + "title": "Connect to a Meshtastic device", + "description": "Add a device connection via HTTP, Bluetooth, or Serial. Your saved connections will be saved in your browser." + }, + "connectionType_ble": "BLE", + "connectionType_serial": "시리얼", + "connectionType_network": "네트워크", + "deleteConnection": "Delete connection", + "areYouSure": "This will remove {{name}}. You canot undo this action.", + "moreActions": "More actions", + "noConnections": { + "title": "No connections yet.", + "description": "Create your first connection. It will connect immediately and be saved for later." + }, + "lastConnectedAt": "Last connected: {{date}}", + "neverConnected": "Never connected", + "toasts": { + "connected": "연결됨", + "nowConnected": "{{name}} is now connected", + "nowDisconnected": "{{name}} are now disconnecte", + "disconnected": "연결 끊김", + "failed": "Failed to connect", + "checkConnetion": "Check your device or settings and try again", + "defaultSet": "Default set", + "defaultConnection": "Default connection is now {{nameisconnected}}", + "deleted": "Deleted", + "deletedByName": "{{name}} was removed", + "pickConnectionAgain": "Could not connect. You may need to reselect the device/port.", + "added": "Connection added", + "savedByName": "{{name}} saved.", + "savedCantConnect": "The connection was saved but could not connect." + } +} diff --git a/packages/web/public/i18n/locales/ko-KR/dashboard.json b/packages/web/public/i18n/locales/ko-KR/dashboard.json deleted file mode 100644 index 150c2f7bd..000000000 --- a/packages/web/public/i18n/locales/ko-KR/dashboard.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "dashboard": { - "title": "연결된 장치", - "description": "연결된 Meshtastic 장치를 관리하세요.", - "connectionType_ble": "BLE", - "connectionType_serial": "시리얼", - "connectionType_network": "네트워크", - "noDevicesTitle": "연결된 장치 없음", - "noDevicesDescription": "새로운 장치를 연결하여 시작하세요.", - "button_newConnection": "새 연결" - } -} diff --git a/packages/web/public/i18n/locales/ko-KR/deviceConfig.json b/packages/web/public/i18n/locales/ko-KR/deviceConfig.json index 490187658..73ace2d47 100644 --- a/packages/web/public/i18n/locales/ko-KR/deviceConfig.json +++ b/packages/web/public/i18n/locales/ko-KR/deviceConfig.json @@ -122,7 +122,7 @@ "title": "Mesh 설정", "description": "LoRa mesh 설정", "bandwidth": { - "description": "채널 대역폭 MHz", + "description": "채널 대역폭 kHz", "label": "대역폭" }, "boostedRxGain": { diff --git a/packages/web/public/i18n/locales/ko-KR/dialog.json b/packages/web/public/i18n/locales/ko-KR/dialog.json index c83361567..545a9e449 100644 --- a/packages/web/public/i18n/locales/ko-KR/dialog.json +++ b/packages/web/public/i18n/locales/ko-KR/dialog.json @@ -1,193 +1,238 @@ { - "deleteMessages": { - "description": "이 작업은 모든 메시지 기록을 삭제합니다. 이 작업은 되돌릴 수 없습니다. 계속하시겠습니까?", - "title": "모든 메시지 삭제" - }, - "deviceName": { - "description": "The Device will restart once the config is saved.", - "longName": "긴 이름", - "shortName": "짧은 이름", - "title": "장치 이름 변경", - "validation": { - "longNameMax": "Long name must not be more than 40 characters", - "shortNameMax": "Short name must not be more than 4 characters", - "longNameMin": "Long name must have at least 1 character", - "shortNameMin": "Short name must have at least 1 character" - } - }, - "import": { - "description": "The current LoRa configuration will be overridden.", - "error": { - "invalidUrl": "Invalid Meshtastic URL" - }, - "channelPrefix": "Channel: ", - "channelSetUrl": "Channel Set/QR Code URL", - "channels": "Channels:", - "usePreset": "Use Preset?", - "title": "Import Channel Set" - }, - "locationResponse": { - "title": "Location: {{identifier}}", - "altitude": "Altitude: ", - "coordinates": "Coordinates: ", - "noCoordinates": "No Coordinates" - }, - "pkiRegenerateDialog": { - "title": "Regenerate Pre-Shared Key?", - "description": "Are you sure you want to regenerate the pre-shared key?", - "regenerate": "재생성" - }, - "newDeviceDialog": { - "title": "Connect New Device", - "https": "https", - "http": "http", - "tabHttp": "HTTP", - "tabBluetooth": "블루투스", - "tabSerial": "시리얼", - "useHttps": "Use HTTPS", - "connecting": "Connecting...", - "connect": "연결", - "connectionFailedAlert": { - "title": "Connection Failed", - "descriptionPrefix": "Could not connect to the device. ", - "httpsHint": "If using HTTPS, you may need to accept a self-signed certificate first. ", - "openLinkPrefix": "Please open ", - "openLinkSuffix": " in a new tab", - "acceptTlsWarningSuffix": ", accept any TLS warnings if prompted, then try again", - "learnMoreLink": "Learn more" - }, - "httpConnection": { - "label": "IP Address/Hostname", - "placeholder": "000.000.000.000 / meshtastic.local" - }, - "serialConnection": { - "noDevicesPaired": "No devices paired yet.", - "newDeviceButton": "New device", - "deviceIdentifier": "# {{index}} - {{vendorId}} - {{productId}}" - }, - "bluetoothConnection": { - "noDevicesPaired": "No devices paired yet.", - "newDeviceButton": "New device", - "connectionFailed": "Connection failed", - "deviceDisconnected": "Device disconnected", - "unknownDevice": "Unknown Device", - "errorLoadingDevices": "Error loading devices", - "unknownErrorLoadingDevices": "Unknown error loading devices" - }, - "validation": { - "requiresWebBluetooth": "This connection type requires <0>Web Bluetooth. Please use a supported browser, like Chrome or Edge.", - "requiresWebSerial": "This connection type requires <0>Web Serial. Please use a supported browser, like Chrome or Edge.", - "requiresSecureContext": "This application requires a <0>secure context. Please connect using HTTPS or localhost.", - "additionallyRequiresSecureContext": "Additionally, it requires a <0>secure context. Please connect using HTTPS or localhost." - } - }, - "nodeDetails": { - "message": "메시지", - "requestPosition": "위치 요청", - "traceRoute": "추적 루트", - "airTxUtilization": "Air TX utilization", - "allRawMetrics": "All Raw Metrics:", - "batteryLevel": "Battery level", - "channelUtilization": "Channel utilization", - "details": "Details:", - "deviceMetrics": "Device Metrics:", - "hardware": "Hardware: ", - "lastHeard": "Last Heard: ", - "nodeHexPrefix": "Node Hex: ", - "nodeNumber": "Node Number: ", - "position": "Position:", - "role": "Role: ", - "uptime": "Uptime: ", - "voltage": "전압", - "title": "Node Details for {{identifier}}", - "ignoreNode": "Ignore node", - "removeNode": "Remove node", - "unignoreNode": "Unignore node", - "security": "Security:", - "publicKey": "Public Key: ", - "messageable": "Messageable: ", - "KeyManuallyVerifiedTrue": "Public Key has been manually verified", - "KeyManuallyVerifiedFalse": "Public Key is not manually verified" - }, - "pkiBackup": { - "loseKeysWarning": "If you lose your keys, you will need to reset your device.", - "secureBackup": "Its important to backup your public and private keys and store your backup securely!", - "footer": "=== END OF KEYS ===", - "header": "=== MESHTASTIC KEYS FOR {{longName}} ({{shortName}}) ===", - "privateKey": "Private Key:", - "publicKey": "Public Key:", - "fileName": "meshtastic_keys_{{longName}}_{{shortName}}.txt", - "title": "Backup Keys" - }, - "pkiBackupReminder": { - "description": "We recommend backing up your key data regularly. Would you like to back up now?", - "title": "Backup Reminder", - "remindLaterPrefix": "Remind me in", - "remindNever": "Never remind me", - "backupNow": "Back up now" - }, - "pkiRegenerate": { - "description": "Are you sure you want to regenerate key pair?", - "title": "Regenerate Key Pair" - }, - "qr": { - "addChannels": "Add Channels", - "replaceChannels": "Replace Channels", - "description": "The current LoRa configuration will also be shared.", - "sharableUrl": "Sharable URL", - "title": "Generate QR Code" - }, - "reboot": { - "title": "Reboot device", - "description": "Reboot now or schedule a reboot of the connected node. Optionally, you can choose to reboot into OTA (Over-the-Air) mode.", - "ota": "Reboot into OTA mode", - "enterDelay": "Enter delay", - "scheduled": "Reboot has been scheduled", - "schedule": "Schedule reboot", - "now": "Reboot now", - "cancel": "Cancel scheduled reboot" - }, - "refreshKeys": { - "description": { - "acceptNewKeys": "This will remove the node from device and request new keys.", - "keyMismatchReasonSuffix": ". This is due to the remote node's current public key does not match the previously stored key for this node.", - "unableToSendDmPrefix": "Your node is unable to send a direct message to node: " - }, - "acceptNewKeys": "Accept New Keys", - "title": "Keys Mismatch - {{identifier}}" - }, - "removeNode": { - "description": "Are you sure you want to remove this Node?", - "title": "Remove Node?" - }, - "shutdown": { - "title": "종료 예약", - "description": "Turn off the connected node after x minutes." - }, - "traceRoute": { - "routeToDestination": "Route to destination:", - "routeBack": "Route back:" - }, - "tracerouteResponse": { - "title": "Traceroute: {{identifier}}" - }, - "unsafeRoles": { - "confirmUnderstanding": "Yes, I know what I'm doing", - "conjunction": " and the blog post about ", - "postamble": " and understand the implications of changing the role.", - "preamble": "I have read the ", - "choosingRightDeviceRole": "Choosing The Right Device Role", - "deviceRoleDocumentation": "Device Role Documentation", - "title": "확실합니까?" - }, - "managedMode": { - "confirmUnderstanding": "Yes, I know what I'm doing", - "title": "확실합니까?", - "description": "Enabling Managed Mode blocks client applications (including the web client) from writing configurations to a radio. Once enabled, radio configurations can only be changed through Remote Admin messages. This setting is not required for remote node administration." - }, - "clientNotification": { - "title": "클라이언트 알림", - "TraceRoute can only be sent once every 30 seconds": "TraceRoute can only be sent once every 30 seconds", - "Compromised keys were detected and regenerated.": "Compromised keys were detected and regenerated." - } + "deleteMessages": { + "description": "이 작업은 모든 메시지 기록을 삭제합니다. 이 작업은 되돌릴 수 없습니다. 계속하시겠습니까?", + "title": "모든 메시지 삭제" + }, + "import": { + "description": "The current LoRa configuration will be overridden.", + "error": { + "invalidUrl": "Invalid Meshtastic URL" + }, + "channelPrefix": "Channel: ", + "primary": "Primary ", + "doNotImport": "No not import", + "channelName": "이름", + "channelSlot": "슬롯", + "channelSetUrl": "Channel Set/QR Code URL", + "useLoraConfig": "Import LoRa Config", + "presetDescription": "The current LoRa Config will be replaced.", + "title": "Import Channel Set" + }, + "locationResponse": { + "title": "Location: {{identifier}}", + "altitude": "Altitude: ", + "coordinates": "Coordinates: ", + "noCoordinates": "No Coordinates" + }, + "pkiRegenerateDialog": { + "title": "Regenerate Pre-Shared Key?", + "description": "Are you sure you want to regenerate the pre-shared key?", + "regenerate": "재생성" + }, + "addConnection": { + "title": "Add connection", + "description": "Choose a connection type and fill in the details", + "validation": { + "requiresWebBluetooth": "This connection type requires <0>Web Bluetooth. Please use a supported browser, like Chrome or Edge.", + "requiresWebSerial": "This connection type requires <0>Web Serial. Please use a supported browser, like Chrome or Edge.", + "requiresSecureContext": "This application requires a <0>secure context. Please connect using HTTPS or localhost.", + "additionallyRequiresSecureContext": "Additionally, it requires a <0>secure context. Please connect using HTTPS or localhost." + }, + "bluetoothConnection": { + "namePlaceholder": "My Bluetooth Node", + "supported": { + "title": "Web Bluetooth supported" + }, + "notSupported": { + "title": "Web Bluetooth not supported", + "description": "Your browser or device does not support Web Bluetooth" + }, + "short": "BT: {{deviceName}}", + "long": "Bluetooth Device", + "device": "장치", + "selectDevice": "Select device", + "selected": "Bluetooth device selected", + "notSelected": "No device selected", + "helperText": "Uses the Meshtastic Bluetooth service for discovery." + }, + "serialConnection": { + "namePlaceholder": "My Serial Node", + "helperText": "Selecting a port grants permission so the app can open it to connect.", + "supported": { + "title": "Web Serial supported" + }, + "notSupported": { + "title": "Web Serial not supported", + "description": "Your browser or device does not support Web Serial" + }, + "portSelected": { + "title": "Serial port selected", + "description": "Port permissions granted." + }, + "port": "Port", + "selectPort": "Select port", + "deviceName": "USB {{vendorId}}:{{productId}}", + "notSelected": "No port selected" + }, + "httpConnection": { + "namePlaceholder": "My HTTP Node", + "inputPlaceholder": "192.168.1.10 or meshtastic.local", + "heading": "URL or IP", + "useHttps": "Use HTTTPS", + "invalidUrl": { + "title": "Invalid URL", + "description": "Please enter a valid HTTP or HTTPS URL." + }, + "connectionTest": { + "description": "Test the connetion before saving to verify the device is reachable.", + "button": { + "loading": "Testing...", + "label": "Test connection" + }, + "reachable": "Reachable", + "notReachable": "Not reachable", + "success": { + "title": "Connection test successful", + "description": "The device appears to be reachable." + }, + "failure": { + "title": "Connection test failed", + "description": "Could not reach the device. Check the URL and try again." + } + } + } + }, + "nodeDetails": { + "message": "메시지", + "requestPosition": "위치 요청", + "traceRoute": "추적 루트", + "airTxUtilization": "Air TX utilization", + "allRawMetrics": "All Raw Metrics:", + "batteryLevel": "Battery level", + "channelUtilization": "Channel utilization", + "details": "Details:", + "deviceMetrics": "Device Metrics:", + "hardware": "Hardware: ", + "lastHeard": "Last Heard: ", + "nodeHexPrefix": "Node Hex: ", + "nodeNumber": "Node Number: ", + "position": "Position:", + "role": "Role: ", + "uptime": "Uptime: ", + "voltage": "전압", + "title": "Node Details for {{identifier}}", + "ignoreNode": "Ignore node", + "removeNode": "Remove node", + "unignoreNode": "Unignore node", + "security": "Security:", + "publicKey": "Public Key: ", + "messageable": "Messageable: ", + "KeyManuallyVerifiedTrue": "Public Key has been manually verified", + "KeyManuallyVerifiedFalse": "Public Key is not manually verified" + }, + "pkiBackup": { + "loseKeysWarning": "If you lose your keys, you will need to reset your device.", + "secureBackup": "Its important to backup your public and private keys and store your backup securely!", + "footer": "=== END OF KEYS ===", + "header": "=== MESHTASTIC KEYS FOR {{longName}} ({{shortName}}) ===", + "privateKey": "Private Key:", + "publicKey": "Public Key:", + "fileName": "meshtastic_keys_{{longName}}_{{shortName}}.txt", + "title": "Backup Keys" + }, + "pkiBackupReminder": { + "description": "We recommend backing up your key data regularly. Would you like to back up now?", + "title": "Backup Reminder", + "remindLaterPrefix": "Remind me in", + "remindNever": "Never remind me", + "backupNow": "Back up now" + }, + "pkiRegenerate": { + "description": "Are you sure you want to regenerate key pair?", + "title": "Regenerate Key Pair" + }, + "qr": { + "addChannels": "Add Channels", + "replaceChannels": "Replace Channels", + "description": "The current LoRa configuration will also be shared.", + "sharableUrl": "Sharable URL", + "title": "Generate QR Code" + }, + "reboot": { + "title": "Reboot device", + "description": "Reboot now or schedule a reboot of the connected node. Optionally, you can choose to reboot into OTA (Over-the-Air) mode.", + "ota": "Reboot into OTA mode", + "enterDelay": "Enter delay", + "scheduled": "Reboot has been scheduled", + "schedule": "Schedule reboot", + "now": "Reboot now", + "cancel": "Cancel scheduled reboot" + }, + "refreshKeys": { + "description": { + "acceptNewKeys": "This will remove the node from device and request new keys.", + "keyMismatchReasonSuffix": ". This is due to the remote node's current public key does not match the previously stored key for this node.", + "unableToSendDmPrefix": "Your node is unable to send a direct message to node: " + }, + "acceptNewKeys": "Accept New Keys", + "title": "Keys Mismatch - {{identifier}}" + }, + "removeNode": { + "description": "Are you sure you want to remove this Node?", + "title": "Remove Node?" + }, + "shutdown": { + "title": "종료 예약", + "description": "Turn off the connected node after x minutes." + }, + "traceRoute": { + "routeToDestination": "Route to destination:", + "routeBack": "Route back:" + }, + "tracerouteResponse": { + "title": "Traceroute: {{identifier}}" + }, + "unsafeRoles": { + "confirmUnderstanding": "Yes, I know what I'm doing", + "conjunction": " and the blog post about ", + "postamble": " and understand the implications of changing the role.", + "preamble": "I have read the ", + "choosingRightDeviceRole": "Choosing The Right Device Role", + "deviceRoleDocumentation": "Device Role Documentation", + "title": "확실합니까?" + }, + "managedMode": { + "confirmUnderstanding": "Yes, I know what I'm doing", + "title": "확실합니까?", + "description": "Enabling Managed Mode blocks client applications (including the web client) from writing configurations to a radio. Once enabled, radio configurations can only be changed through Remote Admin messages. This setting is not required for remote node administration." + }, + "clientNotification": { + "title": "클라이언트 알림", + "TraceRoute can only be sent once every 30 seconds": "TraceRoute can only be sent once every 30 seconds", + "Compromised keys were detected and regenerated.": "Compromised keys were detected and regenerated." + }, + "resetNodeDb": { + "title": "Reset Node Database", + "description": "This will clear all nodes from the connected device's node database and clear all message history in the client. This cannot be undone. Are you sure you want to continue?", + "confirm": "Reset Node Database", + "failedTitle": "There was an error resetting the Node DB. Please try again." + }, + "clearAllStores": { + "title": "Clear All Local Storage", + "description": "This will clear all locally stored data, including message history and node databases for all previously connected devices. This will require you to reconnect to your node once complete and cannot be undone. Are you sure you want to continue?", + "confirm": "Clear all local storage", + "failedTitle": "There was an error clearing local storage. Please try again." + }, + "factoryResetDevice": { + "title": "공장 초기화", + "description": "This will factory reset the connected device, erasing all configurations and data on the device as well as all nodes and messages saved in the client. This cannot be undone. Are you sure you want to continue?", + "confirm": "공장 초기화", + "failedTitle": "There was an error performing the factory reset. Please try again." + }, + "factoryResetConfig": { + "title": "설정 초기", + "description": "This will factory reset the configuration on the connected device, erasing all configurations on the device. This cannot be undone. Are you sure you want to continue?", + "confirm": "설정 초기", + "failedTitle": "There was an error performing the factory reset. Please try again." + } } diff --git a/packages/web/public/i18n/locales/ko-KR/map.json b/packages/web/public/i18n/locales/ko-KR/map.json new file mode 100644 index 000000000..7524d5606 --- /dev/null +++ b/packages/web/public/i18n/locales/ko-KR/map.json @@ -0,0 +1,38 @@ +{ + "maplibre": { + "GeolocateControl.FindMyLocation": "Find my location", + "NavigationControl.ZoomIn": "Zoom in", + "NavigationControl.ZoomOut": "Zoom out", + "CooperativeGesturesHandler.WindowsHelpText": "Use Ctrl + scroll to zoom the map", + "CooperativeGesturesHandler.MacHelpText": "Use ⌘ + scroll to zoom the map", + "CooperativeGesturesHandler.MobileHelpText": "Use two fingers to move the map" + }, + "layerTool": { + "nodeMarkers": "Show nodes", + "directNeighbors": "Show direct connections", + "remoteNeighbors": "Show remote connections", + "positionPrecision": "Show position precision", + "traceroutes": "Show traceroutes", + "waypoints": "Show waypoints" + }, + "mapMenu": { + "locateAria": "Locate my node", + "layersAria": "Change map style" + }, + "waypointDetail": { + "edit": "편집", + "description": "Description:", + "createdBy": "Edited by:", + "createdDate": "Created:", + "updated": "Updated:", + "expires": "Expires:", + "distance": "Distance:", + "bearing": "Absolute bearing:", + "lockedTo": "Locked by:", + "latitude": "Latitude:", + "longitude": "Longitude:" + }, + "myNode": { + "tooltip": "This device" + } +} diff --git a/packages/web/public/i18n/locales/ko-KR/messages.json b/packages/web/public/i18n/locales/ko-KR/messages.json index 22c5a1529..1d220b74e 100644 --- a/packages/web/public/i18n/locales/ko-KR/messages.json +++ b/packages/web/public/i18n/locales/ko-KR/messages.json @@ -1,39 +1,39 @@ { - "page": { - "title": "메시지: {{chatName}}", - "placeholder": "메시지 입력" - }, - "emptyState": { - "title": "채팅 선택", - "text": "아직 메시지가 없습니다." - }, - "selectChatPrompt": { - "text": "채널 또는 노드를 선택하여 메시지 전송을 시작하세요." - }, - "sendMessage": { - "placeholder": "여기에 메시지를 입력하세요...", - "sendButton": "보내기" - }, - "actionsMenu": { - "addReactionLabel": "반응 추가", - "replyLabel": "답장" - }, - "deliveryStatus": { - "delivered": { - "label": "메시지 전송", - "displayText": "메시지 전송됨" - }, - "failed": { - "label": "메시지 전송 실패", - "displayText": "전송 실패" - }, - "unknown": { - "label": "메시지 상태 알 수 없음", - "displayText": "알 수 없는 상태" - }, - "waiting": { - "label": "메시지 전송 중", - "displayText": "전송 대기 중" - } - } + "page": { + "title": "메시지: {{chatName}}", + "placeholder": "메시지 입력" + }, + "emptyState": { + "title": "채팅 선택", + "text": "아직 메시지가 없습니다." + }, + "selectChatPrompt": { + "text": "채널 또는 노드를 선택하여 메시지 전송을 시작하세요." + }, + "sendMessage": { + "placeholder": "여기에 메시지를 입력하세요...", + "sendButton": "보내기" + }, + "actionsMenu": { + "addReactionLabel": "반응 추가", + "replyLabel": "답장" + }, + "deliveryStatus": { + "delivered": { + "label": "메시지 전송", + "displayText": "메시지 전송됨" + }, + "failed": { + "label": "메시지 전송 실패", + "displayText": "전송 실패" + }, + "unknown": { + "label": "메시지 상태 알 수 없음", + "displayText": "알 수 없는 상태" + }, + "waiting": { + "label": "메시지 전송 중", + "displayText": "전송 대기 중" + } + } } diff --git a/packages/web/public/i18n/locales/ko-KR/moduleConfig.json b/packages/web/public/i18n/locales/ko-KR/moduleConfig.json index 54aba35d7..2c1eca711 100644 --- a/packages/web/public/i18n/locales/ko-KR/moduleConfig.json +++ b/packages/web/public/i18n/locales/ko-KR/moduleConfig.json @@ -1,448 +1,448 @@ { - "page": { - "tabAmbientLighting": "조명", - "tabAudio": "오디오", - "tabCannedMessage": "Canned", - "tabDetectionSensor": "감지 센서", - "tabExternalNotification": "Ext Notif", - "tabMqtt": "MQTT", - "tabNeighborInfo": "이웃 정보", - "tabPaxcounter": "팍스카운터", - "tabRangeTest": "거리 테스트", - "tabSerial": "시리얼", - "tabStoreAndForward": "S&F", - "tabTelemetry": "텔레메트리" - }, - "ambientLighting": { - "title": "Ambient Lighting Settings", - "description": "Settings for the Ambient Lighting module", - "ledState": { - "label": "LED State", - "description": "Sets LED to on or off" - }, - "current": { - "label": "전류", - "description": "Sets the current for the LED output. Default is 10" - }, - "red": { - "label": "빨강", - "description": "Sets the red LED level. Values are 0-255" - }, - "green": { - "label": "초록", - "description": "Sets the green LED level. Values are 0-255" - }, - "blue": { - "label": "파랑", - "description": "Sets the blue LED level. Values are 0-255" - } - }, - "audio": { - "title": "Audio Settings", - "description": "Settings for the Audio module", - "codec2Enabled": { - "label": "Codec 2 Enabled", - "description": "Enable Codec 2 audio encoding" - }, - "pttPin": { - "label": "PTT Pin", - "description": "GPIO pin to use for PTT" - }, - "bitrate": { - "label": "Bitrate", - "description": "Bitrate to use for audio encoding" - }, - "i2sWs": { - "label": "i2S WS", - "description": "GPIO pin to use for i2S WS" - }, - "i2sSd": { - "label": "i2S SD", - "description": "GPIO pin to use for i2S SD" - }, - "i2sDin": { - "label": "i2S DIN", - "description": "GPIO pin to use for i2S DIN" - }, - "i2sSck": { - "label": "i2S SCK", - "description": "GPIO pin to use for i2S SCK" - } - }, - "cannedMessage": { - "title": "Canned Message Settings", - "description": "Settings for the Canned Message module", - "moduleEnabled": { - "label": "Module Enabled", - "description": "Enable Canned Message" - }, - "rotary1Enabled": { - "label": "Rotary Encoder #1 Enabled", - "description": "Enable the rotary encoder" - }, - "inputbrokerPinA": { - "label": "Encoder Pin A", - "description": "GPIO Pin Value (1-39) For encoder port A" - }, - "inputbrokerPinB": { - "label": "Encoder Pin B", - "description": "GPIO Pin Value (1-39) For encoder port B" - }, - "inputbrokerPinPress": { - "label": "Encoder Pin Press", - "description": "GPIO Pin Value (1-39) For encoder Press" - }, - "inputbrokerEventCw": { - "label": "Clockwise event", - "description": "Select input event." - }, - "inputbrokerEventCcw": { - "label": "Counter Clockwise event", - "description": "Select input event." - }, - "inputbrokerEventPress": { - "label": "Press event", - "description": "Select input event" - }, - "updown1Enabled": { - "label": "Up Down enabled", - "description": "Enable the up / down encoder" - }, - "allowInputSource": { - "label": "Allow Input Source", - "description": "Select from: '_any', 'rotEnc1', 'upDownEnc1', 'cardkb'" - }, - "sendBell": { - "label": "Send Bell", - "description": "Sends a bell character with each message" - } - }, - "detectionSensor": { - "title": "Detection Sensor Settings", - "description": "Settings for the Detection Sensor module", - "enabled": { - "label": "활성화", - "description": "Enable or disable Detection Sensor Module" - }, - "minimumBroadcastSecs": { - "label": "Minimum Broadcast Seconds", - "description": "The interval in seconds of how often we can send a message to the mesh when a state change is detected" - }, - "stateBroadcastSecs": { - "label": "State Broadcast Seconds", - "description": "The interval in seconds of how often we should send a message to the mesh with the current state regardless of changes" - }, - "sendBell": { - "label": "Send Bell", - "description": "Send ASCII bell with alert message" - }, - "name": { - "label": "Friendly Name", - "description": "Used to format the message sent to mesh, max 20 Characters" - }, - "monitorPin": { - "label": "Monitor Pin", - "description": "The GPIO pin to monitor for state changes" - }, - "detectionTriggerType": { - "label": "Detection Triggered Type", - "description": "The type of trigger event to be used" - }, - "usePullup": { - "label": "Use Pullup", - "description": "Whether or not use INPUT_PULLUP mode for GPIO pin" - } - }, - "externalNotification": { - "title": "External Notification Settings", - "description": "Configure the external notification module", - "enabled": { - "label": "Module Enabled", - "description": "Enable External Notification" - }, - "outputMs": { - "label": "Output MS", - "description": "Output MS" - }, - "output": { - "label": "Output", - "description": "Output" - }, - "outputVibra": { - "label": "Output Vibrate", - "description": "Output Vibrate" - }, - "outputBuzzer": { - "label": "Output Buzzer", - "description": "Output Buzzer" - }, - "active": { - "label": "Active", - "description": "Active" - }, - "alertMessage": { - "label": "Alert Message", - "description": "Alert Message" - }, - "alertMessageVibra": { - "label": "Alert Message Vibrate", - "description": "Alert Message Vibrate" - }, - "alertMessageBuzzer": { - "label": "Alert Message Buzzer", - "description": "Alert Message Buzzer" - }, - "alertBell": { - "label": "Alert Bell", - "description": "Should an alert be triggered when receiving an incoming bell?" - }, - "alertBellVibra": { - "label": "Alert Bell Vibrate", - "description": "Alert Bell Vibrate" - }, - "alertBellBuzzer": { - "label": "Alert Bell Buzzer", - "description": "Alert Bell Buzzer" - }, - "usePwm": { - "label": "Use PWM", - "description": "Use PWM" - }, - "nagTimeout": { - "label": "Nag Timeout", - "description": "Nag Timeout" - }, - "useI2sAsBuzzer": { - "label": "Use I²S Pin as Buzzer", - "description": "Designate I²S Pin as Buzzer Output" - } - }, - "mqtt": { - "title": "MQTT Settings", - "description": "Settings for the MQTT module", - "enabled": { - "label": "활성화", - "description": "Enable or disable MQTT" - }, - "address": { - "label": "MQTT Server Address", - "description": "MQTT server address to use for default/custom servers" - }, - "username": { - "label": "MQTT Username", - "description": "MQTT username to use for default/custom servers" - }, - "password": { - "label": "MQTT Password", - "description": "MQTT password to use for default/custom servers" - }, - "encryptionEnabled": { - "label": "Encryption Enabled", - "description": "Enable or disable MQTT encryption. Note: All messages are sent to the MQTT broker unencrypted if this option is not enabled, even when your uplink channels have encryption keys set. This includes position data." - }, - "jsonEnabled": { - "label": "JSON Enabled", - "description": "Whether to send/consume JSON packets on MQTT" - }, - "tlsEnabled": { - "label": "TLS Enabled", - "description": "Enable or disable TLS" - }, - "root": { - "label": "Root topic", - "description": "MQTT root topic to use for default/custom servers" - }, - "proxyToClientEnabled": { - "label": "MQTT Client Proxy Enabled", - "description": "Utilizes the network connection to proxy MQTT messages to the client." - }, - "mapReportingEnabled": { - "label": "Map Reporting Enabled", - "description": "Your node will periodically send an unencrypted map report packet to the configured MQTT server, this includes id, short and long name, approximate location, hardware model, role, firmware version, LoRa region, modem preset and primary channel name." - }, - "mapReportSettings": { - "publishIntervalSecs": { - "label": "Map Report Publish Interval (s)", - "description": "Interval in seconds to publish map reports" - }, - "positionPrecision": { - "label": "Approximate Location", - "description": "Position shared will be accurate within this distance", - "options": { - "metric_km23": "Within 23 km", - "metric_km12": "Within 12 km", - "metric_km5_8": "Within 5.8 km", - "metric_km2_9": "Within 2.9 km", - "metric_km1_5": "Within 1.5 km", - "metric_m700": "Within 700 m", - "metric_m350": "Within 350 m", - "metric_m200": "Within 200 m", - "metric_m90": "Within 90 m", - "metric_m50": "Within 50 m", - "imperial_mi15": "15 miles 이내", - "imperial_mi7_3": "7.3 miles 이내", - "imperial_mi3_6": "3.6 miles 이내", - "imperial_mi1_8": "1.8 miles 이내", - "imperial_mi0_9": "0.9 miles 이내", - "imperial_mi0_5": "0.5 miles 이내", - "imperial_mi0_2": "0.2 miles 이내", - "imperial_ft600": "600 feet 이내", - "imperial_ft300": "300 feet 이내", - "imperial_ft150": "150 feet 이내" - } - } - } - }, - "neighborInfo": { - "title": "Neighbor Info Settings", - "description": "Settings for the Neighbor Info module", - "enabled": { - "label": "활성화", - "description": "Enable or disable Neighbor Info Module" - }, - "updateInterval": { - "label": "Update Interval", - "description": "Interval in seconds of how often we should try to send our Neighbor Info to the mesh" - } - }, - "paxcounter": { - "title": "Paxcounter Settings", - "description": "Settings for the Paxcounter module", - "enabled": { - "label": "Module Enabled", - "description": "Enable Paxcounter" - }, - "paxcounterUpdateInterval": { - "label": "Update Interval (seconds)", - "description": "How long to wait between sending paxcounter packets" - }, - "wifiThreshold": { - "label": "WiFi RSSI Threshold", - "description": "At what WiFi RSSI level should the counter increase. Defaults to -80." - }, - "bleThreshold": { - "label": "BLE RSSI Threshold", - "description": "At what BLE RSSI level should the counter increase. Defaults to -80." - } - }, - "rangeTest": { - "title": "Range Test Settings", - "description": "Settings for the Range Test module", - "enabled": { - "label": "Module Enabled", - "description": "Enable Range Test" - }, - "sender": { - "label": "Message Interval", - "description": "How long to wait between sending test packets" - }, - "save": { - "label": "Save CSV to storage", - "description": "ESP32 Only" - } - }, - "serial": { - "title": "Serial Settings", - "description": "Settings for the Serial module", - "enabled": { - "label": "Module Enabled", - "description": "Enable Serial output" - }, - "echo": { - "label": "Echo", - "description": "Any packets you send will be echoed back to your device" - }, - "rxd": { - "label": "Receive Pin", - "description": "Set the GPIO pin to the RXD pin you have set up." - }, - "txd": { - "label": "Transmit Pin", - "description": "Set the GPIO pin to the TXD pin you have set up." - }, - "baud": { - "label": "Baud Rate", - "description": "The serial baud rate" - }, - "timeout": { - "label": "시간 초과", - "description": "Seconds to wait before we consider your packet as 'done'" - }, - "mode": { - "label": "Mode", - "description": "Select Mode" - }, - "overrideConsoleSerialPort": { - "label": "Override Console Serial Port", - "description": "If you have a serial port connected to the console, this will override it." - } - }, - "storeForward": { - "title": "Store & Forward Settings", - "description": "Settings for the Store & Forward module", - "enabled": { - "label": "Module Enabled", - "description": "Enable Store & Forward" - }, - "heartbeat": { - "label": "Heartbeat Enabled", - "description": "Enable Store & Forward heartbeat" - }, - "records": { - "label": "Number of records", - "description": "Number of records to store" - }, - "historyReturnMax": { - "label": "History return max", - "description": "Max number of records to return" - }, - "historyReturnWindow": { - "label": "History return window", - "description": "Max number of records to return" - } - }, - "telemetry": { - "title": "Telemetry Settings", - "description": "Settings for the Telemetry module", - "deviceUpdateInterval": { - "label": "Device Metrics", - "description": "장치 메트릭 업데이트 간격 (초)" - }, - "environmentUpdateInterval": { - "label": "환경 메트릭 업데이트 간격 (초)", - "description": "" - }, - "environmentMeasurementEnabled": { - "label": "Module Enabled", - "description": "Enable the Environment Telemetry" - }, - "environmentScreenEnabled": { - "label": "Displayed on Screen", - "description": "Show the Telemetry Module on the OLED" - }, - "environmentDisplayFahrenheit": { - "label": "Display Fahrenheit", - "description": "Display temp in Fahrenheit" - }, - "airQualityEnabled": { - "label": "Air Quality Enabled", - "description": "Enable the Air Quality Telemetry" - }, - "airQualityInterval": { - "label": "Air Quality Update Interval", - "description": "How often to send Air Quality data over the mesh" - }, - "powerMeasurementEnabled": { - "label": "Power Measurement Enabled", - "description": "Enable the Power Measurement Telemetry" - }, - "powerUpdateInterval": { - "label": "Power Update Interval", - "description": "How often to send Power data over the mesh" - }, - "powerScreenEnabled": { - "label": "Power Screen Enabled", - "description": "Enable the Power Telemetry Screen" - } - } + "page": { + "tabAmbientLighting": "조명", + "tabAudio": "오디오", + "tabCannedMessage": "Canned", + "tabDetectionSensor": "감지 센서", + "tabExternalNotification": "Ext Notif", + "tabMqtt": "MQTT", + "tabNeighborInfo": "이웃 정보", + "tabPaxcounter": "팍스카운터", + "tabRangeTest": "거리 테스트", + "tabSerial": "시리얼", + "tabStoreAndForward": "S&F", + "tabTelemetry": "텔레메트리" + }, + "ambientLighting": { + "title": "Ambient Lighting Settings", + "description": "Settings for the Ambient Lighting module", + "ledState": { + "label": "LED State", + "description": "Sets LED to on or off" + }, + "current": { + "label": "전류", + "description": "Sets the current for the LED output. Default is 10" + }, + "red": { + "label": "빨강", + "description": "Sets the red LED level. Values are 0-255" + }, + "green": { + "label": "초록", + "description": "Sets the green LED level. Values are 0-255" + }, + "blue": { + "label": "파랑", + "description": "Sets the blue LED level. Values are 0-255" + } + }, + "audio": { + "title": "Audio Settings", + "description": "Settings for the Audio module", + "codec2Enabled": { + "label": "Codec 2 Enabled", + "description": "Enable Codec 2 audio encoding" + }, + "pttPin": { + "label": "PTT Pin", + "description": "GPIO pin to use for PTT" + }, + "bitrate": { + "label": "Bitrate", + "description": "Bitrate to use for audio encoding" + }, + "i2sWs": { + "label": "i2S WS", + "description": "GPIO pin to use for i2S WS" + }, + "i2sSd": { + "label": "i2S SD", + "description": "GPIO pin to use for i2S SD" + }, + "i2sDin": { + "label": "i2S DIN", + "description": "GPIO pin to use for i2S DIN" + }, + "i2sSck": { + "label": "i2S SCK", + "description": "GPIO pin to use for i2S SCK" + } + }, + "cannedMessage": { + "title": "Canned Message Settings", + "description": "Settings for the Canned Message module", + "moduleEnabled": { + "label": "Module Enabled", + "description": "Enable Canned Message" + }, + "rotary1Enabled": { + "label": "Rotary Encoder #1 Enabled", + "description": "Enable the rotary encoder" + }, + "inputbrokerPinA": { + "label": "Encoder Pin A", + "description": "GPIO Pin Value (1-39) For encoder port A" + }, + "inputbrokerPinB": { + "label": "Encoder Pin B", + "description": "GPIO Pin Value (1-39) For encoder port B" + }, + "inputbrokerPinPress": { + "label": "Encoder Pin Press", + "description": "GPIO Pin Value (1-39) For encoder Press" + }, + "inputbrokerEventCw": { + "label": "Clockwise event", + "description": "Select input event." + }, + "inputbrokerEventCcw": { + "label": "Counter Clockwise event", + "description": "Select input event." + }, + "inputbrokerEventPress": { + "label": "Press event", + "description": "Select input event" + }, + "updown1Enabled": { + "label": "Up Down enabled", + "description": "Enable the up / down encoder" + }, + "allowInputSource": { + "label": "Allow Input Source", + "description": "Select from: '_any', 'rotEnc1', 'upDownEnc1', 'cardkb'" + }, + "sendBell": { + "label": "Send Bell", + "description": "Sends a bell character with each message" + } + }, + "detectionSensor": { + "title": "Detection Sensor Settings", + "description": "Settings for the Detection Sensor module", + "enabled": { + "label": "활성화", + "description": "Enable or disable Detection Sensor Module" + }, + "minimumBroadcastSecs": { + "label": "Minimum Broadcast Seconds", + "description": "The interval in seconds of how often we can send a message to the mesh when a state change is detected" + }, + "stateBroadcastSecs": { + "label": "State Broadcast Seconds", + "description": "The interval in seconds of how often we should send a message to the mesh with the current state regardless of changes" + }, + "sendBell": { + "label": "Send Bell", + "description": "Send ASCII bell with alert message" + }, + "name": { + "label": "Friendly Name", + "description": "Used to format the message sent to mesh, max 20 Characters" + }, + "monitorPin": { + "label": "Monitor Pin", + "description": "The GPIO pin to monitor for state changes" + }, + "detectionTriggerType": { + "label": "Detection Triggered Type", + "description": "The type of trigger event to be used" + }, + "usePullup": { + "label": "Use Pullup", + "description": "Whether or not use INPUT_PULLUP mode for GPIO pin" + } + }, + "externalNotification": { + "title": "External Notification Settings", + "description": "Configure the external notification module", + "enabled": { + "label": "Module Enabled", + "description": "Enable External Notification" + }, + "outputMs": { + "label": "Output MS", + "description": "Output MS" + }, + "output": { + "label": "Output", + "description": "Output" + }, + "outputVibra": { + "label": "Output Vibrate", + "description": "Output Vibrate" + }, + "outputBuzzer": { + "label": "Output Buzzer", + "description": "Output Buzzer" + }, + "active": { + "label": "Active", + "description": "Active" + }, + "alertMessage": { + "label": "Alert Message", + "description": "Alert Message" + }, + "alertMessageVibra": { + "label": "Alert Message Vibrate", + "description": "Alert Message Vibrate" + }, + "alertMessageBuzzer": { + "label": "Alert Message Buzzer", + "description": "Alert Message Buzzer" + }, + "alertBell": { + "label": "Alert Bell", + "description": "Should an alert be triggered when receiving an incoming bell?" + }, + "alertBellVibra": { + "label": "Alert Bell Vibrate", + "description": "Alert Bell Vibrate" + }, + "alertBellBuzzer": { + "label": "Alert Bell Buzzer", + "description": "Alert Bell Buzzer" + }, + "usePwm": { + "label": "Use PWM", + "description": "Use PWM" + }, + "nagTimeout": { + "label": "Nag Timeout", + "description": "Nag Timeout" + }, + "useI2sAsBuzzer": { + "label": "Use I²S Pin as Buzzer", + "description": "Designate I²S Pin as Buzzer Output" + } + }, + "mqtt": { + "title": "MQTT Settings", + "description": "Settings for the MQTT module", + "enabled": { + "label": "활성화", + "description": "Enable or disable MQTT" + }, + "address": { + "label": "MQTT Server Address", + "description": "MQTT server address to use for default/custom servers" + }, + "username": { + "label": "MQTT Username", + "description": "MQTT username to use for default/custom servers" + }, + "password": { + "label": "MQTT Password", + "description": "MQTT password to use for default/custom servers" + }, + "encryptionEnabled": { + "label": "Encryption Enabled", + "description": "Enable or disable MQTT encryption. Note: All messages are sent to the MQTT broker unencrypted if this option is not enabled, even when your uplink channels have encryption keys set. This includes position data." + }, + "jsonEnabled": { + "label": "JSON Enabled", + "description": "Whether to send/consume JSON packets on MQTT" + }, + "tlsEnabled": { + "label": "TLS Enabled", + "description": "Enable or disable TLS" + }, + "root": { + "label": "Root topic", + "description": "MQTT root topic to use for default/custom servers" + }, + "proxyToClientEnabled": { + "label": "MQTT Client Proxy Enabled", + "description": "Utilizes the network connection to proxy MQTT messages to the client." + }, + "mapReportingEnabled": { + "label": "Map Reporting Enabled", + "description": "Your node will periodically send an unencrypted map report packet to the configured MQTT server, this includes id, short and long name, approximate location, hardware model, role, firmware version, LoRa region, modem preset and primary channel name." + }, + "mapReportSettings": { + "publishIntervalSecs": { + "label": "Map Report Publish Interval (s)", + "description": "Interval in seconds to publish map reports" + }, + "positionPrecision": { + "label": "Approximate Location", + "description": "Position shared will be accurate within this distance", + "options": { + "metric_km23": "Within 23 km", + "metric_km12": "Within 12 km", + "metric_km5_8": "Within 5.8 km", + "metric_km2_9": "Within 2.9 km", + "metric_km1_5": "Within 1.5 km", + "metric_m700": "Within 700 m", + "metric_m350": "Within 350 m", + "metric_m200": "Within 200 m", + "metric_m90": "Within 90 m", + "metric_m50": "Within 50 m", + "imperial_mi15": "15 miles 이내", + "imperial_mi7_3": "7.3 miles 이내", + "imperial_mi3_6": "3.6 miles 이내", + "imperial_mi1_8": "1.8 miles 이내", + "imperial_mi0_9": "0.9 miles 이내", + "imperial_mi0_5": "0.5 miles 이내", + "imperial_mi0_2": "0.2 miles 이내", + "imperial_ft600": "600 feet 이내", + "imperial_ft300": "300 feet 이내", + "imperial_ft150": "150 feet 이내" + } + } + } + }, + "neighborInfo": { + "title": "Neighbor Info Settings", + "description": "Settings for the Neighbor Info module", + "enabled": { + "label": "활성화", + "description": "Enable or disable Neighbor Info Module" + }, + "updateInterval": { + "label": "Update Interval", + "description": "Interval in seconds of how often we should try to send our Neighbor Info to the mesh" + } + }, + "paxcounter": { + "title": "Paxcounter Settings", + "description": "Settings for the Paxcounter module", + "enabled": { + "label": "Module Enabled", + "description": "Enable Paxcounter" + }, + "paxcounterUpdateInterval": { + "label": "Update Interval (seconds)", + "description": "How long to wait between sending paxcounter packets" + }, + "wifiThreshold": { + "label": "WiFi RSSI Threshold", + "description": "At what WiFi RSSI level should the counter increase. Defaults to -80." + }, + "bleThreshold": { + "label": "BLE RSSI Threshold", + "description": "At what BLE RSSI level should the counter increase. Defaults to -80." + } + }, + "rangeTest": { + "title": "Range Test Settings", + "description": "Settings for the Range Test module", + "enabled": { + "label": "Module Enabled", + "description": "Enable Range Test" + }, + "sender": { + "label": "Message Interval", + "description": "How long to wait between sending test packets" + }, + "save": { + "label": "Save CSV to storage", + "description": "ESP32 Only" + } + }, + "serial": { + "title": "Serial Settings", + "description": "Settings for the Serial module", + "enabled": { + "label": "Module Enabled", + "description": "Enable Serial output" + }, + "echo": { + "label": "Echo", + "description": "Any packets you send will be echoed back to your device" + }, + "rxd": { + "label": "Receive Pin", + "description": "Set the GPIO pin to the RXD pin you have set up." + }, + "txd": { + "label": "Transmit Pin", + "description": "Set the GPIO pin to the TXD pin you have set up." + }, + "baud": { + "label": "Baud Rate", + "description": "The serial baud rate" + }, + "timeout": { + "label": "시간 초과", + "description": "Seconds to wait before we consider your packet as 'done'" + }, + "mode": { + "label": "Mode", + "description": "Select Mode" + }, + "overrideConsoleSerialPort": { + "label": "Override Console Serial Port", + "description": "If you have a serial port connected to the console, this will override it." + } + }, + "storeForward": { + "title": "Store & Forward Settings", + "description": "Settings for the Store & Forward module", + "enabled": { + "label": "Module Enabled", + "description": "Enable Store & Forward" + }, + "heartbeat": { + "label": "Heartbeat Enabled", + "description": "Enable Store & Forward heartbeat" + }, + "records": { + "label": "Number of records", + "description": "Number of records to store" + }, + "historyReturnMax": { + "label": "History return max", + "description": "Max number of records to return" + }, + "historyReturnWindow": { + "label": "History return window", + "description": "Return records from this time window (minutes)" + } + }, + "telemetry": { + "title": "Telemetry Settings", + "description": "Settings for the Telemetry module", + "deviceUpdateInterval": { + "label": "Device Metrics", + "description": "장치 메트릭 업데이트 간격 (초)" + }, + "environmentUpdateInterval": { + "label": "환경 메트릭 업데이트 간격 (초)", + "description": "" + }, + "environmentMeasurementEnabled": { + "label": "Module Enabled", + "description": "Enable the Environment Telemetry" + }, + "environmentScreenEnabled": { + "label": "Displayed on Screen", + "description": "Show the Telemetry Module on the OLED" + }, + "environmentDisplayFahrenheit": { + "label": "Display Fahrenheit", + "description": "Display temp in Fahrenheit" + }, + "airQualityEnabled": { + "label": "Air Quality Enabled", + "description": "Enable the Air Quality Telemetry" + }, + "airQualityInterval": { + "label": "Air Quality Update Interval", + "description": "How often to send Air Quality data over the mesh" + }, + "powerMeasurementEnabled": { + "label": "Power Measurement Enabled", + "description": "Enable the Power Measurement Telemetry" + }, + "powerUpdateInterval": { + "label": "Power Update Interval", + "description": "How often to send Power data over the mesh" + }, + "powerScreenEnabled": { + "label": "Power Screen Enabled", + "description": "Enable the Power Telemetry Screen" + } + } } diff --git a/packages/web/public/i18n/locales/ko-KR/nodes.json b/packages/web/public/i18n/locales/ko-KR/nodes.json index a1e4ccc3f..304ac9b1c 100644 --- a/packages/web/public/i18n/locales/ko-KR/nodes.json +++ b/packages/web/public/i18n/locales/ko-KR/nodes.json @@ -1,63 +1,59 @@ { - "nodeDetail": { - "publicKeyEnabled": { - "label": "공개 키 활성화" - }, - "noPublicKey": { - "label": "공개 키 없음" - }, - "directMessage": { - "label": "DM {{shortName}}" - }, - "favorite": { - "label": "즐겨찾기", - "tooltip": "이 노드를 즐겨찾기에 추가하거나 삭제" - }, - "notFavorite": { - "label": "즐겨찾기 아님" - }, - "error": { - "label": "Error", - "text": "노드 정보를 가져오는 과정에서 오류가 발생했습니다. 나중에 다시 시도해 주세요." - }, - "status": { - "heard": "수신", - "mqtt": "MQTT" - }, - "elevation": { - "label": "고도" - }, - "channelUtil": { - "label": "채널 사용률" - }, - "airtimeUtil": { - "label": "통신 사용률" - } - }, - "nodesTable": { - "headings": { - "longName": "긴 이름", - "connection": "연결", - "lastHeard": "최근 수신", - "encryption": "암호화", - "model": "하드웨어", - "macAddress": "MAC 주소" - }, - "connectionStatus": { - "direct": "직접 연결", - "away": "떨어짐", - "unknown": "-", - "viaMqtt": ", MQTT 경유" - }, - "lastHeardStatus": { - "never": "수신 된 적 없음" - } - }, - "actions": { - "added": "추가됨", - "removed": "삭제됨", - "ignoreNode": "노드 무시하기", - "unignoreNode": "노드 무시 해제", - "requestPosition": "위치 요청" - } + "nodeDetail": { + "publicKeyEnabled": { + "label": "공개 키 활성화" + }, + "noPublicKey": { + "label": "공개 키 없음" + }, + "directMessage": { + "label": "DM {{shortName}}" + }, + "favorite": { + "label": "즐겨찾기", + "tooltip": "이 노드를 즐겨찾기에 추가하거나 삭제" + }, + "notFavorite": { + "label": "즐겨찾기 아님" + }, + "error": { + "label": "Error", + "text": "노드 정보를 가져오는 과정에서 오류가 발생했습니다. 나중에 다시 시도해 주세요." + }, + "status": { + "heard": "수신", + "mqtt": "MQTT" + }, + "elevation": { + "label": "고도" + }, + "channelUtil": { + "label": "채널 사용률" + }, + "airtimeUtil": { + "label": "통신 사용률" + } + }, + "nodesTable": { + "headings": { + "longName": "긴 이름", + "connection": "연결", + "lastHeard": "최근 수신", + "encryption": "암호화", + "model": "하드웨어", + "macAddress": "MAC 주소" + }, + "connectionStatus": { + "direct": "직접 연결", + "away": "떨어짐", + "viaMqtt": ", MQTT 경유" + } + }, + "actions": { + "added": "추가됨", + "removed": "삭제됨", + "ignoreNode": "노드 무시하기", + "unignoreNode": "노드 무시 해제", + "requestPosition": "위치 요청" + } } diff --git a/packages/web/public/i18n/locales/ko-KR/ui.json b/packages/web/public/i18n/locales/ko-KR/ui.json index 3b9bca41b..e1b193219 100644 --- a/packages/web/public/i18n/locales/ko-KR/ui.json +++ b/packages/web/public/i18n/locales/ko-KR/ui.json @@ -1,228 +1,230 @@ { - "navigation": { - "title": "메뉴", - "messages": "메시지기기", - "map": "지도", - "config": "설정", - "radioConfig": "무선 설정", - "moduleConfig": "모듈 설정", - "channels": "채널", - "nodes": "노드" - }, - "app": { - "title": "Meshtastic", - "logo": "Meshtastic 로고" - }, - "sidebar": { - "collapseToggle": { - "button": { - "open": "사이드바 열기", - "close": "사이드바 닫기" - } - }, - "deviceInfo": { - "volts": "{{voltage}} V", - "firmware": { - "title": "펌웨어", - "version": "v{{version}}", - "buildDate": "빌드 날짜: {{date}}" - }, - "deviceName": { - "title": "장치 이름", - "changeName": "장치 이름 변경", - "placeholder": "장치 이름 입력" - }, - "editDeviceName": "장치 이름 수정" - } - }, - "batteryStatus": { - "charging": "{{level}}% 충전중", - "pluggedIn": "전원 연결됨", - "title": "배터리" - }, - "search": { - "nodes": "노드 검색...", - "channels": "채널 검색...", - "commandPalette": "명령 검색..." - }, - "toast": { - "positionRequestSent": { - "title": "위치 요청 보냄." - }, - "requestingPosition": { - "title": "위치 요청 중, 기다려주세요." - }, - "sendingTraceroute": { - "title": "추적 루트 요청, 기다려주세요." - }, - "tracerouteSent": { - "title": "추적 루트 보냄." - }, - "savedChannel": { - "title": "저장된 채널: {{channelName}}" - }, - "messages": { - "pkiEncryption": { - "title": "채팅은 PKI 암호화를 사용하고 있습니다." - }, - "pskEncryption": { - "title": "채팅은 PSK 암호화를 사용하고 있습니다." - } - }, - "configSaveError": { - "title": "설정 저장 오류", - "description": "설정을 저장하는 과정에서 오류가 발생했습니다." - }, - "validationError": { - "title": "설정 오류", - "description": "저장하기 전에 설정 오류를 수정해 주시기 바랍니다." - }, - "saveSuccess": { - "title": "설정 저장됨", - "description": "설정 변경 사항 {{case}}가 저장되었습니다." - }, - "favoriteNode": { - "title": "{{nodeName}}이 즐겨찾기{{direction}} {{action}}", - "action": { - "added": "추가됨", - "removed": "삭제됨", - "to": "에", - "from": "에서" - } - }, - "ignoreNode": { - "title": "{{nodeName}}이 무시 목록{{direction}} {{action}}", - "action": { - "added": "추가됨", - "removed": "삭제됨", - "to": "에", - "from": "에서" - } - } - }, - "notifications": { - "copied": { - "label": "저장됨!" - }, - "copyToClipboard": { - "label": "클립보드에 복사" - }, - "hidePassword": { - "label": "비밀번호 숨김" - }, - "showPassword": { - "label": "비밀번호 보기" - }, - "deliveryStatus": { - "delivered": "전송됨", - "failed": "전송 실패", - "waiting": "대기 중", - "unknown": "알 수 없는" - } - }, - "general": { - "label": "일반" - }, - "hardware": { - "label": "하드웨어" - }, - "metrics": { - "label": "메트릭" - }, - "role": { - "label": "역할" - }, - "filter": { - "label": "필터" - }, - "advanced": { - "label": "고급" - }, - "clearInput": { - "label": "입력 지우기" - }, - "resetFilters": { - "label": "필터 초기화" - }, - "nodeName": { - "label": "노드 이름/숫자", - "placeholder": "Meshtastic 1234" - }, - "airtimeUtilization": { - "label": "통신 사용률 (%)" - }, - "batteryLevel": { - "label": "배터리 잔량 (%)", - "labelText": "배터리 잔량 (%): {{value}}" - }, - "batteryVoltage": { - "label": "배터리 전압 (V)", - "title": "전압" - }, - "channelUtilization": { - "label": "채널 사용률 (%)" - }, - "hops": { - "direct": "직접 연결", - "label": "Hops 수", - "text": "Hops 수: {{value}}" - }, - "lastHeard": { - "label": "최근 수신", - "labelText": "최근 수신: {{value}}", - "nowLabel": "지금" - }, - "snr": { - "label": "SNR (db)" - }, - "favorites": { - "label": "즐겨찾기" - }, - "hide": { - "label": "숨기기" - }, - "showOnly": { - "label": "만 보이기" - }, - "viaMqtt": { - "label": "MQTT로 연결된" - }, - "hopsUnknown": { - "label": "Hops 알 수 없음" - }, - "showUnheard": { - "label": "수신된 적 없음" - }, - "language": { - "label": "언어", - "changeLanguage": "언어 선택" - }, - "theme": { - "dark": "다크", - "light": "라이트", - "system": "자동", - "changeTheme": "컬러 선택" - }, - "errorPage": { - "title": "이건 좀 부끄러운 일이에요...", - "description1": "정말 죄송합니다. 웹 클라이언트에서 오류가 발생하여 강제 종료되었습니다.
이 문제는 발생하지 않아야 하는 것이며, 현재 이를 해결하기 위해 최선을 다하고 있습니다.", - "description2": "이 문제가 다시 발생하지 않도록 하는 가장 좋은 방법은 해당 문제를 저희에게 신고해 주시는 것입니다.", - "reportInstructions": "보고서에 다음 정보를 포함해 주시기 바랍니다:", - "reportSteps": { - "step1": "오류가 발생했을 때 무엇을 하고 계셨나요?", - "step2": "어떤 상황을 예상 하셨나요?", - "step3": "실제로 무슨 일이 일어났나요?", - "step4": "기타 관련 정보" - }, - "reportLink": "이 문제를 저희 <0>GitHub에 보고해주세요", - "dashboardLink": "<0>메인으로 돌아가기", - "detailsSummary": "오류 세부 정보", - "errorMessageLabel": "오류 메시지:", - "stackTraceLabel": "스택 추적:", - "fallbackError": "{{error}}" - }, - "footer": { - "text": "Powered by <0>▲ Vercel | Meshtastic®는 Meshtastic LLC의 등록 상표입니다. | <1>법적 정보", - "commitSha": "Commit SHA: {{sha}}" - } + "navigation": { + "title": "메뉴", + "messages": "메시지기기", + "map": "지도", + "settings": "설정", + "channels": "채널", + "radioConfig": "무선 설정", + "deviceConfig": "장치 설정", + "moduleConfig": "모듈 설정", + "manageConnections": "Manage Connections", + "nodes": "노드" + }, + "app": { + "title": "Meshtastic", + "logo": "Meshtastic 로고" + }, + "sidebar": { + "collapseToggle": { + "button": { + "open": "사이드바 열기", + "close": "사이드바 닫기" + } + }, + "deviceInfo": { + "volts": "{{voltage}} V", + "firmware": { + "title": "펌웨어", + "version": "v{{version}}", + "buildDate": "빌드 날짜: {{date}}" + } + } + }, + "batteryStatus": { + "charging": "{{level}}% 충전중", + "pluggedIn": "전원 연결됨", + "title": "배터리" + }, + "search": { + "nodes": "노드 검색...", + "channels": "채널 검색...", + "commandPalette": "명령 검색..." + }, + "toast": { + "positionRequestSent": { + "title": "위치 요청 보냄." + }, + "requestingPosition": { + "title": "위치 요청 중, 기다려주세요." + }, + "sendingTraceroute": { + "title": "추적 루트 요청, 기다려주세요." + }, + "tracerouteSent": { + "title": "추적 루트 보냄." + }, + "savedChannel": { + "title": "저장된 채널: {{channelName}}" + }, + "messages": { + "pkiEncryption": { + "title": "채팅은 PKI 암호화를 사용하고 있습니다." + }, + "pskEncryption": { + "title": "채팅은 PSK 암호화를 사용하고 있습니다." + } + }, + "configSaveError": { + "title": "설정 저장 오류", + "description": "설정을 저장하는 과정에서 오류가 발생했습니다." + }, + "validationError": { + "title": "설정 오류", + "description": "저장하기 전에 설정 오류를 수정해 주시기 바랍니다." + }, + "saveSuccess": { + "title": "설정 저장됨", + "description": "설정 변경 사항 {{case}}가 저장되었습니다." + }, + "saveAllSuccess": { + "title": "Saved", + "description": "All configuration changes have been saved." + }, + "favoriteNode": { + "title": "{{nodeName}}이 즐겨찾기{{direction}} {{action}}", + "action": { + "added": "추가됨", + "removed": "삭제됨", + "to": "에", + "from": "에서" + } + }, + "ignoreNode": { + "title": "{{nodeName}}이 무시 목록{{direction}} {{action}}", + "action": { + "added": "추가됨", + "removed": "삭제됨", + "to": "에", + "from": "에서" + } + } + }, + "notifications": { + "copied": { + "label": "저장됨!" + }, + "copyToClipboard": { + "label": "클립보드에 복사" + }, + "hidePassword": { + "label": "비밀번호 숨김" + }, + "showPassword": { + "label": "비밀번호 보기" + }, + "deliveryStatus": { + "delivered": "전송됨", + "failed": "전송 실패", + "waiting": "대기 중", + "unknown": "알 수 없는" + } + }, + "general": { + "label": "일반" + }, + "hardware": { + "label": "하드웨어" + }, + "metrics": { + "label": "메트릭" + }, + "role": { + "label": "역할" + }, + "filter": { + "label": "필터" + }, + "advanced": { + "label": "고급" + }, + "clearInput": { + "label": "입력 지우기" + }, + "resetFilters": { + "label": "필터 초기화" + }, + "nodeName": { + "label": "노드 이름/숫자", + "placeholder": "Meshtastic 1234" + }, + "airtimeUtilization": { + "label": "통신 사용률 (%)", + "short": "Airtime Util. (%)" + }, + "batteryLevel": { + "label": "배터리 잔량 (%)", + "labelText": "배터리 잔량 (%): {{value}}" + }, + "batteryVoltage": { + "label": "배터리 전압 (V)", + "title": "전압" + }, + "channelUtilization": { + "label": "채널 사용률 (%)", + "short": "Channel Util. (%)" + }, + "hops": { + "direct": "직접 연결", + "label": "Hops 수", + "text": "Hops 수: {{value}}" + }, + "lastHeard": { + "label": "최근 수신", + "labelText": "최근 수신: {{value}}", + "nowLabel": "지금" + }, + "snr": { + "label": "SNR (db)" + }, + "favorites": { + "label": "즐겨찾기" + }, + "hide": { + "label": "숨기기" + }, + "showOnly": { + "label": "만 보이기" + }, + "viaMqtt": { + "label": "MQTT로 연결된" + }, + "hopsUnknown": { + "label": "Hops 알 수 없음" + }, + "showUnheard": { + "label": "수신된 적 없음" + }, + "language": { + "label": "언어", + "changeLanguage": "언어 선택" + }, + "theme": { + "dark": "다크", + "light": "라이트", + "system": "자동", + "changeTheme": "컬러 선택" + }, + "errorPage": { + "title": "이건 좀 부끄러운 일이에요...", + "description1": "정말 죄송합니다. 웹 클라이언트에서 오류가 발생하여 강제 종료되었습니다.
이 문제는 발생하지 않아야 하는 것이며, 현재 이를 해결하기 위해 최선을 다하고 있습니다.", + "description2": "이 문제가 다시 발생하지 않도록 하는 가장 좋은 방법은 해당 문제를 저희에게 신고해 주시는 것입니다.", + "reportInstructions": "보고서에 다음 정보를 포함해 주시기 바랍니다:", + "reportSteps": { + "step1": "오류가 발생했을 때 무엇을 하고 계셨나요?", + "step2": "어떤 상황을 예상 하셨나요?", + "step3": "실제로 무슨 일이 일어났나요?", + "step4": "기타 관련 정보" + }, + "reportLink": "이 문제를 저희 <0>GitHub에 보고해주세요", + "connectionsLink": "Return to the <0>connections", + "detailsSummary": "오류 세부 정보", + "errorMessageLabel": "오류 메시지:", + "stackTraceLabel": "스택 추적:", + "fallbackError": "{{error}}" + }, + "footer": { + "text": "Powered by <0>▲ Vercel | Meshtastic®는 Meshtastic LLC의 등록 상표입니다. | <1>법적 정보", + "commitSha": "Commit SHA: {{sha}}" + } } diff --git a/packages/web/public/i18n/locales/nl-NL/channels.json b/packages/web/public/i18n/locales/nl-NL/channels.json index 79f0d8d2a..f26b6f0bc 100644 --- a/packages/web/public/i18n/locales/nl-NL/channels.json +++ b/packages/web/public/i18n/locales/nl-NL/channels.json @@ -1,69 +1,71 @@ { - "page": { - "sectionLabel": "Kanalen", - "channelName": "Channel: {{channelName}}", - "broadcastLabel": "Primair", - "channelIndex": "Ch {{index}}" - }, - "validation": { - "pskInvalid": "Please enter a valid {{bits}} bit PSK." - }, - "settings": { - "label": "Kanaalinstellingen", - "description": "Crypto, MQTT & misc settings" - }, - "role": { - "label": "Functie", - "description": "Device telemetry is sent over PRIMARY. Only one PRIMARY allowed", - "options": { - "primary": "PRIMARY", - "disabled": "DISABLED", - "secondary": "SECONDARY" - } - }, - "psk": { - "label": "Pre-Shared Key", - "description": "Supported PSK lengths: 256-bit, 128-bit, 8-bit, Empty (0-bit)", - "generate": "Generate" - }, - "name": { - "label": "Naam", - "description": "A unique name for the channel <12 bytes, leave blank for default" - }, - "uplinkEnabled": { - "label": "Uplink Enabled", - "description": "Send messages from the local mesh to MQTT" - }, - "downlinkEnabled": { - "label": "Downlink Enabled", - "description": "Send messages from MQTT to the local mesh" - }, - "positionPrecision": { - "label": "Location", - "description": "The precision of the location to share with the channel. Can be disabled.", - "options": { - "none": "Do not share location", - "precise": "Precise Location", - "metric_km23": "Within 23 kilometers", - "metric_km12": "Within 12 kilometers", - "metric_km5_8": "Within 5.8 kilometers", - "metric_km2_9": "Within 2.9 kilometers", - "metric_km1_5": "Within 1.5 kilometers", - "metric_m700": "Within 700 meters", - "metric_m350": "Within 350 meters", - "metric_m200": "Within 200 meters", - "metric_m90": "Within 90 meters", - "metric_m50": "Within 50 meters", - "imperial_mi15": "Within 15 miles", - "imperial_mi7_3": "Within 7.3 miles", - "imperial_mi3_6": "Within 3.6 miles", - "imperial_mi1_8": "Within 1.8 miles", - "imperial_mi0_9": "Within 0.9 miles", - "imperial_mi0_5": "Within 0.5 miles", - "imperial_mi0_2": "Within 0.2 miles", - "imperial_ft600": "Within 600 feet", - "imperial_ft300": "Within 300 feet", - "imperial_ft150": "Within 150 feet" - } - } + "page": { + "sectionLabel": "Kanalen", + "channelName": "Channel: {{channelName}}", + "broadcastLabel": "Primair", + "channelIndex": "Ch {{index}}", + "import": "Importeer", + "export": "Export" + }, + "validation": { + "pskInvalid": "Please enter a valid {{bits}} bit PSK." + }, + "settings": { + "label": "Kanaalinstellingen", + "description": "Crypto, MQTT & misc settings" + }, + "role": { + "label": "Functie", + "description": "Device telemetry is sent over PRIMARY. Only one PRIMARY allowed", + "options": { + "primary": "PRIMARY", + "disabled": "DISABLED", + "secondary": "SECONDARY" + } + }, + "psk": { + "label": "Pre-Shared Key", + "description": "Supported PSK lengths: 256-bit, 128-bit, 8-bit, Empty (0-bit)", + "generate": "Generate" + }, + "name": { + "label": "Naam", + "description": "A unique name for the channel <12 bytes, leave blank for default" + }, + "uplinkEnabled": { + "label": "Uplink Enabled", + "description": "Send messages from the local mesh to MQTT" + }, + "downlinkEnabled": { + "label": "Downlink Enabled", + "description": "Send messages from MQTT to the local mesh" + }, + "positionPrecision": { + "label": "Location", + "description": "The precision of the location to share with the channel. Can be disabled.", + "options": { + "none": "Do not share location", + "precise": "Precise Location", + "metric_km23": "Within 23 kilometers", + "metric_km12": "Within 12 kilometers", + "metric_km5_8": "Within 5.8 kilometers", + "metric_km2_9": "Within 2.9 kilometers", + "metric_km1_5": "Within 1.5 kilometers", + "metric_m700": "Within 700 meters", + "metric_m350": "Within 350 meters", + "metric_m200": "Within 200 meters", + "metric_m90": "Within 90 meters", + "metric_m50": "Within 50 meters", + "imperial_mi15": "Within 15 miles", + "imperial_mi7_3": "Within 7.3 miles", + "imperial_mi3_6": "Within 3.6 miles", + "imperial_mi1_8": "Within 1.8 miles", + "imperial_mi0_9": "Within 0.9 miles", + "imperial_mi0_5": "Within 0.5 miles", + "imperial_mi0_2": "Within 0.2 miles", + "imperial_ft600": "Within 600 feet", + "imperial_ft300": "Within 300 feet", + "imperial_ft150": "Within 150 feet" + } + } } diff --git a/packages/web/public/i18n/locales/nl-NL/commandPalette.json b/packages/web/public/i18n/locales/nl-NL/commandPalette.json index da965c233..c43579fe9 100644 --- a/packages/web/public/i18n/locales/nl-NL/commandPalette.json +++ b/packages/web/public/i18n/locales/nl-NL/commandPalette.json @@ -15,7 +15,6 @@ "messages": "Berichten", "map": "Kaart", "config": "Config", - "channels": "Kanalen", "nodes": "Nodes" } }, @@ -45,7 +44,8 @@ "label": "Debug", "command": { "reconfigure": "Reconfigure", - "clearAllStoredMessages": "Clear All Stored Message" + "clearAllStoredMessages": "Clear All Stored Message", + "clearAllStores": "Clear All Local Storage" } } } diff --git a/packages/web/public/i18n/locales/nl-NL/common.json b/packages/web/public/i18n/locales/nl-NL/common.json index 2aba0c32a..aaa9d0859 100644 --- a/packages/web/public/i18n/locales/nl-NL/common.json +++ b/packages/web/public/i18n/locales/nl-NL/common.json @@ -1,142 +1,165 @@ { - "button": { - "apply": "Toepassen", - "backupKey": "Backup Key", - "cancel": "Annuleer", - "clearMessages": "Clear Messages", - "close": "Sluit", - "confirm": "Confirm", - "delete": "Verwijder", - "dismiss": "Dismiss", - "download": "Download", - "export": "Export", - "generate": "Generate", - "regenerate": "Regenerate", - "import": "Importeer", - "message": "Bericht", - "now": "Now", - "ok": "OK", - "print": "Print", - "remove": "Verwijder", - "requestNewKeys": "Request New Keys", - "requestPosition": "Request Position", - "reset": "Reset", - "save": "Opslaan", - "scanQr": "Scan QR-code", - "traceRoute": "Trace Route", - "submit": "Submit" - }, - "app": { - "title": "Meshtastic", - "fullTitle": "Meshtastic Web Client" - }, - "loading": "Loading...", - "unit": { - "cps": "CPS", - "dbm": "dBm", - "hertz": "Hz", - "hop": { - "one": "Hop", - "plural": "Hops" - }, - "hopsAway": { - "one": "{{count}} hop away", - "plural": "{{count}} hops away", - "unknown": "Unknown hops away" - }, - "megahertz": "MHz", - "raw": "raw", - "meter": { - "one": "Meter", - "plural": "Meters", - "suffix": "m" - }, - "minute": { - "one": "Minute", - "plural": "Minutes" - }, - "hour": { - "one": "Hour", - "plural": "Hours" - }, - "millisecond": { - "one": "Millisecond", - "plural": "Milliseconds", - "suffix": "ms" - }, - "second": { - "one": "Second", - "plural": "Seconds" - }, - "day": { - "one": "Day", - "plural": "Days" - }, - "month": { - "one": "Month", - "plural": "Months" - }, - "year": { - "one": "Year", - "plural": "Years" - }, - "snr": "SNR", - "volt": { - "one": "Volt", - "plural": "Volts", - "suffix": "V" - }, - "record": { - "one": "Records", - "plural": "Records" - } - }, - "security": { - "0bit": "Empty", - "8bit": "8 bit", - "128bit": "128 bit", - "256bit": "256 bit" - }, - "unknown": { - "longName": "Unknown", - "shortName": "UNK", - "notAvailable": "N/A", - "num": "??" - }, - "nodeUnknownPrefix": "!", - "unset": "UNSET", - "fallbackName": "Meshtastic {{last4}}", - "node": "Node", - "formValidation": { - "unsavedChanges": "Unsaved changes", - "tooBig": { - "string": "Too long, expected less than or equal to {{maximum}} characters.", - "number": "Too big, expected a number smaller than or equal to {{maximum}}.", - "bytes": "Too big, expected less than or equal to {{params.maximum}} bytes." - }, - "tooSmall": { - "string": "Too short, expected more than or equal to {{minimum}} characters.", - "number": "Too small, expected a number larger than or equal to {{minimum}}." - }, - "invalidFormat": { - "ipv4": "Invalid format, expected an IPv4 address.", - "key": "Invalid format, expected a Base64 encoded pre-shared key (PSK)." - }, - "invalidType": { - "number": "Invalid type, expected a number." - }, - "pskLength": { - "0bit": "Key is required to be empty.", - "8bit": "Key is required to be an 8 bit pre-shared key (PSK).", - "128bit": "Key is required to be a 128 bit pre-shared key (PSK).", - "256bit": "Key is required to be a 256 bit pre-shared key (PSK)." - }, - "required": { - "generic": "This field is required.", - "managed": "At least one admin key is requred if the node is managed.", - "key": "Key is required." - } - }, - "yes": "Yes", - "no": "No" + "button": { + "apply": "Toepassen", + "addConnection": "Add Connection", + "saveConnection": "Save connection", + "backupKey": "Backup Key", + "cancel": "Annuleer", + "connect": "Verbinding maken", + "clearMessages": "Clear Messages", + "close": "Sluit", + "confirm": "Confirm", + "delete": "Verwijder", + "dismiss": "Dismiss", + "download": "Download", + "disconnect": "Verbinding verbreken", + "export": "Export", + "generate": "Generate", + "regenerate": "Regenerate", + "import": "Importeer", + "message": "Bericht", + "now": "Now", + "ok": "OK", + "print": "Print", + "remove": "Verwijder", + "requestNewKeys": "Request New Keys", + "requestPosition": "Request Position", + "reset": "Reset", + "retry": "Retry", + "save": "Opslaan", + "setDefault": "Set as default", + "unsetDefault": "Unset default", + "scanQr": "Scan QR-code", + "traceRoute": "Trace Route", + "submit": "Submit" + }, + "app": { + "title": "Meshtastic", + "fullTitle": "Meshtastic Web Client" + }, + "loading": "Loading...", + "unit": { + "cps": "CPS", + "dbm": "dBm", + "hertz": "Hz", + "hop": { + "one": "Hop", + "plural": "Hops" + }, + "hopsAway": { + "one": "{{count}} hop away", + "plural": "{{count}} hops away", + "unknown": "Unknown hops away" + }, + "megahertz": "MHz", + "kilohertz": "kHz", + "raw": "raw", + "meter": { + "one": "Meter", + "plural": "Meters", + "suffix": "m" + }, + "kilometer": { + "one": "Kilometer", + "plural": "Kilometers", + "suffix": "km" + }, + "minute": { + "one": "Minute", + "plural": "Minutes" + }, + "hour": { + "one": "Hour", + "plural": "Hours" + }, + "millisecond": { + "one": "Millisecond", + "plural": "Milliseconds", + "suffix": "ms" + }, + "second": { + "one": "Second", + "plural": "Seconds" + }, + "day": { + "one": "Day", + "plural": "Days", + "today": "Today", + "yesterday": "Yesterday" + }, + "month": { + "one": "Month", + "plural": "Months" + }, + "year": { + "one": "Year", + "plural": "Years" + }, + "snr": "SNR", + "volt": { + "one": "Volt", + "plural": "Volts", + "suffix": "V" + }, + "record": { + "one": "Records", + "plural": "Records" + }, + "degree": { + "one": "Degree", + "plural": "Degrees", + "suffix": "°" + } + }, + "security": { + "0bit": "Empty", + "8bit": "8 bit", + "128bit": "128 bit", + "256bit": "256 bit" + }, + "unknown": { + "longName": "Unknown", + "shortName": "UNK", + "notAvailable": "N/A", + "num": "??" + }, + "nodeUnknownPrefix": "!", + "unset": "UNSET", + "fallbackName": "Meshtastic {{last4}}", + "node": "Node", + "formValidation": { + "unsavedChanges": "Unsaved changes", + "tooBig": { + "string": "Too long, expected less than or equal to {{maximum}} characters.", + "number": "Too big, expected a number smaller than or equal to {{maximum}}.", + "bytes": "Too big, expected less than or equal to {{params.maximum}} bytes." + }, + "tooSmall": { + "string": "Too short, expected more than or equal to {{minimum}} characters.", + "number": "Too small, expected a number larger than or equal to {{minimum}}." + }, + "invalidFormat": { + "ipv4": "Invalid format, expected an IPv4 address.", + "key": "Invalid format, expected a Base64 encoded pre-shared key (PSK)." + }, + "invalidType": { + "number": "Invalid type, expected a number." + }, + "pskLength": { + "0bit": "Key is required to be empty.", + "8bit": "Key is required to be an 8 bit pre-shared key (PSK).", + "128bit": "Key is required to be a 128 bit pre-shared key (PSK).", + "256bit": "Key is required to be a 256 bit pre-shared key (PSK)." + }, + "required": { + "generic": "This field is required.", + "managed": "At least one admin key is requred if the node is managed.", + "key": "Key is required." + }, + "invalidOverrideFreq": { + "number": "Invalid format, expected a value in the range 410-930 MHz or 0 (use default)." + } + }, + "yes": "Yes", + "no": "No" } diff --git a/packages/web/public/i18n/locales/nl-NL/config.json b/packages/web/public/i18n/locales/nl-NL/config.json new file mode 100644 index 000000000..7cab6dd94 --- /dev/null +++ b/packages/web/public/i18n/locales/nl-NL/config.json @@ -0,0 +1,458 @@ +{ + "page": { + "title": "Instellingen", + "tabUser": "Gebruiker", + "tabChannels": "Kanalen", + "tabBluetooth": "Bluetooth", + "tabDevice": "Apparaat", + "tabDisplay": "Weergave", + "tabLora": "LoRa", + "tabNetwork": "Netwerk", + "tabPosition": "Positie", + "tabPower": "Vermogen", + "tabSecurity": "Beveiliging" + }, + "sidebar": { + "label": "Configuration" + }, + "device": { + "title": "Device Settings", + "description": "Settings for the device", + "buttonPin": { + "description": "Button pin override", + "label": "Button Pin" + }, + "buzzerPin": { + "description": "Buzzer pin override", + "label": "Buzzer Pin" + }, + "disableTripleClick": { + "description": "Disable triple click", + "label": "Disable Triple Click" + }, + "doubleTapAsButtonPress": { + "description": "Treat double tap as button press", + "label": "Double Tap as Button Press" + }, + "ledHeartbeatDisabled": { + "description": "Disable default blinking LED", + "label": "LED Heartbeat Disabled" + }, + "nodeInfoBroadcastInterval": { + "description": "How often to broadcast node info", + "label": "Node Info Broadcast Interval" + }, + "posixTimezone": { + "description": "The POSIX timezone string for the device", + "label": "POSIX Timezone" + }, + "rebroadcastMode": { + "description": "How to handle rebroadcasting", + "label": "Rebroadcast Mode" + }, + "role": { + "description": "What role the device performs on the mesh", + "label": "Functie" + } + }, + "bluetooth": { + "title": "Bluetooth Settings", + "description": "Settings for the Bluetooth module", + "note": "Note: Some devices (ESP32) cannot use both Bluetooth and WiFi at the same time.", + "enabled": { + "description": "Enable or disable Bluetooth", + "label": "Enabled" + }, + "pairingMode": { + "description": "Pin selection behaviour.", + "label": "Koppelmodus" + }, + "pin": { + "description": "Pin to use when pairing", + "label": "Pin" + } + }, + "display": { + "description": "Settings for the device display", + "title": "Display Settings", + "headingBold": { + "description": "Bolden the heading text", + "label": "Bold Heading" + }, + "carouselDelay": { + "description": "How fast to cycle through windows", + "label": "Carousel Delay" + }, + "compassNorthTop": { + "description": "Fix north to the top of compass", + "label": "Compass North Top" + }, + "displayMode": { + "description": "Screen layout variant", + "label": "Display Mode" + }, + "displayUnits": { + "description": "Display metric or imperial units", + "label": "Display Units" + }, + "flipScreen": { + "description": "Flip display 180 degrees", + "label": "Flip Screen" + }, + "gpsDisplayUnits": { + "description": "Coordinate display format", + "label": "GPS Display Units" + }, + "oledType": { + "description": "Type of OLED screen attached to the device", + "label": "OLED Type" + }, + "screenTimeout": { + "description": "Turn off the display after this long", + "label": "Screen Timeout" + }, + "twelveHourClock": { + "description": "Use 12-hour clock format", + "label": "12-Hour Clock" + }, + "wakeOnTapOrMotion": { + "description": "Wake the device on tap or motion", + "label": "Wake on Tap or Motion" + } + }, + "lora": { + "title": "Mesh Settings", + "description": "Settings for the LoRa mesh", + "bandwidth": { + "description": "Channel bandwidth in kHz", + "label": "Bandbreedte" + }, + "boostedRxGain": { + "description": "Boosted RX gain", + "label": "Boosted RX Gain" + }, + "codingRate": { + "description": "The denominator of the coding rate", + "label": "Coding Rate" + }, + "frequencyOffset": { + "description": "Frequency offset to correct for crystal calibration errors", + "label": "Frequency Offset" + }, + "frequencySlot": { + "description": "LoRa frequency channel number", + "label": "Frequency Slot" + }, + "hopLimit": { + "description": "Maximum number of hops", + "label": "Hop Limit" + }, + "ignoreMqtt": { + "description": "Don't forward MQTT messages over the mesh", + "label": "Negeer MQTT" + }, + "modemPreset": { + "description": "Modem preset to use", + "label": "Modem Preset" + }, + "okToMqtt": { + "description": "When set to true, this configuration indicates that the user approves the packet to be uploaded to MQTT. If set to false, remote nodes are requested not to forward packets to MQTT", + "label": "OK to MQTT" + }, + "overrideDutyCycle": { + "description": "Overschrijf Duty Cycle", + "label": "Overschrijf Duty Cycle" + }, + "overrideFrequency": { + "description": "Override frequency", + "label": "Override Frequency" + }, + "region": { + "description": "Sets the region for your node", + "label": "Regio" + }, + "spreadingFactor": { + "description": "Indicates the number of chirps per symbol", + "label": "Spreading Factor" + }, + "transmitEnabled": { + "description": "Enable/Disable transmit (TX) from the LoRa radio", + "label": "Transmit Enabled" + }, + "transmitPower": { + "description": "Max transmit power", + "label": "Transmit Power" + }, + "usePreset": { + "description": "Use one of the predefined modem presets", + "label": "Use Preset" + }, + "meshSettings": { + "description": "Settings for the LoRa mesh", + "label": "Mesh Settings" + }, + "waveformSettings": { + "description": "Settings for the LoRa waveform", + "label": "Waveform Settings" + }, + "radioSettings": { + "label": "Radio Settings", + "description": "Settings for the LoRa radio" + } + }, + "network": { + "title": "WiFi Config", + "description": "WiFi radio configuration", + "note": "Note: Some devices (ESP32) cannot use both Bluetooth and WiFi at the same time.", + "addressMode": { + "description": "Address assignment selection", + "label": "Address Mode" + }, + "dns": { + "description": "DNS Server", + "label": "DNS" + }, + "ethernetEnabled": { + "description": "Enable or disable the Ethernet port", + "label": "Enabled" + }, + "gateway": { + "description": "Default Gateway", + "label": "Gateway" + }, + "ip": { + "description": "IP Address", + "label": "IP-adres" + }, + "psk": { + "description": "Network password", + "label": "PSK" + }, + "ssid": { + "description": "Network name", + "label": "SSID" + }, + "subnet": { + "description": "Subnet Mask", + "label": "Subnet" + }, + "wifiEnabled": { + "description": "Enable or disable the WiFi radio", + "label": "Enabled" + }, + "meshViaUdp": { + "label": "Mesh via UDP" + }, + "ntpServer": { + "label": "NTP Server" + }, + "rsyslogServer": { + "label": "Rsyslog Server" + }, + "ethernetConfigSettings": { + "description": "Ethernet port configuration", + "label": "Ethernet Config" + }, + "ipConfigSettings": { + "description": "IP configuration", + "label": "IP Config" + }, + "ntpConfigSettings": { + "description": "NTP configuration", + "label": "NTP Config" + }, + "rsyslogConfigSettings": { + "description": "Rsyslog configuration", + "label": "Rsyslog Config" + }, + "udpConfigSettings": { + "description": "UDP over Mesh configuration", + "label": "UDP Configuratie" + } + }, + "position": { + "title": "Position Settings", + "description": "Settings for the position module", + "broadcastInterval": { + "description": "How often your position is sent out over the mesh", + "label": "Broadcast Interval" + }, + "enablePin": { + "description": "GPS module enable pin override", + "label": "Enable Pin" + }, + "fixedPosition": { + "description": "Don't report GPS position, but a manually-specified one", + "label": "Fixed Position" + }, + "gpsMode": { + "description": "Configure whether device GPS is Enabled, Disabled, or Not Present", + "label": "GPS Mode" + }, + "gpsUpdateInterval": { + "description": "How often a GPS fix should be acquired", + "label": "GPS Update Interval" + }, + "positionFlags": { + "description": "Optional fields to include when assembling position messages. The more fields are selected, the larger the message will be leading to longer airtime usage and a higher risk of packet loss.", + "label": "Position Flags" + }, + "receivePin": { + "description": "GPS module RX pin override", + "label": "Receive Pin" + }, + "smartPositionEnabled": { + "description": "Only send position when there has been a meaningful change in location", + "label": "Enable Smart Position" + }, + "smartPositionMinDistance": { + "description": "Minimum distance (in meters) that must be traveled before a position update is sent", + "label": "Smart Position Minimum Distance" + }, + "smartPositionMinInterval": { + "description": "Minimum interval (in seconds) that must pass before a position update is sent", + "label": "Smart Position Minimum Interval" + }, + "transmitPin": { + "description": "GPS module TX pin override", + "label": "Transmit Pin" + }, + "intervalsSettings": { + "description": "How often to send position updates", + "label": "Intervals" + }, + "flags": { + "placeholder": "Select position flags...", + "altitude": "Altitude", + "altitudeGeoidalSeparation": "Altitude Geoidal Separation", + "altitudeMsl": "Altitude is Mean Sea Level", + "dop": "Dilution of precision (DOP) PDOP used by default", + "hdopVdop": "If DOP is set, use HDOP / VDOP values instead of PDOP", + "numSatellites": "Number of satellites", + "sequenceNumber": "Sequence number", + "timestamp": "Tijdstempel", + "unset": "Terugzetten", + "vehicleHeading": "Vehicle heading", + "vehicleSpeed": "Vehicle speed" + } + }, + "power": { + "adcMultiplierOverride": { + "description": "Used for tweaking battery voltage reading", + "label": "ADC Multiplier Override ratio" + }, + "ina219Address": { + "description": "Address of the INA219 battery monitor", + "label": "INA219 Address" + }, + "lightSleepDuration": { + "description": "How long the device will be in light sleep for", + "label": "Light Sleep Duration" + }, + "minimumWakeTime": { + "description": "Minimum amount of time the device will stay awake for after receiving a packet", + "label": "Minimum Wake Time" + }, + "noConnectionBluetoothDisabled": { + "description": "If the device does not receive a Bluetooth connection, the BLE radio will be disabled after this long", + "label": "No Connection Bluetooth Disabled" + }, + "powerSavingEnabled": { + "description": "Select if powered from a low-current source (i.e. solar), to minimize power consumption as much as possible.", + "label": "Energiebesparingsmodus inschakelen" + }, + "shutdownOnBatteryDelay": { + "description": "Automatically shutdown node after this long when on battery, 0 for indefinite", + "label": "Shutdown on battery delay" + }, + "superDeepSleepDuration": { + "description": "How long the device will be in super deep sleep for", + "label": "Super Deep Sleep Duration" + }, + "powerConfigSettings": { + "description": "Settings for the power module", + "label": "Energie configuratie" + }, + "sleepSettings": { + "description": "Sleep settings for the power module", + "label": "Sleep Settings" + } + }, + "security": { + "description": "Settings for the Security configuration", + "title": "Security Settings", + "button_backupKey": "Backup Key", + "adminChannelEnabled": { + "description": "Allow incoming device control over the insecure legacy admin channel", + "label": "Allow Legacy Admin" + }, + "enableDebugLogApi": { + "description": "Output live debug logging over serial, view and export position-redacted device logs over Bluetooth", + "label": "Enable Debug Log API" + }, + "managed": { + "description": "If enabled, device configuration options are only able to be changed remotely by a Remote Admin node via admin messages. Do not enable this option unless at least one suitable Remote Admin node has been setup, and the public key is stored in one of the fields above.", + "label": "Managed" + }, + "privateKey": { + "description": "Used to create a shared key with a remote device", + "label": "Privésleutel" + }, + "publicKey": { + "description": "Sent out to other nodes on the mesh to allow them to compute a shared secret key", + "label": "Publieke sleutel" + }, + "primaryAdminKey": { + "description": "The primary public key authorized to send admin messages to this node", + "label": "Primary Admin Key" + }, + "secondaryAdminKey": { + "description": "The secondary public key authorized to send admin messages to this node", + "label": "Secondary Admin Key" + }, + "serialOutputEnabled": { + "description": "Serial Console over the Stream API", + "label": "Serial Output Enabled" + }, + "tertiaryAdminKey": { + "description": "The tertiary public key authorized to send admin messages to this node", + "label": "Tertiary Admin Key" + }, + "adminSettings": { + "description": "Settings for Admin", + "label": "Admin Settings" + }, + "loggingSettings": { + "description": "Settings for Logging", + "label": "Logging Settings" + } + }, + "user": { + "title": "User Settings", + "description": "Configure your device name and identity settings", + "longName": { + "label": "Long Name", + "description": "Your full display name (1-40 characters)", + "validation": { + "min": "Long name must be at least 1 character", + "max": "Long name must be at most 40 characters" + } + }, + "shortName": { + "label": "Short Name", + "description": "Your abbreviated name (2-4 characters)", + "validation": { + "min": "Short name must be at least 2 characters", + "max": "Short name must be at most 4 characters" + } + }, + "isUnmessageable": { + "label": "Niet berichtbaar", + "description": "Used to identify unmonitored or infrastructure nodes so that messaging is not available to nodes that will never respond." + }, + "isLicensed": { + "label": "Licensed amateur radio (HAM)", + "description": "Enable if you are a licensed amateur radio operator, enabling this option disables encryption and is not compatible with the default Meshtastic network." + } + } +} diff --git a/packages/web/public/i18n/locales/nl-NL/connections.json b/packages/web/public/i18n/locales/nl-NL/connections.json new file mode 100644 index 000000000..2cda5df9f --- /dev/null +++ b/packages/web/public/i18n/locales/nl-NL/connections.json @@ -0,0 +1,34 @@ +{ + "page": { + "title": "Connect to a Meshtastic device", + "description": "Add a device connection via HTTP, Bluetooth, or Serial. Your saved connections will be saved in your browser." + }, + "connectionType_ble": "BLE", + "connectionType_serial": "Serieel", + "connectionType_network": "Netwerk", + "deleteConnection": "Delete connection", + "areYouSure": "This will remove {{name}}. You canot undo this action.", + "moreActions": "More actions", + "noConnections": { + "title": "No connections yet.", + "description": "Create your first connection. It will connect immediately and be saved for later." + }, + "lastConnectedAt": "Last connected: {{date}}", + "neverConnected": "Never connected", + "toasts": { + "connected": "Verbonden", + "nowConnected": "{{name}} is now connected", + "nowDisconnected": "{{name}} are now disconnecte", + "disconnected": "Niet verbonden", + "failed": "Failed to connect", + "checkConnetion": "Check your device or settings and try again", + "defaultSet": "Default set", + "defaultConnection": "Default connection is now {{nameisconnected}}", + "deleted": "Deleted", + "deletedByName": "{{name}} was removed", + "pickConnectionAgain": "Could not connect. You may need to reselect the device/port.", + "added": "Connection added", + "savedByName": "{{name}} saved.", + "savedCantConnect": "The connection was saved but could not connect." + } +} diff --git a/packages/web/public/i18n/locales/nl-NL/dashboard.json b/packages/web/public/i18n/locales/nl-NL/dashboard.json deleted file mode 100644 index 260a97386..000000000 --- a/packages/web/public/i18n/locales/nl-NL/dashboard.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "dashboard": { - "title": "Connected Devices", - "description": "Manage your connected Meshtastic devices.", - "connectionType_ble": "BLE", - "connectionType_serial": "Serieel", - "connectionType_network": "Netwerk", - "noDevicesTitle": "No devices connected", - "noDevicesDescription": "Connect a new device to get started.", - "button_newConnection": "New Connection" - } -} diff --git a/packages/web/public/i18n/locales/nl-NL/deviceConfig.json b/packages/web/public/i18n/locales/nl-NL/deviceConfig.json index 6e7662212..f62bb70cf 100644 --- a/packages/web/public/i18n/locales/nl-NL/deviceConfig.json +++ b/packages/web/public/i18n/locales/nl-NL/deviceConfig.json @@ -122,7 +122,7 @@ "title": "Mesh Settings", "description": "Settings for the LoRa mesh", "bandwidth": { - "description": "Channel bandwidth in MHz", + "description": "Channel bandwidth in kHz", "label": "Bandbreedte" }, "boostedRxGain": { diff --git a/packages/web/public/i18n/locales/nl-NL/dialog.json b/packages/web/public/i18n/locales/nl-NL/dialog.json index fad2cd242..715c9dc5d 100644 --- a/packages/web/public/i18n/locales/nl-NL/dialog.json +++ b/packages/web/public/i18n/locales/nl-NL/dialog.json @@ -1,193 +1,238 @@ { - "deleteMessages": { - "description": "This action will clear all message history. This cannot be undone. Are you sure you want to continue?", - "title": "Clear All Messages" - }, - "deviceName": { - "description": "The Device will restart once the config is saved.", - "longName": "Long Name", - "shortName": "Short Name", - "title": "Change Device Name", - "validation": { - "longNameMax": "Long name must not be more than 40 characters", - "shortNameMax": "Short name must not be more than 4 characters", - "longNameMin": "Long name must have at least 1 character", - "shortNameMin": "Short name must have at least 1 character" - } - }, - "import": { - "description": "The current LoRa configuration will be overridden.", - "error": { - "invalidUrl": "Invalid Meshtastic URL" - }, - "channelPrefix": "Channel: ", - "channelSetUrl": "Channel Set/QR Code URL", - "channels": "Channels:", - "usePreset": "Use Preset?", - "title": "Import Channel Set" - }, - "locationResponse": { - "title": "Location: {{identifier}}", - "altitude": "Altitude: ", - "coordinates": "Coordinates: ", - "noCoordinates": "No Coordinates" - }, - "pkiRegenerateDialog": { - "title": "Regenerate Pre-Shared Key?", - "description": "Are you sure you want to regenerate the pre-shared key?", - "regenerate": "Regenerate" - }, - "newDeviceDialog": { - "title": "Connect New Device", - "https": "https", - "http": "http", - "tabHttp": "HTTP", - "tabBluetooth": "Bluetooth", - "tabSerial": "Serieel", - "useHttps": "Use HTTPS", - "connecting": "Connecting...", - "connect": "Verbinding maken", - "connectionFailedAlert": { - "title": "Connection Failed", - "descriptionPrefix": "Could not connect to the device. ", - "httpsHint": "If using HTTPS, you may need to accept a self-signed certificate first. ", - "openLinkPrefix": "Please open ", - "openLinkSuffix": " in a new tab", - "acceptTlsWarningSuffix": ", accept any TLS warnings if prompted, then try again", - "learnMoreLink": "Learn more" - }, - "httpConnection": { - "label": "IP Address/Hostname", - "placeholder": "000.000.000.000 / meshtastic.local" - }, - "serialConnection": { - "noDevicesPaired": "No devices paired yet.", - "newDeviceButton": "New device", - "deviceIdentifier": "# {{index}} - {{vendorId}} - {{productId}}" - }, - "bluetoothConnection": { - "noDevicesPaired": "No devices paired yet.", - "newDeviceButton": "New device", - "connectionFailed": "Connection failed", - "deviceDisconnected": "Device disconnected", - "unknownDevice": "Unknown Device", - "errorLoadingDevices": "Error loading devices", - "unknownErrorLoadingDevices": "Unknown error loading devices" - }, - "validation": { - "requiresWebBluetooth": "This connection type requires <0>Web Bluetooth. Please use a supported browser, like Chrome or Edge.", - "requiresWebSerial": "This connection type requires <0>Web Serial. Please use a supported browser, like Chrome or Edge.", - "requiresSecureContext": "This application requires a <0>secure context. Please connect using HTTPS or localhost.", - "additionallyRequiresSecureContext": "Additionally, it requires a <0>secure context. Please connect using HTTPS or localhost." - } - }, - "nodeDetails": { - "message": "Bericht", - "requestPosition": "Request Position", - "traceRoute": "Trace Route", - "airTxUtilization": "Air TX utilization", - "allRawMetrics": "All Raw Metrics:", - "batteryLevel": "Battery level", - "channelUtilization": "Channel utilization", - "details": "Details:", - "deviceMetrics": "Device Metrics:", - "hardware": "Hardware: ", - "lastHeard": "Last Heard: ", - "nodeHexPrefix": "Node Hex: ", - "nodeNumber": "Node Number: ", - "position": "Position:", - "role": "Role: ", - "uptime": "Uptime: ", - "voltage": "Spanning", - "title": "Node Details for {{identifier}}", - "ignoreNode": "Ignore node", - "removeNode": "Remove node", - "unignoreNode": "Unignore node", - "security": "Security:", - "publicKey": "Public Key: ", - "messageable": "Messageable: ", - "KeyManuallyVerifiedTrue": "Public Key has been manually verified", - "KeyManuallyVerifiedFalse": "Public Key is not manually verified" - }, - "pkiBackup": { - "loseKeysWarning": "If you lose your keys, you will need to reset your device.", - "secureBackup": "Its important to backup your public and private keys and store your backup securely!", - "footer": "=== END OF KEYS ===", - "header": "=== MESHTASTIC KEYS FOR {{longName}} ({{shortName}}) ===", - "privateKey": "Private Key:", - "publicKey": "Public Key:", - "fileName": "meshtastic_keys_{{longName}}_{{shortName}}.txt", - "title": "Backup Keys" - }, - "pkiBackupReminder": { - "description": "We recommend backing up your key data regularly. Would you like to back up now?", - "title": "Backup Reminder", - "remindLaterPrefix": "Remind me in", - "remindNever": "Never remind me", - "backupNow": "Back up now" - }, - "pkiRegenerate": { - "description": "Are you sure you want to regenerate key pair?", - "title": "Regenerate Key Pair" - }, - "qr": { - "addChannels": "Add Channels", - "replaceChannels": "Replace Channels", - "description": "The current LoRa configuration will also be shared.", - "sharableUrl": "Sharable URL", - "title": "Generate QR Code" - }, - "reboot": { - "title": "Reboot device", - "description": "Reboot now or schedule a reboot of the connected node. Optionally, you can choose to reboot into OTA (Over-the-Air) mode.", - "ota": "Reboot into OTA mode", - "enterDelay": "Enter delay", - "scheduled": "Reboot has been scheduled", - "schedule": "Schedule reboot", - "now": "Reboot now", - "cancel": "Cancel scheduled reboot" - }, - "refreshKeys": { - "description": { - "acceptNewKeys": "This will remove the node from device and request new keys.", - "keyMismatchReasonSuffix": ". This is due to the remote node's current public key does not match the previously stored key for this node.", - "unableToSendDmPrefix": "Your node is unable to send a direct message to node: " - }, - "acceptNewKeys": "Accept New Keys", - "title": "Keys Mismatch - {{identifier}}" - }, - "removeNode": { - "description": "Are you sure you want to remove this Node?", - "title": "Remove Node?" - }, - "shutdown": { - "title": "Schedule Shutdown", - "description": "Turn off the connected node after x minutes." - }, - "traceRoute": { - "routeToDestination": "Route to destination:", - "routeBack": "Route back:" - }, - "tracerouteResponse": { - "title": "Traceroute: {{identifier}}" - }, - "unsafeRoles": { - "confirmUnderstanding": "Yes, I know what I'm doing", - "conjunction": " and the blog post about ", - "postamble": " and understand the implications of changing the role.", - "preamble": "I have read the ", - "choosingRightDeviceRole": "Choosing The Right Device Role", - "deviceRoleDocumentation": "Device Role Documentation", - "title": "Weet u het zeker?" - }, - "managedMode": { - "confirmUnderstanding": "Yes, I know what I'm doing", - "title": "Weet u het zeker?", - "description": "Enabling Managed Mode blocks client applications (including the web client) from writing configurations to a radio. Once enabled, radio configurations can only be changed through Remote Admin messages. This setting is not required for remote node administration." - }, - "clientNotification": { - "title": "Client Notification", - "TraceRoute can only be sent once every 30 seconds": "TraceRoute can only be sent once every 30 seconds", - "Compromised keys were detected and regenerated.": "Compromised keys were detected and regenerated." - } + "deleteMessages": { + "description": "This action will clear all message history. This cannot be undone. Are you sure you want to continue?", + "title": "Clear All Messages" + }, + "import": { + "description": "The current LoRa configuration will be overridden.", + "error": { + "invalidUrl": "Invalid Meshtastic URL" + }, + "channelPrefix": "Channel: ", + "primary": "Primary ", + "doNotImport": "No not import", + "channelName": "Naam", + "channelSlot": "Slot", + "channelSetUrl": "Channel Set/QR Code URL", + "useLoraConfig": "Import LoRa Config", + "presetDescription": "The current LoRa Config will be replaced.", + "title": "Import Channel Set" + }, + "locationResponse": { + "title": "Location: {{identifier}}", + "altitude": "Altitude: ", + "coordinates": "Coordinates: ", + "noCoordinates": "No Coordinates" + }, + "pkiRegenerateDialog": { + "title": "Regenerate Pre-Shared Key?", + "description": "Are you sure you want to regenerate the pre-shared key?", + "regenerate": "Regenerate" + }, + "addConnection": { + "title": "Add connection", + "description": "Choose a connection type and fill in the details", + "validation": { + "requiresWebBluetooth": "This connection type requires <0>Web Bluetooth. Please use a supported browser, like Chrome or Edge.", + "requiresWebSerial": "This connection type requires <0>Web Serial. Please use a supported browser, like Chrome or Edge.", + "requiresSecureContext": "This application requires a <0>secure context. Please connect using HTTPS or localhost.", + "additionallyRequiresSecureContext": "Additionally, it requires a <0>secure context. Please connect using HTTPS or localhost." + }, + "bluetoothConnection": { + "namePlaceholder": "My Bluetooth Node", + "supported": { + "title": "Web Bluetooth supported" + }, + "notSupported": { + "title": "Web Bluetooth not supported", + "description": "Your browser or device does not support Web Bluetooth" + }, + "short": "BT: {{deviceName}}", + "long": "Bluetooth Device", + "device": "Apparaat", + "selectDevice": "Select device", + "selected": "Bluetooth device selected", + "notSelected": "No device selected", + "helperText": "Uses the Meshtastic Bluetooth service for discovery." + }, + "serialConnection": { + "namePlaceholder": "My Serial Node", + "helperText": "Selecting a port grants permission so the app can open it to connect.", + "supported": { + "title": "Web Serial supported" + }, + "notSupported": { + "title": "Web Serial not supported", + "description": "Your browser or device does not support Web Serial" + }, + "portSelected": { + "title": "Serial port selected", + "description": "Port permissions granted." + }, + "port": "Port", + "selectPort": "Select port", + "deviceName": "USB {{vendorId}}:{{productId}}", + "notSelected": "No port selected" + }, + "httpConnection": { + "namePlaceholder": "My HTTP Node", + "inputPlaceholder": "192.168.1.10 or meshtastic.local", + "heading": "URL or IP", + "useHttps": "Use HTTTPS", + "invalidUrl": { + "title": "Invalid URL", + "description": "Please enter a valid HTTP or HTTPS URL." + }, + "connectionTest": { + "description": "Test the connetion before saving to verify the device is reachable.", + "button": { + "loading": "Testing...", + "label": "Test connection" + }, + "reachable": "Reachable", + "notReachable": "Not reachable", + "success": { + "title": "Connection test successful", + "description": "The device appears to be reachable." + }, + "failure": { + "title": "Connection test failed", + "description": "Could not reach the device. Check the URL and try again." + } + } + } + }, + "nodeDetails": { + "message": "Bericht", + "requestPosition": "Request Position", + "traceRoute": "Trace Route", + "airTxUtilization": "Air TX utilization", + "allRawMetrics": "All Raw Metrics:", + "batteryLevel": "Battery level", + "channelUtilization": "Channel utilization", + "details": "Details:", + "deviceMetrics": "Device Metrics:", + "hardware": "Hardware: ", + "lastHeard": "Last Heard: ", + "nodeHexPrefix": "Node Hex: ", + "nodeNumber": "Node Number: ", + "position": "Position:", + "role": "Role: ", + "uptime": "Uptime: ", + "voltage": "Spanning", + "title": "Node Details for {{identifier}}", + "ignoreNode": "Ignore node", + "removeNode": "Remove node", + "unignoreNode": "Unignore node", + "security": "Security:", + "publicKey": "Public Key: ", + "messageable": "Messageable: ", + "KeyManuallyVerifiedTrue": "Public Key has been manually verified", + "KeyManuallyVerifiedFalse": "Public Key is not manually verified" + }, + "pkiBackup": { + "loseKeysWarning": "If you lose your keys, you will need to reset your device.", + "secureBackup": "Its important to backup your public and private keys and store your backup securely!", + "footer": "=== END OF KEYS ===", + "header": "=== MESHTASTIC KEYS FOR {{longName}} ({{shortName}}) ===", + "privateKey": "Private Key:", + "publicKey": "Public Key:", + "fileName": "meshtastic_keys_{{longName}}_{{shortName}}.txt", + "title": "Backup Keys" + }, + "pkiBackupReminder": { + "description": "We recommend backing up your key data regularly. Would you like to back up now?", + "title": "Backup Reminder", + "remindLaterPrefix": "Remind me in", + "remindNever": "Never remind me", + "backupNow": "Back up now" + }, + "pkiRegenerate": { + "description": "Are you sure you want to regenerate key pair?", + "title": "Regenerate Key Pair" + }, + "qr": { + "addChannels": "Add Channels", + "replaceChannels": "Replace Channels", + "description": "The current LoRa configuration will also be shared.", + "sharableUrl": "Sharable URL", + "title": "Generate QR Code" + }, + "reboot": { + "title": "Reboot device", + "description": "Reboot now or schedule a reboot of the connected node. Optionally, you can choose to reboot into OTA (Over-the-Air) mode.", + "ota": "Reboot into OTA mode", + "enterDelay": "Enter delay", + "scheduled": "Reboot has been scheduled", + "schedule": "Schedule reboot", + "now": "Reboot now", + "cancel": "Cancel scheduled reboot" + }, + "refreshKeys": { + "description": { + "acceptNewKeys": "This will remove the node from device and request new keys.", + "keyMismatchReasonSuffix": ". This is due to the remote node's current public key does not match the previously stored key for this node.", + "unableToSendDmPrefix": "Your node is unable to send a direct message to node: " + }, + "acceptNewKeys": "Accept New Keys", + "title": "Keys Mismatch - {{identifier}}" + }, + "removeNode": { + "description": "Are you sure you want to remove this Node?", + "title": "Remove Node?" + }, + "shutdown": { + "title": "Schedule Shutdown", + "description": "Turn off the connected node after x minutes." + }, + "traceRoute": { + "routeToDestination": "Route to destination:", + "routeBack": "Route back:" + }, + "tracerouteResponse": { + "title": "Traceroute: {{identifier}}" + }, + "unsafeRoles": { + "confirmUnderstanding": "Yes, I know what I'm doing", + "conjunction": " and the blog post about ", + "postamble": " and understand the implications of changing the role.", + "preamble": "I have read the ", + "choosingRightDeviceRole": "Choosing The Right Device Role", + "deviceRoleDocumentation": "Device Role Documentation", + "title": "Weet u het zeker?" + }, + "managedMode": { + "confirmUnderstanding": "Yes, I know what I'm doing", + "title": "Weet u het zeker?", + "description": "Enabling Managed Mode blocks client applications (including the web client) from writing configurations to a radio. Once enabled, radio configurations can only be changed through Remote Admin messages. This setting is not required for remote node administration." + }, + "clientNotification": { + "title": "Client Notification", + "TraceRoute can only be sent once every 30 seconds": "TraceRoute can only be sent once every 30 seconds", + "Compromised keys were detected and regenerated.": "Compromised keys were detected and regenerated." + }, + "resetNodeDb": { + "title": "Reset Node Database", + "description": "This will clear all nodes from the connected device's node database and clear all message history in the client. This cannot be undone. Are you sure you want to continue?", + "confirm": "Reset Node Database", + "failedTitle": "There was an error resetting the Node DB. Please try again." + }, + "clearAllStores": { + "title": "Clear All Local Storage", + "description": "This will clear all locally stored data, including message history and node databases for all previously connected devices. This will require you to reconnect to your node once complete and cannot be undone. Are you sure you want to continue?", + "confirm": "Clear all local storage", + "failedTitle": "There was an error clearing local storage. Please try again." + }, + "factoryResetDevice": { + "title": "Factory Reset Device", + "description": "This will factory reset the connected device, erasing all configurations and data on the device as well as all nodes and messages saved in the client. This cannot be undone. Are you sure you want to continue?", + "confirm": "Factory Reset Device", + "failedTitle": "There was an error performing the factory reset. Please try again." + }, + "factoryResetConfig": { + "title": "Factory Reset Config", + "description": "This will factory reset the configuration on the connected device, erasing all configurations on the device. This cannot be undone. Are you sure you want to continue?", + "confirm": "Factory Reset Config", + "failedTitle": "There was an error performing the factory reset. Please try again." + } } diff --git a/packages/web/public/i18n/locales/nl-NL/map.json b/packages/web/public/i18n/locales/nl-NL/map.json new file mode 100644 index 000000000..786abaa45 --- /dev/null +++ b/packages/web/public/i18n/locales/nl-NL/map.json @@ -0,0 +1,38 @@ +{ + "maplibre": { + "GeolocateControl.FindMyLocation": "Find my location", + "NavigationControl.ZoomIn": "Zoom in", + "NavigationControl.ZoomOut": "Zoom out", + "CooperativeGesturesHandler.WindowsHelpText": "Use Ctrl + scroll to zoom the map", + "CooperativeGesturesHandler.MacHelpText": "Use ⌘ + scroll to zoom the map", + "CooperativeGesturesHandler.MobileHelpText": "Use two fingers to move the map" + }, + "layerTool": { + "nodeMarkers": "Show nodes", + "directNeighbors": "Show direct connections", + "remoteNeighbors": "Show remote connections", + "positionPrecision": "Show position precision", + "traceroutes": "Show traceroutes", + "waypoints": "Show waypoints" + }, + "mapMenu": { + "locateAria": "Locate my node", + "layersAria": "Change map style" + }, + "waypointDetail": { + "edit": "Wijzig", + "description": "Description:", + "createdBy": "Edited by:", + "createdDate": "Created:", + "updated": "Updated:", + "expires": "Expires:", + "distance": "Distance:", + "bearing": "Absolute bearing:", + "lockedTo": "Locked by:", + "latitude": "Latitude:", + "longitude": "Longitude:" + }, + "myNode": { + "tooltip": "This device" + } +} diff --git a/packages/web/public/i18n/locales/nl-NL/messages.json b/packages/web/public/i18n/locales/nl-NL/messages.json index 198a335ba..2572ee9ec 100644 --- a/packages/web/public/i18n/locales/nl-NL/messages.json +++ b/packages/web/public/i18n/locales/nl-NL/messages.json @@ -1,39 +1,39 @@ { - "page": { - "title": "Messages: {{chatName}}", - "placeholder": "Enter Message" - }, - "emptyState": { - "title": "Select a Chat", - "text": "No messages yet." - }, - "selectChatPrompt": { - "text": "Select a channel or node to start messaging." - }, - "sendMessage": { - "placeholder": "Enter your message here...", - "sendButton": "Verzend" - }, - "actionsMenu": { - "addReactionLabel": "Add Reaction", - "replyLabel": "Reply" - }, - "deliveryStatus": { - "delivered": { - "label": "Message delivered", - "displayText": "Message delivered" - }, - "failed": { - "label": "Message delivery failed", - "displayText": "Delivery failed" - }, - "unknown": { - "label": "Message status unknown", - "displayText": "Unknown state" - }, - "waiting": { - "label": "Sending message", - "displayText": "Waiting for delivery" - } - } + "page": { + "title": "Messages: {{chatName}}", + "placeholder": "Enter Message" + }, + "emptyState": { + "title": "Select a Chat", + "text": "No messages yet." + }, + "selectChatPrompt": { + "text": "Select a channel or node to start messaging." + }, + "sendMessage": { + "placeholder": "Enter your message here...", + "sendButton": "Verzend" + }, + "actionsMenu": { + "addReactionLabel": "Add Reaction", + "replyLabel": "Reply" + }, + "deliveryStatus": { + "delivered": { + "label": "Message delivered", + "displayText": "Message delivered" + }, + "failed": { + "label": "Message delivery failed", + "displayText": "Delivery failed" + }, + "unknown": { + "label": "Message status unknown", + "displayText": "Unknown state" + }, + "waiting": { + "label": "Sending message", + "displayText": "Waiting for delivery" + } + } } diff --git a/packages/web/public/i18n/locales/nl-NL/moduleConfig.json b/packages/web/public/i18n/locales/nl-NL/moduleConfig.json index 195863a02..d0e6a33f7 100644 --- a/packages/web/public/i18n/locales/nl-NL/moduleConfig.json +++ b/packages/web/public/i18n/locales/nl-NL/moduleConfig.json @@ -1,448 +1,448 @@ { - "page": { - "tabAmbientLighting": "Sfeerverlichting", - "tabAudio": "Geluid", - "tabCannedMessage": "Canned", - "tabDetectionSensor": "Detectie Sensor", - "tabExternalNotification": "Ext Notif", - "tabMqtt": "MQTT", - "tabNeighborInfo": "Neighbor Info", - "tabPaxcounter": "Paxcounter", - "tabRangeTest": "Bereik Test", - "tabSerial": "Serieel", - "tabStoreAndForward": "S&F", - "tabTelemetry": "Telemetrie" - }, - "ambientLighting": { - "title": "Ambient Lighting Settings", - "description": "Settings for the Ambient Lighting module", - "ledState": { - "label": "LED State", - "description": "Sets LED to on or off" - }, - "current": { - "label": "Huidige", - "description": "Sets the current for the LED output. Default is 10" - }, - "red": { - "label": "Rood", - "description": "Sets the red LED level. Values are 0-255" - }, - "green": { - "label": "Groen", - "description": "Sets the green LED level. Values are 0-255" - }, - "blue": { - "label": "Blauw", - "description": "Sets the blue LED level. Values are 0-255" - } - }, - "audio": { - "title": "Audio Settings", - "description": "Settings for the Audio module", - "codec2Enabled": { - "label": "Codec 2 Enabled", - "description": "Enable Codec 2 audio encoding" - }, - "pttPin": { - "label": "PTT Pin", - "description": "GPIO pin to use for PTT" - }, - "bitrate": { - "label": "Bitrate", - "description": "Bitrate to use for audio encoding" - }, - "i2sWs": { - "label": "i2S WS", - "description": "GPIO pin to use for i2S WS" - }, - "i2sSd": { - "label": "i2S SD", - "description": "GPIO pin to use for i2S SD" - }, - "i2sDin": { - "label": "i2S DIN", - "description": "GPIO pin to use for i2S DIN" - }, - "i2sSck": { - "label": "i2S SCK", - "description": "GPIO pin to use for i2S SCK" - } - }, - "cannedMessage": { - "title": "Canned Message Settings", - "description": "Settings for the Canned Message module", - "moduleEnabled": { - "label": "Module Enabled", - "description": "Enable Canned Message" - }, - "rotary1Enabled": { - "label": "Rotary Encoder #1 Enabled", - "description": "Enable the rotary encoder" - }, - "inputbrokerPinA": { - "label": "Encoder Pin A", - "description": "GPIO Pin Value (1-39) For encoder port A" - }, - "inputbrokerPinB": { - "label": "Encoder Pin B", - "description": "GPIO Pin Value (1-39) For encoder port B" - }, - "inputbrokerPinPress": { - "label": "Encoder Pin Press", - "description": "GPIO Pin Value (1-39) For encoder Press" - }, - "inputbrokerEventCw": { - "label": "Clockwise event", - "description": "Select input event." - }, - "inputbrokerEventCcw": { - "label": "Counter Clockwise event", - "description": "Select input event." - }, - "inputbrokerEventPress": { - "label": "Press event", - "description": "Select input event" - }, - "updown1Enabled": { - "label": "Up Down enabled", - "description": "Enable the up / down encoder" - }, - "allowInputSource": { - "label": "Allow Input Source", - "description": "Select from: '_any', 'rotEnc1', 'upDownEnc1', 'cardkb'" - }, - "sendBell": { - "label": "Send Bell", - "description": "Sends a bell character with each message" - } - }, - "detectionSensor": { - "title": "Detection Sensor Settings", - "description": "Settings for the Detection Sensor module", - "enabled": { - "label": "Enabled", - "description": "Enable or disable Detection Sensor Module" - }, - "minimumBroadcastSecs": { - "label": "Minimum Broadcast Seconds", - "description": "The interval in seconds of how often we can send a message to the mesh when a state change is detected" - }, - "stateBroadcastSecs": { - "label": "State Broadcast Seconds", - "description": "The interval in seconds of how often we should send a message to the mesh with the current state regardless of changes" - }, - "sendBell": { - "label": "Send Bell", - "description": "Send ASCII bell with alert message" - }, - "name": { - "label": "Friendly Name", - "description": "Used to format the message sent to mesh, max 20 Characters" - }, - "monitorPin": { - "label": "Monitor Pin", - "description": "The GPIO pin to monitor for state changes" - }, - "detectionTriggerType": { - "label": "Detection Triggered Type", - "description": "The type of trigger event to be used" - }, - "usePullup": { - "label": "Use Pullup", - "description": "Whether or not use INPUT_PULLUP mode for GPIO pin" - } - }, - "externalNotification": { - "title": "External Notification Settings", - "description": "Configure the external notification module", - "enabled": { - "label": "Module Enabled", - "description": "Enable External Notification" - }, - "outputMs": { - "label": "Output MS", - "description": "Output MS" - }, - "output": { - "label": "Output", - "description": "Output" - }, - "outputVibra": { - "label": "Output Vibrate", - "description": "Output Vibrate" - }, - "outputBuzzer": { - "label": "Output Buzzer", - "description": "Output Buzzer" - }, - "active": { - "label": "Active", - "description": "Active" - }, - "alertMessage": { - "label": "Alert Message", - "description": "Alert Message" - }, - "alertMessageVibra": { - "label": "Alert Message Vibrate", - "description": "Alert Message Vibrate" - }, - "alertMessageBuzzer": { - "label": "Alert Message Buzzer", - "description": "Alert Message Buzzer" - }, - "alertBell": { - "label": "Alert Bell", - "description": "Should an alert be triggered when receiving an incoming bell?" - }, - "alertBellVibra": { - "label": "Alert Bell Vibrate", - "description": "Alert Bell Vibrate" - }, - "alertBellBuzzer": { - "label": "Alert Bell Buzzer", - "description": "Alert Bell Buzzer" - }, - "usePwm": { - "label": "Use PWM", - "description": "Use PWM" - }, - "nagTimeout": { - "label": "Nag Timeout", - "description": "Nag Timeout" - }, - "useI2sAsBuzzer": { - "label": "Use I²S Pin as Buzzer", - "description": "Designate I²S Pin as Buzzer Output" - } - }, - "mqtt": { - "title": "MQTT Settings", - "description": "Settings for the MQTT module", - "enabled": { - "label": "Enabled", - "description": "Enable or disable MQTT" - }, - "address": { - "label": "MQTT Server Address", - "description": "MQTT server address to use for default/custom servers" - }, - "username": { - "label": "MQTT Username", - "description": "MQTT username to use for default/custom servers" - }, - "password": { - "label": "MQTT Password", - "description": "MQTT password to use for default/custom servers" - }, - "encryptionEnabled": { - "label": "Encryption Enabled", - "description": "Enable or disable MQTT encryption. Note: All messages are sent to the MQTT broker unencrypted if this option is not enabled, even when your uplink channels have encryption keys set. This includes position data." - }, - "jsonEnabled": { - "label": "JSON Enabled", - "description": "Whether to send/consume JSON packets on MQTT" - }, - "tlsEnabled": { - "label": "TLS Enabled", - "description": "Enable or disable TLS" - }, - "root": { - "label": "Root topic", - "description": "MQTT root topic to use for default/custom servers" - }, - "proxyToClientEnabled": { - "label": "MQTT Client Proxy Enabled", - "description": "Utilizes the network connection to proxy MQTT messages to the client." - }, - "mapReportingEnabled": { - "label": "Map Reporting Enabled", - "description": "Your node will periodically send an unencrypted map report packet to the configured MQTT server, this includes id, short and long name, approximate location, hardware model, role, firmware version, LoRa region, modem preset and primary channel name." - }, - "mapReportSettings": { - "publishIntervalSecs": { - "label": "Map Report Publish Interval (s)", - "description": "Interval in seconds to publish map reports" - }, - "positionPrecision": { - "label": "Approximate Location", - "description": "Position shared will be accurate within this distance", - "options": { - "metric_km23": "Within 23 km", - "metric_km12": "Within 12 km", - "metric_km5_8": "Within 5.8 km", - "metric_km2_9": "Within 2.9 km", - "metric_km1_5": "Within 1.5 km", - "metric_m700": "Within 700 m", - "metric_m350": "Within 350 m", - "metric_m200": "Within 200 m", - "metric_m90": "Within 90 m", - "metric_m50": "Within 50 m", - "imperial_mi15": "Within 15 miles", - "imperial_mi7_3": "Within 7.3 miles", - "imperial_mi3_6": "Within 3.6 miles", - "imperial_mi1_8": "Within 1.8 miles", - "imperial_mi0_9": "Within 0.9 miles", - "imperial_mi0_5": "Within 0.5 miles", - "imperial_mi0_2": "Within 0.2 miles", - "imperial_ft600": "Within 600 feet", - "imperial_ft300": "Within 300 feet", - "imperial_ft150": "Within 150 feet" - } - } - } - }, - "neighborInfo": { - "title": "Neighbor Info Settings", - "description": "Settings for the Neighbor Info module", - "enabled": { - "label": "Enabled", - "description": "Enable or disable Neighbor Info Module" - }, - "updateInterval": { - "label": "Update Interval", - "description": "Interval in seconds of how often we should try to send our Neighbor Info to the mesh" - } - }, - "paxcounter": { - "title": "Paxcounter Settings", - "description": "Settings for the Paxcounter module", - "enabled": { - "label": "Module Enabled", - "description": "Enable Paxcounter" - }, - "paxcounterUpdateInterval": { - "label": "Update Interval (seconds)", - "description": "How long to wait between sending paxcounter packets" - }, - "wifiThreshold": { - "label": "WiFi RSSI Threshold", - "description": "At what WiFi RSSI level should the counter increase. Defaults to -80." - }, - "bleThreshold": { - "label": "BLE RSSI Threshold", - "description": "At what BLE RSSI level should the counter increase. Defaults to -80." - } - }, - "rangeTest": { - "title": "Range Test Settings", - "description": "Settings for the Range Test module", - "enabled": { - "label": "Module Enabled", - "description": "Enable Range Test" - }, - "sender": { - "label": "Message Interval", - "description": "How long to wait between sending test packets" - }, - "save": { - "label": "Save CSV to storage", - "description": "ESP32 Only" - } - }, - "serial": { - "title": "Serial Settings", - "description": "Settings for the Serial module", - "enabled": { - "label": "Module Enabled", - "description": "Enable Serial output" - }, - "echo": { - "label": "Echo", - "description": "Any packets you send will be echoed back to your device" - }, - "rxd": { - "label": "Receive Pin", - "description": "Set the GPIO pin to the RXD pin you have set up." - }, - "txd": { - "label": "Transmit Pin", - "description": "Set the GPIO pin to the TXD pin you have set up." - }, - "baud": { - "label": "Baud Rate", - "description": "The serial baud rate" - }, - "timeout": { - "label": "Time-Out", - "description": "Seconds to wait before we consider your packet as 'done'" - }, - "mode": { - "label": "Mode", - "description": "Select Mode" - }, - "overrideConsoleSerialPort": { - "label": "Override Console Serial Port", - "description": "If you have a serial port connected to the console, this will override it." - } - }, - "storeForward": { - "title": "Store & Forward Settings", - "description": "Settings for the Store & Forward module", - "enabled": { - "label": "Module Enabled", - "description": "Enable Store & Forward" - }, - "heartbeat": { - "label": "Heartbeat Enabled", - "description": "Enable Store & Forward heartbeat" - }, - "records": { - "label": "Aantal records", - "description": "Number of records to store" - }, - "historyReturnMax": { - "label": "History return max", - "description": "Max number of records to return" - }, - "historyReturnWindow": { - "label": "History return window", - "description": "Max number of records to return" - } - }, - "telemetry": { - "title": "Telemetry Settings", - "description": "Settings for the Telemetry module", - "deviceUpdateInterval": { - "label": "Device Metrics", - "description": "Device metrics update interval (seconds)" - }, - "environmentUpdateInterval": { - "label": "Environment metrics update interval (seconds)", - "description": "" - }, - "environmentMeasurementEnabled": { - "label": "Module Enabled", - "description": "Enable the Environment Telemetry" - }, - "environmentScreenEnabled": { - "label": "Displayed on Screen", - "description": "Show the Telemetry Module on the OLED" - }, - "environmentDisplayFahrenheit": { - "label": "Display Fahrenheit", - "description": "Display temp in Fahrenheit" - }, - "airQualityEnabled": { - "label": "Air Quality Enabled", - "description": "Enable the Air Quality Telemetry" - }, - "airQualityInterval": { - "label": "Air Quality Update Interval", - "description": "How often to send Air Quality data over the mesh" - }, - "powerMeasurementEnabled": { - "label": "Power Measurement Enabled", - "description": "Enable the Power Measurement Telemetry" - }, - "powerUpdateInterval": { - "label": "Power Update Interval", - "description": "How often to send Power data over the mesh" - }, - "powerScreenEnabled": { - "label": "Power Screen Enabled", - "description": "Enable the Power Telemetry Screen" - } - } + "page": { + "tabAmbientLighting": "Sfeerverlichting", + "tabAudio": "Geluid", + "tabCannedMessage": "Canned", + "tabDetectionSensor": "Detectie Sensor", + "tabExternalNotification": "Ext Notif", + "tabMqtt": "MQTT", + "tabNeighborInfo": "Neighbor Info", + "tabPaxcounter": "Paxcounter", + "tabRangeTest": "Bereik Test", + "tabSerial": "Serieel", + "tabStoreAndForward": "S&F", + "tabTelemetry": "Telemetrie" + }, + "ambientLighting": { + "title": "Ambient Lighting Settings", + "description": "Settings for the Ambient Lighting module", + "ledState": { + "label": "LED State", + "description": "Sets LED to on or off" + }, + "current": { + "label": "Huidige", + "description": "Sets the current for the LED output. Default is 10" + }, + "red": { + "label": "Rood", + "description": "Sets the red LED level. Values are 0-255" + }, + "green": { + "label": "Groen", + "description": "Sets the green LED level. Values are 0-255" + }, + "blue": { + "label": "Blauw", + "description": "Sets the blue LED level. Values are 0-255" + } + }, + "audio": { + "title": "Audio Settings", + "description": "Settings for the Audio module", + "codec2Enabled": { + "label": "Codec 2 Enabled", + "description": "Enable Codec 2 audio encoding" + }, + "pttPin": { + "label": "PTT Pin", + "description": "GPIO pin to use for PTT" + }, + "bitrate": { + "label": "Bitrate", + "description": "Bitrate to use for audio encoding" + }, + "i2sWs": { + "label": "i2S WS", + "description": "GPIO pin to use for i2S WS" + }, + "i2sSd": { + "label": "i2S SD", + "description": "GPIO pin to use for i2S SD" + }, + "i2sDin": { + "label": "i2S DIN", + "description": "GPIO pin to use for i2S DIN" + }, + "i2sSck": { + "label": "i2S SCK", + "description": "GPIO pin to use for i2S SCK" + } + }, + "cannedMessage": { + "title": "Canned Message Settings", + "description": "Settings for the Canned Message module", + "moduleEnabled": { + "label": "Module Enabled", + "description": "Enable Canned Message" + }, + "rotary1Enabled": { + "label": "Rotary Encoder #1 Enabled", + "description": "Enable the rotary encoder" + }, + "inputbrokerPinA": { + "label": "Encoder Pin A", + "description": "GPIO Pin Value (1-39) For encoder port A" + }, + "inputbrokerPinB": { + "label": "Encoder Pin B", + "description": "GPIO Pin Value (1-39) For encoder port B" + }, + "inputbrokerPinPress": { + "label": "Encoder Pin Press", + "description": "GPIO Pin Value (1-39) For encoder Press" + }, + "inputbrokerEventCw": { + "label": "Clockwise event", + "description": "Select input event." + }, + "inputbrokerEventCcw": { + "label": "Counter Clockwise event", + "description": "Select input event." + }, + "inputbrokerEventPress": { + "label": "Press event", + "description": "Select input event" + }, + "updown1Enabled": { + "label": "Up Down enabled", + "description": "Enable the up / down encoder" + }, + "allowInputSource": { + "label": "Allow Input Source", + "description": "Select from: '_any', 'rotEnc1', 'upDownEnc1', 'cardkb'" + }, + "sendBell": { + "label": "Send Bell", + "description": "Sends a bell character with each message" + } + }, + "detectionSensor": { + "title": "Detection Sensor Settings", + "description": "Settings for the Detection Sensor module", + "enabled": { + "label": "Enabled", + "description": "Enable or disable Detection Sensor Module" + }, + "minimumBroadcastSecs": { + "label": "Minimum Broadcast Seconds", + "description": "The interval in seconds of how often we can send a message to the mesh when a state change is detected" + }, + "stateBroadcastSecs": { + "label": "State Broadcast Seconds", + "description": "The interval in seconds of how often we should send a message to the mesh with the current state regardless of changes" + }, + "sendBell": { + "label": "Send Bell", + "description": "Send ASCII bell with alert message" + }, + "name": { + "label": "Friendly Name", + "description": "Used to format the message sent to mesh, max 20 Characters" + }, + "monitorPin": { + "label": "Monitor Pin", + "description": "The GPIO pin to monitor for state changes" + }, + "detectionTriggerType": { + "label": "Detection Triggered Type", + "description": "The type of trigger event to be used" + }, + "usePullup": { + "label": "Use Pullup", + "description": "Whether or not use INPUT_PULLUP mode for GPIO pin" + } + }, + "externalNotification": { + "title": "External Notification Settings", + "description": "Configure the external notification module", + "enabled": { + "label": "Module Enabled", + "description": "Enable External Notification" + }, + "outputMs": { + "label": "Output MS", + "description": "Output MS" + }, + "output": { + "label": "Output", + "description": "Output" + }, + "outputVibra": { + "label": "Output Vibrate", + "description": "Output Vibrate" + }, + "outputBuzzer": { + "label": "Output Buzzer", + "description": "Output Buzzer" + }, + "active": { + "label": "Active", + "description": "Active" + }, + "alertMessage": { + "label": "Alert Message", + "description": "Alert Message" + }, + "alertMessageVibra": { + "label": "Alert Message Vibrate", + "description": "Alert Message Vibrate" + }, + "alertMessageBuzzer": { + "label": "Alert Message Buzzer", + "description": "Alert Message Buzzer" + }, + "alertBell": { + "label": "Alert Bell", + "description": "Should an alert be triggered when receiving an incoming bell?" + }, + "alertBellVibra": { + "label": "Alert Bell Vibrate", + "description": "Alert Bell Vibrate" + }, + "alertBellBuzzer": { + "label": "Alert Bell Buzzer", + "description": "Alert Bell Buzzer" + }, + "usePwm": { + "label": "Use PWM", + "description": "Use PWM" + }, + "nagTimeout": { + "label": "Nag Timeout", + "description": "Nag Timeout" + }, + "useI2sAsBuzzer": { + "label": "Use I²S Pin as Buzzer", + "description": "Designate I²S Pin as Buzzer Output" + } + }, + "mqtt": { + "title": "MQTT Settings", + "description": "Settings for the MQTT module", + "enabled": { + "label": "Enabled", + "description": "Enable or disable MQTT" + }, + "address": { + "label": "MQTT Server Address", + "description": "MQTT server address to use for default/custom servers" + }, + "username": { + "label": "MQTT Username", + "description": "MQTT username to use for default/custom servers" + }, + "password": { + "label": "MQTT Password", + "description": "MQTT password to use for default/custom servers" + }, + "encryptionEnabled": { + "label": "Encryption Enabled", + "description": "Enable or disable MQTT encryption. Note: All messages are sent to the MQTT broker unencrypted if this option is not enabled, even when your uplink channels have encryption keys set. This includes position data." + }, + "jsonEnabled": { + "label": "JSON Enabled", + "description": "Whether to send/consume JSON packets on MQTT" + }, + "tlsEnabled": { + "label": "TLS Enabled", + "description": "Enable or disable TLS" + }, + "root": { + "label": "Root topic", + "description": "MQTT root topic to use for default/custom servers" + }, + "proxyToClientEnabled": { + "label": "MQTT Client Proxy Enabled", + "description": "Utilizes the network connection to proxy MQTT messages to the client." + }, + "mapReportingEnabled": { + "label": "Map Reporting Enabled", + "description": "Your node will periodically send an unencrypted map report packet to the configured MQTT server, this includes id, short and long name, approximate location, hardware model, role, firmware version, LoRa region, modem preset and primary channel name." + }, + "mapReportSettings": { + "publishIntervalSecs": { + "label": "Map Report Publish Interval (s)", + "description": "Interval in seconds to publish map reports" + }, + "positionPrecision": { + "label": "Approximate Location", + "description": "Position shared will be accurate within this distance", + "options": { + "metric_km23": "Within 23 km", + "metric_km12": "Within 12 km", + "metric_km5_8": "Within 5.8 km", + "metric_km2_9": "Within 2.9 km", + "metric_km1_5": "Within 1.5 km", + "metric_m700": "Within 700 m", + "metric_m350": "Within 350 m", + "metric_m200": "Within 200 m", + "metric_m90": "Within 90 m", + "metric_m50": "Within 50 m", + "imperial_mi15": "Within 15 miles", + "imperial_mi7_3": "Within 7.3 miles", + "imperial_mi3_6": "Within 3.6 miles", + "imperial_mi1_8": "Within 1.8 miles", + "imperial_mi0_9": "Within 0.9 miles", + "imperial_mi0_5": "Within 0.5 miles", + "imperial_mi0_2": "Within 0.2 miles", + "imperial_ft600": "Within 600 feet", + "imperial_ft300": "Within 300 feet", + "imperial_ft150": "Within 150 feet" + } + } + } + }, + "neighborInfo": { + "title": "Neighbor Info Settings", + "description": "Settings for the Neighbor Info module", + "enabled": { + "label": "Enabled", + "description": "Enable or disable Neighbor Info Module" + }, + "updateInterval": { + "label": "Update Interval", + "description": "Interval in seconds of how often we should try to send our Neighbor Info to the mesh" + } + }, + "paxcounter": { + "title": "Paxcounter Settings", + "description": "Settings for the Paxcounter module", + "enabled": { + "label": "Module Enabled", + "description": "Enable Paxcounter" + }, + "paxcounterUpdateInterval": { + "label": "Update Interval (seconds)", + "description": "How long to wait between sending paxcounter packets" + }, + "wifiThreshold": { + "label": "WiFi RSSI Threshold", + "description": "At what WiFi RSSI level should the counter increase. Defaults to -80." + }, + "bleThreshold": { + "label": "BLE RSSI Threshold", + "description": "At what BLE RSSI level should the counter increase. Defaults to -80." + } + }, + "rangeTest": { + "title": "Range Test Settings", + "description": "Settings for the Range Test module", + "enabled": { + "label": "Module Enabled", + "description": "Enable Range Test" + }, + "sender": { + "label": "Message Interval", + "description": "How long to wait between sending test packets" + }, + "save": { + "label": "Save CSV to storage", + "description": "ESP32 Only" + } + }, + "serial": { + "title": "Serial Settings", + "description": "Settings for the Serial module", + "enabled": { + "label": "Module Enabled", + "description": "Enable Serial output" + }, + "echo": { + "label": "Echo", + "description": "Any packets you send will be echoed back to your device" + }, + "rxd": { + "label": "Receive Pin", + "description": "Set the GPIO pin to the RXD pin you have set up." + }, + "txd": { + "label": "Transmit Pin", + "description": "Set the GPIO pin to the TXD pin you have set up." + }, + "baud": { + "label": "Baud Rate", + "description": "The serial baud rate" + }, + "timeout": { + "label": "Time-Out", + "description": "Seconds to wait before we consider your packet as 'done'" + }, + "mode": { + "label": "Mode", + "description": "Select Mode" + }, + "overrideConsoleSerialPort": { + "label": "Override Console Serial Port", + "description": "If you have a serial port connected to the console, this will override it." + } + }, + "storeForward": { + "title": "Store & Forward Settings", + "description": "Settings for the Store & Forward module", + "enabled": { + "label": "Module Enabled", + "description": "Enable Store & Forward" + }, + "heartbeat": { + "label": "Heartbeat Enabled", + "description": "Enable Store & Forward heartbeat" + }, + "records": { + "label": "Aantal records", + "description": "Number of records to store" + }, + "historyReturnMax": { + "label": "History return max", + "description": "Max number of records to return" + }, + "historyReturnWindow": { + "label": "History return window", + "description": "Retourneer records uit dit tijdvenster (minuten)" + } + }, + "telemetry": { + "title": "Telemetry Settings", + "description": "Settings for the Telemetry module", + "deviceUpdateInterval": { + "label": "Device Metrics", + "description": "Device metrics update interval (seconds)" + }, + "environmentUpdateInterval": { + "label": "Environment metrics update interval (seconds)", + "description": "" + }, + "environmentMeasurementEnabled": { + "label": "Module Enabled", + "description": "Enable the Environment Telemetry" + }, + "environmentScreenEnabled": { + "label": "Displayed on Screen", + "description": "Show the Telemetry Module on the OLED" + }, + "environmentDisplayFahrenheit": { + "label": "Display Fahrenheit", + "description": "Display temp in Fahrenheit" + }, + "airQualityEnabled": { + "label": "Air Quality Enabled", + "description": "Enable the Air Quality Telemetry" + }, + "airQualityInterval": { + "label": "Air Quality Update Interval", + "description": "How often to send Air Quality data over the mesh" + }, + "powerMeasurementEnabled": { + "label": "Power Measurement Enabled", + "description": "Enable the Power Measurement Telemetry" + }, + "powerUpdateInterval": { + "label": "Power Update Interval", + "description": "How often to send Power data over the mesh" + }, + "powerScreenEnabled": { + "label": "Power Screen Enabled", + "description": "Enable the Power Telemetry Screen" + } + } } diff --git a/packages/web/public/i18n/locales/nl-NL/nodes.json b/packages/web/public/i18n/locales/nl-NL/nodes.json index 38d882ea4..0dd89317a 100644 --- a/packages/web/public/i18n/locales/nl-NL/nodes.json +++ b/packages/web/public/i18n/locales/nl-NL/nodes.json @@ -1,63 +1,59 @@ { - "nodeDetail": { - "publicKeyEnabled": { - "label": "Public Key Enabled" - }, - "noPublicKey": { - "label": "No Public Key" - }, - "directMessage": { - "label": "Direct Message {{shortName}}" - }, - "favorite": { - "label": "Favoriet", - "tooltip": "Add or remove this node from your favorites" - }, - "notFavorite": { - "label": "Not a Favorite" - }, - "error": { - "label": "Foutmelding", - "text": "An error occurred while fetching node details. Please try again later." - }, - "status": { - "heard": "Heard", - "mqtt": "MQTT" - }, - "elevation": { - "label": "Elevation" - }, - "channelUtil": { - "label": "Channel Util" - }, - "airtimeUtil": { - "label": "Airtime Util" - } - }, - "nodesTable": { - "headings": { - "longName": "Long Name", - "connection": "Connection", - "lastHeard": "Last Heard", - "encryption": "Encryption", - "model": "Model", - "macAddress": "MAC Address" - }, - "connectionStatus": { - "direct": "Direct", - "away": "away", - "unknown": "-", - "viaMqtt": ", via MQTT" - }, - "lastHeardStatus": { - "never": "Never" - } - }, - "actions": { - "added": "Added", - "removed": "Removed", - "ignoreNode": "Ignore Node", - "unignoreNode": "Unignore Node", - "requestPosition": "Request Position" - } + "nodeDetail": { + "publicKeyEnabled": { + "label": "Public Key Enabled" + }, + "noPublicKey": { + "label": "No Public Key" + }, + "directMessage": { + "label": "Direct Message {{shortName}}" + }, + "favorite": { + "label": "Favoriet", + "tooltip": "Add or remove this node from your favorites" + }, + "notFavorite": { + "label": "Not a Favorite" + }, + "error": { + "label": "Foutmelding", + "text": "An error occurred while fetching node details. Please try again later." + }, + "status": { + "heard": "Heard", + "mqtt": "MQTT" + }, + "elevation": { + "label": "Elevation" + }, + "channelUtil": { + "label": "Channel Util" + }, + "airtimeUtil": { + "label": "Airtime Util" + } + }, + "nodesTable": { + "headings": { + "longName": "Long Name", + "connection": "Connection", + "lastHeard": "Last Heard", + "encryption": "Encryption", + "model": "Model", + "macAddress": "MAC Address" + }, + "connectionStatus": { + "direct": "Direct", + "away": "away", + "viaMqtt": ", via MQTT" + } + }, + "actions": { + "added": "Added", + "removed": "Removed", + "ignoreNode": "Ignore Node", + "unignoreNode": "Unignore Node", + "requestPosition": "Request Position" + } } diff --git a/packages/web/public/i18n/locales/nl-NL/ui.json b/packages/web/public/i18n/locales/nl-NL/ui.json index 6b33c8dfb..ca37de0a6 100644 --- a/packages/web/public/i18n/locales/nl-NL/ui.json +++ b/packages/web/public/i18n/locales/nl-NL/ui.json @@ -1,228 +1,230 @@ { - "navigation": { - "title": "Navigation", - "messages": "Berichten", - "map": "Kaart", - "config": "Config", - "radioConfig": "Radio Config", - "moduleConfig": "Module Config", - "channels": "Kanalen", - "nodes": "Nodes" - }, - "app": { - "title": "Meshtastic", - "logo": "Meshtastic Logo" - }, - "sidebar": { - "collapseToggle": { - "button": { - "open": "Open sidebar", - "close": "Close sidebar" - } - }, - "deviceInfo": { - "volts": "{{voltage}} volts", - "firmware": { - "title": "Firmware", - "version": "v{{version}}", - "buildDate": "Build date: {{date}}" - }, - "deviceName": { - "title": "Device Name", - "changeName": "Change Device Name", - "placeholder": "Enter device name" - }, - "editDeviceName": "Edit device name" - } - }, - "batteryStatus": { - "charging": "{{level}}% charging", - "pluggedIn": "Plugged in", - "title": "Batterij" - }, - "search": { - "nodes": "Search nodes...", - "channels": "Search channels...", - "commandPalette": "Search commands..." - }, - "toast": { - "positionRequestSent": { - "title": "Position request sent." - }, - "requestingPosition": { - "title": "Requesting position, please wait..." - }, - "sendingTraceroute": { - "title": "Sending Traceroute, please wait..." - }, - "tracerouteSent": { - "title": "Traceroute sent." - }, - "savedChannel": { - "title": "Saved Channel: {{channelName}}" - }, - "messages": { - "pkiEncryption": { - "title": "Chat is using PKI encryption." - }, - "pskEncryption": { - "title": "Chat is using PSK encryption." - } - }, - "configSaveError": { - "title": "Error Saving Config", - "description": "An error occurred while saving the configuration." - }, - "validationError": { - "title": "Config Errors Exist", - "description": "Please fix the configuration errors before saving." - }, - "saveSuccess": { - "title": "Saving Config", - "description": "The configuration change {{case}} has been saved." - }, - "favoriteNode": { - "title": "{{action}} {{nodeName}} {{direction}} favorites.", - "action": { - "added": "Added", - "removed": "Removed", - "to": "to", - "from": "from" - } - }, - "ignoreNode": { - "title": "{{action}} {{nodeName}} {{direction}} ignore list", - "action": { - "added": "Added", - "removed": "Removed", - "to": "to", - "from": "from" - } - } - }, - "notifications": { - "copied": { - "label": "Copied!" - }, - "copyToClipboard": { - "label": "Copy to clipboard" - }, - "hidePassword": { - "label": "Wachtwoord verbergen" - }, - "showPassword": { - "label": "Wachtwoord tonen" - }, - "deliveryStatus": { - "delivered": "Delivered", - "failed": "Delivery Failed", - "waiting": "Waiting", - "unknown": "Unknown" - } - }, - "general": { - "label": "General" - }, - "hardware": { - "label": "Hardware" - }, - "metrics": { - "label": "Metrics" - }, - "role": { - "label": "Functie" - }, - "filter": { - "label": "Filter" - }, - "advanced": { - "label": "Advanced" - }, - "clearInput": { - "label": "Clear input" - }, - "resetFilters": { - "label": "Reset Filters" - }, - "nodeName": { - "label": "Node name/number", - "placeholder": "Meshtastic 1234" - }, - "airtimeUtilization": { - "label": "Airtime Utilization (%)" - }, - "batteryLevel": { - "label": "Battery level (%)", - "labelText": "Battery level (%): {{value}}" - }, - "batteryVoltage": { - "label": "Battery voltage (V)", - "title": "Spanning" - }, - "channelUtilization": { - "label": "Channel Utilization (%)" - }, - "hops": { - "direct": "Direct", - "label": "Number of hops", - "text": "Number of hops: {{value}}" - }, - "lastHeard": { - "label": "Laatst gehoord", - "labelText": "Last heard: {{value}}", - "nowLabel": "Now" - }, - "snr": { - "label": "SNR (db)" - }, - "favorites": { - "label": "Favorites" - }, - "hide": { - "label": "Hide" - }, - "showOnly": { - "label": "Show Only" - }, - "viaMqtt": { - "label": "Connected via MQTT" - }, - "hopsUnknown": { - "label": "Unknown number of hops" - }, - "showUnheard": { - "label": "Never heard" - }, - "language": { - "label": "Taal", - "changeLanguage": "Change Language" - }, - "theme": { - "dark": "Donker", - "light": "Licht", - "system": "Automatic", - "changeTheme": "Change Color Scheme" - }, - "errorPage": { - "title": "This is a little embarrassing...", - "description1": "We are really sorry but an error occurred in the web client that caused it to crash.
This is not supposed to happen, and we are working hard to fix it.", - "description2": "The best way to prevent this from happening again to you or anyone else is to report the issue to us.", - "reportInstructions": "Please include the following information in your report:", - "reportSteps": { - "step1": "What you were doing when the error occurred", - "step2": "What you expected to happen", - "step3": "What actually happened", - "step4": "Any other relevant information" - }, - "reportLink": "You can report the issue to our <0>GitHub", - "dashboardLink": "Return to the <0>dashboard", - "detailsSummary": "Error Details", - "errorMessageLabel": "Error message:", - "stackTraceLabel": "Stack trace:", - "fallbackError": "{{error}}" - }, - "footer": { - "text": "Powered by <0>▲ Vercel | Meshtastic® is a registered trademark of Meshtastic LLC. | <1>Legal Information", - "commitSha": "Commit SHA: {{sha}}" - } + "navigation": { + "title": "Navigation", + "messages": "Berichten", + "map": "Kaart", + "settings": "Instellingen", + "channels": "Kanalen", + "radioConfig": "Radio Config", + "deviceConfig": "Apparaat Configuratie", + "moduleConfig": "Module Config", + "manageConnections": "Manage Connections", + "nodes": "Nodes" + }, + "app": { + "title": "Meshtastic", + "logo": "Meshtastic Logo" + }, + "sidebar": { + "collapseToggle": { + "button": { + "open": "Open sidebar", + "close": "Close sidebar" + } + }, + "deviceInfo": { + "volts": "{{voltage}} volts", + "firmware": { + "title": "Firmware", + "version": "v{{version}}", + "buildDate": "Build date: {{date}}" + } + } + }, + "batteryStatus": { + "charging": "{{level}}% charging", + "pluggedIn": "Plugged in", + "title": "Batterij" + }, + "search": { + "nodes": "Search nodes...", + "channels": "Search channels...", + "commandPalette": "Search commands..." + }, + "toast": { + "positionRequestSent": { + "title": "Position request sent." + }, + "requestingPosition": { + "title": "Requesting position, please wait..." + }, + "sendingTraceroute": { + "title": "Sending Traceroute, please wait..." + }, + "tracerouteSent": { + "title": "Traceroute sent." + }, + "savedChannel": { + "title": "Saved Channel: {{channelName}}" + }, + "messages": { + "pkiEncryption": { + "title": "Chat is using PKI encryption." + }, + "pskEncryption": { + "title": "Chat is using PSK encryption." + } + }, + "configSaveError": { + "title": "Error Saving Config", + "description": "An error occurred while saving the configuration." + }, + "validationError": { + "title": "Config Errors Exist", + "description": "Please fix the configuration errors before saving." + }, + "saveSuccess": { + "title": "Saving Config", + "description": "The configuration change {{case}} has been saved." + }, + "saveAllSuccess": { + "title": "Saved", + "description": "All configuration changes have been saved." + }, + "favoriteNode": { + "title": "{{action}} {{nodeName}} {{direction}} favorites.", + "action": { + "added": "Added", + "removed": "Removed", + "to": "to", + "from": "from" + } + }, + "ignoreNode": { + "title": "{{action}} {{nodeName}} {{direction}} ignore list", + "action": { + "added": "Added", + "removed": "Removed", + "to": "to", + "from": "from" + } + } + }, + "notifications": { + "copied": { + "label": "Copied!" + }, + "copyToClipboard": { + "label": "Copy to clipboard" + }, + "hidePassword": { + "label": "Wachtwoord verbergen" + }, + "showPassword": { + "label": "Wachtwoord tonen" + }, + "deliveryStatus": { + "delivered": "Delivered", + "failed": "Delivery Failed", + "waiting": "Waiting", + "unknown": "Unknown" + } + }, + "general": { + "label": "General" + }, + "hardware": { + "label": "Hardware" + }, + "metrics": { + "label": "Metrics" + }, + "role": { + "label": "Functie" + }, + "filter": { + "label": "Filter" + }, + "advanced": { + "label": "Advanced" + }, + "clearInput": { + "label": "Clear input" + }, + "resetFilters": { + "label": "Reset Filters" + }, + "nodeName": { + "label": "Node name/number", + "placeholder": "Meshtastic 1234" + }, + "airtimeUtilization": { + "label": "Airtime Utilization (%)", + "short": "Airtime Util. (%)" + }, + "batteryLevel": { + "label": "Battery level (%)", + "labelText": "Battery level (%): {{value}}" + }, + "batteryVoltage": { + "label": "Battery voltage (V)", + "title": "Spanning" + }, + "channelUtilization": { + "label": "Channel Utilization (%)", + "short": "Channel Util. (%)" + }, + "hops": { + "direct": "Direct", + "label": "Number of hops", + "text": "Number of hops: {{value}}" + }, + "lastHeard": { + "label": "Laatst gehoord", + "labelText": "Last heard: {{value}}", + "nowLabel": "Now" + }, + "snr": { + "label": "SNR (db)" + }, + "favorites": { + "label": "Favorites" + }, + "hide": { + "label": "Hide" + }, + "showOnly": { + "label": "Show Only" + }, + "viaMqtt": { + "label": "Connected via MQTT" + }, + "hopsUnknown": { + "label": "Unknown number of hops" + }, + "showUnheard": { + "label": "Never heard" + }, + "language": { + "label": "Taal", + "changeLanguage": "Change Language" + }, + "theme": { + "dark": "Donker", + "light": "Licht", + "system": "Automatic", + "changeTheme": "Change Color Scheme" + }, + "errorPage": { + "title": "This is a little embarrassing...", + "description1": "We are really sorry but an error occurred in the web client that caused it to crash.
This is not supposed to happen, and we are working hard to fix it.", + "description2": "The best way to prevent this from happening again to you or anyone else is to report the issue to us.", + "reportInstructions": "Please include the following information in your report:", + "reportSteps": { + "step1": "What you were doing when the error occurred", + "step2": "What you expected to happen", + "step3": "What actually happened", + "step4": "Any other relevant information" + }, + "reportLink": "You can report the issue to our <0>GitHub", + "connectionsLink": "Return to the <0>connections", + "detailsSummary": "Error Details", + "errorMessageLabel": "Error message:", + "stackTraceLabel": "Stack trace:", + "fallbackError": "{{error}}" + }, + "footer": { + "text": "Powered by <0>▲ Vercel | Meshtastic® is a registered trademark of Meshtastic LLC. | <1>Legal Information", + "commitSha": "Commit SHA: {{sha}}" + } } diff --git a/packages/web/public/i18n/locales/pl-PL/channels.json b/packages/web/public/i18n/locales/pl-PL/channels.json index 5710e5dde..7dbdc06ac 100644 --- a/packages/web/public/i18n/locales/pl-PL/channels.json +++ b/packages/web/public/i18n/locales/pl-PL/channels.json @@ -1,69 +1,71 @@ { - "page": { - "sectionLabel": "Kanały", - "channelName": "Kanał: {{channelName}}", - "broadcastLabel": "Podstawowy", - "channelIndex": "Kan. {{index}}" - }, - "validation": { - "pskInvalid": "Musisz wprowadzić prawidłowy {{bits}} bitowy klucz." - }, - "settings": { - "label": "Ustawienia kanału", - "description": "Kryptografia, MQTT i inne ustawienia" - }, - "role": { - "label": "Rola", - "description": "Telemetria urządzenia jest tylko wysyłania przez GŁOWNY. Tylko jeden GŁOWNY jest dozwolony", - "options": { - "primary": "GŁOWNY", - "disabled": "WYŁĄCZONY", - "secondary": "DODATKOWY" - } - }, - "psk": { - "label": "Klucz współdzielony", - "description": "Wspierane długości klucza: 256, 128, 8, pusty (0) bitów", - "generate": "Wygeneruj" - }, - "name": { - "label": "Nazwa", - "description": "Unikalna nazwa kanału mniejsza niż 12 bajtów, pusty jako domyślny" - }, - "uplinkEnabled": { - "label": "Wysył włączony", - "description": "Wysyłaj wiadomości z lokalnej sieci do MQTT" - }, - "downlinkEnabled": { - "label": "Odbiór włączony", - "description": "Wysyłaj wiadomości z MQTT to lokalnej sieci" - }, - "positionPrecision": { - "label": "Lokalizacja", - "description": "Precyzja lokalizacji, która jest wysyłana na kanale. Może zostać wyłączona.", - "options": { - "none": "Nie udostępniaj lokalizacji", - "precise": "Precyzyjna lokalizacja", - "metric_km23": "W zasięgu 23 kilometrów", - "metric_km12": "W zasięgu 12 kilometrów", - "metric_km5_8": "W zasięgu 5,8 kilometrów", - "metric_km2_9": "W zasięgu 2,9 kilometrów", - "metric_km1_5": "W zasięgu 1,5 kilometra", - "metric_m700": "W zasięgu 700 metrów", - "metric_m350": "W zasięgu 350 metrów", - "metric_m200": "W zasięgu 200 metrów", - "metric_m90": "W zasięgu 90 metrów", - "metric_m50": "W zasięgu 50 metrów", - "imperial_mi15": "W zasięgu 15 mil", - "imperial_mi7_3": "W zasięgu 7,3 mil", - "imperial_mi3_6": "W zasięgu 3,6 mil", - "imperial_mi1_8": "W zasięgu 1,8 mil", - "imperial_mi0_9": "W zasięgu 0,9 mil", - "imperial_mi0_5": "W zasięgu 0,5 mili", - "imperial_mi0_2": "W zasięgu 0,2 mil", - "imperial_ft600": "W zasięgu 600 stóp", - "imperial_ft300": "W zasięgu 300 stóp", - "imperial_ft150": "W zasięgu 150 stóp" - } - } + "page": { + "sectionLabel": "Kanały", + "channelName": "Kanał: {{channelName}}", + "broadcastLabel": "Podstawowy", + "channelIndex": "Kan. {{index}}", + "import": "Import", + "export": "Eksport" + }, + "validation": { + "pskInvalid": "Musisz wprowadzić prawidłowy {{bits}} bitowy klucz." + }, + "settings": { + "label": "Ustawienia kanału", + "description": "Kryptografia, MQTT i inne ustawienia" + }, + "role": { + "label": "Rola", + "description": "Telemetria urządzenia jest tylko wysyłania przez GŁOWNY. Tylko jeden GŁOWNY jest dozwolony", + "options": { + "primary": "GŁOWNY", + "disabled": "WYŁĄCZONY", + "secondary": "DODATKOWY" + } + }, + "psk": { + "label": "Klucz współdzielony", + "description": "Wspierane długości klucza: 256, 128, 8, pusty (0) bitów", + "generate": "Wygeneruj" + }, + "name": { + "label": "Nazwa", + "description": "Unikalna nazwa kanału mniejsza niż 12 bajtów, pusty jako domyślny" + }, + "uplinkEnabled": { + "label": "Wysył włączony", + "description": "Wysyłaj wiadomości z lokalnej sieci do MQTT" + }, + "downlinkEnabled": { + "label": "Odbiór włączony", + "description": "Wysyłaj wiadomości z MQTT to lokalnej sieci" + }, + "positionPrecision": { + "label": "Lokalizacja", + "description": "Precyzja lokalizacji, która jest wysyłana na kanale. Może zostać wyłączona.", + "options": { + "none": "Nie udostępniaj lokalizacji", + "precise": "Precyzyjna lokalizacja", + "metric_km23": "W zasięgu 23 kilometrów", + "metric_km12": "W zasięgu 12 kilometrów", + "metric_km5_8": "W zasięgu 5,8 kilometrów", + "metric_km2_9": "W zasięgu 2,9 kilometrów", + "metric_km1_5": "W zasięgu 1,5 kilometra", + "metric_m700": "W zasięgu 700 metrów", + "metric_m350": "W zasięgu 350 metrów", + "metric_m200": "W zasięgu 200 metrów", + "metric_m90": "W zasięgu 90 metrów", + "metric_m50": "W zasięgu 50 metrów", + "imperial_mi15": "W zasięgu 15 mil", + "imperial_mi7_3": "W zasięgu 7,3 mil", + "imperial_mi3_6": "W zasięgu 3,6 mil", + "imperial_mi1_8": "W zasięgu 1,8 mil", + "imperial_mi0_9": "W zasięgu 0,9 mil", + "imperial_mi0_5": "W zasięgu 0,5 mili", + "imperial_mi0_2": "W zasięgu 0,2 mil", + "imperial_ft600": "W zasięgu 600 stóp", + "imperial_ft300": "W zasięgu 300 stóp", + "imperial_ft150": "W zasięgu 150 stóp" + } + } } diff --git a/packages/web/public/i18n/locales/pl-PL/commandPalette.json b/packages/web/public/i18n/locales/pl-PL/commandPalette.json index 018f88a6a..3719cba73 100644 --- a/packages/web/public/i18n/locales/pl-PL/commandPalette.json +++ b/packages/web/public/i18n/locales/pl-PL/commandPalette.json @@ -15,7 +15,6 @@ "messages": "Wiadomości", "map": "Mapa", "config": "Config", - "channels": "Kanały", "nodes": "Nodes" } }, @@ -45,7 +44,8 @@ "label": "Debug", "command": { "reconfigure": "Reconfigure", - "clearAllStoredMessages": "Clear All Stored Message" + "clearAllStoredMessages": "Clear All Stored Message", + "clearAllStores": "Clear All Local Storage" } } } diff --git a/packages/web/public/i18n/locales/pl-PL/common.json b/packages/web/public/i18n/locales/pl-PL/common.json index fc1709d81..a22c160d0 100644 --- a/packages/web/public/i18n/locales/pl-PL/common.json +++ b/packages/web/public/i18n/locales/pl-PL/common.json @@ -1,142 +1,165 @@ { - "button": { - "apply": "Zastosuj", - "backupKey": "Backup Key", - "cancel": "Anuluj", - "clearMessages": "Clear Messages", - "close": "Zamknij", - "confirm": "Confirm", - "delete": "Usuń", - "dismiss": "Zamknij", - "download": "Download", - "export": "Export", - "generate": "Wygeneruj", - "regenerate": "Regenerate", - "import": "Import", - "message": "Wiadomość", - "now": "Now", - "ok": "OK", - "print": "Print", - "remove": "Usuń", - "requestNewKeys": "Request New Keys", - "requestPosition": "Poproś o pozycję", - "reset": "Zresetuj", - "save": "Zapisz", - "scanQr": "Scan QR Code", - "traceRoute": "Trace Route", - "submit": "Submit" - }, - "app": { - "title": "Meshtastic", - "fullTitle": "Meshtastic Web Client" - }, - "loading": "Loading...", - "unit": { - "cps": "CPS", - "dbm": "dBm", - "hertz": "Hz", - "hop": { - "one": "Hop", - "plural": "Hops" - }, - "hopsAway": { - "one": "{{count}} hop away", - "plural": "{{count}} hops away", - "unknown": "Unknown hops away" - }, - "megahertz": "MHz", - "raw": "raw", - "meter": { - "one": "Meter", - "plural": "Meters", - "suffix": "m" - }, - "minute": { - "one": "Minute", - "plural": "Minutes" - }, - "hour": { - "one": "Hour", - "plural": "Hours" - }, - "millisecond": { - "one": "Millisecond", - "plural": "Milliseconds", - "suffix": "ms" - }, - "second": { - "one": "Second", - "plural": "Seconds" - }, - "day": { - "one": "Day", - "plural": "Days" - }, - "month": { - "one": "Month", - "plural": "Months" - }, - "year": { - "one": "Year", - "plural": "Years" - }, - "snr": "SNR:", - "volt": { - "one": "Volt", - "plural": "Volts", - "suffix": "V" - }, - "record": { - "one": "Rekordy", - "plural": "Rekordy" - } - }, - "security": { - "0bit": "Pusty", - "8bit": "8-bitowy", - "128bit": "128-bitowy", - "256bit": "256-bitowy" - }, - "unknown": { - "longName": "Nieznany", - "shortName": "UNK", - "notAvailable": "N/A", - "num": "??" - }, - "nodeUnknownPrefix": "!", - "unset": "UNSET", - "fallbackName": "Meshtastic {{last4}}", - "node": "Węzeł", - "formValidation": { - "unsavedChanges": "Niezapisane zmiany", - "tooBig": { - "string": "Too long, expected less than or equal to {{maximum}} characters.", - "number": "Too big, expected a number smaller than or equal to {{maximum}}.", - "bytes": "Too big, expected less than or equal to {{params.maximum}} bytes." - }, - "tooSmall": { - "string": "Too short, expected more than or equal to {{minimum}} characters.", - "number": "Too small, expected a number larger than or equal to {{minimum}}." - }, - "invalidFormat": { - "ipv4": "Nieprawidłowy format, oczekiwany adres IPv4.", - "key": "Invalid format, expected a Base64 encoded pre-shared key (PSK)." - }, - "invalidType": { - "number": "Nieprawidłowy typ, oczekiwana liczba." - }, - "pskLength": { - "0bit": "Klucz musi być pusty.", - "8bit": "Key is required to be an 8 bit pre-shared key (PSK).", - "128bit": "Key is required to be a 128 bit pre-shared key (PSK).", - "256bit": "Key is required to be a 256 bit pre-shared key (PSK)." - }, - "required": { - "generic": "To pole jest wymagane.", - "managed": "Co najmniej jeden klucz administratora jest wymagany, jeśli węzeł jest zarządzany.", - "key": "Klucz jest wymagany." - } - }, - "yes": "Yes", - "no": "No" + "button": { + "apply": "Zastosuj", + "addConnection": "Add Connection", + "saveConnection": "Save connection", + "backupKey": "Backup Key", + "cancel": "Anuluj", + "connect": "Połącz", + "clearMessages": "Clear Messages", + "close": "Zamknij", + "confirm": "Confirm", + "delete": "Usuń", + "dismiss": "Zamknij", + "download": "Download", + "disconnect": "Rozłącz", + "export": "Export", + "generate": "Wygeneruj", + "regenerate": "Regenerate", + "import": "Import", + "message": "Wiadomość", + "now": "Now", + "ok": "OK", + "print": "Print", + "remove": "Usuń", + "requestNewKeys": "Request New Keys", + "requestPosition": "Poproś o pozycję", + "reset": "Zresetuj", + "retry": "Retry", + "save": "Zapisz", + "setDefault": "Set as default", + "unsetDefault": "Unset default", + "scanQr": "Scan QR Code", + "traceRoute": "Trace Route", + "submit": "Submit" + }, + "app": { + "title": "Meshtastic", + "fullTitle": "Meshtastic Web Client" + }, + "loading": "Loading...", + "unit": { + "cps": "CPS", + "dbm": "dBm", + "hertz": "Hz", + "hop": { + "one": "Hop", + "plural": "Hops" + }, + "hopsAway": { + "one": "{{count}} hop away", + "plural": "{{count}} hops away", + "unknown": "Unknown hops away" + }, + "megahertz": "MHz", + "kilohertz": "kHz", + "raw": "raw", + "meter": { + "one": "Meter", + "plural": "Meters", + "suffix": "m" + }, + "kilometer": { + "one": "Kilometer", + "plural": "Kilometers", + "suffix": "km" + }, + "minute": { + "one": "Minute", + "plural": "Minutes" + }, + "hour": { + "one": "Hour", + "plural": "Hours" + }, + "millisecond": { + "one": "Millisecond", + "plural": "Milliseconds", + "suffix": "ms" + }, + "second": { + "one": "Second", + "plural": "Seconds" + }, + "day": { + "one": "Day", + "plural": "Days", + "today": "Today", + "yesterday": "Yesterday" + }, + "month": { + "one": "Month", + "plural": "Months" + }, + "year": { + "one": "Year", + "plural": "Years" + }, + "snr": "SNR:", + "volt": { + "one": "Volt", + "plural": "Volts", + "suffix": "V" + }, + "record": { + "one": "Rekordy", + "plural": "Rekordy" + }, + "degree": { + "one": "Degree", + "plural": "Degrees", + "suffix": "°" + } + }, + "security": { + "0bit": "Pusty", + "8bit": "8-bitowy", + "128bit": "128-bitowy", + "256bit": "256-bitowy" + }, + "unknown": { + "longName": "Nieznany", + "shortName": "UNK", + "notAvailable": "N/A", + "num": "??" + }, + "nodeUnknownPrefix": "!", + "unset": "UNSET", + "fallbackName": "Meshtastic {{last4}}", + "node": "Węzeł", + "formValidation": { + "unsavedChanges": "Niezapisane zmiany", + "tooBig": { + "string": "Too long, expected less than or equal to {{maximum}} characters.", + "number": "Too big, expected a number smaller than or equal to {{maximum}}.", + "bytes": "Too big, expected less than or equal to {{params.maximum}} bytes." + }, + "tooSmall": { + "string": "Too short, expected more than or equal to {{minimum}} characters.", + "number": "Too small, expected a number larger than or equal to {{minimum}}." + }, + "invalidFormat": { + "ipv4": "Nieprawidłowy format, oczekiwany adres IPv4.", + "key": "Invalid format, expected a Base64 encoded pre-shared key (PSK)." + }, + "invalidType": { + "number": "Nieprawidłowy typ, oczekiwana liczba." + }, + "pskLength": { + "0bit": "Klucz musi być pusty.", + "8bit": "Key is required to be an 8 bit pre-shared key (PSK).", + "128bit": "Key is required to be a 128 bit pre-shared key (PSK).", + "256bit": "Key is required to be a 256 bit pre-shared key (PSK)." + }, + "required": { + "generic": "To pole jest wymagane.", + "managed": "Co najmniej jeden klucz administratora jest wymagany, jeśli węzeł jest zarządzany.", + "key": "Klucz jest wymagany." + }, + "invalidOverrideFreq": { + "number": "Invalid format, expected a value in the range 410-930 MHz or 0 (use default)." + } + }, + "yes": "Yes", + "no": "No" } diff --git a/packages/web/public/i18n/locales/pl-PL/config.json b/packages/web/public/i18n/locales/pl-PL/config.json new file mode 100644 index 000000000..dfafd45af --- /dev/null +++ b/packages/web/public/i18n/locales/pl-PL/config.json @@ -0,0 +1,458 @@ +{ + "page": { + "title": "Ustawienia", + "tabUser": "Użytkownik", + "tabChannels": "Kanały", + "tabBluetooth": "Bluetooth", + "tabDevice": "Urządzenie", + "tabDisplay": "Wyświetlacz", + "tabLora": "LoRa", + "tabNetwork": "Sieć", + "tabPosition": "Pozycjonowanie", + "tabPower": "Zasilanie", + "tabSecurity": "Bezpieczeństwo" + }, + "sidebar": { + "label": "Konfiguracja" + }, + "device": { + "title": "Ustawienia Urządzenia", + "description": "Ustawienia urządzenia", + "buttonPin": { + "description": "Nadpisanie pinu przycisku", + "label": "Pin przycisku" + }, + "buzzerPin": { + "description": "Nadpisanie pinu buzzera", + "label": "Pin buzzera" + }, + "disableTripleClick": { + "description": "Wyłącz potrójne kliknięcie", + "label": "Wyłącz potrójne kliknięcie" + }, + "doubleTapAsButtonPress": { + "description": "Traktuj podwójne dotknięcie jako naciśnięcie przycisku", + "label": "Podwójne dotknięcie jako naciśnięcie przycisku" + }, + "ledHeartbeatDisabled": { + "description": "Wyłącz domyślne miganie diody LED", + "label": "Pulsowanie diodą LED wyłączone" + }, + "nodeInfoBroadcastInterval": { + "description": "Jak często nadawać informacje o węźle", + "label": "Interwał transmisji informacji o węźle" + }, + "posixTimezone": { + "description": "Strefa czasowa POSIX urządzenia", + "label": "Strefa czasowa POSIX" + }, + "rebroadcastMode": { + "description": "Jak obsługiwać retransmisję", + "label": "Tryb retransmisji" + }, + "role": { + "description": "Jaką rolę pełni urządzenie w sieci", + "label": "Rola" + } + }, + "bluetooth": { + "title": "Ustawienia Bluetooth", + "description": "Ustawienia modułu Bluetooth", + "note": "Uwaga: Niektóre urządzenia (ESP32) nie mogą używać jednocześnie Bluetooth i WiFi.", + "enabled": { + "description": "Włącz/wyłącz Bluetooth", + "label": "Włączony" + }, + "pairingMode": { + "description": "Wybór trybu pinu", + "label": "Tryb parowania" + }, + "pin": { + "description": "Pin do użycia podczas łączenia", + "label": "Pin" + } + }, + "display": { + "description": "Ustawienia ekranu urządzenia", + "title": "Ustawienia ekranu", + "headingBold": { + "description": "Pogrubiony tekst nagłówka", + "label": "Pogrubiony nagłówek" + }, + "carouselDelay": { + "description": "Jak szybko przechodzić przez okna", + "label": "Opóźnienie karuzeli" + }, + "compassNorthTop": { + "description": "Przypnij północ na górę kompasu", + "label": "Północ na górze kompasu" + }, + "displayMode": { + "description": "Wariant układu ekranu", + "label": "Tryb wyświetlania" + }, + "displayUnits": { + "description": "Wyświetl jednostki metryczne lub imperialne", + "label": "Jednostki wyświetlania" + }, + "flipScreen": { + "description": "Odwróć ekran o 180 stopni", + "label": "Odwróć ekran" + }, + "gpsDisplayUnits": { + "description": "Format wyświetlania współrzędnych", + "label": "Jednostki wyświetlania GPS" + }, + "oledType": { + "description": "Typ ekranu OLED podłączonego do urządzenia", + "label": "Typ ekranu OLED" + }, + "screenTimeout": { + "description": "Wyłącz ekran po tym czasie", + "label": "Wygaszenie ekranu" + }, + "twelveHourClock": { + "description": "Użyj 12-godzinnego formatu zegara", + "label": "12-Godzinny Zegar" + }, + "wakeOnTapOrMotion": { + "description": "Obudź urządzenie przy dotknięciu lub ruchu", + "label": "Wybudź przy dotknięciu lub ruchu" + } + }, + "lora": { + "title": "Ustawienia sieci", + "description": "Ustawienia sieci LoRa", + "bandwidth": { + "description": "Szerokość kanału w kHz", + "label": "Pasmo" + }, + "boostedRxGain": { + "description": "Zwiększone wzmocnienie RX", + "label": "Zwiększone wzmocnienie RX" + }, + "codingRate": { + "description": "mianownik tempa kodowania", + "label": "Szybkość kodowania" + }, + "frequencyOffset": { + "description": "Przesunięcie częstotliwości w celu skorygowania błędów kalibracji kryształu", + "label": "Przesunięcie częstotliwości" + }, + "frequencySlot": { + "description": "Numer kanału częstotliwości LoRa", + "label": "Slot częstotliwości" + }, + "hopLimit": { + "description": "Maksymalna liczba przeskoków", + "label": "Limit przeskoków" + }, + "ignoreMqtt": { + "description": "Nie przekazuj wiadomości MQTT przez sieć", + "label": "Zignoruj MQTT" + }, + "modemPreset": { + "description": "Ustawienie modemu do użycia", + "label": "Ustawienie modemu" + }, + "okToMqtt": { + "description": "Gdy ustawione na true, ta konfiguracja wskazuje, że użytkownik zatwierdza pakiet do przesłania do MQTT. Jeśli ustawione na false, zdalne węzły są proszone o nieprzekazywanie pakietów do MQTT", + "label": "Zgoda na MQTT" + }, + "overrideDutyCycle": { + "description": "Nadpisz cykl pracy", + "label": "Nadpisz cykl pracy" + }, + "overrideFrequency": { + "description": "Nadpisz częstotliwość", + "label": "Nadpisz częstotliwość" + }, + "region": { + "description": "Ustawia region dla Twojego węzła", + "label": "Region" + }, + "spreadingFactor": { + "description": "Wskazuje liczbę chirpów na symbol", + "label": "Współczynnik rozszerzania" + }, + "transmitEnabled": { + "description": "Włącz/Wyłącz nadawanie (TX) z LoRa radio", + "label": "Nadawanie włączone" + }, + "transmitPower": { + "description": "Maksymalna moc nadawania", + "label": "Moc nadawania" + }, + "usePreset": { + "description": "Użyj predefiniowanych ustawień modemu", + "label": "Użyj predefiniowanych ustawień" + }, + "meshSettings": { + "description": "Ustawienia sieci LoRa", + "label": "Ustawienia sieci" + }, + "waveformSettings": { + "description": "Ustawienia dla LoRa waveform", + "label": "Ustawienia przebiegu fali" + }, + "radioSettings": { + "label": "Ustawienia radia", + "description": "Ustawienia dla radia LoRa" + } + }, + "network": { + "title": "Konfiguracja Wi-Fi", + "description": "Konfiguracja radia WiFi", + "note": "Uwaga: Niektóre urządzenia (ESP32) nie mogą używać jednocześnie Bluetooth i WiFi.", + "addressMode": { + "description": "Wybór przypisania adresu", + "label": "Tryb adresu" + }, + "dns": { + "description": "Serwer DNS", + "label": "DNS" + }, + "ethernetEnabled": { + "description": "Włącz lub wyłącz port Ethernet", + "label": "Włączony" + }, + "gateway": { + "description": "Brama Domyślna", + "label": "Brama domyślna" + }, + "ip": { + "description": "Adres IP", + "label": "IP" + }, + "psk": { + "description": "Hasło do sieci", + "label": "PSK" + }, + "ssid": { + "description": "Nazwa sieci", + "label": "SSID" + }, + "subnet": { + "description": "Maska podsieci", + "label": "Podsieć" + }, + "wifiEnabled": { + "description": "Włącz lub wyłącz radio Wi-Fi", + "label": "Włączony" + }, + "meshViaUdp": { + "label": "Mesh przez UDP" + }, + "ntpServer": { + "label": "Serwer NTP" + }, + "rsyslogServer": { + "label": "Serwer rsyslog" + }, + "ethernetConfigSettings": { + "description": "Konfiguracja portu Ethernet", + "label": "Konfiguracja Ethernet" + }, + "ipConfigSettings": { + "description": "Konfiguracja adresu IP", + "label": "Konfiguracja IP" + }, + "ntpConfigSettings": { + "description": "Konfiguracja NTP", + "label": "Konfiguracja NTP" + }, + "rsyslogConfigSettings": { + "description": "Konfiguracja Rsyslog", + "label": "Konfiguracja Rsyslog" + }, + "udpConfigSettings": { + "description": "Konfiguracja UDP przez mesh ", + "label": "Ustawienia UDP" + } + }, + "position": { + "title": "Ustawienia położenia", + "description": "Ustawienia modułu położenia", + "broadcastInterval": { + "description": "Jak często Twoja pozycja jest wysyłana przez sieć", + "label": "Interwał transmisji" + }, + "enablePin": { + "description": "Nadpisanie pinu włączającego moduł GPS", + "label": "Pin włączający" + }, + "fixedPosition": { + "description": "Nie zgłaszaj położenia GPS, tylko ręcznie określoną.", + "label": "Położenie stałe" + }, + "gpsMode": { + "description": "Skonfiguruj czy urządzenie GPS jest włączone, wyłączone, czy nie jest obecne", + "label": "Tryb GPS" + }, + "gpsUpdateInterval": { + "description": "Jak często powinna być odczytana pozycja z GPS", + "label": "Interwał aktualizacji pozycji GPS" + }, + "positionFlags": { + "description": "Opcjonalne pola dołączane podczas składania komunikatów o pozycji. Im więcej pól zostanie wybranych, tym większa wiadomość doprowadzi do dłuższego wykorzystania pasma i większego ryzyka utraty pakietów.", + "label": "Flagi położenia" + }, + "receivePin": { + "description": "Nadpisanie pinu RX modułu GPS", + "label": "Pin odbioru" + }, + "smartPositionEnabled": { + "description": "Wyślij pozycję tylko wtedy, gdy nastąpiła znacząca zmiana lokalizacji", + "label": "Włącz inteligentną pozycję" + }, + "smartPositionMinDistance": { + "description": "Minimalna odległość (w metrach), którą należy pokonać przed wysłaniem aktualizacji pozycji", + "label": "Minimalna odległość inteligentnego położenia" + }, + "smartPositionMinInterval": { + "description": "Minimalny interwał (w sekundach), który musi upłynąć przed wysłaniem aktualizacji pozycji", + "label": "Minimalny interwał inteligentnej pozycji" + }, + "transmitPin": { + "description": "Nadpisanie pinu TX modułu GPS", + "label": "Pin nadawania" + }, + "intervalsSettings": { + "description": "Jak często wysyłać aktualizację pozycji", + "label": "Interwały" + }, + "flags": { + "placeholder": "Wybierz flagi pozycji...", + "altitude": "Wysokość", + "altitudeGeoidalSeparation": "Rozdzielenie geoidalne wysokości", + "altitudeMsl": "Wysokość jest średnim poziomem morza", + "dop": "Rozcieńczanie PDOP precyzji (DOP) używane domyślnie", + "hdopVdop": "Jeśli ustawiono DOP, użyj wartości HDOP / VDOP zamiast PDOP", + "numSatellites": "Liczba satelitów", + "sequenceNumber": "Numer sekwencji", + "timestamp": "Znacznik czasu", + "unset": "Nieustawiony", + "vehicleHeading": "Kurs pojazdu", + "vehicleSpeed": "Prędkość pojazdu" + } + }, + "power": { + "adcMultiplierOverride": { + "description": "Używane do poprawiania odczytu napięcia baterii", + "label": "Współczynnik nadpisania mnożnika ADC" + }, + "ina219Address": { + "description": "Adres monitora baterii INA219", + "label": "Adres INA219" + }, + "lightSleepDuration": { + "description": "Jak długo urządzenie pozostanie w lekkim uśpieniu", + "label": "Czas trwania lekkiego uśpienia" + }, + "minimumWakeTime": { + "description": "Minimalny czas, w którym urządzenie pozostanie wybudzone po otrzymaniu pakietu", + "label": "Minimalny czas wybudzania" + }, + "noConnectionBluetoothDisabled": { + "description": "Jeśli urządzenie nie otrzyma połączenia Bluetooth, po tym czasie radio BLE zostanie wyłączone", + "label": "Bluetooth wyłączony przy braku połączeń" + }, + "powerSavingEnabled": { + "description": "Wybierz, jeśli zasilane jest z źródła o niskim natężeniu (np. słonecznego), aby zminimalizować zużycie energii w miarę możliwości.", + "label": "Włącz tryb oszczędzania energii" + }, + "shutdownOnBatteryDelay": { + "description": "Automatycznie zamknij węzeł po tym czasie, gdy jest na baterii, 0 dla bezterminowego", + "label": "Opóźnienie wyłączenia na baterii" + }, + "superDeepSleepDuration": { + "description": "Jak długo urządzenie pozostanie w bardzo głębokim uśpieniu", + "label": "Czas bardzo głębokiego uśpienia" + }, + "powerConfigSettings": { + "description": "Ustawienia modułu zasilania", + "label": "Konfiguracja zarządzania energią" + }, + "sleepSettings": { + "description": "Ustawienia uśpienia modułu zasilania", + "label": "Ustawienia uśpienia" + } + }, + "security": { + "description": "Ustawienia dla konfiguracji zabezpieczeń", + "title": "Ustawienia bezpieczeństwa", + "button_backupKey": "Kopia zapasowa klucza", + "adminChannelEnabled": { + "description": "Zezwalaj na kontrolę urządzenia przez niezabezpieczony kanał admina (stare)", + "label": "Zezwalaj na kontrolę admina (stare)" + }, + "enableDebugLogApi": { + "description": "Wyjście logowania debugowania na żywo nad serwerem, widok i eksport logów urządzenia poprawionego pozycją przez Bluetooth", + "label": "Włącz API logów debugowania" + }, + "managed": { + "description": "Jeśli włączone, opcje konfiguracji urządzenia można zmienić zdalnie tylko przez zdalny węzeł administracyjny za pomocą wiadomości administratora. Nie włączaj tej opcji, chyba że co najmniej jeden odpowiedni zdalny węzeł administracyjny został skonfigurowany, a klucz publiczny jest przechowywany w jednym z powyższych pól.", + "label": "Zarządzane" + }, + "privateKey": { + "description": "Używane do tworzenia klucza współdzielonego ze zdalnym urządzeniem", + "label": "Klucz prywatny" + }, + "publicKey": { + "description": "Wysyłane do innych węzłów w sieci, aby umożliwić im obliczenie wspólnego tajnego klucza", + "label": "Klucz publiczny" + }, + "primaryAdminKey": { + "description": "Główny klucz publiczny autoryzowany do wysyłania wiadomości administratora do tego węzła", + "label": "Główny klucz administratora" + }, + "secondaryAdminKey": { + "description": "Drugorzędny klucz publiczny autoryzowany do wysyłania wiadomości administratora do tego węzła", + "label": "Drugorzędny klucz administracyjny" + }, + "serialOutputEnabled": { + "description": "Konsola szeregowa przez Stream API", + "label": "Wyjście szeregowe włączone" + }, + "tertiaryAdminKey": { + "description": "Klucz publiczny trzeciorzędny autoryzowany do wysyłania wiadomości administratora do tego węzła", + "label": "Trzeciorzędny klucz administracyjny" + }, + "adminSettings": { + "description": "Ustawienia dla administratora", + "label": "Ustawienia administracyjne" + }, + "loggingSettings": { + "description": "Ustawienia logowania", + "label": "Ustawienia logowania" + } + }, + "user": { + "title": "User Settings", + "description": "Configure your device name and identity settings", + "longName": { + "label": "Długa nazwa", + "description": "Your full display name (1-40 characters)", + "validation": { + "min": "Long name must be at least 1 character", + "max": "Long name must be at most 40 characters" + } + }, + "shortName": { + "label": "Krótka nazwa", + "description": "Your abbreviated name (2-4 characters)", + "validation": { + "min": "Short name must be at least 2 characters", + "max": "Short name must be at most 4 characters" + } + }, + "isUnmessageable": { + "label": "Unmessageable", + "description": "Used to identify unmonitored or infrastructure nodes so that messaging is not available to nodes that will never respond." + }, + "isLicensed": { + "label": "Licensed amateur radio (HAM)", + "description": "Enable if you are a licensed amateur radio operator, enabling this option disables encryption and is not compatible with the default Meshtastic network." + } + } +} diff --git a/packages/web/public/i18n/locales/pl-PL/connections.json b/packages/web/public/i18n/locales/pl-PL/connections.json new file mode 100644 index 000000000..ff20044b0 --- /dev/null +++ b/packages/web/public/i18n/locales/pl-PL/connections.json @@ -0,0 +1,34 @@ +{ + "page": { + "title": "Connect to a Meshtastic device", + "description": "Add a device connection via HTTP, Bluetooth, or Serial. Your saved connections will be saved in your browser." + }, + "connectionType_ble": "BLE", + "connectionType_serial": "Seryjny", + "connectionType_network": "Sieć", + "deleteConnection": "Delete connection", + "areYouSure": "This will remove {{name}}. You canot undo this action.", + "moreActions": "More actions", + "noConnections": { + "title": "No connections yet.", + "description": "Create your first connection. It will connect immediately and be saved for later." + }, + "lastConnectedAt": "Last connected: {{date}}", + "neverConnected": "Never connected", + "toasts": { + "connected": "Połączony", + "nowConnected": "{{name}} is now connected", + "nowDisconnected": "{{name}} are now disconnecte", + "disconnected": "Rozłączono", + "failed": "Failed to connect", + "checkConnetion": "Check your device or settings and try again", + "defaultSet": "Default set", + "defaultConnection": "Default connection is now {{nameisconnected}}", + "deleted": "Deleted", + "deletedByName": "{{name}} was removed", + "pickConnectionAgain": "Could not connect. You may need to reselect the device/port.", + "added": "Connection added", + "savedByName": "{{name}} saved.", + "savedCantConnect": "The connection was saved but could not connect." + } +} diff --git a/packages/web/public/i18n/locales/pl-PL/dashboard.json b/packages/web/public/i18n/locales/pl-PL/dashboard.json deleted file mode 100644 index 553ebb9cc..000000000 --- a/packages/web/public/i18n/locales/pl-PL/dashboard.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "dashboard": { - "title": "Connected Devices", - "description": "Manage your connected Meshtastic devices.", - "connectionType_ble": "BLE", - "connectionType_serial": "Seryjny", - "connectionType_network": "Sieć", - "noDevicesTitle": "No devices connected", - "noDevicesDescription": "Connect a new device to get started.", - "button_newConnection": "New Connection" - } -} diff --git a/packages/web/public/i18n/locales/pl-PL/deviceConfig.json b/packages/web/public/i18n/locales/pl-PL/deviceConfig.json index 55d0f3ca9..ebc85cee9 100644 --- a/packages/web/public/i18n/locales/pl-PL/deviceConfig.json +++ b/packages/web/public/i18n/locales/pl-PL/deviceConfig.json @@ -122,7 +122,7 @@ "title": "Mesh Settings", "description": "Settings for the LoRa mesh", "bandwidth": { - "description": "Channel bandwidth in MHz", + "description": "Channel bandwidth in kHz", "label": "Bandwidth" }, "boostedRxGain": { diff --git a/packages/web/public/i18n/locales/pl-PL/dialog.json b/packages/web/public/i18n/locales/pl-PL/dialog.json index ef31acc41..68d72f777 100644 --- a/packages/web/public/i18n/locales/pl-PL/dialog.json +++ b/packages/web/public/i18n/locales/pl-PL/dialog.json @@ -1,193 +1,238 @@ { - "deleteMessages": { - "description": "This action will clear all message history. This cannot be undone. Are you sure you want to continue?", - "title": "Clear All Messages" - }, - "deviceName": { - "description": "The Device will restart once the config is saved.", - "longName": "Długa nazwa", - "shortName": "Short Name", - "title": "Change Device Name", - "validation": { - "longNameMax": "Long name must not be more than 40 characters", - "shortNameMax": "Short name must not be more than 4 characters", - "longNameMin": "Long name must have at least 1 character", - "shortNameMin": "Short name must have at least 1 character" - } - }, - "import": { - "description": "The current LoRa configuration will be overridden.", - "error": { - "invalidUrl": "Invalid Meshtastic URL" - }, - "channelPrefix": "Channel: ", - "channelSetUrl": "Channel Set/QR Code URL", - "channels": "Channels:", - "usePreset": "Use Preset?", - "title": "Import Channel Set" - }, - "locationResponse": { - "title": "Location: {{identifier}}", - "altitude": "Altitude: ", - "coordinates": "Coordinates: ", - "noCoordinates": "Brak współrzędnych" - }, - "pkiRegenerateDialog": { - "title": "Regenerate Pre-Shared Key?", - "description": "Are you sure you want to regenerate the pre-shared key?", - "regenerate": "Regenerate" - }, - "newDeviceDialog": { - "title": "Connect New Device", - "https": "https", - "http": "http", - "tabHttp": "HTTP", - "tabBluetooth": "Bluetooth", - "tabSerial": "Seryjny", - "useHttps": "Use HTTPS", - "connecting": "Connecting...", - "connect": "Połącz", - "connectionFailedAlert": { - "title": "Connection Failed", - "descriptionPrefix": "Could not connect to the device. ", - "httpsHint": "If using HTTPS, you may need to accept a self-signed certificate first. ", - "openLinkPrefix": "Please open ", - "openLinkSuffix": " in a new tab", - "acceptTlsWarningSuffix": ", accept any TLS warnings if prompted, then try again", - "learnMoreLink": "Learn more" - }, - "httpConnection": { - "label": "IP Address/Hostname", - "placeholder": "000.000.000.000 / meshtastic.local" - }, - "serialConnection": { - "noDevicesPaired": "No devices paired yet.", - "newDeviceButton": "New device", - "deviceIdentifier": "# {{index}} - {{vendorId}} - {{productId}}" - }, - "bluetoothConnection": { - "noDevicesPaired": "No devices paired yet.", - "newDeviceButton": "New device", - "connectionFailed": "Connection failed", - "deviceDisconnected": "Device disconnected", - "unknownDevice": "Unknown Device", - "errorLoadingDevices": "Error loading devices", - "unknownErrorLoadingDevices": "Unknown error loading devices" - }, - "validation": { - "requiresWebBluetooth": "This connection type requires <0>Web Bluetooth. Please use a supported browser, like Chrome or Edge.", - "requiresWebSerial": "This connection type requires <0>Web Serial. Please use a supported browser, like Chrome or Edge.", - "requiresSecureContext": "This application requires a <0>secure context. Please connect using HTTPS or localhost.", - "additionallyRequiresSecureContext": "Additionally, it requires a <0>secure context. Please connect using HTTPS or localhost." - } - }, - "nodeDetails": { - "message": "Wiadomość", - "requestPosition": "Poproś o pozycję", - "traceRoute": "Trace Route", - "airTxUtilization": "Air TX utilization", - "allRawMetrics": "All Raw Metrics:", - "batteryLevel": "Battery level", - "channelUtilization": "Channel utilization", - "details": "Details:", - "deviceMetrics": "Device Metrics:", - "hardware": "Hardware: ", - "lastHeard": "Last Heard: ", - "nodeHexPrefix": "Node Hex: ", - "nodeNumber": "Node Number: ", - "position": "Position:", - "role": "Role: ", - "uptime": "Uptime: ", - "voltage": "Napięcie", - "title": "Node Details for {{identifier}}", - "ignoreNode": "Ignore node", - "removeNode": "Remove node", - "unignoreNode": "Unignore node", - "security": "Security:", - "publicKey": "Public Key: ", - "messageable": "Messageable: ", - "KeyManuallyVerifiedTrue": "Public Key has been manually verified", - "KeyManuallyVerifiedFalse": "Public Key is not manually verified" - }, - "pkiBackup": { - "loseKeysWarning": "If you lose your keys, you will need to reset your device.", - "secureBackup": "Its important to backup your public and private keys and store your backup securely!", - "footer": "=== END OF KEYS ===", - "header": "=== MESHTASTIC KEYS FOR {{longName}} ({{shortName}}) ===", - "privateKey": "Private Key:", - "publicKey": "Public Key:", - "fileName": "meshtastic_keys_{{longName}}_{{shortName}}.txt", - "title": "Backup Keys" - }, - "pkiBackupReminder": { - "description": "We recommend backing up your key data regularly. Would you like to back up now?", - "title": "Backup Reminder", - "remindLaterPrefix": "Remind me in", - "remindNever": "Never remind me", - "backupNow": "Back up now" - }, - "pkiRegenerate": { - "description": "Are you sure you want to regenerate key pair?", - "title": "Regenerate Key Pair" - }, - "qr": { - "addChannels": "Add Channels", - "replaceChannels": "Replace Channels", - "description": "The current LoRa configuration will also be shared.", - "sharableUrl": "Sharable URL", - "title": "Generuj Kod QR" - }, - "reboot": { - "title": "Reboot device", - "description": "Reboot now or schedule a reboot of the connected node. Optionally, you can choose to reboot into OTA (Over-the-Air) mode.", - "ota": "Reboot into OTA mode", - "enterDelay": "Enter delay", - "scheduled": "Reboot has been scheduled", - "schedule": "Schedule reboot", - "now": "Reboot now", - "cancel": "Cancel scheduled reboot" - }, - "refreshKeys": { - "description": { - "acceptNewKeys": "This will remove the node from device and request new keys.", - "keyMismatchReasonSuffix": ". This is due to the remote node's current public key does not match the previously stored key for this node.", - "unableToSendDmPrefix": "Your node is unable to send a direct message to node: " - }, - "acceptNewKeys": "Accept New Keys", - "title": "Keys Mismatch - {{identifier}}" - }, - "removeNode": { - "description": "Are you sure you want to remove this Node?", - "title": "Remove Node?" - }, - "shutdown": { - "title": "Schedule Shutdown", - "description": "Turn off the connected node after x minutes." - }, - "traceRoute": { - "routeToDestination": "Route to destination:", - "routeBack": "Route back:" - }, - "tracerouteResponse": { - "title": "Traceroute: {{identifier}}" - }, - "unsafeRoles": { - "confirmUnderstanding": "Yes, I know what I'm doing", - "conjunction": " and the blog post about ", - "postamble": " and understand the implications of changing the role.", - "preamble": "I have read the ", - "choosingRightDeviceRole": "Choosing The Right Device Role", - "deviceRoleDocumentation": "Device Role Documentation", - "title": "Jesteś pewny?" - }, - "managedMode": { - "confirmUnderstanding": "Yes, I know what I'm doing", - "title": "Jesteś pewny?", - "description": "Enabling Managed Mode blocks client applications (including the web client) from writing configurations to a radio. Once enabled, radio configurations can only be changed through Remote Admin messages. This setting is not required for remote node administration." - }, - "clientNotification": { - "title": "Client Notification", - "TraceRoute can only be sent once every 30 seconds": "TraceRoute can only be sent once every 30 seconds", - "Compromised keys were detected and regenerated.": "Compromised keys were detected and regenerated." - } + "deleteMessages": { + "description": "This action will clear all message history. This cannot be undone. Are you sure you want to continue?", + "title": "Clear All Messages" + }, + "import": { + "description": "The current LoRa configuration will be overridden.", + "error": { + "invalidUrl": "Invalid Meshtastic URL" + }, + "channelPrefix": "Channel: ", + "primary": "Primary ", + "doNotImport": "No not import", + "channelName": "Nazwa", + "channelSlot": "Slot", + "channelSetUrl": "Channel Set/QR Code URL", + "useLoraConfig": "Import LoRa Config", + "presetDescription": "The current LoRa Config will be replaced.", + "title": "Import Channel Set" + }, + "locationResponse": { + "title": "Location: {{identifier}}", + "altitude": "Altitude: ", + "coordinates": "Coordinates: ", + "noCoordinates": "Brak współrzędnych" + }, + "pkiRegenerateDialog": { + "title": "Regenerate Pre-Shared Key?", + "description": "Are you sure you want to regenerate the pre-shared key?", + "regenerate": "Regenerate" + }, + "addConnection": { + "title": "Add connection", + "description": "Choose a connection type and fill in the details", + "validation": { + "requiresWebBluetooth": "Ten typ połączenia wymaga <0>Web Bluetooth. Użyj obsługiwanej przeglądarki, takiej jak Chrome lub Edge.", + "requiresWebSerial": "Ten typ połączenia wymaga <0>Web Serial. Użyj obsługiwanej przeglądarki, takiej jak Chrome lub Edge.", + "requiresSecureContext": "Ta aplikacja wymaga <0>bezpiecznego kontekstu. Połącz się używając HTTPS lub localhost.", + "additionallyRequiresSecureContext": "Dodatkowo, wymaga to <0>bezpiecznego kontekstu. Połącz się używając HTTPS lub localhost." + }, + "bluetoothConnection": { + "namePlaceholder": "My Bluetooth Node", + "supported": { + "title": "Web Bluetooth supported" + }, + "notSupported": { + "title": "Web Bluetooth not supported", + "description": "Your browser or device does not support Web Bluetooth" + }, + "short": "BT: {{deviceName}}", + "long": "Bluetooth Device", + "device": "Urządzenie", + "selectDevice": "Select device", + "selected": "Bluetooth device selected", + "notSelected": "No device selected", + "helperText": "Uses the Meshtastic Bluetooth service for discovery." + }, + "serialConnection": { + "namePlaceholder": "My Serial Node", + "helperText": "Selecting a port grants permission so the app can open it to connect.", + "supported": { + "title": "Web Serial supported" + }, + "notSupported": { + "title": "Web Serial not supported", + "description": "Your browser or device does not support Web Serial" + }, + "portSelected": { + "title": "Serial port selected", + "description": "Port permissions granted." + }, + "port": "Port", + "selectPort": "Select port", + "deviceName": "USB {{vendorId}}:{{productId}}", + "notSelected": "No port selected" + }, + "httpConnection": { + "namePlaceholder": "My HTTP Node", + "inputPlaceholder": "192.168.1.10 or meshtastic.local", + "heading": "URL or IP", + "useHttps": "Use HTTTPS", + "invalidUrl": { + "title": "Invalid URL", + "description": "Please enter a valid HTTP or HTTPS URL." + }, + "connectionTest": { + "description": "Test the connetion before saving to verify the device is reachable.", + "button": { + "loading": "Testing...", + "label": "Test connection" + }, + "reachable": "Reachable", + "notReachable": "Not reachable", + "success": { + "title": "Connection test successful", + "description": "The device appears to be reachable." + }, + "failure": { + "title": "Connection test failed", + "description": "Could not reach the device. Check the URL and try again." + } + } + } + }, + "nodeDetails": { + "message": "Wiadomość", + "requestPosition": "Poproś o pozycję", + "traceRoute": "Trace Route", + "airTxUtilization": "Air TX utilization", + "allRawMetrics": "All Raw Metrics:", + "batteryLevel": "Battery level", + "channelUtilization": "Channel utilization", + "details": "Details:", + "deviceMetrics": "Device Metrics:", + "hardware": "Hardware: ", + "lastHeard": "Last Heard: ", + "nodeHexPrefix": "Node Hex: ", + "nodeNumber": "Node Number: ", + "position": "Position:", + "role": "Role: ", + "uptime": "Uptime: ", + "voltage": "Napięcie", + "title": "Node Details for {{identifier}}", + "ignoreNode": "Ignore node", + "removeNode": "Remove node", + "unignoreNode": "Unignore node", + "security": "Security:", + "publicKey": "Public Key: ", + "messageable": "Messageable: ", + "KeyManuallyVerifiedTrue": "Public Key has been manually verified", + "KeyManuallyVerifiedFalse": "Public Key is not manually verified" + }, + "pkiBackup": { + "loseKeysWarning": "If you lose your keys, you will need to reset your device.", + "secureBackup": "Its important to backup your public and private keys and store your backup securely!", + "footer": "=== END OF KEYS ===", + "header": "=== MESHTASTIC KEYS FOR {{longName}} ({{shortName}}) ===", + "privateKey": "Private Key:", + "publicKey": "Public Key:", + "fileName": "meshtastic_keys_{{longName}}_{{shortName}}.txt", + "title": "Backup Keys" + }, + "pkiBackupReminder": { + "description": "We recommend backing up your key data regularly. Would you like to back up now?", + "title": "Backup Reminder", + "remindLaterPrefix": "Remind me in", + "remindNever": "Never remind me", + "backupNow": "Back up now" + }, + "pkiRegenerate": { + "description": "Are you sure you want to regenerate key pair?", + "title": "Regenerate Key Pair" + }, + "qr": { + "addChannels": "Add Channels", + "replaceChannels": "Replace Channels", + "description": "The current LoRa configuration will also be shared.", + "sharableUrl": "Sharable URL", + "title": "Generuj Kod QR" + }, + "reboot": { + "title": "Reboot device", + "description": "Reboot now or schedule a reboot of the connected node. Optionally, you can choose to reboot into OTA (Over-the-Air) mode.", + "ota": "Reboot into OTA mode", + "enterDelay": "Enter delay", + "scheduled": "Reboot has been scheduled", + "schedule": "Schedule reboot", + "now": "Reboot now", + "cancel": "Cancel scheduled reboot" + }, + "refreshKeys": { + "description": { + "acceptNewKeys": "This will remove the node from device and request new keys.", + "keyMismatchReasonSuffix": ". This is due to the remote node's current public key does not match the previously stored key for this node.", + "unableToSendDmPrefix": "Your node is unable to send a direct message to node: " + }, + "acceptNewKeys": "Accept New Keys", + "title": "Keys Mismatch - {{identifier}}" + }, + "removeNode": { + "description": "Are you sure you want to remove this Node?", + "title": "Remove Node?" + }, + "shutdown": { + "title": "Schedule Shutdown", + "description": "Turn off the connected node after x minutes." + }, + "traceRoute": { + "routeToDestination": "Route to destination:", + "routeBack": "Route back:" + }, + "tracerouteResponse": { + "title": "Traceroute: {{identifier}}" + }, + "unsafeRoles": { + "confirmUnderstanding": "Yes, I know what I'm doing", + "conjunction": " and the blog post about ", + "postamble": " and understand the implications of changing the role.", + "preamble": "I have read the ", + "choosingRightDeviceRole": "Choosing The Right Device Role", + "deviceRoleDocumentation": "Device Role Documentation", + "title": "Jesteś pewny?" + }, + "managedMode": { + "confirmUnderstanding": "Yes, I know what I'm doing", + "title": "Jesteś pewny?", + "description": "Enabling Managed Mode blocks client applications (including the web client) from writing configurations to a radio. Once enabled, radio configurations can only be changed through Remote Admin messages. This setting is not required for remote node administration." + }, + "clientNotification": { + "title": "Client Notification", + "TraceRoute can only be sent once every 30 seconds": "TraceRoute can only be sent once every 30 seconds", + "Compromised keys were detected and regenerated.": "Compromised keys were detected and regenerated." + }, + "resetNodeDb": { + "title": "Reset Node Database", + "description": "This will clear all nodes from the connected device's node database and clear all message history in the client. This cannot be undone. Are you sure you want to continue?", + "confirm": "Reset Node Database", + "failedTitle": "There was an error resetting the Node DB. Please try again." + }, + "clearAllStores": { + "title": "Clear All Local Storage", + "description": "This will clear all locally stored data, including message history and node databases for all previously connected devices. This will require you to reconnect to your node once complete and cannot be undone. Are you sure you want to continue?", + "confirm": "Clear all local storage", + "failedTitle": "There was an error clearing local storage. Please try again." + }, + "factoryResetDevice": { + "title": "Zresetuj urządzenie do ustawień fabrycznych", + "description": "This will factory reset the connected device, erasing all configurations and data on the device as well as all nodes and messages saved in the client. This cannot be undone. Are you sure you want to continue?", + "confirm": "Zresetuj urządzenie do ustawień fabrycznych", + "failedTitle": "There was an error performing the factory reset. Please try again." + }, + "factoryResetConfig": { + "title": "Zresetuj ustawienia do ustawień fabrycznych", + "description": "This will factory reset the configuration on the connected device, erasing all configurations on the device. This cannot be undone. Are you sure you want to continue?", + "confirm": "Zresetuj ustawienia do ustawień fabrycznych", + "failedTitle": "There was an error performing the factory reset. Please try again." + } } diff --git a/packages/web/public/i18n/locales/pl-PL/map.json b/packages/web/public/i18n/locales/pl-PL/map.json new file mode 100644 index 000000000..963e7b7be --- /dev/null +++ b/packages/web/public/i18n/locales/pl-PL/map.json @@ -0,0 +1,38 @@ +{ + "maplibre": { + "GeolocateControl.FindMyLocation": "Find my location", + "NavigationControl.ZoomIn": "Zoom in", + "NavigationControl.ZoomOut": "Zoom out", + "CooperativeGesturesHandler.WindowsHelpText": "Use Ctrl + scroll to zoom the map", + "CooperativeGesturesHandler.MacHelpText": "Use ⌘ + scroll to zoom the map", + "CooperativeGesturesHandler.MobileHelpText": "Use two fingers to move the map" + }, + "layerTool": { + "nodeMarkers": "Show nodes", + "directNeighbors": "Show direct connections", + "remoteNeighbors": "Show remote connections", + "positionPrecision": "Show position precision", + "traceroutes": "Show traceroutes", + "waypoints": "Show waypoints" + }, + "mapMenu": { + "locateAria": "Locate my node", + "layersAria": "Change map style" + }, + "waypointDetail": { + "edit": "Edytuj", + "description": "Description:", + "createdBy": "Edited by:", + "createdDate": "Created:", + "updated": "Updated:", + "expires": "Expires:", + "distance": "Distance:", + "bearing": "Absolute bearing:", + "lockedTo": "Locked by:", + "latitude": "Latitude:", + "longitude": "Longitude:" + }, + "myNode": { + "tooltip": "This device" + } +} diff --git a/packages/web/public/i18n/locales/pl-PL/messages.json b/packages/web/public/i18n/locales/pl-PL/messages.json index 2d5461411..1bc5c2fbc 100644 --- a/packages/web/public/i18n/locales/pl-PL/messages.json +++ b/packages/web/public/i18n/locales/pl-PL/messages.json @@ -1,39 +1,39 @@ { - "page": { - "title": "Wiadomości: {{chatName}}", - "placeholder": "Wpisz wiadomość" - }, - "emptyState": { - "title": "Wybierz czat", - "text": "Brak wiadomości." - }, - "selectChatPrompt": { - "text": "Wybierz kanał lub węzeł do wysyłania wiadomości." - }, - "sendMessage": { - "placeholder": "Wpisz tutaj swoją wiadomość...", - "sendButton": "Wyślij" - }, - "actionsMenu": { - "addReactionLabel": "Dodaj reakcję", - "replyLabel": "Odpowiedz" - }, - "deliveryStatus": { - "delivered": { - "label": "Wiadomość doręczona", - "displayText": "Wiadomość doręczona" - }, - "failed": { - "label": "Nie udało się dostarczyć wiadomości", - "displayText": "Dostawa nie powiodła się" - }, - "unknown": { - "label": "Status wiadomości nieznany", - "displayText": "Nieznany stan" - }, - "waiting": { - "label": "Wysyłanie wiadomości", - "displayText": "Oczekiwanie na dostawę" - } - } + "page": { + "title": "Wiadomości: {{chatName}}", + "placeholder": "Wpisz wiadomość" + }, + "emptyState": { + "title": "Wybierz czat", + "text": "Brak wiadomości." + }, + "selectChatPrompt": { + "text": "Wybierz kanał lub węzeł do wysyłania wiadomości." + }, + "sendMessage": { + "placeholder": "Wpisz tutaj swoją wiadomość...", + "sendButton": "Wyślij" + }, + "actionsMenu": { + "addReactionLabel": "Dodaj reakcję", + "replyLabel": "Odpowiedz" + }, + "deliveryStatus": { + "delivered": { + "label": "Wiadomość doręczona", + "displayText": "Wiadomość doręczona" + }, + "failed": { + "label": "Nie udało się dostarczyć wiadomości", + "displayText": "Dostawa nie powiodła się" + }, + "unknown": { + "label": "Status wiadomości nieznany", + "displayText": "Nieznany stan" + }, + "waiting": { + "label": "Wysyłanie wiadomości", + "displayText": "Oczekiwanie na dostawę" + } + } } diff --git a/packages/web/public/i18n/locales/pl-PL/moduleConfig.json b/packages/web/public/i18n/locales/pl-PL/moduleConfig.json index 9f502c007..8bd63a74b 100644 --- a/packages/web/public/i18n/locales/pl-PL/moduleConfig.json +++ b/packages/web/public/i18n/locales/pl-PL/moduleConfig.json @@ -1,448 +1,448 @@ { - "page": { - "tabAmbientLighting": "Ambient Lighting", - "tabAudio": "Audio", - "tabCannedMessage": "Canned", - "tabDetectionSensor": "Detection Sensor", - "tabExternalNotification": "Ext Notif", - "tabMqtt": "MQTT", - "tabNeighborInfo": "Neighbor Info", - "tabPaxcounter": "Paxcounter", - "tabRangeTest": "Test zasięgu", - "tabSerial": "Seryjny", - "tabStoreAndForward": "S&F", - "tabTelemetry": "Telemetria" - }, - "ambientLighting": { - "title": "Ambient Lighting Settings", - "description": "Settings for the Ambient Lighting module", - "ledState": { - "label": "LED State", - "description": "Sets LED to on or off" - }, - "current": { - "label": "Natężenie", - "description": "Sets the current for the LED output. Default is 10" - }, - "red": { - "label": "Czerwony", - "description": "Sets the red LED level. Values are 0-255" - }, - "green": { - "label": "Zielony", - "description": "Sets the green LED level. Values are 0-255" - }, - "blue": { - "label": "Niebieski", - "description": "Sets the blue LED level. Values are 0-255" - } - }, - "audio": { - "title": "Audio Settings", - "description": "Settings for the Audio module", - "codec2Enabled": { - "label": "Codec 2 Enabled", - "description": "Enable Codec 2 audio encoding" - }, - "pttPin": { - "label": "PTT Pin", - "description": "GPIO pin to use for PTT" - }, - "bitrate": { - "label": "Bitrate", - "description": "Bitrate to use for audio encoding" - }, - "i2sWs": { - "label": "i2S WS", - "description": "GPIO pin to use for i2S WS" - }, - "i2sSd": { - "label": "i2S SD", - "description": "GPIO pin to use for i2S SD" - }, - "i2sDin": { - "label": "i2S DIN", - "description": "GPIO pin to use for i2S DIN" - }, - "i2sSck": { - "label": "i2S SCK", - "description": "GPIO pin to use for i2S SCK" - } - }, - "cannedMessage": { - "title": "Canned Message Settings", - "description": "Settings for the Canned Message module", - "moduleEnabled": { - "label": "Module Enabled", - "description": "Enable Canned Message" - }, - "rotary1Enabled": { - "label": "Rotary Encoder #1 Enabled", - "description": "Enable the rotary encoder" - }, - "inputbrokerPinA": { - "label": "Encoder Pin A", - "description": "GPIO Pin Value (1-39) For encoder port A" - }, - "inputbrokerPinB": { - "label": "Encoder Pin B", - "description": "GPIO Pin Value (1-39) For encoder port B" - }, - "inputbrokerPinPress": { - "label": "Encoder Pin Press", - "description": "GPIO Pin Value (1-39) For encoder Press" - }, - "inputbrokerEventCw": { - "label": "Clockwise event", - "description": "Select input event." - }, - "inputbrokerEventCcw": { - "label": "Counter Clockwise event", - "description": "Select input event." - }, - "inputbrokerEventPress": { - "label": "Press event", - "description": "Select input event" - }, - "updown1Enabled": { - "label": "Up Down enabled", - "description": "Enable the up / down encoder" - }, - "allowInputSource": { - "label": "Allow Input Source", - "description": "Select from: '_any', 'rotEnc1', 'upDownEnc1', 'cardkb'" - }, - "sendBell": { - "label": "Send Bell", - "description": "Sends a bell character with each message" - } - }, - "detectionSensor": { - "title": "Detection Sensor Settings", - "description": "Settings for the Detection Sensor module", - "enabled": { - "label": "Włączony", - "description": "Enable or disable Detection Sensor Module" - }, - "minimumBroadcastSecs": { - "label": "Minimum Broadcast Seconds", - "description": "The interval in seconds of how often we can send a message to the mesh when a state change is detected" - }, - "stateBroadcastSecs": { - "label": "State Broadcast Seconds", - "description": "The interval in seconds of how often we should send a message to the mesh with the current state regardless of changes" - }, - "sendBell": { - "label": "Send Bell", - "description": "Send ASCII bell with alert message" - }, - "name": { - "label": "Friendly Name", - "description": "Used to format the message sent to mesh, max 20 Characters" - }, - "monitorPin": { - "label": "Monitor Pin", - "description": "The GPIO pin to monitor for state changes" - }, - "detectionTriggerType": { - "label": "Detection Triggered Type", - "description": "The type of trigger event to be used" - }, - "usePullup": { - "label": "Use Pullup", - "description": "Whether or not use INPUT_PULLUP mode for GPIO pin" - } - }, - "externalNotification": { - "title": "External Notification Settings", - "description": "Configure the external notification module", - "enabled": { - "label": "Module Enabled", - "description": "Enable External Notification" - }, - "outputMs": { - "label": "Output MS", - "description": "Output MS" - }, - "output": { - "label": "Output", - "description": "Output" - }, - "outputVibra": { - "label": "Output Vibrate", - "description": "Output Vibrate" - }, - "outputBuzzer": { - "label": "Output Buzzer", - "description": "Output Buzzer" - }, - "active": { - "label": "Active", - "description": "Active" - }, - "alertMessage": { - "label": "Alert Message", - "description": "Alert Message" - }, - "alertMessageVibra": { - "label": "Alert Message Vibrate", - "description": "Alert Message Vibrate" - }, - "alertMessageBuzzer": { - "label": "Alert Message Buzzer", - "description": "Alert Message Buzzer" - }, - "alertBell": { - "label": "Alert Bell", - "description": "Should an alert be triggered when receiving an incoming bell?" - }, - "alertBellVibra": { - "label": "Alert Bell Vibrate", - "description": "Alert Bell Vibrate" - }, - "alertBellBuzzer": { - "label": "Alert Bell Buzzer", - "description": "Alert Bell Buzzer" - }, - "usePwm": { - "label": "Use PWM", - "description": "Use PWM" - }, - "nagTimeout": { - "label": "Nag Timeout", - "description": "Nag Timeout" - }, - "useI2sAsBuzzer": { - "label": "Use I²S Pin as Buzzer", - "description": "Designate I²S Pin as Buzzer Output" - } - }, - "mqtt": { - "title": "MQTT Settings", - "description": "Settings for the MQTT module", - "enabled": { - "label": "Włączony", - "description": "Enable or disable MQTT" - }, - "address": { - "label": "MQTT Server Address", - "description": "MQTT server address to use for default/custom servers" - }, - "username": { - "label": "MQTT Username", - "description": "MQTT username to use for default/custom servers" - }, - "password": { - "label": "MQTT Password", - "description": "MQTT password to use for default/custom servers" - }, - "encryptionEnabled": { - "label": "Encryption Enabled", - "description": "Enable or disable MQTT encryption. Note: All messages are sent to the MQTT broker unencrypted if this option is not enabled, even when your uplink channels have encryption keys set. This includes position data." - }, - "jsonEnabled": { - "label": "JSON Enabled", - "description": "Whether to send/consume JSON packets on MQTT" - }, - "tlsEnabled": { - "label": "TLS Enabled", - "description": "Enable or disable TLS" - }, - "root": { - "label": "Root topic", - "description": "MQTT root topic to use for default/custom servers" - }, - "proxyToClientEnabled": { - "label": "MQTT Client Proxy Enabled", - "description": "Utilizes the network connection to proxy MQTT messages to the client." - }, - "mapReportingEnabled": { - "label": "Map Reporting Enabled", - "description": "Your node will periodically send an unencrypted map report packet to the configured MQTT server, this includes id, short and long name, approximate location, hardware model, role, firmware version, LoRa region, modem preset and primary channel name." - }, - "mapReportSettings": { - "publishIntervalSecs": { - "label": "Map Report Publish Interval (s)", - "description": "Interval in seconds to publish map reports" - }, - "positionPrecision": { - "label": "Approximate Location", - "description": "Position shared will be accurate within this distance", - "options": { - "metric_km23": "Within 23 km", - "metric_km12": "Within 12 km", - "metric_km5_8": "Within 5.8 km", - "metric_km2_9": "Within 2.9 km", - "metric_km1_5": "Within 1.5 km", - "metric_m700": "Within 700 m", - "metric_m350": "Within 350 m", - "metric_m200": "Within 200 m", - "metric_m90": "Within 90 m", - "metric_m50": "Within 50 m", - "imperial_mi15": "W zasięgu 15 mil", - "imperial_mi7_3": "W zasięgu 7,3 mil", - "imperial_mi3_6": "W zasięgu 3,6 mil", - "imperial_mi1_8": "W zasięgu 1,8 mil", - "imperial_mi0_9": "W zasięgu 0,9 mil", - "imperial_mi0_5": "W zasięgu 0,5 mili", - "imperial_mi0_2": "W zasięgu 0,2 mil", - "imperial_ft600": "W zasięgu 600 stóp", - "imperial_ft300": "W zasięgu 300 stóp", - "imperial_ft150": "W zasięgu 150 stóp" - } - } - } - }, - "neighborInfo": { - "title": "Neighbor Info Settings", - "description": "Settings for the Neighbor Info module", - "enabled": { - "label": "Włączony", - "description": "Enable or disable Neighbor Info Module" - }, - "updateInterval": { - "label": "Update Interval", - "description": "Interval in seconds of how often we should try to send our Neighbor Info to the mesh" - } - }, - "paxcounter": { - "title": "Paxcounter Settings", - "description": "Settings for the Paxcounter module", - "enabled": { - "label": "Module Enabled", - "description": "Enable Paxcounter" - }, - "paxcounterUpdateInterval": { - "label": "Update Interval (seconds)", - "description": "How long to wait between sending paxcounter packets" - }, - "wifiThreshold": { - "label": "WiFi RSSI Threshold", - "description": "At what WiFi RSSI level should the counter increase. Defaults to -80." - }, - "bleThreshold": { - "label": "BLE RSSI Threshold", - "description": "At what BLE RSSI level should the counter increase. Defaults to -80." - } - }, - "rangeTest": { - "title": "Range Test Settings", - "description": "Settings for the Range Test module", - "enabled": { - "label": "Module Enabled", - "description": "Enable Range Test" - }, - "sender": { - "label": "Message Interval", - "description": "How long to wait between sending test packets" - }, - "save": { - "label": "Save CSV to storage", - "description": "ESP32 Only" - } - }, - "serial": { - "title": "Serial Settings", - "description": "Settings for the Serial module", - "enabled": { - "label": "Module Enabled", - "description": "Enable Serial output" - }, - "echo": { - "label": "Echo", - "description": "Any packets you send will be echoed back to your device" - }, - "rxd": { - "label": "Receive Pin", - "description": "Set the GPIO pin to the RXD pin you have set up." - }, - "txd": { - "label": "Transmit Pin", - "description": "Set the GPIO pin to the TXD pin you have set up." - }, - "baud": { - "label": "Baud Rate", - "description": "The serial baud rate" - }, - "timeout": { - "label": "Limit czasu", - "description": "Seconds to wait before we consider your packet as 'done'" - }, - "mode": { - "label": "Tryb", - "description": "Select Mode" - }, - "overrideConsoleSerialPort": { - "label": "Override Console Serial Port", - "description": "If you have a serial port connected to the console, this will override it." - } - }, - "storeForward": { - "title": "Store & Forward Settings", - "description": "Settings for the Store & Forward module", - "enabled": { - "label": "Module Enabled", - "description": "Enable Store & Forward" - }, - "heartbeat": { - "label": "Heartbeat Enabled", - "description": "Enable Store & Forward heartbeat" - }, - "records": { - "label": "Number of records", - "description": "Number of records to store" - }, - "historyReturnMax": { - "label": "History return max", - "description": "Max number of records to return" - }, - "historyReturnWindow": { - "label": "History return window", - "description": "Max number of records to return" - } - }, - "telemetry": { - "title": "Telemetry Settings", - "description": "Settings for the Telemetry module", - "deviceUpdateInterval": { - "label": "Device Metrics", - "description": "Device metrics update interval (seconds)" - }, - "environmentUpdateInterval": { - "label": "Environment metrics update interval (seconds)", - "description": "" - }, - "environmentMeasurementEnabled": { - "label": "Module Enabled", - "description": "Enable the Environment Telemetry" - }, - "environmentScreenEnabled": { - "label": "Displayed on Screen", - "description": "Show the Telemetry Module on the OLED" - }, - "environmentDisplayFahrenheit": { - "label": "Display Fahrenheit", - "description": "Display temp in Fahrenheit" - }, - "airQualityEnabled": { - "label": "Air Quality Enabled", - "description": "Enable the Air Quality Telemetry" - }, - "airQualityInterval": { - "label": "Air Quality Update Interval", - "description": "How often to send Air Quality data over the mesh" - }, - "powerMeasurementEnabled": { - "label": "Power Measurement Enabled", - "description": "Enable the Power Measurement Telemetry" - }, - "powerUpdateInterval": { - "label": "Power Update Interval", - "description": "How often to send Power data over the mesh" - }, - "powerScreenEnabled": { - "label": "Power Screen Enabled", - "description": "Enable the Power Telemetry Screen" - } - } + "page": { + "tabAmbientLighting": "Ambient Lighting", + "tabAudio": "Audio", + "tabCannedMessage": "Canned", + "tabDetectionSensor": "Detection Sensor", + "tabExternalNotification": "Ext Notif", + "tabMqtt": "MQTT", + "tabNeighborInfo": "Neighbor Info", + "tabPaxcounter": "Paxcounter", + "tabRangeTest": "Test zasięgu", + "tabSerial": "Seryjny", + "tabStoreAndForward": "S&F", + "tabTelemetry": "Telemetria" + }, + "ambientLighting": { + "title": "Ambient Lighting Settings", + "description": "Settings for the Ambient Lighting module", + "ledState": { + "label": "LED State", + "description": "Sets LED to on or off" + }, + "current": { + "label": "Natężenie", + "description": "Sets the current for the LED output. Default is 10" + }, + "red": { + "label": "Czerwony", + "description": "Sets the red LED level. Values are 0-255" + }, + "green": { + "label": "Zielony", + "description": "Sets the green LED level. Values are 0-255" + }, + "blue": { + "label": "Niebieski", + "description": "Sets the blue LED level. Values are 0-255" + } + }, + "audio": { + "title": "Audio Settings", + "description": "Settings for the Audio module", + "codec2Enabled": { + "label": "Codec 2 Enabled", + "description": "Enable Codec 2 audio encoding" + }, + "pttPin": { + "label": "PTT Pin", + "description": "GPIO pin to use for PTT" + }, + "bitrate": { + "label": "Bitrate", + "description": "Bitrate to use for audio encoding" + }, + "i2sWs": { + "label": "i2S WS", + "description": "GPIO pin to use for i2S WS" + }, + "i2sSd": { + "label": "i2S SD", + "description": "GPIO pin to use for i2S SD" + }, + "i2sDin": { + "label": "i2S DIN", + "description": "GPIO pin to use for i2S DIN" + }, + "i2sSck": { + "label": "i2S SCK", + "description": "GPIO pin to use for i2S SCK" + } + }, + "cannedMessage": { + "title": "Canned Message Settings", + "description": "Settings for the Canned Message module", + "moduleEnabled": { + "label": "Module Enabled", + "description": "Enable Canned Message" + }, + "rotary1Enabled": { + "label": "Rotary Encoder #1 Enabled", + "description": "Enable the rotary encoder" + }, + "inputbrokerPinA": { + "label": "Encoder Pin A", + "description": "GPIO Pin Value (1-39) For encoder port A" + }, + "inputbrokerPinB": { + "label": "Encoder Pin B", + "description": "GPIO Pin Value (1-39) For encoder port B" + }, + "inputbrokerPinPress": { + "label": "Encoder Pin Press", + "description": "GPIO Pin Value (1-39) For encoder Press" + }, + "inputbrokerEventCw": { + "label": "Clockwise event", + "description": "Select input event." + }, + "inputbrokerEventCcw": { + "label": "Counter Clockwise event", + "description": "Select input event." + }, + "inputbrokerEventPress": { + "label": "Press event", + "description": "Select input event" + }, + "updown1Enabled": { + "label": "Up Down enabled", + "description": "Enable the up / down encoder" + }, + "allowInputSource": { + "label": "Allow Input Source", + "description": "Select from: '_any', 'rotEnc1', 'upDownEnc1', 'cardkb'" + }, + "sendBell": { + "label": "Send Bell", + "description": "Sends a bell character with each message" + } + }, + "detectionSensor": { + "title": "Detection Sensor Settings", + "description": "Settings for the Detection Sensor module", + "enabled": { + "label": "Włączony", + "description": "Enable or disable Detection Sensor Module" + }, + "minimumBroadcastSecs": { + "label": "Minimum Broadcast Seconds", + "description": "The interval in seconds of how often we can send a message to the mesh when a state change is detected" + }, + "stateBroadcastSecs": { + "label": "State Broadcast Seconds", + "description": "The interval in seconds of how often we should send a message to the mesh with the current state regardless of changes" + }, + "sendBell": { + "label": "Send Bell", + "description": "Send ASCII bell with alert message" + }, + "name": { + "label": "Friendly Name", + "description": "Used to format the message sent to mesh, max 20 Characters" + }, + "monitorPin": { + "label": "Monitor Pin", + "description": "The GPIO pin to monitor for state changes" + }, + "detectionTriggerType": { + "label": "Detection Triggered Type", + "description": "The type of trigger event to be used" + }, + "usePullup": { + "label": "Use Pullup", + "description": "Whether or not use INPUT_PULLUP mode for GPIO pin" + } + }, + "externalNotification": { + "title": "External Notification Settings", + "description": "Configure the external notification module", + "enabled": { + "label": "Module Enabled", + "description": "Enable External Notification" + }, + "outputMs": { + "label": "Output MS", + "description": "Output MS" + }, + "output": { + "label": "Output", + "description": "Output" + }, + "outputVibra": { + "label": "Output Vibrate", + "description": "Output Vibrate" + }, + "outputBuzzer": { + "label": "Output Buzzer", + "description": "Output Buzzer" + }, + "active": { + "label": "Active", + "description": "Active" + }, + "alertMessage": { + "label": "Alert Message", + "description": "Alert Message" + }, + "alertMessageVibra": { + "label": "Alert Message Vibrate", + "description": "Alert Message Vibrate" + }, + "alertMessageBuzzer": { + "label": "Alert Message Buzzer", + "description": "Alert Message Buzzer" + }, + "alertBell": { + "label": "Alert Bell", + "description": "Should an alert be triggered when receiving an incoming bell?" + }, + "alertBellVibra": { + "label": "Alert Bell Vibrate", + "description": "Alert Bell Vibrate" + }, + "alertBellBuzzer": { + "label": "Alert Bell Buzzer", + "description": "Alert Bell Buzzer" + }, + "usePwm": { + "label": "Use PWM", + "description": "Use PWM" + }, + "nagTimeout": { + "label": "Nag Timeout", + "description": "Nag Timeout" + }, + "useI2sAsBuzzer": { + "label": "Use I²S Pin as Buzzer", + "description": "Designate I²S Pin as Buzzer Output" + } + }, + "mqtt": { + "title": "MQTT Settings", + "description": "Settings for the MQTT module", + "enabled": { + "label": "Włączony", + "description": "Enable or disable MQTT" + }, + "address": { + "label": "MQTT Server Address", + "description": "MQTT server address to use for default/custom servers" + }, + "username": { + "label": "MQTT Username", + "description": "MQTT username to use for default/custom servers" + }, + "password": { + "label": "MQTT Password", + "description": "MQTT password to use for default/custom servers" + }, + "encryptionEnabled": { + "label": "Encryption Enabled", + "description": "Enable or disable MQTT encryption. Note: All messages are sent to the MQTT broker unencrypted if this option is not enabled, even when your uplink channels have encryption keys set. This includes position data." + }, + "jsonEnabled": { + "label": "JSON Enabled", + "description": "Whether to send/consume JSON packets on MQTT" + }, + "tlsEnabled": { + "label": "TLS Enabled", + "description": "Enable or disable TLS" + }, + "root": { + "label": "Root topic", + "description": "MQTT root topic to use for default/custom servers" + }, + "proxyToClientEnabled": { + "label": "MQTT Client Proxy Enabled", + "description": "Utilizes the network connection to proxy MQTT messages to the client." + }, + "mapReportingEnabled": { + "label": "Map Reporting Enabled", + "description": "Your node will periodically send an unencrypted map report packet to the configured MQTT server, this includes id, short and long name, approximate location, hardware model, role, firmware version, LoRa region, modem preset and primary channel name." + }, + "mapReportSettings": { + "publishIntervalSecs": { + "label": "Map Report Publish Interval (s)", + "description": "Interval in seconds to publish map reports" + }, + "positionPrecision": { + "label": "Approximate Location", + "description": "Position shared will be accurate within this distance", + "options": { + "metric_km23": "Within 23 km", + "metric_km12": "Within 12 km", + "metric_km5_8": "Within 5.8 km", + "metric_km2_9": "Within 2.9 km", + "metric_km1_5": "Within 1.5 km", + "metric_m700": "Within 700 m", + "metric_m350": "Within 350 m", + "metric_m200": "Within 200 m", + "metric_m90": "Within 90 m", + "metric_m50": "Within 50 m", + "imperial_mi15": "W zasięgu 15 mil", + "imperial_mi7_3": "W zasięgu 7,3 mil", + "imperial_mi3_6": "W zasięgu 3,6 mil", + "imperial_mi1_8": "W zasięgu 1,8 mil", + "imperial_mi0_9": "W zasięgu 0,9 mil", + "imperial_mi0_5": "W zasięgu 0,5 mili", + "imperial_mi0_2": "W zasięgu 0,2 mil", + "imperial_ft600": "W zasięgu 600 stóp", + "imperial_ft300": "W zasięgu 300 stóp", + "imperial_ft150": "W zasięgu 150 stóp" + } + } + } + }, + "neighborInfo": { + "title": "Neighbor Info Settings", + "description": "Settings for the Neighbor Info module", + "enabled": { + "label": "Włączony", + "description": "Enable or disable Neighbor Info Module" + }, + "updateInterval": { + "label": "Update Interval", + "description": "Interval in seconds of how often we should try to send our Neighbor Info to the mesh" + } + }, + "paxcounter": { + "title": "Paxcounter Settings", + "description": "Settings for the Paxcounter module", + "enabled": { + "label": "Module Enabled", + "description": "Enable Paxcounter" + }, + "paxcounterUpdateInterval": { + "label": "Update Interval (seconds)", + "description": "How long to wait between sending paxcounter packets" + }, + "wifiThreshold": { + "label": "WiFi RSSI Threshold", + "description": "At what WiFi RSSI level should the counter increase. Defaults to -80." + }, + "bleThreshold": { + "label": "BLE RSSI Threshold", + "description": "At what BLE RSSI level should the counter increase. Defaults to -80." + } + }, + "rangeTest": { + "title": "Range Test Settings", + "description": "Settings for the Range Test module", + "enabled": { + "label": "Module Enabled", + "description": "Enable Range Test" + }, + "sender": { + "label": "Message Interval", + "description": "How long to wait between sending test packets" + }, + "save": { + "label": "Save CSV to storage", + "description": "ESP32 Only" + } + }, + "serial": { + "title": "Serial Settings", + "description": "Settings for the Serial module", + "enabled": { + "label": "Module Enabled", + "description": "Enable Serial output" + }, + "echo": { + "label": "Echo", + "description": "Any packets you send will be echoed back to your device" + }, + "rxd": { + "label": "Receive Pin", + "description": "Set the GPIO pin to the RXD pin you have set up." + }, + "txd": { + "label": "Transmit Pin", + "description": "Set the GPIO pin to the TXD pin you have set up." + }, + "baud": { + "label": "Baud Rate", + "description": "The serial baud rate" + }, + "timeout": { + "label": "Limit czasu", + "description": "Seconds to wait before we consider your packet as 'done'" + }, + "mode": { + "label": "Tryb", + "description": "Select Mode" + }, + "overrideConsoleSerialPort": { + "label": "Override Console Serial Port", + "description": "If you have a serial port connected to the console, this will override it." + } + }, + "storeForward": { + "title": "Store & Forward Settings", + "description": "Settings for the Store & Forward module", + "enabled": { + "label": "Module Enabled", + "description": "Enable Store & Forward" + }, + "heartbeat": { + "label": "Heartbeat Enabled", + "description": "Enable Store & Forward heartbeat" + }, + "records": { + "label": "Number of records", + "description": "Number of records to store" + }, + "historyReturnMax": { + "label": "History return max", + "description": "Max number of records to return" + }, + "historyReturnWindow": { + "label": "History return window", + "description": "Return records from this time window (minutes)" + } + }, + "telemetry": { + "title": "Telemetry Settings", + "description": "Settings for the Telemetry module", + "deviceUpdateInterval": { + "label": "Device Metrics", + "description": "Device metrics update interval (seconds)" + }, + "environmentUpdateInterval": { + "label": "Environment metrics update interval (seconds)", + "description": "" + }, + "environmentMeasurementEnabled": { + "label": "Module Enabled", + "description": "Enable the Environment Telemetry" + }, + "environmentScreenEnabled": { + "label": "Displayed on Screen", + "description": "Show the Telemetry Module on the OLED" + }, + "environmentDisplayFahrenheit": { + "label": "Display Fahrenheit", + "description": "Display temp in Fahrenheit" + }, + "airQualityEnabled": { + "label": "Air Quality Enabled", + "description": "Enable the Air Quality Telemetry" + }, + "airQualityInterval": { + "label": "Air Quality Update Interval", + "description": "How often to send Air Quality data over the mesh" + }, + "powerMeasurementEnabled": { + "label": "Power Measurement Enabled", + "description": "Enable the Power Measurement Telemetry" + }, + "powerUpdateInterval": { + "label": "Power Update Interval", + "description": "How often to send Power data over the mesh" + }, + "powerScreenEnabled": { + "label": "Power Screen Enabled", + "description": "Enable the Power Telemetry Screen" + } + } } diff --git a/packages/web/public/i18n/locales/pl-PL/nodes.json b/packages/web/public/i18n/locales/pl-PL/nodes.json index 9cf22ee2c..07426aa24 100644 --- a/packages/web/public/i18n/locales/pl-PL/nodes.json +++ b/packages/web/public/i18n/locales/pl-PL/nodes.json @@ -1,63 +1,59 @@ { - "nodeDetail": { - "publicKeyEnabled": { - "label": "Publiczny klucz włączony" - }, - "noPublicKey": { - "label": "Brak klucza publicznego" - }, - "directMessage": { - "label": "Wiadomość bezpośrednia {{shortName}}" - }, - "favorite": { - "label": "Ulubiony", - "tooltip": "Dodaj lub usuń ten węzeł z ulubionych" - }, - "notFavorite": { - "label": "Nie ulubiony" - }, - "error": { - "label": "Błąd", - "text": "Wystąpił błąd podczas pobierania danych węzła. Spróbuj ponownie później." - }, - "status": { - "heard": "Usłyszano", - "mqtt": "MQTT" - }, - "elevation": { - "label": "Elewacja" - }, - "channelUtil": { - "label": "Użycie kanału" - }, - "airtimeUtil": { - "label": "Użycie czasu ant" - } - }, - "nodesTable": { - "headings": { - "longName": "Długa nazwa", - "connection": "Połączenie", - "lastHeard": "Ostatnio słyszany", - "encryption": "Szyfrowanie", - "model": "Model", - "macAddress": "Adres MAC" - }, - "connectionStatus": { - "direct": "Bezpośrednio", - "away": "away", - "unknown": "-", - "viaMqtt": ", przez MQTT" - }, - "lastHeardStatus": { - "never": "Nigdy" - } - }, - "actions": { - "added": "Dodano", - "removed": "Usunięto", - "ignoreNode": "Ignoruj węzeł", - "unignoreNode": "Od-ignoruj węzeł", - "requestPosition": "Poproś o pozycję" - } + "nodeDetail": { + "publicKeyEnabled": { + "label": "Publiczny klucz włączony" + }, + "noPublicKey": { + "label": "Brak klucza publicznego" + }, + "directMessage": { + "label": "Wiadomość bezpośrednia {{shortName}}" + }, + "favorite": { + "label": "Ulubiony", + "tooltip": "Dodaj lub usuń ten węzeł z ulubionych" + }, + "notFavorite": { + "label": "Nie ulubiony" + }, + "error": { + "label": "Błąd", + "text": "Wystąpił błąd podczas pobierania danych węzła. Spróbuj ponownie później." + }, + "status": { + "heard": "Usłyszano", + "mqtt": "MQTT" + }, + "elevation": { + "label": "Elewacja" + }, + "channelUtil": { + "label": "Użycie kanału" + }, + "airtimeUtil": { + "label": "Użycie czasu ant" + } + }, + "nodesTable": { + "headings": { + "longName": "Długa nazwa", + "connection": "Połączenie", + "lastHeard": "Ostatnio słyszany", + "encryption": "Szyfrowanie", + "model": "Model", + "macAddress": "Adres MAC" + }, + "connectionStatus": { + "direct": "Bezpośrednio", + "away": "away", + "viaMqtt": ", przez MQTT" + } + }, + "actions": { + "added": "Dodano", + "removed": "Usunięto", + "ignoreNode": "Ignoruj węzeł", + "unignoreNode": "Od-ignoruj węzeł", + "requestPosition": "Poproś o pozycję" + } } diff --git a/packages/web/public/i18n/locales/pl-PL/ui.json b/packages/web/public/i18n/locales/pl-PL/ui.json index bcb6cd029..206a8bb0b 100644 --- a/packages/web/public/i18n/locales/pl-PL/ui.json +++ b/packages/web/public/i18n/locales/pl-PL/ui.json @@ -1,228 +1,230 @@ { - "navigation": { - "title": "Navigation", - "messages": "Wiadomości", - "map": "Mapa", - "config": "Config", - "radioConfig": "Radio Config", - "moduleConfig": "Module Config", - "channels": "Kanały", - "nodes": "Nodes" - }, - "app": { - "title": "Meshtastic", - "logo": "Meshtastic Logo" - }, - "sidebar": { - "collapseToggle": { - "button": { - "open": "Open sidebar", - "close": "Close sidebar" - } - }, - "deviceInfo": { - "volts": "{{voltage}} volts", - "firmware": { - "title": "Oprogramowanie", - "version": "v{{version}}", - "buildDate": "Build date: {{date}}" - }, - "deviceName": { - "title": "Device Name", - "changeName": "Change Device Name", - "placeholder": "Enter device name" - }, - "editDeviceName": "Edit device name" - } - }, - "batteryStatus": { - "charging": "{{level}}% charging", - "pluggedIn": "Plugged in", - "title": "Bateria" - }, - "search": { - "nodes": "Search nodes...", - "channels": "Search channels...", - "commandPalette": "Search commands..." - }, - "toast": { - "positionRequestSent": { - "title": "Position request sent." - }, - "requestingPosition": { - "title": "Requesting position, please wait..." - }, - "sendingTraceroute": { - "title": "Sending Traceroute, please wait..." - }, - "tracerouteSent": { - "title": "Traceroute sent." - }, - "savedChannel": { - "title": "Saved Channel: {{channelName}}" - }, - "messages": { - "pkiEncryption": { - "title": "Chat is using PKI encryption." - }, - "pskEncryption": { - "title": "Chat is using PSK encryption." - } - }, - "configSaveError": { - "title": "Error Saving Config", - "description": "An error occurred while saving the configuration." - }, - "validationError": { - "title": "Config Errors Exist", - "description": "Please fix the configuration errors before saving." - }, - "saveSuccess": { - "title": "Saving Config", - "description": "The configuration change {{case}} has been saved." - }, - "favoriteNode": { - "title": "{{action}} {{nodeName}} {{direction}} favorites.", - "action": { - "added": "Dodano", - "removed": "Usunięto", - "to": "to", - "from": "from" - } - }, - "ignoreNode": { - "title": "{{action}} {{nodeName}} {{direction}} ignore list", - "action": { - "added": "Dodano", - "removed": "Usunięto", - "to": "to", - "from": "from" - } - } - }, - "notifications": { - "copied": { - "label": "Copied!" - }, - "copyToClipboard": { - "label": "Copy to clipboard" - }, - "hidePassword": { - "label": "Ukryj hasło" - }, - "showPassword": { - "label": "Pokaż hasło" - }, - "deliveryStatus": { - "delivered": "Delivered", - "failed": "Delivery Failed", - "waiting": "Czekam. . .", - "unknown": "Nieznany" - } - }, - "general": { - "label": "General" - }, - "hardware": { - "label": "Hardware" - }, - "metrics": { - "label": "Metrics" - }, - "role": { - "label": "Rola" - }, - "filter": { - "label": "Filtr" - }, - "advanced": { - "label": "Advanced" - }, - "clearInput": { - "label": "Clear input" - }, - "resetFilters": { - "label": "Reset Filters" - }, - "nodeName": { - "label": "Node name/number", - "placeholder": "Meshtastic 1234" - }, - "airtimeUtilization": { - "label": "Airtime Utilization (%)" - }, - "batteryLevel": { - "label": "Battery level (%)", - "labelText": "Battery level (%): {{value}}" - }, - "batteryVoltage": { - "label": "Battery voltage (V)", - "title": "Napięcie" - }, - "channelUtilization": { - "label": "Channel Utilization (%)" - }, - "hops": { - "direct": "Bezpośrednio", - "label": "Number of hops", - "text": "Number of hops: {{value}}" - }, - "lastHeard": { - "label": "Aktywność", - "labelText": "Last heard: {{value}}", - "nowLabel": "Now" - }, - "snr": { - "label": "SNR (db)" - }, - "favorites": { - "label": "Favorites" - }, - "hide": { - "label": "Hide" - }, - "showOnly": { - "label": "Show Only" - }, - "viaMqtt": { - "label": "Connected via MQTT" - }, - "hopsUnknown": { - "label": "Unknown number of hops" - }, - "showUnheard": { - "label": "Never heard" - }, - "language": { - "label": "Język", - "changeLanguage": "Change Language" - }, - "theme": { - "dark": "Ciemny", - "light": "Jasny", - "system": "Automatic", - "changeTheme": "Change Color Scheme" - }, - "errorPage": { - "title": "This is a little embarrassing...", - "description1": "We are really sorry but an error occurred in the web client that caused it to crash.
This is not supposed to happen, and we are working hard to fix it.", - "description2": "The best way to prevent this from happening again to you or anyone else is to report the issue to us.", - "reportInstructions": "Please include the following information in your report:", - "reportSteps": { - "step1": "What you were doing when the error occurred", - "step2": "What you expected to happen", - "step3": "What actually happened", - "step4": "Any other relevant information" - }, - "reportLink": "You can report the issue to our <0>GitHub", - "dashboardLink": "Return to the <0>dashboard", - "detailsSummary": "Error Details", - "errorMessageLabel": "Error message:", - "stackTraceLabel": "Stack trace:", - "fallbackError": "{{error}}" - }, - "footer": { - "text": "Powered by <0>▲ Vercel | Meshtastic® is a registered trademark of Meshtastic LLC. | <1>Legal Information", - "commitSha": "Commit SHA: {{sha}}" - } + "navigation": { + "title": "Navigation", + "messages": "Wiadomości", + "map": "Mapa", + "settings": "Ustawienia", + "channels": "Kanały", + "radioConfig": "Radio Config", + "deviceConfig": "Konfiguracja urządzenia", + "moduleConfig": "Module Config", + "manageConnections": "Manage Connections", + "nodes": "Nodes" + }, + "app": { + "title": "Meshtastic", + "logo": "Meshtastic Logo" + }, + "sidebar": { + "collapseToggle": { + "button": { + "open": "Open sidebar", + "close": "Close sidebar" + } + }, + "deviceInfo": { + "volts": "{{voltage}} volts", + "firmware": { + "title": "Oprogramowanie", + "version": "v{{version}}", + "buildDate": "Build date: {{date}}" + } + } + }, + "batteryStatus": { + "charging": "{{level}}% charging", + "pluggedIn": "Plugged in", + "title": "Bateria" + }, + "search": { + "nodes": "Search nodes...", + "channels": "Search channels...", + "commandPalette": "Search commands..." + }, + "toast": { + "positionRequestSent": { + "title": "Position request sent." + }, + "requestingPosition": { + "title": "Requesting position, please wait..." + }, + "sendingTraceroute": { + "title": "Sending Traceroute, please wait..." + }, + "tracerouteSent": { + "title": "Traceroute sent." + }, + "savedChannel": { + "title": "Saved Channel: {{channelName}}" + }, + "messages": { + "pkiEncryption": { + "title": "Chat is using PKI encryption." + }, + "pskEncryption": { + "title": "Chat is using PSK encryption." + } + }, + "configSaveError": { + "title": "Error Saving Config", + "description": "An error occurred while saving the configuration." + }, + "validationError": { + "title": "Config Errors Exist", + "description": "Please fix the configuration errors before saving." + }, + "saveSuccess": { + "title": "Saving Config", + "description": "The configuration change {{case}} has been saved." + }, + "saveAllSuccess": { + "title": "Saved", + "description": "All configuration changes have been saved." + }, + "favoriteNode": { + "title": "{{action}} {{nodeName}} {{direction}} favorites.", + "action": { + "added": "Dodano", + "removed": "Usunięto", + "to": "to", + "from": "from" + } + }, + "ignoreNode": { + "title": "{{action}} {{nodeName}} {{direction}} ignore list", + "action": { + "added": "Dodano", + "removed": "Usunięto", + "to": "to", + "from": "from" + } + } + }, + "notifications": { + "copied": { + "label": "Copied!" + }, + "copyToClipboard": { + "label": "Copy to clipboard" + }, + "hidePassword": { + "label": "Ukryj hasło" + }, + "showPassword": { + "label": "Pokaż hasło" + }, + "deliveryStatus": { + "delivered": "Delivered", + "failed": "Delivery Failed", + "waiting": "Czekam. . .", + "unknown": "Nieznany" + } + }, + "general": { + "label": "General" + }, + "hardware": { + "label": "Hardware" + }, + "metrics": { + "label": "Metrics" + }, + "role": { + "label": "Rola" + }, + "filter": { + "label": "Filtr" + }, + "advanced": { + "label": "Advanced" + }, + "clearInput": { + "label": "Clear input" + }, + "resetFilters": { + "label": "Reset Filters" + }, + "nodeName": { + "label": "Node name/number", + "placeholder": "Meshtastic 1234" + }, + "airtimeUtilization": { + "label": "Airtime Utilization (%)", + "short": "Airtime Util. (%)" + }, + "batteryLevel": { + "label": "Battery level (%)", + "labelText": "Battery level (%): {{value}}" + }, + "batteryVoltage": { + "label": "Battery voltage (V)", + "title": "Napięcie" + }, + "channelUtilization": { + "label": "Channel Utilization (%)", + "short": "Channel Util. (%)" + }, + "hops": { + "direct": "Bezpośrednio", + "label": "Number of hops", + "text": "Number of hops: {{value}}" + }, + "lastHeard": { + "label": "Aktywność", + "labelText": "Last heard: {{value}}", + "nowLabel": "Now" + }, + "snr": { + "label": "SNR (db)" + }, + "favorites": { + "label": "Favorites" + }, + "hide": { + "label": "Hide" + }, + "showOnly": { + "label": "Show Only" + }, + "viaMqtt": { + "label": "Connected via MQTT" + }, + "hopsUnknown": { + "label": "Unknown number of hops" + }, + "showUnheard": { + "label": "Never heard" + }, + "language": { + "label": "Język", + "changeLanguage": "Change Language" + }, + "theme": { + "dark": "Ciemny", + "light": "Jasny", + "system": "Automatic", + "changeTheme": "Change Color Scheme" + }, + "errorPage": { + "title": "This is a little embarrassing...", + "description1": "We are really sorry but an error occurred in the web client that caused it to crash.
This is not supposed to happen, and we are working hard to fix it.", + "description2": "The best way to prevent this from happening again to you or anyone else is to report the issue to us.", + "reportInstructions": "Please include the following information in your report:", + "reportSteps": { + "step1": "What you were doing when the error occurred", + "step2": "What you expected to happen", + "step3": "What actually happened", + "step4": "Any other relevant information" + }, + "reportLink": "You can report the issue to our <0>GitHub", + "connectionsLink": "Return to the <0>connections", + "detailsSummary": "Error Details", + "errorMessageLabel": "Error message:", + "stackTraceLabel": "Stack trace:", + "fallbackError": "{{error}}" + }, + "footer": { + "text": "Powered by <0>▲ Vercel | Meshtastic® is a registered trademark of Meshtastic LLC. | <1>Legal Information", + "commitSha": "Commit SHA: {{sha}}" + } } diff --git a/packages/web/public/i18n/locales/pt-BR/channels.json b/packages/web/public/i18n/locales/pt-BR/channels.json index 71ea2c749..5f65ffb9c 100644 --- a/packages/web/public/i18n/locales/pt-BR/channels.json +++ b/packages/web/public/i18n/locales/pt-BR/channels.json @@ -1,69 +1,71 @@ { - "page": { - "sectionLabel": "Canais", - "channelName": "Channel: {{channelName}}", - "broadcastLabel": "Primário", - "channelIndex": "Ch {{index}}" - }, - "validation": { - "pskInvalid": "Please enter a valid {{bits}} bit PSK." - }, - "settings": { - "label": "Configurações de Canal", - "description": "Crypto, MQTT & misc settings" - }, - "role": { - "label": "Função", - "description": "Device telemetry is sent over PRIMARY. Only one PRIMARY allowed", - "options": { - "primary": "PRIMARY", - "disabled": "DISABLED", - "secondary": "SECONDARY" - } - }, - "psk": { - "label": "Pre-Shared Key", - "description": "Supported PSK lengths: 256-bit, 128-bit, 8-bit, Empty (0-bit)", - "generate": "Generate" - }, - "name": { - "label": "Nome", - "description": "A unique name for the channel <12 bytes, leave blank for default" - }, - "uplinkEnabled": { - "label": "Uplink Enabled", - "description": "Send messages from the local mesh to MQTT" - }, - "downlinkEnabled": { - "label": "Downlink Enabled", - "description": "Send messages from MQTT to the local mesh" - }, - "positionPrecision": { - "label": "Location", - "description": "The precision of the location to share with the channel. Can be disabled.", - "options": { - "none": "Do not share location", - "precise": "Precise Location", - "metric_km23": "Within 23 kilometers", - "metric_km12": "Within 12 kilometers", - "metric_km5_8": "Within 5.8 kilometers", - "metric_km2_9": "Within 2.9 kilometers", - "metric_km1_5": "Within 1.5 kilometers", - "metric_m700": "Within 700 meters", - "metric_m350": "Within 350 meters", - "metric_m200": "Within 200 meters", - "metric_m90": "Within 90 meters", - "metric_m50": "Within 50 meters", - "imperial_mi15": "Within 15 miles", - "imperial_mi7_3": "Within 7.3 miles", - "imperial_mi3_6": "Within 3.6 miles", - "imperial_mi1_8": "Within 1.8 miles", - "imperial_mi0_9": "Within 0.9 miles", - "imperial_mi0_5": "Within 0.5 miles", - "imperial_mi0_2": "Within 0.2 miles", - "imperial_ft600": "Within 600 feet", - "imperial_ft300": "Within 300 feet", - "imperial_ft150": "Within 150 feet" - } - } + "page": { + "sectionLabel": "Canais", + "channelName": "Channel: {{channelName}}", + "broadcastLabel": "Primário", + "channelIndex": "Ch {{index}}", + "import": "Importar", + "export": "Export" + }, + "validation": { + "pskInvalid": "Please enter a valid {{bits}} bit PSK." + }, + "settings": { + "label": "Configurações de Canal", + "description": "Crypto, MQTT & misc settings" + }, + "role": { + "label": "Função", + "description": "Device telemetry is sent over PRIMARY. Only one PRIMARY allowed", + "options": { + "primary": "PRIMARY", + "disabled": "DISABLED", + "secondary": "SECONDARY" + } + }, + "psk": { + "label": "Pre-Shared Key", + "description": "Supported PSK lengths: 256-bit, 128-bit, 8-bit, Empty (0-bit)", + "generate": "Generate" + }, + "name": { + "label": "Nome", + "description": "A unique name for the channel <12 bytes, leave blank for default" + }, + "uplinkEnabled": { + "label": "Uplink Enabled", + "description": "Send messages from the local mesh to MQTT" + }, + "downlinkEnabled": { + "label": "Downlink Enabled", + "description": "Send messages from MQTT to the local mesh" + }, + "positionPrecision": { + "label": "Location", + "description": "The precision of the location to share with the channel. Can be disabled.", + "options": { + "none": "Do not share location", + "precise": "Precise Location", + "metric_km23": "Within 23 kilometers", + "metric_km12": "Within 12 kilometers", + "metric_km5_8": "Within 5.8 kilometers", + "metric_km2_9": "Within 2.9 kilometers", + "metric_km1_5": "Within 1.5 kilometers", + "metric_m700": "Within 700 meters", + "metric_m350": "Within 350 meters", + "metric_m200": "Within 200 meters", + "metric_m90": "Within 90 meters", + "metric_m50": "Within 50 meters", + "imperial_mi15": "Within 15 miles", + "imperial_mi7_3": "Within 7.3 miles", + "imperial_mi3_6": "Within 3.6 miles", + "imperial_mi1_8": "Within 1.8 miles", + "imperial_mi0_9": "Within 0.9 miles", + "imperial_mi0_5": "Within 0.5 miles", + "imperial_mi0_2": "Within 0.2 miles", + "imperial_ft600": "Within 600 feet", + "imperial_ft300": "Within 300 feet", + "imperial_ft150": "Within 150 feet" + } + } } diff --git a/packages/web/public/i18n/locales/pt-BR/commandPalette.json b/packages/web/public/i18n/locales/pt-BR/commandPalette.json index 6dabdcd6c..705d55ed8 100644 --- a/packages/web/public/i18n/locales/pt-BR/commandPalette.json +++ b/packages/web/public/i18n/locales/pt-BR/commandPalette.json @@ -15,7 +15,6 @@ "messages": "Mensagens", "map": "Mapa", "config": "Config", - "channels": "Canais", "nodes": "Nós" } }, @@ -45,7 +44,8 @@ "label": "Debug", "command": { "reconfigure": "Reconfigure", - "clearAllStoredMessages": "Clear All Stored Message" + "clearAllStoredMessages": "Clear All Stored Message", + "clearAllStores": "Clear All Local Storage" } } } diff --git a/packages/web/public/i18n/locales/pt-BR/common.json b/packages/web/public/i18n/locales/pt-BR/common.json index eb333dd31..7fc1e4e46 100644 --- a/packages/web/public/i18n/locales/pt-BR/common.json +++ b/packages/web/public/i18n/locales/pt-BR/common.json @@ -1,142 +1,165 @@ { - "button": { - "apply": "Aplicar", - "backupKey": "Backup Key", - "cancel": "Cancelar", - "clearMessages": "Clear Messages", - "close": "Fechar", - "confirm": "Confirm", - "delete": "Excluir", - "dismiss": "Ignorar", - "download": "Baixar", - "export": "Export", - "generate": "Generate", - "regenerate": "Regenerate", - "import": "Importar", - "message": "Mensagem", - "now": "Now", - "ok": "Ok", - "print": "Print", - "remove": "Excluir", - "requestNewKeys": "Request New Keys", - "requestPosition": "Request Position", - "reset": "Redefinir", - "save": "Salvar", - "scanQr": "Escanear Código QR", - "traceRoute": "Trace Route", - "submit": "Submit" - }, - "app": { - "title": "Meshtastic", - "fullTitle": "Meshtastic Web Client" - }, - "loading": "Loading...", - "unit": { - "cps": "CPS", - "dbm": "dBm", - "hertz": "Hz", - "hop": { - "one": "Hop", - "plural": "Hops" - }, - "hopsAway": { - "one": "{{count}} hop away", - "plural": "{{count}} hops away", - "unknown": "Unknown hops away" - }, - "megahertz": "MHz", - "raw": "raw", - "meter": { - "one": "Meter", - "plural": "Meters", - "suffix": "m" - }, - "minute": { - "one": "Minute", - "plural": "Minutes" - }, - "hour": { - "one": "Hour", - "plural": "Hours" - }, - "millisecond": { - "one": "Millisecond", - "plural": "Milliseconds", - "suffix": "ms" - }, - "second": { - "one": "Second", - "plural": "Seconds" - }, - "day": { - "one": "Day", - "plural": "Days" - }, - "month": { - "one": "Month", - "plural": "Months" - }, - "year": { - "one": "Year", - "plural": "Years" - }, - "snr": "SNR", - "volt": { - "one": "Volt", - "plural": "Volts", - "suffix": "V" - }, - "record": { - "one": "Records", - "plural": "Records" - } - }, - "security": { - "0bit": "Empty", - "8bit": "8 bit", - "128bit": "128 bit", - "256bit": "256 bit" - }, - "unknown": { - "longName": "Desconhecido", - "shortName": "UNK", - "notAvailable": "N/A", - "num": "??" - }, - "nodeUnknownPrefix": "!", - "unset": "UNSET", - "fallbackName": "Meshtastic {{last4}}", - "node": "Node", - "formValidation": { - "unsavedChanges": "Unsaved changes", - "tooBig": { - "string": "Too long, expected less than or equal to {{maximum}} characters.", - "number": "Too big, expected a number smaller than or equal to {{maximum}}.", - "bytes": "Too big, expected less than or equal to {{params.maximum}} bytes." - }, - "tooSmall": { - "string": "Too short, expected more than or equal to {{minimum}} characters.", - "number": "Too small, expected a number larger than or equal to {{minimum}}." - }, - "invalidFormat": { - "ipv4": "Invalid format, expected an IPv4 address.", - "key": "Invalid format, expected a Base64 encoded pre-shared key (PSK)." - }, - "invalidType": { - "number": "Invalid type, expected a number." - }, - "pskLength": { - "0bit": "Key is required to be empty.", - "8bit": "Key is required to be an 8 bit pre-shared key (PSK).", - "128bit": "Key is required to be a 128 bit pre-shared key (PSK).", - "256bit": "Key is required to be a 256 bit pre-shared key (PSK)." - }, - "required": { - "generic": "This field is required.", - "managed": "At least one admin key is requred if the node is managed.", - "key": "Key is required." - } - }, - "yes": "Yes", - "no": "No" + "button": { + "apply": "Aplicar", + "addConnection": "Add Connection", + "saveConnection": "Save connection", + "backupKey": "Backup Key", + "cancel": "Cancelar", + "connect": "Connect", + "clearMessages": "Clear Messages", + "close": "Fechar", + "confirm": "Confirm", + "delete": "Excluir", + "dismiss": "Ignorar", + "download": "Baixar", + "disconnect": "Desconectar", + "export": "Export", + "generate": "Generate", + "regenerate": "Regenerate", + "import": "Importar", + "message": "Mensagem", + "now": "Now", + "ok": "Ok", + "print": "Print", + "remove": "Excluir", + "requestNewKeys": "Request New Keys", + "requestPosition": "Request Position", + "reset": "Redefinir", + "retry": "Retry", + "save": "Salvar", + "setDefault": "Set as default", + "unsetDefault": "Unset default", + "scanQr": "Escanear Código QR", + "traceRoute": "Trace Route", + "submit": "Submit" + }, + "app": { + "title": "Meshtastic", + "fullTitle": "Meshtastic Web Client" + }, + "loading": "Loading...", + "unit": { + "cps": "CPS", + "dbm": "dBm", + "hertz": "Hz", + "hop": { + "one": "Hop", + "plural": "Hops" + }, + "hopsAway": { + "one": "{{count}} hop away", + "plural": "{{count}} hops away", + "unknown": "Unknown hops away" + }, + "megahertz": "MHz", + "kilohertz": "kHz", + "raw": "raw", + "meter": { + "one": "Meter", + "plural": "Meters", + "suffix": "m" + }, + "kilometer": { + "one": "Kilometer", + "plural": "Kilometers", + "suffix": "km" + }, + "minute": { + "one": "Minute", + "plural": "Minutes" + }, + "hour": { + "one": "Hour", + "plural": "Hours" + }, + "millisecond": { + "one": "Millisecond", + "plural": "Milliseconds", + "suffix": "ms" + }, + "second": { + "one": "Second", + "plural": "Seconds" + }, + "day": { + "one": "Day", + "plural": "Days", + "today": "Today", + "yesterday": "Yesterday" + }, + "month": { + "one": "Month", + "plural": "Months" + }, + "year": { + "one": "Year", + "plural": "Years" + }, + "snr": "SNR", + "volt": { + "one": "Volt", + "plural": "Volts", + "suffix": "V" + }, + "record": { + "one": "Records", + "plural": "Records" + }, + "degree": { + "one": "Degree", + "plural": "Degrees", + "suffix": "°" + } + }, + "security": { + "0bit": "Empty", + "8bit": "8 bit", + "128bit": "128 bit", + "256bit": "256 bit" + }, + "unknown": { + "longName": "Desconhecido", + "shortName": "UNK", + "notAvailable": "N/A", + "num": "??" + }, + "nodeUnknownPrefix": "!", + "unset": "UNSET", + "fallbackName": "Meshtastic {{last4}}", + "node": "Node", + "formValidation": { + "unsavedChanges": "Unsaved changes", + "tooBig": { + "string": "Too long, expected less than or equal to {{maximum}} characters.", + "number": "Too big, expected a number smaller than or equal to {{maximum}}.", + "bytes": "Too big, expected less than or equal to {{params.maximum}} bytes." + }, + "tooSmall": { + "string": "Too short, expected more than or equal to {{minimum}} characters.", + "number": "Too small, expected a number larger than or equal to {{minimum}}." + }, + "invalidFormat": { + "ipv4": "Invalid format, expected an IPv4 address.", + "key": "Invalid format, expected a Base64 encoded pre-shared key (PSK)." + }, + "invalidType": { + "number": "Invalid type, expected a number." + }, + "pskLength": { + "0bit": "Key is required to be empty.", + "8bit": "Key is required to be an 8 bit pre-shared key (PSK).", + "128bit": "Key is required to be a 128 bit pre-shared key (PSK).", + "256bit": "Key is required to be a 256 bit pre-shared key (PSK)." + }, + "required": { + "generic": "This field is required.", + "managed": "At least one admin key is requred if the node is managed.", + "key": "Key is required." + }, + "invalidOverrideFreq": { + "number": "Invalid format, expected a value in the range 410-930 MHz or 0 (use default)." + } + }, + "yes": "Yes", + "no": "No" } diff --git a/packages/web/public/i18n/locales/pt-BR/config.json b/packages/web/public/i18n/locales/pt-BR/config.json new file mode 100644 index 000000000..f6218e54e --- /dev/null +++ b/packages/web/public/i18n/locales/pt-BR/config.json @@ -0,0 +1,458 @@ +{ + "page": { + "title": "Configurações", + "tabUser": "Usuário", + "tabChannels": "Canais", + "tabBluetooth": "Bluetooth", + "tabDevice": "Dispositivo", + "tabDisplay": "Tela", + "tabLora": "LoRa", + "tabNetwork": "Rede", + "tabPosition": "Posição", + "tabPower": "Energia", + "tabSecurity": "Segurança" + }, + "sidebar": { + "label": "Configuration" + }, + "device": { + "title": "Device Settings", + "description": "Settings for the device", + "buttonPin": { + "description": "Button pin override", + "label": "Button Pin" + }, + "buzzerPin": { + "description": "Buzzer pin override", + "label": "Buzzer Pin" + }, + "disableTripleClick": { + "description": "Disable triple click", + "label": "Disable Triple Click" + }, + "doubleTapAsButtonPress": { + "description": "Treat double tap as button press", + "label": "Double Tap as Button Press" + }, + "ledHeartbeatDisabled": { + "description": "Disable default blinking LED", + "label": "LED Heartbeat Disabled" + }, + "nodeInfoBroadcastInterval": { + "description": "How often to broadcast node info", + "label": "Node Info Broadcast Interval" + }, + "posixTimezone": { + "description": "The POSIX timezone string for the device", + "label": "Fuso horário POSIX" + }, + "rebroadcastMode": { + "description": "How to handle rebroadcasting", + "label": "Rebroadcast Mode" + }, + "role": { + "description": "What role the device performs on the mesh", + "label": "Função" + } + }, + "bluetooth": { + "title": "Bluetooth Settings", + "description": "Settings for the Bluetooth module", + "note": "Note: Some devices (ESP32) cannot use both Bluetooth and WiFi at the same time.", + "enabled": { + "description": "Enable or disable Bluetooth", + "label": "Enabled" + }, + "pairingMode": { + "description": "Pin selection behaviour.", + "label": "Modo de pareamento" + }, + "pin": { + "description": "Pin to use when pairing", + "label": "Pin" + } + }, + "display": { + "description": "Settings for the device display", + "title": "Display Settings", + "headingBold": { + "description": "Bolden the heading text", + "label": "Bold Heading" + }, + "carouselDelay": { + "description": "How fast to cycle through windows", + "label": "Carousel Delay" + }, + "compassNorthTop": { + "description": "Fix north to the top of compass", + "label": "Compass North Top" + }, + "displayMode": { + "description": "Screen layout variant", + "label": "Display Mode" + }, + "displayUnits": { + "description": "Display metric or imperial units", + "label": "Display Units" + }, + "flipScreen": { + "description": "Flip display 180 degrees", + "label": "Flip Screen" + }, + "gpsDisplayUnits": { + "description": "Coordinate display format", + "label": "GPS Display Units" + }, + "oledType": { + "description": "Type of OLED screen attached to the device", + "label": "OLED Type" + }, + "screenTimeout": { + "description": "Turn off the display after this long", + "label": "Screen Timeout" + }, + "twelveHourClock": { + "description": "Use 12-hour clock format", + "label": "12-Hour Clock" + }, + "wakeOnTapOrMotion": { + "description": "Wake the device on tap or motion", + "label": "Wake on Tap or Motion" + } + }, + "lora": { + "title": "Mesh Settings", + "description": "Settings for the LoRa mesh", + "bandwidth": { + "description": "Channel bandwidth in kHz", + "label": "Largura da banda" + }, + "boostedRxGain": { + "description": "Boosted RX gain", + "label": "Boosted RX Gain" + }, + "codingRate": { + "description": "The denominator of the coding rate", + "label": "Coding Rate" + }, + "frequencyOffset": { + "description": "Frequency offset to correct for crystal calibration errors", + "label": "Frequency Offset" + }, + "frequencySlot": { + "description": "LoRa frequency channel number", + "label": "Frequency Slot" + }, + "hopLimit": { + "description": "Maximum number of hops", + "label": "Hop Limit" + }, + "ignoreMqtt": { + "description": "Don't forward MQTT messages over the mesh", + "label": "Ignorar MQTT" + }, + "modemPreset": { + "description": "Modem preset to use", + "label": "Predefinição do Modem" + }, + "okToMqtt": { + "description": "When set to true, this configuration indicates that the user approves the packet to be uploaded to MQTT. If set to false, remote nodes are requested not to forward packets to MQTT", + "label": "OK para MQTT" + }, + "overrideDutyCycle": { + "description": "Ignorar ciclo de trabalho", + "label": "Ignorar ciclo de trabalho" + }, + "overrideFrequency": { + "description": "Override frequency", + "label": "Override Frequency" + }, + "region": { + "description": "Sets the region for your node", + "label": "Região" + }, + "spreadingFactor": { + "description": "Indicates the number of chirps per symbol", + "label": "Spreading Factor" + }, + "transmitEnabled": { + "description": "Enable/Disable transmit (TX) from the LoRa radio", + "label": "Transmit Enabled" + }, + "transmitPower": { + "description": "Max transmit power", + "label": "Transmit Power" + }, + "usePreset": { + "description": "Use one of the predefined modem presets", + "label": "Use Preset" + }, + "meshSettings": { + "description": "Settings for the LoRa mesh", + "label": "Mesh Settings" + }, + "waveformSettings": { + "description": "Settings for the LoRa waveform", + "label": "Waveform Settings" + }, + "radioSettings": { + "label": "Radio Settings", + "description": "Settings for the LoRa radio" + } + }, + "network": { + "title": "WiFi Config", + "description": "WiFi radio configuration", + "note": "Note: Some devices (ESP32) cannot use both Bluetooth and WiFi at the same time.", + "addressMode": { + "description": "Address assignment selection", + "label": "Address Mode" + }, + "dns": { + "description": "DNS Server", + "label": "DNS" + }, + "ethernetEnabled": { + "description": "Enable or disable the Ethernet port", + "label": "Enabled" + }, + "gateway": { + "description": "Default Gateway", + "label": "Gateway" + }, + "ip": { + "description": "IP Address", + "label": "IP" + }, + "psk": { + "description": "Network password", + "label": "PSK" + }, + "ssid": { + "description": "Network name", + "label": "SSID" + }, + "subnet": { + "description": "Subnet Mask", + "label": "Subnet" + }, + "wifiEnabled": { + "description": "Enable or disable the WiFi radio", + "label": "Enabled" + }, + "meshViaUdp": { + "label": "Mesh via UDP" + }, + "ntpServer": { + "label": "NTP Server" + }, + "rsyslogServer": { + "label": "Rsyslog Server" + }, + "ethernetConfigSettings": { + "description": "Ethernet port configuration", + "label": "Ethernet Config" + }, + "ipConfigSettings": { + "description": "IP configuration", + "label": "IP Config" + }, + "ntpConfigSettings": { + "description": "NTP configuration", + "label": "NTP Config" + }, + "rsyslogConfigSettings": { + "description": "Rsyslog configuration", + "label": "Rsyslog Config" + }, + "udpConfigSettings": { + "description": "UDP over Mesh configuration", + "label": "Configuração UDP" + } + }, + "position": { + "title": "Position Settings", + "description": "Settings for the position module", + "broadcastInterval": { + "description": "How often your position is sent out over the mesh", + "label": "Broadcast Interval" + }, + "enablePin": { + "description": "GPS module enable pin override", + "label": "Enable Pin" + }, + "fixedPosition": { + "description": "Don't report GPS position, but a manually-specified one", + "label": "Fixed Position" + }, + "gpsMode": { + "description": "Configure whether device GPS is Enabled, Disabled, or Not Present", + "label": "GPS Mode" + }, + "gpsUpdateInterval": { + "description": "How often a GPS fix should be acquired", + "label": "GPS Update Interval" + }, + "positionFlags": { + "description": "Optional fields to include when assembling position messages. The more fields are selected, the larger the message will be leading to longer airtime usage and a higher risk of packet loss.", + "label": "Position Flags" + }, + "receivePin": { + "description": "GPS module RX pin override", + "label": "Receive Pin" + }, + "smartPositionEnabled": { + "description": "Only send position when there has been a meaningful change in location", + "label": "Enable Smart Position" + }, + "smartPositionMinDistance": { + "description": "Minimum distance (in meters) that must be traveled before a position update is sent", + "label": "Smart Position Minimum Distance" + }, + "smartPositionMinInterval": { + "description": "Minimum interval (in seconds) that must pass before a position update is sent", + "label": "Smart Position Minimum Interval" + }, + "transmitPin": { + "description": "GPS module TX pin override", + "label": "Transmit Pin" + }, + "intervalsSettings": { + "description": "How often to send position updates", + "label": "Intervals" + }, + "flags": { + "placeholder": "Select position flags...", + "altitude": "Altitude", + "altitudeGeoidalSeparation": "Altitude Geoidal Separation", + "altitudeMsl": "Altitude is Mean Sea Level", + "dop": "Dilution of precision (DOP) PDOP used by default", + "hdopVdop": "If DOP is set, use HDOP / VDOP values instead of PDOP", + "numSatellites": "Number of satellites", + "sequenceNumber": "Sequence number", + "timestamp": "Data e hora", + "unset": "Não definido", + "vehicleHeading": "Vehicle heading", + "vehicleSpeed": "Vehicle speed" + } + }, + "power": { + "adcMultiplierOverride": { + "description": "Used for tweaking battery voltage reading", + "label": "ADC Multiplier Override ratio" + }, + "ina219Address": { + "description": "Address of the INA219 battery monitor", + "label": "INA219 Address" + }, + "lightSleepDuration": { + "description": "How long the device will be in light sleep for", + "label": "Light Sleep Duration" + }, + "minimumWakeTime": { + "description": "Minimum amount of time the device will stay awake for after receiving a packet", + "label": "Minimum Wake Time" + }, + "noConnectionBluetoothDisabled": { + "description": "If the device does not receive a Bluetooth connection, the BLE radio will be disabled after this long", + "label": "No Connection Bluetooth Disabled" + }, + "powerSavingEnabled": { + "description": "Select if powered from a low-current source (i.e. solar), to minimize power consumption as much as possible.", + "label": "Ativar modo de economia de energia" + }, + "shutdownOnBatteryDelay": { + "description": "Automatically shutdown node after this long when on battery, 0 for indefinite", + "label": "Shutdown on battery delay" + }, + "superDeepSleepDuration": { + "description": "How long the device will be in super deep sleep for", + "label": "Super Deep Sleep Duration" + }, + "powerConfigSettings": { + "description": "Settings for the power module", + "label": "Configuração de Energia" + }, + "sleepSettings": { + "description": "Sleep settings for the power module", + "label": "Sleep Settings" + } + }, + "security": { + "description": "Settings for the Security configuration", + "title": "Security Settings", + "button_backupKey": "Backup Key", + "adminChannelEnabled": { + "description": "Allow incoming device control over the insecure legacy admin channel", + "label": "Allow Legacy Admin" + }, + "enableDebugLogApi": { + "description": "Output live debug logging over serial, view and export position-redacted device logs over Bluetooth", + "label": "Enable Debug Log API" + }, + "managed": { + "description": "If enabled, device configuration options are only able to be changed remotely by a Remote Admin node via admin messages. Do not enable this option unless at least one suitable Remote Admin node has been setup, and the public key is stored in one of the fields above.", + "label": "Managed" + }, + "privateKey": { + "description": "Used to create a shared key with a remote device", + "label": "Chave Privada" + }, + "publicKey": { + "description": "Sent out to other nodes on the mesh to allow them to compute a shared secret key", + "label": "Chave Publica" + }, + "primaryAdminKey": { + "description": "The primary public key authorized to send admin messages to this node", + "label": "Primary Admin Key" + }, + "secondaryAdminKey": { + "description": "The secondary public key authorized to send admin messages to this node", + "label": "Secondary Admin Key" + }, + "serialOutputEnabled": { + "description": "Serial Console over the Stream API", + "label": "Serial Output Enabled" + }, + "tertiaryAdminKey": { + "description": "The tertiary public key authorized to send admin messages to this node", + "label": "Tertiary Admin Key" + }, + "adminSettings": { + "description": "Settings for Admin", + "label": "Admin Settings" + }, + "loggingSettings": { + "description": "Settings for Logging", + "label": "Logging Settings" + } + }, + "user": { + "title": "User Settings", + "description": "Configure your device name and identity settings", + "longName": { + "label": "Long Name", + "description": "Your full display name (1-40 characters)", + "validation": { + "min": "Long name must be at least 1 character", + "max": "Long name must be at most 40 characters" + } + }, + "shortName": { + "label": "Short Name", + "description": "Your abbreviated name (2-4 characters)", + "validation": { + "min": "Short name must be at least 2 characters", + "max": "Short name must be at most 4 characters" + } + }, + "isUnmessageable": { + "label": "Impossível enviar mensagens", + "description": "Used to identify unmonitored or infrastructure nodes so that messaging is not available to nodes that will never respond." + }, + "isLicensed": { + "label": "Rádio Amador Licenciado (HAM)", + "description": "Enable if you are a licensed amateur radio operator, enabling this option disables encryption and is not compatible with the default Meshtastic network." + } + } +} diff --git a/packages/web/public/i18n/locales/pt-BR/connections.json b/packages/web/public/i18n/locales/pt-BR/connections.json new file mode 100644 index 000000000..db3fd9de7 --- /dev/null +++ b/packages/web/public/i18n/locales/pt-BR/connections.json @@ -0,0 +1,34 @@ +{ + "page": { + "title": "Connect to a Meshtastic device", + "description": "Add a device connection via HTTP, Bluetooth, or Serial. Your saved connections will be saved in your browser." + }, + "connectionType_ble": "BLE", + "connectionType_serial": "Serial", + "connectionType_network": "Rede", + "deleteConnection": "Delete connection", + "areYouSure": "This will remove {{name}}. You canot undo this action.", + "moreActions": "More actions", + "noConnections": { + "title": "No connections yet.", + "description": "Create your first connection. It will connect immediately and be saved for later." + }, + "lastConnectedAt": "Last connected: {{date}}", + "neverConnected": "Never connected", + "toasts": { + "connected": "Conectado", + "nowConnected": "{{name}} is now connected", + "nowDisconnected": "{{name}} are now disconnecte", + "disconnected": "Desconectado", + "failed": "Failed to connect", + "checkConnetion": "Check your device or settings and try again", + "defaultSet": "Default set", + "defaultConnection": "Default connection is now {{nameisconnected}}", + "deleted": "Deleted", + "deletedByName": "{{name}} was removed", + "pickConnectionAgain": "Could not connect. You may need to reselect the device/port.", + "added": "Connection added", + "savedByName": "{{name}} saved.", + "savedCantConnect": "The connection was saved but could not connect." + } +} diff --git a/packages/web/public/i18n/locales/pt-BR/dashboard.json b/packages/web/public/i18n/locales/pt-BR/dashboard.json deleted file mode 100644 index 3a2d606c5..000000000 --- a/packages/web/public/i18n/locales/pt-BR/dashboard.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "dashboard": { - "title": "Connected Devices", - "description": "Manage your connected Meshtastic devices.", - "connectionType_ble": "BLE", - "connectionType_serial": "Serial", - "connectionType_network": "Rede", - "noDevicesTitle": "No devices connected", - "noDevicesDescription": "Connect a new device to get started.", - "button_newConnection": "New Connection" - } -} diff --git a/packages/web/public/i18n/locales/pt-BR/deviceConfig.json b/packages/web/public/i18n/locales/pt-BR/deviceConfig.json index c19644b41..3a2f05011 100644 --- a/packages/web/public/i18n/locales/pt-BR/deviceConfig.json +++ b/packages/web/public/i18n/locales/pt-BR/deviceConfig.json @@ -122,7 +122,7 @@ "title": "Mesh Settings", "description": "Settings for the LoRa mesh", "bandwidth": { - "description": "Channel bandwidth in MHz", + "description": "Channel bandwidth in kHz", "label": "Largura da banda" }, "boostedRxGain": { diff --git a/packages/web/public/i18n/locales/pt-BR/dialog.json b/packages/web/public/i18n/locales/pt-BR/dialog.json index 8a9c02802..871acce42 100644 --- a/packages/web/public/i18n/locales/pt-BR/dialog.json +++ b/packages/web/public/i18n/locales/pt-BR/dialog.json @@ -1,193 +1,238 @@ { - "deleteMessages": { - "description": "This action will clear all message history. This cannot be undone. Are you sure you want to continue?", - "title": "Clear All Messages" - }, - "deviceName": { - "description": "The Device will restart once the config is saved.", - "longName": "Long Name", - "shortName": "Short Name", - "title": "Change Device Name", - "validation": { - "longNameMax": "Long name must not be more than 40 characters", - "shortNameMax": "Short name must not be more than 4 characters", - "longNameMin": "Long name must have at least 1 character", - "shortNameMin": "Short name must have at least 1 character" - } - }, - "import": { - "description": "The current LoRa configuration will be overridden.", - "error": { - "invalidUrl": "Invalid Meshtastic URL" - }, - "channelPrefix": "Channel: ", - "channelSetUrl": "Channel Set/QR Code URL", - "channels": "Channels:", - "usePreset": "Use Preset?", - "title": "Import Channel Set" - }, - "locationResponse": { - "title": "Location: {{identifier}}", - "altitude": "Altitude: ", - "coordinates": "Coordinates: ", - "noCoordinates": "No Coordinates" - }, - "pkiRegenerateDialog": { - "title": "Regenerate Pre-Shared Key?", - "description": "Are you sure you want to regenerate the pre-shared key?", - "regenerate": "Regenerate" - }, - "newDeviceDialog": { - "title": "Connect New Device", - "https": "https", - "http": "http", - "tabHttp": "HTTP", - "tabBluetooth": "Bluetooth", - "tabSerial": "Serial", - "useHttps": "Use HTTPS", - "connecting": "Connecting...", - "connect": "Connect", - "connectionFailedAlert": { - "title": "Connection Failed", - "descriptionPrefix": "Could not connect to the device. ", - "httpsHint": "If using HTTPS, you may need to accept a self-signed certificate first. ", - "openLinkPrefix": "Please open ", - "openLinkSuffix": " in a new tab", - "acceptTlsWarningSuffix": ", accept any TLS warnings if prompted, then try again", - "learnMoreLink": "Learn more" - }, - "httpConnection": { - "label": "IP Address/Hostname", - "placeholder": "000.000.000.000 / meshtastic.local" - }, - "serialConnection": { - "noDevicesPaired": "No devices paired yet.", - "newDeviceButton": "New device", - "deviceIdentifier": "# {{index}} - {{vendorId}} - {{productId}}" - }, - "bluetoothConnection": { - "noDevicesPaired": "No devices paired yet.", - "newDeviceButton": "New device", - "connectionFailed": "Connection failed", - "deviceDisconnected": "Device disconnected", - "unknownDevice": "Unknown Device", - "errorLoadingDevices": "Error loading devices", - "unknownErrorLoadingDevices": "Unknown error loading devices" - }, - "validation": { - "requiresWebBluetooth": "This connection type requires <0>Web Bluetooth. Please use a supported browser, like Chrome or Edge.", - "requiresWebSerial": "This connection type requires <0>Web Serial. Please use a supported browser, like Chrome or Edge.", - "requiresSecureContext": "This application requires a <0>secure context. Please connect using HTTPS or localhost.", - "additionallyRequiresSecureContext": "Additionally, it requires a <0>secure context. Please connect using HTTPS or localhost." - } - }, - "nodeDetails": { - "message": "Mensagem", - "requestPosition": "Request Position", - "traceRoute": "Trace Route", - "airTxUtilization": "Air TX utilization", - "allRawMetrics": "All Raw Metrics:", - "batteryLevel": "Battery level", - "channelUtilization": "Channel utilization", - "details": "Details:", - "deviceMetrics": "Device Metrics:", - "hardware": "Hardware: ", - "lastHeard": "Last Heard: ", - "nodeHexPrefix": "Node Hex: ", - "nodeNumber": "Node Number: ", - "position": "Position:", - "role": "Role: ", - "uptime": "Uptime: ", - "voltage": "Voltagem", - "title": "Node Details for {{identifier}}", - "ignoreNode": "Ignore node", - "removeNode": "Remove node", - "unignoreNode": "Unignore node", - "security": "Security:", - "publicKey": "Public Key: ", - "messageable": "Messageable: ", - "KeyManuallyVerifiedTrue": "Public Key has been manually verified", - "KeyManuallyVerifiedFalse": "Public Key is not manually verified" - }, - "pkiBackup": { - "loseKeysWarning": "If you lose your keys, you will need to reset your device.", - "secureBackup": "Its important to backup your public and private keys and store your backup securely!", - "footer": "=== END OF KEYS ===", - "header": "=== MESHTASTIC KEYS FOR {{longName}} ({{shortName}}) ===", - "privateKey": "Private Key:", - "publicKey": "Public Key:", - "fileName": "meshtastic_keys_{{longName}}_{{shortName}}.txt", - "title": "Backup Keys" - }, - "pkiBackupReminder": { - "description": "We recommend backing up your key data regularly. Would you like to back up now?", - "title": "Backup Reminder", - "remindLaterPrefix": "Remind me in", - "remindNever": "Never remind me", - "backupNow": "Back up now" - }, - "pkiRegenerate": { - "description": "Are you sure you want to regenerate key pair?", - "title": "Regenerate Key Pair" - }, - "qr": { - "addChannels": "Add Channels", - "replaceChannels": "Replace Channels", - "description": "The current LoRa configuration will also be shared.", - "sharableUrl": "Sharable URL", - "title": "Generate QR Code" - }, - "reboot": { - "title": "Reboot device", - "description": "Reboot now or schedule a reboot of the connected node. Optionally, you can choose to reboot into OTA (Over-the-Air) mode.", - "ota": "Reboot into OTA mode", - "enterDelay": "Enter delay", - "scheduled": "Reboot has been scheduled", - "schedule": "Schedule reboot", - "now": "Reboot now", - "cancel": "Cancel scheduled reboot" - }, - "refreshKeys": { - "description": { - "acceptNewKeys": "This will remove the node from device and request new keys.", - "keyMismatchReasonSuffix": ". This is due to the remote node's current public key does not match the previously stored key for this node.", - "unableToSendDmPrefix": "Your node is unable to send a direct message to node: " - }, - "acceptNewKeys": "Accept New Keys", - "title": "Keys Mismatch - {{identifier}}" - }, - "removeNode": { - "description": "Are you sure you want to remove this Node?", - "title": "Remove Node?" - }, - "shutdown": { - "title": "Schedule Shutdown", - "description": "Turn off the connected node after x minutes." - }, - "traceRoute": { - "routeToDestination": "Route to destination:", - "routeBack": "Route back:" - }, - "tracerouteResponse": { - "title": "Traceroute: {{identifier}}" - }, - "unsafeRoles": { - "confirmUnderstanding": "Yes, I know what I'm doing", - "conjunction": " and the blog post about ", - "postamble": " and understand the implications of changing the role.", - "preamble": "I have read the ", - "choosingRightDeviceRole": "Choosing The Right Device Role", - "deviceRoleDocumentation": "Device Role Documentation", - "title": "Você tem certeza?" - }, - "managedMode": { - "confirmUnderstanding": "Yes, I know what I'm doing", - "title": "Você tem certeza?", - "description": "Enabling Managed Mode blocks client applications (including the web client) from writing configurations to a radio. Once enabled, radio configurations can only be changed through Remote Admin messages. This setting is not required for remote node administration." - }, - "clientNotification": { - "title": "Notificação de cliente", - "TraceRoute can only be sent once every 30 seconds": "TraceRoute can only be sent once every 30 seconds", - "Compromised keys were detected and regenerated.": "Compromised keys were detected and regenerated." - } + "deleteMessages": { + "description": "This action will clear all message history. This cannot be undone. Are you sure you want to continue?", + "title": "Clear All Messages" + }, + "import": { + "description": "The current LoRa configuration will be overridden.", + "error": { + "invalidUrl": "Invalid Meshtastic URL" + }, + "channelPrefix": "Channel: ", + "primary": "Primary ", + "doNotImport": "No not import", + "channelName": "Nome", + "channelSlot": "Slot", + "channelSetUrl": "Channel Set/QR Code URL", + "useLoraConfig": "Import LoRa Config", + "presetDescription": "The current LoRa Config will be replaced.", + "title": "Import Channel Set" + }, + "locationResponse": { + "title": "Location: {{identifier}}", + "altitude": "Altitude: ", + "coordinates": "Coordinates: ", + "noCoordinates": "No Coordinates" + }, + "pkiRegenerateDialog": { + "title": "Regenerate Pre-Shared Key?", + "description": "Are you sure you want to regenerate the pre-shared key?", + "regenerate": "Regenerate" + }, + "addConnection": { + "title": "Add connection", + "description": "Choose a connection type and fill in the details", + "validation": { + "requiresWebBluetooth": "This connection type requires <0>Web Bluetooth. Please use a supported browser, like Chrome or Edge.", + "requiresWebSerial": "This connection type requires <0>Web Serial. Please use a supported browser, like Chrome or Edge.", + "requiresSecureContext": "This application requires a <0>secure context. Please connect using HTTPS or localhost.", + "additionallyRequiresSecureContext": "Additionally, it requires a <0>secure context. Please connect using HTTPS or localhost." + }, + "bluetoothConnection": { + "namePlaceholder": "My Bluetooth Node", + "supported": { + "title": "Web Bluetooth supported" + }, + "notSupported": { + "title": "Web Bluetooth not supported", + "description": "Your browser or device does not support Web Bluetooth" + }, + "short": "BT: {{deviceName}}", + "long": "Bluetooth Device", + "device": "Dispositivo", + "selectDevice": "Select device", + "selected": "Bluetooth device selected", + "notSelected": "No device selected", + "helperText": "Uses the Meshtastic Bluetooth service for discovery." + }, + "serialConnection": { + "namePlaceholder": "My Serial Node", + "helperText": "Selecting a port grants permission so the app can open it to connect.", + "supported": { + "title": "Web Serial supported" + }, + "notSupported": { + "title": "Web Serial not supported", + "description": "Your browser or device does not support Web Serial" + }, + "portSelected": { + "title": "Serial port selected", + "description": "Port permissions granted." + }, + "port": "Port", + "selectPort": "Select port", + "deviceName": "USB {{vendorId}}:{{productId}}", + "notSelected": "No port selected" + }, + "httpConnection": { + "namePlaceholder": "My HTTP Node", + "inputPlaceholder": "192.168.1.10 or meshtastic.local", + "heading": "URL or IP", + "useHttps": "Use HTTTPS", + "invalidUrl": { + "title": "Invalid URL", + "description": "Please enter a valid HTTP or HTTPS URL." + }, + "connectionTest": { + "description": "Test the connetion before saving to verify the device is reachable.", + "button": { + "loading": "Testing...", + "label": "Test connection" + }, + "reachable": "Reachable", + "notReachable": "Not reachable", + "success": { + "title": "Connection test successful", + "description": "The device appears to be reachable." + }, + "failure": { + "title": "Connection test failed", + "description": "Could not reach the device. Check the URL and try again." + } + } + } + }, + "nodeDetails": { + "message": "Mensagem", + "requestPosition": "Request Position", + "traceRoute": "Trace Route", + "airTxUtilization": "Air TX utilization", + "allRawMetrics": "All Raw Metrics:", + "batteryLevel": "Battery level", + "channelUtilization": "Channel utilization", + "details": "Details:", + "deviceMetrics": "Device Metrics:", + "hardware": "Hardware: ", + "lastHeard": "Last Heard: ", + "nodeHexPrefix": "Node Hex: ", + "nodeNumber": "Node Number: ", + "position": "Position:", + "role": "Role: ", + "uptime": "Uptime: ", + "voltage": "Voltagem", + "title": "Node Details for {{identifier}}", + "ignoreNode": "Ignore node", + "removeNode": "Remove node", + "unignoreNode": "Unignore node", + "security": "Security:", + "publicKey": "Public Key: ", + "messageable": "Messageable: ", + "KeyManuallyVerifiedTrue": "Public Key has been manually verified", + "KeyManuallyVerifiedFalse": "Public Key is not manually verified" + }, + "pkiBackup": { + "loseKeysWarning": "If you lose your keys, you will need to reset your device.", + "secureBackup": "Its important to backup your public and private keys and store your backup securely!", + "footer": "=== END OF KEYS ===", + "header": "=== MESHTASTIC KEYS FOR {{longName}} ({{shortName}}) ===", + "privateKey": "Private Key:", + "publicKey": "Public Key:", + "fileName": "meshtastic_keys_{{longName}}_{{shortName}}.txt", + "title": "Backup Keys" + }, + "pkiBackupReminder": { + "description": "We recommend backing up your key data regularly. Would you like to back up now?", + "title": "Backup Reminder", + "remindLaterPrefix": "Remind me in", + "remindNever": "Never remind me", + "backupNow": "Back up now" + }, + "pkiRegenerate": { + "description": "Are you sure you want to regenerate key pair?", + "title": "Regenerate Key Pair" + }, + "qr": { + "addChannels": "Add Channels", + "replaceChannels": "Replace Channels", + "description": "The current LoRa configuration will also be shared.", + "sharableUrl": "Sharable URL", + "title": "Generate QR Code" + }, + "reboot": { + "title": "Reboot device", + "description": "Reboot now or schedule a reboot of the connected node. Optionally, you can choose to reboot into OTA (Over-the-Air) mode.", + "ota": "Reboot into OTA mode", + "enterDelay": "Enter delay", + "scheduled": "Reboot has been scheduled", + "schedule": "Schedule reboot", + "now": "Reboot now", + "cancel": "Cancel scheduled reboot" + }, + "refreshKeys": { + "description": { + "acceptNewKeys": "This will remove the node from device and request new keys.", + "keyMismatchReasonSuffix": ". This is due to the remote node's current public key does not match the previously stored key for this node.", + "unableToSendDmPrefix": "Your node is unable to send a direct message to node: " + }, + "acceptNewKeys": "Accept New Keys", + "title": "Keys Mismatch - {{identifier}}" + }, + "removeNode": { + "description": "Are you sure you want to remove this Node?", + "title": "Remove Node?" + }, + "shutdown": { + "title": "Schedule Shutdown", + "description": "Turn off the connected node after x minutes." + }, + "traceRoute": { + "routeToDestination": "Route to destination:", + "routeBack": "Route back:" + }, + "tracerouteResponse": { + "title": "Traceroute: {{identifier}}" + }, + "unsafeRoles": { + "confirmUnderstanding": "Yes, I know what I'm doing", + "conjunction": " and the blog post about ", + "postamble": " and understand the implications of changing the role.", + "preamble": "I have read the ", + "choosingRightDeviceRole": "Choosing The Right Device Role", + "deviceRoleDocumentation": "Device Role Documentation", + "title": "Você tem certeza?" + }, + "managedMode": { + "confirmUnderstanding": "Yes, I know what I'm doing", + "title": "Você tem certeza?", + "description": "Enabling Managed Mode blocks client applications (including the web client) from writing configurations to a radio. Once enabled, radio configurations can only be changed through Remote Admin messages. This setting is not required for remote node administration." + }, + "clientNotification": { + "title": "Notificação de cliente", + "TraceRoute can only be sent once every 30 seconds": "TraceRoute can only be sent once every 30 seconds", + "Compromised keys were detected and regenerated.": "Compromised keys were detected and regenerated." + }, + "resetNodeDb": { + "title": "Reset Node Database", + "description": "This will clear all nodes from the connected device's node database and clear all message history in the client. This cannot be undone. Are you sure you want to continue?", + "confirm": "Reset Node Database", + "failedTitle": "There was an error resetting the Node DB. Please try again." + }, + "clearAllStores": { + "title": "Clear All Local Storage", + "description": "This will clear all locally stored data, including message history and node databases for all previously connected devices. This will require you to reconnect to your node once complete and cannot be undone. Are you sure you want to continue?", + "confirm": "Clear all local storage", + "failedTitle": "There was an error clearing local storage. Please try again." + }, + "factoryResetDevice": { + "title": "Factory Reset Device", + "description": "This will factory reset the connected device, erasing all configurations and data on the device as well as all nodes and messages saved in the client. This cannot be undone. Are you sure you want to continue?", + "confirm": "Factory Reset Device", + "failedTitle": "There was an error performing the factory reset. Please try again." + }, + "factoryResetConfig": { + "title": "Factory Reset Config", + "description": "This will factory reset the configuration on the connected device, erasing all configurations on the device. This cannot be undone. Are you sure you want to continue?", + "confirm": "Factory Reset Config", + "failedTitle": "There was an error performing the factory reset. Please try again." + } } diff --git a/packages/web/public/i18n/locales/pt-BR/map.json b/packages/web/public/i18n/locales/pt-BR/map.json new file mode 100644 index 000000000..fc2b7c4f2 --- /dev/null +++ b/packages/web/public/i18n/locales/pt-BR/map.json @@ -0,0 +1,38 @@ +{ + "maplibre": { + "GeolocateControl.FindMyLocation": "Find my location", + "NavigationControl.ZoomIn": "Zoom in", + "NavigationControl.ZoomOut": "Zoom out", + "CooperativeGesturesHandler.WindowsHelpText": "Use Ctrl + scroll to zoom the map", + "CooperativeGesturesHandler.MacHelpText": "Use ⌘ + scroll to zoom the map", + "CooperativeGesturesHandler.MobileHelpText": "Use two fingers to move the map" + }, + "layerTool": { + "nodeMarkers": "Show nodes", + "directNeighbors": "Show direct connections", + "remoteNeighbors": "Show remote connections", + "positionPrecision": "Show position precision", + "traceroutes": "Show traceroutes", + "waypoints": "Show waypoints" + }, + "mapMenu": { + "locateAria": "Locate my node", + "layersAria": "Change map style" + }, + "waypointDetail": { + "edit": "Editar", + "description": "Description:", + "createdBy": "Edited by:", + "createdDate": "Created:", + "updated": "Updated:", + "expires": "Expires:", + "distance": "Distance:", + "bearing": "Absolute bearing:", + "lockedTo": "Locked by:", + "latitude": "Latitude:", + "longitude": "Longitude:" + }, + "myNode": { + "tooltip": "This device" + } +} diff --git a/packages/web/public/i18n/locales/pt-BR/messages.json b/packages/web/public/i18n/locales/pt-BR/messages.json index a4647b95c..cd7260a8d 100644 --- a/packages/web/public/i18n/locales/pt-BR/messages.json +++ b/packages/web/public/i18n/locales/pt-BR/messages.json @@ -1,39 +1,39 @@ { - "page": { - "title": "Messages: {{chatName}}", - "placeholder": "Enter Message" - }, - "emptyState": { - "title": "Select a Chat", - "text": "No messages yet." - }, - "selectChatPrompt": { - "text": "Select a channel or node to start messaging." - }, - "sendMessage": { - "placeholder": "Enter your message here...", - "sendButton": "Enviar" - }, - "actionsMenu": { - "addReactionLabel": "Add Reaction", - "replyLabel": "Responder" - }, - "deliveryStatus": { - "delivered": { - "label": "Message delivered", - "displayText": "Message delivered" - }, - "failed": { - "label": "Message delivery failed", - "displayText": "Delivery failed" - }, - "unknown": { - "label": "Message status unknown", - "displayText": "Unknown state" - }, - "waiting": { - "label": "Sending message", - "displayText": "Waiting for delivery" - } - } + "page": { + "title": "Messages: {{chatName}}", + "placeholder": "Enter Message" + }, + "emptyState": { + "title": "Select a Chat", + "text": "No messages yet." + }, + "selectChatPrompt": { + "text": "Select a channel or node to start messaging." + }, + "sendMessage": { + "placeholder": "Enter your message here...", + "sendButton": "Enviar" + }, + "actionsMenu": { + "addReactionLabel": "Add Reaction", + "replyLabel": "Responder" + }, + "deliveryStatus": { + "delivered": { + "label": "Message delivered", + "displayText": "Message delivered" + }, + "failed": { + "label": "Message delivery failed", + "displayText": "Delivery failed" + }, + "unknown": { + "label": "Message status unknown", + "displayText": "Unknown state" + }, + "waiting": { + "label": "Sending message", + "displayText": "Waiting for delivery" + } + } } diff --git a/packages/web/public/i18n/locales/pt-BR/moduleConfig.json b/packages/web/public/i18n/locales/pt-BR/moduleConfig.json index 357f449c6..dacf9681c 100644 --- a/packages/web/public/i18n/locales/pt-BR/moduleConfig.json +++ b/packages/web/public/i18n/locales/pt-BR/moduleConfig.json @@ -1,448 +1,448 @@ { - "page": { - "tabAmbientLighting": "Luz Ambiente", - "tabAudio": "Áudio", - "tabCannedMessage": "Canned", - "tabDetectionSensor": "Sensor de Detecção", - "tabExternalNotification": "Ext Notif", - "tabMqtt": "MQTT", - "tabNeighborInfo": "Informações do Vizinho", - "tabPaxcounter": "Medidor de Fluxo de Pessoas", - "tabRangeTest": "Teste de Alcance", - "tabSerial": "Serial", - "tabStoreAndForward": "S&F", - "tabTelemetry": "Telemetria" - }, - "ambientLighting": { - "title": "Ambient Lighting Settings", - "description": "Settings for the Ambient Lighting module", - "ledState": { - "label": "LED State", - "description": "Sets LED to on or off" - }, - "current": { - "label": "Atual", - "description": "Sets the current for the LED output. Default is 10" - }, - "red": { - "label": "Vermelho", - "description": "Sets the red LED level. Values are 0-255" - }, - "green": { - "label": "Verde", - "description": "Sets the green LED level. Values are 0-255" - }, - "blue": { - "label": "Azul", - "description": "Sets the blue LED level. Values are 0-255" - } - }, - "audio": { - "title": "Audio Settings", - "description": "Settings for the Audio module", - "codec2Enabled": { - "label": "Codec 2 Enabled", - "description": "Enable Codec 2 audio encoding" - }, - "pttPin": { - "label": "PTT Pin", - "description": "GPIO pin to use for PTT" - }, - "bitrate": { - "label": "Bitrate", - "description": "Bitrate to use for audio encoding" - }, - "i2sWs": { - "label": "i2S WS", - "description": "GPIO pin to use for i2S WS" - }, - "i2sSd": { - "label": "i2S SD", - "description": "GPIO pin to use for i2S SD" - }, - "i2sDin": { - "label": "i2S DIN", - "description": "GPIO pin to use for i2S DIN" - }, - "i2sSck": { - "label": "i2S SCK", - "description": "GPIO pin to use for i2S SCK" - } - }, - "cannedMessage": { - "title": "Canned Message Settings", - "description": "Settings for the Canned Message module", - "moduleEnabled": { - "label": "Module Enabled", - "description": "Enable Canned Message" - }, - "rotary1Enabled": { - "label": "Rotary Encoder #1 Enabled", - "description": "Enable the rotary encoder" - }, - "inputbrokerPinA": { - "label": "Encoder Pin A", - "description": "GPIO Pin Value (1-39) For encoder port A" - }, - "inputbrokerPinB": { - "label": "Encoder Pin B", - "description": "GPIO Pin Value (1-39) For encoder port B" - }, - "inputbrokerPinPress": { - "label": "Encoder Pin Press", - "description": "GPIO Pin Value (1-39) For encoder Press" - }, - "inputbrokerEventCw": { - "label": "Clockwise event", - "description": "Select input event." - }, - "inputbrokerEventCcw": { - "label": "Counter Clockwise event", - "description": "Select input event." - }, - "inputbrokerEventPress": { - "label": "Press event", - "description": "Select input event" - }, - "updown1Enabled": { - "label": "Up Down enabled", - "description": "Enable the up / down encoder" - }, - "allowInputSource": { - "label": "Allow Input Source", - "description": "Select from: '_any', 'rotEnc1', 'upDownEnc1', 'cardkb'" - }, - "sendBell": { - "label": "Send Bell", - "description": "Sends a bell character with each message" - } - }, - "detectionSensor": { - "title": "Detection Sensor Settings", - "description": "Settings for the Detection Sensor module", - "enabled": { - "label": "Enabled", - "description": "Enable or disable Detection Sensor Module" - }, - "minimumBroadcastSecs": { - "label": "Minimum Broadcast Seconds", - "description": "The interval in seconds of how often we can send a message to the mesh when a state change is detected" - }, - "stateBroadcastSecs": { - "label": "State Broadcast Seconds", - "description": "The interval in seconds of how often we should send a message to the mesh with the current state regardless of changes" - }, - "sendBell": { - "label": "Send Bell", - "description": "Send ASCII bell with alert message" - }, - "name": { - "label": "Friendly Name", - "description": "Used to format the message sent to mesh, max 20 Characters" - }, - "monitorPin": { - "label": "Monitor Pin", - "description": "The GPIO pin to monitor for state changes" - }, - "detectionTriggerType": { - "label": "Detection Triggered Type", - "description": "The type of trigger event to be used" - }, - "usePullup": { - "label": "Use Pullup", - "description": "Whether or not use INPUT_PULLUP mode for GPIO pin" - } - }, - "externalNotification": { - "title": "External Notification Settings", - "description": "Configure the external notification module", - "enabled": { - "label": "Module Enabled", - "description": "Enable External Notification" - }, - "outputMs": { - "label": "Output MS", - "description": "Output MS" - }, - "output": { - "label": "Output", - "description": "Output" - }, - "outputVibra": { - "label": "Output Vibrate", - "description": "Output Vibrate" - }, - "outputBuzzer": { - "label": "Output Buzzer", - "description": "Output Buzzer" - }, - "active": { - "label": "Active", - "description": "Active" - }, - "alertMessage": { - "label": "Alert Message", - "description": "Alert Message" - }, - "alertMessageVibra": { - "label": "Alert Message Vibrate", - "description": "Alert Message Vibrate" - }, - "alertMessageBuzzer": { - "label": "Alert Message Buzzer", - "description": "Alert Message Buzzer" - }, - "alertBell": { - "label": "Alert Bell", - "description": "Should an alert be triggered when receiving an incoming bell?" - }, - "alertBellVibra": { - "label": "Alert Bell Vibrate", - "description": "Alert Bell Vibrate" - }, - "alertBellBuzzer": { - "label": "Alert Bell Buzzer", - "description": "Alert Bell Buzzer" - }, - "usePwm": { - "label": "Use PWM", - "description": "Use PWM" - }, - "nagTimeout": { - "label": "Nag Timeout", - "description": "Nag Timeout" - }, - "useI2sAsBuzzer": { - "label": "Use I²S Pin as Buzzer", - "description": "Designate I²S Pin as Buzzer Output" - } - }, - "mqtt": { - "title": "MQTT Settings", - "description": "Settings for the MQTT module", - "enabled": { - "label": "Enabled", - "description": "Enable or disable MQTT" - }, - "address": { - "label": "MQTT Server Address", - "description": "MQTT server address to use for default/custom servers" - }, - "username": { - "label": "MQTT Username", - "description": "MQTT username to use for default/custom servers" - }, - "password": { - "label": "MQTT Password", - "description": "MQTT password to use for default/custom servers" - }, - "encryptionEnabled": { - "label": "Encryption Enabled", - "description": "Enable or disable MQTT encryption. Note: All messages are sent to the MQTT broker unencrypted if this option is not enabled, even when your uplink channels have encryption keys set. This includes position data." - }, - "jsonEnabled": { - "label": "JSON Enabled", - "description": "Whether to send/consume JSON packets on MQTT" - }, - "tlsEnabled": { - "label": "TLS Enabled", - "description": "Enable or disable TLS" - }, - "root": { - "label": "Tópico principal", - "description": "MQTT root topic to use for default/custom servers" - }, - "proxyToClientEnabled": { - "label": "MQTT Client Proxy Enabled", - "description": "Utilizes the network connection to proxy MQTT messages to the client." - }, - "mapReportingEnabled": { - "label": "Map Reporting Enabled", - "description": "Your node will periodically send an unencrypted map report packet to the configured MQTT server, this includes id, short and long name, approximate location, hardware model, role, firmware version, LoRa region, modem preset and primary channel name." - }, - "mapReportSettings": { - "publishIntervalSecs": { - "label": "Map Report Publish Interval (s)", - "description": "Interval in seconds to publish map reports" - }, - "positionPrecision": { - "label": "Approximate Location", - "description": "Position shared will be accurate within this distance", - "options": { - "metric_km23": "Within 23 km", - "metric_km12": "Within 12 km", - "metric_km5_8": "Within 5.8 km", - "metric_km2_9": "Within 2.9 km", - "metric_km1_5": "Within 1.5 km", - "metric_m700": "Within 700 m", - "metric_m350": "Within 350 m", - "metric_m200": "Within 200 m", - "metric_m90": "Within 90 m", - "metric_m50": "Within 50 m", - "imperial_mi15": "Within 15 miles", - "imperial_mi7_3": "Within 7.3 miles", - "imperial_mi3_6": "Within 3.6 miles", - "imperial_mi1_8": "Within 1.8 miles", - "imperial_mi0_9": "Within 0.9 miles", - "imperial_mi0_5": "Within 0.5 miles", - "imperial_mi0_2": "Within 0.2 miles", - "imperial_ft600": "Within 600 feet", - "imperial_ft300": "Within 300 feet", - "imperial_ft150": "Within 150 feet" - } - } - } - }, - "neighborInfo": { - "title": "Neighbor Info Settings", - "description": "Settings for the Neighbor Info module", - "enabled": { - "label": "Enabled", - "description": "Enable or disable Neighbor Info Module" - }, - "updateInterval": { - "label": "Update Interval", - "description": "Interval in seconds of how often we should try to send our Neighbor Info to the mesh" - } - }, - "paxcounter": { - "title": "Paxcounter Settings", - "description": "Settings for the Paxcounter module", - "enabled": { - "label": "Module Enabled", - "description": "Enable Paxcounter" - }, - "paxcounterUpdateInterval": { - "label": "Update Interval (seconds)", - "description": "How long to wait between sending paxcounter packets" - }, - "wifiThreshold": { - "label": "WiFi RSSI Threshold", - "description": "At what WiFi RSSI level should the counter increase. Defaults to -80." - }, - "bleThreshold": { - "label": "BLE RSSI Threshold", - "description": "At what BLE RSSI level should the counter increase. Defaults to -80." - } - }, - "rangeTest": { - "title": "Range Test Settings", - "description": "Settings for the Range Test module", - "enabled": { - "label": "Module Enabled", - "description": "Enable Range Test" - }, - "sender": { - "label": "Message Interval", - "description": "How long to wait between sending test packets" - }, - "save": { - "label": "Save CSV to storage", - "description": "ESP32 Only" - } - }, - "serial": { - "title": "Serial Settings", - "description": "Settings for the Serial module", - "enabled": { - "label": "Module Enabled", - "description": "Enable Serial output" - }, - "echo": { - "label": "Echo", - "description": "Any packets you send will be echoed back to your device" - }, - "rxd": { - "label": "Receive Pin", - "description": "Set the GPIO pin to the RXD pin you have set up." - }, - "txd": { - "label": "Transmit Pin", - "description": "Set the GPIO pin to the TXD pin you have set up." - }, - "baud": { - "label": "Baud Rate", - "description": "The serial baud rate" - }, - "timeout": { - "label": "Tempo esgotado", - "description": "Seconds to wait before we consider your packet as 'done'" - }, - "mode": { - "label": "Mode", - "description": "Select Mode" - }, - "overrideConsoleSerialPort": { - "label": "Override Console Serial Port", - "description": "If you have a serial port connected to the console, this will override it." - } - }, - "storeForward": { - "title": "Store & Forward Settings", - "description": "Settings for the Store & Forward module", - "enabled": { - "label": "Module Enabled", - "description": "Enable Store & Forward" - }, - "heartbeat": { - "label": "Heartbeat Enabled", - "description": "Enable Store & Forward heartbeat" - }, - "records": { - "label": "Número de registros", - "description": "Number of records to store" - }, - "historyReturnMax": { - "label": "Histórico de retorno máximo", - "description": "Max number of records to return" - }, - "historyReturnWindow": { - "label": "Janela de retorno do histórico", - "description": "Max number of records to return" - } - }, - "telemetry": { - "title": "Telemetry Settings", - "description": "Settings for the Telemetry module", - "deviceUpdateInterval": { - "label": "Device Metrics", - "description": "Intervalo de atualização das métricas do dispositivo (segundos)" - }, - "environmentUpdateInterval": { - "label": "Intervalo de atualização das métricas de ambiente (segundos)", - "description": "" - }, - "environmentMeasurementEnabled": { - "label": "Module Enabled", - "description": "Enable the Environment Telemetry" - }, - "environmentScreenEnabled": { - "label": "Displayed on Screen", - "description": "Show the Telemetry Module on the OLED" - }, - "environmentDisplayFahrenheit": { - "label": "Display Fahrenheit", - "description": "Display temp in Fahrenheit" - }, - "airQualityEnabled": { - "label": "Air Quality Enabled", - "description": "Enable the Air Quality Telemetry" - }, - "airQualityInterval": { - "label": "Air Quality Update Interval", - "description": "How often to send Air Quality data over the mesh" - }, - "powerMeasurementEnabled": { - "label": "Power Measurement Enabled", - "description": "Enable the Power Measurement Telemetry" - }, - "powerUpdateInterval": { - "label": "Power Update Interval", - "description": "How often to send Power data over the mesh" - }, - "powerScreenEnabled": { - "label": "Power Screen Enabled", - "description": "Enable the Power Telemetry Screen" - } - } + "page": { + "tabAmbientLighting": "Luz Ambiente", + "tabAudio": "Áudio", + "tabCannedMessage": "Canned", + "tabDetectionSensor": "Sensor de Detecção", + "tabExternalNotification": "Ext Notif", + "tabMqtt": "MQTT", + "tabNeighborInfo": "Informações do Vizinho", + "tabPaxcounter": "Medidor de Fluxo de Pessoas", + "tabRangeTest": "Teste de Alcance", + "tabSerial": "Serial", + "tabStoreAndForward": "S&F", + "tabTelemetry": "Telemetria" + }, + "ambientLighting": { + "title": "Ambient Lighting Settings", + "description": "Settings for the Ambient Lighting module", + "ledState": { + "label": "LED State", + "description": "Sets LED to on or off" + }, + "current": { + "label": "Atual", + "description": "Sets the current for the LED output. Default is 10" + }, + "red": { + "label": "Vermelho", + "description": "Sets the red LED level. Values are 0-255" + }, + "green": { + "label": "Verde", + "description": "Sets the green LED level. Values are 0-255" + }, + "blue": { + "label": "Azul", + "description": "Sets the blue LED level. Values are 0-255" + } + }, + "audio": { + "title": "Audio Settings", + "description": "Settings for the Audio module", + "codec2Enabled": { + "label": "Codec 2 Enabled", + "description": "Enable Codec 2 audio encoding" + }, + "pttPin": { + "label": "PTT Pin", + "description": "GPIO pin to use for PTT" + }, + "bitrate": { + "label": "Bitrate", + "description": "Bitrate to use for audio encoding" + }, + "i2sWs": { + "label": "i2S WS", + "description": "GPIO pin to use for i2S WS" + }, + "i2sSd": { + "label": "i2S SD", + "description": "GPIO pin to use for i2S SD" + }, + "i2sDin": { + "label": "i2S DIN", + "description": "GPIO pin to use for i2S DIN" + }, + "i2sSck": { + "label": "i2S SCK", + "description": "GPIO pin to use for i2S SCK" + } + }, + "cannedMessage": { + "title": "Canned Message Settings", + "description": "Settings for the Canned Message module", + "moduleEnabled": { + "label": "Module Enabled", + "description": "Enable Canned Message" + }, + "rotary1Enabled": { + "label": "Rotary Encoder #1 Enabled", + "description": "Enable the rotary encoder" + }, + "inputbrokerPinA": { + "label": "Encoder Pin A", + "description": "GPIO Pin Value (1-39) For encoder port A" + }, + "inputbrokerPinB": { + "label": "Encoder Pin B", + "description": "GPIO Pin Value (1-39) For encoder port B" + }, + "inputbrokerPinPress": { + "label": "Encoder Pin Press", + "description": "GPIO Pin Value (1-39) For encoder Press" + }, + "inputbrokerEventCw": { + "label": "Clockwise event", + "description": "Select input event." + }, + "inputbrokerEventCcw": { + "label": "Counter Clockwise event", + "description": "Select input event." + }, + "inputbrokerEventPress": { + "label": "Press event", + "description": "Select input event" + }, + "updown1Enabled": { + "label": "Up Down enabled", + "description": "Enable the up / down encoder" + }, + "allowInputSource": { + "label": "Allow Input Source", + "description": "Select from: '_any', 'rotEnc1', 'upDownEnc1', 'cardkb'" + }, + "sendBell": { + "label": "Send Bell", + "description": "Sends a bell character with each message" + } + }, + "detectionSensor": { + "title": "Detection Sensor Settings", + "description": "Settings for the Detection Sensor module", + "enabled": { + "label": "Enabled", + "description": "Enable or disable Detection Sensor Module" + }, + "minimumBroadcastSecs": { + "label": "Minimum Broadcast Seconds", + "description": "The interval in seconds of how often we can send a message to the mesh when a state change is detected" + }, + "stateBroadcastSecs": { + "label": "State Broadcast Seconds", + "description": "The interval in seconds of how often we should send a message to the mesh with the current state regardless of changes" + }, + "sendBell": { + "label": "Send Bell", + "description": "Send ASCII bell with alert message" + }, + "name": { + "label": "Friendly Name", + "description": "Used to format the message sent to mesh, max 20 Characters" + }, + "monitorPin": { + "label": "Monitor Pin", + "description": "The GPIO pin to monitor for state changes" + }, + "detectionTriggerType": { + "label": "Detection Triggered Type", + "description": "The type of trigger event to be used" + }, + "usePullup": { + "label": "Use Pullup", + "description": "Whether or not use INPUT_PULLUP mode for GPIO pin" + } + }, + "externalNotification": { + "title": "External Notification Settings", + "description": "Configure the external notification module", + "enabled": { + "label": "Module Enabled", + "description": "Enable External Notification" + }, + "outputMs": { + "label": "Output MS", + "description": "Output MS" + }, + "output": { + "label": "Output", + "description": "Output" + }, + "outputVibra": { + "label": "Output Vibrate", + "description": "Output Vibrate" + }, + "outputBuzzer": { + "label": "Output Buzzer", + "description": "Output Buzzer" + }, + "active": { + "label": "Active", + "description": "Active" + }, + "alertMessage": { + "label": "Alert Message", + "description": "Alert Message" + }, + "alertMessageVibra": { + "label": "Alert Message Vibrate", + "description": "Alert Message Vibrate" + }, + "alertMessageBuzzer": { + "label": "Alert Message Buzzer", + "description": "Alert Message Buzzer" + }, + "alertBell": { + "label": "Alert Bell", + "description": "Should an alert be triggered when receiving an incoming bell?" + }, + "alertBellVibra": { + "label": "Alert Bell Vibrate", + "description": "Alert Bell Vibrate" + }, + "alertBellBuzzer": { + "label": "Alert Bell Buzzer", + "description": "Alert Bell Buzzer" + }, + "usePwm": { + "label": "Use PWM", + "description": "Use PWM" + }, + "nagTimeout": { + "label": "Nag Timeout", + "description": "Nag Timeout" + }, + "useI2sAsBuzzer": { + "label": "Use I²S Pin as Buzzer", + "description": "Designate I²S Pin as Buzzer Output" + } + }, + "mqtt": { + "title": "MQTT Settings", + "description": "Settings for the MQTT module", + "enabled": { + "label": "Enabled", + "description": "Enable or disable MQTT" + }, + "address": { + "label": "MQTT Server Address", + "description": "MQTT server address to use for default/custom servers" + }, + "username": { + "label": "MQTT Username", + "description": "MQTT username to use for default/custom servers" + }, + "password": { + "label": "MQTT Password", + "description": "MQTT password to use for default/custom servers" + }, + "encryptionEnabled": { + "label": "Encryption Enabled", + "description": "Enable or disable MQTT encryption. Note: All messages are sent to the MQTT broker unencrypted if this option is not enabled, even when your uplink channels have encryption keys set. This includes position data." + }, + "jsonEnabled": { + "label": "JSON Enabled", + "description": "Whether to send/consume JSON packets on MQTT" + }, + "tlsEnabled": { + "label": "TLS Enabled", + "description": "Enable or disable TLS" + }, + "root": { + "label": "Tópico principal", + "description": "MQTT root topic to use for default/custom servers" + }, + "proxyToClientEnabled": { + "label": "MQTT Client Proxy Enabled", + "description": "Utilizes the network connection to proxy MQTT messages to the client." + }, + "mapReportingEnabled": { + "label": "Map Reporting Enabled", + "description": "Your node will periodically send an unencrypted map report packet to the configured MQTT server, this includes id, short and long name, approximate location, hardware model, role, firmware version, LoRa region, modem preset and primary channel name." + }, + "mapReportSettings": { + "publishIntervalSecs": { + "label": "Map Report Publish Interval (s)", + "description": "Interval in seconds to publish map reports" + }, + "positionPrecision": { + "label": "Approximate Location", + "description": "Position shared will be accurate within this distance", + "options": { + "metric_km23": "Within 23 km", + "metric_km12": "Within 12 km", + "metric_km5_8": "Within 5.8 km", + "metric_km2_9": "Within 2.9 km", + "metric_km1_5": "Within 1.5 km", + "metric_m700": "Within 700 m", + "metric_m350": "Within 350 m", + "metric_m200": "Within 200 m", + "metric_m90": "Within 90 m", + "metric_m50": "Within 50 m", + "imperial_mi15": "Within 15 miles", + "imperial_mi7_3": "Within 7.3 miles", + "imperial_mi3_6": "Within 3.6 miles", + "imperial_mi1_8": "Within 1.8 miles", + "imperial_mi0_9": "Within 0.9 miles", + "imperial_mi0_5": "Within 0.5 miles", + "imperial_mi0_2": "Within 0.2 miles", + "imperial_ft600": "Within 600 feet", + "imperial_ft300": "Within 300 feet", + "imperial_ft150": "Within 150 feet" + } + } + } + }, + "neighborInfo": { + "title": "Neighbor Info Settings", + "description": "Settings for the Neighbor Info module", + "enabled": { + "label": "Enabled", + "description": "Enable or disable Neighbor Info Module" + }, + "updateInterval": { + "label": "Update Interval", + "description": "Interval in seconds of how often we should try to send our Neighbor Info to the mesh" + } + }, + "paxcounter": { + "title": "Paxcounter Settings", + "description": "Settings for the Paxcounter module", + "enabled": { + "label": "Module Enabled", + "description": "Enable Paxcounter" + }, + "paxcounterUpdateInterval": { + "label": "Update Interval (seconds)", + "description": "How long to wait between sending paxcounter packets" + }, + "wifiThreshold": { + "label": "WiFi RSSI Threshold", + "description": "At what WiFi RSSI level should the counter increase. Defaults to -80." + }, + "bleThreshold": { + "label": "BLE RSSI Threshold", + "description": "At what BLE RSSI level should the counter increase. Defaults to -80." + } + }, + "rangeTest": { + "title": "Range Test Settings", + "description": "Settings for the Range Test module", + "enabled": { + "label": "Module Enabled", + "description": "Enable Range Test" + }, + "sender": { + "label": "Message Interval", + "description": "How long to wait between sending test packets" + }, + "save": { + "label": "Save CSV to storage", + "description": "ESP32 Only" + } + }, + "serial": { + "title": "Serial Settings", + "description": "Settings for the Serial module", + "enabled": { + "label": "Module Enabled", + "description": "Enable Serial output" + }, + "echo": { + "label": "Echo", + "description": "Any packets you send will be echoed back to your device" + }, + "rxd": { + "label": "Receive Pin", + "description": "Set the GPIO pin to the RXD pin you have set up." + }, + "txd": { + "label": "Transmit Pin", + "description": "Set the GPIO pin to the TXD pin you have set up." + }, + "baud": { + "label": "Baud Rate", + "description": "The serial baud rate" + }, + "timeout": { + "label": "Tempo esgotado", + "description": "Seconds to wait before we consider your packet as 'done'" + }, + "mode": { + "label": "Mode", + "description": "Select Mode" + }, + "overrideConsoleSerialPort": { + "label": "Override Console Serial Port", + "description": "If you have a serial port connected to the console, this will override it." + } + }, + "storeForward": { + "title": "Store & Forward Settings", + "description": "Settings for the Store & Forward module", + "enabled": { + "label": "Module Enabled", + "description": "Enable Store & Forward" + }, + "heartbeat": { + "label": "Heartbeat Enabled", + "description": "Enable Store & Forward heartbeat" + }, + "records": { + "label": "Número de registros", + "description": "Number of records to store" + }, + "historyReturnMax": { + "label": "Histórico de retorno máximo", + "description": "Max number of records to return" + }, + "historyReturnWindow": { + "label": "Janela de retorno do histórico", + "description": "Retornar registros desta janela de tempo (minutos)" + } + }, + "telemetry": { + "title": "Telemetry Settings", + "description": "Settings for the Telemetry module", + "deviceUpdateInterval": { + "label": "Device Metrics", + "description": "Intervalo de atualização das métricas do dispositivo (segundos)" + }, + "environmentUpdateInterval": { + "label": "Intervalo de atualização das métricas de ambiente (segundos)", + "description": "" + }, + "environmentMeasurementEnabled": { + "label": "Module Enabled", + "description": "Enable the Environment Telemetry" + }, + "environmentScreenEnabled": { + "label": "Displayed on Screen", + "description": "Show the Telemetry Module on the OLED" + }, + "environmentDisplayFahrenheit": { + "label": "Display Fahrenheit", + "description": "Display temp in Fahrenheit" + }, + "airQualityEnabled": { + "label": "Air Quality Enabled", + "description": "Enable the Air Quality Telemetry" + }, + "airQualityInterval": { + "label": "Air Quality Update Interval", + "description": "How often to send Air Quality data over the mesh" + }, + "powerMeasurementEnabled": { + "label": "Power Measurement Enabled", + "description": "Enable the Power Measurement Telemetry" + }, + "powerUpdateInterval": { + "label": "Power Update Interval", + "description": "How often to send Power data over the mesh" + }, + "powerScreenEnabled": { + "label": "Power Screen Enabled", + "description": "Enable the Power Telemetry Screen" + } + } } diff --git a/packages/web/public/i18n/locales/pt-BR/nodes.json b/packages/web/public/i18n/locales/pt-BR/nodes.json index d48164d1d..f95bc122f 100644 --- a/packages/web/public/i18n/locales/pt-BR/nodes.json +++ b/packages/web/public/i18n/locales/pt-BR/nodes.json @@ -1,63 +1,59 @@ { - "nodeDetail": { - "publicKeyEnabled": { - "label": "Public Key Enabled" - }, - "noPublicKey": { - "label": "No Public Key" - }, - "directMessage": { - "label": "Direct Message {{shortName}}" - }, - "favorite": { - "label": "Favorito", - "tooltip": "Add or remove this node from your favorites" - }, - "notFavorite": { - "label": "Not a Favorite" - }, - "error": { - "label": "Erro", - "text": "An error occurred while fetching node details. Please try again later." - }, - "status": { - "heard": "Heard", - "mqtt": "MQTT" - }, - "elevation": { - "label": "Elevation" - }, - "channelUtil": { - "label": "Channel Util" - }, - "airtimeUtil": { - "label": "Airtime Util" - } - }, - "nodesTable": { - "headings": { - "longName": "Long Name", - "connection": "Connection", - "lastHeard": "Last Heard", - "encryption": "Encryption", - "model": "Model", - "macAddress": "MAC Address" - }, - "connectionStatus": { - "direct": "Direto", - "away": "away", - "unknown": "-", - "viaMqtt": ", via MQTT" - }, - "lastHeardStatus": { - "never": "Never" - } - }, - "actions": { - "added": "Added", - "removed": "Removed", - "ignoreNode": "Ignore Node", - "unignoreNode": "Unignore Node", - "requestPosition": "Request Position" - } + "nodeDetail": { + "publicKeyEnabled": { + "label": "Public Key Enabled" + }, + "noPublicKey": { + "label": "No Public Key" + }, + "directMessage": { + "label": "Direct Message {{shortName}}" + }, + "favorite": { + "label": "Favorito", + "tooltip": "Add or remove this node from your favorites" + }, + "notFavorite": { + "label": "Not a Favorite" + }, + "error": { + "label": "Erro", + "text": "An error occurred while fetching node details. Please try again later." + }, + "status": { + "heard": "Heard", + "mqtt": "MQTT" + }, + "elevation": { + "label": "Elevation" + }, + "channelUtil": { + "label": "Channel Util" + }, + "airtimeUtil": { + "label": "Airtime Util" + } + }, + "nodesTable": { + "headings": { + "longName": "Long Name", + "connection": "Connection", + "lastHeard": "Last Heard", + "encryption": "Encryption", + "model": "Model", + "macAddress": "MAC Address" + }, + "connectionStatus": { + "direct": "Direto", + "away": "away", + "viaMqtt": ", via MQTT" + } + }, + "actions": { + "added": "Added", + "removed": "Removed", + "ignoreNode": "Ignore Node", + "unignoreNode": "Unignore Node", + "requestPosition": "Request Position" + } } diff --git a/packages/web/public/i18n/locales/pt-BR/ui.json b/packages/web/public/i18n/locales/pt-BR/ui.json index fe4fd02b1..ad8410678 100644 --- a/packages/web/public/i18n/locales/pt-BR/ui.json +++ b/packages/web/public/i18n/locales/pt-BR/ui.json @@ -1,228 +1,230 @@ { - "navigation": { - "title": "Navigation", - "messages": "Mensagens", - "map": "Mapa", - "config": "Config", - "radioConfig": "Radio Config", - "moduleConfig": "Module Config", - "channels": "Canais", - "nodes": "Nós" - }, - "app": { - "title": "Meshtastic", - "logo": "Meshtastic Logo" - }, - "sidebar": { - "collapseToggle": { - "button": { - "open": "Open sidebar", - "close": "Close sidebar" - } - }, - "deviceInfo": { - "volts": "{{voltage}} volts", - "firmware": { - "title": "Firmware", - "version": "v{{version}}", - "buildDate": "Build date: {{date}}" - }, - "deviceName": { - "title": "Device Name", - "changeName": "Change Device Name", - "placeholder": "Enter device name" - }, - "editDeviceName": "Edit device name" - } - }, - "batteryStatus": { - "charging": "{{level}}% charging", - "pluggedIn": "Plugged in", - "title": "Bateria" - }, - "search": { - "nodes": "Search nodes...", - "channels": "Search channels...", - "commandPalette": "Search commands..." - }, - "toast": { - "positionRequestSent": { - "title": "Position request sent." - }, - "requestingPosition": { - "title": "Requesting position, please wait..." - }, - "sendingTraceroute": { - "title": "Sending Traceroute, please wait..." - }, - "tracerouteSent": { - "title": "Traceroute sent." - }, - "savedChannel": { - "title": "Saved Channel: {{channelName}}" - }, - "messages": { - "pkiEncryption": { - "title": "Chat is using PKI encryption." - }, - "pskEncryption": { - "title": "Chat is using PSK encryption." - } - }, - "configSaveError": { - "title": "Error Saving Config", - "description": "An error occurred while saving the configuration." - }, - "validationError": { - "title": "Config Errors Exist", - "description": "Please fix the configuration errors before saving." - }, - "saveSuccess": { - "title": "Saving Config", - "description": "The configuration change {{case}} has been saved." - }, - "favoriteNode": { - "title": "{{action}} {{nodeName}} {{direction}} favorites.", - "action": { - "added": "Added", - "removed": "Removed", - "to": "to", - "from": "from" - } - }, - "ignoreNode": { - "title": "{{action}} {{nodeName}} {{direction}} ignore list", - "action": { - "added": "Added", - "removed": "Removed", - "to": "to", - "from": "from" - } - } - }, - "notifications": { - "copied": { - "label": "Copied!" - }, - "copyToClipboard": { - "label": "Copy to clipboard" - }, - "hidePassword": { - "label": "Ocultar senha" - }, - "showPassword": { - "label": "Mostrar senha" - }, - "deliveryStatus": { - "delivered": "Delivered", - "failed": "Delivery Failed", - "waiting": "Waiting", - "unknown": "Desconhecido" - } - }, - "general": { - "label": "General" - }, - "hardware": { - "label": "Hardware" - }, - "metrics": { - "label": "Metrics" - }, - "role": { - "label": "Função" - }, - "filter": { - "label": "Filtro" - }, - "advanced": { - "label": "Advanced" - }, - "clearInput": { - "label": "Clear input" - }, - "resetFilters": { - "label": "Reset Filters" - }, - "nodeName": { - "label": "Node name/number", - "placeholder": "Meshtastic 1234" - }, - "airtimeUtilization": { - "label": "Airtime Utilization (%)" - }, - "batteryLevel": { - "label": "Battery level (%)", - "labelText": "Battery level (%): {{value}}" - }, - "batteryVoltage": { - "label": "Battery voltage (V)", - "title": "Voltagem" - }, - "channelUtilization": { - "label": "Channel Utilization (%)" - }, - "hops": { - "direct": "Direto", - "label": "Number of hops", - "text": "Number of hops: {{value}}" - }, - "lastHeard": { - "label": "Visto pela última vez", - "labelText": "Last heard: {{value}}", - "nowLabel": "Now" - }, - "snr": { - "label": "SNR (db)" - }, - "favorites": { - "label": "Favorites" - }, - "hide": { - "label": "Hide" - }, - "showOnly": { - "label": "Show Only" - }, - "viaMqtt": { - "label": "Connected via MQTT" - }, - "hopsUnknown": { - "label": "Unknown number of hops" - }, - "showUnheard": { - "label": "Never heard" - }, - "language": { - "label": "Idioma", - "changeLanguage": "Change Language" - }, - "theme": { - "dark": "Escuro", - "light": "Claro", - "system": "Automatic", - "changeTheme": "Change Color Scheme" - }, - "errorPage": { - "title": "This is a little embarrassing...", - "description1": "We are really sorry but an error occurred in the web client that caused it to crash.
This is not supposed to happen, and we are working hard to fix it.", - "description2": "The best way to prevent this from happening again to you or anyone else is to report the issue to us.", - "reportInstructions": "Please include the following information in your report:", - "reportSteps": { - "step1": "What you were doing when the error occurred", - "step2": "What you expected to happen", - "step3": "What actually happened", - "step4": "Any other relevant information" - }, - "reportLink": "You can report the issue to our <0>GitHub", - "dashboardLink": "Return to the <0>dashboard", - "detailsSummary": "Error Details", - "errorMessageLabel": "Error message:", - "stackTraceLabel": "Stack trace:", - "fallbackError": "{{error}}" - }, - "footer": { - "text": "Powered by <0>▲ Vercel | Meshtastic® is a registered trademark of Meshtastic LLC. | <1>Legal Information", - "commitSha": "Commit SHA: {{sha}}" - } + "navigation": { + "title": "Navigation", + "messages": "Mensagens", + "map": "Mapa", + "settings": "Configurações", + "channels": "Canais", + "radioConfig": "Radio Config", + "deviceConfig": "Configuração do Dispositivo", + "moduleConfig": "Module Config", + "manageConnections": "Manage Connections", + "nodes": "Nós" + }, + "app": { + "title": "Meshtastic", + "logo": "Meshtastic Logo" + }, + "sidebar": { + "collapseToggle": { + "button": { + "open": "Open sidebar", + "close": "Close sidebar" + } + }, + "deviceInfo": { + "volts": "{{voltage}} volts", + "firmware": { + "title": "Firmware", + "version": "v{{version}}", + "buildDate": "Build date: {{date}}" + } + } + }, + "batteryStatus": { + "charging": "{{level}}% charging", + "pluggedIn": "Plugged in", + "title": "Bateria" + }, + "search": { + "nodes": "Search nodes...", + "channels": "Search channels...", + "commandPalette": "Search commands..." + }, + "toast": { + "positionRequestSent": { + "title": "Position request sent." + }, + "requestingPosition": { + "title": "Requesting position, please wait..." + }, + "sendingTraceroute": { + "title": "Sending Traceroute, please wait..." + }, + "tracerouteSent": { + "title": "Traceroute sent." + }, + "savedChannel": { + "title": "Saved Channel: {{channelName}}" + }, + "messages": { + "pkiEncryption": { + "title": "Chat is using PKI encryption." + }, + "pskEncryption": { + "title": "Chat is using PSK encryption." + } + }, + "configSaveError": { + "title": "Error Saving Config", + "description": "An error occurred while saving the configuration." + }, + "validationError": { + "title": "Config Errors Exist", + "description": "Please fix the configuration errors before saving." + }, + "saveSuccess": { + "title": "Saving Config", + "description": "The configuration change {{case}} has been saved." + }, + "saveAllSuccess": { + "title": "Saved", + "description": "All configuration changes have been saved." + }, + "favoriteNode": { + "title": "{{action}} {{nodeName}} {{direction}} favorites.", + "action": { + "added": "Added", + "removed": "Removed", + "to": "to", + "from": "from" + } + }, + "ignoreNode": { + "title": "{{action}} {{nodeName}} {{direction}} ignore list", + "action": { + "added": "Added", + "removed": "Removed", + "to": "to", + "from": "from" + } + } + }, + "notifications": { + "copied": { + "label": "Copied!" + }, + "copyToClipboard": { + "label": "Copy to clipboard" + }, + "hidePassword": { + "label": "Ocultar senha" + }, + "showPassword": { + "label": "Mostrar senha" + }, + "deliveryStatus": { + "delivered": "Delivered", + "failed": "Delivery Failed", + "waiting": "Waiting", + "unknown": "Desconhecido" + } + }, + "general": { + "label": "General" + }, + "hardware": { + "label": "Hardware" + }, + "metrics": { + "label": "Metrics" + }, + "role": { + "label": "Função" + }, + "filter": { + "label": "Filtro" + }, + "advanced": { + "label": "Advanced" + }, + "clearInput": { + "label": "Clear input" + }, + "resetFilters": { + "label": "Reset Filters" + }, + "nodeName": { + "label": "Node name/number", + "placeholder": "Meshtastic 1234" + }, + "airtimeUtilization": { + "label": "Airtime Utilization (%)", + "short": "Airtime Util. (%)" + }, + "batteryLevel": { + "label": "Battery level (%)", + "labelText": "Battery level (%): {{value}}" + }, + "batteryVoltage": { + "label": "Battery voltage (V)", + "title": "Voltagem" + }, + "channelUtilization": { + "label": "Channel Utilization (%)", + "short": "Channel Util. (%)" + }, + "hops": { + "direct": "Direto", + "label": "Number of hops", + "text": "Number of hops: {{value}}" + }, + "lastHeard": { + "label": "Visto pela última vez", + "labelText": "Last heard: {{value}}", + "nowLabel": "Now" + }, + "snr": { + "label": "SNR (db)" + }, + "favorites": { + "label": "Favorites" + }, + "hide": { + "label": "Hide" + }, + "showOnly": { + "label": "Show Only" + }, + "viaMqtt": { + "label": "Connected via MQTT" + }, + "hopsUnknown": { + "label": "Unknown number of hops" + }, + "showUnheard": { + "label": "Never heard" + }, + "language": { + "label": "Idioma", + "changeLanguage": "Change Language" + }, + "theme": { + "dark": "Escuro", + "light": "Claro", + "system": "Automatic", + "changeTheme": "Change Color Scheme" + }, + "errorPage": { + "title": "This is a little embarrassing...", + "description1": "We are really sorry but an error occurred in the web client that caused it to crash.
This is not supposed to happen, and we are working hard to fix it.", + "description2": "The best way to prevent this from happening again to you or anyone else is to report the issue to us.", + "reportInstructions": "Please include the following information in your report:", + "reportSteps": { + "step1": "What you were doing when the error occurred", + "step2": "What you expected to happen", + "step3": "What actually happened", + "step4": "Any other relevant information" + }, + "reportLink": "You can report the issue to our <0>GitHub", + "connectionsLink": "Return to the <0>connections", + "detailsSummary": "Error Details", + "errorMessageLabel": "Error message:", + "stackTraceLabel": "Stack trace:", + "fallbackError": "{{error}}" + }, + "footer": { + "text": "Powered by <0>▲ Vercel | Meshtastic® is a registered trademark of Meshtastic LLC. | <1>Legal Information", + "commitSha": "Commit SHA: {{sha}}" + } } diff --git a/packages/web/public/i18n/locales/pt-PT/channels.json b/packages/web/public/i18n/locales/pt-PT/channels.json index 000384282..eecece15c 100644 --- a/packages/web/public/i18n/locales/pt-PT/channels.json +++ b/packages/web/public/i18n/locales/pt-PT/channels.json @@ -1,69 +1,71 @@ { - "page": { - "sectionLabel": "Canal", - "channelName": "Channel: {{channelName}}", - "broadcastLabel": "Principal", - "channelIndex": "Ch {{index}}" - }, - "validation": { - "pskInvalid": "Please enter a valid {{bits}} bit PSK." - }, - "settings": { - "label": "Configurações de canal", - "description": "Crypto, MQTT & misc settings" - }, - "role": { - "label": "Papel", - "description": "Device telemetry is sent over PRIMARY. Only one PRIMARY allowed", - "options": { - "primary": "PRIMARY", - "disabled": "DISABLED", - "secondary": "SECONDARY" - } - }, - "psk": { - "label": "Pre-Shared Key", - "description": "Supported PSK lengths: 256-bit, 128-bit, 8-bit, Empty (0-bit)", - "generate": "Generate" - }, - "name": { - "label": "Nome", - "description": "A unique name for the channel <12 bytes, leave blank for default" - }, - "uplinkEnabled": { - "label": "Uplink Enabled", - "description": "Send messages from the local mesh to MQTT" - }, - "downlinkEnabled": { - "label": "Downlink Enabled", - "description": "Send messages from MQTT to the local mesh" - }, - "positionPrecision": { - "label": "Location", - "description": "The precision of the location to share with the channel. Can be disabled.", - "options": { - "none": "Do not share location", - "precise": "Precise Location", - "metric_km23": "Within 23 kilometers", - "metric_km12": "Within 12 kilometers", - "metric_km5_8": "Within 5.8 kilometers", - "metric_km2_9": "Within 2.9 kilometers", - "metric_km1_5": "Within 1.5 kilometers", - "metric_m700": "Within 700 meters", - "metric_m350": "Within 350 meters", - "metric_m200": "Within 200 meters", - "metric_m90": "Within 90 meters", - "metric_m50": "Within 50 meters", - "imperial_mi15": "Within 15 miles", - "imperial_mi7_3": "Within 7.3 miles", - "imperial_mi3_6": "Within 3.6 miles", - "imperial_mi1_8": "Within 1.8 miles", - "imperial_mi0_9": "Within 0.9 miles", - "imperial_mi0_5": "Within 0.5 miles", - "imperial_mi0_2": "Within 0.2 miles", - "imperial_ft600": "Within 600 feet", - "imperial_ft300": "Within 300 feet", - "imperial_ft150": "Within 150 feet" - } - } + "page": { + "sectionLabel": "Canal", + "channelName": "Channel: {{channelName}}", + "broadcastLabel": "Principal", + "channelIndex": "Ch {{index}}", + "import": "Importar", + "export": "Export" + }, + "validation": { + "pskInvalid": "Please enter a valid {{bits}} bit PSK." + }, + "settings": { + "label": "Configurações de canal", + "description": "Crypto, MQTT & misc settings" + }, + "role": { + "label": "Papel", + "description": "Device telemetry is sent over PRIMARY. Only one PRIMARY allowed", + "options": { + "primary": "PRIMARY", + "disabled": "DISABLED", + "secondary": "SECONDARY" + } + }, + "psk": { + "label": "Pre-Shared Key", + "description": "Supported PSK lengths: 256-bit, 128-bit, 8-bit, Empty (0-bit)", + "generate": "Generate" + }, + "name": { + "label": "Nome", + "description": "A unique name for the channel <12 bytes, leave blank for default" + }, + "uplinkEnabled": { + "label": "Uplink Enabled", + "description": "Send messages from the local mesh to MQTT" + }, + "downlinkEnabled": { + "label": "Downlink Enabled", + "description": "Send messages from MQTT to the local mesh" + }, + "positionPrecision": { + "label": "Location", + "description": "The precision of the location to share with the channel. Can be disabled.", + "options": { + "none": "Do not share location", + "precise": "Precise Location", + "metric_km23": "Within 23 kilometers", + "metric_km12": "Within 12 kilometers", + "metric_km5_8": "Within 5.8 kilometers", + "metric_km2_9": "Within 2.9 kilometers", + "metric_km1_5": "Within 1.5 kilometers", + "metric_m700": "Within 700 meters", + "metric_m350": "Within 350 meters", + "metric_m200": "Within 200 meters", + "metric_m90": "Within 90 meters", + "metric_m50": "Within 50 meters", + "imperial_mi15": "Within 15 miles", + "imperial_mi7_3": "Within 7.3 miles", + "imperial_mi3_6": "Within 3.6 miles", + "imperial_mi1_8": "Within 1.8 miles", + "imperial_mi0_9": "Within 0.9 miles", + "imperial_mi0_5": "Within 0.5 miles", + "imperial_mi0_2": "Within 0.2 miles", + "imperial_ft600": "Within 600 feet", + "imperial_ft300": "Within 300 feet", + "imperial_ft150": "Within 150 feet" + } + } } diff --git a/packages/web/public/i18n/locales/pt-PT/commandPalette.json b/packages/web/public/i18n/locales/pt-PT/commandPalette.json index 4f26f18ef..43e819c26 100644 --- a/packages/web/public/i18n/locales/pt-PT/commandPalette.json +++ b/packages/web/public/i18n/locales/pt-PT/commandPalette.json @@ -15,7 +15,6 @@ "messages": "Mensagens", "map": "Mapa", "config": "Config", - "channels": "Canal", "nodes": "Nodes" } }, @@ -45,7 +44,8 @@ "label": "Depuração", "command": { "reconfigure": "Reconfigure", - "clearAllStoredMessages": "Clear All Stored Message" + "clearAllStoredMessages": "Clear All Stored Message", + "clearAllStores": "Clear All Local Storage" } } } diff --git a/packages/web/public/i18n/locales/pt-PT/common.json b/packages/web/public/i18n/locales/pt-PT/common.json index 1aa55494a..8521a7392 100644 --- a/packages/web/public/i18n/locales/pt-PT/common.json +++ b/packages/web/public/i18n/locales/pt-PT/common.json @@ -1,142 +1,165 @@ { - "button": { - "apply": "Aplicar", - "backupKey": "Backup Key", - "cancel": "Cancelar", - "clearMessages": "Clear Messages", - "close": "Fechar", - "confirm": "Confirm", - "delete": "Excluir", - "dismiss": "Dismiss", - "download": "Download", - "export": "Export", - "generate": "Generate", - "regenerate": "Regenerate", - "import": "Importar", - "message": "Mensagem", - "now": "Now", - "ok": "Okay", - "print": "Print", - "remove": "Remover", - "requestNewKeys": "Request New Keys", - "requestPosition": "Request Position", - "reset": "Redefinir", - "save": "Salvar", - "scanQr": "Ler código QR", - "traceRoute": "Trace Route", - "submit": "Submit" - }, - "app": { - "title": "Meshtastic", - "fullTitle": "Meshtastic Web Client" - }, - "loading": "Loading...", - "unit": { - "cps": "CPS", - "dbm": "dBm", - "hertz": "Hz", - "hop": { - "one": "Hop", - "plural": "Hops" - }, - "hopsAway": { - "one": "{{count}} hop away", - "plural": "{{count}} hops away", - "unknown": "Unknown hops away" - }, - "megahertz": "MHz", - "raw": "raw", - "meter": { - "one": "Meter", - "plural": "Meters", - "suffix": "m" - }, - "minute": { - "one": "Minute", - "plural": "Minutes" - }, - "hour": { - "one": "Hour", - "plural": "Hours" - }, - "millisecond": { - "one": "Millisecond", - "plural": "Milliseconds", - "suffix": "ms" - }, - "second": { - "one": "Second", - "plural": "Seconds" - }, - "day": { - "one": "Day", - "plural": "Days" - }, - "month": { - "one": "Month", - "plural": "Months" - }, - "year": { - "one": "Year", - "plural": "Years" - }, - "snr": "SNR", - "volt": { - "one": "Volt", - "plural": "Volts", - "suffix": "V" - }, - "record": { - "one": "Records", - "plural": "Records" - } - }, - "security": { - "0bit": "Empty", - "8bit": "8 bit", - "128bit": "128 bit", - "256bit": "256 bit" - }, - "unknown": { - "longName": "Unknown", - "shortName": "UNK", - "notAvailable": "N/A", - "num": "??" - }, - "nodeUnknownPrefix": "!", - "unset": "UNSET", - "fallbackName": "Meshtastic {{last4}}", - "node": "Node", - "formValidation": { - "unsavedChanges": "Unsaved changes", - "tooBig": { - "string": "Too long, expected less than or equal to {{maximum}} characters.", - "number": "Too big, expected a number smaller than or equal to {{maximum}}.", - "bytes": "Too big, expected less than or equal to {{params.maximum}} bytes." - }, - "tooSmall": { - "string": "Too short, expected more than or equal to {{minimum}} characters.", - "number": "Too small, expected a number larger than or equal to {{minimum}}." - }, - "invalidFormat": { - "ipv4": "Invalid format, expected an IPv4 address.", - "key": "Invalid format, expected a Base64 encoded pre-shared key (PSK)." - }, - "invalidType": { - "number": "Invalid type, expected a number." - }, - "pskLength": { - "0bit": "Key is required to be empty.", - "8bit": "Key is required to be an 8 bit pre-shared key (PSK).", - "128bit": "Key is required to be a 128 bit pre-shared key (PSK).", - "256bit": "Key is required to be a 256 bit pre-shared key (PSK)." - }, - "required": { - "generic": "This field is required.", - "managed": "At least one admin key is requred if the node is managed.", - "key": "Key is required." - } - }, - "yes": "Yes", - "no": "No" + "button": { + "apply": "Aplicar", + "addConnection": "Add Connection", + "saveConnection": "Save connection", + "backupKey": "Backup Key", + "cancel": "Cancelar", + "connect": "Ligar", + "clearMessages": "Clear Messages", + "close": "Fechar", + "confirm": "Confirm", + "delete": "Excluir", + "dismiss": "Dismiss", + "download": "Download", + "disconnect": "Desligar", + "export": "Export", + "generate": "Generate", + "regenerate": "Regenerate", + "import": "Importar", + "message": "Mensagem", + "now": "Now", + "ok": "Okay", + "print": "Print", + "remove": "Remover", + "requestNewKeys": "Request New Keys", + "requestPosition": "Request Position", + "reset": "Redefinir", + "retry": "Retry", + "save": "Salvar", + "setDefault": "Set as default", + "unsetDefault": "Unset default", + "scanQr": "Ler código QR", + "traceRoute": "Trace Route", + "submit": "Submit" + }, + "app": { + "title": "Meshtastic", + "fullTitle": "Meshtastic Web Client" + }, + "loading": "Loading...", + "unit": { + "cps": "CPS", + "dbm": "dBm", + "hertz": "Hz", + "hop": { + "one": "Hop", + "plural": "Hops" + }, + "hopsAway": { + "one": "{{count}} hop away", + "plural": "{{count}} hops away", + "unknown": "Unknown hops away" + }, + "megahertz": "MHz", + "kilohertz": "kHz", + "raw": "raw", + "meter": { + "one": "Meter", + "plural": "Meters", + "suffix": "m" + }, + "kilometer": { + "one": "Kilometer", + "plural": "Kilometers", + "suffix": "km" + }, + "minute": { + "one": "Minute", + "plural": "Minutes" + }, + "hour": { + "one": "Hour", + "plural": "Hours" + }, + "millisecond": { + "one": "Millisecond", + "plural": "Milliseconds", + "suffix": "ms" + }, + "second": { + "one": "Second", + "plural": "Seconds" + }, + "day": { + "one": "Day", + "plural": "Days", + "today": "Today", + "yesterday": "Yesterday" + }, + "month": { + "one": "Month", + "plural": "Months" + }, + "year": { + "one": "Year", + "plural": "Years" + }, + "snr": "SNR", + "volt": { + "one": "Volt", + "plural": "Volts", + "suffix": "V" + }, + "record": { + "one": "Records", + "plural": "Records" + }, + "degree": { + "one": "Degree", + "plural": "Degrees", + "suffix": "°" + } + }, + "security": { + "0bit": "Empty", + "8bit": "8 bit", + "128bit": "128 bit", + "256bit": "256 bit" + }, + "unknown": { + "longName": "Unknown", + "shortName": "UNK", + "notAvailable": "N/A", + "num": "??" + }, + "nodeUnknownPrefix": "!", + "unset": "UNSET", + "fallbackName": "Meshtastic {{last4}}", + "node": "Node", + "formValidation": { + "unsavedChanges": "Unsaved changes", + "tooBig": { + "string": "Too long, expected less than or equal to {{maximum}} characters.", + "number": "Too big, expected a number smaller than or equal to {{maximum}}.", + "bytes": "Too big, expected less than or equal to {{params.maximum}} bytes." + }, + "tooSmall": { + "string": "Too short, expected more than or equal to {{minimum}} characters.", + "number": "Too small, expected a number larger than or equal to {{minimum}}." + }, + "invalidFormat": { + "ipv4": "Invalid format, expected an IPv4 address.", + "key": "Invalid format, expected a Base64 encoded pre-shared key (PSK)." + }, + "invalidType": { + "number": "Invalid type, expected a number." + }, + "pskLength": { + "0bit": "Key is required to be empty.", + "8bit": "Key is required to be an 8 bit pre-shared key (PSK).", + "128bit": "Key is required to be a 128 bit pre-shared key (PSK).", + "256bit": "Key is required to be a 256 bit pre-shared key (PSK)." + }, + "required": { + "generic": "This field is required.", + "managed": "At least one admin key is requred if the node is managed.", + "key": "Key is required." + }, + "invalidOverrideFreq": { + "number": "Invalid format, expected a value in the range 410-930 MHz or 0 (use default)." + } + }, + "yes": "Yes", + "no": "No" } diff --git a/packages/web/public/i18n/locales/pt-PT/config.json b/packages/web/public/i18n/locales/pt-PT/config.json new file mode 100644 index 000000000..a0fc0f302 --- /dev/null +++ b/packages/web/public/i18n/locales/pt-PT/config.json @@ -0,0 +1,458 @@ +{ + "page": { + "title": "Definições", + "tabUser": "Utilizador", + "tabChannels": "Canal", + "tabBluetooth": "Bluetooth", + "tabDevice": "Dispositivo", + "tabDisplay": "Ecrã", + "tabLora": "LoRa", + "tabNetwork": "Rede", + "tabPosition": "Posição", + "tabPower": "Energia", + "tabSecurity": "Segurança" + }, + "sidebar": { + "label": "Configuração" + }, + "device": { + "title": "Definições do dispositivo", + "description": "Configurações para o dispositivo", + "buttonPin": { + "description": "Button pin override", + "label": "Button Pin" + }, + "buzzerPin": { + "description": "Buzzer pin override", + "label": "Buzzer Pin" + }, + "disableTripleClick": { + "description": "Disable triple click", + "label": "Disable Triple Click" + }, + "doubleTapAsButtonPress": { + "description": "Treat double tap as button press", + "label": "Double Tap as Button Press" + }, + "ledHeartbeatDisabled": { + "description": "Disable default blinking LED", + "label": "LED Heartbeat Disabled" + }, + "nodeInfoBroadcastInterval": { + "description": "How often to broadcast node info", + "label": "Node Info Broadcast Interval" + }, + "posixTimezone": { + "description": "The POSIX timezone string for the device", + "label": "Fuso horário POSIX" + }, + "rebroadcastMode": { + "description": "How to handle rebroadcasting", + "label": "Rebroadcast Mode" + }, + "role": { + "description": "What role the device performs on the mesh", + "label": "Papel" + } + }, + "bluetooth": { + "title": "Bluetooth Settings", + "description": "Settings for the Bluetooth module", + "note": "Note: Some devices (ESP32) cannot use both Bluetooth and WiFi at the same time.", + "enabled": { + "description": "Enable or disable Bluetooth", + "label": "Enabled" + }, + "pairingMode": { + "description": "Pin selection behaviour.", + "label": "Modo de emparelhamento" + }, + "pin": { + "description": "Pin to use when pairing", + "label": "Pin" + } + }, + "display": { + "description": "Settings for the device display", + "title": "Display Settings", + "headingBold": { + "description": "Bolden the heading text", + "label": "Bold Heading" + }, + "carouselDelay": { + "description": "How fast to cycle through windows", + "label": "Carousel Delay" + }, + "compassNorthTop": { + "description": "Fix north to the top of compass", + "label": "Compass North Top" + }, + "displayMode": { + "description": "Screen layout variant", + "label": "Display Mode" + }, + "displayUnits": { + "description": "Display metric or imperial units", + "label": "Display Units" + }, + "flipScreen": { + "description": "Flip display 180 degrees", + "label": "Flip Screen" + }, + "gpsDisplayUnits": { + "description": "Coordinate display format", + "label": "GPS Display Units" + }, + "oledType": { + "description": "Type of OLED screen attached to the device", + "label": "OLED Type" + }, + "screenTimeout": { + "description": "Turn off the display after this long", + "label": "Screen Timeout" + }, + "twelveHourClock": { + "description": "Use 12-hour clock format", + "label": "Relógio 12-Horas" + }, + "wakeOnTapOrMotion": { + "description": "Wake the device on tap or motion", + "label": "Wake on Tap or Motion" + } + }, + "lora": { + "title": "Mesh Settings", + "description": "Settings for the LoRa mesh", + "bandwidth": { + "description": "Channel bandwidth in kHz", + "label": "Largura de banda" + }, + "boostedRxGain": { + "description": "Boosted RX gain", + "label": "Boosted RX Gain" + }, + "codingRate": { + "description": "The denominator of the coding rate", + "label": "Coding Rate" + }, + "frequencyOffset": { + "description": "Frequency offset to correct for crystal calibration errors", + "label": "Frequency Offset" + }, + "frequencySlot": { + "description": "LoRa frequency channel number", + "label": "Frequency Slot" + }, + "hopLimit": { + "description": "Maximum number of hops", + "label": "Hop Limit" + }, + "ignoreMqtt": { + "description": "Don't forward MQTT messages over the mesh", + "label": "Ignorar MQTT" + }, + "modemPreset": { + "description": "Modem preset to use", + "label": "Predefinição de modem" + }, + "okToMqtt": { + "description": "When set to true, this configuration indicates that the user approves the packet to be uploaded to MQTT. If set to false, remote nodes are requested not to forward packets to MQTT", + "label": "Disponibilizar no MQTT" + }, + "overrideDutyCycle": { + "description": "Ignorar ciclo de trabalho", + "label": "Ignorar ciclo de trabalho" + }, + "overrideFrequency": { + "description": "Override frequency", + "label": "Override Frequency" + }, + "region": { + "description": "Sets the region for your node", + "label": "Região" + }, + "spreadingFactor": { + "description": "Indicates the number of chirps per symbol", + "label": "Spreading Factor" + }, + "transmitEnabled": { + "description": "Enable/Disable transmit (TX) from the LoRa radio", + "label": "Transmit Enabled" + }, + "transmitPower": { + "description": "Max transmit power", + "label": "Transmit Power" + }, + "usePreset": { + "description": "Use one of the predefined modem presets", + "label": "Use Preset" + }, + "meshSettings": { + "description": "Settings for the LoRa mesh", + "label": "Mesh Settings" + }, + "waveformSettings": { + "description": "Settings for the LoRa waveform", + "label": "Waveform Settings" + }, + "radioSettings": { + "label": "Radio Settings", + "description": "Settings for the LoRa radio" + } + }, + "network": { + "title": "WiFi Config", + "description": "WiFi radio configuration", + "note": "Note: Some devices (ESP32) cannot use both Bluetooth and WiFi at the same time.", + "addressMode": { + "description": "Address assignment selection", + "label": "Address Mode" + }, + "dns": { + "description": "DNS Server", + "label": "DNS" + }, + "ethernetEnabled": { + "description": "Enable or disable the Ethernet port", + "label": "Enabled" + }, + "gateway": { + "description": "Default Gateway", + "label": "Gateway" + }, + "ip": { + "description": "IP Address", + "label": "IP" + }, + "psk": { + "description": "Network password", + "label": "PSK" + }, + "ssid": { + "description": "Network name", + "label": "SSID" + }, + "subnet": { + "description": "Subnet Mask", + "label": "Subnet" + }, + "wifiEnabled": { + "description": "Enable or disable the WiFi radio", + "label": "Enabled" + }, + "meshViaUdp": { + "label": "Mesh via UDP" + }, + "ntpServer": { + "label": "NTP Server" + }, + "rsyslogServer": { + "label": "Rsyslog Server" + }, + "ethernetConfigSettings": { + "description": "Ethernet port configuration", + "label": "Ethernet Config" + }, + "ipConfigSettings": { + "description": "IP configuration", + "label": "IP Config" + }, + "ntpConfigSettings": { + "description": "NTP configuration", + "label": "NTP Config" + }, + "rsyslogConfigSettings": { + "description": "Rsyslog configuration", + "label": "Rsyslog Config" + }, + "udpConfigSettings": { + "description": "UDP over Mesh configuration", + "label": "Configuração UDP" + } + }, + "position": { + "title": "Position Settings", + "description": "Settings for the position module", + "broadcastInterval": { + "description": "How often your position is sent out over the mesh", + "label": "Broadcast Interval" + }, + "enablePin": { + "description": "GPS module enable pin override", + "label": "Enable Pin" + }, + "fixedPosition": { + "description": "Don't report GPS position, but a manually-specified one", + "label": "Fixed Position" + }, + "gpsMode": { + "description": "Configure whether device GPS is Enabled, Disabled, or Not Present", + "label": "GPS Mode" + }, + "gpsUpdateInterval": { + "description": "How often a GPS fix should be acquired", + "label": "GPS Update Interval" + }, + "positionFlags": { + "description": "Optional fields to include when assembling position messages. The more fields are selected, the larger the message will be leading to longer airtime usage and a higher risk of packet loss.", + "label": "Position Flags" + }, + "receivePin": { + "description": "GPS module RX pin override", + "label": "Receive Pin" + }, + "smartPositionEnabled": { + "description": "Only send position when there has been a meaningful change in location", + "label": "Enable Smart Position" + }, + "smartPositionMinDistance": { + "description": "Minimum distance (in meters) that must be traveled before a position update is sent", + "label": "Smart Position Minimum Distance" + }, + "smartPositionMinInterval": { + "description": "Minimum interval (in seconds) that must pass before a position update is sent", + "label": "Smart Position Minimum Interval" + }, + "transmitPin": { + "description": "GPS module TX pin override", + "label": "Transmit Pin" + }, + "intervalsSettings": { + "description": "How often to send position updates", + "label": "Intervals" + }, + "flags": { + "placeholder": "Select position flags...", + "altitude": "Altitude", + "altitudeGeoidalSeparation": "Altitude Geoidal Separation", + "altitudeMsl": "Altitude is Mean Sea Level", + "dop": "Dilution of precision (DOP) PDOP used by default", + "hdopVdop": "If DOP is set, use HDOP / VDOP values instead of PDOP", + "numSatellites": "Number of satellites", + "sequenceNumber": "Sequence number", + "timestamp": "Data e hora", + "unset": "Não Definido", + "vehicleHeading": "Vehicle heading", + "vehicleSpeed": "Vehicle speed" + } + }, + "power": { + "adcMultiplierOverride": { + "description": "Used for tweaking battery voltage reading", + "label": "ADC Multiplier Override ratio" + }, + "ina219Address": { + "description": "Address of the INA219 battery monitor", + "label": "INA219 Address" + }, + "lightSleepDuration": { + "description": "How long the device will be in light sleep for", + "label": "Light Sleep Duration" + }, + "minimumWakeTime": { + "description": "Minimum amount of time the device will stay awake for after receiving a packet", + "label": "Minimum Wake Time" + }, + "noConnectionBluetoothDisabled": { + "description": "If the device does not receive a Bluetooth connection, the BLE radio will be disabled after this long", + "label": "No Connection Bluetooth Disabled" + }, + "powerSavingEnabled": { + "description": "Select if powered from a low-current source (i.e. solar), to minimize power consumption as much as possible.", + "label": "Ativar modo de poupança de energia" + }, + "shutdownOnBatteryDelay": { + "description": "Automatically shutdown node after this long when on battery, 0 for indefinite", + "label": "Shutdown on battery delay" + }, + "superDeepSleepDuration": { + "description": "How long the device will be in super deep sleep for", + "label": "Super Deep Sleep Duration" + }, + "powerConfigSettings": { + "description": "Settings for the power module", + "label": "Configuração de Energia" + }, + "sleepSettings": { + "description": "Sleep settings for the power module", + "label": "Sleep Settings" + } + }, + "security": { + "description": "Settings for the Security configuration", + "title": "Security Settings", + "button_backupKey": "Backup Key", + "adminChannelEnabled": { + "description": "Allow incoming device control over the insecure legacy admin channel", + "label": "Allow Legacy Admin" + }, + "enableDebugLogApi": { + "description": "Output live debug logging over serial, view and export position-redacted device logs over Bluetooth", + "label": "Enable Debug Log API" + }, + "managed": { + "description": "If enabled, device configuration options are only able to be changed remotely by a Remote Admin node via admin messages. Do not enable this option unless at least one suitable Remote Admin node has been setup, and the public key is stored in one of the fields above.", + "label": "Managed" + }, + "privateKey": { + "description": "Used to create a shared key with a remote device", + "label": "Chave privada" + }, + "publicKey": { + "description": "Sent out to other nodes on the mesh to allow them to compute a shared secret key", + "label": "Chave pública" + }, + "primaryAdminKey": { + "description": "The primary public key authorized to send admin messages to this node", + "label": "Primary Admin Key" + }, + "secondaryAdminKey": { + "description": "The secondary public key authorized to send admin messages to this node", + "label": "Secondary Admin Key" + }, + "serialOutputEnabled": { + "description": "Serial Console over the Stream API", + "label": "Serial Output Enabled" + }, + "tertiaryAdminKey": { + "description": "The tertiary public key authorized to send admin messages to this node", + "label": "Tertiary Admin Key" + }, + "adminSettings": { + "description": "Settings for Admin", + "label": "Admin Settings" + }, + "loggingSettings": { + "description": "Settings for Logging", + "label": "Logging Settings" + } + }, + "user": { + "title": "User Settings", + "description": "Configure your device name and identity settings", + "longName": { + "label": "Long Name", + "description": "Your full display name (1-40 characters)", + "validation": { + "min": "Long name must be at least 1 character", + "max": "Long name must be at most 40 characters" + } + }, + "shortName": { + "label": "Short Name", + "description": "Your abbreviated name (2-4 characters)", + "validation": { + "min": "Short name must be at least 2 characters", + "max": "Short name must be at most 4 characters" + } + }, + "isUnmessageable": { + "label": "Impossível enviar mensagens", + "description": "Used to identify unmonitored or infrastructure nodes so that messaging is not available to nodes that will never respond." + }, + "isLicensed": { + "label": "Rádio amador licenciado (HAM)", + "description": "Enable if you are a licensed amateur radio operator, enabling this option disables encryption and is not compatible with the default Meshtastic network." + } + } +} diff --git a/packages/web/public/i18n/locales/pt-PT/connections.json b/packages/web/public/i18n/locales/pt-PT/connections.json new file mode 100644 index 000000000..dc9aa03a5 --- /dev/null +++ b/packages/web/public/i18n/locales/pt-PT/connections.json @@ -0,0 +1,34 @@ +{ + "page": { + "title": "Connect to a Meshtastic device", + "description": "Add a device connection via HTTP, Bluetooth, or Serial. Your saved connections will be saved in your browser." + }, + "connectionType_ble": "BLE", + "connectionType_serial": "Série", + "connectionType_network": "Rede", + "deleteConnection": "Delete connection", + "areYouSure": "This will remove {{name}}. You canot undo this action.", + "moreActions": "More actions", + "noConnections": { + "title": "No connections yet.", + "description": "Create your first connection. It will connect immediately and be saved for later." + }, + "lastConnectedAt": "Last connected: {{date}}", + "neverConnected": "Never connected", + "toasts": { + "connected": "Ligado", + "nowConnected": "{{name}} is now connected", + "nowDisconnected": "{{name}} are now disconnecte", + "disconnected": "Desconectado", + "failed": "Failed to connect", + "checkConnetion": "Check your device or settings and try again", + "defaultSet": "Default set", + "defaultConnection": "Default connection is now {{nameisconnected}}", + "deleted": "Deleted", + "deletedByName": "{{name}} was removed", + "pickConnectionAgain": "Could not connect. You may need to reselect the device/port.", + "added": "Connection added", + "savedByName": "{{name}} saved.", + "savedCantConnect": "The connection was saved but could not connect." + } +} diff --git a/packages/web/public/i18n/locales/pt-PT/dashboard.json b/packages/web/public/i18n/locales/pt-PT/dashboard.json deleted file mode 100644 index 0c694905a..000000000 --- a/packages/web/public/i18n/locales/pt-PT/dashboard.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "dashboard": { - "title": "Connected Devices", - "description": "Manage your connected Meshtastic devices.", - "connectionType_ble": "BLE", - "connectionType_serial": "Série", - "connectionType_network": "Rede", - "noDevicesTitle": "No devices connected", - "noDevicesDescription": "Connect a new device to get started.", - "button_newConnection": "New Connection" - } -} diff --git a/packages/web/public/i18n/locales/pt-PT/deviceConfig.json b/packages/web/public/i18n/locales/pt-PT/deviceConfig.json index 8e280fc0b..3b903b680 100644 --- a/packages/web/public/i18n/locales/pt-PT/deviceConfig.json +++ b/packages/web/public/i18n/locales/pt-PT/deviceConfig.json @@ -122,7 +122,7 @@ "title": "Mesh Settings", "description": "Settings for the LoRa mesh", "bandwidth": { - "description": "Channel bandwidth in MHz", + "description": "Channel bandwidth in kHz", "label": "Largura de banda" }, "boostedRxGain": { diff --git a/packages/web/public/i18n/locales/pt-PT/dialog.json b/packages/web/public/i18n/locales/pt-PT/dialog.json index 2f057128f..1a458b523 100644 --- a/packages/web/public/i18n/locales/pt-PT/dialog.json +++ b/packages/web/public/i18n/locales/pt-PT/dialog.json @@ -1,193 +1,238 @@ { - "deleteMessages": { - "description": "This action will clear all message history. This cannot be undone. Are you sure you want to continue?", - "title": "Clear All Messages" - }, - "deviceName": { - "description": "The Device will restart once the config is saved.", - "longName": "Long Name", - "shortName": "Short Name", - "title": "Change Device Name", - "validation": { - "longNameMax": "Long name must not be more than 40 characters", - "shortNameMax": "Short name must not be more than 4 characters", - "longNameMin": "Long name must have at least 1 character", - "shortNameMin": "Short name must have at least 1 character" - } - }, - "import": { - "description": "The current LoRa configuration will be overridden.", - "error": { - "invalidUrl": "Invalid Meshtastic URL" - }, - "channelPrefix": "Channel: ", - "channelSetUrl": "Channel Set/QR Code URL", - "channels": "Channels:", - "usePreset": "Use Preset?", - "title": "Import Channel Set" - }, - "locationResponse": { - "title": "Location: {{identifier}}", - "altitude": "Altitude: ", - "coordinates": "Coordinates: ", - "noCoordinates": "No Coordinates" - }, - "pkiRegenerateDialog": { - "title": "Regenerate Pre-Shared Key?", - "description": "Are you sure you want to regenerate the pre-shared key?", - "regenerate": "Regenerate" - }, - "newDeviceDialog": { - "title": "Connect New Device", - "https": "https", - "http": "http", - "tabHttp": "HTTP", - "tabBluetooth": "Bluetooth", - "tabSerial": "Série", - "useHttps": "Use HTTPS", - "connecting": "Connecting...", - "connect": "Ligar", - "connectionFailedAlert": { - "title": "Connection Failed", - "descriptionPrefix": "Could not connect to the device. ", - "httpsHint": "If using HTTPS, you may need to accept a self-signed certificate first. ", - "openLinkPrefix": "Please open ", - "openLinkSuffix": " in a new tab", - "acceptTlsWarningSuffix": ", accept any TLS warnings if prompted, then try again", - "learnMoreLink": "Learn more" - }, - "httpConnection": { - "label": "IP Address/Hostname", - "placeholder": "000.000.000.000 / meshtastic.local" - }, - "serialConnection": { - "noDevicesPaired": "No devices paired yet.", - "newDeviceButton": "New device", - "deviceIdentifier": "# {{index}} - {{vendorId}} - {{productId}}" - }, - "bluetoothConnection": { - "noDevicesPaired": "No devices paired yet.", - "newDeviceButton": "New device", - "connectionFailed": "Connection failed", - "deviceDisconnected": "Device disconnected", - "unknownDevice": "Unknown Device", - "errorLoadingDevices": "Error loading devices", - "unknownErrorLoadingDevices": "Unknown error loading devices" - }, - "validation": { - "requiresWebBluetooth": "This connection type requires <0>Web Bluetooth. Please use a supported browser, like Chrome or Edge.", - "requiresWebSerial": "This connection type requires <0>Web Serial. Please use a supported browser, like Chrome or Edge.", - "requiresSecureContext": "This application requires a <0>secure context. Please connect using HTTPS or localhost.", - "additionallyRequiresSecureContext": "Additionally, it requires a <0>secure context. Please connect using HTTPS or localhost." - } - }, - "nodeDetails": { - "message": "Mensagem", - "requestPosition": "Request Position", - "traceRoute": "Trace Route", - "airTxUtilization": "Air TX utilization", - "allRawMetrics": "All Raw Metrics:", - "batteryLevel": "Battery level", - "channelUtilization": "Channel utilization", - "details": "Details:", - "deviceMetrics": "Device Metrics:", - "hardware": "Hardware: ", - "lastHeard": "Last Heard: ", - "nodeHexPrefix": "Node Hex: ", - "nodeNumber": "Node Number: ", - "position": "Position:", - "role": "Role: ", - "uptime": "Uptime: ", - "voltage": "Voltagem", - "title": "Node Details for {{identifier}}", - "ignoreNode": "Ignore node", - "removeNode": "Remove node", - "unignoreNode": "Unignore node", - "security": "Security:", - "publicKey": "Public Key: ", - "messageable": "Messageable: ", - "KeyManuallyVerifiedTrue": "Public Key has been manually verified", - "KeyManuallyVerifiedFalse": "Public Key is not manually verified" - }, - "pkiBackup": { - "loseKeysWarning": "If you lose your keys, you will need to reset your device.", - "secureBackup": "Its important to backup your public and private keys and store your backup securely!", - "footer": "=== END OF KEYS ===", - "header": "=== MESHTASTIC KEYS FOR {{longName}} ({{shortName}}) ===", - "privateKey": "Private Key:", - "publicKey": "Public Key:", - "fileName": "meshtastic_keys_{{longName}}_{{shortName}}.txt", - "title": "Backup Keys" - }, - "pkiBackupReminder": { - "description": "We recommend backing up your key data regularly. Would you like to back up now?", - "title": "Backup Reminder", - "remindLaterPrefix": "Remind me in", - "remindNever": "Never remind me", - "backupNow": "Back up now" - }, - "pkiRegenerate": { - "description": "Are you sure you want to regenerate key pair?", - "title": "Regenerate Key Pair" - }, - "qr": { - "addChannels": "Add Channels", - "replaceChannels": "Replace Channels", - "description": "The current LoRa configuration will also be shared.", - "sharableUrl": "Sharable URL", - "title": "Generate QR Code" - }, - "reboot": { - "title": "Reboot device", - "description": "Reboot now or schedule a reboot of the connected node. Optionally, you can choose to reboot into OTA (Over-the-Air) mode.", - "ota": "Reboot into OTA mode", - "enterDelay": "Enter delay", - "scheduled": "Reboot has been scheduled", - "schedule": "Schedule reboot", - "now": "Reboot now", - "cancel": "Cancel scheduled reboot" - }, - "refreshKeys": { - "description": { - "acceptNewKeys": "This will remove the node from device and request new keys.", - "keyMismatchReasonSuffix": ". This is due to the remote node's current public key does not match the previously stored key for this node.", - "unableToSendDmPrefix": "Your node is unable to send a direct message to node: " - }, - "acceptNewKeys": "Accept New Keys", - "title": "Keys Mismatch - {{identifier}}" - }, - "removeNode": { - "description": "Are you sure you want to remove this Node?", - "title": "Remove Node?" - }, - "shutdown": { - "title": "Schedule Shutdown", - "description": "Turn off the connected node after x minutes." - }, - "traceRoute": { - "routeToDestination": "Route to destination:", - "routeBack": "Route back:" - }, - "tracerouteResponse": { - "title": "Traceroute: {{identifier}}" - }, - "unsafeRoles": { - "confirmUnderstanding": "Yes, I know what I'm doing", - "conjunction": " and the blog post about ", - "postamble": " and understand the implications of changing the role.", - "preamble": "I have read the ", - "choosingRightDeviceRole": "Choosing The Right Device Role", - "deviceRoleDocumentation": "Device Role Documentation", - "title": "Confirma?" - }, - "managedMode": { - "confirmUnderstanding": "Yes, I know what I'm doing", - "title": "Confirma?", - "description": "Enabling Managed Mode blocks client applications (including the web client) from writing configurations to a radio. Once enabled, radio configurations can only be changed through Remote Admin messages. This setting is not required for remote node administration." - }, - "clientNotification": { - "title": "Client Notification", - "TraceRoute can only be sent once every 30 seconds": "TraceRoute can only be sent once every 30 seconds", - "Compromised keys were detected and regenerated.": "Compromised keys were detected and regenerated." - } + "deleteMessages": { + "description": "This action will clear all message history. This cannot be undone. Are you sure you want to continue?", + "title": "Clear All Messages" + }, + "import": { + "description": "The current LoRa configuration will be overridden.", + "error": { + "invalidUrl": "Invalid Meshtastic URL" + }, + "channelPrefix": "Channel: ", + "primary": "Primary ", + "doNotImport": "No not import", + "channelName": "Nome", + "channelSlot": "Slot", + "channelSetUrl": "Channel Set/QR Code URL", + "useLoraConfig": "Import LoRa Config", + "presetDescription": "The current LoRa Config will be replaced.", + "title": "Import Channel Set" + }, + "locationResponse": { + "title": "Location: {{identifier}}", + "altitude": "Altitude: ", + "coordinates": "Coordinates: ", + "noCoordinates": "No Coordinates" + }, + "pkiRegenerateDialog": { + "title": "Regenerate Pre-Shared Key?", + "description": "Are you sure you want to regenerate the pre-shared key?", + "regenerate": "Regenerate" + }, + "addConnection": { + "title": "Add connection", + "description": "Choose a connection type and fill in the details", + "validation": { + "requiresWebBluetooth": "This connection type requires <0>Web Bluetooth. Please use a supported browser, like Chrome or Edge.", + "requiresWebSerial": "This connection type requires <0>Web Serial. Please use a supported browser, like Chrome or Edge.", + "requiresSecureContext": "This application requires a <0>secure context. Please connect using HTTPS or localhost.", + "additionallyRequiresSecureContext": "Additionally, it requires a <0>secure context. Please connect using HTTPS or localhost." + }, + "bluetoothConnection": { + "namePlaceholder": "My Bluetooth Node", + "supported": { + "title": "Web Bluetooth supported" + }, + "notSupported": { + "title": "Web Bluetooth not supported", + "description": "Your browser or device does not support Web Bluetooth" + }, + "short": "BT: {{deviceName}}", + "long": "Bluetooth Device", + "device": "Dispositivo", + "selectDevice": "Select device", + "selected": "Bluetooth device selected", + "notSelected": "No device selected", + "helperText": "Uses the Meshtastic Bluetooth service for discovery." + }, + "serialConnection": { + "namePlaceholder": "My Serial Node", + "helperText": "Selecting a port grants permission so the app can open it to connect.", + "supported": { + "title": "Web Serial supported" + }, + "notSupported": { + "title": "Web Serial not supported", + "description": "Your browser or device does not support Web Serial" + }, + "portSelected": { + "title": "Serial port selected", + "description": "Port permissions granted." + }, + "port": "Port", + "selectPort": "Select port", + "deviceName": "USB {{vendorId}}:{{productId}}", + "notSelected": "No port selected" + }, + "httpConnection": { + "namePlaceholder": "My HTTP Node", + "inputPlaceholder": "192.168.1.10 or meshtastic.local", + "heading": "URL or IP", + "useHttps": "Use HTTTPS", + "invalidUrl": { + "title": "Invalid URL", + "description": "Please enter a valid HTTP or HTTPS URL." + }, + "connectionTest": { + "description": "Test the connetion before saving to verify the device is reachable.", + "button": { + "loading": "Testing...", + "label": "Test connection" + }, + "reachable": "Reachable", + "notReachable": "Not reachable", + "success": { + "title": "Connection test successful", + "description": "The device appears to be reachable." + }, + "failure": { + "title": "Connection test failed", + "description": "Could not reach the device. Check the URL and try again." + } + } + } + }, + "nodeDetails": { + "message": "Mensagem", + "requestPosition": "Request Position", + "traceRoute": "Trace Route", + "airTxUtilization": "Air TX utilization", + "allRawMetrics": "All Raw Metrics:", + "batteryLevel": "Battery level", + "channelUtilization": "Channel utilization", + "details": "Details:", + "deviceMetrics": "Device Metrics:", + "hardware": "Hardware: ", + "lastHeard": "Last Heard: ", + "nodeHexPrefix": "Node Hex: ", + "nodeNumber": "Node Number: ", + "position": "Position:", + "role": "Role: ", + "uptime": "Uptime: ", + "voltage": "Voltagem", + "title": "Node Details for {{identifier}}", + "ignoreNode": "Ignore node", + "removeNode": "Remove node", + "unignoreNode": "Unignore node", + "security": "Security:", + "publicKey": "Public Key: ", + "messageable": "Messageable: ", + "KeyManuallyVerifiedTrue": "Public Key has been manually verified", + "KeyManuallyVerifiedFalse": "Public Key is not manually verified" + }, + "pkiBackup": { + "loseKeysWarning": "If you lose your keys, you will need to reset your device.", + "secureBackup": "Its important to backup your public and private keys and store your backup securely!", + "footer": "=== END OF KEYS ===", + "header": "=== MESHTASTIC KEYS FOR {{longName}} ({{shortName}}) ===", + "privateKey": "Private Key:", + "publicKey": "Public Key:", + "fileName": "meshtastic_keys_{{longName}}_{{shortName}}.txt", + "title": "Backup Keys" + }, + "pkiBackupReminder": { + "description": "We recommend backing up your key data regularly. Would you like to back up now?", + "title": "Backup Reminder", + "remindLaterPrefix": "Remind me in", + "remindNever": "Never remind me", + "backupNow": "Back up now" + }, + "pkiRegenerate": { + "description": "Are you sure you want to regenerate key pair?", + "title": "Regenerate Key Pair" + }, + "qr": { + "addChannels": "Add Channels", + "replaceChannels": "Replace Channels", + "description": "The current LoRa configuration will also be shared.", + "sharableUrl": "Sharable URL", + "title": "Generate QR Code" + }, + "reboot": { + "title": "Reboot device", + "description": "Reboot now or schedule a reboot of the connected node. Optionally, you can choose to reboot into OTA (Over-the-Air) mode.", + "ota": "Reboot into OTA mode", + "enterDelay": "Enter delay", + "scheduled": "Reboot has been scheduled", + "schedule": "Schedule reboot", + "now": "Reboot now", + "cancel": "Cancel scheduled reboot" + }, + "refreshKeys": { + "description": { + "acceptNewKeys": "This will remove the node from device and request new keys.", + "keyMismatchReasonSuffix": ". This is due to the remote node's current public key does not match the previously stored key for this node.", + "unableToSendDmPrefix": "Your node is unable to send a direct message to node: " + }, + "acceptNewKeys": "Accept New Keys", + "title": "Keys Mismatch - {{identifier}}" + }, + "removeNode": { + "description": "Are you sure you want to remove this Node?", + "title": "Remove Node?" + }, + "shutdown": { + "title": "Schedule Shutdown", + "description": "Turn off the connected node after x minutes." + }, + "traceRoute": { + "routeToDestination": "Route to destination:", + "routeBack": "Route back:" + }, + "tracerouteResponse": { + "title": "Traceroute: {{identifier}}" + }, + "unsafeRoles": { + "confirmUnderstanding": "Yes, I know what I'm doing", + "conjunction": " and the blog post about ", + "postamble": " and understand the implications of changing the role.", + "preamble": "I have read the ", + "choosingRightDeviceRole": "Choosing The Right Device Role", + "deviceRoleDocumentation": "Device Role Documentation", + "title": "Confirma?" + }, + "managedMode": { + "confirmUnderstanding": "Yes, I know what I'm doing", + "title": "Confirma?", + "description": "Enabling Managed Mode blocks client applications (including the web client) from writing configurations to a radio. Once enabled, radio configurations can only be changed through Remote Admin messages. This setting is not required for remote node administration." + }, + "clientNotification": { + "title": "Client Notification", + "TraceRoute can only be sent once every 30 seconds": "TraceRoute can only be sent once every 30 seconds", + "Compromised keys were detected and regenerated.": "Compromised keys were detected and regenerated." + }, + "resetNodeDb": { + "title": "Reset Node Database", + "description": "This will clear all nodes from the connected device's node database and clear all message history in the client. This cannot be undone. Are you sure you want to continue?", + "confirm": "Reset Node Database", + "failedTitle": "There was an error resetting the Node DB. Please try again." + }, + "clearAllStores": { + "title": "Clear All Local Storage", + "description": "This will clear all locally stored data, including message history and node databases for all previously connected devices. This will require you to reconnect to your node once complete and cannot be undone. Are you sure you want to continue?", + "confirm": "Clear all local storage", + "failedTitle": "There was an error clearing local storage. Please try again." + }, + "factoryResetDevice": { + "title": "Factory Reset Device", + "description": "This will factory reset the connected device, erasing all configurations and data on the device as well as all nodes and messages saved in the client. This cannot be undone. Are you sure you want to continue?", + "confirm": "Factory Reset Device", + "failedTitle": "There was an error performing the factory reset. Please try again." + }, + "factoryResetConfig": { + "title": "Factory Reset Config", + "description": "This will factory reset the configuration on the connected device, erasing all configurations on the device. This cannot be undone. Are you sure you want to continue?", + "confirm": "Factory Reset Config", + "failedTitle": "There was an error performing the factory reset. Please try again." + } } diff --git a/packages/web/public/i18n/locales/pt-PT/map.json b/packages/web/public/i18n/locales/pt-PT/map.json new file mode 100644 index 000000000..fc2b7c4f2 --- /dev/null +++ b/packages/web/public/i18n/locales/pt-PT/map.json @@ -0,0 +1,38 @@ +{ + "maplibre": { + "GeolocateControl.FindMyLocation": "Find my location", + "NavigationControl.ZoomIn": "Zoom in", + "NavigationControl.ZoomOut": "Zoom out", + "CooperativeGesturesHandler.WindowsHelpText": "Use Ctrl + scroll to zoom the map", + "CooperativeGesturesHandler.MacHelpText": "Use ⌘ + scroll to zoom the map", + "CooperativeGesturesHandler.MobileHelpText": "Use two fingers to move the map" + }, + "layerTool": { + "nodeMarkers": "Show nodes", + "directNeighbors": "Show direct connections", + "remoteNeighbors": "Show remote connections", + "positionPrecision": "Show position precision", + "traceroutes": "Show traceroutes", + "waypoints": "Show waypoints" + }, + "mapMenu": { + "locateAria": "Locate my node", + "layersAria": "Change map style" + }, + "waypointDetail": { + "edit": "Editar", + "description": "Description:", + "createdBy": "Edited by:", + "createdDate": "Created:", + "updated": "Updated:", + "expires": "Expires:", + "distance": "Distance:", + "bearing": "Absolute bearing:", + "lockedTo": "Locked by:", + "latitude": "Latitude:", + "longitude": "Longitude:" + }, + "myNode": { + "tooltip": "This device" + } +} diff --git a/packages/web/public/i18n/locales/pt-PT/messages.json b/packages/web/public/i18n/locales/pt-PT/messages.json index a4647b95c..cd7260a8d 100644 --- a/packages/web/public/i18n/locales/pt-PT/messages.json +++ b/packages/web/public/i18n/locales/pt-PT/messages.json @@ -1,39 +1,39 @@ { - "page": { - "title": "Messages: {{chatName}}", - "placeholder": "Enter Message" - }, - "emptyState": { - "title": "Select a Chat", - "text": "No messages yet." - }, - "selectChatPrompt": { - "text": "Select a channel or node to start messaging." - }, - "sendMessage": { - "placeholder": "Enter your message here...", - "sendButton": "Enviar" - }, - "actionsMenu": { - "addReactionLabel": "Add Reaction", - "replyLabel": "Responder" - }, - "deliveryStatus": { - "delivered": { - "label": "Message delivered", - "displayText": "Message delivered" - }, - "failed": { - "label": "Message delivery failed", - "displayText": "Delivery failed" - }, - "unknown": { - "label": "Message status unknown", - "displayText": "Unknown state" - }, - "waiting": { - "label": "Sending message", - "displayText": "Waiting for delivery" - } - } + "page": { + "title": "Messages: {{chatName}}", + "placeholder": "Enter Message" + }, + "emptyState": { + "title": "Select a Chat", + "text": "No messages yet." + }, + "selectChatPrompt": { + "text": "Select a channel or node to start messaging." + }, + "sendMessage": { + "placeholder": "Enter your message here...", + "sendButton": "Enviar" + }, + "actionsMenu": { + "addReactionLabel": "Add Reaction", + "replyLabel": "Responder" + }, + "deliveryStatus": { + "delivered": { + "label": "Message delivered", + "displayText": "Message delivered" + }, + "failed": { + "label": "Message delivery failed", + "displayText": "Delivery failed" + }, + "unknown": { + "label": "Message status unknown", + "displayText": "Unknown state" + }, + "waiting": { + "label": "Sending message", + "displayText": "Waiting for delivery" + } + } } diff --git a/packages/web/public/i18n/locales/pt-PT/moduleConfig.json b/packages/web/public/i18n/locales/pt-PT/moduleConfig.json index 20f353b49..7aa6c1078 100644 --- a/packages/web/public/i18n/locales/pt-PT/moduleConfig.json +++ b/packages/web/public/i18n/locales/pt-PT/moduleConfig.json @@ -1,448 +1,448 @@ { - "page": { - "tabAmbientLighting": "Iluminação ambiente", - "tabAudio": "Áudio", - "tabCannedMessage": "Canned", - "tabDetectionSensor": "Sensor de deteção", - "tabExternalNotification": "Ext Notif", - "tabMqtt": "MQTT", - "tabNeighborInfo": "Informações da vizinhança", - "tabPaxcounter": "Contador de pessoas", - "tabRangeTest": "Teste de Alcance", - "tabSerial": "Série", - "tabStoreAndForward": "S&F", - "tabTelemetry": "Telemetria" - }, - "ambientLighting": { - "title": "Ambient Lighting Settings", - "description": "Settings for the Ambient Lighting module", - "ledState": { - "label": "LED State", - "description": "Sets LED to on or off" - }, - "current": { - "label": "Atual", - "description": "Sets the current for the LED output. Default is 10" - }, - "red": { - "label": "Vermelho", - "description": "Sets the red LED level. Values are 0-255" - }, - "green": { - "label": "Verde", - "description": "Sets the green LED level. Values are 0-255" - }, - "blue": { - "label": "Azul", - "description": "Sets the blue LED level. Values are 0-255" - } - }, - "audio": { - "title": "Audio Settings", - "description": "Settings for the Audio module", - "codec2Enabled": { - "label": "Codec 2 Enabled", - "description": "Enable Codec 2 audio encoding" - }, - "pttPin": { - "label": "PTT Pin", - "description": "GPIO pin to use for PTT" - }, - "bitrate": { - "label": "Bitrate", - "description": "Bitrate to use for audio encoding" - }, - "i2sWs": { - "label": "i2S WS", - "description": "GPIO pin to use for i2S WS" - }, - "i2sSd": { - "label": "i2S SD", - "description": "GPIO pin to use for i2S SD" - }, - "i2sDin": { - "label": "i2S DIN", - "description": "GPIO pin to use for i2S DIN" - }, - "i2sSck": { - "label": "i2S SCK", - "description": "GPIO pin to use for i2S SCK" - } - }, - "cannedMessage": { - "title": "Canned Message Settings", - "description": "Settings for the Canned Message module", - "moduleEnabled": { - "label": "Module Enabled", - "description": "Enable Canned Message" - }, - "rotary1Enabled": { - "label": "Rotary Encoder #1 Enabled", - "description": "Enable the rotary encoder" - }, - "inputbrokerPinA": { - "label": "Encoder Pin A", - "description": "GPIO Pin Value (1-39) For encoder port A" - }, - "inputbrokerPinB": { - "label": "Encoder Pin B", - "description": "GPIO Pin Value (1-39) For encoder port B" - }, - "inputbrokerPinPress": { - "label": "Encoder Pin Press", - "description": "GPIO Pin Value (1-39) For encoder Press" - }, - "inputbrokerEventCw": { - "label": "Clockwise event", - "description": "Select input event." - }, - "inputbrokerEventCcw": { - "label": "Counter Clockwise event", - "description": "Select input event." - }, - "inputbrokerEventPress": { - "label": "Press event", - "description": "Select input event" - }, - "updown1Enabled": { - "label": "Up Down enabled", - "description": "Enable the up / down encoder" - }, - "allowInputSource": { - "label": "Allow Input Source", - "description": "Select from: '_any', 'rotEnc1', 'upDownEnc1', 'cardkb'" - }, - "sendBell": { - "label": "Send Bell", - "description": "Sends a bell character with each message" - } - }, - "detectionSensor": { - "title": "Detection Sensor Settings", - "description": "Settings for the Detection Sensor module", - "enabled": { - "label": "Enabled", - "description": "Enable or disable Detection Sensor Module" - }, - "minimumBroadcastSecs": { - "label": "Minimum Broadcast Seconds", - "description": "The interval in seconds of how often we can send a message to the mesh when a state change is detected" - }, - "stateBroadcastSecs": { - "label": "State Broadcast Seconds", - "description": "The interval in seconds of how often we should send a message to the mesh with the current state regardless of changes" - }, - "sendBell": { - "label": "Send Bell", - "description": "Send ASCII bell with alert message" - }, - "name": { - "label": "Friendly Name", - "description": "Used to format the message sent to mesh, max 20 Characters" - }, - "monitorPin": { - "label": "Monitor Pin", - "description": "The GPIO pin to monitor for state changes" - }, - "detectionTriggerType": { - "label": "Detection Triggered Type", - "description": "The type of trigger event to be used" - }, - "usePullup": { - "label": "Use Pullup", - "description": "Whether or not use INPUT_PULLUP mode for GPIO pin" - } - }, - "externalNotification": { - "title": "External Notification Settings", - "description": "Configure the external notification module", - "enabled": { - "label": "Module Enabled", - "description": "Enable External Notification" - }, - "outputMs": { - "label": "Output MS", - "description": "Output MS" - }, - "output": { - "label": "Output", - "description": "Output" - }, - "outputVibra": { - "label": "Output Vibrate", - "description": "Output Vibrate" - }, - "outputBuzzer": { - "label": "Output Buzzer", - "description": "Output Buzzer" - }, - "active": { - "label": "Active", - "description": "Active" - }, - "alertMessage": { - "label": "Alert Message", - "description": "Alert Message" - }, - "alertMessageVibra": { - "label": "Alert Message Vibrate", - "description": "Alert Message Vibrate" - }, - "alertMessageBuzzer": { - "label": "Alert Message Buzzer", - "description": "Alert Message Buzzer" - }, - "alertBell": { - "label": "Alert Bell", - "description": "Should an alert be triggered when receiving an incoming bell?" - }, - "alertBellVibra": { - "label": "Alert Bell Vibrate", - "description": "Alert Bell Vibrate" - }, - "alertBellBuzzer": { - "label": "Alert Bell Buzzer", - "description": "Alert Bell Buzzer" - }, - "usePwm": { - "label": "Use PWM", - "description": "Use PWM" - }, - "nagTimeout": { - "label": "Nag Timeout", - "description": "Nag Timeout" - }, - "useI2sAsBuzzer": { - "label": "Use I²S Pin as Buzzer", - "description": "Designate I²S Pin as Buzzer Output" - } - }, - "mqtt": { - "title": "MQTT Settings", - "description": "Settings for the MQTT module", - "enabled": { - "label": "Enabled", - "description": "Enable or disable MQTT" - }, - "address": { - "label": "MQTT Server Address", - "description": "MQTT server address to use for default/custom servers" - }, - "username": { - "label": "MQTT Username", - "description": "MQTT username to use for default/custom servers" - }, - "password": { - "label": "MQTT Password", - "description": "MQTT password to use for default/custom servers" - }, - "encryptionEnabled": { - "label": "Encryption Enabled", - "description": "Enable or disable MQTT encryption. Note: All messages are sent to the MQTT broker unencrypted if this option is not enabled, even when your uplink channels have encryption keys set. This includes position data." - }, - "jsonEnabled": { - "label": "JSON Enabled", - "description": "Whether to send/consume JSON packets on MQTT" - }, - "tlsEnabled": { - "label": "TLS Enabled", - "description": "Enable or disable TLS" - }, - "root": { - "label": "Tópico principal", - "description": "MQTT root topic to use for default/custom servers" - }, - "proxyToClientEnabled": { - "label": "MQTT Client Proxy Enabled", - "description": "Utilizes the network connection to proxy MQTT messages to the client." - }, - "mapReportingEnabled": { - "label": "Map Reporting Enabled", - "description": "Your node will periodically send an unencrypted map report packet to the configured MQTT server, this includes id, short and long name, approximate location, hardware model, role, firmware version, LoRa region, modem preset and primary channel name." - }, - "mapReportSettings": { - "publishIntervalSecs": { - "label": "Map Report Publish Interval (s)", - "description": "Interval in seconds to publish map reports" - }, - "positionPrecision": { - "label": "Approximate Location", - "description": "Position shared will be accurate within this distance", - "options": { - "metric_km23": "Within 23 km", - "metric_km12": "Within 12 km", - "metric_km5_8": "Within 5.8 km", - "metric_km2_9": "Within 2.9 km", - "metric_km1_5": "Within 1.5 km", - "metric_m700": "Within 700 m", - "metric_m350": "Within 350 m", - "metric_m200": "Within 200 m", - "metric_m90": "Within 90 m", - "metric_m50": "Within 50 m", - "imperial_mi15": "Within 15 miles", - "imperial_mi7_3": "Within 7.3 miles", - "imperial_mi3_6": "Within 3.6 miles", - "imperial_mi1_8": "Within 1.8 miles", - "imperial_mi0_9": "Within 0.9 miles", - "imperial_mi0_5": "Within 0.5 miles", - "imperial_mi0_2": "Within 0.2 miles", - "imperial_ft600": "Within 600 feet", - "imperial_ft300": "Within 300 feet", - "imperial_ft150": "Within 150 feet" - } - } - } - }, - "neighborInfo": { - "title": "Neighbor Info Settings", - "description": "Settings for the Neighbor Info module", - "enabled": { - "label": "Enabled", - "description": "Enable or disable Neighbor Info Module" - }, - "updateInterval": { - "label": "Update Interval", - "description": "Interval in seconds of how often we should try to send our Neighbor Info to the mesh" - } - }, - "paxcounter": { - "title": "Paxcounter Settings", - "description": "Settings for the Paxcounter module", - "enabled": { - "label": "Module Enabled", - "description": "Enable Paxcounter" - }, - "paxcounterUpdateInterval": { - "label": "Update Interval (seconds)", - "description": "How long to wait between sending paxcounter packets" - }, - "wifiThreshold": { - "label": "WiFi RSSI Threshold", - "description": "At what WiFi RSSI level should the counter increase. Defaults to -80." - }, - "bleThreshold": { - "label": "BLE RSSI Threshold", - "description": "At what BLE RSSI level should the counter increase. Defaults to -80." - } - }, - "rangeTest": { - "title": "Range Test Settings", - "description": "Settings for the Range Test module", - "enabled": { - "label": "Module Enabled", - "description": "Enable Range Test" - }, - "sender": { - "label": "Message Interval", - "description": "How long to wait between sending test packets" - }, - "save": { - "label": "Save CSV to storage", - "description": "ESP32 Only" - } - }, - "serial": { - "title": "Serial Settings", - "description": "Settings for the Serial module", - "enabled": { - "label": "Module Enabled", - "description": "Enable Serial output" - }, - "echo": { - "label": "Echo", - "description": "Any packets you send will be echoed back to your device" - }, - "rxd": { - "label": "Receive Pin", - "description": "Set the GPIO pin to the RXD pin you have set up." - }, - "txd": { - "label": "Transmit Pin", - "description": "Set the GPIO pin to the TXD pin you have set up." - }, - "baud": { - "label": "Baud Rate", - "description": "The serial baud rate" - }, - "timeout": { - "label": "Timeout", - "description": "Seconds to wait before we consider your packet as 'done'" - }, - "mode": { - "label": "Mode", - "description": "Select Mode" - }, - "overrideConsoleSerialPort": { - "label": "Override Console Serial Port", - "description": "If you have a serial port connected to the console, this will override it." - } - }, - "storeForward": { - "title": "Store & Forward Settings", - "description": "Settings for the Store & Forward module", - "enabled": { - "label": "Module Enabled", - "description": "Enable Store & Forward" - }, - "heartbeat": { - "label": "Heartbeat Enabled", - "description": "Enable Store & Forward heartbeat" - }, - "records": { - "label": "Número de registos", - "description": "Number of records to store" - }, - "historyReturnMax": { - "label": "History return max", - "description": "Max number of records to return" - }, - "historyReturnWindow": { - "label": "History return window", - "description": "Max number of records to return" - } - }, - "telemetry": { - "title": "Telemetry Settings", - "description": "Settings for the Telemetry module", - "deviceUpdateInterval": { - "label": "Device Metrics", - "description": "Intervalo de atualização de métricas do dispositivo (segundos)" - }, - "environmentUpdateInterval": { - "label": "Intervalo de atualização de métricas de ambiente (segundos)", - "description": "" - }, - "environmentMeasurementEnabled": { - "label": "Module Enabled", - "description": "Enable the Environment Telemetry" - }, - "environmentScreenEnabled": { - "label": "Displayed on Screen", - "description": "Show the Telemetry Module on the OLED" - }, - "environmentDisplayFahrenheit": { - "label": "Display Fahrenheit", - "description": "Display temp in Fahrenheit" - }, - "airQualityEnabled": { - "label": "Air Quality Enabled", - "description": "Enable the Air Quality Telemetry" - }, - "airQualityInterval": { - "label": "Air Quality Update Interval", - "description": "How often to send Air Quality data over the mesh" - }, - "powerMeasurementEnabled": { - "label": "Power Measurement Enabled", - "description": "Enable the Power Measurement Telemetry" - }, - "powerUpdateInterval": { - "label": "Power Update Interval", - "description": "How often to send Power data over the mesh" - }, - "powerScreenEnabled": { - "label": "Power Screen Enabled", - "description": "Enable the Power Telemetry Screen" - } - } + "page": { + "tabAmbientLighting": "Iluminação ambiente", + "tabAudio": "Áudio", + "tabCannedMessage": "Canned", + "tabDetectionSensor": "Sensor de deteção", + "tabExternalNotification": "Ext Notif", + "tabMqtt": "MQTT", + "tabNeighborInfo": "Informações da vizinhança", + "tabPaxcounter": "Contador de pessoas", + "tabRangeTest": "Teste de Alcance", + "tabSerial": "Série", + "tabStoreAndForward": "S&F", + "tabTelemetry": "Telemetria" + }, + "ambientLighting": { + "title": "Ambient Lighting Settings", + "description": "Settings for the Ambient Lighting module", + "ledState": { + "label": "LED State", + "description": "Sets LED to on or off" + }, + "current": { + "label": "Atual", + "description": "Sets the current for the LED output. Default is 10" + }, + "red": { + "label": "Vermelho", + "description": "Sets the red LED level. Values are 0-255" + }, + "green": { + "label": "Verde", + "description": "Sets the green LED level. Values are 0-255" + }, + "blue": { + "label": "Azul", + "description": "Sets the blue LED level. Values are 0-255" + } + }, + "audio": { + "title": "Audio Settings", + "description": "Settings for the Audio module", + "codec2Enabled": { + "label": "Codec 2 Enabled", + "description": "Enable Codec 2 audio encoding" + }, + "pttPin": { + "label": "PTT Pin", + "description": "GPIO pin to use for PTT" + }, + "bitrate": { + "label": "Bitrate", + "description": "Bitrate to use for audio encoding" + }, + "i2sWs": { + "label": "i2S WS", + "description": "GPIO pin to use for i2S WS" + }, + "i2sSd": { + "label": "i2S SD", + "description": "GPIO pin to use for i2S SD" + }, + "i2sDin": { + "label": "i2S DIN", + "description": "GPIO pin to use for i2S DIN" + }, + "i2sSck": { + "label": "i2S SCK", + "description": "GPIO pin to use for i2S SCK" + } + }, + "cannedMessage": { + "title": "Canned Message Settings", + "description": "Settings for the Canned Message module", + "moduleEnabled": { + "label": "Module Enabled", + "description": "Enable Canned Message" + }, + "rotary1Enabled": { + "label": "Rotary Encoder #1 Enabled", + "description": "Enable the rotary encoder" + }, + "inputbrokerPinA": { + "label": "Encoder Pin A", + "description": "GPIO Pin Value (1-39) For encoder port A" + }, + "inputbrokerPinB": { + "label": "Encoder Pin B", + "description": "GPIO Pin Value (1-39) For encoder port B" + }, + "inputbrokerPinPress": { + "label": "Encoder Pin Press", + "description": "GPIO Pin Value (1-39) For encoder Press" + }, + "inputbrokerEventCw": { + "label": "Clockwise event", + "description": "Select input event." + }, + "inputbrokerEventCcw": { + "label": "Counter Clockwise event", + "description": "Select input event." + }, + "inputbrokerEventPress": { + "label": "Press event", + "description": "Select input event" + }, + "updown1Enabled": { + "label": "Up Down enabled", + "description": "Enable the up / down encoder" + }, + "allowInputSource": { + "label": "Allow Input Source", + "description": "Select from: '_any', 'rotEnc1', 'upDownEnc1', 'cardkb'" + }, + "sendBell": { + "label": "Send Bell", + "description": "Sends a bell character with each message" + } + }, + "detectionSensor": { + "title": "Detection Sensor Settings", + "description": "Settings for the Detection Sensor module", + "enabled": { + "label": "Enabled", + "description": "Enable or disable Detection Sensor Module" + }, + "minimumBroadcastSecs": { + "label": "Minimum Broadcast Seconds", + "description": "The interval in seconds of how often we can send a message to the mesh when a state change is detected" + }, + "stateBroadcastSecs": { + "label": "State Broadcast Seconds", + "description": "The interval in seconds of how often we should send a message to the mesh with the current state regardless of changes" + }, + "sendBell": { + "label": "Send Bell", + "description": "Send ASCII bell with alert message" + }, + "name": { + "label": "Friendly Name", + "description": "Used to format the message sent to mesh, max 20 Characters" + }, + "monitorPin": { + "label": "Monitor Pin", + "description": "The GPIO pin to monitor for state changes" + }, + "detectionTriggerType": { + "label": "Detection Triggered Type", + "description": "The type of trigger event to be used" + }, + "usePullup": { + "label": "Use Pullup", + "description": "Whether or not use INPUT_PULLUP mode for GPIO pin" + } + }, + "externalNotification": { + "title": "External Notification Settings", + "description": "Configure the external notification module", + "enabled": { + "label": "Module Enabled", + "description": "Enable External Notification" + }, + "outputMs": { + "label": "Output MS", + "description": "Output MS" + }, + "output": { + "label": "Output", + "description": "Output" + }, + "outputVibra": { + "label": "Output Vibrate", + "description": "Output Vibrate" + }, + "outputBuzzer": { + "label": "Output Buzzer", + "description": "Output Buzzer" + }, + "active": { + "label": "Active", + "description": "Active" + }, + "alertMessage": { + "label": "Alert Message", + "description": "Alert Message" + }, + "alertMessageVibra": { + "label": "Alert Message Vibrate", + "description": "Alert Message Vibrate" + }, + "alertMessageBuzzer": { + "label": "Alert Message Buzzer", + "description": "Alert Message Buzzer" + }, + "alertBell": { + "label": "Alert Bell", + "description": "Should an alert be triggered when receiving an incoming bell?" + }, + "alertBellVibra": { + "label": "Alert Bell Vibrate", + "description": "Alert Bell Vibrate" + }, + "alertBellBuzzer": { + "label": "Alert Bell Buzzer", + "description": "Alert Bell Buzzer" + }, + "usePwm": { + "label": "Use PWM", + "description": "Use PWM" + }, + "nagTimeout": { + "label": "Nag Timeout", + "description": "Nag Timeout" + }, + "useI2sAsBuzzer": { + "label": "Use I²S Pin as Buzzer", + "description": "Designate I²S Pin as Buzzer Output" + } + }, + "mqtt": { + "title": "MQTT Settings", + "description": "Settings for the MQTT module", + "enabled": { + "label": "Enabled", + "description": "Enable or disable MQTT" + }, + "address": { + "label": "MQTT Server Address", + "description": "MQTT server address to use for default/custom servers" + }, + "username": { + "label": "MQTT Username", + "description": "MQTT username to use for default/custom servers" + }, + "password": { + "label": "MQTT Password", + "description": "MQTT password to use for default/custom servers" + }, + "encryptionEnabled": { + "label": "Encryption Enabled", + "description": "Enable or disable MQTT encryption. Note: All messages are sent to the MQTT broker unencrypted if this option is not enabled, even when your uplink channels have encryption keys set. This includes position data." + }, + "jsonEnabled": { + "label": "JSON Enabled", + "description": "Whether to send/consume JSON packets on MQTT" + }, + "tlsEnabled": { + "label": "TLS Enabled", + "description": "Enable or disable TLS" + }, + "root": { + "label": "Tópico principal", + "description": "MQTT root topic to use for default/custom servers" + }, + "proxyToClientEnabled": { + "label": "MQTT Client Proxy Enabled", + "description": "Utilizes the network connection to proxy MQTT messages to the client." + }, + "mapReportingEnabled": { + "label": "Map Reporting Enabled", + "description": "Your node will periodically send an unencrypted map report packet to the configured MQTT server, this includes id, short and long name, approximate location, hardware model, role, firmware version, LoRa region, modem preset and primary channel name." + }, + "mapReportSettings": { + "publishIntervalSecs": { + "label": "Map Report Publish Interval (s)", + "description": "Interval in seconds to publish map reports" + }, + "positionPrecision": { + "label": "Approximate Location", + "description": "Position shared will be accurate within this distance", + "options": { + "metric_km23": "Within 23 km", + "metric_km12": "Within 12 km", + "metric_km5_8": "Within 5.8 km", + "metric_km2_9": "Within 2.9 km", + "metric_km1_5": "Within 1.5 km", + "metric_m700": "Within 700 m", + "metric_m350": "Within 350 m", + "metric_m200": "Within 200 m", + "metric_m90": "Within 90 m", + "metric_m50": "Within 50 m", + "imperial_mi15": "Within 15 miles", + "imperial_mi7_3": "Within 7.3 miles", + "imperial_mi3_6": "Within 3.6 miles", + "imperial_mi1_8": "Within 1.8 miles", + "imperial_mi0_9": "Within 0.9 miles", + "imperial_mi0_5": "Within 0.5 miles", + "imperial_mi0_2": "Within 0.2 miles", + "imperial_ft600": "Within 600 feet", + "imperial_ft300": "Within 300 feet", + "imperial_ft150": "Within 150 feet" + } + } + } + }, + "neighborInfo": { + "title": "Neighbor Info Settings", + "description": "Settings for the Neighbor Info module", + "enabled": { + "label": "Enabled", + "description": "Enable or disable Neighbor Info Module" + }, + "updateInterval": { + "label": "Update Interval", + "description": "Interval in seconds of how often we should try to send our Neighbor Info to the mesh" + } + }, + "paxcounter": { + "title": "Paxcounter Settings", + "description": "Settings for the Paxcounter module", + "enabled": { + "label": "Module Enabled", + "description": "Enable Paxcounter" + }, + "paxcounterUpdateInterval": { + "label": "Update Interval (seconds)", + "description": "How long to wait between sending paxcounter packets" + }, + "wifiThreshold": { + "label": "WiFi RSSI Threshold", + "description": "At what WiFi RSSI level should the counter increase. Defaults to -80." + }, + "bleThreshold": { + "label": "BLE RSSI Threshold", + "description": "At what BLE RSSI level should the counter increase. Defaults to -80." + } + }, + "rangeTest": { + "title": "Range Test Settings", + "description": "Settings for the Range Test module", + "enabled": { + "label": "Module Enabled", + "description": "Enable Range Test" + }, + "sender": { + "label": "Message Interval", + "description": "How long to wait between sending test packets" + }, + "save": { + "label": "Save CSV to storage", + "description": "ESP32 Only" + } + }, + "serial": { + "title": "Serial Settings", + "description": "Settings for the Serial module", + "enabled": { + "label": "Module Enabled", + "description": "Enable Serial output" + }, + "echo": { + "label": "Echo", + "description": "Any packets you send will be echoed back to your device" + }, + "rxd": { + "label": "Receive Pin", + "description": "Set the GPIO pin to the RXD pin you have set up." + }, + "txd": { + "label": "Transmit Pin", + "description": "Set the GPIO pin to the TXD pin you have set up." + }, + "baud": { + "label": "Baud Rate", + "description": "The serial baud rate" + }, + "timeout": { + "label": "Timeout", + "description": "Seconds to wait before we consider your packet as 'done'" + }, + "mode": { + "label": "Mode", + "description": "Select Mode" + }, + "overrideConsoleSerialPort": { + "label": "Override Console Serial Port", + "description": "If you have a serial port connected to the console, this will override it." + } + }, + "storeForward": { + "title": "Store & Forward Settings", + "description": "Settings for the Store & Forward module", + "enabled": { + "label": "Module Enabled", + "description": "Enable Store & Forward" + }, + "heartbeat": { + "label": "Heartbeat Enabled", + "description": "Enable Store & Forward heartbeat" + }, + "records": { + "label": "Número de registos", + "description": "Number of records to store" + }, + "historyReturnMax": { + "label": "History return max", + "description": "Max number of records to return" + }, + "historyReturnWindow": { + "label": "History return window", + "description": "Return records from this time window (minutes)" + } + }, + "telemetry": { + "title": "Telemetry Settings", + "description": "Settings for the Telemetry module", + "deviceUpdateInterval": { + "label": "Device Metrics", + "description": "Intervalo de atualização de métricas do dispositivo (segundos)" + }, + "environmentUpdateInterval": { + "label": "Intervalo de atualização de métricas de ambiente (segundos)", + "description": "" + }, + "environmentMeasurementEnabled": { + "label": "Module Enabled", + "description": "Enable the Environment Telemetry" + }, + "environmentScreenEnabled": { + "label": "Displayed on Screen", + "description": "Show the Telemetry Module on the OLED" + }, + "environmentDisplayFahrenheit": { + "label": "Display Fahrenheit", + "description": "Display temp in Fahrenheit" + }, + "airQualityEnabled": { + "label": "Air Quality Enabled", + "description": "Enable the Air Quality Telemetry" + }, + "airQualityInterval": { + "label": "Air Quality Update Interval", + "description": "How often to send Air Quality data over the mesh" + }, + "powerMeasurementEnabled": { + "label": "Power Measurement Enabled", + "description": "Enable the Power Measurement Telemetry" + }, + "powerUpdateInterval": { + "label": "Power Update Interval", + "description": "How often to send Power data over the mesh" + }, + "powerScreenEnabled": { + "label": "Power Screen Enabled", + "description": "Enable the Power Telemetry Screen" + } + } } diff --git a/packages/web/public/i18n/locales/pt-PT/nodes.json b/packages/web/public/i18n/locales/pt-PT/nodes.json index 229aa0862..3a92cdd3e 100644 --- a/packages/web/public/i18n/locales/pt-PT/nodes.json +++ b/packages/web/public/i18n/locales/pt-PT/nodes.json @@ -1,63 +1,59 @@ { - "nodeDetail": { - "publicKeyEnabled": { - "label": "Public Key Enabled" - }, - "noPublicKey": { - "label": "No Public Key" - }, - "directMessage": { - "label": "Direct Message {{shortName}}" - }, - "favorite": { - "label": "Favoritos", - "tooltip": "Add or remove this node from your favorites" - }, - "notFavorite": { - "label": "Not a Favorite" - }, - "error": { - "label": "Erros", - "text": "An error occurred while fetching node details. Please try again later." - }, - "status": { - "heard": "Heard", - "mqtt": "MQTT" - }, - "elevation": { - "label": "Elevation" - }, - "channelUtil": { - "label": "Channel Util" - }, - "airtimeUtil": { - "label": "Airtime Util" - } - }, - "nodesTable": { - "headings": { - "longName": "Long Name", - "connection": "Connection", - "lastHeard": "Last Heard", - "encryption": "Encryption", - "model": "Model", - "macAddress": "MAC Address" - }, - "connectionStatus": { - "direct": "Direto", - "away": "away", - "unknown": "-", - "viaMqtt": ", via MQTT" - }, - "lastHeardStatus": { - "never": "Never" - } - }, - "actions": { - "added": "Added", - "removed": "Removed", - "ignoreNode": "Ignore Node", - "unignoreNode": "Unignore Node", - "requestPosition": "Request Position" - } + "nodeDetail": { + "publicKeyEnabled": { + "label": "Public Key Enabled" + }, + "noPublicKey": { + "label": "No Public Key" + }, + "directMessage": { + "label": "Direct Message {{shortName}}" + }, + "favorite": { + "label": "Favoritos", + "tooltip": "Add or remove this node from your favorites" + }, + "notFavorite": { + "label": "Not a Favorite" + }, + "error": { + "label": "Erros", + "text": "An error occurred while fetching node details. Please try again later." + }, + "status": { + "heard": "Heard", + "mqtt": "MQTT" + }, + "elevation": { + "label": "Elevation" + }, + "channelUtil": { + "label": "Channel Util" + }, + "airtimeUtil": { + "label": "Airtime Util" + } + }, + "nodesTable": { + "headings": { + "longName": "Long Name", + "connection": "Connection", + "lastHeard": "Last Heard", + "encryption": "Encryption", + "model": "Model", + "macAddress": "MAC Address" + }, + "connectionStatus": { + "direct": "Direto", + "away": "away", + "viaMqtt": ", via MQTT" + } + }, + "actions": { + "added": "Added", + "removed": "Removed", + "ignoreNode": "Ignore Node", + "unignoreNode": "Unignore Node", + "requestPosition": "Request Position" + } } diff --git a/packages/web/public/i18n/locales/pt-PT/ui.json b/packages/web/public/i18n/locales/pt-PT/ui.json index e6261a3fb..6763befed 100644 --- a/packages/web/public/i18n/locales/pt-PT/ui.json +++ b/packages/web/public/i18n/locales/pt-PT/ui.json @@ -1,228 +1,230 @@ { - "navigation": { - "title": "Navigation", - "messages": "Mensagens", - "map": "Mapa", - "config": "Config", - "radioConfig": "Radio Config", - "moduleConfig": "Module Config", - "channels": "Canal", - "nodes": "Nodes" - }, - "app": { - "title": "Meshtastic", - "logo": "Meshtastic Logo" - }, - "sidebar": { - "collapseToggle": { - "button": { - "open": "Open sidebar", - "close": "Close sidebar" - } - }, - "deviceInfo": { - "volts": "{{voltage}} volts", - "firmware": { - "title": "Firmware", - "version": "v{{version}}", - "buildDate": "Build date: {{date}}" - }, - "deviceName": { - "title": "Device Name", - "changeName": "Change Device Name", - "placeholder": "Enter device name" - }, - "editDeviceName": "Edit device name" - } - }, - "batteryStatus": { - "charging": "{{level}}% charging", - "pluggedIn": "Plugged in", - "title": "Bateria" - }, - "search": { - "nodes": "Search nodes...", - "channels": "Search channels...", - "commandPalette": "Search commands..." - }, - "toast": { - "positionRequestSent": { - "title": "Position request sent." - }, - "requestingPosition": { - "title": "Requesting position, please wait..." - }, - "sendingTraceroute": { - "title": "Sending Traceroute, please wait..." - }, - "tracerouteSent": { - "title": "Traceroute sent." - }, - "savedChannel": { - "title": "Saved Channel: {{channelName}}" - }, - "messages": { - "pkiEncryption": { - "title": "Chat is using PKI encryption." - }, - "pskEncryption": { - "title": "Chat is using PSK encryption." - } - }, - "configSaveError": { - "title": "Error Saving Config", - "description": "An error occurred while saving the configuration." - }, - "validationError": { - "title": "Config Errors Exist", - "description": "Please fix the configuration errors before saving." - }, - "saveSuccess": { - "title": "Saving Config", - "description": "The configuration change {{case}} has been saved." - }, - "favoriteNode": { - "title": "{{action}} {{nodeName}} {{direction}} favorites.", - "action": { - "added": "Added", - "removed": "Removed", - "to": "to", - "from": "from" - } - }, - "ignoreNode": { - "title": "{{action}} {{nodeName}} {{direction}} ignore list", - "action": { - "added": "Added", - "removed": "Removed", - "to": "to", - "from": "from" - } - } - }, - "notifications": { - "copied": { - "label": "Copied!" - }, - "copyToClipboard": { - "label": "Copy to clipboard" - }, - "hidePassword": { - "label": "Ocultar palavra-passe" - }, - "showPassword": { - "label": "Mostrar palavra-passe" - }, - "deliveryStatus": { - "delivered": "Delivered", - "failed": "Delivery Failed", - "waiting": "Waiting", - "unknown": "Unknown" - } - }, - "general": { - "label": "General" - }, - "hardware": { - "label": "Hardware" - }, - "metrics": { - "label": "Metrics" - }, - "role": { - "label": "Papel" - }, - "filter": { - "label": "Filtrar" - }, - "advanced": { - "label": "Advanced" - }, - "clearInput": { - "label": "Clear input" - }, - "resetFilters": { - "label": "Reset Filters" - }, - "nodeName": { - "label": "Node name/number", - "placeholder": "Meshtastic 1234" - }, - "airtimeUtilization": { - "label": "Airtime Utilization (%)" - }, - "batteryLevel": { - "label": "Battery level (%)", - "labelText": "Battery level (%): {{value}}" - }, - "batteryVoltage": { - "label": "Battery voltage (V)", - "title": "Voltagem" - }, - "channelUtilization": { - "label": "Channel Utilization (%)" - }, - "hops": { - "direct": "Direto", - "label": "Number of hops", - "text": "Number of hops: {{value}}" - }, - "lastHeard": { - "label": "Último recebido", - "labelText": "Last heard: {{value}}", - "nowLabel": "Now" - }, - "snr": { - "label": "SNR (db)" - }, - "favorites": { - "label": "Favorites" - }, - "hide": { - "label": "Hide" - }, - "showOnly": { - "label": "Show Only" - }, - "viaMqtt": { - "label": "Connected via MQTT" - }, - "hopsUnknown": { - "label": "Unknown number of hops" - }, - "showUnheard": { - "label": "Never heard" - }, - "language": { - "label": "Idioma", - "changeLanguage": "Change Language" - }, - "theme": { - "dark": "Escuro", - "light": "Claro", - "system": "Automatic", - "changeTheme": "Change Color Scheme" - }, - "errorPage": { - "title": "This is a little embarrassing...", - "description1": "We are really sorry but an error occurred in the web client that caused it to crash.
This is not supposed to happen, and we are working hard to fix it.", - "description2": "The best way to prevent this from happening again to you or anyone else is to report the issue to us.", - "reportInstructions": "Please include the following information in your report:", - "reportSteps": { - "step1": "What you were doing when the error occurred", - "step2": "What you expected to happen", - "step3": "What actually happened", - "step4": "Any other relevant information" - }, - "reportLink": "You can report the issue to our <0>GitHub", - "dashboardLink": "Return to the <0>dashboard", - "detailsSummary": "Error Details", - "errorMessageLabel": "Error message:", - "stackTraceLabel": "Stack trace:", - "fallbackError": "{{error}}" - }, - "footer": { - "text": "Powered by <0>▲ Vercel | Meshtastic® is a registered trademark of Meshtastic LLC. | <1>Legal Information", - "commitSha": "Commit SHA: {{sha}}" - } + "navigation": { + "title": "Navigation", + "messages": "Mensagens", + "map": "Mapa", + "settings": "Definições", + "channels": "Canal", + "radioConfig": "Radio Config", + "deviceConfig": "Configuração do Dispositivo", + "moduleConfig": "Module Config", + "manageConnections": "Manage Connections", + "nodes": "Nodes" + }, + "app": { + "title": "Meshtastic", + "logo": "Meshtastic Logo" + }, + "sidebar": { + "collapseToggle": { + "button": { + "open": "Open sidebar", + "close": "Close sidebar" + } + }, + "deviceInfo": { + "volts": "{{voltage}} volts", + "firmware": { + "title": "Firmware", + "version": "v{{version}}", + "buildDate": "Build date: {{date}}" + } + } + }, + "batteryStatus": { + "charging": "{{level}}% charging", + "pluggedIn": "Plugged in", + "title": "Bateria" + }, + "search": { + "nodes": "Search nodes...", + "channels": "Search channels...", + "commandPalette": "Search commands..." + }, + "toast": { + "positionRequestSent": { + "title": "Position request sent." + }, + "requestingPosition": { + "title": "Requesting position, please wait..." + }, + "sendingTraceroute": { + "title": "Sending Traceroute, please wait..." + }, + "tracerouteSent": { + "title": "Traceroute sent." + }, + "savedChannel": { + "title": "Saved Channel: {{channelName}}" + }, + "messages": { + "pkiEncryption": { + "title": "Chat is using PKI encryption." + }, + "pskEncryption": { + "title": "Chat is using PSK encryption." + } + }, + "configSaveError": { + "title": "Error Saving Config", + "description": "An error occurred while saving the configuration." + }, + "validationError": { + "title": "Config Errors Exist", + "description": "Please fix the configuration errors before saving." + }, + "saveSuccess": { + "title": "Saving Config", + "description": "The configuration change {{case}} has been saved." + }, + "saveAllSuccess": { + "title": "Saved", + "description": "All configuration changes have been saved." + }, + "favoriteNode": { + "title": "{{action}} {{nodeName}} {{direction}} favorites.", + "action": { + "added": "Added", + "removed": "Removed", + "to": "to", + "from": "from" + } + }, + "ignoreNode": { + "title": "{{action}} {{nodeName}} {{direction}} ignore list", + "action": { + "added": "Added", + "removed": "Removed", + "to": "to", + "from": "from" + } + } + }, + "notifications": { + "copied": { + "label": "Copied!" + }, + "copyToClipboard": { + "label": "Copy to clipboard" + }, + "hidePassword": { + "label": "Ocultar palavra-passe" + }, + "showPassword": { + "label": "Mostrar palavra-passe" + }, + "deliveryStatus": { + "delivered": "Delivered", + "failed": "Delivery Failed", + "waiting": "Waiting", + "unknown": "Unknown" + } + }, + "general": { + "label": "General" + }, + "hardware": { + "label": "Hardware" + }, + "metrics": { + "label": "Metrics" + }, + "role": { + "label": "Papel" + }, + "filter": { + "label": "Filtrar" + }, + "advanced": { + "label": "Advanced" + }, + "clearInput": { + "label": "Clear input" + }, + "resetFilters": { + "label": "Reset Filters" + }, + "nodeName": { + "label": "Node name/number", + "placeholder": "Meshtastic 1234" + }, + "airtimeUtilization": { + "label": "Airtime Utilization (%)", + "short": "Airtime Util. (%)" + }, + "batteryLevel": { + "label": "Battery level (%)", + "labelText": "Battery level (%): {{value}}" + }, + "batteryVoltage": { + "label": "Battery voltage (V)", + "title": "Voltagem" + }, + "channelUtilization": { + "label": "Channel Utilization (%)", + "short": "Channel Util. (%)" + }, + "hops": { + "direct": "Direto", + "label": "Number of hops", + "text": "Number of hops: {{value}}" + }, + "lastHeard": { + "label": "Último recebido", + "labelText": "Last heard: {{value}}", + "nowLabel": "Now" + }, + "snr": { + "label": "SNR (db)" + }, + "favorites": { + "label": "Favorites" + }, + "hide": { + "label": "Hide" + }, + "showOnly": { + "label": "Show Only" + }, + "viaMqtt": { + "label": "Connected via MQTT" + }, + "hopsUnknown": { + "label": "Unknown number of hops" + }, + "showUnheard": { + "label": "Never heard" + }, + "language": { + "label": "Idioma", + "changeLanguage": "Change Language" + }, + "theme": { + "dark": "Escuro", + "light": "Claro", + "system": "Automatic", + "changeTheme": "Change Color Scheme" + }, + "errorPage": { + "title": "This is a little embarrassing...", + "description1": "We are really sorry but an error occurred in the web client that caused it to crash.
This is not supposed to happen, and we are working hard to fix it.", + "description2": "The best way to prevent this from happening again to you or anyone else is to report the issue to us.", + "reportInstructions": "Please include the following information in your report:", + "reportSteps": { + "step1": "What you were doing when the error occurred", + "step2": "What you expected to happen", + "step3": "What actually happened", + "step4": "Any other relevant information" + }, + "reportLink": "You can report the issue to our <0>GitHub", + "connectionsLink": "Return to the <0>connections", + "detailsSummary": "Error Details", + "errorMessageLabel": "Error message:", + "stackTraceLabel": "Stack trace:", + "fallbackError": "{{error}}" + }, + "footer": { + "text": "Powered by <0>▲ Vercel | Meshtastic® is a registered trademark of Meshtastic LLC. | <1>Legal Information", + "commitSha": "Commit SHA: {{sha}}" + } } diff --git a/packages/web/public/i18n/locales/ru-RU/channels.json b/packages/web/public/i18n/locales/ru-RU/channels.json new file mode 100644 index 000000000..73c8baac3 --- /dev/null +++ b/packages/web/public/i18n/locales/ru-RU/channels.json @@ -0,0 +1,71 @@ +{ + "page": { + "sectionLabel": "Каналы", + "channelName": "Канал: {{channelName}}", + "broadcastLabel": "Первичный", + "channelIndex": "Кн {{index}}", + "import": "Импортировать", + "export": "Экспорт" + }, + "validation": { + "pskInvalid": "Введите правильный {{bits}} бит PSK." + }, + "settings": { + "label": "Настройки канала", + "description": "Настройка шифрования, MQTT и пр" + }, + "role": { + "label": "Роль", + "description": "Телеметрия устройства отправляется через ГЛАВНЫЙ. Только один ГЛАВНЫЙ разрешен", + "options": { + "primary": "ГЛАВНЫЙ", + "disabled": "ЗАПРЕЩЕННЫЙ", + "secondary": "ВТОРИЧНЫЙ" + } + }, + "psk": { + "label": "Pre-Shared Ключ", + "description": "Поддерживаемая длина PSK: 256-бит, 128-бит, 8-бит, Пустое (0-бит)", + "generate": "Сгенерировать" + }, + "name": { + "label": "Имя", + "description": "ЗАПРЕЩЕННЫЙ" + }, + "uplinkEnabled": { + "label": "Выгрузка Разрешена", + "description": "Отправлять сообщения из местного mesh в MQTT" + }, + "downlinkEnabled": { + "label": "Загрузка Разрешена", + "description": "Отправлять сообщения из MQTT в местный mesh" + }, + "positionPrecision": { + "label": "Позиция", + "description": "Точность позиции для отправки в канал. Можно запретить.", + "options": { + "none": "Не делиться позицией", + "precise": "Точная позиция", + "metric_km23": "Около 23 километров", + "metric_km12": "Около 12 километров", + "metric_km5_8": "Within 5.8 kilometers", + "metric_km2_9": "Within 2.9 kilometers", + "metric_km1_5": "Около 1,5 километров", + "metric_m700": "Около 700 метров", + "metric_m350": "Около 350 метров", + "metric_m200": "Около 200 метров", + "metric_m90": "Около 90 метров", + "metric_m50": "Около 50 метров", + "imperial_mi15": "Около 15 миль", + "imperial_mi7_3": "Within 7.3 miles", + "imperial_mi3_6": "Within 3.6 miles", + "imperial_mi1_8": "Within 1.8 miles", + "imperial_mi0_9": "Within 0.9 miles", + "imperial_mi0_5": "Within 0.5 miles", + "imperial_mi0_2": "Около 0,2 миль", + "imperial_ft600": "Около 600 футов", + "imperial_ft300": "Около 300 футов", + "imperial_ft150": "Около 150 футов" + } + } +} diff --git a/packages/web/public/i18n/locales/ru-RU/commandPalette.json b/packages/web/public/i18n/locales/ru-RU/commandPalette.json new file mode 100644 index 000000000..2f6f27be2 --- /dev/null +++ b/packages/web/public/i18n/locales/ru-RU/commandPalette.json @@ -0,0 +1,51 @@ +{ + "emptyState": "Результаты не найдены..", + "page": { + "title": "Меню" + }, + "pinGroup": { + "label": "Закрепить меню" + }, + "unpinGroup": { + "label": "Открепить меню" + }, + "goto": { + "label": "Перейти", + "command": { + "messages": "Сообщения", + "map": "Карта", + "config": "Настройка", + "nodes": "Узлы" + } + }, + "manage": { + "label": "Управление", + "command": { + "switchNode": "Выбрать узел", + "connectNewNode": "Подключить новый узел" + } + }, + "contextual": { + "label": "Контекст", + "command": { + "qrCode": "QR Код", + "qrGenerator": "Генератор", + "qrImport": "Импортировать", + "scheduleShutdown": "Расписание выключения", + "scheduleReboot": "Перезагрузить устройство", + "resetNodeDb": "Стереть базу данных узлов", + "dfuMode": "Войти в режим DFU", + "factoryResetDevice": "Сброс устройства к заводским установкам", + "factoryResetConfig": "Factory Reset Config", + "disconnect": "Отключиться" + } + }, + "debug": { + "label": "Debug", + "command": { + "reconfigure": "Перенастроить", + "clearAllStoredMessages": "Удалить все сохранённые сообщения", + "clearAllStores": "Очистить всё локальное хранилище" + } + } +} diff --git a/packages/web/public/i18n/locales/ru-RU/common.json b/packages/web/public/i18n/locales/ru-RU/common.json new file mode 100644 index 000000000..6c8a25659 --- /dev/null +++ b/packages/web/public/i18n/locales/ru-RU/common.json @@ -0,0 +1,165 @@ +{ + "button": { + "apply": "Применить", + "addConnection": "Добавить подключение", + "saveConnection": "Сохранить подключение", + "backupKey": "Бэкап ключа", + "cancel": "Отмена", + "connect": "Подключиться", + "clearMessages": "Очистить сообщения", + "close": "Закрыть", + "confirm": "Подтвердить", + "delete": "Удалить", + "dismiss": "Отменить", + "download": "Скачать", + "disconnect": "Отключиться", + "export": "Экспорт", + "generate": "Создать", + "regenerate": "Создать снова", + "import": "Импортировать", + "message": "Сообщение", + "now": "Сейчас", + "ok": "Лады", + "print": "Печать", + "remove": "Удалить", + "requestNewKeys": "Запрос нового ключа", + "requestPosition": "Запрос позиции", + "reset": "Сброс", + "retry": "Повторить", + "save": "Сохранить", + "setDefault": "Установить по умолчанию", + "unsetDefault": "Убрать умолчание", + "scanQr": "Сканировать QR код", + "traceRoute": "Отследить маршрут", + "submit": "Отправить" + }, + "app": { + "title": "Meshtastic", + "fullTitle": "Веб клиент Meshtastic" + }, + "loading": "Загрузка...", + "unit": { + "cps": "CPS", + "dbm": "dBm", + "hertz": "Гц", + "hop": { + "one": "Прыжок", + "plural": "Прыжков" + }, + "hopsAway": { + "one": "{{count}} прыжок до", + "plural": "{{count}} прыжков", + "unknown": "? прыжков" + }, + "megahertz": "МГц", + "kilohertz": "кГц", + "raw": "raw", + "meter": { + "one": "Метр", + "plural": "Метров", + "suffix": "м" + }, + "kilometer": { + "one": "Километр", + "plural": "Километров", + "suffix": "км" + }, + "minute": { + "one": "Минута", + "plural": "Минут" + }, + "hour": { + "one": "Час", + "plural": "Часов" + }, + "millisecond": { + "one": "Миллисекунда", + "plural": "Миллисекунд", + "suffix": "мс" + }, + "second": { + "one": "Секунда", + "plural": "Секунд" + }, + "day": { + "one": "День", + "plural": "Дней", + "today": "Сегодня", + "yesterday": "Вчера" + }, + "month": { + "one": "Месяц", + "plural": "Месяцев" + }, + "year": { + "one": "Year", + "plural": "Years" + }, + "snr": "Сигнал/шум", + "volt": { + "one": "Volt", + "plural": "Volts", + "suffix": "V" + }, + "record": { + "one": "Records", + "plural": "Records" + }, + "degree": { + "one": "Degree", + "plural": "Degrees", + "suffix": "°" + } + }, + "security": { + "0bit": "Empty", + "8bit": "8 bit", + "128bit": "128 bit", + "256bit": "256 bit" + }, + "unknown": { + "longName": "Неизвестно", + "shortName": "UNK", + "notAvailable": "N/A", + "num": "??" + }, + "nodeUnknownPrefix": "!", + "unset": "UNSET", + "fallbackName": "Meshtastic {{last4}}", + "node": "Node", + "formValidation": { + "unsavedChanges": "Unsaved changes", + "tooBig": { + "string": "Too long, expected less than or equal to {{maximum}} characters.", + "number": "Too big, expected a number smaller than or equal to {{maximum}}.", + "bytes": "Too big, expected less than or equal to {{params.maximum}} bytes." + }, + "tooSmall": { + "string": "Too short, expected more than or equal to {{minimum}} characters.", + "number": "Too small, expected a number larger than or equal to {{minimum}}." + }, + "invalidFormat": { + "ipv4": "Invalid format, expected an IPv4 address.", + "key": "Invalid format, expected a Base64 encoded pre-shared key (PSK)." + }, + "invalidType": { + "number": "Invalid type, expected a number." + }, + "pskLength": { + "0bit": "Key is required to be empty.", + "8bit": "Key is required to be an 8 bit pre-shared key (PSK).", + "128bit": "Key is required to be a 128 bit pre-shared key (PSK).", + "256bit": "Key is required to be a 256 bit pre-shared key (PSK)." + }, + "required": { + "generic": "This field is required.", + "managed": "At least one admin key is requred if the node is managed.", + "key": "Key is required." + }, + "invalidOverrideFreq": { + "number": "Invalid format, expected a value in the range 410-930 MHz or 0 (use default)." + } + }, + "yes": "Yes", + "no": "No" +} diff --git a/packages/web/public/i18n/locales/ru-RU/config.json b/packages/web/public/i18n/locales/ru-RU/config.json new file mode 100644 index 000000000..5db23172e --- /dev/null +++ b/packages/web/public/i18n/locales/ru-RU/config.json @@ -0,0 +1,458 @@ +{ + "page": { + "title": "Настройки", + "tabUser": "Пользователь", + "tabChannels": "Каналы", + "tabBluetooth": "Bluetooth", + "tabDevice": "Устройство", + "tabDisplay": "Дисплей", + "tabLora": "LoRa", + "tabNetwork": "Сеть", + "tabPosition": "Местоположение", + "tabPower": "Питание", + "tabSecurity": "Безопасность" + }, + "sidebar": { + "label": "Configuration" + }, + "device": { + "title": "Device Settings", + "description": "Settings for the device", + "buttonPin": { + "description": "Button pin override", + "label": "Button Pin" + }, + "buzzerPin": { + "description": "Buzzer pin override", + "label": "Buzzer Pin" + }, + "disableTripleClick": { + "description": "Disable triple click", + "label": "Disable Triple Click" + }, + "doubleTapAsButtonPress": { + "description": "Treat double tap as button press", + "label": "Double Tap as Button Press" + }, + "ledHeartbeatDisabled": { + "description": "Disable default blinking LED", + "label": "LED Heartbeat Disabled" + }, + "nodeInfoBroadcastInterval": { + "description": "How often to broadcast node info", + "label": "Интервал вещания передачи информации об узле" + }, + "posixTimezone": { + "description": "The POSIX timezone string for the device", + "label": "Часовой пояс POSIX" + }, + "rebroadcastMode": { + "description": "How to handle rebroadcasting", + "label": "Режим ретрансляции" + }, + "role": { + "description": "What role the device performs on the mesh", + "label": "Роль" + } + }, + "bluetooth": { + "title": "Bluetooth Settings", + "description": "Settings for the Bluetooth module", + "note": "Note: Some devices (ESP32) cannot use both Bluetooth and WiFi at the same time.", + "enabled": { + "description": "Enable or disable Bluetooth", + "label": "Включено" + }, + "pairingMode": { + "description": "Pin selection behaviour.", + "label": "Режим сопряжения" + }, + "pin": { + "description": "Pin to use when pairing", + "label": "Pin" + } + }, + "display": { + "description": "Settings for the device display", + "title": "Display Settings", + "headingBold": { + "description": "Bolden the heading text", + "label": "Выделять жирным заголовок" + }, + "carouselDelay": { + "description": "How fast to cycle through windows", + "label": "Carousel Delay" + }, + "compassNorthTop": { + "description": "Fix north to the top of compass", + "label": "Compass North Top" + }, + "displayMode": { + "description": "Screen layout variant", + "label": "Display Mode" + }, + "displayUnits": { + "description": "Display metric or imperial units", + "label": "Display Units" + }, + "flipScreen": { + "description": "Flip display 180 degrees", + "label": "Flip Screen" + }, + "gpsDisplayUnits": { + "description": "Coordinate display format", + "label": "GPS Display Units" + }, + "oledType": { + "description": "Type of OLED screen attached to the device", + "label": "OLED Type" + }, + "screenTimeout": { + "description": "Turn off the display after this long", + "label": "Screen Timeout" + }, + "twelveHourClock": { + "description": "Use 12-hour clock format", + "label": "12-Hour Clock" + }, + "wakeOnTapOrMotion": { + "description": "Wake the device on tap or motion", + "label": "Wake on Tap or Motion" + } + }, + "lora": { + "title": "Mesh Settings", + "description": "Settings for the LoRa mesh", + "bandwidth": { + "description": "Channel bandwidth in kHz", + "label": "Ширина канала" + }, + "boostedRxGain": { + "description": "Boosted RX gain", + "label": "Boosted RX Gain" + }, + "codingRate": { + "description": "The denominator of the coding rate", + "label": "Частота кодирования" + }, + "frequencyOffset": { + "description": "Frequency offset to correct for crystal calibration errors", + "label": "Frequency Offset" + }, + "frequencySlot": { + "description": "LoRa frequency channel number", + "label": "Частота слота" + }, + "hopLimit": { + "description": "Maximum number of hops", + "label": "Hop Limit" + }, + "ignoreMqtt": { + "description": "Don't forward MQTT messages over the mesh", + "label": "Игнорировать MQTT" + }, + "modemPreset": { + "description": "Modem preset to use", + "label": "Режим работы модема" + }, + "okToMqtt": { + "description": "When set to true, this configuration indicates that the user approves the packet to be uploaded to MQTT. If set to false, remote nodes are requested not to forward packets to MQTT", + "label": "ОК в MQTT" + }, + "overrideDutyCycle": { + "description": "Переопределить рабочий цикл", + "label": "Переопределить рабочий цикл" + }, + "overrideFrequency": { + "description": "Override frequency", + "label": "Override Frequency" + }, + "region": { + "description": "Sets the region for your node", + "label": "Регион / Страна" + }, + "spreadingFactor": { + "description": "Indicates the number of chirps per symbol", + "label": "Spreading Factor" + }, + "transmitEnabled": { + "description": "Enable/Disable transmit (TX) from the LoRa radio", + "label": "Передача включена" + }, + "transmitPower": { + "description": "Max transmit power", + "label": "Мощность передатчика" + }, + "usePreset": { + "description": "Use one of the predefined modem presets", + "label": "Использовать шаблон" + }, + "meshSettings": { + "description": "Settings for the LoRa mesh", + "label": "Mesh Settings" + }, + "waveformSettings": { + "description": "Settings for the LoRa waveform", + "label": "Waveform Settings" + }, + "radioSettings": { + "label": "Radio Settings", + "description": "Settings for the LoRa radio" + } + }, + "network": { + "title": "WiFi Config", + "description": "WiFi radio configuration", + "note": "Note: Some devices (ESP32) cannot use both Bluetooth and WiFi at the same time.", + "addressMode": { + "description": "Address assignment selection", + "label": "Address Mode" + }, + "dns": { + "description": "DNS Server", + "label": "DNS" + }, + "ethernetEnabled": { + "description": "Enable or disable the Ethernet port", + "label": "Включено" + }, + "gateway": { + "description": "Default Gateway", + "label": "Шлюз" + }, + "ip": { + "description": "IP Address", + "label": "IP-адрес" + }, + "psk": { + "description": "Network password", + "label": "Пароль" + }, + "ssid": { + "description": "Network name", + "label": "Название сети" + }, + "subnet": { + "description": "Subnet Mask", + "label": "Подсеть" + }, + "wifiEnabled": { + "description": "Enable or disable the WiFi radio", + "label": "Включено" + }, + "meshViaUdp": { + "label": "Mesh via UDP" + }, + "ntpServer": { + "label": "NTP Server" + }, + "rsyslogServer": { + "label": "Rsyslog Server" + }, + "ethernetConfigSettings": { + "description": "Ethernet port configuration", + "label": "Ethernet Config" + }, + "ipConfigSettings": { + "description": "IP configuration", + "label": "IP Config" + }, + "ntpConfigSettings": { + "description": "NTP configuration", + "label": "NTP Config" + }, + "rsyslogConfigSettings": { + "description": "Rsyslog configuration", + "label": "Rsyslog Config" + }, + "udpConfigSettings": { + "description": "UDP over Mesh configuration", + "label": "UDP Config" + } + }, + "position": { + "title": "Position Settings", + "description": "Settings for the position module", + "broadcastInterval": { + "description": "How often your position is sent out over the mesh", + "label": "Период трансляции" + }, + "enablePin": { + "description": "GPS module enable pin override", + "label": "Enable Pin" + }, + "fixedPosition": { + "description": "Don't report GPS position, but a manually-specified one", + "label": "Фиксированное положение" + }, + "gpsMode": { + "description": "Configure whether device GPS is Enabled, Disabled, or Not Present", + "label": "GPS Mode" + }, + "gpsUpdateInterval": { + "description": "How often a GPS fix should be acquired", + "label": "GPS Update Interval" + }, + "positionFlags": { + "description": "Optional fields to include when assembling position messages. The more fields are selected, the larger the message will be leading to longer airtime usage and a higher risk of packet loss.", + "label": "Флаги позиции" + }, + "receivePin": { + "description": "GPS module RX pin override", + "label": "Receive Pin" + }, + "smartPositionEnabled": { + "description": "Only send position when there has been a meaningful change in location", + "label": "Enable Smart Position" + }, + "smartPositionMinDistance": { + "description": "Minimum distance (in meters) that must be traveled before a position update is sent", + "label": "Smart Position Minimum Distance" + }, + "smartPositionMinInterval": { + "description": "Minimum interval (in seconds) that must pass before a position update is sent", + "label": "Smart Position Minimum Interval" + }, + "transmitPin": { + "description": "GPS module TX pin override", + "label": "Transmit Pin" + }, + "intervalsSettings": { + "description": "How often to send position updates", + "label": "Intervals" + }, + "flags": { + "placeholder": "Select position flags...", + "altitude": "Высота", + "altitudeGeoidalSeparation": "Altitude Geoidal Separation", + "altitudeMsl": "Altitude is Mean Sea Level", + "dop": "Dilution of precision (DOP) PDOP used by default", + "hdopVdop": "If DOP is set, use HDOP / VDOP values instead of PDOP", + "numSatellites": "Number of satellites", + "sequenceNumber": "Sequence number", + "timestamp": "Отметка времени", + "unset": "Не установлена", + "vehicleHeading": "Vehicle heading", + "vehicleSpeed": "Vehicle speed" + } + }, + "power": { + "adcMultiplierOverride": { + "description": "Used for tweaking battery voltage reading", + "label": "ADC Multiplier Override ratio" + }, + "ina219Address": { + "description": "Address of the INA219 battery monitor", + "label": "INA219 Address" + }, + "lightSleepDuration": { + "description": "How long the device will be in light sleep for", + "label": "Light Sleep Duration" + }, + "minimumWakeTime": { + "description": "Minimum amount of time the device will stay awake for after receiving a packet", + "label": "Minimum Wake Time" + }, + "noConnectionBluetoothDisabled": { + "description": "If the device does not receive a Bluetooth connection, the BLE radio will be disabled after this long", + "label": "No Connection Bluetooth Disabled" + }, + "powerSavingEnabled": { + "description": "Select if powered from a low-current source (i.e. solar), to minimize power consumption as much as possible.", + "label": "Включить режим энергосбережения" + }, + "shutdownOnBatteryDelay": { + "description": "Automatically shutdown node after this long when on battery, 0 for indefinite", + "label": "Shutdown on battery delay" + }, + "superDeepSleepDuration": { + "description": "How long the device will be in super deep sleep for", + "label": "Super Deep Sleep Duration" + }, + "powerConfigSettings": { + "description": "Settings for the power module", + "label": "Настройка питания" + }, + "sleepSettings": { + "description": "Sleep settings for the power module", + "label": "Sleep Settings" + } + }, + "security": { + "description": "Settings for the Security configuration", + "title": "Security Settings", + "button_backupKey": "Backup Key", + "adminChannelEnabled": { + "description": "Allow incoming device control over the insecure legacy admin channel", + "label": "Allow Legacy Admin" + }, + "enableDebugLogApi": { + "description": "Output live debug logging over serial, view and export position-redacted device logs over Bluetooth", + "label": "Enable Debug Log API" + }, + "managed": { + "description": "If enabled, device configuration options are only able to be changed remotely by a Remote Admin node via admin messages. Do not enable this option unless at least one suitable Remote Admin node has been setup, and the public key is stored in one of the fields above.", + "label": "Managed" + }, + "privateKey": { + "description": "Used to create a shared key with a remote device", + "label": "Приватный ключ" + }, + "publicKey": { + "description": "Sent out to other nodes on the mesh to allow them to compute a shared secret key", + "label": "Публичный ключ" + }, + "primaryAdminKey": { + "description": "The primary public key authorized to send admin messages to this node", + "label": "Primary Admin Key" + }, + "secondaryAdminKey": { + "description": "The secondary public key authorized to send admin messages to this node", + "label": "Secondary Admin Key" + }, + "serialOutputEnabled": { + "description": "Serial Console over the Stream API", + "label": "Serial Output Enabled" + }, + "tertiaryAdminKey": { + "description": "The tertiary public key authorized to send admin messages to this node", + "label": "Tertiary Admin Key" + }, + "adminSettings": { + "description": "Settings for Admin", + "label": "Admin Settings" + }, + "loggingSettings": { + "description": "Settings for Logging", + "label": "Logging Settings" + } + }, + "user": { + "title": "User Settings", + "description": "Configure your device name and identity settings", + "longName": { + "label": "Полное имя", + "description": "Your full display name (1-40 characters)", + "validation": { + "min": "Long name must be at least 1 character", + "max": "Long name must be at most 40 characters" + } + }, + "shortName": { + "label": "Короткое имя", + "description": "Your abbreviated name (2-4 characters)", + "validation": { + "min": "Short name must be at least 2 characters", + "max": "Short name must be at most 4 characters" + } + }, + "isUnmessageable": { + "label": "Не отправляемо", + "description": "Used to identify unmonitored or infrastructure nodes so that messaging is not available to nodes that will never respond." + }, + "isLicensed": { + "label": "Лицензированный радиолюбитель (HAM)", + "description": "Enable if you are a licensed amateur radio operator, enabling this option disables encryption and is not compatible with the default Meshtastic network." + } + } +} diff --git a/packages/web/public/i18n/locales/ru-RU/connections.json b/packages/web/public/i18n/locales/ru-RU/connections.json new file mode 100644 index 000000000..ed391076f --- /dev/null +++ b/packages/web/public/i18n/locales/ru-RU/connections.json @@ -0,0 +1,34 @@ +{ + "page": { + "title": "Connect to a Meshtastic device", + "description": "Add a device connection via HTTP, Bluetooth, or Serial. Your saved connections will be saved in your browser." + }, + "connectionType_ble": "BLE", + "connectionType_serial": "COM-порт", + "connectionType_network": "Сеть", + "deleteConnection": "Delete connection", + "areYouSure": "This will remove {{name}}. You canot undo this action.", + "moreActions": "More actions", + "noConnections": { + "title": "No connections yet.", + "description": "Create your first connection. It will connect immediately and be saved for later." + }, + "lastConnectedAt": "Last connected: {{date}}", + "neverConnected": "Never connected", + "toasts": { + "connected": "Подключено", + "nowConnected": "{{name}} is now connected", + "nowDisconnected": "{{name}} are now disconnecte", + "disconnected": "Отключено", + "failed": "Failed to connect", + "checkConnetion": "Check your device or settings and try again", + "defaultSet": "Default set", + "defaultConnection": "Default connection is now {{nameisconnected}}", + "deleted": "Deleted", + "deletedByName": "{{name}} was removed", + "pickConnectionAgain": "Could not connect. You may need to reselect the device/port.", + "added": "Connection added", + "savedByName": "{{name}} saved.", + "savedCantConnect": "The connection was saved but could not connect." + } +} diff --git a/packages/web/public/i18n/locales/ru-RU/dialog.json b/packages/web/public/i18n/locales/ru-RU/dialog.json new file mode 100644 index 000000000..4ee529972 --- /dev/null +++ b/packages/web/public/i18n/locales/ru-RU/dialog.json @@ -0,0 +1,238 @@ +{ + "deleteMessages": { + "description": "This action will clear all message history. This cannot be undone. Are you sure you want to continue?", + "title": "Clear All Messages" + }, + "import": { + "description": "Import a Channel Set from a Meshtastic URL.
Valid Meshtasic URLs start with \"https://meshtastic.org/e/...\"", + "error": { + "invalidUrl": "Invalid Meshtastic URL" + }, + "channelPrefix": "Channel ", + "primary": "Primary ", + "doNotImport": "No not import", + "channelName": "Имя", + "channelSlot": "Слот", + "channelSetUrl": "Channel Set/QR Code URL", + "useLoraConfig": "Import LoRa Config", + "presetDescription": "The current LoRa Config will be replaced.", + "title": "Import Channels" + }, + "locationResponse": { + "title": "Location: {{identifier}}", + "altitude": "Altitude: ", + "coordinates": "Coordinates: ", + "noCoordinates": "No Coordinates" + }, + "pkiRegenerateDialog": { + "title": "Regenerate Pre-Shared Key?", + "description": "Are you sure you want to regenerate the pre-shared key?", + "regenerate": "Regenerate" + }, + "addConnection": { + "title": "Add connection", + "description": "Choose a connection type and fill in the details", + "validation": { + "requiresWebBluetooth": "This connection type requires <0>Web Bluetooth. Please use a supported browser, like Chrome or Edge.", + "requiresWebSerial": "This connection type requires <0>Web Serial. Please use a supported browser, like Chrome or Edge.", + "requiresSecureContext": "This application requires a <0>secure context. Please connect using HTTPS or localhost.", + "additionallyRequiresSecureContext": "Additionally, it requires a <0>secure context. Please connect using HTTPS or localhost." + }, + "bluetoothConnection": { + "namePlaceholder": "My Bluetooth Node", + "supported": { + "title": "Web Bluetooth supported" + }, + "notSupported": { + "title": "Web Bluetooth not supported", + "description": "Your browser or device does not support Web Bluetooth" + }, + "short": "BT: {{deviceName}}", + "long": "Bluetooth Device", + "device": "Устройство", + "selectDevice": "Select device", + "selected": "Bluetooth device selected", + "notSelected": "No device selected", + "helperText": "Uses the Meshtastic Bluetooth service for discovery." + }, + "serialConnection": { + "namePlaceholder": "My Serial Node", + "helperText": "Selecting a port grants permission so the app can open it to connect.", + "supported": { + "title": "Web Serial supported" + }, + "notSupported": { + "title": "Web Serial not supported", + "description": "Your browser or device does not support Web Serial" + }, + "portSelected": { + "title": "Serial port selected", + "description": "Port permissions granted." + }, + "port": "Port", + "selectPort": "Select port", + "deviceName": "USB {{vendorId}}:{{productId}}", + "notSelected": "No port selected" + }, + "httpConnection": { + "namePlaceholder": "My HTTP Node", + "inputPlaceholder": "192.168.1.10 or meshtastic.local", + "heading": "URL or IP", + "useHttps": "Use HTTTPS", + "invalidUrl": { + "title": "Invalid URL", + "description": "Please enter a valid HTTP or HTTPS URL." + }, + "connectionTest": { + "description": "Test the connetion before saving to verify the device is reachable.", + "button": { + "loading": "Testing...", + "label": "Test connection" + }, + "reachable": "Reachable", + "notReachable": "Not reachable", + "success": { + "title": "Connection test successful", + "description": "The device appears to be reachable." + }, + "failure": { + "title": "Connection test failed", + "description": "Could not reach the device. Check the URL and try again." + } + } + } + }, + "nodeDetails": { + "message": "Сообщение", + "requestPosition": "Request Position", + "traceRoute": "Trace Route", + "airTxUtilization": "Air TX utilization", + "allRawMetrics": "All Raw Metrics:", + "batteryLevel": "Battery level", + "channelUtilization": "Channel utilization", + "details": "Details:", + "deviceMetrics": "Device Metrics:", + "hardware": "Hardware: ", + "lastHeard": "Last Heard: ", + "nodeHexPrefix": "Node Hex: ", + "nodeNumber": "Node Number: ", + "position": "Position:", + "role": "Role: ", + "uptime": "Uptime: ", + "voltage": "Напряжение", + "title": "Node Details for {{identifier}}", + "ignoreNode": "Ignore node", + "removeNode": "Remove node", + "unignoreNode": "Unignore node", + "security": "Security:", + "publicKey": "Public Key: ", + "messageable": "Messageable: ", + "KeyManuallyVerifiedTrue": "Public Key has been manually verified", + "KeyManuallyVerifiedFalse": "Public Key is not manually verified" + }, + "pkiBackup": { + "loseKeysWarning": "If you lose your keys, you will need to reset your device.", + "secureBackup": "Its important to backup your public and private keys and store your backup securely!", + "footer": "=== END OF KEYS ===", + "header": "=== MESHTASTIC KEYS FOR {{longName}} ({{shortName}}) ===", + "privateKey": "Private Key:", + "publicKey": "Public Key:", + "fileName": "meshtastic_keys_{{longName}}_{{shortName}}.txt", + "title": "Backup Keys" + }, + "pkiBackupReminder": { + "description": "We recommend backing up your key data regularly. Would you like to back up now?", + "title": "Backup Reminder", + "remindLaterPrefix": "Remind me in", + "remindNever": "Never remind me", + "backupNow": "Back up now" + }, + "pkiRegenerate": { + "description": "Are you sure you want to regenerate key pair?", + "title": "Regenerate Key Pair" + }, + "qr": { + "addChannels": "Add Channels", + "replaceChannels": "Replace Channels", + "description": "The current LoRa configuration will also be shared.", + "sharableUrl": "Sharable URL", + "title": "Generate QR Code" + }, + "reboot": { + "title": "Reboot device", + "description": "Reboot now or schedule a reboot of the connected node. Optionally, you can choose to reboot into OTA (Over-the-Air) mode.", + "ota": "Reboot into OTA mode", + "enterDelay": "Enter delay", + "scheduled": "Reboot has been scheduled", + "schedule": "Schedule reboot", + "now": "Reboot now", + "cancel": "Cancel scheduled reboot" + }, + "refreshKeys": { + "description": { + "acceptNewKeys": "This will remove the node from device and request new keys.", + "keyMismatchReasonSuffix": ". This is due to the remote node's current public key does not match the previously stored key for this node.", + "unableToSendDmPrefix": "Your node is unable to send a direct message to node: " + }, + "acceptNewKeys": "Accept New Keys", + "title": "Keys Mismatch - {{identifier}}" + }, + "removeNode": { + "description": "Are you sure you want to remove this Node?", + "title": "Remove Node?" + }, + "shutdown": { + "title": "Schedule Shutdown", + "description": "Turn off the connected node after x minutes." + }, + "traceRoute": { + "routeToDestination": "Route to destination:", + "routeBack": "Route back:" + }, + "tracerouteResponse": { + "title": "Traceroute: {{identifier}}" + }, + "unsafeRoles": { + "confirmUnderstanding": "Yes, I know what I'm doing", + "conjunction": " and the blog post about ", + "postamble": " and understand the implications of changing the role.", + "preamble": "I have read the ", + "choosingRightDeviceRole": "Choosing The Right Device Role", + "deviceRoleDocumentation": "Device Role Documentation", + "title": "Вы уверены?" + }, + "managedMode": { + "confirmUnderstanding": "Yes, I know what I'm doing", + "title": "Вы уверены?", + "description": "Enabling Managed Mode blocks client applications (including the web client) from writing configurations to a radio. Once enabled, radio configurations can only be changed through Remote Admin messages. This setting is not required for remote node administration." + }, + "clientNotification": { + "title": "Уведомления клиента", + "TraceRoute can only be sent once every 30 seconds": "TraceRoute can only be sent once every 30 seconds", + "Compromised keys were detected and regenerated.": "Compromised keys were detected and regenerated." + }, + "resetNodeDb": { + "title": "Reset Node Database", + "description": "This will clear all nodes from the connected device's node database and clear all message history in the client. This cannot be undone. Are you sure you want to continue?", + "confirm": "Reset Node Database", + "failedTitle": "There was an error resetting the Node DB. Please try again." + }, + "clearAllStores": { + "title": "Clear All Local Storage", + "description": "This will clear all locally stored data, including message history and node databases for all previously connected devices. This will require you to reconnect to your node once complete and cannot be undone. Are you sure you want to continue?", + "confirm": "Clear all local storage", + "failedTitle": "There was an error clearing local storage. Please try again." + }, + "factoryResetDevice": { + "title": "Factory Reset Device", + "description": "This will factory reset the connected device, erasing all configurations and data on the device as well as all nodes and messages saved in the client. This cannot be undone. Are you sure you want to continue?", + "confirm": "Factory Reset Device", + "failedTitle": "There was an error performing the factory reset. Please try again." + }, + "factoryResetConfig": { + "title": "Factory Reset Config", + "description": "This will factory reset the configuration on the connected device, erasing all configurations on the device. This cannot be undone. Are you sure you want to continue?", + "confirm": "Factory Reset Config", + "failedTitle": "There was an error performing the factory reset. Please try again." + } +} diff --git a/packages/web/public/i18n/locales/ru-RU/map.json b/packages/web/public/i18n/locales/ru-RU/map.json new file mode 100644 index 000000000..fbd1597aa --- /dev/null +++ b/packages/web/public/i18n/locales/ru-RU/map.json @@ -0,0 +1,38 @@ +{ + "maplibre": { + "GeolocateControl.FindMyLocation": "Find my location", + "NavigationControl.ZoomIn": "Zoom in", + "NavigationControl.ZoomOut": "Zoom out", + "CooperativeGesturesHandler.WindowsHelpText": "Use Ctrl + scroll to zoom the map", + "CooperativeGesturesHandler.MacHelpText": "Use ⌘ + scroll to zoom the map", + "CooperativeGesturesHandler.MobileHelpText": "Use two fingers to move the map" + }, + "layerTool": { + "nodeMarkers": "Show nodes", + "directNeighbors": "Show direct connections", + "remoteNeighbors": "Show remote connections", + "positionPrecision": "Show position precision", + "traceroutes": "Show traceroutes", + "waypoints": "Show waypoints" + }, + "mapMenu": { + "locateAria": "Locate my node", + "layersAria": "Change map style" + }, + "waypointDetail": { + "edit": "Редактировать", + "description": "Description:", + "createdBy": "Edited by:", + "createdDate": "Created:", + "updated": "Updated:", + "expires": "Expires:", + "distance": "Distance:", + "bearing": "Absolute bearing:", + "lockedTo": "Locked by:", + "latitude": "Latitude:", + "longitude": "Longitude:" + }, + "myNode": { + "tooltip": "This device" + } +} diff --git a/packages/web/public/i18n/locales/ru-RU/messages.json b/packages/web/public/i18n/locales/ru-RU/messages.json new file mode 100644 index 000000000..378300fa1 --- /dev/null +++ b/packages/web/public/i18n/locales/ru-RU/messages.json @@ -0,0 +1,39 @@ +{ + "page": { + "title": "Messages: {{chatName}}", + "placeholder": "Enter Message" + }, + "emptyState": { + "title": "Select a Chat", + "text": "No messages yet." + }, + "selectChatPrompt": { + "text": "Select a channel or node to start messaging." + }, + "sendMessage": { + "placeholder": "Enter your message here...", + "sendButton": "Отправить" + }, + "actionsMenu": { + "addReactionLabel": "Add Reaction", + "replyLabel": "Ответить" + }, + "deliveryStatus": { + "delivered": { + "label": "Message delivered", + "displayText": "Message delivered" + }, + "failed": { + "label": "Message delivery failed", + "displayText": "Delivery failed" + }, + "unknown": { + "label": "Message status unknown", + "displayText": "Unknown state" + }, + "waiting": { + "label": "Sending message", + "displayText": "Waiting for delivery" + } + } +} diff --git a/packages/web/public/i18n/locales/ru-RU/moduleConfig.json b/packages/web/public/i18n/locales/ru-RU/moduleConfig.json new file mode 100644 index 000000000..59362373e --- /dev/null +++ b/packages/web/public/i18n/locales/ru-RU/moduleConfig.json @@ -0,0 +1,448 @@ +{ + "page": { + "tabAmbientLighting": "Световое освещение", + "tabAudio": "Звук", + "tabCannedMessage": "Canned", + "tabDetectionSensor": "Датчик обнаружения", + "tabExternalNotification": "Ext Notif", + "tabMqtt": "MQTT", + "tabNeighborInfo": "Информация об окружности", + "tabPaxcounter": "Счётчик прохожих", + "tabRangeTest": "Проверка дальности", + "tabSerial": "COM-порт", + "tabStoreAndForward": "S&F", + "tabTelemetry": "Телеметрия" + }, + "ambientLighting": { + "title": "Ambient Lighting Settings", + "description": "Settings for the Ambient Lighting module", + "ledState": { + "label": "LED State", + "description": "Sets LED to on or off" + }, + "current": { + "label": "Ток", + "description": "Sets the current for the LED output. Default is 10" + }, + "red": { + "label": "Красный", + "description": "Sets the red LED level. Values are 0-255" + }, + "green": { + "label": "Зеленый", + "description": "Sets the green LED level. Values are 0-255" + }, + "blue": { + "label": "Синий", + "description": "Sets the blue LED level. Values are 0-255" + } + }, + "audio": { + "title": "Audio Settings", + "description": "Settings for the Audio module", + "codec2Enabled": { + "label": "Codec 2 Enabled", + "description": "Enable Codec 2 audio encoding" + }, + "pttPin": { + "label": "PTT Pin", + "description": "GPIO pin to use for PTT" + }, + "bitrate": { + "label": "Bitrate", + "description": "Bitrate to use for audio encoding" + }, + "i2sWs": { + "label": "i2S WS", + "description": "GPIO pin to use for i2S WS" + }, + "i2sSd": { + "label": "i2S SD", + "description": "GPIO pin to use for i2S SD" + }, + "i2sDin": { + "label": "i2S DIN", + "description": "GPIO pin to use for i2S DIN" + }, + "i2sSck": { + "label": "i2S SCK", + "description": "GPIO pin to use for i2S SCK" + } + }, + "cannedMessage": { + "title": "Canned Message Settings", + "description": "Settings for the Canned Message module", + "moduleEnabled": { + "label": "Module Enabled", + "description": "Enable Canned Message" + }, + "rotary1Enabled": { + "label": "Rotary Encoder #1 Enabled", + "description": "Enable the rotary encoder" + }, + "inputbrokerPinA": { + "label": "Encoder Pin A", + "description": "GPIO Pin Value (1-39) For encoder port A" + }, + "inputbrokerPinB": { + "label": "Encoder Pin B", + "description": "GPIO Pin Value (1-39) For encoder port B" + }, + "inputbrokerPinPress": { + "label": "Encoder Pin Press", + "description": "GPIO Pin Value (1-39) For encoder Press" + }, + "inputbrokerEventCw": { + "label": "Clockwise event", + "description": "Select input event." + }, + "inputbrokerEventCcw": { + "label": "Counter Clockwise event", + "description": "Select input event." + }, + "inputbrokerEventPress": { + "label": "Press event", + "description": "Select input event" + }, + "updown1Enabled": { + "label": "Up Down enabled", + "description": "Enable the up / down encoder" + }, + "allowInputSource": { + "label": "Allow Input Source", + "description": "Select from: '_any', 'rotEnc1', 'upDownEnc1', 'cardkb'" + }, + "sendBell": { + "label": "Send Bell", + "description": "Sends a bell character with each message" + } + }, + "detectionSensor": { + "title": "Detection Sensor Settings", + "description": "Settings for the Detection Sensor module", + "enabled": { + "label": "Включено", + "description": "Enable or disable Detection Sensor Module" + }, + "minimumBroadcastSecs": { + "label": "Minimum Broadcast Seconds", + "description": "The interval in seconds of how often we can send a message to the mesh when a state change is detected" + }, + "stateBroadcastSecs": { + "label": "State Broadcast Seconds", + "description": "The interval in seconds of how often we should send a message to the mesh with the current state regardless of changes" + }, + "sendBell": { + "label": "Send Bell", + "description": "Send ASCII bell with alert message" + }, + "name": { + "label": "Friendly Name", + "description": "Used to format the message sent to mesh, max 20 Characters" + }, + "monitorPin": { + "label": "Monitor Pin", + "description": "The GPIO pin to monitor for state changes" + }, + "detectionTriggerType": { + "label": "Detection Triggered Type", + "description": "The type of trigger event to be used" + }, + "usePullup": { + "label": "Use Pullup", + "description": "Whether or not use INPUT_PULLUP mode for GPIO pin" + } + }, + "externalNotification": { + "title": "External Notification Settings", + "description": "Configure the external notification module", + "enabled": { + "label": "Module Enabled", + "description": "Enable External Notification" + }, + "outputMs": { + "label": "Output MS", + "description": "Output MS" + }, + "output": { + "label": "Output", + "description": "Output" + }, + "outputVibra": { + "label": "Output Vibrate", + "description": "Output Vibrate" + }, + "outputBuzzer": { + "label": "Output Buzzer", + "description": "Output Buzzer" + }, + "active": { + "label": "Active", + "description": "Active" + }, + "alertMessage": { + "label": "Alert Message", + "description": "Alert Message" + }, + "alertMessageVibra": { + "label": "Alert Message Vibrate", + "description": "Alert Message Vibrate" + }, + "alertMessageBuzzer": { + "label": "Alert Message Buzzer", + "description": "Alert Message Buzzer" + }, + "alertBell": { + "label": "Alert Bell", + "description": "Should an alert be triggered when receiving an incoming bell?" + }, + "alertBellVibra": { + "label": "Alert Bell Vibrate", + "description": "Alert Bell Vibrate" + }, + "alertBellBuzzer": { + "label": "Alert Bell Buzzer", + "description": "Alert Bell Buzzer" + }, + "usePwm": { + "label": "Use PWM", + "description": "Use PWM" + }, + "nagTimeout": { + "label": "Nag Timeout", + "description": "Nag Timeout" + }, + "useI2sAsBuzzer": { + "label": "Use I²S Pin as Buzzer", + "description": "Designate I²S Pin as Buzzer Output" + } + }, + "mqtt": { + "title": "MQTT Settings", + "description": "Settings for the MQTT module", + "enabled": { + "label": "Включено", + "description": "Enable or disable MQTT" + }, + "address": { + "label": "MQTT Server Address", + "description": "MQTT server address to use for default/custom servers" + }, + "username": { + "label": "MQTT Username", + "description": "MQTT username to use for default/custom servers" + }, + "password": { + "label": "MQTT Password", + "description": "MQTT password to use for default/custom servers" + }, + "encryptionEnabled": { + "label": "Encryption Enabled", + "description": "Enable or disable MQTT encryption. Note: All messages are sent to the MQTT broker unencrypted if this option is not enabled, even when your uplink channels have encryption keys set. This includes position data." + }, + "jsonEnabled": { + "label": "JSON Enabled", + "description": "Whether to send/consume JSON packets on MQTT" + }, + "tlsEnabled": { + "label": "TLS Enabled", + "description": "Enable or disable TLS" + }, + "root": { + "label": "Корневая тема", + "description": "MQTT root topic to use for default/custom servers" + }, + "proxyToClientEnabled": { + "label": "MQTT Client Proxy Enabled", + "description": "Utilizes the network connection to proxy MQTT messages to the client." + }, + "mapReportingEnabled": { + "label": "Map Reporting Enabled", + "description": "Your node will periodically send an unencrypted map report packet to the configured MQTT server, this includes id, short and long name, approximate location, hardware model, role, firmware version, LoRa region, modem preset and primary channel name." + }, + "mapReportSettings": { + "publishIntervalSecs": { + "label": "Map Report Publish Interval (s)", + "description": "Interval in seconds to publish map reports" + }, + "positionPrecision": { + "label": "Approximate Location", + "description": "Position shared will be accurate within this distance", + "options": { + "metric_km23": "Within 23 km", + "metric_km12": "Within 12 km", + "metric_km5_8": "Within 5.8 km", + "metric_km2_9": "Within 2.9 km", + "metric_km1_5": "Within 1.5 km", + "metric_m700": "Within 700 m", + "metric_m350": "Within 350 m", + "metric_m200": "Within 200 m", + "metric_m90": "Within 90 m", + "metric_m50": "Within 50 m", + "imperial_mi15": "Within 15 miles", + "imperial_mi7_3": "Within 7.3 miles", + "imperial_mi3_6": "Within 3.6 miles", + "imperial_mi1_8": "Within 1.8 miles", + "imperial_mi0_9": "Within 0.9 miles", + "imperial_mi0_5": "Within 0.5 miles", + "imperial_mi0_2": "Within 0.2 miles", + "imperial_ft600": "Within 600 feet", + "imperial_ft300": "Within 300 feet", + "imperial_ft150": "Within 150 feet" + } + } + } + }, + "neighborInfo": { + "title": "Neighbor Info Settings", + "description": "Settings for the Neighbor Info module", + "enabled": { + "label": "Включено", + "description": "Enable or disable Neighbor Info Module" + }, + "updateInterval": { + "label": "Интервал обновления", + "description": "Interval in seconds of how often we should try to send our Neighbor Info to the mesh" + } + }, + "paxcounter": { + "title": "Paxcounter Settings", + "description": "Settings for the Paxcounter module", + "enabled": { + "label": "Module Enabled", + "description": "Enable Paxcounter" + }, + "paxcounterUpdateInterval": { + "label": "Update Interval (seconds)", + "description": "How long to wait between sending paxcounter packets" + }, + "wifiThreshold": { + "label": "WiFi RSSI Threshold", + "description": "At what WiFi RSSI level should the counter increase. Defaults to -80." + }, + "bleThreshold": { + "label": "BLE RSSI Threshold", + "description": "At what BLE RSSI level should the counter increase. Defaults to -80." + } + }, + "rangeTest": { + "title": "Range Test Settings", + "description": "Settings for the Range Test module", + "enabled": { + "label": "Module Enabled", + "description": "Enable Range Test" + }, + "sender": { + "label": "Message Interval", + "description": "How long to wait between sending test packets" + }, + "save": { + "label": "Save CSV to storage", + "description": "ESP32 Only" + } + }, + "serial": { + "title": "Serial Settings", + "description": "Settings for the Serial module", + "enabled": { + "label": "Module Enabled", + "description": "Enable Serial output" + }, + "echo": { + "label": "Echo", + "description": "Any packets you send will be echoed back to your device" + }, + "rxd": { + "label": "Receive Pin", + "description": "Set the GPIO pin to the RXD pin you have set up." + }, + "txd": { + "label": "Transmit Pin", + "description": "Set the GPIO pin to the TXD pin you have set up." + }, + "baud": { + "label": "Baud Rate", + "description": "The serial baud rate" + }, + "timeout": { + "label": "Время ожидания истекло", + "description": "Seconds to wait before we consider your packet as 'done'" + }, + "mode": { + "label": "Mode", + "description": "Select Mode" + }, + "overrideConsoleSerialPort": { + "label": "Override Console Serial Port", + "description": "If you have a serial port connected to the console, this will override it." + } + }, + "storeForward": { + "title": "Store & Forward Settings", + "description": "Settings for the Store & Forward module", + "enabled": { + "label": "Module Enabled", + "description": "Enable Store & Forward" + }, + "heartbeat": { + "label": "Heartbeat Enabled", + "description": "Enable Store & Forward heartbeat" + }, + "records": { + "label": "Количество записей", + "description": "Number of records to store" + }, + "historyReturnMax": { + "label": "Макс возврат истории", + "description": "Max number of records to return" + }, + "historyReturnWindow": { + "label": "Окно возврата истории", + "description": "Return records from this time window (minutes)" + } + }, + "telemetry": { + "title": "Telemetry Settings", + "description": "Settings for the Telemetry module", + "deviceUpdateInterval": { + "label": "Device Metrics", + "description": "Интервал обновления метрик устройства (в секундах)" + }, + "environmentUpdateInterval": { + "label": "Интервал обновления метрик окружения (в секундах)", + "description": "" + }, + "environmentMeasurementEnabled": { + "label": "Module Enabled", + "description": "Enable the Environment Telemetry" + }, + "environmentScreenEnabled": { + "label": "Displayed on Screen", + "description": "Show the Telemetry Module on the OLED" + }, + "environmentDisplayFahrenheit": { + "label": "Display Fahrenheit", + "description": "Display temp in Fahrenheit" + }, + "airQualityEnabled": { + "label": "Air Quality Enabled", + "description": "Enable the Air Quality Telemetry" + }, + "airQualityInterval": { + "label": "Air Quality Update Interval", + "description": "How often to send Air Quality data over the mesh" + }, + "powerMeasurementEnabled": { + "label": "Power Measurement Enabled", + "description": "Enable the Power Measurement Telemetry" + }, + "powerUpdateInterval": { + "label": "Power Update Interval", + "description": "How often to send Power data over the mesh" + }, + "powerScreenEnabled": { + "label": "Power Screen Enabled", + "description": "Enable the Power Telemetry Screen" + } + } +} diff --git a/packages/web/public/i18n/locales/ru-RU/nodes.json b/packages/web/public/i18n/locales/ru-RU/nodes.json new file mode 100644 index 000000000..ea231b707 --- /dev/null +++ b/packages/web/public/i18n/locales/ru-RU/nodes.json @@ -0,0 +1,59 @@ +{ + "nodeDetail": { + "publicKeyEnabled": { + "label": "Public Key Enabled" + }, + "noPublicKey": { + "label": "No Public Key" + }, + "directMessage": { + "label": "Direct Message {{shortName}}" + }, + "favorite": { + "label": "Избранное", + "tooltip": "Add or remove this node from your favorites" + }, + "notFavorite": { + "label": "Not a Favorite" + }, + "error": { + "label": "Ошибки", + "text": "An error occurred while fetching node details. Please try again later." + }, + "status": { + "heard": "Heard", + "mqtt": "MQTT" + }, + "elevation": { + "label": "Elevation" + }, + "channelUtil": { + "label": "Channel Util" + }, + "airtimeUtil": { + "label": "Airtime Util" + } + }, + "nodesTable": { + "headings": { + "longName": "Полное имя", + "connection": "Соединения", + "lastHeard": "Last Heard", + "encryption": "Encryption", + "model": "Model", + "macAddress": "MAC Address" + }, + "connectionStatus": { + "direct": "Прямой", + "away": "away", + "viaMqtt": ", via MQTT" + } + }, + "actions": { + "added": "Added", + "removed": "Removed", + "ignoreNode": "Ignore Node", + "unignoreNode": "Unignore Node", + "requestPosition": "Request Position" + } +} diff --git a/packages/web/public/i18n/locales/ru-RU/ui.json b/packages/web/public/i18n/locales/ru-RU/ui.json new file mode 100644 index 000000000..492d459ec --- /dev/null +++ b/packages/web/public/i18n/locales/ru-RU/ui.json @@ -0,0 +1,230 @@ +{ + "navigation": { + "title": "Navigation", + "messages": "Сообщения", + "map": "Карта", + "settings": "Настройки", + "channels": "Каналы", + "radioConfig": "Radio Config", + "deviceConfig": "Настройки устройства", + "moduleConfig": "Module Config", + "manageConnections": "Manage Connections", + "nodes": "Узлы" + }, + "app": { + "title": "Meshtastic", + "logo": "Meshtastic Logo" + }, + "sidebar": { + "collapseToggle": { + "button": { + "open": "Open sidebar", + "close": "Close sidebar" + } + }, + "deviceInfo": { + "volts": "{{voltage}} volts", + "firmware": { + "title": "Прошивка", + "version": "v{{version}}", + "buildDate": "Build date: {{date}}" + } + } + }, + "batteryStatus": { + "charging": "{{level}}% charging", + "pluggedIn": "Plugged in", + "title": "Батарея" + }, + "search": { + "nodes": "Search nodes...", + "channels": "Search channels...", + "commandPalette": "Search commands..." + }, + "toast": { + "positionRequestSent": { + "title": "Position request sent." + }, + "requestingPosition": { + "title": "Requesting position, please wait..." + }, + "sendingTraceroute": { + "title": "Sending Traceroute, please wait..." + }, + "tracerouteSent": { + "title": "Traceroute sent." + }, + "savedChannel": { + "title": "Saved Channel: {{channelName}}" + }, + "messages": { + "pkiEncryption": { + "title": "Chat is using PKI encryption." + }, + "pskEncryption": { + "title": "Chat is using PSK encryption." + } + }, + "configSaveError": { + "title": "Error Saving Config", + "description": "An error occurred while saving the configuration." + }, + "validationError": { + "title": "Config Errors Exist", + "description": "Please fix the configuration errors before saving." + }, + "saveSuccess": { + "title": "Saving Config", + "description": "The configuration change {{case}} has been saved." + }, + "saveAllSuccess": { + "title": "Saved", + "description": "All configuration changes have been saved." + }, + "favoriteNode": { + "title": "{{action}} {{nodeName}} {{direction}} favorites.", + "action": { + "added": "Added", + "removed": "Removed", + "to": "to", + "from": "from" + } + }, + "ignoreNode": { + "title": "{{action}} {{nodeName}} {{direction}} ignore list", + "action": { + "added": "Added", + "removed": "Removed", + "to": "to", + "from": "from" + } + } + }, + "notifications": { + "copied": { + "label": "Copied!" + }, + "copyToClipboard": { + "label": "Copy to clipboard" + }, + "hidePassword": { + "label": "Скрыть пароль" + }, + "showPassword": { + "label": "Показать пароль" + }, + "deliveryStatus": { + "delivered": "Delivered", + "failed": "Delivery Failed", + "waiting": "Waiting", + "unknown": "Неизвестно" + } + }, + "general": { + "label": "General" + }, + "hardware": { + "label": "Оборудование" + }, + "metrics": { + "label": "Metrics" + }, + "role": { + "label": "Роль" + }, + "filter": { + "label": "Фильтр" + }, + "advanced": { + "label": "Расширенные" + }, + "clearInput": { + "label": "Clear input" + }, + "resetFilters": { + "label": "Reset Filters" + }, + "nodeName": { + "label": "Node name/number", + "placeholder": "Meshtastic 1234" + }, + "airtimeUtilization": { + "label": "Airtime Utilization (%)", + "short": "Airtime Util. (%)" + }, + "batteryLevel": { + "label": "Battery level (%)", + "labelText": "Battery level (%): {{value}}" + }, + "batteryVoltage": { + "label": "Battery voltage (V)", + "title": "Напряжение" + }, + "channelUtilization": { + "label": "Channel Utilization (%)", + "short": "Channel Util. (%)" + }, + "hops": { + "direct": "Прямой", + "label": "Number of hops", + "text": "Number of hops: {{value}}" + }, + "lastHeard": { + "label": "Последний раз слышен", + "labelText": "Last heard: {{value}}", + "nowLabel": "Now" + }, + "snr": { + "label": "SNR (db)" + }, + "favorites": { + "label": "Favorites" + }, + "hide": { + "label": "Hide" + }, + "showOnly": { + "label": "Show Only" + }, + "viaMqtt": { + "label": "Connected via MQTT" + }, + "hopsUnknown": { + "label": "Unknown number of hops" + }, + "showUnheard": { + "label": "Unknown last heard" + }, + "language": { + "label": "Язык", + "changeLanguage": "Change Language" + }, + "theme": { + "dark": "Темная", + "light": "Светлая", + "system": "Automatic", + "changeTheme": "Change Color Scheme" + }, + "errorPage": { + "title": "This is a little embarrassing...", + "description1": "We are really sorry but an error occurred in the web client that caused it to crash.
This is not supposed to happen, and we are working hard to fix it.", + "description2": "The best way to prevent this from happening again to you or anyone else is to report the issue to us.", + "reportInstructions": "Please include the following information in your report:", + "reportSteps": { + "step1": "What you were doing when the error occurred", + "step2": "What you expected to happen", + "step3": "What actually happened", + "step4": "Any other relevant information" + }, + "reportLink": "You can report the issue to our <0>GitHub", + "connectionsLink": "Return to the <0>connections", + "detailsSummary": "Error Details", + "errorMessageLabel": "Error message:", + "stackTraceLabel": "Stack trace:", + "fallbackError": "{{error}}" + }, + "footer": { + "text": "Powered by <0>▲ Vercel | Meshtastic® is a registered trademark of Meshtastic LLC. | <1>Legal Information", + "commitSha": "Commit SHA: {{sha}}" + } +} diff --git a/packages/web/public/i18n/locales/sv-SE/channels.json b/packages/web/public/i18n/locales/sv-SE/channels.json index 94fb93753..79ed0e6eb 100644 --- a/packages/web/public/i18n/locales/sv-SE/channels.json +++ b/packages/web/public/i18n/locales/sv-SE/channels.json @@ -1,69 +1,71 @@ { - "page": { - "sectionLabel": "Kanaler", - "channelName": "Kanal: {channelName}", - "broadcastLabel": "Primär", - "channelIndex": "# {{index}}" - }, - "validation": { - "pskInvalid": "Ange en giltig {{bits}}-bitars PSK." - }, - "settings": { - "label": "Kanalinställningar", - "description": "Krypto, MQTT & diverse inställningar" - }, - "role": { - "label": "Roll", - "description": "Enhetens telemetri skickas över PRIMÄR. Endast en PRIMÄR kanal tillåts", - "options": { - "primary": "PRIMÄR", - "disabled": "INAKTIVERAD", - "secondary": "SEKUNDÄR" - } - }, - "psk": { - "label": "Delad nyckel (PSK)", - "description": "PSK-längder som stöds: 256-bit, 128-bit, 8-bit eller tom (0-bit)", - "generate": "Generera" - }, - "name": { - "label": "Namn", - "description": "Ett unikt namn för kanalen, <12 bytes. Lämna tomt för standardnamn" - }, - "uplinkEnabled": { - "label": "Upplänk aktiverad", - "description": "Skicka meddelanden från det lokala nätet till MQTT" - }, - "downlinkEnabled": { - "label": "Nedlänk aktiverad", - "description": "Skicka meddelanden från MQTT till det lokala nätet" - }, - "positionPrecision": { - "label": "Plats", - "description": "Platsprecisionen som kan delas med kanalen. Kan inaktiveras.", - "options": { - "none": "Dela inte plats", - "precise": "Exakt plats", - "metric_km23": "Inom 23 kilometer", - "metric_km12": "Inom 12 kilometer", - "metric_km5_8": "Inom 5,8 kilometer", - "metric_km2_9": "Inom 2,9 kilometer", - "metric_km1_5": "Inom 1,5 kilometer", - "metric_m700": "Inom 700 meter", - "metric_m350": "Inom 350 meter", - "metric_m200": "Inom 200 meter", - "metric_m90": "Inom 90 meter", - "metric_m50": "Inom 50 meter", - "imperial_mi15": "Inom 15 engelska mil", - "imperial_mi7_3": "Inom 7,3 engelska mil", - "imperial_mi3_6": "Inom 3,6 engelska mil", - "imperial_mi1_8": "Inom 1,8 engelska mil", - "imperial_mi0_9": "Inom 0,9 engelska mil", - "imperial_mi0_5": "Inom 0,5 engelska mil", - "imperial_mi0_2": "Inom 0,2 engelska mil", - "imperial_ft600": "Inom 600 fot", - "imperial_ft300": "Inom 300 fot", - "imperial_ft150": "Inom 150 fot" - } - } + "page": { + "sectionLabel": "Kanaler", + "channelName": "Kanal: {channelName}", + "broadcastLabel": "Primär", + "channelIndex": "# {{index}}", + "import": "Importera", + "export": "Exportera" + }, + "validation": { + "pskInvalid": "Ange en giltig {{bits}}-bitars PSK." + }, + "settings": { + "label": "Kanalinställningar", + "description": "Krypto, MQTT & diverse inställningar" + }, + "role": { + "label": "Roll", + "description": "Enhetens telemetri skickas över PRIMÄR. Endast en PRIMÄR kanal tillåts", + "options": { + "primary": "PRIMÄR", + "disabled": "INAKTIVERAD", + "secondary": "SEKUNDÄR" + } + }, + "psk": { + "label": "Delad nyckel (PSK)", + "description": "PSK-längder som stöds: 256-bit, 128-bit, 8-bit eller tom (0-bit)", + "generate": "Generera" + }, + "name": { + "label": "Namn", + "description": "Ett unikt namn för kanalen, <12 bytes. Lämna tomt för standardnamn" + }, + "uplinkEnabled": { + "label": "Upplänk aktiverad", + "description": "Skicka meddelanden från det lokala nätet till MQTT" + }, + "downlinkEnabled": { + "label": "Nedlänk aktiverad", + "description": "Skicka meddelanden från MQTT till det lokala nätet" + }, + "positionPrecision": { + "label": "Plats", + "description": "Platsprecisionen som kan delas med kanalen. Kan inaktiveras.", + "options": { + "none": "Dela inte plats", + "precise": "Exakt plats", + "metric_km23": "Inom 23 kilometer", + "metric_km12": "Inom 12 kilometer", + "metric_km5_8": "Inom 5,8 kilometer", + "metric_km2_9": "Inom 2,9 kilometer", + "metric_km1_5": "Inom 1,5 kilometer", + "metric_m700": "Inom 700 meter", + "metric_m350": "Inom 350 meter", + "metric_m200": "Inom 200 meter", + "metric_m90": "Inom 90 meter", + "metric_m50": "Inom 50 meter", + "imperial_mi15": "Inom 15 engelska mil", + "imperial_mi7_3": "Inom 7,3 engelska mil", + "imperial_mi3_6": "Inom 3,6 engelska mil", + "imperial_mi1_8": "Inom 1,8 engelska mil", + "imperial_mi0_9": "Inom 0,9 engelska mil", + "imperial_mi0_5": "Inom 0,5 engelska mil", + "imperial_mi0_2": "Inom 0,2 engelska mil", + "imperial_ft600": "Inom 600 fot", + "imperial_ft300": "Inom 300 fot", + "imperial_ft150": "Inom 150 fot" + } + } } diff --git a/packages/web/public/i18n/locales/sv-SE/commandPalette.json b/packages/web/public/i18n/locales/sv-SE/commandPalette.json index 83f950ce3..df4811666 100644 --- a/packages/web/public/i18n/locales/sv-SE/commandPalette.json +++ b/packages/web/public/i18n/locales/sv-SE/commandPalette.json @@ -15,7 +15,6 @@ "messages": "Meddelanden", "map": "Karta", "config": "Inställningar", - "channels": "Kanaler", "nodes": "Noder" } }, @@ -45,7 +44,8 @@ "label": "Felsökning", "command": { "reconfigure": "Konfigurera om", - "clearAllStoredMessages": "Radera alla sparade meddelanden" + "clearAllStoredMessages": "Radera alla sparade meddelanden", + "clearAllStores": "Töm all lokal lagring" } } } diff --git a/packages/web/public/i18n/locales/sv-SE/common.json b/packages/web/public/i18n/locales/sv-SE/common.json index 0c9efcfb3..424f6056c 100644 --- a/packages/web/public/i18n/locales/sv-SE/common.json +++ b/packages/web/public/i18n/locales/sv-SE/common.json @@ -1,142 +1,165 @@ { - "button": { - "apply": "Verkställ", - "backupKey": "Säkerhetskopiera nyckel", - "cancel": "Avbryt", - "clearMessages": "Ta bort meddelanden", - "close": "Stäng", - "confirm": "Bekräfta", - "delete": "Radera", - "dismiss": "Stäng", - "download": "Ladda ner", - "export": "Exportera", - "generate": "Generera", - "regenerate": "Förnya", - "import": "Importera", - "message": "Meddelande", - "now": "Nu", - "ok": "Okej", - "print": "Skriv ut", - "remove": "Ta bort", - "requestNewKeys": "Begär nya nycklar", - "requestPosition": "Begär position", - "reset": "Nollställ", - "save": "Spara", - "scanQr": "Skanna QR-kod", - "traceRoute": "Spåra rutt", - "submit": "Spara" - }, - "app": { - "title": "Meshtastic", - "fullTitle": "Meshtastic webbklient" - }, - "loading": "Laddar...", - "unit": { - "cps": "CPS", - "dbm": "dBm", - "hertz": "Hz", - "hop": { - "one": "hopp", - "plural": "hopp" - }, - "hopsAway": { - "one": "{{count}} hopp bort", - "plural": "{{count}} hopp bort", - "unknown": "Okänt antal hopp bort" - }, - "megahertz": "MHz", - "raw": "raw", - "meter": { - "one": "Meter", - "plural": "Meter", - "suffix": "m" - }, - "minute": { - "one": "minut", - "plural": "minuter" - }, - "hour": { - "one": "Timme", - "plural": "Timmar" - }, - "millisecond": { - "one": "millisekund", - "plural": "millisekunder", - "suffix": "ms" - }, - "second": { - "one": "sekund", - "plural": "sekunder" - }, - "day": { - "one": "Dag", - "plural": "Dagar" - }, - "month": { - "one": "Månad", - "plural": "Månader" - }, - "year": { - "one": "År", - "plural": "År" - }, - "snr": "SNR", - "volt": { - "one": "Volt", - "plural": "Volt", - "suffix": "V" - }, - "record": { - "one": "Post", - "plural": "Poster" - } - }, - "security": { - "0bit": "Tom", - "8bit": "8 bitar", - "128bit": "128 bitar", - "256bit": "256 bitar" - }, - "unknown": { - "longName": "Okänd", - "shortName": "UNK", - "notAvailable": "–", - "num": "??" - }, - "nodeUnknownPrefix": "!", - "unset": "EJ SATT", - "fallbackName": "Meshtastic {{last4}}", - "node": "Nod", - "formValidation": { - "unsavedChanges": "Osparade ändringar", - "tooBig": { - "string": "Texten är för lång. Ange en text mindre än eller lika med {{maximum}} tecken långt.", - "number": "Värdet är för stort. Ange ett numeriskt värde mindre än eller lika med {{maximum}}.", - "bytes": "Värdet är för stort. En längd mindre än eller lika med {{params.maximum}} bytes krävs." - }, - "tooSmall": { - "string": "Texten är för kort. Ange en text längre än eller lika med {{minimum}} tecken långt.", - "number": "Värdet är för litet. Ange ett numeriskt värde större än eller lika med {{minimum}}." - }, - "invalidFormat": { - "ipv4": "Ogiltigt format, en giltig IPv4-adress krävs.", - "key": "Ogiltigt format, en giltig Base64-kodad nyckel krävs (PSK)." - }, - "invalidType": { - "number": "Ogiltig typ, fältet måste innehålla ett tal." - }, - "pskLength": { - "0bit": "Fältet måste vara tomt.", - "8bit": "Nyckeln måste vara en 8-bitars nyckel (PSK).", - "128bit": "Nyckeln måste vara en 128-bitars nyckel (PSK).", - "256bit": "Nyckeln måste vara en 256-bitars nyckel (PSK)." - }, - "required": { - "generic": "Obligatoriskt fält.", - "managed": "Åtminstone en administratörsnyckel krävs om noden fjärrhanteras.", - "key": "En nyckel måste anges." - } - }, - "yes": "Ja", - "no": "Nej" + "button": { + "apply": "Verkställ", + "addConnection": "Lägg till anslutning", + "saveConnection": "Spara anslutning", + "backupKey": "Säkerhetskopiera nyckel", + "cancel": "Avbryt", + "connect": "Anslut", + "clearMessages": "Ta bort meddelanden", + "close": "Stäng", + "confirm": "Bekräfta", + "delete": "Radera", + "dismiss": "Stäng", + "download": "Ladda ner", + "disconnect": "Koppla från", + "export": "Exportera", + "generate": "Generera", + "regenerate": "Förnya", + "import": "Importera", + "message": "Meddelande", + "now": "Nu", + "ok": "Okej", + "print": "Skriv ut", + "remove": "Ta bort", + "requestNewKeys": "Begär nya nycklar", + "requestPosition": "Begär position", + "reset": "Nollställ", + "retry": "Försök igen", + "save": "Spara", + "setDefault": "Sätt som standard", + "unsetDefault": "Ta bort som standard", + "scanQr": "Skanna QR-kod", + "traceRoute": "Spåra rutt", + "submit": "Spara" + }, + "app": { + "title": "Meshtastic", + "fullTitle": "Meshtastic webbklient" + }, + "loading": "Laddar...", + "unit": { + "cps": "CPS", + "dbm": "dBm", + "hertz": "Hz", + "hop": { + "one": "hopp", + "plural": "hopp" + }, + "hopsAway": { + "one": "{{count}} hopp bort", + "plural": "{{count}} hopp bort", + "unknown": "Okänt antal hopp bort" + }, + "megahertz": "MHz", + "kilohertz": "kHz", + "raw": "raw", + "meter": { + "one": "Meter", + "plural": "Meter", + "suffix": "m" + }, + "kilometer": { + "one": "kilometer", + "plural": "kilometer", + "suffix": "km" + }, + "minute": { + "one": "minut", + "plural": "minuter" + }, + "hour": { + "one": "Timme", + "plural": "Timmar" + }, + "millisecond": { + "one": "millisekund", + "plural": "millisekunder", + "suffix": "ms" + }, + "second": { + "one": "sekund", + "plural": "sekunder" + }, + "day": { + "one": "Dag", + "plural": "Dagar", + "today": "Idag", + "yesterday": "Igår" + }, + "month": { + "one": "Månad", + "plural": "Månader" + }, + "year": { + "one": "År", + "plural": "År" + }, + "snr": "SNR", + "volt": { + "one": "Volt", + "plural": "Volt", + "suffix": "V" + }, + "record": { + "one": "Post", + "plural": "Poster" + }, + "degree": { + "one": "grad", + "plural": "grader", + "suffix": "°" + } + }, + "security": { + "0bit": "Tom", + "8bit": "8 bitar", + "128bit": "128 bitar", + "256bit": "256 bitar" + }, + "unknown": { + "longName": "Okänd", + "shortName": "UNK", + "notAvailable": "–", + "num": "??" + }, + "nodeUnknownPrefix": "!", + "unset": "EJ SATT", + "fallbackName": "Meshtastic {{last4}}", + "node": "Nod", + "formValidation": { + "unsavedChanges": "Osparade ändringar", + "tooBig": { + "string": "Texten är för lång. Ange en text mindre än eller lika med {{maximum}} tecken långt.", + "number": "Värdet är för stort. Ange ett numeriskt värde mindre än eller lika med {{maximum}}.", + "bytes": "Värdet är för stort. En längd mindre än eller lika med {{params.maximum}} bytes krävs." + }, + "tooSmall": { + "string": "Texten är för kort. Ange en text längre än eller lika med {{minimum}} tecken långt.", + "number": "Värdet är för litet. Ange ett numeriskt värde större än eller lika med {{minimum}}." + }, + "invalidFormat": { + "ipv4": "Ogiltigt format, en giltig IPv4-adress krävs.", + "key": "Ogiltigt format, en giltig Base64-kodad nyckel krävs (PSK)." + }, + "invalidType": { + "number": "Ogiltig typ, fältet måste innehålla ett tal." + }, + "pskLength": { + "0bit": "Fältet måste vara tomt.", + "8bit": "Nyckeln måste vara en 8-bitars nyckel (PSK).", + "128bit": "Nyckeln måste vara en 128-bitars nyckel (PSK).", + "256bit": "Nyckeln måste vara en 256-bitars nyckel (PSK)." + }, + "required": { + "generic": "Obligatoriskt fält.", + "managed": "Åtminstone en administratörsnyckel krävs om noden fjärrhanteras.", + "key": "En nyckel måste anges." + }, + "invalidOverrideFreq": { + "number": "Ogiltigt format, förväntat värde i intervallet 410-930 MHz eller 0 (använd standard)." + } + }, + "yes": "Ja", + "no": "Nej" } diff --git a/packages/web/public/i18n/locales/sv-SE/config.json b/packages/web/public/i18n/locales/sv-SE/config.json new file mode 100644 index 000000000..bf332659c --- /dev/null +++ b/packages/web/public/i18n/locales/sv-SE/config.json @@ -0,0 +1,458 @@ +{ + "page": { + "title": "Inställningar", + "tabUser": "Användare", + "tabChannels": "Kanaler", + "tabBluetooth": "Bluetooth", + "tabDevice": "Enhet", + "tabDisplay": "Display", + "tabLora": "LoRa", + "tabNetwork": "Nätverk", + "tabPosition": "Plats", + "tabPower": "Ström", + "tabSecurity": "Säkerhet" + }, + "sidebar": { + "label": "Konfiguration" + }, + "device": { + "title": "Enhetsinställningar", + "description": "Inställningar för enheten", + "buttonPin": { + "description": "Stift för knapp", + "label": "Knapp-stift" + }, + "buzzerPin": { + "description": "Stift för summer", + "label": "Summer-stift" + }, + "disableTripleClick": { + "description": "Inaktivera trippeltryck", + "label": "Inaktivera trippeltryck" + }, + "doubleTapAsButtonPress": { + "description": "Behandla dubbeltryck som knapptryck", + "label": "Dubbeltryck som knapptryck" + }, + "ledHeartbeatDisabled": { + "description": "Inaktivera blinkande LED", + "label": "LED-puls inaktiverad" + }, + "nodeInfoBroadcastInterval": { + "description": "Hur ofta nod-info ska sändas", + "label": "Sändningsintervall för nod-info" + }, + "posixTimezone": { + "description": "POSIX-tidszonsträng för enheten", + "label": "POSIX-tidszon" + }, + "rebroadcastMode": { + "description": "Hur enheten hanterar återutsändning", + "label": "Återutsändningsläge" + }, + "role": { + "description": "Vilken roll enheten har på nätet", + "label": "Roll" + } + }, + "bluetooth": { + "title": "Bluetooth-inställningar", + "description": "Inställningar för Bluetooth-modulen", + "note": "OBS! Vissa enheter (ESP32) kan inte använda både Bluetooth och WiFi samtidigt.", + "enabled": { + "description": "Aktivera eller inaktivera Bluetooth", + "label": "Aktiverad" + }, + "pairingMode": { + "description": "Metod för parkoppling", + "label": "Parkopplingsläge" + }, + "pin": { + "description": "Pinkod för parkoppling", + "label": "Pinkod" + } + }, + "display": { + "description": "Inställningar för enhetens display", + "title": "Displayinställningar", + "headingBold": { + "description": "Visa rubriktexten i fetstil", + "label": "Fetstil för rubriktext" + }, + "carouselDelay": { + "description": "Tid mellan automatiskt byte av sida", + "label": "Karusellfördröjning" + }, + "compassNorthTop": { + "description": "Fixera norr till toppen av kompassen", + "label": "Kompassens norrläge" + }, + "displayMode": { + "description": "Variant på displaylayout", + "label": "Visningsläge" + }, + "displayUnits": { + "description": "Visa metriska eller Brittiska enheter", + "label": "Enheter" + }, + "flipScreen": { + "description": "Vänd displayen 180 grader", + "label": "Vänd skärmen" + }, + "gpsDisplayUnits": { + "description": "Koordinatformat för visning", + "label": "Koordinatformat" + }, + "oledType": { + "description": "Typ av OLED-skärm ansluten till enheten", + "label": "OLED-typ" + }, + "screenTimeout": { + "description": "Stäng av skärmen efter denna tid", + "label": "Tidsgräns för display" + }, + "twelveHourClock": { + "description": "Använd 12-timmarsformat", + "label": "12-timmars klocka" + }, + "wakeOnTapOrMotion": { + "description": "Väck enheten när rörelse upptäcks av enhetens accelerometer", + "label": "Vakna vid rörelse" + } + }, + "lora": { + "title": "Inställningar för nät", + "description": "Inställningar för LoRa-nätet", + "bandwidth": { + "description": "Kanalens bandbredd i kHz", + "label": "Bandbredd" + }, + "boostedRxGain": { + "description": "Ökad RX-förstärkning", + "label": "Ökad RX-förstärkning" + }, + "codingRate": { + "description": "Nämnaren för kodningshastighet", + "label": "Kodningshastighet" + }, + "frequencyOffset": { + "description": "Frekvensförskjutning för att korrigera vid kalibreringsfel i kristallen", + "label": "Frekvensförskjutning" + }, + "frequencySlot": { + "description": "LoRa-kanalnummer för frekvens", + "label": "Frekvens-slot" + }, + "hopLimit": { + "description": "Maximalt antal hopp", + "label": "Hoppgräns" + }, + "ignoreMqtt": { + "description": "Vidarebefordra inte MQTT-meddelanden över nätet", + "label": "Ignorera MQTT" + }, + "modemPreset": { + "description": "Modem-förinställningar som enheten använder", + "label": "Modem-förinställningar" + }, + "okToMqtt": { + "description": "När den är aktiverad anger denna konfiguration att användaren godkänner att paketet sänds till MQTT. Om avaktiverad uppmanas andra noder att inte vidarebefordra enhetens paket till MQTT", + "label": "OK till MQTT" + }, + "overrideDutyCycle": { + "description": "Ersätt gräns för driftsperiod", + "label": "Åsidosätt gräns för driftsperiod" + }, + "overrideFrequency": { + "description": "Åsidosätt frekvens", + "label": "Åsidosätt frekvens" + }, + "region": { + "description": "Anger regionen för din nod", + "label": "Region" + }, + "spreadingFactor": { + "description": "Indikerar antalet chirps per symbol", + "label": "Spridningsfaktor" + }, + "transmitEnabled": { + "description": "Aktivera/inaktivera sändning (TX) från LoRa-radion", + "label": "Sändning aktiverad" + }, + "transmitPower": { + "description": "Max sändningseffekt", + "label": "Sändningseffekt" + }, + "usePreset": { + "description": "Använd en av de fördefinierade modeminställningarna", + "label": "Använd förinställning" + }, + "meshSettings": { + "description": "Inställningar för LoRa-nät", + "label": "Inställningar för nät" + }, + "waveformSettings": { + "description": "Inställningar för LoRa-vågformen", + "label": "Inställningar för vågform" + }, + "radioSettings": { + "label": "Radioinställningar", + "description": "Inställningar för LoRa-radio" + } + }, + "network": { + "title": "Wifi-konfiguration", + "description": "Konfiguration av WiFi-radio", + "note": "OBS! Vissa enheter (ESP32) kan inte använda både Bluetooth och WiFi samtidigt.", + "addressMode": { + "description": "Val för tilldelning av IP-adress", + "label": "Adress-läge" + }, + "dns": { + "description": "DNS-server", + "label": "DNS" + }, + "ethernetEnabled": { + "description": "Aktivera eller inaktivera Ethernet-porten", + "label": "Aktiverad" + }, + "gateway": { + "description": "Standard-gateway", + "label": "Gateway" + }, + "ip": { + "description": "IP-adress", + "label": "Ip-adress" + }, + "psk": { + "description": "Nätverkslösenord", + "label": "PSK" + }, + "ssid": { + "description": "Nätverksnamn", + "label": "SSID" + }, + "subnet": { + "description": "Subnätmask", + "label": "Subnät" + }, + "wifiEnabled": { + "description": "Aktivera eller inaktivera WiFi-radio", + "label": "Aktiverad" + }, + "meshViaUdp": { + "label": "Mesh via UDP" + }, + "ntpServer": { + "label": "NTP-server" + }, + "rsyslogServer": { + "label": "Rsyslog-server" + }, + "ethernetConfigSettings": { + "description": "Ethernet-portens konfiguration", + "label": "Ethernet-konfiguration" + }, + "ipConfigSettings": { + "description": "IP-konfiguration", + "label": "IP-konfiguration" + }, + "ntpConfigSettings": { + "description": "NTP-konfiguration", + "label": "NTP-konfiguration" + }, + "rsyslogConfigSettings": { + "description": "Rsyslog-konfiguration", + "label": "Rsyslog-konfiguration" + }, + "udpConfigSettings": { + "description": "UDP över nät-konfiguration", + "label": "UDP-konfiguration" + } + }, + "position": { + "title": "Platsinställningar", + "description": "Inställningar för platsmodulen", + "broadcastInterval": { + "description": "Hur ofta din plats skickas ut över nätet", + "label": "Sändningsintervall" + }, + "enablePin": { + "description": "Stift för aktivering av GPS-modulen", + "label": "Stift för aktivering" + }, + "fixedPosition": { + "description": "Rapportera inte den inhämtade GPS-positionen, utan en manuellt angiven sådan", + "label": "Fast plats" + }, + "gpsMode": { + "description": "Konfigurera om enhetens GPS är aktiverad, inaktiverad eller saknas", + "label": "GPS-läge" + }, + "gpsUpdateInterval": { + "description": "Hur ofta en GPS-position ska inhämtas", + "label": "Intervall för GPS-uppdatering" + }, + "positionFlags": { + "description": "Valfria fält att inkludera vid sammansättning av positionsmeddelanden. Ju fler fält som väljs, desto större kommer meddelandet att bli. Längre meddelanden leder till högre sändningsutnyttnande och en högre risk för paketförlust.", + "label": "Positionsflaggor" + }, + "receivePin": { + "description": "RX-stift för GPS-modulen", + "label": "RX-stift" + }, + "smartPositionEnabled": { + "description": "Sänd bara positionsuppdatering när det har skett en tillräckligt stor förändring av positionen", + "label": "Aktivera smart position" + }, + "smartPositionMinDistance": { + "description": "Minsta avstånd (i meter) som enheten måste förflyttas innan en positionsuppdatering sänds", + "label": "Minimiavstånd för smart position" + }, + "smartPositionMinInterval": { + "description": "Minsta tidsintervall (i sekunder) som måste passera innan en positionsuppdatering skickas", + "label": "Minimiintervall för smart position" + }, + "transmitPin": { + "description": "TX-stift för GPS-modulen", + "label": "TX-stift" + }, + "intervalsSettings": { + "description": "Hur ofta enheten skickar positionsuppdateringar", + "label": "Intervall" + }, + "flags": { + "placeholder": "Välj positionsflaggor...", + "altitude": "Altitud", + "altitudeGeoidalSeparation": "Geoidhöjd", + "altitudeMsl": "Altitud är medelhavsnivå", + "dop": "Bidrag till osäkerhet i precision (DOP) PDOP används som standard", + "hdopVdop": "Om DOP är satt, använd HDOP / VDOP värden istället för PDOP", + "numSatellites": "Antal satelliter", + "sequenceNumber": "Sekvensnummer", + "timestamp": "Tidsstämpel", + "unset": "Ej inställd", + "vehicleHeading": "Rörelseriktning", + "vehicleSpeed": "Rörelsehastighet" + } + }, + "power": { + "adcMultiplierOverride": { + "description": "Används för att justera batterispänningsavläsning", + "label": "ADC faktor" + }, + "ina219Address": { + "description": "I2C-adress till INA219 batterimonitorn", + "label": "INA219-adress" + }, + "lightSleepDuration": { + "description": "Hur länge enheten kommer att vara i lätt strömsparläge", + "label": "Tid för lätt strömsparläge" + }, + "minimumWakeTime": { + "description": "Minsta tid enheten kommer att vara vaken efter att ha tagit emot ett paket", + "label": "Minsta vakna tid" + }, + "noConnectionBluetoothDisabled": { + "description": "Om enheten inte har en aktiv Bluetooth-anslutning inaktiveras Bluetooth-radion efter så här lång tid", + "label": "Bluetooth inaktiverad vid frånkoppling" + }, + "powerSavingEnabled": { + "description": "Välj om du strömmatar enheten från en lågströmkälla (sol) för att minimera strömförbrukningen så mycket som möjligt.", + "label": "Aktivera strömsparläge" + }, + "shutdownOnBatteryDelay": { + "description": "Automatisk avstängning av enheten efter att ha strömmatats från batteri så här lång tid, 0 för obestämd tid", + "label": "Fördröjd avstängning vid batteridrift" + }, + "superDeepSleepDuration": { + "description": "Hur länge enheten kommer att vara i djupt strömsparläge", + "label": "Tid för djupt strömsparläge" + }, + "powerConfigSettings": { + "description": "Inställningar för strömmodulen", + "label": "Ströminställningar" + }, + "sleepSettings": { + "description": "Strömsparlägesinställningar för strömmodulen", + "label": "Inställningar för strömsparläge" + } + }, + "security": { + "description": "Inställningar för säkerhet", + "title": "Säkerhetsinställningar", + "button_backupKey": "Säkerhetskopiera nyckel", + "adminChannelEnabled": { + "description": "Tillåt inkommande styrning via den förlegade, osäkra, administrationskanalen", + "label": "Tillåt förlegad administration" + }, + "enableDebugLogApi": { + "description": "Skriv felsökningsloggar över seriell kommunikation samt visa och exportera positions-rensade loggar över Bluetooth", + "label": "Aktivera API för felsökningslogg" + }, + "managed": { + "description": "Om aktiverad, kan enhetens konfigurationsalternativ bara ändras på distans av en fjärradministratörsnod via administratörsmeddelanden. Aktivera inte detta alternativ om inte minst en lämplig fjärradministratörsnod har konfigurerats och den publika nyckeln matats in i något av fälten ovan.", + "label": "Fjärrhanterad" + }, + "privateKey": { + "description": "Används för att skapa en delad nyckel med en fjärrnod", + "label": "Privat nyckel" + }, + "publicKey": { + "description": "Sänds ut till andra noder på nätet för att de ska kunna beräkna en delad hemlig nyckel", + "label": "Publik nyckel" + }, + "primaryAdminKey": { + "description": "Den primära publika nyckeln hos en fjärradministratörsnod auktoriserad att skicka administratörsmeddelanden till den här noden", + "label": "Primär administratörsnyckel" + }, + "secondaryAdminKey": { + "description": "Den sekundära publika nyckeln hos en fjärradministratörsnod auktoriserad att skicka administratörsmeddelanden till den här noden", + "label": "Sekundär administratörsnyckel" + }, + "serialOutputEnabled": { + "description": "Seriell kommunikation över Stream API", + "label": "Seriell kommunikation aktiverad" + }, + "tertiaryAdminKey": { + "description": "Den tertiära publika nyckeln hos en fjärradministratörsnod auktoriserad att skicka administratörsmeddelanden till den här noden", + "label": "Tertiär administratörsnyckel" + }, + "adminSettings": { + "description": "Inställningar för fjärradministration", + "label": "Fjärradministrationsinställningar" + }, + "loggingSettings": { + "description": "Inställningar för loggning", + "label": "Loggningsinställningar" + } + }, + "user": { + "title": "Användarinställningar", + "description": "Konfigurera enhetens namn och identitetsinställningar", + "longName": { + "label": "Långt namn", + "description": "Ditt fullständiga visningsnamn (1-40 tecken)", + "validation": { + "min": "Långt namn måste vara minst 1 tecken", + "max": "Långt namn får inte vara längre än 40 tecken" + } + }, + "shortName": { + "label": "Kort namn", + "description": "Ditt förkortade namn (2-4 tecken)", + "validation": { + "min": "Kort namn måste ha minst 2 tecken", + "max": "Kort namn får inte vara längre än 4 tecken" + } + }, + "isUnmessageable": { + "label": "Meddelanden läses ej", + "description": "Används för att identifiera oövervakade eller infrastrukturnoder så att meddelanden inte skickas till noder som inte kommer svara." + }, + "isLicensed": { + "label": "Licensierad radioamatör (HAM)", + "description": "Aktivera om du är en licensierad amatörradiooperatör. Att aktivera detta alternativ inaktiverar kryptering och är inte kompatibel med standard Meshtastic-nätverket." + } + } +} diff --git a/packages/web/public/i18n/locales/sv-SE/connections.json b/packages/web/public/i18n/locales/sv-SE/connections.json new file mode 100644 index 000000000..0ce8fd744 --- /dev/null +++ b/packages/web/public/i18n/locales/sv-SE/connections.json @@ -0,0 +1,34 @@ +{ + "page": { + "title": "Anslut till en Meshtastic-enhet", + "description": "Lägg till en enhetsanslutning via HTTP, Bluetooth eller seriell kommunikation. Dina sparade anslutningar sparas i din webbläsare." + }, + "connectionType_ble": "BLE", + "connectionType_serial": "Seriell kommunikation", + "connectionType_network": "Nätverk", + "deleteConnection": "Ta bort anslutning", + "areYouSure": "Detta kommer ta bort {{name}}. Du kan inte ångra denna åtgärd.", + "moreActions": "Fler åtgärder", + "noConnections": { + "title": "Inga anslutningar än.", + "description": "Skapa din första anslutning. Den ansluts omedelbart och sparas." + }, + "lastConnectedAt": "Senast ansluten: {{date}}", + "neverConnected": "Aldrig ansluten", + "toasts": { + "connected": "Ansluten", + "nowConnected": "{{name}} är nu ansluten", + "nowDisconnected": "{{name}} är nu frånkopplad", + "disconnected": "Frånkopplad", + "failed": "Anslutning misslyckades", + "checkConnetion": "Kontrollera enheten och inställningarna och försök igen", + "defaultSet": "Standard vald", + "defaultConnection": "Standardanslutningen är nu {{nameisconnected}}", + "deleted": "Borttagen", + "deletedByName": "{{name}} togs bort", + "pickConnectionAgain": "Kunde inte ansluta. Du kan behöva välja enheten/porten på nytt.", + "added": "Anslutning tillagd", + "savedByName": "{{name}} sparad.", + "savedCantConnect": "Anslutningen har sparats men enheten kunde inte anslutas till." + } +} diff --git a/packages/web/public/i18n/locales/sv-SE/dashboard.json b/packages/web/public/i18n/locales/sv-SE/dashboard.json deleted file mode 100644 index a6d941ad2..000000000 --- a/packages/web/public/i18n/locales/sv-SE/dashboard.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "dashboard": { - "title": "Anslutna enheter", - "description": "Hantera dina anslutna Meshtastic-enheter.", - "connectionType_ble": "BLE", - "connectionType_serial": "Seriell kommunikation", - "connectionType_network": "Nätverk", - "noDevicesTitle": "Inga anslutna enheter ", - "noDevicesDescription": "Anslut en ny enhet för att komma igång.", - "button_newConnection": "Ny anslutning" - } -} diff --git a/packages/web/public/i18n/locales/sv-SE/deviceConfig.json b/packages/web/public/i18n/locales/sv-SE/deviceConfig.json index 85852b6fc..911b48626 100644 --- a/packages/web/public/i18n/locales/sv-SE/deviceConfig.json +++ b/packages/web/public/i18n/locales/sv-SE/deviceConfig.json @@ -122,7 +122,7 @@ "title": "Inställningar för nät", "description": "Inställningar för LoRa-nätet", "bandwidth": { - "description": "Kanalens bandbredd i MHz", + "description": "Kanalens bandbredd i kHz", "label": "Bandbredd" }, "boostedRxGain": { diff --git a/packages/web/public/i18n/locales/sv-SE/dialog.json b/packages/web/public/i18n/locales/sv-SE/dialog.json index f229a2ac3..a824b35c9 100644 --- a/packages/web/public/i18n/locales/sv-SE/dialog.json +++ b/packages/web/public/i18n/locales/sv-SE/dialog.json @@ -1,193 +1,238 @@ { - "deleteMessages": { - "description": "Den här åtgärden kommer att rensa all meddelandehistorik. Detta kan inte ångras. Är du säker på att du vill fortsätta?", - "title": "Rensa alla meddelanden" - }, - "deviceName": { - "description": "Enheten kommer att starta om när inställningarna har sparats.", - "longName": "Långt namn", - "shortName": "Kort namn", - "title": "Ändra enhetens namn", - "validation": { - "longNameMax": "Långt namn får inte vara längre än 40 tecken", - "shortNameMax": "Kort namn får inte vara längre än 4 tecken", - "longNameMin": "Långt namn måste ha minst 1 tecken", - "shortNameMin": "Kort namn måste ha minst 1 tecken" - } - }, - "import": { - "description": "Den aktuella LoRa konfigurationen kommer att skrivas över.", - "error": { - "invalidUrl": "Ogiltig Meshtastic URL" - }, - "channelPrefix": "Kanal: ", - "channelSetUrl": "Kanalinställning/QR-kod URL", - "channels": "Kanaler:", - "usePreset": "Använd förinställning?", - "title": "Importera kanaluppsättning" - }, - "locationResponse": { - "title": "Plats: {{identifier}}", - "altitude": "Höjd:", - "coordinates": "Koordinater: ", - "noCoordinates": "Koordinater saknas" - }, - "pkiRegenerateDialog": { - "title": "Förnya nyckel?", - "description": "Är du säker på att du vill förnya den fördelade nyckeln?", - "regenerate": "Förnya" - }, - "newDeviceDialog": { - "title": "Anslut ny enhet", - "https": "https", - "http": "http", - "tabHttp": "HTTP", - "tabBluetooth": "Bluetooth", - "tabSerial": "Seriell kommunikation", - "useHttps": "Använd HTTPS", - "connecting": "Ansluter...", - "connect": "Anslut", - "connectionFailedAlert": { - "title": "Anslutningen misslyckades", - "descriptionPrefix": "Kunde inte ansluta till enheten. ", - "httpsHint": "Om du använder HTTPS kan du behöva godkänna ett självsignerat certifikat först. ", - "openLinkPrefix": "Vänligen öppna ", - "openLinkSuffix": " i en ny flik", - "acceptTlsWarningSuffix": ", acceptera eventuella TLS-varningar om du uppmanas och försök igen", - "learnMoreLink": "Läs mer" - }, - "httpConnection": { - "label": "IP-adress/värdnamn", - "placeholder": "000.000.000.000 / meshtastic.lokal" - }, - "serialConnection": { - "noDevicesPaired": "Inga enheter parkopplade ännu.", - "newDeviceButton": "Ny enhet", - "deviceIdentifier": "# {{index}} - {{vendorId}} - {{productId}}" - }, - "bluetoothConnection": { - "noDevicesPaired": "Inga enheter parkopplade ännu.", - "newDeviceButton": "Ny enhet", - "connectionFailed": "Anslutningen misslyckades", - "deviceDisconnected": "Enheten frånkopplad", - "unknownDevice": "Okänd enhet", - "errorLoadingDevices": "Fel vid inläsning av enheter", - "unknownErrorLoadingDevices": "Okänt fel vid inläsning av enheter" - }, - "validation": { - "requiresWebBluetooth": "Den här anslutningstypen kräver <0>Web Bluetooth. Använd en webbläsare som stöds, till exempel Chrome eller Edge.", - "requiresWebSerial": "Den här anslutningstypen kräver <0>Web Serial. Använd en webbläsare som stöds, till exempel Chrome eller Edge.", - "requiresSecureContext": "Denna applikation kräver en <0>säker kontext. Anslut med HTTPS eller localhost.", - "additionallyRequiresSecureContext": "Dessutom kräver den ett <0>säker kontext. Vänligen anslut med HTTPS eller localhost." - } - }, - "nodeDetails": { - "message": "Meddelande", - "requestPosition": "Begär plats", - "traceRoute": "Spåra rutt", - "airTxUtilization": "Sändningsutnyttjande", - "allRawMetrics": "All oformaterad data", - "batteryLevel": "Batterinivå", - "channelUtilization": "Kanalutnyttjande", - "details": "Detaljer:", - "deviceMetrics": "Enhetens mätvärden:", - "hardware": "Hårdvara: ", - "lastHeard": "Senast hörd: ", - "nodeHexPrefix": "Nod-hex: ", - "nodeNumber": "Nodnummer: ", - "position": "Plats:", - "role": "Roll: ", - "uptime": "Drifttid: ", - "voltage": "Spänning", - "title": "Nodinformation för {{identifier}}", - "ignoreNode": "Ignorera nod", - "removeNode": "Ta bort nod", - "unignoreNode": "Ta bort favoritmarkering", - "security": "Säkerhet:", - "publicKey": "Publik nyckel: ", - "messageable": "Övervakad: ", - "KeyManuallyVerifiedTrue": "Den publika nyckeln har verifierats manuellt", - "KeyManuallyVerifiedFalse": "Den publika nyckeln är inte manuellt verifierad" - }, - "pkiBackup": { - "loseKeysWarning": "Om du förlorar dina nycklar måste du återställa din enhet.", - "secureBackup": "Det är viktigt att säkerhetskopiera dina publika och privata nycklar och förvara din säkerhetskopia säkert.", - "footer": "=== END OF KEYS ===", - "header": "=== MESHTASTIC KEYS FOR {{longName}} ({{shortName}}) ===", - "privateKey": "Privat nyckel:", - "publicKey": "Publik nyckel:", - "fileName": "meshtastic_keys_{{longName}}_{{shortName}}.txt", - "title": "Säkerhetskopiera nycklar" - }, - "pkiBackupReminder": { - "description": "Vi rekommenderar att du säkerhetskopierar dina nycklar regelbundet. Vill du säkerhetskopiera nu?", - "title": "Påminnelse om säkerhetskopiering", - "remindLaterPrefix": "Påminn mig om", - "remindNever": "Påminn mig aldrig", - "backupNow": "Säkerhetskopiera nu" - }, - "pkiRegenerate": { - "description": "Är du säker på att du vill förnya nyckelpar?", - "title": "Förnya nyckelpar" - }, - "qr": { - "addChannels": "Lägg till kanaler", - "replaceChannels": "Ersätt kanaler", - "description": "Den aktuella LoRa-konfigurationen kommer också att delas.", - "sharableUrl": "Delbar URL", - "title": "Generera QR-kod" - }, - "reboot": { - "title": "Starta om enhet", - "description": "Starta om nu eller schemalägga en omstart av den anslutna noden. Alternativt kan du välja att starta om till OTA (Over-the-Air) läge.", - "ota": "Starta om till OTA-läge", - "enterDelay": "Ange fördröjning", - "scheduled": "Omstart har schemalagts", - "schedule": "Schemalägg omstart", - "now": "Starta om nu", - "cancel": "Avbryt schemalagd omstart" - }, - "refreshKeys": { - "description": { - "acceptNewKeys": "Detta kommer att ta bort noden från enheten och begära nya nycklar.", - "keyMismatchReasonSuffix": ". Detta beror på att fjärrnodens nuvarande publika nyckel inte matchar den tidigare lagrade nyckeln för den här noden.", - "unableToSendDmPrefix": "Din nod kan inte skicka ett direkt meddelande till noden: " - }, - "acceptNewKeys": "Godkänn nya nycklar", - "title": "Nycklarna matchar inte - {{identifier}}" - }, - "removeNode": { - "description": "Är du säker på att du vill ta bort den här noden?", - "title": "Ta bort noden?" - }, - "shutdown": { - "title": "Schemalägg avstängning", - "description": "Stäng av den anslutna noden efter x minuter." - }, - "traceRoute": { - "routeToDestination": "Rutt till destination:", - "routeBack": "Rutt tillbaka:" - }, - "tracerouteResponse": { - "title": "Spåra rutt: {{identifier}}" - }, - "unsafeRoles": { - "confirmUnderstanding": "Ja, jag vet vad jag gör", - "conjunction": " och blogginlägget om ", - "postamble": " och förstår konsekvenserna av att ändra roll.", - "preamble": "Jag har läst ", - "choosingRightDeviceRole": "Att välja rätt enhetsroll", - "deviceRoleDocumentation": "Dokumentation för enhetsroll", - "title": "Är du säker?" - }, - "managedMode": { - "confirmUnderstanding": "Ja, jag vet vad jag gör", - "title": "Är du säker?", - "description": "Aktivering av fjärrhanterat läge blockerar klienter (inklusive webbklienten) från att skriva inställningar till en radio. När detta är aktiverat kan enhetens inställningar endast ändras via fjärradministratörsmeddelanden. Den här inställningen krävs inte för fjärradministration." - }, - "clientNotification": { - "title": "Meddelande från enheten", - "TraceRoute can only be sent once every 30 seconds": "Ruttspårning kan bara skickas en gång per 30 sekunder", - "Compromised keys were detected and regenerated.": "Komprometterade nycklar upptäcktes på enheten och nya har genererats." - } + "deleteMessages": { + "description": "Den här åtgärden kommer att rensa all meddelandehistorik. Detta kan inte ångras. Är du säker på att du vill fortsätta?", + "title": "Rensa alla meddelanden" + }, + "import": { + "description": "Den aktuella LoRa konfigurationen kommer att skrivas över.", + "error": { + "invalidUrl": "Ogiltig Meshtastic URL" + }, + "channelPrefix": "Kanal: ", + "primary": "Primär ", + "doNotImport": "Importera inte", + "channelName": "Namn", + "channelSlot": "Plats", + "channelSetUrl": "Kanalinställning/QR-kod URL", + "useLoraConfig": "Importera LoRa-konfiguration", + "presetDescription": "Den nuvarande LoRa-konfigurationen kommer att ersättas.", + "title": "Importera kanaluppsättning" + }, + "locationResponse": { + "title": "Plats: {{identifier}}", + "altitude": "Höjd:", + "coordinates": "Koordinater: ", + "noCoordinates": "Koordinater saknas" + }, + "pkiRegenerateDialog": { + "title": "Förnya nyckel?", + "description": "Är du säker på att du vill förnya den fördelade nyckeln?", + "regenerate": "Förnya" + }, + "addConnection": { + "title": "Lägg till anslutning", + "description": "Välj en anslutningstyp och fyll i uppgifterna", + "validation": { + "requiresWebBluetooth": "Den här anslutningstypen kräver <0>Web Bluetooth. Använd en webbläsare som stöds, till exempel Chrome eller Edge.", + "requiresWebSerial": "Den här anslutningstypen kräver <0>Web Serial. Använd en webbläsare som stöds, till exempel Chrome eller Edge.", + "requiresSecureContext": "Denna applikation kräver en <0>säker kontext. Anslut med HTTPS eller localhost.", + "additionallyRequiresSecureContext": "Dessutom kräver den ett <0>säker kontext. Vänligen anslut med HTTPS eller localhost." + }, + "bluetoothConnection": { + "namePlaceholder": "Min Bluetooth-nod", + "supported": { + "title": "Web Bluetooth stöds" + }, + "notSupported": { + "title": "Web Bluetooth stöds inte", + "description": "Din webbläsare eller enhet har inte stöd för Web Bluetooth" + }, + "short": "BT: {{deviceName}}", + "long": "Bluetooth-enhet", + "device": "Enhet", + "selectDevice": "Välj enhet", + "selected": "Bluetooth-enhet vald", + "notSelected": "Ingen enhet vald", + "helperText": "Använder Meshtastic Bluetooth-tjänsten för upptäckt." + }, + "serialConnection": { + "namePlaceholder": "Min seriella nod", + "helperText": "Att välja en port ger behörighet så att appen kan öppna den för att ansluta.", + "supported": { + "title": "Web Serial stöds" + }, + "notSupported": { + "title": "Web Serial stöds inte", + "description": "Din webbläsare eller enhet har inte stöd för Web Serial" + }, + "portSelected": { + "title": "Seriell port vald", + "description": "Portbehörigheter beviljade." + }, + "port": "Port", + "selectPort": "Välj port", + "deviceName": "USB {{vendorId}}:{{productId}}", + "notSelected": "Ingen port vald" + }, + "httpConnection": { + "namePlaceholder": "Min HTTP-nod", + "inputPlaceholder": "192.168.1.10 eller meshtastic.local", + "heading": "URL eller IP", + "useHttps": "Använd HTTPS", + "invalidUrl": { + "title": "Ogiltig adress", + "description": "Ange en giltig HTTP- eller HTTPS-URL." + }, + "connectionTest": { + "description": "Testa konnetionen innan du sparar för att verifiera att enheten är nåbar.", + "button": { + "loading": "Testar...", + "label": "Testa anslutningen" + }, + "reachable": "Nåbar", + "notReachable": "Kan inte nås", + "success": { + "title": "Anslutningstest lyckades", + "description": "Enheten verkar vara nåbar." + }, + "failure": { + "title": "Anslutningen misslyckades", + "description": "Kunde inte nå enheten. Kontrollera URL:en och försök igen." + } + } + } + }, + "nodeDetails": { + "message": "Meddelande", + "requestPosition": "Begär plats", + "traceRoute": "Spåra rutt", + "airTxUtilization": "Sändningsutnyttjande", + "allRawMetrics": "All oformaterad data", + "batteryLevel": "Batterinivå", + "channelUtilization": "Kanalutnyttjande", + "details": "Detaljer:", + "deviceMetrics": "Enhetens mätvärden:", + "hardware": "Hårdvara: ", + "lastHeard": "Senast hörd: ", + "nodeHexPrefix": "Nod-hex: ", + "nodeNumber": "Nodnummer: ", + "position": "Plats:", + "role": "Roll: ", + "uptime": "Drifttid: ", + "voltage": "Spänning", + "title": "Nodinformation för {{identifier}}", + "ignoreNode": "Ignorera nod", + "removeNode": "Ta bort nod", + "unignoreNode": "Ta bort favoritmarkering", + "security": "Säkerhet:", + "publicKey": "Publik nyckel: ", + "messageable": "Övervakad: ", + "KeyManuallyVerifiedTrue": "Den publika nyckeln har verifierats manuellt", + "KeyManuallyVerifiedFalse": "Den publika nyckeln är inte manuellt verifierad" + }, + "pkiBackup": { + "loseKeysWarning": "Om du förlorar dina nycklar måste du återställa din enhet.", + "secureBackup": "Det är viktigt att säkerhetskopiera dina publika och privata nycklar och förvara din säkerhetskopia säkert.", + "footer": "=== END OF KEYS ===", + "header": "=== MESHTASTIC KEYS FOR {{longName}} ({{shortName}}) ===", + "privateKey": "Privat nyckel:", + "publicKey": "Publik nyckel:", + "fileName": "meshtastic_keys_{{longName}}_{{shortName}}.txt", + "title": "Säkerhetskopiera nycklar" + }, + "pkiBackupReminder": { + "description": "Vi rekommenderar att du säkerhetskopierar dina nycklar regelbundet. Vill du säkerhetskopiera nu?", + "title": "Påminnelse om säkerhetskopiering", + "remindLaterPrefix": "Påminn mig om", + "remindNever": "Påminn mig aldrig", + "backupNow": "Säkerhetskopiera nu" + }, + "pkiRegenerate": { + "description": "Är du säker på att du vill förnya nyckelpar?", + "title": "Förnya nyckelpar" + }, + "qr": { + "addChannels": "Lägg till kanaler", + "replaceChannels": "Ersätt kanaler", + "description": "Den aktuella LoRa-konfigurationen kommer också att delas.", + "sharableUrl": "Delbar URL", + "title": "Generera QR-kod" + }, + "reboot": { + "title": "Starta om enhet", + "description": "Starta om nu eller schemalägga en omstart av den anslutna noden. Alternativt kan du välja att starta om till OTA (Over-the-Air) läge.", + "ota": "Starta om till OTA-läge", + "enterDelay": "Ange fördröjning", + "scheduled": "Omstart har schemalagts", + "schedule": "Schemalägg omstart", + "now": "Starta om nu", + "cancel": "Avbryt schemalagd omstart" + }, + "refreshKeys": { + "description": { + "acceptNewKeys": "Detta kommer att ta bort noden från enheten och begära nya nycklar.", + "keyMismatchReasonSuffix": ". Detta beror på att fjärrnodens nuvarande publika nyckel inte matchar den tidigare lagrade nyckeln för den här noden.", + "unableToSendDmPrefix": "Din nod kan inte skicka ett direkt meddelande till noden: " + }, + "acceptNewKeys": "Godkänn nya nycklar", + "title": "Nycklarna matchar inte - {{identifier}}" + }, + "removeNode": { + "description": "Är du säker på att du vill ta bort den här noden?", + "title": "Ta bort noden?" + }, + "shutdown": { + "title": "Schemalägg avstängning", + "description": "Stäng av den anslutna noden efter x minuter." + }, + "traceRoute": { + "routeToDestination": "Rutt till destination:", + "routeBack": "Rutt tillbaka:" + }, + "tracerouteResponse": { + "title": "Spåra rutt: {{identifier}}" + }, + "unsafeRoles": { + "confirmUnderstanding": "Ja, jag vet vad jag gör", + "conjunction": " och blogginlägget om ", + "postamble": " och förstår konsekvenserna av att ändra roll.", + "preamble": "Jag har läst ", + "choosingRightDeviceRole": "Att välja rätt enhetsroll", + "deviceRoleDocumentation": "Dokumentation för enhetsroll", + "title": "Är du säker?" + }, + "managedMode": { + "confirmUnderstanding": "Ja, jag vet vad jag gör", + "title": "Är du säker?", + "description": "Aktivering av fjärrhanterat läge blockerar klienter (inklusive webbklienten) från att skriva inställningar till en radio. När detta är aktiverat kan enhetens inställningar endast ändras via fjärradministratörsmeddelanden. Den här inställningen krävs inte för fjärradministration." + }, + "clientNotification": { + "title": "Meddelande från enheten", + "TraceRoute can only be sent once every 30 seconds": "Ruttspårning kan bara skickas en gång per 30 sekunder", + "Compromised keys were detected and regenerated.": "Komprometterade nycklar upptäcktes på enheten och nya har genererats." + }, + "resetNodeDb": { + "title": "Återställ noddatabas", + "description": "Detta kommer att rensa alla noder från den anslutna enhetens noddatabas och rensa all meddelandehistorik i klienten. Detta kan inte ångras. Är du säker på att du vill fortsätta?", + "confirm": "Återställ noddatabas", + "failedTitle": "Det gick inte att återställa noddatabasen. Försök igen." + }, + "clearAllStores": { + "title": "Töm all lokal lagring", + "description": "Detta kommer att rensa all lokalt lagrad data, inklusive meddelandehistorik och noddatabaser för alla tidigare anslutna enheter. Detta kommer att kräva att du återansluter till din nod och kan inte ångras. Är du säker på att du vill fortsätta?", + "confirm": "Töm all lokal lagring", + "failedTitle": "Det gick inte att rensa lokal lagring. Försök igen." + }, + "factoryResetDevice": { + "title": "Fabriksåterställ enhet", + "description": "Detta kommer fabriksåterställa den anslutna enheten, radera alla konfigurationer och data på enheten samt alla noder och meddelanden som sparats i klienten. Detta kan inte ångras. Är du säker på att du vill fortsätta?", + "confirm": "Fabriksåterställ enhet", + "failedTitle": "Det gick inte att utföra fabriksåterställningen. Försök igen." + }, + "factoryResetConfig": { + "title": "Fabriksåterställ konfigurationen", + "description": "Detta kommer fabriksåterställa konfigurationen på den anslutna enheten och radera alla inställningar på enheten. Detta kan inte ångras. Är du säker på att du vill fortsätta?", + "confirm": "Fabriksåterställ konfigurationen", + "failedTitle": "Det gick inte att utföra fabriksåterställningen. Försök igen." + } } diff --git a/packages/web/public/i18n/locales/sv-SE/map.json b/packages/web/public/i18n/locales/sv-SE/map.json new file mode 100644 index 000000000..c28ebec6b --- /dev/null +++ b/packages/web/public/i18n/locales/sv-SE/map.json @@ -0,0 +1,38 @@ +{ + "maplibre": { + "GeolocateControl.FindMyLocation": "Hitta min plats", + "NavigationControl.ZoomIn": "Zooma in", + "NavigationControl.ZoomOut": "Zooma ut", + "CooperativeGesturesHandler.WindowsHelpText": "Använd ctrl + scroll för att zooma kartan", + "CooperativeGesturesHandler.MacHelpText": "Använd ⌘ + scroll för att zooma kartan", + "CooperativeGesturesHandler.MobileHelpText": "Använd två fingrar för att flytta kartan" + }, + "layerTool": { + "nodeMarkers": "Visa noder", + "directNeighbors": "Visa direktanslutningar", + "remoteNeighbors": "Visa fjärranslutningar", + "positionPrecision": "Visa positionens precision", + "traceroutes": "Visa traceroutes", + "waypoints": "Visa vägpunkter" + }, + "mapMenu": { + "locateAria": "Hitta min nod", + "layersAria": "Ändra kartstil" + }, + "waypointDetail": { + "edit": "Ändra", + "description": "Beskrivning:", + "createdBy": "Ändrad av:", + "createdDate": "Skapad:", + "updated": "Uppdaterad:", + "expires": "Löper ut:", + "distance": "Avstånd:", + "bearing": "Absolut bäring:", + "lockedTo": "Låst av:", + "latitude": "Latitud:", + "longitude": "Longitud:" + }, + "myNode": { + "tooltip": "Den här enheten" + } +} diff --git a/packages/web/public/i18n/locales/sv-SE/messages.json b/packages/web/public/i18n/locales/sv-SE/messages.json index bf46becc9..203b600f6 100644 --- a/packages/web/public/i18n/locales/sv-SE/messages.json +++ b/packages/web/public/i18n/locales/sv-SE/messages.json @@ -1,39 +1,39 @@ { - "page": { - "title": "Meddelanden: {{chatName}}", - "placeholder": "Ange meddelande" - }, - "emptyState": { - "title": "Välj en chatt", - "text": "Det finns inga meddelanden ännu." - }, - "selectChatPrompt": { - "text": "Välj en kanal eller nod för att börja chatta." - }, - "sendMessage": { - "placeholder": "Ange ditt meddelande här...", - "sendButton": "Skicka" - }, - "actionsMenu": { - "addReactionLabel": "Lägg till reaktion", - "replyLabel": "Svara" - }, - "deliveryStatus": { - "delivered": { - "label": "Meddelandet har levererats", - "displayText": "Meddelandet har levererats" - }, - "failed": { - "label": "Meddelandeleverans misslyckades", - "displayText": "Leverans misslyckades" - }, - "unknown": { - "label": "Okänd meddelandestatus", - "displayText": "Okänd status" - }, - "waiting": { - "label": "Skickar meddelande", - "displayText": "Väntar på leverans" - } - } + "page": { + "title": "Meddelanden: {{chatName}}", + "placeholder": "Ange meddelande" + }, + "emptyState": { + "title": "Välj en chatt", + "text": "Det finns inga meddelanden ännu." + }, + "selectChatPrompt": { + "text": "Välj en kanal eller nod för att börja chatta." + }, + "sendMessage": { + "placeholder": "Ange ditt meddelande här...", + "sendButton": "Skicka" + }, + "actionsMenu": { + "addReactionLabel": "Lägg till reaktion", + "replyLabel": "Svara" + }, + "deliveryStatus": { + "delivered": { + "label": "Meddelandet har levererats", + "displayText": "Meddelandet har levererats" + }, + "failed": { + "label": "Meddelandeleverans misslyckades", + "displayText": "Leverans misslyckades" + }, + "unknown": { + "label": "Okänd meddelandestatus", + "displayText": "Okänd status" + }, + "waiting": { + "label": "Skickar meddelande", + "displayText": "Väntar på leverans" + } + } } diff --git a/packages/web/public/i18n/locales/sv-SE/moduleConfig.json b/packages/web/public/i18n/locales/sv-SE/moduleConfig.json index f3e498a12..b9d1239a7 100644 --- a/packages/web/public/i18n/locales/sv-SE/moduleConfig.json +++ b/packages/web/public/i18n/locales/sv-SE/moduleConfig.json @@ -1,448 +1,448 @@ { - "page": { - "tabAmbientLighting": "Omgivande belysning", - "tabAudio": "Ljud", - "tabCannedMessage": "Fördefinierade meddelanden", - "tabDetectionSensor": "Detekteringssensor", - "tabExternalNotification": "Extern avisering", - "tabMqtt": "MQTT", - "tabNeighborInfo": "Granninformation", - "tabPaxcounter": "Paxcounter", - "tabRangeTest": "Räckvidd", - "tabSerial": "Seriell kommunikation", - "tabStoreAndForward": "Lagra & vidarebefodra", - "tabTelemetry": "Telemetri" - }, - "ambientLighting": { - "title": "Inställningar för omgivande belysning", - "description": "Inställningar för modulen för omgivande belysning", - "ledState": { - "label": "LED-läge", - "description": "Anger om lysdioden ska vara på eller av" - }, - "current": { - "label": "Ström", - "description": "Ställer in strömmen för LED-utgången. Standardvärdet är 10" - }, - "red": { - "label": "Rött", - "description": "Anger nivån för den röda lysdioden. Värdena är 0-255" - }, - "green": { - "label": "Grönt", - "description": "Anger nivån för den gröna lysdioden. Värdena är 0-255" - }, - "blue": { - "label": "Blått", - "description": "Anger nivån för den blåa lysdioden. Värdena är 0-255" - } - }, - "audio": { - "title": "Ljudinställningar", - "description": "Inställningar för ljudmodulen", - "codec2Enabled": { - "label": "Codec 2 aktiverad", - "description": "Aktivera Codec 2-ljudkodning" - }, - "pttPin": { - "label": "PTT-stift", - "description": "GPIO-stift för PTT" - }, - "bitrate": { - "label": "Bitrate", - "description": "Bitrate att använda för ljudkodning" - }, - "i2sWs": { - "label": "i2S WS", - "description": "GPIO-stift att använda för i2S WS" - }, - "i2sSd": { - "label": "i2S SD", - "description": "GPIO-stift att använda för i2S SD" - }, - "i2sDin": { - "label": "i2S DIN", - "description": "GPIO-stift att använda för i2S DIN" - }, - "i2sSck": { - "label": "i2S SCK", - "description": "GPIO-stift att använda för i2S SCK" - } - }, - "cannedMessage": { - "title": "Inställningar för fördefinierade meddelanden", - "description": "Inställningar för modulen för fördefinierade meddelanden", - "moduleEnabled": { - "label": "Modul aktiverad", - "description": "Aktivera fördefinierade meddelanden" - }, - "rotary1Enabled": { - "label": "Vridomkopplare #1 aktiverad", - "description": "Aktivera vridomkopplare" - }, - "inputbrokerPinA": { - "label": "Vridomkopplarstift A", - "description": "GPIO-stift (1-39) för vridomkopplarens A-stift" - }, - "inputbrokerPinB": { - "label": "Vridomkopplarstift B", - "description": "GPIO-stift (1-39) för vridomkopplarens B-stift" - }, - "inputbrokerPinPress": { - "label": "Vridomkopplarens knappstift", - "description": "GPIO-stift (1-39) för vridomkopplarens knapp-stift" - }, - "inputbrokerEventCw": { - "label": "Medurs inmatningshändelse", - "description": "Välj inmatningshändelse." - }, - "inputbrokerEventCcw": { - "label": "Moturs inmatningshändelse", - "description": "Välj inmatningshändelse." - }, - "inputbrokerEventPress": { - "label": "Inmatningshändelse för tryck", - "description": "Välj inmatningshändelse." - }, - "updown1Enabled": { - "label": "Upp/ned aktiverad", - "description": "Aktivera upp/ner vridomkopplaren" - }, - "allowInputSource": { - "label": "Tillåten inmatningskälla", - "description": "Välj från: '_any', 'rotEnc1', 'upDownEnc1', 'cardkb'" - }, - "sendBell": { - "label": "Skicka klocka", - "description": "Skickar det speciella klock-tecknet med varje meddelande" - } - }, - "detectionSensor": { - "title": "Inställningar för detekteringssensor", - "description": "Inställningar för detekteringssensor-modulen", - "enabled": { - "label": "Aktiverad", - "description": "Aktivera eller inaktivera detekteringssensor-modulen" - }, - "minimumBroadcastSecs": { - "label": "Minsta sändningsintervall", - "description": "Tidsintervall i sekunder hur ofta vi kan skicka ett meddelande till nätet när en tillståndsändring upptäckts" - }, - "stateBroadcastSecs": { - "label": "Högsta sändningsintervall", - "description": "Tidsintervall i sekunder hur ofta vi ska skicka ett meddelande till nätet med nuvarande tillstånd oavsett eventuella förändringar" - }, - "sendBell": { - "label": "Skicka klocka", - "description": "Skicka det speciella klock-tecknet med meddelandet" - }, - "name": { - "label": "Visningsnamn", - "description": "Används för att formatera meddelandet som skickas till nätet, max 20 tecken" - }, - "monitorPin": { - "label": "Stift att övervaka", - "description": "GPIO-stiftet att övervaka för tillståndsändringar" - }, - "detectionTriggerType": { - "label": "Typ för utlösande händelse", - "description": "Typ av utlösande händelse som ska användas" - }, - "usePullup": { - "label": "Använd Pullup", - "description": "Huruvida INPUT_PULLUP-läget ska användas för GPIO-stiftet " - } - }, - "externalNotification": { - "title": "Inställningar för extern avisering", - "description": "Konfigurera modulen för extern avisering", - "enabled": { - "label": "Modul aktiverad", - "description": "Aktivera extern avisering" - }, - "outputMs": { - "label": "Längd", - "description": "Hur länge ska notifikationen vara aktiverad" - }, - "output": { - "label": "Utgång", - "description": "GPIO-stift för utgång" - }, - "outputVibra": { - "label": "Vibrationsutgång", - "description": "GPIO-stift för vibrationsutgång" - }, - "outputBuzzer": { - "label": "Summerutgång", - "description": "GPIO-stift för summerutgång" - }, - "active": { - "label": "Aktiv", - "description": "Aktiv" - }, - "alertMessage": { - "label": "Meddelande-utgång", - "description": "Aktivera utgång när nytt meddelande tas emot" - }, - "alertMessageVibra": { - "label": "Meddelande-vibrationsutgång", - "description": "Aktivera vibrationsutgång när nytt meddelande tas emot" - }, - "alertMessageBuzzer": { - "label": "Meddelande-summer", - "description": "Aktivera summerutgång när nytt meddelande tas emot" - }, - "alertBell": { - "label": "Klock-tecken-utgång", - "description": "Aktivera utgång när ett inkommande meddelande innehåller det speciella klock-tecknet?" - }, - "alertBellVibra": { - "label": "Klock-tecken-vibration", - "description": "Aktivera vibrationsutgång när ett inkommande meddelande innehåller det speciella klock-tecknet" - }, - "alertBellBuzzer": { - "label": "Klock-tecken-summer", - "description": "Aktivera summerutgång när ett inkommande meddelande innehåller det speciella klock-tecknet" - }, - "usePwm": { - "label": "Använd PWM", - "description": "Använd pulsbreddsmodulering (PWM)" - }, - "nagTimeout": { - "label": "Time-out för påminnelse", - "description": "Time-out för påminnelse" - }, - "useI2sAsBuzzer": { - "label": "Använd I²S-stift som summer", - "description": "Ange I²S-stift som summerutgång" - } - }, - "mqtt": { - "title": "MQTT Inställningar", - "description": "Inställningar för MQTT-modulen", - "enabled": { - "label": "Aktiverad", - "description": "Aktivera eller inaktivera MQTT" - }, - "address": { - "label": "MQTT-serveradress", - "description": "MQTT-serveradress att använda för standard/anpassade servrar" - }, - "username": { - "label": "MQTT-användarnamn", - "description": "MQTT-användarnamn att använda för standard/anpassade servrar" - }, - "password": { - "label": "MQTT-lösenord", - "description": "MQTT-lösenord att använda för standard/anpassade servrar" - }, - "encryptionEnabled": { - "label": "Aktivera kryptering ", - "description": "Aktivera eller inaktivera MQTT-kryptering. OBS: Alla meddelanden skickas okrypterade till MQTT-servern om det här alternativet inte är aktiverat, även när dina kanaler med aktiverad MQTT-upplänk har krypteringsnycklar. Detta inkluderar positionsdata." - }, - "jsonEnabled": { - "label": "JSON aktiverat", - "description": "Om du vill skicka/ta emot JSON-paket på MQTT" - }, - "tlsEnabled": { - "label": "TLS aktiverat", - "description": "Aktivera eller inaktivera TLS" - }, - "root": { - "label": "Rotämne (root topic)", - "description": "MQTT rotämne (root topic) att använda för standard/anpassade servrar " - }, - "proxyToClientEnabled": { - "label": "MQTT-klientproxy aktiverad", - "description": "Utnyttja nätverksanslutningen för att vidarebefodra MQTT-meddelanden till klienten." - }, - "mapReportingEnabled": { - "label": "Kartrapportering aktiverad", - "description": "Din nod kommer periodvis skicka ett okrypterat paket till den konfigurerade MQTT-servern som inkluderar id, kort och långt namn, ungefärlig plats, hardvarumodell, enhetsroll, mjukvaru-version, LoRa-region, modeminställning och den primära kanalens namn." - }, - "mapReportSettings": { - "publishIntervalSecs": { - "label": "Intervall för kartrapportering", - "description": "Intervall i sekunder för hur ofta kartrapportering ska ske" - }, - "positionPrecision": { - "label": "Ungefärlig plats", - "description": "Den delade platsen kommer att avrundas till denna noggrannhet", - "options": { - "metric_km23": "Inom 23 km", - "metric_km12": "Inom 12 km", - "metric_km5_8": "Inom 5,8 km", - "metric_km2_9": "Inom 2,9 km", - "metric_km1_5": "Inom 1,5 km", - "metric_m700": "Inom 700 m", - "metric_m350": "Inom 350 m", - "metric_m200": "Inom 200 m", - "metric_m90": "Inom 90 meter", - "metric_m50": "inom 50 m", - "imperial_mi15": "Inom 15 engelska mil", - "imperial_mi7_3": "Inom 7,3 engelska mil", - "imperial_mi3_6": "Inom 3,6 engelska mil", - "imperial_mi1_8": "Inom 1,8 engelska mil", - "imperial_mi0_9": "Inom 0,9 engelska mil", - "imperial_mi0_5": "Inom 0,5 engelska mil", - "imperial_mi0_2": "Inom 0,2 engelska mil", - "imperial_ft600": "Inom 600 fot", - "imperial_ft300": "Inom 300 fot", - "imperial_ft150": "Inom 150 fot" - } - } - } - }, - "neighborInfo": { - "title": "Inställningar för granninformation", - "description": "Inställningar för granninformation-modulen", - "enabled": { - "label": "Aktiverad", - "description": "Aktivera eller inaktivera granninformation-modulen" - }, - "updateInterval": { - "label": "Uppdateringsintervall", - "description": "Intervall i sekunder av hur ofta granninformation ska försöka skickas till nätet" - } - }, - "paxcounter": { - "title": "Inställningar för Paxcounter", - "description": "Inställningar för Paxcounter-modulen", - "enabled": { - "label": "Modul aktiverad", - "description": "Aktivera Paxcounter" - }, - "paxcounterUpdateInterval": { - "label": "Uppdateringsintervall (sekunder)", - "description": "Hur lång tid mellan paxcounter paket skickas" - }, - "wifiThreshold": { - "label": "Tröskelvärde för WiFi RSSI ", - "description": "På vilken WiFi RSSI-nivå ska räknaren öka. Standardvärdet är -80." - }, - "bleThreshold": { - "label": "Tröskelvärde för Bluetooth RSSI ", - "description": "På vilken Bluetooth RSSI-nivå ska räknaren öka. Standardvärdet är -80." - } - }, - "rangeTest": { - "title": "Inställningar för räckviddstest", - "description": "Inställningar för räckviddstest-modulen", - "enabled": { - "label": "Modul aktiverad", - "description": "Aktivera räckviddstest" - }, - "sender": { - "label": "Meddelandeintervall", - "description": "Hur lång tid mellan utsändning av testpaket" - }, - "save": { - "label": "Spara CSV till lagring", - "description": "Spara CSV till enhetens egna flashminne. Endast tillgängligt på ESP32-enheter." - } - }, - "serial": { - "title": "Inställningar för seriell kommunikation", - "description": "Inställningar för den seriella modulen", - "enabled": { - "label": "Modul aktiverad", - "description": "Aktivera seriell utmatning" - }, - "echo": { - "label": "Eko", - "description": "Alla paket du skickar kommer att upprepas tillbaka till din enhet" - }, - "rxd": { - "label": "Stift för mottagning", - "description": "Ställ in GPIO-stift till det RXD-stift du har konfigurerat." - }, - "txd": { - "label": "Stift för sändning", - "description": "Ställ in GPIO-stift till det TXD-stift du har konfigurerat." - }, - "baud": { - "label": "Hastighet", - "description": "Den seriella kommunikationens hastighet" - }, - "timeout": { - "label": "Timeout", - "description": "Tid att vänta innan ditt paket betraktas som \"klart\"." - }, - "mode": { - "label": "Typ", - "description": "Välj typ av paket" - }, - "overrideConsoleSerialPort": { - "label": "Åsidosätt konsolens serieport", - "description": "Om du har en seriell port ansluten till konsolen kommer detta att ersätta den." - } - }, - "storeForward": { - "title": "Inställningar för lagra & vidarebefodra", - "description": "Inställningar för lagra & vidarebefodra-modulen", - "enabled": { - "label": "Modul aktiverad", - "description": "Aktivera lagra & vidarebefodra-modulen" - }, - "heartbeat": { - "label": "Puls aktiverad", - "description": "Aktivera sändning av lagra & vidarebefodra-puls " - }, - "records": { - "label": "Antal poster", - "description": "Antal poster att lagra" - }, - "historyReturnMax": { - "label": "Maxstorlek för historik", - "description": "Maximalt antal poster att returnera" - }, - "historyReturnWindow": { - "label": "Returfönstrets storlek för historik", - "description": "Maximalt antal poster att returnera" - } - }, - "telemetry": { - "title": "Inställningar för telemetri", - "description": "Inställningar för telemetrimodulen", - "deviceUpdateInterval": { - "label": "Enhetens mätvärden", - "description": "Uppdateringsintervall för enhetsdata" - }, - "environmentUpdateInterval": { - "label": "Uppdateringsintervall för miljömätningar", - "description": "" - }, - "environmentMeasurementEnabled": { - "label": "Modul aktiverad", - "description": "Aktivera miljötelemetri" - }, - "environmentScreenEnabled": { - "label": "Visa på display", - "description": "Visa telemetri-värden på OLED-displayen" - }, - "environmentDisplayFahrenheit": { - "label": "Visa Fahrenheit", - "description": "Visa temperatur i Fahrenheit" - }, - "airQualityEnabled": { - "label": "Aktivera luftkvalitet ", - "description": "Aktivera telemetri för luftkvalitet" - }, - "airQualityInterval": { - "label": "Intervall för uppdatering av luftkvalitet", - "description": "Hur ofta att skicka data om luftkvalitet över nätet" - }, - "powerMeasurementEnabled": { - "label": "Effektmätning aktiverad", - "description": "Aktivera telemetri för effektmätning" - }, - "powerUpdateInterval": { - "label": "Intervall för effektuppdatering", - "description": "Hur ofta ska effektdata skickas över nätet" - }, - "powerScreenEnabled": { - "label": "Aktivera strömskärm", - "description": "Aktivera skärmen för strömdata" - } - } + "page": { + "tabAmbientLighting": "Omgivande belysning", + "tabAudio": "Ljud", + "tabCannedMessage": "Fördefinierade meddelanden", + "tabDetectionSensor": "Detekteringssensor", + "tabExternalNotification": "Extern avisering", + "tabMqtt": "MQTT", + "tabNeighborInfo": "Granninformation", + "tabPaxcounter": "Paxcounter", + "tabRangeTest": "Räckvidd", + "tabSerial": "Seriell kommunikation", + "tabStoreAndForward": "Lagra & vidarebefodra", + "tabTelemetry": "Telemetri" + }, + "ambientLighting": { + "title": "Inställningar för omgivande belysning", + "description": "Inställningar för modulen för omgivande belysning", + "ledState": { + "label": "LED-läge", + "description": "Anger om lysdioden ska vara på eller av" + }, + "current": { + "label": "Ström", + "description": "Ställer in strömmen för LED-utgången. Standardvärdet är 10" + }, + "red": { + "label": "Rött", + "description": "Anger nivån för den röda lysdioden. Värdena är 0-255" + }, + "green": { + "label": "Grönt", + "description": "Anger nivån för den gröna lysdioden. Värdena är 0-255" + }, + "blue": { + "label": "Blått", + "description": "Anger nivån för den blåa lysdioden. Värdena är 0-255" + } + }, + "audio": { + "title": "Ljudinställningar", + "description": "Inställningar för ljudmodulen", + "codec2Enabled": { + "label": "Codec 2 aktiverad", + "description": "Aktivera Codec 2-ljudkodning" + }, + "pttPin": { + "label": "PTT-stift", + "description": "GPIO-stift för PTT" + }, + "bitrate": { + "label": "Bitrate", + "description": "Bitrate att använda för ljudkodning" + }, + "i2sWs": { + "label": "i2S WS", + "description": "GPIO-stift att använda för i2S WS" + }, + "i2sSd": { + "label": "i2S SD", + "description": "GPIO-stift att använda för i2S SD" + }, + "i2sDin": { + "label": "i2S DIN", + "description": "GPIO-stift att använda för i2S DIN" + }, + "i2sSck": { + "label": "i2S SCK", + "description": "GPIO-stift att använda för i2S SCK" + } + }, + "cannedMessage": { + "title": "Inställningar för fördefinierade meddelanden", + "description": "Inställningar för modulen för fördefinierade meddelanden", + "moduleEnabled": { + "label": "Modul aktiverad", + "description": "Aktivera fördefinierade meddelanden" + }, + "rotary1Enabled": { + "label": "Vridomkopplare #1 aktiverad", + "description": "Aktivera vridomkopplare" + }, + "inputbrokerPinA": { + "label": "Vridomkopplarstift A", + "description": "GPIO-stift (1-39) för vridomkopplarens A-stift" + }, + "inputbrokerPinB": { + "label": "Vridomkopplarstift B", + "description": "GPIO-stift (1-39) för vridomkopplarens B-stift" + }, + "inputbrokerPinPress": { + "label": "Vridomkopplarens knappstift", + "description": "GPIO-stift (1-39) för vridomkopplarens knapp-stift" + }, + "inputbrokerEventCw": { + "label": "Medurs inmatningshändelse", + "description": "Välj inmatningshändelse." + }, + "inputbrokerEventCcw": { + "label": "Moturs inmatningshändelse", + "description": "Välj inmatningshändelse." + }, + "inputbrokerEventPress": { + "label": "Inmatningshändelse för tryck", + "description": "Välj inmatningshändelse." + }, + "updown1Enabled": { + "label": "Upp/ned aktiverad", + "description": "Aktivera upp/ner vridomkopplaren" + }, + "allowInputSource": { + "label": "Tillåten inmatningskälla", + "description": "Välj från: '_any', 'rotEnc1', 'upDownEnc1', 'cardkb'" + }, + "sendBell": { + "label": "Skicka klocka", + "description": "Skickar det speciella klock-tecknet med varje meddelande" + } + }, + "detectionSensor": { + "title": "Inställningar för detekteringssensor", + "description": "Inställningar för detekteringssensor-modulen", + "enabled": { + "label": "Aktiverad", + "description": "Aktivera eller inaktivera detekteringssensor-modulen" + }, + "minimumBroadcastSecs": { + "label": "Minsta sändningsintervall", + "description": "Tidsintervall i sekunder hur ofta vi kan skicka ett meddelande till nätet när en tillståndsändring upptäckts" + }, + "stateBroadcastSecs": { + "label": "Högsta sändningsintervall", + "description": "Tidsintervall i sekunder hur ofta vi ska skicka ett meddelande till nätet med nuvarande tillstånd oavsett eventuella förändringar" + }, + "sendBell": { + "label": "Skicka klocka", + "description": "Skicka det speciella klock-tecknet med meddelandet" + }, + "name": { + "label": "Visningsnamn", + "description": "Används för att formatera meddelandet som skickas till nätet, max 20 tecken" + }, + "monitorPin": { + "label": "Stift att övervaka", + "description": "GPIO-stiftet att övervaka för tillståndsändringar" + }, + "detectionTriggerType": { + "label": "Typ för utlösande händelse", + "description": "Typ av utlösande händelse som ska användas" + }, + "usePullup": { + "label": "Använd Pullup", + "description": "Huruvida INPUT_PULLUP-läget ska användas för GPIO-stiftet " + } + }, + "externalNotification": { + "title": "Inställningar för extern avisering", + "description": "Konfigurera modulen för extern avisering", + "enabled": { + "label": "Modul aktiverad", + "description": "Aktivera extern avisering" + }, + "outputMs": { + "label": "Längd", + "description": "Hur länge ska notifikationen vara aktiverad" + }, + "output": { + "label": "Utgång", + "description": "GPIO-stift för utgång" + }, + "outputVibra": { + "label": "Vibrationsutgång", + "description": "GPIO-stift för vibrationsutgång" + }, + "outputBuzzer": { + "label": "Summerutgång", + "description": "GPIO-stift för summerutgång" + }, + "active": { + "label": "Aktiv", + "description": "Aktiv" + }, + "alertMessage": { + "label": "Meddelande-utgång", + "description": "Aktivera utgång när nytt meddelande tas emot" + }, + "alertMessageVibra": { + "label": "Meddelande-vibrationsutgång", + "description": "Aktivera vibrationsutgång när nytt meddelande tas emot" + }, + "alertMessageBuzzer": { + "label": "Meddelande-summer", + "description": "Aktivera summerutgång när nytt meddelande tas emot" + }, + "alertBell": { + "label": "Klock-tecken-utgång", + "description": "Aktivera utgång när ett inkommande meddelande innehåller det speciella klock-tecknet?" + }, + "alertBellVibra": { + "label": "Klock-tecken-vibration", + "description": "Aktivera vibrationsutgång när ett inkommande meddelande innehåller det speciella klock-tecknet" + }, + "alertBellBuzzer": { + "label": "Klock-tecken-summer", + "description": "Aktivera summerutgång när ett inkommande meddelande innehåller det speciella klock-tecknet" + }, + "usePwm": { + "label": "Använd PWM", + "description": "Använd pulsbreddsmodulering (PWM)" + }, + "nagTimeout": { + "label": "Time-out för påminnelse", + "description": "Time-out för påminnelse" + }, + "useI2sAsBuzzer": { + "label": "Använd I²S-stift som summer", + "description": "Ange I²S-stift som summerutgång" + } + }, + "mqtt": { + "title": "MQTT Inställningar", + "description": "Inställningar för MQTT-modulen", + "enabled": { + "label": "Aktiverad", + "description": "Aktivera eller inaktivera MQTT" + }, + "address": { + "label": "MQTT-serveradress", + "description": "MQTT-serveradress att använda för standard/anpassade servrar" + }, + "username": { + "label": "MQTT-användarnamn", + "description": "MQTT-användarnamn att använda för standard/anpassade servrar" + }, + "password": { + "label": "MQTT-lösenord", + "description": "MQTT-lösenord att använda för standard/anpassade servrar" + }, + "encryptionEnabled": { + "label": "Aktivera kryptering ", + "description": "Aktivera eller inaktivera MQTT-kryptering. OBS: Alla meddelanden skickas okrypterade till MQTT-servern om det här alternativet inte är aktiverat, även när dina kanaler med aktiverad MQTT-upplänk har krypteringsnycklar. Detta inkluderar positionsdata." + }, + "jsonEnabled": { + "label": "JSON aktiverat", + "description": "Om du vill skicka/ta emot JSON-paket på MQTT" + }, + "tlsEnabled": { + "label": "TLS aktiverat", + "description": "Aktivera eller inaktivera TLS" + }, + "root": { + "label": "Rotämne (root topic)", + "description": "MQTT rotämne (root topic) att använda för standard/anpassade servrar " + }, + "proxyToClientEnabled": { + "label": "MQTT-klientproxy aktiverad", + "description": "Utnyttja nätverksanslutningen för att vidarebefodra MQTT-meddelanden till klienten." + }, + "mapReportingEnabled": { + "label": "Kartrapportering aktiverad", + "description": "Din nod kommer periodvis skicka ett okrypterat paket till den konfigurerade MQTT-servern som inkluderar id, kort och långt namn, ungefärlig plats, hardvarumodell, enhetsroll, mjukvaru-version, LoRa-region, modeminställning och den primära kanalens namn." + }, + "mapReportSettings": { + "publishIntervalSecs": { + "label": "Intervall för kartrapportering", + "description": "Intervall i sekunder för hur ofta kartrapportering ska ske" + }, + "positionPrecision": { + "label": "Ungefärlig plats", + "description": "Den delade platsen kommer att avrundas till denna noggrannhet", + "options": { + "metric_km23": "Inom 23 km", + "metric_km12": "Inom 12 km", + "metric_km5_8": "Inom 5,8 km", + "metric_km2_9": "Inom 2,9 km", + "metric_km1_5": "Inom 1,5 km", + "metric_m700": "Inom 700 m", + "metric_m350": "Inom 350 m", + "metric_m200": "Inom 200 m", + "metric_m90": "Inom 90 meter", + "metric_m50": "inom 50 m", + "imperial_mi15": "Inom 15 engelska mil", + "imperial_mi7_3": "Inom 7,3 engelska mil", + "imperial_mi3_6": "Inom 3,6 engelska mil", + "imperial_mi1_8": "Inom 1,8 engelska mil", + "imperial_mi0_9": "Inom 0,9 engelska mil", + "imperial_mi0_5": "Inom 0,5 engelska mil", + "imperial_mi0_2": "Inom 0,2 engelska mil", + "imperial_ft600": "Inom 600 fot", + "imperial_ft300": "Inom 300 fot", + "imperial_ft150": "Inom 150 fot" + } + } + } + }, + "neighborInfo": { + "title": "Inställningar för granninformation", + "description": "Inställningar för granninformation-modulen", + "enabled": { + "label": "Aktiverad", + "description": "Aktivera eller inaktivera granninformation-modulen" + }, + "updateInterval": { + "label": "Uppdateringsintervall", + "description": "Intervall i sekunder av hur ofta granninformation ska försöka skickas till nätet" + } + }, + "paxcounter": { + "title": "Inställningar för Paxcounter", + "description": "Inställningar för Paxcounter-modulen", + "enabled": { + "label": "Modul aktiverad", + "description": "Aktivera Paxcounter" + }, + "paxcounterUpdateInterval": { + "label": "Uppdateringsintervall (sekunder)", + "description": "Hur lång tid mellan paxcounter paket skickas" + }, + "wifiThreshold": { + "label": "Tröskelvärde för WiFi RSSI ", + "description": "På vilken WiFi RSSI-nivå ska räknaren öka. Standardvärdet är -80." + }, + "bleThreshold": { + "label": "Tröskelvärde för Bluetooth RSSI ", + "description": "På vilken Bluetooth RSSI-nivå ska räknaren öka. Standardvärdet är -80." + } + }, + "rangeTest": { + "title": "Inställningar för räckviddstest", + "description": "Inställningar för räckviddstest-modulen", + "enabled": { + "label": "Modul aktiverad", + "description": "Aktivera räckviddstest" + }, + "sender": { + "label": "Meddelandeintervall", + "description": "Hur lång tid mellan utsändning av testpaket" + }, + "save": { + "label": "Spara CSV till lagring", + "description": "Spara CSV till enhetens egna flashminne. Endast tillgängligt på ESP32-enheter." + } + }, + "serial": { + "title": "Inställningar för seriell kommunikation", + "description": "Inställningar för den seriella modulen", + "enabled": { + "label": "Modul aktiverad", + "description": "Aktivera seriell utmatning" + }, + "echo": { + "label": "Eko", + "description": "Alla paket du skickar kommer att upprepas tillbaka till din enhet" + }, + "rxd": { + "label": "Stift för mottagning", + "description": "Ställ in GPIO-stift till det RXD-stift du har konfigurerat." + }, + "txd": { + "label": "Stift för sändning", + "description": "Ställ in GPIO-stift till det TXD-stift du har konfigurerat." + }, + "baud": { + "label": "Hastighet", + "description": "Den seriella kommunikationens hastighet" + }, + "timeout": { + "label": "Timeout", + "description": "Tid att vänta innan ditt paket betraktas som \"klart\"." + }, + "mode": { + "label": "Typ", + "description": "Välj typ av paket" + }, + "overrideConsoleSerialPort": { + "label": "Åsidosätt konsolens serieport", + "description": "Om du har en seriell port ansluten till konsolen kommer detta att ersätta den." + } + }, + "storeForward": { + "title": "Inställningar för lagra & vidarebefodra", + "description": "Inställningar för lagra & vidarebefodra-modulen", + "enabled": { + "label": "Modul aktiverad", + "description": "Aktivera lagra & vidarebefodra-modulen" + }, + "heartbeat": { + "label": "Puls aktiverad", + "description": "Aktivera sändning av lagra & vidarebefodra-puls " + }, + "records": { + "label": "Antal poster", + "description": "Antal poster att lagra" + }, + "historyReturnMax": { + "label": "Maxstorlek för historik", + "description": "Maximalt antal poster att returnera" + }, + "historyReturnWindow": { + "label": "Returfönstrets storlek för historik", + "description": "Returnera poster från detta tidsfönster (minuter)" + } + }, + "telemetry": { + "title": "Inställningar för telemetri", + "description": "Inställningar för telemetrimodulen", + "deviceUpdateInterval": { + "label": "Enhetens mätvärden", + "description": "Uppdateringsintervall för enhetsdata" + }, + "environmentUpdateInterval": { + "label": "Uppdateringsintervall för miljömätningar", + "description": "" + }, + "environmentMeasurementEnabled": { + "label": "Modul aktiverad", + "description": "Aktivera miljötelemetri" + }, + "environmentScreenEnabled": { + "label": "Visa på display", + "description": "Visa telemetri-värden på OLED-displayen" + }, + "environmentDisplayFahrenheit": { + "label": "Visa Fahrenheit", + "description": "Visa temperatur i Fahrenheit" + }, + "airQualityEnabled": { + "label": "Aktivera luftkvalitet ", + "description": "Aktivera telemetri för luftkvalitet" + }, + "airQualityInterval": { + "label": "Intervall för uppdatering av luftkvalitet", + "description": "Hur ofta att skicka data om luftkvalitet över nätet" + }, + "powerMeasurementEnabled": { + "label": "Effektmätning aktiverad", + "description": "Aktivera telemetri för effektmätning" + }, + "powerUpdateInterval": { + "label": "Intervall för effektuppdatering", + "description": "Hur ofta ska effektdata skickas över nätet" + }, + "powerScreenEnabled": { + "label": "Aktivera strömskärm", + "description": "Aktivera skärmen för strömdata" + } + } } diff --git a/packages/web/public/i18n/locales/sv-SE/nodes.json b/packages/web/public/i18n/locales/sv-SE/nodes.json index 659c41be9..119e0eaad 100644 --- a/packages/web/public/i18n/locales/sv-SE/nodes.json +++ b/packages/web/public/i18n/locales/sv-SE/nodes.json @@ -1,63 +1,59 @@ { - "nodeDetail": { - "publicKeyEnabled": { - "label": "Publik nyckel aktiverad" - }, - "noPublicKey": { - "label": "Publik nyckel saknas" - }, - "directMessage": { - "label": "Direktmeddelande {{shortName}}" - }, - "favorite": { - "label": "Favorit", - "tooltip": "Lägg till eller ta bort den här noden från dina favoriter" - }, - "notFavorite": { - "label": "Inte en favorit" - }, - "error": { - "label": "Fel", - "text": "Ett fel inträffade vid hämtning av nodens detaljer. Försök igen senare." - }, - "status": { - "heard": "Hörd", - "mqtt": "MQTT" - }, - "elevation": { - "label": "Höjd" - }, - "channelUtil": { - "label": "Kanalutnyttjande" - }, - "airtimeUtil": { - "label": "Sändningstidsutnyttjande" - } - }, - "nodesTable": { - "headings": { - "longName": "Långt namn", - "connection": "Anslutning", - "lastHeard": "Senast hörd", - "encryption": "Kryptering", - "model": "Modell", - "macAddress": "MAC-adress" - }, - "connectionStatus": { - "direct": "Direkt", - "away": "bort", - "unknown": "-", - "viaMqtt": ", via MQTT" - }, - "lastHeardStatus": { - "never": "Aldrig" - } - }, - "actions": { - "added": "Tillagd", - "removed": "Borttagen", - "ignoreNode": "Ignorera nod", - "unignoreNode": "Ta bort ignorering", - "requestPosition": "Begär plats" - } + "nodeDetail": { + "publicKeyEnabled": { + "label": "Publik nyckel aktiverad" + }, + "noPublicKey": { + "label": "Publik nyckel saknas" + }, + "directMessage": { + "label": "Direktmeddelande {{shortName}}" + }, + "favorite": { + "label": "Favorit", + "tooltip": "Lägg till eller ta bort den här noden från dina favoriter" + }, + "notFavorite": { + "label": "Inte en favorit" + }, + "error": { + "label": "Fel", + "text": "Ett fel inträffade vid hämtning av nodens detaljer. Försök igen senare." + }, + "status": { + "heard": "Hörd", + "mqtt": "MQTT" + }, + "elevation": { + "label": "Höjd" + }, + "channelUtil": { + "label": "Kanalutnyttjande" + }, + "airtimeUtil": { + "label": "Sändningstidsutnyttjande" + } + }, + "nodesTable": { + "headings": { + "longName": "Långt namn", + "connection": "Anslutning", + "lastHeard": "Senast hörd", + "encryption": "Kryptering", + "model": "Modell", + "macAddress": "MAC-adress" + }, + "connectionStatus": { + "direct": "Direkt", + "away": "bort", + "viaMqtt": ", via MQTT" + } + }, + "actions": { + "added": "Tillagd", + "removed": "Borttagen", + "ignoreNode": "Ignorera nod", + "unignoreNode": "Ta bort ignorering", + "requestPosition": "Begär plats" + } } diff --git a/packages/web/public/i18n/locales/sv-SE/ui.json b/packages/web/public/i18n/locales/sv-SE/ui.json index a76914e77..44e25cb9c 100644 --- a/packages/web/public/i18n/locales/sv-SE/ui.json +++ b/packages/web/public/i18n/locales/sv-SE/ui.json @@ -1,228 +1,230 @@ { - "navigation": { - "title": "Navigering", - "messages": "Meddelanden", - "map": "Karta", - "config": "Inställningar", - "radioConfig": "Radioinställningar", - "moduleConfig": "Modulinställningar", - "channels": "Kanaler", - "nodes": "Noder" - }, - "app": { - "title": "Meshtastic", - "logo": "Meshtastic logotyp" - }, - "sidebar": { - "collapseToggle": { - "button": { - "open": "Öppna sidopanel", - "close": "Stäng sidopanel" - } - }, - "deviceInfo": { - "volts": "{{voltage}} volt", - "firmware": { - "title": "Firmware", - "version": "v{{version}}", - "buildDate": "Kompileringsdatum: {{date}}" - }, - "deviceName": { - "title": "Enhetsnamn", - "changeName": "Ändra enhetens namn", - "placeholder": "Ange enhetsnamn" - }, - "editDeviceName": "Redigera enhetsnamn" - } - }, - "batteryStatus": { - "charging": "{{level}}%, laddar", - "pluggedIn": "Ansluten", - "title": "Batteri" - }, - "search": { - "nodes": "Sök noder...", - "channels": "Sök kanaler...", - "commandPalette": "Sök kommandon..." - }, - "toast": { - "positionRequestSent": { - "title": "Platsbegäran skickad." - }, - "requestingPosition": { - "title": "Begär plats, var god vänta..." - }, - "sendingTraceroute": { - "title": "Skickar Traceroute (spåra rutt), vänligen vänta..." - }, - "tracerouteSent": { - "title": "Traceroute (spåra rutt) skickat.." - }, - "savedChannel": { - "title": "Sparat kanal: {{channelName}}" - }, - "messages": { - "pkiEncryption": { - "title": "Chatten använder PKI-kryptering." - }, - "pskEncryption": { - "title": "Chatten använder PSK-kryptering." - } - }, - "configSaveError": { - "title": "Kunde inte spara inställningarna", - "description": "Ett fel inträffade när inställningarna sparades." - }, - "validationError": { - "title": "Det förekommer inställningsfel", - "description": "Vänligen åtgärda felen i inställningarna innan du sparar." - }, - "saveSuccess": { - "title": "Sparar inställningarna", - "description": "Ändrignarna av {{case}}-inställningarna har sparats." - }, - "favoriteNode": { - "title": "{{action}} {{nodeName}} {{direction}} dina favoriter.", - "action": { - "added": "La till", - "removed": "Tog bort", - "to": "till", - "from": "från" - } - }, - "ignoreNode": { - "title": "{{action}} {{nodeName}} {{direction}} dina ignorerade noder", - "action": { - "added": "La till", - "removed": "Tog bort", - "to": "till", - "from": "från" - } - } - }, - "notifications": { - "copied": { - "label": "Kopierat!" - }, - "copyToClipboard": { - "label": "Kopiera till Urklipp" - }, - "hidePassword": { - "label": "Dölj lösenord" - }, - "showPassword": { - "label": "Visa lösenord" - }, - "deliveryStatus": { - "delivered": "Levererad", - "failed": "Leverans misslyckades", - "waiting": "Väntar", - "unknown": "Okänd" - } - }, - "general": { - "label": "Allmänt" - }, - "hardware": { - "label": "Hårdvara" - }, - "metrics": { - "label": "Telemetri" - }, - "role": { - "label": "Roll" - }, - "filter": { - "label": "Filter" - }, - "advanced": { - "label": "Advancerat" - }, - "clearInput": { - "label": "Rensa inmatning" - }, - "resetFilters": { - "label": "Återställ filter" - }, - "nodeName": { - "label": "Nodnamn/nummer", - "placeholder": "Meshtastic 1234" - }, - "airtimeUtilization": { - "label": "Sändningstidsutnyttjande (%)" - }, - "batteryLevel": { - "label": "Batterinivå (%)", - "labelText": "Batterinivå (%): {{value}}" - }, - "batteryVoltage": { - "label": "Batterispänning (V)", - "title": "Spänning" - }, - "channelUtilization": { - "label": "Kanalutnyttjande (%)" - }, - "hops": { - "direct": "Direkt", - "label": "Antal hopp", - "text": "Antal hopp: {{value}}" - }, - "lastHeard": { - "label": "Senast hörd", - "labelText": "Senast hörd: {{value}}", - "nowLabel": "Nu" - }, - "snr": { - "label": "SNR (db)" - }, - "favorites": { - "label": "Favoriter" - }, - "hide": { - "label": "Dölj" - }, - "showOnly": { - "label": "Visa endast" - }, - "viaMqtt": { - "label": "Ansluten via MQTT" - }, - "hopsUnknown": { - "label": "Okänt antal hopp" - }, - "showUnheard": { - "label": "Aldrig hörd" - }, - "language": { - "label": "Språk", - "changeLanguage": "Byt språk" - }, - "theme": { - "dark": "Mörkt", - "light": "Ljust", - "system": "Automatisk", - "changeTheme": "Ändra färgschema" - }, - "errorPage": { - "title": "Det här är lite pinsamt...", - "description1": "Vi är verkligen ledsna men ett fel inträffade i webbklienten som fick den att krascha.
Detta var inte meningen, men vi arbetar hårt för att åtgärda det.", - "description2": "Det bästa sättet att förhindra att detta händer igen för dig eller någon annan är att rapportera problemet till oss.", - "reportInstructions": "Vänligen inkludera följande information i din rapport:", - "reportSteps": { - "step1": "Vad du gjorde när felet inträffade", - "step2": "Vad du förväntade dig skulle hända", - "step3": "Vad som faktiskt hände", - "step4": "All annan relevant information" - }, - "reportLink": "Du kan rapportera problemet på vår <0>GitHub", - "dashboardLink": "Återvänd till <0>start", - "detailsSummary": "Detaljer om felet", - "errorMessageLabel": "Felmeddelande:", - "stackTraceLabel": "Stackspårning:", - "fallbackError": "{{error}}" - }, - "footer": { - "text": "Drivs av <0>▲ Vercel | Meshtastic® är ett registrerat varumärke som tillhör Meshtastic LLC. | <1>Juridisk information", - "commitSha": "Commit SHA: {{sha}}" - } + "navigation": { + "title": "Navigering", + "messages": "Meddelanden", + "map": "Karta", + "settings": "Inställningar", + "channels": "Kanaler", + "radioConfig": "Radioinställningar", + "deviceConfig": "Enhetskonfiguration", + "moduleConfig": "Modulinställningar", + "manageConnections": "Hantera anslutningar", + "nodes": "Noder" + }, + "app": { + "title": "Meshtastic", + "logo": "Meshtastic logotyp" + }, + "sidebar": { + "collapseToggle": { + "button": { + "open": "Öppna sidopanel", + "close": "Stäng sidopanel" + } + }, + "deviceInfo": { + "volts": "{{voltage}} volt", + "firmware": { + "title": "Firmware", + "version": "v{{version}}", + "buildDate": "Kompileringsdatum: {{date}}" + } + } + }, + "batteryStatus": { + "charging": "{{level}}%, laddar", + "pluggedIn": "Ansluten", + "title": "Batteri" + }, + "search": { + "nodes": "Sök noder...", + "channels": "Sök kanaler...", + "commandPalette": "Sök kommandon..." + }, + "toast": { + "positionRequestSent": { + "title": "Platsbegäran skickad." + }, + "requestingPosition": { + "title": "Begär plats, var god vänta..." + }, + "sendingTraceroute": { + "title": "Skickar Traceroute (spåra rutt), vänligen vänta..." + }, + "tracerouteSent": { + "title": "Traceroute (spåra rutt) skickat.." + }, + "savedChannel": { + "title": "Sparat kanal: {{channelName}}" + }, + "messages": { + "pkiEncryption": { + "title": "Chatten använder PKI-kryptering." + }, + "pskEncryption": { + "title": "Chatten använder PSK-kryptering." + } + }, + "configSaveError": { + "title": "Kunde inte spara inställningarna", + "description": "Ett fel inträffade när inställningarna sparades." + }, + "validationError": { + "title": "Det förekommer inställningsfel", + "description": "Vänligen åtgärda felen i inställningarna innan du sparar." + }, + "saveSuccess": { + "title": "Sparar inställningarna", + "description": "Ändrignarna av {{case}}-inställningarna har sparats." + }, + "saveAllSuccess": { + "title": "Sparat", + "description": "Alla konfigurationsändringar har sparats." + }, + "favoriteNode": { + "title": "{{action}} {{nodeName}} {{direction}} dina favoriter.", + "action": { + "added": "La till", + "removed": "Tog bort", + "to": "till", + "from": "från" + } + }, + "ignoreNode": { + "title": "{{action}} {{nodeName}} {{direction}} dina ignorerade noder", + "action": { + "added": "La till", + "removed": "Tog bort", + "to": "till", + "from": "från" + } + } + }, + "notifications": { + "copied": { + "label": "Kopierat!" + }, + "copyToClipboard": { + "label": "Kopiera till Urklipp" + }, + "hidePassword": { + "label": "Dölj lösenord" + }, + "showPassword": { + "label": "Visa lösenord" + }, + "deliveryStatus": { + "delivered": "Levererad", + "failed": "Leverans misslyckades", + "waiting": "Väntar", + "unknown": "Okänd" + } + }, + "general": { + "label": "Allmänt" + }, + "hardware": { + "label": "Hårdvara" + }, + "metrics": { + "label": "Telemetri" + }, + "role": { + "label": "Roll" + }, + "filter": { + "label": "Filter" + }, + "advanced": { + "label": "Advancerat" + }, + "clearInput": { + "label": "Rensa inmatning" + }, + "resetFilters": { + "label": "Återställ filter" + }, + "nodeName": { + "label": "Nodnamn/nummer", + "placeholder": "Meshtastic 1234" + }, + "airtimeUtilization": { + "label": "Sändningstidsutnyttjande (%)", + "short": "Sändningstidsutnyttjande (%)" + }, + "batteryLevel": { + "label": "Batterinivå (%)", + "labelText": "Batterinivå (%): {{value}}" + }, + "batteryVoltage": { + "label": "Batterispänning (V)", + "title": "Spänning" + }, + "channelUtilization": { + "label": "Kanalutnyttjande (%)", + "short": "Kanalutnyttjande (%)" + }, + "hops": { + "direct": "Direkt", + "label": "Antal hopp", + "text": "Antal hopp: {{value}}" + }, + "lastHeard": { + "label": "Senast hörd", + "labelText": "Senast hörd: {{value}}", + "nowLabel": "Nu" + }, + "snr": { + "label": "SNR (db)" + }, + "favorites": { + "label": "Favoriter" + }, + "hide": { + "label": "Dölj" + }, + "showOnly": { + "label": "Visa endast" + }, + "viaMqtt": { + "label": "Ansluten via MQTT" + }, + "hopsUnknown": { + "label": "Okänt antal hopp" + }, + "showUnheard": { + "label": "Senast hörd okänt" + }, + "language": { + "label": "Språk", + "changeLanguage": "Byt språk" + }, + "theme": { + "dark": "Mörkt", + "light": "Ljust", + "system": "Automatisk", + "changeTheme": "Ändra färgschema" + }, + "errorPage": { + "title": "Det här är lite pinsamt...", + "description1": "Vi är verkligen ledsna men ett fel inträffade i webbklienten som fick den att krascha.
Detta var inte meningen, men vi arbetar hårt för att åtgärda det.", + "description2": "Det bästa sättet att förhindra att detta händer igen för dig eller någon annan är att rapportera problemet till oss.", + "reportInstructions": "Vänligen inkludera följande information i din rapport:", + "reportSteps": { + "step1": "Vad du gjorde när felet inträffade", + "step2": "Vad du förväntade dig skulle hända", + "step3": "Vad som faktiskt hände", + "step4": "All annan relevant information" + }, + "reportLink": "Du kan rapportera problemet på vår <0>GitHub", + "connectionsLink": "Återgå till <0>-anslutningarna", + "detailsSummary": "Detaljer om felet", + "errorMessageLabel": "Felmeddelande:", + "stackTraceLabel": "Stackspårning:", + "fallbackError": "{{error}}" + }, + "footer": { + "text": "Drivs av <0>▲ Vercel | Meshtastic® är ett registrerat varumärke som tillhör Meshtastic LLC. | <1>Juridisk information", + "commitSha": "Commit SHA: {{sha}}" + } } diff --git a/packages/web/public/i18n/locales/tr-TR/channels.json b/packages/web/public/i18n/locales/tr-TR/channels.json index 04d918717..910b6cff6 100644 --- a/packages/web/public/i18n/locales/tr-TR/channels.json +++ b/packages/web/public/i18n/locales/tr-TR/channels.json @@ -1,69 +1,71 @@ { - "page": { - "sectionLabel": "Kanallar", - "channelName": "Kanal: {{channelName}}", - "broadcastLabel": "Birincil", - "channelIndex": "Ch {{index}}" - }, - "validation": { - "pskInvalid": "Lütfen geçerli bir {{bits}} bit PSK girin." - }, - "settings": { - "label": "Kanal Ayarları", - "description": "Kripto ve MQTT genel ayarları" - }, - "role": { - "label": "Rol", - "description": "Cihaz telemetrisi BİRİNCİL üzerinden gönderildi. Sadece bir BİRİNCİL izin verilir", - "options": { - "primary": "BİRİNCİL", - "disabled": "DEVRE DIŞI", - "secondary": "İKİNCİL" - } - }, - "psk": { - "label": "Paylaşılan Anahtar", - "description": "Desteklenen PSK uzunlukları: 256 bit, 128 bit, 8 bit, Boş (0 bit)", - "generate": "Oluştur" - }, - "name": { - "label": "İsmi", - "description": "12 bayt'tan küçük kanal için benzersiz bir ad, varsayılan olarak boş bırakın" - }, - "uplinkEnabled": { - "label": "Uplink Etkin", - "description": "Yerel ağdan MQTT'ye mesaj gönderin" - }, - "downlinkEnabled": { - "label": "Downlink Etkin", - "description": "MQTT'den yerel mesh ağa mesaj gönderin" - }, - "positionPrecision": { - "label": "Konum", - "description": "Kanalla paylaşılacak konumun kesinliği. Devre dışı bırakılabilir.", - "options": { - "none": "Konumu paylaşma", - "precise": "Tam Konum", - "metric_km23": "23 kilometre içinde", - "metric_km12": "12 kilometre içinde", - "metric_km5_8": "5,8 kilometre içinde", - "metric_km2_9": "2,9 kilometre içinde", - "metric_km1_5": "1,5 kilometre içinde", - "metric_m700": "700 metre içinde", - "metric_m350": "350 metre içinde", - "metric_m200": "200 metre içinde", - "metric_m90": "90 metre içinde", - "metric_m50": "50 metre içinde", - "imperial_mi15": "15 mil içinde", - "imperial_mi7_3": "7,3 mil içinde", - "imperial_mi3_6": "3,6 mil içinde", - "imperial_mi1_8": "1,8 mil içinde", - "imperial_mi0_9": "0,9 mil içinde", - "imperial_mi0_5": "0,5 mil içinde", - "imperial_mi0_2": "0,2 mil içinde", - "imperial_ft600": "600 fit içinde", - "imperial_ft300": "300 fit içinde", - "imperial_ft150": "150 fit içinde" - } - } + "page": { + "sectionLabel": "Kanallar", + "channelName": "Kanal: {{channelName}}", + "broadcastLabel": "Birincil", + "channelIndex": "Ch {{index}}", + "import": "İçeri aktar", + "export": "Dışa Aktar" + }, + "validation": { + "pskInvalid": "Lütfen geçerli bir {{bits}} bit PSK girin." + }, + "settings": { + "label": "Kanal Ayarları", + "description": "Kripto ve MQTT genel ayarları" + }, + "role": { + "label": "Rol", + "description": "Cihaz telemetrisi BİRİNCİL üzerinden gönderildi. Sadece bir BİRİNCİL izin verilir", + "options": { + "primary": "BİRİNCİL", + "disabled": "DEVRE DIŞI", + "secondary": "İKİNCİL" + } + }, + "psk": { + "label": "Paylaşılan Anahtar", + "description": "Desteklenen PSK uzunlukları: 256 bit, 128 bit, 8 bit, Boş (0 bit)", + "generate": "Oluştur" + }, + "name": { + "label": "İsmi", + "description": "12 bayt'tan küçük kanal için benzersiz bir ad, varsayılan olarak boş bırakın" + }, + "uplinkEnabled": { + "label": "Uplink Etkin", + "description": "Yerel ağdan MQTT'ye mesaj gönderin" + }, + "downlinkEnabled": { + "label": "Downlink Etkin", + "description": "MQTT'den yerel mesh ağa mesaj gönderin" + }, + "positionPrecision": { + "label": "Konum", + "description": "Kanalla paylaşılacak konumun kesinliği. Devre dışı bırakılabilir.", + "options": { + "none": "Konumu paylaşma", + "precise": "Tam Konum", + "metric_km23": "23 kilometre içinde", + "metric_km12": "12 kilometre içinde", + "metric_km5_8": "5,8 kilometre içinde", + "metric_km2_9": "2,9 kilometre içinde", + "metric_km1_5": "1,5 kilometre içinde", + "metric_m700": "700 metre içinde", + "metric_m350": "350 metre içinde", + "metric_m200": "200 metre içinde", + "metric_m90": "90 metre içinde", + "metric_m50": "50 metre içinde", + "imperial_mi15": "15 mil içinde", + "imperial_mi7_3": "7,3 mil içinde", + "imperial_mi3_6": "3,6 mil içinde", + "imperial_mi1_8": "1,8 mil içinde", + "imperial_mi0_9": "0,9 mil içinde", + "imperial_mi0_5": "0,5 mil içinde", + "imperial_mi0_2": "0,2 mil içinde", + "imperial_ft600": "600 fit içinde", + "imperial_ft300": "300 fit içinde", + "imperial_ft150": "150 fit içinde" + } + } } diff --git a/packages/web/public/i18n/locales/tr-TR/commandPalette.json b/packages/web/public/i18n/locales/tr-TR/commandPalette.json index e77bf380f..f6b7353ab 100644 --- a/packages/web/public/i18n/locales/tr-TR/commandPalette.json +++ b/packages/web/public/i18n/locales/tr-TR/commandPalette.json @@ -15,7 +15,6 @@ "messages": "Mesajlar", "map": "Harita", "config": "Yapılandır", - "channels": "Kanallar", "nodes": "Düğümler" } }, @@ -45,7 +44,8 @@ "label": "Hata Ayıklama", "command": { "reconfigure": "Yeniden yapılandır", - "clearAllStoredMessages": "Depolanan Tüm Mesajları Sil" + "clearAllStoredMessages": "Depolanan Tüm Mesajları Sil", + "clearAllStores": "Clear All Local Storage" } } } diff --git a/packages/web/public/i18n/locales/tr-TR/common.json b/packages/web/public/i18n/locales/tr-TR/common.json index 8458153de..1583ed22d 100644 --- a/packages/web/public/i18n/locales/tr-TR/common.json +++ b/packages/web/public/i18n/locales/tr-TR/common.json @@ -1,142 +1,165 @@ { - "button": { - "apply": "Uygula", - "backupKey": "Yedekleme Anahtarı", - "cancel": "İptal", - "clearMessages": "Mesajları Sil", - "close": "Kapat", - "confirm": "Onayla", - "delete": "Sil", - "dismiss": "Vazgeç", - "download": "Yükle", - "export": "Dışa Aktar", - "generate": "Oluştur", - "regenerate": "Yeniden Oluştur", - "import": "İçeri aktar", - "message": "Mesaj", - "now": "Şimdi", - "ok": "Tamam", - "print": "Yazdır", - "remove": "Kaldır", - "requestNewKeys": "Yeni Anahtar İste", - "requestPosition": "Konum İste", - "reset": "Sıfırla", - "save": "Kaydet", - "scanQr": "QR Kodu Tara", - "traceRoute": "Rotayı Takip Et", - "submit": "Gönder" - }, - "app": { - "title": "Meshtastic", - "fullTitle": "Meshtastic Web İstemci" - }, - "loading": "Yükleniyor...", - "unit": { - "cps": "CPS", - "dbm": "dBm", - "hertz": "Hz", - "hop": { - "one": "Hop", - "plural": "Hop" - }, - "hopsAway": { - "one": "{{count}} hop uzaklıkta", - "plural": "{{count}} hop uzaklıkta", - "unknown": "Hop uzaklığı bilinmiyor" - }, - "megahertz": "MHz", - "raw": "ham", - "meter": { - "one": "Metre", - "plural": "Metre", - "suffix": "m" - }, - "minute": { - "one": "Dakika", - "plural": "Dakika" - }, - "hour": { - "one": "Saat", - "plural": "Saat" - }, - "millisecond": { - "one": "Milisaniye", - "plural": "Milisaniye", - "suffix": "ms" - }, - "second": { - "one": "Saniye", - "plural": "Saniye" - }, - "day": { - "one": "Gün", - "plural": "Gün" - }, - "month": { - "one": "Ay", - "plural": "Ay" - }, - "year": { - "one": "Yıl", - "plural": "Yıl" - }, - "snr": "SNR", - "volt": { - "one": "Volt", - "plural": "Volt", - "suffix": "V" - }, - "record": { - "one": "Records", - "plural": "Records" - } - }, - "security": { - "0bit": "Boş", - "8bit": "8 bit", - "128bit": "128 bit", - "256bit": "256 bit" - }, - "unknown": { - "longName": "Bilinmeyen", - "shortName": "UNK", - "notAvailable": "Müsait Değil", - "num": "??" - }, - "nodeUnknownPrefix": "!", - "unset": "UNSET", - "fallbackName": "Meshtastic {{last4}}", - "node": "Node", - "formValidation": { - "unsavedChanges": "Kaydedilmemiş değişiklikler", - "tooBig": { - "string": "Çok uzun, {{maximum}} karaktere eşit yada daha az olması gerek.", - "number": "Çok büyük, {{maximum}} sayıya eşit yada daha az olması gerek.", - "bytes": "Too big, expected less than or equal to {{params.maximum}} bytes." - }, - "tooSmall": { - "string": "Too short, expected more than or equal to {{minimum}} characters.", - "number": "Too small, expected a number larger than or equal to {{minimum}}." - }, - "invalidFormat": { - "ipv4": "Invalid format, expected an IPv4 address.", - "key": "Invalid format, expected a Base64 encoded pre-shared key (PSK)." - }, - "invalidType": { - "number": "Invalid type, expected a number." - }, - "pskLength": { - "0bit": "Anahtarın boş olması gerekiyor.", - "8bit": "Key is required to be an 8 bit pre-shared key (PSK).", - "128bit": "Key is required to be a 128 bit pre-shared key (PSK).", - "256bit": "Key is required to be a 256 bit pre-shared key (PSK)." - }, - "required": { - "generic": "Bu alan zorunludur.", - "managed": "Nodeun yönetilmesi için en az bir tane yönetici anahtarı gerekli.", - "key": "Anahtar gerekli." - } - }, - "yes": "Yes", - "no": "No" + "button": { + "apply": "Uygula", + "addConnection": "Add Connection", + "saveConnection": "Save connection", + "backupKey": "Yedekleme Anahtarı", + "cancel": "İptal", + "connect": "Bağlan", + "clearMessages": "Mesajları Sil", + "close": "Kapat", + "confirm": "Onayla", + "delete": "Sil", + "dismiss": "Vazgeç", + "download": "Yükle", + "disconnect": "Bağlantıyı Kes", + "export": "Dışa Aktar", + "generate": "Oluştur", + "regenerate": "Yeniden Oluştur", + "import": "İçeri aktar", + "message": "Mesaj", + "now": "Şimdi", + "ok": "Tamam", + "print": "Yazdır", + "remove": "Kaldır", + "requestNewKeys": "Yeni Anahtar İste", + "requestPosition": "Konum İste", + "reset": "Sıfırla", + "retry": "Retry", + "save": "Kaydet", + "setDefault": "Set as default", + "unsetDefault": "Unset default", + "scanQr": "QR Kodu Tara", + "traceRoute": "Rotayı Takip Et", + "submit": "Gönder" + }, + "app": { + "title": "Meshtastic", + "fullTitle": "Meshtastic Web İstemci" + }, + "loading": "Yükleniyor...", + "unit": { + "cps": "CPS", + "dbm": "dBm", + "hertz": "Hz", + "hop": { + "one": "Hop", + "plural": "Hop" + }, + "hopsAway": { + "one": "{{count}} hop uzaklıkta", + "plural": "{{count}} hop uzaklıkta", + "unknown": "Hop uzaklığı bilinmiyor" + }, + "megahertz": "MHz", + "kilohertz": "kHz", + "raw": "ham", + "meter": { + "one": "Metre", + "plural": "Metre", + "suffix": "m" + }, + "kilometer": { + "one": "Kilometer", + "plural": "Kilometers", + "suffix": "km" + }, + "minute": { + "one": "Dakika", + "plural": "Dakika" + }, + "hour": { + "one": "Saat", + "plural": "Saat" + }, + "millisecond": { + "one": "Milisaniye", + "plural": "Milisaniye", + "suffix": "ms" + }, + "second": { + "one": "Saniye", + "plural": "Saniye" + }, + "day": { + "one": "Gün", + "plural": "Gün", + "today": "Today", + "yesterday": "Yesterday" + }, + "month": { + "one": "Ay", + "plural": "Ay" + }, + "year": { + "one": "Yıl", + "plural": "Yıl" + }, + "snr": "SNR", + "volt": { + "one": "Volt", + "plural": "Volt", + "suffix": "V" + }, + "record": { + "one": "Records", + "plural": "Records" + }, + "degree": { + "one": "Degree", + "plural": "Degrees", + "suffix": "°" + } + }, + "security": { + "0bit": "Boş", + "8bit": "8 bit", + "128bit": "128 bit", + "256bit": "256 bit" + }, + "unknown": { + "longName": "Bilinmeyen", + "shortName": "UNK", + "notAvailable": "Müsait Değil", + "num": "??" + }, + "nodeUnknownPrefix": "!", + "unset": "UNSET", + "fallbackName": "Meshtastic {{last4}}", + "node": "Node", + "formValidation": { + "unsavedChanges": "Kaydedilmemiş değişiklikler", + "tooBig": { + "string": "Çok uzun, {{maximum}} karaktere eşit yada daha az olması gerek.", + "number": "Çok büyük, {{maximum}} sayıya eşit yada daha az olması gerek.", + "bytes": "Too big, expected less than or equal to {{params.maximum}} bytes." + }, + "tooSmall": { + "string": "Too short, expected more than or equal to {{minimum}} characters.", + "number": "Too small, expected a number larger than or equal to {{minimum}}." + }, + "invalidFormat": { + "ipv4": "Invalid format, expected an IPv4 address.", + "key": "Invalid format, expected a Base64 encoded pre-shared key (PSK)." + }, + "invalidType": { + "number": "Invalid type, expected a number." + }, + "pskLength": { + "0bit": "Anahtarın boş olması gerekiyor.", + "8bit": "Key is required to be an 8 bit pre-shared key (PSK).", + "128bit": "Key is required to be a 128 bit pre-shared key (PSK).", + "256bit": "Key is required to be a 256 bit pre-shared key (PSK)." + }, + "required": { + "generic": "Bu alan zorunludur.", + "managed": "Nodeun yönetilmesi için en az bir tane yönetici anahtarı gerekli.", + "key": "Anahtar gerekli." + }, + "invalidOverrideFreq": { + "number": "Invalid format, expected a value in the range 410-930 MHz or 0 (use default)." + } + }, + "yes": "Yes", + "no": "No" } diff --git a/packages/web/public/i18n/locales/tr-TR/config.json b/packages/web/public/i18n/locales/tr-TR/config.json new file mode 100644 index 000000000..0df1b87be --- /dev/null +++ b/packages/web/public/i18n/locales/tr-TR/config.json @@ -0,0 +1,458 @@ +{ + "page": { + "title": "Ayarlar", + "tabUser": "Kullanıcı", + "tabChannels": "Kanallar", + "tabBluetooth": "Bluetooth", + "tabDevice": "Cihaz", + "tabDisplay": "Ekran", + "tabLora": "LoRa", + "tabNetwork": "Ağ", + "tabPosition": "Konum", + "tabPower": "Güç", + "tabSecurity": "Güvenlik" + }, + "sidebar": { + "label": "Yapılandırma" + }, + "device": { + "title": "Cihaz Ayarları", + "description": "Cihazınız için ayar", + "buttonPin": { + "description": "Buton pini geçersiz kılma", + "label": "Buton pini" + }, + "buzzerPin": { + "description": "Buzzer pinini geçersiz kıl", + "label": "Buzer pini" + }, + "disableTripleClick": { + "description": "Üçlü tıklamayı kapat", + "label": "Üçlü Tıklamayı Kapat" + }, + "doubleTapAsButtonPress": { + "description": "Çift dokunuşu düğmeye basma olarak kabul edin", + "label": "Çift Dokunarak Düğmeye Bas" + }, + "ledHeartbeatDisabled": { + "description": "Varsayılan LED yanıp sönmesini kapat", + "label": "LED Kalp Atışı Kapalı" + }, + "nodeInfoBroadcastInterval": { + "description": "Ne sıklıkla node bilgi göndersin", + "label": "Node Bilgisi Yayın Aralığı" + }, + "posixTimezone": { + "description": "The POSIX timezone string for the device", + "label": "POSIX Zaman Dilimi" + }, + "rebroadcastMode": { + "description": "How to handle rebroadcasting", + "label": "Rebroadcast Mode" + }, + "role": { + "description": "What role the device performs on the mesh", + "label": "Rol" + } + }, + "bluetooth": { + "title": "Bluetooth Ayarları", + "description": "Bluetooth modül ayarları", + "note": "Not: Bazı cihazlar (ESP32) aynı anda Bluetooth ve WiFi kullanamazlar.", + "enabled": { + "description": "Bluetooth Aç ya da Kapat", + "label": "Etkin" + }, + "pairingMode": { + "description": "Pin selection behaviour.", + "label": "Eşleştirme Modu" + }, + "pin": { + "description": "Pin to use when pairing", + "label": "Pin" + } + }, + "display": { + "description": "Settings for the device display", + "title": "Ekran Ayarları", + "headingBold": { + "description": "Bolden the heading text", + "label": "Bold Heading" + }, + "carouselDelay": { + "description": "How fast to cycle through windows", + "label": "Carousel Delay" + }, + "compassNorthTop": { + "description": "Fix north to the top of compass", + "label": "Compass North Top" + }, + "displayMode": { + "description": "Screen layout variant", + "label": "Display Mode" + }, + "displayUnits": { + "description": "Display metric or imperial units", + "label": "Display Units" + }, + "flipScreen": { + "description": "Ekranı 180 derece dönder", + "label": "Ekranı Dönder" + }, + "gpsDisplayUnits": { + "description": "Coordinate display format", + "label": "GPS format" + }, + "oledType": { + "description": "Cihazın OLED ekran tipi", + "label": "OLED Tipi" + }, + "screenTimeout": { + "description": "Turn off the display after this long", + "label": "Screen Timeout" + }, + "twelveHourClock": { + "description": "12 saat formatını kullan", + "label": "12 saatlik zaman" + }, + "wakeOnTapOrMotion": { + "description": "Cihazı uyandırmak için dokun veya hareket ettir", + "label": "Wake on Tap or Motion" + } + }, + "lora": { + "title": "Mesh Ayarları", + "description": "Settings for the LoRa mesh", + "bandwidth": { + "description": "Channel bandwidth in kHz", + "label": "Bant genişliği" + }, + "boostedRxGain": { + "description": "Boosted RX gain", + "label": "Boosted RX Gain" + }, + "codingRate": { + "description": "The denominator of the coding rate", + "label": "Coding Rate" + }, + "frequencyOffset": { + "description": "Frequency offset to correct for crystal calibration errors", + "label": "Frequency Offset" + }, + "frequencySlot": { + "description": "LoRa kanal frekans numarası", + "label": "Frequency Slot" + }, + "hopLimit": { + "description": "Maximum number of hops", + "label": "Hop Limiti" + }, + "ignoreMqtt": { + "description": "Don't forward MQTT messages over the mesh", + "label": "MQTT'yi Yoksay" + }, + "modemPreset": { + "description": "Modem preset to use", + "label": "Modem Ön Ayarı" + }, + "okToMqtt": { + "description": "When set to true, this configuration indicates that the user approves the packet to be uploaded to MQTT. If set to false, remote nodes are requested not to forward packets to MQTT", + "label": "MQTT'ye Tamam" + }, + "overrideDutyCycle": { + "description": "Görev Döngüsünü Geçersiz Kıl", + "label": "Görev Döngüsünü Geçersiz Kıl" + }, + "overrideFrequency": { + "description": "Override frequency", + "label": "Override Frequency" + }, + "region": { + "description": "Düğümün için bölge seç", + "label": "Bölge" + }, + "spreadingFactor": { + "description": "Indicates the number of chirps per symbol", + "label": "Spreading Factor" + }, + "transmitEnabled": { + "description": "Enable/Disable transmit (TX) from the LoRa radio", + "label": "Transmit Enabled" + }, + "transmitPower": { + "description": "Max transmit power", + "label": "Transmit Power" + }, + "usePreset": { + "description": "Use one of the predefined modem presets", + "label": "Use Preset" + }, + "meshSettings": { + "description": "Settings for the LoRa mesh", + "label": "Mesh Ayarları" + }, + "waveformSettings": { + "description": "Settings for the LoRa waveform", + "label": "Waveform Settings" + }, + "radioSettings": { + "label": "Radyo Ayarları", + "description": "Settings for the LoRa radio" + } + }, + "network": { + "title": "WiFi Ayarı", + "description": "WiFi radyo ayarı", + "note": "Not: Bazı cihazlar (ESP32) aynı anda Bluetooth ve WiFi kullanamazlar.", + "addressMode": { + "description": "Address assignment selection", + "label": "Address Mode" + }, + "dns": { + "description": "DNS Sunucusu", + "label": "DNS" + }, + "ethernetEnabled": { + "description": "Ethernet portunu aç ya da kapat", + "label": "Açık" + }, + "gateway": { + "description": "Varsayılan Geçit", + "label": "Ağ geçidi" + }, + "ip": { + "description": "IP Adresi", + "label": "IP" + }, + "psk": { + "description": "Ağ şifresi", + "label": "PSK" + }, + "ssid": { + "description": "Ağ adı", + "label": "SSID" + }, + "subnet": { + "description": "Subnet Mask", + "label": "Alt ağ" + }, + "wifiEnabled": { + "description": "Enable or disable the WiFi radio", + "label": "Açık" + }, + "meshViaUdp": { + "label": "UDP ile Mesh" + }, + "ntpServer": { + "label": "NTP Sunucusu" + }, + "rsyslogServer": { + "label": "Rsyslog Server" + }, + "ethernetConfigSettings": { + "description": "Ethernet port configuration", + "label": "Ethernet Config" + }, + "ipConfigSettings": { + "description": "IP yapılandırması", + "label": "IP Ayarı" + }, + "ntpConfigSettings": { + "description": "NTP configuration", + "label": "NTP Config" + }, + "rsyslogConfigSettings": { + "description": "Rsyslog configuration", + "label": "Rsyslog Config" + }, + "udpConfigSettings": { + "description": "UDP over Mesh configuration", + "label": "UDP Ayarları" + } + }, + "position": { + "title": "Position Settings", + "description": "Settings for the position module", + "broadcastInterval": { + "description": "How often your position is sent out over the mesh", + "label": "Broadcast Interval" + }, + "enablePin": { + "description": "GPS module enable pin override", + "label": "Enable Pin" + }, + "fixedPosition": { + "description": "Don't report GPS position, but a manually-specified one", + "label": "Fixed Position" + }, + "gpsMode": { + "description": "Configure whether device GPS is Enabled, Disabled, or Not Present", + "label": "GPS Modu" + }, + "gpsUpdateInterval": { + "description": "How often a GPS fix should be acquired", + "label": "GPS Update Interval" + }, + "positionFlags": { + "description": "Optional fields to include when assembling position messages. The more fields are selected, the larger the message will be leading to longer airtime usage and a higher risk of packet loss.", + "label": "Position Flags" + }, + "receivePin": { + "description": "GPS module RX pin override", + "label": "Receive Pin" + }, + "smartPositionEnabled": { + "description": "Only send position when there has been a meaningful change in location", + "label": "Enable Smart Position" + }, + "smartPositionMinDistance": { + "description": "Minimum distance (in meters) that must be traveled before a position update is sent", + "label": "Smart Position Minimum Distance" + }, + "smartPositionMinInterval": { + "description": "Minimum interval (in seconds) that must pass before a position update is sent", + "label": "Smart Position Minimum Interval" + }, + "transmitPin": { + "description": "GPS module TX pin override", + "label": "Transmit Pin" + }, + "intervalsSettings": { + "description": "How often to send position updates", + "label": "Intervals" + }, + "flags": { + "placeholder": "Select position flags...", + "altitude": "Rakım", + "altitudeGeoidalSeparation": "Altitude Geoidal Separation", + "altitudeMsl": "Altitude is Mean Sea Level", + "dop": "Dilution of precision (DOP) PDOP used by default", + "hdopVdop": "If DOP is set, use HDOP / VDOP values instead of PDOP", + "numSatellites": "Uydu sayısı", + "sequenceNumber": "Sequence number", + "timestamp": "Zaman Damgası", + "unset": "Ayarlanmamış", + "vehicleHeading": "Vehicle heading", + "vehicleSpeed": "Vehicle speed" + } + }, + "power": { + "adcMultiplierOverride": { + "description": "Used for tweaking battery voltage reading", + "label": "ADC Multiplier Override ratio" + }, + "ina219Address": { + "description": "Address of the INA219 battery monitor", + "label": "INA219 Address" + }, + "lightSleepDuration": { + "description": "How long the device will be in light sleep for", + "label": "Light Sleep Duration" + }, + "minimumWakeTime": { + "description": "Minimum amount of time the device will stay awake for after receiving a packet", + "label": "Minimum Wake Time" + }, + "noConnectionBluetoothDisabled": { + "description": "If the device does not receive a Bluetooth connection, the BLE radio will be disabled after this long", + "label": "No Connection Bluetooth Disabled" + }, + "powerSavingEnabled": { + "description": "Select if powered from a low-current source (i.e. solar), to minimize power consumption as much as possible.", + "label": "Güç tasarrufu modunu etkinleştir" + }, + "shutdownOnBatteryDelay": { + "description": "Automatically shutdown node after this long when on battery, 0 for indefinite", + "label": "Shutdown on battery delay" + }, + "superDeepSleepDuration": { + "description": "How long the device will be in super deep sleep for", + "label": "Super Deep Sleep Duration" + }, + "powerConfigSettings": { + "description": "Settings for the power module", + "label": "Güç Ayarı" + }, + "sleepSettings": { + "description": "Sleep settings for the power module", + "label": "Uyku Ayarları" + } + }, + "security": { + "description": "Settings for the Security configuration", + "title": "Security Settings", + "button_backupKey": "Yedekleme Anahtarı", + "adminChannelEnabled": { + "description": "Gelen cihaza güvenli olmayan eski yönetici kanalı üzerinde kontrol izni verin", + "label": "Eski Yöneticiye İzin Ver" + }, + "enableDebugLogApi": { + "description": "Output live debug logging over serial, view and export position-redacted device logs over Bluetooth", + "label": "Enable Debug Log API" + }, + "managed": { + "description": "If enabled, device configuration options are only able to be changed remotely by a Remote Admin node via admin messages. Do not enable this option unless at least one suitable Remote Admin node has been setup, and the public key is stored in one of the fields above.", + "label": "Managed" + }, + "privateKey": { + "description": "Used to create a shared key with a remote device", + "label": "Özel Anahtar" + }, + "publicKey": { + "description": "Sent out to other nodes on the mesh to allow them to compute a shared secret key", + "label": "Genel Anahtar" + }, + "primaryAdminKey": { + "description": "The primary public key authorized to send admin messages to this node", + "label": "Primary Admin Key" + }, + "secondaryAdminKey": { + "description": "The secondary public key authorized to send admin messages to this node", + "label": "Secondary Admin Key" + }, + "serialOutputEnabled": { + "description": "Serial Console over the Stream API", + "label": "Serial Output Enabled" + }, + "tertiaryAdminKey": { + "description": "The tertiary public key authorized to send admin messages to this node", + "label": "Tertiary Admin Key" + }, + "adminSettings": { + "description": "Yönetici Ayarı", + "label": "Yönetici Ayarları" + }, + "loggingSettings": { + "description": "Settings for Logging", + "label": "Logging Settings" + } + }, + "user": { + "title": "User Settings", + "description": "Configure your device name and identity settings", + "longName": { + "label": "Uzun Ad", + "description": "Your full display name (1-40 characters)", + "validation": { + "min": "Long name must be at least 1 character", + "max": "Long name must be at most 40 characters" + } + }, + "shortName": { + "label": "Kısa Ad", + "description": "Your abbreviated name (2-4 characters)", + "validation": { + "min": "Short name must be at least 2 characters", + "max": "Short name must be at most 4 characters" + } + }, + "isUnmessageable": { + "label": "Mesaj gönderilemez", + "description": "Used to identify unmonitored or infrastructure nodes so that messaging is not available to nodes that will never respond." + }, + "isLicensed": { + "label": "Lisanslı amatör radyo", + "description": "Enable if you are a licensed amateur radio operator, enabling this option disables encryption and is not compatible with the default Meshtastic network." + } + } +} diff --git a/packages/web/public/i18n/locales/tr-TR/connections.json b/packages/web/public/i18n/locales/tr-TR/connections.json new file mode 100644 index 000000000..d0fd1a0a6 --- /dev/null +++ b/packages/web/public/i18n/locales/tr-TR/connections.json @@ -0,0 +1,34 @@ +{ + "page": { + "title": "Connect to a Meshtastic device", + "description": "Add a device connection via HTTP, Bluetooth, or Serial. Your saved connections will be saved in your browser." + }, + "connectionType_ble": "BLE", + "connectionType_serial": "Seri", + "connectionType_network": "Ağ", + "deleteConnection": "Delete connection", + "areYouSure": "This will remove {{name}}. You canot undo this action.", + "moreActions": "More actions", + "noConnections": { + "title": "No connections yet.", + "description": "Create your first connection. It will connect immediately and be saved for later." + }, + "lastConnectedAt": "Last connected: {{date}}", + "neverConnected": "Never connected", + "toasts": { + "connected": "Bağlandı", + "nowConnected": "{{name}} is now connected", + "nowDisconnected": "{{name}} are now disconnecte", + "disconnected": "Bağlantı kesildi", + "failed": "Failed to connect", + "checkConnetion": "Check your device or settings and try again", + "defaultSet": "Default set", + "defaultConnection": "Default connection is now {{nameisconnected}}", + "deleted": "Deleted", + "deletedByName": "{{name}} was removed", + "pickConnectionAgain": "Could not connect. You may need to reselect the device/port.", + "added": "Connection added", + "savedByName": "{{name}} saved.", + "savedCantConnect": "The connection was saved but could not connect." + } +} diff --git a/packages/web/public/i18n/locales/tr-TR/dashboard.json b/packages/web/public/i18n/locales/tr-TR/dashboard.json deleted file mode 100644 index a04d05fd2..000000000 --- a/packages/web/public/i18n/locales/tr-TR/dashboard.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "dashboard": { - "title": "Bağlanan Cihazlar", - "description": "Bağlanan Meshtastic cihazlarını yönet.", - "connectionType_ble": "BLE", - "connectionType_serial": "Seri", - "connectionType_network": "Ağ", - "noDevicesTitle": "Bağlı cihaz yok", - "noDevicesDescription": "Başlamak için yeni cihaz bağla.", - "button_newConnection": "Yeni Bağlantı" - } -} diff --git a/packages/web/public/i18n/locales/tr-TR/deviceConfig.json b/packages/web/public/i18n/locales/tr-TR/deviceConfig.json index 75076b197..ed972a507 100644 --- a/packages/web/public/i18n/locales/tr-TR/deviceConfig.json +++ b/packages/web/public/i18n/locales/tr-TR/deviceConfig.json @@ -122,7 +122,7 @@ "title": "Mesh Settings", "description": "Settings for the LoRa mesh", "bandwidth": { - "description": "Channel bandwidth in MHz", + "description": "Channel bandwidth in kHz", "label": "Bant genişliği" }, "boostedRxGain": { diff --git a/packages/web/public/i18n/locales/tr-TR/dialog.json b/packages/web/public/i18n/locales/tr-TR/dialog.json index a434d1d4f..7cd6c1d41 100644 --- a/packages/web/public/i18n/locales/tr-TR/dialog.json +++ b/packages/web/public/i18n/locales/tr-TR/dialog.json @@ -1,193 +1,238 @@ { - "deleteMessages": { - "description": "Bu işlem tüm mesaj geçmişini temizleyecektir. Bu işlem geri alınamaz. Devam etmek istediğinizden emin misiniz?", - "title": "Tüm Mesajları Sil" - }, - "deviceName": { - "description": "Yapılandırma kaydedildikten sonra Cihaz yeniden başlatılacaktır.", - "longName": "Uzun Ad", - "shortName": "Kısa Ad", - "title": "Cihazın Adını Değiştir", - "validation": { - "longNameMax": "Long name must not be more than 40 characters", - "shortNameMax": "Short name must not be more than 4 characters", - "longNameMin": "Long name must have at least 1 character", - "shortNameMin": "Short name must have at least 1 character" - } - }, - "import": { - "description": "The current LoRa configuration will be overridden.", - "error": { - "invalidUrl": "Invalid Meshtastic URL" - }, - "channelPrefix": "Channel: ", - "channelSetUrl": "Channel Set/QR Code URL", - "channels": "Channels:", - "usePreset": "Use Preset?", - "title": "Import Channel Set" - }, - "locationResponse": { - "title": "Location: {{identifier}}", - "altitude": "Altitude: ", - "coordinates": "Coordinates: ", - "noCoordinates": "No Coordinates" - }, - "pkiRegenerateDialog": { - "title": "Regenerate Pre-Shared Key?", - "description": "Are you sure you want to regenerate the pre-shared key?", - "regenerate": "Regenerate" - }, - "newDeviceDialog": { - "title": "Connect New Device", - "https": "https", - "http": "http", - "tabHttp": "HTTP", - "tabBluetooth": "Bluetooth", - "tabSerial": "Seri", - "useHttps": "Use HTTPS", - "connecting": "Connecting...", - "connect": "Bağlan", - "connectionFailedAlert": { - "title": "Connection Failed", - "descriptionPrefix": "Could not connect to the device. ", - "httpsHint": "If using HTTPS, you may need to accept a self-signed certificate first. ", - "openLinkPrefix": "Please open ", - "openLinkSuffix": " in a new tab", - "acceptTlsWarningSuffix": ", accept any TLS warnings if prompted, then try again", - "learnMoreLink": "Learn more" - }, - "httpConnection": { - "label": "IP Address/Hostname", - "placeholder": "000.000.000.000 / meshtastic.local" - }, - "serialConnection": { - "noDevicesPaired": "No devices paired yet.", - "newDeviceButton": "New device", - "deviceIdentifier": "# {{index}} - {{vendorId}} - {{productId}}" - }, - "bluetoothConnection": { - "noDevicesPaired": "No devices paired yet.", - "newDeviceButton": "New device", - "connectionFailed": "Connection failed", - "deviceDisconnected": "Device disconnected", - "unknownDevice": "Bilinmeyen Cihaz", - "errorLoadingDevices": "Cihazları yüklerken hata oluştu", - "unknownErrorLoadingDevices": "Cihazları yüklerken bilinmeyen hata oluştu" - }, - "validation": { - "requiresWebBluetooth": "Bu bağlantı tipi <0>Web Bluetooth gerektirir. Lütfen desteklenen bir tarayıcı kullan, Chrome yada Edge gibi.", - "requiresWebSerial": "Bu bağlantı tipi <0>Web Serial gerektirir. Lütfen desteklenen bir tarayıcı kullan, Chrome yada Edge gibi.", - "requiresSecureContext": "This application requires a <0>secure context. Please connect using HTTPS or localhost.", - "additionallyRequiresSecureContext": "Additionally, it requires a <0>secure context. Please connect using HTTPS or localhost." - } - }, - "nodeDetails": { - "message": "Mesaj", - "requestPosition": "Request Position", - "traceRoute": "Trace Route", - "airTxUtilization": "Air TX utilization", - "allRawMetrics": "All Raw Metrics:", - "batteryLevel": "Battery level", - "channelUtilization": "Channel utilization", - "details": "Details:", - "deviceMetrics": "Device Metrics:", - "hardware": "Donanım: ", - "lastHeard": "Last Heard: ", - "nodeHexPrefix": "Node Hex: ", - "nodeNumber": "Node Number: ", - "position": "Position:", - "role": "Rol: ", - "uptime": "Çalışma süresi: ", - "voltage": "Voltaj", - "title": "{{identifier}} Node Detayları", - "ignoreNode": "Node yoksay", - "removeNode": "Node sil", - "unignoreNode": "Node yoksaymayı bırak", - "security": "Security:", - "publicKey": "Public Key: ", - "messageable": "Messageable: ", - "KeyManuallyVerifiedTrue": "Public Key has been manually verified", - "KeyManuallyVerifiedFalse": "Public Key is not manually verified" - }, - "pkiBackup": { - "loseKeysWarning": "Eğer anahtarınızı kaybederseniz cihazınızı sıfırlamalısınız.", - "secureBackup": "Açık ve gizli anahtarınızı yedekleyin ve güvenli bir şekilde depolayın!", - "footer": "=== ANAHTAR SONU ===", - "header": "=== MESHTASTIC ANAHTARI {{longName}} ({{shortName}}) İÇİN ===", - "privateKey": "Gizli Anahtar:", - "publicKey": "Açık Anahtar:", - "fileName": "meshtastic_keys_{{longName}}_{{shortName}}.txt", - "title": "Anahtarları Yedekle" - }, - "pkiBackupReminder": { - "description": "We recommend backing up your key data regularly. Would you like to back up now?", - "title": "Backup Reminder", - "remindLaterPrefix": "Remind me in", - "remindNever": "Never remind me", - "backupNow": "Back up now" - }, - "pkiRegenerate": { - "description": "Are you sure you want to regenerate key pair?", - "title": "Regenerate Key Pair" - }, - "qr": { - "addChannels": "Kanal Ekle", - "replaceChannels": "Kanalları Değiştir", - "description": "Mevcut LoRa yapılandırması da paylaşılacak.", - "sharableUrl": "Paylaşılabilir URL", - "title": "QR kod oluştur" - }, - "reboot": { - "title": "Reboot device", - "description": "Reboot now or schedule a reboot of the connected node. Optionally, you can choose to reboot into OTA (Over-the-Air) mode.", - "ota": "Reboot into OTA mode", - "enterDelay": "Enter delay", - "scheduled": "Reboot has been scheduled", - "schedule": "Schedule reboot", - "now": "Reboot now", - "cancel": "Cancel scheduled reboot" - }, - "refreshKeys": { - "description": { - "acceptNewKeys": "This will remove the node from device and request new keys.", - "keyMismatchReasonSuffix": ". This is due to the remote node's current public key does not match the previously stored key for this node.", - "unableToSendDmPrefix": "Your node is unable to send a direct message to node: " - }, - "acceptNewKeys": "Accept New Keys", - "title": "Keys Mismatch - {{identifier}}" - }, - "removeNode": { - "description": "Are you sure you want to remove this Node?", - "title": "Remove Node?" - }, - "shutdown": { - "title": "Kapatmayı Planla", - "description": "Turn off the connected node after x minutes." - }, - "traceRoute": { - "routeToDestination": "Route to destination:", - "routeBack": "Route back:" - }, - "tracerouteResponse": { - "title": "Traceroute: {{identifier}}" - }, - "unsafeRoles": { - "confirmUnderstanding": "Evet, ne yaptığımı biliyorum", - "conjunction": " and the blog post about ", - "postamble": " and understand the implications of changing the role.", - "preamble": "Okudum ", - "choosingRightDeviceRole": "Doğru Cihaz Rolünü Seç", - "deviceRoleDocumentation": "Cihaz Rolü Dökümanları", - "title": "Emin misiniz?" - }, - "managedMode": { - "confirmUnderstanding": "Evet, ne yaptığımı biliyorum", - "title": "Emin misiniz?", - "description": "Yönetilen Modun etkinleştirilmesi, istemci uygulamalarının (web istemcisi dahil) bir radyoya yapılandırma yazmasını engeller. Etkinleştirildikten sonra, radyo yapılandırmaları yalnızca Uzak Yönetici mesajları aracılığıyla değiştirilebilir. Bu ayar, uzak düğüm yönetimi için gerekli değildir." - }, - "clientNotification": { - "title": "Client Notification", - "TraceRoute can only be sent once every 30 seconds": "TraceRoute can only be sent once every 30 seconds", - "Compromised keys were detected and regenerated.": "Compromised keys were detected and regenerated." - } + "deleteMessages": { + "description": "Bu işlem tüm mesaj geçmişini temizleyecektir. Bu işlem geri alınamaz. Devam etmek istediğinizden emin misiniz?", + "title": "Tüm Mesajları Sil" + }, + "import": { + "description": "The current LoRa configuration will be overridden.", + "error": { + "invalidUrl": "Invalid Meshtastic URL" + }, + "channelPrefix": "Channel: ", + "primary": "Primary ", + "doNotImport": "No not import", + "channelName": "İsmi", + "channelSlot": "Yuva", + "channelSetUrl": "Channel Set/QR Code URL", + "useLoraConfig": "Import LoRa Config", + "presetDescription": "The current LoRa Config will be replaced.", + "title": "Import Channel Set" + }, + "locationResponse": { + "title": "Location: {{identifier}}", + "altitude": "Altitude: ", + "coordinates": "Coordinates: ", + "noCoordinates": "No Coordinates" + }, + "pkiRegenerateDialog": { + "title": "Regenerate Pre-Shared Key?", + "description": "Are you sure you want to regenerate the pre-shared key?", + "regenerate": "Regenerate" + }, + "addConnection": { + "title": "Add connection", + "description": "Choose a connection type and fill in the details", + "validation": { + "requiresWebBluetooth": "Bu bağlantı tipi <0>Web Bluetooth gerektirir. Lütfen desteklenen bir tarayıcı kullan, Chrome yada Edge gibi.", + "requiresWebSerial": "Bu bağlantı tipi <0>Web Serial gerektirir. Lütfen desteklenen bir tarayıcı kullan, Chrome yada Edge gibi.", + "requiresSecureContext": "Bu uygulama <0>güvenli bir bağlam gerektiriyor. Lütfen HTTPS veya localhost kullanarak bağlanın.", + "additionallyRequiresSecureContext": "Ek olarak, <0>güvenli bir bağlam gerektiriyor. Lütfen HTTPS veya localhost kullanarak bağlanın." + }, + "bluetoothConnection": { + "namePlaceholder": "My Bluetooth Node", + "supported": { + "title": "Web Bluetooth supported" + }, + "notSupported": { + "title": "Web Bluetooth not supported", + "description": "Your browser or device does not support Web Bluetooth" + }, + "short": "BT: {{deviceName}}", + "long": "Bluetooth Device", + "device": "Cihaz", + "selectDevice": "Select device", + "selected": "Bluetooth device selected", + "notSelected": "No device selected", + "helperText": "Uses the Meshtastic Bluetooth service for discovery." + }, + "serialConnection": { + "namePlaceholder": "My Serial Node", + "helperText": "Selecting a port grants permission so the app can open it to connect.", + "supported": { + "title": "Web Serial supported" + }, + "notSupported": { + "title": "Web Serial not supported", + "description": "Your browser or device does not support Web Serial" + }, + "portSelected": { + "title": "Serial port selected", + "description": "Port permissions granted." + }, + "port": "Port", + "selectPort": "Select port", + "deviceName": "USB {{vendorId}}:{{productId}}", + "notSelected": "No port selected" + }, + "httpConnection": { + "namePlaceholder": "My HTTP Node", + "inputPlaceholder": "192.168.1.10 or meshtastic.local", + "heading": "URL or IP", + "useHttps": "Use HTTTPS", + "invalidUrl": { + "title": "Invalid URL", + "description": "Please enter a valid HTTP or HTTPS URL." + }, + "connectionTest": { + "description": "Test the connetion before saving to verify the device is reachable.", + "button": { + "loading": "Testing...", + "label": "Test connection" + }, + "reachable": "Reachable", + "notReachable": "Not reachable", + "success": { + "title": "Connection test successful", + "description": "The device appears to be reachable." + }, + "failure": { + "title": "Connection test failed", + "description": "Could not reach the device. Check the URL and try again." + } + } + } + }, + "nodeDetails": { + "message": "Mesaj", + "requestPosition": "Request Position", + "traceRoute": "Trace Route", + "airTxUtilization": "Air TX utilization", + "allRawMetrics": "All Raw Metrics:", + "batteryLevel": "Battery level", + "channelUtilization": "Channel utilization", + "details": "Details:", + "deviceMetrics": "Device Metrics:", + "hardware": "Donanım: ", + "lastHeard": "Last Heard: ", + "nodeHexPrefix": "Node Hex: ", + "nodeNumber": "Node Number: ", + "position": "Position:", + "role": "Rol: ", + "uptime": "Çalışma süresi: ", + "voltage": "Voltaj", + "title": "{{identifier}} Node Detayları", + "ignoreNode": "Node yoksay", + "removeNode": "Node sil", + "unignoreNode": "Node yoksaymayı bırak", + "security": "Security:", + "publicKey": "Public Key: ", + "messageable": "Messageable: ", + "KeyManuallyVerifiedTrue": "Public Key has been manually verified", + "KeyManuallyVerifiedFalse": "Public Key is not manually verified" + }, + "pkiBackup": { + "loseKeysWarning": "Eğer anahtarınızı kaybederseniz cihazınızı sıfırlamalısınız.", + "secureBackup": "Açık ve gizli anahtarınızı yedekleyin ve güvenli bir şekilde depolayın!", + "footer": "=== ANAHTAR SONU ===", + "header": "=== MESHTASTIC ANAHTARI {{longName}} ({{shortName}}) İÇİN ===", + "privateKey": "Gizli Anahtar:", + "publicKey": "Açık Anahtar:", + "fileName": "meshtastic_keys_{{longName}}_{{shortName}}.txt", + "title": "Anahtarları Yedekle" + }, + "pkiBackupReminder": { + "description": "We recommend backing up your key data regularly. Would you like to back up now?", + "title": "Backup Reminder", + "remindLaterPrefix": "Remind me in", + "remindNever": "Never remind me", + "backupNow": "Back up now" + }, + "pkiRegenerate": { + "description": "Are you sure you want to regenerate key pair?", + "title": "Regenerate Key Pair" + }, + "qr": { + "addChannels": "Kanal Ekle", + "replaceChannels": "Kanalları Değiştir", + "description": "Mevcut LoRa yapılandırması da paylaşılacak.", + "sharableUrl": "Paylaşılabilir URL", + "title": "QR kod oluştur" + }, + "reboot": { + "title": "Reboot device", + "description": "Reboot now or schedule a reboot of the connected node. Optionally, you can choose to reboot into OTA (Over-the-Air) mode.", + "ota": "Reboot into OTA mode", + "enterDelay": "Enter delay", + "scheduled": "Reboot has been scheduled", + "schedule": "Schedule reboot", + "now": "Reboot now", + "cancel": "Cancel scheduled reboot" + }, + "refreshKeys": { + "description": { + "acceptNewKeys": "This will remove the node from device and request new keys.", + "keyMismatchReasonSuffix": ". This is due to the remote node's current public key does not match the previously stored key for this node.", + "unableToSendDmPrefix": "Your node is unable to send a direct message to node: " + }, + "acceptNewKeys": "Accept New Keys", + "title": "Keys Mismatch - {{identifier}}" + }, + "removeNode": { + "description": "Are you sure you want to remove this Node?", + "title": "Remove Node?" + }, + "shutdown": { + "title": "Kapatmayı Planla", + "description": "Turn off the connected node after x minutes." + }, + "traceRoute": { + "routeToDestination": "Route to destination:", + "routeBack": "Route back:" + }, + "tracerouteResponse": { + "title": "Traceroute: {{identifier}}" + }, + "unsafeRoles": { + "confirmUnderstanding": "Evet, ne yaptığımı biliyorum", + "conjunction": " and the blog post about ", + "postamble": " and understand the implications of changing the role.", + "preamble": "Okudum ", + "choosingRightDeviceRole": "Doğru Cihaz Rolünü Seç", + "deviceRoleDocumentation": "Cihaz Rolü Dökümanları", + "title": "Emin misiniz?" + }, + "managedMode": { + "confirmUnderstanding": "Evet, ne yaptığımı biliyorum", + "title": "Emin misiniz?", + "description": "Yönetilen Modun etkinleştirilmesi, istemci uygulamalarının (web istemcisi dahil) bir radyoya yapılandırma yazmasını engeller. Etkinleştirildikten sonra, radyo yapılandırmaları yalnızca Uzak Yönetici mesajları aracılığıyla değiştirilebilir. Bu ayar, uzak düğüm yönetimi için gerekli değildir." + }, + "clientNotification": { + "title": "Client Notification", + "TraceRoute can only be sent once every 30 seconds": "TraceRoute can only be sent once every 30 seconds", + "Compromised keys were detected and regenerated.": "Compromised keys were detected and regenerated." + }, + "resetNodeDb": { + "title": "Reset Node Database", + "description": "This will clear all nodes from the connected device's node database and clear all message history in the client. This cannot be undone. Are you sure you want to continue?", + "confirm": "Reset Node Database", + "failedTitle": "There was an error resetting the Node DB. Please try again." + }, + "clearAllStores": { + "title": "Clear All Local Storage", + "description": "This will clear all locally stored data, including message history and node databases for all previously connected devices. This will require you to reconnect to your node once complete and cannot be undone. Are you sure you want to continue?", + "confirm": "Clear all local storage", + "failedTitle": "There was an error clearing local storage. Please try again." + }, + "factoryResetDevice": { + "title": "Cihazı Fabrika Ayarlarına Sıfırlayın", + "description": "This will factory reset the connected device, erasing all configurations and data on the device as well as all nodes and messages saved in the client. This cannot be undone. Are you sure you want to continue?", + "confirm": "Cihazı Fabrika Ayarlarına Sıfırlayın", + "failedTitle": "There was an error performing the factory reset. Please try again." + }, + "factoryResetConfig": { + "title": "Fabrika Ayarları Yapılandırması", + "description": "This will factory reset the configuration on the connected device, erasing all configurations on the device. This cannot be undone. Are you sure you want to continue?", + "confirm": "Fabrika Ayarları Yapılandırması", + "failedTitle": "There was an error performing the factory reset. Please try again." + } } diff --git a/packages/web/public/i18n/locales/tr-TR/map.json b/packages/web/public/i18n/locales/tr-TR/map.json new file mode 100644 index 000000000..e14c3dde8 --- /dev/null +++ b/packages/web/public/i18n/locales/tr-TR/map.json @@ -0,0 +1,38 @@ +{ + "maplibre": { + "GeolocateControl.FindMyLocation": "Find my location", + "NavigationControl.ZoomIn": "Zoom in", + "NavigationControl.ZoomOut": "Zoom out", + "CooperativeGesturesHandler.WindowsHelpText": "Use Ctrl + scroll to zoom the map", + "CooperativeGesturesHandler.MacHelpText": "Use ⌘ + scroll to zoom the map", + "CooperativeGesturesHandler.MobileHelpText": "Use two fingers to move the map" + }, + "layerTool": { + "nodeMarkers": "Show nodes", + "directNeighbors": "Show direct connections", + "remoteNeighbors": "Show remote connections", + "positionPrecision": "Show position precision", + "traceroutes": "Show traceroutes", + "waypoints": "Show waypoints" + }, + "mapMenu": { + "locateAria": "Locate my node", + "layersAria": "Change map style" + }, + "waypointDetail": { + "edit": "Düzenle", + "description": "Description:", + "createdBy": "Edited by:", + "createdDate": "Created:", + "updated": "Updated:", + "expires": "Expires:", + "distance": "Distance:", + "bearing": "Absolute bearing:", + "lockedTo": "Locked by:", + "latitude": "Latitude:", + "longitude": "Longitude:" + }, + "myNode": { + "tooltip": "This device" + } +} diff --git a/packages/web/public/i18n/locales/tr-TR/messages.json b/packages/web/public/i18n/locales/tr-TR/messages.json index 334caadc3..e2420ea55 100644 --- a/packages/web/public/i18n/locales/tr-TR/messages.json +++ b/packages/web/public/i18n/locales/tr-TR/messages.json @@ -1,39 +1,39 @@ { - "page": { - "title": "Messages: {{chatName}}", - "placeholder": "Enter Message" - }, - "emptyState": { - "title": "Select a Chat", - "text": "No messages yet." - }, - "selectChatPrompt": { - "text": "Select a channel or node to start messaging." - }, - "sendMessage": { - "placeholder": "Enter your message here...", - "sendButton": "Gönder" - }, - "actionsMenu": { - "addReactionLabel": "Add Reaction", - "replyLabel": "Yanıtla" - }, - "deliveryStatus": { - "delivered": { - "label": "Message delivered", - "displayText": "Message delivered" - }, - "failed": { - "label": "Message delivery failed", - "displayText": "Delivery failed" - }, - "unknown": { - "label": "Message status unknown", - "displayText": "Unknown state" - }, - "waiting": { - "label": "Sending message", - "displayText": "Waiting for delivery" - } - } + "page": { + "title": "Messages: {{chatName}}", + "placeholder": "Enter Message" + }, + "emptyState": { + "title": "Select a Chat", + "text": "No messages yet." + }, + "selectChatPrompt": { + "text": "Select a channel or node to start messaging." + }, + "sendMessage": { + "placeholder": "Enter your message here...", + "sendButton": "Gönder" + }, + "actionsMenu": { + "addReactionLabel": "Add Reaction", + "replyLabel": "Yanıtla" + }, + "deliveryStatus": { + "delivered": { + "label": "Message delivered", + "displayText": "Message delivered" + }, + "failed": { + "label": "Message delivery failed", + "displayText": "Delivery failed" + }, + "unknown": { + "label": "Message status unknown", + "displayText": "Unknown state" + }, + "waiting": { + "label": "Sending message", + "displayText": "Waiting for delivery" + } + } } diff --git a/packages/web/public/i18n/locales/tr-TR/moduleConfig.json b/packages/web/public/i18n/locales/tr-TR/moduleConfig.json index e1ac9f723..a1ada1e29 100644 --- a/packages/web/public/i18n/locales/tr-TR/moduleConfig.json +++ b/packages/web/public/i18n/locales/tr-TR/moduleConfig.json @@ -1,448 +1,448 @@ { - "page": { - "tabAmbientLighting": "Ortam Işıklandırması", - "tabAudio": "Ses", - "tabCannedMessage": "Canned", - "tabDetectionSensor": "Algılama Sensörü", - "tabExternalNotification": "Ext Notif", - "tabMqtt": "MQTT", - "tabNeighborInfo": "Komşu Bilgisi", - "tabPaxcounter": "Pax sayacı", - "tabRangeTest": "Mesafe Testi", - "tabSerial": "Seri", - "tabStoreAndForward": "S&F", - "tabTelemetry": "Telemetri" - }, - "ambientLighting": { - "title": "Ambient Lighting Settings", - "description": "Settings for the Ambient Lighting module", - "ledState": { - "label": "LED State", - "description": "Sets LED to on or off" - }, - "current": { - "label": "Akım", - "description": "Sets the current for the LED output. Default is 10" - }, - "red": { - "label": "Kırmızı", - "description": "Sets the red LED level. Values are 0-255" - }, - "green": { - "label": "Yeşil", - "description": "Sets the green LED level. Values are 0-255" - }, - "blue": { - "label": "Mavi", - "description": "Sets the blue LED level. Values are 0-255" - } - }, - "audio": { - "title": "Audio Settings", - "description": "Settings for the Audio module", - "codec2Enabled": { - "label": "Codec 2 Enabled", - "description": "Enable Codec 2 audio encoding" - }, - "pttPin": { - "label": "PTT Pin", - "description": "GPIO pin to use for PTT" - }, - "bitrate": { - "label": "Bitrate", - "description": "Bitrate to use for audio encoding" - }, - "i2sWs": { - "label": "i2S WS", - "description": "GPIO pin to use for i2S WS" - }, - "i2sSd": { - "label": "i2S SD", - "description": "GPIO pin to use for i2S SD" - }, - "i2sDin": { - "label": "i2S DIN", - "description": "GPIO pin to use for i2S DIN" - }, - "i2sSck": { - "label": "i2S SCK", - "description": "GPIO pin to use for i2S SCK" - } - }, - "cannedMessage": { - "title": "Canned Message Settings", - "description": "Settings for the Canned Message module", - "moduleEnabled": { - "label": "Module Enabled", - "description": "Enable Canned Message" - }, - "rotary1Enabled": { - "label": "Rotary Encoder #1 Enabled", - "description": "Enable the rotary encoder" - }, - "inputbrokerPinA": { - "label": "Encoder Pin A", - "description": "GPIO Pin Value (1-39) For encoder port A" - }, - "inputbrokerPinB": { - "label": "Encoder Pin B", - "description": "GPIO Pin Value (1-39) For encoder port B" - }, - "inputbrokerPinPress": { - "label": "Encoder Pin Press", - "description": "GPIO Pin Value (1-39) For encoder Press" - }, - "inputbrokerEventCw": { - "label": "Clockwise event", - "description": "Select input event." - }, - "inputbrokerEventCcw": { - "label": "Counter Clockwise event", - "description": "Select input event." - }, - "inputbrokerEventPress": { - "label": "Press event", - "description": "Select input event" - }, - "updown1Enabled": { - "label": "Up Down enabled", - "description": "Enable the up / down encoder" - }, - "allowInputSource": { - "label": "Allow Input Source", - "description": "Select from: '_any', 'rotEnc1', 'upDownEnc1', 'cardkb'" - }, - "sendBell": { - "label": "Send Bell", - "description": "Sends a bell character with each message" - } - }, - "detectionSensor": { - "title": "Detection Sensor Settings", - "description": "Settings for the Detection Sensor module", - "enabled": { - "label": "Enabled", - "description": "Enable or disable Detection Sensor Module" - }, - "minimumBroadcastSecs": { - "label": "Minimum Broadcast Seconds", - "description": "The interval in seconds of how often we can send a message to the mesh when a state change is detected" - }, - "stateBroadcastSecs": { - "label": "State Broadcast Seconds", - "description": "The interval in seconds of how often we should send a message to the mesh with the current state regardless of changes" - }, - "sendBell": { - "label": "Send Bell", - "description": "Send ASCII bell with alert message" - }, - "name": { - "label": "Friendly Name", - "description": "Used to format the message sent to mesh, max 20 Characters" - }, - "monitorPin": { - "label": "Monitor Pin", - "description": "The GPIO pin to monitor for state changes" - }, - "detectionTriggerType": { - "label": "Detection Triggered Type", - "description": "The type of trigger event to be used" - }, - "usePullup": { - "label": "Use Pullup", - "description": "Whether or not use INPUT_PULLUP mode for GPIO pin" - } - }, - "externalNotification": { - "title": "External Notification Settings", - "description": "Configure the external notification module", - "enabled": { - "label": "Module Enabled", - "description": "Enable External Notification" - }, - "outputMs": { - "label": "Output MS", - "description": "Output MS" - }, - "output": { - "label": "Output", - "description": "Output" - }, - "outputVibra": { - "label": "Output Vibrate", - "description": "Output Vibrate" - }, - "outputBuzzer": { - "label": "Output Buzzer", - "description": "Output Buzzer" - }, - "active": { - "label": "Active", - "description": "Active" - }, - "alertMessage": { - "label": "Alert Message", - "description": "Alert Message" - }, - "alertMessageVibra": { - "label": "Alert Message Vibrate", - "description": "Alert Message Vibrate" - }, - "alertMessageBuzzer": { - "label": "Alert Message Buzzer", - "description": "Alert Message Buzzer" - }, - "alertBell": { - "label": "Alert Bell", - "description": "Should an alert be triggered when receiving an incoming bell?" - }, - "alertBellVibra": { - "label": "Alert Bell Vibrate", - "description": "Alert Bell Vibrate" - }, - "alertBellBuzzer": { - "label": "Alert Bell Buzzer", - "description": "Alert Bell Buzzer" - }, - "usePwm": { - "label": "Use PWM", - "description": "Use PWM" - }, - "nagTimeout": { - "label": "Nag Timeout", - "description": "Nag Timeout" - }, - "useI2sAsBuzzer": { - "label": "Use I²S Pin as Buzzer", - "description": "Designate I²S Pin as Buzzer Output" - } - }, - "mqtt": { - "title": "MQTT Settings", - "description": "Settings for the MQTT module", - "enabled": { - "label": "Enabled", - "description": "Enable or disable MQTT" - }, - "address": { - "label": "MQTT Server Address", - "description": "MQTT server address to use for default/custom servers" - }, - "username": { - "label": "MQTT Username", - "description": "MQTT username to use for default/custom servers" - }, - "password": { - "label": "MQTT Password", - "description": "MQTT password to use for default/custom servers" - }, - "encryptionEnabled": { - "label": "Encryption Enabled", - "description": "Enable or disable MQTT encryption. Note: All messages are sent to the MQTT broker unencrypted if this option is not enabled, even when your uplink channels have encryption keys set. This includes position data." - }, - "jsonEnabled": { - "label": "JSON Enabled", - "description": "Whether to send/consume JSON packets on MQTT" - }, - "tlsEnabled": { - "label": "TLS Enabled", - "description": "Enable or disable TLS" - }, - "root": { - "label": "Ana konu", - "description": "MQTT root topic to use for default/custom servers" - }, - "proxyToClientEnabled": { - "label": "MQTT Client Proxy Enabled", - "description": "Utilizes the network connection to proxy MQTT messages to the client." - }, - "mapReportingEnabled": { - "label": "Map Reporting Enabled", - "description": "Your node will periodically send an unencrypted map report packet to the configured MQTT server, this includes id, short and long name, approximate location, hardware model, role, firmware version, LoRa region, modem preset and primary channel name." - }, - "mapReportSettings": { - "publishIntervalSecs": { - "label": "Map Report Publish Interval (s)", - "description": "Interval in seconds to publish map reports" - }, - "positionPrecision": { - "label": "Approximate Location", - "description": "Position shared will be accurate within this distance", - "options": { - "metric_km23": "Within 23 km", - "metric_km12": "Within 12 km", - "metric_km5_8": "Within 5.8 km", - "metric_km2_9": "Within 2.9 km", - "metric_km1_5": "Within 1.5 km", - "metric_m700": "Within 700 m", - "metric_m350": "Within 350 m", - "metric_m200": "Within 200 m", - "metric_m90": "Within 90 m", - "metric_m50": "Within 50 m", - "imperial_mi15": "Within 15 miles", - "imperial_mi7_3": "Within 7.3 miles", - "imperial_mi3_6": "Within 3.6 miles", - "imperial_mi1_8": "Within 1.8 miles", - "imperial_mi0_9": "Within 0.9 miles", - "imperial_mi0_5": "Within 0.5 miles", - "imperial_mi0_2": "Within 0.2 miles", - "imperial_ft600": "Within 600 feet", - "imperial_ft300": "Within 300 feet", - "imperial_ft150": "Within 150 feet" - } - } - } - }, - "neighborInfo": { - "title": "Neighbor Info Settings", - "description": "Settings for the Neighbor Info module", - "enabled": { - "label": "Enabled", - "description": "Enable or disable Neighbor Info Module" - }, - "updateInterval": { - "label": "Update Interval", - "description": "Interval in seconds of how often we should try to send our Neighbor Info to the mesh" - } - }, - "paxcounter": { - "title": "Paxcounter Settings", - "description": "Settings for the Paxcounter module", - "enabled": { - "label": "Module Enabled", - "description": "Enable Paxcounter" - }, - "paxcounterUpdateInterval": { - "label": "Update Interval (seconds)", - "description": "How long to wait between sending paxcounter packets" - }, - "wifiThreshold": { - "label": "WiFi RSSI Threshold", - "description": "At what WiFi RSSI level should the counter increase. Defaults to -80." - }, - "bleThreshold": { - "label": "BLE RSSI Threshold", - "description": "At what BLE RSSI level should the counter increase. Defaults to -80." - } - }, - "rangeTest": { - "title": "Range Test Settings", - "description": "Settings for the Range Test module", - "enabled": { - "label": "Module Enabled", - "description": "Enable Range Test" - }, - "sender": { - "label": "Message Interval", - "description": "How long to wait between sending test packets" - }, - "save": { - "label": "Save CSV to storage", - "description": "ESP32 Only" - } - }, - "serial": { - "title": "Serial Settings", - "description": "Settings for the Serial module", - "enabled": { - "label": "Module Enabled", - "description": "Enable Serial output" - }, - "echo": { - "label": "Echo", - "description": "Any packets you send will be echoed back to your device" - }, - "rxd": { - "label": "Receive Pin", - "description": "Set the GPIO pin to the RXD pin you have set up." - }, - "txd": { - "label": "Transmit Pin", - "description": "Set the GPIO pin to the TXD pin you have set up." - }, - "baud": { - "label": "Baud Rate", - "description": "The serial baud rate" - }, - "timeout": { - "label": "Zaman Aşımı", - "description": "Seconds to wait before we consider your packet as 'done'" - }, - "mode": { - "label": "Mode", - "description": "Select Mode" - }, - "overrideConsoleSerialPort": { - "label": "Override Console Serial Port", - "description": "If you have a serial port connected to the console, this will override it." - } - }, - "storeForward": { - "title": "Store & Forward Settings", - "description": "Settings for the Store & Forward module", - "enabled": { - "label": "Module Enabled", - "description": "Enable Store & Forward" - }, - "heartbeat": { - "label": "Heartbeat Enabled", - "description": "Enable Store & Forward heartbeat" - }, - "records": { - "label": "Kayıt sayısı", - "description": "Number of records to store" - }, - "historyReturnMax": { - "label": "Geçmiş geri dönüş maksimum", - "description": "Max number of records to return" - }, - "historyReturnWindow": { - "label": "Geçmiş geri dönüş penceresi", - "description": "Max number of records to return" - } - }, - "telemetry": { - "title": "Telemetry Settings", - "description": "Settings for the Telemetry module", - "deviceUpdateInterval": { - "label": "Device Metrics", - "description": "Cihaz metrikleri güncelleme aralığı (saniye)" - }, - "environmentUpdateInterval": { - "label": "Çevre metrikleri güncelleme aralığı (saniye)", - "description": "" - }, - "environmentMeasurementEnabled": { - "label": "Module Enabled", - "description": "Enable the Environment Telemetry" - }, - "environmentScreenEnabled": { - "label": "Displayed on Screen", - "description": "Show the Telemetry Module on the OLED" - }, - "environmentDisplayFahrenheit": { - "label": "Display Fahrenheit", - "description": "Display temp in Fahrenheit" - }, - "airQualityEnabled": { - "label": "Air Quality Enabled", - "description": "Enable the Air Quality Telemetry" - }, - "airQualityInterval": { - "label": "Air Quality Update Interval", - "description": "How often to send Air Quality data over the mesh" - }, - "powerMeasurementEnabled": { - "label": "Power Measurement Enabled", - "description": "Enable the Power Measurement Telemetry" - }, - "powerUpdateInterval": { - "label": "Power Update Interval", - "description": "How often to send Power data over the mesh" - }, - "powerScreenEnabled": { - "label": "Power Screen Enabled", - "description": "Enable the Power Telemetry Screen" - } - } + "page": { + "tabAmbientLighting": "Ortam Işıklandırması", + "tabAudio": "Ses", + "tabCannedMessage": "Canned", + "tabDetectionSensor": "Algılama Sensörü", + "tabExternalNotification": "Ext Notif", + "tabMqtt": "MQTT", + "tabNeighborInfo": "Komşu Bilgisi", + "tabPaxcounter": "Pax sayacı", + "tabRangeTest": "Mesafe Testi", + "tabSerial": "Seri", + "tabStoreAndForward": "S&F", + "tabTelemetry": "Telemetri" + }, + "ambientLighting": { + "title": "Ambient Lighting Settings", + "description": "Settings for the Ambient Lighting module", + "ledState": { + "label": "LED State", + "description": "Sets LED to on or off" + }, + "current": { + "label": "Akım", + "description": "Sets the current for the LED output. Default is 10" + }, + "red": { + "label": "Kırmızı", + "description": "Sets the red LED level. Values are 0-255" + }, + "green": { + "label": "Yeşil", + "description": "Sets the green LED level. Values are 0-255" + }, + "blue": { + "label": "Mavi", + "description": "Sets the blue LED level. Values are 0-255" + } + }, + "audio": { + "title": "Audio Settings", + "description": "Settings for the Audio module", + "codec2Enabled": { + "label": "Codec 2 Enabled", + "description": "Enable Codec 2 audio encoding" + }, + "pttPin": { + "label": "PTT Pin", + "description": "GPIO pin to use for PTT" + }, + "bitrate": { + "label": "Bitrate", + "description": "Bitrate to use for audio encoding" + }, + "i2sWs": { + "label": "i2S WS", + "description": "GPIO pin to use for i2S WS" + }, + "i2sSd": { + "label": "i2S SD", + "description": "GPIO pin to use for i2S SD" + }, + "i2sDin": { + "label": "i2S DIN", + "description": "GPIO pin to use for i2S DIN" + }, + "i2sSck": { + "label": "i2S SCK", + "description": "GPIO pin to use for i2S SCK" + } + }, + "cannedMessage": { + "title": "Canned Message Settings", + "description": "Settings for the Canned Message module", + "moduleEnabled": { + "label": "Module Enabled", + "description": "Enable Canned Message" + }, + "rotary1Enabled": { + "label": "Rotary Encoder #1 Enabled", + "description": "Enable the rotary encoder" + }, + "inputbrokerPinA": { + "label": "Encoder Pin A", + "description": "GPIO Pin Value (1-39) For encoder port A" + }, + "inputbrokerPinB": { + "label": "Encoder Pin B", + "description": "GPIO Pin Value (1-39) For encoder port B" + }, + "inputbrokerPinPress": { + "label": "Encoder Pin Press", + "description": "GPIO Pin Value (1-39) For encoder Press" + }, + "inputbrokerEventCw": { + "label": "Clockwise event", + "description": "Select input event." + }, + "inputbrokerEventCcw": { + "label": "Counter Clockwise event", + "description": "Select input event." + }, + "inputbrokerEventPress": { + "label": "Press event", + "description": "Select input event" + }, + "updown1Enabled": { + "label": "Up Down enabled", + "description": "Enable the up / down encoder" + }, + "allowInputSource": { + "label": "Allow Input Source", + "description": "Select from: '_any', 'rotEnc1', 'upDownEnc1', 'cardkb'" + }, + "sendBell": { + "label": "Send Bell", + "description": "Sends a bell character with each message" + } + }, + "detectionSensor": { + "title": "Detection Sensor Settings", + "description": "Settings for the Detection Sensor module", + "enabled": { + "label": "Enabled", + "description": "Enable or disable Detection Sensor Module" + }, + "minimumBroadcastSecs": { + "label": "Minimum Broadcast Seconds", + "description": "The interval in seconds of how often we can send a message to the mesh when a state change is detected" + }, + "stateBroadcastSecs": { + "label": "State Broadcast Seconds", + "description": "The interval in seconds of how often we should send a message to the mesh with the current state regardless of changes" + }, + "sendBell": { + "label": "Send Bell", + "description": "Send ASCII bell with alert message" + }, + "name": { + "label": "Friendly Name", + "description": "Used to format the message sent to mesh, max 20 Characters" + }, + "monitorPin": { + "label": "Monitor Pin", + "description": "The GPIO pin to monitor for state changes" + }, + "detectionTriggerType": { + "label": "Detection Triggered Type", + "description": "The type of trigger event to be used" + }, + "usePullup": { + "label": "Use Pullup", + "description": "Whether or not use INPUT_PULLUP mode for GPIO pin" + } + }, + "externalNotification": { + "title": "External Notification Settings", + "description": "Configure the external notification module", + "enabled": { + "label": "Module Enabled", + "description": "Enable External Notification" + }, + "outputMs": { + "label": "Output MS", + "description": "Output MS" + }, + "output": { + "label": "Output", + "description": "Output" + }, + "outputVibra": { + "label": "Output Vibrate", + "description": "Output Vibrate" + }, + "outputBuzzer": { + "label": "Output Buzzer", + "description": "Output Buzzer" + }, + "active": { + "label": "Active", + "description": "Active" + }, + "alertMessage": { + "label": "Alert Message", + "description": "Alert Message" + }, + "alertMessageVibra": { + "label": "Alert Message Vibrate", + "description": "Alert Message Vibrate" + }, + "alertMessageBuzzer": { + "label": "Alert Message Buzzer", + "description": "Alert Message Buzzer" + }, + "alertBell": { + "label": "Alert Bell", + "description": "Should an alert be triggered when receiving an incoming bell?" + }, + "alertBellVibra": { + "label": "Alert Bell Vibrate", + "description": "Alert Bell Vibrate" + }, + "alertBellBuzzer": { + "label": "Alert Bell Buzzer", + "description": "Alert Bell Buzzer" + }, + "usePwm": { + "label": "Use PWM", + "description": "Use PWM" + }, + "nagTimeout": { + "label": "Nag Timeout", + "description": "Nag Timeout" + }, + "useI2sAsBuzzer": { + "label": "Use I²S Pin as Buzzer", + "description": "Designate I²S Pin as Buzzer Output" + } + }, + "mqtt": { + "title": "MQTT Settings", + "description": "Settings for the MQTT module", + "enabled": { + "label": "Enabled", + "description": "Enable or disable MQTT" + }, + "address": { + "label": "MQTT Server Address", + "description": "MQTT server address to use for default/custom servers" + }, + "username": { + "label": "MQTT Username", + "description": "MQTT username to use for default/custom servers" + }, + "password": { + "label": "MQTT Password", + "description": "MQTT password to use for default/custom servers" + }, + "encryptionEnabled": { + "label": "Encryption Enabled", + "description": "Enable or disable MQTT encryption. Note: All messages are sent to the MQTT broker unencrypted if this option is not enabled, even when your uplink channels have encryption keys set. This includes position data." + }, + "jsonEnabled": { + "label": "JSON Enabled", + "description": "Whether to send/consume JSON packets on MQTT" + }, + "tlsEnabled": { + "label": "TLS Enabled", + "description": "Enable or disable TLS" + }, + "root": { + "label": "Ana konu", + "description": "MQTT root topic to use for default/custom servers" + }, + "proxyToClientEnabled": { + "label": "MQTT Client Proxy Enabled", + "description": "Utilizes the network connection to proxy MQTT messages to the client." + }, + "mapReportingEnabled": { + "label": "Map Reporting Enabled", + "description": "Your node will periodically send an unencrypted map report packet to the configured MQTT server, this includes id, short and long name, approximate location, hardware model, role, firmware version, LoRa region, modem preset and primary channel name." + }, + "mapReportSettings": { + "publishIntervalSecs": { + "label": "Map Report Publish Interval (s)", + "description": "Interval in seconds to publish map reports" + }, + "positionPrecision": { + "label": "Approximate Location", + "description": "Position shared will be accurate within this distance", + "options": { + "metric_km23": "Within 23 km", + "metric_km12": "Within 12 km", + "metric_km5_8": "Within 5.8 km", + "metric_km2_9": "Within 2.9 km", + "metric_km1_5": "Within 1.5 km", + "metric_m700": "Within 700 m", + "metric_m350": "Within 350 m", + "metric_m200": "Within 200 m", + "metric_m90": "Within 90 m", + "metric_m50": "Within 50 m", + "imperial_mi15": "Within 15 miles", + "imperial_mi7_3": "Within 7.3 miles", + "imperial_mi3_6": "Within 3.6 miles", + "imperial_mi1_8": "Within 1.8 miles", + "imperial_mi0_9": "Within 0.9 miles", + "imperial_mi0_5": "Within 0.5 miles", + "imperial_mi0_2": "Within 0.2 miles", + "imperial_ft600": "Within 600 feet", + "imperial_ft300": "Within 300 feet", + "imperial_ft150": "Within 150 feet" + } + } + } + }, + "neighborInfo": { + "title": "Neighbor Info Settings", + "description": "Settings for the Neighbor Info module", + "enabled": { + "label": "Enabled", + "description": "Enable or disable Neighbor Info Module" + }, + "updateInterval": { + "label": "Update Interval", + "description": "Interval in seconds of how often we should try to send our Neighbor Info to the mesh" + } + }, + "paxcounter": { + "title": "Paxcounter Settings", + "description": "Settings for the Paxcounter module", + "enabled": { + "label": "Module Enabled", + "description": "Enable Paxcounter" + }, + "paxcounterUpdateInterval": { + "label": "Update Interval (seconds)", + "description": "How long to wait between sending paxcounter packets" + }, + "wifiThreshold": { + "label": "WiFi RSSI Threshold", + "description": "At what WiFi RSSI level should the counter increase. Defaults to -80." + }, + "bleThreshold": { + "label": "BLE RSSI Threshold", + "description": "At what BLE RSSI level should the counter increase. Defaults to -80." + } + }, + "rangeTest": { + "title": "Range Test Settings", + "description": "Settings for the Range Test module", + "enabled": { + "label": "Module Enabled", + "description": "Enable Range Test" + }, + "sender": { + "label": "Message Interval", + "description": "How long to wait between sending test packets" + }, + "save": { + "label": "Save CSV to storage", + "description": "ESP32 Only" + } + }, + "serial": { + "title": "Serial Settings", + "description": "Settings for the Serial module", + "enabled": { + "label": "Module Enabled", + "description": "Enable Serial output" + }, + "echo": { + "label": "Echo", + "description": "Any packets you send will be echoed back to your device" + }, + "rxd": { + "label": "Receive Pin", + "description": "Set the GPIO pin to the RXD pin you have set up." + }, + "txd": { + "label": "Transmit Pin", + "description": "Set the GPIO pin to the TXD pin you have set up." + }, + "baud": { + "label": "Baud Rate", + "description": "The serial baud rate" + }, + "timeout": { + "label": "Zaman Aşımı", + "description": "Seconds to wait before we consider your packet as 'done'" + }, + "mode": { + "label": "Mode", + "description": "Select Mode" + }, + "overrideConsoleSerialPort": { + "label": "Override Console Serial Port", + "description": "If you have a serial port connected to the console, this will override it." + } + }, + "storeForward": { + "title": "Store & Forward Settings", + "description": "Settings for the Store & Forward module", + "enabled": { + "label": "Module Enabled", + "description": "Enable Store & Forward" + }, + "heartbeat": { + "label": "Heartbeat Enabled", + "description": "Enable Store & Forward heartbeat" + }, + "records": { + "label": "Kayıt sayısı", + "description": "Number of records to store" + }, + "historyReturnMax": { + "label": "Geçmiş geri dönüş maksimum", + "description": "Max number of records to return" + }, + "historyReturnWindow": { + "label": "Geçmiş geri dönüş penceresi", + "description": "Bu zaman penceresinden kayıtları döndür (dakika)" + } + }, + "telemetry": { + "title": "Telemetry Settings", + "description": "Settings for the Telemetry module", + "deviceUpdateInterval": { + "label": "Device Metrics", + "description": "Cihaz metrikleri güncelleme aralığı (saniye)" + }, + "environmentUpdateInterval": { + "label": "Çevre metrikleri güncelleme aralığı (saniye)", + "description": "" + }, + "environmentMeasurementEnabled": { + "label": "Module Enabled", + "description": "Enable the Environment Telemetry" + }, + "environmentScreenEnabled": { + "label": "Displayed on Screen", + "description": "Show the Telemetry Module on the OLED" + }, + "environmentDisplayFahrenheit": { + "label": "Display Fahrenheit", + "description": "Display temp in Fahrenheit" + }, + "airQualityEnabled": { + "label": "Air Quality Enabled", + "description": "Enable the Air Quality Telemetry" + }, + "airQualityInterval": { + "label": "Air Quality Update Interval", + "description": "How often to send Air Quality data over the mesh" + }, + "powerMeasurementEnabled": { + "label": "Power Measurement Enabled", + "description": "Enable the Power Measurement Telemetry" + }, + "powerUpdateInterval": { + "label": "Power Update Interval", + "description": "How often to send Power data over the mesh" + }, + "powerScreenEnabled": { + "label": "Power Screen Enabled", + "description": "Enable the Power Telemetry Screen" + } + } } diff --git a/packages/web/public/i18n/locales/tr-TR/nodes.json b/packages/web/public/i18n/locales/tr-TR/nodes.json index 8ee002455..6b6bbc974 100644 --- a/packages/web/public/i18n/locales/tr-TR/nodes.json +++ b/packages/web/public/i18n/locales/tr-TR/nodes.json @@ -1,63 +1,59 @@ { - "nodeDetail": { - "publicKeyEnabled": { - "label": "Public Key Enabled" - }, - "noPublicKey": { - "label": "No Public Key" - }, - "directMessage": { - "label": "Direk Mesaj {{shortName}}" - }, - "favorite": { - "label": "Favori", - "tooltip": "Add or remove this node from your favorites" - }, - "notFavorite": { - "label": "Not a Favorite" - }, - "error": { - "label": "Hata", - "text": "An error occurred while fetching node details. Please try again later." - }, - "status": { - "heard": "Heard", - "mqtt": "MQTT" - }, - "elevation": { - "label": "Elevation" - }, - "channelUtil": { - "label": "Channel Util" - }, - "airtimeUtil": { - "label": "Airtime Util" - } - }, - "nodesTable": { - "headings": { - "longName": "Long Name", - "connection": "Connection", - "lastHeard": "Last Heard", - "encryption": "Encryption", - "model": "Model", - "macAddress": "MAC Address" - }, - "connectionStatus": { - "direct": "Doğrudan", - "away": "away", - "unknown": "-", - "viaMqtt": ", via MQTT" - }, - "lastHeardStatus": { - "never": "Hiçbir zaman" - } - }, - "actions": { - "added": "Eklendi", - "removed": "Kaldırıldı", - "ignoreNode": "Ignore Node", - "unignoreNode": "Unignore Node", - "requestPosition": "Request Position" - } + "nodeDetail": { + "publicKeyEnabled": { + "label": "Public Key Enabled" + }, + "noPublicKey": { + "label": "No Public Key" + }, + "directMessage": { + "label": "Direk Mesaj {{shortName}}" + }, + "favorite": { + "label": "Favori", + "tooltip": "Add or remove this node from your favorites" + }, + "notFavorite": { + "label": "Not a Favorite" + }, + "error": { + "label": "Hata", + "text": "An error occurred while fetching node details. Please try again later." + }, + "status": { + "heard": "Heard", + "mqtt": "MQTT" + }, + "elevation": { + "label": "Elevation" + }, + "channelUtil": { + "label": "Channel Util" + }, + "airtimeUtil": { + "label": "Airtime Util" + } + }, + "nodesTable": { + "headings": { + "longName": "Long Name", + "connection": "Connection", + "lastHeard": "Last Heard", + "encryption": "Encryption", + "model": "Model", + "macAddress": "MAC Address" + }, + "connectionStatus": { + "direct": "Doğrudan", + "away": "away", + "viaMqtt": ", via MQTT" + } + }, + "actions": { + "added": "Eklendi", + "removed": "Kaldırıldı", + "ignoreNode": "Ignore Node", + "unignoreNode": "Unignore Node", + "requestPosition": "Request Position" + } } diff --git a/packages/web/public/i18n/locales/tr-TR/ui.json b/packages/web/public/i18n/locales/tr-TR/ui.json index 5fefb77c7..31c79f483 100644 --- a/packages/web/public/i18n/locales/tr-TR/ui.json +++ b/packages/web/public/i18n/locales/tr-TR/ui.json @@ -1,228 +1,230 @@ { - "navigation": { - "title": "Navigation", - "messages": "Mesajlar", - "map": "Harita", - "config": "Config", - "radioConfig": "Radio Config", - "moduleConfig": "Module Config", - "channels": "Kanallar", - "nodes": "Düğümler" - }, - "app": { - "title": "Meshtastic", - "logo": "Meshtastic Logo" - }, - "sidebar": { - "collapseToggle": { - "button": { - "open": "Open sidebar", - "close": "Close sidebar" - } - }, - "deviceInfo": { - "volts": "{{voltage}} volt", - "firmware": { - "title": "Yazılım", - "version": "v{{version}}", - "buildDate": "Build date: {{date}}" - }, - "deviceName": { - "title": "Device Name", - "changeName": "Change Device Name", - "placeholder": "Enter device name" - }, - "editDeviceName": "Edit device name" - } - }, - "batteryStatus": { - "charging": "{{level}}% charging", - "pluggedIn": "Plugged in", - "title": "Pil" - }, - "search": { - "nodes": "Search nodes...", - "channels": "Search channels...", - "commandPalette": "Search commands..." - }, - "toast": { - "positionRequestSent": { - "title": "Position request sent." - }, - "requestingPosition": { - "title": "Requesting position, please wait..." - }, - "sendingTraceroute": { - "title": "Sending Traceroute, please wait..." - }, - "tracerouteSent": { - "title": "Traceroute sent." - }, - "savedChannel": { - "title": "Saved Channel: {{channelName}}" - }, - "messages": { - "pkiEncryption": { - "title": "Chat is using PKI encryption." - }, - "pskEncryption": { - "title": "Chat is using PSK encryption." - } - }, - "configSaveError": { - "title": "Error Saving Config", - "description": "An error occurred while saving the configuration." - }, - "validationError": { - "title": "Config Errors Exist", - "description": "Please fix the configuration errors before saving." - }, - "saveSuccess": { - "title": "Saving Config", - "description": "The configuration change {{case}} has been saved." - }, - "favoriteNode": { - "title": "{{action}} {{nodeName}} {{direction}} favorites.", - "action": { - "added": "Added", - "removed": "Removed", - "to": "to", - "from": "from" - } - }, - "ignoreNode": { - "title": "{{action}} {{nodeName}} {{direction}} ignore list", - "action": { - "added": "Added", - "removed": "Removed", - "to": "to", - "from": "from" - } - } - }, - "notifications": { - "copied": { - "label": "Copied!" - }, - "copyToClipboard": { - "label": "Copy to clipboard" - }, - "hidePassword": { - "label": "Şifreyi gizle" - }, - "showPassword": { - "label": "Şifreyi göster" - }, - "deliveryStatus": { - "delivered": "Delivered", - "failed": "Delivery Failed", - "waiting": "Waiting", - "unknown": "Unknown" - } - }, - "general": { - "label": "General" - }, - "hardware": { - "label": "Donanım" - }, - "metrics": { - "label": "Metrics" - }, - "role": { - "label": "Rol" - }, - "filter": { - "label": "Filtre" - }, - "advanced": { - "label": "Advanced" - }, - "clearInput": { - "label": "Clear input" - }, - "resetFilters": { - "label": "Reset Filters" - }, - "nodeName": { - "label": "Node name/number", - "placeholder": "Meshtastic 1234" - }, - "airtimeUtilization": { - "label": "Airtime Utilization (%)" - }, - "batteryLevel": { - "label": "Battery level (%)", - "labelText": "Battery level (%): {{value}}" - }, - "batteryVoltage": { - "label": "Battery voltage (V)", - "title": "Voltaj" - }, - "channelUtilization": { - "label": "Channel Utilization (%)" - }, - "hops": { - "direct": "Doğrudan", - "label": "Number of hops", - "text": "Number of hops: {{value}}" - }, - "lastHeard": { - "label": "Son duyulma", - "labelText": "Last heard: {{value}}", - "nowLabel": "Now" - }, - "snr": { - "label": "SNR (db)" - }, - "favorites": { - "label": "Favorites" - }, - "hide": { - "label": "Hide" - }, - "showOnly": { - "label": "Show Only" - }, - "viaMqtt": { - "label": "Connected via MQTT" - }, - "hopsUnknown": { - "label": "Unknown number of hops" - }, - "showUnheard": { - "label": "Never heard" - }, - "language": { - "label": "Dil", - "changeLanguage": "Change Language" - }, - "theme": { - "dark": "Koyu", - "light": "Açık", - "system": "Automatic", - "changeTheme": "Change Color Scheme" - }, - "errorPage": { - "title": "This is a little embarrassing...", - "description1": "We are really sorry but an error occurred in the web client that caused it to crash.
This is not supposed to happen, and we are working hard to fix it.", - "description2": "The best way to prevent this from happening again to you or anyone else is to report the issue to us.", - "reportInstructions": "Please include the following information in your report:", - "reportSteps": { - "step1": "What you were doing when the error occurred", - "step2": "What you expected to happen", - "step3": "What actually happened", - "step4": "Any other relevant information" - }, - "reportLink": "You can report the issue to our <0>GitHub", - "dashboardLink": "Return to the <0>dashboard", - "detailsSummary": "Error Details", - "errorMessageLabel": "Error message:", - "stackTraceLabel": "Stack trace:", - "fallbackError": "{{error}}" - }, - "footer": { - "text": "Powered by <0>▲ Vercel | Meshtastic® is a registered trademark of Meshtastic LLC. | <1>Legal Information", - "commitSha": "Commit SHA: {{sha}}" - } + "navigation": { + "title": "Navigation", + "messages": "Mesajlar", + "map": "Harita", + "settings": "Ayarlar", + "channels": "Kanallar", + "radioConfig": "Radio Config", + "deviceConfig": "Cihaz Ayarı", + "moduleConfig": "Module Config", + "manageConnections": "Manage Connections", + "nodes": "Düğümler" + }, + "app": { + "title": "Meshtastic", + "logo": "Meshtastic Logo" + }, + "sidebar": { + "collapseToggle": { + "button": { + "open": "Open sidebar", + "close": "Close sidebar" + } + }, + "deviceInfo": { + "volts": "{{voltage}} volt", + "firmware": { + "title": "Yazılım", + "version": "v{{version}}", + "buildDate": "Build date: {{date}}" + } + } + }, + "batteryStatus": { + "charging": "{{level}}% charging", + "pluggedIn": "Plugged in", + "title": "Pil" + }, + "search": { + "nodes": "Search nodes...", + "channels": "Search channels...", + "commandPalette": "Search commands..." + }, + "toast": { + "positionRequestSent": { + "title": "Position request sent." + }, + "requestingPosition": { + "title": "Requesting position, please wait..." + }, + "sendingTraceroute": { + "title": "Sending Traceroute, please wait..." + }, + "tracerouteSent": { + "title": "Traceroute sent." + }, + "savedChannel": { + "title": "Saved Channel: {{channelName}}" + }, + "messages": { + "pkiEncryption": { + "title": "Chat is using PKI encryption." + }, + "pskEncryption": { + "title": "Chat is using PSK encryption." + } + }, + "configSaveError": { + "title": "Error Saving Config", + "description": "An error occurred while saving the configuration." + }, + "validationError": { + "title": "Config Errors Exist", + "description": "Please fix the configuration errors before saving." + }, + "saveSuccess": { + "title": "Saving Config", + "description": "The configuration change {{case}} has been saved." + }, + "saveAllSuccess": { + "title": "Saved", + "description": "All configuration changes have been saved." + }, + "favoriteNode": { + "title": "{{action}} {{nodeName}} {{direction}} favorites.", + "action": { + "added": "Added", + "removed": "Removed", + "to": "to", + "from": "from" + } + }, + "ignoreNode": { + "title": "{{action}} {{nodeName}} {{direction}} ignore list", + "action": { + "added": "Added", + "removed": "Removed", + "to": "to", + "from": "from" + } + } + }, + "notifications": { + "copied": { + "label": "Copied!" + }, + "copyToClipboard": { + "label": "Copy to clipboard" + }, + "hidePassword": { + "label": "Şifreyi gizle" + }, + "showPassword": { + "label": "Şifreyi göster" + }, + "deliveryStatus": { + "delivered": "Delivered", + "failed": "Delivery Failed", + "waiting": "Waiting", + "unknown": "Unknown" + } + }, + "general": { + "label": "General" + }, + "hardware": { + "label": "Donanım" + }, + "metrics": { + "label": "Metrics" + }, + "role": { + "label": "Rol" + }, + "filter": { + "label": "Filtre" + }, + "advanced": { + "label": "Advanced" + }, + "clearInput": { + "label": "Clear input" + }, + "resetFilters": { + "label": "Reset Filters" + }, + "nodeName": { + "label": "Node name/number", + "placeholder": "Meshtastic 1234" + }, + "airtimeUtilization": { + "label": "Airtime Utilization (%)", + "short": "Airtime Util. (%)" + }, + "batteryLevel": { + "label": "Battery level (%)", + "labelText": "Battery level (%): {{value}}" + }, + "batteryVoltage": { + "label": "Battery voltage (V)", + "title": "Voltaj" + }, + "channelUtilization": { + "label": "Channel Utilization (%)", + "short": "Channel Util. (%)" + }, + "hops": { + "direct": "Doğrudan", + "label": "Number of hops", + "text": "Number of hops: {{value}}" + }, + "lastHeard": { + "label": "Son duyulma", + "labelText": "Last heard: {{value}}", + "nowLabel": "Now" + }, + "snr": { + "label": "SNR (db)" + }, + "favorites": { + "label": "Favorites" + }, + "hide": { + "label": "Hide" + }, + "showOnly": { + "label": "Show Only" + }, + "viaMqtt": { + "label": "Connected via MQTT" + }, + "hopsUnknown": { + "label": "Unknown number of hops" + }, + "showUnheard": { + "label": "Never heard" + }, + "language": { + "label": "Dil", + "changeLanguage": "Change Language" + }, + "theme": { + "dark": "Koyu", + "light": "Açık", + "system": "Automatic", + "changeTheme": "Change Color Scheme" + }, + "errorPage": { + "title": "This is a little embarrassing...", + "description1": "We are really sorry but an error occurred in the web client that caused it to crash.
This is not supposed to happen, and we are working hard to fix it.", + "description2": "The best way to prevent this from happening again to you or anyone else is to report the issue to us.", + "reportInstructions": "Please include the following information in your report:", + "reportSteps": { + "step1": "What you were doing when the error occurred", + "step2": "What you expected to happen", + "step3": "What actually happened", + "step4": "Any other relevant information" + }, + "reportLink": "You can report the issue to our <0>GitHub", + "connectionsLink": "Return to the <0>connections", + "detailsSummary": "Error Details", + "errorMessageLabel": "Error message:", + "stackTraceLabel": "Stack trace:", + "fallbackError": "{{error}}" + }, + "footer": { + "text": "Powered by <0>▲ Vercel | Meshtastic® is a registered trademark of Meshtastic LLC. | <1>Legal Information", + "commitSha": "Commit SHA: {{sha}}" + } } diff --git a/packages/web/public/i18n/locales/uk-UA/channels.json b/packages/web/public/i18n/locales/uk-UA/channels.json index 3e871201c..113894871 100644 --- a/packages/web/public/i18n/locales/uk-UA/channels.json +++ b/packages/web/public/i18n/locales/uk-UA/channels.json @@ -1,69 +1,71 @@ { - "page": { - "sectionLabel": "Канали", - "channelName": "Канал: {{channelName}}", - "broadcastLabel": "Основний", - "channelIndex": "Кн {{index}}" - }, - "validation": { - "pskInvalid": "Please enter a valid {{bits}} bit PSK." - }, - "settings": { - "label": "Channel Settings", - "description": "Crypto, MQTT & misc settings" - }, - "role": { - "label": "Роль", - "description": "Device telemetry is sent over PRIMARY. Only one PRIMARY allowed", - "options": { - "primary": "PRIMARY", - "disabled": "DISABLED", - "secondary": "SECONDARY" - } - }, - "psk": { - "label": "Pre-Shared Key", - "description": "Supported PSK lengths: 256-bit, 128-bit, 8-bit, Empty (0-bit)", - "generate": "Згенерувати" - }, - "name": { - "label": "Ім'я", - "description": "A unique name for the channel <12 bytes, leave blank for default" - }, - "uplinkEnabled": { - "label": "Uplink Enabled", - "description": "Send messages from the local mesh to MQTT" - }, - "downlinkEnabled": { - "label": "Downlink Enabled", - "description": "Send messages from MQTT to the local mesh" - }, - "positionPrecision": { - "label": "Місце розташування", - "description": "The precision of the location to share with the channel. Can be disabled.", - "options": { - "none": "Не повідомляти місце знаходження", - "precise": "Точне місце розташування", - "metric_km23": "У межах 23 км", - "metric_km12": "У межах 12 км", - "metric_km5_8": "У межах 5,8 км", - "metric_km2_9": "У межах 2,9 км", - "metric_km1_5": "У межах 1,5 км", - "metric_m700": "У межах 700 м", - "metric_m350": "У межах 350 м", - "metric_m200": "У межах 200 м", - "metric_m90": "У межах 90 м", - "metric_m50": "У межах 50 м", - "imperial_mi15": "У межах 15 миль", - "imperial_mi7_3": "У межах 7,3 милі", - "imperial_mi3_6": "У межах 3,6 милі", - "imperial_mi1_8": "У межах 1,8 милі", - "imperial_mi0_9": "У межах 0,9 милі", - "imperial_mi0_5": "У межах 0,5 милі", - "imperial_mi0_2": "У межах 0,2 милі", - "imperial_ft600": "У межах 600 фт", - "imperial_ft300": "У межах 300 фт", - "imperial_ft150": "У межах 150 фт" - } - } + "page": { + "sectionLabel": "Канали", + "channelName": "Канал: {{channelName}}", + "broadcastLabel": "Основний", + "channelIndex": "Кн {{index}}", + "import": "Імпортувати", + "export": "Export" + }, + "validation": { + "pskInvalid": "Please enter a valid {{bits}} bit PSK." + }, + "settings": { + "label": "Channel Settings", + "description": "Crypto, MQTT & misc settings" + }, + "role": { + "label": "Роль", + "description": "Device telemetry is sent over PRIMARY. Only one PRIMARY allowed", + "options": { + "primary": "PRIMARY", + "disabled": "DISABLED", + "secondary": "SECONDARY" + } + }, + "psk": { + "label": "Pre-Shared Key", + "description": "Supported PSK lengths: 256-bit, 128-bit, 8-bit, Empty (0-bit)", + "generate": "Згенерувати" + }, + "name": { + "label": "Ім'я", + "description": "A unique name for the channel <12 bytes, leave blank for default" + }, + "uplinkEnabled": { + "label": "Uplink Enabled", + "description": "Send messages from the local mesh to MQTT" + }, + "downlinkEnabled": { + "label": "Downlink Enabled", + "description": "Send messages from MQTT to the local mesh" + }, + "positionPrecision": { + "label": "Місце розташування", + "description": "The precision of the location to share with the channel. Can be disabled.", + "options": { + "none": "Не повідомляти місце знаходження", + "precise": "Точне місце розташування", + "metric_km23": "У межах 23 км", + "metric_km12": "У межах 12 км", + "metric_km5_8": "У межах 5,8 км", + "metric_km2_9": "У межах 2,9 км", + "metric_km1_5": "У межах 1,5 км", + "metric_m700": "У межах 700 м", + "metric_m350": "У межах 350 м", + "metric_m200": "У межах 200 м", + "metric_m90": "У межах 90 м", + "metric_m50": "У межах 50 м", + "imperial_mi15": "У межах 15 миль", + "imperial_mi7_3": "У межах 7,3 милі", + "imperial_mi3_6": "У межах 3,6 милі", + "imperial_mi1_8": "У межах 1,8 милі", + "imperial_mi0_9": "У межах 0,9 милі", + "imperial_mi0_5": "У межах 0,5 милі", + "imperial_mi0_2": "У межах 0,2 милі", + "imperial_ft600": "У межах 600 фт", + "imperial_ft300": "У межах 300 фт", + "imperial_ft150": "У межах 150 фт" + } + } } diff --git a/packages/web/public/i18n/locales/uk-UA/commandPalette.json b/packages/web/public/i18n/locales/uk-UA/commandPalette.json index b02452886..e8df07ceb 100644 --- a/packages/web/public/i18n/locales/uk-UA/commandPalette.json +++ b/packages/web/public/i18n/locales/uk-UA/commandPalette.json @@ -15,7 +15,6 @@ "messages": "Повідомлення", "map": "Мапа", "config": "Config", - "channels": "Канали", "nodes": "Вузли" } }, @@ -45,7 +44,8 @@ "label": "Debug", "command": { "reconfigure": "Reconfigure", - "clearAllStoredMessages": "Clear All Stored Message" + "clearAllStoredMessages": "Clear All Stored Message", + "clearAllStores": "Clear All Local Storage" } } } diff --git a/packages/web/public/i18n/locales/uk-UA/common.json b/packages/web/public/i18n/locales/uk-UA/common.json index c6541320c..3b28b6943 100644 --- a/packages/web/public/i18n/locales/uk-UA/common.json +++ b/packages/web/public/i18n/locales/uk-UA/common.json @@ -1,142 +1,165 @@ { - "button": { - "apply": "Застосувати", - "backupKey": "Backup Key", - "cancel": "Скасувати", - "clearMessages": "Clear Messages", - "close": "Закрити", - "confirm": "Confirm", - "delete": "Видалити", - "dismiss": "Dismiss", - "download": "Download", - "export": "Export", - "generate": "Згенерувати", - "regenerate": "Перегенерувати", - "import": "Імпортувати", - "message": "Повідомлення", - "now": "Зараз", - "ok": "Гаразд", - "print": "Print", - "remove": "Видалити", - "requestNewKeys": "Request New Keys", - "requestPosition": "Запитати позицію", - "reset": "Скинути", - "save": "Зберегти", - "scanQr": "Сканувати QR-код", - "traceRoute": "Trace Route", - "submit": "Submit" - }, - "app": { - "title": "Meshtastic", - "fullTitle": "Meshtastic Web Client" - }, - "loading": "Завантаження...", - "unit": { - "cps": "CPS", - "dbm": "дБм", - "hertz": "Гц", - "hop": { - "one": "Hop", - "plural": "Hops" - }, - "hopsAway": { - "one": "{{count}} hop away", - "plural": "{{count}} hops away", - "unknown": "Unknown hops away" - }, - "megahertz": "МГц", - "raw": "raw", - "meter": { - "one": "Метр", - "plural": "Meters", - "suffix": "м" - }, - "minute": { - "one": "Minute", - "plural": "Хвилин" - }, - "hour": { - "one": "Година", - "plural": "Годин" - }, - "millisecond": { - "one": "Мілісекунда", - "plural": "Мілісекунди", - "suffix": "мс" - }, - "second": { - "one": "Секунда", - "plural": "Секунд" - }, - "day": { - "one": "День", - "plural": "Днів" - }, - "month": { - "one": "Місяць", - "plural": "Місяців" - }, - "year": { - "one": "Year", - "plural": "Years" - }, - "snr": "SNR", - "volt": { - "one": "Вольт", - "plural": "Volts", - "suffix": "V" - }, - "record": { - "one": "Records", - "plural": "Records" - } - }, - "security": { - "0bit": "Empty", - "8bit": "8 bit", - "128bit": "128 bit", - "256bit": "256 bit" - }, - "unknown": { - "longName": "Unknown", - "shortName": "UNK", - "notAvailable": "N/A", - "num": "??" - }, - "nodeUnknownPrefix": "!", - "unset": "UNSET", - "fallbackName": "Meshtastic {{last4}}", - "node": "Node", - "formValidation": { - "unsavedChanges": "Unsaved changes", - "tooBig": { - "string": "Too long, expected less than or equal to {{maximum}} characters.", - "number": "Too big, expected a number smaller than or equal to {{maximum}}.", - "bytes": "Too big, expected less than or equal to {{params.maximum}} bytes." - }, - "tooSmall": { - "string": "Too short, expected more than or equal to {{minimum}} characters.", - "number": "Too small, expected a number larger than or equal to {{minimum}}." - }, - "invalidFormat": { - "ipv4": "Невірний формат, потрібна IPv4-адреса.", - "key": "Invalid format, expected a Base64 encoded pre-shared key (PSK)." - }, - "invalidType": { - "number": "Invalid type, expected a number." - }, - "pskLength": { - "0bit": "Ключ повинен бути пустим.", - "8bit": "Key is required to be an 8 bit pre-shared key (PSK).", - "128bit": "Key is required to be a 128 bit pre-shared key (PSK).", - "256bit": "Key is required to be a 256 bit pre-shared key (PSK)." - }, - "required": { - "generic": "Це поле є обов'язковим.", - "managed": "At least one admin key is requred if the node is managed.", - "key": "Key is required." - } - }, - "yes": "Yes", - "no": "No" + "button": { + "apply": "Застосувати", + "addConnection": "Add Connection", + "saveConnection": "Save connection", + "backupKey": "Backup Key", + "cancel": "Скасувати", + "connect": "Connect", + "clearMessages": "Clear Messages", + "close": "Закрити", + "confirm": "Confirm", + "delete": "Видалити", + "dismiss": "Dismiss", + "download": "Download", + "disconnect": "Disconnect", + "export": "Export", + "generate": "Згенерувати", + "regenerate": "Перегенерувати", + "import": "Імпортувати", + "message": "Повідомлення", + "now": "Зараз", + "ok": "Гаразд", + "print": "Print", + "remove": "Видалити", + "requestNewKeys": "Request New Keys", + "requestPosition": "Запитати позицію", + "reset": "Скинути", + "retry": "Retry", + "save": "Зберегти", + "setDefault": "Set as default", + "unsetDefault": "Unset default", + "scanQr": "Сканувати QR-код", + "traceRoute": "Trace Route", + "submit": "Submit" + }, + "app": { + "title": "Meshtastic", + "fullTitle": "Meshtastic Web Client" + }, + "loading": "Завантаження...", + "unit": { + "cps": "CPS", + "dbm": "дБм", + "hertz": "Гц", + "hop": { + "one": "Hop", + "plural": "Hops" + }, + "hopsAway": { + "one": "{{count}} hop away", + "plural": "{{count}} hops away", + "unknown": "Unknown hops away" + }, + "megahertz": "МГц", + "kilohertz": "кГц", + "raw": "raw", + "meter": { + "one": "Метр", + "plural": "Meters", + "suffix": "м" + }, + "kilometer": { + "one": "Kilometer", + "plural": "Kilometers", + "suffix": "km" + }, + "minute": { + "one": "Minute", + "plural": "Хвилин" + }, + "hour": { + "one": "Година", + "plural": "Годин" + }, + "millisecond": { + "one": "Мілісекунда", + "plural": "Мілісекунди", + "suffix": "мс" + }, + "second": { + "one": "Секунда", + "plural": "Секунд" + }, + "day": { + "one": "День", + "plural": "Днів", + "today": "Today", + "yesterday": "Yesterday" + }, + "month": { + "one": "Місяць", + "plural": "Місяців" + }, + "year": { + "one": "Year", + "plural": "Years" + }, + "snr": "SNR", + "volt": { + "one": "Вольт", + "plural": "Volts", + "suffix": "V" + }, + "record": { + "one": "Records", + "plural": "Records" + }, + "degree": { + "one": "Degree", + "plural": "Degrees", + "suffix": "°" + } + }, + "security": { + "0bit": "Empty", + "8bit": "8 bit", + "128bit": "128 bit", + "256bit": "256 bit" + }, + "unknown": { + "longName": "Unknown", + "shortName": "UNK", + "notAvailable": "N/A", + "num": "??" + }, + "nodeUnknownPrefix": "!", + "unset": "UNSET", + "fallbackName": "Meshtastic {{last4}}", + "node": "Node", + "formValidation": { + "unsavedChanges": "Unsaved changes", + "tooBig": { + "string": "Too long, expected less than or equal to {{maximum}} characters.", + "number": "Too big, expected a number smaller than or equal to {{maximum}}.", + "bytes": "Too big, expected less than or equal to {{params.maximum}} bytes." + }, + "tooSmall": { + "string": "Too short, expected more than or equal to {{minimum}} characters.", + "number": "Too small, expected a number larger than or equal to {{minimum}}." + }, + "invalidFormat": { + "ipv4": "Невірний формат, потрібна IPv4-адреса.", + "key": "Invalid format, expected a Base64 encoded pre-shared key (PSK)." + }, + "invalidType": { + "number": "Invalid type, expected a number." + }, + "pskLength": { + "0bit": "Ключ повинен бути пустим.", + "8bit": "Key is required to be an 8 bit pre-shared key (PSK).", + "128bit": "Key is required to be a 128 bit pre-shared key (PSK).", + "256bit": "Key is required to be a 256 bit pre-shared key (PSK)." + }, + "required": { + "generic": "Це поле є обов'язковим.", + "managed": "At least one admin key is requred if the node is managed.", + "key": "Key is required." + }, + "invalidOverrideFreq": { + "number": "Invalid format, expected a value in the range 410-930 MHz or 0 (use default)." + } + }, + "yes": "Yes", + "no": "No" } diff --git a/packages/web/public/i18n/locales/uk-UA/config.json b/packages/web/public/i18n/locales/uk-UA/config.json new file mode 100644 index 000000000..26996ac80 --- /dev/null +++ b/packages/web/public/i18n/locales/uk-UA/config.json @@ -0,0 +1,458 @@ +{ + "page": { + "title": "Налаштування", + "tabUser": "Користувач", + "tabChannels": "Канали", + "tabBluetooth": "Bluetooth", + "tabDevice": "Пристрій", + "tabDisplay": "Дисплей", + "tabLora": "LoRa", + "tabNetwork": "Мережа", + "tabPosition": "Position", + "tabPower": "Живлення", + "tabSecurity": "Безпека" + }, + "sidebar": { + "label": "Налаштування" + }, + "device": { + "title": "Налаштування пристрою", + "description": "Settings for the device", + "buttonPin": { + "description": "Button pin override", + "label": "Button Pin" + }, + "buzzerPin": { + "description": "Buzzer pin override", + "label": "Buzzer Pin" + }, + "disableTripleClick": { + "description": "Disable triple click", + "label": "Disable Triple Click" + }, + "doubleTapAsButtonPress": { + "description": "Treat double tap as button press", + "label": "Double Tap as Button Press" + }, + "ledHeartbeatDisabled": { + "description": "Disable default blinking LED", + "label": "LED Heartbeat Disabled" + }, + "nodeInfoBroadcastInterval": { + "description": "How often to broadcast node info", + "label": "Node Info Broadcast Interval" + }, + "posixTimezone": { + "description": "The POSIX timezone string for the device", + "label": "Часова зона POSIX" + }, + "rebroadcastMode": { + "description": "How to handle rebroadcasting", + "label": "Rebroadcast Mode" + }, + "role": { + "description": "What role the device performs on the mesh", + "label": "Роль" + } + }, + "bluetooth": { + "title": "Налаштування Bluetooth", + "description": "Settings for the Bluetooth module", + "note": "Note: Some devices (ESP32) cannot use both Bluetooth and WiFi at the same time.", + "enabled": { + "description": "Увімкнути або вимкнути Bluetooth", + "label": "Увімкнено" + }, + "pairingMode": { + "description": "Pin selection behaviour.", + "label": "Pairing mode" + }, + "pin": { + "description": "Pin to use when pairing", + "label": "Pin" + } + }, + "display": { + "description": "Settings for the device display", + "title": "Display Settings", + "headingBold": { + "description": "Bolden the heading text", + "label": "Bold Heading" + }, + "carouselDelay": { + "description": "How fast to cycle through windows", + "label": "Carousel Delay" + }, + "compassNorthTop": { + "description": "Fix north to the top of compass", + "label": "Compass North Top" + }, + "displayMode": { + "description": "Screen layout variant", + "label": "Display Mode" + }, + "displayUnits": { + "description": "Display metric or imperial units", + "label": "Display Units" + }, + "flipScreen": { + "description": "Flip display 180 degrees", + "label": "Flip Screen" + }, + "gpsDisplayUnits": { + "description": "Coordinate display format", + "label": "GPS Display Units" + }, + "oledType": { + "description": "Type of OLED screen attached to the device", + "label": "OLED Type" + }, + "screenTimeout": { + "description": "Turn off the display after this long", + "label": "Screen Timeout" + }, + "twelveHourClock": { + "description": "Use 12-hour clock format", + "label": "12-Hour Clock" + }, + "wakeOnTapOrMotion": { + "description": "Wake the device on tap or motion", + "label": "Wake on Tap or Motion" + } + }, + "lora": { + "title": "Mesh Settings", + "description": "Settings for the LoRa mesh", + "bandwidth": { + "description": "Channel bandwidth in kHz", + "label": "Bandwidth" + }, + "boostedRxGain": { + "description": "Boosted RX gain", + "label": "Boosted RX Gain" + }, + "codingRate": { + "description": "The denominator of the coding rate", + "label": "Coding Rate" + }, + "frequencyOffset": { + "description": "Frequency offset to correct for crystal calibration errors", + "label": "Frequency Offset" + }, + "frequencySlot": { + "description": "LoRa frequency channel number", + "label": "Frequency Slot" + }, + "hopLimit": { + "description": "Maximum number of hops", + "label": "Hop Limit" + }, + "ignoreMqtt": { + "description": "Don't forward MQTT messages over the mesh", + "label": "Ігнорувати MQTT" + }, + "modemPreset": { + "description": "Modem preset to use", + "label": "Modem Preset" + }, + "okToMqtt": { + "description": "When set to true, this configuration indicates that the user approves the packet to be uploaded to MQTT. If set to false, remote nodes are requested not to forward packets to MQTT", + "label": "OK to MQTT" + }, + "overrideDutyCycle": { + "description": "Override Duty Cycle", + "label": "Override Duty Cycle" + }, + "overrideFrequency": { + "description": "Override frequency", + "label": "Override Frequency" + }, + "region": { + "description": "Sets the region for your node", + "label": "Регіон" + }, + "spreadingFactor": { + "description": "Indicates the number of chirps per symbol", + "label": "Spreading Factor" + }, + "transmitEnabled": { + "description": "Enable/Disable transmit (TX) from the LoRa radio", + "label": "Transmit Enabled" + }, + "transmitPower": { + "description": "Max transmit power", + "label": "Transmit Power" + }, + "usePreset": { + "description": "Use one of the predefined modem presets", + "label": "Use Preset" + }, + "meshSettings": { + "description": "Settings for the LoRa mesh", + "label": "Mesh Settings" + }, + "waveformSettings": { + "description": "Settings for the LoRa waveform", + "label": "Waveform Settings" + }, + "radioSettings": { + "label": "Radio Settings", + "description": "Settings for the LoRa radio" + } + }, + "network": { + "title": "Налаштування WiFi", + "description": "WiFi radio configuration", + "note": "Note: Some devices (ESP32) cannot use both Bluetooth and WiFi at the same time.", + "addressMode": { + "description": "Address assignment selection", + "label": "Address Mode" + }, + "dns": { + "description": "DNS-сервер", + "label": "DNS" + }, + "ethernetEnabled": { + "description": "Enable or disable the Ethernet port", + "label": "Увімкнено" + }, + "gateway": { + "description": "Default Gateway", + "label": "Шлюз" + }, + "ip": { + "description": "IP Address", + "label": "IP-адреса" + }, + "psk": { + "description": "Network password", + "label": "PSK" + }, + "ssid": { + "description": "Network name", + "label": "SSID" + }, + "subnet": { + "description": "Маска підмережі", + "label": "Підмережа" + }, + "wifiEnabled": { + "description": "Увімкнути або вимкнути WiFi радіо", + "label": "Увімкнено" + }, + "meshViaUdp": { + "label": "Mesh via UDP" + }, + "ntpServer": { + "label": "NTP-сервер" + }, + "rsyslogServer": { + "label": "Rsyslog-сервер" + }, + "ethernetConfigSettings": { + "description": "Ethernet port configuration", + "label": "Ethernet Config" + }, + "ipConfigSettings": { + "description": "IP configuration", + "label": "IP Config" + }, + "ntpConfigSettings": { + "description": "Налаштування NTP", + "label": "NTP Config" + }, + "rsyslogConfigSettings": { + "description": "Rsyslog configuration", + "label": "Налаштування Rsyslog" + }, + "udpConfigSettings": { + "description": "UDP over Mesh configuration", + "label": "Налаштування UDP" + } + }, + "position": { + "title": "Position Settings", + "description": "Settings for the position module", + "broadcastInterval": { + "description": "How often your position is sent out over the mesh", + "label": "Broadcast Interval" + }, + "enablePin": { + "description": "GPS module enable pin override", + "label": "Enable Pin" + }, + "fixedPosition": { + "description": "Don't report GPS position, but a manually-specified one", + "label": "Fixed Position" + }, + "gpsMode": { + "description": "Configure whether device GPS is Enabled, Disabled, or Not Present", + "label": "GPS Mode" + }, + "gpsUpdateInterval": { + "description": "How often a GPS fix should be acquired", + "label": "GPS Update Interval" + }, + "positionFlags": { + "description": "Optional fields to include when assembling position messages. The more fields are selected, the larger the message will be leading to longer airtime usage and a higher risk of packet loss.", + "label": "Position Flags" + }, + "receivePin": { + "description": "GPS module RX pin override", + "label": "Receive Pin" + }, + "smartPositionEnabled": { + "description": "Only send position when there has been a meaningful change in location", + "label": "Enable Smart Position" + }, + "smartPositionMinDistance": { + "description": "Minimum distance (in meters) that must be traveled before a position update is sent", + "label": "Smart Position Minimum Distance" + }, + "smartPositionMinInterval": { + "description": "Minimum interval (in seconds) that must pass before a position update is sent", + "label": "Smart Position Minimum Interval" + }, + "transmitPin": { + "description": "GPS module TX pin override", + "label": "Transmit Pin" + }, + "intervalsSettings": { + "description": "How often to send position updates", + "label": "Intervals" + }, + "flags": { + "placeholder": "Select position flags...", + "altitude": "Висота", + "altitudeGeoidalSeparation": "Altitude Geoidal Separation", + "altitudeMsl": "Altitude is Mean Sea Level", + "dop": "Dilution of precision (DOP) PDOP used by default", + "hdopVdop": "If DOP is set, use HDOP / VDOP values instead of PDOP", + "numSatellites": "Number of satellites", + "sequenceNumber": "Sequence number", + "timestamp": "Мітка часу", + "unset": "Скинути", + "vehicleHeading": "Vehicle heading", + "vehicleSpeed": "Vehicle speed" + } + }, + "power": { + "adcMultiplierOverride": { + "description": "Used for tweaking battery voltage reading", + "label": "ADC Multiplier Override ratio" + }, + "ina219Address": { + "description": "Address of the INA219 battery monitor", + "label": "INA219 Address" + }, + "lightSleepDuration": { + "description": "How long the device will be in light sleep for", + "label": "Light Sleep Duration" + }, + "minimumWakeTime": { + "description": "Minimum amount of time the device will stay awake for after receiving a packet", + "label": "Minimum Wake Time" + }, + "noConnectionBluetoothDisabled": { + "description": "If the device does not receive a Bluetooth connection, the BLE radio will be disabled after this long", + "label": "No Connection Bluetooth Disabled" + }, + "powerSavingEnabled": { + "description": "Select if powered from a low-current source (i.e. solar), to minimize power consumption as much as possible.", + "label": "Увімкнути енергоощадний режим" + }, + "shutdownOnBatteryDelay": { + "description": "Automatically shutdown node after this long when on battery, 0 for indefinite", + "label": "Shutdown on battery delay" + }, + "superDeepSleepDuration": { + "description": "How long the device will be in super deep sleep for", + "label": "Super Deep Sleep Duration" + }, + "powerConfigSettings": { + "description": "Settings for the power module", + "label": "Налаштування живлення" + }, + "sleepSettings": { + "description": "Sleep settings for the power module", + "label": "Налаштування режиму сну" + } + }, + "security": { + "description": "Settings for the Security configuration", + "title": "Налаштування безпеки", + "button_backupKey": "Backup Key", + "adminChannelEnabled": { + "description": "Allow incoming device control over the insecure legacy admin channel", + "label": "Allow Legacy Admin" + }, + "enableDebugLogApi": { + "description": "Output live debug logging over serial, view and export position-redacted device logs over Bluetooth", + "label": "Enable Debug Log API" + }, + "managed": { + "description": "If enabled, device configuration options are only able to be changed remotely by a Remote Admin node via admin messages. Do not enable this option unless at least one suitable Remote Admin node has been setup, and the public key is stored in one of the fields above.", + "label": "Managed" + }, + "privateKey": { + "description": "Used to create a shared key with a remote device", + "label": "Private Key" + }, + "publicKey": { + "description": "Sent out to other nodes on the mesh to allow them to compute a shared secret key", + "label": "Public Key" + }, + "primaryAdminKey": { + "description": "The primary public key authorized to send admin messages to this node", + "label": "Primary Admin Key" + }, + "secondaryAdminKey": { + "description": "The secondary public key authorized to send admin messages to this node", + "label": "Secondary Admin Key" + }, + "serialOutputEnabled": { + "description": "Serial Console over the Stream API", + "label": "Serial Output Enabled" + }, + "tertiaryAdminKey": { + "description": "The tertiary public key authorized to send admin messages to this node", + "label": "Tertiary Admin Key" + }, + "adminSettings": { + "description": "Settings for Admin", + "label": "Admin Settings" + }, + "loggingSettings": { + "description": "Settings for Logging", + "label": "Logging Settings" + } + }, + "user": { + "title": "User Settings", + "description": "Configure your device name and identity settings", + "longName": { + "label": "Довга назва", + "description": "Your full display name (1-40 characters)", + "validation": { + "min": "Long name must be at least 1 character", + "max": "Long name must be at most 40 characters" + } + }, + "shortName": { + "label": "Коротка назва", + "description": "Your abbreviated name (2-4 characters)", + "validation": { + "min": "Short name must be at least 2 characters", + "max": "Short name must be at most 4 characters" + } + }, + "isUnmessageable": { + "label": "Unmessageable", + "description": "Used to identify unmonitored or infrastructure nodes so that messaging is not available to nodes that will never respond." + }, + "isLicensed": { + "label": "Licensed amateur radio (HAM)", + "description": "Enable if you are a licensed amateur radio operator, enabling this option disables encryption and is not compatible with the default Meshtastic network." + } + } +} diff --git a/packages/web/public/i18n/locales/uk-UA/connections.json b/packages/web/public/i18n/locales/uk-UA/connections.json new file mode 100644 index 000000000..6d61136eb --- /dev/null +++ b/packages/web/public/i18n/locales/uk-UA/connections.json @@ -0,0 +1,34 @@ +{ + "page": { + "title": "Connect to a Meshtastic device", + "description": "Add a device connection via HTTP, Bluetooth, or Serial. Your saved connections will be saved in your browser." + }, + "connectionType_ble": "BLE", + "connectionType_serial": "Серійний порт", + "connectionType_network": "Мережа", + "deleteConnection": "Delete connection", + "areYouSure": "This will remove {{name}}. You canot undo this action.", + "moreActions": "More actions", + "noConnections": { + "title": "No connections yet.", + "description": "Create your first connection. It will connect immediately and be saved for later." + }, + "lastConnectedAt": "Last connected: {{date}}", + "neverConnected": "Never connected", + "toasts": { + "connected": "Connected", + "nowConnected": "{{name}} is now connected", + "nowDisconnected": "{{name}} are now disconnecte", + "disconnected": "Відключено", + "failed": "Failed to connect", + "checkConnetion": "Check your device or settings and try again", + "defaultSet": "Default set", + "defaultConnection": "Default connection is now {{nameisconnected}}", + "deleted": "Deleted", + "deletedByName": "{{name}} was removed", + "pickConnectionAgain": "Could not connect. You may need to reselect the device/port.", + "added": "Connection added", + "savedByName": "{{name}} saved.", + "savedCantConnect": "The connection was saved but could not connect." + } +} diff --git a/packages/web/public/i18n/locales/uk-UA/dashboard.json b/packages/web/public/i18n/locales/uk-UA/dashboard.json deleted file mode 100644 index f356d31be..000000000 --- a/packages/web/public/i18n/locales/uk-UA/dashboard.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "dashboard": { - "title": "Connected Devices", - "description": "Manage your connected Meshtastic devices.", - "connectionType_ble": "BLE", - "connectionType_serial": "Серійний порт", - "connectionType_network": "Мережа", - "noDevicesTitle": "No devices connected", - "noDevicesDescription": "Connect a new device to get started.", - "button_newConnection": "New Connection" - } -} diff --git a/packages/web/public/i18n/locales/uk-UA/deviceConfig.json b/packages/web/public/i18n/locales/uk-UA/deviceConfig.json index c89688af4..2fe366f1f 100644 --- a/packages/web/public/i18n/locales/uk-UA/deviceConfig.json +++ b/packages/web/public/i18n/locales/uk-UA/deviceConfig.json @@ -122,7 +122,7 @@ "title": "Mesh Settings", "description": "Settings for the LoRa mesh", "bandwidth": { - "description": "Channel bandwidth in MHz", + "description": "Channel bandwidth in kHz", "label": "Bandwidth" }, "boostedRxGain": { diff --git a/packages/web/public/i18n/locales/uk-UA/dialog.json b/packages/web/public/i18n/locales/uk-UA/dialog.json index a548135a0..4aa88cc4d 100644 --- a/packages/web/public/i18n/locales/uk-UA/dialog.json +++ b/packages/web/public/i18n/locales/uk-UA/dialog.json @@ -1,193 +1,238 @@ { - "deleteMessages": { - "description": "This action will clear all message history. This cannot be undone. Are you sure you want to continue?", - "title": "Очистити всі повідомлення" - }, - "deviceName": { - "description": "The Device will restart once the config is saved.", - "longName": "Довга назва", - "shortName": "Коротка назва", - "title": "Змінити назву пристрою", - "validation": { - "longNameMax": "Long name must not be more than 40 characters", - "shortNameMax": "Short name must not be more than 4 characters", - "longNameMin": "Long name must have at least 1 character", - "shortNameMin": "Short name must have at least 1 character" - } - }, - "import": { - "description": "The current LoRa configuration will be overridden.", - "error": { - "invalidUrl": "Invalid Meshtastic URL" - }, - "channelPrefix": "Канал: ", - "channelSetUrl": "Channel Set/QR Code URL", - "channels": "Канали:", - "usePreset": "Use Preset?", - "title": "Import Channel Set" - }, - "locationResponse": { - "title": "Розташування: {{identifier}}", - "altitude": "Висота: ", - "coordinates": "Координати: ", - "noCoordinates": "No Coordinates" - }, - "pkiRegenerateDialog": { - "title": "Regenerate Pre-Shared Key?", - "description": "Are you sure you want to regenerate the pre-shared key?", - "regenerate": "Перегенерувати" - }, - "newDeviceDialog": { - "title": "Connect New Device", - "https": "https", - "http": "http", - "tabHttp": "HTTP", - "tabBluetooth": "Bluetooth", - "tabSerial": "Серійний порт", - "useHttps": "Використовувати HTTPS", - "connecting": "Підключення...", - "connect": "Connect", - "connectionFailedAlert": { - "title": "Connection Failed", - "descriptionPrefix": "Could not connect to the device. ", - "httpsHint": "If using HTTPS, you may need to accept a self-signed certificate first. ", - "openLinkPrefix": "Please open ", - "openLinkSuffix": " in a new tab", - "acceptTlsWarningSuffix": ", accept any TLS warnings if prompted, then try again", - "learnMoreLink": "Learn more" - }, - "httpConnection": { - "label": "IP Address/Hostname", - "placeholder": "000.000.000.000 / meshtastic.local" - }, - "serialConnection": { - "noDevicesPaired": "No devices paired yet.", - "newDeviceButton": "Новий пристрій", - "deviceIdentifier": "# {{index}} - {{vendorId}} - {{productId}}" - }, - "bluetoothConnection": { - "noDevicesPaired": "No devices paired yet.", - "newDeviceButton": "Новий пристрій", - "connectionFailed": "Connection failed", - "deviceDisconnected": "Device disconnected", - "unknownDevice": "Unknown Device", - "errorLoadingDevices": "Error loading devices", - "unknownErrorLoadingDevices": "Unknown error loading devices" - }, - "validation": { - "requiresWebBluetooth": "This connection type requires <0>Web Bluetooth. Please use a supported browser, like Chrome or Edge.", - "requiresWebSerial": "This connection type requires <0>Web Serial. Please use a supported browser, like Chrome or Edge.", - "requiresSecureContext": "This application requires a <0>secure context. Please connect using HTTPS or localhost.", - "additionallyRequiresSecureContext": "Additionally, it requires a <0>secure context. Please connect using HTTPS or localhost." - } - }, - "nodeDetails": { - "message": "Повідомлення", - "requestPosition": "Запитати позицію", - "traceRoute": "Trace Route", - "airTxUtilization": "Air TX utilization", - "allRawMetrics": "All Raw Metrics:", - "batteryLevel": "Battery level", - "channelUtilization": "Channel utilization", - "details": "Details:", - "deviceMetrics": "Device Metrics:", - "hardware": "Hardware: ", - "lastHeard": "Last Heard: ", - "nodeHexPrefix": "Node Hex: ", - "nodeNumber": "Node Number: ", - "position": "Position:", - "role": "Role: ", - "uptime": "Uptime: ", - "voltage": "Напруга", - "title": "Node Details for {{identifier}}", - "ignoreNode": "Ignore node", - "removeNode": "Remove node", - "unignoreNode": "Unignore node", - "security": "Security:", - "publicKey": "Public Key: ", - "messageable": "Messageable: ", - "KeyManuallyVerifiedTrue": "Public Key has been manually verified", - "KeyManuallyVerifiedFalse": "Public Key is not manually verified" - }, - "pkiBackup": { - "loseKeysWarning": "If you lose your keys, you will need to reset your device.", - "secureBackup": "Its important to backup your public and private keys and store your backup securely!", - "footer": "=== END OF KEYS ===", - "header": "=== MESHTASTIC KEYS FOR {{longName}} ({{shortName}}) ===", - "privateKey": "Private Key:", - "publicKey": "Public Key:", - "fileName": "meshtastic_keys_{{longName}}_{{shortName}}.txt", - "title": "Backup Keys" - }, - "pkiBackupReminder": { - "description": "We recommend backing up your key data regularly. Would you like to back up now?", - "title": "Backup Reminder", - "remindLaterPrefix": "Remind me in", - "remindNever": "Never remind me", - "backupNow": "Back up now" - }, - "pkiRegenerate": { - "description": "Are you sure you want to regenerate key pair?", - "title": "Regenerate Key Pair" - }, - "qr": { - "addChannels": "Add Channels", - "replaceChannels": "Replace Channels", - "description": "The current LoRa configuration will also be shared.", - "sharableUrl": "Sharable URL", - "title": "Згенерувати QR-код" - }, - "reboot": { - "title": "Reboot device", - "description": "Reboot now or schedule a reboot of the connected node. Optionally, you can choose to reboot into OTA (Over-the-Air) mode.", - "ota": "Reboot into OTA mode", - "enterDelay": "Enter delay", - "scheduled": "Reboot has been scheduled", - "schedule": "Schedule reboot", - "now": "Reboot now", - "cancel": "Cancel scheduled reboot" - }, - "refreshKeys": { - "description": { - "acceptNewKeys": "This will remove the node from device and request new keys.", - "keyMismatchReasonSuffix": ". This is due to the remote node's current public key does not match the previously stored key for this node.", - "unableToSendDmPrefix": "Your node is unable to send a direct message to node: " - }, - "acceptNewKeys": "Accept New Keys", - "title": "Keys Mismatch - {{identifier}}" - }, - "removeNode": { - "description": "Are you sure you want to remove this Node?", - "title": "Remove Node?" - }, - "shutdown": { - "title": "Розклад вимкнення", - "description": "Turn off the connected node after x minutes." - }, - "traceRoute": { - "routeToDestination": "Route to destination:", - "routeBack": "Route back:" - }, - "tracerouteResponse": { - "title": "Traceroute: {{identifier}}" - }, - "unsafeRoles": { - "confirmUnderstanding": "Я знаю, що роблю", - "conjunction": " and the blog post about ", - "postamble": " and understand the implications of changing the role.", - "preamble": "I have read the ", - "choosingRightDeviceRole": "Choosing The Right Device Role", - "deviceRoleDocumentation": "Device Role Documentation", - "title": "Ви впевнені?" - }, - "managedMode": { - "confirmUnderstanding": "Я знаю, що роблю", - "title": "Ви впевнені?", - "description": "Enabling Managed Mode blocks client applications (including the web client) from writing configurations to a radio. Once enabled, radio configurations can only be changed through Remote Admin messages. This setting is not required for remote node administration." - }, - "clientNotification": { - "title": "Client Notification", - "TraceRoute can only be sent once every 30 seconds": "TraceRoute can only be sent once every 30 seconds", - "Compromised keys were detected and regenerated.": "Compromised keys were detected and regenerated." - } + "deleteMessages": { + "description": "This action will clear all message history. This cannot be undone. Are you sure you want to continue?", + "title": "Очистити всі повідомлення" + }, + "import": { + "description": "The current LoRa configuration will be overridden.", + "error": { + "invalidUrl": "Invalid Meshtastic URL" + }, + "channelPrefix": "Канал: ", + "primary": "Primary ", + "doNotImport": "No not import", + "channelName": "Ім'я", + "channelSlot": "Slot", + "channelSetUrl": "Channel Set/QR Code URL", + "useLoraConfig": "Import LoRa Config", + "presetDescription": "The current LoRa Config will be replaced.", + "title": "Import Channel Set" + }, + "locationResponse": { + "title": "Розташування: {{identifier}}", + "altitude": "Висота: ", + "coordinates": "Координати: ", + "noCoordinates": "No Coordinates" + }, + "pkiRegenerateDialog": { + "title": "Regenerate Pre-Shared Key?", + "description": "Are you sure you want to regenerate the pre-shared key?", + "regenerate": "Перегенерувати" + }, + "addConnection": { + "title": "Add connection", + "description": "Choose a connection type and fill in the details", + "validation": { + "requiresWebBluetooth": "This connection type requires <0>Web Bluetooth. Please use a supported browser, like Chrome or Edge.", + "requiresWebSerial": "This connection type requires <0>Web Serial. Please use a supported browser, like Chrome or Edge.", + "requiresSecureContext": "This application requires a <0>secure context. Please connect using HTTPS or localhost.", + "additionallyRequiresSecureContext": "Additionally, it requires a <0>secure context. Please connect using HTTPS or localhost." + }, + "bluetoothConnection": { + "namePlaceholder": "My Bluetooth Node", + "supported": { + "title": "Web Bluetooth supported" + }, + "notSupported": { + "title": "Web Bluetooth not supported", + "description": "Your browser or device does not support Web Bluetooth" + }, + "short": "BT: {{deviceName}}", + "long": "Bluetooth Device", + "device": "Пристрій", + "selectDevice": "Select device", + "selected": "Bluetooth device selected", + "notSelected": "No device selected", + "helperText": "Uses the Meshtastic Bluetooth service for discovery." + }, + "serialConnection": { + "namePlaceholder": "My Serial Node", + "helperText": "Selecting a port grants permission so the app can open it to connect.", + "supported": { + "title": "Web Serial supported" + }, + "notSupported": { + "title": "Web Serial not supported", + "description": "Your browser or device does not support Web Serial" + }, + "portSelected": { + "title": "Serial port selected", + "description": "Port permissions granted." + }, + "port": "Port", + "selectPort": "Select port", + "deviceName": "USB {{vendorId}}:{{productId}}", + "notSelected": "No port selected" + }, + "httpConnection": { + "namePlaceholder": "My HTTP Node", + "inputPlaceholder": "192.168.1.10 or meshtastic.local", + "heading": "URL or IP", + "useHttps": "Use HTTTPS", + "invalidUrl": { + "title": "Invalid URL", + "description": "Please enter a valid HTTP or HTTPS URL." + }, + "connectionTest": { + "description": "Test the connetion before saving to verify the device is reachable.", + "button": { + "loading": "Testing...", + "label": "Test connection" + }, + "reachable": "Reachable", + "notReachable": "Not reachable", + "success": { + "title": "Connection test successful", + "description": "The device appears to be reachable." + }, + "failure": { + "title": "Connection test failed", + "description": "Could not reach the device. Check the URL and try again." + } + } + } + }, + "nodeDetails": { + "message": "Повідомлення", + "requestPosition": "Запитати позицію", + "traceRoute": "Trace Route", + "airTxUtilization": "Air TX utilization", + "allRawMetrics": "All Raw Metrics:", + "batteryLevel": "Battery level", + "channelUtilization": "Channel utilization", + "details": "Details:", + "deviceMetrics": "Device Metrics:", + "hardware": "Hardware: ", + "lastHeard": "Last Heard: ", + "nodeHexPrefix": "Node Hex: ", + "nodeNumber": "Node Number: ", + "position": "Position:", + "role": "Role: ", + "uptime": "Uptime: ", + "voltage": "Напруга", + "title": "Node Details for {{identifier}}", + "ignoreNode": "Ignore node", + "removeNode": "Remove node", + "unignoreNode": "Unignore node", + "security": "Security:", + "publicKey": "Public Key: ", + "messageable": "Messageable: ", + "KeyManuallyVerifiedTrue": "Public Key has been manually verified", + "KeyManuallyVerifiedFalse": "Public Key is not manually verified" + }, + "pkiBackup": { + "loseKeysWarning": "If you lose your keys, you will need to reset your device.", + "secureBackup": "Its important to backup your public and private keys and store your backup securely!", + "footer": "=== END OF KEYS ===", + "header": "=== MESHTASTIC KEYS FOR {{longName}} ({{shortName}}) ===", + "privateKey": "Private Key:", + "publicKey": "Public Key:", + "fileName": "meshtastic_keys_{{longName}}_{{shortName}}.txt", + "title": "Backup Keys" + }, + "pkiBackupReminder": { + "description": "We recommend backing up your key data regularly. Would you like to back up now?", + "title": "Backup Reminder", + "remindLaterPrefix": "Remind me in", + "remindNever": "Never remind me", + "backupNow": "Back up now" + }, + "pkiRegenerate": { + "description": "Are you sure you want to regenerate key pair?", + "title": "Regenerate Key Pair" + }, + "qr": { + "addChannels": "Add Channels", + "replaceChannels": "Replace Channels", + "description": "The current LoRa configuration will also be shared.", + "sharableUrl": "Sharable URL", + "title": "Згенерувати QR-код" + }, + "reboot": { + "title": "Reboot device", + "description": "Reboot now or schedule a reboot of the connected node. Optionally, you can choose to reboot into OTA (Over-the-Air) mode.", + "ota": "Reboot into OTA mode", + "enterDelay": "Enter delay", + "scheduled": "Reboot has been scheduled", + "schedule": "Schedule reboot", + "now": "Reboot now", + "cancel": "Cancel scheduled reboot" + }, + "refreshKeys": { + "description": { + "acceptNewKeys": "This will remove the node from device and request new keys.", + "keyMismatchReasonSuffix": ". This is due to the remote node's current public key does not match the previously stored key for this node.", + "unableToSendDmPrefix": "Your node is unable to send a direct message to node: " + }, + "acceptNewKeys": "Accept New Keys", + "title": "Keys Mismatch - {{identifier}}" + }, + "removeNode": { + "description": "Are you sure you want to remove this Node?", + "title": "Remove Node?" + }, + "shutdown": { + "title": "Розклад вимкнення", + "description": "Turn off the connected node after x minutes." + }, + "traceRoute": { + "routeToDestination": "Route to destination:", + "routeBack": "Route back:" + }, + "tracerouteResponse": { + "title": "Traceroute: {{identifier}}" + }, + "unsafeRoles": { + "confirmUnderstanding": "Я знаю, що роблю", + "conjunction": " and the blog post about ", + "postamble": " and understand the implications of changing the role.", + "preamble": "I have read the ", + "choosingRightDeviceRole": "Choosing The Right Device Role", + "deviceRoleDocumentation": "Device Role Documentation", + "title": "Ви впевнені?" + }, + "managedMode": { + "confirmUnderstanding": "Я знаю, що роблю", + "title": "Ви впевнені?", + "description": "Enabling Managed Mode blocks client applications (including the web client) from writing configurations to a radio. Once enabled, radio configurations can only be changed through Remote Admin messages. This setting is not required for remote node administration." + }, + "clientNotification": { + "title": "Client Notification", + "TraceRoute can only be sent once every 30 seconds": "TraceRoute can only be sent once every 30 seconds", + "Compromised keys were detected and regenerated.": "Compromised keys were detected and regenerated." + }, + "resetNodeDb": { + "title": "Reset Node Database", + "description": "This will clear all nodes from the connected device's node database and clear all message history in the client. This cannot be undone. Are you sure you want to continue?", + "confirm": "Reset Node Database", + "failedTitle": "There was an error resetting the Node DB. Please try again." + }, + "clearAllStores": { + "title": "Clear All Local Storage", + "description": "This will clear all locally stored data, including message history and node databases for all previously connected devices. This will require you to reconnect to your node once complete and cannot be undone. Are you sure you want to continue?", + "confirm": "Clear all local storage", + "failedTitle": "There was an error clearing local storage. Please try again." + }, + "factoryResetDevice": { + "title": "Factory Reset Device", + "description": "This will factory reset the connected device, erasing all configurations and data on the device as well as all nodes and messages saved in the client. This cannot be undone. Are you sure you want to continue?", + "confirm": "Factory Reset Device", + "failedTitle": "There was an error performing the factory reset. Please try again." + }, + "factoryResetConfig": { + "title": "Factory Reset Config", + "description": "This will factory reset the configuration on the connected device, erasing all configurations on the device. This cannot be undone. Are you sure you want to continue?", + "confirm": "Factory Reset Config", + "failedTitle": "There was an error performing the factory reset. Please try again." + } } diff --git a/packages/web/public/i18n/locales/uk-UA/map.json b/packages/web/public/i18n/locales/uk-UA/map.json new file mode 100644 index 000000000..bcfda0dbc --- /dev/null +++ b/packages/web/public/i18n/locales/uk-UA/map.json @@ -0,0 +1,38 @@ +{ + "maplibre": { + "GeolocateControl.FindMyLocation": "Find my location", + "NavigationControl.ZoomIn": "Zoom in", + "NavigationControl.ZoomOut": "Zoom out", + "CooperativeGesturesHandler.WindowsHelpText": "Use Ctrl + scroll to zoom the map", + "CooperativeGesturesHandler.MacHelpText": "Use ⌘ + scroll to zoom the map", + "CooperativeGesturesHandler.MobileHelpText": "Use two fingers to move the map" + }, + "layerTool": { + "nodeMarkers": "Show nodes", + "directNeighbors": "Show direct connections", + "remoteNeighbors": "Show remote connections", + "positionPrecision": "Show position precision", + "traceroutes": "Show traceroutes", + "waypoints": "Show waypoints" + }, + "mapMenu": { + "locateAria": "Locate my node", + "layersAria": "Change map style" + }, + "waypointDetail": { + "edit": "Редагувати", + "description": "Description:", + "createdBy": "Edited by:", + "createdDate": "Created:", + "updated": "Updated:", + "expires": "Expires:", + "distance": "Distance:", + "bearing": "Absolute bearing:", + "lockedTo": "Locked by:", + "latitude": "Latitude:", + "longitude": "Longitude:" + }, + "myNode": { + "tooltip": "This device" + } +} diff --git a/packages/web/public/i18n/locales/uk-UA/messages.json b/packages/web/public/i18n/locales/uk-UA/messages.json index 57301fe49..0500adb8b 100644 --- a/packages/web/public/i18n/locales/uk-UA/messages.json +++ b/packages/web/public/i18n/locales/uk-UA/messages.json @@ -1,39 +1,39 @@ { - "page": { - "title": "Повідомлення: {{chatName}}", - "placeholder": "Введіть повідомлення" - }, - "emptyState": { - "title": "Оберіть чат", - "text": "Поки немає повідомлень." - }, - "selectChatPrompt": { - "text": "Виберіть канал або вузол для початку обміну повідомленнями." - }, - "sendMessage": { - "placeholder": "Введіть ваше повідомлення тут...", - "sendButton": "Надіслати" - }, - "actionsMenu": { - "addReactionLabel": "Додати реакцію", - "replyLabel": "Відповісти" - }, - "deliveryStatus": { - "delivered": { - "label": "Повідомлення доставлено", - "displayText": "Повідомлення доставлено" - }, - "failed": { - "label": "Помилка доставлення повідомлення", - "displayText": "Надсилання не відбулося" - }, - "unknown": { - "label": "Статус повідомлення невідомий", - "displayText": "Невідомий стан" - }, - "waiting": { - "label": "Надсилання повідомлення", - "displayText": "Очікування доставки" - } - } + "page": { + "title": "Повідомлення: {{chatName}}", + "placeholder": "Введіть повідомлення" + }, + "emptyState": { + "title": "Оберіть чат", + "text": "Поки немає повідомлень." + }, + "selectChatPrompt": { + "text": "Виберіть канал або вузол для початку обміну повідомленнями." + }, + "sendMessage": { + "placeholder": "Введіть ваше повідомлення тут...", + "sendButton": "Надіслати" + }, + "actionsMenu": { + "addReactionLabel": "Додати реакцію", + "replyLabel": "Відповісти" + }, + "deliveryStatus": { + "delivered": { + "label": "Повідомлення доставлено", + "displayText": "Повідомлення доставлено" + }, + "failed": { + "label": "Помилка доставлення повідомлення", + "displayText": "Надсилання не відбулося" + }, + "unknown": { + "label": "Статус повідомлення невідомий", + "displayText": "Невідомий стан" + }, + "waiting": { + "label": "Надсилання повідомлення", + "displayText": "Очікування доставки" + } + } } diff --git a/packages/web/public/i18n/locales/uk-UA/moduleConfig.json b/packages/web/public/i18n/locales/uk-UA/moduleConfig.json index 42cc76d84..c86ae43fd 100644 --- a/packages/web/public/i18n/locales/uk-UA/moduleConfig.json +++ b/packages/web/public/i18n/locales/uk-UA/moduleConfig.json @@ -1,448 +1,448 @@ { - "page": { - "tabAmbientLighting": "Ambient Lighting", - "tabAudio": "Аудіо", - "tabCannedMessage": "Canned", - "tabDetectionSensor": "Detection Sensor", - "tabExternalNotification": "Ext Notif", - "tabMqtt": "MQTT", - "tabNeighborInfo": "Neighbor Info", - "tabPaxcounter": "Paxcounter", - "tabRangeTest": "Тест дальності", - "tabSerial": "Серійний порт", - "tabStoreAndForward": "S&F", - "tabTelemetry": "Телеметрія" - }, - "ambientLighting": { - "title": "Ambient Lighting Settings", - "description": "Settings for the Ambient Lighting module", - "ledState": { - "label": "LED State", - "description": "Sets LED to on or off" - }, - "current": { - "label": "Current", - "description": "Sets the current for the LED output. Default is 10" - }, - "red": { - "label": "Червоний", - "description": "Sets the red LED level. Values are 0-255" - }, - "green": { - "label": "Зелений", - "description": "Sets the green LED level. Values are 0-255" - }, - "blue": { - "label": "Синій", - "description": "Sets the blue LED level. Values are 0-255" - } - }, - "audio": { - "title": "Audio Settings", - "description": "Settings for the Audio module", - "codec2Enabled": { - "label": "Codec 2 Enabled", - "description": "Enable Codec 2 audio encoding" - }, - "pttPin": { - "label": "PTT Pin", - "description": "GPIO pin to use for PTT" - }, - "bitrate": { - "label": "Bitrate", - "description": "Bitrate to use for audio encoding" - }, - "i2sWs": { - "label": "i2S WS", - "description": "GPIO pin to use for i2S WS" - }, - "i2sSd": { - "label": "i2S SD", - "description": "GPIO pin to use for i2S SD" - }, - "i2sDin": { - "label": "i2S DIN", - "description": "GPIO pin to use for i2S DIN" - }, - "i2sSck": { - "label": "i2S SCK", - "description": "GPIO pin to use for i2S SCK" - } - }, - "cannedMessage": { - "title": "Canned Message Settings", - "description": "Settings for the Canned Message module", - "moduleEnabled": { - "label": "Module Enabled", - "description": "Enable Canned Message" - }, - "rotary1Enabled": { - "label": "Rotary Encoder #1 Enabled", - "description": "Enable the rotary encoder" - }, - "inputbrokerPinA": { - "label": "Encoder Pin A", - "description": "GPIO Pin Value (1-39) For encoder port A" - }, - "inputbrokerPinB": { - "label": "Encoder Pin B", - "description": "GPIO Pin Value (1-39) For encoder port B" - }, - "inputbrokerPinPress": { - "label": "Encoder Pin Press", - "description": "GPIO Pin Value (1-39) For encoder Press" - }, - "inputbrokerEventCw": { - "label": "Clockwise event", - "description": "Select input event." - }, - "inputbrokerEventCcw": { - "label": "Counter Clockwise event", - "description": "Select input event." - }, - "inputbrokerEventPress": { - "label": "Press event", - "description": "Select input event" - }, - "updown1Enabled": { - "label": "Up Down enabled", - "description": "Enable the up / down encoder" - }, - "allowInputSource": { - "label": "Allow Input Source", - "description": "Select from: '_any', 'rotEnc1', 'upDownEnc1', 'cardkb'" - }, - "sendBell": { - "label": "Send Bell", - "description": "Sends a bell character with each message" - } - }, - "detectionSensor": { - "title": "Detection Sensor Settings", - "description": "Settings for the Detection Sensor module", - "enabled": { - "label": "Увімкнено", - "description": "Enable or disable Detection Sensor Module" - }, - "minimumBroadcastSecs": { - "label": "Minimum Broadcast Seconds", - "description": "The interval in seconds of how often we can send a message to the mesh when a state change is detected" - }, - "stateBroadcastSecs": { - "label": "State Broadcast Seconds", - "description": "The interval in seconds of how often we should send a message to the mesh with the current state regardless of changes" - }, - "sendBell": { - "label": "Send Bell", - "description": "Send ASCII bell with alert message" - }, - "name": { - "label": "Friendly Name", - "description": "Used to format the message sent to mesh, max 20 Characters" - }, - "monitorPin": { - "label": "Monitor Pin", - "description": "The GPIO pin to monitor for state changes" - }, - "detectionTriggerType": { - "label": "Detection Triggered Type", - "description": "The type of trigger event to be used" - }, - "usePullup": { - "label": "Use Pullup", - "description": "Whether or not use INPUT_PULLUP mode for GPIO pin" - } - }, - "externalNotification": { - "title": "External Notification Settings", - "description": "Configure the external notification module", - "enabled": { - "label": "Module Enabled", - "description": "Enable External Notification" - }, - "outputMs": { - "label": "Output MS", - "description": "Output MS" - }, - "output": { - "label": "Output", - "description": "Output" - }, - "outputVibra": { - "label": "Output Vibrate", - "description": "Output Vibrate" - }, - "outputBuzzer": { - "label": "Output Buzzer", - "description": "Output Buzzer" - }, - "active": { - "label": "Active", - "description": "Active" - }, - "alertMessage": { - "label": "Alert Message", - "description": "Alert Message" - }, - "alertMessageVibra": { - "label": "Alert Message Vibrate", - "description": "Alert Message Vibrate" - }, - "alertMessageBuzzer": { - "label": "Alert Message Buzzer", - "description": "Alert Message Buzzer" - }, - "alertBell": { - "label": "Alert Bell", - "description": "Should an alert be triggered when receiving an incoming bell?" - }, - "alertBellVibra": { - "label": "Alert Bell Vibrate", - "description": "Alert Bell Vibrate" - }, - "alertBellBuzzer": { - "label": "Alert Bell Buzzer", - "description": "Alert Bell Buzzer" - }, - "usePwm": { - "label": "Use PWM", - "description": "Use PWM" - }, - "nagTimeout": { - "label": "Nag Timeout", - "description": "Nag Timeout" - }, - "useI2sAsBuzzer": { - "label": "Use I²S Pin as Buzzer", - "description": "Designate I²S Pin as Buzzer Output" - } - }, - "mqtt": { - "title": "Налаштування MQTT", - "description": "Settings for the MQTT module", - "enabled": { - "label": "Увімкнено", - "description": "Enable or disable MQTT" - }, - "address": { - "label": "MQTT Server Address", - "description": "MQTT server address to use for default/custom servers" - }, - "username": { - "label": "Ім'я користувача MQTT", - "description": "MQTT username to use for default/custom servers" - }, - "password": { - "label": "Пароль MQTT", - "description": "MQTT password to use for default/custom servers" - }, - "encryptionEnabled": { - "label": "Encryption Enabled", - "description": "Enable or disable MQTT encryption. Note: All messages are sent to the MQTT broker unencrypted if this option is not enabled, even when your uplink channels have encryption keys set. This includes position data." - }, - "jsonEnabled": { - "label": "JSON Enabled", - "description": "Whether to send/consume JSON packets on MQTT" - }, - "tlsEnabled": { - "label": "TLS Enabled", - "description": "Enable or disable TLS" - }, - "root": { - "label": "Root topic", - "description": "MQTT root topic to use for default/custom servers" - }, - "proxyToClientEnabled": { - "label": "MQTT Client Proxy Enabled", - "description": "Utilizes the network connection to proxy MQTT messages to the client." - }, - "mapReportingEnabled": { - "label": "Map Reporting Enabled", - "description": "Your node will periodically send an unencrypted map report packet to the configured MQTT server, this includes id, short and long name, approximate location, hardware model, role, firmware version, LoRa region, modem preset and primary channel name." - }, - "mapReportSettings": { - "publishIntervalSecs": { - "label": "Map Report Publish Interval (s)", - "description": "Interval in seconds to publish map reports" - }, - "positionPrecision": { - "label": "Approximate Location", - "description": "Position shared will be accurate within this distance", - "options": { - "metric_km23": "Within 23 km", - "metric_km12": "Within 12 km", - "metric_km5_8": "Within 5.8 km", - "metric_km2_9": "Within 2.9 km", - "metric_km1_5": "Within 1.5 km", - "metric_m700": "Within 700 m", - "metric_m350": "Within 350 m", - "metric_m200": "Within 200 m", - "metric_m90": "Within 90 m", - "metric_m50": "Within 50 m", - "imperial_mi15": "У межах 15 миль", - "imperial_mi7_3": "У межах 7,3 милі", - "imperial_mi3_6": "У межах 3,6 милі", - "imperial_mi1_8": "У межах 1,8 милі", - "imperial_mi0_9": "У межах 0,9 милі", - "imperial_mi0_5": "У межах 0,5 милі", - "imperial_mi0_2": "У межах 0,2 милі", - "imperial_ft600": "У межах 600 фт", - "imperial_ft300": "У межах 300 фт", - "imperial_ft150": "У межах 150 фт" - } - } - } - }, - "neighborInfo": { - "title": "Neighbor Info Settings", - "description": "Settings for the Neighbor Info module", - "enabled": { - "label": "Увімкнено", - "description": "Enable or disable Neighbor Info Module" - }, - "updateInterval": { - "label": "Update Interval", - "description": "Interval in seconds of how often we should try to send our Neighbor Info to the mesh" - } - }, - "paxcounter": { - "title": "Paxcounter Settings", - "description": "Settings for the Paxcounter module", - "enabled": { - "label": "Module Enabled", - "description": "Enable Paxcounter" - }, - "paxcounterUpdateInterval": { - "label": "Update Interval (seconds)", - "description": "How long to wait between sending paxcounter packets" - }, - "wifiThreshold": { - "label": "WiFi RSSI Threshold", - "description": "At what WiFi RSSI level should the counter increase. Defaults to -80." - }, - "bleThreshold": { - "label": "BLE RSSI Threshold", - "description": "At what BLE RSSI level should the counter increase. Defaults to -80." - } - }, - "rangeTest": { - "title": "Range Test Settings", - "description": "Settings for the Range Test module", - "enabled": { - "label": "Module Enabled", - "description": "Enable Range Test" - }, - "sender": { - "label": "Message Interval", - "description": "How long to wait between sending test packets" - }, - "save": { - "label": "Save CSV to storage", - "description": "ESP32 Only" - } - }, - "serial": { - "title": "Serial Settings", - "description": "Settings for the Serial module", - "enabled": { - "label": "Module Enabled", - "description": "Enable Serial output" - }, - "echo": { - "label": "Echo", - "description": "Any packets you send will be echoed back to your device" - }, - "rxd": { - "label": "Receive Pin", - "description": "Set the GPIO pin to the RXD pin you have set up." - }, - "txd": { - "label": "Transmit Pin", - "description": "Set the GPIO pin to the TXD pin you have set up." - }, - "baud": { - "label": "Baud Rate", - "description": "The serial baud rate" - }, - "timeout": { - "label": "Таймаут", - "description": "Seconds to wait before we consider your packet as 'done'" - }, - "mode": { - "label": "Mode", - "description": "Select Mode" - }, - "overrideConsoleSerialPort": { - "label": "Override Console Serial Port", - "description": "If you have a serial port connected to the console, this will override it." - } - }, - "storeForward": { - "title": "Store & Forward Settings", - "description": "Settings for the Store & Forward module", - "enabled": { - "label": "Module Enabled", - "description": "Enable Store & Forward" - }, - "heartbeat": { - "label": "Heartbeat Enabled", - "description": "Enable Store & Forward heartbeat" - }, - "records": { - "label": "Number of records", - "description": "Number of records to store" - }, - "historyReturnMax": { - "label": "History return max", - "description": "Max number of records to return" - }, - "historyReturnWindow": { - "label": "History return window", - "description": "Max number of records to return" - } - }, - "telemetry": { - "title": "Telemetry Settings", - "description": "Settings for the Telemetry module", - "deviceUpdateInterval": { - "label": "Device Metrics", - "description": "Device metrics update interval (seconds)" - }, - "environmentUpdateInterval": { - "label": "Environment metrics update interval (seconds)", - "description": "" - }, - "environmentMeasurementEnabled": { - "label": "Module Enabled", - "description": "Enable the Environment Telemetry" - }, - "environmentScreenEnabled": { - "label": "Displayed on Screen", - "description": "Show the Telemetry Module on the OLED" - }, - "environmentDisplayFahrenheit": { - "label": "Display Fahrenheit", - "description": "Display temp in Fahrenheit" - }, - "airQualityEnabled": { - "label": "Air Quality Enabled", - "description": "Enable the Air Quality Telemetry" - }, - "airQualityInterval": { - "label": "Air Quality Update Interval", - "description": "How often to send Air Quality data over the mesh" - }, - "powerMeasurementEnabled": { - "label": "Power Measurement Enabled", - "description": "Enable the Power Measurement Telemetry" - }, - "powerUpdateInterval": { - "label": "Power Update Interval", - "description": "How often to send Power data over the mesh" - }, - "powerScreenEnabled": { - "label": "Power Screen Enabled", - "description": "Enable the Power Telemetry Screen" - } - } + "page": { + "tabAmbientLighting": "Ambient Lighting", + "tabAudio": "Аудіо", + "tabCannedMessage": "Canned", + "tabDetectionSensor": "Detection Sensor", + "tabExternalNotification": "Ext Notif", + "tabMqtt": "MQTT", + "tabNeighborInfo": "Neighbor Info", + "tabPaxcounter": "Paxcounter", + "tabRangeTest": "Тест дальності", + "tabSerial": "Серійний порт", + "tabStoreAndForward": "S&F", + "tabTelemetry": "Телеметрія" + }, + "ambientLighting": { + "title": "Ambient Lighting Settings", + "description": "Settings for the Ambient Lighting module", + "ledState": { + "label": "LED State", + "description": "Sets LED to on or off" + }, + "current": { + "label": "Current", + "description": "Sets the current for the LED output. Default is 10" + }, + "red": { + "label": "Червоний", + "description": "Sets the red LED level. Values are 0-255" + }, + "green": { + "label": "Зелений", + "description": "Sets the green LED level. Values are 0-255" + }, + "blue": { + "label": "Синій", + "description": "Sets the blue LED level. Values are 0-255" + } + }, + "audio": { + "title": "Audio Settings", + "description": "Settings for the Audio module", + "codec2Enabled": { + "label": "Codec 2 Enabled", + "description": "Enable Codec 2 audio encoding" + }, + "pttPin": { + "label": "PTT Pin", + "description": "GPIO pin to use for PTT" + }, + "bitrate": { + "label": "Bitrate", + "description": "Bitrate to use for audio encoding" + }, + "i2sWs": { + "label": "i2S WS", + "description": "GPIO pin to use for i2S WS" + }, + "i2sSd": { + "label": "i2S SD", + "description": "GPIO pin to use for i2S SD" + }, + "i2sDin": { + "label": "i2S DIN", + "description": "GPIO pin to use for i2S DIN" + }, + "i2sSck": { + "label": "i2S SCK", + "description": "GPIO pin to use for i2S SCK" + } + }, + "cannedMessage": { + "title": "Canned Message Settings", + "description": "Settings for the Canned Message module", + "moduleEnabled": { + "label": "Module Enabled", + "description": "Enable Canned Message" + }, + "rotary1Enabled": { + "label": "Rotary Encoder #1 Enabled", + "description": "Enable the rotary encoder" + }, + "inputbrokerPinA": { + "label": "Encoder Pin A", + "description": "GPIO Pin Value (1-39) For encoder port A" + }, + "inputbrokerPinB": { + "label": "Encoder Pin B", + "description": "GPIO Pin Value (1-39) For encoder port B" + }, + "inputbrokerPinPress": { + "label": "Encoder Pin Press", + "description": "GPIO Pin Value (1-39) For encoder Press" + }, + "inputbrokerEventCw": { + "label": "Clockwise event", + "description": "Select input event." + }, + "inputbrokerEventCcw": { + "label": "Counter Clockwise event", + "description": "Select input event." + }, + "inputbrokerEventPress": { + "label": "Press event", + "description": "Select input event" + }, + "updown1Enabled": { + "label": "Up Down enabled", + "description": "Enable the up / down encoder" + }, + "allowInputSource": { + "label": "Allow Input Source", + "description": "Select from: '_any', 'rotEnc1', 'upDownEnc1', 'cardkb'" + }, + "sendBell": { + "label": "Send Bell", + "description": "Sends a bell character with each message" + } + }, + "detectionSensor": { + "title": "Detection Sensor Settings", + "description": "Settings for the Detection Sensor module", + "enabled": { + "label": "Увімкнено", + "description": "Enable or disable Detection Sensor Module" + }, + "minimumBroadcastSecs": { + "label": "Minimum Broadcast Seconds", + "description": "The interval in seconds of how often we can send a message to the mesh when a state change is detected" + }, + "stateBroadcastSecs": { + "label": "State Broadcast Seconds", + "description": "The interval in seconds of how often we should send a message to the mesh with the current state regardless of changes" + }, + "sendBell": { + "label": "Send Bell", + "description": "Send ASCII bell with alert message" + }, + "name": { + "label": "Friendly Name", + "description": "Used to format the message sent to mesh, max 20 Characters" + }, + "monitorPin": { + "label": "Monitor Pin", + "description": "The GPIO pin to monitor for state changes" + }, + "detectionTriggerType": { + "label": "Detection Triggered Type", + "description": "The type of trigger event to be used" + }, + "usePullup": { + "label": "Use Pullup", + "description": "Whether or not use INPUT_PULLUP mode for GPIO pin" + } + }, + "externalNotification": { + "title": "External Notification Settings", + "description": "Configure the external notification module", + "enabled": { + "label": "Module Enabled", + "description": "Enable External Notification" + }, + "outputMs": { + "label": "Output MS", + "description": "Output MS" + }, + "output": { + "label": "Output", + "description": "Output" + }, + "outputVibra": { + "label": "Output Vibrate", + "description": "Output Vibrate" + }, + "outputBuzzer": { + "label": "Output Buzzer", + "description": "Output Buzzer" + }, + "active": { + "label": "Active", + "description": "Active" + }, + "alertMessage": { + "label": "Alert Message", + "description": "Alert Message" + }, + "alertMessageVibra": { + "label": "Alert Message Vibrate", + "description": "Alert Message Vibrate" + }, + "alertMessageBuzzer": { + "label": "Alert Message Buzzer", + "description": "Alert Message Buzzer" + }, + "alertBell": { + "label": "Alert Bell", + "description": "Should an alert be triggered when receiving an incoming bell?" + }, + "alertBellVibra": { + "label": "Alert Bell Vibrate", + "description": "Alert Bell Vibrate" + }, + "alertBellBuzzer": { + "label": "Alert Bell Buzzer", + "description": "Alert Bell Buzzer" + }, + "usePwm": { + "label": "Use PWM", + "description": "Use PWM" + }, + "nagTimeout": { + "label": "Nag Timeout", + "description": "Nag Timeout" + }, + "useI2sAsBuzzer": { + "label": "Use I²S Pin as Buzzer", + "description": "Designate I²S Pin as Buzzer Output" + } + }, + "mqtt": { + "title": "Налаштування MQTT", + "description": "Settings for the MQTT module", + "enabled": { + "label": "Увімкнено", + "description": "Enable or disable MQTT" + }, + "address": { + "label": "MQTT Server Address", + "description": "MQTT server address to use for default/custom servers" + }, + "username": { + "label": "Ім'я користувача MQTT", + "description": "MQTT username to use for default/custom servers" + }, + "password": { + "label": "Пароль MQTT", + "description": "MQTT password to use for default/custom servers" + }, + "encryptionEnabled": { + "label": "Encryption Enabled", + "description": "Enable or disable MQTT encryption. Note: All messages are sent to the MQTT broker unencrypted if this option is not enabled, even when your uplink channels have encryption keys set. This includes position data." + }, + "jsonEnabled": { + "label": "JSON Enabled", + "description": "Whether to send/consume JSON packets on MQTT" + }, + "tlsEnabled": { + "label": "TLS Enabled", + "description": "Enable or disable TLS" + }, + "root": { + "label": "Root topic", + "description": "MQTT root topic to use for default/custom servers" + }, + "proxyToClientEnabled": { + "label": "MQTT Client Proxy Enabled", + "description": "Utilizes the network connection to proxy MQTT messages to the client." + }, + "mapReportingEnabled": { + "label": "Map Reporting Enabled", + "description": "Your node will periodically send an unencrypted map report packet to the configured MQTT server, this includes id, short and long name, approximate location, hardware model, role, firmware version, LoRa region, modem preset and primary channel name." + }, + "mapReportSettings": { + "publishIntervalSecs": { + "label": "Map Report Publish Interval (s)", + "description": "Interval in seconds to publish map reports" + }, + "positionPrecision": { + "label": "Approximate Location", + "description": "Position shared will be accurate within this distance", + "options": { + "metric_km23": "Within 23 km", + "metric_km12": "Within 12 km", + "metric_km5_8": "Within 5.8 km", + "metric_km2_9": "Within 2.9 km", + "metric_km1_5": "Within 1.5 km", + "metric_m700": "Within 700 m", + "metric_m350": "Within 350 m", + "metric_m200": "Within 200 m", + "metric_m90": "Within 90 m", + "metric_m50": "Within 50 m", + "imperial_mi15": "У межах 15 миль", + "imperial_mi7_3": "У межах 7,3 милі", + "imperial_mi3_6": "У межах 3,6 милі", + "imperial_mi1_8": "У межах 1,8 милі", + "imperial_mi0_9": "У межах 0,9 милі", + "imperial_mi0_5": "У межах 0,5 милі", + "imperial_mi0_2": "У межах 0,2 милі", + "imperial_ft600": "У межах 600 фт", + "imperial_ft300": "У межах 300 фт", + "imperial_ft150": "У межах 150 фт" + } + } + } + }, + "neighborInfo": { + "title": "Neighbor Info Settings", + "description": "Settings for the Neighbor Info module", + "enabled": { + "label": "Увімкнено", + "description": "Enable or disable Neighbor Info Module" + }, + "updateInterval": { + "label": "Update Interval", + "description": "Interval in seconds of how often we should try to send our Neighbor Info to the mesh" + } + }, + "paxcounter": { + "title": "Paxcounter Settings", + "description": "Settings for the Paxcounter module", + "enabled": { + "label": "Module Enabled", + "description": "Enable Paxcounter" + }, + "paxcounterUpdateInterval": { + "label": "Update Interval (seconds)", + "description": "How long to wait between sending paxcounter packets" + }, + "wifiThreshold": { + "label": "WiFi RSSI Threshold", + "description": "At what WiFi RSSI level should the counter increase. Defaults to -80." + }, + "bleThreshold": { + "label": "BLE RSSI Threshold", + "description": "At what BLE RSSI level should the counter increase. Defaults to -80." + } + }, + "rangeTest": { + "title": "Range Test Settings", + "description": "Settings for the Range Test module", + "enabled": { + "label": "Module Enabled", + "description": "Enable Range Test" + }, + "sender": { + "label": "Message Interval", + "description": "How long to wait between sending test packets" + }, + "save": { + "label": "Save CSV to storage", + "description": "ESP32 Only" + } + }, + "serial": { + "title": "Serial Settings", + "description": "Settings for the Serial module", + "enabled": { + "label": "Module Enabled", + "description": "Enable Serial output" + }, + "echo": { + "label": "Echo", + "description": "Any packets you send will be echoed back to your device" + }, + "rxd": { + "label": "Receive Pin", + "description": "Set the GPIO pin to the RXD pin you have set up." + }, + "txd": { + "label": "Transmit Pin", + "description": "Set the GPIO pin to the TXD pin you have set up." + }, + "baud": { + "label": "Baud Rate", + "description": "The serial baud rate" + }, + "timeout": { + "label": "Таймаут", + "description": "Seconds to wait before we consider your packet as 'done'" + }, + "mode": { + "label": "Mode", + "description": "Select Mode" + }, + "overrideConsoleSerialPort": { + "label": "Override Console Serial Port", + "description": "If you have a serial port connected to the console, this will override it." + } + }, + "storeForward": { + "title": "Store & Forward Settings", + "description": "Settings for the Store & Forward module", + "enabled": { + "label": "Module Enabled", + "description": "Enable Store & Forward" + }, + "heartbeat": { + "label": "Heartbeat Enabled", + "description": "Enable Store & Forward heartbeat" + }, + "records": { + "label": "Number of records", + "description": "Number of records to store" + }, + "historyReturnMax": { + "label": "History return max", + "description": "Max number of records to return" + }, + "historyReturnWindow": { + "label": "History return window", + "description": "Return records from this time window (minutes)" + } + }, + "telemetry": { + "title": "Telemetry Settings", + "description": "Settings for the Telemetry module", + "deviceUpdateInterval": { + "label": "Device Metrics", + "description": "Device metrics update interval (seconds)" + }, + "environmentUpdateInterval": { + "label": "Environment metrics update interval (seconds)", + "description": "" + }, + "environmentMeasurementEnabled": { + "label": "Module Enabled", + "description": "Enable the Environment Telemetry" + }, + "environmentScreenEnabled": { + "label": "Displayed on Screen", + "description": "Show the Telemetry Module on the OLED" + }, + "environmentDisplayFahrenheit": { + "label": "Display Fahrenheit", + "description": "Display temp in Fahrenheit" + }, + "airQualityEnabled": { + "label": "Air Quality Enabled", + "description": "Enable the Air Quality Telemetry" + }, + "airQualityInterval": { + "label": "Air Quality Update Interval", + "description": "How often to send Air Quality data over the mesh" + }, + "powerMeasurementEnabled": { + "label": "Power Measurement Enabled", + "description": "Enable the Power Measurement Telemetry" + }, + "powerUpdateInterval": { + "label": "Power Update Interval", + "description": "How often to send Power data over the mesh" + }, + "powerScreenEnabled": { + "label": "Power Screen Enabled", + "description": "Enable the Power Telemetry Screen" + } + } } diff --git a/packages/web/public/i18n/locales/uk-UA/nodes.json b/packages/web/public/i18n/locales/uk-UA/nodes.json index e5f2c5536..5ce3fb3f5 100644 --- a/packages/web/public/i18n/locales/uk-UA/nodes.json +++ b/packages/web/public/i18n/locales/uk-UA/nodes.json @@ -1,63 +1,59 @@ { - "nodeDetail": { - "publicKeyEnabled": { - "label": "Public Key Enabled" - }, - "noPublicKey": { - "label": "No Public Key" - }, - "directMessage": { - "label": "Direct Message {{shortName}}" - }, - "favorite": { - "label": "Обране", - "tooltip": "Add or remove this node from your favorites" - }, - "notFavorite": { - "label": "Not a Favorite" - }, - "error": { - "label": "Помилка", - "text": "An error occurred while fetching node details. Please try again later." - }, - "status": { - "heard": "Heard", - "mqtt": "MQTT" - }, - "elevation": { - "label": "Elevation" - }, - "channelUtil": { - "label": "Channel Util" - }, - "airtimeUtil": { - "label": "Airtime Util" - } - }, - "nodesTable": { - "headings": { - "longName": "Довга назва", - "connection": "Connection", - "lastHeard": "Last Heard", - "encryption": "Шифрування", - "model": "Model", - "macAddress": "MAC-адреса" - }, - "connectionStatus": { - "direct": "Direct", - "away": "away", - "unknown": "-", - "viaMqtt": ", через MQTT" - }, - "lastHeardStatus": { - "never": "Ніколи" - } - }, - "actions": { - "added": "Додано", - "removed": "Видалено", - "ignoreNode": "Ігнорувати вузол", - "unignoreNode": "Unignore Node", - "requestPosition": "Запитати позицію" - } + "nodeDetail": { + "publicKeyEnabled": { + "label": "Public Key Enabled" + }, + "noPublicKey": { + "label": "No Public Key" + }, + "directMessage": { + "label": "Direct Message {{shortName}}" + }, + "favorite": { + "label": "Обране", + "tooltip": "Add or remove this node from your favorites" + }, + "notFavorite": { + "label": "Not a Favorite" + }, + "error": { + "label": "Помилка", + "text": "An error occurred while fetching node details. Please try again later." + }, + "status": { + "heard": "Heard", + "mqtt": "MQTT" + }, + "elevation": { + "label": "Elevation" + }, + "channelUtil": { + "label": "Channel Util" + }, + "airtimeUtil": { + "label": "Airtime Util" + } + }, + "nodesTable": { + "headings": { + "longName": "Довга назва", + "connection": "Connection", + "lastHeard": "Last Heard", + "encryption": "Шифрування", + "model": "Model", + "macAddress": "MAC-адреса" + }, + "connectionStatus": { + "direct": "Direct", + "away": "away", + "viaMqtt": ", через MQTT" + } + }, + "actions": { + "added": "Додано", + "removed": "Видалено", + "ignoreNode": "Ігнорувати вузол", + "unignoreNode": "Unignore Node", + "requestPosition": "Запитати позицію" + } } diff --git a/packages/web/public/i18n/locales/uk-UA/ui.json b/packages/web/public/i18n/locales/uk-UA/ui.json index ac3d679da..8ad2d7242 100644 --- a/packages/web/public/i18n/locales/uk-UA/ui.json +++ b/packages/web/public/i18n/locales/uk-UA/ui.json @@ -1,228 +1,230 @@ { - "navigation": { - "title": "Навігація", - "messages": "Повідомлення", - "map": "Мапа", - "config": "Config", - "radioConfig": "Налаштування радіо", - "moduleConfig": "Module Config", - "channels": "Канали", - "nodes": "Вузли" - }, - "app": { - "title": "Meshtastic", - "logo": "Логотип Meshtastic" - }, - "sidebar": { - "collapseToggle": { - "button": { - "open": "Відкрити бічну панель", - "close": "Закрити бічну панель" - } - }, - "deviceInfo": { - "volts": "{{voltage}} Вольт", - "firmware": { - "title": "Прошивка", - "version": "v{{version}}", - "buildDate": "Дата збірки: {{date}}" - }, - "deviceName": { - "title": "Назва пристрою", - "changeName": "Змінити назву пристрою", - "placeholder": "Уведіть назву пристрою" - }, - "editDeviceName": "Змінити назву пристрою" - } - }, - "batteryStatus": { - "charging": "{{level}}% charging", - "pluggedIn": "Plugged in", - "title": "Батарея" - }, - "search": { - "nodes": "Пошук вузлів...", - "channels": "Пошук каналів...", - "commandPalette": "Пошук команд..." - }, - "toast": { - "positionRequestSent": { - "title": "Запит на позицію надіслано." - }, - "requestingPosition": { - "title": "Requesting position, please wait..." - }, - "sendingTraceroute": { - "title": "Sending Traceroute, please wait..." - }, - "tracerouteSent": { - "title": "Traceroute sent." - }, - "savedChannel": { - "title": "Saved Channel: {{channelName}}" - }, - "messages": { - "pkiEncryption": { - "title": "Чат використовує шифрування PKI." - }, - "pskEncryption": { - "title": "Чат використовує PSK шифрування." - } - }, - "configSaveError": { - "title": "Помилка збереження налаштувань", - "description": "An error occurred while saving the configuration." - }, - "validationError": { - "title": "Config Errors Exist", - "description": "Please fix the configuration errors before saving." - }, - "saveSuccess": { - "title": "Saving Config", - "description": "The configuration change {{case}} has been saved." - }, - "favoriteNode": { - "title": "{{action}} {{nodeName}} {{direction}} favorites.", - "action": { - "added": "Додано", - "removed": "Видалено", - "to": "до", - "from": "від" - } - }, - "ignoreNode": { - "title": "{{action}} {{nodeName}} {{direction}} ignore list", - "action": { - "added": "Додано", - "removed": "Видалено", - "to": "до", - "from": "від" - } - } - }, - "notifications": { - "copied": { - "label": "Скопійовано!" - }, - "copyToClipboard": { - "label": "Копіювати до буфера обміну" - }, - "hidePassword": { - "label": "Приховати пароль" - }, - "showPassword": { - "label": "Показати пароль" - }, - "deliveryStatus": { - "delivered": "Доставлено", - "failed": "Delivery Failed", - "waiting": "Очікування", - "unknown": "Unknown" - } - }, - "general": { - "label": "General" - }, - "hardware": { - "label": "Hardware" - }, - "metrics": { - "label": "Метрики" - }, - "role": { - "label": "Роль" - }, - "filter": { - "label": "Фільтри" - }, - "advanced": { - "label": "Розширені" - }, - "clearInput": { - "label": "Clear input" - }, - "resetFilters": { - "label": "Скинути фільтри" - }, - "nodeName": { - "label": "Node name/number", - "placeholder": "Meshtastic 1234" - }, - "airtimeUtilization": { - "label": "Airtime Utilization (%)" - }, - "batteryLevel": { - "label": "Рівень заряду батареї (%)", - "labelText": "Рівень заряду батареї (%): {{value}}" - }, - "batteryVoltage": { - "label": "Напруга батареї (В)", - "title": "Напруга" - }, - "channelUtilization": { - "label": "Channel Utilization (%)" - }, - "hops": { - "direct": "Direct", - "label": "Number of hops", - "text": "Number of hops: {{value}}" - }, - "lastHeard": { - "label": "Last heard", - "labelText": "Last heard: {{value}}", - "nowLabel": "Зараз" - }, - "snr": { - "label": "SNR (дБ)" - }, - "favorites": { - "label": "Обране" - }, - "hide": { - "label": "Сховати" - }, - "showOnly": { - "label": "Show Only" - }, - "viaMqtt": { - "label": "Під'єднано за допомогою MQTT" - }, - "hopsUnknown": { - "label": "Unknown number of hops" - }, - "showUnheard": { - "label": "Never heard" - }, - "language": { - "label": "Мова", - "changeLanguage": "Змінити мову" - }, - "theme": { - "dark": "Темна", - "light": "Світла", - "system": "Automatic", - "changeTheme": "Змінити схему кольорів" - }, - "errorPage": { - "title": "This is a little embarrassing...", - "description1": "We are really sorry but an error occurred in the web client that caused it to crash.
This is not supposed to happen, and we are working hard to fix it.", - "description2": "The best way to prevent this from happening again to you or anyone else is to report the issue to us.", - "reportInstructions": "Please include the following information in your report:", - "reportSteps": { - "step1": "What you were doing when the error occurred", - "step2": "What you expected to happen", - "step3": "What actually happened", - "step4": "Any other relevant information" - }, - "reportLink": "Ви можете повідомити про проблему на нашому <0>GitHub", - "dashboardLink": "Поверніться до <0>панелі", - "detailsSummary": "Інформація про помилку", - "errorMessageLabel": "Помилка:", - "stackTraceLabel": "Stack trace:", - "fallbackError": "{{error}}" - }, - "footer": { - "text": "Powered by <0>▲ Vercel | Meshtastic® is a registered trademark of Meshtastic LLC. | <1>Legal Information", - "commitSha": "SHA коміту: {{sha}}" - } + "navigation": { + "title": "Навігація", + "messages": "Повідомлення", + "map": "Мапа", + "settings": "Налаштування", + "channels": "Канали", + "radioConfig": "Налаштування радіо", + "deviceConfig": "Налаштування пристрою", + "moduleConfig": "Module Config", + "manageConnections": "Manage Connections", + "nodes": "Вузли" + }, + "app": { + "title": "Meshtastic", + "logo": "Логотип Meshtastic" + }, + "sidebar": { + "collapseToggle": { + "button": { + "open": "Відкрити бічну панель", + "close": "Закрити бічну панель" + } + }, + "deviceInfo": { + "volts": "{{voltage}} Вольт", + "firmware": { + "title": "Прошивка", + "version": "v{{version}}", + "buildDate": "Дата збірки: {{date}}" + } + } + }, + "batteryStatus": { + "charging": "{{level}}% charging", + "pluggedIn": "Plugged in", + "title": "Батарея" + }, + "search": { + "nodes": "Пошук вузлів...", + "channels": "Пошук каналів...", + "commandPalette": "Пошук команд..." + }, + "toast": { + "positionRequestSent": { + "title": "Запит на позицію надіслано." + }, + "requestingPosition": { + "title": "Requesting position, please wait..." + }, + "sendingTraceroute": { + "title": "Sending Traceroute, please wait..." + }, + "tracerouteSent": { + "title": "Traceroute sent." + }, + "savedChannel": { + "title": "Saved Channel: {{channelName}}" + }, + "messages": { + "pkiEncryption": { + "title": "Чат використовує шифрування PKI." + }, + "pskEncryption": { + "title": "Чат використовує PSK шифрування." + } + }, + "configSaveError": { + "title": "Помилка збереження налаштувань", + "description": "An error occurred while saving the configuration." + }, + "validationError": { + "title": "Config Errors Exist", + "description": "Please fix the configuration errors before saving." + }, + "saveSuccess": { + "title": "Saving Config", + "description": "The configuration change {{case}} has been saved." + }, + "saveAllSuccess": { + "title": "Saved", + "description": "All configuration changes have been saved." + }, + "favoriteNode": { + "title": "{{action}} {{nodeName}} {{direction}} favorites.", + "action": { + "added": "Додано", + "removed": "Видалено", + "to": "до", + "from": "від" + } + }, + "ignoreNode": { + "title": "{{action}} {{nodeName}} {{direction}} ignore list", + "action": { + "added": "Додано", + "removed": "Видалено", + "to": "до", + "from": "від" + } + } + }, + "notifications": { + "copied": { + "label": "Скопійовано!" + }, + "copyToClipboard": { + "label": "Копіювати до буфера обміну" + }, + "hidePassword": { + "label": "Приховати пароль" + }, + "showPassword": { + "label": "Показати пароль" + }, + "deliveryStatus": { + "delivered": "Доставлено", + "failed": "Delivery Failed", + "waiting": "Очікування", + "unknown": "Unknown" + } + }, + "general": { + "label": "General" + }, + "hardware": { + "label": "Hardware" + }, + "metrics": { + "label": "Метрики" + }, + "role": { + "label": "Роль" + }, + "filter": { + "label": "Фільтри" + }, + "advanced": { + "label": "Розширені" + }, + "clearInput": { + "label": "Clear input" + }, + "resetFilters": { + "label": "Скинути фільтри" + }, + "nodeName": { + "label": "Node name/number", + "placeholder": "Meshtastic 1234" + }, + "airtimeUtilization": { + "label": "Airtime Utilization (%)", + "short": "Airtime Util. (%)" + }, + "batteryLevel": { + "label": "Рівень заряду батареї (%)", + "labelText": "Рівень заряду батареї (%): {{value}}" + }, + "batteryVoltage": { + "label": "Напруга батареї (В)", + "title": "Напруга" + }, + "channelUtilization": { + "label": "Channel Utilization (%)", + "short": "Channel Util. (%)" + }, + "hops": { + "direct": "Direct", + "label": "Number of hops", + "text": "Number of hops: {{value}}" + }, + "lastHeard": { + "label": "Last heard", + "labelText": "Last heard: {{value}}", + "nowLabel": "Зараз" + }, + "snr": { + "label": "SNR (дБ)" + }, + "favorites": { + "label": "Обране" + }, + "hide": { + "label": "Сховати" + }, + "showOnly": { + "label": "Show Only" + }, + "viaMqtt": { + "label": "Під'єднано за допомогою MQTT" + }, + "hopsUnknown": { + "label": "Unknown number of hops" + }, + "showUnheard": { + "label": "Never heard" + }, + "language": { + "label": "Мова", + "changeLanguage": "Змінити мову" + }, + "theme": { + "dark": "Темна", + "light": "Світла", + "system": "Automatic", + "changeTheme": "Змінити схему кольорів" + }, + "errorPage": { + "title": "This is a little embarrassing...", + "description1": "We are really sorry but an error occurred in the web client that caused it to crash.
This is not supposed to happen, and we are working hard to fix it.", + "description2": "The best way to prevent this from happening again to you or anyone else is to report the issue to us.", + "reportInstructions": "Please include the following information in your report:", + "reportSteps": { + "step1": "What you were doing when the error occurred", + "step2": "What you expected to happen", + "step3": "What actually happened", + "step4": "Any other relevant information" + }, + "reportLink": "Ви можете повідомити про проблему на нашому <0>GitHub", + "connectionsLink": "Return to the <0>connections", + "detailsSummary": "Інформація про помилку", + "errorMessageLabel": "Помилка:", + "stackTraceLabel": "Stack trace:", + "fallbackError": "{{error}}" + }, + "footer": { + "text": "Powered by <0>▲ Vercel | Meshtastic® is a registered trademark of Meshtastic LLC. | <1>Legal Information", + "commitSha": "SHA коміту: {{sha}}" + } } diff --git a/packages/web/public/i18n/locales/zh-CN/channels.json b/packages/web/public/i18n/locales/zh-CN/channels.json index c1ba3ed55..81436cbcf 100644 --- a/packages/web/public/i18n/locales/zh-CN/channels.json +++ b/packages/web/public/i18n/locales/zh-CN/channels.json @@ -1,69 +1,71 @@ { - "page": { - "sectionLabel": "频道", - "channelName": "Channel: {{channelName}}", - "broadcastLabel": "主要", - "channelIndex": "Ch {{index}}" - }, - "validation": { - "pskInvalid": "Please enter a valid {{bits}} bit PSK." - }, - "settings": { - "label": "频道设置", - "description": "Crypto, MQTT & misc settings" - }, - "role": { - "label": "角色", - "description": "Device telemetry is sent over PRIMARY. Only one PRIMARY allowed", - "options": { - "primary": "PRIMARY", - "disabled": "DISABLED", - "secondary": "SECONDARY" - } - }, - "psk": { - "label": "Pre-Shared Key", - "description": "Supported PSK lengths: 256-bit, 128-bit, 8-bit, Empty (0-bit)", - "generate": "Generate" - }, - "name": { - "label": "名称", - "description": "A unique name for the channel <12 bytes, leave blank for default" - }, - "uplinkEnabled": { - "label": "启用上传", - "description": "Send messages from the local mesh to MQTT" - }, - "downlinkEnabled": { - "label": "启用下载", - "description": "Send messages from MQTT to the local mesh" - }, - "positionPrecision": { - "label": "位置", - "description": "The precision of the location to share with the channel. Can be disabled.", - "options": { - "none": "Do not share location", - "precise": "Precise Location", - "metric_km23": "Within 23 kilometers", - "metric_km12": "Within 12 kilometers", - "metric_km5_8": "Within 5.8 kilometers", - "metric_km2_9": "Within 2.9 kilometers", - "metric_km1_5": "Within 1.5 kilometers", - "metric_m700": "Within 700 meters", - "metric_m350": "Within 350 meters", - "metric_m200": "Within 200 meters", - "metric_m90": "Within 90 meters", - "metric_m50": "Within 50 meters", - "imperial_mi15": "Within 15 miles", - "imperial_mi7_3": "Within 7.3 miles", - "imperial_mi3_6": "Within 3.6 miles", - "imperial_mi1_8": "Within 1.8 miles", - "imperial_mi0_9": "Within 0.9 miles", - "imperial_mi0_5": "Within 0.5 miles", - "imperial_mi0_2": "Within 0.2 miles", - "imperial_ft600": "Within 600 feet", - "imperial_ft300": "Within 300 feet", - "imperial_ft150": "Within 150 feet" - } - } + "page": { + "sectionLabel": "频道", + "channelName": "Channel: {{channelName}}", + "broadcastLabel": "主要", + "channelIndex": "Ch {{index}}", + "import": "导入", + "export": "Export" + }, + "validation": { + "pskInvalid": "Please enter a valid {{bits}} bit PSK." + }, + "settings": { + "label": "频道设置", + "description": "Crypto, MQTT & misc settings" + }, + "role": { + "label": "角色", + "description": "Device telemetry is sent over PRIMARY. Only one PRIMARY allowed", + "options": { + "primary": "PRIMARY", + "disabled": "DISABLED", + "secondary": "SECONDARY" + } + }, + "psk": { + "label": "Pre-Shared Key", + "description": "Supported PSK lengths: 256-bit, 128-bit, 8-bit, Empty (0-bit)", + "generate": "Generate" + }, + "name": { + "label": "名称", + "description": "A unique name for the channel <12 bytes, leave blank for default" + }, + "uplinkEnabled": { + "label": "启用上传", + "description": "Send messages from the local mesh to MQTT" + }, + "downlinkEnabled": { + "label": "启用下载", + "description": "Send messages from MQTT to the local mesh" + }, + "positionPrecision": { + "label": "位置", + "description": "The precision of the location to share with the channel. Can be disabled.", + "options": { + "none": "Do not share location", + "precise": "Precise Location", + "metric_km23": "Within 23 kilometers", + "metric_km12": "Within 12 kilometers", + "metric_km5_8": "Within 5.8 kilometers", + "metric_km2_9": "Within 2.9 kilometers", + "metric_km1_5": "Within 1.5 kilometers", + "metric_m700": "Within 700 meters", + "metric_m350": "Within 350 meters", + "metric_m200": "Within 200 meters", + "metric_m90": "Within 90 meters", + "metric_m50": "Within 50 meters", + "imperial_mi15": "Within 15 miles", + "imperial_mi7_3": "Within 7.3 miles", + "imperial_mi3_6": "Within 3.6 miles", + "imperial_mi1_8": "Within 1.8 miles", + "imperial_mi0_9": "Within 0.9 miles", + "imperial_mi0_5": "Within 0.5 miles", + "imperial_mi0_2": "Within 0.2 miles", + "imperial_ft600": "Within 600 feet", + "imperial_ft300": "Within 300 feet", + "imperial_ft150": "Within 150 feet" + } + } } diff --git a/packages/web/public/i18n/locales/zh-CN/commandPalette.json b/packages/web/public/i18n/locales/zh-CN/commandPalette.json index 5d1e494cf..476f05125 100644 --- a/packages/web/public/i18n/locales/zh-CN/commandPalette.json +++ b/packages/web/public/i18n/locales/zh-CN/commandPalette.json @@ -15,7 +15,6 @@ "messages": "消息", "map": "地图", "config": "配置", - "channels": "频道", "nodes": "节点" } }, @@ -45,7 +44,8 @@ "label": "调试", "command": { "reconfigure": "Reconfigure", - "clearAllStoredMessages": "Clear All Stored Message" + "clearAllStoredMessages": "Clear All Stored Message", + "clearAllStores": "Clear All Local Storage" } } } diff --git a/packages/web/public/i18n/locales/zh-CN/common.json b/packages/web/public/i18n/locales/zh-CN/common.json index 9d3e0e655..d2b306341 100644 --- a/packages/web/public/i18n/locales/zh-CN/common.json +++ b/packages/web/public/i18n/locales/zh-CN/common.json @@ -1,142 +1,165 @@ { - "button": { - "apply": "申请", - "backupKey": "Backup Key", - "cancel": "取消", - "clearMessages": "Clear Messages", - "close": "关闭", - "confirm": "Confirm", - "delete": "删除", - "dismiss": "收起键盘", - "download": "下载", - "export": "Export", - "generate": "Generate", - "regenerate": "Regenerate", - "import": "导入", - "message": "信息", - "now": "Now", - "ok": "确定", - "print": "Print", - "remove": "移除", - "requestNewKeys": "Request New Keys", - "requestPosition": "Request Position", - "reset": "重置", - "save": "保存", - "scanQr": "扫描二维码", - "traceRoute": "Trace Route", - "submit": "Submit" - }, - "app": { - "title": "Meshtastic", - "fullTitle": "Meshtastic Web Client" - }, - "loading": "Loading...", - "unit": { - "cps": "CPS", - "dbm": "dBm", - "hertz": "Hz", - "hop": { - "one": "Hop", - "plural": "Hops" - }, - "hopsAway": { - "one": "{{count}} hop away", - "plural": "{{count}} hops away", - "unknown": "Unknown hops away" - }, - "megahertz": "MHz", - "raw": "raw", - "meter": { - "one": "Meter", - "plural": "Meters", - "suffix": "m" - }, - "minute": { - "one": "Minute", - "plural": "Minutes" - }, - "hour": { - "one": "小时", - "plural": "Hours" - }, - "millisecond": { - "one": "Millisecond", - "plural": "Milliseconds", - "suffix": "ms" - }, - "second": { - "one": "Second", - "plural": "Seconds" - }, - "day": { - "one": "Day", - "plural": "Days" - }, - "month": { - "one": "Month", - "plural": "Months" - }, - "year": { - "one": "Year", - "plural": "Years" - }, - "snr": "SNR", - "volt": { - "one": "Volt", - "plural": "Volts", - "suffix": "V" - }, - "record": { - "one": "Records", - "plural": "Records" - } - }, - "security": { - "0bit": "空", - "8bit": "8 bit", - "128bit": "128 bit", - "256bit": "256 bit" - }, - "unknown": { - "longName": "未知", - "shortName": "UNK", - "notAvailable": "N/A", - "num": "??" - }, - "nodeUnknownPrefix": "!", - "unset": "UNSET", - "fallbackName": "Meshtastic {{last4}}", - "node": "Node", - "formValidation": { - "unsavedChanges": "Unsaved changes", - "tooBig": { - "string": "Too long, expected less than or equal to {{maximum}} characters.", - "number": "Too big, expected a number smaller than or equal to {{maximum}}.", - "bytes": "Too big, expected less than or equal to {{params.maximum}} bytes." - }, - "tooSmall": { - "string": "Too short, expected more than or equal to {{minimum}} characters.", - "number": "Too small, expected a number larger than or equal to {{minimum}}." - }, - "invalidFormat": { - "ipv4": "Invalid format, expected an IPv4 address.", - "key": "Invalid format, expected a Base64 encoded pre-shared key (PSK)." - }, - "invalidType": { - "number": "Invalid type, expected a number." - }, - "pskLength": { - "0bit": "Key is required to be empty.", - "8bit": "Key is required to be an 8 bit pre-shared key (PSK).", - "128bit": "Key is required to be a 128 bit pre-shared key (PSK).", - "256bit": "Key is required to be a 256 bit pre-shared key (PSK)." - }, - "required": { - "generic": "This field is required.", - "managed": "At least one admin key is requred if the node is managed.", - "key": "Key is required." - } - }, - "yes": "Yes", - "no": "No" + "button": { + "apply": "申请", + "addConnection": "Add Connection", + "saveConnection": "Save connection", + "backupKey": "Backup Key", + "cancel": "取消", + "connect": "连接", + "clearMessages": "Clear Messages", + "close": "关闭", + "confirm": "Confirm", + "delete": "删除", + "dismiss": "收起键盘", + "download": "下载", + "disconnect": "断开", + "export": "Export", + "generate": "Generate", + "regenerate": "Regenerate", + "import": "导入", + "message": "信息", + "now": "Now", + "ok": "确定", + "print": "Print", + "remove": "移除", + "requestNewKeys": "Request New Keys", + "requestPosition": "Request Position", + "reset": "重置", + "retry": "Retry", + "save": "保存", + "setDefault": "Set as default", + "unsetDefault": "Unset default", + "scanQr": "扫描二维码", + "traceRoute": "Trace Route", + "submit": "Submit" + }, + "app": { + "title": "Meshtastic", + "fullTitle": "Meshtastic Web Client" + }, + "loading": "Loading...", + "unit": { + "cps": "CPS", + "dbm": "dBm", + "hertz": "Hz", + "hop": { + "one": "Hop", + "plural": "Hops" + }, + "hopsAway": { + "one": "{{count}} hop away", + "plural": "{{count}} hops away", + "unknown": "Unknown hops away" + }, + "megahertz": "MHz", + "kilohertz": "kHz", + "raw": "raw", + "meter": { + "one": "Meter", + "plural": "Meters", + "suffix": "m" + }, + "kilometer": { + "one": "Kilometer", + "plural": "Kilometers", + "suffix": "km" + }, + "minute": { + "one": "Minute", + "plural": "Minutes" + }, + "hour": { + "one": "小时", + "plural": "Hours" + }, + "millisecond": { + "one": "Millisecond", + "plural": "Milliseconds", + "suffix": "ms" + }, + "second": { + "one": "Second", + "plural": "Seconds" + }, + "day": { + "one": "Day", + "plural": "Days", + "today": "Today", + "yesterday": "Yesterday" + }, + "month": { + "one": "Month", + "plural": "Months" + }, + "year": { + "one": "Year", + "plural": "Years" + }, + "snr": "SNR", + "volt": { + "one": "Volt", + "plural": "Volts", + "suffix": "V" + }, + "record": { + "one": "Records", + "plural": "Records" + }, + "degree": { + "one": "Degree", + "plural": "Degrees", + "suffix": "°" + } + }, + "security": { + "0bit": "空", + "8bit": "8 bit", + "128bit": "128 bit", + "256bit": "256 bit" + }, + "unknown": { + "longName": "未知", + "shortName": "UNK", + "notAvailable": "N/A", + "num": "??" + }, + "nodeUnknownPrefix": "!", + "unset": "UNSET", + "fallbackName": "Meshtastic {{last4}}", + "node": "Node", + "formValidation": { + "unsavedChanges": "Unsaved changes", + "tooBig": { + "string": "Too long, expected less than or equal to {{maximum}} characters.", + "number": "Too big, expected a number smaller than or equal to {{maximum}}.", + "bytes": "Too big, expected less than or equal to {{params.maximum}} bytes." + }, + "tooSmall": { + "string": "Too short, expected more than or equal to {{minimum}} characters.", + "number": "Too small, expected a number larger than or equal to {{minimum}}." + }, + "invalidFormat": { + "ipv4": "Invalid format, expected an IPv4 address.", + "key": "Invalid format, expected a Base64 encoded pre-shared key (PSK)." + }, + "invalidType": { + "number": "Invalid type, expected a number." + }, + "pskLength": { + "0bit": "Key is required to be empty.", + "8bit": "Key is required to be an 8 bit pre-shared key (PSK).", + "128bit": "Key is required to be a 128 bit pre-shared key (PSK).", + "256bit": "Key is required to be a 256 bit pre-shared key (PSK)." + }, + "required": { + "generic": "This field is required.", + "managed": "At least one admin key is requred if the node is managed.", + "key": "Key is required." + }, + "invalidOverrideFreq": { + "number": "Invalid format, expected a value in the range 410-930 MHz or 0 (use default)." + } + }, + "yes": "Yes", + "no": "No" } diff --git a/packages/web/public/i18n/locales/zh-CN/config.json b/packages/web/public/i18n/locales/zh-CN/config.json new file mode 100644 index 000000000..427e11144 --- /dev/null +++ b/packages/web/public/i18n/locales/zh-CN/config.json @@ -0,0 +1,458 @@ +{ + "page": { + "title": "设置", + "tabUser": "用户", + "tabChannels": "频道", + "tabBluetooth": "蓝牙", + "tabDevice": "设备", + "tabDisplay": "显示", + "tabLora": "LoRa", + "tabNetwork": "网络", + "tabPosition": "定位", + "tabPower": "电源", + "tabSecurity": "安全" + }, + "sidebar": { + "label": "Configuration" + }, + "device": { + "title": "Device Settings", + "description": "Settings for the device", + "buttonPin": { + "description": "Button pin override", + "label": "Button Pin" + }, + "buzzerPin": { + "description": "Buzzer pin override", + "label": "Buzzer Pin" + }, + "disableTripleClick": { + "description": "Disable triple click", + "label": "Disable Triple Click" + }, + "doubleTapAsButtonPress": { + "description": "Treat double tap as button press", + "label": "Double Tap as Button Press" + }, + "ledHeartbeatDisabled": { + "description": "Disable default blinking LED", + "label": "LED Heartbeat Disabled" + }, + "nodeInfoBroadcastInterval": { + "description": "How often to broadcast node info", + "label": "Node Info Broadcast Interval" + }, + "posixTimezone": { + "description": "The POSIX timezone string for the device", + "label": "POSIX 时区" + }, + "rebroadcastMode": { + "description": "How to handle rebroadcasting", + "label": "转播模式" + }, + "role": { + "description": "What role the device performs on the mesh", + "label": "角色" + } + }, + "bluetooth": { + "title": "Bluetooth Settings", + "description": "Settings for the Bluetooth module", + "note": "Note: Some devices (ESP32) cannot use both Bluetooth and WiFi at the same time.", + "enabled": { + "description": "Enable or disable Bluetooth", + "label": "启用" + }, + "pairingMode": { + "description": "Pin selection behaviour.", + "label": "配对模式" + }, + "pin": { + "description": "Pin to use when pairing", + "label": "Pin" + } + }, + "display": { + "description": "Settings for the device display", + "title": "Display Settings", + "headingBold": { + "description": "Bolden the heading text", + "label": "Bold Heading" + }, + "carouselDelay": { + "description": "How fast to cycle through windows", + "label": "Carousel Delay" + }, + "compassNorthTop": { + "description": "Fix north to the top of compass", + "label": "Compass North Top" + }, + "displayMode": { + "description": "Screen layout variant", + "label": "显示模式" + }, + "displayUnits": { + "description": "Display metric or imperial units", + "label": "显示单位" + }, + "flipScreen": { + "description": "Flip display 180 degrees", + "label": "Flip Screen" + }, + "gpsDisplayUnits": { + "description": "Coordinate display format", + "label": "GPS Display Units" + }, + "oledType": { + "description": "Type of OLED screen attached to the device", + "label": "OLED 类型" + }, + "screenTimeout": { + "description": "Turn off the display after this long", + "label": "Screen Timeout" + }, + "twelveHourClock": { + "description": "Use 12-hour clock format", + "label": "12-Hour Clock" + }, + "wakeOnTapOrMotion": { + "description": "Wake the device on tap or motion", + "label": "Wake on Tap or Motion" + } + }, + "lora": { + "title": "Mesh Settings", + "description": "Settings for the LoRa mesh", + "bandwidth": { + "description": "Channel bandwidth in kHz", + "label": "带宽" + }, + "boostedRxGain": { + "description": "Boosted RX gain", + "label": "Boosted RX Gain" + }, + "codingRate": { + "description": "The denominator of the coding rate", + "label": "编码率" + }, + "frequencyOffset": { + "description": "Frequency offset to correct for crystal calibration errors", + "label": "Frequency Offset" + }, + "frequencySlot": { + "description": "LoRa frequency channel number", + "label": "Frequency Slot" + }, + "hopLimit": { + "description": "Maximum number of hops", + "label": "Hop Limit" + }, + "ignoreMqtt": { + "description": "Don't forward MQTT messages over the mesh", + "label": "忽略 MQTT" + }, + "modemPreset": { + "description": "Modem preset to use", + "label": "调制解调器预设" + }, + "okToMqtt": { + "description": "When set to true, this configuration indicates that the user approves the packet to be uploaded to MQTT. If set to false, remote nodes are requested not to forward packets to MQTT", + "label": "使用MQTT" + }, + "overrideDutyCycle": { + "description": "覆盖占空比", + "label": "覆盖占空比" + }, + "overrideFrequency": { + "description": "Override frequency", + "label": "Override Frequency" + }, + "region": { + "description": "Sets the region for your node", + "label": "区域" + }, + "spreadingFactor": { + "description": "Indicates the number of chirps per symbol", + "label": "Spreading Factor" + }, + "transmitEnabled": { + "description": "Enable/Disable transmit (TX) from the LoRa radio", + "label": "启用传输" + }, + "transmitPower": { + "description": "Max transmit power", + "label": "Transmit Power" + }, + "usePreset": { + "description": "Use one of the predefined modem presets", + "label": "使用预设" + }, + "meshSettings": { + "description": "Settings for the LoRa mesh", + "label": "Mesh Settings" + }, + "waveformSettings": { + "description": "Settings for the LoRa waveform", + "label": "Waveform Settings" + }, + "radioSettings": { + "label": "Radio Settings", + "description": "Settings for the LoRa radio" + } + }, + "network": { + "title": "WiFi Config", + "description": "WiFi radio configuration", + "note": "Note: Some devices (ESP32) cannot use both Bluetooth and WiFi at the same time.", + "addressMode": { + "description": "Address assignment selection", + "label": "Address Mode" + }, + "dns": { + "description": "DNS Server", + "label": "DNS" + }, + "ethernetEnabled": { + "description": "Enable or disable the Ethernet port", + "label": "启用" + }, + "gateway": { + "description": "Default Gateway", + "label": "网关" + }, + "ip": { + "description": "IP Address", + "label": "IP" + }, + "psk": { + "description": "Network password", + "label": "共享密钥/PSK" + }, + "ssid": { + "description": "Network name", + "label": "SSID" + }, + "subnet": { + "description": "Subnet Mask", + "label": "子网" + }, + "wifiEnabled": { + "description": "Enable or disable the WiFi radio", + "label": "启用" + }, + "meshViaUdp": { + "label": "Mesh via UDP" + }, + "ntpServer": { + "label": "NTP Server" + }, + "rsyslogServer": { + "label": "Rsyslog Server" + }, + "ethernetConfigSettings": { + "description": "Ethernet port configuration", + "label": "Ethernet Config" + }, + "ipConfigSettings": { + "description": "IP configuration", + "label": "IP Config" + }, + "ntpConfigSettings": { + "description": "NTP configuration", + "label": "NTP Config" + }, + "rsyslogConfigSettings": { + "description": "Rsyslog configuration", + "label": "Rsyslog Config" + }, + "udpConfigSettings": { + "description": "UDP over Mesh configuration", + "label": "UDP 设置" + } + }, + "position": { + "title": "Position Settings", + "description": "Settings for the position module", + "broadcastInterval": { + "description": "How often your position is sent out over the mesh", + "label": "广播间隔" + }, + "enablePin": { + "description": "GPS module enable pin override", + "label": "Enable Pin" + }, + "fixedPosition": { + "description": "Don't report GPS position, but a manually-specified one", + "label": "Fixed Position" + }, + "gpsMode": { + "description": "Configure whether device GPS is Enabled, Disabled, or Not Present", + "label": "GPS Mode" + }, + "gpsUpdateInterval": { + "description": "How often a GPS fix should be acquired", + "label": "GPS Update Interval" + }, + "positionFlags": { + "description": "Optional fields to include when assembling position messages. The more fields are selected, the larger the message will be leading to longer airtime usage and a higher risk of packet loss.", + "label": "Position Flags" + }, + "receivePin": { + "description": "GPS module RX pin override", + "label": "Receive Pin" + }, + "smartPositionEnabled": { + "description": "Only send position when there has been a meaningful change in location", + "label": "Enable Smart Position" + }, + "smartPositionMinDistance": { + "description": "Minimum distance (in meters) that must be traveled before a position update is sent", + "label": "Smart Position Minimum Distance" + }, + "smartPositionMinInterval": { + "description": "Minimum interval (in seconds) that must pass before a position update is sent", + "label": "Smart Position Minimum Interval" + }, + "transmitPin": { + "description": "GPS module TX pin override", + "label": "Transmit Pin" + }, + "intervalsSettings": { + "description": "How often to send position updates", + "label": "Intervals" + }, + "flags": { + "placeholder": "Select position flags...", + "altitude": "Altitude", + "altitudeGeoidalSeparation": "Altitude Geoidal Separation", + "altitudeMsl": "Altitude is Mean Sea Level", + "dop": "Dilution of precision (DOP) PDOP used by default", + "hdopVdop": "如果设置了 DOP,则使用 HDOP / VDOP 值而不是 PDOP", + "numSatellites": "Number of satellites", + "sequenceNumber": "Sequence number", + "timestamp": "时间戳", + "unset": "未设置", + "vehicleHeading": "Vehicle heading", + "vehicleSpeed": "Vehicle speed" + } + }, + "power": { + "adcMultiplierOverride": { + "description": "Used for tweaking battery voltage reading", + "label": "ADC Multiplier Override ratio" + }, + "ina219Address": { + "description": "Address of the INA219 battery monitor", + "label": "INA219 Address" + }, + "lightSleepDuration": { + "description": "How long the device will be in light sleep for", + "label": "Light Sleep Duration" + }, + "minimumWakeTime": { + "description": "Minimum amount of time the device will stay awake for after receiving a packet", + "label": "Minimum Wake Time" + }, + "noConnectionBluetoothDisabled": { + "description": "If the device does not receive a Bluetooth connection, the BLE radio will be disabled after this long", + "label": "No Connection Bluetooth Disabled" + }, + "powerSavingEnabled": { + "description": "Select if powered from a low-current source (i.e. solar), to minimize power consumption as much as possible.", + "label": "启用节能模式" + }, + "shutdownOnBatteryDelay": { + "description": "Automatically shutdown node after this long when on battery, 0 for indefinite", + "label": "Shutdown on battery delay" + }, + "superDeepSleepDuration": { + "description": "How long the device will be in super deep sleep for", + "label": "Super Deep Sleep Duration" + }, + "powerConfigSettings": { + "description": "Settings for the power module", + "label": "电源配置" + }, + "sleepSettings": { + "description": "Sleep settings for the power module", + "label": "Sleep Settings" + } + }, + "security": { + "description": "Settings for the Security configuration", + "title": "Security Settings", + "button_backupKey": "Backup Key", + "adminChannelEnabled": { + "description": "Allow incoming device control over the insecure legacy admin channel", + "label": "Allow Legacy Admin" + }, + "enableDebugLogApi": { + "description": "Output live debug logging over serial, view and export position-redacted device logs over Bluetooth", + "label": "Enable Debug Log API" + }, + "managed": { + "description": "If enabled, device configuration options are only able to be changed remotely by a Remote Admin node via admin messages. Do not enable this option unless at least one suitable Remote Admin node has been setup, and the public key is stored in one of the fields above.", + "label": "Managed" + }, + "privateKey": { + "description": "Used to create a shared key with a remote device", + "label": "私钥" + }, + "publicKey": { + "description": "Sent out to other nodes on the mesh to allow them to compute a shared secret key", + "label": "公钥" + }, + "primaryAdminKey": { + "description": "The primary public key authorized to send admin messages to this node", + "label": "一级管理员密钥" + }, + "secondaryAdminKey": { + "description": "The secondary public key authorized to send admin messages to this node", + "label": "二级管理员密钥" + }, + "serialOutputEnabled": { + "description": "Serial Console over the Stream API", + "label": "Serial Output Enabled" + }, + "tertiaryAdminKey": { + "description": "The tertiary public key authorized to send admin messages to this node", + "label": "三级管理员密钥" + }, + "adminSettings": { + "description": "Settings for Admin", + "label": "Admin Settings" + }, + "loggingSettings": { + "description": "Settings for Logging", + "label": "Logging Settings" + } + }, + "user": { + "title": "User Settings", + "description": "Configure your device name and identity settings", + "longName": { + "label": "长名称", + "description": "Your full display name (1-40 characters)", + "validation": { + "min": "Long name must be at least 1 character", + "max": "Long name must be at most 40 characters" + } + }, + "shortName": { + "label": "短名称", + "description": "Your abbreviated name (2-4 characters)", + "validation": { + "min": "Short name must be at least 2 characters", + "max": "Short name must be at most 4 characters" + } + }, + "isUnmessageable": { + "label": "无法发送消息", + "description": "Used to identify unmonitored or infrastructure nodes so that messaging is not available to nodes that will never respond." + }, + "isLicensed": { + "label": "业余无线电模式(HAM)", + "description": "Enable if you are a licensed amateur radio operator, enabling this option disables encryption and is not compatible with the default Meshtastic network." + } + } +} diff --git a/packages/web/public/i18n/locales/zh-CN/connections.json b/packages/web/public/i18n/locales/zh-CN/connections.json new file mode 100644 index 000000000..c7d82b165 --- /dev/null +++ b/packages/web/public/i18n/locales/zh-CN/connections.json @@ -0,0 +1,34 @@ +{ + "page": { + "title": "Connect to a Meshtastic device", + "description": "Add a device connection via HTTP, Bluetooth, or Serial. Your saved connections will be saved in your browser." + }, + "connectionType_ble": "BLE", + "connectionType_serial": "串口", + "connectionType_network": "网络", + "deleteConnection": "Delete connection", + "areYouSure": "This will remove {{name}}. You canot undo this action.", + "moreActions": "More actions", + "noConnections": { + "title": "No connections yet.", + "description": "Create your first connection. It will connect immediately and be saved for later." + }, + "lastConnectedAt": "Last connected: {{date}}", + "neverConnected": "Never connected", + "toasts": { + "connected": "已连接", + "nowConnected": "{{name}} is now connected", + "nowDisconnected": "{{name}} are now disconnecte", + "disconnected": "已断开连接", + "failed": "Failed to connect", + "checkConnetion": "Check your device or settings and try again", + "defaultSet": "Default set", + "defaultConnection": "Default connection is now {{nameisconnected}}", + "deleted": "Deleted", + "deletedByName": "{{name}} was removed", + "pickConnectionAgain": "Could not connect. You may need to reselect the device/port.", + "added": "Connection added", + "savedByName": "{{name}} saved.", + "savedCantConnect": "The connection was saved but could not connect." + } +} diff --git a/packages/web/public/i18n/locales/zh-CN/dashboard.json b/packages/web/public/i18n/locales/zh-CN/dashboard.json deleted file mode 100644 index 0dd5f46c3..000000000 --- a/packages/web/public/i18n/locales/zh-CN/dashboard.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "dashboard": { - "title": "Connected Devices", - "description": "Manage your connected Meshtastic devices.", - "connectionType_ble": "BLE", - "connectionType_serial": "串口", - "connectionType_network": "网络", - "noDevicesTitle": "No devices connected", - "noDevicesDescription": "Connect a new device to get started.", - "button_newConnection": "New Connection" - } -} diff --git a/packages/web/public/i18n/locales/zh-CN/deviceConfig.json b/packages/web/public/i18n/locales/zh-CN/deviceConfig.json index 9924d5af2..3f9aac319 100644 --- a/packages/web/public/i18n/locales/zh-CN/deviceConfig.json +++ b/packages/web/public/i18n/locales/zh-CN/deviceConfig.json @@ -122,7 +122,7 @@ "title": "Mesh Settings", "description": "Settings for the LoRa mesh", "bandwidth": { - "description": "Channel bandwidth in MHz", + "description": "Channel bandwidth in kHz", "label": "带宽" }, "boostedRxGain": { diff --git a/packages/web/public/i18n/locales/zh-CN/dialog.json b/packages/web/public/i18n/locales/zh-CN/dialog.json index 9e6f48cf2..88e0bc238 100644 --- a/packages/web/public/i18n/locales/zh-CN/dialog.json +++ b/packages/web/public/i18n/locales/zh-CN/dialog.json @@ -1,193 +1,238 @@ { - "deleteMessages": { - "description": "This action will clear all message history. This cannot be undone. Are you sure you want to continue?", - "title": "Clear All Messages" - }, - "deviceName": { - "description": "The Device will restart once the config is saved.", - "longName": "长名称", - "shortName": "短名称", - "title": "Change Device Name", - "validation": { - "longNameMax": "Long name must not be more than 40 characters", - "shortNameMax": "Short name must not be more than 4 characters", - "longNameMin": "Long name must have at least 1 character", - "shortNameMin": "Short name must have at least 1 character" - } - }, - "import": { - "description": "The current LoRa configuration will be overridden.", - "error": { - "invalidUrl": "Invalid Meshtastic URL" - }, - "channelPrefix": "Channel: ", - "channelSetUrl": "Channel Set/QR Code URL", - "channels": "Channels:", - "usePreset": "Use Preset?", - "title": "Import Channel Set" - }, - "locationResponse": { - "title": "Location: {{identifier}}", - "altitude": "Altitude: ", - "coordinates": "Coordinates: ", - "noCoordinates": "No Coordinates" - }, - "pkiRegenerateDialog": { - "title": "Regenerate Pre-Shared Key?", - "description": "Are you sure you want to regenerate the pre-shared key?", - "regenerate": "Regenerate" - }, - "newDeviceDialog": { - "title": "Connect New Device", - "https": "https", - "http": "http", - "tabHttp": "HTTP", - "tabBluetooth": "蓝牙", - "tabSerial": "串口", - "useHttps": "Use HTTPS", - "connecting": "Connecting...", - "connect": "连接", - "connectionFailedAlert": { - "title": "Connection Failed", - "descriptionPrefix": "Could not connect to the device. ", - "httpsHint": "If using HTTPS, you may need to accept a self-signed certificate first. ", - "openLinkPrefix": "Please open ", - "openLinkSuffix": " in a new tab", - "acceptTlsWarningSuffix": ", accept any TLS warnings if prompted, then try again", - "learnMoreLink": "Learn more" - }, - "httpConnection": { - "label": "IP Address/Hostname", - "placeholder": "000.000.000.000 / meshtastic.local" - }, - "serialConnection": { - "noDevicesPaired": "No devices paired yet.", - "newDeviceButton": "New device", - "deviceIdentifier": "# {{index}} - {{vendorId}} - {{productId}}" - }, - "bluetoothConnection": { - "noDevicesPaired": "No devices paired yet.", - "newDeviceButton": "New device", - "connectionFailed": "Connection failed", - "deviceDisconnected": "Device disconnected", - "unknownDevice": "Unknown Device", - "errorLoadingDevices": "Error loading devices", - "unknownErrorLoadingDevices": "Unknown error loading devices" - }, - "validation": { - "requiresWebBluetooth": "This connection type requires <0>Web Bluetooth. Please use a supported browser, like Chrome or Edge.", - "requiresWebSerial": "This connection type requires <0>Web Serial. Please use a supported browser, like Chrome or Edge.", - "requiresSecureContext": "This application requires a <0>secure context. Please connect using HTTPS or localhost.", - "additionallyRequiresSecureContext": "Additionally, it requires a <0>secure context. Please connect using HTTPS or localhost." - } - }, - "nodeDetails": { - "message": "信息", - "requestPosition": "Request Position", - "traceRoute": "Trace Route", - "airTxUtilization": "Air TX utilization", - "allRawMetrics": "All Raw Metrics:", - "batteryLevel": "Battery level", - "channelUtilization": "Channel utilization", - "details": "Details:", - "deviceMetrics": "Device Metrics:", - "hardware": "Hardware: ", - "lastHeard": "Last Heard: ", - "nodeHexPrefix": "Node Hex: ", - "nodeNumber": "Node Number: ", - "position": "Position:", - "role": "Role: ", - "uptime": "Uptime: ", - "voltage": "电压", - "title": "Node Details for {{identifier}}", - "ignoreNode": "Ignore node", - "removeNode": "Remove node", - "unignoreNode": "Unignore node", - "security": "Security:", - "publicKey": "Public Key: ", - "messageable": "Messageable: ", - "KeyManuallyVerifiedTrue": "Public Key has been manually verified", - "KeyManuallyVerifiedFalse": "Public Key is not manually verified" - }, - "pkiBackup": { - "loseKeysWarning": "If you lose your keys, you will need to reset your device.", - "secureBackup": "Its important to backup your public and private keys and store your backup securely!", - "footer": "=== END OF KEYS ===", - "header": "=== MESHTASTIC KEYS FOR {{longName}} ({{shortName}}) ===", - "privateKey": "Private Key:", - "publicKey": "Public Key:", - "fileName": "meshtastic_keys_{{longName}}_{{shortName}}.txt", - "title": "Backup Keys" - }, - "pkiBackupReminder": { - "description": "We recommend backing up your key data regularly. Would you like to back up now?", - "title": "Backup Reminder", - "remindLaterPrefix": "Remind me in", - "remindNever": "Never remind me", - "backupNow": "Back up now" - }, - "pkiRegenerate": { - "description": "Are you sure you want to regenerate key pair?", - "title": "Regenerate Key Pair" - }, - "qr": { - "addChannels": "Add Channels", - "replaceChannels": "Replace Channels", - "description": "The current LoRa configuration will also be shared.", - "sharableUrl": "Sharable URL", - "title": "生成二维码" - }, - "reboot": { - "title": "Reboot device", - "description": "Reboot now or schedule a reboot of the connected node. Optionally, you can choose to reboot into OTA (Over-the-Air) mode.", - "ota": "Reboot into OTA mode", - "enterDelay": "Enter delay", - "scheduled": "Reboot has been scheduled", - "schedule": "Schedule reboot", - "now": "Reboot now", - "cancel": "Cancel scheduled reboot" - }, - "refreshKeys": { - "description": { - "acceptNewKeys": "This will remove the node from device and request new keys.", - "keyMismatchReasonSuffix": ". This is due to the remote node's current public key does not match the previously stored key for this node.", - "unableToSendDmPrefix": "Your node is unable to send a direct message to node: " - }, - "acceptNewKeys": "Accept New Keys", - "title": "Keys Mismatch - {{identifier}}" - }, - "removeNode": { - "description": "Are you sure you want to remove this Node?", - "title": "Remove Node?" - }, - "shutdown": { - "title": "Schedule Shutdown", - "description": "Turn off the connected node after x minutes." - }, - "traceRoute": { - "routeToDestination": "Route to destination:", - "routeBack": "Route back:" - }, - "tracerouteResponse": { - "title": "Traceroute: {{identifier}}" - }, - "unsafeRoles": { - "confirmUnderstanding": "Yes, I know what I'm doing", - "conjunction": " and the blog post about ", - "postamble": " and understand the implications of changing the role.", - "preamble": "I have read the ", - "choosingRightDeviceRole": "Choosing The Right Device Role", - "deviceRoleDocumentation": "Device Role Documentation", - "title": "是否确认?" - }, - "managedMode": { - "confirmUnderstanding": "Yes, I know what I'm doing", - "title": "是否确认?", - "description": "Enabling Managed Mode blocks client applications (including the web client) from writing configurations to a radio. Once enabled, radio configurations can only be changed through Remote Admin messages. This setting is not required for remote node administration." - }, - "clientNotification": { - "title": "客户端通知", - "TraceRoute can only be sent once every 30 seconds": "TraceRoute can only be sent once every 30 seconds", - "Compromised keys were detected and regenerated.": "Compromised keys were detected and regenerated." - } + "deleteMessages": { + "description": "This action will clear all message history. This cannot be undone. Are you sure you want to continue?", + "title": "Clear All Messages" + }, + "import": { + "description": "The current LoRa configuration will be overridden.", + "error": { + "invalidUrl": "Invalid Meshtastic URL" + }, + "channelPrefix": "Channel: ", + "primary": "Primary ", + "doNotImport": "No not import", + "channelName": "名称", + "channelSlot": "槽位", + "channelSetUrl": "Channel Set/QR Code URL", + "useLoraConfig": "Import LoRa Config", + "presetDescription": "The current LoRa Config will be replaced.", + "title": "Import Channel Set" + }, + "locationResponse": { + "title": "Location: {{identifier}}", + "altitude": "Altitude: ", + "coordinates": "Coordinates: ", + "noCoordinates": "No Coordinates" + }, + "pkiRegenerateDialog": { + "title": "Regenerate Pre-Shared Key?", + "description": "Are you sure you want to regenerate the pre-shared key?", + "regenerate": "Regenerate" + }, + "addConnection": { + "title": "Add connection", + "description": "Choose a connection type and fill in the details", + "validation": { + "requiresWebBluetooth": "This connection type requires <0>Web Bluetooth. Please use a supported browser, like Chrome or Edge.", + "requiresWebSerial": "This connection type requires <0>Web Serial. Please use a supported browser, like Chrome or Edge.", + "requiresSecureContext": "This application requires a <0>secure context. Please connect using HTTPS or localhost.", + "additionallyRequiresSecureContext": "Additionally, it requires a <0>secure context. Please connect using HTTPS or localhost." + }, + "bluetoothConnection": { + "namePlaceholder": "My Bluetooth Node", + "supported": { + "title": "Web Bluetooth supported" + }, + "notSupported": { + "title": "Web Bluetooth not supported", + "description": "Your browser or device does not support Web Bluetooth" + }, + "short": "BT: {{deviceName}}", + "long": "Bluetooth Device", + "device": "设备", + "selectDevice": "Select device", + "selected": "Bluetooth device selected", + "notSelected": "No device selected", + "helperText": "Uses the Meshtastic Bluetooth service for discovery." + }, + "serialConnection": { + "namePlaceholder": "My Serial Node", + "helperText": "Selecting a port grants permission so the app can open it to connect.", + "supported": { + "title": "Web Serial supported" + }, + "notSupported": { + "title": "Web Serial not supported", + "description": "Your browser or device does not support Web Serial" + }, + "portSelected": { + "title": "Serial port selected", + "description": "Port permissions granted." + }, + "port": "Port", + "selectPort": "Select port", + "deviceName": "USB {{vendorId}}:{{productId}}", + "notSelected": "No port selected" + }, + "httpConnection": { + "namePlaceholder": "My HTTP Node", + "inputPlaceholder": "192.168.1.10 or meshtastic.local", + "heading": "URL or IP", + "useHttps": "Use HTTTPS", + "invalidUrl": { + "title": "Invalid URL", + "description": "Please enter a valid HTTP or HTTPS URL." + }, + "connectionTest": { + "description": "Test the connetion before saving to verify the device is reachable.", + "button": { + "loading": "Testing...", + "label": "Test connection" + }, + "reachable": "Reachable", + "notReachable": "Not reachable", + "success": { + "title": "Connection test successful", + "description": "The device appears to be reachable." + }, + "failure": { + "title": "Connection test failed", + "description": "Could not reach the device. Check the URL and try again." + } + } + } + }, + "nodeDetails": { + "message": "信息", + "requestPosition": "Request Position", + "traceRoute": "Trace Route", + "airTxUtilization": "Air TX utilization", + "allRawMetrics": "All Raw Metrics:", + "batteryLevel": "Battery level", + "channelUtilization": "Channel utilization", + "details": "Details:", + "deviceMetrics": "Device Metrics:", + "hardware": "Hardware: ", + "lastHeard": "Last Heard: ", + "nodeHexPrefix": "Node Hex: ", + "nodeNumber": "Node Number: ", + "position": "Position:", + "role": "Role: ", + "uptime": "Uptime: ", + "voltage": "电压", + "title": "Node Details for {{identifier}}", + "ignoreNode": "Ignore node", + "removeNode": "Remove node", + "unignoreNode": "Unignore node", + "security": "Security:", + "publicKey": "Public Key: ", + "messageable": "Messageable: ", + "KeyManuallyVerifiedTrue": "Public Key has been manually verified", + "KeyManuallyVerifiedFalse": "Public Key is not manually verified" + }, + "pkiBackup": { + "loseKeysWarning": "If you lose your keys, you will need to reset your device.", + "secureBackup": "Its important to backup your public and private keys and store your backup securely!", + "footer": "=== END OF KEYS ===", + "header": "=== MESHTASTIC KEYS FOR {{longName}} ({{shortName}}) ===", + "privateKey": "Private Key:", + "publicKey": "Public Key:", + "fileName": "meshtastic_keys_{{longName}}_{{shortName}}.txt", + "title": "Backup Keys" + }, + "pkiBackupReminder": { + "description": "We recommend backing up your key data regularly. Would you like to back up now?", + "title": "Backup Reminder", + "remindLaterPrefix": "Remind me in", + "remindNever": "Never remind me", + "backupNow": "Back up now" + }, + "pkiRegenerate": { + "description": "Are you sure you want to regenerate key pair?", + "title": "Regenerate Key Pair" + }, + "qr": { + "addChannels": "Add Channels", + "replaceChannels": "Replace Channels", + "description": "The current LoRa configuration will also be shared.", + "sharableUrl": "Sharable URL", + "title": "生成二维码" + }, + "reboot": { + "title": "Reboot device", + "description": "Reboot now or schedule a reboot of the connected node. Optionally, you can choose to reboot into OTA (Over-the-Air) mode.", + "ota": "Reboot into OTA mode", + "enterDelay": "Enter delay", + "scheduled": "Reboot has been scheduled", + "schedule": "Schedule reboot", + "now": "Reboot now", + "cancel": "Cancel scheduled reboot" + }, + "refreshKeys": { + "description": { + "acceptNewKeys": "This will remove the node from device and request new keys.", + "keyMismatchReasonSuffix": ". This is due to the remote node's current public key does not match the previously stored key for this node.", + "unableToSendDmPrefix": "Your node is unable to send a direct message to node: " + }, + "acceptNewKeys": "Accept New Keys", + "title": "Keys Mismatch - {{identifier}}" + }, + "removeNode": { + "description": "Are you sure you want to remove this Node?", + "title": "Remove Node?" + }, + "shutdown": { + "title": "Schedule Shutdown", + "description": "Turn off the connected node after x minutes." + }, + "traceRoute": { + "routeToDestination": "Route to destination:", + "routeBack": "Route back:" + }, + "tracerouteResponse": { + "title": "Traceroute: {{identifier}}" + }, + "unsafeRoles": { + "confirmUnderstanding": "Yes, I know what I'm doing", + "conjunction": " and the blog post about ", + "postamble": " and understand the implications of changing the role.", + "preamble": "I have read the ", + "choosingRightDeviceRole": "Choosing The Right Device Role", + "deviceRoleDocumentation": "Device Role Documentation", + "title": "是否确认?" + }, + "managedMode": { + "confirmUnderstanding": "Yes, I know what I'm doing", + "title": "是否确认?", + "description": "Enabling Managed Mode blocks client applications (including the web client) from writing configurations to a radio. Once enabled, radio configurations can only be changed through Remote Admin messages. This setting is not required for remote node administration." + }, + "clientNotification": { + "title": "客户端通知", + "TraceRoute can only be sent once every 30 seconds": "TraceRoute can only be sent once every 30 seconds", + "Compromised keys were detected and regenerated.": "Compromised keys were detected and regenerated." + }, + "resetNodeDb": { + "title": "Reset Node Database", + "description": "This will clear all nodes from the connected device's node database and clear all message history in the client. This cannot be undone. Are you sure you want to continue?", + "confirm": "Reset Node Database", + "failedTitle": "There was an error resetting the Node DB. Please try again." + }, + "clearAllStores": { + "title": "Clear All Local Storage", + "description": "This will clear all locally stored data, including message history and node databases for all previously connected devices. This will require you to reconnect to your node once complete and cannot be undone. Are you sure you want to continue?", + "confirm": "Clear all local storage", + "failedTitle": "There was an error clearing local storage. Please try again." + }, + "factoryResetDevice": { + "title": "Factory Reset Device", + "description": "This will factory reset the connected device, erasing all configurations and data on the device as well as all nodes and messages saved in the client. This cannot be undone. Are you sure you want to continue?", + "confirm": "Factory Reset Device", + "failedTitle": "There was an error performing the factory reset. Please try again." + }, + "factoryResetConfig": { + "title": "Factory Reset Config", + "description": "This will factory reset the configuration on the connected device, erasing all configurations on the device. This cannot be undone. Are you sure you want to continue?", + "confirm": "Factory Reset Config", + "failedTitle": "There was an error performing the factory reset. Please try again." + } } diff --git a/packages/web/public/i18n/locales/zh-CN/map.json b/packages/web/public/i18n/locales/zh-CN/map.json new file mode 100644 index 000000000..bd5472ae3 --- /dev/null +++ b/packages/web/public/i18n/locales/zh-CN/map.json @@ -0,0 +1,38 @@ +{ + "maplibre": { + "GeolocateControl.FindMyLocation": "Find my location", + "NavigationControl.ZoomIn": "Zoom in", + "NavigationControl.ZoomOut": "Zoom out", + "CooperativeGesturesHandler.WindowsHelpText": "Use Ctrl + scroll to zoom the map", + "CooperativeGesturesHandler.MacHelpText": "Use ⌘ + scroll to zoom the map", + "CooperativeGesturesHandler.MobileHelpText": "Use two fingers to move the map" + }, + "layerTool": { + "nodeMarkers": "Show nodes", + "directNeighbors": "Show direct connections", + "remoteNeighbors": "Show remote connections", + "positionPrecision": "Show position precision", + "traceroutes": "Show traceroutes", + "waypoints": "Show waypoints" + }, + "mapMenu": { + "locateAria": "Locate my node", + "layersAria": "Change map style" + }, + "waypointDetail": { + "edit": "编辑", + "description": "Description:", + "createdBy": "Edited by:", + "createdDate": "Created:", + "updated": "Updated:", + "expires": "Expires:", + "distance": "Distance:", + "bearing": "Absolute bearing:", + "lockedTo": "Locked by:", + "latitude": "Latitude:", + "longitude": "Longitude:" + }, + "myNode": { + "tooltip": "This device" + } +} diff --git a/packages/web/public/i18n/locales/zh-CN/messages.json b/packages/web/public/i18n/locales/zh-CN/messages.json index 790b61b8c..35f3380bb 100644 --- a/packages/web/public/i18n/locales/zh-CN/messages.json +++ b/packages/web/public/i18n/locales/zh-CN/messages.json @@ -1,39 +1,39 @@ { - "page": { - "title": "Messages: {{chatName}}", - "placeholder": "Enter Message" - }, - "emptyState": { - "title": "Select a Chat", - "text": "No messages yet." - }, - "selectChatPrompt": { - "text": "Select a channel or node to start messaging." - }, - "sendMessage": { - "placeholder": "Enter your message here...", - "sendButton": "传送" - }, - "actionsMenu": { - "addReactionLabel": "Add Reaction", - "replyLabel": "回复" - }, - "deliveryStatus": { - "delivered": { - "label": "Message delivered", - "displayText": "Message delivered" - }, - "failed": { - "label": "Message delivery failed", - "displayText": "Delivery failed" - }, - "unknown": { - "label": "Message status unknown", - "displayText": "Unknown state" - }, - "waiting": { - "label": "Sending message", - "displayText": "Waiting for delivery" - } - } + "page": { + "title": "Messages: {{chatName}}", + "placeholder": "Enter Message" + }, + "emptyState": { + "title": "Select a Chat", + "text": "No messages yet." + }, + "selectChatPrompt": { + "text": "Select a channel or node to start messaging." + }, + "sendMessage": { + "placeholder": "Enter your message here...", + "sendButton": "传送" + }, + "actionsMenu": { + "addReactionLabel": "Add Reaction", + "replyLabel": "回复" + }, + "deliveryStatus": { + "delivered": { + "label": "Message delivered", + "displayText": "Message delivered" + }, + "failed": { + "label": "Message delivery failed", + "displayText": "Delivery failed" + }, + "unknown": { + "label": "Message status unknown", + "displayText": "Unknown state" + }, + "waiting": { + "label": "Sending message", + "displayText": "Waiting for delivery" + } + } } diff --git a/packages/web/public/i18n/locales/zh-CN/moduleConfig.json b/packages/web/public/i18n/locales/zh-CN/moduleConfig.json index 8758a23e4..1efed1b2d 100644 --- a/packages/web/public/i18n/locales/zh-CN/moduleConfig.json +++ b/packages/web/public/i18n/locales/zh-CN/moduleConfig.json @@ -1,448 +1,448 @@ { - "page": { - "tabAmbientLighting": "氛围灯", - "tabAudio": "音频", - "tabCannedMessage": "Canned", - "tabDetectionSensor": "检测传感器", - "tabExternalNotification": "Ext Notif", - "tabMqtt": "MQTT", - "tabNeighborInfo": "邻居信息", - "tabPaxcounter": "客流计数", - "tabRangeTest": "拉距测试", - "tabSerial": "串口", - "tabStoreAndForward": "S&F", - "tabTelemetry": "遥测(传感器)" - }, - "ambientLighting": { - "title": "Ambient Lighting Settings", - "description": "Settings for the Ambient Lighting module", - "ledState": { - "label": "LED 状态", - "description": "Sets LED to on or off" - }, - "current": { - "label": "电流", - "description": "Sets the current for the LED output. Default is 10" - }, - "red": { - "label": "红", - "description": "Sets the red LED level. Values are 0-255" - }, - "green": { - "label": "绿", - "description": "Sets the green LED level. Values are 0-255" - }, - "blue": { - "label": "蓝", - "description": "Sets the blue LED level. Values are 0-255" - } - }, - "audio": { - "title": "Audio Settings", - "description": "Settings for the Audio module", - "codec2Enabled": { - "label": "Codec 2 Enabled", - "description": "Enable Codec 2 audio encoding" - }, - "pttPin": { - "label": "PTT Pin", - "description": "GPIO pin to use for PTT" - }, - "bitrate": { - "label": "Bitrate", - "description": "Bitrate to use for audio encoding" - }, - "i2sWs": { - "label": "i2S WS", - "description": "GPIO pin to use for i2S WS" - }, - "i2sSd": { - "label": "i2S SD", - "description": "GPIO pin to use for i2S SD" - }, - "i2sDin": { - "label": "i2S DIN", - "description": "GPIO pin to use for i2S DIN" - }, - "i2sSck": { - "label": "i2S SCK", - "description": "GPIO pin to use for i2S SCK" - } - }, - "cannedMessage": { - "title": "Canned Message Settings", - "description": "Settings for the Canned Message module", - "moduleEnabled": { - "label": "Module Enabled", - "description": "Enable Canned Message" - }, - "rotary1Enabled": { - "label": "Rotary Encoder #1 Enabled", - "description": "Enable the rotary encoder" - }, - "inputbrokerPinA": { - "label": "Encoder Pin A", - "description": "GPIO Pin Value (1-39) For encoder port A" - }, - "inputbrokerPinB": { - "label": "Encoder Pin B", - "description": "GPIO Pin Value (1-39) For encoder port B" - }, - "inputbrokerPinPress": { - "label": "Encoder Pin Press", - "description": "GPIO Pin Value (1-39) For encoder Press" - }, - "inputbrokerEventCw": { - "label": "Clockwise event", - "description": "Select input event." - }, - "inputbrokerEventCcw": { - "label": "Counter Clockwise event", - "description": "Select input event." - }, - "inputbrokerEventPress": { - "label": "Press event", - "description": "Select input event" - }, - "updown1Enabled": { - "label": "Up Down enabled", - "description": "Enable the up / down encoder" - }, - "allowInputSource": { - "label": "Allow Input Source", - "description": "Select from: '_any', 'rotEnc1', 'upDownEnc1', 'cardkb'" - }, - "sendBell": { - "label": "发送铃声", - "description": "Sends a bell character with each message" - } - }, - "detectionSensor": { - "title": "Detection Sensor Settings", - "description": "Settings for the Detection Sensor module", - "enabled": { - "label": "启用", - "description": "Enable or disable Detection Sensor Module" - }, - "minimumBroadcastSecs": { - "label": "Minimum Broadcast Seconds", - "description": "The interval in seconds of how often we can send a message to the mesh when a state change is detected" - }, - "stateBroadcastSecs": { - "label": "State Broadcast Seconds", - "description": "The interval in seconds of how often we should send a message to the mesh with the current state regardless of changes" - }, - "sendBell": { - "label": "发送铃声", - "description": "Send ASCII bell with alert message" - }, - "name": { - "label": "Friendly Name", - "description": "Used to format the message sent to mesh, max 20 Characters" - }, - "monitorPin": { - "label": "Monitor Pin", - "description": "The GPIO pin to monitor for state changes" - }, - "detectionTriggerType": { - "label": "Detection Triggered Type", - "description": "The type of trigger event to be used" - }, - "usePullup": { - "label": "Use Pullup", - "description": "Whether or not use INPUT_PULLUP mode for GPIO pin" - } - }, - "externalNotification": { - "title": "External Notification Settings", - "description": "Configure the external notification module", - "enabled": { - "label": "Module Enabled", - "description": "Enable External Notification" - }, - "outputMs": { - "label": "Output MS", - "description": "Output MS" - }, - "output": { - "label": "Output", - "description": "Output" - }, - "outputVibra": { - "label": "Output Vibrate", - "description": "Output Vibrate" - }, - "outputBuzzer": { - "label": "Output Buzzer", - "description": "Output Buzzer" - }, - "active": { - "label": "Active", - "description": "Active" - }, - "alertMessage": { - "label": "Alert Message", - "description": "Alert Message" - }, - "alertMessageVibra": { - "label": "Alert Message Vibrate", - "description": "Alert Message Vibrate" - }, - "alertMessageBuzzer": { - "label": "Alert Message Buzzer", - "description": "Alert Message Buzzer" - }, - "alertBell": { - "label": "Alert Bell", - "description": "Should an alert be triggered when receiving an incoming bell?" - }, - "alertBellVibra": { - "label": "Alert Bell Vibrate", - "description": "Alert Bell Vibrate" - }, - "alertBellBuzzer": { - "label": "Alert Bell Buzzer", - "description": "Alert Bell Buzzer" - }, - "usePwm": { - "label": "Use PWM", - "description": "Use PWM" - }, - "nagTimeout": { - "label": "Nag Timeout", - "description": "Nag Timeout" - }, - "useI2sAsBuzzer": { - "label": "Use I²S Pin as Buzzer", - "description": "Designate I²S Pin as Buzzer Output" - } - }, - "mqtt": { - "title": "MQTT Settings", - "description": "Settings for the MQTT module", - "enabled": { - "label": "启用", - "description": "Enable or disable MQTT" - }, - "address": { - "label": "MQTT Server Address", - "description": "MQTT server address to use for default/custom servers" - }, - "username": { - "label": "MQTT Username", - "description": "MQTT username to use for default/custom servers" - }, - "password": { - "label": "MQTT Password", - "description": "MQTT password to use for default/custom servers" - }, - "encryptionEnabled": { - "label": "启用加密", - "description": "Enable or disable MQTT encryption. Note: All messages are sent to the MQTT broker unencrypted if this option is not enabled, even when your uplink channels have encryption keys set. This includes position data." - }, - "jsonEnabled": { - "label": "启用 JSON", - "description": "Whether to send/consume JSON packets on MQTT" - }, - "tlsEnabled": { - "label": "启用 TLS", - "description": "Enable or disable TLS" - }, - "root": { - "label": "根主题", - "description": "MQTT root topic to use for default/custom servers" - }, - "proxyToClientEnabled": { - "label": "MQTT Client Proxy Enabled", - "description": "Utilizes the network connection to proxy MQTT messages to the client." - }, - "mapReportingEnabled": { - "label": "Map Reporting Enabled", - "description": "Your node will periodically send an unencrypted map report packet to the configured MQTT server, this includes id, short and long name, approximate location, hardware model, role, firmware version, LoRa region, modem preset and primary channel name." - }, - "mapReportSettings": { - "publishIntervalSecs": { - "label": "Map Report Publish Interval (s)", - "description": "Interval in seconds to publish map reports" - }, - "positionPrecision": { - "label": "Approximate Location", - "description": "Position shared will be accurate within this distance", - "options": { - "metric_km23": "Within 23 km", - "metric_km12": "Within 12 km", - "metric_km5_8": "Within 5.8 km", - "metric_km2_9": "Within 2.9 km", - "metric_km1_5": "Within 1.5 km", - "metric_m700": "Within 700 m", - "metric_m350": "Within 350 m", - "metric_m200": "Within 200 m", - "metric_m90": "Within 90 m", - "metric_m50": "Within 50 m", - "imperial_mi15": "Within 15 miles", - "imperial_mi7_3": "Within 7.3 miles", - "imperial_mi3_6": "Within 3.6 miles", - "imperial_mi1_8": "Within 1.8 miles", - "imperial_mi0_9": "Within 0.9 miles", - "imperial_mi0_5": "Within 0.5 miles", - "imperial_mi0_2": "Within 0.2 miles", - "imperial_ft600": "Within 600 feet", - "imperial_ft300": "Within 300 feet", - "imperial_ft150": "Within 150 feet" - } - } - } - }, - "neighborInfo": { - "title": "Neighbor Info Settings", - "description": "Settings for the Neighbor Info module", - "enabled": { - "label": "启用", - "description": "Enable or disable Neighbor Info Module" - }, - "updateInterval": { - "label": "Update Interval", - "description": "Interval in seconds of how often we should try to send our Neighbor Info to the mesh" - } - }, - "paxcounter": { - "title": "Paxcounter Settings", - "description": "Settings for the Paxcounter module", - "enabled": { - "label": "Module Enabled", - "description": "Enable Paxcounter" - }, - "paxcounterUpdateInterval": { - "label": "Update Interval (seconds)", - "description": "How long to wait between sending paxcounter packets" - }, - "wifiThreshold": { - "label": "WiFi RSSI Threshold", - "description": "At what WiFi RSSI level should the counter increase. Defaults to -80." - }, - "bleThreshold": { - "label": "BLE RSSI Threshold", - "description": "At what BLE RSSI level should the counter increase. Defaults to -80." - } - }, - "rangeTest": { - "title": "Range Test Settings", - "description": "Settings for the Range Test module", - "enabled": { - "label": "Module Enabled", - "description": "Enable Range Test" - }, - "sender": { - "label": "Message Interval", - "description": "How long to wait between sending test packets" - }, - "save": { - "label": "Save CSV to storage", - "description": "ESP32 Only" - } - }, - "serial": { - "title": "Serial Settings", - "description": "Settings for the Serial module", - "enabled": { - "label": "Module Enabled", - "description": "Enable Serial output" - }, - "echo": { - "label": "回声", - "description": "Any packets you send will be echoed back to your device" - }, - "rxd": { - "label": "Receive Pin", - "description": "Set the GPIO pin to the RXD pin you have set up." - }, - "txd": { - "label": "Transmit Pin", - "description": "Set the GPIO pin to the TXD pin you have set up." - }, - "baud": { - "label": "Baud Rate", - "description": "The serial baud rate" - }, - "timeout": { - "label": "超时", - "description": "Seconds to wait before we consider your packet as 'done'" - }, - "mode": { - "label": "模式", - "description": "Select Mode" - }, - "overrideConsoleSerialPort": { - "label": "Override Console Serial Port", - "description": "If you have a serial port connected to the console, this will override it." - } - }, - "storeForward": { - "title": "Store & Forward Settings", - "description": "Settings for the Store & Forward module", - "enabled": { - "label": "Module Enabled", - "description": "Enable Store & Forward" - }, - "heartbeat": { - "label": "Heartbeat Enabled", - "description": "Enable Store & Forward heartbeat" - }, - "records": { - "label": "记录数", - "description": "Number of records to store" - }, - "historyReturnMax": { - "label": "历史记录最大返回值", - "description": "Max number of records to return" - }, - "historyReturnWindow": { - "label": "历史记录返回窗口", - "description": "Max number of records to return" - } - }, - "telemetry": { - "title": "Telemetry Settings", - "description": "Settings for the Telemetry module", - "deviceUpdateInterval": { - "label": "设备指标", - "description": "设备计量更新间隔 (秒)" - }, - "environmentUpdateInterval": { - "label": "环境计量更新间隔 (秒)", - "description": "" - }, - "environmentMeasurementEnabled": { - "label": "Module Enabled", - "description": "Enable the Environment Telemetry" - }, - "environmentScreenEnabled": { - "label": "Displayed on Screen", - "description": "Show the Telemetry Module on the OLED" - }, - "environmentDisplayFahrenheit": { - "label": "展示华氏度", - "description": "Display temp in Fahrenheit" - }, - "airQualityEnabled": { - "label": "Air Quality Enabled", - "description": "Enable the Air Quality Telemetry" - }, - "airQualityInterval": { - "label": "Air Quality Update Interval", - "description": "How often to send Air Quality data over the mesh" - }, - "powerMeasurementEnabled": { - "label": "Power Measurement Enabled", - "description": "Enable the Power Measurement Telemetry" - }, - "powerUpdateInterval": { - "label": "Power Update Interval", - "description": "How often to send Power data over the mesh" - }, - "powerScreenEnabled": { - "label": "Power Screen Enabled", - "description": "Enable the Power Telemetry Screen" - } - } + "page": { + "tabAmbientLighting": "氛围灯", + "tabAudio": "音频", + "tabCannedMessage": "Canned", + "tabDetectionSensor": "检测传感器", + "tabExternalNotification": "Ext Notif", + "tabMqtt": "MQTT", + "tabNeighborInfo": "邻居信息", + "tabPaxcounter": "客流计数", + "tabRangeTest": "拉距测试", + "tabSerial": "串口", + "tabStoreAndForward": "S&F", + "tabTelemetry": "遥测(传感器)" + }, + "ambientLighting": { + "title": "Ambient Lighting Settings", + "description": "Settings for the Ambient Lighting module", + "ledState": { + "label": "LED 状态", + "description": "Sets LED to on or off" + }, + "current": { + "label": "电流", + "description": "Sets the current for the LED output. Default is 10" + }, + "red": { + "label": "红", + "description": "Sets the red LED level. Values are 0-255" + }, + "green": { + "label": "绿", + "description": "Sets the green LED level. Values are 0-255" + }, + "blue": { + "label": "蓝", + "description": "Sets the blue LED level. Values are 0-255" + } + }, + "audio": { + "title": "Audio Settings", + "description": "Settings for the Audio module", + "codec2Enabled": { + "label": "Codec 2 Enabled", + "description": "Enable Codec 2 audio encoding" + }, + "pttPin": { + "label": "PTT Pin", + "description": "GPIO pin to use for PTT" + }, + "bitrate": { + "label": "Bitrate", + "description": "Bitrate to use for audio encoding" + }, + "i2sWs": { + "label": "i2S WS", + "description": "GPIO pin to use for i2S WS" + }, + "i2sSd": { + "label": "i2S SD", + "description": "GPIO pin to use for i2S SD" + }, + "i2sDin": { + "label": "i2S DIN", + "description": "GPIO pin to use for i2S DIN" + }, + "i2sSck": { + "label": "i2S SCK", + "description": "GPIO pin to use for i2S SCK" + } + }, + "cannedMessage": { + "title": "Canned Message Settings", + "description": "Settings for the Canned Message module", + "moduleEnabled": { + "label": "Module Enabled", + "description": "Enable Canned Message" + }, + "rotary1Enabled": { + "label": "Rotary Encoder #1 Enabled", + "description": "Enable the rotary encoder" + }, + "inputbrokerPinA": { + "label": "Encoder Pin A", + "description": "GPIO Pin Value (1-39) For encoder port A" + }, + "inputbrokerPinB": { + "label": "Encoder Pin B", + "description": "GPIO Pin Value (1-39) For encoder port B" + }, + "inputbrokerPinPress": { + "label": "Encoder Pin Press", + "description": "GPIO Pin Value (1-39) For encoder Press" + }, + "inputbrokerEventCw": { + "label": "Clockwise event", + "description": "Select input event." + }, + "inputbrokerEventCcw": { + "label": "Counter Clockwise event", + "description": "Select input event." + }, + "inputbrokerEventPress": { + "label": "Press event", + "description": "Select input event" + }, + "updown1Enabled": { + "label": "Up Down enabled", + "description": "Enable the up / down encoder" + }, + "allowInputSource": { + "label": "Allow Input Source", + "description": "Select from: '_any', 'rotEnc1', 'upDownEnc1', 'cardkb'" + }, + "sendBell": { + "label": "发送铃声", + "description": "Sends a bell character with each message" + } + }, + "detectionSensor": { + "title": "Detection Sensor Settings", + "description": "Settings for the Detection Sensor module", + "enabled": { + "label": "启用", + "description": "Enable or disable Detection Sensor Module" + }, + "minimumBroadcastSecs": { + "label": "Minimum Broadcast Seconds", + "description": "The interval in seconds of how often we can send a message to the mesh when a state change is detected" + }, + "stateBroadcastSecs": { + "label": "State Broadcast Seconds", + "description": "The interval in seconds of how often we should send a message to the mesh with the current state regardless of changes" + }, + "sendBell": { + "label": "发送铃声", + "description": "Send ASCII bell with alert message" + }, + "name": { + "label": "Friendly Name", + "description": "Used to format the message sent to mesh, max 20 Characters" + }, + "monitorPin": { + "label": "Monitor Pin", + "description": "The GPIO pin to monitor for state changes" + }, + "detectionTriggerType": { + "label": "Detection Triggered Type", + "description": "The type of trigger event to be used" + }, + "usePullup": { + "label": "Use Pullup", + "description": "Whether or not use INPUT_PULLUP mode for GPIO pin" + } + }, + "externalNotification": { + "title": "External Notification Settings", + "description": "Configure the external notification module", + "enabled": { + "label": "Module Enabled", + "description": "Enable External Notification" + }, + "outputMs": { + "label": "Output MS", + "description": "Output MS" + }, + "output": { + "label": "Output", + "description": "Output" + }, + "outputVibra": { + "label": "Output Vibrate", + "description": "Output Vibrate" + }, + "outputBuzzer": { + "label": "Output Buzzer", + "description": "Output Buzzer" + }, + "active": { + "label": "Active", + "description": "Active" + }, + "alertMessage": { + "label": "Alert Message", + "description": "Alert Message" + }, + "alertMessageVibra": { + "label": "Alert Message Vibrate", + "description": "Alert Message Vibrate" + }, + "alertMessageBuzzer": { + "label": "Alert Message Buzzer", + "description": "Alert Message Buzzer" + }, + "alertBell": { + "label": "Alert Bell", + "description": "Should an alert be triggered when receiving an incoming bell?" + }, + "alertBellVibra": { + "label": "Alert Bell Vibrate", + "description": "Alert Bell Vibrate" + }, + "alertBellBuzzer": { + "label": "Alert Bell Buzzer", + "description": "Alert Bell Buzzer" + }, + "usePwm": { + "label": "Use PWM", + "description": "Use PWM" + }, + "nagTimeout": { + "label": "Nag Timeout", + "description": "Nag Timeout" + }, + "useI2sAsBuzzer": { + "label": "Use I²S Pin as Buzzer", + "description": "Designate I²S Pin as Buzzer Output" + } + }, + "mqtt": { + "title": "MQTT Settings", + "description": "Settings for the MQTT module", + "enabled": { + "label": "启用", + "description": "Enable or disable MQTT" + }, + "address": { + "label": "MQTT Server Address", + "description": "MQTT server address to use for default/custom servers" + }, + "username": { + "label": "MQTT Username", + "description": "MQTT username to use for default/custom servers" + }, + "password": { + "label": "MQTT Password", + "description": "MQTT password to use for default/custom servers" + }, + "encryptionEnabled": { + "label": "启用加密", + "description": "Enable or disable MQTT encryption. Note: All messages are sent to the MQTT broker unencrypted if this option is not enabled, even when your uplink channels have encryption keys set. This includes position data." + }, + "jsonEnabled": { + "label": "启用 JSON", + "description": "Whether to send/consume JSON packets on MQTT" + }, + "tlsEnabled": { + "label": "启用 TLS", + "description": "Enable or disable TLS" + }, + "root": { + "label": "根主题", + "description": "MQTT root topic to use for default/custom servers" + }, + "proxyToClientEnabled": { + "label": "MQTT Client Proxy Enabled", + "description": "Utilizes the network connection to proxy MQTT messages to the client." + }, + "mapReportingEnabled": { + "label": "Map Reporting Enabled", + "description": "Your node will periodically send an unencrypted map report packet to the configured MQTT server, this includes id, short and long name, approximate location, hardware model, role, firmware version, LoRa region, modem preset and primary channel name." + }, + "mapReportSettings": { + "publishIntervalSecs": { + "label": "Map Report Publish Interval (s)", + "description": "Interval in seconds to publish map reports" + }, + "positionPrecision": { + "label": "Approximate Location", + "description": "Position shared will be accurate within this distance", + "options": { + "metric_km23": "Within 23 km", + "metric_km12": "Within 12 km", + "metric_km5_8": "Within 5.8 km", + "metric_km2_9": "Within 2.9 km", + "metric_km1_5": "Within 1.5 km", + "metric_m700": "Within 700 m", + "metric_m350": "Within 350 m", + "metric_m200": "Within 200 m", + "metric_m90": "Within 90 m", + "metric_m50": "Within 50 m", + "imperial_mi15": "Within 15 miles", + "imperial_mi7_3": "Within 7.3 miles", + "imperial_mi3_6": "Within 3.6 miles", + "imperial_mi1_8": "Within 1.8 miles", + "imperial_mi0_9": "Within 0.9 miles", + "imperial_mi0_5": "Within 0.5 miles", + "imperial_mi0_2": "Within 0.2 miles", + "imperial_ft600": "Within 600 feet", + "imperial_ft300": "Within 300 feet", + "imperial_ft150": "Within 150 feet" + } + } + } + }, + "neighborInfo": { + "title": "Neighbor Info Settings", + "description": "Settings for the Neighbor Info module", + "enabled": { + "label": "启用", + "description": "Enable or disable Neighbor Info Module" + }, + "updateInterval": { + "label": "Update Interval", + "description": "Interval in seconds of how often we should try to send our Neighbor Info to the mesh" + } + }, + "paxcounter": { + "title": "Paxcounter Settings", + "description": "Settings for the Paxcounter module", + "enabled": { + "label": "Module Enabled", + "description": "Enable Paxcounter" + }, + "paxcounterUpdateInterval": { + "label": "Update Interval (seconds)", + "description": "How long to wait between sending paxcounter packets" + }, + "wifiThreshold": { + "label": "WiFi RSSI Threshold", + "description": "At what WiFi RSSI level should the counter increase. Defaults to -80." + }, + "bleThreshold": { + "label": "BLE RSSI Threshold", + "description": "At what BLE RSSI level should the counter increase. Defaults to -80." + } + }, + "rangeTest": { + "title": "Range Test Settings", + "description": "Settings for the Range Test module", + "enabled": { + "label": "Module Enabled", + "description": "Enable Range Test" + }, + "sender": { + "label": "Message Interval", + "description": "How long to wait between sending test packets" + }, + "save": { + "label": "Save CSV to storage", + "description": "ESP32 Only" + } + }, + "serial": { + "title": "Serial Settings", + "description": "Settings for the Serial module", + "enabled": { + "label": "Module Enabled", + "description": "Enable Serial output" + }, + "echo": { + "label": "回声", + "description": "Any packets you send will be echoed back to your device" + }, + "rxd": { + "label": "Receive Pin", + "description": "Set the GPIO pin to the RXD pin you have set up." + }, + "txd": { + "label": "Transmit Pin", + "description": "Set the GPIO pin to the TXD pin you have set up." + }, + "baud": { + "label": "Baud Rate", + "description": "The serial baud rate" + }, + "timeout": { + "label": "超时", + "description": "Seconds to wait before we consider your packet as 'done'" + }, + "mode": { + "label": "模式", + "description": "Select Mode" + }, + "overrideConsoleSerialPort": { + "label": "Override Console Serial Port", + "description": "If you have a serial port connected to the console, this will override it." + } + }, + "storeForward": { + "title": "Store & Forward Settings", + "description": "Settings for the Store & Forward module", + "enabled": { + "label": "Module Enabled", + "description": "Enable Store & Forward" + }, + "heartbeat": { + "label": "Heartbeat Enabled", + "description": "Enable Store & Forward heartbeat" + }, + "records": { + "label": "记录数", + "description": "Number of records to store" + }, + "historyReturnMax": { + "label": "历史记录最大返回值", + "description": "Max number of records to return" + }, + "historyReturnWindow": { + "label": "历史记录返回窗口", + "description": "返回此时间窗口内的记录(分钟)" + } + }, + "telemetry": { + "title": "Telemetry Settings", + "description": "Settings for the Telemetry module", + "deviceUpdateInterval": { + "label": "设备指标", + "description": "设备计量更新间隔 (秒)" + }, + "environmentUpdateInterval": { + "label": "环境计量更新间隔 (秒)", + "description": "" + }, + "environmentMeasurementEnabled": { + "label": "Module Enabled", + "description": "Enable the Environment Telemetry" + }, + "environmentScreenEnabled": { + "label": "Displayed on Screen", + "description": "Show the Telemetry Module on the OLED" + }, + "environmentDisplayFahrenheit": { + "label": "展示华氏度", + "description": "Display temp in Fahrenheit" + }, + "airQualityEnabled": { + "label": "Air Quality Enabled", + "description": "Enable the Air Quality Telemetry" + }, + "airQualityInterval": { + "label": "Air Quality Update Interval", + "description": "How often to send Air Quality data over the mesh" + }, + "powerMeasurementEnabled": { + "label": "Power Measurement Enabled", + "description": "Enable the Power Measurement Telemetry" + }, + "powerUpdateInterval": { + "label": "Power Update Interval", + "description": "How often to send Power data over the mesh" + }, + "powerScreenEnabled": { + "label": "Power Screen Enabled", + "description": "Enable the Power Telemetry Screen" + } + } } diff --git a/packages/web/public/i18n/locales/zh-CN/nodes.json b/packages/web/public/i18n/locales/zh-CN/nodes.json index 85674f90e..fa3f29fdd 100644 --- a/packages/web/public/i18n/locales/zh-CN/nodes.json +++ b/packages/web/public/i18n/locales/zh-CN/nodes.json @@ -1,63 +1,59 @@ { - "nodeDetail": { - "publicKeyEnabled": { - "label": "Public Key Enabled" - }, - "noPublicKey": { - "label": "No Public Key" - }, - "directMessage": { - "label": "Direct Message {{shortName}}" - }, - "favorite": { - "label": "收藏", - "tooltip": "Add or remove this node from your favorites" - }, - "notFavorite": { - "label": "Not a Favorite" - }, - "error": { - "label": "错误", - "text": "An error occurred while fetching node details. Please try again later." - }, - "status": { - "heard": "收到", - "mqtt": "MQTT" - }, - "elevation": { - "label": "Elevation" - }, - "channelUtil": { - "label": "Channel Util" - }, - "airtimeUtil": { - "label": "Airtime Util" - } - }, - "nodesTable": { - "headings": { - "longName": "长名称", - "connection": "Connection", - "lastHeard": "Last Heard", - "encryption": "Encryption", - "model": "模型", - "macAddress": "MAC Address" - }, - "connectionStatus": { - "direct": "直频", - "away": "away", - "unknown": "-", - "viaMqtt": ", via MQTT" - }, - "lastHeardStatus": { - "never": "Never" - } - }, - "actions": { - "added": "Added", - "removed": "Removed", - "ignoreNode": "忽略节点", - "unignoreNode": "Unignore Node", - "requestPosition": "Request Position" - } + "nodeDetail": { + "publicKeyEnabled": { + "label": "Public Key Enabled" + }, + "noPublicKey": { + "label": "No Public Key" + }, + "directMessage": { + "label": "Direct Message {{shortName}}" + }, + "favorite": { + "label": "收藏", + "tooltip": "Add or remove this node from your favorites" + }, + "notFavorite": { + "label": "Not a Favorite" + }, + "error": { + "label": "错误", + "text": "An error occurred while fetching node details. Please try again later." + }, + "status": { + "heard": "收到", + "mqtt": "MQTT" + }, + "elevation": { + "label": "Elevation" + }, + "channelUtil": { + "label": "Channel Util" + }, + "airtimeUtil": { + "label": "Airtime Util" + } + }, + "nodesTable": { + "headings": { + "longName": "长名称", + "connection": "Connection", + "lastHeard": "Last Heard", + "encryption": "Encryption", + "model": "模型", + "macAddress": "MAC Address" + }, + "connectionStatus": { + "direct": "直频", + "away": "away", + "viaMqtt": ", via MQTT" + } + }, + "actions": { + "added": "Added", + "removed": "Removed", + "ignoreNode": "忽略节点", + "unignoreNode": "Unignore Node", + "requestPosition": "Request Position" + } } diff --git a/packages/web/public/i18n/locales/zh-CN/ui.json b/packages/web/public/i18n/locales/zh-CN/ui.json index d50668d30..7269d6f5d 100644 --- a/packages/web/public/i18n/locales/zh-CN/ui.json +++ b/packages/web/public/i18n/locales/zh-CN/ui.json @@ -1,228 +1,230 @@ { - "navigation": { - "title": "Navigation", - "messages": "消息", - "map": "地图", - "config": "配置", - "radioConfig": "Radio Config", - "moduleConfig": "Module Config", - "channels": "频道", - "nodes": "节点" - }, - "app": { - "title": "Meshtastic", - "logo": "Meshtastic Logo" - }, - "sidebar": { - "collapseToggle": { - "button": { - "open": "Open sidebar", - "close": "Close sidebar" - } - }, - "deviceInfo": { - "volts": "{{voltage}} volts", - "firmware": { - "title": "固件", - "version": "v{{version}}", - "buildDate": "Build date: {{date}}" - }, - "deviceName": { - "title": "Device Name", - "changeName": "Change Device Name", - "placeholder": "Enter device name" - }, - "editDeviceName": "Edit device name" - } - }, - "batteryStatus": { - "charging": "{{level}}% charging", - "pluggedIn": "Plugged in", - "title": "电池" - }, - "search": { - "nodes": "Search nodes...", - "channels": "Search channels...", - "commandPalette": "Search commands..." - }, - "toast": { - "positionRequestSent": { - "title": "Position request sent." - }, - "requestingPosition": { - "title": "Requesting position, please wait..." - }, - "sendingTraceroute": { - "title": "Sending Traceroute, please wait..." - }, - "tracerouteSent": { - "title": "Traceroute sent." - }, - "savedChannel": { - "title": "Saved Channel: {{channelName}}" - }, - "messages": { - "pkiEncryption": { - "title": "Chat is using PKI encryption." - }, - "pskEncryption": { - "title": "Chat is using PSK encryption." - } - }, - "configSaveError": { - "title": "Error Saving Config", - "description": "An error occurred while saving the configuration." - }, - "validationError": { - "title": "Config Errors Exist", - "description": "Please fix the configuration errors before saving." - }, - "saveSuccess": { - "title": "Saving Config", - "description": "The configuration change {{case}} has been saved." - }, - "favoriteNode": { - "title": "{{action}} {{nodeName}} {{direction}} favorites.", - "action": { - "added": "Added", - "removed": "Removed", - "to": "to", - "from": "from" - } - }, - "ignoreNode": { - "title": "{{action}} {{nodeName}} {{direction}} ignore list", - "action": { - "added": "Added", - "removed": "Removed", - "to": "to", - "from": "from" - } - } - }, - "notifications": { - "copied": { - "label": "Copied!" - }, - "copyToClipboard": { - "label": "Copy to clipboard" - }, - "hidePassword": { - "label": "隐藏密码" - }, - "showPassword": { - "label": "显示密码" - }, - "deliveryStatus": { - "delivered": "Delivered", - "failed": "Delivery Failed", - "waiting": "等待中...", - "unknown": "未知" - } - }, - "general": { - "label": "General" - }, - "hardware": { - "label": "硬件" - }, - "metrics": { - "label": "Metrics" - }, - "role": { - "label": "角色" - }, - "filter": { - "label": "筛选器csvfganw" - }, - "advanced": { - "label": "高级" - }, - "clearInput": { - "label": "Clear input" - }, - "resetFilters": { - "label": "Reset Filters" - }, - "nodeName": { - "label": "Node name/number", - "placeholder": "Meshtastic 1234" - }, - "airtimeUtilization": { - "label": "Airtime Utilization (%)" - }, - "batteryLevel": { - "label": "Battery level (%)", - "labelText": "Battery level (%): {{value}}" - }, - "batteryVoltage": { - "label": "Battery voltage (V)", - "title": "电压" - }, - "channelUtilization": { - "label": "Channel Utilization (%)" - }, - "hops": { - "direct": "直频", - "label": "Number of hops", - "text": "Number of hops: {{value}}" - }, - "lastHeard": { - "label": "最后听到", - "labelText": "Last heard: {{value}}", - "nowLabel": "Now" - }, - "snr": { - "label": "SNR (db)" - }, - "favorites": { - "label": "Favorites" - }, - "hide": { - "label": "Hide" - }, - "showOnly": { - "label": "Show Only" - }, - "viaMqtt": { - "label": "Connected via MQTT" - }, - "hopsUnknown": { - "label": "Unknown number of hops" - }, - "showUnheard": { - "label": "Never heard" - }, - "language": { - "label": "语言", - "changeLanguage": "Change Language" - }, - "theme": { - "dark": "深色", - "light": "浅色", - "system": "Automatic", - "changeTheme": "Change Color Scheme" - }, - "errorPage": { - "title": "This is a little embarrassing...", - "description1": "We are really sorry but an error occurred in the web client that caused it to crash.
This is not supposed to happen, and we are working hard to fix it.", - "description2": "The best way to prevent this from happening again to you or anyone else is to report the issue to us.", - "reportInstructions": "Please include the following information in your report:", - "reportSteps": { - "step1": "What you were doing when the error occurred", - "step2": "What you expected to happen", - "step3": "What actually happened", - "step4": "Any other relevant information" - }, - "reportLink": "You can report the issue to our <0>GitHub", - "dashboardLink": "Return to the <0>dashboard", - "detailsSummary": "Error Details", - "errorMessageLabel": "Error message:", - "stackTraceLabel": "Stack trace:", - "fallbackError": "{{error}}" - }, - "footer": { - "text": "Powered by <0>▲ Vercel | Meshtastic® is a registered trademark of Meshtastic LLC. | <1>Legal Information", - "commitSha": "Commit SHA: {{sha}}" - } + "navigation": { + "title": "Navigation", + "messages": "消息", + "map": "地图", + "settings": "设置", + "channels": "频道", + "radioConfig": "Radio Config", + "deviceConfig": "设备配置", + "moduleConfig": "Module Config", + "manageConnections": "Manage Connections", + "nodes": "节点" + }, + "app": { + "title": "Meshtastic", + "logo": "Meshtastic Logo" + }, + "sidebar": { + "collapseToggle": { + "button": { + "open": "Open sidebar", + "close": "Close sidebar" + } + }, + "deviceInfo": { + "volts": "{{voltage}} volts", + "firmware": { + "title": "固件", + "version": "v{{version}}", + "buildDate": "Build date: {{date}}" + } + } + }, + "batteryStatus": { + "charging": "{{level}}% charging", + "pluggedIn": "Plugged in", + "title": "电池" + }, + "search": { + "nodes": "Search nodes...", + "channels": "Search channels...", + "commandPalette": "Search commands..." + }, + "toast": { + "positionRequestSent": { + "title": "Position request sent." + }, + "requestingPosition": { + "title": "Requesting position, please wait..." + }, + "sendingTraceroute": { + "title": "Sending Traceroute, please wait..." + }, + "tracerouteSent": { + "title": "Traceroute sent." + }, + "savedChannel": { + "title": "Saved Channel: {{channelName}}" + }, + "messages": { + "pkiEncryption": { + "title": "Chat is using PKI encryption." + }, + "pskEncryption": { + "title": "Chat is using PSK encryption." + } + }, + "configSaveError": { + "title": "Error Saving Config", + "description": "An error occurred while saving the configuration." + }, + "validationError": { + "title": "Config Errors Exist", + "description": "Please fix the configuration errors before saving." + }, + "saveSuccess": { + "title": "Saving Config", + "description": "The configuration change {{case}} has been saved." + }, + "saveAllSuccess": { + "title": "Saved", + "description": "All configuration changes have been saved." + }, + "favoriteNode": { + "title": "{{action}} {{nodeName}} {{direction}} favorites.", + "action": { + "added": "Added", + "removed": "Removed", + "to": "to", + "from": "from" + } + }, + "ignoreNode": { + "title": "{{action}} {{nodeName}} {{direction}} ignore list", + "action": { + "added": "Added", + "removed": "Removed", + "to": "to", + "from": "from" + } + } + }, + "notifications": { + "copied": { + "label": "Copied!" + }, + "copyToClipboard": { + "label": "Copy to clipboard" + }, + "hidePassword": { + "label": "隐藏密码" + }, + "showPassword": { + "label": "显示密码" + }, + "deliveryStatus": { + "delivered": "Delivered", + "failed": "Delivery Failed", + "waiting": "等待中...", + "unknown": "未知" + } + }, + "general": { + "label": "General" + }, + "hardware": { + "label": "硬件" + }, + "metrics": { + "label": "Metrics" + }, + "role": { + "label": "角色" + }, + "filter": { + "label": "筛选器csvfganw" + }, + "advanced": { + "label": "高级" + }, + "clearInput": { + "label": "Clear input" + }, + "resetFilters": { + "label": "Reset Filters" + }, + "nodeName": { + "label": "Node name/number", + "placeholder": "Meshtastic 1234" + }, + "airtimeUtilization": { + "label": "Airtime Utilization (%)", + "short": "Airtime Util. (%)" + }, + "batteryLevel": { + "label": "Battery level (%)", + "labelText": "Battery level (%): {{value}}" + }, + "batteryVoltage": { + "label": "Battery voltage (V)", + "title": "电压" + }, + "channelUtilization": { + "label": "Channel Utilization (%)", + "short": "Channel Util. (%)" + }, + "hops": { + "direct": "直频", + "label": "Number of hops", + "text": "Number of hops: {{value}}" + }, + "lastHeard": { + "label": "最后听到", + "labelText": "Last heard: {{value}}", + "nowLabel": "Now" + }, + "snr": { + "label": "SNR (db)" + }, + "favorites": { + "label": "Favorites" + }, + "hide": { + "label": "Hide" + }, + "showOnly": { + "label": "Show Only" + }, + "viaMqtt": { + "label": "Connected via MQTT" + }, + "hopsUnknown": { + "label": "Unknown number of hops" + }, + "showUnheard": { + "label": "Never heard" + }, + "language": { + "label": "语言", + "changeLanguage": "Change Language" + }, + "theme": { + "dark": "深色", + "light": "浅色", + "system": "Automatic", + "changeTheme": "Change Color Scheme" + }, + "errorPage": { + "title": "This is a little embarrassing...", + "description1": "We are really sorry but an error occurred in the web client that caused it to crash.
This is not supposed to happen, and we are working hard to fix it.", + "description2": "The best way to prevent this from happening again to you or anyone else is to report the issue to us.", + "reportInstructions": "Please include the following information in your report:", + "reportSteps": { + "step1": "What you were doing when the error occurred", + "step2": "What you expected to happen", + "step3": "What actually happened", + "step4": "Any other relevant information" + }, + "reportLink": "You can report the issue to our <0>GitHub", + "connectionsLink": "Return to the <0>connections", + "detailsSummary": "Error Details", + "errorMessageLabel": "Error message:", + "stackTraceLabel": "Stack trace:", + "fallbackError": "{{error}}" + }, + "footer": { + "text": "Powered by <0>▲ Vercel | Meshtastic® is a registered trademark of Meshtastic LLC. | <1>Legal Information", + "commitSha": "Commit SHA: {{sha}}" + } } diff --git a/packages/web/public/i18n/locales/zh-TW/channels.json b/packages/web/public/i18n/locales/zh-TW/channels.json new file mode 100644 index 000000000..98bd6f83a --- /dev/null +++ b/packages/web/public/i18n/locales/zh-TW/channels.json @@ -0,0 +1,71 @@ +{ + "page": { + "sectionLabel": "頻道", + "channelName": "頻道 {{channelName}}", + "broadcastLabel": "主要", + "channelIndex": "頻道 {{index}}", + "import": "匯入", + "export": "匯出" + }, + "validation": { + "pskInvalid": "23公里以內" + }, + "settings": { + "label": "頻道設置", + "description": "加密、MQTT 和其他設置" + }, + "role": { + "label": "角色", + "description": "設備遙測資料透過主要頻道發送。只允許一個主要頻道", + "options": { + "primary": "主要", + "disabled": "停用", + "secondary": "次要" + } + }, + "psk": { + "label": "預分享金鑰", + "description": "支援PSK長度:256位元,128位元,8位元, 空(0 位元)", + "generate": "生成" + }, + "name": { + "label": "名稱", + "description": "頻道名稱需<12字節,預設為空白" + }, + "uplinkEnabled": { + "label": "已啓用上行", + "description": "將訊息從本地網狀網路發布至 MQTT" + }, + "downlinkEnabled": { + "label": "已啓用下行", + "description": "將訊息從 MQTT 轉傳至本地網狀網路" + }, + "positionPrecision": { + "label": "位置", + "description": "與頻道共享的位置精度。可以選不共享。", + "options": { + "none": "不共享位置", + "precise": "精確定位", + "metric_km23": "23公里以內", + "metric_km12": "12公里以內", + "metric_km5_8": "5.8公里以內", + "metric_km2_9": "2.9公里以內", + "metric_km1_5": "1.5公里以內", + "metric_m700": "700米以內", + "metric_m350": "350米以內", + "metric_m200": "200米以內", + "metric_m90": "90米以內", + "metric_m50": "50米以內", + "imperial_mi15": "15英里以內", + "imperial_mi7_3": "7.3英里以內", + "imperial_mi3_6": "3.6英里以內", + "imperial_mi1_8": "1.8英里以內", + "imperial_mi0_9": "0.9英里以內", + "imperial_mi0_5": "0.5英里以內", + "imperial_mi0_2": "0.2英里以內", + "imperial_ft600": "600英尺以內", + "imperial_ft300": "300英尺以內", + "imperial_ft150": "150英尺以內" + } + } +} diff --git a/packages/web/public/i18n/locales/zh-TW/commandPalette.json b/packages/web/public/i18n/locales/zh-TW/commandPalette.json new file mode 100644 index 000000000..81d9faa17 --- /dev/null +++ b/packages/web/public/i18n/locales/zh-TW/commandPalette.json @@ -0,0 +1,51 @@ +{ + "emptyState": "未找到符合的結果。", + "page": { + "title": "命令選單" + }, + "pinGroup": { + "label": "Pin command group" + }, + "unpinGroup": { + "label": "Unpin command group" + }, + "goto": { + "label": "前往", + "command": { + "messages": "訊息", + "map": "地圖", + "config": "設定", + "nodes": "節點" + } + }, + "manage": { + "label": "管理", + "command": { + "switchNode": "切換節點", + "connectNewNode": "連接新節點" + } + }, + "contextual": { + "label": "Contextual", + "command": { + "qrCode": "QR 代碼", + "qrGenerator": "Generator", + "qrImport": "匯入", + "scheduleShutdown": "排程關機", + "scheduleReboot": "重新啟動設備", + "resetNodeDb": "重設節點資料庫", + "dfuMode": "进入 DFU 模式", + "factoryResetDevice": "恢復設備原廠設定", + "factoryResetConfig": "恢復原廠設定", + "disconnect": "中斷連線" + } + }, + "debug": { + "label": "调试", + "command": { + "reconfigure": "重新設定", + "clearAllStoredMessages": "清除所有已儲存訊息", + "clearAllStores": "清除所有本地儲存資料" + } + } +} diff --git a/packages/web/public/i18n/locales/zh-TW/common.json b/packages/web/public/i18n/locales/zh-TW/common.json new file mode 100644 index 000000000..8d6869d31 --- /dev/null +++ b/packages/web/public/i18n/locales/zh-TW/common.json @@ -0,0 +1,165 @@ +{ + "button": { + "apply": "套用", + "addConnection": "Add Connection", + "saveConnection": "Save connection", + "backupKey": "備份金鑰", + "cancel": "取消", + "connect": "連線", + "clearMessages": "清除訊息", + "close": "關閉", + "confirm": "確認", + "delete": "刪除", + "dismiss": "關閉", + "download": "下載", + "disconnect": "中斷連線", + "export": "匯出", + "generate": "生成", + "regenerate": "重新產生", + "import": "匯入", + "message": "訊息:", + "now": "Now", + "ok": "好的", + "print": "Print", + "remove": "移除", + "requestNewKeys": "請求新金鑰", + "requestPosition": "請求位置", + "reset": "重設", + "retry": "Retry", + "save": "儲存", + "setDefault": "Set as default", + "unsetDefault": "Unset default", + "scanQr": "掃描QR碼", + "traceRoute": "追蹤路由", + "submit": "套用" + }, + "app": { + "title": "Meshtastic", + "fullTitle": "Meshtastic 網頁版" + }, + "loading": "載入中……", + "unit": { + "cps": "CPS", + "dbm": "dBm", + "hertz": "Hz", + "hop": { + "one": "Hop", + "plural": "跳數" + }, + "hopsAway": { + "one": "相隔 {{count}} hop", + "plural": "相隔 {{count}} hop", + "unknown": "跳數未知" + }, + "megahertz": "MHz", + "kilohertz": "kHz", + "raw": "raw", + "meter": { + "one": "公尺", + "plural": "公尺", + "suffix": "m" + }, + "kilometer": { + "one": "公里", + "plural": "公里", + "suffix": "km" + }, + "minute": { + "one": "分鐘", + "plural": "分鐘" + }, + "hour": { + "one": "小時", + "plural": "小時" + }, + "millisecond": { + "one": "毫秒", + "plural": "毫秒", + "suffix": "ms" + }, + "second": { + "one": "秒", + "plural": "秒" + }, + "day": { + "one": "天", + "plural": "天", + "today": "今日", + "yesterday": "昨天" + }, + "month": { + "one": "月", + "plural": "月" + }, + "year": { + "one": "年", + "plural": "年" + }, + "snr": "SNR", + "volt": { + "one": "伏特", + "plural": "伏特", + "suffix": "V" + }, + "record": { + "one": "記錄", + "plural": "記錄" + }, + "degree": { + "one": "度", + "plural": "度", + "suffix": "°" + } + }, + "security": { + "0bit": "Empty", + "8bit": "8 bit", + "128bit": "128 bit", + "256bit": "256 bit" + }, + "unknown": { + "longName": "不明", + "shortName": "UNK", + "notAvailable": "不適用", + "num": "??" + }, + "nodeUnknownPrefix": "!", + "unset": "未設定", + "fallbackName": "Meshtastic {{last4}}", + "node": "節點", + "formValidation": { + "unsavedChanges": "未儲存的變更", + "tooBig": { + "string": "長度過長,最大限制為 {{maximum}} 個字元。", + "number": "數值過大,請勿超過 {{maximum}}。", + "bytes": "大小超過限制,必須小於或等於 {{params.maximum}} 位元組。" + }, + "tooSmall": { + "string": "長度不足,至少須 {{minimum}} 個字元。", + "number": "數值過小,至少須 {{minimum}}。" + }, + "invalidFormat": { + "ipv4": "格式無效,請輸入一個 IPv4 地址。", + "key": "格式錯誤,須為 Base64 編碼的預共享金鑰 (PSK)。" + }, + "invalidType": { + "number": "Invalid type, expected a number." + }, + "pskLength": { + "0bit": "此金鑰須留空。", + "8bit": "金鑰須為 8 bit 預共享金鑰 (PSK)。", + "128bit": "金鑰須為 128 bit 預共享金鑰 (PSK)。", + "256bit": "金鑰須為 256 bit 預共享金鑰 (PSK)。" + }, + "required": { + "generic": "這是必填欄位。", + "managed": "若節點為受管理模式,則必須提供至少一個管理金鑰。", + "key": "須輸入金鑰。" + }, + "invalidOverrideFreq": { + "number": "錯誤,數值須介於 410-930 MHz 之間,或輸入 0 (使用預設值)。" + } + }, + "yes": "Yes", + "no": "No" +} diff --git a/packages/web/public/i18n/locales/zh-TW/config.json b/packages/web/public/i18n/locales/zh-TW/config.json new file mode 100644 index 000000000..40cfa13a8 --- /dev/null +++ b/packages/web/public/i18n/locales/zh-TW/config.json @@ -0,0 +1,458 @@ +{ + "page": { + "title": "設定", + "tabUser": "用戶", + "tabChannels": "頻道", + "tabBluetooth": "藍芽", + "tabDevice": "裝置", + "tabDisplay": "顯示", + "tabLora": "LoRa", + "tabNetwork": "網路", + "tabPosition": "位置", + "tabPower": "電源", + "tabSecurity": "安全" + }, + "sidebar": { + "label": "裝置設定" + }, + "device": { + "title": "Device Settings", + "description": "Settings for the device", + "buttonPin": { + "description": "Button pin override", + "label": "Button Pin" + }, + "buzzerPin": { + "description": "Buzzer pin override", + "label": "Buzzer Pin" + }, + "disableTripleClick": { + "description": "Disable triple click", + "label": "Disable Triple Click" + }, + "doubleTapAsButtonPress": { + "description": "Treat double tap as button press", + "label": "Double Tap as Button Press" + }, + "ledHeartbeatDisabled": { + "description": "Disable default blinking LED", + "label": "LED Heartbeat Disabled" + }, + "nodeInfoBroadcastInterval": { + "description": "How often to broadcast node info", + "label": "Node Info Broadcast Interval" + }, + "posixTimezone": { + "description": "The POSIX timezone string for the device", + "label": "POSIX時區" + }, + "rebroadcastMode": { + "description": "How to handle rebroadcasting", + "label": "Rebroadcast Mode" + }, + "role": { + "description": "What role the device performs on the mesh", + "label": "角色" + } + }, + "bluetooth": { + "title": "Bluetooth Settings", + "description": "Settings for the Bluetooth module", + "note": "Note: Some devices (ESP32) cannot use both Bluetooth and WiFi at the same time.", + "enabled": { + "description": "Enable or disable Bluetooth", + "label": "Enabled" + }, + "pairingMode": { + "description": "Pin selection behaviour.", + "label": "配對模式" + }, + "pin": { + "description": "Pin to use when pairing", + "label": "Pin" + } + }, + "display": { + "description": "Settings for the device display", + "title": "Display Settings", + "headingBold": { + "description": "Bolden the heading text", + "label": "Bold Heading" + }, + "carouselDelay": { + "description": "How fast to cycle through windows", + "label": "Carousel Delay" + }, + "compassNorthTop": { + "description": "Fix north to the top of compass", + "label": "Compass North Top" + }, + "displayMode": { + "description": "Screen layout variant", + "label": "Display Mode" + }, + "displayUnits": { + "description": "Display metric or imperial units", + "label": "Display Units" + }, + "flipScreen": { + "description": "Flip display 180 degrees", + "label": "Flip Screen" + }, + "gpsDisplayUnits": { + "description": "Coordinate display format", + "label": "GPS Display Units" + }, + "oledType": { + "description": "Type of OLED screen attached to the device", + "label": "OLED類型" + }, + "screenTimeout": { + "description": "Turn off the display after this long", + "label": "Screen Timeout" + }, + "twelveHourClock": { + "description": "Use 12-hour clock format", + "label": "12-Hour Clock" + }, + "wakeOnTapOrMotion": { + "description": "Wake the device on tap or motion", + "label": "Wake on Tap or Motion" + } + }, + "lora": { + "title": "Mesh Settings", + "description": "Settings for the LoRa mesh", + "bandwidth": { + "description": "Channel bandwidth in kHz", + "label": "帶寬" + }, + "boostedRxGain": { + "description": "Boosted RX gain", + "label": "Boosted RX Gain" + }, + "codingRate": { + "description": "The denominator of the coding rate", + "label": "Coding Rate" + }, + "frequencyOffset": { + "description": "Frequency offset to correct for crystal calibration errors", + "label": "Frequency Offset" + }, + "frequencySlot": { + "description": "LoRa frequency channel number", + "label": "Frequency Slot" + }, + "hopLimit": { + "description": "Maximum number of hops", + "label": "Hop Limit" + }, + "ignoreMqtt": { + "description": "Don't forward MQTT messages over the mesh", + "label": "無視MQTT" + }, + "modemPreset": { + "description": "Modem preset to use", + "label": "Modem 預設集" + }, + "okToMqtt": { + "description": "When set to true, this configuration indicates that the user approves the packet to be uploaded to MQTT. If set to false, remote nodes are requested not to forward packets to MQTT", + "label": "將消息轉發至MQTT" + }, + "overrideDutyCycle": { + "description": "覆蓋工作週期/佔空比", + "label": "覆蓋工作週期/佔空比" + }, + "overrideFrequency": { + "description": "Override frequency", + "label": "Override Frequency" + }, + "region": { + "description": "Sets the region for your node", + "label": "地區" + }, + "spreadingFactor": { + "description": "Indicates the number of chirps per symbol", + "label": "Spreading Factor" + }, + "transmitEnabled": { + "description": "Enable/Disable transmit (TX) from the LoRa radio", + "label": "Transmit Enabled" + }, + "transmitPower": { + "description": "Max transmit power", + "label": "Transmit Power" + }, + "usePreset": { + "description": "Use one of the predefined modem presets", + "label": "Use Preset" + }, + "meshSettings": { + "description": "Settings for the LoRa mesh", + "label": "Mesh Settings" + }, + "waveformSettings": { + "description": "Settings for the LoRa waveform", + "label": "Waveform Settings" + }, + "radioSettings": { + "label": "Radio Settings", + "description": "Settings for the LoRa radio" + } + }, + "network": { + "title": "WiFi Config", + "description": "WiFi radio configuration", + "note": "Note: Some devices (ESP32) cannot use both Bluetooth and WiFi at the same time.", + "addressMode": { + "description": "Address assignment selection", + "label": "Address Mode" + }, + "dns": { + "description": "DNS Server", + "label": "DNS" + }, + "ethernetEnabled": { + "description": "Enable or disable the Ethernet port", + "label": "Enabled" + }, + "gateway": { + "description": "Default Gateway", + "label": "網閘" + }, + "ip": { + "description": "IP Address", + "label": "IP" + }, + "psk": { + "description": "Network password", + "label": "PSK" + }, + "ssid": { + "description": "Network name", + "label": "SSID" + }, + "subnet": { + "description": "Subnet Mask", + "label": "子網" + }, + "wifiEnabled": { + "description": "Enable or disable the WiFi radio", + "label": "Enabled" + }, + "meshViaUdp": { + "label": "Mesh via UDP" + }, + "ntpServer": { + "label": "NTP Server" + }, + "rsyslogServer": { + "label": "Rsyslog Server" + }, + "ethernetConfigSettings": { + "description": "Ethernet port configuration", + "label": "Ethernet Config" + }, + "ipConfigSettings": { + "description": "IP configuration", + "label": "IP Config" + }, + "ntpConfigSettings": { + "description": "NTP configuration", + "label": "NTP Config" + }, + "rsyslogConfigSettings": { + "description": "Rsyslog configuration", + "label": "Rsyslog Config" + }, + "udpConfigSettings": { + "description": "UDP over Mesh configuration", + "label": "UDP設置" + } + }, + "position": { + "title": "Position Settings", + "description": "Settings for the position module", + "broadcastInterval": { + "description": "How often your position is sent out over the mesh", + "label": "Broadcast Interval" + }, + "enablePin": { + "description": "GPS module enable pin override", + "label": "Enable Pin" + }, + "fixedPosition": { + "description": "Don't report GPS position, but a manually-specified one", + "label": "Fixed Position" + }, + "gpsMode": { + "description": "Configure whether device GPS is Enabled, Disabled, or Not Present", + "label": "GPS Mode" + }, + "gpsUpdateInterval": { + "description": "How often a GPS fix should be acquired", + "label": "GPS Update Interval" + }, + "positionFlags": { + "description": "Optional fields to include when assembling position messages. The more fields are selected, the larger the message will be leading to longer airtime usage and a higher risk of packet loss.", + "label": "Position Flags" + }, + "receivePin": { + "description": "GPS module RX pin override", + "label": "Receive Pin" + }, + "smartPositionEnabled": { + "description": "Only send position when there has been a meaningful change in location", + "label": "Enable Smart Position" + }, + "smartPositionMinDistance": { + "description": "Minimum distance (in meters) that must be traveled before a position update is sent", + "label": "Smart Position Minimum Distance" + }, + "smartPositionMinInterval": { + "description": "Minimum interval (in seconds) that must pass before a position update is sent", + "label": "Smart Position Minimum Interval" + }, + "transmitPin": { + "description": "GPS module TX pin override", + "label": "Transmit Pin" + }, + "intervalsSettings": { + "description": "How often to send position updates", + "label": "Intervals" + }, + "flags": { + "placeholder": "Select position flags...", + "altitude": "Altitude", + "altitudeGeoidalSeparation": "Altitude Geoidal Separation", + "altitudeMsl": "Altitude is Mean Sea Level", + "dop": "Dilution of precision (DOP) PDOP used by default", + "hdopVdop": "If DOP is set, use HDOP / VDOP values instead of PDOP", + "numSatellites": "Number of satellites", + "sequenceNumber": "Sequence number", + "timestamp": "時間戳記", + "unset": "取消設定", + "vehicleHeading": "Vehicle heading", + "vehicleSpeed": "Vehicle speed" + } + }, + "power": { + "adcMultiplierOverride": { + "description": "Used for tweaking battery voltage reading", + "label": "ADC Multiplier Override ratio" + }, + "ina219Address": { + "description": "Address of the INA219 battery monitor", + "label": "INA219 Address" + }, + "lightSleepDuration": { + "description": "How long the device will be in light sleep for", + "label": "Light Sleep Duration" + }, + "minimumWakeTime": { + "description": "Minimum amount of time the device will stay awake for after receiving a packet", + "label": "Minimum Wake Time" + }, + "noConnectionBluetoothDisabled": { + "description": "If the device does not receive a Bluetooth connection, the BLE radio will be disabled after this long", + "label": "No Connection Bluetooth Disabled" + }, + "powerSavingEnabled": { + "description": "Select if powered from a low-current source (i.e. solar), to minimize power consumption as much as possible.", + "label": "啟用省電模式" + }, + "shutdownOnBatteryDelay": { + "description": "Automatically shutdown node after this long when on battery, 0 for indefinite", + "label": "Shutdown on battery delay" + }, + "superDeepSleepDuration": { + "description": "How long the device will be in super deep sleep for", + "label": "Super Deep Sleep Duration" + }, + "powerConfigSettings": { + "description": "Settings for the power module", + "label": "電源設定" + }, + "sleepSettings": { + "description": "Sleep settings for the power module", + "label": "Sleep Settings" + } + }, + "security": { + "description": "Settings for the Security configuration", + "title": "Security Settings", + "button_backupKey": "Backup Key", + "adminChannelEnabled": { + "description": "Allow incoming device control over the insecure legacy admin channel", + "label": "Allow Legacy Admin" + }, + "enableDebugLogApi": { + "description": "Output live debug logging over serial, view and export position-redacted device logs over Bluetooth", + "label": "Enable Debug Log API" + }, + "managed": { + "description": "If enabled, device configuration options are only able to be changed remotely by a Remote Admin node via admin messages. Do not enable this option unless at least one suitable Remote Admin node has been setup, and the public key is stored in one of the fields above.", + "label": "Managed" + }, + "privateKey": { + "description": "Used to create a shared key with a remote device", + "label": "私鑰" + }, + "publicKey": { + "description": "Sent out to other nodes on the mesh to allow them to compute a shared secret key", + "label": "公鑰" + }, + "primaryAdminKey": { + "description": "The primary public key authorized to send admin messages to this node", + "label": "Primary Admin Key" + }, + "secondaryAdminKey": { + "description": "The secondary public key authorized to send admin messages to this node", + "label": "Secondary Admin Key" + }, + "serialOutputEnabled": { + "description": "Serial Console over the Stream API", + "label": "Serial Output Enabled" + }, + "tertiaryAdminKey": { + "description": "The tertiary public key authorized to send admin messages to this node", + "label": "Tertiary Admin Key" + }, + "adminSettings": { + "description": "Settings for Admin", + "label": "Admin Settings" + }, + "loggingSettings": { + "description": "Settings for Logging", + "label": "Logging Settings" + } + }, + "user": { + "title": "User Settings", + "description": "Configure your device name and identity settings", + "longName": { + "label": "Long Name", + "description": "Your full display name (1-40 characters)", + "validation": { + "min": "Long name must be at least 1 character", + "max": "Long name must be at most 40 characters" + } + }, + "shortName": { + "label": "Short Name", + "description": "Your abbreviated name (2-4 characters)", + "validation": { + "min": "Short name must be at least 2 characters", + "max": "Short name must be at most 4 characters" + } + }, + "isUnmessageable": { + "label": "不接收訊息", + "description": "Used to identify unmonitored or infrastructure nodes so that messaging is not available to nodes that will never respond." + }, + "isLicensed": { + "label": "業餘無線電模式 (HAM)", + "description": "Enable if you are a licensed amateur radio operator, enabling this option disables encryption and is not compatible with the default Meshtastic network." + } + } +} diff --git a/packages/web/public/i18n/locales/zh-TW/connections.json b/packages/web/public/i18n/locales/zh-TW/connections.json new file mode 100644 index 000000000..1eab52a1d --- /dev/null +++ b/packages/web/public/i18n/locales/zh-TW/connections.json @@ -0,0 +1,34 @@ +{ + "page": { + "title": "Connect to a Meshtastic device", + "description": "Add a device connection via HTTP, Bluetooth, or Serial. Your saved connections will be saved in your browser." + }, + "connectionType_ble": "低功耗藍牙", + "connectionType_serial": "序列埠", + "connectionType_network": "網路", + "deleteConnection": "Delete connection", + "areYouSure": "This will remove {{name}}. You canot undo this action.", + "moreActions": "More actions", + "noConnections": { + "title": "No connections yet.", + "description": "Create your first connection. It will connect immediately and be saved for later." + }, + "lastConnectedAt": "Last connected: {{date}}", + "neverConnected": "Never connected", + "toasts": { + "connected": "已連線", + "nowConnected": "{{name}} is now connected", + "nowDisconnected": "{{name}} are now disconnecte", + "disconnected": "已中斷連線", + "failed": "Failed to connect", + "checkConnetion": "Check your device or settings and try again", + "defaultSet": "Default set", + "defaultConnection": "Default connection is now {{nameisconnected}}", + "deleted": "Deleted", + "deletedByName": "{{name}} was removed", + "pickConnectionAgain": "Could not connect. You may need to reselect the device/port.", + "added": "Connection added", + "savedByName": "{{name}} saved.", + "savedCantConnect": "The connection was saved but could not connect." + } +} diff --git a/packages/web/public/i18n/locales/zh-TW/dashboard.json b/packages/web/public/i18n/locales/zh-TW/dashboard.json new file mode 100644 index 000000000..42f3d8ab9 --- /dev/null +++ b/packages/web/public/i18n/locales/zh-TW/dashboard.json @@ -0,0 +1,12 @@ +{ + "dashboard": { + "title": "已連線的裝置", + "description": "管理已連線的 Meshtastic 裝置。", + "connectionType_ble": "低功耗藍牙", + "connectionType_serial": "序列埠", + "connectionType_network": "網路", + "noDevicesTitle": "沒有裝置連線", + "noDevicesDescription": "連接新設備以開始使用。", + "button_newConnection": "新增連線" + } +} diff --git a/packages/web/public/i18n/locales/zh-TW/dialog.json b/packages/web/public/i18n/locales/zh-TW/dialog.json new file mode 100644 index 000000000..f2ef748d7 --- /dev/null +++ b/packages/web/public/i18n/locales/zh-TW/dialog.json @@ -0,0 +1,238 @@ +{ + "deleteMessages": { + "description": "This action will clear all message history. This cannot be undone. Are you sure you want to continue?", + "title": "Clear All Messages" + }, + "import": { + "description": "Import a Channel Set from a Meshtastic URL.
Valid Meshtasic URLs start with \"https://meshtastic.org/e/...\"", + "error": { + "invalidUrl": "Invalid Meshtastic URL" + }, + "channelPrefix": "Channel ", + "primary": "Primary ", + "doNotImport": "No not import", + "channelName": "名稱", + "channelSlot": "時隙", + "channelSetUrl": "Channel Set/QR Code URL", + "useLoraConfig": "Import LoRa Config", + "presetDescription": "The current LoRa Config will be replaced.", + "title": "Import Channels" + }, + "locationResponse": { + "title": "Location: {{identifier}}", + "altitude": "Altitude: ", + "coordinates": "Coordinates: ", + "noCoordinates": "No Coordinates" + }, + "pkiRegenerateDialog": { + "title": "Regenerate Pre-Shared Key?", + "description": "Are you sure you want to regenerate the pre-shared key?", + "regenerate": "Regenerate" + }, + "addConnection": { + "title": "Add connection", + "description": "Choose a connection type and fill in the details", + "validation": { + "requiresWebBluetooth": "This connection type requires <0>Web Bluetooth. Please use a supported browser, like Chrome or Edge.", + "requiresWebSerial": "This connection type requires <0>Web Serial. Please use a supported browser, like Chrome or Edge.", + "requiresSecureContext": "This application requires a <0>secure context. Please connect using HTTPS or localhost.", + "additionallyRequiresSecureContext": "Additionally, it requires a <0>secure context. Please connect using HTTPS or localhost." + }, + "bluetoothConnection": { + "namePlaceholder": "My Bluetooth Node", + "supported": { + "title": "Web Bluetooth supported" + }, + "notSupported": { + "title": "Web Bluetooth not supported", + "description": "Your browser or device does not support Web Bluetooth" + }, + "short": "BT: {{deviceName}}", + "long": "Bluetooth Device", + "device": "裝置", + "selectDevice": "Select device", + "selected": "Bluetooth device selected", + "notSelected": "No device selected", + "helperText": "Uses the Meshtastic Bluetooth service for discovery." + }, + "serialConnection": { + "namePlaceholder": "My Serial Node", + "helperText": "Selecting a port grants permission so the app can open it to connect.", + "supported": { + "title": "Web Serial supported" + }, + "notSupported": { + "title": "Web Serial not supported", + "description": "Your browser or device does not support Web Serial" + }, + "portSelected": { + "title": "Serial port selected", + "description": "Port permissions granted." + }, + "port": "Port", + "selectPort": "Select port", + "deviceName": "USB {{vendorId}}:{{productId}}", + "notSelected": "No port selected" + }, + "httpConnection": { + "namePlaceholder": "My HTTP Node", + "inputPlaceholder": "192.168.1.10 or meshtastic.local", + "heading": "URL or IP", + "useHttps": "Use HTTTPS", + "invalidUrl": { + "title": "Invalid URL", + "description": "Please enter a valid HTTP or HTTPS URL." + }, + "connectionTest": { + "description": "Test the connetion before saving to verify the device is reachable.", + "button": { + "loading": "Testing...", + "label": "Test connection" + }, + "reachable": "Reachable", + "notReachable": "Not reachable", + "success": { + "title": "Connection test successful", + "description": "The device appears to be reachable." + }, + "failure": { + "title": "Connection test failed", + "description": "Could not reach the device. Check the URL and try again." + } + } + } + }, + "nodeDetails": { + "message": "訊息:", + "requestPosition": "Request Position", + "traceRoute": "Trace Route", + "airTxUtilization": "Air TX utilization", + "allRawMetrics": "All Raw Metrics:", + "batteryLevel": "Battery level", + "channelUtilization": "Channel utilization", + "details": "Details:", + "deviceMetrics": "Device Metrics:", + "hardware": "Hardware: ", + "lastHeard": "Last Heard: ", + "nodeHexPrefix": "Node Hex: ", + "nodeNumber": "Node Number: ", + "position": "Position:", + "role": "Role: ", + "uptime": "Uptime: ", + "voltage": "電壓", + "title": "Node Details for {{identifier}}", + "ignoreNode": "Ignore node", + "removeNode": "Remove node", + "unignoreNode": "Unignore node", + "security": "Security:", + "publicKey": "Public Key: ", + "messageable": "Messageable: ", + "KeyManuallyVerifiedTrue": "Public Key has been manually verified", + "KeyManuallyVerifiedFalse": "Public Key is not manually verified" + }, + "pkiBackup": { + "loseKeysWarning": "If you lose your keys, you will need to reset your device.", + "secureBackup": "Its important to backup your public and private keys and store your backup securely!", + "footer": "=== END OF KEYS ===", + "header": "=== MESHTASTIC KEYS FOR {{longName}} ({{shortName}}) ===", + "privateKey": "Private Key:", + "publicKey": "Public Key:", + "fileName": "meshtastic_keys_{{longName}}_{{shortName}}.txt", + "title": "Backup Keys" + }, + "pkiBackupReminder": { + "description": "We recommend backing up your key data regularly. Would you like to back up now?", + "title": "Backup Reminder", + "remindLaterPrefix": "Remind me in", + "remindNever": "Never remind me", + "backupNow": "Back up now" + }, + "pkiRegenerate": { + "description": "Are you sure you want to regenerate key pair?", + "title": "Regenerate Key Pair" + }, + "qr": { + "addChannels": "Add Channels", + "replaceChannels": "Replace Channels", + "description": "The current LoRa configuration will also be shared.", + "sharableUrl": "Sharable URL", + "title": "Generate QR Code" + }, + "reboot": { + "title": "Reboot device", + "description": "Reboot now or schedule a reboot of the connected node. Optionally, you can choose to reboot into OTA (Over-the-Air) mode.", + "ota": "Reboot into OTA mode", + "enterDelay": "Enter delay", + "scheduled": "Reboot has been scheduled", + "schedule": "Schedule reboot", + "now": "Reboot now", + "cancel": "Cancel scheduled reboot" + }, + "refreshKeys": { + "description": { + "acceptNewKeys": "This will remove the node from device and request new keys.", + "keyMismatchReasonSuffix": ". This is due to the remote node's current public key does not match the previously stored key for this node.", + "unableToSendDmPrefix": "Your node is unable to send a direct message to node: " + }, + "acceptNewKeys": "Accept New Keys", + "title": "Keys Mismatch - {{identifier}}" + }, + "removeNode": { + "description": "Are you sure you want to remove this Node?", + "title": "Remove Node?" + }, + "shutdown": { + "title": "Schedule Shutdown", + "description": "Turn off the connected node after x minutes." + }, + "traceRoute": { + "routeToDestination": "Route to destination:", + "routeBack": "Route back:" + }, + "tracerouteResponse": { + "title": "Traceroute: {{identifier}}" + }, + "unsafeRoles": { + "confirmUnderstanding": "Yes, I know what I'm doing", + "conjunction": " and the blog post about ", + "postamble": " and understand the implications of changing the role.", + "preamble": "I have read the ", + "choosingRightDeviceRole": "Choosing The Right Device Role", + "deviceRoleDocumentation": "Device Role Documentation", + "title": "你確定嗎?" + }, + "managedMode": { + "confirmUnderstanding": "Yes, I know what I'm doing", + "title": "你確定嗎?", + "description": "Enabling Managed Mode blocks client applications (including the web client) from writing configurations to a radio. Once enabled, radio configurations can only be changed through Remote Admin messages. This setting is not required for remote node administration." + }, + "clientNotification": { + "title": "客户端通知", + "TraceRoute can only be sent once every 30 seconds": "TraceRoute can only be sent once every 30 seconds", + "Compromised keys were detected and regenerated.": "Compromised keys were detected and regenerated." + }, + "resetNodeDb": { + "title": "Reset Node Database", + "description": "This will clear all nodes from the connected device's node database and clear all message history in the client. This cannot be undone. Are you sure you want to continue?", + "confirm": "Reset Node Database", + "failedTitle": "There was an error resetting the Node DB. Please try again." + }, + "clearAllStores": { + "title": "Clear All Local Storage", + "description": "This will clear all locally stored data, including message history and node databases for all previously connected devices. This will require you to reconnect to your node once complete and cannot be undone. Are you sure you want to continue?", + "confirm": "Clear all local storage", + "failedTitle": "There was an error clearing local storage. Please try again." + }, + "factoryResetDevice": { + "title": "Factory Reset Device", + "description": "This will factory reset the connected device, erasing all configurations and data on the device as well as all nodes and messages saved in the client. This cannot be undone. Are you sure you want to continue?", + "confirm": "Factory Reset Device", + "failedTitle": "There was an error performing the factory reset. Please try again." + }, + "factoryResetConfig": { + "title": "Factory Reset Config", + "description": "This will factory reset the configuration on the connected device, erasing all configurations on the device. This cannot be undone. Are you sure you want to continue?", + "confirm": "Factory Reset Config", + "failedTitle": "There was an error performing the factory reset. Please try again." + } +} diff --git a/packages/web/public/i18n/locales/zh-TW/map.json b/packages/web/public/i18n/locales/zh-TW/map.json new file mode 100644 index 000000000..01cd2ae82 --- /dev/null +++ b/packages/web/public/i18n/locales/zh-TW/map.json @@ -0,0 +1,38 @@ +{ + "maplibre": { + "GeolocateControl.FindMyLocation": "定位我的位置", + "NavigationControl.ZoomIn": "放大", + "NavigationControl.ZoomOut": "縮小", + "CooperativeGesturesHandler.WindowsHelpText": "按住 Ctrl + 滾動即可縮放地圖", + "CooperativeGesturesHandler.MacHelpText": "按住 ⌘ + 滾動即可縮放地圖", + "CooperativeGesturesHandler.MobileHelpText": "使用雙指移動地圖" + }, + "layerTool": { + "nodeMarkers": "顯示節點", + "directNeighbors": "顯示直接連線", + "remoteNeighbors": "顯示遠端連線", + "positionPrecision": "顯示位置精度", + "traceroutes": "顯示追蹤路由", + "waypoints": "顯示途經點" + }, + "mapMenu": { + "locateAria": "定位我的節點", + "layersAria": "更改地圖樣式" + }, + "waypointDetail": { + "edit": "編輯", + "description": "説明:", + "createdBy": "編輯:", + "createdDate": "建立於:", + "updated": "更新於:", + "expires": "到期時間:", + "distance": "距離:", + "bearing": "絕對方位:", + "lockedTo": "Locked by:", + "latitude": "緯度:", + "longitude": "經度:" + }, + "myNode": { + "tooltip": "此裝置" + } +} diff --git a/packages/web/public/i18n/locales/zh-TW/messages.json b/packages/web/public/i18n/locales/zh-TW/messages.json new file mode 100644 index 000000000..a0e430159 --- /dev/null +++ b/packages/web/public/i18n/locales/zh-TW/messages.json @@ -0,0 +1,39 @@ +{ + "page": { + "title": "訊息:{{chatName}}", + "placeholder": "輸入訊息" + }, + "emptyState": { + "title": "選擇一個對話", + "text": "尚未收到任何訊息。" + }, + "selectChatPrompt": { + "text": "選擇一個頻道或節點來開始聊天。" + }, + "sendMessage": { + "placeholder": "請在此輸入訊息……", + "sendButton": "傳送" + }, + "actionsMenu": { + "addReactionLabel": "新增反應", + "replyLabel": "回覆" + }, + "deliveryStatus": { + "delivered": { + "label": "訊息已送達", + "displayText": "訊息已送達" + }, + "failed": { + "label": "訊息傳送失敗", + "displayText": "傳送失敗" + }, + "unknown": { + "label": "訊息狀態未知", + "displayText": "不明狀態" + }, + "waiting": { + "label": "訊息傳送中", + "displayText": "等待送達" + } + } +} diff --git a/packages/web/public/i18n/locales/zh-TW/moduleConfig.json b/packages/web/public/i18n/locales/zh-TW/moduleConfig.json new file mode 100644 index 000000000..95eb39a5b --- /dev/null +++ b/packages/web/public/i18n/locales/zh-TW/moduleConfig.json @@ -0,0 +1,448 @@ +{ + "page": { + "tabAmbientLighting": "周圍光照", + "tabAudio": "音頻", + "tabCannedMessage": "Canned", + "tabDetectionSensor": "檢測傳感器", + "tabExternalNotification": "Ext Notif", + "tabMqtt": "MQTT", + "tabNeighborInfo": "相鄰設備資訊", + "tabPaxcounter": "客流量計數", + "tabRangeTest": "範圍測試", + "tabSerial": "序列埠", + "tabStoreAndForward": "S&F", + "tabTelemetry": "遙測" + }, + "ambientLighting": { + "title": "Ambient Lighting Settings", + "description": "Settings for the Ambient Lighting module", + "ledState": { + "label": "LED State", + "description": "Sets LED to on or off" + }, + "current": { + "label": "當前", + "description": "Sets the current for the LED output. Default is 10" + }, + "red": { + "label": "紅色", + "description": "Sets the red LED level. Values are 0-255" + }, + "green": { + "label": "綠色", + "description": "Sets the green LED level. Values are 0-255" + }, + "blue": { + "label": "藍色", + "description": "Sets the blue LED level. Values are 0-255" + } + }, + "audio": { + "title": "Audio Settings", + "description": "Settings for the Audio module", + "codec2Enabled": { + "label": "Codec 2 Enabled", + "description": "Enable Codec 2 audio encoding" + }, + "pttPin": { + "label": "PTT Pin", + "description": "GPIO pin to use for PTT" + }, + "bitrate": { + "label": "Bitrate", + "description": "Bitrate to use for audio encoding" + }, + "i2sWs": { + "label": "i2S WS", + "description": "GPIO pin to use for i2S WS" + }, + "i2sSd": { + "label": "i2S SD", + "description": "GPIO pin to use for i2S SD" + }, + "i2sDin": { + "label": "i2S DIN", + "description": "GPIO pin to use for i2S DIN" + }, + "i2sSck": { + "label": "i2S SCK", + "description": "GPIO pin to use for i2S SCK" + } + }, + "cannedMessage": { + "title": "Canned Message Settings", + "description": "Settings for the Canned Message module", + "moduleEnabled": { + "label": "Module Enabled", + "description": "Enable Canned Message" + }, + "rotary1Enabled": { + "label": "Rotary Encoder #1 Enabled", + "description": "Enable the rotary encoder" + }, + "inputbrokerPinA": { + "label": "Encoder Pin A", + "description": "GPIO Pin Value (1-39) For encoder port A" + }, + "inputbrokerPinB": { + "label": "Encoder Pin B", + "description": "GPIO Pin Value (1-39) For encoder port B" + }, + "inputbrokerPinPress": { + "label": "Encoder Pin Press", + "description": "GPIO Pin Value (1-39) For encoder Press" + }, + "inputbrokerEventCw": { + "label": "Clockwise event", + "description": "Select input event." + }, + "inputbrokerEventCcw": { + "label": "Counter Clockwise event", + "description": "Select input event." + }, + "inputbrokerEventPress": { + "label": "Press event", + "description": "Select input event" + }, + "updown1Enabled": { + "label": "Up Down enabled", + "description": "Enable the up / down encoder" + }, + "allowInputSource": { + "label": "Allow Input Source", + "description": "Select from: '_any', 'rotEnc1', 'upDownEnc1', 'cardkb'" + }, + "sendBell": { + "label": "Send Bell", + "description": "Sends a bell character with each message" + } + }, + "detectionSensor": { + "title": "Detection Sensor Settings", + "description": "Settings for the Detection Sensor module", + "enabled": { + "label": "Enabled", + "description": "Enable or disable Detection Sensor Module" + }, + "minimumBroadcastSecs": { + "label": "Minimum Broadcast Seconds", + "description": "The interval in seconds of how often we can send a message to the mesh when a state change is detected" + }, + "stateBroadcastSecs": { + "label": "State Broadcast Seconds", + "description": "The interval in seconds of how often we should send a message to the mesh with the current state regardless of changes" + }, + "sendBell": { + "label": "Send Bell", + "description": "Send ASCII bell with alert message" + }, + "name": { + "label": "Friendly Name", + "description": "Used to format the message sent to mesh, max 20 Characters" + }, + "monitorPin": { + "label": "Monitor Pin", + "description": "The GPIO pin to monitor for state changes" + }, + "detectionTriggerType": { + "label": "Detection Triggered Type", + "description": "The type of trigger event to be used" + }, + "usePullup": { + "label": "Use Pullup", + "description": "Whether or not use INPUT_PULLUP mode for GPIO pin" + } + }, + "externalNotification": { + "title": "External Notification Settings", + "description": "Configure the external notification module", + "enabled": { + "label": "Module Enabled", + "description": "Enable External Notification" + }, + "outputMs": { + "label": "Output MS", + "description": "Output MS" + }, + "output": { + "label": "Output", + "description": "Output" + }, + "outputVibra": { + "label": "Output Vibrate", + "description": "Output Vibrate" + }, + "outputBuzzer": { + "label": "Output Buzzer", + "description": "Output Buzzer" + }, + "active": { + "label": "Active", + "description": "Active" + }, + "alertMessage": { + "label": "Alert Message", + "description": "Alert Message" + }, + "alertMessageVibra": { + "label": "Alert Message Vibrate", + "description": "Alert Message Vibrate" + }, + "alertMessageBuzzer": { + "label": "Alert Message Buzzer", + "description": "Alert Message Buzzer" + }, + "alertBell": { + "label": "Alert Bell", + "description": "Should an alert be triggered when receiving an incoming bell?" + }, + "alertBellVibra": { + "label": "Alert Bell Vibrate", + "description": "Alert Bell Vibrate" + }, + "alertBellBuzzer": { + "label": "Alert Bell Buzzer", + "description": "Alert Bell Buzzer" + }, + "usePwm": { + "label": "Use PWM", + "description": "Use PWM" + }, + "nagTimeout": { + "label": "Nag Timeout", + "description": "Nag Timeout" + }, + "useI2sAsBuzzer": { + "label": "Use I²S Pin as Buzzer", + "description": "Designate I²S Pin as Buzzer Output" + } + }, + "mqtt": { + "title": "MQTT Settings", + "description": "Settings for the MQTT module", + "enabled": { + "label": "Enabled", + "description": "Enable or disable MQTT" + }, + "address": { + "label": "MQTT Server Address", + "description": "MQTT server address to use for default/custom servers" + }, + "username": { + "label": "MQTT Username", + "description": "MQTT username to use for default/custom servers" + }, + "password": { + "label": "MQTT Password", + "description": "MQTT password to use for default/custom servers" + }, + "encryptionEnabled": { + "label": "Encryption Enabled", + "description": "Enable or disable MQTT encryption. Note: All messages are sent to the MQTT broker unencrypted if this option is not enabled, even when your uplink channels have encryption keys set. This includes position data." + }, + "jsonEnabled": { + "label": "JSON Enabled", + "description": "Whether to send/consume JSON packets on MQTT" + }, + "tlsEnabled": { + "label": "TLS Enabled", + "description": "Enable or disable TLS" + }, + "root": { + "label": "根話題", + "description": "MQTT root topic to use for default/custom servers" + }, + "proxyToClientEnabled": { + "label": "MQTT Client Proxy Enabled", + "description": "Utilizes the network connection to proxy MQTT messages to the client." + }, + "mapReportingEnabled": { + "label": "Map Reporting Enabled", + "description": "Your node will periodically send an unencrypted map report packet to the configured MQTT server, this includes id, short and long name, approximate location, hardware model, role, firmware version, LoRa region, modem preset and primary channel name." + }, + "mapReportSettings": { + "publishIntervalSecs": { + "label": "Map Report Publish Interval (s)", + "description": "Interval in seconds to publish map reports" + }, + "positionPrecision": { + "label": "Approximate Location", + "description": "Position shared will be accurate within this distance", + "options": { + "metric_km23": "Within 23 km", + "metric_km12": "Within 12 km", + "metric_km5_8": "Within 5.8 km", + "metric_km2_9": "Within 2.9 km", + "metric_km1_5": "Within 1.5 km", + "metric_m700": "Within 700 m", + "metric_m350": "Within 350 m", + "metric_m200": "Within 200 m", + "metric_m90": "Within 90 m", + "metric_m50": "Within 50 m", + "imperial_mi15": "15英里以內", + "imperial_mi7_3": "7.3英里以內", + "imperial_mi3_6": "3.6英里以內", + "imperial_mi1_8": "1.8英里以內", + "imperial_mi0_9": "0.9英里以內", + "imperial_mi0_5": "0.5英里以內", + "imperial_mi0_2": "0.2英里以內", + "imperial_ft600": "600英尺以內", + "imperial_ft300": "300英尺以內", + "imperial_ft150": "150英尺以內" + } + } + } + }, + "neighborInfo": { + "title": "Neighbor Info Settings", + "description": "Settings for the Neighbor Info module", + "enabled": { + "label": "Enabled", + "description": "Enable or disable Neighbor Info Module" + }, + "updateInterval": { + "label": "Update Interval", + "description": "Interval in seconds of how often we should try to send our Neighbor Info to the mesh" + } + }, + "paxcounter": { + "title": "Paxcounter Settings", + "description": "Settings for the Paxcounter module", + "enabled": { + "label": "Module Enabled", + "description": "Enable Paxcounter" + }, + "paxcounterUpdateInterval": { + "label": "Update Interval (seconds)", + "description": "How long to wait between sending paxcounter packets" + }, + "wifiThreshold": { + "label": "WiFi RSSI Threshold", + "description": "At what WiFi RSSI level should the counter increase. Defaults to -80." + }, + "bleThreshold": { + "label": "BLE RSSI Threshold", + "description": "At what BLE RSSI level should the counter increase. Defaults to -80." + } + }, + "rangeTest": { + "title": "Range Test Settings", + "description": "Settings for the Range Test module", + "enabled": { + "label": "Module Enabled", + "description": "Enable Range Test" + }, + "sender": { + "label": "Message Interval", + "description": "How long to wait between sending test packets" + }, + "save": { + "label": "Save CSV to storage", + "description": "ESP32 Only" + } + }, + "serial": { + "title": "Serial Settings", + "description": "Settings for the Serial module", + "enabled": { + "label": "Module Enabled", + "description": "Enable Serial output" + }, + "echo": { + "label": "Echo", + "description": "Any packets you send will be echoed back to your device" + }, + "rxd": { + "label": "Receive Pin", + "description": "Set the GPIO pin to the RXD pin you have set up." + }, + "txd": { + "label": "Transmit Pin", + "description": "Set the GPIO pin to the TXD pin you have set up." + }, + "baud": { + "label": "Baud Rate", + "description": "The serial baud rate" + }, + "timeout": { + "label": "逾時", + "description": "Seconds to wait before we consider your packet as 'done'" + }, + "mode": { + "label": "Mode", + "description": "Select Mode" + }, + "overrideConsoleSerialPort": { + "label": "Override Console Serial Port", + "description": "If you have a serial port connected to the console, this will override it." + } + }, + "storeForward": { + "title": "Store & Forward Settings", + "description": "Settings for the Store & Forward module", + "enabled": { + "label": "Module Enabled", + "description": "Enable Store & Forward" + }, + "heartbeat": { + "label": "Heartbeat Enabled", + "description": "Enable Store & Forward heartbeat" + }, + "records": { + "label": "紀錄數目", + "description": "Number of records to store" + }, + "historyReturnMax": { + "label": "歴史紀錄最大返回值", + "description": "Max number of records to return" + }, + "historyReturnWindow": { + "label": "歴史紀錄返回視窗", + "description": "Return records from this time window (minutes)" + } + }, + "telemetry": { + "title": "Telemetry Settings", + "description": "Settings for the Telemetry module", + "deviceUpdateInterval": { + "label": "Device Metrics", + "description": "裝置資訊更新週期(秒)" + }, + "environmentUpdateInterval": { + "label": "環境資訊更新週期(秒)", + "description": "" + }, + "environmentMeasurementEnabled": { + "label": "Module Enabled", + "description": "Enable the Environment Telemetry" + }, + "environmentScreenEnabled": { + "label": "Displayed on Screen", + "description": "Show the Telemetry Module on the OLED" + }, + "environmentDisplayFahrenheit": { + "label": "Display Fahrenheit", + "description": "Display temp in Fahrenheit" + }, + "airQualityEnabled": { + "label": "Air Quality Enabled", + "description": "Enable the Air Quality Telemetry" + }, + "airQualityInterval": { + "label": "Air Quality Update Interval", + "description": "How often to send Air Quality data over the mesh" + }, + "powerMeasurementEnabled": { + "label": "Power Measurement Enabled", + "description": "Enable the Power Measurement Telemetry" + }, + "powerUpdateInterval": { + "label": "Power Update Interval", + "description": "How often to send Power data over the mesh" + }, + "powerScreenEnabled": { + "label": "Power Screen Enabled", + "description": "Enable the Power Telemetry Screen" + } + } +} diff --git a/packages/web/public/i18n/locales/zh-TW/nodes.json b/packages/web/public/i18n/locales/zh-TW/nodes.json new file mode 100644 index 000000000..d5029535d --- /dev/null +++ b/packages/web/public/i18n/locales/zh-TW/nodes.json @@ -0,0 +1,59 @@ +{ + "nodeDetail": { + "publicKeyEnabled": { + "label": "公鑰已啟用" + }, + "noPublicKey": { + "label": "沒有公鑰" + }, + "directMessage": { + "label": "私人訊息 {{shortName}}" + }, + "favorite": { + "label": "收藏", + "tooltip": "將此節點加入/移除收藏" + }, + "notFavorite": { + "label": "Not a Favorite" + }, + "error": { + "label": "錯誤", + "text": "無法取得節點詳細資料,請稍後重試。" + }, + "status": { + "heard": "Heard", + "mqtt": "MQTT" + }, + "elevation": { + "label": "海拔高度" + }, + "channelUtil": { + "label": "頻道利用率" + }, + "airtimeUtil": { + "label": "空中時間利用率" + } + }, + "nodesTable": { + "headings": { + "longName": "完整名稱", + "connection": "連線", + "lastHeard": "最後接收時間", + "encryption": "加密", + "model": "Model", + "macAddress": "MAC 地址" + }, + "connectionStatus": { + "direct": "直線", + "away": "away", + "viaMqtt": ",透過 MQTT" + } + }, + "actions": { + "added": "已添加", + "removed": "已移除", + "ignoreNode": "忽略節點", + "unignoreNode": "取消忽略節點", + "requestPosition": "請求位置" + } +} diff --git a/packages/web/public/i18n/locales/zh-TW/ui.json b/packages/web/public/i18n/locales/zh-TW/ui.json new file mode 100644 index 000000000..ac98cfdc9 --- /dev/null +++ b/packages/web/public/i18n/locales/zh-TW/ui.json @@ -0,0 +1,230 @@ +{ + "navigation": { + "title": "導航", + "messages": "訊息", + "map": "地圖", + "settings": "設定", + "channels": "頻道", + "radioConfig": "無線電設定", + "deviceConfig": "設備設置", + "moduleConfig": "模組設定", + "manageConnections": "Manage Connections", + "nodes": "節點" + }, + "app": { + "title": "Meshtastic", + "logo": "Meshtastic Logo" + }, + "sidebar": { + "collapseToggle": { + "button": { + "open": "開啟側邊欄", + "close": "關閉側邊欄" + } + }, + "deviceInfo": { + "volts": "{{voltage}} V", + "firmware": { + "title": "韌體", + "version": "v{{version}}", + "buildDate": "Build date: {{date}}" + } + } + }, + "batteryStatus": { + "charging": "{{level}}% 充電中", + "pluggedIn": "已接上電源", + "title": "電池" + }, + "search": { + "nodes": "搜尋節點……", + "channels": "搜尋頻道……", + "commandPalette": "搜尋指令……" + }, + "toast": { + "positionRequestSent": { + "title": "位置請求已送出。" + }, + "requestingPosition": { + "title": "正在請求位置,請稍候……" + }, + "sendingTraceroute": { + "title": "正在執行追蹤路由,請稍候……" + }, + "tracerouteSent": { + "title": "追蹤路由已送出。" + }, + "savedChannel": { + "title": "已儲存頻道:{{channelName}}" + }, + "messages": { + "pkiEncryption": { + "title": "對話正使用 PKI 加密。" + }, + "pskEncryption": { + "title": "對話正使用 PSK 加密。" + } + }, + "configSaveError": { + "title": "儲存失敗", + "description": "儲存設定時發生錯誤。" + }, + "validationError": { + "title": "配置中存在錯誤", + "description": "儲存前請先修正設定錯誤。" + }, + "saveSuccess": { + "title": "正在儲存設定", + "description": "{{case}} 設定已保存。" + }, + "saveAllSuccess": { + "title": "已儲存", + "description": "所有設定已保存。" + }, + "favoriteNode": { + "title": "{{action}} {{nodeName}} {{direction}} favorites.", + "action": { + "added": "已添加", + "removed": "已移除", + "to": "to", + "from": "from" + } + }, + "ignoreNode": { + "title": "{{action}} {{nodeName}} {{direction}} ignore list", + "action": { + "added": "已添加", + "removed": "已移除", + "to": "to", + "from": "from" + } + } + }, + "notifications": { + "copied": { + "label": "已複製!" + }, + "copyToClipboard": { + "label": "複製到剪貼簿" + }, + "hidePassword": { + "label": "隱藏密碼" + }, + "showPassword": { + "label": "顯示密碼" + }, + "deliveryStatus": { + "delivered": "已送達", + "failed": "傳送失敗", + "waiting": "等待中", + "unknown": "不明" + } + }, + "general": { + "label": "一般設定" + }, + "hardware": { + "label": "硬體" + }, + "metrics": { + "label": "Metrics" + }, + "role": { + "label": "角色" + }, + "filter": { + "label": "過濾器" + }, + "advanced": { + "label": "進階" + }, + "clearInput": { + "label": "清除輸入" + }, + "resetFilters": { + "label": "重設篩選器" + }, + "nodeName": { + "label": "節點名稱/編號", + "placeholder": "Meshtastic 1234" + }, + "airtimeUtilization": { + "label": "空中時間利用率 (%)", + "short": "空中時間利用率 (%)" + }, + "batteryLevel": { + "label": "電池電量 (%)", + "labelText": "電池電量 (%):{{value}}" + }, + "batteryVoltage": { + "label": "電池電壓 (V)", + "title": "電壓" + }, + "channelUtilization": { + "label": "頻道利用率 (%)", + "short": "頻道利用率 (%)" + }, + "hops": { + "direct": "直線", + "label": "跳數", + "text": "跳數:{{value}}" + }, + "lastHeard": { + "label": "最近一次收到排序", + "labelText": "最後接收時間:{{value}}", + "nowLabel": "Now" + }, + "snr": { + "label": "SNR (db)" + }, + "favorites": { + "label": "Favorites" + }, + "hide": { + "label": "隱藏" + }, + "showOnly": { + "label": "僅顯示" + }, + "viaMqtt": { + "label": "已透過 MQTT 連線" + }, + "hopsUnknown": { + "label": "跳數未知" + }, + "showUnheard": { + "label": "Unknown last heard" + }, + "language": { + "label": "語言", + "changeLanguage": "變更語言" + }, + "theme": { + "dark": "深色", + "light": "淺色", + "system": "自動", + "changeTheme": "更改顏色方案" + }, + "errorPage": { + "title": "這有點尷尬……", + "description1": "我們深感抱歉,網頁客戶端發生錯誤並導致程式崩潰。
這是不應該發生的情況,我們正積極努力修復此問題。", + "description2": "幫助我們防止此問題再次發生,請將問題回報給我們。", + "reportInstructions": "請在您的回報中附上下列資訊:", + "reportSteps": { + "step1": "發生錯誤時您正在執行的動作", + "step2": "您預期會發生什麼", + "step3": "實際發生的情況", + "step4": "其他相關資訊" + }, + "reportLink": "您可以將此問題回報到我們的 <0>GitHub", + "connectionsLink": "Return to the <0>connections", + "detailsSummary": "錯誤詳情", + "errorMessageLabel": "錯誤訊息:", + "stackTraceLabel": "Stack trace:", + "fallbackError": "{{error}}" + }, + "footer": { + "text": "技術支援: <0>▲ Vercel | Meshtastic® 是 Meshtastic LLC. 的註冊商標。| <1>法律資訊", + "commitSha": "Commit SHA: {{sha}}" + } +} diff --git a/packages/web/public/logo.svg b/packages/web/public/logo.svg deleted file mode 100644 index 2d4a4fb69..000000000 --- a/packages/web/public/logo.svg +++ /dev/null @@ -1,41 +0,0 @@ - - - - Created with Fabric.js 4.6.0 - - - - - - - - - - - diff --git a/packages/web/public/logo_black.svg b/packages/web/public/logo_black.svg deleted file mode 100644 index 3568d3001..000000000 --- a/packages/web/public/logo_black.svg +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - - - - - - diff --git a/packages/web/public/logo_white.svg b/packages/web/public/logo_white.svg deleted file mode 100644 index 7c5417ed9..000000000 --- a/packages/web/public/logo_white.svg +++ /dev/null @@ -1,28 +0,0 @@ - - - - - - - - - - - - diff --git a/packages/web/src/App.tsx b/packages/web/src/App.tsx index d0eb9ebe4..5fc115c6f 100644 --- a/packages/web/src/App.tsx +++ b/packages/web/src/App.tsx @@ -1,37 +1,35 @@ import { DeviceWrapper } from "@app/DeviceWrapper.tsx"; import { CommandPalette } from "@components/CommandPalette/index.tsx"; import { DialogManager } from "@components/Dialog/DialogManager.tsx"; -import { NewDeviceDialog } from "@components/Dialog/NewDeviceDialog.tsx"; import { KeyBackupReminder } from "@components/KeyBackupReminder.tsx"; import { Toaster } from "@components/Toaster.tsx"; import { ErrorPage } from "@components/UI/ErrorPage.tsx"; import Footer from "@components/UI/Footer.tsx"; import { useTheme } from "@core/hooks/useTheme.ts"; import { SidebarProvider, useAppStore, useDeviceStore } from "@core/stores"; -import { Dashboard } from "@pages/Dashboard/index.tsx"; +import { Connections } from "@pages/Connections/index.tsx"; import { Outlet } from "@tanstack/react-router"; import { TanStackRouterDevtools } from "@tanstack/react-router-devtools"; import { ErrorBoundary } from "react-error-boundary"; import { MapProvider } from "react-map-gl/maplibre"; export function App() { + useTheme(); + const { getDevice } = useDeviceStore(); - const { selectedDeviceId, setConnectDialogOpen, connectDialogOpen } = - useAppStore(); + const { selectedDeviceId } = useAppStore(); const device = getDevice(selectedDeviceId); - // Sets up light/dark mode based on user preferences or system settings - useTheme(); - return ( + // - { setConnectDialogOpen(open); }} - /> + /> */} @@ -40,7 +38,7 @@ export function App() { style={{ scrollbarWidth: "thin" }} > -
+
{device ? (
@@ -52,7 +50,7 @@ export function App() {
) : ( <> - +
)} @@ -61,5 +59,6 @@ export function App() {
+ // ); } diff --git a/packages/web/src/components/Badge/ConnectionStatusBadge.tsx b/packages/web/src/components/Badge/ConnectionStatusBadge.tsx new file mode 100644 index 000000000..e69de29bb diff --git a/packages/web/src/components/Badge/SupportedBadge.tsx b/packages/web/src/components/Badge/SupportedBadge.tsx new file mode 100644 index 000000000..ae935c9c8 --- /dev/null +++ b/packages/web/src/components/Badge/SupportedBadge.tsx @@ -0,0 +1,19 @@ +import { Badge } from "../UI/Badge.tsx"; + +export function SupportBadge({ + supported, + labelSupported, + labelUnsupported, +}: { + supported: boolean; + labelSupported: string; + labelUnsupported: string; +}) { + return ( +
+ + {supported ? labelSupported : labelUnsupported} + +
+ ); +} diff --git a/packages/web/src/components/CommandPalette/index.tsx b/packages/web/src/components/CommandPalette/index.tsx index ba53c9805..afda6b5c3 100644 --- a/packages/web/src/components/CommandPalette/index.tsx +++ b/packages/web/src/components/CommandPalette/index.tsx @@ -126,14 +126,7 @@ export const CommandPalette = () => { label: getNode(device.hardware.myNodeNum)?.user?.longName ?? t("unknown.shortName"), - icon: ( - - ), + icon: , action() { setSelectedDevice(device.id); }, diff --git a/packages/web/src/components/DeviceInfoPanel.tsx b/packages/web/src/components/DeviceInfoPanel.tsx index 6480cb395..f962a382b 100644 --- a/packages/web/src/components/DeviceInfoPanel.tsx +++ b/packages/web/src/components/DeviceInfoPanel.tsx @@ -1,10 +1,13 @@ +import type { ConnectionStatus } from "@app/core/stores/deviceStore/types.ts"; import { cn } from "@core/utils/cn.ts"; +import type { Protobuf } from "@meshtastic/core"; +import { useNavigate } from "@tanstack/react-router"; import { + ChevronRight, CpuIcon, Languages, type LucideIcon, Palette, - PenLine, Search as SearchIcon, ZapIcon, } from "lucide-react"; @@ -23,13 +26,12 @@ interface DeviceInfoPanelProps { isCollapsed: boolean; deviceMetrics: DeviceMetrics; firmwareVersion: string; - user: { - shortName: string; - longName: string; - }; + user?: Protobuf.Mesh.User; setDialogOpen: () => void; setCommandPaletteOpen: () => void; disableHover?: boolean; + connectionStatus?: ConnectionStatus; + connectionName?: string; } interface InfoDisplayItem { @@ -53,13 +55,46 @@ export const DeviceInfoPanel = ({ firmwareVersion, user, isCollapsed, - setDialogOpen, setCommandPaletteOpen, disableHover = false, + connectionStatus, + connectionName, }: DeviceInfoPanelProps) => { const { t } = useTranslation(); + const navigate = useNavigate({ from: "/" }); const { batteryLevel, voltage } = deviceMetrics; + const getStatusColor = (status?: ConnectionStatus): string => { + if (!status) { + return "bg-gray-400"; + } + switch (status) { + case "connected": + case "configured": + case "online": + return "bg-emerald-500"; + case "connecting": + case "configuring": + case "disconnecting": + return "bg-amber-500"; + case "error": + return "bg-red-500"; + default: + return "bg-gray-400"; + } + }; + + const getStatusLabel = (status?: ConnectionStatus): string => { + if (!status) { + return t("unknown.notAvailable", "N/A"); + } + // Show "connected" for configured state + if (status === "configured") { + return t("toasts.connected", { ns: "connections" }); + } + return status; + }; + const deviceInfoItems: InfoDisplayItem[] = [ { id: "battery", @@ -91,12 +126,6 @@ export const DeviceInfoPanel = ({ icon: Palette, render: () => , }, - { - id: "changeName", - label: t("sidebar.deviceInfo.deviceName.changeName"), - icon: PenLine, - onClick: setDialogOpen, - }, { id: "commandMenu", label: t("page.title", { ns: "commandPalette" }), @@ -106,7 +135,7 @@ export const DeviceInfoPanel = ({ { id: "language", - label: t("language.changeLanguage"), + label: t("languagePicker.label"), icon: Languages, render: () => , }, @@ -114,28 +143,69 @@ export const DeviceInfoPanel = ({ return ( <> -
- - {!isCollapsed && ( -

+ + {!isCollapsed && ( +

+ {user.longName} +

+ )} +
+ )} + + {connectionStatus && ( +
+ aria-hidden="true" + /> + {!isCollapsed && ( + <> +
+ + {connectionName || "Connection"} + + + {getStatusLabel(connectionStatus)} + +
+ + + )} + + )} {!isCollapsed && (
diff --git a/packages/web/src/components/Dialog/AddConnectionDialog/AddConnectionDialog.tsx b/packages/web/src/components/Dialog/AddConnectionDialog/AddConnectionDialog.tsx new file mode 100644 index 000000000..38332c7f3 --- /dev/null +++ b/packages/web/src/components/Dialog/AddConnectionDialog/AddConnectionDialog.tsx @@ -0,0 +1,675 @@ +import { SupportBadge } from "@app/components/Badge/SupportedBadge.tsx"; +import { Switch } from "@app/components/UI/Switch.tsx"; +import type { + ConnectionType, + NewConnection, +} from "@app/core/stores/deviceStore/types.ts"; +import { testHttpReachable } from "@app/pages/Connections/utils"; +import { Button } from "@components/UI/Button.tsx"; +import { Input } from "@components/UI/Input.tsx"; +import { Label } from "@components/UI/Label.tsx"; +import { + Tabs, + TabsContent, + TabsList, + TabsTrigger, +} from "@components/UI/Tabs.tsx"; +import { Link } from "@components/UI/Typography/Link.tsx"; +import { + type BrowserFeature, + useBrowserFeatureDetection, +} from "@core/hooks/useBrowserFeatureDetection.ts"; +import { useToast } from "@core/hooks/useToast.ts"; +import { TransportWebBluetooth } from "@meshtastic/transport-web-bluetooth"; +import { + AlertCircle, + Bluetooth, + Cable, + CheckCircle2, + Globe, + Loader2, + type LucideIcon, + MousePointerClick, + XCircle, +} from "lucide-react"; +import { useCallback, useEffect, useMemo, useReducer } from "react"; +import { Trans, useTranslation } from "react-i18next"; +import { DialogWrapper } from "../DialogWrapper.tsx"; +import { urlOrIpv4Schema } from "./validation.ts"; + +type TabKey = ConnectionType; +type TestingStatus = "idle" | "testing" | "success" | "failure"; +type DialogState = { + tab: TabKey; + name: string; + protocol: "http" | "https"; + url: string; + testStatus: TestingStatus; + btSelected: + | { id: string; name?: string; device?: BluetoothDevice } + | undefined; + serialSelected: { vendorId?: number; productId?: number } | undefined; +}; + +type DialogAction = + | { type: "RESET"; payload?: { isHTTPS?: boolean } } + | { type: "SET_TAB"; payload: TabKey } + | { type: "SET_NAME"; payload: string } + | { type: "SET_PROTOCOL"; payload: "http" | "https" } + | { type: "SET_URL"; payload: string } + | { type: "SET_TEST_STATUS"; payload: TestingStatus } + | { + type: "SET_BT_SELECTED"; + payload: + | { id: string; name?: string; device?: BluetoothDevice } + | undefined; + } + | { + type: "SET_SERIAL_SELECTED"; + payload: { vendorId?: number; productId?: number } | undefined; + } + | { type: "SET_URL_AND_RESET_TEST"; payload: string }; + +interface FeatureErrorProps { + missingFeatures: BrowserFeature[]; + tabId: "bluetooth" | "serial"; +} + +type Pane = { + children: () => React.ReactNode; + placeholder: string; + validate: () => boolean; + build: () => NewConnection | null; +}; + +const featureErrors: Record = + { + "Web Bluetooth": { + href: "https://developer.mozilla.org/en-US/docs/Web/API/Web_Bluetooth_API#browser_compatibility", + i18nKey: "addConnection.validation.requiresWebBluetooth", + }, + "Web Serial": { + href: "https://developer.mozilla.org/en-US/docs/Web/API/Web_Serial_API#browser_compatibility", + i18nKey: "addConnection.validation.requiresWebSerial", + }, + "Secure Context": { + href: "https://developer.mozilla.org/en-US/docs/Web/Security/Secure_Contexts", + i18nKey: "addConnection.validation.requiresSecureContext", + }, + }; + +const FeatureErrorMessage = ({ missingFeatures, tabId }: FeatureErrorProps) => { + if (missingFeatures.length === 0) { + return null; + } + + const browserFeatures = missingFeatures.filter( + (feature) => feature !== "Secure Context", + ); + const needsSecureContext = missingFeatures.includes("Secure Context"); + + const needsFeature = + tabId === "bluetooth" && browserFeatures.includes("Web Bluetooth") + ? "Web Bluetooth" + : tabId === "serial" && browserFeatures.includes("Web Serial") + ? "Web Serial" + : undefined; + + return ( +
+
+ +
+
+ {needsFeature && ( + , + ]} + /> + )} + {needsFeature && needsSecureContext && " "} + {needsSecureContext && ( + 0 + ? "addConnection.validation.additionallyRequiresSecureContext" + : "addConnection.validation.requiresSecureContext" + } + components={{ + "0": ( + + ), + }} + /> + )} +
+
+
+
+ ); +}; + +const initialState: DialogState = { + tab: "http", + name: "", + protocol: "http", + url: "", + testStatus: "idle", + btSelected: undefined, + serialSelected: undefined, +}; +export const createInitialDialogState = ( + overrides?: Partial, +): DialogState => { + return { ...initialState, ...(overrides ?? {}) }; +}; + +export const dialogStateInitializer = ( + overrides?: Partial, +): DialogState => createInitialDialogState(overrides); + +function dialogReducer(state: DialogState, action: DialogAction): DialogState { + switch (action.type) { + case "RESET": + return createInitialDialogState( + action.payload?.isHTTPS ? { protocol: "https" } : {}, + ); + case "SET_TAB": + return { ...state, tab: action.payload }; + case "SET_NAME": + return { ...state, name: action.payload }; + case "SET_PROTOCOL": + return { ...state, protocol: action.payload }; + case "SET_URL": + return { ...state, url: action.payload }; + case "SET_TEST_STATUS": + return { ...state, testStatus: action.payload }; + case "SET_BT_SELECTED": + return { ...state, btSelected: action.payload }; + case "SET_SERIAL_SELECTED": + return { ...state, serialSelected: action.payload }; + case "SET_URL_AND_RESET_TEST": + return { ...state, url: action.payload, testStatus: "idle" }; + default: + return state; + } +} + +function PickerRow({ + label, + buttonText, + onPick, + disabled, + display, + helper, +}: { + label: string; + buttonText: string; + onPick: () => void | Promise; + disabled?: boolean; + display: string; + helper?: string; +}) { + return ( +
+ +
+ +
+ {display} +
+
+ {helper ? ( +

{helper}

+ ) : null} +
+ ); +} + +const TAB_META: Array<{ key: TabKey; label: string; Icon: LucideIcon }> = [ + { key: "http", label: "HTTP", Icon: Globe }, + { key: "bluetooth", label: "Bluetooth", Icon: Bluetooth }, + { key: "serial", label: "Serial", Icon: Cable }, +]; + +export default function AddConnectionDialog({ + open = false, + onOpenChange = () => {}, + onSave = async () => {}, + isHTTPS = false, +}: { + open?: boolean; + onOpenChange?: (open: boolean) => void; + onSave?: (conn: NewConnection, device?: BluetoothDevice) => Promise; + isHTTPS?: boolean; +}) { + const { toast } = useToast(); + const [state, dispatch] = useReducer(dialogReducer, initialState, () => + dialogStateInitializer(isHTTPS ? { protocol: "https" } : {}), + ); + const { unsupported } = useBrowserFeatureDetection(); + const { t } = useTranslation(); + + const bluetoothSupported = + typeof navigator !== "undefined" && "bluetooth" in navigator; + const serialSupported = + typeof navigator !== "undefined" && "serial" in navigator; + const isURLHTTPS = isHTTPS; + + const reset = useCallback(() => { + dispatch({ type: "RESET", payload: { isHTTPS } }); + }, [isHTTPS]); + + useEffect(() => { + if (!open) { + reset(); + } + }, [reset, open]); + + const makeToastErrorHandler = useCallback( + (titlePrefix: string) => + (err: unknown): void => { + if (err && (err as { name?: string }).name === "NotFoundError") { + return; // user canceled + } + const message = err instanceof Error ? err.message : String(err); + toast({ title: `${titlePrefix} error`, description: message }); + }, + [toast], + ); + + const handlePickBluetooth = useCallback(async () => { + if (!bluetoothSupported) { + toast({ + title: t("addConnection.bluetoothConnection.notSupported.title"), + description: t( + "addConnection.bluetoothConnection.notSupported.description", + ), + }); + return; + } + try { + const device = await navigator.bluetooth.requestDevice({ + filters: [{ services: [TransportWebBluetooth.ServiceUuid] }], + }); + dispatch({ + type: "SET_BT_SELECTED", + payload: { id: device.id, name: device.name ?? undefined, device }, + }); + if (!state.name || state.name === "") { + dispatch({ + type: "SET_NAME", + payload: device.name + ? t("addConnection.bluetoothConnection.short", { + deviceName: device.name, + }) + : t("addConnection.bluetoothConnection.long"), + }); + } + toast({ + title: t("addConnection.bluetoothConnection.selected"), + description: device.name || device.id, + }); + } catch (err) { + makeToastErrorHandler("Bluetooth")(err); + } + }, [bluetoothSupported, state.name, toast, makeToastErrorHandler, t]); + + const handlePickSerial = useCallback(async () => { + if (!serialSupported) { + toast({ + title: t("addConnection.serialConnection.notSupported.title"), + description: t( + "addConnection.serialConnection.notSupported.description", + ), + }); + return; + } + try { + const port = await ( + navigator as Navigator & { + serial: { + requestPort: (o: Record) => Promise; + }; + } + ).serial.requestPort({}); + const info = + ( + port as SerialPort & { + getInfo?: () => { usbVendorId?: number; usbProductId?: number }; + } + ).getInfo?.() ?? {}; + dispatch({ + type: "SET_SERIAL_SELECTED", + payload: { + vendorId: info.usbVendorId, + productId: info.usbProductId, + }, + }); + if (!state.name || state.name === "") { + const v = info.usbVendorId ? info.usbVendorId.toString(16) : "?"; + const p = info.usbProductId ? info.usbProductId.toString(16) : "?"; + dispatch({ type: "SET_NAME", payload: `Serial: ${v}:${p}` }); + } + toast({ + title: t("addConnection.serialConnection.portSelected.title"), + description: t( + "addConnection.serialConnection.portSelected.description", + ), + }); + } catch (err) { + makeToastErrorHandler("Serial")(err); + } + }, [serialSupported, state.name, toast, makeToastErrorHandler, t]); + + const handleTestHttp = useCallback(async () => { + const fullUrl = `${state.protocol}://${state.url}`; + const validatedURL = urlOrIpv4Schema.safeParse(fullUrl); + if (validatedURL.success === false) { + toast({ + title: t("addConnection.httpConnection.invalidUrl.title"), + description: t("addConnection.httpConnection.invalidUrl.description"), + }); + return; + } + dispatch({ type: "SET_TEST_STATUS", payload: "testing" }); + const reachable = await testHttpReachable(validatedURL.data); + if (reachable) { + dispatch({ type: "SET_TEST_STATUS", payload: "success" }); + } else { + dispatch({ type: "SET_TEST_STATUS", payload: "failure" }); + toast({ + title: t("addConnection.httpConnection.connectionTest.failure.title"), + description: t( + "addConnection.httpConnection.connectionTest.failure.description", + ), + }); + } + }, [state.protocol, state.url, toast, t]); + + const PANES: Record = useMemo( + () => ({ + http: { + placeholder: t("addConnection.httpConnection.namePlaceholder"), + children: () => ( +
+ + + { + dispatch({ + type: "SET_URL_AND_RESET_TEST", + payload: e.target.value, + }); + }} + /> +
+ { + dispatch({ + type: "SET_PROTOCOL", + payload: value ? "https" : "http", + }); + dispatch({ type: "SET_TEST_STATUS", payload: "idle" }); + }} + > + +
+
+ + {state.testStatus === "success" && ( +
+ + {t("addConnection.httpConnection.connectionTest.reachable")} +
+ )} + {state.testStatus === "failure" && ( +
+ + {t( + "addConnection.httpConnection.connectionTest.notReachable", + )} +
+ )} +
+

+ {t("addConnection.httpConnection.connectionTest.description")} +

+
+ ), + validate: () => + urlOrIpv4Schema.safeParse(`${state.protocol}://${state.url}`) + .success === true && state.testStatus === "success", + build: () => ({ + type: "http", + name: state.name.trim(), + url: `${state.protocol}://${state.url.trim()}`, + }), + }, + bluetooth: { + placeholder: "My Bluetooth Node", + children: () => ( + <> + + + + + ), + validate: () => state.name.trim().length > 0 && !!state.btSelected, + build: () => ({ + type: "bluetooth", + name: state.name.trim(), + deviceId: state.btSelected?.id, + deviceName: state.btSelected?.name, + gattServiceUUID: TransportWebBluetooth.ServiceUuid, + }), + }, + serial: { + placeholder: t("addConnection.serialConnection.namePlaceholder"), + children: () => ( + <> + + + + + ), + validate: () => + state.name.trim().length > 0 && + (!!state.serialSelected || !serialSupported), + build: () => ({ + type: "serial", + name: state.name.trim(), + usbVendorId: state.serialSelected?.vendorId, + usbProductId: state.serialSelected?.productId, + }), + }, + }), + [ + state, + bluetoothSupported, + serialSupported, + isURLHTTPS, + handlePickBluetooth, + handlePickSerial, + handleTestHttp, + unsupported, + t, + ], + ); + + const currentPane = PANES[state.tab]; + const canCreate = useMemo(() => currentPane.validate(), [currentPane]); + + const submit = + (fn: (p: NewConnection, device?: BluetoothDevice) => Promise) => + async () => { + if (!canCreate) { + return; + } + const payload = currentPane.build(); + + if (!payload) { + return; + } + const btDevice = + state.tab === "bluetooth" ? state.btSelected?.device : undefined; + await fn(payload, btDevice); + }; + + return ( + + + dispatch({ type: "SET_TAB", payload: v as TabKey }) + } + > + + {TAB_META.map(({ key, label, Icon }) => ( + + + {label} + + ))} + + + {TAB_META.map(({ key }) => ( + + {state.tab === key ? ( +
+
+ + + dispatch({ type: "SET_NAME", payload: evt.target.value }) + } + placeholder={currentPane.placeholder} + /> +
+ {PANES[key].children()} +
+
+ +
+
+
+ ) : null} +
+ ))} +
+
+ ); +} diff --git a/packages/web/src/components/Dialog/AddConnectionDialog/validation.ts b/packages/web/src/components/Dialog/AddConnectionDialog/validation.ts new file mode 100644 index 000000000..e9d278b4c --- /dev/null +++ b/packages/web/src/components/Dialog/AddConnectionDialog/validation.ts @@ -0,0 +1,46 @@ +import z from "zod"; + +export const urlOrIpv4Schema = z + .string() + .trim() + .refine((val) => { + const input = val.replace(/^https?:\/\//i, ""); + + // Split input into host and port (port is optional) + const lastColonIndex = input.lastIndexOf(":"); + let host = input; + let port = null; + + if (lastColonIndex !== -1) { + const potentialPort = input.substring(lastColonIndex + 1); + if (/^\d+$/.test(potentialPort)) { + host = input.substring(0, lastColonIndex); + port = parseInt(potentialPort, 10); + } + } + + // Validate port if present + if (port !== null) { + // Must be 2-5 digits and between 10-65535 + if (port < 10 || port > 65535) { + return false; + } + } + + // IPv4 pattern + const ipv4Regex = + /^(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(\.(25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}$/; + // Domain pattern (e.g. example.com, meshtastic.local) + const domainRegex = /^(?!-)(?:[a-zA-Z0-9-]{1,63}\.)+[a-zA-Z]{2,}$/; + // Local domain (e.g. meshtastic.local) + const localDomainRegex = /^(?!-)[a-zA-Z0-9-]+(\.[a-zA-Z0-9-]+)*\.local$/; + + return ( + ipv4Regex.test(host) || + domainRegex.test(host) || + localDomainRegex.test(host) + ); + }, "Must be a valid IPv4 address or domain name with optional port (10-65535)") + .transform((val) => { + return /^https?:\/\//i.test(val) ? val : `http://${val}`; + }); diff --git a/packages/web/src/components/Dialog/DeviceNameDialog.tsx b/packages/web/src/components/Dialog/DeviceNameDialog.tsx deleted file mode 100644 index 055d11f86..000000000 --- a/packages/web/src/components/Dialog/DeviceNameDialog.tsx +++ /dev/null @@ -1,140 +0,0 @@ -import { create } from "@bufbuild/protobuf"; -import { GenericInput } from "@components/Form/FormInput.tsx"; -import { Button } from "@components/UI/Button.tsx"; -import { - Dialog, - DialogClose, - DialogContent, - DialogDescription, - DialogFooter, - DialogHeader, - DialogTitle, -} from "@components/UI/Dialog.tsx"; -import { useDevice, useNodeDB } from "@core/stores"; -import { zodResolver } from "@hookform/resolvers/zod"; -import { Protobuf } from "@meshtastic/core"; -import { useForm } from "react-hook-form"; -import { useTranslation } from "react-i18next"; -import z from "zod"; -import { Label } from "../UI/Label.tsx"; - -export interface User { - longName: string; - shortName: string; -} - -export interface DeviceNameDialogProps { - open: boolean; - onOpenChange: (open: boolean) => void; -} - -export const DeviceNameDialog = ({ - open, - onOpenChange, -}: DeviceNameDialogProps) => { - const { t } = useTranslation("dialog"); - const { hardware, connection } = useDevice(); - const { getNode } = useNodeDB(); - const myNode = getNode(hardware.myNodeNum); - - const defaultValues = { - shortName: myNode?.user?.shortName ?? "", - longName: myNode?.user?.longName ?? "", - }; - - const deviceNameSchema = z.object({ - longName: z - .string() - .min(1, t("deviceName.validation.longNameMin")) - .max(40, t("deviceName.validation.longNameMax")), - shortName: z - .string() - .min(2, t("deviceName.validation.shortNameMin")) - .max(4, t("deviceName.validation.shortNameMax")), - }); - - const { getValues, reset, control, handleSubmit } = useForm({ - values: defaultValues, - resolver: zodResolver(deviceNameSchema), - }); - - const onSubmit = handleSubmit((data) => { - connection?.setOwner( - create(Protobuf.Mesh.UserSchema, { - ...data, - }), - ); - onOpenChange(false); - }); - - const handleReset = () => { - reset(defaultValues); - }; - - return ( - - - - - {t("deviceName.title")} - {t("deviceName.description")} - -
-
- - -
-
- - -
- - - - - -
-
-
- ); -}; diff --git a/packages/web/src/components/Dialog/DialogManager.tsx b/packages/web/src/components/Dialog/DialogManager.tsx index 484cc2614..811e35a77 100644 --- a/packages/web/src/components/Dialog/DialogManager.tsx +++ b/packages/web/src/components/Dialog/DialogManager.tsx @@ -3,7 +3,6 @@ import { FactoryResetDeviceDialog } from "@app/components/Dialog/FactoryResetDev import { ClearAllStoresDialog } from "@components/Dialog/ClearAllStoresDialog/ClearAllStoresDialog.tsx"; import { ClientNotificationDialog } from "@components/Dialog/ClientNotificationDialog/ClientNotificationDialog.tsx"; import { DeleteMessagesDialog } from "@components/Dialog/DeleteMessagesDialog/DeleteMessagesDialog.tsx"; -import { DeviceNameDialog } from "@components/Dialog/DeviceNameDialog.tsx"; import { ImportDialog } from "@components/Dialog/ImportDialog.tsx"; import { NodeDetailsDialog } from "@components/Dialog/NodeDetailsDialog/NodeDetailsDialog.tsx"; import { PkiBackupDialog } from "@components/Dialog/PKIBackupDialog.tsx"; @@ -47,12 +46,6 @@ export const DialogManager = () => { setDialogOpen("reboot", false); }} /> - { - setDialogOpen("deviceName", open); - }} - /> { diff --git a/packages/web/src/components/Dialog/FactoryResetDeviceDialog/FactoryResetDeviceDialog.test.tsx b/packages/web/src/components/Dialog/FactoryResetDeviceDialog/FactoryResetDeviceDialog.test.tsx index 848e802fa..01492e02f 100644 --- a/packages/web/src/components/Dialog/FactoryResetDeviceDialog/FactoryResetDeviceDialog.test.tsx +++ b/packages/web/src/components/Dialog/FactoryResetDeviceDialog/FactoryResetDeviceDialog.test.tsx @@ -1,29 +1,41 @@ -// FactoryResetDeviceDialog.test.tsx import { fireEvent, render, screen, waitFor } from "@testing-library/react"; import { beforeEach, describe, expect, it, vi } from "vitest"; import { FactoryResetDeviceDialog } from "./FactoryResetDeviceDialog.tsx"; const mockFactoryResetDevice = vi.fn(); -const mockDeleteAllMessages = vi.fn(); -const mockRemoveAllNodeErrors = vi.fn(); -const mockRemoveAllNodes = vi.fn(); +const mockRemoveDevice = vi.fn(); +const mockRemoveMessageStore = vi.fn(); +const mockRemoveNodeDB = vi.fn(); +const mockToast = vi.fn(); -vi.mock("@core/stores", () => ({ - CurrentDeviceContext: { - _currentValue: { deviceId: 1234 }, - }, - useDevice: () => ({ - connection: { - factoryResetDevice: mockFactoryResetDevice, +vi.mock("@core/stores", () => { + // Make each store a callable fn (like a Zustand hook), and attach .getState() + const useDeviceStore = Object.assign(vi.fn(), { + getState: () => ({ removeDevice: mockRemoveDevice }), + }); + const useMessageStore = Object.assign(vi.fn(), { + getState: () => ({ removeMessageStore: mockRemoveMessageStore }), + }); + const useNodeDBStore = Object.assign(vi.fn(), { + getState: () => ({ removeNodeDB: mockRemoveNodeDB }), + }); + + return { + CurrentDeviceContext: { + _currentValue: { deviceId: 1234 }, }, - }), - useMessages: () => ({ - deleteAllMessages: mockDeleteAllMessages, - }), - useNodeDB: () => ({ - removeAllNodeErrors: mockRemoveAllNodeErrors, - removeAllNodes: mockRemoveAllNodes, - }), + useDevice: () => ({ + id: 42, + connection: { factoryResetDevice: mockFactoryResetDevice }, + }), + useDeviceStore, + useMessageStore, + useNodeDBStore, + }; +}); + +vi.mock("@core/hooks/useToast.ts", () => ({ + toast: (...args: unknown[]) => mockToast(...args), })); describe("FactoryResetDeviceDialog", () => { @@ -31,10 +43,11 @@ describe("FactoryResetDeviceDialog", () => { beforeEach(() => { mockOnOpenChange.mockClear(); - mockFactoryResetDevice.mockClear(); - mockDeleteAllMessages.mockClear(); - mockRemoveAllNodeErrors.mockClear(); - mockRemoveAllNodes.mockClear(); + mockFactoryResetDevice.mockReset(); + mockRemoveDevice.mockClear(); + mockRemoveMessageStore.mockClear(); + mockRemoveNodeDB.mockClear(); + mockToast.mockClear(); }); it("calls factoryResetDevice, closes dialog, and after reset resolves clears messages and node DB", async () => { @@ -61,20 +74,12 @@ describe("FactoryResetDeviceDialog", () => { expect(mockOnOpenChange).toHaveBeenCalledWith(false); }); - // Nothing else should have happened yet (the promise hasn't resolved) - expect(mockDeleteAllMessages).not.toHaveBeenCalled(); - expect(mockRemoveAllNodeErrors).not.toHaveBeenCalled(); - expect(mockRemoveAllNodes).not.toHaveBeenCalled(); - // Resolve the reset resolveReset?.(); - // Now the .then() chain should fire - await waitFor(() => { - expect(mockDeleteAllMessages).toHaveBeenCalledTimes(1); - expect(mockRemoveAllNodeErrors).toHaveBeenCalledTimes(1); - expect(mockRemoveAllNodes).toHaveBeenCalledTimes(1); - }); + expect(mockRemoveDevice).toHaveBeenCalledTimes(1); + expect(mockRemoveMessageStore).toHaveBeenCalledTimes(1); + expect(mockRemoveNodeDB).toHaveBeenCalledTimes(1); }); it("calls onOpenChange(false) and does not call factoryResetDevice when cancel is clicked", async () => { @@ -87,8 +92,8 @@ describe("FactoryResetDeviceDialog", () => { }); expect(mockFactoryResetDevice).not.toHaveBeenCalled(); - expect(mockDeleteAllMessages).not.toHaveBeenCalled(); - expect(mockRemoveAllNodeErrors).not.toHaveBeenCalled(); - expect(mockRemoveAllNodes).not.toHaveBeenCalled(); + expect(mockRemoveDevice).not.toHaveBeenCalled(); + expect(mockRemoveMessageStore).not.toHaveBeenCalled(); + expect(mockRemoveNodeDB).not.toHaveBeenCalled(); }); }); diff --git a/packages/web/src/components/Dialog/FactoryResetDeviceDialog/FactoryResetDeviceDialog.tsx b/packages/web/src/components/Dialog/FactoryResetDeviceDialog/FactoryResetDeviceDialog.tsx index a261a025f..e171c8ba9 100644 --- a/packages/web/src/components/Dialog/FactoryResetDeviceDialog/FactoryResetDeviceDialog.tsx +++ b/packages/web/src/components/Dialog/FactoryResetDeviceDialog/FactoryResetDeviceDialog.tsx @@ -1,5 +1,10 @@ import { toast } from "@core/hooks/useToast.ts"; -import { useDevice, useMessages, useNodeDB } from "@core/stores"; +import { + useDevice, + useDeviceStore, + useMessageStore, + useNodeDBStore, +} from "@core/stores"; import { useTranslation } from "react-i18next"; import { DialogWrapper } from "../DialogWrapper.tsx"; @@ -13,24 +18,24 @@ export const FactoryResetDeviceDialog = ({ onOpenChange, }: FactoryResetDeviceDialogProps) => { const { t } = useTranslation("dialog"); - const { connection } = useDevice(); - const { removeAllNodeErrors, removeAllNodes } = useNodeDB(); - const { deleteAllMessages } = useMessages(); + const { connection, id } = useDevice(); const handleFactoryResetDevice = () => { - connection - ?.factoryResetDevice() - .then(() => { - deleteAllMessages(); - removeAllNodeErrors(); - removeAllNodes(); - }) - .catch((error) => { - toast({ - title: t("factoryResetDevice.failedTitle"), - }); - console.error("Failed to factory reset device:", error); + connection?.factoryResetDevice().catch((error) => { + toast({ + title: t("factoryResetDevice.failedTitle"), }); + console.error("Failed to factory reset device:", error); + }); + + // The device will be wiped and disconnected without resolving the promise + // so we proceed to clear all data associated with the device immediately + useDeviceStore.getState().removeDevice(id); + useMessageStore.getState().removeMessageStore(id); + useNodeDBStore.getState().removeNodeDB(id); + + // Reload the app to ensure all ephemeral state is cleared + window.location.href = "/"; }; return ( diff --git a/packages/web/src/components/Dialog/ImportDialog.tsx b/packages/web/src/components/Dialog/ImportDialog.tsx index 7b2fb8fde..aea9bf74f 100644 --- a/packages/web/src/components/Dialog/ImportDialog.tsx +++ b/packages/web/src/components/Dialog/ImportDialog.tsx @@ -33,7 +33,7 @@ export interface ImportDialogProps { } export const ImportDialog = ({ open, onOpenChange }: ImportDialogProps) => { - const { config, channels } = useDevice(); + const { setChange, channels, config } = useDevice(); const { t } = useTranslation("dialog"); const [importDialogInput, setImportDialogInput] = useState(""); const [channelSet, setChannelSet] = useState(); @@ -41,8 +41,6 @@ export const ImportDialog = ({ open, onOpenChange }: ImportDialogProps) => { const [updateConfig, setUpdateConfig] = useState(true); const [importIndex, setImportIndex] = useState([]); - const { setWorkingChannelConfig, setWorkingConfig } = useDevice(); - useEffect(() => { // the channel information is contained in the URL's fragment, which will be present after a // non-URL encoded `#`. @@ -106,7 +104,11 @@ export const ImportDialog = ({ open, onOpenChange }: ImportDialogProps) => { true, ) ) { - setWorkingChannelConfig(payload); + setChange( + { type: "channels", index: importIndex[index] ?? 0 }, + payload, + channels.get(importIndex[index] ?? 0), + ); } }, ); @@ -118,14 +120,7 @@ export const ImportDialog = ({ open, onOpenChange }: ImportDialogProps) => { }; if (!deepCompareConfig(config.lora, payload, true)) { - setWorkingConfig( - create(Protobuf.Config.ConfigSchema, { - payloadVariant: { - case: "lora", - value: payload, - }, - }), - ); + setChange({ type: "config", variant: "lora" }, payload, config.lora); } } // Reset state after import diff --git a/packages/web/src/components/Dialog/PKIBackupDialog.tsx b/packages/web/src/components/Dialog/PKIBackupDialog.tsx index df68b59d1..2c19721e2 100644 --- a/packages/web/src/components/Dialog/PKIBackupDialog.tsx +++ b/packages/web/src/components/Dialog/PKIBackupDialog.tsx @@ -94,7 +94,11 @@ export const PkiBackupDialog = ({ const decodedPublicKey = decodeKeyData(publicKey); const formattedContent = [ - `${t("pkiBackup.header")}\n\n`, + `${t("pkiBackup.header", { + interpolation: { escapeValue: false }, + shortName: getMyNode()?.user?.shortName ?? t("unknown.shortName"), + longName: getMyNode()?.user?.longName ?? t("unknown.longName"), + })}\n\n`, `${t("pkiBackup.privateKey")}\n`, decodedPrivateKey, `\n\n${t("pkiBackup.publicKey")}\n`, diff --git a/packages/web/src/components/Form/FormMultiSelect.tsx b/packages/web/src/components/Form/FormMultiSelect.tsx index aa999439f..6558a325d 100644 --- a/packages/web/src/components/Form/FormMultiSelect.tsx +++ b/packages/web/src/components/Form/FormMultiSelect.tsx @@ -25,7 +25,7 @@ export function MultiSelectInput({ isDirty, invalid, }: GenericFormElementProps>) { - const { t } = useTranslation("deviceConfig"); + const { t } = useTranslation("config"); const { enumValue, className, ...remainingProperties } = field.properties; const isNewConfigStructure = diff --git a/packages/web/src/components/LanguageSwitcher.tsx b/packages/web/src/components/LanguageSwitcher.tsx index 8dfc63773..d41ff03af 100644 --- a/packages/web/src/components/LanguageSwitcher.tsx +++ b/packages/web/src/components/LanguageSwitcher.tsx @@ -1,6 +1,7 @@ -import { type LangCode, supportedLanguages } from "@app/i18n-config.ts"; +import type { LangCode } from "@app/i18n-config.ts"; import useLang from "@core/hooks/useLang.ts"; import { cn } from "@core/utils/cn.ts"; +import { t } from "i18next"; import { Check, Languages } from "lucide-react"; import { useCallback } from "react"; import { useTranslation } from "react-i18next"; @@ -21,7 +22,7 @@ export default function LanguageSwitcher({ disableHover = false, }: LanguageSwitcherProps) { const { i18n } = useTranslation("ui"); - const { set: setLanguage, currentLanguage } = useLang(); + const { set: setLanguage, current, getSupportedLangs } = useLang(); const handleLanguageChange = useCallback( async (languageCode: LangCode) => { @@ -56,7 +57,7 @@ export default function LanguageSwitcher({ "group-hover:text-gray-800 dark:group-hover:text-gray-100", )} > - {`${i18n.t("language.changeLanguage")}:`} + {`${t("languagePicker.label")}:`} - {currentLanguage?.name} + {current?.name} - {supportedLanguages.map((language) => ( + {getSupportedLangs.map((language) => ( handleLanguageChange(language.code)} diff --git a/packages/web/src/components/Map.tsx b/packages/web/src/components/Map.tsx index c0ced8814..0300a96c3 100644 --- a/packages/web/src/components/Map.tsx +++ b/packages/web/src/components/Map.tsx @@ -15,6 +15,11 @@ interface MapProps { onMouseMove?: (event: MapLayerMouseEvent) => void; onClick?: (event: MapLayerMouseEvent) => void; interactiveLayerIds?: string[]; + initialViewState?: { + latitude?: number; + longitude?: number; + zoom?: number; + }; } export const BaseMap = ({ @@ -23,6 +28,7 @@ export const BaseMap = ({ onClick, onMouseMove, interactiveLayerIds, + initialViewState, }: MapProps) => { const { theme } = useTheme(); const { t } = useTranslation("map"); @@ -67,11 +73,13 @@ export const BaseMap = ({ maxPitch={0} dragRotate={false} touchZoomRotate={false} - initialViewState={{ - zoom: 1.8, - latitude: 35, - longitude: 0, - }} + initialViewState={ + initialViewState ?? { + zoom: 1.8, + latitude: 35, + longitude: 0, + } + } style={{ filter: darkMode ? "brightness(0.9)" : undefined }} locale={locale} interactiveLayerIds={interactiveLayerIds} diff --git a/packages/web/src/components/PageComponents/ChannelConfig/Channel.tsx b/packages/web/src/components/PageComponents/Channels/Channel.tsx similarity index 95% rename from packages/web/src/components/PageComponents/ChannelConfig/Channel.tsx rename to packages/web/src/components/PageComponents/Channels/Channel.tsx index 305dbacdd..deb81d5de 100644 --- a/packages/web/src/components/PageComponents/ChannelConfig/Channel.tsx +++ b/packages/web/src/components/PageComponents/Channels/Channel.tsx @@ -24,12 +24,7 @@ export interface SettingsPanelProps { } export const Channel = ({ onFormInit, channel }: SettingsPanelProps) => { - const { - config, - setWorkingChannelConfig, - getWorkingChannelConfig, - removeWorkingChannelConfig, - } = useDevice(); + const { config, setChange, getChange, removeChange } = useDevice(); const { t } = useTranslation(["channels", "ui", "dialog"]); const defaultConfig = channel; @@ -51,7 +46,11 @@ export const Channel = ({ onFormInit, channel }: SettingsPanelProps) => { }, }; - const effectiveConfig = getWorkingChannelConfig(channel.index) ?? channel; + const workingChannel = getChange({ + type: "channels", + index: channel.index, + }) as Protobuf.Channel.Channel | undefined; + const effectiveConfig = workingChannel ?? channel; const formValues = { ...effectiveConfig, ...{ @@ -111,7 +110,7 @@ export const Channel = ({ onFormInit, channel }: SettingsPanelProps) => { return; } - const payload = { + const payload = create(Protobuf.Channel.ChannelSchema, { ...data, settings: { ...data.settings, @@ -121,14 +120,14 @@ export const Channel = ({ onFormInit, channel }: SettingsPanelProps) => { positionPrecision: data.settings.moduleSettings.positionPrecision, }), }, - }; + }); if (deepCompareConfig(channel, payload, true)) { - removeWorkingChannelConfig(channel.index); + removeChange({ type: "channel", index: channel.index }); return; } - setWorkingChannelConfig(create(Protobuf.Channel.ChannelSchema, payload)); + setChange({ type: "channel", index: channel.index }, payload, channel); }; const preSharedKeyRegenerate = async () => { diff --git a/packages/web/src/pages/Config/ChannelConfig.tsx b/packages/web/src/components/PageComponents/Channels/Channels.tsx similarity index 89% rename from packages/web/src/pages/Config/ChannelConfig.tsx rename to packages/web/src/components/PageComponents/Channels/Channels.tsx index 7ec004fd5..ad8edfd1b 100644 --- a/packages/web/src/pages/Config/ChannelConfig.tsx +++ b/packages/web/src/components/PageComponents/Channels/Channels.tsx @@ -1,4 +1,4 @@ -import { Channel } from "@app/components/PageComponents/ChannelConfig/Channel"; +import { Channel } from "@app/components/PageComponents/Channels/Channel"; import { Button } from "@components/UI/Button.tsx"; import { Spinner } from "@components/UI/Spinner.tsx"; import { @@ -30,8 +30,8 @@ export const getChannelName = (channel: Protobuf.Channel.Channel) => { }); }; -export const ChannelConfig = ({ onFormInit }: ConfigProps) => { - const { channels, getWorkingChannelConfig, setDialogOpen } = useDevice(); +export const Channels = ({ onFormInit }: ConfigProps) => { + const { channels, hasChannelChange, setDialogOpen } = useDevice(); const { t } = useTranslation("channels"); const allChannels = Array.from(channels.values()); @@ -40,10 +40,10 @@ export const ChannelConfig = ({ onFormInit }: ConfigProps) => { new Map( allChannels.map((channel) => [ channel.index, - getWorkingChannelConfig(channel.index), + hasChannelChange(channel.index), ]), ), - [allChannels, getWorkingChannelConfig], + [allChannels, hasChannelChange], ); return ( diff --git a/packages/web/src/components/PageComponents/Connect/BLE.tsx b/packages/web/src/components/PageComponents/Connect/BLE.tsx deleted file mode 100644 index 21e322386..000000000 --- a/packages/web/src/components/PageComponents/Connect/BLE.tsx +++ /dev/null @@ -1,104 +0,0 @@ -import { Mono } from "@components/generic/Mono.tsx"; -import { Button } from "@components/UI/Button.tsx"; -import { - useAppStore, - useDeviceStore, - useMessageStore, - useNodeDBStore, -} from "@core/stores"; -import { subscribeAll } from "@core/subscriptions.ts"; -import { randId } from "@core/utils/randId.ts"; -import { MeshDevice } from "@meshtastic/core"; -import { TransportWebBluetooth } from "@meshtastic/transport-web-bluetooth"; -import { useCallback, useEffect, useState } from "react"; -import { useTranslation } from "react-i18next"; -import type { TabElementProps } from "../../Dialog/NewDeviceDialog.tsx"; - -export const BLE = ({ closeDialog }: TabElementProps) => { - const [connectionInProgress, setConnectionInProgress] = useState(false); - const [bleDevices, setBleDevices] = useState([]); - - const { addDevice } = useDeviceStore(); - const { addNodeDB } = useNodeDBStore(); - const { addMessageStore } = useMessageStore(); - const { setSelectedDevice } = useAppStore(); - const { t } = useTranslation(); - - const updateBleDeviceList = useCallback(async (): Promise => { - setBleDevices(await navigator.bluetooth.getDevices()); - }, []); - - useEffect(() => { - updateBleDeviceList(); - }, [updateBleDeviceList]); - - const onConnect = async (bleDevice: BluetoothDevice) => { - const id = randId(); - const transport = await TransportWebBluetooth.createFromDevice(bleDevice); - const device = addDevice(id); - const nodeDB = addNodeDB(id); - const messageStore = addMessageStore(id); - - const connection = new MeshDevice(transport, id); - connection.configure(); - setSelectedDevice(id); - device.addConnection(connection); - subscribeAll(device, connection, messageStore, nodeDB); - - const HEARTBEAT_INTERVAL = 5 * 60 * 1000; - connection.setHeartbeatInterval(HEARTBEAT_INTERVAL); - - closeDialog(); - }; - - return ( -
-
- {bleDevices.map((device) => ( - - ))} - {bleDevices.length === 0 && ( - - {t("newDeviceDialog.bluetoothConnection.noDevicesPaired")} - - )} -
- -
- ); -}; diff --git a/packages/web/src/components/PageComponents/Connect/HTTP.test.tsx b/packages/web/src/components/PageComponents/Connect/HTTP.test.tsx deleted file mode 100644 index 340400023..000000000 --- a/packages/web/src/components/PageComponents/Connect/HTTP.test.tsx +++ /dev/null @@ -1,103 +0,0 @@ -import { HTTP } from "@components/PageComponents/Connect/HTTP.tsx"; -import { MeshDevice } from "@meshtastic/core"; -import { TransportHTTP } from "@meshtastic/transport-http"; -import { fireEvent, render, screen, waitFor } from "@testing-library/react"; -import { describe, expect, it, vi } from "vitest"; - -vi.mock("@core/stores", () => ({ - useAppStore: vi.fn(() => ({ setSelectedDevice: vi.fn() })), - useDeviceStore: vi.fn(() => ({ - addDevice: vi.fn(() => ({ addConnection: vi.fn() })), - })), - useMessageStore: vi.fn(() => ({ - addMessageStore: vi.fn(), - })), - useNodeDBStore: vi.fn(() => ({ - addNodeDB: vi.fn(), - })), -})); - -vi.mock("@core/utils/randId.ts", () => ({ - randId: vi.fn(() => "mock-id"), -})); - -vi.mock("@meshtastic/transport-http", () => ({ - TransportHTTP: { - create: vi.fn(() => Promise.resolve({})), - }, -})); - -vi.mock("@meshtastic/core", () => ({ - MeshDevice: vi.fn(() => ({ - configure: vi.fn(), - })), -})); - -describe("HTTP Component", () => { - it("renders correctly", () => { - render(); - expect(screen.getByText("IP Address/Hostname")).toBeInTheDocument(); - expect(screen.getByRole("textbox")).toBeInTheDocument(); - expect( - screen.getByPlaceholderText("000.000.000.000 / meshtastic.local"), - ).toBeInTheDocument(); - expect(screen.getByText("Use HTTPS")).toBeInTheDocument(); - expect(screen.getByRole("button", { name: "Connect" })).toBeInTheDocument(); - }); - - it("allows input field to be updated", () => { - render(); - const inputField = screen.getByRole("textbox"); - fireEvent.change(inputField, { target: { value: "meshtastic.local" } }); - expect( - screen.getByPlaceholderText("000.000.000.000 / meshtastic.local"), - ).toBeInTheDocument(); - }); - - it("toggles HTTPS switch and updates prefix", () => { - render(); - - const switchInput = screen.getByRole("switch"); - expect(screen.getByText("http://")).toBeInTheDocument(); - - fireEvent.click(switchInput); - expect(screen.getByText("https://")).toBeInTheDocument(); - - fireEvent.click(switchInput); - expect(switchInput).not.toBeChecked(); - expect(screen.getByText("http://")).toBeInTheDocument(); - }); - - it("enables HTTPS toggle when location protocol is https", () => { - Object.defineProperty(window, "location", { - value: { protocol: "https:" }, - writable: true, - }); - - render(); - - const switchInput = screen.getByRole("switch"); - expect(switchInput).toBeChecked(); - - expect(screen.getByText("https://")).toBeInTheDocument(); - }); - - it.skip("submits form and triggers connection process", async () => { - const closeDialog = vi.fn(); - render(); - const button = screen.getByRole("button", { name: "Connect" }); - expect(button).not.toBeDisabled(); - - try { - fireEvent.click(button); - await waitFor(() => { - expect(button).toBeDisabled(); - expect(closeDialog).toBeCalled(); - expect(TransportHTTP.create).toBeCalled(); - expect(MeshDevice).toBeCalled(); - }); - } catch (e) { - console.error(e); - } - }); -}); diff --git a/packages/web/src/components/PageComponents/Connect/HTTP.tsx b/packages/web/src/components/PageComponents/Connect/HTTP.tsx deleted file mode 100644 index ebc24a772..000000000 --- a/packages/web/src/components/PageComponents/Connect/HTTP.tsx +++ /dev/null @@ -1,172 +0,0 @@ -import type { TabElementProps } from "@components/Dialog/NewDeviceDialog.tsx"; -import { Button } from "@components/UI/Button.tsx"; -import { Input } from "@components/UI/Input.tsx"; -import { Label } from "@components/UI/Label.tsx"; -import { Switch } from "@components/UI/Switch.tsx"; -import { Link } from "@components/UI/Typography/Link.tsx"; -import { - useAppStore, - useDeviceStore, - useMessageStore, - useNodeDBStore, -} from "@core/stores"; -import { subscribeAll } from "@core/subscriptions.ts"; -import { randId } from "@core/utils/randId.ts"; -import { MeshDevice } from "@meshtastic/core"; -import { TransportHTTP } from "@meshtastic/transport-http"; -import { AlertTriangle } from "lucide-react"; -import { useState } from "react"; -import { useController, useForm } from "react-hook-form"; -import { useTranslation } from "react-i18next"; - -interface FormData { - ip: string; - tls: boolean; -} - -export const HTTP = ({ closeDialog }: TabElementProps) => { - const { t } = useTranslation("dialog"); - const [connectionInProgress, setConnectionInProgress] = useState(false); - const isURLHTTPS = location.protocol === "https:"; - - const { addDevice } = useDeviceStore(); - const { addNodeDB } = useNodeDBStore(); - const { addMessageStore } = useMessageStore(); - const { setSelectedDevice } = useAppStore(); - - const { control, handleSubmit, register } = useForm({ - defaultValues: { - ip: ["client.meshtastic.org", "localhost"].includes( - globalThis.location.hostname, - ) - ? "meshtastic.local" - : globalThis.location.host, - tls: !!isURLHTTPS, - }, - }); - - const { - field: { value: tlsValue, onChange: setTLS }, - } = useController({ name: "tls", control }); - - const [connectionError, setConnectionError] = useState<{ - host: string; - secure: boolean; - } | null>(null); - - const onSubmit = handleSubmit(async (data) => { - setConnectionInProgress(true); - setConnectionError(null); - - try { - const id = randId(); - const transport = await TransportHTTP.create(data.ip, data.tls); - const device = addDevice(id); - const nodeDB = addNodeDB(id); - const messageStore = addMessageStore(id); - - const connection = new MeshDevice(transport, id); - connection.configure(); - setSelectedDevice(id); - device.addConnection(connection); - subscribeAll(device, connection, messageStore, nodeDB); - closeDialog(); - } catch (error) { - if (error instanceof Error) { - console.error("Connection error:", error); - } - // Capture all connection errors regardless of type - setConnectionError({ host: data.ip, secure: data.tls }); - setConnectionInProgress(false); - } - }); - - return ( -
-
-
- - -
-
- - -
- - {connectionError && ( -
-
- -
-

- {t("newDeviceDialog.connectionFailedAlert.title")} -

-

- {t("newDeviceDialog.connectionFailedAlert.descriptionPrefix")} - {connectionError.secure && - t("newDeviceDialog.connectionFailedAlert.httpsHint")} - {t("newDeviceDialog.connectionFailedAlert.openLinkPrefix")} - - {`${ - connectionError.secure - ? t("newDeviceDialog.https") - : t("newDeviceDialog.http") - }://${connectionError.host}`} - {" "} - {t("newDeviceDialog.connectionFailedAlert.openLinkSuffix")} - {connectionError.secure - ? t( - "newDeviceDialog.connectionFailedAlert.acceptTlsWarningSuffix", - ) - : ""} - .{" "} - - {t("newDeviceDialog.connectionFailedAlert.learnMoreLink")} - -

-
-
-
- )} -
- -
- ); -}; diff --git a/packages/web/src/components/PageComponents/Connect/Serial.tsx b/packages/web/src/components/PageComponents/Connect/Serial.tsx deleted file mode 100644 index 477ded030..000000000 --- a/packages/web/src/components/PageComponents/Connect/Serial.tsx +++ /dev/null @@ -1,116 +0,0 @@ -import { Mono } from "@components/generic/Mono.tsx"; -import { Button } from "@components/UI/Button.tsx"; -import { - useAppStore, - useDeviceStore, - useMessageStore, - useNodeDBStore, -} from "@core/stores"; -import { subscribeAll } from "@core/subscriptions.ts"; -import { randId } from "@core/utils/randId.ts"; -import { MeshDevice } from "@meshtastic/core"; -import { TransportWebSerial } from "@meshtastic/transport-web-serial"; -import { useCallback, useEffect, useState } from "react"; -import { useTranslation } from "react-i18next"; -import type { TabElementProps } from "../../Dialog/NewDeviceDialog.tsx"; - -export const Serial = ({ closeDialog }: TabElementProps) => { - const [connectionInProgress, setConnectionInProgress] = useState(false); - const [serialPorts, setSerialPorts] = useState([]); - - const { addDevice } = useDeviceStore(); - const { addNodeDB } = useNodeDBStore(); - const { addMessageStore } = useMessageStore(); - const { setSelectedDevice } = useAppStore(); - const { t } = useTranslation(); - - const updateSerialPortList = useCallback(async () => { - setSerialPorts(await navigator.serial.getPorts()); - }, []); - - navigator.serial.addEventListener("connect", () => { - updateSerialPortList(); - }); - navigator.serial.addEventListener("disconnect", () => { - updateSerialPortList(); - }); - useEffect(() => { - updateSerialPortList(); - }, [updateSerialPortList]); - - const onConnect = async (port: SerialPort) => { - const id = randId(); - const device = addDevice(id); - const nodeDB = addNodeDB(id); - const messageStore = addMessageStore(id); - - setSelectedDevice(id); - const transport = await TransportWebSerial.createFromPort(port); - const connection = new MeshDevice(transport, id); - connection.configure(); - device.addConnection(connection); - subscribeAll(device, connection, messageStore, nodeDB); - - const HEARTBEAT_INTERVAL = 5 * 60 * 1000; - connection.setHeartbeatInterval(HEARTBEAT_INTERVAL); - - closeDialog(); - }; - - return ( -
-
- {serialPorts.map((port, idx) => { - const { usbProductId, usbVendorId } = port.getInfo(); - const vendor = usbVendorId ?? t("unknown.shortName"); - const product = usbProductId ?? t("unknown.shortName"); - return ( - - ); - })} - {serialPorts.length === 0 && ( - - {t("newDeviceDialog.serialConnection.noDevicesPaired")} - - )} -
- -
- ); -}; diff --git a/packages/web/src/components/PageComponents/Connections/ConnectionStatusBadge.tsx b/packages/web/src/components/PageComponents/Connections/ConnectionStatusBadge.tsx new file mode 100644 index 000000000..cc42a258d --- /dev/null +++ b/packages/web/src/components/PageComponents/Connections/ConnectionStatusBadge.tsx @@ -0,0 +1,42 @@ +import { Button } from "@app/components/UI/Button"; +import type { Connection } from "@app/core/stores/deviceStore/types"; + +export function ConnectionStatusBadge({ + status, +}: { + status: Connection["status"]; +}) { + let color = ""; + let displayStatus = status; + + switch (status) { + case "connected": + case "configured": + color = "bg-emerald-500"; + displayStatus = "connected"; + break; + case "connecting": + case "configuring": + color = "bg-amber-500"; + break; + case "online": + color = "bg-blue-500"; + break; + case "error": + color = "bg-red-500"; + break; + default: + color = "bg-gray-400"; + } + return ( + + ); +} diff --git a/packages/web/src/components/PageComponents/Map/Layers/HeatmapLayer.tsx b/packages/web/src/components/PageComponents/Map/Layers/HeatmapLayer.tsx new file mode 100644 index 000000000..e4ba7467d --- /dev/null +++ b/packages/web/src/components/PageComponents/Map/Layers/HeatmapLayer.tsx @@ -0,0 +1,103 @@ +import { hasPos, toLngLat } from "@core/utils/geo"; +import type { Protobuf } from "@meshtastic/core"; +import type { Feature, FeatureCollection } from "geojson"; +import type { HeatmapLayerSpecification } from "maplibre-gl"; +import { useMemo } from "react"; +import { Layer, Source } from "react-map-gl/maplibre"; + +export type HeatmapMode = "density" | "snr"; + +export interface HeatmapLayerProps { + id: string; + filteredNodes: Protobuf.Mesh.NodeInfo[]; + mode: HeatmapMode; +} + +export const HeatmapLayer = ({ + id, + filteredNodes, + mode, +}: HeatmapLayerProps) => { + const data: FeatureCollection = useMemo(() => { + const features: Feature[] = filteredNodes + .filter((node) => hasPos(node.position)) + .filter((node) => mode !== "snr" || node.snr !== undefined) + .map((node) => ({ + type: "Feature", + geometry: { + type: "Point", + coordinates: toLngLat(node.position), + }, + properties: { + snr: node.snr, + name: node.user?.longName, + shortName: node.user?.shortName, + num: node.num, + }, + })); + + return { + type: "FeatureCollection", + features, + }; + }, [filteredNodes, mode]); + + const paintProps: HeatmapLayerSpecification["paint"] = useMemo( + () => ({ + "heatmap-weight": + mode === "density" + ? 1 + : ["interpolate", ["linear"], ["get", "snr"], -20, 0, 10, 1], + "heatmap-intensity": ["interpolate", ["linear"], ["zoom"], 0, 1, 15, 3], + // Color ramp for heatmap. Domain is 0 (low) to 1 (high). + // Begin color ramp at 0-stop with a 0-transparancy color + // to create a blur-like effect. + "heatmap-color": [ + "interpolate", + ["linear"], + ["heatmap-density"], + 0, + "rgba(33,102,172,0)", + 0.2, + "rgb(103,169,207)", + 0.4, + "rgb(209,229,240)", + 0.6, + "rgb(253,219,199)", + 0.8, + "rgb(239,138,98)", + 1, + "rgb(178,24,43)", + ], + "heatmap-radius": [ + "interpolate", + ["linear"], + ["zoom"], + 0, + 2, + 9, + 20, + 15, + 30, + ], + // Opacity 0.7 to be visible but not blocking + "heatmap-opacity": 0.7, + }), + [mode], + ); + + return ( + + + + + ); +}; diff --git a/packages/web/src/components/PageComponents/Map/Layers/PrecisionLayer.tsx b/packages/web/src/components/PageComponents/Map/Layers/PrecisionLayer.tsx index dd0ebca1f..22b8d0241 100644 --- a/packages/web/src/components/PageComponents/Map/Layers/PrecisionLayer.tsx +++ b/packages/web/src/components/PageComponents/Map/Layers/PrecisionLayer.tsx @@ -1,7 +1,6 @@ -import { getColorFromText, isLightColor } from "@app/core/utils/color"; +import { getColorFromNodeNum, isLightColor } from "@app/core/utils/color"; import { precisionBitsToMeters, toLngLat } from "@core/utils/geo.ts"; import type { Protobuf } from "@meshtastic/core"; -import { numberToHexUnpadded } from "@noble/curves/abstract/utils"; import { circle } from "@turf/turf"; import type { Feature, FeatureCollection, Polygon } from "geojson"; import { Layer, Source } from "react-map-gl/maplibre"; @@ -46,10 +45,7 @@ export function generatePrecisionCircles( const [lng, lat] = toLngLat(node.position); const radiusM = precisionBitsToMeters(node.position?.precisionBits ?? 0); - const safeText = - node.user?.shortName ?? - numberToHexUnpadded(node.num).slice(-4).toUpperCase(); - const color = getColorFromText(safeText); + const color = getColorFromNodeNum(node.num); const isLight = isLightColor(color); const key = `${lat},${lng}:${radiusM}`; diff --git a/packages/web/src/components/PageComponents/Map/Layers/SNRLayer.tsx b/packages/web/src/components/PageComponents/Map/Layers/SNRLayer.tsx index febb3a3cd..c361fcda1 100644 --- a/packages/web/src/components/PageComponents/Map/Layers/SNRLayer.tsx +++ b/packages/web/src/components/PageComponents/Map/Layers/SNRLayer.tsx @@ -268,8 +268,12 @@ export const SNRTooltip = ({ >
{from ?? ""} - - {to ?? ""} + {to && ( + <> + + {to ?? ""} + + )}
SNR: {snr?.toFixed?.(2) ?? t("unknown.shortName")} dB diff --git a/packages/web/src/components/PageComponents/Map/Markers/NodeMarker.tsx b/packages/web/src/components/PageComponents/Map/Markers/NodeMarker.tsx index c5dade90b..1e358c8d3 100644 --- a/packages/web/src/components/PageComponents/Map/Markers/NodeMarker.tsx +++ b/packages/web/src/components/PageComponents/Map/Markers/NodeMarker.tsx @@ -16,7 +16,6 @@ export const NodeMarker = memo(function NodeMarker({ id, lng, lat, - label, longLabel, tooltipLabel, hasError, @@ -68,7 +67,7 @@ export const NodeMarker = memo(function NodeMarker({ onClick={(e) => onClick(id, { originalEvent: e.nativeEvent })} > {
- +
{ diff --git a/packages/web/src/components/PageComponents/Map/Popups/WaypointDetail.tsx b/packages/web/src/components/PageComponents/Map/Popups/WaypointDetail.tsx index 68a1479e5..20c3c0eef 100644 --- a/packages/web/src/components/PageComponents/Map/Popups/WaypointDetail.tsx +++ b/packages/web/src/components/PageComponents/Map/Popups/WaypointDetail.tsx @@ -172,7 +172,7 @@ export const WaypointDetail = ({ waypoint, myNode }: WaypointDetailProps) => { )} {/* Locked To */} - {waypoint.lockedTo && ( + {waypoint.lockedTo != null && waypoint.lockedTo !== 0 && (
diff --git a/packages/web/src/components/PageComponents/Map/Tools/MapLayerTool.tsx b/packages/web/src/components/PageComponents/Map/Tools/MapLayerTool.tsx index 9a3557ffe..3b9b1cef7 100644 --- a/packages/web/src/components/PageComponents/Map/Tools/MapLayerTool.tsx +++ b/packages/web/src/components/PageComponents/Map/Tools/MapLayerTool.tsx @@ -1,3 +1,4 @@ +import type { HeatmapMode } from "@components/PageComponents/Map/Layers/HeatmapLayer.tsx"; import { Checkbox } from "@components/UI/Checkbox/index.tsx"; import { Popover, @@ -6,7 +7,7 @@ import { } from "@components/UI/Popover.tsx"; import { cn } from "@core/utils/cn.ts"; import { LayersIcon } from "lucide-react"; -import type { ReactNode } from "react"; +import { type ReactNode, useMemo } from "react"; import { useTranslation } from "react-i18next"; export interface VisibilityState { @@ -16,6 +17,7 @@ export interface VisibilityState { positionPrecision: boolean; traceroutes: boolean; waypoints: boolean; + heatmap: boolean; } export const defaultVisibilityState: VisibilityState = { @@ -25,11 +27,14 @@ export const defaultVisibilityState: VisibilityState = { positionPrecision: false, traceroutes: false, waypoints: true, + heatmap: false, }; interface MapLayerToolProps { visibilityState: VisibilityState; setVisibilityState: (state: VisibilityState) => void; + heatmapMode: HeatmapMode; + setHeatmapMode: (mode: HeatmapMode) => void; } interface CheckboxProps { @@ -59,16 +64,55 @@ const CheckboxItem = ({ export function MapLayerTool({ visibilityState, setVisibilityState, + heatmapMode, + setHeatmapMode, }: MapLayerToolProps): ReactNode { const { t } = useTranslation("map"); + const enabledCount = useMemo(() => { + return Object.values(visibilityState).filter(Boolean).length; + }, [visibilityState]); + + const handleCheckboxChange = (key: keyof VisibilityState) => { + if (key === "heatmap" && !visibilityState.heatmap) { + // If turning heatmap on, turn everything else off so the layer is visible + setVisibilityState({ + nodeMarkers: false, + directNeighbors: false, + remoteNeighbors: false, + positionPrecision: false, + traceroutes: false, + waypoints: false, + heatmap: true, + }); + } else { + setVisibilityState({ + ...visibilityState, + [key]: !visibilityState[key], + }); + } + }; + + const layers = useMemo( + () => [ + { key: "nodeMarkers", label: t("layerTool.nodeMarkers") }, + { key: "waypoints", label: t("layerTool.waypoints") }, + { key: "directNeighbors", label: t("layerTool.directNeighbors") }, + { key: "remoteNeighbors", label: t("layerTool.remoteNeighbors") }, + { key: "positionPrecision", label: t("layerTool.positionPrecision") }, + { key: "heatmap", label: t("layerTool.heatmap") }, + // { key: "traceroutes", label: t("layerTool.traceroutes") }, + ], + [t], + ); + return ( - { - setVisibilityState({ ...visibilityState, nodeMarkers: checked }); - }} - /> - { - setVisibilityState({ ...visibilityState, waypoints: checked }); - }} - /> - { - setVisibilityState({ - ...visibilityState, - directNeighbors: checked, - }); - }} - /> - { - setVisibilityState({ - ...visibilityState, - remoteNeighbors: checked, - }); - }} - /> - { - setVisibilityState({ - ...visibilityState, - positionPrecision: checked, - }); - }} - /> + {layers.map(({ key, label }) => ( +
+ + handleCheckboxChange(key as keyof VisibilityState) + } + /> + {key === "heatmap" && visibilityState.heatmap && ( +
+ + +
+ )} +
+ ))} {/* ( ); +const MessageSkeleton = () => { + console.log("[ChannelChat] Showing MessageSkeleton (Suspense fallback)"); + return ( +
  • +
    + +
    +
    + + +
    + +
    +
    +
  • + ); +}; + const EmptyState = () => { const { t } = useTranslation("messages"); return ( @@ -130,10 +149,12 @@ export const ChannelChat = ({ messages = [] }: ChannelChatProps) => { {/* Render messages first, then delimiter — with flex-col-reverse this shows the delimiter above that day's messages */} {items.map((message) => ( - + fallback={} + > + + ))} diff --git a/packages/web/src/components/PageComponents/Messages/MessageItem.tsx b/packages/web/src/components/PageComponents/Messages/MessageItem.tsx index acf89a632..16cd394c1 100644 --- a/packages/web/src/components/PageComponents/Messages/MessageItem.tsx +++ b/packages/web/src/components/PageComponents/Messages/MessageItem.tsx @@ -6,7 +6,7 @@ import { TooltipProvider, TooltipTrigger, } from "@components/UI/Tooltip.tsx"; -import { MessageState, useDevice, useNodeDB } from "@core/stores"; +import { MessageState, useAppStore, useDevice, useNodeDB } from "@core/stores"; import type { Message } from "@core/stores/messageStore/types.ts"; import { cn } from "@core/utils/cn.ts"; import { type Protobuf, Types } from "@meshtastic/core"; @@ -15,6 +15,50 @@ import { AlertCircle, CheckCircle2, CircleEllipsis } from "lucide-react"; import { type ReactNode, useMemo } from "react"; import { useTranslation } from "react-i18next"; +// Cache for pending promises +const myNodePromises = new Map>(); + +// Hook that suspends when myNode is not available +function useSuspendingMyNode() { + const { getMyNode } = useNodeDB(); + const selectedDeviceId = useAppStore((s) => s.selectedDeviceId); + const myNode = getMyNode(); + + if (!myNode) { + // Use the selected device ID to cache promises per device + const deviceKey = `device-${selectedDeviceId}`; + + if (!myNodePromises.has(deviceKey)) { + const promise = new Promise((resolve) => { + // Poll for myNode to become available + const checkInterval = setInterval(() => { + const node = getMyNode(); + if (node) { + console.log( + "[MessageItem] myNode now available, resolving promise", + ); + clearInterval(checkInterval); + myNodePromises.delete(deviceKey); + resolve(node); + } + }, 100); + + setTimeout(() => { + clearInterval(checkInterval); + myNodePromises.delete(deviceKey); + }, 10000); + }); + + myNodePromises.set(deviceKey, promise); + } + + // Throw the promise to trigger Suspense + throw myNodePromises.get(deviceKey); + } + + return myNode; +} + // import { MessageActionsMenu } from "@components/PageComponents/Messages/MessageActionsMenu.tsx"; // TODO: Uncomment when actions menu is implemented interface MessageStatusInfo { @@ -48,9 +92,13 @@ interface MessageItemProps { export const MessageItem = ({ message }: MessageItemProps) => { const { config } = useDevice(); - const { getNode, getMyNode } = useNodeDB(); + const { getNode } = useNodeDB(); const { t, i18n } = useTranslation("messages"); + // This will suspend if myNode is not available yet + const myNode = useSuspendingMyNode(); + const myNodeNum = myNode.num; + const MESSAGE_STATUS_MAP = useMemo( (): Record => ({ [MessageState.Ack]: { @@ -96,9 +144,7 @@ export const MessageItem = ({ message }: MessageItemProps) => { return message.from != null ? getNode(message.from) : null; }, [getNode, message.from]); - const myNodeNum = useMemo(() => getMyNode().num, [getMyNode]); - - const { displayName, shortName, isFavorite } = useMemo(() => { + const { displayName, isFavorite, nodeNum } = useMemo(() => { const userIdHex = message.from.toString(16).toUpperCase().padStart(2, "0"); const last4 = userIdHex.slice(-4); const fallbackName = t("fallbackName", { last4 }); @@ -111,6 +157,7 @@ export const MessageItem = ({ message }: MessageItemProps) => { displayName: derivedDisplayName, shortName: derivedShortName, isFavorite: isFavorite, + nodeNum: message.from, }; }, [messageUser, message.from, t, myNodeNum]); @@ -159,7 +206,7 @@ export const MessageItem = ({ message }: MessageItemProps) => {
    diff --git a/packages/web/src/components/PageComponents/ModuleConfig/AmbientLighting.tsx b/packages/web/src/components/PageComponents/ModuleConfig/AmbientLighting.tsx index 5ae258dd1..108b3796e 100644 --- a/packages/web/src/components/PageComponents/ModuleConfig/AmbientLighting.tsx +++ b/packages/web/src/components/PageComponents/ModuleConfig/AmbientLighting.tsx @@ -3,14 +3,12 @@ import { type AmbientLightingValidation, AmbientLightingValidationSchema, } from "@app/validation/moduleConfig/ambientLighting.ts"; -import { create } from "@bufbuild/protobuf"; import { DynamicForm, type DynamicFormFormInit, } from "@components/Form/DynamicForm.tsx"; import { useDevice } from "@core/stores"; import { deepCompareConfig } from "@core/utils/deepCompareConfig.ts"; -import { Protobuf } from "@meshtastic/core"; import { useTranslation } from "react-i18next"; interface AmbientLightingModuleConfigProps { @@ -21,27 +19,20 @@ export const AmbientLighting = ({ onFormInit, }: AmbientLightingModuleConfigProps) => { useWaitForConfig({ moduleConfigCase: "ambientLighting" }); - const { - moduleConfig, - setWorkingModuleConfig, - getEffectiveModuleConfig, - removeWorkingModuleConfig, - } = useDevice(); + const { moduleConfig, setChange, getEffectiveModuleConfig, removeChange } = + useDevice(); const { t } = useTranslation("moduleConfig"); const onSubmit = (data: AmbientLightingValidation) => { if (deepCompareConfig(moduleConfig.ambientLighting, data, true)) { - removeWorkingModuleConfig("ambientLighting"); + removeChange({ type: "moduleConfig", variant: "ambientLighting" }); return; } - setWorkingModuleConfig( - create(Protobuf.ModuleConfig.ModuleConfigSchema, { - payloadVariant: { - case: "ambientLighting", - value: data, - }, - }), + setChange( + { type: "moduleConfig", variant: "ambientLighting" }, + data, + moduleConfig.ambientLighting, ); }; diff --git a/packages/web/src/components/PageComponents/ModuleConfig/Audio.tsx b/packages/web/src/components/PageComponents/ModuleConfig/Audio.tsx index eb7068f28..067383236 100644 --- a/packages/web/src/components/PageComponents/ModuleConfig/Audio.tsx +++ b/packages/web/src/components/PageComponents/ModuleConfig/Audio.tsx @@ -3,7 +3,6 @@ import { type AudioValidation, AudioValidationSchema, } from "@app/validation/moduleConfig/audio.ts"; -import { create } from "@bufbuild/protobuf"; import { DynamicForm, type DynamicFormFormInit, @@ -19,27 +18,20 @@ interface AudioModuleConfigProps { export const Audio = ({ onFormInit }: AudioModuleConfigProps) => { useWaitForConfig({ moduleConfigCase: "audio" }); - const { - moduleConfig, - setWorkingModuleConfig, - getEffectiveModuleConfig, - removeWorkingModuleConfig, - } = useDevice(); + const { moduleConfig, setChange, getEffectiveModuleConfig, removeChange } = + useDevice(); const { t } = useTranslation("moduleConfig"); const onSubmit = (data: AudioValidation) => { if (deepCompareConfig(moduleConfig.audio, data, true)) { - removeWorkingModuleConfig("audio"); + removeChange({ type: "moduleConfig", variant: "audio" }); return; } - setWorkingModuleConfig( - create(Protobuf.ModuleConfig.ModuleConfigSchema, { - payloadVariant: { - case: "audio", - value: data, - }, - }), + setChange( + { type: "moduleConfig", variant: "audio" }, + data, + moduleConfig.audio, ); }; diff --git a/packages/web/src/components/PageComponents/ModuleConfig/CannedMessage.tsx b/packages/web/src/components/PageComponents/ModuleConfig/CannedMessage.tsx index 711c16575..402fbdfe1 100644 --- a/packages/web/src/components/PageComponents/ModuleConfig/CannedMessage.tsx +++ b/packages/web/src/components/PageComponents/ModuleConfig/CannedMessage.tsx @@ -3,7 +3,6 @@ import { type CannedMessageValidation, CannedMessageValidationSchema, } from "@app/validation/moduleConfig/cannedMessage.ts"; -import { create } from "@bufbuild/protobuf"; import { DynamicForm, type DynamicFormFormInit, @@ -22,27 +21,20 @@ export const CannedMessage = ({ }: CannedMessageModuleConfigProps) => { useWaitForConfig({ moduleConfigCase: "cannedMessage" }); - const { - moduleConfig, - setWorkingModuleConfig, - getEffectiveModuleConfig, - removeWorkingModuleConfig, - } = useDevice(); + const { moduleConfig, setChange, getEffectiveModuleConfig, removeChange } = + useDevice(); const { t } = useTranslation("moduleConfig"); const onSubmit = (data: CannedMessageValidation) => { if (deepCompareConfig(moduleConfig.cannedMessage, data, true)) { - removeWorkingModuleConfig("cannedMessage"); + removeChange({ type: "moduleConfig", variant: "cannedMessage" }); return; } - setWorkingModuleConfig( - create(Protobuf.ModuleConfig.ModuleConfigSchema, { - payloadVariant: { - case: "cannedMessage", - value: data, - }, - }), + setChange( + { type: "moduleConfig", variant: "cannedMessage" }, + data, + moduleConfig.cannedMessage, ); }; diff --git a/packages/web/src/components/PageComponents/ModuleConfig/DetectionSensor.tsx b/packages/web/src/components/PageComponents/ModuleConfig/DetectionSensor.tsx index 5d041884a..79d188479 100644 --- a/packages/web/src/components/PageComponents/ModuleConfig/DetectionSensor.tsx +++ b/packages/web/src/components/PageComponents/ModuleConfig/DetectionSensor.tsx @@ -3,7 +3,6 @@ import { type DetectionSensorValidation, DetectionSensorValidationSchema, } from "@app/validation/moduleConfig/detectionSensor.ts"; -import { create } from "@bufbuild/protobuf"; import { DynamicForm, type DynamicFormFormInit, @@ -22,27 +21,20 @@ export const DetectionSensor = ({ }: DetectionSensorModuleConfigProps) => { useWaitForConfig({ moduleConfigCase: "detectionSensor" }); - const { - moduleConfig, - setWorkingModuleConfig, - getEffectiveModuleConfig, - removeWorkingModuleConfig, - } = useDevice(); + const { moduleConfig, setChange, getEffectiveModuleConfig, removeChange } = + useDevice(); const { t } = useTranslation("moduleConfig"); const onSubmit = (data: DetectionSensorValidation) => { if (deepCompareConfig(moduleConfig.detectionSensor, data, true)) { - removeWorkingModuleConfig("detectionSensor"); + removeChange({ type: "moduleConfig", variant: "detectionSensor" }); return; } - setWorkingModuleConfig( - create(Protobuf.ModuleConfig.ModuleConfigSchema, { - payloadVariant: { - case: "detectionSensor", - value: data, - }, - }), + setChange( + { type: "moduleConfig", variant: "detectionSensor" }, + data, + moduleConfig.detectionSensor, ); }; diff --git a/packages/web/src/components/PageComponents/ModuleConfig/ExternalNotification.tsx b/packages/web/src/components/PageComponents/ModuleConfig/ExternalNotification.tsx index 9bbb61787..e316ac78a 100644 --- a/packages/web/src/components/PageComponents/ModuleConfig/ExternalNotification.tsx +++ b/packages/web/src/components/PageComponents/ModuleConfig/ExternalNotification.tsx @@ -3,14 +3,12 @@ import { type ExternalNotificationValidation, ExternalNotificationValidationSchema, } from "@app/validation/moduleConfig/externalNotification.ts"; -import { create } from "@bufbuild/protobuf"; import { DynamicForm, type DynamicFormFormInit, } from "@components/Form/DynamicForm.tsx"; import { useDevice } from "@core/stores"; import { deepCompareConfig } from "@core/utils/deepCompareConfig.ts"; -import { Protobuf } from "@meshtastic/core"; import { useTranslation } from "react-i18next"; interface ExternalNotificationModuleConfigProps { @@ -22,27 +20,20 @@ export const ExternalNotification = ({ }: ExternalNotificationModuleConfigProps) => { useWaitForConfig({ moduleConfigCase: "externalNotification" }); - const { - moduleConfig, - setWorkingModuleConfig, - getEffectiveModuleConfig, - removeWorkingModuleConfig, - } = useDevice(); + const { moduleConfig, setChange, getEffectiveModuleConfig, removeChange } = + useDevice(); const { t } = useTranslation("moduleConfig"); const onSubmit = (data: ExternalNotificationValidation) => { if (deepCompareConfig(moduleConfig.externalNotification, data, true)) { - removeWorkingModuleConfig("externalNotification"); + removeChange({ type: "moduleConfig", variant: "externalNotification" }); return; } - setWorkingModuleConfig( - create(Protobuf.ModuleConfig.ModuleConfigSchema, { - payloadVariant: { - case: "externalNotification", - value: data, - }, - }), + setChange( + { type: "moduleConfig", variant: "externalNotification" }, + data, + moduleConfig.externalNotification, ); }; diff --git a/packages/web/src/components/PageComponents/ModuleConfig/MQTT.tsx b/packages/web/src/components/PageComponents/ModuleConfig/MQTT.tsx index c505a34a5..c65c7aa81 100644 --- a/packages/web/src/components/PageComponents/ModuleConfig/MQTT.tsx +++ b/packages/web/src/components/PageComponents/ModuleConfig/MQTT.tsx @@ -23,9 +23,9 @@ export const MQTT = ({ onFormInit }: MqttModuleConfigProps) => { const { config, moduleConfig, - setWorkingModuleConfig, + setChange, getEffectiveModuleConfig, - removeWorkingModuleConfig, + removeChange, } = useDevice(); const { t } = useTranslation("moduleConfig"); @@ -39,17 +39,14 @@ export const MQTT = ({ onFormInit }: MqttModuleConfigProps) => { }; if (deepCompareConfig(moduleConfig.mqtt, payload, true)) { - removeWorkingModuleConfig("mqtt"); + removeChange({ type: "moduleConfig", variant: "mqtt" }); return; } - setWorkingModuleConfig( - create(Protobuf.ModuleConfig.ModuleConfigSchema, { - payloadVariant: { - case: "mqtt", - value: payload, - }, - }), + setChange( + { type: "moduleConfig", variant: "mqtt" }, + payload, + moduleConfig.mqtt, ); }; diff --git a/packages/web/src/components/PageComponents/ModuleConfig/NeighborInfo.tsx b/packages/web/src/components/PageComponents/ModuleConfig/NeighborInfo.tsx index 2e4f189fc..1b134cbc9 100644 --- a/packages/web/src/components/PageComponents/ModuleConfig/NeighborInfo.tsx +++ b/packages/web/src/components/PageComponents/ModuleConfig/NeighborInfo.tsx @@ -3,14 +3,12 @@ import { type NeighborInfoValidation, NeighborInfoValidationSchema, } from "@app/validation/moduleConfig/neighborInfo.ts"; -import { create } from "@bufbuild/protobuf"; import { DynamicForm, type DynamicFormFormInit, } from "@components/Form/DynamicForm.tsx"; import { useDevice } from "@core/stores"; import { deepCompareConfig } from "@core/utils/deepCompareConfig.ts"; -import { Protobuf } from "@meshtastic/core"; import { useTranslation } from "react-i18next"; interface NeighborInfoModuleConfigProps { @@ -20,27 +18,20 @@ interface NeighborInfoModuleConfigProps { export const NeighborInfo = ({ onFormInit }: NeighborInfoModuleConfigProps) => { useWaitForConfig({ moduleConfigCase: "neighborInfo" }); - const { - moduleConfig, - setWorkingModuleConfig, - getEffectiveModuleConfig, - removeWorkingModuleConfig, - } = useDevice(); + const { moduleConfig, setChange, getEffectiveModuleConfig, removeChange } = + useDevice(); const { t } = useTranslation("moduleConfig"); const onSubmit = (data: NeighborInfoValidation) => { if (deepCompareConfig(moduleConfig.neighborInfo, data, true)) { - removeWorkingModuleConfig("neighborInfo"); + removeChange({ type: "moduleConfig", variant: "neighborInfo" }); return; } - setWorkingModuleConfig( - create(Protobuf.ModuleConfig.ModuleConfigSchema, { - payloadVariant: { - case: "neighborInfo", - value: data, - }, - }), + setChange( + { type: "moduleConfig", variant: "neighborInfo" }, + data, + moduleConfig.neighborInfo, ); }; diff --git a/packages/web/src/components/PageComponents/ModuleConfig/Paxcounter.tsx b/packages/web/src/components/PageComponents/ModuleConfig/Paxcounter.tsx index d878c32a3..13d636b04 100644 --- a/packages/web/src/components/PageComponents/ModuleConfig/Paxcounter.tsx +++ b/packages/web/src/components/PageComponents/ModuleConfig/Paxcounter.tsx @@ -3,14 +3,12 @@ import { type PaxcounterValidation, PaxcounterValidationSchema, } from "@app/validation/moduleConfig/paxcounter.ts"; -import { create } from "@bufbuild/protobuf"; import { DynamicForm, type DynamicFormFormInit, } from "@components/Form/DynamicForm.tsx"; import { useDevice } from "@core/stores"; import { deepCompareConfig } from "@core/utils/deepCompareConfig.ts"; -import { Protobuf } from "@meshtastic/core"; import { useTranslation } from "react-i18next"; interface PaxcounterModuleConfigProps { @@ -20,27 +18,20 @@ interface PaxcounterModuleConfigProps { export const Paxcounter = ({ onFormInit }: PaxcounterModuleConfigProps) => { useWaitForConfig({ moduleConfigCase: "paxcounter" }); - const { - moduleConfig, - setWorkingModuleConfig, - getEffectiveModuleConfig, - removeWorkingModuleConfig, - } = useDevice(); + const { moduleConfig, setChange, getEffectiveModuleConfig, removeChange } = + useDevice(); const { t } = useTranslation("moduleConfig"); const onSubmit = (data: PaxcounterValidation) => { if (deepCompareConfig(moduleConfig.paxcounter, data, true)) { - removeWorkingModuleConfig("paxcounter"); + removeChange({ type: "moduleConfig", variant: "paxcounter" }); return; } - setWorkingModuleConfig( - create(Protobuf.ModuleConfig.ModuleConfigSchema, { - payloadVariant: { - case: "paxcounter", - value: data, - }, - }), + setChange( + { type: "moduleConfig", variant: "paxcounter" }, + data, + moduleConfig.paxcounter, ); }; diff --git a/packages/web/src/components/PageComponents/ModuleConfig/RangeTest.tsx b/packages/web/src/components/PageComponents/ModuleConfig/RangeTest.tsx index 73c08fabd..a360492e6 100644 --- a/packages/web/src/components/PageComponents/ModuleConfig/RangeTest.tsx +++ b/packages/web/src/components/PageComponents/ModuleConfig/RangeTest.tsx @@ -3,14 +3,12 @@ import { type RangeTestValidation, RangeTestValidationSchema, } from "@app/validation/moduleConfig/rangeTest.ts"; -import { create } from "@bufbuild/protobuf"; import { DynamicForm, type DynamicFormFormInit, } from "@components/Form/DynamicForm.tsx"; import { useDevice } from "@core/stores"; import { deepCompareConfig } from "@core/utils/deepCompareConfig.ts"; -import { Protobuf } from "@meshtastic/core"; import { useTranslation } from "react-i18next"; interface RangeTestModuleConfigProps { @@ -20,28 +18,21 @@ interface RangeTestModuleConfigProps { export const RangeTest = ({ onFormInit }: RangeTestModuleConfigProps) => { useWaitForConfig({ moduleConfigCase: "rangeTest" }); - const { - moduleConfig, - setWorkingModuleConfig, - getEffectiveModuleConfig, - removeWorkingModuleConfig, - } = useDevice(); + const { moduleConfig, setChange, getEffectiveModuleConfig, removeChange } = + useDevice(); const { t } = useTranslation("moduleConfig"); const onSubmit = (data: RangeTestValidation) => { if (deepCompareConfig(moduleConfig.rangeTest, data, true)) { - removeWorkingModuleConfig("rangeTest"); + removeChange({ type: "moduleConfig", variant: "rangeTest" }); return; } - setWorkingModuleConfig( - create(Protobuf.ModuleConfig.ModuleConfigSchema, { - payloadVariant: { - case: "rangeTest", - value: data, - }, - }), + setChange( + { type: "moduleConfig", variant: "rangeTest" }, + data, + moduleConfig.rangeTest, ); }; diff --git a/packages/web/src/components/PageComponents/ModuleConfig/Serial.tsx b/packages/web/src/components/PageComponents/ModuleConfig/Serial.tsx index 708434305..96de4bc65 100644 --- a/packages/web/src/components/PageComponents/ModuleConfig/Serial.tsx +++ b/packages/web/src/components/PageComponents/ModuleConfig/Serial.tsx @@ -3,7 +3,6 @@ import { type SerialValidation, SerialValidationSchema, } from "@app/validation/moduleConfig/serial.ts"; -import { create } from "@bufbuild/protobuf"; import { DynamicForm, type DynamicFormFormInit, @@ -20,27 +19,20 @@ interface SerialModuleConfigProps { export const Serial = ({ onFormInit }: SerialModuleConfigProps) => { useWaitForConfig({ moduleConfigCase: "serial" }); - const { - moduleConfig, - setWorkingModuleConfig, - getEffectiveModuleConfig, - removeWorkingModuleConfig, - } = useDevice(); + const { moduleConfig, setChange, getEffectiveModuleConfig, removeChange } = + useDevice(); const { t } = useTranslation("moduleConfig"); const onSubmit = (data: SerialValidation) => { if (deepCompareConfig(moduleConfig.serial, data, true)) { - removeWorkingModuleConfig("serial"); + removeChange({ type: "moduleConfig", variant: "serial" }); return; } - setWorkingModuleConfig( - create(Protobuf.ModuleConfig.ModuleConfigSchema, { - payloadVariant: { - case: "serial", - value: data, - }, - }), + setChange( + { type: "moduleConfig", variant: "serial" }, + data, + moduleConfig.serial, ); }; diff --git a/packages/web/src/components/PageComponents/ModuleConfig/StoreForward.tsx b/packages/web/src/components/PageComponents/ModuleConfig/StoreForward.tsx index eebb84e7d..658362df0 100644 --- a/packages/web/src/components/PageComponents/ModuleConfig/StoreForward.tsx +++ b/packages/web/src/components/PageComponents/ModuleConfig/StoreForward.tsx @@ -3,14 +3,12 @@ import { type StoreForwardValidation, StoreForwardValidationSchema, } from "@app/validation/moduleConfig/storeForward.ts"; -import { create } from "@bufbuild/protobuf"; import { DynamicForm, type DynamicFormFormInit, } from "@components/Form/DynamicForm.tsx"; import { useDevice } from "@core/stores"; import { deepCompareConfig } from "@core/utils/deepCompareConfig.ts"; -import { Protobuf } from "@meshtastic/core"; import { useTranslation } from "react-i18next"; interface StoreForwardModuleConfigProps { @@ -20,27 +18,20 @@ interface StoreForwardModuleConfigProps { export const StoreForward = ({ onFormInit }: StoreForwardModuleConfigProps) => { useWaitForConfig({ moduleConfigCase: "storeForward" }); - const { - moduleConfig, - setWorkingModuleConfig, - getEffectiveModuleConfig, - removeWorkingModuleConfig, - } = useDevice(); + const { moduleConfig, setChange, getEffectiveModuleConfig, removeChange } = + useDevice(); const { t } = useTranslation("moduleConfig"); const onSubmit = (data: StoreForwardValidation) => { if (deepCompareConfig(moduleConfig.storeForward, data, true)) { - removeWorkingModuleConfig("storeForward"); + removeChange({ type: "moduleConfig", variant: "storeForward" }); return; } - setWorkingModuleConfig( - create(Protobuf.ModuleConfig.ModuleConfigSchema, { - payloadVariant: { - case: "storeForward", - value: data, - }, - }), + setChange( + { type: "moduleConfig", variant: "storeForward" }, + data, + moduleConfig.storeForward, ); }; diff --git a/packages/web/src/components/PageComponents/ModuleConfig/Telemetry.tsx b/packages/web/src/components/PageComponents/ModuleConfig/Telemetry.tsx index 782c50221..c6d1384a1 100644 --- a/packages/web/src/components/PageComponents/ModuleConfig/Telemetry.tsx +++ b/packages/web/src/components/PageComponents/ModuleConfig/Telemetry.tsx @@ -3,14 +3,12 @@ import { type TelemetryValidation, TelemetryValidationSchema, } from "@app/validation/moduleConfig/telemetry.ts"; -import { create } from "@bufbuild/protobuf"; import { DynamicForm, type DynamicFormFormInit, } from "@components/Form/DynamicForm.tsx"; import { useDevice } from "@core/stores"; import { deepCompareConfig } from "@core/utils/deepCompareConfig.ts"; -import { Protobuf } from "@meshtastic/core"; import { useTranslation } from "react-i18next"; interface TelemetryModuleConfigProps { @@ -20,27 +18,20 @@ interface TelemetryModuleConfigProps { export const Telemetry = ({ onFormInit }: TelemetryModuleConfigProps) => { useWaitForConfig({ moduleConfigCase: "telemetry" }); - const { - moduleConfig, - setWorkingModuleConfig, - getEffectiveModuleConfig, - removeWorkingModuleConfig, - } = useDevice(); + const { moduleConfig, setChange, getEffectiveModuleConfig, removeChange } = + useDevice(); const { t } = useTranslation("moduleConfig"); const onSubmit = (data: TelemetryValidation) => { if (deepCompareConfig(moduleConfig.telemetry, data, true)) { - removeWorkingModuleConfig("telemetry"); + removeChange({ type: "moduleConfig", variant: "telemetry" }); return; } - setWorkingModuleConfig( - create(Protobuf.ModuleConfig.ModuleConfigSchema, { - payloadVariant: { - case: "telemetry", - value: data, - }, - }), + setChange( + { type: "moduleConfig", variant: "telemetry" }, + data, + moduleConfig.telemetry, ); }; diff --git a/packages/web/src/components/PageComponents/Config/Bluetooth.tsx b/packages/web/src/components/PageComponents/Settings/Bluetooth.tsx similarity index 84% rename from packages/web/src/components/PageComponents/Config/Bluetooth.tsx rename to packages/web/src/components/PageComponents/Settings/Bluetooth.tsx index ee283cdc8..423197c95 100644 --- a/packages/web/src/components/PageComponents/Config/Bluetooth.tsx +++ b/packages/web/src/components/PageComponents/Settings/Bluetooth.tsx @@ -3,7 +3,6 @@ import { type BluetoothValidation, BluetoothValidationSchema, } from "@app/validation/config/bluetooth.ts"; -import { create } from "@bufbuild/protobuf"; import { DynamicForm, type DynamicFormFormInit, @@ -19,24 +18,16 @@ interface BluetoothConfigProps { export const Bluetooth = ({ onFormInit }: BluetoothConfigProps) => { useWaitForConfig({ configCase: "bluetooth" }); - const { config, setWorkingConfig, getEffectiveConfig, removeWorkingConfig } = - useDevice(); - const { t } = useTranslation("deviceConfig"); + const { config, setChange, getEffectiveConfig, removeChange } = useDevice(); + const { t } = useTranslation("config"); const onSubmit = (data: BluetoothValidation) => { if (deepCompareConfig(config.bluetooth, data, true)) { - removeWorkingConfig("bluetooth"); + removeChange({ type: "config", variant: "bluetooth" }); return; } - setWorkingConfig( - create(Protobuf.Config.ConfigSchema, { - payloadVariant: { - case: "bluetooth", - value: data, - }, - }), - ); + setChange({ type: "config", variant: "bluetooth" }, data, config.bluetooth); }; return ( diff --git a/packages/web/src/components/PageComponents/Config/Device/index.tsx b/packages/web/src/components/PageComponents/Settings/Device/index.tsx similarity index 91% rename from packages/web/src/components/PageComponents/Config/Device/index.tsx rename to packages/web/src/components/PageComponents/Settings/Device/index.tsx index 96afeeedf..063eb682f 100644 --- a/packages/web/src/components/PageComponents/Config/Device/index.tsx +++ b/packages/web/src/components/PageComponents/Settings/Device/index.tsx @@ -3,7 +3,6 @@ import { type DeviceValidation, DeviceValidationSchema, } from "@app/validation/config/device.ts"; -import { create } from "@bufbuild/protobuf"; import { useUnsafeRolesDialog } from "@components/Dialog/UnsafeRolesDialog/useUnsafeRolesDialog.ts"; import { DynamicForm, @@ -20,25 +19,17 @@ interface DeviceConfigProps { export const Device = ({ onFormInit }: DeviceConfigProps) => { useWaitForConfig({ configCase: "device" }); - const { config, setWorkingConfig, getEffectiveConfig, removeWorkingConfig } = - useDevice(); - const { t } = useTranslation("deviceConfig"); + const { config, setChange, getEffectiveConfig, removeChange } = useDevice(); + const { t } = useTranslation("config"); const { validateRoleSelection } = useUnsafeRolesDialog(); const onSubmit = (data: DeviceValidation) => { if (deepCompareConfig(config.device, data, true)) { - removeWorkingConfig("device"); + removeChange({ type: "config", variant: "device" }); return; } - setWorkingConfig( - create(Protobuf.Config.ConfigSchema, { - payloadVariant: { - case: "device", - value: data, - }, - }), - ); + setChange({ type: "config", variant: "device" }, data, config.device); }; return ( diff --git a/packages/web/src/components/PageComponents/Config/Display.tsx b/packages/web/src/components/PageComponents/Settings/Display.tsx similarity index 85% rename from packages/web/src/components/PageComponents/Config/Display.tsx rename to packages/web/src/components/PageComponents/Settings/Display.tsx index f8e1ce36d..963e7ea72 100644 --- a/packages/web/src/components/PageComponents/Config/Display.tsx +++ b/packages/web/src/components/PageComponents/Settings/Display.tsx @@ -3,7 +3,6 @@ import { type DisplayValidation, DisplayValidationSchema, } from "@app/validation/config/display.ts"; -import { create } from "@bufbuild/protobuf"; import { DynamicForm, type DynamicFormFormInit, @@ -18,24 +17,16 @@ interface DisplayConfigProps { } export const Display = ({ onFormInit }: DisplayConfigProps) => { useWaitForConfig({ configCase: "display" }); - const { config, setWorkingConfig, getEffectiveConfig, removeWorkingConfig } = - useDevice(); - const { t } = useTranslation("deviceConfig"); + const { config, setChange, getEffectiveConfig, removeChange } = useDevice(); + const { t } = useTranslation("config"); const onSubmit = (data: DisplayValidation) => { if (deepCompareConfig(config.display, data, true)) { - removeWorkingConfig("display"); + removeChange({ type: "config", variant: "display" }); return; } - setWorkingConfig( - create(Protobuf.Config.ConfigSchema, { - payloadVariant: { - case: "display", - value: data, - }, - }), - ); + setChange({ type: "config", variant: "display" }, data, config.display); }; return ( @@ -59,6 +50,10 @@ export const Display = ({ onFormInit }: DisplayConfigProps) => { suffix: t("unit.second.plural"), }, }, + // TODO: This field is deprecated since protobufs 2.7.4 and only has UNUSED=0 value. + // GPS format has been moved to DeviceUIConfig.gps_format with proper enum values (DEC, DMS, UTM, MGRS, OLC, OSGR, MLS). + // This should be removed once DeviceUI settings are implemented. + // See: packages/protobufs/meshtastic/device_ui.proto { type: "select", name: "gpsFormat", @@ -66,7 +61,8 @@ export const Display = ({ onFormInit }: DisplayConfigProps) => { description: t("display.gpsDisplayUnits.description"), properties: { enumValue: - Protobuf.Config.Config_DisplayConfig_GpsCoordinateFormat, + Protobuf.Config + .Config_DisplayConfig_DeprecatedGpsCoordinateFormat, }, }, { diff --git a/packages/web/src/components/PageComponents/Config/LoRa.tsx b/packages/web/src/components/PageComponents/Settings/LoRa.tsx similarity index 93% rename from packages/web/src/components/PageComponents/Config/LoRa.tsx rename to packages/web/src/components/PageComponents/Settings/LoRa.tsx index cfa7c612d..a8b41fa8f 100644 --- a/packages/web/src/components/PageComponents/Config/LoRa.tsx +++ b/packages/web/src/components/PageComponents/Settings/LoRa.tsx @@ -3,7 +3,6 @@ import { type LoRaValidation, LoRaValidationSchema, } from "@app/validation/config/lora.ts"; -import { create } from "@bufbuild/protobuf"; import { DynamicForm, type DynamicFormFormInit, @@ -19,24 +18,16 @@ interface LoRaConfigProps { export const LoRa = ({ onFormInit }: LoRaConfigProps) => { useWaitForConfig({ configCase: "lora" }); - const { config, setWorkingConfig, getEffectiveConfig, removeWorkingConfig } = - useDevice(); - const { t } = useTranslation("deviceConfig"); + const { config, setChange, getEffectiveConfig, removeChange } = useDevice(); + const { t } = useTranslation("config"); const onSubmit = (data: LoRaValidation) => { if (deepCompareConfig(config.lora, data, true)) { - removeWorkingConfig("lora"); + removeChange({ type: "config", variant: "lora" }); return; } - setWorkingConfig( - create(Protobuf.Config.ConfigSchema, { - payloadVariant: { - case: "lora", - value: data, - }, - }), - ); + setChange({ type: "config", variant: "lora" }, data, config.lora); }; return ( @@ -126,7 +117,7 @@ export const LoRa = ({ onFormInit }: LoRaConfigProps) => { }, ], properties: { - suffix: t("unit.megahertz"), + suffix: t("unit.kilohertz"), }, }, { diff --git a/packages/web/src/components/PageComponents/Config/Network/index.tsx b/packages/web/src/components/PageComponents/Settings/Network/index.tsx similarity index 95% rename from packages/web/src/components/PageComponents/Config/Network/index.tsx rename to packages/web/src/components/PageComponents/Settings/Network/index.tsx index b999d5dc2..6b5bb63ec 100644 --- a/packages/web/src/components/PageComponents/Config/Network/index.tsx +++ b/packages/web/src/components/PageComponents/Settings/Network/index.tsx @@ -23,9 +23,8 @@ interface NetworkConfigProps { export const Network = ({ onFormInit }: NetworkConfigProps) => { useWaitForConfig({ configCase: "network" }); - const { config, setWorkingConfig, getEffectiveConfig, removeWorkingConfig } = - useDevice(); - const { t } = useTranslation("deviceConfig"); + const { config, setChange, getEffectiveConfig, removeChange } = useDevice(); + const { t } = useTranslation("config"); const networkConfig = getEffectiveConfig("network"); @@ -44,18 +43,11 @@ export const Network = ({ onFormInit }: NetworkConfigProps) => { }; if (deepCompareConfig(config.network, payload, true)) { - removeWorkingConfig("network"); + removeChange({ type: "config", variant: "network" }); return; } - setWorkingConfig( - create(Protobuf.Config.ConfigSchema, { - payloadVariant: { - case: "network", - value: payload, - }, - }), - ); + setChange({ type: "config", variant: "network" }, payload, config.network); }; return ( diff --git a/packages/web/src/components/PageComponents/Config/Position.tsx b/packages/web/src/components/PageComponents/Settings/Position.tsx similarity index 52% rename from packages/web/src/components/PageComponents/Config/Position.tsx rename to packages/web/src/components/PageComponents/Settings/Position.tsx index c52bc6680..f8ab0ab2e 100644 --- a/packages/web/src/components/PageComponents/Config/Position.tsx +++ b/packages/web/src/components/PageComponents/Settings/Position.tsx @@ -12,10 +12,10 @@ import { type FlagName, usePositionFlags, } from "@core/hooks/usePositionFlags.ts"; -import { useDevice } from "@core/stores"; +import { useDevice, useNodeDB } from "@core/stores"; import { deepCompareConfig } from "@core/utils/deepCompareConfig.ts"; import { Protobuf } from "@meshtastic/core"; -import { useCallback } from "react"; +import { useCallback, useMemo } from "react"; import { useTranslation } from "react-i18next"; interface PositionConfigProps { @@ -24,27 +24,85 @@ interface PositionConfigProps { export const Position = ({ onFormInit }: PositionConfigProps) => { useWaitForConfig({ configCase: "position" }); - const { setWorkingConfig, config, getEffectiveConfig, removeWorkingConfig } = - useDevice(); + const { + setChange, + config, + getEffectiveConfig, + removeChange, + queueAdminMessage, + } = useDevice(); + const { getMyNode } = useNodeDB(); const { flagsValue, activeFlags, toggleFlag, getAllFlags } = usePositionFlags( getEffectiveConfig("position")?.positionFlags ?? 0, ); - const { t } = useTranslation("deviceConfig"); + const { t } = useTranslation("config"); + + const myNode = getMyNode(); + const currentPosition = myNode?.position; + + const effectiveConfig = getEffectiveConfig("position"); + const displayUnits = getEffectiveConfig("display")?.units; + + const formValues = useMemo(() => { + return { + ...config.position, + ...effectiveConfig, + // Include current position coordinates if available + latitude: currentPosition?.latitudeI + ? currentPosition.latitudeI / 1e7 + : undefined, + longitude: currentPosition?.longitudeI + ? currentPosition.longitudeI / 1e7 + : undefined, + altitude: currentPosition?.altitude ?? 0, + } as PositionValidation; + }, [config.position, effectiveConfig, currentPosition]); const onSubmit = (data: PositionValidation) => { - if (deepCompareConfig(config.position, data, true)) { - removeWorkingConfig("position"); - return; + // Exclude position coordinates from config payload (they're handled via admin message) + const { + latitude: _latitude, + longitude: _longitude, + altitude: _altitude, + ...configData + } = data; + const payload = { ...configData, positionFlags: flagsValue }; + + // Save config first + let configResult: ReturnType | undefined; + if (deepCompareConfig(config.position, payload, true)) { + removeChange({ type: "config", variant: "position" }); + configResult = undefined; + } else { + configResult = setChange( + { type: "config", variant: "position" }, + payload, + config.position, + ); } - return setWorkingConfig( - create(Protobuf.Config.ConfigSchema, { + // Then handle position coordinates via admin message if fixedPosition is enabled + if ( + data.fixedPosition && + data.latitude !== undefined && + data.longitude !== undefined + ) { + const message = create(Protobuf.Admin.AdminMessageSchema, { payloadVariant: { - case: "position", - value: { ...data, positionFlags: flagsValue }, + case: "setFixedPosition", + value: create(Protobuf.Mesh.PositionSchema, { + latitudeI: Math.round(data.latitude * 1e7), + longitudeI: Math.round(data.longitude * 1e7), + altitude: data.altitude || 0, + time: Math.floor(Date.now() / 1000), + }), }, - }), - ); + }); + + queueAdminMessage(message); + } + + return configResult; }; const onPositonFlagChange = useCallback( @@ -63,7 +121,7 @@ export const Position = ({ onFormInit }: PositionConfigProps) => { onFormInit={onFormInit} validationSchema={PositionValidationSchema} defaultValues={config.position} - values={getEffectiveConfig("position")} + values={formValues} fieldGroups={[ { label: t("position.title"), @@ -89,6 +147,75 @@ export const Position = ({ onFormInit }: PositionConfigProps) => { name: "fixedPosition", label: t("position.fixedPosition.label"), description: t("position.fixedPosition.description"), + disabledBy: [ + { + fieldName: "gpsMode", + selector: + Protobuf.Config.Config_PositionConfig_GpsMode.ENABLED, + }, + ], + }, + // Position coordinate fields (only shown when fixedPosition is enabled) + { + type: "number", + name: "latitude", + label: t("position.fixedPosition.latitude.label"), + description: `${t("position.fixedPosition.latitude.description")} (Max 7 decimal precision)`, + properties: { + step: 0.0000001, + suffix: "Degrees", + fieldLength: { + max: 10, + }, + }, + disabledBy: [ + { + fieldName: "fixedPosition", + }, + ], + }, + { + type: "number", + name: "longitude", + label: t("position.fixedPosition.longitude.label"), + description: `${t("position.fixedPosition.longitude.description")} (Max 7 decimal precision)`, + properties: { + step: 0.0000001, + suffix: "Degrees", + fieldLength: { + max: 10, + }, + }, + disabledBy: [ + { + fieldName: "fixedPosition", + }, + ], + }, + { + type: "number", + name: "altitude", + label: t("position.fixedPosition.altitude.label"), + description: t("position.fixedPosition.altitude.description", { + unit: + displayUnits === + Protobuf.Config.Config_DisplayConfig_DisplayUnits.IMPERIAL + ? "Feet" + : "Meters", + }), + properties: { + step: 0.0000001, + suffix: + displayUnits === + Protobuf.Config.Config_DisplayConfig_DisplayUnits.IMPERIAL + ? "Feet" + : "Meters", + }, + disabledBy: [ + { + fieldName: "fixedPosition", + }, + ], }, { type: "multiSelect", diff --git a/packages/web/src/components/PageComponents/Config/Power.tsx b/packages/web/src/components/PageComponents/Settings/Power.tsx similarity index 89% rename from packages/web/src/components/PageComponents/Config/Power.tsx rename to packages/web/src/components/PageComponents/Settings/Power.tsx index 323c1ec22..dcad23d91 100644 --- a/packages/web/src/components/PageComponents/Config/Power.tsx +++ b/packages/web/src/components/PageComponents/Settings/Power.tsx @@ -3,14 +3,12 @@ import { type PowerValidation, PowerValidationSchema, } from "@app/validation/config/power.ts"; -import { create } from "@bufbuild/protobuf"; import { DynamicForm, type DynamicFormFormInit, } from "@components/Form/DynamicForm.tsx"; import { useDevice } from "@core/stores"; import { deepCompareConfig } from "@core/utils/deepCompareConfig.ts"; -import { Protobuf } from "@meshtastic/core"; import { useTranslation } from "react-i18next"; interface PowerConfigProps { @@ -19,24 +17,16 @@ interface PowerConfigProps { export const Power = ({ onFormInit }: PowerConfigProps) => { useWaitForConfig({ configCase: "power" }); - const { setWorkingConfig, config, getEffectiveConfig, removeWorkingConfig } = - useDevice(); - const { t } = useTranslation("deviceConfig"); + const { setChange, config, getEffectiveConfig, removeChange } = useDevice(); + const { t } = useTranslation("config"); const onSubmit = (data: PowerValidation) => { if (deepCompareConfig(config.power, data, true)) { - removeWorkingConfig("power"); + removeChange({ type: "config", variant: "power" }); return; } - setWorkingConfig( - create(Protobuf.Config.ConfigSchema, { - payloadVariant: { - case: "power", - value: data, - }, - }), - ); + setChange({ type: "config", variant: "power" }, data, config.power); }; return ( diff --git a/packages/web/src/components/PageComponents/Config/Security/Security.tsx b/packages/web/src/components/PageComponents/Settings/Security/Security.tsx similarity index 95% rename from packages/web/src/components/PageComponents/Config/Security/Security.tsx rename to packages/web/src/components/PageComponents/Settings/Security/Security.tsx index 21d620ea5..a3e08e2cb 100644 --- a/packages/web/src/components/PageComponents/Config/Security/Security.tsx +++ b/packages/web/src/components/PageComponents/Settings/Security/Security.tsx @@ -4,7 +4,6 @@ import { type RawSecurity, RawSecuritySchema, } from "@app/validation/config/security.ts"; -import { create } from "@bufbuild/protobuf"; import { ManagedModeDialog } from "@components/Dialog/ManagedModeDialog.tsx"; import { PkiRegenerateDialog } from "@components/Dialog/PkiRegenerateDialog.tsx"; import { createZodResolver } from "@components/Form/createZodResolver.ts"; @@ -15,7 +14,6 @@ import { import { useDevice } from "@core/stores"; import { deepCompareConfig } from "@core/utils/deepCompareConfig.ts"; import { getX25519PrivateKey, getX25519PublicKey } from "@core/utils/x25519.ts"; -import { Protobuf } from "@meshtastic/core"; import { fromByteArray, toByteArray } from "base64-js"; import { useEffect, useState } from "react"; import { type DefaultValues, useForm } from "react-hook-form"; @@ -27,15 +25,10 @@ interface SecurityConfigProps { export const Security = ({ onFormInit }: SecurityConfigProps) => { useWaitForConfig({ configCase: "security" }); - const { - config, - setWorkingConfig, - setDialogOpen, - getEffectiveConfig, - removeWorkingConfig, - } = useDevice(); + const { config, setChange, setDialogOpen, getEffectiveConfig, removeChange } = + useDevice(); - const { t } = useTranslation("deviceConfig"); + const { t } = useTranslation("config"); const defaultConfig = config.security; const defaultValues = { @@ -103,17 +96,14 @@ export const Security = ({ onFormInit }: SecurityConfigProps) => { }; if (deepCompareConfig(config.security, payload, true)) { - removeWorkingConfig("security"); + removeChange({ type: "config", variant: "security" }); return; } - setWorkingConfig( - create(Protobuf.Config.ConfigSchema, { - payloadVariant: { - case: "security", - value: payload, - }, - }), + setChange( + { type: "config", variant: "security" }, + payload, + config.security, ); }; diff --git a/packages/web/src/components/PageComponents/Settings/User.tsx b/packages/web/src/components/PageComponents/Settings/User.tsx new file mode 100644 index 000000000..c4f094f10 --- /dev/null +++ b/packages/web/src/components/PageComponents/Settings/User.tsx @@ -0,0 +1,111 @@ +import { + type UserValidation, + UserValidationSchema, +} from "@app/validation/config/user.ts"; +import { create } from "@bufbuild/protobuf"; +import { + DynamicForm, + type DynamicFormFormInit, +} from "@components/Form/DynamicForm.tsx"; +import { useDevice, useNodeDB } from "@core/stores"; +import { Protobuf } from "@meshtastic/core"; +import { useTranslation } from "react-i18next"; + +interface UserConfigProps { + onFormInit: DynamicFormFormInit; +} + +export const User = ({ onFormInit }: UserConfigProps) => { + const { hardware, getChange, connection } = useDevice(); + const { getNode } = useNodeDB(); + const { t } = useTranslation("config"); + + const myNode = getNode(hardware.myNodeNum); + const defaultUser = myNode?.user ?? { + id: "", + longName: "", + shortName: "", + isLicensed: false, + }; + + // Get working copy from change registry + const workingUser = getChange({ type: "user" }) as + | Protobuf.Mesh.User + | undefined; + + const effectiveUser = workingUser ?? defaultUser; + + const onSubmit = (data: UserValidation) => { + connection?.setOwner( + create(Protobuf.Mesh.UserSchema, { + ...data, + }), + ); + }; + + return ( + + onSubmit={onSubmit} + onFormInit={onFormInit} + validationSchema={UserValidationSchema} + defaultValues={{ + longName: defaultUser.longName, + shortName: defaultUser.shortName, + isLicensed: defaultUser.isLicensed, + isUnmessageable: false, + }} + values={{ + longName: effectiveUser.longName, + shortName: effectiveUser.shortName, + isLicensed: effectiveUser.isLicensed, + isUnmessageable: false, + }} + fieldGroups={[ + { + label: t("user.title"), + description: t("user.description"), + fields: [ + { + type: "text", + name: "longName", + label: t("user.longName.label"), + description: t("user.longName.description"), + properties: { + fieldLength: { + min: 1, + max: 40, + showCharacterCount: true, + }, + }, + }, + { + type: "text", + name: "shortName", + label: t("user.shortName.label"), + description: t("user.shortName.description"), + properties: { + fieldLength: { + min: 2, + max: 4, + showCharacterCount: true, + }, + }, + }, + { + type: "toggle", + name: "isUnmessageable", + label: t("user.isUnmessageable.label"), + description: t("user.isUnmessageable.description"), + }, + { + type: "toggle", + name: "isLicensed", + label: t("user.isLicensed.label"), + description: t("user.isLicensed.description"), + }, + ], + }, + ]} + /> + ); +}; diff --git a/packages/web/src/components/Sidebar.tsx b/packages/web/src/components/Sidebar.tsx index 8cc117d81..a5cf71a09 100644 --- a/packages/web/src/components/Sidebar.tsx +++ b/packages/web/src/components/Sidebar.tsx @@ -1,10 +1,13 @@ +import { useFirstSavedConnection } from "@app/core/stores/deviceStore/selectors.ts"; import { SidebarButton } from "@components/UI/Sidebar/SidebarButton.tsx"; import { SidebarSection } from "@components/UI/Sidebar/SidebarSection.tsx"; import { Spinner } from "@components/UI/Spinner.tsx"; import { Subtle } from "@components/UI/Typography/Subtle.tsx"; import { type Page, + useActiveConnection, useAppStore, + useDefaultConnection, useDevice, useNodeDB, useSidebar, @@ -75,6 +78,14 @@ export const Sidebar = ({ children }: SidebarProps) => { const { t } = useTranslation("ui"); const navigate = useNavigate({ from: "/" }); + // Get the active connection from selector (connected > default > first) + const activeConnection = + useActiveConnection() || + // biome-ignore lint/correctness/useHookAtTopLevel: not a react hook + useDefaultConnection() || + // biome-ignore lint/correctness/useHookAtTopLevel: not a hook + useFirstSavedConnection(); + const pathname = useLocation({ select: (location) => location.pathname.replace(/^\//, ""), }); @@ -108,9 +119,9 @@ export const Sidebar = ({ children }: SidebarProps) => { }, { name: t("navigation.map"), icon: MapIcon, page: "map" }, { - name: t("navigation.config"), + name: t("navigation.settings"), icon: SettingsIcon, - page: "config", + page: "settings", }, { name: `${t("navigation.nodes")} (${displayedNodeCount})`, @@ -196,10 +207,7 @@ export const Sidebar = ({ children }: SidebarProps) => { isCollapsed={isCollapsed} setCommandPaletteOpen={() => setCommandPaletteOpen(true)} setDialogOpen={() => setDialogOpen("deviceName", true)} - user={{ - longName: myNode?.user?.longName ?? t("unknown.longName"), - shortName: myNode?.user?.shortName ?? t("unknown.shortName"), - }} + user={myNode.user} firmwareVersion={ myMetadata?.firmwareVersion ?? t("unknown.notAvailable") } @@ -210,6 +218,8 @@ export const Sidebar = ({ children }: SidebarProps) => { ? Math.abs(myNode.deviceMetrics?.voltage) : undefined, }} + connectionStatus={activeConnection?.status} + connectionName={activeConnection?.name} /> )}
    diff --git a/packages/web/src/components/UI/AlertDialog.tsx b/packages/web/src/components/UI/AlertDialog.tsx new file mode 100644 index 000000000..264328cb6 --- /dev/null +++ b/packages/web/src/components/UI/AlertDialog.tsx @@ -0,0 +1,149 @@ +import { cn } from "@core/utils/cn.ts"; +import * as AlertDialogPrimitive from "@radix-ui/react-alert-dialog"; +import * as React from "react"; +import { buttonVariants } from "./Button.tsx"; + +const AlertDialog = AlertDialogPrimitive.Root; + +const AlertDialogTrigger = AlertDialogPrimitive.Trigger; + +const AlertDialogPortal = ({ + children, + ...props +}: AlertDialogPrimitive.AlertDialogPortalProps) => ( + +
    + {children} +
    +
    +); +AlertDialogPortal.displayName = AlertDialogPrimitive.Portal.displayName; + +const AlertDialogOverlay = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); +AlertDialogOverlay.displayName = AlertDialogPrimitive.Overlay.displayName; + +const AlertDialogContent = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + + + + +)); +AlertDialogContent.displayName = AlertDialogPrimitive.Content.displayName; + +const AlertDialogHeader = ({ + className, + ...props +}: React.HTMLAttributes) => ( +
    +); +AlertDialogHeader.displayName = "AlertDialogHeader"; + +const AlertDialogFooter = ({ + className, + ...props +}: React.HTMLAttributes) => ( +
    +); +AlertDialogFooter.displayName = "AlertDialogFooter"; + +const AlertDialogTitle = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); +AlertDialogTitle.displayName = AlertDialogPrimitive.Title.displayName; + +const AlertDialogDescription = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); +AlertDialogDescription.displayName = + AlertDialogPrimitive.Description.displayName; + +const AlertDialogAction = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); +AlertDialogAction.displayName = AlertDialogPrimitive.Action.displayName; + +const AlertDialogCancel = React.forwardRef< + React.ElementRef, + React.ComponentPropsWithoutRef +>(({ className, ...props }, ref) => ( + +)); +AlertDialogCancel.displayName = AlertDialogPrimitive.Cancel.displayName; + +export { + AlertDialog, + AlertDialogAction, + AlertDialogCancel, + AlertDialogContent, + AlertDialogDescription, + AlertDialogFooter, + AlertDialogHeader, + AlertDialogTitle, + AlertDialogTrigger, +}; diff --git a/packages/web/src/components/UI/Avatar.tsx b/packages/web/src/components/UI/Avatar.tsx index 12a1ea481..209a69eef 100644 --- a/packages/web/src/components/UI/Avatar.tsx +++ b/packages/web/src/components/UI/Avatar.tsx @@ -1,8 +1,10 @@ -import { getColorFromText, isLightColor } from "@app/core/utils/color"; +import { useNodeDB } from "@app/core/stores"; +import { getColorFromNodeNum, isLightColor } from "@app/core/utils/color"; import { Tooltip, TooltipArrow, TooltipContent, + TooltipPortal, TooltipProvider, TooltipTrigger, } from "@components/UI/Tooltip.tsx"; @@ -11,7 +13,7 @@ import { LockKeyholeOpenIcon, StarIcon } from "lucide-react"; import { useTranslation } from "react-i18next"; interface AvatarProps { - text: string | number; + nodeNum: number; size?: "sm" | "lg"; className?: string; showError?: boolean; @@ -19,24 +21,33 @@ interface AvatarProps { } export const Avatar = ({ - text, + nodeNum, size = "sm", showError = false, showFavorite = false, className, }: AvatarProps) => { const { t } = useTranslation(); + const { getNode } = useNodeDB(); + const node = getNode(nodeNum); + + if (!nodeNum) { + return null; + } const sizes = { sm: "size-10 text-xs font-light", lg: "size-16 text-lg", }; - const safeText = text?.toString().toUpperCase(); - const bgColor = getColorFromText(safeText); + const shortName = node?.user?.shortName ?? ""; + const longName = node?.user?.longName ?? ""; + const displayName = shortName || longName; + + const bgColor = getColorFromNodeNum(nodeNum); const isLight = isLightColor(bgColor); const textColor = isLight ? "#000000" : "#FFFFFF"; - const initials = safeText?.slice(0, 4) ?? t("unknown.shortName"); + const initials = displayName.slice(0, 4) || t("unknown.shortName"); return (
    - - {t("nodeDetail.favorite.label", { ns: "nodes" })} - - + + + {t("nodeDetail.favorite.label", { ns: "nodes" })} + + + ) : null} @@ -84,10 +97,12 @@ export const Avatar = ({ aria-hidden="true" /> - - {t("nodeDetail.error.label", { ns: "nodes" })} - - + + + {t("nodeDetail.error.label", { ns: "nodes" })} + + + ) : null} diff --git a/packages/web/src/components/UI/Badge.tsx b/packages/web/src/components/UI/Badge.tsx new file mode 100644 index 000000000..df7ee9321 --- /dev/null +++ b/packages/web/src/components/UI/Badge.tsx @@ -0,0 +1,35 @@ +import { cn } from "@core/utils/cn.ts"; +import { cva, type VariantProps } from "class-variance-authority"; +import type * as React from "react"; + +const badgeVariants = cva( + "inline-flex items-center rounded-full border px-2.5 py-0.5 text-xs font-semibold transition-colors focus:outline-none focus:ring-2 focus:ring-slate-400 focus:ring-offset-2", + { + variants: { + variant: { + default: + "border-transparent bg-slate-900 text-white hover:bg-slate-900/80 dark:bg-slate-50 dark:text-slate-900 dark:hover:bg-slate-50/80", + secondary: + "border-transparent bg-slate-100 text-slate-900 hover:bg-slate-100/80 dark:bg-slate-800 dark:text-slate-100 dark:hover:bg-slate-800/80", + destructive: + "border-transparent bg-red-500 text-white hover:bg-red-500/80 dark:bg-red-900 dark:text-red-50 dark:hover:bg-red-900/80", + outline: "text-slate-900 dark:text-slate-100", + }, + }, + defaultVariants: { + variant: "default", + }, + }, +); + +export interface BadgeProps + extends React.HTMLAttributes, + VariantProps {} + +function Badge({ className, variant, ...props }: BadgeProps) { + return ( +
    + ); +} + +export { Badge, badgeVariants }; diff --git a/packages/web/src/components/UI/Card.tsx b/packages/web/src/components/UI/Card.tsx new file mode 100644 index 000000000..e67e1b38a --- /dev/null +++ b/packages/web/src/components/UI/Card.tsx @@ -0,0 +1,85 @@ +import { cn } from "@core/utils/cn.ts"; +import * as React from "react"; + +const Card = React.forwardRef< + HTMLDivElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +
    +)); +Card.displayName = "Card"; + +const CardHeader = React.forwardRef< + HTMLDivElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +
    +)); +CardHeader.displayName = "CardHeader"; + +const CardTitle = React.forwardRef< + HTMLParagraphElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +

    +)); +CardTitle.displayName = "CardTitle"; + +const CardDescription = React.forwardRef< + HTMLParagraphElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +

    +)); +CardDescription.displayName = "CardDescription"; + +const CardContent = React.forwardRef< + HTMLDivElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +

    +)); +CardContent.displayName = "CardContent"; + +const CardFooter = React.forwardRef< + HTMLDivElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +
    +)); +CardFooter.displayName = "CardFooter"; + +export { + Card, + CardContent, + CardDescription, + CardFooter, + CardHeader, + CardTitle, +}; diff --git a/packages/web/src/components/UI/ErrorPage.tsx b/packages/web/src/components/UI/ErrorPage.tsx index 2cd2b638a..c35a74df8 100644 --- a/packages/web/src/components/UI/ErrorPage.tsx +++ b/packages/web/src/components/UI/ErrorPage.tsx @@ -48,8 +48,8 @@ export function ErrorPage({ error }: { error: Error }) {

    ]} + i18nKey="errorPage.connectionsLink" + components={[]} />

    diff --git a/packages/web/src/components/UI/Sidebar/SidebarButton.tsx b/packages/web/src/components/UI/Sidebar/SidebarButton.tsx index c3cb5c289..ea1f8d1e9 100644 --- a/packages/web/src/components/UI/Sidebar/SidebarButton.tsx +++ b/packages/web/src/components/UI/Sidebar/SidebarButton.tsx @@ -70,7 +70,7 @@ export const SidebarButton = ({ "flex-shrink-0", "transition-opacity duration-300 ease-in-out", isButtonCollapsed ? "opacity-0 invisible" : "opacity-100 visible", - isDirty ? "bg-sky-500" : "bg-red-600", + isDirty ? "bg-sky-500" : "bg-blue-500", )} > {count} diff --git a/packages/web/src/components/UI/Sidebar/SidebarSection.tsx b/packages/web/src/components/UI/Sidebar/SidebarSection.tsx index f0b52d4b7..e43c46bb3 100644 --- a/packages/web/src/components/UI/Sidebar/SidebarSection.tsx +++ b/packages/web/src/components/UI/Sidebar/SidebarSection.tsx @@ -21,7 +21,7 @@ export const SidebarSection = ({ as="h3" className={cn( "mb-2", - "uppercase tracking-wider text-md", + "capitalize tracking-wider text-sm", "transition-all duration-300 ease-in-out", "whitespace-nowrap overflow-hidden", isCollapsed diff --git a/packages/web/src/components/UI/Skeleton.tsx b/packages/web/src/components/UI/Skeleton.tsx new file mode 100644 index 000000000..07237aca9 --- /dev/null +++ b/packages/web/src/components/UI/Skeleton.tsx @@ -0,0 +1,18 @@ +import { cn } from "@core/utils/cn.ts"; + +function Skeleton({ + className, + ...props +}: React.HTMLAttributes) { + return ( +
    + ); +} + +export { Skeleton }; diff --git a/packages/web/src/components/UI/Switch.tsx b/packages/web/src/components/UI/Switch.tsx index 343e8d525..d99e2166b 100644 --- a/packages/web/src/components/UI/Switch.tsx +++ b/packages/web/src/components/UI/Switch.tsx @@ -3,7 +3,7 @@ import * as SwitchPrimitives from "@radix-ui/react-switch"; import * as React from "react"; const Switch = React.forwardRef< - React.ElementRef, + React.ComponentRef, React.ComponentPropsWithoutRef >(({ className, ...props }, ref) => ( )); + Switch.displayName = SwitchPrimitives.Root.displayName; export { Switch }; diff --git a/packages/web/src/components/UI/Typography/Code.tsx b/packages/web/src/components/UI/Typography/Code.tsx index 7f80886c4..b6102b7af 100644 --- a/packages/web/src/components/UI/Typography/Code.tsx +++ b/packages/web/src/components/UI/Typography/Code.tsx @@ -3,7 +3,7 @@ export interface CodeProps { } export const Code = ({ children }: CodeProps) => ( - + {children} ); diff --git a/packages/web/src/core/hooks/useLRUList.ts b/packages/web/src/core/hooks/useLRUList.ts new file mode 100644 index 000000000..d28fb61b2 --- /dev/null +++ b/packages/web/src/core/hooks/useLRUList.ts @@ -0,0 +1,232 @@ +import { useCallback, useEffect, useMemo, useRef, useState } from "react"; + +/** + * A minimal serializable wrapper so we can store metadata alongside items. + */ +type PersistedPayload = { + v: 1; // schema version + capacity: number; // last used capacity (for info/migrations) + items: J[]; // serialized items (MRU -> LRU) +}; + +export type UseLRUListOptions = { + /** localStorage key */ + key: string; + /** max number of items to keep (>=1) */ + capacity: number; + /** optional initial items used when storage is empty/invalid */ + initial?: T[]; + /** equality to de-duplicate items; default: Object.is */ + eq?: (a: T, b: T) => boolean; + /** convert T -> JSON-safe type; default: (x) => x as unknown as J */ + toJSON?: (t: T) => J; + /** convert JSON-safe type -> T; default: (x) => x as unknown as T */ + fromJSON?: (j: J) => T; + /** storage impl (for tests); default: window.localStorage */ + storage?: Storage; + /** listen to storage events and live-sync across tabs/windows; default: true */ + syncTabs?: boolean; +}; + +export type UseLRUListReturn = { + /** Items ordered MRU -> LRU */ + items: T[]; + /** Add or "touch" an item (move to MRU); inserts if missing */ + add: (item: T) => void; + /** Remove a matching item (no-op if missing) */ + remove: (item: T) => void; + /** Clear all items */ + clear: () => void; + /** Whether a matching item exists */ + has: (item: T) => boolean; + /** Replace the entire list (applies LRU trimming) */ + replaceAll: (next: T[]) => void; + /** Current capacity (for information) */ + capacity: number; +}; + +/** + * useLRUList – maintains a most-recently-used list and persists it to localStorage. + * + * MRU is index 0. Adding an existing item "touches" it (moves to front). + */ +export function useLRUList( + opts: UseLRUListOptions, +): UseLRUListReturn { + const { + key, + capacity, + initial = [], + eq = Object.is, + toJSON = (x: T) => x as unknown as J, + fromJSON = (x: J) => x as unknown as T, + storage = typeof window !== "undefined" ? window.localStorage : undefined, + syncTabs = true, + } = opts; + + if (capacity < 1) { + // Fail fast in dev; silently coerce in prod + if (process.env.NODE_ENV !== "production") { + throw new Error("useLRUList: capacity must be >= 1"); + } + } + + const effectiveCapacity = Math.max(1, capacity); + + // Guard against SSR or no-storage environments + const canPersist = !!storage && typeof storage.getItem === "function"; + + const readPersisted = useCallback((): T[] | null => { + if (!canPersist) { + return null; + } + try { + const raw = storage.getItem(key); + if (!raw) { + return null; + } + const parsed = JSON.parse(raw) as PersistedPayload; + if (!parsed || parsed.v !== 1 || !Array.isArray(parsed.items)) { + return null; + } + const deserialized = parsed.items.map(fromJSON); + return trimToCapacity(deserialized, effectiveCapacity); + } catch { + return null; + } + }, [canPersist, storage, key, fromJSON, effectiveCapacity]); + + const writePersisted = useCallback( + (items: T[]) => { + if (!canPersist) { + return; + } + try { + const payload: PersistedPayload = { + v: 1, + capacity: effectiveCapacity, + items: items.map(toJSON), + }; + storage.setItem(key, JSON.stringify(payload)); + } catch { + // Swallow quota/serialization errors; keep in-memory state working + } + }, + [canPersist, storage, key, toJSON, effectiveCapacity], + ); + + // Initialize from storage (or fallback to `initial`) + const [items, setItems] = useState( + () => readPersisted() ?? trimToCapacity([...initial], effectiveCapacity), + ); + + // Keep a ref to avoid feedback loops when applying remote (storage event) updates + const applyingExternal = useRef(false); + + // Persist on changes + useEffect(() => { + if (applyingExternal.current) { + applyingExternal.current = false; + return; + } + writePersisted(items); + }, [items, writePersisted]); + + // Cross-tab synchronization via storage events + useEffect(() => { + if (!syncTabs || !canPersist || typeof window === "undefined") { + return; + } + const onStorage = (e: StorageEvent) => { + if (e.storageArea !== storage || e.key !== key) { + return; + } + // Another tab changed it; re-read safely + const next = readPersisted(); + if (!next) { + return; + } + applyingExternal.current = true; + setItems(next); + }; + window.addEventListener("storage", onStorage); + return () => window.removeEventListener("storage", onStorage); + }, [syncTabs, canPersist, storage, key, readPersisted]); + + // Helpers + const indexOf = useCallback( + (arr: T[], needle: T) => arr.findIndex((x) => eq(x, needle)), + [eq], + ); + + const add = useCallback( + (item: T) => { + setItems((prev) => { + const idx = indexOf(prev, item); + if (idx === 0) { + return prev; // already MRU + } + if (idx > 0) { + const next = [...prev]; + next.splice(idx, 1); + next.unshift(item); + return next; + } + // Not present: insert at MRU and trim + const next = [item, ...prev]; + return trimToCapacity(next, effectiveCapacity); + }); + }, + [indexOf, effectiveCapacity], + ); + + const remove = useCallback( + (item: T) => { + setItems((prev) => { + const idx = indexOf(prev, item); + if (idx === -1) { + return prev; + } + const next = [...prev]; + next.splice(idx, 1); + return next; + }); + }, + [indexOf], + ); + + const clear = useCallback(() => setItems([]), []); + + const has = useCallback( + (item: T) => indexOf(items, item) !== -1, + [items, indexOf], + ); + + const replaceAll = useCallback( + (next: T[]) => setItems(trimToCapacity([...next], effectiveCapacity)), + [effectiveCapacity], + ); + + // Stable API shape + return useMemo( + () => ({ + items, + add, + remove, + clear, + has, + replaceAll, + capacity: effectiveCapacity, + }), + [items, add, remove, clear, has, replaceAll, effectiveCapacity], + ); +} + +// --- utils --- + +function trimToCapacity(arr: T[], capacity: number): T[] { + if (arr.length <= capacity) { + return arr; + } + return arr.slice(0, capacity); +} diff --git a/packages/web/src/core/hooks/useLang.ts b/packages/web/src/core/hooks/useLang.ts index 6cc7f748d..30282eeb3 100644 --- a/packages/web/src/core/hooks/useLang.ts +++ b/packages/web/src/core/hooks/useLang.ts @@ -50,6 +50,11 @@ function useLang() { [i18n.language, i18n.changeLanguage, setLanguageInStorage], ); + const getSupportedLangs = useMemo( + () => supportedLanguages.toSorted((a, b) => a.name.localeCompare(b.name)), + [], + ); + const compare = useCallback( (a: string, b: string) => { return collator.compare(a, b); @@ -57,7 +62,7 @@ function useLang() { [collator], ); - return { compare, set, currentLanguage }; + return { compare, set, current: currentLanguage, getSupportedLangs }; } export default useLang; diff --git a/packages/web/src/core/services/dev-overrides.ts b/packages/web/src/core/services/dev-overrides.ts index 928c43a59..59c060de9 100644 --- a/packages/web/src/core/services/dev-overrides.ts +++ b/packages/web/src/core/services/dev-overrides.ts @@ -7,5 +7,6 @@ if (isDev) { featureFlags.setOverrides({ persistNodeDB: true, persistMessages: true, + persistApp: true, }); } diff --git a/packages/web/src/core/services/featureFlags.ts b/packages/web/src/core/services/featureFlags.ts index 645861b64..48e72e6a0 100644 --- a/packages/web/src/core/services/featureFlags.ts +++ b/packages/web/src/core/services/featureFlags.ts @@ -4,6 +4,8 @@ import { z } from "zod"; export const FLAG_ENV = { persistNodeDB: "VITE_PERSIST_NODE_DB", persistMessages: "VITE_PERSIST_MESSAGES", + persistDevices: "VITE_PERSIST_DEVICES", + persistApp: "VITE_PERSIST_APP", } as const; export type FlagKey = keyof typeof FLAG_ENV; diff --git a/packages/web/src/core/stores/appStore/appStore.test.ts b/packages/web/src/core/stores/appStore/appStore.test.ts new file mode 100644 index 000000000..7ebe8ca0e --- /dev/null +++ b/packages/web/src/core/stores/appStore/appStore.test.ts @@ -0,0 +1,177 @@ +import type { RasterSource } from "@core/stores/appStore/types.ts"; +import { beforeEach, describe, expect, it, vi } from "vitest"; + +const idbMem = new Map(); +vi.mock("idb-keyval", () => ({ + get: vi.fn((key: string) => Promise.resolve(idbMem.get(key))), + set: vi.fn((key: string, val: string) => { + idbMem.set(key, val); + return Promise.resolve(); + }), + del: vi.fn((key: string) => { + idbMem.delete(key); + return Promise.resolve(); + }), +})); + +async function freshStore(persistApp = false) { + vi.resetModules(); + + vi.spyOn(console, "debug").mockImplementation(() => {}); + vi.spyOn(console, "log").mockImplementation(() => {}); + vi.spyOn(console, "info").mockImplementation(() => {}); + + vi.doMock("@core/services/featureFlags.ts", () => ({ + featureFlags: { + get: vi.fn((key: string) => (key === "persistApp" ? persistApp : false)), + }, + })); + + const storeMod = await import("./index.ts"); + return storeMod as typeof import("./index.ts"); +} + +function makeRaster(fields: Record): RasterSource { + return { + enabled: true, + title: "default", + tiles: `https://default.com/default.json`, + tileSize: 256, + ...fields, + }; +} + +describe("AppStore – basic state & actions", () => { + beforeEach(() => { + idbMem.clear(); + vi.clearAllMocks(); + }); + + it("setters flip UI flags and numeric fields", async () => { + const { useAppStore } = await freshStore(false); + const state = useAppStore.getState(); + + state.setSelectedDevice(42); + expect(useAppStore.getState().selectedDeviceId).toBe(42); + + state.setCommandPaletteOpen(true); + expect(useAppStore.getState().commandPaletteOpen).toBe(true); + + state.setConnectDialogOpen(true); + expect(useAppStore.getState().connectDialogOpen).toBe(true); + + state.setNodeNumToBeRemoved(123); + expect(useAppStore.getState().nodeNumToBeRemoved).toBe(123); + + state.setNodeNumDetails(777); + expect(useAppStore.getState().nodeNumDetails).toBe(777); + }); + + it("setRasterSources replaces; addRasterSource appends; removeRasterSource splices by index", async () => { + const { useAppStore } = await freshStore(false); + const state = useAppStore.getState(); + + const a = makeRaster({ title: "a" }); + const b = makeRaster({ title: "b" }); + const c = makeRaster({ title: "c" }); + + state.setRasterSources([a, b]); + expect( + useAppStore.getState().rasterSources.map((raster) => raster.title), + ).toEqual(["a", "b"]); + + state.addRasterSource(c); + expect( + useAppStore.getState().rasterSources.map((raster) => raster.title), + ).toEqual(["a", "b", "c"]); + + // "b" + state.removeRasterSource(1); + expect( + useAppStore.getState().rasterSources.map((raster) => raster.title), + ).toEqual(["a", "c"]); + }); +}); + +describe("AppStore – persistence: partialize + rehydrate", () => { + beforeEach(() => { + idbMem.clear(); + vi.clearAllMocks(); + }); + + it("persists only rasterSources; methods still work after rehydrate", async () => { + // Write data + { + const { useAppStore } = await freshStore(true); + const state = useAppStore.getState(); + + state.setRasterSources([ + makeRaster({ title: "x" }), + makeRaster({ title: "y" }), + ]); + state.setSelectedDevice(99); + state.setCommandPaletteOpen(true); + // Only rasterSources should persist by partialize + expect(useAppStore.getState().rasterSources.length).toBe(2); + } + + // Rehydrate from idbMem + { + const { useAppStore } = await freshStore(true); + const state = useAppStore.getState(); + + // persisted slice: + expect(state.rasterSources.map((raster) => raster.title)).toEqual([ + "x", + "y", + ]); + + // ephemeral fields reset to defaults: + expect(state.selectedDeviceId).toBe(0); + expect(state.commandPaletteOpen).toBe(false); + expect(state.connectDialogOpen).toBe(false); + expect(state.nodeNumToBeRemoved).toBe(0); + expect(state.nodeNumDetails).toBe(0); + + // methods still work post-rehydrate: + state.addRasterSource(makeRaster({ title: "z" })); + expect( + useAppStore.getState().rasterSources.map((raster) => raster.title), + ).toEqual(["x", "y", "z"]); + state.removeRasterSource(0); + expect( + useAppStore.getState().rasterSources.map((raster) => raster.title), + ).toEqual(["y", "z"]); + } + }); + + it("removing and resetting sources persists across reload", async () => { + { + const { useAppStore } = await freshStore(true); + const state = useAppStore.getState(); + state.setRasterSources([ + makeRaster({ title: "keep" }), + makeRaster({ title: "drop" }), + ]); + state.removeRasterSource(1); // drop "drop" + expect( + useAppStore.getState().rasterSources.map((raster) => raster.title), + ).toEqual(["keep"]); + } + { + const { useAppStore } = await freshStore(true); + const state = useAppStore.getState(); + expect(state.rasterSources.map((raster) => raster.title)).toEqual([ + "keep", + ]); + + // Now replace entirely + state.setRasterSources([]); + } + { + const { useAppStore } = await freshStore(true); + const state = useAppStore.getState(); + expect(state.rasterSources).toEqual([]); // stayed cleared + } + }); +}); diff --git a/packages/web/src/core/stores/appStore/index.ts b/packages/web/src/core/stores/appStore/index.ts index 1f342c291..72034911d 100644 --- a/packages/web/src/core/stores/appStore/index.ts +++ b/packages/web/src/core/stores/appStore/index.ts @@ -1,41 +1,42 @@ +import { featureFlags } from "@core/services/featureFlags.ts"; +import { createStorage } from "@core/stores/utils/indexDB.ts"; import { produce } from "immer"; -import { create } from "zustand"; +import { create as createStore, type StateCreator } from "zustand"; +import { + type PersistOptions, + persist, + subscribeWithSelector, +} from "zustand/middleware"; +import type { RasterSource } from "./types.ts"; -export interface RasterSource { - enabled: boolean; - title: string; - tiles: string; - tileSize: number; -} +const IDB_KEY_NAME = "meshtastic-app-store"; +const CURRENT_STORE_VERSION = 0; -interface AppState { - selectedDeviceId: number; - devices: { - id: number; - num: number; - }[]; +type AppData = { + // Persisted data rasterSources: RasterSource[]; - commandPaletteOpen: boolean; +}; + +export interface AppState extends AppData { + // Ephemeral state (not persisted) + selectedDeviceId: number; nodeNumToBeRemoved: number; connectDialogOpen: boolean; nodeNumDetails: number; + commandPaletteOpen: boolean; setRasterSources: (sources: RasterSource[]) => void; addRasterSource: (source: RasterSource) => void; removeRasterSource: (index: number) => void; setSelectedDevice: (deviceId: number) => void; - addDevice: (device: { id: number; num: number }) => void; - removeDevice: (deviceId: number) => void; setCommandPaletteOpen: (open: boolean) => void; setNodeNumToBeRemoved: (nodeNum: number) => void; setConnectDialogOpen: (open: boolean) => void; setNodeNumDetails: (nodeNum: number) => void; } -export const useAppStore = create()((set, _get) => ({ +export const deviceStoreInitializer: StateCreator = (set, _get) => ({ selectedDeviceId: 0, - devices: [], - currentPage: "messages", rasterSources: [], commandPaletteOpen: false, connectDialogOpen: false, @@ -67,14 +68,6 @@ export const useAppStore = create()((set, _get) => ({ set(() => ({ selectedDeviceId: deviceId, })), - addDevice: (device) => - set((state) => ({ - devices: [...state.devices, device], - })), - removeDevice: (deviceId) => - set((state) => ({ - devices: state.devices.filter((device) => device.id !== deviceId), - })), setCommandPaletteOpen: (open: boolean) => { set( produce((draft) => { @@ -93,9 +86,35 @@ export const useAppStore = create()((set, _get) => ({ }), ); }, - setNodeNumDetails: (nodeNum) => set(() => ({ nodeNumDetails: nodeNum, })), -})); +}); + +const persistOptions: PersistOptions = { + name: IDB_KEY_NAME, + storage: createStorage(), + version: CURRENT_STORE_VERSION, + partialize: (s): AppData => ({ + rasterSources: s.rasterSources, + }), + onRehydrateStorage: () => (state) => { + if (!state) { + return; + } + console.debug("AppStore: Rehydrating state", state); + }, +}; + +// Add persist middleware on the store if the feature flag is enabled +const persistApps = featureFlags.get("persistApp"); +console.debug( + `AppStore: Persisting app is ${persistApps ? "enabled" : "disabled"}`, +); + +export const useAppStore = persistApps + ? createStore( + subscribeWithSelector(persist(deviceStoreInitializer, persistOptions)), + ) + : createStore(subscribeWithSelector(deviceStoreInitializer)); diff --git a/packages/web/src/core/stores/appStore/types.ts b/packages/web/src/core/stores/appStore/types.ts new file mode 100644 index 000000000..3b673c994 --- /dev/null +++ b/packages/web/src/core/stores/appStore/types.ts @@ -0,0 +1,6 @@ +export interface RasterSource { + enabled: boolean; + title: string; + tiles: string; + tileSize: number; +} diff --git a/packages/web/src/core/stores/deviceStore/changeRegistry.ts b/packages/web/src/core/stores/deviceStore/changeRegistry.ts new file mode 100644 index 000000000..844ed8db7 --- /dev/null +++ b/packages/web/src/core/stores/deviceStore/changeRegistry.ts @@ -0,0 +1,260 @@ +import type { Types } from "@meshtastic/core"; + +// Config type discriminators +export type ValidConfigType = + | "device" + | "position" + | "power" + | "network" + | "display" + | "lora" + | "bluetooth" + | "security"; + +export type ValidModuleConfigType = + | "mqtt" + | "serial" + | "externalNotification" + | "storeForward" + | "rangeTest" + | "telemetry" + | "cannedMessage" + | "audio" + | "neighborInfo" + | "ambientLighting" + | "detectionSensor" + | "paxcounter"; + +// Admin message types that can be queued +export type ValidAdminMessageType = "setFixedPosition" | "other"; + +// Unified config change key type +export type ConfigChangeKey = + | { type: "config"; variant: ValidConfigType } + | { type: "moduleConfig"; variant: ValidModuleConfigType } + | { type: "channel"; index: Types.ChannelNumber } + | { type: "user" } + | { type: "adminMessage"; variant: ValidAdminMessageType; id: string }; + +// Serialized key for Map storage +export type ConfigChangeKeyString = string; + +// Registry entry +export interface ChangeEntry { + key: ConfigChangeKey; + value: unknown; + timestamp: number; + originalValue?: unknown; +} + +// The unified registry +export interface ChangeRegistry { + changes: Map; +} + +/** + * Convert structured key to string for Map lookup + */ +export function serializeKey(key: ConfigChangeKey): ConfigChangeKeyString { + switch (key.type) { + case "config": + return `config:${key.variant}`; + case "moduleConfig": + return `moduleConfig:${key.variant}`; + case "channel": + return `channel:${key.index}`; + case "user": + return "user"; + case "adminMessage": + return `adminMessage:${key.variant}:${key.id}`; + } +} + +/** + * Reverse operation for type-safe retrieval + */ +export function deserializeKey(keyStr: ConfigChangeKeyString): ConfigChangeKey { + const parts = keyStr.split(":"); + const type = parts[0]; + + switch (type) { + case "config": + return { type: "config", variant: parts[1] as ValidConfigType }; + case "moduleConfig": + return { + type: "moduleConfig", + variant: parts[1] as ValidModuleConfigType, + }; + case "channel": + return { + type: "channel", + index: Number(parts[1]) as Types.ChannelNumber, + }; + case "user": + return { type: "user" }; + case "adminMessage": + return { + type: "adminMessage", + variant: parts[1] as ValidAdminMessageType, + id: parts[2] ?? "", + }; + default: + throw new Error(`Unknown key type: ${type}`); + } +} + +/** + * Create an empty change registry + */ +export function createChangeRegistry(): ChangeRegistry { + return { + changes: new Map(), + }; +} + +/** + * Check if a config variant has changes + */ +export function hasConfigChange( + registry: ChangeRegistry, + variant: ValidConfigType, +): boolean { + return registry.changes.has(serializeKey({ type: "config", variant })); +} + +/** + * Check if a module config variant has changes + */ +export function hasModuleConfigChange( + registry: ChangeRegistry, + variant: ValidModuleConfigType, +): boolean { + return registry.changes.has(serializeKey({ type: "moduleConfig", variant })); +} + +/** + * Check if a channel has changes + */ +export function hasChannelChange( + registry: ChangeRegistry, + index: Types.ChannelNumber, +): boolean { + return registry.changes.has(serializeKey({ type: "channel", index })); +} + +/** + * Check if user config has changes + */ +export function hasUserChange(registry: ChangeRegistry): boolean { + return registry.changes.has(serializeKey({ type: "user" })); +} + +/** + * Get count of config changes + */ +export function getConfigChangeCount(registry: ChangeRegistry): number { + let count = 0; + for (const keyStr of registry.changes.keys()) { + const key = deserializeKey(keyStr); + if (key.type === "config") { + count++; + } + } + return count; +} + +/** + * Get count of module config changes + */ +export function getModuleConfigChangeCount(registry: ChangeRegistry): number { + let count = 0; + for (const keyStr of registry.changes.keys()) { + const key = deserializeKey(keyStr); + if (key.type === "moduleConfig") { + count++; + } + } + return count; +} + +/** + * Get count of channel changes + */ +export function getChannelChangeCount(registry: ChangeRegistry): number { + let count = 0; + for (const keyStr of registry.changes.keys()) { + const key = deserializeKey(keyStr); + if (key.type === "channel") { + count++; + } + } + return count; +} + +/** + * Get all config changes as an array + */ +export function getAllConfigChanges(registry: ChangeRegistry): ChangeEntry[] { + const changes: ChangeEntry[] = []; + for (const entry of registry.changes.values()) { + if (entry.key.type === "config") { + changes.push(entry); + } + } + return changes; +} + +/** + * Get all module config changes as an array + */ +export function getAllModuleConfigChanges( + registry: ChangeRegistry, +): ChangeEntry[] { + const changes: ChangeEntry[] = []; + for (const entry of registry.changes.values()) { + if (entry.key.type === "moduleConfig") { + changes.push(entry); + } + } + return changes; +} + +/** + * Get all channel changes as an array + */ +export function getAllChannelChanges(registry: ChangeRegistry): ChangeEntry[] { + const changes: ChangeEntry[] = []; + for (const entry of registry.changes.values()) { + if (entry.key.type === "channel") { + changes.push(entry); + } + } + return changes; +} + +/** + * Get all admin message changes as an array + */ +export function getAllAdminMessages(registry: ChangeRegistry): ChangeEntry[] { + const changes: ChangeEntry[] = []; + for (const entry of registry.changes.values()) { + if (entry.key.type === "adminMessage") { + changes.push(entry); + } + } + return changes; +} + +/** + * Get count of admin message changes + */ +export function getAdminMessageChangeCount(registry: ChangeRegistry): number { + let count = 0; + for (const keyStr of registry.changes.keys()) { + const key = deserializeKey(keyStr); + if (key.type === "adminMessage") { + count++; + } + } + return count; +} diff --git a/packages/web/src/core/stores/deviceStore/deviceStore.mock.ts b/packages/web/src/core/stores/deviceStore/deviceStore.mock.ts index 06040336b..eb67f7bf1 100644 --- a/packages/web/src/core/stores/deviceStore/deviceStore.mock.ts +++ b/packages/web/src/core/stores/deviceStore/deviceStore.mock.ts @@ -14,13 +14,12 @@ import type { Device } from "./index.ts"; */ export const mockDeviceStore: Device = { id: 0, + myNodeNum: 123456, status: 5 as const, channels: new Map(), config: {} as Protobuf.LocalOnly.LocalConfig, moduleConfig: {} as Protobuf.LocalOnly.LocalModuleConfig, - workingConfig: [], - workingModuleConfig: [], - workingChannelConfig: [], + changeRegistry: { changes: new Map() }, hardware: {} as Protobuf.Mesh.MyNodeInfo, metadata: new Map(), traceroutes: new Map(), @@ -44,28 +43,26 @@ export const mockDeviceStore: Device = { deleteMessages: false, managedMode: false, clientNotification: false, + resetNodeDb: false, + clearAllStores: false, + factoryResetConfig: false, + factoryResetDevice: false, }, clientNotifications: [], + neighborInfo: new Map(), setStatus: vi.fn(), setConfig: vi.fn(), setModuleConfig: vi.fn(), - setWorkingConfig: vi.fn(), - setWorkingModuleConfig: vi.fn(), - getWorkingConfig: vi.fn(), - getWorkingModuleConfig: vi.fn(), - removeWorkingConfig: vi.fn(), - removeWorkingModuleConfig: vi.fn(), getEffectiveConfig: vi.fn(), getEffectiveModuleConfig: vi.fn(), - setWorkingChannelConfig: vi.fn(), - getWorkingChannelConfig: vi.fn(), - removeWorkingChannelConfig: vi.fn(), setHardware: vi.fn(), setActiveNode: vi.fn(), setPendingSettingsChanges: vi.fn(), addChannel: vi.fn(), addWaypoint: vi.fn(), + removeWaypoint: vi.fn(), + getWaypoint: vi.fn(), addConnection: vi.fn(), addTraceRoute: vi.fn(), addMetadata: vi.fn(), @@ -80,4 +77,23 @@ export const mockDeviceStore: Device = { getClientNotification: vi.fn(), getAllUnreadCount: vi.fn().mockReturnValue(0), getUnreadCount: vi.fn().mockReturnValue(0), + getNeighborInfo: vi.fn(), + addNeighborInfo: vi.fn(), + + // New unified change tracking methods + setChange: vi.fn(), + removeChange: vi.fn(), + hasChange: vi.fn().mockReturnValue(false), + getChange: vi.fn(), + clearAllChanges: vi.fn(), + hasConfigChange: vi.fn().mockReturnValue(false), + hasModuleConfigChange: vi.fn().mockReturnValue(false), + hasChannelChange: vi.fn().mockReturnValue(false), + hasUserChange: vi.fn().mockReturnValue(false), + getConfigChangeCount: vi.fn().mockReturnValue(0), + getModuleConfigChangeCount: vi.fn().mockReturnValue(0), + getChannelChangeCount: vi.fn().mockReturnValue(0), + getAllConfigChanges: vi.fn().mockReturnValue([]), + getAllModuleConfigChanges: vi.fn().mockReturnValue([]), + getAllChannelChanges: vi.fn().mockReturnValue([]), }; diff --git a/packages/web/src/core/stores/deviceStore/deviceStore.test.ts b/packages/web/src/core/stores/deviceStore/deviceStore.test.ts new file mode 100644 index 000000000..f7644bdd4 --- /dev/null +++ b/packages/web/src/core/stores/deviceStore/deviceStore.test.ts @@ -0,0 +1,523 @@ +import { create, toBinary } from "@bufbuild/protobuf"; +import { Protobuf, type Types } from "@meshtastic/core"; +import { beforeEach, describe, expect, it, vi } from "vitest"; + +const idbMem = new Map(); +vi.mock("idb-keyval", () => ({ + get: vi.fn((key: string) => Promise.resolve(idbMem.get(key))), + set: vi.fn((key: string, val: string) => { + idbMem.set(key, val); + return Promise.resolve(); + }), + del: vi.fn((k: string) => { + idbMem.delete(k); + return Promise.resolve(); + }), +})); + +// Helper to load a fresh copy of the store with persist flag on/off +async function freshStore(persist = false) { + vi.resetModules(); + + // suppress console output from the store during tests (for github actions) + vi.spyOn(console, "debug").mockImplementation(() => {}); + vi.spyOn(console, "log").mockImplementation(() => {}); + vi.spyOn(console, "info").mockImplementation(() => {}); + + vi.doMock("@core/services/featureFlags", () => ({ + featureFlags: { + get: vi.fn((key: string) => (key === "persistDevices" ? persist : false)), + }, + })); + + const storeMod = await import("./index.ts"); + const { useNodeDB } = await import("../index.ts"); + return { ...storeMod, useNodeDB }; +} + +function makeHardware(myNodeNum: number) { + return create(Protobuf.Mesh.MyNodeInfoSchema, { myNodeNum }); +} +function makeRoute(from: number, time = Date.now() / 1000) { + return { + from, + rxTime: time, + portnum: Protobuf.Portnums.PortNum.ROUTING_APP, + data: create(Protobuf.Mesh.RouteDiscoverySchema, {}), + } as unknown as Types.PacketMetadata; +} +function makeChannel(index: number) { + return create(Protobuf.Channel.ChannelSchema, { index }); +} +function makeWaypoint(id: number, expire?: number) { + return create(Protobuf.Mesh.WaypointSchema, { id, expire }); +} + +function makeAdminMessage(fields: Record) { + return create(Protobuf.Admin.AdminMessageSchema, fields); +} + +describe("DeviceStore – basic map ops & retention", () => { + beforeEach(() => { + idbMem.clear(); + vi.clearAllMocks(); + }); + + it("addDevice returns same instance on repeated calls; getDevice(s) works; retention evicts oldest after cap", async () => { + const { useDeviceStore } = await freshStore(false); + const state = useDeviceStore.getState(); + + const a = state.addDevice(1); + const b = state.addDevice(1); + expect(a).toBe(b); + expect(state.getDevice(1)).toBe(a); + expect(state.getDevices().length).toBe(1); + + // DEVICESTORE_RETENTION_NUM = 10; create 11 to evict #1 + for (let i = 2; i <= 11; i++) { + state.addDevice(i); + } + expect(state.getDevice(1)).toBeUndefined(); + expect(state.getDevice(11)).toBeDefined(); + expect(state.getDevices().length).toBe(10); + }); + + it("removeDevice deletes only that entry", async () => { + const { useDeviceStore } = await freshStore(false); + const state = useDeviceStore.getState(); + state.addDevice(10); + state.addDevice(11); + expect(state.getDevices().length).toBe(2); + + state.removeDevice(10); + expect(state.getDevice(10)).toBeUndefined(); + expect(state.getDevice(11)).toBeDefined(); + expect(state.getDevices().length).toBe(1); + }); +}); + +describe("DeviceStore – change registry API", () => { + beforeEach(() => { + idbMem.clear(); + vi.clearAllMocks(); + }); + + it("setChange/hasChange/getChange for config and getEffectiveConfig merges base + working", async () => { + const { useDeviceStore } = await freshStore(false); + const state = useDeviceStore.getState(); + const device = state.addDevice(42); + + // config deviceConfig.role = CLIENT + device.setConfig( + create(Protobuf.Config.ConfigSchema, { + payloadVariant: { + case: "device", + value: create(Protobuf.Config.Config_DeviceConfigSchema, { + role: Protobuf.Config.Config_DeviceConfig_Role.CLIENT, + }), + }, + }), + ); + + // working deviceConfig.role = ROUTER + const routerConfig = create(Protobuf.Config.Config_DeviceConfigSchema, { + role: Protobuf.Config.Config_DeviceConfig_Role.ROUTER, + }); + device.setChange({ type: "config", variant: "device" }, routerConfig); + + // expect change is tracked + expect(device.hasConfigChange("device")).toBe(true); + const working = device.getChange({ + type: "config", + variant: "device", + }) as Protobuf.Config.Config_DeviceConfig; + expect(working?.role).toBe(Protobuf.Config.Config_DeviceConfig_Role.ROUTER); + + // expect effective deviceConfig.role = ROUTER + const effective = device.getEffectiveConfig("device"); + expect(effective?.role).toBe( + Protobuf.Config.Config_DeviceConfig_Role.ROUTER, + ); + + // remove change, effective should equal base + device.removeChange({ type: "config", variant: "device" }); + expect(device.hasConfigChange("device")).toBe(false); + expect(device.getEffectiveConfig("device")?.role).toBe( + Protobuf.Config.Config_DeviceConfig_Role.CLIENT, + ); + + // add multiple, then clear all + device.setChange({ type: "config", variant: "device" }, routerConfig); + device.setChange({ type: "config", variant: "position" }, {}); + device.clearAllChanges(); + expect(device.hasConfigChange("device")).toBe(false); + expect(device.hasConfigChange("position")).toBe(false); + }); + + it("setChange/hasChange for moduleConfig and getEffectiveModuleConfig", async () => { + const { useDeviceStore } = await freshStore(false); + const state = useDeviceStore.getState(); + const device = state.addDevice(7); + + // base moduleConfig.mqtt with base address + device.setModuleConfig( + create(Protobuf.ModuleConfig.ModuleConfigSchema, { + payloadVariant: { + case: "mqtt", + value: create(Protobuf.ModuleConfig.ModuleConfig_MQTTConfigSchema, { + address: "mqtt://base", + }), + }, + }), + ); + + // working mqtt config + const workingMqtt = create( + Protobuf.ModuleConfig.ModuleConfig_MQTTConfigSchema, + { address: "mqtt://working" }, + ); + device.setChange({ type: "moduleConfig", variant: "mqtt" }, workingMqtt); + + expect(device.hasModuleConfigChange("mqtt")).toBe(true); + const mqtt = device.getChange({ + type: "moduleConfig", + variant: "mqtt", + }) as Protobuf.ModuleConfig.ModuleConfig_MQTTConfig; + expect(mqtt?.address).toBe("mqtt://working"); + + // effective should return working value + expect(device.getEffectiveModuleConfig("mqtt")?.address).toBe( + "mqtt://working", + ); + + // remove change + device.removeChange({ type: "moduleConfig", variant: "mqtt" }); + expect(device.hasModuleConfigChange("mqtt")).toBe(false); + expect(device.getEffectiveModuleConfig("mqtt")?.address).toBe( + "mqtt://base", + ); + + // Clear all + device.setChange({ type: "moduleConfig", variant: "mqtt" }, workingMqtt); + device.clearAllChanges(); + expect(device.hasModuleConfigChange("mqtt")).toBe(false); + }); + + it("channel change tracking add/update/remove/get", async () => { + const { useDeviceStore } = await freshStore(false); + const state = useDeviceStore.getState(); + const device = state.addDevice(9); + + const channel0 = makeChannel(0); + const channel1 = create(Protobuf.Channel.ChannelSchema, { + index: 1, + settings: { name: "one" }, + }); + + device.setChange({ type: "channel", index: 0 }, channel0); + device.setChange({ type: "channel", index: 1 }, channel1); + + expect(device.hasChannelChange(0)).toBe(true); + expect(device.hasChannelChange(1)).toBe(true); + const ch0 = device.getChange({ type: "channel", index: 0 }) as + | Protobuf.Channel.Channel + | undefined; + expect(ch0?.index).toBe(0); + const ch1 = device.getChange({ type: "channel", index: 1 }) as + | Protobuf.Channel.Channel + | undefined; + expect(ch1?.settings?.name).toBe("one"); + + // update channel 1 + const channel1Updated = create(Protobuf.Channel.ChannelSchema, { + index: 1, + settings: { name: "uno" }, + }); + device.setChange({ type: "channel", index: 1 }, channel1Updated); + const ch1Updated = device.getChange({ type: "channel", index: 1 }) as + | Protobuf.Channel.Channel + | undefined; + expect(ch1Updated?.settings?.name).toBe("uno"); + + // remove specific + device.removeChange({ type: "channel", index: 1 }); + expect(device.hasChannelChange(1)).toBe(false); + + // remove all + device.clearAllChanges(); + expect(device.hasChannelChange(0)).toBe(false); + }); +}); + +describe("DeviceStore – metadata, dialogs, unread counts, message draft", () => { + beforeEach(() => { + idbMem.clear(); + vi.clearAllMocks(); + }); + + it("addMetadata stores by node id", async () => { + const { useDeviceStore } = await freshStore(false); + const state = useDeviceStore.getState(); + const device = state.addDevice(1); + + const metadata = create(Protobuf.Mesh.DeviceMetadataSchema, { + firmwareVersion: "1.2.3", + }); + device.addMetadata(123, metadata); + + expect(useDeviceStore.getState().devices.get(1)?.metadata.get(123)).toEqual( + metadata, + ); + }); + + it("dialogs set/get work and throw if device missing", async () => { + const { useDeviceStore } = await freshStore(false); + const state = useDeviceStore.getState(); + const device = state.addDevice(5); + + device.setDialogOpen("reboot", true); + expect(device.getDialogOpen("reboot")).toBe(true); + device.setDialogOpen("reboot", false); + expect(device.getDialogOpen("reboot")).toBe(false); + + // getDialogOpen uses getDevice or throws if device missing + state.removeDevice(5); + expect(() => device.getDialogOpen("reboot")).toThrow(/Device 5 not found/); + }); + + it("unread counts: increment/get/getAll/reset", async () => { + const { useDeviceStore } = await freshStore(false); + const state = useDeviceStore.getState(); + const device = state.addDevice(2); + + expect(device.getUnreadCount(10)).toBe(0); + device.incrementUnread(10); + device.incrementUnread(10); + device.incrementUnread(11); + expect(device.getUnreadCount(10)).toBe(2); + expect(device.getUnreadCount(11)).toBe(1); + expect(device.getAllUnreadCount()).toBe(3); + + device.resetUnread(10); + expect(device.getUnreadCount(10)).toBe(0); + expect(device.getAllUnreadCount()).toBe(1); + }); + + it("setMessageDraft stores the text", async () => { + const { useDeviceStore } = await freshStore(false); + const device = useDeviceStore.getState().addDevice(3); + device.setMessageDraft("hello"); + + expect(useDeviceStore.getState().devices.get(3)?.messageDraft).toBe( + "hello", + ); + }); +}); + +describe("DeviceStore – traceroutes & waypoints retention + merge on setHardware", () => { + beforeEach(() => { + idbMem.clear(); + vi.clearAllMocks(); + }); + + it("addTraceRoute appends and enforces per-target and target caps", async () => { + const { useDeviceStore } = await freshStore(false); + const state = useDeviceStore.getState(); + const device = state.addDevice(100); + + // Per target: cap = 100; push 101 for from=7 + for (let i = 0; i < 101; i++) { + device.addTraceRoute(makeRoute(7, i)); + } + + const routesFor7 = useDeviceStore + .getState() + .devices.get(100) + ?.traceroutes.get(7)!; + expect(routesFor7.length).toBe(100); + expect(routesFor7[0]?.rxTime).toBe(1); // first (0) evicted + + // Target map cap: 100 keys, add 101 unique "from" + for (let from = 0; from <= 100; from++) { + device.addTraceRoute(makeRoute(1000 + from)); + } + + const keys = Array.from( + useDeviceStore.getState().devices.get(100)!.traceroutes.keys(), + ); + expect(keys.length).toBe(100); + }); + + it("addWaypoint upserts by id and enforces retention; setHardware moves traceroutes + prunes expired waypoints", async () => { + vi.setSystemTime(new Date("2025-01-01T00:00:00Z")); + const { useDeviceStore } = await freshStore(false); + const state = useDeviceStore.getState(); + + // Old device with myNodeNum=777 and some waypoints (one expired) + const oldDevice = state.addDevice(1); + const mockSendWaypoint = vi.fn(); + oldDevice.addConnection({ sendWaypoint: mockSendWaypoint } as any); + + oldDevice.setHardware(makeHardware(777)); + oldDevice.addWaypoint( + makeWaypoint(1, Date.parse("2024-12-31T23:59:59Z")), // This is expired, will not be added + 0, + 0, + new Date(), + ); // expired + oldDevice.addWaypoint(makeWaypoint(2, 0), 0, 0, new Date()); // no expire + oldDevice.addWaypoint( + makeWaypoint(3, Date.parse("2026-01-01T00:00:00Z")), + 0, + 0, + new Date(), + ); // ok + oldDevice.addTraceRoute(makeRoute(55)); + oldDevice.addTraceRoute(makeRoute(56)); + + // Upsert waypoint by id + oldDevice.addWaypoint( + makeWaypoint(2, Date.parse("2027-01-01T00:00:00Z")), + 0, + 0, + new Date(), + ); + + const wps = useDeviceStore.getState().devices.get(1)!.waypoints; + expect(wps.length).toBe(2); + expect(wps.find((w) => w.id === 2)?.expire).toBe( + Date.parse("2027-01-01T00:00:00Z"), + ); + + // Retention: push 102 total waypoints -> capped at 100. Oldest evicted + for (let i = 3; i <= 102; i++) { + oldDevice.addWaypoint(makeWaypoint(i), 0, 0, new Date()); + } + + expect(useDeviceStore.getState().devices.get(1)!.waypoints.length).toBe( + 100, + ); + + // Remove waypoint + oldDevice.removeWaypoint(102, false); + expect(mockSendWaypoint).not.toHaveBeenCalled(); + + await oldDevice.removeWaypoint(101, true); // toMesh=true + expect(mockSendWaypoint).toHaveBeenCalled(); + + expect(useDeviceStore.getState().devices.get(1)!.waypoints.length).toBe(98); + + // New device shares myNodeNum; setHardware should: + // - move traceroutes from old device + // - copy waypoints minus expired + // - delete old device entry + const newDevice = state.addDevice(2); + newDevice.setHardware(makeHardware(777)); + + expect(state.getDevice(1)).toBeUndefined(); + expect(state.getDevice(2)).toBeDefined(); + + // traceroutes moved: + expect(state.getDevice(2)!.traceroutes.size).toBe(2); + + // Getter for waypoint by id works + expect(newDevice.getWaypoint(1)).toBeUndefined(); + expect(newDevice.getWaypoint(2)).toBeUndefined(); + expect(newDevice.getWaypoint(3)).toBeTruthy(); + + vi.useRealTimers(); + }); +}); + +describe("DeviceStore – persistence partialize & rehydrate", () => { + beforeEach(() => { + idbMem.clear(); + vi.clearAllMocks(); + }); + + it("partialize stores only DeviceData; onRehydrateStorage rebuilds only devices with myNodeNum set (orphans dropped)", async () => { + // First run: persist=true + { + const { useDeviceStore } = await freshStore(true); + const state = useDeviceStore.getState(); + + const orphan = state.addDevice(500); // no myNodeNum -> should be dropped + orphan.addWaypoint(makeWaypoint(123), 0, 0, new Date()); + + const good = state.addDevice(501); + good.setHardware(makeHardware(42)); // sets myNodeNum + good.addTraceRoute(makeRoute(77)); + good.addWaypoint(makeWaypoint(1), 0, 0, new Date()); + // ensure some ephemeral fields differ so we can verify methods work after rehydrate + good.setMessageDraft("draft"); + } + + // Reload: persist=true -> rehydrate from idbMem + { + const { useDeviceStore } = await freshStore(true); + const state = useDeviceStore.getState(); + + expect(state.getDevice(500)).toBeUndefined(); // orphan dropped + const device = state.getDevice(501)!; + expect(device).toBeDefined(); + + // methods should work + device.addWaypoint(makeWaypoint(2), 0, 0, new Date()); + expect( + useDeviceStore.getState().devices.get(501)!.waypoints.length, + ).toBeGreaterThan(0); + + // traceroutes survived + expect( + useDeviceStore.getState().devices.get(501)!.traceroutes.size, + ).toBeGreaterThan(0); + } + }); + + it("removing a device persists across reload", async () => { + { + const { useDeviceStore } = await freshStore(true); + const state = useDeviceStore.getState(); + const device = state.addDevice(900); + device.setHardware(makeHardware(9)); // ensure it will be rehydrated + expect(state.getDevice(900)).toBeDefined(); + state.removeDevice(900); + expect(state.getDevice(900)).toBeUndefined(); + } + { + const { useDeviceStore } = await freshStore(true); + expect(useDeviceStore.getState().getDevice(900)).toBeUndefined(); + } + }); +}); + +describe("DeviceStore – connection & sendAdminMessage", () => { + beforeEach(() => { + idbMem.clear(); + vi.clearAllMocks(); + }); + + it("sendAdminMessage calls through to connection.sendPacket with correct args", async () => { + const { useDeviceStore } = await freshStore(false); + const state = useDeviceStore.getState(); + const device = state.addDevice(77); + + const sendPacket = vi.fn(); + device.addConnection({ sendPacket } as any); + + const message = makeAdminMessage({ logVerbosity: 1 }); + device.sendAdminMessage(message); + + expect(sendPacket).toHaveBeenCalledTimes(1); + const [bytes, port, dest] = sendPacket.mock.calls[0]!; + expect(port).toBe(Protobuf.Portnums.PortNum.ADMIN_APP); + expect(dest).toBe("self"); + + // sanity: encoded bytes match toBinary on the same schema + const expected = toBinary(Protobuf.Admin.AdminMessageSchema, message); + expect(bytes).toBeInstanceOf(Uint8Array); + + // compare content length as minimal assertion (exact byte-for-byte is fine too) + expect((bytes as Uint8Array).length).toBe(expected.length); + }); +}); diff --git a/packages/web/src/core/stores/deviceStore/index.ts b/packages/web/src/core/stores/deviceStore/index.ts index e83547067..789ecb2d0 100644 --- a/packages/web/src/core/stores/deviceStore/index.ts +++ b/packages/web/src/core/stores/deviceStore/index.ts @@ -1,110 +1,95 @@ import { create, toBinary } from "@bufbuild/protobuf"; +import { evictOldestEntries } from "@core/stores/utils/evictOldestEntries.ts"; +import { createStorage } from "@core/stores/utils/indexDB.ts"; import { type MeshDevice, Protobuf, Types } from "@meshtastic/core"; import { produce } from "immer"; -import { create as createStore } from "zustand"; +import { create as createStore, type StateCreator } from "zustand"; +import { + type PersistOptions, + persist, + subscribeWithSelector, +} from "zustand/middleware"; +import type { ChangeRegistry, ConfigChangeKey } from "./changeRegistry.ts"; +import { + createChangeRegistry, + getAdminMessageChangeCount, + getAllAdminMessages, + getAllChannelChanges, + getAllConfigChanges, + getAllModuleConfigChanges, + getChannelChangeCount, + getConfigChangeCount, + getModuleConfigChangeCount, + hasChannelChange, + hasConfigChange, + hasModuleConfigChange, + hasUserChange, + serializeKey, +} from "./changeRegistry.ts"; +import type { + Connection, + ConnectionId, + Dialogs, + DialogVariant, + ValidConfigType, + ValidModuleConfigType, + WaypointWithMetadata, +} from "./types.ts"; -export type Page = "messages" | "map" | "config" | "channels" | "nodes"; +const IDB_KEY_NAME = "meshtastic-device-store"; +const CURRENT_STORE_VERSION = 0; +const DEVICESTORE_RETENTION_NUM = 10; +const TRACEROUTE_TARGET_RETENTION_NUM = 100; // Number of traceroutes targets to keep +const TRACEROUTE_ROUTE_RETENTION_NUM = 100; // Number of traceroutes to keep per target +const WAYPOINT_RETENTION_NUM = 100; -export interface ProcessPacketParams { - from: number; - snr: number; - time: number; -} - -export type DialogVariant = keyof Device["dialog"]; - -export type ValidConfigType = Exclude< - Protobuf.Config.Config["payloadVariant"]["case"], - "deviceUi" | "sessionkey" | undefined ->; -export type ValidModuleConfigType = Exclude< - Protobuf.ModuleConfig.ModuleConfig["payloadVariant"]["case"], - undefined ->; - -export type WaypointWithMetadata = Protobuf.Mesh.Waypoint & { - metadata: { - channel: number; // Channel on which the waypoint was received - created: Date; // Timestamp when the waypoint was received - updated?: Date; // Timestamp when the waypoint was last updated - from: number; // Node number of the device that sent the waypoint - }; +type DeviceData = { + // Persisted data + id: number; + myNodeNum: number | undefined; + traceroutes: Map< + number, + Types.PacketMetadata[] + >; + waypoints: WaypointWithMetadata[]; + neighborInfo: Map; }; +export type ConnectionPhase = + | "disconnected" + | "connecting" + | "configuring" + | "configured"; -export interface Device { - id: number; +export interface Device extends DeviceData { + // Ephemeral state (not persisted) status: Types.DeviceStatusEnum; + connectionPhase: ConnectionPhase; + connectionId: ConnectionId | null; channels: Map; config: Protobuf.LocalOnly.LocalConfig; moduleConfig: Protobuf.LocalOnly.LocalModuleConfig; - workingConfig: Protobuf.Config.Config[]; - workingModuleConfig: Protobuf.ModuleConfig.ModuleConfig[]; - workingChannelConfig: Protobuf.Channel.Channel[]; + changeRegistry: ChangeRegistry; // Unified change tracking hardware: Protobuf.Mesh.MyNodeInfo; metadata: Map; - traceroutes: Map< - number, - Types.PacketMetadata[] - >; connection?: MeshDevice; activeNode: number; - waypoints: WaypointWithMetadata[]; - neighborInfo: Map; pendingSettingsChanges: boolean; messageDraft: string; unreadCounts: Map; - dialog: { - import: boolean; - QR: boolean; - shutdown: boolean; - reboot: boolean; - deviceName: boolean; - nodeRemoval: boolean; - pkiBackup: boolean; - nodeDetails: boolean; - unsafeRoles: boolean; - refreshKeys: boolean; - deleteMessages: boolean; - managedMode: boolean; - clientNotification: boolean; - resetNodeDb: boolean; - clearAllStores: boolean; - factoryResetDevice: boolean; - factoryResetConfig: boolean; - }; + dialog: Dialogs; clientNotifications: Protobuf.Mesh.ClientNotification[]; setStatus: (status: Types.DeviceStatusEnum) => void; + setConnectionPhase: (phase: ConnectionPhase) => void; + setConnectionId: (id: ConnectionId | null) => void; setConfig: (config: Protobuf.Config.Config) => void; setModuleConfig: (config: Protobuf.ModuleConfig.ModuleConfig) => void; - setWorkingConfig: (config: Protobuf.Config.Config) => void; - setWorkingModuleConfig: (config: Protobuf.ModuleConfig.ModuleConfig) => void; - getWorkingConfig: ( - payloadVariant: ValidConfigType, - ) => - | Protobuf.LocalOnly.LocalConfig[Exclude] - | undefined; - getWorkingModuleConfig: ( - payloadVariant: ValidModuleConfigType, - ) => - | Protobuf.LocalOnly.LocalModuleConfig[Exclude< - ValidModuleConfigType, - undefined - >] - | undefined; - removeWorkingConfig: (payloadVariant?: ValidConfigType) => void; - removeWorkingModuleConfig: (payloadVariant?: ValidModuleConfigType) => void; getEffectiveConfig( payloadVariant: K, ): Protobuf.LocalOnly.LocalConfig[K] | undefined; getEffectiveModuleConfig( payloadVariant: K, ): Protobuf.LocalOnly.LocalModuleConfig[K] | undefined; - setWorkingChannelConfig: (channelNum: Protobuf.Channel.Channel) => void; - getWorkingChannelConfig: ( - index: Types.ChannelNumber, - ) => Protobuf.Channel.Channel | undefined; - removeWorkingChannelConfig: (channelNum?: Types.ChannelNumber) => void; setHardware: (hardware: Protobuf.Mesh.MyNodeInfo) => void; setActiveNode: (node: number) => void; setPendingSettingsChanges: (state: boolean) => void; @@ -115,6 +100,8 @@ export interface Device { from: number, rxTime: Date, ) => void; + removeWaypoint: (waypointId: number, toMesh: boolean) => Promise; + getWaypoint: (waypointId: number) => WaypointWithMetadata | undefined; addConnection: (connection: MeshDevice) => void; addTraceRoute: ( traceroute: Types.PacketMetadata, @@ -140,661 +127,1036 @@ export interface Device { neighborInfo: Protobuf.Mesh.NeighborInfo, ) => void; getNeighborInfo: (nodeNum: number) => Protobuf.Mesh.NeighborInfo | undefined; + + // New unified change tracking methods + setChange: ( + key: ConfigChangeKey, + value: unknown, + originalValue?: unknown, + ) => void; + removeChange: (key: ConfigChangeKey) => void; + hasChange: (key: ConfigChangeKey) => boolean; + getChange: (key: ConfigChangeKey) => unknown | undefined; + clearAllChanges: () => void; + hasConfigChange: (variant: ValidConfigType) => boolean; + hasModuleConfigChange: (variant: ValidModuleConfigType) => boolean; + hasChannelChange: (index: Types.ChannelNumber) => boolean; + hasUserChange: () => boolean; + getConfigChangeCount: () => number; + getModuleConfigChangeCount: () => number; + getChannelChangeCount: () => number; + getAllConfigChanges: () => Protobuf.Config.Config[]; + getAllModuleConfigChanges: () => Protobuf.ModuleConfig.ModuleConfig[]; + getAllChannelChanges: () => Protobuf.Channel.Channel[]; + queueAdminMessage: (message: Protobuf.Admin.AdminMessage) => void; + getAllQueuedAdminMessages: () => Protobuf.Admin.AdminMessage[]; + getAdminMessageChangeCount: () => number; } -export interface DeviceState { +export interface deviceState { addDevice: (id: number) => Device; removeDevice: (id: number) => void; getDevices: () => Device[]; getDevice: (id: number) => Device | undefined; + + // Saved connections management + savedConnections: Connection[]; + addSavedConnection: (connection: Connection) => void; + updateSavedConnection: ( + id: ConnectionId, + updates: Partial, + ) => void; + removeSavedConnection: (id: ConnectionId) => void; + getSavedConnections: () => Connection[]; + + // Active connection tracking + activeConnectionId: ConnectionId | null; + setActiveConnectionId: (id: ConnectionId | null) => void; + getActiveConnectionId: () => ConnectionId | null; + + // Helper selectors for connection ↔ device relationships + getActiveConnection: () => Connection | undefined; + getDeviceForConnection: (id: ConnectionId) => Device | undefined; + getConnectionForDevice: (deviceId: number) => Connection | undefined; } -interface PrivateDeviceState extends DeviceState { +interface PrivateDeviceState extends deviceState { devices: Map; - remoteDevices: Map; } -export const useDeviceStore = createStore((set, get) => ({ - devices: new Map(), - remoteDevices: new Map(), +type DevicePersisted = { + devices: Map; + savedConnections: Connection[]; +}; - addDevice: (id: number) => { - set( - produce((draft) => { - draft.devices.set(id, { - id, - status: Types.DeviceStatusEnum.DeviceDisconnected, - channels: new Map(), - config: create(Protobuf.LocalOnly.LocalConfigSchema), - moduleConfig: create(Protobuf.LocalOnly.LocalModuleConfigSchema), - workingConfig: [], - workingModuleConfig: [], - workingChannelConfig: [], - hardware: create(Protobuf.Mesh.MyNodeInfoSchema), - metadata: new Map(), - traceroutes: new Map(), - connection: undefined, - activeNode: 0, - waypoints: [], - neighborInfo: new Map(), - dialog: { - import: false, - QR: false, - shutdown: false, - reboot: false, - deviceName: false, - nodeRemoval: false, - pkiBackup: false, - nodeDetails: false, - unsafeRoles: false, - refreshKeys: false, - deleteMessages: false, - managedMode: false, - clientNotification: false, - resetNodeDb: false, - clearAllStores: false, - factoryResetDevice: false, - factoryResetConfig: false, - }, - pendingSettingsChanges: false, - messageDraft: "", - unreadCounts: new Map(), - clientNotifications: [], - - setStatus: (status: Types.DeviceStatusEnum) => { - set( - produce((draft) => { - const device = draft.devices.get(id); - if (device) { - device.status = status; - } - }), - ); - }, - setConfig: (config: Protobuf.Config.Config) => { - set( - produce((draft) => { - const device = draft.devices.get(id); - if (device) { - switch (config.payloadVariant.case) { - case "device": { - device.config.device = config.payloadVariant.value; - break; - } - case "position": { - device.config.position = config.payloadVariant.value; - break; - } - case "power": { - device.config.power = config.payloadVariant.value; - break; - } - case "network": { - device.config.network = config.payloadVariant.value; - break; - } - case "display": { - device.config.display = config.payloadVariant.value; - break; - } - case "lora": { - device.config.lora = config.payloadVariant.value; - break; - } - case "bluetooth": { - device.config.bluetooth = config.payloadVariant.value; - break; - } - case "security": { - device.config.security = config.payloadVariant.value; - } - } - } - }), - ); - }, - setModuleConfig: (config: Protobuf.ModuleConfig.ModuleConfig) => { - set( - produce((draft) => { - const device = draft.devices.get(id); - if (device) { - switch (config.payloadVariant.case) { - case "mqtt": { - device.moduleConfig.mqtt = config.payloadVariant.value; - break; - } - case "serial": { - device.moduleConfig.serial = config.payloadVariant.value; - break; - } - case "externalNotification": { - device.moduleConfig.externalNotification = - config.payloadVariant.value; - break; - } - case "storeForward": { - device.moduleConfig.storeForward = - config.payloadVariant.value; - break; - } - case "rangeTest": { - device.moduleConfig.rangeTest = - config.payloadVariant.value; - break; - } - case "telemetry": { - device.moduleConfig.telemetry = - config.payloadVariant.value; - break; - } - case "cannedMessage": { - device.moduleConfig.cannedMessage = - config.payloadVariant.value; - break; - } - case "audio": { - device.moduleConfig.audio = config.payloadVariant.value; - break; - } - case "neighborInfo": { - device.moduleConfig.neighborInfo = - config.payloadVariant.value; - break; - } - case "ambientLighting": { - device.moduleConfig.ambientLighting = - config.payloadVariant.value; - break; - } - case "detectionSensor": { - device.moduleConfig.detectionSensor = - config.payloadVariant.value; - break; - } - case "paxcounter": { - device.moduleConfig.paxcounter = - config.payloadVariant.value; - break; - } - } - } - }), - ); - }, - setWorkingConfig: (config: Protobuf.Config.Config) => { - set( - produce((draft) => { - const device = draft.devices.get(id); - if (!device) { - return; - } - const index = device.workingConfig.findIndex( - (wc) => wc.payloadVariant.case === config.payloadVariant.case, - ); - - if (index !== -1) { - device.workingConfig[index] = config; - } else { - device.workingConfig.push(config); - } - }), - ); - }, - setWorkingModuleConfig: ( - moduleConfig: Protobuf.ModuleConfig.ModuleConfig, - ) => { - set( - produce((draft) => { - const device = draft.devices.get(id); - if (!device) { - return; - } - const index = device.workingModuleConfig.findIndex( - (wmc) => - wmc.payloadVariant.case === - moduleConfig.payloadVariant.case, - ); - - if (index !== -1) { - device.workingModuleConfig[index] = moduleConfig; - } else { - device.workingModuleConfig.push(moduleConfig); - } - }), - ); - }, +function deviceFactory( + id: number, + get: () => PrivateDeviceState, + set: typeof useDeviceStore.setState, + data?: Partial, +): Device { + const myNodeNum = data?.myNodeNum; + const traceroutes = + data?.traceroutes ?? + new Map[]>(); + const waypoints = data?.waypoints ?? []; + const neighborInfo = + data?.neighborInfo ?? new Map(); + return { + id, + myNodeNum, + traceroutes, + waypoints, + neighborInfo, - getWorkingConfig: (payloadVariant: ValidConfigType) => { - const device = get().devices.get(id); - if (!device) { - return; + status: Types.DeviceStatusEnum.DeviceDisconnected, + connectionPhase: "disconnected", + connectionId: null, + channels: new Map(), + config: create(Protobuf.LocalOnly.LocalConfigSchema), + moduleConfig: create(Protobuf.LocalOnly.LocalModuleConfigSchema), + changeRegistry: createChangeRegistry(), + hardware: create(Protobuf.Mesh.MyNodeInfoSchema), + metadata: new Map(), + connection: undefined, + activeNode: 0, + dialog: { + import: false, + QR: false, + shutdown: false, + reboot: false, + deviceName: false, + nodeRemoval: false, + pkiBackup: false, + nodeDetails: false, + unsafeRoles: false, + refreshKeys: false, + deleteMessages: false, + managedMode: false, + clientNotification: false, + resetNodeDb: false, + clearAllStores: false, + factoryResetDevice: false, + factoryResetConfig: false, + }, + pendingSettingsChanges: false, + messageDraft: "", + unreadCounts: new Map(), + clientNotifications: [], + + setStatus: (status: Types.DeviceStatusEnum) => { + set( + produce((draft) => { + const device = draft.devices.get(id); + if (device) { + device.status = status; + } + }), + ); + }, + setConnectionPhase: (phase: ConnectionPhase) => { + set( + produce((draft) => { + const device = draft.devices.get(id); + if (device) { + device.connectionPhase = phase; + } + }), + ); + }, + setConnectionId: (connectionId: ConnectionId | null) => { + set( + produce((draft) => { + const device = draft.devices.get(id); + if (device) { + device.connectionId = connectionId; + } + }), + ); + }, + setConfig: (config: Protobuf.Config.Config) => { + set( + produce((draft) => { + const device = draft.devices.get(id); + if (device) { + switch (config.payloadVariant.case) { + case "device": { + device.config.device = config.payloadVariant.value; + break; + } + case "position": { + device.config.position = config.payloadVariant.value; + break; + } + case "power": { + device.config.power = config.payloadVariant.value; + break; + } + case "network": { + device.config.network = config.payloadVariant.value; + break; + } + case "display": { + device.config.display = config.payloadVariant.value; + break; + } + case "lora": { + device.config.lora = config.payloadVariant.value; + break; + } + case "bluetooth": { + device.config.bluetooth = config.payloadVariant.value; + break; + } + case "security": { + device.config.security = config.payloadVariant.value; + } + } + } + }), + ); + }, + setModuleConfig: (config: Protobuf.ModuleConfig.ModuleConfig) => { + set( + produce((draft) => { + const device = draft.devices.get(id); + if (device) { + switch (config.payloadVariant.case) { + case "mqtt": { + device.moduleConfig.mqtt = config.payloadVariant.value; + break; + } + case "serial": { + device.moduleConfig.serial = config.payloadVariant.value; + break; + } + case "externalNotification": { + device.moduleConfig.externalNotification = + config.payloadVariant.value; + break; + } + case "storeForward": { + device.moduleConfig.storeForward = config.payloadVariant.value; + break; + } + case "rangeTest": { + device.moduleConfig.rangeTest = config.payloadVariant.value; + break; + } + case "telemetry": { + device.moduleConfig.telemetry = config.payloadVariant.value; + break; + } + case "cannedMessage": { + device.moduleConfig.cannedMessage = config.payloadVariant.value; + break; + } + case "audio": { + device.moduleConfig.audio = config.payloadVariant.value; + break; + } + case "neighborInfo": { + device.moduleConfig.neighborInfo = config.payloadVariant.value; + break; + } + case "ambientLighting": { + device.moduleConfig.ambientLighting = + config.payloadVariant.value; + break; + } + case "detectionSensor": { + device.moduleConfig.detectionSensor = + config.payloadVariant.value; + break; + } + case "paxcounter": { + device.moduleConfig.paxcounter = config.payloadVariant.value; + break; + } } + } + }), + ); + }, + getEffectiveConfig( + payloadVariant: K, + ): Protobuf.LocalOnly.LocalConfig[K] | undefined { + if (!payloadVariant) { + return; + } + const device = get().devices.get(id); + if (!device) { + return; + } - const workingConfig = device.workingConfig.find( - (c) => c.payloadVariant.case === payloadVariant, - ); + const workingValue = device.changeRegistry.changes.get( + serializeKey({ type: "config", variant: payloadVariant }), + )?.value as Protobuf.LocalOnly.LocalConfig[K] | undefined; - if ( - workingConfig?.payloadVariant.case === "deviceUi" || - workingConfig?.payloadVariant.case === "sessionkey" - ) { - return; - } + return { + ...device.config[payloadVariant], + ...workingValue, + }; + }, + getEffectiveModuleConfig( + payloadVariant: K, + ): Protobuf.LocalOnly.LocalModuleConfig[K] | undefined { + const device = get().devices.get(id); + if (!device) { + return; + } + + const workingValue = device.changeRegistry.changes.get( + serializeKey({ type: "moduleConfig", variant: payloadVariant }), + )?.value as Protobuf.LocalOnly.LocalModuleConfig[K] | undefined; + + return { + ...device.moduleConfig[payloadVariant], + ...workingValue, + }; + }, - return workingConfig?.payloadVariant.value; - }, - getWorkingModuleConfig: (payloadVariant: ValidModuleConfigType) => { - const device = get().devices.get(id); - if (!device) { - return; + setHardware: (hardware: Protobuf.Mesh.MyNodeInfo) => { + set( + produce((draft) => { + const newDevice = draft.devices.get(id); + if (!newDevice) { + throw new Error(`No DeviceStore found for id: ${id}`); + } + newDevice.myNodeNum = hardware.myNodeNum; + + for (const [otherId, oldStore] of draft.devices) { + if (otherId === id || oldStore.myNodeNum !== hardware.myNodeNum) { + continue; } + newDevice.traceroutes = oldStore.traceroutes; + newDevice.neighborInfo = oldStore.neighborInfo; - return device.workingModuleConfig.find( - (c) => c.payloadVariant.case === payloadVariant, - )?.payloadVariant.value; - }, - - removeWorkingConfig: (payloadVariant?: ValidConfigType) => { - set( - produce((draft) => { - const device = draft.devices.get(id); - if (!device) { - return; - } - - if (!payloadVariant) { - device.workingConfig = []; - return; - } - - const index = device.workingConfig.findIndex( - (wc: Protobuf.Config.Config) => - wc.payloadVariant.case === payloadVariant, - ); - - if (index !== -1) { - device.workingConfig.splice(index, 1); - } - }), - ); - }, - removeWorkingModuleConfig: ( - payloadVariant?: ValidModuleConfigType, - ) => { - set( - produce((draft) => { - const device = draft.devices.get(id); - if (!device) { - return; - } - - if (!payloadVariant) { - device.workingModuleConfig = []; - return; - } - - const index = device.workingModuleConfig.findIndex( - (wc: Protobuf.ModuleConfig.ModuleConfig) => - wc.payloadVariant.case === payloadVariant, - ); - - if (index !== -1) { - device.workingModuleConfig.splice(index, 1); - } - }), + // Take this opportunity to remove stale waypoints + newDevice.waypoints = oldStore.waypoints.filter( + (waypoint) => !waypoint?.expire || waypoint.expire > Date.now(), ); - }, - getEffectiveConfig( - payloadVariant: K, - ): Protobuf.LocalOnly.LocalConfig[K] | undefined { - if (!payloadVariant) { - return; - } - const device = get().devices.get(id); - if (!device) { - return; - } + // Drop old device + draft.devices.delete(otherId); + } - return { - ...device.config[payloadVariant], - ...device.workingConfig.find( - (c) => c.payloadVariant.case === payloadVariant, - )?.payloadVariant.value, - }; - }, - getEffectiveModuleConfig( - payloadVariant: K, - ): Protobuf.LocalOnly.LocalModuleConfig[K] | undefined { - const device = get().devices.get(id); - if (!device) { - return; - } + newDevice.hardware = hardware; // Always replace hardware with latest + }), + ); + }, + setPendingSettingsChanges: (state) => { + set( + produce((draft) => { + const device = draft.devices.get(id); + if (device) { + device.pendingSettingsChanges = state; + } + }), + ); + }, + addChannel: (channel: Protobuf.Channel.Channel) => { + set( + produce((draft) => { + const device = draft.devices.get(id); + if (device) { + device.channels.set(channel.index, channel); + } + }), + ); + }, + addWaypoint: (waypoint, channel, from, rxTime) => { + set( + produce((draft) => { + const device = draft.devices.get(id); + if (!device) { + return undefined; + } + + const index = device.waypoints.findIndex( + (wp) => wp.id === waypoint.id, + ); - return { - ...device.moduleConfig[payloadVariant], - ...device.workingModuleConfig.find( - (c) => c.payloadVariant.case === payloadVariant, - )?.payloadVariant.value, + if (index !== -1) { + const created = + device.waypoints[index]?.metadata.created ?? new Date(); + const updatedWaypoint = { + ...waypoint, + metadata: { created, updated: rxTime, from, channel }, }; - }, - - setWorkingChannelConfig: (config: Protobuf.Channel.Channel) => { - set( - produce((draft) => { - const device = draft.devices.get(id); - if (!device) { - return; - } - const index = device.workingChannelConfig.findIndex( - (wcc) => wcc.index === config.index, - ); - - if (index !== -1) { - device.workingChannelConfig[index] = config; - } else { - device.workingChannelConfig.push(config); - } - }), - ); - }, - getWorkingChannelConfig: (channelNum: Types.ChannelNumber) => { - const device = get().devices.get(id); - if (!device) { - return; - } - const workingChannelConfig = device.workingChannelConfig.find( - (c) => c.index === channelNum, - ); + // Remove existing waypoint + device.waypoints.splice(index, 1); - return workingChannelConfig; - }, - removeWorkingChannelConfig: (channelNum?: Types.ChannelNumber) => { - set( - produce((draft) => { - const device = draft.devices.get(id); - if (!device) { - return; - } - - if (channelNum === undefined) { - device.workingChannelConfig = []; - return; - } - - const index = device.workingChannelConfig.findIndex( - (wcc: Protobuf.Channel.Channel) => wcc.index === channelNum, - ); - - if (index !== -1) { - device.workingChannelConfig.splice(index, 1); - } - }), - ); - }, - - setHardware: (hardware: Protobuf.Mesh.MyNodeInfo) => { - set( - produce((draft) => { - const device = draft.devices.get(id); - if (device) { - device.hardware = hardware; - } - }), - ); - }, - setPendingSettingsChanges: (state) => { - set( - produce((draft) => { - const device = draft.devices.get(id); - if (device) { - device.pendingSettingsChanges = state; - } - }), - ); - }, - addChannel: (channel: Protobuf.Channel.Channel) => { - set( - produce((draft) => { - const device = draft.devices.get(id); - if (device) { - device.channels.set(channel.index, channel); - } - }), - ); - }, - addWaypoint: (waypoint, channel, from, rxTime) => { - set( - produce((draft) => { - const device = draft.devices.get(id); - if (device) { - const index = device.waypoints.findIndex( - (wp) => wp.id === waypoint.id, - ); - if (index !== -1) { - const created = - device.waypoints[index]?.metadata.created ?? new Date(); - const updatedWaypoint = { - ...waypoint, - metadata: { created, updated: rxTime, from, channel }, - }; - - device.waypoints[index] = updatedWaypoint; - } else { - device.waypoints.push({ - ...waypoint, - metadata: { created: rxTime, from, channel }, - }); - } - } - }), - ); - }, - setActiveNode: (node) => { - set( - produce((draft) => { - const device = draft.devices.get(id); - if (device) { - device.activeNode = node; - } - }), - ); - }, - addConnection: (connection) => { - set( - produce((draft) => { - const device = draft.devices.get(id); - if (device) { - device.connection = connection; - } - }), - ); - }, - addMetadata: (from, metadata) => { - set( - produce((draft) => { - const device = draft.devices.get(id); - if (device) { - device.metadata.set(from, metadata); - } - }), - ); - }, - addTraceRoute: (traceroute) => { - set( - produce((draft) => { - const device = draft.devices.get(id); - if (!device) { - return; - } - const routes = device.traceroutes.get(traceroute.from) ?? []; - routes.push(traceroute); - device.traceroutes.set(traceroute.from, routes); - }), - ); - }, - setDialogOpen: (dialog: DialogVariant, open: boolean) => { - set( - produce((draft) => { - const device = draft.devices.get(id); - if (device) { - device.dialog[dialog] = open; - } - }), - ); - }, - getDialogOpen: (dialog: DialogVariant) => { - const device = get().devices.get(id); - if (!device) { - throw new Error(`Device ${id} not found`); + // Push new if no expiry or not expired + if (waypoint.expire === 0 || waypoint.expire > Date.now()) { + device.waypoints.push(updatedWaypoint); } - return device.dialog[dialog]; - }, - - setMessageDraft: (message: string) => { - set( - produce((draft) => { - const device = draft.devices.get(id); - if (device) { - device.messageDraft = message; - } - }), - ); - }, - incrementUnread: (nodeNum: number) => { - set( - produce((draft) => { - const device = draft.devices.get(id); - if (!device) { - return; - } - const currentCount = device.unreadCounts.get(nodeNum) ?? 0; - device.unreadCounts.set(nodeNum, currentCount + 1); - }), - ); - }, - getUnreadCount: (nodeNum: number): number => { - const device = get().devices.get(id); - if (!device) { - return 0; - } - return device.unreadCounts.get(nodeNum) ?? 0; - }, - getAllUnreadCount: (): number => { - const device = get().devices.get(id); - if (!device) { - return 0; - } - let totalUnread = 0; - device.unreadCounts.forEach((count) => { - totalUnread += count; + } else if ( + // only add if set to never expire or not already expired + waypoint.expire === 0 || + (waypoint.expire !== 0 && waypoint.expire < Date.now()) + ) { + device.waypoints.push({ + ...waypoint, + metadata: { created: rxTime, from, channel }, }); - return totalUnread; - }, - resetUnread: (nodeNum: number) => { - set( - produce((draft) => { - const device = draft.devices.get(id); - if (!device) { - return; - } - device.unreadCounts.set(nodeNum, 0); - if (device.unreadCounts.get(nodeNum) === 0) { - device.unreadCounts.delete(nodeNum); - } - }), - ); - }, + } - sendAdminMessage(message: Protobuf.Admin.AdminMessage) { - const device = get().devices.get(id); - if (!device) { - return; - } + // Enforce retention limit + evictOldestEntries(device.waypoints, WAYPOINT_RETENTION_NUM); + }), + ); + }, + removeWaypoint: async (waypointId: number, toMesh: boolean) => { + const device = get().devices.get(id); + if (!device) { + return; + } - device.connection?.sendPacket( - toBinary(Protobuf.Admin.AdminMessageSchema, message), - Protobuf.Portnums.PortNum.ADMIN_APP, - "self", - ); - }, - - addClientNotification: ( - clientNotificationPacket: Protobuf.Mesh.ClientNotification, - ) => { - set( - produce((draft) => { - const device = draft.devices.get(id); - if (!device) { - return; - } - device.clientNotifications.push(clientNotificationPacket); - }), - ); - }, - removeClientNotification: (index: number) => { - set( - produce((draft) => { - const device = draft.devices.get(id); - if (!device) { - return; - } - device.clientNotifications.splice(index, 1); - }), - ); - }, - getClientNotification: (index: number) => { - const device = get().devices.get(id); - if (!device) { - return; - } - return device.clientNotifications[index]; - }, - addNeighborInfo: ( - nodeId: number, - neighborInfo: Protobuf.Mesh.NeighborInfo, - ) => { - set( - produce((draft) => { - const device = draft.devices.get(id); - if (!device) { - return; - } - - // Replace any existing neighbor info for this nodeId - device.neighborInfo.set(nodeId, neighborInfo); - }), - ); - }, + const waypoint = device.waypoints.find((wp) => wp.id === waypointId); + if (!waypoint) { + return; + } - getNeighborInfo: (nodeNum: number) => { - const device = get().devices.get(id); - if (!device) { - return; - } - return device.neighborInfo.get(nodeNum); - }, + if (toMesh) { + if (!device.connection) { + return; + } + + const waypointToBroadcast = create(Protobuf.Mesh.WaypointSchema, { + id: waypoint.id, // Bare minimum to delete a waypoint + lockedTo: 0, + name: "", + description: "", + icon: 0, + expire: 1, }); + + await device.connection.sendWaypoint( + waypointToBroadcast, + "broadcast", + waypoint.metadata.channel, + ); + } + + // Remove from store + set( + produce((draft) => { + const device = draft.devices.get(id); + if (!device) { + return; + } + + const idx = device.waypoints.findIndex( + (waypoint) => waypoint.id === waypointId, + ); + if (idx >= 0) { + device.waypoints.splice(idx, 1); + } + }), + ); + }, + getWaypoint: (waypointId: number) => { + const device = get().devices.get(id); + if (!device) { + return; + } + + return device.waypoints.find((waypoint) => waypoint.id === waypointId); + }, + setActiveNode: (node) => { + set( + produce((draft) => { + const device = draft.devices.get(id); + if (device) { + device.activeNode = node; + } + }), + ); + }, + addConnection: (connection) => { + set( + produce((draft) => { + const device = draft.devices.get(id); + if (device) { + device.connection = connection; + } + }), + ); + }, + addMetadata: (from, metadata) => { + set( + produce((draft) => { + const device = draft.devices.get(id); + if (device) { + device.metadata.set(from, metadata); + } + }), + ); + }, + addTraceRoute: (traceroute) => { + set( + produce((draft) => { + const device = draft.devices.get(id); + if (!device) { + return; + } + const routes = device.traceroutes.get(traceroute.from) ?? []; + routes.push(traceroute); + device.traceroutes.set(traceroute.from, routes); + + // Enforce retention limit, both in terms of targets (device.traceroutes) and routes per target (routes) + evictOldestEntries(routes, TRACEROUTE_ROUTE_RETENTION_NUM); + evictOldestEntries( + device.traceroutes, + TRACEROUTE_TARGET_RETENTION_NUM, + ); + }), + ); + }, + setDialogOpen: (dialog: DialogVariant, open: boolean) => { + set( + produce((draft) => { + const device = draft.devices.get(id); + if (device) { + device.dialog[dialog] = open; + } + }), + ); + }, + getDialogOpen: (dialog: DialogVariant) => { + const device = get().devices.get(id); + if (!device) { + throw new Error(`Device ${id} not found`); + } + return device.dialog[dialog]; + }, + + setMessageDraft: (message: string) => { + set( + produce((draft) => { + const device = draft.devices.get(id); + if (device) { + device.messageDraft = message; + } + }), + ); + }, + incrementUnread: (nodeNum: number) => { + set( + produce((draft) => { + const device = draft.devices.get(id); + if (!device) { + return; + } + const currentCount = device.unreadCounts.get(nodeNum) ?? 0; + device.unreadCounts.set(nodeNum, currentCount + 1); + }), + ); + }, + getUnreadCount: (nodeNum: number): number => { + const device = get().devices.get(id); + if (!device) { + return 0; + } + return device.unreadCounts.get(nodeNum) ?? 0; + }, + getAllUnreadCount: (): number => { + const device = get().devices.get(id); + if (!device) { + return 0; + } + let totalUnread = 0; + device.unreadCounts.forEach((count) => { + totalUnread += count; + }); + return totalUnread; + }, + resetUnread: (nodeNum: number) => { + set( + produce((draft) => { + const device = draft.devices.get(id); + if (!device) { + return; + } + device.unreadCounts.set(nodeNum, 0); + if (device.unreadCounts.get(nodeNum) === 0) { + device.unreadCounts.delete(nodeNum); + } + }), + ); + }, + + sendAdminMessage(message: Protobuf.Admin.AdminMessage) { + const device = get().devices.get(id); + if (!device) { + return; + } + + device.connection?.sendPacket( + toBinary(Protobuf.Admin.AdminMessageSchema, message), + Protobuf.Portnums.PortNum.ADMIN_APP, + "self", + ); + }, + + addClientNotification: ( + clientNotificationPacket: Protobuf.Mesh.ClientNotification, + ) => { + set( + produce((draft) => { + const device = draft.devices.get(id); + if (!device) { + return; + } + device.clientNotifications.push(clientNotificationPacket); + }), + ); + }, + removeClientNotification: (index: number) => { + set( + produce((draft) => { + const device = draft.devices.get(id); + if (!device) { + return; + } + device.clientNotifications.splice(index, 1); + }), + ); + }, + getClientNotification: (index: number) => { + const device = get().devices.get(id); + if (!device) { + return; + } + return device.clientNotifications[index]; + }, + addNeighborInfo: ( + nodeId: number, + neighborInfo: Protobuf.Mesh.NeighborInfo, + ) => { + set( + produce((draft) => { + const device = draft.devices.get(id); + if (!device) { + return; + } + + // Replace any existing neighbor info for this nodeId + device.neighborInfo.set(nodeId, neighborInfo); + }), + ); + }, + + getNeighborInfo: (nodeNum: number) => { + const device = get().devices.get(id); + if (!device) { + return; + } + return device.neighborInfo.get(nodeNum); + }, + + // New unified change tracking methods + setChange: ( + key: ConfigChangeKey, + value: unknown, + originalValue?: unknown, + ) => { + set( + produce((draft) => { + const device = draft.devices.get(id); + if (!device) { + return; + } + + const keyStr = serializeKey(key); + device.changeRegistry.changes.set(keyStr, { + key, + value, + originalValue, + timestamp: Date.now(), + }); + }), + ); + }, + + removeChange: (key: ConfigChangeKey) => { + set( + produce((draft) => { + const device = draft.devices.get(id); + if (!device) { + return; + } + + device.changeRegistry.changes.delete(serializeKey(key)); + }), + ); + }, + + hasChange: (key: ConfigChangeKey) => { + const device = get().devices.get(id); + return device?.changeRegistry.changes.has(serializeKey(key)) ?? false; + }, + + getChange: (key: ConfigChangeKey) => { + const device = get().devices.get(id); + if (!device) { + return; + } + + return device.changeRegistry.changes.get(serializeKey(key))?.value; + }, + + clearAllChanges: () => { + set( + produce((draft) => { + const device = draft.devices.get(id); + if (!device) { + return; + } + + device.changeRegistry.changes.clear(); + }), + ); + }, + + hasConfigChange: (variant: ValidConfigType) => { + const device = get().devices.get(id); + if (!device) { + return false; + } + + return hasConfigChange(device.changeRegistry, variant); + }, + + hasModuleConfigChange: (variant: ValidModuleConfigType) => { + const device = get().devices.get(id); + if (!device) { + return false; + } + + return hasModuleConfigChange(device.changeRegistry, variant); + }, + + hasChannelChange: (index: Types.ChannelNumber) => { + const device = get().devices.get(id); + if (!device) { + return false; + } + + return hasChannelChange(device.changeRegistry, index); + }, + + hasUserChange: () => { + const device = get().devices.get(id); + if (!device) { + return false; + } + + return hasUserChange(device.changeRegistry); + }, + + getConfigChangeCount: () => { + const device = get().devices.get(id); + if (!device) { + return 0; + } + + return getConfigChangeCount(device.changeRegistry); + }, + + getModuleConfigChangeCount: () => { + const device = get().devices.get(id); + if (!device) { + return 0; + } + + return getModuleConfigChangeCount(device.changeRegistry); + }, + + getChannelChangeCount: () => { + const device = get().devices.get(id); + if (!device) { + return 0; + } + + return getChannelChangeCount(device.changeRegistry); + }, + + getAllConfigChanges: () => { + const device = get().devices.get(id); + if (!device) { + return []; + } + + const changes = getAllConfigChanges(device.changeRegistry); + return changes + .map((entry) => { + if (entry.key.type !== "config") { + return null; + } + if (!entry.value) { + return null; + } + return create(Protobuf.Config.ConfigSchema, { + payloadVariant: { + case: entry.key.variant, + value: entry.value, + }, + }); + }) + .filter((c): c is Protobuf.Config.Config => c !== null); + }, + + getAllModuleConfigChanges: () => { + const device = get().devices.get(id); + if (!device) { + return []; + } + + const changes = getAllModuleConfigChanges(device.changeRegistry); + return changes + .map((entry) => { + if (entry.key.type !== "moduleConfig") { + return null; + } + if (!entry.value) { + return null; + } + return create(Protobuf.ModuleConfig.ModuleConfigSchema, { + payloadVariant: { + case: entry.key.variant, + value: entry.value, + }, + }); + }) + .filter((c): c is Protobuf.ModuleConfig.ModuleConfig => c !== null); + }, + + getAllChannelChanges: () => { + const device = get().devices.get(id); + if (!device) { + return []; + } + + const changes = getAllChannelChanges(device.changeRegistry); + return changes + .map((entry) => entry.value as Protobuf.Channel.Channel) + .filter((c): c is Protobuf.Channel.Channel => c !== undefined); + }, + + queueAdminMessage: (message: Protobuf.Admin.AdminMessage) => { + // Generate a unique ID for this admin message + const messageId = `${Date.now()}-${Math.random().toString(36).substring(7)}`; + + // Determine the variant type + const variant = + message.payloadVariant.case === "setFixedPosition" + ? "setFixedPosition" + : "other"; + + set( + produce((draft) => { + const device = draft.devices.get(id); + if (!device) { + return; + } + + const keyStr = serializeKey({ + type: "adminMessage", + variant, + id: messageId, + }); + + device.changeRegistry.changes.set(keyStr, { + key: { type: "adminMessage", variant, id: messageId }, + value: message, + timestamp: Date.now(), + }); + }), + ); + }, + + getAllQueuedAdminMessages: () => { + const device = get().devices.get(id); + if (!device) { + return []; + } + + const changes = getAllAdminMessages(device.changeRegistry); + return changes + .map((entry) => entry.value as Protobuf.Admin.AdminMessage) + .filter((m): m is Protobuf.Admin.AdminMessage => m !== undefined); + }, + + getAdminMessageChangeCount: () => { + const device = get().devices.get(id); + if (!device) { + return 0; + } + + return getAdminMessageChangeCount(device.changeRegistry); + }, + }; +} + +export const deviceStoreInitializer: StateCreator = ( + set, + get, +) => ({ + devices: new Map(), + savedConnections: [], + activeConnectionId: null, + + addDevice: (id) => { + const existing = get().devices.get(id); + if (existing) { + return existing; + } + + const device = deviceFactory(id, get, set); + set( + produce((draft) => { + draft.devices = new Map(draft.devices).set(id, device); + + // Enforce retention limit + evictOldestEntries(draft.devices, DEVICESTORE_RETENTION_NUM); }), ); - const device = get().devices.get(id); - if (!device) { - throw new Error(`Failed to create or retrieve device with ID ${id}`); - } return device; }, - removeDevice: (id) => { set( produce((draft) => { - draft.devices.delete(id); + const updated = new Map(draft.devices); + updated.delete(id); + draft.devices = updated; }), ); }, - getDevices: () => Array.from(get().devices.values()), - getDevice: (id) => get().devices.get(id), -})); + + addSavedConnection: (connection) => { + set( + produce((draft) => { + draft.savedConnections.push(connection); + }), + ); + }, + updateSavedConnection: (id, updates) => { + set( + produce((draft) => { + const conn = draft.savedConnections.find( + (c: Connection) => c.id === id, + ); + if (conn) { + for (const key in updates) { + if (Object.hasOwn(updates, key)) { + (conn as Record)[key] = + updates[key as keyof typeof updates]; + } + } + } + }), + ); + }, + removeSavedConnection: (id) => { + set( + produce((draft) => { + draft.savedConnections = draft.savedConnections.filter( + (c: Connection) => c.id !== id, + ); + }), + ); + }, + getSavedConnections: () => get().savedConnections, + + setActiveConnectionId: (id) => { + set( + produce((draft) => { + draft.activeConnectionId = id; + }), + ); + }, + getActiveConnectionId: () => get().activeConnectionId, + + getActiveConnection: () => { + const activeId = get().activeConnectionId; + if (!activeId) { + return undefined; + } + return get().savedConnections.find((c) => c.id === activeId); + }, + getDeviceForConnection: (id) => { + const connection = get().savedConnections.find((c) => c.id === id); + if (!connection?.meshDeviceId) { + return undefined; + } + return get().devices.get(connection.meshDeviceId); + }, + getConnectionForDevice: (deviceId) => { + return get().savedConnections.find((c) => c.meshDeviceId === deviceId); + }, +}); + +const persistOptions: PersistOptions = { + name: IDB_KEY_NAME, + storage: createStorage(), + version: CURRENT_STORE_VERSION, + partialize: (s): DevicePersisted => ({ + devices: new Map( + Array.from(s.devices.entries()).map(([id, db]) => [ + id, + { + id: db.id, + myNodeNum: db.myNodeNum, + traceroutes: db.traceroutes, + waypoints: db.waypoints, + neighborInfo: db.neighborInfo, + }, + ]), + ), + savedConnections: s.savedConnections, + }), + onRehydrateStorage: () => (state) => { + if (!state) { + return; + } + console.debug( + "DeviceStore: Rehydrating state with ", + state.devices.size, + " devices -", + state.devices, + ); + + useDeviceStore.setState( + produce((draft) => { + const rebuilt = new Map(); + for (const [id, data] of ( + draft.devices as unknown as Map + ).entries()) { + if (data.myNodeNum !== undefined) { + // Only rebuild if there is a nodenum set otherwise orphan dbs will acumulate + rebuilt.set( + id, + deviceFactory( + id, + useDeviceStore.getState, + useDeviceStore.setState, + data, + ), + ); + } + } + draft.devices = rebuilt; + }), + ); + }, +}; + +export const useDeviceStore = createStore( + subscribeWithSelector(persist(deviceStoreInitializer, persistOptions)), +); diff --git a/packages/web/src/core/stores/deviceStore/selectors.ts b/packages/web/src/core/stores/deviceStore/selectors.ts new file mode 100644 index 000000000..7a7852700 --- /dev/null +++ b/packages/web/src/core/stores/deviceStore/selectors.ts @@ -0,0 +1,109 @@ +import type { Device } from "./index.ts"; +import { useDeviceStore } from "./index.ts"; +import type { Connection, ConnectionId } from "./types.ts"; + +/** + * Hook to get the currently active connection + */ +export function useActiveConnection(): Connection | undefined { + return useDeviceStore((s) => s.getActiveConnection()); +} + +/** + * Hook to get the HTTP connection marked as default + */ +export function useDefaultConnection(): Connection | undefined { + return useDeviceStore((s) => s.savedConnections.find((c) => c.isDefault)); +} + +/** + * Hook to get the first saved connection + */ +export function useFirstSavedConnection(): Connection | undefined { + return useDeviceStore((s) => s.savedConnections.at(0)); +} + +export function useAddSavedConnection() { + return useDeviceStore((s) => s.addSavedConnection); +} + +export function useUpdateSavedConnection() { + return useDeviceStore((s) => s.updateSavedConnection); +} + +export function useRemoveSavedConnection() { + return useDeviceStore((s) => s.removeSavedConnection); +} + +/** + * Hook to get the active connection ID + */ +export function useActiveConnectionId(): ConnectionId | null { + return useDeviceStore((s) => s.activeConnectionId); +} + +export function useSetActiveConnectionId() { + return useDeviceStore((s) => s.setActiveConnectionId); +} + +/** + * Hook to get a specific connection's status + */ +export function useConnectionStatus(id: ConnectionId): string | undefined { + return useDeviceStore( + (s) => s.savedConnections.find((c) => c.id === id)?.status, + ); +} + +/** + * Hook to get a device for a specific connection + */ +export function useDeviceForConnection(id: ConnectionId): Device | undefined { + return useDeviceStore((s) => s.getDeviceForConnection(id)); +} + +/** + * Hook to get a connection for a specific device + */ +export function useConnectionForDevice( + deviceId: number, +): Connection | undefined { + return useDeviceStore((s) => s.getConnectionForDevice(deviceId)); +} + +/** + * Hook to check if any connection is currently connecting + */ +export function useIsConnecting(): boolean { + return useDeviceStore((s) => + s.savedConnections.some( + (c) => c.status === "connecting" || c.status === "configuring", + ), + ); +} + +/** + * Hook to get error message for a specific connection + */ +export function useConnectionError(id: ConnectionId): string | null { + return useDeviceStore( + (s) => s.savedConnections.find((c) => c.id === id)?.error ?? null, + ); +} + +/** + * Hook to get all saved connections + */ +export function useSavedConnections(): Connection[] { + return useDeviceStore((s) => s.savedConnections); +} + +/** + * Hook to check if a connection is connected + */ +export function useIsConnected(id: ConnectionId): boolean { + return useDeviceStore((s) => { + const status = s.savedConnections.find((c) => c.id === id)?.status; + return status === "connected" || status === "configured"; + }); +} diff --git a/packages/web/src/core/stores/deviceStore/types.ts b/packages/web/src/core/stores/deviceStore/types.ts new file mode 100644 index 000000000..484f3b315 --- /dev/null +++ b/packages/web/src/core/stores/deviceStore/types.ts @@ -0,0 +1,87 @@ +import type { Protobuf } from "@meshtastic/core"; +import type { + ValidConfigType, + ValidModuleConfigType, +} from "./changeRegistry.ts"; + +interface Dialogs { + import: boolean; + QR: boolean; + shutdown: boolean; + reboot: boolean; + deviceName: boolean; + nodeRemoval: boolean; + pkiBackup: boolean; + nodeDetails: boolean; + unsafeRoles: boolean; + refreshKeys: boolean; + deleteMessages: boolean; + managedMode: boolean; + clientNotification: boolean; + resetNodeDb: boolean; + clearAllStores: boolean; + factoryResetDevice: boolean; + factoryResetConfig: boolean; +} + +type DialogVariant = keyof Dialogs; + +type Page = "messages" | "map" | "settings" | "channels" | "nodes"; + +export type ConnectionId = number; +export type ConnectionType = "http" | "bluetooth" | "serial"; +export type ConnectionStatus = + | "connected" + | "connecting" + | "disconnected" + | "disconnecting" + | "configuring" + | "configured" + | "online" + | "error"; + +export type Connection = { + id: ConnectionId; + type: ConnectionType; + name: string; + createdAt: number; + lastConnectedAt?: number; + isDefault?: boolean; + status: ConnectionStatus; + error?: string; + meshDeviceId?: number; +} & NewConnection; + +export type NewConnection = + | { type: "http"; name: string; url: string } + | { + type: "bluetooth"; + name: string; + deviceId?: string; + deviceName?: string; + gattServiceUUID?: string; + } + | { + type: "serial"; + name: string; + usbVendorId?: number; + usbProductId?: number; + }; + +type WaypointWithMetadata = Protobuf.Mesh.Waypoint & { + metadata: { + channel: number; // Channel on which the waypoint was received + created: Date; // Timestamp when the waypoint was received + updated?: Date; // Timestamp when the waypoint was last updated + from: number; // Node number of the device that sent the waypoint + }; +}; + +export type { + Page, + Dialogs, + DialogVariant, + ValidConfigType, + ValidModuleConfigType, + WaypointWithMetadata, +}; diff --git a/packages/web/src/core/stores/index.ts b/packages/web/src/core/stores/index.ts index 4cf74c94f..2d3428409 100644 --- a/packages/web/src/core/stores/index.ts +++ b/packages/web/src/core/stores/index.ts @@ -1,35 +1,53 @@ -import { useDeviceContext } from "@core/hooks/useDeviceContext"; -import { type Device, useDeviceStore } from "@core/stores/deviceStore"; -import { type MessageStore, useMessageStore } from "@core/stores/messageStore"; -import { type NodeDB, useNodeDBStore } from "@core/stores/nodeDBStore"; -import { bindStoreToDevice } from "@core/stores/utils/bindStoreToDevice"; +import { useDeviceContext } from "@core/hooks/useDeviceContext.ts"; +import { type Device, useDeviceStore } from "@core/stores/deviceStore/index.ts"; +import { + type MessageStore, + useMessageStore, +} from "@core/stores/messageStore/index.ts"; +import { type NodeDB, useNodeDBStore } from "@core/stores/nodeDBStore/index.ts"; +import { bindStoreToDevice } from "@core/stores/utils/bindStoreToDevice.ts"; export { CurrentDeviceContext, type DeviceContext, useDeviceContext, } from "@core/hooks/useDeviceContext"; -export { useAppStore } from "@core/stores/appStore"; +export { useAppStore } from "@core/stores/appStore/index.ts"; +export { type Device, useDeviceStore } from "@core/stores/deviceStore/index.ts"; export { - type Device, - type Page, - useDeviceStore, - type ValidConfigType, - type ValidModuleConfigType, - type WaypointWithMetadata, -} from "@core/stores/deviceStore"; + useActiveConnection, + useActiveConnectionId, + useAddSavedConnection, + useConnectionError, + useConnectionForDevice, + useConnectionStatus, + useDefaultConnection, + useDeviceForConnection, + useFirstSavedConnection, + useIsConnected, + useIsConnecting, + useRemoveSavedConnection, + useSavedConnections, + useUpdateSavedConnection, +} from "@core/stores/deviceStore/selectors.ts"; +export type { + Page, + ValidConfigType, + ValidModuleConfigType, + WaypointWithMetadata, +} from "@core/stores/deviceStore/types.ts"; export { MessageState, type MessageStore, MessageType, useMessageStore, } from "@core/stores/messageStore"; -export { type NodeDB, useNodeDBStore } from "@core/stores/nodeDBStore"; -export type { NodeErrorType } from "@core/stores/nodeDBStore/types"; +export { type NodeDB, useNodeDBStore } from "@core/stores/nodeDBStore/index.ts"; +export type { NodeErrorType } from "@core/stores/nodeDBStore/types.ts"; export { SidebarProvider, useSidebar, // TODO: Bring hook into this file -} from "@core/stores/sidebarStore"; +} from "@core/stores/sidebarStore/index.tsx"; // Re-export idb-keyval functions for clearing all stores, expand this if we add more local storage types export { clear as clearAllStores } from "idb-keyval"; diff --git a/packages/web/src/core/stores/messageStore/index.ts b/packages/web/src/core/stores/messageStore/index.ts index 3c86ac40f..ffc176714 100644 --- a/packages/web/src/core/stores/messageStore/index.ts +++ b/packages/web/src/core/stores/messageStore/index.ts @@ -17,6 +17,7 @@ import { produce } from "immer"; import { create as createStore, type StateCreator } from "zustand"; import { type PersistOptions, persist } from "zustand/middleware"; +const IDB_KEY_NAME = "meshtastic-message-store"; const CURRENT_STORE_VERSION = 0; const MESSAGESTORE_RETENTION_NUM = 10; const MESSAGELOG_RETENTION_NUM = 1000; // Max messages per conversation/channel @@ -43,14 +44,17 @@ export interface MessageBuckets { direct: Map; broadcast: Map; } -export interface MessageStore { + +type MessageStoreData = { + // Persisted data id: number; myNodeNum: number | undefined; - messages: MessageBuckets; drafts: Map; +}; - // Ephemeral UI state (not persisted) +export interface MessageStore extends MessageStoreData { + // Ephemeral state (not persisted) activeChat: number; chatType: MessageType; @@ -78,14 +82,6 @@ interface PrivateMessageStoreState extends MessageStoreState { messageStores: Map; } -type MessageStoreData = { - id: number; - myNodeNum: number | undefined; - - messages: MessageBuckets; - drafts: Map; -}; - type MessageStorePersisted = { messageStores: Map; }; @@ -393,7 +389,7 @@ const persistOptions: PersistOptions< PrivateMessageStoreState, MessageStorePersisted > = { - name: "meshtastic-message-store", + name: IDB_KEY_NAME, storage: createStorage(), version: CURRENT_STORE_VERSION, partialize: (s): MessageStorePersisted => ({ diff --git a/packages/web/src/core/stores/nodeDBStore/index.ts b/packages/web/src/core/stores/nodeDBStore/index.ts index 14bc40a6a..632cc7573 100644 --- a/packages/web/src/core/stores/nodeDBStore/index.ts +++ b/packages/web/src/core/stores/nodeDBStore/index.ts @@ -1,7 +1,6 @@ import { create } from "@bufbuild/protobuf"; import { featureFlags } from "@core/services/featureFlags"; import { validateIncomingNode } from "@core/stores/nodeDBStore/nodeValidation"; -import { evictOldestEntries } from "@core/stores/utils/evictOldestEntries.ts"; import { createStorage } from "@core/stores/utils/indexDB.ts"; import { Protobuf, type Types } from "@meshtastic/core"; import { produce } from "immer"; @@ -13,18 +12,24 @@ import { } from "zustand/middleware"; import type { NodeError, NodeErrorType, ProcessPacketParams } from "./types.ts"; +const IDB_KEY_NAME = "meshtastic-nodedb-store"; const CURRENT_STORE_VERSION = 0; -const NODEDB_RETENTION_NUM = 10; +const NODE_RETENTION_DAYS = 14; // Remove nodes not heard from in 14 days -export interface NodeDB { +type NodeDBData = { + // Persisted data id: number; myNodeNum: number | undefined; nodeMap: Map; nodeErrors: Map; +}; +export interface NodeDB extends NodeDBData { + // Ephemeral state (not persisted) addNode: (nodeInfo: Protobuf.Mesh.NodeInfo) => void; removeNode: (nodeNum: number) => void; removeAllNodes: (keepMyNode?: boolean) => void; + pruneStaleNodes: () => number; processPacket: (data: ProcessPacketParams) => void; addUser: (user: Types.PacketMetadata) => void; addPosition: (position: Types.PacketMetadata) => void; @@ -58,13 +63,6 @@ interface PrivateNodeDBState extends nodeDBState { nodeDBs: Map; } -type NodeDBData = { - id: number; - myNodeNum: number | undefined; - nodeMap: Map; - nodeErrors: Map; -}; - type NodeDBPersisted = { nodeDBs: Map; }; @@ -92,6 +90,11 @@ function nodeDBFactory( if (!nodeDB) { throw new Error(`No nodeDB found (id: ${id})`); } + + // Check if node already exists + const existing = nodeDB.nodeMap.get(node.num); + const isNew = !existing; + // Use validation to check the new node before adding const next = validateIncomingNode( node, @@ -107,7 +110,30 @@ function nodeDBFactory( return; } - nodeDB.nodeMap = new Map(nodeDB.nodeMap).set(node.num, next); + // Merge with existing node data if it exists + const merged = existing + ? { + ...existing, + ...next, + // Preserve existing fields if new node doesn't have them + user: next.user ?? existing.user, + position: next.position ?? existing.position, + deviceMetrics: next.deviceMetrics ?? existing.deviceMetrics, + } + : next; + + // Use the validated node's num to ensure consistency + nodeDB.nodeMap = new Map(nodeDB.nodeMap).set(merged.num, merged); + + if (isNew) { + console.log( + `[NodeDB] Adding new node from NodeInfo packet: ${merged.num} (${merged.user?.longName || "unknown"})`, + ); + } else { + console.log( + `[NodeDB] Updating existing node from NodeInfo packet: ${merged.num} (${merged.user?.longName || "unknown"})`, + ); + } }), ), @@ -147,6 +173,56 @@ function nodeDBFactory( }), ), + pruneStaleNodes: () => { + const nodeDB = get().nodeDBs.get(id); + if (!nodeDB) { + throw new Error(`No nodeDB found (id: ${id})`); + } + + const nowSec = Math.floor(Date.now() / 1000); + const cutoffSec = nowSec - NODE_RETENTION_DAYS * 24 * 60 * 60; + let prunedCount = 0; + + set( + produce((draft) => { + const nodeDB = draft.nodeDBs.get(id); + if (!nodeDB) { + throw new Error(`No nodeDB found (id: ${id})`); + } + + const newNodeMap = new Map(); + + for (const [nodeNum, node] of nodeDB.nodeMap) { + // Keep myNode regardless of lastHeard + // Keep nodes that have been heard recently + // Keep nodes without lastHeard (just in case) + if ( + nodeNum === nodeDB.myNodeNum || + !node.lastHeard || + node.lastHeard >= cutoffSec + ) { + newNodeMap.set(nodeNum, node); + } else { + prunedCount++; + console.log( + `[NodeDB] Pruning stale node ${nodeNum} (last heard ${Math.floor((nowSec - node.lastHeard) / 86400)} days ago)`, + ); + } + } + + nodeDB.nodeMap = newNodeMap; + }), + ); + + if (prunedCount > 0) { + console.log( + `[NodeDB] Pruned ${prunedCount} stale node(s) older than ${NODE_RETENTION_DAYS} days`, + ); + } + + return prunedCount; + }, + setNodeError: (nodeNum, error) => set( produce((draft) => { @@ -222,11 +298,20 @@ function nodeDBFactory( if (!nodeDB) { throw new Error(`No nodeDB found (id: ${id})`); } - const current = - nodeDB.nodeMap.get(user.from) ?? - create(Protobuf.Mesh.NodeInfoSchema); - const updated = { ...current, user: user.data, num: user.from }; + const current = nodeDB.nodeMap.get(user.from); + const isNew = !current; + const updated = { + ...(current ?? create(Protobuf.Mesh.NodeInfoSchema)), + user: user.data, + num: user.from, + }; nodeDB.nodeMap = new Map(nodeDB.nodeMap).set(user.from, updated); + + if (isNew) { + console.log( + `[NodeDB] Adding new node from user packet: ${user.from} (${user.data.longName || "unknown"})`, + ); + } }), ), @@ -237,15 +322,20 @@ function nodeDBFactory( if (!nodeDB) { throw new Error(`No nodeDB found (id: ${id})`); } - const current = - nodeDB.nodeMap.get(position.from) ?? - create(Protobuf.Mesh.NodeInfoSchema); + const current = nodeDB.nodeMap.get(position.from); + const isNew = !current; const updated = { - ...current, + ...(current ?? create(Protobuf.Mesh.NodeInfoSchema)), position: position.data, num: position.from, }; nodeDB.nodeMap = new Map(nodeDB.nodeMap).set(position.from, updated); + + if (isNew) { + console.log( + `[NodeDB] Adding new node from position packet: ${position.from}`, + ); + } }), ), @@ -413,6 +503,8 @@ export const nodeDBInitializer: StateCreator = ( addNodeDB: (id) => { const existing = get().nodeDBs.get(id); if (existing) { + // Prune stale nodes when accessing existing nodeDB + existing.pruneStaleNodes(); return existing; } @@ -420,12 +512,12 @@ export const nodeDBInitializer: StateCreator = ( set( produce((draft) => { draft.nodeDBs = new Map(draft.nodeDBs).set(id, nodeDB); - - // Enforce retention limit - evictOldestEntries(draft.nodeDBs, NODEDB_RETENTION_NUM); }), ); + // Prune stale nodes on creation (useful when rehydrating from storage) + nodeDB.pruneStaleNodes(); + return nodeDB; }, removeNodeDB: (id) => { @@ -442,7 +534,7 @@ export const nodeDBInitializer: StateCreator = ( }); const persistOptions: PersistOptions = { - name: "meshtastic-nodedb-store", + name: IDB_KEY_NAME, storage: createStorage(), version: CURRENT_STORE_VERSION, partialize: (s): NodeDBPersisted => ({ diff --git a/packages/web/src/core/stores/nodeDBStore/nodeDBStore.mock.ts b/packages/web/src/core/stores/nodeDBStore/nodeDBStore.mock.ts index 031ee84d1..f01daa990 100644 --- a/packages/web/src/core/stores/nodeDBStore/nodeDBStore.mock.ts +++ b/packages/web/src/core/stores/nodeDBStore/nodeDBStore.mock.ts @@ -15,9 +15,12 @@ export const mockNodeDBStore: NodeDB = { addUser: vi.fn(), addPosition: vi.fn(), removeNode: vi.fn(), + removeAllNodes: vi.fn(), + pruneStaleNodes: vi.fn().mockReturnValue(0), processPacket: vi.fn(), setNodeError: vi.fn(), clearNodeError: vi.fn(), + removeAllNodeErrors: vi.fn(), getNodeError: vi.fn().mockReturnValue(undefined), hasNodeError: vi.fn().mockReturnValue(false), getNodes: vi.fn().mockReturnValue([]), diff --git a/packages/web/src/core/stores/nodeDBStore/nodeDBStore.test.tsx b/packages/web/src/core/stores/nodeDBStore/nodeDBStore.test.tsx index a54827114..fadb65d41 100644 --- a/packages/web/src/core/stores/nodeDBStore/nodeDBStore.test.tsx +++ b/packages/web/src/core/stores/nodeDBStore/nodeDBStore.test.tsx @@ -66,10 +66,10 @@ describe("NodeDB store", () => { const db1 = useNodeDBStore.getState().addNodeDB(123); const db2 = useNodeDBStore.getState().addNodeDB(123); - expect(db1).toBe(db2); + expect(db1).toStrictEqual(db2); const got = useNodeDBStore.getState().getNodeDB(123); - expect(got).toBe(db1); + expect(got).toStrictEqual(db1); expect(useNodeDBStore.getState().getNodeDBs().length).toBe(1); }); @@ -204,15 +204,18 @@ describe("NodeDB store", () => { expect(filtered.map((n) => n.num).sort()).toEqual([12]); // still excludes 11 }); - it("when exceeding cap, evicts earliest inserted, not the newly added", async () => { + it("will prune nodes after 14 days of inactivitiy", async () => { const { useNodeDBStore } = await freshStore(); const st = useNodeDBStore.getState(); - for (let i = 1; i <= 10; i++) { - st.addNodeDB(i); - } - st.addNodeDB(11); - expect(st.getNodeDB(1)).toBeUndefined(); - expect(st.getNodeDB(11)).toBeDefined(); + st.addNodeDB(1).addNode( + makeNode(1, { lastHeard: Date.now() / 1000 - 15 * 24 * 3600 }), + ); // 15 days ago + st.addNodeDB(1).addNode( + makeNode(2, { lastHeard: Date.now() / 1000 - 7 * 24 * 3600 }), + ); // 7 days ago + + st.getNodeDB(1)!.pruneStaleNodes(); + expect(st.getNodeDB(1)?.getNode(2)).toBeDefined(); }); it("removeNodeDB persists removal across reload", async () => { @@ -401,28 +404,6 @@ describe("NodeDB – merge semantics, PKI checks & extras", () => { expect(newDB.getNodeError(2)!.error).toBe("NEW_ERR"); // new added }); - it("eviction still honors cap after merge", async () => { - const { useNodeDBStore } = await freshStore(); - const st = useNodeDBStore.getState(); - - for (let i = 1; i <= 10; i++) { - st.addNodeDB(i); - } - const oldDB = st.addNodeDB(100); - oldDB.setNodeNum(12345); - oldDB.addNode(makeNode(2000)); - - const newDB = st.addNodeDB(101); - newDB.setNodeNum(12345); // merges + deletes 100 - - // adding another to trigger eviction of earliest non-merged entry (which was 1) - st.addNodeDB(102); - - expect(st.getNodeDB(1)).toBeUndefined(); // evicted - expect(st.getNodeDB(101)).toBeDefined(); // merged entry exists - expect(st.getNodeDB(101)!.getNode(2000)).toBeTruthy(); // carried over - }); - it("removeAllNodes (optionally keeping my node) and removeAllNodeErrors persist across reload", async () => { { const { useNodeDBStore } = await freshStore(true); // with persistence @@ -456,7 +437,7 @@ describe("NodeDB – merge semantics, PKI checks & extras", () => { const newDB = st.addNodeDB(1101); newDB.setNodeNum(4242); - expect(newDB.getMyNode().num).toBe(4242); + expect(newDB.getMyNode()?.num).toBe(4242); }); }); diff --git a/packages/web/src/core/stores/utils/evictOldestEntries.ts b/packages/web/src/core/stores/utils/evictOldestEntries.ts index 500726dea..2e4631f45 100644 --- a/packages/web/src/core/stores/utils/evictOldestEntries.ts +++ b/packages/web/src/core/stores/utils/evictOldestEntries.ts @@ -1,14 +1,24 @@ -export function evictOldestEntries( - map: Map, +export function evictOldestEntries(arr: T[], maxSize: number): void; +export function evictOldestEntries(map: Map, maxSize: number): void; + +export function evictOldestEntries( + collection: T[] | Map, maxSize: number, ): void { - // while loop in case maxSize is ever changed to be lower, to trim all the way down - while (map.size > maxSize) { - const firstKey = map.keys().next().value; // maps keep insertion order, so this is oldest - if (firstKey !== undefined) { - map.delete(firstKey); - } else { - break; // should not happen, but just in case + if (Array.isArray(collection)) { + // Trim array from the front (assuming oldest entries are at the start) + while (collection.length > maxSize) { + collection.shift(); + } + } else if (collection instanceof Map) { + // Trim map by insertion order + while (collection.size > maxSize) { + const firstKey = collection.keys().next().value; + if (firstKey !== undefined) { + collection.delete(firstKey); + } else { + break; + } } } } diff --git a/packages/web/src/core/subscriptions.ts b/packages/web/src/core/subscriptions.ts index 78f0bd808..f20f5443d 100644 --- a/packages/web/src/core/subscriptions.ts +++ b/packages/web/src/core/subscriptions.ts @@ -1,4 +1,3 @@ -import { ensureDefaultUser } from "@core/dto/NodeNumToNodeInfoDTO.ts"; import PacketToMessageDTO from "@core/dto/PacketToMessageDTO.ts"; import { useNewNodeNum } from "@core/hooks/useNewNodeNum"; import { @@ -68,11 +67,11 @@ export const subscribeAll = ( nodeDB.addPosition(position); }); + // NOTE: Node handling is managed by the nodeDB + // Nodes are added via subscriptions.ts and stored in nodeDB + // Configuration is handled directly by meshDevice.configure() in useConnections connection.events.onNodeInfoPacket.subscribe((nodeInfo) => { - const nodeWithUser = ensureDefaultUser(nodeInfo); - - // PKI sanity check is handled inside nodeDB.addNode - nodeDB.addNode(nodeWithUser); + nodeDB.addNode(nodeInfo); }); connection.events.onChannelPacket.subscribe((channel) => { diff --git a/packages/web/src/core/utils/color.test.ts b/packages/web/src/core/utils/color.test.ts new file mode 100644 index 000000000..678a5135d --- /dev/null +++ b/packages/web/src/core/utils/color.test.ts @@ -0,0 +1,93 @@ +import { describe, expect, it } from "vitest"; +import { + getColorFromNodeNum, + hexToRgb, + isLightColor, + type RGBColor, + rgbToHex, +} from "./color.ts"; + +describe("hexToRgb", () => { + it.each([ + [0x000000, { r: 0, g: 0, b: 0 }], + [0xffffff, { r: 255, g: 255, b: 255 }], + [0x123456, { r: 0x12, g: 0x34, b: 0x56 }], + [0xff8000, { r: 255, g: 128, b: 0 }], + ])("parses 0x%s correctly", (hex, expected) => { + expect(hexToRgb(hex)).toEqual(expected); + }); +}); + +describe("rgbToHex", () => { + it.each<[RGBColor, number]>([ + [{ r: 0, g: 0, b: 0 }, 0x000000], + [{ r: 255, g: 255, b: 255 }, 0xffffff], + [{ r: 0x12, g: 0x34, b: 0x56 }, 0x123456], + [{ r: 255, g: 128, b: 0 }, 0xff8000], + ])("packs %j into 0x%s", (rgb, expected) => { + expect(rgbToHex(rgb)).toBe(expected); + }); + + it("rounds component values before packing", () => { + expect(rgbToHex({ r: 12.2, g: 12.8, b: 99.5 })).toBe( + (12 << 16) | (13 << 8) | 100, + ); + }); +}); + +describe("hexToRgb ⟷ rgbToHex round-trip", () => { + it("is identity for representative values (masked to 24-bit)", () => { + const samples = [0, 1, 0x7fffff, 0x800000, 0xffffff, 0x123456, 0x00ff00]; + for (const hex of samples) { + const rgb = hexToRgb(hex); + expect(rgbToHex(rgb)).toBe(hex & 0xffffff); + } + }); + + it("holds for random 24-bit values", () => { + for (let i = 0; i < 100; i++) { + const hex = Math.floor(Math.random() * 0x1000000); // 0..0xFFFFFF + expect(rgbToHex(hexToRgb(hex))).toBe(hex); + } + }); +}); + +describe("isLightColor", () => { + it("detects obvious extremes", () => { + expect(isLightColor({ r: 255, g: 255, b: 255 })).toBe(true); // white + expect(isLightColor({ r: 0, g: 0, b: 0 })).toBe(false); // black + }); + + it("respects the 127.5 threshold at boundary", () => { + // mid-gray 127 → false, 128 → true (given the formula and 127.5 threshold) + expect(isLightColor({ r: 127, g: 127, b: 127 })).toBe(false); + expect(isLightColor({ r: 128, g: 128, b: 128 })).toBe(true); + }); +}); + +describe("getColorFromNodeNum", () => { + it.each([ + [0x000000, { r: 0, g: 0, b: 0 }], + [0xffffff, { r: 255, g: 255, b: 255 }], + [0x123456, { r: 0x12, g: 0x34, b: 0x56 }], + ])("extracts RGB from lower 24 bits of %s", (nodeNum, expected) => { + expect(getColorFromNodeNum(nodeNum)).toEqual(expected); + }); + + it("matches hexToRgb when masking to 24 bits", () => { + const nodeNums = [1127947528, 42, 999999, 0xfeef12, 0xfeedface, -123456]; + for (const n of nodeNums) { + // JS bitwise ops use signed 32-bit, so mask the lower 24 bits for comparison. + const masked = n & 0xffffff; + expect(getColorFromNodeNum(n)).toEqual(hexToRgb(masked)); + } + }); + + it("always yields components within 0..255", () => { + const color = getColorFromNodeNum(Math.floor(Math.random() * 2 ** 31)); + for (const v of Object.values(color)) { + expect(v).toBeGreaterThanOrEqual(0); + expect(v).toBeLessThanOrEqual(255); + } + }); +}); diff --git a/packages/web/src/core/utils/color.ts b/packages/web/src/core/utils/color.ts index 9abb7b301..cfbe286d0 100644 --- a/packages/web/src/core/utils/color.ts +++ b/packages/web/src/core/utils/color.ts @@ -2,39 +2,25 @@ export interface RGBColor { r: number; g: number; b: number; - a: number; } export const hexToRgb = (hex: number): RGBColor => ({ r: (hex & 0xff0000) >> 16, g: (hex & 0x00ff00) >> 8, b: hex & 0x0000ff, - a: 255, }); export const rgbToHex = (c: RGBColor): number => - (Math.round(c.a) << 24) | - (Math.round(c.r) << 16) | - (Math.round(c.g) << 8) | - Math.round(c.b); + (Math.round(c.r) << 16) | (Math.round(c.g) << 8) | Math.round(c.b); export const isLightColor = (c: RGBColor): boolean => (c.r * 299 + c.g * 587 + c.b * 114) / 1000 > 127.5; -export const getColorFromText = (text: string): RGBColor => { - if (!text) { - return { r: 0, g: 0, b: 0, a: 255 }; - } +export const getColorFromNodeNum = (nodeNum: number): RGBColor => { + // Extract RGB values directly from nodeNum (treated as hex color) + const r = (nodeNum & 0xff0000) >> 16; + const g = (nodeNum & 0x00ff00) >> 8; + const b = nodeNum & 0x0000ff; - let hash = 0; - for (let i = 0; i < text.length; i++) { - hash = text.charCodeAt(i) + ((hash << 5) - hash); - hash |= 0; // force 32‑bit - } - return { - r: (hash & 0xff0000) >> 16, - g: (hash & 0x00ff00) >> 8, - b: hash & 0x0000ff, - a: 255, - }; + return { r, g, b }; }; diff --git a/packages/web/src/i18n-config.ts b/packages/web/src/i18n-config.ts index 08f50ba06..3c6f4637e 100644 --- a/packages/web/src/i18n-config.ts +++ b/packages/web/src/i18n-config.ts @@ -13,9 +13,10 @@ export type Lang = { export type LangCode = Lang["code"]; export const supportedLanguages: Lang[] = [ + { code: "fi", name: "Suomi", flag: "🇫🇮" }, { code: "de", name: "Deutsch", flag: "🇩🇪" }, { code: "en", name: "English", flag: "🇺🇸" }, - { code: "fi", name: "Suomi", flag: "🇫🇮" }, + { code: "fr", name: "Français", flag: "🇫🇷" }, { code: "sv", name: "Svenska", flag: "🇸🇪" }, ]; @@ -41,6 +42,7 @@ i18next fallbackLng: { default: [FALLBACK_LANGUAGE_CODE], fi: ["fi-FI", FALLBACK_LANGUAGE_CODE], + fr: ["fr-FR", FALLBACK_LANGUAGE_CODE], sv: ["sv-SE", FALLBACK_LANGUAGE_CODE], de: ["de-DE", FALLBACK_LANGUAGE_CODE], }, @@ -48,11 +50,11 @@ i18next debug: import.meta.env.MODE === "development", ns: [ "channels", + "connections", "commandPalette", "common", - "deviceConfig", + "config", "moduleConfig", - "dashboard", "dialog", "messages", "nodes", diff --git a/packages/web/src/index.css b/packages/web/src/index.css index 5ab88c885..f9a80685d 100644 --- a/packages/web/src/index.css +++ b/packages/web/src/index.css @@ -1,14 +1,33 @@ -@import "tailwindcss"; +@font-face { + font-family: 'Inter var'; + font-style: normal; + font-weight: 100 900; + font-display: swap; + src: url('/fonts/InterVariable.woff2') format('woff2'); +} +@font-face { + font-family: 'Inter var'; + font-style: italic; + font-weight: 100 900; + font-display: swap; + src: url('/fonts/InterVariable-Italic.woff2') format('woff2'); +} + +@import "tailwindcss"; +/* @import '@meshtastic/ui/theme/default.css'; */ +/* @source "../node_modules/@meshtastic/ui"; */ @custom-variant dark (&:where([data-theme=dark], [data-theme=dark] *)); @view-transition { navigation: auto; } + + @theme { --font-mono: - Cascadia Code, ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, + ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace; --font-sans: Inter var, ui-sans-serif, system-ui, sans-serif, "Apple Color Emoji", @@ -76,7 +95,7 @@ .animate-fan-out { transform: translate(var(--dx), var(--dy)); - transition: transform 200ms ease-out; /* expand AND collapse */ + transition: transform 200ms ease-out; } @@ -91,12 +110,10 @@ body { body { font-family: var(--font-sans); -} -.app-container { - height: 100%; } + @layer base { *, @@ -106,6 +123,32 @@ body { ::file-selector-button { border-color: var(--color-slate-200, currentColor); } + + ::-webkit-scrollbar { + @apply bg-transparent w-2; + } + + ::-webkit-scrollbar-thumb { + @apply bg-gray-400; + } + + ::-webkit-scrollbar-corner { + @apply bg-slate-200; + } + + .dark { + ::-webkit-scrollbar { + @apply bg-transparent w-2; + } + + ::-webkit-scrollbar-thumb { + @apply bg-slate-600 rounded-4xl; + } + + ::-webkit-scrollbar-corner { + @apply bg-slate-900; + } + } } @layer components { diff --git a/packages/web/src/pages/Connections/index.tsx b/packages/web/src/pages/Connections/index.tsx new file mode 100644 index 000000000..27c413c30 --- /dev/null +++ b/packages/web/src/pages/Connections/index.tsx @@ -0,0 +1,423 @@ +import AddConnectionDialog from "@app/components/Dialog/AddConnectionDialog/AddConnectionDialog"; +import { TimeAgo } from "@app/components/generic/TimeAgo"; +import LanguageSwitcher from "@app/components/LanguageSwitcher"; +import { ConnectionStatusBadge } from "@app/components/PageComponents/Connections/ConnectionStatusBadge"; +import type { Connection } from "@app/core/stores/deviceStore/types"; +import { useConnections } from "@app/pages/Connections/useConnections"; +import { + connectionTypeIcon, + formatConnectionSubtext, +} from "@app/pages/Connections/utils"; +import { + AlertDialog, + AlertDialogAction, + AlertDialogCancel, + AlertDialogContent, + AlertDialogDescription, + AlertDialogFooter, + AlertDialogHeader, + AlertDialogTitle, + AlertDialogTrigger, +} from "@components/UI/AlertDialog.tsx"; +import { Badge } from "@components/UI/Badge.tsx"; +import { Button } from "@components/UI/Button.tsx"; +import { + Card, + CardContent, + CardFooter, + CardHeader, + CardTitle, +} from "@components/UI/Card.tsx"; +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuTrigger, +} from "@components/UI/DropdownMenu.tsx"; +import { Separator } from "@components/UI/Separator.tsx"; +import { useToast } from "@core/hooks/useToast.ts"; +import { useNavigate } from "@tanstack/react-router"; +import { + ArrowLeft, + LinkIcon, + MoreHorizontal, + RotateCw, + RouterIcon, + Star, + StarOff, + Trash2, +} from "lucide-react"; +import { useEffect, useMemo, useState } from "react"; +import { useTranslation } from "react-i18next"; + +export const Connections = () => { + const { + connections, + addConnectionAndConnect, + connect, + disconnect, + removeConnection, + setDefaultConnection, + refreshStatuses, + syncConnectionStatuses, + } = useConnections(); + const { toast } = useToast(); + const navigate = useNavigate({ from: "/" }); + const [addOpen, setAddOpen] = useState(false); + const isURLHTTPS = useMemo(() => location.protocol === "https:", []); + const { t } = useTranslation("connections"); + + // On first mount, sync statuses and refresh + // biome-ignore lint/correctness/useExhaustiveDependencies: This can cause the icon to refresh too often + useEffect(() => { + syncConnectionStatuses(); + refreshStatuses(); + }, []); + const sorted = useMemo(() => { + const copy = [...connections]; + return copy.sort((a, b) => { + if (a.isDefault && !b.isDefault) { + return -1; + } + if (!a.isDefault && b.isDefault) { + return 1; + } + const aConnected = a.status === "connected" || a.status === "configured"; + const bConnected = b.status === "connected" || b.status === "configured"; + if (aConnected && !bConnected) { + return -1; + } + return a.name.localeCompare(b.name); + }); + }, [connections]); + + return ( +
    +
    +
    + +
    +

    + {t("page.title")} +

    +

    + {t("page.description")} +

    +
    +
    +
    + + +
    +
    + + + + {sorted.length === 0 ? ( + + + + {t("noConnections.title")}{" "} + + + + {t("noConnections.description")} + + + + + + ) : ( +
    + {sorted.map((c) => ( + { + const ok = await connect(c.id, { allowPrompt: true }); + toast({ + title: ok ? t("toasts.connected") : t("toasts.failed"), + description: ok + ? t("toasts.nowConnected", { + name: c.name, + interpolation: { escapeValue: false }, + }) + : t("toasts.checkConnection"), + }); + if (ok) { + navigate({ to: "/" }); + } + }} + onDisconnect={async () => { + await disconnect(c.id); + toast({ + title: t("toasts.disconnected"), + description: t("toasts.nowDisconnected", { + name: c.name, + interpolation: { escapeValue: false }, + }), + }); + }} + onSetDefault={() => { + setDefaultConnection(c.id); + toast({ + title: t("toasts.defaultSet"), + description: t("toasts.defaultConnection", { + name: c.name, + interpolation: { escapeValue: false }, + }), + }); + }} + onDelete={async () => { + await disconnect(c.id); + removeConnection(c.id); + toast({ + title: t("toasts.deleted"), + description: t("toasts.deletedByName", { + name: c.name, + interpolation: { escapeValue: false }, + }), + }); + }} + onRetry={async () => { + const ok = await connect(c.id, { allowPrompt: true }); + toast({ + title: ok ? t("toasts.connected") : t("toasts.failed"), + description: ok + ? t("toasts.nowConnected", { + name: c.name, + interpolation: { escapeValue: false }, + }) + : t("toasts.pickConnectionAgain"), + }); + if (ok) { + navigate({ to: "/" }); + } + }} + /> + ))} +
    + )} + + { + const created = await addConnectionAndConnect(partial, btDevice); + if (created) { + setAddOpen(false); + toast({ + title: t("toasts.added"), + description: t("toasts.savedByName", { + name: created.name, + interpolation: { escapeValue: false }, + }), + }); + if ( + created.status === "connected" || + created.status === "configured" + ) { + navigate({ to: "/" }); + } + } else { + toast({ + title: "Unable to connect", + description: "savedCantConnect", + }); + } + }} + /> +
    + ); +}; + +function TypeBadge({ type }: { type: Connection["type"] }) { + const Icon = connectionTypeIcon(type); + const label = + type === "http" ? "HTTP" : type === "bluetooth" ? "Bluetooth" : "Serial"; + return ( + + + {label} + + ); +} + +function ConnectionCard({ + connection, + onConnect, + onDisconnect, + onSetDefault, + onDelete, + onRetry, +}: { + connection: Connection; + onConnect: () => Promise | Promise; + onDisconnect: () => Promise | Promise; + onSetDefault: () => void; + onDelete: () => void; + onRetry: () => Promise | Promise; +}) { + const { t } = useTranslation("connections"); + + const Icon = connectionTypeIcon(connection.type); + const isBusy = + connection.status === "connecting" || connection.status === "configuring"; + const isConnected = + connection.status === "connected" || connection.status === "configured"; + const isError = connection.status === "error"; + + return ( + + +
    +
    + + + {connection.name} + {connection.isDefault ? ( + + + {t("default")} + + ) : null} + +
    + + + {formatConnectionSubtext(connection)} + +
    +
    +
    + + + + + + + + {connection.type === "http" && connection.isDefault && ( + onSetDefault()} + > + + {t("button.unsetDefault")} + + )} + {connection.type === "http" && !connection.isDefault && ( + onSetDefault()} + > + + {t("button.setDefault")} + + )} + + + e.preventDefault()} + > + + {t("button.delete")} + + + + + + {t("deleteConnection")} + + + {t("areYouSure", { name: connection.name })} + + + + + {t("button.cancel")} + + onDelete()} + > + {t("button.delete")} + + + + + + +
    +
    +
    + + {connection.error ? ( +

    + {connection.error} +

    + ) : connection.lastConnectedAt ? ( +

    + {t("lastConnectedAt", { date: "" })}{" "} + +

    + ) : ( +

    + {t("neverConnected")} +

    + )} +
    + + {isConnected ? ( + + ) : ( + + )} + +
    + ); +} diff --git a/packages/web/src/pages/Connections/useConnections.ts b/packages/web/src/pages/Connections/useConnections.ts new file mode 100644 index 000000000..206e24ab0 --- /dev/null +++ b/packages/web/src/pages/Connections/useConnections.ts @@ -0,0 +1,660 @@ +import type { + Connection, + ConnectionId, + ConnectionStatus, + NewConnection, +} from "@app/core/stores/deviceStore/types"; +import { + createConnectionFromInput, + testHttpReachable, +} from "@app/pages/Connections/utils"; +import { + useAppStore, + useDeviceStore, + useMessageStore, + useNodeDBStore, +} from "@core/stores"; +import { subscribeAll } from "@core/subscriptions.ts"; +import { randId } from "@core/utils/randId.ts"; +import { MeshDevice } from "@meshtastic/core"; +import { TransportHTTP } from "@meshtastic/transport-http"; +import { TransportWebBluetooth } from "@meshtastic/transport-web-bluetooth"; +import { TransportWebSerial } from "@meshtastic/transport-web-serial"; +import { useCallback } from "react"; + +// Local storage for cleanup only (not in Zustand) +const transports = new Map(); +const heartbeats = new Map>(); +const configSubscriptions = new Map void>(); + +const HEARTBEAT_INTERVAL_MS = 5 * 60 * 1000; // 5 minutes +const CONFIG_HEARTBEAT_INTERVAL_MS = 5000; // 5s during configuration + +export function useConnections() { + const connections = useDeviceStore((s) => s.savedConnections); + + const addSavedConnection = useDeviceStore((s) => s.addSavedConnection); + const updateSavedConnection = useDeviceStore((s) => s.updateSavedConnection); + const removeSavedConnectionFromStore = useDeviceStore( + (s) => s.removeSavedConnection, + ); + + // DeviceStore methods + const setActiveConnectionId = useDeviceStore((s) => s.setActiveConnectionId); + + const { addDevice } = useDeviceStore(); + const { addNodeDB } = useNodeDBStore(); + const { addMessageStore } = useMessageStore(); + const { setSelectedDevice } = useAppStore(); + const selectedDeviceId = useAppStore((s) => s.selectedDeviceId); + + const updateStatus = useCallback( + (id: ConnectionId, status: ConnectionStatus, error?: string) => { + const updates: Partial = { + status, + error: error || undefined, + ...(status === "disconnected" ? { lastConnectedAt: Date.now() } : {}), + }; + updateSavedConnection(id, updates); + }, + [updateSavedConnection], + ); + + const removeConnection = useCallback( + (id: ConnectionId) => { + const conn = connections.find((c) => c.id === id); + + // Stop heartbeat + const heartbeatId = heartbeats.get(id); + if (heartbeatId) { + clearInterval(heartbeatId); + heartbeats.delete(id); + console.log(`[useConnections] Heartbeat stopped for connection ${id}`); + } + + // Unsubscribe from config complete event + const unsubConfigComplete = configSubscriptions.get(id); + if (unsubConfigComplete) { + unsubConfigComplete(); + configSubscriptions.delete(id); + console.log( + `[useConnections] Config subscription cleaned up for connection ${id}`, + ); + } + + // Get device and MeshDevice from Device.connection + if (conn?.meshDeviceId) { + const { getDevice, removeDevice } = useDeviceStore.getState(); + const device = getDevice(conn.meshDeviceId); + + if (device?.connection) { + // Disconnect MeshDevice + try { + device.connection.disconnect(); + } catch {} + } + + // Close transport if it's BT or Serial + const transport = transports.get(id); + if (transport) { + const bt = transport as BluetoothDevice; + if (bt.gatt?.connected) { + try { + bt.gatt.disconnect(); + } catch {} + } + + const sp = transport as SerialPort & { close?: () => Promise }; + if (sp.close) { + try { + sp.close(); + } catch {} + } + + transports.delete(id); + } + + // Clean up orphaned Device + try { + removeDevice(conn.meshDeviceId); + } catch {} + } + + removeSavedConnectionFromStore(id); + }, + [connections, removeSavedConnectionFromStore], + ); + + const setDefaultConnection = useCallback( + (id: ConnectionId) => { + for (const connection of connections) { + if (connection.id === id) { + updateSavedConnection(connection.id, { + isDefault: !connection.isDefault, + }); + } + } + }, + [connections, updateSavedConnection], + ); + + const setupMeshDevice = useCallback( + ( + id: ConnectionId, + transport: + | Awaited> + | Awaited> + | Awaited>, + btDevice?: BluetoothDevice, + serialPort?: SerialPort, + ): number => { + // Reuse existing meshDeviceId if available to prevent duplicate nodeDBs, + // but only if the corresponding nodeDB still exists. Otherwise, generate a new ID. + const conn = connections.find((c) => c.id === id); + let deviceId = conn?.meshDeviceId; + if (deviceId && !useNodeDBStore.getState().getNodeDB(deviceId)) { + deviceId = undefined; + } + deviceId = deviceId ?? randId(); + + const device = addDevice(deviceId); + const nodeDB = addNodeDB(deviceId); + const messageStore = addMessageStore(deviceId); + const meshDevice = new MeshDevice(transport, deviceId); + + setSelectedDevice(deviceId); + device.addConnection(meshDevice); // This stores meshDevice in Device.connection + subscribeAll(device, meshDevice, messageStore, nodeDB); + + // Store transport locally for cleanup (BT/Serial only) + if (btDevice || serialPort) { + transports.set(id, btDevice || serialPort); + } + + // Set active connection and link device bidirectionally + setActiveConnectionId(id); + device.setConnectionId(id); + + // Listen for config complete event (with nonce/ID) + const unsubConfigComplete = meshDevice.events.onConfigComplete.subscribe( + (configCompleteId) => { + console.log( + `[useConnections] Configuration complete with ID: ${configCompleteId}`, + ); + device.setConnectionPhase("configured"); + updateStatus(id, "configured"); + + // Switch from fast config heartbeat to slow maintenance heartbeat + const oldHeartbeat = heartbeats.get(id); + if (oldHeartbeat) { + clearInterval(oldHeartbeat); + console.log( + `[useConnections] Switching to maintenance heartbeat (5 min interval)`, + ); + } + + const maintenanceHeartbeat = setInterval(() => { + meshDevice.heartbeat().catch((error) => { + console.warn("[useConnections] Heartbeat failed:", error); + }); + }, HEARTBEAT_INTERVAL_MS); + heartbeats.set(id, maintenanceHeartbeat); + }, + ); + configSubscriptions.set(id, unsubConfigComplete); + + // Start configuration + device.setConnectionPhase("configuring"); + updateStatus(id, "configuring"); + console.log("[useConnections] Starting configuration"); + + meshDevice + .configure() + .then(() => { + console.log( + "[useConnections] Configuration complete, starting heartbeat", + ); + // Send initial heartbeat after configure completes + meshDevice + .heartbeat() + .then(() => { + // Start fast heartbeat after first successful heartbeat + const configHeartbeatId = setInterval(() => { + meshDevice.heartbeat().catch((error) => { + console.warn( + "[useConnections] Config heartbeat failed:", + error, + ); + }); + }, CONFIG_HEARTBEAT_INTERVAL_MS); + heartbeats.set(id, configHeartbeatId); + console.log( + `[useConnections] Heartbeat started for connection ${id} (5s interval during config)`, + ); + }) + .catch((error) => { + console.warn("[useConnections] Initial heartbeat failed:", error); + }); + }) + .catch((error) => { + console.error(`[useConnections] Failed to configure:`, error); + updateStatus(id, "error", error.message); + }); + + updateSavedConnection(id, { meshDeviceId: deviceId }); + return deviceId; + }, + [ + connections, + addDevice, + addNodeDB, + addMessageStore, + setSelectedDevice, + setActiveConnectionId, + updateSavedConnection, + updateStatus, + ], + ); + + const connect = useCallback( + async (id: ConnectionId, opts?: { allowPrompt?: boolean }) => { + const conn = connections.find((c) => c.id === id); + if (!conn) { + return false; + } + if (conn.status === "configured" || conn.status === "connected") { + return true; + } + + updateStatus(id, "connecting"); + try { + if (conn.type === "http") { + const ok = await testHttpReachable(conn.url); + if (!ok) { + const url = new URL(conn.url); + const isHTTPS = url.protocol === "https:"; + const message = isHTTPS + ? `Cannot reach HTTPS endpoint. If using a self-signed certificate, open ${conn.url} in a new tab, accept the certificate warning, then try connecting again.` + : "HTTP endpoint not reachable (may be blocked by CORS)"; + throw new Error(message); + } + + const url = new URL(conn.url); + const isTLS = url.protocol === "https:"; + const transport = await TransportHTTP.create(url.host, isTLS); + setupMeshDevice(id, transport); + // Status will be set to "configured" by onConfigComplete event + return true; + } + + if (conn.type === "bluetooth") { + if (!("bluetooth" in navigator)) { + throw new Error("Web Bluetooth not supported"); + } + let bleDevice = transports.get(id) as BluetoothDevice | undefined; + if (!bleDevice) { + // Try to recover permitted devices + const getDevices = ( + navigator.bluetooth as Navigator["bluetooth"] & { + getDevices?: () => Promise; + } + ).getDevices; + + if (getDevices) { + const known = await getDevices(); + if (known && known.length > 0 && conn.deviceId) { + bleDevice = known.find( + (d: BluetoothDevice) => d.id === conn.deviceId, + ); + } + } + } + if (!bleDevice && opts?.allowPrompt) { + // Prompt user to reselect (filter by optional service if provided) + bleDevice = await navigator.bluetooth.requestDevice({ + acceptAllDevices: !conn.gattServiceUUID, + optionalServices: conn.gattServiceUUID + ? [conn.gattServiceUUID] + : undefined, + filters: conn.gattServiceUUID + ? [{ services: [conn.gattServiceUUID] }] + : undefined, + }); + } + if (!bleDevice) { + throw new Error( + "Bluetooth device not available. Re-select the device.", + ); + } + + const transport = + await TransportWebBluetooth.createFromDevice(bleDevice); + setupMeshDevice(id, transport, bleDevice); + + bleDevice.addEventListener("gattserverdisconnected", () => { + updateStatus(id, "disconnected"); + }); + + // Status will be set to "configured" by onConfigComplete event + return true; + } + + if (conn.type === "serial") { + if (!("serial" in navigator)) { + throw new Error("Web Serial not supported"); + } + let port = transports.get(id) as SerialPort | undefined; + if (!port) { + // Find a previously granted port by vendor/product + const ports: SerialPort[] = await ( + navigator as Navigator & { + serial: { getPorts: () => Promise }; + } + ).serial.getPorts(); + if (ports && conn.usbVendorId && conn.usbProductId) { + port = ports.find((p: SerialPort) => { + const info = + ( + p as SerialPort & { + getInfo?: () => { + usbVendorId?: number; + usbProductId?: number; + }; + } + ).getInfo?.() ?? {}; + return ( + info.usbVendorId === conn.usbVendorId && + info.usbProductId === conn.usbProductId + ); + }); + } + } + if (!port && opts?.allowPrompt) { + port = await ( + navigator as Navigator & { + serial: { + requestPort: ( + options: Record, + ) => Promise; + }; + } + ).serial.requestPort({}); + } + if (!port) { + throw new Error("Serial port not available. Re-select the port."); + } + + // Ensure the port is closed before opening it + const portWithStreams = port as SerialPort & { + readable: ReadableStream | null; + writable: WritableStream | null; + close: () => Promise; + }; + if (portWithStreams.readable || portWithStreams.writable) { + try { + await portWithStreams.close(); + await new Promise((resolve) => setTimeout(resolve, 100)); + } catch (err) { + console.warn("Error closing port before reconnect:", err); + } + } + + const transport = await TransportWebSerial.createFromPort(port); + setupMeshDevice(id, transport, undefined, port); + // Status will be set to "configured" by onConfigComplete event + return true; + } + } catch (err: unknown) { + const message = err instanceof Error ? err.message : String(err); + updateStatus(id, "error", message); + return false; + } + return false; + }, + [connections, updateStatus, setupMeshDevice], + ); + + const disconnect = useCallback( + async (id: ConnectionId) => { + const conn = connections.find((c) => c.id === id); + if (!conn) { + return; + } + try { + // Stop heartbeat + const heartbeatId = heartbeats.get(id); + if (heartbeatId) { + clearInterval(heartbeatId); + heartbeats.delete(id); + console.log( + `[useConnections] Heartbeat stopped for connection ${id}`, + ); + } + + // Unsubscribe from config complete event + const unsubConfigComplete = configSubscriptions.get(id); + if (unsubConfigComplete) { + unsubConfigComplete(); + configSubscriptions.delete(id); + console.log( + `[useConnections] Config subscription cleaned up for connection ${id}`, + ); + } + + // Get device and meshDevice from Device.connection + if (conn.meshDeviceId) { + const { getDevice } = useDeviceStore.getState(); + const device = getDevice(conn.meshDeviceId); + + if (device?.connection) { + // Disconnect MeshDevice + try { + device.connection.disconnect(); + } catch { + // Ignore errors + } + } + + // Close transport connections + const transport = transports.get(id); + if (transport) { + if (conn.type === "bluetooth") { + const dev = transport as BluetoothDevice; + if (dev.gatt?.connected) { + dev.gatt.disconnect(); + } + } + if (conn.type === "serial") { + const port = transport as SerialPort & { + close?: () => Promise; + readable?: ReadableStream | null; + }; + if (port.close && port.readable) { + try { + await port.close(); + } catch (err) { + console.warn("Error closing serial port:", err); + } + } + } + } + + // Clear the device's connectionId link + if (device) { + device.setConnectionId(null); + device.setConnectionPhase("disconnected"); + } + } + } finally { + updateSavedConnection(id, { + status: "disconnected", + error: undefined, + }); + } + }, + [connections, updateSavedConnection], + ); + + const addConnection = useCallback( + (input: NewConnection) => { + const conn = createConnectionFromInput(input); + addSavedConnection(conn); + return conn; + }, + [addSavedConnection], + ); + + const addConnectionAndConnect = useCallback( + async (input: NewConnection, btDevice?: BluetoothDevice) => { + const conn = addConnection(input); + // If a Bluetooth device was provided, store it to avoid re-prompting + if (btDevice && conn.type === "bluetooth") { + transports.set(conn.id, btDevice); + } + await connect(conn.id, { allowPrompt: true }); + // Get updated connection from store after connect + if (conn.id) { + return conn; + } + }, + [addConnection, connect], + ); + + const refreshStatuses = useCallback(async () => { + // Check reachability/availability without auto-connecting + // HTTP: test endpoint reachability + // Bluetooth/Serial: check permission grants + + // HTTP connections: test reachability if not already connected/configured + const httpChecks = connections + .filter( + (c): c is Connection & { type: "http"; url: string } => + c.type === "http" && + c.status !== "connected" && + c.status !== "configured" && + c.status !== "configuring", + ) + .map(async (c) => { + const ok = await testHttpReachable(c.url); + updateSavedConnection(c.id, { + status: ok ? "online" : "error", + }); + }); + + // Bluetooth connections: check permission grants + const btChecks = connections + .filter( + (c): c is Connection & { type: "bluetooth"; deviceId?: string } => + c.type === "bluetooth" && + c.status !== "connected" && + c.status !== "configured" && + c.status !== "configuring", + ) + .map(async (c) => { + if (!("bluetooth" in navigator)) { + return; + } + try { + const known = await ( + navigator.bluetooth as Navigator["bluetooth"] & { + getDevices?: () => Promise; + } + ).getDevices?.(); + const hasPermission = known?.some( + (d: BluetoothDevice) => d.id === c.deviceId, + ); + updateSavedConnection(c.id, { + status: hasPermission ? "configured" : "disconnected", + }); + } catch { + // getDevices not supported or failed + updateSavedConnection(c.id, { status: "disconnected" }); + } + }); + + // Serial connections: check permission grants + const serialChecks = connections + .filter( + ( + c, + ): c is Connection & { + type: "serial"; + usbVendorId?: number; + usbProductId?: number; + } => + c.type === "serial" && + c.status !== "connected" && + c.status !== "configured" && + c.status !== "configuring", + ) + .map(async (c) => { + if (!("serial" in navigator)) { + return; + } + try { + const ports: SerialPort[] = await ( + navigator as Navigator & { + serial: { getPorts: () => Promise }; + } + ).serial.getPorts(); + const hasPermission = ports.some((p: SerialPort) => { + const info = + ( + p as SerialPort & { + getInfo?: () => { + usbVendorId?: number; + usbProductId?: number; + }; + } + ).getInfo?.() ?? {}; + return ( + info.usbVendorId === c.usbVendorId && + info.usbProductId === c.usbProductId + ); + }); + updateSavedConnection(c.id, { + status: hasPermission ? "configured" : "disconnected", + }); + } catch { + // getPorts failed + updateSavedConnection(c.id, { status: "disconnected" }); + } + }); + + await Promise.all([...httpChecks, ...btChecks, ...serialChecks]); + }, [connections, updateSavedConnection]); + + const syncConnectionStatuses = useCallback(() => { + // Find which connection corresponds to the currently selected device + const activeConnection = connections.find( + (c) => c.meshDeviceId === selectedDeviceId, + ); + + // Update all connection statuses + connections.forEach((conn) => { + const shouldBeConnected = activeConnection?.id === conn.id; + const isConnectedState = + conn.status === "connected" || + conn.status === "configured" || + conn.status === "configuring"; + + // Update status if it doesn't match reality + if (!shouldBeConnected && isConnectedState) { + updateSavedConnection(conn.id, { status: "disconnected" }); + } + // Don't force status to "connected" if shouldBeConnected - let the connection flow set the proper status + }); + }, [connections, selectedDeviceId, updateSavedConnection]); + + return { + connections, + addConnection, + addConnectionAndConnect, + connect, + disconnect, + removeConnection, + setDefaultConnection, + refreshStatuses, + syncConnectionStatuses, + }; +} diff --git a/packages/web/src/pages/Connections/utils.ts b/packages/web/src/pages/Connections/utils.ts new file mode 100644 index 000000000..d55d9fd2c --- /dev/null +++ b/packages/web/src/pages/Connections/utils.ts @@ -0,0 +1,84 @@ +import type { + Connection, + ConnectionStatus, + ConnectionType, + NewConnection, +} from "@app/core/stores/deviceStore/types"; +import { randId } from "@app/core/utils/randId"; +import { Bluetooth, Cable, Globe, type LucideIcon } from "lucide-react"; + +export function createConnectionFromInput(input: NewConnection): Connection { + const base = { + id: randId(), + name: input.name, + createdAt: Date.now(), + status: "disconnected" as ConnectionStatus, + }; + if (input.type === "http") { + return { + ...base, + type: "http", + url: input.url, + isDefault: false, + name: input.name.length === 0 ? input.url : input.name, + }; + } + if (input.type === "bluetooth") { + return { + ...base, + type: "bluetooth", + deviceId: input.deviceId, + deviceName: input.deviceName, + gattServiceUUID: input.gattServiceUUID, + }; + } + return { + ...base, + type: "serial", + usbVendorId: input.usbVendorId, + usbProductId: input.usbProductId, + }; +} + +export async function testHttpReachable( + url: string, + timeoutMs = 2500, +): Promise { + try { + const controller = new AbortController(); + const timer = setTimeout(() => controller.abort(), timeoutMs); + // Use no-cors to avoid CORS failure; opaque responses resolve but status is 0 + await fetch(url, { + method: "GET", + mode: "no-cors", + cache: "no-store", + signal: controller.signal, + }); + clearTimeout(timer); + return true; + } catch { + return false; + } +} + +export function connectionTypeIcon(type: ConnectionType): LucideIcon { + if (type === "http") { + return Globe; + } + if (type === "bluetooth") { + return Bluetooth; + } + return Cable; +} + +export function formatConnectionSubtext(conn: Connection): string { + if (conn.type === "http") { + return conn.url; + } + if (conn.type === "bluetooth") { + return conn.deviceName || conn.deviceId || "No device selected"; + } + const v = conn.usbVendorId ? conn.usbVendorId.toString(16) : "?"; + const p = conn.usbProductId ? conn.usbProductId.toString(16) : "?"; + return `USB ${v}:${p}`; +} diff --git a/packages/web/src/pages/Dashboard/index.tsx b/packages/web/src/pages/Dashboard/index.tsx deleted file mode 100644 index abf069f72..000000000 --- a/packages/web/src/pages/Dashboard/index.tsx +++ /dev/null @@ -1,90 +0,0 @@ -import LanguageSwitcher from "@components/LanguageSwitcher.tsx"; -import { Button } from "@components/UI/Button.tsx"; -import { Separator } from "@components/UI/Separator.tsx"; -import { Heading } from "@components/UI/Typography/Heading.tsx"; -import { Subtle } from "@components/UI/Typography/Subtle.tsx"; -import { useAppStore, useDeviceStore, useNodeDBStore } from "@core/stores"; -import { ListPlusIcon, PlusIcon, UsersIcon } from "lucide-react"; -import { useMemo } from "react"; -import { useTranslation } from "react-i18next"; - -export const Dashboard = () => { - const { t } = useTranslation("dashboard"); - const { setConnectDialogOpen, setSelectedDevice } = useAppStore(); - const { getDevices } = useDeviceStore(); - const { getNodeDB } = useNodeDBStore(); - - const devices = useMemo(() => getDevices(), [getDevices]); - - return ( -
    -
    -
    - {t("dashboard.title")} - {t("dashboard.description")} -
    - -
    - - - -
    - {devices.length ? ( -
      - {devices.map((device) => { - const nodeDB = getNodeDB(device.id); - if (!nodeDB) { - return undefined; - } - - return ( -
    • - -
    • - ); - })} -
    - ) : ( -
    - - {t("dashboard.noDevicesTitle")} - {t("dashboard.noDevicesDescription")} - -
    - )} -
    -
    - ); -}; diff --git a/packages/web/src/pages/Map/index.tsx b/packages/web/src/pages/Map/index.tsx index 91cf5bbc4..dd3441ebe 100644 --- a/packages/web/src/pages/Map/index.tsx +++ b/packages/web/src/pages/Map/index.tsx @@ -9,6 +9,10 @@ import { useFilterNode, } from "@components/generic/Filter/useFilterNode.ts"; import { BaseMap } from "@components/Map.tsx"; +import { + HeatmapLayer, + type HeatmapMode, +} from "@components/PageComponents/Map/Layers/HeatmapLayer.tsx"; import { NodesLayer } from "@components/PageComponents/Map/Layers/NodesLayer.tsx"; import { PrecisionLayer } from "@components/PageComponents/Map/Layers/PrecisionLayer.tsx"; import { @@ -69,6 +73,7 @@ const MapPage = () => { const [visibilityState, setVisibilityState] = useState( () => defaultVisibilityState, ); + const [heatmapMode, setHeatmapMode] = useState("density"); // Filters const [filterState, setFilterState] = useState( @@ -103,6 +108,25 @@ const MapPage = () => { [filteredNodes, myNode, visibilityState, snrLayerElementId], ); + // Heatmap + const heatmapLayerElementId = useId(); + const heatmapLayerElement = useMemo( + () => ( + + ), + [ + filteredNodes, + visibilityState.heatmap, + heatmapMode, + heatmapLayerElementId, + ], + ); + const onMouseMove = useCallback( (event: MapLayerMouseEvent) => { const { @@ -112,8 +136,29 @@ const MapPage = () => { const hoveredFeature = features?.[0]; if (hoveredFeature) { - const { from, to, snr } = hoveredFeature.properties; + const { from, to, snr, name, shortName, num } = + hoveredFeature.properties; + + // Handle Heatmap Hover + if ( + hoveredFeature.layer.id === `${heatmapLayerElementId}-interaction` && + name !== undefined + ) { + setSnrHover({ + pos: { x, y }, + snr: snr, // Single node SNR + from: + name || + shortName || + t("fallbackName", { + last4: numberToHexUnpadded(num).slice(-4).toUpperCase(), + }), + to: undefined, // Single node + }); + return; + } + // Handle SNR Line Hover const fromLong = getNode(from)?.user?.longName ?? t("fallbackName", { @@ -131,7 +176,7 @@ const MapPage = () => { setSnrHover(undefined); } }, - [getNode, t], + [getNode, t, heatmapLayerElementId], ); // Node markers & clusters @@ -199,8 +244,12 @@ const MapPage = () => { onLoad={getMapBounds} onMouseMove={onMouseMove} onClick={onMapBackgroundClick} - interactiveLayerIds={[snrLayerElementId]} + interactiveLayerIds={[ + snrLayerElementId, + `${heatmapLayerElementId}-interaction`, + ]} > + {heatmapLayerElement} {markerElements} {snrLayerElement} {precisionCirclesElement} @@ -260,6 +309,8 @@ const MapPage = () => {
    diff --git a/packages/web/src/pages/Messages.tsx b/packages/web/src/pages/Messages.tsx index 83186a242..389495aa6 100644 --- a/packages/web/src/pages/Messages.tsx +++ b/packages/web/src/pages/Messages.tsx @@ -19,7 +19,6 @@ import { import { cn } from "@core/utils/cn.ts"; import { randId } from "@core/utils/randId.ts"; import { Protobuf, Types } from "@meshtastic/core"; -import { getChannelName } from "@pages/Config/ChannelConfig.tsx"; import { useNavigate, useParams } from "@tanstack/react-router"; import { HashIcon, LockIcon, LockOpenIcon } from "lucide-react"; import { @@ -30,6 +29,7 @@ import { useState, } from "react"; import { useTranslation } from "react-i18next"; +import { getChannelName } from "../components/PageComponents/Channels/Channels.tsx"; type NodeInfoWithUnread = Protobuf.Mesh.NodeInfo & { unreadCount: number }; @@ -283,7 +283,7 @@ export const MessagesPage = () => { }} > { const { t } = useTranslation("nodes"); - const { currentLanguage } = useLang(); + const { current } = useLang(); const { hardware, connection, setDialogOpen } = useDevice(); const { setNodeNumDetails } = useAppStore(); @@ -152,7 +152,7 @@ const NodesPage = (): JSX.Element => { { content: ( @@ -200,7 +200,7 @@ const NodesPage = (): JSX.Element => { ) : ( )} diff --git a/packages/web/src/pages/Config/DeviceConfig.tsx b/packages/web/src/pages/Settings/DeviceConfig.tsx similarity index 68% rename from packages/web/src/pages/Config/DeviceConfig.tsx rename to packages/web/src/pages/Settings/DeviceConfig.tsx index ead1d4f5b..034864e79 100644 --- a/packages/web/src/pages/Config/DeviceConfig.tsx +++ b/packages/web/src/pages/Settings/DeviceConfig.tsx @@ -1,11 +1,10 @@ -import { Bluetooth } from "@components/PageComponents/Config/Bluetooth.tsx"; -import { Device } from "@components/PageComponents/Config/Device/index.tsx"; -import { Display } from "@components/PageComponents/Config/Display.tsx"; -import { LoRa } from "@components/PageComponents/Config/LoRa.tsx"; -import { Network } from "@components/PageComponents/Config/Network/index.tsx"; -import { Position } from "@components/PageComponents/Config/Position.tsx"; -import { Power } from "@components/PageComponents/Config/Power.tsx"; -import { Security } from "@components/PageComponents/Config/Security/Security.tsx"; +import { Bluetooth } from "@components/PageComponents/Settings/Bluetooth.tsx"; +import { Device } from "@components/PageComponents/Settings/Device/index.tsx"; +import { Display } from "@components/PageComponents/Settings/Display.tsx"; +import { Network } from "@components/PageComponents/Settings/Network/index.tsx"; +import { Position } from "@components/PageComponents/Settings/Position.tsx"; +import { Power } from "@components/PageComponents/Settings/Power.tsx"; +import { User } from "@components/PageComponents/Settings/User.tsx"; import { Spinner } from "@components/UI/Spinner.tsx"; import { Tabs, @@ -23,21 +22,25 @@ interface ConfigProps { } type TabItem = { - case: ValidConfigType; + case: ValidConfigType | "user"; label: string; element: ComponentType; count?: number; }; export const DeviceConfig = ({ onFormInit }: ConfigProps) => { - const { getWorkingConfig } = useDevice(); - const { t } = useTranslation("deviceConfig"); + const { hasConfigChange, hasUserChange } = useDevice(); + const { t } = useTranslation("config"); const tabs: TabItem[] = [ + { + case: "user", + label: t("page.tabUser"), + element: User, + }, { case: "device", label: t("page.tabDevice"), element: Device, - count: 0, }, { case: "position", @@ -59,30 +62,28 @@ export const DeviceConfig = ({ onFormInit }: ConfigProps) => { label: t("page.tabDisplay"), element: Display, }, - { - case: "lora", - label: t("page.tabLora"), - element: LoRa, - }, { case: "bluetooth", label: t("page.tabBluetooth"), element: Bluetooth, }, - { - case: "security", - label: t("page.tabSecurity"), - element: Security, - }, ] as const; const flags = useMemo( - () => new Map(tabs.map((tab) => [tab.case, getWorkingConfig(tab.case)])), - [tabs, getWorkingConfig], + () => + new Map( + tabs.map((tab) => [ + tab.case, + tab.case === "user" + ? hasUserChange() + : hasConfigChange(tab.case as ValidConfigType), + ]), + ), + [tabs, hasConfigChange, hasUserChange], ); return ( - + {tabs.map((tab) => ( { - const { getWorkingModuleConfig } = useDevice(); + const { hasModuleConfigChange } = useDevice(); const { t } = useTranslation("moduleConfig"); const tabs: TabItem[] = [ { @@ -97,8 +97,8 @@ export const ModuleConfig = ({ onFormInit }: ConfigProps) => { const flags = useMemo( () => - new Map(tabs.map((tab) => [tab.case, getWorkingModuleConfig(tab.case)])), - [tabs, getWorkingModuleConfig], + new Map(tabs.map((tab) => [tab.case, hasModuleConfigChange(tab.case)])), + [tabs, hasModuleConfigChange], ); return ( diff --git a/packages/web/src/pages/Settings/RadioConfig.tsx b/packages/web/src/pages/Settings/RadioConfig.tsx new file mode 100644 index 000000000..ddcc52c0f --- /dev/null +++ b/packages/web/src/pages/Settings/RadioConfig.tsx @@ -0,0 +1,81 @@ +import { Channels } from "@app/components/PageComponents/Channels/Channels"; +import { LoRa } from "@components/PageComponents/Settings/LoRa.tsx"; +import { Security } from "@components/PageComponents/Settings/Security/Security.tsx"; +import { Spinner } from "@components/UI/Spinner.tsx"; +import { + Tabs, + TabsContent, + TabsList, + TabsTrigger, +} from "@components/UI/Tabs.tsx"; +import { useDevice, type ValidConfigType } from "@core/stores"; +import { type ComponentType, Suspense, useMemo } from "react"; +import type { UseFormReturn } from "react-hook-form"; +import { useTranslation } from "react-i18next"; + +interface ConfigProps { + onFormInit: (methods: UseFormReturn) => void; +} + +type TabItem = { + case: ValidConfigType; + label: string; + element: ComponentType; + count?: number; +}; + +export const RadioConfig = ({ onFormInit }: ConfigProps) => { + const { hasConfigChange } = useDevice(); + const { t } = useTranslation("config"); + const tabs: TabItem[] = [ + { + case: "lora", + label: t("page.tabLora"), + element: LoRa, + }, + { + case: "channels", + label: t("page.tabChannels"), + element: Channels, + }, + { + case: "security", + label: t("page.tabSecurity"), + element: Security, + }, + ] as const; + + const flags = useMemo( + () => new Map(tabs.map((tab) => [tab.case, hasConfigChange(tab.case)])), + [tabs, hasConfigChange], + ); + + return ( + + + {tabs.map((tab) => ( + + {tab.label} + {flags.get(tab.case) && ( + + + + + )} + + ))} + + {tabs.map((tab) => ( + + }> + + + + ))} + + ); +}; diff --git a/packages/web/src/pages/Config/index.tsx b/packages/web/src/pages/Settings/index.tsx similarity index 60% rename from packages/web/src/pages/Config/index.tsx rename to packages/web/src/pages/Settings/index.tsx index 7c0531de1..13b1175db 100644 --- a/packages/web/src/pages/Config/index.tsx +++ b/packages/web/src/pages/Settings/index.tsx @@ -1,3 +1,5 @@ +import { deviceRoute, moduleRoute, radioRoute } from "@app/routes"; +import { toBinary } from "@bufbuild/protobuf"; import { PageLayout } from "@components/PageLayout.tsx"; import { Sidebar } from "@components/Sidebar.tsx"; import { SidebarButton } from "@components/UI/Sidebar/SidebarButton.tsx"; @@ -5,44 +7,88 @@ import { SidebarSection } from "@components/UI/Sidebar/SidebarSection.tsx"; import { useToast } from "@core/hooks/useToast.ts"; import { useDevice } from "@core/stores"; import { cn } from "@core/utils/cn.ts"; -import { ChannelConfig } from "@pages/Config/ChannelConfig.tsx"; -import { DeviceConfig } from "@pages/Config/DeviceConfig.tsx"; -import { ModuleConfig } from "@pages/Config/ModuleConfig.tsx"; +import { Protobuf } from "@meshtastic/core"; +import { DeviceConfig } from "@pages/Settings/DeviceConfig.tsx"; +import { ModuleConfig } from "@pages/Settings/ModuleConfig.tsx"; +import { useNavigate, useRouterState } from "@tanstack/react-router"; import { - BoxesIcon, LayersIcon, + RadioTowerIcon, RefreshCwIcon, + RouterIcon, SaveIcon, SaveOff, - SettingsIcon, } from "lucide-react"; import { useCallback, useEffect, useMemo, useRef, useState } from "react"; import type { FieldValues, UseFormReturn } from "react-hook-form"; import { useTranslation } from "react-i18next"; +import { RadioConfig } from "./RadioConfig.tsx"; const ConfigPage = () => { const { - workingConfig, - workingModuleConfig, - workingChannelConfig, + getAllConfigChanges, + getAllModuleConfigChanges, + getAllChannelChanges, + getAllQueuedAdminMessages, connection, - removeWorkingConfig, - removeWorkingModuleConfig, - removeWorkingChannelConfig, + clearAllChanges, setConfig, setModuleConfig, addChannel, + getConfigChangeCount, + getModuleConfigChangeCount, + getChannelChangeCount, + getAdminMessageChangeCount, } = useDevice(); - const [activeConfigSection, setActiveConfigSection] = useState< - "device" | "module" | "channel" - >("device"); const [isSaving, setIsSaving] = useState(false); const [rhfState, setRhfState] = useState({ isDirty: false, isValid: true }); const unsubRef = useRef<(() => void) | null>(null); const [formMethods, setFormMethods] = useState(null); const { toast } = useToast(); - const { t } = useTranslation("deviceConfig"); + const navigate = useNavigate(); + const routerState = useRouterState(); + const { t } = useTranslation("config"); + + const configChangeCount = getConfigChangeCount(); + const moduleConfigChangeCount = getModuleConfigChangeCount(); + const channelChangeCount = getChannelChangeCount(); + const adminMessageChangeCount = getAdminMessageChangeCount(); + + const sections = useMemo( + () => [ + { + key: "radio", + route: radioRoute, + label: t("navigation.radioConfig"), + icon: RadioTowerIcon, + changeCount: configChangeCount, + component: RadioConfig, + }, + { + key: "device", + route: deviceRoute, + label: t("navigation.deviceConfig"), + icon: RouterIcon, + changeCount: moduleConfigChangeCount, + component: DeviceConfig, + }, + { + key: "module", + route: moduleRoute, + label: t("navigation.moduleConfig"), + icon: LayersIcon, + changeCount: channelChangeCount, + component: ModuleConfig, + }, + ], + [t, configChangeCount, moduleConfigChangeCount, channelChangeCount], + ); + + const activeSection = + sections.find((section) => + routerState.location.pathname.includes(`/settings/${section.key}`), + ) ?? sections[0]; const onFormInit = useCallback( (methods: UseFormReturn) => { @@ -69,7 +115,6 @@ const ConfigPage = () => { [], ); - // Cleanup subscription on unmount useEffect(() => { return () => unsubRef.current?.(); }, []); @@ -78,9 +123,13 @@ const ConfigPage = () => { setIsSaving(true); try { - // Save all working channel configs first, doesn't require a commit/reboot + const channelChanges = getAllChannelChanges(); + const configChanges = getAllConfigChanges(); + const moduleConfigChanges = getAllModuleConfigChanges(); + const adminMessages = getAllQueuedAdminMessages(); + await Promise.all( - workingChannelConfig.map((channel) => + channelChanges.map((channel) => connection?.setChannel(channel).then(() => { toast({ title: t("toast.savedChannel.title", { @@ -93,7 +142,7 @@ const ConfigPage = () => { ); await Promise.all( - workingConfig.map((newConfig) => + configChanges.map((newConfig) => connection?.setConfig(newConfig).then(() => { toast({ title: t("toast.saveSuccess.title"), @@ -106,7 +155,7 @@ const ConfigPage = () => { ); await Promise.all( - workingModuleConfig.map((newModuleConfig) => + moduleConfigChanges.map((newModuleConfig) => connection?.setModuleConfig(newModuleConfig).then(() => toast({ title: t("toast.saveSuccess.title"), @@ -118,23 +167,34 @@ const ConfigPage = () => { ), ); - if (workingConfig.length > 0 || workingModuleConfig.length > 0) { + if (configChanges.length > 0 || moduleConfigChanges.length > 0) { await connection?.commitEditSettings(); } - workingChannelConfig.forEach((newChannel) => { + // Send queued admin messages after configs are committed + if (adminMessages.length > 0) { + await Promise.all( + adminMessages.map((message) => + connection?.sendPacket( + toBinary(Protobuf.Admin.AdminMessageSchema, message), + Protobuf.Portnums.PortNum.ADMIN_APP, + "self", + ), + ), + ); + } + + channelChanges.forEach((newChannel) => { addChannel(newChannel); }); - workingConfig.forEach((newConfig) => { + configChanges.forEach((newConfig) => { setConfig(newConfig); }); - workingModuleConfig.forEach((newModuleConfig) => { + moduleConfigChanges.forEach((newModuleConfig) => { setModuleConfig(newModuleConfig); }); - removeWorkingChannelConfig(); - removeWorkingConfig(); - removeWorkingModuleConfig(); + clearAllChanges(); if (formMethods) { formMethods.reset(formMethods.getValues(), { @@ -144,7 +204,6 @@ const ConfigPage = () => { keepValues: true, }); - // Force RHF to re-validate and emit state formMethods.trigger(); } } catch (_error) { @@ -162,77 +221,51 @@ const ConfigPage = () => { }, [ toast, t, - workingConfig, + getAllConfigChanges, connection, - workingModuleConfig, - workingChannelConfig, + getAllModuleConfigChanges, + getAllChannelChanges, + getAllQueuedAdminMessages, formMethods, addChannel, setConfig, setModuleConfig, - removeWorkingConfig, - removeWorkingModuleConfig, - removeWorkingChannelConfig, + clearAllChanges, ]); const handleReset = useCallback(() => { if (formMethods) { formMethods.reset(); } - removeWorkingChannelConfig(); - removeWorkingConfig(); - removeWorkingModuleConfig(); - }, [ - formMethods, - removeWorkingConfig, - removeWorkingModuleConfig, - removeWorkingChannelConfig, - ]); + clearAllChanges(); + }, [formMethods, clearAllChanges]); const leftSidebar = useMemo( () => ( - setActiveConfigSection("device")} - Icon={SettingsIcon} - isDirty={workingConfig.length > 0} - count={workingConfig.length} - /> - setActiveConfigSection("module")} - Icon={BoxesIcon} - isDirty={workingModuleConfig.length > 0} - count={workingModuleConfig.length} - /> - setActiveConfigSection("channel")} - Icon={LayersIcon} - isDirty={workingChannelConfig.length > 0} - count={workingChannelConfig.length} - /> + {sections.map((section) => ( + navigate({ to: section.route.to })} + Icon={section.icon} + isDirty={section.changeCount > 0} + count={section.changeCount} + /> + ))} ), - [ - activeConfigSection, - workingConfig, - workingModuleConfig, - workingChannelConfig, - t, - ], + [sections, activeSection?.key, navigate, t], ); const hasDrafts = - workingConfig.length > 0 || - workingModuleConfig.length > 0 || - workingChannelConfig.length > 0; + getConfigChangeCount() > 0 || + getModuleConfigChangeCount() > 0 || + getChannelChangeCount() > 0 || + adminMessageChangeCount > 0; const hasPending = hasDrafts || rhfState.isDirty; const buttonOpacity = hasPending ? "opacity-100" : "opacity-0"; const saveDisabled = isSaving || !rhfState.isValid || !hasPending; @@ -291,26 +324,16 @@ const ConfigPage = () => { ], ); + const ActiveComponent = activeSection?.component; + return ( - {activeConfigSection === "device" ? ( - - ) : activeConfigSection === "module" ? ( - - ) : ( - - )} + {ActiveComponent && } ); }; diff --git a/packages/web/src/routes.tsx b/packages/web/src/routes.tsx index 07125f820..e32a47d6b 100644 --- a/packages/web/src/routes.tsx +++ b/packages/web/src/routes.tsx @@ -1,10 +1,10 @@ import { DialogManager } from "@components/Dialog/DialogManager.tsx"; import type { useAppStore, useMessageStore } from "@core/stores"; -import ConfigPage from "@pages/Config/index.tsx"; -import { Dashboard } from "@pages/Dashboard/index.tsx"; +import { Connections } from "@pages/Connections/index.tsx"; import MapPage from "@pages/Map/index.tsx"; import MessagesPage from "@pages/Messages.tsx"; import NodesPage from "@pages/Nodes/index.tsx"; +import ConfigPage from "@pages/Settings/index.tsx"; import { createRootRouteWithContext, createRoute, @@ -30,7 +30,7 @@ export const rootRoute = createRootRouteWithContext()({ const indexRoute = createRoute({ getParentRoute: () => rootRoute, path: "/", - component: Dashboard, + component: Connections, loader: () => { // Redirect to the broadcast messages page on initial load return redirect({ to: "/messages/broadcast/0", replace: true }); @@ -109,9 +109,33 @@ export const mapWithParamsRoute = createRoute({ // }), }); -const configRoute = createRoute({ +export const settingsRoute = createRoute({ getParentRoute: () => rootRoute, - path: "/config", + path: "/settings", + component: ConfigPage, + // beforeLoad: () => { + // throw redirect({ + // to: "/settings/radio", + // replace: true, + // }); + // }, +}); + +export const radioRoute = createRoute({ + getParentRoute: () => settingsRoute, + path: "radio", + component: ConfigPage, +}); + +export const deviceRoute = createRoute({ + getParentRoute: () => settingsRoute, + path: "device", + component: ConfigPage, +}); + +export const moduleRoute = createRoute({ + getParentRoute: () => settingsRoute, + path: "module", component: ConfigPage, }); @@ -127,15 +151,22 @@ const dialogWithParamsRoute = createRoute({ component: DialogManager, }); +const connectionsRoute = createRoute({ + getParentRoute: () => rootRoute, + path: "/connections", + component: Connections, +}); + const routeTree = rootRoute.addChildren([ indexRoute, messagesRoute, messagesWithParamsRoute, mapRoute, mapWithParamsRoute, - configRoute, + settingsRoute.addChildren([radioRoute, deviceRoute, moduleRoute]), nodesRoute, dialogWithParamsRoute, + connectionsRoute, ]); const router = createRouter({ diff --git a/packages/web/src/tests/setup.ts b/packages/web/src/tests/setup.ts index 1b36f7d8a..9763e8c65 100644 --- a/packages/web/src/tests/setup.ts +++ b/packages/web/src/tests/setup.ts @@ -12,10 +12,10 @@ import commandPaletteEN from "@public/i18n/locales/en/commandPalette.json" with import commonEN from "@public/i18n/locales/en/common.json" with { type: "json", }; -import dashboardEN from "@public/i18n/locales/en/dashboard.json" with { +import configEN from "@public/i18n/locales/en/config.json" with { type: "json", }; -import deviceConfigEN from "@public/i18n/locales/en/deviceConfig.json" with { +import connectionsEN from "@public/i18n/locales/en/connections.json" with { type: "json", }; import dialogEN from "@public/i18n/locales/en/dialog.json" with { @@ -53,9 +53,9 @@ const appNamespaces = [ "channels", "commandPalette", "common", - "deviceConfig", + "config", "moduleConfig", - "dashboard", + "connections", "dialog", "messages", "nodes", @@ -76,9 +76,9 @@ i18n.use(initReactI18next).init({ channels: channelsEN, commandPalette: commandPaletteEN, common: commonEN, - deviceConfig: deviceConfigEN, + config: configEN, moduleConfig: moduleConfigEN, - dashboard: dashboardEN, + connections: connectionsEN, dialog: dialogEN, messages: messagesEN, nodes: nodesEN, diff --git a/packages/web/src/validation/config/position.ts b/packages/web/src/validation/config/position.ts index c7506b64a..b901a667c 100644 --- a/packages/web/src/validation/config/position.ts +++ b/packages/web/src/validation/config/position.ts @@ -15,6 +15,9 @@ export const PositionValidationSchema = z.object({ broadcastSmartMinimumIntervalSecs: z.coerce.number().int().min(0), gpsEnGpio: z.coerce.number().int().min(0), gpsMode: GpsModeEnum, + latitude: z.coerce.number().min(-90).max(90).optional(), + longitude: z.coerce.number().min(-180).max(180).optional(), + altitude: z.coerce.number().optional(), }); export type PositionValidation = z.infer; diff --git a/packages/web/src/validation/config/user.ts b/packages/web/src/validation/config/user.ts new file mode 100644 index 000000000..59fac8602 --- /dev/null +++ b/packages/web/src/validation/config/user.ts @@ -0,0 +1,17 @@ +import { t } from "i18next"; +import { z } from "zod/v4"; + +export const UserValidationSchema = z.object({ + longName: z + .string() + .min(1, t("user.longName.validation.min")) + .max(40, t("user.longName.validation.max")), + shortName: z + .string() + .min(2, t("user.shortName.validation.min")) + .max(4, t("user.shortName.validation.max")), + isUnmessageable: z.boolean().default(false), + isLicensed: z.boolean().default(false), +}); + +export type UserValidation = z.infer; diff --git a/packages/web/vite.config.ts b/packages/web/vite.config.ts index 707686721..6b0488d9b 100644 --- a/packages/web/vite.config.ts +++ b/packages/web/vite.config.ts @@ -2,6 +2,7 @@ import { execSync } from "node:child_process"; import path from "node:path"; import process from "node:process"; import tailwindcss from "@tailwindcss/vite"; +import basicSsl from "@vitejs/plugin-basic-ssl"; import react from "@vitejs/plugin-react"; import { defineConfig, loadEnv } from "vite"; import { createHtmlPlugin } from "vite-plugin-html"; @@ -32,19 +33,21 @@ export default defineConfig(({ mode }) => { const isProd = mode === "production"; const isTest = env.VITE_IS_TEST; + const useHTTPS = env.VITE_USE_HTTPS === "true"; return { plugins: [ react(), tailwindcss(), - // This is for GDPR/CCPA compliance + ...(useHTTPS ? [basicSsl()] : []), createHtmlPlugin({ inject: { data: { title: isTest ? "Meshtastic Web (TEST)" : "Meshtastic Web", cookieYesScript: isProd && env.VITE_COOKIEYES_CLIENT_ID - ? `` + ? // This is for GDPR/CCPA compliance + `` : "", }, }, @@ -76,7 +79,7 @@ export default defineConfig(({ mode }) => { server: { port: 3000, headers: { - "content-security-policy": CONTENT_SECURITY_POLICY, + "Content-Security-Policy": CONTENT_SECURITY_POLICY, "Cross-Origin-Opener-Policy": "same-origin", "Cross-Origin-Embedder-Policy": "credentialless", "X-Content-Type-Options": "nosniff", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 8f92ec3f3..479805822 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -29,13 +29,13 @@ importers: version: 24.3.1 tsdown: specifier: ^0.15.0 - version: 0.15.0(typescript@5.9.2) + version: 0.15.0(publint@0.3.15)(typescript@5.9.2) typescript: specifier: ^5.9.2 version: 5.9.2 vitest: specifier: ^3.2.4 - version: 3.2.4(@types/node@24.3.1)(happy-dom@20.0.0)(jiti@2.6.1)(lightningcss@1.30.1)(terser@5.44.0)(tsx@4.20.3) + version: 3.2.4(@types/node@24.3.1)(happy-dom@20.0.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.3) packages/core: dependencies: @@ -97,6 +97,88 @@ importers: specifier: npm:@types/w3c-web-serial@^1.0.7 version: 1.0.8 + packages/ui: + dependencies: + '@radix-ui/react-collapsible': + specifier: ^1.1.12 + version: 1.1.12(@types/react-dom@18.3.7(@types/react@18.3.26))(@types/react@18.3.26)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-dialog': + specifier: ^1.1.15 + version: 1.1.15(@types/react-dom@18.3.7(@types/react@18.3.26))(@types/react@18.3.26)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-dropdown-menu': + specifier: ^2.1.16 + version: 2.1.16(@types/react-dom@18.3.7(@types/react@18.3.26))(@types/react@18.3.26)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-separator': + specifier: ^1.1.7 + version: 1.1.7(@types/react-dom@18.3.7(@types/react@18.3.26))(@types/react@18.3.26)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-slot': + specifier: ^1.2.3 + version: 1.2.3(@types/react@18.3.26)(react@19.2.0) + '@radix-ui/react-tooltip': + specifier: ^1.2.8 + version: 1.2.8(@types/react-dom@18.3.7(@types/react@18.3.26))(@types/react@18.3.26)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@tanstack/react-router': + specifier: ^1.132.47 + version: 1.132.47(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + class-variance-authority: + specifier: ^0.7.1 + version: 0.7.1 + clsx: + specifier: ^2.1.1 + version: 2.1.1 + lucide-react: + specifier: ^0.545.0 + version: 0.545.0(react@19.2.0) + react: + specifier: '>=19' + version: 19.2.0 + react-dom: + specifier: '>=19' + version: 19.2.0(react@19.2.0) + tailwind-merge: + specifier: ^2.6.0 + version: 2.6.0 + devDependencies: + '@tailwindcss/postcss': + specifier: ^4.1.7 + version: 4.1.15 + '@tailwindcss/vite': + specifier: ^4.1.14 + version: 4.1.14(vite@7.1.11(@types/node@24.7.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.3)) + '@types/react': + specifier: ^18.3.5 + version: 18.3.26 + '@types/react-dom': + specifier: ^18.3.0 + version: 18.3.7(@types/react@18.3.26) + '@vitejs/plugin-react': + specifier: ^4.3.4 + version: 4.7.0(vite@7.1.11(@types/node@24.7.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.3)) + publint: + specifier: ^0.3.14 + version: 0.3.15 + tailwindcss: + specifier: ^4.1.14 + version: 4.1.15 + tw-animate-css: + specifier: ^1.4.0 + version: 1.4.0 + typescript: + specifier: ^5.6.3 + version: 5.9.3 + vite: + specifier: ^7.0.0 + version: 7.1.11(@types/node@24.7.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.3) + vite-plugin-dts: + specifier: ^4.5.4 + version: 4.5.4(@types/node@24.7.0)(rollup@4.52.5)(typescript@5.9.3)(vite@7.1.11(@types/node@24.7.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.3)) + vite-plugin-static-copy: + specifier: ^3.1.4 + version: 3.1.4(vite@7.1.11(@types/node@24.7.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.3)) + vitest: + specifier: ^3.0.0 + version: 3.2.4(@types/node@24.7.0)(happy-dom@20.0.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.3) + packages/web: dependencies: '@hookform/resolvers': @@ -120,6 +202,9 @@ importers: '@radix-ui/react-accordion': specifier: ^1.2.12 version: 1.2.12(@types/react-dom@19.2.0(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-alert-dialog': + specifier: ^1.1.15 + version: 1.1.15(@types/react-dom@19.2.0(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@radix-ui/react-checkbox': specifier: ^1.3.3 version: 1.3.3(@types/react-dom@19.2.0(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) @@ -170,19 +255,19 @@ importers: version: 1.2.3(@types/react-dom@19.2.0(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@tailwindcss/vite': specifier: ^4.1.14 - version: 4.1.14(vite@7.1.9(@types/node@24.7.0)(jiti@2.6.1)(lightningcss@1.30.1)(terser@5.44.0)(tsx@4.20.3)) + version: 4.1.14(vite@7.1.11(@types/node@24.7.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.3)) '@tanstack/react-router': specifier: ^1.132.47 version: 1.132.47(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@tanstack/react-router-devtools': specifier: ^1.132.47 - version: 1.132.47(@tanstack/react-router@1.132.47(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@tanstack/router-core@1.132.47)(@types/node@24.7.0)(csstype@3.1.3)(jiti@2.6.1)(lightningcss@1.30.1)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(terser@5.44.0)(tiny-invariant@1.3.3)(tsx@4.20.3) + version: 1.132.47(@tanstack/react-router@1.132.47(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@tanstack/router-core@1.132.47)(@types/node@24.7.0)(csstype@3.1.3)(jiti@2.6.1)(lightningcss@1.30.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(terser@5.44.1)(tiny-invariant@1.3.3)(tsx@4.20.3) '@tanstack/router-cli': specifier: ^1.132.47 version: 1.132.47 '@tanstack/router-devtools': specifier: ^1.132.47 - version: 1.132.47(@tanstack/react-router@1.132.47(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@tanstack/router-core@1.132.47)(@types/node@24.7.0)(csstype@3.1.3)(jiti@2.6.1)(lightningcss@1.30.1)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(terser@5.44.0)(tiny-invariant@1.3.3)(tsx@4.20.3) + version: 1.132.47(@tanstack/react-router@1.132.47(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@tanstack/router-core@1.132.47)(@types/node@24.7.0)(csstype@3.1.3)(jiti@2.6.1)(lightningcss@1.30.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(terser@5.44.1)(tiny-invariant@1.3.3)(tsx@4.20.3) '@turf/turf': specifier: ^7.2.0 version: 7.2.0 @@ -256,14 +341,14 @@ importers: specifier: ^1.5.4 version: 1.5.4 vite: - specifier: ^7.1.9 - version: 7.1.9(@types/node@24.7.0)(jiti@2.6.1)(lightningcss@1.30.1)(terser@5.44.0)(tsx@4.20.3) + specifier: ^7.1.11 + version: 7.1.11(@types/node@24.7.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.3) vite-plugin-html: specifier: ^3.2.2 - version: 3.2.2(vite@7.1.9(@types/node@24.7.0)(jiti@2.6.1)(lightningcss@1.30.1)(terser@5.44.0)(tsx@4.20.3)) + version: 3.2.2(vite@7.1.11(@types/node@24.7.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.3)) vite-plugin-pwa: specifier: ^1.0.3 - version: 1.0.3(vite@7.1.9(@types/node@24.7.0)(jiti@2.6.1)(lightningcss@1.30.1)(terser@5.44.0)(tsx@4.20.3))(workbox-build@7.3.0(@types/babel__core@7.20.5))(workbox-window@7.3.0) + version: 1.0.3(vite@7.1.11(@types/node@24.7.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.3))(workbox-build@7.3.0(@types/babel__core@7.20.5))(workbox-window@7.3.0) zod: specifier: ^4.1.12 version: 4.1.12 @@ -273,7 +358,7 @@ importers: devDependencies: '@tanstack/router-plugin': specifier: ^1.132.47 - version: 1.132.47(@tanstack/react-router@1.132.47(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(vite@7.1.9(@types/node@24.7.0)(jiti@2.6.1)(lightningcss@1.30.1)(terser@5.44.0)(tsx@4.20.3)) + version: 1.132.47(@tanstack/react-router@1.132.47(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(vite@7.1.11(@types/node@24.7.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.3)) '@testing-library/jest-dom': specifier: ^6.9.1 version: 6.9.1 @@ -304,9 +389,12 @@ importers: '@types/w3c-web-serial': specifier: ^1.0.8 version: 1.0.8 + '@vitejs/plugin-basic-ssl': + specifier: ^2.1.0 + version: 2.1.0(vite@7.1.11(@types/node@24.7.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.3)) '@vitejs/plugin-react': specifier: ^5.0.4 - version: 5.0.4(vite@7.1.9(@types/node@24.7.0)(jiti@2.6.1)(lightningcss@1.30.1)(terser@5.44.0)(tsx@4.20.3)) + version: 5.0.4(vite@7.1.11(@types/node@24.7.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.3)) autoprefixer: specifier: ^10.4.21 version: 10.4.21(postcss@8.5.6) @@ -314,8 +402,8 @@ importers: specifier: ^8.2.1 version: 8.2.1 happy-dom: - specifier: ^20.0.0 - version: 20.0.0 + specifier: ^20.0.2 + version: 20.0.2 simple-git-hooks: specifier: ^2.13.1 version: 2.13.1 @@ -339,13 +427,17 @@ importers: version: 5.9.3 vitest: specifier: ^3.2.4 - version: 3.2.4(@types/node@24.7.0)(happy-dom@20.0.0)(jiti@2.6.1)(lightningcss@1.30.1)(terser@5.44.0)(tsx@4.20.3) + version: 3.2.4(@types/node@24.7.0)(happy-dom@20.0.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.3) packages: '@adobe/css-tools@4.4.3': resolution: {integrity: sha512-VQKMkwriZbaOgVCby1UDY/LDk5fIjhQicCvVPFqfe+69fWaPWydbWJ3wRt59/YzIwda1I81loas3oCoHxnqvdA==} + '@alloc/quick-lru@5.2.0': + resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==} + engines: {node: '>=10'} + '@ampproject/remapping@2.3.0': resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==} engines: {node: '>=6.0.0'} @@ -376,6 +468,10 @@ packages: resolution: {integrity: sha512-YsmSKC29MJwf0gF8Rjjrg5LQCmyh+j/nD8/eP7f+BeoQTKYqs9RoWbjGOdy0+1Ekr68RJZMUOPVQaQisnIo4Rw==} engines: {node: '>=6.9.0'} + '@babel/compat-data@7.28.5': + resolution: {integrity: sha512-6uFXyCayocRbqhZOB+6XcuZbkMNimwfVGFji8CTZnCzOHVGvDqzvitu1re2AU5LROliz7eQPhB8CpAMvnx9EjA==} + engines: {node: '>=6.9.0'} + '@babel/core@7.28.0': resolution: {integrity: sha512-UlLAnTPrFdNGoFtbSXwcGFQBtQZJCNjaN6hQNP3UPvuNXT1i82N26KL3dZeIpNalWywr9IuQuncaAfUaS1g6sQ==} engines: {node: '>=6.9.0'} @@ -388,6 +484,10 @@ packages: resolution: {integrity: sha512-3lSpxGgvnmZznmBkCRnVREPUFJv2wrv9iAoFDvADJc0ypmdOxdUtcLeBgBJ6zE0PMeTKnxeQzyk0xTBq4Ep7zw==} engines: {node: '>=6.9.0'} + '@babel/generator@7.28.5': + resolution: {integrity: sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ==} + engines: {node: '>=6.9.0'} + '@babel/helper-annotate-as-pure@7.27.3': resolution: {integrity: sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg==} engines: {node: '>=6.9.0'} @@ -402,8 +502,14 @@ packages: peerDependencies: '@babel/core': ^7.0.0 - '@babel/helper-create-regexp-features-plugin@7.27.1': - resolution: {integrity: sha512-uVDC72XVf8UbrH5qQTc18Agb8emwjTiZrQE11Nv3CuBEZmVvTwwE9CBUEvHku06gQCAyYf8Nv6ja1IN+6LMbxQ==} + '@babel/helper-create-class-features-plugin@7.28.5': + resolution: {integrity: sha512-q3WC4JfdODypvxArsJQROfupPBq9+lMwjKq7C33GhbFYJsufD0yd/ziwD+hJucLeWsnFPWZjsU2DNFqBPE7jwQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/helper-create-regexp-features-plugin@7.28.5': + resolution: {integrity: sha512-N1EhvLtHzOvj7QQOUCCS3NrPJP8c5W6ZXCHDn7Yialuy1iu4r5EmIYkXlKNqT99Ciw+W0mDqWoR6HWMZlFP3hw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 @@ -421,6 +527,10 @@ packages: resolution: {integrity: sha512-E5chM8eWjTp/aNoVpcbfM7mLxu9XGLWYise2eBKGQomAk/Mb4XoxyqXTZbuTohbsl8EKqdlMhnDI2CCLfcs9wA==} engines: {node: '>=6.9.0'} + '@babel/helper-member-expression-to-functions@7.28.5': + resolution: {integrity: sha512-cwM7SBRZcPCLgl8a7cY0soT1SptSzAlMH39vwiRpOQkJlh53r5hdHwLSCZpQdVLT39sZt+CRpNwYG4Y2v77atg==} + engines: {node: '>=6.9.0'} + '@babel/helper-module-imports@7.27.1': resolution: {integrity: sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==} engines: {node: '>=6.9.0'} @@ -463,6 +573,10 @@ packages: resolution: {integrity: sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==} engines: {node: '>=6.9.0'} + '@babel/helper-validator-identifier@7.28.5': + resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==} + engines: {node: '>=6.9.0'} + '@babel/helper-validator-option@7.27.1': resolution: {integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==} engines: {node: '>=6.9.0'} @@ -484,8 +598,13 @@ packages: engines: {node: '>=6.0.0'} hasBin: true - '@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.27.1': - resolution: {integrity: sha512-QPG3C9cCVRQLxAVwmefEmwdTanECuUBMQZ/ym5kiw3XKCGA7qkuQLcjWWHcrD/GKbn/WmJwaezfuuAOcyKlRPA==} + '@babel/parser@7.28.5': + resolution: {integrity: sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==} + engines: {node: '>=6.0.0'} + hasBin: true + + '@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.28.5': + resolution: {integrity: sha512-87GDMS3tsmMSi/3bWOte1UblL+YUTFMV8SZPZ2eSEL17s74Cw/l63rR6NmGVKMYW2GYi85nE+/d6Hw5N0bEk2Q==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 @@ -574,8 +693,8 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-block-scoping@7.28.4': - resolution: {integrity: sha512-1yxmvN0MJHOhPVmAsmoW5liWwoILobu/d/ShymZmj867bAdxGbehIrew1DuLpw2Ukv+qDSSPQdYW1dLNE7t11A==} + '@babel/plugin-transform-block-scoping@7.28.5': + resolution: {integrity: sha512-45DmULpySVvmq9Pj3X9B+62Xe+DJGov27QravQJU1LLcapR6/10i+gYVAucGGJpHBp5mYxIMK4nDAT/QDLr47g==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 @@ -604,8 +723,8 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-destructuring@7.28.0': - resolution: {integrity: sha512-v1nrSMBiKcodhsyJ4Gf+Z0U/yawmJDBOTpEB3mcQY52r9RIyPneGyAS/yM6seP/8I+mWI3elOMtT5dB8GJVs+A==} + '@babel/plugin-transform-destructuring@7.28.5': + resolution: {integrity: sha512-Kl9Bc6D0zTUcFUvkNuQh4eGXPKKNDOJQXVyyM4ZAQPMveniJdxi8XMJwLo+xSoW3MIq81bD33lcUe9kZpl0MCw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 @@ -640,8 +759,8 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-exponentiation-operator@7.27.1': - resolution: {integrity: sha512-uspvXnhHvGKf2r4VVtBpeFnuDWsJLQ6MF6lGJLC89jBR1uoVeqM416AZtTuhTezOfgHicpJQmoD5YUakO/YmXQ==} + '@babel/plugin-transform-exponentiation-operator@7.28.5': + resolution: {integrity: sha512-D4WIMaFtwa2NizOp+dnoFjRez/ClKiC2BqqImwKd1X28nqBtZEyCYJ2ozQrrzlxAFrcrjxo39S6khe9RNDlGzw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 @@ -676,8 +795,8 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-logical-assignment-operators@7.27.1': - resolution: {integrity: sha512-SJvDs5dXxiae4FbSL1aBJlG4wvl594N6YEVVn9e3JGulwioy6z3oPjx/sQBO3Y4NwUu5HNix6KJ3wBZoewcdbw==} + '@babel/plugin-transform-logical-assignment-operators@7.28.5': + resolution: {integrity: sha512-axUuqnUTBuXyHGcJEVVh9pORaN6wC5bYfE7FGzPiaWa3syib9m7g+/IT/4VgCOe2Upef43PHzeAvcrVek6QuuA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 @@ -700,8 +819,8 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-modules-systemjs@7.27.1': - resolution: {integrity: sha512-w5N1XzsRbc0PQStASMksmUeqECuzKuTJer7kFagK8AXgpCMkeDMO5S+aaFb7A51ZYDF7XI34qsTX+fkHiIm5yA==} + '@babel/plugin-transform-modules-systemjs@7.28.5': + resolution: {integrity: sha512-vn5Jma98LCOeBy/KpeQhXcV2WZgaRUtjwQmjoBuLNlOmkg0fB5pdvYVeWRYI69wWKwK2cD1QbMiUQnoujWvrew==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 @@ -754,8 +873,8 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-optional-chaining@7.27.1': - resolution: {integrity: sha512-BQmKPPIuc8EkZgNKsv0X4bPmOoayeu4F1YCwx2/CfmDSXDbp7GnzlUH+/ul5VGfRg1AoFPsrIThlEBj2xb4CAg==} + '@babel/plugin-transform-optional-chaining@7.28.5': + resolution: {integrity: sha512-N6fut9IZlPnjPwgiQkXNhb+cT8wQKFlJNqcZkWlcTqkcqx6/kU4ynGmLFoa4LViBSirn05YAwk+sQBbPfxtYzQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 @@ -874,8 +993,8 @@ packages: peerDependencies: '@babel/core': ^7.0.0 - '@babel/preset-env@7.28.3': - resolution: {integrity: sha512-ROiDcM+GbYVPYBOeCR6uBXKkQpBExLl8k9HO1ygXEyds39j+vCCsjmj7S8GOniZQlEs81QlkdJZe76IpLSiqpg==} + '@babel/preset-env@7.28.5': + resolution: {integrity: sha512-S36mOoi1Sb6Fz98fBfE+UZSpYw5mJm0NUHtIKrOuNcqeFauy1J6dIvXm2KRVKobOSaGq4t/hBXdN4HGU3wL9Wg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 @@ -907,10 +1026,18 @@ packages: resolution: {integrity: sha512-YEzuboP2qvQavAcjgQNVgsvHIDv6ZpwXvcvjmyySP2DIMuByS/6ioU5G9pYrWHM6T2YDfc7xga9iNzYOs12CFQ==} engines: {node: '>=6.9.0'} + '@babel/traverse@7.28.5': + resolution: {integrity: sha512-TCCj4t55U90khlYkVV/0TfkJkAkUg3jZFA3Neb7unZT8CPok7iiRfaX0F+WnqWqt7OxhOn0uBKXCw4lbL8W0aQ==} + engines: {node: '>=6.9.0'} + '@babel/types@7.28.4': resolution: {integrity: sha512-bkFqkLhh3pMBUQQkpVgWDWq/lqzc2678eUyDlTBhRqhCHFguYYGM0Efga7tYk4TogG/3x0EEl66/OQ+WGbWB/Q==} engines: {node: '>=6.9.0'} + '@babel/types@7.28.5': + resolution: {integrity: sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==} + engines: {node: '>=6.9.0'} + '@biomejs/biome@2.2.4': resolution: {integrity: sha512-TBHU5bUy/Ok6m8c0y3pZiuO/BZoY/OcGxoLlrfQof5s8ISVwbVBdFINPQZyFfKwil8XibYWb7JMwnT8wT4WVPg==} engines: {node: '>=14.21.3'} @@ -987,17 +1114,17 @@ packages: '@bufbuild/protoplugin@1.10.1': resolution: {integrity: sha512-LaSbfwabAFIvbVnbn8jWwElRoffCIxhVraO8arliVwWupWezHLXgqPHEYLXZY/SsAR+/YsFBQJa8tAGtNPJyaQ==} - '@emnapi/core@1.5.0': - resolution: {integrity: sha512-sbP8GzB1WDzacS8fgNPpHlp6C9VZe+SJP3F90W9rLemaQj2PzIuTEl1qDOYQf58YIpyjViI24y9aPWCjEzY2cg==} + '@emnapi/core@1.7.1': + resolution: {integrity: sha512-o1uhUASyo921r2XtHYOHy7gdkGLge8ghBEQHMWmyJFoXlpU58kIrhhN3w26lpQb6dspetweapMn2CSNwQ8I4wg==} - '@emnapi/runtime@1.5.0': - resolution: {integrity: sha512-97/BJ3iXHww3djw6hYIfErCZFee7qCtrneuLa20UXFCOTCfBM2cvQHjWJ2EG0s0MtdNwInarqCTz35i4wWXHsQ==} + '@emnapi/runtime@1.7.1': + resolution: {integrity: sha512-PVtJr5CmLwYAU9PZDMITZoR5iAOShYREoR45EyyLrbntV50mdePTgUn4AmOw90Ifcj+x2kRjdzr1HP3RrNiHGA==} '@emnapi/wasi-threads@1.1.0': resolution: {integrity: sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ==} - '@esbuild/aix-ppc64@0.25.8': - resolution: {integrity: sha512-urAvrUedIqEiFR3FYSLTWQgLu5tb+m0qZw0NBEasUeo6wuqatkMDaRT+1uABiGXEu5vqgPd7FGE1BhsAIy9QVA==} + '@esbuild/aix-ppc64@0.25.11': + resolution: {integrity: sha512-Xt1dOL13m8u0WE8iplx9Ibbm+hFAO0GsU2P34UNoDGvZYkY8ifSiy6Zuc1lYxfG7svWE2fzqCUmFp5HCn51gJg==} engines: {node: '>=18'} cpu: [ppc64] os: [aix] @@ -1008,8 +1135,8 @@ packages: cpu: [ppc64] os: [aix] - '@esbuild/android-arm64@0.25.8': - resolution: {integrity: sha512-OD3p7LYzWpLhZEyATcTSJ67qB5D+20vbtr6vHlHWSQYhKtzUYrETuWThmzFpZtFsBIxRvhO07+UgVA9m0i/O1w==} + '@esbuild/android-arm64@0.25.11': + resolution: {integrity: sha512-9slpyFBc4FPPz48+f6jyiXOx/Y4v34TUeDDXJpZqAWQn/08lKGeD8aDp9TMn9jDz2CiEuHwfhRmGBvpnd/PWIQ==} engines: {node: '>=18'} cpu: [arm64] os: [android] @@ -1020,8 +1147,8 @@ packages: cpu: [arm64] os: [android] - '@esbuild/android-arm@0.25.8': - resolution: {integrity: sha512-RONsAvGCz5oWyePVnLdZY/HHwA++nxYWIX1atInlaW6SEkwq6XkP3+cb825EUcRs5Vss/lGh/2YxAb5xqc07Uw==} + '@esbuild/android-arm@0.25.11': + resolution: {integrity: sha512-uoa7dU+Dt3HYsethkJ1k6Z9YdcHjTrSb5NUy66ZfZaSV8hEYGD5ZHbEMXnqLFlbBflLsl89Zke7CAdDJ4JI+Gg==} engines: {node: '>=18'} cpu: [arm] os: [android] @@ -1032,8 +1159,8 @@ packages: cpu: [arm] os: [android] - '@esbuild/android-x64@0.25.8': - resolution: {integrity: sha512-yJAVPklM5+4+9dTeKwHOaA+LQkmrKFX96BM0A/2zQrbS6ENCmxc4OVoBs5dPkCCak2roAD+jKCdnmOqKszPkjA==} + '@esbuild/android-x64@0.25.11': + resolution: {integrity: sha512-Sgiab4xBjPU1QoPEIqS3Xx+R2lezu0LKIEcYe6pftr56PqPygbB7+szVnzoShbx64MUupqoE0KyRlN7gezbl8g==} engines: {node: '>=18'} cpu: [x64] os: [android] @@ -1044,8 +1171,8 @@ packages: cpu: [x64] os: [android] - '@esbuild/darwin-arm64@0.25.8': - resolution: {integrity: sha512-Jw0mxgIaYX6R8ODrdkLLPwBqHTtYHJSmzzd+QeytSugzQ0Vg4c5rDky5VgkoowbZQahCbsv1rT1KW72MPIkevw==} + '@esbuild/darwin-arm64@0.25.11': + resolution: {integrity: sha512-VekY0PBCukppoQrycFxUqkCojnTQhdec0vevUL/EDOCnXd9LKWqD/bHwMPzigIJXPhC59Vd1WFIL57SKs2mg4w==} engines: {node: '>=18'} cpu: [arm64] os: [darwin] @@ -1056,8 +1183,8 @@ packages: cpu: [arm64] os: [darwin] - '@esbuild/darwin-x64@0.25.8': - resolution: {integrity: sha512-Vh2gLxxHnuoQ+GjPNvDSDRpoBCUzY4Pu0kBqMBDlK4fuWbKgGtmDIeEC081xi26PPjn+1tct+Bh8FjyLlw1Zlg==} + '@esbuild/darwin-x64@0.25.11': + resolution: {integrity: sha512-+hfp3yfBalNEpTGp9loYgbknjR695HkqtY3d3/JjSRUyPg/xd6q+mQqIb5qdywnDxRZykIHs3axEqU6l1+oWEQ==} engines: {node: '>=18'} cpu: [x64] os: [darwin] @@ -1068,8 +1195,8 @@ packages: cpu: [x64] os: [darwin] - '@esbuild/freebsd-arm64@0.25.8': - resolution: {integrity: sha512-YPJ7hDQ9DnNe5vxOm6jaie9QsTwcKedPvizTVlqWG9GBSq+BuyWEDazlGaDTC5NGU4QJd666V0yqCBL2oWKPfA==} + '@esbuild/freebsd-arm64@0.25.11': + resolution: {integrity: sha512-CmKjrnayyTJF2eVuO//uSjl/K3KsMIeYeyN7FyDBjsR3lnSJHaXlVoAK8DZa7lXWChbuOk7NjAc7ygAwrnPBhA==} engines: {node: '>=18'} cpu: [arm64] os: [freebsd] @@ -1080,8 +1207,8 @@ packages: cpu: [arm64] os: [freebsd] - '@esbuild/freebsd-x64@0.25.8': - resolution: {integrity: sha512-MmaEXxQRdXNFsRN/KcIimLnSJrk2r5H8v+WVafRWz5xdSVmWLoITZQXcgehI2ZE6gioE6HirAEToM/RvFBeuhw==} + '@esbuild/freebsd-x64@0.25.11': + resolution: {integrity: sha512-Dyq+5oscTJvMaYPvW3x3FLpi2+gSZTCE/1ffdwuM6G1ARang/mb3jvjxs0mw6n3Lsw84ocfo9CrNMqc5lTfGOw==} engines: {node: '>=18'} cpu: [x64] os: [freebsd] @@ -1092,8 +1219,8 @@ packages: cpu: [x64] os: [freebsd] - '@esbuild/linux-arm64@0.25.8': - resolution: {integrity: sha512-WIgg00ARWv/uYLU7lsuDK00d/hHSfES5BzdWAdAig1ioV5kaFNrtK8EqGcUBJhYqotlUByUKz5Qo6u8tt7iD/w==} + '@esbuild/linux-arm64@0.25.11': + resolution: {integrity: sha512-Qr8AzcplUhGvdyUF08A1kHU3Vr2O88xxP0Tm8GcdVOUm25XYcMPp2YqSVHbLuXzYQMf9Bh/iKx7YPqECs6ffLA==} engines: {node: '>=18'} cpu: [arm64] os: [linux] @@ -1104,8 +1231,8 @@ packages: cpu: [arm64] os: [linux] - '@esbuild/linux-arm@0.25.8': - resolution: {integrity: sha512-FuzEP9BixzZohl1kLf76KEVOsxtIBFwCaLupVuk4eFVnOZfU+Wsn+x5Ryam7nILV2pkq2TqQM9EZPsOBuMC+kg==} + '@esbuild/linux-arm@0.25.11': + resolution: {integrity: sha512-TBMv6B4kCfrGJ8cUPo7vd6NECZH/8hPpBHHlYI3qzoYFvWu2AdTvZNuU/7hsbKWqu/COU7NIK12dHAAqBLLXgw==} engines: {node: '>=18'} cpu: [arm] os: [linux] @@ -1116,8 +1243,8 @@ packages: cpu: [arm] os: [linux] - '@esbuild/linux-ia32@0.25.8': - resolution: {integrity: sha512-A1D9YzRX1i+1AJZuFFUMP1E9fMaYY+GnSQil9Tlw05utlE86EKTUA7RjwHDkEitmLYiFsRd9HwKBPEftNdBfjg==} + '@esbuild/linux-ia32@0.25.11': + resolution: {integrity: sha512-TmnJg8BMGPehs5JKrCLqyWTVAvielc615jbkOirATQvWWB1NMXY77oLMzsUjRLa0+ngecEmDGqt5jiDC6bfvOw==} engines: {node: '>=18'} cpu: [ia32] os: [linux] @@ -1128,8 +1255,8 @@ packages: cpu: [ia32] os: [linux] - '@esbuild/linux-loong64@0.25.8': - resolution: {integrity: sha512-O7k1J/dwHkY1RMVvglFHl1HzutGEFFZ3kNiDMSOyUrB7WcoHGf96Sh+64nTRT26l3GMbCW01Ekh/ThKM5iI7hQ==} + '@esbuild/linux-loong64@0.25.11': + resolution: {integrity: sha512-DIGXL2+gvDaXlaq8xruNXUJdT5tF+SBbJQKbWy/0J7OhU8gOHOzKmGIlfTTl6nHaCOoipxQbuJi7O++ldrxgMw==} engines: {node: '>=18'} cpu: [loong64] os: [linux] @@ -1140,8 +1267,8 @@ packages: cpu: [loong64] os: [linux] - '@esbuild/linux-mips64el@0.25.8': - resolution: {integrity: sha512-uv+dqfRazte3BzfMp8PAQXmdGHQt2oC/y2ovwpTteqrMx2lwaksiFZ/bdkXJC19ttTvNXBuWH53zy/aTj1FgGw==} + '@esbuild/linux-mips64el@0.25.11': + resolution: {integrity: sha512-Osx1nALUJu4pU43o9OyjSCXokFkFbyzjXb6VhGIJZQ5JZi8ylCQ9/LFagolPsHtgw6himDSyb5ETSfmp4rpiKQ==} engines: {node: '>=18'} cpu: [mips64el] os: [linux] @@ -1152,8 +1279,8 @@ packages: cpu: [mips64el] os: [linux] - '@esbuild/linux-ppc64@0.25.8': - resolution: {integrity: sha512-GyG0KcMi1GBavP5JgAkkstMGyMholMDybAf8wF5A70CALlDM2p/f7YFE7H92eDeH/VBtFJA5MT4nRPDGg4JuzQ==} + '@esbuild/linux-ppc64@0.25.11': + resolution: {integrity: sha512-nbLFgsQQEsBa8XSgSTSlrnBSrpoWh7ioFDUmwo158gIm5NNP+17IYmNWzaIzWmgCxq56vfr34xGkOcZ7jX6CPw==} engines: {node: '>=18'} cpu: [ppc64] os: [linux] @@ -1164,8 +1291,8 @@ packages: cpu: [ppc64] os: [linux] - '@esbuild/linux-riscv64@0.25.8': - resolution: {integrity: sha512-rAqDYFv3yzMrq7GIcen3XP7TUEG/4LK86LUPMIz6RT8A6pRIDn0sDcvjudVZBiiTcZCY9y2SgYX2lgK3AF+1eg==} + '@esbuild/linux-riscv64@0.25.11': + resolution: {integrity: sha512-HfyAmqZi9uBAbgKYP1yGuI7tSREXwIb438q0nqvlpxAOs3XnZ8RsisRfmVsgV486NdjD7Mw2UrFSw51lzUk1ww==} engines: {node: '>=18'} cpu: [riscv64] os: [linux] @@ -1176,8 +1303,8 @@ packages: cpu: [riscv64] os: [linux] - '@esbuild/linux-s390x@0.25.8': - resolution: {integrity: sha512-Xutvh6VjlbcHpsIIbwY8GVRbwoviWT19tFhgdA7DlenLGC/mbc3lBoVb7jxj9Z+eyGqvcnSyIltYUrkKzWqSvg==} + '@esbuild/linux-s390x@0.25.11': + resolution: {integrity: sha512-HjLqVgSSYnVXRisyfmzsH6mXqyvj0SA7pG5g+9W7ESgwA70AXYNpfKBqh1KbTxmQVaYxpzA/SvlB9oclGPbApw==} engines: {node: '>=18'} cpu: [s390x] os: [linux] @@ -1188,8 +1315,8 @@ packages: cpu: [s390x] os: [linux] - '@esbuild/linux-x64@0.25.8': - resolution: {integrity: sha512-ASFQhgY4ElXh3nDcOMTkQero4b1lgubskNlhIfJrsH5OKZXDpUAKBlNS0Kx81jwOBp+HCeZqmoJuihTv57/jvQ==} + '@esbuild/linux-x64@0.25.11': + resolution: {integrity: sha512-HSFAT4+WYjIhrHxKBwGmOOSpphjYkcswF449j6EjsjbinTZbp8PJtjsVK1XFJStdzXdy/jaddAep2FGY+wyFAQ==} engines: {node: '>=18'} cpu: [x64] os: [linux] @@ -1200,8 +1327,8 @@ packages: cpu: [x64] os: [linux] - '@esbuild/netbsd-arm64@0.25.8': - resolution: {integrity: sha512-d1KfruIeohqAi6SA+gENMuObDbEjn22olAR7egqnkCD9DGBG0wsEARotkLgXDu6c4ncgWTZJtN5vcgxzWRMzcw==} + '@esbuild/netbsd-arm64@0.25.11': + resolution: {integrity: sha512-hr9Oxj1Fa4r04dNpWr3P8QKVVsjQhqrMSUzZzf+LZcYjZNqhA3IAfPQdEh1FLVUJSiu6sgAwp3OmwBfbFgG2Xg==} engines: {node: '>=18'} cpu: [arm64] os: [netbsd] @@ -1212,8 +1339,8 @@ packages: cpu: [arm64] os: [netbsd] - '@esbuild/netbsd-x64@0.25.8': - resolution: {integrity: sha512-nVDCkrvx2ua+XQNyfrujIG38+YGyuy2Ru9kKVNyh5jAys6n+l44tTtToqHjino2My8VAY6Lw9H7RI73XFi66Cg==} + '@esbuild/netbsd-x64@0.25.11': + resolution: {integrity: sha512-u7tKA+qbzBydyj0vgpu+5h5AeudxOAGncb8N6C9Kh1N4n7wU1Xw1JDApsRjpShRpXRQlJLb9wY28ELpwdPcZ7A==} engines: {node: '>=18'} cpu: [x64] os: [netbsd] @@ -1224,8 +1351,8 @@ packages: cpu: [x64] os: [netbsd] - '@esbuild/openbsd-arm64@0.25.8': - resolution: {integrity: sha512-j8HgrDuSJFAujkivSMSfPQSAa5Fxbvk4rgNAS5i3K+r8s1X0p1uOO2Hl2xNsGFppOeHOLAVgYwDVlmxhq5h+SQ==} + '@esbuild/openbsd-arm64@0.25.11': + resolution: {integrity: sha512-Qq6YHhayieor3DxFOoYM1q0q1uMFYb7cSpLD2qzDSvK1NAvqFi8Xgivv0cFC6J+hWVw2teCYltyy9/m/14ryHg==} engines: {node: '>=18'} cpu: [arm64] os: [openbsd] @@ -1236,8 +1363,8 @@ packages: cpu: [arm64] os: [openbsd] - '@esbuild/openbsd-x64@0.25.8': - resolution: {integrity: sha512-1h8MUAwa0VhNCDp6Af0HToI2TJFAn1uqT9Al6DJVzdIBAd21m/G0Yfc77KDM3uF3T/YaOgQq3qTJHPbTOInaIQ==} + '@esbuild/openbsd-x64@0.25.11': + resolution: {integrity: sha512-CN+7c++kkbrckTOz5hrehxWN7uIhFFlmS/hqziSFVWpAzpWrQoAG4chH+nN3Be+Kzv/uuo7zhX716x3Sn2Jduw==} engines: {node: '>=18'} cpu: [x64] os: [openbsd] @@ -1248,8 +1375,8 @@ packages: cpu: [x64] os: [openbsd] - '@esbuild/openharmony-arm64@0.25.8': - resolution: {integrity: sha512-r2nVa5SIK9tSWd0kJd9HCffnDHKchTGikb//9c7HX+r+wHYCpQrSgxhlY6KWV1nFo1l4KFbsMlHk+L6fekLsUg==} + '@esbuild/openharmony-arm64@0.25.11': + resolution: {integrity: sha512-rOREuNIQgaiR+9QuNkbkxubbp8MSO9rONmwP5nKncnWJ9v5jQ4JxFnLu4zDSRPf3x4u+2VN4pM4RdyIzDty/wQ==} engines: {node: '>=18'} cpu: [arm64] os: [openharmony] @@ -1260,8 +1387,8 @@ packages: cpu: [arm64] os: [openharmony] - '@esbuild/sunos-x64@0.25.8': - resolution: {integrity: sha512-zUlaP2S12YhQ2UzUfcCuMDHQFJyKABkAjvO5YSndMiIkMimPmxA+BYSBikWgsRpvyxuRnow4nS5NPnf9fpv41w==} + '@esbuild/sunos-x64@0.25.11': + resolution: {integrity: sha512-nq2xdYaWxyg9DcIyXkZhcYulC6pQ2FuCgem3LI92IwMgIZ69KHeY8T4Y88pcwoLIjbed8n36CyKoYRDygNSGhA==} engines: {node: '>=18'} cpu: [x64] os: [sunos] @@ -1272,8 +1399,8 @@ packages: cpu: [x64] os: [sunos] - '@esbuild/win32-arm64@0.25.8': - resolution: {integrity: sha512-YEGFFWESlPva8hGL+zvj2z/SaK+pH0SwOM0Nc/d+rVnW7GSTFlLBGzZkuSU9kFIGIo8q9X3ucpZhu8PDN5A2sQ==} + '@esbuild/win32-arm64@0.25.11': + resolution: {integrity: sha512-3XxECOWJq1qMZ3MN8srCJ/QfoLpL+VaxD/WfNRm1O3B4+AZ/BnLVgFbUV3eiRYDMXetciH16dwPbbHqwe1uU0Q==} engines: {node: '>=18'} cpu: [arm64] os: [win32] @@ -1284,8 +1411,8 @@ packages: cpu: [arm64] os: [win32] - '@esbuild/win32-ia32@0.25.8': - resolution: {integrity: sha512-hiGgGC6KZ5LZz58OL/+qVVoZiuZlUYlYHNAmczOm7bs2oE1XriPFi5ZHHrS8ACpV5EjySrnoCKmcbQMN+ojnHg==} + '@esbuild/win32-ia32@0.25.11': + resolution: {integrity: sha512-3ukss6gb9XZ8TlRyJlgLn17ecsK4NSQTmdIXRASVsiS2sQ6zPPZklNJT5GR5tE/MUarymmy8kCEf5xPCNCqVOA==} engines: {node: '>=18'} cpu: [ia32] os: [win32] @@ -1296,8 +1423,8 @@ packages: cpu: [ia32] os: [win32] - '@esbuild/win32-x64@0.25.8': - resolution: {integrity: sha512-cn3Yr7+OaaZq1c+2pe+8yxC8E144SReCQjN6/2ynubzYjvyqZjTXfQJpAcQpsdJq3My7XADANiYGHoFC69pLQw==} + '@esbuild/win32-x64@0.25.11': + resolution: {integrity: sha512-D7Hpz6A2L4hzsRpPaCYkQnGOotdUpDzSGRIv9I+1ITdHROSFUWW95ZPZWQmGka1Fg7W3zFJowyn9WGwMJ0+KPA==} engines: {node: '>=18'} cpu: [x64] os: [win32] @@ -1364,9 +1491,6 @@ packages: '@jridgewell/source-map@0.3.11': resolution: {integrity: sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==} - '@jridgewell/sourcemap-codec@1.5.4': - resolution: {integrity: sha512-VT2+G1VQs/9oz078bLrYbecdZKs912zQlkelYpuf+SXF+QvZDYJlbx/LSx+meSAwdDFnF8FVXW92AVjjkVmgFw==} - '@jridgewell/sourcemap-codec@1.5.5': resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} @@ -1411,8 +1535,21 @@ packages: '@maplibre/vt-pbf@4.0.3': resolution: {integrity: sha512-YsW99BwnT+ukJRkseBcLuZHfITB4puJoxnqPVjo72rhW/TaawVYsgQHcqWLzTxqknttYoDpgyERzWSa/XrETdA==} - '@napi-rs/wasm-runtime@1.0.7': - resolution: {integrity: sha512-SeDnOO0Tk7Okiq6DbXmmBODgOAb9dp9gjlphokTUxmt8U3liIP1ZsozBahH69j/RJv+Rfs6IwUKHTgQYJ/HBAw==} + '@microsoft/api-extractor-model@7.31.2': + resolution: {integrity: sha512-d0WwxwBLZaHokTrOngqHVkQK59NlveV5RE4wEpjaybhSNmEK9N7KPCcT5n8JcpH6k5o6AhxG47g1km2D7BZw8Q==} + + '@microsoft/api-extractor@7.53.2': + resolution: {integrity: sha512-hG3+wJY6aZlkQhGpUbhq1C5F1uJLsmDjrwVea+WT18RbD1XtIGn/c4uyMF7gdXLjLNwErB47hnRk9QNjpEHUWA==} + hasBin: true + + '@microsoft/tsdoc-config@0.17.1': + resolution: {integrity: sha512-UtjIFe0C6oYgTnad4q1QP4qXwLhe6tIpNTRStJ2RZEPIkqQPREAwE5spzVxsdn9UaEMUqhh0AqSx3X4nWAKXWw==} + + '@microsoft/tsdoc@0.15.1': + resolution: {integrity: sha512-4aErSrCR/On/e5G2hDP0wjooqDdauzEbIq8hIkIe5pXV0rtWJZvdCEKL0ykZxex+IxIwBp0eGeV48hQN07dXtw==} + + '@napi-rs/wasm-runtime@0.2.12': + resolution: {integrity: sha512-ZVWUcfwY4E/yPitQJl481FjFo3K22D6qF0DuFH6Y/nbnE11GY5uguDxZMGXPQ8WQ0128MXQD7TnfHyK4oWoIJQ==} '@noble/curves@1.9.6': resolution: {integrity: sha512-GIKz/j99FRthB8icyJQA51E8Uk5hXmdyThjgQXRKiv9h0zeRlzSCLIzFw6K1LotZ3XuB7yzlf76qk7uBmTdFqA==} @@ -1434,8 +1571,16 @@ packages: resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} engines: {node: '>= 8'} - '@oxc-project/types@0.94.0': - resolution: {integrity: sha512-+UgQT/4o59cZfH6Cp7G0hwmqEQ0wE+AdIwhikdwnhWI9Dp8CgSY081+Q3O67/wq3VJu8mgUEB93J9EHHn70fOw==} + '@oxc-project/runtime@0.71.0': + resolution: {integrity: sha512-QwoF5WUXIGFQ+hSxWEib4U/aeLoiDN9JlP18MnBgx9LLPRDfn1iICtcow7Jgey6HLH4XFceWXQD5WBJ39dyJcw==} + engines: {node: '>=6.9.0'} + + '@oxc-project/types@0.71.0': + resolution: {integrity: sha512-5CwQ4MI+P4MQbjLWXgNurA+igGwu/opNetIE13LBs9+V93R64MLvDKOOLZIXSzEfovU3Zef3q3GjPnMTgJTn2w==} + + '@publint/pack@0.1.2': + resolution: {integrity: sha512-S+9ANAvUmjutrshV4jZjaiG8XQyuJIZ8a4utWmN/vW1sgQ9IfBnPndwkmQYw53QmouOIytT874u65HEmu6H5jw==} + engines: {node: '>=18'} '@quansync/fs@0.1.5': resolution: {integrity: sha512-lNS9hL2aS2NZgNW7BBj+6EBl4rOf8l+tQ0eRY6JWCI8jI2kc53gSoqbjojU0OnAWhzoXiOjFyGsHcDGePB3lhA==} @@ -1459,6 +1604,19 @@ packages: '@types/react-dom': optional: true + '@radix-ui/react-alert-dialog@1.1.15': + resolution: {integrity: sha512-oTVLkEw5GpdRe29BqJ0LSDFWI3qu0vR1M0mUkOQWDIUnY/QIkLpgDMWuKxP94c2NAC2LGcgVhG1ImF3jkZ5wXw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + '@radix-ui/react-arrow@1.1.7': resolution: {integrity: sha512-F+M1tLhO+mlQaOWspE8Wstg+z6PwxwRd8oQ8IXceWz92kfAmalTRf0EjrouQeo7QssEPfCn05B4Ihs1K9WQ/7w==} peerDependencies: @@ -1952,98 +2110,78 @@ packages: '@radix-ui/rect@1.1.1': resolution: {integrity: sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw==} - '@rolldown/binding-android-arm64@1.0.0-beta.43': - resolution: {integrity: sha512-TP8bcPOb1s6UmY5syhXrDn9k0XkYcw+XaoylTN4cJxf0JOVS2j682I3aTcpfT51hOFGr2bRwNKN9RZ19XxeQbA==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [android] - - '@rolldown/binding-darwin-arm64@1.0.0-beta.43': - resolution: {integrity: sha512-kuVWnZsE4vEjMF/10SbSUyzucIW2zmdsqFghYMqy+fsjXnRHg0luTU6qWF8IqJf4Cbpm9NEZRnjIEPpAbdiSNQ==} - engines: {node: ^20.19.0 || >=22.12.0} + '@rolldown/binding-darwin-arm64@1.0.0-beta.9-commit.d91dfb5': + resolution: {integrity: sha512-Mp0/gqiPdepHjjVm7e0yL1acWvI0rJVVFQEADSezvAjon9sjQ7CEg9JnXICD4B1YrPmN9qV/e7cQZCp87tTV4w==} cpu: [arm64] os: [darwin] - '@rolldown/binding-darwin-x64@1.0.0-beta.43': - resolution: {integrity: sha512-u9Ps4sh6lcmJ3vgLtyEg/x4jlhI64U0mM93Ew+tlfFdLDe7yKyA+Fe80cpr2n1mNCeZXrvTSbZluKpXQ0GxLjw==} - engines: {node: ^20.19.0 || >=22.12.0} + '@rolldown/binding-darwin-x64@1.0.0-beta.9-commit.d91dfb5': + resolution: {integrity: sha512-40re4rMNrsi57oavRzIOpRGmg3QRlW6Ea8Q3znaqgOuJuKVrrm2bIQInTfkZJG7a4/5YMX7T951d0+toGLTdCA==} cpu: [x64] os: [darwin] - '@rolldown/binding-freebsd-x64@1.0.0-beta.43': - resolution: {integrity: sha512-h9lUtVtXgfbk/tnicMpbFfZ3DJvk5Zn2IvmlC1/e0+nUfwoc/TFqpfrRRqcNBXk/e+xiWMSKv6b0MF8N+Rtvlg==} - engines: {node: ^20.19.0 || >=22.12.0} + '@rolldown/binding-freebsd-x64@1.0.0-beta.9-commit.d91dfb5': + resolution: {integrity: sha512-8BDM939bbMariZupiHp3OmP5N+LXPT4mULA0hZjDaq970PCxv4krZOSMG+HkWUUwmuQROtV+/00xw39EO0P+8g==} cpu: [x64] os: [freebsd] - '@rolldown/binding-linux-arm-gnueabihf@1.0.0-beta.43': - resolution: {integrity: sha512-IX2C6bA6wM2rX/RvD75ko+ix9yxPKjKGGq7pOhB8wGI4Z4fqX5B1nDHga/qMDmAdCAR1m9ymzxkmqhm/AFYf7A==} - engines: {node: ^20.19.0 || >=22.12.0} + '@rolldown/binding-linux-arm-gnueabihf@1.0.0-beta.9-commit.d91dfb5': + resolution: {integrity: sha512-sntsPaPgrECpBB/+2xrQzVUt0r493TMPI+4kWRMhvMsmrxOqH1Ep5lM0Wua/ZdbfZNwm1aVa5pcESQfNfM4Fhw==} cpu: [arm] os: [linux] - '@rolldown/binding-linux-arm64-gnu@1.0.0-beta.43': - resolution: {integrity: sha512-mcjd57vEj+CEQbZAzUiaxNzNgwwgOpFtZBWcINm8DNscvkXl5b/s622Z1dqGNWSdrZmdjdC6LWMvu8iHM6v9sQ==} - engines: {node: ^20.19.0 || >=22.12.0} + '@rolldown/binding-linux-arm64-gnu@1.0.0-beta.9-commit.d91dfb5': + resolution: {integrity: sha512-5clBW/I+er9F2uM1OFjJFWX86y7Lcy0M+NqsN4s3o07W+8467Zk8oQa4B45vdaXoNUF/yqIAgKkA/OEdQDxZqA==} cpu: [arm64] os: [linux] libc: [glibc] - '@rolldown/binding-linux-arm64-musl@1.0.0-beta.43': - resolution: {integrity: sha512-Pa8QMwlkrztTo/1mVjZmPIQ44tCSci10TBqxzVBvXVA5CFh5EpiEi99fPSll2dHG2uT4dCOMeC6fIhyDdb0zXA==} - engines: {node: ^20.19.0 || >=22.12.0} + '@rolldown/binding-linux-arm64-musl@1.0.0-beta.9-commit.d91dfb5': + resolution: {integrity: sha512-wv+rnAfQDk9p/CheX8/Kmqk2o1WaFa4xhWI9gOyDMk/ljvOX0u0ubeM8nI1Qfox7Tnh71eV5AjzSePXUhFOyOg==} cpu: [arm64] os: [linux] libc: [musl] - '@rolldown/binding-linux-x64-gnu@1.0.0-beta.43': - resolution: {integrity: sha512-BgynXKMjeaX4AfWLARhOKDetBOOghnSiVRjAHVvhiAaDXgdQN8e65mSmXRiVoVtD3cHXx/cfU8Gw0p0K+qYKVQ==} - engines: {node: ^20.19.0 || >=22.12.0} + '@rolldown/binding-linux-x64-gnu@1.0.0-beta.9-commit.d91dfb5': + resolution: {integrity: sha512-gxD0/xhU4Py47IH3bKZbWtvB99tMkUPGPJFRfSc5UB9Osoje0l0j1PPbxpUtXIELurYCqwLBKXIMTQGifox1BQ==} cpu: [x64] os: [linux] libc: [glibc] - '@rolldown/binding-linux-x64-musl@1.0.0-beta.43': - resolution: {integrity: sha512-VIsoPlOB/tDSAw9CySckBYysoIBqLeps1/umNSYUD8pMtalJyzMTneAVI1HrUdf4ceFmQ5vARoLIXSsPwVFxNg==} - engines: {node: ^20.19.0 || >=22.12.0} + '@rolldown/binding-linux-x64-musl@1.0.0-beta.9-commit.d91dfb5': + resolution: {integrity: sha512-HotuVe3XUjDwqqEMbm3o3IRkP9gdm8raY/btd/6KE3JGLF/cv4+3ff1l6nOhAZI8wulWDPEXPtE7v+HQEaTXnA==} cpu: [x64] os: [linux] libc: [musl] - '@rolldown/binding-openharmony-arm64@1.0.0-beta.43': - resolution: {integrity: sha512-YDXTxVJG67PqTQMKyjVJSddoPbSWJ4yRz/E3xzTLHqNrTDGY0UuhG8EMr8zsYnfH/0cPFJ3wjQd/hJWHuR6nkA==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [openharmony] - - '@rolldown/binding-wasm32-wasi@1.0.0-beta.43': - resolution: {integrity: sha512-3M+2DmorXvDuAIGYQ9Z93Oy1G9ETkejLwdXXb1uRTgKN9pMcu7N+KG2zDrJwqyxeeLIFE22AZGtSJm3PJbNu9Q==} - engines: {node: '>=14.0.0'} + '@rolldown/binding-wasm32-wasi@1.0.0-beta.9-commit.d91dfb5': + resolution: {integrity: sha512-8Cx+ucbd8n2dIr21FqBh6rUvTVL0uTgEtKR7l+MUZ5BgY4dFh1e4mPVX8oqmoYwOxBiXrsD2JIOCz4AyKLKxWA==} + engines: {node: '>=14.21.3'} cpu: [wasm32] - '@rolldown/binding-win32-arm64-msvc@1.0.0-beta.43': - resolution: {integrity: sha512-/B1j1pJs33y9ywtslOMxryUPHq8zIGu/OGEc2gyed0slimJ8fX2uR/SaJVhB4+NEgCFIeYDR4CX6jynAkeRuCA==} - engines: {node: ^20.19.0 || >=22.12.0} + '@rolldown/binding-win32-arm64-msvc@1.0.0-beta.9-commit.d91dfb5': + resolution: {integrity: sha512-Vhq5vikrVDxAa75fxsyqj0c0Y/uti/TwshXI71Xb8IeUQJOBnmLUsn5dgYf5ljpYYkNa0z9BPAvUDIDMmyDi+w==} cpu: [arm64] os: [win32] - '@rolldown/binding-win32-ia32-msvc@1.0.0-beta.43': - resolution: {integrity: sha512-29oG1swCz7hNP+CQYrsM4EtylsKwuYzM8ljqbqC5TsQwmKat7P8ouDpImsqg/GZxFSXcPP9ezQm0Q0wQwGM3JA==} - engines: {node: ^20.19.0 || >=22.12.0} + '@rolldown/binding-win32-ia32-msvc@1.0.0-beta.9-commit.d91dfb5': + resolution: {integrity: sha512-lN7RIg9Iugn08zP2aZN9y/MIdG8iOOCE93M1UrFlrxMTqPf8X+fDzmR/OKhTSd1A2pYNipZHjyTcb5H8kyQSow==} cpu: [ia32] os: [win32] - '@rolldown/binding-win32-x64-msvc@1.0.0-beta.43': - resolution: {integrity: sha512-eWBV1Ef3gfGNehxVGCyXs7wLayRIgCmyItuCZwYYXW5bsk4EvR4n2GP5m3ohjnx7wdiY3nLmwQfH2Knb5gbNZw==} - engines: {node: ^20.19.0 || >=22.12.0} + '@rolldown/binding-win32-x64-msvc@1.0.0-beta.9-commit.d91dfb5': + resolution: {integrity: sha512-7/7cLIn48Y+EpQ4CePvf8reFl63F15yPUlg4ZAhl+RXJIfydkdak1WD8Ir3AwAO+bJBXzrfNL+XQbxm0mcQZmw==} cpu: [x64] os: [win32] + '@rolldown/pluginutils@1.0.0-beta.27': + resolution: {integrity: sha512-+d0F4MKMCbeVUJwG96uQ4SgAznZNSq93I3V+9NHA4OpvqG8mRCpGdKmK8l/dl02h2CCDHwW2FqilnTyDcAnqjA==} + '@rolldown/pluginutils@1.0.0-beta.38': resolution: {integrity: sha512-N/ICGKleNhA5nc9XXQG/kkKHJ7S55u0x0XUJbbkmdCnFuoRkM1Il12q9q0eX19+M7KKUEPw/daUPIRnxhcxAIw==} - '@rolldown/pluginutils@1.0.0-beta.43': - resolution: {integrity: sha512-5Uxg7fQUCmfhax7FJke2+8B6cqgeUJUD9o2uXIKXhD+mG0mL6NObmVoi9wXEU1tY89mZKgAYA6fTbftx3q2ZPQ==} + '@rolldown/pluginutils@1.0.0-beta.9-commit.d91dfb5': + resolution: {integrity: sha512-8sExkWRK+zVybw3+2/kBkYBFeLnEUWz1fT7BLHplpzmtqkOfTbAQ9gkt4pzwGIIZmg4Qn5US5ACjUBenrhezwQ==} '@rollup/plugin-babel@5.3.1': resolution: {integrity: sha512-WFfdLWU/xVWKeRQnKmIAQULUI7Il0gZnBIH/ZFO069wYIfPu+8zrfp/KMW0atmELoRDq8FbiP3VCss9MhCut7Q==} @@ -2098,233 +2236,157 @@ packages: rollup: optional: true - '@rollup/rollup-android-arm-eabi@4.46.2': - resolution: {integrity: sha512-Zj3Hl6sN34xJtMv7Anwb5Gu01yujyE/cLBDB2gnHTAHaWS1Z38L7kuSG+oAh0giZMqG060f/YBStXtMH6FvPMA==} - cpu: [arm] - os: [android] - - '@rollup/rollup-android-arm-eabi@4.50.1': - resolution: {integrity: sha512-HJXwzoZN4eYTdD8bVV22DN8gsPCAj3V20NHKOs8ezfXanGpmVPR7kalUHd+Y31IJp9stdB87VKPFbsGY3H/2ag==} + '@rollup/rollup-android-arm-eabi@4.52.5': + resolution: {integrity: sha512-8c1vW4ocv3UOMp9K+gToY5zL2XiiVw3k7f1ksf4yO1FlDFQ1C2u72iACFnSOceJFsWskc2WZNqeRhFRPzv+wtQ==} cpu: [arm] os: [android] - '@rollup/rollup-android-arm64@4.46.2': - resolution: {integrity: sha512-nTeCWY83kN64oQ5MGz3CgtPx8NSOhC5lWtsjTs+8JAJNLcP3QbLCtDDgUKQc/Ro/frpMq4SHUaHN6AMltcEoLQ==} - cpu: [arm64] - os: [android] - - '@rollup/rollup-android-arm64@4.50.1': - resolution: {integrity: sha512-PZlsJVcjHfcH53mOImyt3bc97Ep3FJDXRpk9sMdGX0qgLmY0EIWxCag6EigerGhLVuL8lDVYNnSo8qnTElO4xw==} + '@rollup/rollup-android-arm64@4.52.5': + resolution: {integrity: sha512-mQGfsIEFcu21mvqkEKKu2dYmtuSZOBMmAl5CFlPGLY94Vlcm+zWApK7F/eocsNzp8tKmbeBP8yXyAbx0XHsFNA==} cpu: [arm64] os: [android] - '@rollup/rollup-darwin-arm64@4.46.2': - resolution: {integrity: sha512-HV7bW2Fb/F5KPdM/9bApunQh68YVDU8sO8BvcW9OngQVN3HHHkw99wFupuUJfGR9pYLLAjcAOA6iO+evsbBaPQ==} - cpu: [arm64] - os: [darwin] - - '@rollup/rollup-darwin-arm64@4.50.1': - resolution: {integrity: sha512-xc6i2AuWh++oGi4ylOFPmzJOEeAa2lJeGUGb4MudOtgfyyjr4UPNK+eEWTPLvmPJIY/pgw6ssFIox23SyrkkJw==} + '@rollup/rollup-darwin-arm64@4.52.5': + resolution: {integrity: sha512-takF3CR71mCAGA+v794QUZ0b6ZSrgJkArC+gUiG6LB6TQty9T0Mqh3m2ImRBOxS2IeYBo4lKWIieSvnEk2OQWA==} cpu: [arm64] os: [darwin] - '@rollup/rollup-darwin-x64@4.46.2': - resolution: {integrity: sha512-SSj8TlYV5nJixSsm/y3QXfhspSiLYP11zpfwp6G/YDXctf3Xkdnk4woJIF5VQe0of2OjzTt8EsxnJDCdHd2xMA==} + '@rollup/rollup-darwin-x64@4.52.5': + resolution: {integrity: sha512-W901Pla8Ya95WpxDn//VF9K9u2JbocwV/v75TE0YIHNTbhqUTv9w4VuQ9MaWlNOkkEfFwkdNhXgcLqPSmHy0fA==} cpu: [x64] os: [darwin] - '@rollup/rollup-darwin-x64@4.50.1': - resolution: {integrity: sha512-2ofU89lEpDYhdLAbRdeyz/kX3Y2lpYc6ShRnDjY35bZhd2ipuDMDi6ZTQ9NIag94K28nFMofdnKeHR7BT0CATw==} - cpu: [x64] - os: [darwin] - - '@rollup/rollup-freebsd-arm64@4.46.2': - resolution: {integrity: sha512-ZyrsG4TIT9xnOlLsSSi9w/X29tCbK1yegE49RYm3tu3wF1L/B6LVMqnEWyDB26d9Ecx9zrmXCiPmIabVuLmNSg==} - cpu: [arm64] - os: [freebsd] - - '@rollup/rollup-freebsd-arm64@4.50.1': - resolution: {integrity: sha512-wOsE6H2u6PxsHY/BeFHA4VGQN3KUJFZp7QJBmDYI983fgxq5Th8FDkVuERb2l9vDMs1D5XhOrhBrnqcEY6l8ZA==} + '@rollup/rollup-freebsd-arm64@4.52.5': + resolution: {integrity: sha512-QofO7i7JycsYOWxe0GFqhLmF6l1TqBswJMvICnRUjqCx8b47MTo46W8AoeQwiokAx3zVryVnxtBMcGcnX12LvA==} cpu: [arm64] os: [freebsd] - '@rollup/rollup-freebsd-x64@4.46.2': - resolution: {integrity: sha512-pCgHFoOECwVCJ5GFq8+gR8SBKnMO+xe5UEqbemxBpCKYQddRQMgomv1104RnLSg7nNvgKy05sLsY51+OVRyiVw==} - cpu: [x64] - os: [freebsd] - - '@rollup/rollup-freebsd-x64@4.50.1': - resolution: {integrity: sha512-A/xeqaHTlKbQggxCqispFAcNjycpUEHP52mwMQZUNqDUJFFYtPHCXS1VAG29uMlDzIVr+i00tSFWFLivMcoIBQ==} + '@rollup/rollup-freebsd-x64@4.52.5': + resolution: {integrity: sha512-jr21b/99ew8ujZubPo9skbrItHEIE50WdV86cdSoRkKtmWa+DDr6fu2c/xyRT0F/WazZpam6kk7IHBerSL7LDQ==} cpu: [x64] os: [freebsd] - '@rollup/rollup-linux-arm-gnueabihf@4.46.2': - resolution: {integrity: sha512-EtP8aquZ0xQg0ETFcxUbU71MZlHaw9MChwrQzatiE8U/bvi5uv/oChExXC4mWhjiqK7azGJBqU0tt5H123SzVA==} - cpu: [arm] - os: [linux] - libc: [glibc] - - '@rollup/rollup-linux-arm-gnueabihf@4.50.1': - resolution: {integrity: sha512-54v4okehwl5TaSIkpp97rAHGp7t3ghinRd/vyC1iXqXMfjYUTm7TfYmCzXDoHUPTTf36L8pr0E7YsD3CfB3ZDg==} + '@rollup/rollup-linux-arm-gnueabihf@4.52.5': + resolution: {integrity: sha512-PsNAbcyv9CcecAUagQefwX8fQn9LQ4nZkpDboBOttmyffnInRy8R8dSg6hxxl2Re5QhHBf6FYIDhIj5v982ATQ==} cpu: [arm] os: [linux] libc: [glibc] - '@rollup/rollup-linux-arm-musleabihf@4.46.2': - resolution: {integrity: sha512-qO7F7U3u1nfxYRPM8HqFtLd+raev2K137dsV08q/LRKRLEc7RsiDWihUnrINdsWQxPR9jqZ8DIIZ1zJJAm5PjQ==} - cpu: [arm] - os: [linux] - libc: [musl] - - '@rollup/rollup-linux-arm-musleabihf@4.50.1': - resolution: {integrity: sha512-p/LaFyajPN/0PUHjv8TNyxLiA7RwmDoVY3flXHPSzqrGcIp/c2FjwPPP5++u87DGHtw+5kSH5bCJz0mvXngYxw==} + '@rollup/rollup-linux-arm-musleabihf@4.52.5': + resolution: {integrity: sha512-Fw4tysRutyQc/wwkmcyoqFtJhh0u31K+Q6jYjeicsGJJ7bbEq8LwPWV/w0cnzOqR2m694/Af6hpFayLJZkG2VQ==} cpu: [arm] os: [linux] libc: [musl] - '@rollup/rollup-linux-arm64-gnu@4.46.2': - resolution: {integrity: sha512-3dRaqLfcOXYsfvw5xMrxAk9Lb1f395gkoBYzSFcc/scgRFptRXL9DOaDpMiehf9CO8ZDRJW2z45b6fpU5nwjng==} - cpu: [arm64] - os: [linux] - libc: [glibc] - - '@rollup/rollup-linux-arm64-gnu@4.50.1': - resolution: {integrity: sha512-2AbMhFFkTo6Ptna1zO7kAXXDLi7H9fGTbVaIq2AAYO7yzcAsuTNWPHhb2aTA6GPiP+JXh85Y8CiS54iZoj4opw==} + '@rollup/rollup-linux-arm64-gnu@4.52.5': + resolution: {integrity: sha512-a+3wVnAYdQClOTlyapKmyI6BLPAFYs0JM8HRpgYZQO02rMR09ZcV9LbQB+NL6sljzG38869YqThrRnfPMCDtZg==} cpu: [arm64] os: [linux] libc: [glibc] - '@rollup/rollup-linux-arm64-musl@4.46.2': - resolution: {integrity: sha512-fhHFTutA7SM+IrR6lIfiHskxmpmPTJUXpWIsBXpeEwNgZzZZSg/q4i6FU4J8qOGyJ0TR+wXBwx/L7Ho9z0+uDg==} - cpu: [arm64] - os: [linux] - libc: [musl] - - '@rollup/rollup-linux-arm64-musl@4.50.1': - resolution: {integrity: sha512-Cgef+5aZwuvesQNw9eX7g19FfKX5/pQRIyhoXLCiBOrWopjo7ycfB292TX9MDcDijiuIJlx1IzJz3IoCPfqs9w==} + '@rollup/rollup-linux-arm64-musl@4.52.5': + resolution: {integrity: sha512-AvttBOMwO9Pcuuf7m9PkC1PUIKsfaAJ4AYhy944qeTJgQOqJYJ9oVl2nYgY7Rk0mkbsuOpCAYSs6wLYB2Xiw0Q==} cpu: [arm64] os: [linux] libc: [musl] - '@rollup/rollup-linux-loongarch64-gnu@4.46.2': - resolution: {integrity: sha512-i7wfGFXu8x4+FRqPymzjD+Hyav8l95UIZ773j7J7zRYc3Xsxy2wIn4x+llpunexXe6laaO72iEjeeGyUFmjKeA==} - cpu: [loong64] - os: [linux] - libc: [glibc] - - '@rollup/rollup-linux-loongarch64-gnu@4.50.1': - resolution: {integrity: sha512-RPhTwWMzpYYrHrJAS7CmpdtHNKtt2Ueo+BlLBjfZEhYBhK00OsEqM08/7f+eohiF6poe0YRDDd8nAvwtE/Y62Q==} + '@rollup/rollup-linux-loong64-gnu@4.52.5': + resolution: {integrity: sha512-DkDk8pmXQV2wVrF6oq5tONK6UHLz/XcEVow4JTTerdeV1uqPeHxwcg7aFsfnSm9L+OO8WJsWotKM2JJPMWrQtA==} cpu: [loong64] os: [linux] libc: [glibc] - '@rollup/rollup-linux-ppc64-gnu@4.46.2': - resolution: {integrity: sha512-B/l0dFcHVUnqcGZWKcWBSV2PF01YUt0Rvlurci5P+neqY/yMKchGU8ullZvIv5e8Y1C6wOn+U03mrDylP5q9Yw==} - cpu: [ppc64] - os: [linux] - libc: [glibc] - - '@rollup/rollup-linux-ppc64-gnu@4.50.1': - resolution: {integrity: sha512-eSGMVQw9iekut62O7eBdbiccRguuDgiPMsw++BVUg+1K7WjZXHOg/YOT9SWMzPZA+w98G+Fa1VqJgHZOHHnY0Q==} + '@rollup/rollup-linux-ppc64-gnu@4.52.5': + resolution: {integrity: sha512-W/b9ZN/U9+hPQVvlGwjzi+Wy4xdoH2I8EjaCkMvzpI7wJUs8sWJ03Rq96jRnHkSrcHTpQe8h5Tg3ZzUPGauvAw==} cpu: [ppc64] os: [linux] libc: [glibc] - '@rollup/rollup-linux-riscv64-gnu@4.46.2': - resolution: {integrity: sha512-32k4ENb5ygtkMwPMucAb8MtV8olkPT03oiTxJbgkJa7lJ7dZMr0GCFJlyvy+K8iq7F/iuOr41ZdUHaOiqyR3iQ==} - cpu: [riscv64] - os: [linux] - libc: [glibc] - - '@rollup/rollup-linux-riscv64-gnu@4.50.1': - resolution: {integrity: sha512-S208ojx8a4ciIPrLgazF6AgdcNJzQE4+S9rsmOmDJkusvctii+ZvEuIC4v/xFqzbuP8yDjn73oBlNDgF6YGSXQ==} + '@rollup/rollup-linux-riscv64-gnu@4.52.5': + resolution: {integrity: sha512-sjQLr9BW7R/ZiXnQiWPkErNfLMkkWIoCz7YMn27HldKsADEKa5WYdobaa1hmN6slu9oWQbB6/jFpJ+P2IkVrmw==} cpu: [riscv64] os: [linux] libc: [glibc] - '@rollup/rollup-linux-riscv64-musl@4.46.2': - resolution: {integrity: sha512-t5B2loThlFEauloaQkZg9gxV05BYeITLvLkWOkRXogP4qHXLkWSbSHKM9S6H1schf/0YGP/qNKtiISlxvfmmZw==} - cpu: [riscv64] - os: [linux] - libc: [musl] - - '@rollup/rollup-linux-riscv64-musl@4.50.1': - resolution: {integrity: sha512-3Ag8Ls1ggqkGUvSZWYcdgFwriy2lWo+0QlYgEFra/5JGtAd6C5Hw59oojx1DeqcA2Wds2ayRgvJ4qxVTzCHgzg==} + '@rollup/rollup-linux-riscv64-musl@4.52.5': + resolution: {integrity: sha512-hq3jU/kGyjXWTvAh2awn8oHroCbrPm8JqM7RUpKjalIRWWXE01CQOf/tUNWNHjmbMHg/hmNCwc/Pz3k1T/j/Lg==} cpu: [riscv64] os: [linux] libc: [musl] - '@rollup/rollup-linux-s390x-gnu@4.46.2': - resolution: {integrity: sha512-YKjekwTEKgbB7n17gmODSmJVUIvj8CX7q5442/CK80L8nqOUbMtf8b01QkG3jOqyr1rotrAnW6B/qiHwfcuWQA==} - cpu: [s390x] - os: [linux] - libc: [glibc] - - '@rollup/rollup-linux-s390x-gnu@4.50.1': - resolution: {integrity: sha512-t9YrKfaxCYe7l7ldFERE1BRg/4TATxIg+YieHQ966jwvo7ddHJxPj9cNFWLAzhkVsbBvNA4qTbPVNsZKBO4NSg==} + '@rollup/rollup-linux-s390x-gnu@4.52.5': + resolution: {integrity: sha512-gn8kHOrku8D4NGHMK1Y7NA7INQTRdVOntt1OCYypZPRt6skGbddska44K8iocdpxHTMMNui5oH4elPH4QOLrFQ==} cpu: [s390x] os: [linux] libc: [glibc] - '@rollup/rollup-linux-x64-gnu@4.46.2': - resolution: {integrity: sha512-Jj5a9RUoe5ra+MEyERkDKLwTXVu6s3aACP51nkfnK9wJTraCC8IMe3snOfALkrjTYd2G1ViE1hICj0fZ7ALBPA==} - cpu: [x64] - os: [linux] - libc: [glibc] - - '@rollup/rollup-linux-x64-gnu@4.50.1': - resolution: {integrity: sha512-MCgtFB2+SVNuQmmjHf+wfI4CMxy3Tk8XjA5Z//A0AKD7QXUYFMQcns91K6dEHBvZPCnhJSyDWLApk40Iq/H3tA==} + '@rollup/rollup-linux-x64-gnu@4.52.5': + resolution: {integrity: sha512-hXGLYpdhiNElzN770+H2nlx+jRog8TyynpTVzdlc6bndktjKWyZyiCsuDAlpd+j+W+WNqfcyAWz9HxxIGfZm1Q==} cpu: [x64] os: [linux] libc: [glibc] - '@rollup/rollup-linux-x64-musl@4.46.2': - resolution: {integrity: sha512-7kX69DIrBeD7yNp4A5b81izs8BqoZkCIaxQaOpumcJ1S/kmqNFjPhDu1LHeVXv0SexfHQv5cqHsxLOjETuqDuA==} - cpu: [x64] - os: [linux] - libc: [musl] - - '@rollup/rollup-linux-x64-musl@4.50.1': - resolution: {integrity: sha512-nEvqG+0jeRmqaUMuwzlfMKwcIVffy/9KGbAGyoa26iu6eSngAYQ512bMXuqqPrlTyfqdlB9FVINs93j534UJrg==} + '@rollup/rollup-linux-x64-musl@4.52.5': + resolution: {integrity: sha512-arCGIcuNKjBoKAXD+y7XomR9gY6Mw7HnFBv5Rw7wQRvwYLR7gBAgV7Mb2QTyjXfTveBNFAtPt46/36vV9STLNg==} cpu: [x64] os: [linux] libc: [musl] - '@rollup/rollup-openharmony-arm64@4.50.1': - resolution: {integrity: sha512-RDsLm+phmT3MJd9SNxA9MNuEAO/J2fhW8GXk62G/B4G7sLVumNFbRwDL6v5NrESb48k+QMqdGbHgEtfU0LCpbA==} + '@rollup/rollup-openharmony-arm64@4.52.5': + resolution: {integrity: sha512-QoFqB6+/9Rly/RiPjaomPLmR/13cgkIGfA40LHly9zcH1S0bN2HVFYk3a1eAyHQyjs3ZJYlXvIGtcCs5tko9Cw==} cpu: [arm64] os: [openharmony] - '@rollup/rollup-win32-arm64-msvc@4.46.2': - resolution: {integrity: sha512-wiJWMIpeaak/jsbaq2HMh/rzZxHVW1rU6coyeNNpMwk5isiPjSTx0a4YLSlYDwBH/WBvLz+EtsNqQScZTLJy3g==} - cpu: [arm64] - os: [win32] - - '@rollup/rollup-win32-arm64-msvc@4.50.1': - resolution: {integrity: sha512-hpZB/TImk2FlAFAIsoElM3tLzq57uxnGYwplg6WDyAxbYczSi8O2eQ+H2Lx74504rwKtZ3N2g4bCUkiamzS6TQ==} + '@rollup/rollup-win32-arm64-msvc@4.52.5': + resolution: {integrity: sha512-w0cDWVR6MlTstla1cIfOGyl8+qb93FlAVutcor14Gf5Md5ap5ySfQ7R9S/NjNaMLSFdUnKGEasmVnu3lCMqB7w==} cpu: [arm64] os: [win32] - '@rollup/rollup-win32-ia32-msvc@4.46.2': - resolution: {integrity: sha512-gBgaUDESVzMgWZhcyjfs9QFK16D8K6QZpwAaVNJxYDLHWayOta4ZMjGm/vsAEy3hvlS2GosVFlBlP9/Wb85DqQ==} + '@rollup/rollup-win32-ia32-msvc@4.52.5': + resolution: {integrity: sha512-Aufdpzp7DpOTULJCuvzqcItSGDH73pF3ko/f+ckJhxQyHtp67rHw3HMNxoIdDMUITJESNE6a8uh4Lo4SLouOUg==} cpu: [ia32] os: [win32] - '@rollup/rollup-win32-ia32-msvc@4.50.1': - resolution: {integrity: sha512-SXjv8JlbzKM0fTJidX4eVsH+Wmnp0/WcD8gJxIZyR6Gay5Qcsmdbi9zVtnbkGPG8v2vMR1AD06lGWy5FLMcG7A==} - cpu: [ia32] - os: [win32] - - '@rollup/rollup-win32-x64-msvc@4.46.2': - resolution: {integrity: sha512-CvUo2ixeIQGtF6WvuB87XWqPQkoFAFqW+HUo/WzHwuHDvIwZCtjdWXoYCcr06iKGydiqTclC4jU/TNObC/xKZg==} + '@rollup/rollup-win32-x64-gnu@4.52.5': + resolution: {integrity: sha512-UGBUGPFp1vkj6p8wCRraqNhqwX/4kNQPS57BCFc8wYh0g94iVIW33wJtQAx3G7vrjjNtRaxiMUylM0ktp/TRSQ==} cpu: [x64] os: [win32] - '@rollup/rollup-win32-x64-msvc@4.50.1': - resolution: {integrity: sha512-StxAO/8ts62KZVRAm4JZYq9+NqNsV7RvimNK+YM7ry//zebEH6meuugqW/P5OFUCjyQgui+9fUxT6d5NShvMvA==} + '@rollup/rollup-win32-x64-msvc@4.52.5': + resolution: {integrity: sha512-TAcgQh2sSkykPRWLrdyy2AiceMckNf5loITqXxFI5VuQjS5tSuw3WlwdN8qv8vzjLAUTvYaH/mVjSFpbkFbpTg==} cpu: [x64] os: [win32] + '@rushstack/node-core-library@5.17.1': + resolution: {integrity: sha512-Mtcsa0aRJgYJOpeTe4qElLTRBlijNohdliq/xOhqce5rlzMIfLr73j9wUuj6GYPZPbG0S+is/RL2l0m/vnL55A==} + peerDependencies: + '@types/node': '*' + peerDependenciesMeta: + '@types/node': + optional: true + + '@rushstack/problem-matcher@0.1.1': + resolution: {integrity: sha512-Fm5XtS7+G8HLcJHCWpES5VmeMyjAKaWeyZU5qPzZC+22mPlJzAsOxymHiWIfuirtPckX3aptWws+K2d0BzniJA==} + peerDependencies: + '@types/node': '*' + peerDependenciesMeta: + '@types/node': + optional: true + + '@rushstack/rig-package@0.6.0': + resolution: {integrity: sha512-ZQmfzsLE2+Y91GF15c65L/slMRVhF6Hycq04D4TwtdGaUAbIXXg9c5pKA5KFU7M4QMaihoobp9JJYpYcaY3zOw==} + + '@rushstack/terminal@0.19.2': + resolution: {integrity: sha512-SJLC+6oUrJ0OOpuuwXxhktCTE3jeYVIwtvREdNhbcnVQrYGaDJpAoBgNVfw+VH0pTPpFLBqoPHsRRz7mj7WlbA==} + peerDependencies: + '@types/node': '*' + peerDependenciesMeta: + '@types/node': + optional: true + + '@rushstack/ts-command-line@5.1.2': + resolution: {integrity: sha512-jn0EnSefYrkZDrBGd6KGuecL84LI06DgzL4hVQ46AUijNBt2nRU/ST4HhrfII/w91siCd1J/Okvxq/BS75Me/A==} + '@serialport/binding-mock@10.2.2': resolution: {integrity: sha512-HAFzGhk9OuFMpuor7aT5G1ChPgn5qSsklTFOTUX72Rl6p0xwcSVsRtG/xaGp6bxpN7fI9D/S8THLBWbBgS6ldw==} engines: {node: '>=12.0.0'} @@ -2398,36 +2460,69 @@ packages: '@tailwindcss/node@4.1.14': resolution: {integrity: sha512-hpz+8vFk3Ic2xssIA3e01R6jkmsAhvkQdXlEbRTk6S10xDAtiQiM3FyvZVGsucefq764euO/b8WUW9ysLdThHw==} + '@tailwindcss/node@4.1.15': + resolution: {integrity: sha512-HF4+7QxATZWY3Jr8OlZrBSXmwT3Watj0OogeDvdUY/ByXJHQ+LBtqA2brDb3sBxYslIFx6UP94BJ4X6a4L9Bmw==} + '@tailwindcss/oxide-android-arm64@4.1.14': resolution: {integrity: sha512-a94ifZrGwMvbdeAxWoSuGcIl6/DOP5cdxagid7xJv6bwFp3oebp7y2ImYsnZBMTwjn5Ev5xESvS3FFYUGgPODQ==} engines: {node: '>= 10'} cpu: [arm64] os: [android] + '@tailwindcss/oxide-android-arm64@4.1.15': + resolution: {integrity: sha512-TkUkUgAw8At4cBjCeVCRMc/guVLKOU1D+sBPrHt5uVcGhlbVKxrCaCW9OKUIBv1oWkjh4GbunD/u/Mf0ql6kEA==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [android] + '@tailwindcss/oxide-darwin-arm64@4.1.14': resolution: {integrity: sha512-HkFP/CqfSh09xCnrPJA7jud7hij5ahKyWomrC3oiO2U9i0UjP17o9pJbxUN0IJ471GTQQmzwhp0DEcpbp4MZTA==} engines: {node: '>= 10'} cpu: [arm64] os: [darwin] + '@tailwindcss/oxide-darwin-arm64@4.1.15': + resolution: {integrity: sha512-xt5XEJpn2piMSfvd1UFN6jrWXyaKCwikP4Pidcf+yfHTSzSpYhG3dcMktjNkQO3JiLCp+0bG0HoWGvz97K162w==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [darwin] + '@tailwindcss/oxide-darwin-x64@4.1.14': resolution: {integrity: sha512-eVNaWmCgdLf5iv6Qd3s7JI5SEFBFRtfm6W0mphJYXgvnDEAZ5sZzqmI06bK6xo0IErDHdTA5/t7d4eTfWbWOFw==} engines: {node: '>= 10'} cpu: [x64] os: [darwin] + '@tailwindcss/oxide-darwin-x64@4.1.15': + resolution: {integrity: sha512-TnWaxP6Bx2CojZEXAV2M01Yl13nYPpp0EtGpUrY+LMciKfIXiLL2r/SiSRpagE5Fp2gX+rflp/Os1VJDAyqymg==} + engines: {node: '>= 10'} + cpu: [x64] + os: [darwin] + '@tailwindcss/oxide-freebsd-x64@4.1.14': resolution: {integrity: sha512-QWLoRXNikEuqtNb0dhQN6wsSVVjX6dmUFzuuiL09ZeXju25dsei2uIPl71y2Ic6QbNBsB4scwBoFnlBfabHkEw==} engines: {node: '>= 10'} cpu: [x64] os: [freebsd] + '@tailwindcss/oxide-freebsd-x64@4.1.15': + resolution: {integrity: sha512-quISQDWqiB6Cqhjc3iWptXVZHNVENsWoI77L1qgGEHNIdLDLFnw3/AfY7DidAiiCIkGX/MjIdB3bbBZR/G2aJg==} + engines: {node: '>= 10'} + cpu: [x64] + os: [freebsd] + '@tailwindcss/oxide-linux-arm-gnueabihf@4.1.14': resolution: {integrity: sha512-VB4gjQni9+F0VCASU+L8zSIyjrLLsy03sjcR3bM0V2g4SNamo0FakZFKyUQ96ZVwGK4CaJsc9zd/obQy74o0Fw==} engines: {node: '>= 10'} cpu: [arm] os: [linux] + '@tailwindcss/oxide-linux-arm-gnueabihf@4.1.15': + resolution: {integrity: sha512-ObG76+vPlab65xzVUQbExmDU9FIeYLQ5k2LrQdR2Ud6hboR+ZobXpDoKEYXf/uOezOfIYmy2Ta3w0ejkTg9yxg==} + engines: {node: '>= 10'} + cpu: [arm] + os: [linux] + '@tailwindcss/oxide-linux-arm64-gnu@4.1.14': resolution: {integrity: sha512-qaEy0dIZ6d9vyLnmeg24yzA8XuEAD9WjpM5nIM1sUgQ/Zv7cVkharPDQcmm/t/TvXoKo/0knI3me3AGfdx6w1w==} engines: {node: '>= 10'} @@ -2435,6 +2530,13 @@ packages: os: [linux] libc: [glibc] + '@tailwindcss/oxide-linux-arm64-gnu@4.1.15': + resolution: {integrity: sha512-4WbBacRmk43pkb8/xts3wnOZMDKsPFyEH/oisCm2q3aLZND25ufvJKcDUpAu0cS+CBOL05dYa8D4U5OWECuH/Q==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + libc: [glibc] + '@tailwindcss/oxide-linux-arm64-musl@4.1.14': resolution: {integrity: sha512-ISZjT44s59O8xKsPEIesiIydMG/sCXoMBCqsphDm/WcbnuWLxxb+GcvSIIA5NjUw6F8Tex7s5/LM2yDy8RqYBQ==} engines: {node: '>= 10'} @@ -2442,6 +2544,13 @@ packages: os: [linux] libc: [musl] + '@tailwindcss/oxide-linux-arm64-musl@4.1.15': + resolution: {integrity: sha512-AbvmEiteEj1nf42nE8skdHv73NoR+EwXVSgPY6l39X12Ex8pzOwwfi3Kc8GAmjsnsaDEbk+aj9NyL3UeyHcTLg==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + libc: [musl] + '@tailwindcss/oxide-linux-x64-gnu@4.1.14': resolution: {integrity: sha512-02c6JhLPJj10L2caH4U0zF8Hji4dOeahmuMl23stk0MU1wfd1OraE7rOloidSF8W5JTHkFdVo/O7uRUJJnUAJg==} engines: {node: '>= 10'} @@ -2449,6 +2558,13 @@ packages: os: [linux] libc: [glibc] + '@tailwindcss/oxide-linux-x64-gnu@4.1.15': + resolution: {integrity: sha512-+rzMVlvVgrXtFiS+ES78yWgKqpThgV19ISKD58Ck+YO5pO5KjyxLt7AWKsWMbY0R9yBDC82w6QVGz837AKQcHg==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + libc: [glibc] + '@tailwindcss/oxide-linux-x64-musl@4.1.14': resolution: {integrity: sha512-TNGeLiN1XS66kQhxHG/7wMeQDOoL0S33x9BgmydbrWAb9Qw0KYdd8o1ifx4HOGDWhVmJ+Ul+JQ7lyknQFilO3Q==} engines: {node: '>= 10'} @@ -2456,6 +2572,13 @@ packages: os: [linux] libc: [musl] + '@tailwindcss/oxide-linux-x64-musl@4.1.15': + resolution: {integrity: sha512-fPdEy7a8eQN9qOIK3Em9D3TO1z41JScJn8yxl/76mp4sAXFDfV4YXxsiptJcOwy6bGR+70ZSwFIZhTXzQeqwQg==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + libc: [musl] + '@tailwindcss/oxide-wasm32-wasi@4.1.14': resolution: {integrity: sha512-uZYAsaW/jS/IYkd6EWPJKW/NlPNSkWkBlaeVBi/WsFQNP05/bzkebUL8FH1pdsqx4f2fH/bWFcUABOM9nfiJkQ==} engines: {node: '>=14.0.0'} @@ -2468,22 +2591,53 @@ packages: - '@emnapi/wasi-threads' - tslib + '@tailwindcss/oxide-wasm32-wasi@4.1.15': + resolution: {integrity: sha512-sJ4yd6iXXdlgIMfIBXuVGp/NvmviEoMVWMOAGxtxhzLPp9LOj5k0pMEMZdjeMCl4C6Up+RM8T3Zgk+BMQ0bGcQ==} + engines: {node: '>=14.0.0'} + cpu: [wasm32] + bundledDependencies: + - '@napi-rs/wasm-runtime' + - '@emnapi/core' + - '@emnapi/runtime' + - '@tybys/wasm-util' + - '@emnapi/wasi-threads' + - tslib + '@tailwindcss/oxide-win32-arm64-msvc@4.1.14': resolution: {integrity: sha512-Az0RnnkcvRqsuoLH2Z4n3JfAef0wElgzHD5Aky/e+0tBUxUhIeIqFBTMNQvmMRSP15fWwmvjBxZ3Q8RhsDnxAA==} engines: {node: '>= 10'} cpu: [arm64] os: [win32] + '@tailwindcss/oxide-win32-arm64-msvc@4.1.15': + resolution: {integrity: sha512-sJGE5faXnNQ1iXeqmRin7Ds/ru2fgCiaQZQQz3ZGIDtvbkeV85rAZ0QJFMDg0FrqsffZG96H1U9AQlNBRLsHVg==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [win32] + '@tailwindcss/oxide-win32-x64-msvc@4.1.14': resolution: {integrity: sha512-ttblVGHgf68kEE4om1n/n44I0yGPkCPbLsqzjvybhpwa6mKKtgFfAzy6btc3HRmuW7nHe0OOrSeNP9sQmmH9XA==} engines: {node: '>= 10'} cpu: [x64] os: [win32] + '@tailwindcss/oxide-win32-x64-msvc@4.1.15': + resolution: {integrity: sha512-NLeHE7jUV6HcFKS504bpOohyi01zPXi2PXmjFfkzTph8xRxDdxkRsXm/xDO5uV5K3brrE1cCwbUYmFUSHR3u1w==} + engines: {node: '>= 10'} + cpu: [x64] + os: [win32] + '@tailwindcss/oxide@4.1.14': resolution: {integrity: sha512-23yx+VUbBwCg2x5XWdB8+1lkPajzLmALEfMb51zZUBYaYVPDQvBSD/WYDqiVyBIo2BZFa3yw1Rpy3G2Jp+K0dw==} engines: {node: '>= 10'} + '@tailwindcss/oxide@4.1.15': + resolution: {integrity: sha512-krhX+UOOgnsUuks2SR7hFafXmLQrKxB4YyRTERuCE59JlYL+FawgaAlSkOYmDRJdf1Q+IFNDMl9iRnBW7QBDfQ==} + engines: {node: '>= 10'} + + '@tailwindcss/postcss@4.1.15': + resolution: {integrity: sha512-IZh8IT76KujRz6d15wZw4eoeViT4TqmzVWNNfpuNCTKiaZUwgr5vtPqO4HjuYDyx3MgGR5qgPt1HMzTeLJyA3g==} + '@tailwindcss/vite@4.1.14': resolution: {integrity: sha512-BoFUoU0XqgCUS1UXWhmDJroKKhNXeDzD7/XwabjkDIAbMnc4ULn5e2FuEuBbhZ6ENZoSYzKlzvZ44Yr6EUDUSA==} peerDependencies: @@ -2959,6 +3113,9 @@ packages: '@tybys/wasm-util@0.10.1': resolution: {integrity: sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==} + '@types/argparse@1.0.38': + resolution: {integrity: sha512-ebDJ9b0e702Yr7pWgB0jzm+CX4Srzz8RcXtLJDJB+BSccqMa36uyH/zUsSYao5+BD1ytv3k3rPYCq4mAE1hsXA==} + '@types/aria-query@5.0.4': resolution: {integrity: sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==} @@ -3010,8 +3167,8 @@ packages: '@types/js-cookie@3.0.6': resolution: {integrity: sha512-wkw9yd1kEXOPnvEeEV1Go1MmxtBJL0RR79aOTAApecWFVu7w0NNXNqhcWgvw2YgZDYadliXkl14pa3WXw5jlCQ==} - '@types/node@20.19.21': - resolution: {integrity: sha512-CsGG2P3I5y48RPMfprQGfy4JPRZ6csfC3ltBZSRItG3ngggmNY/qs2uZKp4p9VbrpqNNSMzUZNFZKzgOGnd/VA==} + '@types/node@20.19.25': + resolution: {integrity: sha512-ZsJzA5thDQMSQO788d7IocwwQbI8B5OPzmqNvpf3NY/+MHDAS759Wo0gd2WQeXYt5AAAQjzcrTVC6SKCuYgoCQ==} '@types/node@24.3.1': resolution: {integrity: sha512-3vXmQDXy+woz+gnrTvuvNrPzekOi+Ds0ReMxw0LzBiK3a+1k0kQn9f2NWk+lgD4rJehFUmYy2gMhJ2ZI+7YP9g==} @@ -3019,11 +3176,22 @@ packages: '@types/node@24.7.0': resolution: {integrity: sha512-IbKooQVqUBrlzWTi79E8Fw78l8k1RNtlDDNWsFZs7XonuQSJ8oNYfEeclhprUldXISRMLzBpILuKgPlIxm+/Yw==} - '@types/react-dom@19.2.0': + '@types/prop-types@15.7.15': + resolution: {integrity: sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==} + + '@types/react-dom@18.3.7': + resolution: {integrity: sha512-MEe3UeoENYVFXzoXEWsvcpg6ZvlrFNlOQ7EOsvhI3CfAXwzPfO8Qwuxd40nepsYKqyyVQnTdEfv68q91yLcKrQ==} + peerDependencies: + '@types/react': ^18.0.0 + + '@types/react-dom@19.2.0': resolution: {integrity: sha512-brtBs0MnE9SMx7px208g39lRmC5uHZs96caOJfTjFcYSLHNamvaSMfJNagChVNkup2SdtOxKX1FDBkRSJe1ZAg==} peerDependencies: '@types/react': ^19.2.0 + '@types/react@18.3.26': + resolution: {integrity: sha512-RFA/bURkcKzx/X9oumPG9Vp3D3JUgus/d0b67KB0t5S/raciymilkOa66olh78MUI92QLbEJevO7rvqU/kjwKA==} + '@types/react@19.2.1': resolution: {integrity: sha512-1U5NQWh/GylZQ50ZMnnPjkYHEaGhg6t5i/KI0LDDh3t4E3h3T3vzm+GLY2BRzMfIjSBwzm6tginoZl5z0O/qsA==} @@ -3076,6 +3244,18 @@ packages: maplibre-gl: optional: true + '@vitejs/plugin-basic-ssl@2.1.0': + resolution: {integrity: sha512-dOxxrhgyDIEUADhb/8OlV9JIqYLgos03YorAueTIeOUskLJSEsfwCByjbu98ctXitUN3znXKp0bYD/WHSudCeA==} + engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} + peerDependencies: + vite: ^6.0.0 || ^7.0.0 + + '@vitejs/plugin-react@4.7.0': + resolution: {integrity: sha512-gUu9hwfWvvEDBBmgtAowQCojwZmJ5mcLn3aufeCsitijs3+f2NsrPtlAWIR6OPiqljl96GVCUbLe0HyqIpVaoA==} + engines: {node: ^14.18.0 || >=16.0.0} + peerDependencies: + vite: ^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 + '@vitejs/plugin-react@5.0.4': resolution: {integrity: sha512-La0KD0vGkVkSk6K+piWDKRUyg8Rl5iAIKRMH0vMJI0Eg47bq1eOxmoObAaQG37WMW9MSyk7Cs8EIWwJC1PtzKA==} engines: {node: ^20.19.0 || >=22.12.0} @@ -3111,14 +3291,68 @@ packages: '@vitest/utils@3.2.4': resolution: {integrity: sha512-fB2V0JFrQSMsCo9HiSq3Ezpdv4iYaXRG1Sx8edX3MwxfyNn83mKiGzOcH+Fkxt4MHxr3y42fQi1oeAInqgX2QA==} + '@volar/language-core@2.4.23': + resolution: {integrity: sha512-hEEd5ET/oSmBC6pi1j6NaNYRWoAiDhINbT8rmwtINugR39loROSlufGdYMF9TaKGfz+ViGs1Idi3mAhnuPcoGQ==} + + '@volar/source-map@2.4.23': + resolution: {integrity: sha512-Z1Uc8IB57Lm6k7q6KIDu/p+JWtf3xsXJqAX/5r18hYOTpJyBn0KXUR8oTJ4WFYOcDzWC9n3IflGgHowx6U6z9Q==} + + '@volar/typescript@2.4.23': + resolution: {integrity: sha512-lAB5zJghWxVPqfcStmAP1ZqQacMpe90UrP5RJ3arDyrhy4aCUQqmxPPLB2PWDKugvylmO41ljK7vZ+t6INMTag==} + + '@vue/compiler-core@3.5.22': + resolution: {integrity: sha512-jQ0pFPmZwTEiRNSb+i9Ow/I/cHv2tXYqsnHKKyCQ08irI2kdF5qmYedmF8si8mA7zepUFmJ2hqzS8CQmNOWOkQ==} + + '@vue/compiler-dom@3.5.22': + resolution: {integrity: sha512-W8RknzUM1BLkypvdz10OVsGxnMAuSIZs9Wdx1vzA3mL5fNMN15rhrSCLiTm6blWeACwUwizzPVqGJgOGBEN/hA==} + + '@vue/compiler-vue2@2.7.16': + resolution: {integrity: sha512-qYC3Psj9S/mfu9uVi5WvNZIzq+xnXMhOwbTFKKDD7b1lhpnn71jXSFdTQ+WsIEk0ONCd7VV2IMm7ONl6tbQ86A==} + + '@vue/language-core@2.2.0': + resolution: {integrity: sha512-O1ZZFaaBGkKbsRfnVH1ifOK1/1BUkyK+3SQsfnh6PmMmD4qJcTU8godCeA96jjDRTL6zgnK7YzCHfaUlH2r0Mw==} + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + + '@vue/shared@3.5.22': + resolution: {integrity: sha512-F4yc6palwq3TT0u+FYf0Ns4Tfl9GRFURDN2gWG7L1ecIaS/4fCIuFOjMTnCyjsu/OK6vaDKLCrGAa+KvvH+h4w==} + acorn@8.15.0: resolution: {integrity: sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==} engines: {node: '>=0.4.0'} hasBin: true + ajv-draft-04@1.0.0: + resolution: {integrity: sha512-mv00Te6nmYbRp5DCwclxtt7yV/joXJPGS7nM+97GdxvuttCOfgI3K4U25zboyeX0O+myI8ERluxQe5wljMmVIw==} + peerDependencies: + ajv: ^8.5.0 + peerDependenciesMeta: + ajv: + optional: true + + ajv-formats@3.0.1: + resolution: {integrity: sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==} + peerDependencies: + ajv: ^8.0.0 + peerDependenciesMeta: + ajv: + optional: true + + ajv@8.12.0: + resolution: {integrity: sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==} + + ajv@8.13.0: + resolution: {integrity: sha512-PRA911Blj99jR5RMeTunVbNXMF6Lp4vZXnk5GQjcnUWUTsrXtekg/pnmFFI2u/I36Y/2bITGS30GZCXei6uNkA==} + ajv@8.17.1: resolution: {integrity: sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==} + alien-signals@0.4.14: + resolution: {integrity: sha512-itUAVzhczTmP2U5yX67xVpsbbOiquusbWVyA9N+sy6+r6YVbFkahXvNCeEPWEOMhwDYwbVbGHFkVL03N9I5g+Q==} + ansi-regex@5.0.1: resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} engines: {node: '>=8'} @@ -3151,6 +3385,9 @@ packages: resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} engines: {node: '>= 8'} + argparse@1.0.10: + resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==} + aria-hidden@1.2.6: resolution: {integrity: sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA==} engines: {node: '>=10'} @@ -3236,8 +3473,8 @@ packages: base64-js@1.5.1: resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} - baseline-browser-mapping@2.8.16: - resolution: {integrity: sha512-OMu3BGQ4E7P1ErFsIPpbJh0qvDudM/UuJeHgkAvfWe+0HFJCXh+t/l8L6fVLR55RI/UbKrVLnAXZSVwd9ysWYw==} + baseline-browser-mapping@2.8.31: + resolution: {integrity: sha512-a28v2eWrrRWPpJSzxc+mKwm0ZtVx/G8SepdQZDArnXYU/XS+IF6mp8aB/4E+hH1tyGCoDo3KlUCdlSxGDsRkAw==} hasBin: true bignumber.js@9.3.1: @@ -3273,8 +3510,8 @@ packages: engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true - browserslist@4.26.3: - resolution: {integrity: sha512-lAUU+02RFBuCKQPj/P6NgjlbCnLBMp4UtgTx7vNHd3XSIJF87s9a5rA3aH2yw3GS9DqZAUbOtZdCCiZeVRqt0w==} + browserslist@4.28.0: + resolution: {integrity: sha512-tbydkR/CxfMwelN0vwdP/pLkDwyAASZ+VfWm4EOwlB6SWhx1sYnWLqo8N5j0rAzPfzfRaxt0mM/4wPU/Su84RQ==} engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true @@ -3312,8 +3549,8 @@ packages: caniuse-lite@1.0.30001741: resolution: {integrity: sha512-QGUGitqsc8ARjLdgAfxETDhRbJ0REsP6O3I96TAth/mVjh2cYzN2u+3AzPP3aVSm2FehEItaJw1xd+IGBXWeSw==} - caniuse-lite@1.0.30001750: - resolution: {integrity: sha512-cuom0g5sdX6rw00qOoLNSFCJ9/mYIsuSOA+yzpDw8eopiFqcVwQvZHqov0vmEighRxX++cfC0Vg1G+1Iy/mSpQ==} + caniuse-lite@1.0.30001757: + resolution: {integrity: sha512-r0nnL/I28Zi/yjk1el6ilj27tKcdjLsNqAOZr0yVjWPrSQyHgKI2INaEWw21bAQSv2LXRt1XuCS/GomNpWOxsQ==} chai@5.2.1: resolution: {integrity: sha512-5nFxhUrX0PqtyogoYOA8IPswy5sZFTOsBFl/9bNsmDLgsxYTzSZQJDPppDnZPTQbzSEm0hqGjWPzRemQCYbD6A==} @@ -3381,12 +3618,21 @@ packages: resolution: {integrity: sha512-gk/Z852D2Wtb//0I+kRFNKKE9dIIVirjoqPoA1wJU+XePVXZfGeBpk45+A1rKO4Q43prqWBNY/MiIeRLbPWUaA==} engines: {node: '>=4.0.0'} + compare-versions@6.1.1: + resolution: {integrity: sha512-4hm4VPpIecmlg59CHXnRDnqGplJFrbLG4aFEl5vl6cK1u76ws3LLvX7ikFnTDl5vo39sjWD6AaDPYodJp/NNHg==} + concat-map@0.0.1: resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} concaveman@1.2.1: resolution: {integrity: sha512-PwZYKaM/ckQSa8peP5JpVr7IMJ4Nn/MHIaWUjP4be+KoZ7Botgs8seAZGpmaOM+UZXawcdYRao/px9ycrCihHw==} + confbox@0.1.8: + resolution: {integrity: sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==} + + confbox@0.2.2: + resolution: {integrity: sha512-1NB+BKqhtNipMsov4xI/NnhCKp9XG9NamYp5PVm9klAT0fsrNPjaFICsCFhNhwZJKNh7zB/3q8qXz0E9oaMNtQ==} + connect-history-api-fallback@1.6.0: resolution: {integrity: sha512-e54B99q/OUoH64zYYRf3HBP5z24G38h5D3qXu23JGRoigpX5Ss4r9ZnDk3g0Z8uQC2x2lPaJ+UlWBc1ZWBWdLg==} engines: {node: '>=0.8'} @@ -3400,8 +3646,8 @@ packages: cookie-es@2.0.0: resolution: {integrity: sha512-RAj4E421UYRgqokKUmotqAwuplYw15qtdXfY+hGzgCJ/MBjCVZcSoHK/kH9kocfjRjcDME7IiDWR/1WX1TM2Pg==} - core-js-compat@3.46.0: - resolution: {integrity: sha512-p9hObIIEENxSV8xIu+V68JjSeARg6UVMG5mR+JEUguG3sI6MsiS1njz2jHmyJDvA+8jX/sytkBHup6kxhM9law==} + core-js-compat@3.47.0: + resolution: {integrity: sha512-IGfuznZ/n7Kp9+nypamBhvwdwLsW6KC8IOaURw2doAK5e98AG3acVLdh0woOnEqCfUtS+Vu882JE4k/DAm3ItQ==} core-util-is@1.0.3: resolution: {integrity: sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==} @@ -3464,6 +3710,9 @@ packages: resolution: {integrity: sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==} engines: {node: '>= 0.4'} + de-indent@1.0.2: + resolution: {integrity: sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg==} + debug@4.4.0: resolution: {integrity: sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==} engines: {node: '>=6.0'} @@ -3594,8 +3843,8 @@ packages: electron-to-chromium@1.5.217: resolution: {integrity: sha512-Pludfu5iBxp9XzNl0qq2G87hdD17ZV7h5T4n6rQXDi3nCyloBV3jreE9+8GC6g4X/5yxqVgXEURpcLtM0WS4jA==} - electron-to-chromium@1.5.234: - resolution: {integrity: sha512-RXfEp2x+VRYn8jbKfQlRImzoJU01kyDvVPBmG39eU2iuRVhuS6vQNocB8J0/8GrIMLnPzgz4eW6WiRnJkTuNWg==} + electron-to-chromium@1.5.260: + resolution: {integrity: sha512-ov8rBoOBhVawpzdre+Cmz4FB+y66Eqrk6Gwqd8NGxuhv99GQ8XqMAr351KEkOt7gukXWDg6gJWEMKgL2RLMPtA==} emoji-regex@8.0.0: resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} @@ -3617,6 +3866,10 @@ packages: entities@2.2.0: resolution: {integrity: sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==} + entities@4.5.0: + resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} + engines: {node: '>=0.12'} + es-abstract@1.24.0: resolution: {integrity: sha512-WSzPgsdLtTcQwm4CROfS5ju2Wa1QQcVeT37jFjYzdFz1r9ahadC8B8/a4qxJxM+09F18iumCdRmlr96ZYkQvEg==} engines: {node: '>= 0.4'} @@ -3644,8 +3897,8 @@ packages: resolution: {integrity: sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==} engines: {node: '>= 0.4'} - esbuild@0.25.8: - resolution: {integrity: sha512-vVC0USHGtMi8+R4Kz8rt6JhEWLxsv9Rnu/lGYbPR8u47B+DCBksq9JarW0zOO7bs37hyOK1l2/oqtbciutL5+Q==} + esbuild@0.25.11: + resolution: {integrity: sha512-KohQwyzrKTQmhXDW1PjCv3Tyspn9n5GcY2RTDqeORIdIJY8yKIF7sTSopFmn/wpMPW4rdPXI0UE5LJLuq3bx0Q==} engines: {node: '>=18'} hasBin: true @@ -3680,6 +3933,9 @@ packages: resolution: {integrity: sha512-JhFGDVJ7tmDJItKhYgJCGLOWjuK9vPxiXoUFLwLDc99NlmklilbiQJwoctZtt13+xMw91MCk/REan6MWHqDjyA==} engines: {node: '>=12.0.0'} + exsolve@1.0.7: + resolution: {integrity: sha512-VO5fQUzZtI6C+vx4w/4BWJpg3s/5l+6pRQEHzFRM8WFi4XffSP1Z+4qi7GbjWbvRQEbdIco5mIMq+zX4rPuLrw==} + extend-shallow@2.0.1: resolution: {integrity: sha512-zCnTtlxNoAiDc3gqY2aYAWFx7XWWiasuF2K8Me5WbN8otHKTUKBwjPtNpRs/rbUZm7KxWAaNj7P1a/p52GbVug==} engines: {node: '>=0.10.0'} @@ -3743,6 +3999,10 @@ packages: resolution: {integrity: sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==} engines: {node: '>=12'} + fs-extra@11.3.2: + resolution: {integrity: sha512-Xr9F6z6up6Ws+NjzMCZc6WXg2YFRlrLP9NQDO3VQrWrfiojdhS56TzueT88ze0uBdCTwEIhQ3ptnmKeWGFAe0A==} + engines: {node: '>=14.14'} + fs-extra@9.1.0: resolution: {integrity: sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==} engines: {node: '>=10'} @@ -3853,14 +4113,18 @@ packages: engines: {node: '>=20.11.0'} hasBin: true - happy-dom@20.0.0: - resolution: {integrity: sha512-GkWnwIFxVGCf2raNrxImLo397RdGhLapj5cT3R2PT7FwL62Ze1DROhzmYW7+J3p9105DYMVenEejEbnq5wA37w==} + happy-dom@20.0.2: + resolution: {integrity: sha512-pYOyu624+6HDbY+qkjILpQGnpvZOusItCk+rvF5/V+6NkcgTKnbOldpIy22tBnxoaLtlM9nXgoqAcW29/B7CIw==} engines: {node: '>=20.0.0'} has-bigints@1.1.0: resolution: {integrity: sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==} engines: {node: '>= 0.4'} + has-flag@4.0.0: + resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} + engines: {node: '>=8'} + has-property-descriptors@1.0.2: resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==} @@ -3918,6 +4182,10 @@ packages: immer@10.1.3: resolution: {integrity: sha512-tmjF/k8QDKydUlm3mZU+tjM6zeq9/fFpPqH9SzWmBnVVKsPBg/V66qsMwb3/Bo90cgUN+ghdVBess+hPsxUyRw==} + import-lazy@4.0.0: + resolution: {integrity: sha512-rKtvo6a868b5Hu3heneU+L4yEQ4jYKLtjpnPeUdK7h0yzXGmyBTypknlkCvHFBqfX9YlorEiMM6Dnq/5atfHkw==} + engines: {node: '>=8'} + indent-string@4.0.0: resolution: {integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==} engines: {node: '>=8'} @@ -4097,14 +4365,13 @@ packages: engines: {node: '>=10'} hasBin: true - jiti@2.5.1: - resolution: {integrity: sha512-twQoecYPiVA5K/h6SxtORw/Bs3ar+mLUtoPSc7iMXzQzK8d7eJ/R09wmTwAjiamETn1cXYPGfNnu7DMoHgu12w==} - hasBin: true - jiti@2.6.1: resolution: {integrity: sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==} hasBin: true + jju@1.4.0: + resolution: {integrity: sha512-8wb9Yw966OSxApiCt0K3yNJL8pnNeIv+OEq2YMidz4FKP6nonSRoOXc80iXY4JaN2FC11B9qsNmDsm+ZOfMROA==} + js-cookie@3.0.5: resolution: {integrity: sha512-cEiJEAEoIbWfCZYKWhVwFuvPX1gETRYPw6LlaTKoxD3s2AkXzkCjnp6h0V77ozyqj0jakteJ4YqDJT830+lVGw==} engines: {node: '>=14'} @@ -4154,34 +4421,67 @@ packages: kdbush@4.0.2: resolution: {integrity: sha512-WbCVYJ27Sz8zi9Q7Q0xHC+05iwkm3Znipc2XTlrnJbsHMYktW4hPhXUE8Ys1engBrvffoSCqbil1JQAa7clRpA==} + kolorist@1.8.0: + resolution: {integrity: sha512-Y+60/zizpJ3HRH8DCss+q95yr6145JXZo46OTpFvDZWLfRCE4qChOyk1b26nMaNpfHHgxagk9dXT5OP0Tfe+dQ==} + leven@3.1.0: resolution: {integrity: sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==} engines: {node: '>=6'} + lightningcss-android-arm64@1.30.2: + resolution: {integrity: sha512-BH9sEdOCahSgmkVhBLeU7Hc9DWeZ1Eb6wNS6Da8igvUwAe0sqROHddIlvU06q3WyXVEOYDZ6ykBZQnjTbmo4+A==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [android] + lightningcss-darwin-arm64@1.30.1: resolution: {integrity: sha512-c8JK7hyE65X1MHMN+Viq9n11RRC7hgin3HhYKhrMyaXflk5GVplZ60IxyoVtzILeKr+xAJwg6zK6sjTBJ0FKYQ==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [darwin] + lightningcss-darwin-arm64@1.30.2: + resolution: {integrity: sha512-ylTcDJBN3Hp21TdhRT5zBOIi73P6/W0qwvlFEk22fkdXchtNTOU4Qc37SkzV+EKYxLouZ6M4LG9NfZ1qkhhBWA==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [darwin] + lightningcss-darwin-x64@1.30.1: resolution: {integrity: sha512-k1EvjakfumAQoTfcXUcHQZhSpLlkAuEkdMBsI/ivWw9hL+7FtilQc0Cy3hrx0AAQrVtQAbMI7YjCgYgvn37PzA==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [darwin] + lightningcss-darwin-x64@1.30.2: + resolution: {integrity: sha512-oBZgKchomuDYxr7ilwLcyms6BCyLn0z8J0+ZZmfpjwg9fRVZIR5/GMXd7r9RH94iDhld3UmSjBM6nXWM2TfZTQ==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [darwin] + lightningcss-freebsd-x64@1.30.1: resolution: {integrity: sha512-kmW6UGCGg2PcyUE59K5r0kWfKPAVy4SltVeut+umLCFoJ53RdCUWxcRDzO1eTaxf/7Q2H7LTquFHPL5R+Gjyig==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [freebsd] + lightningcss-freebsd-x64@1.30.2: + resolution: {integrity: sha512-c2bH6xTrf4BDpK8MoGG4Bd6zAMZDAXS569UxCAGcA7IKbHNMlhGQ89eRmvpIUGfKWNVdbhSbkQaWhEoMGmGslA==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [freebsd] + lightningcss-linux-arm-gnueabihf@1.30.1: resolution: {integrity: sha512-MjxUShl1v8pit+6D/zSPq9S9dQ2NPFSQwGvxBCYaBYLPlCWuPh9/t1MRS8iUaR8i+a6w7aps+B4N0S1TYP/R+Q==} engines: {node: '>= 12.0.0'} cpu: [arm] os: [linux] + lightningcss-linux-arm-gnueabihf@1.30.2: + resolution: {integrity: sha512-eVdpxh4wYcm0PofJIZVuYuLiqBIakQ9uFZmipf6LF/HRj5Bgm0eb3qL/mr1smyXIS1twwOxNWndd8z0E374hiA==} + engines: {node: '>= 12.0.0'} + cpu: [arm] + os: [linux] + lightningcss-linux-arm64-gnu@1.30.1: resolution: {integrity: sha512-gB72maP8rmrKsnKYy8XUuXi/4OctJiuQjcuqWNlJQ6jZiWqtPvqFziskH3hnajfvKB27ynbVCucKSm2rkQp4Bw==} engines: {node: '>= 12.0.0'} @@ -4189,6 +4489,13 @@ packages: os: [linux] libc: [glibc] + lightningcss-linux-arm64-gnu@1.30.2: + resolution: {integrity: sha512-UK65WJAbwIJbiBFXpxrbTNArtfuznvxAJw4Q2ZGlU8kPeDIWEX1dg3rn2veBVUylA2Ezg89ktszWbaQnxD/e3A==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + libc: [glibc] + lightningcss-linux-arm64-musl@1.30.1: resolution: {integrity: sha512-jmUQVx4331m6LIX+0wUhBbmMX7TCfjF5FoOH6SD1CttzuYlGNVpA7QnrmLxrsub43ClTINfGSYyHe2HWeLl5CQ==} engines: {node: '>= 12.0.0'} @@ -4196,6 +4503,13 @@ packages: os: [linux] libc: [musl] + lightningcss-linux-arm64-musl@1.30.2: + resolution: {integrity: sha512-5Vh9dGeblpTxWHpOx8iauV02popZDsCYMPIgiuw97OJ5uaDsL86cnqSFs5LZkG3ghHoX5isLgWzMs+eD1YzrnA==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + libc: [musl] + lightningcss-linux-x64-gnu@1.30.1: resolution: {integrity: sha512-piWx3z4wN8J8z3+O5kO74+yr6ze/dKmPnI7vLqfSqI8bccaTGY5xiSGVIJBDd5K5BHlvVLpUB3S2YCfelyJ1bw==} engines: {node: '>= 12.0.0'} @@ -4203,6 +4517,13 @@ packages: os: [linux] libc: [glibc] + lightningcss-linux-x64-gnu@1.30.2: + resolution: {integrity: sha512-Cfd46gdmj1vQ+lR6VRTTadNHu6ALuw2pKR9lYq4FnhvgBc4zWY1EtZcAc6EffShbb1MFrIPfLDXD6Xprbnni4w==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + libc: [glibc] + lightningcss-linux-x64-musl@1.30.1: resolution: {integrity: sha512-rRomAK7eIkL+tHY0YPxbc5Dra2gXlI63HL+v1Pdi1a3sC+tJTcFrHX+E86sulgAXeI7rSzDYhPSeHHjqFhqfeQ==} engines: {node: '>= 12.0.0'} @@ -4210,22 +4531,49 @@ packages: os: [linux] libc: [musl] + lightningcss-linux-x64-musl@1.30.2: + resolution: {integrity: sha512-XJaLUUFXb6/QG2lGIW6aIk6jKdtjtcffUT0NKvIqhSBY3hh9Ch+1LCeH80dR9q9LBjG3ewbDjnumefsLsP6aiA==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + libc: [musl] + lightningcss-win32-arm64-msvc@1.30.1: resolution: {integrity: sha512-mSL4rqPi4iXq5YVqzSsJgMVFENoa4nGTT/GjO2c0Yl9OuQfPsIfncvLrEW6RbbB24WtZ3xP/2CCmI3tNkNV4oA==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [win32] + lightningcss-win32-arm64-msvc@1.30.2: + resolution: {integrity: sha512-FZn+vaj7zLv//D/192WFFVA0RgHawIcHqLX9xuWiQt7P0PtdFEVaxgF9rjM/IRYHQXNnk61/H/gb2Ei+kUQ4xQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [win32] + lightningcss-win32-x64-msvc@1.30.1: resolution: {integrity: sha512-PVqXh48wh4T53F/1CCu8PIPCxLzWyCnn/9T5W1Jpmdy5h9Cwd+0YQS6/LwhHXSafuc61/xg9Lv5OrCby6a++jg==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [win32] + lightningcss-win32-x64-msvc@1.30.2: + resolution: {integrity: sha512-5g1yc73p+iAkid5phb4oVFMB45417DkRevRbt/El/gKXJk4jid+vPFF/AXbxn05Aky8PapwzZrdJShv5C0avjw==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [win32] + lightningcss@1.30.1: resolution: {integrity: sha512-xi6IyHML+c9+Q3W0S4fCQJOym42pyurFiJUHEcEyHS0CeKzia4yZDEsLlqOFykxOdHpNy0NmvVO31vcSqAxJCg==} engines: {node: '>= 12.0.0'} + lightningcss@1.30.2: + resolution: {integrity: sha512-utfs7Pr5uJyyvDETitgsaqSyjCb2qNRAtuqUeWIAKztsOYdcACf2KtARYXg2pSvhkt+9NfoaNY7fxjl6nuMjIQ==} + engines: {node: '>= 12.0.0'} + + local-pkg@1.1.2: + resolution: {integrity: sha512-arhlxbFRmoQHl33a0Zkle/YWlmNwoyt6QNZEIJcqNbdrsix5Lvc4HyyI3EnwxTYlZYc32EbYrQ8SzEZ7dqgg9A==} + engines: {node: '>=14'} + lodash.debounce@4.0.8: resolution: {integrity: sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==} @@ -4248,6 +4596,10 @@ packages: lru-cache@5.1.1: resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} + lru-cache@6.0.0: + resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} + engines: {node: '>=10'} + lucide-react@0.545.0: resolution: {integrity: sha512-7r1/yUuflQDSt4f1bpn5ZAocyIxcTyVyBBChSVtBKn5M+392cPmI5YJMWOJKk/HUWGm5wg83chlAZtCcGbEZtw==} peerDependencies: @@ -4260,9 +4612,6 @@ packages: magic-string@0.25.9: resolution: {integrity: sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==} - magic-string@0.30.17: - resolution: {integrity: sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==} - magic-string@0.30.19: resolution: {integrity: sha512-2N21sPY9Ws53PZvsEpVtNuSW+ScYbQdp4b9qUaL+9QkHUrGFKo56Lg9Emg5s9V/qrtNBmiR01sYhUOwu3H+VOw==} @@ -4300,6 +4649,10 @@ packages: resolution: {integrity: sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==} engines: {node: '>=10'} + minimatch@9.0.5: + resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} + engines: {node: '>=16 || 14 >=14.17'} + minimist@1.2.8: resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} @@ -4311,9 +4664,19 @@ packages: resolution: {integrity: sha512-KZxYo1BUkWD2TVFLr0MQoM8vUUigWD3LlD83a/75BqC+4qE0Hb1Vo5v1FgcfaNXvfXzr+5EhQ6ing/CaBijTlw==} engines: {node: '>= 18'} + mlly@1.8.0: + resolution: {integrity: sha512-l8D9ODSRWLe2KHJSifWGwBqpTZXIXTeo8mlKjY+E2HAakaTeNpqAyBZ8GSqLzHgw4XmHmC8whvpjJNMbFZN7/g==} + + mri@1.2.0: + resolution: {integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==} + engines: {node: '>=4'} + ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + muggle-string@0.4.1: + resolution: {integrity: sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ==} + murmurhash-js@1.0.0: resolution: {integrity: sha512-TvmkNhkv8yct0SVBSy+o8wYzXjE4Zz3PCesbfs8HiCXXdcTuocApFv11UWlNFWKYsP2okqrhb7JNlSm9InBhIw==} @@ -4351,8 +4714,8 @@ packages: node-releases@2.0.20: resolution: {integrity: sha512-7gK6zSXEH6neM212JgfYFXe+GmZQM+fia5SsusuBIUgnPheLFBmIPhtFoAQRj8/7wASYQnbDlHPVwY0BefoFgA==} - node-releases@2.0.23: - resolution: {integrity: sha512-cCmFDMSm26S6tQSDpBCg/NR8NENrVPhAJSf+XbxBG4rPFaaonlEoE9wHQmun+cls499TQGSb7ZyPBRlzgKfpeg==} + node-releases@2.0.27: + resolution: {integrity: sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==} normalize-path@3.0.0: resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} @@ -4384,15 +4747,25 @@ packages: resolution: {integrity: sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==} engines: {node: '>= 0.4'} + p-map@7.0.3: + resolution: {integrity: sha512-VkndIv2fIB99swvQoA65bm+fsmt6UNdGeIB0oxBs+WhAhdh08QA04JXpI7rbB9r08/nkbysKoya9rtDERYOYMA==} + engines: {node: '>=18'} + package-json-from-dist@1.0.1: resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==} + package-manager-detector@1.5.0: + resolution: {integrity: sha512-uBj69dVlYe/+wxj8JOpr97XfsxH/eumMt6HqjNTmJDf/6NO9s+0uxeOneIz3AsPt2m6y9PqzDzd3ATcU17MNfw==} + param-case@3.0.4: resolution: {integrity: sha512-RXlj7zCYokReqWpOPH9oYivUzLYZ5vAPIfEmCTNViosC78F8F0H9y7T7gG2M39ymgutxF5gcFEsyZQSph9Bp3A==} pascal-case@3.1.2: resolution: {integrity: sha512-uWlGT3YSnK9x3BQJaOdcZwrnV6hPpd8jFH1/ucpiLRPh/2zCVJKS19E4GvYHvaCcACn3foXZ0cLB9Wrx1KGe5g==} + path-browserify@1.0.1: + resolution: {integrity: sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==} + path-is-absolute@1.0.1: resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} engines: {node: '>=0.10.0'} @@ -4436,6 +4809,12 @@ packages: resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==} engines: {node: '>=12'} + pkg-types@1.3.1: + resolution: {integrity: sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==} + + pkg-types@2.3.0: + resolution: {integrity: sha512-SIqCzDRg0s9npO5XQ3tNZioRY1uK06lA41ynBC1YmFTmnY6FjUjVt6s4LoADmwoig1qqD0oK8h1p/8mlMx8Oig==} + point-in-polygon-hao@1.2.4: resolution: {integrity: sha512-x2pcvXeqhRHlNRdhLs/tgFapAbSSe86wa/eqmj1G6pWftbEs5aVRJhRGM6FYSUERKu0PjekJzMq0gsI2XyiclQ==} @@ -4485,6 +4864,11 @@ packages: protocol-buffers-schema@3.6.0: resolution: {integrity: sha512-TdDRD+/QNdrCGCE7v8340QyuXd4kIWIgapsE2+n/SaGiSSbomYl4TjHlvIoCWRpE7wFt02EpB35VVA2ImcBVqw==} + publint@0.3.15: + resolution: {integrity: sha512-xPbRAPW+vqdiaKy5sVVY0uFAu3LaviaPO3pZ9FaRx59l9+U/RKR1OEbLhkug87cwiVKxPXyB4txsv5cad67u+A==} + engines: {node: '>=18'} + hasBin: true + punycode@2.3.1: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} @@ -4675,8 +5059,8 @@ packages: resolve-protobuf-schema@2.1.0: resolution: {integrity: sha512-kI5ffTiZWmJaS/huM8wZfEMer1eRd7oJQhDuxeCLe3t7N7mX3z94CN0xPxBQxFYQTSNz9T0i+v6inKqSdK8xrQ==} - resolve@1.22.10: - resolution: {integrity: sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==} + resolve@1.22.11: + resolution: {integrity: sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==} engines: {node: '>= 0.4'} hasBin: true @@ -4714,9 +5098,8 @@ packages: vue-tsc: optional: true - rolldown@1.0.0-beta.43: - resolution: {integrity: sha512-6RcqyRx0tY1MlRLnjXPp/849Rl/CPFhzpGGwNPEPjKwqBMqPq/Rbbkxasa8s0x+IkUk46ty4jazb5skZ/Vgdhw==} - engines: {node: ^20.19.0 || >=22.12.0} + rolldown@1.0.0-beta.9-commit.d91dfb5: + resolution: {integrity: sha512-FHkj6gGEiEgmAXQchglofvUUdwj2Oiw603Rs+zgFAnn9Cb7T7z3fiaEc0DbN3ja4wYkW6sF2rzMEtC1V4BGx/g==} hasBin: true rollup@2.79.2: @@ -4724,13 +5107,8 @@ packages: engines: {node: '>=10.0.0'} hasBin: true - rollup@4.46.2: - resolution: {integrity: sha512-WMmLFI+Boh6xbop+OAGo9cQ3OgX9MIg7xOQjn+pTCwOkk+FNDAeAemXkJ3HzDJrVXleLOFVa1ipuc1AmEx1Dwg==} - engines: {node: '>=18.0.0', npm: '>=8.0.0'} - hasBin: true - - rollup@4.50.1: - resolution: {integrity: sha512-78E9voJHwnXQMiQdiqswVLZwJIzdBKJ1GdI5Zx6XwoFKUIk09/sSrr+05QFzvYb8q6Y9pPV45zzDuYa3907TZA==} + rollup@4.52.5: + resolution: {integrity: sha512-3GuObel8h7Kqdjt0gxkEzaifHTqLVW56Y/bjN7PSQtkKr0w3V/QYSdt6QWYtd7A1xUtYQigtdUfgj1RvWVtorw==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true @@ -4744,6 +5122,10 @@ packages: resolution: {integrity: sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==} engines: {npm: '>=2.0.0'} + sade@1.8.1: + resolution: {integrity: sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==} + engines: {node: '>=6'} + safe-array-concat@1.1.3: resolution: {integrity: sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==} engines: {node: '>=0.4'} @@ -4769,6 +5151,11 @@ packages: resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} hasBin: true + semver@7.5.4: + resolution: {integrity: sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==} + engines: {node: '>=10'} + hasBin: true + semver@7.7.2: resolution: {integrity: sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==} engines: {node: '>=10'} @@ -4894,6 +5281,9 @@ packages: resolution: {integrity: sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==} engines: {node: '>=0.10.0'} + sprintf-js@1.0.3: + resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} + stackback@0.0.2: resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} @@ -4915,6 +5305,10 @@ packages: stream-shift@1.0.3: resolution: {integrity: sha512-76ORR0DO1o1hlKwTbi/DM3EXWGf3ZJYO8cXX5RJwnul2DEg2oyoZyjLNoQM8WsvZiFKCRfC1O0J7iCvie3RZmQ==} + string-argv@0.3.2: + resolution: {integrity: sha512-aqD2Q0144Z+/RqG52NeHEkZauTAUWJO8c6yTftGJKO3Tja5tUgIfmIl6kExvhtxSDP7fXB6DvzkfMpCd/F3G+Q==} + engines: {node: '>=0.6.19'} + string-width@4.2.3: resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} engines: {node: '>=8'} @@ -4965,12 +5359,20 @@ packages: resolution: {integrity: sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==} engines: {node: '>=8'} + strip-json-comments@3.1.1: + resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} + engines: {node: '>=8'} + strip-literal@3.0.0: resolution: {integrity: sha512-TcccoMhJOM3OebGhSBEmp3UZ2SfDMZUEBdRA/9ynfLi8yYajyWX3JiXArcJt4Umh4vISpspkQIY8ZZoCqjbviA==} supercluster@8.0.1: resolution: {integrity: sha512-IiOea5kJ9iqzD2t7QJq/cREyLHTtSmUT6gQsweojg9WH2sYJqZK9SswTu6jrscO6D1G5v5vYZ9ru/eq85lXeZQ==} + supports-color@8.1.1: + resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} + engines: {node: '>=10'} + supports-preserve-symlinks-flag@1.0.0: resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} engines: {node: '>= 0.4'} @@ -4978,6 +5380,9 @@ packages: sweepline-intersections@1.5.0: resolution: {integrity: sha512-AoVmx72QHpKtItPu72TzFL+kcYjd67BPLDoR0LarIk+xyaRg+pDTMFXndIEvZf9xEKnJv6JdhgRMnocoG0D3AQ==} + tailwind-merge@2.6.0: + resolution: {integrity: sha512-P+Vu1qXfzediirmHOC3xKGAYeZtPcV9g76X+xg2FD4tYgR71ewMA35Y3sCz3zhiN/dwefRpJX0yBcgwi1fXNQA==} + tailwind-merge@3.3.1: resolution: {integrity: sha512-gBXpgUm/3rp1lMZZrM/w7D8GKqshif0zAymAhbCyIt8KMe+0v9DQ7cdYLR4FHH/cKpdTXb+A/tKKU3eolfsI+g==} @@ -4989,6 +5394,9 @@ packages: tailwindcss@4.1.14: resolution: {integrity: sha512-b7pCxjGO98LnxVkKjaZSDeNuljC4ueKUddjENJOADtubtdo8llTaJy7HwBMeLNSSo2N5QIAgklslK1+Ir8r6CA==} + tailwindcss@4.1.15: + resolution: {integrity: sha512-k2WLnWkYFkdpRv+Oby3EBXIyQC8/s1HOFMBUViwtAh6Z5uAozeUSMQlIsn/c6Q2iJzqG6aJT3wdPaRNj70iYxQ==} + tapable@2.2.2: resolution: {integrity: sha512-Re10+NauLTMCudc7T5WLFLAwDhQ0JWdrMK+9B2M8zR5hRExKmsRDCBA7/aV/pNJFltmBFO5BAMlQFi/vq3nKOg==} engines: {node: '>=6'} @@ -5010,8 +5418,8 @@ packages: engines: {node: '>=10'} hasBin: true - terser@5.44.0: - resolution: {integrity: sha512-nIVck8DK+GM/0Frwd+nIhZ84pR/BX7rmXMfYwyg+Sri5oGVE99/E3KvXqpC2xHFxyqXyGHTKBSioxxplrO4I4w==} + terser@5.44.1: + resolution: {integrity: sha512-t/R3R/n0MSwnnazuPpPNVO60LX0SKL45pyl9YlvxIdkH0Of7D5qM2EVe+yASRIlY5pZ73nclYJfNANGWPwFDZw==} engines: {node: '>=10'} hasBin: true @@ -5127,6 +5535,9 @@ packages: engines: {node: '>=18.0.0'} hasBin: true + tw-animate-css@1.4.0: + resolution: {integrity: sha512-7bziOlRqH0hJx80h/3mbicLW7o8qLsH5+RaLR2t+OHM3D0JlWGODQKQ4cxbK7WlvmUxpcj6Kgu6EKqjrGFe3QQ==} + type-fest@0.16.0: resolution: {integrity: sha512-eaBzG6MxNzEn9kiwvtre90cXaNLkmadMWa1zQMs3XORCXNbsH/OewwbxC5ia9dCxIxnTAsSxXJaa/p5y8DlvJg==} engines: {node: '>=10'} @@ -5156,6 +5567,11 @@ packages: engines: {node: '>=4.2.0'} hasBin: true + typescript@5.8.2: + resolution: {integrity: sha512-aJn6wq13/afZp/jT9QZmwEjDqqvSGp1VT5GVg+f/t6/oVyrgXM6BY1h9BRh/O5p3PlUPAe+WuiEZOmb/49RqoQ==} + engines: {node: '>=14.17'} + hasBin: true + typescript@5.9.2: resolution: {integrity: sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A==} engines: {node: '>=14.17'} @@ -5172,6 +5588,9 @@ packages: typewise@1.0.3: resolution: {integrity: sha512-aXofE06xGhaQSPzt8hlTY+/YWQhm9P0jYUp1f2XtmW/3Bk0qzXcyFWAtPoo2uTGQj1ZwbDuSyuxicq+aDo8lCQ==} + ufo@1.6.1: + resolution: {integrity: sha512-9a4/uxlTWJ4+a5i0ooc1rU7C7YOw3wT+UGqdeNNHWnOF9qcMBgLRS+4IYUqbczewFx4mLEig6gawh7X6mFlEkA==} + unbox-primitive@1.1.0: resolution: {integrity: sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==} engines: {node: '>= 0.4'} @@ -5230,6 +5649,15 @@ packages: peerDependencies: browserslist: '>= 4.21.0' + update-browserslist-db@1.1.4: + resolution: {integrity: sha512-q0SPT4xyU84saUX+tomz1WLkxUbuaJnR1xWt17M7fJtEJigJeWUNGUqrauFXsHnqev9y9JTRGwk13tFBuKby4A==} + hasBin: true + peerDependencies: + browserslist: '>= 4.21.0' + + uri-js@4.4.1: + resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + use-callback-ref@1.3.3: resolution: {integrity: sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg==} engines: {node: '>=10'} @@ -5263,6 +5691,15 @@ packages: engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} hasBin: true + vite-plugin-dts@4.5.4: + resolution: {integrity: sha512-d4sOM8M/8z7vRXHHq/ebbblfaxENjogAAekcfcDCCwAyvGqnPrc7f4NZbvItS+g4WTgerW0xDwSz5qz11JT3vg==} + peerDependencies: + typescript: '*' + vite: '*' + peerDependenciesMeta: + vite: + optional: true + vite-plugin-html@3.2.2: resolution: {integrity: sha512-vb9C9kcdzcIo/Oc3CLZVS03dL5pDlOFuhGlZYDCJ840BhWl/0nGeZWf3Qy7NlOayscY4Cm/QRgULCQkEZige5Q==} peerDependencies: @@ -5280,48 +5717,14 @@ packages: '@vite-pwa/assets-generator': optional: true - vite@7.1.1: - resolution: {integrity: sha512-yJ+Mp7OyV+4S+afWo+QyoL9jFWD11QFH0i5i7JypnfTcA1rmgxCbiA8WwAICDEtZ1Z1hzrVhN8R8rGTqkTY8ZQ==} - engines: {node: ^20.19.0 || >=22.12.0} - hasBin: true + vite-plugin-static-copy@3.1.4: + resolution: {integrity: sha512-iCmr4GSw4eSnaB+G8zc2f4dxSuDjbkjwpuBLLGvQYR9IW7rnDzftnUjOH5p4RYR+d4GsiBqXRvzuFhs5bnzVyw==} + engines: {node: ^18.0.0 || >=20.0.0} peerDependencies: - '@types/node': ^20.19.0 || >=22.12.0 - jiti: '>=1.21.0' - less: ^4.0.0 - lightningcss: ^1.21.0 - sass: ^1.70.0 - sass-embedded: ^1.70.0 - stylus: '>=0.54.8' - sugarss: ^5.0.0 - terser: ^5.16.0 - tsx: ^4.8.1 - yaml: ^2.4.2 - peerDependenciesMeta: - '@types/node': - optional: true - jiti: - optional: true - less: - optional: true - lightningcss: - optional: true - sass: - optional: true - sass-embedded: - optional: true - stylus: - optional: true - sugarss: - optional: true - terser: - optional: true - tsx: - optional: true - yaml: - optional: true + vite: ^5.0.0 || ^6.0.0 || ^7.0.0 - vite@7.1.9: - resolution: {integrity: sha512-4nVGliEpxmhCL8DslSAUdxlB6+SMrhB0a1v5ijlh1xB1nEPuy1mxaHxysVucLHuWryAxLWg6a5ei+U4TLn/rFg==} + vite@7.1.11: + resolution: {integrity: sha512-uzcxnSDVjAopEUjljkWh8EIrg6tlzrjFUfMcR1EVsRDGwf/ccef0qQPRyOrROwhrTDaApueq+ja+KLPlzR/zdg==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true peerDependencies: @@ -5392,6 +5795,9 @@ packages: resolution: {integrity: sha512-Dhxzh5HZuiHQhbvTW9AMetFfBHDMYpo23Uo9btPXgdYP+3T5S+p+jgNy7spra+veYhBP2dCSgxR/i2Y02h5/6w==} engines: {node: '>=0.10.0'} + vscode-uri@3.1.0: + resolution: {integrity: sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ==} + webidl-conversions@3.0.1: resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} @@ -5508,6 +5914,9 @@ packages: yallist@3.1.1: resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} + yallist@4.0.0: + resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} + yallist@5.0.0: resolution: {integrity: sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==} engines: {node: '>=18'} @@ -5551,6 +5960,8 @@ snapshots: '@adobe/css-tools@4.4.3': {} + '@alloc/quick-lru@5.2.0': {} + '@ampproject/remapping@2.3.0': dependencies: '@jridgewell/gen-mapping': 0.3.13 @@ -5583,6 +5994,8 @@ snapshots: '@babel/compat-data@7.28.4': {} + '@babel/compat-data@7.28.5': {} + '@babel/core@7.28.0': dependencies: '@ampproject/remapping': 2.3.0 @@ -5616,7 +6029,7 @@ snapshots: '@babel/types': 7.28.4 '@jridgewell/remapping': 2.3.5 convert-source-map: 2.0.0 - debug: 4.4.1 + debug: 4.4.3 gensync: 1.0.0-beta.2 json5: 2.2.3 semver: 6.3.1 @@ -5631,6 +6044,14 @@ snapshots: '@jridgewell/trace-mapping': 0.3.31 jsesc: 3.1.0 + '@babel/generator@7.28.5': + dependencies: + '@babel/parser': 7.28.5 + '@babel/types': 7.28.5 + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + jsesc: 3.1.0 + '@babel/helper-annotate-as-pure@7.27.3': dependencies: '@babel/types': 7.28.4 @@ -5656,20 +6077,20 @@ snapshots: transitivePeerDependencies: - supports-color - '@babel/helper-create-class-features-plugin@7.28.3(@babel/core@7.28.4)': + '@babel/helper-create-class-features-plugin@7.28.5(@babel/core@7.28.4)': dependencies: '@babel/core': 7.28.4 '@babel/helper-annotate-as-pure': 7.27.3 - '@babel/helper-member-expression-to-functions': 7.27.1 + '@babel/helper-member-expression-to-functions': 7.28.5 '@babel/helper-optimise-call-expression': 7.27.1 '@babel/helper-replace-supers': 7.27.1(@babel/core@7.28.4) '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 - '@babel/traverse': 7.28.4 + '@babel/traverse': 7.28.5 semver: 6.3.1 transitivePeerDependencies: - supports-color - '@babel/helper-create-regexp-features-plugin@7.27.1(@babel/core@7.28.4)': + '@babel/helper-create-regexp-features-plugin@7.28.5(@babel/core@7.28.4)': dependencies: '@babel/core': 7.28.4 '@babel/helper-annotate-as-pure': 7.27.3 @@ -5683,7 +6104,7 @@ snapshots: '@babel/helper-plugin-utils': 7.27.1 debug: 4.4.3 lodash.debounce: 4.0.8 - resolve: 1.22.10 + resolve: 1.22.11 transitivePeerDependencies: - supports-color @@ -5696,6 +6117,13 @@ snapshots: transitivePeerDependencies: - supports-color + '@babel/helper-member-expression-to-functions@7.28.5': + dependencies: + '@babel/traverse': 7.28.5 + '@babel/types': 7.28.5 + transitivePeerDependencies: + - supports-color + '@babel/helper-module-imports@7.27.1': dependencies: '@babel/traverse': 7.28.4 @@ -5732,7 +6160,7 @@ snapshots: '@babel/core': 7.28.4 '@babel/helper-annotate-as-pure': 7.27.3 '@babel/helper-wrap-function': 7.28.3 - '@babel/traverse': 7.28.4 + '@babel/traverse': 7.28.5 transitivePeerDependencies: - supports-color @@ -5765,13 +6193,15 @@ snapshots: '@babel/helper-validator-identifier@7.27.1': {} + '@babel/helper-validator-identifier@7.28.5': {} + '@babel/helper-validator-option@7.27.1': {} '@babel/helper-wrap-function@7.28.3': dependencies: '@babel/template': 7.27.2 - '@babel/traverse': 7.28.4 - '@babel/types': 7.28.4 + '@babel/traverse': 7.28.5 + '@babel/types': 7.28.5 transitivePeerDependencies: - supports-color @@ -5789,11 +6219,15 @@ snapshots: dependencies: '@babel/types': 7.28.4 - '@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.27.1(@babel/core@7.28.4)': + '@babel/parser@7.28.5': + dependencies: + '@babel/types': 7.28.5 + + '@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.28.5(@babel/core@7.28.4)': dependencies: '@babel/core': 7.28.4 '@babel/helper-plugin-utils': 7.27.1 - '@babel/traverse': 7.28.4 + '@babel/traverse': 7.28.5 transitivePeerDependencies: - supports-color @@ -5812,7 +6246,7 @@ snapshots: '@babel/core': 7.28.4 '@babel/helper-plugin-utils': 7.27.1 '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 - '@babel/plugin-transform-optional-chaining': 7.27.1(@babel/core@7.28.4) + '@babel/plugin-transform-optional-chaining': 7.28.5(@babel/core@7.28.4) transitivePeerDependencies: - supports-color @@ -5820,7 +6254,7 @@ snapshots: dependencies: '@babel/core': 7.28.4 '@babel/helper-plugin-utils': 7.27.1 - '@babel/traverse': 7.28.4 + '@babel/traverse': 7.28.5 transitivePeerDependencies: - supports-color @@ -5851,7 +6285,7 @@ snapshots: '@babel/plugin-syntax-unicode-sets-regex@7.18.6(@babel/core@7.28.4)': dependencies: '@babel/core': 7.28.4 - '@babel/helper-create-regexp-features-plugin': 7.27.1(@babel/core@7.28.4) + '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.28.4) '@babel/helper-plugin-utils': 7.27.1 '@babel/plugin-transform-arrow-functions@7.27.1(@babel/core@7.28.4)': @@ -5864,7 +6298,7 @@ snapshots: '@babel/core': 7.28.4 '@babel/helper-plugin-utils': 7.27.1 '@babel/helper-remap-async-to-generator': 7.27.1(@babel/core@7.28.4) - '@babel/traverse': 7.28.4 + '@babel/traverse': 7.28.5 transitivePeerDependencies: - supports-color @@ -5882,7 +6316,7 @@ snapshots: '@babel/core': 7.28.4 '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-transform-block-scoping@7.28.4(@babel/core@7.28.4)': + '@babel/plugin-transform-block-scoping@7.28.5(@babel/core@7.28.4)': dependencies: '@babel/core': 7.28.4 '@babel/helper-plugin-utils': 7.27.1 @@ -5890,7 +6324,7 @@ snapshots: '@babel/plugin-transform-class-properties@7.27.1(@babel/core@7.28.4)': dependencies: '@babel/core': 7.28.4 - '@babel/helper-create-class-features-plugin': 7.28.3(@babel/core@7.28.4) + '@babel/helper-create-class-features-plugin': 7.28.5(@babel/core@7.28.4) '@babel/helper-plugin-utils': 7.27.1 transitivePeerDependencies: - supports-color @@ -5898,7 +6332,7 @@ snapshots: '@babel/plugin-transform-class-static-block@7.28.3(@babel/core@7.28.4)': dependencies: '@babel/core': 7.28.4 - '@babel/helper-create-class-features-plugin': 7.28.3(@babel/core@7.28.4) + '@babel/helper-create-class-features-plugin': 7.28.5(@babel/core@7.28.4) '@babel/helper-plugin-utils': 7.27.1 transitivePeerDependencies: - supports-color @@ -5911,7 +6345,7 @@ snapshots: '@babel/helper-globals': 7.28.0 '@babel/helper-plugin-utils': 7.27.1 '@babel/helper-replace-supers': 7.27.1(@babel/core@7.28.4) - '@babel/traverse': 7.28.4 + '@babel/traverse': 7.28.5 transitivePeerDependencies: - supports-color @@ -5921,18 +6355,18 @@ snapshots: '@babel/helper-plugin-utils': 7.27.1 '@babel/template': 7.27.2 - '@babel/plugin-transform-destructuring@7.28.0(@babel/core@7.28.4)': + '@babel/plugin-transform-destructuring@7.28.5(@babel/core@7.28.4)': dependencies: '@babel/core': 7.28.4 '@babel/helper-plugin-utils': 7.27.1 - '@babel/traverse': 7.28.4 + '@babel/traverse': 7.28.5 transitivePeerDependencies: - supports-color '@babel/plugin-transform-dotall-regex@7.27.1(@babel/core@7.28.4)': dependencies: '@babel/core': 7.28.4 - '@babel/helper-create-regexp-features-plugin': 7.27.1(@babel/core@7.28.4) + '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.28.4) '@babel/helper-plugin-utils': 7.27.1 '@babel/plugin-transform-duplicate-keys@7.27.1(@babel/core@7.28.4)': @@ -5943,7 +6377,7 @@ snapshots: '@babel/plugin-transform-duplicate-named-capturing-groups-regex@7.27.1(@babel/core@7.28.4)': dependencies: '@babel/core': 7.28.4 - '@babel/helper-create-regexp-features-plugin': 7.27.1(@babel/core@7.28.4) + '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.28.4) '@babel/helper-plugin-utils': 7.27.1 '@babel/plugin-transform-dynamic-import@7.27.1(@babel/core@7.28.4)': @@ -5955,11 +6389,11 @@ snapshots: dependencies: '@babel/core': 7.28.4 '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-transform-destructuring': 7.28.0(@babel/core@7.28.4) + '@babel/plugin-transform-destructuring': 7.28.5(@babel/core@7.28.4) transitivePeerDependencies: - supports-color - '@babel/plugin-transform-exponentiation-operator@7.27.1(@babel/core@7.28.4)': + '@babel/plugin-transform-exponentiation-operator@7.28.5(@babel/core@7.28.4)': dependencies: '@babel/core': 7.28.4 '@babel/helper-plugin-utils': 7.27.1 @@ -5982,7 +6416,7 @@ snapshots: '@babel/core': 7.28.4 '@babel/helper-compilation-targets': 7.27.2 '@babel/helper-plugin-utils': 7.27.1 - '@babel/traverse': 7.28.4 + '@babel/traverse': 7.28.5 transitivePeerDependencies: - supports-color @@ -5996,7 +6430,7 @@ snapshots: '@babel/core': 7.28.4 '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-transform-logical-assignment-operators@7.27.1(@babel/core@7.28.4)': + '@babel/plugin-transform-logical-assignment-operators@7.28.5(@babel/core@7.28.4)': dependencies: '@babel/core': 7.28.4 '@babel/helper-plugin-utils': 7.27.1 @@ -6030,13 +6464,13 @@ snapshots: transitivePeerDependencies: - supports-color - '@babel/plugin-transform-modules-systemjs@7.27.1(@babel/core@7.28.4)': + '@babel/plugin-transform-modules-systemjs@7.28.5(@babel/core@7.28.4)': dependencies: '@babel/core': 7.28.4 '@babel/helper-module-transforms': 7.28.3(@babel/core@7.28.4) '@babel/helper-plugin-utils': 7.27.1 - '@babel/helper-validator-identifier': 7.27.1 - '@babel/traverse': 7.28.4 + '@babel/helper-validator-identifier': 7.28.5 + '@babel/traverse': 7.28.5 transitivePeerDependencies: - supports-color @@ -6051,7 +6485,7 @@ snapshots: '@babel/plugin-transform-named-capturing-groups-regex@7.27.1(@babel/core@7.28.4)': dependencies: '@babel/core': 7.28.4 - '@babel/helper-create-regexp-features-plugin': 7.27.1(@babel/core@7.28.4) + '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.28.4) '@babel/helper-plugin-utils': 7.27.1 '@babel/plugin-transform-new-target@7.27.1(@babel/core@7.28.4)': @@ -6074,9 +6508,9 @@ snapshots: '@babel/core': 7.28.4 '@babel/helper-compilation-targets': 7.27.2 '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-transform-destructuring': 7.28.0(@babel/core@7.28.4) + '@babel/plugin-transform-destructuring': 7.28.5(@babel/core@7.28.4) '@babel/plugin-transform-parameters': 7.27.7(@babel/core@7.28.4) - '@babel/traverse': 7.28.4 + '@babel/traverse': 7.28.5 transitivePeerDependencies: - supports-color @@ -6093,7 +6527,7 @@ snapshots: '@babel/core': 7.28.4 '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-transform-optional-chaining@7.27.1(@babel/core@7.28.4)': + '@babel/plugin-transform-optional-chaining@7.28.5(@babel/core@7.28.4)': dependencies: '@babel/core': 7.28.4 '@babel/helper-plugin-utils': 7.27.1 @@ -6109,7 +6543,7 @@ snapshots: '@babel/plugin-transform-private-methods@7.27.1(@babel/core@7.28.4)': dependencies: '@babel/core': 7.28.4 - '@babel/helper-create-class-features-plugin': 7.28.3(@babel/core@7.28.4) + '@babel/helper-create-class-features-plugin': 7.28.5(@babel/core@7.28.4) '@babel/helper-plugin-utils': 7.27.1 transitivePeerDependencies: - supports-color @@ -6118,7 +6552,7 @@ snapshots: dependencies: '@babel/core': 7.28.4 '@babel/helper-annotate-as-pure': 7.27.3 - '@babel/helper-create-class-features-plugin': 7.28.3(@babel/core@7.28.4) + '@babel/helper-create-class-features-plugin': 7.28.5(@babel/core@7.28.4) '@babel/helper-plugin-utils': 7.27.1 transitivePeerDependencies: - supports-color @@ -6146,7 +6580,7 @@ snapshots: '@babel/plugin-transform-regexp-modifiers@7.27.1(@babel/core@7.28.4)': dependencies: '@babel/core': 7.28.4 - '@babel/helper-create-regexp-features-plugin': 7.27.1(@babel/core@7.28.4) + '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.28.4) '@babel/helper-plugin-utils': 7.27.1 '@babel/plugin-transform-reserved-words@7.27.1(@babel/core@7.28.4)': @@ -6201,29 +6635,29 @@ snapshots: '@babel/plugin-transform-unicode-property-regex@7.27.1(@babel/core@7.28.4)': dependencies: '@babel/core': 7.28.4 - '@babel/helper-create-regexp-features-plugin': 7.27.1(@babel/core@7.28.4) + '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.28.4) '@babel/helper-plugin-utils': 7.27.1 '@babel/plugin-transform-unicode-regex@7.27.1(@babel/core@7.28.4)': dependencies: '@babel/core': 7.28.4 - '@babel/helper-create-regexp-features-plugin': 7.27.1(@babel/core@7.28.4) + '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.28.4) '@babel/helper-plugin-utils': 7.27.1 '@babel/plugin-transform-unicode-sets-regex@7.27.1(@babel/core@7.28.4)': dependencies: '@babel/core': 7.28.4 - '@babel/helper-create-regexp-features-plugin': 7.27.1(@babel/core@7.28.4) + '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.28.4) '@babel/helper-plugin-utils': 7.27.1 - '@babel/preset-env@7.28.3(@babel/core@7.28.4)': + '@babel/preset-env@7.28.5(@babel/core@7.28.4)': dependencies: - '@babel/compat-data': 7.28.4 + '@babel/compat-data': 7.28.5 '@babel/core': 7.28.4 '@babel/helper-compilation-targets': 7.27.2 '@babel/helper-plugin-utils': 7.27.1 '@babel/helper-validator-option': 7.27.1 - '@babel/plugin-bugfix-firefox-class-in-computed-class-key': 7.27.1(@babel/core@7.28.4) + '@babel/plugin-bugfix-firefox-class-in-computed-class-key': 7.28.5(@babel/core@7.28.4) '@babel/plugin-bugfix-safari-class-field-initializer-scope': 7.27.1(@babel/core@7.28.4) '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression': 7.27.1(@babel/core@7.28.4) '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining': 7.27.1(@babel/core@7.28.4) @@ -6236,28 +6670,28 @@ snapshots: '@babel/plugin-transform-async-generator-functions': 7.28.0(@babel/core@7.28.4) '@babel/plugin-transform-async-to-generator': 7.27.1(@babel/core@7.28.4) '@babel/plugin-transform-block-scoped-functions': 7.27.1(@babel/core@7.28.4) - '@babel/plugin-transform-block-scoping': 7.28.4(@babel/core@7.28.4) + '@babel/plugin-transform-block-scoping': 7.28.5(@babel/core@7.28.4) '@babel/plugin-transform-class-properties': 7.27.1(@babel/core@7.28.4) '@babel/plugin-transform-class-static-block': 7.28.3(@babel/core@7.28.4) '@babel/plugin-transform-classes': 7.28.4(@babel/core@7.28.4) '@babel/plugin-transform-computed-properties': 7.27.1(@babel/core@7.28.4) - '@babel/plugin-transform-destructuring': 7.28.0(@babel/core@7.28.4) + '@babel/plugin-transform-destructuring': 7.28.5(@babel/core@7.28.4) '@babel/plugin-transform-dotall-regex': 7.27.1(@babel/core@7.28.4) '@babel/plugin-transform-duplicate-keys': 7.27.1(@babel/core@7.28.4) '@babel/plugin-transform-duplicate-named-capturing-groups-regex': 7.27.1(@babel/core@7.28.4) '@babel/plugin-transform-dynamic-import': 7.27.1(@babel/core@7.28.4) '@babel/plugin-transform-explicit-resource-management': 7.28.0(@babel/core@7.28.4) - '@babel/plugin-transform-exponentiation-operator': 7.27.1(@babel/core@7.28.4) + '@babel/plugin-transform-exponentiation-operator': 7.28.5(@babel/core@7.28.4) '@babel/plugin-transform-export-namespace-from': 7.27.1(@babel/core@7.28.4) '@babel/plugin-transform-for-of': 7.27.1(@babel/core@7.28.4) '@babel/plugin-transform-function-name': 7.27.1(@babel/core@7.28.4) '@babel/plugin-transform-json-strings': 7.27.1(@babel/core@7.28.4) '@babel/plugin-transform-literals': 7.27.1(@babel/core@7.28.4) - '@babel/plugin-transform-logical-assignment-operators': 7.27.1(@babel/core@7.28.4) + '@babel/plugin-transform-logical-assignment-operators': 7.28.5(@babel/core@7.28.4) '@babel/plugin-transform-member-expression-literals': 7.27.1(@babel/core@7.28.4) '@babel/plugin-transform-modules-amd': 7.27.1(@babel/core@7.28.4) '@babel/plugin-transform-modules-commonjs': 7.27.1(@babel/core@7.28.4) - '@babel/plugin-transform-modules-systemjs': 7.27.1(@babel/core@7.28.4) + '@babel/plugin-transform-modules-systemjs': 7.28.5(@babel/core@7.28.4) '@babel/plugin-transform-modules-umd': 7.27.1(@babel/core@7.28.4) '@babel/plugin-transform-named-capturing-groups-regex': 7.27.1(@babel/core@7.28.4) '@babel/plugin-transform-new-target': 7.27.1(@babel/core@7.28.4) @@ -6266,7 +6700,7 @@ snapshots: '@babel/plugin-transform-object-rest-spread': 7.28.4(@babel/core@7.28.4) '@babel/plugin-transform-object-super': 7.27.1(@babel/core@7.28.4) '@babel/plugin-transform-optional-catch-binding': 7.27.1(@babel/core@7.28.4) - '@babel/plugin-transform-optional-chaining': 7.27.1(@babel/core@7.28.4) + '@babel/plugin-transform-optional-chaining': 7.28.5(@babel/core@7.28.4) '@babel/plugin-transform-parameters': 7.27.7(@babel/core@7.28.4) '@babel/plugin-transform-private-methods': 7.27.1(@babel/core@7.28.4) '@babel/plugin-transform-private-property-in-object': 7.27.1(@babel/core@7.28.4) @@ -6287,7 +6721,7 @@ snapshots: babel-plugin-polyfill-corejs2: 0.4.14(@babel/core@7.28.4) babel-plugin-polyfill-corejs3: 0.13.0(@babel/core@7.28.4) babel-plugin-polyfill-regenerator: 0.6.5(@babel/core@7.28.4) - core-js-compat: 3.46.0 + core-js-compat: 3.47.0 semver: 6.3.1 transitivePeerDependencies: - supports-color @@ -6296,7 +6730,7 @@ snapshots: dependencies: '@babel/core': 7.28.4 '@babel/helper-plugin-utils': 7.27.1 - '@babel/types': 7.28.4 + '@babel/types': 7.28.5 esutils: 2.0.3 '@babel/preset-typescript@7.27.1(@babel/core@7.28.0)': @@ -6332,11 +6766,28 @@ snapshots: transitivePeerDependencies: - supports-color + '@babel/traverse@7.28.5': + dependencies: + '@babel/code-frame': 7.27.1 + '@babel/generator': 7.28.5 + '@babel/helper-globals': 7.28.0 + '@babel/parser': 7.28.5 + '@babel/template': 7.27.2 + '@babel/types': 7.28.5 + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + '@babel/types@7.28.4': dependencies: '@babel/helper-string-parser': 7.27.1 '@babel/helper-validator-identifier': 7.27.1 + '@babel/types@7.28.5': + dependencies: + '@babel/helper-string-parser': 7.27.1 + '@babel/helper-validator-identifier': 7.28.5 + '@biomejs/biome@2.2.4': optionalDependencies: '@biomejs/cli-darwin-arm64': 2.2.4 @@ -6392,13 +6843,13 @@ snapshots: transitivePeerDependencies: - supports-color - '@emnapi/core@1.5.0': + '@emnapi/core@1.7.1': dependencies: '@emnapi/wasi-threads': 1.1.0 tslib: 2.8.1 optional: true - '@emnapi/runtime@1.5.0': + '@emnapi/runtime@1.7.1': dependencies: tslib: 2.8.1 optional: true @@ -6408,157 +6859,157 @@ snapshots: tslib: 2.8.1 optional: true - '@esbuild/aix-ppc64@0.25.8': + '@esbuild/aix-ppc64@0.25.11': optional: true '@esbuild/aix-ppc64@0.25.9': optional: true - '@esbuild/android-arm64@0.25.8': + '@esbuild/android-arm64@0.25.11': optional: true '@esbuild/android-arm64@0.25.9': optional: true - '@esbuild/android-arm@0.25.8': + '@esbuild/android-arm@0.25.11': optional: true '@esbuild/android-arm@0.25.9': optional: true - '@esbuild/android-x64@0.25.8': + '@esbuild/android-x64@0.25.11': optional: true '@esbuild/android-x64@0.25.9': optional: true - '@esbuild/darwin-arm64@0.25.8': + '@esbuild/darwin-arm64@0.25.11': optional: true '@esbuild/darwin-arm64@0.25.9': optional: true - '@esbuild/darwin-x64@0.25.8': + '@esbuild/darwin-x64@0.25.11': optional: true '@esbuild/darwin-x64@0.25.9': optional: true - '@esbuild/freebsd-arm64@0.25.8': + '@esbuild/freebsd-arm64@0.25.11': optional: true '@esbuild/freebsd-arm64@0.25.9': optional: true - '@esbuild/freebsd-x64@0.25.8': + '@esbuild/freebsd-x64@0.25.11': optional: true '@esbuild/freebsd-x64@0.25.9': optional: true - '@esbuild/linux-arm64@0.25.8': + '@esbuild/linux-arm64@0.25.11': optional: true '@esbuild/linux-arm64@0.25.9': optional: true - '@esbuild/linux-arm@0.25.8': + '@esbuild/linux-arm@0.25.11': optional: true '@esbuild/linux-arm@0.25.9': optional: true - '@esbuild/linux-ia32@0.25.8': + '@esbuild/linux-ia32@0.25.11': optional: true '@esbuild/linux-ia32@0.25.9': optional: true - '@esbuild/linux-loong64@0.25.8': + '@esbuild/linux-loong64@0.25.11': optional: true '@esbuild/linux-loong64@0.25.9': optional: true - '@esbuild/linux-mips64el@0.25.8': + '@esbuild/linux-mips64el@0.25.11': optional: true '@esbuild/linux-mips64el@0.25.9': optional: true - '@esbuild/linux-ppc64@0.25.8': + '@esbuild/linux-ppc64@0.25.11': optional: true '@esbuild/linux-ppc64@0.25.9': optional: true - '@esbuild/linux-riscv64@0.25.8': + '@esbuild/linux-riscv64@0.25.11': optional: true '@esbuild/linux-riscv64@0.25.9': optional: true - '@esbuild/linux-s390x@0.25.8': + '@esbuild/linux-s390x@0.25.11': optional: true '@esbuild/linux-s390x@0.25.9': optional: true - '@esbuild/linux-x64@0.25.8': + '@esbuild/linux-x64@0.25.11': optional: true '@esbuild/linux-x64@0.25.9': optional: true - '@esbuild/netbsd-arm64@0.25.8': + '@esbuild/netbsd-arm64@0.25.11': optional: true '@esbuild/netbsd-arm64@0.25.9': optional: true - '@esbuild/netbsd-x64@0.25.8': + '@esbuild/netbsd-x64@0.25.11': optional: true '@esbuild/netbsd-x64@0.25.9': optional: true - '@esbuild/openbsd-arm64@0.25.8': + '@esbuild/openbsd-arm64@0.25.11': optional: true '@esbuild/openbsd-arm64@0.25.9': optional: true - '@esbuild/openbsd-x64@0.25.8': + '@esbuild/openbsd-x64@0.25.11': optional: true '@esbuild/openbsd-x64@0.25.9': optional: true - '@esbuild/openharmony-arm64@0.25.8': + '@esbuild/openharmony-arm64@0.25.11': optional: true '@esbuild/openharmony-arm64@0.25.9': optional: true - '@esbuild/sunos-x64@0.25.8': + '@esbuild/sunos-x64@0.25.11': optional: true '@esbuild/sunos-x64@0.25.9': optional: true - '@esbuild/win32-arm64@0.25.8': + '@esbuild/win32-arm64@0.25.11': optional: true '@esbuild/win32-arm64@0.25.9': optional: true - '@esbuild/win32-ia32@0.25.8': + '@esbuild/win32-ia32@0.25.11': optional: true '@esbuild/win32-ia32@0.25.9': optional: true - '@esbuild/win32-x64@0.25.8': + '@esbuild/win32-x64@0.25.11': optional: true '@esbuild/win32-x64@0.25.9': @@ -6631,8 +7082,6 @@ snapshots: '@jridgewell/gen-mapping': 0.3.13 '@jridgewell/trace-mapping': 0.3.31 - '@jridgewell/sourcemap-codec@1.5.4': {} - '@jridgewell/sourcemap-codec@1.5.5': {} '@jridgewell/trace-mapping@0.3.31': @@ -6694,10 +7143,45 @@ snapshots: pbf: 4.0.1 supercluster: 8.0.1 - '@napi-rs/wasm-runtime@1.0.7': + '@microsoft/api-extractor-model@7.31.2(@types/node@24.7.0)': + dependencies: + '@microsoft/tsdoc': 0.15.1 + '@microsoft/tsdoc-config': 0.17.1 + '@rushstack/node-core-library': 5.17.1(@types/node@24.7.0) + transitivePeerDependencies: + - '@types/node' + + '@microsoft/api-extractor@7.53.2(@types/node@24.7.0)': dependencies: - '@emnapi/core': 1.5.0 - '@emnapi/runtime': 1.5.0 + '@microsoft/api-extractor-model': 7.31.2(@types/node@24.7.0) + '@microsoft/tsdoc': 0.15.1 + '@microsoft/tsdoc-config': 0.17.1 + '@rushstack/node-core-library': 5.17.1(@types/node@24.7.0) + '@rushstack/rig-package': 0.6.0 + '@rushstack/terminal': 0.19.2(@types/node@24.7.0) + '@rushstack/ts-command-line': 5.1.2(@types/node@24.7.0) + lodash: 4.17.21 + minimatch: 10.0.3 + resolve: 1.22.11 + semver: 7.5.4 + source-map: 0.6.1 + typescript: 5.8.2 + transitivePeerDependencies: + - '@types/node' + + '@microsoft/tsdoc-config@0.17.1': + dependencies: + '@microsoft/tsdoc': 0.15.1 + ajv: 8.12.0 + jju: 1.4.0 + resolve: 1.22.11 + + '@microsoft/tsdoc@0.15.1': {} + + '@napi-rs/wasm-runtime@0.2.12': + dependencies: + '@emnapi/core': 1.7.1 + '@emnapi/runtime': 1.7.1 '@tybys/wasm-util': 0.10.1 optional: true @@ -6719,7 +7203,11 @@ snapshots: '@nodelib/fs.scandir': 2.1.5 fastq: 1.19.1 - '@oxc-project/types@0.94.0': {} + '@oxc-project/runtime@0.71.0': {} + + '@oxc-project/types@0.71.0': {} + + '@publint/pack@0.1.2': {} '@quansync/fs@0.1.5': dependencies: @@ -6746,6 +7234,29 @@ snapshots: '@types/react': 19.2.1 '@types/react-dom': 19.2.0(@types/react@19.2.1) + '@radix-ui/react-alert-dialog@1.1.15(@types/react-dom@19.2.0(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.1)(react@19.2.0) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.1)(react@19.2.0) + '@radix-ui/react-dialog': 1.1.15(@types/react-dom@19.2.0(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.0(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-slot': 1.2.3(@types/react@19.2.1)(react@19.2.0) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + optionalDependencies: + '@types/react': 19.2.1 + '@types/react-dom': 19.2.0(@types/react@19.2.1) + + '@radix-ui/react-arrow@1.1.7(@types/react-dom@18.3.7(@types/react@18.3.26))(@types/react@18.3.26)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.26))(@types/react@18.3.26)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + optionalDependencies: + '@types/react': 18.3.26 + '@types/react-dom': 18.3.7(@types/react@18.3.26) + '@radix-ui/react-arrow@1.1.7(@types/react-dom@19.2.0(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': dependencies: '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.0(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) @@ -6771,6 +7282,22 @@ snapshots: '@types/react': 19.2.1 '@types/react-dom': 19.2.0(@types/react@19.2.1) + '@radix-ui/react-collapsible@1.1.12(@types/react-dom@18.3.7(@types/react@18.3.26))(@types/react@18.3.26)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.26)(react@19.2.0) + '@radix-ui/react-context': 1.1.2(@types/react@18.3.26)(react@19.2.0) + '@radix-ui/react-id': 1.1.1(@types/react@18.3.26)(react@19.2.0) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@18.3.7(@types/react@18.3.26))(@types/react@18.3.26)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.26))(@types/react@18.3.26)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.26)(react@19.2.0) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.26)(react@19.2.0) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + optionalDependencies: + '@types/react': 18.3.26 + '@types/react-dom': 18.3.7(@types/react@18.3.26) + '@radix-ui/react-collapsible@1.1.12(@types/react-dom@19.2.0(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': dependencies: '@radix-ui/primitive': 1.1.3 @@ -6787,6 +7314,18 @@ snapshots: '@types/react': 19.2.1 '@types/react-dom': 19.2.0(@types/react@19.2.1) + '@radix-ui/react-collection@1.1.7(@types/react-dom@18.3.7(@types/react@18.3.26))(@types/react@18.3.26)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.26)(react@19.2.0) + '@radix-ui/react-context': 1.1.2(@types/react@18.3.26)(react@19.2.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.26))(@types/react@18.3.26)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-slot': 1.2.3(@types/react@18.3.26)(react@19.2.0) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + optionalDependencies: + '@types/react': 18.3.26 + '@types/react-dom': 18.3.7(@types/react@18.3.26) + '@radix-ui/react-collection@1.1.7(@types/react-dom@19.2.0(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': dependencies: '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.1)(react@19.2.0) @@ -6799,18 +7338,52 @@ snapshots: '@types/react': 19.2.1 '@types/react-dom': 19.2.0(@types/react@19.2.1) + '@radix-ui/react-compose-refs@1.1.2(@types/react@18.3.26)(react@19.2.0)': + dependencies: + react: 19.2.0 + optionalDependencies: + '@types/react': 18.3.26 + '@radix-ui/react-compose-refs@1.1.2(@types/react@19.2.1)(react@19.2.0)': dependencies: react: 19.2.0 optionalDependencies: '@types/react': 19.2.1 + '@radix-ui/react-context@1.1.2(@types/react@18.3.26)(react@19.2.0)': + dependencies: + react: 19.2.0 + optionalDependencies: + '@types/react': 18.3.26 + '@radix-ui/react-context@1.1.2(@types/react@19.2.1)(react@19.2.0)': dependencies: react: 19.2.0 optionalDependencies: '@types/react': 19.2.1 + '@radix-ui/react-dialog@1.1.15(@types/react-dom@18.3.7(@types/react@18.3.26))(@types/react@18.3.26)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.26)(react@19.2.0) + '@radix-ui/react-context': 1.1.2(@types/react@18.3.26)(react@19.2.0) + '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@18.3.7(@types/react@18.3.26))(@types/react@18.3.26)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-focus-guards': 1.1.3(@types/react@18.3.26)(react@19.2.0) + '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@18.3.7(@types/react@18.3.26))(@types/react@18.3.26)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-id': 1.1.1(@types/react@18.3.26)(react@19.2.0) + '@radix-ui/react-portal': 1.1.9(@types/react-dom@18.3.7(@types/react@18.3.26))(@types/react@18.3.26)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@18.3.7(@types/react@18.3.26))(@types/react@18.3.26)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.26))(@types/react@18.3.26)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-slot': 1.2.3(@types/react@18.3.26)(react@19.2.0) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.26)(react@19.2.0) + aria-hidden: 1.2.6 + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + react-remove-scroll: 2.7.1(@types/react@18.3.26)(react@19.2.0) + optionalDependencies: + '@types/react': 18.3.26 + '@types/react-dom': 18.3.7(@types/react@18.3.26) + '@radix-ui/react-dialog@1.1.15(@types/react-dom@19.2.0(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': dependencies: '@radix-ui/primitive': 1.1.3 @@ -6833,12 +7406,31 @@ snapshots: '@types/react': 19.2.1 '@types/react-dom': 19.2.0(@types/react@19.2.1) + '@radix-ui/react-direction@1.1.1(@types/react@18.3.26)(react@19.2.0)': + dependencies: + react: 19.2.0 + optionalDependencies: + '@types/react': 18.3.26 + '@radix-ui/react-direction@1.1.1(@types/react@19.2.1)(react@19.2.0)': dependencies: react: 19.2.0 optionalDependencies: '@types/react': 19.2.1 + '@radix-ui/react-dismissable-layer@1.1.11(@types/react-dom@18.3.7(@types/react@18.3.26))(@types/react@18.3.26)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.26)(react@19.2.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.26))(@types/react@18.3.26)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@18.3.26)(react@19.2.0) + '@radix-ui/react-use-escape-keydown': 1.1.1(@types/react@18.3.26)(react@19.2.0) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + optionalDependencies: + '@types/react': 18.3.26 + '@types/react-dom': 18.3.7(@types/react@18.3.26) + '@radix-ui/react-dismissable-layer@1.1.11(@types/react-dom@19.2.0(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': dependencies: '@radix-ui/primitive': 1.1.3 @@ -6852,6 +7444,21 @@ snapshots: '@types/react': 19.2.1 '@types/react-dom': 19.2.0(@types/react@19.2.1) + '@radix-ui/react-dropdown-menu@2.1.16(@types/react-dom@18.3.7(@types/react@18.3.26))(@types/react@18.3.26)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.26)(react@19.2.0) + '@radix-ui/react-context': 1.1.2(@types/react@18.3.26)(react@19.2.0) + '@radix-ui/react-id': 1.1.1(@types/react@18.3.26)(react@19.2.0) + '@radix-ui/react-menu': 2.1.16(@types/react-dom@18.3.7(@types/react@18.3.26))(@types/react@18.3.26)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.26))(@types/react@18.3.26)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.26)(react@19.2.0) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + optionalDependencies: + '@types/react': 18.3.26 + '@types/react-dom': 18.3.7(@types/react@18.3.26) + '@radix-ui/react-dropdown-menu@2.1.16(@types/react-dom@19.2.0(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': dependencies: '@radix-ui/primitive': 1.1.3 @@ -6867,12 +7474,29 @@ snapshots: '@types/react': 19.2.1 '@types/react-dom': 19.2.0(@types/react@19.2.1) + '@radix-ui/react-focus-guards@1.1.3(@types/react@18.3.26)(react@19.2.0)': + dependencies: + react: 19.2.0 + optionalDependencies: + '@types/react': 18.3.26 + '@radix-ui/react-focus-guards@1.1.3(@types/react@19.2.1)(react@19.2.0)': dependencies: react: 19.2.0 optionalDependencies: '@types/react': 19.2.1 + '@radix-ui/react-focus-scope@1.1.7(@types/react-dom@18.3.7(@types/react@18.3.26))(@types/react@18.3.26)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.26)(react@19.2.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.26))(@types/react@18.3.26)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@18.3.26)(react@19.2.0) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + optionalDependencies: + '@types/react': 18.3.26 + '@types/react-dom': 18.3.7(@types/react@18.3.26) + '@radix-ui/react-focus-scope@1.1.7(@types/react-dom@19.2.0(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': dependencies: '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.1)(react@19.2.0) @@ -6884,6 +7508,13 @@ snapshots: '@types/react': 19.2.1 '@types/react-dom': 19.2.0(@types/react@19.2.1) + '@radix-ui/react-id@1.1.1(@types/react@18.3.26)(react@19.2.0)': + dependencies: + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.26)(react@19.2.0) + react: 19.2.0 + optionalDependencies: + '@types/react': 18.3.26 + '@radix-ui/react-id@1.1.1(@types/react@19.2.1)(react@19.2.0)': dependencies: '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.1)(react@19.2.0) @@ -6900,6 +7531,32 @@ snapshots: '@types/react': 19.2.1 '@types/react-dom': 19.2.0(@types/react@19.2.1) + '@radix-ui/react-menu@2.1.16(@types/react-dom@18.3.7(@types/react@18.3.26))(@types/react@18.3.26)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-collection': 1.1.7(@types/react-dom@18.3.7(@types/react@18.3.26))(@types/react@18.3.26)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.26)(react@19.2.0) + '@radix-ui/react-context': 1.1.2(@types/react@18.3.26)(react@19.2.0) + '@radix-ui/react-direction': 1.1.1(@types/react@18.3.26)(react@19.2.0) + '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@18.3.7(@types/react@18.3.26))(@types/react@18.3.26)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-focus-guards': 1.1.3(@types/react@18.3.26)(react@19.2.0) + '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@18.3.7(@types/react@18.3.26))(@types/react@18.3.26)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-id': 1.1.1(@types/react@18.3.26)(react@19.2.0) + '@radix-ui/react-popper': 1.2.8(@types/react-dom@18.3.7(@types/react@18.3.26))(@types/react@18.3.26)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-portal': 1.1.9(@types/react-dom@18.3.7(@types/react@18.3.26))(@types/react@18.3.26)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@18.3.7(@types/react@18.3.26))(@types/react@18.3.26)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.26))(@types/react@18.3.26)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-roving-focus': 1.1.11(@types/react-dom@18.3.7(@types/react@18.3.26))(@types/react@18.3.26)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-slot': 1.2.3(@types/react@18.3.26)(react@19.2.0) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@18.3.26)(react@19.2.0) + aria-hidden: 1.2.6 + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + react-remove-scroll: 2.7.1(@types/react@18.3.26)(react@19.2.0) + optionalDependencies: + '@types/react': 18.3.26 + '@types/react-dom': 18.3.7(@types/react@18.3.26) + '@radix-ui/react-menu@2.1.16(@types/react-dom@19.2.0(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': dependencies: '@radix-ui/primitive': 1.1.3 @@ -6967,6 +7624,24 @@ snapshots: '@types/react': 19.2.1 '@types/react-dom': 19.2.0(@types/react@19.2.1) + '@radix-ui/react-popper@1.2.8(@types/react-dom@18.3.7(@types/react@18.3.26))(@types/react@18.3.26)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@floating-ui/react-dom': 2.1.5(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-arrow': 1.1.7(@types/react-dom@18.3.7(@types/react@18.3.26))(@types/react@18.3.26)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.26)(react@19.2.0) + '@radix-ui/react-context': 1.1.2(@types/react@18.3.26)(react@19.2.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.26))(@types/react@18.3.26)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@18.3.26)(react@19.2.0) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.26)(react@19.2.0) + '@radix-ui/react-use-rect': 1.1.1(@types/react@18.3.26)(react@19.2.0) + '@radix-ui/react-use-size': 1.1.1(@types/react@18.3.26)(react@19.2.0) + '@radix-ui/rect': 1.1.1 + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + optionalDependencies: + '@types/react': 18.3.26 + '@types/react-dom': 18.3.7(@types/react@18.3.26) + '@radix-ui/react-popper@1.2.8(@types/react-dom@19.2.0(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': dependencies: '@floating-ui/react-dom': 2.1.5(react-dom@19.2.0(react@19.2.0))(react@19.2.0) @@ -6985,6 +7660,16 @@ snapshots: '@types/react': 19.2.1 '@types/react-dom': 19.2.0(@types/react@19.2.1) + '@radix-ui/react-portal@1.1.9(@types/react-dom@18.3.7(@types/react@18.3.26))(@types/react@18.3.26)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.26))(@types/react@18.3.26)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.26)(react@19.2.0) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + optionalDependencies: + '@types/react': 18.3.26 + '@types/react-dom': 18.3.7(@types/react@18.3.26) + '@radix-ui/react-portal@1.1.9(@types/react-dom@19.2.0(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': dependencies: '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.0(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) @@ -6995,6 +7680,16 @@ snapshots: '@types/react': 19.2.1 '@types/react-dom': 19.2.0(@types/react@19.2.1) + '@radix-ui/react-presence@1.1.5(@types/react-dom@18.3.7(@types/react@18.3.26))(@types/react@18.3.26)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.26)(react@19.2.0) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.26)(react@19.2.0) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + optionalDependencies: + '@types/react': 18.3.26 + '@types/react-dom': 18.3.7(@types/react@18.3.26) + '@radix-ui/react-presence@1.1.5(@types/react-dom@19.2.0(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': dependencies: '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.1)(react@19.2.0) @@ -7005,6 +7700,15 @@ snapshots: '@types/react': 19.2.1 '@types/react-dom': 19.2.0(@types/react@19.2.1) + '@radix-ui/react-primitive@2.1.3(@types/react-dom@18.3.7(@types/react@18.3.26))(@types/react@18.3.26)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@radix-ui/react-slot': 1.2.3(@types/react@18.3.26)(react@19.2.0) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + optionalDependencies: + '@types/react': 18.3.26 + '@types/react-dom': 18.3.7(@types/react@18.3.26) + '@radix-ui/react-primitive@2.1.3(@types/react-dom@19.2.0(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': dependencies: '@radix-ui/react-slot': 1.2.3(@types/react@19.2.1)(react@19.2.0) @@ -7014,6 +7718,23 @@ snapshots: '@types/react': 19.2.1 '@types/react-dom': 19.2.0(@types/react@19.2.1) + '@radix-ui/react-roving-focus@1.1.11(@types/react-dom@18.3.7(@types/react@18.3.26))(@types/react@18.3.26)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-collection': 1.1.7(@types/react-dom@18.3.7(@types/react@18.3.26))(@types/react@18.3.26)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.26)(react@19.2.0) + '@radix-ui/react-context': 1.1.2(@types/react@18.3.26)(react@19.2.0) + '@radix-ui/react-direction': 1.1.1(@types/react@18.3.26)(react@19.2.0) + '@radix-ui/react-id': 1.1.1(@types/react@18.3.26)(react@19.2.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.26))(@types/react@18.3.26)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@18.3.26)(react@19.2.0) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.26)(react@19.2.0) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + optionalDependencies: + '@types/react': 18.3.26 + '@types/react-dom': 18.3.7(@types/react@18.3.26) + '@radix-ui/react-roving-focus@1.1.11(@types/react-dom@19.2.0(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': dependencies: '@radix-ui/primitive': 1.1.3 @@ -7077,6 +7798,15 @@ snapshots: '@types/react': 19.2.1 '@types/react-dom': 19.2.0(@types/react@19.2.1) + '@radix-ui/react-separator@1.1.7(@types/react-dom@18.3.7(@types/react@18.3.26))(@types/react@18.3.26)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.26))(@types/react@18.3.26)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + optionalDependencies: + '@types/react': 18.3.26 + '@types/react-dom': 18.3.7(@types/react@18.3.26) + '@radix-ui/react-separator@1.1.7(@types/react-dom@19.2.0(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': dependencies: '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.0(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) @@ -7105,6 +7835,13 @@ snapshots: '@types/react': 19.2.1 '@types/react-dom': 19.2.0(@types/react@19.2.1) + '@radix-ui/react-slot@1.2.3(@types/react@18.3.26)(react@19.2.0)': + dependencies: + '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.26)(react@19.2.0) + react: 19.2.0 + optionalDependencies: + '@types/react': 18.3.26 + '@radix-ui/react-slot@1.2.3(@types/react@19.2.1)(react@19.2.0)': dependencies: '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.1)(react@19.2.0) @@ -7189,6 +7926,26 @@ snapshots: '@types/react': 19.2.1 '@types/react-dom': 19.2.0(@types/react@19.2.1) + '@radix-ui/react-tooltip@1.2.8(@types/react-dom@18.3.7(@types/react@18.3.26))(@types/react@18.3.26)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@18.3.26)(react@19.2.0) + '@radix-ui/react-context': 1.1.2(@types/react@18.3.26)(react@19.2.0) + '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@18.3.7(@types/react@18.3.26))(@types/react@18.3.26)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-id': 1.1.1(@types/react@18.3.26)(react@19.2.0) + '@radix-ui/react-popper': 1.2.8(@types/react-dom@18.3.7(@types/react@18.3.26))(@types/react@18.3.26)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-portal': 1.1.9(@types/react-dom@18.3.7(@types/react@18.3.26))(@types/react@18.3.26)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@18.3.7(@types/react@18.3.26))(@types/react@18.3.26)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.26))(@types/react@18.3.26)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-slot': 1.2.3(@types/react@18.3.26)(react@19.2.0) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@18.3.26)(react@19.2.0) + '@radix-ui/react-visually-hidden': 1.2.3(@types/react-dom@18.3.7(@types/react@18.3.26))(@types/react@18.3.26)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + optionalDependencies: + '@types/react': 18.3.26 + '@types/react-dom': 18.3.7(@types/react@18.3.26) + '@radix-ui/react-tooltip@1.2.8(@types/react-dom@19.2.0(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': dependencies: '@radix-ui/primitive': 1.1.3 @@ -7209,12 +7966,26 @@ snapshots: '@types/react': 19.2.1 '@types/react-dom': 19.2.0(@types/react@19.2.1) + '@radix-ui/react-use-callback-ref@1.1.1(@types/react@18.3.26)(react@19.2.0)': + dependencies: + react: 19.2.0 + optionalDependencies: + '@types/react': 18.3.26 + '@radix-ui/react-use-callback-ref@1.1.1(@types/react@19.2.1)(react@19.2.0)': dependencies: react: 19.2.0 optionalDependencies: '@types/react': 19.2.1 + '@radix-ui/react-use-controllable-state@1.2.2(@types/react@18.3.26)(react@19.2.0)': + dependencies: + '@radix-ui/react-use-effect-event': 0.0.2(@types/react@18.3.26)(react@19.2.0) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.26)(react@19.2.0) + react: 19.2.0 + optionalDependencies: + '@types/react': 18.3.26 + '@radix-ui/react-use-controllable-state@1.2.2(@types/react@19.2.1)(react@19.2.0)': dependencies: '@radix-ui/react-use-effect-event': 0.0.2(@types/react@19.2.1)(react@19.2.0) @@ -7223,6 +7994,13 @@ snapshots: optionalDependencies: '@types/react': 19.2.1 + '@radix-ui/react-use-effect-event@0.0.2(@types/react@18.3.26)(react@19.2.0)': + dependencies: + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.26)(react@19.2.0) + react: 19.2.0 + optionalDependencies: + '@types/react': 18.3.26 + '@radix-ui/react-use-effect-event@0.0.2(@types/react@19.2.1)(react@19.2.0)': dependencies: '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.1)(react@19.2.0) @@ -7230,6 +8008,13 @@ snapshots: optionalDependencies: '@types/react': 19.2.1 + '@radix-ui/react-use-escape-keydown@1.1.1(@types/react@18.3.26)(react@19.2.0)': + dependencies: + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@18.3.26)(react@19.2.0) + react: 19.2.0 + optionalDependencies: + '@types/react': 18.3.26 + '@radix-ui/react-use-escape-keydown@1.1.1(@types/react@19.2.1)(react@19.2.0)': dependencies: '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.1)(react@19.2.0) @@ -7237,6 +8022,12 @@ snapshots: optionalDependencies: '@types/react': 19.2.1 + '@radix-ui/react-use-layout-effect@1.1.1(@types/react@18.3.26)(react@19.2.0)': + dependencies: + react: 19.2.0 + optionalDependencies: + '@types/react': 18.3.26 + '@radix-ui/react-use-layout-effect@1.1.1(@types/react@19.2.1)(react@19.2.0)': dependencies: react: 19.2.0 @@ -7249,6 +8040,13 @@ snapshots: optionalDependencies: '@types/react': 19.2.1 + '@radix-ui/react-use-rect@1.1.1(@types/react@18.3.26)(react@19.2.0)': + dependencies: + '@radix-ui/rect': 1.1.1 + react: 19.2.0 + optionalDependencies: + '@types/react': 18.3.26 + '@radix-ui/react-use-rect@1.1.1(@types/react@19.2.1)(react@19.2.0)': dependencies: '@radix-ui/rect': 1.1.1 @@ -7256,6 +8054,13 @@ snapshots: optionalDependencies: '@types/react': 19.2.1 + '@radix-ui/react-use-size@1.1.1(@types/react@18.3.26)(react@19.2.0)': + dependencies: + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@18.3.26)(react@19.2.0) + react: 19.2.0 + optionalDependencies: + '@types/react': 18.3.26 + '@radix-ui/react-use-size@1.1.1(@types/react@19.2.1)(react@19.2.0)': dependencies: '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.1)(react@19.2.0) @@ -7263,6 +8068,15 @@ snapshots: optionalDependencies: '@types/react': 19.2.1 + '@radix-ui/react-visually-hidden@1.2.3(@types/react-dom@18.3.7(@types/react@18.3.26))(@types/react@18.3.26)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@18.3.7(@types/react@18.3.26))(@types/react@18.3.26)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + optionalDependencies: + '@types/react': 18.3.26 + '@types/react-dom': 18.3.7(@types/react@18.3.26) + '@radix-ui/react-visually-hidden@1.2.3(@types/react-dom@19.2.0(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': dependencies: '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.0(@types/react@19.2.1))(@types/react@19.2.1)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) @@ -7274,53 +8088,49 @@ snapshots: '@radix-ui/rect@1.1.1': {} - '@rolldown/binding-android-arm64@1.0.0-beta.43': - optional: true - - '@rolldown/binding-darwin-arm64@1.0.0-beta.43': + '@rolldown/binding-darwin-arm64@1.0.0-beta.9-commit.d91dfb5': optional: true - '@rolldown/binding-darwin-x64@1.0.0-beta.43': + '@rolldown/binding-darwin-x64@1.0.0-beta.9-commit.d91dfb5': optional: true - '@rolldown/binding-freebsd-x64@1.0.0-beta.43': + '@rolldown/binding-freebsd-x64@1.0.0-beta.9-commit.d91dfb5': optional: true - '@rolldown/binding-linux-arm-gnueabihf@1.0.0-beta.43': + '@rolldown/binding-linux-arm-gnueabihf@1.0.0-beta.9-commit.d91dfb5': optional: true - '@rolldown/binding-linux-arm64-gnu@1.0.0-beta.43': + '@rolldown/binding-linux-arm64-gnu@1.0.0-beta.9-commit.d91dfb5': optional: true - '@rolldown/binding-linux-arm64-musl@1.0.0-beta.43': + '@rolldown/binding-linux-arm64-musl@1.0.0-beta.9-commit.d91dfb5': optional: true - '@rolldown/binding-linux-x64-gnu@1.0.0-beta.43': + '@rolldown/binding-linux-x64-gnu@1.0.0-beta.9-commit.d91dfb5': optional: true - '@rolldown/binding-linux-x64-musl@1.0.0-beta.43': + '@rolldown/binding-linux-x64-musl@1.0.0-beta.9-commit.d91dfb5': optional: true - '@rolldown/binding-openharmony-arm64@1.0.0-beta.43': - optional: true - - '@rolldown/binding-wasm32-wasi@1.0.0-beta.43': + '@rolldown/binding-wasm32-wasi@1.0.0-beta.9-commit.d91dfb5': dependencies: - '@napi-rs/wasm-runtime': 1.0.7 + '@napi-rs/wasm-runtime': 0.2.12 optional: true - '@rolldown/binding-win32-arm64-msvc@1.0.0-beta.43': + '@rolldown/binding-win32-arm64-msvc@1.0.0-beta.9-commit.d91dfb5': optional: true - '@rolldown/binding-win32-ia32-msvc@1.0.0-beta.43': + '@rolldown/binding-win32-ia32-msvc@1.0.0-beta.9-commit.d91dfb5': optional: true - '@rolldown/binding-win32-x64-msvc@1.0.0-beta.43': + '@rolldown/binding-win32-x64-msvc@1.0.0-beta.9-commit.d91dfb5': optional: true + '@rolldown/pluginutils@1.0.0-beta.27': {} + '@rolldown/pluginutils@1.0.0-beta.38': {} - '@rolldown/pluginutils@1.0.0-beta.43': {} + '@rolldown/pluginutils@1.0.0-beta.9-commit.d91dfb5': {} '@rollup/plugin-babel@5.3.1(@babel/core@7.28.4)(@types/babel__core@7.20.5)(rollup@2.79.2)': dependencies: @@ -7339,7 +8149,7 @@ snapshots: '@types/resolve': 1.20.2 deepmerge: 4.3.1 is-module: 1.0.0 - resolve: 1.22.10 + resolve: 1.22.11 optionalDependencies: rollup: 2.79.2 @@ -7353,7 +8163,7 @@ snapshots: dependencies: serialize-javascript: 6.0.2 smob: 1.5.0 - terser: 5.44.0 + terser: 5.44.1 optionalDependencies: rollup: 2.79.2 @@ -7377,128 +8187,118 @@ snapshots: optionalDependencies: rollup: 2.79.2 - '@rollup/rollup-android-arm-eabi@4.46.2': - optional: true - - '@rollup/rollup-android-arm-eabi@4.50.1': - optional: true - - '@rollup/rollup-android-arm64@4.46.2': - optional: true - - '@rollup/rollup-android-arm64@4.50.1': - optional: true - - '@rollup/rollup-darwin-arm64@4.46.2': - optional: true - - '@rollup/rollup-darwin-arm64@4.50.1': - optional: true - - '@rollup/rollup-darwin-x64@4.46.2': - optional: true - - '@rollup/rollup-darwin-x64@4.50.1': - optional: true - - '@rollup/rollup-freebsd-arm64@4.46.2': - optional: true - - '@rollup/rollup-freebsd-arm64@4.50.1': - optional: true - - '@rollup/rollup-freebsd-x64@4.46.2': - optional: true - - '@rollup/rollup-freebsd-x64@4.50.1': - optional: true - - '@rollup/rollup-linux-arm-gnueabihf@4.46.2': - optional: true - - '@rollup/rollup-linux-arm-gnueabihf@4.50.1': - optional: true + '@rollup/pluginutils@5.3.0(rollup@4.52.5)': + dependencies: + '@types/estree': 1.0.8 + estree-walker: 2.0.2 + picomatch: 4.0.3 + optionalDependencies: + rollup: 4.52.5 - '@rollup/rollup-linux-arm-musleabihf@4.46.2': + '@rollup/rollup-android-arm-eabi@4.52.5': optional: true - '@rollup/rollup-linux-arm-musleabihf@4.50.1': + '@rollup/rollup-android-arm64@4.52.5': optional: true - '@rollup/rollup-linux-arm64-gnu@4.46.2': + '@rollup/rollup-darwin-arm64@4.52.5': optional: true - '@rollup/rollup-linux-arm64-gnu@4.50.1': + '@rollup/rollup-darwin-x64@4.52.5': optional: true - '@rollup/rollup-linux-arm64-musl@4.46.2': + '@rollup/rollup-freebsd-arm64@4.52.5': optional: true - '@rollup/rollup-linux-arm64-musl@4.50.1': + '@rollup/rollup-freebsd-x64@4.52.5': optional: true - '@rollup/rollup-linux-loongarch64-gnu@4.46.2': + '@rollup/rollup-linux-arm-gnueabihf@4.52.5': optional: true - '@rollup/rollup-linux-loongarch64-gnu@4.50.1': + '@rollup/rollup-linux-arm-musleabihf@4.52.5': optional: true - '@rollup/rollup-linux-ppc64-gnu@4.46.2': + '@rollup/rollup-linux-arm64-gnu@4.52.5': optional: true - '@rollup/rollup-linux-ppc64-gnu@4.50.1': + '@rollup/rollup-linux-arm64-musl@4.52.5': optional: true - '@rollup/rollup-linux-riscv64-gnu@4.46.2': + '@rollup/rollup-linux-loong64-gnu@4.52.5': optional: true - '@rollup/rollup-linux-riscv64-gnu@4.50.1': + '@rollup/rollup-linux-ppc64-gnu@4.52.5': optional: true - '@rollup/rollup-linux-riscv64-musl@4.46.2': + '@rollup/rollup-linux-riscv64-gnu@4.52.5': optional: true - '@rollup/rollup-linux-riscv64-musl@4.50.1': + '@rollup/rollup-linux-riscv64-musl@4.52.5': optional: true - '@rollup/rollup-linux-s390x-gnu@4.46.2': + '@rollup/rollup-linux-s390x-gnu@4.52.5': optional: true - '@rollup/rollup-linux-s390x-gnu@4.50.1': + '@rollup/rollup-linux-x64-gnu@4.52.5': optional: true - '@rollup/rollup-linux-x64-gnu@4.46.2': + '@rollup/rollup-linux-x64-musl@4.52.5': optional: true - '@rollup/rollup-linux-x64-gnu@4.50.1': + '@rollup/rollup-openharmony-arm64@4.52.5': optional: true - '@rollup/rollup-linux-x64-musl@4.46.2': + '@rollup/rollup-win32-arm64-msvc@4.52.5': optional: true - '@rollup/rollup-linux-x64-musl@4.50.1': + '@rollup/rollup-win32-ia32-msvc@4.52.5': optional: true - '@rollup/rollup-openharmony-arm64@4.50.1': + '@rollup/rollup-win32-x64-gnu@4.52.5': optional: true - '@rollup/rollup-win32-arm64-msvc@4.46.2': + '@rollup/rollup-win32-x64-msvc@4.52.5': optional: true - '@rollup/rollup-win32-arm64-msvc@4.50.1': - optional: true + '@rushstack/node-core-library@5.17.1(@types/node@24.7.0)': + dependencies: + ajv: 8.13.0 + ajv-draft-04: 1.0.0(ajv@8.13.0) + ajv-formats: 3.0.1(ajv@8.13.0) + fs-extra: 11.3.2 + import-lazy: 4.0.0 + jju: 1.4.0 + resolve: 1.22.11 + semver: 7.5.4 + optionalDependencies: + '@types/node': 24.7.0 - '@rollup/rollup-win32-ia32-msvc@4.46.2': - optional: true + '@rushstack/problem-matcher@0.1.1(@types/node@24.7.0)': + optionalDependencies: + '@types/node': 24.7.0 - '@rollup/rollup-win32-ia32-msvc@4.50.1': - optional: true + '@rushstack/rig-package@0.6.0': + dependencies: + resolve: 1.22.11 + strip-json-comments: 3.1.1 - '@rollup/rollup-win32-x64-msvc@4.46.2': - optional: true + '@rushstack/terminal@0.19.2(@types/node@24.7.0)': + dependencies: + '@rushstack/node-core-library': 5.17.1(@types/node@24.7.0) + '@rushstack/problem-matcher': 0.1.1(@types/node@24.7.0) + supports-color: 8.1.1 + optionalDependencies: + '@types/node': 24.7.0 - '@rollup/rollup-win32-x64-msvc@4.50.1': - optional: true + '@rushstack/ts-command-line@5.1.2(@types/node@24.7.0)': + dependencies: + '@rushstack/terminal': 0.19.2(@types/node@24.7.0) + '@types/argparse': 1.0.38 + argparse: 1.0.10 + string-argv: 0.3.2 + transitivePeerDependencies: + - '@types/node' '@serialport/binding-mock@10.2.2': dependencies: @@ -7573,42 +8373,88 @@ snapshots: source-map-js: 1.2.1 tailwindcss: 4.1.14 + '@tailwindcss/node@4.1.15': + dependencies: + '@jridgewell/remapping': 2.3.5 + enhanced-resolve: 5.18.3 + jiti: 2.6.1 + lightningcss: 1.30.2 + magic-string: 0.30.19 + source-map-js: 1.2.1 + tailwindcss: 4.1.15 + '@tailwindcss/oxide-android-arm64@4.1.14': optional: true + '@tailwindcss/oxide-android-arm64@4.1.15': + optional: true + '@tailwindcss/oxide-darwin-arm64@4.1.14': optional: true - '@tailwindcss/oxide-darwin-x64@4.1.14': + '@tailwindcss/oxide-darwin-arm64@4.1.15': + optional: true + + '@tailwindcss/oxide-darwin-x64@4.1.14': + optional: true + + '@tailwindcss/oxide-darwin-x64@4.1.15': optional: true '@tailwindcss/oxide-freebsd-x64@4.1.14': optional: true + '@tailwindcss/oxide-freebsd-x64@4.1.15': + optional: true + '@tailwindcss/oxide-linux-arm-gnueabihf@4.1.14': optional: true + '@tailwindcss/oxide-linux-arm-gnueabihf@4.1.15': + optional: true + '@tailwindcss/oxide-linux-arm64-gnu@4.1.14': optional: true + '@tailwindcss/oxide-linux-arm64-gnu@4.1.15': + optional: true + '@tailwindcss/oxide-linux-arm64-musl@4.1.14': optional: true + '@tailwindcss/oxide-linux-arm64-musl@4.1.15': + optional: true + '@tailwindcss/oxide-linux-x64-gnu@4.1.14': optional: true + '@tailwindcss/oxide-linux-x64-gnu@4.1.15': + optional: true + '@tailwindcss/oxide-linux-x64-musl@4.1.14': optional: true + '@tailwindcss/oxide-linux-x64-musl@4.1.15': + optional: true + '@tailwindcss/oxide-wasm32-wasi@4.1.14': optional: true + '@tailwindcss/oxide-wasm32-wasi@4.1.15': + optional: true + '@tailwindcss/oxide-win32-arm64-msvc@4.1.14': optional: true + '@tailwindcss/oxide-win32-arm64-msvc@4.1.15': + optional: true + '@tailwindcss/oxide-win32-x64-msvc@4.1.14': optional: true + '@tailwindcss/oxide-win32-x64-msvc@4.1.15': + optional: true + '@tailwindcss/oxide@4.1.14': dependencies: detect-libc: 2.0.4 @@ -7627,22 +8473,45 @@ snapshots: '@tailwindcss/oxide-win32-arm64-msvc': 4.1.14 '@tailwindcss/oxide-win32-x64-msvc': 4.1.14 - '@tailwindcss/vite@4.1.14(vite@7.1.9(@types/node@24.7.0)(jiti@2.6.1)(lightningcss@1.30.1)(terser@5.44.0)(tsx@4.20.3))': + '@tailwindcss/oxide@4.1.15': + optionalDependencies: + '@tailwindcss/oxide-android-arm64': 4.1.15 + '@tailwindcss/oxide-darwin-arm64': 4.1.15 + '@tailwindcss/oxide-darwin-x64': 4.1.15 + '@tailwindcss/oxide-freebsd-x64': 4.1.15 + '@tailwindcss/oxide-linux-arm-gnueabihf': 4.1.15 + '@tailwindcss/oxide-linux-arm64-gnu': 4.1.15 + '@tailwindcss/oxide-linux-arm64-musl': 4.1.15 + '@tailwindcss/oxide-linux-x64-gnu': 4.1.15 + '@tailwindcss/oxide-linux-x64-musl': 4.1.15 + '@tailwindcss/oxide-wasm32-wasi': 4.1.15 + '@tailwindcss/oxide-win32-arm64-msvc': 4.1.15 + '@tailwindcss/oxide-win32-x64-msvc': 4.1.15 + + '@tailwindcss/postcss@4.1.15': + dependencies: + '@alloc/quick-lru': 5.2.0 + '@tailwindcss/node': 4.1.15 + '@tailwindcss/oxide': 4.1.15 + postcss: 8.5.6 + tailwindcss: 4.1.15 + + '@tailwindcss/vite@4.1.14(vite@7.1.11(@types/node@24.7.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.3))': dependencies: '@tailwindcss/node': 4.1.14 '@tailwindcss/oxide': 4.1.14 tailwindcss: 4.1.14 - vite: 7.1.9(@types/node@24.7.0)(jiti@2.6.1)(lightningcss@1.30.1)(terser@5.44.0)(tsx@4.20.3) + vite: 7.1.11(@types/node@24.7.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.3) '@tanstack/history@1.132.31': {} - '@tanstack/react-router-devtools@1.132.47(@tanstack/react-router@1.132.47(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@tanstack/router-core@1.132.47)(@types/node@24.7.0)(csstype@3.1.3)(jiti@2.6.1)(lightningcss@1.30.1)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(terser@5.44.0)(tiny-invariant@1.3.3)(tsx@4.20.3)': + '@tanstack/react-router-devtools@1.132.47(@tanstack/react-router@1.132.47(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@tanstack/router-core@1.132.47)(@types/node@24.7.0)(csstype@3.1.3)(jiti@2.6.1)(lightningcss@1.30.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(terser@5.44.1)(tiny-invariant@1.3.3)(tsx@4.20.3)': dependencies: '@tanstack/react-router': 1.132.47(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@tanstack/router-devtools-core': 1.132.47(@tanstack/router-core@1.132.47)(@types/node@24.7.0)(csstype@3.1.3)(jiti@2.6.1)(lightningcss@1.30.1)(terser@5.44.0)(tiny-invariant@1.3.3)(tsx@4.20.3) + '@tanstack/router-devtools-core': 1.132.47(@tanstack/router-core@1.132.47)(@types/node@24.7.0)(csstype@3.1.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tiny-invariant@1.3.3)(tsx@4.20.3) react: 19.2.0 react-dom: 19.2.0(react@19.2.0) - vite: 7.1.9(@types/node@24.7.0)(jiti@2.6.1)(lightningcss@1.30.1)(terser@5.44.0)(tsx@4.20.3) + vite: 7.1.11(@types/node@24.7.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.3) transitivePeerDependencies: - '@tanstack/router-core' - '@types/node' @@ -7695,13 +8564,13 @@ snapshots: tiny-invariant: 1.3.3 tiny-warning: 1.0.3 - '@tanstack/router-devtools-core@1.132.47(@tanstack/router-core@1.132.47)(@types/node@24.7.0)(csstype@3.1.3)(jiti@2.6.1)(lightningcss@1.30.1)(terser@5.44.0)(tiny-invariant@1.3.3)(tsx@4.20.3)': + '@tanstack/router-devtools-core@1.132.47(@tanstack/router-core@1.132.47)(@types/node@24.7.0)(csstype@3.1.3)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tiny-invariant@1.3.3)(tsx@4.20.3)': dependencies: '@tanstack/router-core': 1.132.47 clsx: 2.1.1 goober: 2.1.16(csstype@3.1.3) tiny-invariant: 1.3.3 - vite: 7.1.9(@types/node@24.7.0)(jiti@2.6.1)(lightningcss@1.30.1)(terser@5.44.0)(tsx@4.20.3) + vite: 7.1.11(@types/node@24.7.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.3) optionalDependencies: csstype: 3.1.3 transitivePeerDependencies: @@ -7717,15 +8586,15 @@ snapshots: - tsx - yaml - '@tanstack/router-devtools@1.132.47(@tanstack/react-router@1.132.47(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@tanstack/router-core@1.132.47)(@types/node@24.7.0)(csstype@3.1.3)(jiti@2.6.1)(lightningcss@1.30.1)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(terser@5.44.0)(tiny-invariant@1.3.3)(tsx@4.20.3)': + '@tanstack/router-devtools@1.132.47(@tanstack/react-router@1.132.47(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@tanstack/router-core@1.132.47)(@types/node@24.7.0)(csstype@3.1.3)(jiti@2.6.1)(lightningcss@1.30.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(terser@5.44.1)(tiny-invariant@1.3.3)(tsx@4.20.3)': dependencies: '@tanstack/react-router': 1.132.47(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@tanstack/react-router-devtools': 1.132.47(@tanstack/react-router@1.132.47(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@tanstack/router-core@1.132.47)(@types/node@24.7.0)(csstype@3.1.3)(jiti@2.6.1)(lightningcss@1.30.1)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(terser@5.44.0)(tiny-invariant@1.3.3)(tsx@4.20.3) + '@tanstack/react-router-devtools': 1.132.47(@tanstack/react-router@1.132.47(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(@tanstack/router-core@1.132.47)(@types/node@24.7.0)(csstype@3.1.3)(jiti@2.6.1)(lightningcss@1.30.2)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(terser@5.44.1)(tiny-invariant@1.3.3)(tsx@4.20.3) clsx: 2.1.1 goober: 2.1.16(csstype@3.1.3) react: 19.2.0 react-dom: 19.2.0(react@19.2.0) - vite: 7.1.9(@types/node@24.7.0)(jiti@2.6.1)(lightningcss@1.30.1)(terser@5.44.0)(tsx@4.20.3) + vite: 7.1.11(@types/node@24.7.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.3) optionalDependencies: csstype: 3.1.3 transitivePeerDependencies: @@ -7756,7 +8625,7 @@ snapshots: transitivePeerDependencies: - supports-color - '@tanstack/router-plugin@1.132.47(@tanstack/react-router@1.132.47(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(vite@7.1.9(@types/node@24.7.0)(jiti@2.6.1)(lightningcss@1.30.1)(terser@5.44.0)(tsx@4.20.3))': + '@tanstack/router-plugin@1.132.47(@tanstack/react-router@1.132.47(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(vite@7.1.11(@types/node@24.7.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.3))': dependencies: '@babel/core': 7.28.0 '@babel/plugin-syntax-jsx': 7.27.1(@babel/core@7.28.0) @@ -7774,7 +8643,7 @@ snapshots: zod: 3.25.76 optionalDependencies: '@tanstack/react-router': 1.132.47(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - vite: 7.1.9(@types/node@24.7.0)(jiti@2.6.1)(lightningcss@1.30.1)(terser@5.44.0)(tsx@4.20.3) + vite: 7.1.11(@types/node@24.7.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.3) transitivePeerDependencies: - supports-color @@ -8944,6 +9813,8 @@ snapshots: tslib: 2.8.1 optional: true + '@types/argparse@1.0.38': {} + '@types/aria-query@5.0.4': {} '@types/babel__core@7.20.5': @@ -9000,7 +9871,7 @@ snapshots: '@types/js-cookie@3.0.6': {} - '@types/node@20.19.21': + '@types/node@20.19.25': dependencies: undici-types: 6.21.0 @@ -9012,10 +9883,21 @@ snapshots: dependencies: undici-types: 7.14.0 + '@types/prop-types@15.7.15': {} + + '@types/react-dom@18.3.7(@types/react@18.3.26)': + dependencies: + '@types/react': 18.3.26 + '@types/react-dom@19.2.0(@types/react@19.2.1)': dependencies: '@types/react': 19.2.1 + '@types/react@18.3.26': + dependencies: + '@types/prop-types': 15.7.15 + csstype: 3.1.3 + '@types/react@19.2.1': dependencies: csstype: 3.1.3 @@ -9058,7 +9940,23 @@ snapshots: optionalDependencies: maplibre-gl: 5.8.0 - '@vitejs/plugin-react@5.0.4(vite@7.1.9(@types/node@24.7.0)(jiti@2.6.1)(lightningcss@1.30.1)(terser@5.44.0)(tsx@4.20.3))': + '@vitejs/plugin-basic-ssl@2.1.0(vite@7.1.11(@types/node@24.7.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.3))': + dependencies: + vite: 7.1.11(@types/node@24.7.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.3) + + '@vitejs/plugin-react@4.7.0(vite@7.1.11(@types/node@24.7.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.3))': + dependencies: + '@babel/core': 7.28.4 + '@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.28.4) + '@babel/plugin-transform-react-jsx-source': 7.27.1(@babel/core@7.28.4) + '@rolldown/pluginutils': 1.0.0-beta.27 + '@types/babel__core': 7.20.5 + react-refresh: 0.17.0 + vite: 7.1.11(@types/node@24.7.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.3) + transitivePeerDependencies: + - supports-color + + '@vitejs/plugin-react@5.0.4(vite@7.1.11(@types/node@24.7.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.3))': dependencies: '@babel/core': 7.28.4 '@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.28.4) @@ -9066,7 +9964,7 @@ snapshots: '@rolldown/pluginutils': 1.0.0-beta.38 '@types/babel__core': 7.20.5 react-refresh: 0.17.0 - vite: 7.1.9(@types/node@24.7.0)(jiti@2.6.1)(lightningcss@1.30.1)(terser@5.44.0)(tsx@4.20.3) + vite: 7.1.11(@types/node@24.7.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.3) transitivePeerDependencies: - supports-color @@ -9078,21 +9976,21 @@ snapshots: chai: 5.2.1 tinyrainbow: 2.0.0 - '@vitest/mocker@3.2.4(vite@7.1.1(@types/node@24.3.1)(jiti@2.6.1)(lightningcss@1.30.1)(terser@5.44.0)(tsx@4.20.3))': + '@vitest/mocker@3.2.4(vite@7.1.11(@types/node@24.3.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.3))': dependencies: '@vitest/spy': 3.2.4 estree-walker: 3.0.3 - magic-string: 0.30.17 + magic-string: 0.30.19 optionalDependencies: - vite: 7.1.1(@types/node@24.3.1)(jiti@2.6.1)(lightningcss@1.30.1)(terser@5.44.0)(tsx@4.20.3) + vite: 7.1.11(@types/node@24.3.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.3) - '@vitest/mocker@3.2.4(vite@7.1.1(@types/node@24.7.0)(jiti@2.6.1)(lightningcss@1.30.1)(terser@5.44.0)(tsx@4.20.3))': + '@vitest/mocker@3.2.4(vite@7.1.11(@types/node@24.7.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.3))': dependencies: '@vitest/spy': 3.2.4 estree-walker: 3.0.3 - magic-string: 0.30.17 + magic-string: 0.30.19 optionalDependencies: - vite: 7.1.1(@types/node@24.7.0)(jiti@2.6.1)(lightningcss@1.30.1)(terser@5.44.0)(tsx@4.20.3) + vite: 7.1.11(@types/node@24.7.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.3) '@vitest/pretty-format@3.2.4': dependencies: @@ -9107,7 +10005,7 @@ snapshots: '@vitest/snapshot@3.2.4': dependencies: '@vitest/pretty-format': 3.2.4 - magic-string: 0.30.17 + magic-string: 0.30.19 pathe: 2.0.3 '@vitest/spy@3.2.4': @@ -9120,8 +10018,75 @@ snapshots: loupe: 3.2.0 tinyrainbow: 2.0.0 + '@volar/language-core@2.4.23': + dependencies: + '@volar/source-map': 2.4.23 + + '@volar/source-map@2.4.23': {} + + '@volar/typescript@2.4.23': + dependencies: + '@volar/language-core': 2.4.23 + path-browserify: 1.0.1 + vscode-uri: 3.1.0 + + '@vue/compiler-core@3.5.22': + dependencies: + '@babel/parser': 7.28.4 + '@vue/shared': 3.5.22 + entities: 4.5.0 + estree-walker: 2.0.2 + source-map-js: 1.2.1 + + '@vue/compiler-dom@3.5.22': + dependencies: + '@vue/compiler-core': 3.5.22 + '@vue/shared': 3.5.22 + + '@vue/compiler-vue2@2.7.16': + dependencies: + de-indent: 1.0.2 + he: 1.2.0 + + '@vue/language-core@2.2.0(typescript@5.9.3)': + dependencies: + '@volar/language-core': 2.4.23 + '@vue/compiler-dom': 3.5.22 + '@vue/compiler-vue2': 2.7.16 + '@vue/shared': 3.5.22 + alien-signals: 0.4.14 + minimatch: 9.0.5 + muggle-string: 0.4.1 + path-browserify: 1.0.1 + optionalDependencies: + typescript: 5.9.3 + + '@vue/shared@3.5.22': {} + acorn@8.15.0: {} + ajv-draft-04@1.0.0(ajv@8.13.0): + optionalDependencies: + ajv: 8.13.0 + + ajv-formats@3.0.1(ajv@8.13.0): + optionalDependencies: + ajv: 8.13.0 + + ajv@8.12.0: + dependencies: + fast-deep-equal: 3.1.3 + json-schema-traverse: 1.0.0 + require-from-string: 2.0.2 + uri-js: 4.4.1 + + ajv@8.13.0: + dependencies: + fast-deep-equal: 3.1.3 + json-schema-traverse: 1.0.0 + require-from-string: 2.0.2 + uri-js: 4.4.1 + ajv@8.17.1: dependencies: fast-deep-equal: 3.1.3 @@ -9129,6 +10094,8 @@ snapshots: json-schema-traverse: 1.0.0 require-from-string: 2.0.2 + alien-signals@0.4.14: {} + ansi-regex@5.0.1: {} ansi-regex@6.2.2: {} @@ -9150,6 +10117,10 @@ snapshots: normalize-path: 3.0.0 picomatch: 2.3.1 + argparse@1.0.10: + dependencies: + sprintf-js: 1.0.3 + aria-hidden@1.2.6: dependencies: tslib: 2.8.1 @@ -9221,7 +10192,7 @@ snapshots: babel-plugin-polyfill-corejs2@0.4.14(@babel/core@7.28.4): dependencies: - '@babel/compat-data': 7.28.4 + '@babel/compat-data': 7.28.5 '@babel/core': 7.28.4 '@babel/helper-define-polyfill-provider': 0.6.5(@babel/core@7.28.4) semver: 6.3.1 @@ -9232,7 +10203,7 @@ snapshots: dependencies: '@babel/core': 7.28.4 '@babel/helper-define-polyfill-provider': 0.6.5(@babel/core@7.28.4) - core-js-compat: 3.46.0 + core-js-compat: 3.47.0 transitivePeerDependencies: - supports-color @@ -9247,7 +10218,7 @@ snapshots: base64-js@1.5.1: {} - baseline-browser-mapping@2.8.16: {} + baseline-browser-mapping@2.8.31: {} bignumber.js@9.3.1: {} @@ -9284,13 +10255,13 @@ snapshots: node-releases: 2.0.20 update-browserslist-db: 1.1.3(browserslist@4.25.4) - browserslist@4.26.3: + browserslist@4.28.0: dependencies: - baseline-browser-mapping: 2.8.16 - caniuse-lite: 1.0.30001750 - electron-to-chromium: 1.5.234 - node-releases: 2.0.23 - update-browserslist-db: 1.1.3(browserslist@4.26.3) + baseline-browser-mapping: 2.8.31 + caniuse-lite: 1.0.30001757 + electron-to-chromium: 1.5.260 + node-releases: 2.0.27 + update-browserslist-db: 1.1.4(browserslist@4.28.0) buffer-from@1.1.2: {} @@ -9331,7 +10302,7 @@ snapshots: caniuse-lite@1.0.30001741: {} - caniuse-lite@1.0.30001750: {} + caniuse-lite@1.0.30001757: {} chai@5.2.1: dependencies: @@ -9405,6 +10376,8 @@ snapshots: common-tags@1.8.2: {} + compare-versions@6.1.1: {} + concat-map@0.0.1: {} concaveman@1.2.1: @@ -9414,6 +10387,10 @@ snapshots: robust-predicates: 2.0.4 tinyqueue: 2.0.3 + confbox@0.1.8: {} + + confbox@0.2.2: {} + connect-history-api-fallback@1.6.0: {} consola@2.15.3: {} @@ -9422,9 +10399,9 @@ snapshots: cookie-es@2.0.0: {} - core-js-compat@3.46.0: + core-js-compat@3.47.0: dependencies: - browserslist: 4.26.3 + browserslist: 4.28.0 core-util-is@1.0.3: {} @@ -9488,6 +10465,8 @@ snapshots: es-errors: 1.3.0 is-data-view: 1.0.2 + de-indent@1.0.2: {} + debug@4.4.0: dependencies: ms: 2.1.3 @@ -9588,7 +10567,7 @@ snapshots: electron-to-chromium@1.5.217: {} - electron-to-chromium@1.5.234: {} + electron-to-chromium@1.5.260: {} emoji-regex@8.0.0: {} @@ -9607,6 +10586,8 @@ snapshots: entities@2.2.0: {} + entities@4.5.0: {} + es-abstract@1.24.0: dependencies: array-buffer-byte-length: 1.0.2 @@ -9687,34 +10668,34 @@ snapshots: is-date-object: 1.1.0 is-symbol: 1.1.1 - esbuild@0.25.8: - optionalDependencies: - '@esbuild/aix-ppc64': 0.25.8 - '@esbuild/android-arm': 0.25.8 - '@esbuild/android-arm64': 0.25.8 - '@esbuild/android-x64': 0.25.8 - '@esbuild/darwin-arm64': 0.25.8 - '@esbuild/darwin-x64': 0.25.8 - '@esbuild/freebsd-arm64': 0.25.8 - '@esbuild/freebsd-x64': 0.25.8 - '@esbuild/linux-arm': 0.25.8 - '@esbuild/linux-arm64': 0.25.8 - '@esbuild/linux-ia32': 0.25.8 - '@esbuild/linux-loong64': 0.25.8 - '@esbuild/linux-mips64el': 0.25.8 - '@esbuild/linux-ppc64': 0.25.8 - '@esbuild/linux-riscv64': 0.25.8 - '@esbuild/linux-s390x': 0.25.8 - '@esbuild/linux-x64': 0.25.8 - '@esbuild/netbsd-arm64': 0.25.8 - '@esbuild/netbsd-x64': 0.25.8 - '@esbuild/openbsd-arm64': 0.25.8 - '@esbuild/openbsd-x64': 0.25.8 - '@esbuild/openharmony-arm64': 0.25.8 - '@esbuild/sunos-x64': 0.25.8 - '@esbuild/win32-arm64': 0.25.8 - '@esbuild/win32-ia32': 0.25.8 - '@esbuild/win32-x64': 0.25.8 + esbuild@0.25.11: + optionalDependencies: + '@esbuild/aix-ppc64': 0.25.11 + '@esbuild/android-arm': 0.25.11 + '@esbuild/android-arm64': 0.25.11 + '@esbuild/android-x64': 0.25.11 + '@esbuild/darwin-arm64': 0.25.11 + '@esbuild/darwin-x64': 0.25.11 + '@esbuild/freebsd-arm64': 0.25.11 + '@esbuild/freebsd-x64': 0.25.11 + '@esbuild/linux-arm': 0.25.11 + '@esbuild/linux-arm64': 0.25.11 + '@esbuild/linux-ia32': 0.25.11 + '@esbuild/linux-loong64': 0.25.11 + '@esbuild/linux-mips64el': 0.25.11 + '@esbuild/linux-ppc64': 0.25.11 + '@esbuild/linux-riscv64': 0.25.11 + '@esbuild/linux-s390x': 0.25.11 + '@esbuild/linux-x64': 0.25.11 + '@esbuild/netbsd-arm64': 0.25.11 + '@esbuild/netbsd-x64': 0.25.11 + '@esbuild/openbsd-arm64': 0.25.11 + '@esbuild/openbsd-x64': 0.25.11 + '@esbuild/openharmony-arm64': 0.25.11 + '@esbuild/sunos-x64': 0.25.11 + '@esbuild/win32-arm64': 0.25.11 + '@esbuild/win32-ia32': 0.25.11 + '@esbuild/win32-x64': 0.25.11 esbuild@0.25.9: optionalDependencies: @@ -9761,6 +10742,8 @@ snapshots: expect-type@1.2.2: {} + exsolve@1.0.7: {} + extend-shallow@2.0.1: dependencies: is-extendable: 0.1.1 @@ -9821,6 +10804,12 @@ snapshots: jsonfile: 6.1.0 universalify: 2.0.1 + fs-extra@11.3.2: + dependencies: + graceful-fs: 4.2.11 + jsonfile: 6.2.0 + universalify: 2.0.1 + fs-extra@9.1.0: dependencies: at-least-node: 1.0.0 @@ -9941,14 +10930,16 @@ snapshots: commander: 12.1.0 simple-zstd: 1.4.2 - happy-dom@20.0.0: + happy-dom@20.0.2: dependencies: - '@types/node': 20.19.21 + '@types/node': 20.19.25 '@types/whatwg-mimetype': 3.0.2 whatwg-mimetype: 3.0.0 has-bigints@1.1.0: {} + has-flag@4.0.0: {} + has-property-descriptors@1.0.2: dependencies: es-define-property: 1.0.1 @@ -10007,6 +10998,8 @@ snapshots: immer@10.1.3: {} + import-lazy@4.0.0: {} + indent-string@4.0.0: {} inflight@1.0.6: @@ -10176,10 +11169,10 @@ snapshots: filelist: 1.0.4 picocolors: 1.1.1 - jiti@2.5.1: {} - jiti@2.6.1: {} + jju@1.4.0: {} + js-cookie@3.0.5: {} js-tokens@4.0.0: {} @@ -10216,38 +11209,73 @@ snapshots: kdbush@4.0.2: {} + kolorist@1.8.0: {} + leven@3.1.0: {} + lightningcss-android-arm64@1.30.2: + optional: true + lightningcss-darwin-arm64@1.30.1: optional: true + lightningcss-darwin-arm64@1.30.2: + optional: true + lightningcss-darwin-x64@1.30.1: optional: true + lightningcss-darwin-x64@1.30.2: + optional: true + lightningcss-freebsd-x64@1.30.1: optional: true + lightningcss-freebsd-x64@1.30.2: + optional: true + lightningcss-linux-arm-gnueabihf@1.30.1: optional: true + lightningcss-linux-arm-gnueabihf@1.30.2: + optional: true + lightningcss-linux-arm64-gnu@1.30.1: optional: true + lightningcss-linux-arm64-gnu@1.30.2: + optional: true + lightningcss-linux-arm64-musl@1.30.1: optional: true + lightningcss-linux-arm64-musl@1.30.2: + optional: true + lightningcss-linux-x64-gnu@1.30.1: optional: true + lightningcss-linux-x64-gnu@1.30.2: + optional: true + lightningcss-linux-x64-musl@1.30.1: optional: true + lightningcss-linux-x64-musl@1.30.2: + optional: true + lightningcss-win32-arm64-msvc@1.30.1: optional: true + lightningcss-win32-arm64-msvc@1.30.2: + optional: true + lightningcss-win32-x64-msvc@1.30.1: optional: true + lightningcss-win32-x64-msvc@1.30.2: + optional: true + lightningcss@1.30.1: dependencies: detect-libc: 2.0.4 @@ -10263,6 +11291,28 @@ snapshots: lightningcss-win32-arm64-msvc: 1.30.1 lightningcss-win32-x64-msvc: 1.30.1 + lightningcss@1.30.2: + dependencies: + detect-libc: 2.0.4 + optionalDependencies: + lightningcss-android-arm64: 1.30.2 + lightningcss-darwin-arm64: 1.30.2 + lightningcss-darwin-x64: 1.30.2 + lightningcss-freebsd-x64: 1.30.2 + lightningcss-linux-arm-gnueabihf: 1.30.2 + lightningcss-linux-arm64-gnu: 1.30.2 + lightningcss-linux-arm64-musl: 1.30.2 + lightningcss-linux-x64-gnu: 1.30.2 + lightningcss-linux-x64-musl: 1.30.2 + lightningcss-win32-arm64-msvc: 1.30.2 + lightningcss-win32-x64-msvc: 1.30.2 + + local-pkg@1.1.2: + dependencies: + mlly: 1.8.0 + pkg-types: 2.3.0 + quansync: 0.2.11 + lodash.debounce@4.0.8: {} lodash.sortby@4.7.0: {} @@ -10281,6 +11331,10 @@ snapshots: dependencies: yallist: 3.1.1 + lru-cache@6.0.0: + dependencies: + yallist: 4.0.0 + lucide-react@0.545.0(react@19.2.0): dependencies: react: 19.2.0 @@ -10291,10 +11345,6 @@ snapshots: dependencies: sourcemap-codec: 1.4.8 - magic-string@0.30.17: - dependencies: - '@jridgewell/sourcemap-codec': 1.5.4 - magic-string@0.30.19: dependencies: '@jridgewell/sourcemap-codec': 1.5.5 @@ -10349,6 +11399,10 @@ snapshots: dependencies: brace-expansion: 2.0.2 + minimatch@9.0.5: + dependencies: + brace-expansion: 2.0.2 + minimist@1.2.8: {} minipass@7.1.2: {} @@ -10357,8 +11411,19 @@ snapshots: dependencies: minipass: 7.1.2 + mlly@1.8.0: + dependencies: + acorn: 8.15.0 + pathe: 2.0.3 + pkg-types: 1.3.1 + ufo: 1.6.1 + + mri@1.2.0: {} + ms@2.1.3: {} + muggle-string@0.4.1: {} + murmurhash-js@1.0.0: {} nanoid@3.3.11: {} @@ -10385,7 +11450,7 @@ snapshots: node-releases@2.0.20: {} - node-releases@2.0.23: {} + node-releases@2.0.27: {} normalize-path@3.0.0: {} @@ -10418,8 +11483,12 @@ snapshots: object-keys: 1.1.1 safe-push-apply: 1.0.0 + p-map@7.0.3: {} + package-json-from-dist@1.0.1: {} + package-manager-detector@1.5.0: {} + param-case@3.0.4: dependencies: dot-case: 3.0.4 @@ -10430,6 +11499,8 @@ snapshots: no-case: 3.0.4 tslib: 2.8.1 + path-browserify@1.0.1: {} + path-is-absolute@1.0.1: {} path-key@3.1.1: {} @@ -10463,6 +11534,18 @@ snapshots: picomatch@4.0.3: {} + pkg-types@1.3.1: + dependencies: + confbox: 0.1.8 + mlly: 1.8.0 + pathe: 2.0.3 + + pkg-types@2.3.0: + dependencies: + confbox: 0.2.2 + exsolve: 1.0.7 + pathe: 2.0.3 + point-in-polygon-hao@1.2.4: dependencies: robust-predicates: 3.0.2 @@ -10506,6 +11589,13 @@ snapshots: protocol-buffers-schema@3.6.0: {} + publint@0.3.15: + dependencies: + '@publint/pack': 0.1.2 + package-manager-detector: 1.5.0 + picocolors: 1.1.1 + sade: 1.8.1 + punycode@2.3.1: {} qrcode-generator@2.0.4: {} @@ -10575,6 +11665,14 @@ snapshots: react-refresh@0.17.0: {} + react-remove-scroll-bar@2.3.8(@types/react@18.3.26)(react@19.2.0): + dependencies: + react: 19.2.0 + react-style-singleton: 2.2.3(@types/react@18.3.26)(react@19.2.0) + tslib: 2.8.1 + optionalDependencies: + '@types/react': 18.3.26 + react-remove-scroll-bar@2.3.8(@types/react@19.2.1)(react@19.2.0): dependencies: react: 19.2.0 @@ -10583,6 +11681,17 @@ snapshots: optionalDependencies: '@types/react': 19.2.1 + react-remove-scroll@2.7.1(@types/react@18.3.26)(react@19.2.0): + dependencies: + react: 19.2.0 + react-remove-scroll-bar: 2.3.8(@types/react@18.3.26)(react@19.2.0) + react-style-singleton: 2.2.3(@types/react@18.3.26)(react@19.2.0) + tslib: 2.8.1 + use-callback-ref: 1.3.3(@types/react@18.3.26)(react@19.2.0) + use-sidecar: 1.1.3(@types/react@18.3.26)(react@19.2.0) + optionalDependencies: + '@types/react': 18.3.26 + react-remove-scroll@2.7.1(@types/react@19.2.1)(react@19.2.0): dependencies: react: 19.2.0 @@ -10594,6 +11703,14 @@ snapshots: optionalDependencies: '@types/react': 19.2.1 + react-style-singleton@2.2.3(@types/react@18.3.26)(react@19.2.0): + dependencies: + get-nonce: 1.0.1 + react: 19.2.0 + tslib: 2.8.1 + optionalDependencies: + '@types/react': 18.3.26 + react-style-singleton@2.2.3(@types/react@19.2.1)(react@19.2.0): dependencies: get-nonce: 1.0.1 @@ -10692,7 +11809,7 @@ snapshots: dependencies: protocol-buffers-schema: 3.6.0 - resolve@1.22.10: + resolve@1.22.11: dependencies: is-core-module: 2.16.1 path-parse: 1.0.7 @@ -10711,99 +11828,73 @@ snapshots: robust-predicates@3.0.2: {} - rolldown-plugin-dts@0.16.3(rolldown@1.0.0-beta.43)(typescript@5.9.2): + rolldown-plugin-dts@0.16.3(rolldown@1.0.0-beta.9-commit.d91dfb5)(typescript@5.9.2): dependencies: '@babel/generator': 7.28.3 '@babel/parser': 7.28.4 '@babel/types': 7.28.4 ast-kit: 2.1.2 birpc: 2.5.0 - debug: 4.4.1 + debug: 4.4.3 dts-resolver: 2.1.2 get-tsconfig: 4.10.1 - rolldown: 1.0.0-beta.43 + rolldown: 1.0.0-beta.9-commit.d91dfb5 optionalDependencies: typescript: 5.9.2 transitivePeerDependencies: - oxc-resolver - supports-color - rolldown@1.0.0-beta.43: + rolldown@1.0.0-beta.9-commit.d91dfb5: dependencies: - '@oxc-project/types': 0.94.0 - '@rolldown/pluginutils': 1.0.0-beta.43 + '@oxc-project/runtime': 0.71.0 + '@oxc-project/types': 0.71.0 + '@rolldown/pluginutils': 1.0.0-beta.9-commit.d91dfb5 ansis: 4.2.0 optionalDependencies: - '@rolldown/binding-android-arm64': 1.0.0-beta.43 - '@rolldown/binding-darwin-arm64': 1.0.0-beta.43 - '@rolldown/binding-darwin-x64': 1.0.0-beta.43 - '@rolldown/binding-freebsd-x64': 1.0.0-beta.43 - '@rolldown/binding-linux-arm-gnueabihf': 1.0.0-beta.43 - '@rolldown/binding-linux-arm64-gnu': 1.0.0-beta.43 - '@rolldown/binding-linux-arm64-musl': 1.0.0-beta.43 - '@rolldown/binding-linux-x64-gnu': 1.0.0-beta.43 - '@rolldown/binding-linux-x64-musl': 1.0.0-beta.43 - '@rolldown/binding-openharmony-arm64': 1.0.0-beta.43 - '@rolldown/binding-wasm32-wasi': 1.0.0-beta.43 - '@rolldown/binding-win32-arm64-msvc': 1.0.0-beta.43 - '@rolldown/binding-win32-ia32-msvc': 1.0.0-beta.43 - '@rolldown/binding-win32-x64-msvc': 1.0.0-beta.43 + '@rolldown/binding-darwin-arm64': 1.0.0-beta.9-commit.d91dfb5 + '@rolldown/binding-darwin-x64': 1.0.0-beta.9-commit.d91dfb5 + '@rolldown/binding-freebsd-x64': 1.0.0-beta.9-commit.d91dfb5 + '@rolldown/binding-linux-arm-gnueabihf': 1.0.0-beta.9-commit.d91dfb5 + '@rolldown/binding-linux-arm64-gnu': 1.0.0-beta.9-commit.d91dfb5 + '@rolldown/binding-linux-arm64-musl': 1.0.0-beta.9-commit.d91dfb5 + '@rolldown/binding-linux-x64-gnu': 1.0.0-beta.9-commit.d91dfb5 + '@rolldown/binding-linux-x64-musl': 1.0.0-beta.9-commit.d91dfb5 + '@rolldown/binding-wasm32-wasi': 1.0.0-beta.9-commit.d91dfb5 + '@rolldown/binding-win32-arm64-msvc': 1.0.0-beta.9-commit.d91dfb5 + '@rolldown/binding-win32-ia32-msvc': 1.0.0-beta.9-commit.d91dfb5 + '@rolldown/binding-win32-x64-msvc': 1.0.0-beta.9-commit.d91dfb5 rollup@2.79.2: optionalDependencies: fsevents: 2.3.3 - rollup@4.46.2: + rollup@4.52.5: dependencies: '@types/estree': 1.0.8 optionalDependencies: - '@rollup/rollup-android-arm-eabi': 4.46.2 - '@rollup/rollup-android-arm64': 4.46.2 - '@rollup/rollup-darwin-arm64': 4.46.2 - '@rollup/rollup-darwin-x64': 4.46.2 - '@rollup/rollup-freebsd-arm64': 4.46.2 - '@rollup/rollup-freebsd-x64': 4.46.2 - '@rollup/rollup-linux-arm-gnueabihf': 4.46.2 - '@rollup/rollup-linux-arm-musleabihf': 4.46.2 - '@rollup/rollup-linux-arm64-gnu': 4.46.2 - '@rollup/rollup-linux-arm64-musl': 4.46.2 - '@rollup/rollup-linux-loongarch64-gnu': 4.46.2 - '@rollup/rollup-linux-ppc64-gnu': 4.46.2 - '@rollup/rollup-linux-riscv64-gnu': 4.46.2 - '@rollup/rollup-linux-riscv64-musl': 4.46.2 - '@rollup/rollup-linux-s390x-gnu': 4.46.2 - '@rollup/rollup-linux-x64-gnu': 4.46.2 - '@rollup/rollup-linux-x64-musl': 4.46.2 - '@rollup/rollup-win32-arm64-msvc': 4.46.2 - '@rollup/rollup-win32-ia32-msvc': 4.46.2 - '@rollup/rollup-win32-x64-msvc': 4.46.2 - fsevents: 2.3.3 - - rollup@4.50.1: - dependencies: - '@types/estree': 1.0.8 - optionalDependencies: - '@rollup/rollup-android-arm-eabi': 4.50.1 - '@rollup/rollup-android-arm64': 4.50.1 - '@rollup/rollup-darwin-arm64': 4.50.1 - '@rollup/rollup-darwin-x64': 4.50.1 - '@rollup/rollup-freebsd-arm64': 4.50.1 - '@rollup/rollup-freebsd-x64': 4.50.1 - '@rollup/rollup-linux-arm-gnueabihf': 4.50.1 - '@rollup/rollup-linux-arm-musleabihf': 4.50.1 - '@rollup/rollup-linux-arm64-gnu': 4.50.1 - '@rollup/rollup-linux-arm64-musl': 4.50.1 - '@rollup/rollup-linux-loongarch64-gnu': 4.50.1 - '@rollup/rollup-linux-ppc64-gnu': 4.50.1 - '@rollup/rollup-linux-riscv64-gnu': 4.50.1 - '@rollup/rollup-linux-riscv64-musl': 4.50.1 - '@rollup/rollup-linux-s390x-gnu': 4.50.1 - '@rollup/rollup-linux-x64-gnu': 4.50.1 - '@rollup/rollup-linux-x64-musl': 4.50.1 - '@rollup/rollup-openharmony-arm64': 4.50.1 - '@rollup/rollup-win32-arm64-msvc': 4.50.1 - '@rollup/rollup-win32-ia32-msvc': 4.50.1 - '@rollup/rollup-win32-x64-msvc': 4.50.1 + '@rollup/rollup-android-arm-eabi': 4.52.5 + '@rollup/rollup-android-arm64': 4.52.5 + '@rollup/rollup-darwin-arm64': 4.52.5 + '@rollup/rollup-darwin-x64': 4.52.5 + '@rollup/rollup-freebsd-arm64': 4.52.5 + '@rollup/rollup-freebsd-x64': 4.52.5 + '@rollup/rollup-linux-arm-gnueabihf': 4.52.5 + '@rollup/rollup-linux-arm-musleabihf': 4.52.5 + '@rollup/rollup-linux-arm64-gnu': 4.52.5 + '@rollup/rollup-linux-arm64-musl': 4.52.5 + '@rollup/rollup-linux-loong64-gnu': 4.52.5 + '@rollup/rollup-linux-ppc64-gnu': 4.52.5 + '@rollup/rollup-linux-riscv64-gnu': 4.52.5 + '@rollup/rollup-linux-riscv64-musl': 4.52.5 + '@rollup/rollup-linux-s390x-gnu': 4.52.5 + '@rollup/rollup-linux-x64-gnu': 4.52.5 + '@rollup/rollup-linux-x64-musl': 4.52.5 + '@rollup/rollup-openharmony-arm64': 4.52.5 + '@rollup/rollup-win32-arm64-msvc': 4.52.5 + '@rollup/rollup-win32-ia32-msvc': 4.52.5 + '@rollup/rollup-win32-x64-gnu': 4.52.5 + '@rollup/rollup-win32-x64-msvc': 4.52.5 fsevents: 2.3.3 run-parallel@1.2.0: @@ -10816,6 +11907,10 @@ snapshots: dependencies: tslib: 1.14.1 + sade@1.8.1: + dependencies: + mri: 1.2.0 + safe-array-concat@1.1.3: dependencies: call-bind: 1.0.8 @@ -10843,6 +11938,10 @@ snapshots: semver@6.3.1: {} + semver@7.5.4: + dependencies: + lru-cache: 6.0.0 + semver@7.7.2: {} serialize-javascript@6.0.2: @@ -10990,6 +12089,8 @@ snapshots: dependencies: extend-shallow: 3.0.2 + sprintf-js@1.0.3: {} + stackback@0.0.2: {} std-env@3.9.0: {} @@ -11007,6 +12108,8 @@ snapshots: stream-shift@1.0.3: {} + string-argv@0.3.2: {} + string-width@4.2.3: dependencies: emoji-regex: 8.0.0 @@ -11086,6 +12189,8 @@ snapshots: dependencies: min-indent: 1.0.1 + strip-json-comments@3.1.1: {} + strip-literal@3.0.0: dependencies: js-tokens: 9.0.1 @@ -11094,12 +12199,18 @@ snapshots: dependencies: kdbush: 4.0.2 + supports-color@8.1.1: + dependencies: + has-flag: 4.0.0 + supports-preserve-symlinks-flag@1.0.0: {} sweepline-intersections@1.5.0: dependencies: tinyqueue: 2.0.3 + tailwind-merge@2.6.0: {} + tailwind-merge@3.3.1: {} tailwindcss-animate@1.0.7(tailwindcss@4.1.14): @@ -11108,6 +12219,8 @@ snapshots: tailwindcss@4.1.14: {} + tailwindcss@4.1.15: {} + tapable@2.2.2: {} tar@7.5.1: @@ -11134,7 +12247,7 @@ snapshots: commander: 2.20.3 source-map-support: 0.5.21 - terser@5.44.0: + terser@5.44.1: dependencies: '@jridgewell/source-map': 0.3.11 acorn: 8.15.0 @@ -11206,7 +12319,7 @@ snapshots: tree-kill@1.2.2: {} - tsdown@0.15.0(typescript@5.9.2): + tsdown@0.15.0(publint@0.3.15)(typescript@5.9.2): dependencies: ansis: 4.1.0 cac: 6.7.14 @@ -11215,14 +12328,15 @@ snapshots: diff: 8.0.2 empathic: 2.0.0 hookable: 5.5.3 - rolldown: 1.0.0-beta.43 - rolldown-plugin-dts: 0.16.3(rolldown@1.0.0-beta.43)(typescript@5.9.2) + rolldown: 1.0.0-beta.9-commit.d91dfb5 + rolldown-plugin-dts: 0.16.3(rolldown@1.0.0-beta.9-commit.d91dfb5)(typescript@5.9.2) semver: 7.7.2 tinyexec: 1.0.1 tinyglobby: 0.2.15 tree-kill: 1.2.2 unconfig: 7.3.3 optionalDependencies: + publint: 0.3.15 typescript: 5.9.2 transitivePeerDependencies: - '@typescript/native-preview' @@ -11243,6 +12357,8 @@ snapshots: optionalDependencies: fsevents: 2.3.3 + tw-animate-css@1.4.0: {} + type-fest@0.16.0: {} type-fest@2.19.0: {} @@ -11282,6 +12398,8 @@ snapshots: typescript@4.5.2: {} + typescript@5.8.2: {} + typescript@5.9.2: {} typescript@5.9.3: {} @@ -11292,6 +12410,8 @@ snapshots: dependencies: typewise-core: 1.2.0 + ufo@1.6.1: {} + unbox-primitive@1.1.0: dependencies: call-bound: 1.0.4 @@ -11303,7 +12423,7 @@ snapshots: dependencies: '@quansync/fs': 0.1.5 defu: 6.1.4 - jiti: 2.5.1 + jiti: 2.6.1 quansync: 0.2.11 undici-types@6.21.0: {} @@ -11356,12 +12476,23 @@ snapshots: escalade: 3.2.0 picocolors: 1.1.1 - update-browserslist-db@1.1.3(browserslist@4.26.3): + update-browserslist-db@1.1.4(browserslist@4.28.0): dependencies: - browserslist: 4.26.3 + browserslist: 4.28.0 escalade: 3.2.0 picocolors: 1.1.1 + uri-js@4.4.1: + dependencies: + punycode: 2.3.1 + + use-callback-ref@1.3.3(@types/react@18.3.26)(react@19.2.0): + dependencies: + react: 19.2.0 + tslib: 2.8.1 + optionalDependencies: + '@types/react': 18.3.26 + use-callback-ref@1.3.3(@types/react@19.2.1)(react@19.2.0): dependencies: react: 19.2.0 @@ -11369,6 +12500,14 @@ snapshots: optionalDependencies: '@types/react': 19.2.1 + use-sidecar@1.1.3(@types/react@18.3.26)(react@19.2.0): + dependencies: + detect-node-es: 1.1.0 + react: 19.2.0 + tslib: 2.8.1 + optionalDependencies: + '@types/react': 18.3.26 + use-sidecar@1.1.3(@types/react@19.2.1)(react@19.2.0): dependencies: detect-node-es: 1.1.0 @@ -11383,13 +12522,13 @@ snapshots: util-deprecate@1.0.2: {} - vite-node@3.2.4(@types/node@24.3.1)(jiti@2.6.1)(lightningcss@1.30.1)(terser@5.44.0)(tsx@4.20.3): + vite-node@3.2.4(@types/node@24.3.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.3): dependencies: cac: 6.7.14 - debug: 4.4.1 + debug: 4.4.3 es-module-lexer: 1.7.0 pathe: 2.0.3 - vite: 7.1.9(@types/node@24.3.1)(jiti@2.6.1)(lightningcss@1.30.1)(terser@5.44.0)(tsx@4.20.3) + vite: 7.1.11(@types/node@24.3.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.3) transitivePeerDependencies: - '@types/node' - jiti @@ -11404,13 +12543,13 @@ snapshots: - tsx - yaml - vite-node@3.2.4(@types/node@24.7.0)(jiti@2.6.1)(lightningcss@1.30.1)(terser@5.44.0)(tsx@4.20.3): + vite-node@3.2.4(@types/node@24.7.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.3): dependencies: cac: 6.7.14 - debug: 4.4.1 + debug: 4.4.3 es-module-lexer: 1.7.0 pathe: 2.0.3 - vite: 7.1.9(@types/node@24.7.0)(jiti@2.6.1)(lightningcss@1.30.1)(terser@5.44.0)(tsx@4.20.3) + vite: 7.1.11(@types/node@24.7.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.3) transitivePeerDependencies: - '@types/node' - jiti @@ -11425,7 +12564,26 @@ snapshots: - tsx - yaml - vite-plugin-html@3.2.2(vite@7.1.9(@types/node@24.7.0)(jiti@2.6.1)(lightningcss@1.30.1)(terser@5.44.0)(tsx@4.20.3)): + vite-plugin-dts@4.5.4(@types/node@24.7.0)(rollup@4.52.5)(typescript@5.9.3)(vite@7.1.11(@types/node@24.7.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.3)): + dependencies: + '@microsoft/api-extractor': 7.53.2(@types/node@24.7.0) + '@rollup/pluginutils': 5.3.0(rollup@4.52.5) + '@volar/typescript': 2.4.23 + '@vue/language-core': 2.2.0(typescript@5.9.3) + compare-versions: 6.1.1 + debug: 4.4.3 + kolorist: 1.8.0 + local-pkg: 1.1.2 + magic-string: 0.30.19 + typescript: 5.9.3 + optionalDependencies: + vite: 7.1.11(@types/node@24.7.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.3) + transitivePeerDependencies: + - '@types/node' + - rollup + - supports-color + + vite-plugin-html@3.2.2(vite@7.1.11(@types/node@24.7.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.3)): dependencies: '@rollup/pluginutils': 4.2.1 colorette: 2.0.20 @@ -11439,111 +12597,87 @@ snapshots: html-minifier-terser: 6.1.0 node-html-parser: 5.4.2 pathe: 0.2.0 - vite: 7.1.9(@types/node@24.7.0)(jiti@2.6.1)(lightningcss@1.30.1)(terser@5.44.0)(tsx@4.20.3) + vite: 7.1.11(@types/node@24.7.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.3) - vite-plugin-pwa@1.0.3(vite@7.1.9(@types/node@24.7.0)(jiti@2.6.1)(lightningcss@1.30.1)(terser@5.44.0)(tsx@4.20.3))(workbox-build@7.3.0(@types/babel__core@7.20.5))(workbox-window@7.3.0): + vite-plugin-pwa@1.0.3(vite@7.1.11(@types/node@24.7.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.3))(workbox-build@7.3.0(@types/babel__core@7.20.5))(workbox-window@7.3.0): dependencies: debug: 4.4.1 pretty-bytes: 6.1.1 tinyglobby: 0.2.14 - vite: 7.1.9(@types/node@24.7.0)(jiti@2.6.1)(lightningcss@1.30.1)(terser@5.44.0)(tsx@4.20.3) + vite: 7.1.11(@types/node@24.7.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.3) workbox-build: 7.3.0(@types/babel__core@7.20.5) workbox-window: 7.3.0 transitivePeerDependencies: - supports-color - vite@7.1.1(@types/node@24.3.1)(jiti@2.6.1)(lightningcss@1.30.1)(terser@5.44.0)(tsx@4.20.3): - dependencies: - esbuild: 0.25.8 - fdir: 6.4.6(picomatch@4.0.3) - picomatch: 4.0.3 - postcss: 8.5.6 - rollup: 4.46.2 - tinyglobby: 0.2.14 - optionalDependencies: - '@types/node': 24.3.1 - fsevents: 2.3.3 - jiti: 2.6.1 - lightningcss: 1.30.1 - terser: 5.44.0 - tsx: 4.20.3 - - vite@7.1.1(@types/node@24.7.0)(jiti@2.6.1)(lightningcss@1.30.1)(terser@5.44.0)(tsx@4.20.3): + vite-plugin-static-copy@3.1.4(vite@7.1.11(@types/node@24.7.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.3)): dependencies: - esbuild: 0.25.8 - fdir: 6.4.6(picomatch@4.0.3) - picomatch: 4.0.3 - postcss: 8.5.6 - rollup: 4.46.2 - tinyglobby: 0.2.14 - optionalDependencies: - '@types/node': 24.7.0 - fsevents: 2.3.3 - jiti: 2.6.1 - lightningcss: 1.30.1 - terser: 5.44.0 - tsx: 4.20.3 + chokidar: 3.6.0 + p-map: 7.0.3 + picocolors: 1.1.1 + tinyglobby: 0.2.15 + vite: 7.1.11(@types/node@24.7.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.3) - vite@7.1.9(@types/node@24.3.1)(jiti@2.6.1)(lightningcss@1.30.1)(terser@5.44.0)(tsx@4.20.3): + vite@7.1.11(@types/node@24.3.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.3): dependencies: - esbuild: 0.25.9 + esbuild: 0.25.11 fdir: 6.5.0(picomatch@4.0.3) picomatch: 4.0.3 postcss: 8.5.6 - rollup: 4.50.1 + rollup: 4.52.5 tinyglobby: 0.2.15 optionalDependencies: '@types/node': 24.3.1 fsevents: 2.3.3 jiti: 2.6.1 - lightningcss: 1.30.1 - terser: 5.44.0 + lightningcss: 1.30.2 + terser: 5.44.1 tsx: 4.20.3 - vite@7.1.9(@types/node@24.7.0)(jiti@2.6.1)(lightningcss@1.30.1)(terser@5.44.0)(tsx@4.20.3): + vite@7.1.11(@types/node@24.7.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.3): dependencies: - esbuild: 0.25.9 + esbuild: 0.25.11 fdir: 6.5.0(picomatch@4.0.3) picomatch: 4.0.3 postcss: 8.5.6 - rollup: 4.50.1 + rollup: 4.52.5 tinyglobby: 0.2.15 optionalDependencies: '@types/node': 24.7.0 fsevents: 2.3.3 jiti: 2.6.1 - lightningcss: 1.30.1 - terser: 5.44.0 + lightningcss: 1.30.2 + terser: 5.44.1 tsx: 4.20.3 - vitest@3.2.4(@types/node@24.3.1)(happy-dom@20.0.0)(jiti@2.6.1)(lightningcss@1.30.1)(terser@5.44.0)(tsx@4.20.3): + vitest@3.2.4(@types/node@24.3.1)(happy-dom@20.0.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.3): dependencies: '@types/chai': 5.2.2 '@vitest/expect': 3.2.4 - '@vitest/mocker': 3.2.4(vite@7.1.1(@types/node@24.3.1)(jiti@2.6.1)(lightningcss@1.30.1)(terser@5.44.0)(tsx@4.20.3)) + '@vitest/mocker': 3.2.4(vite@7.1.11(@types/node@24.3.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.3)) '@vitest/pretty-format': 3.2.4 '@vitest/runner': 3.2.4 '@vitest/snapshot': 3.2.4 '@vitest/spy': 3.2.4 '@vitest/utils': 3.2.4 chai: 5.2.1 - debug: 4.4.1 + debug: 4.4.3 expect-type: 1.2.2 - magic-string: 0.30.17 + magic-string: 0.30.19 pathe: 2.0.3 picomatch: 4.0.3 std-env: 3.9.0 tinybench: 2.9.0 tinyexec: 0.3.2 - tinyglobby: 0.2.14 + tinyglobby: 0.2.15 tinypool: 1.1.1 tinyrainbow: 2.0.0 - vite: 7.1.1(@types/node@24.3.1)(jiti@2.6.1)(lightningcss@1.30.1)(terser@5.44.0)(tsx@4.20.3) - vite-node: 3.2.4(@types/node@24.3.1)(jiti@2.6.1)(lightningcss@1.30.1)(terser@5.44.0)(tsx@4.20.3) + vite: 7.1.11(@types/node@24.3.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.3) + vite-node: 3.2.4(@types/node@24.3.1)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.3) why-is-node-running: 2.3.0 optionalDependencies: '@types/node': 24.3.1 - happy-dom: 20.0.0 + happy-dom: 20.0.2 transitivePeerDependencies: - jiti - less @@ -11558,34 +12692,34 @@ snapshots: - tsx - yaml - vitest@3.2.4(@types/node@24.7.0)(happy-dom@20.0.0)(jiti@2.6.1)(lightningcss@1.30.1)(terser@5.44.0)(tsx@4.20.3): + vitest@3.2.4(@types/node@24.7.0)(happy-dom@20.0.2)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.3): dependencies: '@types/chai': 5.2.2 '@vitest/expect': 3.2.4 - '@vitest/mocker': 3.2.4(vite@7.1.1(@types/node@24.7.0)(jiti@2.6.1)(lightningcss@1.30.1)(terser@5.44.0)(tsx@4.20.3)) + '@vitest/mocker': 3.2.4(vite@7.1.11(@types/node@24.7.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.3)) '@vitest/pretty-format': 3.2.4 '@vitest/runner': 3.2.4 '@vitest/snapshot': 3.2.4 '@vitest/spy': 3.2.4 '@vitest/utils': 3.2.4 chai: 5.2.1 - debug: 4.4.1 + debug: 4.4.3 expect-type: 1.2.2 - magic-string: 0.30.17 + magic-string: 0.30.19 pathe: 2.0.3 picomatch: 4.0.3 std-env: 3.9.0 tinybench: 2.9.0 tinyexec: 0.3.2 - tinyglobby: 0.2.14 + tinyglobby: 0.2.15 tinypool: 1.1.1 tinyrainbow: 2.0.0 - vite: 7.1.1(@types/node@24.7.0)(jiti@2.6.1)(lightningcss@1.30.1)(terser@5.44.0)(tsx@4.20.3) - vite-node: 3.2.4(@types/node@24.7.0)(jiti@2.6.1)(lightningcss@1.30.1)(terser@5.44.0)(tsx@4.20.3) + vite: 7.1.11(@types/node@24.7.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.3) + vite-node: 3.2.4(@types/node@24.7.0)(jiti@2.6.1)(lightningcss@1.30.2)(terser@5.44.1)(tsx@4.20.3) why-is-node-running: 2.3.0 optionalDependencies: '@types/node': 24.7.0 - happy-dom: 20.0.0 + happy-dom: 20.0.2 transitivePeerDependencies: - jiti - less @@ -11602,6 +12736,8 @@ snapshots: void-elements@3.1.0: {} + vscode-uri@3.1.0: {} + webidl-conversions@3.0.1: {} webidl-conversions@4.0.2: {} @@ -11684,7 +12820,7 @@ snapshots: dependencies: '@apideck/better-ajv-errors': 0.3.6(ajv@8.17.1) '@babel/core': 7.28.4 - '@babel/preset-env': 7.28.3(@babel/core@7.28.4) + '@babel/preset-env': 7.28.5(@babel/core@7.28.4) '@babel/runtime': 7.28.4 '@rollup/plugin-babel': 5.3.1(@babel/core@7.28.4)(@types/babel__core@7.20.5)(rollup@2.79.2) '@rollup/plugin-node-resolve': 15.3.1(rollup@2.79.2) @@ -11804,6 +12940,8 @@ snapshots: yallist@3.1.1: {} + yallist@4.0.0: {} + yallist@5.0.0: {} yargs-parser@21.1.1: {} diff --git a/tsconfig.base.json b/tsconfig.base.json index bb8b8c287..d783ccba4 100644 --- a/tsconfig.base.json +++ b/tsconfig.base.json @@ -1,7 +1,7 @@ { "compilerOptions": { - "target": "ES2022", - "lib": ["DOM", "DOM.Iterable", "ES2022"], + "target": "ES2023", + "lib": ["DOM", "DOM.Iterable", "ES2023"], "module": "ESNext", "moduleResolution": "bundler", "strict": true,