Laravel localization in Romanian Română
Everything you need to ship Romanian 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
ro
Script / Direction
Latin · LTR
Plural forms (Laravel)
3
Text vs English
Expands
Locale codes
Set the base locale in config/app.php. For regional variants,
Romanian commonly uses:
ro_RO, ro_MD
// config/app.php
'locale' => 'ro',
'fallback_locale' => 'en',
// Or switch at runtime
App::setLocale('ro');
Plural rules: what Romanian actually needs
CLDR defines 3 cardinal categories for Romanian. The sample numbers below were computed by ICU for this exact locale:
| CLDR category | Numbers that select it |
|---|---|
| one | 1 |
| few | 0, 2–19, 101–119, 1.5 |
| other | 20–100, 120–130, 200, 1000, 1000000 |
Laravel's trans_choice() maps numbers to
3 pipe-separated
forms for this locale:
| Form index | Numbers that select it |
|---|---|
| 0 | 1 |
| 1 | 0, 2–19, 101–119 |
| 2 | 20–100, 120–130, 200, 1000 |
// lang/ro/messages.php
'items' => ':count item|:count items'
// Usage
trans_choice('messages.items', $count, ['count' => $count]);
This language uses 3 plural forms. Laravel's built-in trans_choice only resolves two, so for grammatically correct output use an ICU MessageFormat package or handle the extra forms explicitly against the CLDR categories above.
Try any number live in the pluralization tester.
Localized dates with Carbon
Real output for Romanian (ro locale),
generated by Carbon for March 21, 2026:
$date = now()->locale('ro');
$date->translatedFormat('l, j F Y');
// "sâmbătă, 21 martie 2026"
$date->isoFormat('LLLL');
// "sâmbătă, 21 martie 2026 14:30"
$date->isoFormat('L');
// "21.03.2026"
$date->subDays(3)->diffForHumans();
// "3 luni în urmă"
What to watch out for in Romanian
- Definite article is a suffix (cartea = "the book"), so "the {noun}" patterns do not map one-to-one.
- Correct diacritics use comma-below ș and ț (U+0219, U+021B), not the cedilla forms; verify font support.
- Three plural categories (one/few/other): numbers above 19 take the "few" form with "de".
- Tu/dumneavoastră formal distinction; decimal comma with dot as thousands separator (1.234,56).
A Romance language with cases and suffixed articles
Romanian is the outlier of the Romance family. It kept features the others lost and acquired others from its Slavic and Balkan neighbours, so code and copy patterns that work for Spanish, French and Italian frequently do not transfer.
The most visible difference is that the definite article is a suffix rather than a separate word, as in the Scandinavian languages. Fișier is a file; fișierul is the file. There is no word to concatenate, because the grammar lives inside the noun a placeholder would hold.
| English | Romanian | Form |
|---|---|---|
| a file | un fișier | indefinite |
| the file | fișierul | definite suffix |
| files | fișiere | indefinite plural |
| the files | fișierele | definite plural suffix |
| of the file | fișierului | genitive definite |
Romanian also retains a case system — nominative-accusative, genitive-dative and vocative — which combines with the article suffix, so a single noun has a substantial number of forms and the one required depends on its role in the sentence.
There are three genders, and the third is genuinely unusual: neuter nouns behave as masculine in the singular and feminine in the plural. That means adjective agreement can switch gender between one and many, which no amount of template logic will reproduce.
Neuter nouns are common rather than exotic — many everyday objects are neuter — so this is not an edge case to be handled later. A shared adjective string reused between a singular and a plural context will produce the wrong agreement for every neuter noun in the interface, which is a substantial fraction of them.
Three plural forms, including one driven by the number itself
Romanian uses three CLDR categories, and the rule is unusual: the few category applies not to small numbers but to numbers whose last two digits fall between 1 and 19, excluding 1 itself, plus zero.
| Category | Selected by | Example |
|---|---|---|
| one | 1 | 1 fișier |
| few | 0, 2–19, 101–119, 201–219… | 3 fișiere |
| other | 20–100, 120–200… | 25 de fișiere |
The other form carries a grammatical marker the others do not: numbers from twenty upward require the preposition de between the number and the noun. Three files is 3 fișiere, but twenty-five files is 25 de fișiere, and omitting the de is a basic grammatical error.
Three forms, and the de that appears at twenty
// lang/ro/messages.php
// one|few|other
'files' => ':count fișier|:count fișiere|:count de fișiere',
trans_choice('messages.files', $count, ['count' => $count]);
A two-form translation therefore fails twice: it gets the boundary wrong and it drops the preposition entirely for every number above nineteen. Test with 1, 3, 20 and 101 — the last value is the one that catches people, since 101 takes the few form despite being large.
The rule reads oddly to speakers of two-form languages because size and category come apart: 3 and 119 share a form, while 20 and 101 do not. It is worth writing the four test values into an automated check rather than relying on a reviewer to remember them, since nothing about the rendered string suggests which branch produced it.
The comma-below characters that fonts get wrong
Romanian uses five diacritics: ă, â, î, ș and ț. The last two are the problem. They are correctly written with a comma below, not a cedilla, and Unicode encodes the two forms as different characters.
| Correct (comma below) | Wrong (cedilla) | Code points |
|---|---|---|
| ș | ş | U+0219 vs U+015F |
| ț | ţ | U+021B vs U+0163 |
The cedilla forms belong to Turkish and were used for Romanian historically because early character sets and fonts lacked the comma-below variants. A great deal of legacy Romanian text and many older fonts still use them, so real-world data contains both, and they compare unequal while looking nearly identical.
Normalising cedilla forms to comma-below
<?php
$value = strtr($value, [
"\u{015F}" => "\u{0219}", // ş -> ș
"\u{015E}" => "\u{0218}", // Ş -> Ș
"\u{0163}" => "\u{021B}", // ţ -> ț
"\u{0162}" => "\u{021A}", // Ţ -> Ț
]);
Normalise to the comma-below forms on input and verify that the fonts you ship actually contain them — many otherwise complete fonts include the cedilla variants only, and the browser then falls back to a different typeface for those two letters, producing text where a few characters are visibly mismatched.
Sorting needs a Romanian collator. The accented letters sort immediately after their base letters rather than at the end of the alphabet, and a byte-order sort places all of them after z.
Romanian is also written in Moldova, where it is the official language and where it was written in Cyrillic until 1989. Modern Moldovan uses the Latin alphabet and is linguistically the same language, so a single Romanian translation serves both markets — but the currency differs, the Moldovan leu and the Romanian leu being distinct, so the market must be stored separately from the language.
Formality, layout and formatting
Romanian distinguishes informal tu from formal dumneavoastră, with an intermediate dumneata that is now dated. The formal pronoun is notably long, which has a real layout consequence: a sentence addressing the user formally is meaningfully wider than the informal equivalent.
Consumer software generally uses tu; banking, government and formal business use dumneavoastră. As in the other Romance languages, buttons commonly take the infinitive — Salvează, Anulează, Șterge — which sidesteps the register question for short labels.
Romanian expands roughly twenty to thirty per cent over English, and the suffixed articles plus case endings make individual words longer than their Romance cousins.
| Romanian convention | |
|---|---|
| Thousands | 1.234.567 |
| Decimal | 1234,56 |
| Currency | 1.234,56 lei (after the amount) |
| Short date | 21.03.2026 |
| Long date | 21 martie 2026 |
| First day of week | Monday |
Romania is in the European Union and uses the leu rather than the euro, which billing code written for a generic European market regularly gets wrong. Month names are lowercase, and the decimal comma creates the usual numeric-input hazard.
One layout consequence of the suffixed article is worth planning for: a Romanian noun grows when it becomes definite, so labels expand between their indefinite and definite forms. A column header or a button sized against the dictionary form of a word may not fit the form that actually appears in the interface, which is a failure mode with no equivalent in the other Romance languages.
Getting Romanian into the application
Romanian concentrates its difficulty in two places — the character encoding of two letters, and a plural rule with a grammatical marker attached — and both are the kind of problem that is cheap to prevent and expensive to discover late.
Normalise the comma-below characters at every entry point: form submissions, imports, API payloads and the translation files themselves. Doing it in only some places is worse than doing it nowhere, because it guarantees the same word exists in two forms in your data, and reconciling that after several years of records is genuinely hard.
Verify font coverage explicitly rather than trusting a font's description. Many otherwise complete typefaces include only the Turkish cedilla variants, and the browser then falls back for exactly two letters — producing Romanian text where ș and ț are visibly a different typeface. Test with a string containing both rather than with a character sample.
Keyboard layouts are the other source of drift. Romanian layouts configured on older systems produce the cedilla forms by default, so data typed by users accumulates both variants over time even when your own strings are correct.
Treat the plural forms as three plus a preposition rather than as three strings. The de that appears from twenty upward is easy for a translator to omit when working from a two-form English source, and easy for a reviewer to miss because the sentence still reads as a number followed by a noun. Test at 20 specifically.
Set the full locale so dates render with the genitive-free Romanian pattern and amounts show the leu rather than the euro, and install the Laravel-Lang Romanian files for framework strings rather than reproducing the case agreement across several hundred validation messages by hand.
Romanian is a useful sanity check on a localisation pipeline that already handles Slavic languages, because it combines a Romance vocabulary with a case system and suffixed articles. Code that assumes Romance means simple, or that cases mean Cyrillic, will have made an assumption somewhere that Romanian exposes.
What ships broken most often
- Cedilla characters instead of comma-below. ş and ţ where ș and ț belong, splitting records and triggering font fallback.
- Two plural forms instead of three. Wrong boundaries, and the missing de above nineteen.
- Articles concatenated to placeholders. Definiteness is a suffix, so there is nothing to concatenate.
- Neuter gender mishandled. Adjectives that agree as masculine in the singular and feminine in the plural.
- Sorting that dumps diacritics after z. A byte sort rather than a Romanian collator.
- Euro assumed. Romania is in the EU and uses the leu.
- Formal copy overflowing. Dumneavoastră is considerably wider than tu.
The comma-below issue is the one worth automating a check for, because it is invisible in review at normal sizes and corrupts data rather than only presentation. Normalise at every entry point and assert that stored Romanian text contains no cedilla code points.
The second automated check worth having is on the plural strings themselves: assert that every Romanian counting message has exactly three pipe-separated segments and that the third contains de. Both failures are silent, both are easy for a translator to introduce from a two-form source, and neither is visible to a reviewer who does not read Romanian.
Framework strings already translated
Laravel's own validation, auth and pagination strings are maintained in Romanian 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 ro
php artisan lang:update
Translate your app into Romanian today
Import your lang files, translate every key into Romanian with one AI click, and publish changes live — no deploy. Set up in 5 minutes.