LangTags.Match (lang_tags v0.3.1)

Copy Markdown View Source

Matching of language tags against language ranges, according to RFC 4647.

A language range identifies a set of language tags. The most common source of one is an HTTP Accept-Language header, where a client lists the ranges it will accept in order of preference; the server then picks from the tags it actually has.

Two schemes are provided:

  • filter/2 returns every tag a range covers, which suits listing all the acceptable options.
  • lookup/2 returns the single best tag, which suits choosing one thing to serve.

Both compare case-insensitively and return tags in the casing they were given in. Neither consults the registry, so a tag is matched as written, whether or not it is registered; pass it to LangTags.check/1 first if that matters.

Summary

Functions

Returns every tag matched by any of the ranges, using basic filtering.

Returns the single tag that best matches ranges, or nil if none does.

Functions

filter(tags, range)

@spec filter([String.t()], String.t() | [String.t()]) :: [String.t()]

Returns every tag matched by any of the ranges, using basic filtering.

A range matches a tag when it equals the tag, or when it equals a prefix of the tag and the next character in the tag is -. So "de-DE" matches "de-DE-1996" but not "de-Deva". The range "*" matches every tag.

Tags come back in the order they were given, each at most once, however many ranges match them.

For more information, see RFC 4647 section 3.3.1.

Examples

iex> LangTags.Match.filter(["de-DE-1996", "de-Deva", "en-GB"], ["de-de"])
["de-DE-1996"]
iex> LangTags.Match.filter(["de", "en-GB"], ["*"])
["de", "en-GB"]
iex> LangTags.Match.filter(["fr"], ["de"])
[]

lookup(tags, range)

@spec lookup([String.t()], String.t() | [String.t()]) :: String.t() | nil

Returns the single tag that best matches ranges, or nil if none does.

Ranges are tried in order, and the first one to produce a match wins, so the caller's priority beats the order of tags. A range that matches nothing is shortened one subtag at a time and tried again, which is how "en-US" falls back to "en".

Unlike filter/2, a range is only ever shortened, never extended: the range "en" does not match the tag "en-GB".

nil stands for the RFC's notion of a default value, which it leaves to each application to define. Supply your own with lookup(tags, ranges) || "en".

For more information, see RFC 4647 section 3.4.

Examples

iex> LangTags.Match.lookup(["zh-Hant", "en"], ["zh-Hant-CN"])
"zh-Hant"
iex> LangTags.Match.lookup(["fr", "en"], ["de", "en"])
"en"
iex> LangTags.Match.lookup(["en-GB"], ["en"])
nil