336 lines
7.3 KiB
Markdown
336 lines
7.3 KiB
Markdown
# `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(基于所提供代码分析) |