main
1// 部分取自 modern-nju-thesis
2
3// 双语参考文献
4#let bilingual-bibliography(
5 bibliography: none,
6 title: [参考文献#metadata((en: "References"))],
7 full: false,
8 style: "gb-7714-2005-numeric",
9 mapping: (:),
10 extra-comma-before-et-al-trans: false,
11 // 用于控制多位译者时表现为 `et al. tran`(false) 还是 `et al., tran`(true)
12 allow-comma-in-name: false,
13 // 如果使用的 CSL 中,英文姓名中会出现逗号,请设置为 true
14) = {
15 assert(
16 bibliography != none,
17 message: "请传入带有 source 的 bibliography 函数。",
18 )
19
20 // Please fill in the remaining mapping table here
21 mapping = (
22 (
23 //"等": "et al",
24 "卷": "Vol.",
25 "册": "Bk.",
26 // "译": ", tran",
27 // "等译": "et al. tran",
28 // 注: 请见下方译者数量判断部分。
29 )
30 + mapping
31 )
32
33 let to-string(content) = {
34 if content.has("text") {
35 content.text
36 } else if content.has("children") {
37 content.children.map(to-string).join("")
38 } else if content.has("child") {
39 to-string(content.child)
40 } else if content.has("body") {
41 to-string(content.body)
42 } else if content == [ ] {
43 " "
44 }
45 }
46
47 show grid.cell.where(x: 1): it => {
48 // 后续的操作是对 string 进行的。
49 let ittext = to-string(it)
50 // 判断是否为中文文献:去除特定词组后,仍有至少两个连续汉字。
51 let pureittext = ittext.replace(
52 regex("[等卷册和版本章期页篇译间者(不详)]"),
53 "",
54 )
55 let ittext = if pureittext.find(regex("\p{sc=Hani}{2,}")) != none {
56 ittext
57 } else {
58 // 若不是中文文献,进行替换
59 // 第xxx卷、第xxx册的情况:变为 Vol. XXX 或 Bk. XXX。
60 let reptext = ittext
61 reptext = reptext.replace(
62 regex("(第\s?)?\d+\s?[卷册]"),
63 itt => {
64 if itt.text.contains("卷") {
65 "Vol. "
66 } else {
67 "Bk. "
68 }
69 itt.text.find(regex("\d+"))
70 },
71 )
72
73 // 第xxx版/第xxx本的情况:变为 1st ed 格式。
74 reptext = reptext.replace(
75 regex("(第\s?)?\d+\s?[版本]"),
76 itt => {
77 let num = itt.text.find(regex("\d+"))
78 num
79 if num.clusters().len() == 2 and num.clusters().first() == "1" {
80 "th"
81 } else {
82 (
83 "1": "st",
84 "2": "nd",
85 "3": "rd",
86 ).at(num.clusters().last(), default: "th")
87 }
88 " ed"
89 },
90 )
91
92 // 译者数量判断:单数时需要用 trans,复数时需要用 tran 。
93 /*
94 注:
95 1. 目前判断译者数量的方法非常草率:有逗号就是多个作者。但是在部分 GB/T 7714-2015 方言中,姓名中可以含有逗号。如果使用的 CSL 是姓名中含有逗号的版本,请将 bilingual-bibliography 的 allow-comma-in-name 参数设为 true。
96 2. 在 GB/T 7714-2015 原文中有 `等译`(P15 10.1.3 小节 示例 1-[1] 等),但未给出相应的英文缩写翻译。CSL 社区库内的 GB/T 7714-2015 会使用 `等, 译` 和 `et al., tran` 的写法。为使中英文与标准原文写法一致,本小工具会译作 `et al. tran`。若需要添加逗号,请将 bilingual-bibliography 的 extra-comma-before-et-al-trans 参数设为 true。
97 3. GB/T 7714-2015 P8 7.2 小节规定:“译”前需加逗号。因此单个作者的情形,“译” 会被替换为 ", trans"。与“等”并用时的情况请见上一条注。
98 如果工作不正常,可以考虑换为简单关键词替换,即注释这段情况,取消 13 行 mapping 内 `译` 条目的注释。
99 */
100 reptext = reptext.replace(
101 regex("\].+?译"),
102 itt => {
103 // 我想让上面这一行匹配变成非贪婪的,但加问号后没啥效果?
104 let comma-in-itt = itt.text.replace(regex(",?\s?译"), "").matches(",")
105 if (
106 type(comma-in-itt) == array
107 and comma-in-itt.len()
108 >= (
109 if allow-comma-in-name { 2 } else { 1 }
110 )
111 ) {
112 if extra-comma-before-et-al-trans {
113 itt.text.replace(regex(",?\s?译"), ", tran")
114 } else {
115 itt.text.replace(regex(",?\s?译"), " tran")
116 }
117 } else {
118 itt.text.replace(regex(",?\s?译"), ", trans")
119 }
120 },
121 )
122
123 // `等` 特殊处理:`等`后方接内容也需要译作 `et al.`,如 `等译` 需要翻译为 `et al. trans`
124 reptext = reptext.replace(
125 regex("等."),
126 itt => {
127 "et al."
128 // 如果原文就是 `等.`,则仅需简单替换,不需要额外处理
129 // 如果原文 `等` 后没有跟随英文标点,则需要补充一个空格
130 if not (
131 itt.text.last()
132 in (
133 ".",
134 ",",
135 ";",
136 ":",
137 "[",
138 "]",
139 "/",
140 "\\",
141 "<",
142 ">",
143 "?",
144 "(",
145 ")",
146 " ",
147 "\"",
148 "'",
149 )
150 ) {
151 " "
152 }
153 // 原文有英文句号时不需要重复句号,否则需要将匹配到的最后一个字符吐回来
154 if not itt.text.last() == "." {
155 itt.text.last()
156 }
157 },
158 )
159
160 // 其他情况:直接替换
161 reptext = reptext.replace(
162 regex("\p{sc=Hani}+"),
163 itt => {
164 mapping.at(itt.text, default: itt.text)
165 // 注意:若替换功能工作良好,应该不会出现 `default` 情形
166 },
167 )
168 reptext
169 }
170
171 // 判断文献类型的方括号前是否为中文
172 // 如果不是中文且不是空格,加一个空格
173 // 并且 style 应为 gb-7714
174 if style.starts-with("gb-7714") {
175 ittext = ittext.replace(
176 regex("(.)\[([A-Z])"),
177 itt => {
178 if itt.captures.at(0) != none {
179 let char = itt.captures.at(0)
180 if char.match(regex("\p{sc=Hani}")) == none and char != " " {
181 char + " ["
182 } else {
183 char + "["
184 }
185 }
186 itt.captures.at(1)
187 },
188 )
189 }
190 ittext
191 }
192
193 set text(lang: "zh")
194 bibliography(
195 title: title,
196 full: full,
197 style: style,
198 )
199}