Compare commits
186 Commits
screenshot
...
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 |
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.
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
1624
l10n/cs/LC_MESSAGES/messages.po
Normal file
1624
l10n/cs/LC_MESSAGES/messages.po
Normal file
File diff suppressed because it is too large
Load Diff
1624
l10n/de/LC_MESSAGES/messages.po
Normal file
1624
l10n/de/LC_MESSAGES/messages.po
Normal file
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
1637
l10n/fr/LC_MESSAGES/messages.po
Normal file
1637
l10n/fr/LC_MESSAGES/messages.po
Normal file
File diff suppressed because it is too large
Load Diff
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
1629
l10n/it/LC_MESSAGES/messages.po
Normal file
1629
l10n/it/LC_MESSAGES/messages.po
Normal file
File diff suppressed because it is too large
Load Diff
1603
l10n/ja/LC_MESSAGES/messages.po
Normal file
1603
l10n/ja/LC_MESSAGES/messages.po
Normal file
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
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
1617
l10n/no/LC_MESSAGES/messages.po
Normal file
1617
l10n/no/LC_MESSAGES/messages.po
Normal file
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
1635
l10n/pt_BR/LC_MESSAGES/messages.po
Normal file
1635
l10n/pt_BR/LC_MESSAGES/messages.po
Normal file
File diff suppressed because it is too large
Load Diff
1626
l10n/ru/LC_MESSAGES/messages.po
Normal file
1626
l10n/ru/LC_MESSAGES/messages.po
Normal file
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
1616
l10n/tr/LC_MESSAGES/messages.po
Normal file
1616
l10n/tr/LC_MESSAGES/messages.po
Normal file
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