diff --git a/api-client/src/robot/getRobotSettings.ts b/api-client/src/robot/getRobotSettings.ts new file mode 100644 index 00000000000..ffe0014fcb0 --- /dev/null +++ b/api-client/src/robot/getRobotSettings.ts @@ -0,0 +1,11 @@ +import { GET, request } from '../request' + +import type { ResponsePromise } from '../request' +import type { HostConfig } from '../types' +import type { RobotSettingsResponse } from './types' + +export function getRobotSettings( + config: HostConfig +): ResponsePromise { + return request(GET, '/settings', null, config) +} diff --git a/api-client/src/robot/index.ts b/api-client/src/robot/index.ts index 96ef28165b0..588a2f7a80e 100644 --- a/api-client/src/robot/index.ts +++ b/api-client/src/robot/index.ts @@ -3,11 +3,16 @@ export { getEstopStatus } from './getEstopStatus' export { acknowledgeEstopDisengage } from './acknowledgeEstopDisengage' export { getLights } from './getLights' export { setLights } from './setLights' +export { getRobotSettings } from './getRobotSettings' + export type { DoorStatus, EstopPhysicalStatus, EstopState, EstopStatus, Lights, + RobotSettings, + RobotSettingsField, + RobotSettingsResponse, SetLightsData, } from './types' diff --git a/api-client/src/robot/types.ts b/api-client/src/robot/types.ts index 00d887b9c4e..088d78fa5c8 100644 --- a/api-client/src/robot/types.ts +++ b/api-client/src/robot/types.ts @@ -27,3 +27,18 @@ export interface Lights { export interface SetLightsData { on: boolean } + +export interface RobotSettingsField { + id: string + title: string + description: string + value: boolean | null + restart_required?: boolean +} + +export type RobotSettings = RobotSettingsField[] + +export interface RobotSettingsResponse { + settings: RobotSettings + links?: { restart?: string } +} diff --git a/app/src/App/DesktopApp.tsx b/app/src/App/DesktopApp.tsx index f42ef7e0e80..ffa50727da1 100644 --- a/app/src/App/DesktopApp.tsx +++ b/app/src/App/DesktopApp.tsx @@ -1,6 +1,7 @@ import * as React from 'react' import { Redirect, Route, Switch, useRouteMatch } from 'react-router-dom' import { ErrorBoundary } from 'react-error-boundary' +import { I18nextProvider } from 'react-i18next' import { Box, @@ -11,6 +12,7 @@ import { import { ApiHostProvider } from '@opentrons/react-api-client' import NiceModal from '@ebay/nice-modal-react' +import { i18n } from '../i18n' import { Alerts } from '../organisms/Alerts' import { Breadcrumbs } from '../organisms/Breadcrumbs' import { ToasterOven } from '../organisms/ToasterOven' @@ -101,45 +103,47 @@ export const DesktopApp = (): JSX.Element => { return ( - - - - - - - - {desktopRoutes.map( - ({ Component, exact, path }: RouteProps) => { - return ( - - - - - - - - ) - } - )} - - - - - - - - + + + + + + + + + {desktopRoutes.map( + ({ Component, exact, path }: RouteProps) => { + return ( + + + + + + + + ) + } + )} + + + + + + + + + ) } diff --git a/app/src/App/OnDeviceDisplayApp.tsx b/app/src/App/OnDeviceDisplayApp.tsx index c9923e1aea3..7afc0775a79 100644 --- a/app/src/App/OnDeviceDisplayApp.tsx +++ b/app/src/App/OnDeviceDisplayApp.tsx @@ -16,6 +16,7 @@ import { ApiHostProvider } from '@opentrons/react-api-client' import NiceModal from '@ebay/nice-modal-react' import { SleepScreen } from '../atoms/SleepScreen' +import { OnDeviceLocalizationProvider } from '../LocalizationProvider' import { ToasterOven } from '../organisms/ToasterOven' import { MaintenanceRunTakeover } from '../organisms/TakeoverModal' import { FirmwareUpdateTakeover } from '../organisms/FirmwareUpdateModal/FirmwareUpdateTakeover' @@ -151,6 +152,53 @@ export const OnDeviceDisplayApp = (): JSX.Element => { } const dispatch = useDispatch() const isIdle = useIdle(sleepTime, options) + + React.useEffect(() => { + if (isIdle) { + dispatch(updateBrightness(TURN_OFF_BACKLIGHT)) + } else { + dispatch( + updateConfigValue( + 'onDeviceDisplaySettings.brightness', + userSetBrightness + ) + ) + } + }, [dispatch, isIdle, userSetBrightness]) + + // TODO (sb:6/12/23) Create a notification manager to set up preference and order of takeover modals + return ( + + + + + {isIdle ? ( + + ) : ( + <> + + + + + + + + + + + + )} + + + + + + ) +} + +// split to a separate function because scrollRef rerenders on every route change +// this avoids rerendering parent providers as well +export function OnDeviceDisplayAppRoutes(): JSX.Element { const [currentNode, setCurrentNode] = React.useState(null) const scrollRef = React.useCallback((node: HTMLElement | null) => { setCurrentNode(node) @@ -176,54 +224,18 @@ export const OnDeviceDisplayApp = (): JSX.Element => { } ` - React.useEffect(() => { - if (isIdle) { - dispatch(updateBrightness(TURN_OFF_BACKLIGHT)) - } else { - dispatch( - updateConfigValue( - 'onDeviceDisplaySettings.brightness', - userSetBrightness - ) - ) - } - }, [dispatch, isIdle, userSetBrightness]) - - // TODO (sb:6/12/23) Create a notification manager to set up preference and order of takeover modals return ( - - - - {isIdle ? ( - - ) : ( - <> - - - - - - - - {ON_DEVICE_DISPLAY_PATHS.map(path => ( - - - - {getPathComponent(path)} - - - ))} - - - - - - - )} - - - - + + {ON_DEVICE_DISPLAY_PATHS.map(path => ( + + + + {getPathComponent(path)} + + + ))} + + ) } diff --git a/app/src/App/OnDeviceDisplayAppFallback.tsx b/app/src/App/OnDeviceDisplayAppFallback.tsx index 6a345c1735e..0e48a31e565 100644 --- a/app/src/App/OnDeviceDisplayAppFallback.tsx +++ b/app/src/App/OnDeviceDisplayAppFallback.tsx @@ -27,7 +27,7 @@ import type { ModalHeaderBaseProps } from '../molecules/Modal/types' export function OnDeviceDisplayAppFallback({ error, }: FallbackProps): JSX.Element { - const { t } = useTranslation('app_settings') + const { t } = useTranslation(['app_settings', 'branded']) const trackEvent = useTrackEvent() const dispatch = useDispatch() const localRobot = useSelector(getLocalRobot) @@ -59,7 +59,9 @@ export function OnDeviceDisplayAppFallback({ alignItems={ALIGN_CENTER} justifyContent={JUSTIFY_CENTER} > - {t('error_boundary_description')} + + {t('branded:error_boundary_description')} + { }, }, } as any) + // TODO(bh, 2024-03-27): implement testing of branded and anonymous i18n, but for now pass through + vi.mocked( + OnDeviceLocalizationProvider + ).mockImplementation((props: OnDeviceLocalizationProviderProps) => ( + <>{props.children} + )) }) afterEach(() => { vi.resetAllMocks() diff --git a/app/src/LocalizationProvider.tsx b/app/src/LocalizationProvider.tsx new file mode 100644 index 00000000000..ec45fa31a3e --- /dev/null +++ b/app/src/LocalizationProvider.tsx @@ -0,0 +1,63 @@ +import * as React from 'react' +import { I18nextProvider } from 'react-i18next' +import reduce from 'lodash/reduce' + +import { useRobotSettingsQuery } from '@opentrons/react-api-client' + +import { resources } from './assets/localization' +import { i18n, i18nCb, i18nConfig } from './i18n' + +import type { RobotSettingsField } from '@opentrons/api-client' + +export interface OnDeviceLocalizationProviderProps { + children?: React.ReactNode +} + +const BRANDED_RESOURCE = 'branded' +const ANONYMOUS_RESOURCE = 'anonymous' + +// TODO(bh, 2024-03-26): anonymization limited to ODD for now, may change in future OEM phases +export function OnDeviceLocalizationProvider( + props: OnDeviceLocalizationProviderProps +): JSX.Element | null { + const { settings } = useRobotSettingsQuery().data ?? {} + const oemModeSetting = (settings ?? []).find( + (setting: RobotSettingsField) => setting?.id === 'enableOEMMode' + ) + const isOEMMode = oemModeSetting?.value ?? false + + // iterate through language resources, nested files, substitute anonymous file for branded file for OEM mode + const anonResources = reduce( + resources, + (acc, resource, language) => { + const anonFiles = reduce( + resource, + (acc, file, fileName) => { + if (fileName === BRANDED_RESOURCE && isOEMMode) { + return acc + } else if (fileName === ANONYMOUS_RESOURCE) { + return isOEMMode ? { ...acc, [BRANDED_RESOURCE]: file } : acc + } else { + return { ...acc, [fileName]: file } + } + }, + {} + ) + return { ...acc, [language]: anonFiles } + }, + {} + ) + + const anonI18n = i18n.createInstance( + { + ...i18nConfig, + resources: anonResources, + }, + i18nCb + ) + + // block render until settings are fetched + return settings != null ? ( + {props.children} + ) : null +} diff --git a/app/src/assets/localization/en/anonymous.json b/app/src/assets/localization/en/anonymous.json new file mode 100644 index 00000000000..ac288115d49 --- /dev/null +++ b/app/src/assets/localization/en/anonymous.json @@ -0,0 +1,72 @@ +{ + "a_robot_software_update_is_available": "A robot software update is required to run protocols with this version of the Opentrons App. Go to Robot", + "about_flex_gripper": "About Gripper", + "alternative_security_types_description": "The robot supports connecting to various enterprise access points. Connect via USB and finish setup in the robot's app.", + "calibration_block_description": "This block is a specially made tool that fits perfectly on your deck and helps with calibration.If you do not have a Calibration Block, please email support@opentrons.com so we can send you one. In your message, be sure to include your name, company or institution name, and shipping address. While you wait for the block to arrive, you can use the flat surface on the trash bin of your robot instead.", + "calibration_on_opentrons_tips_is_important": "It’s extremely important to perform this calibration using the Opentrons tips and tip racks specified above, as the robot determines accuracy based on the known measurements of these tips.", + "choose_what_data_to_share": "Choose what robot data to share.", + "computer_in_app_is_controlling_robot": "A computer with the Opentrons App is currently controlling this robot.", + "confirm_terminate": "This will immediately stop the activity begun on a computer. You, or another user, may lose progress or see an error in the Opentrons App.", + "connect_and_screw_in_gripper": "Connect and secure Gripper", + "connect_via_usb_description_3": "3. Launch the robot's desktop app on your computer to continue.", + "connection_description_usb": "Connect directly to a computer.", + "connection_lost_description": "The Opentrons App is unable to communicate with this robot right now. Double check the USB or Wifi connection to the robot, then try to reconnect.", + "contact_information": "Contact support for assistance.", + "contact_support_for_connection_help": "If none of these work, contact Opentrons Support for help (via the question mark link in this app, or by emailing {{support_email}}.)", + "deck_fixture_setup_modal_bottom_description": "For details on installing different fixture types, contact support.", + "delete_protocol_from_app": "Delete the protocol, make changes to address the error, and resend the protocol to this robot from the robot's app.", + "error_boundary_description": "You need to restart the touchscreen. Contact support for assistance.", + "estop_pressed_description": "First, safely clear the deck of any labware or spills. Then, twist the E-stop button clockwise. Finally, have the robot move the gantry to its home position.", + "find_your_robot": "Find your robot in the Opentrons App to install software updates.", + "firmware_update_download_logs": "Contact support for assistance.", + "general_error_message": "If you keep getting this message, try restarting your app and/or robot. If this does not resolve the issue please contact Opentrons Support.", + "gripper_still_attached": "Gripper still attached", + "gripper_successfully_attached_and_calibrated": "Gripper successfully attached and calibrated", + "gripper_successfully_calibrated": "Gripper successfully calibrated", + "gripper_successfully_detached": "Gripper successfully detached", + "gripper": "Gripper", + "ip_description_second": "Opentrons recommends working with your network administrator to assign a static IP address to the robot.", + "learn_uninstalling": "Learn more about uninstalling the Opentrons App", + "loosen_screws_and_detach": "Loosen screws and detach Gripper", + "modal_instructions": "For step-by-step instructions on setting up your module, consult the Quickstart Guide that came in its box. You can also click the link below or scan the QR code to visit the modules section of the Opentrons Help Center.", + "module_calibration_failed": "Module calibration was unsuccessful. Make sure the calibration adapter is fully seated on the module and try again. If you still have trouble, contact Opentrons Support.{{error}}", + "module_calibration_get_started": "To get started, remove labware from the deck and clean up the working area to make the calibration easier. Also gather the needed equipment shown to the right.The calibration adapter came with your module. The pipette probe came with your robot's pipette.", + "module_error_contact_support": "Try powering the module off and on again. If the error persists, contact Opentrons Support.", + "network_setup_menu_description": "You’ll use this connection to run software updates and load protocols onto your robot.", + "opentrons_app_successfully_updated": "The Opentrons App was successfully updated.", + "opentrons_app_update": "Opentrons App update", + "opentrons_app_update_available": "Opentrons App Update Available", + "opentrons_app_update_available_variation": "An Opentrons App update is available.", + "opentrons_app_will_use_interpreter": "If specified, the Opentrons App will use the Python interpreter at this path instead of the default bundled Python interpreter.", + "opentrons_cares_about_privacy": "We care about your privacy. We anonymize all data and only use it to improve our products.", + "opentrons_def": "Opentrons Definition", + "opentrons_labware_def": "Opentrons labware definition", + "opentrons_tip_racks_recommended": "Opentrons tip racks are highly recommended. Accuracy cannot be guaranteed with other tip racks.", + "opentrons_tip_rack_name": "opentrons", + "previous_releases": "View previous Opentrons releases", + "receive_alert": "Receive an alert when an Opentrons software update is available.", + "restore_description": "Opentrons does not recommend reverting to previous software versions, but you can access previous releases below. For best results, uninstall the existing app and remove its configuration files before installing the previous version.", + "robot_server_version_ot3_description": "The robot software includes the robot server and the touchscreen display interface.", + "robot_software_update_required": "A robot software update is required to run protocols with this version of the Opentrons App.", + "run_failed_modal_description_desktop": "Contact support for assistance.", + "secure_labware_explanation_magnetic_module": "Opentrons recommends ensuring your labware locks to the Magnetic Module by adjusting the black plate bracket on top of the module. Please note there are two sizes of plate brackets supplied with your module: standard and deep well. These brackets can be removed and swapped by unscrewing the modules thumb screw (the silver knob on the front).", + "secure_labware_explanation_thermocycler": "Opentrons recommends securing your labware to the Thermocycler module by closing its latch. Doing so ensures level and accurate plate placement for optimal results.", + "send_a_protocol_to_store": "Send a protocol to the robot to get started.", + "setup_instructions_description": "For step-by-step instructions on setting up your module, consult the Quickstart Guide that came in its box or scan the QR code to visit the modules section of the Opentrons Help Center.", + "share_app_analytics": "Share App Analytics with Opentrons", + "share_app_analytics_description": "Help Opentrons improve its products and services by automatically sending anonymous diagnostics and usage data.", + "share_display_usage_description": "Data on how you interact with the robot's touchscreen.", + "share_logs_with_opentrons": "Share Robot logs with Opentrons", + "share_logs_with_opentrons_description": "Help Opentrons improve its products and services by automatically sending anonymous robot logs. Opentrons uses these logs to troubleshoot robot issues and spot error trends.", + "show_labware_offset_snippets_description": "Only for users who need to apply Labware Offset data outside of the Opentrons App. When enabled, code snippets for Jupyter Notebook and SSH are available during protocol setup.", + "something_seems_wrong": "There may be a problem with your pipette. Exit setup and contact support for assistance.", + "these_are_advanced_settings": "These are advanced settings. Please do not attempt to adjust without assistance from support. Changing these settings may affect the lifespan of your pipette.These settings do not override any pipette settings defined in protocols.", + "update_requires_restarting_app": "Updating requires restarting the Opentrons App.", + "update_robot_software_description": "Bypass the Opentrons App auto-update process and update the robot software manually.", + "update_robot_software_link": "Launch Opentrons software update page", + "use_older_protocol_analysis_method_description": "Use an older, slower method of analyzing uploaded protocols. This changes how the OT-2 validates your protocol during the upload step, but does not affect how your protocol actually runs. Support might ask you to change this setting if you encounter problems with the newer, faster protocol analysis method.", + "versions_sync": "Learn more about keeping the Opentrons App and robot software in sync", + "want_to_help_out": "Want to help out Opentrons?", + "welcome_title": "Welcome!", + "why_use_lpc": "Labware Position Check is intended to correct for minor variances. Opentrons does not recommend using Labware Position Check to compensate for large positional adjustments. Needing to set large labware offsets could indicate a problem with robot calibration." +} diff --git a/app/src/assets/localization/en/app_settings.json b/app/src/assets/localization/en/app_settings.json index 18e3eef9e8a..389854a8b33 100644 --- a/app/src/assets/localization/en/app_settings.json +++ b/app/src/assets/localization/en/app_settings.json @@ -11,16 +11,12 @@ "additional_folder_location": "Additional Source Folder", "additional_labware_folder_title": "Additional Custom Labware Source Folder", "advanced": "Advanced", - "allow_sending_all_protocols_to_ot3": "Allow Sending All Protocols to Opentrons Flex", - "allow_sending_all_protocols_to_ot3_description": "Enable the \"Send to Opentrons Flex\" menu item for each imported protocol, even if protocol analysis fails or does not recognize it as designed for the Opentrons Flex.", - "analytics_description": "Help Opentrons improve its products and services by automatically sending anonymous diagnostics and usage data.", "app_changes": "App Changes in ", "app_settings": "App Settings", "bug_fixes": "Bug Fixes", "cal_block": "Always use calibration block to calibrate", "change_folder_button": "Change labware source folder", "channel": "Channel", - "choose_what_data_to_share": "Choose what data to share with Opentrons.", "clear_confirm": "Clear unavailable robots", "clear_robots_button": "Clear unavailable robots list", "clear_robots_description": "Clear the list of unavailable robots on the Devices page. This action cannot be undone.", @@ -35,7 +31,6 @@ "download_update": "Downloading update...", "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_description": "You need to restart the touchscreen. Then download the robot logs from the Opentrons App and send them to support@opentrons.com for assistance.", "error_boundary_desktop_app_description": "You need to reload the app. Contact support with the following error message:", "error_boundary_title": "An unknown error has occurred", "feature_flags": "Feature Flags", @@ -46,20 +41,12 @@ "installing_update": "Installing update...", "ip_available": "Available", "ip_description_first": "Enter an IP address or hostname to connect to a robot.", - "ip_description_second": "Opentrons recommends working with your network administrator to assign a static IP address to the robot.", - "learn_uninstalling": "Learn more about uninstalling the Opentrons App", "manage_versions": "It is very important for the robot and app software to be on the same version. Manage the robot software versions via Robot Settings > Advanced.", "new_features": "New Features", "no_folder": "No additional source folder specified", "no_specified_folder": "No path specified", "no_unavail_robots_to_clear": "No unavailable robots to clear", "not_found": "Not Found", - "opentrons_app_successfully_updated": "The Opentrons App was successfully updated.", - "opentrons_app_update": "Opentrons App update", - "opentrons_app_update_available": "Opentrons App Update Available", - "opentrons_app_update_available_variation": "An Opentrons App update is available.", - "opentrons_app_will_use_interpreter": "If specified, the Opentrons App will use the Python interpreter at this path instead of the default bundled Python interpreter.", - "opentrons_cares_about_privacy": "Opentrons cares about your privacy. We anonymize all data and only use it to improve our products.", "opt_in": "Opt in", "opt_in_description": "Automatically send us anonymous diagnostics and usage data. We only use this information to improve our products.", "opt_out": "Opt out", @@ -68,29 +55,22 @@ "override_path_to_python": "Override Path to Python", "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.", - "previous_releases": "View previous Opentrons releases", "privacy": "Privacy", "problem_during_update": "This update is taking longer than usual.", "prompt": "Always show the prompt to choose calibration block or trash bin", - "receive_alert": "Receive an alert when an Opentrons software update is available.", "release_notes": "Release notes", "reload_app": "Reload app", "remind_later": "Remind me later", "reset_to_default": "Reset to default", "restart_touchscreen": "Restart touchscreen", "restarting_app": "Download complete, restarting the app...", - "restore_description": "Opentrons does not recommend reverting to previous software versions, but you can access previous releases below. For best results, uninstall the existing app and remove its configuration files before installing the previous version.", "restore_previous": "See how to restore a previous software version", "searching": "Searching for 30s", "setup_connection": "Set up connection", - "share_app_analytics": "Share App Analytics with Opentrons", - "share_app_analytics_description": "Help Opentrons improve its products and services by automatically sending anonymous diagnostics and usage data.", "share_display_usage": "Share display usage", - "share_display_usage_description": "Data on how you interact with the touchscreen on Flex.", "share_robot_logs": "Share robot logs", "share_robot_logs_description": "Data on actions the robot does, like running protocols.", "show_labware_offset_snippets": "Show Labware Offset data code snippets", - "show_labware_offset_snippets_description": "Only for users who need to apply Labware Offset data outside of the Opentrons App. When enabled, code snippets for Jupyter Notebook and SSH are available during protocol setup.", "software_update_available": "Software Update Available", "software_version": "App Software Version", "successfully_deleted_unavail_robots": "Successfully deleted unavailable robots", @@ -104,7 +84,6 @@ "update_available": "Update available", "update_channel": "Update Channel", "update_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.", - "update_requires_restarting": "Updating requires restarting the Opentrons App.", "usb_to_ethernet_adapter_description": "Description", "usb_to_ethernet_adapter_driver_version": "Driver Version", "usb_to_ethernet_adapter_info": "USB-to-Ethernet Adapter Information", @@ -116,11 +95,6 @@ "usb_to_ethernet_not_connected": "No USB-to-Ethernet adapter connected", "usb_to_ethernet_unknown_manufacturer": "Unknown Manufacturer", "usb_to_ethernet_unknown_product": "Unknown Adapter", - "versions_sync": "Learn more about keeping the Opentrons App and robot software in sync", - "view_change_log": "View Opentrons technical change log", - "view_issue_tracker": "View Opentrons issue tracker", - "view_release_notes": "View full Opentrons release notes", "view_software_update": "View software update", - "view_update": "View Update", - "want_to_help_out": "Want to help out Opentrons?" + "view_update": "View Update" } diff --git a/app/src/assets/localization/en/branded.json b/app/src/assets/localization/en/branded.json new file mode 100644 index 00000000000..c28f2d9b3cc --- /dev/null +++ b/app/src/assets/localization/en/branded.json @@ -0,0 +1,72 @@ +{ + "a_robot_software_update_is_available": "A robot software update is required to run protocols with this version of the Opentrons App. Go to Robot", + "about_flex_gripper": "About Flex Gripper", + "alternative_security_types_description": "The Opentrons App supports connecting Flex to various enterprise access points. Connect via USB and finish setup in the app.", + "calibration_block_description": "This block is a specially made tool that fits perfectly on your deck and helps with calibration.If you do not have a Calibration Block, please email support@opentrons.com so we can send you one. In your message, be sure to include your name, company or institution name, and shipping address. While you wait for the block to arrive, you can use the flat surface on the trash bin of your robot instead.", + "calibration_on_opentrons_tips_is_important": "It’s extremely important to perform this calibration using the Opentrons tips and tip racks specified above, as the robot determines accuracy based on the known measurements of these tips.", + "choose_what_data_to_share": "Choose what data to share with Opentrons.", + "computer_in_app_is_controlling_robot": "A computer with the Opentrons App is currently controlling this robot.", + "confirm_terminate": "This will immediately stop the activity begun on a computer. You, or another user, may lose progress or see an error in the Opentrons App.", + "connect_and_screw_in_gripper": "Connect and secure Flex Gripper", + "connect_via_usb_description_3": "3. Launch the Opentrons App on the computer to continue.", + "connection_description_usb": "Connect directly to a computer (running the Opentrons App).", + "connection_lost_description": "The Opentrons App is unable to communicate with this robot right now. Double check the USB or Wifi connection to the robot, then try to reconnect.", + "contact_information": "Download the robot logs from the Opentrons App and send it to support@opentrons.com for assistance.", + "contact_support_for_connection_help": "If none of these work, contact Opentrons Support for help (via the question mark link in this app, or by emailing {{support_email}}.)", + "deck_fixture_setup_modal_bottom_description": "For details on installing different fixture types, scan the QR code or search for “deck configuration” on support.opentrons.com", + "delete_protocol_from_app": "Delete the protocol, make changes to address the error, and resend the protocol to this robot from the Opentrons App.", + "error_boundary_description": "You need to restart the touchscreen. Then download the robot logs from the Opentrons App and send them to support@opentrons.com for assistance.", + "estop_pressed_description": "First, safely clear the deck of any labware or spills. Then, twist the E-stop button clockwise. Finally, have Flex move the gantry to its home position.", + "find_your_robot": "Find your robot in the Opentrons App to install software updates.", + "firmware_update_download_logs": "Download the robot logs from the Opentrons App and send them to support@opentrons.com for assistance.", + "general_error_message": "If you keep getting this message, try restarting your app and/or robot. If this does not resolve the issue please contact Opentrons Support.", + "gripper_still_attached": "Flex Gripper still attached", + "gripper_successfully_attached_and_calibrated": "Flex Gripper successfully attached and calibrated", + "gripper_successfully_calibrated": "Flex Gripper successfully calibrated", + "gripper_successfully_detached": "Flex Gripper successfully detached", + "gripper": "Flex Gripper", + "ip_description_second": "Opentrons recommends working with your network administrator to assign a static IP address to the robot.", + "learn_uninstalling": "Learn more about uninstalling the Opentrons App", + "loosen_screws_and_detach": "Loosen screws and detach Flex Gripper", + "modal_instructions": "For step-by-step instructions on setting up your module, consult the Quickstart Guide that came in its box. You can also click the link below or scan the QR code to visit the modules section of the Opentrons Help Center.", + "module_calibration_failed": "Module calibration was unsuccessful. Make sure the calibration adapter is fully seated on the module and try again. If you still have trouble, contact Opentrons Support.{{error}}", + "module_calibration_get_started": "To get started, remove labware from the deck and clean up the working area to make the calibration easier. Also gather the needed equipment shown to the right.The calibration adapter came with your module. The pipette probe came with your Flex pipette.", + "module_error_contact_support": "Try powering the module off and on again. If the error persists, contact Opentrons Support.", + "network_setup_menu_description": "You’ll use this connection to run software updates and load protocols onto your Opentrons Flex.", + "opentrons_app_successfully_updated": "The Opentrons App was successfully updated.", + "opentrons_app_update": "Opentrons App update", + "opentrons_app_update_available": "Opentrons App Update Available", + "opentrons_app_update_available_variation": "An Opentrons App update is available.", + "opentrons_app_will_use_interpreter": "If specified, the Opentrons App will use the Python interpreter at this path instead of the default bundled Python interpreter.", + "opentrons_cares_about_privacy": "Opentrons cares about your privacy. We anonymize all data and only use it to improve our products.", + "opentrons_def": "Opentrons Definition", + "opentrons_labware_def": "Opentrons labware definition", + "opentrons_tip_rack_name": "opentrons", + "opentrons_tip_racks_recommended": "Opentrons tip racks are highly recommended. Accuracy cannot be guaranteed with other tip racks.", + "previous_releases": "View previous Opentrons releases", + "receive_alert": "Receive an alert when an Opentrons software update is available.", + "restore_description": "Opentrons does not recommend reverting to previous software versions, but you can access previous releases below. For best results, uninstall the existing app and remove its configuration files before installing the previous version.", + "robot_server_version_ot3_description": "The Opentrons Flex software includes the robot server and the touchscreen display interface.", + "robot_software_update_required": "A robot software update is required to run protocols with this version of the Opentrons App.", + "run_failed_modal_description_desktop": "Download the run log and send it to support@opentrons.com for assistance.", + "secure_labware_explanation_magnetic_module": "Opentrons recommends ensuring your labware locks to the Magnetic Module by adjusting the black plate bracket on top of the module. Please note there are two sizes of plate brackets supplied with your module: standard and deep well. These brackets can be removed and swapped by unscrewing the modules thumb screw (the silver knob on the front).", + "secure_labware_explanation_thermocycler": "Opentrons recommends securing your labware to the Thermocycler module by closing its latch. Doing so ensures level and accurate plate placement for optimal results.", + "send_a_protocol_to_store": "Send a protocol from the Opentrons App to get started.", + "setup_instructions_description": "For step-by-step instructions on setting up your module, consult the Quickstart Guide that came in its box or scan the QR code to visit the modules section of the Opentrons Help Center.", + "share_app_analytics": "Share App Analytics with Opentrons", + "share_app_analytics_description": "Help Opentrons improve its products and services by automatically sending anonymous diagnostics and usage data.", + "share_display_usage_description": "Data on how you interact with the touchscreen on Flex.", + "share_logs_with_opentrons": "Share Robot logs with Opentrons", + "share_logs_with_opentrons_description": "Help Opentrons improve its products and services by automatically sending anonymous robot logs. Opentrons uses these logs to troubleshoot robot issues and spot error trends.", + "show_labware_offset_snippets_description": "Only for users who need to apply Labware Offset data outside of the Opentrons App. When enabled, code snippets for Jupyter Notebook and SSH are available during protocol setup.", + "something_seems_wrong": "There may be a problem with your pipette. Exit setup and contact Opentrons Support for assistance.", + "these_are_advanced_settings": "These are advanced settings. Please do not attempt to adjust without assistance from Opentrons Support. Changing these settings may affect the lifespan of your pipette.These settings do not override any pipette settings defined in protocols.", + "update_requires_restarting_app": "Updating requires restarting the Opentrons App.", + "update_robot_software_description": "Bypass the Opentrons App auto-update process and update the robot software manually.", + "update_robot_software_link": "Launch Opentrons software update page", + "use_older_protocol_analysis_method_description": "Use an older, slower method of analyzing uploaded protocols. This changes how the OT-2 validates your protocol during the upload step, but does not affect how your protocol actually runs. Opentrons Support might ask you to change this setting if you encounter problems with the newer, faster protocol analysis method.", + "versions_sync": "Learn more about keeping the Opentrons App and robot software in sync", + "want_to_help_out": "Want to help out Opentrons?", + "welcome_title": "Welcome to your Opentrons Flex!", + "why_use_lpc": "Labware Position Check is intended to correct for minor variances. Opentrons does not recommend using Labware Position Check to compensate for large positional adjustments. Needing to set large labware offsets could indicate a problem with robot calibration." +} diff --git a/app/src/assets/localization/en/device_details.json b/app/src/assets/localization/en/device_details.json index d217718af42..4520a016224 100644 --- a/app/src/assets/localization/en/device_details.json +++ b/app/src/assets/localization/en/device_details.json @@ -1,5 +1,4 @@ { - "about_flex_gripper": "About Flex Gripper", "about_gripper": "About gripper", "about_module": "About {{name}}", "about_pipette_name": "About {{name}} Pipette", @@ -40,7 +39,6 @@ "deck_configuration": "deck configuration", "deck_fixture_setup_instructions": "Deck fixture setup instructions", "deck_fixture_setup_modal_bottom_description_desktop": "For detailed instructions for different types of fixtures, scan the QR code or go to the link below.", - "deck_fixture_setup_modal_bottom_description": "For details on installing different fixture types, scan the QR code or search for “deck configuration” on support.opentrons.com", "deck_fixture_setup_modal_top_description": "First, unscrew and remove the deck slot where you'll install a fixture. Then put the fixture in place and attach it as needed.", "deck_slot": "deck slot {{slot}}", "delete_run": "Delete protocol run record", @@ -94,7 +92,6 @@ "module_calibration_required_update_pipette_FW": "Update pipette firmware before proceeding with required module calibration.", "module_calibration_required": "Module calibration required.", "module_controls": "Module Controls", - "module_error_contact_support": "Try powering the module off and on again. If the error persists, contact Opentrons Support.", "module_error": "Module error", "module_name_error": "{{moduleName}} error", "module_status_range": "Between {{min}} - {{max}} {{unit}}", @@ -177,7 +174,6 @@ "tempdeck_slideout_body": "Pre heat or cool your {{model}}. Enter a whole number between 4 °C and 96 °C.", "tempdeck_slideout_title": "Set Temperature for {{name}}", "temperature": "Temperature", - "these_are_advanced_settings": "These are advanced settings. Please do not attempt to adjust without assistance from Opentrons Support. Changing these settings may affect the lifespan of your pipette.These settings do not override any pipette settings defined in protocols.", "this_robot_will_restart_with_update": "This robot has to restart to update its software. Restarting will immediately stop the current run or calibration.Do you want to update now anyway?", "tip_pickup_drop": "Tip Pickup / Drop", "to_run_protocol_go_to_protocols_page": "To run a protocol on this robot, import a protocol on the Protocols page", diff --git a/app/src/assets/localization/en/device_settings.json b/app/src/assets/localization/en/device_settings.json index f92a6e30d69..c6bd00ad70d 100644 --- a/app/src/assets/localization/en/device_settings.json +++ b/app/src/assets/localization/en/device_settings.json @@ -6,7 +6,6 @@ "advanced": "Advanced", "alpha_description": "Warning: alpha releases are feature-complete but may contain significant bugs.", "alternative_security_types": "Alternative security types", - "alternative_security_types_description": "The Opentrons App supports connecting Flex to various enterprise access points. Connect via USB and finish setup in the app.", "app_change_in": "App Changes in {{version}}", "apply_historic_offsets": "Apply Labware Offsets", "are_you_sure_you_want_to_disconnect": "Are you sure you want to disconnect from {{ssid}}?", @@ -59,16 +58,13 @@ "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.", - "connect_via_usb_description_3": "3. Launch the Opentrons App on the computer to continue.", "connected": "Connected", "connected_network": "Connected Network", "connected_to_ssid": "Connected to {{ssid}}", "connected_via": "Connected via {{networkInterface}}", "connecting_to": "Connecting to {{ssid}}...", "connection_description_ethernet": "Connect to your lab's wired network.", - "connection_description_usb": "Connect directly to a computer (running the Opentrons App).", "connection_description_wifi": "Find a network in your lab or enter your own.", - "connection_lost_description": "The Opentrons App is unable to communicate with this robot right now. Double check the USB or Wifi connection to the robot, then try to reconnect.", "connection_to_robot_lost": "Connection to robot lost", "deck_calibration_description": "Calibrating the deck is required for new robots or after you relocate your robot. Recalibrating the deck will require you to also recalibrate pipette offsets.", "deck_calibration_missing": "Deck calibration missing", @@ -119,7 +115,6 @@ "estop_missing": "E-stop missing", "estop_missing_description": "Your E-stop could be damaged or detached. {{robotName}} lost its connection to the E-stop, so it canceled the protocol. Connect a functioning E-stop to continue.", "estop_pressed": "E-stop pressed", - "estop_pressed_description": "First, safely clear the deck of any labware or spills. Then, twist the E-stop button clockwise. Finally, have Flex move the gantry to its home position.", "ethernet": "Ethernet", "ethernet_connection_description": "Connect an Ethernet cable to the back of the robot and a network switch or hub.", "exit": "exit", @@ -129,7 +124,6 @@ "factory_resets_cannot_be_undone": "Factory resets cannot be undone.", "failed_to_connect_to_ssid": "Failed to connect to {{ssid}}", "feature_flags": "Feature Flags", - "find_your_robot": "Find your robot in the Opentrons App to install software updates.", "finish_setup": "Finish setup", "firmware_version": "Firmware Version", "fully_calibrate_before_checking_health": "Fully calibrate your robot before checking calibration health", @@ -174,7 +168,6 @@ "need_another_security_type": "Need another security type?", "network_name": "Network Name", "network_settings": "Network Settings", - "network_setup_menu_description": "You’ll use this connection to run software updates and load protocols onto your Opentrons Flex.", "networking": "Networking", "never": "Never", "new_features": "New Features", @@ -240,10 +233,8 @@ "robot_operating_update_available": "Robot Operating System Update Available", "robot_serial_number": "Robot Serial Number", "robot_server_version": "Robot Server Version", - "robot_server_version_ot3_description": "The Opentrons Flex software includes the robot server and the touchscreen display interface.", "robot_settings": "Robot Settings", "robot_settings_advanced_unknown": "Unknown", - "robot_software_update_required": "A robot software update is required to run protocols with this version of the Opentrons App.", "robot_successfully_connected": "Robot successfully connected to {{networkName}}.", "robot_system_version": "Robot System Version", "robot_system_version_available": "Robot System Version {{releaseVersion}} available", @@ -261,10 +252,6 @@ "select_authentication_method": "Select authentication method for your selected network.", "sending_software": "Sending software...", "serial": "Serial", - "share_logs_with_opentrons": "Share Robot logs with Opentrons", - "share_logs_with_opentrons_description": "Help Opentrons improve its products and services by automatically sending anonymous robot logs. Opentrons uses these logs to troubleshoot robot issues and spot error trends.", - "share_logs_with_opentrons_description_short": "Share anonymous robot logs with Opentrons.", - "share_logs_with_opentrons_short": "Share Robot logs", "short_trash_bin": "Short trash bin", "short_trash_bin_description": "For pre-2019 robots with trash bins that are 55mm tall (instead of 77mm default)", "show": "Show", @@ -278,7 +265,6 @@ "successfully_connected": "Successfully connected!", "successfully_connected_to_network": "Successfully connected to {{ssid}}!", "supported_protocol_api_versions": "Supported Protocol API Versions", - "switch_to_usb_description": "If your network uses a different authentication method, connect to the Opentrons App and finish Wi-Fi setup there.", "text_size": "Text Size", "text_size_description": "Text on all screens will adjust to the size you choose below.", "tip_length_calibrations_history": "See all Tip Length Calibration history", @@ -296,27 +282,20 @@ "update_found": "Update found!", "update_robot_now": "Update robot now", "update_robot_software": "Update robot software manually with a local file (.zip)", - "update_robot_software_description": "Bypass the Opentrons App auto-update process and update the robot software manually.", - "update_robot_software_link": "Launch Opentrons software update page", "updating": "Updating", - "update_requires_restarting": "Updating the robot software requires restarting the robot", + "update_requires_restarting_robot": "Updating the robot software requires restarting the robot", "usage_settings": "Usage Settings", "usb": "USB", "usb_to_ethernet_description": "Looking for USB-to-Ethernet Adapter info?", "use_older_aspirate": "Use older aspirate behavior", "use_older_aspirate_description": "Aspirate with the less accurate volumetric calibrations that were used before version 3.7.0. Use this if you need consistency with pre-v3.7.0 results. This only affects GEN1 P10S, P10M, P50M, and P300S pipettes.", "use_older_protocol_analysis_method": "Use older protocol analysis method", - "use_older_protocol_analysis_method_description": "Use an older, slower method of analyzing uploaded protocols. This changes how the OT-2 validates your protocol during the upload step, but does not affect how your protocol actually runs. Opentrons Support might ask you to change this setting if you encounter problems with the newer, faster protocol analysis method.", "validating_software": "Validating software...", "view_details": "View details", "view_latest_release_notes_at": "View latest release notes at {{url}}", "view_network_details": "View network details", - "view_opentrons_issue_tracker": "View Opentrons issue tracker", - "view_opentrons_release_notes": "View full Opentrons release notes", - "view_opentrons_technical_change_log": "View Opentrons technical change log", "view_update": "View update", "welcome_description": "Quickly run protocols and check on your robot's status right on your lab bench.", - "welcome_title": "Welcome to your Opentrons Flex!", "wifi": "Wi-Fi", "wired_ip": "Wired IP", "wired_mac_address": "Wired MAC Address", diff --git a/app/src/assets/localization/en/devices_landing.json b/app/src/assets/localization/en/devices_landing.json index 60a25974fec..b0a3307ace1 100644 --- a/app/src/assets/localization/en/devices_landing.json +++ b/app/src/assets/localization/en/devices_landing.json @@ -4,7 +4,6 @@ "check_same_network": "Check that the computer and robot are on the same network", "connect_to_network": "Connect to network", "connection_troubleshooting_intro": "If you’re having trouble with the robot’s connection, try these troubleshooting tasks. First, double check that the robot is powered on.", - "contact_support_for_connection_help": "If none of these work, contact Opentrons Support for help (via the question mark link in this app, or by emailing {{support_email}}.)", "deck_configuration": "Deck configuration", "devices": "Devices", "disconnect_from_network": "Disconnect from network", diff --git a/app/src/assets/localization/en/firmware_update.json b/app/src/assets/localization/en/firmware_update.json index 8abe122d914..c34fa96fe77 100644 --- a/app/src/assets/localization/en/firmware_update.json +++ b/app/src/assets/localization/en/firmware_update.json @@ -1,5 +1,4 @@ { - "download_logs": "Download the robot logs from the Opentrons App and send them to support@opentrons.com for assistance.", "firmware_out_of_date": "The firmware for {{mount}} {{instrument}} is out of date. You need to update it before running protocols that use this instrument.", "gantry_x": "Gantry X", "gantry_y": "Gantry Y", diff --git a/app/src/assets/localization/en/gripper_wizard_flows.json b/app/src/assets/localization/en/gripper_wizard_flows.json index a868cdb474e..ff98d8e07f0 100644 --- a/app/src/assets/localization/en/gripper_wizard_flows.json +++ b/app/src/assets/localization/en/gripper_wizard_flows.json @@ -8,7 +8,6 @@ "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", - "connect_and_screw_in_gripper": "Connect and secure Flex Gripper", "continue": "Continue", "continue_calibration": "Continue calibration", "detach_gripper": "Detach Gripper", @@ -17,17 +16,11 @@ "get_started": "Get started", "gripper_calibration": "Gripper Calibration", "gripper_recalibration": "Gripper Recalibration", - "gripper_still_attached": "Flex Gripper still attached", - "gripper_successfully_attached_and_calibrated": "Flex Gripper successfully attached and calibrated", "gripper_successfully_attached": "Gripper successfully attached", - "gripper_successfully_calibrated": "Flex Gripper successfully calibrated", - "gripper_successfully_detached": "Flex Gripper successfully detached", - "gripper": "Flex Gripper", "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", - "loosen_screws_and_detach": "Loosen screws and detach Flex Gripper", "move_gantry_to_front": "Move gantry to front", "move_pin_from_front_to_rear_jaw": "Remove the calibration pin from the front jaw and attach it to the rear jaw.", "move_pin_from_rear_jaw_to_storage": "Take the calibration pin from the rear gripper jaw and return it to its storage location.", diff --git a/app/src/assets/localization/en/index.ts b/app/src/assets/localization/en/index.ts index c7256b1d415..68534a6b3ac 100644 --- a/app/src/assets/localization/en/index.ts +++ b/app/src/assets/localization/en/index.ts @@ -1,5 +1,7 @@ import shared from './shared.json' +import anonymous from './anonymous.json' import app_settings from './app_settings.json' +import branded from './branded.json' import change_pipette from './change_pipette.json' import protocol_command_text from './protocol_command_text.json' import device_details from './device_details.json' @@ -14,25 +16,21 @@ import labware_details from './labware_details.json' import labware_landing from './labware_landing.json' import labware_position_check from './labware_position_check.json' import module_wizard_flows from './module_wizard_flows.json' -import more_network_and_system from './more_network_and_system.json' -import more_panel from './more_panel.json' import pipette_wizard_flows from './pipette_wizard_flows.json' -import protocol_calibration from './protocol_calibration.json' import protocol_details from './protocol_details.json' import protocol_info from './protocol_info.json' import protocol_list from './protocol_list.json' import protocol_setup from './protocol_setup.json' -import robot_advanced_settings from './robot_advanced_settings.json' import robot_calibration from './robot_calibration.json' -import robot_connection from './robot_connection.json' import robot_controls from './robot_controls.json' -import robot_info from './robot_info.json' import run_details from './run_details.json' import top_navigation from './top_navigation.json' export const en = { shared, + anonymous, app_settings, + branded, change_pipette, protocol_command_text, device_details, @@ -47,19 +45,13 @@ export const en = { labware_landing, labware_position_check, module_wizard_flows, - more_network_and_system, - more_panel, pipette_wizard_flows, - protocol_calibration, protocol_details, protocol_info, protocol_list, protocol_setup, - robot_advanced_settings, robot_calibration, - robot_connection, robot_controls, - robot_info, run_details, top_navigation, } diff --git a/app/src/assets/localization/en/labware_landing.json b/app/src/assets/localization/en/labware_landing.json index 63212567561..17eebda979d 100644 --- a/app/src/assets/localization/en/labware_landing.json +++ b/app/src/assets/localization/en/labware_landing.json @@ -22,8 +22,6 @@ "labware": "labware", "last_updated": "Last updated", "open_labware_creator": "Open Labware Creator", - "opentrons_def": "Opentrons Definition", - "opentrons_labware_def": "Opentrons labware definition", "show_in_folder": "Show in folder", "unable_to_upload": "Unable to upload file", "yes_delete_def": "Yes, delete definition" diff --git a/app/src/assets/localization/en/labware_position_check.json b/app/src/assets/localization/en/labware_position_check.json index f08c465f7fa..4072826650a 100644 --- a/app/src/assets/localization/en/labware_position_check.json +++ b/app/src/assets/localization/en/labware_position_check.json @@ -27,9 +27,6 @@ "detach_probe": "Remove calibration probe", "ensure_nozzle_position_odd": "Ensure that the {{tip_type}} is centered above and level with {{item_location}}. If it isn't, tap Move pipette and then jog the pipette until it is properly aligned.", "ensure_nozzle_position_desktop": "Ensure that the {{tip_type}} is centered above and level with {{item_location}}. If it isn't, use the controls below or your keyboard to jog the pipette until it is properly aligned.", - "error_modal_header": "Something went wrong", - "error_modal_problem_in_app": "There was an error performing Labware Position Check. Please restart the app. If the problem persists, please contact Opentrons Support", - "error_modal_problem_on_robot": "There was an error processing your request on the robot", "exit_screen_confirm_exit": "Exit and discard all labware offsets", "exit_screen_go_back": "Go back to labware position check", "exit_screen_subtitle": "If you exit now, all labware offsets will be discarded. This cannot be undone.", diff --git a/app/src/assets/localization/en/module_wizard_flows.json b/app/src/assets/localization/en/module_wizard_flows.json index 636bb368662..a502b0ef797 100644 --- a/app/src/assets/localization/en/module_wizard_flows.json +++ b/app/src/assets/localization/en/module_wizard_flows.json @@ -21,12 +21,10 @@ "exit": "Exit", "firmware_up_to_date": "{{module}} firmware up to date.", "firmware_updated": "{{module}} firmware updated!", - "get_started": "To get started, remove labware from the deck and clean up the working area to make the calibration easier. Also gather the needed equipment shown to the right.The calibration adapter came with your module. The pipette probe came with your Flex pipette.", "install_adapter": "Place calibration adapter in {{module}}", "install_calibration_adapter": "Install calibration adapter", "location_occupied": "A {{fixture}} is currently specified here on the deck configuration", "module_calibrating": "Stand back, {{moduleName}} is calibrating", - "module_calibration_failed": "Module calibration was unsuccessful. Make sure the calibration adapter is fully seated on the module and try again. If you still have trouble, contact Opentrons Support.{{error}}", "module_calibration": "Module calibration", "module_secured": "The module must be fully secured in its caddy and secured in the deck slot.", "module_too_hot": "Module is too hot to proceed to module calibration", diff --git a/app/src/assets/localization/en/more_network_and_system.json b/app/src/assets/localization/en/more_network_and_system.json deleted file mode 100644 index a6fd1593b38..00000000000 --- a/app/src/assets/localization/en/more_network_and_system.json +++ /dev/null @@ -1,9 +0,0 @@ -{ - "description": "Description", - "driver_version": "Driver Version", - "launch_realtek_adapter_drivers_site": "Launch Realtek Adapter Drivers Site", - "manufacturer": "Manufacturer", - "network_and_system_title": "Network & System", - "u2e_adapter_information": "USB-to-Ethernet Adapter Information", - "u2e_driver_update_alert": "Update available for Realtek USB-to-Ethernet adapter driver" -} diff --git a/app/src/assets/localization/en/more_panel.json b/app/src/assets/localization/en/more_panel.json deleted file mode 100644 index 63b594c1f37..00000000000 --- a/app/src/assets/localization/en/more_panel.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "app": "App", - "custom_labware": "Custom Labware", - "network_and_system": "Network & System", - "resources": "Resources" -} diff --git a/app/src/assets/localization/en/pipette_wizard_flows.json b/app/src/assets/localization/en/pipette_wizard_flows.json index 5d13142349c..c1694816f00 100644 --- a/app/src/assets/localization/en/pipette_wizard_flows.json +++ b/app/src/assets/localization/en/pipette_wizard_flows.json @@ -77,7 +77,6 @@ "return_probe_error": "Return the calibration probe to its storage location before exiting. {{error}}", "single_mount_attached_error": "Single mount pipette is selected when this is the 96 channel flow", "single_or_8_channel": "{{single}} or {{eight}} pipette", - "something_seems_wrong": "There may be a problem with your pipette. Exit setup and contact Opentrons Support for assistance.", "stand_back": "Stand back, robot is in motion", "try_again": "try again", "unable_to_detect_probe": "Unable to detect calibration probe", diff --git a/app/src/assets/localization/en/protocol_calibration.json b/app/src/assets/localization/en/protocol_calibration.json deleted file mode 100644 index 1c65b64721f..00000000000 --- a/app/src/assets/localization/en/protocol_calibration.json +++ /dev/null @@ -1,22 +0,0 @@ -{ - "cal_data_existing_data": "Existing data", - "cal_data_legacy_definition": "Calibration Data N/A", - "cal_data_not_calibrated": "Not yet calibrated", - "cal_data_updated_data": "Updated data", - "cal_panel_title": "Placement and Calibration", - "labware_cal_labware_title": "labware", - "labware_cal_tipracks_title": "tip racks", - "labware_cal_title": "Labware Calibration", - "module_connect_description": "Power up and plug in the required module(s) via the OT-2 USB Ports. Place the modules as shown in the deck map.", - "module_connect_duplicate_description": "Plug the modules in to the USB ports as listed in the Placement and Calibration Panel. Check out our help docs for more information on using modules of the same type.", - "module_connect_instruction": "Plug the modules in to the USB ports as listed below, from left to right.", - "module_connect_missing_tooltip": "Connect module(s) to proceed to labware calibration", - "module_connect_proceed_button": "Continue to labware setup", - "modules_deck_slot_title": "slot", - "modules_module_title": "module", - "modules_title": "modules", - "modules_update_software_tooltip": "Update robot software to see USB port information", - "modules_usb_order_title": "USB order (L to R)", - "modules_usb_port_title": "USB port", - "tip_length_cal_title": "Tip Length Calibration" -} diff --git a/app/src/assets/localization/en/protocol_info.json b/app/src/assets/localization/en/protocol_info.json index d1e73288dcd..20d618db601 100644 --- a/app/src/assets/localization/en/protocol_info.json +++ b/app/src/assets/localization/en/protocol_info.json @@ -10,7 +10,6 @@ "creation_method": "Creation Method", "custom_labware_not_supported": "Robot doesn't support custom labware", "date_added": "Date Added", - "delete_protocol_from_app": "Delete the protocol, make changes to address the error, and resend the protocol to this robot from the Opentrons App.", "delete_protocol": "Delete protocol", "description": "Description", "drag_file_here": "Drag and drop protocol file here", @@ -69,16 +68,11 @@ "required_cal_data_title": "Calibration Data", "required_quantity_title": "Quantity", "required_type_title": "Type", - "rerunning_protocol_modal_body": "Opentrons displays the connected robot’s last protocol run on on the Protocol Upload page. If you run again, Opentrons loads this protocol and applies Labware Offset data if any exists.Clicking “Run Again” will take you directly to the Run tab. If you’d like to review the deck setup or run Labware Position Check before running the protocol, navigate to the Protocol tab.If you recalibrate your robot, it will clear the last run from the upload page. A run can have the following statuses:Not started: when this protocol was loaded on to the robot, it was closed before the user ran itCanceled: when this protocol was loaded on to the robot, it was canceled before the run completedComplete: when this protocol was loaded on to the robot, it was closed after the protocol run completed", - "rerunning_protocol_modal_header": "How Rerunning A Protocol Works", - "rerunning_protocol_modal_link": "Learn more about Labware Offset Data", - "rerunning_protocol_modal_title": "See How Rerunning a Protocol Works", "robot_name_last_run": "{{robot_name}}’s last run", "robot_type_first": "{{robotType}} protocols first", "run_again": "Run again", "run_protocol": "Run protocol", "run_timestamp_title": "Run timestamp", - "send_a_protocol_to_store": "Send a protocol from the Opentrons App to get started.", "simulation_in_progress": "Simulation in Progress", "timestamp": "+{{index}}", "too_many_pins_body": "Remove a protocol in order to add more protocols to your pinned list.", diff --git a/app/src/assets/localization/en/protocol_list.json b/app/src/assets/localization/en/protocol_list.json index d014c27abae..76c1b068d94 100644 --- a/app/src/assets/localization/en/protocol_list.json +++ b/app/src/assets/localization/en/protocol_list.json @@ -1,5 +1,4 @@ { - "a_robot_software_update_is_available": "A robot software update is required to run protocols with this version of the Opentrons App. Go to Robot", "delete_protocol_message": " and its run history will be permanently deleted.", "last_updated_at": "Updated {{date}}", "left_mount": "left mount", diff --git a/app/src/assets/localization/en/protocol_setup.json b/app/src/assets/localization/en/protocol_setup.json index 99b496a3479..3aa726d707a 100644 --- a/app/src/assets/localization/en/protocol_setup.json +++ b/app/src/assets/localization/en/protocol_setup.json @@ -121,8 +121,6 @@ "lpc_disabled_modules_not_connected": "Make sure all modules are connected before running Labware Position Check", "lpc_disabled_no_tipracks_loaded": "Labware Position Check requires that the protocol loads a tip rack", "lpc_disabled_no_tipracks_used": "Labware Position Check requires that the protocol has at least one pipette that picks up a tip", - "magnetic_module_attention_warning": "Opentrons recommends securing labware with the module’s bracket. See how to secure labware to the Magnetic Module", - "magnetic_module_extra_attention": "Opentrons recommends securing labware with the module’s bracket", "map_view": "Map View", "missing_gripper": "Missing gripper", "missing_instruments": "Missing {{count}}", @@ -130,7 +128,6 @@ "missing_pipettes": "Missing {{count}} pipette", "missing": "Missing", "modal_instructions_title": "{{moduleName}} Setup Instructions", - "modal_instructions": "For step-by-step instructions on setting up your module, consult the Quickstart Guide that came in its box. You can also click the link below or scan the QR code to visit the modules section of the Opentrons Help Center.", "module_and_deck_setup": "Modules & deck", "module_connected": "Connected", "module_disconnected": "Disconnected", @@ -238,22 +235,16 @@ "run_disabled_modules_not_connected": "Make sure all modules are connected before proceeding to run", "run_labware_position_check": "run labware position check", "run": "Run", - "secure_labware_explanation_magnetic_module": "Opentrons recommends ensuring your labware locks to the Magnetic Module by adjusting the black plate bracket on top of the module. Please note there are two sizes of plate brackets supplied with your module: standard and deep well. These brackets can be removed and swapped by unscrewing the modules thumb screw (the silver knob on the front).", - "secure_labware_explanation_thermocycler": "Opentrons recommends securing your labware to the Thermocycler module by closing its latch. Doing so ensures level and accurate plate placement for optimal results.", "secure_labware_instructions": "Secure labware instructions", "secure_labware_modal": "Securing labware to the {{name}}", "secure": "Secure", "setup_for_run": "Setup for Run", - "setup_instructions_description": "For step-by-step instructions on setting up your module, consult the Quickstart Guide that came in its box or scan the QR code to visit the modules section of the Opentrons Help Center.", "setup_instructions": "setup instructions", "setup_is_view_only": "Setup is view-only once run has started", "slot_location": "Slot {{slotName}}", "slot_number": "Slot Number", "status": "Status", "step": "STEP {{index}}", - "thermocycler_attention_warning": " Labware must be secured with the module’s latch. See how to secure labware to the Thermocycler Module Thermocycler lid must be open when robot moves to the slots it occupies. Opentrons will automatically open the lid to move to these slots during Labware Position Check.", - "thermocycler_extra_attention_gen_1": "Labware must be secured with the module’s latch. Thermocycler lid must be open when robot moves to the slots it occupies. Opentrons will automatically open the lid to move to these slots during Labware Position Check.", - "thermocycler_extra_attention_gen_2": "The lid will automatically open when moving to these slots during Labware Position Check.", "tip_length_cal_description_bullet": "Perform Tip Length Calibration for each new tip type used on a pipette.", "tip_length_cal_description": "This measures the Z distance between the bottom of the tip and the pipette’s nozzle. If you redo the tip length calibration for the tip you used to calibrate a pipette, you will also have to redo that Pipette Offset Calibration.", "tip_length_cal_title": "Tip Length Calibration", @@ -270,6 +261,5 @@ "view_setup_instructions": "View setup instructions", "volume": "Volume", "what_labware_offset_is": "A Labware Offset is a type of positional adjustment that accounts for small, real-world variances in the overall position of the labware on a robot’s deck. Labware Offset data is unique to a specific combination of labware definition, deck slot, and robot.", - "why_use_lpc": "Labware Position Check is intended to correct for minor variances. Opentrons does not recommend using Labware Position Check to compensate for large positional adjustments. Needing to set large labware offsets could indicate a problem with robot calibration.", "with_the_chosen_value": "With the chosen values, the following error occurred:" } diff --git a/app/src/assets/localization/en/robot_advanced_settings.json b/app/src/assets/localization/en/robot_advanced_settings.json deleted file mode 100644 index 8ce165ecaa0..00000000000 --- a/app/src/assets/localization/en/robot_advanced_settings.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "download_logs_button": "download", - "download_logs_description": "Access logs from this robot.", - "download_logs_label": "download logs", - "log_opt_out_explanation": "If your OT-2 is connected to the internet, Opentrons will collect logs from your robot to troubleshoot issues and identify error trends.", - "log_opt_out_heading": "Robot Logging", - "log_opt_out_instruction": "If you would like to disable log collection, please click "Opt out" below.", - "open_jupyter_description": "Open the Jupyter Notebook running on this OT-2 in your web browser. (Experimental feature! See documentation for more details.)", - "open_jupyter_label": "Jupyter Notebook", - "opt_in": "Sounds Good!", - "opt_out": "Opt Out", - "reset_button": "reset", - "reset_description": "Restore robot to factory configuration.", - "reset_label": "factory reset", - "title": "advanced settings", - "update_from_file_description": "If your app is unable to auto-download robot updates, you can download the robot update yourself and update your robot manually.", - "update_from_file_label": "Update robot software from file" -} diff --git a/app/src/assets/localization/en/robot_calibration.json b/app/src/assets/localization/en/robot_calibration.json index 9828ed706c4..1e96d8d1c24 100644 --- a/app/src/assets/localization/en/robot_calibration.json +++ b/app/src/assets/localization/en/robot_calibration.json @@ -11,13 +11,11 @@ "calibrate_z_axis_on_block": "Calibrate z-axis on block", "calibrate_z_axis_on_slot": "Calibrate z-axis in slot 5", "calibrate_z_axis_on_trash": "Calibrate z-axis on trash bin", - "calibration_block_description": "This block is a specially made tool that fits perfectly on your deck and helps with calibration.If you do not have a Calibration Block, please email support@opentrons.com so we can send you one. In your message, be sure to include your name, company or institution name, and shipping address. While you wait for the block to arrive, you can use the flat surface on the trash bin of your robot instead.", "calibration_complete": "Calibration complete", "calibration_dashboard": "Calibration Dashboard", "calibration_health_check": "Calibration Health Check", "calibration_health_check_intro_body": "Calibration Health Check diagnoses problems with Deck, Tip Length, and Pipette Offset Calibration.You will move the pipettes to various positions, which will be compared against your existing calibration data.If there is a large difference, you will be prompted to redo some or all of your calibrations.", "calibration_health_check_results": "Calibration Health Check Results", - "calibration_on_opentrons_tips_is_important": "It’s extremely important to perform this calibration using the Opentrons tips and tip racks specified above, as the robot determines accuracy based on the known measurements of these tips.", "calibration_recommended": "Calibration recommended", "calibration_status": "Calibration Status", "calibration_status_description": "For accurate and precise movement, calibrate the robot's deck, pipette offsets, and tip lengths.", @@ -84,8 +82,6 @@ "need_help": "Need help?", "no_pipette": "No pipette attached", "no_tip_length": "Calibrate your pipette to see saved tip length", - "opentrons": "opentrons", - "opentrons_tip_racks_recommended": "Opentrons tip racks are highly recommended. Accuracy cannot be guaranteed with other tip racks.", "pick_up_tip": "Pick up tip", "pipette_name_and_serial": "{{name}}, {{serial}}", "pipette_offset_calibration": "Pipette Offset Calibration", diff --git a/app/src/assets/localization/en/robot_connection.json b/app/src/assets/localization/en/robot_connection.json deleted file mode 100644 index 46d1874d51c..00000000000 --- a/app/src/assets/localization/en/robot_connection.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "connect": "connect", - "connected_description": "Your app is currently connected to your robot via {{type}} at IP address {{ip}}", - "connection_label": "this robot is currently", - "connection_status_default": "idle", - "connection_status_disconnected": "unknown - connect to view status", - "connection_status_not_connectable": "not connectable", - "connection_title": "status", - "disconnect": "disconnect", - "disconnected_description": "Your app is trying to connect to your robot via {{type}} at IP address {{ip}}", - "failed_connection_heading": "Could not connect to robot", - "health_status_not_ok": "not responding correctly to requests", - "health_status_ok": "responding to requests", - "health_status_unreachable": "unreachable", - "internet_status_full": "Internet: The robot is connected to a network and has full access to the Internet.", - "internet_status_limited": "Internet: The robot is connected to a network, but it has no access to the Internet.", - "internet_status_none": "Internet: The robot is not connected to any network.", - "internet_status_portal": "Internet: The robot is behind a captive portal and cannot reach the full Internet.", - "internet_status_unknown": "Internet: Unknown", - "internet_status": "Internet: Unknown", - "ip": "{{type}} IP: {{ip}}", - "last_resort": "If your robot remains unresponsive, please reach out to our Support team.", - "mac": "{{type}} MAC Address: {{mac}}", - "no_server_message": "This OT-2 has been seen recently, but it is currently {{status}} at IP address {{ip}}.We recommend power-cycling your robot.", - "server_message": "Your OT-2's API server is {{status}} at IP address {{ip}}.We recommend the following troubleshooting steps:
  1. Power-cycle your robot
  2. If power-cycling does not work, please update your robot's software
    (Note: your robot's update server is still responding and should accept an update.)
", - "subnet": "{{type}} Subnet Mask: {{subnet}}", - "success_banner": "{{robot}} successfully connected", - "title": "connectivity", - "unresponsive_title": "Unable to establish connection with robot", - "wired": "wired", - "wireless": "wireless" -} diff --git a/app/src/assets/localization/en/robot_info.json b/app/src/assets/localization/en/robot_info.json deleted file mode 100644 index f608623ac4c..00000000000 --- a/app/src/assets/localization/en/robot_info.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "api_version_min_max": "min: {{min}}, max: {{max}}", - "firmware_version": "firmware version", - "robot_name": "robot name", - "server_version": "server version", - "supported_api_versions": "supported protocol API versions", - "title": "information" -} diff --git a/app/src/assets/localization/en/run_details.json b/app/src/assets/localization/en/run_details.json index 90a6977806e..53fbf0956ff 100644 --- a/app/src/assets/localization/en/run_details.json +++ b/app/src/assets/localization/en/run_details.json @@ -22,7 +22,6 @@ "comment_step": "Comment", "comment": "Comment", "complete_protocol_to_download": "Complete the protocol to download the run log", - "contact_information": "Download the robot logs from the Opentrons App and send it to support@opentrons.com for assistance.", "current_step_pause_timer": "Timer", "current_step_pause": "Current Step - Paused by User", "current_step": "Current Step", @@ -101,8 +100,6 @@ "run_completed": "Run completed.", "run_cta_disabled": "Complete required steps on Protocol tab before starting the run", "run_failed_modal_body": "Error occurred when protocol was {{command}}", - "run_failed_modal_description_desktop": "Download the run log and send it to support@opentrons.com for assistance.", - "run_failed_modal_description": "Please contact support@opentrons.com with relevant information for assistance with troubleshooting.", "run_failed_modal_header": "{{errorName}}: {{errorCode}} at protocol step {{count}}", "run_failed_modal_title": "Run failed", "run_failed_splash": "Run failed", diff --git a/app/src/assets/localization/en/shared.json b/app/src/assets/localization/en/shared.json index adb939134f8..fe1a9bb21e6 100644 --- a/app/src/assets/localization/en/shared.json +++ b/app/src/assets/localization/en/shared.json @@ -11,10 +11,8 @@ "clear_data": "clear data", "close_robot_door": "Close the robot door before starting the run.", "close": "close", - "computer_in_app_is_controlling_robot": "A computer with the Opentrons App is currently controlling this robot.", "confirm_placement": "Confirm placement", "confirm_position": "Confirm position", - "confirm_terminate": "This will immediately stop the activity begun on a computer. You, or another user, may lose progress or see an error in the Opentrons App.", "confirm_values": "Confirm values", "confirm": "Confirm", "continue_activity": "Continue activity", @@ -35,7 +33,6 @@ "exit": "exit", "extension_mount": "extension mount", "flow_complete": "{{flowName}} complete!", - "general_error_message": "If you keep getting this message, try restarting your app and/or robot. If this does not resolve the issue please contact Opentrons Support.", "get_started": "Get started", "github": "GitHub", "go_back": "Go back", diff --git a/app/src/i18n.ts b/app/src/i18n.ts index 9e03af972c0..38bb6803b45 100644 --- a/app/src/i18n.ts +++ b/app/src/i18n.ts @@ -5,49 +5,43 @@ import { initReactI18next } from 'react-i18next' import { resources } from './assets/localization' import { titleCase } from '@opentrons/shared-data' -i18n.use(initReactI18next).init( - { - resources, - lng: 'en', - fallbackLng: 'en', - debug: process.env.NODE_ENV === 'development', - ns: [ - 'shared', - 'robot_advanced_settings', - 'robot_calibration', - 'robot_connection', - 'robot_controls', - 'robot_info', - 'top_navigation', - ], - defaultNS: 'shared', - interpolation: { - escapeValue: false, // not needed for react as it escapes by default - format: function (value, format, lng) { - if (format === 'upperCase') return value.toUpperCase() - if (format === 'lowerCase') return value.toLowerCase() - if (format === 'capitalize') return capitalize(value) - if (format === 'sentenceCase') return startCase(value) - if (format === 'titleCase') return titleCase(value) - return value - }, - }, - keySeparator: false, // use namespaces and context instead - saveMissing: true, - missingKeyHandler: (lng, ns, key) => { - process.env.NODE_ENV === 'test' - ? console.error(`Missing ${lng} Translation: key={${key}} ns={${ns}}`) - : console.warn(`Missing ${lng} Translation: key={${key}} ns={${ns}}`) +import type { InitOptions } from 'i18next' + +const i18nConfig: InitOptions = { + resources, + lng: 'en', + fallbackLng: 'en', + debug: process.env.NODE_ENV === 'development', + defaultNS: 'shared', + interpolation: { + escapeValue: false, // not needed for react as it escapes by default + format: function (value, format, lng) { + if (format === 'upperCase') return value.toUpperCase() + if (format === 'lowerCase') return value.toLowerCase() + if (format === 'capitalize') return capitalize(value) + if (format === 'sentenceCase') return startCase(value) + if (format === 'titleCase') return titleCase(value) + return value }, }, - err => { - if (err) { - console.error( - 'Internationalization was not initialized properly. error: ', - err - ) - } + keySeparator: false, // use namespaces and context instead + saveMissing: true, + missingKeyHandler: (lng, ns, key) => { + process.env.NODE_ENV === 'test' + ? console.error(`Missing ${lng} Translation: key={${key}} ns={${ns}}`) + : console.warn(`Missing ${lng} Translation: key={${key}} ns={${ns}}`) + }, +} + +const i18nCb = (err?: Error): void => { + if (err != null) { + console.error( + 'Internationalization was not initialized properly. error: ', + err + ) } -) +} + +void i18n.use(initReactI18next).init(i18nConfig, i18nCb) -export { i18n } +export { i18n, i18nCb, i18nConfig } diff --git a/app/src/index.tsx b/app/src/index.tsx index f6f4918d769..e37435c9aba 100644 --- a/app/src/index.tsx +++ b/app/src/index.tsx @@ -5,10 +5,8 @@ import { Provider } from 'react-redux' import { ConnectedRouter } from 'connected-react-router' -import { I18nextProvider } from 'react-i18next' import { ApiClientProvider } from '@opentrons/react-api-client' -import { i18n } from './i18n' import { createLogger } from './logger' import { uiInitialized } from './redux/shell' @@ -38,9 +36,7 @@ root.render( - - - + diff --git a/app/src/organisms/AdvancedSettings/OverridePathToPython.tsx b/app/src/organisms/AdvancedSettings/OverridePathToPython.tsx index 0ca2d39579f..57331d825bf 100644 --- a/app/src/organisms/AdvancedSettings/OverridePathToPython.tsx +++ b/app/src/organisms/AdvancedSettings/OverridePathToPython.tsx @@ -30,7 +30,7 @@ import { import type { Dispatch } from '../../redux/types' export function OverridePathToPython(): JSX.Element { - const { t } = useTranslation('app_settings') + const { t } = useTranslation(['app_settings', 'branded']) const pathToPythonInterpreter = useSelector(getPathToPythonOverride) const dispatch = useDispatch() const trackEvent = useTrackEvent() @@ -54,7 +54,7 @@ export function OverridePathToPython(): JSX.Element { {t('override_path_to_python')} - {t('opentrons_app_will_use_interpreter')} + {t('branded:opentrons_app_will_use_interpreter')} () const isLabwareOffsetCodeSnippetsOn = useSelector( getIsLabwareOffsetCodeSnippetsOn @@ -47,7 +47,7 @@ export function ShowLabwareOffsetSnippets(): JSX.Element { {t('show_labware_offset_snippets')} - {t('show_labware_offset_snippets_description')} + {t('branded:show_labware_offset_snippets_description')} () const [showUpdateModal, setShowUpdateModal] = React.useState(false) - const { t } = useTranslation('app_settings') + const { t } = useTranslation(['app_settings', 'branded']) const { makeToast } = useToaster() const { removeActiveAppUpdateToast } = useRemoveActiveAppUpdateToast() @@ -54,10 +54,14 @@ export function AlertsModal({ toastIdRef }: AlertsModalProps): JSX.Element { // Only run this hook on app startup React.useEffect(() => { if (hasJustUpdated) { - makeToast(t('opentrons_app_successfully_updated'), SUCCESS_TOAST, { - closeButton: true, - disableTimeout: true, - }) + makeToast( + t('branded:opentrons_app_successfully_updated'), + SUCCESS_TOAST, + { + closeButton: true, + disableTimeout: true, + } + ) dispatch(toggleConfigValue('update.hasJustUpdated')) } }, []) @@ -65,7 +69,7 @@ export function AlertsModal({ toastIdRef }: AlertsModalProps): JSX.Element { React.useEffect(() => { if (createAppUpdateAvailableToast) { toastIdRef.current = makeToast( - t('opentrons_app_update_available_variation'), + t('branded:opentrons_app_update_available_variation'), WARNING_TOAST, { closeButton: true, diff --git a/app/src/organisms/AppSettings/ConnectRobotSlideout.tsx b/app/src/organisms/AppSettings/ConnectRobotSlideout.tsx index eaef9184985..1935cd33d78 100644 --- a/app/src/organisms/AppSettings/ConnectRobotSlideout.tsx +++ b/app/src/organisms/AppSettings/ConnectRobotSlideout.tsx @@ -43,7 +43,7 @@ export function ConnectRobotSlideout({ const [mostRecentDiscovered, setMostRecentDiscovered] = React.useState< boolean | null >(null) - const { t } = useTranslation(['app_settings', 'shared']) + const { t } = useTranslation(['app_settings', 'shared', 'branded']) const dispatch = useDispatch() const refreshDiscovery = (): unknown => dispatch(startDiscovery()) const isScanning = useSelector(getScanning) @@ -81,7 +81,7 @@ export function ConnectRobotSlideout({ {t('ip_description_first')} - {t('ip_description_second')} + {t('branded:ip_description_second')} - {t('restore_description')} + {t('branded:restore_description')} - {t('learn_uninstalling')} + {t('branded:learn_uninstalling')} - {t('previous_releases')} + {t('branded:previous_releases')} diff --git a/app/src/organisms/CalibrateTipLength/AskForCalibrationBlockModal.tsx b/app/src/organisms/CalibrateTipLength/AskForCalibrationBlockModal.tsx index 41a21ff0cba..c767cb4ee39 100644 --- a/app/src/organisms/CalibrateTipLength/AskForCalibrationBlockModal.tsx +++ b/app/src/organisms/CalibrateTipLength/AskForCalibrationBlockModal.tsx @@ -40,7 +40,7 @@ interface Props { } export function AskForCalibrationBlockModal(props: Props): JSX.Element { - const { t } = useTranslation(['robot_calibration', 'shared']) + const { t } = useTranslation(['robot_calibration', 'shared', 'branded']) const [rememberPreference, setRememberPreference] = React.useState( true ) @@ -77,7 +77,7 @@ export function AskForCalibrationBlockModal(props: Props): JSX.Element { , supportLink: ( diff --git a/app/src/organisms/CalibrationPanels/ChooseTipRack.tsx b/app/src/organisms/CalibrationPanels/ChooseTipRack.tsx index fed5ab02911..08e0b22e51b 100644 --- a/app/src/organisms/CalibrationPanels/ChooseTipRack.tsx +++ b/app/src/organisms/CalibrationPanels/ChooseTipRack.tsx @@ -75,7 +75,7 @@ export function ChooseTipRack(props: ChooseTipRackProps): JSX.Element { robotName, defaultTipracks, } = props - const { t } = useTranslation(['robot_calibration', 'shared']) + const { t } = useTranslation(['robot_calibration', 'shared', 'branded']) const pipSerial = usePipettesQuery( {}, { @@ -143,7 +143,7 @@ export function ChooseTipRack(props: ChooseTipRackProps): JSX.Element { customTipRacks.length > 0 ? [ { - label: t('opentrons'), + label: t('branded:opentrons_tip_rack_name'), options: opentronsTipRacksOptions, }, { @@ -233,14 +233,14 @@ export function ChooseTipRack(props: ChooseTipRackProps): JSX.Element { - {t('opentrons_tip_racks_recommended')} + {t('branded:opentrons_tip_racks_recommended')} - {t('calibration_on_opentrons_tips_is_important')} + {t('branded:calibration_on_opentrons_tips_is_important')} diff --git a/app/src/organisms/ChooseRobotSlideout/AvailableRobotOption.tsx b/app/src/organisms/ChooseRobotSlideout/AvailableRobotOption.tsx index c65e69ce163..148b9e30e35 100644 --- a/app/src/organisms/ChooseRobotSlideout/AvailableRobotOption.tsx +++ b/app/src/organisms/ChooseRobotSlideout/AvailableRobotOption.tsx @@ -53,7 +53,7 @@ export function AvailableRobotOption( registerRobotBusyStatus, } = props const { ip, local, name: robotName } = robot ?? {} - const { t } = useTranslation('protocol_list') + const { t } = useTranslation(['protocol_list', 'branded']) const dispatch = useDispatch() const robotModel = useSelector((state: State) => getRobotModelByName(state, robotName) @@ -160,7 +160,7 @@ export function AvailableRobotOption( > , }} diff --git a/app/src/organisms/ConfigurePipette/ConfigFormResetButton.tsx b/app/src/organisms/ConfigurePipette/ConfigFormResetButton.tsx index d97524f1e59..32ac241955d 100644 --- a/app/src/organisms/ConfigurePipette/ConfigFormResetButton.tsx +++ b/app/src/organisms/ConfigurePipette/ConfigFormResetButton.tsx @@ -17,13 +17,13 @@ export interface ButtonProps { export function ConfigFormResetButton(props: ButtonProps): JSX.Element { const { onClick, disabled } = props - const { t } = useTranslation(['shared', 'device_details']) + const { t } = useTranslation(['shared', 'branded']) return ( - {t('deck_fixture_setup_modal_bottom_description')} + {t('branded:deck_fixture_setup_modal_bottom_description')} diff --git a/app/src/organisms/Devices/ConnectionTroubleshootingModal.tsx b/app/src/organisms/Devices/ConnectionTroubleshootingModal.tsx index 560eedb235b..03cbde6898a 100644 --- a/app/src/organisms/Devices/ConnectionTroubleshootingModal.tsx +++ b/app/src/organisms/Devices/ConnectionTroubleshootingModal.tsx @@ -48,7 +48,7 @@ export function ConnectionTroubleshootingModal(props: Props): JSX.Element { steps={[t('restart_the_robot'), t('restart_the_app')]} /> - {t('contact_support_for_connection_help', { + {t('branded:contact_support_for_connection_help', { support_email: SUPPORT_EMAIL, })} diff --git a/app/src/organisms/Devices/ProtocolRun/RunFailedModal.tsx b/app/src/organisms/Devices/ProtocolRun/RunFailedModal.tsx index dbaeff488b8..e03287f5959 100644 --- a/app/src/organisms/Devices/ProtocolRun/RunFailedModal.tsx +++ b/app/src/organisms/Devices/ProtocolRun/RunFailedModal.tsx @@ -51,7 +51,7 @@ export function RunFailedModal({ setShowRunFailedModal, highestPriorityError, }: RunFailedModalProps): JSX.Element | null { - const { i18n, t } = useTranslation(['run_details', 'shared']) + const { i18n, t } = useTranslation(['run_details', 'shared', 'branded']) const modalProps: LegacyModalProps = { type: 'error', title: t('run_failed_modal_title'), @@ -89,7 +89,7 @@ export function RunFailedModal({ - {t('run_failed_modal_description_desktop')} + {t('branded:run_failed_modal_description_desktop')} { - const { t } = useTranslation(['protocol_setup', 'shared']) + const { t } = useTranslation(['protocol_setup', 'shared', 'branded']) const moduleName = getModuleName(props.type) return createPortal( - {t(`secure_labware_explanation_${snakeCase(moduleName)}`)} + {t(`branded:secure_labware_explanation_${snakeCase(moduleName)}`)} { - const { t } = useTranslation(['protocol_setup', 'shared']) + const { t } = useTranslation(['protocol_setup', 'shared', 'branded']) return createPortal( { /> - {t('why_use_lpc')} + {t('branded:why_use_lpc')} - {t('connection_lost_description')} + {t('branded:connection_lost_description')} { @@ -65,7 +65,7 @@ export function RobotServerVersion({ {isFlex ? ( - {t('robot_server_version_ot3_description')} + {t('branded:robot_server_version_ot3_description')} ) : null} diff --git a/app/src/organisms/Devices/RobotSettings/AdvancedTab/SoftwareUpdateModal.tsx b/app/src/organisms/Devices/RobotSettings/AdvancedTab/SoftwareUpdateModal.tsx deleted file mode 100644 index 9884676e224..00000000000 --- a/app/src/organisms/Devices/RobotSettings/AdvancedTab/SoftwareUpdateModal.tsx +++ /dev/null @@ -1,121 +0,0 @@ -import * as React from 'react' -import { useTranslation } from 'react-i18next' -import { useSelector } from 'react-redux' -import { - DIRECTION_COLUMN, - Flex, - JUSTIFY_FLEX_END, - PrimaryButton, - SecondaryButton, - SPACING, - StyledText, - TYPOGRAPHY, -} from '@opentrons/components' -import { getShellUpdateState } from '../../../../redux/shell' -import { useCurrentRunId } from '../../../../organisms/ProtocolUpload/hooks' -// import { ReleaseNotes } from '../../../../molecules/ReleaseNotes' - -import { ExternalLink } from '../../../../atoms/Link/ExternalLink' -import { Banner } from '../../../../atoms/Banner' -import { LegacyModal } from '../../../../molecules/LegacyModal' -import { CONNECTABLE, REACHABLE } from '../../../../redux/discovery' -import { Divider } from '../../../../atoms/structure' -import { useRobot } from '../../hooks' -import { handleUpdateBuildroot } from '../UpdateBuildroot' - -const TECHNICAL_CHANGE_LOG_URL = - 'https://github.com/Opentrons/opentrons/blob/edge/CHANGELOG.md' -const ISSUE_TRACKER_URL = - 'https://github.com/Opentrons/opentrons/issues?q=is%3Aopen+is%3Aissue+label%3Abug' -const RELEASE_NOTES_URL = 'https://github.com/Opentrons/opentrons/releases' - -interface SoftwareUpdateModalProps { - robotName: string - closeModal: () => void -} - -export function SoftwareUpdateModal({ - robotName, - closeModal, -}: SoftwareUpdateModalProps): JSX.Element | null { - const { t } = useTranslation('device_settings') - - const currentRunId = useCurrentRunId() - // ToDo: Add release notes for the new design - const updateState = useSelector(getShellUpdateState) - // const { downloaded, downloading, error, info: updateInfo } = updateState - const { info: updateInfo } = updateState - const version = updateInfo?.version ?? '' - // const releaseNotes = updateInfo?.releaseNotes - const [showUpdateModal, setShowUpdateModal] = React.useState(false) - const robot = useRobot(robotName) - - if (robot?.status !== CONNECTABLE && robot?.status !== REACHABLE) return null - - return !showUpdateModal ? ( - - {t('requires_restarting_the_robot')} - - {/* ToDo: align with new design */} - - {t('app_change_in', { version })} - - - {'None in the Opentrons (Here will be change logs)'} - - - {t('new_features')} - - - {'None in the Opentrons (Here will be features info)'} - - - {t('bug_fixes')} - - - {'None in the Opentrons (Here will be fixes info)'} - - - - {t('view_opentrons_technical_change_log')} - - - {t('view_opentrons_issue_tracker')} - - - {t('view_opentrons_release_notes')} - - - - {t('remind_me_later')} - - { - setShowUpdateModal(true) - handleUpdateBuildroot(robot) - }} - disabled={currentRunId != null} - > - {t('update_robot_now')} - - - - - ) : null -} diff --git a/app/src/organisms/Devices/RobotSettings/AdvancedTab/UpdateRobotSoftware.tsx b/app/src/organisms/Devices/RobotSettings/AdvancedTab/UpdateRobotSoftware.tsx index a8febac7092..bf7a27e389b 100644 --- a/app/src/organisms/Devices/RobotSettings/AdvancedTab/UpdateRobotSoftware.tsx +++ b/app/src/organisms/Devices/RobotSettings/AdvancedTab/UpdateRobotSoftware.tsx @@ -40,7 +40,7 @@ export function UpdateRobotSoftware({ onUpdateStart, isRobotBusy, }: UpdateRobotSoftwareProps): JSX.Element { - const { t } = useTranslation('device_settings') + const { t } = useTranslation(['device_settings', 'branded']) const { updateFromFileDisabledReason } = useSelector((state: State) => { return getRobotUpdateDisplayInfo(state, robotName) }) @@ -77,10 +77,10 @@ export function UpdateRobotSoftware({ {t('update_robot_software')} - {t('update_robot_software_description')} + {t('branded:update_robot_software_description')} - {t('update_robot_software_link')} + {t('branded:update_robot_software_link')} () const value = settings?.value ? settings.value : false const id = settings?.id ? settings.id : 'disableFastProtocolUpload' @@ -54,7 +54,7 @@ export function UseOlderProtocol({ {t('use_older_protocol_analysis_method')} - {t('use_older_protocol_analysis_method_description')} + {t('branded:use_older_protocol_analysis_method_description')} { - const actual = await importOriginal() - return { - ...actual, - getShellUpdateState: vi.fn(), - } -}) -vi.mock('../../../hooks') -vi.mock('../../../../../redux/discovery/selectors') - -const mockClose = vi.fn() - -const render = () => { - return renderWithProviders( - - - , - { i18nInstance: i18n } - ) -} - -describe('RobotSettings SoftwareUpdateModal', () => { - beforeEach(() => { - vi.mocked(useRobot).mockReturnValue(mockReachableRobot) - vi.mocked(getShellUpdateState).mockReturnValue({ - downloaded: true, - info: { - version: '1.2.3', - releaseNotes: 'this is a release', - }, - } as ShellUpdateState) - }) - - it('should render title ,description and button', () => { - render() - screen.getByText('Robot Update Available') - screen.getByText( - 'Updating the robot’s software requires restarting the robot' - ) - screen.getByText('App Changes in 1.2.3') - screen.getByText('New Features') - screen.getByText('Bug Fixes') - screen.getByText('View Opentrons technical change log') - screen.getByText('View Opentrons issue tracker') - screen.getByText('View full Opentrons release notes') - screen.getByRole('button', { name: 'Remind me later' }) - screen.getByRole('button', { name: 'Update robot now' }) - }) - - it('should have correct href', () => { - render() - const changeLogUrl = - 'https://github.com/Opentrons/opentrons/blob/edge/CHANGELOG.md' - const issueTrackerUrl = - 'https://github.com/Opentrons/opentrons/issues?q=is%3Aopen+is%3Aissue+label%3Abug' - const releaseNotesUrl = 'https://github.com/Opentrons/opentrons/releases' - - const linkForChangeLog = screen.getByRole('link', { - name: 'View Opentrons technical change log', - }) - expect(linkForChangeLog).toHaveAttribute('href', changeLogUrl) - - const linkForIssueTracker = screen.getByRole('link', { - name: 'View Opentrons issue tracker', - }) - expect(linkForIssueTracker.closest('a')).toHaveAttribute( - 'href', - issueTrackerUrl - ) - - const linkForReleaseNotes = screen.getByRole('link', { - name: 'View full Opentrons release notes', - }) - expect(linkForReleaseNotes.closest('a')).toHaveAttribute( - 'href', - releaseNotesUrl - ) - }) -}) diff --git a/app/src/organisms/Devices/RobotSettings/AdvancedTab/index.ts b/app/src/organisms/Devices/RobotSettings/AdvancedTab/index.ts index 1c5cb506bc7..86e45ab1f73 100644 --- a/app/src/organisms/Devices/RobotSettings/AdvancedTab/index.ts +++ b/app/src/organisms/Devices/RobotSettings/AdvancedTab/index.ts @@ -7,7 +7,6 @@ export * from './OpenJupyterControl' export * from './RobotInformation' export * from './RobotServerVersion' export * from './ShortTrashBin' -export * from './SoftwareUpdateModal' export * from './Troubleshooting' export * from './UpdateRobotSoftware' export * from './UsageSettings' diff --git a/app/src/organisms/Devices/RobotSettings/ConnectNetwork/DisconnectModal.tsx b/app/src/organisms/Devices/RobotSettings/ConnectNetwork/DisconnectModal.tsx index 660e04a1519..b489af43d1f 100644 --- a/app/src/organisms/Devices/RobotSettings/ConnectNetwork/DisconnectModal.tsx +++ b/app/src/organisms/Devices/RobotSettings/ConnectNetwork/DisconnectModal.tsx @@ -47,7 +47,7 @@ export const DisconnectModal = ({ onCancel, robotName, }: DisconnectModalProps): JSX.Element => { - const { t } = useTranslation(['device_settings', 'shared']) + const { t } = useTranslation(['device_settings', 'shared', 'branded']) const wifiList = useWifiList(robotName) const { wifi } = useSelector((state: State) => @@ -144,7 +144,7 @@ export const DisconnectModal = ({ {isError ? ( - {t('shared:general_error_message')} + {t('branded:general_error_message')} ) : null} diff --git a/app/src/organisms/Devices/RobotSettings/RobotSettingsPrivacy.tsx b/app/src/organisms/Devices/RobotSettings/RobotSettingsPrivacy.tsx index 267171774d9..9a0f0164fc5 100644 --- a/app/src/organisms/Devices/RobotSettings/RobotSettingsPrivacy.tsx +++ b/app/src/organisms/Devices/RobotSettings/RobotSettingsPrivacy.tsx @@ -25,8 +25,8 @@ const INFO_BY_SETTING_ID: { } } = { disableLogAggregation: { - titleKey: 'share_logs_with_opentrons', - descriptionKey: 'share_logs_with_opentrons_description', + titleKey: 'branded:share_logs_with_opentrons', + descriptionKey: 'branded:share_logs_with_opentrons_description', invert: true, }, } @@ -34,7 +34,7 @@ const INFO_BY_SETTING_ID: { export function RobotSettingsPrivacy({ robotName, }: RobotSettingsPrivacyProps): JSX.Element { - const { t } = useTranslation('device_settings') + const { t } = useTranslation(['device_settings', 'branded']) const settings = useSelector((state: State) => getRobotSettings(state, robotName) ) diff --git a/app/src/organisms/Devices/RobotSettings/UpdateBuildroot/UpdateRobotModal.tsx b/app/src/organisms/Devices/RobotSettings/UpdateBuildroot/UpdateRobotModal.tsx index f02ad6ae3ce..4a1ffaec5ea 100644 --- a/app/src/organisms/Devices/RobotSettings/UpdateBuildroot/UpdateRobotModal.tsx +++ b/app/src/organisms/Devices/RobotSettings/UpdateBuildroot/UpdateRobotModal.tsx @@ -155,7 +155,7 @@ export function UpdateRobotModal({ > - {t('update_requires_restarting')} + {t('update_requires_restarting_robot')} diff --git a/app/src/organisms/EmergencyStop/EstopPressedModal.tsx b/app/src/organisms/EmergencyStop/EstopPressedModal.tsx index cb32ae550b9..3cd06ff2fd8 100644 --- a/app/src/organisms/EmergencyStop/EstopPressedModal.tsx +++ b/app/src/organisms/EmergencyStop/EstopPressedModal.tsx @@ -73,7 +73,7 @@ function TouchscreenModal({ isEngaged, closeModal, }: EstopPressedModalProps): JSX.Element { - const { t } = useTranslation('device_settings') + const { t } = useTranslation(['device_settings', 'branded']) const [isResuming, setIsResuming] = React.useState(false) const { acknowledgeEstopDisengage } = useAcknowledgeEstopDisengageMutation() const modalHeader: ModalHeaderBaseProps = { @@ -94,7 +94,7 @@ function TouchscreenModal({ - {t('estop_pressed_description')} + {t('branded:estop_pressed_description')} - {t('estop_pressed_description')} + {t('branded:estop_pressed_description')} - {t('download_logs')} + {t('branded:firmware_update_download_logs')} { const { serialNumber, firmwareVersion, isExpanded, onCloseClick } = props - const { i18n, t } = useTranslation(['device_details', 'shared']) + const { i18n, t } = useTranslation(['device_details', 'shared', 'branded']) return ( { if (createdMaintenanceRunId == null) { createMaintenanceRun({}) @@ -108,7 +108,7 @@ export const BeforeBeginning = ( displayName: t('hex_screwdriver'), subtitle: t('provided_with_robot_use_right_size'), }, - [GRIPPER_LOADNAME]: { displayName: t('gripper') }, + [GRIPPER_LOADNAME]: { displayName: t('branded:gripper') }, } const { bodyI18nKey, equipmentLoadNames } = INFO_BY_FLOW_TYPE[flowType] diff --git a/app/src/organisms/GripperWizardFlows/MountGripper.tsx b/app/src/organisms/GripperWizardFlows/MountGripper.tsx index 7e1636f6d05..a7049cf447d 100644 --- a/app/src/organisms/GripperWizardFlows/MountGripper.tsx +++ b/app/src/organisms/GripperWizardFlows/MountGripper.tsx @@ -58,7 +58,7 @@ export const MountGripper = ( props: GripperWizardStepProps ): JSX.Element | null => { const { proceed, isRobotMoving } = props - const { t } = useTranslation(['gripper_wizard_flows', 'shared']) + const { t } = useTranslation(['gripper_wizard_flows', 'shared', 'branded']) const isOnDevice = useSelector(getIsOnDevice) const [showUnableToDetect, setShowUnableToDetect] = React.useState(false) const [isPending, setIsPending] = React.useState(false) @@ -119,7 +119,7 @@ export const MountGripper = ( ) : ( { const { proceed, successfulAction, isRobotMoving } = props - const { t, i18n } = useTranslation(['gripper_wizard_flows', 'shared']) + const { t, i18n } = useTranslation([ + 'gripper_wizard_flows', + 'shared', + 'branded', + ]) const isOnDevice = useSelector(getIsOnDevice) const infoByAction: { @@ -46,11 +50,11 @@ export const Success = ( } } = { [SUCCESSFULLY_ATTACHED_AND_CALIBRATED]: { - header: t('gripper_successfully_attached_and_calibrated'), + header: t('branded:gripper_successfully_attached_and_calibrated'), buttonText: i18n.format(t('shared:exit'), 'capitalize'), }, [SUCCESSFULLY_CALIBRATED]: { - header: t('gripper_successfully_calibrated'), + header: t('branded:gripper_successfully_calibrated'), buttonText: i18n.format(t('shared:exit'), 'capitalize'), }, [SUCCESSFULLY_ATTACHED]: { @@ -58,7 +62,7 @@ export const Success = ( buttonText: t('calibrate_gripper'), }, [SUCCESSFULLY_DETACHED]: { - header: t('gripper_successfully_detached'), + header: t('branded:gripper_successfully_detached'), buttonText: i18n.format(t('shared:exit'), 'capitalize'), }, } diff --git a/app/src/organisms/GripperWizardFlows/UnmountGripper.tsx b/app/src/organisms/GripperWizardFlows/UnmountGripper.tsx index c8e25bc0228..f0b2467e95d 100644 --- a/app/src/organisms/GripperWizardFlows/UnmountGripper.tsx +++ b/app/src/organisms/GripperWizardFlows/UnmountGripper.tsx @@ -51,7 +51,7 @@ export const UnmountGripper = ( props: GripperWizardStepProps ): JSX.Element | null => { const { proceed, isRobotMoving, goBack, chainRunCommands } = props - const { t } = useTranslation(['gripper_wizard_flows', 'shared']) + const { t } = useTranslation(['gripper_wizard_flows', 'shared', 'branded']) const isOnDevice = useSelector(getIsOnDevice) const [isPending, setIsPending] = React.useState(false) const { data: instrumentsQueryData, refetch } = useInstrumentsQuery({ @@ -100,7 +100,7 @@ export const UnmountGripper = ( return showGripperStillDetected ? ( ) : ( - {t('opentrons_def')} + {t('branded:opentrons_def')} )} diff --git a/app/src/organisms/LabwareDetails/index.tsx b/app/src/organisms/LabwareDetails/index.tsx index 4f0cc83b3a4..7787e13f57f 100644 --- a/app/src/organisms/LabwareDetails/index.tsx +++ b/app/src/organisms/LabwareDetails/index.tsx @@ -65,7 +65,7 @@ export interface LabwareDetailsProps { } export function LabwareDetails(props: LabwareDetailsProps): JSX.Element { - const { t } = useTranslation('labware_landing') + const { t } = useTranslation(['labware_landing', 'branded']) const { definition, modified, filename } = props.labware const { metadata, parameters, brand, wells, ordering } = definition const apiName = definition.parameters.loadName @@ -129,7 +129,7 @@ export function LabwareDetails(props: LabwareDetailsProps): JSX.Element { id="LabwareDetails_opentronsDef" marginLeft={SPACING.spacing4} > - {t('opentrons_def')} + {t('branded:opentrons_def')} )} diff --git a/app/src/organisms/ModuleCard/ErrorInfo.tsx b/app/src/organisms/ModuleCard/ErrorInfo.tsx index 75158e7010f..d8bb5e28b6e 100644 --- a/app/src/organisms/ModuleCard/ErrorInfo.tsx +++ b/app/src/organisms/ModuleCard/ErrorInfo.tsx @@ -29,7 +29,7 @@ interface ErrorInfoProps { } export function ErrorInfo(props: ErrorInfoProps): JSX.Element | null { const { attachedModule } = props - const { t } = useTranslation(['device_details', 'shared']) + const { t } = useTranslation(['device_details', 'shared', 'branded']) const [showErrorDetails, setShowErrorDetails] = React.useState(false) let isError: boolean = false @@ -92,7 +92,7 @@ export function ErrorInfo(props: ErrorInfoProps): JSX.Element | null { {errorDetails} ) : null} - {t('module_error_contact_support')} + {t('branded:module_error_contact_support')} diff --git a/app/src/organisms/ModuleCard/ModuleSetupModal.tsx b/app/src/organisms/ModuleCard/ModuleSetupModal.tsx index 8af56a5bcf4..21e3adb598a 100644 --- a/app/src/organisms/ModuleCard/ModuleSetupModal.tsx +++ b/app/src/organisms/ModuleCard/ModuleSetupModal.tsx @@ -26,7 +26,7 @@ interface ModuleSetupModalProps { export const ModuleSetupModal = (props: ModuleSetupModalProps): JSX.Element => { const { moduleDisplayName } = props - const { t, i18n } = useTranslation(['protocol_setup', 'shared']) + const { t, i18n } = useTranslation(['protocol_setup', 'shared', 'branded']) return createPortal( { width="50%" > - {t('modal_instructions')} + {t('branded:modal_instructions')} }} /> diff --git a/app/src/organisms/ModuleWizardFlows/index.tsx b/app/src/organisms/ModuleWizardFlows/index.tsx index 39c235bd782..be36d681950 100644 --- a/app/src/organisms/ModuleWizardFlows/index.tsx +++ b/app/src/organisms/ModuleWizardFlows/index.tsx @@ -276,7 +276,7 @@ export const ModuleWizardFlows = ( ) : ( , diff --git a/app/src/organisms/NetworkSettings/AlternativeSecurityTypeModal.tsx b/app/src/organisms/NetworkSettings/AlternativeSecurityTypeModal.tsx index b0e365d08fc..375476f2a2e 100644 --- a/app/src/organisms/NetworkSettings/AlternativeSecurityTypeModal.tsx +++ b/app/src/organisms/NetworkSettings/AlternativeSecurityTypeModal.tsx @@ -26,7 +26,7 @@ interface AlternativeSecurityTypeModalProps { export function AlternativeSecurityTypeModal({ setShowAlternativeSecurityTypeModal, }: AlternativeSecurityTypeModalProps): JSX.Element { - const { t } = useTranslation('device_settings') + const { t } = useTranslation(['device_settings', 'branded']) const history = useHistory() const modalHeader: ModalHeaderBaseProps = { title: t('alternative_security_types'), @@ -58,7 +58,7 @@ export function AlternativeSecurityTypeModal({ fontWeight={TYPOGRAPHY.fontWeightRegular} color={COLORS.grey60} > - {t('alternative_security_types_description')} + {t('branded:alternative_security_types_description')} - {t('contact_information')} + {t('branded:contact_information')} { - const { t, i18n } = useTranslation(['pipette_wizard_flows', 'shared']) + const { t, i18n } = useTranslation([ + 'pipette_wizard_flows', + 'shared', + 'branded', + ]) const { isOnDevice, handleOnClick, setShowUnableToDetect } = props const [numberOfTryAgains, setNumberOfTryAgains] = React.useState(0) return ( 2 ? t('something_seems_wrong') : undefined} + subHeader={ + numberOfTryAgains > 2 ? t('branded:something_seems_wrong') : undefined + } iconColor={COLORS.red50} isSuccess={false} > diff --git a/app/src/organisms/PipetteWizardFlows/Results.tsx b/app/src/organisms/PipetteWizardFlows/Results.tsx index 04549e686df..fda57800151 100644 --- a/app/src/organisms/PipetteWizardFlows/Results.tsx +++ b/app/src/organisms/PipetteWizardFlows/Results.tsx @@ -60,7 +60,11 @@ export const Results = (props: ResultsProps): JSX.Element => { setShowErrorMessage, nextMount, } = props - const { t, i18n } = useTranslation(['pipette_wizard_flows', 'shared']) + const { t, i18n } = useTranslation([ + 'pipette_wizard_flows', + 'shared', + 'branded', + ]) const pipetteName = attachedPipettes[mount] != null ? attachedPipettes[mount]?.displayName : '' @@ -263,7 +267,8 @@ export const Results = (props: ResultsProps): JSX.Element => { } } ` - subHeader = numberOfTryAgains > 2 ? t('something_seems_wrong') : undefined + subHeader = + numberOfTryAgains > 2 ? t('branded:something_seems_wrong') : undefined button = ( <> {isOnDevice ? ( diff --git a/app/src/organisms/ProtocolSetupModulesAndDeck/SetupInstructionsModal.tsx b/app/src/organisms/ProtocolSetupModulesAndDeck/SetupInstructionsModal.tsx index 7fbbf4f048e..c7acb6f2a42 100644 --- a/app/src/organisms/ProtocolSetupModulesAndDeck/SetupInstructionsModal.tsx +++ b/app/src/organisms/ProtocolSetupModulesAndDeck/SetupInstructionsModal.tsx @@ -26,7 +26,7 @@ interface SetupInstructionsModalProps { export function SetupInstructionsModal({ setShowSetupInstructionsModal, }: SetupInstructionsModalProps): JSX.Element { - const { i18n, t } = useTranslation('protocol_setup') + const { i18n, t } = useTranslation(['protocol_setup', 'branded']) const modalHeader: ModalHeaderBaseProps = { title: i18n.format(t('setup_instructions'), 'capitalize'), iconName: 'information', @@ -45,7 +45,9 @@ export function SetupInstructionsModal({ gridGap={SPACING.spacing40} > - {t('setup_instructions_description')} + + {t('branded:setup_instructions_description')} + () const allRobotSettings = useSelector((state: State) => @@ -62,7 +62,7 @@ export function Privacy({ lineHeight={TYPOGRAPHY.lineHeight36} fontWeight={TYPOGRAPHY.fontWeightRegular} > - {t('opentrons_cares_about_privacy')} + {t('branded:opentrons_cares_about_privacy')} } onClick={() => dispatch(toggleAnalyticsOptedIn())} diff --git a/app/src/organisms/RobotSettingsDashboard/RobotSystemVersionModal.tsx b/app/src/organisms/RobotSettingsDashboard/RobotSystemVersionModal.tsx index e1fffe74e30..8e2a8675f18 100644 --- a/app/src/organisms/RobotSettingsDashboard/RobotSystemVersionModal.tsx +++ b/app/src/organisms/RobotSettingsDashboard/RobotSystemVersionModal.tsx @@ -51,7 +51,7 @@ export function RobotSystemVersionModal({ > diff --git a/app/src/organisms/TakeoverModal/TakeoverModal.tsx b/app/src/organisms/TakeoverModal/TakeoverModal.tsx index 3dab071bdec..c87f33fc150 100644 --- a/app/src/organisms/TakeoverModal/TakeoverModal.tsx +++ b/app/src/organisms/TakeoverModal/TakeoverModal.tsx @@ -32,7 +32,7 @@ export function TakeoverModal(props: TakeoverModalProps): JSX.Element { confirmTerminate, terminateInProgress, } = props - const { i18n, t } = useTranslation('shared') + const { i18n, t } = useTranslation(['shared', 'branded']) const terminateHeader: ModalHeaderBaseProps = { title: t('terminate') + '?', @@ -46,7 +46,7 @@ export function TakeoverModal(props: TakeoverModalProps): JSX.Element { - {t('confirm_terminate')} + {t('branded:confirm_terminate')} - {t('computer_in_app_is_controlling_robot')} + {t('branded:computer_in_app_is_controlling_robot')} ) : null} {(downloading || downloaded) && error == null ? ( - + closeModal(true)} closeOnOutsideClick={true} footer={appUpdateFooter} @@ -191,7 +194,7 @@ export function UpdateAppModal(props: UpdateAppModalProps): JSX.Element { > - {t('update_requires_restarting')} + {t('branded:update_requires_restarting_app')} diff --git a/app/src/organisms/UpdateRobotBanner/index.tsx b/app/src/organisms/UpdateRobotBanner/index.tsx index ced443a2018..86e2201bf84 100644 --- a/app/src/organisms/UpdateRobotBanner/index.tsx +++ b/app/src/organisms/UpdateRobotBanner/index.tsx @@ -25,7 +25,7 @@ export function UpdateRobotBanner( props: UpdateRobotBannerProps ): JSX.Element | null { const { robot, ...styleProps } = props - const { t } = useTranslation('device_settings') + const { t } = useTranslation(['device_settings', 'branded']) const { autoUpdateAction } = useSelector((state: State) => { return getRobotUpdateDisplayInfo(state, robot?.name) @@ -40,7 +40,7 @@ export function UpdateRobotBanner( > - {t('robot_software_update_required')} + {t('branded:robot_software_update_required')} handleUpdateBuildroot(robot)} diff --git a/app/src/pages/AppSettings/GeneralSettings.tsx b/app/src/pages/AppSettings/GeneralSettings.tsx index 99bdf464d04..553f0e56356 100644 --- a/app/src/pages/AppSettings/GeneralSettings.tsx +++ b/app/src/pages/AppSettings/GeneralSettings.tsx @@ -54,7 +54,7 @@ const GITHUB_LINK = const ENABLE_APP_UPDATE_NOTIFICATIONS = 'Enable app update notifications' export function GeneralSettings(): JSX.Element { - const { t } = useTranslation(['app_settings', 'shared']) + const { t } = useTranslation(['app_settings', 'shared', 'branded']) const dispatch = useDispatch() const trackEvent = useTrackEvent() const [ @@ -113,7 +113,7 @@ export function GeneralSettings(): JSX.Element { type="warning" onCloseClick={() => setShowUpdateBanner(false)} > - {t('opentrons_app_update_available_variation')} + {t('branded:opentrons_app_update_available_variation')} - {t('versions_sync')} + {t('branded:versions_sync')} @@ -218,7 +218,7 @@ export function GeneralSettings(): JSX.Element { alignItems={ALIGN_CENTER} justifyContent={JUSTIFY_SPACE_BETWEEN} > - {t('receive_alert')} + {t('branded:receive_alert')} () const analyticsOptedIn = useSelector((s: State) => getAnalyticsOptedIn(s)) diff --git a/app/src/pages/ConnectViaUSB/index.tsx b/app/src/pages/ConnectViaUSB/index.tsx index 961da9b6092..72130c5444c 100644 --- a/app/src/pages/ConnectViaUSB/index.tsx +++ b/app/src/pages/ConnectViaUSB/index.tsx @@ -22,7 +22,7 @@ import { StepMeter } from '../../atoms/StepMeter' import { MediumButton } from '../../atoms/buttons' export function ConnectViaUSB(): JSX.Element { - const { i18n, t } = useTranslation(['device_settings', 'shared']) + const { i18n, t } = useTranslation(['device_settings', 'shared', 'branded']) const history = useHistory() // TODO(bh, 2023-5-31): active connections from /system/connected isn't exactly the right way to monitor for a usb connection - // the system-server tracks active connections by authorization token, which is valid for 2 hours @@ -92,7 +92,7 @@ export function ConnectViaUSB(): JSX.Element { color={COLORS.grey60} textAlign={TYPOGRAPHY.textAlignCenter} > - {t('find_your_robot')} + {t('branded:find_your_robot')} @@ -134,7 +134,7 @@ export function ConnectViaUSB(): JSX.Element { {t('connect_via_usb_description_2')} - {t('connect_via_usb_description_3')} + {t('branded:connect_via_usb_description_3')} diff --git a/app/src/pages/Labware/hooks.tsx b/app/src/pages/Labware/hooks.tsx index caf37544be5..b1453738652 100644 --- a/app/src/pages/Labware/hooks.tsx +++ b/app/src/pages/Labware/hooks.tsx @@ -69,7 +69,7 @@ export function useLabwareFailure(): { labwareFailureMessage: string | null clearLabwareFailure: () => unknown } { - const { t } = useTranslation('labware_landing') + const { t } = useTranslation(['labware_landing', 'branded']) const dispatch = useDispatch() const labwareFailure = useSelector(getAddLabwareFailure) @@ -82,7 +82,7 @@ export function useLabwareFailure(): { } else if (failedFile?.type === 'DUPLICATE_LABWARE_FILE') { errorMessage = t('duplicate_labware_def') } else if (failedFile?.type === 'OPENTRONS_LABWARE_FILE') { - errorMessage = t('opentrons_labware_def') + errorMessage = t('branded:opentrons_labware_def') } labwareFailureMessage = failedFile != null diff --git a/app/src/pages/NetworkSetupMenu/index.tsx b/app/src/pages/NetworkSetupMenu/index.tsx index 7250eaa3dda..11909bdb77f 100644 --- a/app/src/pages/NetworkSetupMenu/index.tsx +++ b/app/src/pages/NetworkSetupMenu/index.tsx @@ -34,13 +34,13 @@ const NetworkSetupOptions = [ { title: 'usb', iconName: 'usb' as IconName, - description: 'connection_description_usb', + description: 'branded:connection_description_usb', destinationPath: '/network-setup/usb', }, ] export function NetworkSetupMenu(): JSX.Element { - const { t } = useTranslation('device_settings') + const { t } = useTranslation(['device_settings', 'branded']) return ( <> @@ -73,7 +73,7 @@ export function NetworkSetupMenu(): JSX.Element { color={COLORS.grey60} textAlign={TYPOGRAPHY.textAlignCenter} > - {t('network_setup_menu_description')} + {t('branded:network_setup_menu_description')} - {t('send_a_protocol_to_store')} + {t('branded:send_a_protocol_to_store')} ) diff --git a/app/src/pages/ProtocolDashboard/ProtocolCard.tsx b/app/src/pages/ProtocolDashboard/ProtocolCard.tsx index 1ed35b8632f..305ca99c7bc 100644 --- a/app/src/pages/ProtocolDashboard/ProtocolCard.tsx +++ b/app/src/pages/ProtocolDashboard/ProtocolCard.tsx @@ -60,7 +60,7 @@ export function ProtocolCard(props: { showFailedAnalysisModal, setShowFailedAnalysisModal, ] = React.useState(false) - const { t, i18n } = useTranslation('protocol_info') + const { t, i18n } = useTranslation(['protocol_info', 'branded']) const protocolName = protocol.metadata.protocolName ?? protocol.files[0].name const longpress = useLongPress() const queryClient = useQueryClient() @@ -264,7 +264,9 @@ export function ProtocolCard(props: { }} /> - {t('delete_protocol_from_app')} + + {t('branded:delete_protocol_from_app')} + () const localRobot = useSelector(getLocalRobot) @@ -57,7 +57,7 @@ export function AnalyticsOptInModal({ } return ( - + () const localRobot = useSelector(getLocalRobot) const robotName = localRobot?.name != null ? localRobot.name : 'no name' @@ -144,7 +148,7 @@ export function RobotSettingsList(props: RobotSettingsListProps): JSX.Element { setCurrentOption('Privacy')} iconName="privacy" /> diff --git a/app/src/pages/Welcome/index.tsx b/app/src/pages/Welcome/index.tsx index 47bb9cbcb50..f5c1ac686bd 100644 --- a/app/src/pages/Welcome/index.tsx +++ b/app/src/pages/Welcome/index.tsx @@ -17,7 +17,7 @@ import screenImage from '../../assets/images/on-device-display/welcome_backgroun const IMAGE_ALT = 'Welcome screen background image' export function Welcome(): JSX.Element { - const { t } = useTranslation(['device_settings', 'shared']) + const { t } = useTranslation(['device_settings', 'shared', 'branded']) const history = useHistory() return ( @@ -30,7 +30,7 @@ export function Welcome(): JSX.Element { {IMAGE_ALT} - {t('welcome_title')} + {t('branded:welcome_title')} diff --git a/app/src/redux/robot-settings/types.ts b/app/src/redux/robot-settings/types.ts index 5571be6a441..3f998311c46 100644 --- a/app/src/redux/robot-settings/types.ts +++ b/app/src/redux/robot-settings/types.ts @@ -1,20 +1,10 @@ +import type { + RobotSettings, + RobotSettingsField, + RobotSettingsResponse, +} from '@opentrons/api-client' import type { RobotApiRequestMeta } from '../robot-api/types' -export interface RobotSettingsField { - id: string - title: string - description: string - value: boolean | null - restart_required?: boolean -} - -export type RobotSettings = RobotSettingsField[] - -export interface RobotSettingsResponse { - settings: RobotSettings - links?: { restart?: string } -} - export interface PerRobotRobotSettingsState { settings: RobotSettings restartPath: string | null @@ -94,3 +84,6 @@ export type RobotSettingsAction = | UpdateSettingAction | UpdateSettingSuccessAction | UpdateSettingFailureAction + +// TODO(bh, 2024-03-26): update type imports elsewhere to @opentrons/api-client +export type { RobotSettings, RobotSettingsField, RobotSettingsResponse } diff --git a/react-api-client/src/robot/__tests__/useRobotSettingsQuery.test.tsx b/react-api-client/src/robot/__tests__/useRobotSettingsQuery.test.tsx new file mode 100644 index 00000000000..2f980be9473 --- /dev/null +++ b/react-api-client/src/robot/__tests__/useRobotSettingsQuery.test.tsx @@ -0,0 +1,81 @@ +import * as React from 'react' +import { describe, it, expect, beforeEach, vi, afterEach } from 'vitest' +import { QueryClient, QueryClientProvider } from 'react-query' +import { renderHook, waitFor } from '@testing-library/react' + +import { getRobotSettings } from '@opentrons/api-client' +import { useHost } from '../../api' +import { useRobotSettingsQuery } from '..' + +import type { + HostConfig, + Response, + RobotSettingsResponse, +} from '@opentrons/api-client' +import type { UseRobotSettingsQueryOptions } from '../useRobotSettingsQuery' + +vi.mock('@opentrons/api-client') +vi.mock('../../api/useHost') + +const HOST_CONFIG: HostConfig = { hostname: 'localhost' } +const ROBOT_SETTINGS_RESPONSE: RobotSettingsResponse = { + settings: [ + { + id: 'enableOEMMode', + title: 'Enable OEM Mode', + description: 'a mode for an OEM', + value: false, + }, + ], +} + +describe('useRobotSettingsQuery hook', () => { + let wrapper: React.FunctionComponent< + { children: React.ReactNode } & UseRobotSettingsQueryOptions + > + + beforeEach(() => { + const queryClient = new QueryClient() + const clientProvider: React.FunctionComponent< + { children: React.ReactNode } & UseRobotSettingsQueryOptions + > = ({ children }) => ( + {children} + ) + + wrapper = clientProvider + }) + + afterEach(() => { + vi.resetAllMocks() + }) + + it('should return no data if no host', () => { + vi.mocked(useHost).mockReturnValue(null) + + const { result } = renderHook(() => useRobotSettingsQuery(), { wrapper }) + + expect(result.current?.data).toBeUndefined() + }) + + it('should return no data if robot settings request fails', () => { + vi.mocked(useHost).mockReturnValue(HOST_CONFIG) + vi.mocked(getRobotSettings).mockRejectedValue('oh no') + + const { result } = renderHook(() => useRobotSettingsQuery(), { wrapper }) + + expect(result.current?.data).toBeUndefined() + }) + + it('should return robot settings response data', async () => { + vi.mocked(useHost).mockReturnValue(HOST_CONFIG) + vi.mocked(getRobotSettings).mockResolvedValue({ + data: ROBOT_SETTINGS_RESPONSE, + } as Response) + + const { result } = renderHook(() => useRobotSettingsQuery(), { wrapper }) + + await waitFor(() => { + expect(result.current?.data).toEqual(ROBOT_SETTINGS_RESPONSE) + }) + }) +}) diff --git a/react-api-client/src/robot/index.ts b/react-api-client/src/robot/index.ts index 8a539abcea9..4b296d6a4fe 100644 --- a/react-api-client/src/robot/index.ts +++ b/react-api-client/src/robot/index.ts @@ -3,3 +3,4 @@ export { useEstopQuery } from './useEstopQuery' export { useLightsQuery } from './useLightsQuery' export { useAcknowledgeEstopDisengageMutation } from './useAcknowledgeEstopDisengageMutation' export { useSetLightsMutation } from './useSetLightsMutation' +export { useRobotSettingsQuery } from './useRobotSettingsQuery' diff --git a/react-api-client/src/robot/useRobotSettingsQuery.ts b/react-api-client/src/robot/useRobotSettingsQuery.ts new file mode 100644 index 00000000000..455457ec83b --- /dev/null +++ b/react-api-client/src/robot/useRobotSettingsQuery.ts @@ -0,0 +1,21 @@ +import { useQuery } from 'react-query' +import { getRobotSettings } from '@opentrons/api-client' +import { useHost } from '../api' + +import type { UseQueryResult, UseQueryOptions } from 'react-query' +import type { HostConfig, RobotSettingsResponse } from '@opentrons/api-client' + +export type UseRobotSettingsQueryOptions = UseQueryOptions + +export function useRobotSettingsQuery( + options: UseRobotSettingsQueryOptions = {} +): UseQueryResult { + const host = useHost() + const query = useQuery( + [host as HostConfig, 'robot_settings'], + () => getRobotSettings(host as HostConfig).then(response => response.data), + { enabled: host !== null, ...options } + ) + + return query +}