“Authors Give Back” SmashWords Sale (March 20 - April 20, 2020): ebook editions of crime novel The Private Enemy and short story I've Heard the Mermaid Sing both FREE for the duration of the sale.

# Writing a datetime2 Language Module

The article Localisation with tracklang.tex describes the reason why I created the tracklang package. The article Integrating tracklang into Language Packages gives an example of how to integrate tracklang into a language package. The article Using tracklang in Packages with Localisation Features is for those who are writing a package that needs to detect the document’s localisation settings.

This article describes how to write a datetime2 language resource file. I recommend you first read the previous articles (particularly Using tracklang in Packages with Localisation Features) to understand the purpose of tracklang and how it’s designed to allow packages to input the appropriate language resource files.

I originally created both the tracklang and datetime2 packages around the same time, with the initial release of datetime2 occurring around six months after the initial release of tracklang. This means that the original .ldf language resource files don’t use some of the more convenient commands added to tracklang at a later date.

For example, instead of using \TrackLangRequireDialect datetime2 defines its own internal command that uses \IfTrackedLanguageFileExists. Instead of using \TrackLangRequireResource, datetime2 uses \RequireDateTimeModule. (The new tracklang commands were introduced as a result of developing the datetime2 commands and expanding them for more general purpose use.)

Each datetime2 language file identifies itself with:

\ProvidesDateTimeModule{localeid}[version]


This is analogous to the new \TrackLangProvidesResource added to tracklang v1.3.

The code to redefine the date hook is also quite convoluted. For example, datetime2-en-GB.ldf uses:

\ifcsundef{date\CurrentTrackedDialect}
{% do nothing
\ifundef\dateenglish
{%
}%
{%
\def\dateenglish{%
\DTMifcaseregional
{}% do nothing
{\DTMsetstyle{en-GB}}%
{\DTMsetstyle{en-GB-numeric}}%
}%
}%
}%
{%
\csdef{date\CurrentTrackedDialect}{%
\DTMifcaseregional
{}% do nothing
{\DTMsetstyle{en-GB}}%
{\DTMsetstyle{en-GB-numeric}}%
}%
}%


This essentially works like \TrackLangRedefHook except that it doesn’t take mappings into account. With tracklang v1.4, a more compact method would be:

\TrackLangRedefHook
{% new definition of \date... hook:
\DTMifcaseregional
{}% do nothing
{\DTMsetstyle{en-GB}}%
{\DTMsetstyle{en-GB-numeric}}%
}%
{date}


In time I may add v1.4 as a requirement for datetime2 and update it to use \TrackLangRequireDialect and \TrackLangRequireResource, but it’s currently too early to do that as v1.4 has only just been released at the time of writing. However, if your language files require other features of v1.4 then you may insist on that version as a minimum requirement.

As discussed in the previous article, it’s useful to have a base file for common elements (such as month names). If you have multiple scripts, you may need a base file for each script. Remember that when the file starts with the file identifier (\ProvidesDateTimeModule) each resource file can only be loaded once with \RequireDateTimeModule (just as a package can only be loaded once with \usepackage/ or \RequirePackage). For example, the file datetime2-serbian.ldf might simply contain the line:

\RequireDateTimeModule{sr-\CurrentTrackedDialectScript}


which will load datetime2-sr-Cyrl.ldf or datetime2-sr-Latn.ldf depending on the script. This provides a fallback in the event that a pre-v1.4 version of tracklang is installed.

Each language file should contain a date-time style with month names (and optionally day of week names), which should be used with the useregional=text option, and a numeric style, which should be used with useregional=numeric. The \DTMifcaseregional code in the date hook is used to determine which style to set. The first case, which corresponds to useregional=false, indicates that the date-time style shouldn’t change when the document localisation changes. In other words, the \date… should do nothing.

The naming convention for the locale date-time styles is now 〈localeid〉 for the textual date and 〈localeid〉-numeric for the numeric date. This allows \DTMtryregional to guess the style name. However, that command was only introduced to datetime2 v1.5.2 and the regionless style provided in datetime2-english.ldf doesn’t define a numeric style, but instead just switches to the default style if useregional=numeric, so that’s a legacy case.

One of the major issues with the precursor datetime package was that the date commands couldn’t expand. (They were made robust because the definitions contained fragile content.) This causes a problem in certain situations where the date needs to expand, typically because the date needs to be written to an external file (such as hyperref’s bookmarks file or the table of contents file). The datetime2 package was designed with expandable commands in mind (although there are some robust commands). Therefore new styles are encouraged to be designed in an expandable manner.

An exception to this is the style provided by the datetime2-en-fulltext package, but this isn’t a locale-sensitive resource file and the style is documented as being non-expandable. This is an example of an ornate style rather than a practical everyday style.

Here are some general guidelines to help keep styles expandable:

• Avoid \relax if possible. This doesn’t expand. If a date needs to be written to an external file that’s read by something (or someone!) other than TeX, control sequences that end up in the file can be problematic. If you look at some existing styles, you may notice “space intended” comments. These highlight where a space is used to indicate the end of a number in situations where TeX discards the space but recognises it as a terminator (just as with spaces occurring after control sequence names). So instead of \number##1\relax do:
\number##1 % space intended

• Use \DTMtexorpdfstring if you do have some non-expandable content. This includes \⌴ (that is backslash space). For example, datetime2-english-base.ldf provides \DTMenglishampmfmt for formatting the “am” etc parts. Since the definition of this can include font changing commands, it’s not always expandable. Therefore \DTMtexorpdfstring has to be used:
\DTMtexorpdfstring
{\DTMenglishampmfmt{\DTMenglisham}}%
{\DTMenglisham}%

• Don’t use the fmtcount package for date ordinals. (The code from the original release of fmtcount was actual split way from the old datetime package and developed independently. However the commands aren’t expandable and so shouldn’t be used in date styles unless they are ornate styles that are documented as unexpandable.) Since there are a maximum number of 31 days in a month it’s simpler to use \ifcase.)

The inputenc package provides a trick to support UTF-8 characters where the first octet is made active and takes the second octet as the argument. This meant that UTF-8 characters expanded to a form involving \IeC when being written to a file. This isn’t a problem for XeLaTeX and LuaLaTeX, which both natively support UTF-8. Therefore the language resource files that use extended Latin or non-Latin characters provided a UTF-8 version for XeLaTeX/LuaLaTeX and an ASCII version for LaTeX/PDFLaTeX. For example, datetime2-danish.ldf has:

\RequirePackage{ifxetex,ifluatex}
\ifxetex
\RequireDateTimeModule{danish-utf8}
\else
\ifluatex
\RequireDateTimeModule{danish-utf8}
\else
\RequireDateTimeModule{danish-ascii}
\fi
\fi


The LaTeX kernel release 2019/10/01 changed the way UTF-8 characters are dealt with so they should now not be expanded when written to a file. This means that the ASCII version can start to be phased out in favour of the UTF-8 version. You can test the LaTeX version with:

\@ifl@t@r\fmtversion{2019/10/01}
% code for new format
{ ... }
% older formats
{ ... }


If your date style ends with a period (full-stop) then you can use \DTMfinaldot in its place. (Requires at least datetime2 v1.5.5.) The starred versions of \DTMdate and \DTMDate locally redefine \DTMfinaldot to do nothing to allow the user to display the date without the terminating punctuation.