Implement translation fallback of files included with preprocessing

This commit is contained in:
Ruin0x11 2020-08-29 16:11:47 -07:00
parent 5fed5e866d
commit d6c27abc22
4 changed files with 79 additions and 20 deletions

View File

@ -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");
} }

View File

@ -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",
); );

View 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");
}

View File

@ -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.