PHPackages                             lochmueller/language-detection - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Localization &amp; i18n](/categories/localization)
4. /
5. lochmueller/language-detection

ActiveTypo3-cms-extension[Localization &amp; i18n](/categories/localization)

lochmueller/language-detection
==============================

Modern language detection middleware for TYPO3. Based on PSR-7, PSR-14 &amp; PSR-15.

5.1.0(6mo ago)1595.0k↓37.7%8[3 issues](https://github.com/lochmueller/language_detection/issues)GPL-2.0-or-laterPHPPHP ^8.2CI failing

Since Sep 4Pushed 6mo ago1 watchersCompare

[ Source](https://github.com/lochmueller/language_detection)[ Packagist](https://packagist.org/packages/lochmueller/language-detection)[ Docs](https://github.com/lochmueller/language_detection)[ Fund](https://paypal.me/lochmueller)[ GitHub Sponsors](https://github.com/lochmueller)[ RSS](/packages/lochmueller-language-detection/feed)WikiDiscussions main Synced 3d ago

READMEChangelog (10)Dependencies (8)Versions (36)Used By (0)

TYPO3 Language Detection
========================

[](#typo3-language-detection)

**Meta:**[![start with why](https://camo.githubusercontent.com/340757f8f825b91a83ebb088fbed9d34e7cbc1db10f1541d748a7871f213b1d2/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f7374617274253230776974682d7768792533462d627269676874677265656e2e7376673f7374796c653d666c6174)](https://www.ted.com/talks/simon_sinek_how_great_leaders_inspire_action)[![Latest Stable Version](https://camo.githubusercontent.com/87b6e1f18690c3a01c936946d3880373e2dd77dffbd1c02138bc541fd1dbddf4/68747470733a2f2f706f7365722e707567782e6f72672f6c6f63686d75656c6c65722f6c616e67756167652d646574656374696f6e2f762f737461626c65)](https://packagist.org/packages/lochmueller/language-detection)[![Total Downloads](https://camo.githubusercontent.com/324f1d664fa85076747ba49f839c5455b0935757641f0e0fe567fdbf4dcae7c9/68747470733a2f2f706f7365722e707567782e6f72672f6c6f63686d75656c6c65722f6c616e67756167652d646574656374696f6e2f646f776e6c6f616473)](https://packagist.org/packages/lochmueller/language-detection)[![License](https://camo.githubusercontent.com/897e1ee40d2e696ed498df1fb24265b9595a0e6f553637a4fc7b2f1a97e84515/68747470733a2f2f706f7365722e707567782e6f72672f6c6f63686d75656c6c65722f6c616e67756167652d646574656374696f6e2f6c6963656e7365)](https://packagist.org/packages/lochmueller/language-detection)[![Crowdin](https://camo.githubusercontent.com/f6eb327e716102abf5f7bdb72eedc407788053d059d0ef5dc166b570a4df4c70/68747470733a2f2f6261646765732e63726f7764696e2e6e65742f7479706f332d657874656e73696f6e2d6c616e67756167656465746563742f6c6f63616c697a65642e737667)](https://crowdin.com/project/typo3-extension-languagedetect)[![Average time to resolve an issue](https://camo.githubusercontent.com/20b978029950256be26227263521162e3a9135a096c84226566b69186926b69e/68747470733a2f2f697369746d61696e7461696e65642e636f6d2f62616467652f7265736f6c7574696f6e2f6c6f63686d75656c6c65722f6c616e67756167655f646574656374696f6e2e737667)](https://isitmaintained.com/project/lochmueller/language_detection "Average time to resolve an issue")[![Percentage of issues still open](https://camo.githubusercontent.com/7d311fcdfdb8a32d95353fe6b8dbcf34bcb44adf478e5702c229e058a4e30892/68747470733a2f2f697369746d61696e7461696e65642e636f6d2f62616467652f6f70656e2f6c6f63686d75656c6c65722f6c616e67756167655f646574656374696f6e2e737667)](https://isitmaintained.com/project/lochmueller/language_detection "Percentage of issues still open")

**Compatibility:**[![TYPO3](https://camo.githubusercontent.com/614ff8ea70de89b6c0ffa951832460b9b407e0c321814a05fe00c02fe6999487/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f5459504f332d31302d6f72616e67652e737667)](https://get.typo3.org/version/10)[![TYPO3](https://camo.githubusercontent.com/5432de37ab8517e6d9e6f803a2e1a7674a308c6d93896fe8a6fbc8a4cb50aece/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f5459504f332d31312d6f72616e67652e737667)](https://get.typo3.org/version/11)[![TYPO3](https://camo.githubusercontent.com/08afacc49187e63c796f7d1c4401d0f0563bab574d9c525312b2827acb09a7c5/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f5459504f332d31322d6f72616e67652e737667)](https://get.typo3.org/version/12)

**Quality:**[![Test](https://github.com/lochmueller/language_detection/actions/workflows/Test.yml/badge.svg)](https://github.com/lochmueller/language_detection/actions/workflows/Test.yml)[![codecov](https://camo.githubusercontent.com/82810146d679860f6e169c90fb5056d2a09ee036ea446decdaa7c6a5aed78f0b/68747470733a2f2f636f6465636f762e696f2f67682f6c6f63686d75656c6c65722f6c616e67756167655f646574656374696f6e2f6272616e63682f6d61696e2f67726170682f62616467652e7376673f746f6b656e3d3756493157464158385a)](https://codecov.io/gh/lochmueller/language_detection)[![Scrutinizer Code Quality](https://camo.githubusercontent.com/bb32aa2a5f8cf826082d2dac0ad02346a76aa5f15cfd7390e644c4984e2505dc/68747470733a2f2f7363727574696e697a65722d63692e636f6d2f672f6c6f63686d75656c6c65722f6c616e67756167655f646574656374696f6e2f6261646765732f7175616c6974792d73636f72652e706e673f623d6d61696e)](https://scrutinizer-ci.com/g/lochmueller/language_detection/?branch=main)[![PHPStan](https://camo.githubusercontent.com/f60d96f7c2579690ab6dfa8918f777fe93a02a92301c661eb38a85861a92b780/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f5048505374616e2d6c6576656c253230382d627269676874677265656e2e7376673f7374796c653d666c6174)](https://github.com/lochmueller/language_detection/actions)

**Support:**[![Donate](https://camo.githubusercontent.com/604e3db9c8751116b3f765aad0353ec7ded655bbe8aaacbc38d8c4a6b784b3ed/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f446f6e6174652d50617950616c2d677265656e2e737667)](https://www.paypal.me/lochmueller/19.99)[![contributions welcome](https://camo.githubusercontent.com/9e93e892d0685e1bf7a1d0bd7c8410d6ecf2086a0a7b48dd58a6b96fa556ea2a/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f636f6e747269627574696f6e732d77656c636f6d652d627269676874677265656e2e7376673f7374796c653d666c6174)](https://github.com/lochmueller/language_detection/issues)[![Plant Tree](https://camo.githubusercontent.com/0684488bba9ddf99c130b487f3b837ab0e40e9900ca5195ce437df5d650aadf1/68747470733a2f2f696d672e736869656c64732e696f2f74726565776172652f74726565732f6c6f63686d75656c6c65722f6c616e67756167655f646574656374696f6e)](https://plant.treeware.earth/lochmueller/language_detection)

---

Table of Contents
=================

[](#table-of-contents)

1. [Why?](#why)
2. [Installation](#installation)
3. [Configuration](#configuration)
4. [Event Structure](#event-structure)
    1. [CheckLanguageDetectionEvent](#checklanguagedetectionevent)
    2. [DetectUserLanguagesEvent](#detectuserlanguagesevent)
    3. [NegotiateSiteLanguageEvent](#negotiatesitelanguageevent)
    4. [BuildResponseEvent](#buildresponseevent)
5. [Troubleshooting](#troubleshooting)
6. [Dev](#dev)
7. [Contribution](#contribution)
8. [Licence](#licence)

Why?
----

[](#why)

Language Detection should be easy &amp; simple to integrate and powerfully in development! TYPO3 Core do not handle language detection via client information. EXT:languag\_detection use a PSR-15/PSR-7 middleware/request ([TYPO3 Documentation](https://docs.typo3.org/m/typo3/reference-coreapi/main/en-us/ApiOverview/RequestHandling/Index.html)) to handle a language detection logic via PSR-14 events([TYPO3 Documentation](https://docs.typo3.org/m/typo3/reference-coreapi/main/en-us/Events/EventDispatcher/Index.html)). Very flexible! Give it a try and checkout the future of language detection!

Installation
------------

[](#installation)

> composer require lochmueller/language-detection

Configuration
-------------

[](#configuration)

Use the site configuration module to configure the language detection. Just enable it, and it will work :) There are several configuration options for the Site configuration that handle the control events. The following screenshot show the options of the detection configuration.

[![Configuration](https://raw.githubusercontent.com/lochmueller/language_detection/main/Resources/Public/Configuration.png)](https://raw.githubusercontent.com/lochmueller/language_detection/main/Resources/Public/Configuration.png)

Event Structure
---------------

[](#event-structure)

There are four central PSR-14 events that control the language detection. The attached list explain the different events and the default listener. The events are ordered in the execution order.

[Diagram](https://sequencediagram.org/index.html#initialData=C4S2BsFMAICVII4FdIGdjQGbgPYHcAoIgYXBEgDtgBaAPgBUBNABQHkBmALmgHEBRetADkAeiEEmbdnT4A3ShgDKwAIYBjANbcAEiooATKNGIALSJoAyegOZIV1yABFIwc6BwU5Cgl6rRl6hrUdJIc3Mo4AA7Q+i5uIB4ANNAgmNBqZpopqFgq4KiQEiwcMvJ+AZo6eoYwzq5qwACqBQBOVhS29mi+wD5lSqqawQzFXP7AUTFxDQkUyanQ4DZ2DjkqLTCYOEgGKRTpZArQG6iRHgVFUqVHFVrQugZGAHKQ1jigKq6KYJDtnQ49Po3QZBEKjcITaKxeruOYpNIUHDQAC2nwykH0i2WXTWGyw2wMlxKtB640CVUeMAAQkgQOB9PBTudIIDSbdhqRyFRuPB9OQGtAJliOitIPM0iczhQCultvToAAjGAK2n0gichTDUJjYh5cCCszQCiQPDC-4wRqwACSBERrmgOHkLWg2p5ryQS2dGwMkBaIA6ROktA13P8lEx2ugzC6sqoCiAA)[![Request flow](https://github.com/lochmueller/language_detection/raw/main/Documentation/Images/Diagram.svg?raw=true)](https://github.com/lochmueller/language_detection/blob/main/Documentation/Images/Diagram.svg?raw=true)

### CheckLanguageDetectionEvent

[](#checklanguagedetectionevent)

Check if the language detection should execute by the extension. You can register listeners for this event and call "disableLanguageDetection" on the event object to disable the language detection.

Default-Listener:

NameDescriptionBackendUserCheckCheck if a backend user call the language detection and disable the redirect (respect "disableRedirectWithBackendSession" config)BotAgentCheckCheck if a bot call the language detection and disable the redirectEnableCheckCheck if the Language Detection is enabled in the current SiteFromCurrentPageCheckCheck the referrer and disable the redirect if the user comes from the current sitePathCheckCheck if the user call "/" and disable the redirect for other paths (respect "allowAllPaths" configuration)WorkspacePreviewCheckCheck if the page is a workspace preview and disable the redirect### DetectUserLanguagesEvent

[](#detectuserlanguagesevent)

This event collect user information to get the user languages. You can register your own detections and manipulate the data via "getUserLanguages" and "setUserLanguages".

Default-Listener:

NameDescriptionBrowserLanguageDetectGet the users "accept-language" languagesGeoPluginDetectSend the IP to ip-api.com and add the language of the location to the checked languages (respect "addIpLocationToBrowserLanguage" configuration)MaxMindDetectUse MaxMind database or webservice to get the country information*Please keep data privacy in mind in case of the "IpLanguage" Listener!*

### NegotiateSiteLanguageEvent

[](#negotiatesitelanguageevent)

This event calculates the best matching page language for the user. If you build your own listener. Please use "setSelectedLanguage" on the event. If a language is already selected the default listener will be skipped.

Default-Listener:

NameDescriptionDefaultNegotiationCheck the Locale and TwoLetterIso of the TYPO3 languages against the user languages of the previous eventFallbackNegotiationHandle a fallback, if there are no matches by the default negotiation### BuildResponseEvent

[](#buildresponseevent)

The last event build the middleware response. You can overwrite this step. You have to use "setResponse" to set the response.

Default-Listener:

NameDescriptionDefaultResponseBuild the response object and respect the "redirectHttpStatusCode" configTroubleshooting
---------------

[](#troubleshooting)

> There are missing or wrong languages in the detection process. Why?

Do you check in incognito mode? The browser will not send all languages in incognito mode. So "wrong results" are possible. Please check the request header to TYPO3 in detail. Otherwise, perhaps the DefaultNegotiation do not handle the "best fitting language" selection process for your needs?

> Why the redirect not work on subpages?

The middleware is early in the middleware stack. There is no concept of links and translations (or even page UID). Furthermore, it is recommended not redirect on subpages. A user that call a subpage first bookmark the page or search in a search engine. In both cases the user already get the right language. I suggest hreflang tags so search engines get the right language of the content

Dev
---

[](#dev)

Run all code standards

> docker run --rm -it --volume $(pwd):/app prooph/composer:8.0 -d /app code:all

Execute tests with PHP 8.0:

> docker run --rm -it --volume $(pwd):/app prooph/composer:8.0 -d /app test:unit

With coverage:

> docker run --rm -it --volume $(pwd):/app cicnavi/dap:80 /app/.Build/bin/phpunit -c /app/phpunit.xml --coverage-text --testdox --coverage-html=/app/var/phpunit

Run Mutation tests:

> docker run --rm -it --workdir=/app/ --volume $(pwd):/app cicnavi/dap:80 /app/.Build/bin/infection -c /app/phpunit.xml

Contribution
------------

[](#contribution)

Thanks all for the great contribution to the project!

[![GitHub Contributors Image](https://camo.githubusercontent.com/c335ec6910557a698b93890865abb999a6c24dbd4f6303ca95c065113f8d7e6b/68747470733a2f2f636f6e747269622e726f636b732f696d6167653f7265706f3d6c6f63686d75656c6c65722f6c616e67756167655f646574656374696f6e)](https://camo.githubusercontent.com/c335ec6910557a698b93890865abb999a6c24dbd4f6303ca95c065113f8d7e6b/68747470733a2f2f636f6e747269622e726f636b732f696d6167653f7265706f3d6c6f63686d75656c6c65722f6c616e67756167655f646574656374696f6e)

Licence
-------

[](#licence)

This package is [Treeware](https://treeware.earth). If you use it in production, then we ask that you [**buy the world a tree**](https://plant.treeware.earth/lochmueller/language_detection) to thank us for our work. By contributing to the Treeware forest you’ll be creating employment for local families and restoring wildlife habitats.

###  Health Score

54

—

FairBetter than 96% of packages

Maintenance62

Regular maintenance activity

Popularity41

Moderate usage in the ecosystem

Community18

Small or concentrated contributor base

Maturity79

Established project with proven stability

 Bus Factor1

Top contributor holds 96.2% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~56 days

Recently: every ~190 days

Total

35

Last Release

206d ago

Major Versions

1.10.2 → 2.0.02021-12-20

2.0.2 → 3.0.02022-02-24

3.0.1 → 4.0.02022-10-16

4.0.3 → 5.0.02024-11-20

PHP version history (5 changes)1.0.0PHP ^7.4

1.6.0PHP ^7.4||^8.0

4.0.0PHP ^8.0

5.0.0PHP ^8.1

5.0.1PHP ^8.2

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/3907126?v=4)[Tim](/maintainers/lochmueller)[@lochmueller](https://github.com/lochmueller)

---

Top Contributors

[![lochmueller](https://avatars.githubusercontent.com/u/3907126?v=4)](https://github.com/lochmueller "lochmueller (254 commits)")[![ghermens](https://avatars.githubusercontent.com/u/47635467?v=4)](https://github.com/ghermens "ghermens (2 commits)")[![georgringer](https://avatars.githubusercontent.com/u/1905663?v=4)](https://github.com/georgringer "georgringer (2 commits)")[![Lukas220300](https://avatars.githubusercontent.com/u/27235229?v=4)](https://github.com/Lukas220300 "Lukas220300 (1 commits)")[![ohader](https://avatars.githubusercontent.com/u/402145?v=4)](https://github.com/ohader "ohader (1 commits)")[![devmes](https://avatars.githubusercontent.com/u/20454675?v=4)](https://github.com/devmes "devmes (1 commits)")[![peterkraume](https://avatars.githubusercontent.com/u/4234704?v=4)](https://github.com/peterkraume "peterkraume (1 commits)")[![feline-fabijan](https://avatars.githubusercontent.com/u/57144349?v=4)](https://github.com/feline-fabijan "feline-fabijan (1 commits)")[![janhelke](https://avatars.githubusercontent.com/u/5299739?v=4)](https://github.com/janhelke "janhelke (1 commits)")

---

Tags

detectionlanguagemiddlewaretypo3typo3-extensionlanguageTYPO3 CMSdetection

###  Code Quality

Static AnalysisPHPStan

Code StylePHP CS Fixer

Type Coverage Yes

### Embed Badge

![Health badge](/badges/lochmueller-language-detection/health.svg)

```
[![Health](https://phpackages.com/badges/lochmueller-language-detection/health.svg)](https://phpackages.com/packages/lochmueller-language-detection)
```

###  Alternatives

[web-vision/wv_deepltranslate

DeepL Translate (CORE) - This extension provides option to translate content element, and TCA record texts to DeepL supported languages.

33304.3k](/packages/web-vision-wv-deepltranslate)[web-vision/deepltranslate-core

DeepL Translate (CORE) - This extension provides option to translate content element, and TCA record texts to DeepL supported languages.

33142.5k8](/packages/web-vision-deepltranslate-core)[friendsoftypo3/content-blocks

TYPO3 CMS Content Blocks - Content Types API | Define reusable components via YAML

103519.9k53](/packages/friendsoftypo3-content-blocks)[brotkrueml/schema

Embedding schema.org vocabulary - API and view helpers for schema.org markup

34653.7k16](/packages/brotkrueml-schema)[leuchtfeuer/locate

Locate - The users country, preferred language and other facts will be detected. Depending on configurable rules the user can be redirected to other languages or pages. Locate also provides geo blocking for configurable pages in configurable countries.

1186.6k](/packages/leuchtfeuer-locate)[b13/link2language

Set Links with a specific language parameter

17184.5k](/packages/b13-link2language)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
