cursor wrapping -- it missed entire sections, changed formatting, and didn't use trn properly!!!!!!!!!!!!!!!!!

pull/36410/head
Shane Smiskol 5 days ago
parent 45c4ffb1b6
commit 16fe347f75
  1. 15
      selfdrive/ui/layouts/onboarding.py
  2. 17
      selfdrive/ui/layouts/settings/developer.py
  3. 31
      selfdrive/ui/layouts/settings/device.py
  4. 14
      selfdrive/ui/layouts/settings/firehose.py
  5. 13
      selfdrive/ui/layouts/settings/settings.py
  6. 41
      selfdrive/ui/layouts/settings/software.py
  7. 36
      selfdrive/ui/layouts/settings/toggles.py
  8. 39
      selfdrive/ui/layouts/sidebar.py

@ -6,6 +6,7 @@ from enum import IntEnum
import pyray as rl import pyray as rl
from openpilot.common.basedir import BASEDIR from openpilot.common.basedir import BASEDIR
from openpilot.system.ui.lib.application import FontWeight, gui_app from openpilot.system.ui.lib.application import FontWeight, gui_app
from openpilot.system.ui.lib.multilang import tr
from openpilot.system.ui.widgets import Widget from openpilot.system.ui.widgets import Widget
from openpilot.system.ui.widgets.button import Button, ButtonStyle from openpilot.system.ui.widgets.button import Button, ButtonStyle
from openpilot.system.ui.widgets.label import Label from openpilot.system.ui.widgets.label import Label
@ -107,12 +108,12 @@ class TermsPage(Widget):
self._on_accept = on_accept self._on_accept = on_accept
self._on_decline = on_decline self._on_decline = on_decline
self._title = Label("Welcome to openpilot", font_size=90, font_weight=FontWeight.BOLD, text_alignment=rl.GuiTextAlignment.TEXT_ALIGN_LEFT) self._title = Label(tr("Welcome to openpilot"), font_size=90, font_weight=FontWeight.BOLD, text_alignment=rl.GuiTextAlignment.TEXT_ALIGN_LEFT)
self._desc = Label("You must accept the Terms and Conditions to use openpilot. Read the latest terms at https://comma.ai/terms before continuing.", self._desc = Label(tr("You must accept the Terms and Conditions to use openpilot. Read the latest terms at https://comma.ai/terms before continuing."),
font_size=90, font_weight=FontWeight.MEDIUM, text_alignment=rl.GuiTextAlignment.TEXT_ALIGN_LEFT) font_size=90, font_weight=FontWeight.MEDIUM, text_alignment=rl.GuiTextAlignment.TEXT_ALIGN_LEFT)
self._decline_btn = Button("Decline", click_callback=on_decline) self._decline_btn = Button(tr("Decline"), click_callback=on_decline)
self._accept_btn = Button("Agree", button_style=ButtonStyle.PRIMARY, click_callback=on_accept) self._accept_btn = Button(tr("Agree"), button_style=ButtonStyle.PRIMARY, click_callback=on_accept)
def _render(self, _): def _render(self, _):
welcome_x = self._rect.x + 165 welcome_x = self._rect.x + 165
@ -141,10 +142,10 @@ class TermsPage(Widget):
class DeclinePage(Widget): class DeclinePage(Widget):
def __init__(self, back_callback=None): def __init__(self, back_callback=None):
super().__init__() super().__init__()
self._text = Label("You must accept the Terms and Conditions in order to use openpilot.", self._text = Label(tr("You must accept the Terms and Conditions in order to use openpilot."),
font_size=90, font_weight=FontWeight.MEDIUM, text_alignment=rl.GuiTextAlignment.TEXT_ALIGN_LEFT) font_size=90, font_weight=FontWeight.MEDIUM, text_alignment=rl.GuiTextAlignment.TEXT_ALIGN_LEFT)
self._back_btn = Button("Back", click_callback=back_callback) self._back_btn = Button(tr("Back"), click_callback=back_callback)
self._uninstall_btn = Button("Decline, uninstall openpilot", button_style=ButtonStyle.DANGER, self._uninstall_btn = Button(tr("Decline, uninstall openpilot"), button_style=ButtonStyle.DANGER,
click_callback=self._on_uninstall_clicked) click_callback=self._on_uninstall_clicked)
def _on_uninstall_clicked(self): def _on_uninstall_clicked(self):

@ -6,19 +6,20 @@ from openpilot.system.ui.widgets.list_view import toggle_item
from openpilot.system.ui.widgets.scroller import Scroller from openpilot.system.ui.widgets.scroller import Scroller
from openpilot.system.ui.widgets.confirm_dialog import ConfirmDialog from openpilot.system.ui.widgets.confirm_dialog import ConfirmDialog
from openpilot.system.ui.lib.application import gui_app from openpilot.system.ui.lib.application import gui_app
from openpilot.system.ui.lib.multilang import tr
from openpilot.system.ui.widgets import DialogResult from openpilot.system.ui.widgets import DialogResult
# Description constants # Description constants
DESCRIPTIONS = { DESCRIPTIONS = {
'enable_adb': ( 'enable_adb': tr(
"ADB (Android Debug Bridge) allows connecting to your device over USB or over the network. " + "ADB (Android Debug Bridge) allows connecting to your device over USB or over the network. " +
"See https://docs.comma.ai/how-to/connect-to-comma for more info." "See https://docs.comma.ai/how-to/connect-to-comma for more info."
), ),
'ssh_key': ( 'ssh_key': tr(
"Warning: This grants SSH access to all public keys in your GitHub settings. Never enter a GitHub username " + "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." "other than your own. A comma employee will NEVER ask you to add their GitHub username."
), ),
'alpha_longitudinal': ( 'alpha_longitudinal': tr(
"<b>WARNING: openpilot longitudinal control is in alpha for this car and will disable Automatic Emergency Braking (AEB).</b><br><br>" + "<b>WARNING: openpilot longitudinal control is in alpha for this car and will disable Automatic Emergency Braking (AEB).</b><br><br>" +
"On this car, openpilot defaults to the car's built-in ACC instead of openpilot's longitudinal control. " + "On this car, openpilot defaults to the car's built-in ACC instead of openpilot's longitudinal control. " +
"Enable this to switch to openpilot longitudinal control. Enabling Experimental mode is recommended when enabling openpilot longitudinal control alpha." "Enable this to switch to openpilot longitudinal control. Enabling Experimental mode is recommended when enabling openpilot longitudinal control alpha."
@ -34,7 +35,7 @@ class DeveloperLayout(Widget):
# Build items and keep references for callbacks/state updates # Build items and keep references for callbacks/state updates
self._adb_toggle = toggle_item( self._adb_toggle = toggle_item(
"Enable ADB", tr("Enable ADB"),
description=DESCRIPTIONS["enable_adb"], description=DESCRIPTIONS["enable_adb"],
initial_state=self._params.get_bool("AdbEnabled"), initial_state=self._params.get_bool("AdbEnabled"),
callback=self._on_enable_adb, callback=self._on_enable_adb,
@ -43,7 +44,7 @@ class DeveloperLayout(Widget):
# SSH enable toggle + SSH key management # SSH enable toggle + SSH key management
self._ssh_toggle = toggle_item( self._ssh_toggle = toggle_item(
"Enable SSH", tr("Enable SSH"),
description="", description="",
initial_state=self._params.get_bool("SshEnabled"), initial_state=self._params.get_bool("SshEnabled"),
callback=self._on_enable_ssh, callback=self._on_enable_ssh,
@ -51,7 +52,7 @@ class DeveloperLayout(Widget):
self._ssh_keys = ssh_key_item("SSH Keys", description=DESCRIPTIONS["ssh_key"]) self._ssh_keys = ssh_key_item("SSH Keys", description=DESCRIPTIONS["ssh_key"])
self._joystick_toggle = toggle_item( self._joystick_toggle = toggle_item(
"Joystick Debug Mode", tr("Joystick Debug Mode"),
description="", description="",
initial_state=self._params.get_bool("JoystickDebugMode"), initial_state=self._params.get_bool("JoystickDebugMode"),
callback=self._on_joystick_debug_mode, callback=self._on_joystick_debug_mode,
@ -59,14 +60,14 @@ class DeveloperLayout(Widget):
) )
self._long_maneuver_toggle = toggle_item( self._long_maneuver_toggle = toggle_item(
"Longitudinal Maneuver Mode", tr("Longitudinal Maneuver Mode"),
description="", description="",
initial_state=self._params.get_bool("LongitudinalManeuverMode"), initial_state=self._params.get_bool("LongitudinalManeuverMode"),
callback=self._on_long_maneuver_mode, callback=self._on_long_maneuver_mode,
) )
self._alpha_long_toggle = toggle_item( self._alpha_long_toggle = toggle_item(
"openpilot Longitudinal Control (Alpha)", tr("openpilot Longitudinal Control (Alpha)"),
description=DESCRIPTIONS["alpha_longitudinal"], description=DESCRIPTIONS["alpha_longitudinal"],
initial_state=self._params.get_bool("AlphaLongitudinalEnabled"), initial_state=self._params.get_bool("AlphaLongitudinalEnabled"),
callback=self._on_alpha_long_enabled, callback=self._on_alpha_long_enabled,

@ -49,24 +49,23 @@ class DeviceLayout(Widget):
dongle_id = self._params.get("DongleId") or "N/A" dongle_id = self._params.get("DongleId") or "N/A"
serial = self._params.get("HardwareSerial") or "N/A" serial = self._params.get("HardwareSerial") or "N/A"
self._pair_device_btn = button_item("Pair Device", "PAIR", DESCRIPTIONS['pair_device'], callback=self._pair_device) self._pair_device_btn = button_item(tr("Pair Device"), tr("PAIR"), DESCRIPTIONS['pair_device'], callback=self._pair_device)
self._pair_device_btn.set_visible(lambda: not ui_state.prime_state.is_paired()) self._pair_device_btn.set_visible(lambda: not ui_state.prime_state.is_paired())
self._reset_calib_btn = button_item("Reset Calibration", "RESET", DESCRIPTIONS['reset_calibration'], callback=self._reset_calibration_prompt) self._reset_calib_btn = button_item(tr("Reset Calibration"), tr("RESET"), DESCRIPTIONS['reset_calibration'], callback=self._reset_calibration_prompt)
self._reset_calib_btn.set_description_opened_callback(self._update_calib_description) self._reset_calib_btn.set_description_opened_callback(self._update_calib_description)
self._power_off_btn = dual_button_item("Reboot", "Power Off", left_callback=self._reboot_prompt, right_callback=self._power_off_prompt) self._power_off_btn = dual_button_item(tr("Reboot"), tr("Power Off"), left_callback=self._reboot_prompt, right_callback=self._power_off_prompt)
items = [ items = [
text_item("Dongle ID", dongle_id), text_item(tr("Dongle ID"), dongle_id),
text_item("Serial", serial), text_item(tr("Serial"), serial),
self._pair_device_btn, self._pair_device_btn,
button_item("Driver Camera", "PREVIEW", DESCRIPTIONS['driver_camera'], callback=self._show_driver_camera, enabled=ui_state.is_offroad), button_item(tr("Driver Camera"), tr("PREVIEW"), DESCRIPTIONS['driver_camera'], callback=self._show_driver_camera, enabled=ui_state.is_offroad),
self._reset_calib_btn, self._reset_calib_btn,
button_item("Review Training Guide", "REVIEW", DESCRIPTIONS['review_guide'], self._on_review_training_guide, enabled=ui_state.is_offroad), button_item(tr("Review Training Guide"), tr("REVIEW"), DESCRIPTIONS['review_guide'], self._on_review_training_guide, enabled=ui_state.is_offroad),
regulatory_btn := button_item("Regulatory", "VIEW", callback=self._on_regulatory, enabled=ui_state.is_offroad), regulatory_btn := button_item(tr("Regulatory"), tr("VIEW"), callback=self._on_regulatory, enabled=ui_state.is_offroad),
# TODO: implement multilang button_item(tr("Change Language"), tr("CHANGE"), callback=self._show_language_dialog, enabled=ui_state.is_offroad),
button_item("Change Language", "CHANGE", callback=self._show_language_dialog, enabled=ui_state.is_offroad),
self._power_off_btn, self._power_off_btn,
] ]
regulatory_btn.set_visible(TICI) regulatory_btn.set_visible(TICI)
@ -108,7 +107,7 @@ class DeviceLayout(Widget):
def _reset_calibration_prompt(self): def _reset_calibration_prompt(self):
if ui_state.engaged: if ui_state.engaged:
gui_app.set_modal_overlay(alert_dialog("Disengage to Reset Calibration")) gui_app.set_modal_overlay(alert_dialog(tr("Disengage to Reset Calibration")))
return return
def reset_calibration(result: int): def reset_calibration(result: int):
@ -124,7 +123,7 @@ class DeviceLayout(Widget):
self._params.put_bool("OnroadCycleRequested", True) self._params.put_bool("OnroadCycleRequested", True)
self._update_calib_description() self._update_calib_description()
dialog = ConfirmDialog("Are you sure you want to reset calibration?", "Reset") dialog = ConfirmDialog(tr("Are you sure you want to reset calibration?"), tr("Reset"))
gui_app.set_modal_overlay(dialog, callback=reset_calibration) gui_app.set_modal_overlay(dialog, callback=reset_calibration)
def _update_calib_description(self): def _update_calib_description(self):
@ -176,10 +175,10 @@ class DeviceLayout(Widget):
def _reboot_prompt(self): def _reboot_prompt(self):
if ui_state.engaged: if ui_state.engaged:
gui_app.set_modal_overlay(alert_dialog("Disengage to Reboot")) gui_app.set_modal_overlay(alert_dialog(tr("Disengage to Reboot")))
return return
dialog = ConfirmDialog("Are you sure you want to reboot?", "Reboot") dialog = ConfirmDialog(tr("Are you sure you want to reboot?"), tr("Reboot"))
gui_app.set_modal_overlay(dialog, callback=self._perform_reboot) gui_app.set_modal_overlay(dialog, callback=self._perform_reboot)
def _perform_reboot(self, result: int): def _perform_reboot(self, result: int):
@ -188,10 +187,10 @@ class DeviceLayout(Widget):
def _power_off_prompt(self): def _power_off_prompt(self):
if ui_state.engaged: if ui_state.engaged:
gui_app.set_modal_overlay(alert_dialog("Disengage to Power Off")) gui_app.set_modal_overlay(alert_dialog(tr("Disengage to Power Off")))
return return
dialog = ConfirmDialog("Are you sure you want to power off?", "Power Off") dialog = ConfirmDialog(tr("Are you sure you want to power off?"), tr("Power Off"))
gui_app.set_modal_overlay(dialog, callback=self._perform_power_off) gui_app.set_modal_overlay(dialog, callback=self._perform_power_off)
def _perform_power_off(self, result: int): def _perform_power_off(self, result: int):

@ -8,19 +8,20 @@ from openpilot.common.swaglog import cloudlog
from openpilot.selfdrive.ui.ui_state import ui_state from openpilot.selfdrive.ui.ui_state import ui_state
from openpilot.system.athena.registration import UNREGISTERED_DONGLE_ID from openpilot.system.athena.registration import UNREGISTERED_DONGLE_ID
from openpilot.system.ui.lib.application import gui_app, FontWeight, FONT_SCALE from openpilot.system.ui.lib.application import gui_app, FontWeight, FONT_SCALE
from openpilot.system.ui.lib.multilang import tr, trn
from openpilot.system.ui.lib.text_measure import measure_text_cached from openpilot.system.ui.lib.text_measure import measure_text_cached
from openpilot.system.ui.lib.scroll_panel import GuiScrollPanel from openpilot.system.ui.lib.scroll_panel import GuiScrollPanel
from openpilot.system.ui.lib.wrap_text import wrap_text from openpilot.system.ui.lib.wrap_text import wrap_text
from openpilot.system.ui.widgets import Widget from openpilot.system.ui.widgets import Widget
from openpilot.selfdrive.ui.lib.api_helpers import get_token from openpilot.selfdrive.ui.lib.api_helpers import get_token
TITLE = "Firehose Mode" TITLE = tr("Firehose Mode")
DESCRIPTION = ( DESCRIPTION = tr(
"openpilot learns to drive by watching humans, like you, drive.\n\n" "openpilot learns to drive by watching humans, like you, drive.\n\n"
+ "Firehose Mode allows you to maximize your training data uploads to improve " + "Firehose Mode allows you to maximize your training data uploads to improve "
+ "openpilot's driving models. More data means bigger models, which means better Experimental Mode." + "openpilot's driving models. More data means bigger models, which means better Experimental Mode."
) )
INSTRUCTIONS = ( INSTRUCTIONS = tr(
"For maximum effectiveness, bring your device inside and connect to a good USB-C adapter and Wi-Fi weekly.\n\n" "For maximum effectiveness, bring your device inside and connect to a good USB-C adapter and Wi-Fi weekly.\n\n"
+ "Firehose Mode can also work while you're driving if connected to a hotspot or unlimited SIM card.\n\n\n" + "Firehose Mode can also work while you're driving if connected to a hotspot or unlimited SIM card.\n\n\n"
+ "Frequently Asked Questions\n\n" + "Frequently Asked Questions\n\n"
@ -106,7 +107,8 @@ class FirehoseLayout(Widget):
# Contribution count (if available) # Contribution count (if available)
if self.segment_count > 0: if self.segment_count > 0:
contrib_text = f"{self.segment_count} segment(s) of your driving is in the training dataset so far." contrib_text = trn("{} segment of your driving is in the training dataset so far.",
"{} segment of your driving is in the training dataset so far.", self.segment_count).format(self.segment_count)
y = self._draw_wrapped_text(x, y, w, contrib_text, gui_app.font(FontWeight.BOLD), 52, rl.WHITE) y = self._draw_wrapped_text(x, y, w, contrib_text, gui_app.font(FontWeight.BOLD), 52, rl.WHITE)
y += 20 + 20 y += 20 + 20
@ -132,9 +134,9 @@ class FirehoseLayout(Widget):
network_metered = ui_state.sm["deviceState"].networkMetered network_metered = ui_state.sm["deviceState"].networkMetered
if not network_metered and network_type != 0: # Not metered and connected if not network_metered and network_type != 0: # Not metered and connected
return "ACTIVE", self.GREEN return tr("ACTIVE"), self.GREEN
else: else:
return "INACTIVE: connect to an unmetered network", self.RED return tr("INACTIVE: connect to an unmetered network"), self.RED
def _fetch_firehose_stats(self): def _fetch_firehose_stats(self):
try: try:

@ -8,6 +8,7 @@ from openpilot.selfdrive.ui.layouts.settings.firehose import FirehoseLayout
from openpilot.selfdrive.ui.layouts.settings.software import SoftwareLayout from openpilot.selfdrive.ui.layouts.settings.software import SoftwareLayout
from openpilot.selfdrive.ui.layouts.settings.toggles import TogglesLayout from openpilot.selfdrive.ui.layouts.settings.toggles import TogglesLayout
from openpilot.system.ui.lib.application import gui_app, FontWeight, MousePos from openpilot.system.ui.lib.application import gui_app, FontWeight, MousePos
from openpilot.system.ui.lib.multilang import tr
from openpilot.system.ui.lib.text_measure import measure_text_cached from openpilot.system.ui.lib.text_measure import measure_text_cached
from openpilot.system.ui.lib.wifi_manager import WifiManager from openpilot.system.ui.lib.wifi_manager import WifiManager
from openpilot.system.ui.widgets import Widget from openpilot.system.ui.widgets import Widget
@ -58,12 +59,12 @@ class SettingsLayout(Widget):
wifi_manager.set_active(False) wifi_manager.set_active(False)
self._panels = { self._panels = {
PanelType.DEVICE: PanelInfo("Device", DeviceLayout()), PanelType.DEVICE: PanelInfo(tr("Device"), DeviceLayout()),
PanelType.NETWORK: PanelInfo("Network", NetworkUI(wifi_manager)), PanelType.NETWORK: PanelInfo(tr("Network"), NetworkUI(wifi_manager)),
PanelType.TOGGLES: PanelInfo("Toggles", TogglesLayout()), PanelType.TOGGLES: PanelInfo(tr("Toggles"), TogglesLayout()),
PanelType.SOFTWARE: PanelInfo("Software", SoftwareLayout()), PanelType.SOFTWARE: PanelInfo(tr("Software"), SoftwareLayout()),
PanelType.FIREHOSE: PanelInfo("Firehose", FirehoseLayout()), PanelType.FIREHOSE: PanelInfo(tr("Firehose"), FirehoseLayout()),
PanelType.DEVELOPER: PanelInfo("Developer", DeveloperLayout()), PanelType.DEVELOPER: PanelInfo(tr("Developer"), DeveloperLayout()),
} }
self._font_medium = gui_app.font(FontWeight.MEDIUM) self._font_medium = gui_app.font(FontWeight.MEDIUM)

@ -4,6 +4,7 @@ import datetime
from openpilot.common.time_helpers import system_time_valid from openpilot.common.time_helpers import system_time_valid
from openpilot.selfdrive.ui.ui_state import ui_state from openpilot.selfdrive.ui.ui_state import ui_state
from openpilot.system.ui.lib.application import gui_app from openpilot.system.ui.lib.application import gui_app
from openpilot.system.ui.lib.multilang import tr, trn
from openpilot.system.ui.widgets import Widget, DialogResult from openpilot.system.ui.widgets import Widget, DialogResult
from openpilot.system.ui.widgets.confirm_dialog import ConfirmDialog from openpilot.system.ui.widgets.confirm_dialog import ConfirmDialog
from openpilot.system.ui.widgets.list_view import button_item, text_item, ListItem from openpilot.system.ui.widgets.list_view import button_item, text_item, ListItem
@ -15,7 +16,7 @@ UPDATED_TIMEOUT = 10 # seconds to wait for updated to respond
def time_ago(date: datetime.datetime | None) -> str: def time_ago(date: datetime.datetime | None) -> str:
if not date: if not date:
return "never" return tr("never")
if not system_time_valid(): if not system_time_valid():
return date.strftime("%a %b %d %Y") return date.strftime("%a %b %d %Y")
@ -26,16 +27,16 @@ def time_ago(date: datetime.datetime | None) -> str:
diff_seconds = int((now - date).total_seconds()) diff_seconds = int((now - date).total_seconds())
if diff_seconds < 60: if diff_seconds < 60:
return "now" return tr("now")
if diff_seconds < 3600: if diff_seconds < 3600:
m = diff_seconds // 60 m = diff_seconds // 60
return f"{m} minute{'s' if m != 1 else ''} ago" return trn("{} minute ago", "{} minutes ago", m).format(m)
if diff_seconds < 86400: if diff_seconds < 86400:
h = diff_seconds // 3600 h = diff_seconds // 3600
return f"{h} hour{'s' if h != 1 else ''} ago" return trn("{} hour ago", "{} hours ago", h).format(h)
if diff_seconds < 604800: if diff_seconds < 604800:
d = diff_seconds // 86400 d = diff_seconds // 86400
return f"{d} day{'s' if d != 1 else ''} ago" return trn("{} day ago", "{} days ago", d).format(d)
return date.strftime("%a %b %d %Y") return date.strftime("%a %b %d %Y")
@ -43,12 +44,12 @@ class SoftwareLayout(Widget):
def __init__(self): def __init__(self):
super().__init__() super().__init__()
self._onroad_label = ListItem(title="Updates are only downloaded while the car is off.") self._onroad_label = ListItem(title=tr("Updates are only downloaded while the car is off."))
self._version_item = text_item("Current Version", ui_state.params.get("UpdaterCurrentDescription") or "") self._version_item = text_item(tr("Current Version"), ui_state.params.get("UpdaterCurrentDescription") or "")
self._download_btn = button_item("Download", "CHECK", callback=self._on_download_update) self._download_btn = button_item(tr("Download"), tr("CHECK"), callback=self._on_download_update)
# Install button is initially hidden # Install button is initially hidden
self._install_btn = button_item("Install Update", "INSTALL", callback=self._on_install_update) self._install_btn = button_item(tr("Install Update"), tr("INSTALL"), callback=self._on_install_update)
self._install_btn.set_visible(False) self._install_btn.set_visible(False)
# Track waiting-for-updater transition to avoid brief re-enable while still idle # Track waiting-for-updater transition to avoid brief re-enable while still idle
@ -66,7 +67,7 @@ class SoftwareLayout(Widget):
self._install_btn, self._install_btn,
# TODO: implement branch switching # TODO: implement branch switching
# button_item("Target Branch", "SELECT", callback=self._on_select_branch), # button_item("Target Branch", "SELECT", callback=self._on_select_branch),
button_item("Uninstall", "UNINSTALL", callback=self._on_uninstall), button_item("Uninstall", tr("UNINSTALL"), callback=self._on_uninstall),
] ]
return items return items
@ -101,19 +102,19 @@ class SoftwareLayout(Widget):
self._download_btn.action_item.set_value(updater_state) self._download_btn.action_item.set_value(updater_state)
else: else:
if failed_count > 0: if failed_count > 0:
self._download_btn.action_item.set_value("failed to check for update") self._download_btn.action_item.set_value(tr("failed to check for update"))
self._download_btn.action_item.set_text("CHECK") self._download_btn.action_item.set_text(tr("CHECK"))
elif fetch_available: elif fetch_available:
self._download_btn.action_item.set_value("update available") self._download_btn.action_item.set_value(tr("update available"))
self._download_btn.action_item.set_text("DOWNLOAD") self._download_btn.action_item.set_text(tr("DOWNLOAD"))
else: else:
last_update = ui_state.params.get("LastUpdateTime") last_update = ui_state.params.get("LastUpdateTime")
if last_update: if last_update:
formatted = time_ago(last_update) formatted = time_ago(last_update)
self._download_btn.action_item.set_value(f"up to date, last checked {formatted}") self._download_btn.action_item.set_value(tr("up to date, last checked {}").format(formatted))
else: else:
self._download_btn.action_item.set_value("up to date, last checked never") self._download_btn.action_item.set_value(tr("up to date, last checked never"))
self._download_btn.action_item.set_text("CHECK") self._download_btn.action_item.set_text(tr("CHECK"))
# If we've been waiting too long without a state change, reset state # If we've been waiting too long without a state change, reset state
if self._waiting_for_updater and (time.monotonic() - self._waiting_start_ts > UPDATED_TIMEOUT): if self._waiting_for_updater and (time.monotonic() - self._waiting_start_ts > UPDATED_TIMEOUT):
@ -127,7 +128,7 @@ class SoftwareLayout(Widget):
if update_available: if update_available:
new_desc = ui_state.params.get("UpdaterNewDescription") or "" new_desc = ui_state.params.get("UpdaterNewDescription") or ""
new_release_notes = (ui_state.params.get("UpdaterNewReleaseNotes") or b"").decode("utf-8", "replace") new_release_notes = (ui_state.params.get("UpdaterNewReleaseNotes") or b"").decode("utf-8", "replace")
self._install_btn.action_item.set_text("INSTALL") self._install_btn.action_item.set_text(tr("INSTALL"))
self._install_btn.action_item.set_value(new_desc) self._install_btn.action_item.set_value(new_desc)
self._install_btn.set_description(new_release_notes) self._install_btn.set_description(new_release_notes)
# Enable install button for testing (like Qt showEvent) # Enable install button for testing (like Qt showEvent)
@ -138,7 +139,7 @@ class SoftwareLayout(Widget):
def _on_download_update(self): def _on_download_update(self):
# Check if we should start checking or start downloading # Check if we should start checking or start downloading
self._download_btn.action_item.set_enabled(False) self._download_btn.action_item.set_enabled(False)
if self._download_btn.action_item.text == "CHECK": if self._download_btn.action_item.text == tr("CHECK"):
# Start checking for updates # Start checking for updates
self._waiting_for_updater = True self._waiting_for_updater = True
self._waiting_start_ts = time.monotonic() self._waiting_start_ts = time.monotonic()
@ -154,7 +155,7 @@ class SoftwareLayout(Widget):
if result == DialogResult.CONFIRM: if result == DialogResult.CONFIRM:
ui_state.params.put_bool("DoUninstall", True) ui_state.params.put_bool("DoUninstall", True)
dialog = ConfirmDialog("Are you sure you want to uninstall?", "Uninstall") dialog = ConfirmDialog(tr("Are you sure you want to uninstall?"), tr("Uninstall"))
gui_app.set_modal_overlay(dialog, callback=handle_uninstall_confirmation) gui_app.set_modal_overlay(dialog, callback=handle_uninstall_confirmation)
def _on_install_update(self): def _on_install_update(self):

@ -43,49 +43,49 @@ class TogglesLayout(Widget):
# param, title, desc, icon, needs_restart # param, title, desc, icon, needs_restart
self._toggle_defs = { self._toggle_defs = {
"OpenpilotEnabledToggle": ( "OpenpilotEnabledToggle": (
"Enable openpilot", tr("Enable openpilot"),
DESCRIPTIONS["OpenpilotEnabledToggle"], DESCRIPTIONS["OpenpilotEnabledToggle"],
"chffr_wheel.png", "chffr_wheel.png",
True, True,
), ),
"ExperimentalMode": ( "ExperimentalMode": (
"Experimental Mode", tr("Experimental Mode"),
"", "",
"experimental_white.png", "experimental_white.png",
False, False,
), ),
"DisengageOnAccelerator": ( "DisengageOnAccelerator": (
"Disengage on Accelerator Pedal", tr("Disengage on Accelerator Pedal"),
DESCRIPTIONS["DisengageOnAccelerator"], DESCRIPTIONS["DisengageOnAccelerator"],
"disengage_on_accelerator.png", "disengage_on_accelerator.png",
False, False,
), ),
"IsLdwEnabled": ( "IsLdwEnabled": (
"Enable Lane Departure Warnings", tr("Enable Lane Departure Warnings"),
DESCRIPTIONS["IsLdwEnabled"], DESCRIPTIONS["IsLdwEnabled"],
"warning.png", "warning.png",
False, False,
), ),
"AlwaysOnDM": ( "AlwaysOnDM": (
"Always-On Driver Monitoring", tr("Always-On Driver Monitoring"),
DESCRIPTIONS["AlwaysOnDM"], DESCRIPTIONS["AlwaysOnDM"],
"monitoring.png", "monitoring.png",
False, False,
), ),
"RecordFront": ( "RecordFront": (
"Record and Upload Driver Camera", tr("Record and Upload Driver Camera"),
DESCRIPTIONS["RecordFront"], DESCRIPTIONS["RecordFront"],
"monitoring.png", "monitoring.png",
True, True,
), ),
"RecordAudio": ( "RecordAudio": (
"Record and Upload Microphone Audio", tr("Record and Upload Microphone Audio"),
DESCRIPTIONS["RecordAudio"], DESCRIPTIONS["RecordAudio"],
"microphone.png", "microphone.png",
True, True,
), ),
"IsMetric": ( "IsMetric": (
"Use Metric System", tr("Use Metric System"),
DESCRIPTIONS["IsMetric"], DESCRIPTIONS["IsMetric"],
"metric.png", "metric.png",
False, False,
@ -93,9 +93,9 @@ class TogglesLayout(Widget):
} }
self._long_personality_setting = multiple_button_item( self._long_personality_setting = multiple_button_item(
"Driving Personality", tr("Driving Personality"),
DESCRIPTIONS["LongitudinalPersonality"], DESCRIPTIONS["LongitudinalPersonality"],
buttons=["Aggressive", "Standard", "Relaxed"], buttons=[tr("Aggressive"), tr("Standard"), tr("Relaxed")],
button_width=255, button_width=255,
callback=self._set_longitudinal_personality, callback=self._set_longitudinal_personality,
selected_index=self._params.get("LongitudinalPersonality", return_default=True), selected_index=self._params.get("LongitudinalPersonality", return_default=True),
@ -120,7 +120,7 @@ class TogglesLayout(Widget):
toggle.action_item.set_enabled(not locked) toggle.action_item.set_enabled(not locked)
if needs_restart and not locked: if needs_restart and not locked:
toggle.set_description(toggle.description + " Changing this setting will restart openpilot if the car is powered on.") toggle.set_description(toggle.description + tr(" Changing this setting will restart openpilot if the car is powered on."))
# track for engaged state updates # track for engaged state updates
if locked: if locked:
@ -151,7 +151,7 @@ class TogglesLayout(Widget):
def _update_toggles(self): def _update_toggles(self):
ui_state.update_params() ui_state.update_params()
e2e_description = ( e2e_description = tr(
"openpilot defaults to driving in chill mode. Experimental mode enables alpha-level features that aren't ready for chill mode. " + "openpilot defaults to driving in chill mode. Experimental mode enables alpha-level features that aren't ready for chill mode. " +
"Experimental features are listed below:<br>" + "Experimental features are listed below:<br>" +
"<h4>End-to-End Longitudinal Control</h4><br>" + "<h4>End-to-End Longitudinal Control</h4><br>" +
@ -175,15 +175,15 @@ class TogglesLayout(Widget):
self._long_personality_setting.action_item.set_enabled(False) self._long_personality_setting.action_item.set_enabled(False)
self._params.remove("ExperimentalMode") self._params.remove("ExperimentalMode")
unavailable = "Experimental mode is currently unavailable on this car since the car's stock ACC is used for longitudinal control." unavailable = tr("Experimental mode is currently unavailable on this car since the car's stock ACC is used for longitudinal control.")
long_desc = unavailable + " openpilot longitudinal control may come in a future update." long_desc = unavailable + " " + tr("openpilot longitudinal control may come in a future update.")
if ui_state.CP.alphaLongitudinalAvailable: if ui_state.CP.alphaLongitudinalAvailable:
if self._is_release: if self._is_release:
long_desc = unavailable + " " + ("An alpha version of openpilot longitudinal control can be tested, along with " + long_desc = unavailable + " " + tr("An alpha version of openpilot longitudinal control can be tested, along with " +
"Experimental mode, on non-release branches.") "Experimental mode, on non-release branches.")
else: else:
long_desc = "Enable the openpilot longitudinal control (alpha) toggle to allow Experimental mode." long_desc = tr("Enable the openpilot longitudinal control (alpha) toggle to allow Experimental mode.")
self._toggles["ExperimentalMode"].set_description("<b>" + long_desc + "</b><br><br>" + e2e_description) self._toggles["ExperimentalMode"].set_description("<b>" + long_desc + "</b><br><br>" + e2e_description)
else: else:
@ -222,7 +222,7 @@ class TogglesLayout(Widget):
# show confirmation dialog # show confirmation dialog
content = (f"<h1>{self._toggles['ExperimentalMode'].title}</h1><br>" + content = (f"<h1>{self._toggles['ExperimentalMode'].title}</h1><br>" +
f"<p>{self._toggles['ExperimentalMode'].description}</p>") f"<p>{self._toggles['ExperimentalMode'].description}</p>")
dlg = ConfirmDialog(content, "Enable", rich=True) dlg = ConfirmDialog(content, tr("Enable"), rich=True)
gui_app.set_modal_overlay(dlg, callback=confirm_callback) gui_app.set_modal_overlay(dlg, callback=confirm_callback)
else: else:
self._update_experimental_mode_icon() self._update_experimental_mode_icon()

@ -5,6 +5,7 @@ from collections.abc import Callable
from cereal import log from cereal import log
from openpilot.selfdrive.ui.ui_state import ui_state from openpilot.selfdrive.ui.ui_state import ui_state
from openpilot.system.ui.lib.application import gui_app, FontWeight, MousePos, FONT_SCALE from openpilot.system.ui.lib.application import gui_app, FontWeight, MousePos, FONT_SCALE
from openpilot.system.ui.lib.multilang import tr
from openpilot.system.ui.lib.text_measure import measure_text_cached from openpilot.system.ui.lib.text_measure import measure_text_cached
from openpilot.system.ui.widgets import Widget from openpilot.system.ui.widgets import Widget
@ -39,13 +40,13 @@ class Colors:
NETWORK_TYPES = { NETWORK_TYPES = {
NetworkType.none: "--", NetworkType.none: tr("--"),
NetworkType.wifi: "Wi-Fi", NetworkType.wifi: tr("Wi-Fi"),
NetworkType.ethernet: "ETH", NetworkType.ethernet: tr("ETH"),
NetworkType.cell2G: "2G", NetworkType.cell2G: tr("2G"),
NetworkType.cell3G: "3G", NetworkType.cell3G: tr("3G"),
NetworkType.cell4G: "LTE", NetworkType.cell4G: tr("LTE"),
NetworkType.cell5G: "5G", NetworkType.cell5G: tr("5G"),
} }
@ -67,9 +68,9 @@ class Sidebar(Widget):
self._net_type = NETWORK_TYPES.get(NetworkType.none) self._net_type = NETWORK_TYPES.get(NetworkType.none)
self._net_strength = 0 self._net_strength = 0
self._temp_status = MetricData("TEMP", "GOOD", Colors.GOOD) self._temp_status = MetricData(tr("TEMP"), tr("GOOD"), Colors.GOOD)
self._panda_status = MetricData("VEHICLE", "ONLINE", Colors.GOOD) self._panda_status = MetricData(tr("VEHICLE"), tr("ONLINE"), Colors.GOOD)
self._connect_status = MetricData("CONNECT", "OFFLINE", Colors.WARNING) self._connect_status = MetricData(tr("CONNECT"), tr("OFFLINE"), Colors.WARNING)
self._recording_audio = False self._recording_audio = False
self._home_img = gui_app.texture("images/button_home.png", HOME_BTN.width, HOME_BTN.height) self._home_img = gui_app.texture("images/button_home.png", HOME_BTN.width, HOME_BTN.height)
@ -113,7 +114,7 @@ class Sidebar(Widget):
self._update_panda_status() self._update_panda_status()
def _update_network_status(self, device_state): def _update_network_status(self, device_state):
self._net_type = NETWORK_TYPES.get(device_state.networkType.raw, "Unknown") self._net_type = NETWORK_TYPES.get(device_state.networkType.raw, tr("Unknown"))
strength = device_state.networkStrength strength = device_state.networkStrength
self._net_strength = max(0, min(5, strength.raw + 1)) if strength > 0 else 0 self._net_strength = max(0, min(5, strength.raw + 1)) if strength > 0 else 0
@ -121,26 +122,26 @@ class Sidebar(Widget):
thermal_status = device_state.thermalStatus thermal_status = device_state.thermalStatus
if thermal_status == ThermalStatus.green: if thermal_status == ThermalStatus.green:
self._temp_status.update("TEMP", "GOOD", Colors.GOOD) self._temp_status.update(tr("TEMP"), tr("GOOD"), Colors.GOOD)
elif thermal_status == ThermalStatus.yellow: elif thermal_status == ThermalStatus.yellow:
self._temp_status.update("TEMP", "OK", Colors.WARNING) self._temp_status.update(tr("TEMP"), tr("OK"), Colors.WARNING)
else: else:
self._temp_status.update("TEMP", "HIGH", Colors.DANGER) self._temp_status.update(tr("TEMP"), tr("HIGH"), Colors.DANGER)
def _update_connection_status(self, device_state): def _update_connection_status(self, device_state):
last_ping = device_state.lastAthenaPingTime last_ping = device_state.lastAthenaPingTime
if last_ping == 0: if last_ping == 0:
self._connect_status.update("CONNECT", "OFFLINE", Colors.WARNING) self._connect_status.update(tr("CONNECT"), tr("OFFLINE"), Colors.WARNING)
elif time.monotonic_ns() - last_ping < 80_000_000_000: # 80 seconds in nanoseconds elif time.monotonic_ns() - last_ping < 80_000_000_000: # 80 seconds in nanoseconds
self._connect_status.update("CONNECT", "ONLINE", Colors.GOOD) self._connect_status.update(tr("CONNECT"), tr("ONLINE"), Colors.GOOD)
else: else:
self._connect_status.update("CONNECT", "ERROR", Colors.DANGER) self._connect_status.update(tr("CONNECT"), tr("ERROR"), Colors.DANGER)
def _update_panda_status(self): def _update_panda_status(self):
if ui_state.panda_type == log.PandaState.PandaType.unknown: if ui_state.panda_type == log.PandaState.PandaType.unknown:
self._panda_status.update("NO", "PANDA", Colors.DANGER) self._panda_status.update(tr("NO"), tr("PANDA"), Colors.DANGER)
else: else:
self._panda_status.update("VEHICLE", "ONLINE", Colors.GOOD) self._panda_status.update(tr("VEHICLE"), tr("ONLINE"), Colors.GOOD)
def _handle_mouse_release(self, mouse_pos: MousePos): def _handle_mouse_release(self, mouse_pos: MousePos):
if rl.check_collision_point_rec(mouse_pos, SETTINGS_BTN): if rl.check_collision_point_rec(mouse_pos, SETTINGS_BTN):

Loading…
Cancel
Save