<a id="automation-reference"></a>

# Automation reference and cookbook

The [Automation](https://docs.weblate.org/ro/latest/admin/addons.md#addon-weblate-automation-automation) add-on runs declarative workflows
using existing Weblate operations. This page describes the workflow structure,
triggers, conditions, and actions. See [Cookbook](#automation-cookbook) for complete
examples, including [Apply translation memory before machine translation](#automation-translation-ordering).

<!-- AUTOGENERATED START: workflows -->
<!-- This section is automatically generated by `./manage.py list_automation`. Do not edit manually. -->

<a id="automation-workflows"></a>

## Workflow definition

#### Versionadded
Added in version 2026.10.

#### Parametrii

| Nume         | Required   | Type or allowed values                            |
|--------------|------------|---------------------------------------------------|
| `version`    | Yes        | `1`                                               |
| `triggers`   | Yes        | List of (object); maximum items 100; unique items |
| `conditions` | No         | List of (condition); maximum items 100            |
| `actions`    | Yes        | List of (action); maximum items 100               |
<!-- AUTOGENERATED END: workflows -->

Enter YAML or JSON in the add-on’s Workflow field. The API accepts
the same structure as the `workflow` member of `configuration`. The
[`JSON Schema`](https://docs.weblate.org/ro/latest/admin/_downloads/3c36c60db683d0580f9999fb3d2b94cc/automation.schema.json) describes this
representation independently of the editor. Unknown keys are rejected.

`version` identifies the workflow schema version, not the Weblate release.
List the events to subscribe to in `triggers`, conditions that must pass before
any action runs in `conditions`, and the ordered operations in `actions`.
Omitting `conditions` is equivalent to an empty list. Empty `triggers` allows
manual execution only; empty `actions` performs no operations.

### Literal settings and expressions

Action settings are literal YAML/JSON values. Only the `value` of an
`expression` condition is evaluated as CEL. Queries, engine IDs, labels, and
other settings do not support CEL expressions, variable substitution, or template
syntax such as `{{ unit.id }}`. A query containing that syntax is not expanded.
Use [Choose](#automation-action-choose) to select actions with different fixed
settings. Actions select strings using their `scope` and optional query.

### String scope

Set `scope` on an action to choose its starting selection. `component` is
the default and retains the existing component-wide behavior. `trigger` uses
the unit affected by a change event; a source-unit change selects its
corresponding target-language units. `result:ID` uses units actually changed
or given new suggestions by an earlier action with that `id`. For an AI quality
action, it uses units successfully evaluated by that action. Set
`settings.q` to filter the selected units further. For `trigger` and
`result:ID`, omitting `q` selects the whole scope.

For example, a translation action with `id: machine` and `scope: trigger`
can be followed by a bulk edit with `scope: result:machine`. The second
action sees only units affected by the first. Source-level edits can select the
corresponding target units in a later action.

Workflows using `scope: trigger` can declare only change triggers. A change
without a unit, or a manual run without change context, fails if execution
reaches that action. A `result:ID` action fails if its referenced action did
not run, for example because a branch was skipped. Preview marks result scopes
as conditional because earlier actions have not run.

Selections are kept only while the run is active. The activity log records
affected counts and scoped unit counts (before the `q` filter), but does not
store the full unit ID lists.

<a id="automation-execution-context"></a>

### Execution context

CEL conditions can access the following fields. Context is captured when the run
is scheduled, and only `results` changes between actions. In particular,
`unit.state` is a snapshot; use `matching_strings` for current database state.
Timestamps are strings, not CEL timestamp objects.

#### Context fields

| Domeniul                  | Type                     | Meaning                                                                                   |
|---------------------------|--------------------------|-------------------------------------------------------------------------------------------|
| `component.id`            | integer                  | Target component ID; always present.                                                      |
| `component.slug`          | string                   | Target component slug.                                                                    |
| `component.project`       | string                   | Project slug, not a project object.                                                       |
| `component.category`      | string or null           | Category slug; null for an uncategorized component.                                       |
| `language.id`             | integer                  | Event language ID, when language is available.                                            |
| `language.code`           | string                   | Event language code, when language is available.                                          |
| `unit.id`                 | integer                  | Event unit ID, when unit is available.                                                    |
| `unit.state`              | integer                  | Captured string state; see [String states](#automation-string-states).  |
| `unit.source`             | string                   | Source text, truncated to 4,096 characters.                                               |
| `unit.target`             | string                   | Target text, truncated to 4,096 characters.                                               |
| `change.id`               | integer                  | Triggering change ID, when change is available.                                           |
| `change.action`           | integer                  | Numeric ActionEvents value, not the lowercase event name.                                 |
| `change.timestamp`        | string                   | Change timestamp in ISO 8601 format with a timezone offset.                               |
| `actor.id`                | integer                  | Recorded actor ID, when actor is available.                                               |
| `actor.username`          | string                   | Recorded actor username.                                                                  |
| `trigger.name`            | string                   | Trigger identifier such as change, daily, or manual.                                      |
| `trigger.timestamp`       | string                   | Change timestamp, or scheduling time for other triggers; ISO 8601 with a timezone offset. |
| `trigger.revision`        | string or null           | Component local revision recorded when scheduled; null if unavailable.                    |
| `trigger.unit_ids`        | list of integers or null | Currently a one-element list when the change references a unit; otherwise null.           |
| `trigger.source_unit_ids` | list of integers or null | Source-unit IDs corresponding to `trigger.unit_ids`; otherwise null.                      |
| `results`                 | object                   | Initially empty; maps action IDs to successful operation outputs.                         |

Availability depends on the trigger:

* `change` supplies `change`. It supplies `unit` and `language` only when
  the change references them, and `actor` from the change’s user or, if absent,
  its author. Any of those optional objects can be null.
* `manual` supplies `actor` when initiated by a user through the UI or API.
  Other manual entry points may have no actor. `change`, `unit`, and
  `language` are null.
* `daily`, `component_update`, `post_update`, `post_commit`, and
  `post_push` have null `actor`, `change`, `unit`, and `language`.
* A preview with a change ID uses that change’s context and `trigger.name` of
  `change`. Without one, it uses manual context.

When an object is null, its child fields cannot be accessed directly. For
example, use `unit != null && unit.state == 10` or
`language != null && language.code == "de"`. Prefer the typed `unit_state`,
`language`, and `change_action` conditions when possible; they handle missing
context and event-name conversion for you. See [Translate after source changes](#automation-event-example).

### Execution identity and permissions

The usual add-on management permission authorizes configuration, preview, and
manual execution. `actor` records who caused an event; it does not select the
account or permissions used to perform actions. Changing a condition on `actor`
only determines whether the workflow runs.

Operations execute with the add-on’s authority within its configured scope, not
with the triggering user’s individual translation permissions. Automatic
translation receives the Automation add-on bot as its execution user and does not
apply per-user operation permission checks. Reused translations can retain their
original author attribution. Bulk editing calls the shared operation without a
user, rather than impersonating the recorded actor. The activity context retains
the actor separately from translation change attribution.

Before a queued run executes, Weblate checks that the add-on is still valid and
the component still belongs to its scope. The queued definition and event context
are snapshots: editing the workflow after scheduling does not change that run.
Operation settings are validated again against the target component at execution.

### Testing and execution

Use Preview without changes to validate a workflow and inspect its
conditions and planned actions. Inherited automations require a preview component
ID. An optional change ID supplies event context and must belong to that component.
Preview neither calls translation services nor changes strings. Conditions that
depend on unexecuted action results or changed strings are marked unknown, and
their branches are shown as conditional. Use Run now for real execution.
The [Suplimente](https://docs.weblate.org/ro/latest/api.md#addons-api) provides equivalent preview and run operations.

Runs use ordinary Celery tasks and existing operation locks. Separate runs may
overlap; there are no execution modes or parallel action blocks. The activity log
records the definition, context, conditions, actions, and failures. An error stops
later actions without rolling back completed work. Runs are not automatically
replayed; after a worker is forcibly terminated, a pending log can remain and must
be inspected before manually starting another run. Changes originating from an
automation, including follow-up tasks, do not start other automation runs.

### Validation and limits

Workflows must contain JSON-compatible values with string mapping keys. YAML
aliases, explicit tags, duplicate mapping keys, non-finite numbers, and native
YAML date/timestamp values are rejected. Quote a date if a string is intended.
Unknown fields are rejected, and action IDs must be unique across the entire
workflow, including mutually exclusive branches. Missing required fields and
wrong value types are errors; for example, `state` must be an integer, not
`"10"`. Nested mappings and lists also have a structural depth limit of 32.

Generated parameter tables show list limits, uniqueness requirements, numeric
bounds, and string patterns from the schema. Item constraints in parentheses
apply to each list element. The workflow-wide node and nesting limits below
still apply even when each individual list is within its limit.

Definitions are limited to 64 KiB both as submitted and as ASCII-escaped JSON
after operation defaults are applied, 100 action/condition nodes, and eight nesting
levels. CEL expressions are limited to 4,096 characters and evaluated in a helper
process with two seconds of CPU time and five seconds of wall time per invocation.
The helper also limits virtual address space to 512 MiB except on macOS, where
no memory cap is enforced. The helper fails closed if a required operating-system
resource limit cannot be applied. The pinned CEL runtime provides native wheels;
Linux installations require a supported glibc platform. No runtime settings or
separate service are required. Use [Add-on de scriere](https://docs.weblate.org/ro/latest/admin/addons.md#own-addon) for unrestricted custom Python
logic on self-hosted installations.

<!-- AUTOGENERATED START: triggers -->
<!-- This section is automatically generated by `./manage.py list_automation`. Do not edit manually. -->

## Declanșări

<!-- AUTOGENERATED END: triggers -->

Each trigger is an object in the workflow’s `triggers` list. An instance can
subscribe to multiple triggers. Manual execution is always available, even when
`manual` is absent from the list.

<!-- AUTOGENERATED START: trigger-daily -->
<!-- This section is automatically generated by `./manage.py list_automation`. Do not edit manually. -->

<a id="automation-trigger-daily"></a>

### daily

#### Parametrii

| Nume      | Required   | Type or allowed values   |
|-----------|------------|--------------------------|
| `trigger` | Yes        | `"daily"`                |
<!-- AUTOGENERATED END: trigger-daily -->

Runs on [Daily](https://docs.weblate.org/ro/latest/admin/addons.md#addon-event-daily), respecting [`BACKGROUND_TASKS`](https://docs.weblate.org/ro/latest/admin/config.md#std-setting-BACKGROUND_TASKS).

<!-- AUTOGENERATED START: trigger-component_update -->
<!-- This section is automatically generated by `./manage.py list_automation`. Do not edit manually. -->

<a id="automation-trigger-component-update"></a>

### component_update

#### Parametrii

| Nume      | Required   | Type or allowed values   |
|-----------|------------|--------------------------|
| `trigger` | Yes        | `"component_update"`     |
<!-- AUTOGENERATED END: trigger-component_update -->

Runs on [Component update](https://docs.weblate.org/ro/latest/admin/addons.md#addon-event-component-update), after Weblate updates the component.

<!-- AUTOGENERATED START: trigger-post_update -->
<!-- This section is automatically generated by `./manage.py list_automation`. Do not edit manually. -->

<a id="automation-trigger-post-update"></a>

### post_update

#### Parametrii

| Nume      | Required   | Type or allowed values   |
|-----------|------------|--------------------------|
| `trigger` | Yes        | `"post_update"`          |
<!-- AUTOGENERATED END: trigger-post_update -->

Runs on [Repository post-update](https://docs.weblate.org/ro/latest/admin/addons.md#addon-event-repository-post-update).

<!-- AUTOGENERATED START: trigger-post_commit -->
<!-- This section is automatically generated by `./manage.py list_automation`. Do not edit manually. -->

<a id="automation-trigger-post-commit"></a>

### post_commit

#### Parametrii

| Nume      | Required   | Type or allowed values   |
|-----------|------------|--------------------------|
| `trigger` | Yes        | `"post_commit"`          |
<!-- AUTOGENERATED END: trigger-post_commit -->

Runs on [Repository post-commit](https://docs.weblate.org/ro/latest/admin/addons.md#addon-event-repository-post-commit).

<!-- AUTOGENERATED START: trigger-post_push -->
<!-- This section is automatically generated by `./manage.py list_automation`. Do not edit manually. -->

<a id="automation-trigger-post-push"></a>

### post_push

#### Parametrii

| Nume      | Required   | Type or allowed values   |
|-----------|------------|--------------------------|
| `trigger` | Yes        | `"post_push"`            |
<!-- AUTOGENERATED END: trigger-post_push -->

Runs on [Repository post-push](https://docs.weblate.org/ro/latest/admin/addons.md#addon-event-repository-post-push).

<!-- AUTOGENERATED START: trigger-manual -->
<!-- This section is automatically generated by `./manage.py list_automation`. Do not edit manually. -->

<a id="automation-trigger-manual"></a>

### manual

#### Parametrii

| Nume      | Required   | Type or allowed values   |
|-----------|------------|--------------------------|
| `trigger` | Yes        | `"manual"`               |
<!-- AUTOGENERATED END: trigger-manual -->

Runs when an administrator selects Run now, or requests manual
execution through the [Suplimente](https://docs.weblate.org/ro/latest/api.md#addons-api).

<!-- AUTOGENERATED START: trigger-change -->
<!-- This section is automatically generated by `./manage.py list_automation`. Do not edit manually. -->

<a id="automation-trigger-change"></a>

### change

#### Parametrii

| Nume      | Required   | Type or allowed values                                                                                                                        |
|-----------|------------|-----------------------------------------------------------------------------------------------------------------------------------------------|
| `trigger` | Yes        | `"change"`                                                                                                                                    |
| `events`  | Yes        | List of (Event name from [Selected change events](https://docs.weblate.org/ro/latest/admin/addons.md#change-actions)); minimum items 1; unique items |
<!-- AUTOGENERATED END: trigger-change -->

Subscribes to the selected [Selected change events](https://docs.weblate.org/ro/latest/admin/addons.md#change-actions). Use lowercase `ActionEvents`
names with underscores, for example `source_change` or `new_source_repo`.
These distinguish edits in Weblate from uploads and repository imports;
`source_change` alone does not cover all three. Only changes associated with a
component can start a run.

<!-- AUTOGENERATED START: conditions -->
<!-- This section is automatically generated by `./manage.py list_automation`. Do not edit manually. -->

## Conditions

<!-- AUTOGENERATED END: conditions -->

Every condition in a list must pass. A false workflow-level condition skips the
run. Conditions can also select a [Choose](#automation-action-choose) branch.
Conditions concerning unavailable language, unit, or change context return false.
An empty condition list passes.

<!-- AUTOGENERATED START: condition-expression -->
<!-- This section is automatically generated by `./manage.py list_automation`. Do not edit manually. -->

<a id="automation-condition-expression"></a>

### expression

#### Parametrii

| Nume        | Required   | Type or allowed values      |
|-------------|------------|-----------------------------|
| `condition` | Yes        | `"expression"`              |
| `value`     | Yes        | string; maximum length 4096 |
<!-- AUTOGENERATED END: condition-expression -->

Evaluates `value` as CEL and requires a boolean result. CEL supports arithmetic,
comparisons, standard functions, and comprehensions, but cannot call Python or
access the database, network, or filesystem. Expressions can use the captured
execution context and outputs of earlier actions, for example
`results.machine.updated > 0`. Missing fields or expression errors fail the run.

<!-- AUTOGENERATED START: condition-component_category -->
<!-- This section is automatically generated by `./manage.py list_automation`. Do not edit manually. -->

<a id="automation-condition-component-category"></a>

### component_category

#### Parametrii

| Nume        | Required   | Type or allowed values      |
|-------------|------------|-----------------------------|
| `condition` | Yes        | `"component_category"`      |
| `value`     | Yes        | string; maximum length 4096 |
<!-- AUTOGENERATED END: condition-component_category -->

Compares the triggering component’s category slug with `value`.

<!-- AUTOGENERATED START: condition-language -->
<!-- This section is automatically generated by `./manage.py list_automation`. Do not edit manually. -->

<a id="automation-condition-language"></a>

### language

#### Parametrii

| Nume        | Required   | Type or allowed values      |
|-------------|------------|-----------------------------|
| `condition` | Yes        | `"language"`                |
| `value`     | Yes        | string; maximum length 4096 |
<!-- AUTOGENERATED END: condition-language -->

Compares the event’s language code with `value`. This tests the trigger context;
it does not restrict subsequent actions to that language. Use an action’s search
query to restrict the strings it processes.

<!-- AUTOGENERATED START: condition-matching_strings -->
<!-- This section is automatically generated by `./manage.py list_automation`. Do not edit manually. -->

<a id="automation-condition-matching-strings"></a>

### matching_strings

#### Parametrii

| Nume        | Required   | Type or allowed values      |
|-------------|------------|-----------------------------|
| `condition` | Yes        | `"matching_strings"`        |
| `value`     | Yes        | string; maximum length 4096 |
<!-- AUTOGENERATED END: condition-matching_strings -->

Passes when the component currently contains at least one string matching the
[search query](https://docs.weblate.org/ro/latest/user/search.md#search-strings) in `value`. The query runs when the condition
is evaluated, so it can observe changes made by earlier actions.

<!-- AUTOGENERATED START: condition-change_action -->
<!-- This section is automatically generated by `./manage.py list_automation`. Do not edit manually. -->

<a id="automation-condition-change-action"></a>

### change_action

#### Parametrii

| Nume        | Required   | Type or allowed values                                                                               |
|-------------|------------|------------------------------------------------------------------------------------------------------|
| `condition` | Yes        | `"change_action"`                                                                                    |
| `value`     | Yes        | Event name from [Selected change events](https://docs.weblate.org/ro/latest/admin/addons.md#change-actions) |
<!-- AUTOGENERATED END: condition-change_action -->

Compares the triggering change’s action with `value`. Use the lowercase event
name, as for [change](#automation-trigger-change).

<!-- AUTOGENERATED START: condition-unit_state -->
<!-- This section is automatically generated by `./manage.py list_automation`. Do not edit manually. -->

<a id="automation-condition-unit-state"></a>

### unit_state

#### Parametrii

| Nume        | Required   | Type or allowed values                   |
|-------------|------------|------------------------------------------|
| `condition` | Yes        | `"unit_state"`                           |
| `value`     | Yes        | `0`, `10`, `11`, `12`, `20`, `30`, `100` |
<!-- AUTOGENERATED END: condition-unit_state -->

Compares the triggering unit’s captured state with the integer `value`.
It uses the event snapshot, not a new query of the unit after earlier actions.

<!-- AUTOGENERATED START: condition-and -->
<!-- This section is automatically generated by `./manage.py list_automation`. Do not edit manually. -->

<a id="automation-condition-and"></a>

### and

#### Parametrii

| Nume         | Required   | Type or allowed values                 |
|--------------|------------|----------------------------------------|
| `condition`  | Yes        | `"and"`                                |
| `conditions` | Yes        | List of (condition); maximum items 100 |
<!-- AUTOGENERATED END: condition-and -->

Passes when every nested condition passes. Evaluation stops at the first false
condition. An empty list passes.

<!-- AUTOGENERATED START: condition-or -->
<!-- This section is automatically generated by `./manage.py list_automation`. Do not edit manually. -->

<a id="automation-condition-or"></a>

### or

#### Parametrii

| Nume         | Required   | Type or allowed values                 |
|--------------|------------|----------------------------------------|
| `condition`  | Yes        | `"or"`                                 |
| `conditions` | Yes        | List of (condition); maximum items 100 |
<!-- AUTOGENERATED END: condition-or -->

Passes when any nested condition passes. Evaluation stops at the first true
condition. An empty list does not pass.

<!-- AUTOGENERATED START: condition-not -->
<!-- This section is automatically generated by `./manage.py list_automation`. Do not edit manually. -->

<a id="automation-condition-not"></a>

### not

#### Parametrii

| Nume         | Required   | Type or allowed values                 |
|--------------|------------|----------------------------------------|
| `condition`  | Yes        | `"not"`                                |
| `conditions` | Yes        | List of (condition); maximum items 100 |
<!-- AUTOGENERATED END: condition-not -->

Negates exactly one nested condition. Empty lists and lists containing multiple
conditions are invalid.

<!-- AUTOGENERATED START: actions -->
<!-- This section is automatically generated by `./manage.py list_automation`. Do not edit manually. -->

## Actions

<!-- AUTOGENERATED END: actions -->

Actions run in list order. Each operation and its batched checks finish before
the next action starts. Actions target the component; use [Searching for strings](https://docs.weblate.org/ro/latest/user/search.md#search-strings)
queries to narrow them. Queries are evaluated when each action executes.

Optional unique action IDs expose outputs as `results.<id>`. An ID starts with
a lowercase letter and contains up to 64 lowercase letters, digits, or
underscores. After a successful operation, its output is stored in the activity
log and, when it has an ID, in `results.<id>` for later CEL conditions. For
example, `results.memory.updated > 0` tests whether the `memory` action
reported updates. Outputs belong to the current run and are not shared with
other runs.

Skipped, failed, and previewed operations do not create result entries. If an
action might be skipped, guard access with a presence check such as
`has(results.memory) && results.memory.updated > 0`. A failed operation records
an error in the trace and stops later actions; its partial changes are not rolled
back. Actions without IDs still record their outputs in the activity log.

The YAML examples below are items to place in the workflow’s `actions` list.
The cookbook provides complete workflow definitions.

Settings and queries are validated against the target component before execution.
For inherited workflows, labels must exist in each target project and selected
engines must be enabled there.

<!-- AUTOGENERATED START: action-weblate.automatic_translation -->
<!-- This section is automatically generated by `./manage.py list_automation`. Do not edit manually. -->

<a id="automation-action-weblate-automatic-translation"></a>

### Traducere automată

#### Versionadded
Added in version 2026.10.

#### Parametrii

| Nume                   | Required   | Type or allowed values                                                      |
|------------------------|------------|-----------------------------------------------------------------------------|
| `action`               | Yes        | `"weblate.automatic_translation"`                                           |
| `id`                   | No         | string; pattern `^[a-z][a-z0-9_]{0,63}$`                                    |
| `scope`                | No         | `"component"`, `"trigger"`, string; pattern `^result:[a-z][a-z0-9_]{0,63}$` |
| `settings`             | Yes        | object                                                                      |
| `settings.mode`        | No         | `"suggest"`, `"translate"`, `"fuzzy"`, `"approved"`                         |
| `settings.q`           | No         | string; maximum length 4096                                                 |
| `settings.auto_source` | No         | `"others"`, `"mt"`                                                          |
| `settings.component`   | No         | integer or null; minimum 1                                                  |
| `settings.engines`     | No         | List of (string; maximum length 4096); maximum items 100                    |
| `settings.threshold`   | No         | integer; minimum 1; maximum 100                                             |

#### Result fields

| Nume               | Required   | Type or allowed values                                  |
|--------------------|------------|---------------------------------------------------------|
| `component`        | Yes        | integer                                                 |
| `updated`          | Yes        | integer                                                 |
| `message`          | Yes        | string                                                  |
| `warnings`         | Yes        | List of (string; maximum length 1024); maximum items 20 |
| `warnings_omitted` | Yes        | integer; minimum 0                                      |
<!-- AUTOGENERATED END: action-weblate.automatic_translation -->

Runs [Traducere automată](https://docs.weblate.org/ro/latest/user/translating.md#auto-translation) synchronously. `auto_source: others` reuses
translations from other components, optionally restricted by the source
`component` ID. `auto_source: mt` uses the service IDs in `engines`;
translation memory and AI services use the same mechanism as other providers.

Defaults are `auto_source: others`, `mode: suggest`, `q: state:<translated`,
`threshold: 80`, no source component restriction, and an empty engine list.
For a scoped action, omitted `q` selects its whole scope instead. Provide
configured engine IDs when selecting `mt`.

`mode` selects suggestions (`suggest`), translations (`translate`), strings
needing editing (`fuzzy`), or approved translations (`approved`). Approval
follows each language’s effective review settings. `threshold` is a minimum
score from 1 to 100 for services; each service has its own maximum score.

#### Example

Apply local translation memory matches scoring at least 95 to strings still
needing translation. Enable [Memorie de traducere Weblate](https://docs.weblate.org/ro/latest/admin/machine.md#mt-weblate-translation-memory) in the target
project before running this action.

```yaml
- action: weblate.automatic_translation
  id: memory
  settings:
    auto_source: mt
    engines: [weblate-translation-memory]
    threshold: 95
    mode: translate
    q: "state:<translated"
```

See [Apply translation memory before machine translation](#automation-translation-ordering) to follow this pass with a remote
translation service.

#### Outputs

`component` (integer)
: ID of the component processed, not the optional source component.

`updated` (integer)
: Number of translation updates or new suggestions reported across the
  component’s languages. In suggestion mode, this counts newly created
  suggestions, not strings whose translation state changed. A translation that
  exceeds the string’s maximum length can also become a suggestion, even in
  translation mode. Zero means the operation reported no updates; it is not
  an error by itself.

`message` (string)
: Human-readable completion summary in English. Use `updated` for conditions
  instead of parsing this message.

`warnings` (list of strings)
: Warnings reported by automatic translation, or an empty list when none were
  reported. At most 20 messages are retained, each truncated to 1,024 characters.
  A successful action can still have warnings; inspect them when fewer strings
  were translated than expected.

`warnings_omitted` (integer)
: Number of warning messages omitted beyond the first 20. This does not count
  characters removed from retained messages.

For example, a successful run might record:

```json
{
  "component": 42,
  "updated": 3,
  "message": "Automatic translation completed, 3 strings were updated.",
  "warnings": [],
  "warnings_omitted": 0
}
```

A later condition can access these fields through `results.memory`, for example
`results.memory.updated > 0 && size(results.memory.warnings) == 0`.

<!-- AUTOGENERATED START: action-weblate.ai_quality -->
<!-- This section is automatically generated by `./manage.py list_automation`. Do not edit manually. -->

<a id="automation-action-weblate-ai-quality"></a>

### AI quality evaluation

#### Versionadded
Added in version 2026.10.

#### Parametrii

| Nume               | Required   | Type or allowed values                                                      |
|--------------------|------------|-----------------------------------------------------------------------------|
| `action`           | Yes        | `"weblate.ai_quality"`                                                      |
| `id`               | No         | string; pattern `^[a-z][a-z0-9_]{0,63}$`                                    |
| `scope`            | No         | `"component"`, `"trigger"`, string; pattern `^result:[a-z][a-z0-9_]{0,63}$` |
| `settings`         | Yes        | object                                                                      |
| `settings.service` | Yes        | string; maximum length 4096                                                 |
| `settings.q`       | No         | string; maximum length 4096                                                 |

#### Result fields

| Nume        | Required   | Type or allowed values   |
|-------------|------------|--------------------------|
| `component` | Yes        | integer                  |
| `evaluated` | Yes        | integer; minimum 0       |
<!-- AUTOGENERATED END: action-weblate.ai_quality -->

Evaluates existing target translations synchronously using the effective
[AI quality evaluation add-on](https://docs.weblate.org/ro/latest/admin/addons.md#addon-weblate-ai-quality). The required
`service` must match that add-on’s evaluation service and be configured for
the target project. The optional `q` filters the action’s scope further;
the add-on’s own query and eligibility rules still apply. Empty scoped
selections make no provider requests.

Each evaluated string is available to a later `result:ID` action when this
action has an `id`. `evaluated` counts those strings; unit IDs are kept only
during the run. The action stops later steps if a request fails, is rate
limited, or its response is discarded because the string changed during
evaluation. Earlier successful batches can retain their findings, so a later
run may reevaluate them. See [Evaluate AI translations before approval](#automation-ai-quality-gateway) for a complete
translation and review workflow.

<!-- AUTOGENERATED START: action-weblate.bulk_edit -->
<!-- This section is automatically generated by `./manage.py list_automation`. Do not edit manually. -->

<a id="automation-action-weblate-bulk-edit"></a>

### Bulk editing

#### Versionadded
Added in version 2026.10.

#### Parametrii

| Nume                                | Required   | Type or allowed values                                                      |
|-------------------------------------|------------|-----------------------------------------------------------------------------|
| `action`                            | Yes        | `"weblate.bulk_edit"`                                                       |
| `id`                                | No         | string; pattern `^[a-z][a-z0-9_]{0,63}$`                                    |
| `scope`                             | No         | `"component"`, `"trigger"`, string; pattern `^result:[a-z][a-z0-9_]{0,63}$` |
| `settings`                          | Yes        | object                                                                      |
| `settings.q`                        | No         | string; maximum length 4096                                                 |
| `settings.state`                    | No         | integer                                                                     |
| `settings.add_flags`                | No         | string; maximum length 4096                                                 |
| `settings.remove_flags`             | No         | string; maximum length 4096                                                 |
| `settings.add_translation_flags`    | No         | string; maximum length 4096                                                 |
| `settings.remove_translation_flags` | No         | string; maximum length 4096                                                 |
| `settings.add_labels`               | No         | List of (string; maximum length 4096); maximum items 100                    |
| `settings.remove_labels`            | No         | List of (string; maximum length 4096); maximum items 100                    |

#### Result fields

| Nume        | Required   | Type or allowed values   |
|-------------|------------|--------------------------|
| `component` | Yes        | integer                  |
| `updated`   | Yes        | integer                  |
<!-- AUTOGENERATED END: action-weblate.bulk_edit -->

Uses the same operation as [Editare în masă](https://docs.weblate.org/ro/latest/admin/addons.md#addon-weblate-flags-bulk). For component scope,
`q` is required and selects strings using [Searching for strings](https://docs.weblate.org/ro/latest/user/search.md#search-strings). For trigger
and result scopes, `q` is optional and filters the selected strings.
`state` sets an integer string state, or leaves it unchanged with -1 (the
default).

<a id="automation-string-states"></a>

#### String states

#### State values

| Valoare   | Meaning                         | Accepted as a bulk-edit target         |
|-----------|---------------------------------|----------------------------------------|
| `-1`      | Leave unchanged                 | Yes; default, not an actual unit state |
| `0`       | Empty                           | No                                     |
| `10`      | Necesită editare                | Yes                                    |
| `11`      | Needs editing (needs rewriting) | Yes                                    |
| `12`      | Needs editing (needs checking)  | Yes                                    |
| `20`      | Tradus                          | Yes                                    |
| `30`      | Aprobat                         | Yes                                    |
| `100`     | Doar în citire                  | No                                     |

The `unit_state` condition accepts actual unit states, including 0 and 100,
but not -1. Bulk editing only changes eligible editable strings; selecting a
read-only string does not make it editable.

#### Flags and labels

Flag settings are strings containing flags to add or remove. Label settings are
lists of label names. Flag defaults are empty strings and label defaults are
empty lists. Source flags and labels affect all languages, just as with the
bulk-edit add-on; translation flags affect the matching translations, excluding
source strings. Removing a translation flag removes its local setting; inherited
flags remain in effect.

Use comma-separated flags, with colon-separated parameters, for example
`add_translation_flags: "max-length:100, check-glossary"`. To remove a
parameterized flag, specify its name, for example
`remove_translation_flags: "max-length"`. See [Personalizarea comportamentului cu ajutorul stegulețelor](https://docs.weblate.org/ro/latest/admin/checks.md#custom-checks) for quoting
rules and [Controale de calitate](https://docs.weblate.org/ro/latest/user/checks.md#checks) for available checks. Labels use YAML/JSON lists of
existing project label names, for example `add_labels: [needs-attention]`;
this does not create a label.

#### Example

Mark currently translated German strings as needing editing, leaving other
languages and approved strings outside the query unchanged:

```yaml
- action: weblate.bulk_edit
  id: marked_for_edit
  settings:
    q: "language:de AND state:translated"
    state: 10
```

See [Run an action only when a translation pass updates strings](#automation-conditional-actions) for a conditional bulk-edit example.

#### Outputs

`component` (integer)
: ID of the component processed.

`updated` (integer)
: Count reported by the bulk-edit operation. State changes, changes to source
  flags or labels, and changes to translation flags contribute separately.
  When an action combines these operations, the same string can contribute
  more than once; this is not a count of distinct affected strings. Source
  flag and label changes are counted per source string, rather than once per
  language. Zero means the operation made no changes.

For example, an action that only changes the states of three strings returns:

```json
{"component": 42, "updated": 3}
```

A later condition can test `results.marked_for_edit.updated > 0`. This output
does not contain unit IDs or a list of the changed strings. A later action must
select its strings with its own query.

<!-- AUTOGENERATED START: action-sequence -->
<!-- This section is automatically generated by `./manage.py list_automation`. Do not edit manually. -->

<a id="automation-action-sequence"></a>

### Sequence

#### Versionadded
Added in version 2026.10.

#### Parametrii

| Nume       | Required   | Type or allowed values              |
|------------|------------|-------------------------------------|
| `sequence` | Yes        | List of (action); maximum items 100 |
<!-- AUTOGENERATED END: action-sequence -->

Groups an ordered list of actions. A sequence finishes before the next sibling
action starts. It can contain operations, further sequences, and
[Choose](#automation-action-choose) blocks. It does not introduce parallel execution.

#### Example

Group two translation passes: reuse other components first, then apply local
translation memory to strings still needing translation.

```yaml
- sequence:
    - action: weblate.automatic_translation
      id: reused
      settings:
        auto_source: others
        mode: translate
        q: "state:<translated"
    - action: weblate.automatic_translation
      id: memory
      settings:
        auto_source: mt
        engines: [weblate-translation-memory]
        threshold: 95
        mode: translate
        q: "state:<translated"
```

#### Outputs

A sequence has no output object and does not accept an `id`. Its successful
child actions expose their individual outputs in the shared `results` object,
including to subsequent children and actions outside the sequence. In this
example, those entries are `results.reused` and `results.memory`; there is
no combined update count. A failing child stops the remaining actions.

<!-- AUTOGENERATED START: action-choose -->
<!-- This section is automatically generated by `./manage.py list_automation`. Do not edit manually. -->

<a id="automation-action-choose"></a>

### Choose

#### Versionadded
Added in version 2026.10.

#### Parametrii

| Nume                  | Required   | Type or allowed values                 |
|-----------------------|------------|----------------------------------------|
| `choose`              | Yes        | List of (object); maximum items 100    |
| `choose[].conditions` | Yes        | List of (condition); maximum items 100 |
| `choose[].sequence`   | Yes        | List of (action); maximum items 100    |
| `default`             | No         | List of (action); maximum items 100    |
<!-- AUTOGENERATED END: action-choose -->

Evaluates branches in order and executes the first branch whose `conditions`
all pass. Each branch requires both `conditions` and `sequence`. Later branches
are skipped after a match, even if the matching sequence is empty.

If no branch matches, `default` runs. Omitting `default` is equivalent to an
empty action list.

#### Example

For components in the `frontend` category, mark translated German strings as
needing editing. Other components take the empty default branch.

```yaml
- choose:
    - conditions:
        - condition: component_category
          value: frontend
      sequence:
        - action: weblate.bulk_edit
          id: frontend_edit
          settings:
            q: "language:de AND state:translated"
            state: 10
  default: []
```

See [Run an action only when a translation pass updates strings](#automation-conditional-actions) for a branch that uses an earlier
action’s output instead of the component category.

#### Outputs

A choose block has no output object and does not accept an `id`. Only successful
operations in the selected branch or default branch create result entries.
Branch conditions and skipped actions are recorded in the activity trace.
In this example, `results.frontend_edit` exists only if the category matches
and the bulk edit succeeds. A later condition can safely check
`has(results.frontend_edit) && results.frontend_edit.updated > 0`.
Preview records planned or conditional actions, without creating their outputs.

<!-- AUTOGENERATED START: cookbook -->
<!-- This section is automatically generated by `./manage.py list_automation`. Do not edit manually. -->

<a id="automation-cookbook"></a>

## Cookbook

<!-- AUTOGENERATED END: cookbook -->

<a id="automation-translation-ordering"></a>

### Apply translation memory before machine translation

Use separate automatic translation actions to give one source priority over
another. This example first applies local translation memory matches scoring at
least 95, then asks DeepL to translate only strings still needing translation.

Enable [Memorie de traducere Weblate](https://docs.weblate.org/ro/latest/admin/machine.md#mt-weblate-translation-memory) and configure [DeepL](https://docs.weblate.org/ro/latest/admin/machine.md#mt-deepl) in the
target project’s [Sugestii automate](https://docs.weblate.org/ro/latest/admin/machine.md#machine-translation-setup). Install the Automation add-on
and enter this workflow:

```yaml
version: 1
triggers:
  - trigger: component_update
  - trigger: daily
actions:
  - action: weblate.automatic_translation
    id: memory
    settings:
      auto_source: mt
      engines: [weblate-translation-memory]
      threshold: 95
      mode: translate
      q: "state:<translated"
  - action: weblate.automatic_translation
    id: machine
    settings:
      auto_source: mt
      engines: [deepl]
      threshold: 80
      mode: translate
      q: "state:<translated"
```

The first action finishes before the second action selects its strings. Both use
`mode: translate`, so a successful first-pass translation no longer matches
`state:<translated` and is not sent to DeepL by the second action. Existing
translated or approved strings are excluded from both passes. Untranslated
strings and strings needing editing are eligible; use `state:empty` in both
actions if only untranslated strings should be processed.

Each threshold applies only to its action. Set the memory threshold to 100 to
accept only exact matches, or lower it to accept less similar matches before
trying the remote service. Machine translation scores are service-specific:
choose a threshold no higher than the service’s documented maximum score.
Replace `deepl` with another configured service ID to use a different provider,
including an AI service.

Keep one engine per action when the order matters. Putting both IDs in one
`engines` list uses the existing [Priority of machine translation and translation memory services](https://docs.weblate.org/ro/latest/admin/machine.md#mt-translation-services-priority), not
the list order. To try additional providers, append another action with its own
engine, threshold, and the same query. To reuse translations from other Weblate
components first, prepend an action using `auto_source: others` instead of
`auto_source: mt` and omit `engines`.

Changing a pass to `mode: suggest` leaves the string state unchanged;
`mode: fuzzy` leaves it needing editing. Neither excludes its results from a
later `state:<translated` pass. Keep `mode: translate` when the intention is
to retain each successful pass’s translations.

Use Preview without changes to validate the workflow before using
Run now. Preview does not call translation services or predict their
results. After a real run, inspect the activity log for each action’s `updated`
count and warnings. A service failure that stops the workflow is recorded as an
error; later actions do not run.

Remove or disable overlapping Automatic translation add-ons when replacing them
with this workflow. Ordering applies within a single automation run; separate
add-ons and concurrent runs can still overlap. The `daily` trigger respects
[`BACKGROUND_TASKS`](https://docs.weblate.org/ro/latest/admin/config.md#std-setting-BACKGROUND_TASKS). Use `triggers: []` for manual execution only.

<a id="automation-ai-quality-gateway"></a>

### Evaluate AI translations before approval

This workflow runs after repository component updates or source edits in Weblate.
It applies translation memory first, translates remaining strings with OpenAI,
and evaluates only strings changed by the OpenAI action. Clean
strings are approved; strings with AI quality findings are marked as needing
checking. Configure the translation memory and OpenAI services in the target
project. Install the [AI quality evaluation](https://docs.weblate.org/ro/latest/admin/addons.md#addon-weblate-ai-quality) add-on with OpenAI as its
evaluation service and its query including translated strings. Its service must
match `settings.service` below.

```yaml
version: 1
triggers:
  - trigger: component_update
  - trigger: change
    events: [source_change]
actions:
  - action: weblate.automatic_translation
    id: memory
    settings:
      auto_source: mt
      engines: [weblate-translation-memory]
      threshold: 95
      mode: translate
      q: "state:<translated"
  - action: weblate.automatic_translation
    id: machine
    settings:
      auto_source: mt
      engines: [openai]
      mode: translate
      q: "state:<translated"
  - action: weblate.ai_quality
    id: quality
    scope: result:machine
    settings:
      service: openai
  - action: weblate.bulk_edit
    scope: result:quality
    settings:
      q: "NOT (check:ai_accuracy OR check:ai_fluency OR check:ai_terminology OR check:ai_style OR check:ai_formatting)"
      state: 30
  - action: weblate.bulk_edit
    scope: result:quality
    settings:
      q: "check:ai_accuracy OR check:ai_fluency OR check:ai_terminology OR check:ai_style OR check:ai_formatting"
      state: 12
```

The quality action uses the intersection of its scope, the add-on query, and
its optional `settings.q`. It stops the workflow if evaluation fails or skips
any batch, so incomplete results never reach the approval action. Its result
scope contains only units successfully evaluated in this run. State `12` is
Needs editing (Needs checking); reviewers can inspect the findings
and revise those translations. The five `check:ai_*` filters select
non-dismissed findings. Disable the add-on’s evaluation frequency and its
change and update triggers if only this workflow should initiate evaluation.

<a id="automation-conditional-actions"></a>

### Run an action only when a translation pass updates strings

Action IDs make outputs available to later conditions. For example, append the
following item to the previous workflow’s `actions` list to mark translations
from the component as needing editing when the machine translation pass updated
at least one string:

```yaml
- choose:
    - conditions:
        - condition: expression
          value: results.machine.updated > 0
      sequence:
        - action: weblate.bulk_edit
          settings:
            q: "state:translated"
            state: 10
  default: []
```

The bulk-edit query selects all currently translated strings in the component,
including translations that existed before the run and memory matches. It does
not select only the strings updated by `machine`. Narrow the query to the
intended strings before using this example. String state `10` means needing
editing; it does not approve or request review of translations.

`choose` executes only the first branch whose conditions pass. Here, the empty
`default` performs no action when the translation pass updated no strings.
During preview, the condition is unknown because `machine` has not executed.

<a id="automation-event-example"></a>

### Translate after source changes

This complete workflow listens for source edits in Weblate and new source strings
from the repository. It runs only for categorized components matching either
`frontend` or `backend`, and only when the change includes a nonempty unit.
The action reuses other components» translations for German strings needing
translation.

```yaml
version: 1
triggers:
  - trigger: change
    events: [source_change, new_source_repo]
conditions:
  - condition: and
    conditions:
      - condition: or
        conditions:
          - condition: component_category
            value: frontend
          - condition: component_category
            value: backend
      - condition: expression
        value: unit != null && unit.source != ""
actions:
  - action: weblate.automatic_translation
    id: reused
    settings:
      auto_source: others
      mode: translate
      q: "language:de AND state:<translated"
```

The null guard makes changes without a unit safely skip the workflow. It also
means Run now skips this workflow, because real manual execution has
no unit context. To inspect the event-driven path without changing strings, use
Preview without changes with a change ID belonging to the target
component.

The action’s query targets all matching German strings in the component, not
only the unit from the triggering change. `trigger.unit_ids` provides context
for conditions; it is not automatically applied to operations and cannot be
interpolated into `q`. The listed events do not cover every kind of source
update; select additional [Selected change events](https://docs.weblate.org/ro/latest/admin/addons.md#change-actions) if the workflow should also
respond to uploads or other changes.
