Coverage for aipyapp/i18n.py: 65%

74 statements  

« 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 -*- 

3 

4import locale 

5import csv 

6from importlib import resources 

7import os 

8import ctypes 

9import platform 

10 

11from loguru import logger 

12 

13def get_system_language() -> str: 

14 """ 

15 获取当前运行环境的语言代码 (例如 'en', 'zh')。 

16 支持 Windows, macOS, Linux。 

17 返回小写的语言代码,如果无法确定则返回 'en'。 

18 """ 

19 language_code = 'en' # 默认英语 

20 

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 

37 

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() 

48 

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() 

59 

60 # 规范化常见的中文代码 

61 if language_code.startswith('zh'): 

62 language_code = 'zh' 

63 

64 except Exception: 

65 # 如果发生任何错误,回退到默认值 'en' 

66 pass # 使用默认的 'en' 

67 

68 return language_code 

69 

70class Translator: 

71 def __init__(self, lang=None): 

72 self.lang = lang 

73 self.messages = {} 

74 self.log = logger.bind(src='i18n') 

75 

76 def get_lang(self): 

77 return self.lang 

78 

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}") 

84 

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() 

90 

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}") 

99 

100 def translate(self, key, *args): 

101 if not self.lang: 

102 self.set_lang() 

103 

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 

112 

113translator = Translator() 

114T = translator.translate 

115get_lang = translator.get_lang 

116set_lang = translator.set_lang 

117