1

In one of my last questions concerned the creation of a persons register Generating an name index with \index{name@name and surname}

Christian commented, to use Glossaries. I read about it and got a Proof of Concept working. Than I tried to code the POC into macros. The macro works, but unfortunately, every glossary entry, which is inserted using my macro, gets listet as a symbol, using the name of the last inserted person.

Inserting names "by hand" works as intended.


EDIT


I can't see the difference of the manual insertion versus the macro code. Please help me.

Nicola Talbot pointed out, that this question might be a duplicate to A dynamic variable as content of a glossary entry , which it kind of is. The answer to the above questions solves part of my problem, in that the person names are now inserted into the glossary (instead of only using the last name for all entries).

Since I will only collect names, I don't expect any fragile expression to be collected. Hence I decided (for simplicity reasons) to generally shut of the late expansion and added

\glsexpandfields

to my MWE.

Unfortunately, all automatically collected entries still reside below symbols and I still have no idea, why. I consider this to be a significant difference from the above linked question and hence no duplicate.

MWE:

\documentclass[12pt]{article}
\usepackage[ngerman]{babel}
\usepackage[T1]{fontenc}


\RequirePackage[final]{hyperref} % should be last package
\RequirePackage[nopostdot]{glossaries} % This is one of the seldom
                                % exceptions. 

\makeatletter

%%% Any time, you call the persons name again, you can use the
%%% glossary command.
%%%
%%% Arguments
%%%   #1: Lastname (mandatory)

%%%
%%% The book shall contain a list of all persons, which were
%%% mentioned.  The register should be sorted alphabetically, which in
%%% turn requires Makeindex or Xindy.  As I haven't used Xindy before,
%%% I will stay with Makeindex.  Both programms have difficulties, to
%%% sort names, which contain special characters as is the case for
%%% Henrie Poincaré.  Therefore, we must have a fool proof sorting
%%% entry.  Glossries relies on the fact, that an entry for the
%%% register is defined, before it is used.  Therefore, we can use the
%%% \initpers command, whenever a persons name is used for the first
%%% time.  Any following usage can be done with the normal \pers
%%% command. 
%%%
%%% Create the glossaries files.
\makeglossaries 

%% UPDATED!!!    
%% Protected fields like name have to be expanded before usage.
%% c.f. http://ctan.space-pro.be/tex-archive/macros/latex/contrib/glossaries/glossaries-user.html#sec:expansion
\glsexpandfields

%%% \initpers is the command, which is used, whenever a person is
%%% named in the document for the first time.  It will a) define the
%%% glossary entry, b) insert an entry into the register and finally
%%% c) will print the name into the text.  Makeindex/Glossaries does
%%% need the following arguments in a key=<value> manner:
%%%   1) label (uniqe identifier, used also for sorting purposes)
%%%      must be ASCII only, may be identical to 2)
%%%   2) name (may be identical to the label), will be inserted into
%%%      the document, may contain LaTeX specials and non ASCII
%%%      characters. 
%%%   3) description, i.e. the text, which should be printed into the
%%%      register.  The description can contain further information,
%%%      which wasn't in the document before.  IN our case, this will
%%%      be the surname and any further information
%%%      4) sorting key (if not given by the label) 
%%% Whenever a new name is introduced, its full name has to be
%%% inserted, but on the other hand, in some cases, only the last name
%%% has to be inserted into the document itself.  Therefore, we must
%%%
%%% NEW:
%%%   #1: Label (optional, only used, when Lastname contains non ASCII
%%%       characters) 
%%%   #2: Lastname (mandatory
%%%   #3: Surname (mandatory)
%%%   #4: Additional Info (mandatory but may be empty)

\newcommand{\pers}[1]{%
  \Gls{#1}}%
\newcommand{\initpers}[4][\@nil]{%
  %% Reset the internal variables
  \def\dntpers@label{}%
  \def\dntpers@name{}%
  %% Check, if the optional argument is in use and is the arguments
  %% accordingly.
  \def\@tmp{#1}%
  \ifx\@tmp\@nnil
    \def\dntpers@label{#2}%
  \else
    % use the optional argument as label, ...
    \def\dntpers@label{#1}%
  \fi
  \def\dntpers@name{#2}%
  %% Define the Glossar entry
  \newglossaryentry{\dntpers@label}{%
    name=\dntpers@name,
    % sort=\dntpers@label,
    description={#3 #4}}%
  %% Print the name
  #3 \gls{\dntpers@label}%
}%

\newcommand{\personenregister}{%
  \glossarystyle{listgroup}
  \printglossary[title=Personenregister]
}

\makeatother

\begin{document}

\newglossaryentry{Works}{
  name=Works,
  sort=Works,
  description={I have no idea, where the fuking difference comes
    from!}}
\gls{Works}

\initpers{Arrow}{Kenneth}{},
\initpers{Arthur}{Brian}{},
\initpers{Casti}{John}{},
\initpers{Gell-Mann}{Murray}{},
\initpers{Holland}{John}{},
\initpers[Help]{Kauffmann}{Stuart}{},
\initpers{Foo}{Bar}{Baz}

\personenregister

\end{document}% 

And the resultenter image description here


EDIT


This is the output after having added the above mentioned code line \glsexpandfields. Now the Lastname is missing.

enter image description here

  • 1
    The name field doesn't get expanded on definition by default. See the section Expansion in the glossaries user manual for details. Possibly a duplicate of A dynamic variable as content of a glossary entry. – Nicola Talbot Apr 5 '18 at 20:56
  • @NicolaTalbot Thank you very much, this helped a lot. This is indeed sorta of duplicate, I apologise. I added \\glsexpandfields into the preamble, which helped a bit. Still, the automatically created entries are located beneath Symbols. :-( – Jan Apr 6 '18 at 6:03
  • 1
    You need \glssetexpandfield{name} to ensure the name field is expanded. Have a look at the .glo file. It should have lines in the form \glossaryentry{...?...}. The bit before ? is the sort value. Does that look correct? You also may have problems because you're defining entries in the document environment. (See Drawbacks With Defining Entries in the Document Environment). You'd be better off defining the people in the preamble and then reference them with \gls. – Nicola Talbot Apr 6 '18 at 12:05
  • @NicolaTalbot thank you for your insigths. In my question tex.stackexchange.com/q/423792/120477 Christian pointed me towards Glossaries. My OMW (Original MWE) used macros, to insert names into a person register, while writing the main document. I think, it is way more comfortable for the author (which is not me) of that particular document in question, to declare an index or glossary entry, in the moment, a person is named, instead of defining them first, before being able to use them. – Jan Apr 6 '18 at 12:44
  • Okay. If the list of people is always at the end of the document (after all definitions) then you'd be better off replacing \usepackage[nopostdot]{glossaries} with \usepackage[docdef=restricted]{glossaries-extra}. That will remove the need for the .glsdefs file, which will make the document more stable. (The nopostdot option is the default with glossaries-extra so it can be omitted.) – Nicola Talbot Apr 6 '18 at 14:59
1

I think there are two problems. The first is the expansion problem (covered in A dynamic variable as content of a glossary entry) but I think another problem may be that when you modified your document, the next LaTeX run picked up the old definitions from the temporary .glsdefs file. This file is created when entries are defined within the document environment to allow for glossary lists at the start of the document.

Since you have the list at the end of the document, it's better to use glossaries-extra with docdef=restricted but you must delete the .glsdefs file otherwise you will continue to have the out-of-date information input at the beginning of the document.

Here's a modified version that uses \protected@edef to ensure expansion (I've changed the obsolete \glossarystyle with the newer \setglossarystyle):

\documentclass[12pt]{article}
\usepackage[ngerman]{babel}
\usepackage[T1]{fontenc}

\RequirePackage[final]{hyperref}
\RequirePackage[docdef=restricted]{glossaries-extra} 

\makeglossaries 

\makeatletter

\newcommand{\pers}[1]{%
  \Gls{#1}}%
\newcommand{\initpers}[4][\@nil]{%
  %% Reset the internal variables
  \def\dntpers@label{}%
  \def\dntpers@name{}%
  %% Check, if the optional argument is in use and is the arguments
  %% accordingly.
  \def\@tmp{#1}%
  \ifx\@tmp\@nnil
    \def\dntpers@label{#2}%
  \else
    % use the optional argument as label, ...
    \def\dntpers@label{#1}%
  \fi
  \def\dntpers@name{#2}%
  %% Define the Glossar entry
  \protected@edef\@dodef{\noexpand\newglossaryentry{\dntpers@label}{%
    name=\dntpers@name,
    % sort=\dntpers@label,
    description={#3 #4}}}%
  \@dodef
  %% Print the name
  #3 \gls{\dntpers@label}%
}%

\newcommand{\personenregister}{%
  \setglossarystyle{listgroup}%
  \printglossary[title=Personenregister]
}

\makeatother

\begin{document}
\initpers{Arrow}{Kenneth}{},
\initpers{Arthur}{Brian}{},
\initpers{Casti}{John}{},
\initpers{Gell-Mann}{Murray}{},
\initpers{Holland}{John}{},
\initpers[Help]{Kauffmann}{Stuart}{},
\initpers{Foo}{Bar}{Baz}

\personenregister

\end{document}

image of document

If you want a comma after the surname, the glossaries-extra package provides a convenient hook for appending material after the name field (within the encapsulating formatting command used on the name):

\newcommand{\glsxtrpostnamegeneral}{,}

This can go anywhere before the list is displayed.

Note: since you've used \usepackage[ngerman]{babel} be aware that this makes " active. Unfortunately this is a special character for makeindex and requires escaping. The glossaries package tries to internally escape all indexing special characters, but it can only do this when they have their normal meanings. This doesn't cause a problem when entries are defined in the preamble as babel doesn't activate shortcuts until the start of the document environment, but it does cause a problem for entries that are defined within the document if they happen to contain any of those characters.

This means that you need to take care if any of your names contain umlauts, even if you are using inputenc because the expansion will convert those characters into their internal representation.

A slightly modified version of \initpers that uses \expandonce to only perform one level of expansion on \dntpers@name can prevent UTF-8 characters from being expanded:

\newcommand{\initpers}[4][\@nil]{%
  %% Reset the internal variables
  \def\dntpers@label{}%
  \def\dntpers@name{}%
  %% Check, if the optional argument is in use and is the arguments
  %% accordingly.
  \def\@tmp{#1}%
  \ifx\@tmp\@nnil
    \def\dntpers@label{#2}%
  \else
    % use the optional argument as label, ...
    \def\dntpers@label{#1}%
  \fi
  \def\dntpers@name{#2}%
  %% Define the Glossar entry
  \protected@edef\@dodef{\noexpand\newglossaryentry{\dntpers@label}{%
    name=\expandonce\dntpers@name,
    description={#3 #4}}}%
  \@dodef
  %% Print the name
  #3 \gls{\dntpers@label}%
}%

However, since makeindex doesn't support UTF-8 I'm guessing you'll either use the label as the sort value or use " with makeindex's -g switch.

Here's the first case (UTF-8 support and sort by label):

\documentclass[12pt]{article}
\usepackage[ngerman]{babel}
\usepackage[T1]{fontenc}
\usepackage[utf8]{inputenc}

\RequirePackage[final]{hyperref}
\RequirePackage[docdef=restricted]{glossaries-extra} 

\makeglossaries 

\makeatletter

\newcommand{\pers}[1]{%
  \Gls{#1}}%
\newcommand{\initpers}[4][\@nil]{%
  %% Reset the internal variables
  \def\dntpers@label{}%
  \def\dntpers@name{}%
  %% Check, if the optional argument is in use and is the arguments
  %% accordingly.
  \def\@tmp{#1}%
  \ifx\@tmp\@nnil
    \def\dntpers@label{#2}%
  \else
    % use the optional argument as label, ...
    \def\dntpers@label{#1}%
  \fi
  \def\dntpers@name{#2}%
  %% Define the Glossar entry
  \protected@edef\@dodef{\noexpand\newglossaryentry{\dntpers@label}{%
    name=\expandonce\dntpers@name,
    sort=\expandonce\dntpers@label,
    description={#3 #4}}}%
  \@dodef
  %% Print the name
  #3 \gls{\dntpers@label}%
}%

\newcommand{\glsxtrpostnamegeneral}{,}

\newcommand{\personenregister}{%
  \setglossarystyle{listgroup}%
  \printglossary[title=Personenregister]
}

\makeatother

\begin{document}
\initpers[Arrow]{Ärrow}{Kenneth}{},
\initpers{Arthur}{Brian}{},
\initpers{Casti}{John}{},
\initpers{Gell-Mann}{Murray}{},
\initpers{Holland}{John}{},
\initpers[Help]{Kauffmann}{Stuart}{},
\initpers{Foo}{Bar}{Baz}

\personenregister

\end{document}

image of document

Here's the second case. This uses \GlsSetQuote to change makeindex's escape character from " to + (which presumably hasn't been made active in your document).

\documentclass[12pt]{article}
\usepackage[ngerman]{babel}
\usepackage[T1]{fontenc}

\RequirePackage[final]{hyperref}
\RequirePackage[docdef=restricted]{glossaries-extra} 

\GlsSetQuote{+}

\makeglossaries 

\makeatletter

\newcommand{\pers}[1]{%
  \Gls{#1}}%
\newcommand{\initpers}[4][\@nil]{%
  %% Reset the internal variables
  \def\dntpers@label{}%
  \def\dntpers@name{}%
  %% Check, if the optional argument is in use and is the arguments
  %% accordingly.
  \def\@tmp{#1}%
  \ifx\@tmp\@nnil
    \def\dntpers@label{#2}%
  \else
    % use the optional argument as label, ...
    \def\dntpers@label{#1}%
  \fi
  \def\dntpers@name{#2}%
  %% Define the Glossar entry
  \protected@edef\@dodef{\noexpand\newglossaryentry{\dntpers@label}{%
    name=\expandonce\dntpers@name,
    description={#3 #4}}}%
  \@dodef
  %% Print the name
  #3 \gls{\dntpers@label}%
}%

\newcommand{\glsxtrpostnamegeneral}{,}

\newcommand{\personenregister}{%
  \setglossarystyle{listgroup}%
  \printglossary[title=Personenregister]
}

\makeatother

\begin{document}
\initpers[Arrow]{"Arrow}{Kenneth}{},
\initpers{Arthur}{Brian}{},
\initpers{Casti}{John}{},
\initpers{Gell-Mann}{Murray}{},
\initpers{Holland}{John}{},
\initpers[Help]{Kauffmann}{Stuart}{},
\initpers{Foo}{Bar}{Baz}

\personenregister

\end{document}

(The result is the same as the previous example.)

Note that makeindex needs to be run with -g, which makeglossaries does automatically.

Finally, if you choose the last method, I recommend you change \Gls to \gls if all your names start with a capital. The problem shows up if \pers{Arrow} is added to the example:

\begin{document}
\initpers[Arrow]{"Arrow}{Kenneth}{},
\initpers{Arthur}{Brian}{},
\initpers{Casti}{John}{},
\initpers{Gell-Mann}{Murray}{},
\initpers{Holland}{John}{},
\initpers[Help]{Kauffmann}{Stuart}{},
\initpers{Foo}{Bar}{Baz}

\pers{Arrow}

\personenregister

\end{document}

The result looks like:

Kenneth Ärrow, Brian Arthur, John Casti, Murray Gell-Mann, John Holland, Stuart Kauffmann, Bar Foo "Arrow

The upper casing is applied to the " which breaks it so you end up with "Arrow instead of Ärrow. The alternative is to do:

\initpers[Arrow]{{"A}rrow}{Kenneth}{}

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.