%% biblatex-apa-zh.sty %% 繁體中文行文的 APA 7 引用呈現層(biblatex-apa 的補丁,不是獨立 style) %% %% 輸出的是繁體字串(「等人」「與」「、」),書目標點採臺灣的學術慣例。 %% 簡體中文的慣例不同,本版不涵蓋。 %% %% Copyright (C) 2026 Che Cheng %% This work may be distributed and/or modified under the conditions of the %% LaTeX Project Public License, either version 1.3c or any later version. %% %% --------------------------------------------------------------------------- %% 這個套件解決什麼 %% --------------------------------------------------------------------------- %% biblatex-apa 實作 APA 7,但它的在地化檔(.lbx)出了二十幾種語言就是沒有中文。 %% 用中文寫作、引用外文文獻時會出現兩個問題: %% %% 1. 括號式引用印成半形:(Meehl & Hathaway, 1946) %% 中文行文的標點規範要求全形:(Meehl & Hathaway,1946) %% %% 2. 「等人/與」無法逐筆切換。andothers 是全域字串,中英文獻混排時 %% 兩邊會被套成同一種。 %% %% --------------------------------------------------------------------------- %% 兩個軸,兩套機制(這是本套件的核心設計) %% --------------------------------------------------------------------------- %% 內文語言 → 決定「標點」(括號、逗號全形或半形)→ 文件層設定 %% 一份 PDF 只有一種內文語言,所以是選項不是欄位。 %% %% 文獻語言 → 決定「字串與姓名」(et al./等人、&/與)→ 逐筆條目 %% 靠 .bib 的 langid 欄位。同一份參考文獻表可以中英並存。 %% %% biblatex 原生的逐筆切換(autolang=langname + \DeclareLanguageMapping)依賴 %% babel/polyglossia。用 xeCJK 而不載 babel 的文件(中文 LaTeX 的常見組態)沒有 %% 那條路,所以本套件改成直接判斷 langid 欄位,不要求 babel。 %% %% --------------------------------------------------------------------------- %% 用法 %% --------------------------------------------------------------------------- %% \usepackage[style=apa, backend=biber]{biblatex} %% \usepackage[prose=chinese]{biblatex-apa-zh} % 必須在 biblatex 之後 %% %% 選項 %% prose=chinese|english 內文語言。預設 chinese %% foreignandothers=etal|zh 中文行文中,**外文**文獻的 et al. 怎麼印。 %% 預設 etal(保守:不改動既有文件的輸出) %% %% 中文文獻(.bib 裡寫 langid = {chinese})一律用「等人」與「與」,不受 %% foreignandothers 影響——那個選項只管外文文獻。 \NeedsTeXFormat{LaTeX2e} \ProvidesPackage{biblatex-apa-zh}[2026/08/15 v0.2.0 APA 7 citation rendering for Chinese prose] \RequirePackage{kvoptions} \RequirePackage{etoolbox} \SetupKeyvalOptions{family=apazh, prefix=apazh@} \DeclareStringOption[chinese]{prose} \DeclareStringOption[etal]{foreignandothers} \ProcessKeyvalOptions* \@ifpackageloaded{biblatex}{}{% \PackageError{biblatex-apa-zh} {biblatex 尚未載入} {本套件是 biblatex-apa 的補丁,必須寫在 \string\usepackage{biblatex} 之後。}% } % --------------------------------------------------------------------------- % 一、標點:由內文語言決定 % --------------------------------------------------------------------------- % 只改「引用命令」的括號與逗號,不動參考文獻表——文獻表裡的 (2002)、15(3) % 屬於英文書目格式,APA 要求半形,跟內文語言無關。這個分界是本節的重點: % 把 \bibopenparen 整個改成全形會連文獻表一起改掉,那是錯的。 \newcommand*{\apazh@parens}[1]{(#1)} \newcommand*{\apazh@comma}{,} \ifdefstring{\apazh@prose}{chinese}{% % \parencite:APA 的 (Author, year)。中文行文改全形括號與全形逗號。 % % 為什麼要整個 \DeclareCiteCommand 重寫而不是只設 \DeclareFieldFormat{parens}: % \parencite 的外框走 \mkbibparens → \bibopenparen,**不吃** parens 這個 % field format。只設 field format 會安靜地沒有效果(踩過,見 README 的 % 「已知陷阱」)。 \DeclareCiteCommand{\parencite}[\apazh@parens] {\usebibmacro{prenote}} {\usebibmacro{citeindex}% \printtext[bibhyperref]{% \printnames{labelname}% \setunit{\apazh@comma\space}% \printfield{year}}} {\multicitedelim} {\usebibmacro{postnote}} % \textcite:APA 的 Author (year)。名字在文句裡,只有年份進括號。 \DeclareCiteCommand{\textcite} {\boolfalse{cbx:parens}} {\usebibmacro{citeindex}% \printtext[bibhyperref]{\printnames{labelname}}% \setunit{}% \printtext[bibhyperref]{\apazh@parens{\printfield{year}}}} {\multicitedelim} {} % \autocite 不必額外處理,上面重寫 \parencite 就會傳導過去。 % % 這裡曾經放過一行 \ExecuteBibliographyOptions{autocite=inline}「重新綁定」, % 依據是「biblatex 在處理選項當下就把 \autocite 綁到當時的 \parencite」。 % 那個依據是錯的:biblatex.sty:15906 的 \letcs\autocite{blx@acite@inline} 綁的是 % 中介巨集,而 biblatex.def:2667 的 \DeclareAutoCiteCommand{inline}{\parencite} % 讓該巨集在**使用時**才去找 \parencite。所以重定義本來就會生效。 % % 實測:把那行註解掉,autocite 固件照樣全綠——正因為它是無效程式碼。 % 保留這段註解是因為錯誤的診斷會再長回來;沒有記錄的話,下一個人看到 % \autocite 出問題時會再加一次那行,然後以為是它修好的。 }{} % --------------------------------------------------------------------------- % 二、字串:由文獻語言決定(逐筆) % --------------------------------------------------------------------------- % \bibstring{andothers} 是全域的,所以這裡改的是印出它的那個 bibmacro, % 依該筆條目的 langid 分流。定義照抄 biblatex.def 的 name:andothers, % 只把最後印字串那一步換成條件式。 \newcommand*{\apazh@andothers}{% \iffieldequalstr{langid}{chinese} {等人}% {\ifdefstring{\apazh@foreignandothers}{zh} {等人}% {\bibstring{andothers}}}% } % 定義照抄 biblatex.def 的 name:andothers,只換掉最後印字串那一步。 % % 中文文獻走另一條分支:不加 \finalandcomma、不印 andothersdelim。那兩個是為 % 西文姓名設計的(逗號與空格),套在中文上會排成「陳一, 等人」。中文的寫法是 % 姓名直接接「等人」。 \renewbibmacro*{name:andothers}{% \ifboolexpr{ test {\ifnumequal{\value{listcount}}{\value{liststop}}} and test \ifmorenames } {\iffieldequalstr{langid}{chinese} {等人}% {\ifnumgreater{\value{liststop}}{1} {\finalandcomma} {}% \printdelim{andothersdelim}\apazh@andothers}}% {}% } % 中文文獻最後兩位作者之間用「與」,且**前後不加空格**——中文姓名之間插西文 % 空格會排成「王四 與 李五」。外文文獻維持 APA 原樣。 % % 必須分兩個 delimiter context 各寫一次。APA 對這兩者的規定本來就不同: % 敘述式(textcite)用 "and"、括號式(parencite)用 "&"。biblatex-apa 因此在 % apa.cbx:477 另外宣告了 [parencite] 版本,只覆寫預設 context 的話,括號式 % 會安靜地維持 & 不變(v0.1 實測踩到)。 \DeclareDelimFormat{finalnamedelim}{% \iffieldequalstr{langid}{chinese} {與}% {\ifnumgreater{\value{liststop}}{2}{\finalandcomma}{}% \addspace\bibstring{and}\space}% } \DeclareDelimFormat[parencite]{finalnamedelim}{% \iffieldequalstr{langid}{chinese} {與}% {\ifnum\value{liststop}>2 \finalandcomma\fi\addspace\&\space}% } \DeclareDelimAlias[nptextcite]{finalnamedelim}[parencite]{finalnamedelim} % 參考文獻表是第三個 context(apa.bbx:704 另外宣告了 [bib,biblist])。 % 只改內文的話,文獻表會留著「陳一、林二, & 黃三」這種半套結果。 % 非中文的分支逐字抄自 apa.bbx:704,**含 \maxprtauth 那道守衛**。 % 自己重寫看起來會過,但作者數超過 maxprtauth 被截斷時原版不印分隔符、 % 重寫版會印——那種差異只在多作者條目上出現,很難在一般測試裡看到。 % 覆寫既有 delimiter 時一律抄原文再加分支,不要憑印象重寫。 \DeclareDelimFormat[bib,biblist]{finalnamedelim}{% \iffieldequalstr{langid}{chinese} {與}% {\ifthenelse{\value{listcount}>\maxprtauth} {} {\ifthenelse{\value{liststop}>2} {\finalandcomma\addspace\&\space} {\addspace\&\space}}}% } % --------------------------------------------------------------------------- % 三、中文文獻的書目格式(v0.2) % --------------------------------------------------------------------------- % 中文書目的標點與英文不同:欄位之間用「。」、年份用全形括號、頁碼前用「,」。 % % 英文:Meehl, P. E., & Hathaway, S. R. (1946). The K factor... 30(5), 525-564. % 中文:王四與李五(2021)。學習動機量表的跨年級測量恆等性。教育心理學報,52(3),45-68。 % % 逐筆條目的標點靠 \AtEveryBibitem 局部重定義。實測確認它侷限在該筆條目內, % 不會外溢到英文條目——這是本節可行的前提。 \AtEveryBibitem{% \iffieldequalstr{langid}{chinese}{% \renewcommand*{\newunitpunct}{。}% \renewcommand*{\finentrypunct}{。}% \renewcommand*{\bibpagespunct}{,}% % 期刊名與卷之間走 \addcomma(article driver 的 \setunit*{\addcomma\space})。 % 在中文條目內整個換成全形逗號並吃掉後面的空格。 % 影響範圍僅限本筆條目:作者之間走 multinamedelim(頓號)、頁碼範圍走短破折號, % 都不經過 \addcomma,所以這裡不會誤傷。 \renewcommand*{\addcomma}{,}% \renewcommand*{\addspace}{}% }{}% } % 年份的括號。apa.bbx:733 用 \mkbibparens 包,這裡改成全形。 % % 條件寫在格式定義裡、而不是塞進 \AtEveryBibitem,是因為 hook body 的 # 展開 % 層級與一般巨集定義不同:在 hook 裡寫 \DeclareFieldFormat{apadate}{(##1)} % 會印出「(1)」而不是年份(實測踩到)。宣告一次、條件在內部,沒有這個問題。 % % 非中文分支逐字抄自 apa.bbx:733,含 circa/uncertain 那條支線。 \DeclareFieldFormat{apadate}{% \iffieldequalstr{langid}{chinese} {(#1)}% {\ifboolexpr{ test {\ifdatecirca} or test {\ifdateuncertain} } {\mkbibbrackets{#1}} {\mkbibparens{#1}}}% } % 作者與年份之間:中文不加標點(「王四與李五(2021)」),英文維持原樣。 % apa.bbx:630 原本宣告成 \newunitpunct,而上面把中文的 \newunitpunct 改成了 % 「。」,不覆寫的話會排成「王四與李五。(2021)」。 \DeclareDelimFormat[bib,biblist]{nameyeardelim}{% \iffieldequalstr{langid}{chinese}{}{\newunitpunct}% } % 中文文獻的作者之間用頓號,不用半形逗號加空格。 % % multinamedelim 只有 biblatex.def:84 一份定義(APA 沒有覆寫),所以覆寫預設 % context 就涵蓋內文與文獻表兩邊,不必逐 context 再寫。這與下面的 % finalnamedelim 不同——那個 APA 宣告了三份。 \DeclareDelimFormat{multinamedelim}{% \iffieldequalstr{langid}{chinese}{、}{\addcomma\space}% } \endinput