Laravel localization in Turkish Türkçe
Everything you need to ship Turkish in a Laravel app: the right locale codes,
the exact plural forms trans_choice() expects,
real localized Carbon output and Latin-script considerations.
Every value on this page was generated by running ICU, CLDR and Carbon — not copied from another article.
ISO 639-1
tr
Script / Direction
Latin · LTR
Plural forms (Laravel)
1
Text vs English
Similar
Locale codes
Set the base locale in config/app.php. For regional variants,
Turkish commonly uses:
tr_TR, tr_CY
// config/app.php
'locale' => 'tr',
'fallback_locale' => 'en',
// Or switch at runtime
App::setLocale('tr');
Plural rules: what Turkish actually needs
CLDR defines 2 cardinal categories for Turkish. The sample numbers below were computed by ICU for this exact locale:
| CLDR category | Numbers that select it |
|---|---|
| one | 1 |
| other | 0, 2–130, 200, 1000, 1000000, 1.5 |
Laravel's trans_choice() maps numbers to
1 pipe-separated
form for this locale:
| Form index | Numbers that select it |
|---|---|
| 0 | 0–130, 200, 1000 |
// lang/tr/messages.php
'items' => ':count'
// Usage
trans_choice('messages.items', $count, ['count' => $count]);
This language has no grammatical plural, so a single form covers every number.
Try any number live in the pluralization tester.
Localized dates with Carbon
Real output for Turkish (tr locale),
generated by Carbon for March 21, 2026:
$date = now()->locale('tr');
$date->translatedFormat('l, j F Y');
// "Cumartesi, 21 Mart 2026"
$date->isoFormat('LLLL');
// "Cumartesi, 21 Mart 2026 14:30"
$date->isoFormat('L');
// "21.03.2026"
$date->subDays(3)->diffForHumans();
// "3 ay önce"
What to watch out for in Turkish
- Agglutinative with vowel harmony: suffixes change form to match the word they attach to, so placeholder + suffix patterns break.
- Dotted and dotless i are distinct letters (i↔İ, ı↔I); locale-aware case conversion is required to avoid bugs.
- Sen/siz formal-informal distinction; no grammatical gender (o covers he/she/it).
- Decimal comma with dot as thousands separator (1.234,56).
The dotted and dotless i will break your code
Turkish has four i-letters, not two. Alongside the familiar dotted pair it has a dotless ı and its capital I, and the case mappings cross over in a way no other language does.
| Lowercase | Uppercase | Letter |
|---|---|---|
| i | İ (dotted capital) | dotted i |
| ı | I (dotless capital) | dotless i |
So uppercasing i in Turkish gives İ, not I, and lowercasing I gives ı, not i. This is the single most notorious internationalisation bug in software, because it silently breaks code that has nothing to do with display.
The classic Turkish-locale failure
<?php
// With a Turkish locale active, a locale-aware
// uppercase turns 'title' into 'TİTLE'
setlocale(LC_ALL, 'tr_TR');
// Any code doing case-insensitive comparison by
// uppercasing then matching against 'TITLE' now fails.
// Classic victims: header names, file extensions,
// config keys, HTML tag names, 'ID' vs 'id'.
The rule is to keep locale out of machine-facing comparisons entirely. Use locale-invariant case folding for identifiers, protocol tokens, file extensions and config keys, and reserve locale-aware case conversion strictly for text being shown to a person. In PHP that means strtolower() for identifiers and mb_convert_case() with an explicit locale for display.
The same applies in the database: a case-insensitive collation set to Turkish will match i and ı differently from every other locale, which affects unique constraints on usernames and email addresses. Store and compare those with a locale-invariant collation.
This bug does not require Turkish users. It requires a Turkish locale being active in the process, which can happen from a server setting, a request header or a library call, and it then breaks the application for everyone.
Vowel harmony and suffixes with four forms
Turkish is agglutinative: grammatical relationships are expressed by suffixes attached to the word, and suffixes stack. Where English uses prepositions and separate words, Turkish builds a single long token.
The suffixes are not fixed. Turkish vowel harmony means the vowel in a suffix must match the vowels of the stem, and many suffixes therefore have two or four written variants. Consonants can change as well, so the same grammatical ending looks different depending on the word it attaches to.
| Meaning | Example | Suffix variant |
|---|---|---|
| in the file | dosyada | -da |
| in the house | evde | -de |
| in the book | kitapta | -ta (consonant change) |
| in the fruit | meyvede | -de |
This makes placeholders holding nouns fundamentally unsafe, exactly as in Hungarian and Finnish. A template appending a suffix to a variable will produce the wrong form for most values, and the correct variant depends on the vowels and final consonant of a word chosen at runtime.
A template that cannot be made correct
// English: 'Saved in :folder'
// Turkish needs the locative suffix to harmonise:
//
// Belgeler -> Belgelerde
// Resimler -> Resimlerde
// Kitap -> Kitapta
//
// -da, -de, -ta and -te are all the same suffix.
The workable pattern is to quote the variable and attach the suffix to a fixed noun instead: „Resimler” klasörüne kaydedildi. The grammar now lands on klasör (folder), which you control, and the variable sits untouched in quotation marks.
One plural form, and none after numbers
CLDR gives Turkish two plural categories, so trans_choice() takes a two-part string. But there is a rule that matters more than the category count: Turkish does not use the plural suffix after a number. Three files is üç dosya, not üç dosyalar — the numeral already conveys plurality.
A numeral suppresses the plural suffix
// lang/tr/messages.php
'files' => ':count dosya|:count dosya',
// 0 -> 0 dosya
// 1 -> 1 dosya
// 42 -> 42 dosya
//
// ':count dosyalar' is wrong for every number.
The plural suffix -ler or -lar does exist and is used when no number is present — dosyalar (the files) — so both forms occur in an interface. A translator working from an English source with singular and plural forms will often supply the suffixed noun for the second, producing text that is wrong wherever a count appears.
Turkish also has no grammatical gender and no gendered pronouns: o covers he, she and it. That removes an entire class of agreement problems and makes gender-neutral copy the default rather than something to engineer around.
Turkish also lacks articles entirely, so there is no equivalent of the a/an or der/die/das problem that defeats templates elsewhere. Between that and the absence of gender, the only structural obstacle to interpolation is the suffix harmony described above — which is unfortunately sufficient on its own.
Sen or siz, and how Turkish addresses people
Turkish distinguishes informal sen from formal siz, with siz also serving as the ordinary plural. Software convention leans formal: banking, government and business software use siz, and consumer products increasingly use sen but with less uniformity than in Scandinavia.
| English | Informal (sen) | Formal (siz) |
|---|---|---|
| Your account | hesabın | hesabınız |
| Do you want to continue? | Devam etmek istiyor musun? | Devam etmek istiyor musunuz? |
| Welcome | Hoş geldin | Hoş geldiniz |
Note that possession is a suffix rather than a separate word — hesabınız is account-your, one token — so switching register changes the shape of nouns, not only pronouns. This is another reason the choice cannot be swapped late.
Turkish interfaces commonly use the verbal noun for buttons — Kaydet, İptal, Sil — which sidesteps the register question for short labels, as in most languages with a formality distinction.
Layout, sorting and formatting
Turkish expands roughly twenty to thirty per cent over English, and agglutination means individual words can become very long. A stacked chain of suffixes produces a single token with no space to wrap at, so plan for German-like overflow behaviour even though the languages are unrelated.
| English | Turkish | Growth |
|---|---|---|
| Save | Kaydet | +50% |
| Settings | Ayarlar | -13% |
| Cancel | İptal | -17% |
| Sign in | Giriş yap | +13% |
| Your account settings | Hesap ayarlarınız | suffixed |
Sorting needs a Turkish collator. The alphabet includes ç, ğ, ı, ö, ş and ü, each sorting immediately after its base letter, and dotless ı sorts before dotted i — an order no generic Unicode collation produces.
Turkish collation
<?php
$collator = new Collator('tr_TR');
$collator->sort($words);
// Correct order: ... g, ğ, h, ı, i, j ...
// A generic collator places ı and i the other way round.
| Turkish convention | |
|---|---|
| Thousands | 1.234.567 |
| Decimal | 1234,56 |
| Currency | 1.234,56 ₺ |
| Short date | 21.03.2026 |
| Long date | 21 Mart 2026 |
| First day of week | Monday |
Month names are capitalised in Turkish, unlike most European languages. The decimal comma creates the usual numeric-input hazard where floatval() silently discards the fractional part, and the lira is subject to enough inflation that amounts run long — currency fields need room for more digits than a euro design assumes.
Auditing for the locale-sensitive case bug
The dotted-i problem is worth treating as a codebase audit rather than as a Turkish translation task, because it is triggered by a locale being active in the process and affects every user once it is. The work is finding the places where case conversion is used as logic rather than as presentation.
Grep for case functions and classify each call site. Anything comparing a header name, a file extension, a config key, a database column, an enum value, a route name, an HTML tag or a protocol token is machine-facing and must use locale-invariant folding. Anything producing text a person will read is display and may be locale-aware.
In PHP the distinction is not enforced by the function names, which is what makes this easy to get wrong. strtolower() is byte-based and locale-invariant in modern versions, so it is safe for identifiers; mb_convert_case() and anything honouring setlocale() is not. Laravel's Str::lower() uses the multibyte functions, so it belongs in display code rather than in comparisons.
Databases need the same review. A case-insensitive collation configured for Turkish will fold I onto ı rather than i, so a unique constraint on usernames or email addresses behaves differently from every other locale. Store identifiers with a locale-invariant collation and keep the Turkish collation for user-visible sorting.
A regression test is worth writing once. Set the process locale to Turkish, run the comparison paths you rely on, and assert they still match. It takes minutes and it pins down a class of bug that is otherwise discovered only when a server configuration changes.
What ships broken most often
- The dotted-i case bug. Locale-aware case conversion applied to identifiers, breaking comparisons for every user rather than only Turkish ones.
- Suffixes attached to placeholders. Vowel harmony makes the correct form undecidable from a template.
- Plural suffix after a numeral. 3 dosyalar instead of 3 dosya.
- Sorting that swaps ı and i. A generic collator rather than a Turkish one.
- Truncated agglutinated words. Long suffix chains overflowing buttons and table headers.
- Lowercase months. mart instead of Mart — Turkish capitalises them.
- Decimal comma truncating numeric input. The usual silent loss.
The i-bug deserves its reputation. It is the one entry on this list that damages the application for users who have nothing to do with Turkish, it is triggered by configuration rather than by content, and it produces failures — a header not matching, a file extension not recognised — that look nothing like a localisation problem. Audit for locale-aware case conversion in non-display code before it bites.
Install the Laravel-Lang Turkish files for framework strings. They handle the suffix harmony and the numeral rule consistently across every validation message, which is a considerable amount of detail to reproduce by hand.
Turkish also shares the agglutinative structure of Hungarian and Finnish, so the string architecture that works for one works for all three. If your messages are already written as complete keys with quoted variables, Turkish costs little beyond the case audit; if they are assembled from fragments, Turkish will expose that in the same way those languages do, and the fix is the same restructuring.
One further formatting note: Turkey moved to permanent daylight saving time in 2016 and no longer changes its clocks. Scheduling and reminder features that assume a European transition schedule will drift for Turkish users twice a year, and the failure is subtle enough to go unreported for a long time.
Framework strings already translated
Laravel's own validation, auth and pagination strings are maintained in Turkish by the open-source Laravel-Lang project (MIT). Install them, then manage your app's own strings live:
composer require laravel-lang/common --dev
php artisan lang:add tr
php artisan lang:update
Translate your app into Turkish today
Import your lang files, translate every key into Turkish with one AI click, and publish changes live — no deploy. Set up in 5 minutes.