Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 35 additions & 1 deletion .github/workflows/check-code.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ on:

jobs:
check-i18n:
name: Check Translation Files
name: Check i18n translations
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
Expand All @@ -15,3 +15,37 @@ jobs:
python-version: "3.x"

- run: python3 tests/check_i18n.py

check-json:
name: Validate JSON files
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- uses: actions/setup-python@v5
with:
python-version: "3.x"

- run: python3 tests/check_json.py

check-trailing-newline:
name: Check trailing newlines
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- uses: actions/setup-python@v5
with:
python-version: "3.x"

- run: python3 tests/check_trailing_newline.py

biome-lint:
name: Biome lint
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

- uses: biomejs/setup-biome@v2

- run: biome lint src/
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,5 @@ __MACOSX/
.DS_Store
desktop.ini
Thumbs.db

tests/.biome/
78 changes: 72 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,78 @@
A Pseudo-localization Translater Demo
# Pseudo Localization Demo

一个伪本地化演示

伪本地化pseudo-localization语言环境名称为 qps-ploc, qps-plocm, qps-ploca, en-XA, en-XB),是模拟本地化过程的一种方式。而通过模拟本地化过程能够有效地调查在本地化中出现的问题如字符无法正常显示或因字符串过长而导致语段显示不完整等
伪本地化 (pseudo-localization, 语言环境名称为 qps-ploc, qps-plocm, qps-ploca, en-XA, en-XB), 是模拟本地化过程的一种方式。而通过模拟本地化过程, 能够有效地调查在本地化中出现的问题 (如字符无法正常显示, 或因字符串过长而导致语段显示不完整等)

在伪本地化过程中英文字母会被替换为来自其他语言的重音符号和字符。(例如,字母 a 可以被 αäáàāāǎǎăăåå 中的任何一个替换。),还会添加分隔符等以增加字符串长度。
举例:“Windows 照片库Windows Photo Gallery)”→“ [1iaT9][ Ẅĭпðøωś Þнôтŏ Ģάŀļєяÿ !!! !]
在伪本地化过程中, 英文字母会被替换为来自其他语言的重音符号和字符 (例如, 字母 a 可以被 αäáàāāǎǎăăåå 中的任何一个替换), 还会添加分隔符等以增加字符串长度。
举例: "Windows 照片库 (Windows Photo Gallery)"→" [1iaT9][ Ẅĭпðøωś Þнôтŏ Ģάŀļєяÿ !!! !] "

该网页演示了伪本地化的一部分即用不同的字符替换英文字母和添加分隔符。
该网页演示了伪本地化的一部分, 即用不同的字符替换英文字母和添加分隔符。

更多功能将在之后更新,感谢大家的支持!
此工具不会上传你的任何数据。

## 使用

如果想要在线预览, 请访问: https://suntrise.github.io/pseudo/

如果需要在本地使用, 且您安装了 Python 3, 可以直接执行:
~~~bash
python3 -m http.server 8000
~~~
在 `localhost:8000` 中预览页面

## 开发

### 环境准备

| 工具 | 用途 | 安装方式 |
|------|------|----------|
| Python 3 | 运行检查脚本, 或启用本地服务器 | [python.org](https://www.python.org/) |

### 进行本地化

翻译文件位于 `data/i18n.json`, 您可以简单的编辑此 JSON 文件进行进行开发。

编辑翻译后, 请运行 i18n 检查以确保翻译质量:

~~~bash
python3 tests/check_i18n.py
~~~

检查内容包括:
- 全角字符检测
- 缺失/多余的翻译键
- 空值检测
- 占位符一致性
- 首尾空白字符

### 开发功能

开发完成后, 请执行以下检查确保代码质量:

~~~bash
# i18n 翻译检查
python3 tests/check_i18n.py

# JSON 文件检查 (语法 + 重复键)
python3 tests/check_json.py

# 文件尾换行符检查
python3 tests/check_trailing_newline.py

# JavaScript 代码检查 (首次运行会自动下载 Biome)
python3 tests/check_biome.py
~~~

> **Windows 用户** 可能需要将 `python3` 替换为 `python`

### 检查说明

| 检查项 | 脚本 | 说明 |
|--------|------|------|
| i18n 翻译 | `tests/check_i18n.py` | 检查翻译完整性、占位符一致性、全角字符等 |
| JSON 验证 | `tests/check_json.py` | 检查 JSON 语法和重复键 |
| 换行符 | `tests/check_trailing_newline.py` | 检查文本文件是否以换行符结尾 |
| JS 代码 | `tests/check_biome.py` | 检查 JavaScript 代码质量 (自动下载 Biome)|

所有检查会在 Pull Request 时自动运行。
30 changes: 30 additions & 0 deletions biome.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
{
"$schema": "https://biomejs.dev/schemas/2.4.2/schema.json",
"files": {
"includes": ["src/**/*.js"]
},
"linter": {
"enabled": true,
"rules": {
"recommended": true,
"style": {
"useTemplate": "warn",
"useConst": "warn"
},
"complexity": {
"useLiteralKeys": "warn"
},
"correctness": {
"noUnusedImports": "warn",
"noUnusedVariables": "warn",
"useParseIntRadix": "warn"
},
"suspicious": {
"useIterableCallbackReturn": "warn"
}
}
},
"formatter": {
"enabled": false
}
}
2 changes: 1 addition & 1 deletion index.html
Original file line number Diff line number Diff line change
Expand Up @@ -218,4 +218,4 @@ <h1 id="app-title" class="app-title"></h1>
<script type="module" src="src/app.js"></script>
</body>

</html>
</html>
133 changes: 133 additions & 0 deletions tests/check_biome.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
#!/usr/bin/env python3
import platform
import subprocess
import sys
import os
import ssl
import urllib.request
import stat
import shutil
import time
from pathlib import Path

BIOME_VERSION = "2.4.2"
BIOME_DIR = Path(__file__).parent / ".biome"
TIMEOUT = 30
MAX_RETRIES = 3

def get_platform():
system, machine = platform.system().lower(), platform.machine().lower()
platform_map = {"darwin": "darwin", "linux": "linux", "windows": "win32"}
platform_name = platform_map.get(system)
if not platform_name:
sys.exit(f"Unsupported OS: {system}")
if platform_name == "linux":
try:
if Path("/proc/self/maps").exists():
with open("/proc/self/maps") as f:
if "musl" in f.read():
platform_name = "linux-musl"
except Exception:
pass
arch_map = {"x86_64": "x64", "amd64": "x64", "arm64": "arm64", "aarch64": "arm64"}
arch = arch_map.get(machine)
if not arch:
sys.exit(f"Unsupported architecture: {machine}")
return platform_name, arch

def find_biome():
if path := shutil.which("biome"):
return Path(path)
candidate = Path.home() / ".biome" / "bin" / "biome"
if candidate.exists() and os.access(candidate, os.X_OK):
return candidate
return None

def check_version(executable, version):
try:
result = subprocess.run(
[str(executable), "--version"],
capture_output=True, text=True, timeout=10, check=True
)
return version in result.stdout
except Exception:
return False

def download_file(url, target):
target.parent.mkdir(parents=True, exist_ok=True)
for attempt in range(MAX_RETRIES):
try:
ctx = ssl.create_default_context()
with urllib.request.urlopen(url, context=ctx, timeout=TIMEOUT) as resp:
tmp_path = target.with_suffix(target.suffix + ".tmp")
with open(tmp_path, "wb") as f:
f.write(resp.read())
tmp_path.replace(target)
return True
except urllib.error.HTTPError as e:
if e.code == 404:
return False
except Exception:
if attempt < MAX_RETRIES - 1:
time.sleep(2 ** attempt)
continue
return False

def download_biome():
platform_name, arch = get_platform()
ext = ".exe" if platform.system().lower() == "windows" else ""
suffix = "-musl" if platform_name == "linux-musl" else ""
filename = f"biome-{platform_name}-{arch}{suffix}{ext}"
url = f"https://github.com/biomejs/biome/releases/download/biome@{BIOME_VERSION}/{filename}"
target = BIOME_DIR / f"biome{ext}"
if target.exists() and check_version(target, BIOME_VERSION):
return target
if not download_file(url, target):
sys.exit(f"Failed to download: {url}")
if platform.system().lower() != "windows":
target.chmod(target.stat().st_mode | stat.S_IXUSR | stat.S_IXGRP | stat.S_IXOTH)
return target

def install_via_package_manager():
system = platform.system().lower()
if system == "darwin" and shutil.which("brew"):
subprocess.run(["brew", "install", "biome"], capture_output=True, timeout=180)
return True
if system == "windows":
for manager, cmd in [("choco", ["choco", "install", "biome", "-y"]), ("scoop", ["scoop", "install", "biome"])]:
if shutil.which(manager):
subprocess.run(cmd, capture_output=True, timeout=180)
return True
if shutil.which("curl"):
subprocess.run(
"sh -c 'curl -fsSL https://biomejs.dev/install.sh | sh'",
shell=True, capture_output=True, timeout=120
)
return True
return False

def run_lint(executable):
src_dir = Path(__file__).parent.parent / "src"
if not src_dir.exists():
return 0
result = subprocess.run([str(executable), "lint", str(src_dir)])
return result.returncode

def main():
if exe := find_biome():
if check_version(exe, BIOME_VERSION):
sys.exit(run_lint(exe))
install_via_package_manager()
if exe := find_biome():
if check_version(exe, BIOME_VERSION):
sys.exit(run_lint(exe))
exe = download_biome()
sys.exit(run_lint(exe))

if __name__ == "__main__":
try:
main()
except KeyboardInterrupt:
sys.exit(130)
except Exception as e:
sys.exit(2)
Loading