Copyright 2013 The Go Authors. All rights reserved. Use of this source code is governed by a BSD-style license that can be found in the LICENSE file.

package language

import (
	
	
	

	
)
ValueError is returned by any of the parsing functions when the input is well-formed but the respective subtag is not recognized as a valid value.
type ValueError interface {
	error
Subtag returns the subtag for which the error occurred.
	Subtag() string
}
Parse parses the given BCP 47 string and returns a valid Tag. If parsing failed it returns an error and any part of the tag that could be parsed. If parsing succeeded but an unknown value was found, it returns ValueError. The Tag returned in this case is just stripped of the unknown value. All other values are preserved. It accepts tags in the BCP 47 format and extensions to this standard defined in https://www.unicode.org/reports/tr35/#Unicode_Language_and_Locale_Identifiers. The resulting tag is canonicalized using the default canonicalization type.
func ( string) ( Tag,  error) {
	return Default.Parse()
}
Parse parses the given BCP 47 string and returns a valid Tag. If parsing failed it returns an error and any part of the tag that could be parsed. If parsing succeeded but an unknown value was found, it returns ValueError. The Tag returned in this case is just stripped of the unknown value. All other values are preserved. It accepts tags in the BCP 47 format and extensions to this standard defined in https://www.unicode.org/reports/tr35/#Unicode_Language_and_Locale_Identifiers. The resulting tag is canonicalized using the canonicalization type c.
func ( CanonType) ( string) ( Tag,  error) {
	,  := language.Parse()
	if  != nil {
		return makeTag(), 
	}
	,  := canonicalize(, )
	if  {
		.RemakeString()
	}
	return makeTag(), 
}
Compose creates a Tag from individual parts, which may be of type Tag, Base, Script, Region, Variant, []Variant, Extension, []Extension or error. If a Base, Script or Region or slice of type Variant or Extension is passed more than once, the latter will overwrite the former. Variants and Extensions are accumulated, but if two extensions of the same type are passed, the latter will replace the former. For -u extensions, though, the key-type pairs are added, where later values overwrite older ones. A Tag overwrites all former values and typically only makes sense as the first argument. The resulting tag is returned after canonicalizing using the Default CanonType. If one or more errors are encountered, one of the errors is returned.
func ( ...interface{}) ( Tag,  error) {
	return Default.Compose(...)
}
Compose creates a Tag from individual parts, which may be of type Tag, Base, Script, Region, Variant, []Variant, Extension, []Extension or error. If a Base, Script or Region or slice of type Variant or Extension is passed more than once, the latter will overwrite the former. Variants and Extensions are accumulated, but if two extensions of the same type are passed, the latter will replace the former. For -u extensions, though, the key-type pairs are added, where later values overwrite older ones. A Tag overwrites all former values and typically only makes sense as the first argument. The resulting tag is returned after canonicalizing using CanonType c. If one or more errors are encountered, one of the errors is returned.
func ( CanonType) ( ...interface{}) ( Tag,  error) {
	var  language.Builder
	if  = update(&, ...);  != nil {
		return und, 
	}
	.Tag, _ = canonicalize(, .Tag)
	return makeTag(.Make()), 
}

var errInvalidArgument = errors.New("invalid Extension or Variant")

func ( *language.Builder,  ...interface{}) ( error) {
	for ,  := range  {
		switch v := .(type) {
		case Tag:
			.SetTag(.tag())
		case Base:
			.Tag.LangID = .langID
		case Script:
			.Tag.ScriptID = .scriptID
		case Region:
			.Tag.RegionID = .regionID
		case Variant:
			if .variant == "" {
				 = errInvalidArgument
				break
			}
			.AddVariant(.variant)
		case Extension:
			if .s == "" {
				 = errInvalidArgument
				break
			}
			.SetExt(.s)
		case []Variant:
			.ClearVariants()
			for ,  := range  {
				.AddVariant(.variant)
			}
		case []Extension:
			.ClearExtensions()
			for ,  := range  {
				.SetExt(.s)
TODO: support parsing of raw strings based on morphology or just extensions?
		case error:
			if  != nil {
				 = 
			}
		}
	}
	return
}

var errInvalidWeight = errors.New("ParseAcceptLanguage: invalid weight")
ParseAcceptLanguage parses the contents of an Accept-Language header as defined in http://www.ietf.org/rfc/rfc2616.txt and returns a list of Tags and a list of corresponding quality weights. It is more permissive than RFC 2616 and may return non-nil slices even if the input is not valid. The Tags will be sorted by highest weight first and then by first occurrence. Tags with a weight of zero will be dropped. An error will be returned if the input could not be parsed.
func ( string) ( []Tag,  []float32,  error) {
	var  string
	for  != "" {
		if ,  = split(, ',');  == "" {
			continue
		}

		,  := split(, ';')
Scan the language.
		,  := Parse()
		if  != nil {
			,  := acceptFallback[]
			if ! {
				return nil, nil, 
			}
			 = makeTag(language.Tag{LangID: })
		}
Scan the optional weight.
		 := 1.0
		if  != "" {
			 = consume(, 'q')
consume returns the empty string when a token could not be consumed, resulting in an error for ParseFloat.
			if ,  = strconv.ParseFloat(, 32);  != nil {
				return nil, nil, errInvalidWeight
Drop tags with a quality weight of 0.
			if  <= 0 {
				continue
			}
		}

		 = append(, )
		 = append(, float32())
	}
	sortStable(&tagSort{, })
	return , , nil
}
consume removes a leading token c from s and returns the result or the empty string if there is no such token.
func ( string,  byte) string {
	if  == "" || [0] !=  {
		return ""
	}
	return strings.TrimSpace([1:])
}

func ( string,  byte) (,  string) {
	if  := strings.IndexByte(, );  >= 0 {
		return strings.TrimSpace([:]), strings.TrimSpace([+1:])
	}
	return strings.TrimSpace(), ""
}
Add hack mapping to deal with a small number of cases that occur in Accept-Language (with reasonable frequency).
var acceptFallback = map[string]language.Language{
	"english": _en,
	"deutsch": _de,
	"italian": _it,
	"french":  _fr,
	"*":       _mul, // defined in the spec to match all languages.
}

type tagSort struct {
	tag []Tag
	q   []float32
}

func ( *tagSort) () int {
	return len(.q)
}

func ( *tagSort) (,  int) bool {
	return .q[] > .q[]
}

func ( *tagSort) (,  int) {
	.tag[], .tag[] = .tag[], .tag[]
	.q[], .q[] = .q[], .q[]