From 967a650d2d1bfa7d1f09e1fe7c743785f4217d0e Mon Sep 17 00:00:00 2001
From: Laura Benz <48948963+L-M-K-B@users.noreply.github.com>
Date: Thu, 1 Feb 2024 12:44:18 +0100
Subject: [PATCH] I18n: Refactor crowdin workflow (#81571)
* refactor: crowdin config
* feat: add GH actions
* refactor: remove old GH action
* refactor: fix formatting issue
* refactor: adjust docs
* refactor: add changes after code review
* refactor: add changes after code review
* refactor: update CODEOWNERS file
---
.github/CODEOWNERS | 3 +-
.github/workflows/i18n-crowdin-download.yml | 51 +++++++++++++++
.github/workflows/i18n-crowdin-fix-files.yml | 67 --------------------
.github/workflows/i18n-crowdin-upload.yml | 29 +++++++++
contribute/internationalization.md | 20 +++---
crowdin.yml | 7 +-
public/locales/i18next-parser.config.js | 4 +-
7 files changed, 98 insertions(+), 83 deletions(-)
create mode 100644 .github/workflows/i18n-crowdin-download.yml
delete mode 100644 .github/workflows/i18n-crowdin-fix-files.yml
create mode 100644 .github/workflows/i18n-crowdin-upload.yml
diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
index 166112a5a7d..1ccee149cb5 100644
--- a/.github/CODEOWNERS
+++ b/.github/CODEOWNERS
@@ -678,7 +678,8 @@ embed.go @grafana/grafana-as-code
/.github/workflows/ephemeral-instances-pr-opened-closed.yml @grafana/grafana-operator-experience-squad
/.github/workflows/create-security-patch-from-security-mirror.yml @grafana/grafana-release-guild
/.github/workflows/core-plugins-build-and-release.yml @grafana/plugins-platform-frontend @grafana/plugins-platform-backend
-/.github/workflows/i18n-crowdin-fix-files.yml @grafana/grafana-frontend-platform
+/.github/workflows/i18n-crowdin-upload.yml @grafana/grafana-frontend-platform
+/.github/workflows/i18n-crowdin-download.yml @grafana/grafana-frontend-platform
/.github/workflows/feature-toggle-cleanup.yml @tolzhabayev
/.github/workflows/scripts/feature-toggle-cleanup/feature-toggle-cleanup.js @tolzhabayev
diff --git a/.github/workflows/i18n-crowdin-download.yml b/.github/workflows/i18n-crowdin-download.yml
new file mode 100644
index 00000000000..89d8a1c303e
--- /dev/null
+++ b/.github/workflows/i18n-crowdin-download.yml
@@ -0,0 +1,51 @@
+name: Crowdin Download Action
+
+on:
+ workflow_dispatch:
+ schedule:
+ - cron: "0 * * * *"
+
+jobs:
+ download-sources-from-crowdin:
+ runs-on: ubuntu-latest
+
+ permissions:
+ contents: write # needed to commit changes into the PR
+ pull-requests: write # needed to update PR description, labels, etc
+
+ steps:
+ - uses: actions/checkout@v4
+ with:
+ ref: ${{ github.head_ref }}
+
+ - name: Download sources
+ uses: crowdin/github-action@v1
+ with:
+ upload_sources: false
+ upload_translations: false
+ download_sources: false
+ download_translations: true
+ localization_branch_name: i18n_crowdin_translations
+ create_pull_request: true
+ pull_request_title: 'I18n: Download translations from Crowdin'
+ pull_request_body: |
+ :robot: Automatic download of translations from Crowdin.
+
+ Steps for merging:
+ 1. A quick sanity check of the changes and approve. Things to look out for:
+ - No changes in the English file. The source of truth is in the main branch, NOT in Crowdin.
+ - Translations maybe be removed if the English phrase was removed, but there should not be many of these
+ - Anything else that looks 'funky'. Ask if you're not sure.
+ 2. Approve & (Auto-)merge. :tada:
+
+ If there's a conflict, close the pull request and **delete the branch**. A GH action will recreate the pull request.
+ Remember, the longer this pull request is open, the more likely it is that it'll get conflicts.
+ pull_request_labels: 'area/frontend, area/internationalization, no-changelog, no-backport'
+ pull_request_reviewers: 'grafana-frontend-platform'
+ pull_request_base_branch_name: 'main'
+ base_url: 'https://grafana.api.crowdin.com'
+ config: 'crowdin.yml'
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+ CROWDIN_PROJECT_ID: ${{ secrets.CROWDIN_PROJECT_ID }}
+ CROWDIN_PERSONAL_TOKEN: ${{ secrets.CROWDIN_PERSONAL_TOKEN }}
diff --git a/.github/workflows/i18n-crowdin-fix-files.yml b/.github/workflows/i18n-crowdin-fix-files.yml
deleted file mode 100644
index 5117bd381d6..00000000000
--- a/.github/workflows/i18n-crowdin-fix-files.yml
+++ /dev/null
@@ -1,67 +0,0 @@
-# When Crowdin creates a pull request from the crowdin-service-branch branch,
-# run `yarn i18n:extract` and commit the changed grafana.json files back into the PR
-# to reformat crowdin's changes to prevent conflicts with our CI checks.
-
-name: Fix Crowdin I18n files
-
-on:
- pull_request:
- paths:
- - 'public/locales/*/grafana.json'
- branches:
- - main # Only run on pull requests *target* main (will be merged into main)
-
-jobs:
- fix-files:
- # Only run on pull requests *from* the crowdin-service-branch branch
- if: github.head_ref == 'crowdin-service-branch'
-
- name: Fix files
- runs-on: ubuntu-latest
-
-
- permissions:
- contents: write # needed to commit changes back into the PR
- pull-requests: write # needed to update PR description
-
- steps:
- - uses: actions/checkout@v4
- with:
- ref: ${{ github.head_ref }}
-
- - uses: actions/setup-node@v4
- with:
- node-version: 20.9.0
- cache: 'yarn'
-
- - name: Install dependencies
- run: yarn install
-
- - name: Extract I18n files
- run: yarn i18n:extract
-
- - name: Commit changes
- uses: stefanzweifel/git-auto-commit-action@8756aa072ef5b4a080af5dc8fef36c5d586e521d # v5.0.0
- with:
- commit_message: "Github Action: Auto-fix i18n files"
- file_pattern: public/locales/*/grafana.json
-
- - name: Update PR description
- uses: devindford/Append_PR_Comment@32dd2619cd96ac8da9907c416c992fe265233ca8 # v1.1.3
- if: ${{ ! contains(github.event.pull_request.body, 'Steps for merging') }}
- with:
- repo-token: ${{ secrets.GITHUB_TOKEN }}
- body-update-action: prefix
- body-template: |
- :robot: Automatic sync of translations from Crowdin.
-
- Steps for merging:
- 1. Wait for the "Github Action: Auto-fix i18n files" commit that may be required for CI to pass.
- 2. A quick sanity check of the changes and approve. Things to look out for:
- - No changes to the English strings. The source of truth is already in the main branch, NOT Crowdin.
- - Translations maybe be removed if the English phrase was removed, but there should not be many of these
- - Anything else that looks 'funky'. Ask if you're not sure.
- 3. Approve & (Auto-)merge. :tada:
-
- If there's a conflict, close the pull request and **delete the branch**. Crowdin will recreate the pull request eventually.
- Remember, the longer this pull request is open, the more likely it is that it'll get conflicts.
diff --git a/.github/workflows/i18n-crowdin-upload.yml b/.github/workflows/i18n-crowdin-upload.yml
new file mode 100644
index 00000000000..9dcdd5a6b10
--- /dev/null
+++ b/.github/workflows/i18n-crowdin-upload.yml
@@ -0,0 +1,29 @@
+name: Crowdin Upload Action
+
+on:
+ push:
+ paths:
+ - 'public/locales/en-US/grafana.json'
+ branches:
+ - main
+
+jobs:
+ upload-sources-to-crowdin:
+ runs-on: ubuntu-latest
+
+ steps:
+ - name: Checkout
+ uses: actions/checkout@v4
+
+ - name: Upload sources
+ uses: crowdin/github-action@v1
+ with:
+ upload_sources: true
+ upload_translations: false
+ download_translations: false
+ create_pull_request: false
+ base_url: 'https://grafana.api.crowdin.com'
+ config: 'crowdin.yml'
+ env:
+ CROWDIN_PROJECT_ID: ${{ secrets.CROWDIN_PROJECT_ID }}
+ CROWDIN_PERSONAL_TOKEN: ${{ secrets.CROWDIN_PERSONAL_TOKEN }}
diff --git a/contribute/internationalization.md b/contribute/internationalization.md
index 243db35efe2..8d32a65e3ed 100644
--- a/contribute/internationalization.md
+++ b/contribute/internationalization.md
@@ -9,7 +9,8 @@ Grafana uses the [i18next](https://www.i18next.com/) framework for managing tran
- Use `Go to {{ pageTitle }}` in code to add a translatable phrase
- Translations are stored in JSON files in `public/locales/{locale}/grafana.json`
- If a particular phrase is not available in the a language then it will fall back to English
-- To update phrases in English, edit the default phrase in both the component's source and the [English grafana.json message catalogue](../public/locales/en-US/grafana.json), then run `yarn i18n:extract`.
+- To update phrases in English, edit the default phrase in the component's source and then run `yarn i18n:extract`.
+- The single source of truth for en-US (fallback language) is in grafana/grafana, the single source of truth for any translated language is Crowdin
- To update phrases in any translated language, edit the phrase in Crowdin. Do not edit the `{locale}/grafana.json`
## How to add a new translation phrase
@@ -40,7 +41,8 @@ const ErrorMessage = ({ id, message }) => There
2. Upon reload, the default English phrase will appear on the page.
-3. Before submitting your PR, run the `yarn i18n:extract` command to extract the messages you added into the `grafana.json` file and make them available for translation.
+3. Before submitting your PR, run the `yarn i18n:extract` command to extract the messages you added into the `public/locales/en-US/grafana.json` file and make them available for translation.
+ **Note:** All other languages will receive their translations when they are ready to be downloaded from Crowdin.
### Plain JS usage
@@ -64,20 +66,20 @@ While the `t` function can technically be used outside of React functions (e.g,
## How to add a new language
-1. Add new locale in Crowdin and sync files to repo
+1. Add new locale in Crowdin and download files to repo
1. Grafana OSS Crowdin project -> "dot dot dot" menu in top right -> Target languages
- 2. Grafana OSS Crowdin project -> Integrations -> Github -> Sync Now
- 3. If Crowdin's locale code is different from our IETF language tag, add a custom mapping in Project Settings -> Language mapping
-2. Update `public/app/core/internationalization/constants.ts` (add new constant, and add to `LOCALES`)
-3. Update `public/locales/i18next-parser.config.js` to add the new locale to `locales`
-4. Run `yarn i18n:extract` and commit the result
+ 2. If Crowdin's locale code is different from our IETF language tag, add a custom mapping in Project Settings -> Language mapping
+ 3. GH repo grafana/grafana -> Actions -> Choose `Crowdin Download Action` -> Run workflow -> Creates a PR automatically
+2. Review the PR `I18n: Download translations from Crowdin`
+3. Update `public/app/core/internationalization/constants.ts` (add new constant, and add to `LOCALES`) and add changes to the open PR
+4. Approve and merge the PR
## How translations work in Grafana
Grafana uses the [i18next](https://www.i18next.com/) framework for managing translating phrases in the Grafana frontend. It:
- Marks up phrases within our code for extraction
-- Extracts phrases into messages catalogues for translating in external systems
+- Extracts phrases into the default messages catalogue for translating in external systems
- Manages the user's locale and putting the translated phrases in the UI
Grafana will load the message catalogue JSON before the initial render.
diff --git a/crowdin.yml b/crowdin.yml
index 1cdf69254df..ba8846585f1 100644
--- a/crowdin.yml
+++ b/crowdin.yml
@@ -2,7 +2,6 @@ files:
- source: /public/locales/en-US/grafana.json
translation: /public/locales/%locale%/%original_file_name%
type: i18next_json
-pull_request_title: 'I18n: Crowdin sync'
-pull_request_labels:
- - area/internationalization
- - no-changelog
+# The following are pulled from env variables
+project_id_env: CROWDIN_PROJECT_ID
+api_token_env: CROWDIN_PERSONAL_TOKEN
diff --git a/public/locales/i18next-parser.config.js b/public/locales/i18next-parser.config.js
index 0628220503a..f3f5bd6c9bc 100644
--- a/public/locales/i18next-parser.config.js
+++ b/public/locales/i18next-parser.config.js
@@ -1,8 +1,8 @@
module.exports = {
// Default namespace used in your i18next config
defaultNamespace: 'grafana',
-
- locales: ['en-US', 'fr-FR', 'es-ES', "de-DE", "zh-Hans", 'pseudo-LOCALE'],
+ // Adds changes only to en-US when extracting keys, every other language is provided by Crowdin
+ locales: ['en-US'],
output: './public/locales/$LOCALE/$NAMESPACE.json',