diff --git a/app/src/App/DesktopApp.tsx b/app/src/App/DesktopApp.tsx index df2105007b3..34c09316f97 100644 --- a/app/src/App/DesktopApp.tsx +++ b/app/src/App/DesktopApp.tsx @@ -1,4 +1,5 @@ import { useState, Fragment } from 'react' +import { useTranslation } from 'react-i18next' import { Navigate, Route, Routes, useMatch } from 'react-router-dom' import { ErrorBoundary } from 'react-error-boundary' @@ -43,6 +44,7 @@ import { ReactQueryDevtools } from './tools' import type { RouteProps } from './types' export const DesktopApp = (): JSX.Element => { + const { t } = useTranslation('top_navigation') useSoftwareUpdatePoll() const [ isEmergencyStopModalDismissed, @@ -52,55 +54,55 @@ export const DesktopApp = (): JSX.Element => { const desktopRoutes: RouteProps[] = [ { Component: ProtocolsLanding, - name: 'protocols', + name: t('protocols'), navLinkTo: '/protocols', path: '/protocols', }, { Component: ProtocolDetails, - name: 'Protocol Details', + name: t('protocol_details'), path: '/protocols/:protocolKey', }, { Component: ProtocolTimeline, - name: 'Protocol Timeline', + name: t('protocol_timeline'), path: '/protocols/:protocolKey/timeline', }, { Component: Labware, - name: 'labware', + name: t('labware'), navLinkTo: '/labware', path: '/labware', }, { Component: DevicesLanding, - name: 'devices', + name: t('devices'), navLinkTo: '/devices', path: '/devices', }, { Component: DeviceDetails, - name: 'Device', + name: t('device'), path: '/devices/:robotName', }, { Component: RobotSettings, - name: 'Robot Settings', + name: t('robot_settings'), path: '/devices/:robotName/robot-settings/:robotSettingsTab?', }, { Component: CalibrationDashboard, - name: 'Calibration Dashboard', + name: t('calibration_dashboard'), path: '/devices/:robotName/robot-settings/calibration/dashboard', }, { Component: ProtocolRunDetails, - name: 'Run Details', + name: t('run_details'), path: '/devices/:robotName/protocol-runs/:runId/:protocolRunDetailsTab?', }, { Component: AppSettings, - name: 'App Settings', + name: t('app_settings'), path: '/app-settings/:appSettingsTab?', }, ] diff --git a/app/src/App/Navbar.tsx b/app/src/App/Navbar.tsx index 1471ca4c593..1d7711563ae 100644 --- a/app/src/App/Navbar.tsx +++ b/app/src/App/Navbar.tsx @@ -1,5 +1,4 @@ import { useCallback } from 'react' -import { useTranslation } from 'react-i18next' import { NavLink, useNavigate } from 'react-router-dom' import styled from 'styled-components' import debounce from 'lodash/debounce' @@ -111,8 +110,6 @@ const LogoImg = styled('img')` ` export function Navbar({ routes }: { routes: RouteProps[] }): JSX.Element { - const { t } = useTranslation('top_navigation') - const navigate = useNavigate() const navRoutes = routes.filter( ({ navLinkTo }: RouteProps) => navLinkTo != null @@ -151,7 +148,7 @@ export function Navbar({ routes }: { routes: RouteProps[] }): JSX.Element { as="h3" margin={`${SPACING.spacing8} 0 ${SPACING.spacing8} ${SPACING.spacing12}`} > - {t(name)} + {name} ))} diff --git a/app/src/assets/localization/en/app_settings.json b/app/src/assets/localization/en/app_settings.json index 1cdc29feab0..b8043fb9563 100644 --- a/app/src/assets/localization/en/app_settings.json +++ b/app/src/assets/localization/en/app_settings.json @@ -36,7 +36,9 @@ "connect_ip_link": "Learn more about connecting a robot manually", "discovery_timeout": "Discovery timed out.", "dont_change": "Don’t change", + "dont_remind_me": "Don't remind me again", "download_update": "Downloading update...", + "driver_out_of_date": "Realtek USB-to-Ethernet Driver Update Available", "enable_dev_tools": "Developer Tools", "enable_dev_tools_description": "Enabling this setting opens Developer Tools on app launch, enables additional logging and gives access to feature flags.", "error_boundary_desktop_app_description": "You need to reload the app. Contact support with the following error message:", @@ -45,6 +47,7 @@ "error_recovery_mode_description": "Pause on protocol errors instead of canceling the run.", "feature_flags": "Feature Flags", "general": "General", + "get_update": "get update", "heater_shaker_attach_description": "Display a reminder to attach the Heater-Shaker properly before running a test shake or using it in a protocol.", "heater_shaker_attach_visible": "Confirm Heater-Shaker Module Attachment", "how_to_restore": "How to Restore a Previous Software Version", @@ -65,6 +68,7 @@ "ot2_advanced_settings": "OT-2 Advanced Settings", "override_path": "override path", "override_path_to_python": "Override Path to Python", + "please_update_driver": "Please update your computer's driver to ensure a reliable connection to your OT-2.", "prevent_robot_caching": "Prevent Robot Caching", "prevent_robot_caching_description": "The app will immediately clear unavailable robots and will not remember unavailable robots while this is enabled. On networks with many robots, preventing caching may improve network performance at the expense of slower and less reliable robot discovery on app launch.", "privacy": "Privacy", @@ -93,6 +97,8 @@ "trash_bin": "Always use trash bin to calibrate", "try_restarting_the_update": "Try restarting the update.", "turn_off_updates": "Turn off software update notifications in App Settings.", + "u2e_driver_description": "The OT-2 uses this adapter for its USB connection to the Opentrons App.", + "u2e_driver_outdated_message": "There is an updated Realtek USB-to-Ethernet adapter driver available for your computer.", "up_to_date": "Up to date", "update_alerts": "Software Update Alerts", "update_app_now": "Update app now", @@ -112,5 +118,6 @@ "usb_to_ethernet_unknown_product": "Unknown Adapter", "use_system_language": "Use system language", "view_software_update": "View software update", + "view_adapter_info": "view adapter info", "view_update": "View Update" } diff --git a/app/src/assets/localization/en/device_settings.json b/app/src/assets/localization/en/device_settings.json index 79416a09f73..06a67d39d35 100644 --- a/app/src/assets/localization/en/device_settings.json +++ b/app/src/assets/localization/en/device_settings.json @@ -3,6 +3,7 @@ "about_calibration_description": "For the robot to move accurately and precisely, you need to calibrate it. Positional calibration happens in three parts: deck calibration, pipette offset calibration and tip length calibration.", "about_calibration_description_ot3": "For the robot to move accurately and precisely, you need to calibrate it. Pipette and gripper calibration is an automated process that uses a calibration probe or pin.After calibration is complete, you can save the calibration data to your computer as a JSON file.", "about_calibration_title": "About Calibration", + "add_new": "Add new...", "advanced": "Advanced", "alpha_description": "Warning: alpha releases are feature-complete but may contain significant bugs.", "alternative_security_types": "Alternative security types", @@ -10,10 +11,12 @@ "apply_historic_offsets": "Apply Labware Offsets", "are_you_sure_you_want_to_disconnect": "Are you sure you want to disconnect from {{ssid}}?", "attach_a_pipette_before_calibrating": "Attach a pipette in order to perform calibration", + "authentication": "Authentication", "boot_scripts": "Boot scripts", "both": "Both", "browse_file_system": "Browse file system", "bug_fixes": "Bug Fixes", + "but_we_expected": "but we expected", "calibrate_deck": "Calibrate deck", "calibrate_deck_description": "For pre-2019 robots that do not have crosses etched on the deck.", "calibrate_deck_to_dots": "Calibrate deck to dots", @@ -28,8 +31,10 @@ "change_network": "Change network", "characters_max": "17 characters max", "check_for_updates": "Check for updates", + "check_to_verify_update": "Check your robot's settings page to verify whether or not the update was successful", "checking_for_updates": "Checking for updates", "choose": "Choose...", + "choose_a_network": "Choose a network...", "choose_file": "Choose file", "choose_network_type": "Choose network type", "choose_reset_settings": "Choose reset settings", @@ -56,7 +61,9 @@ "confirm_device_reset_heading": "Are you sure you want to reset your device?", "connect": "Connect", "connect_the_estop_to_continue": "Connect the E-stop to continue", + "connect_to_ssid": "Connect to {{ssid}}", "connect_to_wifi_network": "Connect to Wi-Fi network", + "connect_to_wifi_network_failure": "Your robot was unable to connect to Wi-Fi network {{ssid}}", "connect_via": "Connect via {{type}}", "connect_via_usb_description_1": "1. Connect the USB A-to-B cable to the robot’s USB-B port.", "connect_via_usb_description_2": "2. Connect the cable to an open USB port on your computer.", @@ -65,6 +72,7 @@ "connected_to_ssid": "Connected to {{ssid}}", "connected_via": "Connected via {{networkInterface}}", "connecting_to": "Connecting to {{ssid}}...", + "connecting_to_wifi_network": "Connecting to Wi-Fi network {{ssid}}", "connection_description_ethernet": "Connect to your lab's wired network.", "connection_description_wifi": "Find a network in your lab or enter your own.", "connection_to_robot_lost": "Connection to robot lost", @@ -96,6 +104,7 @@ "display_sleep_settings": "Display Sleep Settings", "do_not_turn_off": "This could take up to {{minutes}} minutes. Don't turn off the robot.", "done": "Done", + "downgrade": "downgrade", "download": "Download", "download_calibration_data": "Download calibration logs", "download_error": "Download error", @@ -109,6 +118,7 @@ "enable_status_light_description": "Turn on or off the strip of color LEDs on the front of the robot.", "engaged": "Engaged", "enter_factory_password": "Enter factory password", + "enter_name_security_type": "Enter the network name and security type.", "enter_network_name": "Enter network name", "enter_password": "Enter password", "estop": "E-stop", @@ -127,6 +137,8 @@ "factory_resets_cannot_be_undone": "Factory resets cannot be undone.", "failed_to_connect_to_ssid": "Failed to connect to {{ssid}}", "feature_flags": "Feature Flags", + "field_is_required": "{{field}} is required", + "find_and_join_network": "Find and join a Wi-Fi network", "finish_setup": "Finish setup", "firmware_version": "Firmware Version", "fully_calibrate_before_checking_health": "Fully calibrate your robot before checking calibration health", @@ -154,6 +166,7 @@ "last_calibrated_label": "Last Calibrated", "launch_jupyter_notebook": "Launch Jupyter Notebook", "legacy_settings": "Legacy Settings", + "likely_incorrect_password": "Likely incorrect network password.", "mac_address": "MAC Address", "manage_oem_settings": "Manage OEM settings", "minutes": "{{minute}} minutes", @@ -171,7 +184,10 @@ "name_your_robot": "Name your robot", "name_your_robot_description": "Don’t worry, you can always change this in your settings.", "need_another_security_type": "Need another security type?", + "network_is_unsecured": "Wi-Fi network {{ssid}} is unsecured", "network_name": "Network Name", + "network_requires_auth": "Wi-Fi network {{ssid}} requires 802.1X authentication", + "network_requires_wpa_password": "Wi-Fi network {{ssid}} requires a WPA2 password", "network_settings": "Network Settings", "networking": "Networking", "never": "Never", @@ -183,6 +199,7 @@ "no_modules_attached": "No modules attached", "no_network_found": "No network found", "no_pipette_attached": "No pipette attached", + "no_update_files": "Unable to retrieve update for this robot. Ensure your computer is connected to the internet and try again later.", "none_description": "Not recommended", "not_calibrated": "Not calibrated yet", "not_calibrated_short": "Not calibrated", @@ -197,8 +214,10 @@ "on": "On", "one_hour": "1 hour", "other_networks": "Other Networks", + "other_robot_updating": "Unable to update because the app is currently updating a different robot.", "password": "Password", "password_error_message": "Must be at least 8 characters", + "password_not_long_enough": "Password must be at least {{minLength}} characters", "pause_protocol": "Pause protocol when robot door opens", "pause_protocol_description": "When enabled, opening the robot door during a run will pause the robot after it has completed its current motion.", "pipette_calibrations_description": "Pipette calibration uses a metal probe to determine the pipette's exact position relative to precision-cut squares on deck slots.", @@ -208,6 +227,7 @@ "pipette_offset_calibration_recommended": "Pipette Offset calibration recommended", "pipette_offset_calibrations_history": "See all Pipette Offset Calibration history", "pipette_offset_calibrations_title": "Pipette Offset Calibrations", + "please_check_credentials": "Please double-check your network credentials", "privacy": "Privacy", "problem_during_update": "This update is taking longer than usual.", "proceed_without_updating": "Proceed without update", @@ -238,9 +258,12 @@ "returns_your_device_to_new_state": "This returns your device to a new state.", "robot_busy_protocol": "This robot cannot be updated while a protocol is running on it", "robot_calibration_data": "Robot Calibration Data", + "robot_has_bad_capabilities": "Robot has incorrect capabilities shape", "robot_initializing": "Initializing robot...", "robot_name": "Robot Name", "robot_operating_update_available": "Robot Operating System Update Available", + "robot_reconnected_with version": "Robot reconnected with version", + "robot_requires_premigration": "This robot must be updated by the system before a custom update can occur", "robot_serial_number": "Robot Serial Number", "robot_server_version": "Robot Server Version", "robot_settings": "Robot Settings", @@ -259,7 +282,9 @@ "select_a_network": "Select a network", "select_a_security_type": "Select a security type", "select_all_settings": "Select all settings", + "select_auth_method_short": "Select authentication method", "select_authentication_method": "Select authentication method for your selected network.", + "select_file": "Select file", "sending_software": "Sending software...", "serial": "Serial", "setup_mode": "Setup mode", @@ -275,6 +300,9 @@ "subnet_mask": "Subnet Mask", "successfully_connected": "Successfully connected!", "successfully_connected_to_network": "Successfully connected to {{ssid}}!", + "successfully_connected_to_ssid": "Your robot has successfully connected to Wi-Fi network {{ssid}}", + "successfully_connected_to_wifi": "Successfully connected to Wi-Fi", + "successfully_disconnected_from_wifi": "Successfully disconnected from Wi-Fi", "supported_protocol_api_versions": "Supported Protocol API Versions", "text_size": "Text Size", "text_size_description": "Text on all screens will adjust to the size you choose below.", @@ -286,6 +314,14 @@ "troubleshooting": "Troubleshooting", "try_again": "Try again", "try_restarting_the_update": "Try restarting the update.", + "unable_to_cancel_update": "Unable to cancel in-progress update session", + "unable_to_commit_update": "Unable to commit update", + "unable_to_connect": "Unable to connect to Wi-Fi", + "unable_to_disconnect": "Unable to disconnect from Wi-Fi", + "unable_to_find_system_file": "Unable to find system file for update", + "unable_to_find_robot_with_name": "Unable to find online robot with name", + "unable_to_restart": "Unable to restart robot", + "unable_to_start_update_session": "Unable to start update session", "up_to_date": "up to date", "update_available": "Update Available", "update_channel_description": "Stable receives the latest stable releases. Beta allows you to try out new in-progress features before they launch in Stable channel, but they have not completed testing yet.", @@ -294,7 +330,10 @@ "update_requires_restarting_robot": "Updating the robot software requires restarting the robot", "update_robot_now": "Update robot now", "update_robot_software": "Update robot software manually with a local file (.zip)", + "update_server_unavailable": "Unable to update because your robot's update server is not responding.", + "update_unavailable": "Update unavailable", "updating": "Updating", + "upgrade": "upgrade", "upload_custom_logo": "Upload custom logo", "upload_custom_logo_description": "Upload a logo for the robot to display during boot up.", "upload_custom_logo_dimensions": "The logo must fit within dimensions 1024 x 600 and be a PNG file (.png).", diff --git a/app/src/assets/localization/en/gripper_wizard_flows.json b/app/src/assets/localization/en/gripper_wizard_flows.json index ff98d8e07f0..70df5688820 100644 --- a/app/src/assets/localization/en/gripper_wizard_flows.json +++ b/app/src/assets/localization/en/gripper_wizard_flows.json @@ -5,7 +5,6 @@ "before_you_begin": "Before you begin", "begin_calibration": "Begin calibration", "calibrate_gripper": "Calibrate Gripper", - "calibration_pin": "Calibration Pin", "calibration_pin_touching": "The calibration pin will touch the calibration square in slot {{slot}} to determine its exact position.", "complete_calibration": "Complete calibration", "continue": "Continue", @@ -17,7 +16,6 @@ "gripper_calibration": "Gripper Calibration", "gripper_recalibration": "Gripper Recalibration", "gripper_successfully_attached": "Gripper successfully attached", - "hex_screwdriver": "2.5 mm Hex Screwdriver", "hold_gripper_and_loosen_screws": "Hold the gripper in place and loosen the top gripper screw first. After that move onto the bottom screw. (The screws are captive and will not come apart from the gripper.) Then carefully remove the gripper.", "insert_pin_into_front_jaw": "Insert calibration pin in front jaw", "insert_pin_into_rear_jaw": "Insert calibration pin in rear jaw", diff --git a/app/src/assets/localization/en/pipette_wizard_flows.json b/app/src/assets/localization/en/pipette_wizard_flows.json index 78dc2b852a6..1154d6f9659 100644 --- a/app/src/assets/localization/en/pipette_wizard_flows.json +++ b/app/src/assets/localization/en/pipette_wizard_flows.json @@ -67,6 +67,7 @@ "pipette_heavy": "The 96-Channel Pipette is heavy ({{weight}}). Ask a labmate for help, if needed.", "please_install_correct_pip": "Install {{pipetteName}} instead", "progress_will_be_lost": "{{flow}} progress will be lost", + "provided_with_robot": "Provided with the robot. Using another size can strip the instruments’s screws.", "reattach_carriage": "reattach z-axis carriage", "recalibrate_pipette": "recalibrate {{mount}} pipette", "remove_cal_probe": "remove calibration probe", diff --git a/app/src/assets/localization/en/protocol_command_text.json b/app/src/assets/localization/en/protocol_command_text.json index 2842f9dc30d..8037b8f2778 100644 --- a/app/src/assets/localization/en/protocol_command_text.json +++ b/app/src/assets/localization/en/protocol_command_text.json @@ -6,11 +6,13 @@ "adapter_in_mod_in_slot": "{{adapter}} on {{module}} in Slot {{slot}}", "adapter_in_slot": "{{adapter}} in Slot {{slot}}", "air_gap_in_place": "Air gapping {{volume}} µL", + "all_nozzles": "all nozzles", "aspirate": "Aspirating {{volume}} µL from well {{well_name}} of {{labware}} in {{labware_location}} at {{flow_rate}} µL/sec", "aspirate_in_place": "Aspirating {{volume}} µL in place at {{flow_rate}} µL/sec ", "blowout": "Blowing out at well {{well_name}} of {{labware}} in {{labware_location}} at {{flow_rate}} µL/sec", "blowout_in_place": "Blowing out in place at {{flow_rate}} µL/sec", "closing_tc_lid": "Closing Thermocycler lid", + "column_layout": "column layout", "comment": "Comment", "configure_for_volume": "Configure {{pipette}} to aspirate {{volume}} µL", "configure_nozzle_layout": "Configure {{pipette}} to use {{layout}}", @@ -59,11 +61,13 @@ "opening_tc_lid": "Opening Thermocycler lid", "pause": "Pause", "pause_on": "Pause on {{robot_name}}", + "partial_layout": "partial layout", "pickup_tip": "Picking up tip(s) from {{well_range}} of {{labware}} in {{labware_location}}", "prepare_to_aspirate": "Preparing {{pipette}} to aspirate", "reloading_labware": "Reloading {{labware}}", "return_tip": "Returning tip to {{well_name}} of {{labware}} in {{labware_location}}", "right": "Right", + "row_layout": "row layout", "save_position": "Saving position", "set_and_await_hs_shake": "Setting Heater-Shaker to shake at {{rpm}} rpm and waiting until reached", "setting_hs_temp": "Setting Target Temperature of Heater-Shaker to {{temp}}", @@ -71,6 +75,7 @@ "setting_thermocycler_block_temp": "Setting Thermocycler block temperature to {{temp}} with hold time of {{hold_time_seconds}} seconds after target reached", "setting_thermocycler_lid_temp": "Setting Thermocycler lid temperature to {{temp}}", "single": "single", + "single_nozzle_layout": "single nozzle layout", "slot": "Slot {{slot_name}}", "target_temperature": "target temperature", "tc_awaiting_for_duration": "Waiting for Thermocycler profile to complete", diff --git a/app/src/assets/localization/en/top_navigation.json b/app/src/assets/localization/en/top_navigation.json index 178b02042b9..16d5e2d011d 100644 --- a/app/src/assets/localization/en/top_navigation.json +++ b/app/src/assets/localization/en/top_navigation.json @@ -1,7 +1,10 @@ { + "app_settings": "App Settings", "attached_pipettes_do_not_match": "Attached pipettes do not match pipettes specified in loaded protocol", "calibrate_deck_to_proceed": "Calibrate your deck to proceed", + "calibration_dashboard": "Calibration Dashboard", "deck_setup": "Deck Setup", + "device": "Device", "devices": "Devices", "instruments": "Instruments", "labware": "Labware", @@ -10,10 +13,13 @@ "pipettes": "pipettes", "please_connect_to_a_robot": "Please connect to a robot to proceed", "please_load_a_protocol": "Please load a protocol to proceed", + "protocol_details": "Protocol Details", "protocol_runs": "Protocol Runs", + "protocol_timeline": "Protocol Timeline", "protocols": "Protocols", "quick_transfer": "Quick Transfer", "robot_settings": "Robot Settings", "run": "run", + "run_details": "Run Details", "settings": "Settings" } diff --git a/app/src/local-resources/commands/hooks/useCommandTextString/utils/commandText/getConfigureNozzleLayoutCommandText.ts b/app/src/local-resources/commands/hooks/useCommandTextString/utils/commandText/getConfigureNozzleLayoutCommandText.ts index 8c9e12f3d5b..f6440d69e1d 100644 --- a/app/src/local-resources/commands/hooks/useCommandTextString/utils/commandText/getConfigureNozzleLayoutCommandText.ts +++ b/app/src/local-resources/commands/hooks/useCommandTextString/utils/commandText/getConfigureNozzleLayoutCommandText.ts @@ -13,13 +13,12 @@ export function getConfigureNozzleLayoutCommandText({ pip => pip.id === pipetteId )?.pipetteName - // TODO(cb, 2024-09-10): confirm these strings for copy consistency and add them to i18n const ConfigAmount = { - SINGLE: 'single nozzle layout', - COLUMN: 'column layout', - ROW: 'row layout', - QUADRANT: 'partial layout', - ALL: 'all nozzles', + SINGLE: t('single_nozzle_layout'), + COLUMN: t('column_layout'), + ROW: t('row_layout'), + QUADRANT: t('partial_layout'), + ALL: t('all_nozzles'), } return t('configure_nozzle_layout', { diff --git a/app/src/organisms/Desktop/Alerts/U2EDriverOutdatedAlert.tsx b/app/src/organisms/Desktop/Alerts/U2EDriverOutdatedAlert.tsx index fbb79a6b935..a3bb26ecc7e 100644 --- a/app/src/organisms/Desktop/Alerts/U2EDriverOutdatedAlert.tsx +++ b/app/src/organisms/Desktop/Alerts/U2EDriverOutdatedAlert.tsx @@ -1,5 +1,6 @@ import { Link as InternalLink } from 'react-router-dom' import styled from 'styled-components' +import { useTranslation } from 'react-i18next' import { AlertModal, @@ -12,20 +13,9 @@ import { ANALYTICS_U2E_DRIVE_ALERT_DISMISSED, ANALYTICS_U2E_DRIVE_LINK_CLICKED, } from '/app/redux/analytics' -import { - U2E_DRIVER_UPDATE_URL, - U2E_DRIVER_OUTDATED_MESSAGE, - U2E_DRIVER_DESCRIPTION, - U2E_DRIVER_OUTDATED_CTA, -} from '/app/redux/system-info' +import { U2E_DRIVER_UPDATE_URL } from '/app/redux/system-info' import type { AlertProps } from './types' -// TODO(mc, 2020-05-07): i18n -const DRIVER_OUT_OF_DATE = 'Realtek USB-to-Ethernet Driver Update Available' -const VIEW_ADAPTER_INFO = 'view adapter info' -const GET_UPDATE = 'get update' -const DONT_REMIND_ME_AGAIN = "Don't remind me again" - const ADAPTER_INFO_URL = '/more/network-and-system' const LinkButton = styled(Link)` @@ -42,19 +32,20 @@ const IgnoreCheckbox = styled(DeprecatedCheckboxField)` export function U2EDriverOutdatedAlert(props: AlertProps): JSX.Element { const trackEvent = useTrackEvent() + const { t } = useTranslation('app_settings') const [rememberDismiss, toggleRememberDismiss] = useToggle() const { dismissAlert } = props return ( { dismissAlert(rememberDismiss) trackEvent({ @@ -67,7 +58,7 @@ export function U2EDriverOutdatedAlert(props: AlertProps): JSX.Element { Component: LinkButton, href: U2E_DRIVER_UPDATE_URL, external: true, - children: GET_UPDATE, + children: t('get_update'), onClick: () => { dismissAlert(rememberDismiss) trackEvent({ @@ -79,11 +70,11 @@ export function U2EDriverOutdatedAlert(props: AlertProps): JSX.Element { ]} >

- {U2E_DRIVER_OUTDATED_MESSAGE} {U2E_DRIVER_DESCRIPTION} + {t('u2e_driver_outdated_message')} {t('u2e_driver_description')}

-

{U2E_DRIVER_OUTDATED_CTA}

+

{t('please_update_driver')}

diff --git a/app/src/organisms/Desktop/Devices/ConfigurePipette/ConfigMessage.tsx b/app/src/organisms/Desktop/Devices/ConfigurePipette/ConfigMessage.tsx deleted file mode 100644 index d6a32fa6d4b..00000000000 --- a/app/src/organisms/Desktop/Devices/ConfigurePipette/ConfigMessage.tsx +++ /dev/null @@ -1,19 +0,0 @@ -import styles from './styles.module.css' - -// TODO (ka 2019-2-12): Add intercom onClick to assistance text -export function ConfigMessage(): JSX.Element { - return ( -
-

Warning:

-

- These are advanced settings. Please do not attempt to adjust without - assistance from an Opentrons support team member, as doing - so may affect the lifespan of your pipette. -

-

- Note that these settings will not override any pipette settings - pre-defined in protocols. -

-
- ) -} diff --git a/app/src/organisms/Desktop/Devices/RobotSettings/AdvancedTab/UpdateRobotSoftware.tsx b/app/src/organisms/Desktop/Devices/RobotSettings/AdvancedTab/UpdateRobotSoftware.tsx index a893c616508..abad78feeca 100644 --- a/app/src/organisms/Desktop/Devices/RobotSettings/AdvancedTab/UpdateRobotSoftware.tsx +++ b/app/src/organisms/Desktop/Devices/RobotSettings/AdvancedTab/UpdateRobotSoftware.tsx @@ -106,7 +106,7 @@ export function UpdateRobotSoftware({ {updateFromFileDisabledReason != null && ( - {updateFromFileDisabledReason} + {t(updateFromFileDisabledReason)} )} diff --git a/app/src/organisms/Desktop/Devices/RobotSettings/ConnectNetwork/ConnectModal/FormModal.tsx b/app/src/organisms/Desktop/Devices/RobotSettings/ConnectNetwork/ConnectModal/FormModal.tsx index 60ce3d2a88e..73f6004eb73 100644 --- a/app/src/organisms/Desktop/Devices/RobotSettings/ConnectNetwork/ConnectModal/FormModal.tsx +++ b/app/src/organisms/Desktop/Devices/RobotSettings/ConnectNetwork/ConnectModal/FormModal.tsx @@ -1,17 +1,17 @@ import { Controller } from 'react-hook-form' import styled, { css } from 'styled-components' - +import { useTranslation } from 'react-i18next' import { FONT_SIZE_BODY_1, BUTTON_TYPE_SUBMIT, Flex, } from '@opentrons/components' +import { SECURITY_WPA_PSK, SECURITY_WPA_EAP } from '/app/redux/networking' import { ScrollableAlertModal } from '/app/molecules/modals' import { TextField } from './TextField' import { KeyFileField } from './KeyFileField' import { SecurityField } from './SecurityField' import { FIELD_TYPE_KEY_FILE, FIELD_TYPE_SECURITY } from '../constants' -import * as Copy from '../i18n' import type { Control } from 'react-hook-form' import type { ConnectFormField, ConnectFormValues, WifiNetwork } from '../types' @@ -53,16 +53,23 @@ export interface FormModalProps { export const FormModal = (props: FormModalProps): JSX.Element => { const { id, network, fields, isValid, onCancel, control } = props + const { t } = useTranslation(['device_settings', 'shared']) const heading = network !== null - ? Copy.CONNECT_TO_SSID(network.ssid) - : Copy.FIND_AND_JOIN_A_NETWORK + ? t('connect_to_ssid', { ssid: network.ssid }) + : t('find_and_join_network') - const body = - network !== null - ? Copy.NETWORK_REQUIRES_SECURITY(network) - : Copy.ENTER_NAME_AND_SECURITY_TYPE + let bodyText = t('enter_name_security_type') + if (network != null) { + if (network.securityType === SECURITY_WPA_PSK) { + bodyText = t('network_requires_wpa_password', { ssid: network.ssid }) + } else if (network.securityType === SECURITY_WPA_EAP) { + bodyText = t('network_requires_auth', { ssid: network.ssid }) + } else { + bodyText = t('network_is_unsecured', { ssid: network.ssid }) + } + } return ( { iconName="wifi" onCloseClick={onCancel} buttons={[ - { children: Copy.CANCEL, onClick: props.onCancel }, + { children: t('shared:cancel'), onClick: props.onCancel }, { - children: Copy.CONNECT, + children: t('connect'), type: BUTTON_TYPE_SUBMIT, form: id, disabled: !isValid, }, ]} > - {body} + {bodyText} {fields.map(fieldProps => { const { name } = fieldProps diff --git a/app/src/organisms/Desktop/Devices/RobotSettings/ConnectNetwork/ConnectModal/KeyFileField.tsx b/app/src/organisms/Desktop/Devices/RobotSettings/ConnectNetwork/ConnectModal/KeyFileField.tsx index 376048ba420..b7ea68d5e36 100644 --- a/app/src/organisms/Desktop/Devices/RobotSettings/ConnectNetwork/ConnectModal/KeyFileField.tsx +++ b/app/src/organisms/Desktop/Devices/RobotSettings/ConnectNetwork/ConnectModal/KeyFileField.tsx @@ -1,9 +1,9 @@ import { useRef } from 'react' +import { useTranslation } from 'react-i18next' import { SelectField } from '@opentrons/components' import { FormRow } from './FormRow' import { UploadKeyInput } from './UploadKeyInput' -import { LABEL_ADD_NEW_KEY } from '../i18n' import { useConnectFormField } from './form-state' import type { WifiKey } from '../types' @@ -27,10 +27,6 @@ export interface KeyFileFieldProps { const ADD_NEW_KEY_VALUE = '__addNewKey__' -const ADD_NEW_KEY_OPTION_GROUP = { - options: [{ value: ADD_NEW_KEY_VALUE, label: LABEL_ADD_NEW_KEY }], -} - const makeKeyOptions = ( keys: WifiKey[] ): { options: Array<{ value: string; label: string }> } => ({ @@ -48,6 +44,11 @@ export const KeyFileField = (props: KeyFileFieldProps): JSX.Element => { field, fieldState, } = props + const { t } = useTranslation('device_settings') + const ADD_NEW_KEY_OPTION_GROUP = { + options: [{ value: ADD_NEW_KEY_VALUE, label: t('add_new') }], + } + const { value, error, setValue, setTouched } = useConnectFormField( field, fieldState @@ -81,7 +82,7 @@ export const KeyFileField = (props: KeyFileFieldProps): JSX.Element => { diff --git a/app/src/organisms/Desktop/Devices/RobotSettings/ConnectNetwork/ConnectModal/SecurityField.tsx b/app/src/organisms/Desktop/Devices/RobotSettings/ConnectNetwork/ConnectModal/SecurityField.tsx index c9fa4e0c069..cb7c2cbf615 100644 --- a/app/src/organisms/Desktop/Devices/RobotSettings/ConnectNetwork/ConnectModal/SecurityField.tsx +++ b/app/src/organisms/Desktop/Devices/RobotSettings/ConnectNetwork/ConnectModal/SecurityField.tsx @@ -1,7 +1,7 @@ +import { useTranslation } from 'react-i18next' import { SelectField } from '@opentrons/components' import { SECURITY_NONE, SECURITY_WPA_PSK } from '../constants' -import { LABEL_SECURITY_NONE, LABEL_SECURITY_PSK } from '../i18n' import { useConnectFormField } from './form-state' import { FormRow } from './FormRow' @@ -25,8 +25,8 @@ export interface SecurityFieldProps { } const ALL_SECURITY_OPTIONS = [ - { options: [{ value: SECURITY_NONE, label: LABEL_SECURITY_NONE }] }, - { options: [{ value: SECURITY_WPA_PSK, label: LABEL_SECURITY_PSK }] }, + { options: [{ value: SECURITY_NONE, label: 'shared:none' }] }, + { options: [{ value: SECURITY_WPA_PSK, label: 'wpa2_personal' }] }, ] const makeEapOptionsGroup = ( @@ -39,6 +39,7 @@ const makeEapOptionsGroup = ( }) export const SecurityField = (props: SecurityFieldProps): JSX.Element => { + const { t } = useTranslation(['device_settings', 'shared']) const { id, name, @@ -62,7 +63,7 @@ export const SecurityField = (props: SecurityFieldProps): JSX.Element => { ] return ( - + { + const { t } = useTranslation('device_settings') const { id, name, label, isPassword, className, field, fieldState } = props const { value, error, onChange, onBlur } = useConnectFormField( field, @@ -42,7 +43,7 @@ export const TextField = (props: TextFieldProps): JSX.Element => { /> {isPassword && ( diff --git a/app/src/organisms/Desktop/Devices/RobotSettings/ConnectNetwork/ConnectModal/form-fields.ts b/app/src/organisms/Desktop/Devices/RobotSettings/ConnectNetwork/ConnectModal/form-fields.ts index 1a91d2ac994..b8caeb3824c 100644 --- a/app/src/organisms/Desktop/Devices/RobotSettings/ConnectNetwork/ConnectModal/form-fields.ts +++ b/app/src/organisms/Desktop/Devices/RobotSettings/ConnectNetwork/ConnectModal/form-fields.ts @@ -1,9 +1,9 @@ import get from 'lodash/get' import * as Constants from '../constants' -import * as Copy from '../i18n' import type { FieldError } from 'react-hook-form' +import type { TFunction } from 'i18next' import type { WifiNetwork, WifiKey, @@ -24,28 +24,29 @@ type Errors = Record export const renderLabel = (label: string, required: boolean): string => `${required ? '* ' : ''}${label}` -const FIELD_SSID: ConnectFormTextField = { +const makeFieldSsid = (t: TFunction): ConnectFormTextField => ({ type: Constants.FIELD_TYPE_TEXT, name: Constants.CONFIGURE_FIELD_SSID, - label: renderLabel(Copy.LABEL_SSID, true), + label: renderLabel(t('network_name'), true), isPassword: false, -} +}) -const FIELD_PSK: ConnectFormTextField = { +const makeFieldPsk = (t: TFunction): ConnectFormTextField => ({ type: Constants.FIELD_TYPE_TEXT, name: Constants.CONFIGURE_FIELD_PSK, - label: renderLabel(Copy.LABEL_PSK, true), + label: renderLabel(t('password'), true), isPassword: true, -} +}) const makeSecurityField = ( eapOptions: EapOption[], - showAllOptions: boolean + showAllOptions: boolean, + t: TFunction ): ConnectFormSecurityField => ({ type: Constants.FIELD_TYPE_SECURITY, name: Constants.CONFIGURE_FIELD_SECURITY_TYPE, - label: renderLabel(Copy.LABEL_SECURITY, true), - placeholder: Copy.SELECT_AUTHENTICATION_METHOD, + label: renderLabel(t('authentication'), true), + placeholder: t('select_auth_method_short'), eapOptions, showAllOptions, }) @@ -77,21 +78,22 @@ export function getConnectFormFields( robotName: string, eapOptions: EapOption[], wifiKeys: WifiKey[], - values: ConnectFormValues + values: ConnectFormValues, + t: TFunction ): ConnectFormField[] { const { securityType: formSecurityType } = values const fields = [] // if the network is unknown, display a field to enter the SSID if (network === null) { - fields.push(FIELD_SSID) + fields.push(makeFieldSsid(t)) } // if the network is unknown or the known network is EAP, display a // security dropdown; security dropdown will handle which options to // display based on known or unknown network if (!network || network.securityType === Constants.SECURITY_WPA_EAP) { - fields.push(makeSecurityField(eapOptions, !network)) + fields.push(makeSecurityField(eapOptions, !network, t)) } // if known network is PSK or network is unknown and user has selected PSK @@ -100,7 +102,7 @@ export function getConnectFormFields( network?.securityType === Constants.SECURITY_WPA_PSK || formSecurityType === Constants.SECURITY_WPA_PSK ) { - fields.push(FIELD_PSK) + fields.push(makeFieldPsk(t)) } // if known network is EAP or user selected EAP, map eap options to fields @@ -121,7 +123,7 @@ export function getConnectFormFields( label, robotName, wifiKeys, - placeholder: Copy.SELECT_FILE, + placeholder: t('select_file'), } } @@ -142,7 +144,8 @@ export function validateConnectFormFields( network: WifiNetwork | null, eapOptions: EapOption[], values: ConnectFormValues, - errors: Errors + errors: Errors, + t: TFunction ): Errors { const { ssid: formSsid, @@ -152,7 +155,7 @@ export function validateConnectFormFields( let errorMessage: string | undefined if (network === null && (formSsid == null || formSsid.length === 0)) { - errorMessage = Copy.FIELD_IS_REQUIRED(Copy.LABEL_SSID) + errorMessage = t('field_is_required', { field: t('network_name') }) return errorMessage != null ? { ...errors, @@ -168,7 +171,7 @@ export function validateConnectFormFields( (network === null || network.securityType === Constants.SECURITY_WPA_EAP) && !formSecurityType ) { - errorMessage = Copy.FIELD_IS_REQUIRED(Copy.LABEL_SECURITY) + errorMessage = t('field_is_required', { field: t('authentication') }) return errorMessage != null ? { ...errors, @@ -185,10 +188,9 @@ export function validateConnectFormFields( formSecurityType === Constants.SECURITY_WPA_PSK) && (!formPsk || formPsk.length < Constants.CONFIGURE_PSK_MIN_LENGTH) ) { - errorMessage = Copy.FIELD_NOT_LONG_ENOUGH( - Copy.LABEL_PSK, - Constants.CONFIGURE_PSK_MIN_LENGTH - ) + errorMessage = t('password_not_long_enough', { + minLength: Constants.CONFIGURE_PSK_MIN_LENGTH, + }) return errorMessage != null ? { ...errors, @@ -215,7 +217,9 @@ export function validateConnectFormFields( ) => { const fieldName = getEapFieldName(name) const errorMessage = - displayName != null ? Copy.FIELD_IS_REQUIRED(displayName) : '' + displayName != null + ? t('field_is_required', { field: displayName }) + : '' if (errorMessage != null) { acc[fieldName] = { diff --git a/app/src/organisms/Desktop/Devices/RobotSettings/ConnectNetwork/ConnectModal/index.tsx b/app/src/organisms/Desktop/Devices/RobotSettings/ConnectNetwork/ConnectModal/index.tsx index 3e1c731d33e..2b5d228c12b 100644 --- a/app/src/organisms/Desktop/Devices/RobotSettings/ConnectNetwork/ConnectModal/index.tsx +++ b/app/src/organisms/Desktop/Devices/RobotSettings/ConnectNetwork/ConnectModal/index.tsx @@ -1,4 +1,5 @@ import { useForm } from 'react-hook-form' +import { useTranslation } from 'react-i18next' import { useResetFormOnSecurityChange } from './form-state' import { @@ -10,6 +11,7 @@ import { import { FormModal } from './FormModal' import type { Control, Resolver } from 'react-hook-form' +import type { TFunction } from 'i18next' import type { ConnectFormValues, WifiConfigureRequest, @@ -35,6 +37,7 @@ interface ConnectModalComponentProps extends ConnectModalProps { } export const ConnectModal = (props: ConnectModalProps): JSX.Element => { + const { t } = useTranslation(['device_settings', 'shared']) const { network, eapOptions, onConnect } = props const onSubmit = (values: ConnectFormValues): void => { @@ -45,7 +48,13 @@ export const ConnectModal = (props: ConnectModalProps): JSX.Element => { const handleValidate: Resolver = values => { let errors = {} - errors = validateConnectFormFields(network, eapOptions, values, errors) + errors = validateConnectFormFields( + network, + eapOptions, + values, + errors, + t as TFunction + ) return { values, errors } } @@ -78,6 +87,7 @@ export const ConnectModal = (props: ConnectModalProps): JSX.Element => { export const ConnectModalComponent = ( props: ConnectModalComponentProps ): JSX.Element => { + const { t } = useTranslation(['device_settings', 'shared']) const { robotName, network, @@ -95,7 +105,8 @@ export const ConnectModalComponent = ( robotName, eapOptions, wifiKeys, - values + values, + t as TFunction ) useResetFormOnSecurityChange() diff --git a/app/src/organisms/Desktop/Devices/RobotSettings/ConnectNetwork/ResultModal.tsx b/app/src/organisms/Desktop/Devices/RobotSettings/ConnectNetwork/ResultModal.tsx index 6628c35dfc5..3a372c6df66 100644 --- a/app/src/organisms/Desktop/Devices/RobotSettings/ConnectNetwork/ResultModal.tsx +++ b/app/src/organisms/Desktop/Devices/RobotSettings/ConnectNetwork/ResultModal.tsx @@ -1,6 +1,6 @@ +import { useTranslation } from 'react-i18next' import { AlertModal, SpinnerModal } from '@opentrons/components' -import * as Copy from './i18n' import { ErrorModal } from '/app/molecules/modals' import { DISCONNECT } from './constants' import { PENDING, FAILURE } from '/app/redux/robot-api' @@ -18,29 +18,32 @@ export interface ResultModalProps { export const ResultModal = (props: ResultModalProps): JSX.Element => { const { type, ssid, requestStatus, error, onClose } = props + const { t } = useTranslation(['device_settings', 'shared']) const isDisconnect = type === DISCONNECT if (requestStatus === PENDING) { const message = isDisconnect - ? Copy.DISCONNECTING_FROM_NETWORK(ssid) - : Copy.CONNECTING_TO_NETWORK(ssid) + ? t('disconnecting_from_wifi_network', { ssid: ssid }) + : t('connecting_to_wifi_network', { ssid: ssid }) return } if (error || requestStatus === FAILURE) { const heading = isDisconnect - ? Copy.UNABLE_TO_DISCONNECT - : Copy.UNABLE_TO_CONNECT + ? t('unable_to_disconnect') + : t('unable_to_connect') const message = isDisconnect - ? Copy.YOUR_ROBOT_WAS_UNABLE_TO_DISCONNECT(ssid) - : Copy.YOUR_ROBOT_WAS_UNABLE_TO_CONNECT(ssid) + ? t('disconnect_from_wifi_network_failure', { ssid: ssid }) + : t('connect_to_wifi_network_failure', { ssid: ssid }) - const retryMessage = !isDisconnect ? ` ${Copy.CHECK_YOUR_CREDENTIALS}.` : '' + const retryMessage = !isDisconnect ? t('please_check_credentials') : '' const placeholderError = { - message: `Likely incorrect network password. ${Copy.CHECK_YOUR_CREDENTIALS}.`, + message: `${t('likely_incorrect_password')} ${t( + 'please_check_credentials' + )}.`, } return ( @@ -54,12 +57,12 @@ export const ResultModal = (props: ResultModalProps): JSX.Element => { } const heading = isDisconnect - ? Copy.SUCCESSFULLY_DISCONNECTED - : Copy.SUCCESSFULLY_CONNECTED + ? t('successfully_disconnected') + : t('successfully_connected_to_wifi') const message = isDisconnect - ? Copy.YOUR_ROBOT_HAS_DISCONNECTED(ssid) - : Copy.YOUR_ROBOT_HAS_CONNECTED(ssid) + ? t('disconnect_from_wifi_network_success') + : t('successfully_connected_to_ssid', { ssid: ssid }) return ( { iconName="wifi" heading={heading} onCloseClick={props.onClose} - buttons={[{ children: Copy.CLOSE, onClick: onClose }]} + buttons={[{ children: t('shared:close'), onClick: onClose }]} > {message} diff --git a/app/src/organisms/Desktop/Devices/RobotSettings/ConnectNetwork/SelectSsid/index.tsx b/app/src/organisms/Desktop/Devices/RobotSettings/ConnectNetwork/SelectSsid/index.tsx index b85cc72d563..a8b04feba4b 100644 --- a/app/src/organisms/Desktop/Devices/RobotSettings/ConnectNetwork/SelectSsid/index.tsx +++ b/app/src/organisms/Desktop/Devices/RobotSettings/ConnectNetwork/SelectSsid/index.tsx @@ -1,9 +1,10 @@ import type * as React from 'react' +import { useTranslation } from 'react-i18next' import { CONTEXT_MENU } from '@opentrons/components' import { SelectField } from '/app/atoms/SelectField' -import * as Copy from '../i18n' import { NetworkOptionLabel, NetworkActionLabel } from './NetworkOptionLabel' +import type { TFunction } from 'i18next' import type { SelectOptionOrGroup } from '@opentrons/components' import type { WifiNetwork } from '../types' @@ -20,11 +21,16 @@ const FIELD_NAME = '__SelectSsid__' const JOIN_OTHER_VALUE = '__join-other-network__' -const SELECT_JOIN_OTHER_GROUP = { - options: [{ value: JOIN_OTHER_VALUE, label: Copy.LABEL_JOIN_OTHER_NETWORK }], -} +const formatOptions = ( + list: WifiNetwork[], + t: TFunction +): SelectOptionOrGroup[] => { + const SELECT_JOIN_OTHER_GROUP = { + options: [ + { value: JOIN_OTHER_VALUE, label: `${t('join_other_network')}...` }, + ], + } -const formatOptions = (list: WifiNetwork[]): SelectOptionOrGroup[] => { const ssidOptionsList = { options: list?.map(({ ssid }) => ({ value: ssid })), } @@ -34,6 +40,7 @@ const formatOptions = (list: WifiNetwork[]): SelectOptionOrGroup[] => { } export function SelectSsid(props: SelectSsidProps): JSX.Element { + const { t } = useTranslation('device_settings') const { list, value, onConnect, onJoinOther, isRobotBusy } = props const handleValueChange = (_: string, value: string): void => { @@ -69,8 +76,8 @@ export function SelectSsid(props: SelectSsidProps): JSX.Element { disabled={isRobotBusy} name={FIELD_NAME} value={value} - options={formatOptions(list)} - placeholder={Copy.SELECT_NETWORK} + options={formatOptions(list, t as TFunction)} + placeholder={t('choose_a_network')} onValueChange={handleValueChange} formatOptionLabel={formatOptionLabel} width="16rem" diff --git a/app/src/organisms/Desktop/Devices/RobotSettings/ConnectNetwork/i18n.ts b/app/src/organisms/Desktop/Devices/RobotSettings/ConnectNetwork/i18n.ts deleted file mode 100644 index cfee1e77d89..00000000000 --- a/app/src/organisms/Desktop/Devices/RobotSettings/ConnectNetwork/i18n.ts +++ /dev/null @@ -1,103 +0,0 @@ -// TODO(mc, 2020-03-11): i18n -import { - SECURITY_WPA_PSK, - SECURITY_WPA_EAP, - SECURITY_NONE, -} from '/app/redux/networking' - -import type { WifiNetwork } from './types' - -const SECURITY_DESC = { - [SECURITY_WPA_PSK]: 'requires a WPA2 password', - [SECURITY_WPA_EAP]: 'requires 802.1X authentication', - [SECURITY_NONE]: 'is unsecured', -} - -export const FIND_AND_JOIN_A_NETWORK = 'Find and join a Wi-Fi network' - -export const ENTER_NAME_AND_SECURITY_TYPE = - 'Enter the network name and security type.' - -const WIFI_NETWORK = 'Wi-Fi network' - -export const CANCEL = 'cancel' - -export const CONNECT = 'connect' - -export const CLOSE = 'close' - -export const DISCONNECT = 'disconnect' - -export const LABEL_SSID = 'Network Name (SSID)' - -export const LABEL_PSK = 'Password' - -export const LABEL_SECURITY = 'Authentication' - -export const LABEL_SECURITY_NONE = 'None' - -export const LABEL_SECURITY_PSK = 'WPA2 Personal' - -export const LABEL_ADD_NEW_KEY = 'Add new...' - -export const LABEL_SHOW_PASSWORD = 'Show password' - -export const LABEL_JOIN_OTHER_NETWORK = 'Join other network...' - -export const SELECT_AUTHENTICATION_METHOD = 'Select authentication method' - -export const SELECT_FILE = 'Select file' - -export const SELECT_NETWORK = 'Choose a network...' - -export const SUCCESSFULLY_DISCONNECTED = 'Successfully disconnected from Wi-Fi' - -export const SUCCESSFULLY_CONNECTED = 'Successfully connected to Wi-Fi' - -export const UNABLE_TO_DISCONNECT = 'Unable to disconnect from Wi-Fi' - -export const UNABLE_TO_CONNECT = 'Unable to connect to Wi-Fi' - -export const CHECK_YOUR_CREDENTIALS = - 'Please double-check your network credentials' - -export const CONNECT_TO_SSID = (ssid: string): string => `Connect to ${ssid}` - -export const DISCONNECT_FROM_SSID = (ssid: string): string => - `Disconnect from ${ssid}` - -export const ARE_YOU_SURE_YOU_WANT_TO_DISCONNECT = (ssid: string): string => - `Are you sure you want to disconnect from ${ssid}?` - -export const NETWORK_REQUIRES_SECURITY = (network: WifiNetwork): string => - `${WIFI_NETWORK} ${network.ssid} ${SECURITY_DESC[network.securityType]}` - -export const FIELD_IS_REQUIRED = (name: string): string => `${name} is required` - -export const FIELD_NOT_LONG_ENOUGH = ( - name: string, - minLength: number -): string => `${name} must be at least ${minLength} characters` - -const renderMaybeSsid = (ssid: string | null): string => - ssid !== null ? ` network ${ssid}` : '' - -export const CONNECTING_TO_NETWORK = (ssid: string | null): string => - `Connecting to Wi-Fi${renderMaybeSsid(ssid)}` - -export const DISCONNECTING_FROM_NETWORK = (ssid: string | null): string => - `Disconnecting from Wi-Fi${renderMaybeSsid(ssid)}` - -export const YOUR_ROBOT_WAS_UNABLE_TO_CONNECT = (ssid: string | null): string => - `Your robot was unable to connect to Wi-Fi${renderMaybeSsid(ssid)}` - -export const YOUR_ROBOT_WAS_UNABLE_TO_DISCONNECT = ( - ssid: string | null -): string => - `Your robot was unable to disconnect from Wi-Fi${renderMaybeSsid(ssid)}` - -export const YOUR_ROBOT_HAS_DISCONNECTED = (ssid: string | null): string => - `Your robot has successfully disconnected from Wi-Fi${renderMaybeSsid(ssid)}` - -export const YOUR_ROBOT_HAS_CONNECTED = (ssid: string | null): string => - `Your robot has successfully connected to Wi-Fi${renderMaybeSsid(ssid)}` diff --git a/app/src/organisms/Desktop/Devices/RobotSettings/UpdateBuildroot/UpdateRobotModal.tsx b/app/src/organisms/Desktop/Devices/RobotSettings/UpdateBuildroot/UpdateRobotModal.tsx index 4b2225fe868..da77dee89c9 100644 --- a/app/src/organisms/Desktop/Devices/RobotSettings/UpdateBuildroot/UpdateRobotModal.tsx +++ b/app/src/organisms/Desktop/Devices/RobotSettings/UpdateBuildroot/UpdateRobotModal.tsx @@ -88,7 +88,7 @@ export function UpdateRobotModal({ let disabledReason: string = '' if (updateFromFileDisabledReason) - disabledReason = updateFromFileDisabledReason + disabledReason = t(updateFromFileDisabledReason) else if (isRobotBusy) disabledReason = t('robot_busy_protocol') useEffect(() => { diff --git a/app/src/organisms/GripperWizardFlows/BeforeBeginning.tsx b/app/src/organisms/GripperWizardFlows/BeforeBeginning.tsx index 89395aeee10..316a3a5526a 100644 --- a/app/src/organisms/GripperWizardFlows/BeforeBeginning.tsx +++ b/app/src/organisms/GripperWizardFlows/BeforeBeginning.tsx @@ -13,6 +13,8 @@ import { SCREWDRIVER_LOADNAME, GRIPPER_LOADNAME, CAL_PIN_LOADNAME, + CALIBRATION_PIN_DISPLAY_NAME, + HEX_SCREWDRIVER_DISPLAY_NAME, } from './constants' import type { UseMutateFunction } from 'react-query' @@ -105,9 +107,9 @@ export const BeforeBeginning = ( const equipmentInfoByLoadName: { [loadName: string]: { displayName: string; subtitle?: string } } = { - calibration_pin: { displayName: t('calibration_pin') }, + calibration_pin: { displayName: CALIBRATION_PIN_DISPLAY_NAME }, hex_screwdriver: { - displayName: t('hex_screwdriver'), + displayName: HEX_SCREWDRIVER_DISPLAY_NAME, subtitle: t('provided_with_robot_use_right_size'), }, [GRIPPER_LOADNAME]: { displayName: t('branded:gripper') }, diff --git a/app/src/organisms/GripperWizardFlows/constants.ts b/app/src/organisms/GripperWizardFlows/constants.ts index db06adc340f..a5b633bab14 100644 --- a/app/src/organisms/GripperWizardFlows/constants.ts +++ b/app/src/organisms/GripperWizardFlows/constants.ts @@ -13,6 +13,10 @@ export const GRIPPER_FLOW_TYPES = { RECALIBRATE: 'RECALIBRATE', } as const +// note: we will not translate these item titles to be consistent with manuals +export const CALIBRATION_PIN_DISPLAY_NAME = 'Calibration Pin' +export const HEX_SCREWDRIVER_DISPLAY_NAME = '2.5 mm Hex Screwdriver' + // pin movements export const MOVE_PIN_TO_FRONT_JAW = 'movePinToFrontJaw' as const diff --git a/app/src/organisms/ODD/QuickTransferFlow/NameQuickTransfer.tsx b/app/src/organisms/ODD/QuickTransferFlow/NameQuickTransfer.tsx index 8bff060ac38..2ef4592f568 100644 --- a/app/src/organisms/ODD/QuickTransferFlow/NameQuickTransfer.tsx +++ b/app/src/organisms/ODD/QuickTransferFlow/NameQuickTransfer.tsx @@ -33,7 +33,6 @@ export function NameQuickTransfer(props: NameQuickTransferProps): JSX.Element { if (name.length > 60) { error = t('character_limit_error') } - // TODO add error handling for quick transfer name replication return createPortal( diff --git a/app/src/organisms/PipetteWizardFlows/BeforeBeginning.tsx b/app/src/organisms/PipetteWizardFlows/BeforeBeginning.tsx index ffcb72dae18..a69e095a674 100644 --- a/app/src/organisms/PipetteWizardFlows/BeforeBeginning.tsx +++ b/app/src/organisms/PipetteWizardFlows/BeforeBeginning.tsx @@ -107,6 +107,10 @@ export const BeforeBeginning = ( let equipmentList = [CALIBRATION_PROBE] const proceedButtonText = t('move_gantry_to_front') + const hexScrewdriverWithSubtitle = { + ...HEX_SCREWDRIVER, + subtitle: t('provided_with_robot'), + } let bodyTranslationKey: string = '' switch (flowType) { @@ -124,7 +128,7 @@ export const BeforeBeginning = ( equipmentList = [ { ...PIPETTE, displayName: displayName ?? PIPETTE.displayName }, CALIBRATION_PROBE, - HEX_SCREWDRIVER, + hexScrewdriverWithSubtitle, ] } else { equipmentList = [ @@ -133,7 +137,7 @@ export const BeforeBeginning = ( displayName: displayName ?? NINETY_SIX_CHANNEL_PIPETTE.displayName, }, CALIBRATION_PROBE, - HEX_SCREWDRIVER, + hexScrewdriverWithSubtitle, NINETY_SIX_CHANNEL_MOUNTING_PLATE, ] } @@ -148,19 +152,19 @@ export const BeforeBeginning = ( equipmentList = [ { ...NINETY_SIX_CHANNEL_PIPETTE, displayName }, CALIBRATION_PROBE, - HEX_SCREWDRIVER, + hexScrewdriverWithSubtitle, NINETY_SIX_CHANNEL_MOUNTING_PLATE, ] } else { equipmentList = [ { ...PIPETTE, displayName }, CALIBRATION_PROBE, - HEX_SCREWDRIVER, + hexScrewdriverWithSubtitle, ] } } else { bodyTranslationKey = 'get_started_detach' - equipmentList = [HEX_SCREWDRIVER] + equipmentList = [hexScrewdriverWithSubtitle] } break } diff --git a/app/src/organisms/PipetteWizardFlows/constants.ts b/app/src/organisms/PipetteWizardFlows/constants.ts index e4ddd762d95..1d0b94878c1 100644 --- a/app/src/organisms/PipetteWizardFlows/constants.ts +++ b/app/src/organisms/PipetteWizardFlows/constants.ts @@ -18,6 +18,8 @@ export const FLOWS = { DETACH: 'DETACH', CALIBRATE: 'CALIBRATE', } + +// note: we will not be translating these item titles to be consistent with manuals export const CALIBRATION_PROBE_DISPLAY_NAME = 'Calibration Probe' export const HEX_SCREWDRIVER_DISPLAY_NAME = '2.5 mm Hex Screwdriver' export const PIPETTE_DISPLAY_NAME = '1- or 8-Channel Pipette' @@ -33,9 +35,6 @@ export const CALIBRATION_PROBE = { export const HEX_SCREWDRIVER = { loadName: 'hex_screwdriver', displayName: HEX_SCREWDRIVER_DISPLAY_NAME, - // TODO(jr, 4/3/23): add this subtitle to i18n - subtitle: - 'Provided with the robot. Using another size can strip the instruments’s screws.', } export const PIPETTE = { loadName: 'flex_pipette', diff --git a/app/src/pages/Desktop/Labware/index.tsx b/app/src/pages/Desktop/Labware/index.tsx index 83f9dd94f3f..5d8959a5861 100644 --- a/app/src/pages/Desktop/Labware/index.tsx +++ b/app/src/pages/Desktop/Labware/index.tsx @@ -63,6 +63,7 @@ const labwareDisplayCategoryFilters: LabwareFilter[] = [ 'wellPlate', ] +// note: we've decided not to translate these categories const FILTER_OPTIONS: DropdownOption[] = labwareDisplayCategoryFilters.map( category => ({ name: startCase(category), diff --git a/app/src/redux/robot-update/selectors.ts b/app/src/redux/robot-update/selectors.ts index 0570a9dd2c8..a2427dfefb5 100644 --- a/app/src/redux/robot-update/selectors.ts +++ b/app/src/redux/robot-update/selectors.ts @@ -19,15 +19,6 @@ import type { RobotUpdateTarget, } from './types' -// TODO(mc, 2020-08-02): i18n -const UPDATE_SERVER_UNAVAILABLE = - "Unable to update because your robot's update server is not responding." -const OTHER_ROBOT_UPDATING = - 'Unable to update because the app is currently updating a different robot.' -const NO_UPDATE_FILES = - 'Unable to retrieve update for this robot. Ensure your computer is connected to the internet and try again later.' -const UNAVAILABLE = 'Update unavailable' - export const getRobotUpdateTarget: ( state: State, robotName: string @@ -198,6 +189,7 @@ export function getRobotUpdateAvailable( : getRobotUpdateType(currentVersion, updateVersion) } +// this util returns i18n keys in device_settings export const getRobotUpdateDisplayInfo: ( state: State, robotName: string @@ -212,21 +204,21 @@ export const getRobotUpdateDisplayInfo: ( (robot, currentUpdatingRobot, updateVersion) => { const robotVersion = robot ? getRobotApiVersion(robot) : null const autoUpdateType = getRobotUpdateType(robotVersion, updateVersion) - const autoUpdateAction = autoUpdateType ?? UNAVAILABLE + const autoUpdateAction = autoUpdateType ?? 'update_unavailable' let autoUpdateDisabledReason = null let updateFromFileDisabledReason = null if (robot?.serverHealthStatus !== HEALTH_STATUS_OK) { - autoUpdateDisabledReason = UPDATE_SERVER_UNAVAILABLE - updateFromFileDisabledReason = UPDATE_SERVER_UNAVAILABLE + autoUpdateDisabledReason = 'update_server_unavailable' + updateFromFileDisabledReason = 'update_server_unavailable' } else if ( currentUpdatingRobot !== null && currentUpdatingRobot.name !== robot?.name ) { - autoUpdateDisabledReason = OTHER_ROBOT_UPDATING - updateFromFileDisabledReason = OTHER_ROBOT_UPDATING + autoUpdateDisabledReason = 'other_robot_updating' + updateFromFileDisabledReason = 'other_robot_updating' } else if (autoUpdateType === null) { - autoUpdateDisabledReason = NO_UPDATE_FILES + autoUpdateDisabledReason = 'no_update_files' } return { diff --git a/app/src/redux/system-info/constants.ts b/app/src/redux/system-info/constants.ts index 1502d4bba07..a79b6ffb7bb 100644 --- a/app/src/redux/system-info/constants.ts +++ b/app/src/redux/system-info/constants.ts @@ -22,12 +22,3 @@ export const USB_DEVICE_REMOVED: 'systemInfo:USB_DEVICE_REMOVED' = export const NETWORK_INTERFACES_CHANGED: 'systemInfo:NETWORK_INTERFACES_CHANGED' = 'systemInfo:NETWORK_INTERFACES_CHANGED' - -// copy -// TODO(mc, 2020-05-11): i18n -export const U2E_DRIVER_OUTDATED_MESSAGE = - 'There is an updated Realtek USB-to-Ethernet adapter driver available for your computer.' -export const U2E_DRIVER_DESCRIPTION = - 'The OT-2 uses this adapter for its USB connection to the Opentrons App.' -export const U2E_DRIVER_OUTDATED_CTA = - "Please update your computer's driver to ensure a reliable connection to your OT-2." diff --git a/shared-data/js/fixtures.ts b/shared-data/js/fixtures.ts index 4f13a8b0321..905429cd111 100644 --- a/shared-data/js/fixtures.ts +++ b/shared-data/js/fixtures.ts @@ -238,7 +238,7 @@ export function getAddressableAreaNamesFromLoadedModule( return [...acc, ...providedAddressableAreas] }, []) } - +// note: we've decided not to translate these strings export function getFixtureDisplayName( cutoutFixtureId: CutoutFixtureId | null, usbPortNumber?: number