The full version of langtag-clj needs the IANA Language Subtag Registry. This page says what it needs from it, how small that can be and how a ClojureScript build can leave it out when nothing uses it. The registry is that of 17 September 2026, and the builds are releases of shadow-cljs 3.5.3 with advanced compilation.
| Feature | Field of the registry | Records |
|---|---|---|
| Validity (RFC 5646, section 2.2.9) | the subtags of each type | 9,203 |
| The canonical form (section 4.5) | Preferred-Value (section 3.1.7) | 423 |
| The extlang form (section 4.5) | the Prefix of an extlang (section 3.1.8) | 258 |
| Scripts that go without saying | Suppress-Script (section 3.1.9) | 134 |
| Macrolanguages | Macrolanguage (section 3.1.10) | 545 |
| The prefixes of variants, which section 4.1 recommends | the Prefix of a variant | 132 |
None of them read the descriptions, comments or dates, which are more than half of the registry's 731 KB. The -u- and -t- extensions take their keys from CLDR's BCP 47 data rather than from this registry, so they're left for later.
Most of the data is the 8,085 language subtags of three letters. They fill half of the 17,576 combinations of three letters, so a bit for each combination (2.9 KB in base64) is much smaller than a list of them. Go's x/text/language packs its tables in the same spirit, as sorted strings of fixed width that it searches by halves (gen.go).
| Data | As lists | With the languages as bits |
|---|---|---|
| Validity | 37 KB, 21 KB gzipped | 6 KB, 4 KB gzipped |
| The mappings of the canonical form, the extlang form, Suppress-Script and macrolanguages | 11 KB, 4 KB gzipped | the same |
| Both | 48 KB, 25 KB gzipped | 17 KB, 8 KB gzipped |
For comparison, the registry is 731 KB (99 KB gzipped), and npm's language-tags, which ships it as JSON, is listed at 1,049 KB minified and 156 KB gzipped (DepScope).
Advanced compilation drops a table that nothing asks for, as long as nothing reads it when its namespace loads. These are builds with a test table of 60 KB:
| The table's namespace | Build | Gzipped |
|---|---|---|
| not required | 90 KB | 19 KB |
| required, with the table parsed in a delay that nothing derefs | 91 KB | 19 KB |
| required, with the table parsed in a function that nothing calls | 91 KB | 19 KB |
| required, with the table parsed when the namespace loads | 224 KB | 93 KB |
| required and used, with the table parsed by clojure.string/split | 224 KB | 94 KB |
| required and used, with the table parsed by one call of .split | 155 KB | 57 KB |
Two rules follow:
A table for each feature, each in a delay of its own, would let a project that only checks validity leave out the mappings too. That follows from the same rule, but I didn't test it.
As whatwg-url ships its Unicode tables:
The registry gets new subtags four or five times a year: its records carry 18 dates of addition since 2023. Each update means a new File-Date and a release. That's enough for now. A function that reads the registry file itself (as whatwg-url has for the Public Suffix List) can wait until a project needs subtags before a release has them.
That's about as much work again as the minimal version, most of it in the generator and the tests.
Can you improve this documentation?Edit on GitHub
cljdoc builds & hosts documentation for Clojure/Script libraries
| Ctrl+k | Jump to recent docs |
| ← | Move to previous article |
| → | Move to next article |
| Ctrl+/ | Jump to the search field |