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

Laravel Pinyin Laravel Package

overtrue/laravel-pinyin

Laravel wrapper around overtrue/pinyin that converts Chinese characters into pinyin, supporting tone marks, initials, and custom separators. Easily generate slugs, sortable keys, or searchable text from Chinese input via a simple facade and configurable options.

View on GitHub
Deep Wiki
Context7

Getting Started

Install

composer require overtrue/laravel-pinyin

Laravel package auto-discovery registers the service provider and the Pinyin facade — no manual registration in config/app.php for L13 (or L10–L12).

First use

use Overtrue\LaravelPinyin\Facades\Pinyin;

Pinyin::permalink('北京欢迎你');   // "bei-jing-huan-ying-ni"
Pinyin::sentence('北京欢迎你');    // "bei jing huan ying ni"
Pinyin::convert('北京欢迎你');     // ['bei','jing','huan','ying','ni']
Pinyin::abbr('北京欢迎你');        // "bjhyn"

Where to look first

  1. vendor/overtrue/pinyin/README.md — the facade is a thin wrapper; almost every method, option and edge case lives in the underlying library.
  2. vendor/overtrue/laravel-pinyin/src/ — usually just a ServiceProvider and a Facades/Pinyin.php; read it to see exactly which class is bound and how it is resolved from the container.
  3. Publish the config only if you need to swap the bound class:
    php artisan vendor:publish --tag=laravel-pinyin
    

First real use case

Generating URL slugs for Chinese-titled content — this is the 80% case. Create a slug column, populate on save, and index it. Do not compute it in a Blade loop.

Implementation Patterns

Store pinyin, don't compute it at render time

Pinyin conversion is CPU-bound and the package does no caching. For any list, search or sort feature, persist the result:

// migration
$table->string('slug')->unique();
$table->string('pinyin_index')->nullable()->index();
$table->string('initials', 32)->nullable();
// model observer / booted()
protected static function booted(): void
{
    static::saving(function (self $post) {
        $post->slug ??= Pinyin::permalink($post->title);
        $post->pinyin_index = Pinyin::sentence($post->title);
        $post->initials = Pinyin::abbr($post->title);
    });
}

Slug strategy

Compose with Laravel's Str, because permalink() only transliterates Han characters and passes Latin/digits/punctuation through:

$slug = Str::limit(Str::slug(Pinyin::permalink($title)), 80, '');
$slug = $slug ?: Str::random(8);
$slug .= '-' . Str::lower(Str::random(5)); // uniqueness guard

Names and polyphones

Context-free conversion gets polyphonic characters wrong. For people, use the dedicated name mode; for known ambiguous phrases, feed whole phrases rather than single characters:

Pinyin::name('单雄信');    // surname-aware, "shan" not "dan"
Pinyin::polyphones('重');  // inspect all readings

Rule of thumb: convert the longest meaningful unit (full name, full phrase). Per-character conversion is where most wrong output comes from.

Indexing / grouping Chinese by letter

Use abbr() or the first syllable to build an A–Z contact index or "alphabetical" sort for Chinese names, then sort in SQL on the stored column. This is far more reliable than ORDER BY name under a Chinese collation.

Wrap it in your own class

Don't call the facade from controllers and views. Bind a small Transliterator service and inject it — it gives you a single seam to change separators, add caching, or mock in tests:

final class Transliterator
{
    public function slug(string $value): string { /* ... */ }
    public function index(string $value): string { /* ... */ }
}

Backfilling existing rows

For large tables, run an artisan command with chunkById() and queue the work. Never run a full-table conversion inside a migration.

Swap the implementation

The config publishes a class binding. Point it at your own subclass/decorator if you need custom dictionaries or memoization — this is the intended extension point.

Gotchas and Tips

  • Laravel 13 support only. 6.1.0 is purely a constraint widening (PR #37). No API changes, no deprecations, drop-in from 6.0.0. If you're on L13, verify the underlying overtrue/pinyin version is compatible with composer why-not overtrue/pinyin; the wrapper release does not pin the core for you.
  • Not transliteration of everything. Latin, digits, emoji and punctuation pass through unchanged. Pinyin::permalink('iPhone 15 发布') mixes scripts — always run the result through Str::slug() and add a fallback for the all-non-Han case (empty slug).
  • ü handling. Decide once whether you want lv or lü, and make sure column collation and existing slugs agree. Changing this later means re-slugging and breaking every URL.
  • Polyphones are context-sensitive, not character-sensitive. If output looks wrong, it's almost always because you converted a single character instead of the phrase. Test with 单, 重, 长, 行, 乐, 曾.
  • The facade has no cache. Two calls in the same request cost twice. Memoize in your wrapper (Str::of-style cache or a request-scoped array) if you convert in bulk.
  • Never convert in accessors or Blade. A $post->slug accessor that calls Pinyin::permalink() will silently melt a 100-row index page.
  • Testing: the facade is mockable — Pinyin::shouldReceive('permalink')->andReturn('stub'), or swap the bound class with $this->instance(...). Do this so tests don't depend on library output strings.
  • Custom dictionaries live in overtrue/pinyin, not the Laravel wrapper. Check the core README for the dictionary API before assuming a config key exists here.
  • Debugging: when output is unexpected, dump Pinyin::convert($input) (the array form) first — it shows exactly which characters were split and which were passed through, which usually explains the problem faster than reading the permalink string.
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.
socialdept/atp-orm
cboxdk/laravel-assistant-client
socialdept/atp-resolver
socialdept/tenant-domains
tautvydasr/blade-class-names
socialdept/color-scales
maherelgamil/controller
coleus/widgets
coleus/table
coleus/users
coleus/music
coleus/health
coleus/calendar
coleus/notes
coleus/support
coleus/settings
coleus/apps
seampact/laravel
emmyconceptng/laravel-ng-postcode
jjsquady/round-robin