Add MPI Typst template
This commit is contained in:
@@ -112,6 +112,32 @@ When editing `.dj` files, use `patch` (mode='replace') — not regex-based
|
|||||||
string replacement in `execute_code`. `patch` is safer, surfaces conflicts,
|
string replacement in `execute_code`. `patch` is safer, surfaces conflicts,
|
||||||
and produces a diff you can review.
|
and produces a diff you can review.
|
||||||
|
|
||||||
|
## Typst Bilingual Template
|
||||||
|
|
||||||
|
For producing PDFs from bilingual Chinese-English articles:
|
||||||
|
|
||||||
|
- Repo / project root: `~/documents/mpi/`
|
||||||
|
- Template directory (contains `lib/`): `~/documents/mpi/translate-files/`
|
||||||
|
- Template: `translate-files/lib/mpi-bilingual-template.typ`
|
||||||
|
- Example host: `translate-files/从物品整理到心灵整理/mindful-organizing.typ`
|
||||||
|
- Design notes: `references/typst-template-design.md`
|
||||||
|
|
||||||
|
Host files should contain only one `#import` and one `#show:` rule; all
|
||||||
|
formatting is handled by the template.
|
||||||
|
|
||||||
|
Compile with the helper script:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
~/documents/mpi/scripts/compile-typst.fish ./从物品整理到心灵整理/mindful-organizing.typ [output.pdf]
|
||||||
|
```
|
||||||
|
|
||||||
|
Or manually from the template directory:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd ~/documents/mpi/translate-files
|
||||||
|
typst compile --root . ./从物品整理到心灵整理/mindful-organizing.typ
|
||||||
|
```
|
||||||
|
|
||||||
## Scripts
|
## Scripts
|
||||||
|
|
||||||
Utility scripts in `scripts/` (fish for CLI wrappers, Python for data processing).
|
Utility scripts in `scripts/` (fish for CLI wrappers, Python for data processing).
|
||||||
|
|||||||
Executable
+20
@@ -0,0 +1,20 @@
|
|||||||
|
#!/usr/bin/env fish
|
||||||
|
# Compile a Typst file to PDF.
|
||||||
|
# Usage: compile-typst <path-to-file.typ> [output.pdf]
|
||||||
|
# Output defaults to /tmp/<basename>.pdf
|
||||||
|
# The Typst project root is set to the parent of the file's directory
|
||||||
|
# (so imports like ../lib/... resolve correctly).
|
||||||
|
|
||||||
|
set src (realpath $argv[1])
|
||||||
|
set src_dir (dirname $src)
|
||||||
|
set root (dirname $src_dir)
|
||||||
|
|
||||||
|
if set -q argv[2]
|
||||||
|
set out "$argv[2]"
|
||||||
|
else
|
||||||
|
set base (basename $src .typ)
|
||||||
|
set out "/tmp/$base.pdf"
|
||||||
|
end
|
||||||
|
|
||||||
|
typst compile --root $root $src $out
|
||||||
|
echo $out
|
||||||
@@ -0,0 +1,136 @@
|
|||||||
|
// MPI Bilingual Chinese-English Template
|
||||||
|
// ============================================================
|
||||||
|
// A simple Typst template for bilingual Chinese-English Buddhist
|
||||||
|
// texts, matching the 静心学堂丛书 formatting guide.
|
||||||
|
//
|
||||||
|
// Fonts (all available from Google Fonts):
|
||||||
|
// - Chinese body: Noto Serif CJK SC
|
||||||
|
// - English body: Noto Serif (Times New Roman substitute)
|
||||||
|
//
|
||||||
|
// Format highlights:
|
||||||
|
// - Body size: 10.5pt (Chinese 五号)
|
||||||
|
// - Line spacing: 1.5em
|
||||||
|
// - Justified body text with 2em first-line indent
|
||||||
|
// - Headings unnumbered, with 1.2em block spacing
|
||||||
|
// - Footnotes in 8pt, left aligned
|
||||||
|
// ============================================================
|
||||||
|
|
||||||
|
#let chinese-font = "Noto Serif CJK SC"
|
||||||
|
#let english-font = "Noto Serif"
|
||||||
|
|
||||||
|
// Convert any content to a plain string.
|
||||||
|
#let to-string(content) = {
|
||||||
|
if type(content) == str {
|
||||||
|
content
|
||||||
|
} else if content.func() == text {
|
||||||
|
content.text
|
||||||
|
} else if content.has("children") {
|
||||||
|
content.children.map(to-string).join("")
|
||||||
|
} else {
|
||||||
|
""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return true if the content is primarily Chinese.
|
||||||
|
#let is-chinese(content) = {
|
||||||
|
let txt = to-string(content)
|
||||||
|
let cn-re = regex("[\u{4e00}-\u{9fff}]")
|
||||||
|
let en-re = regex("[A-Za-z]")
|
||||||
|
for c in txt.clusters() {
|
||||||
|
if c.match(cn-re) != none { return true }
|
||||||
|
if c.match(en-re) != none { return false }
|
||||||
|
}
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bilingual table of contents.
|
||||||
|
// Only English headings show dotted leaders and page numbers;
|
||||||
|
// Chinese headings are shown compactly as section headers.
|
||||||
|
#let toc() = context {
|
||||||
|
let indent-per-level = 1.5em
|
||||||
|
for h in query(heading.where(outlined: true)) {
|
||||||
|
let cn = is-chinese(h.body)
|
||||||
|
block(
|
||||||
|
inset: (left: (h.level - 1) * indent-per-level),
|
||||||
|
above: if cn { 0.3em } else { 0.7em },
|
||||||
|
below: if cn { 0.7em } else { 1.2em },
|
||||||
|
{
|
||||||
|
if cn {
|
||||||
|
h.body
|
||||||
|
} else {
|
||||||
|
let page-num = counter(page).at(h.location()).first()
|
||||||
|
h.body + box(width: 1fr, repeat[.]) + str(page-num)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Document class.
|
||||||
|
//
|
||||||
|
// title-cn, title-en, subtitle-cn, subtitle-en accept free Typst content.
|
||||||
|
// The template centers them and applies only size/weight; the global font
|
||||||
|
// stack handles Chinese vs English glyphs.
|
||||||
|
#let mpi-bilingual(
|
||||||
|
title-cn: none,
|
||||||
|
title-en: none,
|
||||||
|
subtitle-cn: none,
|
||||||
|
subtitle-en: none,
|
||||||
|
show-toc: true,
|
||||||
|
body,
|
||||||
|
) = {
|
||||||
|
// Base text: Chinese font first, then English fallback.
|
||||||
|
set text(font: (chinese-font, english-font), size: 10.5pt, lang: "zh")
|
||||||
|
|
||||||
|
// A4 page with 2.5cm margins.
|
||||||
|
set page(
|
||||||
|
paper: "a4",
|
||||||
|
margin: (top: 2.5cm, bottom: 2.5cm, left: 2.5cm, right: 2.5cm),
|
||||||
|
numbering: "1",
|
||||||
|
)
|
||||||
|
|
||||||
|
// Body paragraphs: justified, 1.5 line spacing, 2em first-line indent,
|
||||||
|
// with a blank line's worth of space between paragraphs.
|
||||||
|
set par(justify: true, leading: 1.5em, spacing: 1.5em, first-line-indent: (amount: 2em, all: true))
|
||||||
|
|
||||||
|
// Headings: no numbering, bold, with generous block spacing.
|
||||||
|
set heading(numbering: none)
|
||||||
|
show heading: it => block(above: 2em, below: 1.2em, it.body)
|
||||||
|
|
||||||
|
// Footnotes: 8pt, left aligned.
|
||||||
|
show footnote: set text(size: 8pt)
|
||||||
|
set footnote.entry(indent: 0pt)
|
||||||
|
|
||||||
|
// Title page.
|
||||||
|
align(center)[
|
||||||
|
#set par(leading: 1.5em, spacing: 0pt)
|
||||||
|
#if title-cn != none {
|
||||||
|
text(size: 1.4em, weight: "bold")[#title-cn]
|
||||||
|
}
|
||||||
|
#if subtitle-cn != none {
|
||||||
|
linebreak()
|
||||||
|
subtitle-cn
|
||||||
|
}
|
||||||
|
#v(1.5em)
|
||||||
|
#if title-en != none {
|
||||||
|
text(size: 1.2em, weight: "bold")[#title-en]
|
||||||
|
}
|
||||||
|
#if subtitle-en != none {
|
||||||
|
linebreak()
|
||||||
|
subtitle-en
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
v(2.5em)
|
||||||
|
|
||||||
|
// Table of contents.
|
||||||
|
if show-toc {
|
||||||
|
align(center)[#text(size: 1.2em)[目录 / Contents]]
|
||||||
|
v(0.8em)
|
||||||
|
toc()
|
||||||
|
pagebreak()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Main body.
|
||||||
|
body
|
||||||
|
}
|
||||||
@@ -1,45 +0,0 @@
|
|||||||
// Helper functions for the bilingual outline and table of contents.
|
|
||||||
|
|
||||||
#let to-string(content) = {
|
|
||||||
if type(content) == str {
|
|
||||||
content
|
|
||||||
} else if content.func() == text {
|
|
||||||
content.text
|
|
||||||
} else if content.has("children") {
|
|
||||||
content.children.map(to-string).join("")
|
|
||||||
} else {
|
|
||||||
""
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#let is-chinese-heading(content) = {
|
|
||||||
let txt = to-string(content)
|
|
||||||
let cn-re = regex("[\u{4e00}-\u{9fff}]")
|
|
||||||
let en-re = regex("[A-Za-z]")
|
|
||||||
for c in txt.clusters() {
|
|
||||||
if c.match(cn-re) != none { return true }
|
|
||||||
if c.match(en-re) != none { return false }
|
|
||||||
}
|
|
||||||
false
|
|
||||||
}
|
|
||||||
|
|
||||||
#let toc() = context {
|
|
||||||
let indent-per-level = 1.5em
|
|
||||||
let headings = query(heading.where(outlined: true))
|
|
||||||
for h in headings {
|
|
||||||
let is-cn = is-chinese-heading(h.body)
|
|
||||||
block(
|
|
||||||
inset: (left: (h.level - 1) * indent-per-level),
|
|
||||||
above: if is-cn { 0.3em } else { 0.7em },
|
|
||||||
below: if is-cn { 0.7em } else { 1.2em },
|
|
||||||
{
|
|
||||||
if is-cn {
|
|
||||||
h.body
|
|
||||||
} else {
|
|
||||||
let page-num = counter(page).at(h.location()).first()
|
|
||||||
h.body + box(width: 1fr, repeat[.]) + str(page-num)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,33 +1,14 @@
|
|||||||
// Auto-generated from DOCX via pandoc + cleanup
|
// Auto-generated from DOCX via pandoc + cleanup
|
||||||
#set text(font: ("Noto Serif CJK SC", "Noto Serif"), size: 11pt, lang: "zh")
|
// Reformatted to use lib/mpi-bilingual-template.typ
|
||||||
#set page(margin: (top: 2.5cm, bottom: 2.5cm, left: 2.5cm, right: 2.5cm), numbering: "1")
|
|
||||||
#set heading(numbering: none)
|
|
||||||
#set par(justify: true, leading: 0.8em)
|
|
||||||
#show heading: set block(spacing: 1.2em)
|
|
||||||
|
|
||||||
#import "helpers.typ": toc
|
#import "../lib/mpi-bilingual-template.typ": mpi-bilingual
|
||||||
|
|
||||||
#align(center)[
|
#show: mpi-bilingual.with(
|
||||||
#heading(outlined: false)[从物品整理到心灵整理]
|
title-cn: [从物品整理到心灵整理],
|
||||||
#v(0.5em)
|
title-en: [From Organizing Belongings to Organizing the Mind],
|
||||||
——济群法师 2024年9月28日讲于泰宁甘露别院
|
subtitle-cn: [——济群法师 2024年9月28日讲于泰宁甘露别院],
|
||||||
]
|
subtitle-en: [—Lectured by Master Jiqun at Amrita Retreat Center, Taining, September 28, 2024],
|
||||||
|
)
|
||||||
#align(center)[
|
|
||||||
*From Organizing Belongings to Organizing the Mind*
|
|
||||||
#v(0.3em)
|
|
||||||
—Lectured by Master Jiqun at Amrita Retreat Center, Taining, September 28, 2024
|
|
||||||
]
|
|
||||||
|
|
||||||
#v(3em)
|
|
||||||
#align(center)[#text(size: 1.2em)[目录 / Contents]]
|
|
||||||
#v(0.8em)
|
|
||||||
#set page(numbering: none)
|
|
||||||
#toc()
|
|
||||||
#pagebreak()
|
|
||||||
#set page(numbering: "1")
|
|
||||||
|
|
||||||
#set par(first-line-indent: (amount: 2em, all: true))
|
|
||||||
|
|
||||||
静心整理的项目已经研发很长时间,我们原来还做过断舍离的项目。静心整理和断舍离,可以说是两个项目,也可以说是一个项目的两部分。为什么我们讲了断舍离,还要再讲静心整理?主要是因为,断舍离落实起来相对较难。关于这个问题,我曾问过项目组:虽然社会上一直在倡导断舍离,但相关从业者有多少?真正在实践的人有多少?其实并不多。因为对普通人来说,舍弃物品并非易事,出离物欲更是难上加难。
|
静心整理的项目已经研发很长时间,我们原来还做过断舍离的项目。静心整理和断舍离,可以说是两个项目,也可以说是一个项目的两部分。为什么我们讲了断舍离,还要再讲静心整理?主要是因为,断舍离落实起来相对较难。关于这个问题,我曾问过项目组:虽然社会上一直在倡导断舍离,但相关从业者有多少?真正在实践的人有多少?其实并不多。因为对普通人来说,舍弃物品并非易事,出离物欲更是难上加难。
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user