LOG IN SIGN UP
Documentation

Accept-Language header VCL features

  Last updated December 15, 2016

Fastly provides functions in VCL to parse and normalize the Accept-Language header.

Language lookup

An implementation of the Lookup functionality as defined by RFC 4647, section 3.4.

Syntax

accept.language_lookup(<available languages>, <default>, <priority list>)

Argument Explanation
available languages A colon-separated list of languages to choose from. Typically the languages that the origin can provide. For example: en:de:fr:pt:es:zh-CN
default The default language to return if none from the priority list match. For example: en
priority list The Accept-Language header. A comma-separated list of languages, optionally accompanied by weights (q-values). For example: pt-BR,pt;q=0.8,en-US;q=0.6,en;q=0.4

Return values

The best matching language (as per the RFC) is returned. If none are found, the default language is returned, unless a weight of zero (q=0) was indicated by the priority list, in which case NULL is returned.

Examples

set req.http.Normalized-Language =
  accept.language_lookup("en:de:fr:pt:es:zh-CN", "en", req.http.Accept-Language);

The above would result in Normalized-Language: pt given an Accept-Language: pt-BR,pt;q=0.8,en-US;q=0.6,en;q=0.4 header.

accept.language_lookup("en", "nl", "en-GB") results in en, as each subtag is removed and the match retried when a tag does not match.

accept.language_lookup("en:nl", "nl", "en-GB,nl;q=0.5") results in en still, even if nl is a more exact match, because the q-value of nl is lower, and that has precedence. Exactness just does not come into the equation.

accept.language_lookup("en-US:nl", "nl", "en-GB,nl;q=0.5") results in nl, because subtags are not removed from the available languages, only from language tags on the priority list.

accept.language_lookup("en-US:nl", "nl", "en-us,nl;q=0.5") results in en-US, as the lookup is case insensitive.

accept.language_lookup("en-US:nl", "nl", "en-GB,nl;q=0") results in NULL (the value, not a string) since en-GB and en do not match, and nl (the default) is listed as unacceptable.

If q=0 for the default language is to be ignored, the following VCL can be used:

set req.http.Normalized-Language =
  accept.language_lookup("en-US:nl", "nl", req.http.Accept-Language);
if (!req.http.Normalized-Language) {
  # User will get Dutch even if he doesn't want it!
  # (Because none of our languages were acceptable)
  set req.http.Normalized-Language = "nl";
}

Language filter (Basic)

An implementation of the Basic Filtering functionality as defined by RFC 4647, section 3.3.1.

The implementation is not exact when the wildcard tag (*) is used. If a wildcard is encountered and no matches have been found yet, the default is returned. If there are matches, those are returned and the remainder of the priority list is ignored.

(There is no implementation of Extended Filtering, but if you are in need you could always file a feature request with Support. :) )

Syntax

accept.language_filter_basic(<available languages>, <default>, <priority list>, <limit>)

Argument Explanation
available languages A colon-separated list of languages choose from. Typically the languages that the origin can provide. For example: en:de:fr:pt:es:zh-CN
default The default language to return if none from the priority list match. For example: en
priority list The Accept-Language header. A comma-separated list of languages, optionally accompanied by weights (q-values). For example: pt-BR,pt;q=0.8,en-US;q=0.6,en;q=0.4
limit The maximum amount of languages returned.

Return values

The best matching language (as per the RFC) is returned. If none are found, the default language is returned, unless a weight of zero (q=0) was indicated by the priority list, in which case NULL is returned.

Examples

set req.http.Filtered-Language =
  accept.language_filter_basic("en:de:fr:pt:es:zh-CN", "en", req.http.Accept-Language, 2);

The above would result in Filtered-Language: pt,en given an Accept-Language: pt-BR,pt;q=0.8,en-US;q=0.6,en;q=0.4 header.

accept.language_filter_basic("en", "nl", "en-GB", 2) results in en, as each subtag is removed and the match retried when a tag does not match.

accept.language_filter_basic("en:nl", "nl", "en-GB,nl;q=0.5", 2) results in en,nl, even if nl is a more exact match, because the q-value of nl is lower, and that has precedence. Exactness just does not come into the equation.

accept.language_filter_basic("en-US:nl", "nl", "en-GB,nl;q=0.5", 2) results in nl, because subtags are not removed from the available languages during the search.

accept.language_filter_basic("en-US:nl", "nl", "en-us,nl;q=0.5", 2) results in en-US,nl, as the lookup is case insensitive.

accept.language_filter_basic("en-US:nl", "nl", "en-GB,nl;q=0", 2) results in NULL (the value, not a string) since en-GB and en do not match, and nl (the default) is listed as unacceptable.

If q=0 for the default language is to be ignored, the following VCL can be used:

set req.http.Filtered-Language =
  accept.language_filter_basic("en-US:nl", "nl", req.http.Accept-Language, 2);
if (!req.http.Filtered-Language) {
  # User will get Dutch even if he doesn't want it!
  # (Because none of our languages were acceptable)
  set req.http.Filtered-Language = "nl";
}

accept.language_filter_basic("en:nl:de:fr", "nl", "en-GB,*;q=0.5", 2) results in en and accept.language_filter_basic("en:nl:de:fr", "nl", "*", 2) results in nl.


Back to Top