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

190 lines
6.2 KiB
Markdown

# 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.