OpenType feature tips: ordinals

This is part of a set of posts on OpenType font features. Here's the full list of posts:


Ordinal numbers are numbers describing something's position in an order, e.g. “first”, “second”, “third”. They're often abbreviated by combining the number with the last few letters from the ordinal word, e.g. “1st”, “2nd”, “3rd”. Those letters are called the ordinal indicator (e.g. the “st” in “1st”).

Historically, in several West-European languages, ordinal indicators were written in superscript (shrunk and raised above the baseline), but you don't want to apply this superscript to everything in your text, just certain combinations of numerals and letters.

Enter “ordinals”, codename ordn. If you write this feature's code correctly (see below for an example), you can apply it to an entire block of text and it'll automatically superscript ordinal indicators and only ordinal indicators, saving you time superscripting every ordinal by hand.

Which letters do you need? #

This is the slightly tricky thing. There are dozens of different indicators across West-European languages. These examples cover all the common modern ordinal indicators I'm aware of:

English
1st, 2nd, 3rd, 4th
Irish
French
1er, 1ers, 1re, 1res, 2e, 2es, 2d, 2ds, 2des
Spanish and Portuguese
1o, 1os, 1a, 1as, 1.o, 1.os, 1.a, 1.as
Spanish extras
1er, 1ers, 1.er, 1.ers
Asturian
1u, 1us, 1a, 1as, 1o, 1os

And here are all the characters you need to change in the feature (the period used in some of those ordinals isn't superscripted):

OpenType code #

This code uses contextual substitution to detect when a series of indicator letters follow a numeral (or a numeral followed by a period) and replace those letters with superscript forms (marked .ordn, though you could just use regular superscript forms, often marked .sups).

@figures = [ zero one two three four five six seven eight nine ];
@indicators = [ a d e h n o r s t u uacute ];
@indicatorsSuper = [ a.ordn d.ordn e.ordn h.ordn n.ordn o.ordn r.ordn s.ordn t.ordn u.ordn uacute.ordn ];

sub @figures @indicators' by @indicatorsSuper;
sub @figures period @indicators' by @indicatorsSuper;
sub @indicatorsSuper @indicators' by @indicatorsSuper;

You can add the following code if you have ligatures for ordinal indicators (this can be useful if, e.g. you're creating a handwriting-styled font):

# ligatures
## English
sub s.ordn t.ordn by s_t.ordn;
sub n.ordn d.ordn by n_d.ordn;
sub r.ordn d.ordn by r_d.ordn;
sub t.ordn h.ordn by t_h.ordn;

## French
sub e.ordn r.ordn s.ordn by e_r_s.ordn;
sub e.ordn r.ordn by e_r.ordn;
sub r.ordn e.ordn s.ordn by r_e_s.ordn;
sub r.ordn e.ordn by r_e.ordn;
sub d.ordn e.ordn s.ordn by d_e_s.ordn; # variant second
sub d.ordn e.ordn by d_e.ordn; # variant second
sub d.ordn s.ordn by d_s.ordn; # variant second
sub e.ordn s.ordn by e_s.ordn;

## Iberian
sub a.ordn s.ordn by a_s.ordn;
sub o.ordn s.ordn by o_s.ordn;
sub u.ordn s.ordn by u_s.ordn;

I haven't divided this code by language; you can type any ordinal indicator in any language and it'll apply just the same (e.g. type “1ú” in English and the “ú” will still get superscripted).


If you want to implement ordinals you need to write more-complex feature code than either of the two previous features I went over (tabular figures and case-sensitive forms). You not only need to redraw all the glyphs in the feature in mini, you also need to write some code with custom character classes, conditional substitutions, and many-to-one substitutions. However, it's still a widely-recognised feature! If the code above doesn't make total sense, check out the OpenType Cookbook. Fortunately, the last post in this set uses much simpler code.