2

Using the glossaries-extra package, it is possible to define the used terms and their abbreviation for convenient and consistent use within the document. But handling inflections within a sentence becomes unexpectedly difficult, as I write in German and the plural forms are not sufficient. A simple solution is to use \glslink and \glsdisp to show a custom text, but this has several shortcomings shown in the example below. My understanding of LaTeX hacking is insufficient to grasp the internals of the glossaries packages and I cannot estimate whether creating a custom command to handle this is feasible.

Example

To compile this, execute pdflatex test, bib2gls --record-count test, pdflatex test in this order. Also, to show why \gsldisp is insufficient, the example only shows the abbreviation at all, when the term is used at least twice.

File test.tex:

\documentclass{article}
\usepackage{xcolor}
\usepackage{hyperref}
\hypersetup{linkbordercolor=blue!30!white}

\usepackage[record,abbreviations,nomain]{glossaries-extra}
\setabbreviationstyle[abbreviation]{long-short-desc}
\glssetcategoryattribute{abbreviation}{nohyperfirst}{true}
\renewcommand{\glsfirstlongdefaultfont}[1]{\emph{#1}}
\GlsXtrLoadResources[src={glossary},selection=all]
\GlsXtrEnableEntryCounting{abbreviation}{1}
% Show only terms that are used more than once:
\renewcommand{\printunsrtglossaryhandler}[1]{%
  \ifthenelse{\GlsXtrTotalRecordCount{#1}>1}%
  {\glsxtrunsrtdo{#1}}%
  {}%
}
\begin{document}
% Good; No abbreviation shown:
The first mention with a different inflection ``des \glsdisp{Vektorraum}{Vektorraums}''.

% Bad; Should show choose abbreviation here and italicize the long part:
The first mention with a different inflection ``des \glsdisp{Körper}{Körpers}''.
And here the second use ``der \gls{Körper}''.

The first mention of ``der \gls{Vektor}''.
% Bad; Should choose abbreviation here:
And here with a different inflection ``des \glsdisp{Vektor}{Vektors}''.

\printunsrtglossary[type=\acronymtype,title=Abkürzungen]
\end{document}

File glossary.bib:

@abbreviation{Vektorraum,
short={VR},
long={Vektorraum},
description={Menge von Vektoren mit Vektoraddition und Skalarmultiplikation über einen Körper.},
}
@abbreviation{Vektor,
short={VEC},
long={Vektor},
description={Ein Vektor ist ein Element eines Vektorraums.},
}
@abbreviation{Körper,
short={K},
long={Körper},
description={Zwei kompatible zweistellige Verknüfungen über eine gemeinsame Menge.},
}

Question

Given the requirements, can a gls like command be easily created to handle all the above cases, while also respecting the abbreviation style selected and also handle regular glossary terms analogously?

Existing Solutions

A similar question was posted here, but the solution sought, was to specify the inflection on usage, whereas I want to call gls with a replacement text for the long part of the abbreviation on usage to be more practical.

Thanks in advance, even if there is no solution.

EDIT: Working Example

With the code examples given by Nicola Talbot, the following achieves all requirements (at least, that I can see):

\documentclass{article}
\usepackage{xcolor}
\usepackage{hyperref}
\hypersetup{linkbordercolor=blue!30!white}

\usepackage[record,abbreviations,nomain]{glossaries-extra}
\setabbreviationstyle[abbreviation]{long-postshort-user-desc}
\glssetcategoryattribute{abbreviation}{nohyperfirst}{true}
\renewcommand{\glsfirstlonguserfont}[1]{\emph{#1}}
\GlsXtrLoadResources[src={glossary},selection=all]
\GlsXtrEnableEntryCounting{abbreviation}{1}
% Show only terms that are used more than once:
\renewcommand{\printunsrtglossaryhandler}[1]{%
  \ifthenelse{\GlsXtrTotalRecordCount{#1}>1}%
  {\glsxtrunsrtdo{#1}}%
  {}%
}

\newcommand{\disp}[3][]{%
  \ifglsentryexists{#2}%
  {\glsifregular{#2}%
    {\glsdisp[#1]{#2}{#3}}%
    {\ifglshasshort{#2}%
      {\glsxtrifcounttrigger{#2}%
        {\glsifattribute{#2}{nohyperfirst}{true}%
          {\glslink[hyper=false,#1]{#2}{#3}}%
          {\glslink[#1]{#2}{#3}}%
          \glsunset{#2} }%
        {\ifglsused{#2}%
          {\gls[#1]{#2}}%
          {\glsdisp[textformat=glsfirstlongfont,#1]{#2}{#3}} } }%
      {\glsdisp[#1]{#2}{#3}} } }%
  {\glsdisp[#1]{#2}{3}}%
}

\begin{document}
% The following assertions show the required behavour:
\begin{figure}
\begin{tabular}{cc}
  \disp{Vektorraum}{Vektorraums} & Vektorraums \\ % <- Without link
  \disp{Vektor}{Vektors} & \emph{Vektors} (VEC) \\ % <- Without link
  \disp{Vektor}{Vektors} & VEC \\ % <- With link
\end{tabular}
\end{figure}
\printunsrtglossary[type=\acronymtype,title=Abkürzungen]
\end{document}

Example output

Some things that came up during testing:

  • Changing the style from long-postshort-user-desc to long-postshort-user has the side-effect of removing the long form from the printed glossary listing for some reason.
  • Using \gls like commands within $\text{...\gls{Vektor}...}$ behaves weirdly, since each use is counted as 4 occurences with regards to the use counter (\glsentryprevcount is 4 times as high).

Otherwise this seems like a splendid solution.

  • The long-postshort-user-desc style puts the long and short form in the name field, leaving the user to supply the description field. The long-postshort-user style puts the short form in the name field and the long form in the description field. If you set the description it will override this, so the long form won't appear in the glossary. That's the basic difference between those two styles. For your second point, is $\text{...\gls{Vektor}...}$ inside an environment that parses its contents (such as tabularx)? That might require a separate question. – Nicola Talbot Apr 13 at 12:31
1

There are two commands that allow you to display custom text encapsulated by the abbreviation formatting commands for a particular category:

  • \glsuseabbrvfont{text}{category}
  • \glsuselongfont{text}{category}

However, these use the subsequent (non-first-use) formatting commands. In your example, you've only set the first use long formatting command to \emph.

Simple example:

\documentclass{article}

\usepackage{glossaries-extra}

\setabbreviationstyle[abbreviation]{long-short-desc}
\renewcommand{\glsfirstlongdefaultfont}[1]{\emph{#1}}

\newabbreviation[description={Ein Vektor ist ein Element eines Vektorraums.}]{Vektor}{VEC}{Vektor}

\begin{document}
First: \gls{Vektor}.

Explicit long: \glsxtrlong{Vektor}.

\glsuselongfont{Vektors}{abbreviation}.
\end{document}

In this case only the first use of \gls shows the long form in an emphasized font:

First: Vektor (VEC). Explicit long: Vektor. Vektors.

If non-first-use also needs to be emphasized, then you'd need to redefine \glslongdefaultfont instead of \glsfirstlongdefaultfont:

\renewcommand{\glslongdefaultfont}[1]{\emph{#1}}

This is quite convoluted and using \glsuselongfont simply encapsulates the given text, so it's not querying the first use flag or indexing.

With the glossaries-extra package, \gls, \glspl, \Gls, \Glspl, \glsdisp and \glslink all use the command \glsentryfmt to format the link text. The base glossaries package also does this, but the glossaries-extra package modifies \glsentryfmt to take the abbreviation handling into account:

\renewcommand*{\glsentryfmt}{%
  \ifglshasshort{\glslabel}{\glssetabbrvfmt{\glscategory{\glslabel}}}{}%
  \glsifregular{\glslabel}%
  {\glsxtrregularfont{\glsgenentryfmt}}%
  {%
    \ifglshasshort{\glslabel}%
    {\glsxtrabbreviationfont{\glsxtrgenabbrvfmt}}%
    {\glsxtrregularfont{\glsgenentryfmt}}%
  }%
}

This first checks if the entry (whose label can be accessed with \glslabel) has the short field set. If it does then it switches to the formatting commands associated with that entry's category (\glssetabbrvfmt{\glscategory{\glslabel}}).

Then it tests if the entry has the regular attribute set for it's category. There are some abbreviation styles that set this attribute because they're designed to behave like regular entries (such as short-nolong and long-noshort). So even if the short field is set, if the regular attribute is set then the "regular" general formatting command is used (\glsxtrregularfont{\glsgenentryfmt}).

If the entry doesn't have the regular attribute set and has the short field set, then the abbreviation formatting is used instead (\glsxtrabbreviationfont{\glsxtrgenabbrvfmt}).

The actual formatting is a bit complicated as it needs to know if this is the first use, whether or not any case-changing (\Gls, \GLS, \Glspl, \GLSpl) or plural (\glspl, \Glspl, \GLSpl) is required, or if custom text was provided instead (\glsdisp or \glslink).

In the case of \glsdisp and \glslink, just the custom text is displayed. In the other cases it uses one of the commands set up by the abbreviation style:

  • \glsxtrsubsequentplfmt: subsequent use, plural, no case change.
  • \Glsxtrsubsequentplfmt: subsequent use, plural, first letter converted to upper case.
  • \glsxtrsubsequentfmt: subsequent use, singular, no case change.
  • \Glsxtrsubsequentfmt: subsequent use, singular, first letter converted to upper case.
  • \glsxtrfullplformat: first use, plural, no case change.
  • \Glsxtrfullplformat: first use, plural, first letter converted to upper case.
  • \glsxtrfullformat: first use, singular, no case change.
  • \Glsxtrfullformat: first use, singular, first letter converted to upper case.

These commands all take two arguments: the label (\glslabel) and the inserted material (\glsinsert) provided in the final optional argument of \gls etc (\gls[options]{label}[*insert*]).

The long-short-desc abbreviation style redefines the first use commands as follows (these are actually defined in the inherited long-short style):

  \renewcommand*{\glsxtrfullformat}[2]{%
    \glsfirstlongfont{\glsaccesslong{##1}\ifglsxtrinsertinside##2\fi}%
    \ifglsxtrinsertinside\else##2\fi
    \glsxtrfullsep{##1}%
    \glsxtrparen{\glsfirstabbrvfont{\glsaccessshort{##1}}}%
  }%
  \renewcommand*{\glsxtrfullplformat}[2]{%
    \glsfirstlongfont{\glsaccesslongpl{##1}\ifglsxtrinsertinside##2\fi}%
    \ifglsxtrinsertinside\else##2\fi\glsxtrfullsep{##1}%
    \glsxtrparen{\glsfirstabbrvfont{\glsaccessshortpl{##1}}}%
  }%
  \renewcommand*{\Glsxtrfullformat}[2]{%
    \glsfirstlongfont{\Glsaccesslong{##1}\ifglsxtrinsertinside##2\fi}%
    \ifglsxtrinsertinside\else##2\fi\glsxtrfullsep{##1}%
    \glsxtrparen{\glsfirstabbrvfont{\glsaccessshort{##1}}}%
  }%
  \renewcommand*{\Glsxtrfullplformat}[2]{%
    \glsfirstlongfont{\Glsaccesslongpl{##1}\ifglsxtrinsertinside##2\fi}%
    \ifglsxtrinsertinside\else##2\fi\glsxtrfullsep{##1}%
    \glsxtrparen{\glsfirstabbrvfont{\glsaccessshortpl{##1}}}%
  }%

(The double hash ## is because these redefinitions are performed inside the style definition command.) If the abbreviation style doesn't explicitly set the subsequent use formatting commands, the defaults are used:

\let\glsxtrsubsequentfmt\glsxtrdefaultsubsequentfmt
\let\glsxtrsubsequentplfmt\glsxtrdefaultsubsequentplfmt
\let\Glsxtrsubsequentfmt\Glsxtrdefaultsubsequentfmt
\let\Glsxtrsubsequentplfmt\Glsxtrdefaultsubsequentplfmt

So the reference to the long, short, longplural and shortplural fields are all hard-coded inside the abbreviation styles. This is necessary to allow the case-changing to work correctly. (The original acronym handling in the base glossaries package used a command that took the long form and short form as arguments, but this caused problems for certain styles. It was later replaced with another command that took the label instead.)

One possibility is to redefine \glsentryfmt to check for \glscustomtext if the entry is an abbreviation. For example:

\documentclass{article}

\usepackage{glossaries-extra}

\setabbreviationstyle[abbreviation]{long-short-desc}
\renewcommand{\glslongdefaultfont}[1]{\emph{#1}}

\renewcommand*{\glsentryfmt}{%
  \ifglshasshort{\glslabel}{\glssetabbrvfmt{\glscategory{\glslabel}}}{}%
  \glsifregular{\glslabel}%
  {\glsxtrregularfont{\glsgenentryfmt}}%
  {%
    \ifglshasshort{\glslabel}%
    {%
      \ifdefempty\glscustomtext
      {%
         \glsxtrabbreviationfont{\glsxtrgenabbrvfmt}%
      }%
      {%
        \ifglsused{\glslabel}%
        {%
          \glsabbrvfont{\glscustomtext}% replace short with custom text
        }%
        {%
          \glsfirstlongfont{\glscustomtext}% replace long with custom text
          \glsxtrfullsep{\glslabel}% separator
          \glsxtrparen{\glsfirstabbrvfont{\glsaccessshort{\glslabel}}}% (short)
        }%
      }%
    }%
    {\glsxtrregularfont{\glsgenentryfmt}}%
  }%
}

\newabbreviation[description={Ein Vektor ist ein Element eines Vektorraums.}]{Vektor}{VEC}{Vektor}

\begin{document}
First: \gls{Vektor}. Next: \gls{Vektor}.

Reset\glsresetall.

First: \glsdisp{Vektor}{Vektors}. Next: \glsdisp{Vektor}{Vektors}.

\end{document}

The first instance of \glsdisp swaps the long form for the supplied text. The next instance swaps the short form for the supplied text.

First: Vektor (VEC). Next: VEC. Reset. First: Vektors (VEC). Next: Vektors.

You can vary this according to your requirements. For example, on subsequent use you might want to ignore the custom text and just use the short form as normal:

\renewcommand*{\glsentryfmt}{%
  \ifglshasshort{\glslabel}{\glssetabbrvfmt{\glscategory{\glslabel}}}{}%
  \glsifregular{\glslabel}%
  {\glsxtrregularfont{\glsgenentryfmt}}%
  {%
    \ifglshasshort{\glslabel}%
    {%
      \ifdefempty\glscustomtext
      {%
         \glsxtrabbreviationfont{\glsxtrgenabbrvfmt}%
      }%
      {%
        \ifglsused{\glslabel}%
        {%
          \glsabbrvfont{\glsaccessshort{\glslabel}}% short
        }%
        {%
          \glsfirstlongfont{\glscustomtext}% replace long with custom text
          \glsxtrfullsep{\glslabel}% separator
          \glsxtrparen{\glsfirstabbrvfont{\glsaccessshort{\glslabel}}}% (short)
        }%
      }%
    }%
    {\glsxtrregularfont{\glsgenentryfmt}}%
  }%
}

An alternative method is to use long-postshort-user-desc instead of long-short-desc (or long-postshort-user instead of long-short if you decide not to have a description). The "post" styles put the first part of the full form in the link text and the second part in the post-link hook. This means that \glsdisp and \glslink will only replace the first part with the supplied text:

\documentclass{article}

\usepackage{glossaries-extra}

\setabbreviationstyle[abbreviation]{long-postshort-user-desc}
\renewcommand{\glsfirstlonguserfont}[1]{\emph{#1}}

\newabbreviation[description={Ein Vektor ist ein Element eines Vektorraums.}]{Vektor}{VEC}{Vektor}

% syntax: \disp[options]{label}{text}
\newcommand{\disp}[3][]{%
 \GlsXtrIfUnusedOrUndefined
  {#2}%
  {\glsdisp[textformat=glsfirstlongfont,#1]{#2}{#3}}%
  {\glsdisp[#1]{#2}{#3}}%
}

\begin{document}
First: \gls{Vektor}. Next: \gls{Vektor}.

Reset\glsresetall.

First: \disp{Vektor}{Vektors}. Next: \disp{Vektor}{Vektors}.

\end{document}

(The "user" styles use \glsfirstlonguserfont to format the long form on first use.)

You may want to consider defining a shortcut command. For example:

\newcommand{\disp}[3][]{%
 \GlsXtrIfUnusedOrUndefined
  {#2}%
  {\glsdisp[textformat=glsfirstlongfont,#1]{#2}{#3}}%
  {\glsdisp[#1]{#2}{#3}}%
}

(Since you're using bib2gls, it's better to use \GlsXtrIfUnusedOrUndefined instead of \ifglsused.) The style-sensitive \glsfirstlongfont is set by \glssetabbrvfmt at the start of \glsentryfmt, so it can be used in this context.

The result is:

First: Vektor (VEC). Next: VEC. Reset. First: Vektors (VEC). Next: Vektors.

  • Thank you very much for your help. I slightly modified your long-postshort-desc method to respect the entry counting and reported the solution in my question. As it is, this works fine :) – Araeos Apr 11 at 17:12

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.