Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
7478c02
Prepare the site for translation
lmac-1 Sep 30, 2026
ed1912d
Keep homepage highlight links in the reader's locale
lmac-1 Sep 30, 2026
3e8470e
Ask before editing sidebars-adaptors.js
lmac-1 Sep 30, 2026
c31e740
Merge pull request #878 from OpenFn/i18n-setup
lmac-1 Sep 30, 2026
df94414
Turn on Spanish without linking to it
lmac-1 Sep 30, 2026
aa0d453
Explain how to run the site in Spanish locally
lmac-1 Sep 30, 2026
d3e0675
Close the Workflows callout with :::
lmac-1 Sep 30, 2026
c953079
Mark state as the state object on the terminology page
lmac-1 Sep 30, 2026
2f55953
Split the translate skill into pages and interface tasks
lmac-1 Sep 30, 2026
e064029
Say where the translate skill records problems in the English
lmac-1 Sep 30, 2026
17a8e80
Keep custom code.json strings and format the translate skill
lmac-1 Sep 30, 2026
e877ad6
Merge pull request #880 from OpenFn/translate-skill-split
lmac-1 Sep 30, 2026
260d4e0
Keep the blog and articles titles in the translate skill
lmac-1 Sep 30, 2026
485dbae
Let project, credential, collection and operation be translated
lmac-1 Oct 1, 2026
d0fa81e
Add project, credential, collection and operation back to the glossary
lmac-1 Oct 1, 2026
4b50306
Merge branch 'main' into i18n
lmac-1 Oct 1, 2026
51ba069
Translate only changed blocks, and add a side-by-side review script
lmac-1 Oct 1, 2026
3c97a9f
Show the old translation and a word diff for changed blocks
lmac-1 Oct 1, 2026
62e87fe
Show review blocks stacked, English above the translation
lmac-1 Oct 1, 2026
5364ef8
Give each locale a house style guide for translation
lmac-1 Oct 1, 2026
6f78f9d
Drop the entregables translation rule
lmac-1 Oct 1, 2026
4d2610f
Restore the rules key in translation-rules.yml
lmac-1 Oct 1, 2026
ba47041
Apply new translation rules without retranslating whole pages
lmac-1 Oct 1, 2026
4795435
Add a review-translation skill
lmac-1 Oct 1, 2026
f441c65
Merge remote-tracking branch 'origin/main' into i18n
lmac-1 Oct 1, 2026
3d453e0
Check that the branch has the latest main before translating
lmac-1 Oct 1, 2026
4c3fcc5
Commit a translation before reviewing it, and check every block
lmac-1 Oct 1, 2026
ce3ea96
Trim the translate skills and drop the HTML review view
lmac-1 Oct 2, 2026
7d43153
Keep glossary terms in English unless locales gives a word
lmac-1 Oct 2, 2026
2b4713e
Merge branch 'main' into i18n
lmac-1 Oct 2, 2026
ca715a4
Add the language dropdown to the navbar
lmac-1 Oct 2, 2026
96b7432
Merge branch 'main' into i18n
lmac-1 Oct 2, 2026
ef4182b
Check for rule changes by commit ancestry, not commit time
lmac-1 Oct 5, 2026
fdffd1b
Update translations from a git diff of the English, and fix the check…
lmac-1 Oct 5, 2026
aa8b7fb
Remove the unused tagline from the site config
lmac-1 Oct 5, 2026
f5ac477
Rename side-by-side.js to check-translation.js
lmac-1 Oct 5, 2026
bc04193
Note in AGENTS.md that the build covers every locale
lmac-1 Oct 5, 2026
73969a9
Translate docs into Spanish using our /translate skill (#884)
lmac-1 Oct 6, 2026
c637ea7
Fix the Spanish roadmap anchors that included link URLs
lmac-1 Oct 6, 2026
e261053
Tidy the translate skills after the Spanish rollout
lmac-1 Oct 6, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
116 changes: 116 additions & 0 deletions .agents/skills/review-translation/SKILL.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
---
name: review-translation
description:
Checks translated docs pages against the English in a fresh session, fixes
clear problems (changed meaning, literal phrasing, broken house style rules),
and reports the rest. Does not commit or open a PR. Use after /translate
pages, once the section is committed.
disable-model-invocation: true
---

# Review a translation

Run `/review-translation <scope>` in a fresh session, not the one that
translated the pages: a translator is poor at spotting its own mistakes. Commit
the translation first, so the review's fixes show up as their own diff. The
scope is the same as for `/translate pages`: one page, one folder under `docs/`,
or one sidebar category. If no scope is given, ask.

The review checks against the rules the translator followed: "How to translate"
in `.agents/skills/translate/SKILL.md`, the house style in
`.agents/skills/translate/<locale>.md`, the rules for the locale in
`translation-rules.yml`, and `glossary.yml`.

The review fixes clear problems in `machine` pages and reports the rest. It does
not commit, open a PR, or add rules. Never edit a `human-reviewed` page or a
fenced block; report the problem instead.

## 1. Lay out the pages

Read each translated page next to its English page in `docs/`. The translation
keeps the same structure, so the blocks line up in order.

Then read the rules listed above.

## 2. Search for rule breaks

These need no judgement, so search for them across the whole scope rather than
reading for them:

- Run the check:

```bash
node .agents/skills/translate/check-translation.js <locale> docs/<path>.md...
```

Each block it lists is a candidate, not a verdict: read it against the
English. It skips rules with their context in brackets, like "upgrade (a
plan)", so search for those by hand.

- Punctuation `<locale>.md` rules out, such as curly quotes.
- English terms kept from `glossary.yml` written with a capital mid-sentence, if
`<locale>.md` says to lower-case them. Case-sensitive terms (OpenFn, Canvas,
Inspector) and names of things in the app keep their capitals.

## 3. Read each block against its English

Check that the translation:

- **Says the same thing.** Nothing added, dropped, or softened. Numbers, dates,
limits, and "must", "should", and "can" match, and so does who does what.
- **Reads naturally.** No word-for-word phrasing, repeated subjects, stacked
nouns, or asides that repeat the sentence.
- **Uses the right voice**, as `<locale>.md` sets it. In Spanish, watch for verb
forms that read as "usted".
- **Keeps names of things in the app** exactly as in the English, and keeps
links and inline code the same.
- **Is consistent across the scope.** The same English term gets the same
translation on every page.

Do not flag wording you would only have written differently. If the English
itself is wrong or unclear, note it under "Problems in the English" and leave
the translation matching it.

## 4. Fix what is clear

Fix a block when the problem and the fix are both clear. Change only the words
that are wrong, so the diff shows just the fix. Leave the front matter alone.
Then run `yarn prettier --write <files>` on the pages you changed, and run the
check again.

## 5. Report

Build the site and serve it (`yarn serve`), so each item can point to the page
as the reader sees it. Report in the chat. Place each item by the page URL, such
as `http://localhost:3000/es/documentation/build/triggers`, and the section
heading, not by file and line. Group the items like this:

- **Fixed.** For each fix, give the English sentence, the translation before,
and the translation after, all in full, with the changed words in bold. Then
say why in one line.
- **Needs a decision.** Problems you were not sure how to fix, or where the fix
changes meaning. Quote the English and the current translation.
- **Problems in the English.**
- **Suggested rules.** A problem found on more than one page, or likely to come
back in later sections, with the line you would add to `<locale>.md` or
`translation-rules.yml`. Add it only if asked.
- **Page to spot-check.** The page with the most fixes, with its URL.

## Marking a page human-reviewed

Only a person who reads the language well marks a page `human-reviewed`. It
means they checked the meaning against the English, not only that the
translation reads well: a page can read perfectly and still say something
different. With the translated page open next to the English one on the built
site, they check every paragraph for the points in step 3, fix what is wrong,
and then set in the front matter:

```yaml
translation_review_status: human-reviewed
translation_reviewer: <GitHub handle>
translation_review_date: <YYYY-MM-DD>
```

A fix that would apply to other pages goes into `<locale>.md` or
`translation-rules.yml` too. A `human-reviewed` page is never retranslated in
full again; changes to its English come to the reviewer as a separate PR.
161 changes: 51 additions & 110 deletions .agents/skills/translate/SKILL.md
Original file line number Diff line number Diff line change
@@ -1,136 +1,76 @@
---
name: translate
description:
Translates English docs pages into Spanish and French under i18n/, respecting
glossary.yml, translation-rules.yml, review status, and do-not-retranslate
fences, and opens one PR per locale. Use when asked to translate or refresh
translations.
Translates the docs under i18n/ into each language enabled in
docusaurus.config.js, either a set of English pages or the interface text
(navbar, footer, sidebar headings, homepage). Respects glossary.yml,
translation-rules.yml, each locale's house style, review status, and
do-not-retranslate fences, and opens one PR per locale. Use when asked to
translate or refresh translations.
disable-model-invocation: true
---

# Translate

Translate English docs into Spanish (`es`) and French (`fr`). The English is
always the source of truth. Translations are generated files that live in this
repo. Save each one at the same path as the English page, under
`i18n/<locale>/docusaurus-plugin-content-docs/current/`. For example,
`docs/build/triggers.md` goes to
`i18n/es/docusaurus-plugin-content-docs/current/build/triggers.md`. Docusaurus
ignores a file anywhere else without an error, and the page stays English.
Translate English docs into each locale in `i18n.locales` in
`docusaurus.config.js`, other than English. The English is always the source of
truth. Translations are generated files that live in this repo, under
`i18n/<locale>/`.

The sidebar headings come from `sidebars-main.js`, not from the pages. If it has
new or renamed entries, run
`yarn docusaurus write-translations --locale <locale>`. This adds them to
`i18n/<locale>/docusaurus-plugin-content-docs/current.json` in English and keeps
the ones already translated. Translate the new ones.
There are two tasks. Each has its own file in this folder; read the one you
need.

- **`/translate pages <scope>`** translates a set of pages. The scope is one
page, one folder under `docs/`, or one sidebar category. With no scope, it
covers every page that needs it. See `pages.md`.
- **`/translate interface`** translates the text that is not in a page: the
navbar, footer, sidebar headings, and homepage. Run it when
`sidebars-main.js`, the navbar or footer in `docusaurus.config.js`, or any
`<Translate>` text in `src/` has changed. See `interface.md`.

If you are not told which task, work out which ones are needed from what has
changed in English, say so, and ask before starting.

Never translate the generated adaptor pages, the job library, the old v1 docs,
or articles and blog posts.

## Before you start

Check these three things. If any fails, stop and ask.
Check these five things. If any fails, stop and ask.

- The locale is enabled in `docusaurus.config.js`. Do not enable it yourself;
that changes what gets deployed.
- `i18n/` is not in `.gitignore`.
- `glossary.yml` and `translation-rules.yml` are valid YAML.

Translate the English page exactly as it is on disk, so the hash you record
matches what you translated. Do not reformat it; English changes belong in their
own PR. After writing the translation, run `yarn prettier --write <files>` on
only the files you changed under `i18n/`.

## Front matter

Copy the English page's front matter. Translate only `title` and
`sidebar_label`. Then add:

```yaml
translation_source_hash: <git hash-object of the English file>
translation_review_status: machine
```

The hash is the content hash of the English file, from
`git hash-object docs/<path>.md`, not a commit. Commits do not survive squash
merges: a hash pointing at a commit made on a branch dangles as soon as the
branch is squashed onto main. A content hash is the same wherever the file
lives, and it answers the only question the field exists to answer: is the
English still the version this was translated from? To compare, hash the current
English file and check it against the recorded value.

`translation_review_status` can be `machine`, `needs-review`, or
`human-reviewed`. Only a human ever sets `human-reviewed`, and when they do they
also add `translation_reviewer` and `translation_review_date`.

## Decide what to do with each page

- **No translation yet.** Translate the whole page.
- **The hash matches the current English file.** Skip it, whatever its status.
The English has not changed since it was translated. The one exception: if
`glossary.yml` or `translation-rules.yml` was committed more recently than the
translation (compare `git log -1 --format=%ct -- <file>`), treat a `machine`
page as if the hash no longer matches, so it picks up the new rules.
- **The hash no longer matches, and the status is `machine`, `needs-review`, or
missing.** Translate the whole page again, but keep any fenced blocks (see
below) exactly as they were.
- **The hash no longer matches, and the status is `human-reviewed`.** Leave the
file out of the translation PR. Instead, open a separate PR for the named
reviewer that changes only the affected parts. Recover the English the
reviewer saw with `git cat-file -p <recorded hash>`, diff it against the
current English, and translate only what changed. In the same PR, set
`translation_source_hash` to the current English hash and leave the status as
`human-reviewed`: the reviewer merging it approves it. If the old version is
no longer in the repo, say so and offer a full retranslation in that PR
instead.

## Fenced blocks

A human can wrap part of a translation like this:

```markdown
<!-- do-not-retranslate -->
Text a reviewer has corrected by hand.
<!-- /do-not-retranslate -->
```

Copy those blocks into the new translation exactly, in the same place. If the
English they correspond to has been deleted, keep the block anyway and ask what
to do with it.
- The locale has a house style guide, `<locale>.md`, in this folder.
- Your branch has everything on `main`. Run `git fetch origin main` and then
`git merge-base --is-ancestor origin/main HEAD`. If it fails, the English you
would translate is out of date, and the hashes you record will not match
`main`. Ask to merge `main` in first. If your branch comes off another branch,
merge `main` into that one, then that one into yours.

## How to translate

- Words in `glossary.yml` stay in English. For ordinary words that are also
product terms, like "run" or "step", keep the English only when the word means
the OpenFn thing.
- Follow any rules for the locale in `translation-rules.yml`. By default,
Spanish uses "tú" and French uses "vous".
- Copy code blocks and inline code exactly. You may translate comments inside
code.
These apply to both tasks.

- Terms in `glossary.yml` stay in English, unless the term lists a word for the
locale under `locales`, such as `es: proyecto`. For ordinary words that are
also product terms, like "run" or "step", keep the English only when the word
means the OpenFn thing.
- Follow the house style for the locale in `<locale>.md` in this folder, such as
`es.md`, and any rules for the locale in `translation-rules.yml`.
- Write the way a native writer would, not word for word. Reorder or split a
sentence when the literal version is awkward, drop a subject the sentence has
already given, and cut an aside that repeats what the sentence says. Keep the
meaning and the facts; change only the wording.
- Copy code blocks and inline code exactly, comments included.
- Keep the names of things in the app, like buttons, menus, tabs, and field
labels, exactly as they are in the English. The app is English only, so a
translated button name points the reader at a button that does not exist.
- Keep the same structure: same headings at the same levels, same lists, same
callouts, same components.
- Keep links exactly as they are in the English. Do not add `/es/` or `/fr/`;
Docusaurus adds the locale when it builds the page. If the English has a
relative link like `../deploy/portability.md`, it breaks the translated build,
so fix it in the English first (see `STYLE.md`).
- Give translated headings the original English anchor so existing links still
work.

## Before you commit

Check that the fixed glossary terms (the ones without `product_noun: true`, such
as OpenFn, Lightning, adaptor, webhook) appear as many times as in the English.
Product nouns like "run" and "step" are allowed to differ, since their
ordinary-English uses get translated. Before counting, join each file into one
line with single spaces: Prettier wraps prose at 80 columns, and English and
Spanish wrap at different points, so a multi-word term like "work order" can sit
across a line break in one file and not the other. Check the code blocks are
identical. Check the counts of headings, code blocks, callouts, images, and
tables match. Check the front matter is complete. Check every fenced block
survived. Then build the site and make sure it passes:

## Before you open the PR

Build the site and make sure it passes:

```bash
yarn generate-library
Expand All @@ -144,6 +84,7 @@ broken.

Open one PR per locale, separate from the English PR. Translated files do not
count toward the 20-file limit, because a locale's translations are reviewed as
a set. In the PR description, say which tool and model translated the pages. If
you spot a problem in the English while translating, note it for the next
English pass; do not fix it here.
a set. In the PR description, say which tool and model translated the text. If
you spot a problem in the English while translating, list it in the PR
description under "Problems in the English", with the file and line. Do not fix
it in this PR.
Loading