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

Jolitypo Laravel Package

jolicode/jolitypo

JoliTypo is a PHP typography fixer that cleans up HTML fragments: smart quotes, dashes, ellipses, non-breaking spaces, and French typography rules. It offers customizable fixers and works well in Laravel or any PHP project.

View on GitHub
Deep Wiki
Context7

Getting Started

composer require jolicode/jolitypo

Requires a recent PHP 8.x and ext-mbstring (check composer.json for the exact floor). There is no Laravel service provider bundled, so plan to wire it yourself.

Look here first, in order:

  1. README.md — the canonical list of fixer names and the Fixer API.
  2. src/Fixer.php — the orchestrator; this is the class you actually instantiate.
  3. src/Fixer/ — one class per rule (Ellipsis, Dash, SmartQuotes, FrenchNoBreakSpace, EnglishQuotes, Hyphen, Trademark, Dimension, Unit, etc.). Read these to know exactly what each will and won't touch.
  4. tests/ — fixture files showing input/output pairs are the fastest way to understand real behavior, especially around HTML.

Minimal use:

use JoliTypo\Fixer;

$fixer = new Fixer(['Ellipsis', 'Dash', 'SmartQuotes', 'FrenchNoBreakSpace']);
$fixer->setLocale('fr_FR');

$out = $fixer->fix('Hello... "World" -- it\'s fine');
// ≈ Hello… « World » – it’s fine

First use case: wrap it in a tiny Typography service and call it on rendered HTML just before output — e.g. a Blade component for editorial pages, or a Mailable body. Confirm the HTML-safe behavior against a snippet containing tags, attributes, and a <code> block before trusting it in production.

Implementation Patterns

Bind a configured instance in the container. Because fixer sets and locale are request-dependent, register a factory rather than a single singleton:

$this->app->singleton(TypographyFactory::class, fn () => new TypographyFactory(
    config('typography.fixers'),
));

Then create a per-locale fixer (app()->setLocale() → setLocale(), mapping fr → fr_FR if needed).

Config-driven fixer lists. Put fixer arrays per locale in config/typography.php rather than hard-coding them. Editorial teams change these ("we don't want the dash fixer in product descriptions") without a deploy touching PHP logic.

Blade integration. Add a helper or Blade directive, but be deliberate about escaping:

Blade::directive('typography', fn ($expr) => "<?php echo app(Typography::class)->fix($expr); ?>");

Use it only on content you already trust/sanitize. {!! !!} plus a typography pass is a common double-mistake: fixer output is not a sanitizer.

Persist at write time vs. render time.

  • Static/editorial content: run in a model observer or queued job when the record is saved. Cheap to read, easy to re-run in a migration.
  • Dynamic/user content: run at render time only if you can cache the result. input + locale + fixer set is deterministic, so a Redis key is safe.

Mailables and PDFs. Apply the fixer to the final HTML body, not the template source. Exclude transactional templates containing code samples or literal ASCII (verification codes, URLs, CSV samples) — typographic quotes in a URL or a copy-paste token is a real bug.

Batch migration. One queued job per locale, chunked by ID, that diffs before/after and logs changed rows. Since output isn't guaranteed idempotent (see below), store a typography_version column and re-run only when the fixer config changes.

Custom fixers. Implement the fixer contract, keep it pure and byte-in/byte-out, and add it last in the chain unless you have a specific ordering need. Copy the package's own test fixture style for your tests.

Gotchas and Tips

  • Fixer order is meaningful. Fixers run sequentially and can interfere. Put SmartQuotes/EnglishQuotes/FrenchNoBreakSpace after entity/normalization fixers, and test sequences like ...-- and "word"... explicitly.
  • Not reliably idempotent. A second pass can re-add a non-breaking space or re-wrap an already-curly quote. Either enforce single-pass (flag on the model) or run a regression fixture twice and assert equality before enabling re-runs.
  • Invisible characters will ruin your afternoon. NBSP (\u{00A0}) and NNBSP are invisible. Enable "show whitespace" in your IDE or write a debug helper that swaps them for · before diffing.
  • Enforce UTF-8 end to end. Bad bytes make mb_* calls silently mangle text; also check your DB connection charset. A ? appearing mid-sentence after fixing is almost always an encoding problem, not a fixer bug.
  • HTML-safe ≠ context-aware. Verify behavior inside <pre>, <code>, <script>, <style>, and attribute values (title="…"). Even if the library skips tags, self-closing tags and malformed HTML are worth a fixture.
  • Run after sanitization, not before. Typography is cosmetic; sanitizing is security. Doing them in the wrong order either lets HTML through or escapes your nice &laquo; entities.
  • Locale values matter. Confirm accepted formats (fr_FR vs fr) against the source; don't rely on the default locale. For a French site, FrenchNoBreakSpace is essentially mandatory — without it your : and » will wrap badly.
  • Debug by bisection. If output looks wrong, instantiate with one fixer at a time and run the offending string through each until it breaks. The fixer classes are small enough to read in a minute.
  • Cache aggressively. This is pure, deterministic work; paying for it on every request is waste. Cache per (hash(input), locale, fixerSetVersion).
  • Watch extension points that add state. Custom fixers that read config or hit the DB make caching and idempotency harder. Keep custom fixers stateless and constructor-injected.
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.
uni-method/symfony-lib
tacticmedia/scim-server-bundle
neika-ai/symfony-bundle
mattleads/agent-publishing-bundle
glavweb/framework-bundle
glavweb/extra-bundle
glavweb/api-bundle
glavweb/admin-bundle
adachsoft/api-version-bundle
elsayed85/laravel-api-exceptions
ouhssini/laravel-demo-mode
daworks/ncloud-outbound-mailer-driver
gp247/cms
ignibyte/aic-gates
nexa-merchant/blog
novasa/laravel-language-center
opencage/geocode
adolfoholzer/parameters
livenetworks/ln-starter
cgv/localized-resource