Laravel localization in German Deutsch
Everything you need to ship German 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
de
Script / Direction
Latin · LTR
Plural forms (Laravel)
2
Text vs English
Expands
Locale codes
Set the base locale in config/app.php. For regional variants,
German commonly uses:
de_DE, de_AT, de_CH, de_LU
// config/app.php
'locale' => 'de',
'fallback_locale' => 'en',
// Or switch at runtime
App::setLocale('de');
Plural rules: what German actually needs
CLDR defines 2 cardinal categories for German. 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
2 pipe-separated
forms for this locale:
| Form index | Numbers that select it |
|---|---|
| 0 | 1 |
| 1 | 0, 2–130, 200, 1000 |
// lang/de/messages.php
'items' => ':count item|:count items'
// Usage
trans_choice('messages.items', $count, ['count' => $count]);
Try any number live in the pluralization tester.
Localized dates with Carbon
Real output for German (de locale),
generated by Carbon for March 21, 2026:
$date = now()->locale('de');
$date->translatedFormat('l, j F Y');
// "Samstag, 21 März 2026"
$date->isoFormat('LLLL');
// "Samstag, 21. März 2026 14:30"
$date->isoFormat('L');
// "21.03.2026"
$date->subDays(3)->diffForHumans();
// "vor 3 Monaten"
What to watch out for in German
- Du/Sie formal-informal distinction must be decided before translating UI copy.
- All nouns are capitalized, three grammatical genders, and four cases affect articles and adjective endings.
- Long compound nouns are common; leave room in buttons and labels to avoid truncation.
- Decimal comma (1.234,56); Swiss German (de_CH) uses ss instead of ß and apostrophes as thousands separators.
Why German breaks layouts that survive every other language
German is the language that exposes hardcoded widths. Translated German runs roughly thirty per cent longer than English on average, and short interface strings are far worse than the average suggests — the shorter the English, the larger the expansion ratio. A button reading "Save" becomes "Speichern", "Edit" becomes "Bearbeiten", and "Settings" becomes "Einstellungen".
| English | German | Growth |
|---|---|---|
| Save | Speichern | +125% |
| Edit | Bearbeiten | +150% |
| Cancel | Abbrechen | +80% |
| Settings | Einstellungen | +63% |
| Search | Suchen | +17% |
| Undo | Rückgängig machen | +375% |
Compounding makes it worse. German forms new nouns by welding existing ones together rather than separating them with spaces, so concepts that are three words in English become one unbreakable token. Zahlungsbedingungen (payment terms), Benutzerkontoeinstellungen (user account settings) and Geschwindigkeitsbegrenzung (speed limit) cannot wrap at a space because there is no space in them.
The practical consequence is that a fixed-width container which fits every Romance language will still overflow in German, and the overflow will be a single long word rather than a graceful second line. Test German early rather than treating it as one more locale at the end.
Let long compounds break instead of overflowing
<!-- Tailwind -->
<span class="hyphens-auto break-words" lang="de">
Benutzerkontoeinstellungen
</span>
<!-- The lang attribute is required: hyphenation
rules are language-specific and the browser
needs to know which dictionary to apply. -->
The lang="de" attribute is not decorative. Without it, hyphens: auto has no dictionary to work from and silently does nothing, which is why hyphenation often appears broken in multilingual apps.
Du or Sie: a decision you cannot postpone
German distinguishes formal and informal address grammatically, and the choice runs through every sentence that speaks to the user. This is not a stylistic preference you can settle later — it changes pronouns, possessives, verb conjugations and imperatives, so switching afterwards means retranslating essentially all of your interface copy.
| Informal (du) | Formal (Sie) | |
|---|---|---|
| You | du | Sie |
| Your account | dein Konto | Ihr Konto |
| Save your changes | Speichere deine Änderungen | Speichern Sie Ihre Änderungen |
| Log in | Melde dich an | Melden Sie sich an |
| Do you want to continue? | Willst du fortfahren? | Möchten Sie fortfahren? |
The convention splits by market. Consumer products, startups and anything targeting a younger audience overwhelmingly use du — it is now standard for German-language SaaS. Banking, insurance, healthcare, government and most B2B enterprise software use Sie, and using du there reads as presumptuous rather than friendly.
Note that formal Sie and its possessive Ihr are always capitalised, in any position in the sentence. That capital is what distinguishes Sie (formal you) from sie (she, or they), so a translator lowercasing it changes the meaning rather than just the style.
Record the decision somewhere your translators will see it, ideally as a note attached to the locale itself. The most common way a German translation ends up inconsistent is two translators working on different features a few months apart, each making their own reasonable choice.
Cases and gender make concatenation impossible
German nouns carry one of three grammatical genders — masculine, feminine or neuter — and the language inflects for four cases. Together these determine the form of articles, adjective endings and pronouns, and they make the common English habit of building sentences from fragments completely unworkable.
The definite article alone has six distinct forms depending on gender and case:
| Case | Masculine | Feminine | Neuter | Plural |
|---|---|---|---|---|
| Nominative | der | die | das | die |
| Accusative | den | die | das | die |
| Dative | dem | der | dem | den |
| Genitive | des | der | des | der |
So a template like "Delete the " . $type cannot work. "Delete the file" is Die Datei löschen, "delete the user" is Den Benutzer löschen, and "delete the project" is Das Projekt löschen. The article changes with the noun, and no amount of clever string building will get it right.
Wrong — assembles a sentence from parts
// This cannot be translated correctly into German
__('actions.delete_the') . ' ' . __("types.{$type}")
// Produces: "Löschen die Benutzer" — wrong article, wrong order
Right — one complete key per message
// lang/de/actions.php
return [
'delete_file' => 'Die Datei löschen',
'delete_user' => 'Den Benutzer löschen',
'delete_project' => 'Das Projekt löschen',
];
Gender is also not predictable from meaning. Das Mädchen (the girl) is neuter, because the diminutive suffix -chen always is. Translators know this; string concatenation does not.
Capitalisation and the ß character
German capitalises every noun, not just proper nouns. Der Benutzer speichert die Datei capitalises both Benutzer and Datei because both are nouns. This is a hard orthographic rule rather than a style choice, so applying English title-case or sentence-case transformations to German strings produces text that reads as misspelled.
That has a direct implication for CSS. A text-transform: capitalize or uppercase applied globally will mangle German, and text-transform: lowercase is actively wrong because it strips the capitals the language requires. Scope those rules so they do not apply to German text.
The ß character (Eszett or sharp s) is the other orthographic trap. It exists in Germany and Austria but not in Switzerland, where it is always written as ss. So Straße in Germany is Strasse in Switzerland, and a Swiss user seeing ß registers it as a foreign spelling.
When uppercasing, ß traditionally becomes SS, which means uppercase transformations are not reversible: STRASSE could be Straße or Strasse. A capital ẞ exists and was formally accepted in 2017, but support is inconsistent enough that most style guides still prefer SS.
If you serve Switzerland, treat de_CH as its own locale rather than an alias for de_DE. The ß difference alone is enough for Swiss users to notice, and Swiss German also uses different quotation marks and thousands separators.
Plurals look simple and hide a trap
German takes two plural forms, exactly like English, so trans_choice() works with a straightforward two-part string. That simplicity is real but it conceals a genuine difficulty: German plural noun formation is highly irregular, and the noun itself changes in ways translators must handle per word.
| Singular | Plural | Pattern |
|---|---|---|
| das Bild (image) | die Bilder | add -er |
| der Benutzer (user) | die Benutzer | no change |
| die Datei (file) | die Dateien | add -en |
| das Konto (account) | die Konten | irregular |
| der Ordner (folder) | die Ordner | no change |
| das Formular (form) | die Formulare | add -e |
Notice that several plurals are identical to their singular. Der Benutzer and die Benutzer differ only in the article, so a string that drops the article becomes genuinely ambiguous — :count Benutzer reads correctly for any number, but a bare Benutzer label could mean one or many.
The zero case also differs from English convention. German normally uses the plural form with keine: keine Dateien rather than keine Datei. Since Laravel maps zero to the "other" form for German, this works by default — but only if the translator wrote the plural form there rather than copying the singular.
Numbers, dates and the three German markets
German-speaking Europe is three markets with different conventions, and treating them as one locale produces numbers that look subtly wrong to two thirds of your users.
| Germany (de_DE) | Austria (de_AT) | Switzerland (de_CH) | |
|---|---|---|---|
| Thousands | 1.234.567 | 1.234.567 | 1'234'567 |
| Decimal | 1234,56 | 1234,56 | 1234.56 |
| Currency | 1.234,56 € | € 1.234,56 | CHF 1'234.56 |
| Date | 21.03.2026 | 21.03.2026 | 21.03.2026 |
| January | Januar | Jänner | Januar |
The decimal comma is the one that causes real bugs. A German user typing 1234,56 into a price field submits a string that floatval() reads as 1234, silently discarding the cents. Parse localised numeric input explicitly rather than relying on PHP's default coercion.
Austrian month names differ from German ones for January and February — Jänner and Feber rather than Januar and Februar. Carbon handles this when given the right locale, which is a good reason to pass de_AT rather than falling back to de.
Dates are written day-first with dots and, in the long form, a full stop after the day number: 21. März 2026. That trailing dot is an ordinal marker rather than punctuation, and omitting it is a common tell that a date was formatted by English-centric code.
What ships broken most often
- Mixed du and Sie. The most visible quality problem in German software, and it happens whenever the convention was never written down.
- Truncated compounds. A single unbreakable noun overflowing a button. Test with Benutzerkontoeinstellungen as a worst case rather than with short words.
- Concatenated sentences. Any string built by joining fragments will have the wrong article, the wrong adjective ending, or both.
- Global text-transform. CSS that lowercases or title-cases German breaks the noun-capitalisation rule the language requires.
- Decimal comma in numeric input. Prices and quantities silently losing everything after the comma.
- ß served to Swiss users. Correct for Germany and Austria, wrong for Switzerland.
- Untranslated framework strings. Validation messages in English alongside translated content — install the Laravel-Lang German files rather than writing your own.
Two of these are worth catching automatically. A test that renders every German string into a fixed-width container and flags overflow costs an afternoon to write and finds truncation before users do. A grep for concatenation — any __() call adjacent to a string join — finds the sentences that can never be translated correctly, and it finds them at the point where they are cheap to restructure.
The formality decision deserves a written home rather than a shared assumption. A single line in your translation brief stating that the product uses du or Sie, with one worked example, prevents the drift that otherwise accumulates every time a new feature is translated by someone who was not there for the original conversation.
German is a useful first target precisely because it is demanding. An interface that survives German compounds, case agreement and the formality decision will usually absorb Dutch, the Nordic languages and most of Slavic Europe without further layout work.
Framework strings already translated
Laravel's own validation, auth and pagination strings are maintained in German 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 de
php artisan lang:update
Translate your app into German today
Import your lang files, translate every key into German with one AI click, and publish changes live — no deploy. Set up in 5 minutes.