Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 47 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,26 +24,63 @@ Build the same static site and validate the same links as CI:
npm run build
```

## Ukrainian translations
## Translations

English is the default locale. Current documentation and site pages are also
available in Ukrainian under `/uk/`. Preview that locale with:
English is the default locale. Ukrainian is available under `/uk/`. Spanish
onboarding and core guides are available under `/es/`. Untranslated reference
pages show the English text with a language notice and a link to the English
route. Blog articles and versioned 1.x documentation remain in English.

Preview one locale with:

```bash
npm run start -- --locale uk
npm run start -- --locale es
```

Translate current docs in `i18n/uk/docusaurus-plugin-content-docs/current/`
and standalone pages in `i18n/uk/docusaurus-plugin-content-pages/`. Keep the
Translate current docs in `i18n/<locale>/docusaurus-plugin-content-docs/current/`
and standalone pages in `i18n/<locale>/docusaurus-plugin-content-pages/`. Keep the
English source file paths, examples, commands, API names and explicit heading
anchors intact. Keep workflow, activity, worker, signal, timer, query, update
and saga as English technical terms.
anchors intact. Ukrainian keeps workflow, activity, worker, signal, timer,
query, update and saga as English technical terms. Spanish uses workflow and
worker, with actividad, señal, temporizador, consulta and actualización in
prose. Never translate identifiers in code, protocol fields or type names.

Use Docusaurus translation markers for component text. Run
`npm run write-translations -- --locale uk` to extract new messages, then
translate them in `i18n/uk/code.json` and the plugin message files. Build both
locales with `npm run build` before submitting a change. Blog articles and the
versioned 1.x docs use the English fallback.
translate them in `i18n/<locale>/code.json` and the plugin message files. Build
all locales with `npm run build` before submitting a change.

When changing an English guide that already has a translation, review and
update that translation in the same pull request. Review the prose for fluent
language and the technical contract for accuracy. Keep executable code blocks
identical to the English source. The build checks this for Spanish. If a
translation cannot be brought current, remove the stale translated file so
readers see the current English source and the fallback notice. Artifact
version placeholders stay shared with English and update automatically.

The documentation maintainers own translation upkeep. The existing build also
compares reviewed English source hashes for Spanish and reports the guides
needing review. Prose edits produce a notice, while changed executable examples
must still match. After reviewing and
updating the translation, run `node scripts/check-doc-translations.js --record-review`
and commit `i18n/es/source-hashes.json` with it. This command still checks the
code blocks. Recording hashes alone does not review the prose.

The pinned Docusaurus 3.10.2 utility patch resolves relative Markdown links
between translated and English fallback files. It uses Docusaurus's document
map and preserves strict missing-link checks and version boundaries. The
build exercises both directions. Recheck and remove the patch when upgrading
Docusaurus if the upstream resolver handles these cases.

For a new locale, qualify installation, a completed first workflow, core
concepts, safe recovery, navigation, search, language switching and fallback
before publication. Check representative pages in a browser, including mobile,
and verify canonical and alternate-language links. Spanish is the first
expansion in [#169](https://github.com/durable-workflow/durable-workflow.github.io/issues/169).
Portuguese (Brazil), Simplified Chinese and Japanese remain subsequent stages,
subject to audience evidence and language review. Country totals alone do not
establish a reader's preferred language.

## Repository layout

Expand Down
3 changes: 2 additions & 1 deletion docusaurus.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,11 @@ const config = {

i18n: {
defaultLocale: 'en',
locales: ['en', 'uk'],
locales: ['en', 'uk', 'es'],
localeConfigs: {
en: {label: 'English', htmlLang: 'en'},
uk: {label: 'Українська', htmlLang: 'uk'},
es: {label: 'Español', htmlLang: 'es'},
},
},

Expand Down
32 changes: 32 additions & 0 deletions i18n/es/code.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
{
"theme.SearchPage.existingResultsTitle": {"message": "Resultados de búsqueda de «{query}»"},
"theme.SearchPage.emptyResultsTitle": {"message": "Buscar en la documentación"},
"theme.SearchPage.searchContext.everywhere": {"message": "En todas partes"},
"theme.SearchPage.documentsFound.plurals": {"message": "Se ha encontrado {count} documento|Se han encontrado {count} documentos"},
"theme.SearchPage.noResultsText": {"message": "No se han encontrado documentos"},
"theme.SearchBar.noResultsText": {"message": "No hay resultados"},
"theme.SearchBar.seeAllOutsideContext": {"message": "Ver todos los resultados fuera de «{context}»"},
"theme.SearchBar.searchInContext": {"message": "Ver todos los resultados en «{context}»"},
"theme.SearchBar.seeAll": {"message": "Ver todos los resultados"},
"theme.SearchBar.label": {"message": "Buscar"},
"docs.translationFallback": {"message": "Esta página está disponible en inglés."},
"docs.readInEnglish": {"message": "Leer en inglés"},
"homepage.tagline": {"message": "Ejecución duradera para PHP, Python y Rust."},
"homepage.getStarted": {"message": "Empieza aquí"},
"homepage.deploymentModes": {"message": "Elige un modelo de despliegue"},
"homepage.description": {"message": "Plataforma de ejecución duradera para PHP, Python y Rust, disponible como Cloud gestionado, Server autogestionado o entorno integrado en Laravel."},
"homepage.cloudDescription": {"message": "Ejecuta workers de PHP, Python o Rust en un espacio de nombres gestionado mientras Durable Workflow opera el entorno de orquestación."},
"homepage.features.languages.title": {"message": "Desarrolla con PHP, Python o Rust"},
"homepage.features.languages.description": {"message": "Crea clientes, workflows y actividades con SDK oficiales que comparten un protocolo público y un modelo de datos Avro portable."},
"homepage.features.runtime.title": {"message": "Elige quién opera el entorno"},
"homepage.features.runtime.description": {"message": "Usa Durable Workflow Cloud, ejecuta un Server independiente o conserva el entorno integrado dentro de tu aplicación Laravel."},
"homepage.features.recovery.title": {"message": "Recupera el trabajo después de un fallo"},
"homepage.features.recovery.description": {"message": "El historial duradero, la reproducción determinista, los temporizadores, los reintentos, las señales, las actualizaciones, los workflows hijos y las sagas permiten continuar procesos largos."},
"promotion.eyebrow": {"message": "Servicio gestionado · grupo limitado"},
"promotion.title": {"message": "Grupo de lanzamiento de Durable Workflow Cloud"},
"promotion.requestAccess": {"message": "Solicita acceso anticipado"},
"navbar.github.repository": {"message": "Repositorio de GitHub"},
"navbar.github.repositoryStars": {"message": "{repository} ({count} estrellas)"},
"navbar.github.starCount": {"message": "Estrellas en GitHub: {count}"},
"navbar.github.stars": {"message": "Estrellas en GitHub"}
}
25 changes: 25 additions & 0 deletions i18n/es/docusaurus-plugin-content-docs/current.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{
"version.label": {"message": "2.0"},
"sidebar.tutorialSidebar.category.Service Mode": {"message": "Modo servicio"},
"sidebar.tutorialSidebar.category.Service Mode.link.generated-index.description": {"message": "Conecta clientes y workers oficiales de PHP, Python o Rust a Cloud o Server autogestionado. Cloud incluye Managed Waterline. Para Server, Waterline se despliega por separado."},
"sidebar.tutorialSidebar.category.CLI": {"message": "CLI"},
"sidebar.tutorialSidebar.category.CLI.link.generated-index.description": {"message": "Instala el cliente de operación dw y consulta sus comandos."},
"sidebar.tutorialSidebar.category.SDKs": {"message": "SDK"},
"sidebar.tutorialSidebar.category.SDKs.link.generated-index.description": {"message": "Crea clientes y workers en modo servicio con los SDK oficiales de PHP, Python y Rust."},
"sidebar.tutorialSidebar.category.Embedded": {"message": "Modo integrado"},
"sidebar.tutorialSidebar.category.Embedded.link.generated-index.description": {"message": "Instala, desarrolla, prueba y configura workflows dentro de una aplicación Laravel."},
"sidebar.tutorialSidebar.category.Defining Workflows": {"message": "Definición de workflows"},
"sidebar.tutorialSidebar.category.Defining Workflows.link.generated-index.description": {"message": "Define workflows, actividades, datos, identificadores y estados en Laravel integrado."},
"sidebar.tutorialSidebar.category.Features": {"message": "Funciones"},
"sidebar.tutorialSidebar.category.Features.link.generated-index.description": {"message": "Elige mensajes, comandos duraderos, esperas, reintentos, versiones y límites de historial para Laravel integrado."},
"sidebar.tutorialSidebar.category.Constraints": {"message": "Restricciones"},
"sidebar.tutorialSidebar.category.Constraints.link.generated-index.description": {"message": "Conoce las reglas de determinismo y los límites estructurales del modo integrado."},
"sidebar.tutorialSidebar.category.Configuration": {"message": "Configuración"},
"sidebar.tutorialSidebar.category.Configuration.link.generated-index.description": {"message": "Configura almacenamiento, conexiones, límites y retención para Laravel integrado."},
"sidebar.tutorialSidebar.category.Run And Operate": {"message": "Ejecución y operación"},
"sidebar.tutorialSidebar.category.Run And Operate.link.generated-index.description": {"message": "Despliega, observa, diagnostica, recupera y mantén tus workflows."},
"sidebar.tutorialSidebar.category.External Execution And Ingress": {"message": "Ejecución externa y entrada de solicitudes"},
"sidebar.tutorialSidebar.category.External Execution And Ingress.link.generated-index.description": {"message": "Conecta API HTTP, workers externos, colas y otras integraciones de protocolo."},
"sidebar.tutorialSidebar.category.AI And Automation": {"message": "IA y automatización"},
"sidebar.tutorialSidebar.category.AI And Automation.link.generated-index.description": {"message": "Proporciona documentación, manifiestos, comandos y herramientas estables a agentes y automatización."}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
---
sidebar_position: 3
---

# Restricciones de las actividades {#activity-constraints}

Las actividades realizan las operaciones de entrada/salida y los efectos
externos de un workflow. Su código se ejecuta **al menos una vez**. Los
reintentos, el vencimiento de una lease y la reentrega pueden hacer que el
mismo trabajo lógico se ejecute varias veces.

Si una actividad cobra un pago, envía un correo, escribe en otro sistema o
modifica un recurso externo, la operación debe ser segura al repetirse.

## Consecuencias prácticas {#what-this-means-in-practice}

- `activity_execution_id` es la identidad idempotente predeterminada de una
ejecución lógica de actividad.
- Cada intento tiene además su propio `activity_attempt_id`.
- Un worker puede completar el efecto externo, perder su lease y comunicar el
resultado tarde. El motor puede rechazar ese resultado porque otro worker
ya registró el resultado duradero. El efecto externo puede haber ocurrido.
- Las actividades pueden usar entrada/salida, el reloj del sistema y estado
mutable del proceso. El código de workflow debe mantenerse determinista.

## Patrones de idempotencia recomendados {#preferred-idempotency-patterns}

Muchas API externas aceptan una cabecera `Idempotency-Key`. Cuando el servicio
lo permita, usa la identidad lógica de la actividad:

- Prefiere `activity_execution_id` si los reintentos deben representar la
misma solicitud lógica.
- Usa `activity_attempt_id` cuando el sistema externo necesite distinguir
cada intento de ese trabajo.

También puedes:

- Escribir en un recurso externo con un nombre o una clave determinista.
- Usar operaciones upsert o tablas de deduplicación con un identificador duradero.
- Diseñar la operación para que repetirla no cambie el resultado.

Algunas operaciones ya son idempotentes: codificar el mismo vídeo puede
producir el mismo archivo, y borrar un archivo ya borrado no produce otro
efecto.

En otras operaciones, duplicar puede ser preferible a perder el resultado.
Si no sabes si un proveedor envió un correo, puede ser más seguro enviarlo de
nuevo que omitir la notificación. Decide esa compensación de forma explícita.

## Suposiciones que debes evitar {#what-not-to-assume}

- Un intento de actividad puede llegar a más de un worker.
- Un reintento no demuestra que el efecto externo anterior haya fallado.
- Un resultado tardío no demuestra que la actividad no se ejecutara.
- Mantén los efectos externos en actividades. Llevarlos al código de workflow
convierte el problema de idempotencia en un problema de determinismo.

Consulta el contrato completo en
[Garantías de ejecución e idempotencia](./execution-guarantees.md) y el modelo
de recuperación para operadores en [Fallos y recuperación](../failures-and-recovery.md).
Loading
Loading