1

I am writing a class file which takes an option english and then loads the article class. The english option defined in the new class is not passed to article. However, if then I load babel with option USenglish, then I get the warning

Package Babel Warning: The package option `english' should not be used
(Babel)                with a more specific one (like `USenglish')

as if english was passed to the article class.

Here is how I pass the options to my class:

\NeedsTeXFormat{LaTeX2e}
\ProvidesClass{myclass}[2020/11/07 myclass template]

\newif\ifEnglish\Englishfalse

\DeclareOption{english}{\Englishtrue}
\DeclareOption*{\ClassWarning{myclass}{Unknown option `\CurrentOption'}}
\ProcessOptions\relax

\LoadClass[10pt, a4paper, oneside]{article}

The code

\documentclass[english]{myclass}
\usepackage[USenglish]{babel}

produces the babel warning above. How can I fix this?

I understand that a warning is not an error, but (1) I want to make sure that the scope of the english option I define is limited to myclass and is not inherited by article, (2) I would really like to have a warning-free template, and (3) I would like to load as few packages as possible (thus I'd like to avoid invoking silence just for this).

7
  • 1
    If you pass english to \documentclass this is a global option (LaTeX has a list of global options), and global options are by default parsed in packages as well (which is what happened here). You can fix this by removing english from the list of global options in your class code. Use \@expandtwoargs\@removeelement{english}\@classoptionslist\@classoptionslist if the english option was used to achieve this (untested but should do).
    – Skillmon
    Nov 7, 2020 at 8:51
  • 1
    Apart from what Skillmon has said, I don't think article itself even reacts to the english option. So I think that inheriting to article is a non-issue.
    – moewe
    Nov 7, 2020 at 8:52
  • @Skillmon Thank you for the explanation and for the solution! It works like a charm! Why don't you post your comment as an answer so that I can mark the question as solved
    – AndreasT
    Nov 7, 2020 at 8:55
  • 1
    If you want to avoid problems with your class settings it might be wiser to choose a name for your class option that does not clash with babel's language identifiers. If you insist on the name english it might be an option to handle the class setup with a settings command (like e.g. siunitx's \sisetup or \KOMAoptions from the KOMA Script classes). The nicest option of course would be to make your class interface with babel such that it just uses the language settings selected by the user with babel. (Currently the user may have to declare the language in two different places.)
    – moewe
    Nov 7, 2020 at 8:56
  • @moewe Thank you for the valuable point. I however prefer to stick to english since I'm writing a multilingual template and I believe english is the most "intuitive" option name for the english template.
    – AndreasT
    Nov 7, 2020 at 9:00

2 Answers 2

3

Turning my comment into an answer.

LaTeX maintains a list of global options (this is called \@classoptionslist) containing the options passed to \documentclass. These options are by default forwarded to every package which is loaded after \documentclass (this depends on the used interface used in the different packages, the standard LaTeX interface picks up the global options, but packages like pgfopts, l3keys2e or expkv-opt provide mechanisms to only pass the local option list).

You can remove options from the \@classoptionslist by using the LaTeX macro \@removeelement which takes three arguments, the element which should be removed, the complete list, and the macro in which the filtered list should be stored.

Using this knowledge you could alter your class file to use

\NeedsTeXFormat{LaTeX2e}
\ProvidesClass{myclass}[2020/11/07 myclass template]

\newif\ifEnglish\Englishfalse

\DeclareOption{english}
  {%
    \Englishtrue
    \@expandtwoargs\@removeelement{english}\@classoptionslist\@classoptionslist
  }
\DeclareOption*{\ClassWarning{myclass}{Unknown option `\CurrentOption'}}
\ProcessOptions\relax

\LoadClass[10pt, a4paper, oneside]{article}

which would remove english from the list of global options.


However, as others have noted (thanks @moewe), it might be a better idea to either cooperate with babel, or to use different names. Because of that, the following suggests to use a key=value option with a distinct option name (which is much less likely to clash) for your templates language. I use expkv-opt for this, but the same could also be achieved using pgfkeys with pgfopts, or l3keys and l3keys2e, or kvoptions, or.... (there are a lot of key=value solutions out there).

The following implements english and german as choices for the template-language.

myclass.cls:

\NeedsTeXFormat{LaTeX2e}
\ProvidesClass{myclass}[2020/11/07 myclass template]

\RequirePackage{expkv-opt, expkv-def}
\ekvdefinekeys{myclass}
  {
    choice template-language =
      {
        ,english = \Englishtrue  \Germanfalse
        ,german  = \Englishfalse \Germantrue
      }
  }

\newif\ifEnglish\Englishfalse
\newif\ifGerman\Germanfalse

\ekvoProcessGlobalOptions{myclass}
\ekvoProcessLocalOptions {myclass}

\LoadClass[10pt, a4paper, oneside]{article}

Document:

\documentclass[template-language=english]{myclass}

\usepackage[USenglish]{babel}

\begin{document}
\ifEnglish English \fi
\ifGerman Deutscher \fi
Test
\end{document}

enter image description here

1
  • Excellent explanation and great solution to @moewe 's point. Thanks
    – AndreasT
    Nov 7, 2020 at 9:16
2

It will depend on the exact nature of your template and the localisation your template provides, but for a certain class of localisation features it would probably be nicest if your template could simply react to the language set by the user via babel (and possibly polyglossia).

Unfortunately, there are currently two systems for localisation of documents in LaTeX, babel and polyglossia. The two have slightly different approaches in some areas and no unified interface. There was an effort not too long ago to offer babel-equivalent features in polyglossia to make it easier for developers to write locale-aware packages, but one still has to write different code for babel and polyglossia.

For simple translations of strings with babel you could do something like the following.

\begin{filecontents}[overwrite]{myclass.cls}
\NeedsTeXFormat{LaTeX2e}
\ProvidesClass{myclass}[2020/11/07 myclass template]

\RequirePackage{etoolbox}

\newcommand*{\rabbit}{\textbf{??? rabbit is missing a translation}}

\AtBeginDocument{%
  \appto\captionsenglish{%
    \renewcommand{\rabbit}{rabbit}%
  }%
  \appto\captionsUSenglish{%
    \renewcommand{\rabbit}{rabbit}%
  }%
  \appto\captionsgerman{%
    \renewcommand{\rabbit}{Hase}%
  }%
  \appto\captionsngerman{%
    \renewcommand{\rabbit}{Hase}%
  }%
}

\LoadClass[10pt, a4paper, oneside]{article}
\end{filecontents}

\documentclass{myclass}

\usepackage[USenglish]{babel}

\begin{document}
Ohh, \rabbit!
\end{document}

You simply define a new macro for your string and then use \appto to inject its translation for the language <language> into \captions<language>. (This is done in an \AtBeginDocument hook to make sure that the \captions<language> macros exist already and that our changes are not overwritten. Getting the timing right can be a bit of a pain.)

Packages like tracklang, iflang, translator and translations can also help you with this.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .