Follow BCP 47 for language codes: tags in the code and the tests, folder names only where the browser demands them #12

Closed
opened 2026-10-01 06:39:30 +00:00 by tiagoagueda · 0 comments
Owner

The requirement: all language codes must follow BCP 47. A BCP 47 tag (RFC 5646) is made of subtags from the IANA registry joined by hyphens, and §2.1.1 gives the form to write one in: the language in lower case, a script in title case, a region in upper case (pt-BR, en-GB, sr-Cyrl). The rule for the whole project is postulo/postulo#337; this is what it means for the extension, whose source this repository holds for both browsers.

What exists today

  • Already canonical. Each catalogue's languageTag is a tag in the right form (pt-BR, pt-PT, nb, fr). It is what the pages put in <html lang> (src/lib/i18n.js:23), what dates are formatted with on the list page (Intl.DateTimeFormat(t("languageTag")), src/captures.js:177), and what the downloadable log's header says (src/options.js:48).
  • Forced by the browser. The folders under src/_locales/ are named the way the WebExtension format demands, with an underscore: pt_BR, pt_PT. default_locale in the manifest names a folder. These stay.

Where it does not follow

  1. The test holds folder names, not tags. OFFERED in test/i18n.test.mjs lists "pt_BR" and "pt_PT", and the check that a catalogue names its own language is folder.replace("_", "-"): it swaps one character and checks neither case nor validity.
  2. One date ignores the tag. The popup's "captured before" date is toLocaleDateString() with no locale (src/popup.js:204), so it follows the browser, not the catalogue in use. postulo/postulo-chromium#11 names the same line.
  3. A comment writes the core's codes as locale names (fr_FR, en_GB, test/i18n.test.mjs:11).
  4. Two tags for one catalogue. The extension says fr and en where the core says fr-fr and en-gb (fr-FR and en-GB once postulo/postulo#337 lands). Both are valid; the mapping is written nowhere but that comment.

What the extension should do

  • The list of languages is a list of BCP 47 tags in canonical form, and a folder's name is derived from its tag (hyphen to underscore) in one place. The test asserts each languageTag is canonical, for instance Intl.getCanonicalLocales(tag)[0] === tag, and that the folder is the one derived from it.
  • Every date and every lang attribute uses the tag of the catalogue in use.
  • The mapping from the core's tags to the extension's is written down once, with its rule: the region is dropped where the core has one variety of a language, kept where it has two. postulo/postulo-chromium#10 proposes the script that writes the list from the core; it is the place for it.
  • Whatever a person chooses or the extension sends is a tag, never a folder name: the stored display language of postulo/postulo-chromium#11, and an Accept-Language header if that issue adds one.
  • The README's Languages section states the rule.

Decisions

  • Serbian. The catalogue is Cyrillic and its tag is sr. If postulo/postulo#337 settles on sr-Cyrl, languageTag can say so while the folder stays sr, the name browsers match. Recommended: follow the core.
  • fr or fr-FR. Recommended: keep fr and en: a browser set to any French matches the fr folder, and the tag should name the catalogue actually served.

postulo-firefox needs no change: it holds no language code and takes this through its pin. No new on-screen sentence is expected; if one appears, test/i18n.test.mjs requires it in all 40 _locales at once.

Done when

  • npm test fails on a languageTag that is not a canonical BCP 47 tag, and on a folder whose name is not derived from its tag.
  • The popup's dates follow the catalogue in use.
  • The README says what a language code is here and where the underscore form is the browser's.

Requested on 2026-10-01: all language codes must follow BCP 47.

The requirement: **all language codes must follow BCP 47.** A BCP 47 tag (RFC 5646) is made of subtags from the IANA registry joined by hyphens, and §2.1.1 gives the form to write one in: the language in lower case, a script in title case, a region in upper case (`pt-BR`, `en-GB`, `sr-Cyrl`). The rule for the whole project is postulo/postulo#337; this is what it means for the extension, whose source this repository holds for both browsers. ## What exists today - **Already canonical.** Each catalogue's `languageTag` is a tag in the right form (`pt-BR`, `pt-PT`, `nb`, `fr`). It is what the pages put in `<html lang>` (`src/lib/i18n.js:23`), what dates are formatted with on the list page (`Intl.DateTimeFormat(t("languageTag"))`, `src/captures.js:177`), and what the downloadable log's header says (`src/options.js:48`). - **Forced by the browser.** The folders under `src/_locales/` are named the way the WebExtension format demands, with an underscore: `pt_BR`, `pt_PT`. `default_locale` in the manifest names a folder. These stay. ## Where it does not follow 1. **The test holds folder names, not tags.** `OFFERED` in `test/i18n.test.mjs` lists `"pt_BR"` and `"pt_PT"`, and the check that a catalogue names its own language is `folder.replace("_", "-")`: it swaps one character and checks neither case nor validity. 2. **One date ignores the tag.** The popup's "captured before" date is `toLocaleDateString()` with no locale (`src/popup.js:204`), so it follows the browser, not the catalogue in use. postulo/postulo-chromium#11 names the same line. 3. **A comment writes the core's codes as locale names** (`fr_FR`, `en_GB`, `test/i18n.test.mjs:11`). 4. **Two tags for one catalogue.** The extension says `fr` and `en` where the core says `fr-fr` and `en-gb` (`fr-FR` and `en-GB` once postulo/postulo#337 lands). Both are valid; the mapping is written nowhere but that comment. ## What the extension should do - The list of languages is a list of BCP 47 tags in canonical form, and a folder's name is derived from its tag (hyphen to underscore) in one place. The test asserts each `languageTag` is canonical, for instance `Intl.getCanonicalLocales(tag)[0] === tag`, and that the folder is the one derived from it. - Every date and every `lang` attribute uses the tag of the catalogue in use. - The mapping from the core's tags to the extension's is written down once, with its rule: the region is dropped where the core has one variety of a language, kept where it has two. postulo/postulo-chromium#10 proposes the script that writes the list from the core; it is the place for it. - Whatever a person chooses or the extension sends is a tag, never a folder name: the stored display language of postulo/postulo-chromium#11, and an `Accept-Language` header if that issue adds one. - The README's *Languages* section states the rule. ## Decisions - **Serbian.** The catalogue is Cyrillic and its tag is `sr`. If postulo/postulo#337 settles on `sr-Cyrl`, `languageTag` can say so while the folder stays `sr`, the name browsers match. Recommended: follow the core. - **`fr` or `fr-FR`.** Recommended: keep `fr` and `en`: a browser set to any French matches the `fr` folder, and the tag should name the catalogue actually served. postulo-firefox needs no change: it holds no language code and takes this through its pin. No new on-screen sentence is expected; if one appears, `test/i18n.test.mjs` requires it in all 40 `_locales` at once. ## Done when - `npm test` fails on a `languageTag` that is not a canonical BCP 47 tag, and on a folder whose name is not derived from its tag. - The popup's dates follow the catalogue in use. - The README says what a language code is here and where the underscore form is the browser's. Requested on 2026-10-01: all language codes must follow BCP 47.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
Postulo/postulo-chromium#12
No description provided.