Getting started
Basics
Domains & Origins
Performance

Configuration
Basics
Conditions
Dictionaries
Domains & Origins
Request settings
Cache settings
Headers
Responses
Performance
Custom VCL
Image optimization
Video

Security
Access Control Lists
Monitoring and testing
Securing communications
Security measures
TLS
Web Application Firewall

Integrations
Logging endpoints
Non-Fastly services

Diagnostics
Streaming logs
Debugging techniques
Common errors

Account info
Account management
Billing
User access and control

Reference

    Accept-Language header VCL features

      Last updated May 11, 2018

    Fastly provides a number of extensions to VCL, including functions to parse and normalize the Accept-Language header.

    Language lookup

    We've implemented 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

    1
    2
    
    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:

    1
    2
    3
    4
    5
    6
    7
    
    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)

    We've implemented 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

    1
    2
    
    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:

    1
    2
    3
    4
    5
    6
    7
    
    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