Start adding some tests for building multilingual sites
This commit is contained in:
parent
779511ae43
commit
7313b41f4d
|
@ -861,6 +861,11 @@ impl Site {
|
||||||
pub fn render_section(&self, section: &Section, render_pages: bool) -> Result<()> {
|
pub fn render_section(&self, section: &Section, render_pages: bool) -> Result<()> {
|
||||||
ensure_directory_exists(&self.output_path)?;
|
ensure_directory_exists(&self.output_path)?;
|
||||||
let mut output_path = self.output_path.clone();
|
let mut output_path = self.output_path.clone();
|
||||||
|
|
||||||
|
if let Some(ref lang) = section.lang {
|
||||||
|
output_path.push(lang);
|
||||||
|
}
|
||||||
|
|
||||||
for component in §ion.file.components {
|
for component in §ion.file.components {
|
||||||
output_path.push(component);
|
output_path.push(component);
|
||||||
|
|
||||||
|
|
66
components/site/tests/common.rs
Normal file
66
components/site/tests/common.rs
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
extern crate tempfile;
|
||||||
|
extern crate site;
|
||||||
|
|
||||||
|
use std::env;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
use self::site::Site;
|
||||||
|
use self::tempfile::{tempdir, TempDir};
|
||||||
|
|
||||||
|
// 2 helper macros to make all the build testing more bearable
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! file_exists {
|
||||||
|
($root: expr, $path: expr) => {{
|
||||||
|
let mut path = $root.clone();
|
||||||
|
for component in $path.split("/") {
|
||||||
|
path = path.join(component);
|
||||||
|
}
|
||||||
|
std::path::Path::new(&path).exists()
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! file_contains {
|
||||||
|
($root: expr, $path: expr, $text: expr) => {{
|
||||||
|
use std::io::prelude::*;
|
||||||
|
let mut path = $root.clone();
|
||||||
|
for component in $path.split("/") {
|
||||||
|
path = path.join(component);
|
||||||
|
}
|
||||||
|
let mut file = std::fs::File::open(&path).unwrap();
|
||||||
|
let mut s = String::new();
|
||||||
|
file.read_to_string(&mut s).unwrap();
|
||||||
|
println!("{}", s);
|
||||||
|
s.contains($text)
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// We return the tmpdir otherwise it would get out of scope and be deleted
|
||||||
|
/// The tests can ignore it if they dont need it by prefixing it with a `_`
|
||||||
|
pub fn build_site(name: &str) -> (Site, TempDir, PathBuf) {
|
||||||
|
let mut path = env::current_dir().unwrap().parent().unwrap().parent().unwrap().to_path_buf();
|
||||||
|
path.push(name);
|
||||||
|
let mut site = Site::new(&path, "config.toml").unwrap();
|
||||||
|
site.load().unwrap();
|
||||||
|
let tmp_dir = tempdir().expect("create temp dir");
|
||||||
|
let public = &tmp_dir.path().join("public");
|
||||||
|
site.set_output_path(&public);
|
||||||
|
site.build().unwrap();
|
||||||
|
(site, tmp_dir, public.clone())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Same as `build_site` but has a hook to setup some config options
|
||||||
|
pub fn build_site_with_setup<F>(name: &str, mut setup_cb: F) -> (Site, TempDir, PathBuf) where F: FnMut(Site) -> (Site, bool) {
|
||||||
|
let mut path = env::current_dir().unwrap().parent().unwrap().parent().unwrap().to_path_buf();
|
||||||
|
path.push(name);
|
||||||
|
let site = Site::new(&path, "config.toml").unwrap();
|
||||||
|
let (mut site, needs_loading) = setup_cb(site);
|
||||||
|
if needs_loading {
|
||||||
|
site.load().unwrap();
|
||||||
|
}
|
||||||
|
let tmp_dir = tempdir().expect("create temp dir");
|
||||||
|
let public = &tmp_dir.path().join("public");
|
||||||
|
site.set_output_path(&public);
|
||||||
|
site.build().unwrap();
|
||||||
|
(site, tmp_dir, public.clone())
|
||||||
|
}
|
|
@ -1,16 +1,14 @@
|
||||||
extern crate config;
|
extern crate config;
|
||||||
extern crate site;
|
extern crate site;
|
||||||
extern crate tempfile;
|
mod common;
|
||||||
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::fs::File;
|
|
||||||
use std::io::prelude::*;
|
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
|
||||||
use config::Taxonomy;
|
use config::Taxonomy;
|
||||||
use site::Site;
|
use site::Site;
|
||||||
use tempfile::tempdir;
|
use common::{build_site, build_site_with_setup};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn can_parse_site() {
|
fn can_parse_site() {
|
||||||
|
@ -92,41 +90,9 @@ fn can_parse_site() {
|
||||||
assert_eq!(prog_section.pages.len(), 2);
|
assert_eq!(prog_section.pages.len(), 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 2 helper macros to make all the build testing more bearable
|
|
||||||
macro_rules! file_exists {
|
|
||||||
($root: expr, $path: expr) => {{
|
|
||||||
let mut path = $root.clone();
|
|
||||||
for component in $path.split("/") {
|
|
||||||
path = path.join(component);
|
|
||||||
}
|
|
||||||
Path::new(&path).exists()
|
|
||||||
}};
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! file_contains {
|
|
||||||
($root: expr, $path: expr, $text: expr) => {{
|
|
||||||
let mut path = $root.clone();
|
|
||||||
for component in $path.split("/") {
|
|
||||||
path = path.join(component);
|
|
||||||
}
|
|
||||||
let mut file = File::open(&path).unwrap();
|
|
||||||
let mut s = String::new();
|
|
||||||
file.read_to_string(&mut s).unwrap();
|
|
||||||
println!("{}", s);
|
|
||||||
s.contains($text)
|
|
||||||
}};
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn can_build_site_without_live_reload() {
|
fn can_build_site_without_live_reload() {
|
||||||
let mut path = env::current_dir().unwrap().parent().unwrap().parent().unwrap().to_path_buf();
|
let (_, _tmp_dir, public) = build_site("test_site");
|
||||||
path.push("test_site");
|
|
||||||
let mut site = Site::new(&path, "config.toml").unwrap();
|
|
||||||
site.load().unwrap();
|
|
||||||
let tmp_dir = tempdir().expect("create temp dir");
|
|
||||||
let public = &tmp_dir.path().join("public");
|
|
||||||
site.set_output_path(&public);
|
|
||||||
site.build().unwrap();
|
|
||||||
|
|
||||||
assert!(&public.exists());
|
assert!(&public.exists());
|
||||||
assert!(file_exists!(public, "index.html"));
|
assert!(file_exists!(public, "index.html"));
|
||||||
|
@ -222,17 +188,12 @@ fn can_build_site_without_live_reload() {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn can_build_site_with_live_reload() {
|
fn can_build_site_with_live_reload() {
|
||||||
let mut path = env::current_dir().unwrap().parent().unwrap().parent().unwrap().to_path_buf();
|
let (_, _tmp_dir, public) = build_site_with_setup("test_site", |mut site| {
|
||||||
path.push("test_site");
|
site.enable_live_reload(1000);
|
||||||
let mut site = Site::new(&path, "config.toml").unwrap();
|
(site, true)
|
||||||
site.load().unwrap();
|
});
|
||||||
let tmp_dir = tempdir().expect("create temp dir");
|
|
||||||
let public = &tmp_dir.path().join("public");
|
|
||||||
site.set_output_path(&public);
|
|
||||||
site.enable_live_reload(1000);
|
|
||||||
site.build().unwrap();
|
|
||||||
|
|
||||||
assert!(Path::new(&public).exists());
|
assert!(&public.exists());
|
||||||
|
|
||||||
assert!(file_exists!(public, "index.html"));
|
assert!(file_exists!(public, "index.html"));
|
||||||
assert!(file_exists!(public, "sitemap.xml"));
|
assert!(file_exists!(public, "sitemap.xml"));
|
||||||
|
@ -271,28 +232,23 @@ fn can_build_site_with_live_reload() {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn can_build_site_with_taxonomies() {
|
fn can_build_site_with_taxonomies() {
|
||||||
let mut path = env::current_dir().unwrap().parent().unwrap().parent().unwrap().to_path_buf();
|
let (site, _tmp_dir, public) = build_site_with_setup("test_site", |mut site| {
|
||||||
path.push("test_site");
|
site.load().unwrap();
|
||||||
let mut site = Site::new(&path, "config.toml").unwrap();
|
for (i, (_, page)) in site.library.pages_mut().iter_mut().enumerate() {
|
||||||
site.load().unwrap();
|
page.meta.taxonomies = {
|
||||||
|
let mut taxonomies = HashMap::new();
|
||||||
|
taxonomies.insert(
|
||||||
|
"categories".to_string(),
|
||||||
|
vec![if i % 2 == 0 { "A" } else { "B" }.to_string()],
|
||||||
|
);
|
||||||
|
taxonomies
|
||||||
|
};
|
||||||
|
}
|
||||||
|
site.populate_taxonomies().unwrap();
|
||||||
|
(site, false)
|
||||||
|
});
|
||||||
|
|
||||||
for (i, (_, page)) in site.library.pages_mut().iter_mut().enumerate() {
|
assert!(&public.exists());
|
||||||
page.meta.taxonomies = {
|
|
||||||
let mut taxonomies = HashMap::new();
|
|
||||||
taxonomies.insert(
|
|
||||||
"categories".to_string(),
|
|
||||||
vec![if i % 2 == 0 { "A" } else { "B" }.to_string()],
|
|
||||||
);
|
|
||||||
taxonomies
|
|
||||||
};
|
|
||||||
}
|
|
||||||
site.populate_taxonomies().unwrap();
|
|
||||||
let tmp_dir = tempdir().expect("create temp dir");
|
|
||||||
let public = &tmp_dir.path().join("public");
|
|
||||||
site.set_output_path(&public);
|
|
||||||
site.build().unwrap();
|
|
||||||
|
|
||||||
assert!(Path::new(&public).exists());
|
|
||||||
assert_eq!(site.taxonomies.len(), 1);
|
assert_eq!(site.taxonomies.len(), 1);
|
||||||
|
|
||||||
assert!(file_exists!(public, "index.html"));
|
assert!(file_exists!(public, "index.html"));
|
||||||
|
@ -340,15 +296,7 @@ fn can_build_site_with_taxonomies() {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn can_build_site_and_insert_anchor_links() {
|
fn can_build_site_and_insert_anchor_links() {
|
||||||
let mut path = env::current_dir().unwrap().parent().unwrap().parent().unwrap().to_path_buf();
|
let (_, _tmp_dir, public) = build_site("test_site");
|
||||||
path.push("test_site");
|
|
||||||
let mut site = Site::new(&path, "config.toml").unwrap();
|
|
||||||
site.load().unwrap();
|
|
||||||
|
|
||||||
let tmp_dir = tempdir().expect("create temp dir");
|
|
||||||
let public = &tmp_dir.path().join("public");
|
|
||||||
site.set_output_path(&public);
|
|
||||||
site.build().unwrap();
|
|
||||||
|
|
||||||
assert!(Path::new(&public).exists());
|
assert!(Path::new(&public).exists());
|
||||||
// anchor link inserted
|
// anchor link inserted
|
||||||
|
@ -361,23 +309,19 @@ fn can_build_site_and_insert_anchor_links() {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn can_build_site_with_pagination_for_section() {
|
fn can_build_site_with_pagination_for_section() {
|
||||||
let mut path = env::current_dir().unwrap().parent().unwrap().parent().unwrap().to_path_buf();
|
let (_, _tmp_dir, public) = build_site_with_setup("test_site", |mut site| {
|
||||||
path.push("test_site");
|
site.load().unwrap();
|
||||||
let mut site = Site::new(&path, "config.toml").unwrap();
|
for (_, section) in site.library.sections_mut() {
|
||||||
site.load().unwrap();
|
if section.is_index() {
|
||||||
for (_, section) in site.library.sections_mut() {
|
continue;
|
||||||
if section.is_index() {
|
}
|
||||||
continue;
|
section.meta.paginate_by = Some(2);
|
||||||
|
section.meta.template = Some("section_paginated.html".to_string());
|
||||||
}
|
}
|
||||||
section.meta.paginate_by = Some(2);
|
(site, false)
|
||||||
section.meta.template = Some("section_paginated.html".to_string());
|
});
|
||||||
}
|
|
||||||
let tmp_dir = tempdir().expect("create temp dir");
|
|
||||||
let public = &tmp_dir.path().join("public");
|
|
||||||
site.set_output_path(&public);
|
|
||||||
site.build().unwrap();
|
|
||||||
|
|
||||||
assert!(Path::new(&public).exists());
|
assert!(&public.exists());
|
||||||
|
|
||||||
assert!(file_exists!(public, "index.html"));
|
assert!(file_exists!(public, "index.html"));
|
||||||
assert!(file_exists!(public, "sitemap.xml"));
|
assert!(file_exists!(public, "sitemap.xml"));
|
||||||
|
@ -478,21 +422,17 @@ fn can_build_site_with_pagination_for_section() {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn can_build_site_with_pagination_for_index() {
|
fn can_build_site_with_pagination_for_index() {
|
||||||
let mut path = env::current_dir().unwrap().parent().unwrap().parent().unwrap().to_path_buf();
|
let (_, _tmp_dir, public) = build_site_with_setup("test_site", |mut site| {
|
||||||
path.push("test_site");
|
site.load().unwrap();
|
||||||
let mut site = Site::new(&path, "config.toml").unwrap();
|
{
|
||||||
site.load().unwrap();
|
let index = site.library.get_section_mut(&site.base_path.join("content").join("_index.md")).unwrap();
|
||||||
{
|
index.meta.paginate_by = Some(2);
|
||||||
let index = site.library.get_section_mut(&path.join("content").join("_index.md")).unwrap();
|
index.meta.template = Some("index_paginated.html".to_string());
|
||||||
index.meta.paginate_by = Some(2);
|
}
|
||||||
index.meta.template = Some("index_paginated.html".to_string());
|
(site, false)
|
||||||
}
|
});
|
||||||
let tmp_dir = tempdir().expect("create temp dir");
|
|
||||||
let public = &tmp_dir.path().join("public");
|
|
||||||
site.set_output_path(&public);
|
|
||||||
site.build().unwrap();
|
|
||||||
|
|
||||||
assert!(Path::new(&public).exists());
|
assert!(&public.exists());
|
||||||
|
|
||||||
assert!(file_exists!(public, "index.html"));
|
assert!(file_exists!(public, "index.html"));
|
||||||
assert!(file_exists!(public, "sitemap.xml"));
|
assert!(file_exists!(public, "sitemap.xml"));
|
||||||
|
@ -530,33 +470,28 @@ fn can_build_site_with_pagination_for_index() {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn can_build_site_with_pagination_for_taxonomy() {
|
fn can_build_site_with_pagination_for_taxonomy() {
|
||||||
let mut path = env::current_dir().unwrap().parent().unwrap().parent().unwrap().to_path_buf();
|
let (_, _tmp_dir, public) = build_site_with_setup("test_site", |mut site| {
|
||||||
path.push("test_site");
|
site.config.taxonomies.push(Taxonomy {
|
||||||
let mut site = Site::new(&path, "config.toml").unwrap();
|
name: "tags".to_string(),
|
||||||
site.config.taxonomies.push(Taxonomy {
|
paginate_by: Some(2),
|
||||||
name: "tags".to_string(),
|
paginate_path: None,
|
||||||
paginate_by: Some(2),
|
rss: true,
|
||||||
paginate_path: None,
|
});
|
||||||
rss: true,
|
site.load().unwrap();
|
||||||
|
|
||||||
|
for (i, (_, page)) in site.library.pages_mut().iter_mut().enumerate() {
|
||||||
|
page.meta.taxonomies = {
|
||||||
|
let mut taxonomies = HashMap::new();
|
||||||
|
taxonomies
|
||||||
|
.insert("tags".to_string(), vec![if i % 2 == 0 { "A" } else { "B" }.to_string()]);
|
||||||
|
taxonomies
|
||||||
|
};
|
||||||
|
}
|
||||||
|
site.populate_taxonomies().unwrap();
|
||||||
|
(site, false)
|
||||||
});
|
});
|
||||||
site.load().unwrap();
|
|
||||||
|
|
||||||
for (i, (_, page)) in site.library.pages_mut().iter_mut().enumerate() {
|
assert!(&public.exists());
|
||||||
page.meta.taxonomies = {
|
|
||||||
let mut taxonomies = HashMap::new();
|
|
||||||
taxonomies
|
|
||||||
.insert("tags".to_string(), vec![if i % 2 == 0 { "A" } else { "B" }.to_string()]);
|
|
||||||
taxonomies
|
|
||||||
};
|
|
||||||
}
|
|
||||||
site.populate_taxonomies().unwrap();
|
|
||||||
|
|
||||||
let tmp_dir = tempdir().expect("create temp dir");
|
|
||||||
let public = &tmp_dir.path().join("public");
|
|
||||||
site.set_output_path(&public);
|
|
||||||
site.build().unwrap();
|
|
||||||
|
|
||||||
assert!(Path::new(&public).exists());
|
|
||||||
|
|
||||||
assert!(file_exists!(public, "index.html"));
|
assert!(file_exists!(public, "index.html"));
|
||||||
assert!(file_exists!(public, "sitemap.xml"));
|
assert!(file_exists!(public, "sitemap.xml"));
|
||||||
|
@ -610,16 +545,9 @@ fn can_build_site_with_pagination_for_taxonomy() {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn can_build_rss_feed() {
|
fn can_build_rss_feed() {
|
||||||
let mut path = env::current_dir().unwrap().parent().unwrap().parent().unwrap().to_path_buf();
|
let (_, _tmp_dir, public) = build_site("test_site");
|
||||||
path.push("test_site");
|
|
||||||
let mut site = Site::new(&path, "config.toml").unwrap();
|
|
||||||
site.load().unwrap();
|
|
||||||
let tmp_dir = tempdir().expect("create temp dir");
|
|
||||||
let public = &tmp_dir.path().join("public");
|
|
||||||
site.set_output_path(&public);
|
|
||||||
site.build().unwrap();
|
|
||||||
|
|
||||||
assert!(Path::new(&public).exists());
|
assert!(&public.exists());
|
||||||
assert!(file_exists!(public, "rss.xml"));
|
assert!(file_exists!(public, "rss.xml"));
|
||||||
// latest article is posts/extra-syntax.md
|
// latest article is posts/extra-syntax.md
|
||||||
assert!(file_contains!(public, "rss.xml", "Extra Syntax"));
|
assert!(file_contains!(public, "rss.xml", "Extra Syntax"));
|
||||||
|
@ -629,15 +557,10 @@ fn can_build_rss_feed() {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn can_build_search_index() {
|
fn can_build_search_index() {
|
||||||
let mut path = env::current_dir().unwrap().parent().unwrap().parent().unwrap().to_path_buf();
|
let (_, _tmp_dir, public) = build_site_with_setup("test_site", |mut site| {
|
||||||
path.push("test_site");
|
site.config.build_search_index = true;
|
||||||
let mut site = Site::new(&path, "config.toml").unwrap();
|
(site, true)
|
||||||
site.load().unwrap();
|
});
|
||||||
site.config.build_search_index = true;
|
|
||||||
let tmp_dir = tempdir().expect("create temp dir");
|
|
||||||
let public = &tmp_dir.path().join("public");
|
|
||||||
site.set_output_path(&public);
|
|
||||||
site.build().unwrap();
|
|
||||||
|
|
||||||
assert!(Path::new(&public).exists());
|
assert!(Path::new(&public).exists());
|
||||||
assert!(file_exists!(public, "elasticlunr.min.js"));
|
assert!(file_exists!(public, "elasticlunr.min.js"));
|
||||||
|
@ -646,14 +569,7 @@ fn can_build_search_index() {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn can_build_with_extra_syntaxes() {
|
fn can_build_with_extra_syntaxes() {
|
||||||
let mut path = env::current_dir().unwrap().parent().unwrap().parent().unwrap().to_path_buf();
|
let (_, _tmp_dir, public) = build_site("test_site");
|
||||||
path.push("test_site");
|
|
||||||
let mut site = Site::new(&path, "config.toml").unwrap();
|
|
||||||
site.load().unwrap();
|
|
||||||
let tmp_dir = tempdir().expect("create temp dir");
|
|
||||||
let public = &tmp_dir.path().join("public");
|
|
||||||
site.set_output_path(&public);
|
|
||||||
site.build().unwrap();
|
|
||||||
|
|
||||||
assert!(&public.exists());
|
assert!(&public.exists());
|
||||||
assert!(file_exists!(public, "posts/extra-syntax/index.html"));
|
assert!(file_exists!(public, "posts/extra-syntax/index.html"));
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
extern crate site;
|
extern crate site;
|
||||||
|
mod common;
|
||||||
|
|
||||||
use std::env;
|
use std::env;
|
||||||
|
|
||||||
use site::Site;
|
use site::Site;
|
||||||
|
use common::build_site;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn can_parse_multilingual_site() {
|
fn can_parse_multilingual_site() {
|
||||||
|
@ -44,3 +46,29 @@ fn can_parse_multilingual_site() {
|
||||||
assert_eq!(page.lang, Some("fr".to_string()));
|
assert_eq!(page.lang, Some("fr".to_string()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn can_build_multilingual_site() {
|
||||||
|
let (_, _tmp_dir, public) = build_site("test_site_i18n");
|
||||||
|
|
||||||
|
assert!(public.exists());
|
||||||
|
|
||||||
|
// Index pages
|
||||||
|
assert!(file_exists!(public, "index.html"));
|
||||||
|
assert!(file_exists!(public, "fr/index.html"));
|
||||||
|
assert!(file_contains!(public, "fr/index.html", "Une page"));
|
||||||
|
assert!(file_contains!(public, "fr/index.html", "Language: fr"));
|
||||||
|
|
||||||
|
assert!(file_exists!(public, "base/index.html"));
|
||||||
|
assert!(file_exists!(public, "fr/base/index.html"));
|
||||||
|
|
||||||
|
// Sections are there as well
|
||||||
|
assert!(file_exists!(public, "blog/index.html"));
|
||||||
|
assert!(file_exists!(public, "fr/blog/index.html"));
|
||||||
|
assert!(file_contains!(public, "fr/blog/index.html", "Language: fr"));
|
||||||
|
|
||||||
|
// sitemap contains all languages
|
||||||
|
assert!(file_exists!(public, "sitemap.xml"));
|
||||||
|
assert!(file_contains!(public, "sitemap.xml", "https://example.com/blog/something-else/"));
|
||||||
|
assert!(file_contains!(public, "sitemap.xml", "https://example.com/fr/blog/something-else/"));
|
||||||
|
}
|
||||||
|
|
4
test_site_i18n/templates/section.html
Normal file
4
test_site_i18n/templates/section.html
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
{% for page in section.pages %}
|
||||||
|
{{page.title}}
|
||||||
|
{% endfor %}
|
||||||
|
Language: {{lang}}
|
Loading…
Reference in a new issue