diff --git a/selfdrive/ui/qt/sidebar.h b/selfdrive/ui/qt/sidebar.h index 98ae6564d6..4c6d8f47e5 100644 --- a/selfdrive/ui/qt/sidebar.h +++ b/selfdrive/ui/qt/sidebar.h @@ -34,13 +34,13 @@ protected: QPixmap home_img, settings_img; const QMap network_type = { - {cereal::DeviceState::NetworkType::NONE, "--"}, - {cereal::DeviceState::NetworkType::WIFI, "Wi-Fi"}, - {cereal::DeviceState::NetworkType::ETHERNET, "ETH"}, - {cereal::DeviceState::NetworkType::CELL2_G, "2G"}, - {cereal::DeviceState::NetworkType::CELL3_G, "3G"}, - {cereal::DeviceState::NetworkType::CELL4_G, "LTE"}, - {cereal::DeviceState::NetworkType::CELL5_G, "5G"} + {cereal::DeviceState::NetworkType::NONE, tr("--")}, + {cereal::DeviceState::NetworkType::WIFI, tr("Wi-Fi")}, + {cereal::DeviceState::NetworkType::ETHERNET, tr("ETH")}, + {cereal::DeviceState::NetworkType::CELL2_G, tr("2G")}, + {cereal::DeviceState::NetworkType::CELL3_G, tr("3G")}, + {cereal::DeviceState::NetworkType::CELL4_G, tr("LTE")}, + {cereal::DeviceState::NetworkType::CELL5_G, tr("5G")} }; const QRect settings_btn = QRect(50, 35, 200, 117); diff --git a/selfdrive/ui/tests/test_translations.py b/selfdrive/ui/tests/test_translations.py index ccea748e24..2dedf3d785 100755 --- a/selfdrive/ui/tests/test_translations.py +++ b/selfdrive/ui/tests/test_translations.py @@ -1,10 +1,13 @@ #!/usr/bin/env python3 import json import os +import shutil import unittest from selfdrive.ui.update_translations import TRANSLATIONS_DIR, LANGUAGES_FILE, update_translations +TMP_TRANSLATIONS_DIR = os.path.join(TRANSLATIONS_DIR, "tmp") + class TestTranslations(unittest.TestCase): @classmethod @@ -12,11 +15,25 @@ class TestTranslations(unittest.TestCase): with open(LANGUAGES_FILE, "r") as f: cls.translation_files = json.load(f) + # Set up temp directory + shutil.copytree(TRANSLATIONS_DIR, TMP_TRANSLATIONS_DIR, dirs_exist_ok=True) + + @classmethod + def tearDownClass(cls): + shutil.rmtree(TMP_TRANSLATIONS_DIR, ignore_errors=True) + + @staticmethod + def _read_translation_file(path, file, file_ext): + tr_file = os.path.join(path, f"{file}.{file_ext}") + with open(tr_file, "rb") as f: + # fix relative path depth + return f.read().replace(b"filename=\"../../", b"filename=\"../") + def test_missing_translation_files(self): for name, file in self.translation_files.items(): with self.subTest(name=name, file=file): if not len(file): - self.skipTest(f"{name} translation has no file") + self.skipTest(f"{name} translation has no defined file") self.assertTrue(os.path.exists(os.path.join(TRANSLATIONS_DIR, f"{file}.ts")), f"{name} has no XML translation file, run selfdrive/ui/update_translations.py") @@ -24,26 +41,25 @@ class TestTranslations(unittest.TestCase): f"{name} has no compiled QM translation file, run selfdrive/ui/update_translations.py --release") def test_translations_updated(self): - suffix = "_test" - update_translations(suffix=suffix) + update_translations(release=True, translations_dir=TMP_TRANSLATIONS_DIR) for name, file in self.translation_files.items(): with self.subTest(name=name, file=file): - cur_tr_file = os.path.join(TRANSLATIONS_DIR, f"{file}.ts") - new_tr_file = os.path.join(TRANSLATIONS_DIR, f"{file}{suffix}.ts") - if not len(file): - self.skipTest(f"{name} translation has no file") - elif not os.path.exists(cur_tr_file): - self.skipTest(f"{name} missing translation file") # caught by test_missing_translation_files + self.skipTest(f"{name} translation has no defined file") + + for file_ext in ["ts", "qm"]: + with self.subTest(file_ext=file_ext): + + # caught by test_missing_translation_files + if not os.path.exists(os.path.join(TRANSLATIONS_DIR, f"{file}.{file_ext}")): + self.skipTest(f"{name} missing translation file") - with open(cur_tr_file, "r") as f: - cur_translations = f.read() - with open(new_tr_file, "r") as f: - new_translations = f.read() + cur_translations = self._read_translation_file(TRANSLATIONS_DIR, file, file_ext) + new_translations = self._read_translation_file(TMP_TRANSLATIONS_DIR, file, file_ext) - self.assertEqual(cur_translations, new_translations, - f"{name} translation file out of date. Run selfdrive/ui/update_translations.py to update the translation files") + self.assertEqual(cur_translations, new_translations, + f"{file} ({name}) {file_ext.upper()} translation file out of date. Run selfdrive/ui/update_translations.py --release to update the translation files") if __name__ == "__main__": diff --git a/selfdrive/ui/translations/languages.json b/selfdrive/ui/translations/languages.json index f2f9400d64..e62de24a1e 100644 --- a/selfdrive/ui/translations/languages.json +++ b/selfdrive/ui/translations/languages.json @@ -1,3 +1,4 @@ { - "English": "" + "English": "", + "中文(简体)": "main_zh" } diff --git a/selfdrive/ui/translations/main_zh.qm b/selfdrive/ui/translations/main_zh.qm new file mode 100644 index 0000000000..c40d61024e --- /dev/null +++ b/selfdrive/ui/translations/main_zh.qm @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c7bf2551ac2c4ccb08c6fa66a18d28faa0b6a489b3073fa239bd63555ffcdb5b +size 17617 diff --git a/selfdrive/ui/translations/main_zh.ts b/selfdrive/ui/translations/main_zh.ts new file mode 100644 index 0000000000..7bcee2c23a --- /dev/null +++ b/selfdrive/ui/translations/main_zh.ts @@ -0,0 +1,1212 @@ + + + + + AbstractAlert + + + Close + + + + + Snooze Update + 暂停更新 + + + + Reboot and Update + 重启和更新 + + + + AdvancedNetworking + + + Back + 后退 + + + + Enable Tethering + 启用网络共享 + + + + Tethering Password + 网络共享密码 + + + + + EDIT + 编辑 + + + + Enter new tethering password + 输入新的网络共享密码 + + + + IP Address + IP地址 + + + + Enable Roaming + 启用漫游 + + + + APN Setting + APN 设置 + + + + Enter APN + 输入 APN + + + + leave blank for automatic configuration + 为自动配置留空 + + + + ConfirmationDialog + + + + Ok + 好的 + + + + Cancel + 取消 + + + + DeclinePage + + + You must accept the Terms and Conditions in order to use openpilot. + 您必须接受条款和条件才能使用 openpilot。 + + + + Back + 后退 + + + + Decline, uninstall %1 + 拒绝,卸载 %1 + + + + DevicePanel + + + Dongle ID + 加密狗 ID + + + + N/A + 不适用 + + + + Serial + 串行 + + + + Driver Camera + 司机摄像头 + + + + PREVIEW + 预习 + + + + Preview the driver facing camera to help optimize device mounting position for best driver monitoring experience. (vehicle must be off) + 预览面向驾驶员的摄像头,以帮助优化设备安装位置以获得最佳驾驶员监控体验。 (车辆必须关闭) + + + + Reset Calibration + 重置校准 + + + + RESET + 重置 + + + + Are you sure you want to reset calibration? + 您确定要重置校准吗? + + + + Review Training Guide + 查看培训指南 + + + + REVIEW + 审查 + + + + Review the rules, features, and limitations of openpilot + 查看 openpilot 的规则、功能和限制 + + + + Are you sure you want to review the training guide? + 您确定要查看培训指南吗? + + + + Regulatory + 监管 + + + + VIEW + 看法 + + + Change Language + 改变语言 + + + CHANGE + 改变 + + + Select a language + 选择语言 + + + + Reboot + 重启 + + + + Power Off + 关机 + + + + openpilot requires the device to be mounted within 4° left or right and within 5° up or 8° down. openpilot is continuously calibrating, resetting is rarely required. + openpilot 要求设备安装在左或右 4° 以内,上 5° 或下 8° 以内。 openpilot 会持续校准,很少需要重置。 + + + + Your device is pointed %1° %2 and %3° %4. + 您的设备指向 %1° %2 和 %3° %4。 + + + + down + + + + + up + 向上 + + + + left + 剩下 + + + + right + 向右 + + + + Are you sure you want to reboot? + 您确定要重新启动吗? + + + + Disengage to Reboot + 脱离以重新启动 + + + + Are you sure you want to power off? + 您确定要关闭电源吗? + + + + Disengage to Power Off + 脱离以关闭电源 + + + + DriveStats + + + Drives + 驱动器 + + + + Hours + 小时 + + + + ALL TIME + 整天 + + + + PAST WEEK + 上周 + + + + KM + 千米 + + + + Miles + 迈尔斯 + + + + DriverViewScene + + + camera starting + 相机启动 + + + + InputDialog + + + Cancel + 取消 + + + + Need at least + 需要至少 + + + + characters! + 字符! + + + + Installer + + + Installing... + 安装... + + + + Receiving objects: + 接收物体: + + + + Resolving deltas: + 解决增量: + + + + Updating files: + 更新文件: + + + + MapPanel + + + Current Destination + 当前目的地 + + + + CLEAR + CLEAR + + + + Recent Destinations + 近期目的地 + + + + Try the Navigation Beta + 试用导航测试版 + + + + Get turn-by-turn directions displayed and more with a comma +prime subscription. Sign up now: https://connect.comma.ai + 使用逗号获取显示的详细路线和更多信息 +主要订阅。 立即注册:https://connect.comma.ai + + + + No home +location set + 没有家 +位置集 + + + + No work +location set + 没有工作 +位置集 + + + + no recent destinations + 没有最近的目的地 + + + + MultiOptionDialog + + Select + 选择 + + + Cancel + 取消 + + + + Networking + + + Advanced + 先进的 + + + + Enter password + 先进的 + + + + + for " + 为了 " + + + + Wrong password + Wrong password + + + + NvgWindow + + + km/h + 公里/小时 + + + + mph + 英里/小时 + + + + + MAX + 最大限度 + + + + + SPEED + 速度 + + + + + LIMIT + 限制 + + + + OffroadHome + + + UPDATE + 更新 + + + + ALERTS + 个警报 + + + + ALERT + 个警报 + + + + PairingPopup + + + Pair your device to your comma account + 将您的设备与您的逗号账户配对 + + + + + <ol type='1' style='margin-left: 15px;'> + <li style='margin-bottom: 50px;'>Go to https://connect.comma.ai on your phone</li> + <li style='margin-bottom: 50px;'>Click "add new device" and scan the QR code on the right</li> + <li style='margin-bottom: 50px;'>Bookmark connect.comma.ai to your home screen to use it like an app</li> + </ol> + + + <ol type='1' style='margin-left: 15px;'> + <li style='margin-bottom: 50px;'>在手机上访问 https://connect.comma.ai</li> + <li style='margin-bottom: 50px;'>点击“添加新设备”,扫描右侧二维码</li> + <li style='margin-bottom: 50px;'>将 connect.comma.ai 收藏到您的主屏幕,以便像应用程序一样使用它</li> + </ol> + + + + + PrimeAdWidget + + + Upgrade Now + 现在升级 + + + + Become a comma prime member at connect.comma.ai + 成为 connect.comma.ai 的逗号主要会员 + + + + PRIME FEATURES: + 主要特点: + + + + Remote access + 远程访问 + + + + 1 year of storage + 1年存储 + + + + Developer perks + 开发者福利 + + + + PrimeUserWidget + + + ✓ SUBSCRIBED + ✓ 订阅 + + + + comma prime + 逗号素数 + + + + CONNECT.COMMA.AI + CONNECT.COMMA.AI + + + + COMMA POINTS + 逗号分 + + + + QObject + + + Reboot + 重启 + + + + Exit + 出口 + + + + dashcam + 行车记录器 + + + + openpilot + 开放式飞行员 + + + + %1 minute%2 ago + %1 分钟%2 前 + + + + %1 hour%2 ago + %1 小时%2 前 + + + + %1 day%2 ago + %1 天%2 前 + + + + Reset + + + Reset failed. Reboot to try again. + 重置失败。 重新启动以重试。 + + + + Are you sure you want to reset your device? + 您确定要重置您的设备吗? + + + + Resetting device... + 正在重置设备... + + + + System Reset + 系统重置 + + + + System reset triggered. Press confirm to erase all content and settings. Press cancel to resume boot. + 触发系统重置。 按确认删除所有内容和设置。 按取消恢复启动。 + + + + Cancel + 取消 + + + + Reboot + 重启 + + + + Confirm + 确认 + + + + Unable to mount data partition. Press confirm to reset your device. + 无法挂载数据分区。 按确认重置您的设备。 + + + + RichTextDialog + + + Ok + 好的 + + + + SettingsWindow + + + × + × + + + + Device + 设备 + + + + + Network + 网络 + + + + Toggles + 切换 + + + + Software + 软件 + + + + Navigation + 导航 + + + + Setup + + + WARNING: Low Voltage + 警告:低电压 + + + + Power your device in a car with a harness or proceed at your own risk. + 使用安全带在汽车中为您的设备供电或自行承担风险。 + + + + Power off + 关机 + + + + + + Continue + 继续 + + + + Getting Started + 入门 + + + + Before we get on the road, let’s finish installation and cover some details. + 在我们上路之前,让我们完成安装并介绍一些细节。 + + + + Connect to Wi-Fi + 连接到无线网络 + + + + + Back + 后退 + + + + Continue without Wi-Fi + 在没有 Wi-Fi 的情况下继续 + + + + Waiting for internet + 等待上网 + + + + Choose Software to Install + 选择要安装的软件 + + + + Dashcam + 行车记录器 + + + + Custom Software + 定制的软件 + + + + Enter URL + 输入网址 + + + + for Custom Software + 定制软件 + + + + Downloading... + 正在下载... + + + + Download Failed + 下载失败 + + + + Ensure the entered URL is valid, and the device’s internet connection is good. + 确保输入的 URL 有效,并且设备的互联网连接良好。 + + + + Reboot device + 重启设备 + + + + Start over + 重来 + + + + SetupWidget + + + Finish Setup + 完成设置 + + + + Pair your device with comma connect (connect.comma.ai) and claim your comma prime offer. + 将您的设备与 comma connect (connect.comma.ai) 配对并领取您的 comma prime 优惠。 + + + + Pair device + 配对设备 + + + + Sidebar + + + + CONNECT + 连接 + + + + OFFLINE + 离线 + + + + + ONLINE + 在线的 + + + + ERROR + 错误 + + + + + + TEMP + 温度 + + + + HIGH + 高的 + + + + GOOD + 好的 + + + + OK + 好的 + + + + VEHICLE + 车辆 + + + + NO + + + + + PANDA + 熊猫 + + + + GPS + GPS + + + + SEARCH + 搜索 + + + + -- + -- + + + + Wi-Fi + Wi-Fi + + + + ETH + 以太網 + + + + 2G + 2G + + + + 3G + 3G + + + + LTE + LTE + + + + 5G + 5G + + + + SoftwarePanel + + + Git Branch + Git 分支 + + + + Git Commit + Git 提交 + + + + OS Version + 操作系统版本 + + + + Version + 版本 + + + + Last Update Check + 最后更新检查 + + + + The last time openpilot successfully checked for an update. The updater only runs while the car is off. + 上次 openpilot 成功检查更新的时间。 更新程序仅在汽车关闭时运行。 + + + + Check for Update + 检查更新 + + + + CHECKING + 正在检查 + + + + Uninstall + 卸载 + + + + UNINSTALL + 卸载 + + + + Are you sure you want to uninstall? + 您确定要卸载吗? + + + + failed to fetch update + 未能获取更新 + + + + + CHECK + 查看 + + + + SshControl + + + SSH Keys + SSH 密钥 + + + + Warning: This grants SSH access to all public keys in your GitHub settings. Never enter a GitHub username other than your own. A comma employee will NEVER ask you to add their GitHub username. + 警告:这将授予对 GitHub 设置中所有公钥的 SSH 访问权限。 切勿输入您自己以外的 GitHub 用户名。 逗号员工永远不会要求您添加他们的 GitHub 用户名。 + + + + + ADD + 添加 + + + + Enter your GitHub username + 输入你的 GitHub 用户名 + + + + LOADING + 正在加载 + + + + REMOVE + 消除 + + + + Username '%1' has no keys on GitHub + 用户名“%1”在 GitHub 上没有密钥 + + + + Request timed out + 请求超时 + + + + Username '%1' doesn't exist on GitHub + GitHub 上不存在用户名“%1” + + + + SshToggle + + + Enable SSH + 启用 SSH + + + + TermsPage + + + Terms & Conditions + 条款和条件 + + + + Decline + 衰退 + + + + Scroll to accept + 滚动接受 + + + + Agree + 同意 + + + + TogglesPanel + + + Enable openpilot + 启用 openpilot + + + + Use the openpilot system for adaptive cruise control and lane keep driver assistance. Your attention is required at all times to use this feature. Changing this setting takes effect when the car is powered off. + 使用 openpilot 系统进行自适应巡航控制和车道保持驾驶员辅助。 任何时候都需要您注意使用此功能。 更改此设置在汽车断电时生效。 + + + + Enable Lane Departure Warnings + 启用车道偏离警告 + + + + Receive alerts to steer back into the lane when your vehicle drifts over a detected lane line without a turn signal activated while driving over 31 mph (50 km/h). + 当您的车辆在以超过 31 英里/小时(50 公里/小时)的速度行驶时在检测到的车道线上漂移而没有激活转向信号时,接收提醒以返回车道。 + + + + Enable Right-Hand Drive + 启用右手驱动 + + + + Allow openpilot to obey left-hand traffic conventions and perform driver monitoring on right driver seat. + 允许 openpilot 遵守左侧交通惯例并在右侧驾驶座上执行驾驶员监控。 + + + + Use Metric System + 使用公制 + + + + Display speed in km/h instead of mph. + 以公里/小时而不是英里/小时显示速度。 + + + + Record and Upload Driver Camera + 记录和上传司机摄像头 + + + + Upload data from the driver facing camera and help improve the driver monitoring algorithm. + 从面向驾驶员的摄像头上传数据,帮助改进驾驶员监控算法。 + + + + Disengage On Accelerator Pedal + 松开加速踏板 + + + + When enabled, pressing the accelerator pedal will disengage openpilot. + 启用后,踩下油门踏板将解除 openpilot。 + + + + Show ETA in 24h format + 以 24 小时格式显示 ETA + + + + Use 24h format instead of am/pm + 使用 24 小时制代替上午/下午 + + + + openpilot Longitudinal Control + openpilot 纵向控制 + + + + openpilot will disable the car's radar and will take over control of gas and brakes. Warning: this disables AEB! + openpilot 将禁用汽车的雷达并接管油门和刹车的控制。 警告:这会禁用 AEB! + + + + Updater + + + Update Required + 需要更新 + + + + An operating system update is required. Connect your device to Wi-Fi for the fastest update experience. The download size is approximately 1GB. + 需要操作系统更新。 将您的设备连接到 Wi-Fi,以获得最快的更新体验。 下载大小约为 1GB。 + + + + Connect to Wi-Fi + 连接到无线网络 + + + + Install + 安装 + + + + Back + 后退 + + + + Loading... + 正在加载... + + + + Reboot + 重启 + + + + Update failed + 更新失败 + + + + WifiUI + + + + Scanning for networks... + 正在扫描网络... + + + + CONNECTING... + 正在连接... + + + + FORGET + 忘记 + + + + Forget Wi-Fi Network " + 忘记 Wi-Fi 网络" + + + diff --git a/selfdrive/ui/update_translations.py b/selfdrive/ui/update_translations.py index 5d57fa39d2..263eb5e670 100755 --- a/selfdrive/ui/update_translations.py +++ b/selfdrive/ui/update_translations.py @@ -10,7 +10,7 @@ TRANSLATIONS_DIR = os.path.join(UI_DIR, "translations") LANGUAGES_FILE = os.path.join(TRANSLATIONS_DIR, "languages.json") -def update_translations(release=False, suffix=""): +def update_translations(release=False, translations_dir=TRANSLATIONS_DIR): with open(LANGUAGES_FILE, "r") as f: translation_files = json.load(f) @@ -19,7 +19,7 @@ def update_translations(release=False, suffix=""): print(f"{name} has no translation file, skipping...") continue - tr_file = os.path.join(TRANSLATIONS_DIR, f"{file}{suffix}.ts") + tr_file = os.path.join(translations_dir, f"{file}.ts") ret = os.system(f"lupdate -recursive {UI_DIR} -ts {tr_file}") assert ret == 0