Translation Coverage

Per-language coverage rings and a focused tree of pages still missing translations.

The coverage dashboard sits below the list of languages in Kirby's Languages view (Languages in the Panel menu, or /panel/languages). It shows a coverage ring for each secondary language and one tree of the pages still missing a translation – click a page to open it, or one of its language tags to open it in the language that's missing content.

Kirby PanelLanguages
Deutsch
100%
All pages translated
Español
21%
15 incomplete pages
Français
64%
5 incomplete pages

What You See

Translation Coverage: one ring per secondary language, showing the percentage of eligible fields that have content. The label below each ring reports how many pages are still incomplete (e.g. 4 incomplete pages), or All pages translated once a language is complete. A language at 100% is highlighted as positive.

Pages to Translate: a tree of pages that have at least one missing language. Branches collapse to keep the list compact: only incomplete pages and their ancestors are shown. Each entry links to its Panel view, and each language tag to the view in the language still missing. The tree leaves out pages you may not list, and the pages below them, while the rings and their page count cover every page.

If everything is translated, the section is hidden entirely – the rings (all at 100%, themed positive) are the only signal you need.

How Coverage Is Calculated

A field counts toward the totals when two conditions are met: your blueprint marks it translatable (or it's translatable by default for its field type), and the default language has content for that field. It counts as translated if its value in the secondary language is not empty. Only top-level fields are counted – a block or structure counts once, as a whole. Language variables don't count toward the rings – translate them from Kirby's language view.

The dashboard spans the whole site, so it reads fieldTypes, includeFields, and excludeFields from config.php alone. Narrowing those per blueprint changes what a view button translates, but not what the rings report.

A language without its own content file counts as zero translated fields, not as a copy of the default language.
A page where every eligible field is empty in the default language is omitted from the dashboard – there's nothing to translate against.

The default language itself is excluded from the rings – it's the source, not a target.

Configuration

The dashboard audits site()->index() by default, which walks published pages only – scope the audit to site()->index(true) to count drafts too. Both the scope and the dashboard itself are controlled by the coverage option.

Scoping the Audit

Pass a pages closure returning any Pages collection. Use it when parts of the site aren't editorial content – a large archive, generated pages, or a section no one translates:

site/config/config.php
return [
    'johannschopplich.content-translator' => [
        'coverage' => [
            'pages' => fn () => page('blog')->children()->listed()
        ]
    ]
];
Scoping changes what the rings measure, not just what the tree lists. A ring reports coverage across the pages you selected, so narrowing the scope raises the percentage.

Disabling the Dashboard

Set the option to false to remove the dashboard from the Languages view entirely:

site/config/config.php
return [
    'johannschopplich.content-translator' => [
        'coverage' => false
    ]
];
Coverage results are cached and invalidated automatically when pages, the site, or languages change. Disabling is about the dashboard, not about performance.

Caching

The plugin registers its own cache, active by default and shared by the coverage rings and the page tree. Point it at another driver, or turn it off entirely, through Kirby's cache options:

site/config/config.php
return [
    'johannschopplich.content-translator' => [
        'cache' => [
            'type' => 'apcu'
        ]
    ]
];
With 'cache' => false every coverage ring is recomputed per request, which walks the whole page index. Prefer coverage: false when the goal is to remove the dashboard.