feat: UX polish, localization, advert relocation, and map filter fixes

- i18n: translate connection screen + chat tab keys into 13 locales;
  add "Send my contact" (advert) strings in all locales
- feat: move self-advert from home header into composer "+" action menu
  (new lib/utils/advert_helper.dart, always shows Flood/Direct sheet)
- fix: hide-repeaters map toggle was bypassed in simple mode
- fix: simple mode map now shows only favourite chat contacts
- fix: wrap ListTiles in Material (contact_tile secondary actions,
  inferred contact group card) to satisfy Flutter ink assertions
- device-authoritative contact/channel sync and UX review fixes

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Janez T
2026-06-12 10:01:10 +02:00
parent 3e1113035d
commit ba27843166
62 changed files with 12546 additions and 2521 deletions

View File

@@ -2493,5 +2493,125 @@
"enterRegionName": "区域名称(例如 auckland",
"noRegionsFound": "此中继器上未找到区域。",
"regionScopeSet": "区域范围已设置为 {name}",
"regionScopeCleared": "区域范围已清除"
"regionScopeCleared": "区域范围已清除",
"simpleMode": "简单模式",
"simpleModeDescription": "仅与收藏联系人聊天和查看地图",
"simpleModeRequiresLockedDestination": "请先启用“锁定目的地”并选择一个频道,再使用简单模式",
"noFavouriteContacts": "暂无收藏联系人",
"selectDestinationFirst": "请先选择频道、联系人或房间",
"recipientNoLongerAvailable": "收件人已不可用",
"failedToSendMessage": "发送失败:{error}",
"tictactoeDirectOnly": "井字棋仅适用于私聊消息。请先选择联系人。",
"deviceKeyUnavailable": "设备密钥不可用",
"imageCompressionFailed": "图片压缩失败",
"imageFragmentationFailed": "图片分片失败",
"failedToAnnounceImage": "图片通告失败",
"noRecipientSelected": "未选择收件人",
"imageSendFailed": "图片发送失败",
"microphonePermissionRequiredForVoice": "语音消息需要麦克风权限",
"recordingDiscarded": "已丢弃录音",
"publicChannelMediaWarning": "您即将向公共频道发送{mediaType}。不建议这样做,因为 mesh 网络中的所有人都可能收到。除非确有需要,请选择私有或带标签的频道。",
"selectPrivateChannelToShareLocation": "请选择私有频道来分享您的位置。",
"stopSharingMyLocation": "停止分享我的位置",
"shareMyLocation": "分享我的位置",
"stopRecording": "停止录音",
"recordVoice": "录制语音",
"moreActions": "更多操作",
"noMessagesInFilter": "此筛选条件下没有消息",
"noMatchesInFilter": "此筛选条件下没有匹配项",
"syncFailed": "同步失败:{error}",
"invalidLink": "无效链接",
"cannotOpenLink": "无法打开链接",
"failedToOpenLink": "打开链接失败",
"failedToResendMessage": "重新发送消息失败",
"retryFailed": "重试失败:{error}",
"deleteDrawingAndMessage": "删除绘图和消息",
"lastEchoRelay": "最后回声:中继",
"lastEchoPath": "最后回声:路径",
"lastEchoBytesReport": "最后回声:字节报告",
"noGpsCoordinatesAvailable": "没有可用的 GPS 坐标",
"notASarMarker": "不是搜救标记",
"failedToSaveTemplate": "保存模板失败:{error}",
"drawingNotFound": "未找到绘图",
"unknownDrawingType": "未知绘图类型",
"customMapMarker": "自定义地图标记",
"customMapPointLabel": "坐标点:{point}",
"mapIdLabel": "地图 ID{id}",
"cannotFetchVoice": "无法获取语音",
"senderContactUnknown": "发送者联系人未知。请先同步联系人。",
"senderRouteUnknown": "发送者路由未知。请先同步联系人/路径。",
"messageTooFar": "消息距离过远({hops} 跳,最多 {maxHops} 跳)。",
"senderRouteNoPathResponse": "发送者路由未响应路径检测。请同步联系人/路径后重试。",
"senderRouteNoRawResponse": "发送者路由在原始传输路径上未响应。",
"voiceFetchOverHops": "通过 {hops} 跳获取语音可能需要一些时间。",
"voiceReceiveCanceled": "已取消接收语音",
"fetchingMissingVoiceFragments": "正在获取缺失的语音分片",
"receivingVoice": "正在接收语音",
"cannotFetchImage": "无法获取图片",
"imageFetchOverHops": "通过 {hops} 跳获取图片可能需要一些时间。",
"imageAlreadyBeingReceived": "图片正在接收中",
"loadImage": "加载图片",
"imageFetchFailedToSendRequest": "图片获取请求发送失败",
"imageUnavailable": "图片暂时不可用",
"imageFetchTimedOut": "图片获取超时",
"imageReceiveCanceled": "已取消接收图片",
"closeImagePreview": "关闭图片预览",
"recordingReleaseToSend": "正在录音……松开发送",
"sendingVoice": "正在发送语音……",
"sendLongPressToRecordVoice": "发送(长按录制语音)",
"discardRecording": "丢弃录音",
"hopCount": "{count, plural, other{{count} 跳}}",
"channelsSectionDescription": "用于附近 mesh 通信的广播频道",
"roomsSectionDescription": "用于团队持续协调的共享空间",
"contactsSectionDescription": "可直接联系的人员和设备",
"noRecentChatters": "最近没有人发言",
"public": "公共",
"failedToSendTicTacToeMove": "井字棋走子发送失败",
"youWon": "您赢了",
"opponentWon": "对手赢了",
"gameDraw": "平局",
"yourTurn": "轮到您",
"opponentTurn": "轮到对手",
"pleaseEnterValidCoordinates": "请输入有效坐标",
"locationNotAvailable": "位置不可用",
"customCaveMapPoint": "自定义洞穴地图点",
"mapPoint": "地图点",
"fetchingMissingImageFragments": "正在获取缺失分片……",
"loadingImage": "加载中……",
"receivingImage": "接收中……",
"tapToLoad": "点按加载",
"connectDevice": "连接设备",
"chooseTransportSubtitle": "选择 Bluetooth、WiFi 或串口传输",
"ble": "BLE",
"network": "网络",
"serial": "串口",
"scan": "扫描",
"pressScanToSearchForDevices": "点按扫描以搜索附近设备",
"failedToConnectToDevice": "连接 {name} 失败",
"unknownDevice": "未知设备",
"showingCachedResultsTapRefresh": "正在显示缓存结果。点按刷新以重新扫描。",
"scanningLocalNetworkOnPort": "正在扫描本地网络中端口 {port} 上的 MeshCore WiFi 设备",
"cancelScanAndAddServer": "取消扫描并添加服务器",
"addServer": "添加服务器",
"scanningProgressIps": "正在扫描……{scanned}/{total} 个 IP",
"cancelAndEnterManually": "取消并手动输入",
"noRecentOrDiscoveredServers": "暂无最近使用或发现的服务器",
"recentlyUsed": "最近使用",
"connecting": "正在连接……",
"discoveredOnThisNetwork": "在此网络中发现",
"serverNoLongerAvailable": "{host}:{port} 上的服务器已不可用。请重新扫描以查找活跃的服务器。",
"failedToConnectToHost": "连接 {host}:{port} 失败",
"enterValidIpAddress": "请输入有效的 IP 地址",
"enterValidTcpPort": "请输入有效的 TCP 端口",
"ipAddress": "IP 地址",
"tcpPort": "TCP 端口",
"customServerPort": "自定义服务器端口",
"chat": "聊天",
"restoringPreviousLink": "正在恢复先前的连接",
"noDeviceConnected": "未连接设备",
"sendAdvert": "发送我的联系人信息",
"advertMode": "发送我的联系人信息",
"advertModeSubtitle": "选择您的联系人信息应传播多远。",
"floodAdvertSent": "联系人信息已发送至整个 mesh 网络",
"directAdvertSent": "联系人信息已发送至附近设备"
}