---
title: "Translate Related Pages and Files"
description: "Translate the pages and files that belong to a view along with it – Kirby Modules, a page's files, or any model a Kirby query reaches."
canonical_url: "https://kirby.tools/docs/content-translator/advanced/cascade"
---

# Translate Related Pages and Files

> Translate the pages and files that belong to a view along with it – Kirby Modules, a page's files, or any model a Kirby query reaches.

Some content lives outside the page an editor has open: the module pages of a page builder, the metadata of a page's files, the children of an overview page. The `cascade` option names these models with a Kirby query, and every translation started from the view translates them too.

The model whose view starts the translation is the **host**. The models its `cascade` option names are its **cascade**.

## Name the Cascade

Set `cascade` on the [view button or the section](/docs/content-translator/configuration/local) of the host's blueprint. It takes one [Kirby query](https://getkirby.com/docs/guide/blueprints/query-language) or a list of them:

<code-group>

```yaml [View Button]
buttons:
  open: true
  preview: true
  settings: true
  content-translator:
    cascade: page.files
  languages: true
  status: true
```

```yaml [Section]
sections:
  contentTranslator:
    type: content-translator
    cascade:
      - page.files
      - page.children.listed
```

</code-group>

On the view button, `cascade` needs the [map form](/docs/content-translator/configuration/local#advanced-configuration) shown above. A map replaces Kirby's default buttons, so keep naming every button you want.

A translation cascades only when the view button or section it starts from sets `cascade`. With both in one blueprint, give them the same queries.

A query can use `kirby`, `site`, and `model` – the host itself – plus the alias of the host's own type: `page`, `file`, or `site`. The null-safe operator keeps a query valid while the model it starts from does not exist yet:

```yaml
cascade: page.find("modules")?.children
```

Only pages and files take part, drafts included when a query such as `page.drafts` reaches them. The host itself and the models the current user may not open or edit are left out. A query that fails or finds nothing adds nothing and shows no error, so a typo shows up only as a missing or too-low count in the dialog before a translation.

<warning>

Every model of the cascade costs a translation per language. A query like `site.index` translates the whole site from one button.

</warning>

## The Cascade Is Saved Directly

The cascade is always translated from the **saved content of the default language** and **saved directly** in the target language, so **Discard** on the host does not revert it. The dialog before a translation states how many pages and files come along.

- **Batch translation** translates the host and its cascade into every selected language.
- **Single-language translation** saves the cascade in the current language, while the host's fields stay in the form for review. Nothing is cascaded while the default language is open, while another user edits the host, or without the permission to update the host.
- **Import** does not cascade.

A model of the cascade is translated by the host's options:

- The host's `fieldTypes`, `kirbyTags`, and `systemPrompt` apply. A `content-translator` section or view button on the model's own blueprint is not read, but `translate: false` on its fields holds.
- `includeFields` and `excludeFields` from the host's blueprint do not apply, since they name the host's fields. Those set in the [global configuration](/docs/content-translator/configuration/global) do.
- A page gets a translated title when the host's `title` option is on and the current user may change that page's title.
- The slug is never translated.

Three things hold a model of the cascade back, and the [translation results](/docs/content-translator/panel/translation-results) say which:

- **Another user edits it.** The remaining models are still translated.
- **Its default language has unsaved changes.** The translation would miss them, so save or discard them first.
- **A target language has unsaved changes.** Only that language of the model is held back, as for the host.

## Kirby Modules

[Kirby Modules](https://github.com/medienbaecker/kirby-modules) stores the modules of a section as child pages of a container page named after the section. For a section named `modules`, one line in the host's blueprint translates them along with the page:

```yaml [site/blueprints/pages/default.yml]
buttons:
  open: true
  preview: true
  settings: true
  content-translator:
    cascade: page.find("modules")?.children
  languages: true
  status: true

sections:
  modules:
    type: modules
```

For more than one modules section, list one query per section. A section named `sidebar` keeps its modules in `page.find("sidebar")`.

The query reads the container's children rather than Kirby Modules' `page.modules` method, because that method leaves out hidden modules, and new modules start hidden.

For modules that contain modules, collect the whole tree and keep only the module pages:

```yaml
cascade: page.find("modules")?.index.filterBy("isModule", true)
```

Module blueprints set `changeTitle: false` by default, so module titles stay as they are.

## From PHP

The [PHP API](/docs/content-translator/php-classes/translator) has no cascade. Loop over the same models instead:

```php
$targetLanguage = 'de';
$defaultLanguage = kirby()->defaultLanguage()->code();
$page = page('about');

$models = [$page, ...$page->files(), ...($page->find('modules')?->children() ?? [])];

foreach ($models as $model) {
    $translator = $model->translator();
    $translator->copyContent($targetLanguage, $defaultLanguage);
    $translator->translateContent($targetLanguage, $targetLanguage, $defaultLanguage);
}
```

---

Every page of this site as Markdown: <https://kirby.tools/sitemap.md>
