diff --git a/apps/.i18n/apple-translation-contradictions.json b/apps/.i18n/apple-translation-contradictions.json
index 94e19624056..4c2222daaa9 100644
--- a/apps/.i18n/apple-translation-contradictions.json
+++ b/apps/.i18n/apple-translation-contradictions.json
@@ -1603,6 +1603,22 @@
"連線中"
]
},
+ {
+ "locale": "it",
+ "source": "Connecting...",
+ "translations": [
+ "Connessione in corso...",
+ "Connessione..."
+ ]
+ },
+ {
+ "locale": "nl",
+ "source": "Connecting...",
+ "translations": [
+ "Verbinden...",
+ "Verbinding maken..."
+ ]
+ },
{
"locale": "zh-TW",
"source": "Connecting...",
@@ -3323,39 +3339,23 @@
"source": "Gateway connected",
"translations": [
"Gateway متصل",
- "تم اتصال Gateway"
+ "تم الاتصال بـ Gateway"
]
},
{
- "locale": "fa",
+ "locale": "tr",
"source": "Gateway connected",
"translations": [
- "Gateway متصل است",
- "Gateway متصل شد"
+ "Gateway bağlandı",
+ "Gateway bağlı"
]
},
{
- "locale": "ja-JP",
+ "locale": "vi",
"source": "Gateway connected",
"translations": [
- "Gateway に接続しました",
- "Gatewayに接続済み"
- ]
- },
- {
- "locale": "pl",
- "source": "Gateway connected",
- "translations": [
- "Gateway połączony",
- "Połączono z Gateway"
- ]
- },
- {
- "locale": "ru",
- "source": "Gateway connected",
- "translations": [
- "Gateway подключен",
- "Gateway подключён"
+ "Gateway đã kết nối",
+ "Đã kết nối Gateway"
]
},
{
@@ -8680,6 +8680,14 @@
"Статус"
]
},
+ {
+ "locale": "id",
+ "source": "Stop",
+ "translations": [
+ "Berhenti",
+ "Hentikan"
+ ]
+ },
{
"locale": "ar",
"source": "Technical details",
diff --git a/apps/.i18n/native-source.json b/apps/.i18n/native-source.json
index 22240508612..7aff760b500 100644
--- a/apps/.i18n/native-source.json
+++ b/apps/.i18n/native-source.json
@@ -13923,7 +13923,7 @@
},
{
"kind": "conditional-branch",
- "line": 189,
+ "line": 193,
"path": "apps/ios/Sources/Camera/CameraController.swift",
"source": "Camera",
"surface": "apple",
@@ -13931,7 +13931,7 @@
},
{
"kind": "conditional-branch",
- "line": 189,
+ "line": 193,
"path": "apps/ios/Sources/Camera/CameraController.swift",
"source": "Microphone",
"surface": "apple",
@@ -17267,7 +17267,7 @@
},
{
"kind": "ui-localized-call",
- "line": 173,
+ "line": 174,
"path": "apps/ios/Sources/Design/ChatProTab.swift",
"source": "Unable to Export Transcript",
"surface": "apple",
@@ -17275,7 +17275,7 @@
},
{
"kind": "ui-call",
- "line": 177,
+ "line": 178,
"path": "apps/ios/Sources/Design/ChatProTab.swift",
"source": "OK",
"surface": "apple",
@@ -17283,7 +17283,7 @@
},
{
"kind": "ui-call",
- "line": 181,
+ "line": 182,
"path": "apps/ios/Sources/Design/ChatProTab.swift",
"source": "OpenClaw could not prepare the Markdown file.",
"surface": "apple",
@@ -17291,7 +17291,7 @@
},
{
"kind": "ui-localized-call",
- "line": 203,
+ "line": 204,
"path": "apps/ios/Sources/Design/ChatProTab.swift",
"source": "What would you like to work on?",
"surface": "apple",
@@ -17299,7 +17299,7 @@
},
{
"kind": "ui-call",
- "line": 223,
+ "line": 224,
"path": "apps/ios/Sources/Design/ChatProTab.swift",
"source": "The thread attaches once the gateway is ready.",
"surface": "apple",
@@ -17307,7 +17307,7 @@
},
{
"kind": "conditional-branch",
- "line": 311,
+ "line": 312,
"path": "apps/ios/Sources/Design/ChatProTab.swift",
"source": "Collapsed",
"surface": "apple",
@@ -17315,7 +17315,7 @@
},
{
"kind": "conditional-branch",
- "line": 311,
+ "line": 312,
"path": "apps/ios/Sources/Design/ChatProTab.swift",
"source": "Expanded",
"surface": "apple",
@@ -17323,7 +17323,7 @@
},
{
"kind": "ui-localized-call",
- "line": 381,
+ "line": 382,
"path": "apps/ios/Sources/Design/ChatProTab.swift",
"source": "Opens Settings / Gateway",
"surface": "apple",
@@ -17331,7 +17331,7 @@
},
{
"kind": "ui-localized-call",
- "line": 384,
+ "line": 385,
"path": "apps/ios/Sources/Design/ChatProTab.swift",
"source": "Hides the gateway status label",
"surface": "apple",
@@ -17339,7 +17339,7 @@
},
{
"kind": "ui-localized-call",
- "line": 385,
+ "line": 386,
"path": "apps/ios/Sources/Design/ChatProTab.swift",
"source": "Shows the full gateway status label",
"surface": "apple",
@@ -17347,7 +17347,7 @@
},
{
"kind": "ui-localized-call",
- "line": 404,
+ "line": 405,
"path": "apps/ios/Sources/Design/ChatProTab.swift",
"source": "Voice off",
"surface": "apple",
@@ -17355,7 +17355,7 @@
},
{
"kind": "ui-call",
- "line": 545,
+ "line": 568,
"path": "apps/ios/Sources/Design/ChatProTab.swift",
"source": "New Chat",
"surface": "apple",
@@ -17363,7 +17363,7 @@
},
{
"kind": "ui-call",
- "line": 558,
+ "line": 581,
"path": "apps/ios/Sources/Design/ChatProTab.swift",
"source": "New Chat in Worktree",
"surface": "apple",
@@ -17371,7 +17371,7 @@
},
{
"kind": "ui-localized-call",
- "line": 571,
+ "line": 594,
"path": "apps/ios/Sources/Design/ChatProTab.swift",
"source": "Threads…",
"surface": "apple",
@@ -17379,7 +17379,7 @@
},
{
"kind": "ui-call",
- "line": 584,
+ "line": 607,
"path": "apps/ios/Sources/Design/ChatProTab.swift",
"source": "Background Tasks",
"surface": "apple",
@@ -17387,7 +17387,7 @@
},
{
"kind": "ui-call",
- "line": 596,
+ "line": 619,
"path": "apps/ios/Sources/Design/ChatProTab.swift",
"source": "Export Transcript",
"surface": "apple",
@@ -17395,7 +17395,7 @@
},
{
"kind": "ui-call",
- "line": 609,
+ "line": 632,
"path": "apps/ios/Sources/Design/ChatProTab.swift",
"source": "Gateway Settings",
"surface": "apple",
@@ -17403,7 +17403,7 @@
},
{
"kind": "ui-localized-call",
- "line": 620,
+ "line": 643,
"path": "apps/ios/Sources/Design/ChatProTab.swift",
"source": "Show reasoning & tool activity",
"surface": "apple",
@@ -17411,7 +17411,7 @@
},
{
"kind": "ui-modifier",
- "line": 629,
+ "line": 652,
"path": "apps/ios/Sources/Design/ChatProTab.swift",
"source": "Chat actions",
"surface": "apple",
@@ -17419,7 +17419,7 @@
},
{
"kind": "conditional-branch",
- "line": 731,
+ "line": 754,
"path": "apps/ios/Sources/Design/ChatProTab.swift",
"source": "Connected",
"surface": "apple",
@@ -17427,7 +17427,7 @@
},
{
"kind": "conditional-branch",
- "line": 731,
+ "line": 754,
"path": "apps/ios/Sources/Design/ChatProTab.swift",
"source": "Unavailable",
"surface": "apple",
@@ -17435,7 +17435,7 @@
},
{
"kind": "ui-localized-call",
- "line": 744,
+ "line": 767,
"path": "apps/ios/Sources/Design/ChatProTab.swift",
"source": "Message %@...",
"surface": "apple",
@@ -17443,7 +17443,7 @@
},
{
"kind": "ui-localized-call",
- "line": 749,
+ "line": 772,
"path": "apps/ios/Sources/Design/ChatProTab.swift",
"source": "Message %@; sends when connected",
"surface": "apple",
@@ -17451,7 +17451,7 @@
},
{
"kind": "ui-localized-call",
- "line": 752,
+ "line": 775,
"path": "apps/ios/Sources/Design/ChatProTab.swift",
"source": "Connect to a gateway",
"surface": "apple",
@@ -17459,7 +17459,7 @@
},
{
"kind": "ui-localized-call",
- "line": 841,
+ "line": 864,
"path": "apps/ios/Sources/Design/ChatProTab.swift",
"source": "Check OpenClaw status",
"surface": "apple",
@@ -17467,7 +17467,7 @@
},
{
"kind": "ui-localized-call",
- "line": 842,
+ "line": 865,
"path": "apps/ios/Sources/Design/ChatProTab.swift",
"source": "Summarize the current OpenClaw status and tell me what needs attention.",
"surface": "apple",
@@ -17475,7 +17475,7 @@
},
{
"kind": "ui-localized-call",
- "line": 845,
+ "line": 868,
"path": "apps/ios/Sources/Design/ChatProTab.swift",
"source": "What can I control here?",
"surface": "apple",
@@ -17483,7 +17483,7 @@
},
{
"kind": "ui-localized-call",
- "line": 846,
+ "line": 869,
"path": "apps/ios/Sources/Design/ChatProTab.swift",
"source": "Show me which phone controls and device capabilities are available right now.",
"surface": "apple",
@@ -17491,7 +17491,7 @@
},
{
"kind": "ui-localized-call",
- "line": 849,
+ "line": 872,
"path": "apps/ios/Sources/Design/ChatProTab.swift",
"source": "Help me start voice chat",
"surface": "apple",
@@ -17499,7 +17499,7 @@
},
{
"kind": "ui-localized-call",
- "line": 850,
+ "line": 873,
"path": "apps/ios/Sources/Design/ChatProTab.swift",
"source": "Help me start a realtime voice session from this phone.",
"surface": "apple",
@@ -23819,7 +23819,7 @@
},
{
"kind": "ui-localized-call",
- "line": 4087,
+ "line": 4112,
"path": "apps/ios/Sources/Model/NodeAppModel.swift",
"source": "Approval needed",
"surface": "apple",
@@ -23827,7 +23827,7 @@
},
{
"kind": "ui-localized-call",
- "line": 4088,
+ "line": 4113,
"path": "apps/ios/Sources/Model/NodeAppModel.swift",
"source": "Action required",
"surface": "apple",
@@ -23835,7 +23835,7 @@
},
{
"kind": "ui-localized-call",
- "line": 4803,
+ "line": 4828,
"path": "apps/ios/Sources/Model/NodeAppModel.swift",
"source": "Connecting...",
"surface": "apple",
@@ -23843,7 +23843,7 @@
},
{
"kind": "ui-localized-call",
- "line": 4804,
+ "line": 4829,
"path": "apps/ios/Sources/Model/NodeAppModel.swift",
"source": "Reconnecting...",
"surface": "apple",
@@ -23851,7 +23851,7 @@
},
{
"kind": "conditional-branch",
- "line": 5156,
+ "line": 5181,
"path": "apps/ios/Sources/Model/NodeAppModel.swift",
"source": "Connected",
"surface": "apple",
@@ -23859,7 +23859,7 @@
},
{
"kind": "conditional-branch",
- "line": 5156,
+ "line": 5181,
"path": "apps/ios/Sources/Model/NodeAppModel.swift",
"source": "Offline",
"surface": "apple",
@@ -23867,7 +23867,7 @@
},
{
"kind": "conditional-branch",
- "line": 6326,
+ "line": 6351,
"path": "apps/ios/Sources/Model/NodeAppModel.swift",
"source": "No chat messages yet",
"surface": "apple",
@@ -23875,7 +23875,7 @@
},
{
"kind": "conditional-branch",
- "line": 6525,
+ "line": 6550,
"path": "apps/ios/Sources/Model/NodeAppModel.swift",
"source": "Connecting…",
"surface": "apple",
@@ -23883,7 +23883,7 @@
},
{
"kind": "conditional-branch",
- "line": 6525,
+ "line": 6550,
"path": "apps/ios/Sources/Model/NodeAppModel.swift",
"source": "Reconnecting…",
"surface": "apple",
@@ -23891,7 +23891,7 @@
},
{
"kind": "conditional-branch",
- "line": 8934,
+ "line": 8959,
"path": "apps/ios/Sources/Model/NodeAppModel.swift",
"source": "Approval",
"surface": "apple",
@@ -23899,7 +23899,7 @@
},
{
"kind": "conditional-branch",
- "line": 8934,
+ "line": 8959,
"path": "apps/ios/Sources/Model/NodeAppModel.swift",
"source": "This approval was already",
"surface": "apple",
@@ -23907,7 +23907,7 @@
},
{
"kind": "conditional-branch",
- "line": 8940,
+ "line": 8965,
"path": "apps/ios/Sources/Model/NodeAppModel.swift",
"source": "This approval was already set to Always Allow.",
"surface": "apple",
@@ -23915,7 +23915,7 @@
},
{
"kind": "conditional-branch",
- "line": 8941,
+ "line": 8966,
"path": "apps/ios/Sources/Model/NodeAppModel.swift",
"source": "Approval set to Always Allow.",
"surface": "apple",
@@ -23923,7 +23923,7 @@
},
{
"kind": "conditional-branch",
- "line": 10278,
+ "line": 10303,
"path": "apps/ios/Sources/Model/NodeAppModel.swift",
"source": "\\(urlText.prefix(500))…",
"surface": "apple",
@@ -25667,7 +25667,7 @@
},
{
"kind": "ui-localized-call",
- "line": 591,
+ "line": 608,
"path": "apps/ios/Sources/Voice/TalkModeManager.swift",
"source": "Gateway relay ready",
"surface": "apple",
@@ -25675,7 +25675,7 @@
},
{
"kind": "ui-localized-call",
- "line": 593,
+ "line": 610,
"path": "apps/ios/Sources/Voice/TalkModeManager.swift",
"source": "Realtime Voice, Gateway relay ready",
"surface": "apple",
@@ -25683,7 +25683,7 @@
},
{
"kind": "ui-localized-call",
- "line": 595,
+ "line": 612,
"path": "apps/ios/Sources/Voice/TalkModeManager.swift",
"source": "Listening starts from this phone",
"surface": "apple",
@@ -25691,7 +25691,7 @@
},
{
"kind": "ui-localized-call",
- "line": 835,
+ "line": 852,
"path": "apps/ios/Sources/Voice/TalkModeManager.swift",
"source": "Off",
"surface": "apple",
@@ -25699,7 +25699,7 @@
},
{
"kind": "ui-localized-call",
- "line": 838,
+ "line": 855,
"path": "apps/ios/Sources/Voice/TalkModeManager.swift",
"source": "Not active",
"surface": "apple",
@@ -25707,7 +25707,7 @@
},
{
"kind": "ui-localized-call",
- "line": 1024,
+ "line": 1041,
"path": "apps/ios/Sources/Voice/TalkModeManager.swift",
"source": "Requesting permissions…",
"surface": "apple",
@@ -25715,7 +25715,7 @@
},
{
"kind": "ui-localized-call",
- "line": 1053,
+ "line": 1070,
"path": "apps/ios/Sources/Voice/TalkModeManager.swift",
"source": "Start failed: %@",
"surface": "apple",
@@ -25723,7 +25723,7 @@
},
{
"kind": "ui-localized-call",
- "line": 1309,
+ "line": 1326,
"path": "apps/ios/Sources/Voice/TalkModeManager.swift",
"source": "Microphone permission denied",
"surface": "apple",
@@ -25731,7 +25731,7 @@
},
{
"kind": "ui-localized-call",
- "line": 1319,
+ "line": 1336,
"path": "apps/ios/Sources/Voice/TalkModeManager.swift",
"source": "Speech recognition",
"surface": "apple",
@@ -25739,7 +25739,7 @@
},
{
"kind": "ui-localized-call",
- "line": 1450,
+ "line": 1467,
"path": "apps/ios/Sources/Voice/TalkModeManager.swift",
"source": "Offline",
"surface": "apple",
@@ -25747,7 +25747,7 @@
},
{
"kind": "ui-localized-call",
- "line": 1649,
+ "line": 1666,
"path": "apps/ios/Sources/Voice/TalkModeManager.swift",
"source": "Speech error: %@",
"surface": "apple",
@@ -25755,7 +25755,7 @@
},
{
"kind": "ui-localized-call",
- "line": 1964,
+ "line": 1981,
"path": "apps/ios/Sources/Voice/TalkModeManager.swift",
"source": "Gateway not connected",
"surface": "apple",
@@ -25763,7 +25763,7 @@
},
{
"kind": "conditional-branch",
- "line": 2008,
+ "line": 2025,
"path": "apps/ios/Sources/Voice/TalkModeManager.swift",
"source": "Aborted",
"surface": "apple",
@@ -25771,7 +25771,7 @@
},
{
"kind": "conditional-branch",
- "line": 2008,
+ "line": 2025,
"path": "apps/ios/Sources/Voice/TalkModeManager.swift",
"source": "Chat error",
"surface": "apple",
@@ -25779,7 +25779,7 @@
},
{
"kind": "ui-localized-call",
- "line": 2036,
+ "line": 2053,
"path": "apps/ios/Sources/Voice/TalkModeManager.swift",
"source": "Talk failed: %@",
"surface": "apple",
@@ -25787,7 +25787,7 @@
},
{
"kind": "ui-localized-call",
- "line": 2140,
+ "line": 2157,
"path": "apps/ios/Sources/Voice/TalkModeManager.swift",
"source": "No reply",
"surface": "apple",
@@ -25795,7 +25795,7 @@
},
{
"kind": "ui-localized-call",
- "line": 2232,
+ "line": 2252,
"path": "apps/ios/Sources/Voice/TalkModeManager.swift",
"source": "Paused",
"surface": "apple",
@@ -25803,7 +25803,7 @@
},
{
"kind": "ui-localized-call",
- "line": 2644,
+ "line": 2664,
"path": "apps/ios/Sources/Voice/TalkModeManager.swift",
"source": "Generating voice…",
"surface": "apple",
@@ -25811,7 +25811,7 @@
},
{
"kind": "ui-localized-call",
- "line": 2782,
+ "line": 2802,
"path": "apps/ios/Sources/Voice/TalkModeManager.swift",
"source": "Speak failed: %@",
"surface": "apple",
@@ -25819,7 +25819,7 @@
},
{
"kind": "ui-localized-call",
- "line": 2881,
+ "line": 2901,
"path": "apps/ios/Sources/Voice/TalkModeManager.swift",
"source": "Speaking (System)…",
"surface": "apple",
@@ -25827,7 +25827,7 @@
},
{
"kind": "ui-localized-call",
- "line": 3762,
+ "line": 3782,
"path": "apps/ios/Sources/Voice/TalkModeManager.swift",
"source": "iOS System Voice",
"surface": "apple",
@@ -25835,7 +25835,7 @@
},
{
"kind": "ui-localized-call",
- "line": 3764,
+ "line": 3784,
"path": "apps/ios/Sources/Voice/TalkModeManager.swift",
"source": "Realtime Voice",
"surface": "apple",
@@ -25843,7 +25843,7 @@
},
{
"kind": "ui-localized-call",
- "line": 3768,
+ "line": 3788,
"path": "apps/ios/Sources/Voice/TalkModeManager.swift",
"source": "Gateway Default",
"surface": "apple",
@@ -25851,7 +25851,7 @@
},
{
"kind": "ui-localized-call",
- "line": 3827,
+ "line": 3847,
"path": "apps/ios/Sources/Voice/TalkModeManager.swift",
"source": "Listening (Realtime)",
"surface": "apple",
@@ -25859,7 +25859,7 @@
},
{
"kind": "ui-localized-call",
- "line": 3829,
+ "line": 3849,
"path": "apps/ios/Sources/Voice/TalkModeManager.swift",
"source": "Thinking",
"surface": "apple",
@@ -25867,7 +25867,7 @@
},
{
"kind": "ui-localized-call",
- "line": 3831,
+ "line": 3851,
"path": "apps/ios/Sources/Voice/TalkModeManager.swift",
"source": "Thinking…",
"surface": "apple",
@@ -25875,7 +25875,7 @@
},
{
"kind": "ui-localized-call",
- "line": 3833,
+ "line": 3853,
"path": "apps/ios/Sources/Voice/TalkModeManager.swift",
"source": "Asking OpenClaw",
"surface": "apple",
@@ -25883,7 +25883,7 @@
},
{
"kind": "ui-localized-call",
- "line": 3835,
+ "line": 3855,
"path": "apps/ios/Sources/Voice/TalkModeManager.swift",
"source": "Still asking OpenClaw",
"surface": "apple",
@@ -25891,7 +25891,7 @@
},
{
"kind": "ui-localized-call",
- "line": 3837,
+ "line": 3857,
"path": "apps/ios/Sources/Voice/TalkModeManager.swift",
"source": "Updating OpenClaw",
"surface": "apple",
@@ -25899,7 +25899,7 @@
},
{
"kind": "ui-localized-call",
- "line": 3839,
+ "line": 3859,
"path": "apps/ios/Sources/Voice/TalkModeManager.swift",
"source": "Speaking",
"surface": "apple",
@@ -25907,7 +25907,7 @@
},
{
"kind": "ui-localized-call",
- "line": 3841,
+ "line": 3861,
"path": "apps/ios/Sources/Voice/TalkModeManager.swift",
"source": "Speaking…",
"surface": "apple",
@@ -25915,7 +25915,7 @@
},
{
"kind": "ui-localized-call",
- "line": 3843,
+ "line": 3863,
"path": "apps/ios/Sources/Voice/TalkModeManager.swift",
"source": "Connecting",
"surface": "apple",
@@ -25923,7 +25923,7 @@
},
{
"kind": "ui-localized-call",
- "line": 3845,
+ "line": 3865,
"path": "apps/ios/Sources/Voice/TalkModeManager.swift",
"source": "Connecting realtime…",
"surface": "apple",
@@ -25931,7 +25931,7 @@
},
{
"kind": "ui-localized-call",
- "line": 3847,
+ "line": 3867,
"path": "apps/ios/Sources/Voice/TalkModeManager.swift",
"source": "Waiting for realtime…",
"surface": "apple",
@@ -25939,7 +25939,7 @@
},
{
"kind": "ui-localized-call",
- "line": 3849,
+ "line": 3869,
"path": "apps/ios/Sources/Voice/TalkModeManager.swift",
"source": "Ready",
"surface": "apple",
@@ -25947,7 +25947,7 @@
},
{
"kind": "ui-localized-call",
- "line": 3851,
+ "line": 3871,
"path": "apps/ios/Sources/Voice/TalkModeManager.swift",
"source": "Reconnecting",
"surface": "apple",
@@ -25955,7 +25955,7 @@
},
{
"kind": "ui-localized-call",
- "line": 3853,
+ "line": 3873,
"path": "apps/ios/Sources/Voice/TalkModeManager.swift",
"source": "Reconnecting…",
"surface": "apple",
@@ -25963,7 +25963,7 @@
},
{
"kind": "ui-localized-call",
- "line": 3855,
+ "line": 3875,
"path": "apps/ios/Sources/Voice/TalkModeManager.swift",
"source": "Realtime failed before connecting",
"surface": "apple",
@@ -25971,7 +25971,7 @@
},
{
"kind": "ui-localized-call",
- "line": 3857,
+ "line": 3877,
"path": "apps/ios/Sources/Voice/TalkModeManager.swift",
"source": "Realtime disconnected",
"surface": "apple",
@@ -25979,7 +25979,7 @@
},
{
"kind": "ui-localized-call",
- "line": 3859,
+ "line": 3879,
"path": "apps/ios/Sources/Voice/TalkModeManager.swift",
"source": "OpenClaw unavailable",
"surface": "apple",
@@ -25987,7 +25987,7 @@
},
{
"kind": "ui-localized-call",
- "line": 3899,
+ "line": 3919,
"path": "apps/ios/Sources/Voice/TalkModeManager.swift",
"source": "iOS Speech + TTS",
"surface": "apple",
@@ -25995,7 +25995,7 @@
},
{
"kind": "ui-localized-call",
- "line": 3901,
+ "line": 3921,
"path": "apps/ios/Sources/Voice/TalkModeManager.swift",
"source": "Listening",
"surface": "apple",
@@ -26003,7 +26003,7 @@
},
{
"kind": "ui-localized-call",
- "line": 3905,
+ "line": 3925,
"path": "apps/ios/Sources/Voice/TalkModeManager.swift",
"source": "iOS Speech fallback",
"surface": "apple",
@@ -26011,7 +26011,7 @@
},
{
"kind": "ui-localized-call",
- "line": 4166,
+ "line": 4186,
"path": "apps/ios/Sources/Voice/TalkModeManager.swift",
"source": "Gateway Relay",
"surface": "apple",
@@ -26019,7 +26019,7 @@
},
{
"kind": "ui-localized-call",
- "line": 4168,
+ "line": 4188,
"path": "apps/ios/Sources/Voice/TalkModeManager.swift",
"source": "Native WebRTC",
"surface": "apple",
@@ -26027,7 +26027,7 @@
},
{
"kind": "ui-localized-call",
- "line": 4169,
+ "line": 4189,
"path": "apps/ios/Sources/Voice/TalkModeManager.swift",
"source": "Native",
"surface": "apple",
@@ -26035,7 +26035,7 @@
},
{
"kind": "ui-localized-call",
- "line": 4230,
+ "line": 4250,
"path": "apps/ios/Sources/Voice/TalkModeManager.swift",
"source": "Gateway permission required",
"surface": "apple",
@@ -26043,7 +26043,7 @@
},
{
"kind": "ui-localized-call",
- "line": 4252,
+ "line": 4272,
"path": "apps/ios/Sources/Voice/TalkModeManager.swift",
"source": "Not loaded",
"surface": "apple",
@@ -26051,7 +26051,7 @@
},
{
"kind": "ui-localized-call",
- "line": 4270,
+ "line": 4290,
"path": "apps/ios/Sources/Voice/TalkModeManager.swift",
"source": "Approval requested",
"surface": "apple",
@@ -26059,7 +26059,7 @@
},
{
"kind": "ui-localized-call",
- "line": 4693,
+ "line": 4729,
"path": "apps/ios/Sources/Voice/TalkModeManager.swift",
"source": "Realtime unavailable",
"surface": "apple",
@@ -26067,7 +26067,7 @@
},
{
"kind": "ui-localized-call",
- "line": 4715,
+ "line": 4751,
"path": "apps/ios/Sources/Voice/TalkModeManager.swift",
"source": "Listening (PTT)",
"surface": "apple",
@@ -36905,6 +36905,78 @@
"surface": "apple",
"id": "native.apple.d4f7cdeb3737a201"
},
+ {
+ "kind": "ui-localized-call",
+ "line": 36,
+ "path": "apps/shared/OpenClawKit/Sources/OpenClawChatUI/ChatCameraFlipButton.swift",
+ "source": "Switch to back camera",
+ "surface": "apple",
+ "id": "native.apple.fc5931c1f0a6bbec"
+ },
+ {
+ "kind": "ui-localized-call",
+ "line": 38,
+ "path": "apps/shared/OpenClawKit/Sources/OpenClawChatUI/ChatCameraFlipButton.swift",
+ "source": "Switch to front camera",
+ "surface": "apple",
+ "id": "native.apple.cce3b539e31701c0"
+ },
+ {
+ "kind": "ui-localized-call",
+ "line": 40,
+ "path": "apps/shared/OpenClawKit/Sources/OpenClawChatUI/ChatCameraFlipButton.swift",
+ "source": "Flip camera",
+ "surface": "apple",
+ "id": "native.apple.f397daffdfd02ee0"
+ },
+ {
+ "kind": "conditional-branch",
+ "line": 73,
+ "path": "apps/shared/OpenClawKit/Sources/OpenClawChatUI/ChatCameraFlipButton.swift",
+ "source": "Stop",
+ "surface": "apple",
+ "id": "native.apple.11f8de87ca3fcb11"
+ },
+ {
+ "kind": "conditional-branch",
+ "line": 73,
+ "path": "apps/shared/OpenClawKit/Sources/OpenClawChatUI/ChatCameraFlipButton.swift",
+ "source": "Talk",
+ "surface": "apple",
+ "id": "native.apple.7c92bec1c8a83e43"
+ },
+ {
+ "kind": "conditional-branch",
+ "line": 118,
+ "path": "apps/shared/OpenClawKit/Sources/OpenClawChatUI/ChatCameraFlipButton.swift",
+ "source": "Start realtime chat",
+ "surface": "apple",
+ "id": "native.apple.dae61543f9b416ca"
+ },
+ {
+ "kind": "conditional-branch",
+ "line": 118,
+ "path": "apps/shared/OpenClawKit/Sources/OpenClawChatUI/ChatCameraFlipButton.swift",
+ "source": "Stop realtime chat",
+ "surface": "apple",
+ "id": "native.apple.d376b015a90792a9"
+ },
+ {
+ "kind": "conditional-branch",
+ "line": 203,
+ "path": "apps/shared/OpenClawKit/Sources/OpenClawChatUI/ChatCameraFlipButton.swift",
+ "source": "Connecting...",
+ "surface": "apple",
+ "id": "native.apple.ac48dbe25ac4d40d"
+ },
+ {
+ "kind": "conditional-branch",
+ "line": 203,
+ "path": "apps/shared/OpenClawKit/Sources/OpenClawChatUI/ChatCameraFlipButton.swift",
+ "source": "Gateway connected",
+ "surface": "apple",
+ "id": "native.apple.ccce98756eb1dacd"
+ },
{
"kind": "ui-localized-call",
"line": 415,
@@ -37059,31 +37131,7 @@
},
{
"kind": "conditional-branch",
- "line": 813,
- "path": "apps/shared/OpenClawKit/Sources/OpenClawChatUI/ChatComposer.swift",
- "source": "Talk",
- "surface": "apple",
- "id": "native.apple.ee2c0d22f5861159"
- },
- {
- "kind": "conditional-branch",
- "line": 884,
- "path": "apps/shared/OpenClawKit/Sources/OpenClawChatUI/ChatComposer.swift",
- "source": "Start realtime chat",
- "surface": "apple",
- "id": "native.apple.5d5041aefe6dfddd"
- },
- {
- "kind": "conditional-branch",
- "line": 884,
- "path": "apps/shared/OpenClawKit/Sources/OpenClawChatUI/ChatComposer.swift",
- "source": "Stop realtime chat",
- "surface": "apple",
- "id": "native.apple.21a7d3a3386a2218"
- },
- {
- "kind": "conditional-branch",
- "line": 918,
+ "line": 821,
"path": "apps/shared/OpenClawKit/Sources/OpenClawChatUI/ChatComposer.swift",
"source": "Start",
"surface": "apple",
@@ -37091,7 +37139,7 @@
},
{
"kind": "conditional-branch",
- "line": 918,
+ "line": 821,
"path": "apps/shared/OpenClawKit/Sources/OpenClawChatUI/ChatComposer.swift",
"source": "Stop",
"surface": "apple",
@@ -37099,7 +37147,7 @@
},
{
"kind": "ui-call",
- "line": 1035,
+ "line": 919,
"path": "apps/shared/OpenClawKit/Sources/OpenClawChatUI/ChatComposer.swift",
"source": "Loading commands",
"surface": "apple",
@@ -37107,7 +37155,7 @@
},
{
"kind": "ui-call",
- "line": 1044,
+ "line": 928,
"path": "apps/shared/OpenClawKit/Sources/OpenClawChatUI/ChatComposer.swift",
"source": "Commands unavailable",
"surface": "apple",
@@ -37115,7 +37163,7 @@
},
{
"kind": "ui-call",
- "line": 1053,
+ "line": 937,
"path": "apps/shared/OpenClawKit/Sources/OpenClawChatUI/ChatComposer.swift",
"source": "Retry",
"surface": "apple",
@@ -37123,7 +37171,7 @@
},
{
"kind": "ui-call",
- "line": 1062,
+ "line": 946,
"path": "apps/shared/OpenClawKit/Sources/OpenClawChatUI/ChatComposer.swift",
"source": "No matching commands",
"surface": "apple",
@@ -37131,7 +37179,7 @@
},
{
"kind": "ui-modifier",
- "line": 1294,
+ "line": 1178,
"path": "apps/shared/OpenClawKit/Sources/OpenClawChatUI/ChatComposer.swift",
"source": "Stop response",
"surface": "apple",
@@ -37139,7 +37187,7 @@
},
{
"kind": "ui-modifier",
- "line": 1319,
+ "line": 1203,
"path": "apps/shared/OpenClawKit/Sources/OpenClawChatUI/ChatComposer.swift",
"source": "Send message",
"surface": "apple",
@@ -37147,7 +37195,7 @@
},
{
"kind": "ui-modifier",
- "line": 1333,
+ "line": 1217,
"path": "apps/shared/OpenClawKit/Sources/OpenClawChatUI/ChatComposer.swift",
"source": "Refresh",
"surface": "apple",
@@ -37155,23 +37203,7 @@
},
{
"kind": "conditional-branch",
- "line": 1458,
- "path": "apps/shared/OpenClawKit/Sources/OpenClawChatUI/ChatComposer.swift",
- "source": "Connecting...",
- "surface": "apple",
- "id": "native.apple.6c984c0e3ed3a69e"
- },
- {
- "kind": "conditional-branch",
- "line": 1458,
- "path": "apps/shared/OpenClawKit/Sources/OpenClawChatUI/ChatComposer.swift",
- "source": "Gateway connected",
- "surface": "apple",
- "id": "native.apple.898849eb2bcb0b53"
- },
- {
- "kind": "conditional-branch",
- "line": 1467,
+ "line": 1343,
"path": "apps/shared/OpenClawKit/Sources/OpenClawChatUI/ChatComposer.swift",
"source": "Message…",
"surface": "apple",
diff --git a/apps/.i18n/native/ar.json b/apps/.i18n/native/ar.json
index 6a47c54f165..e3f9aba6574 100644
--- a/apps/.i18n/native/ar.json
+++ b/apps/.i18n/native/ar.json
@@ -23068,6 +23068,51 @@
"source": "<\\(tag)",
"translated": "<\\(tag)"
},
+ {
+ "id": "native.apple.fc5931c1f0a6bbec",
+ "source": "Switch to back camera",
+ "translated": "التبديل إلى الكاميرا الخلفية"
+ },
+ {
+ "id": "native.apple.cce3b539e31701c0",
+ "source": "Switch to front camera",
+ "translated": "التبديل إلى الكاميرا الأمامية"
+ },
+ {
+ "id": "native.apple.f397daffdfd02ee0",
+ "source": "Flip camera",
+ "translated": "عكس الكاميرا"
+ },
+ {
+ "id": "native.apple.11f8de87ca3fcb11",
+ "source": "Stop",
+ "translated": "إيقاف"
+ },
+ {
+ "id": "native.apple.7c92bec1c8a83e43",
+ "source": "Talk",
+ "translated": "تحدّث"
+ },
+ {
+ "id": "native.apple.dae61543f9b416ca",
+ "source": "Start realtime chat",
+ "translated": "بدء الدردشة الفورية"
+ },
+ {
+ "id": "native.apple.d376b015a90792a9",
+ "source": "Stop realtime chat",
+ "translated": "إيقاف الدردشة الفورية"
+ },
+ {
+ "id": "native.apple.ac48dbe25ac4d40d",
+ "source": "Connecting...",
+ "translated": "جارٍ الاتصال..."
+ },
+ {
+ "id": "native.apple.ccce98756eb1dacd",
+ "source": "Gateway connected",
+ "translated": "تم الاتصال بـ Gateway"
+ },
{
"id": "native.apple.03aca5cfee32f12d",
"source": "Context %@%% used",
@@ -23163,21 +23208,6 @@
"source": "Attachments",
"translated": "المرفقات"
},
- {
- "id": "native.apple.ee2c0d22f5861159",
- "source": "Talk",
- "translated": "تحدث"
- },
- {
- "id": "native.apple.5d5041aefe6dfddd",
- "source": "Start realtime chat",
- "translated": "بدء دردشة فورية"
- },
- {
- "id": "native.apple.21a7d3a3386a2218",
- "source": "Stop realtime chat",
- "translated": "إيقاف الدردشة الفورية"
- },
{
"id": "native.apple.88c2de261ddae511",
"source": "Start",
@@ -23223,16 +23253,6 @@
"source": "Refresh",
"translated": "تحديث"
},
- {
- "id": "native.apple.6c984c0e3ed3a69e",
- "source": "Connecting...",
- "translated": "جارٍ الاتصال..."
- },
- {
- "id": "native.apple.898849eb2bcb0b53",
- "source": "Gateway connected",
- "translated": "تم اتصال Gateway"
- },
{
"id": "native.apple.b6adfcd17a6e73d7",
"source": "Message…",
diff --git a/apps/.i18n/native/de.json b/apps/.i18n/native/de.json
index 27a2608ac98..1e3d711332a 100644
--- a/apps/.i18n/native/de.json
+++ b/apps/.i18n/native/de.json
@@ -23068,6 +23068,51 @@
"source": "<\\(tag)",
"translated": "<\\(tag)"
},
+ {
+ "id": "native.apple.fc5931c1f0a6bbec",
+ "source": "Switch to back camera",
+ "translated": "Zur Rückkamera wechseln"
+ },
+ {
+ "id": "native.apple.cce3b539e31701c0",
+ "source": "Switch to front camera",
+ "translated": "Zur Frontkamera wechseln"
+ },
+ {
+ "id": "native.apple.f397daffdfd02ee0",
+ "source": "Flip camera",
+ "translated": "Kamera wechseln"
+ },
+ {
+ "id": "native.apple.11f8de87ca3fcb11",
+ "source": "Stop",
+ "translated": "Stopp"
+ },
+ {
+ "id": "native.apple.7c92bec1c8a83e43",
+ "source": "Talk",
+ "translated": "Sprechen"
+ },
+ {
+ "id": "native.apple.dae61543f9b416ca",
+ "source": "Start realtime chat",
+ "translated": "Echtzeit-Chat starten"
+ },
+ {
+ "id": "native.apple.d376b015a90792a9",
+ "source": "Stop realtime chat",
+ "translated": "Echtzeit-Chat beenden"
+ },
+ {
+ "id": "native.apple.ac48dbe25ac4d40d",
+ "source": "Connecting...",
+ "translated": "Verbindung wird hergestellt..."
+ },
+ {
+ "id": "native.apple.ccce98756eb1dacd",
+ "source": "Gateway connected",
+ "translated": "Gateway verbunden"
+ },
{
"id": "native.apple.03aca5cfee32f12d",
"source": "Context %@%% used",
@@ -23163,21 +23208,6 @@
"source": "Attachments",
"translated": "Anhänge"
},
- {
- "id": "native.apple.ee2c0d22f5861159",
- "source": "Talk",
- "translated": "Sprechen"
- },
- {
- "id": "native.apple.5d5041aefe6dfddd",
- "source": "Start realtime chat",
- "translated": "Echtzeit-Chat starten"
- },
- {
- "id": "native.apple.21a7d3a3386a2218",
- "source": "Stop realtime chat",
- "translated": "Echtzeit-Chat beenden"
- },
{
"id": "native.apple.88c2de261ddae511",
"source": "Start",
@@ -23223,16 +23253,6 @@
"source": "Refresh",
"translated": "Aktualisieren"
},
- {
- "id": "native.apple.6c984c0e3ed3a69e",
- "source": "Connecting...",
- "translated": "Verbindung wird hergestellt..."
- },
- {
- "id": "native.apple.898849eb2bcb0b53",
- "source": "Gateway connected",
- "translated": "Gateway verbunden"
- },
{
"id": "native.apple.b6adfcd17a6e73d7",
"source": "Message…",
diff --git a/apps/.i18n/native/es.json b/apps/.i18n/native/es.json
index 7a2d3ac96d7..a77740417e3 100644
--- a/apps/.i18n/native/es.json
+++ b/apps/.i18n/native/es.json
@@ -23068,6 +23068,51 @@
"source": "<\\(tag)",
"translated": "<\\(tag)"
},
+ {
+ "id": "native.apple.fc5931c1f0a6bbec",
+ "source": "Switch to back camera",
+ "translated": "Cambiar a la cámara trasera"
+ },
+ {
+ "id": "native.apple.cce3b539e31701c0",
+ "source": "Switch to front camera",
+ "translated": "Cambiar a la cámara frontal"
+ },
+ {
+ "id": "native.apple.f397daffdfd02ee0",
+ "source": "Flip camera",
+ "translated": "Voltear la cámara"
+ },
+ {
+ "id": "native.apple.11f8de87ca3fcb11",
+ "source": "Stop",
+ "translated": "Detener"
+ },
+ {
+ "id": "native.apple.7c92bec1c8a83e43",
+ "source": "Talk",
+ "translated": "Hablar"
+ },
+ {
+ "id": "native.apple.dae61543f9b416ca",
+ "source": "Start realtime chat",
+ "translated": "Iniciar chat en tiempo real"
+ },
+ {
+ "id": "native.apple.d376b015a90792a9",
+ "source": "Stop realtime chat",
+ "translated": "Detener chat en tiempo real"
+ },
+ {
+ "id": "native.apple.ac48dbe25ac4d40d",
+ "source": "Connecting...",
+ "translated": "Conectando..."
+ },
+ {
+ "id": "native.apple.ccce98756eb1dacd",
+ "source": "Gateway connected",
+ "translated": "Gateway conectado"
+ },
{
"id": "native.apple.03aca5cfee32f12d",
"source": "Context %@%% used",
@@ -23163,21 +23208,6 @@
"source": "Attachments",
"translated": "Archivos adjuntos"
},
- {
- "id": "native.apple.ee2c0d22f5861159",
- "source": "Talk",
- "translated": "Hablar"
- },
- {
- "id": "native.apple.5d5041aefe6dfddd",
- "source": "Start realtime chat",
- "translated": "Iniciar chat en tiempo real"
- },
- {
- "id": "native.apple.21a7d3a3386a2218",
- "source": "Stop realtime chat",
- "translated": "Detener chat en tiempo real"
- },
{
"id": "native.apple.88c2de261ddae511",
"source": "Start",
@@ -23223,16 +23253,6 @@
"source": "Refresh",
"translated": "Actualizar"
},
- {
- "id": "native.apple.6c984c0e3ed3a69e",
- "source": "Connecting...",
- "translated": "Conectando..."
- },
- {
- "id": "native.apple.898849eb2bcb0b53",
- "source": "Gateway connected",
- "translated": "Gateway conectado"
- },
{
"id": "native.apple.b6adfcd17a6e73d7",
"source": "Message…",
diff --git a/apps/.i18n/native/fa.json b/apps/.i18n/native/fa.json
index 28f180f790f..a47ab3f48a9 100644
--- a/apps/.i18n/native/fa.json
+++ b/apps/.i18n/native/fa.json
@@ -23068,6 +23068,51 @@
"source": "<\\(tag)",
"translated": "<\\(tag)"
},
+ {
+ "id": "native.apple.fc5931c1f0a6bbec",
+ "source": "Switch to back camera",
+ "translated": "تغییر به دوربین پشت"
+ },
+ {
+ "id": "native.apple.cce3b539e31701c0",
+ "source": "Switch to front camera",
+ "translated": "تغییر به دوربین جلو"
+ },
+ {
+ "id": "native.apple.f397daffdfd02ee0",
+ "source": "Flip camera",
+ "translated": "برگرداندن دوربین"
+ },
+ {
+ "id": "native.apple.11f8de87ca3fcb11",
+ "source": "Stop",
+ "translated": "توقف"
+ },
+ {
+ "id": "native.apple.7c92bec1c8a83e43",
+ "source": "Talk",
+ "translated": "صحبت"
+ },
+ {
+ "id": "native.apple.dae61543f9b416ca",
+ "source": "Start realtime chat",
+ "translated": "شروع گفتوگوی همزمان"
+ },
+ {
+ "id": "native.apple.d376b015a90792a9",
+ "source": "Stop realtime chat",
+ "translated": "توقف گفتوگوی همزمان"
+ },
+ {
+ "id": "native.apple.ac48dbe25ac4d40d",
+ "source": "Connecting...",
+ "translated": "در حال اتصال..."
+ },
+ {
+ "id": "native.apple.ccce98756eb1dacd",
+ "source": "Gateway connected",
+ "translated": "Gateway متصل است"
+ },
{
"id": "native.apple.03aca5cfee32f12d",
"source": "Context %@%% used",
@@ -23163,21 +23208,6 @@
"source": "Attachments",
"translated": "پیوستها"
},
- {
- "id": "native.apple.ee2c0d22f5861159",
- "source": "Talk",
- "translated": "گفتگو"
- },
- {
- "id": "native.apple.5d5041aefe6dfddd",
- "source": "Start realtime chat",
- "translated": "شروع گفتگوی بلادرنگ"
- },
- {
- "id": "native.apple.21a7d3a3386a2218",
- "source": "Stop realtime chat",
- "translated": "توقف گفتگوی بلادرنگ"
- },
{
"id": "native.apple.88c2de261ddae511",
"source": "Start",
@@ -23223,16 +23253,6 @@
"source": "Refresh",
"translated": "تازهسازی"
},
- {
- "id": "native.apple.6c984c0e3ed3a69e",
- "source": "Connecting...",
- "translated": "در حال اتصال..."
- },
- {
- "id": "native.apple.898849eb2bcb0b53",
- "source": "Gateway connected",
- "translated": "Gateway متصل شد"
- },
{
"id": "native.apple.b6adfcd17a6e73d7",
"source": "Message…",
diff --git a/apps/.i18n/native/fr.json b/apps/.i18n/native/fr.json
index 5266f0915ae..ab9f02f68ac 100644
--- a/apps/.i18n/native/fr.json
+++ b/apps/.i18n/native/fr.json
@@ -23068,6 +23068,51 @@
"source": "<\\(tag)",
"translated": "<\\(tag)"
},
+ {
+ "id": "native.apple.fc5931c1f0a6bbec",
+ "source": "Switch to back camera",
+ "translated": "Passer à la caméra arrière"
+ },
+ {
+ "id": "native.apple.cce3b539e31701c0",
+ "source": "Switch to front camera",
+ "translated": "Passer à la caméra avant"
+ },
+ {
+ "id": "native.apple.f397daffdfd02ee0",
+ "source": "Flip camera",
+ "translated": "Retourner la caméra"
+ },
+ {
+ "id": "native.apple.11f8de87ca3fcb11",
+ "source": "Stop",
+ "translated": "Arrêter"
+ },
+ {
+ "id": "native.apple.7c92bec1c8a83e43",
+ "source": "Talk",
+ "translated": "Parler"
+ },
+ {
+ "id": "native.apple.dae61543f9b416ca",
+ "source": "Start realtime chat",
+ "translated": "Démarrer le chat en temps réel"
+ },
+ {
+ "id": "native.apple.d376b015a90792a9",
+ "source": "Stop realtime chat",
+ "translated": "Arrêter le chat en temps réel"
+ },
+ {
+ "id": "native.apple.ac48dbe25ac4d40d",
+ "source": "Connecting...",
+ "translated": "Connexion..."
+ },
+ {
+ "id": "native.apple.ccce98756eb1dacd",
+ "source": "Gateway connected",
+ "translated": "Gateway connecté"
+ },
{
"id": "native.apple.03aca5cfee32f12d",
"source": "Context %@%% used",
@@ -23163,21 +23208,6 @@
"source": "Attachments",
"translated": "Pièces jointes"
},
- {
- "id": "native.apple.ee2c0d22f5861159",
- "source": "Talk",
- "translated": "Parler"
- },
- {
- "id": "native.apple.5d5041aefe6dfddd",
- "source": "Start realtime chat",
- "translated": "Démarrer la discussion en temps réel"
- },
- {
- "id": "native.apple.21a7d3a3386a2218",
- "source": "Stop realtime chat",
- "translated": "Arrêter la discussion en temps réel"
- },
{
"id": "native.apple.88c2de261ddae511",
"source": "Start",
@@ -23223,16 +23253,6 @@
"source": "Refresh",
"translated": "Actualiser"
},
- {
- "id": "native.apple.6c984c0e3ed3a69e",
- "source": "Connecting...",
- "translated": "Connexion..."
- },
- {
- "id": "native.apple.898849eb2bcb0b53",
- "source": "Gateway connected",
- "translated": "Gateway connecté"
- },
{
"id": "native.apple.b6adfcd17a6e73d7",
"source": "Message…",
diff --git a/apps/.i18n/native/hi.json b/apps/.i18n/native/hi.json
index e4d9bef9b45..03bb6a5ac47 100644
--- a/apps/.i18n/native/hi.json
+++ b/apps/.i18n/native/hi.json
@@ -23068,6 +23068,51 @@
"source": "<\\(tag)",
"translated": "<\\(tag)"
},
+ {
+ "id": "native.apple.fc5931c1f0a6bbec",
+ "source": "Switch to back camera",
+ "translated": "पीछे वाले कैमरे पर स्विच करें"
+ },
+ {
+ "id": "native.apple.cce3b539e31701c0",
+ "source": "Switch to front camera",
+ "translated": "सामने वाले कैमरे पर स्विच करें"
+ },
+ {
+ "id": "native.apple.f397daffdfd02ee0",
+ "source": "Flip camera",
+ "translated": "कैमरा पलटें"
+ },
+ {
+ "id": "native.apple.11f8de87ca3fcb11",
+ "source": "Stop",
+ "translated": "रोकें"
+ },
+ {
+ "id": "native.apple.7c92bec1c8a83e43",
+ "source": "Talk",
+ "translated": "बात करें"
+ },
+ {
+ "id": "native.apple.dae61543f9b416ca",
+ "source": "Start realtime chat",
+ "translated": "रीयल-टाइम चैट शुरू करें"
+ },
+ {
+ "id": "native.apple.d376b015a90792a9",
+ "source": "Stop realtime chat",
+ "translated": "रीयल-टाइम चैट रोकें"
+ },
+ {
+ "id": "native.apple.ac48dbe25ac4d40d",
+ "source": "Connecting...",
+ "translated": "कनेक्ट हो रहा है..."
+ },
+ {
+ "id": "native.apple.ccce98756eb1dacd",
+ "source": "Gateway connected",
+ "translated": "Gateway कनेक्ट हो गया"
+ },
{
"id": "native.apple.03aca5cfee32f12d",
"source": "Context %@%% used",
@@ -23163,21 +23208,6 @@
"source": "Attachments",
"translated": "अटैचमेंट"
},
- {
- "id": "native.apple.ee2c0d22f5861159",
- "source": "Talk",
- "translated": "बात करें"
- },
- {
- "id": "native.apple.5d5041aefe6dfddd",
- "source": "Start realtime chat",
- "translated": "रीयल-टाइम चैट शुरू करें"
- },
- {
- "id": "native.apple.21a7d3a3386a2218",
- "source": "Stop realtime chat",
- "translated": "रीयल-टाइम चैट बंद करें"
- },
{
"id": "native.apple.88c2de261ddae511",
"source": "Start",
@@ -23223,16 +23253,6 @@
"source": "Refresh",
"translated": "रीफ़्रेश करें"
},
- {
- "id": "native.apple.6c984c0e3ed3a69e",
- "source": "Connecting...",
- "translated": "कनेक्ट हो रहा है..."
- },
- {
- "id": "native.apple.898849eb2bcb0b53",
- "source": "Gateway connected",
- "translated": "Gateway कनेक्ट हो गया"
- },
{
"id": "native.apple.b6adfcd17a6e73d7",
"source": "Message…",
diff --git a/apps/.i18n/native/id.json b/apps/.i18n/native/id.json
index 2643850e182..e864ed0c074 100644
--- a/apps/.i18n/native/id.json
+++ b/apps/.i18n/native/id.json
@@ -23068,6 +23068,51 @@
"source": "<\\(tag)",
"translated": "<\\(tag)"
},
+ {
+ "id": "native.apple.fc5931c1f0a6bbec",
+ "source": "Switch to back camera",
+ "translated": "Beralih ke kamera belakang"
+ },
+ {
+ "id": "native.apple.cce3b539e31701c0",
+ "source": "Switch to front camera",
+ "translated": "Beralih ke kamera depan"
+ },
+ {
+ "id": "native.apple.f397daffdfd02ee0",
+ "source": "Flip camera",
+ "translated": "Balik kamera"
+ },
+ {
+ "id": "native.apple.11f8de87ca3fcb11",
+ "source": "Stop",
+ "translated": "Berhenti"
+ },
+ {
+ "id": "native.apple.7c92bec1c8a83e43",
+ "source": "Talk",
+ "translated": "Bicara"
+ },
+ {
+ "id": "native.apple.dae61543f9b416ca",
+ "source": "Start realtime chat",
+ "translated": "Mulai obrolan waktu nyata"
+ },
+ {
+ "id": "native.apple.d376b015a90792a9",
+ "source": "Stop realtime chat",
+ "translated": "Hentikan obrolan waktu nyata"
+ },
+ {
+ "id": "native.apple.ac48dbe25ac4d40d",
+ "source": "Connecting...",
+ "translated": "Menghubungkan..."
+ },
+ {
+ "id": "native.apple.ccce98756eb1dacd",
+ "source": "Gateway connected",
+ "translated": "Gateway terhubung"
+ },
{
"id": "native.apple.03aca5cfee32f12d",
"source": "Context %@%% used",
@@ -23163,21 +23208,6 @@
"source": "Attachments",
"translated": "Lampiran"
},
- {
- "id": "native.apple.ee2c0d22f5861159",
- "source": "Talk",
- "translated": "Bicara"
- },
- {
- "id": "native.apple.5d5041aefe6dfddd",
- "source": "Start realtime chat",
- "translated": "Mulai chat realtime"
- },
- {
- "id": "native.apple.21a7d3a3386a2218",
- "source": "Stop realtime chat",
- "translated": "Hentikan chat realtime"
- },
{
"id": "native.apple.88c2de261ddae511",
"source": "Start",
@@ -23223,16 +23253,6 @@
"source": "Refresh",
"translated": "Segarkan"
},
- {
- "id": "native.apple.6c984c0e3ed3a69e",
- "source": "Connecting...",
- "translated": "Menghubungkan..."
- },
- {
- "id": "native.apple.898849eb2bcb0b53",
- "source": "Gateway connected",
- "translated": "Gateway terhubung"
- },
{
"id": "native.apple.b6adfcd17a6e73d7",
"source": "Message…",
diff --git a/apps/.i18n/native/it.json b/apps/.i18n/native/it.json
index a75379038da..722a021e93f 100644
--- a/apps/.i18n/native/it.json
+++ b/apps/.i18n/native/it.json
@@ -23068,6 +23068,51 @@
"source": "<\\(tag)",
"translated": "<\\(tag)"
},
+ {
+ "id": "native.apple.fc5931c1f0a6bbec",
+ "source": "Switch to back camera",
+ "translated": "Passa alla fotocamera posteriore"
+ },
+ {
+ "id": "native.apple.cce3b539e31701c0",
+ "source": "Switch to front camera",
+ "translated": "Passa alla fotocamera anteriore"
+ },
+ {
+ "id": "native.apple.f397daffdfd02ee0",
+ "source": "Flip camera",
+ "translated": "Capovolgi fotocamera"
+ },
+ {
+ "id": "native.apple.11f8de87ca3fcb11",
+ "source": "Stop",
+ "translated": "Interrompi"
+ },
+ {
+ "id": "native.apple.7c92bec1c8a83e43",
+ "source": "Talk",
+ "translated": "Parla"
+ },
+ {
+ "id": "native.apple.dae61543f9b416ca",
+ "source": "Start realtime chat",
+ "translated": "Avvia chat in tempo reale"
+ },
+ {
+ "id": "native.apple.d376b015a90792a9",
+ "source": "Stop realtime chat",
+ "translated": "Interrompi chat in tempo reale"
+ },
+ {
+ "id": "native.apple.ac48dbe25ac4d40d",
+ "source": "Connecting...",
+ "translated": "Connessione..."
+ },
+ {
+ "id": "native.apple.ccce98756eb1dacd",
+ "source": "Gateway connected",
+ "translated": "Gateway connesso"
+ },
{
"id": "native.apple.03aca5cfee32f12d",
"source": "Context %@%% used",
@@ -23163,21 +23208,6 @@
"source": "Attachments",
"translated": "Allegati"
},
- {
- "id": "native.apple.ee2c0d22f5861159",
- "source": "Talk",
- "translated": "Parla"
- },
- {
- "id": "native.apple.5d5041aefe6dfddd",
- "source": "Start realtime chat",
- "translated": "Avvia chat in tempo reale"
- },
- {
- "id": "native.apple.21a7d3a3386a2218",
- "source": "Stop realtime chat",
- "translated": "Interrompi chat in tempo reale"
- },
{
"id": "native.apple.88c2de261ddae511",
"source": "Start",
@@ -23223,16 +23253,6 @@
"source": "Refresh",
"translated": "Aggiorna"
},
- {
- "id": "native.apple.6c984c0e3ed3a69e",
- "source": "Connecting...",
- "translated": "Connessione in corso..."
- },
- {
- "id": "native.apple.898849eb2bcb0b53",
- "source": "Gateway connected",
- "translated": "Gateway connesso"
- },
{
"id": "native.apple.b6adfcd17a6e73d7",
"source": "Message…",
diff --git a/apps/.i18n/native/ja-JP.json b/apps/.i18n/native/ja-JP.json
index 6ac03ccb917..1c77e422f79 100644
--- a/apps/.i18n/native/ja-JP.json
+++ b/apps/.i18n/native/ja-JP.json
@@ -23068,6 +23068,51 @@
"source": "<\\(tag)",
"translated": "<\\(tag)"
},
+ {
+ "id": "native.apple.fc5931c1f0a6bbec",
+ "source": "Switch to back camera",
+ "translated": "背面カメラに切り替え"
+ },
+ {
+ "id": "native.apple.cce3b539e31701c0",
+ "source": "Switch to front camera",
+ "translated": "前面カメラに切り替え"
+ },
+ {
+ "id": "native.apple.f397daffdfd02ee0",
+ "source": "Flip camera",
+ "translated": "カメラを反転"
+ },
+ {
+ "id": "native.apple.11f8de87ca3fcb11",
+ "source": "Stop",
+ "translated": "停止"
+ },
+ {
+ "id": "native.apple.7c92bec1c8a83e43",
+ "source": "Talk",
+ "translated": "話す"
+ },
+ {
+ "id": "native.apple.dae61543f9b416ca",
+ "source": "Start realtime chat",
+ "translated": "リアルタイムチャットを開始"
+ },
+ {
+ "id": "native.apple.d376b015a90792a9",
+ "source": "Stop realtime chat",
+ "translated": "リアルタイムチャットを停止"
+ },
+ {
+ "id": "native.apple.ac48dbe25ac4d40d",
+ "source": "Connecting...",
+ "translated": "接続中..."
+ },
+ {
+ "id": "native.apple.ccce98756eb1dacd",
+ "source": "Gateway connected",
+ "translated": "Gatewayに接続済み"
+ },
{
"id": "native.apple.03aca5cfee32f12d",
"source": "Context %@%% used",
@@ -23163,21 +23208,6 @@
"source": "Attachments",
"translated": "添付ファイル"
},
- {
- "id": "native.apple.ee2c0d22f5861159",
- "source": "Talk",
- "translated": "トーク"
- },
- {
- "id": "native.apple.5d5041aefe6dfddd",
- "source": "Start realtime chat",
- "translated": "リアルタイムチャットを開始"
- },
- {
- "id": "native.apple.21a7d3a3386a2218",
- "source": "Stop realtime chat",
- "translated": "リアルタイムチャットを停止"
- },
{
"id": "native.apple.88c2de261ddae511",
"source": "Start",
@@ -23223,16 +23253,6 @@
"source": "Refresh",
"translated": "更新"
},
- {
- "id": "native.apple.6c984c0e3ed3a69e",
- "source": "Connecting...",
- "translated": "接続中..."
- },
- {
- "id": "native.apple.898849eb2bcb0b53",
- "source": "Gateway connected",
- "translated": "Gateway に接続しました"
- },
{
"id": "native.apple.b6adfcd17a6e73d7",
"source": "Message…",
diff --git a/apps/.i18n/native/ko.json b/apps/.i18n/native/ko.json
index a7fc5b89287..ba0886775a4 100644
--- a/apps/.i18n/native/ko.json
+++ b/apps/.i18n/native/ko.json
@@ -23068,6 +23068,51 @@
"source": "<\\(tag)",
"translated": "<\\(tag)"
},
+ {
+ "id": "native.apple.fc5931c1f0a6bbec",
+ "source": "Switch to back camera",
+ "translated": "후면 카메라로 전환"
+ },
+ {
+ "id": "native.apple.cce3b539e31701c0",
+ "source": "Switch to front camera",
+ "translated": "전면 카메라로 전환"
+ },
+ {
+ "id": "native.apple.f397daffdfd02ee0",
+ "source": "Flip camera",
+ "translated": "카메라 전환"
+ },
+ {
+ "id": "native.apple.11f8de87ca3fcb11",
+ "source": "Stop",
+ "translated": "중지"
+ },
+ {
+ "id": "native.apple.7c92bec1c8a83e43",
+ "source": "Talk",
+ "translated": "말하기"
+ },
+ {
+ "id": "native.apple.dae61543f9b416ca",
+ "source": "Start realtime chat",
+ "translated": "실시간 채팅 시작"
+ },
+ {
+ "id": "native.apple.d376b015a90792a9",
+ "source": "Stop realtime chat",
+ "translated": "실시간 채팅 중지"
+ },
+ {
+ "id": "native.apple.ac48dbe25ac4d40d",
+ "source": "Connecting...",
+ "translated": "연결 중..."
+ },
+ {
+ "id": "native.apple.ccce98756eb1dacd",
+ "source": "Gateway connected",
+ "translated": "Gateway 연결됨"
+ },
{
"id": "native.apple.03aca5cfee32f12d",
"source": "Context %@%% used",
@@ -23163,21 +23208,6 @@
"source": "Attachments",
"translated": "첨부 파일"
},
- {
- "id": "native.apple.ee2c0d22f5861159",
- "source": "Talk",
- "translated": "대화"
- },
- {
- "id": "native.apple.5d5041aefe6dfddd",
- "source": "Start realtime chat",
- "translated": "실시간 채팅 시작"
- },
- {
- "id": "native.apple.21a7d3a3386a2218",
- "source": "Stop realtime chat",
- "translated": "실시간 채팅 중지"
- },
{
"id": "native.apple.88c2de261ddae511",
"source": "Start",
@@ -23223,16 +23253,6 @@
"source": "Refresh",
"translated": "새로 고침"
},
- {
- "id": "native.apple.6c984c0e3ed3a69e",
- "source": "Connecting...",
- "translated": "연결 중..."
- },
- {
- "id": "native.apple.898849eb2bcb0b53",
- "source": "Gateway connected",
- "translated": "Gateway 연결됨"
- },
{
"id": "native.apple.b6adfcd17a6e73d7",
"source": "Message…",
diff --git a/apps/.i18n/native/nl.json b/apps/.i18n/native/nl.json
index 3691d7acc8e..318f928a4a3 100644
--- a/apps/.i18n/native/nl.json
+++ b/apps/.i18n/native/nl.json
@@ -23068,6 +23068,51 @@
"source": "<\\(tag)",
"translated": "<\\(tag)"
},
+ {
+ "id": "native.apple.fc5931c1f0a6bbec",
+ "source": "Switch to back camera",
+ "translated": "Schakel over naar de camera aan de achterkant"
+ },
+ {
+ "id": "native.apple.cce3b539e31701c0",
+ "source": "Switch to front camera",
+ "translated": "Schakel over naar de camera aan de voorkant"
+ },
+ {
+ "id": "native.apple.f397daffdfd02ee0",
+ "source": "Flip camera",
+ "translated": "Camera omdraaien"
+ },
+ {
+ "id": "native.apple.11f8de87ca3fcb11",
+ "source": "Stop",
+ "translated": "Stoppen"
+ },
+ {
+ "id": "native.apple.7c92bec1c8a83e43",
+ "source": "Talk",
+ "translated": "Praten"
+ },
+ {
+ "id": "native.apple.dae61543f9b416ca",
+ "source": "Start realtime chat",
+ "translated": "Realtimechat starten"
+ },
+ {
+ "id": "native.apple.d376b015a90792a9",
+ "source": "Stop realtime chat",
+ "translated": "Realtimechat stoppen"
+ },
+ {
+ "id": "native.apple.ac48dbe25ac4d40d",
+ "source": "Connecting...",
+ "translated": "Verbinding maken..."
+ },
+ {
+ "id": "native.apple.ccce98756eb1dacd",
+ "source": "Gateway connected",
+ "translated": "Gateway verbonden"
+ },
{
"id": "native.apple.03aca5cfee32f12d",
"source": "Context %@%% used",
@@ -23163,21 +23208,6 @@
"source": "Attachments",
"translated": "Bijlagen"
},
- {
- "id": "native.apple.ee2c0d22f5861159",
- "source": "Talk",
- "translated": "Praten"
- },
- {
- "id": "native.apple.5d5041aefe6dfddd",
- "source": "Start realtime chat",
- "translated": "Realtime chat starten"
- },
- {
- "id": "native.apple.21a7d3a3386a2218",
- "source": "Stop realtime chat",
- "translated": "Realtime chat stoppen"
- },
{
"id": "native.apple.88c2de261ddae511",
"source": "Start",
@@ -23223,16 +23253,6 @@
"source": "Refresh",
"translated": "Vernieuwen"
},
- {
- "id": "native.apple.6c984c0e3ed3a69e",
- "source": "Connecting...",
- "translated": "Verbinden..."
- },
- {
- "id": "native.apple.898849eb2bcb0b53",
- "source": "Gateway connected",
- "translated": "Gateway verbonden"
- },
{
"id": "native.apple.b6adfcd17a6e73d7",
"source": "Message…",
diff --git a/apps/.i18n/native/pl.json b/apps/.i18n/native/pl.json
index 0c3b79b041b..351414814cb 100644
--- a/apps/.i18n/native/pl.json
+++ b/apps/.i18n/native/pl.json
@@ -23068,6 +23068,51 @@
"source": "<\\(tag)",
"translated": "<\\(tag)"
},
+ {
+ "id": "native.apple.fc5931c1f0a6bbec",
+ "source": "Switch to back camera",
+ "translated": "Przełącz na tylny aparat"
+ },
+ {
+ "id": "native.apple.cce3b539e31701c0",
+ "source": "Switch to front camera",
+ "translated": "Przełącz na przedni aparat"
+ },
+ {
+ "id": "native.apple.f397daffdfd02ee0",
+ "source": "Flip camera",
+ "translated": "Odwróć aparat"
+ },
+ {
+ "id": "native.apple.11f8de87ca3fcb11",
+ "source": "Stop",
+ "translated": "Zatrzymaj"
+ },
+ {
+ "id": "native.apple.7c92bec1c8a83e43",
+ "source": "Talk",
+ "translated": "Mów"
+ },
+ {
+ "id": "native.apple.dae61543f9b416ca",
+ "source": "Start realtime chat",
+ "translated": "Rozpocznij czat w czasie rzeczywistym"
+ },
+ {
+ "id": "native.apple.d376b015a90792a9",
+ "source": "Stop realtime chat",
+ "translated": "Zatrzymaj czat w czasie rzeczywistym"
+ },
+ {
+ "id": "native.apple.ac48dbe25ac4d40d",
+ "source": "Connecting...",
+ "translated": "Łączenie..."
+ },
+ {
+ "id": "native.apple.ccce98756eb1dacd",
+ "source": "Gateway connected",
+ "translated": "Połączono z Gateway"
+ },
{
"id": "native.apple.03aca5cfee32f12d",
"source": "Context %@%% used",
@@ -23163,21 +23208,6 @@
"source": "Attachments",
"translated": "Załączniki"
},
- {
- "id": "native.apple.ee2c0d22f5861159",
- "source": "Talk",
- "translated": "Rozmawiaj"
- },
- {
- "id": "native.apple.5d5041aefe6dfddd",
- "source": "Start realtime chat",
- "translated": "Rozpocznij czat w czasie rzeczywistym"
- },
- {
- "id": "native.apple.21a7d3a3386a2218",
- "source": "Stop realtime chat",
- "translated": "Zatrzymaj czat w czasie rzeczywistym"
- },
{
"id": "native.apple.88c2de261ddae511",
"source": "Start",
@@ -23223,16 +23253,6 @@
"source": "Refresh",
"translated": "Odśwież"
},
- {
- "id": "native.apple.6c984c0e3ed3a69e",
- "source": "Connecting...",
- "translated": "Łączenie..."
- },
- {
- "id": "native.apple.898849eb2bcb0b53",
- "source": "Gateway connected",
- "translated": "Gateway połączony"
- },
{
"id": "native.apple.b6adfcd17a6e73d7",
"source": "Message…",
diff --git a/apps/.i18n/native/pt-BR.json b/apps/.i18n/native/pt-BR.json
index 660228c4dfe..607554f3510 100644
--- a/apps/.i18n/native/pt-BR.json
+++ b/apps/.i18n/native/pt-BR.json
@@ -23068,6 +23068,51 @@
"source": "<\\(tag)",
"translated": "<\\(tag)"
},
+ {
+ "id": "native.apple.fc5931c1f0a6bbec",
+ "source": "Switch to back camera",
+ "translated": "Alternar para a câmera traseira"
+ },
+ {
+ "id": "native.apple.cce3b539e31701c0",
+ "source": "Switch to front camera",
+ "translated": "Alternar para a câmera frontal"
+ },
+ {
+ "id": "native.apple.f397daffdfd02ee0",
+ "source": "Flip camera",
+ "translated": "Inverter câmera"
+ },
+ {
+ "id": "native.apple.11f8de87ca3fcb11",
+ "source": "Stop",
+ "translated": "Parar"
+ },
+ {
+ "id": "native.apple.7c92bec1c8a83e43",
+ "source": "Talk",
+ "translated": "Falar"
+ },
+ {
+ "id": "native.apple.dae61543f9b416ca",
+ "source": "Start realtime chat",
+ "translated": "Iniciar conversa em tempo real"
+ },
+ {
+ "id": "native.apple.d376b015a90792a9",
+ "source": "Stop realtime chat",
+ "translated": "Encerrar conversa em tempo real"
+ },
+ {
+ "id": "native.apple.ac48dbe25ac4d40d",
+ "source": "Connecting...",
+ "translated": "Conectando..."
+ },
+ {
+ "id": "native.apple.ccce98756eb1dacd",
+ "source": "Gateway connected",
+ "translated": "Gateway conectado"
+ },
{
"id": "native.apple.03aca5cfee32f12d",
"source": "Context %@%% used",
@@ -23163,21 +23208,6 @@
"source": "Attachments",
"translated": "Anexos"
},
- {
- "id": "native.apple.ee2c0d22f5861159",
- "source": "Talk",
- "translated": "Falar"
- },
- {
- "id": "native.apple.5d5041aefe6dfddd",
- "source": "Start realtime chat",
- "translated": "Iniciar chat em tempo real"
- },
- {
- "id": "native.apple.21a7d3a3386a2218",
- "source": "Stop realtime chat",
- "translated": "Parar chat em tempo real"
- },
{
"id": "native.apple.88c2de261ddae511",
"source": "Start",
@@ -23223,16 +23253,6 @@
"source": "Refresh",
"translated": "Atualizar"
},
- {
- "id": "native.apple.6c984c0e3ed3a69e",
- "source": "Connecting...",
- "translated": "Conectando..."
- },
- {
- "id": "native.apple.898849eb2bcb0b53",
- "source": "Gateway connected",
- "translated": "Gateway conectado"
- },
{
"id": "native.apple.b6adfcd17a6e73d7",
"source": "Message…",
diff --git a/apps/.i18n/native/ru.json b/apps/.i18n/native/ru.json
index 75aa2bc17e1..b68b5af074f 100644
--- a/apps/.i18n/native/ru.json
+++ b/apps/.i18n/native/ru.json
@@ -23068,6 +23068,51 @@
"source": "<\\(tag)",
"translated": "<\\(tag)"
},
+ {
+ "id": "native.apple.fc5931c1f0a6bbec",
+ "source": "Switch to back camera",
+ "translated": "Переключиться на заднюю камеру"
+ },
+ {
+ "id": "native.apple.cce3b539e31701c0",
+ "source": "Switch to front camera",
+ "translated": "Переключиться на фронтальную камеру"
+ },
+ {
+ "id": "native.apple.f397daffdfd02ee0",
+ "source": "Flip camera",
+ "translated": "Сменить камеру"
+ },
+ {
+ "id": "native.apple.11f8de87ca3fcb11",
+ "source": "Stop",
+ "translated": "Остановить"
+ },
+ {
+ "id": "native.apple.7c92bec1c8a83e43",
+ "source": "Talk",
+ "translated": "Говорить"
+ },
+ {
+ "id": "native.apple.dae61543f9b416ca",
+ "source": "Start realtime chat",
+ "translated": "Начать чат в реальном времени"
+ },
+ {
+ "id": "native.apple.d376b015a90792a9",
+ "source": "Stop realtime chat",
+ "translated": "Остановить чат в реальном времени"
+ },
+ {
+ "id": "native.apple.ac48dbe25ac4d40d",
+ "source": "Connecting...",
+ "translated": "Подключение..."
+ },
+ {
+ "id": "native.apple.ccce98756eb1dacd",
+ "source": "Gateway connected",
+ "translated": "Gateway подключён"
+ },
{
"id": "native.apple.03aca5cfee32f12d",
"source": "Context %@%% used",
@@ -23163,21 +23208,6 @@
"source": "Attachments",
"translated": "Вложения"
},
- {
- "id": "native.apple.ee2c0d22f5861159",
- "source": "Talk",
- "translated": "Разговор"
- },
- {
- "id": "native.apple.5d5041aefe6dfddd",
- "source": "Start realtime chat",
- "translated": "Начать чат в реальном времени"
- },
- {
- "id": "native.apple.21a7d3a3386a2218",
- "source": "Stop realtime chat",
- "translated": "Остановить чат в реальном времени"
- },
{
"id": "native.apple.88c2de261ddae511",
"source": "Start",
@@ -23223,16 +23253,6 @@
"source": "Refresh",
"translated": "Обновить"
},
- {
- "id": "native.apple.6c984c0e3ed3a69e",
- "source": "Connecting...",
- "translated": "Подключение..."
- },
- {
- "id": "native.apple.898849eb2bcb0b53",
- "source": "Gateway connected",
- "translated": "Gateway подключен"
- },
{
"id": "native.apple.b6adfcd17a6e73d7",
"source": "Message…",
diff --git a/apps/.i18n/native/sv.json b/apps/.i18n/native/sv.json
index 9808f13027e..0c436c7b4ab 100644
--- a/apps/.i18n/native/sv.json
+++ b/apps/.i18n/native/sv.json
@@ -23068,6 +23068,51 @@
"source": "<\\(tag)",
"translated": "<\\(tag)"
},
+ {
+ "id": "native.apple.fc5931c1f0a6bbec",
+ "source": "Switch to back camera",
+ "translated": "Byt till bakre kameran"
+ },
+ {
+ "id": "native.apple.cce3b539e31701c0",
+ "source": "Switch to front camera",
+ "translated": "Byt till främre kameran"
+ },
+ {
+ "id": "native.apple.f397daffdfd02ee0",
+ "source": "Flip camera",
+ "translated": "Vänd kameran"
+ },
+ {
+ "id": "native.apple.11f8de87ca3fcb11",
+ "source": "Stop",
+ "translated": "Stoppa"
+ },
+ {
+ "id": "native.apple.7c92bec1c8a83e43",
+ "source": "Talk",
+ "translated": "Prata"
+ },
+ {
+ "id": "native.apple.dae61543f9b416ca",
+ "source": "Start realtime chat",
+ "translated": "Starta realtidschatt"
+ },
+ {
+ "id": "native.apple.d376b015a90792a9",
+ "source": "Stop realtime chat",
+ "translated": "Stoppa realtidschatt"
+ },
+ {
+ "id": "native.apple.ac48dbe25ac4d40d",
+ "source": "Connecting...",
+ "translated": "Ansluter..."
+ },
+ {
+ "id": "native.apple.ccce98756eb1dacd",
+ "source": "Gateway connected",
+ "translated": "Gateway ansluten"
+ },
{
"id": "native.apple.03aca5cfee32f12d",
"source": "Context %@%% used",
@@ -23163,21 +23208,6 @@
"source": "Attachments",
"translated": "Bilagor"
},
- {
- "id": "native.apple.ee2c0d22f5861159",
- "source": "Talk",
- "translated": "Prata"
- },
- {
- "id": "native.apple.5d5041aefe6dfddd",
- "source": "Start realtime chat",
- "translated": "Starta realtidschatt"
- },
- {
- "id": "native.apple.21a7d3a3386a2218",
- "source": "Stop realtime chat",
- "translated": "Stoppa realtidschatt"
- },
{
"id": "native.apple.88c2de261ddae511",
"source": "Start",
@@ -23223,16 +23253,6 @@
"source": "Refresh",
"translated": "Uppdatera"
},
- {
- "id": "native.apple.6c984c0e3ed3a69e",
- "source": "Connecting...",
- "translated": "Ansluter..."
- },
- {
- "id": "native.apple.898849eb2bcb0b53",
- "source": "Gateway connected",
- "translated": "Gateway ansluten"
- },
{
"id": "native.apple.b6adfcd17a6e73d7",
"source": "Message…",
diff --git a/apps/.i18n/native/th.json b/apps/.i18n/native/th.json
index 3b90b574a1d..ddbadc958b8 100644
--- a/apps/.i18n/native/th.json
+++ b/apps/.i18n/native/th.json
@@ -23068,6 +23068,51 @@
"source": "<\\(tag)",
"translated": "<\\(tag)"
},
+ {
+ "id": "native.apple.fc5931c1f0a6bbec",
+ "source": "Switch to back camera",
+ "translated": "สลับไปใช้กล้องหลัง"
+ },
+ {
+ "id": "native.apple.cce3b539e31701c0",
+ "source": "Switch to front camera",
+ "translated": "สลับไปใช้กล้องหน้า"
+ },
+ {
+ "id": "native.apple.f397daffdfd02ee0",
+ "source": "Flip camera",
+ "translated": "สลับกล้อง"
+ },
+ {
+ "id": "native.apple.11f8de87ca3fcb11",
+ "source": "Stop",
+ "translated": "หยุด"
+ },
+ {
+ "id": "native.apple.7c92bec1c8a83e43",
+ "source": "Talk",
+ "translated": "พูด"
+ },
+ {
+ "id": "native.apple.dae61543f9b416ca",
+ "source": "Start realtime chat",
+ "translated": "เริ่มแชทแบบเรียลไทม์"
+ },
+ {
+ "id": "native.apple.d376b015a90792a9",
+ "source": "Stop realtime chat",
+ "translated": "หยุดแชทแบบเรียลไทม์"
+ },
+ {
+ "id": "native.apple.ac48dbe25ac4d40d",
+ "source": "Connecting...",
+ "translated": "กำลังเชื่อมต่อ..."
+ },
+ {
+ "id": "native.apple.ccce98756eb1dacd",
+ "source": "Gateway connected",
+ "translated": "เชื่อมต่อ Gateway แล้ว"
+ },
{
"id": "native.apple.03aca5cfee32f12d",
"source": "Context %@%% used",
@@ -23163,21 +23208,6 @@
"source": "Attachments",
"translated": "ไฟล์แนบ"
},
- {
- "id": "native.apple.ee2c0d22f5861159",
- "source": "Talk",
- "translated": "พูดคุย"
- },
- {
- "id": "native.apple.5d5041aefe6dfddd",
- "source": "Start realtime chat",
- "translated": "เริ่มแชทแบบเรียลไทม์"
- },
- {
- "id": "native.apple.21a7d3a3386a2218",
- "source": "Stop realtime chat",
- "translated": "หยุดแชทแบบเรียลไทม์"
- },
{
"id": "native.apple.88c2de261ddae511",
"source": "Start",
@@ -23223,16 +23253,6 @@
"source": "Refresh",
"translated": "รีเฟรช"
},
- {
- "id": "native.apple.6c984c0e3ed3a69e",
- "source": "Connecting...",
- "translated": "กำลังเชื่อมต่อ..."
- },
- {
- "id": "native.apple.898849eb2bcb0b53",
- "source": "Gateway connected",
- "translated": "เชื่อมต่อ Gateway แล้ว"
- },
{
"id": "native.apple.b6adfcd17a6e73d7",
"source": "Message…",
diff --git a/apps/.i18n/native/tr.json b/apps/.i18n/native/tr.json
index aed0d214094..77d8fd313ea 100644
--- a/apps/.i18n/native/tr.json
+++ b/apps/.i18n/native/tr.json
@@ -23068,6 +23068,51 @@
"source": "<\\(tag)",
"translated": "<\\(tag)"
},
+ {
+ "id": "native.apple.fc5931c1f0a6bbec",
+ "source": "Switch to back camera",
+ "translated": "Arka kameraya geç"
+ },
+ {
+ "id": "native.apple.cce3b539e31701c0",
+ "source": "Switch to front camera",
+ "translated": "Ön kameraya geç"
+ },
+ {
+ "id": "native.apple.f397daffdfd02ee0",
+ "source": "Flip camera",
+ "translated": "Kamerayı çevir"
+ },
+ {
+ "id": "native.apple.11f8de87ca3fcb11",
+ "source": "Stop",
+ "translated": "Durdur"
+ },
+ {
+ "id": "native.apple.7c92bec1c8a83e43",
+ "source": "Talk",
+ "translated": "Konuş"
+ },
+ {
+ "id": "native.apple.dae61543f9b416ca",
+ "source": "Start realtime chat",
+ "translated": "Gerçek zamanlı sohbeti başlat"
+ },
+ {
+ "id": "native.apple.d376b015a90792a9",
+ "source": "Stop realtime chat",
+ "translated": "Gerçek zamanlı sohbeti durdur"
+ },
+ {
+ "id": "native.apple.ac48dbe25ac4d40d",
+ "source": "Connecting...",
+ "translated": "Bağlanıyor..."
+ },
+ {
+ "id": "native.apple.ccce98756eb1dacd",
+ "source": "Gateway connected",
+ "translated": "Gateway bağlandı"
+ },
{
"id": "native.apple.03aca5cfee32f12d",
"source": "Context %@%% used",
@@ -23163,21 +23208,6 @@
"source": "Attachments",
"translated": "Ekler"
},
- {
- "id": "native.apple.ee2c0d22f5861159",
- "source": "Talk",
- "translated": "Konuş"
- },
- {
- "id": "native.apple.5d5041aefe6dfddd",
- "source": "Start realtime chat",
- "translated": "Gerçek zamanlı sohbeti başlat"
- },
- {
- "id": "native.apple.21a7d3a3386a2218",
- "source": "Stop realtime chat",
- "translated": "Gerçek zamanlı sohbeti durdur"
- },
{
"id": "native.apple.88c2de261ddae511",
"source": "Start",
@@ -23223,16 +23253,6 @@
"source": "Refresh",
"translated": "Yenile"
},
- {
- "id": "native.apple.6c984c0e3ed3a69e",
- "source": "Connecting...",
- "translated": "Bağlanıyor..."
- },
- {
- "id": "native.apple.898849eb2bcb0b53",
- "source": "Gateway connected",
- "translated": "Gateway bağlı"
- },
{
"id": "native.apple.b6adfcd17a6e73d7",
"source": "Message…",
diff --git a/apps/.i18n/native/uk.json b/apps/.i18n/native/uk.json
index 8e26aa5954d..c9c3eda856b 100644
--- a/apps/.i18n/native/uk.json
+++ b/apps/.i18n/native/uk.json
@@ -23068,6 +23068,51 @@
"source": "<\\(tag)",
"translated": "<\\(tag)"
},
+ {
+ "id": "native.apple.fc5931c1f0a6bbec",
+ "source": "Switch to back camera",
+ "translated": "Перемкнути на задню камеру"
+ },
+ {
+ "id": "native.apple.cce3b539e31701c0",
+ "source": "Switch to front camera",
+ "translated": "Перемкнути на фронтальну камеру"
+ },
+ {
+ "id": "native.apple.f397daffdfd02ee0",
+ "source": "Flip camera",
+ "translated": "Змінити камеру"
+ },
+ {
+ "id": "native.apple.11f8de87ca3fcb11",
+ "source": "Stop",
+ "translated": "Зупинити"
+ },
+ {
+ "id": "native.apple.7c92bec1c8a83e43",
+ "source": "Talk",
+ "translated": "Говорити"
+ },
+ {
+ "id": "native.apple.dae61543f9b416ca",
+ "source": "Start realtime chat",
+ "translated": "Почати чат у реальному часі"
+ },
+ {
+ "id": "native.apple.d376b015a90792a9",
+ "source": "Stop realtime chat",
+ "translated": "Зупинити чат у реальному часі"
+ },
+ {
+ "id": "native.apple.ac48dbe25ac4d40d",
+ "source": "Connecting...",
+ "translated": "Підключення..."
+ },
+ {
+ "id": "native.apple.ccce98756eb1dacd",
+ "source": "Gateway connected",
+ "translated": "Gateway підключено"
+ },
{
"id": "native.apple.03aca5cfee32f12d",
"source": "Context %@%% used",
@@ -23163,21 +23208,6 @@
"source": "Attachments",
"translated": "Вкладення"
},
- {
- "id": "native.apple.ee2c0d22f5861159",
- "source": "Talk",
- "translated": "Говорити"
- },
- {
- "id": "native.apple.5d5041aefe6dfddd",
- "source": "Start realtime chat",
- "translated": "Почати чат у реальному часі"
- },
- {
- "id": "native.apple.21a7d3a3386a2218",
- "source": "Stop realtime chat",
- "translated": "Зупинити чат у реальному часі"
- },
{
"id": "native.apple.88c2de261ddae511",
"source": "Start",
@@ -23223,16 +23253,6 @@
"source": "Refresh",
"translated": "Оновити"
},
- {
- "id": "native.apple.6c984c0e3ed3a69e",
- "source": "Connecting...",
- "translated": "Підключення..."
- },
- {
- "id": "native.apple.898849eb2bcb0b53",
- "source": "Gateway connected",
- "translated": "Gateway підключено"
- },
{
"id": "native.apple.b6adfcd17a6e73d7",
"source": "Message…",
diff --git a/apps/.i18n/native/vi.json b/apps/.i18n/native/vi.json
index e9d9a603012..f9168891449 100644
--- a/apps/.i18n/native/vi.json
+++ b/apps/.i18n/native/vi.json
@@ -23068,6 +23068,51 @@
"source": "<\\(tag)",
"translated": "<\\(tag)"
},
+ {
+ "id": "native.apple.fc5931c1f0a6bbec",
+ "source": "Switch to back camera",
+ "translated": "Chuyển sang camera sau"
+ },
+ {
+ "id": "native.apple.cce3b539e31701c0",
+ "source": "Switch to front camera",
+ "translated": "Chuyển sang camera trước"
+ },
+ {
+ "id": "native.apple.f397daffdfd02ee0",
+ "source": "Flip camera",
+ "translated": "Đổi chiều camera"
+ },
+ {
+ "id": "native.apple.11f8de87ca3fcb11",
+ "source": "Stop",
+ "translated": "Dừng"
+ },
+ {
+ "id": "native.apple.7c92bec1c8a83e43",
+ "source": "Talk",
+ "translated": "Nói"
+ },
+ {
+ "id": "native.apple.dae61543f9b416ca",
+ "source": "Start realtime chat",
+ "translated": "Bắt đầu trò chuyện theo thời gian thực"
+ },
+ {
+ "id": "native.apple.d376b015a90792a9",
+ "source": "Stop realtime chat",
+ "translated": "Dừng trò chuyện theo thời gian thực"
+ },
+ {
+ "id": "native.apple.ac48dbe25ac4d40d",
+ "source": "Connecting...",
+ "translated": "Đang kết nối..."
+ },
+ {
+ "id": "native.apple.ccce98756eb1dacd",
+ "source": "Gateway connected",
+ "translated": "Đã kết nối Gateway"
+ },
{
"id": "native.apple.03aca5cfee32f12d",
"source": "Context %@%% used",
@@ -23163,21 +23208,6 @@
"source": "Attachments",
"translated": "Tệp đính kèm"
},
- {
- "id": "native.apple.ee2c0d22f5861159",
- "source": "Talk",
- "translated": "Nói chuyện"
- },
- {
- "id": "native.apple.5d5041aefe6dfddd",
- "source": "Start realtime chat",
- "translated": "Bắt đầu trò chuyện thời gian thực"
- },
- {
- "id": "native.apple.21a7d3a3386a2218",
- "source": "Stop realtime chat",
- "translated": "Dừng trò chuyện thời gian thực"
- },
{
"id": "native.apple.88c2de261ddae511",
"source": "Start",
@@ -23223,16 +23253,6 @@
"source": "Refresh",
"translated": "Làm mới"
},
- {
- "id": "native.apple.6c984c0e3ed3a69e",
- "source": "Connecting...",
- "translated": "Đang kết nối..."
- },
- {
- "id": "native.apple.898849eb2bcb0b53",
- "source": "Gateway connected",
- "translated": "Gateway đã kết nối"
- },
{
"id": "native.apple.b6adfcd17a6e73d7",
"source": "Message…",
diff --git a/apps/.i18n/native/zh-CN.json b/apps/.i18n/native/zh-CN.json
index c4a5714f2a8..60023c3122b 100644
--- a/apps/.i18n/native/zh-CN.json
+++ b/apps/.i18n/native/zh-CN.json
@@ -23068,6 +23068,51 @@
"source": "<\\(tag)",
"translated": "<\\(tag)"
},
+ {
+ "id": "native.apple.fc5931c1f0a6bbec",
+ "source": "Switch to back camera",
+ "translated": "切换到后置摄像头"
+ },
+ {
+ "id": "native.apple.cce3b539e31701c0",
+ "source": "Switch to front camera",
+ "translated": "切换到前置摄像头"
+ },
+ {
+ "id": "native.apple.f397daffdfd02ee0",
+ "source": "Flip camera",
+ "translated": "翻转摄像头"
+ },
+ {
+ "id": "native.apple.11f8de87ca3fcb11",
+ "source": "Stop",
+ "translated": "停止"
+ },
+ {
+ "id": "native.apple.7c92bec1c8a83e43",
+ "source": "Talk",
+ "translated": "说话"
+ },
+ {
+ "id": "native.apple.dae61543f9b416ca",
+ "source": "Start realtime chat",
+ "translated": "开始实时聊天"
+ },
+ {
+ "id": "native.apple.d376b015a90792a9",
+ "source": "Stop realtime chat",
+ "translated": "停止实时聊天"
+ },
+ {
+ "id": "native.apple.ac48dbe25ac4d40d",
+ "source": "Connecting...",
+ "translated": "正在连接..."
+ },
+ {
+ "id": "native.apple.ccce98756eb1dacd",
+ "source": "Gateway connected",
+ "translated": "Gateway 已连接"
+ },
{
"id": "native.apple.03aca5cfee32f12d",
"source": "Context %@%% used",
@@ -23163,21 +23208,6 @@
"source": "Attachments",
"translated": "附件"
},
- {
- "id": "native.apple.ee2c0d22f5861159",
- "source": "Talk",
- "translated": "对话"
- },
- {
- "id": "native.apple.5d5041aefe6dfddd",
- "source": "Start realtime chat",
- "translated": "开始实时聊天"
- },
- {
- "id": "native.apple.21a7d3a3386a2218",
- "source": "Stop realtime chat",
- "translated": "停止实时聊天"
- },
{
"id": "native.apple.88c2de261ddae511",
"source": "Start",
@@ -23223,16 +23253,6 @@
"source": "Refresh",
"translated": "刷新"
},
- {
- "id": "native.apple.6c984c0e3ed3a69e",
- "source": "Connecting...",
- "translated": "正在连接..."
- },
- {
- "id": "native.apple.898849eb2bcb0b53",
- "source": "Gateway connected",
- "translated": "Gateway 已连接"
- },
{
"id": "native.apple.b6adfcd17a6e73d7",
"source": "Message…",
diff --git a/apps/.i18n/native/zh-TW.json b/apps/.i18n/native/zh-TW.json
index e1506e9ee64..d0f1f3fc961 100644
--- a/apps/.i18n/native/zh-TW.json
+++ b/apps/.i18n/native/zh-TW.json
@@ -23068,6 +23068,51 @@
"source": "<\\(tag)",
"translated": "<\\(tag)"
},
+ {
+ "id": "native.apple.fc5931c1f0a6bbec",
+ "source": "Switch to back camera",
+ "translated": "切換至後置相機"
+ },
+ {
+ "id": "native.apple.cce3b539e31701c0",
+ "source": "Switch to front camera",
+ "translated": "切換至前置相機"
+ },
+ {
+ "id": "native.apple.f397daffdfd02ee0",
+ "source": "Flip camera",
+ "translated": "翻轉相機"
+ },
+ {
+ "id": "native.apple.11f8de87ca3fcb11",
+ "source": "Stop",
+ "translated": "停止"
+ },
+ {
+ "id": "native.apple.7c92bec1c8a83e43",
+ "source": "Talk",
+ "translated": "說話"
+ },
+ {
+ "id": "native.apple.dae61543f9b416ca",
+ "source": "Start realtime chat",
+ "translated": "開始即時聊天"
+ },
+ {
+ "id": "native.apple.d376b015a90792a9",
+ "source": "Stop realtime chat",
+ "translated": "停止即時聊天"
+ },
+ {
+ "id": "native.apple.ac48dbe25ac4d40d",
+ "source": "Connecting...",
+ "translated": "連線中..."
+ },
+ {
+ "id": "native.apple.ccce98756eb1dacd",
+ "source": "Gateway connected",
+ "translated": "Gateway 已連線"
+ },
{
"id": "native.apple.03aca5cfee32f12d",
"source": "Context %@%% used",
@@ -23163,21 +23208,6 @@
"source": "Attachments",
"translated": "附件"
},
- {
- "id": "native.apple.ee2c0d22f5861159",
- "source": "Talk",
- "translated": "說話"
- },
- {
- "id": "native.apple.5d5041aefe6dfddd",
- "source": "Start realtime chat",
- "translated": "開始即時聊天"
- },
- {
- "id": "native.apple.21a7d3a3386a2218",
- "source": "Stop realtime chat",
- "translated": "停止即時聊天"
- },
{
"id": "native.apple.88c2de261ddae511",
"source": "Start",
@@ -23223,16 +23253,6 @@
"source": "Refresh",
"translated": "重新整理"
},
- {
- "id": "native.apple.6c984c0e3ed3a69e",
- "source": "Connecting...",
- "translated": "正在連線..."
- },
- {
- "id": "native.apple.898849eb2bcb0b53",
- "source": "Gateway connected",
- "translated": "Gateway 已連線"
- },
{
"id": "native.apple.b6adfcd17a6e73d7",
"source": "Message…",
diff --git a/apps/android/app/src/main/res/values-ar/strings.xml b/apps/android/app/src/main/res/values-ar/strings.xml
index 8b737b8f8f0..51e5de9e141 100644
--- a/apps/android/app/src/main/res/values-ar/strings.xml
+++ b/apps/android/app/src/main/res/values-ar/strings.xml
@@ -421,7 +421,7 @@
"screenshot"
"تعبير Cron، مثل 0 9 * * *"
"العودة إلى الصوت"
- "تحدث"
+ "تحدّث"
"%1$s/%2$s متصلة"
"يُسمح لـ %1$s تطبيقات بإعادة التوجيه."
"الدردشة"
diff --git a/apps/android/app/src/main/res/values-fa/strings.xml b/apps/android/app/src/main/res/values-fa/strings.xml
index d6ce64f64ca..d233c1931a6 100644
--- a/apps/android/app/src/main/res/values-fa/strings.xml
+++ b/apps/android/app/src/main/res/values-fa/strings.xml
@@ -421,7 +421,7 @@
"screenshot"
"عبارت cron، مثلاً 0 9 * * *"
"بازگشت به صدا"
- "گفتگو"
+ "صحبت"
"%1$s/%2$s آنلاین"
"%1$s برنامه مجاز به بازارسال."
"گفتوگو"
diff --git a/apps/android/app/src/main/res/values-in/strings.xml b/apps/android/app/src/main/res/values-in/strings.xml
index db7fdf32943..b6e743cb968 100644
--- a/apps/android/app/src/main/res/values-in/strings.xml
+++ b/apps/android/app/src/main/res/values-in/strings.xml
@@ -1204,7 +1204,7 @@
"Folder kosong"
"Nonaktif"
"Tipografi"
- "Hentikan"
+ "Berhenti"
"Belum ada utas yang cocok."
"Pemasangan Gateway berhasil.\nSetujui kapabilitas node ponsel ini dari UI operator."
"Skill ini sudah terinstal, tetapi saat ini belum memenuhi syarat untuk dijalankan. Gunakan desktop atau CLI untuk mengubah konfigurasi."
diff --git a/apps/android/app/src/main/res/values-pl/strings.xml b/apps/android/app/src/main/res/values-pl/strings.xml
index 4b23dfe816a..a6bb2459585 100644
--- a/apps/android/app/src/main/res/values-pl/strings.xml
+++ b/apps/android/app/src/main/res/values-pl/strings.xml
@@ -421,7 +421,7 @@
"screenshot"
"Wyrażenie cron, np. 0 9 * * *"
"Powrót do głosu"
- "Rozmawiaj"
+ "Mów"
"%1$s/%2$s online"
"Zezwolono %1$s aplikacjom na przekazywanie."
"Czat"
diff --git a/apps/android/app/src/main/res/values-ru/strings.xml b/apps/android/app/src/main/res/values-ru/strings.xml
index bfba3669c63..22c8a346951 100644
--- a/apps/android/app/src/main/res/values-ru/strings.xml
+++ b/apps/android/app/src/main/res/values-ru/strings.xml
@@ -421,7 +421,7 @@
"screenshot"
"Cron-выражение, например 0 9 * * *"
"Вернуться к голосу"
- "Разговор"
+ "Говорить"
"В сети: %1$s/%2$s"
"Разрешена переадресация для %1$s приложений."
"Чат"
diff --git a/apps/android/app/src/main/res/values-th/strings.xml b/apps/android/app/src/main/res/values-th/strings.xml
index 5e39b806151..c01d1854418 100644
--- a/apps/android/app/src/main/res/values-th/strings.xml
+++ b/apps/android/app/src/main/res/values-th/strings.xml
@@ -421,7 +421,7 @@
"screenshot"
"นิพจน์ cron เช่น 0 9 * * *"
"กลับไปที่เสียง"
- "พูดคุย"
+ "พูด"
"ออนไลน์ %1$s/%2$s"
"อนุญาตให้ส่งต่อ %1$s แอป"
"แชท"
diff --git a/apps/android/app/src/main/res/values-vi/strings.xml b/apps/android/app/src/main/res/values-vi/strings.xml
index 72d22b19f0a..30f51c2d8a8 100644
--- a/apps/android/app/src/main/res/values-vi/strings.xml
+++ b/apps/android/app/src/main/res/values-vi/strings.xml
@@ -421,7 +421,7 @@
"screenshot"
"Biểu thức cron, ví dụ 0 9 * * *"
"Quay lại giọng nói"
- "Nói chuyện"
+ "Nói"
"%1$s/%2$s đang trực tuyến"
"%1$s ứng dụng được phép chuyển tiếp."
"Trò chuyện"
diff --git a/apps/ios/Resources/Localizable.xcstrings b/apps/ios/Resources/Localizable.xcstrings
index ef9183d4df9..a4913afc42b 100644
--- a/apps/ios/Resources/Localizable.xcstrings
+++ b/apps/ios/Resources/Localizable.xcstrings
@@ -68409,6 +68409,142 @@
}
}
},
+ "Flip camera": {
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Flip camera"
+ }
+ },
+ "zh-CN": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "翻转摄像头"
+ }
+ },
+ "zh-TW": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "翻轉相機"
+ }
+ },
+ "pt-BR": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Inverter câmera"
+ }
+ },
+ "de": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Kamera wechseln"
+ }
+ },
+ "es": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Cambiar de cámara"
+ }
+ },
+ "ja-JP": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "カメラを切り替える"
+ }
+ },
+ "ko": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "카메라 전환"
+ }
+ },
+ "fr": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Inverser la caméra"
+ }
+ },
+ "hi": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "कैमरा पलटें"
+ }
+ },
+ "ar": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "تبديل الكاميرا"
+ }
+ },
+ "it": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Inverti fotocamera"
+ }
+ },
+ "tr": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Kamerayı çevir"
+ }
+ },
+ "uk": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Змінити камеру"
+ }
+ },
+ "id": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Balik kamera"
+ }
+ },
+ "pl": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Odwróć aparat"
+ }
+ },
+ "th": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "สลับกล้อง"
+ }
+ },
+ "vi": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Đổi camera"
+ }
+ },
+ "nl": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Wissel van camera"
+ }
+ },
+ "fa": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "تعویض دوربین"
+ }
+ },
+ "ru": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Сменить камеру"
+ }
+ },
+ "sv": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Vänd kameran"
+ }
+ }
+ }
+ },
"For local iOS app development": {
"localizations": {
"en": {
@@ -164289,6 +164425,278 @@
}
}
},
+ "Switch to back camera": {
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Switch to back camera"
+ }
+ },
+ "zh-CN": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "切换到后置摄像头"
+ }
+ },
+ "zh-TW": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "切換至後置相機"
+ }
+ },
+ "pt-BR": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Alternar para a câmera traseira"
+ }
+ },
+ "de": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Zur rückseitigen Kamera wechseln"
+ }
+ },
+ "es": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Cambiar a la cámara trasera"
+ }
+ },
+ "ja-JP": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "背面カメラに切り替える"
+ }
+ },
+ "ko": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "후면 카메라로 전환"
+ }
+ },
+ "fr": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Passer à la caméra arrière"
+ }
+ },
+ "hi": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "पीछे वाले कैमरे पर स्विच करें"
+ }
+ },
+ "ar": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "التبديل إلى الكاميرا الخلفية"
+ }
+ },
+ "it": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Passa alla fotocamera posteriore"
+ }
+ },
+ "tr": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Arka kameraya geç"
+ }
+ },
+ "uk": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Перемкнутися на задню камеру"
+ }
+ },
+ "id": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Beralih ke kamera belakang"
+ }
+ },
+ "pl": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Przełącz na tylny aparat"
+ }
+ },
+ "th": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "สลับไปใช้กล้องหลัง"
+ }
+ },
+ "vi": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Chuyển sang camera sau"
+ }
+ },
+ "nl": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Schakel over naar de camera aan de achterkant"
+ }
+ },
+ "fa": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "تغییر به دوربین پشتی"
+ }
+ },
+ "ru": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Переключиться на заднюю камеру"
+ }
+ },
+ "sv": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Byt till den bakre kameran"
+ }
+ }
+ }
+ },
+ "Switch to front camera": {
+ "localizations": {
+ "en": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Switch to front camera"
+ }
+ },
+ "zh-CN": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "切换到前置摄像头"
+ }
+ },
+ "zh-TW": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "切換至前置相機"
+ }
+ },
+ "pt-BR": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Alternar para a câmera frontal"
+ }
+ },
+ "de": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Zur Frontkamera wechseln"
+ }
+ },
+ "es": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Cambiar a la cámara frontal"
+ }
+ },
+ "ja-JP": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "前面カメラに切り替える"
+ }
+ },
+ "ko": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "전면 카메라로 전환"
+ }
+ },
+ "fr": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Passer à la caméra avant"
+ }
+ },
+ "hi": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "सामने वाले कैमरे पर स्विच करें"
+ }
+ },
+ "ar": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "التبديل إلى الكاميرا الأمامية"
+ }
+ },
+ "it": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Passa alla fotocamera anteriore"
+ }
+ },
+ "tr": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Ön kameraya geç"
+ }
+ },
+ "uk": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Перемкнутися на фронтальну камеру"
+ }
+ },
+ "id": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Beralih ke kamera depan"
+ }
+ },
+ "pl": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Przełącz na przedni aparat"
+ }
+ },
+ "th": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "สลับไปใช้กล้องหน้า"
+ }
+ },
+ "vi": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Chuyển sang camera trước"
+ }
+ },
+ "nl": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Schakel over naar de camera aan de voorkant"
+ }
+ },
+ "fa": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "تغییر به دوربین جلو"
+ }
+ },
+ "ru": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Переключиться на фронтальную камеру"
+ }
+ },
+ "sv": {
+ "stringUnit": {
+ "state": "translated",
+ "value": "Byt till den främre kameran"
+ }
+ }
+ }
+ },
"Switching to %@…": {
"localizations": {
"en": {
diff --git a/apps/ios/Sources/Camera/CameraController.swift b/apps/ios/Sources/Camera/CameraController.swift
index 725e9eecc0f..fc9bc163193 100644
--- a/apps/ios/Sources/Camera/CameraController.swift
+++ b/apps/ios/Sources/Camera/CameraController.swift
@@ -37,13 +37,15 @@ actor CameraController {
}
}
- func snap(params: OpenClawCameraSnapParams) async throws -> (
+ func snap(
+ params: OpenClawCameraSnapParams,
+ defaultFacing: OpenClawCameraFacing = .front) async throws -> (
format: String,
base64: String,
width: Int,
height: Int)
{
- let facing = params.facing ?? .front
+ let facing = Self.resolveFacing(params.facing, defaultFacing: defaultFacing)
let format = params.format ?? .jpg
// Default to a reasonable max width to keep gateway payload sizes manageable.
// If you need the full-res photo, explicitly request a larger maxWidth.
@@ -102,13 +104,15 @@ actor CameraController {
height: res.heightPx)
}
- func clip(params: OpenClawCameraClipParams) async throws -> (
+ func clip(
+ params: OpenClawCameraClipParams,
+ defaultFacing: OpenClawCameraFacing = .front) async throws -> (
format: String,
base64: String,
durationMs: Int,
hasAudio: Bool)
{
- let facing = params.facing ?? .front
+ let facing = Self.resolveFacing(params.facing, defaultFacing: defaultFacing)
let durationMs = Self.clampDurationMs(params.durationMs)
let includeAudio = params.includeAudio ?? true
let format = params.format ?? .mp4
@@ -247,6 +251,13 @@ actor CameraController {
return min(60000, max(250, v))
}
+ nonisolated static func resolveFacing(
+ _ explicitFacing: OpenClawCameraFacing?,
+ defaultFacing: OpenClawCameraFacing) -> OpenClawCameraFacing
+ {
+ explicitFacing ?? defaultFacing
+ }
+
private nonisolated static func exportToMP4(inputURL: URL, outputURL: URL) async throws {
try Task.checkCancellation()
let asset = AVURLAsset(url: inputURL)
diff --git a/apps/ios/Sources/Design/ChatProTab.swift b/apps/ios/Sources/Design/ChatProTab.swift
index b73899c76d1..07e43211a34 100644
--- a/apps/ios/Sources/Design/ChatProTab.swift
+++ b/apps/ios/Sources/Design/ChatProTab.swift
@@ -1,3 +1,4 @@
+import AVFAudio
import OpenClawChatUI
import OpenClawProtocol
import SwiftUI
@@ -499,12 +500,34 @@ struct ChatProTab: View {
statusText: self.appModel.talkMode.statusText,
providerLabel: self.appModel.talkMode.gatewayTalkProviderLabel,
level: self.talkLevel,
+ inputDevices: self.talkInputDevices,
+ selectedInputDeviceID: self.selectedTalkInputDeviceID,
+ selectInputDevice: { deviceID in
+ self.appModel.talkMode.selectInputDevice(deviceID)
+ },
+ cameraFacing: self.appModel.preferredCameraFacing == .front ? .front : .back,
+ flipCamera: {
+ self.appModel.flipPreferredCameraFacing()
+ },
toggle: { sessionKey in
self.appModel.focusChatSession(sessionKey)
self.appModel.setTalkEnabled(!self.appModel.talkMode.isEnabled)
})
}
+ private var talkInputDevices: [OpenClawChatAudioInputDevice] {
+ (AVAudioSession.sharedInstance().availableInputs ?? []).map { input in
+ OpenClawChatAudioInputDevice(id: input.uid, name: input.portName)
+ }
+ }
+
+ private var selectedTalkInputDeviceID: String? {
+ guard let preferredID = self.appModel.talkMode.preferredInputDeviceID,
+ self.talkInputDevices.contains(where: { $0.id == preferredID })
+ else { return nil }
+ return preferredID
+ }
+
private var dictationControl: OpenClawChatDictationControl {
OpenClawChatDictationControl(
isActive: self.appModel.isChatDictationActive,
diff --git a/apps/ios/Sources/Model/NodeAppModel.swift b/apps/ios/Sources/Model/NodeAppModel.swift
index ef703c6ac58..9738b3659a5 100644
--- a/apps/ios/Sources/Model/NodeAppModel.swift
+++ b/apps/ios/Sources/Model/NodeAppModel.swift
@@ -405,6 +405,7 @@ final class NodeAppModel {
var isBackgrounded: Bool = false
let screen: ScreenController
private let camera: any CameraServicing
+ private(set) var preferredCameraFacing: OpenClawCameraFacing
private let screenRecorder: any ScreenRecordingServicing
private var watchGatewayConnectionStatus: OpenClawWatchAppStatusCode?
var gatewayStatusText: String = "Offline" {
@@ -804,6 +805,7 @@ final class NodeAppModel {
private static let watchExecApprovalBridgeStateKey = "watch.execApproval.bridge.state.v1"
private static let backgroundAliveLastSuccessAtMsKey = "gateway.backgroundAlive.lastSuccessAtMs"
private static let backgroundAliveLastTriggerKey = "gateway.backgroundAlive.lastTrigger"
+ private static let preferredCameraFacingKey = "camera.preferredFacing"
private static let foregroundResumeHealthTimeoutSeconds = 1
private static let watchChatCompletionWaitMs = 75000
private static let watchChatRunWaitSliceMs = 60000
@@ -839,6 +841,8 @@ final class NodeAppModel {
{
self.screen = screen
self.camera = camera
+ self.preferredCameraFacing = Self.cameraFacingPreference(
+ rawValue: UserDefaults.standard.string(forKey: Self.preferredCameraFacingKey))
self.screenRecorder = screenRecorder
self.locationService = locationService
self.notificationCenter = notificationCenter
@@ -2391,8 +2395,11 @@ final class NodeAppModel {
triggerCameraFlash()
let params = (try? Self.decodeParams(OpenClawCameraSnapParams.self, from: req.paramsJSON)) ??
OpenClawCameraSnapParams()
+ let defaultFacing = self.preferredCameraFacing
let res = try await self.withForegroundCapture {
- try await self.camera.snap(params: params)
+ try await self.camera.snap(
+ params: params,
+ defaultFacing: defaultFacing)
}
struct Payload: Codable {
@@ -2415,11 +2422,14 @@ final class NodeAppModel {
OpenClawCameraClipParams()
let includeAudio = params.includeAudio ?? true
+ let defaultFacing = self.preferredCameraFacing
showCameraHUD(ownerID: req.id, text: "Recording…", kind: .recording)
let res = try await self.withForegroundCapture(
audioOwner: includeAudio ? .cameraClip : nil)
{
- try await self.camera.clip(params: params)
+ try await self.camera.clip(
+ params: params,
+ defaultFacing: defaultFacing)
}
struct Payload: Codable {
@@ -3440,6 +3450,21 @@ extension NodeAppModel {
return UserDefaults.standard.bool(forKey: "camera.enabled")
}
+ nonisolated static func cameraFacingPreference(rawValue: String?) -> OpenClawCameraFacing {
+ rawValue.flatMap(OpenClawCameraFacing.init(rawValue:)) ?? .front
+ }
+
+ func setPreferredCameraFacing(_ facing: OpenClawCameraFacing) {
+ guard self.preferredCameraFacing != facing else { return }
+ self.preferredCameraFacing = facing
+ UserDefaults.standard.set(facing.rawValue, forKey: Self.preferredCameraFacingKey)
+ }
+
+ func flipPreferredCameraFacing() {
+ self.setPreferredCameraFacing(self.preferredCameraFacing == .front ? .back : .front)
+ UIImpactFeedbackGenerator(style: .light).impactOccurred()
+ }
+
private func triggerCameraFlash() {
self.cameraFlashNonce &+= 1
}
diff --git a/apps/ios/Sources/Services/NodeServiceProtocols.swift b/apps/ios/Sources/Services/NodeServiceProtocols.swift
index 803906dfe66..d23679d5839 100644
--- a/apps/ios/Sources/Services/NodeServiceProtocols.swift
+++ b/apps/ios/Sources/Services/NodeServiceProtocols.swift
@@ -8,8 +8,12 @@ typealias OpenClawCameraClipResult = (format: String, base64: String, durationMs
protocol CameraServicing: Sendable {
func listDevices() async -> [CameraController.CameraDeviceInfo]
- func snap(params: OpenClawCameraSnapParams) async throws -> OpenClawCameraSnapResult
- func clip(params: OpenClawCameraClipParams) async throws -> OpenClawCameraClipResult
+ func snap(
+ params: OpenClawCameraSnapParams,
+ defaultFacing: OpenClawCameraFacing) async throws -> OpenClawCameraSnapResult
+ func clip(
+ params: OpenClawCameraClipParams,
+ defaultFacing: OpenClawCameraFacing) async throws -> OpenClawCameraClipResult
}
protocol ScreenRecordingServicing: Sendable {
diff --git a/apps/ios/Sources/Voice/TalkModeManager.swift b/apps/ios/Sources/Voice/TalkModeManager.swift
index c476dc0fd16..0d4c0fe991b 100644
--- a/apps/ios/Sources/Voice/TalkModeManager.swift
+++ b/apps/ios/Sources/Voice/TalkModeManager.swift
@@ -133,6 +133,7 @@ final class TalkModeManager: NSObject {
private static let defaultSilenceTimeoutMs = TalkDefaults.silenceTimeoutMs
private static let redactedConfigSentinel = "__OPENCLAW_REDACTED__"
private static let realtimePrefetchExpiryLeewaySeconds: TimeInterval = 30
+ private static let preferredInputDeviceIDKey = "talk.preferredInputDeviceID"
var isEnabled: Bool = false
var isListening: Bool = false
var isSpeaking: Bool = false
@@ -156,6 +157,7 @@ final class TalkModeManager: NSObject {
/// voice path exposes no real level (system voice, compressed streaming); the
/// waveform then falls back to a synthetic pulse.
var playbackLevel: Double?
+ private(set) var preferredInputDeviceID: String?
var gatewayTalkConfigLoaded: Bool = false
var gatewayTalkApiKeyConfigured: Bool = false
var gatewayTalkDefaultModelId: String?
@@ -480,9 +482,24 @@ final class TalkModeManager: NSObject {
self.allowSimulatorCapture = allowSimulatorCapture
self.gatewaySpeechSynthesizerOverride = gatewaySpeechSynthesizer
self.audioSessionDeactivationAction = audioSessionDeactivationAction
+ self.preferredInputDeviceID = UserDefaults.standard.string(
+ forKey: Self.preferredInputDeviceIDKey)
super.init()
}
+ func selectInputDevice(_ deviceID: String?) {
+ let normalizedID = deviceID.flatMap { $0.isEmpty ? nil : $0 }
+ self.preferredInputDeviceID = normalizedID
+ if let normalizedID {
+ UserDefaults.standard.set(normalizedID, forKey: Self.preferredInputDeviceIDKey)
+ } else {
+ UserDefaults.standard.removeObject(forKey: Self.preferredInputDeviceIDKey)
+ }
+
+ guard self.audioSessionIsActive else { return }
+ Self.applyPreferredInput(normalizedID, to: AVAudioSession.sharedInstance())
+ }
+
func attachGateway(_ gateway: GatewayNodeSession) {
if let current = self.gateway, current !== gateway {
// Local dictation has no gateway owner, so a route replacement must
@@ -2200,6 +2217,9 @@ final class TalkModeManager: NSObject {
session.stop()
return .ignored
}
+ // WebRTC configures the shared session and may force speaker + built-in mic.
+ // Apply the user's input last so the explicit microphone selection wins.
+ Self.applyPreferredInput(self.preferredInputDeviceID, to: AVAudioSession.sharedInstance())
self.markRealtimeSessionReady()
GatewayDiagnostics.log(
"talk.timeline realtime start ready elapsedMs=\(Self.elapsedMs(since: startedAt))")
@@ -4287,12 +4307,12 @@ extension TalkModeManager {
}
private func configureOwnedAudioSession() throws {
- try Self.configureAudioSession()
+ try Self.configureAudioSession(preferredInputDeviceID: self.preferredInputDeviceID)
self.audioSessionIsActive = true
}
private func configureOwnedRealtimeAudioSession() throws {
- try Self.configureRealtimeAudioSession()
+ try Self.configureRealtimeAudioSession(preferredInputDeviceID: self.preferredInputDeviceID)
self.audioSessionIsActive = true
}
@@ -4320,7 +4340,7 @@ extension TalkModeManager {
}
}
- static func configureAudioSession() throws {
+ static func configureAudioSession(preferredInputDeviceID: String? = nil) throws {
let session = AVAudioSession.sharedInstance()
let forceSpeaker = TalkDefaults.speakerphoneEnabled()
let options = TalkAudioRoute.categoryOptions(speakerphoneEnabled: forceSpeaker)
@@ -4337,10 +4357,12 @@ extension TalkModeManager {
} else {
try? session.overrideOutputAudioPort(.none)
}
+ // A speaker override also forces the built-in microphone; apply an explicit input last.
+ self.applyPreferredInput(preferredInputDeviceID, to: session)
GatewayDiagnostics.log("talk audio: session speakerphone=\(forceSpeaker) \(Self.describeAudioSession())")
}
- static func configureRealtimeAudioSession() throws {
+ static func configureRealtimeAudioSession(preferredInputDeviceID: String? = nil) throws {
let session = AVAudioSession.sharedInstance()
let forceSpeaker = TalkDefaults.speakerphoneEnabled()
let options = TalkAudioRoute.categoryOptions(speakerphoneEnabled: forceSpeaker)
@@ -4358,10 +4380,24 @@ extension TalkModeManager {
} else {
try? session.overrideOutputAudioPort(.none)
}
+ // A speaker override also forces the built-in microphone; apply an explicit input last.
+ self.applyPreferredInput(preferredInputDeviceID, to: session)
GatewayDiagnostics.log(
"talk realtime audio: session speakerphone=\(forceSpeaker) \(Self.describeAudioSession())")
}
+ private static func applyPreferredInput(_ deviceID: String?, to session: AVAudioSession) {
+ let input = deviceID.flatMap { id in
+ session.availableInputs?.first(where: { $0.uid == id })
+ }
+ do {
+ try session.setPreferredInput(input)
+ } catch {
+ try? session.setPreferredInput(nil)
+ GatewayDiagnostics.log("talk audio: preferred input update failed: \(error.localizedDescription)")
+ }
+ }
+
private static func describeAudioSession() -> String {
let session = AVAudioSession.sharedInstance()
let inputs = session.currentRoute.inputs
diff --git a/apps/ios/Tests/CameraControllerClampTests.swift b/apps/ios/Tests/CameraControllerClampTests.swift
index 791010d11b0..f641a8a5ad0 100644
--- a/apps/ios/Tests/CameraControllerClampTests.swift
+++ b/apps/ios/Tests/CameraControllerClampTests.swift
@@ -1,8 +1,8 @@
import Testing
@testable import OpenClaw
-@Suite struct CameraControllerClampTests {
- @Test func clampQualityDefaultsAndBounds() {
+struct CameraControllerClampTests {
+ @Test func `clamp quality defaults and bounds`() {
#expect(CameraController.clampQuality(nil) == 0.9)
#expect(CameraController.clampQuality(0.0) == 0.05)
#expect(CameraController.clampQuality(0.049) == 0.05)
@@ -12,7 +12,7 @@ import Testing
#expect(CameraController.clampQuality(1.1) == 1.0)
}
- @Test func clampDurationDefaultsAndBounds() {
+ @Test func `clamp duration defaults and bounds`() {
#expect(CameraController.clampDurationMs(nil) == 3000)
#expect(CameraController.clampDurationMs(0) == 250)
#expect(CameraController.clampDurationMs(249) == 250)
@@ -21,4 +21,11 @@ import Testing
#expect(CameraController.clampDurationMs(60000) == 60000)
#expect(CameraController.clampDurationMs(60001) == 60000)
}
+
+ @Test func `preferred facing defaults and explicit override`() {
+ #expect(NodeAppModel.cameraFacingPreference(rawValue: nil) == .front)
+ #expect(NodeAppModel.cameraFacingPreference(rawValue: "back") == .back)
+ #expect(CameraController.resolveFacing(nil, defaultFacing: .back) == .back)
+ #expect(CameraController.resolveFacing(.front, defaultFacing: .back) == .front)
+ }
}
diff --git a/apps/ios/Tests/NodeAppModelInvokeTests.swift b/apps/ios/Tests/NodeAppModelInvokeTests.swift
index 9031a131571..3c17da2c3c4 100644
--- a/apps/ios/Tests/NodeAppModelInvokeTests.swift
+++ b/apps/ios/Tests/NodeAppModelInvokeTests.swift
@@ -34,11 +34,17 @@ private actor CancellingCameraService: CameraServicing {
[]
}
- func snap(params _: OpenClawCameraSnapParams) async throws -> OpenClawCameraSnapResult {
+ func snap(
+ params _: OpenClawCameraSnapParams,
+ defaultFacing _: OpenClawCameraFacing) async throws -> OpenClawCameraSnapResult
+ {
throw CancellationError()
}
- func clip(params _: OpenClawCameraClipParams) async throws -> OpenClawCameraClipResult {
+ func clip(
+ params _: OpenClawCameraClipParams,
+ defaultFacing _: OpenClawCameraFacing) async throws -> OpenClawCameraClipResult
+ {
throw CancellationError()
}
}
@@ -50,11 +56,17 @@ private actor RecordingCameraService: CameraServicing {
[]
}
- func snap(params _: OpenClawCameraSnapParams) async throws -> OpenClawCameraSnapResult {
+ func snap(
+ params _: OpenClawCameraSnapParams,
+ defaultFacing _: OpenClawCameraFacing) async throws -> OpenClawCameraSnapResult
+ {
(format: "jpg", base64: "", width: 1, height: 1)
}
- func clip(params _: OpenClawCameraClipParams) async throws -> OpenClawCameraClipResult {
+ func clip(
+ params _: OpenClawCameraClipParams,
+ defaultFacing _: OpenClawCameraFacing) async throws -> OpenClawCameraClipResult
+ {
self.clipCalls += 1
return (format: "mp4", base64: "", durationMs: 1, hasAudio: true)
}
@@ -105,11 +117,17 @@ private actor BlockingAudioCameraService: CameraServicing {
[]
}
- func snap(params _: OpenClawCameraSnapParams) async throws -> OpenClawCameraSnapResult {
+ func snap(
+ params _: OpenClawCameraSnapParams,
+ defaultFacing _: OpenClawCameraFacing) async throws -> OpenClawCameraSnapResult
+ {
(format: "jpg", base64: "", width: 1, height: 1)
}
- func clip(params _: OpenClawCameraClipParams) async throws -> OpenClawCameraClipResult {
+ func clip(
+ params _: OpenClawCameraClipParams,
+ defaultFacing _: OpenClawCameraFacing) async throws -> OpenClawCameraClipResult
+ {
await self.barrier.suspendFirstPreparation()
try Task.checkCancellation()
return (format: "mp4", base64: "", durationMs: 1, hasAudio: true)
@@ -186,7 +204,10 @@ private actor OverlappingCameraService: CameraServicing {
[]
}
- func snap(params _: OpenClawCameraSnapParams) async throws -> OpenClawCameraSnapResult {
+ func snap(
+ params _: OpenClawCameraSnapParams,
+ defaultFacing _: OpenClawCameraFacing) async throws -> OpenClawCameraSnapResult
+ {
self.snapCount += 1
if self.snapCount == 1 {
self.firstStarted.yield()
@@ -201,7 +222,10 @@ private actor OverlappingCameraService: CameraServicing {
return (format: "jpg", base64: "", width: 1, height: 1)
}
- func clip(params _: OpenClawCameraClipParams) async throws -> OpenClawCameraClipResult {
+ func clip(
+ params _: OpenClawCameraClipParams,
+ defaultFacing _: OpenClawCameraFacing) async throws -> OpenClawCameraClipResult
+ {
throw CancellationError()
}
diff --git a/apps/shared/OpenClawKit/Sources/OpenClawChatUI/ChatCameraFlipButton.swift b/apps/shared/OpenClawKit/Sources/OpenClawChatUI/ChatCameraFlipButton.swift
new file mode 100644
index 00000000000..05a6f721415
--- /dev/null
+++ b/apps/shared/OpenClawKit/Sources/OpenClawChatUI/ChatCameraFlipButton.swift
@@ -0,0 +1,214 @@
+import Foundation
+import SwiftUI
+
+@MainActor
+struct ChatCameraFlipButton: View {
+ let control: OpenClawChatTalkControl
+ let size: CGFloat
+
+ static func isAvailable(for control: OpenClawChatTalkControl) -> Bool {
+ control.isEnabled && control.cameraFacing != nil && control.flipCamera != nil
+ }
+
+ var body: some View {
+ Button {
+ self.control.flipCamera?()
+ } label: {
+ Image(systemName: "arrow.triangle.2.circlepath.camera")
+ .font(OpenClawChatTypography.body(size: 14, weight: .semibold, relativeTo: .subheadline))
+ .foregroundStyle(.primary)
+ .frame(width: self.size, height: self.size)
+ .background {
+ Circle()
+ .fill(OpenClawChatTheme.accent.opacity(0.12))
+ }
+ .contentShape(Rectangle())
+ }
+ .buttonStyle(.plain)
+ .accessibilityLabel(self.accessibilityLabel)
+ .accessibilityIdentifier("chat-camera-flip")
+ .help(self.accessibilityLabel)
+ }
+
+ private var accessibilityLabel: String {
+ switch self.control.cameraFacing {
+ case .front:
+ String(localized: "Switch to back camera")
+ case .back:
+ String(localized: "Switch to front camera")
+ case nil:
+ String(localized: "Flip camera")
+ }
+ }
+}
+
+@MainActor
+struct ChatTalkButton: View {
+ enum Style {
+ case full
+ case compact(controlHeight: CGFloat, iconControlSize: CGFloat)
+ }
+
+ let control: OpenClawChatTalkControl
+ let sessionKey: String
+ let helpText: String
+ let style: Style
+
+ var body: some View {
+ switch self.style {
+ case .full:
+ self.fullButton
+ case let .compact(controlHeight, iconControlSize):
+ self.compactButton(controlHeight: controlHeight, iconControlSize: iconControlSize)
+ }
+ }
+
+ private var fullButton: some View {
+ Button {
+ self.control.toggle(self.sessionKey)
+ } label: {
+ HStack(spacing: 6) {
+ ChatTalkButtonGlyph(control: self.control)
+ .font(OpenClawChatTypography.captionSemiBold)
+ Text(self.control.isEnabled ? "Stop" : "Talk")
+ .font(OpenClawChatTypography.captionSemiBold)
+ .lineLimit(1)
+ }
+ .foregroundStyle(self.control.isEnabled ? .white : .primary)
+ .padding(.horizontal, 10)
+ .frame(height: 32)
+ .background {
+ Capsule()
+ .fill(self.fill)
+ }
+ .overlay {
+ Capsule()
+ .strokeBorder(self.stroke, lineWidth: 1)
+ }
+ }
+ .buttonStyle(.plain)
+ .disabled(!self.control.isGatewayConnected && !self.control.isEnabled)
+ .accessibilityLabel(self.control.isEnabled ? "Stop realtime chat" : "Start realtime chat")
+ .accessibilityValue(self.accessibilityValue)
+ .accessibilityIdentifier("chat-realtime-control")
+ .help(self.helpText)
+ .chatTalkInputDeviceMenu(self.control)
+ }
+
+ private func compactButton(controlHeight: CGFloat, iconControlSize: CGFloat) -> some View {
+ Button {
+ self.control.toggle(self.sessionKey)
+ } label: {
+ ChatTalkButtonGlyph(control: self.control)
+ .font(OpenClawChatTypography.body(size: 14, weight: .semibold, relativeTo: .subheadline))
+ .foregroundStyle(.white)
+ .frame(width: iconControlSize, height: iconControlSize)
+ // Prominent filled circle so the mic reads as the primary action,
+ // mirroring the send button it swaps with once a draft exists.
+ .background {
+ Circle()
+ .fill(self.control.isEnabled ? self.fill : AnyShapeStyle(OpenClawChatTheme.accent))
+ .opacity(self.control.isGatewayConnected || self.control.isEnabled ? 1 : 0.4)
+ }
+ .frame(width: controlHeight, height: controlHeight)
+ .contentShape(Rectangle())
+ }
+ .buttonStyle(.plain)
+ .disabled(!self.control.isGatewayConnected && !self.control.isEnabled)
+ .accessibilityLabel(self.control.isEnabled ? "Stop realtime chat" : "Start realtime chat")
+ .accessibilityValue(self.accessibilityValue)
+ .accessibilityIdentifier("chat-realtime-control")
+ .help(self.helpText)
+ .chatTalkInputDeviceMenu(self.control)
+ }
+
+ private var fill: AnyShapeStyle {
+ if self.control.isEnabled {
+ return AnyShapeStyle(OpenClawChatTheme.userBubble)
+ }
+ if !self.control.isGatewayConnected {
+ return AnyShapeStyle(Color.secondary.opacity(0.12))
+ }
+ return OpenClawChatTheme.subtleCard
+ }
+
+ private var stroke: Color {
+ if self.control.isEnabled {
+ return Color.white.opacity(0.18)
+ }
+ return OpenClawChatTheme.composerBorder
+ }
+
+ private var accessibilityValue: String {
+ let status = self.control.statusText.trimmingCharacters(in: .whitespacesAndNewlines)
+ let provider = self.control.providerLabel.trimmingCharacters(in: .whitespacesAndNewlines)
+ return [status, provider].filter { !$0.isEmpty }.joined(separator: ", ")
+ }
+}
+
+extension OpenClawChatComposer {
+ /// Local capture and realtime Talk share one microphone, so the Talk affordance
+ /// must yield until dictation or voice-note capture releases audio ownership.
+ nonisolated static func showsCompactTalkControl(
+ hasDraftToSend: Bool,
+ hasBlockingRunActivity: Bool,
+ isLocalVoiceCaptureActive: Bool) -> Bool
+ {
+ !hasDraftToSend && !hasBlockingRunActivity && !isLocalVoiceCaptureActive
+ }
+}
+
+@MainActor
+enum ChatDictationActions {
+ static func start(
+ _ control: OpenClawChatDictationControl,
+ task: Binding?>,
+ viewModel: OpenClawChatViewModel)
+ {
+ guard task.wrappedValue == nil else { return }
+ let session = viewModel.currentSessionSnapshot()
+ task.wrappedValue = Task { @MainActor in
+ defer { task.wrappedValue = nil }
+ do {
+ guard let transcript = try await control.start(), !transcript.isEmpty else { return }
+ try Task.checkCancellation()
+ viewModel.appendDictationTranscript(transcript, for: session)
+ } catch is CancellationError {
+ return
+ } catch {
+ guard !Task.isCancelled else { return }
+ viewModel.setDictationError(error, for: session)
+ }
+ }
+ }
+
+ static func cancel(
+ task: Binding?>,
+ control: OpenClawChatDictationControl?)
+ {
+ guard task.wrappedValue != nil else { return }
+ task.wrappedValue?.cancel()
+ control?.cancel()
+ }
+}
+
+struct ChatConnectionPill: View {
+ let isConnected: Bool
+
+ var body: some View {
+ HStack(spacing: 6) {
+ Circle()
+ .fill(self.isConnected ? .green : .orange)
+ .frame(width: 7, height: 7)
+ Text(self.isConnected ? "Gateway connected" : "Connecting...")
+ .font(OpenClawChatTypography.caption2)
+ .foregroundStyle(.secondary)
+ }
+ .padding(.horizontal, 8)
+ .padding(.vertical, 4)
+ .background {
+ Capsule()
+ .fill(OpenClawChatTheme.subtleCard)
+ }
+ }
+}
diff --git a/apps/shared/OpenClawKit/Sources/OpenClawChatUI/ChatComposer.swift b/apps/shared/OpenClawKit/Sources/OpenClawChatUI/ChatComposer.swift
index f16e70c0d33..af54ad161d1 100644
--- a/apps/shared/OpenClawKit/Sources/OpenClawChatUI/ChatComposer.swift
+++ b/apps/shared/OpenClawKit/Sources/OpenClawChatUI/ChatComposer.swift
@@ -186,7 +186,7 @@ struct OpenClawChatComposer: View {
private var lifecycleComposer: some View {
self.recorderLifecycleComposer
.onChange(of: self.presentationOwner) { _, _ in
- self.cancelActiveDictation()
+ ChatDictationActions.cancel(task: self.$dictationTask, control: self.dictationControl)
#if !os(macOS)
self.showsPhotoPicker = false
self.showsFileImporter = false
@@ -204,7 +204,7 @@ struct OpenClawChatComposer: View {
self.stageCompletedVoiceNoteIfNeeded()
}
.onDisappear {
- self.cancelActiveDictation()
+ ChatDictationActions.cancel(task: self.$dictationTask, control: self.dictationControl)
#if !os(macOS)
self.showsPhotoPicker = false
self.showsFileImporter = false
@@ -696,10 +696,18 @@ struct OpenClawChatComposer: View {
HStack(alignment: .center, spacing: 8) {
if let talkControl {
- self.talkButton(talkControl)
+ ChatTalkButton(
+ control: talkControl,
+ sessionKey: self.viewModel.sessionKey,
+ helpText: self.talkHelpText(talkControl),
+ style: .full)
+ if ChatCameraFlipButton.isAvailable(for: talkControl) {
+ ChatCameraFlipButton(control: talkControl, size: 32)
+ }
}
if self.showsConnectionPill {
- self.connectionPill
+ ChatConnectionPill(
+ isConnected: self.viewModel.healthOK || (self.talkControl?.isGatewayConnected ?? false))
}
Spacer(minLength: 0)
self.sendButton
@@ -756,15 +764,22 @@ struct OpenClawChatComposer: View {
isComposerEnabled: self.isComposerEnabled,
isAttachmentInputEnabled: self.isAttachmentInputEnabled,
onCancelDictation: {
- self.cancelActiveDictation()
+ ChatDictationActions.cancel(task: self.$dictationTask, control: self.dictationControl)
},
onStartDictation: {
if let dictationControl = self.dictationControl {
- self.startDictation(dictationControl)
+ ChatDictationActions.start(
+ dictationControl,
+ task: self.$dictationTask,
+ viewModel: self.viewModel)
}
})
}
+ if let talkControl, ChatCameraFlipButton.isAvailable(for: talkControl) {
+ ChatCameraFlipButton(control: talkControl, size: self.cleanControlHeight)
+ }
+
self.cleanTrailingControl
}
}
@@ -779,7 +794,13 @@ struct OpenClawChatComposer: View {
isLocalVoiceCaptureActive: self.isLocalVoiceCaptureActive),
let talkControl
{
- self.compactTalkButton(talkControl)
+ ChatTalkButton(
+ control: talkControl,
+ sessionKey: self.viewModel.sessionKey,
+ helpText: self.talkHelpText(talkControl),
+ style: .compact(
+ controlHeight: self.cleanControlHeight,
+ iconControlSize: self.cleanIconControlSize))
} else {
sendButton
.frame(width: cleanControlHeight, height: cleanControlHeight)
@@ -793,124 +814,6 @@ struct OpenClawChatComposer: View {
self.voiceNoteControl?.recorder.isRequestingPermission == true
}
- /// Local capture and realtime Talk share one microphone, so the Talk affordance
- /// must yield until dictation or voice-note capture releases audio ownership.
- nonisolated static func showsCompactTalkControl(
- hasDraftToSend: Bool,
- hasBlockingRunActivity: Bool,
- isLocalVoiceCaptureActive: Bool) -> Bool
- {
- !hasDraftToSend && !hasBlockingRunActivity && !isLocalVoiceCaptureActive
- }
-
- private func talkButton(_ talkControl: OpenClawChatTalkControl) -> some View {
- Button {
- talkControl.toggle(self.viewModel.sessionKey)
- } label: {
- HStack(spacing: 6) {
- ChatTalkButtonGlyph(control: talkControl)
- .font(OpenClawChatTypography.captionSemiBold)
- Text(talkControl.isEnabled ? "Stop" : "Talk")
- .font(OpenClawChatTypography.captionSemiBold)
- .lineLimit(1)
- }
- .foregroundStyle(talkControl.isEnabled ? .white : .primary)
- .padding(.horizontal, 10)
- .frame(height: 32)
- .background {
- Capsule()
- .fill(self.talkButtonFill(talkControl))
- }
- .overlay {
- Capsule()
- .strokeBorder(self.talkButtonStroke(talkControl), lineWidth: 1)
- }
- }
- .buttonStyle(.plain)
- .disabled(!talkControl.isGatewayConnected && !talkControl.isEnabled)
- .accessibilityLabel(talkControl.isEnabled ? "Stop realtime chat" : "Start realtime chat")
- .accessibilityValue(self.talkAccessibilityValue(talkControl))
- .accessibilityIdentifier("chat-realtime-control")
- .help(self.talkHelpText(talkControl))
- .chatTalkInputDeviceMenu(talkControl)
- }
-
- private func startDictation(_ control: OpenClawChatDictationControl) {
- guard self.dictationTask == nil else { return }
- let session = self.viewModel.currentSessionSnapshot()
- self.dictationTask = Task { @MainActor in
- defer { self.dictationTask = nil }
- do {
- guard let transcript = try await control.start(), !transcript.isEmpty else { return }
- try Task.checkCancellation()
- self.viewModel.appendDictationTranscript(transcript, for: session)
- } catch is CancellationError {
- return
- } catch {
- guard !Task.isCancelled else { return }
- self.viewModel.setDictationError(error, for: session)
- }
- }
- }
-
- private func cancelActiveDictation() {
- guard self.dictationTask != nil else { return }
- self.dictationTask?.cancel()
- self.dictationControl?.cancel()
- }
-
- private func compactTalkButton(_ talkControl: OpenClawChatTalkControl) -> some View {
- Button {
- talkControl.toggle(self.viewModel.sessionKey)
- } label: {
- ChatTalkButtonGlyph(control: talkControl)
- .font(OpenClawChatTypography.body(size: 14, weight: .semibold, relativeTo: .subheadline))
- .foregroundStyle(.white)
- .frame(width: self.cleanIconControlSize, height: self.cleanIconControlSize)
- // Prominent filled circle so the mic reads as the primary action,
- // mirroring the send button it swaps with once a draft exists.
- .background {
- Circle()
- .fill(talkControl.isEnabled
- ? self.talkButtonFill(talkControl)
- : AnyShapeStyle(OpenClawChatTheme.accent))
- .opacity(talkControl.isGatewayConnected || talkControl.isEnabled ? 1 : 0.4)
- }
- .frame(width: self.cleanControlHeight, height: self.cleanControlHeight)
- .contentShape(Rectangle())
- }
- .buttonStyle(.plain)
- .disabled(!talkControl.isGatewayConnected && !talkControl.isEnabled)
- .accessibilityLabel(talkControl.isEnabled ? "Stop realtime chat" : "Start realtime chat")
- .accessibilityValue(self.talkAccessibilityValue(talkControl))
- .accessibilityIdentifier("chat-realtime-control")
- .help(self.talkHelpText(talkControl))
- .chatTalkInputDeviceMenu(talkControl)
- }
-
- private func talkButtonFill(_ talkControl: OpenClawChatTalkControl) -> AnyShapeStyle {
- if talkControl.isEnabled {
- return AnyShapeStyle(OpenClawChatTheme.userBubble)
- }
- if !talkControl.isGatewayConnected {
- return AnyShapeStyle(Color.secondary.opacity(0.12))
- }
- return OpenClawChatTheme.subtleCard
- }
-
- private func talkButtonStroke(_ talkControl: OpenClawChatTalkControl) -> Color {
- if talkControl.isEnabled {
- return Color.white.opacity(0.18)
- }
- return OpenClawChatTheme.composerBorder
- }
-
- private func talkAccessibilityValue(_ talkControl: OpenClawChatTalkControl) -> String {
- let status = talkControl.statusText.trimmingCharacters(in: .whitespacesAndNewlines)
- let provider = talkControl.providerLabel.trimmingCharacters(in: .whitespacesAndNewlines)
- return [status, provider].filter { !$0.isEmpty }.joined(separator: ", ")
- }
-
private func talkHelpText(_ talkControl: OpenClawChatTalkControl) -> String {
if !talkControl.isGatewayConnected, !talkControl.isEnabled {
return "Connect the gateway before starting realtime chat"
@@ -919,25 +822,6 @@ struct OpenClawChatComposer: View {
return "\(action) realtime chat for \(self.activeSessionLabel)"
}
- private var connectionPill: some View {
- HStack(spacing: 6) {
- Circle()
- .fill(self.connectionOK ? .green : .orange)
- .frame(width: 7, height: 7)
- Text(self.connectionStatusText)
- .font(OpenClawChatTypography.caption2)
- .foregroundStyle(.secondary)
- }
- .padding(.horizontal, self.composerChrome == .clean ? 0 : 8)
- .padding(.vertical, self.composerChrome == .clean ? 0 : 4)
- .background {
- if self.composerChrome == .full {
- Capsule()
- .fill(OpenClawChatTheme.subtleCard)
- }
- }
- }
-
private var activeSessionLabel: String {
let match = self.viewModel.sessions.first { $0.key == self.viewModel.sessionKey }
let trimmed = match?.displayName?.trimmingCharacters(in: .whitespacesAndNewlines) ?? ""
@@ -1454,14 +1338,6 @@ extension OpenClawChatComposer {
recorder.cancel()
}
- private var connectionStatusText: String {
- self.connectionOK ? "Gateway connected" : "Connecting..."
- }
-
- private var connectionOK: Bool {
- self.viewModel.healthOK || (self.talkControl?.isGatewayConnected ?? false)
- }
-
private var placeholderText: String {
let trimmed = self.messagePlaceholder?.trimmingCharacters(in: .whitespacesAndNewlines) ?? ""
return trimmed.isEmpty ? "Message…" : trimmed
diff --git a/apps/shared/OpenClawKit/Sources/OpenClawChatUI/OpenClawChatTalkControl.swift b/apps/shared/OpenClawKit/Sources/OpenClawChatUI/OpenClawChatTalkControl.swift
index 5ea31f0d47c..14da957710d 100644
--- a/apps/shared/OpenClawKit/Sources/OpenClawChatUI/OpenClawChatTalkControl.swift
+++ b/apps/shared/OpenClawKit/Sources/OpenClawChatUI/OpenClawChatTalkControl.swift
@@ -8,6 +8,11 @@ public struct OpenClawChatAudioInputDevice: Equatable, Identifiable, Sendable {
}
}
+public enum OpenClawCameraFacingSelection: String, Equatable, Sendable {
+ case back
+ case front
+}
+
public struct OpenClawChatTalkControl {
public var isEnabled: Bool
public var isListening: Bool
@@ -21,6 +26,8 @@ public struct OpenClawChatTalkControl {
public var inputDevices: [OpenClawChatAudioInputDevice]
public var selectedInputDeviceID: String?
public var selectInputDevice: (@MainActor (_ deviceID: String?) -> Void)?
+ public var cameraFacing: OpenClawCameraFacingSelection?
+ public var flipCamera: (@MainActor () -> Void)?
public var toggle: @MainActor (_ sessionKey: String) -> Void
public init(
@@ -36,6 +43,8 @@ public struct OpenClawChatTalkControl {
inputDevices: [OpenClawChatAudioInputDevice] = [],
selectedInputDeviceID: String? = nil,
selectInputDevice: (@MainActor (_ deviceID: String?) -> Void)? = nil,
+ cameraFacing: OpenClawCameraFacingSelection? = nil,
+ flipCamera: (@MainActor () -> Void)? = nil,
toggle: @escaping @MainActor (_ sessionKey: String) -> Void)
{
self.isEnabled = isEnabled
@@ -50,6 +59,8 @@ public struct OpenClawChatTalkControl {
self.inputDevices = inputDevices
self.selectedInputDeviceID = selectedInputDeviceID
self.selectInputDevice = selectInputDevice
+ self.cameraFacing = cameraFacing
+ self.flipCamera = flipCamera
self.toggle = toggle
}
}
diff --git a/apps/shared/OpenClawKit/Tests/OpenClawKitTests/ChatTalkActivityTests.swift b/apps/shared/OpenClawKit/Tests/OpenClawKitTests/ChatTalkActivityTests.swift
index 23668dd6b2f..4f6ee7216c6 100644
--- a/apps/shared/OpenClawKit/Tests/OpenClawKitTests/ChatTalkActivityTests.swift
+++ b/apps/shared/OpenClawKit/Tests/OpenClawKitTests/ChatTalkActivityTests.swift
@@ -19,10 +19,13 @@ struct ChatTalkControlTests {
#expect(control.inputDevices.isEmpty)
#expect(control.selectedInputDeviceID == nil)
#expect(control.selectInputDevice == nil)
+ #expect(control.cameraFacing == nil)
+ #expect(control.flipCamera == nil)
}
@Test func `feedback and input selection fields preserve supplied values`() {
var selectedID: String? = "unchanged"
+ var flipCount = 0
let devices = [OpenClawChatAudioInputDevice(id: "mic-1", name: "Desk Mic")]
let control = OpenClawChatTalkControl(
isEnabled: true,
@@ -37,9 +40,12 @@ struct ChatTalkControlTests {
inputDevices: devices,
selectedInputDeviceID: "mic-1",
selectInputDevice: { selectedID = $0 },
+ cameraFacing: .back,
+ flipCamera: { flipCount += 1 },
toggle: { _ in })
control.selectInputDevice?(nil)
+ control.flipCamera?()
#expect(control.level == 0.6)
#expect(control.partialTranscript == "hello")
@@ -47,6 +53,8 @@ struct ChatTalkControlTests {
#expect(control.inputDevices == devices)
#expect(control.selectedInputDeviceID == "mic-1")
#expect(selectedID == nil)
+ #expect(control.cameraFacing == .back)
+ #expect(flipCount == 1)
}
}