CI: Add automatic PR creation for source string updates (#4544)

* wording

* add pr creation

* Update translations.yml

* Update translations.yml

* update translation workflow

* Update CONTRIBUTING.md

* Update CONTRIBUTING.md

* Update CONTRIBUTING.md

* skip ci update

* skip ci update

* update conditions

* remove empty line

* typo

* tee test

* cleanup

* pass data between steps

* opt for step output over env variable

* remove space

* create script

* wording

* fix fork protection, re-add pr run

* updates

* Update translations.yml

* adjust for new source paths

* update comment

* wording

Co-authored-by: ebbit1q <ebbit1q@gmail.com>

* wording

* reorder

* reorder

* fix deprecation of set-output

* fix version

---------

Co-authored-by: ebbit1q <ebbit1q@gmail.com>
This commit is contained in:
tooomm 2023-08-06 23:55:50 +02:00 committed by GitHub
parent 244cb847fb
commit ca308636c3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 181 additions and 62 deletions

56
.ci/update_translations.sh Executable file
View file

@ -0,0 +1,56 @@
#!/bin/bash
# ci script to update translation files
# usage:
# $0 cockatrice/cockatrice_en@source.ts cockatrice/src common
# or
# FILE="cockatrice/cockatrice_en@source.ts"
# DIRS="cockatrice/src common"
# $0
# note: directories can't contain spaces
# check parameters
if [[ ! $FILE ]]; then
FILE="$1"
shift
fi
if [[ ! $FILE ]]; then
echo "no output file selected" >&2
exit 2;
fi
if [[ ! $DIRS ]]; then
DIRS="$*"
fi
if [[ ! $DIRS ]]; then
echo "no source directories selected to translate" >&2
exit 2;
fi
if [[ ! -e $FILE ]]; then
echo "output file does not exist at: $FILE" >&2
exit 3;
fi
# print version
if ! lupdate -version; then
echo "failed to run lupdate" >&2
exit 4;
fi
# run lupdate, duplicating the output in stderr and saving it
# for convenience we ignore that $DIRS will be split on spaces
# shellcheck disable=SC2086
if ! got="$(lupdate $DIRS -ts "$FILE" | tee /dev/stderr)"; then
echo "failed to update $FILE with $DIRS" >&2
exit 4;
fi
# trim output
output="${got##*(}" # trim everything before last (
output="${output%%)*}" # trim everything after first )
if [[ $output == $got ]]; then
echo "could not parse generated output" >&2
exit 4;
fi
# write output to ci environment file
echo "output=$output" >> $GITHUB_OUTPUT

View file

@ -0,0 +1,11 @@
Updated language source strings:
- {{ .cockatrice_output }} (Cockatrice)
- {{ .oracle_output }} (Oracle)
<br>
Last changes are based on commit {{ .commit }}.
---
*This PR is automatically generated and updated by the workflow at `.github/workflows/translations.yml`.*<br>
*After merging, all changes to the source language are available for translation at [Transifex](https://www.transifex.com/projects/p/cockatrice/) shortly.*

View file

@ -290,20 +290,21 @@ be included in the next release 👍
Basic workflow for translations: Basic workflow for translations:
1. Developer adds a `tr("foo")` string in the code; 1. Developer adds a `tr("foo")` string in the code;
2. Every few days, a maintainer updates the `*_en@source.ts files` with the new strings; 2. CI updates the `*_en@source.ts files` regularly and creates a PR automatically;
3. Transifex picks up the new files from GitHub every 24 hours; 3. Maintainer verifies and merges the change;
4. Translators translate the new untranslated strings on Transifex; 4. Transifex picks up the new files from GitHub automatically;
5. Before a release, a maintainer fetches the updated translations from Transifex. 5. Translators translate the new untranslated strings on Transifex;
6. Before a release, a maintainer fetches the updated translations from Transifex.
### Using Translations (for developers) ### ### Using Translations (for developers) ###
All the user-interface strings inside Cockatrice's source code must be written All user interface strings inside Cockatrice's source code must be written
in English (US). in English (US).
Translations to other languages are managed using [Transifex]( Translations to other languages are managed using [Transifex](
https://www.transifex.com/projects/p/cockatrice/). https://www.transifex.com/projects/p/cockatrice/).
Adding a new string to translate is as easy as adding the string in the Adding a new string to translate is as easy as adding the string in the
'tr("")' function, the string will be picked up as translatable automatically `tr("")` function, the string will be picked up as translatable automatically
and translated as needed. and translated as needed.
For example, setting the text of a label in the way that the string For example, setting the text of a label in the way that the string
`"My name is:"` can be translated: `"My name is:"` can be translated:
@ -312,7 +313,7 @@ nameLabel.setText(tr("My name is:"));
``` ```
To translate a string that would have plural forms you can add the amount to To translate a string that would have plural forms you can add the amount to
the tr call, also you can add an extra string as a hint for translators: the tr() call, also you can add an extra string as a hint for translators:
```c++ ```c++
QString message = tr("Everyone draws %n cards", "pop up message", amount); QString message = tr("Everyone draws %n cards", "pop up message", amount);
``` ```
@ -321,20 +322,46 @@ https://doc.qt.io/qt-5/i18n-source-translation.html#handling-plurals)
If you're about to propose a change that adds or modifies any translatable If you're about to propose a change that adds or modifies any translatable
string in the code, you don't need to take care of adding the new strings to string in the code, you don't need to take care of adding the new strings to
the translation files. the translation files.<br>
Every few days, or when a lot of new strings have been added, someone from the We have an automated process to update our language source files on a schedule
development team will take care of extracting all the new strings and adding and provide the translators on Transifex with the new contents.<br>
them to the english translation files and making them available to translators Maintainers can also manually trigger this on demand.
on Transifex.
### Maintaining Translations (for maintainers) ### ### Maintaining Translations (for maintainers) ###
When new translatable strings have been added to the code, a maintainer should When new translatable strings have been added to the code, a maintainer has to
make them available to translators on Transifex. Every few days, or when a lot make them available to translators on Transifex.
of new strings have been added, a maintainer should take care of extracting all
the new strings and add them to the english translation files.
To update the english translation files, re-run cmake enabling the appropriate To help with that, we have an automated CI workflow, that regularly looks at the
code in the master branch, extracts all strings and updates dedicated source string
files with any changes. These updates are not commited right away, the CI creates a
PR for reviewing instead.<br>
After approval, our translation tool automatically picks the changes up and deploys
them to our translators. Be mindful when merging only a few changes!
Once a release is planned, or when a lot of strings have been added or changed, a
maintainer can manually trigger a CI run to extract all strings on demand.
<details>
<summary><b>Manually trigger CI run (Workflow Dispatch)</b></summary>
Maintainers can always request the CI to run on demand if it's required.
Go to the `Actions` tab and select our dedicated translation workflow:
https://github.com/Cockatrice/Cockatrice/actions/workflows/translations.yml
You see a "This workflow has a workflow_dispatch event trigger." hint at the top of
the list.<br>
Select `Run workflow` on the right and trigger a run from master branch.
The CI will now check for changed strings and create a PR if there are any updates.
</details>
<details>
<summary><b>Manually update source strings locally</b></summary>
To update the english source files for translation, re-run cmake enabling the appropriate
parameter and then run make: parameter and then run make:
```sh ```sh
cd cockatrice/build cd cockatrice/build
@ -357,11 +384,13 @@ It is recommended to disable the parameter afterwards using:
```sh ```sh
cmake .. -DUPDATE_TRANSLATIONS=OFF cmake .. -DUPDATE_TRANSLATIONS=OFF
``` ```
Now you are ready to propose your change. Now you are ready to commit your changes and open a PR.
Once your change gets merged, Transifex will pick up the modified files </details>
automatically (checked every 24 hours) and update the interface where
translators will be able to translate the new strings. Once the changes get merged, Transifex will pick up the modified files
automatically (checked every few hours) and update their online editor where
translators will be able to translate the new strings right in the browser.
### Releasing Translations (for maintainers) ### ### Releasing Translations (for maintainers) ###

View file

@ -8,6 +8,7 @@ on:
- '**.md' - '**.md'
- 'webclient/**' - 'webclient/**'
- '.github/workflows/web-*.yml' - '.github/workflows/web-*.yml'
- '.github/workflows/translations.yml'
tags: tags:
- '*' - '*'
pull_request: pull_request:
@ -15,6 +16,7 @@ on:
- '**.md' - '**.md'
- 'webclient/**' - 'webclient/**'
- '.github/workflows/web-*.yml' - '.github/workflows/web-*.yml'
- '.github/workflows/translations.yml'
jobs: jobs:
configure: configure:

View file

@ -6,6 +6,7 @@ on:
- '**.md' - '**.md'
- 'webclient/**' - 'webclient/**'
- '.github/workflows/web-*.yml' - '.github/workflows/web-*.yml'
- '.github/workflows/translations.yml'
jobs: jobs:
format: format:

View file

@ -1,66 +1,87 @@
name: Update translation source name: Update Translation Source
on: on:
workflow_dispatch: workflow_dispatch:
schedule: schedule:
# runs once per month # runs at the start of each month (UTC)
- cron: '0 0 1 * *' - cron: '0 0 1 * *'
pull_request:
paths:
- '.github/workflows/translations.yml'
jobs: jobs:
translations: translations:
# Do not run the scheduled workflow on forks # Do not run the scheduled workflow on forks
if: github.event_name != 'schedule' || github.repository_owner == 'Cockatrice' if: github.event_name != 'schedule' || github.repository_owner == 'Cockatrice'
name: Update translation source
runs-on: ubuntu-latest runs-on: ubuntu-latest
steps: steps:
- name: Checkout repo
uses: actions/checkout@v3
- name: Install lupdate - name: Install lupdate
shell: bash shell: bash
run: | run: |
sudo apt-get update sudo apt-get update
sudo apt-get install -y --no-install-recommends qttools5-dev-tools sudo apt-get install -y --no-install-recommends qttools5-dev-tools
- name: Checkout repo - name: Update Cockatrice translation source
uses: actions/checkout@v3 id: cockatrice
- name: Update cockatrice translations
shell: bash shell: bash
run: | env:
shopt -s globstar # globstar is needed for recursive ** FILE: 'cockatrice/cockatrice_en@source.ts'
lupdate -version DIRS: 'cockatrice/src common'
echo "reading the following source files:" run: .ci/update_translations.sh
# note: there are three strings to translate in common right now
echo {cockatrice,common}/**/*.{cpp,h}
echo "$(echo {cockatrice,common}/**/*.{cpp,h} | wc -w) files total"
lupdate {cockatrice,common}/**/*.{cpp,h} -ts cockatrice/translations/cockatrice_en@source.ts
- name: Update oracle translations - name: Update Oracle translation source
id: oracle
shell: bash shell: bash
run: | env:
shopt -s globstar # globstar is needed for recursive ** FILE: 'oracle/oracle_en@source.ts'
lupdate -version DIRS: 'oracle/src'
echo "reading the following source files:" run: .ci/update_translations.sh
echo oracle/**/*.{cpp,h}
echo "$(echo oracle/**/*.{cpp,h} | wc -w) files total"
lupdate oracle/**/*.{cpp,h} -ts oracle/translations/oracle_en@source.ts
- name: Check for updates - name: Render template
id: check id: template
shell: bash uses: chuhlomin/render-template@v1.7
run: | with:
set +e # do not fail, just save the exit state template: .ci/update_translations_template.md
git diff --exit-code vars: |
echo "deploy=$?" >>"$GITHUB_OUTPUT" cockatrice_output: ${{ steps.cockatrice.outputs.output }}
oracle_output: ${{ steps.oracle.outputs.output }}
commit: ${{ github.sha }}
- name: Commit changes - name: Create pull request
if: steps.check.outputs.deploy == '1' if: github.event_name != 'pull_request'
id: create_pr
uses: peter-evans/create-pull-request@v4
with:
add-paths: |
cockatrice/cockatrice_en@source.ts
oracle/oracle_en@source.ts
commit-message: Update translation source strings
# author is the owner of the commit
author: github-actions <github-actions@github.com>
branch: ci-update_translations
delete-branch: true
title: '[Translations] Update source strings'
body: ${{ steps.template.outputs.result }}
labels: |
CI
Translation
draft: false
- name: PR Status
if: github.event_name != 'pull_request'
shell: bash shell: bash
working-directory: ${{env.OUTPUT_PATH}} env:
STATUS: ${{ steps.create_pr.outputs.pull-request-operation }}
run: | run: |
git config user.name github-actions if [[ "$STATUS" == "" ]]; then
git config user.email github-actions@github.com echo "PR #${{ steps.create_pr.outputs.pull-request-number }} unchanged!"
git add cockatrice/translations/cockatrice_en@source.ts oracle/translations/oracle_en@source.ts else
git commit -m "Automated translation update ( $GITHUB_SHA )" echo "PR #${{ steps.create_pr.outputs.pull-request-number }} $STATUS!"
git push fi
deploy_commit=$(git rev-parse HEAD) echo "URL: ${{ steps.create_pr.outputs.pull-request-url }}"
echo "Created commit: $GITHUB_SERVER_URL/$GITHUB_REPOSITORY/commit/$deploy_commit"

View file

@ -50,4 +50,3 @@ jobs:
- name: Test app - name: Test app
run: npm run test run: npm run test