74 lines
3.4 KiB
JavaScript
74 lines
3.4 KiB
JavaScript
const storageKey = 'autonomy-studio.lms.language';
|
|
let language = 'ko';
|
|
try { language = localStorage.getItem(storageKey) === 'en' ? 'en' : 'ko'; } catch {}
|
|
|
|
const english = {
|
|
'벽 배치': 'Place walls',
|
|
'맵 저장': 'Save map',
|
|
'로봇 경로 표시': 'Show robot path',
|
|
'센서 표시': 'Show sensors',
|
|
'카메라 영상 표시': 'Show camera preview',
|
|
'초기 위치 지정': 'Set initial pose',
|
|
'목표 위치 지정': 'Set goal',
|
|
'카메라 시점': 'Camera view',
|
|
'미니맵 접기/펼치기': 'Toggle minimap',
|
|
'미니맵 접기': 'Collapse minimap',
|
|
'미니맵 펼치기': 'Expand minimap',
|
|
'카메라 화면 접기/펼치기': 'Toggle camera preview',
|
|
'카메라 화면 접기': 'Collapse camera preview',
|
|
'카메라 화면 펼치기': 'Expand camera preview',
|
|
'실시간 카메라 화면': 'Live camera preview',
|
|
'i 전진 · , 후진 · j/l 회전 · k 정지': 'i Forward · , Reverse · j/l Turn · k Stop',
|
|
'i 전진 · , 후진 · j/l 주행 중 조향 · k 정지': 'i Forward · , Reverse · j/l Steer while moving · k Stop',
|
|
'ROS 상태 접기/펼치기': 'Toggle ROS status',
|
|
'ROS 상태 접기': 'Collapse ROS status',
|
|
'ROS 상태 펼치기': 'Expand ROS status',
|
|
'ROS 상태': 'ROS status',
|
|
'응답을 기다리는 중입니다.': 'Waiting for a response.',
|
|
'맵을 저장하고 있습니다.': 'Saving the map.',
|
|
'가제보 로봇 위치를 적용하지 못했습니다.': 'Failed to set the Gazebo robot pose.',
|
|
'주행 시뮬레이션에서는 초기 위치를 한 번만 설정할 수 있습니다.': 'The initial pose can only be set once during navigation simulation.',
|
|
'로봇 초기 위치 설정': 'Set initial robot pose',
|
|
'3D 포인트클라우드를 표시 중입니다.': 'Displaying the 3D point cloud.',
|
|
'모듈을 연결해주세요.': 'Connect your modules.',
|
|
'맵 저장에 실패했습니다.': 'Failed to save the map.',
|
|
'기존 목표를 취소하지 못했습니다.': 'Failed to cancel the previous goal.',
|
|
'가제보 로봇 위치 적용 시간이 초과되었습니다.': 'Setting the Gazebo robot pose timed out.'
|
|
};
|
|
|
|
export function t(key) { return language === 'en' ? (english[key] ?? key) : key; }
|
|
|
|
// Only explicitly marked viewer UI is translated. Topic names and telemetry stay intact.
|
|
export function setText(element, key) {
|
|
element.dataset.i18n = key;
|
|
element.textContent = t(key);
|
|
}
|
|
|
|
function refresh() {
|
|
document.documentElement.lang = language;
|
|
document.querySelectorAll('[data-i18n]').forEach(element => {
|
|
element.textContent = t(element.dataset.i18n);
|
|
});
|
|
for (const attribute of ['title', 'aria-label', 'alt']) {
|
|
document.querySelectorAll(`[data-i18n-${attribute}]`).forEach(element => {
|
|
element.setAttribute(attribute, t(element.getAttribute(`data-i18n-${attribute}`)));
|
|
});
|
|
}
|
|
}
|
|
|
|
window.addEventListener('storage', event => {
|
|
if (event.key !== storageKey) return;
|
|
language = event.newValue === 'en' ? 'en' : 'ko';
|
|
refresh();
|
|
});
|
|
refresh();
|
|
|
|
// Embedded viewers may not share storage with the app (for example file URLs).
|
|
window.addEventListener('message', event => {
|
|
if (window.parent === window || event.source !== window.parent) return;
|
|
if (event.data?.type !== 'lms:language' || !['ko', 'en'].includes(event.data.language)) return;
|
|
language = event.data.language;
|
|
refresh();
|
|
});
|
|
if (window.parent !== window) window.parent.postMessage({ type: 'lms:language:ready' }, '*');
|