Do these 3 things before closing this tab:
1Clear out junk files and repair common Windows errors2Scan for outdated or missing drivers - takes under a minute3Repair Windows errors before they cause bigger problemsPHP can read a browser’s Accept-Language request header and use it as an initial language preference. The header is only a preference signal—not proof of a person’s identity, location, or fluency—so match it against the languages your site actually serves, keep an intentional fallback, and let an explicit visitor choice override automatic detection.
What PHP is detecting
Browsers send preferred natural languages in the HTTP Accept-Language header. A request might contain da, en-gb;q=0.8, en;q=0.7: language ranges are listed with relative q weights. The header can be absent, shortened for privacy, or contain languages your application does not support. See RFC 9110 and the MDN Accept-Language reference.
In PHP, the incoming value is normally available as $_SERVER['HTTP_ACCEPT_LANGUAGE']. It is request data, so do not use it directly as a filename, include path, or other executable input.
Smallest implementation with PHP Intl
If the Intl extension is enabled, Locale::acceptFromHttp() provides a standard-library starting point:
Quick wins for a faster PC:
Scan for outdated or missing drivers - takes under a minuteDriver Scan →Repair Windows errors before they cause bigger problemsFix Now →#1 Best Overall
<?php
declare(strict_types=1);
$header = $_SERVER['HTTP_ACCEPT_LANGUAGE'] ?? '';
$locale = $header !== '' ? Locale::acceptFromHttp($header) : false;
if ($locale === false) {
$locale = 'en_US'; // Replace with your deliberate site default.
}
echo htmlspecialchars($locale, ENT_QUOTES, 'UTF-8');
The function returns a locale identifier, or false when the header is too long for INTL_MAX_LOCALE_LEN. It is documented for PHP 5.3+, PHP 7 and PHP 8 through PECL/Intl; verify that Intl is installed and enabled on the deployment. The helper does not accept your application’s supported-language list, so its result must be mapped or validated before selecting a translation. Consult the PHP manual.
Limit the result to languages your site serves
A translation site should define an allowlist using one consistent set of language tags or locale identifiers. Never assume that a locale returned by Intl corresponds to an available translation.
Rank #2
<?php
$header = $_SERVER['HTTP_ACCEPT_LANGUAGE'] ?? '';
$detected = $header !== '' ? Locale::acceptFromHttp($header) : false;
// Keys are the values your application knows how to render.
$supported = [
'en_US' => '/en/',
'fr_FR' => '/fr/',
'de_DE' => '/de/',
];
$locale = is_string($detected) && array_key_exists($detected, $supported)
? $detected
: 'en_US';
$path = $supported[$locale];
Real applications often need an explicit negotiator that accepts supported tags, parses every range and weight, and applies a documented fallback policy. Matching a broad prefix such as en to every English variant is not universally correct; choose a matching scheme appropriate to your locale data, as allowed by RFC 9110 and the language-matching rules it references.
How to negotiate reliably
- Read safely: use
$_SERVER['HTTP_ACCEPT_LANGUAGE'] ?? ''and handle an empty value. - Parse all ranges: recognize tags such as
en-GB, wildcard ranges, and validqweights rather than taking the first substring. - Compare with the allowlist: select only a translation your application can render, using the matching policy you have chosen.
- Define ties and fallback: do not treat equal-
qordering as a guaranteed standard tie-breaker; use a deterministic policy and then the site default. - Normalize safely: map the selected tag to an internal key, never to an arbitrary path supplied by the request.
For a constrained application, a dedicated negotiation library or carefully reviewed parser can be more suitable than Locale::acceptFromHttp(), because the latter performs best-available locale selection without knowing your catalog.
What’s actually slowing this PC down?
Pick the symptom - the matching free tool is one click away.
Give visitors control
Automatic selection should be an initial suggestion. If a visitor has chosen a language previously—through a URL, cookie, session, or account setting—apply that explicit choice before examining Accept-Language. Provide a visible language selector and validate its value against the same allowlist. If the header is missing or no range matches, use the deliberate site default rather than showing an error.
Keep caches correct
If a cacheable response changes because of Accept-Language, send:
Rank #4
Vary: Accept-Language
RFC 9110 defines Vary as the signal that request fields influenced representation selection. Without it, a shared cache can serve one language’s representation to another request. If the response is selected only by a cookie or URL, vary on the mechanism actually used and configure cache keys accordingly.
Choose an implementation approach
| Approach | Strength | Trade-off |
|---|---|---|
Locale::acceptFromHttp() |
Small, standard-library entry point when Intl is enabled | No supported-language allowlist argument; map or validate the result |
| Custom or library negotiation | Explicit selection from only the tags your application serves, with a defined fallback | Requires careful handling of ranges, weights, tags, and matching rules |
| Server-driven negotiation | Apache can select configured language variants without application-level selection | Requires server configuration and variant files; fallback behavior must be tested |
Apache’s content-negotiation documentation describes server-side selection using Accept-Language and its interaction with Vary.
Common mistakes
- Indexing
$_SERVER['HTTP_ACCEPT_LANGUAGE']without a fallback, which can produce notices when the header is absent. - Using the first raw token as the answer and ignoring weights or additional ranges.
- Assuming the header identifies nationality, residence, or a user’s complete language ability.
- Redirecting permanently based only on an automatically detected preference, making it difficult to change languages.
- Passing a browser-provided locale into a filesystem path, SQL fragment, or include statement.
- Varying the response by language without declaring
Vary: Accept-Languagewhen shared caching is involved.
Frequently Asked Questions
What is the exact PHP variable for browser language?
Use $_SERVER['HTTP_ACCEPT_LANGUAGE'] when the web server forwards the header, and provide a fallback because it may be missing.
Does PHP automatically know a visitor’s language?
No. It receives the browser’s preference list. The visitor may use a different language, and browsers may send only a reduced list.
Can Locale::acceptFromHttp() restrict results to my translations?
No. It returns a best-available locale from the header. Validate or map that result to your supported-language allowlist, or use a negotiator designed for that allowlist.
The Bottom Line
Use Accept-Language as a safe first guess: parse and match it against supported translations, honor explicit choices, fall back deliberately, and add Vary: Accept-Language when cacheable content depends on the header.
Crashes, No Sound, or Screen Glitches?
Random freezes, missing sound and display glitches usually trace back to one bad driver. Find and replace yours safely.Free scan · under a minuteWindows Errors? Fix Them Before They Spread
Repair common Windows errors and clear accumulated junk for a smoother, more stable PC - no reinstall needed.Free scan · no reinstallQuick Recap
Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

