Skip to content

Commit

Permalink
New translations root
Browse files Browse the repository at this point in the history
  • Loading branch information
afbora committed Feb 3, 2024
1 parent 69810e2 commit ec21d27
Show file tree
Hide file tree
Showing 3 changed files with 209 additions and 27 deletions.
53 changes: 27 additions & 26 deletions src/Cms/Core.php
Original file line number Diff line number Diff line change
Expand Up @@ -316,33 +316,34 @@ public function load(): Loader
public function roots(): array
{
return $this->cache['roots'] ??= [
'kirby' => fn (array $roots) => dirname(__DIR__, 2),
'i18n' => fn (array $roots) => $roots['kirby'] . '/i18n',
'kirby' => fn (array $roots) => dirname(__DIR__, 2),
'i18n' => fn (array $roots) => $roots['kirby'] . '/i18n',
'i18n:translations' => fn (array $roots) => $roots['i18n'] . '/translations',
'i18n:rules' => fn (array $roots) => $roots['i18n'] . '/rules',

'index' => fn (array $roots) => static::$indexRoot ?? dirname(__DIR__, 3),
'assets' => fn (array $roots) => $roots['index'] . '/assets',
'content' => fn (array $roots) => $roots['index'] . '/content',
'media' => fn (array $roots) => $roots['index'] . '/media',
'panel' => fn (array $roots) => $roots['kirby'] . '/panel',
'site' => fn (array $roots) => $roots['index'] . '/site',
'accounts' => fn (array $roots) => $roots['site'] . '/accounts',
'blueprints' => fn (array $roots) => $roots['site'] . '/blueprints',
'cache' => fn (array $roots) => $roots['site'] . '/cache',
'collections' => fn (array $roots) => $roots['site'] . '/collections',
'commands' => fn (array $roots) => $roots['site'] . '/commands',
'config' => fn (array $roots) => $roots['site'] . '/config',
'controllers' => fn (array $roots) => $roots['site'] . '/controllers',
'languages' => fn (array $roots) => $roots['site'] . '/languages',
'license' => fn (array $roots) => $roots['config'] . '/.license',
'logs' => fn (array $roots) => $roots['site'] . '/logs',
'models' => fn (array $roots) => $roots['site'] . '/models',
'plugins' => fn (array $roots) => $roots['site'] . '/plugins',
'sessions' => fn (array $roots) => $roots['site'] . '/sessions',
'snippets' => fn (array $roots) => $roots['site'] . '/snippets',
'templates' => fn (array $roots) => $roots['site'] . '/templates',
'roles' => fn (array $roots) => $roots['blueprints'] . '/users',
'i18n:rules' => fn (array $roots) => $roots['i18n'] . '/rules',

'index' => fn (array $roots) => static::$indexRoot ?? dirname(__DIR__, 3),
'assets' => fn (array $roots) => $roots['index'] . '/assets',
'content' => fn (array $roots) => $roots['index'] . '/content',
'media' => fn (array $roots) => $roots['index'] . '/media',
'panel' => fn (array $roots) => $roots['kirby'] . '/panel',
'site' => fn (array $roots) => $roots['index'] . '/site',
'accounts' => fn (array $roots) => $roots['site'] . '/accounts',
'blueprints' => fn (array $roots) => $roots['site'] . '/blueprints',
'cache' => fn (array $roots) => $roots['site'] . '/cache',
'collections' => fn (array $roots) => $roots['site'] . '/collections',
'commands' => fn (array $roots) => $roots['site'] . '/commands',
'config' => fn (array $roots) => $roots['site'] . '/config',
'controllers' => fn (array $roots) => $roots['site'] . '/controllers',
'languages' => fn (array $roots) => $roots['site'] . '/languages',
'license' => fn (array $roots) => $roots['config'] . '/.license',
'logs' => fn (array $roots) => $roots['site'] . '/logs',
'models' => fn (array $roots) => $roots['site'] . '/models',
'plugins' => fn (array $roots) => $roots['site'] . '/plugins',
'roles' => fn (array $roots) => $roots['blueprints'] . '/users',
'sessions' => fn (array $roots) => $roots['site'] . '/sessions',
'snippets' => fn (array $roots) => $roots['site'] . '/snippets',
'templates' => fn (array $roots) => $roots['site'] . '/templates',
'translations' => null,
];
}

Expand Down
43 changes: 42 additions & 1 deletion src/Cms/Language.php
Original file line number Diff line number Diff line change
Expand Up @@ -62,14 +62,15 @@ public function __construct(array $props)
$this->name = trim($props['name'] ?? $this->code);
$this->slugs = $props['slugs'] ?? [];
$this->smartypants = $props['smartypants'] ?? [];
$this->translations = $props['translations'] ?? [];
$this->url = $props['url'] ?? null;

if ($locale = $props['locale'] ?? null) {
$this->locale = Locale::normalize($locale);
} else {
$this->locale = [LC_ALL => $this->code];
}

$this->setTranslations($props['translations'] ?? []);
}

/**
Expand Down Expand Up @@ -409,6 +410,13 @@ public function save(): static
{
try {
$existingData = Data::read($this->root());

// inject translations from custom root
// returns existing translations
// if custom root is not defined as fallback
$data['translations'] = $this
->translationsObject()
->load($existingData['translations'] ?? []);
} catch (Throwable) {
$existingData = [];
}
Expand All @@ -427,11 +435,31 @@ public function save(): static

ksort($data);

// save translations to the custom root and remove translations
// to prevent duplication write into the language file
if ($this->translationsObject()->root() !== null) {
$this->translationsObject()
->save($data['translations'] ?? []);
$data['translations'] = [];
}

Data::write($this->root(), $data);

return $this;
}

/**
* Sets the translations data
*
* @return $this
*/
protected function setTranslations(array $translations = []): static
{
$this->translations = (new LanguageTranslations($this))->load($translations);

return $this;
}

/**
* Private siblings collector
*/
Expand Down Expand Up @@ -475,12 +503,25 @@ public function toArray(): array

/**
* Returns the translation strings for this language
* @todo In v5, remove this method and
* rename `->translationsObject()` method with the `translations`.
* This will be a breaking change.
*/
public function translations(): array
{
return $this->translations;
}

/**
* Returns the language translations object for this language
* @todo In v5, rename this method name as `translations`
* @internal
*/
public function translationsObject(): LanguageTranslations
{
return new LanguageTranslations($this, $this->translations);
}

/**
* Returns the absolute Url for the language
*/
Expand Down
140 changes: 140 additions & 0 deletions src/Cms/LanguageTranslations.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
<?php

namespace Kirby\Cms;

use Exception;
use Kirby\Data\Data;
use Kirby\Filesystem\F;

/**
* With helper methods provides get language translations or
* loads from custom `translations` root
* @since 4.2.0
*
* @package Kirby Cms
* @author Ahmet Bora <ahmet@getkirby.com>
* @link https://getkirby.com
* @copyright Bastian Allgeier
* @license https://getkirby.com/license
*/
class LanguageTranslations
{
protected array $data;

public function __construct(
protected Language $language,
self|array $translations = []
) {
$this->setTranslations($translations);
}

/**
* Returns a single translation string by key
*/
public function get(string $key, string $default = null): string|null
{
return $this->data[$key] ?? $default;
}

/**
* Loads the language translations based on custom roots for provided language code
*/
public function load(array $default = []): array
{
if ($file = static::root()) {
try {
return Data::read($file);
} catch (Exception) {
return $default;
}
}

return $default;
}

/**
* Saves the language translations in the custom root
* @internal
*
* @return $this
*/
public function save(array $translations = []): static
{
$this->setTranslations($translations);

if ($root = $this->root()) {
Data::write($root, $translations);
}

return $this;
}

/**
* Returns custom translations root path if defined
*/
public function root(): string|null
{
$kirby = App::instance();
$root = $kirby->root('translations');
$file = ($root ?? '') . '/' . $this->language->code() . '.php';

if (
$root !== null &&
F::exists($file) === true
) {
return $file;
}

return null;
}

/**
* Removes a translation key
*
* @return $this
*/
public function remove(string $key): static
{
unset($this->data[$key]);
return $this;
}

/**
* Sets the translation key
*
* @return $this
*/
public function set(string $key, string|null $value = null): static
{
$this->data[$key] = $value;
return $this;
}

/**
* Set translations
*
* @return $this
*/
public function setTranslations(self|array $translations = []): static
{
if (empty($translations) === false) {
if ($translations instanceof self) {
$this->data = $translations->toArray();
} else {
$this->data = $translations;
}
} else {
$this->data = static::load();
}

return $this;
}

/**
* Returns translations
*/
public function toArray(): array
{
return $this->data;
}
}

0 comments on commit ec21d27

Please sign in to comment.