Files
foreignthon-docs/docs/contributing/language-packs.md

6.2 KiB

Contributing Language Packs

Language packs are published independently to PyPI — no access to the foreignthon-core repo is needed. There are more packs than the ones listed here; the ones on the official docs site are the ones hosted under the foreign-thon org on Gitea.


The right starting point

Do not start from scratch. Fork the official language template:

https://git.keshavanand.net/foreign-thon/language-template.git

The template gives you:

File Purpose
src/foreignthon_xx/__init__.py Exposes get_pack_path() and reads version/author metadata
src/foreignthon_xx/xx.json The pack file — all keys are English stubs to replace
tests/test_pack.py Universal test suite shared by every official pack
.gitea/workflows/ci.yml Runs pytest on every push and PR
.gitea/workflows/publish.yml Builds and uploads to PyPI on a v* tag
.gitea/workflows/trigger-docs.yml Pings the docs site to rebuild when README.md changes
pyproject.toml Pre-wired entry points, hatchling build, GPL v3

Step 1 — Fork and rename

Fork the template on Gitea (or GitHub mirror). Rename your fork to foreignthon-xx where xx is the ISO 639-1 two-letter code for your language (use ISO 639-2 three-letter code if no two-letter code exists).

Clone your fork locally:

git clone https://git.keshavanand.net/yourname/foreignthon-xx
cd foreignthon-xx

Step 2 — Rename the template files

The template uses placeholder names. Rename:

src/foreignthon_xx/xx.json     → src/foreignthon_fr/fr.json   (example: French)
src/foreignthon_xx/            → src/foreignthon_fr/

Then update every occurrence of xx in:

  • pyproject.tomlname, entry-points key, packages path, keywords, description
  • src/foreignthon_fr/__init__.py — the get_pack_path() return value

Step 3 — Fill in the JSON

Open src/foreignthon_fr/fr.json. Every value is an English Python identifier — never change the values. Replace the keys with your language's words.

{
  "meta": {
    "name": "French",
    "native_name": "Français",
    "code": "fr"
  },
  "keywords": {
    "si": "if",
    "sinon": "else",
    ...
  },
  "builtins": { ... },
  "exceptions": { ... },
  "error_messages": { ... },
  "stdlib": { ... },
  "postfix_keywords": []
}

The filename must exactly match meta.code (e.g. fr.json for code "fr").

Set postfix_keywords to a list of English keywords (e.g. ["if", "elif", "while"]) if your language is SOV and benefits from @@ postfix style on decompile. Set it to [] for SVO languages.

For a full reference on the JSON schema see Custom Packs → Pack schema.


Step 4 — Validate and test

Install your pack in editable mode and run the test suite:

pip install -e .
pip install pytest

fpy pack src/foreignthon_fr/fr.json
# ✓ Pack 'French' is valid.

pytest tests/ -v

The shared test suite (tests/test_pack.py) checks:

  • All required sections exist (meta, keywords, builtins, exceptions, error_messages, stdlib, postfix_keywords)
  • Every keyword value is a real Python keyword
  • Every builtin/exception value is a real Python builtin
  • The filename matches meta.code
  • All postfix_keywords entries have a matching translation in keywords

The CI (ci.yml) runs this same suite on every push and pull request automatically.


Step 5 — Publish to PyPI

You can publish from your own fork at any time — the pack works as soon as it is on PyPI, regardless of whether it is in the official org.

Tag a release and push:

git tag v0.1.0
git push origin v0.1.0

The publish.yml workflow builds the wheel and uploads it to PyPI using the PYPI_TOKEN secret. If you are working from your personal fork you will need to add your own PYPI_TOKEN secret in your fork's Gitea/GitHub settings.

Once published, anyone can install your pack:

pip install foreignthon-fr
fpy new myproject --lang fr

Getting hosted under the official org

The foreign-thon org on Gitea is where official packs live and where the org-level CI secrets (PYPI_TOKEN, GIT_RELEASE_TOKEN, DOCS_TRIGGER_TOKEN) are inherited automatically.

Nobody has direct repo-creation access in the org. To get your pack hosted there:

  1. Make sure your pack is working and published to PyPI.
  2. Open an issue or PR on foreignthon-docs requesting inclusion, and include:
    • Your language code, English name, and native name
    • A link to your published PyPI package
    • Your Gitea handle
  3. The maintainer will transfer or mirror your repo into the org and wire up the secrets.

Getting listed on the docs site

The docs site table in Language Packs → Overview is maintained in languages.yml in the foreignthon-docs repo. Open a PR to add your entry:

- code: fr
  name: French
  repo: foreignthon-fr

The trigger-docs.yml workflow in your pack repo fires a rebuild of the docs site whenever README.md is pushed to main.


Quality bar

Before submitting for listing, your pack should satisfy:

  • fpy pack xx.json passes
  • pytest tests/ passes
  • Every foreign key is unique within the pack
  • No English words used as foreign keys unless the language genuinely keeps them (e.g. lambda)
  • meta.code matches the JSON filename and the entry-point key in pyproject.toml
  • Package name is foreignthon-xx (hyphen), module name is foreignthon_xx (underscore)
  • pip install foreignthon-xx works from PyPI

Versioning and updates

When foreignthon-core releases a new version that adds entries to template.json, update your pack to cover them and release a new version. Update the foreignthon lower-bound dependency in pyproject.toml if your pack requires the new core:

dependencies = ["foreignthon>=0.5.4"]

Follow Semantic Versioning. Use 0.x.y while the keyword set is still being refined; move to 1.0.0 once stable.