Languages and translation
This page explains how the interface language is chosen, the language switcher, and how to translate texts.
Acun UI comes with Turkish and English interfaces. The components appear in whatever language the application uses. Numbers (1.234,5 / 1,234.5) and short dates (05.10.2026 / 10/05/2026) follow the language too.
Quick example
// bootstrap/app.php
use Acun\Ui\Http\Middleware\SetLocale;
->withMiddleware(function (Middleware $middleware): void {
$middleware->web(append: SetLocale::class);
})
{{-- resources/views/layouts/admin/sections/navbar.blade.php --}}
<acun:slot:actions><acun:locale-switcher /></acun:slot:actions>
Both are already set up in the theme. The middleware picks the language of each request, and the visitor changes it with the switcher in the top bar. Livewire updates also go through the web group, so they use the same language.
The visitor's language
SetLocale picks the language in this order:
- Saved choice: The field on the signed-in user's account, otherwise the switcher's cookie.
- Browser language: The first of the browser's languages that is offered. A value such as
en-UScounts asen. - Country: A country in the
countrieslist gets its own language, for example Turkey gets Turkish. Any other known country gets the fallback. - Fallback: If nothing else decides,
fallback, English by default.
Where the country comes from is described at the end of the page, in the Advanced section.
Common options
The language settings are in the locale block of config/acun-ui.php. Keys you leave out use the package default:
'locale' => [
'supported' => ['tr', 'en'],
'fallback' => 'en',
'countries' => ['TR' => 'tr'],
'user_attribute' => 'preferred_locale', // null: cookie only
],
| Option | What it does | Default |
|---|---|---|
supported |
The languages offered; the switcher lists them. | ['tr', 'en'] |
fallback |
The language used when no rule decides. | 'en' |
countries |
Country code → language. | ['TR' => 'tr'] |
user_attribute |
The users table column that stores the choice. | null (cookie only) |
cookie |
The name of the cookie that stores the choice. | 'acun_locale' |
names |
The names in the switcher, each in its own language. | Türkçe, English |
flags |
Each language's flag, as a country code. | tr → tr, en → gb |
country_headers |
The request headers that carry the country code. | Cloudflare, CloudFront, Vercel |
Language switcher
<acun:locale-switcher /> goes in the top bar. It lists the offered languages by their own names, with flags: Türkçe, English.
- The choice is sent to the
acun-ui.localeroute and stored in a cookie that lasts 400 days. The page reopens in the new language. - If
user_attributenames a column, the choice is also saved on the signed-in user's account. That column takes precedence over the cookie, so the preference follows the user across devices. - Flags are country codes:
tr,gb,us,de,fr,es,it,nl,ru. For the US flag on English, write'flags' => ['en' => 'us']. A language without a flag shows none. - If only one language is offered, the switcher isn't shown.
align="start"aligns the list to the left; the default isend.
Changing the package's texts
Components have two kinds of text:
| Text type | Example | How to change it |
|---|---|---|
| Translation key | "Clear selection", "Close", "Change theme" | The application's lang/*.json file |
| Prop | title, label, placeholder, cancel-text |
Pass your own text when you use the component |
The package's key is the English text; the Turkish is in the package's lang/tr.json file. If you write the same key in your application's lang/tr.json file, yours is used. To change the English, use lang/en.json:
// lang/tr.json
{ "Clear selection": "Seçimi kaldır" }
// lang/en.json
{ "Could not copy": "Copy failed" }
All the package's keys are in the vendor/acunsoft/acun-ui-free/lang/tr.json and vendor/acunsoft/acun-ui-pro/lang/tr.json files. To add another language, translate the keys into that language's file and add the language to the supported list.
The application's own texts
Titles, labels, descriptions and empty-state texts are values you pass to the component. In a multilingual application, pass them through __(). If your application is written in Turkish, the key can be Turkish, and its English goes in the lang/en.json file:
<acun:confirmation-dialog name="user-delete" :title="__('Kullanıcıyı sil')">
<acun:button variant="danger" wire:click="delete">{{ __('Sil') }}</acun:button>
</acun:confirmation-dialog>
// lang/en.json
{ "Kullanıcıyı sil": "Delete user", "Sil": "Delete" }
Titles and section names in the JSON menu are translation keys too. The layout translates a Livewire page's #[Title] value. A text without a translation is shown as is.
Plural texts
trans_choice() looks a text up in the current language only if the key exists in that language's JSON file. Otherwise it switches to the fallback language. If a Turkish key is missing from lang/tr.json, a Turkish page shows the English text.
Warning
In an application with Turkish keys, add every key you use with
trans_choice()tolang/tr.json, mapped to itself.
{{ trans_choice(':count ürün|:count ürün', $count, ['count' => $count]) }}
// lang/tr.json
{ ":count ürün|:count ürün": ":count ürün|:count ürün" }
// lang/en.json
{ ":count ürün|:count ürün": ":count product|:count products" }
__() doesn't behave this way: when the key isn't found, it shows the key itself.
Number and date format
{{ \Acun\Ui\Support\Localization::number(1234.5, 1) }} {{-- 1.234,5 · 1,234.5 --}}
{{ \Acun\Ui\Support\Localization::date($order->created_at) }} {{-- 05.10.2026 · 10/05/2026 --}}
number() takes the number of decimal places as its second value. Both use the page's current language.
Advanced
The country
The country code is read from these request headers: CF-IPCountry (Cloudflare), CloudFront-Viewer-Country (CloudFront), X-Vercel-IP-Country (Vercel) and X-Country-Code (your own proxy). Change the list with country_headers. Cloudflare's XX (unknown) and T1 (Tor) values count as unknown.
On a server without these headers, you can plug in your own GeoIP lookup. The function returns a two-letter country code or null:
// AppServiceProvider::boot()
use Acun\Ui\Support\Localization;
Localization::countryUsing(fn (Request $request) => GeoIp::country($request->ip()));
The package never sends the visitor's IP address to an external service.
Caching
Because the page varies by language, the middleware adds Vary: Accept-Language, Cookie to the response. A cache then keeps a separate copy for each language.
Search and Turkish characters
The DataTable and WithListing search (->searchable(), applySearch()) ignores case and Turkish characters. ı, İ, I and i count as the same letter, and ş/s, ç/c, ğ/g, ö/o and ü/u match. Even if the user types "ayse", "Ayşe" is found. This matching happens in the database, in a generated search column; see the Search page for details.
The in-browser search of acun:combobox follows the same rule. The command palette applies the case rules of the page's language: on a Turkish page, "İSTANBUL" matches "istanbul".
Learn more
- Menu: translating menu titles.
- Search: search that ignores Turkish characters.
- Configuration: every key of the
localeblock.