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.toml—name,entry-pointskey,packagespath,keywords,descriptionsrc/foreignthon_fr/__init__.py— theget_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_keywordsentries have a matching translation inkeywords
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:
- Make sure your pack is working and published to PyPI.
- 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
- 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.jsonpassespytest 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.codematches the JSON filename and the entry-point key inpyproject.toml- Package name is
foreignthon-xx(hyphen), module name isforeignthon_xx(underscore) pip install foreignthon-xxworks 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.