# 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](https://git.keshavanand.net/foreign-thon/). --- ## 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](https://en.wikipedia.org/wiki/List_of_ISO_639_language_codes) two-letter code for your language (use ISO 639-2 three-letter code if no two-letter code exists). Clone your fork locally: ```bash 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-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. ```json { "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](../custom-packs.md#pack-schema). --- ## Step 4 — Validate and test Install your pack in editable mode and run the test suite: ```bash 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: ```bash 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: ```bash 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](https://git.keshavanand.net/foreign-thon/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](../language-packs/index.md) is maintained in `languages.yml` in the `foreignthon-docs` repo. Open a PR to add your entry: ```yaml - 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: ```toml dependencies = ["foreignthon>=0.5.4"] ``` Follow [Semantic Versioning](https://semver.org/). Use `0.x.y` while the keyword set is still being refined; move to `1.0.0` once stable.