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

Transliterate Laravel Package

elforastero/transliterate

elforastero/transliterate is a Laravel package for converting Cyrillic text into Latin characters. It provides a simple helper and facade, configurable transliteration maps, and seamless integration for generating readable slugs, filenames, and search-friendly strings.

View on GitHub
Deep Wiki
Context7

Getting Started

  1. Install the package:

    composer require elforastero/transliterate
    

    The service provider and Transliterate facade are auto-discovered on Laravel 5.5+, so no manual registration is normally required.

  2. Publish the config if you need to change the engine:

    php artisan vendor:publish --provider="ElForastero\Transliterate\TransliterateServiceProvider"
    

    This creates config/transliterate.php, which points at the default transliterator engine. In most apps you will not touch it.

  3. First use case — Cyrillic-to-Latin strings (slugs, usernames, filenames):

    use ElForastero\Transliterate\Facades\Transliterate;
    
    Transliterate::make('Привет, мир!')->transliterate();
    // "Privet, mir!"
    
  4. Where to look first in the repo:

    • src/Transliterator.php — the engine and its public transliterate() method.
    • src/Maps/ — per-language character maps. This is the file to read when output looks wrong for ё, й, ъ, ь, or Ukrainian/Bulgarian characters.
    • src/Transliterable.php — the Eloquent trait if you want automatic slug fields.
    • config/transliterate.php — engine binding and any map/language defaults.
  5. Fastest real win: drop it into a Post/Page model to build slugs from a Russian title without pulling in a full ICU/intl dependency.

Implementation Patterns

  • Explicit service calls — inject or resolve the transliterator and call it at the point of use:

    $slug = str(Transliterate::make($post->title)->transliterate())
        ->slug('-')
        ->lower()
        ->toString();
    

    Chaining Str::slug() after transliteration is the most reliable pattern: transliteration handles script conversion, Str::slug() handles punctuation, whitespace, and case.

  • Model trait for slugs — the package ships a Transliterable trait that maps a source attribute to a target attribute on save. Check the trait source in your installed version for the exact protected property name, then:

    use ElForastero\Transliterate\Transliterable;
    
    class Post extends Model
    {
        use Transliterable;
    
        protected $transliterable = [
            'slug' => 'title',
        ];
    }
    

    This is best for simple CRUD. For anything with uniqueness rules or fallbacks, prefer a model observer or saving listener so you keep full control.

  • Form request / DTO normalization — transliterate on input rather than on output when the value is also used as a key (slugs, storage paths, cache keys). Doing it once at write time avoids inconsistent results from later config changes.

  • Custom engine — implement a class with the same make()/transliterate() contract and swap the engine class in config/transliterate.php. Useful if you need a different map set or want to delegate to intl's Transliterator on servers that have it.

  • Bulk backfill — for existing rows, chunk over the model and save each record so trait/observer hooks fire:

    Post::whereNull('slug')->chunkById(500, function ($posts) {
        $posts->each->save();
    });
    

    Avoid Post::whereNull('slug')->update([...]) — mass updates bypass model events, so the transliteration hook never runs.

  • Route model binding — once slug is transliterated, bind routes with getRouteKeyName() returning 'slug'. Transliterated slugs are stable and URL-safe, unlike raw Cyrillic in URLs (which browsers percent-encode into unreadable strings).

Gotchas and Tips

  • It is not a universal transliterator. The maps are Cyrillic-focused (Russian plus several related languages). It will not help with Chinese, Arabic, Greek, etc. — use intl/voku/portable-ascii for broader coverage.
  • Lossy output creates collisions. ё/е, й/и, and ь/ъ frequently collapse to the same Latin string. Always pair transliteration with a uniqueness strategy (-2, -3 suffixes, or a UUID fragment) before persisting a slug.
  • Str::slug() alone returns an empty string on Cyrillic. A common bug is adding Str::slug() and getting '' for Russian titles. This package exists precisely to fix that, so make sure both steps are present and in the right order.
  • Check the map, not the docs, for edge cases. The expected output of ё => e vs yo, й => i vs y, and word-final ий varies by language map. If a client cares about how a name is romanized, write a small test with realistic strings and assert the exact output.
  • Encoding. Inputs must be valid UTF-8. Values from legacy databases or CSV imports in Windows-1251 will silently produce garbage. Convert with mb_convert_encoding($value, 'UTF-8', 'Windows-1251') before passing in.
  • Config caching. If you change the engine in config/transliterate.php, run php artisan config:cache (or config:clear) — otherwise stale cached config will keep the old binding.
  • Trait ordering and events. If another package or your own boot() logic also hooks saving/creating, verify the order. Slug generation must happen before your uniqueness check, otherwise you will validate the pre-transliteration value.
  • Wrap it. With ~56 stars and a small maintainer surface, avoid scattering Transliterate::make() calls across the codebase. Put one SlugService or helper behind an interface, so replacing the engine later is a one-file change.
  • Debugging tip. Dump Transliterate::make($value)->transliterate() directly in php artisan tinker with the exact string from the failing record — including invisible characters (soft hyphen, NBSP), which are the usual cause of "it worked in my test" slug bugs.
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.
diephp/sequences
users-au/socialite-provider
twidpay/twid-logger
mrnewport/laravel-plaid
mrnewport/laravel-repo
mrnewport/laravel-docsign
mrnewport/laravel-stow
mrnewport/laravel-flow
mrnewport/laravel-priceable
mrnewport/laravel-nestedterms
fredmeng/laravel-apidoc-generator
itstructure/laravel-multilingual-tools
pdustdar/elasticsearch
markupai/php-sdk
rlacerda83/lumem-microservice-shipment
uni-method/symfony-lib
tacticmedia/scim-server-bundle
neika-ai/symfony-bundle
mattleads/agent-publishing-bundle
glavweb/framework-bundle