Compare commits

..

10 Commits

Author SHA1 Message Date
Vincent Koc
46584db0c1 fix(i18n): restrict native UI extraction 2026-06-26 18:04:47 -07:00
Vincent Koc
897214d248 fix(i18n): guard native refresh inputs 2026-06-26 18:04:47 -07:00
Vincent Koc
eff4ab356c fix(i18n): cover all native source roots 2026-06-26 18:04:46 -07:00
Vincent Koc
dba00247ca fix(i18n): validate Kotlin and Swift placeholders 2026-06-26 18:04:46 -07:00
Vincent Koc
5cbf6928d9 fix(ci): restrict native locale refresh dispatch 2026-06-26 18:04:46 -07:00
Vincent Koc
1c54e76223 fix(i18n): validate native translation structure 2026-06-26 18:04:46 -07:00
Vincent Koc
bd38ea44d0 docs(i18n): clarify native artifact ownership 2026-06-26 18:04:46 -07:00
Vincent Koc
aa2c87fcc9 fix(ci): commit first native locale artifacts 2026-06-26 18:04:46 -07:00
Vincent Koc
e51433b092 feat(i18n): refresh every native locale 2026-06-26 18:04:46 -07:00
Vincent Koc
90855f194e feat(i18n): refresh native locale artifacts 2026-06-26 18:04:46 -07:00
32 changed files with 700 additions and 921 deletions

View File

@@ -870,10 +870,6 @@ jobs:
- name: Check native app i18n inventory
run: pnpm native:i18n:check
- name: Check Android app i18n resources
if: needs.preflight.outputs.run_android == 'true'
run: pnpm android:i18n:check
checks-fast-core:
permissions:
contents: read

View File

@@ -0,0 +1,119 @@
name: Native App Locale Refresh
on:
push:
branches:
- main
paths:
- apps/android/app/src/main/**
- apps/ios/**
- apps/macos/Sources/**
- apps/macos/Package.swift
- apps/shared/OpenClawKit/Sources/**
- apps/.i18n/native-source.json
- scripts/control-ui-i18n.ts
- scripts/native-app-i18n.ts
- .github/workflows/native-app-locale-refresh.yml
workflow_dispatch:
permissions:
contents: write
concurrency:
group: native-app-locale-refresh-${{ github.event_name == 'push' && github.ref || format('manual-{0}', github.run_id) }}
cancel-in-progress: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }}
jobs:
refresh:
if: github.repository == 'openclaw/openclaw' && (github.event_name != 'workflow_dispatch' || github.ref == 'refs/heads/main') && (github.event_name != 'push' || github.actor != 'github-actions[bot]')
strategy:
fail-fast: false
max-parallel: 2
matrix:
locale:
[
zh-CN,
zh-TW,
pt-BR,
de,
es,
ja-JP,
ko,
fr,
hi,
ar,
it,
tr,
uk,
id,
pl,
th,
vi,
nl,
fa,
ru,
]
runs-on: ubuntu-latest
name: Refresh native ${{ matrix.locale }}
steps:
- name: Checkout
uses: actions/checkout@df4cb1c069e1874edd31b4311f1884172cec0e10 # v6
with:
persist-credentials: true
submodules: false
- name: Setup Node environment
uses: ./.github/actions/setup-node-env
with:
install-bun: "false"
- name: Ensure translation provider secrets exist
env:
OPENAI_API_KEY: ${{ secrets.OPENCLAW_DOCS_I18N_OPENAI_API_KEY || secrets.OPENAI_API_KEY }}
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
run: |
set -euo pipefail
if [ -z "${OPENAI_API_KEY:-}" ] && [ -z "${ANTHROPIC_API_KEY:-}" ]; then
echo "Missing OPENCLAW_DOCS_I18N_OPENAI_API_KEY, OPENAI_API_KEY, or ANTHROPIC_API_KEY secret."
exit 1
fi
- name: Refresh native locale artifact
env:
OPENAI_API_KEY: ${{ secrets.OPENCLAW_DOCS_I18N_OPENAI_API_KEY || secrets.OPENAI_API_KEY }}
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
OPENCLAW_CONTROL_UI_I18N_PROVIDER: ${{ secrets.ANTHROPIC_API_KEY != '' && 'anthropic' || 'openai' }}
OPENCLAW_CONTROL_UI_I18N_MODEL: ${{ secrets.ANTHROPIC_API_KEY != '' && 'claude-opus-4-8' || vars.OPENCLAW_CI_OPENAI_MODEL_BARE }}
OPENCLAW_CONTROL_UI_I18N_THINKING: low
OPENCLAW_CONTROL_UI_I18N_AUTH_OPTIONAL: "0"
LOCALE: ${{ matrix.locale }}
run: node --import tsx scripts/native-app-i18n.ts sync --write --locale "${LOCALE}"
- name: Commit and push locale artifact
env:
LOCALE: ${{ matrix.locale }}
TARGET_BRANCH: ${{ github.event.repository.default_branch }}
run: |
set -euo pipefail
if ! git status --porcelain -- apps/.i18n/native apps/.i18n/native-source.json | grep -q .; then
echo "No native locale changes for ${LOCALE}."
exit 0
fi
git config user.name "github-actions[bot]"
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
git add -A apps/.i18n/native apps/.i18n/native-source.json
git commit --no-verify -m "chore(i18n): refresh native ${LOCALE} locale"
for attempt in 1 2 3 4 5; do
git fetch origin "${TARGET_BRANCH}"
git rebase --autostash "origin/${TARGET_BRANCH}"
if git push origin HEAD:"${TARGET_BRANCH}"; then
exit 0
fi
echo "Push attempt ${attempt} for ${LOCALE} failed; retrying."
sleep $((attempt * 2))
done
echo "Failed to push ${LOCALE} native locale update after retries."
exit 1

View File

@@ -1275,7 +1275,127 @@
},
{
"kind": "ui-call",
"line": 380,
"line": 103,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ConnectTabScreen.kt",
"source": "Trust this gateway?",
"surface": "android",
"id": "native.android.db9b3ffd6b7983d3"
},
{
"kind": "ui-call",
"line": 122,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ConnectTabScreen.kt",
"source": "Trust and continue",
"surface": "android",
"id": "native.android.f60e86cd1e4a386f"
},
{
"kind": "ui-call",
"line": 130,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ConnectTabScreen.kt",
"source": "Cancel",
"surface": "android",
"id": "native.android.e82eac1ea98d5344"
},
{
"kind": "ui-call",
"line": 161,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ConnectTabScreen.kt",
"source": "Gateway Connection",
"surface": "android",
"id": "native.android.bd14ca8081e66fb5"
},
{
"kind": "conditional-branch",
"line": 163,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ConnectTabScreen.kt",
"source": "Connect to your gateway to get started.",
"surface": "android",
"id": "native.android.74a6a2d805c19a60"
},
{
"kind": "conditional-branch",
"line": 163,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ConnectTabScreen.kt",
"source": "Your gateway is active and ready.",
"surface": "android",
"id": "native.android.64a0ae87f54277e7"
},
{
"kind": "ui-call",
"line": 194,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ConnectTabScreen.kt",
"source": "Endpoint",
"surface": "android",
"id": "native.android.3c87c3eb8b76443d"
},
{
"kind": "ui-call",
"line": 216,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ConnectTabScreen.kt",
"source": "Status",
"surface": "android",
"id": "native.android.cb8ca12247f5574d"
},
{
"kind": "ui-call",
"line": 241,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ConnectTabScreen.kt",
"source": "Disconnect",
"surface": "android",
"id": "native.android.3947ebe9e7302445"
},
{
"kind": "ui-call",
"line": 310,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ConnectTabScreen.kt",
"source": "Connect Gateway",
"surface": "android",
"id": "native.android.29b6c84cc243897f"
},
{
"kind": "conditional-branch",
"line": 325,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ConnectTabScreen.kt",
"source": "Last gateway error",
"surface": "android",
"id": "native.android.f1c67abfbe3ec6e0"
},
{
"kind": "conditional-branch",
"line": 325,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ConnectTabScreen.kt",
"source": "Pairing required",
"surface": "android",
"id": "native.android.6c4cd299250df476"
},
{
"kind": "ui-call",
"line": 336,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ConnectTabScreen.kt",
"source": "OpenClaw Android ${openClawAndroidVersionLabel()}",
"surface": "android",
"id": "native.android.d4cf912850bd01fa"
},
{
"kind": "ui-call",
"line": 357,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ConnectTabScreen.kt",
"source": "Copy Report for Claw",
"surface": "android",
"id": "native.android.b81ffcf00e1d5aa2"
},
{
"kind": "ui-call",
"line": 376,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ConnectTabScreen.kt",
"source": "Advanced controls",
"surface": "android",
"id": "native.android.54e06efb5730c9d3"
},
{
"kind": "ui-call",
"line": 377,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ConnectTabScreen.kt",
"source": "Setup code, endpoint, TLS, token, password, onboarding.",
"surface": "android",
@@ -1299,7 +1419,31 @@
},
{
"kind": "ui-call",
"line": 415,
"line": 398,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ConnectTabScreen.kt",
"source": "Connection method",
"surface": "android",
"id": "native.android.cb057f35d269d945"
},
{
"kind": "ui-property",
"line": 401,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ConnectTabScreen.kt",
"source": "Setup Code",
"surface": "android",
"id": "native.android.0e2eec805f9c2448"
},
{
"kind": "ui-property",
"line": 406,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ConnectTabScreen.kt",
"source": "Manual",
"surface": "android",
"id": "native.android.5fcf0beb9ef48a98"
},
{
"kind": "ui-call",
"line": 412,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ConnectTabScreen.kt",
"source": "Run these on the gateway host:",
"surface": "android",
@@ -1307,15 +1451,23 @@
},
{
"kind": "ui-call",
"line": 418,
"line": 415,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ConnectTabScreen.kt",
"source": "For Tailscale or public hosts, use wss:// or Tailscale Serve. Private LAN ws:// remains supported.",
"surface": "android",
"id": "native.android.8b607ce7ba3ac4d3"
},
{
"kind": "ui-call",
"line": 429,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ConnectTabScreen.kt",
"source": "Paste setup code",
"surface": "android",
"id": "native.android.8338a39bcb90b86e"
},
{
"kind": "ui-property",
"line": 447,
"line": 444,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ConnectTabScreen.kt",
"source": "Android Emulator",
"surface": "android",
@@ -1323,7 +1475,7 @@
},
{
"kind": "ui-property",
"line": 456,
"line": 453,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ConnectTabScreen.kt",
"source": "Localhost",
"surface": "android",
@@ -1331,7 +1483,39 @@
},
{
"kind": "ui-call",
"line": 509,
"line": 463,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ConnectTabScreen.kt",
"source": "Host",
"surface": "android",
"id": "native.android.3cc6464a0aa1f0ef"
},
{
"kind": "conditional-branch",
"line": 480,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ConnectTabScreen.kt",
"source": "Port",
"surface": "android",
"id": "native.android.8eb9efc461827277"
},
{
"kind": "conditional-branch",
"line": 480,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ConnectTabScreen.kt",
"source": "Port (optional, defaults to 443)",
"surface": "android",
"id": "native.android.e1ad7cf446f7d370"
},
{
"kind": "ui-call",
"line": 505,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ConnectTabScreen.kt",
"source": "Use TLS",
"surface": "android",
"id": "native.android.02693afaa85da5ea"
},
{
"kind": "ui-call",
"line": 506,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ConnectTabScreen.kt",
"source": "Turn this on for Tailscale or public hosts. Private LAN ws:// remains supported.",
"surface": "android",
@@ -1339,15 +1523,15 @@
},
{
"kind": "ui-call",
"line": 535,
"line": 528,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ConnectTabScreen.kt",
"source": "token",
"source": "Token (optional)",
"surface": "android",
"id": "native.android.60da1ba96bf1ed31"
"id": "native.android.795ba55a55ed1684"
},
{
"kind": "ui-call",
"line": 544,
"line": 541,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ConnectTabScreen.kt",
"source": "Password (optional)",
"surface": "android",
@@ -1355,7 +1539,15 @@
},
{
"kind": "ui-call",
"line": 654,
"line": 566,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ConnectTabScreen.kt",
"source": "Run onboarding again",
"surface": "android",
"id": "native.android.94891650ca526e96"
},
{
"kind": "ui-call",
"line": 651,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/ConnectTabScreen.kt",
"source": "Resolved endpoint",
"surface": "android",
@@ -1939,23 +2131,47 @@
},
{
"kind": "ui-call",
"line": 418,
"line": 215,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt",
"source": "OPENCLAW",
"source": "Trust this gateway?",
"surface": "android",
"id": "native.android.e8893dbc155f10f9"
"id": "native.android.40b4074a84478a80"
},
{
"kind": "ui-call",
"line": 423,
"line": 217,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt",
"source": "Verify the certificate fingerprint before continuing.\n\n${prompt.fingerprintSha256}",
"surface": "android",
"id": "native.android.644eda7a3020dd44"
},
{
"kind": "ui-call",
"line": 225,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt",
"source": "Trust",
"surface": "android",
"id": "native.android.9ac2d4498b17d478"
},
{
"kind": "ui-call",
"line": 230,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt",
"source": "Cancel",
"surface": "android",
"id": "native.android.e26ee07a1d1911be"
},
{
"kind": "ui-call",
"line": 416,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt",
"source": "Your personal AI assistant.\nExfoliate! Exfoliate!",
"surface": "android",
"id": "native.android.57eade577dad4d30"
},
{
"kind": "ui-property",
"line": 434,
"kind": "ui-wrapper-argument",
"line": 427,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt",
"source": "Connect Gateway",
"surface": "android",
@@ -1963,95 +2179,183 @@
},
{
"kind": "ui-property",
"line": 450,
"line": 443,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt",
"source": "OpenClaw logo",
"surface": "android",
"id": "native.android.15ac481631a30324"
},
{
"kind": "ui-wrapper-argument",
"line": 537,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt",
"source": "Gateway Setup",
"surface": "android",
"id": "native.android.1516c3a171d7376f"
},
{
"kind": "ui-property",
"line": 578,
"line": 542,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt",
"source": "Scan setup code",
"surface": "android",
"id": "native.android.76ceadaf7b51474c"
},
{
"kind": "ui-property",
"line": 550,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt",
"source": "Nearby gateway",
"surface": "android",
"id": "native.android.bfd274cb057bd574"
},
{
"kind": "ui-property",
"line": 559,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt",
"source": "Enter gateway URL",
"surface": "android",
"id": "native.android.25e15f33b1c19f06"
},
{
"kind": "ui-property",
"line": 567,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt",
"source": "Setup code issue",
"surface": "android",
"id": "native.android.1c98a29d88f42418"
},
{
"kind": "ui-call",
"line": 595,
"kind": "ui-wrapper-argument",
"line": 584,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt",
"source": "Advanced",
"surface": "android",
"id": "native.android.7552d5a1dcb88478"
},
{
"kind": "ui-property",
"line": 604,
"kind": "ui-wrapper-argument",
"line": 593,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt",
"source": "Setup code",
"surface": "android",
"id": "native.android.141c95005e676db1"
},
{
"kind": "ui-property",
"line": 606,
"kind": "ui-wrapper-argument",
"line": 595,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt",
"source": "Host",
"surface": "android",
"id": "native.android.443d858a6ca5f601"
},
{
"kind": "ui-property",
"line": 607,
"kind": "ui-wrapper-argument",
"line": 596,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt",
"source": "Port",
"surface": "android",
"id": "native.android.7cf45f21fb09bc37"
},
{
"kind": "ui-property",
"line": 613,
"kind": "conditional-branch",
"line": 599,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt",
"source": "TLS off",
"surface": "android",
"id": "native.android.20d94e1cedd3f319"
},
{
"kind": "conditional-branch",
"line": 599,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt",
"source": "TLS on",
"surface": "android",
"id": "native.android.a3a158b4a10d34ba"
},
{
"kind": "ui-wrapper-argument",
"line": 600,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt",
"source": "Local",
"surface": "android",
"id": "native.android.4dc1b6cf20c305b2"
},
{
"kind": "ui-wrapper-argument",
"line": 602,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt",
"source": "Token optional",
"surface": "android",
"id": "native.android.c0720e16ee7ce3c8"
},
{
"kind": "ui-property",
"line": 614,
"kind": "ui-wrapper-argument",
"line": 603,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt",
"source": "Password optional",
"surface": "android",
"id": "native.android.654546c96d8ca11c"
},
{
"kind": "ui-call",
"line": 688,
"kind": "ui-wrapper-argument",
"line": 608,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt",
"source": "Pair with Gateway",
"surface": "android",
"id": "native.android.69199b32069173f7"
},
{
"kind": "ui-wrapper-argument",
"line": 641,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt",
"source": "Gateway Recovery",
"surface": "android",
"id": "native.android.62cff50b54cbcdf2"
},
{
"kind": "ui-wrapper-argument",
"line": 677,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt",
"source": "Last gateway",
"surface": "android",
"id": "native.android.a40c59a92d7e402f"
},
{
"kind": "ui-property",
"line": 735,
"kind": "conditional-branch",
"line": 719,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt",
"source": "Continue",
"surface": "android",
"id": "native.android.cb352d79dc9a8156"
},
{
"kind": "conditional-branch",
"line": 719,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt",
"source": "Retry connection",
"surface": "android",
"id": "native.android.3b169db8b57795b5"
},
{
"kind": "ui-wrapper-argument",
"line": 724,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt",
"source": "Edit connection",
"surface": "android",
"id": "native.android.b5c86ec385060f0e"
},
{
"kind": "ui-property",
"line": 736,
"kind": "ui-wrapper-argument",
"line": 725,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt",
"source": "Copy diagnostic",
"surface": "android",
"id": "native.android.94b4bbf4e4a95867"
},
{
"kind": "ui-property",
"line": 770,
"kind": "ui-wrapper-argument",
"line": 759,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt",
"source": "Copy approval command",
"surface": "android",
@@ -2059,7 +2363,7 @@
},
{
"kind": "ui-call",
"line": 796,
"line": 785,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt",
"source": "Allow permissions",
"surface": "android",
@@ -2067,23 +2371,15 @@
},
{
"kind": "ui-call",
"line": 801,
"line": 790,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt",
"source": "These permissions keep OpenClaw secure\nand useful.",
"surface": "android",
"id": "native.android.405adf25f42a55a1"
},
{
"kind": "ui-property",
"line": 852,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt",
"source": "Back",
"surface": "android",
"id": "native.android.bbb5487f0dc5555c"
},
{
"kind": "ui-property",
"line": 880,
"kind": "ui-wrapper-argument",
"line": 869,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt",
"source": "Open $title",
"surface": "android",
@@ -2091,31 +2387,47 @@
},
{
"kind": "ui-call",
"line": 941,
"line": 926,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt",
"source": "Permissions",
"surface": "android",
"id": "native.android.1f83a6973cd9d621"
},
{
"kind": "ui-call",
"line": 928,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt",
"source": "Choose what this phone can share with OpenClaw. You can change these later in Settings.",
"surface": "android",
"id": "native.android.f38ca3445453a6bb"
},
{
"kind": "ui-property",
"line": 962,
"kind": "ui-call",
"line": 936,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt",
"source": "Done",
"surface": "android",
"id": "native.android.552df4241451e350"
},
{
"kind": "ui-wrapper-argument",
"line": 949,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt",
"source": "Back",
"surface": "android",
"id": "native.android.bbb5487f0dc5555c.962"
"id": "native.android.f7f0fe046cd417a0"
},
{
"kind": "ui-call",
"line": 965,
"line": 952,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt",
"source": "Permission Setup",
"surface": "android",
"id": "native.android.a67520d5c3818724"
},
{
"kind": "ui-call",
"line": 1046,
"kind": "conditional-branch",
"line": 1008,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt",
"source": "Granted",
"surface": "android",
@@ -2131,7 +2443,7 @@
},
{
"kind": "ui-property",
"line": 1062,
"line": 1049,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt",
"source": "Connected",
"surface": "android",
@@ -2139,7 +2451,7 @@
},
{
"kind": "ui-property",
"line": 1063,
"line": 1050,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt",
"source": "Your Gateway is ready.",
"surface": "android",
@@ -2147,15 +2459,7 @@
},
{
"kind": "ui-property",
"line": 1066,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt",
"source": "Pairing Gateway",
"surface": "android",
"id": "native.android.2c7c31ff12ac75d4"
},
{
"kind": "ui-property",
"line": 1067,
"line": 1054,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt",
"source": "Approve this phone on the gateway.\nThen retry the connection.",
"surface": "android",
@@ -2163,7 +2467,7 @@
},
{
"kind": "ui-property",
"line": 1070,
"line": 1057,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt",
"source": "Node Approval Pending",
"surface": "android",
@@ -2171,7 +2475,7 @@
},
{
"kind": "ui-property",
"line": 1071,
"line": 1058,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt",
"source": "Gateway pairing worked.\nApprove this phone's node capabilities from an operator UI.",
"surface": "android",
@@ -2179,15 +2483,15 @@
},
{
"kind": "ui-property",
"line": 1074,
"line": 1061,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt",
"source": "Pairing Gateway",
"surface": "android",
"id": "native.android.2c7c31ff12ac75d4.1074"
"id": "native.android.2c7c31ff12ac75d4"
},
{
"kind": "ui-property",
"line": 1075,
"line": 1062,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt",
"source": "Approval is in progress.\nOpenClaw will reconnect automatically.",
"surface": "android",
@@ -2195,7 +2499,7 @@
},
{
"kind": "ui-property",
"line": 1078,
"line": 1065,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt",
"source": "Connecting Gateway",
"surface": "android",
@@ -2203,7 +2507,7 @@
},
{
"kind": "ui-property",
"line": 1079,
"line": 1066,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt",
"source": "OpenClaw is checking gateway and node access.",
"surface": "android",
@@ -2211,7 +2515,7 @@
},
{
"kind": "ui-property",
"line": 1082,
"line": 1069,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt",
"source": "Connection issue",
"surface": "android",
@@ -2219,7 +2523,7 @@
},
{
"kind": "ui-property",
"line": 1083,
"line": 1070,
"path": "apps/android/app/src/main/java/ai/openclaw/app/ui/OnboardingFlow.kt",
"source": "We could not reach your Gateway.\nLet's fix this.",
"surface": "android",

View File

@@ -2,7 +2,6 @@ package ai.openclaw.app.ui
import ai.openclaw.app.GatewayConnectionProblem
import ai.openclaw.app.MainViewModel
import ai.openclaw.app.R
import ai.openclaw.app.ui.mobileCardSurface
import androidx.compose.animation.AnimatedVisibility
import androidx.compose.foundation.BorderStroke
@@ -52,7 +51,6 @@ import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.input.KeyboardType
@@ -102,7 +100,7 @@ fun ConnectTabScreen(viewModel: MainViewModel) {
AlertDialog(
onDismissRequest = { viewModel.declineGatewayTrustPrompt() },
containerColor = mobileCardSurface,
title = { Text(stringResource(R.string.trust_this_gateway), style = mobileHeadline, color = mobileText) },
title = { Text("Trust this gateway?", style = mobileHeadline, color = mobileText) },
text = {
val message =
if (prompt.previousFingerprintSha256.isNullOrBlank()) {
@@ -121,7 +119,7 @@ fun ConnectTabScreen(viewModel: MainViewModel) {
onClick = { viewModel.acceptGatewayTrustPrompt() },
colors = ButtonDefaults.textButtonColors(contentColor = mobileAccent),
) {
Text(stringResource(R.string.trust_and_continue))
Text("Trust and continue")
}
},
dismissButton = {
@@ -129,7 +127,7 @@ fun ConnectTabScreen(viewModel: MainViewModel) {
onClick = { viewModel.declineGatewayTrustPrompt() },
colors = ButtonDefaults.textButtonColors(contentColor = mobileTextSecondary),
) {
Text(stringResource(R.string.cancel))
Text("Cancel")
}
},
)
@@ -160,10 +158,9 @@ fun ConnectTabScreen(viewModel: MainViewModel) {
verticalArrangement = Arrangement.spacedBy(14.dp),
) {
Column(verticalArrangement = Arrangement.spacedBy(6.dp)) {
Text(stringResource(R.string.gateway_connection), style = mobileTitle1, color = mobileText)
Text("Gateway Connection", style = mobileTitle1, color = mobileText)
Text(
if (isConnected) stringResource(R.string.connected_gateway_ready)
else stringResource(R.string.connect_gateway_get_started),
if (isConnected) "Your gateway is active and ready." else "Connect to your gateway to get started.",
style = mobileCallout,
color = mobileTextSecondary,
)
@@ -194,7 +191,7 @@ fun ConnectTabScreen(viewModel: MainViewModel) {
)
}
Column(verticalArrangement = Arrangement.spacedBy(2.dp)) {
Text(stringResource(R.string.endpoint), style = mobileCaption1.copy(fontWeight = FontWeight.SemiBold), color = mobileTextSecondary)
Text("Endpoint", style = mobileCaption1.copy(fontWeight = FontWeight.SemiBold), color = mobileTextSecondary)
Text(activeEndpoint, style = mobileBody.copy(fontFamily = FontFamily.Monospace), color = mobileText)
}
}
@@ -216,7 +213,7 @@ fun ConnectTabScreen(viewModel: MainViewModel) {
)
}
Column(verticalArrangement = Arrangement.spacedBy(2.dp)) {
Text(stringResource(R.string.status), style = mobileCaption1.copy(fontWeight = FontWeight.SemiBold), color = mobileTextSecondary)
Text("Status", style = mobileCaption1.copy(fontWeight = FontWeight.SemiBold), color = mobileTextSecondary)
Text(statusText, style = mobileBody, color = if (isConnected) mobileSuccess else mobileText)
}
}
@@ -241,7 +238,7 @@ fun ConnectTabScreen(viewModel: MainViewModel) {
) {
Icon(Icons.Default.PowerSettingsNew, contentDescription = null, modifier = Modifier.size(18.dp))
Spacer(modifier = Modifier.width(8.dp))
Text(stringResource(R.string.disconnect), style = mobileHeadline.copy(fontWeight = FontWeight.SemiBold))
Text("Disconnect", style = mobileHeadline.copy(fontWeight = FontWeight.SemiBold))
}
} else {
Button(
@@ -310,7 +307,7 @@ fun ConnectTabScreen(viewModel: MainViewModel) {
contentColor = Color.White,
),
) {
Text(stringResource(R.string.connect_gateway), style = mobileHeadline.copy(fontWeight = FontWeight.Bold))
Text("Connect Gateway", style = mobileHeadline.copy(fontWeight = FontWeight.Bold))
}
}
@@ -357,7 +354,7 @@ fun ConnectTabScreen(viewModel: MainViewModel) {
) {
Icon(Icons.Default.ContentCopy, contentDescription = null, modifier = Modifier.size(18.dp))
Spacer(modifier = Modifier.width(8.dp))
Text(stringResource(R.string.copy_report_for_claw), style = mobileCallout.copy(fontWeight = FontWeight.Bold))
Text("Copy Report for Claw", style = mobileCallout.copy(fontWeight = FontWeight.Bold))
}
}
}
@@ -376,7 +373,7 @@ fun ConnectTabScreen(viewModel: MainViewModel) {
horizontalArrangement = Arrangement.SpaceBetween,
) {
Column(verticalArrangement = Arrangement.spacedBy(2.dp)) {
Text(stringResource(R.string.advanced_controls), style = mobileHeadline, color = mobileText)
Text("Advanced controls", style = mobileHeadline, color = mobileText)
Text("Setup code, endpoint, TLS, token, password, onboarding.", style = mobileCaption1, color = mobileTextSecondary)
}
Icon(
@@ -398,15 +395,15 @@ fun ConnectTabScreen(viewModel: MainViewModel) {
modifier = Modifier.fillMaxWidth().padding(horizontal = 14.dp, vertical = 14.dp),
verticalArrangement = Arrangement.spacedBy(12.dp),
) {
Text(stringResource(R.string.connection_method), style = mobileCaption1.copy(fontWeight = FontWeight.SemiBold), color = mobileTextSecondary)
Text("Connection method", style = mobileCaption1.copy(fontWeight = FontWeight.SemiBold), color = mobileTextSecondary)
Row(horizontalArrangement = Arrangement.spacedBy(8.dp)) {
MethodChip(
label = stringResource(R.string.setup_code),
label = "Setup Code",
active = inputMode == ConnectInputMode.SetupCode,
onClick = { inputMode = ConnectInputMode.SetupCode },
)
MethodChip(
label = stringResource(R.string.manual),
label = "Manual",
active = inputMode == ConnectInputMode.Manual,
onClick = { inputMode = ConnectInputMode.Manual },
)
@@ -422,14 +419,14 @@ fun ConnectTabScreen(viewModel: MainViewModel) {
)
if (inputMode == ConnectInputMode.SetupCode) {
Text(stringResource(R.string.setup_code), style = mobileCaption1.copy(fontWeight = FontWeight.SemiBold), color = mobileTextSecondary)
Text("Setup Code", style = mobileCaption1.copy(fontWeight = FontWeight.SemiBold), color = mobileTextSecondary)
OutlinedTextField(
value = setupCode,
onValueChange = {
setupCode = it
validationText = null
},
placeholder = { Text(stringResource(R.string.paste_setup_code), style = mobileBody, color = mobileTextTertiary) },
placeholder = { Text("Paste setup code", style = mobileBody, color = mobileTextTertiary) },
modifier = Modifier.fillMaxWidth(),
minLines = 3,
maxLines = 5,
@@ -463,7 +460,7 @@ fun ConnectTabScreen(viewModel: MainViewModel) {
)
}
Text(stringResource(R.string.host), style = mobileCaption1.copy(fontWeight = FontWeight.SemiBold), color = mobileTextSecondary)
Text("Host", style = mobileCaption1.copy(fontWeight = FontWeight.SemiBold), color = mobileTextSecondary)
OutlinedTextField(
value = manualHostInput,
onValueChange = {
@@ -505,7 +502,7 @@ fun ConnectTabScreen(viewModel: MainViewModel) {
horizontalArrangement = Arrangement.SpaceBetween,
) {
Column(verticalArrangement = Arrangement.spacedBy(2.dp)) {
Text(stringResource(R.string.use_tls), style = mobileHeadline, color = mobileText)
Text("Use TLS", style = mobileHeadline, color = mobileText)
Text(
"Turn this on for Tailscale or public hosts. Private LAN ws:// remains supported.",
style = mobileCallout,
@@ -528,7 +525,7 @@ fun ConnectTabScreen(viewModel: MainViewModel) {
)
}
Text(stringResource(R.string.token_optional), style = mobileCaption1.copy(fontWeight = FontWeight.SemiBold), color = mobileTextSecondary)
Text("Token (optional)", style = mobileCaption1.copy(fontWeight = FontWeight.SemiBold), color = mobileTextSecondary)
OutlinedTextField(
value = gatewayToken,
onValueChange = { viewModel.setGatewayToken(it) },
@@ -549,7 +546,7 @@ fun ConnectTabScreen(viewModel: MainViewModel) {
OutlinedTextField(
value = passwordInput,
onValueChange = { passwordInput = it },
placeholder = { Text(stringResource(R.string.password), style = mobileBody, color = mobileTextTertiary) },
placeholder = { Text("password", style = mobileBody, color = mobileTextTertiary) },
modifier = Modifier.fillMaxWidth(),
singleLine = true,
keyboardOptions = KeyboardOptions(keyboardType = KeyboardType.Ascii),
@@ -566,7 +563,7 @@ fun ConnectTabScreen(viewModel: MainViewModel) {
HorizontalDivider(color = mobileBorder)
TextButton(onClick = { viewModel.setOnboardingCompleted(false) }) {
Text(stringResource(R.string.run_onboarding_again), style = mobileCallout.copy(fontWeight = FontWeight.SemiBold), color = mobileAccent)
Text("Run onboarding again", style = mobileCallout.copy(fontWeight = FontWeight.SemiBold), color = mobileAccent)
}
}
}

View File

@@ -103,7 +103,6 @@ import androidx.compose.ui.graphics.drawscope.Stroke
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
@@ -213,13 +212,7 @@ fun OnboardingFlow(
AlertDialog(
onDismissRequest = viewModel::declineGatewayTrustPrompt,
containerColor = ClawTheme.colors.surfaceRaised,
title = {
Text(
stringResource(R.string.trust_this_gateway),
style = ClawTheme.type.section,
color = ClawTheme.colors.text,
)
},
title = { Text("Trust this gateway?", style = ClawTheme.type.section, color = ClawTheme.colors.text) },
text = {
Text(
"Verify the certificate fingerprint before continuing.\n\n${prompt.fingerprintSha256}",
@@ -229,12 +222,12 @@ fun OnboardingFlow(
},
confirmButton = {
TextButton(onClick = viewModel::acceptGatewayTrustPrompt) {
Text(stringResource(R.string.trust_and_continue))
Text("Trust")
}
},
dismissButton = {
TextButton(onClick = viewModel::declineGatewayTrustPrompt) {
Text(stringResource(R.string.cancel))
Text("Cancel")
}
},
)
@@ -541,24 +534,20 @@ private fun GatewaySetupScreen(
Column(modifier = Modifier.fillMaxSize().imePadding(), verticalArrangement = Arrangement.SpaceBetween) {
LazyColumn(verticalArrangement = Arrangement.spacedBy(9.dp)) {
item {
OnboardingHeader(
title = stringResource(R.string.gateway_setup),
subtitle = stringResource(R.string.connect_to_gateway),
onBack = onBack,
)
OnboardingHeader(title = "Gateway Setup", subtitle = "Connect to your Gateway", onBack = onBack)
}
item {
GatewayOption(
icon = Icons.Default.QrCode2,
title = stringResource(R.string.scan_setup_code),
subtitle = stringResource(R.string.use_gateway_qr),
title = "Scan setup code",
subtitle = "Use your Gateway QR or setup code",
onClick = onScan,
)
}
item {
GatewayOption(
icon = Icons.Default.WifiTethering,
title = stringResource(R.string.nearby_gateway),
title = "Nearby gateway",
subtitle = nearbyGateway.subtitle,
status = nearbyGateway.status,
onClick = onUseNearby.takeIf { nearbyGateway.canConnect },
@@ -567,8 +556,8 @@ private fun GatewaySetupScreen(
item {
GatewayOption(
icon = Icons.Default.Link,
title = stringResource(R.string.enter_gateway_url),
subtitle = stringResource(R.string.connect_manual_url),
title = "Enter gateway URL",
subtitle = "Connect using a manual URL",
onClick = { advancedOpen = true },
)
}
@@ -649,7 +638,7 @@ private fun GatewayRecoveryScreen(
ClawScaffold(modifier = modifier, contentPadding = PaddingValues(horizontal = 18.dp, vertical = 16.dp)) {
Column(modifier = Modifier.fillMaxSize(), verticalArrangement = Arrangement.spacedBy(18.dp)) {
OnboardingHeader(title = stringResource(R.string.gateway_setup), onBack = onBack)
OnboardingHeader(title = "Gateway Recovery", onBack = onBack)
Spacer(modifier = Modifier.height(12.dp))
Column(modifier = Modifier.fillMaxWidth(), horizontalAlignment = Alignment.CenterHorizontally, verticalArrangement = Arrangement.spacedBy(12.dp)) {
Icon(
@@ -934,9 +923,7 @@ private fun PermissionTopBar(onBack: () -> Unit) {
AlertDialog(
onDismissRequest = { showHelp = false },
containerColor = ClawTheme.colors.surfaceRaised,
title = {
Text(stringResource(R.string.permissions), style = ClawTheme.type.section, color = ClawTheme.colors.text)
},
title = { Text("Permissions", style = ClawTheme.type.section, color = ClawTheme.colors.text) },
text = {
Text(
"Choose what this phone can share with OpenClaw. You can change these later in Settings.",
@@ -946,7 +933,7 @@ private fun PermissionTopBar(onBack: () -> Unit) {
},
confirmButton = {
TextButton(onClick = { showHelp = false }) {
Text(stringResource(R.string.done))
Text("Done")
}
},
)

View File

@@ -1,34 +0,0 @@
<resources>
<string name="app_name">OpenClaw Node</string>
<string name="gateway_connection">اتصال البوابة</string>
<string name="connect_gateway">توصيل البوابة</string>
<string name="disconnect">قطع الاتصال</string>
<string name="trust_this_gateway">هل تثق بهذه البوابة؟</string>
<string name="trust_and_continue">الثقة والمتابعة</string>
<string name="cancel">إلغاء</string>
<string name="endpoint">نقطة النهاية</string>
<string name="status">الحالة</string>
<string name="connected_gateway_ready">بوابتك نشطة وجاهزة.</string>
<string name="connect_gateway_get_started">اتصل ببوابتك للبدء.</string>
<string name="copy_report_for_claw">نسخ التقرير لـ Claw</string>
<string name="advanced_controls">عناصر التحكم المتقدمة</string>
<string name="connection_method">طريقة الاتصال</string>
<string name="setup_code">رمز الإعداد</string>
<string name="manual">يدوي</string>
<string name="paste_setup_code">الصق رمز الإعداد</string>
<string name="host">المضيف</string>
<string name="use_tls">استخدام TLS</string>
<string name="token_optional">الرمز المميز (اختياري)</string>
<string name="password">كلمة المرور</string>
<string name="run_onboarding_again">تشغيل الإعداد الأولي مرة أخرى</string>
<string name="resolved_endpoint">نقطة النهاية التي تم حلها</string>
<string name="gateway_setup">إعداد البوابة</string>
<string name="connect_to_gateway">الاتصال ببوابتك</string>
<string name="scan_setup_code">مسح رمز الإعداد</string>
<string name="use_gateway_qr">استخدم رمز QR الخاص ببوابتك أو رمز الإعداد</string>
<string name="nearby_gateway">بوابة قريبة</string>
<string name="enter_gateway_url">أدخل عنوان URL للبوابة</string>
<string name="connect_manual_url">الاتصال باستخدام عنوان URL يدوي</string>
<string name="permissions">الأذونات</string>
<string name="done">تم</string>
</resources>

View File

@@ -1,34 +0,0 @@
<resources>
<string name="app_name">OpenClaw Node</string>
<string name="gateway_connection">Gateway-Verbindung</string>
<string name="connect_gateway">Gateway verbinden</string>
<string name="disconnect">Trennen</string>
<string name="trust_this_gateway">Diesem Gateway vertrauen?</string>
<string name="trust_and_continue">Vertrauen und fortfahren</string>
<string name="cancel">Abbrechen</string>
<string name="endpoint">Endpunkt</string>
<string name="status">Status</string>
<string name="connected_gateway_ready">Ihr Gateway ist aktiv und bereit.</string>
<string name="connect_gateway_get_started">Verbinden Sie sich mit Ihrem Gateway, um loszulegen.</string>
<string name="copy_report_for_claw">Bericht für Claw kopieren</string>
<string name="advanced_controls">Erweiterte Steuerungen</string>
<string name="connection_method">Verbindungsmethode</string>
<string name="setup_code">Einrichtungscode</string>
<string name="manual">Manuell</string>
<string name="paste_setup_code">Einrichtungscode einfügen</string>
<string name="host">Host</string>
<string name="use_tls">TLS verwenden</string>
<string name="token_optional">Token (optional)</string>
<string name="password">Passwort</string>
<string name="run_onboarding_again">Onboarding erneut ausführen</string>
<string name="resolved_endpoint">Aufgelöster Endpunkt</string>
<string name="gateway_setup">Gateway-Einrichtung</string>
<string name="connect_to_gateway">Mit Ihrem Gateway verbinden</string>
<string name="scan_setup_code">Einrichtungscode scannen</string>
<string name="use_gateway_qr">Verwenden Sie Ihren Gateway-QR- oder Einrichtungscode</string>
<string name="nearby_gateway">Gateway in der Nähe</string>
<string name="enter_gateway_url">Gateway-URL eingeben</string>
<string name="connect_manual_url">Über eine manuelle URL verbinden</string>
<string name="permissions">Berechtigungen</string>
<string name="done">Fertig</string>
</resources>

View File

@@ -1,34 +0,0 @@
<resources>
<string name="app_name">OpenClaw Node</string>
<string name="gateway_connection">Conexión de Gateway</string>
<string name="connect_gateway">Conectar Gateway</string>
<string name="disconnect">Desconectar</string>
<string name="trust_this_gateway">¿Confiar en este gateway?</string>
<string name="trust_and_continue">Confiar y continuar</string>
<string name="cancel">Cancelar</string>
<string name="endpoint">Endpoint</string>
<string name="status">Estado</string>
<string name="connected_gateway_ready">Tu gateway está activo y listo.</string>
<string name="connect_gateway_get_started">Conéctate a tu gateway para empezar.</string>
<string name="copy_report_for_claw">Copiar informe para Claw</string>
<string name="advanced_controls">Controles avanzados</string>
<string name="connection_method">Método de conexión</string>
<string name="setup_code">Código de configuración</string>
<string name="manual">Manual</string>
<string name="paste_setup_code">Pegar código de configuración</string>
<string name="host">Host</string>
<string name="use_tls">Usar TLS</string>
<string name="token_optional">Token (opcional)</string>
<string name="password">Contraseña</string>
<string name="run_onboarding_again">Ejecutar la incorporación de nuevo</string>
<string name="resolved_endpoint">Endpoint resuelto</string>
<string name="gateway_setup">Configuración de Gateway</string>
<string name="connect_to_gateway">Conéctate a tu Gateway</string>
<string name="scan_setup_code">Escanear código de configuración</string>
<string name="use_gateway_qr">Usa el QR o código de configuración de tu Gateway</string>
<string name="nearby_gateway">Gateway cercano</string>
<string name="enter_gateway_url">Introduce la URL del gateway</string>
<string name="connect_manual_url">Conectar usando una URL manual</string>
<string name="permissions">Permisos</string>
<string name="done">Listo</string>
</resources>

View File

@@ -1,34 +0,0 @@
<resources>
<string name="app_name">OpenClaw Node</string>
<string name="gateway_connection">اتصال دروازه</string>
<string name="connect_gateway">اتصال به دروازه</string>
<string name="disconnect">قطع اتصال</string>
<string name="trust_this_gateway">به این دروازه اعتماد دارید؟</string>
<string name="trust_and_continue">اعتماد و ادامه</string>
<string name="cancel">لغو</string>
<string name="endpoint">نقطه پایانی</string>
<string name="status">وضعیت</string>
<string name="connected_gateway_ready">دروازه شما فعال و آماده است.</string>
<string name="connect_gateway_get_started">برای شروع، به دروازه خود متصل شوید.</string>
<string name="copy_report_for_claw">کپی گزارش برای Claw</string>
<string name="advanced_controls">کنترل‌های پیشرفته</string>
<string name="connection_method">روش اتصال</string>
<string name="setup_code">کد راه‌اندازی</string>
<string name="manual">دستی</string>
<string name="paste_setup_code">کد راه‌اندازی را جای‌گذاری کنید</string>
<string name="host">میزبان</string>
<string name="use_tls">استفاده از TLS</string>
<string name="token_optional">توکن (اختیاری)</string>
<string name="password">رمز عبور</string>
<string name="run_onboarding_again">اجرای دوباره فرایند شروع به کار</string>
<string name="resolved_endpoint">نقطه پایانی حل‌شده</string>
<string name="gateway_setup">راه‌اندازی دروازه</string>
<string name="connect_to_gateway">به دروازه خود متصل شوید</string>
<string name="scan_setup_code">اسکن کد راه‌اندازی</string>
<string name="use_gateway_qr">از QR دروازه یا کد راه‌اندازی خود استفاده کنید</string>
<string name="nearby_gateway">دروازه نزدیک</string>
<string name="enter_gateway_url">URL دروازه را وارد کنید</string>
<string name="connect_manual_url">اتصال با استفاده از URL دستی</string>
<string name="permissions">مجوزها</string>
<string name="done">انجام شد</string>
</resources>

View File

@@ -1,34 +0,0 @@
<resources>
<string name="app_name">OpenClaw Node</string>
<string name="gateway_connection">Connexion à la passerelle</string>
<string name="connect_gateway">Connecter la passerelle</string>
<string name="disconnect">Déconnecter</string>
<string name="trust_this_gateway">Faire confiance à cette passerelle ?</string>
<string name="trust_and_continue">Faire confiance et continuer</string>
<string name="cancel">Annuler</string>
<string name="endpoint">Point de terminaison</string>
<string name="status">État</string>
<string name="connected_gateway_ready">Votre passerelle est active et prête.</string>
<string name="connect_gateway_get_started">Connectez-vous à votre passerelle pour commencer.</string>
<string name="copy_report_for_claw">Copier le rapport pour Claw</string>
<string name="advanced_controls">Contrôles avancés</string>
<string name="connection_method">Méthode de connexion</string>
<string name="setup_code">Code de configuration</string>
<string name="manual">Manuel</string>
<string name="paste_setup_code">Coller le code de configuration</string>
<string name="host">Hôte</string>
<string name="use_tls">Utiliser TLS</string>
<string name="token_optional">Jeton (facultatif)</string>
<string name="password">Mot de passe</string>
<string name="run_onboarding_again">Relancer lintégration</string>
<string name="resolved_endpoint">Point de terminaison résolu</string>
<string name="gateway_setup">Configuration de la passerelle</string>
<string name="connect_to_gateway">Connectez-vous à votre Gateway</string>
<string name="scan_setup_code">Scanner le code de configuration</string>
<string name="use_gateway_qr">Utilisez le QR de votre Gateway ou le code de configuration</string>
<string name="nearby_gateway">Passerelle à proximité</string>
<string name="enter_gateway_url">Saisir lURL de la passerelle</string>
<string name="connect_manual_url">Se connecter avec une URL manuelle</string>
<string name="permissions">Autorisations</string>
<string name="done">Terminé</string>
</resources>

View File

@@ -1,34 +0,0 @@
<resources>
<string name="app_name">OpenClaw Node</string>
<string name="gateway_connection">गेटवे कनेक्शन</string>
<string name="connect_gateway">गेटवे कनेक्ट करें</string>
<string name="disconnect">डिस्कनेक्ट करें</string>
<string name="trust_this_gateway">इस गेटवे पर भरोसा करें?</string>
<string name="trust_and_continue">भरोसा करें और जारी रखें</string>
<string name="cancel">रद्द करें</string>
<string name="endpoint">एंडपॉइंट</string>
<string name="status">स्थिति</string>
<string name="connected_gateway_ready">आपका गेटवे सक्रिय और तैयार है।</string>
<string name="connect_gateway_get_started">शुरू करने के लिए अपने गेटवे से कनेक्ट करें।</string>
<string name="copy_report_for_claw">Claw के लिए रिपोर्ट कॉपी करें</string>
<string name="advanced_controls">उन्नत नियंत्रण</string>
<string name="connection_method">कनेक्शन विधि</string>
<string name="setup_code">सेटअप कोड</string>
<string name="manual">मैन्युअल</string>
<string name="paste_setup_code">सेटअप कोड पेस्ट करें</string>
<string name="host">होस्ट</string>
<string name="use_tls">TLS का उपयोग करें</string>
<string name="token_optional">टोकन (वैकल्पिक)</string>
<string name="password">पासवर्ड</string>
<string name="run_onboarding_again">ऑनबोर्डिंग फिर से चलाएँ</string>
<string name="resolved_endpoint">रिज़ॉल्व किया गया एंडपॉइंट</string>
<string name="gateway_setup">गेटवे सेटअप</string>
<string name="connect_to_gateway">अपने गेटवे से कनेक्ट करें</string>
<string name="scan_setup_code">सेटअप कोड स्कैन करें</string>
<string name="use_gateway_qr">अपने गेटवे QR या सेटअप कोड का उपयोग करें</string>
<string name="nearby_gateway">नज़दीकी गेटवे</string>
<string name="enter_gateway_url">गेटवे URL दर्ज करें</string>
<string name="connect_manual_url">मैन्युअल URL का उपयोग करके कनेक्ट करें</string>
<string name="permissions">अनुमतियाँ</string>
<string name="done">हो गया</string>
</resources>

View File

@@ -1,34 +0,0 @@
<resources>
<string name="app_name">OpenClaw Node</string>
<string name="gateway_connection">Koneksi Gateway</string>
<string name="connect_gateway">Hubungkan Gateway</string>
<string name="disconnect">Putuskan koneksi</string>
<string name="trust_this_gateway">Percayai gateway ini?</string>
<string name="trust_and_continue">Percayai dan lanjutkan</string>
<string name="cancel">Batal</string>
<string name="endpoint">Endpoint</string>
<string name="status">Status</string>
<string name="connected_gateway_ready">Gateway Anda aktif dan siap.</string>
<string name="connect_gateway_get_started">Hubungkan ke gateway Anda untuk memulai.</string>
<string name="copy_report_for_claw">Salin Laporan untuk Claw</string>
<string name="advanced_controls">Kontrol lanjutan</string>
<string name="connection_method">Metode koneksi</string>
<string name="setup_code">Kode Penyiapan</string>
<string name="manual">Manual</string>
<string name="paste_setup_code">Tempel kode penyiapan</string>
<string name="host">Host</string>
<string name="use_tls">Gunakan TLS</string>
<string name="token_optional">Token (opsional)</string>
<string name="password">Kata sandi</string>
<string name="run_onboarding_again">Jalankan onboarding lagi</string>
<string name="resolved_endpoint">Endpoint yang diselesaikan</string>
<string name="gateway_setup">Penyiapan Gateway</string>
<string name="connect_to_gateway">Hubungkan ke Gateway Anda</string>
<string name="scan_setup_code">Pindai kode penyiapan</string>
<string name="use_gateway_qr">Gunakan QR Gateway atau kode penyiapan Anda</string>
<string name="nearby_gateway">Gateway terdekat</string>
<string name="enter_gateway_url">Masukkan URL gateway</string>
<string name="connect_manual_url">Hubungkan menggunakan URL manual</string>
<string name="permissions">Izin</string>
<string name="done">Selesai</string>
</resources>

View File

@@ -1,34 +0,0 @@
<resources>
<string name="app_name">OpenClaw Node</string>
<string name="gateway_connection">Connessione al gateway</string>
<string name="connect_gateway">Connetti gateway</string>
<string name="disconnect">Disconnetti</string>
<string name="trust_this_gateway">Considerare attendibile questo gateway?</string>
<string name="trust_and_continue">Considera attendibile e continua</string>
<string name="cancel">Annulla</string>
<string name="endpoint">Endpoint</string>
<string name="status">Stato</string>
<string name="connected_gateway_ready">Il tuo gateway è attivo e pronto.</string>
<string name="connect_gateway_get_started">Connettiti al tuo gateway per iniziare.</string>
<string name="copy_report_for_claw">Copia report per Claw</string>
<string name="advanced_controls">Controlli avanzati</string>
<string name="connection_method">Metodo di connessione</string>
<string name="setup_code">Codice di configurazione</string>
<string name="manual">Manuale</string>
<string name="paste_setup_code">Incolla codice di configurazione</string>
<string name="host">Host</string>
<string name="use_tls">Usa TLS</string>
<string name="token_optional">Token (opzionale)</string>
<string name="password">Password</string>
<string name="run_onboarding_again">Esegui di nuovo l&apos;onboarding</string>
<string name="resolved_endpoint">Endpoint risolto</string>
<string name="gateway_setup">Configurazione gateway</string>
<string name="connect_to_gateway">Connettiti al tuo Gateway</string>
<string name="scan_setup_code">Scansiona codice di configurazione</string>
<string name="use_gateway_qr">Usa il QR del tuo Gateway o il codice di configurazione</string>
<string name="nearby_gateway">Gateway nelle vicinanze</string>
<string name="enter_gateway_url">Inserisci URL del gateway</string>
<string name="connect_manual_url">Connetti usando un URL manuale</string>
<string name="permissions">Autorizzazioni</string>
<string name="done">Fine</string>
</resources>

View File

@@ -1,34 +0,0 @@
<resources>
<string name="app_name">OpenClaw Node</string>
<string name="gateway_connection">ゲートウェイ接続</string>
<string name="connect_gateway">ゲートウェイに接続</string>
<string name="disconnect">切断</string>
<string name="trust_this_gateway">このゲートウェイを信頼しますか?</string>
<string name="trust_and_continue">信頼して続行</string>
<string name="cancel">キャンセル</string>
<string name="endpoint">エンドポイント</string>
<string name="status">ステータス</string>
<string name="connected_gateway_ready">ゲートウェイはアクティブで準備完了です。</string>
<string name="connect_gateway_get_started">開始するにはゲートウェイに接続してください。</string>
<string name="copy_report_for_claw">Claw 用レポートをコピー</string>
<string name="advanced_controls">詳細コントロール</string>
<string name="connection_method">接続方法</string>
<string name="setup_code">セットアップコード</string>
<string name="manual">手動</string>
<string name="paste_setup_code">セットアップコードを貼り付け</string>
<string name="host">ホスト</string>
<string name="use_tls">TLS を使用</string>
<string name="token_optional">トークン(任意)</string>
<string name="password">パスワード</string>
<string name="run_onboarding_again">オンボーディングを再実行</string>
<string name="resolved_endpoint">解決済みエンドポイント</string>
<string name="gateway_setup">ゲートウェイ設定</string>
<string name="connect_to_gateway">ゲートウェイに接続</string>
<string name="scan_setup_code">セットアップコードをスキャン</string>
<string name="use_gateway_qr">ゲートウェイの QR またはセットアップコードを使用</string>
<string name="nearby_gateway">近くのゲートウェイ</string>
<string name="enter_gateway_url">ゲートウェイ URL を入力</string>
<string name="connect_manual_url">手動 URL で接続</string>
<string name="permissions">権限</string>
<string name="done">完了</string>
</resources>

View File

@@ -1,34 +0,0 @@
<resources>
<string name="app_name">OpenClaw Node</string>
<string name="gateway_connection">게이트웨이 연결</string>
<string name="connect_gateway">게이트웨이 연결</string>
<string name="disconnect">연결 해제</string>
<string name="trust_this_gateway">이 게이트웨이를 신뢰하시겠습니까?</string>
<string name="trust_and_continue">신뢰하고 계속</string>
<string name="cancel">취소</string>
<string name="endpoint">엔드포인트</string>
<string name="status">상태</string>
<string name="connected_gateway_ready">게이트웨이가 활성화되어 준비되었습니다.</string>
<string name="connect_gateway_get_started">시작하려면 게이트웨이에 연결하세요.</string>
<string name="copy_report_for_claw">Claw용 보고서 복사</string>
<string name="advanced_controls">고급 제어</string>
<string name="connection_method">연결 방법</string>
<string name="setup_code">설정 코드</string>
<string name="manual">수동</string>
<string name="paste_setup_code">설정 코드 붙여넣기</string>
<string name="host">호스트</string>
<string name="use_tls">TLS 사용</string>
<string name="token_optional">토큰(선택 사항)</string>
<string name="password">비밀번호</string>
<string name="run_onboarding_again">온보딩 다시 실행</string>
<string name="resolved_endpoint">확인된 엔드포인트</string>
<string name="gateway_setup">게이트웨이 설정</string>
<string name="connect_to_gateway">게이트웨이에 연결</string>
<string name="scan_setup_code">설정 코드 스캔</string>
<string name="use_gateway_qr">게이트웨이 QR 또는 설정 코드 사용</string>
<string name="nearby_gateway">주변 게이트웨이</string>
<string name="enter_gateway_url">게이트웨이 URL 입력</string>
<string name="connect_manual_url">수동 URL을 사용하여 연결</string>
<string name="permissions">권한</string>
<string name="done">완료</string>
</resources>

View File

@@ -1,34 +0,0 @@
<resources>
<string name="app_name">OpenClaw Node</string>
<string name="gateway_connection">Gatewayverbinding</string>
<string name="connect_gateway">Gateway verbinden</string>
<string name="disconnect">Verbinding verbreken</string>
<string name="trust_this_gateway">Deze gateway vertrouwen?</string>
<string name="trust_and_continue">Vertrouwen en doorgaan</string>
<string name="cancel">Annuleren</string>
<string name="endpoint">Endpoint</string>
<string name="status">Status</string>
<string name="connected_gateway_ready">Je gateway is actief en klaar voor gebruik.</string>
<string name="connect_gateway_get_started">Verbind met je gateway om te beginnen.</string>
<string name="copy_report_for_claw">Rapport voor Claw kopiëren</string>
<string name="advanced_controls">Geavanceerde bediening</string>
<string name="connection_method">Verbindingsmethode</string>
<string name="setup_code">Setupcode</string>
<string name="manual">Handmatig</string>
<string name="paste_setup_code">Setupcode plakken</string>
<string name="host">Host</string>
<string name="use_tls">TLS gebruiken</string>
<string name="token_optional">Token (optioneel)</string>
<string name="password">Wachtwoord</string>
<string name="run_onboarding_again">Onboarding opnieuw uitvoeren</string>
<string name="resolved_endpoint">Opgelost endpoint</string>
<string name="gateway_setup">Gateway instellen</string>
<string name="connect_to_gateway">Verbinden met je Gateway</string>
<string name="scan_setup_code">Setupcode scannen</string>
<string name="use_gateway_qr">Gebruik je Gateway-QR-code of setupcode</string>
<string name="nearby_gateway">Gateway in de buurt</string>
<string name="enter_gateway_url">Gateway-URL invoeren</string>
<string name="connect_manual_url">Verbinden met een handmatige URL</string>
<string name="permissions">Machtigingen</string>
<string name="done">Gereed</string>
</resources>

View File

@@ -1,34 +0,0 @@
<resources>
<string name="app_name">OpenClaw Node</string>
<string name="gateway_connection">Połączenie z bramą</string>
<string name="connect_gateway">Połącz z bramą</string>
<string name="disconnect">Rozłącz</string>
<string name="trust_this_gateway">Ufać tej bramie?</string>
<string name="trust_and_continue">Zaufaj i kontynuuj</string>
<string name="cancel">Anuluj</string>
<string name="endpoint">Punkt końcowy</string>
<string name="status">Status</string>
<string name="connected_gateway_ready">Twoja brama jest aktywna i gotowa.</string>
<string name="connect_gateway_get_started">Połącz się ze swoją bramą, aby rozpocząć.</string>
<string name="copy_report_for_claw">Kopiuj raport dla Claw</string>
<string name="advanced_controls">Zaawansowane ustawienia</string>
<string name="connection_method">Metoda połączenia</string>
<string name="setup_code">Kod konfiguracji</string>
<string name="manual">Ręcznie</string>
<string name="paste_setup_code">Wklej kod konfiguracji</string>
<string name="host">Host</string>
<string name="use_tls">Użyj TLS</string>
<string name="token_optional">Token (opcjonalnie)</string>
<string name="password">Hasło</string>
<string name="run_onboarding_again">Uruchom ponownie wdrażanie</string>
<string name="resolved_endpoint">Rozpoznany punkt końcowy</string>
<string name="gateway_setup">Konfiguracja bramy</string>
<string name="connect_to_gateway">Połącz ze swoją bramą</string>
<string name="scan_setup_code">Zeskanuj kod konfiguracji</string>
<string name="use_gateway_qr">Użyj kodu QR bramy lub kodu konfiguracji</string>
<string name="nearby_gateway">Pobliska brama</string>
<string name="enter_gateway_url">Wprowadź URL bramy</string>
<string name="connect_manual_url">Połącz, używając ręcznego URL</string>
<string name="permissions">Uprawnienia</string>
<string name="done">Gotowe</string>
</resources>

View File

@@ -1,34 +0,0 @@
<resources>
<string name="app_name">OpenClaw Node</string>
<string name="gateway_connection">Conexão do Gateway</string>
<string name="connect_gateway">Conectar Gateway</string>
<string name="disconnect">Desconectar</string>
<string name="trust_this_gateway">Confiar neste gateway?</string>
<string name="trust_and_continue">Confiar e continuar</string>
<string name="cancel">Cancelar</string>
<string name="endpoint">Endpoint</string>
<string name="status">Status</string>
<string name="connected_gateway_ready">Seu gateway está ativo e pronto.</string>
<string name="connect_gateway_get_started">Conecte-se ao seu gateway para começar.</string>
<string name="copy_report_for_claw">Copiar relatório para o Claw</string>
<string name="advanced_controls">Controles avançados</string>
<string name="connection_method">Método de conexão</string>
<string name="setup_code">Código de configuração</string>
<string name="manual">Manual</string>
<string name="paste_setup_code">Colar código de configuração</string>
<string name="host">Host</string>
<string name="use_tls">Usar TLS</string>
<string name="token_optional">Token (opcional)</string>
<string name="password">Senha</string>
<string name="run_onboarding_again">Executar integração novamente</string>
<string name="resolved_endpoint">Endpoint resolvido</string>
<string name="gateway_setup">Configuração do Gateway</string>
<string name="connect_to_gateway">Conecte-se ao seu Gateway</string>
<string name="scan_setup_code">Escanear código de configuração</string>
<string name="use_gateway_qr">Use o QR do seu Gateway ou o código de configuração</string>
<string name="nearby_gateway">Gateway próximo</string>
<string name="enter_gateway_url">Inserir URL do gateway</string>
<string name="connect_manual_url">Conectar usando uma URL manual</string>
<string name="permissions">Permissões</string>
<string name="done">Concluído</string>
</resources>

View File

@@ -1,34 +0,0 @@
<resources>
<string name="app_name">OpenClaw Node</string>
<string name="gateway_connection">Подключение к шлюзу</string>
<string name="connect_gateway">Подключить шлюз</string>
<string name="disconnect">Отключить</string>
<string name="trust_this_gateway">Доверять этому шлюзу?</string>
<string name="trust_and_continue">Доверять и продолжить</string>
<string name="cancel">Отмена</string>
<string name="endpoint">Конечная точка</string>
<string name="status">Статус</string>
<string name="connected_gateway_ready">Ваш шлюз активен и готов.</string>
<string name="connect_gateway_get_started">Подключитесь к своему шлюзу, чтобы начать.</string>
<string name="copy_report_for_claw">Скопировать отчет для Claw</string>
<string name="advanced_controls">Расширенные настройки</string>
<string name="connection_method">Способ подключения</string>
<string name="setup_code">Код настройки</string>
<string name="manual">Вручную</string>
<string name="paste_setup_code">Вставьте код настройки</string>
<string name="host">Хост</string>
<string name="use_tls">Использовать TLS</string>
<string name="token_optional">Токен (необязательно)</string>
<string name="password">Пароль</string>
<string name="run_onboarding_again">Запустить настройку заново</string>
<string name="resolved_endpoint">Разрешенная конечная точка</string>
<string name="gateway_setup">Настройка шлюза</string>
<string name="connect_to_gateway">Подключитесь к своему шлюзу</string>
<string name="scan_setup_code">Сканировать код настройки</string>
<string name="use_gateway_qr">Используйте QR-код или код настройки вашего шлюза</string>
<string name="nearby_gateway">Шлюз поблизости</string>
<string name="enter_gateway_url">Введите URL шлюза</string>
<string name="connect_manual_url">Подключиться с помощью URL вручную</string>
<string name="permissions">Разрешения</string>
<string name="done">Готово</string>
</resources>

View File

@@ -1,34 +0,0 @@
<resources>
<string name="app_name">OpenClaw Node</string>
<string name="gateway_connection">การเชื่อมต่อเกตเวย์</string>
<string name="connect_gateway">เชื่อมต่อเกตเวย์</string>
<string name="disconnect">ตัดการเชื่อมต่อ</string>
<string name="trust_this_gateway">เชื่อถือเกตเวย์นี้หรือไม่?</string>
<string name="trust_and_continue">เชื่อถือและดำเนินการต่อ</string>
<string name="cancel">ยกเลิก</string>
<string name="endpoint">เอนด์พอยต์</string>
<string name="status">สถานะ</string>
<string name="connected_gateway_ready">เกตเวย์ของคุณเปิดใช้งานและพร้อมใช้งานแล้ว</string>
<string name="connect_gateway_get_started">เชื่อมต่อกับเกตเวย์ของคุณเพื่อเริ่มต้นใช้งาน</string>
<string name="copy_report_for_claw">คัดลอกรายงานสำหรับ Claw</string>
<string name="advanced_controls">การควบคุมขั้นสูง</string>
<string name="connection_method">วิธีการเชื่อมต่อ</string>
<string name="setup_code">รหัสตั้งค่า</string>
<string name="manual">ด้วยตนเอง</string>
<string name="paste_setup_code">วางรหัสตั้งค่า</string>
<string name="host">โฮสต์</string>
<string name="use_tls">ใช้ TLS</string>
<string name="token_optional">โทเค็น (ไม่บังคับ)</string>
<string name="password">รหัสผ่าน</string>
<string name="run_onboarding_again">เรียกใช้การเริ่มต้นใช้งานอีกครั้ง</string>
<string name="resolved_endpoint">เอนด์พอยต์ที่แก้ไขแล้ว</string>
<string name="gateway_setup">การตั้งค่าเกตเวย์</string>
<string name="connect_to_gateway">เชื่อมต่อกับเกตเวย์ของคุณ</string>
<string name="scan_setup_code">สแกนรหัสตั้งค่า</string>
<string name="use_gateway_qr">ใช้ QR ของเกตเวย์หรือรหัสตั้งค่าของคุณ</string>
<string name="nearby_gateway">เกตเวย์ใกล้เคียง</string>
<string name="enter_gateway_url">ป้อน URL เกตเวย์</string>
<string name="connect_manual_url">เชื่อมต่อโดยใช้ URL ด้วยตนเอง</string>
<string name="permissions">สิทธิ์</string>
<string name="done">เสร็จสิ้น</string>
</resources>

View File

@@ -1,34 +0,0 @@
<resources>
<string name="app_name">OpenClaw Node</string>
<string name="gateway_connection">Ağ Geçidi Bağlantısı</string>
<string name="connect_gateway">Ağ Geçidine Bağlan</string>
<string name="disconnect">Bağlantıyı Kes</string>
<string name="trust_this_gateway">Bu ağ geçidine güvenilsin mi?</string>
<string name="trust_and_continue">Güven ve devam et</string>
<string name="cancel">İptal</string>
<string name="endpoint">Uç nokta</string>
<string name="status">Durum</string>
<string name="connected_gateway_ready">Ağ geçidiniz etkin ve hazır.</string>
<string name="connect_gateway_get_started">Başlamak için ağ geçidinize bağlanın.</string>
<string name="copy_report_for_claw">Claw için Raporu Kopyala</string>
<string name="advanced_controls">Gelişmiş kontroller</string>
<string name="connection_method">Bağlantı yöntemi</string>
<string name="setup_code">Kurulum Kodu</string>
<string name="manual">Manuel</string>
<string name="paste_setup_code">Kurulum kodunu yapıştır</string>
<string name="host">Ana makine</string>
<string name="use_tls">TLS kullan</string>
<string name="token_optional">Token (isteğe bağlı)</string>
<string name="password">Parola</string>
<string name="run_onboarding_again">Başlangıç sürecini tekrar çalıştır</string>
<string name="resolved_endpoint">Çözümlenen uç nokta</string>
<string name="gateway_setup">Ağ Geçidi Kurulumu</string>
<string name="connect_to_gateway">Ağ Geçidinize Bağlanın</string>
<string name="scan_setup_code">Kurulum kodunu tara</string>
<string name="use_gateway_qr">Gateway QR kodunuzu veya kurulum kodunuzu kullanın</string>
<string name="nearby_gateway">Yakındaki ağ geçidi</string>
<string name="enter_gateway_url">Ağ geçidi URL&apos;sini girin</string>
<string name="connect_manual_url">Manuel URL kullanarak bağlan</string>
<string name="permissions">İzinler</string>
<string name="done">Bitti</string>
</resources>

View File

@@ -1,34 +0,0 @@
<resources>
<string name="app_name">OpenClaw Node</string>
<string name="gateway_connection">Підключення до шлюзу</string>
<string name="connect_gateway">Підключити шлюз</string>
<string name="disconnect">Відключити</string>
<string name="trust_this_gateway">Довіряти цьому шлюзу?</string>
<string name="trust_and_continue">Довіряти й продовжити</string>
<string name="cancel">Скасувати</string>
<string name="endpoint">Кінцева точка</string>
<string name="status">Стан</string>
<string name="connected_gateway_ready">Ваш шлюз активний і готовий.</string>
<string name="connect_gateway_get_started">Підключіться до свого шлюзу, щоб почати.</string>
<string name="copy_report_for_claw">Скопіювати звіт для Claw</string>
<string name="advanced_controls">Розширені елементи керування</string>
<string name="connection_method">Спосіб підключення</string>
<string name="setup_code">Код налаштування</string>
<string name="manual">Вручну</string>
<string name="paste_setup_code">Вставте код налаштування</string>
<string name="host">Хост</string>
<string name="use_tls">Використовувати TLS</string>
<string name="token_optional">Токен (необов’язково)</string>
<string name="password">Пароль</string>
<string name="run_onboarding_again">Запустити адаптацію знову</string>
<string name="resolved_endpoint">Визначена кінцева точка</string>
<string name="gateway_setup">Налаштування шлюзу</string>
<string name="connect_to_gateway">Підключіться до свого шлюзу</string>
<string name="scan_setup_code">Сканувати код налаштування</string>
<string name="use_gateway_qr">Використайте QR-код свого шлюзу або код налаштування</string>
<string name="nearby_gateway">Шлюз поблизу</string>
<string name="enter_gateway_url">Введіть URL-адресу шлюзу</string>
<string name="connect_manual_url">Підключитися за допомогою URL-адреси вручну</string>
<string name="permissions">Дозволи</string>
<string name="done">Готово</string>
</resources>

View File

@@ -1,34 +0,0 @@
<resources>
<string name="app_name">OpenClaw Node</string>
<string name="gateway_connection">Kết nối cổng</string>
<string name="connect_gateway">Kết nối cổng</string>
<string name="disconnect">Ngắt kết nối</string>
<string name="trust_this_gateway">Tin cậy cổng này?</string>
<string name="trust_and_continue">Tin cậy và tiếp tục</string>
<string name="cancel">Hủy</string>
<string name="endpoint">Điểm cuối</string>
<string name="status">Trạng thái</string>
<string name="connected_gateway_ready">Cổng của bạn đang hoạt động và sẵn sàng.</string>
<string name="connect_gateway_get_started">Kết nối với cổng của bạn để bắt đầu.</string>
<string name="copy_report_for_claw">Sao chép báo cáo cho Claw</string>
<string name="advanced_controls">Điều khiển nâng cao</string>
<string name="connection_method">Phương thức kết nối</string>
<string name="setup_code">Mã thiết lập</string>
<string name="manual">Thủ công</string>
<string name="paste_setup_code">Dán mã thiết lập</string>
<string name="host">Máy chủ</string>
<string name="use_tls">Sử dụng TLS</string>
<string name="token_optional">Token (tùy chọn)</string>
<string name="password">Mật khẩu</string>
<string name="run_onboarding_again">Chạy hướng dẫn thiết lập lại</string>
<string name="resolved_endpoint">Điểm cuối đã phân giải</string>
<string name="gateway_setup">Thiết lập cổng</string>
<string name="connect_to_gateway">Kết nối với Gateway của bạn</string>
<string name="scan_setup_code">Quét mã thiết lập</string>
<string name="use_gateway_qr">Sử dụng mã QR Gateway hoặc mã thiết lập của bạn</string>
<string name="nearby_gateway">Cổng gần đây</string>
<string name="enter_gateway_url">Nhập URL cổng</string>
<string name="connect_manual_url">Kết nối bằng URL thủ công</string>
<string name="permissions">Quyền</string>
<string name="done">Xong</string>
</resources>

View File

@@ -1,34 +0,0 @@
<resources>
<string name="app_name">OpenClaw Node</string>
<string name="gateway_connection">网关连接</string>
<string name="connect_gateway">连接网关</string>
<string name="disconnect">断开连接</string>
<string name="trust_this_gateway">信任此网关?</string>
<string name="trust_and_continue">信任并继续</string>
<string name="cancel">取消</string>
<string name="endpoint">端点</string>
<string name="status">状态</string>
<string name="connected_gateway_ready">你的网关已激活并准备就绪。</string>
<string name="connect_gateway_get_started">连接到你的网关以开始使用。</string>
<string name="copy_report_for_claw">复制 Claw 报告</string>
<string name="advanced_controls">高级控制</string>
<string name="connection_method">连接方式</string>
<string name="setup_code">设置代码</string>
<string name="manual">手动</string>
<string name="paste_setup_code">粘贴设置代码</string>
<string name="host">主机</string>
<string name="use_tls">使用 TLS</string>
<string name="token_optional">令牌(可选)</string>
<string name="password">密码</string>
<string name="run_onboarding_again">再次运行引导流程</string>
<string name="resolved_endpoint">已解析的端点</string>
<string name="gateway_setup">网关设置</string>
<string name="connect_to_gateway">连接到你的网关</string>
<string name="scan_setup_code">扫描设置代码</string>
<string name="use_gateway_qr">使用你的网关 QR 码或设置代码</string>
<string name="nearby_gateway">附近的网关</string>
<string name="enter_gateway_url">输入网关 URL</string>
<string name="connect_manual_url">使用手动 URL 连接</string>
<string name="permissions">权限</string>
<string name="done">完成</string>
</resources>

View File

@@ -1,34 +0,0 @@
<resources>
<string name="app_name">OpenClaw Node</string>
<string name="gateway_connection">閘道連線</string>
<string name="connect_gateway">連接閘道</string>
<string name="disconnect">中斷連線</string>
<string name="trust_this_gateway">信任此閘道?</string>
<string name="trust_and_continue">信任並繼續</string>
<string name="cancel">取消</string>
<string name="endpoint">端點</string>
<string name="status">狀態</string>
<string name="connected_gateway_ready">您的閘道已啟用並準備就緒。</string>
<string name="connect_gateway_get_started">連接到您的閘道以開始使用。</string>
<string name="copy_report_for_claw">複製 Claw 報告</string>
<string name="advanced_controls">進階控制項</string>
<string name="connection_method">連線方式</string>
<string name="setup_code">設定碼</string>
<string name="manual">手動</string>
<string name="paste_setup_code">貼上設定碼</string>
<string name="host">主機</string>
<string name="use_tls">使用 TLS</string>
<string name="token_optional">權杖(選填)</string>
<string name="password">密碼</string>
<string name="run_onboarding_again">再次執行新手導覽</string>
<string name="resolved_endpoint">已解析的端點</string>
<string name="gateway_setup">閘道設定</string>
<string name="connect_to_gateway">連接到您的閘道</string>
<string name="scan_setup_code">掃描設定碼</string>
<string name="use_gateway_qr">使用您的 Gateway QR 或設定碼</string>
<string name="nearby_gateway">附近的閘道</string>
<string name="enter_gateway_url">輸入閘道 URL</string>
<string name="connect_manual_url">使用手動 URL 連接</string>
<string name="permissions">權限</string>
<string name="done">完成</string>
</resources>

View File

@@ -1,34 +1,3 @@
<resources>
<string name="app_name">OpenClaw Node</string>
<string name="gateway_connection">Gateway Connection</string>
<string name="connect_gateway">Connect Gateway</string>
<string name="disconnect">Disconnect</string>
<string name="trust_this_gateway">Trust this gateway?</string>
<string name="trust_and_continue">Trust and continue</string>
<string name="cancel">Cancel</string>
<string name="endpoint">Endpoint</string>
<string name="status">Status</string>
<string name="connected_gateway_ready">Your gateway is active and ready.</string>
<string name="connect_gateway_get_started">Connect to your gateway to get started.</string>
<string name="copy_report_for_claw">Copy Report for Claw</string>
<string name="advanced_controls">Advanced controls</string>
<string name="connection_method">Connection method</string>
<string name="setup_code">Setup Code</string>
<string name="manual">Manual</string>
<string name="paste_setup_code">Paste setup code</string>
<string name="host">Host</string>
<string name="use_tls">Use TLS</string>
<string name="token_optional">Token (optional)</string>
<string name="password">Password</string>
<string name="run_onboarding_again">Run onboarding again</string>
<string name="resolved_endpoint">Resolved endpoint</string>
<string name="gateway_setup">Gateway Setup</string>
<string name="connect_to_gateway">Connect to your Gateway</string>
<string name="scan_setup_code">Scan setup code</string>
<string name="use_gateway_qr">Use your Gateway QR or setup code</string>
<string name="nearby_gateway">Nearby gateway</string>
<string name="enter_gateway_url">Enter gateway URL</string>
<string name="connect_manual_url">Connect using a manual URL</string>
<string name="permissions">Permissions</string>
<string name="done">Done</string>
</resources>

View File

@@ -1953,7 +1953,6 @@
"ui:i18n:sync": "node --import tsx scripts/control-ui-i18n.ts sync --write",
"native:i18n:check": "node --import tsx scripts/native-app-i18n.ts check",
"native:i18n:sync": "node --import tsx scripts/native-app-i18n.ts sync --write",
"android:i18n:check": "node --import tsx scripts/android-app-i18n.ts check",
"ui:install": "node scripts/ui.js install",
"verify": "node scripts/verify.mjs"
},

View File

@@ -1,52 +0,0 @@
import { readFile } from "node:fs/promises";
import path from "node:path";
import { fileURLToPath } from "node:url";
import { NATIVE_I18N_LOCALES } from "./native-app-i18n.ts";
const HERE = path.dirname(fileURLToPath(import.meta.url));
const ROOT = path.resolve(HERE, "..");
const RESOURCE_ROOT = path.join(ROOT, "apps", "android", "app", "src", "main", "res");
const ANDROID_QUALIFIERS: Record<string, string> = {
"zh-CN": "zh-rCN",
"zh-TW": "zh-rTW",
"pt-BR": "pt-rBR",
"ja-JP": "ja",
};
const localeDirectory = (locale: string) => `values-${ANDROID_QUALIFIERS[locale] ?? locale}`;
const LOCALES = ["values", ...NATIVE_I18N_LOCALES.map(localeDirectory)] as const;
const KEY_RE = /<string\s+name="([A-Za-z0-9_]+)"[^>]*>/gu;
async function readKeys(locale: string): Promise<Set<string>> {
const source = await readFile(path.join(RESOURCE_ROOT, locale, "strings.xml"), "utf8");
return new Set([...source.matchAll(KEY_RE)].map((match) => match[1]).filter(Boolean));
}
export async function checkAndroidAppI18n() {
const [base, ...translations] = await Promise.all(LOCALES.map(readKeys));
const problems = translations.flatMap((keys, index) => {
const locale = NATIVE_I18N_LOCALES[index];
return [
[`${locale} missing`, [...base].filter((key) => !keys.has(key))],
[`${locale} extra`, [...keys].filter((key) => !base.has(key))],
] as const;
});
if (problems.some(([, keys]) => keys.length)) {
throw new Error(
[
"Android app i18n resources are out of sync.",
...problems.map(([label, keys]) => `${label}=${keys.join(",") || "none"}`),
].join("\n"),
);
}
process.stdout.write(
`android-app-i18n: keys=${base.size} locales=${NATIVE_I18N_LOCALES.join(",")}\n`,
);
}
if (process.argv[1] && import.meta.url === `file://${path.resolve(process.argv[1])}`) {
const [command] = process.argv.slice(2);
if (command !== "check") {
throw new Error("usage: node --import tsx scripts/android-app-i18n.ts check");
}
await checkAndroidAppI18n();
}

View File

@@ -1486,6 +1486,63 @@ async function translateBatch(
throw lastError ?? new Error("translation failed");
}
export type NativeTranslationEntry = {
id: string;
source: string;
sourcePath: string;
};
export async function translateNativeEntries(
entries: readonly NativeTranslationEntry[],
targetLocale: string,
glossary: readonly GlossaryEntry[] = [],
): Promise<Map<string, string>> {
if (!hasTranslationProvider()) {
throw new Error("native app translation requires OPENAI_API_KEY or ANTHROPIC_API_KEY");
}
const pending = entries.map((entry) => ({
cacheKey: cacheKey(entry.id, hashText(entry.source), targetLocale),
key: entry.id,
text: entry.source,
textHash: hashText(entry.source),
}));
const batches = buildTranslationBatches(pending);
let client: TranslationClient | null = null;
const clientAccess: ClientAccess = {
async getClient() {
if (!client) {
client = await TranslationClient.create(buildSystemPrompt(targetLocale, glossary));
}
return client;
},
async resetClient() {
if (!client) {
return;
}
await client.close();
client = null;
},
};
try {
const translated = new Map<string, string>();
for (const [batchIndex, batch] of batches.entries()) {
const result = await translateBatch(clientAccess, batch, {
locale: targetLocale,
localeCount: 1,
localeIndex: 1,
batchCount: batches.length,
batchIndex: batchIndex + 1,
});
for (const [id, value] of result) {
translated.set(id, value);
}
}
return translated;
} finally {
await clientAccess.resetClient();
}
}
type SyncOutcome = {
changed: boolean;
fallbackCount: number;

View File

@@ -2,6 +2,7 @@ import { createHash } from "node:crypto";
import { mkdir, readdir, readFile, writeFile } from "node:fs/promises";
import path from "node:path";
import { fileURLToPath } from "node:url";
import { translateNativeEntries } from "./control-ui-i18n.ts";
export type NativeI18nSurface = "android" | "apple";
@@ -38,10 +39,16 @@ export type NativeI18nEntry = {
};
type Candidate = Omit<NativeI18nEntry, "id">;
type NativeTranslationArtifact = {
entries: Array<{ id: string; source: string; translated: string }>;
locale: string;
version: 1;
};
const HERE = path.dirname(fileURLToPath(import.meta.url));
const ROOT = path.resolve(HERE, "..");
const OUTPUT_PATH = path.join(ROOT, "apps", ".i18n", "native-source.json");
const TRANSLATIONS_DIR = path.join(ROOT, "apps", ".i18n", "native");
const SOURCE_ROOTS: Record<NativeI18nSurface, string[]> = {
android: [path.join(ROOT, "apps", "android", "app", "src", "main")],
apple: [
@@ -80,21 +87,7 @@ const GENERATED_PATH_RE = /(?:^|[\\/])(?:build|\.gradle|\.build|DerivedData)(?:$
const EXCLUDED_PATH_RE = /(?:^|[\\/])(?:Tests?|UITests?|test|Preview(?:s)?)(?:$|[\\/])/u;
const EXCLUDED_FILE_RE = /(?:Tests?|UITests?|Previews?|Testing)\.(?:swift|kt|kts)$/u;
const BUILD_SETTING_RE = /\$\([A-Za-z0-9_.-]+\)/gu;
function isTranslatableCandidate(source: string, kind: string): boolean {
if (BUILD_SETTING_RE.test(source)) {
BUILD_SETTING_RE.lastIndex = 0;
return false;
}
BUILD_SETTING_RE.lastIndex = 0;
if (/^[a-z0-9_.:/$-]+$/u.test(source) || /^[A-Z0-9_.:/$-]+$/u.test(source)) {
return false;
}
if (/[{}[\]]/u.test(source) && !/(?:\\\(|\$\{)/u.test(source)) {
return false;
}
return kind !== "plist-string" || /\s/u.test(source);
}
const NATIVE_I18N_LOCALE_SET = new Set<string>(NATIVE_I18N_LOCALES);
function extractSwiftInterpolations(source: string): string[] | null {
const values: string[] = [];
@@ -160,6 +153,29 @@ function normalizeSource(source: string): string {
return source;
}
function structuralTokenSignature(source: string): string {
const swift = extractSwiftInterpolations(source);
const kotlin = extractKotlinInterpolations(source);
const buildSettings = source.match(BUILD_SETTING_RE) ?? [];
const lineBreaks = (source.match(/\n/gu) ?? []).length;
return JSON.stringify({ swift, kotlin, buildSettings, lineBreaks });
}
function isTranslatableCandidate(source: string, kind: string): boolean {
if (BUILD_SETTING_RE.test(source)) {
BUILD_SETTING_RE.lastIndex = 0;
return false;
}
BUILD_SETTING_RE.lastIndex = 0;
if (/^[a-z0-9_.:/$-]+$/u.test(source) || /^[A-Z0-9_.:/$-]+$/u.test(source)) {
return false;
}
if (/[{}[\]]/u.test(source) && !/(?:\\\(|\$\{)/u.test(source)) {
return false;
}
return kind !== "plist-string" || /\s/u.test(source);
}
function addCandidate(
entries: Candidate[],
surface: NativeI18nSurface,
@@ -346,15 +362,91 @@ export async function syncNativeI18n(options: { checkOnly: boolean; write: boole
process.stdout.write(`native-app-i18n: entries=${count} changed=${current !== expected}\n`);
}
async function loadGlossary(locale: string): Promise<Array<{ source: string; target: string }>> {
try {
return JSON.parse(
await readFile(
path.join(ROOT, "ui", "src", "i18n", ".i18n", `glossary.${locale}.json`),
"utf8",
),
) as Array<{ source: string; target: string }>;
} catch {
return [];
}
}
async function syncNativeLocale(locale: string, entries: NativeI18nEntry[]) {
// Native runtime resources are owned by the Android and Apple slices; these
// artifacts keep the shared translation-memory handoff current between them.
const artifactPath = path.join(TRANSLATIONS_DIR, `${locale}.json`);
let previous: NativeTranslationArtifact = { entries: [], locale, version: 1 };
try {
previous = JSON.parse(await readFile(artifactPath, "utf8")) as NativeTranslationArtifact;
} catch {
// The first refresh creates the locale artifact.
}
const previousById = new Map(previous.entries.map((entry) => [entry.id, entry]));
const pending = entries
.filter((entry) => {
const current = previousById.get(entry.id);
return !current || current.source !== entry.source || !current.translated.trim();
})
.map((entry) => ({
id: entry.id,
source: entry.source,
sourcePath: entry.path,
}));
const translated = pending.length
? await translateNativeEntries(pending, locale, await loadGlossary(locale))
: new Map<string, string>();
const artifact: NativeTranslationArtifact = {
version: 1,
locale,
entries: entries.map((entry) => ({
id: entry.id,
source: entry.source,
translated:
translated.get(entry.id) ?? previousById.get(entry.id)?.translated ?? entry.source,
})),
};
for (const entry of artifact.entries) {
if (structuralTokenSignature(entry.source) !== structuralTokenSignature(entry.translated)) {
throw new Error(
`native translation changed placeholders or line breaks for ${locale}:${entry.id}`,
);
}
}
await mkdir(TRANSLATIONS_DIR, { recursive: true });
await writeFile(artifactPath, `${JSON.stringify(artifact, null, 2)}\n`, "utf8");
process.stdout.write(
`native-app-i18n: locale=${locale} entries=${entries.length} translated=${translated.size}\n`,
);
}
async function main() {
const [command] = process.argv.slice(2);
const [command, ...args] = process.argv.slice(2);
if (command !== "check" && command !== "sync") {
throw new Error("usage: node --import tsx scripts/native-app-i18n.ts check|sync [--write]");
throw new Error(
"usage: node --import tsx scripts/native-app-i18n.ts check|sync [--write] [--locale <code>]",
);
}
await syncNativeI18n({
checkOnly: command === "check",
write: command === "sync" && process.argv.includes("--write"),
});
const localeFlag = args.indexOf("--locale");
const locale = localeFlag >= 0 ? args[localeFlag + 1] : undefined;
if (locale) {
if (command !== "sync" || !process.argv.includes("--write")) {
throw new Error("native locale refresh requires `sync --write --locale <code>`");
}
if (!NATIVE_I18N_LOCALE_SET.has(locale)) {
throw new Error(
`unsupported native locale "${locale}". Expected one of: ${NATIVE_I18N_LOCALES.join(", ")}`,
);
}
await syncNativeLocale(locale, await collectNativeI18nEntries());
}
}
if (process.argv[1] && import.meta.url === `file://${path.resolve(process.argv[1])}`) {

View File

@@ -747,7 +747,6 @@ const TOOLING_SOURCE_TEST_TARGETS = new Map([
["scripts/ci-docker-pull-retry.sh", ["test/scripts/ci-docker-pull-retry.test.ts"]],
["scripts/control-ui-i18n.ts", ["test/scripts/control-ui-i18n.test.ts"]],
["scripts/native-app-i18n.ts", ["test/scripts/native-app-i18n.test.ts"]],
["scripts/android-app-i18n.ts", ["test/scripts/android-app-i18n.test.ts"]],
[
"scripts/copy-bundled-plugin-metadata.mjs",
["src/plugins/copy-bundled-plugin-metadata.test.ts", "src/infra/run-node.test.ts"],

View File

@@ -1,8 +0,0 @@
import { describe, expect, it } from "vitest";
import { checkAndroidAppI18n } from "../../scripts/android-app-i18n.ts";
describe("Android app i18n resources", () => {
it("keeps every native locale resource key aligned with English", async () => {
await expect(checkAndroidAppI18n()).resolves.toBeUndefined();
});
});