diff --git a/.agents/skills/accuracy-check.md b/.agents/skills/accuracy-check.md new file mode 100644 index 000000000000..7d1ae90913ea --- /dev/null +++ b/.agents/skills/accuracy-check.md @@ -0,0 +1,52 @@ +# Accuracy check + +Go through a page and check that everything it claims is actually true in the +code. + +## Where to look + +- Anything about the web app, its screens, settings, or API: `OpenFn/lightning`. +- Anything about the CLI, deploying, `project.yaml`, or how job code is + compiled: `OpenFn/kit`. +- Anything about a specific adaptor's functions or credentials: + `OpenFn/adaptors`, under `packages//`. + +Use the main branch unless the page names a version. Write down which commit +you checked against. + +## Steps + +1. **List the claims.** Read the page and number every statement a reader + could act on: code samples, function names and arguments, button and menu + names, settings and their defaults, version numbers, file paths, limits. + Skip the motivational text and the "in v1 this used to be" notes. +2. **Check each one.** Find the code that backs it up and note the file and + line. For job code samples, run `openfn compile` to make sure they at least + compile. Only run commands that read; never deploy, delete, or hit a live + OpenFn instance. If a name is missing from the code, look at the git + history in case it was renamed. +3. **Mark each claim** pass, fail, or uncertain. Uncertain covers things you + cannot verify from code: values set per deployment, anything that needs a + running system, pricing, and policy. Those belong to the product team. +4. **Decide what to do about failures.** Fix it if the right value drops + straight into the sentence (a flag name, a default, a label). Suggest it if + the paragraph would need rewriting. Ask if you cannot tell whether the docs + or the code is the one that is wrong, and say which you suspect. + +## Generated adaptor pages + +The pages under `adaptors/packages/` are built from code comments in +`OpenFn/adaptors`. Do not edit them here. Instead, find the comment in +`packages//src/` and write up an issue: the page URL, the source file +and line, what the docs say, what the code does, and the corrected comment. +Put it in the PR under "Upstream issues". Only file it if the user asked you +to. + +If a hand-written overview page (`adaptors/.md`) repeats the same +mistake, fix that one normally. + +## What to report + +For each page: the commits you checked, how many claims passed, failed, or +were uncertain, a table of the claims with their evidence, and the findings +in the standard format. Apply your fixes, run Prettier, and run `yarn build`. diff --git a/.agents/skills/fresh-user-eval.md b/.agents/skills/fresh-user-eval.md new file mode 100644 index 000000000000..50f4b0a2ed9d --- /dev/null +++ b/.agents/skills/fresh-user-eval.md @@ -0,0 +1,59 @@ +# Fresh-user evaluation + +Read one page as if you had never heard of OpenFn, then try to do what it +says. The point is to find where a newcomer would get lost. Run this after the +accuracy check, so the facts are already right. + +## Steps + +1. **Read it cold.** Pretend you know what an API, a webhook, JSON, and a + terminal are, and nothing else. Do not follow links. Do not look at the + page's history. When you finish, write one sentence saying what the page + teaches and who it is for. If you cannot, that is your first finding. + +2. **Try to do it.** + - If it is a how-to, follow the steps. For anything in the web app, check + the button or screen really exists in the Lightning code. For CLI steps, + run the commands. + - If it explains a concept, explain it back in two sentences. Then think of + three questions a newcomer would ask and see if the page answers them. + - If it is a reference table, pick three rows and see if you could use each + one from its description alone. + + Every time you have to guess what a word means, cannot find what the page + points at, read a sentence two ways, need something the page assumed you + had, find the steps in the wrong order, or cannot tell whether you + succeeded, write it down. + +3. **Check your guesses** against the code or nearby pages. If you guessed + wrong, the page definitely needs that information. If you guessed right, it + probably still does. + +## Sorting the findings + +- **Fix**: one missing fact that fits in one sentence and that you have + verified. Add it. +- **Suggestion**: anything bigger, such as a new subsection, an example, or a + rewrite. Propose the text but do not add it. +- **Question**: you could not find the answer, or it depends on who the page + is for. + +Do not touch the tone or voice. + +## Scores + +Give two scores from 1 to 5, each with a one-sentence reason. + +- **Readability.** 5: understood everything on one read. 3: got the gist but + had to work at it. 1: could not follow it without outside knowledge. +- **Completeness.** 5: could finish the task from this page alone and knew + when I was done. 3: got there, but only by following links or guessing. + 1: the page does not actually say how to do it. + +## What to report + +What the page teaches, who it is for, what you tried, your findings in the +standard format, and the two scores. + +Do not evaluate the generated adaptor pages. Do not write a new page; if the +page a user needs does not exist, that is a job for gap analysis. diff --git a/.agents/skills/gap-analysis.md b/.agents/skills/gap-analysis.md new file mode 100644 index 000000000000..b95d1df7b590 --- /dev/null +++ b/.agents/skills/gap-analysis.md @@ -0,0 +1,69 @@ +# Gap analysis + +Work out what a section of the docs should cover but does not. Produce a +ranked list. Do not write the missing pages unless you are asked to. + +## Steps + +1. **List what the docs cover.** For every page in the section, note what it + explains, using the headings and tables. Also note where it links out to + other sections, and check those pages exist. + +2. **List what the product has.** Look at the part of the code that matches + the section. For the web app, that is the routes and screens in + `OpenFn/lightning`. For the CLI, read `packages/cli/src/cli.ts` and + `commands.ts` in `OpenFn/kit`; that is where commands are registered, and + it shows things `--help` hides. Use `openfn --help` only as a fallback if + the CLI happens to be installed. For job writing, look at what + `packages/common` exports in `OpenFn/adaptors`. For deployment, read + `DEPLOYMENT.md` and the runtime config in Lightning. + + If you cannot reach the repo you need, say so in the report and skip that + part. Do not fill the gap from memory. + +3. **Compare the two lists.** Before you call anything a gap, search the + whole docs folder, the articles, and the adaptor overviews. It might be + documented somewhere else. Search for the thing as a user would type it, + not the bare noun: "openfn metadata" settles the question in one hit, + while "metadata" matches twenty pages of ordinary prose. Label each gap + as one of: + - **Missing page**: nothing in the docs mentions it. + - **Partial page**: the right page exists but does not cover this. + - **Misplaced**: it is documented, but not where a user would look. + - **Stale**: it describes an old version. Hand these to the accuracy check. + + Also note anything the docs describe that the product no longer has. + +4. **Look for user evidence**, if you have access to it: issues on the docs + repo, the community forum, support channels, search analytics. Count how + often a topic comes up. Do not quote anyone. If you have no access, say so, + and do not make up demand. + +5. **Rank.** Score each gap from 1 to 5 on three things: how many users it + affects, how bad it is to be without it, and how much evidence you have + that people want it. Add those three up; that is the impact score, and + you sort by it. Separately, score how easy it is to write (5 means a + paragraph, 1 means a whole tutorial) and show it in its own column. Use + ease only to break ties. Folding it into the sum lets a trivial gap + nobody asked for outrank a genuinely undocumented feature. + +## What to report + +For each gap: its label, its impact score and ease score, what is missing, +your evidence, where it should go (which file, and where in the sidebar or +which heading), and a rough outline. Put the top ten in the PR description +and collapse the rest. + +The report is the deliverable. A normal run of this skill opens a PR with an +empty or near-empty diff and a long description. That is expected. + +## What you may change + +Only one thing: add a single sentence linking to a page that clearly already +covers the topic. Everything else is a suggestion. + +Thin generated adaptor pages are not gaps here; they are code-comment issues +for `OpenFn/adaptors`. If a feature is behind a feature flag, or a command is +deliberately hidden in code (for example a CLI command with `describe: +false`), it is not a gap. Do not propose documenting it. Note it and ask the +product team if it looks like it should be public. diff --git a/.agents/skills/lint.md b/.agents/skills/lint.md new file mode 100644 index 000000000000..d4fa4bd812b2 --- /dev/null +++ b/.agents/skills/lint.md @@ -0,0 +1,55 @@ +# Lint + +Run this first on any section. These are mechanical checks. Most of what you +find, you can fix on the spot. + +Before you start, read `glossary.yml` (the approved terms) and +`style-exceptions.yml` (things humans have told us not to flag). Skip any +finding that matches an exception. + +Do not lint the generated adaptor pages, the old v1 docs, or translations +marked human-reviewed. + +## What to check + +Only look at prose. Ignore code blocks, URLs, and front matter. + +1. **Terminology.** If a page uses a spelling listed under `variants` in the + glossary, replace it with the approved term. Always change "adapter" to + "adaptor". Fix. Multi-word terms can be split across a line break by + Prettier's wrapping, so match against text with newlines collapsed to + spaces. +2. **Headings.** No `#` headings in the body (the title comes from front + matter). No jumping from `##` to `####`. No two headings with the same + text. Fix. If a page mixes Title Case and sentence case, suggest a change + rather than making it, because headings double as link anchors. +3. **Internal links.** Every link to another docs page must work. The easiest + way to check is `yarn build`, which fails on broken links. Fix it if the + right target is obvious. Otherwise ask. +4. **External links.** Try each one twice. A 404 or 410 means it is dead. + Replace it if there is a clear replacement; otherwise suggest removing it. + A 403 or 429 does not mean dead, so leave those alone and note them. +5. **Orphan pages.** A page that is not in any sidebar and not linked from + anywhere. Suggest adding or removing it. Do not decide yourself; someone + might be drafting it. +6. **Front matter.** Must be valid YAML and must have a `title`. If the title + is missing, take it from the page's first heading. Fix. +7. **Code blocks.** Every fenced block needs a language: `js`, `json`, + `yaml`, `bash`, or `text`. Fix. +8. **Alt text.** Every image needs alt text that says what the image shows. + "Screenshot" does not count. Write it from the surrounding paragraph. Fix. +9. **Callouts.** `:::tip` and similar blocks need a blank line after the + opening and before the closing. Fix. + +## How to fix + +Change only the line with the problem. When you are done, run Prettier on the +files you touched, then `yarn build`. Do not commit until both are clean. + +## What to report + +Give the counts (files checked, fixes, suggestions, questions), then one line +per finding in the standard format. + +If a reviewer undoes one of your fixes, do not push back. Suggest they add an +entry to `style-exceptions.yml` so it is not flagged again. diff --git a/.agents/skills/release-review.md b/.agents/skills/release-review.md new file mode 100644 index 000000000000..5c6406f31f0f --- /dev/null +++ b/.agents/skills/release-review.md @@ -0,0 +1,80 @@ +# Release review + +Look at what the product shipped recently and make sure the docs caught up. +With no arguments, review every release in `OpenFn/lightning`, `OpenFn/kit`, +and `OpenFn/adaptors` from the last month. Someone can narrow it to one repo, +a date range, a release tag, or a single PR. + +This is the inverse of the accuracy check. That skill starts from a docs page +and looks for the code. This one starts from what changed in the code and +looks for the docs. + +## Two repos are involved + +The releases live in the product repos. The docs live here. You need both. + +- **Running in the docs repo** (the usual case): clone each product repo you + need into a scratch directory outside this one. Fetch tags. Do not modify + the product repos. +- **Running inside a product repo** (someone asks "did the docs keep up with + this release?"): clone `OpenFn/docs` into a scratch directory and do the + same work. Docs changes always go in a branch and PR on the docs repo. + +Say at the top of your report which repos, tags, and dates you covered. + +## Steps + +1. **Start from the changelogs, not the diffs.** Each repo keeps one: + Lightning has a single `CHANGELOG.md`; kit and adaptors have one per + package under `packages//CHANGELOG.md`. Read every entry released in + the period. These are already a curated list of user-facing changes, so + they are cheaper and more reliable than reading every PR. Skip the + Unreleased section; docs describe what has shipped. + +2. **Turn each entry into a plain statement of what changed for a user**: a + new feature, a renamed button, a new CLI flag, a changed default, a removed + option, a new setting. Drop entries that are internal (refactors, + dependency bumps, test changes). If an entry is too vague to act on, open + the PR it links to and read the diff. Only then. + +3. **Find the docs that talk about it.** For each change, search `docs/`, + `articles/`, and `adaptors/*.md` for the feature, the old and new names, + the flag, or the setting. Search for things the way a user would type + them ("openfn pull --beta", not "beta"). Note every page and line. + +4. **Decide what each page needs.** + - **Now wrong.** The docs describe the old behaviour. Fix it if the new + behaviour is clear and slots into the existing sentence. Otherwise + suggest wording. + - **Now incomplete.** The page is still right but does not mention the new + thing. Suggest where the paragraph or table row goes and draft it. + - **Nothing in the docs.** A new feature with no home. Suggest a page or + section and a short outline. Do not write the page unless asked. + - **Screenshot affected.** The change alters a screen that appears in an + image. List the image for the retake list. Never retake it. + + A feature behind a feature flag, or a command hidden in code, is not a + docs gap. Note it and ask the product team if it looks like it should be + public. + +## Adaptors are different + +Changes to adaptor functions flow into the docs automatically through the +generated reference pages, so you do not need to chase those. For adaptors, +ask only two questions: is there a new adaptor with no overview page in +`adaptors/`, and did a change break something a tutorial or guide relies on. + +## What to report + +Start with one paragraph: the repos and period covered, how many releases, +how many user-facing changes, and how many docs pages are affected. Then the +findings in the standard format, grouped by page. Finish with images that +need retaking and new pages that are needed. + +Apply the fixes, run Prettier and `yarn build`, and open a docs PR that links +to the releases it covers. Suggestions and questions go in the PR +description. If the period had no user-facing changes, say so and do not open +a PR. + +This skill suits a monthly schedule with default arguments, plus a manual run +after any large release. diff --git a/.agents/skills/screenshot-triage.md b/.agents/skills/screenshot-triage.md new file mode 100644 index 000000000000..91c580214326 --- /dev/null +++ b/.agents/skills/screenshot-triage.md @@ -0,0 +1,74 @@ +# Screenshot triage + +Find the screenshots most likely to be out of date and rank them so a human +can retake them. You never retake, edit, or delete an image yourself. + +By default, scan the whole repo. A ranking only means something across the +whole site. If the user names a page or section, limit the scan to the images +those pages use. + +You need a clone of `OpenFn/lightning` with full history, because the whole +method is about comparing dates. + +## Remembering what each image shows + +Keep a file called `screenshot-map.yml` at the repo root. For each image it +records what the image shows, which UI area that maps to, and how confident +you were. Read it at the start of every run. Only classify images that are +new, renamed, or missing from the file, then add them. Dates are always +recomputed; classifications are not. This makes a repeat scan of the whole +repo cheap. + +Humans can edit this file to correct a classification, and the correction +sticks. Put a short comment at the top explaining the format. + +## Steps + +1. **List the images.** For the whole repo, everything in `static/img/`, + noting any image no page uses. For a page or section, only the images + those pages link as `/img/...`. + +2. **Find out how old each image is** from its last commit in this repo. If + the last commit was a bulk optimisation that touched lots of images, look + at the one before it. + +3. **Work out what each image shows**, for images not already in + `screenshot-map.yml`. Use the file name, the alt text, and the paragraph + around it. Say how confident you are. Then match it to the part of the + Lightning code that draws that screen. Roughly: the workflow + canvas is under `assets/js/workflow-diagram`; the step editor, runs, + credentials, and project settings each have their own folder under + `lib/lightning_web/live/`; global styling is in `assets/css` and + `lib/lightning_web/components`. Screenshots of other products (Kobo, + DHIS2) have no matching code; mark them "external". + +4. **Find out when that part of the UI last changed.** Take the newest commit + touching the matching code, or the global styling, whichever is later. Skim + the commit messages since the image was taken and keep the ones that sound + visible to users (renamed, moved, redesigned, added a button). + +5. **Flag and rank.** An image is a suspect if the UI changed after it was + taken. Sort by the size of the gap, then by how many visible changes + happened in it, and give pages in Get Started and Tutorials a nudge up the + list. If you were not confident about what an image shows and it lands + near the top, say so. + +## What to report + +A table with: image, page and line, image date, what it shows and your +confidence, date of the last UI change, the gap in days, and what probably +changed. List external, unused, and diagram images separately. Put the top +fifteen in the PR and collapse the rest. + +Whole-repo scans are report-only apart from updating `screenshot-map.yml`. +When scoped to a page or section, you may also correct alt text that describes +an image wrongly. + +## Later: taking screenshots automatically + +Not built yet. Lightning already has Playwright browser tests under +`assets/test/e2e/specs/`. When those can produce screenshots, add a final +step: a mapping file that says which test reaches which screenshot, run the +test with a capture flag against a local Lightning, save the result over the +old image, and present the before-and-after in the PR as a suggestion for a +human to approve. diff --git a/.agents/skills/translate.md b/.agents/skills/translate.md new file mode 100644 index 000000000000..3e96a37082bd --- /dev/null +++ b/.agents/skills/translate.md @@ -0,0 +1,107 @@ +# 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, in the `i18n/` folder, mirroring the path of the English page. + +Never translate the generated adaptor pages, the job library, or the old v1 +docs. + +## Before you start + +Check these three 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 as it is on disk after any fixes and after +Prettier has run, so the hash you record matches what you translated. + +## Front matter + +Copy the English page's front matter. Translate only `title` and +`sidebar_label`. Then add: + +```yaml +translation_source_hash: +translation_review_status: machine +translation_model: +``` + +The hash is the content hash of the English file, from +`git hash-object docs/.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. +- **Translation exists, status is `machine` or `needs-review`.** Translate the + whole page again, but keep any fenced blocks (see below) exactly as they + were. +- **Translation exists but has no `translation_review_status`.** Treat it as + `machine` and regenerate it. +- **Status is `human-reviewed` and the hash matches the current English + file.** Skip it. It is up to date and approved. +- **Status is `human-reviewed` and the hash no longer matches.** Do not touch + the file. Recover the English the reviewer saw with + `git cat-file -p `, diff it against the current English, + translate only the changed parts, and open a separate PR with the proposed + diff for the named reviewer. If the old blob is no longer in the repo, + say so and offer a full retranslation as the suggested diff instead. + +## Fenced blocks + +A human can wrap part of a translation like this: + +```markdown + +Text a reviewer has corrected by hand. + +``` + +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. + +## 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. +- Keep the same structure: same headings at the same levels, same lists, + same callouts, same components. +- Add the locale to internal links (`/es/documentation/...`), except links + into the generated adaptor pages, which are English only. 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 that locale and make sure it passes. + +Open one PR per locale per section, separate from the English PR. Translated +files do not count toward the 20-file limit, because a section's translations +are reviewed as a set. If you spot a problem in the English while translating, +note it for the next English pass; do not fix it here. diff --git a/.gitignore b/.gitignore index a35029f45316..504d16736448 100644 --- a/.gitignore +++ b/.gitignore @@ -13,8 +13,7 @@ .docusaurus .cache-loader -# translation -/i18n +# translation: i18n/ is committed (translations are generated artefacts kept in-repo, see AGENTS.md) # Misc .DS_Store diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 000000000000..4227d03cd0ad --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,117 @@ +# Docs maintenance agent + +You look after the OpenFn documentation site. It is a Docusaurus project. You +work on one section of the docs at a time, and your job is to make that +section accurate, easy to follow, complete, and (once the English is right) +translated. + +The detailed instructions for each job live in `.agents/skills/`. Each one +stands alone; read the one you need. + +## What you can and cannot edit + +**Edit freely** + +- Everything in `docs/`. This is the English source of truth. +- `sidebars-main.js`, which controls the navigation. +- The adaptor overview pages in `adaptors/*.md`. + +**Do not edit** + +- Anything in `adaptors/packages/` or `adaptors/library/`. These pages are + built automatically from code comments in the `OpenFn/adaptors` repo. If + something is wrong there, the fix belongs in that repo, not here. +- Anything in `versioned_docs/`. These are the old v1 docs and are frozen. + +**Ask before editing** + +- `docusaurus.config.js`, `package.json`, and anything in `.github/`. These + change how the site builds and deploys. + +**Special rules apply** + +- Translations in `i18n/`. See `translate.md`. +- The three rule files: `glossary.yml`, `style-exceptions.yml`, and + `translation-rules.yml`. Humans maintain these. Each explains its format at + the top. Only add an entry if the user asks you to. + +To check facts, you can read the product code. Clone `OpenFn/lightning` (the +web app), `OpenFn/kit` (the CLI), and `OpenFn/adaptors` somewhere outside this +repo. Never change them. + +## The order of work + +1. **Lint.** Fix formatting, links, headings, and terminology. +2. **Accuracy check.** Make sure every claim matches the code. +3. **Fresh-user evaluation.** Read the page as a newcomer and see if it works. +4. **Gap analysis.** Work out what is missing from the section. +5. **Screenshot triage.** Scans the whole repo by default; runs on request + rather than every time. +6. **Translate**, in its own PR per locale. + +If the user asks for one skill only, run that one and still finish with a PR. + +One skill runs from the other direction. **Release review** starts from what +the product shipped, by default every release in the last month, and finds +the docs pages that need to change because of it. Run it on a monthly +schedule, or by hand after a big release, or narrowed to one PR if someone +asks. + +## Pick one section + +A section is one category from the sidebar, one folder under `docs/`, or one +page. Never work on the whole site at once. If the user has not said which +section, stop and ask. List the sidebar categories to make choosing easy. + +## Three kinds of finding + +Everything you notice falls into one of three buckets: + +- **Fix.** It is clearly wrong and you know the right answer from the code or + the build. Make the change. Keep it small. Do not rewrite a page's voice or + structure and call it a fix. +- **Suggestion.** It is a judgement call. Do not change it. Write up what you + would change and why in the PR description, so a human can decide. +- **Question.** The docs and the code disagree and you cannot tell which is + right, or the decision is not yours to make. Do not guess. Ask. + +If you are unsure which bucket something belongs in, pick the more cautious +one. + +Write findings like this: + +``` +[fix] docs/build/triggers.md:42 — flag is called --force, not -f — corrected +``` + +## Rules that never bend + +- Never edit a translated page marked `translation_review_status: + human-reviewed`. Offer a diff instead. +- Never edit generated adaptor pages. Draft an issue for `OpenFn/adaptors` + and put it in the PR. Only file it if asked. +- Never retranslate text inside `` fences. +- Never translate a term listed in `glossary.yml`. +- Never retake, crop, or replace screenshots. +- Never disable a check to make the build pass. + +## When to stop + +Stop when the section is finished, or when you have changed 20 files, +whichever comes first. Then open a PR. Translations are the exception: they go +in their own PR per locale and do not count toward the 20. + +Before you open it: run Prettier on the files you changed, run `yarn build` +(a broken link will fail the build), and read your own diff once more. + +Use the PR template in `.github/`. Tick "I have used Claude Code". Then add +sections for: what changed, suggestions, questions, what you skipped and why, +upstream issues, scores, gaps, and suspect screenshots. Leave out any that +are empty. + +## House style + +- Every page has a `title` in its front matter. +- Internal links start with `/documentation/`, `/adaptors/`, or `/articles/`. +- Images live in `static/img/` and are linked as `/img/filename`. +- It is spelled **adaptor**, never "adapter". diff --git a/docs/contribute/translating.md b/docs/contribute/translating.md new file mode 100644 index 000000000000..81596ba60b11 --- /dev/null +++ b/docs/contribute/translating.md @@ -0,0 +1,261 @@ +--- +id: translating +title: Translating the Docs +sidebar_label: Translating Docs +--- + +This page covers how translation is **wired into the site**: what the config +does, where files go, and the build behaviour that will bite you. It does not +cover how to translate a page — that is the `translate` skill in +`.agents/skills/translate.md`, and the vocabulary rules live in `glossary.yml` +and `translation-rules.yml`. + +Keep it that way. If you find yourself writing a terminology rule here, it +belongs in `glossary.yml` instead. + +| Where | What it decides | +| ----------------------------- | ------------------------------------------- | +| `.agents/skills/translate.md` | How a page gets translated, and when | +| `glossary.yml` | Which terms stay in English | +| `translation-rules.yml` | Locale phrasing, register, punctuation | +| `AGENTS.md` | Order of work, house style, what to edit | +| This page | How the site is built and served per locale | + +English is always the source of truth. Translated content lives under +`i18n//` and mirrors the English path. Anything not translated falls +back to the English page automatically, so partial coverage is a valid state — +no broken pages, no placeholders. + +:::tip Current status + +- `en` — source of truth, complete +- `es` — site chrome (navbar, footer, sidebar labels, homepage) plus **What is + OpenFn?**, **Try out v2**, **Key Concepts**, and **Get Help**. All four pages + were produced by the `translate` skill and are + `translation_review_status: machine`; none has been human-reviewed yet. +- `fr` — planned, not enabled + +::: + +## Enabling a locale + +`docusaurus.config.js` declares which locales exist: + +```js +i18n: { + defaultLocale: 'en', + locales: ['en', 'es'], + // ... +} +``` + +English is served from the site root (`/documentation/...`), Spanish from a +locale prefix (`/es/documentation/...`). A locale dropdown in the navbar +switches between them. + +**Enabling a locale is a human decision, not a translation step** — it changes +what gets built and deployed. The `translate` skill checks that the locale is +already enabled and stops if it is not. Adding French means editing +`i18n.locales` and `i18n.localeConfigs`, then running +`yarn docusaurus write-translations --locale fr`. + +## Where files go + +The path after `current/` must match the path after `docs/` exactly: + +| English source | Spanish translation | +| -------------------------- | -------------------------------------------------------------------- | +| `docs/get-started/home.md` | `i18n/es/docusaurus-plugin-content-docs/current/get-started/home.md` | +| `docs/get-help/support.md` | `i18n/es/docusaurus-plugin-content-docs/current/get-help/support.md` | + +`id` and `slug` in the front matter define the route, so they must stay +identical to the English page. `title` and `sidebar_label` get translated. The +`translation_*` keys are described in the `translate` skill; Docusaurus ignores +unknown front matter keys, so they are safe to add. + +## Three things that will break the build + +These are all real failures we hit enabling Spanish, and they only show up on +non-default locales — English keeps passing, which makes them confusing to +debug. + +### Link to docs with site-absolute paths, not relative `.md` paths + +This is already the house style in `AGENTS.md`, and i18n is why it matters. On +an English page, use: + +```md +[Key Concepts](/documentation/get-started/terminology) +``` + +not: + +```md +[Key Concepts](../get-started/terminology.md) +``` + +Relative `.md` links only resolve when both pages come from the same content +directory. Once one is translated and the other is not, they come from different +directories — one from `i18n/es/`, the other falling back from `docs/` — and +Docusaurus cannot resolve the path. With `onBrokenLinks` set to `throw`, that +fails the build. + +On a **translated** page, write the locale in: the `translate` skill asks for +`/es/documentation/get-started/terminology`, and that is what these pages do. +Links into the generated adaptor pages stay unprefixed, since those are English +only. + +Four such links were converted when Spanish was added. Roughly **100 relative +`.md` links remain across ~35 pages** in `docs/`, which are house-style +violations the `lint` skill should pick up section by section. They are harmless +while both ends are English, and become build failures the moment either end is +translated. + +### Translated headings need the English anchor + +A heading's anchor is a link target, so translating the text silently breaks +every link pointing at it. Pin the English anchor: + +```md +## Nuestros productos {#our-products} +``` + +Only headings whose text actually changes need this. Glossary product nouns that +stay in English (`## Work Order`, `## Run`) keep their anchors for free — the +whole of Key Concepts needed no pinning for exactly that reason. + +### Sidebar items need a unique `key` + +Docusaurus derives a sidebar item's translation key from its `key` if it has +one, and from its **label** otherwise, so two items sharing a label collide and +throw `Multiple docs sidebar items produce the same translation key`. + +`sidebars-adaptors.js` generates one category per adaptor, each with items +labelled `Functions`, `Configuration`, `Changelog`, `README.md` and `Overview` — +about 100 collisions per label. Every generated item now carries a key +namespaced by adaptor: + +```js +{ + type: 'doc', + label: 'Overview', + key: `${a.name}-overview`, + id: a.name, +} +``` + +If you add items to a generated sidebar, give them a unique `key`. + +## Interface strings + +Anything that is not markdown — navbar labels, footer columns, sidebar category +names, the homepage — lives in JSON. Do not hand-write those files; generate +them: + +```bash +yarn docusaurus write-translations --locale es +``` + +This writes new or missing keys into `i18n/es/` and **leaves existing +translations untouched**. Then fill in the `message` values: + +| File | What it covers | +| ---------------------------------------------- | ------------------------------------------- | +| `code.json` | Strings from React components (`src/pages`) | +| `docusaurus-theme-classic/navbar.json` | Navbar labels | +| `docusaurus-theme-classic/footer.json` | Footer columns and links | +| `docusaurus-plugin-content-docs/current.json` | Sidebar category labels, version label | +| `docusaurus-plugin-content-blog*/options.json` | Blog and Articles SEO titles | + +Two things worth knowing about these files: + +- **Only keep keys we actually own.** `@docusaurus/theme-translations` already + ships Spanish for the theme's own strings, so `code.json` holds our + `homepage.*` keys plus the handful of `theme.*` strings upstream has left in + English. Copying the rest would override upstream and go stale on upgrade. +- **Leave out anything computed.** The footer copyright is built from + `new Date().getFullYear()`, so translating it would freeze the year. It is + omitted deliberately and falls back to the source. + +:::warning After running write-translations, check your diff + +`write-translations` does not know which keys we deliberately left out. It will +re-add roughly 130 `theme.*` keys to `code.json` and the footer `copyright` key, +filled in with values it read from upstream. Committing those silently takes +over maintenance of strings Docusaurus already translates for us, and freezes +the copyright year. + +Keep only the keys you actually came to add. If `git diff` on `code.json` shows +more than the strings you were working on, you have picked up the inherited +ones. + +::: + +If you add user-facing copy to a React component, wrap it so it can be +extracted: + +```jsx +import Translate, { translate } from '@docusaurus/Translate'; + +

+ Newsletter +

; + +; +``` + +Always set an explicit `id`. Auto-generated ids are derived from the English +text, so they change whenever the English copy is edited and silently orphan the +translation. + +## Not translated, on purpose + +- **Adaptor docs** (`/adaptors/`) — generated from adaptor source repos, so + anything written here would be overwritten. +- **The job library** — same reason. +- **The v1.105 (legacy) docs** — frozen and being sunsetted. +- **Articles and blog posts** — long-form and frequently added. + +All of these fall back to English. + +## Known gaps + +**Search does not cover Spanish.** The site uses Algolia DocSearch with +`contextualSearch: true`, which scopes results to the language being browsed. +The crawler is only configured for the English site, so searching from a `/es/` +page returns nothing until the DocSearch crawler config is updated. Worth +resolving before the Spanish site is promoted anywhere. + +**Full builds are slower.** `yarn build` builds every locale, so build time +scales with the number of languages. + +## Running it locally + +For a quick look at a single locale, use the dev server: + +```bash +yarn start --locale es +``` + +:::danger `yarn build --locale es` is not a substitute for `yarn build` + +The two use different base URLs, and they disagree about locale-prefixed links. + +A full `yarn build` builds `es` as a sub-site at `baseUrl: /es/`, so its route +paths are `/es/documentation/...` and the `/es/`-prefixed links in translated +pages resolve. `yarn build --locale es` builds Spanish as though it were the +only language, at `baseUrl: /`, so its route paths are `/documentation/...` — +and every correctly written `/es/...` link in a translated page is reported as a +broken link. With `onBrokenLinks: throw`, the single-locale build fails on pages +the real build is perfectly happy with. + +So treat a `--locale` failure as suspect until you have reproduced it with a +full build, and always run plain `yarn build` before opening a PR. That is what +CI and the deploy workflow run. + +::: diff --git a/docs/get-help/support.md b/docs/get-help/support.md index df511222aa6d..2a73f0ecc831 100644 --- a/docs/get-help/support.md +++ b/docs/get-help/support.md @@ -3,15 +3,26 @@ title: Support for OpenFn Implementations sidebar_label: Get Help --- -## Ask the Community! -If you need help getting started, have questions, or product feedback, first check out our **[Community](https://community.openfn.org)**. Our core team and other OpenFn implementers monitor all posts to help each other out, share examples, and circulate product updates. +## Ask the Community! -## Have a question about your project on OpenFn.org? -If you're using the hosted OpenFn platform SaaS, and have a private question about your project, account, or billing, contact our core team at [support@openfn.org](mailto://support@openfn.org). +If you need help getting started, have questions, or product feedback, first +check out our **[Community](https://community.openfn.org)**. Our core team and +other OpenFn implementers monitor all posts to help each other out, share +examples, and circulate product updates. + +## Have a question about your project on OpenFn.org? + +If you're using the hosted OpenFn platform SaaS, and have a private question +about your project, account, or billing, contact our core team at +[support@openfn.org](mailto://support@openfn.org). ## Need helping hands? -The OpenFn core team and our certified partners offer enterprise support, implementation & developer services, and training to jump-start your team. Check out our website: + +The OpenFn core team and our certified partners offer enterprise support, +implementation & developer services, and training to jump-start your team. Check +out our website: + - About [OpenFn services & pricing](https://www.openfn.org/pricing) - About our [certified partners](https://www.openfn.org/partners) - \ No newline at end of file + diff --git a/docs/get-started/try-out.md b/docs/get-started/try-out.md index db9d1ffb1c65..23289e04c3ac 100644 --- a/docs/get-started/try-out.md +++ b/docs/get-started/try-out.md @@ -50,7 +50,7 @@ without limits. See our GitHub repo for developer docs: :::info Questions? Check out these docs for more details on specific features (see menu sidebar), -browse the [main docs page](./home.md), or post your questions on +browse the [main docs page](/documentation/), or post your questions on [Community](https://community.openfn.org). ::: diff --git a/docs/monitor-history/inspect-runs.md b/docs/monitor-history/inspect-runs.md index e63b28fa78e6..75d55e3d4785 100644 --- a/docs/monitor-history/inspect-runs.md +++ b/docs/monitor-history/inspect-runs.md @@ -3,7 +3,7 @@ title: Inspect Runs & Search via the History page sidebar_label: Inspect Runs --- -A [Run](../get-started/terminology.md#run) is created each time +A [Run](/documentation/get-started/terminology#run) is created each time OpenFn attempts to excute a Workflow for a given Work Order. All Runs can be viewed, filtered, and searched via the `History` page. diff --git a/docs/tutorials/commcare-to-db.md b/docs/tutorials/commcare-to-db.md index 57432a272d52..01d0f256d779 100644 --- a/docs/tutorials/commcare-to-db.md +++ b/docs/tutorials/commcare-to-db.md @@ -9,7 +9,7 @@ title: Syncing your CommCare form submissions to a PostgreSQL database minute!) - You have checked out our glossary and have an understanding of basic OpenFn and API terminology. Check out the pages below to get started - - [OpenFn Concepts](../get-started/terminology.md) + - [OpenFn Concepts](/documentation/get-started/terminology) - [A glossary for data integration](../get-started/glossary.md) - You have a CommCare application with at least one form configured. This is your source system. diff --git a/docs/tutorials/http-to-googlesheets.md b/docs/tutorials/http-to-googlesheets.md index ff1abea1c410..9fcaba5b66f4 100644 --- a/docs/tutorials/http-to-googlesheets.md +++ b/docs/tutorials/http-to-googlesheets.md @@ -21,7 +21,7 @@ Here are some we assume you've looked over before you begin this process. - You have checked out our glossary and have an understanding of basic OpenFn & API concepts. Check out the pages below to get started - - [OpenFn Concepts](../get-started/terminology.md) + - [OpenFn Concepts](/documentation/get-started/terminology) - [A glossary for data integration](../get-started/glossary.md) - You have a Google Account. We will use it to create a credential to authorize with Google Sheets. diff --git a/docusaurus.config.js b/docusaurus.config.js index fdf1a521f462..d67373e4e7c5 100644 --- a/docusaurus.config.js +++ b/docusaurus.config.js @@ -12,6 +12,30 @@ module.exports = { favicon: 'img/favicon.ico', organizationName: 'openfn', projectName: 'docs', + // --- i18n (internationalization) --- + // Proof of concept: English (default) + Spanish. + // Translated content lives in i18n//. Anything not translated + // falls back to the English source automatically. + // + // Local dev for a single locale (much faster than building everything): + // yarn start --locale es + // yarn build --locale es + i18n: { + defaultLocale: 'en', + locales: ['en', 'es'], + localeConfigs: { + en: { + label: 'English', + direction: 'ltr', + htmlLang: 'en', + }, + es: { + label: 'Español', + direction: 'ltr', + htmlLang: 'es', + }, + }, + }, markdown: { hooks: { onBrokenMarkdownLinks: 'warn' }, mermaid: true, @@ -71,6 +95,10 @@ module.exports = { label: 'Articles', position: 'left', }, + { + type: 'localeDropdown', + position: 'right', + }, { type: 'docsVersionDropdown', position: 'right', @@ -151,6 +179,9 @@ module.exports = { sidebarPath: require.resolve('./sidebars-main.js'), routeBasePath: '/documentation', editUrl: 'https://github.com/openfn/docs/edit/main', + // Point "Edit this page" at the translated file rather than the + // English source when reading a non-default locale. + editLocalizedFiles: true, lastVersion: 'current', versions: { current: { diff --git a/glossary.yml b/glossary.yml new file mode 100644 index 000000000000..f15f801eaa04 --- /dev/null +++ b/glossary.yml @@ -0,0 +1,194 @@ +# glossary.yml +# +# Purpose +# ------- +# Product vocabulary for the OpenFn docs. Two consumers read this file: +# +# 1. The translate skill (.agents/skills/translate.md). Any term with +# `translate: false` must appear verbatim in every translated page. +# 2. The lint skill (.agents/skills/lint.md). Any spelling in `variants` +# is flagged in English pages and replaced with `term`. +# +# Humans maintain this file. Add a term when a review shows the same +# correction being made more than once. +# +# Schema +# ------ +# terms: # list of glossary entries +# - term: string # canonical English spelling (required) +# translate: boolean # false = keep verbatim in all locales (default false) +# product_noun: boolean # true = the rule only applies when the word is used +# # as the OpenFn concept, not as ordinary English +# # (e.g. "run" the noun, not "run the command"). +# # Translators keep the product noun and may +# # translate the ordinary-English use. Default false. +# case_sensitive: boolean # true = lint flags case variants too (default false) +# variants: [string] # spellings lint should flag and replace with `term` +# note: string # guidance for humans and the agent +# locales: # optional. Only used when translate: true, to pin a +# es: string # specific rendering per locale instead of free +# fr: string # translation. +# +# patterns: # regexes that are never translated, for families +# - pattern: string # of identifiers too numerous to list (adaptor +# note: string # package names, CLI flags, env vars, ...) +# +# Matching is whole-word for `term` and `variants`. Code blocks, inline code, +# URLs, and front matter are always exempt from lint and translation. + +terms: + - term: OpenFn + translate: false + case_sensitive: true + variants: + - Open Fn + - Openfn + - openFn + note: The product and organisation name. Never localised. + + - term: Lightning + translate: false + case_sensitive: true + note: >- + The OpenFn web app (OpenFn/lightning). In user-facing docs prefer + "the OpenFn platform" or "the web app"; keep "Lightning" when the docs + refer to the repo or to self-hosting. + + - term: adaptor + translate: false + variants: + - adapter + - Adapter + note: >- + Always "adaptor", never "adapter". Also covers "adaptors", "Adaptor", + "Adaptors". Adaptor package names are matched by the pattern below. + + - term: workflow + translate: false + product_noun: true + note: >- + A Trigger plus Steps plus Paths configured on the Canvas or in + project.yaml. Keep "workflow" in translations when it names the OpenFn + object. + + - term: step + translate: false + product_noun: true + note: A unit of work inside a workflow. Was "job" in OpenFn v1. + + - term: job + translate: false + product_noun: true + note: >- + In v2 the job is the JavaScript expression a Step runs. Do not + "correct" v1 usage inside pages that are explicitly about v1 or + migration. + + - term: credential + translate: false + product_noun: true + note: Stored authentication configuration attached to a Step. + + - term: trigger + translate: false + product_noun: true + note: What starts a workflow. Types are webhook, cron, and kafka. + + - term: cron + translate: false + note: Trigger type and the scheduling syntax. + + - term: webhook + translate: false + note: Trigger type. One word, lower case, no hyphen. + + - term: run + translate: false + product_noun: true + note: >- + One execution of a workflow for a work order. Only the noun is + protected. "Run the CLI" is ordinary English and may be translated. + + - term: attempt + translate: false + product_noun: true + note: >- + Legacy name for a run. Do not replace it in migration or historical + pages. In pages about current v2 behaviour, prefer "run" and record the + change as a suggestion, not a fix. + + - term: work order + translate: false + variants: + - workorder + - work-order + note: The record created when a trigger fires; owns one or more runs. + + - term: project space + translate: false + note: Billing and hosting unit on the hosted OpenFn app. + + - term: project + translate: false + product_noun: true + note: Administrative grouping of workflows, credentials, and collaborators. + + - term: dataclip + translate: false + variants: + - data clip + - data-clip + note: A stored input or output state object. + + - term: collection + translate: false + product_noun: true + note: The Collections key-value store feature. Ordinary English use may be translated. + + - term: sandbox + translate: false + product_noun: true + note: A Lightning sandbox environment. + + - term: Canvas + translate: false + case_sensitive: true + note: The visual workflow editor in the web app. + + - term: Inspector + translate: false + case_sensitive: true + note: The step editing panel in the web app. + + - term: CLI + translate: false + case_sensitive: true + note: "@openfn/cli. Also keep every CLI command and flag verbatim." + + - term: state + translate: false + product_noun: true + note: >- + The `state` object passed between operations. Protected only when it + names the object (usually rendered in code as `state`). + + - term: operation + translate: false + product_noun: true + note: A function exported by an adaptor, e.g. `get()`, `upsert()`. + +patterns: + - pattern: "@openfn/[a-z0-9-]+" + note: npm package names (adaptors, CLI, runtime). + + - pattern: "language-[a-z0-9-]+" + note: Bare adaptor package names as they appear in the adaptor picker. + + - pattern: "\\bopenfn [a-z][a-z-]*" + note: CLI subcommands such as `openfn deploy`, `openfn pull`. + + - pattern: "\\b[A-Z][A-Z0-9_]{2,}\\b" + note: Environment variables and constants (OPENFN_API_KEY, WORKER_SECRET). + + - pattern: "\\bproject\\.yaml\\b" + note: The project state file name. diff --git a/i18n/es/code.json b/i18n/es/code.json new file mode 100644 index 000000000000..91c5e2d5c0d7 --- /dev/null +++ b/i18n/es/code.json @@ -0,0 +1,126 @@ +{ + "homepage.highlights.jobWritingGuide.title": { + "message": "Guía para escribir Jobs" + }, + "homepage.highlights.jobWritingGuide.description": { + "message": "¿Vas a escribir un Job para OpenFn? Empieza por aquí" + }, + "homepage.highlights.cliUsage.title": { + "message": "Ejemplos de uso del CLI" + }, + "homepage.highlights.cliUsage.description": { + "message": "Descubre de un vistazo todo lo que puede hacer el CLI" + }, + "homepage.highlights.javascriptTips.title": { + "message": "Trucos y consejos de JavaScript" + }, + "homepage.highlights.javascriptTips.description": { + "message": "Mejora tu código" + }, + "homepage.highlights.heading": { + "message": "✨Destacados de la documentación✨" + }, + "homepage.features.docs.title": { + "message": "Documentación" + }, + "homepage.features.docs.description": { + "message": "Documentación sobre todos los aspectos de OpenFn, el principal bien público digital para la automatización de flujos de trabajo." + }, + "homepage.features.adaptors.title": { + "message": "Adaptors" + }, + "homepage.features.adaptors.description": { + "message": "Documentación, ejemplos, registros de cambios y descripciones generales de los Adaptors, con búsqueda y navegación, para conectar los bienes públicos digitales más usados del mundo." + }, + "homepage.features.articles.title": { + "message": "Artículos" + }, + "homepage.features.articles.description": { + "message": "¿Cómo prepararse para una integración de datos? ¿Cómo estructurar los IDs externos? ¿Cómo..." + }, + "homepage.features.blog.title": { + "message": "Blog" + }, + "homepage.features.blog.description": { + "message": "Ayudamos a que las iniciativas de impacto social más prometedoras del mundo alcancen escala mediante la automatización, la integración de datos y la interoperabilidad. Estas son sus historias." + }, + "homepage.features.enterprise.title": { + "message": "Empresas" + }, + "homepage.features.enterprise.description": { + "message": "Descubre la plataforma de integración como servicio (iPaaS) de OpenFn para empresas, con planes gratuitos permanentes y opciones accesibles para crecer." + }, + "homepage.meta.title": { + "message": "Inicio" + }, + "homepage.meta.description": { + "message": "El sitio de documentación de OpenFn" + }, + "homepage.hero.title": { + "message": "Documentación de OpenFn" + }, + "homepage.hero.subtitle": { + "message": "El principal bien público digital para la automatización de flujos de trabajo. OpenFn hace que las TIC para el desarrollo (ICT4D) sean más eficientes." + }, + "homepage.hero.cta": { + "message": "Comenzar" + }, + "homepage.newsletter.title": { + "message": "Boletín" + }, + "homepage.newsletter.imageAlt": { + "message": "Boletín" + }, + "homepage.newsletter.description": { + "message": "No te pierdas ninguna novedad: suscríbete aquí a nuestro boletín." + }, + "homepage.newsletter.emailPlaceholder": { + "message": "Correo electrónico" + }, + "homepage.newsletter.subscribe": { + "message": "Suscribirse" + }, + "theme.admonition.tip": { + "message": "consejo", + "description": "The default label used for the Tip admonition (:::tip)" + }, + "theme.admonition.info": { + "message": "información", + "description": "The default label used for the Info admonition (:::info)" + }, + "theme.docs.versionBadge.label": { + "message": "Versión: {versionLabel}" + }, + "theme.IconExternalLink.ariaLabel": { + "message": "(se abre en una pestaña nueva)", + "description": "The ARIA label for the external link icon" + }, + "theme.colorToggle.ariaLabel.mode.system": { + "message": "modo del sistema", + "description": "The name for the system color mode" + }, + "theme.navbar.mobileDropdown.collapseButton.expandAriaLabel": { + "message": "Expandir el menú desplegable", + "description": "The ARIA label of the button to expand the mobile dropdown navbar item" + }, + "theme.navbar.mobileDropdown.collapseButton.collapseAriaLabel": { + "message": "Contraer el menú desplegable", + "description": "The ARIA label of the button to collapse the mobile dropdown navbar item" + }, + "theme.blog.authorsList.pageTitle": { + "message": "Autores", + "description": "The title of the authors page" + }, + "theme.blog.author.noPosts": { + "message": "Este autor aún no ha escrito publicaciones.", + "description": "The text for authors with 0 blog post" + }, + "theme.contentVisibility.draftBanner.title": { + "message": "Página en borrador", + "description": "The draft content banner title" + }, + "theme.contentVisibility.draftBanner.message": { + "message": "Esta página es un borrador. Solo será visible en el entorno de desarrollo y se excluirá de la compilación de producción.", + "description": "The draft content banner message" + } +} diff --git a/i18n/es/docusaurus-plugin-content-blog-articles/options.json b/i18n/es/docusaurus-plugin-content-blog-articles/options.json new file mode 100644 index 000000000000..fabe0f18cf00 --- /dev/null +++ b/i18n/es/docusaurus-plugin-content-blog-articles/options.json @@ -0,0 +1,14 @@ +{ + "title": { + "message": "Artículos", + "description": "The title for the blog used in SEO" + }, + "description": { + "message": "Artículos de ayuda de OpenFn", + "description": "The description for the blog used in SEO" + }, + "sidebar.title": { + "message": "Artículos recientes", + "description": "The label for the left sidebar" + } +} diff --git a/i18n/es/docusaurus-plugin-content-blog/options.json b/i18n/es/docusaurus-plugin-content-blog/options.json new file mode 100644 index 000000000000..18375b3a3f5a --- /dev/null +++ b/i18n/es/docusaurus-plugin-content-blog/options.json @@ -0,0 +1,14 @@ +{ + "title": { + "message": "Blog", + "description": "The title for the blog used in SEO" + }, + "description": { + "message": "Blog", + "description": "The description for the blog used in SEO" + }, + "sidebar.title": { + "message": "Publicaciones recientes", + "description": "The label for the left sidebar" + } +} diff --git a/i18n/es/docusaurus-plugin-content-docs/current.json b/i18n/es/docusaurus-plugin-content-docs/current.json new file mode 100644 index 000000000000..dc9d21a0b2af --- /dev/null +++ b/i18n/es/docusaurus-plugin-content-docs/current.json @@ -0,0 +1,62 @@ +{ + "version.label": { + "message": "v2 ⚡", + "description": "The label for version current" + }, + "sidebar.docs.category.Get Started": { + "message": "Primeros pasos", + "description": "The label for category 'Get Started' in sidebar 'docs'" + }, + "sidebar.docs.category.Tutorials": { + "message": "Tutoriales", + "description": "The label for category 'Tutorials' in sidebar 'docs'" + }, + "sidebar.docs.category.Design Workflows": { + "message": "Diseñar Workflows", + "description": "The label for category 'Design Workflows' in sidebar 'docs'" + }, + "sidebar.docs.category.Write Jobs": { + "message": "Escribir Jobs", + "description": "The label for category 'Write Jobs' in sidebar 'docs'" + }, + "sidebar.docs.category.Platform ⚡": { + "message": "Plataforma ⚡", + "description": "The label for category 'Platform ⚡' in sidebar 'docs'" + }, + "sidebar.docs.category.Build & Manage Workflows": { + "message": "Crear y gestionar Workflows", + "description": "The label for category 'Build & Manage Workflows' in sidebar 'docs'" + }, + "sidebar.docs.category.Monitor History": { + "message": "Monitorear el historial", + "description": "The label for category 'Monitor History' in sidebar 'docs'" + }, + "sidebar.docs.category.Manage Projects": { + "message": "Gestionar Projects", + "description": "The label for category 'Manage Projects' in sidebar 'docs'" + }, + "sidebar.docs.category.Manage Users & Credentials": { + "message": "Gestionar usuarios y Credentials", + "description": "The label for category 'Manage Users & Credentials' in sidebar 'docs'" + }, + "sidebar.docs.category.CLI": { + "message": "CLI", + "description": "The label for category 'CLI' in sidebar 'docs'" + }, + "sidebar.docs.category.Deployment": { + "message": "Despliegue", + "description": "The label for category 'Deployment' in sidebar 'docs'" + }, + "sidebar.docs.category.Migrate to v2": { + "message": "Migrar a v2", + "description": "The label for category 'Migrate to v2' in sidebar 'docs'" + }, + "sidebar.docs.category.Contribute": { + "message": "Contribuir", + "description": "The label for category 'Contribute' in sidebar 'docs'" + }, + "sidebar.docs.link.Community Forum": { + "message": "Foro de la comunidad", + "description": "The label for link 'Community Forum' in sidebar 'docs', linking to 'https://community.openfn.org'" + } +} diff --git a/i18n/es/docusaurus-plugin-content-docs/current/get-help/support.md b/i18n/es/docusaurus-plugin-content-docs/current/get-help/support.md new file mode 100644 index 000000000000..306e74ed3b4e --- /dev/null +++ b/i18n/es/docusaurus-plugin-content-docs/current/get-help/support.md @@ -0,0 +1,31 @@ +--- +title: Soporte para implementaciones de OpenFn +sidebar_label: Obtener ayuda +translation_source_hash: 2a73f0ecc8314aa6d23cfc20a7193d77ea125d0f +translation_review_status: machine +--- + +## ¡Pregunta a la Comunidad! {#ask-the-community} + +Si necesitas ayuda para empezar, tienes preguntas o quieres compartir +comentarios sobre el producto, primero visita nuestra +**[Comunidad](https://community.openfn.org)**. Nuestro equipo central y otras +personas que implementan OpenFn revisan todas las publicaciones para ayudarse +entre sí, compartir ejemplos y difundir novedades del producto. + +## ¿Tienes una pregunta sobre tu Project en OpenFn.org? {#have-a-question-about-your-project-on-openfnorg} + +Si usas la plataforma alojada de OpenFn (SaaS) y tienes una pregunta privada +sobre tu Project, tu cuenta o tu facturación, escribe a nuestro equipo central a +[support@openfn.org](mailto://support@openfn.org). + +## ¿Necesitas una mano? {#need-helping-hands} + +El equipo central de OpenFn y nuestros socios certificados ofrecen soporte +empresarial, servicios de implementación y desarrollo, y capacitaciones para +poner en marcha a tu equipo. Visita nuestro sitio web: + +- Sobre los [servicios y precios de OpenFn](https://www.openfn.org/pricing) +- Sobre nuestros [socios certificados](https://www.openfn.org/partners) + + diff --git a/i18n/es/docusaurus-plugin-content-docs/current/get-started/home.md b/i18n/es/docusaurus-plugin-content-docs/current/get-started/home.md new file mode 100644 index 000000000000..e6c55cf217d5 --- /dev/null +++ b/i18n/es/docusaurus-plugin-content-docs/current/get-started/home.md @@ -0,0 +1,154 @@ +--- +title: ¿Qué es OpenFn? +id: home +sidebar_label: ¿Qué es OpenFn? +slug: / +translation_source_hash: c4af9efb3157acd6020bb65eaa98b3d278887e0b +translation_review_status: machine +--- + +**OpenFn es el principal +[bien público digital](https://digitalpublicgoods.net/digital-public-goods/) +para la automatización de flujos de trabajo**. + +Es una plataforma que ya han usado más de 70 ONG y ministerios de gobierno para +automatizar e integrar procesos de negocio y sistemas de información críticos. + +**Conecta cualquier aplicación** con la biblioteca de [Adaptors](/adaptors/) de +código abierto de OpenFn (es decir, conectores). Desde los servicios de última +milla hasta los reportes de alcance nacional, OpenFn mejora la eficiencia y la +efectividad, y habilita una interoperabilidad segura, estable y escalable en +todos los niveles. + +OpenFn se puede desplegar localmente o en la +[plataforma segura alojada en la nube](https://openfn.org/pricing). Consulta la +[documentación de despliegue](/es/documentation/deploy/options) para conocer más +sobre las opciones y los requisitos de despliegue. + +Para apoyar a quienes implementan, OpenFn cuenta con una +[comunidad](https://community.openfn.org) en línea, documentación y +[soporte](mailto://support@openfn.org). Escribe a +[partnerships@openfn.org](mailto://partnerships@openfn.org) para conocer más +sobre los socios de implementación de OpenFn y el Programa de Socios de OpenFn. + +:::tip Automatización, integración e interoperabilidad + +OpenFn es software de código abierto que les facilita a los gobiernos y a las +ONG _conectar_ las distintas tecnologías que usan, automatizar procesos de +negocio críticos y escalar sus intervenciones. OpenFn habilita la +automatización, la integración y la interoperabilidad de datos para las +organizaciones de mayor impacto del mundo. + +::: + +## Nuestros productos {#our-products} + +OpenFn ofrece un conjunto de productos, todos ellos interoperables entre sí. +Esto les da a nuestros usuarios la libertad de cambiar entre cualquiera de los +productos de OpenFn. + +Todos los productos de OpenFn, con excepción del iPaaS de OpenFn v1, forman +parte del `OpenFn Integration Toolkit`, que es gratuito y de código abierto y es +un **bien público digital** (un "DPG", por sus siglas en inglés) reconocido en +el [Registro de DPG](https://digitalpublicgoods.net/registry/) y en la +[Global Goods Guidebook](https://digitalsquare.org/resourcesrepository/global-goods-guidebook) +de Digital Square. + +Los productos principales de OpenFn incluyen: + +- **[OpenFn/lightning](https://github.com/OpenFn/lightning)**: nuestra + plataforma de código abierto de integración de datos y automatización de + flujos de trabajo. Es la versión "v2", la que está en uso actualmente. +- OpenFn/platform: la primera versión de nuestra plataforma. Reemplazada por la + v2 y con retiro previsto para 2025 +- [**OpenFn/adaptors**](https://github.com/OpenFn/adaptors): código fuente de + los adaptors +- [**OpenFn/kit**](https://github.com/OpenFn/kit): CLI, herramientas para + desarrolladores y entornos de ejecución de JavaScript +- [**OpenFn/docs**](https://github.com/OpenFn/docs): documentación y código + fuente de docs.openfn.org + +Consulta todos los productos y el código en +[GitHub.com/OpenFn](https://github.com/OpenFn). + +### OpenFn v2: Lightning ⚡ + +Cuando escuches "OpenFn", piensa en +[OpenFn/lightning](https://github.com/OpenFn/lightning/). La v2 es una +aplicación web de automatización de flujos de trabajo _totalmente de código +abierto_ que se puede desplegar y ejecutar en cualquier lugar. Está diseñada +para gobiernos y ONG que buscan capacidades de última generación en +automatización de flujos de trabajo e integración e interoperabilidad de datos, +con gestión de usuarios y auditoría completas, ya sea en una plataforma +gestionada _o_ totalmente autoalojada. + +La versión 2 se apoya en la misma tecnología central, probada y confiable, de +OpenFn v1, y viene con una interfaz visual mejorada para construir +integraciones. + +![Canvas de Workflow de OpenFn](/img/case_referral_workflow.webp) + +**Echa un vistazo a la +[lista de reproducción OpenFn v2 Basics](https://www.youtube.com/watch?v=U0MXYRXkDnI&list=PL1pD3-abjHJ0L01RjouO2xOWKtEUYi8e4&ab_channel=OpenFn.org)** +en YouTube para ver videos que te ayudarán a empezar rápidamente, o revisa las +demás páginas de documentación del sitio. + +:::info OpenFn v2 reemplaza a la v1 + +OpenFn v2 está disponible para cualquier usuario nuevo. Todas las organizaciones +que hoy usan la plataforma heredada OpenFn v1 serán migradas a OpenFn v2 para +finales de 2024. + +::: + +### OpenFn v1 + +OpenFn v1 es la _plataforma de integración como servicio_ (o "iPaaS") heredada +de OpenFn, lanzada por primera vez en 2015. OpenFn v1 tenía un núcleo abierto +con una aplicación web propietaria. + +La plataforma v1 será retirada en 2025 y reemplazada por OpenFn v2, que es +totalmente de código abierto (ver arriba). + +### Herramientas de desarrollo de OpenFn {#openfn-developer-tooling} + +[OpenFn/kit](https://github.com/OpenFn/kit) ofrece un CLI y un conjunto de +herramientas para desarrolladores que sirven para escribir y probar workflows, +gestionar Projects de OpenFn y desarrollar +[Adaptors](https://github.com/openfn/adaptors). + +:::note Explora todo el código de OpenFn + +Puedes consultar la documentación técnica y el código fuente de las herramientas +de integración y los adaptors de OpenFn, que son totalmente de código abierto +("FOSS"), en sus respectivos repositorios en +[GitHub.com/OpenFn](https://github.com/openfn), o revisar la sección +[Despliegue](/es/documentation/deploy/options) para ver un resumen de las +opciones FOSS y documentación adicional. + +::: + +## Comunidad {#community} + +Para hacer preguntas, reportar problemas o aprender de otras personas que +implementan OpenFn, visita nuestro foro de Discourse en +[community.openfn.org](https://community.openfn.org). Regístrate y únete a la +conversación. Normalmente es la forma más rápida de obtener ayuda si tienes +preguntas que no se responden aquí. + +Si tienes preguntas sobre nuestros productos, pregunta en la Comunidad o escribe +al equipo central a [support@openfn.org](mailto:support@openfn.org). + +## ¿Quién lo desarrolla? {#who-is-it-built-by} + +El principal responsable de OpenFn es +[Open Function Group](https://openfn.org/about), un equipo global de +especialistas en automatización de flujos de trabajo e integración de datos, y +contribuyentes principales de OpenFn. Conoce más sobre la gobernanza de OpenFn +[aquí](https://github.com/OpenFn/governance). + +El [bien público digital](https://app.digitalpublicgoods.net/a/11038) OpenFn ha +sido desarrollado por y para la creciente comunidad de ONG, gobiernos, socios +"tech-for-good" y contribuyentes de código abierto que trabajan en +intervenciones de salud y humanitarias en países de ingresos bajos y medios +(LMIC). diff --git a/i18n/es/docusaurus-plugin-content-docs/current/get-started/terminology.md b/i18n/es/docusaurus-plugin-content-docs/current/get-started/terminology.md new file mode 100644 index 000000000000..7b5e39e1c0fa --- /dev/null +++ b/i18n/es/docusaurus-plugin-content-docs/current/get-started/terminology.md @@ -0,0 +1,318 @@ +--- +title: Conceptos clave +translation_source_hash: 88f1bae70e80318a23a5c56152c2e9da1d0d37e4 +translation_review_status: machine +--- + +A lo largo del OpenFn Integration Toolkit y de este sitio de documentación +encontrarás terminología propia de OpenFn que es importante entender. Esta +página es tu guía de referencia: un glosario de las palabras más importantes +_específicas de OpenFn_ y su significado. + +:::tip ¿Falta algo? + +Si te encontraste con una palabra, frase o concepto que crees que falta en esta +página, abre un issue en [OpenFn/docs](https://github.com/OpenFn/docs), sugiere +una edición a +[esta página](https://github.com/OpenFn/docs/blob/main/docs/get-started/terminology.md) +o pregunta en la [Comunidad](https://community.openfn.org) + +::: + +Ten en cuenta que si buscas un glosario de términos genéricos de integración de +datos (en lugar de estos términos _específicos de OpenFn_), dirígete a la página +[Glosario de integración](/es/documentation/get-started/glossary) en la sección +de Diseño. Si no, ¡sigue leyendo! + +## Project + +Un Project es una agrupación administrativa en OpenFn, algo así como un "espacio +de trabajo". + +En la plataforma (OpenFn/lightning), los Projects definen quién puede acceder a +la configuración y al historial de tus Workflows de OpenFn. Los Projects tienen +una persona propietaria y uno o más Collaborators. + +En despliegues y desarrollo local, un Project también corresponde a un archivo +[`project.yaml`](/es/documentation/deploy/portability-versions#v2), que define +la configuración de un Project. + +En cualquiera de los dos casos, un Project contiene Workflows, Triggers, +Credentials y todo lo que necesitas para automatizar e integrar con OpenFn. + +## Workflow + +:::tip + +¡Los Workflows son la parte del **"qué hacer"** de la automatización! + +::: + +Un Workflow es una secuencia estructurada de tareas, procesos o acciones que se +ejecutan automáticamente según reglas, Triggers y lógica predefinidos. + +Cuando se trabaja con IA, los Workflows aportan la ejecución estructurada que se +necesita para convertir los hallazgos de un LLM en acciones concretas, mientras +que los agentes de IA permiten una toma de decisiones más dinámica dentro de los +Workflows. + +Un Workflow es un conjunto formado por un Trigger, Steps, Paths y lógica +personalizada, conectados entre sí para automatizar un proceso de negocio o una +tarea específica. Un Workflow se configura desde el Canvas en la aplicación web, +o localmente (mediante código). + +La automatización en OpenFn gira en torno a los +[Workflows](/es/documentation/build/workflows), que pueden tener uno o varios +Steps. Los Workflows pueden ejecutarse en tiempo real (a partir de un evento, +por ejemplo el registro de un nuevo paciente), de forma programada (por ejemplo, +todos los días a las 8 a.m.) o manualmente, cuando se necesite. + +Piensa en un Workflow como un conjunto de instrucciones que le darías a una +persona del equipo (por ejemplo: crea un registro de Paciente nuevo en OpenMRS +cuando llegue de CommCare un formulario con un cliente recién registrado; +exporta los datos a DHIS2 todas las semanas, los viernes a las 11 p.m.; envía un +SMS con el número de confirmación de pago cuando se reciba el mensaje de +confirmación de pago, etc.). + +Los Workflows más comunes automatizan: + +- Reportes para un monitoreo de programas más rápido y completo (en especial, + reportes desde dispositivos móviles hacia un MIS) +- Pasos rutinarios de ETL de datos (extracción, transformación y carga) y de + limpieza de datos +- Alertas (SMS, correo electrónico) +- Referencias entre sistemas de organizaciones socias +- Asignación o aprobación de tareas +- Reporte de quejas o de casos +- Transacciones financieras o pagos + +:::note Los Workflows son reutilizables + +Los Workflows son totalmente configurables y reutilizables. También pueden +encadenarse para automatizar procesos de varios pasos y sincronizaciones de +datos bidireccionales, de modo que los datos se mantengan consistentes entre +varias aplicaciones (usando patrones Saga multiaplicación). + +::: + +### Adaptor + +:::tip + +¡Los Adaptors son la parte del **"dónde hacerlo"** de la automatización! + +::: + +Los [Adaptors](/adaptors) de OpenFn son módulos de código abierto que le dan a +tus Workflows las funcionalidades que necesitan para comunicarse con la API de +un sistema en particular. Algunos ejemplos son [dhis](/adaptors/dhis2), +[`postgresql`](/adaptors/postgresql) y [`http`](/adaptors/packages/http-docs), +entre otros. Actualmente hay más de 70 adaptors activos, y cualquiera puede +crear uno nuevo o mejorar los existentes. Consulta +[GitHub/Adaptors](https://github.com/OpenFn/adaptors) para ver el código fuente. + +### Credential + +:::tip + +¡Los Credentials son la parte del **"cómo iniciar sesión"** de la +automatización! + +::: + +Un Credential se usa para autenticarse ante una aplicación de destino (por +ejemplo, el usuario, la contraseña y la URL de acceso de una base de datos) para +que un Step de un Workflow pueda ejecutarse. Según el modelo de seguridad de +OpenFn, los Credentials se mantienen separados de los Workflows para asegurar +que los usuarios y contraseñas almacenados (todos ellos cifrados) no se filtren +ni queden al alcance de las personas equivocadas. + +## Trigger + +:::tip + +¡Los Triggers son la parte del **"cuándo hacerlo"** de la automatización! + +::: + +Un [Trigger](/es/documentation/build/triggers) determina **cómo y cuándo** deben +ejecutarse los Workflows automáticamente (por ejemplo, en tiempo real o según +una programación). Cuando se activan, los Triggers crean un nuevo +[Work Order](/es/documentation/get-started/terminology#work-order) y ejecutan (o +"corren") el Workflow. + +Puedes configurar un Trigger de tipo "Webhook Event" si quieres que tu Workflow +se ejecute en tiempo real cuando ocurra un evento en una aplicación externa (por +ejemplo, el envío de un formulario nuevo o la recepción de una notificación +nueva). + +Puedes configurar un Trigger de tipo "Cron" si quieres que tu Workflow se +ejecute según una programación específica (por ejemplo, todos los días a las 8 +a.m., o el primer lunes de cada mes). + +## Work Order + +:::tip + +Los Work Orders registran **"cuándo y qué activó"** la automatización, y nos +ayudan a monitorear si el Workflow se completó correctamente y en qué momento. + +::: + +Un Work Order es una solicitud de ejecución de un Workflow con una entrada +determinada (por ejemplo, el envío de un formulario nuevo o el registro de un +paciente que necesita procesarse). + +Se crea un Work Order cada vez que se activa el Trigger de un Workflow, o +manualmente por parte de un usuario administrador. + +Para que un Work Order se complete correctamente, el Work Order debe llegar sin +errores a un Step final: así se garantiza que el procesamiento terminó. Es +posible que se necesiten varios "Runs" del Workflow para que un Work Order +determinado se considere exitoso. + +Los Work Orders les permiten a los usuarios monitorear de cerca si cada entrada +individual (por ejemplo, el "registro de paciente 123") es procesada +correctamente por un Workflow determinado, con una experiencia de auditoría +similar a la gestión de casos. + +Imagina que hay un Workflow configurado para crear un paciente nuevo en OpenMRS +cada vez que se abre un caso nuevo en CommCare. Si durante la próxima semana se +abren 5 casos en CommCare, verás 5 Work Orders distintos para ese único +Workflow. Si 4 Work Orders son exitosos y uno falla, verás 4 pacientes nuevos en +OpenMRS, y tu administrador de sistemas habrá recibido una notificación de que +uno de esos pacientes no se pudo crear (o se aplicará el manejo de errores más +robusto que hayas configurado). + +![Work Order](/img/work_order_shot.webp) + +:::note + +Normalmente hay una correspondencia de uno a uno entre los Work Orders y las +cosas del mundo real con las que trabajas. Podría crear un Workflow que obtenga +de DHIS2 todos los datos de eventos actualizados de las últimas 2 semanas y los +publique en un mapa público usando CartoDB. Este Workflow se activará en +intervalos de tiempo definidos, cada 2 semanas en este caso, y al cabo de un mes +veremos solo 2 Work Orders en OpenFn (o sea, uno cada dos semanas). Cada Work +Order tendrá un estado de éxito o de falla, con Runs asociados que registran los +detalles de cada transacción y cuántos registros de eventos se procesaron. + +::: + +## Run + +:::tip + +¡Los Runs registran **"qué pasó"** en la automatización! + +::: + +Un Run es un intento individual de ejecución para completar un Work Order. +Pueden existir varios Runs de un Workflow para cumplir con un mismo Work Order +(porque el primer Run puede fallar y hay que reintentarlo para que se procese +correctamente). + +Los Runs tienen horas de inicio, horas de finalización, logs y códigos de estado +que indican cuándo ocurrieron, qué hicieron y si tuvieron éxito o no. + +![Canvas de Workflow de OpenFn](/img/run_view_logs.webp) + +Imagina que hay un Workflow configurado para crear un paciente nuevo en OpenMRS +cada vez que se abre un caso nuevo en CommCare. Si hoy se crea 1 paciente, +entonces: + +- Se creará 1 Work Order en OpenFn. Esto activará un Run para crear el paciente + en OpenMRS. +- Si ese Run falla por un error (por ejemplo, la contraseña del usuario de + OpenMRS es incorrecta, o al paciente le falta información obligatoria), el + "Status" de ese Run y del Work Order asociado aparecerá como `failed`. +- Los usuarios de OpenFn pueden corregir el error y luego elegir "rerun" para + volver a ejecutar ese Run fallido. Esto creará un 2.º Run relacionado con el + Work Order original. Si tiene éxito, el "Status" del 2.º Run y del Work Order + aparecerá como "success". + +### Logs + +Los logs son los registros que genera el motor de ejecución de Workflows para +capturar las actividades realizadas al ejecutar un Workflow o un Step +específico. + +Quienes desarrollan en OpenFn pueden controlar qué aparece en los logs editando +las sentencias `console.log(...)` en las expresiones de Job de los Steps +individuales. + +![Logs](/img/logs_run.webp) + +## History + +En la plataforma, la página History muestra la lista de todos los Work Orders y +Runs que se han procesado en un Project. + +![History](/img/case-referral-history.webp) + +## Inspector + +En la plataforma, la interfaz del Inspector les permite a los usuarios editar, +probar y ejecutar Workflows. + +El Inspector tiene 3 interfaces principales: `Input`, `Editor` y `Output`. + +![Inspector](/img/inspector_interfaces.webp) + +### Input + +Un Input son los datos (`json`) que se usan como Input inicial para que un Step +de un Workflow los utilice al ejecutarse. Cada Run tendrá un Input (estado +inicial) y un Output (estado final). + +Los Inputs pueden crearse automáticamente a partir de un evento de webhook (por +ejemplo, un mensaje reenviado o un payload JSON enviado a OpenFn) o de otro Step +del Workflow, o bien manualmente por parte de un usuario de OpenFn. + +Ejemplo de Input a partir del envío de un formulario desde una aplicación móvil +de recolección de datos (por ejemplo, Kobo, ODK o CommCare): + +```json +{ + "data": { + "form": { + "@name": "Register New Patient", + "case": { + "@case_id": "a9bX12c", + "@date_modified": "2021-01-21T07:08:19.431000Z", + "@user_id": "aaa", + "@xmlns": "http://commcarehq.org/case/transaction/v2", + "create": { + "case_name": "John Doe", + "age": 16, + "case_type": "patient", + "owner_id": "alan.worker" + } + } + } + } +} +``` + +### Output + +Un Output son los datos finales (`json`) que produce un Step de un Workflow, +según la lógica de negocio definida en la expresión de Job de ese Step. Los +Outputs se pasan al siguiente Step del Workflow y/o a la aplicación de destino +conectada. + +Ejemplo de Output si el envío de formulario del ejemplo anterior (ver la sección +de arriba) se mapeara a una aplicación de gestión de casos conectada: + +```json +{ + "data": { + "patient": { + "full_name": "John Doe", + "age_at_enrollment": 16, + "type": "new", + "source": "mobile-app" + } + } +} +``` diff --git a/i18n/es/docusaurus-plugin-content-docs/current/get-started/try-out.md b/i18n/es/docusaurus-plugin-content-docs/current/get-started/try-out.md new file mode 100644 index 000000000000..005c7cedd1d2 --- /dev/null +++ b/i18n/es/docusaurus-plugin-content-docs/current/get-started/try-out.md @@ -0,0 +1,60 @@ +--- +title: Prueba la v2⚡ +id: try-out +sidebar_label: Prueba la v2⚡ +translation_source_hash: 23289e04c3acffebfc62930b673c2f85e50f6d82 +translation_review_status: machine +--- + +Si te interesa probar OpenFn v2⚡ hoy mismo, tienes 3 opciones: + +## 1. Regístrate para obtener una cuenta gratuita {#1-register-for-a-free-account} + +Regístrate para obtener una cuenta gratuita en el servicio alojado de OpenFn.org +y crea tu propio Project privado. Para hacerlo, visita: +[www.openfn.org/register](https://www.openfn.org/register) + +Ten en cuenta que esta cuenta gratuita tiene límites. Mejora tu plan para +acceder a más funcionalidades en la plataforma segura alojada de OpenFn. Conoce +más en [nuestro sitio web](https://www.openfn.org/pricing). + +:::tip ¿Ya tienes una cuenta? + +Visita [www.openfn.org/login](https://www.openfn.org/login) para iniciar sesión +en tu cuenta de Lightning v2. Si solo tienes un usuario de la v1, tendrás que +crear una cuenta nueva de v2 en +[www.openfn.org/register](https://www.openfn.org/register). + +::: + +## 2. Inicia sesión en el sitio de demostración de OpenFn {#2-log-into-the-openfn-demo-site} + +Visita [demo.openfn.org](https://demo.openfn.org) y usa las siguientes +credenciales para iniciar sesión y explorar la plataforma: + +- usuario: `demo@openfn.org` +- contraseña: `welcome12345` + +:::warning + +El sitio de demostración se reinicia cada 24 horas, por lo que se perderá +cualquier cambio de configuración que hagas. Por eso, no uses este sitio para +configuraciones que quieras conservar. + +::: + +## 3. Instala OpenFn/lightning localmente {#3-install-openfnlightning-locally} + +Instala OpenFn v2 localmente para acceder al software de código abierto y +explorarlo sin límites. Consulta nuestro repositorio de GitHub para ver la +documentación para desarrolladores: +[github.com/OpenFn/lightning](https://github.com/OpenFn/lightning). + +:::info ¿Tienes preguntas? + +Revisa esta documentación para conocer más detalles sobre funcionalidades +específicas (ver el menú lateral), explora la +[página principal de la documentación](/es/documentation/) o publica tus +preguntas en la [Comunidad](https://community.openfn.org). + +::: diff --git a/i18n/es/docusaurus-theme-classic/footer.json b/i18n/es/docusaurus-theme-classic/footer.json new file mode 100644 index 000000000000..0279f041812f --- /dev/null +++ b/i18n/es/docusaurus-theme-classic/footer.json @@ -0,0 +1,42 @@ +{ + "link.title.This Site": { + "message": "Este sitio", + "description": "The title of the footer links column with title=This Site in the footer" + }, + "link.title.Community": { + "message": "Comunidad", + "description": "The title of the footer links column with title=Community in the footer" + }, + "link.title.More": { + "message": "Más", + "description": "The title of the footer links column with title=More in the footer" + }, + "link.item.label.Articles": { + "message": "Artículos", + "description": "The label of footer link with label=Articles linking to articles" + }, + "link.item.label.Adaptors": { + "message": "Adaptors", + "description": "The label of footer link with label=Adaptors linking to adaptors" + }, + "link.item.label.Forum": { + "message": "Foro", + "description": "The label of footer link with label=Forum linking to https://community.openfn.org" + }, + "link.item.label.Stack Overflow": { + "message": "Stack Overflow", + "description": "The label of footer link with label=Stack Overflow linking to https://stackoverflow.com/questions/tagged/openfn" + }, + "link.item.label.Twitter": { + "message": "Twitter", + "description": "The label of footer link with label=Twitter linking to https://twitter.com/openfn" + }, + "link.item.label.OpenFn.org": { + "message": "OpenFn.org", + "description": "The label of footer link with label=OpenFn.org linking to https://www.openfn.org" + }, + "link.item.label.GitHub": { + "message": "GitHub", + "description": "The label of footer link with label=GitHub linking to https://github.com/openfn" + } +} diff --git a/i18n/es/docusaurus-theme-classic/navbar.json b/i18n/es/docusaurus-theme-classic/navbar.json new file mode 100644 index 000000000000..f56684752de1 --- /dev/null +++ b/i18n/es/docusaurus-theme-classic/navbar.json @@ -0,0 +1,22 @@ +{ + "title": { + "message": "OpenFn", + "description": "The title in the navbar" + }, + "logo.alt": { + "message": "OpenFn", + "description": "The alt text of navbar logo" + }, + "item.label.Docs": { + "message": "Documentación", + "description": "Navbar item with label Docs" + }, + "item.label.Adaptors": { + "message": "Adaptors", + "description": "Navbar item with label Adaptors" + }, + "item.label.Articles": { + "message": "Artículos", + "description": "Navbar item with label Articles" + } +} diff --git a/sidebars-adaptors.js b/sidebars-adaptors.js index fe4b96418fd7..b94e3b8b5614 100644 --- a/sidebars-adaptors.js +++ b/sidebars-adaptors.js @@ -25,28 +25,38 @@ if ( return r; }, Object.create(null)); + // Every adaptor repeats the same item labels ('Functions', 'Overview', ...). + // Docusaurus derives a sidebar item's translation key from `key ?? label`, + // so without an explicit `key` those labels collide and the build throws + // `Multiple docs sidebar items produce the same translation key` for any + // non-default locale. Namespacing each key by adaptor keeps them unique. const items = adaptors.sort().map(a => { const base = { type: 'category', label: a.name, + key: a.name, items: [ { type: 'doc', label: 'Functions', + key: `${a.name}-functions`, id: a.docsId, }, { type: 'doc', label: 'Configuration', + key: `${a.name}-configuration`, id: a.configurationSchemaId, }, groupedJobs[a.name] && groupedJobs[a.name].length > 0 ? { type: 'category', label: 'Examples', + key: `${a.name}-examples`, items: groupedJobs[a.name].map(j => ({ type: 'doc', label: j.name, + key: `library/${j.id}`, id: `library/${j.id}`, })), } @@ -54,11 +64,13 @@ if ( { type: 'doc', label: 'Changelog', + key: `${a.name}-changelog`, id: a.changelogId, }, { type: 'doc', label: 'README.md', + key: `${a.name}-readme`, id: a.readmeId, }, ], @@ -70,6 +82,7 @@ if ( base.items.unshift({ type: 'doc', label: 'Overview', + key: `${a.name}-overview`, id: a.name, }); } @@ -88,7 +101,7 @@ if ( const extras = overviews .filter(id => !adaptors.map(a => `${a.name}`).includes(id)) - .map(id => ({ type: 'doc', id, label: id })); + .map(id => ({ type: 'doc', id, label: id, key: id })); list = [...items, ...extras].sort((a, b) => a.label.localeCompare(b.label)); } else { diff --git a/sidebars-main.js b/sidebars-main.js index 92ca90f868c2..d6ab10d3b7d7 100644 --- a/sidebars-main.js +++ b/sidebars-main.js @@ -161,6 +161,7 @@ module.exports = { 'contribute/writing-code', 'contribute/writing-docs', 'contribute/style-guide', + 'contribute/translating', ], }, 'get-help/support', diff --git a/src/pages/index.js b/src/pages/index.js index 4ef9e65e6de7..40905ef9f161 100644 --- a/src/pages/index.js +++ b/src/pages/index.js @@ -2,7 +2,7 @@ import React, { useCallback } from 'react'; import clsx from 'clsx'; import Layout from '@theme/Layout'; import Link from '@docusaurus/Link'; -import useDocusaurusContext from '@docusaurus/useDocusaurusContext'; +import Translate, { translate } from '@docusaurus/Translate'; import useBaseUrl from '@docusaurus/useBaseUrl'; import Particles from 'react-particles'; import { loadFull } from 'tsparticles'; @@ -10,77 +10,104 @@ import styles from './styles.module.css'; const highlights = [ { - title: 'Job Writing Guide', + title: translate({ + id: 'homepage.highlights.jobWritingGuide.title', + message: 'Job Writing Guide', + }), link: 'documentation/jobs/job-writing-guide', - description: 'Writing a job for OpenFn? Start here', + description: translate({ + id: 'homepage.highlights.jobWritingGuide.description', + message: 'Writing a job for OpenFn? Start here', + }), }, { - title: 'CLI Usage Examples', + title: translate({ + id: 'homepage.highlights.cliUsage.title', + message: 'CLI Usage Examples', + }), link: 'documentation/cli-usage', - description: 'See what the CLI can do at a glance', + description: translate({ + id: 'homepage.highlights.cliUsage.description', + message: 'See what the CLI can do at a glance', + }), }, { - title: 'JavaScript Tips & Tricks', + title: translate({ + id: 'homepage.highlights.javascriptTips.title', + message: 'JavaScript Tips & Tricks', + }), link: 'documentation/cli-usage', - description: 'Level up your code', + description: translate({ + id: 'homepage.highlights.javascriptTips.description', + message: 'Level up your code', + }), }, ]; const features = [ { - title: 'Docs', + title: translate({ id: 'homepage.features.docs.title', message: 'Docs' }), link: 'documentation', imageUrl: 'img/undraw_Code_review_re_woeb.svg', description: ( - <> + Documentation on all aspects of OpenFn, the leading digital public good for workflow automation. - + ), }, { - title: 'Adaptors', + title: translate({ + id: 'homepage.features.adaptors.title', + message: 'Adaptors', + }), link: 'adaptors', imageUrl: 'img/undraw_pair_programming_njlp.svg', description: ( - <> + Searchable and browseable adaptors docs, examples, changelogs, and overviews for connecting the world's most common DPGs. - + ), }, { - title: 'Articles', + title: translate({ + id: 'homepage.features.articles.title', + message: 'Articles', + }), link: 'articles', imageUrl: 'img/undraw_Portfolio_update_re_jqnp.svg', description: ( - <> + How to prepare for data integration? How to structure external IDs? How to... - + ), }, { - title: 'Blog', + title: translate({ id: 'homepage.features.blog.title', message: 'Blog' }), link: 'https://openfn.org/blog', imageUrl: 'img/undraw_reading_time_gvg0.svg', description: ( - <> + We help the world's most promising social impact interventions achieve scale through automation, data integration, and interoperability. These are their stories. - + ), }, { - title: 'Enterprise', + title: translate({ + id: 'homepage.features.enterprise.title', + message: 'Enterprise', + }), link: 'https://www.openfn.org', imageUrl: 'img/undraw_secure_server_s9u8.svg', description: ( - <> + Check out the enterprise-grade OpenFn integration-platform-as-a-service (iPaaS), offering free-forever plans and affordable pathways to scale. - + ), }, ]; @@ -109,9 +136,6 @@ function Feature({ imageUrl, title, description, link }) { } function Home() { - const context = useDocusaurusContext(); - const { siteConfig = {} } = context; - const particlesInit = useCallback(async engine => { await loadFull(engine); }, []); @@ -235,7 +259,13 @@ function Home() { }; return ( - +
-

OpenFn Documentation

-

{siteConfig.tagline}

+

+ OpenFn Documentation +

+ {/* The English copy here mirrors `tagline` in docusaurus.config.js. + Site-level config values are not extracted for translation, so the + hero subtitle is declared as a translatable string instead. */} +

+ + The leading digital public good for workflow automation, OpenFn + makes ICT4D more efficient. + +

- Get Started + Get Started
@@ -271,13 +311,22 @@ function Home() { Newsletter -

Newsletter

+

+ + Newsletter + +

- Never miss a story from us, subscribe to our newsletter - here. + + Never miss a story from us, subscribe to our newsletter + here. +

- Subscribe + + Subscribe +
@@ -312,7 +366,11 @@ function Home() { )}
-

✨Documentation Highlights✨

+

+ + ✨Documentation Highlights✨ + +

{highlights.map(h => (
diff --git a/style-exceptions.yml b/style-exceptions.yml new file mode 100644 index 000000000000..563597b2f443 --- /dev/null +++ b/style-exceptions.yml @@ -0,0 +1,43 @@ +# style-exceptions.yml +# +# Purpose +# ------- +# Lint findings that a human has rejected. The lint skill +# (.agents/skills/lint.md) loads this file and suppresses any finding that +# matches an entry, so the same rejected suggestion is not raised again. +# +# Humans maintain this file. Add an entry when you reject or revert a lint +# change in a PR and do not want it raised again. +# +# Schema +# ------ +# exceptions: +# - rule: string # lint rule id, one of: +# # terminology, heading-hierarchy, heading-case, +# # internal-link, external-link, orphan-page, +# # frontmatter, code-language, image-alt, +# # admonition-spacing +# scope: string # glob of files the exception applies to. +# # "**" = whole repo, "docs/jobs/**" = a section, +# # "docs/jobs/state.md" = one page. +# match: string # optional. Substring or regex the finding text must +# # contain for the exception to apply (e.g. a heading +# # text, a link URL, a term). Omit to suppress the whole +# # rule within the scope. +# reason: string # why the human rejected it. Required. +# added_by: string # GitHub handle +# added_on: string # ISO date (YYYY-MM-DD) +# source_pr: string # PR URL or number where the rejection happened +# +# Example +# ------- +# exceptions: +# - rule: heading-case +# scope: "docs/contribute/style-guide.md" +# match: "H1 - Create the best documentation" +# reason: The style guide intentionally shows every heading level. +# added_by: someone +# added_on: 2026-01-01 +# source_pr: https://github.com/OpenFn/docs/pull/000 + +exceptions: [] diff --git a/translation-rules.yml b/translation-rules.yml new file mode 100644 index 000000000000..07a70955629a --- /dev/null +++ b/translation-rules.yml @@ -0,0 +1,58 @@ +# translation-rules.yml +# +# Purpose +# ------- +# Locale-specific phrasing rules learned from human edits to machine +# translations. The translate skill (.agents/skills/translate.md) loads this +# file after glossary.yml and applies every rule whose `locale` matches the +# target locale. +# +# Glossary terms (never translate) belong in glossary.yml, not here. This file +# is for how to translate, not what to leave alone. +# +# Humans maintain this file. Add a rule when you correct a translation in a +# way that should apply to other pages too. +# +# Schema +# ------ +# rules: +# - locale: string # "es" or "fr" (or "*" for every locale) +# kind: string # one of: +# # term - a fixed rendering for a phrase +# # register - tone/voice guidance (formal vs informal "you") +# # punctuation - spacing, quotation marks, list punctuation +# # structure - how to handle headings, admonition titles, UI labels +# # avoid - a rendering the reviewer rejected +# source: string # English phrase or pattern the rule applies to (for +# # kind: term and avoid). Omit for global rules. +# target: string # required rendering (kind: term) or rejected rendering +# # (kind: avoid) +# instruction: string # plain-language rule the translator must follow +# example_source: string # optional English example +# example_target: string # optional translated example +# reason: string # why, in one sentence +# added_by: string # GitHub handle +# added_on: string # ISO date (YYYY-MM-DD) +# source_pr: string # PR URL or number where the edit happened +# +# Example +# ------- +# rules: +# - locale: es +# kind: register +# instruction: Address the reader as "tú", not "usted". +# reason: Matches the informal tone of the English docs. +# added_by: someone +# added_on: 2026-01-01 +# source_pr: https://github.com/OpenFn/docs/pull/000 +# - locale: fr +# kind: term +# source: "Save and Run" +# target: "Enregistrer et exécuter" +# instruction: UI button labels are translated to match the French UI strings in OpenFn/lightning. +# reason: Reviewer aligned button names with the app's own translations. +# added_by: someone +# added_on: 2026-01-01 +# source_pr: https://github.com/OpenFn/docs/pull/000 + +rules: []