diff --git a/.ci/update_translations.sh b/.ci/update_translations.sh
new file mode 100755
index 000000000..7192b8abe
--- /dev/null
+++ b/.ci/update_translations.sh
@@ -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
diff --git a/.ci/update_translations_template.md b/.ci/update_translations_template.md
new file mode 100644
index 000000000..a2fa690ef
--- /dev/null
+++ b/.ci/update_translations_template.md
@@ -0,0 +1,11 @@
+Updated language source strings:
+- {{ .cockatrice_output }} (Cockatrice)
+- {{ .oracle_output }} (Oracle)
+
+
+
+Last changes are based on commit {{ .commit }}.
+
+---
+*This PR is automatically generated and updated by the workflow at `.github/workflows/translations.yml`.*
+*After merging, all changes to the source language are available for translation at [Transifex](https://www.transifex.com/projects/p/cockatrice/) shortly.*
diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md
index 574375894..2db045819 100644
--- a/.github/CONTRIBUTING.md
+++ b/.github/CONTRIBUTING.md
@@ -290,20 +290,21 @@ be included in the next release 👍
Basic workflow for translations:
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;
- 3. Transifex picks up the new files from GitHub every 24 hours;
- 4. Translators translate the new untranslated strings on Transifex;
- 5. Before a release, a maintainer fetches the updated translations from Transifex.
+ 2. CI updates the `*_en@source.ts files` regularly and creates a PR automatically;
+ 3. Maintainer verifies and merges the change;
+ 4. Transifex picks up the new files from GitHub automatically;
+ 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) ###
-All the user-interface strings inside Cockatrice's source code must be written
-in English(US).
+All user interface strings inside Cockatrice's source code must be written
+in English (US).
Translations to other languages are managed using [Transifex](
https://www.transifex.com/projects/p/cockatrice/).
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.
For example, setting the text of a label in the way that the string
`"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
-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++
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
string in the code, you don't need to take care of adding the new strings to
-the translation files.
-Every few days, or when a lot of new strings have been added, someone from the
-development team will take care of extracting all the new strings and adding
-them to the english translation files and making them available to translators
-on Transifex.
+the translation files.
+We have an automated process to update our language source files on a schedule
+and provide the translators on Transifex with the new contents.
+Maintainers can also manually trigger this on demand.
### Maintaining Translations (for maintainers) ###
-When new translatable strings have been added to the code, a maintainer should
-make them available to translators on Transifex. Every few days, or when a lot
-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.
+When new translatable strings have been added to the code, a maintainer has to
+make them available to translators on Transifex.
-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.
+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.
+
+
+Manually trigger CI run (Workflow Dispatch)
+
+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.
+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.
+
+
+
+
+Manually update source strings locally
+
+To update the english source files for translation, re-run cmake enabling the appropriate
parameter and then run make:
```sh
cd cockatrice/build
@@ -357,11 +384,13 @@ It is recommended to disable the parameter afterwards using:
```sh
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
-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) ###
diff --git a/.github/workflows/desktop-build.yml b/.github/workflows/desktop-build.yml
index cf8fbed8b..8efe8bfbd 100644
--- a/.github/workflows/desktop-build.yml
+++ b/.github/workflows/desktop-build.yml
@@ -8,6 +8,7 @@ on:
- '**.md'
- 'webclient/**'
- '.github/workflows/web-*.yml'
+ - '.github/workflows/translations.yml'
tags:
- '*'
pull_request:
@@ -15,6 +16,7 @@ on:
- '**.md'
- 'webclient/**'
- '.github/workflows/web-*.yml'
+ - '.github/workflows/translations.yml'
jobs:
configure:
diff --git a/.github/workflows/desktop-lint.yml b/.github/workflows/desktop-lint.yml
index 95a95a8ea..a1dce8a20 100644
--- a/.github/workflows/desktop-lint.yml
+++ b/.github/workflows/desktop-lint.yml
@@ -6,6 +6,7 @@ on:
- '**.md'
- 'webclient/**'
- '.github/workflows/web-*.yml'
+ - '.github/workflows/translations.yml'
jobs:
format:
diff --git a/.github/workflows/translations.yml b/.github/workflows/translations.yml
index c9b10d0a6..01526a42e 100644
--- a/.github/workflows/translations.yml
+++ b/.github/workflows/translations.yml
@@ -1,66 +1,87 @@
-name: Update translation source
+name: Update Translation Source
on:
workflow_dispatch:
schedule:
- # runs once per month
+ # runs at the start of each month (UTC)
- cron: '0 0 1 * *'
+ pull_request:
+ paths:
+ - '.github/workflows/translations.yml'
jobs:
translations:
# Do not run the scheduled workflow on forks
if: github.event_name != 'schedule' || github.repository_owner == 'Cockatrice'
+ name: Update translation source
runs-on: ubuntu-latest
steps:
+ - name: Checkout repo
+ uses: actions/checkout@v3
+
- name: Install lupdate
shell: bash
run: |
sudo apt-get update
sudo apt-get install -y --no-install-recommends qttools5-dev-tools
- - name: Checkout repo
- uses: actions/checkout@v3
-
- - name: Update cockatrice translations
+ - name: Update Cockatrice translation source
+ id: cockatrice
shell: bash
- run: |
- shopt -s globstar # globstar is needed for recursive **
- lupdate -version
- echo "reading the following source files:"
- # 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
+ env:
+ FILE: 'cockatrice/cockatrice_en@source.ts'
+ DIRS: 'cockatrice/src common'
+ run: .ci/update_translations.sh
- - name: Update oracle translations
+ - name: Update Oracle translation source
+ id: oracle
shell: bash
- run: |
- shopt -s globstar # globstar is needed for recursive **
- lupdate -version
- echo "reading the following source files:"
- echo oracle/**/*.{cpp,h}
- echo "$(echo oracle/**/*.{cpp,h} | wc -w) files total"
- lupdate oracle/**/*.{cpp,h} -ts oracle/translations/oracle_en@source.ts
+ env:
+ FILE: 'oracle/oracle_en@source.ts'
+ DIRS: 'oracle/src'
+ run: .ci/update_translations.sh
- - name: Check for updates
- id: check
- shell: bash
- run: |
- set +e # do not fail, just save the exit state
- git diff --exit-code
- echo "deploy=$?" >>"$GITHUB_OUTPUT"
+ - name: Render template
+ id: template
+ uses: chuhlomin/render-template@v1.7
+ with:
+ template: .ci/update_translations_template.md
+ vars: |
+ cockatrice_output: ${{ steps.cockatrice.outputs.output }}
+ oracle_output: ${{ steps.oracle.outputs.output }}
+ commit: ${{ github.sha }}
- - name: Commit changes
- if: steps.check.outputs.deploy == '1'
+ - name: Create pull request
+ 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
+ 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
- working-directory: ${{env.OUTPUT_PATH}}
+ env:
+ STATUS: ${{ steps.create_pr.outputs.pull-request-operation }}
run: |
- git config user.name github-actions
- git config user.email github-actions@github.com
- git add cockatrice/translations/cockatrice_en@source.ts oracle/translations/oracle_en@source.ts
- git commit -m "Automated translation update ( $GITHUB_SHA )"
- git push
- deploy_commit=$(git rev-parse HEAD)
- echo "Created commit: $GITHUB_SERVER_URL/$GITHUB_REPOSITORY/commit/$deploy_commit"
+ if [[ "$STATUS" == "" ]]; then
+ echo "PR #${{ steps.create_pr.outputs.pull-request-number }} unchanged!"
+ else
+ echo "PR #${{ steps.create_pr.outputs.pull-request-number }} $STATUS!"
+ fi
+ echo "URL: ${{ steps.create_pr.outputs.pull-request-url }}"
diff --git a/.github/workflows/web-build.yml b/.github/workflows/web-build.yml
index bf1d4a870..a50e90ce4 100644
--- a/.github/workflows/web-build.yml
+++ b/.github/workflows/web-build.yml
@@ -50,4 +50,3 @@ jobs:
- name: Test app
run: npm run test
-