# cletter
Locale-correct business correspondence, composed from focused units. No
models, no I/O: same input always yields the same output.
`cletter` is the front door: it re-exports [`cgreet`](https://github.com/corbet-labs/cgreet)
(salutations), [`cfarewell`](https://github.com/corbet-labs/cfarewell)
(valedictions) and [`cink`](https://github.com/corbet-labs/cink) (signature
images), and adds what only makes sense together — locale resolution,
openings, subjects, orthography, and advisories:
```rust
use cletter::{closing, opening, resolve_locale, salutation, subject};
assert_eq!(resolve_locale(Some("de"), Some("Zürich, Zug")), "de-CH");
assert_eq!(
salutation("de-CH", "Frau Dr. Müller"),
"Sehr geehrte Frau Dr. Müller",
);
assert_eq!(closing("de-CH", None), "Freundliche Grüsse");
assert_eq!(opening("en-US", Some("Jane Doe"), None), "Dear Jane Doe,");
assert_eq!(
subject("de-CH", Some("Leiterin Kommunikation"), None),
"Bewerbung als Leiterin Kommunikation",
);
```
One locale per document (BCP 47). Unknown locales fall back through the
base language to English. Explicit overrides always win — user choice is
never degraded, the tables only supply defaults.
## Use
Rust:
```toml
[dependencies]
cletter = "0.1"
```
TypeScript (zero dependencies, runs in browsers, edge runtimes, and Node):
```sh
npm install @corbet-labs/cletter
```
Run `cargo test`, `cargo fmt --check`, and
`cargo clippy --all-targets -- -D warnings` before pushing.
## Contract for ports
Behavior is defined by data: `tables/locales.json` (openings, subjects,
orthography, region mapping) and `tables/countries.json` (location to
country resolution), documented in `tables/README.md`.
`tests/vectors/*.json` is the executable conformance suite every language
port runs. The Typst module in `typst/` derives from the same tables. A
port is done when every vector passes.
## License
FSL-1.1-ALv2; see `LICENSES/FSL-1.1-ALv2.txt`. Each published version
becomes available under Apache-2.0 two years after publication.