Add scripts to allow addons from personal repos to be synchronized with Crowdin#1
Conversation
… addedwith dev role to Crowdin if they use a project not owned by them to upload source files)
…flow to upload/update files in Crowdin
…k pass creating a PR at nvdaes/translateNvdaaddonsWithCrowdin repo
PurposeAdd-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
Development approachA workflow (GitHub Actions), and several scripts (Python and Powershell), as well as a json file with language mappings have been added. |
|
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. |
|
Export translations to Crowdin running the workflow with update=False works properly: https://github.com/nvdaes/translateNvdaAddonsWithCrowdin/actions/runs/19802210157 |
|
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 |
|
If someone can help with this issue when update xliff, I'll be grateful. |
|
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 |
|
@seanbudd wrote:
OK. |
|
@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. |
Document XLIFF-based documentation synchronization, translation threshold configuration, GitHub Actions variables, and related Crowdin workflow changes.
|
Hi @nvdaes and everyone, I have just pushed two new commits for review. The first commit updates the Crowdin synchronization logic to address the concerns raised by @wmhn1872265132 regarding the coexistence of Markdown and XLIFF documentation files in Crowdin. The main changes are:
Following @nvdaes' review, I also revisited the translation threshold logic and found an issue while testing the workflow. In MIN_PERCENTAGE_TRANSLATED: ${{ vars.MIN_PERCENTAGE_TRANSLATED || 50 }}This indicates that the workflow expects percentage values between 0 and 100. However, the return progress / 100As a result, a translation progress of 93% became To keep both values on the same scale, I changed the function to return the percentage directly: return progressI tested this modification in a workflow run and the threshold validation behaved correctly afterwards: https://github.com/abdel792/dayOfTheWeek/actions/runs/27070359050/job/79898355233 I also updated the comparison operator from This means that translations reaching exactly the configured threshold are now accepted. For example, if a repository maintainer sets: a file translated at exactly 100% will be synchronized, which seems more intuitive than requiring a value strictly greater than the configured threshold. The second commit updates the README documentation accordingly. The documentation now:
I also took into account the recent comments from @wmhn1872265132 regarding the migration path from Markdown to XLIFF and the current state of the tooling. Please review the changes when you have time and let me know if you see anything that should be adjusted before merging. One additional note regarding the README updates. I did not document the AddonTemplate update procedure for now. I understand the workflow that was suggested: git remote add addonTemplate https://github.com/nvaccess/AddonTemplate.git
git fetch addonTemplate
git branch -u addonTemplate/master
git pull --allow-unrelated-historiesHowever, in my own tests, especially with add-ons based on older versions of AddonTemplate, the My concern is not only the conflicts themselves, but also the possibility of accidentally overwriting add-on-specific metadata while resolving them. For example, files such as:
typically contain information that is specific to the local add-on repository and should not be replaced by the template version. These files frequently contain add-on-specific information such as metadata, version history, build configuration, documentation, and release notes that cannot always be merged automatically. When using Because of that, I was not fully comfortable documenting this procedure as a general recommendation in the README without additional guidance, warnings, or testing. I think this topic may deserve a dedicated section in the future explaining the expected conflicts and the best practices for safely merging AddonTemplate updates into existing add-ons, particularly those created from much older template versions. Thanks everyone for the feedback, testing, and suggestions. |
|
@abdel792 , I've reviewed diffs: And for me this is ready to request a review. Note: In the documentation, it's recommended to avoiding to run the workflow at the same time if various add-ons are managed. Anyway, as requested by Sean, now the workflow includes a procedure to start with a random delay: Anyway, we have also the possibility of collisions even with the random delay. I have seen your testing workflow. Let's request a review from NV Access. |
|
Hi @nvdaes, Thanks for your review and feedback. I have just pushed an additional documentation update. Regarding your comment about workflow scheduling, I noticed that the README was still recommending the use of different cron schedules without mentioning the random startup delay that was later added to the workflow. I have therefore updated the documentation to clarify that the workflow already includes a random delay before scheduled executions, while noting that collisions may still occur in some situations. I also revisited the Previously, the documentation explained how to create the The section has therefore been reorganized so that the process for creating repository variables is introduced before listing the supported variables, making the overall structure more consistent and easier to follow. Please let me know if you think any further adjustments are needed before requesting the NV Access review. Thanks again for all your work on this PR. |
|
@abdel792 , I've reviewed your last commit, and for me it's right. I requested a review from NV Access, and in fact I think that this PR is ready for review. |
|
Hi @wmhn1872265132, Thank you for the clarification regarding the After reading your comment, I decided to perform a local test using the Clock add-on documentation. For local testing, I temporarily replaced the GitHub Actions authentication used by First, I checked the translation status reported by Crowdin for the existing XLIFF file: Output: I then checked the legacy Markdown documentation: Output: This showed that Crowdin currently reports 61% translation progress for the Markdown documentation, while the corresponding XLIFF file still reports 0%. Since the translated Markdown documentation already contained a significant amount of work, I decided to try the migration procedure you described. Before running the conversion, I adjusted the translated I then executed: Output: The conversion completed successfully and produced a translated XLIFF file. I will attach the generated If you wish, you may continue reviewing and completing the translation in Poedit and then upload the updated XLIFF file to Crowdin whenever convenient. Since the workflow changes proposed in this PR now use XLIFF files exclusively as the source for documentation synchronization, having an initial translated XLIFF file should make the migration easier and allow existing translation work to be preserved. Once uploaded to Crowdin, future synchronization cycles between the Clock repository and Crowdin should use this XLIFF translation instead of relying on the legacy Markdown file. Thank you again for pointing out this migration path. My test suggests that it can be a practical way to reuse existing Markdown translations when their structure is still sufficiently close to the source document. |
|
Hi @abdel792, Please note that I uploaded the translation for the Clock Add-on's XLIFF file last Monday. I checked the Crowdin history and saw that the file was recreated last Thursday, causing all translations to be lost. I'm not sure which version of the XLIFF file should be used. Once you have confirmed that the file is stable, I can re-upload the translation for it. Please be very careful: once translators start working on an XLIFF file, modifications should only be made in one place. Creating the same file from multiple locations very easily leads to loss of existing translations. This is the main reason I opened nvaccess/nvda#20215 |
|
Hi @wmhn1872265132, Thank you for the clarification. I now better understand what happened. After reviewing the workflow, I believe the recreation of the XLIFF file that you observed last Thursday is most likely related to the synchronization process introduced in this PR. As implemented by @nvdaes, the workflow currently regenerates the source XLIFF file during each synchronization cycle using For the Clock repository, synchronization currently runs every Thursday, which matches the timing you observed. I am starting to suspect that this regeneration process may be responsible for the loss of previously uploaded translations. My concern is that generating a completely new XLIFF source file with This would explain why a translation uploaded on Monday could appear to be lost after the Thursday synchronization. GitHub did not accept the generated XLIFF file that I mentioned in my previous comment, so it never appeared in the discussion. I have therefore uploaded it here: http://cyber25.free.fr/nvda-addons/zh/readme.xliff You may download it and compare it with your current translation work if you find it useful. @nvdaes, this also made me think about the old Perhaps it would be worth investigating whether similar functionality should eventually be added to Of course, this is only a hypothesis at this stage and would need to be confirmed by comparing the source XLIFF files generated before and after synchronization. Thank you again for raising this issue and for all the work you have contributed to the Chinese translation. |
|
No, I've looked at the commits in the Clock repository. The translation loss was not caused by the scheduled run of the workflow. If you hadn't made any changes at that time, then I'm not sure whether there is also a scheduled workflow running in your forked repository. If there is, you need to disable the scheduled run in the forked repository, and then manually run the translation synchronization workflow in the Clock repository once. That should resolve the issue. |
|
I have confirmed that the translation loss was caused by |
|
@abdel792, replying from email since I don't have access to GitHub from
this computer, in case you can check this now.
I tried to implement this, and should be used in our workflow:
•
md2xliff - Convert a Markdown file to XLIFF.
◦ Required: mdPath — path to the Markdown file; xliffPath — path for the
resulting XLIFF file.
◦ Optional: -o/--oldXliffPath — path to a previously generated XLIFF file
used as a baseline so existing translated strings are retained and applied
to the newly generated XLIFF file.
https://github.com/nvaccess/nvdaL10n/
Please let me know if this is not been used or if something is wrong in
l10nUtil.exe.
El lun, 8 jun 2026 a las 10:47, abdel792 ***@***.***>)
escribió:
… *abdel792* left a comment (nvaccess/AddonTemplate#1)
<#1 (comment)>
Hi @wmhn1872265132 <https://github.com/wmhn1872265132>,
Thank you for the clarification.
I now better understand what happened.
After reviewing the workflow, I believe the recreation of the XLIFF file
that you observed last Thursday is most likely related to the
synchronization process introduced in this PR.
As implemented by @nvdaes <https://github.com/nvdaes>, the workflow
currently regenerates the source XLIFF file during each synchronization
cycle using l10nUtil.exe md2xliff. The purpose is to ensure that any
updates made by the add-on author to the official English documentation are
automatically reflected in the translation source uploaded to Crowdin.
For the Clock repository, synchronization currently runs every Thursday,
which matches the timing you observed.
I am starting to suspect that this regeneration process may be responsible
for the loss of previously uploaded translations.
My concern is that generating a completely new XLIFF source file with
md2xliff may also generate new internal identifiers within the XLIFF
skeleton. If Crowdin relies on those identifiers to associate existing
translations with source strings, regenerating them could prevent
previously uploaded translations from being matched correctly.
This would explain why a translation uploaded on Monday could appear to be
lost after the Thursday synchronization.
GitHub did not accept the generated XLIFF file that I mentioned in my
previous comment, so it never appeared in the discussion.
I have therefore uploaded it here:
http://cyber25.free.fr/nvda-addons/zh/readme.xliff
You may download it and compare it with your current translation work if
you find it useful.
@nvdaes <https://github.com/nvdaes>, this also made me think about the
old markdownTranslate.py updateXliff workflow, which was designed to
update an existing XLIFF file rather than recreate it from scratch.
Perhaps it would be worth investigating whether similar functionality
should eventually be added to l10nUtil.exe. My intuition is that updating
an existing XLIFF while preserving its internal structure and identifiers
could help maintain translation continuity across documentation updates and
reduce the risk of losing previously uploaded translations.
Of course, this is only a hypothesis at this stage and would need to be
confirmed by comparing the source XLIFF files generated before and after
synchronization.
Thank you again for raising this issue and for all the work you have
contributed to the Chinese translation.
—
Reply to this email directly, view it on GitHub
<#1?email_source=notifications&email_token=ADYTVZGCZIKBUWLKEOFEDYD46Z4R3A5CNFSNUABFM5UWIORPF5TWS5BNNB2WEL2JONZXKZKDN5WW2ZLOOQXTINRUGY4TAMJRHE32M4TFMFZW63VHNVSW45DJN5XKKZLWMVXHJLDGN5XXIZLSL5RWY2LDNM#issuecomment-4646901197>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/ADYTVZF2R3SCFXXDBPVR2ND46Z4R3AVCNFSM6AAAAACNAEHU72VHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHM2DMNBWHEYDCMJZG4>
.
You are receiving this because you were mentioned.Message ID:
***@***.***>
|
|
@nvdaes I have confirmed that there is no problem with the workflow. The issue is due to a planned workflow running in the Fork repository of clock |
|
Thank you both for investigating this. I have now deleted the Indeed, this was only a temporary fork created for testing purposes, and it appears that its scheduled workflow was the source of the issue identified by @wmhn1872265132. Thank you @wmhn1872265132 for tracking this down and confirming the actual cause of the translation loss. Thank you as well @nvdaes for your clarification regarding the With the test fork now removed, everything should be fine. Future synchronizations between the Clock repository and Crowdin should no longer be affected by the issue that was observed. For reference, the Clock repository is still using the previous workflow version. I have not yet integrated the latest changes from this PR that switch the documentation synchronization to the XLIFF-only workflow. Thanks again to both of you for the investigation and explanations. |
|
Thanks @wmhn1872265132 for the explanation. I believe I now understand what happened. In Since the synchronization workflows were able to run against the same Crowdin project using the same token, this likely created the conflict you identified during the last synchronization cycle. At the time, I have now deleted that fork to prevent this situation from happening again. For future pull requests, I will avoid configuring I also have contributor access to Thanks for investigating this and identifying the real cause of the issue. Your explanation makes perfect sense now. |
|
There's been a long conversation here - does anything need further action? is this still ready for review? |
|
@seanbudd , this is ready for review. Note: When this is merged, we may have to create a PR to the add-on-datastore repo to inform that this is not in progress. |
|
Hi @seanbudd, Apologies for the length of the discussion. Several topics were investigated during the review process, which probably makes it difficult to quickly identify the final state of the PR from the conversation alone. Since then, @nvdaes has addressed the remaining comments and pushed two additional commits, including a pre-commit cleanup and the corresponding For reference, the workflow validation run I shared previously completed successfully: https://github.com/abdel792/dayOfTheWeek/actions/runs/27070359050/job/79898355233 I would also like to thank @nvdaes, @wmhn1872265132 and @CyrilleB79 for their reviews, testing, suggestions, and feedback throughout this process. Their comments helped improve both the implementation and the documentation. Following @nvdaes' assessment, I can also confirm from my side that the requested changes have been implemented, the workflow behavior has been validated, and the documentation has been updated accordingly. As far as I can tell, this PR is ready for NV Access review. |
Co-authored-by: Sean Budd <seanbudd123@gmail.com>
seanbudd
left a comment
There was a problem hiding this comment.
Thanks @nvdaes @abdel792 @wmhn1872265132 and everyone else who worked on this.
Co-authored-by: WMHN <1872265132@qq.com>
This pull request introduces a complete, automated workflow for synchronizing translations with Crowdin, including new scripts, a scheduled GitHub Actions workflow, and supporting documentation. The main changes add Python and PowerShell scripts for translation status checking and synchronization, a workflow for scheduled and manual Crowdin sync, language mapping configuration, and documentation updates. These improvements enable seamless translation management for add-on projects.
Specifically: