Implement translation fallback of files included with preprocessing
This commit is contained in:
parent
5fed5e866d
commit
d6c27abc22
@ -48,17 +48,21 @@ impl Preprocessor for LinkPreprocessor {
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
let src_dir = ctx.root.join(src_dir);
|
let src_dir = ctx.root.join(src_dir);
|
||||||
|
|
||||||
|
let fallback_src_dir = ctx
|
||||||
|
.config
|
||||||
|
.get_localized_src_path(ctx.config.default_language().as_ref())
|
||||||
|
.unwrap();
|
||||||
|
let fallback_src_dir = ctx.root.join(fallback_src_dir);
|
||||||
|
|
||||||
book.for_each_mut(|section: &mut BookItem| {
|
book.for_each_mut(|section: &mut BookItem| {
|
||||||
if let BookItem::Chapter(ref mut ch) = *section {
|
if let BookItem::Chapter(ref mut ch) = *section {
|
||||||
if let Some(ref chapter_path) = ch.path {
|
if let Some(ref chapter_path) = ch.path {
|
||||||
let base = chapter_path
|
let parent = chapter_path.parent().expect("All book items have a parent");
|
||||||
.parent()
|
let base = src_dir.join(parent);
|
||||||
.map(|dir| src_dir.join(dir))
|
let fallback = fallback_src_dir.join(parent);
|
||||||
.expect("All book items have a parent");
|
|
||||||
|
|
||||||
let mut chapter_title = ch.name.clone();
|
let mut chapter_title = ch.name.clone();
|
||||||
let content =
|
let content = replace_all(&ch.content, base, Some(fallback), chapter_path, 0, &mut chapter_title);
|
||||||
replace_all(&ch.content, base, chapter_path, 0, &mut chapter_title);
|
|
||||||
ch.content = content;
|
ch.content = content;
|
||||||
if chapter_title != ch.name {
|
if chapter_title != ch.name {
|
||||||
ctx.chapter_titles
|
ctx.chapter_titles
|
||||||
@ -76,9 +80,10 @@ impl Preprocessor for LinkPreprocessor {
|
|||||||
fn replace_all<P1, P2>(
|
fn replace_all<P1, P2>(
|
||||||
s: &str,
|
s: &str,
|
||||||
path: P1,
|
path: P1,
|
||||||
|
fallback: Option<P1>,
|
||||||
source: P2,
|
source: P2,
|
||||||
depth: usize,
|
depth: usize,
|
||||||
chapter_title: &mut String,
|
chapter_title: &mut String
|
||||||
) -> String
|
) -> String
|
||||||
where
|
where
|
||||||
P1: AsRef<Path>,
|
P1: AsRef<Path>,
|
||||||
@ -88,6 +93,7 @@ where
|
|||||||
// the indices after that will not correspond,
|
// the indices after that will not correspond,
|
||||||
// we therefore have to store the difference to correct this
|
// we therefore have to store the difference to correct this
|
||||||
let path = path.as_ref();
|
let path = path.as_ref();
|
||||||
|
let fallback = fallback.as_ref();
|
||||||
let source = source.as_ref();
|
let source = source.as_ref();
|
||||||
let mut previous_end_index = 0;
|
let mut previous_end_index = 0;
|
||||||
let mut replaced = String::new();
|
let mut replaced = String::new();
|
||||||
@ -95,13 +101,14 @@ where
|
|||||||
for link in find_links(s) {
|
for link in find_links(s) {
|
||||||
replaced.push_str(&s[previous_end_index..link.start_index]);
|
replaced.push_str(&s[previous_end_index..link.start_index]);
|
||||||
|
|
||||||
match link.render_with_path(&path, chapter_title) {
|
match link.render_with_path(&path, fallback, chapter_title) {
|
||||||
Ok(new_content) => {
|
Ok(new_content) => {
|
||||||
if depth < MAX_LINK_NESTED_DEPTH {
|
if depth < MAX_LINK_NESTED_DEPTH {
|
||||||
if let Some(rel_path) = link.link_type.relative_path(path) {
|
if let Some(rel_path) = link.link_type.relative_path(path) {
|
||||||
replaced.push_str(&replace_all(
|
replaced.push_str(&replace_all(
|
||||||
&new_content,
|
&new_content,
|
||||||
rel_path,
|
rel_path,
|
||||||
|
None,
|
||||||
source,
|
source,
|
||||||
depth + 1,
|
depth + 1,
|
||||||
chapter_title,
|
chapter_title,
|
||||||
@ -323,6 +330,7 @@ impl<'a> Link<'a> {
|
|||||||
fn render_with_path<P: AsRef<Path>>(
|
fn render_with_path<P: AsRef<Path>>(
|
||||||
&self,
|
&self,
|
||||||
base: P,
|
base: P,
|
||||||
|
fallback: Option<P2>,
|
||||||
chapter_title: &mut String,
|
chapter_title: &mut String,
|
||||||
) -> Result<String> {
|
) -> Result<String> {
|
||||||
let base = base.as_ref();
|
let base = base.as_ref();
|
||||||
@ -330,7 +338,20 @@ impl<'a> Link<'a> {
|
|||||||
// omit the escape char
|
// omit the escape char
|
||||||
LinkType::Escaped => Ok((&self.link_text[1..]).to_owned()),
|
LinkType::Escaped => Ok((&self.link_text[1..]).to_owned()),
|
||||||
LinkType::Include(ref pat, ref range_or_anchor) => {
|
LinkType::Include(ref pat, ref range_or_anchor) => {
|
||||||
let target = base.join(pat);
|
let mut target = base.join(pat);
|
||||||
|
|
||||||
|
if !target.exists() {
|
||||||
|
if let Some(fallback) = fallback {
|
||||||
|
let fallback_target = fallback.as_ref().join(pat);
|
||||||
|
if fallback_target.exists() {
|
||||||
|
debug!(
|
||||||
|
"Included file fallback: {:?} => {:?}",
|
||||||
|
target, fallback_target
|
||||||
|
);
|
||||||
|
target = fallback_target;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fs::read_to_string(&target)
|
fs::read_to_string(&target)
|
||||||
.map(|s| match range_or_anchor {
|
.map(|s| match range_or_anchor {
|
||||||
@ -346,7 +367,20 @@ impl<'a> Link<'a> {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
LinkType::RustdocInclude(ref pat, ref range_or_anchor) => {
|
LinkType::RustdocInclude(ref pat, ref range_or_anchor) => {
|
||||||
let target = base.join(pat);
|
let mut target = base.join(pat);
|
||||||
|
|
||||||
|
if !target.exists() {
|
||||||
|
if let Some(fallback) = fallback {
|
||||||
|
let fallback_target = fallback.as_ref().join(pat);
|
||||||
|
if fallback_target.exists() {
|
||||||
|
debug!(
|
||||||
|
"Included file fallback: {:?} => {:?}",
|
||||||
|
target, fallback_target
|
||||||
|
);
|
||||||
|
target = fallback_target;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fs::read_to_string(&target)
|
fs::read_to_string(&target)
|
||||||
.map(|s| match range_or_anchor {
|
.map(|s| match range_or_anchor {
|
||||||
@ -366,7 +400,20 @@ impl<'a> Link<'a> {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
LinkType::Playground(ref pat, ref attrs) => {
|
LinkType::Playground(ref pat, ref attrs) => {
|
||||||
let target = base.join(pat);
|
let mut target = base.join(pat);
|
||||||
|
|
||||||
|
if !target.exists() {
|
||||||
|
if let Some(fallback) = fallback {
|
||||||
|
let fallback_target = fallback.as_ref().join(pat);
|
||||||
|
if fallback_target.exists() {
|
||||||
|
debug!(
|
||||||
|
"Included file fallback: {:?} => {:?}",
|
||||||
|
target, fallback_target
|
||||||
|
);
|
||||||
|
target = fallback_target;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
let mut contents = fs::read_to_string(&target).with_context(|| {
|
let mut contents = fs::read_to_string(&target).with_context(|| {
|
||||||
format!(
|
format!(
|
||||||
@ -444,7 +491,7 @@ mod tests {
|
|||||||
{{#include file.rs}} << an escaped link!
|
{{#include file.rs}} << an escaped link!
|
||||||
```";
|
```";
|
||||||
let mut chapter_title = "test_replace_all_escaped".to_owned();
|
let mut chapter_title = "test_replace_all_escaped".to_owned();
|
||||||
assert_eq!(replace_all(start, "", "", 0, &mut chapter_title), end);
|
assert_eq!(replace_all(start, "", None, "", 0, &mut chapter_title), end);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -456,7 +503,7 @@ mod tests {
|
|||||||
# My Chapter
|
# My Chapter
|
||||||
";
|
";
|
||||||
let mut chapter_title = "test_set_chapter_title".to_owned();
|
let mut chapter_title = "test_set_chapter_title".to_owned();
|
||||||
assert_eq!(replace_all(start, "", "", 0, &mut chapter_title), end);
|
assert_eq!(replace_all(start, "", None, "", 0, &mut chapter_title), end);
|
||||||
assert_eq!(chapter_title, "My Title");
|
assert_eq!(chapter_title, "My Title");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -518,10 +518,11 @@ more text with spaces
|
|||||||
let _ = env_logger::builder().is_test(true).try_init();
|
let _ = env_logger::builder().is_test(true).try_init();
|
||||||
let test = |dest, path, exists, expected| {
|
let test = |dest, path, exists, expected| {
|
||||||
let src_dir = tempfile::tempdir().unwrap();
|
let src_dir = tempfile::tempdir().unwrap();
|
||||||
|
let path = PathBuf::from(path);
|
||||||
|
|
||||||
let ctx = if exists {
|
let ctx = if exists {
|
||||||
Some(RenderMarkdownContext {
|
Some(RenderMarkdownContext {
|
||||||
path: PathBuf::from(path),
|
path: path,
|
||||||
src_dir: PathBuf::new(),
|
src_dir: PathBuf::new(),
|
||||||
language: None,
|
language: None,
|
||||||
fallback_language: None,
|
fallback_language: None,
|
||||||
@ -534,7 +535,7 @@ more text with spaces
|
|||||||
let fallback_dir = src_dir.path().join("en");
|
let fallback_dir = src_dir.path().join("en");
|
||||||
fs::create_dir_all(&fallback_dir).unwrap();
|
fs::create_dir_all(&fallback_dir).unwrap();
|
||||||
|
|
||||||
let chapter_path = fallback_dir.join(path).join(dest);
|
let chapter_path = fallback_dir.join(path.parent().unwrap()).join(dest);
|
||||||
fs::create_dir_all(chapter_path.parent().unwrap()).unwrap();
|
fs::create_dir_all(chapter_path.parent().unwrap()).unwrap();
|
||||||
debug!("Create: {}", chapter_path.display());
|
debug!("Create: {}", chapter_path.display());
|
||||||
File::create(&chapter_path)
|
File::create(&chapter_path)
|
||||||
@ -543,7 +544,7 @@ more text with spaces
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
Some(RenderMarkdownContext {
|
Some(RenderMarkdownContext {
|
||||||
path: PathBuf::from(path),
|
path: path,
|
||||||
src_dir: PathBuf::from(src_dir.path()),
|
src_dir: PathBuf::from(src_dir.path()),
|
||||||
language: Some(String::from("ja")),
|
language: Some(String::from("ja")),
|
||||||
fallback_language: Some(String::from("en")),
|
fallback_language: Some(String::from("en")),
|
||||||
@ -557,17 +558,17 @@ more text with spaces
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
test("../b/summary.md", "a.md", true, "../b/summary.html");
|
test("../b/summary.md", "a/index.md", true, "../b/summary.html");
|
||||||
test(
|
test(
|
||||||
"../b/summary.md",
|
"../b/summary.md",
|
||||||
"a.md",
|
"a/index.md",
|
||||||
false,
|
false,
|
||||||
"../../en/../b/summary.html",
|
"../../en/../b/summary.html",
|
||||||
);
|
);
|
||||||
test("../c/summary.md", "a/b.md", true, "../c/summary.html");
|
test("../c/summary.md", "a/b/index.md", true, "../c/summary.html");
|
||||||
test(
|
test(
|
||||||
"../c/summary.md",
|
"../c/summary.md",
|
||||||
"a/b.md",
|
"a/b/index.md",
|
||||||
false,
|
false,
|
||||||
"../../../en/../c/summary.html",
|
"../../../en/../c/summary.html",
|
||||||
);
|
);
|
||||||
|
6
tests/localized_book/src/en/example.rs
Normal file
6
tests/localized_book/src/en/example.rs
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
fn main() {
|
||||||
|
println!("Hello World!");
|
||||||
|
#
|
||||||
|
# // You can even hide lines! :D
|
||||||
|
# println!("I am hidden! Expand the code snippet to see me");
|
||||||
|
}
|
@ -12,4 +12,9 @@ Here is an [inline link](missing-summary-chapter.md) to a page missing from this
|
|||||||
|
|
||||||
Also, here is an [inline link](blah.md) to a page missing from both translations. It should point to this language's 404 page.
|
Also, here is an [inline link](blah.md) to a page missing from both translations. It should point to this language's 404 page.
|
||||||
|
|
||||||
|
Here is a file included from the default language.
|
||||||
|
```rust
|
||||||
|
{{ #include example.rs }}
|
||||||
|
```
|
||||||
|
|
||||||
The substitution won't work if you specify the `-l`/`--language` option, since it only builds a single translation in that case.
|
The substitution won't work if you specify the `-l`/`--language` option, since it only builds a single translation in that case.
|
||||||
|
Loading…
Reference in New Issue
Block a user