(function() {
'use strict';
// ========== i18n 初始化 ==========
var _lang = localStorage.getItem('qriflow_lang') || (navigator.language.startsWith('zh') ? 'zh' : 'en');
var translations = {
zh: {
appName: 'QRFlow',
headerDesc: '在线二维码生成器 · 自定义颜色 · 嵌入 Logo · 批量导出',
inputLabel: '输入文本 / URL',
sizeLabel: '尺寸',
fgLabel: '前景色',
bgLabel: '背景色',
logoLabel: '嵌入 Logo(选填)',
batchLabel: '批量生成模式',
uploadLogo: '点击上传 Logo 图片',
uploadCSV: '或上传 CSV 文件',
batchPlaceholder: '每行一个文本或 URL,或粘贴 CSV 格式\n名称,内容\n例如:\nGitHub,https://github.com\nTwitter,https://twitter.com',
downloadPng: '下载 PNG',
downloadSvg: '下载 SVG',
downloadZip: '下载全部 ZIP',
removeLogo: '移除',
previewPlaceholder: '输入内容后自动生成二维码',
generated: '已生成 {count} 个二维码',
processing: '处理中…',
privacy: '隐私政策',
copyright: '© 2025 QRFlow',
pleaseInput: '请输入内容',
pleaseGenerate: '请先生成二维码',
downloadedPng: '已下载 PNG',
downloadedZip: '已下载 ZIP',
genFailed: '生成失败: ',
logoLoadError: 'Logo 加载失败',
csvParseError: 'CSV 解析失败',
svgNotSupport: 'SVG 导出暂不支持,请使用 PNG',
switchLang: 'EN'
},
en: {
appName: 'QRFlow',
headerDesc: 'Online QR Code Generator · Custom Colors · Logo Embed · Batch Export',
inputLabel: 'Text / URL',
sizeLabel: 'Size',
fgLabel: 'Foreground',
bgLabel: 'Background',
logoLabel: 'Embed Logo (optional)',
batchLabel: 'Batch Mode',
uploadLogo: 'Click to upload logo image',
uploadCSV: 'Or upload CSV file',
batchPlaceholder: 'One text/URL per line, or CSV format\nname,content\ne.g.:\nGitHub,https://github.com\nTwitter,https://twitter.com',
downloadPng: 'Download PNG',
downloadSvg: 'Download SVG',
downloadZip: 'Download All ZIP',
removeLogo: 'Remove',
previewPlaceholder: 'Enter content to generate QR code',
generated: 'Generated {count} QR codes',
processing: 'Processing…',
privacy: 'Privacy Policy',
copyright: '© 2025 QRFlow',
pleaseInput: 'Please enter content',
pleaseGenerate: 'Please generate a QR code first',
downloadedPng: 'PNG Downloaded',
downloadedZip: 'ZIP Downloaded',
genFailed: 'Generation failed: ',
logoLoadError: 'Logo load failed',
csvParseError: 'CSV parse failed',
svgNotSupport: 'SVG export not supported yet. Please use PNG.',
switchLang: '中'
}
};
window.__ = function(key, vars) {
var t = translations[_lang] || translations.zh;
var str = t[key] || translations.zh[key] || key;
if (vars) {
for (var k in vars) {
str = str.replace('{'+k+'}', vars[k]);
}
}
return str;
};
window.setLang = function(lang) {
if (translations[lang]) {
_lang = lang;
localStorage.setItem('qriflow_lang', lang);
applyI18n();
}
};
window.getLang = function() { return _lang; };
function applyI18n() {
// data-i18n 文本替换
document.querySelectorAll('[data-i18n]').forEach(function(el) {
var key = el.getAttribute('data-i18n');
el.textContent = __(key);
});
// data-i18n-placeholder 替换
document.querySelectorAll('[data-i18n-placeholder]').forEach(function(el) {
var key = el.getAttribute('data-i18n-placeholder');
el.placeholder = __(key);
});
// 特殊处理进度文字
var pt = document.getElementById('progressText');
if (pt) pt.textContent = __('processing');
// 处理批量计数区域
var bc = document.getElementById('batchCount');
if (bc) {
var parentDiv = bc.parentNode;
var count = parseInt(bc.textContent) || 0;
parentDiv.innerHTML = __('generated', {count: count});
}
// 语言切换按钮文字
var langBtn = document.getElementById('langToggleBtn');
if (langBtn) langBtn.textContent = __('switchLang');
}
// 语言选择器(追加到 footer)
function addLangToggle() {
var footer = document.querySelector('.footer');
if (!footer) return;
var btn = document.createElement('button');
btn.id = 'langToggleBtn';
btn.className = 'lang-toggle';
btn.textContent = __('switchLang');
btn.addEventListener('click', function() {
var newLang = _lang === 'zh' ? 'en' : 'zh';
setLang(newLang);
});
footer.appendChild(btn);
}
// ========== 全局错误捕获 ==========
window.onerror = function(msg, url, line, col, error) {
console.error('全局错误:', msg, url, line, col);
var toast = document.getElementById('toast');
if (toast) {
toast.textContent = '发生错误,请刷新页面重试';
toast.classList.add('show');
setTimeout(function(){toast.classList.remove('show');}, 3000);
}
return true;
};
// ========== 修复 FileReader 无 catch ==========
// 重新绑定 logo 上传事件(覆盖原监听)
var logoInput = document.getElementById('logoInput');
var oldLogoListener = null;
if (logoInput) {
// 移除原有的所有 change 监听(使用新函数)
// 由于原有是匿名函数,我们通过 clone 替换
var newLogoInput = logoInput.cloneNode(true);
logoInput.parentNode.replaceChild(newLogoInput, logoInput);
logoInput = newLogoInput;
logoInput.addEventListener('change', function() {
if (this.files.length > 0) {
var r = new FileReader();
r.onload = function(e) {
try {
logoDataURL = e.target.result;
var logoImg = document.getElementById('logoImg');
var logoPreview = document.getElementById('logoPreview');
if (logoImg) logoImg.src = logoDataURL;
if (logoPreview) logoPreview.style.display = 'flex';
if (typeof generateQR === 'function') generateQR();
} catch(err) {
showToast(__('logoLoadError'));
}
};
r.onerror = function() {
showToast(__('logoLoadError'));
};
r.readAsDataURL(this.files[0]);
}
});
}
// 重新绑定 CSV 上传
var csvInput = document.getElementById('csvInput');
if (csvInput) {
var newCsvInput = csvInput.cloneNode(true);
csvInput.parentNode.replaceChild(newCsvInput, csvInput);
csvInput = newCsvInput;
csvInput.addEventListener('change', function() {
if (this.files.length > 0) {
var r = new FileReader();
r.onload = function(e) {
try {
var batchInput = document.getElementById('batchInput');
if (batchInput) batchInput.value = e.target.result;
if (typeof generateQR === 'function') generateQR();
} catch(err) {
showToast(__('csvParseError'));
}
};
r.onerror = function() {
showToast(__('csvParseError'));
};
r.readAsText(this.files[0]);
}
});
// 同时更新上传标签文字
var csvUpload = document.getElementById('csvUpload');
if (csvUpload) {
var p = csvUpload.querySelector('p');
if (p) p.setAttribute('data-i18n', 'uploadCSV');
}
}
// ========== 补充 SVG 下载功能 ==========
var svgBtn = document.getElementById('downloadSvgBtn');
if (svgBtn) {
svgBtn.addEventListener('click', function() {
showToast(__('svgNotSupport'));
});
}
// ========== 语言切换初始化 ==========
document.addEventListener('DOMContentLoaded', function() {
addLangToggle();
applyI18n();
// 确保尺寸滑块位置
var activeSizeBtn = document.querySelector('#sizeSelector .mode-btn.active');
if (activeSizeBtn && typeof moveSizeSlider === 'function') {
moveSizeSlider(activeSizeBtn);
}
});
// 为 window.showToast 添加 i18n 兼容(保留原函数)
var originalShowToast = window.showToast;
window.showToast = function(msg) {
if (originalShowToast) originalShowToast(msg);
else {
var el = document.getElementById('toast');
if (el) {
el.textContent = msg;
el.classList.add('show');
clearTimeout(window._toastTimer);
window._toastTimer = setTimeout(function(){el.classList.remove('show');}, 2400);
}
}
};
// ========== 资源加载状态检测 ==========
setTimeout(function() {
var cssLink = document.querySelector('link[href="../shared/nav-bar.css"]');
if (cssLink && !cssLink.sheet) {
console.warn('nav-bar.css 可能未正确加载');
}
}, 2000);
})();