Let's say you have a font that has a set of Cyrillic alternates in the “round upright cursive with extenders” aka “Bulgarian” style, and the default Cyrillic glyphs are in the “square” aka “Russian” style.
You could implement a substitution lookup that replaces the square with the round style in the “locl” (Localized Forms) feature for the “cyrl BGR” (Bulgarian) languagesystem. Apps that support it would automatically do the replacement if the user tags the text as being set in the Bulgarian language (also for spellcheck and hyphenation purposes).
In addition, you could implement the replacement in a stylistic set (e.g. “ss04”) for use in apps that don't support localized forms.
But imagine that a user who users an app that supports localized forms tags the text as Bulgarian for spellcheck and hyphenation purposes, but they would prefer (for whatever reasons) to set it in the square (“Russian”) typographic style. It's not obvious how they could achieve that, because the app might not offer any UI to deactivate “locl”.
I think the solution should be that the same “ss04” feature works both ways:
One and the same lookup replaces the alternate forms with the default ones and the default ones with the alternates.
So if the input string had the default forms, with “ss04” applied, you get the alternates, but if it had the alternates (as a result of the previously automatically applied "locl"), you get the defaults. So effectively, you get a “swap”. There is no risk of any circular replacements if the swapping is done inside the same lookup.
This could be of course also done in two different stylistic sets, but if your font has many stylistic sets, this might be unreasonable. So it is a question of UX.
This technique could be used for any replacements that are performed automatically which the user might want to “undo”. What do you think?
Comments
This pertains to the recently released Minion 3. The reformed round Bulgarian style appeared in the 1960s and only recently gained popularity.
Say that a publisher wants to set a book written in Bulgarian in the 1940s, or maybe issue a re-edition of a book that was published earlier and was set in older Minion
Then the publisher may wish to use InDesign’s “Bulgarian” language setting to get proper hyphenation, but may wish to preserve the “Russian style” of the Cyrillic, which may have been previously used in an earlier edition of the text.
If the font implements the round style using both “locl” and “ss04” (does Minion 3 do that?), then achieving it might be tricky (or is there a way to switch from Bulgarian to default already?).
More generally, the reason to implement the Cyrillic replacement in both “locl” and “ssXX“ features is not just that the stylistic set needs to a fallback choice for apps that don't support localized forms.
The round Cyrillic forms may be the increasingly preferred localized forms for the Bulgarian language today, while many other Cyrillic language communities currently prefer the square forms — but it doesn't mean that this will always be that way.
The Bulgarian designers from the 1960s proposed this new style as a reformed Cyrillic, not just reformed Bulgarian Cyrillic.
This has gained traction just in Bulgaria so far, but who knows — perhaps some communities will also like this style for another language. So offering this as a stylistic set makes sense as well, especially since fonts tend to be quite long-lived.
Interesting line of thinking, and I think it has a lot of merit. Particularly in situations where there are fluid and evolving norms.
Of course, if the substitutions are in two separate lookup tables, then it will work for only half the scenarios you care about.
will do. Very briefly:
My friend and colleague Botio Nikoltchev has created this guide for implementing Bulgarian "locl" alternates:
https://www.lettersoup.de/what-shall-be-done-for-bulgarian-cyrillic-loclbgr/
To extend this, instead of the current recommended implementation down there as:
feature ss04{
sub uni0414 by uni0414.loclBGR;
sub uni041B by uni041B.loclBGR;
sub uni0424 by uni0424.loclBGR;
...
}ss04;
you would do this:
feature ss04{
sub uni0414 by uni0414.loclBGR;
sub uni0414.loclBGR by uni0414;
sub uni041B by uni041B.loclBGR;
sub uni041B.loclBGR by uni041B;
sub uni0424 by uni0424.loclBGR;
sub uni0424.loclBGR by uni0424;
...
}ss04;
Of course it doesn't have to be "ss04" but can be any ssXX feature.
The principle is that in one and the same lookup, you have substitutions that go both ways. If you put your code right between the "feature XXXX{ ... }XXXX" keywords as shown above, without using the keyword "lookup", all the substitutions will indeed be in the same lookup, which is what you want.
In short, the code in "locl" goes just one way, and the code in "ssXX" goes both ways so you have twice as many substitution lines. That's the easiest way to make sure it works.
I'll work on some more info about this and will help extend Botio's article on his Lettersoup website.
Adam
# In the FEA code in the Features panel, the prefix section (in FLS5, bottom-right section, in FLVI top section), define all languagesystems that your font will support, e.g.:
languagesystem DFLT dflt;
languagesystem latn dflt;
languagesystem cyrl dflt;
languagesystem cyrl BGR;
# Define your "loclBGR1" OpenType class in the classes panel — or in the prefix section of the FEA code using the "loclBGR1 = [glyphname glyphname...];" syntax.
# That class should list all the default ("square/Russian") glyphs, i.e. the glyphs that have Unicode codepoints assigned.
# Define your loclBGR2 OpenType class in the classes panel — or in the prefix section of the FEA code using the "loclBGR2 = [glyphname glyphname...];" syntax.
# That class should list all the alternate ("round/Bulgarian") glyphs, and should have the same number of glyphs as loclBGR1, and the order of the glyphs in the class definitions should correspond.
# Add the feature definition for locl (in this example only for Bulgarian but your font may have other localized forms for other languages also from other scripts):
feature locl {
script cyrl;
language BGR;
sub @loclBGR1 by @loclBGR2;
} locl;
# Add the feature definition for the stylistic set (here, ss04 is used as an example). Note that this feature definition makes the substitutions go both ways, which is what we're talking about here.
feature ss04 {
sub @loclBGR1 by @loclBGR2;
sub @loclBGR2 by @loclBGR1; # This very line is my "new idea", everything else has been done previously by font developers.
} ss04;
# I believe that this should work fine. I'll need to double-check if the two sub-class-by-class statements will correctly expand to just a list of simple substitutions in the same lookup, but I think they will.
(Did I get that right?)
Thank you for the link! I found the whole article is more understandable than an official documentation.
One thing I didn't see in your book is the statement of the convention that a sequence of rules not explicitly written within a lookup is implicitly grouped into a single lookup.
Instead of "Bulgarian Cyrillic" the Set could be named like a "Bulgarian/Russian Cyrillic". Not sure about the slash in a featureNames, but what do you think?