215 lines
6.5 KiB
Python
215 lines
6.5 KiB
Python
#!/usr/bin/env python3
|
||
# -*- coding: utf-8 -*-
|
||
"""测试 i18n po 文件中是否有重复的 msgid
|
||
|
||
注意:此测试独立于 conftest.py,可以单独运行
|
||
使用方法:python tests/test_i18n_duplicates.py
|
||
"""
|
||
|
||
import re
|
||
import sys
|
||
from pathlib import Path
|
||
from collections import Counter
|
||
|
||
try:
|
||
import pytest
|
||
PYTEST_AVAILABLE = True
|
||
except ImportError:
|
||
PYTEST_AVAILABLE = False
|
||
|
||
|
||
import polib
|
||
|
||
def extract_msgids(filepath: Path) -> list[str]:
|
||
"""从 po 文件中提取所有 msgid"""
|
||
if not filepath.exists():
|
||
return []
|
||
|
||
try:
|
||
po = polib.pofile(str(filepath))
|
||
return [entry.msgid for entry in po]
|
||
except Exception as e:
|
||
print(f"Warning: Could not read {filepath} with polib: {e}")
|
||
# Fallback to regex
|
||
with open(filepath, 'r', encoding='utf-8') as f:
|
||
content = f.read()
|
||
pattern = r'msgid\s+"([^"]*)"'
|
||
matches = re.findall(pattern, content)
|
||
return [m for m in matches if m]
|
||
|
||
|
||
def find_duplicates(msgids: list[str]) -> dict[str, int]:
|
||
"""找出重复的 msgid"""
|
||
counter = Counter(msgids)
|
||
duplicates = {msgid: count for msgid, count in counter.items() if count > 1}
|
||
return duplicates
|
||
|
||
|
||
def get_po_file_path(lang: str) -> Path:
|
||
"""获取指定语言的 po 文件路径"""
|
||
project_root = Path(__file__).parent.parent
|
||
# Ensure hyphen is used for folder name (zh_CN -> zh-CN)
|
||
lang_folder = lang.replace('_', '-')
|
||
po_file = project_root / "static" / "locales" / lang_folder / "LC_MESSAGES" / "messages.po"
|
||
return po_file
|
||
|
||
|
||
def test_zh_cn_no_duplicates():
|
||
"""测试中文 po 文件没有重复的 msgid"""
|
||
po_file = get_po_file_path("zh_CN")
|
||
|
||
if not po_file.exists():
|
||
msg = f"中文 po 文件不存在: {po_file}"
|
||
if PYTEST_AVAILABLE:
|
||
pytest.skip(msg)
|
||
else:
|
||
print(f"[FAIL] {msg}")
|
||
return False
|
||
|
||
msgids = extract_msgids(po_file)
|
||
duplicates = find_duplicates(msgids)
|
||
|
||
if duplicates:
|
||
msg = f"中文 po 文件中发现 {len(duplicates)} 个重复的 msgid:\n"
|
||
for msgid, count in sorted(duplicates.items()):
|
||
msg += f" - '{msgid}' 出现了 {count} 次\n"
|
||
|
||
if PYTEST_AVAILABLE:
|
||
pytest.fail(msg)
|
||
else:
|
||
print(f"[FAIL] {msg}")
|
||
return False
|
||
|
||
print(f"[PASS] 中文 po 文件没有重复的 msgid (共 {len(msgids)} 个)")
|
||
if not PYTEST_AVAILABLE:
|
||
return True
|
||
|
||
|
||
def test_en_us_no_duplicates():
|
||
"""测试英文 po 文件没有重复的 msgid"""
|
||
po_file = get_po_file_path("en_US")
|
||
|
||
if not po_file.exists():
|
||
msg = f"英文 po 文件不存在: {po_file}"
|
||
if PYTEST_AVAILABLE:
|
||
pytest.skip(msg)
|
||
else:
|
||
print(f"[FAIL] {msg}")
|
||
return False
|
||
|
||
msgids = extract_msgids(po_file)
|
||
duplicates = find_duplicates(msgids)
|
||
|
||
if duplicates:
|
||
msg = f"英文 po 文件中发现 {len(duplicates)} 个重复的 msgid:\n"
|
||
for msgid, count in sorted(duplicates.items()):
|
||
msg += f" - '{msgid}' 出现了 {count} 次\n"
|
||
|
||
if PYTEST_AVAILABLE:
|
||
pytest.fail(msg)
|
||
else:
|
||
print(f"[FAIL] {msg}")
|
||
return False
|
||
|
||
print(f"[PASS] 英文 po 文件没有重复的 msgid (共 {len(msgids)} 个)")
|
||
if not PYTEST_AVAILABLE:
|
||
return True
|
||
|
||
|
||
def test_msgid_count_consistency():
|
||
"""测试中英文 po 文件的 msgid 数量一致"""
|
||
zh_file = get_po_file_path("zh_CN")
|
||
en_file = get_po_file_path("en_US")
|
||
|
||
zh_msgids = extract_msgids(zh_file)
|
||
en_msgids = extract_msgids(en_file)
|
||
|
||
if len(zh_msgids) != len(en_msgids):
|
||
msg = f"中英文 po 文件的 msgid 数量不一致: 中文 {len(zh_msgids)} 个, 英文 {len(en_msgids)} 个"
|
||
if PYTEST_AVAILABLE:
|
||
pytest.fail(msg)
|
||
else:
|
||
print(f"[FAIL] {msg}")
|
||
return False
|
||
|
||
print(f"[PASS] 中英文 po 文件的 msgid 数量一致: {len(zh_msgids)} 个")
|
||
if not PYTEST_AVAILABLE:
|
||
return True
|
||
|
||
|
||
def test_msgid_keys_match():
|
||
"""测试中英文 po 文件的 msgid 键完全匹配"""
|
||
zh_file = get_po_file_path("zh_CN")
|
||
en_file = get_po_file_path("en_US")
|
||
|
||
zh_msgids = set(extract_msgids(zh_file))
|
||
en_msgids = set(extract_msgids(en_file))
|
||
|
||
# 找出只在中文中存在的 msgid
|
||
zh_only = zh_msgids - en_msgids
|
||
# 找出只在英文中存在的 msgid
|
||
en_only = en_msgids - zh_msgids
|
||
|
||
if zh_only or en_only:
|
||
msg = "中英文 po 文件的 msgid 键不完全匹配\n"
|
||
|
||
if zh_only:
|
||
msg += f" 只在中文中存在的 msgid ({len(zh_only)} 个):\n"
|
||
for msgid in sorted(zh_only)[:3]:
|
||
msg += f" - '{msgid}'\n"
|
||
if len(zh_only) > 3:
|
||
msg += f" ... 还有 {len(zh_only) - 3} 个\n"
|
||
|
||
if en_only:
|
||
msg += f" 只在英文中存在的 msgid ({len(en_only)} 个):\n"
|
||
for msgid in sorted(en_only)[:3]:
|
||
msg += f" - '{msgid}'\n"
|
||
if len(en_only) > 3:
|
||
msg += f" ... 还有 {len(en_only) - 3} 个\n"
|
||
|
||
if PYTEST_AVAILABLE:
|
||
pytest.fail(msg)
|
||
else:
|
||
print(f"[FAIL] {msg}")
|
||
return False
|
||
|
||
print(f"[PASS] 中英文 po 文件的 msgid 键完全匹配")
|
||
if not PYTEST_AVAILABLE:
|
||
return True
|
||
|
||
|
||
def main():
|
||
"""运行所有测试"""
|
||
print("="*60)
|
||
print("i18n PO 文件重复项检查")
|
||
print("="*60)
|
||
|
||
tests = [
|
||
("检查中文 po 文件没有重复", test_zh_cn_no_duplicates),
|
||
("检查英文 po 文件没有重复", test_en_us_no_duplicates),
|
||
("检查中英文 msgid 数量一致", test_msgid_count_consistency),
|
||
("检查中英文 msgid 键完全匹配", test_msgid_keys_match),
|
||
]
|
||
|
||
results = []
|
||
for test_name, test_func in tests:
|
||
print(f"\n{test_name}...")
|
||
passed = test_func()
|
||
# 当运行在非 pytest 环境时,True 表示通过,False 表示失败,None 表示通过(pytest 环境)
|
||
results.append(passed if passed is not None else True)
|
||
|
||
print("\n" + "="*60)
|
||
passed_count = sum(results)
|
||
total_count = len(results)
|
||
|
||
if all(results):
|
||
print(f"[OK] 所有测试通过 ({passed_count}/{total_count})")
|
||
return 0
|
||
else:
|
||
print(f"[FAIL] 部分测试失败 ({passed_count}/{total_count})")
|
||
return 1
|
||
|
||
|
||
if __name__ == "__main__":
|
||
sys.exit(main())
|