Last week, I was working on a Laravel API for a real estate platform targeting UAE clients. The client specifically requested support for Arabic text in property listings. Seemed straightforward—until the first API response came back garbled, returning المنظور instead of plain Arabic text. That’s when I remembered: UTF-8 in Laravel isn’t a "set it and forget it" thing, especially with non-Latin scripts.
Database Setup: The Starting Point (and Where It Fails)
First step: make sure the database can store Arabic characters. This might sound obvious, but I’ve seen it trip up developers. MySQL’s default charset is utf8, which supports basic Unicode but chokes on longer Arabic strings. We switched to utf8mb4 for the database and tables:
ALTER DATABASE your_db CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;
ALTER TABLE your_table CONVERT TO CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;Then in Laravel’s config/database.php, we updated the charset to match:
'charset' => 'utf8mb4',
'collation' => 'utf8mb4_unicode_ci',But here’s the catch: even after this, the API still returned broken characters. Why? Because the PHP config on the server had default_charset set to UTF-8 instead of utf8mb4. It took me 90 minutes of staring at config files to spot it. Laravel doesn’t handle that part for you.
Accept-Charset Headers and Middleware Nonsense
API clients (like mobile apps or frontend frameworks) need to know Arabic text is coming. Laravel defaults to Accept-Charset: utf-8, but we wanted explicit support for utf8mb4. So I created a middleware to force the right charset in the response header:
// app/Http/Middleware/ForceUtf8Charset.php
public function handle($request, $next)
{
$response = $next($request);
$response->headers->set('Content-Type', 'application/json; charset=utf8mb4');
return $response;
}Then added it to the API route group in routes/api.php. Simple, right? Well, I spent an hour testing it because Postman was caching old responses. Clear your cache, folks.
JSON Encoding in PHP: The Silent Killer
Even after the database and headers were fixed, we had a bug where Arabic text in the response was getting double-encoded. Turned out PHP’s json_encode was the issue. By default, it doesn’t handle emoji or 4-byte UTF-8 sequences properly (like some Arabic script variations). We had to add the JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES flags:
// Override the default JSON response behavior
Response::macro('api', function ($data) {
return response()->json($data, 200, [], JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
});I’ll be real: this was the third time I’d dealt with this exact issue in two years. It still caught me off-guard because the project’s first milestone involved testing only with English data.
Testing with Arabic Slugs (and Why That’s a Pain)
A client once asked for Arabic URL slugs. That seems cool until you realize Laravel’s Str::slug() doesn’t handle Arabic letters by default. We had to extend it:
use Illuminate\Support\Str;
Str::macro('customSlug', function ($string) {
return Str::slug($string, '-');
});No, it’s not perfect. We ended up using thoonk/laravel-transliterated sluggable for better Arabic support. But honestly, most clients in the UAE/GCC region prefer using English slugs for SEO compatibility in both Arabic and English markets. It’s a trade-off they’ll argue about endlessly—until you say "we can test it" and let their analytics team handle the debate.
A Real-World Project That Taught Me a Lesson
The Greeny Corner app (the UAE-based plant store I worked on) had a similar issue with Arabic text in React Native. They wanted the app to support both languages dynamically. We built the backend in Laravel, and I spent three days debugging why Arabic input from the app was getting stored as ??? in the database. Turns out the mobile team had forgotten to set Content-Type: charset=utf-8 in their Axios config. I was this close to shipping it anyway and blaming the mobile team in the standup meeting.
Final Checks Before Deployment
- •Database: Use
utf8mb4withutf8mb4_unicode_cicollation. - •PHP.ini: Override
default_charsettoutf8mb4. - •Response headers: Force
application/json; charset=utf8mb4. - •Test with real data: Arabic users input text in all sorts of strange ways—test with real-life examples from the UAE market.
Also: If you’re building for GCC clients, they’ll often complain about Arabic text looking "small" in the app. Hint: it’s a frontend problem. Blame the frontend team. (Kidding. Sort of.)