feat(ios): Talk camera flip control and mic input selection (#111044)

* feat(ios): add Talk camera flip and mic selection

* chore(ios): sync native i18n inventory and locale artifacts for talk camera/mic strings

* chore(ios): commit regenerated Localizable.xcstrings for new talk strings

* fix(ios): extract Talk composer controls

* chore(ios): resync native i18n inventory and locale artifacts atop landed Android entries

* fix(ios): repair Talk composer CI checks

* chore(i18n): commit regenerated Android locale outputs from catalog reconciliation

* chore(i18n): sync Android locale outputs after rebase
This commit is contained in:
Peter Steinberger
2026-07-19 01:24:53 -07:00
committed by GitHub
parent 96c9cc112c
commit 59b2fbbb4b
42 changed files with 1984 additions and 877 deletions
@@ -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",
+179 -147
View File
@@ -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",
+45 -25
View File
@@ -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…",
+45 -25
View File
@@ -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…",
+45 -25
View File
@@ -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…",
+45 -25
View File
@@ -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…",
+45 -25
View File
@@ -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…",
+45 -25
View File
@@ -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…",
+45 -25
View File
@@ -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…",
+45 -25
View File
@@ -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…",
+45 -25
View File
@@ -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…",
+45 -25
View File
@@ -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…",
+45 -25
View File
@@ -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…",
+45 -25
View File
@@ -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…",
+45 -25
View File
@@ -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…",
+45 -25
View File
@@ -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…",
+45 -25
View File
@@ -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…",
+45 -25
View File
@@ -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…",
+45 -25
View File
@@ -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…",
+45 -25
View File
@@ -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…",
+45 -25
View File
@@ -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…",
+45 -25
View File
@@ -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…",
+45 -25
View File
@@ -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…",
@@ -421,7 +421,7 @@
<string name="native_4441146b0fe1d5c6" formatted="false" tools:ignore="Typos,TypographyDashes,TypographyEllipsis">"screenshot"</string>
<string name="native_4481c2190a1b4bca" formatted="false" tools:ignore="Typos,TypographyDashes,TypographyEllipsis">"تعبير Cron، مثل 0 9 * * *"</string>
<string name="native_4499e7b7e1c9ddbc" formatted="false" tools:ignore="Typos,TypographyDashes,TypographyEllipsis">"العودة إلى الصوت"</string>
<string name="native_449f5a775762cdc5" formatted="false" tools:ignore="Typos,TypographyDashes,TypographyEllipsis">"تحدث"</string>
<string name="native_449f5a775762cdc5" formatted="false" tools:ignore="Typos,TypographyDashes,TypographyEllipsis">"تحدّث"</string>
<string name="native_45a64dc17588f2ca" tools:ignore="Typos,TypographyDashes,TypographyEllipsis">"%1$s/%2$s متصلة"</string>
<string name="native_45a8847c4a6b2c81" tools:ignore="Typos,TypographyDashes,TypographyEllipsis">"يُسمح لـ %1$s تطبيقات بإعادة التوجيه."</string>
<string name="native_460b3a7da007b7af" formatted="false" tools:ignore="Typos,TypographyDashes,TypographyEllipsis">"الدردشة"</string>
@@ -421,7 +421,7 @@
<string name="native_4441146b0fe1d5c6" formatted="false" tools:ignore="Typos,TypographyDashes,TypographyEllipsis">"screenshot"</string>
<string name="native_4481c2190a1b4bca" formatted="false" tools:ignore="Typos,TypographyDashes,TypographyEllipsis">"عبارت cron، مثلاً 0 9 * * *"</string>
<string name="native_4499e7b7e1c9ddbc" formatted="false" tools:ignore="Typos,TypographyDashes,TypographyEllipsis">"بازگشت به صدا"</string>
<string name="native_449f5a775762cdc5" formatted="false" tools:ignore="Typos,TypographyDashes,TypographyEllipsis">"گفتگو"</string>
<string name="native_449f5a775762cdc5" formatted="false" tools:ignore="Typos,TypographyDashes,TypographyEllipsis">"صحبت"</string>
<string name="native_45a64dc17588f2ca" tools:ignore="Typos,TypographyDashes,TypographyEllipsis">"%1$s/%2$s آنلاین"</string>
<string name="native_45a8847c4a6b2c81" tools:ignore="Typos,TypographyDashes,TypographyEllipsis">"%1$s برنامه مجاز به بازارسال."</string>
<string name="native_460b3a7da007b7af" formatted="false" tools:ignore="Typos,TypographyDashes,TypographyEllipsis">"گفت‌وگو"</string>
@@ -1204,7 +1204,7 @@
<string name="native_ca1fd4548524cb2e" formatted="false" tools:ignore="Typos,TypographyDashes,TypographyEllipsis">"Folder kosong"</string>
<string name="native_ca7981b46ecf2c17" formatted="false" tools:ignore="Typos,TypographyDashes,TypographyEllipsis">"Nonaktif"</string>
<string name="native_cab94aba84f97f7f" formatted="false" tools:ignore="Typos,TypographyDashes,TypographyEllipsis">"Tipografi"</string>
<string name="native_cae7d57bc067a514" formatted="false" tools:ignore="Typos,TypographyDashes,TypographyEllipsis">"Hentikan"</string>
<string name="native_cae7d57bc067a514" formatted="false" tools:ignore="Typos,TypographyDashes,TypographyEllipsis">"Berhenti"</string>
<string name="native_cae98462b30650eb" formatted="false" tools:ignore="Typos,TypographyDashes,TypographyEllipsis">"Belum ada utas yang cocok."</string>
<string name="native_cba62d81f910c7f0" formatted="false" tools:ignore="Typos,TypographyDashes,TypographyEllipsis">"Pemasangan Gateway berhasil.\nSetujui kapabilitas node ponsel ini dari UI operator."</string>
<string name="native_cc4b66e7e22230c3" formatted="false" tools:ignore="Typos,TypographyDashes,TypographyEllipsis">"Skill ini sudah terinstal, tetapi saat ini belum memenuhi syarat untuk dijalankan. Gunakan desktop atau CLI untuk mengubah konfigurasi."</string>
@@ -421,7 +421,7 @@
<string name="native_4441146b0fe1d5c6" formatted="false" tools:ignore="Typos,TypographyDashes,TypographyEllipsis">"screenshot"</string>
<string name="native_4481c2190a1b4bca" formatted="false" tools:ignore="Typos,TypographyDashes,TypographyEllipsis">"Wyrażenie cron, np. 0 9 * * *"</string>
<string name="native_4499e7b7e1c9ddbc" formatted="false" tools:ignore="Typos,TypographyDashes,TypographyEllipsis">"Powrót do głosu"</string>
<string name="native_449f5a775762cdc5" formatted="false" tools:ignore="Typos,TypographyDashes,TypographyEllipsis">"Rozmawiaj"</string>
<string name="native_449f5a775762cdc5" formatted="false" tools:ignore="Typos,TypographyDashes,TypographyEllipsis">"Mów"</string>
<string name="native_45a64dc17588f2ca" tools:ignore="Typos,TypographyDashes,TypographyEllipsis">"%1$s/%2$s online"</string>
<string name="native_45a8847c4a6b2c81" tools:ignore="Typos,TypographyDashes,TypographyEllipsis">"Zezwolono %1$s aplikacjom na przekazywanie."</string>
<string name="native_460b3a7da007b7af" formatted="false" tools:ignore="Typos,TypographyDashes,TypographyEllipsis">"Czat"</string>
@@ -421,7 +421,7 @@
<string name="native_4441146b0fe1d5c6" formatted="false" tools:ignore="Typos,TypographyDashes,TypographyEllipsis">"screenshot"</string>
<string name="native_4481c2190a1b4bca" formatted="false" tools:ignore="Typos,TypographyDashes,TypographyEllipsis">"Cron-выражение, например 0 9 * * *"</string>
<string name="native_4499e7b7e1c9ddbc" formatted="false" tools:ignore="Typos,TypographyDashes,TypographyEllipsis">"Вернуться к голосу"</string>
<string name="native_449f5a775762cdc5" formatted="false" tools:ignore="Typos,TypographyDashes,TypographyEllipsis">"Разговор"</string>
<string name="native_449f5a775762cdc5" formatted="false" tools:ignore="Typos,TypographyDashes,TypographyEllipsis">"Говорить"</string>
<string name="native_45a64dc17588f2ca" tools:ignore="Typos,TypographyDashes,TypographyEllipsis">"В сети: %1$s/%2$s"</string>
<string name="native_45a8847c4a6b2c81" tools:ignore="Typos,TypographyDashes,TypographyEllipsis">"Разрешена переадресация для %1$s приложений."</string>
<string name="native_460b3a7da007b7af" formatted="false" tools:ignore="Typos,TypographyDashes,TypographyEllipsis">"Чат"</string>
@@ -421,7 +421,7 @@
<string name="native_4441146b0fe1d5c6" formatted="false" tools:ignore="Typos,TypographyDashes,TypographyEllipsis">"screenshot"</string>
<string name="native_4481c2190a1b4bca" formatted="false" tools:ignore="Typos,TypographyDashes,TypographyEllipsis">"นิพจน์ cron เช่น 0 9 * * *"</string>
<string name="native_4499e7b7e1c9ddbc" formatted="false" tools:ignore="Typos,TypographyDashes,TypographyEllipsis">"กลับไปที่เสียง"</string>
<string name="native_449f5a775762cdc5" formatted="false" tools:ignore="Typos,TypographyDashes,TypographyEllipsis">"พูดคุย"</string>
<string name="native_449f5a775762cdc5" formatted="false" tools:ignore="Typos,TypographyDashes,TypographyEllipsis">"พูด"</string>
<string name="native_45a64dc17588f2ca" tools:ignore="Typos,TypographyDashes,TypographyEllipsis">"ออนไลน์ %1$s/%2$s"</string>
<string name="native_45a8847c4a6b2c81" tools:ignore="Typos,TypographyDashes,TypographyEllipsis">"อนุญาตให้ส่งต่อ %1$s แอป"</string>
<string name="native_460b3a7da007b7af" formatted="false" tools:ignore="Typos,TypographyDashes,TypographyEllipsis">"แชท"</string>
@@ -421,7 +421,7 @@
<string name="native_4441146b0fe1d5c6" formatted="false" tools:ignore="Typos,TypographyDashes,TypographyEllipsis">"screenshot"</string>
<string name="native_4481c2190a1b4bca" formatted="false" tools:ignore="Typos,TypographyDashes,TypographyEllipsis">"Biểu thức cron, ví dụ 0 9 * * *"</string>
<string name="native_4499e7b7e1c9ddbc" formatted="false" tools:ignore="Typos,TypographyDashes,TypographyEllipsis">"Quay lại giọng nói"</string>
<string name="native_449f5a775762cdc5" formatted="false" tools:ignore="Typos,TypographyDashes,TypographyEllipsis">"Nói chuyện"</string>
<string name="native_449f5a775762cdc5" formatted="false" tools:ignore="Typos,TypographyDashes,TypographyEllipsis">"Nói"</string>
<string name="native_45a64dc17588f2ca" tools:ignore="Typos,TypographyDashes,TypographyEllipsis">"%1$s/%2$s đang trực tuyến"</string>
<string name="native_45a8847c4a6b2c81" tools:ignore="Typos,TypographyDashes,TypographyEllipsis">"%1$s ứng dụng được phép chuyển tiếp."</string>
<string name="native_460b3a7da007b7af" formatted="false" tools:ignore="Typos,TypographyDashes,TypographyEllipsis">"Trò chuyện"</string>
+408
View File
@@ -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": {
+15 -4
View File
@@ -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)
+23
View File
@@ -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,
+27 -2
View File
@@ -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
}
@@ -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 {
+40 -4
View File
@@ -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
@@ -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)
}
}
+32 -8
View File
@@ -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()
}
@@ -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<Task<Void, Never>?>,
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<Task<Void, Never>?>,
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)
}
}
}
@@ -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
@@ -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
}
}
@@ -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)
}
}