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:
parent
244cb847fb
commit
ca308636c3
7 changed files with 181 additions and 62 deletions
56
.ci/update_translations.sh
Executable file
56
.ci/update_translations.sh
Executable 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
|
11
.ci/update_translations_template.md
Normal file
11
.ci/update_translations_template.md
Normal 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.*
|
71
.github/CONTRIBUTING.md
vendored
71
.github/CONTRIBUTING.md
vendored
|
@ -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) ###
|
||||||
|
|
||||||
|
|
2
.github/workflows/desktop-build.yml
vendored
2
.github/workflows/desktop-build.yml
vendored
|
@ -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:
|
||||||
|
|
1
.github/workflows/desktop-lint.yml
vendored
1
.github/workflows/desktop-lint.yml
vendored
|
@ -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:
|
||||||
|
|
99
.github/workflows/translations.yml
vendored
99
.github/workflows/translations.yml
vendored
|
@ -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"
|
|
||||||
|
|
1
.github/workflows/web-build.yml
vendored
1
.github/workflows/web-build.yml
vendored
|
@ -50,4 +50,3 @@ jobs:
|
||||||
|
|
||||||
- name: Test app
|
- name: Test app
|
||||||
run: npm run test
|
run: npm run test
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue