translation links

rename with _
translation links
css for translation links
This commit is contained in:
Gambhiro 2017-01-10 06:35:56 +00:00
parent e7ba6fac85
commit c021940331
45 changed files with 270 additions and 177 deletions

View File

@ -12,7 +12,7 @@ build = "build.rs"
include = ["data"] include = ["data"]
exclude = [ exclude = [
"book-example/*", "book-example/*",
"data/html-template/_stylus", "data/_html-template/_stylus",
] ]
@ -20,6 +20,7 @@ exclude = [
clap = "2.19.2" clap = "2.19.2"
handlebars = { version = "0.23.0", features = ["serde_type"] } handlebars = { version = "0.23.0", features = ["serde_type"] }
serde = "0.8" serde = "0.8"
serde_derive = "0.8"
serde_json = "0.8" serde_json = "0.8"
pulldown-cmark = "0.0.8" pulldown-cmark = "0.0.8"
regex = "0.1" regex = "0.1"

View File

@ -24,7 +24,7 @@ fn main() {
// Compile stylus stylesheet to css // Compile stylus stylesheet to css
let manifest_dir = env::var("CARGO_MANIFEST_DIR").unwrap(); let manifest_dir = env::var("CARGO_MANIFEST_DIR").unwrap();
let template_dir = Path::new(&manifest_dir).join("data/html-template/"); let template_dir = Path::new(&manifest_dir).join("data/_html-template/");
let stylus_dir = template_dir.join("_stylus/book.styl"); let stylus_dir = template_dir.join("_stylus/book.styl");
if !Command::new("stylus") if !Command::new("stylus")

View File

@ -53,6 +53,10 @@
<i id="theme-toggle" class="fa fa-paint-brush"></i> <i id="theme-toggle" class="fa fa-paint-brush"></i>
</div> </div>
<div class="translations">
{{#translations}}{{/translations}}
</div>
<h1 class="menu-title">{{ title }}</h1> <h1 class="menu-title">{{ title }}</h1>
<div class="right-buttons"> <div class="right-buttons">
@ -60,6 +64,8 @@
</div> </div>
</div> </div>
<div id="content" class="content"> <div id="content" class="content">
{{{ content }}} {{{ content }}}
</div> </div>

View File

@ -17,18 +17,13 @@
.right-buttons { float: right } .right-buttons { float: right }
} }
.menu-title { h1.menu-title {
display: inline-block float: left
margin: 0 0 0 2em
padding: 0
font-weight: 200 font-weight: 200
font-size: 20px font-size: 20px
line-height: 50px line-height: 50px
position: absolute
top: 0
left: 0
right: 0
bottom: 0
text-align: center
margin: 0
opacity: 0 opacity: 0
transition: opacity 0.5s ease-in-out transition: opacity 0.5s ease-in-out

View File

@ -53,3 +53,21 @@
img { max-width: 100%; } img { max-width: 100%; }
} }
div.translations {
float: left
height: 50px
ul {
margin: 10px 0 0 0
display: inline-block
list-style-type: none
li {
display: inline-block
padding: 0.2em 0.5em
a {
text-decoration: none
&:hover { text-decoration: underline; }
}
}
}
}

View File

@ -37,7 +37,7 @@ table thead td {
font-weight: 700; font-weight: 700;
} }
.sidebar { .sidebar {
position: fixed; position: absolute;
left: 0; left: 0;
top: 0; top: 0;
bottom: 0; bottom: 0;
@ -99,6 +99,7 @@ table thead td {
} }
.page-wrapper { .page-wrapper {
position: absolute; position: absolute;
overflow-y: auto;
left: 315px; left: 315px;
right: 0; right: 0;
top: 0; top: 0;
@ -133,14 +134,7 @@ table thead td {
left: 0; left: 0;
bottom: 0; bottom: 0;
padding-right: 15px; padding-right: 15px;
} overflow-y: auto;
@media only screen and (max-width: 400px) {
.page {
/* Only prevent horizontal scrolling on screens with less than 100px for the content
A better way would be to somehow prevent horizontal scrolling all the time, but this causes scrolling problems on iOS Safari.
Also, would be better to only enable horizontal scrolling when it is needed (content does not fit on page) but I have no idea how to do that. */
overflow-x: hidden;
}
} }
.content { .content {
margin-left: auto; margin-left: auto;
@ -157,6 +151,25 @@ table thead td {
.content img { .content img {
max-width: 100%; max-width: 100%;
} }
div.translations {
float: left;
height: 50px;
}
div.translations ul {
margin: 10px 0 0 0;
display: inline-block;
list-style-type: none;
}
div.translations ul li {
display: inline-block;
padding: 0.2em 0.5em;
}
div.translations ul li a {
text-decoration: none;
}
div.translations ul li a:hover {
text-decoration: underline;
}
.menu-bar { .menu-bar {
position: relative; position: relative;
height: 50px; height: 50px;
@ -181,18 +194,13 @@ table thead td {
.menu-bar .right-buttons { .menu-bar .right-buttons {
float: right; float: right;
} }
.menu-title { h1.menu-title {
display: inline-block; float: left;
margin: 0 0 0 2em;
padding: 0;
font-weight: 200; font-weight: 200;
font-size: 20px; font-size: 20px;
line-height: 50px; line-height: 50px;
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
text-align: center;
margin: 0;
opacity: 0; opacity: 0;
-ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)"; -ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)";
filter: alpha(opacity=0); filter: alpha(opacity=0);
@ -211,7 +219,7 @@ table thead td {
font-size: 2.5em; font-size: 2.5em;
text-align: center; text-align: center;
text-decoration: none; text-decoration: none;
position: fixed; position: absolute;
top: 50px /* Height of menu-bar */; top: 50px /* Height of menu-bar */;
bottom: 0; bottom: 0;
margin: 0; margin: 0;
@ -250,13 +258,7 @@ table thead td {
.nav-chapters:hover { .nav-chapters:hover {
text-decoration: none; text-decoration: none;
} }
.sidebar-hidden .previous { .previous {
left: 0;
}
.sidebar-visible .nav-chapters .previous {
left: 300px;
}
.sidebar-visible .mobile-nav-chapters .previous {
left: 0; left: 0;
} }
.next { .next {
@ -266,7 +268,6 @@ table thead td {
position: relative; position: relative;
left: 10px; left: 10px;
z-index: 1000; z-index: 1000;
-webkit-border-radius: 4px;
border-radius: 4px; border-radius: 4px;
font-size: 0.7em; font-size: 0.7em;
} }
@ -303,7 +304,6 @@ table thead td {
position: relative; position: relative;
display: inline-block; display: inline-block;
margin-bottom: 50px; margin-bottom: 50px;
-webkit-border-radius: 5px;
border-radius: 5px; border-radius: 5px;
} }
.next { .next {
@ -406,7 +406,6 @@ table thead td {
display: inline-block; display: inline-block;
vertical-align: middle; vertical-align: middle;
padding: 0.1em 0.3em; padding: 0.1em 0.3em;
-webkit-border-radius: 3px;
border-radius: 3px; border-radius: 3px;
} }
.light pre { .light pre {
@ -521,7 +520,6 @@ table thead td {
display: inline-block; display: inline-block;
vertical-align: middle; vertical-align: middle;
padding: 0.1em 0.3em; padding: 0.1em 0.3em;
-webkit-border-radius: 3px;
border-radius: 3px; border-radius: 3px;
} }
.coal pre { .coal pre {
@ -636,7 +634,6 @@ table thead td {
display: inline-block; display: inline-block;
vertical-align: middle; vertical-align: middle;
padding: 0.1em 0.3em; padding: 0.1em 0.3em;
-webkit-border-radius: 3px;
border-radius: 3px; border-radius: 3px;
} }
.navy pre { .navy pre {
@ -751,7 +748,6 @@ table thead td {
display: inline-block; display: inline-block;
vertical-align: middle; vertical-align: middle;
padding: 0.1em 0.3em; padding: 0.1em 0.3em;
-webkit-border-radius: 3px;
border-radius: 3px; border-radius: 3px;
} }
.rust pre { .rust pre {
@ -794,7 +790,6 @@ table thead td {
} }
code { code {
background-color: #666; background-color: #666;
-webkit-border-radius: 5px;
border-radius: 5px; border-radius: 5px;
/* Force background to be printed in Chrome */ /* Force background to be printed in Chrome */
-webkit-print-color-adjust: exact; -webkit-print-color-adjust: exact;

View File

Before

Width:  |  Height:  |  Size: 348 KiB

After

Width:  |  Height:  |  Size: 348 KiB

View File

Before

Width:  |  Height:  |  Size: 5.5 KiB

After

Width:  |  Height:  |  Size: 5.5 KiB

View File

@ -1,116 +0,0 @@
<!DOCTYPE HTML>
<html lang="{{ language }}">
<head>
<meta charset="UTF-8">
<title>{{ title }}</title>
<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
<meta name="description" content="{{ description }}">
<meta name="viewport" content="width=device-width, initial-scale=1">
<base href="{{ path_to_root }}">
<link rel="stylesheet" href="book.css">
<link href='https://fonts.googleapis.com/css?family=Open+Sans:300italic,400italic,600italic,700italic,800italic,400,300,600,700,800' rel='stylesheet' type='text/css'>
<link rel="shortcut icon" href="{{ favicon }}">
<!-- Font Awesome -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/font-awesome/4.3.0/css/font-awesome.min.css">
<link rel="stylesheet" href="highlight.css">
<link rel="stylesheet" href="tomorrow-night.css">
<!-- MathJax -->
<script type="text/javascript" src="https://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
<!-- Fetch JQuery from CDN but have a local fallback -->
<script src="https://code.jquery.com/jquery-2.1.4.min.js"></script>
<script>
if (typeof jQuery == 'undefined') {
document.write(unescape("%3Cscript src='jquery.js'%3E%3C/script%3E"));
}
</script>
</head>
<body class="light">
<!-- Set the theme before any content is loaded, prevents flash -->
<script type="text/javascript">
var theme = localStorage.getItem('theme');
if (theme == null) { theme = 'light'; }
$('body').removeClass().addClass(theme);
</script>
<!-- Hide / unhide sidebar before it is displayed -->
<script type="text/javascript">
var sidebar = localStorage.getItem('sidebar');
if (sidebar === "hidden") { $("html").addClass("sidebar-hidden") }
else if (sidebar === "visible") { $("html").addClass("sidebar-visible") }
</script>
<div id="sidebar" class="sidebar">
{{#toc}}{{/toc}}
</div>
<div id="page-wrapper" class="page-wrapper">
<div class="page">
<div id="menu-bar" class="menu-bar">
<div class="left-buttons">
<i id="sidebar-toggle" class="fa fa-bars"></i>
<i id="theme-toggle" class="fa fa-paint-brush"></i>
</div>
<h1 class="menu-title">{{ title }}</h1>
<div class="right-buttons">
<i id="print-button" class="fa fa-print" title="Print this book"></i>
</div>
</div>
<div id="content" class="content">
{{{ content }}}
</div>
<!-- Mobile navigation buttons -->
{{#previous}}
<a href="{{link}}" class="mobile-nav-chapters previous">
<i class="fa fa-angle-left"></i>
</a>
{{/previous}}
{{#next}}
<a href="{{link}}" class="mobile-nav-chapters next">
<i class="fa fa-angle-right"></i>
</a>
{{/next}}
</div>
{{#previous}}
<a href="{{link}}" class="nav-chapters previous" title="You can navigate through the chapters using the arrow keys">
<i class="fa fa-angle-left"></i>
</a>
{{/previous}}
{{#next}}
<a href="{{link}}" class="nav-chapters next" title="You can navigate through the chapters using the arrow keys">
<i class="fa fa-angle-right"></i>
</a>
{{/next}}
</div>
<!-- Local fallback for Font Awesome -->
<script>
if ($(".fa").css("font-family") !== "FontAwesome") {
$('<link rel="stylesheet" type="text/css" href="_FontAwesome/css/font-awesome.css">').prependTo('head');
}
</script>
<!-- Livereload script (if served using the cli tool) -->
{{{livereload}}}
<script src="highlight.js"></script>
<script src="book.js"></script>
</body>
</html>

View File

@ -53,6 +53,9 @@ pub struct Chapter {
/// chapter's path to index.html. /// chapter's path to index.html.
pub dest_path: Option<PathBuf>, pub dest_path: Option<PathBuf>,
/// Links to the corresponding translations.
pub translation_links: Option<Vec<TranslationLink>>,
/// The author of the chapter, or the book. /// The author of the chapter, or the book.
pub authors: Option<Vec<Author>>, pub authors: Option<Vec<Author>>,
@ -73,6 +76,7 @@ impl Default for Chapter {
title: "Untitled".to_string(), title: "Untitled".to_string(),
path: PathBuf::from("src".to_string()).join("untitled.md"), path: PathBuf::from("src".to_string()).join("untitled.md"),
dest_path: None, dest_path: None,
translation_links: None,
authors: None, authors: None,
translators: None, translators: None,
description: None, description: None,
@ -153,6 +157,17 @@ impl Chapter {
self.css_class = Some(a.to_string()); self.css_class = Some(a.to_string());
} }
if let Some(a) = data.get("translation_links") {
if let Some(b) = a.as_slice() {
let links: Vec<TranslationLink> = b.iter()
.filter_map(|x| x.as_table())
.map(|x| TranslationLink::from(x.to_owned()))
.collect::<Vec<TranslationLink>>();
self.translation_links = Some(links);
}
}
// Author name as a hash key. // Author name as a hash key.
if let Some(a) = data.get("author") { if let Some(a) = data.get("author") {
if let Some(b) = a.as_str() { if let Some(b) = a.as_str() {
@ -213,3 +228,40 @@ impl Chapter {
} }
} }
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TranslationLink {
pub code: String,
pub link: String,
}
impl Default for TranslationLink {
fn default() -> TranslationLink {
TranslationLink {
code: "".to_string(),
link: "".to_string(),
}
}
}
impl TranslationLink {
pub fn new(code: String, link: String) -> TranslationLink {
TranslationLink {
code: code,
link: link,
}
}
}
impl From<toml::Table> for TranslationLink {
fn from(data: toml::Table) -> TranslationLink {
let mut link = TranslationLink::default();
if let Some(x) = data.get("code") {
link.code = x.to_string().replace("\"", "");
}
if let Some(x) = data.get("link") {
link.link = x.to_string().replace("\"", "");
}
link
}
}

View File

@ -7,6 +7,9 @@ pub mod chapter;
pub use self::book::Book; pub use self::book::Book;
use renderer::{Renderer, HtmlHandlebars}; use renderer::{Renderer, HtmlHandlebars};
use self::chapter::TranslationLink;
use self::toc::{TocItem, TocContent};
use utils; use utils;
use std::env; use std::env;
@ -32,7 +35,7 @@ pub struct MDBook {
/// A book doesn't necessarily has to have the template files. When not /// A book doesn't necessarily has to have the template files. When not
/// found in the book's folder, the embedded static assets will be used. /// found in the book's folder, the embedded static assets will be used.
/// ///
/// Html Handlebars: `project_root` + `assets/html-template`. /// Html Handlebars: `project_root` + `assets/_html-template`.
template_dir: PathBuf, template_dir: PathBuf,
/// Output base for all books, relative to `project_root`. Defaults to /// Output base for all books, relative to `project_root`. Defaults to
@ -367,6 +370,69 @@ impl MDBook {
self self
} }
pub fn link_translations(&mut self) -> &mut MDBook {
for (key, book) in self.translations.clone() {
let mut newbook: Book = book.clone();
newbook.toc = book.toc.iter()
.map(|item| {
match *item {
TocItem::Numbered(ref i) =>
TocItem::Numbered(self.set_translation_links(i)),
TocItem::Unnumbered(ref i) =>
TocItem::Unnumbered(self.set_translation_links(i)),
TocItem::Unlisted(ref i) =>
TocItem::Unlisted(self.set_translation_links(i)),
TocItem::Spacer =>
TocItem::Spacer,
}
}).collect::<Vec<TocItem>>();
self.translations.remove(&key);
self.translations.insert(key, newbook);
}
self
}
/// prepare a Vec of default links to point to the index.html of each translation
fn translation_index_links(&mut self) -> Vec<TranslationLink> {
let mut default_links: Vec<TranslationLink> = vec![];
let mut keys = self.translations.keys()
.map(|x| x.to_string())
.collect::<Vec<String>>();
keys.sort();
for key in keys {
let book = self.translations.get(&key).unwrap();
let z = self.get_dest_base();
let a = book.config.dest.strip_prefix(&z).unwrap();
let b = a.join("index.html");
let c = b.to_str().unwrap();
let link = TranslationLink::new(key, c.to_string());
default_links.push(link);
}
default_links
}
fn set_translation_links(&mut self, content: &TocContent) -> TocContent {
let default_links = self.translation_index_links();
let mut newcontent: TocContent = content.clone();
match newcontent.chapter.translation_links {
Some(_) => {},
None => {
newcontent.chapter.translation_links = Some(default_links);
}
}
newcontent
}
pub fn get_project_root(&self) -> &Path { pub fn get_project_root(&self) -> &Path {
&self.project_root &self.project_root
} }
@ -414,7 +480,7 @@ impl MDBook {
self.render_intent = intent; self.render_intent = intent;
match self.render_intent { match self.render_intent {
RenderIntent::HtmlHandlebars => { RenderIntent::HtmlHandlebars => {
self.set_template_dir(&PathBuf::from("assets").join("html-template")); self.set_template_dir(&PathBuf::from("assets").join("_html-template"));
}, },
} }
self self

View File

@ -69,6 +69,11 @@
//! //!
//! Make sure to take a look at it. //! Make sure to take a look at it.
#![feature(proc_macro)]
#[macro_use]
extern crate serde_derive;
extern crate includedir; extern crate includedir;
extern crate phf; extern crate phf;

View File

@ -36,9 +36,14 @@ impl Renderer for HtmlHandlebars {
book_project.read_config(); book_project.read_config();
book_project.parse_books(); book_project.parse_books();
book_project.link_translations();
// Clean output directory // Clean output directory
try!(utils::fs::remove_dir_content(&book_project.get_dest_base()));
// FIXME don't remove dotfiles such as .git/ folder. It's a common
// practice to track gh-pages in a versioned output folder.
//try!(utils::fs::remove_dir_content(&book_project.get_dest_base()));
try!(self.render(&book_project)); try!(self.render(&book_project));
@ -116,9 +121,9 @@ impl Renderer for HtmlHandlebars {
&book_project.get_dest_base()); &book_project.get_dest_base());
} else { } else {
try!(utils::fs::copy_data("data/html-template/**/*", try!(utils::fs::copy_data("data/_html-template/**/*",
"data/html-template/", "data/_html-template/",
vec!["data/html-template/_*"], vec!["data/_html-template/_*"],
&book_project.get_dest_base())); &book_project.get_dest_base()));
} }
@ -133,7 +138,7 @@ impl Renderer for HtmlHandlebars {
let s = if tmpl_path.exists() { let s = if tmpl_path.exists() {
try!(utils::fs::file_to_string(&tmpl_path)) try!(utils::fs::file_to_string(&tmpl_path))
} else { } else {
try!(utils::fs::get_data_file("data/html-template/_layouts/page.hbs")) try!(utils::fs::get_data_file("data/_html-template/_layouts/page.hbs"))
}; };
// Register template // Register template
@ -145,6 +150,7 @@ impl Renderer for HtmlHandlebars {
handlebars.register_helper("toc", Box::new(helpers::toc::RenderToc)); handlebars.register_helper("toc", Box::new(helpers::toc::RenderToc));
handlebars.register_helper("previous", Box::new(helpers::navigation::previous)); handlebars.register_helper("previous", Box::new(helpers::navigation::previous));
handlebars.register_helper("next", Box::new(helpers::navigation::next)); handlebars.register_helper("next", Box::new(helpers::navigation::next));
handlebars.register_helper("translations", Box::new(helpers::translations::TranslationsHelper));
// Check if book's dest directory exists // Check if book's dest directory exists
@ -332,6 +338,10 @@ fn make_data(book: &Book,
data.insert("path_to_root".to_owned(), utils::fs::path_to_root(&path).to_json()); data.insert("path_to_root".to_owned(), utils::fs::path_to_root(&path).to_json());
if let Some(ref links) = chapter.translation_links {
data.insert("translation_links".to_owned(), links.to_json());
}
let chapters = try!(items_to_chapters(&book.toc, &book)); let chapters = try!(items_to_chapters(&book.toc, &book));
data.insert("chapters".to_owned(), chapters.to_json()); data.insert("chapters".to_owned(), chapters.to_json());

View File

@ -1,3 +1,4 @@
pub mod navigation; pub mod navigation;
pub mod toc; pub mod toc;
pub mod playpen; pub mod playpen;
pub mod translations;

View File

@ -0,0 +1,34 @@
use std::path::Path;
use std::collections::{VecDeque, BTreeMap};
use serde_json;
use handlebars::{Handlebars, HelperDef, RenderError, RenderContext, Helper, Context};
#[derive(Clone, Copy)]
pub struct TranslationsHelper;
impl HelperDef for TranslationsHelper {
fn call(&self, c: &Context, _h: &Helper, _: &Handlebars, rc: &mut RenderContext) -> Result<(), RenderError> {
let translation_links = c.navigate(rc.get_path(), &VecDeque::new(), "translation_links");
let decoded: Vec<BTreeMap<String, String>> = serde_json::from_str(&translation_links.to_string()).unwrap();
if decoded.len() == 0 {
return Ok(());
}
try!(rc.writer.write("<ul class=\"translations\">".as_bytes()));
for item in decoded {
let empty = "".to_string();
let link = item.get("link").unwrap_or(&empty);
let code = item.get("code").unwrap_or(&empty);
let text = format!("<li><a href=\"{}\">{}</a></li>", link, code);
try!(rc.writer.write(text.as_bytes()));
}
try!(rc.writer.write("</ul>".as_bytes()));
Ok(())
}
}

View File

@ -1,3 +1,13 @@
+++
[[translation_links]]
code = "fr"
link = "fr/terrier.html"
[[translation_links]]
code = "hu"
link = "hu/nyuszi.html"
+++
# Down The Rabbit-Hole # Down The Rabbit-Hole
![Rabbit](images/Rabbit.png) ![Rabbit](images/Rabbit.png)

View File

@ -9,7 +9,7 @@ use utils;
#[test] #[test]
fn it_copies_data_file() { fn it_copies_data_file() {
let dest_path = Path::new("the place was dark").join("and dusty and half-lost").join("book.css"); let dest_path = Path::new("the place was dark").join("and dusty and half-lost").join("book.css");
utils::fs::copy_data_file("data/html-template/css/books.css", &dest_path); utils::fs::copy_data_file("data/_html-template/css/books.css", &dest_path);
let mut file = match File::open(&dest_path) { let mut file = match File::open(&dest_path) {
Ok(f) => f, Ok(f) => f,
@ -32,9 +32,9 @@ fn it_copies_data_file() {
fn it_copies_data_by_pattern() { fn it_copies_data_by_pattern() {
let dest_base = Path::new("in tangles of old alleys").join("near the quays"); let dest_base = Path::new("in tangles of old alleys").join("near the quays");
if let Err(e) = utils::fs::copy_data("data/html-template/**/*", if let Err(e) = utils::fs::copy_data("data/_html-template/**/*",
"data/html-template/", "data/_html-template/",
vec!["data/html-template/_*"], vec!["data/_html-template/_*"],
&dest_base) { &dest_base) {
println!("Error: {:#?}", e); println!("Error: {:#?}", e);
return; return;

View File

@ -50,4 +50,20 @@ fn it_renders_multilanguage_book() {
assert!(proj.get_dest_base().join("images").join("Queen.jpg").exists()); assert!(proj.get_dest_base().join("images").join("Queen.jpg").exists());
// Test if translation links given in the TOML header were rendered
book_path = proj.translations.get("en").unwrap().config.get_dest();
chapter_path = book_path.join("rabbit-hole.html");
s = utils::fs::file_to_string(&chapter_path).unwrap();
assert!(s.contains("<a href=\"hu/nyuszi.html\">hu</a>"));
assert!(s.contains("<a href=\"fr/terrier.html\">fr</a>"));
// Test if default translation links are set
book_path = proj.translations.get("hu").unwrap().config.get_dest();
chapter_path = book_path.join("tarka-farka.html");
s = utils::fs::file_to_string(&chapter_path).unwrap();
assert!(s.contains("<a href=\"en/index.html\">en</a>"));
assert!(s.contains("<a href=\"hu/index.html\">hu</a>"));
assert!(s.contains("<a href=\"fr/index.html\">fr</a>"));
} }

View File

@ -61,17 +61,17 @@ pub fn copy_data_file(src_path: &str, dest_path: &Path) -> Result<(), Box<Error>
/// `include_base` will be removed from the source path. This way the path /// `include_base` will be removed from the source path. This way the path
/// relative to the `dest_path` can be controlled. /// relative to the `dest_path` can be controlled.
/// ///
/// The following will copy all files under "data/html-template/", excluding /// The following will copy all files under "data/_html-template/", excluding
/// folders that start with "_", take the "data/html-template/" part off the /// folders that start with "_", take the "data/_html-template/" part off the
/// source path, and write the entries to "assets" folder. /// source path, and write the entries to "assets" folder.
/// ///
/// I.e. "data/html-template/css/book.css" will be written to /// I.e. "data/_html-template/css/book.css" will be written to
/// "assets/css/book.css". /// "assets/css/book.css".
/// ///
/// ```no_run /// ```no_run
/// utils::fs::copy_data("data/html-template/**/*", /// utils::fs::copy_data("data/_html-template/**/*",
/// "data/html-template/", /// "data/_html-template/",
/// vec!["data/html-template/_*"], /// vec!["data/_html-template/_*"],
/// &Path::new("assets")); /// &Path::new("assets"));
/// ``` /// ```
pub fn copy_data(include_glob: &str, pub fn copy_data(include_glob: &str,