# bcp-47-match [![Build][build-badge]][build] [![Coverage][coverage-badge]][coverage] [![Downloads][downloads-badge]][downloads] [![Size][size-badge]][size] Match BCP 47 language tags with language ranges per RFC 4647. ## Contents * [What is this?](#what-is-this) * [When should I use this?](#when-should-i-use-this) * [Install](#install) * [Use](#use) * [API](#api) * [`basicFilter(tags[, ranges='*'])`](#basicfiltertags-ranges) * [`extendedFilter(tags[, ranges='*'])`](#extendedfiltertags-ranges) * [`lookup(tags, ranges)`](#lookuptags-ranges) * [Types](#types) * [Compatibility](#compatibility) * [Security](#security) * [Related](#related) * [Contribute](#contribute) * [License](#license) ## What is this? This package can match [BCP 47][spec] language tags with β€œlanguage ranges” per [RFC 4647][match]. This is done by the `:lang()` pseudo class in CSS, the `Accept-Language` HTTP header, and a few other places. ## When should I use this? You can use this package if you want to choose a certain document based on language tags. ## Install This package is [ESM only][esm]. In Node.js (version 14.14+, 16.0+), install with [npm][]: ```sh npm install bcp-47-match ``` In Deno with [`esm.sh`][esmsh]: ```js import * as bcp47Match from 'https://esm.sh/bcp-47-match@2' ``` In browsers with [`esm.sh`][esmsh]: ```html ``` ## Use ```js import {basicFilter, extendedFilter, lookup} from 'bcp-47-match' const tags = ['en-GB', 'de-CH', 'en', 'de'] console.log(basicFilter(tags, '*')) // => [ 'en-GB', 'de-CH', 'en', 'de' ] console.log(basicFilter(tags, 'en')) // => [ 'en-GB', 'en' ] console.log(basicFilter(tags, 'en-GB')) // => [ 'en-GB' ] console.log(basicFilter(tags, ['en-GB', 'en'])) // => [ 'en-GB', 'en' ] console.log(basicFilter(tags, 'jp')) // => [] console.log(extendedFilter(tags, '*')) // => [ 'en-GB', 'de-CH', 'en', 'de' ] console.log(extendedFilter(tags, 'en')) // => [ 'en-GB', 'en' ] console.log(extendedFilter(tags, 'en-GB')) // => [ 'en-GB' ] console.log(extendedFilter(tags, '*-GB')) // => [ 'en-GB' ] console.log(extendedFilter(tags, ['en-GB', 'en'])) // => [ 'en-GB', 'en' ] console.log(extendedFilter(tags, 'jp')) // => [] console.log(lookup(tags, 'en')) // => 'en' console.log(lookup(tags, 'en-GB')) // => 'en-GB' console.log(lookup(tags, ['en-GB', 'en'])) // => 'en-GB' console.log(lookup(tags, ['en', 'en-GB'])) // => 'en' console.log(lookup(tags, 'jp')) // => undefined ``` ## API This package exports the identifier `basicFilter`, `extendedFilter`, and `lookup`. There is no default export. ### `basicFilter(tags[, ranges='*'])` > πŸ‘‰ **Note**: See > [Basic Filtering spec](https://tools.ietf.org/html/rfc4647#section-3.3.1) Match language tags to a list of simple ranges. Searches for matches between the first range and all tags, and continues with further ranges. Returns a list of matching tags in the order they matched.
View matching table | Basic Filter | `*` | `de` | `de-CH` | `de-DE` | `de-*-DE` | `*-CH` | | - | - | - | - | - | - | - | | `de` | βœ”οΈŽ | βœ”οΈŽ | | | | | | `de-CH` | βœ”οΈŽ | βœ”οΈŽ | βœ”οΈŽ | | | | | `de-CH-1996` | βœ”οΈŽ | βœ”οΈŽ | βœ”οΈŽ | | | | | `de-DE` | βœ”οΈŽ | βœ”οΈŽ | | βœ”οΈŽ | | | | `de-DE-1996` | βœ”οΈŽ | βœ”οΈŽ | | βœ”οΈŽ | | | | `de-DE-x-goethe` | βœ”οΈŽ | βœ”οΈŽ | | βœ”οΈŽ | | | | `de-Deva` | βœ”οΈŽ | βœ”οΈŽ | | | | | | `de-Deva-DE` | βœ”οΈŽ | βœ”οΈŽ | | | | | | `de-Latf-DE` | βœ”οΈŽ | βœ”οΈŽ | | | | | | `de-Latn-DE` | βœ”οΈŽ | βœ”οΈŽ | | | | | | `de-Latn-DE-1996` | βœ”οΈŽ | βœ”οΈŽ | | | | | | `de-x-DE` | βœ”οΈŽ | βœ”οΈŽ | | | | | | `en` | βœ”οΈŽ | | | | | | | `en-GB` | βœ”οΈŽ | | | | | | | `zh` | βœ”οΈŽ | | | | | | | `zh-Hans` | βœ”οΈŽ | | | | | | | `zh-Hant` | βœ”οΈŽ | | | | | |
###### Parameters * `tags` (`string` or `Array`) β€” list of BCP 47 tags * `ranges` (`string` or `Array`, default: `'*'`) β€” list of RFC 4647 [basic ranges][basic-range] (aka, matching `/^(\*|[a-z]{1,8}(-[a-z0-9]{1,8})*)$/i`) ###### Returns Possibly empty list of matching tags in the order they matched (`Array`). ### `extendedFilter(tags[, ranges='*'])` > πŸ‘‰ **Note**: See > [Extended Filtering spec](https://tools.ietf.org/html/rfc4647#section-3.3.2) Match language tags to a list of extended ranges. Searches for matches between the first range and all tags, and continues with further ranges.
View matching table | Extended Filter | `*` | `de` | `de-CH` | `de-DE` | `de-*-DE` | `*-CH` | | - | - | - | - | - | - | - | | `de` | βœ”οΈŽ | βœ”οΈŽ | | | | | | `de-CH` | βœ”οΈŽ | βœ”οΈŽ | βœ”οΈŽ | | | βœ”οΈŽ | | `de-CH-1996` | βœ”οΈŽ | βœ”οΈŽ | βœ”οΈŽ | | | βœ”οΈŽ | | `de-DE` | βœ”οΈŽ | βœ”οΈŽ | | βœ”οΈŽ | βœ”οΈŽ | | | `de-DE-1996` | βœ”οΈŽ | βœ”οΈŽ | | βœ”οΈŽ | βœ”οΈŽ | | | `de-DE-x-goethe` | βœ”οΈŽ | βœ”οΈŽ | | βœ”οΈŽ | βœ”οΈŽ | | | `de-Deva` | βœ”οΈŽ | βœ”οΈŽ | | | | | | `de-Deva-DE` | βœ”οΈŽ | βœ”οΈŽ | | βœ”οΈŽ | βœ”οΈŽ | | | `de-Latf-DE` | βœ”οΈŽ | βœ”οΈŽ | | βœ”οΈŽ | βœ”οΈŽ | | | `de-Latn-DE` | βœ”οΈŽ | βœ”οΈŽ | | βœ”οΈŽ | βœ”οΈŽ | | | `de-Latn-DE-1996` | βœ”οΈŽ | βœ”οΈŽ | | βœ”οΈŽ | βœ”οΈŽ | | | `de-x-DE` | βœ”οΈŽ | βœ”οΈŽ | | | | | | `en` | βœ”οΈŽ | | | | | | | `en-GB` | βœ”οΈŽ | | | | | | | `zh` | βœ”οΈŽ | | | | | | | `zh-Hans` | βœ”οΈŽ | | | | | | | `zh-Hant` | βœ”οΈŽ | | | | | |
###### Parameters * `tags` (`string` or `Array`) β€” list of BCP 47 tags * `ranges` (`string` or `Array`, default: `'*'`) β€” list of RFC 4647 [extended ranges][extended-range] (aka, matching `/^(\*|[a-z]{1,8})(-(\*|[a-z0-9]{1,8}))*$/i`) ###### Returns Possibly empty list of matching tags in the order they matched (`Array`). ### `lookup(tags, ranges)` > πŸ‘‰ **Note**: See > [Lookup spec](https://tools.ietf.org/html/rfc4647#section-3.4) Find the best language tag that matches a list of ranges. Searches for a match between the first range and all tags, and continues with further ranges. Returns the first match, if any.
View matching table | Lookup | `*` | `de` | `de-CH` | `de-DE` | `de-*-DE` | `*-CH` | | - | - | - | - | - | - | - | | `de` | | βœ”οΈŽοΈŽ | βœ”οΈŽοΈŽ | βœ”οΈŽ | βœ”οΈŽ | βœ”οΈŽ | | `de-CH` | | | βœ”οΈŽ | | | βœ”οΈŽ | | `de-CH-1996` | | | | | | βœ”οΈŽ | | `de-DE` | | | | βœ”οΈŽ | | βœ”οΈŽ | | `de-DE-1996` | | | | | | βœ”οΈŽ | | `de-DE-x-goethe` | | | | | | βœ”οΈŽ | | `de-Deva` | | | | | | βœ”οΈŽ | | `de-Deva-DE` | | | | | | βœ”οΈŽ | | `de-Latf-DE` | | | | | | βœ”οΈŽ | | `de-Latn-DE` | | | | | | βœ”οΈŽ | | `de-Latn-DE-1996` | | | | | | βœ”οΈŽ | | `de-x-DE` | | | | | | βœ”οΈŽ | | `en` | | | | | | βœ”οΈŽ | | `en-GB` | | | | | | βœ”οΈŽ | | `zh` | | | | | | βœ”οΈŽ | | `zh-Hans` | | | | | | βœ”οΈŽ | | `zh-Hant` | | | | | | βœ”οΈŽ |
###### Parameters * `tags` (`string` or `Array`) β€” list of BCP 47 tags * `ranges` (`string` or `Array`) β€” list of RFC 4647 basic ranges (but `*` is ignored) ###### Returns First matching tag in `tags`, `undefined` otherwise (`string?`). ## Types This package is fully typed with [TypeScript][]. It exports no additional types. ## Compatibility This package is at least compatible with all maintained versions of Node.js. As of now, that is Node.js 14.14+ and 16.0+. It also works in Deno and modern browsers. ## Security This package is safe. ## Related * [`wooorm/bcp-47`](https://github.com/wooorm/bcp-47) β€” parse and serialize BCP 47 language tags * [`wooorm/bcp-47-normalize`](https://github.com/wooorm/bcp-47-normalize) β€” normalize, canonicalize, and format BCP 47 tags * [`wooorm/iso-3166`](https://github.com/wooorm/iso-3166) β€” ISO 3166 codes * [`wooorm/iso-639-2`](https://github.com/wooorm/iso-639-2) β€” ISO 639-2 codes * [`wooorm/iso-639-3`](https://github.com/wooorm/iso-639-3) β€” ISO 639-3 codes * [`wooorm/iso-15924`](https://github.com/wooorm/iso-15924) β€” ISO 15924 codes * [`wooorm/un-m49`](https://github.com/wooorm/un-m49) β€” UN M49 codes ## Contribute Yes please! See [How to Contribute to Open Source][contribute]. ## License [MIT][license] Β© [Titus Wormer][author] [build-badge]: https://github.com/wooorm/bcp-47-match/workflows/main/badge.svg [build]: https://github.com/wooorm/bcp-47-match/actions [coverage-badge]: https://img.shields.io/codecov/c/github/wooorm/bcp-47-match.svg [coverage]: https://codecov.io/github/wooorm/bcp-47-match [downloads-badge]: https://img.shields.io/npm/dm/bcp-47-match.svg [downloads]: https://www.npmjs.com/package/bcp-47-match [size-badge]: https://img.shields.io/bundlephobia/minzip/bcp-47-match.svg [size]: https://bundlephobia.com/result?p=bcp-47-match [npm]: https://docs.npmjs.com/cli/install [esmsh]: https://esm.sh [license]: license [author]: https://wooorm.com [esm]: https://gist.github.com/sindresorhus/a39789f98801d908bbc7ff3ecc99d99c [typescript]: https://www.typescriptlang.org [contribute]: https://opensource.guide/how-to-contribute/ [spec]: https://tools.ietf.org/html/bcp47 [match]: https://tools.ietf.org/html/rfc4647 [basic-range]: https://tools.ietf.org/html/rfc4647#section-2.1 [extended-range]: https://tools.ietf.org/html/rfc4647#section-2.2