added template

This commit is contained in:
2026-05-21 14:36:47 +00:00
parent 16fb3478bb
commit d9c907a25a

View File

@@ -1 +1,240 @@
# Add Your Language
Anyone can publish a `foreignthon-xx` language pack to PyPI — no access to the core repo is needed, and the pack works for anyone who installs it the moment it is on PyPI.
The recommended path is to start from the official language template. See [Contributing → Language Packs](../contributing/language-packs.md) for the full contribution and review process. This page is a quick reference.
---
## Start from the template
Fork the official language template on Gitea:
```
https://git.keshavanand.net/foreign-thon/language-template.git
```
The template gives you the full correct structure — `__init__.py`, JSON pack, the universal `tests/test_pack.py`, and all three CI workflows — pre-wired and ready to rename.
!!! tip "Why fork instead of starting fresh?"
The template includes the shared test suite (`tests/test_pack.py`) that every official pack uses. Starting from it means your CI is already correct and your pack will pass the same checks as `foreignthon-es` and `foreignthon-ta` from day one.
Alternatively, if you just want a local pack for your own project without publishing, use:
```bash
fpy new myproject --lang custom
```
This scaffolds a `custom.json` locally — no PyPI account needed. See [Custom Packs](../custom-packs.md) for details.
---
## Package structure
After renaming the template for your language (e.g. French, code `fr`):
```
foreignthon-fr/
├── .gitea/workflows/
│ ├── ci.yml # pytest on push / PR
│ ├── publish.yml # PyPI upload on v* tag
│ └── trigger-docs.yml # docs rebuild on README.md change
├── .gitignore
├── LICENSE # GPL v3
├── README.md
├── pyproject.toml
└── src/
└── foreignthon_fr/
├── __init__.py
└── fr.json
```
---
## `pyproject.toml`
```toml
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"
[project]
name = "foreignthon-fr"
version = "0.1.0"
description = "French language pack for ForeignThon."
license = { text = "GPL v3" }
requires-python = ">=3.9"
authors = [
{ name = "Your Name", email = "you@example.com" }
]
keywords = ["foreignthon", "french", "français"]
dependencies = ["foreignthon>=0.5.3"]
[project.urls]
Homepage = "https://git.keshavanand.net/foreign-thon/foreignthon-fr"
[project.entry-points."foreignthon.langs"]
fr = "foreignthon_fr"
[tool.hatch.build.targets.wheel]
packages = ["src/foreignthon_fr"]
```
The `[project.entry-points."foreignthon.langs"]` block is what makes ForeignThon auto-discover your pack — the key is the language code, the value is the Python module name.
---
## `__init__.py`
```python
from importlib.resources import files
from importlib.metadata import version, metadata, PackageNotFoundError
try:
package_name = (__package__ or "").replace("_", "-")
__version__ = version(package_name)
pkg_metadata = metadata(package_name)
raw_authors = pkg_metadata.get_all("Author") or []
raw_emails = pkg_metadata.get_all("Author-email") or []
combined = []
for item in (raw_authors + raw_emails):
clean_name = item.split("<")[0].strip()
if clean_name and clean_name not in combined:
combined.append(clean_name)
__authors__ = combined
except PackageNotFoundError:
__version__ = "0.0.0"
__authors__ = []
def get_pack_path():
return files(__name__) / "fr.json"
```
Change `"fr.json"` to match your actual filename.
---
## The JSON pack
Keys are your language's words. Values are English Python identifiers — **never change the values**.
```json
{
"meta": {
"name": "French",
"native_name": "Français",
"code": "fr"
},
"keywords": {
"si": "if",
"sinon": "else",
"sinonsi": "elif",
"pour": "for",
"tantque": "while",
"déf": "def",
"classe": "class",
"importer": "import",
"depuis": "from",
"comme": "as",
"retourner": "return",
"arrêter": "break",
"continuer": "continue",
"passer": "pass",
"essayer": "try",
"sauf": "except",
"finalement": "finally",
"lever": "raise",
"avec": "with",
"dans": "in",
"est": "is",
"et": "and",
"ou": "or",
"non": "not",
"supprimer": "del",
"global": "global",
"nonlocal": "nonlocal",
"affirmer": "assert",
"générer": "yield",
"attendre": "await",
"asynchrone": "async",
"lambda": "lambda",
"Vrai": "True",
"Faux": "False",
"Rien": "None"
},
"builtins": {
"afficher": "print",
"saisir": "input",
"longueur": "len",
"intervalle": "range",
...
},
"exceptions": {
"ErreurDeValeur": "ValueError",
...
},
"error_messages": {
"ValueError": "Erreur de valeur",
...
},
"stdlib": {
"mathématiques": "math",
...
},
"postfix_keywords": []
}
```
### `postfix_keywords`
Set this to a list of English keywords if your language is SOV (subject-object-verb) and benefits from `@@` postfix style on decompile. Example (Tamil):
```json
"postfix_keywords": ["if", "elif", "while", "class", "with"]
```
Set it to `[]` for SVO languages like Spanish or French.
### Filename rule
The JSON filename **must** match `meta.code` exactly. `fr.json` for code `"fr"`.
---
## Validate and test
```bash
pip install -e .
pip install pytest
fpy pack src/foreignthon_fr/fr.json
# ✓ Pack 'French' is valid.
pytest tests/ -v
```
The shared `tests/test_pack.py` checks that all sections exist, all values are real Python identifiers, the filename matches `meta.code`, and `postfix_keywords` entries each have a translation.
---
## Publish
Tag and push — the CI handles the rest:
```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. Add your own `PYPI_TOKEN` to your fork's secrets if you are not yet under the official org.
---
## Getting listed
Once your pack is working and on PyPI, open a PR or issue on [foreignthon-docs](https://git.keshavanand.net/foreign-thon/foreignthon-docs) to get added to the [Language Packs overview](index.md). See [Contributing → Language Packs](../contributing/language-packs.md) for the full process.