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();
|
||||
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| {
|
||||
if let BookItem::Chapter(ref mut ch) = *section {
|
||||
if let Some(ref chapter_path) = ch.path {
|
||||
let base = chapter_path
|
||||
.parent()
|
||||
.map(|dir| src_dir.join(dir))
|
||||
.expect("All book items have a parent");
|
||||
let parent = chapter_path.parent().expect("All book items have a parent");
|
||||
let base = src_dir.join(parent);
|
||||
let fallback = fallback_src_dir.join(parent);
|
||||
|
||||
let mut chapter_title = ch.name.clone();
|
||||
let content =
|
||||
replace_all(&ch.content, base, chapter_path, 0, &mut chapter_title);
|
||||
let content = replace_all(&ch.content, base, Some(fallback), chapter_path, 0, &mut chapter_title);
|
||||
ch.content = content;
|
||||
if chapter_title != ch.name {
|
||||
ctx.chapter_titles
|
||||
@ -76,9 +80,10 @@ impl Preprocessor for LinkPreprocessor {
|
||||
fn replace_all<P1, P2>(
|
||||
s: &str,
|
||||
path: P1,
|
||||
fallback: Option<P1>,
|
||||
source: P2,
|
||||
depth: usize,
|
||||
chapter_title: &mut String,
|
||||
chapter_title: &mut String
|
||||
) -> String
|
||||
where
|
||||
P1: AsRef<Path>,
|
||||
@ -88,6 +93,7 @@ where
|
||||
// the indices after that will not correspond,
|
||||
// we therefore have to store the difference to correct this
|
||||
let path = path.as_ref();
|
||||
let fallback = fallback.as_ref();
|
||||
let source = source.as_ref();
|
||||
let mut previous_end_index = 0;
|
||||
let mut replaced = String::new();
|
||||
@ -95,13 +101,14 @@ where
|
||||
for link in find_links(s) {
|
||||
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) => {
|
||||
if depth < MAX_LINK_NESTED_DEPTH {
|
||||
if let Some(rel_path) = link.link_type.relative_path(path) {
|
||||
replaced.push_str(&replace_all(
|
||||
&new_content,
|
||||
rel_path,
|
||||
None,
|
||||
source,
|
||||
depth + 1,
|
||||
chapter_title,
|
||||
@ -323,6 +330,7 @@ impl<'a> Link<'a> {
|
||||
fn render_with_path<P: AsRef<Path>>(
|
||||
&self,
|
||||
base: P,
|
||||
fallback: Option<P2>,
|
||||
chapter_title: &mut String,
|
||||
) -> Result<String> {
|
||||
let base = base.as_ref();
|
||||
@ -330,7 +338,20 @@ impl<'a> Link<'a> {
|
||||
// omit the escape char
|
||||
LinkType::Escaped => Ok((&self.link_text[1..]).to_owned()),
|
||||
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)
|
||||
.map(|s| match range_or_anchor {
|
||||
@ -346,7 +367,20 @@ impl<'a> Link<'a> {
|
||||
})
|
||||
}
|
||||
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)
|
||||
.map(|s| match range_or_anchor {
|
||||
@ -366,7 +400,20 @@ impl<'a> Link<'a> {
|
||||
})
|
||||
}
|
||||
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(|| {
|
||||
format!(
|
||||
@ -444,7 +491,7 @@ mod tests {
|
||||
{{#include file.rs}} << an escaped link!
|
||||
```";
|
||||
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]
|
||||
@ -456,7 +503,7 @@ mod tests {
|
||||
# My Chapter
|
||||
";
|
||||
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");
|
||||
}
|
||||
|
||||
|
@ -518,10 +518,11 @@ more text with spaces
|
||||
let _ = env_logger::builder().is_test(true).try_init();
|
||||
let test = |dest, path, exists, expected| {
|
||||
let src_dir = tempfile::tempdir().unwrap();
|
||||
let path = PathBuf::from(path);
|
||||
|
||||
let ctx = if exists {
|
||||
Some(RenderMarkdownContext {
|
||||
path: PathBuf::from(path),
|
||||
path: path,
|
||||
src_dir: PathBuf::new(),
|
||||
language: None,
|
||||
fallback_language: None,
|
||||
@ -534,7 +535,7 @@ more text with spaces
|
||||
let fallback_dir = src_dir.path().join("en");
|
||||
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();
|
||||
debug!("Create: {}", chapter_path.display());
|
||||
File::create(&chapter_path)
|
||||
@ -543,7 +544,7 @@ more text with spaces
|
||||
.unwrap();
|
||||
|
||||
Some(RenderMarkdownContext {
|
||||
path: PathBuf::from(path),
|
||||
path: path,
|
||||
src_dir: PathBuf::from(src_dir.path()),
|
||||
language: Some(String::from("ja")),
|
||||
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(
|
||||
"../b/summary.md",
|
||||
"a.md",
|
||||
"a/index.md",
|
||||
false,
|
||||
"../../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(
|
||||
"../c/summary.md",
|
||||
"a/b.md",
|
||||
"a/b/index.md",
|
||||
false,
|
||||
"../../../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.
|
||||
|
||||
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.
|
||||
|
Loading…
Reference in New Issue
Block a user