Translation Coverage

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

Open /panel/languages (or the Languages icon in the Panel topbar) to see the coverage dashboard. Each language shows a coverage ring and a list of incomplete pages – 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
Français
64%
5 incomplete pages
Español
21%
15 incomplete pages

What You See

Translation Coverage: one ring per non-default 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.

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.

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.

Default-language content is read without fallback when calculating coverage. A secondary-language content file that doesn't exist 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. 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 coverage view from /panel/languages 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 view, 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 view.