// Shared localization for the service panel and progress window. (function () { 'use strict'; const fs = require('fs'); const path = require('path'); const LANGUAGES = ['en', 'zh_CN', 'zh_TW', 'ja_JP', 'ko_KR', 'ru_RU', 'es_ES', 'de_DE']; const FALLBACK = 'zh_CN'; function normalizeLocale(raw) { if (!raw) return null; const tag = String(raw).trim().toLowerCase().replace(/-/g, '_'); if (tag === 'zh_tw' || tag === 'zh_hk' || tag === 'zh_hant' || tag === 'zh_mo') return 'zh_TW'; for (const code of LANGUAGES) { if (code.toLowerCase() === tag) return code; } const base = tag.split('_')[0]; if (base === 'zh') return 'zh_CN'; for (const code of LANGUAGES) { if (code.toLowerCase().split('_')[0] === base) return code; } return null; } function requestedLocale() { try { const fromUrl = new URLSearchParams(location.search).get('lang'); if (fromUrl) return fromUrl; } catch (error) { /* No browser location. */ } try { if (typeof eagle !== 'undefined' && eagle.app && eagle.app.locale) return eagle.app.locale; } catch (error) { /* Eagle API is injected asynchronously. */ } try { return navigator.language; } catch (error) { return null; } } function pluginRoot() { if (window.SpinePluginPath) return window.SpinePluginPath; if (window.SpinePluginRoot) return window.SpinePluginRoot; return typeof __dirname !== 'undefined' ? __dirname : null; } function readLocale(code) { try { const root = pluginRoot(); if (!root) return {}; return JSON.parse(fs.readFileSync(path.join(root, '_locales', code + '.json'), 'utf8')); } catch (error) { return {}; } } function lookup(table, key) { let node = table; for (const part of String(key).split('.')) { if (!node || typeof node !== 'object') return undefined; node = node[part]; } return typeof node === 'string' ? node : undefined; } function apply(root) { const scope = root || document; for (const el of scope.querySelectorAll('[data-i18n]')) el.textContent = t(el.dataset.i18n); for (const el of scope.querySelectorAll('[data-i18n-title]')) el.title = t(el.dataset.i18nTitle); for (const el of scope.querySelectorAll('[data-i18n-aria-label]')) el.setAttribute('aria-label', t(el.dataset.i18nAriaLabel)); } let fallbackMessages = readLocale(FALLBACK); let locale = FALLBACK; let messages = fallbackMessages; function t(key, vars) { let text = lookup(messages, key); if (text === undefined) text = lookup(fallbackMessages, key); if (text === undefined) return key; if (vars) { text = text.replace(/\{(\w+)\}/g, (whole, name) => Object.prototype.hasOwnProperty.call(vars, name) ? String(vars[name]) : whole); } return text; } function setLocale(raw) { locale = normalizeLocale(raw) || FALLBACK; fallbackMessages = readLocale(FALLBACK); messages = locale === FALLBACK ? fallbackMessages : readLocale(locale); document.documentElement.lang = locale.replace('_', '-'); apply(document); return locale; } const api = { languages: LANGUAGES, fallback: FALLBACK, get locale() { return locale; }, normalizeLocale, requestedLocale, setLocale, t, apply, }; window.SpineThumbI18n = api; setLocale(requestedLocale()); })();