Files
orca/mobile/src/terminal/TerminalWebView.tsx
T
OrcaWinandOrcaWin d8eef80bf4 feat(mobile): localize sessions, terminal, agent chat, browser and files (#35553)
Moves ~970 strings in session screens, the terminal, agent chat (including the
copy mobile used to render straight from shared English records), the browser pane
and the file explorer to the translation API, with all ten translations.

- Chat tool-run sentences, task lists, receipts, notices and turn status take
  translated words; the shared sentence joiner accepts an optional continuation so
  German nouns and Turkish casing survive mid-sentence (desktop unchanged)
- "Used the browser" vs "… 21 times" and resolved PR comment headers use explicit
  keys instead of plural rules, which would drop the count for Russian 21, 31, …
- Action sheet rows carry stable ids instead of being keyed by translated labels
- Rename inputs keep the raw title rather than a translated placeholder

Co-authored-by: OrcaWin <293788423+OrcaWin@users.noreply.github.com>
2026-10-29 03:55:41 +00:00

112 lines
4.0 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { useRef, useCallback, useState, forwardRef, useImperativeHandle } from 'react'
import { Platform, View } from 'react-native'
import { WebView, type WebViewMessageEvent } from 'react-native-webview'
import { useMobileTranslation } from '../i18n/use-mobile-translation'
import type { TerminalWebViewHandle, TerminalWebViewProps } from './terminal-webview-contract'
import { TerminalWebViewEngineErrorOverlay } from './terminal-webview-engine-error-state'
import { TERMINAL_WEBVIEW_FRAME_STYLES } from './terminal-webview-frame-styles'
import { xtermWebViewSource } from './terminal-webview-html'
import type { TerminalWebViewCommand } from './terminal-webview-messages'
import { useTerminalWebViewController } from './use-terminal-webview-controller'
type Props = TerminalWebViewProps
export type { TerminalWebViewHandle } from './terminal-webview-contract'
export const TerminalWebView = forwardRef<TerminalWebViewHandle, Props>(
function TerminalWebView(props, ref) {
const t = useMobileTranslation()
const webViewRef = useRef<WebView>(null)
const post = useCallback((command: TerminalWebViewCommand & { id: number }) => {
webViewRef.current?.postMessage(JSON.stringify(command))
}, [])
const {
clearEngineError,
engineError,
handle,
receive,
reportNativeEngineError,
resetReadiness
} = useTerminalWebViewController(props, {
post,
// iOS can preserve the native view while discarding its JS/backing-store state.
pingsOnForegroundRecovery: () => Platform.OS === 'ios'
})
useImperativeHandle(ref, () => handle, [handle])
// Seed scale in page source before document startup; Android injected scripts may run too late.
const [source] = useState(() =>
xtermWebViewSource({ textScale: props.textScale ?? 1, shown: props.shownAtMount ?? true })
)
const handleMessage = useCallback(
(event: WebViewMessageEvent) => {
let msg: Record<string, unknown>
try {
msg = JSON.parse(event.nativeEvent.data) as Record<string, unknown>
} catch {
return
}
receive(msg)
},
[receive]
)
const handleReload = useCallback(() => {
clearEngineError()
webViewRef.current?.reload()
}, [clearEngineError])
const handleContentProcessDidTerminate = useCallback(() => {
// Content-process recovery must discard dead-document commands and prove new readiness before replay.
resetReadiness()
clearEngineError()
webViewRef.current?.reload()
}, [clearEngineError, resetReadiness])
return (
<View style={[TERMINAL_WEBVIEW_FRAME_STYLES.container, props.style]}>
<WebView
ref={webViewRef}
source={source}
style={TERMINAL_WEBVIEW_FRAME_STYLES.webview}
originWhitelist={['*']}
javaScriptEnabled
scrollEnabled={false}
// Prevent Android parent gestures from intercepting drags before xterm sees them.
nestedScrollEnabled
scalesPageToFit={false}
// Fix Android textZoom at 100 so OS font scaling cannot exceed xterm’s canvas-measured grid.
textZoom={100}
onLoadStart={resetReadiness}
onMessage={handleMessage}
onError={(event) =>
reportNativeEngineError(
t('terminal.webView.loadFailed', 'Terminal WebView load failed'),
event
)
}
onHttpError={(event) =>
reportNativeEngineError(
t('terminal.webView.httpError', 'Terminal WebView HTTP error'),
event
)
}
onRenderProcessGone={(event) =>
reportNativeEngineError(
t('terminal.webView.renderProcessEnded', 'Terminal WebView render process ended'),
event
)
}
onContentProcessDidTerminate={handleContentProcessDidTerminate}
/>
{engineError ? (
<TerminalWebViewEngineErrorOverlay message={engineError} onReload={handleReload} />
) : null}
</View>
)
}
)