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
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
- Subtags use ASCII hyphens (
-). Underscores are invalid: usept-br, not
pt_BR.
- Examples include
en,zh-hans,zh-hant,pt-br, andsr-latn-rs. -
zh-cnis a region-qualified Chinese tag andzh-hansis a script-qualified
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
enand
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
{ "schema_version": 2, "name": "sqlite", "summary": "SQLite 文件数据库扩展", "summary.en": "SQLite file database extension", "description": "为 BT 项目提供 SQLite 访问能力。", "description.en": "Provides SQLite access for BT projects.", "author": "BT Team", "developer": { "id": "bt_official", "name": "BT 官方", "name.en": "BT Official", "homepage": "https://btlang.org" }, "repository": "https://github.com/bt-lang/bt/tree/main/extension/sqlite", "license": "MIT OR Apache-2.0", "latest": "1.0.0", "versions": [] }
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
| Field | Type | Required | Default | Valid value | Meaning |
|---|---|---|---|---|---|
schema_version | Int | Yes | None | 2 | Registry metadata schema. |
name | String | Yes | None | Lowercase extension identifier | Stable machine name; never localized. |
summary | String | Yes | None | Non-empty text in the publisher's chosen default language | Default short description. |
summary.<locale> | String | No | summary | Non-empty text; locale is normalized BCP 47 | Exact localized short description. |
description | String | Yes | None | Non-empty text in the publisher's chosen default language | Default full description. |
description.<locale> | String | No | description | Non-empty text; locale is normalized BCP 47 | Exact localized full description. |
author | String | Yes | None | Non-empty text | Package author fallback; not selected by locale. |
developer | Object | Yes | None | Fields below | Publisher identity. |
repository | String | Yes | None | Public HTTPS URL | Source repository for this release. |
license | String | Yes | None | SPDX expression | Package license. |
latest | String | Yes | None | Published SemVer | Latest non-yanked version. |
versions | Array[Object] | Yes | None | At least one published version | Version and package records. |
developer fields
| Field | Type | Required | Default | Valid value | Meaning |
|---|---|---|---|---|---|
id | String | Yes | None | Stable publisher identifier | Machine identity; never localized. |
name | String | Yes | None | Non-empty text in the publisher's chosen default language | Default publisher display name. |
name.<locale> | String | No | name | Non-empty text; normalized BCP 47 suffix | Exact localized display name. |
homepage | String | Yes | None | Public HTTPS URL | Publisher homepage. |
versions item fields
| Field | Type | Required | Default | Valid value | Meaning |
|---|---|---|---|---|---|
version | String | Yes | None | Three-part SemVer | Published extension version. |
file | String | Yes | None | <name>-<version>.bts | Download filename. |
download_url | String | Yes | None | Registry HTTPS API URL | Canonical download endpoint. |
sha256 | String | Yes | None | 64 lowercase hexadecimal characters | Exact package digest. |
size | Int | Yes | None | Positive byte count | Exact package size. |
bt_min_version | String | Yes | None | Three-part SemVer | Oldest compatible BT runtime. |
kind | String | Yes | None | bt or wasm | Extension backend. |
abi | String | Yes | None | ABI supported by the selected kind | Runtime calling contract. |
created_at | String | Yes | None | Registry publication timestamp | Publication time. |
yanked | Bool | Yes | false | true or false | Whether new installation should be discouraged. |
downloads | Int | Yes | 0 | Nonnegative | Recorded installation count. |
permissions | Array[String] | Yes | [] | Manifest permission identifiers | Capabilities shown before installation. |
exports | Array[Object] | Yes | [] | name and returns per item | Public global entries; identifiers are not localized. |
objects | Array[Object] | Yes | [] | name and methods per item | Public object API summary; identifiers are not localized. |
README localization
The publisher chooses the language of readme.md. Localized files add a
normalized dotted suffix:
readme.md readme.en.md readme.zh-hans.md readme.zh-hant.md readme.ja.md readme.pt-br.md
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,
- Translation suffixes must match the website's normalized URL locale exactly.
- Language tags are case-insensitive for comparison; filenames and JSON keys use
- The root preference is only an initial redirect hint. Bookmarkable, canonical,