Skip to content

Add scripts to allow addons from personal repos to be synchronized with Crowdin#1

Draft
nvdaes wants to merge 103 commits intonvaccess:masterfrom
nvdaes:l10n
Draft

Add scripts to allow addons from personal repos to be synchronized with Crowdin#1
nvdaes wants to merge 103 commits intonvaccess:masterfrom
nvdaes:l10n

Conversation

@nvdaes
Copy link
Copy Markdown

@nvdaes nvdaes commented Nov 24, 2025

Blocked by #7

Comment thread pyproject.toml
strictSetInference = true

# Compliant rules
reportAbstractUsage = true
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it's probably better to keep these rules than dropping to NVDA's standard

@nvdaes
Copy link
Copy Markdown
Author

nvdaes commented Nov 28, 2025

Purpose

Add-on authors may wish to help translators use Crowdin, the same framework where they translate NVDA. to translate messages and documentation for maintained add-ons:

Other details

  • Pot file are created/updated, and uploaded to a Crowdin project.
  • The readme.md file is converted to xliff and uploaded to a Crowdin project.
  • Po and xfiles are translated.
  • Translated files are downloaded and processed to be copied to locale/langCode/LC_MESSAGES/nvda.po, and doc/langCode/readme.md, in the addon folder.
    Authors need to store a Crowdin token with permissions to upload files to the Crowdin project as a repository secret.

Development approach

Use the Crowdin registration repo to add scripts usable by individual add-ons in personal repos.

@nvdaes
Copy link
Copy Markdown
Author

nvdaes commented Nov 28, 2025

I've tested that all check pass using this pyproject.toml file on this PR:

nvdaes/translateNvdaAddonsWithCrowdin#11

I use precommit, CodeQL and a workflow to check that all translatable messages have comments for translators.

I'll try to use the cache action to cache some add-on metadata like its id, and also hashfiles from l10nSources (taking the value of buildVars.py), and the hasf¡hfile of the readme.md, to determine if pot and xliff files should be updated.

@nvdaes
Copy link
Copy Markdown
Author

nvdaes commented Nov 30, 2025

Export translations to Crowdin running the workflow with update=False works properly:

https://github.com/nvdaes/translateNvdaAddonsWithCrowdin/actions/runs/19802210157

@nvdaes
Copy link
Copy Markdown
Author

nvdaes commented Nov 30, 2025

This time, updatexLiff is failing. Seems that adding blank lines to readme may cause problems:

https://github.com/nvdaes/translateNvdaAddonsWithCrowdin/actions/runs/19802391926/job/56731562709

@nvdaes
Copy link
Copy Markdown
Author

nvdaes commented Nov 30, 2025

If someone can help with this issue when update xliff, I'll be grateful.
I think that this is one of the bugest problems with xliff files. Sometimes sel lines are None and they don't have a strip method. I don't know if this should be also improved in NVDA
cc: @seanbudd

@seanbudd
Copy link
Copy Markdown
Member

seanbudd commented Dec 1, 2025

It might be easier to avoid xliff and just translate the markdown files directly. This won't support diffs very well but worth experimenting with

@nvdaes
Copy link
Copy Markdown
Author

nvdaes commented Dec 1, 2025

@seanbudd wrote:

It might be easier to avoid xliff and just translate the markdown files directly. This won't support diffs very well but worth experimenting with

OK.

@nvdaes
Copy link
Copy Markdown
Author

nvdaes commented Dec 3, 2025

@CyrilleB79, you were interested in this framework. If you want, feel free to see how the translateNvdaAddonsWithCrowdin.md can be translated in the project. Using xliff files is causing problems, as mentioned, and we are experimenting uploading md files instead.

@abdel792
Copy link
Copy Markdown

Hi @nvdaes,

Ah, sorry — I didn’t answer your question earlier.

I took a look at your implementation in .github/scripts/crowdinSync.ps1, and I think you did a really great job.

The recent PR I submitted keeps all your previous additions intact.

Your idea is very good, @nvdaes — I hope it will be approved.

As for my PR, it mainly builds on your approach while adding the comparison logic between MD and XLIFF via the Crowdin API.

Regarding my latest PR, of course, you’re not obligated to merge it — it’s entirely up to you.

My idea was simply to offer more flexibility in the process of updating translations from Crowdin.

@nvdaes
Copy link
Copy Markdown
Author

nvdaes commented Apr 26, 2026

@abdel792, I have fixed the script and this works well, as shown in

https://github.com/nvdaes/readFeeds/actions/runs/24959977513/job/73084835945

But I think that this may be improved:

  1. Can we remove the lang short variable and use just lang codes? readFeeds.md cannot be uploaded to Crowdin with "es" language, since "es" doesn't exist. The language is "es-ES". Or perhaps this can be changed in Crowdin for some languages.
  2. I have excluded pyright checks for checkTranslation.py. It contains errors, like the markdownTranslate.py file.
    I'll wait for your feedback.

@wmhn1872265132
Copy link
Copy Markdown

I think we can only keep one of XLIFF and Markdown. If we keep both, there will be two 'XXX documentation' files on Crowdin, which will confuse translators about which file to actually translate. Therefore, I prefer to keep XLIFF and delete the Markdown file.
Additionally, I found a file named /.xliff documentation on Crowdin, which might have been generated due to a code error.

@nvdaes
Copy link
Copy Markdown
Author

nvdaes commented Apr 27, 2026

I think we can only keep one of XLIFF and Markdown.

I think that translators can remove what they don't need, but I think that markdown files are needed in many cases. Especially, since they are old add-ons translated in markdown. Before we didn't use xliff. Then, translators may prefer to add small pieces to translate documentation when the addonId.md is updated. I tried to convert translated markdown for some add-ons to xliff without success, since the translated markdown don't fit the xliff file. For example, in cursorLocator and readFeeds add-on, I tried to test without success.
about the .xliff documentation, I fixed the error which probably produced it.

@seanbudd
Copy link
Copy Markdown
Member

I tend to agree that we only should support xliff, markdown doesn't work properly in Crowdin. Even if migration can't be done automatically, there is no point trying to support markdown.

@wmhn1872265132
Copy link
Copy Markdown

Sorry, I might not have expressed myself clearly. What I meant was deleting the md files in Crowdin without uploading the local md files to Crowdin. Of course, for md files that already exist locally and whose xliff translations are not yet complete, they need to be kept.

@nvdaes
Copy link
Copy Markdown
Author

nvdaes commented Apr 27, 2026

@abdel792 , for languages, perhaps we can also use the API. You can see

tag/Projects/operation/api.projects.getGet Project

This can be found here:

https://support.crowdin.com/developer/api/v2/#tag/Projects/operation/api.projects.post

For spanish, the locale is es-ES. See response samples.

@nvdaes
Copy link
Copy Markdown
Author

nvdaes commented Apr 27, 2026

OK, if you don't want to support markdown, perhaps an issue may be opened to make easy the migration. From my side, I'm not able to deal with readFeeds add-on in Spanish. My add-ons are quite stable, and I don't think that the documentation needs updates, since the changelog is managed in po files. But other add-ons may need it.

@seanbudd
Copy link
Copy Markdown
Member

If we have an easy way of maintaining them, it's fine to keep, I'm just not sure if it is possible

@nvdaes
Copy link
Copy Markdown
Author

nvdaes commented Apr 27, 2026

Sean wrote:

If we have an easy way of maintaining them, it's fine to keep, I'm just not sure if it is possible

Not sure. If you want, we can fix the problem with locales, and I think that this is ready for review adjusting the readme. Also, I think that we can remove the request dependency. I think it was used in NVDA for an old Python file using requests instead of the Crowdin API client.

@seanbudd
Copy link
Copy Markdown
Member

sure, feel free to mark as ready when it is.

@wmhn1872265132
Copy link
Copy Markdown

From my side, I'm not able to deal with readFeeds add-on in Spanish. My add-ons are quite stable, and I don't think that the documentation needs updates, since the changelog is managed in po files.

I checked readFeeds-main\addon\doc\es\readme.md. The structure of this file is very different from the English documentation. To convert it to xliff, you must ensure that the structure of this file is completely consistent with the English version.

@nvdaes
Copy link
Copy Markdown
Author

nvdaes commented Apr 27, 2026

I had another idea. In the translateNvdaAddonsWithCrowdin, I included a dictionary with language mappings. Instead of consuming API requests, we can try to use that mapping. I'll try to go how it goes, @abdel792 and others. Let's seel.

@nvdaes
Copy link
Copy Markdown
Author

nvdaes commented Apr 27, 2026

Seems that we still have issues with Spanish. Also, @abdel792, why aren't po files uploaded if they are translated just locally?

You can see this workflow:

https://github.com/nvdaes/readFeeds/actions/runs/25008567730/job/73237940567

Also, I don't know the best way of decide if source files should be uploaded. Now they are always uploaded even if markdown or Gettext messages haven't been added. I don't think that this has bad effects, but perhaps this may be improved.

@abdel792
Copy link
Copy Markdown

Hi @nvdaes,

To address the issues regarding language codes (like es-ES vs es) and the upload of local .po files, I’ve refined the logic and I am attaching the updated files to this comment.

This implementation uses your idea of a mapping dictionary, but I've moved it into a dedicated Python helper script for better maintainability and to avoid redundant API calls.

1. New Python Script: langCodes.py

Path: .github/scripts/langCodes.py
This script ensures Crowdin codes map correctly to the standard NVDA language directory structure. For example, it explicitly maps es-ES to es and ar-SA to ar_SA. This will fix the "folder not found" errors in your recent workflow runs.

2. Updated PowerShell Script: crowdinSync.ps1

Path: .github/scripts/crowdinSync.ps1
Note: I have renamed this file to crowdinSync.txt so I could attach it here. Please rename it back to .ps1 before testing.

This version incorporates your latest requests and handles bi-directional synchronization:

  • Automatic PO Upload: I’ve updated the logic to handle the case you mentioned: "why aren't po files uploaded if they are translated just locally?". Now, if the script finds that Crowdin has no translation (or if the quality is below the threshold), it will automatically look for the local legacy .po file in the addon's locale folder and upload it to Crowdin. This ensures no local work is lost.
  • Regional Variant Support: The script now automatically handles the conversion of dashes to underscores (e.g., pt-BR becomes pt_BR), ensuring full compatibility with the directory structure of NVDA.

You should be able to test these files directly by placing them in the specified paths. Let me know if this resolves the issues with the Spanish and Arabic locales!
crowdinSync.txt
langCodes.py

@abdel792
Copy link
Copy Markdown

Hi @nvdaes,

I would like to apologize for missing your .github/scripts/languageMappings.json file in my previous analysis. I have now fully integrated it into the workflow.

I am attaching the updated versions of langCodes.py, checkTranslation.py, and crowdinSync.ps1 (renamed to .txt for the attachment).

Key Updates:

  1. Alignment with your Mappings:
    The new langCodes.py is now the perfect symmetrical counterpart to your languageMappings.json. It ensures that when Crowdin exports files, they are placed in the exact local folders NVDA expects (handling cases like sr-CS to sr, es-ES to es, etc.).

  2. Fixing the "Missing Languages" Issue (API Pagination):
    I've included an updated checkTranslation.py. The previous version was failing for many languages (like Turkish) because it didn't account for Crowdin API pagination, only retrieving the first 25 results. I have rewritten the logic to iterate through all result pages, ensuring 100% of the languages are now correctly tracked and scored.

  3. Bi-directional Sync:
    The updated crowdinSync.ps1 now properly uses your mapping logic to decide when to upload local .po files to Crowdin if the remote translation is missing or incomplete.

I will integrate all these improvements into a clean, dedicated PR shortly. In the meantime, feel free to test these files to see if they resolve the issues in your latest runs.

Thanks again for your patience and for the great work on the mappings!
crowdinSync.txt
langCodes.py
checkTranslation.py

@nvdaes
Copy link
Copy Markdown
Author

nvdaes commented Apr 28, 2026 via email

@abdel792
Copy link
Copy Markdown

Hi @nvdaes,

Following up on our recent exchange, I have opened a new Pull Request to consolidate and finalize the translation workflow improvements:
👉 PR #5: Refactor translation sync and language code handling

What’s included in this PR:

  • Integration of your Mapping: I have officially integrated your languageMappings.json. It is now used as the source of truth for Crowdin API uploads.
  • Symmetrical Path Handling: I’ve added langCodes.py to handle the "return" trip (Crowdin → Local). This ensures that files like es-ES or ar-SA are perfectly mapped to the standard NVDA folders (es, ar_SA, etc.) without creating duplicates.
  • The Pagination Fix: I rewritten the logic in checkTranslation.py to support API pagination. This was the reason why languages like Turkish (and others further down the alphabet) were returning 0% scores—the script now correctly scans all available result pages.
  • Bi-directional Sync & Debugging: crowdinSync.ps1 now includes the fallback logic to upload local .po files when needed, along with much more detailed logs (DEBUG/SUCCESS) to track the XLIFF vs. Markdown scoring process.

This PR should resolve the remaining issues with regional codes and missing translations. I've detailed the technical changes in the PR description. Looking forward to your feedback!

@nvdaes
Copy link
Copy Markdown
Author

nvdaes commented Apr 28, 2026 via email

@abdel792
Copy link
Copy Markdown

Hi @nvdaes,

Done! I have just pushed a new commit to the l10nImprovements branch with the updated readme.md.

As you suggested, I’ve added a detailed "Translation workflow" section. It now includes:

  • Instructions on how to request developer access via the mailing list.
  • The required GitHub Secrets (crowdinAuthToken and CROWDIN_PROJECT_ID).
  • A list of the necessary scripts for the infrastructure to work properly.
  • Clear steps for both the initial export and the automatic download process.

The PR is now complete and ready for your review. Thanks for the suggestion to update the documentation!

@abdel792
Copy link
Copy Markdown

Hi again @nvdaes,
I've updated the readme.md and made sure to point to the correct mailing list (nvda-translations@groups.io) as you requested.

@nvdaes
Copy link
Copy Markdown
Author

nvdaes commented Apr 28, 2026 via email

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants