diff --git a/composer.lock b/composer.lock index 63e579f75..98d02f71e 100644 --- a/composer.lock +++ b/composer.lock @@ -1734,16 +1734,16 @@ }, { "name": "symfony/config", - "version": "v5.4.26", + "version": "v5.4.31", "source": { "type": "git", "url": "https://github.com/symfony/config.git", - "reference": "8109892f27beed9252bd1f1c1880aeb4ad842650" + "reference": "dd5ea39de228813aba0c23c3a4153da2a4cf3cd9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/config/zipball/8109892f27beed9252bd1f1c1880aeb4ad842650", - "reference": "8109892f27beed9252bd1f1c1880aeb4ad842650", + "url": "https://api.github.com/repos/symfony/config/zipball/dd5ea39de228813aba0c23c3a4153da2a4cf3cd9", + "reference": "dd5ea39de228813aba0c23c3a4153da2a4cf3cd9", "shasum": "" }, "require": { @@ -1793,7 +1793,7 @@ "description": "Helps you find, load, combine, autofill and validate configuration values of any kind", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/config/tree/v5.4.26" + "source": "https://github.com/symfony/config/tree/v5.4.31" }, "funding": [ { @@ -1809,20 +1809,20 @@ "type": "tidelift" } ], - "time": "2023-07-19T20:21:11+00:00" + "time": "2023-11-09T08:22:43+00:00" }, { "name": "symfony/console", - "version": "v5.4.28", + "version": "v5.4.31", "source": { "type": "git", "url": "https://github.com/symfony/console.git", - "reference": "f4f71842f24c2023b91237c72a365306f3c58827" + "reference": "11ac5f154e0e5c4c77af83ad11ead9165280b92a" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/console/zipball/f4f71842f24c2023b91237c72a365306f3c58827", - "reference": "f4f71842f24c2023b91237c72a365306f3c58827", + "url": "https://api.github.com/repos/symfony/console/zipball/11ac5f154e0e5c4c77af83ad11ead9165280b92a", + "reference": "11ac5f154e0e5c4c77af83ad11ead9165280b92a", "shasum": "" }, "require": { @@ -1892,7 +1892,7 @@ "terminal" ], "support": { - "source": "https://github.com/symfony/console/tree/v5.4.28" + "source": "https://github.com/symfony/console/tree/v5.4.31" }, "funding": [ { @@ -1908,7 +1908,7 @@ "type": "tidelift" } ], - "time": "2023-08-07T06:12:30+00:00" + "time": "2023-10-31T07:58:33+00:00" }, { "name": "symfony/css-selector", @@ -3153,16 +3153,16 @@ }, { "name": "symfony/serializer", - "version": "v5.4.30", + "version": "v5.4.31", "source": { "type": "git", "url": "https://github.com/symfony/serializer.git", - "reference": "ceadb4e08830e69738d313b667cfb426269f67f6" + "reference": "15574cfa408a6082b6d66c2b6922f95db6cab26d" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/serializer/zipball/ceadb4e08830e69738d313b667cfb426269f67f6", - "reference": "ceadb4e08830e69738d313b667cfb426269f67f6", + "url": "https://api.github.com/repos/symfony/serializer/zipball/15574cfa408a6082b6d66c2b6922f95db6cab26d", + "reference": "15574cfa408a6082b6d66c2b6922f95db6cab26d", "shasum": "" }, "require": { @@ -3236,7 +3236,7 @@ "description": "Handles serializing and deserializing data structures, including object graphs, into array structures or other formats like XML and JSON.", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/serializer/tree/v5.4.30" + "source": "https://github.com/symfony/serializer/tree/v5.4.31" }, "funding": [ { @@ -3252,7 +3252,7 @@ "type": "tidelift" } ], - "time": "2023-10-25T18:53:19+00:00" + "time": "2023-10-31T07:58:33+00:00" }, { "name": "symfony/service-contracts", @@ -3339,16 +3339,16 @@ }, { "name": "symfony/string", - "version": "v5.4.29", + "version": "v5.4.31", "source": { "type": "git", "url": "https://github.com/symfony/string.git", - "reference": "e41bdc93def20eaf3bfc1537c4e0a2b0680a152d" + "reference": "2765096c03f39ddf54f6af532166e42aaa05b24b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/string/zipball/e41bdc93def20eaf3bfc1537c4e0a2b0680a152d", - "reference": "e41bdc93def20eaf3bfc1537c4e0a2b0680a152d", + "url": "https://api.github.com/repos/symfony/string/zipball/2765096c03f39ddf54f6af532166e42aaa05b24b", + "reference": "2765096c03f39ddf54f6af532166e42aaa05b24b", "shasum": "" }, "require": { @@ -3405,7 +3405,7 @@ "utf8" ], "support": { - "source": "https://github.com/symfony/string/tree/v5.4.29" + "source": "https://github.com/symfony/string/tree/v5.4.31" }, "funding": [ { @@ -3421,20 +3421,20 @@ "type": "tidelift" } ], - "time": "2023-09-13T11:47:41+00:00" + "time": "2023-11-09T08:19:44+00:00" }, { "name": "symfony/translation", - "version": "v5.4.30", + "version": "v5.4.31", "source": { "type": "git", "url": "https://github.com/symfony/translation.git", - "reference": "8560dc532e4e48d331937532a7cbfd2a9f9f53ce" + "reference": "ba72f72fceddf36f00bd495966b5873f2d17ad8f" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/translation/zipball/8560dc532e4e48d331937532a7cbfd2a9f9f53ce", - "reference": "8560dc532e4e48d331937532a7cbfd2a9f9f53ce", + "url": "https://api.github.com/repos/symfony/translation/zipball/ba72f72fceddf36f00bd495966b5873f2d17ad8f", + "reference": "ba72f72fceddf36f00bd495966b5873f2d17ad8f", "shasum": "" }, "require": { @@ -3502,7 +3502,7 @@ "description": "Provides tools to internationalize your application", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/translation/tree/v5.4.30" + "source": "https://github.com/symfony/translation/tree/v5.4.31" }, "funding": [ { @@ -3518,7 +3518,7 @@ "type": "tidelift" } ], - "time": "2023-10-28T09:19:54+00:00" + "time": "2023-11-03T16:16:43+00:00" }, { "name": "symfony/translation-contracts", @@ -3600,16 +3600,16 @@ }, { "name": "symfony/twig-bridge", - "version": "v5.4.29", + "version": "v5.4.31", "source": { "type": "git", "url": "https://github.com/symfony/twig-bridge.git", - "reference": "8e94856da373b63e7ba69e51a6c4f834d991cd58" + "reference": "fc6ee0a3b672ea12ca1f26592d257bfc7f4ee942" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/twig-bridge/zipball/8e94856da373b63e7ba69e51a6c4f834d991cd58", - "reference": "8e94856da373b63e7ba69e51a6c4f834d991cd58", + "url": "https://api.github.com/repos/symfony/twig-bridge/zipball/fc6ee0a3b672ea12ca1f26592d257bfc7f4ee942", + "reference": "fc6ee0a3b672ea12ca1f26592d257bfc7f4ee942", "shasum": "" }, "require": { @@ -3701,7 +3701,7 @@ "description": "Provides integration for Twig with various Symfony components", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/twig-bridge/tree/v5.4.29" + "source": "https://github.com/symfony/twig-bridge/tree/v5.4.31" }, "funding": [ { @@ -3717,7 +3717,7 @@ "type": "tidelift" } ], - "time": "2023-09-06T21:54:06+00:00" + "time": "2023-11-09T21:19:08+00:00" }, { "name": "symfony/var-dumper", @@ -3810,16 +3810,16 @@ }, { "name": "symfony/yaml", - "version": "v5.4.30", + "version": "v5.4.31", "source": { "type": "git", "url": "https://github.com/symfony/yaml.git", - "reference": "c6980e82a6656f6ebfabfd82f7585794cb122554" + "reference": "f387675d7f5fc4231f7554baa70681f222f73563" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/yaml/zipball/c6980e82a6656f6ebfabfd82f7585794cb122554", - "reference": "c6980e82a6656f6ebfabfd82f7585794cb122554", + "url": "https://api.github.com/repos/symfony/yaml/zipball/f387675d7f5fc4231f7554baa70681f222f73563", + "reference": "f387675d7f5fc4231f7554baa70681f222f73563", "shasum": "" }, "require": { @@ -3865,7 +3865,7 @@ "description": "Loads and dumps YAML files", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/yaml/tree/v5.4.30" + "source": "https://github.com/symfony/yaml/tree/v5.4.31" }, "funding": [ { @@ -3881,7 +3881,7 @@ "type": "tidelift" } ], - "time": "2023-10-27T18:36:14+00:00" + "time": "2023-11-03T14:41:28+00:00" }, { "name": "thecodingmachine/safe", @@ -8531,16 +8531,16 @@ }, { "name": "symfony/dependency-injection", - "version": "v5.4.29", + "version": "v5.4.31", "source": { "type": "git", "url": "https://github.com/symfony/dependency-injection.git", - "reference": "338638ed8c9d5c7fcb136a73f5c7043465ae2f05" + "reference": "eb1bcafa54e00ed218e1b733b8b6ad1c9ff83d20" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/338638ed8c9d5c7fcb136a73f5c7043465ae2f05", - "reference": "338638ed8c9d5c7fcb136a73f5c7043465ae2f05", + "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/eb1bcafa54e00ed218e1b733b8b6ad1c9ff83d20", + "reference": "eb1bcafa54e00ed218e1b733b8b6ad1c9ff83d20", "shasum": "" }, "require": { @@ -8600,7 +8600,7 @@ "description": "Allows you to standardize and centralize the way objects are constructed in your application", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/dependency-injection/tree/v5.4.29" + "source": "https://github.com/symfony/dependency-injection/tree/v5.4.31" }, "funding": [ { @@ -8616,7 +8616,7 @@ "type": "tidelift" } ], - "time": "2023-09-20T06:23:43+00:00" + "time": "2023-10-31T07:58:33+00:00" }, { "name": "symfony/event-dispatcher", diff --git a/docs/3-Templates.md b/docs/3-Templates.md index 53b26a31b..01e2d692a 100644 --- a/docs/3-Templates.md +++ b/docs/3-Templates.md @@ -29,19 +29,42 @@ Cecil is powered by the [Twig](https://twig.symfony.com) template engine, so ple ## Files organization -There is two kinds of templates: _layouts_ and _others templates_. +There is two kinds of templates, **_layouts_** and **_others templates_**: _layouts_ are used to render [pages](2-Content.md#pages), and each of them can [include templates](https://twig.symfony.com/doc/templates.html#including-other-templates). -_Layouts_ are used to render [pages](2-Content.md#pages), and each of them can [include](https://twig.symfony.com/doc/templates.html#including-other-templates) templates. - -_Layouts_ files are stored in the `layouts/` directory and must be named according to the following convention: +Templates files are stored in the `layouts/` directory and must be named according to the following convention: ```plaintext -..twig +layouts/(
/)|.(.).twig ``` -- `` is the name of the layout, the same as the one defined in [front matter](2-Content.md#front-matter) of a page (e.g.: `layout: my-layout`) or the name of a generic layout (i.e.: `index`, `page`, `list`, etc. See below for details) -- `` of the [output](4-Configuration.md#formats) of the generated page (e.g.: `html`, `rss`, `json`, `xml`, etc.) -- `.twig` is the mandatory file extension +`
` (optional) +: The section of the page (e.g.: `blog`). + +`` +: The page type: `home` (or `index`) for _homepage_, `list` for _list_, `page` for _page_, etc. (See [_Lookup rules_](#lookup-rules) for details). + +`` (optional) +: The custom layout name defined in the [front matter](2-Content.md#front-matter) of the page (e.g.: `layout: my-layout`). + +`` (optional) +: The language of the page (e.g.: `fr`). + +`` +: The [output format](4-Configuration.md#formats) of the rendered page (e.g.: `html`, `rss`, `json`, `xml`, etc.). + +".twig" +: The mandatory Twig file extension. + +_Examples:_ + +```plaintext +layouts/home.html.twig # `type` is "homepage" +layouts/page.html.twig # `type` is "page" +layouts/page.html.fr.twig # `type` is "page" and `language` is "fr" +layouts/my-layout.html.twig # `layout` is "my-layout" +layouts/blog/list.html.twig # `section` is "blog" +layouts/blog/list.rss.twig # `section` is "blog" and `format` is "rss" +``` ```plaintext @@ -53,7 +76,7 @@ _Layouts_ files are stored in the `layouts/` directory and must be named accordi | ├─ list.rss.twig <- Used by types "homepage", "section" and "term", for RSS output format | ├─ page.html.twig <- Used by type "page" | ├─ ... -| ├─ _default <- Default layouts, that can be easily extended by "root" layouts +| ├─ _default <- Default layouts, that can be easily extended | | ├─ list.html.twig | | ├─ page.html.twig | | └─ ... @@ -68,14 +91,15 @@ _Layouts_ files are stored in the `layouts/` directory and must be named accordi ## Lookup rules -In most of cases **you don’t need to specify a layout name** (in the [front matter](2-Content.md#front-matter) of the page) : **Cecil selects the most appropriate layout**, according to the page _type_. +In most of cases **you don’t need to specify the layout**: Cecil selects the most appropriate layout, according to the page _type_. -For example, the HTML output of _home page_ will be rendered in the following order: +For example, the HTML output of _home page_ (`index.md`) will be rendered: -1. with `my-layout.html.twig` if the `layout` variable is set to "my-layout" in the front matter of `index.md` -2. if not, with `index.html.twig` if the file exists -3. if not, with `list.html.twig` if the file exists -4. etc. +1. with `my-layout.html.twig` if the `layout` variable is set to "my-layout" (in the front matter) +2. if not, with `home.html.twig` if the file exists +3. if not, with `index.html.twig` if the file exists +4. if not, with `list.html.twig` if the file exists +5. etc. All rules are detailed below, for each page type, in the priority order. @@ -83,10 +107,12 @@ All rules are detailed below, for each page type, in the priority order. 1. `..twig` 2. `index..twig` -3. `list..twig` -4. `_default/index..twig` -5. `_default/list..twig` -6. `_default/page..twig` +3. `home..twig` +4. `list..twig` +5. `_default/index..twig` +6. `_default/home..twig` +7. `_default/list..twig` +8. `_default/page..twig` ### Type _page_ @@ -94,15 +120,17 @@ All rules are detailed below, for each page type, in the priority order. 2. `..twig` 3. `
/page..twig` 4. `page..twig` -5. `_default/page..twig` +5. `_default/..twig` +6. `_default/page..twig` ### Type _section_ 1. `..twig` -2. `
/list..twig` -3. `section/
..twig` -4. `_default/section..twig` -5. `_default/list..twig` +2. `
/index..twig` +3. `
/list..twig` +4. `section/
..twig` +5. `_default/section..twig` +6. `_default/list..twig` ### Type _vocabulary_ diff --git a/resources/layouts/404.html.twig b/resources/layouts/_default/404.html.twig similarity index 62% rename from resources/layouts/404.html.twig rename to resources/layouts/_default/404.html.twig index 962d94ed5..f8d265a58 100644 --- a/resources/layouts/404.html.twig +++ b/resources/layouts/_default/404.html.twig @@ -1,4 +1,4 @@ -{% extends '_default/page.html.twig' %} +{% extends ['page.html.twig', '_default/page.html.twig'] %} {%- block content ~%} {% trans %}Page not found.{% endtrans %} diff --git a/resources/layouts/404.json.twig b/resources/layouts/_default/404.json.twig similarity index 100% rename from resources/layouts/404.json.twig rename to resources/layouts/_default/404.json.twig diff --git a/resources/layouts/feed.xsl.twig b/resources/layouts/_default/feed.xsl.twig similarity index 100% rename from resources/layouts/feed.xsl.twig rename to resources/layouts/_default/feed.xsl.twig diff --git a/resources/layouts/_default/list.html.twig b/resources/layouts/_default/list.html.twig index ee2cd0db3..f203a43bb 100644 --- a/resources/layouts/_default/list.html.twig +++ b/resources/layouts/_default/list.html.twig @@ -9,7 +9,7 @@ {%- set pages = page.paginator.pages -%} {% endif %} -{% extends '_default/page.html.twig' %} +{% extends ['page.html.twig', '_default/page.html.twig'] %} {%- block content ~%}
diff --git a/resources/layouts/_default/list.json.twig b/resources/layouts/_default/list.json.twig index dc58be921..6cf1ac885 100644 --- a/resources/layouts/_default/list.json.twig +++ b/resources/layouts/_default/list.json.twig @@ -11,4 +11,4 @@ {% set items = pages %} -{% extends '_default/page.json.twig' %} \ No newline at end of file +{% extends ['page.json.twig', '_default/page.json.twig'] %} \ No newline at end of file diff --git a/resources/layouts/redirect.html.twig b/resources/layouts/_default/redirect.html.twig similarity index 100% rename from resources/layouts/redirect.html.twig rename to resources/layouts/_default/redirect.html.twig diff --git a/resources/layouts/robots.txt.twig b/resources/layouts/_default/robots.txt.twig similarity index 100% rename from resources/layouts/robots.txt.twig rename to resources/layouts/_default/robots.txt.twig diff --git a/resources/layouts/sitemap.xml.twig b/resources/layouts/_default/sitemap.xml.twig similarity index 100% rename from resources/layouts/sitemap.xml.twig rename to resources/layouts/_default/sitemap.xml.twig diff --git a/resources/layouts/_default/vocabulary.html.twig b/resources/layouts/_default/vocabulary.html.twig index 845105e5a..1596d0bd2 100644 --- a/resources/layouts/_default/vocabulary.html.twig +++ b/resources/layouts/_default/vocabulary.html.twig @@ -1,4 +1,4 @@ -{% extends '_default/page.html.twig' %} +{% extends ['page.html.twig', '_default/page.html.twig'] %} {%- block content ~%} {{- parent() ~}} diff --git a/src/Renderer/Layout.php b/src/Renderer/Layout.php index 229177c80..d1f8b0171 100644 --- a/src/Renderer/Layout.php +++ b/src/Renderer/Layout.php @@ -36,19 +36,19 @@ public static function finder(CollectionPage $page, string $format, Config $conf $layout = 'unknown'; // what layouts, in what format, could be use for the page? - $layouts = self::fallback($page, $format); + $layouts = self::fallback($page, $format, $config); // take the first available layout foreach ($layouts as $layout) { $layout = Util::joinFile($layout); - // is it in layouts/ dir? + // is it in `layouts/` dir? if (Util\File::getFS()->exists(Util::joinFile($config->getLayoutsPath(), $layout))) { return [ 'scope' => 'site', 'file' => $layout, ]; } - // is it in /layouts/ dir? + // is it in `/layouts/` dir? if ($config->hasTheme()) { $themes = $config->getTheme(); foreach ($themes as $theme) { @@ -60,7 +60,7 @@ public static function finder(CollectionPage $page, string $format, Config $conf } } } - // is it in resources/layouts/ dir? + // is it in `resources/layouts/` dir? if (Util\File::getFS()->exists(Util::joinPath($config->getInternalLayoutsPath(), $layout))) { return [ 'scope' => 'cecil', @@ -77,7 +77,7 @@ public static function finder(CollectionPage $page, string $format, Config $conf * * @see finder() */ - protected static function fallback(CollectionPage $page, string $format): array + protected static function fallback(CollectionPage $page, string $format, Config $config): array { $ext = self::EXT; @@ -89,42 +89,33 @@ protected static function fallback(CollectionPage $page, string $format): array $layouts = [ // "$layout.$format.$ext", "index.$format.$ext", + "home.$format.$ext", "list.$format.$ext", "_default/index.$format.$ext", + "_default/home.$format.$ext", "_default/list.$format.$ext", "_default/page.$format.$ext", ]; if ($page->hasVariable('layout')) { - $layouts = array_merge( - [sprintf('%s.%s.%s', $layout, $format, $ext)], - $layouts - ); + $layouts = array_merge(["$layout.$format.$ext"], $layouts); } break; case PageType::SECTION: $layouts = [ // "$layout.$format.$ext", + // "$section/index.$format.$ext", // "$section/list.$format.$ext", // "section/$section.$format.$ext", "_default/section.$format.$ext", "_default/list.$format.$ext", ]; if ($page->getPath()) { - $section = $page->getSection(); - $layouts = array_merge( - [sprintf('section/%s.%s.%s', $section, $format, $ext)], - $layouts - ); - $layouts = array_merge( - [sprintf('%s/list.%s.%s', $section, $format, $ext)], - $layouts - ); + $layouts = array_merge(["section/{$page->getSection()}.$format.$ext"], $layouts); + $layouts = array_merge(["{$page->getSection()}/list.$format.$ext"], $layouts); + $layouts = array_merge(["{$page->getSection()}/index.$format.$ext"], $layouts); } if ($page->hasVariable('layout')) { - $layouts = array_merge( - [sprintf('%s.%s.%s', $layout, $format, $ext)], - $layouts - ); + $layouts = array_merge(["$layout.$format.$ext"], $layouts); } break; case PageType::VOCABULARY: @@ -133,10 +124,7 @@ protected static function fallback(CollectionPage $page, string $format): array "_default/vocabulary.$format.$ext", // e.g.: _default/vocabulary.html.twig ]; if ($page->hasVariable('plural')) { - $layouts = array_merge( - [sprintf('taxonomy/%s.%s.%s', $page->getVariable('plural'), $format, $ext)], - $layouts - ); + $layouts = array_merge(["taxonomy/{$page->getVariable('plural')}.$format.$ext"], $layouts); } break; case PageType::TERM: @@ -147,16 +135,10 @@ protected static function fallback(CollectionPage $page, string $format): array "_default/list.$format.$ext", // e.g.: _default/list.html.twig ]; if ($page->hasVariable('term')) { - $layouts = array_merge( - [sprintf('taxonomy/%s.%s.%s', $page->getVariable('term'), $format, $ext)], - $layouts - ); + $layouts = array_merge(["taxonomy/{$page->getVariable('term')}.$format.$ext"], $layouts); } if ($page->hasVariable('singular')) { - $layouts = array_merge( - [sprintf('taxonomy/%s.%s.%s', $page->getVariable('singular'), $format, $ext)], - $layouts - ); + $layouts = array_merge(["taxonomy/{$page->getVariable('singular')}.$format.$ext"], $layouts); } break; default: @@ -165,32 +147,31 @@ protected static function fallback(CollectionPage $page, string $format): array // "$layout.$format.$ext", // "$section/page.$format.$ext", // "page.$format.$ext", + // "_default/$layout.$format.$ext", "_default/page.$format.$ext", ]; - $layouts = array_merge( - ["page.$format.$ext"], - $layouts - ); + if ($page->hasVariable('layout')) { + $layouts = array_merge(["_default/$layout.$format.$ext"], $layouts); + } + $layouts = array_merge(["page.$format.$ext"], $layouts); if ($page->getSection()) { - $layouts = array_merge( - [sprintf('%s/page.%s.%s', $page->getSection(), $format, $ext)], - $layouts - ); + $layouts = array_merge(["{$page->getSection()}/page.$format.$ext"], $layouts); } if ($page->hasVariable('layout')) { - $layouts = array_merge( - [sprintf('%s.%s.%s', $layout, $format, $ext)], - $layouts - ); + $layouts = array_merge(["$layout.$format.$ext"], $layouts); if ($page->getSection()) { - $layouts = array_merge( - [sprintf('%s/%s.%s.%s', $page->getSection(), $layout, $format, $ext)], - $layouts - ); + $layouts = array_merge(["{$page->getSection()}/$layout.$format.$ext"], $layouts); } } } + // add localized layouts + if ($page->getVariable('language') !== $config->getLanguageDefault()) { + foreach ($layouts as $key => $value) { + $layouts = array_merge(\array_slice($layouts, 0, $key), [str_replace(".$ext", ".{$page->getVariable('language')}.$ext", $value)], \array_slice($layouts, $key)); + } + } + return $layouts; } }