当加载roboto
默认使用浅色字体的包时,暂时切换到不同的字体粗细会导致siunitx
无法检测正确的字体。
\documentclass{article}
\usepackage[light,medium]{roboto}
\providecommand*\lseries{\fontseries{l}\selectfont}
\usepackage{siunitx}
\sisetup{detect-all=true}
\begin{document}
\sffamily
1\,mV \SI{1}{\milli\volt}
\fontseries{m}\selectfont%
1\,mV \SI{1}{\milli\volt}
\end{document}
siunitx
当使用额外的字体粗细时,检测字体粗细似乎会有些麻烦,例如这里或者这里。但是,在这种情况下,我无法理解这个问题,因为我改回了应该理解的默认权m
重siunitx
。这里的问题是什么?
答案1
问题在于 siunitx 的代码试图以类似的方式在数学和文本模式下工作。在数学中基本上只有普通和粗体,因此在文本模式下,siunitx 或多或少只尝试检测粗体是否处于活动状态,如果没有,则使用普通系列,这意味着这里是浅色字体。一种解决方法是本地重置默认系列。以下示例需要当前的 LaTeX 2020-02-02:
\documentclass{article}
\usepackage[light,medium]{roboto}
\providecommand*\lseries{\mdseries}
\usepackage{siunitx}
\sisetup{detect-all=true}
\begin{document}
\sffamily
1\,mV \SI{1}{\milli\volt} \textbf{1\,mV}
{\DeclareFontSeriesDefault[sf]{md}{m}\mdseries
1\,mV \SI{1}{\milli\volt}}
1\,mV \SI{1}{\milli\volt}
\end{document}
这里还隐藏着另一个问题:siunitx
通过查看当前系列是 b 还是 bx 来检测粗体。但是,您的设置是bx
针对罗马字体的,而不是sb
针对无衬线字体的,因此检测无衬线字体的粗细会失败:
\documentclass{article}
\usepackage[light,medium]{roboto}
\providecommand*\lseries{\mdseries}
\usepackage{siunitx}
\sisetup{detect-all=true}
\begin{document}
1\,mV \SI{1}{\milli\volt}
{\bfseries \makeatletter f@series is: \f@series. \quad
1\,mV \SI{1}{\milli\volt}}
\sffamily
1\,mV \SI{1}{\milli\volt}
{\bfseries \makeatletter f@series is: \f@series. \quad
1\,mV \SI{1}{\milli\volt}}
\end{document}
答案2
您可以尝试使用类似这样的方法进行正确的检测(以更通用的方式):
\documentclass{article}
\makeatletter
\newif\if@series@context
% test if current typesetting context is "\mdseries" or "\bfseries"
% in the current font family is one of the document meta families rm/sf/tt
% if not it works if it fits \mddefault or \bfdefault
% \IfSeriesContextTF {<either md or bf>}{<true code>}{<false code>}
\def\IfSeriesContextTF#1{%
\expand@font@defaults
\@series@contextfalse
\def\@test@context{#1}%
\expandafter\edef\csname ??def@ult\endcsname{\f@family}%
\let\@elt\test@series@context
\@meta@family@list
\@elt{??}%
\let\@elt\relax
\if@series@context
\expandafter\@firstoftwo
\else
\expandafter\@secondoftwo
\fi
}
\def\test@series@context#1{%
\edef\reserved@a{\csname #1def@ult\endcsname}%
\ifx\f@family\reserved@a
\let\@elt\@gobble
\typeout{Internal test 1: \csname\@test@context series@#1\endcsname=\f@series}%
\expandafter\ifx
\csname\@test@context series@#1\endcsname\f@series
\@series@contexttrue
\else
\typeout{Internal test 2: \csname\@test@context def@ult\endcsname=\f@series}%
\expandafter\ifx
\csname\@test@context def@ult\endcsname\f@series
\@series@contexttrue
\fi\fi\fi
}
% update to the current kernel
\def\expand@font@defaults{%
\edef\rmdef@ult{\rmdefault}%
\edef\sfdef@ult{\sfdefault}%
\edef\ttdef@ult{\ttdefault}%
\expandafter\series@maybe@drop@one@m\expandafter{\bfdefault}\bfdef@ult
\expandafter\series@maybe@drop@one@m\expandafter{\mddefault}\mddef@ult
\edef\famdef@ult{\familydefault}%
}
\DeclareFontSeriesDefault{bf}{bm} % this one may need adding to LaTeX as default
\makeatother
% test setup
\DeclareFontShape{OT1}{cmss}{l}{n}{<->alias * cmtt/m/n}{}
\DeclareFontShape{OT1}{cmss}{eb}{n}{<->alias * cmr/bx/n}{}
\DeclareFontSeriesDefault[rm]{bf}{b}
\DeclareFontSeriesDefault[sf]{md}{l}
\DeclareFontSeriesDefault[sf]{bf}{eb}
\newcommand\test[1]{\IfSeriesContextTF{#1}{\typeout{==> #1: T}}{\typeout{==> #1: F}}}
\begin{document}
\typeout{rm uses m/b in this doc}
\typeout{series = \csname f@series\endcsname}
\test{md}
\test{bf}
\bfseries
\typeout{series = \csname f@series\endcsname}
\test{md}
\test{bf}
\sffamily
\typeout{sf has l/eb}
\typeout{series = \csname f@series\endcsname}
\test{md}
\test{bf}
\mdseries
\typeout{series = \csname f@series\endcsname}
\test{md}
\test{bf}
\typeout{sf has "bx" but it is neither the bold nor the medium face per spec above}
\fontseries{bx}\selectfont
\typeout{series = \csname f@series\endcsname}
\test{md}
\test{bf}
\typeout{this is ptm not one of the meta families}
\fontfamily{ptm}\selectfont % neither "rm" "sf" or "tt"
\typeout{request bx is not recognized for ptm as bold}
\typeout{series = \csname f@series\endcsname}
\test{md}
\test{bf}
\bfseries
\typeout{but explicitly reasking for bfseries (which produces "b" now) does}
\typeout{series = \csname f@series\endcsname}
\test{md}
\test{bf}
\end{document}
我可能会在下一个版本中以某种方式添加它。
这将产生:
This is pdfTeX, Version 3.14159265-2.6-1.40.20 (TeX Live 2019) (preloaded format=pdflatex)
restricted \write18 enabled.
entering extended mode
(./Untitled-2.tex
LaTeX2e <2020-02-02> patch level 5
L3 programming layer <2020-02-25>
(/usr/local/texlive/2019/texmf-dist/tex/latex/base/article.cls
Document Class: article 2019/12/20 v1.4l Standard LaTeX document class
(/usr/local/texlive/2019/texmf-dist/tex/latex/base/size10.clo))
(/usr/local/texlive/2019/texmf-dist/tex/latex/l3backend/l3backend-pdfmode.def)
(./Untitled-2.aux)
rm uses m/b in this doc
series = m
Internal test 1: m=m
==> md: T
Internal test 1: b=m
Internal test 2: b=m
==> bf: F
series = b
Internal test 1: m=b
Internal test 2: m=b
==> md: F
Internal test 1: b=b
==> bf: T
sf has l/eb
series = eb
Internal test 1: l=eb
Internal test 2: m=eb
==> md: F
Internal test 1: eb=eb
==> bf: T
series = l
Internal test 1: l=l
==> md: T
Internal test 1: eb=l
Internal test 2: b=l
==> bf: F
sf has "bx" but it is neither the bold nor the medium face per spec above
series = bx
Internal test 1: l=bx
Internal test 2: m=bx
==> md: F
Internal test 1: eb=bx
Internal test 2: b=bx
==> bf: F
this is ptm not one of the meta families
(/usr/local/texlive/2019/texmf-dist/tex/latex/psnfss/ot1ptm.fd)
request bx is not recognized for ptm as bold
series = bx
Internal test 1: \mdseries@?? =bx
Internal test 2: m=bx
==> md: F
Internal test 1: \bfseries@?? =bx
Internal test 2: b=bx
==> bf: F
but explicitly reasking for bfseries (which produces "b" now) does
series = b
Internal test 1: \mdseries@?? =b
Internal test 2: m=b
==> md: F
Internal test 1: \bfseries@?? =b
Internal test 2: b=b
==> bf: T
(./Untitled-2.aux) )
No pages of output.
Transcript written on Untitled-2.log.
答案3
以 Ulrikes 为基础回答我想扩展她的解决方案,并提供更多背景信息,了解这里发生的事情,因为其中涉及许多不同的因素,使情况变得复杂。
首先,值得一提的是,它siunitx
可以在两种不同的模式,即mode=text
和mode=math
。siunitx
手动的关于此选项有如下说明。
该
mode
选项决定siunitx
打印输出时使用数学模式还是文本模式。选项包括math
和。使用数学模式时,使用数学字体打印文本,而在文本模式下则使用文本字体。这在视觉上有多明显取决于文档中使用的字体。[...] 如果开关为 ,text
则此选项无效。detect-mode
true
这里我只讨论这种mode=text
情况,因为 Roboto 是文本字体,而不是数学字体。因为mode=math
应该可以采用类似的方法。
由于需要检测字体粗细,我们需要知道存储在中的当前粗细是多少\f@series
。对于 Roboto 字体,此机制最近已更改。例如,在 2019/04/19 的软件包版本中,带有medium
选项的粗体字体定义为
\ifroboto@medium\def\bfseries@sf{medium}\fi
而对于 2019/12/11 的新版本,此值更改为
\ifroboto@medium\def\bfseries@sf{sb}\fi
这导致 Ulrike 指出需要当前版本的 LaTeX。类似地,许多显式单词(如light
或 )thin
被更改为简写形式(如l
或 )el
。这实际上不会给后续解决方案带来问题,但这意味着它需要适应软件包版本。
我首先解决了无法检测到常规粗细的问题,然后转向粗体文本的问题。Ulrike 表示,它siunitx
只会尝试找出粗体是否处于活动状态,而不会检查字体可能提供的额外粗细。因此,让我们看看siuntix
在文本模式。
\cs_new_protected:Npn \__siunitx_detect_font_weight_text: {
\tl_set:Nx \l__siunitx_tmpa_tl { \tl_head:N \f@series }
\str_if_eq:VnT \l__siunitx_tmpa_tl { b }
{
\cs_set:Npn \__siunitx_font_weight:
{
\boldmath
\bfseries
}
}
\str_if_eq:VnT \l__siunitx_tmpa_tl { l }
{ \cs_set:Npn \__siunitx_font_weight: { \lseries } }
}
因此,siunitx
查看是否\f@series
以字母开头b
,如果是,则设置粗体打印。但是它还检查是否\f@series
以字母开头l
,如果是,则发出\lseries
。因此,这看起来应该按原样工作,因为它会\lseries
为轻型 Roboto 发出,为中型 Roboto 不执行任何操作,并为以\f@series
开头设置粗体b
。
那么,为什么切换到中等 Roboto 后输出会出错?原来,为了在 sans 中设置数字和单位,siunitx
需要调用。现在,当通过或\sffamily
选择中等重量时,则计算为,其定义为\fontseries{m}\selectfont
\mdseries
\sffamily
\mdseries@sf
\ifroboto@light\def\mdseries@sf{l}
当roboto
包加载选项时light
。这意味着\sffamily
实际上明确切换回轻量级并产生错误的输出。我不太确定这应该归咎于哪个包,因为对于siunitx
和roboto
单独来说,它们的方法似乎合理,但结合起来却带来了麻烦。
Ulrike 给出了一个可能的解决方案,即(本地)重新定义\sffamily
,例如使用她提供的便捷命令。
\DeclareFontSeriesDefault[sf]{md}{m}
另一个选项是(本地)告诉siunitx
使用不同的命令来设置 sans 字体,使用据我所知未记录的siunitx
选项text-sf
(或number-text-sf
和)。unit-text-sf
\sisetup{text-sf=\sffamily\fontseries{m}\selectfont}
粗体的问题在于,软件包medium
的选项roboto
设置了半粗体,而相应的sb
,嗯,就是不以字母开头b
。我在这里看到的唯一方法是修补测试\__siunitx_detect_font_weight_text:
。
这种方法类似于这个答案,但显然不太可靠。正如该回答和 Ulrike 在其评论,在软件包的内部命令中摸索通常不是一个好主意。 的实现甚至名称\__siunitx_detect_font_weight_text:
可能会随着 的未来版本而改变siunitx
,然后必须相应地更正补丁。
\apptocmd \__siunitx_detect_font_weight_text: {
\str_if_eq:VnT \f@series { sb }
{
\cs_set:Npn \__siunitx_font_weight:
{
\boldmath
\bfseries
}
}
} { } { }
此补丁使用的\apptocmd
功能etoolbox
。请注意,问题在 GitHub 上要求添加此功能,因此希望这个补丁将来会过时。
最后,结合以上所有内容的完整解决方案可能如下所示。
\documentclass{article}
\usepackage{etoolbox}
\usepackage[light,medium]{roboto}
\providecommand*\lseries{\fontseries{l}\selectfont}
\usepackage{siunitx}
\sisetup{detect-weight=true,detect-family=true,mode=text}
\makeatletter
\ExplSyntaxOn
\apptocmd \__siunitx_detect_font_weight_text: {
\str_if_eq:VnT \f@series { sb }
{
\cs_set:Npn \__siunitx_font_weight:
{
\boldmath
\bfseries
}
}
} { } { }
\ExplSyntaxOff
\makeatother
\newenvironment{RobotoRegular}{%
\begingroup%
\sisetup{text-sf=\sffamily\fontseries{m}\selectfont}%
\fontseries{m}\selectfont%
}{%
\endgroup%
}
\begin{document}
\sffamily
\makeatletter f@series is: \f@series. \quad
1\,mV \SI{1}{\milli\volt}
\begin{RobotoRegular}
\makeatletter f@series is: \f@series. \quad
1\,mV \SI{1}{\milli\volt}
\end{RobotoRegular}
\begingroup
\bfseries \makeatletter f@series is: \f@series. \quad
1\,mV \SI{1}{\milli\volt}
\endgroup
\end{document}
此解决方案现在考虑了所有三种情况的权重。如果需要该软件包提供的更多权重roboto
,当然可能需要在这方面进行更多更改。