Files
sbackup/sbackup/i18n.py
T

109 lines
3.4 KiB
Python

import json
import os
import sys
import logging
logger = logging.getLogger(__name__)
_current_locale = "zh_CN"
_translations = {}
def _get_locales_dir() -> str:
"""获取 locales 目录路径(兼容正常 Python 和 Nuitka/PyInstaller 打包)"""
if getattr(sys, "frozen", False):
# Nuitka/PyInstaller 打包后,资源在可执行文件同级目录
base_dir = os.path.dirname(sys.executable)
return os.path.join(base_dir, "sbackup", "locales")
# 正常 Python 环境
return os.path.join(os.path.dirname(__file__), "locales")
# 初始化默认语言包
_default_file = os.path.join(_get_locales_dir(), "zh_CN.json")
if os.path.exists(_default_file):
try:
with open(_default_file, "r", encoding="utf-8") as f:
_translations = json.load(f)
except (json.JSONDecodeError, OSError) as e:
logger.warning("i18n.load.default_failed %s: %s", _default_file, e)
def set_locale(lang: str) -> None:
"""
设置当前语言环境并加载对应的翻译文件
"""
global _current_locale, _translations
# 安全检查:拒绝包含路径遍历字符的语言代码
if not lang or "/" in lang or "\\" in lang or ".." in lang or ":" in lang:
logger.warning("i18n.set_locale.invalid_lang: %s", lang)
return
# 白名单校验:只允许已知的语言代码格式
_KNOWN_LOCALES = {
"zh_CN",
"en_US",
"fr_FR",
"es_ES",
"ru_RU",
"de_DE",
"ja_JP",
"pt_BR",
"ko_KR",
}
if lang not in _KNOWN_LOCALES:
logger.warning("i18n.set_locale.unknown_locale: %s", lang)
# 仍然设置 _current_locale 以保持向后兼容
_current_locale = lang
# 回退到默认中文翻译
default_file = os.path.join(_get_locales_dir(), "zh_CN.json")
if os.path.exists(default_file):
try:
with open(default_file, "r", encoding="utf-8") as f:
_translations = json.load(f)
except (json.JSONDecodeError, OSError) as e:
logger.warning(
t("log.i18n.load.fallback_failed", path=default_file, error=e)
)
_translations = {}
return
_current_locale = lang
locale_file = os.path.join(_get_locales_dir(), f"{lang}.json")
if os.path.exists(locale_file):
try:
with open(locale_file, "r", encoding="utf-8") as f:
_translations = json.load(f)
return
except (json.JSONDecodeError, OSError) as e:
logger.warning(t("log.i18n.load.failed", path=locale_file, error=e))
# 回退到默认中文
default_file = os.path.join(_get_locales_dir(), "zh_CN.json")
if os.path.exists(default_file):
try:
with open(default_file, "r", encoding="utf-8") as f:
_translations = json.load(f)
except (json.JSONDecodeError, OSError) as e:
logger.warning(
t("log.i18n.load.fallback_failed", path=default_file, error=e)
)
_translations = {}
def t(key: str, **kwargs) -> str:
"""
获取翻译文本
:param key: 翻译键名
:param kwargs: 格式化参数
:return: 翻译后的字符串
"""
text = _translations.get(key, key)
if kwargs:
try:
return text.format(**kwargs)
except (KeyError, ValueError):
return text
return text