Skip to content

Commit 3d7a8fb

Browse files
Add Crowdin to set up translations (Qiskit#541)
Part of Qiskit#476. This PR sets up two GitHub actions for interfacing with Crowdin.com, the website the translation team uses for translations. 1. Upload English sources. We do this on any change to `docs/` (except API docs), which the translation team so that they can start making updates sooner. For example: <img width="346" alt="Screenshot 2023-12-20 at 5 45 05 PM" src="https://github.com/Qiskit/documentation/assets/14852634/0ed4cbed-45db-45bb-9150-5d90bec7a0f6"> 2. Download the translations. This happens once a week, which the translations team requested. It will open up a pull request like https://github.com/Eric-Arellano/documentation/pull/10. ## How auth works We only need to set GitHub Secrets for CROWDIN_PROJECT_ID and CROWDIN_PERSONAL_TOKEN. GitHub will automatically set GITHUB_TOKEN using [this mechanism](https://docs.github.com/en/actions/security-guides/automatic-token-authentication). ## Translations saved at `translations/` folder This adds a top-level `translations/` folder, rather than nesting the translations inside the `docs/` folder. For example: <img width="367" alt="Screenshot 2023-12-20 at 5 48 09 PM" src="https://github.com/Qiskit/documentation/assets/14852634/42e27fd4-5c67-4ceb-aae3-8f25315f7aae"> This top-level folder is useful because it reduces noise in the `docs/` folder. It makes it more obvious to the team what is the original source docs vs. what is translations and should not be modified directly in this repository. ### How this works with the app To get docs previews working in this repo, we teach the Docker image to mount `translations/` as if its contents were in the folder `docs/`, since the application expects all content to live there. When we sync the translations from open-source to closed-source for production, we will copy the contents of `translations/` so that it actually lives underneath `docs/`. For example, `translations/es/support.mdx` becomes `docs/es/support.mdx`. ## Locales As explained in Qiskit#7, we generally want to use the two-letter code for languages, like `es` and `fr`. The only exception is Chinese, where we need to distinguish between Traditional and Simplified. This config works with that, so long as in Crowdin.com, the project sets up this Language Mapping under the Languages settings: <img width="475" alt="Screenshot 2023-12-20 at 5 59 19 PM" src="https://github.com/Qiskit/documentation/assets/14852634/adf643d1-716a-435c-9e32-9762c6570956"> ## Doesn't yet add `_languages.json` As explained in Qiskit#7, we will probably want a file like `_languages.json` that teaches the docs app what each language is, such as its name to show in the language toggle. That schema still needs to be finalized and it can be added in a follow up.
1 parent baf3eaf commit 3d7a8fb

File tree

8 files changed

+145
-1
lines changed

8 files changed

+145
-1
lines changed
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
# This code is a Qiskit project.
2+
#
3+
# (C) Copyright IBM 2023.
4+
#
5+
# This code is licensed under the Apache License, Version 2.0. You may
6+
# obtain a copy of this license in the LICENSE file in the root directory
7+
# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.
8+
#
9+
# Any modifications or derivative works of this code must retain this
10+
# copyright notice, and modified files need to carry a notice indicating
11+
# that they have been altered from the originals.
12+
13+
# This Action downloads the translations from Crowdin once a week.
14+
#
15+
# The Translations team requested the updates to be once a week because
16+
# they think it's a good balance between giving enough time for translations
17+
# vs. the docs becoming out-of-date. This schedule can be revisited with
18+
# the Translations team.
19+
#
20+
# We may also want to have per-language configuration. For example, one language
21+
# is updated every week, whereas another every two weeks. But for now, all
22+
# languages are treated the same to keep things simple.
23+
24+
name: Download Crowdin translations
25+
on:
26+
schedule:
27+
- cron: "0 5 * * 1" # Every Monday at 5:00 am UTC
28+
workflow_dispatch:
29+
30+
jobs:
31+
download-translations:
32+
if: github.repository_owner == 'Qiskit'
33+
runs-on: ubuntu-latest
34+
permissions:
35+
contents: write
36+
pull-requests: write
37+
steps:
38+
- name: Checkout
39+
uses: actions/checkout@v4
40+
- name: Download translations
41+
uses: crowdin/github-action@v1
42+
with:
43+
upload_sources: false
44+
upload_translations: false
45+
download_sources: false
46+
download_translations: true
47+
project_id: ${{ secrets.CROWDIN_PROJECT_ID }}
48+
token: ${{ secrets.CROWDIN_PERSONAL_TOKEN }}
49+
env:
50+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
# This code is a Qiskit project.
2+
#
3+
# (C) Copyright IBM 2023.
4+
#
5+
# This code is licensed under the Apache License, Version 2.0. You may
6+
# obtain a copy of this license in the LICENSE file in the root directory
7+
# of this source tree or at http://www.apache.org/licenses/LICENSE-2.0.
8+
#
9+
# Any modifications or derivative works of this code must retain this
10+
# copyright notice, and modified files need to carry a notice indicating
11+
# that they have been altered from the originals.
12+
13+
# This Action uploads the English documentation to Crowdin so that it can be
14+
# translated.
15+
#
16+
# We upload on every merge to `main` rather than batching changes.
17+
# The Translations team prefers that workflow: it lets them get
18+
# started on changes right away and makes the changes less
19+
# overwhelming since they're smaller.
20+
21+
name: Upload English to Crowdin
22+
on:
23+
push:
24+
branches: [main]
25+
paths:
26+
- "docs/**/*"
27+
- "!docs/api/qiskit/**/*"
28+
- "!docs/api/qiskit-ibm-runtime/**/*"
29+
- "!docs/api/qiskit-ibm-provider/**/*"
30+
workflow_dispatch:
31+
32+
jobs:
33+
upload-english:
34+
if: github.repository_owner == 'Qiskit'
35+
runs-on: ubuntu-latest
36+
steps:
37+
- name: Checkout
38+
uses: actions/checkout@v4
39+
- name: Upload English
40+
uses: crowdin/github-action@v1
41+
with:
42+
upload_sources: true
43+
upload_translations: false
44+
download_sources: false
45+
download_translations: false
46+
project_id: ${{ secrets.CROWDIN_PROJECT_ID }}
47+
token: ${{ secrets.CROWDIN_PERSONAL_TOKEN }}

.github/workflows/staging.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ on:
2424

2525
jobs:
2626
deploy:
27-
if: github.repository
27+
if: github.repository_owner == 'Qiskit'
2828
uses: Qiskit/gh-actions/.github/workflows/code-engine-preview.yml@main
2929
with:
3030
code_engine_project: qiskit-docs-preview

Dockerfile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
FROM icr.io/quantum-computing/iqp-channel-docs-dev
3535

3636
COPY docs/ /home/node/app/docs
37+
COPY translations/ /home/node/app/docs
3738
COPY public/images /home/node/app/public/images
3839

3940
EXPOSE 3000 5001

README.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,18 +87,27 @@ The local preview does not include the initial index page and the top nav bar fr
8787
- http://localhost:3000/api/qiskit-ibm-provider
8888
- http://localhost:3000/api/migration-guides
8989

90+
For historical API versions, use URLs like http://localhost:3000/api/qiskit/0.44, i.e. put the desired version after the
91+
API name.
92+
93+
For translations, put the language code in front of the URL, like http://localhost:3000/es/start or http://localhost:3000/fr/start. You can find the language codes by looking in the `translations/` folder.
94+
9095
## Preview the docs in PRs
9196

9297
Contributors with write access to this repository can use live previews of the docs: GitHub will deploy a website using your changes.
9398

9499
To use live previews, push your branch to `upstream` rather than your fork. GitHub will leave a comment with the link to the site. Please prefix your branch name with your initials, e.g. `EA/fix-build-typo`, for good Git hygiene.
95100

101+
The preview application's UI is currently out-of-date so it does not properly show certain navigation like historical API versions. Refer to [Preview the docs locally](#preview-the-docs-locally) for instructions on how to explicitly visit pages.
102+
96103
## Staging
97104

98105
We also re-deploy the docs every time we merge into `main` at the site https://qiskit-docs-preview-staging.1799mxdls7qz.us-south.codeengine.appdomain.cloud.
99106

100107
This staging environment can be useful to see how the docs are rendering before we push it live to production.
101108

109+
The staging application's UI is currently out-of-date so it does not properly show certain navigation like historical API versions. Refer to [Preview the docs locally](#preview-the-docs-locally) for instructions on how to explicitly visit pages.
110+
102111
## Execute notebooks
103112

104113
To execute notebooks in a fixed Python environment, first install `tox` using

crowdin.yml

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# Refer to https://developer.crowdin.com/configuration-file/.
2+
3+
"preserve_hierarchy": true
4+
5+
files:
6+
[
7+
{
8+
"source": "docs/**/*",
9+
"translation": "translations/%two_letters_code%/%original_path%/%original_file_name%",
10+
"ignore":
11+
[
12+
"docs/api/qiskit/**/*",
13+
"docs/api/qiskit-ibm-runtime/**/*",
14+
"docs/api/qiskit-ibm-provider/**/*",
15+
],
16+
"translation_replace": {
17+
# We don't want to include the `docs/` folder in each of our translated
18+
# language folders.
19+
"docs/": "",
20+
},
21+
},
22+
]

start

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,22 @@
1313

1414
import subprocess
1515
from pathlib import Path
16+
from typing import Iterator
1617

1718
PWD = Path(__file__).parent
1819

1920

21+
def translation_volume_mounts() -> Iterator[str]:
22+
"""Return the CLI args to mount each language in the translations/ folder.
23+
24+
Unlike the root `Dockerfile`, we cannot use `-v $PWD/translations:/home/node/app/docs` because
25+
Docker complains that the volume is already mounted when we mount the `/docs` folder. So, instead
26+
we need to be more specific to mount each language's folder.
27+
"""
28+
for folder in PWD.glob("translations/*"):
29+
yield from ["-v", f"{folder}:/home/node/app/docs/{folder.name}"]
30+
31+
2032
def main() -> None:
2133
subprocess.run(
2234
# Keep this aligned with the Dockerfile at the root of the repository.
@@ -25,6 +37,7 @@ def main() -> None:
2537
"run",
2638
"-v",
2739
f"{PWD}/docs:/home/node/app/docs",
40+
*translation_volume_mounts(),
2841
"-v",
2942
f"{PWD}/public/images:/home/node/app/packages/preview/public/images",
3043
"-p",

translations/placeholder.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Remove me once actual translations exist. This is only so that the translations/ folder
2+
is saved with Git.

0 commit comments

Comments
 (0)