translation links
rename with _ translation links css for translation links
This commit is contained in:
parent
e7ba6fac85
commit
c021940331
|
@ -12,7 +12,7 @@ build = "build.rs"
|
|||
include = ["data"]
|
||||
exclude = [
|
||||
"book-example/*",
|
||||
"data/html-template/_stylus",
|
||||
"data/_html-template/_stylus",
|
||||
]
|
||||
|
||||
|
||||
|
@ -20,6 +20,7 @@ exclude = [
|
|||
clap = "2.19.2"
|
||||
handlebars = { version = "0.23.0", features = ["serde_type"] }
|
||||
serde = "0.8"
|
||||
serde_derive = "0.8"
|
||||
serde_json = "0.8"
|
||||
pulldown-cmark = "0.0.8"
|
||||
regex = "0.1"
|
||||
|
|
2
build.rs
2
build.rs
|
@ -24,7 +24,7 @@ fn main() {
|
|||
// Compile stylus stylesheet to css
|
||||
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");
|
||||
|
||||
if !Command::new("stylus")
|
||||
|
|
|
@ -53,6 +53,10 @@
|
|||
<i id="theme-toggle" class="fa fa-paint-brush"></i>
|
||||
</div>
|
||||
|
||||
<div class="translations">
|
||||
{{#translations}}{{/translations}}
|
||||
</div>
|
||||
|
||||
<h1 class="menu-title">{{ title }}</h1>
|
||||
|
||||
<div class="right-buttons">
|
||||
|
@ -60,6 +64,8 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
|
||||
<div id="content" class="content">
|
||||
{{{ content }}}
|
||||
</div>
|
|
@ -17,18 +17,13 @@
|
|||
.right-buttons { float: right }
|
||||
}
|
||||
|
||||
.menu-title {
|
||||
display: inline-block
|
||||
h1.menu-title {
|
||||
float: left
|
||||
margin: 0 0 0 2em
|
||||
padding: 0
|
||||
font-weight: 200
|
||||
font-size: 20px
|
||||
line-height: 50px
|
||||
position: absolute
|
||||
top: 0
|
||||
left: 0
|
||||
right: 0
|
||||
bottom: 0
|
||||
text-align: center
|
||||
margin: 0
|
||||
|
||||
opacity: 0
|
||||
transition: opacity 0.5s ease-in-out
|
|
@ -53,3 +53,21 @@
|
|||
|
||||
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; }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -37,7 +37,7 @@ table thead td {
|
|||
font-weight: 700;
|
||||
}
|
||||
.sidebar {
|
||||
position: fixed;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
|
@ -99,6 +99,7 @@ table thead td {
|
|||
}
|
||||
.page-wrapper {
|
||||
position: absolute;
|
||||
overflow-y: auto;
|
||||
left: 315px;
|
||||
right: 0;
|
||||
top: 0;
|
||||
|
@ -133,14 +134,7 @@ table thead td {
|
|||
left: 0;
|
||||
bottom: 0;
|
||||
padding-right: 15px;
|
||||
}
|
||||
@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;
|
||||
}
|
||||
overflow-y: auto;
|
||||
}
|
||||
.content {
|
||||
margin-left: auto;
|
||||
|
@ -157,6 +151,25 @@ table thead td {
|
|||
.content img {
|
||||
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 {
|
||||
position: relative;
|
||||
height: 50px;
|
||||
|
@ -181,18 +194,13 @@ table thead td {
|
|||
.menu-bar .right-buttons {
|
||||
float: right;
|
||||
}
|
||||
.menu-title {
|
||||
display: inline-block;
|
||||
h1.menu-title {
|
||||
float: left;
|
||||
margin: 0 0 0 2em;
|
||||
padding: 0;
|
||||
font-weight: 200;
|
||||
font-size: 20px;
|
||||
line-height: 50px;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
text-align: center;
|
||||
margin: 0;
|
||||
opacity: 0;
|
||||
-ms-filter: "progid:DXImageTransform.Microsoft.Alpha(Opacity=0)";
|
||||
filter: alpha(opacity=0);
|
||||
|
@ -211,7 +219,7 @@ table thead td {
|
|||
font-size: 2.5em;
|
||||
text-align: center;
|
||||
text-decoration: none;
|
||||
position: fixed;
|
||||
position: absolute;
|
||||
top: 50px /* Height of menu-bar */;
|
||||
bottom: 0;
|
||||
margin: 0;
|
||||
|
@ -250,13 +258,7 @@ table thead td {
|
|||
.nav-chapters:hover {
|
||||
text-decoration: none;
|
||||
}
|
||||
.sidebar-hidden .previous {
|
||||
left: 0;
|
||||
}
|
||||
.sidebar-visible .nav-chapters .previous {
|
||||
left: 300px;
|
||||
}
|
||||
.sidebar-visible .mobile-nav-chapters .previous {
|
||||
.previous {
|
||||
left: 0;
|
||||
}
|
||||
.next {
|
||||
|
@ -266,7 +268,6 @@ table thead td {
|
|||
position: relative;
|
||||
left: 10px;
|
||||
z-index: 1000;
|
||||
-webkit-border-radius: 4px;
|
||||
border-radius: 4px;
|
||||
font-size: 0.7em;
|
||||
}
|
||||
|
@ -303,7 +304,6 @@ table thead td {
|
|||
position: relative;
|
||||
display: inline-block;
|
||||
margin-bottom: 50px;
|
||||
-webkit-border-radius: 5px;
|
||||
border-radius: 5px;
|
||||
}
|
||||
.next {
|
||||
|
@ -406,7 +406,6 @@ table thead td {
|
|||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
padding: 0.1em 0.3em;
|
||||
-webkit-border-radius: 3px;
|
||||
border-radius: 3px;
|
||||
}
|
||||
.light pre {
|
||||
|
@ -521,7 +520,6 @@ table thead td {
|
|||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
padding: 0.1em 0.3em;
|
||||
-webkit-border-radius: 3px;
|
||||
border-radius: 3px;
|
||||
}
|
||||
.coal pre {
|
||||
|
@ -636,7 +634,6 @@ table thead td {
|
|||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
padding: 0.1em 0.3em;
|
||||
-webkit-border-radius: 3px;
|
||||
border-radius: 3px;
|
||||
}
|
||||
.navy pre {
|
||||
|
@ -751,7 +748,6 @@ table thead td {
|
|||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
padding: 0.1em 0.3em;
|
||||
-webkit-border-radius: 3px;
|
||||
border-radius: 3px;
|
||||
}
|
||||
.rust pre {
|
||||
|
@ -794,7 +790,6 @@ table thead td {
|
|||
}
|
||||
code {
|
||||
background-color: #666;
|
||||
-webkit-border-radius: 5px;
|
||||
border-radius: 5px;
|
||||
/* Force background to be printed in Chrome */
|
||||
-webkit-print-color-adjust: exact;
|
Before Width: | Height: | Size: 348 KiB After Width: | Height: | Size: 348 KiB |
Before Width: | Height: | Size: 5.5 KiB After Width: | Height: | Size: 5.5 KiB |
|
@ -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>
|
|
@ -53,6 +53,9 @@ pub struct Chapter {
|
|||
/// chapter's path to index.html.
|
||||
pub dest_path: Option<PathBuf>,
|
||||
|
||||
/// Links to the corresponding translations.
|
||||
pub translation_links: Option<Vec<TranslationLink>>,
|
||||
|
||||
/// The author of the chapter, or the book.
|
||||
pub authors: Option<Vec<Author>>,
|
||||
|
||||
|
@ -73,6 +76,7 @@ impl Default for Chapter {
|
|||
title: "Untitled".to_string(),
|
||||
path: PathBuf::from("src".to_string()).join("untitled.md"),
|
||||
dest_path: None,
|
||||
translation_links: None,
|
||||
authors: None,
|
||||
translators: None,
|
||||
description: None,
|
||||
|
@ -153,6 +157,17 @@ impl Chapter {
|
|||
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.
|
||||
if let Some(a) = data.get("author") {
|
||||
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
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,6 +7,9 @@ pub mod chapter;
|
|||
|
||||
pub use self::book::Book;
|
||||
use renderer::{Renderer, HtmlHandlebars};
|
||||
|
||||
use self::chapter::TranslationLink;
|
||||
use self::toc::{TocItem, TocContent};
|
||||
use utils;
|
||||
|
||||
use std::env;
|
||||
|
@ -32,7 +35,7 @@ pub struct MDBook {
|
|||
/// 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.
|
||||
///
|
||||
/// Html Handlebars: `project_root` + `assets/html-template`.
|
||||
/// Html Handlebars: `project_root` + `assets/_html-template`.
|
||||
template_dir: PathBuf,
|
||||
|
||||
/// Output base for all books, relative to `project_root`. Defaults to
|
||||
|
@ -367,6 +370,69 @@ impl MDBook {
|
|||
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 {
|
||||
&self.project_root
|
||||
}
|
||||
|
@ -414,7 +480,7 @@ impl MDBook {
|
|||
self.render_intent = intent;
|
||||
match self.render_intent {
|
||||
RenderIntent::HtmlHandlebars => {
|
||||
self.set_template_dir(&PathBuf::from("assets").join("html-template"));
|
||||
self.set_template_dir(&PathBuf::from("assets").join("_html-template"));
|
||||
},
|
||||
}
|
||||
self
|
||||
|
|
|
@ -69,6 +69,11 @@
|
|||
//!
|
||||
//! Make sure to take a look at it.
|
||||
|
||||
#![feature(proc_macro)]
|
||||
|
||||
#[macro_use]
|
||||
extern crate serde_derive;
|
||||
|
||||
extern crate includedir;
|
||||
extern crate phf;
|
||||
|
||||
|
|
|
@ -36,9 +36,14 @@ impl Renderer for HtmlHandlebars {
|
|||
|
||||
book_project.read_config();
|
||||
book_project.parse_books();
|
||||
book_project.link_translations();
|
||||
|
||||
// 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));
|
||||
|
||||
|
@ -116,9 +121,9 @@ impl Renderer for HtmlHandlebars {
|
|||
&book_project.get_dest_base());
|
||||
|
||||
} else {
|
||||
try!(utils::fs::copy_data("data/html-template/**/*",
|
||||
"data/html-template/",
|
||||
vec!["data/html-template/_*"],
|
||||
try!(utils::fs::copy_data("data/_html-template/**/*",
|
||||
"data/_html-template/",
|
||||
vec!["data/_html-template/_*"],
|
||||
&book_project.get_dest_base()));
|
||||
}
|
||||
|
||||
|
@ -133,7 +138,7 @@ impl Renderer for HtmlHandlebars {
|
|||
let s = if tmpl_path.exists() {
|
||||
try!(utils::fs::file_to_string(&tmpl_path))
|
||||
} 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
|
||||
|
@ -145,6 +150,7 @@ impl Renderer for HtmlHandlebars {
|
|||
handlebars.register_helper("toc", Box::new(helpers::toc::RenderToc));
|
||||
handlebars.register_helper("previous", Box::new(helpers::navigation::previous));
|
||||
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
|
||||
|
||||
|
@ -332,6 +338,10 @@ fn make_data(book: &Book,
|
|||
|
||||
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));
|
||||
|
||||
data.insert("chapters".to_owned(), chapters.to_json());
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
pub mod navigation;
|
||||
pub mod toc;
|
||||
pub mod playpen;
|
||||
pub mod translations;
|
||||
|
|
|
@ -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(())
|
||||
}
|
||||
}
|
|
@ -1,3 +1,13 @@
|
|||
+++
|
||||
[[translation_links]]
|
||||
code = "fr"
|
||||
link = "fr/terrier.html"
|
||||
|
||||
[[translation_links]]
|
||||
code = "hu"
|
||||
link = "hu/nyuszi.html"
|
||||
+++
|
||||
|
||||
# Down The Rabbit-Hole
|
||||
|
||||
![Rabbit](images/Rabbit.png)
|
||||
|
|
|
@ -9,7 +9,7 @@ use utils;
|
|||
#[test]
|
||||
fn it_copies_data_file() {
|
||||
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) {
|
||||
Ok(f) => f,
|
||||
|
@ -32,9 +32,9 @@ fn it_copies_data_file() {
|
|||
fn it_copies_data_by_pattern() {
|
||||
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/**/*",
|
||||
"data/html-template/",
|
||||
vec!["data/html-template/_*"],
|
||||
if let Err(e) = utils::fs::copy_data("data/_html-template/**/*",
|
||||
"data/_html-template/",
|
||||
vec!["data/_html-template/_*"],
|
||||
&dest_base) {
|
||||
println!("Error: {:#?}", e);
|
||||
return;
|
||||
|
|
|
@ -50,4 +50,20 @@ fn it_renders_multilanguage_book() {
|
|||
|
||||
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>"));
|
||||
}
|
||||
|
|
|
@ -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
|
||||
/// relative to the `dest_path` can be controlled.
|
||||
///
|
||||
/// The following will copy all files under "data/html-template/", excluding
|
||||
/// folders that start with "_", take the "data/html-template/" part off the
|
||||
/// The following will copy all files under "data/_html-template/", excluding
|
||||
/// folders that start with "_", take the "data/_html-template/" part off the
|
||||
/// 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".
|
||||
///
|
||||
/// ```no_run
|
||||
/// utils::fs::copy_data("data/html-template/**/*",
|
||||
/// "data/html-template/",
|
||||
/// vec!["data/html-template/_*"],
|
||||
/// utils::fs::copy_data("data/_html-template/**/*",
|
||||
/// "data/_html-template/",
|
||||
/// vec!["data/_html-template/_*"],
|
||||
/// &Path::new("assets"));
|
||||
/// ```
|
||||
pub fn copy_data(include_glob: &str,
|
||||
|
|
Loading…
Reference in New Issue