Publishing extensions

Publishing extensions

Publishing extensions

Function

The BT website extension registry stores installable package metadata under

db/ext/<name>/<version>/. This page defines the info.json localization model,

README filenames, language-tag rules, fallback behavior, and the distinction

between browser language preferences and explicit localized URLs.

Registry metadata schema 2 lets the publisher choose the language of each

unsuffixed default field. Additional translations use a dot followed by the

website's normalized language tag, for example summary.en or

summary.zh-hans. Machine-readable identifiers are never translated.

Language-tag standard

Language identifiers follow BCP 47. BCP 47 is the umbrella specification:

RFC 5646 defines the syntax and registry

of language tags, while RFC 4647

defines language-range matching. These are complementary specifications, not

alternative naming systems.

The HTML language-preference standard

requires navigator.language and every entry in navigator.languages to be

valid BCP 47 language tags. The latter is ordered by preference. HTTP

Accept-Language is defined by

RFC 9110 section 12.5.4

as a preference list of language ranges with optional q weights. The HTML

standard recommends that browsers use the same preference list for the Navigator

APIs and the HTTP header, but privacy measures mean a server must not assume their

byte-for-byte values are always identical.

BT language tags obey these storage rules:

  • Tags are compared case-insensitively as required by BCP 47, then normalized to
lowercase for URL segments, JSON suffixes, and filenames.
  • Subtags use ASCII hyphens (-). Underscores are invalid: use pt-br, not
pt_BR.
  • Examples include en, zh-hans, zh-hant, pt-br, and sr-latn-rs.
  • zh-cn is a region-qualified Chinese tag and zh-hans is a script-qualified
Chinese tag. They are not generally interchangeable. The current website

redirects its historical zh-cn URL alias to zh-hans; this is a website

compatibility rule, not a general BCP 47 equivalence.

  • The current public website supports the explicit URL locales en and
zh-hans. Metadata for another valid tag can be prepared, but it is displayed

only after that locale is added to the website route allowlist.

Case normalization is mandatory because the production filesystem can be

case-sensitive. readme.zh-Hans.md, readme.ZH-HANS.md, and

readme.zh-hans.md would otherwise be different files on Linux. The registry

accepts one canonical stored spelling: readme.zh-hans.md.

Website language selection

An explicit localized URL such as /en/ext/sqlite or

/zh-hans/ext/sqlite always determines the rendered language. It is not changed

by JavaScript, cookies, or request headers.

Only a request to the root / performs language negotiation, in this order:

1. A supported bt_locale cookie wins.

2. Otherwise the server reads the HTTP Accept-Language header, honors valid

q weights, retains header order for equal weights, and selects a supported

website locale.

3. If no supported language matches, the website uses en.

The website does not execute navigator.language to select the initial route.

The browser normally creates Accept-Language from its language preferences and

sends it with the HTTP request, allowing the server to redirect before HTML and

JavaScript load. Current Chinese language ranges map to the available

zh-hans site locale; English ranges and * map to en. A q=0 range is not

acceptable. Responses from explicit localized routes set the corresponding

Content-Language value.

Syntax

Localized JSON property names contain a literal dot. Consumers must use bracket

lookup such as info['summary.' + locale]; info.summary.zh-hans does not mean

the same thing.

info.json fields

FieldTypeRequiredDefaultValid valueMeaning
schema_versionIntYesNone2Registry metadata schema.
nameStringYesNoneLowercase extension identifierStable machine name; never localized.
summaryStringYesNoneNon-empty text in the publisher's chosen default languageDefault short description.
summary.<locale>StringNosummaryNon-empty text; locale is normalized BCP 47Exact localized short description.
descriptionStringYesNoneNon-empty text in the publisher's chosen default languageDefault full description.
description.<locale>StringNodescriptionNon-empty text; locale is normalized BCP 47Exact localized full description.
authorStringYesNoneNon-empty textPackage author fallback; not selected by locale.
developerObjectYesNoneFields belowPublisher identity.
repositoryStringYesNonePublic HTTPS URLSource repository for this release.
licenseStringYesNoneSPDX expressionPackage license.
latestStringYesNonePublished SemVerLatest non-yanked version.
versionsArray[Object]YesNoneAt least one published versionVersion and package records.

developer fields

FieldTypeRequiredDefaultValid valueMeaning
idStringYesNoneStable publisher identifierMachine identity; never localized.
nameStringYesNoneNon-empty text in the publisher's chosen default languageDefault publisher display name.
name.<locale>StringNonameNon-empty text; normalized BCP 47 suffixExact localized display name.
homepageStringYesNonePublic HTTPS URLPublisher homepage.

versions item fields

FieldTypeRequiredDefaultValid valueMeaning
versionStringYesNoneThree-part SemVerPublished extension version.
fileStringYesNone<name>-<version>.btsDownload filename.
download_urlStringYesNoneRegistry HTTPS API URLCanonical download endpoint.
sha256StringYesNone64 lowercase hexadecimal charactersExact package digest.
sizeIntYesNonePositive byte countExact package size.
bt_min_versionStringYesNoneThree-part SemVerOldest compatible BT runtime.
kindStringYesNonebt or wasmExtension backend.
abiStringYesNoneABI supported by the selected kindRuntime calling contract.
created_atStringYesNoneRegistry publication timestampPublication time.
yankedBoolYesfalsetrue or falseWhether new installation should be discouraged.
downloadsIntYes0NonnegativeRecorded installation count.
permissionsArray[String]Yes[]Manifest permission identifiersCapabilities shown before installation.
exportsArray[Object]Yes[]name and returns per itemPublic global entries; identifiers are not localized.
objectsArray[Object]Yes[]name and methods per itemPublic object API summary; identifiers are not localized.

README localization

The publisher chooses the language of readme.md. Localized files add a

normalized dotted suffix:

For /en/ext/<name>, the renderer tries readme.en.md and then readme.md.

For /zh-hans/ext/<name>, it tries readme.zh-hans.md and then readme.md.

It performs an exact normalized-tag lookup and then the publisher's default

fallback; it does not silently truncate pt-br to pt. The same rule applies to

summary.<locale>, description.<locale>, and developer.name.<locale>.

readme.md in the website registry is separate from the uppercase README.md

inside a .bts package. Production registry filenames are lowercase and exact.

The legacy schema 1 fields summary_en, description_en, and name_en remain

readable during migration, but new metadata must use schema 2 dotted keys.

Return value and fallback

The localized HTML page displays the exact localized value when present and the

unsuffixed publisher-defined default value otherwise. The registry JSON API

returns the complete raw metadata, including all translations, so API consumers

can apply the same rule.

Missing translations are not errors and do not produce empty page sections.

Notes

  • Do not localize name, API identifiers, configuration keys, event names,
versions, hashes, permissions, ABI names, filenames, or download URLs.
  • Translation suffixes must match the website's normalized URL locale exactly.
  • Language tags are case-insensitive for comparison; filenames and JSON keys use
lowercase to remain deterministic on case-sensitive and case-insensitive hosts.
  • The root preference is only an initial redirect hint. Bookmarkable, canonical,
and shared links always include an explicit language segment.