mirror of
https://github.com/getgrav/grav.git
synced 2026-07-06 05:28:35 +02:00
Merge branch 'feature/better_language_yaml_support' into develop
This commit is contained in:
@@ -60,6 +60,12 @@ class Config extends Data
|
||||
'' => ['user://themes'],
|
||||
]
|
||||
],
|
||||
'languages' => [
|
||||
'type' => 'ReadOnlyStream',
|
||||
'prefixes' => [
|
||||
'' => ['user://languages', 'system/languages'],
|
||||
]
|
||||
],
|
||||
'cache' => [
|
||||
'type' => 'Stream',
|
||||
'prefixes' => [
|
||||
@@ -85,17 +91,21 @@ class Config extends Data
|
||||
|
||||
protected $blueprintFiles = [];
|
||||
protected $configFiles = [];
|
||||
protected $languageFiles = [];
|
||||
protected $checksum;
|
||||
protected $timestamp;
|
||||
|
||||
protected $configLookup;
|
||||
protected $blueprintLookup;
|
||||
protected $pluginLookup;
|
||||
protected $languagesLookup;
|
||||
|
||||
protected $finder;
|
||||
protected $environment;
|
||||
protected $messages = [];
|
||||
|
||||
protected $languages;
|
||||
|
||||
public function __construct(array $setup = array(), Grav $grav = null, $environment = null)
|
||||
{
|
||||
$this->grav = $grav ?: Grav::instance();
|
||||
@@ -164,42 +174,61 @@ class Config extends Data
|
||||
$this->blueprintLookup = $locator->findResources('blueprints://config');
|
||||
$this->pluginLookup = $locator->findResources('plugins://');
|
||||
|
||||
|
||||
$this->loadCompiledBlueprints($this->blueprintLookup, $this->pluginLookup, 'master');
|
||||
$this->loadCompiledConfig($this->configLookup, $this->pluginLookup, 'master');
|
||||
|
||||
// process languages if supported
|
||||
if ($this->get('languages', false)) {
|
||||
$this->languagesLookup = $locator->findResources('languages://');
|
||||
$this->loadCompiledLanguages($this->languagesLookup, $this->pluginLookup, 'master');
|
||||
}
|
||||
|
||||
$this->initializeLocator($locator);
|
||||
}
|
||||
|
||||
public function checksum()
|
||||
{
|
||||
$checkBlueprints = $this->get('system.cache.check.blueprints', false);
|
||||
$checkConfig = $this->get('system.cache.check.config', true);
|
||||
$checkSystem = $this->get('system.cache.check.system', true);
|
||||
if (empty($this->checksum)) {
|
||||
$checkBlueprints = $this->get('system.cache.check.blueprints', false);
|
||||
$checkLanguages = $this->get('system.cache.check.languages', false);
|
||||
$checkConfig = $this->get('system.cache.check.config', true);
|
||||
$checkSystem = $this->get('system.cache.check.system', true);
|
||||
|
||||
if (!$checkBlueprints && !$checkConfig && !$checkSystem) {
|
||||
$this->messages[] = 'Skip configuration timestamp check.';
|
||||
return false;
|
||||
if (!$checkBlueprints && !!$checkLanguages && $checkConfig && !$checkSystem) {
|
||||
$this->messages[] = 'Skip configuration timestamp check.';
|
||||
return false;
|
||||
}
|
||||
|
||||
// Generate checksum according to the configuration settings.
|
||||
if (!$checkConfig) {
|
||||
$this->messages[] = 'Check configuration timestamps from system.yaml files.';
|
||||
// Just check changes in system.yaml files and ignore all the other files.
|
||||
$cc = $checkSystem ? $this->finder->locateConfigFile($this->configLookup, 'system') : [];
|
||||
} else {
|
||||
$this->messages[] = 'Check configuration timestamps from all configuration files.';
|
||||
// Check changes in all configuration files.
|
||||
$cc = $this->finder->locateConfigFiles($this->configLookup, $this->pluginLookup);
|
||||
}
|
||||
|
||||
if ($checkBlueprints) {
|
||||
$this->messages[] = 'Check blueprint timestamps from all blueprint files.';
|
||||
$cb = $this->finder->locateBlueprintFiles($this->blueprintLookup, $this->pluginLookup);
|
||||
} else {
|
||||
$cb = [];
|
||||
}
|
||||
|
||||
if ($checkLanguages) {
|
||||
$this->messages[] = 'Check language timestamps from all language files.';
|
||||
$cl = $this->finder->locateLanguageFiles($this->languagesLookup, $this->pluginLookup);
|
||||
} else {
|
||||
$cl = [];
|
||||
}
|
||||
|
||||
$this->checksum = md5(json_encode([$cc, $cb, $cl]));
|
||||
}
|
||||
|
||||
// Generate checksum according to the configuration settings.
|
||||
if (!$checkConfig) {
|
||||
$this->messages[] = 'Check configuration timestamps from system.yaml files.';
|
||||
// Just check changes in system.yaml files and ignore all the other files.
|
||||
$cc = $checkSystem ? $this->finder->locateConfigFile($this->configLookup, 'system') : [];
|
||||
} else {
|
||||
$this->messages[] = 'Check configuration timestamps from all configuration files.';
|
||||
// Check changes in all configuration files.
|
||||
$cc = $this->finder->locateConfigFiles($this->configLookup, $this->pluginLookup);
|
||||
}
|
||||
|
||||
if ($checkBlueprints) {
|
||||
$this->messages[] = 'Check blueprint timestamps from all blueprint files.';
|
||||
$cb = $this->finder->locateBlueprintFiles($this->blueprintLookup, $this->pluginLookup);
|
||||
} else {
|
||||
$cb = [];
|
||||
}
|
||||
|
||||
return md5(json_encode([$cc, $cb]));
|
||||
return $this->checksum;
|
||||
}
|
||||
|
||||
protected function autoDetectEnvironmentConfig($items)
|
||||
@@ -312,6 +341,54 @@ class Config extends Data
|
||||
$this->items = $cache['data'];
|
||||
}
|
||||
|
||||
protected function loadCompiledLanguages($languages, $plugins, $filename = null)
|
||||
{
|
||||
$checksum = md5(json_encode($languages));
|
||||
$filename = $filename
|
||||
? CACHE_DIR . 'compiled/languages/' . $filename . '-' . $this->environment . '.php'
|
||||
: CACHE_DIR . 'compiled/languages/' . $checksum . '-' . $this->environment . '.php';
|
||||
$file = PhpFile::instance($filename);
|
||||
$cache = $file->exists() ? $file->content() : null;
|
||||
$languageFiles = $this->finder->locateLanguageFiles($languages, $plugins);
|
||||
$checksum .= ':' . md5(json_encode($languageFiles));
|
||||
$class = get_class($this);
|
||||
|
||||
// Load real file if cache isn't up to date (or is invalid).
|
||||
if (
|
||||
!is_array($cache)
|
||||
|| !isset($cache['checksum'])
|
||||
|| !isset($cache['@class'])
|
||||
|| $cache['checksum'] != $checksum
|
||||
|| $cache['@class'] != $class
|
||||
) {
|
||||
// Attempt to lock the file for writing.
|
||||
$file->lock(false);
|
||||
|
||||
// Load languages.
|
||||
$this->languages = new Languages;
|
||||
foreach ($languageFiles as $files) {
|
||||
$this->loadLanguagesFiles($files);
|
||||
}
|
||||
|
||||
$this->languages->reformat();
|
||||
|
||||
$cache = [
|
||||
'@class' => $class,
|
||||
'checksum' => $checksum,
|
||||
'files' => $languageFiles,
|
||||
'data' => $this->languages->toArray()
|
||||
];
|
||||
// If compiled file wasn't already locked by another process, save it.
|
||||
if ($file->locked() !== false) {
|
||||
$this->messages[] = 'Saving compiled languages.';
|
||||
$file->save($cache);
|
||||
$file->unlock();
|
||||
}
|
||||
} else {
|
||||
$this->languages = new Languages($cache['data']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Load blueprints.
|
||||
*
|
||||
@@ -338,6 +415,14 @@ class Config extends Data
|
||||
}
|
||||
}
|
||||
|
||||
public function loadLanguagesFiles(array $files)
|
||||
{
|
||||
foreach ($files as $name => $item) {
|
||||
$file = CompiledYamlFile::instance($item['file']);
|
||||
$this->languages->join($name, $file->content(), '/');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize resource locator by using the configuration.
|
||||
*
|
||||
@@ -380,4 +465,9 @@ class Config extends Data
|
||||
|
||||
return $schemes;
|
||||
}
|
||||
|
||||
public function getLanguages()
|
||||
{
|
||||
return $this->languages;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,6 +49,18 @@ class ConfigFinder
|
||||
return $list;
|
||||
}
|
||||
|
||||
public function locateLanguageFiles(array $languages, array $plugins)
|
||||
{
|
||||
$list = [];
|
||||
foreach (array_reverse($plugins) as $folder) {
|
||||
$list += $this->detectLanguagesInFolder($folder, 'languages');
|
||||
}
|
||||
foreach (array_reverse($languages) as $folder) {
|
||||
$list += $this->detectRecursive($folder);
|
||||
}
|
||||
return $list;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all locations for a single configuration file.
|
||||
*
|
||||
@@ -90,11 +102,11 @@ class ConfigFinder
|
||||
$list = [];
|
||||
|
||||
if (is_dir($folder)) {
|
||||
$iterator = new \DirectoryIterator($folder);
|
||||
$iterator = new \FilesystemIterator($folder);
|
||||
|
||||
/** @var \DirectoryIterator $directory */
|
||||
foreach ($iterator as $directory) {
|
||||
if (!$directory->isDir() || $directory->isDot()) {
|
||||
if (!$directory->isDir()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -111,6 +123,34 @@ class ConfigFinder
|
||||
return [$path => $list];
|
||||
}
|
||||
|
||||
protected function detectLanguagesInFolder($folder, $lookup = null)
|
||||
{
|
||||
$path = trim(Folder::getRelativePath($folder), '/');
|
||||
|
||||
$list = [];
|
||||
|
||||
if (is_dir($folder)) {
|
||||
$iterator = new \FilesystemIterator($folder);
|
||||
|
||||
/** @var \DirectoryIterator $directory */
|
||||
foreach ($iterator as $directory) {
|
||||
if (!$directory->isDir()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$name = $directory->getBasename();
|
||||
$find = ($lookup ?: $name) . '.yaml';
|
||||
$filename = "{$path}/{$name}/$find";
|
||||
|
||||
if (file_exists($filename)) {
|
||||
$list["plugins"] = ['file' => $filename, 'modified' => filemtime($filename)];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return [$path => $list];
|
||||
}
|
||||
|
||||
/**
|
||||
* Detects all plugins with a configuration file and returns them with last modification time.
|
||||
*
|
||||
|
||||
27
system/src/Grav/Common/Config/Languages.php
Normal file
27
system/src/Grav/Common/Config/Languages.php
Normal file
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
namespace Grav\Common\Config;
|
||||
|
||||
use Grav\Common\Data\Data;
|
||||
|
||||
/**
|
||||
* The Languages class contains configuration rules.
|
||||
*
|
||||
* @author RocketTheme
|
||||
* @license MIT
|
||||
*/
|
||||
class Languages extends Data
|
||||
{
|
||||
|
||||
public function reformat()
|
||||
{
|
||||
if (isset($this->items['plugins'])) {
|
||||
$this->items = array_merge_recursive($this->items, $this->items['plugins']);
|
||||
unset($this->items['plugins']);
|
||||
}
|
||||
}
|
||||
|
||||
public function mergeRecursive(array $data)
|
||||
{
|
||||
$this->items = array_merge_recursive($this->items, $data);
|
||||
}
|
||||
}
|
||||
@@ -248,6 +248,13 @@ class Language
|
||||
$lookup = array_shift($args);
|
||||
|
||||
if ($this->enabled() && $lookup) {
|
||||
|
||||
if ($this->config->get('system.languages.translations.fallback', true)) {
|
||||
$languages = $this->getFallbackLanguages();
|
||||
} else {
|
||||
$languages = (array) $this->getDefault();
|
||||
}
|
||||
|
||||
foreach ($this->getFallbackLanguages() as $lang) {
|
||||
$translation = $this->getTranslation($lang, $lookup);
|
||||
|
||||
@@ -272,6 +279,13 @@ class Language
|
||||
* @return string
|
||||
*/
|
||||
public function getTranslation($lang, $key) {
|
||||
return $this->config->get('languages.'.$lang.'.'.$key, null);
|
||||
$languages = $this->config->getLanguages();
|
||||
|
||||
$translation = $languages->get($lang.'.'.$key, null);
|
||||
if (is_array($translation)) {
|
||||
return (string) array_shift($translation);
|
||||
}
|
||||
|
||||
return $translation;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -221,7 +221,13 @@ class Themes extends Iterator
|
||||
protected function loadConfiguration($name, Config $config)
|
||||
{
|
||||
$themeConfig = CompiledYamlFile::instance("themes://{$name}/{$name}" . YAML_EXT)->content();
|
||||
|
||||
$config->joinDefaults("themes.{$name}", $themeConfig);
|
||||
|
||||
if ($this->grav['language']->enabled()) {
|
||||
$languages = CompiledYamlFile::instance("themes://{$name}/languages". YAML_EXT)->content();
|
||||
if ($languages) {
|
||||
$config->getLanguages()->mergeRecursive($languages);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -95,9 +95,13 @@ class Uri
|
||||
$uri = $language->setActiveFromUri($uri);
|
||||
|
||||
// redirect to language specific homepage if configured to do so
|
||||
if ($uri == '/' && $language->enabled() && $config->get('system.languages.home.redirect', true) && !$language->getActive()) {
|
||||
$prefix = $config->get('system.languages.home.include_lang', true) ? $language->getDefault() . '/' : '';
|
||||
$grav->redirect($prefix . Pages::getHomeRoute());
|
||||
if ($uri == '/' && $language->enabled() && !$language->getActive()) {
|
||||
if ($config->get('system.languages.home_redirect.include_route', true)) {
|
||||
$prefix = $config->get('system.languages.home_redirect.include_lang', true) ? $language->getDefault() . '/' : '';
|
||||
$grav->redirect($prefix . Pages::getHomeRoute());
|
||||
} elseif ($config->get('system.languages.home_redirect.include_lang', true)) {
|
||||
$grav->redirect($language->getDefault() . '/');
|
||||
}
|
||||
}
|
||||
|
||||
// split the URL and params
|
||||
|
||||
Reference in New Issue
Block a user