docs, modifying cli to use language packs
This commit is contained in:
parent
45f4d6e401
commit
68128b5dc6
112
README.md
112
README.md
|
@ -1,11 +1,84 @@
|
|||
# D&D Language Generator
|
||||
# D&D Name and Language Generator
|
||||
|
||||
This package is a fantasy language generator. By defining a number of characteristics about your imagined language -- the graphemes, their relative frequency distributions, the construction of syllables, and so on -- you can generate random but internally consistent gibberish that feels distinct, evocative, and appropriate to your setting.
|
||||
|
||||
## Quick Start
|
||||
## Usage
|
||||
|
||||
The `fanlang` command-line utility supports three commands:
|
||||
|
||||
* **names**: generate names
|
||||
* **text**: generate a paragraph of text
|
||||
* **list**: list the supported language in the current language pack
|
||||
|
||||
### Examples:
|
||||
|
||||
```
|
||||
>>> from language imported supported_languages
|
||||
% fanlang --language=dwarvish names --count 5
|
||||
Tiny Châ Pothesadottyr
|
||||
Khâkhu Zhûdothir
|
||||
Quiet Ke Vêdothir
|
||||
Cû Tozhon
|
||||
Big Pâ Thadottyr
|
||||
```
|
||||
|
||||
```
|
||||
% fanlang --language=dwarvish text
|
||||
Cû ne do tho khâ tasha, vê wûva lû, ku phu thâ thê, tûko kê, pevo kâ têtetv zha
|
||||
pataso keks khate? Fâ zhû shû yf pho pa me. Dupha dê thê khâ! Shikm tu! Cê
|
||||
sâdêto. Dê yo nâ topho, my sû pida phe, vi phûtw châcho, po sotê?
|
||||
```
|
||||
|
||||
```
|
||||
% fanlang list
|
||||
Abyssal
|
||||
Celestial
|
||||
Common
|
||||
Draconic
|
||||
Dwarvish
|
||||
Elvish
|
||||
Gnomish
|
||||
Halfling
|
||||
Infernal
|
||||
Lizardfolk
|
||||
Orcish
|
||||
Undercommon
|
||||
```
|
||||
|
||||
## Language Packs
|
||||
|
||||
A *Language Pack* is a python package that defines one or more language modules. The default language pack includes a number of D&D languages with rules built according to the conventions established by my D&D group over several years of play in our homebrew setting.
|
||||
|
||||
The default language pack is [language.languages](language/languages/); each submodule contains a README that describes the basic characteristics of the language, along with examples.
|
||||
|
||||
### Using Your Own Language Pack
|
||||
|
||||
You can override `fanlang`'s default language pack by specifying the `FANLANG_LANGUAGE_PACK` environment variable:
|
||||
|
||||
```
|
||||
# Create your ancient_elvish module in campaign/language_pack/ancient_elvish
|
||||
% FANLANG_LANGUAGE_PACK=campaign.language_pack fanlang list
|
||||
Ancient Elvish
|
||||
``
|
||||
|
||||
### Setting the Default Language
|
||||
|
||||
'common' is the default language module. You can override this by setting the `FANLANG_DEFAULT_LANGUAGE` environment variable:
|
||||
|
||||
```
|
||||
% FANLANG_DEFAULT_LANGUAGE=gnomish fanlang names --count=1
|
||||
Jey Lea
|
||||
```
|
||||
|
||||
You can read about creating custom language packs below.
|
||||
|
||||
|
||||
## Library Quick Start
|
||||
|
||||
You can load all supported languages in a language pack using `language.load_langauge_pack()`:
|
||||
|
||||
```
|
||||
>>> import language
|
||||
>>> language_pack, supported_languages = language.load_language_pack()
|
||||
>>> common = supported_languages['common']
|
||||
>>> common.word(2)
|
||||
['apsoo', 'nirtoet']
|
||||
|
@ -21,23 +94,38 @@ Proitsiiiy be itkif eesof detytaen. Ojaot tyskuaz apsoo nirtoet prenao.
|
|||
}
|
||||
```
|
||||
|
||||
## Supported Languages
|
||||
You can also load individual languages directly:
|
||||
|
||||
A number of D&D languages are defined, with rules built according to the
|
||||
conventions established by my D&D group over several years of play in our
|
||||
homebrew setting. You can find all supported languages [in the languages
|
||||
submodule](language/languages/); each submodule contains a README that
|
||||
describes the basic characteristics of the language, along with examples.
|
||||
```
|
||||
>>> from language.languages import common
|
||||
>>> common.Language.word(2)
|
||||
['apsoo', 'nirtoet']
|
||||
>>> str(common.Name)
|
||||
"Quiet" Gushi Murk Lirpusome
|
||||
```
|
||||
|
||||
## Defining a Language
|
||||
## Defining a New Language Pack
|
||||
|
||||
### Layout
|
||||
Language packs are python packages with the following structure:
|
||||
|
||||
```
|
||||
language_pack:
|
||||
__init__.py
|
||||
language_name:
|
||||
__init__.py
|
||||
base.py
|
||||
names.py
|
||||
rules.py
|
||||
...
|
||||
```
|
||||
|
||||
### Languge Modules
|
||||
|
||||
A language consists of several submodules:
|
||||
|
||||
* `base.py`, which contains grapheme definitions and the `Language` subclasses;
|
||||
* `names.py`, which defines the `NameGenerator` subclasses; and
|
||||
* `rules.py`, which is optional but defines the rules all words in the language must follow.
|
||||
* `rules.py`, which is optional, and defines the rules all words in the language must follow.
|
||||
|
||||
|
||||
### Language Construction
|
||||
|
|
|
@ -1 +1,26 @@
|
|||
from .languages import supported_languages
|
||||
import importlib
|
||||
import os
|
||||
import pkgutil
|
||||
import sys
|
||||
|
||||
from types import ModuleType
|
||||
|
||||
language_pack = None
|
||||
supported_languages = None
|
||||
|
||||
|
||||
def _import_submodules(module):
|
||||
pkgs = pkgutil.iter_modules(module.__path__)
|
||||
for loader, module_name, is_pkg in pkgs:
|
||||
yield importlib.import_module(f"{module.__name__}.{module_name}")
|
||||
|
||||
|
||||
def load_language_pack(module_name: str = "") -> ModuleType:
|
||||
if not module_name:
|
||||
module_name = os.getenv("FANLANG_LANGUAGE_PACK", "language.languages")
|
||||
language_pack = importlib.import_module(module_name)
|
||||
_import_submodules(language_pack)
|
||||
supported_languages = dict(
|
||||
(module.__name__.split(".")[-1], module) for module in list(_import_submodules(sys.modules[module_name]))
|
||||
)
|
||||
return language_pack, supported_languages
|
||||
|
|
|
@ -1,20 +1,23 @@
|
|||
import logging
|
||||
import os
|
||||
import random
|
||||
from enum import Enum
|
||||
from types import ModuleType
|
||||
|
||||
import language
|
||||
|
||||
import typer
|
||||
from rich.logging import RichHandler
|
||||
from rich.console import Console
|
||||
from rich.markdown import Markdown
|
||||
|
||||
from language import supported_languages
|
||||
|
||||
app = typer.Typer()
|
||||
|
||||
app_state = {}
|
||||
|
||||
default_language = os.environ.get("FANLANG_DEFAULT_LANGUAGE", "common")
|
||||
language_pack, supported_languages = language.load_language_pack()
|
||||
|
||||
Supported = Enum("Supported", ((k, k) for k in supported_languages.keys()))
|
||||
|
||||
|
||||
|
@ -34,21 +37,47 @@ def print_sample(lang: str, module: ModuleType) -> None:
|
|||
|
||||
@app.callback()
|
||||
def main(
|
||||
language: Supported = typer.Option("common", help="The language to use."),
|
||||
language: Supported = typer.Option(
|
||||
default=default_language,
|
||||
help="The language to use."
|
||||
),
|
||||
):
|
||||
app_state["language"] = supported_languages[language.name]
|
||||
|
||||
debug = os.getenv("DEBUG", None)
|
||||
debug = os.getenv("FANLANG_DEBUG", None)
|
||||
logging.basicConfig(
|
||||
format="%(message)s",
|
||||
format="%(name)s %(message)s",
|
||||
level=logging.DEBUG if debug else logging.INFO,
|
||||
handlers=[RichHandler(rich_tracebacks=True, tracebacks_suppress=[typer])],
|
||||
)
|
||||
logging.getLogger('markdown_it').setLevel(logging.ERROR)
|
||||
logging.debug(f"Loaded language pack {language_pack}.")
|
||||
logging.debug(f"Default language: {default_language}.")
|
||||
|
||||
|
||||
@app.command()
|
||||
def words(count: int = typer.Option(50, help="The number of words to generate.")):
|
||||
print(" ".join(list(app_state["language"].Language.word(count))))
|
||||
def text(count: int = typer.Option(50, help="The number of words to generate.")):
|
||||
|
||||
phrases = []
|
||||
phrase = []
|
||||
for word in app_state["language"].Language.word(count):
|
||||
phrase.append(str(word))
|
||||
if len(phrase) >= random.randint(1, 12):
|
||||
phrases.append(' '.join(phrase))
|
||||
phrase = []
|
||||
if phrase:
|
||||
phrases.append(' '.join(phrase))
|
||||
|
||||
paragraph = phrases[0].capitalize()
|
||||
for phrase in phrases[1:]:
|
||||
if random.choice([0, 0, 1]):
|
||||
paragraph = paragraph + random.choice('?!.') + ' ' + phrase.capitalize()
|
||||
else:
|
||||
paragraph = paragraph + ', ' + phrase
|
||||
paragraph = paragraph + random.choice('?!.')
|
||||
|
||||
console = Console(width=80)
|
||||
console.print(paragraph)
|
||||
|
||||
|
||||
@app.command()
|
||||
|
|
|
@ -1,14 +0,0 @@
|
|||
import importlib
|
||||
import pkgutil
|
||||
import sys
|
||||
|
||||
|
||||
def import_submodules(module):
|
||||
pkgs = pkgutil.iter_modules(module.__path__)
|
||||
for loader, module_name, is_pkg in pkgs:
|
||||
yield importlib.import_module(f"{module.__name__}.{module_name}")
|
||||
|
||||
|
||||
supported_languages = dict(
|
||||
(module.__name__.split(".")[-1], module) for module in list(import_submodules(sys.modules[__name__]))
|
||||
)
|
Loading…
Reference in New Issue
Block a user