# cletter
**Locale-correct correspondence, from salutation to closing.**
[](https://crates.io/crates/cletter) [](https://www.npmjs.com/package/@corbet-labs/cletter) [](https://docs.rs/cletter)
Compose a formal letter from deterministic rules: resolve a document locale, address a recipient, write an application subject, format the date, choose a closing, and prepare a handwritten signature image. Rust, JavaScript, and Python share the same conformance vectors.
```js
import { salutation } from '@corbet-labs/cletter';
salutation('de-ch', 'Frau Dr. Müller');
// Sehr geehrte Frau Dr. Müller
```
## Install
| Environment | Command |
| --- | --- |
| Rust / Cargo | `cargo add cletter` |
| Node.js / npm | `npm install @corbet-labs/cletter` |
| pnpm | `pnpm add @corbet-labs/cletter` |
| Yarn | `yarn add @corbet-labs/cletter` |
| Bun | `bun add @corbet-labs/cletter` |
| Deno | `deno add npm:@corbet-labs/cletter` |
The 0.2.1 JavaScript distribution includes compiled ESM, CommonJS,
TypeScript declarations, and a standalone browser module. Node.js 20+ is
supported; no TypeScript loader is required.
```js
// CommonJS
const { salutation } = require('@corbet-labs/cletter');
```
```html
<script type="module">
import { salutation } from 'https://cdn.jsdelivr.net/npm/@corbet-labs/cletter@0.2.1/dist/browser.js';
console.log(salutation('de-ch', 'Frau Dr. Müller'));
</script>
```
Python wheels, source distributions, and CLI instructions are in the
[installation guide](https://github.com/corbet-labs/cletter/blob/main/docs/installation.md).
JSR publication and Typst availability are listed there explicitly.
## Rust
```rust
use cletter::{closing, long_date, resolve_locale, salutation};
let locale = resolve_locale(Some("de"), Some("Zürich, Zug"));
assert_eq!(salutation(&locale, "Frau Dr. Müller"), "Sehr geehrte Frau Dr. Müller");
assert_eq!(closing(&locale, None), "Freundliche Grüsse");
assert_eq!(long_date(&locale, 2026, 9, 7).as_deref(), Some("7. September 2026"));
```
## Python
```python
from cletter import salutation
assert salutation("de-ch", "Frau Dr. Müller") == 'Sehr geehrte Frau Dr. Müller'
```
## API
| JavaScript / Python or Rust | Purpose |
| --- | --- |
| `resolveLocale` / `resolve_locale` | Language and location → document locale |
| `salutation`, `opening` | Recipient address or formal opening |
| `subject` | Application subject with optional prefix override |
| `closing` | Locale-specific valediction |
| `longDate` / `long_date` and other date helpers | Gregorian datelines |
| `applyOrtho` / `apply_ortho` | Explicit `ß` → `ss`, `ẞ` → `SS` for caller-selected `de-ch`/`de-li` prose |
| `orthographyIssues` / `orthography_issues` | Non-mutating matched source/replacement pairs |
| `orthographyReplacements` / `orthography_replacements` | Applicable spelling pairs from the shared table |
| `normalize`, `signatureSize` / `signature_size` | Signature-image preparation |
| `warnings` | Advisories for incomplete recipient details |
Openings and closings have 40 locale entries. Date formatting currently covers German and English variants; other dates fall back to English. Locale IDs are lowercase in tables and outputs; lookups accept mixed case and explicit overrides win. Subject defaults are for job applications; supply a prefix override for other correspondence. The library produces letter components; your application owns the body, layout, and PDF rendering. Spelling transformations require caller-selected prose: preserve exact names, quotations, URLs and source material; use diagnostics when those boundaries are unavailable.
The self-contained [Typst facade](https://github.com/corbet-labs/cletter/blob/main/typst/README.md) consumes the same greeting, closing and date helpers as the other ports.
## Correspondence family
| Library | Responsibility |
| --- | --- |
| [cletter](https://github.com/corbet-labs/cletter) | Compose the correspondence helpers |
| [cgreet](https://github.com/corbet-labs/cgreet) | German salutations and titles |
| [cfarewell](https://github.com/corbet-labs/cfarewell) | Locale-specific closings |
| [cdate](https://github.com/corbet-labs/cdate) | Calendar-date formatting |
| [cink](https://github.com/corbet-labs/cink) | Handwritten signature images |
## Development
Behavior is defined by [the locale tables](https://github.com/corbet-labs/cletter/tree/main/tables)
and [shared conformance vectors](https://github.com/corbet-labs/cletter/tree/main/tests/vectors).
Rust, JavaScript, and Python run the same vectors. Selected CI checks exercise
installed JavaScript tarballs, Python wheels and command-line entrypoints, and
Typst packages. Release validation records the actual runtime and platform;
Linux results do not establish native Windows or macOS coverage.
All five Rust crates forbid unsafe code in their own source.
See [the release guide](https://github.com/corbet-labs/cletter/blob/main/docs/releasing.md)
for generation, verification, and publication commands.
## License
Copyright 2026 Julian Y. Richard Corbet. Licensed under [Apache-2.0](LICENSES/Apache-2.0.txt). Vendored dependencies retain their notices; `typst/vendor/cgreet/` offers MIT OR Apache-2.0 and the other components use Apache-2.0.