Compare commits
190 Commits
initial_nl
...
dev
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
708961a416 | ||
|
|
e7ff6b560d | ||
|
|
7913942dc7 | ||
|
|
1813230fcb | ||
|
|
0693542537 | ||
|
|
2e8620c426 | ||
|
|
3aa3638d12 | ||
|
|
9a76a81275 | ||
|
|
b12327a214 | ||
|
|
6051acc495 | ||
|
|
8f3838e383 | ||
|
|
7e802d8a87 | ||
|
|
8875f3e879 | ||
|
|
9cd9fb3d32 | ||
|
|
ca5cf1b9a0 | ||
|
|
bf20905ccc | ||
|
|
e2e3a2298d | ||
|
|
6b6b754c41 | ||
|
|
8549f2c2ea | ||
|
|
f3e8e92096 | ||
|
|
0818bda20e | ||
|
|
f2c8414cd6 | ||
|
|
3251f9a30f | ||
|
|
55abc7fbc9 | ||
|
|
bf297d6bfb | ||
|
|
7ee18625e6 | ||
|
|
9d16de8e47 | ||
|
|
5fd98b2b3b | ||
|
|
74b0a329e8 | ||
|
|
d3e89766a5 | ||
|
|
985747be9d | ||
|
|
2083a7a519 | ||
|
|
1dff6e0730 | ||
|
|
3616fb5c9c | ||
|
|
a32d3fc148 | ||
|
|
057b541977 | ||
|
|
cdeb7008de | ||
|
|
593af36a3f | ||
|
|
c3ceb30de8 | ||
|
|
02f5e26176 | ||
|
|
1e416a4dec | ||
|
|
6c23108965 | ||
|
|
225064752e | ||
|
|
4206206c0b | ||
|
|
7da06bd0ff | ||
|
|
4288f982b0 | ||
|
|
b313ad5c75 | ||
|
|
9547f0fc12 | ||
|
|
6921630722 | ||
|
|
26e8570caf | ||
|
|
4d72df34d3 | ||
|
|
64fc314980 | ||
|
|
f4372a8134 | ||
|
|
8710e418cd | ||
|
|
6084a57bb7 | ||
|
|
7d61ae2aee | ||
|
|
9b68dfba1c | ||
|
|
ccd382b4e6 | ||
|
|
e3f0627111 | ||
|
|
70431d99be | ||
|
|
8054fc04a5 | ||
|
|
76c6f57dee | ||
|
|
b147b595f3 | ||
|
|
3efc554b89 | ||
|
|
5e52b505ca | ||
|
|
6b911be2da | ||
|
|
0335db88de | ||
|
|
dd414b89eb | ||
|
|
cbb699f6a5 | ||
|
|
79813f5a2f | ||
|
|
70c1873cb1 | ||
|
|
8b084d58f5 | ||
|
|
687977994b | ||
|
|
ba422307f7 | ||
|
|
2308a0fc0e | ||
|
|
c25e30b4e3 | ||
|
|
71250f071e | ||
|
|
b9321db488 | ||
|
|
1afe546b73 | ||
|
|
7ba7453348 | ||
|
|
7a3c4e4ed1 | ||
|
|
55add6578c | ||
|
|
a779c2292c | ||
|
|
2c4a2968fa | ||
|
|
d6371ca135 | ||
|
|
bbf5492124 | ||
|
|
006aa7d298 | ||
|
|
9b7db49302 | ||
|
|
1041014190 | ||
|
|
8a7c563efb | ||
|
|
a7817f156f | ||
|
|
6a5a01219b | ||
|
|
c5e45a65f0 | ||
|
|
ff379aa8d6 | ||
|
|
b0ab97d7b1 | ||
|
|
bec3422644 | ||
|
|
b7750bb4a9 | ||
|
|
984a2d156f | ||
|
|
620377da61 | ||
|
|
f403437ec0 | ||
|
|
ee823c87a4 | ||
|
|
9fefac9069 | ||
|
|
7177490bff | ||
|
|
12d4c5df51 | ||
|
|
c4eec19803 | ||
|
|
0b810c1464 | ||
|
|
3fec2386b2 | ||
|
|
7853d300c3 | ||
|
|
5e88830ae9 | ||
|
|
909dfde0fc | ||
|
|
77d8218b5a | ||
|
|
96890360ad | ||
|
|
1d31ff4c9b | ||
|
|
284f10b39c | ||
|
|
ad90db179e | ||
|
|
ee3499ddae | ||
|
|
e461aa422b | ||
|
|
736b336f58 | ||
|
|
9310f8c455 | ||
|
|
063ef858b1 | ||
|
|
97c4cd6cf5 | ||
|
|
3f5939712a | ||
|
|
2ebd15ef8e | ||
|
|
a7b6b4f314 | ||
|
|
735b23ae0a | ||
|
|
43bcd25b86 | ||
|
|
2e6f4aef53 | ||
|
|
f0880a1423 | ||
|
|
50d681a9e0 | ||
|
|
1ba15e63f1 | ||
|
|
9f528ae075 | ||
|
|
9cc3406aef | ||
|
|
9aa4a2141e | ||
|
|
d00357c621 | ||
|
|
f4fe29f4a7 | ||
|
|
4566badbfe | ||
|
|
845a735bc2 | ||
|
|
d50cd0c360 | ||
|
|
d22d9e60f5 | ||
|
|
bd92bccd40 | ||
|
|
b47b12f857 | ||
|
|
26286c6ff5 | ||
|
|
56ace6127a | ||
|
|
8fb35c22cf | ||
|
|
2e57d5e8fe | ||
|
|
17dbeee789 | ||
|
|
d54b994c98 | ||
|
|
3976ab3ec1 | ||
|
|
f9d5e26bfd | ||
|
|
924d63089c | ||
|
|
3a2d7615ff | ||
|
|
e2326764e0 | ||
|
|
d77132d947 | ||
|
|
56415be656 | ||
|
|
7958c4f75e | ||
|
|
b49dfdb0fd | ||
|
|
a5b750d69f | ||
|
|
a034d83c23 | ||
|
|
bc28e27243 | ||
|
|
ce21b8fb17 | ||
|
|
3af63cca93 | ||
|
|
5b9806be4b | ||
|
|
84311aefa2 | ||
|
|
786bdc09de | ||
|
|
a64af2645f | ||
|
|
dc569a09a8 | ||
|
|
b9ec6dbfa7 | ||
|
|
0e43c4fac7 | ||
|
|
7b5605e922 | ||
|
|
2c66d4f022 | ||
|
|
5f4cbc16e7 | ||
|
|
fbbf956c45 | ||
|
|
3461b11596 | ||
|
|
957ef69d3a | ||
|
|
10ee02ae23 | ||
|
|
feebe3b44c | ||
|
|
cb874aa179 | ||
|
|
265f4e3871 | ||
|
|
a8b7270ba7 | ||
|
|
281a3dab83 | ||
|
|
e45c24e0a8 | ||
|
|
112fc9e9d2 | ||
|
|
0212580a18 | ||
|
|
0f6602af39 | ||
|
|
05e7dddd38 | ||
|
|
bdeb1692c8 | ||
|
|
2ef2f2811d | ||
|
|
597e03dafb | ||
|
|
23e8ff42f5 | ||
|
|
999e51e700 |
138
.github/diff_report/diff_screenshots.py
vendored
Normal file
138
.github/diff_report/diff_screenshots.py
vendored
Normal file
@ -0,0 +1,138 @@
|
||||
"""
|
||||
Utility to compare screenshots before and after a change and generate a report of the
|
||||
differences.
|
||||
|
||||
Expected usage in a GitHub Actions workflow; compare `dev` with the `$INCOMING_CHANGES_REF` in the
|
||||
associated PR or merge that triggered the CI run:
|
||||
python src/seedsigner/resources/seedsigner-translations/.github/diff_report/diff_screenshots.py ./artifacts/dev ./artifacts/incoming ./artifacts/diff $INCOMING_CHANGES_REF
|
||||
"""
|
||||
import argparse
|
||||
import glob
|
||||
import hashlib
|
||||
import os
|
||||
import pathlib
|
||||
import shutil
|
||||
|
||||
|
||||
parser = argparse.ArgumentParser(prog=__name__)
|
||||
|
||||
parser.add_argument("before_dir", type=str, help="Directory containing screenshots before the incoming changes")
|
||||
parser.add_argument("after_dir", type=str, help="Directory containing screenshots after the incoming changes")
|
||||
parser.add_argument("output_dir", type=str, help="Directory to save the screenshots diff report")
|
||||
parser.add_argument("incoming_changes_ref", type=str, help="Branch name or commit hash that contains the incoming changes")
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
# `before_dir` includes the branch name we'll be merging into
|
||||
baseline_branch = args.before_dir.split(os.path.sep)[-1]
|
||||
incoming_changes_ref = args.incoming_changes_ref
|
||||
|
||||
def list_files_recursively(path: str) -> list[str]:
|
||||
""" Return a list of paths to all png files in the directory tree """
|
||||
return glob.glob(path + "/**/*.png", recursive=True)
|
||||
|
||||
|
||||
def compute_file_hash(file_path: str) -> str:
|
||||
""" Return the file hash using sha256 """
|
||||
hash_func = hashlib.new('sha256')
|
||||
|
||||
with open(file_path, 'rb') as file:
|
||||
while chunk := file.read(8192): # Read the file in chunks of 8192 bytes
|
||||
hash_func.update(chunk)
|
||||
|
||||
return hash_func.hexdigest()
|
||||
|
||||
|
||||
def get_pathname_fragment(path:str) -> str:
|
||||
""" Extract the last 3 parts of the path:
|
||||
en/tools_views/ToolsCalcFinalWordDoneView.png
|
||||
|
||||
These paths will be the same in the "before" and "after" directories.
|
||||
"""
|
||||
parts = path.split(os.path.sep)
|
||||
if len(parts) < 3:
|
||||
raise ValueError(f"Path should have at least 3 parts: {path}")
|
||||
return os.path.sep.join(parts[-3:])
|
||||
|
||||
|
||||
def get_locale_and_screenshot_name(path: str) -> tuple[str, str]:
|
||||
""" Parse the path to extract the locale and the screenshot name.
|
||||
|
||||
Assumes we're working with a path like:
|
||||
en/tools_views/ToolsCalcFinalWordDoneView.png
|
||||
"""
|
||||
parts = path.split(os.path.sep)
|
||||
if len(parts) != 3:
|
||||
raise ValueError(f"Path should have 3 parts: {path}")
|
||||
return parts[0], parts[-1].split(".")[0]
|
||||
|
||||
|
||||
# Recursively list and hash all png files in the "before" directory
|
||||
before_screenshots = {}
|
||||
paths_before = []
|
||||
for file in list_files_recursively(args.before_dir):
|
||||
screenshot_path = get_pathname_fragment(file)
|
||||
before_screenshots[screenshot_path] = compute_file_hash(file)
|
||||
paths_before.append(screenshot_path)
|
||||
|
||||
# Do the same for the "after" directory, but do the diff while we're here
|
||||
only_in_after = []
|
||||
diffs: list[str] = []
|
||||
paths_after = []
|
||||
for file in list_files_recursively(args.after_dir):
|
||||
screenshot_path = get_pathname_fragment(file)
|
||||
if screenshot_path not in before_screenshots:
|
||||
only_in_after.append(screenshot_path)
|
||||
|
||||
elif before_screenshots[screenshot_path] != compute_file_hash(file):
|
||||
diffs.append(screenshot_path)
|
||||
|
||||
paths_after.append(screenshot_path)
|
||||
|
||||
only_in_before = set(paths_before) - set(paths_after)
|
||||
|
||||
html_content = "<h1>Screenshots diff report</h1>"
|
||||
html_content += f"""<p>Comparing {baseline_branch} to {incoming_changes_ref}</p>"""
|
||||
output_dir_before = os.path.join(args.output_dir, "before")
|
||||
output_dir_after = os.path.join(args.output_dir, "after")
|
||||
os.makedirs(output_dir_before, exist_ok=True)
|
||||
os.makedirs(output_dir_after, exist_ok=True)
|
||||
|
||||
for screenshot_path in only_in_before:
|
||||
locale, screenshot_name = get_locale_and_screenshot_name(screenshot_path)
|
||||
print(f"Screenshot only in before: {locale}: {screenshot_name}")
|
||||
os.makedirs(os.path.join(output_dir_before, os.path.dirname(screenshot_path)), exist_ok=True)
|
||||
shutil.copy(os.path.join(args.before_dir, screenshot_path), os.path.join(output_dir_before, screenshot_path))
|
||||
html_content += f"<p>{locale}: REMOVED {screenshot_name}</br><img src='{os.path.join('before', screenshot_path)}'></p></br></br>"
|
||||
|
||||
for screenshot_path in only_in_after:
|
||||
locale, screenshot_name = get_locale_and_screenshot_name(screenshot_path)
|
||||
print(f"Screenshot only in after: {locale}: {screenshot_name}")
|
||||
os.makedirs(os.path.join(output_dir_after, os.path.dirname(screenshot_path)), exist_ok=True)
|
||||
shutil.copy(os.path.join(args.after_dir, screenshot_path), os.path.join(output_dir_after, screenshot_path))
|
||||
html_content += f"<p>{locale}: ADDED {screenshot_name}</br><img src='{os.path.join('after', screenshot_path)}'></p></br></br>"
|
||||
|
||||
for screenshot_path in diffs:
|
||||
locale, screenshot_name = get_locale_and_screenshot_name(screenshot_path)
|
||||
print(f"Screenshot different: {locale}: {screenshot_name}")
|
||||
# Copy both screenshots to the output dir
|
||||
os.makedirs(os.path.join(output_dir_before, os.path.dirname(screenshot_path)), exist_ok=True)
|
||||
os.makedirs(os.path.join(output_dir_after, os.path.dirname(screenshot_path)), exist_ok=True)
|
||||
shutil.copy(os.path.join(args.before_dir, screenshot_path), os.path.join(output_dir_before, screenshot_path))
|
||||
shutil.copy(os.path.join(args.after_dir, screenshot_path), os.path.join(output_dir_after, screenshot_path))
|
||||
html_content += f"<p>{locale}: {screenshot_name}</br><img src='{os.path.join('before', screenshot_path)}'> <img src='{os.path.join('after', screenshot_path)}'></p></br></br>"
|
||||
|
||||
if not only_in_after and not only_in_before and not diffs:
|
||||
print("No differences found")
|
||||
html_content += "<h1>No differences found</h1>"
|
||||
|
||||
script_dir = pathlib.Path(__file__).parent.resolve()
|
||||
html_output = ""
|
||||
with open(os.path.join(script_dir, "index.html"), "r") as f:
|
||||
html_output = f.read().replace("{{ content }}", html_content)
|
||||
|
||||
with open(os.path.join(args.output_dir, "index.html"), "w") as f:
|
||||
f.write(html_output)
|
||||
|
||||
# Also copy the css file; source: https://github.com/picocss/pico
|
||||
shutil.copy(os.path.join(script_dir, "pico.min.css"), os.path.join(args.output_dir, "pico.min.css"))
|
||||
15
.github/diff_report/index.html
vendored
Normal file
15
.github/diff_report/index.html
vendored
Normal file
@ -0,0 +1,15 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<meta name="color-scheme" content="light dark" />
|
||||
<title>SeedSigner screenshot diffs</title>
|
||||
<link rel="stylesheet" href="pico.min.css" />
|
||||
</head>
|
||||
<body>
|
||||
<main class="container">
|
||||
{{ content }}
|
||||
</main>
|
||||
</body>
|
||||
</html>
|
||||
4
.github/diff_report/pico.min.css
vendored
Normal file
4
.github/diff_report/pico.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
91
.github/workflows/tests.yml
vendored
Normal file
91
.github/workflows/tests.yml
vendored
Normal file
@ -0,0 +1,91 @@
|
||||
name: CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- dev
|
||||
- main
|
||||
pull_request:
|
||||
|
||||
concurrency:
|
||||
# Concurrency group that uses the workflow name and PR number if available
|
||||
# or commit SHA as a fallback. If a new build is triggered under that
|
||||
# concurrency group while a previous build is running it will be canceled.
|
||||
# Repeated pushes to a PR will cancel all previous builds, while multiple
|
||||
# merges to main will not cancel.
|
||||
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.sha }}
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
# head_ref: source branch name of a PR; null when action isn't a PR.
|
||||
# sha: hash of a commit / merge.
|
||||
INCOMING_CHANGES_REF: ${{ github.head_ref || github.sha }}
|
||||
steps:
|
||||
- name: Checkout main repo 'dev'
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
repository: 'SeedSigner/seedsigner'
|
||||
ref: dev
|
||||
submodules: true
|
||||
- name: Set up Python 3.10
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: "3.10"
|
||||
- name: Install dependencies
|
||||
run: |
|
||||
sudo apt-get install libzbar0
|
||||
python -m pip install --upgrade pip
|
||||
pip install -r requirements.txt -r tests/requirements.txt -r l10n/requirements-l10n.txt
|
||||
pip install -e .
|
||||
- name: Generate current 'dev' screenshots
|
||||
run: |
|
||||
mkdir -p artifacts/dev
|
||||
python -m pytest tests/screenshot_generator/generator.py
|
||||
sleep 10
|
||||
mv ./seedsigner-screenshots/* ./artifacts/dev/
|
||||
- name: Checkout updated translations (PR)
|
||||
uses: actions/checkout@v4
|
||||
if: ${{ github.event_name == 'pull_request' }}
|
||||
with:
|
||||
path: src/seedsigner/resources/seedsigner-translations
|
||||
ref: ${{ github.event.pull_request.head.sha }}
|
||||
- name: Checkout updated translations (Push)
|
||||
uses: actions/checkout@v4
|
||||
if: ${{ github.event_name == 'push' }}
|
||||
with:
|
||||
path: src/seedsigner/resources/seedsigner-translations
|
||||
ref: ${{ github.sha }}
|
||||
- name: Compile updated translations catalogs
|
||||
run: |
|
||||
python setup.py compile_catalog
|
||||
cd src/seedsigner/resources/seedsigner-translations
|
||||
git status
|
||||
- name: Generate latest screenshots
|
||||
run: |
|
||||
rm -rf seedsigner-screenshots
|
||||
mkdir -p artifacts/incoming
|
||||
python -m pytest tests/screenshot_generator/generator.py
|
||||
sleep 10
|
||||
mv ./seedsigner-screenshots/* ./artifacts/incoming/
|
||||
- name: Diff screenshots
|
||||
run: |
|
||||
mkdir -p artifacts/diff
|
||||
python src/seedsigner/resources/seedsigner-translations/.github/diff_report/diff_screenshots.py ./artifacts/dev ./artifacts/incoming ./artifacts/diff $INCOMING_CHANGES_REF
|
||||
- name: Clean up artifacts
|
||||
run: |
|
||||
rm -rf ./artifacts/incoming
|
||||
rm -rf ./artifacts/dev
|
||||
mv ./artifacts/diff/* ./artifacts
|
||||
rmdir ./artifacts/diff
|
||||
- name: Archive CI Artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: ci-artifacts
|
||||
path: artifacts/**
|
||||
retention-days: 60
|
||||
# Upload also when tests fail. The workflow result (red/green) will
|
||||
# be not effected by this.
|
||||
if: always()
|
||||
4
.gitignore
vendored
4
.gitignore
vendored
@ -1 +1,5 @@
|
||||
.DS_Store
|
||||
|
||||
# Only check in *.po files since *.mo
|
||||
# files can be generated from from them
|
||||
*.mo
|
||||
|
||||
12
.tx/config
Normal file
12
.tx/config
Normal file
@ -0,0 +1,12 @@
|
||||
[main]
|
||||
host = https://app.transifex.com
|
||||
|
||||
[o:seedsigner:p:seedsigner:r:messagespot]
|
||||
file_filter = l10n/<lang>/LC_MESSAGES/messages.po
|
||||
source_file = ../../../../l10n/messages.pot
|
||||
type = PO
|
||||
minimum_perc = 15
|
||||
resource_name = messages.pot
|
||||
replace_edited_strings = false
|
||||
keep_translations = false
|
||||
lang_map = zh-Hans: zh_Hans_CN
|
||||
48
README.md
48
README.md
@ -1 +1,47 @@
|
||||
# SeedSigner Translations
|
||||
# SeedSigner Translations
|
||||
|
||||
## Transifex CLI
|
||||
You can pull the latest translations directly from Transifex for all translated languages.
|
||||
|
||||
You'll need to create a Transifex user if you don't already have one. Your user will also
|
||||
need some minimal role permissions within the SeedSigner Transifex project in order for
|
||||
your user's API key to have access to the translations data.
|
||||
|
||||
* Install the [Transifex CLI](https://developers.transifex.com/docs/cli).
|
||||
* [Create an API key](https://help.transifex.com/en/articles/6248858-generating-an-api-token)
|
||||
for your Transifex user.
|
||||
* From the `seedsigner/src/seedsigner/resources/seedsigner-translations` dir run:
|
||||
|
||||
```bash
|
||||
# --force, -f Force the download of the translations files regardless of whether timestamps on the local computer are newer than those on the server (default: false)
|
||||
# --all, -a Whether to download all files (default: false)
|
||||
tx pull -f --all
|
||||
```
|
||||
* We use `-f` because as we manipulate the .po files through our PR process, they may
|
||||
end up with newer timestamps even though the translation content has not changed.
|
||||
That timestamp would then mislead the `tx pull` to disregard newer translations.
|
||||
|
||||
* Then from the SeedSigner project root, compile the catalogs to process the *.po files into
|
||||
*.mo:
|
||||
|
||||
```bash
|
||||
python setup.py compile_catalog
|
||||
```
|
||||
|
||||
### Pulling translations for a specific language
|
||||
Use the `--language, -l` flag with the `--force, -f` flag:
|
||||
```bash
|
||||
# Example: Spanish ("es")
|
||||
tx pull -f -l es
|
||||
|
||||
# Or comma-separated list
|
||||
tx pull -f -l pl,no
|
||||
```
|
||||
|
||||
|
||||
### Misc notes
|
||||
The `.tx/config` is set to `minimum-perc = 15` (this means that the CLI will skip any
|
||||
language whose translation completion falls below this minimum percentage).
|
||||
|
||||
You can manually override this by adding, for example, `--minimum-perc 25` to require at
|
||||
least 25% translation completion.
|
||||
|
||||
BIN
fonts/NotoSansAR-Regular.ttf
Normal file
BIN
fonts/NotoSansAR-Regular.ttf
Normal file
Binary file not shown.
BIN
fonts/NotoSansJP-Regular.ttf
Normal file
BIN
fonts/NotoSansJP-Regular.ttf
Normal file
Binary file not shown.
BIN
fonts/NotoSansKR-Regular.ttf
Normal file
BIN
fonts/NotoSansKR-Regular.ttf
Normal file
Binary file not shown.
BIN
fonts/NotoSansSC-Regular.ttf
Normal file
BIN
fonts/NotoSansSC-Regular.ttf
Normal file
Binary file not shown.
BIN
fonts/NotoSansTH-Regular.ttf
Normal file
BIN
fonts/NotoSansTH-Regular.ttf
Normal file
Binary file not shown.
Binary file not shown.
1639
l10n/ca/LC_MESSAGES/messages.po
Normal file
1639
l10n/ca/LC_MESSAGES/messages.po
Normal file
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
1628
l10n/el/LC_MESSAGES/messages.po
Normal file
1628
l10n/el/LC_MESSAGES/messages.po
Normal file
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
1625
l10n/fa/LC_MESSAGES/messages.po
Normal file
1625
l10n/fa/LC_MESSAGES/messages.po
Normal file
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
1618
l10n/hi/LC_MESSAGES/messages.po
Normal file
1618
l10n/hi/LC_MESSAGES/messages.po
Normal file
File diff suppressed because it is too large
Load Diff
1625
l10n/id/LC_MESSAGES/messages.po
Normal file
1625
l10n/id/LC_MESSAGES/messages.po
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
1606
l10n/ko/LC_MESSAGES/messages.po
Normal file
1606
l10n/ko/LC_MESSAGES/messages.po
Normal file
File diff suppressed because it is too large
Load Diff
Binary file not shown.
1629
l10n/nl/LC_MESSAGES/messages.po
Normal file
1629
l10n/nl/LC_MESSAGES/messages.po
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
1625
l10n/pl/LC_MESSAGES/messages.po
Normal file
1625
l10n/pl/LC_MESSAGES/messages.po
Normal file
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
1645
l10n/th/LC_MESSAGES/messages.po
Normal file
1645
l10n/th/LC_MESSAGES/messages.po
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
1621
l10n/vi/LC_MESSAGES/messages.po
Normal file
1621
l10n/vi/LC_MESSAGES/messages.po
Normal file
File diff suppressed because it is too large
Load Diff
1607
l10n/zh_Hans_CN/LC_MESSAGES/messages.po
Normal file
1607
l10n/zh_Hans_CN/LC_MESSAGES/messages.po
Normal file
File diff suppressed because it is too large
Load Diff
74
tools/extract_characters_from_babel_mo.py
Normal file
74
tools/extract_characters_from_babel_mo.py
Normal file
@ -0,0 +1,74 @@
|
||||
"""
|
||||
Extracts all unique characters that appear in the translated strings for the specified
|
||||
locale.
|
||||
|
||||
This is a utility for build / dev purposes only.
|
||||
"""
|
||||
|
||||
if __name__ == "__main__":
|
||||
import argparse
|
||||
import os
|
||||
from babel.messages import mofile
|
||||
|
||||
# Define required input args and help text
|
||||
|
||||
parser = argparse.ArgumentParser(
|
||||
description="Extracts all unique characters that appear in the translated strings for the specified locale."
|
||||
)
|
||||
parser.usage = "python3 extract_characters_from_babel_mo.py <locale>"
|
||||
parser.add_argument("locale", help="Target locale (e.g. es, pt_BR, zh_Hans_CN)")
|
||||
parser.add_argument("--debug", action="store_true", help="Enable debug output")
|
||||
args = parser.parse_args()
|
||||
debug = args.debug
|
||||
|
||||
basic_chars = set((chr(c) for c in range(0x20, 0x7E + 1))) # all basic ascii chars from SPACE to "~"
|
||||
|
||||
mo_fullfilename = os.path.join(os.pardir, "l10n", args.locale, "LC_MESSAGES", "messages.mo")
|
||||
try:
|
||||
with open(mo_fullfilename, "rb") as f:
|
||||
catalog = mofile.read_mo(f)
|
||||
except FileNotFoundError:
|
||||
print(f"Could not find translations for locale \"{args.locale}\" ({mo_fullfilename})")
|
||||
exit(1)
|
||||
|
||||
id_chars = set()
|
||||
translations_chars = set()
|
||||
for msg in catalog:
|
||||
if msg.id:
|
||||
if isinstance(msg.id, list):
|
||||
# plural message
|
||||
# get chars from all plural forms
|
||||
for msgid in msg.id:
|
||||
id_chars.update(msgid)
|
||||
else:
|
||||
# singular message
|
||||
id_chars.update(msg.id)
|
||||
if msg.string:
|
||||
if isinstance(msg.string, list):
|
||||
# plural message
|
||||
# get chars from all plural forms
|
||||
for msgstring in msg.string:
|
||||
translations_chars.update(msgstring)
|
||||
else:
|
||||
# singular message
|
||||
translations_chars.update(msg.string)
|
||||
|
||||
if debug:
|
||||
# Print the difference between the chars in the ids vs the basic_chars
|
||||
print("Chars in ids but not in basic_chars:", sorted(set("".join(id_chars)) - set(basic_chars)))
|
||||
|
||||
# And show the opposite
|
||||
print("Chars in basic_chars but not in ids:", sorted(basic_chars - set("".join(id_chars))))
|
||||
|
||||
print("Chars in translations:", "".join(sorted(translations_chars)))
|
||||
|
||||
# get a unique list of chars from all translation messages and included_chars string
|
||||
chars = sorted(translations_chars.union(basic_chars))
|
||||
|
||||
# convert set to string
|
||||
chars_string = "".join(chars)
|
||||
|
||||
# remove newlines
|
||||
chars_string = chars_string.replace("\n", "").replace("\r", "")
|
||||
|
||||
print(chars_string)
|
||||
1
tools/requirements.txt
Normal file
1
tools/requirements.txt
Normal file
@ -0,0 +1 @@
|
||||
Babel
|
||||
Loading…
Reference in New Issue
Block a user