diff --git a/plugins/langswitcher/CHANGELOG.md b/plugins/langswitcher/CHANGELOG.md new file mode 100644 index 0000000..165780c --- /dev/null +++ b/plugins/langswitcher/CHANGELOG.md @@ -0,0 +1,118 @@ +# v3.0.2 +## 10/05/2022 + +1. [](#new) + * Require Grav `1.7.37` to make use of the new `Pages::getSimplePagesHash()` method + * Added caching to `translated_routes` so translation work is only performed on the first load, resulting in faster subsequent page loads + +# v3.0.1 +## 08/19/2022 + +1. [](#bugfix) + * Fixed another issue with incorrect `hreflang` URLs + +# v3.0.0 +## 08/19/2022 + +1. [](#new) + * Completely rewrote the logic for translated URLs to be more robust. + * Added configuration option to use **Translated URLs** or use previous **Raw-Route** approach +1. [](#improved) + * Updated `hreflang` Twig template to use new translated URLs logic + * Added an `x-default` entry for `hreflang` template when default language has `include_default_lang` set to false + * Support `params` and `query` string parameters in URLs + * Full domain URLs for `hreflang` entries + +# v2.0.1 +## 08/04/2022 + +1. [](#bugfix) + * Fixed exception thrown instead of **404 Page not found** [#66](https://github.com/getgrav/grav-plugin-langswitcher/issues/66) + +# v2.0.0 +## 07/25/2022 + +1. [](#new) + * Support for translated slugs!!!! [#50](https://github.com/getgrav/grav-plugin-langswitcher/pull/50) + * Require Grav `1.7` +1. [](#improved) + * Improved support for home URL [#59](https://github.com/getgrav/grav-plugin-langswitcher/pull/59) + +# v1.5.0 +## 07/01/2021 + +1. [](#new) + * Made langswitcher display more customizable. See README.md for full details. + +# v1.4.3 +## 06/25/2021 + +1. [](#new) + * Made langswitcher data available in Grav object +1. [](#bugfix) + * Fix multilang alternatives [#58](https://github.com/getgrav/grav-plugin-langswitcher/pull/58) +# v1.4.2 +## 03/17/2021 + +1. [](#new) + * Pass phpstan level 1 tests + * Require Grav v1.6 +1. [](#bugfix) + * Fix `hreflang` URLs [#57](https://github.com/getgrav/grav-plugin-langswitcher/pull/57) + +# v1.4.1 +## 05/09/2019 + +1. [](#new) + * Added some translations [#45](https://github.com/getgrav/grav-plugin-langswitcher/pull/45) + +# v1.4.0 +## 06/29/2017 + +1. [](#new) + * Added the `untranslated_pages_behavior` option to determine what to do with a language link when the current page doesn't exist in that language or it exists but it's not published +1. [](#bugfix) + * Fixed generated URLs when `append_url_extension` is set, via PR [#22](https://github.com/getgrav/grav-plugin-langswitcher/pull/22) + +# v1.3.0 +## 02/17/2017 + +1. [](#new) + * Added support for `hreflang` annotations via PR [#19](https://github.com/getgrav/grav-plugin-langswitcher/pull/19) + +# v1.2.1 +## 05/28/2016 + +1. [](#bugfix) + * Display all language names, even those with non supported locales + +# v1.2.0 +## 05/03/2016 + +1. [](#improved) + * Take URI parameters into account when switching languages + * Add `external` class to avoid problems on modular pages when `jquery.singlePageNav` is loaded + +# v1.1.0 +## 10/15/2015 + +1. [](#improved) + * Added active class to language links + +# v1.0.2 +## 07/13/2015 + +1. [](#improved) + * Improved homepage routing + +# v1.0.1 +## 07/08/2015 + +1. [](#improved) + * Updated blueprints with some typo fixes + +# v1.0.0 +## 07/08/2015 + +1. [](#new) + * ChangeLog started... diff --git a/plugins/langswitcher/LICENSE b/plugins/langswitcher/LICENSE new file mode 100644 index 0000000..0e788c6 --- /dev/null +++ b/plugins/langswitcher/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2015 Grav + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/plugins/langswitcher/README.md b/plugins/langswitcher/README.md new file mode 100644 index 0000000..81bcc04 --- /dev/null +++ b/plugins/langswitcher/README.md @@ -0,0 +1,128 @@ +# Grav LangSwitcher Plugin + +![LangSwitcher](assets/readme_1.png) + +`LangSwitcher` is a [Grav](http://github.com/getgrav/grav) plugin that provides native language text links to switch between [Multiple Languages](http://learn.getgrav.org/content/multi-language) in Grav **0.9.30** or greater. + +# Installation + +Installing the LangSwitcher plugin can be done in one of two ways. Our GPM (Grav Package Manager) installation method enables you to quickly and easily install the plugin with a simple terminal command, while the manual method enables you to do so via a zip file. + +## GPM Installation (Preferred) + +The simplest way to install this plugin is via the [Grav Package Manager (GPM)](http://learn.getgrav.org/advanced/grav-gpm) through your system's Terminal (also called the command line). From the root of your Grav install type: + + bin/gpm install langswitcher + +This will install the LangSwitcher plugin into your `/user/plugins` directory within Grav. Its files can be found under `/your/site/grav/user/plugins/langswitcher`. + +## Manual Installation + +To install this plugin, just download the zip version of this repository and unzip it under `/your/site/grav/user/plugins`. Then, rename the folder to `langswitcher`. You can find these files either on [GitHub](https://github.com/getgrav/grav-plugin-langswitcher) or via [GetGrav.org](http://getgrav.org/downloads/plugins#extras). + +You should now have all the plugin files under + + /your/site/grav/user/plugins/langswitcher + +# Usage + +The `langswitcher` plugin doesn't require any configuration. You do however need to add the included Twig partials template into your own theme somewhere you want the available languages to be displayed. + +```twig +{% include 'partials/langswitcher.html.twig' %} +``` + +Something you might want to do is to override the look and feel of the langswitcher, and with Grav it is super easy. + +Copy the template file [langswitcher.html.twig](templates/partials/langswitcher.html.twig) into the `templates` folder of your custom theme: + +``` +/your/site/grav/user/themes/custom-theme/templates/partials/langswitcher.html.twig +``` + +You can now edit the override and tweak it however you prefer. + +## Usage of the `hreflang` partial + +A second template is available for `hreflang` annotations in the header of the page. In order to emit language annotations for the available languages of a page you need to add the corrsponding Twig partial template into the `` section of your page, which can typically be found in `base.html.twig`: + +```twkg +{% include 'partials/langswitcher.hreflang.html.twig' %} +``` + +This will generate something like: + +```html + + + +``` + +# Updating + +As development for the LangSwitcher plugin continues, new versions may become available that add additional features and functionality, improve compatibility with newer Grav releases, and generally provide a better user experience. Updating LangSwitcher is easy, and can be done through Grav's GPM system, as well as manually. + +## GPM Update (Preferred) + +The simplest way to update this plugin is via the [Grav Package Manager (GPM)](http://learn.getgrav.org/advanced/grav-gpm). You can do this with this by navigating to the root directory of your Grav install using your system's Terminal (also called command line) and typing the following: + + bin/gpm update langswitcher + +This command will check your Grav install to see if your LangSwitcher plugin is due for an update. If a newer release is found, you will be asked whether or not you wish to update. To continue, type `y` and hit enter. The plugin will automatically update and clear Grav's cache. + +> Note: Any changes you have made to any of the files listed under this directory will also be removed and replaced by the new set. Any files located elsewhere (for example a YAML settings file placed in `user/config/plugins`) will remain intact. + +## Configuration + +Simply copy the `user/plugins/langswitcher/langswitcher.yaml` into `user/config/plugins/langswitcher.yaml` and make your modifications. + +```yaml +enabled: true +built_in_css: true +translated_urls: true +untranslated_pages_behavior: none +language_display: long +``` + +Options are pretty self explanatory. + +## Redirecting after switching language + +To have Grav redirect to the default page route after switching language, you must add the following configuration to `user/config/system.yaml` + +```yaml +pages: + redirect_default_route: true +``` + +## Customization + +The default format for the displaying of the languages is to use the native language names in a **long** format (e.g. `English`, `Deutsch`, `Français`). However, you can change the default output to use **short** names (e.g. `EN`, `DE`, `FR`). + +This can be configured via the `langswitcher.yaml` configuration file: + +```yaml +language_display: long # long | short are the valid options +``` + +You can also pass the format in directly via the Twig include: + +```twig +{% include 'partials/langswitcher.hreflang.html.twig' with {display_format: 'short'} %} +``` + +Also you can override the two Twig partials that control the actual display of the **long** and **short** output, by copying the partial int your theme's `templates/partials/` folder and modifying: + +```twig +# templates/partials/langswitcher-long.html.twig +{{ native_name(language)|capitalize }} +``` + +and + +```twig +# templates/partials/langswitcher-short.html.twig +{{ language|upper }} +``` + + diff --git a/plugins/langswitcher/assets/readme_1.png b/plugins/langswitcher/assets/readme_1.png new file mode 100644 index 0000000..8cfb824 Binary files /dev/null and b/plugins/langswitcher/assets/readme_1.png differ diff --git a/plugins/langswitcher/blueprints.yaml b/plugins/langswitcher/blueprints.yaml new file mode 100644 index 0000000..910baee --- /dev/null +++ b/plugins/langswitcher/blueprints.yaml @@ -0,0 +1,73 @@ +name: LangSwitcher +version: 3.0.2 +description: LangSwitcher is a [Grav](https://github.com/getgrav/grav) plugin that provides native language text links to switch between [multiple languages](http://learn.getgrav.org/content/multi-language) in Grav **v0.9.30** or greater. +icon: globe +author: + name: Team Grav + email: devs@getgrav.org + url: http://getgrav.org +homepage: https://github.com/getgrav/grav-plugin-langswitcher +keywords: mulitlang, multilanguage, translation, switcher +bugs: https://github.com/getgrav/grav-plugin-langswitcher/issues +license: MIT +dependencies: + - { name: grav, version: '>=1.7.37' } + +form: + validation: strict + fields: + enabled: + type: toggle + label: PLUGIN_ADMIN.PLUGIN_STATUS + highlight: 1 + default: 1 + options: + 1: PLUGIN_ADMIN.ENABLED + 0: PLUGIN_ADMIN.DISABLED + validate: + type: bool + + built_in_css: + type: toggle + label: PLUGIN_LANGSWITCHER.BUILTIN_CSS + help: PLUGIN_LANGSWITCHER.BUILTIN_CSS_HELP + highlight: 1 + default: 1 + options: + 1: PLUGIN_ADMIN.ENABLED + 0: PLUGIN_ADMIN.DISABLED + validate: + type: bool + + translated_urls: + type: toggle + label: PLUGIN_LANGSWITCHER.TRANSLATED_URLS + help: PLUGIN_LANGSWITCHER.TRANSLATED_URLS_HELP + highlight: 1 + default: 1 + options: + 1: PLUGIN_ADMIN.ENABLED + 0: PLUGIN_ADMIN.DISABLED + validate: + type: bool + + language_display: + type: select + size: small + label: PLUGIN_LANGSWITCHER.LANGUAGE_DISPLAY + help: PLUGIN_LANGSWITCHER.LANGUAGE_DISPLAY_HELP + default: long + options: + long: PLUGIN_LANGSWITCHER.LANGUAGE_DISPLAY_LONG + short: PLUGIN_LANGSWITCHER.LANGUAGE_DISPLAY_SHORT + + untranslated_pages_behavior: + type: select + size: medium + label: PLUGIN_LANGSWITCHER.UNTRANSLATED_PAGES_BEHAVIOR + help: PLUGIN_LANGSWITCHER.UNTRANSLATED_PAGES_BEHAVIOR_HELP + default: none + options: + none: PLUGIN_LANGSWITCHER.UNTRANSLATED_PAGES_BEHAVIOR_OPTION_NONE + redirect: PLUGIN_LANGSWITCHER.UNTRANSLATED_PAGES_BEHAVIOR_OPTION_REDIRECT + hide: PLUGIN_LANGSWITCHER.UNTRANSLATED_PAGES_BEHAVIOR_OPTION_HIDE diff --git a/plugins/langswitcher/composer.json b/plugins/langswitcher/composer.json new file mode 100644 index 0000000..d32049d --- /dev/null +++ b/plugins/langswitcher/composer.json @@ -0,0 +1,29 @@ +{ + "name": "grav-plugin-langswitcher", + "type": "grav-plugin", + "description": "Language switcher plugin for Grav CMS", + "keywords": ["langswitcher"], + "homepage": "https://github.com/getgrav/grav-plugin-langswitcher/", + "license": "MIT", + "authors": [ + { + "name": "Team Grav", + "email": "devs@getgrav.org", + "homepage": "http://getgrav.org", + "role": "Developer" + } + ], + "require": { + "php": ">=7.1.3", + "ext-json": "*", + "ext-mbstring": "*" + }, + "autoload": { + "classmap": ["langswitcher.php"] + }, + "config": { + "platform": { + "php": "7.1.3" + } + } +} diff --git a/plugins/langswitcher/composer.lock b/plugins/langswitcher/composer.lock new file mode 100644 index 0000000..232467f --- /dev/null +++ b/plugins/langswitcher/composer.lock @@ -0,0 +1,24 @@ +{ + "_readme": [ + "This file locks the dependencies of your project to a known state", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", + "This file is @generated automatically" + ], + "content-hash": "54479277654e1741212fe76198612572", + "packages": [], + "packages-dev": [], + "aliases": [], + "minimum-stability": "stable", + "stability-flags": [], + "prefer-stable": false, + "prefer-lowest": false, + "platform": { + "php": ">=7.1.3", + "ext-json": "*", + "ext-mbstring": "*" + }, + "platform-dev": [], + "platform-overrides": { + "php": "7.1.3" + } +} diff --git a/plugins/langswitcher/css/langswitcher.css b/plugins/langswitcher/css/langswitcher.css new file mode 100644 index 0000000..710dee3 --- /dev/null +++ b/plugins/langswitcher/css/langswitcher.css @@ -0,0 +1,22 @@ +.langswitcher { + position: relative; + top: 50%; + -webkit-transform: translateY(-50%); + -moz-transform: translateY(-50%); + -o-transform: translateY(-50%); + -ms-transform: translateY(-50%); + transform: translateY(-50%); + margin-left: 1rem !important; + display: inline-block; +} + +.langswitcher li { + display: inline-block; + margin-left: 0.5rem; + line-height: 1rem; +} + +.langswitcher .active { + font-weight: bold; + text-decoration: underline; +} diff --git a/plugins/langswitcher/langswitcher.php b/plugins/langswitcher/langswitcher.php new file mode 100644 index 0000000..82f22eb --- /dev/null +++ b/plugins/langswitcher/langswitcher.php @@ -0,0 +1,180 @@ + [ + ['autoload', 100001], + ['onPluginsInitialized', 0] + ] + ]; + } + + /** + * [onPluginsInitialized:100000] Composer autoload. + * + * @return ClassLoader + */ + public function autoload() + { + return require __DIR__ . '/vendor/autoload.php'; + } + + /** + * Initialize configuration + */ + public function onPluginsInitialized() + { + if ($this->isAdmin()) { + $this->active = false; + return; + } + + $this->enable([ + 'onTwigInitialized' => ['onTwigInitialized', 0], + 'onTwigTemplatePaths' => ['onTwigTemplatePaths', 0], + 'onTwigSiteVariables' => ['onTwigSiteVariables', 0] + ]); + } + + /** Add the native_name function */ + public function onTwigInitialized() + { + $this->grav['twig']->twig()->addFunction( + new \Twig_SimpleFunction('native_name', function($key) { + return LanguageCodes::getNativeName($key); + }) + ); + } + + /** + * Add current directory to twig lookup paths. + */ + public function onTwigTemplatePaths() + { + $this->grav['twig']->twig_paths[] = __DIR__ . '/templates'; + } + + /** + * Generate localized route based on the translated slugs found through the pages hierarchy + */ + protected function getTranslatedUrl($lang, $path) + { + /** @var Language $language */ + $url = null; + /** @var Pages $pages */ + $pages = $this->grav['pages']; + /** @var Language $language */ + $language = $this->grav['language']; + + $language->init(); + $language->setActive($lang); + $pages->reset(); + $page = $pages->get($path); + if ($page) { + $url = $page->url(); + } + return $url; + } + + /** + * Set needed variables to display Langswitcher. + */ + public function onTwigSiteVariables() + { + + /** @var PageInterface $page */ + $page = $this->grav['page']; + + /** @var Pages $pages */ + $pages = $this->grav['pages']; + + /** @var Cache $cache */ + $cache = $this->grav['cache']; + + $data = new \stdClass; + $data->page_route = $page->rawRoute(); + if ($page->home()) { + $data->page_route = '/'; + } + + $translated_cache_key = md5('translated_cache_key'.$data->page_route.$pages->getSimplePagesHash()); + + $languages = $this->grav['language']->getLanguages(); + $data->languages = $languages; + + if ($this->config->get('plugins.langswitcher.untranslated_pages_behavior') !== 'none') { + $translated_pages = []; + foreach ($languages as $language) { + $translated_pages[$language] = null; + $page_name_without_ext = substr($page->name(), 0, -(strlen($page->extension()))); + $translated_page_path = $page->path() . DS . $page_name_without_ext . '.' . $language . '.md'; + if (!file_exists($translated_page_path) and $language == $this->grav['language']->getDefault()) { + $translated_page_path = $page->path() . DS . $page_name_without_ext . '.md'; + } + if (file_exists($translated_page_path)) { + $translated_page = new Page(); + $translated_page->init(new \SplFileInfo($translated_page_path), $language . '.md'); + $translated_pages[$language] = $translated_page; + } + } + $data->translated_pages = $translated_pages; + } + + $language = $this->grav['language']; + $active = $language->getActive() ?? $language->getDefault(); + + if ($this->config->get('plugins.langswitcher.translated_urls', true)) { + $data->translated_routes = $cache->fetch($translated_cache_key); + + if ($data->translated_routes === false) { + $translate_langs = $data->languages; + + if (($key = array_search($active, $translate_langs)) !== false) { + $data->translated_routes[$active] = $page->url(); + unset($translate_langs[$key]); + } + + foreach ($translate_langs as $lang) { + $data->translated_routes[$lang] = $this->getTranslatedUrl($lang, $page->path()); + if (is_null($data->translated_routes[$lang])) { + $data->translated_routes[$lang] = $data->page_route; + } + } + // Reset pages to current active language + $language->init(); + $language->setActive($active); + $this->grav['pages']->reset(); + $cache->save($translated_cache_key, $data->translated_routes); + } + } + + $data->current = $language->getLanguage(); + + $this->grav['twig']->twig_vars['langswitcher'] = $this->grav['langswitcher'] = $data; + + if ($this->config->get('plugins.langswitcher.built_in_css')) { + $this->grav['assets']->add('plugin://langswitcher/css/langswitcher.css'); + } + } + + public function getNativeName($code) { + + } +} diff --git a/plugins/langswitcher/langswitcher.yaml b/plugins/langswitcher/langswitcher.yaml new file mode 100644 index 0000000..a4973cd --- /dev/null +++ b/plugins/langswitcher/langswitcher.yaml @@ -0,0 +1,5 @@ +enabled: true +built_in_css: true +translated_urls: true +untranslated_pages_behavior: none +language_display: long diff --git a/plugins/langswitcher/languages.yaml b/plugins/langswitcher/languages.yaml new file mode 100644 index 0000000..b2ece9f --- /dev/null +++ b/plugins/langswitcher/languages.yaml @@ -0,0 +1,35 @@ +en: + PLUGIN_LANGSWITCHER: + BUILTIN_CSS: 'Use built in CSS' + BUILTIN_CSS_HELP: 'Include the CSS provided by the LangSwitcher plugin.' + UNTRANSLATED_PAGES_BEHAVIOR: 'Untranslated pages behavior' + UNTRANSLATED_PAGES_BEHAVIOR_HELP: "Determine what to do with a language link when the current page doesn't exist in that language or it exists but it's not published." + UNTRANSLATED_PAGES_BEHAVIOR_OPTION_NONE: 'Show language (default)' + UNTRANSLATED_PAGES_BEHAVIOR_OPTION_REDIRECT: 'Show language, link to home route' + UNTRANSLATED_PAGES_BEHAVIOR_OPTION_HIDE: 'Hide language' + LANGUAGE_DISPLAY: 'Language Display' + LANGUAGE_DISPLAY_HELP: 'The format of the language display, either "long" (e.g. English), or "short" (e.g. EN)' + LANGUAGE_DISPLAY_LONG: 'Long' + LANGUAGE_DISPLAY_SHORT: 'Short' + TRANSLATED_URLS: 'Translated URLs' + TRANSLATED_URLS_HELP: 'Use the actual translated page URL rather then the raw-route' + +ru: + PLUGIN_LANGSWITCHER: + BUILTIN_CSS: 'Использовать встроенный CSS' + BUILTIN_CSS_HELP: 'Использовать CSS, предоставленный плагином LangSwitcher.' + UNTRANSLATED_PAGES_BEHAVIOR: 'Поведение непереведенных страниц' + UNTRANSLATED_PAGES_BEHAVIOR_HELP: 'Определяет что делать с языковой ссылкой, если текущая страница не существует на этом языке или существует, но не опубликована.' + UNTRANSLATED_PAGES_BEHAVIOR_OPTION_NONE: 'Показать язык (по умолчанию)' + UNTRANSLATED_PAGES_BEHAVIOR_OPTION_REDIRECT: 'Показать язык, ссылка на домашнюю страницу' + UNTRANSLATED_PAGES_BEHAVIOR_OPTION_HIDE: 'Скрыть язык' + +uk: + PLUGIN_LANGSWITCHER: + BUILTIN_CSS: 'Використовувати вбудований CSS' + BUILTIN_CSS_HELP: 'Використовувати CSS, наданий плагіном LangSwitcher.' + UNTRANSLATED_PAGES_BEHAVIOR: 'Поведінка неперекладених сторінок' + UNTRANSLATED_PAGES_BEHAVIOR_HELP: 'Визначає що робити з посиланням на мову, якщо поточна сторінка не існує на цій мові або існує, але не опублікована.' + UNTRANSLATED_PAGES_BEHAVIOR_OPTION_NONE: 'Показати мову (за умовчанням)' + UNTRANSLATED_PAGES_BEHAVIOR_OPTION_REDIRECT: 'Показати мову, посилання на домашню сторінку' + UNTRANSLATED_PAGES_BEHAVIOR_OPTION_HIDE: 'Приховати мову' diff --git a/plugins/langswitcher/templates/partials/langswitcher-long.html.twig b/plugins/langswitcher/templates/partials/langswitcher-long.html.twig new file mode 100644 index 0000000..0fea2fc --- /dev/null +++ b/plugins/langswitcher/templates/partials/langswitcher-long.html.twig @@ -0,0 +1 @@ +{{ native_name(language)|capitalize }} \ No newline at end of file diff --git a/plugins/langswitcher/templates/partials/langswitcher-short.html.twig b/plugins/langswitcher/templates/partials/langswitcher-short.html.twig new file mode 100644 index 0000000..e71027e --- /dev/null +++ b/plugins/langswitcher/templates/partials/langswitcher-short.html.twig @@ -0,0 +1 @@ +{{ language|upper }} \ No newline at end of file diff --git a/plugins/langswitcher/templates/partials/langswitcher.hreflang.html.twig b/plugins/langswitcher/templates/partials/langswitcher.hreflang.html.twig new file mode 100644 index 0000000..1646ea4 --- /dev/null +++ b/plugins/langswitcher/templates/partials/langswitcher.hreflang.html.twig @@ -0,0 +1,16 @@ +{% set language_obj = grav.language %} +{% for language in langswitcher.languages %} + {% if langswitcher.translated_routes[language] %} + {% set lang_url = langswitcher.translated_routes[language] ~ page.urlExtension %} + {% else %} + {% set base_lang_url = base_url_simple ~ grav.language.getLanguageURLPrefix(language) %} + {% set lang_url = base_lang_url ~ langswitcher.page_route ~ page.urlExtension %} + {% endif %} + + {% set href_url = uri.base ~ lang_url ~ uri.params ~ (uri.query|length > 1 ? '?' ~ uri.query) %} + + {% if (language_obj.default == language and config.languages.include_default_lang == false) %} + + {% endif %} + +{% endfor %} diff --git a/plugins/langswitcher/templates/partials/langswitcher.html.twig b/plugins/langswitcher/templates/partials/langswitcher.html.twig new file mode 100644 index 0000000..3b44b1f --- /dev/null +++ b/plugins/langswitcher/templates/partials/langswitcher.html.twig @@ -0,0 +1,33 @@ + diff --git a/plugins/langswitcher/vendor/autoload.php b/plugins/langswitcher/vendor/autoload.php new file mode 100644 index 0000000..9211701 --- /dev/null +++ b/plugins/langswitcher/vendor/autoload.php @@ -0,0 +1,7 @@ + + * Jordi Boggiano + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace Composer\Autoload; + +/** + * ClassLoader implements a PSR-0, PSR-4 and classmap class loader. + * + * $loader = new \Composer\Autoload\ClassLoader(); + * + * // register classes with namespaces + * $loader->add('Symfony\Component', __DIR__.'/component'); + * $loader->add('Symfony', __DIR__.'/framework'); + * + * // activate the autoloader + * $loader->register(); + * + * // to enable searching the include path (eg. for PEAR packages) + * $loader->setUseIncludePath(true); + * + * In this example, if you try to use a class in the Symfony\Component + * namespace or one of its children (Symfony\Component\Console for instance), + * the autoloader will first look for the class under the component/ + * directory, and it will then fallback to the framework/ directory if not + * found before giving up. + * + * This class is loosely based on the Symfony UniversalClassLoader. + * + * @author Fabien Potencier + * @author Jordi Boggiano + * @see http://www.php-fig.org/psr/psr-0/ + * @see http://www.php-fig.org/psr/psr-4/ + */ +class ClassLoader +{ + // PSR-4 + private $prefixLengthsPsr4 = array(); + private $prefixDirsPsr4 = array(); + private $fallbackDirsPsr4 = array(); + + // PSR-0 + private $prefixesPsr0 = array(); + private $fallbackDirsPsr0 = array(); + + private $useIncludePath = false; + private $classMap = array(); + private $classMapAuthoritative = false; + private $missingClasses = array(); + private $apcuPrefix; + + public function getPrefixes() + { + if (!empty($this->prefixesPsr0)) { + return call_user_func_array('array_merge', $this->prefixesPsr0); + } + + return array(); + } + + public function getPrefixesPsr4() + { + return $this->prefixDirsPsr4; + } + + public function getFallbackDirs() + { + return $this->fallbackDirsPsr0; + } + + public function getFallbackDirsPsr4() + { + return $this->fallbackDirsPsr4; + } + + public function getClassMap() + { + return $this->classMap; + } + + /** + * @param array $classMap Class to filename map + */ + public function addClassMap(array $classMap) + { + if ($this->classMap) { + $this->classMap = array_merge($this->classMap, $classMap); + } else { + $this->classMap = $classMap; + } + } + + /** + * Registers a set of PSR-0 directories for a given prefix, either + * appending or prepending to the ones previously set for this prefix. + * + * @param string $prefix The prefix + * @param array|string $paths The PSR-0 root directories + * @param bool $prepend Whether to prepend the directories + */ + public function add($prefix, $paths, $prepend = false) + { + if (!$prefix) { + if ($prepend) { + $this->fallbackDirsPsr0 = array_merge( + (array) $paths, + $this->fallbackDirsPsr0 + ); + } else { + $this->fallbackDirsPsr0 = array_merge( + $this->fallbackDirsPsr0, + (array) $paths + ); + } + + return; + } + + $first = $prefix[0]; + if (!isset($this->prefixesPsr0[$first][$prefix])) { + $this->prefixesPsr0[$first][$prefix] = (array) $paths; + + return; + } + if ($prepend) { + $this->prefixesPsr0[$first][$prefix] = array_merge( + (array) $paths, + $this->prefixesPsr0[$first][$prefix] + ); + } else { + $this->prefixesPsr0[$first][$prefix] = array_merge( + $this->prefixesPsr0[$first][$prefix], + (array) $paths + ); + } + } + + /** + * Registers a set of PSR-4 directories for a given namespace, either + * appending or prepending to the ones previously set for this namespace. + * + * @param string $prefix The prefix/namespace, with trailing '\\' + * @param array|string $paths The PSR-4 base directories + * @param bool $prepend Whether to prepend the directories + * + * @throws \InvalidArgumentException + */ + public function addPsr4($prefix, $paths, $prepend = false) + { + if (!$prefix) { + // Register directories for the root namespace. + if ($prepend) { + $this->fallbackDirsPsr4 = array_merge( + (array) $paths, + $this->fallbackDirsPsr4 + ); + } else { + $this->fallbackDirsPsr4 = array_merge( + $this->fallbackDirsPsr4, + (array) $paths + ); + } + } elseif (!isset($this->prefixDirsPsr4[$prefix])) { + // Register directories for a new namespace. + $length = strlen($prefix); + if ('\\' !== $prefix[$length - 1]) { + throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator."); + } + $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length; + $this->prefixDirsPsr4[$prefix] = (array) $paths; + } elseif ($prepend) { + // Prepend directories for an already registered namespace. + $this->prefixDirsPsr4[$prefix] = array_merge( + (array) $paths, + $this->prefixDirsPsr4[$prefix] + ); + } else { + // Append directories for an already registered namespace. + $this->prefixDirsPsr4[$prefix] = array_merge( + $this->prefixDirsPsr4[$prefix], + (array) $paths + ); + } + } + + /** + * Registers a set of PSR-0 directories for a given prefix, + * replacing any others previously set for this prefix. + * + * @param string $prefix The prefix + * @param array|string $paths The PSR-0 base directories + */ + public function set($prefix, $paths) + { + if (!$prefix) { + $this->fallbackDirsPsr0 = (array) $paths; + } else { + $this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths; + } + } + + /** + * Registers a set of PSR-4 directories for a given namespace, + * replacing any others previously set for this namespace. + * + * @param string $prefix The prefix/namespace, with trailing '\\' + * @param array|string $paths The PSR-4 base directories + * + * @throws \InvalidArgumentException + */ + public function setPsr4($prefix, $paths) + { + if (!$prefix) { + $this->fallbackDirsPsr4 = (array) $paths; + } else { + $length = strlen($prefix); + if ('\\' !== $prefix[$length - 1]) { + throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator."); + } + $this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length; + $this->prefixDirsPsr4[$prefix] = (array) $paths; + } + } + + /** + * Turns on searching the include path for class files. + * + * @param bool $useIncludePath + */ + public function setUseIncludePath($useIncludePath) + { + $this->useIncludePath = $useIncludePath; + } + + /** + * Can be used to check if the autoloader uses the include path to check + * for classes. + * + * @return bool + */ + public function getUseIncludePath() + { + return $this->useIncludePath; + } + + /** + * Turns off searching the prefix and fallback directories for classes + * that have not been registered with the class map. + * + * @param bool $classMapAuthoritative + */ + public function setClassMapAuthoritative($classMapAuthoritative) + { + $this->classMapAuthoritative = $classMapAuthoritative; + } + + /** + * Should class lookup fail if not found in the current class map? + * + * @return bool + */ + public function isClassMapAuthoritative() + { + return $this->classMapAuthoritative; + } + + /** + * APCu prefix to use to cache found/not-found classes, if the extension is enabled. + * + * @param string|null $apcuPrefix + */ + public function setApcuPrefix($apcuPrefix) + { + $this->apcuPrefix = function_exists('apcu_fetch') && ini_get('apc.enabled') ? $apcuPrefix : null; + } + + /** + * The APCu prefix in use, or null if APCu caching is not enabled. + * + * @return string|null + */ + public function getApcuPrefix() + { + return $this->apcuPrefix; + } + + /** + * Registers this instance as an autoloader. + * + * @param bool $prepend Whether to prepend the autoloader or not + */ + public function register($prepend = false) + { + spl_autoload_register(array($this, 'loadClass'), true, $prepend); + } + + /** + * Unregisters this instance as an autoloader. + */ + public function unregister() + { + spl_autoload_unregister(array($this, 'loadClass')); + } + + /** + * Loads the given class or interface. + * + * @param string $class The name of the class + * @return bool|null True if loaded, null otherwise + */ + public function loadClass($class) + { + if ($file = $this->findFile($class)) { + includeFile($file); + + return true; + } + } + + /** + * Finds the path to the file where the class is defined. + * + * @param string $class The name of the class + * + * @return string|false The path if found, false otherwise + */ + public function findFile($class) + { + // class map lookup + if (isset($this->classMap[$class])) { + return $this->classMap[$class]; + } + if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) { + return false; + } + if (null !== $this->apcuPrefix) { + $file = apcu_fetch($this->apcuPrefix.$class, $hit); + if ($hit) { + return $file; + } + } + + $file = $this->findFileWithExtension($class, '.php'); + + // Search for Hack files if we are running on HHVM + if (false === $file && defined('HHVM_VERSION')) { + $file = $this->findFileWithExtension($class, '.hh'); + } + + if (null !== $this->apcuPrefix) { + apcu_add($this->apcuPrefix.$class, $file); + } + + if (false === $file) { + // Remember that this class does not exist. + $this->missingClasses[$class] = true; + } + + return $file; + } + + private function findFileWithExtension($class, $ext) + { + // PSR-4 lookup + $logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext; + + $first = $class[0]; + if (isset($this->prefixLengthsPsr4[$first])) { + $subPath = $class; + while (false !== $lastPos = strrpos($subPath, '\\')) { + $subPath = substr($subPath, 0, $lastPos); + $search = $subPath.'\\'; + if (isset($this->prefixDirsPsr4[$search])) { + $pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1); + foreach ($this->prefixDirsPsr4[$search] as $dir) { + if (file_exists($file = $dir . $pathEnd)) { + return $file; + } + } + } + } + } + + // PSR-4 fallback dirs + foreach ($this->fallbackDirsPsr4 as $dir) { + if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) { + return $file; + } + } + + // PSR-0 lookup + if (false !== $pos = strrpos($class, '\\')) { + // namespaced class name + $logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1) + . strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR); + } else { + // PEAR-like class name + $logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext; + } + + if (isset($this->prefixesPsr0[$first])) { + foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) { + if (0 === strpos($class, $prefix)) { + foreach ($dirs as $dir) { + if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) { + return $file; + } + } + } + } + } + + // PSR-0 fallback dirs + foreach ($this->fallbackDirsPsr0 as $dir) { + if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) { + return $file; + } + } + + // PSR-0 include paths. + if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) { + return $file; + } + + return false; + } +} + +/** + * Scope isolated include. + * + * Prevents access to $this/self from included files. + */ +function includeFile($file) +{ + include $file; +} diff --git a/plugins/langswitcher/vendor/composer/LICENSE b/plugins/langswitcher/vendor/composer/LICENSE new file mode 100644 index 0000000..f27399a --- /dev/null +++ b/plugins/langswitcher/vendor/composer/LICENSE @@ -0,0 +1,21 @@ + +Copyright (c) Nils Adermann, Jordi Boggiano + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is furnished +to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. + diff --git a/plugins/langswitcher/vendor/composer/autoload_classmap.php b/plugins/langswitcher/vendor/composer/autoload_classmap.php new file mode 100644 index 0000000..015272b --- /dev/null +++ b/plugins/langswitcher/vendor/composer/autoload_classmap.php @@ -0,0 +1,10 @@ + $baseDir . '/langswitcher.php', +); diff --git a/plugins/langswitcher/vendor/composer/autoload_namespaces.php b/plugins/langswitcher/vendor/composer/autoload_namespaces.php new file mode 100644 index 0000000..b7fc012 --- /dev/null +++ b/plugins/langswitcher/vendor/composer/autoload_namespaces.php @@ -0,0 +1,9 @@ += 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded()); + if ($useStaticLoader) { + require_once __DIR__ . '/autoload_static.php'; + + call_user_func(\Composer\Autoload\ComposerStaticInitc810fb4e9d827a69b99d6583ac14140c::getInitializer($loader)); + } else { + $map = require __DIR__ . '/autoload_namespaces.php'; + foreach ($map as $namespace => $path) { + $loader->set($namespace, $path); + } + + $map = require __DIR__ . '/autoload_psr4.php'; + foreach ($map as $namespace => $path) { + $loader->setPsr4($namespace, $path); + } + + $classMap = require __DIR__ . '/autoload_classmap.php'; + if ($classMap) { + $loader->addClassMap($classMap); + } + } + + $loader->register(true); + + return $loader; + } +} diff --git a/plugins/langswitcher/vendor/composer/autoload_static.php b/plugins/langswitcher/vendor/composer/autoload_static.php new file mode 100644 index 0000000..19ecc0a --- /dev/null +++ b/plugins/langswitcher/vendor/composer/autoload_static.php @@ -0,0 +1,20 @@ + __DIR__ . '/../..' . '/langswitcher.php', + ); + + public static function getInitializer(ClassLoader $loader) + { + return \Closure::bind(function () use ($loader) { + $loader->classMap = ComposerStaticInitc810fb4e9d827a69b99d6583ac14140c::$classMap; + + }, null, ClassLoader::class); + } +} diff --git a/plugins/langswitcher/vendor/composer/installed.json b/plugins/langswitcher/vendor/composer/installed.json new file mode 100644 index 0000000..fe51488 --- /dev/null +++ b/plugins/langswitcher/vendor/composer/installed.json @@ -0,0 +1 @@ +[]