Write translations to .yml file (or an external php file)

Hi, I saw here: https://getkirby.com/docs/quicktips/language-variables, that you can read translations from external files. I was wondering if it’s also possible to write to external files? Currently, if you read from an external file and change a translation in the panel, the entire translation array gets replaced.

The reason we prefer translations to be separate is that we want them to be ignored by git.

No, that’s currently not possible, I think there is a feature request already somewhere.

Ok thanks!

For reference: Found it, not a feature request, but reported as issue here: External language variables setup no longer works since K4's language views · Issue #6176 · getkirby/kirby · GitHub

Okay and I see that it’s on the roadmap for kirby 5!

Not officially.
Unofficially, in a plugin, you could override the dialogs that store the data.

Here’s an example implementation that stores the data in a yaml file in a “vars” directory (like the quick tip). You could adjust it so that it does the right thing for you.

<?php

use Kirby\Cms\App;
use Kirby\Data\Data;
use Kirby\Filesystem\F;

class TranslationsStore {
    protected $cache;

    public function __construct(protected readonly string $language) {
        $this->cache = null;
    }

    public function root() {
        return kirby()->root('languages') . "/vars/{$this->language}.yml";
    }

    public function fetch(): array {
        if($this->cache !== null) {
            return $this->cache;
        }

        $root = $this->root();
        if(file_exists($root)) {
            $this->cache = Data::decode(F::read($root), 'yaml');
        } else {
            $this->cache = [];
        }
        
        return $this->cache;
    }

    protected function store(array $arr) {
        $filename = $this->root();
        $this->cache = $arr;
        F::write($filename, Data::encode($arr, 'yaml'));
    }

    public function create(string $key, string $value):void {
        $arr = $this->fetch();
        $arr[$key] = $value;
        $this->store($arr);
    }

    public function delete(string $key):void {
        $arr = $this->fetch();
        unset($arr[$key]);
        $this->store($arr);
    }

    public function update(string $key, string $value):void {
        $arr = $this->fetch();
        $arr[$key] = $value;
        $this->store($arr);
    }    
}

App::plugin('lol/lol', [
    'areas' => [
        'languages' => fn(App $kirby) => [
            'dialogs' => [
                'language.translation.create' => [
                    'submit' => function(string $code) use ($kirby) {
                        $request = $kirby->request();

                        $store = new TranslationsStore($code);
                        $store->create($request->get('key'), $request->get('value', ''));

                        return true;
                    }
                ],
                'language.translation.delete' => [
                    'submit' => function(string $code, string $translationKey) {
                        $store = new TranslationsStore($code);
                        $key = rawurldecode(base64_decode($translationKey));
                        $store->delete($key);

                        return true;
                    }
                ],
                'language.translation.update' => [
                    'submit' => function(string $code, string $translationKey) use ($kirby) {
                        $request = $kirby->request();

                        $store = new TranslationsStore($code);
                        $key = rawurldecode(base64_decode($translationKey));
                        $store->update($key, $request->get('value', ''));

                        return true;
                    }
                ]
            ]
        ],
    ]
]);

Thanks, will look try :slight_smile: