#!/usr/bin/env python3 # -*- coding: utf-8 -*- """Update LoopFollow/Resources/Localizable.xcstrings from a zh-Hans dict. Keys must match the exact source literal so SwiftUI auto-localizes. Existing catalog entries are preserved so Xcode-extracted source strings, plural variants, comments, and other languages are not discarded. """ import json, collections, os APP = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))), "LoopFollow") OUT = os.path.join(APP, "Resources", "Localizable.xcstrings") # English source -> 简体中文. Terminology aligned with Trio-Diy glossary. T = collections.OrderedDict() def add(pairs): for en, zh in pairs: T[en] = zh # ---- 通用按钮/操作 ---- add([ ("OK", "好"), ("Cancel", "取消"), ("Save", "保存"), ("Done", "完成"), ("Close", "关闭"), ("Delete", "删除"), ("Confirm", "确认"), ("Continue", "继续"), ("Send", "发送"), ("Share", "分享"), ("Export", "导出"), ("Refresh", "刷新"), ("Enact", "执行"), ("Load More", "加载更多"), ("Enabled", "已启用"), ("Active", "启用"), ("Inactive", "未启用"), ("Connected", "已连接"), ("Disconnect", "断开连接"), ("Snoozed", "已暂停"), ("Off", "关闭"), ("All", "全部"), ("Custom", "自定义"), ("Always", "始终"), ("None", "无"), ("Yes, send anonymous stats", "是,发送匿名统计"), ("No thanks", "不用了"), ("Opt out", "退出"), ("Use Anyway", "仍然使用"), ("Run diagnostics", "运行诊断"), ("Run diagnostics again", "重新运行诊断"), ("Copy JSON", "复制 JSON"), ("See exactly what's sent", "查看具体发送内容"), ]) # ---- 顶层/导航/分区标题 ---- add([ ("Settings", "设置"), ("App Settings", "应用设置"), ("General", "通用"), ("General Settings", "通用设置"), ("Advanced Settings", "高级设置"), ("Display", "显示"), ("Display Settings", "显示设置"), ("Features", "功能"), ("Integrations", "集成"), ("Security", "安全"), ("Privacy", "隐私"), ("Diagnostics", "诊断"), ("Logging", "日志"), ("Logging Options", "日志选项"), ("Appearance", "外观"), ("Home", "首页"), ("Menu", "菜单"), ("In Menu", "在菜单中"), ("History", "历史"), ("Statistics", "统计"), ("Status", "状态"), ("Category", "类别"), ("Description", "说明"), ("Additional Information", "附加信息"), ("Build Information", "构建信息"), ("User Information", "用户信息"), ("Information Display Settings", "信息展示设置"), ("Data Settings", "数据设置"), ("Data Availability", "数据可用性"), ("Device Data", "设备数据"), ("Meal Data", "餐食数据"), ("Source", "来源"), ("Server", "服务器"), ("Endpoint", "端点"), ("Environment", "环境"), ("Frequency", "频率"), ("Filter", "筛选"), ("Range", "范围"), ("Range Mode", "范围模式"), ("Duration", "持续时间"), ("Time", "时间"), ("Time Zone", "时区"), ("Time Zone Override", "自定义时区"), ("Schedule", "计划"), ("Name", "名称"), ("Preset Name", "预设名称"), ("Presets", "预设"), ("Increment", "步进"), ("Minimum", "最小值"), ("Maximum", "最大值"), ("Min", "最小"), ("Max", "最大"), ("Metric", "指标"), ("Guardrails", "安全护栏"), ]) # ---- 血糖/单位/指标 ---- add([ ("Glucose", "血糖"), ("Glucose Unit", "血糖单位"), ("Glucose value", "血糖值"), ("Glycemic Metrics", "血糖指标"), ("Units and Metrics", "单位与指标"), ("Output Unit", "输出单位"), ("Set Up Units", "设置单位"), ("Variability", "变异性"), ("Std Dev", "标准差"), ("Delta", "变化值"), ("Trend", "趋势"), ("Eventual", "预计血糖"), ("Target", "目标"), ("Target Range", "目标范围"), ("Current Target", "当前目标"), ("Sensitivity", "敏感度"), ("Prediction", "预测"), ("Prediction Style", "预测样式"), ("Download Prediction", "下载预测"), ("Ambulatory Glucose Profile (AGP)", "动态血糖图谱(AGP)"), ("GRI (Glucose Risk Index)", "GRI(血糖风险指数)"), ("Hyperglycemia Component (%)", "高血糖分量(%)"), ("Hypoglycemia Component (%)", "低血糖分量(%)"), ("High", "高"), ("Low", "低"), ("Proactive Low", "低血糖预警"), ("Recommended Bolus", "推荐大剂量"), ("Insulin Totals", "胰岛素总量"), ]) # ---- 治疗/餐食/胰岛素 ---- add([ ("Bolus", "大剂量"), ("Bolus Filter", "大剂量筛选"), ("Bolus Increment", "大剂量步进"), ("Carbs", "碳水"), ("Insulin", "胰岛素"), ("Meal", "餐食"), ("Meal Settings", "餐食设置"), ("Meal with Bolus", "带大剂量的餐食"), ("Meal with Fat/Protein", "带脂肪/蛋白质的餐食"), ("Treatments", "治疗"), ("No recent treatments", "暂无近期治疗"), ("Treatments on Small Graph", "小图上显示治疗"), ("Download Treatments", "下载治疗"), ("Tap to load older treatments", "点按加载更早的治疗"), ("Absorption Time", "吸收时间"), ("Consumption Time", "进食时间"), ("Food Type", "食物类型"), ("Max Bolus", "最大大剂量"), ("Max Carbs", "最大碳水"), ("Max Fat", "最大脂肪"), ("Max Protein", "最大蛋白质"), ("Confirm Bolus", "确认大剂量"), ("Confirm Carbs", "确认碳水"), ("Confirm Insulin", "确认胰岛素"), ("Confirm Meal", "确认餐食"), ("Confirm Command", "确认指令"), ("Confirm Cancellation", "确认取消"), ("Confirm & Import", "确认并导入"), ("Send Bolus", "发送大剂量"), ("Send Carbs", "发送碳水"), ("Send Insulin", "发送胰岛素"), ("Send Meal", "发送餐食"), ("Sending Bolus...", "正在发送大剂量…"), ("Sending Meal Data...", "正在发送餐食数据…"), ("Sending...", "正在发送…"), ("Note: The meal will be scheduled, but the bolus is enacted immediately.", "注意:餐食将被计划安排,但大剂量会立即执行。"), ("Schedule for later", "计划稍后执行"), ("End now", "立即结束"), ("End Date", "结束日期"), ("Start Date", "开始日期"), ]) # ---- Override / Temp Target(对齐 Trio:临时配置 / 临时目标)---- add([ ("Override", "临时配置"), ("Overrides", "临时配置"), ("Remote Overrides", "远程临时配置"), ("Available Overrides", "可用的临时配置"), ("Activate Override", "启用临时配置"), ("Active Override", "启用中的临时配置"), ("Cancel Override", "取消临时配置"), ("Cancel Active Override", "取消当前临时配置"), ("No overrides available.", "暂无可用的临时配置。"), ("No override presets found. Configure presets in your Loop app.", "未找到临时配置预设。请在 Loop 应用中配置预设。"), ("Loading override presets...", "正在加载临时配置预设…"), ("Are you sure you want to cancel the active override?", "确定要取消当前临时配置吗?"), ("Temporary Target", "临时目标"), ("Existing Temp Target", "现有临时目标"), ("Cancel Temp Target", "取消临时目标"), ("Are you sure you want to cancel the existing temp target?", "确定要取消现有的临时目标吗?"), ("Active During", "生效时段"), ("Enable indefinitely", "无限期启用"), ]) # ---- 闹钟/提醒 ---- add([ ("Alarms", "闹钟"), ("Add Alarm", "添加闹钟"), ("Alarm Name", "闹钟名称"), ("Alarm Settings", "闹钟设置"), ("Alarm not found", "未找到闹钟"), ("Delete Alarm", "删除闹钟"), ("Delete this alarm?", "删除此闹钟?"), ("Alert Sound", "提示音"), ("Choose Tone", "选择铃声"), ("Tone", "铃声"), ("Unknown Alert", "未知提醒"), ("Old Calculation Warning", "旧计算结果警告"), ("Delay Between Sounds", "声音间隔"), ("Persistent Notification", "持续通知"), ("Snooze all · 1h", "全部暂停 · 1 小时"), ("Snooze for", "暂停时长"), ("Snooze Time", "暂停时间"), ("Snooze Date", "暂停日期"), ("Default Snooze:", "默认暂停时长:"), ("Snooze & Mute Options", "暂停与静音选项"), ("All Alerts Snoozed", "所有提醒已暂停"), ("All alerts snoozed", "所有提醒已暂停"), ("All Sounds Muted", "所有声音已静音"), ("SNOOZE", "暂停"), ("Snoozer emoji", "暂停页表情"), ("Give each alarm a unique name—especially if you’ve added more than one of the same kind—so you can tell them apart at a glance.", "给每个闹钟起一个独特的名字——尤其是当你添加了多个同类型闹钟时——这样一眼就能区分它们。"), ("Adding this alarm would exceed the QR code character limit. Please remove some alarms first.", "添加此闹钟会超出二维码字符上限。请先删除部分闹钟。"), ("Select Alarms to Export", "选择要导出的闹钟"), ("Character Limit Reached", "已达字符上限"), ]) # ---- Nightscout / Dexcom / 数据源 ---- add([ ("Nightscout Settings", "Nightscout 设置"), ("Nightscout URL", "Nightscout 网址"), ("Dexcom Settings", "Dexcom 设置"), ("Please enter your Nightscout URL in Settings.", "请在设置中输入你的 Nightscout 网址。"), ("Checking Nightscout profile history…", "正在检查 Nightscout 配置文件历史…"), ("Multiple devices uploading profiles", "多台设备正在上传配置文件"), ("Expected: 1 CGM reading every 5 minutes", "预期:每 5 分钟 1 次 CGM 读数"), ("No data available", "暂无数据"), ("No devices found yet. They'll appear here when discovered.", "尚未发现设备。发现后将显示在这里。"), ("No issues detected", "未检测到问题"), ("Selected Device", "已选设备"), ("Selected Device", "已选设备"), ("Access Token", "访问令牌"), ("Token", "令牌"), ("URL", "网址"), ("Enter URL", "输入网址"), ("Enter User", "输入用户"), ("Enter User Name", "输入用户名"), ("User", "用户"), ("User Name", "用户名"), ("Password", "密码"), ("Shared Secret", "共享密钥"), ("Calendar access denied", "日历访问被拒绝"), ]) # ---- 远程控制 / APNS ---- add([ ("Remote", "远程"), ("Remote Settings", "远程设置"), ("Loop Remote Control", "Loop 远程控制"), ("Trio Remote Control", "Trio 远程控制"), ("Trio Remote Control Settings", "Trio 远程控制设置"), ("Trio Remote Control is only supported for 'Trio'", "Trio 远程控制仅支持「Trio」"), ("Loop APNS Configuration", "Loop APNS 配置"), ("Loop APNS Not Configured", "Loop APNS 未配置"), ("Configure Loop APNS", "配置 Loop APNS"), ("LoopFollow APNs Credentials", "LoopFollow APNs 凭据"), ("APNS Key", "APNS 密钥"), ("APNS Key ID", "APNS 密钥 ID"), ("Developer Team ID", "开发者团队 ID"), ("Key ID must be exactly 10 uppercase letters or digits.", "密钥 ID 必须正好是 10 位大写字母或数字。"), ("Paste the full .p8 contents — must include the BEGIN PRIVATE KEY and END PRIVATE KEY lines.", "粘贴完整的 .p8 内容——必须包含 BEGIN PRIVATE KEY 与 END PRIVATE KEY 两行。"), ("Please configure Loop APNS settings in Remote Settings to use APNS commands.", "请在远程设置中配置 Loop APNS,方可使用 APNS 指令。"), ("Please select a Remote Type in Settings.", "请在设置中选择远程类型。"), ("Current OTP Code", "当前 OTP 验证码"), ("TOTP Code Already Used", "TOTP 验证码已使用"), ("This TOTP code has already been used for a command. Please wait for the next code to be generated before sending another command.", "此 TOTP 验证码已用于某条指令。请等待生成下一个验证码后再发送新指令。"), ("Production", "生产环境"), ("Production is used for browser builders and should be switched off for Xcode builders", "生产环境用于浏览器打包,Xcode 打包时应关闭"), ]) # ---- 显示/图表/外观 ---- add([ ("Display App Badge", "显示应用角标"), ("Display Dots", "显示圆点"), ("Display Lines", "显示连线"), ("Display Small Graph", "显示小图"), ("Display Stats", "显示统计"), ("Small Graph", "小图"), ("Graph Display", "图表显示"), ("Graph Settings", "图表设置"), ("Graph Basal", "图表显示基础率"), ("Graph Bolus", "图表显示大剂量"), ("Graph Carbs", "图表显示碳水"), ("Graph Other Treatments", "图表显示其他治疗"), ("Show Carb Absorption", "显示碳水吸收"), ("Show Carb/Bolus Values", "显示碳水/大剂量数值"), ("Show DIA Lines", "显示 DIA 线"), ("Show Delta", "显示变化值"), ("Show Display Name", "显示名称"), ("Show IOB", "显示 IOB"), ("Show Midnight Lines", "显示午夜分隔线"), ("Show Trend", "显示趋势"), ("Show Yesterday's BG", "显示昨日血糖"), ("Show −30 min Line", "显示 −30 分钟线"), ("Show −90 min Line", "显示 −90 分钟线"), ("Hide Information Table", "隐藏信息表"), ("Include Delta in", "在以下项包含变化值"), ("Include IOB in", "在以下项包含 IOB"), ("Include Trend in", "在以下项包含趋势"), ("Color BG Text", "血糖文字着色"), ("Color Mode", "颜色模式"), ("Color Options", "颜色选项"), ("Text Color", "文字颜色"), ("Background Color", "背景颜色"), ("Basal / BG Scale", "基础率 / 血糖比例"), ("Line 1", "第 1 行"), ("Line 2", "第 2 行"), ("Right slot", "右侧栏位"), ("Grid Slot - CarPlay / Watch", "网格栏位 - CarPlay / 手表"), ("Grid Slots - Live Activity", "网格栏位 - 实时活动"), ("Calendar Text", "日历文本"), ("Force portrait mode", "强制竖屏"), ("Keep Screen Active", "保持屏幕常亮"), ("Speak BG", "朗读血糖"), ("Save BG to Calendar", "保存血糖到日历"), ("Drag to reorder", "拖动可重新排序"), ("Dynamic mode colors text based on BG range: Green (in range), Yellow (high), Red (low)", "动态模式会按血糖范围为文字着色:绿色(范围内)、黄色(偏高)、红色(偏低)。"), ("Select the colors for your BG values. Note: not all watch faces allow control over colors. Recommend options like Activity or Modular Duo if you want to customize colors.", "选择血糖数值的颜色。注意:并非所有表盘都支持自定义颜色。若想自定义颜色,推荐使用「活动」或「模块化双重」等表盘。"), ]) # ---- Live Activity / Contact / Calendar ---- add([ ("Live Activity", "实时活动"), ("Enable Live Activity", "启用实时活动"), ("Live Activity updates require APNs credentials. Configure them in Settings → APN.", "实时活动更新需要 APNs 凭据。请在「设置 → APN」中配置。"), ("Contact", "联系人"), ("Contact Integration", "联系人集成"), ("Enable Contact BG Updates", "启用联系人血糖更新"), ("Calendar", "日历"), ("Real-time Updates", "实时更新"), ("To see your trend, delta, or IOB, include them in another contact or create separate contacts. When using 'Include', select which contact to add the value to.", "若想查看趋势、变化值或 IOB,请把它们加入另一个联系人,或分别创建联系人。使用「包含」时,选择要将数值添加到哪个联系人。"), ]) # ---- 后台刷新 ---- add([ ("Background Refresh Settings", "后台刷新设置"), ("Background Refresh Type", "后台刷新方式"), ("Adjust the background refresh type.", "调整后台刷新方式。"), ("No background refresh. Alarms and updates will not work unless the app is open in the foreground.", "不进行后台刷新。除非应用在前台打开,否则闹钟和更新都不会生效。"), ("A silent tune will play in the background, keeping the app active. May be interrupted by other apps. Allows continuous updates but consumes more battery.", "后台会播放一段静音音频以保持应用活跃。可能被其他应用打断。可持续更新,但更耗电。"), ("Requires a Dexcom G6/ONE/G7/ONE+ transmitter within Bluetooth range. Provides updates every 5 minutes and uses less battery than the silent tune method. If you have more than one device to choose from, select the one with the smallest expected bg delay.", "需要蓝牙范围内有 Dexcom G6/ONE/G7/ONE+ 发射器。每 5 分钟更新一次,比静音音频方式更省电。如果有多个设备可选,请选择预计血糖延迟最小的那个。"), ("Requires a RileyLink-compatible device within Bluetooth range. Provides updates once per minute and uses less battery than the silent tune method.", "需要蓝牙范围内有兼容 RileyLink 的设备。每分钟更新一次,比静音音频方式更省电。"), ("Requires an OmniPod DASH pod paired with this device within Bluetooth range. Provides updates once every 3 minutes and uses less battery than the silent tune method.", "需要蓝牙范围内有与本设备配对的 OmniPod DASH Pod。每 3 分钟更新一次,比静音音频方式更省电。"), ]) # ---- 导入/导出/二维码 ---- add([ ("Import Settings", "导入设置"), ("Import Settings from QR Code", "从二维码导入设置"), ("Import/Export Settings", "导入/导出设置"), ("Export Settings To QR Code", "将设置导出为二维码"), ("Settings to Import", "待导入的设置"), ("Review the settings that will be imported", "查看将要导入的设置"), ("This will overwrite your current settings", "这将覆盖你当前的设置"), ("Scan QR Code from Loop App", "从 Loop 应用扫描二维码"), ("Scan QR Code to Import Settings", "扫描二维码以导入设置"), ("Enter QR code URL or scan from Loop app", "输入二维码网址,或从 Loop 应用扫描"), ("QR Code URL", "二维码网址"), ("Invalid QR code URL", "无效的二维码网址"), ("Failed to generate QR code", "生成二维码失败"), ]) # ---- 诊断/遥测/隐私 ---- add([ ("What is sent", "发送了什么"), ("What's sent", "发送内容"), ("What stays on your device", "留在你设备上的内容"), ("Send anonymous usage stats", "发送匿名使用统计"), ("Help us help you!", "帮助我们更好地帮助你!"), ("Share Logs", "分享日志"), ("View Log", "查看日志"), ("Today's Logs", "今日日志"), ("Debug Log Level", "调试日志级别"), ("Debug / Info", "调试 / 信息"), ("You can change this any time in Settings → Diagnostics.", "你可以随时在「设置 → 诊断」中更改此项。"), ("Once a day (or after a new build), the app sends a small JSON object to https://lf.bjorkert.se. The endpoint is self-hosted by the maintainer; no third-party analytics service is involved.", "每天一次(或在有新构建后),应用会向 https://lf.bjorkert.se 发送一个小的 JSON 对象。该端点由维护者自行托管,不涉及任何第三方分析服务。"), ("Use the Send anonymous usage stats toggle above. Turning it off is immediate and persistent.", "使用上方的「发送匿名使用统计」开关。关闭后立即生效并长期保持。"), ]) # ---- 语言名 ---- add([ ("Language", "语言"), ("English", "英语"), ("French", "法语"), ("Italian", "意大利语"), ("Slovak", "斯洛伐克语"), ("Swedish", "瑞典语"), ]) # ---- 杂项/状态提示 ---- add([ ("Error", "错误"), ("Warning", "警告"), ("Success", "成功"), ("Validation Error", "校验错误"), ("Reconnecting...", "正在重新连接…"), ("Loading stats...", "正在加载统计…"), ("...because the data could not be loaded", "…因为数据无法加载"), ("Note", "备注"), ("Enable WebSocket", "启用 WebSocket"), ("Enter QR code URL or scan from Loop app", "输入二维码网址,或从 Loop 应用扫描"), ("Support & Community", "支持与社区"), ("Tab Order", "标签顺序"), ("Tabs", "标签"), ("The top 4 items appear in the tab bar. The Menu can always open every feature.", "前 4 项会显示在标签栏中。「菜单」始终可以打开所有功能。"), ("Day / Night Schedule", "白天 / 夜间时段"), ("Pick when your day period begins and when your night period begins. ", "选择你的白天时段与夜间时段各自的起始时间。"), ("The order of Fat and Protein inputs has changed.", "脂肪和蛋白质的输入顺序已更改。"), ("⚠️ Please enable at least one limit.", "⚠️ 请至少启用一个限制。"), ("Available Variables", "可用变量"), ("minutes", "分钟"), ("Minutes", "分钟"), ("Hours", "小时"), ]) # ---- 补充批次:TOTP/URL/Token 标签、预设、遥测披露长段 ---- add([ ("Current TOTP Code:", "当前 TOTP 验证码:"), ("Current OTP Code", "当前 OTP 验证码"), ("Current Token:", "当前令牌:"), ("Current URL:", "当前网址:"), ("Scanned Token:", "扫描到的令牌:"), ("Scanned URL:", "扫描到的网址:"), ("TOTP Code: Invalid QR code URL", "TOTP 验证码:无效的二维码网址"), ("URL/Token Update", "网址/令牌更新"), ("URL/Token Validation", "网址/令牌校验"), ("Save Preset", "保存预设"), ("Save as Preset", "存为预设"), ("Tab 5", "标签 5"), ("APNs credentials are missing or invalid — Live Activity updates will not work. Open Settings → APN to fix.", "APNs 凭据缺失或无效——实时活动将无法更新。请打开「设置 → APN」进行修复。"), ("Below is the exact JSON object that LoopFollow would send to lf.bjorkert.se right now.", "下面是 LoopFollow 此刻将发送到 lf.bjorkert.se 的确切 JSON 对象。"), ("Once every 24 hours, plus once after installing a new build. The check runs in the background while the app is active or refreshing in the background.", "每 24 小时一次,另加安装新构建后一次。检查会在应用活跃或后台刷新时于后台运行。"), ("Thanks for sharing these logs to help us find the problem. Please describe it in as much detail as possible — what time did it happen, what did you do, and what did you expect to happen that didn't?", "感谢你分享这些日志来帮助我们定位问题。请尽可能详细地描述——问题发生在什么时间、你当时做了什么、你原本期望发生什么却没有发生?"), ("You can choose to share anonymous information with the developers to help improve LoopFollow—such as app and iOS version, device type, which app you're following, and a few settings. Your health data, credentials, time zone, and logs remain on your device.", "你可以选择与开发者分享匿名信息来帮助改进 LoopFollow——例如应用与 iOS 版本、设备型号、你正在跟随的应用,以及少量设置项。你的健康数据、凭据、时区和日志都会保留在你的设备上。"), ("All glucose, insulin, and carb data. Your Nightscout URL and API token. Your Dexcom credentials. Remote-command secrets and APNS keys. Time zone. Location data. Logs — these are never sent automatically; the Settings → Logs sharing flow is unchanged and only triggered by you.", "所有血糖、胰岛素和碳水数据。你的 Nightscout 网址与 API 令牌。你的 Dexcom 凭据。远程指令密钥与 APNS 密钥。时区。位置数据。日志——这些绝不会自动发送;「设置 → 日志」的分享流程保持不变,且仅由你手动触发。"), ("App version, build date, whether this is a TestFlight build, the install instance number, an Apple-supplied per-vendor identifier (IDFV) that resets when all this developer's apps are removed from the device, the hardware identifier (e.g. iPhone15,2), and iOS version. Whether Nightscout and Dexcom are configured (yes/no — no URLs or usernames). Which app you're following (Loop, Trio, etc), if known. A small set of preference flags (units, appearance mode, calendar/contact integration enabled, remote-command type, background refresh method). The full JSON is visible under Diagnostics → What's sent.", "应用版本、构建日期、是否为 TestFlight 构建、安装实例编号、由 Apple 提供的按供应商标识符(IDFV,当本开发者的所有应用从设备移除后会重置)、硬件标识符(如 iPhone15,2)以及 iOS 版本。Nightscout 和 Dexcom 是否已配置(是/否——不含网址或用户名)。你正在跟随哪个应用(Loop、Trio 等,若已知)。以及一小组偏好标记(单位、外观模式、是否启用日历/联系人集成、远程指令类型、后台刷新方式)。完整 JSON 可在「诊断 → 发送内容」中查看。"), ]) # ---- UIKit / 本地通知(代码已用 String(localized:) 包裹)---- add([ ("Live Activity Expiring", "实时活动即将过期"), ("Live Activity will expire soon. Open LoopFollow to restart.", "实时活动即将过期。请打开 LoopFollow 以重新启动。"), ("Live Activity Setup Needed", "需要设置实时活动"), ("APNs credentials are missing or invalid. Configure them in Settings → APN.", "APNs 凭据缺失或无效。请在「设置 → APN」中配置。"), ("Live Activity Could Not Start", "实时活动无法启动"), ("Live Activity could not start — try again in a moment.", "实时活动无法启动——请稍后重试。"), ("Setup Nightscout", "设置 Nightscout"), ("Setup Dexcom Share", "设置 Dexcom Share"), ("Loading...", "正在加载…"), ("Scan QR Code", "扫描二维码"), ]) # ---- 高置信度插值文案(占位符 %lld=整数 / %@=字符串;如首次构建后 Xcode 抽取的 key 略有差异,会安全回退英文)---- add([ ("(%lld days)", "(%lld 天)"), ("Are you sure you want to send %@ U?", "确定要发送 %@ U 吗?"), ("Duration: %lld minutes", "持续时间:%lld 分钟"), ("Duration: %@", "持续时间:%@"), ("Selected Alarms: %lld", "已选闹钟:%lld"), ("Max %lld alarms at a time", "一次最多 %lld 个闹钟"), ("Scanning for %@...", "正在扫描 %@…"), ("Export %@", "导出 %@"), ("Disconnected for %@", "已断开连接 %@"), ("Last connection: %@", "上次连接:%@"), ("Tab %lld", "标签 %lld"), ("%lld gaps", "%lld 段缺口"), ("%lld of %lld expected readings", "预期 %2$lld 次读数中的 %1$lld 次"), ]) # ---- Alarm 模块:AlarmType 显示名(代码已用 localizedTitle 按 rawValue 查表)---- add([ ("Temporary Alert", "临时告警"), ("IOB Alert", "IOB 告警"), ("COB Alert", "COB 告警"), ("Low BG Alert", "低血糖告警"), ("High BG Alert", "高血糖告警"), ("Fast Drop Alert", "快速下降告警"), ("Fast Rise Alert", "快速上升告警"), ("Missed Reading Alert", "读数缺失告警"), ("Not Looping Alert", "未闭环告警"), ("Missed Bolus Alert", "漏打大剂量告警"), ("Future Carbs Alert", "待摄入碳水告警"), ("Sensor Change Alert", "传感器更换告警"), ("Pump Change Alert", "泵更换告警"), ("Pump Insulin Alert", "泵储药量告警"), ("Pump Battery Alert", "泵电量告警"), ("Low Battery", "电量过低"), ("Battery Drop", "电量骤降"), ("Rec. Bolus", "推荐剂量"), ("Override Started", "临时配置已开始"), ("Override Ended", "临时配置已结束"), ("Temp Target Started", "临时目标已开始"), ("Temp Target Ended", "临时目标已结束"), ("Looping app expiration", "闭环应用即将到期"), ]) # ---- Alarm 模块:blurb 说明(代码已用 String(localized:))---- add([ ("Alerts when BG goes below a limit.", "当血糖低于限值时提醒。"), ("Alerts when BG rises above a limit.", "当血糖高于限值时提醒。"), ("Rapid downward BG trend.", "血糖快速下降趋势。"), ("Rapid upward BG trend.", "血糖快速上升趋势。"), ("No CGM data for X minutes.", "已有 X 分钟无 CGM 数据。"), ("High insulin-on-board.", "活性胰岛素(IOB)偏高。"), ("High carbs-on-board.", "活性碳水(COB)偏高。"), ("Carbs without bolus.", "记录了碳水但未打大剂量。"), ("Reminder when future carbs are due.", "到了预定碳水时间时提醒。"), ("Recommended bolus issued.", "已给出推荐大剂量。"), ("Phone battery low.", "手机电量过低。"), ("Battery drops quickly.", "电量快速下降。"), ("Reservoir level low.", "储药器余量过低。"), ("Pump battery low.", "泵电量过低。"), ("Pump change due.", "到了更换泵的时间。"), ("Sensor change due.", "到了更换传感器的时间。"), ("Loop hasn’t completed.", "闭环未完成。"), ("Looping-app build expiring.", "闭环应用构建即将到期。"), ("Override just started.", "临时配置刚刚开始。"), ("Override ended.", "临时配置已结束。"), ("Temp target started.", "临时目标已开始。"), ("Temp target ended.", "临时目标已结束。"), ("One-time BG limit alert.", "一次性血糖限值告警。"), ]) # ---- Alarm 模块:白天/夜间选项 + 通知动作 ---- add([ ("Day & Night", "全天"), ("Day", "白天"), ("Night", "夜间"), ("Never", "从不"), ("Acknowledge", "知道了"), ("Snooze", "暂停"), ]) # ---- App 界面语言手动选择 + 外观 System/Light/Dark ---- add([ ("App Language", "应用语言"), ("Overrides the system language for this app. Restart the app to apply.", "覆盖本应用的系统语言。重启应用后生效。"), ("Restart Required", "需要重启"), ("Fully close and reopen LoopFollow for the language change to take effect.", "请完全关闭并重新打开 LoopFollow,语言更改才会生效。"), ("System", "系统"), ("Light", "浅色"), ("Dark", "深色"), ]) # ---- 校验补漏批次一:Tab 栏 / 设置菜单(代码已包 String(localized:) / LocalizedStringKey)---- add([ ("Tab 1", "标签 1"), ("Tab 2", "标签 2"), ("Tab 3", "标签 3"), ("Tab 4", "标签 4"), ("Snoozer", "暂停页"), ("Graph", "图表"), ("Information Display", "信息展示"), ("Background Refresh", "后台刷新"), ("Import/Export", "导入/导出"), ("Advanced", "高级"), ]) # ---- 校验补漏批次二:闹钟编辑器(AlarmStepperSection/BGPicker 等组件调用点)---- add([ ("Play", "播放"), ("Repeat", "重复"), ("Phone Battery Drop", "手机电量下降"), ("This alerts you if the phone battery drops by this much or more.", "当手机电量下降达到或超过此幅度时提醒你。"), ("Drop Amount", "下降幅度"), ("Over This Time", "检测时间范围"), ("How far back to look for that drop.", "向前回溯多长时间来检测该下降。"), ("Time Window", "时间窗口"), ("min", "分钟"), ("Notice Period", "提前通知期"), ("Choose how many days of notice you’d like before the build becomes unusable.", "选择在构建失效前,你希望提前多少天收到通知。"), ("Days of notice", "提前通知天数"), ("Carbs-on-Board Limit", "活性碳水(COB)上限"), ("Alert when Carbs-on-Board is at or above this number.", "当活性碳水达到或超过此数值时提醒。"), ("At or Above", "达到或高于"), ("Rate of Fall", "下降速率"), ("This is how much the glucose must drop to be considered a fast drop.", "血糖下降需达到此幅度才算快速下降。"), ("Falls by", "每次下降"), ("Consecutive Drops", "连续下降次数"), ("Number of drops—each meeting the rate above—required before an alert fires.", "触发提醒所需的下降次数(每次都需达到上述速率)。"), ("Number of Drops", "下降次数"), ("BG Limit", "血糖限值"), ("When enabled, this alert only fires if the glucose is below the limit you set.", "启用后,仅当血糖低于你设定的限值时才会触发此提醒。"), ("Use BG Limit", "使用血糖限值"), ("Dropping below", "降至低于"), ("Rate of Rise", "上升速率"), ("This is how much the glucose must rise to be considered a fast rise.", "血糖上升需达到此幅度才算快速上升。"), ("Rises by", "每次上升"), ("Consecutive Rises", "连续上升次数"), ("Number of rises—each meeting the rate above—required before an alert fires.", "触发提醒所需的上升次数(每次都需达到上述速率)。"), ("Rises in a row", "连续上升"), ("When enabled, this alert only fires if the glucose is above the limit you set.", "启用后,仅当血糖高于你设定的限值时才会触发此提醒。"), ("Rising above", "升至高于"), ("Max Lookahead", "最长预看时间"), ("Only track carb entries scheduled up to this many minutes in the future. Entries beyond this window are ignored.", "仅跟踪未来这么多分钟内计划的碳水记录,超出此窗口的记录会被忽略。"), ("Lookahead", "预看时间"), ("Minimum Carbs", "最少碳水"), ("Ignore carb entries below this amount.", "忽略低于此数量的碳水记录。"), ("High Glucose Limit", "高血糖限值"), ("The alert becomes eligible once any reading is at or above this value.", "任一读数达到或高于此值后,提醒即符合触发条件。"), ("BG", "血糖"), ("Persistent High", "持续偏高"), ("How long glucose must remain above the threshold before the alarm actually fires. Set to 0 for an immediate alert.", "血糖需持续高于阈值多久闹钟才会真正触发。设为 0 表示立即提醒。"), ("Persistent for", "持续达"), ("Boluses Size Limit", "大剂量大小下限"), ("This counts only boluses larger than this size.", "仅统计大于此大小的大剂量。"), ("Above", "高于"), ("Units", "单位"), ("Bolus Count", "大剂量次数"), ("Number of qualifying boluses needed to trigger.", "触发所需的符合条件大剂量次数。"), ("Count", "次数"), ("Boluses", "次大剂量"), ("How far back to look for those boluses.", "向前回溯多长时间来统计这些大剂量。"), ("Insulin On Board", "活性胰岛素(IOB)"), ("Alert if current IOB or total boluses reach this.", "当当前 IOB 或大剂量总量达到此值时提醒。"), ("IOB Above", "IOB 高于"), ("Low Limit", "低限"), ("Alert when any reading or prediction is at or below this value.", "当任一读数或预测达到或低于此值时提醒。"), ("PERSISTENCE", "持续"), ("Glucose must stay below the threshold for this many minutes before the alert sounds. Set 0 to alert immediately.", "血糖需持续低于阈值这么多分钟提醒才会响。设为 0 表示立即提醒。"), ("Persistent", "持续达"), ("PREDICTION", "预测"), ("Look ahead this many minutes in Loop’s prediction; if any future value is at or below the threshold, you’ll be warned early. Set 0 to disable.", "在 Loop 的预测中向前看这么多分钟;若任一未来值达到或低于阈值,会提前警告你。设为 0 表示禁用。"), ("Predictive", "预测提前量"), ("Delay", "延迟"), ("Minutes to wait after the carb entry before checking for a bolus.", "碳水记录后等待多少分钟再检查是否已打大剂量。"), ("Pre-bolus", "餐前大剂量"), ("Count boluses given up to this many minutes before the carb entry as valid.", "将碳水记录前这么多分钟内的大剂量计为有效。"), ("Pre-Bolus Time", "餐前大剂量时间"), ("Ignore small boluses", "忽略小剂量"), ("Boluses at or below this size are ignored.", "忽略等于或小于此大小的大剂量。"), ("At or Below", "达到或低于"), ("Ignore small carbs", "忽略少量碳水"), ("Carb entries at or below this amount will not trigger the alarm.", "等于或少于此数量的碳水记录不会触发闹钟。"), ("Grams", "克"), ("Ignore low BG", "忽略低血糖"), ("Only alert if the current BG is above this value.", "仅当当前血糖高于此值时才提醒。"), ("Reading Delay", "读数延迟"), ("Choose how long the app should wait before alerting.", "选择应用在提醒前应等待多长时间。"), ("No reading for", "无读数达"), ("No Loop for…", "未闭环达…"), ("Number of minutes since the last successful loop. When this time has elapsed, the alarm becomes eligible.", "距上次成功闭环的分钟数。超过该时间后,闹钟即符合触发条件。"), ("Elapsed time", "已经过时间"), ("Alert only if BG is equal to or below this value.", "仅当血糖等于或低于此值时提醒。"), ("Enable low limit", "启用低限"), ("Below", "低于"), ("High Limit", "高限"), ("Alert only if BG is equal to or above this value.", "仅当血糖等于或高于此值时提醒。"), ("Enable high limit", "启用高限"), ("Phone Battery Level", "手机电量"), ("This alerts you when the phone battery drops to or below this level.", "当手机电量降至或低于此水平时提醒你。"), ("Pump Battery Level", "泵电量"), ("This alerts you when the pump battery drops to or below this level.", "当泵电量降至或低于此水平时提醒你。"), ("Advance Notice", "提前提醒"), ("How many hours before the 3-day limit you’d like a reminder.", "在 3 天期限前多少小时提醒你。"), ("Warning Time", "提醒提前量"), ("Hours", "小时"), ("Trigger Level", "触发水平"), ("An alert fires once the reservoir is at this value or lower.", "储药量达到或低于此值时触发提醒。"), ("Reservoir Below", "储药量低于"), ("Threshold", "阈值"), ("Alert when recommended bolus is at or above this value.", "当推荐大剂量达到或高于此值时提醒。"), ("Sensor Lifetime", "传感器寿命"), ("Number of days your CGM sensor lasts (e.g. 10 for Dexcom G6, 15 for G7 15-day).", "CGM 传感器可用的天数(如 Dexcom G6 为 10 天,G7 15 天版为 15)。"), ("Lifetime", "寿命"), ("days", "天"), ("Early Reminder", "提前提醒"), ("Number of hours before the %lld-day mark that the alert will fire.", "在 %lld 天期限前多少小时触发提醒。"), ("Reminder Time", "提醒时间"), ("hours", "小时"), ("Alert if BG is equal to or below this value.", "当血糖等于或低于此值时提醒。"), ("Alert if BG is equal to or above this value.", "当血糖等于或高于此值时提醒。"), ("Latest BG", "最新血糖"), ]) # ---- 校验补漏批次三:设置/统计/治疗/远程 ---- add([ ("Low BG Limit", "低血糖限值"), ("Fast Drop Delta", "快速下降幅度"), ("High BG Limit", "高血糖限值"), ("Height", "高度"), ("Hours of Prediction", "预测小时数"), ("Min Basal", "基础率最小刻度"), ("Min BG Scale", "血糖最小刻度"), ("Show Days Back", "显示过去天数"), ("Dexcom Username", "Dexcom 用户名"), ("Remote Type", "远程类型"), ("Avg Glucose", "平均血糖"), ("Avg Carbs", "平均碳水"), ("Programmed Basal", "计划基础率"), ("Avg Bolus", "平均大剂量"), ("Total Daily Dose", "每日总剂量"), ("Est. A1C", "估算 A1C"), ("Std Deviation", "标准差"), ("Profile uploaded by a different app", "配置文件由其他应用上传"), ("Future-dated profile record found", "发现未来日期的配置文件记录"), ("Temp Basal", "临时基础率"), ("Temp Target", "临时目标"), ("Automatic Bolus", "自动大剂量"), ("Automatic", "自动"), ("All Boluses", "全部大剂量"), ("Manual", "手动"), ("Basal", "基础率"), ("Quick-Pick Boluses", "快选大剂量"), ("Quick-Pick Meals", "快选餐食"), ("Version", "版本"), ("Latest version", "最新版本"), ("Built", "构建时间"), ("Branch", "分支"), ("Fetching…", "获取中…"), ("App Expiration Warning", "应用到期警告"), ("This app will expire in less than a week. Please rebuild to continue using it.", "本应用将在一周内到期。请重新构建以继续使用。"), ("Access Denied", "访问被拒绝"), ("Please allow access to Contacts in Settings to enable this feature.", "请在「设置」中允许访问通讯录以启用此功能。"), ("Access to Contacts is denied. Please go to Settings and enable Contacts access.", "通讯录访问已被拒绝。请前往「设置」开启通讯录访问权限。"), ("Access Restricted", "访问受限"), ("Access to Contacts is restricted.", "通讯录访问受限。"), ("An unknown error occurred while checking Contacts access.", "检查通讯录访问权限时发生未知错误。"), ]) # ---- 校验补漏批次四:联系人枚举 rawValue(LocalizedStringKey 查表)+ 实时活动槽位 ---- add([ ("Include", "包含"), ("Separate", "单独"), ("Red", "红"), ("Blue", "蓝"), ("Cyan", "青"), ("Green", "绿"), ("Yellow", "黄"), ("Orange", "橙"), ("Purple", "紫"), ("White", "白"), ("Black", "黑"), ("Empty", "留空"), ("Projected BG", "预测血糖"), ("Min/Max", "最低/最高"), ("Autosens", "自动敏感度"), ("Pump", "泵"), ("Pump Battery", "泵电量"), ("Battery", "电量"), ("Carbs today", "今日碳水"), ("Profile", "配置文件"), ]) # ---- 校验补漏批次五:快选说明弹窗(多行 key,与源码逐字一致)---- add([ ("These buttons show your most-used recent bolus amounts.\n\nThey're based on what you've sent before at similar times on similar days — so if you usually give 4 units before breakfast on weekdays, that button will show up on weekday mornings.\n\nTap a button to fill in the amount. Nothing is sent until you review and confirm.", "这些按钮显示你最近最常用的大剂量数值。\n\n它们基于你以往在相近日子、相近时间发送过的内容——比如你通常在工作日早餐前打 4 个单位,工作日早晨就会出现对应按钮。\n\n点按按钮即可填入剂量。在你查看并确认之前,不会发送任何内容。"), ("These buttons show your most-used recent meals.\n\nThey're based on what you've sent before at similar times on similar days — so if you usually send the same breakfast on weekday mornings, it'll appear as an option.\n\nTap a button to fill in the details. Nothing is sent until you review and confirm.", "这些按钮显示你最近最常用的餐食。\n\n它们基于你以往在相近日子、相近时间发送过的内容——比如你通常在工作日早晨发送同样的早餐,它就会作为选项出现。\n\n点按按钮即可填入详情。在你查看并确认之前,不会发送任何内容。"), ]) # ==== 二轮深查:主页面 ==== add([ ("⚠️ Not Looping!", "⚠️ 未闭环!"), ("LOW", "低"), ("HIGH", "高"), ("Est A1C:", "估算 A1C:"), ("Est. A1C:", "估算 A1C:"), ("Std Dev:", "标准差:"), ("Low:", "低:"), ("In Range:", "范围内:"), ("High:", "高:"), ("Avg BG:", "平均血糖:"), ("Updated", "更新时间"), ("LoopFollow Background Refresh", "LoopFollow 后台刷新"), ("App inactive for 6 minutes. Verify Bluetooth connectivity.", "应用已 6 分钟未活动。请检查蓝牙连接。"), ("App inactive for 6 minutes. Open to resume.", "应用已 6 分钟未活动。请打开应用以恢复。"), ("App inactive for 12 minutes. Verify Bluetooth connectivity.", "应用已 12 分钟未活动。请检查蓝牙连接。"), ("App inactive for 12 minutes. Open to resume.", "应用已 12 分钟未活动。请打开应用以恢复。"), ("App inactive for 18 minutes. Verify Bluetooth connectivity.", "应用已 18 分钟未活动。请检查蓝牙连接。"), ("App inactive for 18 minutes. Open to resume.", "应用已 18 分钟未活动。请打开应用以恢复。"), ("Suspend Pump", "暂停泵"), ("Resume Pump", "恢复泵"), ("Start Sensor", "启动传感器"), ("Entered By: ", "录入者:"), ("Bolus:", "大剂量:"), ("Carbs:", "碳水:"), ("Absorption:", "吸收时间:"), ("hrs", "小时"), ("From:", "来自:"), ]) # ==== 二轮深查:远程控制(Trio TRC + Loop APNS)==== add([ ("Bolus Amount", "大剂量数值"), ("Insulin Amount", "胰岛素数值"), ("Carbs Amount", "碳水数值"), ("Fat", "脂肪"), ("Protein", "蛋白质"), ("Select Time", "选择时间"), ("Confirm your identity to send bolus.", "确认你的身份以发送大剂量。"), ("Confirm your identity to send insulin.", "确认你的身份以发送胰岛素。"), ("Authentication failed", "身份验证失败"), ("Bolus command sent successfully.", "大剂量指令已发送成功。"), ("Failed to send bolus command.", "大剂量指令发送失败。"), ("Meal command sent successfully.", "餐食指令已发送成功。"), ("Failed to send meal command.", "餐食指令发送失败。"), ("Temp target command successfully sent.", "临时目标指令已发送成功。"), ("Failed to send temp target command.", "临时目标指令发送失败。"), ("Cancel temp target command successfully sent.", "取消临时目标指令已发送成功。"), ("Failed to send cancel temp target command.", "取消临时目标指令发送失败。"), ("Override command sent successfully.", "临时配置指令已发送成功。"), ("Failed to send override command.", "临时配置指令发送失败。"), ("Cancel override command sent successfully.", "取消临时配置指令已发送成功。"), ("Failed to send cancel override command.", "取消临时配置指令发送失败。"), ("Active override cancelled successfully.", "当前临时配置已成功取消。"), ("An error occurred.", "发生错误。"), ("Invalid input.", "输入无效。"), ("Please wait...", "请稍候…"), ("Remote commands are currently only available for Trio.", "远程指令目前仅支持 Trio。"), ("Are you sure you want to send the meal data", "确定要发送该餐食数据"), (" for %@?", ",用餐时间 %@ 吗?"), (" now?", "吗?"), ("This recommended bolus was calculated %lld minutes ago. New treatments may have occurred since then. Proceed with caution.", "该推荐大剂量计算于 %lld 分钟前。此后可能已有新的治疗发生,请谨慎操作。"), ("WARNING: New treatments may have occurred since the last recommended bolus was calculated %@ ago.", "警告:推荐大剂量计算于 %@ 前,此后可能已有新的治疗发生。"), ("Calculated %lld minute%@ ago", "计算于 %1$lld 分钟前"), ("Indefinite", "无限期"), ("Nightscout URL and token not configured in settings", "设置中未配置 Nightscout 网址和令牌"), ("Invalid response from server", "服务器响应无效"), ("Loop APNS Configuration not valid", "Loop APNS 配置无效"), ("Failed generating JWT token, check APNS Key ID, APNS Key and Team ID", "生成 JWT 令牌失败,请检查 APNS 密钥 ID、APNS 密钥和团队 ID"), ("Network error occurred", "发生网络错误"), ("No device token found in profile", "配置文件中未找到设备令牌"), ("Unauthorized - check your API secret", "未授权——请检查你的 API 密钥"), ("Device token not configured", "设备令牌未配置"), ("Too many requests - please wait a few minutes before trying again", "请求过于频繁——请等待几分钟后再试"), ("Loop APNS setup is incomplete. Please configure all required fields in settings.", "Loop APNS 设置不完整。请在设置中填写所有必填项。"), ("Invalid QR code URL. Please re-scan the QR code in settings.", "二维码网址无效。请在设置中重新扫描二维码。"), ("Please enter a valid insulin amount", "请输入有效的胰岛素数值"), ("Please enter a valid carb amount", "请输入有效的碳水数值"), ("Insulin sent successfully!", "胰岛素已发送成功!"), ("Failed to send insulin. Check your Loop APNS configuration.", "胰岛素发送失败。请检查你的 Loop APNS 配置。"), ("Failed to send carbs. Check your Loop APNS configuration.", "碳水发送失败。请检查你的 Loop APNS 配置。"), ("Carbs sent successfully for %@!", "碳水已发送成功(用餐时间 %@)!"), ("Carbs amount (%lldg) exceeds the maximum allowed (%lldg). Please reduce the amount.", "碳水数量(%1$lld 克)超过允许的最大值(%2$lld 克)。请减少数量。"), ("Time must be within the prior %lld hours", "时间必须在过去 %lld 小时之内"), ("Time must be within the next %lld hour", "时间必须在未来 %lld 小时之内"), ("The scanned settings include a Nightscout URL. Would you like to set this as your Nightscout address?", "扫描到的设置包含一个 Nightscout 网址。要将它设为你的 Nightscout 地址吗?"), ("The scanned settings also include a token. Would you like to set this as your access token?", "扫描到的设置还包含一个令牌。要将它设为你的访问令牌吗?"), ("The scanned settings include a token. Would you like to set this as your access token?", "扫描到的设置包含一个令牌。要将它设为你的访问令牌吗?"), ("The scanned token doesn't match your current access token. Would you like to update your token?", "扫描到的令牌与当前访问令牌不一致。要更新你的令牌吗?"), ("Enter Shared Secret", "输入共享密钥"), ("Enter APNS Key ID", "输入 APNS 密钥 ID"), ("Paste APNS Key", "粘贴 APNS 密钥"), ("Enter Team ID", "输入团队 ID"), ("Enter Token", "输入令牌"), ("A profile record has startDate %@. LoopFollow ignores future-dated records, but it will still appear as the current profile in your Nightscout dashboard. Consider deleting it — it usually means a phone with the wrong system clock is uploading.", "有一条配置文件记录的开始日期为 %@。LoopFollow 会忽略未来日期的记录,但它仍会显示为你 Nightscout 面板中的当前配置文件。建议删除——这通常意味着有一部系统时钟错误的手机正在上传。"), ("Diagnostics unavailable: %@", "诊断不可用:%@"), ("Device tokens are alternating in recent profile uploads (%lld tokens involved across %lld records). This usually means more than one app installation is uploading to the same Nightscout. Remove the app from spare or unused phones.", "近期的配置文件上传中设备令牌交替出现(%2$lld 条记录中涉及 %1$lld 个令牌)。这通常意味着有多个应用安装在向同一个 Nightscout 上传。请从闲置手机上移除该应用。"), ("Do you want to activate the override '%@'?", "要启用临时配置「%@」吗?"), ("Percentage: %lld%", "比例:%lld%"), ("Percentage: %lld%%", "比例:%lld%%"), ("Target: %@ %@", "目标:%1$@ %2$@"), ("Target: %@-%@", "目标:%1$@-%2$@"), ("Insulin: %lld%", "胰岛素:%lld%"), ("Insulin: %lld%%", "胰岛素:%lld%%"), ("New Target: %@ %@\nDuration: %lld minutes", "新目标:%1$@ %2$@\n持续时间:%3$lld 分钟"), ]) # ==== 二轮深查:Nightscout 状态 ==== add([ ("Checking...", "正在检查…"), ("Disconnected", "未连接"), ("Connecting...", "正在连接…"), ("Invalid URL", "网址无效"), ("Network Error", "网络错误"), ("Invalid Token", "令牌无效"), ("Token Required", "需要令牌"), ("Site Not Found", "未找到站点"), ("Unknown Error", "未知错误"), ("Address Empty", "地址为空"), ("Admin", "管理员"), ("OK (%@)", "正常(%@)"), ]) # ==== 二轮深查:统计页 ==== add([ ("Loading data...", "正在加载数据…"), ("Total Negative Basal", "负向基础率合计"), ("Total Positive Basal", "正向基础率合计"), ("Actual Basal", "实际基础率"), ("g/day", "克/天"), ("U/day", "U/天"), ("Very High (%@)", "非常高(%@)"), ("High (%@)", "高(%@)"), ("In Range (%@)", "范围内(%@)"), ("Low (%@)", "低(%@)"), ("Very Low (%@)", "非常低(%@)"), ("Time in Range", "目标范围内时间"), ("Time in Tight Range", "严格范围内时间"), ("Custom Range", "自定义范围"), ("Very Low", "非常低"), ("In Range", "范围内"), ("Very High", "非常高"), ("Morning", "上午"), ("Evening", "傍晚"), ("Average", "平均"), ("Zone A", "区域 A"), ("Zone B", "区域 B"), ("Zone C", "区域 C"), ("Zone D", "区域 D"), ("Zone E", "区域 E"), ("Current GRI", "当前 GRI"), ("Median", "中位数"), ("Excellent", "极好"), ("Good", "良好"), ("Fair", "一般"), ("Poor", "较差"), ("Select Start Date", "选择开始日期"), ("Select End Date", "选择结束日期"), ("Cutoffs in %@", "阈值单位:%@"), ]) # ==== 二轮深查:实时活动设置与其它 ==== add([ ("Top left", "左上"), ("Top right", "右上"), ("Bottom left", "左下"), ("Bottom right", "右下"), ("Live Activity Restarted", "实时活动已重启"), ("Restart Live Activity", "重启实时活动"), ("Snooze until (date)", "暂停至(日期)"), ("Snooze until (time)", "暂停至(时间)"), ("Unknown", "未知"), ]) # ==== 三轮:首页 min ago 与缩写行名(用户点名) ==== add([ (" min ago", " 分钟前"), ("?? min ago", "?? 分钟前"), ("Refreshing", "刷新中"), (" min", " 分钟"), ("IOB", "活性胰岛素"), ("COB", "活性碳水"), ("SAGE", "传感器"), ("CAGE", "管路"), ("IAGE", "胰岛素"), ("TDD", "每日总量"), ("ISF", "敏感系数"), ("CR", "碳水系数"), ]) # ==== 三轮:版本提醒 / 身份验证 / 构建信息 ==== add([ ("Update Available", "有可用更新"), ("The current version has a critical issue and should be updated as soon as possible.", "当前版本存在严重问题,请尽快更新。"), ("A new version is available: %@. It is recommended to update.", "新版本已发布:%@。建议尽快更新。"), ("Enter Passcode", "输入设备密码"), ("Device authentication is not available. ", "设备身份验证不可用。"), ("Please enable Face ID, Touch ID, or set up a device passcode in Settings.", "请在「设置」中启用面容 ID、触控 ID,或设置设备密码。"), ("Face ID is not available. Please set up a device passcode in Settings.", "面容 ID 不可用。请在「设置」中设置设备密码。"), ("Touch ID is not available. Please set up a device passcode in Settings.", "触控 ID 不可用。请在「设置」中设置设备密码。"), ("TestFlight Expires", "TestFlight 到期"), ("App Expires", "应用到期"), ("Search Log", "搜索日志"), ("No Logs Available", "暂无日志"), ("There are no logs to share.", "没有可分享的日志。"), ]) # ==== 三轮:时间单位 / 闹钟分组 / 默认闹钟名 ==== add([ ("none", "无"), ("Until", "直到"), ("Insulin / Food", "胰岛素 / 食物"), ("Device / System", "设备 / 系统"), ("Override / Target", "临时配置 / 目标"), ("Urgent Low", "紧急低血糖"), ("Urgent High", "紧急高血糖"), ("Fast Drop", "快速下降"), ("Fast Rise", "快速上升"), ("Missed Reading", "读数缺失"), ("Sensor Change Reminder", "传感器更换提醒"), ("Pump / Cannula Change", "泵/管路更换"), ("Temporary BG Limit", "临时血糖限值"), ("Pump Reservoir", "泵储药量"), ("High IOB", "高活性胰岛素"), ("High COB", "高活性碳水"), ("Snoozed until %@", "已暂停至 %@"), ("%lld sec", "%lld 秒"), ("up to %lld sec", "最多 %lld 秒"), ("%lld seconds", "%lld 秒"), ("“Default Snooze” controls the default value for how long the alert stays quiet after you press Snooze. \"A snooze duration of 0 means the alarm is acknowledged (silenced), and will alert again next time the condition applies, without time limitation. \" Toggle “Snoozed” to mute this alarm right now.", "「默认暂停时长」控制按下暂停后提醒静默多久的默认值。暂停时长为 0 表示仅确认(静音)该提醒,下次条件满足时仍会再次提醒,不受时间限制。打开「已暂停」可立即静音此闹钟。"), ]) # ==== 三轮:闹钟编辑器介绍段 ==== add([ ("This warns you if your phone’s battery drops quickly, based on the percentage and time you set.", "当手机电量按你设定的幅度和时间快速下降时提醒你。"), ("Alerts when Carbs-on-Board is at or above the amount you set below.", "当活性碳水达到或超过下方设定值时提醒。"), ("Alerts when glucose readings rise rapidly. For example, three straight readings each climbing by at least the amount you set. Optionally limit alerts to only fire above a certain BG.", "当血糖读数快速上升时提醒。例如连续三次读数、每次上升都不低于你设定的幅度。还可限制仅在血糖高于某个值时才提醒。"), ("Alerts when glucose stays above the limit you set below. Use Persistent if you want to ignore brief spikes.", "当血糖持续高于下方设定的限值时提醒。若想忽略短暂冲高,请使用「持续时间」。"), ("Sends a reminder before the looping-app build you’re following reaches its TestFlight or Xcode expiry date. Works with Trio 0.4 and later.", "在你跟随的闭环应用构建到达 TestFlight 或 Xcode 到期日前发送提醒。适用于 Trio 0.4 及以上版本。"), ("Alerts when glucose readings drop rapidly. For example, three straight readings each falling by at least the amount you set. Optionally limit alerts to only fire below a certain BG level.", "当血糖读数快速下降时提醒。例如连续三次读数、每次下降都不低于你设定的幅度。还可限制仅在血糖低于某个值时才提醒。"), ("Alerts when a future-dated carb entry's scheduled time arrives — a reminder to start eating. Use the max lookahead to ignore fat/protein entries that are typically scheduled further ahead.", "当未来时间的碳水记录到点时提醒——提示该吃东西了。用最长预看时间可忽略通常安排得更靠后的脂肪/蛋白质条目。"), ("Alerts when carbs are logged but no bolus is delivered within the delay below. Allows small-carb / treatment exclusions and pre-bolus detection.", "记录碳水后,若在下方延迟时间内未输注大剂量则提醒。支持排除少量碳水,并可识别餐前大剂量。"), ("This warns you when the phone's battery gets low, based on the percentage you choose.", "当手机电量低于你选择的百分比时提醒你。"), ("Alerts when insulin-on-board is high, or when several boluses in quick succession exceed the limits you set.", "当活性胰岛素偏高,或短时间内多次大剂量超过你设定的限值时提醒。"), ("Alerts when the pump / cannula is within the time window you choose below (relative to the 3-day change limit).", "当泵/管路进入你在下方选择的时间窗口(相对 3 天更换期限)时提醒。"), ("Alerts when the recommended bolus equals or exceeds the threshold you set below.", "当推荐大剂量达到或超过下方设定的阈值时提醒。"), ("Alerts when an override begins.", "当临时配置开始时提醒。"), ("Alerts when an override ends.", "当临时配置结束时提醒。"), ("Alerts when a temp target starts.", "当临时目标开始时提醒。"), ("Alerts when a temp target ends.", "当临时目标结束时提醒。"), ("This alert fires once when glucose crosses either of the limits you set below, and then disables itself.", "当血糖越过下方任一限值时提醒一次,然后自动停用。"), ("This warns you when the insulin pump is running low on insulin.", "当胰岛素泵的药量不足时提醒你。"), ("Alerts when no successful loop has occurred for the time you set below.", "当超过下方设定时间仍未成功闭环时提醒。"), ("This warns you if the glucose is too low now or might be soon, based on the forecast.", "当血糖现在过低、或根据预测即将过低时提醒你。"), ("This warns you if the glucose monitor stops sending readings for too long..", "当血糖仪停止发送读数太久时提醒你。"), ("Warn me before the sensor’s %lld-day change-over.", "在传感器 %lld 天更换期前提醒我。"), ]) # ==== 三轮:护栏 / Nightscout 校验 / 杂项 ==== add([ ("Value outside of guardrails: %@\n", "数值超出安全护栏:%@\n"), ("Minimum: %@\n", "最小值:%@\n"), ("Maximum: %@", "最大值:%@"), ("The address is empty.", "地址为空。"), ("The URL is invalid.", "网址无效。"), ("A network error occurred.", "发生网络错误。"), ("The site was not found.", "未找到该站点。"), ("The token is invalid.", "令牌无效。"), ("A token is required.", "需要令牌。"), ("An unknown error occurred.", "发生未知错误。"), ("Cone", "锥形区间"), ("Lines", "线条"), ("Static", "固定"), ("Dynamic (BG Range)", "动态(按血糖范围)"), ("Unknown Device", "未知设备"), ("Expected bg delay: %@", "预计血糖延迟:%@"), ("Temporary Override", "临时配置"), ("Add the contact named '%@' to your watch face to show the current BG value in real time. Make sure to give the app full access to Contacts when prompted.", "把名为「%@」的联系人添加到表盘,即可实时显示当前血糖。弹出授权时请允许应用完整访问通讯录。"), ("BG Update Delay (Sec): %lld", "血糖更新延迟(秒):%lld"), ]) # ==== 三轮:导入/导出 ==== add([ ("Scanning failed: %@", "扫描失败:%@"), ("Invalid QR code data", "二维码数据无效"), ("Failed to decode or migrate settings from QR code", "无法解析或迁移二维码中的设置"), ("Import failed. This might be due to a version change (current: %@). Please try exporting settings from the source device again.", "导入失败。可能是版本变更所致(当前版本:%@)。请在源设备上重新导出设置后再试。"), ("Successfully imported: %@", "导入成功:%@"), ("Please configure your Nightscout settings first (URL and Token)", "请先配置你的 Nightscout 设置(网址和令牌)"), ("Please complete your Remote settings configuration (check required fields for %@)", "请完善你的远程设置(检查 %@ 的必填项)"), ("Please configure your Remote settings first (select a remote type and configure required fields)", "请先配置你的远程设置(选择远程类型并填写必填项)"), ("Please configure your Alarm settings first", "请先配置你的闹钟设置"), ("Please configure your Dexcom Share settings first (username and password)", "请先配置你的 Dexcom Share 设置(用户名和密码)"), ("The settings file exists but contains no valid settings to import.", "设置文件存在,但不包含可导入的有效设置。"), ("Import failed: %@", "导入失败:%@"), ("Remote type is changing from %@ to %@. This may affect your remote commands.\n", "远程类型将从 %1$@ 变更为 %2$@。这可能影响你的远程指令。\n"), ("Remote user is changing from '%@' to '%@'. This may affect your remote commands.\n", "远程用户将从「%1$@」变更为「%2$@」。这可能影响你的远程指令。\n"), ("APNS Key ID is changing. This may affect your remote commands.\n", "APNS 密钥 ID 即将变更。这可能影响你的远程指令。\n"), ("APNS Key is changing. This may affect your remote commands.\n", "APNS 密钥即将变更。这可能影响你的远程指令。\n"), ("Shared secret is changing. This may affect your remote commands.\n", "共享密钥即将变更。这可能影响你的远程指令。\n"), ("Team ID is changing. This may affect your remote commands.\n", "团队 ID 即将变更。这可能影响你的远程指令。\n"), ("Loop APNS QR Code URL is changing. This may affect your remote commands.\n", "Loop APNS 二维码网址即将变更。这可能影响你的远程指令。\n"), ("Note: This import does not include Nightscout token settings. Your current Nightscout token will be preserved.\n", "注意:此次导入不包含 Nightscout 令牌设置。你当前的 Nightscout 令牌将被保留。\n"), ("Settings from version %@ may not be fully compatible with current version %@. Some features may not work as expected.", "来自版本 %1$@ 的设置可能与当前版本 %2$@ 不完全兼容,部分功能可能无法正常工作。"), ("Nightscout Settings", "Nightscout 设置"), ("Dexcom Share Settings", "Dexcom Share 设置"), ("Scan this QR code with another LoopFollow app to import %@", "用另一台 LoopFollow 扫描此二维码以导入%@"), ("Export %@", "导出%@"), ]) # ---------- 写出 ---------- if os.path.exists(OUT): with open(OUT, "r", encoding="utf-8") as f: catalog = json.load(f, object_pairs_hook=collections.OrderedDict) else: catalog = collections.OrderedDict([ ("sourceLanguage", "en"), ("strings", collections.OrderedDict()), ("version", "1.0"), ]) strings = catalog.setdefault("strings", collections.OrderedDict()) for en in sorted(T.keys()): zh = T[en] entry = strings.setdefault(en, collections.OrderedDict()) entry.setdefault("extractionState", "manual") localizations = entry.setdefault("localizations", collections.OrderedDict()) localizations["zh-Hans"] = { "stringUnit": {"state": "translated", "value": zh} } os.makedirs(os.path.dirname(OUT), exist_ok=True) with open(OUT, "w", encoding="utf-8") as f: json.dump(catalog, f, ensure_ascii=False, indent=2) f.write("\n") print("keys translated:", len(T)) print("written:", OUT)