Translating Panel field options of plugins & plugin strings in general

Hello Kirby community,

I’m back into the Kirby universe for a month now and really like how Kirby has grown over the last two years. Right now I’m adding some finishing touches on a multilingual Kirby powered site.

Today I added the Kirby Status plugin and wanted to translate the select element options for “published”, “unpublished” and “private”. As the options are “hard-coded” into the plugin I wonder how I can override them for my German translation?

I tried to add an l::get() function instead of a hard-coded string, but then it looks like fields don’t read the language files from sites/languages/?

In other plugins I saw this l::get('', 'Default value'). When I set that key in my language file I wasn’t able to change the string either.

Can someone of you give me a hint of how to accomplish that (simple) task? Thank you very much.


Link to plugin:

If a plugin doesn’t offer an option to localize the options, you have to modify the plugin itself or extend the field.

Edit: if you want to modify the plugin, do this:

  1. Add the following function to the StatusField class in kirby-status/field/status.php

    public function translate($string) {
     $translation = c::get('selectplus.translation', false);
     $language = site()->user()->data()['language'];
     if(!$translation) {
    	 $translations = require __DIR__ . DS . 'translations.php';
    	 if (! array_key_exists($language, $translations)) {
    		 $language = 'en';
    	 $translation = $translations[$language];
     if(array_key_exists($string, $translation)) {
    	 $string = $translation[$string];
     return $string;


  1. Create a new file translations.php in /kirby-status/field with the following content and modify as required, i.e. add the languages you need and their key-value pairs.

    return [
        'en' => [
            'published'  => 'Published',
            'private'  => 'Private',
            'unpublished' => 'Unpublished',
        'de' => [
          'published'  => 'Publiziert',
          'private'  => 'Privat',
          'unpublished' => 'Nicht publiziert',
  2. Modify line #10 of /kirby-status/field/template.php like this:

    <option value="<?php echo $key; ?>"<?php echo $selected; ?>><?php echo $field->translate($key); ?></option>

That’s it.

Wow! That’s a perfect detailed answer for creating a bunch of PRs over on GitHub. :smiley:

Thank you very much.

I was going to create one …

1 Like

Awesome, thank you. Once it’s in I’ll test it. :+1:

I will implement it into the Translations plugin I think. :thinking:

@mikewink, @jenstornell merged the PR, so please feel free to test it.

1 Like

I have tested your code and it works great. Thank you very much for the super quick reply and blueprint for other plugins. :slight_smile:

Hello @texnixe,

I have two follow up questions regarding your code.

What about when I want to set new translations for different languages in the config? Your current code does not support this right? What about this instead? It also allows selective overrides of strings.

public function translate($string)
    $default_translations = require __DIR__ . DS . 'translations.php';
    $custom_translations = c::get('status.translation', false);
    $language = site()->user()->data()['language'];

    $translations = (!$custom_translations)
      ? $default_translations
      : $custom_translations;

    $language = (array_key_exists($language, $translations))
      ? $language
      : 'en';

    return (array_key_exists($string, $translations[$language]))
      ? $translations[$language][$string]
      : $default_translations[$language][$string];

Question two is about language files. Could we use language files for the strings instead of putting it into config? Or are those files not available to plugins?

$translation = l::get('status.translation', false);

No, not in the Panel context. The Panel has its own language files and there is no way to merge them that I’m aware of. Which is why we use a translation method in our plugins.

The config setting is for defining translations in languages that do not exist in the default translation file. But thinking about this, it would actually make sense to merge the default translations. with the custom. translations, so that you can add to the set rather than replacing the set.

Hello @texnixe,

You are absolutely right about the merge. So here is the revised code with a single source of truth.

public function translate($string)
    $translations = require __DIR__ . DS . 'languages.php';
    $custom_translations = c::get('status.translation', []);
    $language = site()->user()->data()['language'];

    array_walk($translations, function (&$default, $lang, $custom) {
        if (!empty($custom) && array_key_exists($lang, $custom)) {
            $default = array_merge($default, $custom[$lang]);
    }, $custom_translations);

    $language = (array_key_exists($language, $translations))
      ? $language
      : 'en';

    if (array_key_exists($string, $translations[$language])) {
        $string = $translations[$language][$string];

    return $string;
1 Like