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 Arabic Numbers Middleware Laravel Package

yemenifree/laravel-arabic-numbers-middleware

A Laravel middleware that automatically converts Arabic-Indic numerals to standard Western digits in incoming requests, so user input from Arabic keyboards is normalized before it reaches your controllers, validation, and database.

View on GitHub
Deep Wiki
Context7

Getting Started

This is a small, single-purpose package: a Laravel middleware that normalizes digit characters in incoming requests so controllers and validators only ever see one numeral system. It does not touch responses, models, or views — that's your job (see below).

Install and publish

composer require yemenifree/laravel-arabic-numbers-middleware
php artisan vendor:publish --provider="Yemenifree\ArabicNumbers\ArabicNumbersServiceProvider"

Check config/arabic-numbers.php (or whatever the README names it) for the direction toggle and any except/only lists. The defaults are usually what you want: convert input to Latin digits.

Register it

Add the middleware to a group or a route. For a mostly-Arabic app, put it in the web group so every form submission is normalized; for an API, attach it per-route.

// app/Http/Kernel.php
protected $middlewareGroups = [
    'web' => [
        \App\Http\Middleware\EncryptCookies::class,
        // ... TrimStrings, ConvertEmptyStringsToNull ...
        \Yemenifree\ArabicNumbers\Middleware\ArabicNumbersMiddleware::class,
    ],
];

Use the exact class name from the README — the namespace is the one thing worth copy-pasting rather than guessing.

First use case: an Arabic-locale form with a phone or quantity field. A user types ١٢٣٤٥٦٧٨, hits submit, and your FormRequest rule ['phone' => 'required|digits:8'] passes because the middleware already rewrote the input to 12345678 before validation runs. That single flow — Arabic input, Latin validation/DB — is the package's whole reason to exist.

Implementation Patterns

Global normalization + per-route exceptions. Register globally in web, then use the config's except list to skip routes where conversion is wrong (file uploads, webhook receivers, signed URLs). If the config doesn't support route patterns in your version, create a thin subclass that checks $request->routeIs(...) before delegating to the parent.

Normalize in, format out. The middleware is request-only. For the reverse direction (displaying 1234 as ١٢٣٤), either flip the direction config for read-only routes or, better, format at the presentation layer. A Blade directive or a small helper wrapping str_replace over the digit table keeps display logic out of middleware:

Blade::directive('arabic', fn ($expr) => "<?php echo strtr($expr, ['0'=>'٠','1'=>'١', /* ... */]); ?>");

Order it against the built-in stack. Place it after TrimStrings and ConvertEmptyStringsToNull so you're converting trimmed strings and not producing ' ١٢٣ '. It must be before any FormRequest resolution — middleware always is, but if you're doing $request->validate() inside a route closure the same rule applies.

Convert route parameters too. If you accept IDs in the path (/orders/١٢٣), route-model binding happens after route middleware, so registering the middleware on the route is enough if the package reads route parameters. If it doesn't, add a Route::bind or a prependMiddleware that calls $request->route()->setParameter(...).

Pair with a JSON response normalizer for APIs. Clients that send Arabic digits often expect to receive them. A tiny terminating middleware or an API Resource with() that runs numberToArabic on selected fields gives you symmetric behavior without pulling the request middleware into the response path.

Use the underlying conversion directly when you need it outside HTTP. If the package exposes a helper/class for the character mapping, reuse it in casts, imports (CSV parsing of Arabic numerals), and queued jobs. Don't duplicate the digit table.

Test it like any middleware. Feature-test the endpoint with Arabic digits in the body and assert on the FormRequest/controller output:

$this->post('/register', ['phone' => '١٢٣٤٥٦٧٨'])
     ->assertSessionHasNoErrors();
$this->assertDatabaseHas('users', ['phone' => '12345678']);

That test doubles as regression protection for the package's exact behavior.

Gotchas and Tips

  • Two numeral systems, not one. Arabic-Indic (٠١٢٣٤٥٦٧٨٩, U+0660–0669) and Eastern Arabic/Persian (۰۱۲۳۴۵۶۷۸۹, U+06F0–06F9) are different code points. Confirm both are mapped — many "Arabic numbers" packages only handle the first. Add a unit test with ۱۲۳ and ١٢٣ if your users are mixed.
  • $request->replace() is shallow by default. If the middleware doesn't recurse, nested fields like items[0][qty] sail through unconverted. Test a nested payload before trusting it in production; if it fails, wrap the conversion in array_walk_recursive yourself.
  • Raw input bypasses the middleware. Reading $request->getContent() for a hand-parsed JSON body, or php://input directly, returns the original Arabic digits. Stay on $request->all() / $request->input().
  • Query string vs. body. Some implementations only replace request, not query. A GET /search?q=١٢٣ may still be Arabic in $request->query('q'). Verify, and fall back to $request->merge($request->query->all())-style handling if needed.
  • Don't convert everything blindly. Passwords, API tokens, base64 blobs, file names, and signed hashes should never be digit-rewritten. Use the except/only config or a route-level opt-out; a corrupted HMAC signature is a very confusing 403.
  • File uploads. UploadedFile instances should be skipped. If the package walks the whole input array naively, a $request->file('x') in the same request may be mangled. Check is_string() before converting.
  • Decimals and separators are not digits. ١٢٫٥ uses the Arabic decimal separator ٫ (U+066B), which the middleware typically does not map. ١٢.٥ with an ASCII dot converts cleanly to 12.5, but ١٢٫٥ becomes 12٫5 and fails numeric. Normalize separators separately if you expect them.
  • Validation rules that look at characters. digits:8 and integer behave differently on a mixed string like 12٣٤. The middleware normalizes it, but decide whether you want mixed input accepted. Add regex:/^[0-9]+$/ on top if you don't.
  • Direction is one-way per request. If you configure it to emit Eastern digits, your integer validation and integer column casts will break. Treat "to Latin" as the input direction and "to Eastern" as a display-only concern.
  • Idempotent by nature. Re-running the conversion on already-Latin digits is a no-op, so it's safe to leave the middleware on for all requests, including those already normalized by a client.
  • The package is small and last tagged in 2023. The middleware contract is stable, so it likely still works on current Laravel, but there's little active maintenance and few config knobs. If you hit an edge case (recursion, route params, separators), the fastest fix is usually a ~40-line middleware of your own built on strtr with the same two digit tables — don't fight the package's limitations for a feature this simple.
  • Debugging tip: when a value "mysteriously" differs between the form and the DB, dump $request->all() inside a throwaway middleware placed before the converter and compare with an after dump. It isolates whether the package or your own code is doing the rewriting.
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.
se7enxweb/flysystem
lampwick/laravel
jeslage/statamic-emojis
micahdshackelford/rmap-laravel
draftsmaninc/draftsman
square-bit/laravel-volition
himito/laravel-mailman
htinlynn/genius-helper
maco-studios/hephaestus
elmogy/larafast
xeviant/laravel-paystack
gorilladash/laravel-website-sdk
martialbe/flysystem-oss
chondal/3312client
jeroen-g/flickr
opscale-co/nova-genbi
itsjustvita/laravel-retention
tequilarapido/trackit
gregsphotography/site-builder-filament
cabaoctavio/laravel-query-log