निरंजन
I am trying to generate small caps with \textsc and for that I am using package [unisc](https://ctan.org/pkg/unisc), but the problem I am facing here is it isn't working with a very important package in linguistics, i.e., the [leipzig](https://ctan.org/pkg/leipzig) package. See the following code.


\documentclass{article}
\usepackage{unisc}
\usepackage{leipzig}
\usepackage{fontspec}
\setmainfont{CharisSIL}

\begin{document}
\Acc
\end{document}


With LuaTeX-1.15.0; this gives me Missing \endcsname inserted. error. In the output I can see ᴀᴄᴄ@short (note that the 'ᴀᴄᴄ' part is in small caps). Is the problem with package unisc or with package leipzig? How to solve this problem?
frougon
I'm afraid unisc redefines \textsc in a way that places too many restrictions on the argument to work in all situations where the standard \textsc works. I'll show how to understand the problem.


\documentclass{article}
\usepackage{unisc}
\usepackage{leipzig}

\usepackage{fontspec}
\setmainfont{CharisSIL}

\begin{document}

\tracingmacros=1\tracingcommands=2
\Acc
\tracingmacros=0\tracingcommands=0

\end{document}


then run lualatex on this code:


This is LuaHBTeX, Version 1.15.0 (TeX Live 2022)

...

! Missing \endcsname inserted.
\protect
l.12 \tracingmacros
=0\tracingcommands=0
? x
556 words of node memory still in use:
6 hlist, 1 vlist, 2 rule, 1 local_par, 1 dir, 1 glue, 4 kern, 1 glyph, 9 att
ribute, 63 glue_spec, 9 attribute_list, 1 temp, 1 if_stack, 3 write nodes
avail lists: 1:1,2:9,3:1,4:1,5:6,7:5,11:1

warning  (pdf backend): no pages of output.
Transcript written on test_unisc.log.


# A little aside

The first thing that may seem puzzling is that the error happens *after* TeX has read (and tokenized) \tracingmacros on the line following \Acc. This is because after expanding \Acc and performing a few operations, TeX finds \s@gls@hyp@opt which looks ahead in the input for a possible [ because \s@gls@hyp@opt is defined with \newcommand*{\s@gls@hyp@opt}[1][]{...}.

One can reproduce the error in “bare bones” style with the same lookahead phenomenon like so:


\documentclass{article}

\newcommand*{\foo}[1][]{\csname\protect}

\begin{document}

\foo
abc

\end{document}


which gives:


This is LuaHBTeX, Version 1.15.0 (TeX Live 2022)

...

! Missing \endcsname inserted.
\protect
l.8 a
bc
? x
375 words of node memory still in use:
...


\foo looks ahead in the input for a possible [ and finds the character token a (with catcode 11). So, it sees that the optional argument wasn't passed, calls the internal macro \\foo with the empty token list substituted for the optional argument, which results in \csname\protect. \csname recursively expands tokens until it (hopefully) finds \endcsname. However, while doing so, it finds \protect which is illegal in this context, because during the recursive expansion started by \csname, the only unexpandable tokens allowed are character tokens (cf. TeXbook p. 213).

In normal typesetting, \protect is unexpandable because it is \ifx-equivalent to the \relax primitive. Since \protect is not a character token, this is invalid in the context of \csname ... \endcsname expansion; therefore, TeX inserts \endcsname in the input stream to finish the started \csname ... \endcsname, hence the error message.

# From your example to this error

Now, let's see how to discover that your example produces exactly this error, and why. We start from the log file produced by the first code sample in this answer, which is your code with some tracing commands. In this log file, we can see that the error results from the following:


\glsentryshort #1->\@gls@entry@field {#1}{short}

#1<-\protect \char "1D00\relax \protect \char "1D04\relax \protect \char "1D04\relax

\@gls@entry@field #1#2->\csname glo@\glsdetoklabel {#1}@#2\endcsname

#1<-\protect \char "1D00\relax \protect \char "1D04\relax \protect \char "1D04\relax

#2<-short
{\csname}

\glsdetoklabel #1->#1

#1<-\protect \char "1D00\relax \protect \char "1D04\relax \protect \char "1D04\relax

! Missing \endcsname inserted.
\protect
l.12 \tracingmacros
=0\tracingcommands=0


Here, we see the \csname of the error message (the line containing {\csname} indicates when TeX expands the \csname primitive, which starts recursive expansion until the matching \endcsname). We also see that \glsdetoklabel simply expands to its argument (like \@firstofone), so that the recursive expansion process started by \csname then finds \protect \char "1D00\relax \protect \char "1D04\relax \protect \char "1D04\relax, hence the error (as explained above).

Now we have to understand why \glsdetoklabel received this strange argument. As you can guess, this is what \textsc{acc} produces when \textsc has been redefined by unisc; however, what glossaries would need to work properly is acc (three character tokens) instead of this big argument—then the \csname wouldn't trigger any error.

Since the big argument comes from this:


\glsentryshort #1->\@gls@entry@field {#1}{short}

#1<-\protect \char "1D00\relax \protect \char "1D04\relax \protect \char "1D04\relax


the next step is to find how \glsentryshort was called. The answer can be found earlier in the log file, before the pgfparser processing:


\glscustomtext ->\acronymfont {\glsentryshort {acc}}

\acronymfont #1->\leipzigfont {#1}

#1<-\glsentryshort {acc}

\leipzigfont #1->\textsc {#1}

#1<-\glsentryshort {acc}


Et voilà. Basically, with the default settings, \glscustomtext does \textsc{\glsentryshort{acc}}. In normal conditions, \glsentryshort{acc} would expand to acc (three character tokens), but because of unisc's redefinition of \textsc and \scshape, \glsentryshort sees \protect \char "1D00\relax \protect \char "1D04\relax \protect \char "1D04\relax as its argument, because here pgfparser leaves \glsentryshort as is and processes the three character tokens acc in the special way specified by unisc after \scshape.

Since the \glsentryshort macro is expandable (i.e., it works fine in expansion-only contexts; see the annex for more explanations), we can verify this theory by providing a fix that works **in this particular situation:**


\RenewDocumentCommand\textsc{ m }{%
\begingroup
\edef\unisc@tmp{\csname text_expand:n\endcsname{#1}}%
\expandafter\scshape\unisc@tmp
\endgroup
}%


(modified definition to substitute at the end of unisc.sty). This makes your example work but is not good enough in general:

- no fix for \scshape (would be harder, as it doesn't take any argument);

- won't work properly for general unexpandable material in the argument of \textsc (which is allowed to contain very complex algorithms, built with assignments in particular);

- changes the argument handling of \textsc by using \text_expand:n first on it (which justifies the previous point and belongs to the same class of problems as the one that triggered your question).

Basically, unisc causes \textsc and \scshape to work in a very particular way, which is more restrictive than what these commands require; and \Acc makes this clearly visible...

# Annex: on the word “expandable”

There are some subtleties regarding what “expandable” means depending on what we are talking about.

1. A token is, in a given context, either *expandable* or *unexpandable*. In the former case, one expansion step on the token causes it to be replaced in the input stream by other tokens (after possibly grabbing arguments). Many primitives such as \relax, \def, \edef, \count, \box, \hbox, \endgraf, ⟨integer parameter⟩s like \tracingmacros, etc., are unexpandable tokens (unless redefined!). If \foo has been defined with \def or \newcommand, it is normally an *expandable token* (but not if preceded with \noexpand). Character tokens are unexpandable, except those of category code 13 (“active characters”).

This is the intuitive meaning of the word “expandable”. By this meaning, a control sequence token which is the name of a macro is “always” expandable (not after \noexpand), therefore the concept of an “expandable macro” wouldn't be interesting if it used the intuitive meaning.

2. We say that *macro \foobar is expandable* if it performs its job correctly even in expansion-only contexts.

Generally, macros may need both expansion and execution to perform their duty (mouth and stomach processing in Knuth's analogy). For instance, defining a macro or increasing a counter are assignments and therefore can't be triggered only by expansion (e.g. inside \edef, \write, \message, \expanded, \csname ... \endcsname, when reading a ⟨number⟩, ⟨dimen⟩ or ⟨glue⟩, after \romannumeral, etc.; or by a hit from \expandafter). (One exception with LuaTeX: \directlua works in expansion-only contexts and can perform assignments.) General macros need the full expansion + execution interleaved process in order to perform their work: we say that they are *not expandable* (this doesn't use the intuitive meaning of “expandable”, of course).

The other macros, that can perform their work as designed even in a context where only expansion takes place, are said to be *expandable*. We can extend this meaning to primitives that do their useful work without requiring anything more than expansion: \expandafter, \csname, \the, \jobname, \ifnum, \ifcase, \if, \ifcat, \ifx, \ifhmode, \ifvmode, \ifmmode, \else, \fi, \number, \romannumeral and a few more (see the TeXbook on pages 212 and following).

Expandable macros are very convenient because they can be meaningfully used in many more places than non-expandable ones. In particular, you can “retrieve and store the result” (of the expansion) of an expandable macro using \edef.

We sometimes distinguish between “fully expandable” and “restricted-expandable” macros, but I believe this answer is not the right place for diving into this rabbit hole. :-)

In certain circumstances, TeX tries to expand tokens; in other circumstances, it doesn't. For instance, when executing the \edef in \edef\foo{...}, TeX doesn't try to expand \foo, but recursively expands tokens inside the braces. Let's see two short examples with \def, \edef and \noexpand.

**First example**


\def\foo{what\bar}
\def\bar{ever}
\edef\tmp{\noexpand\foo\foo}
\show\tmp


This prints the following output on the terminal:


> \tmp=macro:
->\foo whatever.
l.4 \show\tmp


\noexpand made the first \foo inside the \edef temporarily unexpandable; on the other hand, the second \foo was recursively expanded.

**Second example**


\def\foo{\noexpand\bar}
\edef\tmp{\def\foo{whatever}}
\tmp
\show\bar


which prints:


> \bar=macro:
->whatever.
l.4 \show\bar


Here, the \edef tries to expand the \def token, but it is unexpandable, thus remains \def. Expanding \def didn't do anything, so the recursive expansion process started by \edef continues: the \foo token that follows is recursively expanded. This first yields \noexpand\bar, then an unexpandable \bar token. In the end, since the remaining tokens inside the \edef (namely, the character tokens in {whatever}) are all unexpandable, after \edef has been executed, \tmp is a macro whose replacement text is \def\bar{whatever}, hence the output.
Ulrike Fischer
The unicode chars you are using are not meant for normal text. To quote wikipedia https://en.wikipedia.org/wiki/Small_caps
(emphasis by me):

> the Unicode standard does define a number of "small capital" characters in the IPA extensions, Phonetic Extensions and Latin Extended-D ranges (0250–02AF, 1D00–1D7F, A720–A7FF).
>These characters, with official names such as latin letter small capital a, are **meant for use in phonetic representations**. For example, ʀ represents a uvular trill. They **should not normally be used in other contexts** (the 'normal' character set should be used with suitable formatting controls as described in the preceding sections).

The set not even cover all standard letters, there is e.g. no x. So unrelated to technical questions it is semantically wrong to use them with a font command like \textsc.

You should define a command \ipasmallcaps or similar that then can be used in appropriate places.


frougon
Since having Unicode small caps output by leipzig.sty seems important to you, I examined the situation in order to find a clean solution. I propose to add a new option to the leipzig package, which is named use-unicode-small-caps-in-short-form here (I don't mind if the name is changed).

All you need to do is to apply the following patch to leipzig.sty. If this is really useful, it could be submitted upstream. Besides, my patch fixes a few bugs in leipzig.sty (one of them is a programming error with no consequence; the other ones are real little bugs, AFAICS). Here is the patch (it applies against leipzig.sty 2019/10/19 v2.3):


diff --git a/leipzig.sty b/leipzig.sty
index 7171e28..bb4163f 100644
--- a/leipzig.sty
+++ b/leipzig.sty
@@ -51,7 +51,14 @@
\newcommand*{\@leipzig@default@style}{inline}
\newif\ifleipzighyper\leipzighyperfalse
\newif\ifleipzignonumbers\leipzignonumberstrue
-\newcommand{\leipzigfont}[1]{\textsc{#1}}%
+\newif\ifleipzig@use@unicode@small@caps@in@short@form % initially false
+\newcommand{\leipzigfont}[1]{%
+  \ifleipzig@use@unicode@small@caps@in@short@form
+    {#1}% no need to use \textsc around Unicode small caps
+  \else
+    \textsc{#1}%
+  \fi
+}%
\DeclareOption{glossaries}{\leipzig@glossariestrue}
\DeclareOption{noglossaries}{%
\leipzig@glossariesfalse
@@ -71,6 +78,9 @@
}%
\DeclareOption{leipzighyper}{\leipzighypertrue}
\DeclareOption{leipzignohyper}{\leipzighyperfalse}
+\DeclareOption{use-unicode-small-caps-in-short-form}{%
+  \leipzig@use@unicode@small@caps@in@short@formtrue
+}
\DeclareOption*{%
\PassOptionsToPackage{\CurrentOption}{glossaries}%
}%
@@ -414,10 +424,62 @@
}%
}%
}{\relax}%
+
+% Unicode small caps in replacement texts (you need to complete this list with
+% the other letters).
+\newcommand*{\leipzig@usc@char@transl@a}{ᴀ}
+\newcommand*{\leipzig@usc@char@transl@c}{ᴄ}
+
+\newcommand*{\leipzig@usc@translate@char}[1]{%
+  \ifcsname leipzig@usc@char@transl@#1\endcsname
+    \unexpanded\expandafter\expandafter\expandafter{%
+      \csname leipzig@usc@char@transl@#1\endcsname
+    }%
+  \else
+    \unexpanded{#1}%
+  \fi
+}
+
+\newcommand*{\leipzig@usc@transform@aux}[1]{%
+  \ifx#1\@nil
+    \expandafter\@gobble                   % eat the second \@nil
+  \else
+    \leipzig@usc@translate@char{#1}%
+    \expandafter\leipzig@usc@transform@aux % recurse
+  \fi
+}
+
+% Apply the transformation to (roughly) each non-space character token c in #1
+% for which \leipzig@usc@char@transl@c is defined.
+\newcommand*{\leipzig@usc@transform}[1]{%
+  \leipzig@usc@transform@aux#1\@nil\@nil
+}
+
+% Depending on \ifleipzig@use@unicode@small@caps@in@short@form, call either
+% #1{#2} or #1{x}, where 'x' stands for the \edef-expansion of
+% \leipzig@usc@transform{#2} (which converts #2 to Unicode small caps).
+% #1 must be a single token.
+\newcommand*{\leipzig@maybe@usc}[2]{%
+  \ifleipzig@use@unicode@small@caps@in@short@form
+    \expandafter\@firstoftwo
+  \else
+    \expandafter\@secondoftwo
+  \fi
+  {%
+    \edef\leipzig@tmp{\leipzig@usc@transform{#2}}%
+    \expandafter#1\expandafter{\leipzig@tmp}%
+  }%
+  {#1{#2}}%
+}
+
+  \newcommand{\leipzig@newacronym@aux}[4]{%
+    \newacronym[type=\leipzigtype,#2]{#3}{#1}{#4}%
+  }
+  %
\newcommand{\newleipzig}[4][]{%
\bgroup
-    {\newacronym[type=\leipzigtype,#1]{#2}{#3}{#4}}%
+    {\leipzig@maybe@usc\leipzig@newacronym@aux{#3}{#1}{#2}{#4}}% useless group?
\@newleipzig#2\@nil%
}%
\def\@newleipzig#1#2\@nil{%
@@ -459,28 +521,22 @@
}
\def\renew@leipzig#1#2{%
\ifcsname glo@\glsdetoklabel{#2}@name\endcsname
-    \csundef{glo@\glsdetoklabel{#2}@name}
-  \fi
-  \if\relax\detokenize{#2}\relax
-    \expandafter\@firstoftwo
-  \else
-    \expandafter\@secondoftwo
+    \csundef{glo@\glsdetoklabel{#2}@name}%
\fi
-  {\newleipzig{#2}}{\newleipzig[#1]{#2}}%
+  \newleipzig[#1]{#2}%
}%
}%
{%
-  \newcommand{\newleipzig}[4][]{\@newleipzig(#3)#2\@nil}%
+  \newcommand{\newleipzig}[4][]{\leipzig@maybe@usc\@newleipzig{#3}#2\@nil}%
\newcommand{\renewleipzig}[4][]{%
\if@leipzig@defined{#2}
{%
-       \@newleipzig(#3)#2\@nil%
+       \leipzig@maybe@usc\@newleipzig{#3}#2\@nil
}%
{%
\PackageError{leipzig}
{Abbreviation #2' undefined}
{No #2 abbreviation is defined, use \string\newleipzig}%
-       \@gobbletwo
}%
}
\def\if@leipzig@defined#1{%
@@ -490,8 +546,8 @@
\expandafter\@secondoftwo
\fi
}
-  \def\@newleipzig(#1)#2#3\@nil{%
-    \uppercase{\expandafter\gdef\csname #2}#3\endcsname{\leipzigfont{#1}}
+  \def\@newleipzig#1#2#3\@nil{%
+    \uppercase{\expandafter\gdef\csname #2}#3\endcsname{\leipzigfont{#1}}%
}%
}


This only does the work for letters a and c (the only ones used in your MWE), however the implemented machinery is generic: all you need to do is to add the other letters, following the pattern in these two lines:


\newcommand*{\leipzig@usc@char@transl@a}{ᴀ}
\newcommand*{\leipzig@usc@char@transl@c}{ᴄ}


Also, the above patch **assumes that the short form** of a \newleipzig (its second mandatory argument) **never contains spaces**; some modifications would be needed in case this assumption doesn't hold.

To avoid any confusion, I called the modified file leipzig-modified.sty on my computer (and \ProvidesPackage rightfully warns since I didn't change the package name there); here is a MWE that uses this file (tested with LuaTeX):


\documentclass{article}
\usepackage[use-unicode-small-caps-in-short-form]{leipzig-modified}
\usepackage{fontspec}
\setmainfont{CharisSIL}

\begin{document}
ACC \Acc\ \textsc{acc}
\end{document}


![image.png](/image?hash=a386826319ea52d19103969f9fa0638183ec40beb55fa95b934e60eb8edcf9ea)

which, after a copy/paste from the PDF, yields ACC ᴀᴄᴄ acc (the middle one is composed of Unicode small caps).

Note that my code doesn't use nor test anything from unisc or pgfparser: it is designed to do what you want for leipzig.sty, nothing else. For your other use cases *where you control the input*, I think a dedicated \unisc macro as @Skillmon [proposed](https://topanswers.xyz/transcript?room=2052#c139141) would be fine. If you only put non-space character tokens in the argument (or protect spaces with braces as in \unisc{Foo{ }Bar{ }Baz}), my \leipzig@usc@transform does the job: after


\makeatletter
\NewCommandCopy{\unisc}{\leipzig@usc@transform}
\makeatother


\unisc{FooBarBaz} will output the Unicode small caps in an [expandable way](https://topanswers.xyz/tex?q=2007#a2255), assuming you've defined all used letters with the \leipzig@usc@char@transl@... macros (see above). If spaces or more complex stuff needs to be transparently supported in the argument, a pgfparser-based solution [as in your other question](https://topanswers.xyz/tex?q=2005#a2252) could do the trick; alternatively, one could probably use some expl3 function to iterate over the tokens without ignoring space tokens that are not inside braces (or the classical way using \futurelet, however this is not expandable, so would require a few changes).

# Separate patches: bug fixes, support for the new option

For easier upstream submission, the proposed changes to leipzig.sty can be decomposed into two patches applied in the following order:

1. Bug fixes and simplification:


diff --git a/leipzig.sty b/leipzig.sty
index 7171e28..1d46fda 100644
--- a/leipzig.sty
+++ b/leipzig.sty
@@ -459,14 +459,9 @@
}
\def\renew@leipzig#1#2{%
\ifcsname glo@\glsdetoklabel{#2}@name\endcsname
-    \csundef{glo@\glsdetoklabel{#2}@name}
+    \csundef{glo@\glsdetoklabel{#2}@name}%
\fi
-  \if\relax\detokenize{#2}\relax
-    \expandafter\@firstoftwo
-  \else
-    \expandafter\@secondoftwo
-  \fi
-  {\newleipzig{#2}}{\newleipzig[#1]{#2}}%
+  \newleipzig[#1]{#2}%
}%
}%
{%
@@ -480,7 +475,6 @@
\PackageError{leipzig}
{Abbreviation #2' undefined}
{No #2 abbreviation is defined, use \string\newleipzig}%
-       \@gobbletwo
}%
}
\def\if@leipzig@defined#1{%
@@ -491,7 +485,7 @@
\fi
}
\def\@newleipzig(#1)#2#3\@nil{%
-    \uppercase{\expandafter\gdef\csname #2}#3\endcsname{\leipzigfont{#1}}
+    \uppercase{\expandafter\gdef\csname #2}#3\endcsname{\leipzigfont{#1}}%
}%
}


Note: the \if\relax\detokenize{#2}\relax was incorrect (#1 was meant, as far as I understand it), but this didn't trigger any error because passing an empty optional argument to \newleipzig doesn't seem to cause any problem... and this is precisely what allows us to simplify this part (as far as I can see, there is no need for the separate code paths).

2. Support for the new option use-unicode-small-caps-in-short-form:


diff --git a/leipzig.sty b/leipzig.sty
index 1d46fda..bb4163f 100644
--- a/leipzig.sty
+++ b/leipzig.sty
@@ -51,7 +51,14 @@
\newcommand*{\@leipzig@default@style}{inline}
\newif\ifleipzighyper\leipzighyperfalse
\newif\ifleipzignonumbers\leipzignonumberstrue
-\newcommand{\leipzigfont}[1]{\textsc{#1}}%
+\newif\ifleipzig@use@unicode@small@caps@in@short@form % initially false
+\newcommand{\leipzigfont}[1]{%
+  \ifleipzig@use@unicode@small@caps@in@short@form
+    {#1}% no need to use \textsc around Unicode small caps
+  \else
+    \textsc{#1}%
+  \fi
+}%
\DeclareOption{glossaries}{\leipzig@glossariestrue}
\DeclareOption{noglossaries}{%
\leipzig@glossariesfalse
@@ -71,6 +78,9 @@
}%
\DeclareOption{leipzighyper}{\leipzighypertrue}
\DeclareOption{leipzignohyper}{\leipzighyperfalse}
+\DeclareOption{use-unicode-small-caps-in-short-form}{%
+  \leipzig@use@unicode@small@caps@in@short@formtrue
+}
\DeclareOption*{%
\PassOptionsToPackage{\CurrentOption}{glossaries}%
}%
@@ -414,10 +424,62 @@
}%
}%
}{\relax}%
+
+% Unicode small caps in replacement texts (you need to complete this list with
+% the other letters).
+\newcommand*{\leipzig@usc@char@transl@a}{ᴀ}
+\newcommand*{\leipzig@usc@char@transl@c}{ᴄ}
+
+\newcommand*{\leipzig@usc@translate@char}[1]{%
+  \ifcsname leipzig@usc@char@transl@#1\endcsname
+    \unexpanded\expandafter\expandafter\expandafter{%
+      \csname leipzig@usc@char@transl@#1\endcsname
+    }%
+  \else
+    \unexpanded{#1}%
+  \fi
+}
+
+\newcommand*{\leipzig@usc@transform@aux}[1]{%
+  \ifx#1\@nil
+    \expandafter\@gobble                   % eat the second \@nil
+  \else
+    \leipzig@usc@translate@char{#1}%
+    \expandafter\leipzig@usc@transform@aux % recurse
+  \fi
+}
+
+% Apply the transformation to (roughly) each non-space character token c in #1
+% for which \leipzig@usc@char@transl@c is defined.
+\newcommand*{\leipzig@usc@transform}[1]{%
+  \leipzig@usc@transform@aux#1\@nil\@nil
+}
+
+% Depending on \ifleipzig@use@unicode@small@caps@in@short@form, call either
+% #1{#2} or #1{x}, where 'x' stands for the \edef-expansion of
+% \leipzig@usc@transform{#2} (which converts #2 to Unicode small caps).
+% #1 must be a single token.
+\newcommand*{\leipzig@maybe@usc}[2]{%
+  \ifleipzig@use@unicode@small@caps@in@short@form
+    \expandafter\@firstoftwo
+  \else
+    \expandafter\@secondoftwo
+  \fi
+  {%
+    \edef\leipzig@tmp{\leipzig@usc@transform{#2}}%
+    \expandafter#1\expandafter{\leipzig@tmp}%
+  }%
+  {#1{#2}}%
+}
+
+  \newcommand{\leipzig@newacronym@aux}[4]{%
+    \newacronym[type=\leipzigtype,#2]{#3}{#1}{#4}%
+  }
+  %
\newcommand{\newleipzig}[4][]{%
\bgroup
-    {\newacronym[type=\leipzigtype,#1]{#2}{#3}{#4}}%
+    {\leipzig@maybe@usc\leipzig@newacronym@aux{#3}{#1}{#2}{#4}}% useless group?
\@newleipzig#2\@nil%
}%
\def\@newleipzig#1#2\@nil{%
@@ -465,11 +527,11 @@
}%
}%
{%
-  \newcommand{\newleipzig}[4][]{\@newleipzig(#3)#2\@nil}%
+  \newcommand{\newleipzig}[4][]{\leipzig@maybe@usc\@newleipzig{#3}#2\@nil}%
\newcommand{\renewleipzig}[4][]{%
\if@leipzig@defined{#2}
{%
-       \@newleipzig(#3)#2\@nil%
+       \leipzig@maybe@usc\@newleipzig{#3}#2\@nil
}%
{%
\PackageError{leipzig}
@@ -484,7 +546,7 @@
\expandafter\@secondoftwo
\fi
}
-  \def\@newleipzig(#1)#2#3\@nil{%
+  \def\@newleipzig#1#2#3\@nil{%
\uppercase{\expandafter\gdef\csname #2}#3\endcsname{\leipzigfont{#1}}%
}%
}


Unless the package author knows a good reason that I ignore, the outer braces where I commented “useless group?” can be removed.

Enter question or answer id or url (and optionally further answer ids/urls from the same question) from

Separate each id/url with a space. No need to list your own answers; they will be imported automatically.