Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Hyphenator Laravel Package

org_heigl/hyphenator

org_heigl/hyphenator is a PHP library for automatic hyphenation using TeX patterns. It supports multiple languages, preserves HTML markup, and improves typography in web pages, emails, PDFs, and generated documents.

View on GitHub
Deep Wiki
Context7

Getting Started

composer require org_heigl/hyphenator:^3.2

As of v3.2.0 the package supports UTF-8 TeX pattern files and now applies single-letter hyphenation patterns. Those are the two release items that affect day-to-day use; the rest is CI/supply-chain housekeeping. The package still has no Laravel service provider, facade, or config file, so you wire it yourself. Where to look first, in order:

  1. vendor/org_heigl/hyphenator/README.md — the canonical usage snippet. The API predates PSR conventions, so confirm the exact pattern-registration call here before writing wrappers.
  2. src/Org/Heigl/Hyphenator/Hyphenator.php — the entry point; hyphenate() is the method you will call from application code.
  3. src/Org/Heigl/Hyphenator/Options.php — minimum word length, minimum leading/trailing characters, and the hyphen character itself (soft hyphen vs. visible hyphen).
  4. src/Org/Heigl/Hyphenator/Pattern/ — wraps TeX .pat/.hyp files; this is what you point at a locale's pattern data. Confirm on the release tag whether your pattern file is read in UTF-8 mode (see Gotchas).
  5. src/Org/Heigl/Hyphenator/Tokenizer/ and Filter/ — how plain text is split into word/non-word tokens and how rules are applied. This is where you extend behavior.

Minimal integration — bind a configured instance once and inject it:

// app/Providers/HyphenationServiceProvider.php
namespace App\Providers;

use Illuminate\Support\ServiceProvider;
use Org\Heigl\Hyphenator\Hyphenator;
use Org\Heigl\Hyphenator\Options;

class HyphenationServiceProvider extends ServiceProvider
{
    public function register(): void
    {
        $this->app->singleton(Hyphenator::class, function ($app) {
            $hyphenator = new Hyphenator();

            // Register TeX pattern files for the locales you support.
            // Confirm the exact Pattern constructor/registration call in the README.
            // UTF-8 pattern data is supported since v3.2.0 — save the .pat files as UTF-8.
            // $hyphenator->addPattern(new \Org\Heigl\Hyphenator\Pattern\Pattern(
            //     resource_path('hyphenation/hyph-en-us.pat.txt')
            // ));

            $options = new Options();
            // Tune to taste — these prevent "a-bout" style breaks.
            // $options->setMinWordLength(6);
            // $options->setMinLeading(2);
            // $options->setMinTrailing(2);
            // $options->setHyphen('­');
            // $hyphenator->setOptions($options);

            return $hyphenator;
        });
    }
}

First use case: hyphenating a headline or article body for a PDF export (Dompdf, Snappy, Browsershot) where CSS hyphens is unreliable, or for a CMS that renders justified text and needs break opportunities in long German/Scandinavian compounds. With 3.2.0, accented locales (fr, es, pt, pl, cs, hu, …) are finally realistic because their .pat files can be shipped in UTF-8 instead of Latin-1.

Implementation Patterns

Wrap it behind your own interface. The package is niche (still low adoption, effectively single-maintainer), so isolate it:

interface Hyphenator
{
    public function hyphenate(string $text, string $locale = 'en_US'): string;
}

Bind the concrete adapter in the container; swap implementations later without touching call sites.

Per-locale instances. Hyphenation is language-specific. Keep a keyed map rather than one giant instance, and resolve the locale from the current request / model:

$this->app->singleton(HyphenationManager::class, fn () => new HyphenationManager(
    locales: ['en_US', 'de_DE', 'sv_SE', 'fr_FR', 'pl_PL'],
    patternPath: resource_path('hyphenation'),
));

Blade directive / helper. Hyphenation is a rendering concern:

Blade::directive('hyphenate', fn ($expression) => "<?php echo e(app(\App\Hyphenation\Hyphenator::class)->hyphenate($expression)); ?>");

Or a Str::macro('hyphenate', ...) so it composes with Str::of($title)->limit(60)->hyphenate().

Accessor / presenter layer. Add a model accessor for rendered output and keep the raw column untouched:

public function getHyphenatedTitleAttribute(): string
{
    return app(\App\Hyphenation\Hyphenator::class)->hyphenate($this->title, $this->locale);
}

Cache per word. Long documents repeat words constantly. Memoize in Redis, and include the package version in the cache key prefix so a composer update invalidates output that 3.2.0 may legitimately change:

$key = "hyph:v3.2:{$locale}:".md5($word);
$word = Cache::remember($key, now()->addDay(), fn () => $this->hyphenateWord($word, $locale));

Queue bulk work. Hyphenating thousands of article bodies belongs in a job, not a request. Store the rendered variant alongside the source so the front end never computes it inline.

Custom filters for "don't touch this" content. The tokenizer/filter pipeline is the natural extension point: skip URLs, emails, product SKUs, code identifiers, all-caps acronyms, and strings containing digits. Implement a Filter rather than pre-regexing the input — you keep the package's token boundaries intact.

Tokenize before hyphenating HTML. Never pass markup into hyphenate(). Either strip tags, operate on text nodes only, or hyphenate at the field level and render with {!! !!} after escaping the text nodes individually.

PDF pipeline pattern. For Dompdf/Snappy: hyphenate plain text fields first, insert &shy; (or a visible - if the renderer ignores soft hyphens), then build the HTML. Pair with hyphens: auto only as a fallback for languages where you have no patterns.

Golden-word regression test. Cheap and high-value: assert a handful of known words per locale (hyphenation → hy-phen-ation, Silbentrennung → Sil-ben-tren-nung). 3.2.0 changes output for single-letter patterns, so this test is what tells you an upgrade is safe.

Gotchas and Tips

  • v3.2.0 changes hyphenation output. Two behavior changes: single-letter patterns are now applied (PR #69) and UTF-8 pattern data is honored (PR #68). Neither breaks the public API, but snapshots, stored rendered HTML, and per-word caches will differ. Re-run your golden-word test, flush hyphenation caches, and re-render any pre-computed bodies before shipping the bump.
  • Single-letter patterns widen break opportunities. Expect more breaks in short/compound words that previously came back untouched. This is usually a correctness win, but tighten minWordLength, minLeading, minTrailing if you see fragments you dislike — the options still gate the output.
  • UTF-8 patterns need UTF-8 files. Supporting UTF-8 pattern data does not convert Latin-1-encoded .pat files for you. Audit the encoding of every shipped pattern/exception file (file --mime-encoding), normalize to UTF-8 without BOM, and re-test accented words (Silbentrennung, déshydratation) — mojibake here presents as silently wrong or missing breaks.
  • Non-Latin scripts are still out of scope. Cyrillic, CJK, Arabic, Hebrew and Thai are not meaningfully covered by TeX pattern files of this shape, UTF-8 or not. Fall back to a no-op for unsupported locales rather than emitting bad breaks.
  • The library inserts break opportunities, not line breaks. In HTML the output is only useful if it contains &shy; (U+00AD) and the engine honors it. In plain text/PDF you often want a real -, so set the hyphen character explicitly in Options.
  • HTML/XSS safety. Stripping tags naively can merge words and change meaning. Hyphenate before escaping, escape after, and verify that entities (&amp;, &shy;) survive the pipeline.
  • Don't hyphenate at write time. Locale changes, design changes, typographic fixes — and now upstream algorithm fixes — will force a re-render. Persist raw text; hyphenate in the presentation layer.
  • Idempotency. Re-running the hyphenator on already-hyphenated text compounds soft hyphens and produces garbage. Normalize (strip U+00AD) before re-processing.
  • Minimum lengths matter more than you think. Defaults can produce one-character fragments — tune minWordLength, minLeading, minTrailing per language and add a filter to skip short/uppercase tokens.
  • Pattern loading is the expensive part. Parse patterns once in a singleton; never construct Hyphenator or re-read .pat files per request. Watch memory on very large documents — chunk long bodies by paragraph.
  • Tokenizer edge cases. Numbers, decimals, URLs, emails, CamelCase identifiers, and punctuation-adjacent words can be split unexpectedly. Dump tokens before and after filters when debugging odd output.
  • Language coverage is on you. Only locales whose TeX pattern and exception files you actually register will work. Document supported locales in config and fail gracefully (return input unchanged) for the rest.
  • Compatibility and maintenance risk. Still a low-adoption package with an API older than modern PHP typing conventions. Mitigations: pin the version (^3.2), run it against your PHP/Laravel matrix, keep the characterization test above, and keep it behind your own interface so replacement is a one-class change. The 3.2.0 release does show outside contributors landing features and CI hardening (PRs on PRs, action pinning), which is a mild positive signal.
  • No auto-discovery. Register the provider in bootstrap/providers.php (Laravel 11+) or config/app.php, and note that composer require alone does nothing.
  • Debugging checklist: log which pattern file was loaded for a locale and in which encoding mode, assert the file is readable and valid UTF-8, and compare hyphenate('hyphenation') against the expected hy-phen-ation before blaming your integration.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
robertmarney/lara-hierarchial-collections
simonschaufi/rule-doc-generator
emissaoja/emissaoja
blackbricksoftware/gravityforms-civicrm-form-processor
al-rahabi/fancy-crud
jinas/dhivatar-component
mltstephane/laravel-quality
bernskiold/laravel-talentlms
bernskioldmedia/laravel-form-architect