Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
94 commits
Select commit Hold shift + click to select a range
28c060d
Add scripts to allow addons from personal repos to be synchronized wi…
nvdaes Nov 24, 2025
4669430
use a json file to store addonId, and use it to filter files to get C…
nvdaes Nov 24, 2025
b188560
Try to get files just for the current add-on
nvdaes Nov 24, 2025
7092615
Add workflow to export an add-on to Crowdin (authors would need to be…
nvdaes Nov 24, 2025
e89640d
Use buildVars, not metadata.json file
nvdaes Nov 25, 2025
4c7771b
Add userAccount to buildVars, and step to get addon-id to GitHub work…
nvdaes Nov 26, 2025
c529cee
Update files after testing exporting an add-on to Crowdin, needs refi…
nvdaes Nov 26, 2025
186b755
Add python version file
nvdaes Nov 26, 2025
f1fbf8e
Improve pyproject and update precommit config after testing that chec…
nvdaes Nov 26, 2025
b867a9a
Restore rules
nvdaes Nov 27, 2025
47ed91c
Restore pyproject
nvdaes Nov 27, 2025
402002e
Improve uv project
nvdaes Nov 27, 2025
d820711
Remove files
nvdaes Nov 27, 2025
8e0f88e
Bump actions/checkout from 5 to 6 (#3)
CyrilleB79 Nov 28, 2025
9f6b3dc
Calculate hash of i18nSources
nvdaes Nov 29, 2025
4c938ec
Update workflow
nvdaes Nov 30, 2025
a303210
Update _l10n
nvdaes Nov 30, 2025
a0d02da
Upload md file
nvdaes Dec 1, 2025
a8d4252
Updates
nvdaes Dec 3, 2025
1a1e6fd
Update l10nUtil
nvdaes Dec 14, 2025
d2395b0
Update workflow
nvdaes Dec 14, 2025
e4dafe1
Update readme
nvdaes Dec 16, 2025
f76904e
Update readme.md
nvdaes Dec 16, 2025
aea5eba
Update _l10n/crowdinSync.py
nvdaes Dec 16, 2025
f7ccaf6
Add setOutput.py to separate Python code from yaml file
nvdaes Dec 16, 2025
0276e22
Remove bad comment
nvdaes Dec 16, 2025
253eb46
Reset pyproject to master
nvdaes Dec 16, 2025
c51e7ad
reset .pre-commit configuration to master
nvdaes Dec 16, 2025
00c6b31
Update precommit configuration (#4)
nvdaes Dec 16, 2025
cd4816c
Remove userAccount variable, since we use markdown, not xliff
nvdaes Dec 17, 2025
314220b
Update or add files from scratch depending on existence of hashFile
nvdaes Dec 17, 2025
f3e8b8d
Use addMd and addPotFromScratch outputs
nvdaes Dec 17, 2025
de4fa15
Update dependencies
nvdaes Dec 20, 2025
46a105a
Update setOutput
nvdaes Dec 20, 2025
053d4de
Update workflow
nvdaes Dec 20, 2025
4a3f5a0
Update lock
nvdaes Dec 20, 2025
3c1a73e
Merge branch 'master' into l10n
nvdaes Dec 21, 2025
dbe74dc
Verify uv lock
nvdaes Dec 21, 2025
e717292
Add uv to dependencies in case this is relevant to verify the lock ac…
nvdaes Dec 21, 2025
c4ed575
Remove debug statement
nvdaes Dec 21, 2025
befa647
Run pre-commit
nvdaes Dec 21, 2025
05c8161
Update dependencies
nvdaes Dec 22, 2025
9a0f62a
Deleted Pyproject to avoid conflicts
nvdaes Dec 22, 2025
4abd788
Reset pyproject to master
nvdaes Dec 22, 2025
c256364
Remove _l10n since this will be added as a submodule
nvdaes Dec 22, 2025
0505a3b
Don't run pre-commit since it requires a different token to access hooks
nvdaes Dec 22, 2025
fd2554b
Merge translations into branch
nvdaes Dec 22, 2025
b30f46f
Add project id without using vars
nvdaes Dec 22, 2025
70293c8
Schedule workflow
nvdaes Dec 22, 2025
da09c8c
Rename workflow
nvdaes Dec 22, 2025
5c52f33
Create PR
nvdaes Dec 22, 2025
d0d5e03
Don't create a PR since this nΒ‘may need a personal access token
nvdaes Dec 22, 2025
b40f94a
Update removing permissions for PR
nvdaes Dec 22, 2025
cb7807e
Update Python version compatible with ubuntu-latest
nvdaes Dec 28, 2025
1449a01
Add dry-run
nvdaes Dec 28, 2025
697d048
Optimize workflow to test with act and docker locally
nvdaes Dec 28, 2025
0273641
Update pyproject (#5)
nvdaes Dec 29, 2025
3ec67ac
Fix branch args (#9)
nvdaes Dec 30, 2025
c890dd0
fixRuffInPyProject (#8)
nvdaes Dec 30, 2025
ce86935
Fixes using pre-commit (#10)
nvdaes Dec 30, 2025
7b7b8b1
Add a note encouraging to use pre-commit.ci (#11)
nvdaes Dec 30, 2025
8c9247b
Update uv.lock
nvdaes Dec 30, 2025
a8469fb
Merge branch 'master' into l10n
nvdaes Dec 30, 2025
c6f50e9
Bump actions/download-artifact from 6 to 7 and bump actions/upload-ar…
CyrilleB79 Jan 8, 2026
a4f9291
Bump actions/download-artifact from 7 to 8 (#17)
dependabot[bot] Feb 26, 2026
20c3919
Bump actions/upload-artifact from 6 to 7 (#16)
dependabot[bot] Feb 26, 2026
945487a
Bump the uv group across 1 directory with 3 updates (#18)
dependabot[bot] Feb 26, 2026
3ac4b6f
Add-on template: add support for custom speech pronunciation dictiona…
josephsl Mar 2, 2026
bda47e6
BuildVars: add missing SpeechDictionaries import (#20)
josephsl Mar 3, 2026
3ab0021
Run workflow just when files are changed in the addon folder (#21)
nvdaes Mar 3, 2026
6093c55
Do not restrict workflow triggers to addon path (#22)
CyrilleB79 Mar 4, 2026
e0585fd
Fixes for CI workflow (#23)
CyrilleB79 Mar 17, 2026
867f183
Workflow runs produce add-on and .pot artifacts instead of a .zip (#24)
CyrilleB79 Mar 19, 2026
6089057
Add workflow call to build the add-on, so it can be reused in other w…
nvdaes Mar 25, 2026
d8154a9
Update workflow for testing
nvdaes Mar 25, 2026
eef379d
Bump requests from 2.32.5 to 2.33.0 in the uv group across 1 director…
dependabot[bot] Mar 30, 2026
b4c72dd
Bump uv from 0.9.11 to 0.11.6 in the uv group across 1 directory (#26)
dependabot[bot] Apr 16, 2026
dab00d5
Bump softprops/action-gh-release from 2 to 3 (#27)
dependabot[bot] Apr 16, 2026
e699abc
Improve workflow to download files from Crowdin
nvdaes Apr 18, 2026
5eafa64
Update setOutputs to set just add-on id to download translations
nvdaes Apr 18, 2026
0eb3223
[crowdinL10n.yml] improve CI translation workflow
abdel792 Apr 20, 2026
a195110
Remove duplicate setOutputs.py from .github/workflows
abdel792 Apr 20, 2026
9ed44a3
Merge pull request #2 from abdel792/l10nImprovements
nvdaes Apr 20, 2026
e62bd5b
Update lock
nvdaes Apr 20, 2026
37c4d4f
Merge
nvdaes Apr 20, 2026
91995bd
Try to fix pre-commit configuration
nvdaes Apr 20, 2026
0c613be
Reset gitignore to master
nvdaes Apr 20, 2026
0b65072
Require polib 1.2.0
nvdaes Apr 20, 2026
f9ba8fe
Update lock file
nvdaes Apr 20, 2026
8e514ba
Remove sha256 file
nvdaes Apr 20, 2026
9c64247
Remove verification of lock file in pre-commit config, not present in…
nvdaes Apr 20, 2026
7589fef
Remove Crowdin client
nvdaes Apr 20, 2026
94b1a88
Update lock file
nvdaes Apr 20, 2026
65290e4
Enhance Crowdin l10n workflow with MD quality evaluation and comparis…
abdel792 Apr 22, 2026
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
175 changes: 175 additions & 0 deletions .github/scripts/checkTranslation.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
import sys
import os
import xml.etree.ElementTree as ET
import polib
import langid

def normalize(s: str | None) -> str:
return " ".join((s or "").strip().lower().split())

# -----------------------------
# PO CHECK
# -----------------------------

def checkPo(path: str) -> float:
po = polib.pofile(path)
translated = 0
total = 0

for entry in po:
if not entry.msgid.strip():
continue

total += 1

if entry.msgstr and normalize(entry.msgstr) != normalize(entry.msgid):
translated += 1

return translated / total if total else 0.0

# -----------------------------
# XLIFF CHECK
# -----------------------------

def checkXliff(path: str) -> float:
tree = ET.parse(path)
root = tree.getroot()
translated = 0
total = 0
source = None

for elem in root.iter():
if elem.tag.endswith("source"):
source = normalize(elem.text)

elif elem.tag.endswith("target"):
target = normalize(elem.text)

if source:
total += 1
if target and target != source:
translated += 1

return translated / total if total else 0.0

# -----------------------------
# MD LANGUAGE SCORE (langid)
# -----------------------------

def scoreMd(path: str, expected_lang: str) -> float:
try:
with open(path, "r", encoding="utf-8") as f:
text = f.read()
except Exception:
return 0.0

if not text.strip():
return 0.0

lang, score = langid.classify(text)

# Normalize score into positive confidence
confidence = 1 / (1 + abs(score))

if lang == expected_lang:
return confidence
else:
return 0.0

# -----------------------------
# COMPARE MULTIPLE MD FILES
# -----------------------------

def compareMd(files: list[str], lang: str):
results = []

for f in files:
if not os.path.exists(f):
continue

score = scoreMd(f, lang)
results.append((f, score))

if not results:
print("winner=None")
sys.exit(1)

results.sort(key=lambda x: x[1], reverse=True)

winner = results[0]

print("comparison_results:")
for f, s in results:
print(f"{f}={s}")

print(f"winner={winner[0]}")
print(f"winner_score={winner[1]}")

sys.exit(0)

# -----------------------------
# MAIN
# -----------------------------

def main():
if len(sys.argv) < 2:
print("Usage:")
print(" checkTranslation.py <file>")
print(" checkTranslation.py <file> <lang>")
print(" checkTranslation.py <file1> <file2> [...] <lang>")
sys.exit(2)

args = sys.argv[1:]

# -------------------------
# MULTI FILE MODE
# -------------------------
if len(args) >= 3:
*files, lang = args
compareMd(files, lang)
return

path = args[0]

if not os.path.exists(path):
print(f"File not found: {path}")
sys.exit(2)

ext = os.path.splitext(path)[1].lower()

# -------------------------
# PO
# -------------------------
if ext == ".po":
ratio = checkPo(path)
print(f"translation_ratio={ratio}")
sys.exit(0 if ratio > 0.05 else 1)

# -------------------------
# XLIFF
# -------------------------
elif ext in [".xliff", ".xlf"]:
ratio = checkXliff(path)
print(f"translation_ratio={ratio}")
sys.exit(0 if ratio > 0.05 else 1)

# -------------------------
# MD (LANG SCORE)
# -------------------------
elif ext == ".md":
if len(args) < 2:
print("Missing language argument for MD scoring")
sys.exit(2)

lang = args[1]
score = scoreMd(path, lang)

print(f"md_score={score}")
sys.exit(0)

else:
print(f"Unsupported file type: {ext}")
sys.exit(2)

if __name__ == "__main__":
main()
21 changes: 21 additions & 0 deletions .github/scripts/setOutputs.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Copyright (C) 2025 NV Access Limited, Noelia Ruiz MartΓ­nez
# This file is covered by the GNU General Public License.
# See the file COPYING for more details.

import os
import sys

sys.path.insert(0, os.getcwd())
import buildVars


def main():
addonId = buildVars.addon_info["addon_name"]
name = "addonId"
value = addonId
with open(os.environ["GITHUB_OUTPUT"], "a") as f:
_ = f.write(f"{name}={value}\n")


if __name__ == "__main__":
main()
45 changes: 27 additions & 18 deletions .github/workflows/build_addon.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,42 +10,48 @@ on:
branches: [ main, master ]

workflow_dispatch:
workflow_call:

jobs:
build:
# Building the add-on template as an add-on does not make sense (and fails).
# Do not modify this repo name with your own one! (should remain the template)
if: github.repository != 'nvaccess/addonTemplate'

runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v5

- run: echo -e "pre-commit\nscons\nmarkdown">requirements.txt

- name: Set up Python
uses: actions/setup-python@v6
- name: Checkout repo
uses: actions/checkout@v6
- name: Install uv
uses: astral-sh/setup-uv@v7
with:
python-version: 3.11
cache: 'pip'

enable-cache: true
- name: Install dependencies
run: |
python -m pip install --upgrade pip wheel
pip install -r requirements.txt
sudo apt-get update -y
sudo apt-get install -y gettext
uv sync

- name: Code checks
run: export SKIP=no-commit-to-branch; pre-commit run --all
run: export SKIP=no-commit-to-branch; uv run pre-commit run --all-files

- name: building addon
run: scons && scons pot
run: uv run scons && uv run scons pot

- uses: actions/upload-artifact@v5
- uses: actions/upload-artifact@v7
with:
name: packaged_addon
path: |
./*.nvda-addon
archive: false

- uses: actions/upload-artifact@v7
with:
name: translation_template
path: |
./*.pot
archive: false

upload_release:
runs-on: ubuntu-latest
Expand All @@ -54,9 +60,12 @@ jobs:
permissions:
contents: write
steps:
- uses: actions/checkout@v5
- name: download releases files
uses: actions/download-artifact@v6
- uses: actions/checkout@v6
- name: download all artifacts
uses: actions/download-artifact@v8
with:
path: .
merge-multiple: true
- name: Display structure of downloaded files
run: ls -R
- name: Calculate sha256
Expand All @@ -65,7 +74,7 @@ jobs:
sha256sum *.nvda-addon >> changelog.md

- name: Release
uses: softprops/action-gh-release@v2
uses: softprops/action-gh-release@v3
with:
files: |
*.nvda-addon
Expand Down
Loading
Loading