diff --git a/system/src/Grav/Common/Language.php b/system/src/Grav/Common/Language.php index 36ee463c2..77c5c8892 100644 --- a/system/src/Grav/Common/Language.php +++ b/system/src/Grav/Common/Language.php @@ -2,52 +2,110 @@ namespace Grav\Common; /** - * Contain some useful language functions + * Language and translation functionality for Grav */ class Language { + protected $enabled = true; protected $languages = []; protected $page_extensions = []; + protected $fallback_languages = []; protected $default; protected $active; - protected $enabled = true; + protected $config; + /** + * Constructor + * + * @param \Grav\Common\Grav $grav + */ public function __construct(Grav $grav) { - $this->languages = $grav['config']->get('system.languages.supported', []); + $this->config = $grav['config']; + $this->languages = $this->config->get('system.languages.supported', []); + $this->init(); + } + + /** + * Initialize the default and enabled languages + */ + public function init() + { $this->default = reset($this->languages); if (empty($this->languages)) { $this->enabled = false; } - } + /** + * Ensure that languages are enabled + * + * @return bool + */ public function enabled() { return $this->enabled; } + /** + * Gets the array of supported languages + * + * @return array + */ public function getLanguages() { return $this->languages; } + /** + * Sets the current supported languages manually + * + * @param $langs + */ public function setLanguages($langs) { $this->languages = $langs; + $this->init(); } + /** + * Gets a pipe-separated string of available languages + * + * @return string + */ public function getAvailable() { return implode('|', $this->languages); } + /** + * Gets language, active if set, else default + * + * @return mixed + */ + public function getLanguage() + { + return $this->active ? $this->active : $this->default; + } + + /** + * Gets current default language + * + * @return mixed + */ public function getDefault() { return $this->default; } + /** + * Sets default language manually + * + * @param $lang + * + * @return bool + */ public function setDefault($lang) { if ($this->validate($lang)) { @@ -57,11 +115,23 @@ class Language return false; } + /** + * Gets current active language + * + * @return mixed + */ public function getActive() { return $this->active; } + /** + * Sets active language manually + * + * @param $lang + * + * @return bool + */ public function setActive($lang) { if ($this->validate($lang)) { @@ -71,6 +141,13 @@ class Language return false; } + /** + * Sets the active language based on the first part of the URL + * + * @param $uri + * + * @return mixed + */ public function setActiveFromUri($uri) { $regex = '/(\/('.$this->getAvailable().')).*/'; @@ -87,30 +164,70 @@ class Language return $uri; } - public function getValidPageExtensions() + + /** + * Gets an array of valid extensions with active first, then fallback extensions + * + * @return array + */ + public function getFallbackPageExtensions($file_ext = null) { if (empty($this->page_extensions)) { + if (empty($file_ext)) { + $file_ext = CONTENT_EXT; + } + if ($this->enabled()) { $valid_lang_extensions = []; foreach ($this->languages as $lang) { - $valid_lang_extensions[] = '.'.$lang.CONTENT_EXT; + $valid_lang_extensions[] = '.'.$lang.$file_ext; } if ($this->active) { - $active_extension = '.'.$this->active.CONTENT_EXT; + $active_extension = '.'.$this->active.$file_ext; $key = array_search($active_extension, $valid_lang_extensions); unset($valid_lang_extensions[$key]); array_unshift($valid_lang_extensions, $active_extension); } - $this->page_extensions = array_merge($valid_lang_extensions, (array) CONTENT_EXT); + $this->page_extensions = array_merge($valid_lang_extensions, (array) $file_ext); } else { - $this->page_extensions = (array) CONTENT_EXT; + $this->page_extensions = (array) $file_ext; } } return $this->page_extensions; } + /** + * Gets an array of languages with active first, then fallback languages + * + * @return array + */ + public function getFallbackLanguages() + { + if (empty($this->fallback_languages)) { + if ($this->enabled()) { + $fallback_languages = $this->languages; + + if ($this->active) { + $active_extension = $this->active; + $key = array_search($active_extension, $fallback_languages); + unset($fallback_languages[$key]); + array_unshift($fallback_languages, $active_extension); + } + $this->fallback_languages = $fallback_languages; + } + } + return $this->fallback_languages; + } + + /** + * Ensures the language is valid and supported + * + * @param $lang + * + * @return bool + */ public function validate($lang) { if (in_array($lang, $this->languages)) { @@ -119,4 +236,42 @@ class Language return false; } + /** + * Translate a key and possibly arguments into a string using current lang and fallbacks + * + * @param Array $args first argument is the lookup key value + * other arguments can be passed and replaced in the translation with sprintf syntax + * @return string + */ + public function translate(Array $args) + { + $lookup = array_shift($args); + + if ($this->enabled() && $lookup) { + foreach ($this->getFallbackLanguages() as $lang) { + $translation = $this->getTranslation($lang, $lookup); + + if ($translation) { + if (count($args) >= 1) { + return vsprintf($translation, $args); + } else { + return $translation; + } + } + } + } + return ''.$lookup.''; + } + + /** + * Lookup the translation text for a given lang and key + * + * @param $lang lang code + * @param $key key to lookup with + * + * @return string + */ + public function getTranslation($lang, $key) { + return $this->config->get('languages.'.$lang.'.'.$key, null); + } } diff --git a/system/src/Grav/Common/Page/Pages.php b/system/src/Grav/Common/Page/Pages.php index 5b1cf143e..9a705c8fd 100644 --- a/system/src/Grav/Common/Page/Pages.php +++ b/system/src/Grav/Common/Page/Pages.php @@ -603,10 +603,9 @@ class Pages $content_exists = false; $pages_found = glob($directory.'/*'.CONTENT_EXT); - $page_extensions = $language->getValidPageExtensions(); + $page_extensions = $language->getFallbackPageExtensions(); if ($pages_found) { - foreach ($page_extensions as $extension) { foreach ($pages_found as $found) { if (preg_match('/^.*\/[0-9A-Za-z\-\_]+('.$extension.')$/', $found)) { diff --git a/system/src/Grav/Common/TwigExtension.php b/system/src/Grav/Common/TwigExtension.php index 6645100f4..77d06bcfe 100644 --- a/system/src/Grav/Common/TwigExtension.php +++ b/system/src/Grav/Common/TwigExtension.php @@ -16,11 +16,13 @@ class TwigExtension extends \Twig_Extension { protected $grav; protected $debugger; + protected $config; public function __construct() { $this->grav = Grav::instance(); $this->debugger = isset($this->grav['debugger']) ? $this->grav['debugger'] : null; + $this->config = $this->grav['config']; } /** @@ -54,7 +56,8 @@ class TwigExtension extends \Twig_Extension new \Twig_SimpleFilter('absolute_url', [$this, 'absoluteUrlFilter']), new \Twig_SimpleFilter('markdown', [$this, 'markdownFilter']), new \Twig_SimpleFilter('starts_with', [$this, 'startsWithFilter']), - new \Twig_SimpleFilter('ends_with', [$this, 'endsWithFilter']) + new \Twig_SimpleFilter('ends_with', [$this, 'endsWithFilter']), + new \Twig_SimpleFilter('t', [$this, 'translateFilter']) ]; } @@ -72,6 +75,7 @@ class TwigExtension extends \Twig_Extension new \Twig_SimpleFunction('debug', [$this, 'dump'], ['needs_context' => true, 'needs_environment' => true]), new \Twig_SimpleFunction('gist', [$this, 'gistFunc']), new \Twig_simpleFunction('random_string', [$this, 'randomStringFunc']), + new \Twig_simpleFunction('t', [$this, 'translateFunc']) ]; } @@ -335,7 +339,7 @@ class TwigExtension extends \Twig_Extension public function markdownFilter($string) { $page = $this->grav['page']; - $defaults = $this->grav['config']->get('system.pages.markdown'); + $defaults = $this->$config->get('system.pages.markdown'); // Initialize the preferred variant of Parsedown if ($defaults['extra']) { @@ -359,6 +363,11 @@ class TwigExtension extends \Twig_Extension return Utils::endsWith($haystack, $needle); } + public function translateFilter() + { + return $this->grav['language']->translate(func_get_args()); + } + /** * Repeat given string x times. * @@ -459,4 +468,9 @@ class TwigExtension extends \Twig_Extension { return Utils::generateRandomString($count); } + + public function translateFunc() + { + return $this->grav['language']->translate(func_get_args()); + } }