2025-10-05 11:23:33 +08:00

336 lines
7.3 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# `MiniI18N` 国际化工具技术文档
```markdown
# MiniI18N - 轻量级多语言支持模块
`MiniI18N` 是一个基于 Python 的轻量级国际化i18n工具用于在应用程序中实现多语言文本的加载与动态切换。它通过读取指定目录下的语言文件`msg.txt`),将键值对形式的消息映射到目标语言,并提供线程安全的语言上下文管理。
---
## 模块依赖
```python
import os, re, sys
import codecs
from appPublic.folderUtils import _mkdir, ProgramPath
from appPublic.Singleton import SingletonDecorator
from appPublic.jsonConfig import getConfig
import threading
import time
import locale
```
> 说明:该模块依赖于 `appPublic` 包中的若干实用工具类和函数,包括单例装饰器、配置读取、路径处理等。
---
## 全局变量与常量
### 正则表达式
- `comment_re`: 匹配以 `#` 开头的注释行。
```python
comment_re = re.compile(r'\s*#.*')
```
- `msg_re`: 匹配形如 `key : value` 的消息条目(允许前后空格)。
```python
msg_re = re.compile(r'\s*([^:]*)\s*:\s*([^\s].*)')
```
### 编码转换表
用于对特殊字符进行编码/解码,避免配置文件解析冲突:
```python
convert_pairs = {
':': '\\x3A',
'\n': '\\x0A',
'\r': '\\x0D',
}
```
| 原始字符 | 编码表示 |
|--------|---------|
| `:` | `\x3A` |
| `\n` | `\x0A` |
| `\r` | `\x0D` |
---
## 核心函数
### `dictModify(d, md)`
合并字典 `md` 到字典 `d`,仅当值不为 `None` 时更新。
**参数:**
- `d` (dict): 目标字典
- `md` (dict): 更新数据字典
**返回:**
- 修改后的 `d`
---
### `charEncode(s)`
对字符串中的特殊字符进行编码替换,防止解析错误。
**参数:**
- `s` (str): 待编码字符串
**逻辑:**
1. 将 `\` 替换为 `\\\\`
2.`convert_pairs` 中定义的字符进行编码替换
**示例:**
```python
charEncode("hello:world\n")
# 输出: "hello\\x3Aworld\\x0A"
```
---
### `charDecode(s)`
反向解码由 `charEncode` 编码的字符串。
**参数:**
- `s` (str): 已编码字符串
**逻辑:**
1. 按照 `convert_pairs` 的逆序还原特殊字符
2.`\\\\` 还原为 `\`
**示例:**
```python
charDecode("hello\\x3Aworld\\x0A")
# 输出: "hello:world\n"
```
---
### `getTextDictFromLines(lines)`
从文本行列表中解析出语言键值对字典。
**参数:**
- `lines` (list of str): 文件内容的每一行
**处理规则:**
- 忽略空行和以 `#` 开头的注释行
- 使用正则匹配 `key : value` 结构
- 对 key 和 value 分别调用 `charDecode` 解码
**返回:**
- dict: `{原始消息: 翻译文本}`
---
### `getFirstLang(lang)`
从浏览器或系统传入的逗号分隔语言优先级列表中提取首选语言。
**参数:**
- `lang` (str): 如 `"zh-CN,zh;q=0.9,en-US;q=0.8"`
**返回:**
- str: 第一个语言代码(如 `"zh-CN"`
---
## 核心类:`MiniI18N`
使用 `@SingletonDecorator` 实现单例模式,确保全局唯一实例。
### 类定义
```python
@SingletonDecorator
class MiniI18N:
```
---
### 构造函数 `__init__(path, lang=None, coding='utf8')`
初始化 i18n 引擎。
**参数:**
- `path` (str): 应用根路径,语言资源位于 `{path}/i18n/`
- `lang` (str, optional): 默认语言(可选)
- `coding` (str): 文件编码,默认 `'utf8'`
**初始化行为:**
- 获取系统默认语言 `locale.getdefaultlocale()[0]`
- 初始化内部字典:
- `langTextDict`: 存储各语言的翻译字典
- `messages`: 所有出现过的原始消息集合
- `clientLangs`: 线程级别的语言上下文(含时间戳)
- 加载语言映射配置(来自 `getConfig().langMapping`
- 调用 `setupMiniI18N()` 加载所有语言文件
---
### 方法列表
#### `setLangMapping(lang, path)`
设置语言别名映射,例如将 `"zh"` 映射到 `"zh_CN"`
**用途:** 支持语言标签标准化。
```python
i18n.setLangMapping('zh', 'zh_CN')
```
#### `getLangMapping(lang)`
获取实际使用的语言目录名。若无映射,则返回原语言名。
#### `setTimeout(timeout=600)`
设置客户端语言上下文的有效期(单位:秒)。超时后自动清理过期记录。
#### `delClientLangs()`
清理 `clientLangs` 中超过 `timeout` 时间未访问的线程语言设置。
> 自动在 `getCurrentLang` 和 `setCurrentLang` 中触发。
#### `getLangDict(lang)`
获取指定语言的完整翻译字典。
会先通过 `getLangMapping` 解析真实语言名称。
#### `getLangText(msg, lang=None)`
根据当前或指定语言查找翻译文本。
- 若未找到对应翻译,返回原始 `msg`
- 支持 bytes 输入自动解码
#### `setupMiniI18N()`
扫描 `{self.path}/i18n/` 目录下所有子目录(视为语言目录),读取其中的 `msg.txt` 文件并构建翻译字典。
**结构要求:**
```
<i18n_root>/
└── en_US/
└── msg.txt
└── zh_CN/
└── msg.txt
```
每条记录格式:
```
hello world : Hello, World!
greeting : Welcome to our app.
# 这是注释
error_open : Failed to open file: %s
```
#### `setCurrentLang(lang)`
为当前线程设置语言环境,并记录时间戳。
**注意:** 基于线程 ID 存储,支持多线程独立语言上下文。
#### `getCurrentLang()`
获取当前线程的语言设置。若未设置,则抛出异常(需确保已调用 `setCurrentLang`)。
---
## 辅助函数
### `getI18N(path=None, coding='utf8')`
获取 `MiniI18N` 单例实例的便捷入口。
**参数:**
- `path`: 项目根路径(默认为 `ProgramPath()`
- `coding`: 文件编码
**返回:**
- `MiniI18N` 实例
**示例:**
```python
i18n = getI18N()
print(i18n("hello world")) # 根据当前线程语言输出翻译
```
---
## 使用示例
### 1. 准备语言文件
创建 `./i18n/en_US/msg.txt`
```
hello : Hello, World!
greeting : Welcome!
```
创建 `./i18n/zh_CN/msg.txt`
```
hello : 你好,世界!
greeting : 欢迎!
```
### 2. 在代码中使用
```python
from your_module import getI18N
i18n = getI18N()
# 设置当前线程语言
i18n.setCurrentLang('zh_CN')
# 获取翻译
print(i18n('hello')) # 输出: 你好,世界!
print(i18n('greeting')) # 输出: 欢迎!
# 切换语言
i18n.setCurrentLang('en_US')
print(i18n('hello')) # 输出: Hello, World!
```
---
## 高级特性
### 语言映射配置via JSON Config
`config.json` 中添加:
```json
{
"langMapping": {
"zh": "zh_CN",
"en": "en_US"
}
}
```
这样即使请求 `zh`,也会自动加载 `zh_CN` 的翻译文件。
### 线程安全设计
- 每个线程可通过 `setCurrentLang/lang` 独立设置语言
- 使用 `threading.currentThread()` 作为键存储上下文
- 定期清理过期线程状态(防止内存泄漏)
---
## 注意事项
1. **文件编码必须一致**,默认为 UTF-8。
2. 键名中不能包含未转义的 `:``\n``\r` 等特殊字符(应使用编码形式)。
3. 推荐使用英文原始消息作为 key便于维护。
4. `msg.txt` 文件建议按功能模块分类组织。
---
## TODO / 扩展建议
- 支持 `.po``.yaml` 格式导入
- 提供运行时动态添加翻译接口
- 添加缺失翻译日志记录机制(`missed_pt` 可扩展)
- Web 场景下结合 Cookie 或 Header 自动识别语言
---
```
> ✅ **版本信息**
> 作者AutoDoc Generator
> 生成时间2025-04-05
> 模块版本v1.0(基于所提供代码分析)