/** * MeshBay i18n — lightweight string localization. * * Usage: * import { t, setLocale, getLocale, LOCALES } from './i18n.js'; * t('nav.logout') // "Logout" * t('status.files', { n: 42 }) // "42 files" */ const LANG_KEY = 'mb_lang'; // ── English strings ───────────────────────────────────────────────────────── const en = { // Nav 'nav.toggle_menu': 'Toggle menu', 'nav.light_mode': 'Light mode', 'nav.dark_mode': 'Dark mode', 'nav.logout': 'Logout', 'nav.login': 'Login', // Sidebar 'sidebar.my_groups': 'My Groups', 'sidebar.no_groups': 'No groups yet', 'sidebar.discover': 'Discover', 'sidebar.public_groups': 'Public groups', // Login 'login.title': 'Login', 'login.username': 'Username', 'login.password': 'Password', 'login.submit': 'Login', 'login.loading': 'Logging in...', 'login.no_account': 'No account?', 'login.register_link': 'Register', // Register 'register.title': 'Register', 'register.username': 'Username', 'register.email': 'Email', 'register.password': 'Password (min 8 chars)', 'register.confirm': 'Confirm password', 'register.submit': 'Register', 'register.loading': 'Creating account...', 'register.has_account': 'Already have an account?', 'register.login_link': 'Login', 'register.success_title': 'Account created', 'register.success_msg': 'You can now log in with your credentials.', 'register.go_login': 'Go to login', 'register.err_mismatch': 'Passwords do not match', 'register.err_min_len': 'Password must be at least 8 characters', // Home 'home.welcome': 'Welcome to MeshBay', 'home.no_groups': 'You are not a member of any group yet.', 'home.browse_prefix': 'Browse ', 'home.browse_link': 'public groups', 'home.browse_suffix': ' or ask a group admin to invite you.', 'home.my_groups': 'My Groups', // Explore 'explore.title': 'Public Groups', 'explore.loading': 'Loading...', 'explore.empty': 'No public groups available.', // Group page 'group.default_name': 'Group', 'group.tab_files': 'Files', 'group.tab_chat': 'Chat', 'group.filter': 'Filter files...', 'group.col_name': 'Name', 'group.col_size': 'Size', 'group.col_type': 'Type', 'group.col_date': 'Date', 'group.empty_filter': 'No files match the filter', 'group.empty_dir': 'This directory is empty', 'group.download': 'Download', 'group.play': 'Play', 'group.dl_failed': 'Download failed: {err}', 'group.offline_title': 'No nodes are currently online for this group.', 'group.offline_hint': 'Files will appear when a node hosting this group connects.', 'group.err_transport': 'Transport module not loaded', // Status 'status.idle': 'Idle', 'status.discovering': 'Finding nodes...', 'status.connecting': 'Connecting via WebRTC...', 'status.fetching': 'Fetching index...', 'status.files': '{n} files', 'status.offline': 'No nodes online', 'status.error': 'Connection failed', // Chat 'chat.empty': 'No messages yet. Start the conversation!', 'chat.placeholder': 'Type a message...', 'chat.send': 'Send', // Video player 'video.loading': 'Loading {name}...', 'video.close': 'Close (Esc)', 'video.err_transport': 'Transport not connected', // Settings 'settings.title': 'Settings', 'settings.coming_soon': 'Coming soon.', 'settings.profile': 'Profile', 'settings.username': 'Username', 'settings.appearance': 'Appearance', 'settings.theme': 'Theme', 'settings.theme_light': 'Light', 'settings.theme_dark': 'Dark', 'settings.theme_system': 'System', 'settings.language': 'Language', 'settings.about': 'About', 'settings.version': 'Version', 'settings.protocol': 'Protocol', // Sidebar 'sidebar.settings': 'Settings', 'sidebar.admin': 'Admin', // Admin panel 'admin.title': 'Administration', 'admin.tab_stats': 'Stats', 'admin.tab_users': 'Users', 'admin.tab_groups': 'Groups', 'admin.tab_logs': 'Logs', 'admin.tab_blocklist': 'Blocklist', // Admin stats 'admin.stat_users': 'Users', 'admin.stat_groups': 'Groups', 'admin.stat_nodes': 'Nodes', 'admin.stat_online': 'Online Nodes', // Admin users 'admin.users_search': 'Search users...', 'admin.col_username': 'Username', 'admin.col_role': 'Role', 'admin.col_status': 'Status', 'admin.col_created': 'Created', 'admin.col_actions': 'Actions', 'admin.col_email': 'Email', 'admin.col_groups': 'Groups', 'admin.no_users': 'No users found', 'admin.btn_suspend': 'Suspend', 'admin.btn_unsuspend': 'Unsuspend', 'admin.btn_details': 'Details', 'admin.user_detail': 'User details', 'admin.btn_close': 'Close', 'admin.self_note': '(you)', // Admin groups 'admin.col_name': 'Name', 'admin.col_visibility': 'Visibility', 'admin.col_members': 'Members', 'admin.no_groups': 'No groups found', // Admin logs 'admin.col_time': 'Time', 'admin.col_event': 'Event', 'admin.col_user': 'User', 'admin.col_ip': 'IP', 'admin.col_detail': 'Detail', 'admin.filter_all': 'All events', 'admin.no_logs': 'No logs found', 'admin.btn_load_more': 'Load more', // Admin blocklist 'admin.col_hash': 'Hash', 'admin.col_reason': 'Reason', 'admin.col_date': 'Date', 'admin.col_added_by': 'Added by', 'admin.no_blocked': 'No blocked hashes', 'admin.add_hash': 'Add hash to blocklist', 'admin.hash_placeholder': 'blake3 hash (64 hex chars)', 'admin.reason_placeholder': 'Reason', 'admin.btn_block': 'Block', 'admin.btn_unblock': 'Unblock', }; // ── Locale registry ───────────────────────────────────────────────────────── const _strings = { en }; let _locale = 'en'; export const LOCALES = [ { code: 'en', name: 'English' }, ]; export function getLocale() { return _locale; } export function setLocale(code) { if (_strings[code]) { _locale = code; localStorage.setItem(LANG_KEY, code); return true; } return false; } export function addLocale(code, strings) { _strings[code] = strings; } export function t(key, params) { let s = (_strings[_locale] && _strings[_locale][key]) || _strings.en[key] || key; if (params) { for (const [k, v] of Object.entries(params)) { s = s.replace(`{${k}}`, v); } } return s; } // ── Init ──────────────────────────────────────────────────────────────────── function _init() { const stored = localStorage.getItem(LANG_KEY); if (stored && _strings[stored]) { _locale = stored; return; } const browserLang = (navigator.language || '').split('-')[0]; if (_strings[browserLang]) { _locale = browserLang; } } _init();