Skip to content

Commit e725fb4

Browse files
committed
Expanding templates guide section
1 parent af29fd0 commit e725fb4

1 file changed

Lines changed: 233 additions & 0 deletions

File tree

docs/templates.md

Lines changed: 233 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,112 @@ document:
3232
{{- if $prefix -}}{{ $prefix }} - {{- end -}}{{ .Title -}}
3333
```
3434
35+
How this template works:
36+
37+
- `{{ ... }}` marks a Go template action. Text outside actions is copied to the result.
38+
- The `-` in `{{-` or `-}}` trims whitespace next to the action. This keeps generated file names from accumulating newlines and indentation from the YAML block.
39+
- `$prefix := ""` creates a template variable named `$prefix` and initializes it to an empty string.
40+
- `len .Authors` returns the number of authors in the book metadata.
41+
- `gt (len .Authors) 0` means "greater than zero". The surrounding `if` checks whether at least one author exists.
42+
- `first .Authors` is a slim-sprig helper that returns the first author object from the list.
43+
- `with first .Authors` changes the current dot (`.`) to that first author for the duration of the block, so `.LastName` means the first author's last name inside the block.
44+
- `$prefix = .LastName` assigns the first author's last name to the previously created `$prefix` variable.
45+
- `if $prefix` checks whether `$prefix` is non-empty. If it is, the template writes the prefix followed by ` - `.
46+
- `.Title` writes the book title.
47+
48+
In plain English, the sample means: "If the book has at least one author, start the file name with the first author's last name and a separator, then append the book title."
49+
50+
Advanced example with first author name parts and language-specific "et al" text:
51+
52+
```yaml
53+
document:
54+
output_name_template: |
55+
{{- $all := "" -}}
56+
{{- if gt (len .Authors) 0 -}}
57+
{{- with first .Authors -}}
58+
{{- $all = .LastName -}}
59+
{{- if .FirstName }}{{ $all = (cat $all .FirstName) }}{{- end -}}
60+
{{- if .MiddleName }}{{ $all = (cat $all .MiddleName) }}{{- end -}}
61+
{{- end -}}
62+
{{- if gt (len .Authors) 1 -}}
63+
{{- if eq .Language "ru" }}{{ $all = (cat $all "и др") }}{{- else -}}{{ $all = (printf "%s%s" $all ", et al") }}{{- end -}}
64+
{{- end -}}
65+
{{- $all = cat $all "-" -}}
66+
{{- end -}}
67+
{{- if $all -}}
68+
{{- cat $all .Title -}}
69+
{{- else -}}
70+
{{- .Title -}}
71+
{{- end -}}
72+
```
73+
74+
How the advanced template works:
75+
76+
- `$all := ""` creates an accumulator variable that will eventually contain the author prefix.
77+
- `if gt (len .Authors) 0` runs the author-prefix logic only when the book has at least one author.
78+
- `with first .Authors` selects the first author and makes that author the current dot (`.`).
79+
- `$all = .LastName` starts the prefix with the first author's last name.
80+
- `if .FirstName` checks whether the first author has a first name. If yes, `$all = (cat $all .FirstName)` appends it.
81+
- `if .MiddleName` does the same for the middle name.
82+
- `cat` is a slim-sprig helper that concatenates values with spaces between arguments. So `cat "Иванов" "Иван"` produces `Иванов Иван`.
83+
- After the `with` block ends, dot (`.`) returns to the full book metadata context.
84+
- `if gt (len .Authors) 1` checks whether there is more than one author.
85+
- `eq .Language "ru"` checks whether the book language is Russian.
86+
- For Russian books, `cat $all "и др"` appends `и др` to mean "and others".
87+
- For non-Russian books, `printf "%s%s" $all ", et al"` appends `, et al` without inserting an extra space before the comma. `printf` is used here instead of `cat` because `cat` always inserts spaces between arguments.
88+
- `$all = cat $all "-"` appends a hyphen separator after the author prefix.
89+
- The final `if $all` chooses between two outputs: if an author prefix exists, concatenate it with the title; otherwise output only `.Title`.
90+
91+
In plain English, the advanced sample means: "Build a file name from the first author's last/first/middle name, add `и др` or `, et al` when there are multiple authors, add a hyphen separator, and then append the book title. If there are no authors, use only the title."
92+
93+
Advanced example using a list of filename parts:
94+
95+
```yaml
96+
document:
97+
output_name_template: |
98+
{{- $parts := list -}}
99+
{{- if gt (len .Authors) 0 -}}
100+
{{- with first .Authors -}}
101+
{{- $author := .LastName -}}
102+
{{- if .FirstName -}}
103+
{{- $author = printf "%s %s." $author (first (splitList "" .FirstName)) -}}
104+
{{- end -}}
105+
{{- $parts = append $parts $author -}}
106+
{{- end -}}
107+
{{- end -}}
108+
{{- if gt (len .Series) 0 -}}
109+
{{- with first .Series -}}
110+
{{- if gt .Number 0 -}}
111+
{{- $parts = append $parts (printf "%02d" .Number) -}}
112+
{{- end -}}
113+
{{- end -}}
114+
{{- end -}}
115+
{{- $parts = append $parts .Title -}}
116+
{{- printf "%s_%s" (join " " $parts) .SourceFile -}}
117+
```
118+
119+
How this template works:
120+
121+
- `$parts := list` creates an empty list. This template builds the file name by appending pieces to that list.
122+
- `if gt (len .Authors) 0` checks whether any authors exist.
123+
- `with first .Authors` selects the first author and makes that author the current dot (`.`).
124+
- `$author := .LastName` creates a local author string initialized to the first author's last name.
125+
- `if .FirstName` checks whether the first author has a first name.
126+
- `splitList "" .FirstName` splits the first name into individual characters.
127+
- `first (splitList "" .FirstName)` takes the first character, effectively creating an initial.
128+
- `printf "%s %s." $author ...` formats the last name plus first initial, such as `Иванов И.` or `Doe J.`.
129+
- `$parts = append $parts $author` appends the author string to the `$parts` list.
130+
- After the author block, `if gt (len .Series) 0` checks whether the book has series metadata.
131+
- `with first .Series` selects the first series entry.
132+
- `if gt .Number 0` checks whether the series number is present and greater than zero.
133+
- `printf "%02d" .Number` formats the series number as two digits, such as `01`, `02`, or `12`.
134+
- `$parts = append $parts ...` appends that formatted series number to the filename parts.
135+
- `$parts = append $parts .Title` always appends the book title.
136+
- `join " " $parts` joins all accumulated parts with spaces.
137+
- `printf "%s_%s" ... .SourceFile` appends an underscore and the original source file base name. This can help keep names unique when metadata is duplicated.
138+
139+
In plain English, this sample means: "Build a file name from first-author last name and initial, optional two-digit series number, book title, and original source filename."
140+
35141
Available fields:
36142

37143
| Field | Meaning |
@@ -74,6 +180,26 @@ document:
74180
{{- if .MiddleName }} {{ .MiddleName }}{{ end -}}
75181
```
76182

183+
How the `title_template` works:
184+
185+
- `if gt (len .Series) 0` checks whether the book has at least one series entry.
186+
- `with first .Series` switches the current dot (`.`) to the first series entry.
187+
- `{{ .Name }}` writes that series name.
188+
- `printf "%02d" .Number` formats the series number as a two-digit integer. For example, `1` becomes `01` and `12` stays `12`.
189+
- The literal punctuation outside actions, such as `(`, ` - `, `)`, and spaces, is copied directly to the output.
190+
- After the series prefix, `{{ .Title }}` writes the original book title from the metadata context.
191+
192+
In plain English, the title sample means: "If the book belongs to a series, prefix the title with `(Series Name - 01)`, then write the book title."
193+
194+
How the `creator_name_template` works:
195+
196+
- `.LastName`, `.FirstName`, and `.MiddleName` come from the current author. This template is executed once per author.
197+
- `{{- .LastName -}}` writes the last name and trims surrounding whitespace.
198+
- `if .FirstName` writes the comma and first name only when a first name is present.
199+
- `if .MiddleName` writes the middle name only when a middle name is present.
200+
201+
In plain English, the author sample means: "Render each author as `LastName, FirstName MiddleName`, omitting missing name parts."
202+
77203
## `label_template`
78204

79205
Formats logical footnote labels. See [Footnotes](footnotes.md) for mode-specific behavior.
@@ -100,6 +226,67 @@ document:
100226
{{- end -}}
101227
```
102228

229+
How this template works:
230+
231+
- `.BodyNumber` is the logical footnote body number. It is `0` when the book has only one footnote body, so single-body books do not need a body prefix.
232+
- `.NoteNumber` is the sequential number of the note inside that body.
233+
- `if gt .BodyNumber 0` checks whether a body number should be shown.
234+
- `printf "%d.%d" .BodyNumber .NoteNumber` formats two integers separated by a dot, such as `2.17`.
235+
- The `else` branch is used when `.BodyNumber` is `0`.
236+
- `printf "%d" .NoteNumber` formats just the note number, such as `17`.
237+
238+
In plain English, the sample means: "Use `body.note` numbering when there are multiple footnote bodies; otherwise use just the note number."
239+
240+
PDF-aware example that uses note titles when they look meaningful:
241+
242+
```yaml
243+
document:
244+
footnotes:
245+
label_template: |
246+
{{- if eq .Format "pdf" -}}
247+
{{- $bodyTitle := default "Notes" .BodyTitle -}}
248+
{{- $noteTitle := trim .NoteTitle -}}
249+
{{- $noteNumber := printf "%d" .NoteNumber -}}
250+
{{- $label := "" -}}
251+
{{- if gt .BodyNumber 0 -}}
252+
{{- $label = printf "%d.%s" .BodyNumber $noteNumber -}}
253+
{{- else -}}
254+
{{- $label = $noteNumber -}}
255+
{{- end -}}
256+
{{- if and $noteTitle (regexMatch "[^0-9[:space:]]" $noteTitle) -}}
257+
{{- printf "%s: %s" $bodyTitle $noteTitle -}}
258+
{{- else -}}
259+
{{- printf "%s: %s" $bodyTitle $label -}}
260+
{{- end -}}
261+
{{- else -}}
262+
{{- if gt .BodyNumber 0 -}}
263+
{{- printf "%d" .BodyNumber -}}.
264+
{{- end -}}
265+
{{- printf "%d" .NoteNumber -}}
266+
{{- end -}}
267+
```
268+
269+
How this template works:
270+
271+
- `if eq .Format "pdf"` creates a separate branch for PDF output.
272+
- `default "Notes" .BodyTitle` is a slim-sprig helper. It returns `.BodyTitle` when it is non-empty; otherwise it returns `Notes`.
273+
- `$bodyTitle := ...` stores that result in a variable so it can be reused.
274+
- `trim .NoteTitle` removes leading and trailing whitespace from the original note title.
275+
- `$noteNumber := printf "%d" .NoteNumber` converts the numeric note number to a string.
276+
- `$label := ""` creates a variable that will hold the generated numeric label.
277+
- `if gt .BodyNumber 0` checks whether the note belongs to one of multiple footnote bodies.
278+
- `printf "%d.%s" .BodyNumber $noteNumber` builds a body-prefixed label such as `2.17`.
279+
- If `.BodyNumber` is `0`, `$label = $noteNumber` uses only the note number, such as `17`.
280+
- `and $noteTitle (regexMatch "[^0-9[:space:]]" $noteTitle)` checks two things: the note title is non-empty, and it contains at least one character that is not a digit or whitespace.
281+
- `regexMatch "[^0-9[:space:]]" $noteTitle` treats titles like `17` or ` 17 ` as plain numbering, but titles like `Translator note` as meaningful text.
282+
- If the title looks meaningful, `printf "%s: %s" $bodyTitle $noteTitle` renders something like `Notes: Translator note`.
283+
- Otherwise, `printf "%s: %s" $bodyTitle $label` renders something like `Notes: 17` or `Comments: 2.17`.
284+
- The final `else` branch is for non-PDF formats.
285+
- In the non-PDF branch, `printf "%d" .BodyNumber` writes the body number only when it is greater than zero, then a literal dot is emitted outside the template action.
286+
- `printf "%d" .NoteNumber` writes the note number.
287+
288+
In plain English, this sample means: "For PDF, make printed footnote title text from the footnote body title plus either a meaningful source note title or a generated numeric label. For non-PDF formats, use compact numeric labels like `17` or `2.17`."
289+
103290
## `backlink_template`
104291

105292
Formats generated return links from footnotes back to the original reference. See [Footnotes](footnotes.md#backlink_template) for cross-format behavior.
@@ -137,10 +324,56 @@ document:
137324
{{- end -}}
138325
```
139326

327+
How this template works:
328+
329+
- `and (eq .Format "pdf") .PageNumber` combines two checks. It is true only when the output format is PDF and `.PageNumber` is non-zero.
330+
- `eq .Format "pdf"` compares the current output format with the string `pdf`.
331+
- `.PageNumber` by itself is treated as false when it is `0` and true when it is non-zero.
332+
- `printf "[page %d]" .PageNumber` formats a backlink label such as `[page 23]`.
333+
- `else if .LocationNumber` is used when the PDF page condition did not match but a location number is available.
334+
- `printf "[loc %d]" .LocationNumber` formats a label such as `[loc 183]`.
335+
- `else if .SectionTitle` uses the nearest section title when no page or location number is available.
336+
- `printf "[%s]" .SectionTitle` formats that string inside square brackets.
337+
- The final `else` branch returns the compact fallback marker `[<]`.
338+
339+
In plain English, the sample means: "Prefer exact PDF page numbers, otherwise use a generated location, otherwise use the source section title, otherwise use a generic back marker."
340+
140341
Markdown note: in Markdown, `.Href` is also used as the actual Markdown backlink target, so visible template text and clickable destination correspond.
141342

142343
## TOC Page Author Template
143344

144345
`document.toc_page.authors_template` formats author text on the optional visible TOC page.
145346

146347
Use it when you want a visible table of contents page to display author names differently from metadata.
348+
349+
Example:
350+
351+
```yaml
352+
document:
353+
toc_page:
354+
authors_template: |
355+
{{- $names := list -}}
356+
{{- range .Authors -}}
357+
{{- $name := list -}}
358+
{{- if .FirstName -}}{{ $name = append $name .FirstName -}}{{- end -}}
359+
{{- if .MiddleName -}}{{ $name = append $name .MiddleName -}}{{- end -}}
360+
{{- if .LastName -}}{{ $name = append $name .LastName }}{{- end -}}
361+
{{- $names = append $names (join " " $name) -}}
362+
{{- end -}}
363+
{{- join ", " $names -}}
364+
```
365+
366+
How this template works:
367+
368+
- `$names := list` creates an empty list that will hold one formatted string per author.
369+
- `range .Authors` loops over all authors. Inside the `range` block, dot (`.`) is the current author.
370+
- `$name := list` creates a fresh empty list for the current author's name parts.
371+
- `if .FirstName` checks whether the current author has a first name. If yes, `append $name .FirstName` adds it to the current author's name-part list.
372+
- `if .MiddleName` does the same for the middle name.
373+
- `if .LastName` does the same for the last name.
374+
- `join " " $name` joins the current author's available name parts with spaces. Missing parts are skipped, so there are no doubled spaces.
375+
- `$names = append $names (join " " $name)` appends the completed current-author string to the outer `$names` list.
376+
- After `end`, the loop is finished and `$names` contains all formatted authors.
377+
- `join ", " $names` joins all formatted authors with comma-space separators.
378+
379+
In plain English, this sample means: "For each author, join the available first, middle, and last name parts with spaces, then join all authors with commas for display on the visible TOC page."

0 commit comments

Comments
 (0)