%% 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
