diff --git a/app/src/App.tsx b/app/src/App.tsx
index 82a7df97b..9387b847e 100644
--- a/app/src/App.tsx
+++ b/app/src/App.tsx
@@ -19,6 +19,7 @@ import PersistRehydrationScreen from './components/PersistRehydrationScreen';
import GlobalUpsellBanner from './components/upsell/GlobalUpsellBanner';
import AppWalkthrough from './components/walkthrough/AppWalkthrough';
import { MascotFrameProducer } from './features/meet/MascotFrameProducer';
+import { I18nProvider } from './lib/i18n/I18nContext';
// [#1123] Commented out — welcome-agent onboarding replaced by Joyride walkthrough
// import { isWelcomeLocked } from './lib/coreState/store';
import { startNativeNotificationsService } from './lib/nativeNotifications';
@@ -58,24 +59,26 @@ function App() {
)}>
} persistor={persistor}>
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/components/BootCheckGate/BootCheckGate.tsx b/app/src/components/BootCheckGate/BootCheckGate.tsx
index 895c12fad..2d03cd522 100644
--- a/app/src/components/BootCheckGate/BootCheckGate.tsx
+++ b/app/src/components/BootCheckGate/BootCheckGate.tsx
@@ -13,6 +13,7 @@ import debug from 'debug';
import { useCallback, useEffect, useRef, useState } from 'react';
import { type BootCheckResult, runBootCheck } from '../../lib/bootCheck';
+import { useT } from '../../lib/i18n/I18nContext';
import { bootCheckTransport } from '../../services/bootCheckService';
import {
clearCoreRpcTokenCache,
@@ -82,6 +83,7 @@ type TestStatus =
const DESKTOP_DOWNLOAD_URL = 'https://github.com/tinyhumansai/openhuman/releases/latest';
function ModePicker({ onConfirm }: PickerProps) {
+ const { t } = useT();
// Web build cannot spawn a local sidecar, so the only viable choice is
// cloud. Default the selection accordingly and hide the local option in
// the render path below.
@@ -108,13 +110,13 @@ function ModePicker({ onConfirm }: PickerProps) {
const validateInputs = (): { url: string; token: string } | null => {
const trimmedUrl = cloudUrl.trim();
if (!trimmedUrl) {
- setUrlError('Please enter a core URL.');
+ setUrlError(t('bootCheck.invalidUrl'));
return null;
}
try {
const parsed = new URL(trimmedUrl);
if (parsed.protocol !== 'http:' && parsed.protocol !== 'https:') {
- setUrlError('URL must start with http:// or https://');
+ setUrlError(t('bootCheck.urlMustStartWith'));
return null;
}
if (parsed.protocol === 'http:' && !isLocalOrPrivateNetworkHost(parsed.hostname)) {
@@ -124,14 +126,14 @@ function ModePicker({ onConfirm }: PickerProps) {
return null;
}
} catch {
- setUrlError('Please enter a valid URL (e.g. https://core.example.com/rpc)');
+ setUrlError(t('bootCheck.validUrlRequired'));
return null;
}
setUrlError(null);
const trimmedToken = cloudToken.trim();
if (!trimmedToken) {
- setTokenError('Please enter the core auth token.');
+ setTokenError(t('bootCheck.tokenRequired'));
return null;
}
setTokenError(null);
@@ -198,25 +200,23 @@ function ModePicker({ onConfirm }: PickerProps) {
return (
- {isDesktop ? 'Choose core mode' : 'Connect to your core'}
+ {isDesktop ? t('bootCheck.chooseCoreMode') : t('bootCheck.connectToCore')}
- {isDesktop
- ? 'OpenHuman needs a running core to operate. Choose how you want to connect.'
- : 'OpenHuman on the web connects to a remote core you control. Enter its URL and auth token, or install the desktop app to run one locally.'}
+ {isDesktop ? t('bootCheck.desktopDescription') : t('bootCheck.webDescription')}
- Stored on this device only. Required for remote cores — the desktop sends it as{' '}
- Authorization: Bearer … on every RPC.
+ {t('bootCheck.storedLocally')} Authorization: Bearer … on every RPC.