bigit/vokativ
A PHP/Laravel package for Czech vocative inflection. Convert first names into the fifth case for natural personalized greetings, emails, notifications, and templates. Simple API, reliable handling of common names, and easy integration into Laravel applications. Ideal for customer communication.
bigit/vokativ is a small Czech-only inflection library: it converts a first name into the 5th grammatical case (vokativ) so you can generate natural greetings — Petr → Petře, Petra → Petro, Jan → Jane.
Install. The package is not on Packagist (0 stars, 0 dependents, GitLab-only), so composer require bigit/vokativ will fail. Add a VCS repository entry instead:
"repositories": [
{ "type": "vcs", "url": "https://gitlab.com/bigit/vokativ.git" }
],
"require": { "bigit/vokativ": "dev-master" }
Pin it to a commit hash (dev-master#abc1234) — there is no semver tag to rely on.
Read the README first, then the source. It is a few hundred lines at most; the whole contract is one entry point plus a name dictionary. Confirm the exact call signature and whether it expects a first name only or first + last name — that distinction matters (see below).
Smoke-test in Tinker before writing any app code. Run a spread of names through it and eyeball the output: Jan, Petr, Pavel, Marek, Tomáš, Jiří, Ondřej, Petra, Lucie, Kateřina, Anna, Nikola (last one is the ambiguity canary).
First real use case: personalized transactional mail. Instead of Dobrý den, Petře, falling out of a {{ $user->first_name }} interpolation, you produce Dobrý den, {{ $greetingName }}, in a Mailable view, Notification, or PDF letter.
Immediately wrap it. Do not call the library from Blade, controllers, or models. Create one adapter class so the rest of the app has a single seam to test, cache, and later swap.
Adapter + container binding. The package is framework-agnostic and ships no service provider, so you own the lifecycle.
namespace App\Support;
class CzechVocative
{
public function name(?string $first): ?string
{
$first = trim((string) $first);
if ($first === '') return null;
try {
return \Bigit\Vokativ\Vokativ::jmeno($first); // adjust to actual API
} catch (\Throwable $e) {
report($e);
return $first; // never break a mail send over a name
}
}
}
Bind it in AppServiceProvider::register() as a singleton. Inject CzechVocative where needed — this keeps the vendor class name out of your codebase.
Locale gate. This is Czech-only. Guard it centrally rather than at each call site:
public function greeting(string $first, string $locale): string
{
return $locale === 'cs' ? $this->name($first) : $first;
}
Model accessor for ergonomics. If greetings are used widely, expose it on User:
protected function vocativeName(): Attribute
{
return Attribute::get(fn () => app(CzechVocative::class)->greeting(
$this->first_name, $this->locale ?? app()->getLocale()
));
}
Then {{ $user->vocative_name }} works in any Mailable.
Greeting composition as a first-class concept. Don't let templates decide between Dobrý den, Dobré ráno, Ahoj and comma/colon rules. A Greeting value object returning a full string (Dobrý den, Petře, / Milá Petro,) keeps formality, gender, and punctuation in one place, and gives you one thing to snapshot-test.
Salutation by gender. For formal letters you often need Vážený pane / Vážená paní, which the library does not give you. Store gender (or infer from the name where reliable) and combine.
Bulk personalization. For newsletters, run the inflection once per recipient in a queued job and cache the result (Cache::remember("voc:{$name}", now()->addYear(), ...)). The dictionary lookup is cheap, but you don't want it inside a 50k-row Blade loop.
Testing. Wrap the adapter in a data-provider test with the exact name set your users actually have. This is your regression net when the package or a name list changes:
#[DataProvider('names')]
public function test_inflects(string $in, string $out) { ... }
public static function names(): array
{
return [['Petr','Petře'], ['Petra','Petro'], ['Jan','Jane'], ['Lucie','Lucie']];
}
app/ entirely.Novák → Nováku, Nováková → Nováková), and the rules differ by gender and by whether the surname is adjectival. Do not feed "Jan Novák" into a first-name inflector. Split, inflect each part with the right rules, and re-join.Ing., Mgr., Ph.D., Bc. are fixed strings; strip them before inflection and re-attach afterwards.Nikola, Sára-like imports, and foreign names (Andrea, Alex, Maria) can resolve incorrectly or not at all. Decide a policy: fall back to the nominative, or let the user store a preferred salutation. The latter is the only robust answer for an international user base.mb_* everywhere. Vocative endings change the final consonant (-k → -ku, -ch → -chu, -ec → -če), so byte-level substr/str_replace on the input will corrupt names. Normalize with mb_strtolower/mb_convert_case(MB_CASE_TITLE) before calling, and verify your DB column is utf8mb4.Petře, make sure downstream code knows that's a vocative, not a first name — otherwise you get Petře → Petřee. Keep the nominative as the source of truth.null/the original rather than an empty string; a mail that says Dobrý den, , is worse than the uninflected name. Single letters and nicknames (Péťa, Jirka) are usually outside the dictionary — verify.app()->getLocale() inside a queued job is the worker's locale, not the recipient's. Pass the recipient's locale explicitly into the greeting function.Log::debug('vocative unchanged', ['name' => $n])) and review weekly — that list is your dictionary gap and the input to a user-facing "how should we address you?" field.str_replace in your adapter; ad-hoc suffix rules will fight the library's and produce inconsistency across your app.How can I help you explore Laravel packages today?