{"id":24489120,"url":"https://github.com/kudashevs/accept-language","last_synced_at":"2025-10-13T17:32:55.575Z","repository":{"id":57009709,"uuid":"340038187","full_name":"kudashevs/accept-language","owner":"kudashevs","description":"A PHP package that retrieves the preferred language from an HTTP Accept-Language request-header field.","archived":false,"fork":false,"pushed_at":"2025-02-25T21:40:48.000Z","size":850,"stargazers_count":2,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-03-27T12:38:29.153Z","etag":null,"topics":["accept-language","http-headers","preferred-language"],"latest_commit_sha":null,"homepage":"","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/kudashevs.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"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}},"created_at":"2021-02-18T12:08:08.000Z","updated_at":"2025-03-17T20:19:18.000Z","dependencies_parsed_at":"2025-01-09T06:36:13.722Z","dependency_job_id":"362c1c0a-95f9-43dc-b34e-d505d3e2055e","html_url":"https://github.com/kudashevs/accept-language","commit_stats":{"total_commits":829,"total_committers":1,"mean_commits":829.0,"dds":0.0,"last_synced_commit":"a77c72dd4e71923ed9147b34d58c775ee07e0129"},"previous_names":[],"tags_count":23,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kudashevs%2Faccept-language","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kudashevs%2Faccept-language/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kudashevs%2Faccept-language/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/kudashevs%2Faccept-language/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/kudashevs","download_url":"https://codeload.github.com/kudashevs/accept-language/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248788917,"owners_count":21161728,"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":["accept-language","http-headers","preferred-language"],"created_at":"2025-01-21T16:30:50.651Z","updated_at":"2025-10-13T17:32:50.547Z","avatar_url":"https://github.com/kudashevs.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Accept-Language\n\n[![Latest Version on Packagist](https://img.shields.io/packagist/v/kudashevs/accept-language.svg)](https://packagist.org/packages/kudashevs/accept-language)\n[![Run Tests](https://github.com/kudashevs/accept-language/actions/workflows/run-tests.yml/badge.svg)](https://github.com/kudashevs/accept-language/actions/workflows/run-tests.yml)\n[![License MIT](https://img.shields.io/badge/License-MIT-green.svg)](LICENSE.md)\n\nThis PHP package retrieves a user's language of preference from the HTTP Accept-Language request-header field.\n\n\n## Features\n\nBy default, the retrieved language uses the format similar to the Unicode Locale Identifier. This format consists of a\nmandatory 2-/3-letter primary language and a region subtag separated with an underscore (e.g., `en_GB`). However, the format\nis configurable and can be changed, as the set of subtags included in the final result.\n\nMain package features:\n- it can use the default language value set by the `default_language` option\n- it can return a default language value when a client accepts any language (e.g., `Accept-Language: *`)\n- it can retrieve only the languages with the two-letter code by setting the `two_letter_only` option\n- it can retrieve only the languages that are listed in the `accepted_languages` option and their derivatives\n- it can retrieve only the languages that exactly match the `accepted_languages` by setting the `exact_match_only` option\n- it can include extlang, script, and region subtags by setting the `use_\u003csubtag-name\u003e_subtag` options\n- it can set the default separator value by providing the `separator` option\n- it can log its activity at the specific log level by providing the `log_level` option\n- it can log only the events that are listed in the `log_only` option\n\nThe package goes with the built-in Laravel framework support. For more information see [Laravel integration](#laravel-integration) section.\n\n\n## Installation\n\nYou can install the package via composer:\n```bash\ncomposer require kudashevs/accept-language\n```\n\nYou may also want to publish the [configuration](#configuration) file (optional).\n```php\nphp artisan vendor:publish --provider=\"Kudashevs\\AcceptLanguage\\Providers\\AcceptLanguageServiceProvider\"\n```\n\n\n## Usage\n\nTo retrieve a preferred language you need to instantiate the `AcceptLanguage` class and call a `process` method on the\ninstance. This should be done before the point where you want the user's preferred language (for example, in a front\ncontroller or in a middleware). **Note:** if you don't call the `process` method, the values will remain empty.\n```php\nuse \\Kudashevs\\AcceptLanguage\\AcceptLanguage;\n\n$service = new AcceptLanguage();\n$service-\u003eprocess();\n```\n\n**Note:** The `AcceptLanguage` class, at the moment of instantiation, can throw a few exceptions: `InvalidOptionType`,\n`InvalidOptionValue`, `InvalidLogEventName`, `InvalidLogLevelName`. All of these exceptions extend a common built-in\n`InvalidArgumentException` class, so they are easy to deal with.\n\nOnce obtained, the preferred language value can be accessed in any part of your application through these methods:\n```php\n$service-\u003egetPreferredLanguage();           # Returns the user's preferred language\n$service-\u003egetLanguage();                    # An alias of the getPreferredLanguage()\n$service-\u003egetPreferredLanguageQuality();    # Returns a quality of the preferred language\n$service-\u003egetQuality();                     # An alias of the getPreferredLanguageQuality()\n```\n\nIf you need the original HTTP Accept-Language header, it is available via the `getHeader` method.\n```php\n$service-\u003egetHeader();\n```\n\n\n## Configuration\n\nAfter [publishing](#installation), the configuration settings are located in the `config/accept-language.php` file.\n\nThere configuration options are currently supported:\n```\n'default_language'          # A string with a default preferred language value (default is 'en')¹.\n'accepted_languages'        # An array with a list of accepted languages (default is [])².\n'exact_match_only'          # A boolean defines whether to retrieve only languages that match exactly a supported languages (default is false).\n'two_letter_only'           # A boolean defines whether to retrieve only two-letter primary subtags (default is true).\n'use_extlang_subtag'        # A boolean defines whether to include an extlang subtag in the result (default is false).\n'use_script_subtag'         # A boolean defines whether to include a script subtag in the result (default is false).\n'use_region_subtag'         # A boolean defines whether to include a region subtag in the result (default is true).\n'separator'                 # A string with a character that will be used as a separator in the result (default is '_')³.\n'log_level'                 # A string with a PSR-3 compatible log level (default is 'info').\n'log_only'                  # An array with a list of log events to log (default is []).\n```\n\u003csub\u003e1 - the `default_language` option should contain a valid Language Tag (it will be formatted according to the settings)\u003c/sub\u003e  \n\u003csub\u003e2 - the `accepted_languages` option should include valid Language Tags only (the primary subtags are limited to 2-/3-letters for now)\u003c/sub\u003e  \n\u003csub\u003e3 - the separator can accept any string value, however it is recommended to use the [URL Safe Alphabet](https://datatracker.ietf.org/doc/html/rfc4648#section-5).\u003c/sub\u003e\n\n### Notes\n\nSome options require additional explanations:\n\n- the `default_language` option must contain a valid Language Tag. This default value can be written in any case (as the standard says).\nDifferent separators can be used too (for example, ['en-GB', 'en-ca', 'en_GB', 'en_ca']). \n\n**Important note!** the package supports the `-` and `_` separators by default. If you want to use any other separator, use the `separator` option. \n\n- the `accepted_languages` option must include valid Language Tags only. These values can be written in any case (as the standard says).\nDifferent separators can be used too (for example, ['en-GB', 'en-ca', 'en_GB', 'en_ca']). If the `accepted_languages` is empty,\nthe package will retrieve and use the first valid language from an HTTP Accept-Language header. \n\n**Important note!** the values of the `accepted_languages` option will be formatted according to the settings. Therefore,\nif you want to retrieve languages including script subtags you should enable the `use_script_subtag` option.\n\n- the `exact_match_only` option instructs the matching algorithm to retrieve only the languages that exactly match the languages listed\nin the `accepted_languages` option. By default, the matching algorithm is more flexible and retrieves a language and its derivatives.\n\nLet's dig deeper in the matching behavior. Let's assume that the header is `fr-CH, fr;q=0.9, *;q=0.5`:\n| `exact_match_only` option | `accepted_languages` option | \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; the result language |\n|:-------------------------:|:---------------------------:|----------------------------------------------------|\n| false | ['fr'] | the first tag with the quality 1 (derivative case) |\n| false | ['fr-ch'] | the first tag with the quality 1 |\n| true | ['fr'] | the second tag with the quality 0.9 |\n| true | ['fr-ch'] | the first tag with the quality 1 |\n\n, but, when we swap the first two tags and the Accept-Language header becomes `fr, fr-CH;q=0.9, *;q=0.5`:\n| `exact_match_only` option | `accepted_languages` option | \u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp;\u0026nbsp; the result language |\n|:-------------------------:|:---------------------------:|----------------------------------------------------|\n| false | ['fr'] | the first tag with the quality 1 |\n| false | ['fr-ch'] | the second tag with the quality 0.9 |\n| true | ['fr'] | the first tag with the quality 1 |\n| true | ['fr-ch'] | the second tag with the quality 0.9 |\n\n- the `two_letter_only` option is set to `true` by default. When set to `true`, it orders the instance to retrieve only the languages\nwith the two-letter primary subtag. This option has a **higher priority** than the `accepted_languages` option. Thus, if you want to\naccept languages with three-letter primary subtag (by listing them in the `accepted_languages`), don't forget to disable this option.\n\n\n## Logging\n\nThe package is capable to log information gathered throughout the execution process. To start the logging process, you must\nprovide an instance of `Psr\\Log\\LoggerInterface` implementation to the `useLogger` method.\n```php\nuse \\Kudashevs\\AcceptLanguage\\AcceptLanguage;\n\n$service = new AcceptLanguage();\n$service-\u003euseLogger(new PsrCompatibleLogger());\n$service-\u003eprocess();\n```\n\n### Log events\n\nTo distinguish different stages of the execution process the package introduces **log events**. If you want to log specific\nevents only, please add these events to the `log_only` option. If the `log_only` is empty, the package logs all known events.\n\n- `retrieve_header` occurs after retrieving an HTTP Accept-Language header. It logs a raw Accept-Language header value.\n- `retrieve_default_language` occurs when it returns the default language without further processing (the default language case).\n- `retrieve_raw_languages` occurs after retrieving raw languages from the header value. It logs the raw languages and their correctness.\n- `retrieve_normalized_languages` occurs after applying the normalization process to the raw languages. It logs the normalized languages.\n- `retrieve_preferred_languages` occurs after applying the matching algorithm to the normalized languages. It logs the found preferred languages.\n- `retrieve_preferred_language` occurs after the preferred language was or was not found. It logs the preferred language.\n\n\n## Usage example\n\nLet's imaging that we have a web application that uses three different languages: American, British, and Canadian English.\nWe want to redirect users according to their HTTP Accept-Language header settings to specific sections: en_US, en_GB, en_CA.\nAll routes are set correctly, and we just want to retrieve the preferred language, if user has any, to redirect them.\n\nTo work properly, the package requires us to provide two initial options:\n`default_language` let's give it the value `en_US`\n`accepted_languages` let's give it the value `['en_US', 'en_GB', 'en_CA']`\n\n```php\n$service = new AcceptLanguage([\n    'default_language' =\u003e 'en_US',\n    'accepted_languages' =\u003e ['en_US', 'en_GB', 'en_CA'],\n]);\n$service-\u003eprocess();\n```\n\nThese options instruct the package to retrieve only the values that are listed in the `accepted_languages` option.\nIf one of the language tags in an HTTP Accept-Language header matches any of these values, it will be retained for\nthe further processing. If none of them matches the listed values, the default language will be returned.\n\n\n## Laravel integration\n\nInstall the package. If you don't use auto-discovery just add a ServiceProvider to the `config/app.php` file.\n```php\n'providers' =\u003e [\n    Kudashevs\\AcceptLanguage\\Providers\\AcceptLanguageServiceProvider::class,\n];\n```\n\nThe `AcceptLanguageServiceProvider` will instantiate the `AcceptLanguage` class and apply some initial configuration settings.\nThen, it will call the `process` method. However, you can comment it and call the `proccess` method in whatever place you want.\nAfter being registered, the `AcceptLanguage` instance becomes accessible via the Laravel's service container. The instance\ncan be accessed by the class name or through an alias (e.g `app('acceptlanguage')`).\n\nIf you want to add a Laravel Facade, add it to the aliases array in the `config/app.php` file.\n```php\n'aliases' =\u003e [\n    'AcceptLanguage' =\u003e Kudashevs\\AcceptLanguage\\Facades\\AcceptLanguage::class,\n];\n```\n\nIf you want to log the execution process, don't forget to set the `log_activity` option to `true`.\n\nThe configuration settings are located in the `config/accept-language.php` file.\n```\n'default_language' =\u003e 'string'      # Set the `default_language` option value (default is `en`)\n'accepted_languages' =\u003e []          # Set the `accepted_languages` option value (default is [])\n'exact_match_only' =\u003e bool,         # Set the `exact_match_only` option value (default is `false`)\n'use_extlang_subtag' =\u003e bool,       # Set the `use_extlang_subtag` option value (default is `false`)\n'use_script_subtag' =\u003e bool,        # Set the `use_script_subtag` option value (default is `false`)\n'use_region_subtag' =\u003e bool,        # Set the `use_region_subtag` option value (default is `true`)\n'log_activity' =\u003e bool              # Set the `log_activity` option value (default is `false`)\n```\n\u003csub\u003efor more information about different options, please refer to the [Options](#options) section\u003c/sub\u003e\n\nIf you want to change the default values, don't forget to publish the configuration file.\n```bash\nphp artisan vendor:publish --provider=\"Kudashevs\\AcceptLanguage\\Providers\\AcceptLanguageServiceProvider\"\n```\n\n\n## Testing\n\n```bash\ncomposer test\n```\n\n\n## References\n\n- [RFC 7231 Hypertext Transfer Protocol (HTTP/1.1)](https://datatracker.ietf.org/doc/html/rfc7231#section-5.3.5)\n- [RFC 5646 Tags for Identifying Languages](https://datatracker.ietf.org/doc/html/rfc5646#section-2)\n- [RFC 4647 Matching of Language Tags](https://datatracker.ietf.org/doc/html/rfc4647#section-2)\n\n\n## Contributing\n\nPull requests are welcome. For major changes, please open an issue first to discuss what you would like to change.\n\n **Note:** Please make sure to update tests as appropriate.\n\n\n## License\n\nThe MIT License (MIT). Please see the [License file](LICENSE.md) for more information.","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkudashevs%2Faccept-language","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fkudashevs%2Faccept-language","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fkudashevs%2Faccept-language/lists"}