feat: add language selector with i18n support

- Add createLanguageSelector function to amipro_utils.js
- Add language selector CSS styles to modern.css and core.css
- Support EN/JA language switching with localStorage persistence
This commit is contained in:
qingjie.du
2026-06-21 12:23:26 +09:00
parent d06b4cf629
commit 97a3a007e6
3 changed files with 251 additions and 4 deletions

View File

@@ -4,16 +4,60 @@
'use strict';
var _currentLang = null;
var _i18n_map = null;
function getCurrentLanguage() {
if (_currentLang) return _currentLang;
var stored = localStorage.getItem('amipro_lang');
if (stored) { _currentLang = stored; return stored; }
var browserLang = window.navigator.language || 'en';
if (browserLang.indexOf('ja') === 0) return 'ja';
return 'en';
}
function setLanguage(lang) {
_currentLang = lang;
localStorage.setItem('amipro_lang', lang);
document.documentElement.lang = lang;
if (_i18n_map) setI18NText(_i18n_map);
updateImages(lang);
var sel = document.getElementById('lang-selector');
if (sel) sel.value = lang;
}
function updateImages(lang) {
var heroImg = document.getElementById('hero-image');
var searchImg = document.getElementById('search-image');
if (heroImg) {
if (lang === 'ja') {
heroImg.src = 'contextwizard-files/cw-banner-jp.png';
} else {
heroImg.src = 'contextwizard-files/screen-platforms-640-400.jpg';
}
}
if (searchImg) {
if (lang === 'ja') {
searchImg.src = 'contextwizard-files/screen-search-640-400-jp.jpg';
} else {
searchImg.src = 'contextwizard-files/screen-search-640-400.jpg';
}
}
}
function setI18NText(i18n_map){
_i18n_map = i18n_map;
var lang = getCurrentLanguage();
for (const key of i18n_map.keys()) {
const elm = $("#"+key);
if(elm){
const lang = window.navigator.language;
var elem = i18n_map.get(key)
var msg = null
if(elem){
msg = elem.get(lang)
if(!msg && lang && lang.indexOf('-') > -1) msg = elem.get(lang.split('-')[0]);
if(!msg) msg = elem.get('en');
if(!msg) msg = elem.get('en-US');
}
if(!msg)msg = key+"-"+lang
@@ -24,12 +68,12 @@ function setI18NText(i18n_map){
}
function getI18NText(i18n_map, key){
const lang = window.navigator.language;
var lang = getCurrentLanguage();
var elem = i18n_map.get(key)
var msg = null
if(elem){
msg = elem.get(lang)
if(!msg && lang && lang.indexOf('-') > -1) msg = elem.get(lang.split('-')[0]);
if(!msg) msg = elem.get('en');
if(!msg) msg = elem.get('en-US');
}
if(!msg)msg = key+"-"+lang
@@ -37,6 +81,106 @@ function getI18NText(i18n_map, key){
return msg
}
function createLanguageSelector() {
var current = getCurrentLanguage();
var wrapper = document.createElement('div');
wrapper.className = 'lang-selector-wrapper lang-selector-floating';
wrapper.id = 'lang-selector-draggable';
wrapper.innerHTML = '<select id="lang-selector" class="lang-selector" onchange="setLanguage(this.value)">' +
'<option value="en"' + (current === 'en' ? ' selected' : '') + '>EN</option>' +
'<option value="ja"' + (current === 'ja' ? ' selected' : '') + '>JA</option>' +
'</select>';
var savedPos = localStorage.getItem('amipro_lang_pos');
if (savedPos) {
try {
var pos = JSON.parse(savedPos);
wrapper.style.left = pos.x + 'px';
wrapper.style.top = pos.y + 'px';
wrapper.style.right = 'auto';
} catch(e) {}
}
makeDraggable(wrapper);
return wrapper;
}
function makeDraggable(el) {
var isDragging = false;
var startX, startY, startLeft, startTop;
el.style.cursor = 'grab';
el.addEventListener('mousedown', function(e) {
if (e.target.tagName === 'SELECT') return;
isDragging = true;
startX = e.clientX;
startY = e.clientY;
startLeft = el.offsetLeft;
startTop = el.offsetTop;
el.style.cursor = 'grabbing';
el.style.right = 'auto';
e.preventDefault();
});
document.addEventListener('mousemove', function(e) {
if (!isDragging) return;
var dx = e.clientX - startX;
var dy = e.clientY - startY;
var newLeft = startLeft + dx;
var newTop = startTop + dy;
newLeft = Math.max(0, Math.min(newLeft, window.innerWidth - el.offsetWidth));
newTop = Math.max(0, Math.min(newTop, window.innerHeight - el.offsetHeight));
el.style.left = newLeft + 'px';
el.style.top = newTop + 'px';
});
document.addEventListener('mouseup', function() {
if (!isDragging) return;
isDragging = false;
el.style.cursor = 'grab';
localStorage.setItem('amipro_lang_pos', JSON.stringify({
x: el.offsetLeft,
y: el.offsetTop
}));
});
el.addEventListener('touchstart', function(e) {
if (e.target.tagName === 'SELECT') return;
isDragging = true;
startX = e.touches[0].clientX;
startY = e.touches[0].clientY;
startLeft = el.offsetLeft;
startTop = el.offsetTop;
el.style.right = 'auto';
}, { passive: true });
document.addEventListener('touchmove', function(e) {
if (!isDragging) return;
var dx = e.touches[0].clientX - startX;
var dy = e.touches[0].clientY - startY;
var newLeft = startLeft + dx;
var newTop = startTop + dy;
newLeft = Math.max(0, Math.min(newLeft, window.innerWidth - el.offsetWidth));
newTop = Math.max(0, Math.min(newTop, window.innerHeight - el.offsetHeight));
el.style.left = newLeft + 'px';
el.style.top = newTop + 'px';
}, { passive: true });
document.addEventListener('touchend', function() {
if (!isDragging) return;
isDragging = false;
localStorage.setItem('amipro_lang_pos', JSON.stringify({
x: el.offsetLeft,
y: el.offsetTop
}));
});
}
function initRevealAnimations(){
const animated = document.querySelectorAll('.reveal, [data-animate]');
if(!animated || animated.length === 0){