Coverage for aipyapp/i18n.py: 65%
74 statements
« prev ^ index » next coverage.py v7.10.3, created at 2025-08-11 12:02 +0200
« prev ^ index » next coverage.py v7.10.3, created at 2025-08-11 12:02 +0200
1#!/usr/bin/env python
2# -*- coding: utf-8 -*-
4import locale
5import csv
6from importlib import resources
7import os
8import ctypes
9import platform
11from loguru import logger
13def get_system_language() -> str:
14 """
15 获取当前运行环境的语言代码 (例如 'en', 'zh')。
16 支持 Windows, macOS, Linux。
17 返回小写的语言代码,如果无法确定则返回 'en'。
18 """
19 language_code = 'en' # 默认英语
21 try:
22 if platform.system() == "Windows":
23 # Windows: 使用 GetUserDefaultUILanguage 或 GetSystemDefaultUILanguage
24 # https://learn.microsoft.com/en-us/windows/win32/intl/language-identifiers
25 windll = ctypes.windll.kernel32
26 # GetUserDefaultUILanguage 返回当前用户的UI语言ID
27 lang_id = windll.GetUserDefaultUILanguage()
28 # 将语言ID转换为标准语言代码 (例如 1033 -> en, 2052 -> zh)
29 # 主要语言ID在低10位
30 primary_lang_id = lang_id & 0x3FF
31 if primary_lang_id == 0x04: # zh - Chinese
32 language_code = 'zh'
33 elif primary_lang_id == 0x09: # en - English
34 language_code = 'en'
35 # 可以根据需要添加更多语言ID映射
36 # 参考: https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-lcid/a9eac961-e77d-41a6-90a5-ce1a8b0cdb9c
38 elif platform.system() == "Darwin": # macOS
39 # macOS: 优先使用 locale.getlocale()
40 language, encoding = locale.getlocale()
41 if language:
42 language_code = language.split('_')[0].lower()
43 else:
44 # 备选方案: 读取环境变量
45 lang_env = os.environ.get('LANG')
46 if lang_env:
47 language_code = lang_env.split('_')[0].lower()
49 else: # Linux/Unix
50 # Linux/Unix: 优先使用 locale.getlocale()
51 language, encoding = locale.getlocale()
52 if language:
53 language_code = language.split('_')[0].lower()
54 else:
55 # 备选方案: 读取环境变量 LANG 或 LANGUAGE
56 lang_env = os.environ.get('LANG') or os.environ.get('LANGUAGE')
57 if lang_env:
58 language_code = lang_env.split('_')[0].lower()
60 # 规范化常见的中文代码
61 if language_code.startswith('zh'):
62 language_code = 'zh'
64 except Exception:
65 # 如果发生任何错误,回退到默认值 'en'
66 pass # 使用默认的 'en'
68 return language_code
70class Translator:
71 def __init__(self, lang=None):
72 self.lang = lang
73 self.messages = {}
74 self.log = logger.bind(src='i18n')
76 def get_lang(self):
77 return self.lang
79 def set_lang(self, lang=None):
80 """Set the current language."""
81 if not lang:
82 lang = get_system_language()
83 self.log.info(f"No language specified, using system language: {lang}")
85 if lang != self.lang:
86 if self.lang: self.log.info(f"Switching language from {self.lang} to: {lang}")
87 else: self.log.info(f"Setting language to: {lang}")
88 self.lang = lang
89 self.load_messages()
91 def load_messages(self):
92 try:
93 with resources.open_text('aipyapp.res', 'locales.csv') as f:
94 reader = csv.DictReader(f)
95 for row in reader:
96 self.messages[row['en']] = None if self.lang=='en' else row.get(self.lang)
97 except Exception as e:
98 self.log.error(f"Error loading translations: {e}")
100 def translate(self, key, *args):
101 if not self.lang:
102 self.set_lang()
104 if self.lang == 'en':
105 msg = key
106 else:
107 msg = self.messages.get(key)
108 if not msg:
109 self.log.error(f"Translation not found for key: {key}")
110 msg = key
111 return msg.format(*args) if args else msg
113translator = Translator()
114T = translator.translate
115get_lang = translator.get_lang
116set_lang = translator.set_lang