{"id":13507420,"url":"https://github.com/codemix/yii2-localeurls","last_synced_at":"2025-05-15T12:00:19.410Z","repository":{"id":21884115,"uuid":"25207823","full_name":"codemix/yii2-localeurls","owner":"codemix","description":"Automatic locale/language management for URLs","archived":false,"fork":false,"pushed_at":"2025-04-01T07:29:15.000Z","size":194,"stargazers_count":410,"open_issues_count":4,"forks_count":112,"subscribers_count":34,"default_branch":"master","last_synced_at":"2025-04-14T19:59:02.890Z","etag":null,"topics":["i18n","language-detection","yii2"],"latest_commit_sha":null,"homepage":null,"language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/codemix.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":".github/CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2014-10-14T13:20:42.000Z","updated_at":"2025-03-15T20:57:41.000Z","dependencies_parsed_at":"2024-06-01T21:00:54.653Z","dependency_job_id":"0b06d672-bdba-4c3f-ad14-2b53b53d3315","html_url":"https://github.com/codemix/yii2-localeurls","commit_stats":{"total_commits":145,"total_committers":15,"mean_commits":9.666666666666666,"dds":"0.16551724137931034","last_synced_commit":"afa019668ccd63b73dcd3cd27e74f5fd92d43c79"},"previous_names":[],"tags_count":39,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/codemix%2Fyii2-localeurls","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/codemix%2Fyii2-localeurls/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/codemix%2Fyii2-localeurls/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/codemix%2Fyii2-localeurls/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/codemix","download_url":"https://codeload.github.com/codemix/yii2-localeurls/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254337612,"owners_count":22054253,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["i18n","language-detection","yii2"],"created_at":"2024-08-01T02:00:33.272Z","updated_at":"2025-05-15T12:00:19.144Z","avatar_url":"https://github.com/codemix.png","language":"PHP","funding_links":[],"categories":["Core components"],"sub_categories":[],"readme":"Yii2 Locale URLs\n================\n\n[![build](https://github.com/codemix/yii2-localeurls/actions/workflows/build.yml/badge.svg)](https://github.com/codemix/yii2-localeurls/actions/workflows/build.yml)\n[![Latest Stable Version](https://poser.pugx.org/codemix/yii2-localeurls/v/stable.svg)](https://packagist.org/packages/codemix/yii2-localeurls)\n[![Total Downloads](https://poser.pugx.org/codemix/yii2-localeurls/downloads)](https://packagist.org/packages/codemix/yii2-localeurls)\n[![Latest Unstable Version](https://poser.pugx.org/codemix/yii2-localeurls/v/unstable.svg)](https://packagist.org/packages/codemix/yii2-localeurls)\n[![License](https://poser.pugx.org/codemix/yii2-localeurls/license.svg)](https://packagist.org/packages/codemix/yii2-localeurls)\n\n\nAutomatic locale/language management through URLs for Yii 2.\n\n\u003e **IMPORTANT:** If you upgraded from version 1.0.* you have to modify your configuration.\n\u003e Please check the section on [Upgrading](#upgrading) below.\n\n## Features\n\nWith this extension you can use URLs that contain a language code like:\n\n    /en/some/page\n    /de/some/page\n    http://www.example.com/en/some/page\n    http://www.example.com/de/some/page\n\nYou can also configure friendly names if you want:\n\n    http://www.example.com/english/some/page\n    http://www.example.com/deutsch/some/page\n\nThe language code is automatically added whenever you create a URL, and\nread back when a URL is parsed. For best user experience the language is\nautodetected from the browser settings, if no language is used in the URL.\nThe user can still access other languages, though, simply by calling a URL\nwith another language code.\n\nThe last requested language is also persisted in the user session and\nin a cookie. So if the user tries to access your site without a language\ncode in the URL, he'll get redirected to the language he had used on\nhis last visit.\n\nAll the above (and more) is configurable of course.\n\n\n## Installation\n\nInstall the package through [composer](http://getcomposer.org):\n\n    composer require codemix/yii2-localeurls\n\nAnd then add this to your application configuration:\n\n```php\n\u003c?php\nreturn [\n\n    // ...\n\n    'components' =\u003e [\n        // ...\n\n        // Override the urlManager component\n        'urlManager' =\u003e [\n            'class' =\u003e 'codemix\\localeurls\\UrlManager',\n\n            // List all supported languages here\n            // Make sure, you include your app's default language.\n            'languages' =\u003e ['en-US', 'en', 'fr', 'de', 'es-*'],\n        ]\n\n        // ...\n    ]\n];\n```\n\nNow you're ready to use the extension.\n\n\u003e Note: You can still configure custom URL rules as usual. Just ignore any `language` parameter\n\u003e in your URL rules as it will get removed before parsing and added after creating a URL.\n\n\u003e Note 2: The language code will be removed from the\n\u003e [pathInfo](http://www.yiiframework.com/doc-2.0/yii-web-request.html#$pathInfo-detail).\n\n## Mode of operation and configuration\n\n### Creating URLs\n\nAll created URLs will contain the code of the current application language. So if the\nlanguage was detected to be `de` and you use:\n\n```php\n\u003c?php $url = Url::to(['demo/action']) ?\u003e\n\u003c?= Html::a('Click', ['demo/action']) ?\u003e\n```\n\nyou'll get URLs like\n\n    /de/demo/action\n\nTo create a link to switch the application to a different language, you can\nexplicitly add the `language` URL parameter:\n\n```php\n\u003c?= $url = Url::to(['demo/action', 'language' =\u003e 'fr']) ?\u003e\n\u003c?= Html::a('Click', ['demo/action', 'language' =\u003e 'fr']) ?\u003e\n```\n\nThis will give you a URL like\n\n    /fr/demo/action\n\n\u003e Note: The URLs may look different if you use custom URL rules. In this case\n\u003e the language parameter is always prepended/inserted to the final relative/absolute URL.\n\nIf for some reason you want to use a different name than `language` for that URL\nparameter you can configure it through the `languageParam` option of the `urlManager`\ncomponent.\n\n### Default Language\n\nThe default language is configured via the\n[language](http://www.yiiframework.com/doc-2.0/yii-base-application.html#$language-detail)\nparameter of your application configuration. You always have to include this\nlanguage in the `$languages` configuration (see below).\n\nBy default the URLs for the default language won't contain any language code. For example:\n\n    /\n    /some/page\n\nIf the site is accessed with URLs containing the default language code, the visitor gets\nredirected to the URLs without language code. For example if default language is `fr`:\n\n    /fr/            -\u003e Redirect to /\n    /fr/some/page   -\u003e Redirect to /some/page\n\nIf `enableDefaultLanguageUrlCode` is changed to `true` it's vice versa. The default language\nis now treated like any other configured language. Requests with URL that don't contain a\nlanguage code are no longer accessible:\n\n    /fr\n    /fr/some/page\n    /               -\u003e Redirect to /fr\n    /some/page      -\u003e Redirect to /fr/some/page\n\n### Language Configuration\n\nAll languages **including the default language** must be configured in the `languages`\nparameter of the `localeUrls` component:\n\n    'languages' =\u003e ['en-US', 'en-UK', 'en', 'fr', 'de-AT', 'de'],\n\n\u003e **Note:** If you use country codes, they should always be configured in upper case letters\n\u003e as shown above. The URLs will still always use lowercase codes. If a URL with an uppercase\n\u003e code like `en-US` is used, the user will be redirected to the lowercase `en-us` variant.\n\u003e The application language will always use the correct `en-US` code. If you don't want to\n\u003e redirect URLs with lowercase country code, you can set the `keepUppercaseLanguageCode`\n\u003e option to `true`.\n\nIf you want your URL to optionally contain *any* country variant you can also use a wildcard pattern:\n\n    'languages' =\u003e ['en-*', 'de-*'],\n\nNow any URL that matches `en-??` or `de-??` could be used, like `en-us` or `de-at`.\nURLs without a country code like `en` and `de` will also still work:\n\n    /en/demo/action\n    /en-us/demo/action\n    /en-en/demo/action\n    /de/demo/action\n    /de-de/demo/action\n    /de-at/demo/action\n\nThe URLs with a country code will set the full `ll-CC` code as Yii language whereas the\nURLs with a language code only, will lead to `ll` as configured language.\n\n\u003e **Note:** You don't need this if all you want is a fallback of `de-AT` to `de` for\n\u003e languages detected from the browser settings. See the section on [Language Detection](#language-detection) below.\n\nYou can also use friendlier names or aliases in URLs, which are configured like so:\n\n    'languages' =\u003e ['en', 'german' =\u003e 'de', 'br' =\u003e 'pt-BR'],\n\n```php\n\u003c?= Url::to(['demo/action', 'language' =\u003e 'de']) ?\u003e\n```\n\nThis will give you URLs like\n\n    /german/demo/action\n    /br/demo/action\n\nand set the respective language to `de` or `pt-PR` if matched.\n\n### Persistence\n\nThe last language a visitor has used will be stored in the user session and in a cookie.\nIf the user visits your site again without a language code, he will get redirected\nto the stored language.\n\nFor example, if the user first visits:\n\n    /de/some/page\n\nthen after some time comes back to one of the following URLs:\n\n    /some/page      -\u003e Redirect to /de/some/page\n    /               -\u003e Redirect to /de/\n    /dk/some/page\n\nIn the last case, `dk` will be stored as last language.\n\nPersistence is enabled by default and can be disabled by setting `enableLanguagePersistence`\nto `false` in the `localeUrls` component.\n\nYou can modify other persistence settings with:\n\n * `languageCookieDuration`: How long in seconds to store the language information in a cookie.\n   Set to `false` to disable the cookie.\n * `languageCookieName`: The name of the language cookie. Default is `_language`.\n * `languageCookieOptions`: Other options to set on the language cookie.\n * `languageSessionKey`: The name of the language session key. Default is `_language`.\n    Since 1.6.0 this can also be set to `false` to not use the session at all.\n\n#### Reset To Default Language\n\nYou'll notice, that there's one problem, if `enableDefaultLanguageUrlCode` is `false` (which\nis the default) and the user has e.g. stored `de` as last language. How can we now\naccess the site in the default language? Because if we try `/` we'd be redirected \nto `/de/`.\n\nThe answer is simple: To create a reset URL, you explicitly include the language code\nfor the default language in the URL. For example if default language is `fr`:\n\n```php\n\u003c?= Url::to(['demo/action', 'language' =\u003e 'fr']) ?\u003e\n```\n\n    /fr/demo/action -\u003e Redirect to /demo/action\n\nIn this case, `fr` will first be stored as last used language before the user is redirected.\n\nIf you explicitely need to create a URL to the default language without any language code,\nyou can also pass an empty string as language:\n\n```php\n\u003c?= Url::to(['demo/action', 'language' =\u003e '']) ?\u003e\n```\n\nThis will give you:\n\n    /demo/action\n\n\n#### Language Change Event\n\nWhen persistence is enabled, the component will fire a `languageChanged` event\nwhenever the language stored in session or cookie changes. Here's an example\nhow this can be used to track user languages in the database:\n\n```php\n\u003c?php\n\n'urlManager' =\u003e [\n    'class' =\u003e 'codemix\\localeurls\\UrlManager',\n    'languages' =\u003e ['en', 'fr', 'de'],\n    'on languageChanged' =\u003e `\\app\\components\\User::onLanguageChanged',\n]\n```\n\nThe static class method in `User` could look like this:\n\n```php\n\u003c?php\npublic static function onLanguageChanged($event)\n{\n    // $event-\u003elanguage: new language\n    // $event-\u003eoldLanguage: old language\n\n    // Save the current language to user record\n    $user = Yii::$app-\u003euser;\n    if (!$user-\u003eisGuest) {\n        $user-\u003eidentity-\u003elanguage = $event-\u003elanguage;\n        $user-\u003eidentity-\u003esave();\n    }\n}\n```\n\u003e **Note:** A language may already have been selected before a user logs in or\n\u003e signs up. So you should also save or update the language in these cases.\n\n\n### Language Detection\n\nIf a user visits your site for the first time and there's no language stored in session\nor cookie (or persistence is turned off), then the language is detected from the visitor's\nbrowser settings. If one of the preferred languages matches your language, it will be\nused as application language (and also persisted if persistence is enabled).\n\nTo disable this, you can set `enableLanguageDetection` to `false`. It's enabled by default.\n\nIf the browser language contains a country code like `de-AT` and you only have `de` in your\n`$languages` configuration, it will fall back to that language. Only if you've used a wildcard\nlike `de-*` or have explicitly configured `de-AT` or an alias like `'at' =\u003e 'de-AT'`, the\nbrowser language including the country code will be used.\n\nLet's look at an example configuration to better understand, how the `$languages` configuration\naffects language detection and the created URLs.\n\n```php\n'languages' =\u003e [\n  'en',\n  'at' =\u003e 'de-AT',\n  'de',\n  'pt-*'\n],\n```\n\nNow say a user visits your site for the first time. Depending on his browser settings, he will\nbe directed to different URLs.\n\nAccept-Language Header              | Resulting URL code    | Resulting Yii language\n------------------------------------|-----------------------|-----------------------\n`en`, `en-us`, `en-US`, ...         | `/en`                 | `en`\n`de-at`, `de-AT`                    | `/at`                 | `de-AT`\n`de`, `de-de`, `de-DE`, `de-ch`, ...| `/de`                 | `de`\n`pt-BR`, `pt-br`                    | `/pt-br`              | `pt-BR`\n`pt-PT`, `pt-pt`                    | `/pt-pt`              | `pt-PT`\nAny other `pt-CC` code              | `/pt-cc`              | `pt-CC`\n`pt`                                | `/pt`                 | `pt`\n\n\n#### Detection via GeoIP server module\n\nSince 1.7.0 language can also be detected via the webserver's GeoIP module.\nNote though that this only happens if no valid language was found in the\nbrowser settings.\n\nFor this feature to work the related GeoIp module must already be installed and\nit must provide the country code in a server variable in `$_SERVER`. You can\nconfigure the key in `$geoIpServerVar`. The default is `HTTP_X_GEO_COUNTRY`.\n\nTo enable this feature, you have to provide a list of GeoIp country codes and\nindex them by the corresponding language that should be set:\n\n```php\n'geoIpLanguageCountries' =\u003e [\n    'de' =\u003e ['DEU', 'AUT'],\n    'pt' =\u003e ['PRT', 'BRA'],\n],\n```\n\n\n### Excluding Routes / URLs\n\nYou may want to disable the language processing for some routes and URLs with the\n`$ignoreLanguageUrlPatterns` option:\n\n```php\n\u003c?php\n    'ignoreLanguageUrlPatterns' =\u003e [\n        // route pattern =\u003e url pattern\n        '#^site/(login|register)#' =\u003e '#^(signin|signup)#',\n        '#^api/#' =\u003e '#^api/#',\n    ],\n```\n\nBoth, keys and values are regular expressions. The keys are patterns that match routes\nto exclude from language processing during *URL creation*, whereas the values are patterns\nfor [pathInfo](http://www.yiiframework.com/doc-2.0/yii-web-request.html#$pathInfo-detail)\nthat should be excluded during *URL parsing*.\n\n\u003e Note: Keys and values don't necessarily have to relate to each other. It's just for\n\u003e convenience, that the configuration is combined into a single option.\n\n## Example Language Selection Widget\n\nThere's no widget for language selection included, because there are simply too many options\nfor the markup and behavior of such a widget. But it's very easy to build. Here's the basic idea:\n\n```php\n\u003c?php\nuse Yii;\nuse yii\\bootstrap\\Dropdown;\n\nclass LanguageDropdown extends Dropdown\n{\n    private static $_labels;\n\n    private $_isError;\n\n    public function init()\n    {\n        $route = Yii::$app-\u003econtroller-\u003eroute;\n        $appLanguage = Yii::$app-\u003elanguage;\n        $params = $_GET;\n        $this-\u003e_isError = $route === Yii::$app-\u003eerrorHandler-\u003eerrorAction;\n\n        array_unshift($params, '/' . $route);\n\n        foreach (Yii::$app-\u003eurlManager-\u003elanguages as $language) {\n            $isWildcard = substr($language, -2) === '-*';\n            if (\n                $language === $appLanguage ||\n                // Also check for wildcard language\n                $isWildcard \u0026\u0026 substr($appLanguage, 0, 2) === substr($language, 0, 2)\n            ) {\n                continue;   // Exclude the current language\n            }\n            if ($isWildcard) {\n                $language = substr($language, 0, 2);\n            }\n            $params['language'] = $language;\n            $this-\u003eitems[] = [\n                'label' =\u003e self::label($language),\n                'url' =\u003e $params,\n            ];\n        }\n        parent::init();\n    }\n\n    public function run()\n    {\n        // Only show this widget if we're not on the error page\n        if ($this-\u003e_isError) {\n            return '';\n        } else {\n            return parent::run();\n        }\n    }\n\n    public static function label($code)\n    {\n        if (self::$_labels === null) {\n            self::$_labels = [\n                'de' =\u003e Yii::t('language', 'German'),\n                'fr' =\u003e Yii::t('language', 'French'),\n                'en' =\u003e Yii::t('language', 'English'),\n            ];\n        }\n\n        return isset(self::$_labels[$code]) ? self::$_labels[$code] : null;\n    }\n}\n```\n\n## Upgrading\n\n### Changes from 1.0.* to 1.1.*\n\nIf you upgrade from a 1.0.* version you'll have to modify your configuration. There no\nlonger is a `localeUrls` component now. Instead everything was merged into our custom\n`urlManager` component. So you should move any configuration for the `localeUrls` component\ninto the `urlManager` component.\n\nTwo options also have been renamed for more clarity:\n\n * `enableDefaultSuffix` is now `enableDefaultLanguageUrlCode`\n * `enablePersistence` is now `enableLanguagePersistence`\n\nSo if your configuration looked like this before:\n\n```php\n\u003c?php\nreturn [\n    'bootstrap' =\u003e ['localeUrls'],\n    'components' =\u003e [\n        'localeUrls' =\u003e [\n            'languages' =\u003e ['en-US', 'en', 'fr', 'de', 'es-*'],\n            'enableDefaultSuffix' =\u003e true,\n            'enablePersistence' =\u003e false,\n        ],\n        'urlManager' =\u003e [\n            'class' =\u003e 'codemix\\localeurls\\UrlManager',\n        ]\n    ]\n];\n```\n\nyou should now change it to:\n\n```php\n\u003c?php\nreturn [\n    'components' =\u003e [\n        'urlManager' =\u003e [\n            'class' =\u003e 'codemix\\localeurls\\UrlManager',\n            'languages' =\u003e ['en-US', 'en', 'fr', 'de', 'es-*'],\n            'enableDefaultLanguageUrlCode' =\u003e true,\n            'enableLanguagePersistence' =\u003e false,\n        ]\n    ]\n];\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcodemix%2Fyii2-localeurls","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcodemix%2Fyii2-localeurls","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcodemix%2Fyii2-localeurls/lists"}