vendor: update all dependencies to latest versions

This commit is contained in:
Nick Craig-Wood
2018-01-16 13:20:59 +00:00
parent 8e83fb6fb9
commit 7d3a17725d
4878 changed files with 1974213 additions and 201199 deletions
+39 -9
View File
@@ -1,25 +1,32 @@
# Go Text
This repository holds supplementary Go libraries for text processing, many involving Unicode.
# Semantic Versioning
## Semantic Versioning
This repo uses Semantic versioning (http://semver.org/), so
1. MAJOR version when you make incompatible API changes,
1. MINOR version when you add functionality in a backwards-compatible manner,
and
1. PATCH version when you make backwards-compatible bug fixes.
A Unicode major and minor version bump is mapped to a major version bump in
x/text.
A path version bump in Unicode is mapped to a minor version bump in x/text.
Note that, consistent with the definitions in semver, until version 1.0.0 of
x/text is reached, the minor version is considered a major version.
So going from 0.1.0 to 0.2.0 is considered to be a major version bump.
Until version 1.0.0 of x/text is reached, the minor version is considered a
major version. So going from 0.1.0 to 0.2.0 is considered to be a major version
bump.
A major new CLDR version is mapped to a minor version increase in x/text.
Any other new CLDR version is mapped to a patch version increase in x/text.
It is important that the Unicode version used in `x/text` matches the one used
by your Go compiler. The `x/text` repository supports multiple versions of
Unicode and will match the version of Unicode to that of the Go compiler. At the
moment this is supported for Go compilers from version 1.7.
# Contribute
## Download/Install
The easiest way to install is to run `go get -u golang.org/x/text`. You can
also manually git clone the repository to `$GOPATH/src/golang.org/x/text`.
## Contribute
To submit changes to this repository, see http://golang.org/doc/contribute.html.
To generate the tables in this repository (except for the encoding tables),
@@ -40,6 +47,20 @@ from this directory to run all tests. Add the "-tags icu" flag to also run
ICU conformance tests (if available). This requires that you have the correct
ICU version installed on your system.
TODO:
- updating unversioned source files.
## Generating Tables
To generate the tables in this repository (except for the encoding
tables), run `go generate` from this directory. By default tables are
generated for the Unicode version in core and the CLDR version defined in
golang.org/x/text/unicode/cldr.
Running go generate will as a side effect create a DATA subdirectory in this
directory which holds all files that are used as a source for generating the
tables. This directory will also serve as a cache.
## Versions
To update a Unicode version run
@@ -61,3 +82,12 @@ backwards compatibility is not maintained.
So updating to a different version may not work.
The files in DATA/{iana|icu|w3|whatwg} are currently not versioned.
## Report Issues / Send Patches
This repository uses Gerrit for code changes. To learn how to submit changes to
this repository, see https://golang.org/doc/contribute.html.
The main issue tracker for the image repository is located at
https://github.com/golang/go/issues. Prefix your issue with "x/image:" in the
subject line, so it is easy to find.
+2 -2
View File
@@ -207,7 +207,7 @@ func genTables() {
}
w := gen.NewCodeWriter()
defer w.WriteGoFile("tables.go", "cases")
defer w.WriteVersionedGoFile("tables.go", "cases")
gen.WriteUnicodeVersion(w)
@@ -761,7 +761,7 @@ func genTablesTest() {
fmt.Fprintln(w, ")")
gen.WriteGoFile("tables_test.go", "cases", w.Bytes())
gen.WriteVersionedGoFile("tables_test.go", "cases", w.Bytes())
}
// These functions are just used for verification that their definition have not
@@ -1,5 +1,7 @@
// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT.
// +build go1.10
package cases
// UnicodeVersion is the Unicode version from which the tables in this package are derived.
@@ -1,5 +1,7 @@
// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT.
// +build go1.10
package cases
var (
+2213
View File
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff
+49
View File
@@ -0,0 +1,49 @@
// Copyright 2017 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 main
import (
"fmt"
"go/build"
"go/parser"
"golang.org/x/tools/go/loader"
)
const (
extractFile = "extracted.gotext.json"
outFile = "out.gotext.json"
gotextSuffix = ".gotext.json"
)
// NOTE: The command line tool already prefixes with "gotext:".
var (
wrap = func(err error, msg string) error {
if err == nil {
return nil
}
return fmt.Errorf("%s: %v", msg, err)
}
errorf = fmt.Errorf
)
// TODO: still used. Remove when possible.
func loadPackages(conf *loader.Config, args []string) (*loader.Program, error) {
if len(args) == 0 {
args = []string{"."}
}
conf.Build = &build.Default
conf.ParserMode = parser.ParseComments
// Use the initial packages from the command line.
args, err := conf.FromArgs(args, false)
if err != nil {
return nil, wrap(err, "loading packages failed")
}
// Load, parse and type-check the whole program.
return conf.Load()
}
+26 -8
View File
@@ -1,9 +1,4 @@
// Copyright 2016 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.
// DO NOT EDIT THIS FILE. GENERATED BY go generate.
// Edit the documentation in other files and rerun go generate to generate this one.
// Code generated by go generate. DO NOT EDIT.
// gotext is a tool for managing text in Go source code.
//
@@ -13,7 +8,9 @@
//
// The commands are:
//
// extract extract strings to be translated from code
// extract extracts strings to be translated from code
// rewrite rewrites fmt functions to use a message Printer
// generate generates code to insert translated messages
//
// Use "go help [command]" for more information about a command.
//
@@ -23,7 +20,7 @@
// Use "gotext help [topic]" for more information about that topic.
//
//
// Extract strings to be translated from code
// Extracts strings to be translated from code
//
// Usage:
//
@@ -32,4 +29,25 @@
//
//
//
// Rewrites fmt functions to use a message Printer
//
// Usage:
//
// go rewrite <package>
//
// rewrite is typically done once for a project. It rewrites all usages of
// fmt to use x/text's message package whenever a message.Printer is in scope.
// It rewrites Print and Println calls with constant strings to the equivalent
// using Printf to allow translators to reorder arguments.
//
//
// Generates code to insert translated messages
//
// Usage:
//
// go generate <package>
//
//
//
//
package main
+84
View File
@@ -0,0 +1,84 @@
// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT.
package main
import (
"golang.org/x/text/language"
"golang.org/x/text/message"
"golang.org/x/text/message/catalog"
)
type dictionary struct {
index []uint32
data string
}
func (d *dictionary) Lookup(key string) (data string, ok bool) {
p := messageKeyToIndex[key]
start, end := d.index[p], d.index[p+1]
if start == end {
return "", false
}
return d.data[start:end], true
}
func init() {
dict := map[string]catalog.Dictionary{
"de": &dictionary{index: deIndex, data: deData},
"en_US": &dictionary{index: en_USIndex, data: en_USData},
"zh": &dictionary{index: zhIndex, data: zhData},
}
fallback := language.MustParse("en-US")
cat, err := catalog.NewFromMap(dict, catalog.Fallback(fallback))
if err != nil {
panic(err)
}
message.DefaultCatalog = cat
}
var messageKeyToIndex = map[string]int{
"%.2[1]f miles traveled (%[1]f)": 8,
"%[1]s is visiting %[3]s!\n": 3,
"%d files remaining!": 5,
"%d more files remaining!": 4,
"%s is out of order!": 7,
"%s is visiting %s!\n": 2,
"Hello %s!\n": 1,
"Hello world!\n": 0,
"Use the following code for your discount: %d\n": 6,
}
var deIndex = []uint32{ // 10 elements
0x00000000, 0x00000011, 0x00000023, 0x0000003d,
0x00000057, 0x00000076, 0x00000076, 0x00000076,
0x00000076, 0x00000076,
} // Size: 64 bytes
const deData string = "" + // Size: 118 bytes
"\x04\x00\x01\x0a\x0c\x02Hallo Welt!\x04\x00\x01\x0a\x0d\x02Hallo %[1]s!" +
"\x04\x00\x01\x0a\x15\x02%[1]s besucht %[2]s!\x04\x00\x01\x0a\x15\x02%[1]" +
"s besucht %[3]s!\x02Noch %[1]d Bestände zu gehen!"
var en_USIndex = []uint32{ // 10 elements
0x00000000, 0x00000012, 0x00000024, 0x00000042,
0x00000060, 0x000000a3, 0x000000ba, 0x000000ef,
0x00000106, 0x00000125,
} // Size: 64 bytes
const en_USData string = "" + // Size: 293 bytes
"\x04\x00\x01\x0a\x0d\x02Hello world!\x04\x00\x01\x0a\x0d\x02Hello %[1]sn" +
"\x04\x00\x01\x0a\x19\x02%[1]s is visiting %[2]s!\x04\x00\x01\x0a\x19\x02" +
"%[1]s is visiting %[3]s!\x14\x01\x81\x01\x00\x02\x14\x02One file remaini" +
"ng!\x00&\x02There are %[1]d more files remaining!\x02%[1]d files remaini" +
"ng!\x04\x00\x01\x0a0\x02Use the following code for your discount: %[1]d" +
"\x02%[1]s is out of order!\x02%.2[1]f miles traveled (%[1]f)"
var zhIndex = []uint32{ // 10 elements
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000,
} // Size: 64 bytes
const zhData string = ""
// Total table size 603 bytes (0KiB); checksum: 1D2754EE
+186
View File
@@ -0,0 +1,186 @@
{
"language": "de",
"messages": [
{
"id": "Hello world!",
"key": "Hello world!\n",
"message": "Hello world!",
"translation": "Hallo Welt!",
"position": "golang.org/x/text/cmd/gotext/examples/extract/main.go:27:10"
},
{
"id": "Hello {City}!",
"key": "Hello %s!\n",
"message": "Hello {City}!",
"translation": "Hallo {City}!",
"placeholders": [
{
"id": "City",
"string": "%[1]s",
"type": "string",
"underlyingType": "string",
"argNum": 1,
"expr": "city"
}
],
"position": "golang.org/x/text/cmd/gotext/examples/extract/main.go:31:10"
},
{
"id": "Hello {Town}!",
"key": "Hello %s!\n",
"message": "Hello {Town}!",
"translation": "Hallo {Town}!",
"placeholders": [
{
"id": "Town",
"string": "%[1]s",
"type": "string",
"underlyingType": "string",
"argNum": 1,
"expr": "town",
"comment": "Town"
}
],
"position": "golang.org/x/text/cmd/gotext/examples/extract/main.go:35:10"
},
{
"id": "{Person} is visiting {Place}!",
"key": "%s is visiting %s!\n",
"message": "{Person} is visiting {Place}!",
"translation": "{Person} besucht {Place}!",
"placeholders": [
{
"id": "Person",
"string": "%[1]s",
"type": "string",
"underlyingType": "string",
"argNum": 1,
"expr": "person",
"comment": "The person of matter."
},
{
"id": "Place",
"string": "%[2]s",
"type": "string",
"underlyingType": "string",
"argNum": 2,
"expr": "place",
"comment": "Place the person is visiting."
}
],
"position": "golang.org/x/text/cmd/gotext/examples/extract/main.go:40:10"
},
{
"id": "{Person} is visiting {Place}!",
"key": "%[1]s is visiting %[3]s!\n",
"message": "{Person} is visiting {Place}!",
"translation": "{Person} besucht {Place}!",
"comment": "Person visiting a place.",
"placeholders": [
{
"id": "Person",
"string": "%[1]s",
"type": "string",
"underlyingType": "string",
"argNum": 1,
"expr": "pp.Person"
},
{
"id": "Place",
"string": "%[3]s",
"type": "string",
"underlyingType": "string",
"argNum": 3,
"expr": "pp.Place",
"comment": "Place the person is visiting."
},
{
"id": "Extra",
"string": "%[2]v",
"type": "int",
"underlyingType": "int",
"argNum": 2,
"expr": "pp.extra"
}
],
"position": "golang.org/x/text/cmd/gotext/examples/extract/main.go:55:10"
},
{
"id": "{N} more files remaining!",
"key": "%d more files remaining!",
"message": "{N} more files remaining!",
"translation": "Noch {N} Bestände zu gehen!",
"placeholders": [
{
"id": "N",
"string": "%[1]d",
"type": "int",
"underlyingType": "int",
"argNum": 1,
"expr": "n"
}
],
"position": "golang.org/x/text/cmd/gotext/examples/extract/main.go:67:10"
},
{
"id": "Use the following code for your discount: {ReferralCode}",
"key": "Use the following code for your discount: %d\n",
"message": "Use the following code for your discount: {ReferralCode}",
"translation": "",
"placeholders": [
{
"id": "ReferralCode",
"string": "%[1]d",
"type": "golang.org/x/text/cmd/gotext/examples/extract.referralCode",
"underlyingType": "int",
"argNum": 1,
"expr": "c"
}
],
"position": "golang.org/x/text/cmd/gotext/examples/extract/main.go:73:10"
},
{
"id": [ "msgOutOfOrder", "{Device} is out of order!" ],
"key": "%s is out of order!",
"message": "{Device} is out of order!",
"translation": "",
"comment": "FOO\n",
"placeholders": [
{
"id": "Device",
"string": "%[1]s",
"type": "string",
"underlyingType": "string",
"argNum": 1,
"expr": "device"
}
],
"position": "golang.org/x/text/cmd/gotext/examples/extract/main.go:81:10"
},
{
"id": "{Miles} miles traveled ({Miles_1})",
"key": "%.2[1]f miles traveled (%[1]f)",
"message": "{Miles} miles traveled ({Miles_1})",
"translation": "",
"placeholders": [
{
"id": "Miles",
"string": "%.2[1]f",
"type": "float64",
"underlyingType": "float64",
"argNum": 1,
"expr": "miles"
},
{
"id": "Miles_1",
"string": "%[1]f",
"type": "float64",
"underlyingType": "float64",
"argNum": 1,
"expr": "miles"
}
],
"position": "golang.org/x/text/cmd/gotext/examples/extract/main.go:85:10"
}
]
}
+137
View File
@@ -0,0 +1,137 @@
{
"language": "de",
"messages": [
{
"id": "Hello world!",
"message": "Hello world!",
"translation": "Hallo Welt!"
},
{
"id": "Hello {City}!",
"message": "Hello {City}!",
"translation": "Hallo {City}!",
"placeholders": [
{
"id": "City",
"string": "%[1]s",
"type": "string",
"underlyingType": "string",
"argNum": 1,
"expr": "city"
}
]
},
{
"id": "{Person} is visiting {Place}!",
"message": "{Person} is visiting {Place}!",
"translation": "{Person} besucht {Place}!",
"placeholders": [
{
"id": "Person",
"string": "%[1]s",
"type": "string",
"underlyingType": "string",
"argNum": 1,
"expr": "person",
"comment": "The person of matter."
},
{
"id": "Place",
"string": "%[2]s",
"type": "string",
"underlyingType": "string",
"argNum": 2,
"expr": "place",
"comment": "Place the person is visiting."
}
]
},
{
"id": "{2} files remaining!",
"message": "{2} files remaining!",
"translation": "",
"placeholders": [
{
"id": "2",
"string": "%[1]d",
"type": "int",
"underlyingType": "int",
"argNum": 1,
"expr": "2"
}
]
},
{
"id": "{N} more files remaining!",
"message": "{N} more files remaining!",
"translation": "Noch {N} Bestände zu gehen!",
"placeholders": [
{
"id": "N",
"string": "%[1]d",
"type": "int",
"underlyingType": "int",
"argNum": 1,
"expr": "n"
}
]
},
{
"id": "Use the following code for your discount: {ReferralCode}",
"message": "Use the following code for your discount: {ReferralCode}",
"translation": "",
"placeholders": [
{
"id": "ReferralCode",
"string": "%[1]d",
"type": "golang.org/x/text/cmd/gotext/examples/extract.referralCode",
"underlyingType": "int",
"argNum": 1,
"expr": "c"
}
]
},
{
"id": [
"msgOutOfOrder",
"{Device} is out of order!"
],
"message": "{Device} is out of order!",
"translation": "",
"comment": "FOO\n",
"placeholders": [
{
"id": "Device",
"string": "%[1]s",
"type": "string",
"underlyingType": "string",
"argNum": 1,
"expr": "device"
}
]
},
{
"id": "{Miles} miles traveled ({Miles_1})",
"message": "{Miles} miles traveled ({Miles_1})",
"translation": "",
"placeholders": [
{
"id": "Miles",
"string": "%.2[1]f",
"type": "float64",
"underlyingType": "float64",
"argNum": 1,
"expr": "miles"
},
{
"id": "Miles_1",
"string": "%[1]f",
"type": "float64",
"underlyingType": "float64",
"argNum": 1,
"expr": "miles"
}
]
}
]
}
@@ -0,0 +1,82 @@
{
"language": "en-US",
"messages": [
{
"id": "Hello world!",
"key": "Hello world!\n",
"message": "Hello world!",
"translation": "Hello world!",
"position": "golang.org/x/text/cmd/gotext/examples/extract/main.go:27:10"
},
{
"id": "Hello {City}!",
"key": "Hello %s!\n",
"message": "Hello {City}!",
"translation": "Hello {City}n"
},
{
"id": "Hello {Town}!",
"key": "Hello %s!\n",
"message": "Hello {Town}!",
"translation": "Hello {Town}!",
"placeholders": [
{
"id": "Town",
"string": "%[1]s",
"type": "string",
"underlyingType": "string",
"argNum": 1,
"expr": "town",
"comment": "Town"
}
]
},
{
"id": "{Person} is visiting {Place}!",
"key": "%s is visiting %s!\n",
"message": "{Person} is visiting {Place}!",
"translation": "{Person} is visiting {Place}!\n"
},
{
"id": "{Person} is visiting {Place}!",
"key": "%[1]s is visiting %[3]s!\n",
"message": "{Person} is visiting {Place}!",
"translation": "{Person} is visiting {Place}!",
"comment": "Person visiting a place."
},
{
"id": "{N} more files remaining!",
"key": "%d more files remaining!",
"message": "{N} more files remaining!",
"translation": {
"select": {
"feature": "plural",
"arg": "N",
"cases": {
"one": "One file remaining!",
"other": "There are {N} more files remaining!"
}
}
}
},
{
"id": "Use the following code for your discount: {ReferralCode}",
"key": "Use the following code for your discount: %d\n",
"message": "Use the following code for your discount: {ReferralCode}",
"translation": ""
},
{
"id": [ "msgOutOfOrder", "{Device} is out of order!" ],
"key": "%s is out of order!",
"message": "{Device} is out of order!",
"translation": "{Device} is out of order!",
"comment": "FOO\n"
},
{
"id": "{Miles} miles traveled ({Miles_1})",
"key": "%.2[1]f miles traveled (%[1]f)",
"message": "{Miles} miles traveled ({Miles_1})",
"translation": "{Miles} miles traveled ({Miles_1})"
}
]
}
+154
View File
@@ -0,0 +1,154 @@
{
"language": "en-US",
"messages": [
{
"id": "Hello world!",
"message": "Hello world!",
"translation": "Hello world!"
},
{
"id": "Hello {City}!",
"message": "Hello {City}!",
"translation": "Hello {City}n",
"placeholders": [
{
"id": "City",
"string": "%[1]s",
"type": "string",
"underlyingType": "string",
"argNum": 1,
"expr": "city"
}
]
},
{
"id": "{Person} is visiting {Place}!",
"message": "{Person} is visiting {Place}!",
"translation": "{Person} is visiting {Place}!",
"placeholders": [
{
"id": "Person",
"string": "%[1]s",
"type": "string",
"underlyingType": "string",
"argNum": 1,
"expr": "person",
"comment": "The person of matter."
},
{
"id": "Place",
"string": "%[2]s",
"type": "string",
"underlyingType": "string",
"argNum": 2,
"expr": "place",
"comment": "Place the person is visiting."
}
]
},
{
"id": "{2} files remaining!",
"message": "{2} files remaining!",
"translation": "{2} files remaining!",
"translatorComment": "Copied from source.",
"placeholders": [
{
"id": "2",
"string": "%[1]d",
"type": "int",
"underlyingType": "int",
"argNum": 1,
"expr": "2"
}
],
"fuzzy": true
},
{
"id": "{N} more files remaining!",
"message": "{N} more files remaining!",
"translation": {
"select": {
"feature": "plural",
"arg": "N",
"cases": {
"one": {
"msg": "One file remaining!"
},
"other": {
"msg": "There are {N} more files remaining!"
}
}
}
},
"placeholders": [
{
"id": "N",
"string": "%[1]d",
"type": "int",
"underlyingType": "int",
"argNum": 1,
"expr": "n"
}
]
},
{
"id": "Use the following code for your discount: {ReferralCode}",
"message": "Use the following code for your discount: {ReferralCode}",
"translation": "Use the following code for your discount: {ReferralCode}",
"translatorComment": "Copied from source.",
"placeholders": [
{
"id": "ReferralCode",
"string": "%[1]d",
"type": "golang.org/x/text/cmd/gotext/examples/extract.referralCode",
"underlyingType": "int",
"argNum": 1,
"expr": "c"
}
],
"fuzzy": true
},
{
"id": [
"msgOutOfOrder",
"{Device} is out of order!"
],
"message": "{Device} is out of order!",
"translation": "{Device} is out of order!",
"comment": "FOO\n",
"placeholders": [
{
"id": "Device",
"string": "%[1]s",
"type": "string",
"underlyingType": "string",
"argNum": 1,
"expr": "device"
}
]
},
{
"id": "{Miles} miles traveled ({Miles_1})",
"message": "{Miles} miles traveled ({Miles_1})",
"translation": "{Miles} miles traveled ({Miles_1})",
"placeholders": [
{
"id": "Miles",
"string": "%.2[1]f",
"type": "float64",
"underlyingType": "float64",
"argNum": 1,
"expr": "miles"
},
{
"id": "Miles_1",
"string": "%[1]f",
"type": "float64",
"underlyingType": "float64",
"argNum": 1,
"expr": "miles"
}
]
}
]
}
+203
View File
@@ -0,0 +1,203 @@
{
"language": "zh",
"messages": [
{
"id": "Hello world!",
"key": "Hello world!\n",
"message": "Hello world!",
"translation": "",
"position": "golang.org/x/text/cmd/gotext/examples/extract/main.go:27:10"
},
{
"id": "Hello {City}!",
"key": "Hello %s!\n",
"message": "Hello {City}!",
"translation": "",
"placeholders": [
{
"id": "City",
"string": "%[1]s",
"type": "string",
"underlyingType": "string",
"argNum": 1,
"expr": "city"
}
],
"position": "golang.org/x/text/cmd/gotext/examples/extract/main.go:31:10"
},
{
"id": "Hello {Town}!",
"key": "Hello %s!\n",
"message": "Hello {Town}!",
"translation": "",
"placeholders": [
{
"id": "Town",
"string": "%[1]s",
"type": "string",
"underlyingType": "string",
"argNum": 1,
"expr": "town",
"comment": "Town"
}
],
"position": "golang.org/x/text/cmd/gotext/examples/extract/main.go:35:10"
},
{
"id": "{Person} is visiting {Place}!",
"key": "%s is visiting %s!\n",
"message": "{Person} is visiting {Place}!",
"translation": "",
"placeholders": [
{
"id": "Person",
"string": "%[1]s",
"type": "string",
"underlyingType": "string",
"argNum": 1,
"expr": "person",
"comment": "The person of matter."
},
{
"id": "Place",
"string": "%[2]s",
"type": "string",
"underlyingType": "string",
"argNum": 2,
"expr": "place",
"comment": "Place the person is visiting."
}
],
"position": "golang.org/x/text/cmd/gotext/examples/extract/main.go:40:10"
},
{
"id": "{Person} is visiting {Place}!",
"key": "%[1]s is visiting %[3]s!\n",
"message": "{Person} is visiting {Place}!",
"translation": "",
"comment": "Person visiting a place.",
"placeholders": [
{
"id": "Person",
"string": "%[1]s",
"type": "string",
"underlyingType": "string",
"argNum": 1,
"expr": "pp.Person"
},
{
"id": "Place",
"string": "%[3]s",
"type": "string",
"underlyingType": "string",
"argNum": 3,
"expr": "pp.Place",
"comment": "Place the person is visiting."
},
{
"id": "Extra",
"string": "%[2]v",
"type": "int",
"underlyingType": "int",
"argNum": 2,
"expr": "pp.extra"
}
],
"position": "golang.org/x/text/cmd/gotext/examples/extract/main.go:55:10"
},
{
"id": "{} files remaining!",
"key": "%d files remaining!",
"message": "{} files remaining!",
"translation": "",
"placeholders": [
{
"id": "",
"string": "%[1]d",
"type": "int",
"underlyingType": "int",
"argNum": 1,
"expr": "2"
}
],
"position": "golang.org/x/text/cmd/gotext/examples/extract/main.go:62:10"
},
{
"id": "{N} more files remaining!",
"key": "%d more files remaining!",
"message": "{N} more files remaining!",
"translation": "",
"placeholders": [
{
"id": "N",
"string": "%[1]d",
"type": "int",
"underlyingType": "int",
"argNum": 1,
"expr": "n"
}
],
"position": "golang.org/x/text/cmd/gotext/examples/extract/main.go:67:10"
},
{
"id": "Use the following code for your discount: {ReferralCode}\n",
"key": "Use the following code for your discount: %d\n",
"message": "Use the following code for your discount: {ReferralCode}\n",
"translation": "",
"placeholders": [
{
"id": "ReferralCode",
"string": "%[1]d",
"type": "golang.org/x/text/cmd/gotext/examples/extract.referralCode",
"underlyingType": "int",
"argNum": 1,
"expr": "c"
}
],
"position": "golang.org/x/text/cmd/gotext/examples/extract/main.go:73:10"
},
{
"id": [ "{Device} is out of order!", "msgOutOfOrder" ],
"key": "%s is out of order!",
"message": "{Device} is out of order!",
"translation": "",
"comment": "FOO\n",
"placeholders": [
{
"id": "Device",
"string": "%[1]s",
"type": "string",
"underlyingType": "string",
"argNum": 1,
"expr": "device"
}
],
"position": "golang.org/x/text/cmd/gotext/examples/extract/main.go:81:10"
},
{
"id": "{Miles} miles traveled ({Miles_1})",
"key": "%.2[1]f miles traveled (%[1]f)",
"message": "{Miles} miles traveled ({Miles_1})",
"translation": "",
"placeholders": [
{
"id": "Miles",
"string": "%.2[1]f",
"type": "float64",
"underlyingType": "float64",
"argNum": 1,
"expr": "miles"
},
{
"id": "Miles_1",
"string": "%[1]f",
"type": "float64",
"underlyingType": "float64",
"argNum": 1,
"expr": "miles"
}
],
"position": "golang.org/x/text/cmd/gotext/examples/extract/main.go:85:10"
}
]
}
+137
View File
@@ -0,0 +1,137 @@
{
"language": "zh",
"messages": [
{
"id": "Hello world!",
"message": "Hello world!",
"translation": ""
},
{
"id": "Hello {City}!",
"message": "Hello {City}!",
"translation": "",
"placeholders": [
{
"id": "City",
"string": "%[1]s",
"type": "string",
"underlyingType": "string",
"argNum": 1,
"expr": "city"
}
]
},
{
"id": "{Person} is visiting {Place}!",
"message": "{Person} is visiting {Place}!",
"translation": "",
"placeholders": [
{
"id": "Person",
"string": "%[1]s",
"type": "string",
"underlyingType": "string",
"argNum": 1,
"expr": "person",
"comment": "The person of matter."
},
{
"id": "Place",
"string": "%[2]s",
"type": "string",
"underlyingType": "string",
"argNum": 2,
"expr": "place",
"comment": "Place the person is visiting."
}
]
},
{
"id": "{2} files remaining!",
"message": "{2} files remaining!",
"translation": "",
"placeholders": [
{
"id": "2",
"string": "%[1]d",
"type": "int",
"underlyingType": "int",
"argNum": 1,
"expr": "2"
}
]
},
{
"id": "{N} more files remaining!",
"message": "{N} more files remaining!",
"translation": "",
"placeholders": [
{
"id": "N",
"string": "%[1]d",
"type": "int",
"underlyingType": "int",
"argNum": 1,
"expr": "n"
}
]
},
{
"id": "Use the following code for your discount: {ReferralCode}",
"message": "Use the following code for your discount: {ReferralCode}",
"translation": "",
"placeholders": [
{
"id": "ReferralCode",
"string": "%[1]d",
"type": "golang.org/x/text/cmd/gotext/examples/extract.referralCode",
"underlyingType": "int",
"argNum": 1,
"expr": "c"
}
]
},
{
"id": [
"msgOutOfOrder",
"{Device} is out of order!"
],
"message": "{Device} is out of order!",
"translation": "",
"comment": "FOO\n",
"placeholders": [
{
"id": "Device",
"string": "%[1]s",
"type": "string",
"underlyingType": "string",
"argNum": 1,
"expr": "device"
}
]
},
{
"id": "{Miles} miles traveled ({Miles_1})",
"message": "{Miles} miles traveled ({Miles_1})",
"translation": "",
"placeholders": [
{
"id": "Miles",
"string": "%.2[1]f",
"type": "float64",
"underlyingType": "float64",
"argNum": 1,
"expr": "miles"
},
{
"id": "Miles_1",
"string": "%[1]f",
"type": "float64",
"underlyingType": "float64",
"argNum": 1,
"expr": "miles"
}
]
}
]
}
+86
View File
@@ -0,0 +1,86 @@
// Copyright 2017 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 main
//go:generate gotext update -out catalog.go
import (
"golang.org/x/text/language"
"golang.org/x/text/message"
)
func main() {
p := message.NewPrinter(language.English)
p.Print("Hello world!\n")
p.Println("Hello", "world!")
person := "Sheila"
place := "Zürich"
p.Print("Hello ", person, " in ", place, "!\n")
// Greet everyone.
p.Printf("Hello world!\n")
city := "Amsterdam"
// Greet a city.
p.Printf("Hello %s!\n", city)
town := "Amsterdam"
// Greet a town.
p.Printf("Hello %s!\n",
town, // Town
)
// Person visiting a place.
p.Printf("%s is visiting %s!\n",
person, // The person of matter.
place, // Place the person is visiting.
)
pp := struct {
Person string // The person of matter. // TODO: get this comment.
Place string
extra int
}{
person, place, 4,
}
// extract will drop this comment in favor of the one below.
// argument is added as a placeholder.
p.Printf("%[1]s is visiting %[3]s!\n", // Person visiting a place.
pp.Person,
pp.extra,
pp.Place, // Place the person is visiting.
)
// Numeric literal
p.Printf("%d files remaining!", 2)
const n = 2
// Numeric var
p.Printf("%d more files remaining!", n)
// Infer better names from type names.
type referralCode int
const c = referralCode(5)
p.Printf("Use the following code for your discount: %d\n", c)
// Using a constant for a message will cause the constant name to be
// added as an identifier, allowing for stable message identifiers.
// Explain that a device is out of order.
const msgOutOfOrder = "%s is out of order!" // FOO
const device = "Soda machine"
p.Printf(msgOutOfOrder, device)
// Double arguments.
miles := 1.2345
p.Printf("%.2[1]f miles traveled (%[1]f)", miles)
}
@@ -0,0 +1,57 @@
// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT.
package main
import (
"golang.org/x/text/language"
"golang.org/x/text/message"
"golang.org/x/text/message/catalog"
)
type dictionary struct {
index []uint32
data string
}
func (d *dictionary) Lookup(key string) (data string, ok bool) {
p := messageKeyToIndex[key]
start, end := d.index[p], d.index[p+1]
if start == end {
return "", false
}
return d.data[start:end], true
}
func init() {
dict := map[string]catalog.Dictionary{
"en": &dictionary{index: enIndex, data: enData},
"zh": &dictionary{index: zhIndex, data: zhData},
}
fallback := language.MustParse("en")
cat, err := catalog.NewFromMap(dict, catalog.Fallback(fallback))
if err != nil {
panic(err)
}
message.DefaultCatalog = cat
}
var messageKeyToIndex = map[string]int{
"Do you like your browser (%s)?\n": 1,
"Hello %s!\n": 0,
}
var enIndex = []uint32{ // 3 elements
0x00000000, 0x00000012, 0x00000039,
} // Size: 36 bytes
const enData string = "" + // Size: 57 bytes
"\x04\x00\x01\x0a\x0d\x02Hello %[1]s!\x04\x00\x01\x0a\x22\x02Do you like " +
"your browser (%[1]s)?"
var zhIndex = []uint32{ // 3 elements
0x00000000, 0x00000000, 0x00000000,
} // Size: 36 bytes
const zhData string = ""
// Total table size 129 bytes (0KiB); checksum: 9C146C82
+39
View File
@@ -0,0 +1,39 @@
{
"language": "de",
"messages": [
{
"id": "Hello {From}!",
"key": "Hello %s!\n",
"message": "Hello {From}!",
"translation": "",
"placeholders": [
{
"id": "From",
"string": "%[1]s",
"type": "string",
"underlyingType": "string",
"argNum": 1,
"expr": "r.Header.Get(\"From\")"
}
],
"position": "golang.org/x/text/cmd/gotext/examples/extract_http/pkg/pkg.go:22:11"
},
{
"id": "Do you like your browser ({User_Agent})?",
"key": "Do you like your browser (%s)?\n",
"message": "Do you like your browser ({User_Agent})?",
"translation": "",
"placeholders": [
{
"id": "User_Agent",
"string": "%[1]s",
"type": "string",
"underlyingType": "string",
"argNum": 1,
"expr": "r.Header.Get(\"User-Agent\")"
}
],
"position": "golang.org/x/text/cmd/gotext/examples/extract_http/pkg/pkg.go:24:11"
}
]
}
@@ -0,0 +1,39 @@
{
"language": "en-US",
"messages": [
{
"id": "Hello {From}!",
"key": "Hello %s!\n",
"message": "Hello {From}!",
"translation": "",
"placeholders": [
{
"id": "From",
"string": "%[1]s",
"type": "string",
"underlyingType": "string",
"argNum": 1,
"expr": "r.Header.Get(\"From\")"
}
],
"position": "golang.org/x/text/cmd/gotext/examples/extract_http/pkg/pkg.go:22:11"
},
{
"id": "Do you like your browser ({User_Agent})?",
"key": "Do you like your browser (%s)?\n",
"message": "Do you like your browser ({User_Agent})?",
"translation": "",
"placeholders": [
{
"id": "User_Agent",
"string": "%[1]s",
"type": "string",
"underlyingType": "string",
"argNum": 1,
"expr": "r.Header.Get(\"User-Agent\")"
}
],
"position": "golang.org/x/text/cmd/gotext/examples/extract_http/pkg/pkg.go:24:11"
}
]
}
@@ -0,0 +1,39 @@
{
"language": "en",
"messages": [
{
"id": "Hello {From}!",
"message": "Hello {From}!",
"translation": "Hello {From}!",
"translatorComment": "Copied from source.",
"placeholders": [
{
"id": "From",
"string": "%[1]s",
"type": "string",
"underlyingType": "string",
"argNum": 1,
"expr": "r.Header.Get(\"From\")"
}
],
"fuzzy": true
},
{
"id": "Do you like your browser ({User_Agent})?",
"message": "Do you like your browser ({User_Agent})?",
"translation": "Do you like your browser ({User_Agent})?",
"translatorComment": "Copied from source.",
"placeholders": [
{
"id": "User_Agent",
"string": "%[1]s",
"type": "string",
"underlyingType": "string",
"argNum": 1,
"expr": "r.Header.Get(\"User-Agent\")"
}
],
"fuzzy": true
}
]
}
+35
View File
@@ -0,0 +1,35 @@
{
"language": "zh",
"messages": [
{
"id": "Hello {From}!",
"message": "Hello {From}!",
"translation": "",
"placeholders": [
{
"id": "From",
"string": "%[1]s",
"type": "string",
"underlyingType": "string",
"argNum": 1,
"expr": "r.Header.Get(\"From\")"
}
]
},
{
"id": "Do you like your browser ({User_Agent})?",
"message": "Do you like your browser ({User_Agent})?",
"translation": "",
"placeholders": [
{
"id": "User_Agent",
"string": "%[1]s",
"type": "string",
"underlyingType": "string",
"argNum": 1,
"expr": "r.Header.Get(\"User-Agent\")"
}
]
}
]
}
+17
View File
@@ -0,0 +1,17 @@
// Copyright 2017 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 main
//go:generate gotext -srclang=en update -out=catalog_gen.go -lang=en,zh
import (
"net/http"
"golang.org/x/text/cmd/gotext/examples/extract_http/pkg"
)
func main() {
http.Handle("/generize", http.HandlerFunc(pkg.Generize))
}
+25
View File
@@ -0,0 +1,25 @@
// Copyright 2017 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 pkg
import (
"net/http"
"golang.org/x/text/language"
"golang.org/x/text/message"
)
var matcher = language.NewMatcher(message.DefaultCatalog.Languages())
func Generize(w http.ResponseWriter, r *http.Request) {
lang, _ := r.Cookie("lang")
accept := r.Header.Get("Accept-Language")
tag := message.MatchLanguage(lang.String(), accept)
p := message.NewPrinter(tag)
p.Fprintf(w, "Hello %s!\n", r.Header.Get("From"))
p.Fprintf(w, "Do you like your browser (%s)?\n", r.Header.Get("User-Agent"))
}
+37
View File
@@ -0,0 +1,37 @@
// Copyright 2017 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 main
import (
"fmt"
"golang.org/x/text/language"
"golang.org/x/text/message"
)
func main() {
var nPizzas = 4
// The following call gets replaced by a call to the globally
// defined printer.
fmt.Println("We ate", nPizzas, "pizzas.")
p := message.NewPrinter(language.English)
// Prevent build failure, although it is okay for gotext.
p.Println(1024)
// Replaced by a call to p.
fmt.Println("Example punctuation:", "$%^&!")
{
q := message.NewPrinter(language.French)
const leaveAnIdentBe = "Don't expand me."
fmt.Print(leaveAnIdentBe)
q.Println() // Prevent build failure, although it is okay for gotext.
}
fmt.Printf("Hello %s\n", "City")
}
+16
View File
@@ -0,0 +1,16 @@
// Copyright 2017 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.
// +build ignore
package main
import (
"golang.org/x/text/language"
"golang.org/x/text/message"
)
// The printer defined here will be picked up by the first print statement
// in main.go.
var printer = message.NewPrinter(language.English)
+15 -170
View File
@@ -5,22 +5,7 @@
package main
import (
"bytes"
"encoding/json"
"fmt"
"go/ast"
"go/build"
"go/constant"
"go/format"
"go/parser"
"go/types"
"io/ioutil"
"os"
"path"
"path/filepath"
"strings"
"golang.org/x/tools/go/loader"
"golang.org/x/text/message/pipeline"
)
// TODO:
@@ -29,167 +14,27 @@ import (
// - handle features (gender, plural)
// - message rewriting
func init() {
lang = cmdExtract.Flag.String("lang", "en-US", "comma-separated list of languages to process")
}
var cmdExtract = &Command{
Run: runExtract,
UsageLine: "extract <package>*",
Short: "extract strings to be translated from code",
Short: "extracts strings to be translated from code",
}
func runExtract(cmd *Command, args []string) error {
if len(args) == 0 {
args = []string{"."}
}
conf := loader.Config{
Build: &build.Default,
ParserMode: parser.ParseComments,
}
// Use the initial packages from the command line.
args, err := conf.FromArgs(args, false)
func runExtract(cmd *Command, config *pipeline.Config, args []string) error {
config.Packages = args
state, err := pipeline.Extract(config)
if err != nil {
return err
return wrap(err, "extract failed")
}
// Load, parse and type-check the whole program.
iprog, err := conf.Load()
if err != nil {
return err
if err := state.Import(); err != nil {
return wrap(err, "import failed")
}
// print returns Go syntax for the specified node.
print := func(n ast.Node) string {
var buf bytes.Buffer
format.Node(&buf, conf.Fset, n)
return buf.String()
if err := state.Merge(); err != nil {
return wrap(err, "merge failed")
}
var translations []Translation
for _, info := range iprog.InitialPackages() {
for _, f := range info.Files {
// Associate comments with nodes.
cmap := ast.NewCommentMap(iprog.Fset, f, f.Comments)
getComment := func(n ast.Node) string {
cs := cmap.Filter(n).Comments()
if len(cs) > 0 {
return strings.TrimSpace(cs[0].Text())
}
return ""
}
// Find function calls.
ast.Inspect(f, func(n ast.Node) bool {
call, ok := n.(*ast.CallExpr)
if !ok {
return true
}
// Skip calls of functions other than
// (*message.Printer).{Sp,Fp,P}rintf.
sel, ok := call.Fun.(*ast.SelectorExpr)
if !ok {
return true
}
meth := info.Selections[sel]
if meth == nil || meth.Kind() != types.MethodVal {
return true
}
// TODO: remove cheap hack and check if the type either
// implements some interface or is specifically of type
// "golang.org/x/text/message".Printer.
m, ok := extractFuncs[path.Base(meth.Recv().String())]
if !ok {
return true
}
// argn is the index of the format string.
argn, ok := m[meth.Obj().Name()]
if !ok || argn >= len(call.Args) {
return true
}
// Skip calls with non-constant format string.
fmtstr := info.Types[call.Args[argn]].Value
if fmtstr == nil || fmtstr.Kind() != constant.String {
return true
}
posn := conf.Fset.Position(call.Lparen)
filepos := fmt.Sprintf("%s:%d:%d", filepath.Base(posn.Filename), posn.Line, posn.Column)
// TODO: identify the type of the format argument. If it is not
// a string, multiple keys may be defined.
var key []string
// TODO: replace substitutions (%v) with a translator friendly
// notation. For instance:
// "%d files remaining" -> "{numFiles} files remaining", or
// "%d files remaining" -> "{arg1} files remaining"
// Alternatively, this could be done at a later stage.
msg := constant.StringVal(fmtstr)
// Construct a Translation unit.
c := Translation{
Key: key,
Position: filepath.Join(info.Pkg.Path(), filepos),
Original: Text{Msg: msg},
ExtractedComment: getComment(call.Args[0]),
// TODO(fix): this doesn't get the before comment.
// Comment: getComment(call),
}
for i, arg := range call.Args[argn+1:] {
var val string
if v := info.Types[arg].Value; v != nil {
val = v.ExactString()
}
posn := conf.Fset.Position(arg.Pos())
filepos := fmt.Sprintf("%s:%d:%d", filepath.Base(posn.Filename), posn.Line, posn.Column)
c.Args = append(c.Args, Argument{
ID: i + 1,
Type: info.Types[arg].Type.String(),
UnderlyingType: info.Types[arg].Type.Underlying().String(),
Expr: print(arg),
Value: val,
Comment: getComment(arg),
Position: filepath.Join(info.Pkg.Path(), filepos),
// TODO report whether it implements
// interfaces plural.Interface,
// gender.Interface.
})
}
translations = append(translations, c)
return true
})
}
}
data, err := json.MarshalIndent(translations, "", " ")
if err != nil {
return err
}
for _, tag := range getLangs() {
// TODO: merge with existing files, don't overwrite.
os.MkdirAll(*dir, 0744)
file := filepath.Join(*dir, fmt.Sprintf("gotext_%v.out.json", tag))
if err := ioutil.WriteFile(file, data, 0744); err != nil {
return fmt.Errorf("could not create file: %v", err)
}
}
return nil
}
// extractFuncs indicates the types and methods for which to extract strings,
// and which argument to extract.
// TODO: use the types in conf.Import("golang.org/x/text/message") to extract
// the correct instances.
var extractFuncs = map[string]map[string]int{
// TODO: Printer -> *golang.org/x/text/message.Printer
"message.Printer": {
"Printf": 0,
"Sprintf": 0,
"Fprintf": 1,
},
return wrap(state.Export(), "export failed")
}
+31
View File
@@ -0,0 +1,31 @@
// Copyright 2017 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 main
import (
"golang.org/x/text/message/pipeline"
)
func init() {
out = cmdGenerate.Flag.String("out", "", "output file to write to")
}
var cmdGenerate = &Command{
Run: runGenerate,
UsageLine: "generate <package>",
Short: "generates code to insert translated messages",
}
func runGenerate(cmd *Command, config *pipeline.Config, args []string) error {
config.Packages = args
s, err := pipeline.Extract(config)
if err != nil {
return wrap(err, "extraction failed")
}
if err := s.Import(); err != nil {
return wrap(err, "import failed")
}
return wrap(s.Generate(), "generation failed")
}
+36 -17
View File
@@ -25,6 +25,8 @@ import (
"unicode"
"unicode/utf8"
"golang.org/x/text/message/pipeline"
"golang.org/x/text/language"
"golang.org/x/tools/go/buildutil"
)
@@ -34,10 +36,23 @@ func init() {
}
var (
dir = flag.String("dir", "textdata", "default subdirectory to store translation files")
langs = flag.String("lang", "en", "comma-separated list of languages to process")
srcLang = flag.String("srclang", "en-US", "the source-code language")
dir = flag.String("dir", "locales", "default subdirectory to store translation files")
)
func config() (*pipeline.Config, error) {
tag, err := language.Parse(*srcLang)
if err != nil {
return nil, wrap(err, "invalid srclang")
}
return &pipeline.Config{
SourceLanguage: tag,
Supported: getLangs(),
TranslationsPattern: `messages\.(.*)\.json`,
GenFile: *out,
}, nil
}
// NOTE: the Command struct is copied from the go tool in core.
// A Command is an implementation of a go command
@@ -45,7 +60,7 @@ var (
type Command struct {
// Run runs the command.
// The args are the arguments after the command name.
Run func(cmd *Command, args []string) error
Run func(cmd *Command, c *pipeline.Config, args []string) error
// UsageLine is the one-line usage message.
// The first word in the line is taken to be the command name.
@@ -86,9 +101,11 @@ func (c *Command) Runnable() bool {
// Commands lists the available commands and help topics.
// The order here is the order in which they are printed by 'go help'.
var commands = []*Command{
cmdUpdate,
cmdExtract,
cmdRewrite,
cmdGenerate,
// TODO:
// - generate code from translations.
// - update: full-cycle update of extraction, sending, and integration
// - report: report of freshness of translations
}
@@ -126,8 +143,12 @@ func main() {
cmd.Flag.Usage = func() { cmd.Usage() }
cmd.Flag.Parse(args[1:])
args = cmd.Flag.Args()
if err := cmd.Run(cmd, args); err != nil {
fatalf("gotext: %v", err)
config, err := config()
if err != nil {
fatalf("gotext: %+v", err)
}
if err := cmd.Run(cmd, config, args); err != nil {
fatalf("gotext: %+v", err)
}
exit()
return
@@ -277,12 +298,7 @@ func help(args []string) {
if strings.HasSuffix(arg, "documentation") {
w := &bytes.Buffer{}
fmt.Fprintln(w, "// Copyright 2016 The Go Authors. All rights reserved.")
fmt.Fprintln(w, "// Use of this source code is governed by a BSD-style")
fmt.Fprintln(w, "// license that can be found in the LICENSE file.")
fmt.Fprintln(w)
fmt.Fprintln(w, "// DO NOT EDIT THIS FILE. GENERATED BY go generate.")
fmt.Fprintln(w, "// Edit the documentation in other files and rerun go generate to generate this one.")
fmt.Fprintln(w, "// Code generated by go generate. DO NOT EDIT.")
fmt.Fprintln(w)
buf := new(bytes.Buffer)
printUsage(buf)
@@ -292,10 +308,10 @@ func help(args []string) {
if arg == "gendocumentation" {
b, err := format.Source(w.Bytes())
if err != nil {
errorf("Could not format generated docs: %v\n", err)
logf("Could not format generated docs: %v\n", err)
}
if err := ioutil.WriteFile("doc.go", b, 0666); err != nil {
errorf("Could not create file alldocs.go: %v\n", err)
logf("Could not create file alldocs.go: %v\n", err)
}
} else {
fmt.Println(w.String())
@@ -316,7 +332,10 @@ func help(args []string) {
}
func getLangs() (tags []language.Tag) {
for _, t := range strings.Split(*langs, ",") {
for _, t := range strings.Split(*lang, ",") {
if t == "" {
continue
}
tag, err := language.Parse(t)
if err != nil {
fatalf("gotext: could not parse language %q: %v", t, err)
@@ -340,11 +359,11 @@ func exit() {
}
func fatalf(format string, args ...interface{}) {
errorf(format, args...)
logf(format, args...)
exit()
}
func errorf(format string, args ...interface{}) {
func logf(format string, args ...interface{}) {
log.Printf(format, args...)
setExitStatus(1)
}
-127
View File
@@ -1,127 +0,0 @@
// Copyright 2016 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 main
// TODO: these definitions should be moved to a package so that the can be used
// by other tools.
// The file contains the structures used to define translations of a certain
// messages.
//
// A translation may have multiple translations strings, or messages, depending
// on the feature values of the various arguments. For instance, consider
// a hypothetical translation from English to English, where the source defines
// the format string "%d file(s) remaining". A completed translation, expressed
// in JS, for this format string could look like:
//
// {
// "Key": [
// "\"%d files(s) remaining\""
// ],
// "Original": {
// "Msg": "\"%d files(s) remaining\""
// },
// "Translation": {
// "Select": {
// "Feature": "plural",
// "Arg": 1,
// "Case": {
// "one": { "Msg": "1 file remaining" },
// "other": { "Msg": "%d files remaining" }
// },
// },
// },
// "Args": [
// {
// "ID": 2,
// "Type": "int",
// "UnderlyingType": "int",
// "Expr": "nFiles",
// "Comment": "number of files remaining",
// "Position": "golang.org/x/text/cmd/gotext/demo.go:34:3"
// }
// ],
// "Position": "golang.org/x/text/cmd/gotext/demo.go:33:10",
// }
//
// Alternatively, the Translation section could be written as:
//
// "Translation": {
// "Msg": "%d %[files]s remaining",
// "Var": {
// "files" : {
// "Select": {
// "Feature": "plural",
// "Arg": 1,
// "Case": {
// "one": { "Msg": "file" },
// "other": { "Msg": "files" }
// }
// }
// }
// }
// }
// A Translation describes a translation for a single language for a single
// message.
type Translation struct {
// Key contains a list of identifiers for the message. If this list is empty
// Original is used as the key.
Key []string `json:"key,omitempty"`
Original Text `json:"original"`
Translation Text `json:"translation"`
ExtractedComment string `json:"extractedComment,omitempty"`
TranslatorComment string `json:"translatorComment,omitempty"`
Args []Argument `json:"args,omitempty"`
// Extraction information.
Position string `json:"position,omitempty"` // filePosition:line
}
// An Argument contains information about the arguments passed to a message.
type Argument struct {
ID interface{} `json:"id"` // An int for printf-style calls, but could be a string.
Type string `json:"type"`
UnderlyingType string `json:"underlyingType"`
Expr string `json:"expr"`
Value string `json:"value,omitempty"`
Comment string `json:"comment,omitempty"`
Position string `json:"position,omitempty"`
// Features contains the features that are available for the implementation
// of this argument.
Features []Feature `json:"features,omitempty"`
}
// Feature holds information about a feature that can be implemented by
// an Argument.
type Feature struct {
Type string `json:"type"` // Right now this is only gender and plural.
// TODO: possible values and examples for the language under consideration.
}
// Text defines a message to be displayed.
type Text struct {
// Msg and Select contains the message to be displayed. Within a Text value
// either Msg or Select is defined.
Msg string `json:"msg,omitempty"`
Select *Select `json:"select,omitempty"`
// Var defines a map of variables that may be substituted in the selected
// message.
Var map[string]Text `json:"var,omitempty"`
// Example contains an example message formatted with default values.
Example string `json:"example,omitempty"`
}
// Type Select selects a Text based on the feature value associated with
// a feature of a certain argument.
type Select struct {
Feature string `json:"feature"` // Name of variable or Feature type
Arg interface{} `json:"arg"` // The argument ID.
Cases map[string]Text `json:"cases"`
}
+55
View File
@@ -0,0 +1,55 @@
// Copyright 2017 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 main
import (
"os"
"golang.org/x/text/message/pipeline"
)
const printerType = "golang.org/x/text/message.Printer"
// TODO:
// - merge information into existing files
// - handle different file formats (PO, XLIFF)
// - handle features (gender, plural)
// - message rewriting
func init() {
overwrite = cmdRewrite.Flag.Bool("w", false, "write files in place")
}
var (
overwrite *bool
)
var cmdRewrite = &Command{
Run: runRewrite,
UsageLine: "rewrite <package>",
Short: "rewrites fmt functions to use a message Printer",
Long: `
rewrite is typically done once for a project. It rewrites all usages of
fmt to use x/text's message package whenever a message.Printer is in scope.
It rewrites Print and Println calls with constant strings to the equivalent
using Printf to allow translators to reorder arguments.
`,
}
func runRewrite(cmd *Command, _ *pipeline.Config, args []string) error {
w := os.Stdout
if *overwrite {
w = nil
}
pkg := "."
switch len(args) {
case 0:
case 1:
pkg = args[0]
default:
return errorf("can only specify at most one package")
}
return pipeline.Rewrite(w, pkg)
}
+52
View File
@@ -0,0 +1,52 @@
// Copyright 2016 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 main
import (
"golang.org/x/text/message/pipeline"
)
// TODO:
// - merge information into existing files
// - handle different file formats (PO, XLIFF)
// - handle features (gender, plural)
// - message rewriting
var (
lang *string
out *string
)
func init() {
lang = cmdUpdate.Flag.String("lang", "en-US", "comma-separated list of languages to process")
out = cmdUpdate.Flag.String("out", "", "output file to write to")
}
var cmdUpdate = &Command{
Run: runUpdate,
UsageLine: "update <package>* [-out <gofile>]",
Short: "merge translations and generate catalog",
}
func runUpdate(cmd *Command, config *pipeline.Config, args []string) error {
config.Packages = args
state, err := pipeline.Extract(config)
if err != nil {
return wrap(err, "extract failed")
}
if err := state.Import(); err != nil {
return wrap(err, "import failed")
}
if err := state.Merge(); err != nil {
return wrap(err, "merge failed")
}
if err := state.Export(); err != nil {
return wrap(err, "export failed")
}
if *out != "" {
return wrap(state.Generate(), "generation failed")
}
return nil
}
+10 -10
View File
@@ -39,13 +39,13 @@ type osxCollator struct {
func (c *osxCollator) init(locale string) {
l := C.CFStringCreateWithBytes(
nil,
C.kCFAllocatorDefault,
osxUInt8P([]byte(locale)),
C.CFIndex(len(locale)),
C.kCFStringEncodingUTF8,
C.Boolean(0),
)
c.loc = C.CFLocaleCreate(nil, l)
c.loc = C.CFLocaleCreate(C.kCFAllocatorDefault, l)
}
func newOSX8Collator(locale string) (Collator, error) {
@@ -74,16 +74,16 @@ type osx16Collator struct {
func (c osx16Collator) Compare(a, b Input) int {
sa := C.CFStringCreateWithCharactersNoCopy(
nil,
C.kCFAllocatorDefault,
osxCharP(a.UTF16),
C.CFIndex(len(a.UTF16)),
nil,
C.kCFAllocatorDefault,
)
sb := C.CFStringCreateWithCharactersNoCopy(
nil,
C.kCFAllocatorDefault,
osxCharP(b.UTF16),
C.CFIndex(len(b.UTF16)),
nil,
C.kCFAllocatorDefault,
)
_range := C.CFRangeMake(0, C.CFStringGetLength(sa))
return int(C.CFStringCompareWithOptionsAndLocale(sa, sb, _range, c.opt, c.loc))
@@ -91,20 +91,20 @@ func (c osx16Collator) Compare(a, b Input) int {
func (c osx8Collator) Compare(a, b Input) int {
sa := C.CFStringCreateWithBytesNoCopy(
nil,
C.kCFAllocatorDefault,
osxUInt8P(a.UTF8),
C.CFIndex(len(a.UTF8)),
C.kCFStringEncodingUTF8,
C.Boolean(0),
nil,
C.kCFAllocatorDefault,
)
sb := C.CFStringCreateWithBytesNoCopy(
nil,
C.kCFAllocatorDefault,
osxUInt8P(b.UTF8),
C.CFIndex(len(b.UTF8)),
C.kCFStringEncodingUTF8,
C.Boolean(0),
nil,
C.kCFAllocatorDefault,
)
_range := C.CFRangeMake(0, C.CFStringGetLength(sa))
return int(C.CFStringCompareWithOptionsAndLocale(sa, sb, _range, c.opt, c.loc))
+1
View File
@@ -38,6 +38,7 @@ var roundings = [...]roundingType{
{3, 1},
{4, 1},
{2, 5}, // cash rounding alternative
{2, 50},
}
// regionToCode returns a 16-bit region code. Only two-letter codes are
+2 -2
View File
@@ -105,10 +105,10 @@ func TestTable(t *testing.T) {
}
// First currency has index 1, last is numCurrencies.
if c := currency.Elem(1)[:3]; c != "ADP" {
t.Errorf("first was %c; want ADP", c)
t.Errorf("first was %q; want ADP", c)
}
if c := currency.Elem(numCurrencies)[:3]; c != "ZWR" {
t.Errorf("last was %c; want ZWR", c)
t.Errorf("last was %q; want ZWR", c)
}
}
+2 -2
View File
@@ -16,12 +16,12 @@ func ExampleQuery() {
for it := currency.Query(currency.Date(t1799)); it.Next(); {
from := ""
if t, ok := it.From(); ok {
from = t.Format("2006-01-01")
from = t.Format("2006-01-02")
}
fmt.Printf("%v is used in %v since: %v\n", it.Unit(), it.Region(), from)
}
// Output:
// GBP is used in GB since: 1694-07-07
// GBP is used in GB since: 1694-07-27
// GIP is used in GI since: 1713-01-01
// USD is used in US since: 1792-01-01
}
+1
View File
@@ -42,6 +42,7 @@ var roundings = [...]roundingType{
{3, 1},
{4, 1},
{2, 5}, // cash rounding alternative
{2, 50},
}
// regionToCode returns a 16-bit region code. Only two-letter codes are
+2392 -2337
View File
File diff suppressed because it is too large Load Diff
+335
View File
@@ -0,0 +1,335 @@
// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT.
package date
var enumMap = map[string]uint16{
"": 0,
"calendars": 0,
"fields": 1,
"timeZoneNames": 2,
"buddhist": 0,
"chinese": 1,
"coptic": 2,
"dangi": 3,
"ethiopic": 4,
"ethiopic-amete-alem": 5,
"generic": 6,
"gregorian": 7,
"hebrew": 8,
"indian": 9,
"islamic": 10,
"islamic-civil": 11,
"islamic-rgsa": 12,
"islamic-tbla": 13,
"islamic-umalqura": 14,
"japanese": 15,
"persian": 16,
"roc": 17,
"months": 0,
"days": 1,
"quarters": 2,
"dayPeriods": 3,
"eras": 4,
"dateFormats": 5,
"timeFormats": 6,
"dateTimeFormats": 7,
"monthPatterns": 8,
"cyclicNameSets": 9,
"format": 0,
"stand-alone": 1,
"numeric": 2,
"widthAbbreviated": 0,
"widthNarrow": 1,
"widthWide": 2,
"widthAll": 3,
"widthShort": 4,
"leap7": 0,
"sun": 0,
"mon": 1,
"tue": 2,
"wed": 3,
"thu": 4,
"fri": 5,
"sat": 6,
"am": 0,
"pm": 1,
"midnight": 2,
"morning1": 3,
"afternoon1": 4,
"evening1": 5,
"night1": 6,
"noon": 7,
"morning2": 8,
"afternoon2": 9,
"night2": 10,
"evening2": 11,
"variant": 1,
"short": 0,
"long": 1,
"full": 2,
"medium": 3,
"dayPartsCycleType": 0,
"daysCycleType": 1,
"monthsCycleType": 2,
"solarTermsCycleType": 3,
"yearsCycleType": 4,
"zodiacsCycleType": 5,
"eraField": 0,
"era-shortField": 1,
"era-narrowField": 2,
"yearField": 3,
"year-shortField": 4,
"year-narrowField": 5,
"quarterField": 6,
"quarter-shortField": 7,
"quarter-narrowField": 8,
"monthField": 9,
"month-shortField": 10,
"month-narrowField": 11,
"weekField": 12,
"week-shortField": 13,
"week-narrowField": 14,
"weekOfMonthField": 15,
"weekOfMonth-shortField": 16,
"weekOfMonth-narrowField": 17,
"dayField": 18,
"day-shortField": 19,
"day-narrowField": 20,
"dayOfYearField": 21,
"dayOfYear-shortField": 22,
"dayOfYear-narrowField": 23,
"weekdayField": 24,
"weekday-shortField": 25,
"weekday-narrowField": 26,
"weekdayOfMonthField": 27,
"weekdayOfMonth-shortField": 28,
"weekdayOfMonth-narrowField": 29,
"sunField": 30,
"sun-shortField": 31,
"sun-narrowField": 32,
"monField": 33,
"mon-shortField": 34,
"mon-narrowField": 35,
"tueField": 36,
"tue-shortField": 37,
"tue-narrowField": 38,
"wedField": 39,
"wed-shortField": 40,
"wed-narrowField": 41,
"thuField": 42,
"thu-shortField": 43,
"thu-narrowField": 44,
"friField": 45,
"fri-shortField": 46,
"fri-narrowField": 47,
"satField": 48,
"sat-shortField": 49,
"sat-narrowField": 50,
"dayperiod-shortField": 51,
"dayperiodField": 52,
"dayperiod-narrowField": 53,
"hourField": 54,
"hour-shortField": 55,
"hour-narrowField": 56,
"minuteField": 57,
"minute-shortField": 58,
"minute-narrowField": 59,
"secondField": 60,
"second-shortField": 61,
"second-narrowField": 62,
"zoneField": 63,
"zone-shortField": 64,
"zone-narrowField": 65,
"displayName": 0,
"relative": 1,
"relativeTime": 2,
"relativePeriod": 3,
"before1": 0,
"current": 1,
"after1": 2,
"before2": 3,
"after2": 4,
"after3": 5,
"future": 0,
"past": 1,
"other": 0,
"one": 1,
"zero": 2,
"two": 3,
"few": 4,
"many": 5,
"zoneFormat": 0,
"regionFormat": 1,
"zone": 2,
"metaZone": 3,
"hourFormat": 0,
"gmtFormat": 1,
"gmtZeroFormat": 2,
"genericTime": 0,
"daylightTime": 1,
"standardTime": 2,
"Etc/UTC": 0,
"Europe/London": 1,
"Europe/Dublin": 2,
"Pacific/Honolulu": 3,
"Afghanistan": 0,
"Africa_Central": 1,
"Africa_Eastern": 2,
"Africa_Southern": 3,
"Africa_Western": 4,
"Alaska": 5,
"Amazon": 6,
"America_Central": 7,
"America_Eastern": 8,
"America_Mountain": 9,
"America_Pacific": 10,
"Anadyr": 11,
"Apia": 12,
"Arabian": 13,
"Argentina": 14,
"Argentina_Western": 15,
"Armenia": 16,
"Atlantic": 17,
"Australia_Central": 18,
"Australia_CentralWestern": 19,
"Australia_Eastern": 20,
"Australia_Western": 21,
"Azerbaijan": 22,
"Azores": 23,
"Bangladesh": 24,
"Bhutan": 25,
"Bolivia": 26,
"Brasilia": 27,
"Brunei": 28,
"Cape_Verde": 29,
"Chamorro": 30,
"Chatham": 31,
"Chile": 32,
"China": 33,
"Choibalsan": 34,
"Christmas": 35,
"Cocos": 36,
"Colombia": 37,
"Cook": 38,
"Cuba": 39,
"Davis": 40,
"DumontDUrville": 41,
"East_Timor": 42,
"Easter": 43,
"Ecuador": 44,
"Europe_Central": 45,
"Europe_Eastern": 46,
"Europe_Further_Eastern": 47,
"Europe_Western": 48,
"Falkland": 49,
"Fiji": 50,
"French_Guiana": 51,
"French_Southern": 52,
"Galapagos": 53,
"Gambier": 54,
"Georgia": 55,
"Gilbert_Islands": 56,
"GMT": 57,
"Greenland_Eastern": 58,
"Greenland_Western": 59,
"Gulf": 60,
"Guyana": 61,
"Hawaii_Aleutian": 62,
"Hong_Kong": 63,
"Hovd": 64,
"India": 65,
"Indian_Ocean": 66,
"Indochina": 67,
"Indonesia_Central": 68,
"Indonesia_Eastern": 69,
"Indonesia_Western": 70,
"Iran": 71,
"Irkutsk": 72,
"Israel": 73,
"Japan": 74,
"Kamchatka": 75,
"Kazakhstan_Eastern": 76,
"Kazakhstan_Western": 77,
"Korea": 78,
"Kosrae": 79,
"Krasnoyarsk": 80,
"Kyrgystan": 81,
"Line_Islands": 82,
"Lord_Howe": 83,
"Macquarie": 84,
"Magadan": 85,
"Malaysia": 86,
"Maldives": 87,
"Marquesas": 88,
"Marshall_Islands": 89,
"Mauritius": 90,
"Mawson": 91,
"Mexico_Northwest": 92,
"Mexico_Pacific": 93,
"Mongolia": 94,
"Moscow": 95,
"Myanmar": 96,
"Nauru": 97,
"Nepal": 98,
"New_Caledonia": 99,
"New_Zealand": 100,
"Newfoundland": 101,
"Niue": 102,
"Norfolk": 103,
"Noronha": 104,
"Novosibirsk": 105,
"Omsk": 106,
"Pakistan": 107,
"Palau": 108,
"Papua_New_Guinea": 109,
"Paraguay": 110,
"Peru": 111,
"Philippines": 112,
"Phoenix_Islands": 113,
"Pierre_Miquelon": 114,
"Pitcairn": 115,
"Ponape": 116,
"Pyongyang": 117,
"Reunion": 118,
"Rothera": 119,
"Sakhalin": 120,
"Samara": 121,
"Samoa": 122,
"Seychelles": 123,
"Singapore": 124,
"Solomon": 125,
"South_Georgia": 126,
"Suriname": 127,
"Syowa": 128,
"Tahiti": 129,
"Taipei": 130,
"Tajikistan": 131,
"Tokelau": 132,
"Tonga": 133,
"Truk": 134,
"Turkmenistan": 135,
"Tuvalu": 136,
"Uruguay": 137,
"Uzbekistan": 138,
"Vanuatu": 139,
"Venezuela": 140,
"Vladivostok": 141,
"Volgograd": 142,
"Vostok": 143,
"Wake": 144,
"Wallis": 145,
"Yakutsk": 146,
"Yekaterinburg": 147,
"Guam": 148,
"North_Mariana": 149,
"Acre": 150,
"Almaty": 151,
"Aqtau": 152,
"Aqtobe": 153,
"Casey": 154,
"Lanka": 155,
"Macau": 156,
"Qyzylorda": 157,
}
// Total table size 0 bytes (0KiB); checksum: 811C9DC5
+329
View File
@@ -0,0 +1,329 @@
// Copyright 2017 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.
// +build ignore
package main
import (
"flag"
"log"
"strconv"
"strings"
"golang.org/x/text/internal/cldrtree"
"golang.org/x/text/internal/gen"
"golang.org/x/text/language"
"golang.org/x/text/unicode/cldr"
)
var (
draft = flag.String("draft",
"contributed",
`Minimal draft requirements (approved, contributed, provisional, unconfirmed).`)
)
// TODO:
// - Compile format patterns.
// - Compress the large amount of redundancy in metazones.
// - Split trees (with shared buckets) with data that is enough for default
// formatting of Go Time values and and tables that are needed for larger
// variants.
// - zone to metaZone mappings (in supplemental)
// - Add more enum values and also some key maps for some of the elements.
func main() {
gen.Init()
r := gen.OpenCLDRCoreZip()
defer r.Close()
d := &cldr.Decoder{}
d.SetDirFilter("supplemental", "main")
d.SetSectionFilter("dates")
data, err := d.DecodeZip(r)
if err != nil {
log.Fatalf("DecodeZip: %v", err)
}
dates := cldrtree.New("dates")
buildCLDRTree(data, dates)
w := gen.NewCodeWriter()
if err := dates.Gen(w); err != nil {
log.Fatal(err)
}
gen.WriteCLDRVersion(w)
w.WriteGoFile("tables.go", "date")
w = gen.NewCodeWriter()
if err := dates.GenTestData(w); err != nil {
log.Fatal(err)
}
w.WriteGoFile("data_test.go", "date")
}
func buildCLDRTree(data *cldr.CLDR, dates *cldrtree.Builder) {
context := cldrtree.Enum("context")
widthMap := func(s string) string {
// Align era with width values.
if r, ok := map[string]string{
"eraAbbr": "abbreviated",
"eraNarrow": "narrow",
"eraNames": "wide",
}[s]; ok {
s = r
}
// Prefix width to disambiguate with some overlapping length values.
return "width" + strings.Title(s)
}
width := cldrtree.EnumFunc("width", widthMap, "abbreviated", "narrow", "wide")
length := cldrtree.Enum("length", "short", "long")
month := cldrtree.Enum("month", "leap7")
relTime := cldrtree.EnumFunc("relTime", func(s string) string {
x, err := strconv.ParseInt(s, 10, 8)
if err != nil {
log.Fatal("Invalid number:", err)
}
return []string{
"before2",
"before1",
"current",
"after1",
"after2",
"after3",
}[x+2]
})
// Disambiguate keys like 'months' and 'sun'.
cycleType := cldrtree.EnumFunc("cycleType", func(s string) string {
return s + "CycleType"
})
field := cldrtree.EnumFunc("field", func(s string) string {
return s + "Field"
})
timeType := cldrtree.EnumFunc("timeType", func(s string) string {
if s == "" {
return "genericTime"
}
return s + "Time"
}, "generic")
zoneType := []cldrtree.Option{cldrtree.SharedType(), timeType}
metaZoneType := []cldrtree.Option{cldrtree.SharedType(), timeType}
for _, lang := range data.Locales() {
tag := language.Make(lang)
ldml := data.RawLDML(lang)
if ldml.Dates == nil {
continue
}
x := dates.Locale(tag)
if x := x.Index(ldml.Dates.Calendars); x != nil {
for _, cal := range ldml.Dates.Calendars.Calendar {
x := x.IndexFromType(cal)
if x := x.Index(cal.Months); x != nil {
for _, mc := range cal.Months.MonthContext {
x := x.IndexFromType(mc, context)
for _, mw := range mc.MonthWidth {
x := x.IndexFromType(mw, width)
for _, m := range mw.Month {
x.SetValue(m.Yeartype+m.Type, m, month)
}
}
}
}
if x := x.Index(cal.MonthPatterns); x != nil {
for _, mc := range cal.MonthPatterns.MonthPatternContext {
x := x.IndexFromType(mc, context)
for _, mw := range mc.MonthPatternWidth {
// Value is always leap, so no need to create a
// subindex.
for _, m := range mw.MonthPattern {
x.SetValue(mw.Type, m, width)
}
}
}
}
if x := x.Index(cal.CyclicNameSets); x != nil {
for _, cns := range cal.CyclicNameSets.CyclicNameSet {
x := x.IndexFromType(cns, cycleType)
for _, cc := range cns.CyclicNameContext {
x := x.IndexFromType(cc, context)
for _, cw := range cc.CyclicNameWidth {
x := x.IndexFromType(cw, width)
for _, c := range cw.CyclicName {
x.SetValue(c.Type, c)
}
}
}
}
}
if x := x.Index(cal.Days); x != nil {
for _, dc := range cal.Days.DayContext {
x := x.IndexFromType(dc, context)
for _, dw := range dc.DayWidth {
x := x.IndexFromType(dw, width)
for _, d := range dw.Day {
x.SetValue(d.Type, d)
}
}
}
}
if x := x.Index(cal.Quarters); x != nil {
for _, qc := range cal.Quarters.QuarterContext {
x := x.IndexFromType(qc, context)
for _, qw := range qc.QuarterWidth {
x := x.IndexFromType(qw, width)
for _, q := range qw.Quarter {
x.SetValue(q.Type, q)
}
}
}
}
if x := x.Index(cal.DayPeriods); x != nil {
for _, dc := range cal.DayPeriods.DayPeriodContext {
x := x.IndexFromType(dc, context)
for _, dw := range dc.DayPeriodWidth {
x := x.IndexFromType(dw, width)
for _, d := range dw.DayPeriod {
x.IndexFromType(d).SetValue(d.Alt, d)
}
}
}
}
if x := x.Index(cal.Eras); x != nil {
opts := []cldrtree.Option{width, cldrtree.SharedType()}
if x := x.Index(cal.Eras.EraNames, opts...); x != nil {
for _, e := range cal.Eras.EraNames.Era {
x.IndexFromAlt(e).SetValue(e.Type, e)
}
}
if x := x.Index(cal.Eras.EraAbbr, opts...); x != nil {
for _, e := range cal.Eras.EraAbbr.Era {
x.IndexFromAlt(e).SetValue(e.Type, e)
}
}
if x := x.Index(cal.Eras.EraNarrow, opts...); x != nil {
for _, e := range cal.Eras.EraNarrow.Era {
x.IndexFromAlt(e).SetValue(e.Type, e)
}
}
}
if x := x.Index(cal.DateFormats); x != nil {
for _, dfl := range cal.DateFormats.DateFormatLength {
x := x.IndexFromType(dfl, length)
for _, df := range dfl.DateFormat {
for _, p := range df.Pattern {
x.SetValue(p.Alt, p)
}
}
}
}
if x := x.Index(cal.TimeFormats); x != nil {
for _, tfl := range cal.TimeFormats.TimeFormatLength {
x := x.IndexFromType(tfl, length)
for _, tf := range tfl.TimeFormat {
for _, p := range tf.Pattern {
x.SetValue(p.Alt, p)
}
}
}
}
if x := x.Index(cal.DateTimeFormats); x != nil {
for _, dtfl := range cal.DateTimeFormats.DateTimeFormatLength {
x := x.IndexFromType(dtfl, length)
for _, dtf := range dtfl.DateTimeFormat {
for _, p := range dtf.Pattern {
x.SetValue(p.Alt, p)
}
}
}
// TODO:
// - appendItems
// - intervalFormats
}
}
}
// TODO: this is a lot of data and is probably relatively little used.
// Store this somewhere else.
if x := x.Index(ldml.Dates.Fields); x != nil {
for _, f := range ldml.Dates.Fields.Field {
x := x.IndexFromType(f, field)
for _, d := range f.DisplayName {
x.Index(d).SetValue(d.Alt, d)
}
for _, r := range f.Relative {
x.Index(r).SetValue(r.Type, r, relTime)
}
for _, rt := range f.RelativeTime {
x := x.Index(rt).IndexFromType(rt)
for _, p := range rt.RelativeTimePattern {
x.SetValue(p.Count, p)
}
}
for _, rp := range f.RelativePeriod {
x.Index(rp).SetValue(rp.Alt, rp)
}
}
}
if x := x.Index(ldml.Dates.TimeZoneNames); x != nil {
format := x.IndexWithName("zoneFormat")
for _, h := range ldml.Dates.TimeZoneNames.HourFormat {
format.SetValue(h.Element(), h)
}
for _, g := range ldml.Dates.TimeZoneNames.GmtFormat {
format.SetValue(g.Element(), g)
}
for _, g := range ldml.Dates.TimeZoneNames.GmtZeroFormat {
format.SetValue(g.Element(), g)
}
for _, r := range ldml.Dates.TimeZoneNames.RegionFormat {
x.Index(r).SetValue(r.Type, r, timeType)
}
set := func(x *cldrtree.Index, e []*cldr.Common, zone string) {
for _, n := range e {
x.Index(n, zoneType...).SetValue(zone, n)
}
}
zoneWidth := []cldrtree.Option{length, cldrtree.SharedType()}
zs := x.IndexWithName("zone")
for _, z := range ldml.Dates.TimeZoneNames.Zone {
for _, l := range z.Long {
x := zs.Index(l, zoneWidth...)
set(x, l.Generic, z.Type)
set(x, l.Standard, z.Type)
set(x, l.Daylight, z.Type)
}
for _, s := range z.Short {
x := zs.Index(s, zoneWidth...)
set(x, s.Generic, z.Type)
set(x, s.Standard, z.Type)
set(x, s.Daylight, z.Type)
}
}
set = func(x *cldrtree.Index, e []*cldr.Common, zone string) {
for _, n := range e {
x.Index(n, metaZoneType...).SetValue(zone, n)
}
}
zoneWidth = []cldrtree.Option{length, cldrtree.SharedType()}
zs = x.IndexWithName("metaZone")
for _, z := range ldml.Dates.TimeZoneNames.Metazone {
for _, l := range z.Long {
x := zs.Index(l, zoneWidth...)
set(x, l.Generic, z.Type)
set(x, l.Standard, z.Type)
set(x, l.Daylight, z.Type)
}
for _, s := range z.Short {
x := zs.Index(s, zoneWidth...)
set(x, s.Generic, z.Type)
set(x, s.Standard, z.Type)
set(x, s.Daylight, z.Type)
}
}
}
}
}
+241
View File
@@ -0,0 +1,241 @@
// Copyright 2017 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 date
import (
"strconv"
"strings"
"testing"
"golang.org/x/text/internal/cldrtree"
"golang.org/x/text/internal/gen"
"golang.org/x/text/internal/testtext"
"golang.org/x/text/language"
"golang.org/x/text/unicode/cldr"
)
func TestTables(t *testing.T) {
testtext.SkipIfNotLong(t)
r := gen.OpenCLDRCoreZip()
defer r.Close()
d := &cldr.Decoder{}
d.SetDirFilter("supplemental", "main")
d.SetSectionFilter("dates")
data, err := d.DecodeZip(r)
if err != nil {
t.Fatalf("DecodeZip: %v", err)
}
count := 0
for _, lang := range data.Locales() {
ldml := data.RawLDML(lang)
if ldml.Dates == nil {
continue
}
tag, _ := language.CompactIndex(language.MustParse(lang))
test := func(want cldrtree.Element, path ...string) {
if count > 30 {
return
}
t.Run(lang+"/"+strings.Join(path, "/"), func(t *testing.T) {
p := make([]uint16, len(path))
for i, s := range path {
if v, err := strconv.Atoi(s); err == nil {
p[i] = uint16(v)
} else if v, ok := enumMap[s]; ok {
p[i] = v
} else {
count++
t.Fatalf("Unknown key %q", s)
}
}
wantStr := want.GetCommon().Data()
if got := tree.Lookup(tag, p...); got != wantStr {
count++
t.Errorf("got %q; want %q", got, wantStr)
}
})
}
width := func(s string) string { return "width" + strings.Title(s) }
if ldml.Dates.Calendars != nil {
for _, cal := range ldml.Dates.Calendars.Calendar {
if cal.Months != nil {
for _, mc := range cal.Months.MonthContext {
for _, mw := range mc.MonthWidth {
for _, m := range mw.Month {
test(m, "calendars", cal.Type, "months", mc.Type, width(mw.Type), m.Yeartype+m.Type)
}
}
}
}
if cal.MonthPatterns != nil {
for _, mc := range cal.MonthPatterns.MonthPatternContext {
for _, mw := range mc.MonthPatternWidth {
for _, m := range mw.MonthPattern {
test(m, "calendars", cal.Type, "monthPatterns", mc.Type, width(mw.Type))
}
}
}
}
if cal.CyclicNameSets != nil {
for _, cns := range cal.CyclicNameSets.CyclicNameSet {
for _, cc := range cns.CyclicNameContext {
for _, cw := range cc.CyclicNameWidth {
for _, c := range cw.CyclicName {
test(c, "calendars", cal.Type, "cyclicNameSets", cns.Type+"CycleType", cc.Type, width(cw.Type), c.Type)
}
}
}
}
}
if cal.Days != nil {
for _, dc := range cal.Days.DayContext {
for _, dw := range dc.DayWidth {
for _, d := range dw.Day {
test(d, "calendars", cal.Type, "days", dc.Type, width(dw.Type), d.Type)
}
}
}
}
if cal.Quarters != nil {
for _, qc := range cal.Quarters.QuarterContext {
for _, qw := range qc.QuarterWidth {
for _, q := range qw.Quarter {
test(q, "calendars", cal.Type, "quarters", qc.Type, width(qw.Type), q.Type)
}
}
}
}
if cal.DayPeriods != nil {
for _, dc := range cal.DayPeriods.DayPeriodContext {
for _, dw := range dc.DayPeriodWidth {
for _, d := range dw.DayPeriod {
test(d, "calendars", cal.Type, "dayPeriods", dc.Type, width(dw.Type), d.Type, d.Alt)
}
}
}
}
if cal.Eras != nil {
if cal.Eras.EraNames != nil {
for _, e := range cal.Eras.EraNames.Era {
test(e, "calendars", cal.Type, "eras", "widthWide", e.Alt, e.Type)
}
}
if cal.Eras.EraAbbr != nil {
for _, e := range cal.Eras.EraAbbr.Era {
test(e, "calendars", cal.Type, "eras", "widthAbbreviated", e.Alt, e.Type)
}
}
if cal.Eras.EraNarrow != nil {
for _, e := range cal.Eras.EraNarrow.Era {
test(e, "calendars", cal.Type, "eras", "widthNarrow", e.Alt, e.Type)
}
}
}
if cal.DateFormats != nil {
for _, dfl := range cal.DateFormats.DateFormatLength {
for _, df := range dfl.DateFormat {
for _, p := range df.Pattern {
test(p, "calendars", cal.Type, "dateFormats", dfl.Type, p.Alt)
}
}
}
}
if cal.TimeFormats != nil {
for _, tfl := range cal.TimeFormats.TimeFormatLength {
for _, tf := range tfl.TimeFormat {
for _, p := range tf.Pattern {
test(p, "calendars", cal.Type, "timeFormats", tfl.Type, p.Alt)
}
}
}
}
if cal.DateTimeFormats != nil {
for _, dtfl := range cal.DateTimeFormats.DateTimeFormatLength {
for _, dtf := range dtfl.DateTimeFormat {
for _, p := range dtf.Pattern {
test(p, "calendars", cal.Type, "dateTimeFormats", dtfl.Type, p.Alt)
}
}
}
// TODO:
// - appendItems
// - intervalFormats
}
}
}
// TODO: this is a lot of data and is probably relatively little used.
// Store this somewhere else.
if ldml.Dates.Fields != nil {
for _, f := range ldml.Dates.Fields.Field {
field := f.Type + "Field"
for _, d := range f.DisplayName {
test(d, "fields", field, "displayName", d.Alt)
}
for _, r := range f.Relative {
i, _ := strconv.Atoi(r.Type)
v := []string{"before2", "before1", "current", "after1", "after2", "after3"}[i+2]
test(r, "fields", field, "relative", v)
}
for _, rt := range f.RelativeTime {
for _, p := range rt.RelativeTimePattern {
test(p, "fields", field, "relativeTime", rt.Type, p.Count)
}
}
for _, rp := range f.RelativePeriod {
test(rp, "fields", field, "relativePeriod", rp.Alt)
}
}
}
if ldml.Dates.TimeZoneNames != nil {
for _, h := range ldml.Dates.TimeZoneNames.HourFormat {
test(h, "timeZoneNames", "zoneFormat", h.Element())
}
for _, g := range ldml.Dates.TimeZoneNames.GmtFormat {
test(g, "timeZoneNames", "zoneFormat", g.Element())
}
for _, g := range ldml.Dates.TimeZoneNames.GmtZeroFormat {
test(g, "timeZoneNames", "zoneFormat", g.Element())
}
for _, r := range ldml.Dates.TimeZoneNames.RegionFormat {
s := r.Type
if s == "" {
s = "generic"
}
test(r, "timeZoneNames", "regionFormat", s+"Time")
}
testZone := func(zoneType, zoneWidth, zone string, a ...[]*cldr.Common) {
for _, e := range a {
for _, n := range e {
test(n, "timeZoneNames", zoneType, zoneWidth, n.Element()+"Time", zone)
}
}
}
for _, z := range ldml.Dates.TimeZoneNames.Zone {
for _, l := range z.Long {
testZone("zone", l.Element(), z.Type, l.Generic, l.Standard, l.Daylight)
}
for _, l := range z.Short {
testZone("zone", l.Element(), z.Type, l.Generic, l.Standard, l.Daylight)
}
}
for _, z := range ldml.Dates.TimeZoneNames.Metazone {
for _, l := range z.Long {
testZone("metaZone", l.Element(), z.Type, l.Generic, l.Standard, l.Daylight)
}
for _, l := range z.Short {
testZone("metaZone", l.Element(), z.Type, l.Generic, l.Standard, l.Daylight)
}
}
}
}
}
+64522
View File
File diff suppressed because it is too large Load Diff
+61 -54
View File
@@ -9,8 +9,8 @@ type pluralTest struct {
decimal []string
}
var ordinalTests = []pluralTest{ // 59 elements
0: {locales: "af am ar bg bs ce cs da de dsb el es et eu fa fi fy gl gsw he hr hsb id in is iw ja km kn ko ky lt lv ml mn my nb nl pa pl prg pt root ru sh si sk sl sr sw ta te th tr ur uz yue zh zu", form: 0, integer: []string{"0~15", "100", "1000", "10000", "100000", "1000000"}, decimal: []string(nil)},
var ordinalTests = []pluralTest{ // 66 elements
0: {locales: "af am ar bg bs ce cs da de dsb el es et eu fa fi fy gl gsw he hr hsb id in is iw ja km kn ko ky lt lv ml mn my nb nl pa pl prg ps pt root ru sd sh si sk sl sr sw ta te th tr ur uz yue zh zu", form: 0, integer: []string{"0~15", "100", "1000", "10000", "100000", "1000000"}, decimal: []string(nil)},
1: {locales: "sv", form: 2, integer: []string{"1", "2", "21", "22", "31", "32", "41", "42", "51", "52", "61", "62", "71", "72", "81", "82", "101", "1001"}, decimal: []string(nil)},
2: {locales: "sv", form: 0, integer: []string{"0", "3~17", "100", "1000", "10000", "100000", "1000000"}, decimal: []string(nil)},
3: {locales: "fil fr ga hy lo mo ms ro tl vi", form: 2, integer: []string{"1"}, decimal: []string(nil)},
@@ -23,53 +23,60 @@ var ordinalTests = []pluralTest{ // 59 elements
10: {locales: "be", form: 0, integer: []string{"0", "1", "4~17", "100", "1000", "10000", "100000", "1000000"}, decimal: []string(nil)},
11: {locales: "uk", form: 4, integer: []string{"3", "23", "33", "43", "53", "63", "73", "83", "103", "1003"}, decimal: []string(nil)},
12: {locales: "uk", form: 0, integer: []string{"0~2", "4~16", "100", "1000", "10000", "100000", "1000000"}, decimal: []string(nil)},
13: {locales: "kk", form: 5, integer: []string{"6", "9", "10", "16", "19", "20", "26", "29", "30", "36", "39", "40", "100", "1000", "10000", "100000", "1000000"}, decimal: []string(nil)},
14: {locales: "kk", form: 0, integer: []string{"0~5", "7", "8", "11~15", "17", "18", "21", "101", "1001"}, decimal: []string(nil)},
15: {locales: "it", form: 5, integer: []string{"8", "11", "80", "800"}, decimal: []string(nil)},
16: {locales: "it", form: 0, integer: []string{"0~7", "9", "10", "12~17", "100", "1000", "10000", "100000", "1000000"}, decimal: []string(nil)},
17: {locales: "ka", form: 2, integer: []string{"1"}, decimal: []string(nil)},
18: {locales: "ka", form: 5, integer: []string{"0", "2~16", "102", "1002"}, decimal: []string(nil)},
19: {locales: "ka", form: 0, integer: []string{"21~36", "100", "1000", "10000", "100000", "1000000"}, decimal: []string(nil)},
20: {locales: "sq", form: 2, integer: []string{"1"}, decimal: []string(nil)},
21: {locales: "sq", form: 5, integer: []string{"4", "24", "34", "44", "54", "64", "74", "84", "104", "1004"}, decimal: []string(nil)},
22: {locales: "sq", form: 0, integer: []string{"0", "2", "3", "5~17", "100", "1000", "10000", "100000", "1000000"}, decimal: []string(nil)},
23: {locales: "en", form: 2, integer: []string{"1", "21", "31", "41", "51", "61", "71", "81", "101", "1001"}, decimal: []string(nil)},
24: {locales: "en", form: 3, integer: []string{"2", "22", "32", "42", "52", "62", "72", "82", "102", "1002"}, decimal: []string(nil)},
25: {locales: "en", form: 4, integer: []string{"3", "23", "33", "43", "53", "63", "73", "83", "103", "1003"}, decimal: []string(nil)},
26: {locales: "en", form: 0, integer: []string{"0", "4~18", "100", "1000", "10000", "100000", "1000000"}, decimal: []string(nil)},
27: {locales: "mr", form: 2, integer: []string{"1"}, decimal: []string(nil)},
28: {locales: "mr", form: 3, integer: []string{"2", "3"}, decimal: []string(nil)},
29: {locales: "mr", form: 4, integer: []string{"4"}, decimal: []string(nil)},
30: {locales: "mr", form: 0, integer: []string{"0", "5~19", "100", "1000", "10000", "100000", "1000000"}, decimal: []string(nil)},
31: {locales: "ca", form: 2, integer: []string{"1", "3"}, decimal: []string(nil)},
32: {locales: "ca", form: 3, integer: []string{"2"}, decimal: []string(nil)},
33: {locales: "ca", form: 4, integer: []string{"4"}, decimal: []string(nil)},
34: {locales: "ca", form: 0, integer: []string{"0", "5~19", "100", "1000", "10000", "100000", "1000000"}, decimal: []string(nil)},
35: {locales: "mk", form: 2, integer: []string{"1", "21", "31", "41", "51", "61", "71", "81", "101", "1001"}, decimal: []string(nil)},
36: {locales: "mk", form: 3, integer: []string{"2", "22", "32", "42", "52", "62", "72", "82", "102", "1002"}, decimal: []string(nil)},
37: {locales: "mk", form: 5, integer: []string{"7", "8", "27", "28", "37", "38", "47", "48", "57", "58", "67", "68", "77", "78", "87", "88", "107", "1007"}, decimal: []string(nil)},
38: {locales: "mk", form: 0, integer: []string{"0", "3~6", "9~19", "100", "1000", "10000", "100000", "1000000"}, decimal: []string(nil)},
39: {locales: "az", form: 2, integer: []string{"1", "2", "5", "7", "8", "11", "12", "15", "17", "18", "20~22", "25", "101", "1001"}, decimal: []string(nil)},
40: {locales: "az", form: 4, integer: []string{"3", "4", "13", "14", "23", "24", "33", "34", "43", "44", "53", "54", "63", "64", "73", "74", "100", "1003"}, decimal: []string(nil)},
41: {locales: "az", form: 5, integer: []string{"0", "6", "16", "26", "36", "40", "46", "56", "106", "1006"}, decimal: []string(nil)},
42: {locales: "az", form: 0, integer: []string{"9", "10", "19", "29", "30", "39", "49", "59", "69", "79", "109", "1000", "10000", "100000", "1000000"}, decimal: []string(nil)},
43: {locales: "gu hi", form: 2, integer: []string{"1"}, decimal: []string(nil)},
44: {locales: "gu hi", form: 3, integer: []string{"2", "3"}, decimal: []string(nil)},
45: {locales: "gu hi", form: 4, integer: []string{"4"}, decimal: []string(nil)},
46: {locales: "gu hi", form: 5, integer: []string{"6"}, decimal: []string(nil)},
47: {locales: "gu hi", form: 0, integer: []string{"0", "5", "7~20", "100", "1000", "10000", "100000", "1000000"}, decimal: []string(nil)},
48: {locales: "as bn", form: 2, integer: []string{"1", "5", "7~10"}, decimal: []string(nil)},
49: {locales: "as bn", form: 3, integer: []string{"2", "3"}, decimal: []string(nil)},
50: {locales: "as bn", form: 4, integer: []string{"4"}, decimal: []string(nil)},
51: {locales: "as bn", form: 5, integer: []string{"6"}, decimal: []string(nil)},
52: {locales: "as bn", form: 0, integer: []string{"0", "11~25", "100", "1000", "10000", "100000", "1000000"}, decimal: []string(nil)},
53: {locales: "cy", form: 1, integer: []string{"0", "7~9"}, decimal: []string(nil)},
54: {locales: "cy", form: 2, integer: []string{"1"}, decimal: []string(nil)},
55: {locales: "cy", form: 3, integer: []string{"2"}, decimal: []string(nil)},
56: {locales: "cy", form: 4, integer: []string{"3", "4"}, decimal: []string(nil)},
57: {locales: "cy", form: 5, integer: []string{"5", "6"}, decimal: []string(nil)},
58: {locales: "cy", form: 0, integer: []string{"10~25", "100", "1000", "10000", "100000", "1000000"}, decimal: []string(nil)},
} // Size: 4272 bytes
13: {locales: "tk", form: 4, integer: []string{"6", "9", "10", "16", "19", "26", "29", "36", "39", "106", "1006"}, decimal: []string(nil)},
14: {locales: "tk", form: 0, integer: []string{"0~5", "7", "8", "11~15", "17", "18", "20", "100", "1000", "10000", "100000", "1000000"}, decimal: []string(nil)},
15: {locales: "kk", form: 5, integer: []string{"6", "9", "10", "16", "19", "20", "26", "29", "30", "36", "39", "40", "100", "1000", "10000", "100000", "1000000"}, decimal: []string(nil)},
16: {locales: "kk", form: 0, integer: []string{"0~5", "7", "8", "11~15", "17", "18", "21", "101", "1001"}, decimal: []string(nil)},
17: {locales: "it", form: 5, integer: []string{"8", "11", "80", "800"}, decimal: []string(nil)},
18: {locales: "it", form: 0, integer: []string{"0~7", "9", "10", "12~17", "100", "1000", "10000", "100000", "1000000"}, decimal: []string(nil)},
19: {locales: "ka", form: 2, integer: []string{"1"}, decimal: []string(nil)},
20: {locales: "ka", form: 5, integer: []string{"0", "2~16", "102", "1002"}, decimal: []string(nil)},
21: {locales: "ka", form: 0, integer: []string{"21~36", "100", "1000", "10000", "100000", "1000000"}, decimal: []string(nil)},
22: {locales: "sq", form: 2, integer: []string{"1"}, decimal: []string(nil)},
23: {locales: "sq", form: 5, integer: []string{"4", "24", "34", "44", "54", "64", "74", "84", "104", "1004"}, decimal: []string(nil)},
24: {locales: "sq", form: 0, integer: []string{"0", "2", "3", "5~17", "100", "1000", "10000", "100000", "1000000"}, decimal: []string(nil)},
25: {locales: "en", form: 2, integer: []string{"1", "21", "31", "41", "51", "61", "71", "81", "101", "1001"}, decimal: []string(nil)},
26: {locales: "en", form: 3, integer: []string{"2", "22", "32", "42", "52", "62", "72", "82", "102", "1002"}, decimal: []string(nil)},
27: {locales: "en", form: 4, integer: []string{"3", "23", "33", "43", "53", "63", "73", "83", "103", "1003"}, decimal: []string(nil)},
28: {locales: "en", form: 0, integer: []string{"0", "4~18", "100", "1000", "10000", "100000", "1000000"}, decimal: []string(nil)},
29: {locales: "mr", form: 2, integer: []string{"1"}, decimal: []string(nil)},
30: {locales: "mr", form: 3, integer: []string{"2", "3"}, decimal: []string(nil)},
31: {locales: "mr", form: 4, integer: []string{"4"}, decimal: []string(nil)},
32: {locales: "mr", form: 0, integer: []string{"0", "5~19", "100", "1000", "10000", "100000", "1000000"}, decimal: []string(nil)},
33: {locales: "ca", form: 2, integer: []string{"1", "3"}, decimal: []string(nil)},
34: {locales: "ca", form: 3, integer: []string{"2"}, decimal: []string(nil)},
35: {locales: "ca", form: 4, integer: []string{"4"}, decimal: []string(nil)},
36: {locales: "ca", form: 0, integer: []string{"0", "5~19", "100", "1000", "10000", "100000", "1000000"}, decimal: []string(nil)},
37: {locales: "mk", form: 2, integer: []string{"1", "21", "31", "41", "51", "61", "71", "81", "101", "1001"}, decimal: []string(nil)},
38: {locales: "mk", form: 3, integer: []string{"2", "22", "32", "42", "52", "62", "72", "82", "102", "1002"}, decimal: []string(nil)},
39: {locales: "mk", form: 5, integer: []string{"7", "8", "27", "28", "37", "38", "47", "48", "57", "58", "67", "68", "77", "78", "87", "88", "107", "1007"}, decimal: []string(nil)},
40: {locales: "mk", form: 0, integer: []string{"0", "3~6", "9~19", "100", "1000", "10000", "100000", "1000000"}, decimal: []string(nil)},
41: {locales: "az", form: 2, integer: []string{"1", "2", "5", "7", "8", "11", "12", "15", "17", "18", "20~22", "25", "101", "1001"}, decimal: []string(nil)},
42: {locales: "az", form: 4, integer: []string{"3", "4", "13", "14", "23", "24", "33", "34", "43", "44", "53", "54", "63", "64", "73", "74", "100", "1003"}, decimal: []string(nil)},
43: {locales: "az", form: 5, integer: []string{"0", "6", "16", "26", "36", "40", "46", "56", "106", "1006"}, decimal: []string(nil)},
44: {locales: "az", form: 0, integer: []string{"9", "10", "19", "29", "30", "39", "49", "59", "69", "79", "109", "1000", "10000", "100000", "1000000"}, decimal: []string(nil)},
45: {locales: "gu hi", form: 2, integer: []string{"1"}, decimal: []string(nil)},
46: {locales: "gu hi", form: 3, integer: []string{"2", "3"}, decimal: []string(nil)},
47: {locales: "gu hi", form: 4, integer: []string{"4"}, decimal: []string(nil)},
48: {locales: "gu hi", form: 5, integer: []string{"6"}, decimal: []string(nil)},
49: {locales: "gu hi", form: 0, integer: []string{"0", "5", "7~20", "100", "1000", "10000", "100000", "1000000"}, decimal: []string(nil)},
50: {locales: "as bn", form: 2, integer: []string{"1", "5", "7~10"}, decimal: []string(nil)},
51: {locales: "as bn", form: 3, integer: []string{"2", "3"}, decimal: []string(nil)},
52: {locales: "as bn", form: 4, integer: []string{"4"}, decimal: []string(nil)},
53: {locales: "as bn", form: 5, integer: []string{"6"}, decimal: []string(nil)},
54: {locales: "as bn", form: 0, integer: []string{"0", "11~25", "100", "1000", "10000", "100000", "1000000"}, decimal: []string(nil)},
55: {locales: "or", form: 2, integer: []string{"1", "5", "7~9"}, decimal: []string(nil)},
56: {locales: "or", form: 3, integer: []string{"2", "3"}, decimal: []string(nil)},
57: {locales: "or", form: 4, integer: []string{"4"}, decimal: []string(nil)},
58: {locales: "or", form: 5, integer: []string{"6"}, decimal: []string(nil)},
59: {locales: "or", form: 0, integer: []string{"0", "10~24", "100", "1000", "10000", "100000", "1000000"}, decimal: []string(nil)},
60: {locales: "cy", form: 1, integer: []string{"0", "7~9"}, decimal: []string(nil)},
61: {locales: "cy", form: 2, integer: []string{"1"}, decimal: []string(nil)},
62: {locales: "cy", form: 3, integer: []string{"2"}, decimal: []string(nil)},
63: {locales: "cy", form: 4, integer: []string{"3", "4"}, decimal: []string(nil)},
64: {locales: "cy", form: 5, integer: []string{"5", "6"}, decimal: []string(nil)},
65: {locales: "cy", form: 0, integer: []string{"10~25", "100", "1000", "10000", "100000", "1000000"}, decimal: []string(nil)},
} // Size: 4776 bytes
var cardinalTests = []pluralTest{ // 113 elements
0: {locales: "bm bo dz id ig ii in ja jbo jv jw kde kea km ko lkt lo ms my nqo root sah ses sg th to vi wo yo yue zh", form: 0, integer: []string{"0~15", "100", "1000", "10000", "100000", "1000000"}, decimal: []string{"0.0~1.5", "10.0", "100.0", "1000.0", "10000.0", "100000.0", "1000000.0"}},
@@ -79,16 +86,16 @@ var cardinalTests = []pluralTest{ // 113 elements
4: {locales: "ff fr hy kab", form: 0, integer: []string{"2~17", "100", "1000", "10000", "100000", "1000000"}, decimal: []string{"2.0~3.5", "10.0", "100.0", "1000.0", "10000.0", "100000.0", "1000000.0"}},
5: {locales: "pt", form: 2, integer: []string{"0", "1"}, decimal: []string{"0.0~1.5"}},
6: {locales: "pt", form: 0, integer: []string{"2~17", "100", "1000", "10000", "100000", "1000000"}, decimal: []string{"2.0~3.5", "10.0", "100.0", "1000.0", "10000.0", "100000.0", "1000000.0"}},
7: {locales: "ast ca de en et fi fy gl it ji nl sv sw ur yi", form: 2, integer: []string{"1"}, decimal: []string(nil)},
8: {locales: "ast ca de en et fi fy gl it ji nl sv sw ur yi", form: 0, integer: []string{"0", "2~16", "100", "1000", "10000", "100000", "1000000"}, decimal: []string{"0.0~1.5", "10.0", "100.0", "1000.0", "10000.0", "100000.0", "1000000.0"}},
7: {locales: "ast ca de en et fi fy gl io it ji nl pt_PT sv sw ur yi", form: 2, integer: []string{"1"}, decimal: []string(nil)},
8: {locales: "ast ca de en et fi fy gl io it ji nl pt_PT sv sw ur yi", form: 0, integer: []string{"0", "2~16", "100", "1000", "10000", "100000", "1000000"}, decimal: []string{"0.0~1.5", "10.0", "100.0", "1000.0", "10000.0", "100000.0", "1000000.0"}},
9: {locales: "si", form: 2, integer: []string{"0", "1"}, decimal: []string{"0.0", "0.1", "1.0", "0.00", "0.01", "1.00", "0.000", "0.001", "1.000", "0.0000", "0.0001", "1.0000"}},
10: {locales: "si", form: 0, integer: []string{"2~17", "100", "1000", "10000", "100000", "1000000"}, decimal: []string{"0.2~0.9", "1.1~1.8", "10.0", "100.0", "1000.0", "10000.0", "100000.0", "1000000.0"}},
11: {locales: "ak bh guw ln mg nso pa ti wa", form: 2, integer: []string{"0", "1"}, decimal: []string{"0.0", "1.0", "0.00", "1.00", "0.000", "1.000", "0.0000", "1.0000"}},
12: {locales: "ak bh guw ln mg nso pa ti wa", form: 0, integer: []string{"2~17", "100", "1000", "10000", "100000", "1000000"}, decimal: []string{"0.1~0.9", "1.1~1.7", "10.0", "100.0", "1000.0", "10000.0", "100000.0", "1000000.0"}},
13: {locales: "tzm", form: 2, integer: []string{"0", "1", "11~24"}, decimal: []string{"0.0", "1.0", "11.0", "12.0", "13.0", "14.0", "15.0", "16.0", "17.0", "18.0", "19.0", "20.0", "21.0", "22.0", "23.0", "24.0"}},
14: {locales: "tzm", form: 0, integer: []string{"2~10", "100~106", "1000", "10000", "100000", "1000000"}, decimal: []string{"0.1~0.9", "1.1~1.7", "10.0", "100.0", "1000.0", "10000.0", "100000.0", "1000000.0"}},
15: {locales: "af asa az bem bez bg brx ce cgg chr ckb dv ee el eo es eu fo fur gsw ha haw hu jgo jmc ka kaj kcg kk kkj kl ks ksb ku ky lb lg mas mgo ml mn nah nb nd ne nn nnh no nr ny nyn om or os pap ps rm rof rwk saq sdh seh sn so sq ss ssy st syr ta te teo tig tk tn tr ts ug uz ve vo vun wae xh xog", form: 2, integer: []string{"1"}, decimal: []string{"1.0", "1.00", "1.000", "1.0000"}},
16: {locales: "af asa az bem bez bg brx ce cgg chr ckb dv ee el eo es eu fo fur gsw ha haw hu jgo jmc ka kaj kcg kk kkj kl ks ksb ku ky lb lg mas mgo ml mn nah nb nd ne nn nnh no nr ny nyn om or os pap ps rm rof rwk saq sdh seh sn so sq ss ssy st syr ta te teo tig tk tn tr ts ug uz ve vo vun wae xh xog", form: 0, integer: []string{"0", "2~16", "100", "1000", "10000", "100000", "1000000"}, decimal: []string{"0.0~0.9", "1.1~1.6", "10.0", "100.0", "1000.0", "10000.0", "100000.0", "1000000.0"}},
15: {locales: "af asa az bem bez bg brx ce cgg chr ckb dv ee el eo es eu fo fur gsw ha haw hu jgo jmc ka kaj kcg kk kkj kl ks ksb ku ky lb lg mas mgo ml mn nah nb nd ne nn nnh no nr ny nyn om or os pap ps rm rof rwk saq sd sdh seh sn so sq ss ssy st syr ta te teo tig tk tn tr ts ug uz ve vo vun wae xh xog", form: 2, integer: []string{"1"}, decimal: []string{"1.0", "1.00", "1.000", "1.0000"}},
16: {locales: "af asa az bem bez bg brx ce cgg chr ckb dv ee el eo es eu fo fur gsw ha haw hu jgo jmc ka kaj kcg kk kkj kl ks ksb ku ky lb lg mas mgo ml mn nah nb nd ne nn nnh no nr ny nyn om or os pap ps rm rof rwk saq sd sdh seh sn so sq ss ssy st syr ta te teo tig tk tn tr ts ug uz ve vo vun wae xh xog", form: 0, integer: []string{"0", "2~16", "100", "1000", "10000", "100000", "1000000"}, decimal: []string{"0.0~0.9", "1.1~1.6", "10.0", "100.0", "1000.0", "10000.0", "100000.0", "1000000.0"}},
17: {locales: "da", form: 2, integer: []string{"1"}, decimal: []string{"0.1~1.6"}},
18: {locales: "da", form: 0, integer: []string{"0", "2~16", "100", "1000", "10000", "100000", "1000000"}, decimal: []string{"0.0", "2.0~3.4", "10.0", "100.0", "1000.0", "10000.0", "100000.0", "1000000.0"}},
19: {locales: "is", form: 2, integer: []string{"1", "21", "31", "41", "51", "61", "71", "81", "101", "1001"}, decimal: []string{"0.1~1.6", "10.1", "100.1", "1000.1"}},
@@ -187,4 +194,4 @@ var cardinalTests = []pluralTest{ // 113 elements
112: {locales: "cy", form: 0, integer: []string{"4", "5", "7~20", "100", "1000", "10000", "100000", "1000000"}, decimal: []string{"0.1~0.9", "1.1~1.7", "10.0", "100.0", "1000.0", "10000.0", "100000.0", "1000000.0"}},
} // Size: 8160 bytes
// Total table size 12432 bytes (12KiB); checksum: 166DAB71
// Total table size 12936 bytes (12KiB); checksum: 8456DC5D
Generated Vendored Executable → Regular
View File
+202 -194
View File
@@ -3,9 +3,9 @@
package plural
// CLDRVersion is the CLDR version from which the tables in this package are derived.
const CLDRVersion = "31"
const CLDRVersion = "32"
var ordinalRules = []pluralCheck{ // 58 elements
var ordinalRules = []pluralCheck{ // 64 elements
0: {cat: 0x2f, setID: 0x4},
1: {cat: 0x3a, setID: 0x5},
2: {cat: 0x22, setID: 0x1},
@@ -15,148 +15,154 @@ var ordinalRules = []pluralCheck{ // 58 elements
6: {cat: 0x3c, setID: 0x9},
7: {cat: 0x2f, setID: 0xa},
8: {cat: 0x3c, setID: 0xb},
9: {cat: 0x2d, setID: 0xc},
10: {cat: 0x2d, setID: 0xd},
11: {cat: 0x2f, setID: 0xe},
12: {cat: 0x35, setID: 0x3},
13: {cat: 0xc5, setID: 0xf},
14: {cat: 0x2, setID: 0x1},
15: {cat: 0x5, setID: 0x3},
16: {cat: 0xd, setID: 0x10},
17: {cat: 0x22, setID: 0x1},
18: {cat: 0x2f, setID: 0x11},
19: {cat: 0x3d, setID: 0x12},
9: {cat: 0x2c, setID: 0xc},
10: {cat: 0x24, setID: 0xd},
11: {cat: 0x2d, setID: 0xe},
12: {cat: 0x2d, setID: 0xf},
13: {cat: 0x2f, setID: 0x10},
14: {cat: 0x35, setID: 0x3},
15: {cat: 0xc5, setID: 0x11},
16: {cat: 0x2, setID: 0x1},
17: {cat: 0x5, setID: 0x3},
18: {cat: 0xd, setID: 0x12},
19: {cat: 0x22, setID: 0x1},
20: {cat: 0x2f, setID: 0x13},
21: {cat: 0x3a, setID: 0x14},
21: {cat: 0x3d, setID: 0x14},
22: {cat: 0x2f, setID: 0x15},
23: {cat: 0x3b, setID: 0x16},
24: {cat: 0x2f, setID: 0xa},
25: {cat: 0x3c, setID: 0xb},
26: {cat: 0x22, setID: 0x1},
27: {cat: 0x23, setID: 0x17},
28: {cat: 0x24, setID: 0x18},
29: {cat: 0x22, setID: 0x19},
30: {cat: 0x23, setID: 0x2},
31: {cat: 0x24, setID: 0x18},
32: {cat: 0xf, setID: 0x13},
33: {cat: 0x1a, setID: 0x14},
23: {cat: 0x3a, setID: 0x16},
24: {cat: 0x2f, setID: 0x17},
25: {cat: 0x3b, setID: 0x18},
26: {cat: 0x2f, setID: 0xa},
27: {cat: 0x3c, setID: 0xb},
28: {cat: 0x22, setID: 0x1},
29: {cat: 0x23, setID: 0x19},
30: {cat: 0x24, setID: 0x1a},
31: {cat: 0x22, setID: 0x1b},
32: {cat: 0x23, setID: 0x2},
33: {cat: 0x24, setID: 0x1a},
34: {cat: 0xf, setID: 0x15},
35: {cat: 0x1b, setID: 0x16},
36: {cat: 0xf, setID: 0x1a},
37: {cat: 0x1d, setID: 0x1b},
38: {cat: 0xa, setID: 0x1c},
39: {cat: 0xa, setID: 0x1d},
40: {cat: 0xc, setID: 0x1e},
41: {cat: 0xe4, setID: 0x0},
42: {cat: 0x5, setID: 0x3},
43: {cat: 0xd, setID: 0xc},
44: {cat: 0xd, setID: 0x1f},
45: {cat: 0x22, setID: 0x1},
46: {cat: 0x23, setID: 0x17},
47: {cat: 0x24, setID: 0x18},
48: {cat: 0x25, setID: 0x20},
49: {cat: 0x22, setID: 0x21},
50: {cat: 0x23, setID: 0x17},
51: {cat: 0x24, setID: 0x18},
52: {cat: 0x25, setID: 0x20},
53: {cat: 0x21, setID: 0x22},
54: {cat: 0x22, setID: 0x1},
55: {cat: 0x23, setID: 0x2},
56: {cat: 0x24, setID: 0x23},
57: {cat: 0x25, setID: 0x24},
} // Size: 140 bytes
35: {cat: 0x1a, setID: 0x16},
36: {cat: 0xf, setID: 0x17},
37: {cat: 0x1b, setID: 0x18},
38: {cat: 0xf, setID: 0x1c},
39: {cat: 0x1d, setID: 0x1d},
40: {cat: 0xa, setID: 0x1e},
41: {cat: 0xa, setID: 0x1f},
42: {cat: 0xc, setID: 0x20},
43: {cat: 0xe4, setID: 0x0},
44: {cat: 0x5, setID: 0x3},
45: {cat: 0xd, setID: 0xe},
46: {cat: 0xd, setID: 0x21},
47: {cat: 0x22, setID: 0x1},
48: {cat: 0x23, setID: 0x19},
49: {cat: 0x24, setID: 0x1a},
50: {cat: 0x25, setID: 0x22},
51: {cat: 0x22, setID: 0x23},
52: {cat: 0x23, setID: 0x19},
53: {cat: 0x24, setID: 0x1a},
54: {cat: 0x25, setID: 0x22},
55: {cat: 0x22, setID: 0x24},
56: {cat: 0x23, setID: 0x19},
57: {cat: 0x24, setID: 0x1a},
58: {cat: 0x25, setID: 0x22},
59: {cat: 0x21, setID: 0x25},
60: {cat: 0x22, setID: 0x1},
61: {cat: 0x23, setID: 0x2},
62: {cat: 0x24, setID: 0x26},
63: {cat: 0x25, setID: 0x27},
} // Size: 152 bytes
var ordinalIndex = []uint8{ // 20 elements
var ordinalIndex = []uint8{ // 22 elements
0x00, 0x00, 0x02, 0x03, 0x04, 0x05, 0x07, 0x09,
0x0d, 0x0e, 0x11, 0x14, 0x1a, 0x1d, 0x20, 0x26,
0x2d, 0x31, 0x35, 0x3a,
} // Size: 44 bytes
0x0b, 0x0f, 0x10, 0x13, 0x16, 0x1c, 0x1f, 0x22,
0x28, 0x2f, 0x33, 0x37, 0x3b, 0x40,
} // Size: 46 bytes
var ordinalLangToIndex = []uint8{ // 754 elements
var ordinalLangToIndex = []uint8{ // 768 elements
// Entry 0 - 3F
0x00, 0x0d, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x0e, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x11, 0x11, 0x00, 0x00, 0x00, 0x00,
0x0f, 0x00, 0x00, 0x0f, 0x0f, 0x00, 0x00, 0x05,
0x00, 0x00, 0x12, 0x12, 0x00, 0x00, 0x00, 0x00,
0x10, 0x00, 0x00, 0x10, 0x10, 0x00, 0x00, 0x05,
0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// Entry 40 - 7F
0x00, 0x00, 0x11, 0x11, 0x11, 0x00, 0x00, 0x00,
0x00, 0x00, 0x12, 0x12, 0x12, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x0d, 0x0d, 0x0d, 0x0d, 0x0d, 0x00, 0x00,
0x00, 0x0e, 0x0e, 0x0e, 0x0e, 0x0e, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x12, 0x12, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x14, 0x14,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// Entry 80 - BF
0x00, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x0b, 0x0b,
0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
// Entry C0 - FF
0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
// Entry C0 - FF
0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// Entry 100 - 13F
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x00,
0x00, 0x00, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x02, 0x02, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02,
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
// Entry 140 - 17F
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
0x02, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10,
0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x10,
0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x03, 0x02,
0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x02, 0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00,
0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x11, 0x11, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x11, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00,
0x03, 0x03, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00,
// Entry 180 - 1BF
0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09,
0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x07,
0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x09, 0x09,
0x09, 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x0a, 0x0a, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x08, 0x08, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// Entry 1C0 - 1FF
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0e, 0x0e,
0x00, 0x00, 0x00, 0x00, 0x0c, 0x0c, 0x02, 0x02,
0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x0f, 0x0f, 0x00, 0x00, 0x00, 0x00,
0x0d, 0x0d, 0x02, 0x02, 0x02, 0x02, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// Entry 200 - 23F
0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x04, 0x04,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x04, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x13, 0x13,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// Entry 240 - 27F
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x02, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x02, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -164,57 +170,58 @@ var ordinalLangToIndex = []uint8{ // 754 elements
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// Entry 280 - 2BF
0x00, 0x0a, 0x0a, 0x0a, 0x0a, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0b,
0x0b, 0x0b, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x01, 0x01, 0x01, 0x01, 0x00,
0x00, 0x01, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x07, 0x07, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x06, 0x06, 0x00, 0x00,
// Entry 2C0 - 2FF
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x06,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x02,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x02, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00,
} // Size: 778 bytes
} // Size: 792 bytes
var ordinalInclusionMasks = []uint64{ // 100 elements
// Entry 0 - 1F
0x0000000400004009, 0x00000002120800d3, 0x0000000010a10195, 0x0000000842810581,
0x0000000841030081, 0x0000001210010041, 0x0000001100011001, 0x0000000614010001,
0x0000000614018001, 0x0000000600012001, 0x0000000200014001, 0x0000000010198031,
0x0000000010610331, 0x0000000040010f01, 0x0000000040070001, 0x0000000010010001,
0x0000000000011001, 0x000000001c010001, 0x000000001c010001, 0x0000000000012001,
0x0000000020014001, 0x0000000010080011, 0x0000000010200111, 0x0000000040000501,
0x0000000040020001, 0x0000000010000001, 0x0000000000001001, 0x0000000014000001,
0x0000000014000001, 0x0000000000002001, 0x0000000000004001, 0x0000000010080011,
0x0000002000010009, 0x00000018482000d3, 0x0000000042840195, 0x000000410a040581,
0x00000041040c0081, 0x0000009840040041, 0x0000008400045001, 0x0000003850040001,
0x0000003850060001, 0x0000003800049001, 0x0000000800052001, 0x0000000040660031,
0x0000000041840331, 0x0000000100040f01, 0x00000001001c0001, 0x0000000040040001,
0x0000000000045001, 0x0000000070040001, 0x0000000070040001, 0x0000000000049001,
0x0000000080050001, 0x0000000040200011, 0x0000000040800111, 0x0000000100000501,
0x0000000100080001, 0x0000000040000001, 0x0000000000005001, 0x0000000050000001,
0x0000000050000001, 0x0000000000009001, 0x0000000000010001, 0x0000000040200011,
// Entry 20 - 3F
0x0000000010200111, 0x0000000040000501, 0x0000000040020001, 0x0000000010000001,
0x0000000000001001, 0x0000000014000001, 0x0000000014000001, 0x0000000000002001,
0x0000000080014001, 0x0000000010080011, 0x0000000010200111, 0x0000000040000501,
0x0000000040020001, 0x0000000010000001, 0x0000000000001001, 0x0000000014000001,
0x0000000014000001, 0x0000000000002001, 0x0000000020004001, 0x0000000010080011,
0x0000000010200111, 0x0000000040000501, 0x0000000040020001, 0x0000000010000001,
0x0000000000001001, 0x0000000014000001, 0x0000000014000001, 0x0000000000002001,
0x0000000080014001, 0x0000000010080011, 0x0000000010200111, 0x0000000040000501,
0x0000000040800111, 0x0000000100000501, 0x0000000100080001, 0x0000000040000001,
0x0000000000005001, 0x0000000050000001, 0x0000000050000001, 0x0000000000009001,
0x0000000200050001, 0x0000000040200011, 0x0000000040800111, 0x0000000100000501,
0x0000000100080001, 0x0000000040000001, 0x0000000000005001, 0x0000000050000001,
0x0000000050000001, 0x0000000000009001, 0x0000000080010001, 0x0000000040200011,
0x0000000040800111, 0x0000000100000501, 0x0000000100080001, 0x0000000040000001,
0x0000000000005001, 0x0000000050000001, 0x0000000050000001, 0x0000000000009001,
0x0000000200050001, 0x0000000040200011, 0x0000000040800111, 0x0000000100000501,
// Entry 40 - 5F
0x0000000040020001, 0x0000000010000001, 0x0000000000001001, 0x0000000014000001,
0x0000000014000001, 0x0000000000002001, 0x0000000020004001, 0x0000000010080011,
0x0000000010200111, 0x0000000040000501, 0x0000000040020001, 0x0000000010000001,
0x0000000000001001, 0x0000000014000001, 0x0000000014000001, 0x0000000000002001,
0x000000002001c001, 0x0000000010080011, 0x0000000010200111, 0x0000000040000501,
0x0000000040020001, 0x0000000010000001, 0x0000000000001001, 0x0000000014000001,
0x0000000014000001, 0x0000000000002001, 0x0000000080004001, 0x0000000010080011,
0x0000000010200111, 0x0000000040000501, 0x0000000040020001, 0x0000000010000001,
0x0000000100080001, 0x0000000040000001, 0x0000000000005001, 0x0000000050000001,
0x0000000050000001, 0x0000000000009001, 0x0000000080010001, 0x0000000040200011,
0x0000000040800111, 0x0000000100000501, 0x0000000100080001, 0x0000000040000001,
0x0000000000005001, 0x0000000050000001, 0x0000000050000001, 0x0000000000009001,
0x0000000080070001, 0x0000000040200011, 0x0000000040800111, 0x0000000100000501,
0x0000000100080001, 0x0000000040000001, 0x0000000000005001, 0x0000000050000001,
0x0000000050000001, 0x0000000000009001, 0x0000000200010001, 0x0000000040200011,
0x0000000040800111, 0x0000000100000501, 0x0000000100080001, 0x0000000040000001,
// Entry 60 - 7F
0x0000000000001001, 0x0000000014000001, 0x0000000014000001, 0x0000000000002001,
0x0000000000005001, 0x0000000050000001, 0x0000000050000001, 0x0000000000009001,
} // Size: 824 bytes
// Slots used for ordinal: 3A of 0xFF rules; 14 of 0xFF indexes; 37 of 64 sets
// Slots used for ordinal: 40 of 0xFF rules; 16 of 0xFF indexes; 40 of 64 sets
var cardinalRules = []pluralCheck{ // 166 elements
0: {cat: 0x2, setID: 0x3},
@@ -393,7 +400,7 @@ var cardinalIndex = []uint8{ // 36 elements
0x95, 0x9c, 0xa1, 0xa6,
} // Size: 60 bytes
var cardinalLangToIndex = []uint8{ // 754 elements
var cardinalLangToIndex = []uint8{ // 768 elements
// Entry 0 - 3F
0x00, 0x04, 0x04, 0x08, 0x08, 0x08, 0x00, 0x00,
0x06, 0x06, 0x01, 0x01, 0x21, 0x21, 0x21, 0x21,
@@ -406,14 +413,14 @@ var cardinalLangToIndex = []uint8{ // 754 elements
// Entry 40 - 7F
0x00, 0x00, 0x01, 0x01, 0x01, 0x00, 0x00, 0x00,
0x1e, 0x1e, 0x08, 0x08, 0x13, 0x00, 0x00, 0x13,
0x13, 0x04, 0x04, 0x04, 0x04, 0x04, 0x08, 0x08,
0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x18,
0x18, 0x00, 0x00, 0x22, 0x22, 0x09, 0x09, 0x09,
0x00, 0x00, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
0x04, 0x04, 0x00, 0x00, 0x16, 0x16, 0x00, 0x00,
0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08,
0x13, 0x04, 0x04, 0x04, 0x04, 0x04, 0x00, 0x00,
0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
0x08, 0x08, 0x18, 0x18, 0x00, 0x00, 0x22, 0x22,
0x09, 0x09, 0x09, 0x00, 0x00, 0x04, 0x04, 0x04,
0x04, 0x04, 0x04, 0x04, 0x04, 0x00, 0x00, 0x16,
0x16, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00,
// Entry 80 - BF
0x08, 0x08, 0x08, 0x08, 0x08, 0x04, 0x04, 0x04,
0x00, 0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
@@ -427,81 +434,82 @@ var cardinalLangToIndex = []uint8{ // 754 elements
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x08, 0x08,
0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
0x04, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
// Entry 100 - 13F
0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
0x08, 0x08, 0x08, 0x08, 0x08, 0x04, 0x04, 0x08,
0x08, 0x00, 0x00, 0x01, 0x01, 0x01, 0x02, 0x02,
0x02, 0x02, 0x02, 0x04, 0x04, 0x0c, 0x0c, 0x08,
0x08, 0x08, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
0x04, 0x04, 0x08, 0x08, 0x00, 0x00, 0x01, 0x01,
0x01, 0x02, 0x02, 0x02, 0x02, 0x02, 0x04, 0x04,
0x0c, 0x0c, 0x08, 0x08, 0x08, 0x02, 0x02, 0x02,
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
// Entry 140 - 17F
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
0x02, 0x08, 0x08, 0x04, 0x04, 0x1f, 0x1f, 0x14,
0x14, 0x04, 0x04, 0x08, 0x08, 0x08, 0x08, 0x01,
0x01, 0x06, 0x00, 0x00, 0x20, 0x20, 0x08, 0x08,
0x08, 0x08, 0x08, 0x08, 0x17, 0x17, 0x01, 0x01,
0x13, 0x13, 0x13, 0x16, 0x16, 0x08, 0x08, 0x02,
0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0a,
0x02, 0x02, 0x02, 0x02, 0x08, 0x08, 0x04, 0x04,
0x1f, 0x1f, 0x14, 0x14, 0x04, 0x04, 0x08, 0x08,
0x08, 0x08, 0x01, 0x01, 0x06, 0x00, 0x00, 0x20,
0x20, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x17,
0x17, 0x01, 0x01, 0x13, 0x13, 0x13, 0x16, 0x16,
0x08, 0x08, 0x02, 0x02, 0x00, 0x00, 0x00, 0x00,
// Entry 180 - 1BF
0x0a, 0x04, 0x04, 0x04, 0x04, 0x04, 0x10, 0x00,
0x00, 0x00, 0x08, 0x08, 0x08, 0x08, 0x00, 0x08,
0x08, 0x02, 0x02, 0x08, 0x00, 0x00, 0x08, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08,
0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00,
0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x0f, 0x0f,
0x08, 0x10, 0x10, 0x08, 0x08, 0x0e, 0x0e, 0x08,
0x00, 0x00, 0x04, 0x0a, 0x0a, 0x04, 0x04, 0x04,
0x04, 0x04, 0x10, 0x00, 0x00, 0x00, 0x08, 0x08,
0x08, 0x08, 0x00, 0x08, 0x08, 0x02, 0x02, 0x08,
0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x08, 0x08, 0x08, 0x08, 0x08,
0x08, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00,
0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x08, 0x08,
0x00, 0x00, 0x0f, 0x0f, 0x08, 0x10, 0x10, 0x08,
// Entry 1C0 - 1FF
0x08, 0x08, 0x08, 0x00, 0x00, 0x06, 0x06, 0x06,
0x06, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b,
0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d,
0x0d, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00,
0x06, 0x06, 0x00, 0x00, 0x08, 0x08, 0x0b, 0x0b,
0x08, 0x08, 0x08, 0x08, 0x01, 0x01, 0x00, 0x00,
0x00, 0x00, 0x1c, 0x1c, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x08, 0x10, 0x10, 0x08, 0x08, 0x08,
0x08, 0x0e, 0x0e, 0x08, 0x08, 0x08, 0x08, 0x00,
0x00, 0x06, 0x06, 0x06, 0x06, 0x06, 0x00, 0x00,
0x00, 0x00, 0x00, 0x1b, 0x1b, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x0d, 0x0d, 0x08, 0x08, 0x08,
0x00, 0x00, 0x00, 0x00, 0x06, 0x06, 0x00, 0x00,
0x08, 0x08, 0x0b, 0x0b, 0x08, 0x08, 0x08, 0x08,
0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x1c,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x10,
// Entry 200 - 23F
0x08, 0x08, 0x00, 0x00, 0x00, 0x08, 0x08, 0x08,
0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
0x00, 0x00, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00,
0x08, 0x06, 0x00, 0x00, 0x08, 0x08, 0x08, 0x08,
0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x06,
0x00, 0x00, 0x06, 0x06, 0x08, 0x19, 0x19, 0x0d,
0x0d, 0x08, 0x08, 0x03, 0x03, 0x03, 0x03, 0x03,
0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03,
0x10, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00,
0x00, 0x08, 0x08, 0x08, 0x04, 0x04, 0x04, 0x04,
0x04, 0x04, 0x04, 0x04, 0x00, 0x00, 0x08, 0x08,
0x08, 0x08, 0x08, 0x00, 0x08, 0x06, 0x00, 0x00,
0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
0x08, 0x08, 0x08, 0x06, 0x00, 0x00, 0x06, 0x06,
0x08, 0x19, 0x19, 0x0d, 0x0d, 0x08, 0x08, 0x03,
0x04, 0x03, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
// Entry 240 - 27F
0x00, 0x00, 0x00, 0x00, 0x08, 0x08, 0x00, 0x00,
0x12, 0x12, 0x12, 0x08, 0x08, 0x1d, 0x1d, 0x1d,
0x1d, 0x1d, 0x1d, 0x1d, 0x00, 0x00, 0x08, 0x08,
0x00, 0x00, 0x08, 0x08, 0x00, 0x00, 0x08, 0x10,
0x10, 0x10, 0x10, 0x08, 0x08, 0x00, 0x00, 0x00,
0x00, 0x11, 0x00, 0x00, 0x11, 0x11, 0x05, 0x05,
0x18, 0x18, 0x15, 0x15, 0x10, 0x10, 0x10, 0x10,
0x10, 0x10, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
0x04, 0x04, 0x04, 0x04, 0x00, 0x00, 0x00, 0x00,
0x08, 0x08, 0x00, 0x00, 0x12, 0x12, 0x12, 0x08,
0x08, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d, 0x1d,
0x00, 0x00, 0x08, 0x08, 0x00, 0x00, 0x08, 0x08,
0x00, 0x00, 0x08, 0x08, 0x08, 0x10, 0x10, 0x10,
0x10, 0x08, 0x08, 0x00, 0x00, 0x00, 0x00, 0x11,
0x00, 0x00, 0x11, 0x11, 0x05, 0x05, 0x18, 0x18,
0x15, 0x15, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
// Entry 280 - 2BF
0x08, 0x08, 0x08, 0x08, 0x08, 0x13, 0x13, 0x13,
0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x13,
0x08, 0x08, 0x08, 0x04, 0x04, 0x04, 0x04, 0x04,
0x04, 0x04, 0x04, 0x04, 0x08, 0x08, 0x08, 0x08,
0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x00,
0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
0x08, 0x08, 0x08, 0x13, 0x13, 0x13, 0x13, 0x13,
0x13, 0x13, 0x13, 0x13, 0x13, 0x13, 0x08, 0x08,
0x08, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
0x04, 0x04, 0x08, 0x08, 0x08, 0x08, 0x08, 0x08,
0x08, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00, 0x00,
0x00, 0x06, 0x06, 0x06, 0x08, 0x08, 0x08, 0x08,
0x00, 0x00, 0x08, 0x08, 0x08, 0x08, 0x00, 0x00,
0x07, 0x07, 0x08, 0x08, 0x1d, 0x1d, 0x04, 0x04,
// Entry 2C0 - 2FF
0x04, 0x08, 0x00, 0x00, 0x00, 0x00, 0x08, 0x08,
0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00,
0x08, 0x08, 0x08, 0x08, 0x06, 0x08, 0x08, 0x00,
0x08, 0x08, 0x08, 0x00, 0x00, 0x04, 0x04, 0x00,
0x00, 0x00, 0x07, 0x07, 0x08, 0x08, 0x1d, 0x1d,
0x04, 0x04, 0x04, 0x08, 0x00, 0x00, 0x00, 0x00,
0x08, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08,
0x00, 0x00, 0x08, 0x08, 0x08, 0x08, 0x06, 0x08,
0x08, 0x00, 0x00, 0x08, 0x08, 0x08, 0x00, 0x00,
0x04, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x01, 0x01,
} // Size: 778 bytes
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01,
} // Size: 792 bytes
var cardinalInclusionMasks = []uint64{ // 100 elements
// Entry 0 - 1F
@@ -537,4 +545,4 @@ var cardinalInclusionMasks = []uint64{ // 100 elements
// Slots used for cardinal: A6 of 0xFF rules; 24 of 0xFF indexes; 37 of 64 sets
// Total table size 3804 bytes (3KiB); checksum: FFC009FC
// Total table size 3846 bytes (3KiB); checksum: B8556665
+5 -4
View File
@@ -117,14 +117,15 @@ pkg unicode, var <new script or property> *RangeTable
width = generate("./width", unicode)
bidi = generate("./unicode/bidi", unicode, norm, rangetable)
mib = generate("./encoding/internal/identifier", unicode)
number = generate("./internal/number", unicode, cldr, language, internal)
_ = generate("./encoding/htmlindex", unicode, language, mib)
_ = generate("./encoding/ianaindex", unicode, language, mib)
_ = generate("./secure/precis", unicode, norm, rangetable, cases, width, bidi)
_ = generate("./currency", unicode, cldr, language, internal)
_ = generate("./internal/number", unicode, cldr, language, internal)
_ = generate("./feature/plural", unicode, cldr, language, internal)
_ = generate("./internal/cldrtree", language)
_ = generate("./currency", unicode, cldr, language, internal, number)
_ = generate("./feature/plural", unicode, cldr, language, internal, number)
_ = generate("./internal/export/idna", unicode, bidi, norm)
_ = generate("./language/display", unicode, cldr, language, internal)
_ = generate("./language/display", unicode, cldr, language, internal, number)
_ = generate("./collate", unicode, norm, cldr, language, rangetable)
_ = generate("./search", unicode, norm, cldr, language, rangetable)
)
+58 -9
View File
@@ -74,13 +74,6 @@ import (
// A Handle refers to a registered message type.
type Handle int
// First is used as a Handle to EncodeMessageType, followed by a series of calls
// to EncodeMessage, to implement selecting the first matching Message.
//
// TODO: this can be removed once we either can use type aliases or if the
// internals of this package are merged with the catalog package.
var First Handle = msgFirst
// A Handler decodes and evaluates data compiled by a Message and sends the
// result to the Decoder. The output may depend on the value of the substitution
// arguments, accessible by the Decoder's Arg method. The Handler returns false
@@ -111,20 +104,24 @@ const (
msgFirst
msgRaw
msgString
numFixed
msgAffix
// Leave some arbitrary room for future expansion: 20 should suffice.
numInternal = 20
)
const prefix = "golang.org/x/text/internal/catmsg."
var (
// TODO: find a more stable way to link handles to message types.
mutex sync.Mutex
names = map[string]Handle{
prefix + "Vars": msgVars,
prefix + "First": msgFirst,
prefix + "Raw": msgRaw,
prefix + "String": msgString,
prefix + "Affix": msgAffix,
}
handlers = make([]Handler, numFixed)
handlers = make([]Handler, numInternal)
)
func init() {
@@ -168,6 +165,20 @@ func init() {
}
return true
}
handlers[msgAffix] = func(d *Decoder) bool {
// TODO: use an alternative method for common cases.
prefix := d.DecodeString()
suffix := d.DecodeString()
if prefix != "" {
d.Render(prefix)
}
ret := d.ExecuteMessage()
if suffix != "" {
d.Render(suffix)
}
return ret
}
}
var (
@@ -236,6 +247,23 @@ func Compile(tag language.Tag, macros Dictionary, m Message) (data string, err e
return string(buf), err
}
// FirstOf is a message type that prints the first message in the sequence that
// resolves to a match for the given substitution arguments.
type FirstOf []Message
// Compile implements Message.
func (s FirstOf) Compile(e *Encoder) error {
e.EncodeMessageType(msgFirst)
err := ErrIncomplete
for i, m := range s {
if err == nil {
return fmt.Errorf("catalog: message argument %d is complete and blocks subsequent messages", i-1)
}
err = e.EncodeMessage(m)
}
return err
}
// Var defines a message that can be substituted for a placeholder of the same
// name. If an expression does not result in a string after evaluation, Name is
// used as the substitution. For example:
@@ -364,3 +392,24 @@ func (s String) Compile(e *Encoder) (err error) {
}
return err
}
// Affix is a message that adds a prefix and suffix to another message.
// This is mostly used add back whitespace to a translation that was stripped
// before sending it out.
type Affix struct {
Message Message
Prefix string
Suffix string
}
// Compile implements Message.
func (a Affix) Compile(e *Encoder) (err error) {
// TODO: consider adding a special message type that just adds a single
// return. This is probably common enough to handle the majority of cases.
// Get some stats first, though.
e.EncodeMessageType(msgAffix)
e.EncodeString(a.Prefix)
e.EncodeString(a.Suffix)
e.EncodeMessage(a.Message)
return nil
}
+13 -2
View File
@@ -70,6 +70,10 @@ func TestCodec(t *testing.T) {
desc: "simple string",
m: String("foo"),
tests: single("foo", ""),
}, {
desc: "affix",
m: &Affix{String("foo"), "\t", "\n"},
tests: single("\t|foo|\n", ""),
}, {
desc: "missing var",
m: String("foo${bar}"),
@@ -100,6 +104,13 @@ func TestCodec(t *testing.T) {
String("foo${bar}"),
},
tests: single("foo|baz", ""),
}, {
desc: "affix with substitution",
m: &Affix{seq{
&Var{"bar", String("baz")},
String("foo${bar}"),
}, "\t", "\n"},
tests: single("\t|foo|baz|\n", ""),
}, {
desc: "shadowed variable",
m: seq{
@@ -140,7 +151,7 @@ func TestCodec(t *testing.T) {
&Var{"bar", incomplete{}},
String("${bar}"),
},
enc: "\x00\t\b\x01\x01\x04\x04\x02bar\x03\x00\x00\x00",
enc: "\x00\t\b\x01\x01\x14\x04\x02bar\x03\x00\x00\x00",
// TODO: recognize that it is cheaper to substitute bar.
tests: single("bar", ""),
}, {
@@ -246,7 +257,7 @@ type seq []Message
func (s seq) Compile(e *Encoder) (err error) {
err = ErrIncomplete
e.EncodeMessageType(First)
e.EncodeMessageType(msgFirst)
for _, m := range s {
// Pass only the last error, but allow erroneous or complete messages
// here to allow testing different scenarios.
Generated Vendored Executable → Regular
+1 -1
View File
@@ -169,7 +169,7 @@ func (e *Encoder) addVar(key string, m Message) error {
case err == ErrIncomplete:
if Handle(e.buf[0]) != msgFirst {
seq := &Encoder{root: e.root, parent: e}
seq.EncodeMessageType(First)
seq.EncodeMessageType(msgFirst)
e.flushTo(seq)
e = seq
}
+353
View File
@@ -0,0 +1,353 @@
// Copyright 2017 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 cldrtree builds and generates a CLDR index file, including all
// inheritance.
//
package cldrtree
//go:generate go test -gen
// cldrtree stores CLDR data in a tree-like structure called Tree. In the CLDR
// data each branch in the tree is indicated by either an element name or an
// attribute value. A Tree does not distinguish between these two cases, but
// rather assumes that all branches can be accessed by an enum with a compact
// range of positive integer values starting from 0.
//
// Each Tree consists of three parts:
// - a slice mapping compact language identifiers to an offset into a set of
// indices,
// - a set of indices, stored as a large blob of uint16 values that encode
// the actual tree structure of data, and
// - a set of buckets that each holds a collection of strings.
// each of which is explained in more detail below.
//
//
// Tree lookup
// A tree lookup is done by providing a locale and a "path", which is a
// sequence of enum values. The search starts with getting the index for the
// given locale and then incrementally jumping into the index using the path
// values. If an element cannot be found in the index, the search starts anew
// for the locale's parent locale. The path may change during lookup by means
// of aliasing, described below.
//
// Buckets
// Buckets hold the actual string data of the leaf values of the CLDR tree.
// This data is stored in buckets, rather than one large string, for multiple
// reasons:
// - it allows representing leaf values more compactly, by storing all leaf
// values in a single bucket and then needing only needing a uint16 to index
// into this bucket for all leaf values,
// - (TBD) allow multiple trees to share subsets of buckets, mostly to allow
// linking in a smaller amount of data if only a subset of the buckets is
// needed,
// - to be nice to go fmt and the compiler.
//
// indices
// An index is a slice of uint16 for which the values are interpreted in one of
// two ways: as a node or a set of leaf values.
// A set of leaf values has the following form:
// <max_size>, <bucket>, <offset>...
// max_size indicates the maximum enum value for which an offset is defined.
// An offset value of 0xFFFF (missingValue) also indicates an undefined value.
// If defined offset indicates the offset within the given bucket of the string.
// A node value has the following form:
// <max_size>, <offset_or_alias>...
// max_size indicates the maximum value for which an offset is defined.
// A missing offset may also be indicated with 0. If the high bit (0x8000, or
// inheritMask) is not set, the offset points to the offset within the index
// for the current locale.
// An offset with high bit set is an alias. In this case the uint16 has the form
// bits:
// 15: 1
// 14-12: negative offset into path relative to current position
// 0-11: new enum value for path element.
// On encountering an alias, the path is modified accordingly and the lookup is
// restarted for the given locale.
import (
"fmt"
"reflect"
"regexp"
"strings"
"unicode/utf8"
"golang.org/x/text/internal/gen"
"golang.org/x/text/language"
"golang.org/x/text/unicode/cldr"
)
// TODO:
// - allow two Trees to share the same set of buckets.
// A Builder allows storing CLDR data in compact form.
type Builder struct {
table []string
rootMeta *metaData
locales []locale
strToBucket map[string]stringInfo
buckets [][]byte
enums []*enum
err error
// Stats
size int
sizeAll int
bucketWaste int
}
const (
maxBucketSize = 8 * 1024 // 8K
maxStrlen = 254 // allow 0xFF sentinel
)
func (b *Builder) setError(err error) {
if b.err == nil {
b.err = err
}
}
func (b *Builder) addString(data string) stringInfo {
data = b.makeString(data)
info, ok := b.strToBucket[data]
if !ok {
b.size += len(data)
x := len(b.buckets) - 1
bucket := b.buckets[x]
if len(bucket)+len(data) < maxBucketSize {
info.bucket = uint16(x)
info.bucketPos = uint16(len(bucket))
b.buckets[x] = append(bucket, data...)
} else {
info.bucket = uint16(len(b.buckets))
info.bucketPos = 0
b.buckets = append(b.buckets, []byte(data))
}
b.strToBucket[data] = info
}
return info
}
func (b *Builder) addStringToBucket(data string, bucket uint16) stringInfo {
data = b.makeString(data)
info, ok := b.strToBucket[data]
if !ok || info.bucket != bucket {
if ok {
b.bucketWaste += len(data)
}
b.size += len(data)
bk := b.buckets[bucket]
info.bucket = bucket
info.bucketPos = uint16(len(bk))
b.buckets[bucket] = append(bk, data...)
b.strToBucket[data] = info
}
return info
}
func (b *Builder) makeString(data string) string {
if len(data) > maxStrlen {
b.setError(fmt.Errorf("string %q exceeds maximum length of %d", data, maxStrlen))
data = data[:maxStrlen]
for i := len(data) - 1; i > len(data)-4; i-- {
if utf8.RuneStart(data[i]) {
data = data[:i]
break
}
}
}
data = string([]byte{byte(len(data))}) + data
b.sizeAll += len(data)
return data
}
type stringInfo struct {
bufferPos uint32
bucket uint16
bucketPos uint16
}
// New creates a new Builder.
func New(tableName string) *Builder {
b := &Builder{
strToBucket: map[string]stringInfo{},
buckets: [][]byte{nil}, // initialize with first bucket.
}
b.rootMeta = &metaData{
b: b,
typeInfo: &typeInfo{},
}
return b
}
// Gen writes all the tables and types for the collected data.
func (b *Builder) Gen(w *gen.CodeWriter) error {
t, err := build(b)
if err != nil {
return err
}
return generate(b, t, w)
}
// GenTestData generates tables useful for testing data generated with Gen.
func (b *Builder) GenTestData(w *gen.CodeWriter) error {
return generateTestData(b, w)
}
type locale struct {
tag language.Tag
root *Index
}
// Locale creates an index for the given locale.
func (b *Builder) Locale(t language.Tag) *Index {
index := &Index{
meta: b.rootMeta,
}
b.locales = append(b.locales, locale{tag: t, root: index})
return index
}
// An Index holds a map of either leaf values or other indices.
type Index struct {
meta *metaData
subIndex []*Index
values []keyValue
}
func (i *Index) setError(err error) { i.meta.b.setError(err) }
type keyValue struct {
key enumIndex
value stringInfo
}
// Element is a CLDR XML element.
type Element interface {
GetCommon() *cldr.Common
}
// Index creates a subindex where the type and enum values are not shared
// with siblings by default. The name is derived from the elem. If elem is
// an alias reference, the alias will be resolved and linked. If elem is nil
// Index returns nil.
func (i *Index) Index(elem Element, opt ...Option) *Index {
if elem == nil || reflect.ValueOf(elem).IsNil() {
return nil
}
c := elem.GetCommon()
o := &options{
parent: i,
name: c.GetCommon().Element(),
}
o.fill(opt)
o.setAlias(elem)
return i.subIndexForKey(o)
}
// IndexWithName is like Section but derives the name from the given name.
func (i *Index) IndexWithName(name string, opt ...Option) *Index {
o := &options{parent: i, name: name}
o.fill(opt)
return i.subIndexForKey(o)
}
// IndexFromType creates a subindex the value of tye type attribute as key. It
// will also configure the Index to share the enumeration values with all
// sibling values. If elem is an alias, it will be resolved and linked.
func (i *Index) IndexFromType(elem Element, opts ...Option) *Index {
o := &options{
parent: i,
name: elem.GetCommon().Type,
}
o.fill(opts)
o.setAlias(elem)
useSharedType()(o)
return i.subIndexForKey(o)
}
// IndexFromAlt creates a subindex the value of tye alt attribute as key. It
// will also configure the Index to share the enumeration values with all
// sibling values. If elem is an alias, it will be resolved and linked.
func (i *Index) IndexFromAlt(elem Element, opts ...Option) *Index {
o := &options{
parent: i,
name: elem.GetCommon().Alt,
}
o.fill(opts)
o.setAlias(elem)
useSharedType()(o)
return i.subIndexForKey(o)
}
func (i *Index) subIndexForKey(opts *options) *Index {
key := opts.name
if len(i.values) > 0 {
panic(fmt.Errorf("cldrtree: adding Index for %q when value already exists", key))
}
meta := i.meta.sub(key, opts)
for _, x := range i.subIndex {
if x.meta == meta {
return x
}
}
if alias := opts.alias; alias != nil {
if a := alias.GetCommon().Alias; a != nil {
if a.Source != "locale" {
i.setError(fmt.Errorf("cldrtree: non-locale alias not supported %v", a.Path))
}
if meta.inheritOffset < 0 {
i.setError(fmt.Errorf("cldrtree: alias was already set %v", a.Path))
}
path := a.Path
for ; strings.HasPrefix(path, "../"); path = path[len("../"):] {
meta.inheritOffset--
}
m := aliasRe.FindStringSubmatch(path)
if m == nil {
i.setError(fmt.Errorf("cldrtree: could not parse alias %q", a.Path))
} else {
key := m[4]
if key == "" {
key = m[1]
}
meta.inheritIndex = key
}
}
}
x := &Index{meta: meta}
i.subIndex = append(i.subIndex, x)
return x
}
var aliasRe = regexp.MustCompile(`^([a-zA-Z]+)(\[@([a-zA-Z-]+)='([a-zA-Z-]+)'\])?`)
// SetValue sets the value, the data from a CLDR XML element, for the given key.
func (i *Index) SetValue(key string, value Element, opt ...Option) {
if len(i.subIndex) > 0 {
panic(fmt.Errorf("adding value for key %q when index already exists", key))
}
o := &options{parent: i}
o.fill(opt)
c := value.GetCommon()
if c.Alias != nil {
i.setError(fmt.Errorf("cldrtree: alias not supported for SetValue %v", c.Alias.Path))
}
i.setValue(key, c.Data(), o)
}
func (i *Index) setValue(key, data string, o *options) {
index, _ := i.meta.typeInfo.lookupSubtype(key, o)
kv := keyValue{key: index}
if len(i.values) > 0 {
// Add string to the same bucket as the other values.
bucket := i.values[0].value.bucket
kv.value = i.meta.b.addStringToBucket(data, bucket)
} else {
kv.value = i.meta.b.addString(data)
}
i.values = append(i.values, kv)
}
+456
View File
@@ -0,0 +1,456 @@
// Copyright 2017 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 cldrtree
import (
"bytes"
"flag"
"io/ioutil"
"log"
"math/rand"
"path/filepath"
"reflect"
"regexp"
"strconv"
"strings"
"testing"
"golang.org/x/text/internal/gen"
"golang.org/x/text/language"
"golang.org/x/text/unicode/cldr"
)
var genOutput = flag.Bool("gen", false, "generate output files")
func TestAliasRegexp(t *testing.T) {
testCases := []struct {
alias string
want []string
}{{
alias: "miscPatterns[@numberSystem='latn']",
want: []string{
"miscPatterns[@numberSystem='latn']",
"miscPatterns",
"[@numberSystem='latn']",
"numberSystem",
"latn",
},
}, {
alias: `calendar[@type='greg-foo']/days/`,
want: []string{
"calendar[@type='greg-foo']",
"calendar",
"[@type='greg-foo']",
"type",
"greg-foo",
},
}, {
alias: "eraAbbr",
want: []string{
"eraAbbr",
"eraAbbr",
"",
"",
"",
},
}, {
// match must be anchored at beginning.
alias: `../calendar[@type='gregorian']/days/`,
}}
for _, tc := range testCases {
t.Run(tc.alias, func(t *testing.T) {
got := aliasRe.FindStringSubmatch(tc.alias)
if !reflect.DeepEqual(got, tc.want) {
t.Errorf("got %v; want %v", got, tc.want)
}
})
}
}
func TestBuild(t *testing.T) {
tree1, _ := loadTestdata(t, "test1")
tree2, _ := loadTestdata(t, "test2")
// Constants for second test test
const (
calendar = iota
field
)
const (
month = iota
era
filler
cyclicNameSet
)
const (
abbreviated = iota
narrow
wide
)
testCases := []struct {
desc string
tree *Tree
locale string
path []uint16
isFeature bool
result string
}{{
desc: "und/chinese month format wide m1",
tree: tree1,
locale: "und",
path: path(calendar, 0, month, 0, wide, 1),
result: "cM01",
}, {
desc: "und/chinese month format wide m12",
tree: tree1,
locale: "und",
path: path(calendar, 0, month, 0, wide, 12),
result: "cM12",
}, {
desc: "und/non-existing value",
tree: tree1,
locale: "und",
path: path(calendar, 0, month, 0, wide, 13),
result: "",
}, {
desc: "und/dangi:chinese month format wide",
tree: tree1,
locale: "und",
path: path(calendar, 1, month, 0, wide, 1),
result: "cM01",
}, {
desc: "und/chinese month format abbreviated:wide",
tree: tree1,
locale: "und",
path: path(calendar, 0, month, 0, abbreviated, 1),
result: "cM01",
}, {
desc: "und/chinese month format narrow:wide",
tree: tree1,
locale: "und",
path: path(calendar, 0, month, 0, narrow, 1),
result: "cM01",
}, {
desc: "und/gregorian month format wide",
tree: tree1,
locale: "und",
path: path(calendar, 2, month, 0, wide, 2),
result: "gM02",
}, {
desc: "und/gregorian month format:stand-alone narrow",
tree: tree1,
locale: "und",
path: path(calendar, 2, month, 0, narrow, 1),
result: "1",
}, {
desc: "und/gregorian month stand-alone:format abbreviated",
tree: tree1,
locale: "und",
path: path(calendar, 2, month, 1, abbreviated, 1),
result: "gM01",
}, {
desc: "und/gregorian month stand-alone:format wide ",
tree: tree1,
locale: "und",
path: path(calendar, 2, month, 1, abbreviated, 1),
result: "gM01",
}, {
desc: "und/dangi:chinese month format narrow:wide ",
tree: tree1,
locale: "und",
path: path(calendar, 1, month, 0, narrow, 4),
result: "cM04",
}, {
desc: "und/field era displayname 0",
tree: tree2,
locale: "und",
path: path(field, 0, 0, 0),
result: "Era",
}, {
desc: "en/field era displayname 0",
tree: tree2,
locale: "en",
path: path(field, 0, 0, 0),
result: "era",
}, {
desc: "und/calendar hebrew format wide 7-leap",
tree: tree2,
locale: "und",
path: path(calendar, 7, month, 0, wide, 0),
result: "Adar II",
}, {
desc: "en-GB:en-001:en:und/calendar hebrew format wide 7-leap",
tree: tree2,
locale: "en-GB",
path: path(calendar, 7, month, 0, wide, 0),
result: "Adar II",
}, {
desc: "und/buddhist month format wide 11",
tree: tree2,
locale: "und",
path: path(calendar, 0, month, 0, wide, 12),
result: "genWideM12",
}, {
desc: "en-GB/gregorian month stand-alone narrow 2",
tree: tree2,
locale: "en-GB",
path: path(calendar, 6, month, 1, narrow, 3),
result: "gbNarrowM3",
}, {
desc: "en-GB/gregorian month format narrow 3/missing in en-GB",
tree: tree2,
locale: "en-GB",
path: path(calendar, 6, month, 0, narrow, 4),
result: "enNarrowM4",
}, {
desc: "en-GB/gregorian month format narrow 3/missing in en and en-GB",
tree: tree2,
locale: "en-GB",
path: path(calendar, 6, month, 0, narrow, 7),
result: "gregNarrowM7",
}, {
desc: "en-GB/gregorian month format narrow 3/missing in en and en-GB",
tree: tree2,
locale: "en-GB",
path: path(calendar, 6, month, 0, narrow, 7),
result: "gregNarrowM7",
}, {
desc: "en-GB/gregorian era narrow",
tree: tree2,
locale: "en-GB",
path: path(calendar, 6, era, abbreviated, 0, 1),
isFeature: true,
result: "AD",
}, {
desc: "en-GB/gregorian era narrow",
tree: tree2,
locale: "en-GB",
path: path(calendar, 6, era, narrow, 0, 0),
isFeature: true,
result: "BC",
}, {
desc: "en-GB/gregorian era narrow",
tree: tree2,
locale: "en-GB",
path: path(calendar, 6, era, wide, 1, 0),
isFeature: true,
result: "Before Common Era",
}, {
desc: "en-GB/dangi:chinese cyclicName, months, format, narrow:abbreviated 2",
tree: tree2,
locale: "en-GB",
path: path(calendar, 1, cyclicNameSet, 3, 0, 1, 2),
isFeature: true,
result: "year2",
}, {
desc: "en-GB/field era-narrow ",
tree: tree2,
locale: "en-GB",
path: path(field, 2, 0, 0),
result: "era",
}, {
desc: "en-GB/field month-narrow relativeTime future one",
tree: tree2,
locale: "en-GB",
path: path(field, 5, 2, 0, 1),
isFeature: true,
result: "001NarrowFutMOne",
}, {
// Don't fall back to the one of "en".
desc: "en-GB/field month-short relativeTime past one:other",
tree: tree2,
locale: "en-GB",
path: path(field, 4, 2, 1, 1),
isFeature: true,
result: "001ShortPastMOther",
}, {
desc: "en-GB/field month relativeTime future two:other",
tree: tree2,
locale: "en-GB",
path: path(field, 3, 2, 0, 2),
isFeature: true,
result: "enFutMOther",
}}
for _, tc := range testCases {
t.Run(tc.desc, func(t *testing.T) {
tag, _ := language.CompactIndex(language.MustParse(tc.locale))
s := tc.tree.lookup(tag, tc.isFeature, tc.path...)
if s != tc.result {
t.Errorf("got %q; want %q", s, tc.result)
}
})
}
}
func path(e ...uint16) []uint16 { return e }
func TestGen(t *testing.T) {
testCases := []string{"test1", "test2"}
for _, tc := range testCases {
t.Run(tc, func(t *testing.T) {
_, got := loadTestdata(t, tc)
// Remove sizes that may vary per architecture.
re := regexp.MustCompile("// Size: [0-9]*")
got = re.ReplaceAllLiteral(got, []byte("// Size: xxxx"))
re = regexp.MustCompile("// Total table size [0-9]*")
got = re.ReplaceAllLiteral(got, []byte("// Total table size: xxxx"))
file := filepath.Join("testdata", tc, "output.go")
if *genOutput {
ioutil.WriteFile(file, got, 0700)
t.SkipNow()
}
b, err := ioutil.ReadFile(file)
if err != nil {
t.Fatalf("failed to open file: %v", err)
}
if want := string(b); string(got) != want {
t.Log(string(got))
t.Errorf("files differ")
}
})
}
}
func loadTestdata(t *testing.T, test string) (tree *Tree, file []byte) {
b := New("test")
var d cldr.Decoder
data, err := d.DecodePath(filepath.Join("testdata", test))
if err != nil {
t.Fatalf("error decoding testdata: %v", err)
}
context := Enum("context")
widthMap := func(s string) string {
// Align era with width values.
if r, ok := map[string]string{
"eraAbbr": "abbreviated",
"eraNarrow": "narrow",
"eraNames": "wide",
}[s]; ok {
s = r
}
return "w" + strings.Title(s)
}
width := EnumFunc("width", widthMap, "abbreviated", "narrow", "wide")
month := Enum("month", "leap7")
relative := EnumFunc("relative", func(s string) string {
x, err := strconv.ParseInt(s, 10, 8)
if err != nil {
log.Fatal("Invalid number:", err)
}
return []string{
"before1",
"current",
"after1",
}[x+1]
})
cycleType := EnumFunc("cycleType", func(s string) string {
return "cyc" + strings.Title(s)
})
r := rand.New(rand.NewSource(0))
for _, loc := range data.Locales() {
ldml := data.RawLDML(loc)
x := b.Locale(language.Make(loc))
if x := x.Index(ldml.Dates.Calendars); x != nil {
for _, cal := range ldml.Dates.Calendars.Calendar {
x := x.IndexFromType(cal)
if x := x.Index(cal.Months); x != nil {
for _, mc := range cal.Months.MonthContext {
x := x.IndexFromType(mc, context)
for _, mw := range mc.MonthWidth {
x := x.IndexFromType(mw, width)
for _, m := range mw.Month {
x.SetValue(m.Yeartype+m.Type, m, month)
}
}
}
}
if x := x.Index(cal.CyclicNameSets); x != nil {
for _, cns := range cal.CyclicNameSets.CyclicNameSet {
x := x.IndexFromType(cns, cycleType)
for _, cc := range cns.CyclicNameContext {
x := x.IndexFromType(cc, context)
for _, cw := range cc.CyclicNameWidth {
x := x.IndexFromType(cw, width)
for _, c := range cw.CyclicName {
x.SetValue(c.Type, c)
}
}
}
}
}
if x := x.Index(cal.Eras); x != nil {
opts := []Option{width, SharedType()}
if x := x.Index(cal.Eras.EraNames, opts...); x != nil {
for _, e := range cal.Eras.EraNames.Era {
x.IndexFromAlt(e).SetValue(e.Type, e)
}
}
if x := x.Index(cal.Eras.EraAbbr, opts...); x != nil {
for _, e := range cal.Eras.EraAbbr.Era {
x.IndexFromAlt(e).SetValue(e.Type, e)
}
}
if x := x.Index(cal.Eras.EraNarrow, opts...); x != nil {
for _, e := range cal.Eras.EraNarrow.Era {
x.IndexFromAlt(e).SetValue(e.Type, e)
}
}
}
{
// Ensure having more than 2 buckets.
f := x.IndexWithName("filler")
b := make([]byte, maxStrlen)
opt := &options{parent: x}
r.Read(b)
f.setValue("0", string(b), opt)
}
}
}
if x := x.Index(ldml.Dates.Fields); x != nil {
for _, f := range ldml.Dates.Fields.Field {
x := x.IndexFromType(f)
for _, d := range f.DisplayName {
x.Index(d).SetValue("", d)
}
for _, r := range f.Relative {
x.Index(r).SetValue(r.Type, r, relative)
}
for _, rt := range f.RelativeTime {
x := x.Index(rt).IndexFromType(rt)
for _, p := range rt.RelativeTimePattern {
x.SetValue(p.Count, p)
}
}
for _, rp := range f.RelativePeriod {
x.Index(rp).SetValue("", rp)
}
}
}
}
tree, err = build(b)
if err != nil {
t.Fatal("error building tree:", err)
}
w := gen.NewCodeWriter()
generate(b, tree, w)
generateTestData(b, w)
buf := &bytes.Buffer{}
if _, err = w.WriteGo(buf, "test", ""); err != nil {
t.Log(buf.String())
t.Fatal("error generating code:", err)
}
return tree, buf.Bytes()
}
+208
View File
@@ -0,0 +1,208 @@
// Copyright 2017 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 cldrtree
import (
"bytes"
"fmt"
"io"
"reflect"
"strconv"
"strings"
"golang.org/x/text/internal/gen"
)
func generate(b *Builder, t *Tree, w *gen.CodeWriter) error {
fmt.Fprintln(w, `import "golang.org/x/text/internal/cldrtree"`)
fmt.Fprintln(w)
fmt.Fprintf(w, "var tree = &cldrtree.Tree{locales, indices, buckets}\n\n")
w.WriteComment("Path values:\n" + b.stats())
fmt.Fprintln(w)
// Generate enum types.
for _, e := range b.enums {
// Build enum types.
w.WriteComment("%s specifies a property of a CLDR field.", e.name)
fmt.Fprintf(w, "type %s uint16\n", e.name)
}
d, err := getEnumData(b)
if err != nil {
return err
}
fmt.Fprintln(w, "const (")
for i, k := range d.keys {
fmt.Fprintf(w, "%s %s = %d // %s\n", toCamel(k), d.enums[i], d.m[k], k)
}
fmt.Fprintln(w, ")")
w.WriteVar("locales", t.Locales)
w.WriteVar("indices", t.Indices)
// Generate string buckets.
fmt.Fprintln(w, "var buckets = []string{")
for i := range t.Buckets {
fmt.Fprintf(w, "bucket%d,\n", i)
}
fmt.Fprint(w, "}\n\n")
w.Size += int(reflect.TypeOf("").Size()) * len(t.Buckets)
// Generate string buckets.
for i, bucket := range t.Buckets {
w.WriteVar(fmt.Sprint("bucket", i), bucket)
}
return nil
}
func generateTestData(b *Builder, w *gen.CodeWriter) error {
d, err := getEnumData(b)
if err != nil {
return err
}
fmt.Fprintln(w)
fmt.Fprintln(w, "var enumMap = map[string]uint16{")
fmt.Fprintln(w, `"": 0,`)
for _, k := range d.keys {
fmt.Fprintf(w, "%q: %d,\n", k, d.m[k])
}
fmt.Fprintln(w, "}")
return nil
}
func toCamel(s string) string {
p := strings.Split(s, "-")
for i, s := range p[1:] {
p[i+1] = strings.Title(s)
}
return strings.Replace(strings.Join(p, ""), "/", "", -1)
}
func (b *Builder) stats() string {
w := &bytes.Buffer{}
b.rootMeta.validate()
for _, es := range b.enums {
fmt.Fprintf(w, "<%s>\n", es.name)
printEnumValues(w, es, 1, nil)
}
fmt.Fprintln(w)
printEnums(w, b.rootMeta.typeInfo, 0)
fmt.Fprintln(w)
fmt.Fprintln(w, "Nr elem: ", len(b.strToBucket))
fmt.Fprintln(w, "uniqued size: ", b.size)
fmt.Fprintln(w, "total string size: ", b.sizeAll)
fmt.Fprintln(w, "bucket waste: ", b.bucketWaste)
return w.String()
}
func printEnums(w io.Writer, s *typeInfo, indent int) {
idStr := strings.Repeat(" ", indent) + "- "
e := s.enum
if e == nil {
if len(s.entries) > 0 {
panic(fmt.Errorf("has entries but no enum values: %#v", s.entries))
}
return
}
if e.name != "" {
fmt.Fprintf(w, "%s<%s>\n", idStr, e.name)
} else {
printEnumValues(w, e, indent, s)
}
if s.sharedKeys() {
for _, v := range s.entries {
printEnums(w, v, indent+1)
break
}
}
}
func printEnumValues(w io.Writer, e *enum, indent int, info *typeInfo) {
idStr := strings.Repeat(" ", indent) + "- "
for i := 0; i < len(e.keys); i++ {
fmt.Fprint(w, idStr)
k := e.keys[i]
if u, err := strconv.ParseUint(k, 10, 16); err == nil {
fmt.Fprintf(w, "%s", k)
// Skip contiguous integers
var v, last uint64
for i++; i < len(e.keys); i++ {
k = e.keys[i]
if v, err = strconv.ParseUint(k, 10, 16); err != nil {
break
}
last = v
}
if u < last {
fmt.Fprintf(w, `..%d`, last)
}
fmt.Fprintln(w)
if err != nil {
fmt.Fprintf(w, "%s%s\n", idStr, k)
}
} else if k == "" {
fmt.Fprintln(w, `""`)
} else {
fmt.Fprintf(w, "%s\n", k)
}
if info != nil && !info.sharedKeys() {
if e := info.entries[enumIndex(i)]; e != nil {
printEnums(w, e, indent+1)
}
}
}
}
func getEnumData(b *Builder) (*enumData, error) {
d := &enumData{m: map[string]int{}}
if errStr := d.insert(b.rootMeta.typeInfo); errStr != "" {
// TODO: consider returning the error.
return nil, fmt.Errorf("cldrtree: %s", errStr)
}
return d, nil
}
type enumData struct {
m map[string]int
keys []string
enums []string
}
func (d *enumData) insert(t *typeInfo) (errStr string) {
e := t.enum
if e == nil {
return ""
}
for i, k := range e.keys {
if _, err := strconv.ParseUint(k, 10, 16); err == nil {
// We don't include any enum that has integer values.
break
}
if v, ok := d.m[k]; ok {
if v != i {
return fmt.Sprintf("%q has value %d and %d", k, i, v)
}
} else {
d.m[k] = i
if k != "" {
d.keys = append(d.keys, k)
d.enums = append(d.enums, e.name)
}
}
}
for i := range t.enum.keys {
if e := t.entries[enumIndex(i)]; e != nil {
if errStr := d.insert(e); errStr != "" {
return fmt.Sprintf("%q>%v", t.enum.keys[i], errStr)
}
}
}
return ""
}
+86
View File
@@ -0,0 +1,86 @@
// Copyright 2017 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 cldrtree
import (
"reflect"
"golang.org/x/text/unicode/cldr"
)
// An Option configures an Index.
type Option func(*options)
type options struct {
parent *Index
name string
alias *cldr.Common
sharedType *typeInfo
sharedEnums *enum
}
func (o *options) fill(opt []Option) {
for _, f := range opt {
f(o)
}
}
// aliasOpt sets an alias from the given node, if the node defines one.
func (o *options) setAlias(n Element) {
if n != nil && !reflect.ValueOf(n).IsNil() {
o.alias = n.GetCommon()
}
}
// Enum defines a enumeration type. The resulting option may be passed for the
// construction of multiple Indexes, which they will share the same enum values.
// Calling Gen on a Builder will generate the Enum for the given name. The
// optional values fix the values for the given identifier to the argument
// position (starting at 0). Other values may still be added and will be
// assigned to subsequent values.
func Enum(name string, value ...string) Option {
return EnumFunc(name, nil, value...)
}
// EnumFunc is like Enum but also takes a function that allows rewriting keys.
func EnumFunc(name string, rename func(string) string, value ...string) Option {
enum := &enum{name: name, rename: rename, keyMap: map[string]enumIndex{}}
for _, e := range value {
enum.lookup(e)
}
return func(o *options) {
found := false
for _, e := range o.parent.meta.b.enums {
if e.name == enum.name {
found = true
break
}
}
if !found {
o.parent.meta.b.enums = append(o.parent.meta.b.enums, enum)
}
o.sharedEnums = enum
}
}
// SharedType returns an option which causes all Indexes to which this option is
// passed to have the same type.
func SharedType() Option {
info := &typeInfo{}
return func(o *options) { o.sharedType = info }
}
func useSharedType() Option {
return func(o *options) {
sub := o.parent.meta.typeInfo.keyTypeInfo
if sub == nil {
sub = &typeInfo{}
o.parent.meta.typeInfo.keyTypeInfo = sub
}
o.sharedType = sub
}
}
@@ -0,0 +1,89 @@
<?xml version="1.0" encoding="UTF-8" ?>
<ldml>
<identity>
<language type="root"/>
</identity>
<dates>
<calendars>
<calendar type="chinese">
<months>
<monthContext type="format">
<monthWidth type="abbreviated">
<alias source="locale" path="../monthWidth[@type='wide']"/>
</monthWidth>
<monthWidth type="narrow">
<alias source="locale" path="../monthWidth[@type='wide']"/>
</monthWidth>
<monthWidth type="wide">
<month type="1">cM01</month>
<month type="2">cM02</month>
<month type="3">cM03</month>
<month type="4">cM04</month>
<month type="5">cM05</month>
<month type="6">cM06</month>
<month type="7">cM07</month>
<month type="8">cM08</month>
<month type="9">cM09</month>
<month type="10">cM10</month>
<month type="11">cM11</month>
<month type="12">cM12</month>
</monthWidth>
</monthContext>
</months>
</calendar>
<calendar type="dangi">
<months>
<alias source="locale" path="../../calendar[@type='chinese']/months"/>
</months>
</calendar>
<calendar type="gregorian">
<months>
<monthContext type="format">
<monthWidth type="abbreviated">
<alias source="locale" path="../monthWidth[@type='wide']"/>
</monthWidth>
<monthWidth type="narrow">
<alias source="locale" path="../../monthContext[@type='stand-alone']/monthWidth[@type='narrow']"/>
</monthWidth>
<monthWidth type="wide">
<month type="1">gM01</month>
<month type="2">gM02</month>
<month type="3">gM03</month>
<month type="4">gM04</month>
<month type="5">gM05</month>
<month type="6">gM06</month>
<month type="7">gM07</month>
<month type="8">gM08</month>
<month type="9">gM09</month>
<month type="10">gM10</month>
<month type="11">gM11</month>
<month type="12">gM12</month>
</monthWidth>
</monthContext>
<monthContext type="stand-alone">
<monthWidth type="abbreviated">
<alias source="locale" path="../../monthContext[@type='format']/monthWidth[@type='abbreviated']"/>
</monthWidth>
<monthWidth type="narrow">
<month type="1">1</month>
<month type="2">2</month>
<month type="3">3</month>
<month type="4">4</month>
<month type="5">5</month>
<month type="6">6</month>
<month type="7">7</month>
<month type="8">8</month>
<month type="9">9</month>
<month type="10">10</month>
<month type="11">11</month>
<month type="12">12</month>
</monthWidth>
<monthWidth type="wide">
<alias source="locale" path="../../monthContext[@type='format']/monthWidth[@type='wide']"/>
</monthWidth>
</monthContext>
</months>
</calendar>
</calendars>
</dates>
</ldml>
+350
View File
@@ -0,0 +1,350 @@
// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT.
package test
import "golang.org/x/text/internal/cldrtree"
var tree = &cldrtree.Tree{locales, indices, buckets}
// Path values:
// <context>
// - format
// - stand-alone
// <width>
// - wAbbreviated
// - wNarrow
// - wWide
// <month>
// - leap7
// - 1..12
//
// - calendars
// - chinese
// - dangi
// - gregorian
// - months
// - <context>
// - <width>
// - <month>
// - filler
// - 0
//
// Nr elem: 39
// uniqued size: 912
// total string size: 912
// bucket waste: 0
// context specifies a property of a CLDR field.
type context uint16
// width specifies a property of a CLDR field.
type width uint16
// month specifies a property of a CLDR field.
type month uint16
const (
calendars = 0 // calendars
chinese = 0 // chinese
dangi = 1 // dangi
gregorian = 2 // gregorian
months = 0 // months
filler = 1 // filler
format context = 0 // format
standAlone context = 1 // stand-alone
wAbbreviated width = 0 // wAbbreviated
wNarrow width = 1 // wNarrow
wWide width = 2 // wWide
leap7 month = 0 // leap7
)
var locales = []uint32{ // 768 elements
// Entry 0 - 1F
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
// Entry 20 - 3F
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
// Entry 40 - 5F
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
// Entry 60 - 7F
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
// Entry 80 - 9F
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
// Entry A0 - BF
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
// Entry C0 - DF
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
// Entry E0 - FF
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
// Entry 100 - 11F
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
// Entry 120 - 13F
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
// Entry 140 - 15F
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
// Entry 160 - 17F
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
// Entry 180 - 19F
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
// Entry 1A0 - 1BF
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
// Entry 1C0 - 1DF
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
// Entry 1E0 - 1FF
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
// Entry 200 - 21F
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
// Entry 220 - 23F
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
// Entry 240 - 25F
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
// Entry 260 - 27F
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
// Entry 280 - 29F
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
// Entry 2A0 - 2BF
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
// Entry 2C0 - 2DF
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
// Entry 2E0 - 2FF
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
} // Size: xxxx bytes
var indices = []uint16{ // 86 elements
// Entry 0 - 3F
0x0001, 0x0002, 0x0003, 0x0006, 0x0021, 0x0027, 0x0002, 0x0009,
0x001e, 0x0001, 0x000b, 0x0003, 0x8002, 0x8002, 0x000f, 0x000d,
0x0000, 0xffff, 0x0000, 0x0005, 0x000a, 0x000f, 0x0014, 0x0019,
0x001e, 0x0023, 0x0028, 0x002d, 0x0032, 0x0037, 0x0001, 0x0000,
0x003c, 0x0002, 0x9000, 0x0024, 0x0001, 0x0000, 0x013b, 0x0002,
0x002a, 0x0053, 0x0002, 0x002d, 0x0040, 0x0003, 0x8002, 0x9001,
0x0031, 0x000d, 0x0000, 0xffff, 0x023a, 0x023f, 0x0244, 0x0249,
0x024e, 0x0253, 0x0258, 0x025d, 0x0262, 0x0267, 0x026c, 0x0271,
// Entry 40 - 7F
0x0003, 0x9000, 0x0044, 0x9000, 0x000d, 0x0000, 0xffff, 0x0276,
0x0278, 0x027a, 0x027c, 0x027e, 0x0280, 0x0282, 0x0284, 0x0286,
0x0288, 0x028b, 0x028e, 0x0001, 0x0000, 0x0291,
} // Size: xxxx bytes
var buckets = []string{
bucket0,
}
var bucket0 string = "" + // Size: xxxx bytes
"\x04cM01\x04cM02\x04cM03\x04cM04\x04cM05\x04cM06\x04cM07\x04cM08\x04cM09" +
"\x04cM10\x04cM11\x04cM12\xfe\x01\x94\xfd\xc2\xfa/\xfc\xc0A\xd3\xff\x12" +
"\x04[s\xc8nO\xf9_\xf6b\xa5\xee\xe8*\xbd\xf4J-\x0bu\xfb\x18\x0d\xafH\xa7" +
"\x9e\xe0\xb1\x0d9FQ\x85\x0fԡx\x89.\xe2\x85\xec\xe1Q\x14Ux\x08u\xd6N\xe2" +
"\xd3\xd0\xd0\xdek\xf8\xf9\xb4L\xe8_\xf0DƱ\xf8;\x8e\x88;\xbf\x85z\xab\x99" +
"ŲR\xc7B\x9c2\U000e8bb7\x9e\xf8V\xf6Y\xc1\x8f\x0d\xce\xccw\xc7^z\x81\xbf" +
"\xde'_g\xcf\xe2B\xcf<\xc3T\xf3\xed\xe2־\xccN\xa3\xae^\x88Rj\x9fJW\x8b˞" +
"\xf2ԦS\x14v\x8dm)\x97a\xea\x9eOZ\xa6\xae\xc3\xfcxƪ\xe0\x81\xac\x81 \xc7 " +
"\xef\xcdlꄶ\x92^`{\xe0cqo\x96\xdd\xcd\xd0\x1du\x04\\?\x00\x0f\x8ayk\xcelQ" +
",8\x01\xaa\xca\xee߭[Pfd\xe8\xc0\xe4\xa7q\xecื\xc1\x96]\x91\x81%\x1b|\x9c" +
"\x9c\xa5 Z\xfc\x16\xa26\xa2\xef\xcd\xd2\xd1-*y\xd0\xfet\xa8(\x0a\xe9C" +
"\x9e\xb0֮\xca\x08#\xae\x02\xd6}\x86j\xc2\xc4\xfeJrPS\xda\x11\x9b\x9dOQQ@" +
"\xa2\xd7#\x9c@\xb4ZÕ\x0d\x94\x1f\xc4\xfe\x1c\x0c\xb9j\xd3\x22\xd6\x22" +
"\x82)_\xbf\xe1\x1e&\xa43\x07m\xb5\xc1DL:4\xd3*\\J\x7f\xfb\xe8с\xf7\xed;" +
"\x8c\xfe\x90O\x93\xf8\xf0m)\xbc\xd9\xed\x84{\x18.\x04d\x10\xf4Kİ\xf3\xf0" +
":\x0d\x06\x82\x0a0\xf2W\xf8\x11A0g\x8a\xc0E\x86\xc1\xe3\xc94,\x8b\x80U" +
"\xc4f؆D\x1d%\x99\x06͉֚K\x96\x8a\xe9\xf0띖\\\xe6\xa4i<N\xbe\x88\x15\x01" +
"\xb7لkf\xeb\x02\xb5~\\\xda{l\xbah\x91\xd6\x16\xbdhl7\xb84a:Ⱥ\xa2,\x00" +
"\x8f\xfeh\x83RsJ\xe4\xe3\xf1!z\xcd_\x83'\x08\x140\x18g\xb5\xd0g\x11\xb28" +
"\x00\x1cyW\xb2w\x19\xce?1\x88\xdf\xe5}\xee\xbfo\x82YZ\x10\xf7\xbbV,\xa0M" +
"\\='\x04gM01\x04gM02\x04gM03\x04gM04\x04gM05\x04gM06\x04gM07\x04gM08\x04" +
"gM09\x04gM10\x04gM11\x04gM12\x011\x012\x013\x014\x015\x016\x017\x018\x01" +
"9\x0210\x0211\x0212\xfe\x94)X\xc6\xdb2bg\x06I\xf3\xbc\x97٢1g5\xed悥\xdf" +
"\xe6\xf1\xa0\x11\xfbɊ\xd0\xfb\xe7\x90\x00<\x01\xe8\xe9\x96w\x03\xaff^" +
"\x9fr@\x7fK\x03\xd4\xfd\xb4t\xaa\xfe\x8a\x0d>\x05\x15\xddFP\xcfQ\x17+" +
"\x81$\x8b\xcb\x7f\x96\x9e@\x0bl[\x12wh\xb1\xc4\x12\xfa\xe9\x8c\xf5v1\xcf" +
"7\x03;KJ\xba}~\xd3\x19\xba\x14rI\xc9\x08\xacp\xd1\xc4\x06\xda\xde\x0e" +
"\x82\x8e\xb6\xba\x0dʨ\x82\x85T>\x10!<d?\xc8`;X`#fp\xba\xbc\xad\x0b\xd7" +
"\xf4\xc4\x19\x0e26#\xa8h\xd1\xea\xe1v\x9f@\xa2f1C\x1b;\xd5!V\x05\xd2\x08" +
"o\xeaԙ\xacc\xa4e=\x12(=V\x01\x9c7\x95\xa9\x8a\x12m\x09\xcf\xcb\xe3l\xdc" +
"\xc97\x88\xa5@\x9f\x8bnB\xc2݃\xaaFa\x18R\xad\x0bP(w\\w\x16\x90\xb6\x85N" +
"\x05\xb3w$\x1es\xa8\x83\xddw\xaf\xf00,m\xa8f\\B4\x1d\xdaJ\xda\xea"
var enumMap = map[string]uint16{
"": 0,
"calendars": 0,
"chinese": 0,
"dangi": 1,
"gregorian": 2,
"months": 0,
"filler": 1,
"format": 0,
"stand-alone": 1,
"wAbbreviated": 0,
"wNarrow": 1,
"wWide": 2,
"leap7": 0,
}
// Total table size: xxxx bytes (4KiB); checksum: EB82B0F5
@@ -0,0 +1,171 @@
<?xml version="1.0" encoding="UTF-8" ?>
<ldml>
<identity>
<language type="en"/>
</identity>
<dates>
<calendars>
<calendar type="buddhist">
<eras>
<eraAbbr>
<era type="0">BE</era>
</eraAbbr>
</eras>
</calendar>
<calendar type="chinese">
<months>
<monthContext type="format">
<monthWidth type="abbreviated">
<month type="1">Mo1</month>
<month type="2">Mo2</month>
<month type="3">Mo3</month>
<month type="4">Mo4</month>
<month type="5">Mo5</month>
<month type="6">Mo6</month>
<month type="7">Mo7</month>
<month type="8">Mo8</month>
<month type="9">Mo9</month>
<month type="10">Mo10</month>
<month type="11">Mo11</month>
<month type="12">Mo12</month>
</monthWidth>
<monthWidth type="wide">
<month type="1">First Month</month>
<month type="2">Second Month</month>
<month type="3">Third Month</month>
<month type="4">Fourth Month</month>
<month type="5">Fifth Month</month>
<month type="6">Sixth Month</month>
<month type="7">Seventh Month</month>
<month type="8">Eighth Month</month>
<month type="9">Ninth Month</month>
<month type="10">Tenth Month</month>
<month type="11">Eleventh Month</month>
<month type="12">Twelfth Month</month>
</monthWidth>
</monthContext>
</months>
<cyclicNameSets>
<cyclicNameSet type="zodiacs">
<cyclicNameContext type="format">
<cyclicNameWidth type="abbreviated">
<cyclicName type="1">Rat</cyclicName>
<cyclicName type="2">Ox</cyclicName>
<cyclicName type="3">Tiger</cyclicName>
<cyclicName type="4">Rabbit</cyclicName>
<cyclicName type="5">Dragon</cyclicName>
<cyclicName type="6">Snake</cyclicName>
<cyclicName type="7">Horse</cyclicName>
<cyclicName type="8">Goat</cyclicName>
<cyclicName type="9">Monkey</cyclicName>
<cyclicName type="10">Rooster</cyclicName>
<cyclicName type="11">Dog</cyclicName>
<cyclicName type="12">Pig</cyclicName>
</cyclicNameWidth>
</cyclicNameContext>
</cyclicNameSet>
</cyclicNameSets>
</calendar>
<calendar type="generic">
</calendar>
<calendar type="gregorian">
<months>
<monthContext type="format">
<monthWidth type="wide">
<month type="1">enWideM1</month>
<month type="2">enWideM2</month>
<month type="3">enWideM3</month>
<month type="4">enWideM4</month>
<month type="5">enWideM5</month>
<month type="6">enWideM6</month>
<month type="7">enWideM7</month>
<month type="8">enWideM8</month>
<month type="9">enWideM9</month>
<month type="10">enWideM10</month>
<month type="11">enWideM11</month>
<month type="12">enWideM12</month>
</monthWidth>
</monthContext>
<monthContext type="stand-alone">
<monthWidth type="narrow">
<month type="1">enNarrowM1</month>
<month type="2">enNarrowM2</month>
<month type="3">enNarrowM3</month>
<month type="4">enNarrowM4</month>
<month type="5">enNarrowM5</month>
<month type="6">enNarrowM6</month>
<!-- missing -->
<month type="8">enNarrowM8</month>
<month type="9">enNarrowM9</month>
<month type="10">enNarrowM10</month>
<month type="11">enNarrowM11</month>
<month type="12">enNarrowM12</month>
</monthWidth>
</monthContext>
</months>
<eras>
<eraNames>
<era type="0">Before Christ</era>
<era type="0" alt="variant">Before Common Era</era>
<era type="1">Anno Domini</era>
<era type="1" alt="variant">Common Era</era>
</eraNames>
<eraAbbr>
<era type="0">BC</era>
<era type="0" alt="variant">BCE</era>
<era type="1">AD</era>
<era type="1" alt="variant">CE</era>
</eraAbbr>
<!-- nothing for eraNarrow -->
</eras>
</calendar>
<calendar type="hebrew">
<eras>
<eraAbbr>
<era type="0">AM</era>
</eraAbbr>
</eras>
</calendar>
<calendar type="islamic">
<eras>
<eraAbbr>
<era type="0">AH</era>
</eraAbbr>
</eras>
</calendar>
</calendars>
<fields>
<field type="era">
<displayName>era</displayName>
</field>
<field type="month">
<displayName>month</displayName>
<relative type="-1">last month</relative>
<relative type="0">this month</relative>
<relative type="1">next month</relative>
<relativeTime type="future">
<relativeTimePattern count="one">enFutMOne</relativeTimePattern>
<relativeTimePattern count="other">enFutMOther</relativeTimePattern>
</relativeTime>
<relativeTime type="past">
<relativeTimePattern count="one">enPastMOne</relativeTimePattern>
<relativeTimePattern count="other">enPastMOther</relativeTimePattern>
</relativeTime>
</field>
<field type="month-short">
<displayName>mo.</displayName>
<relative type="-1">last mo.</relative>
<relative type="0">this mo.</relative>
<relative type="1">next mo.</relative>
<relativeTime type="future">
<relativeTimePattern count="one">enShortFutMOne</relativeTimePattern>
<relativeTimePattern count="other">enShortFutMOther</relativeTimePattern>
</relativeTime>
<relativeTime type="past">
<relativeTimePattern count="one">enShortPastMOne</relativeTimePattern>
<relativeTimePattern count="other">enShortPastMOther</relativeTimePattern>
</relativeTime>
</field>
</fields>
</dates>
</ldml>
@@ -0,0 +1,60 @@
<?xml version="1.0" encoding="UTF-8" ?>
<ldml>
<identity>
<language type="en"/>
<territory type="001"/>
</identity>
<dates>
<calendars>
<calendar type="chinese">
<months>
<monthContext type="format">
<monthWidth type="abbreviated">
<month type="1">001AbbrMo1</month>
<month type="2">001AbbrMo2</month>
<month type="3">001AbbrMo3</month>
<month type="4">001AbbrMo4</month>
<month type="5">001AbbrMo5</month>
<month type="6">001AbbrMo6</month>
<month type="7">001AbbrMo7</month>
<month type="8">001AbbrMo8</month>
<month type="9">001AbbrMo9</month>
<month type="10">001AbbrMo10</month>
<month type="11">001AbbrMo11</month>
<month type="12">001AbbrMo12</month>
</monthWidth>
</monthContext>
</months>
</calendar>
<calendar type="generic">
</calendar>
<calendar type="gregorian">
</calendar>
</calendars>
<fields>
<field type="month-short">
<displayName>mo</displayName>
<relativeTime type="future">
<relativeTimePattern count="one">001ShortFutMOne</relativeTimePattern>
<relativeTimePattern count="other">001ShortFutMOther</relativeTimePattern>
</relativeTime>
<relativeTime type="past">
<!-- missing -->
<relativeTimePattern count="other">001ShortPastMOther</relativeTimePattern>
</relativeTime>
</field>
<field type="month-narrow">
<displayName>mo</displayName>
<relativeTime type="future">
<relativeTimePattern count="one">001NarrowFutMOne</relativeTimePattern>
<relativeTimePattern count="two">001NarrowFutMTwo</relativeTimePattern>
<relativeTimePattern count="other">001NarrowFutMOther</relativeTimePattern>
</relativeTime>
<relativeTime type="past">
<relativeTimePattern count="one">001NarrowPastMOne</relativeTimePattern>
<relativeTimePattern count="other">001NarrowPastMOther</relativeTimePattern>
</relativeTime>
</field>
</fields>
</dates>
</ldml>
@@ -0,0 +1,63 @@
<?xml version="1.0" encoding="UTF-8" ?>
<ldml>
<identity>
<language type="en"/>
<territory type="GB"/>
</identity>
<dates>
<calendars>
<calendar type="gregorian">
<months>
<monthContext type="format">
<monthWidth type="abbreviated">
<month type="1">gbAbbrM1</month>
<month type="2">gbAbbrM2</month>
<month type="3">gbAbbrM3</month>
<month type="4">gbAbbrM4</month>
<month type="5">gbAbbrM5</month>
<month type="6">gbAbbrM6</month>
<month type="7">gbAbbrM7</month>
<month type="8">gbAbbrM8</month>
<month type="9">gbAbbrM9</month>
<month type="10">gbAbbrM10</month>
<month type="11">gbAbbrM11</month>
<month type="12">gbAbbrM12</month>
</monthWidth>
<monthWidth type="wide">
<month type="1">gbWideM1</month>
<month type="2">gbWideM2</month>
<month type="3">gbWideM3</month>
<month type="4">gbWideM4</month>
<month type="5">gbWideM5</month>
<month type="6">gbWideM6</month>
<month type="7">gbWideM7</month>
<month type="8">gbWideM8</month>
<month type="9">gbWideM9</month>
<month type="10">gbWideM10</month>
<month type="11">gbWideM11</month>
<month type="12">gbWideM12</month>
</monthWidth>
</monthContext>
<monthContext type="stand-alone">
<monthWidth type="narrow">
<month type="1">gbNarrowM1</month>
<month type="2">gbNarrowM2</month>
<month type="3">gbNarrowM3</month>
<!-- missing -->
<month type="5">gbNarrowM5</month>
<month type="6">gbNarrowM6</month>
<!-- missing -->
<month type="8">gbNarrowM8</month>
<month type="9">gbNarrowM9</month>
<month type="10">gbNarrowM10</month>
<month type="11">gbNarrowM11</month>
<month type="12">gbNarrowM12</month>
</monthWidth>
</monthContext>
</months>
</calendar>
<calendar type="islamic">
</calendar>
</calendars>
</dates>
</ldml>
@@ -0,0 +1,646 @@
<?xml version="1.0" encoding="UTF-8" ?>
<ldml>
<identity>
<language type="root"/>
</identity>
<dates>
<calendars>
<calendar type="buddhist">
<months>
<alias source="locale" path="../../calendar[@type='generic']/months"/> <!-- gregorian in original -->
</months>
<eras>
<eraNames>
<alias source="locale" path="../eraAbbr"/>
</eraNames>
<eraAbbr>
<era type="0">BE</era>
</eraAbbr>
<eraNarrow>
<alias source="locale" path="../eraAbbr"/>
</eraNarrow>
</eras>
</calendar>
<calendar type="chinese">
<months>
<monthContext type="format">
<monthWidth type="abbreviated">
<alias source="locale" path="../monthWidth[@type='wide']"/>
</monthWidth>
<monthWidth type="narrow">
<alias source="locale" path="../../monthContext[@type='stand-alone']/monthWidth[@type='narrow']"/>
</monthWidth>
<monthWidth type="wide">
<month type="1">chineseWideM01</month>
<month type="2">chineseWideM02</month>
<month type="3">chineseWideM03</month>
<month type="4">chineseWideM04</month>
<month type="5">chineseWideM05</month>
<month type="6">chineseWideM06</month>
<month type="7">chineseWideM07</month>
<month type="8">chineseWideM08</month>
<month type="9">chineseWideM09</month>
<month type="10">chineseWideM10</month>
<month type="11">chineseWideM11</month>
<month type="12">chineseWideM12</month>
</monthWidth>
</monthContext>
<monthContext type="stand-alone">
<monthWidth type="abbreviated">
<alias source="locale" path="../../monthContext[@type='format']/monthWidth[@type='abbreviated']"/>
</monthWidth>
<monthWidth type="narrow">
<month type="1">chineseNarrowM1</month>
<month type="2">chineseNarrowM2</month>
<month type="3">chineseNarrowM3</month>
<month type="4">chineseNarrowM4</month>
<month type="5">chineseNarrowM5</month>
<month type="6">chineseNarrowM6</month>
<month type="7">chineseNarrowM7</month>
<month type="8">chineseNarrowM8</month>
<month type="9">chineseNarrowM9</month>
<month type="10">chineseNarrowM10</month>
<month type="11">chineseNarrowM11</month>
<month type="12">chineseNarrowM12</month>
</monthWidth>
<monthWidth type="wide">
<alias source="locale" path="../../monthContext[@type='format']/monthWidth[@type='wide']"/>
</monthWidth>
</monthContext>
</months>
<!-- chinese eras are computed, and don't fall back to gregorian -->
<cyclicNameSets>
<cyclicNameSet type="dayParts">
<cyclicNameContext type="format">
<cyclicNameWidth type="abbreviated">
<cyclicName type="1">dpAbbr1</cyclicName>
<cyclicName type="2">dpAbbr2</cyclicName>
<cyclicName type="3">dpAbbr3</cyclicName>
<cyclicName type="4">dpAbbr4</cyclicName>
<cyclicName type="5">dpAbbr5</cyclicName>
<cyclicName type="6">dpAbbr6</cyclicName>
<cyclicName type="7">dpAbbr7</cyclicName>
<cyclicName type="8">dpAbbr8</cyclicName>
<cyclicName type="9">dpAbbr9</cyclicName>
<cyclicName type="10">dpAbbr10</cyclicName>
<cyclicName type="11">dpAbbr11</cyclicName>
<cyclicName type="12">dpAbbr12</cyclicName>
</cyclicNameWidth>
<cyclicNameWidth type="narrow">
<alias source="locale" path="../cyclicNameWidth[@type='abbreviated']"/>
</cyclicNameWidth>
<cyclicNameWidth type="wide">
<alias source="locale" path="../cyclicNameWidth[@type='abbreviated']"/>
</cyclicNameWidth>
</cyclicNameContext>
</cyclicNameSet>
<cyclicNameSet type="days">
<alias source="locale" path="../cyclicNameSet[@type='years']"/>
</cyclicNameSet>
<cyclicNameSet type="months">
<alias source="locale" path="../cyclicNameSet[@type='years']"/>
</cyclicNameSet>
<cyclicNameSet type="years">
<cyclicNameContext type="format">
<cyclicNameWidth type="abbreviated">
<cyclicName type="1">year1</cyclicName>
<cyclicName type="2">year2</cyclicName>
<cyclicName type="3">year3</cyclicName>
<cyclicName type="4">year4</cyclicName>
<cyclicName type="5">year5</cyclicName>
<cyclicName type="6">year6</cyclicName>
<cyclicName type="7">year7</cyclicName>
<cyclicName type="8">year8</cyclicName>
<cyclicName type="9">year9</cyclicName>
<cyclicName type="10">year10</cyclicName>
<cyclicName type="11">year11</cyclicName>
<cyclicName type="12">year12</cyclicName>
<cyclicName type="13">year13</cyclicName>
<cyclicName type="14">year14</cyclicName>
<cyclicName type="15">year15</cyclicName>
<cyclicName type="16">year16</cyclicName>
<cyclicName type="17">year17</cyclicName>
<cyclicName type="18">year18</cyclicName>
<cyclicName type="19">year19</cyclicName>
<cyclicName type="20">year20</cyclicName>
<cyclicName type="21">year21</cyclicName>
<cyclicName type="22">year22</cyclicName>
<cyclicName type="23">year23</cyclicName>
<cyclicName type="24">year24</cyclicName>
<cyclicName type="25">year25</cyclicName>
<cyclicName type="26">year26</cyclicName>
<cyclicName type="27">year27</cyclicName>
<cyclicName type="28">year28</cyclicName>
<cyclicName type="29">year29</cyclicName>
<cyclicName type="30">year30</cyclicName>
<cyclicName type="31">year31</cyclicName>
<cyclicName type="32">year32</cyclicName>
<cyclicName type="33">year33</cyclicName>
<cyclicName type="34">year34</cyclicName>
<cyclicName type="35">year35</cyclicName>
<cyclicName type="36">year36</cyclicName>
<cyclicName type="37">year37</cyclicName>
<cyclicName type="38">year38</cyclicName>
<cyclicName type="39">year39</cyclicName>
<cyclicName type="40">year40</cyclicName>
<cyclicName type="41">year41</cyclicName>
<cyclicName type="42">year42</cyclicName>
<cyclicName type="43">year43</cyclicName>
<cyclicName type="44">year44</cyclicName>
<cyclicName type="45">year45</cyclicName>
<cyclicName type="46">year46</cyclicName>
<cyclicName type="47">year47</cyclicName>
<cyclicName type="48">year48</cyclicName>
<cyclicName type="49">year49</cyclicName>
<cyclicName type="50">year50</cyclicName>
<cyclicName type="51">year51</cyclicName>
<cyclicName type="52">year52</cyclicName>
<cyclicName type="53">year53</cyclicName>
<cyclicName type="54">year54</cyclicName>
<cyclicName type="55">year55</cyclicName>
<cyclicName type="56">year56</cyclicName>
<cyclicName type="57">year57</cyclicName>
<cyclicName type="58">year58</cyclicName>
<cyclicName type="59">year59</cyclicName>
<cyclicName type="60">year60</cyclicName>
</cyclicNameWidth>
<cyclicNameWidth type="narrow">
<alias source="locale" path="../cyclicNameWidth[@type='abbreviated']"/>
</cyclicNameWidth>
<cyclicNameWidth type="wide">
<alias source="locale" path="../cyclicNameWidth[@type='abbreviated']"/>
</cyclicNameWidth>
</cyclicNameContext>
</cyclicNameSet>
<cyclicNameSet type="zodiacs">
<cyclicNameContext type="format">
<cyclicNameWidth type="abbreviated">
<alias source="locale" path="../../../cyclicNameSet[@type='dayParts']/cyclicNameContext[@type='format']/cyclicNameWidth[@type='abbreviated']"/>
</cyclicNameWidth>
<cyclicNameWidth type="narrow">
<alias source="locale" path="../cyclicNameWidth[@type='abbreviated']"/>
</cyclicNameWidth>
<cyclicNameWidth type="wide">
<alias source="locale" path="../cyclicNameWidth[@type='abbreviated']"/>
</cyclicNameWidth>
</cyclicNameContext>
</cyclicNameSet>
</cyclicNameSets>
</calendar>
<calendar type="dangi">
<months>
<alias source="locale" path="../../calendar[@type='chinese']/months"/>
</months>
<cyclicNameSets>
<alias source="locale" path="../../calendar[@type='chinese']/cyclicNameSets"/>
</cyclicNameSets>
</calendar>
<calendar type="ethiopic">
<months>
<monthContext type="format">
<monthWidth type="abbreviated">
<alias source="locale" path="../monthWidth[@type='wide']"/>
</monthWidth>
<monthWidth type="narrow">
<alias source="locale" path="../../monthContext[@type='stand-alone']/monthWidth[@type='narrow']"/>
</monthWidth>
<monthWidth type="wide">
<month type="1">Meskerem</month>
<month type="2">Tekemt</month>
<month type="3">Hedar</month>
<month type="4">Tahsas</month>
<month type="5">Ter</month>
<month type="6">Yekatit</month>
<month type="7">Megabit</month>
<month type="8">Miazia</month>
<month type="9">Genbot</month>
<month type="10">Sene</month>
<month type="11">Hamle</month>
<month type="12">Nehasse</month>
<month type="13">Pagumen</month>
</monthWidth>
</monthContext>
<monthContext type="stand-alone">
<monthWidth type="abbreviated">
<alias source="locale" path="../../monthContext[@type='format']/monthWidth[@type='abbreviated']"/>
</monthWidth>
<monthWidth type="narrow">
<month type="1">1</month>
<month type="2">2</month>
<month type="3">3</month>
<month type="4">4</month>
<month type="5">5</month>
<month type="6">6</month>
<month type="7">7</month>
<month type="8">8</month>
<month type="9">9</month>
<month type="10">10</month>
<month type="11">11</month>
<month type="12">12</month>
<month type="13">13</month>
</monthWidth>
<monthWidth type="wide">
<alias source="locale" path="../../monthContext[@type='format']/monthWidth[@type='wide']"/>
</monthWidth>
</monthContext>
</months>
<eras>
<eraNames>
<alias source="locale" path="../eraAbbr"/>
</eraNames>
<eraAbbr>
<era type="0">ERA0</era>
<era type="1">ERA1</era>
</eraAbbr>
<eraNarrow>
<alias source="locale" path="../eraAbbr"/>
</eraNarrow>
</eras>
</calendar>
<calendar type="ethiopic-amete-alem">
<months>
<alias source="locale" path="../../calendar[@type='ethiopic']/months"/>
</months>
<eras>
<eraNames>
<alias source="locale" path="../eraAbbr"/>
</eraNames>
<eraAbbr>
<era type="0">ERA0</era>
</eraAbbr>
<eraNarrow>
<alias source="locale" path="../eraAbbr"/>
</eraNarrow>
</eras>
</calendar>
<calendar type="generic">
<months>
<monthContext type="format">
<monthWidth type="abbreviated">
<alias source="locale" path="../monthWidth[@type='wide']"/>
</monthWidth>
<monthWidth type="narrow">
<alias source="locale" path="../../monthContext[@type='stand-alone']/monthWidth[@type='narrow']"/>
</monthWidth>
<monthWidth type="wide">
<month type="1">genWideM01</month>
<month type="2">genWideM02</month>
<month type="3">genWideM03</month>
<month type="4">genWideM04</month>
<month type="5">genWideM05</month>
<month type="6">genWideM06</month>
<month type="7">genWideM07</month>
<month type="8">genWideM08</month>
<month type="9">genWideM09</month>
<month type="10">genWideM10</month>
<month type="11">genWideM11</month>
<month type="12">genWideM12</month>
</monthWidth>
</monthContext>
<monthContext type="stand-alone">
<monthWidth type="abbreviated">
<alias source="locale" path="../../monthContext[@type='format']/monthWidth[@type='abbreviated']"/>
</monthWidth>
<monthWidth type="narrow">
<month type="1">genNarrowM1</month>
<month type="2">genNarrowM2</month>
<month type="3">genNarrowM3</month>
<month type="4">genNarrowM4</month>
<month type="5">genNarrowM5</month>
<month type="6">genNarrowM6</month>
<month type="7">genNarrowM7</month>
<month type="8">genNarrowM8</month>
<month type="9">genNarrowM9</month>
<month type="10">genNarrowM10</month>
<month type="11">genNarrowM11</month>
<month type="12">genNarrowM12</month>
</monthWidth>
<monthWidth type="wide">
<alias source="locale" path="../../monthContext[@type='format']/monthWidth[@type='wide']"/>
</monthWidth>
</monthContext>
</months>
<eras>
<eraNames>
<alias source="locale" path="../eraAbbr"/>
</eraNames>
<eraAbbr>
<era type="0">ERA0</era>
<era type="1">ERA1</era>
</eraAbbr>
<eraNarrow>
<alias source="locale" path="../eraAbbr"/>
</eraNarrow>
</eras>
</calendar>
<calendar type="gregorian">
<months>
<monthContext type="format">
<monthWidth type="abbreviated">
<alias source="locale" path="../monthWidth[@type='wide']"/>
</monthWidth>
<monthWidth type="narrow">
<alias source="locale" path="../../monthContext[@type='stand-alone']/monthWidth[@type='narrow']"/>
</monthWidth>
<monthWidth type="wide">
<month type="1">gregWideM01</month>
<month type="2">gregWideM02</month>
<month type="3">gregWideM03</month>
<month type="4">gregWideM04</month>
<month type="5">gregWideM05</month>
<month type="6">gregWideM06</month>
<month type="7">gregWideM07</month>
<month type="8">gregWideM08</month>
<month type="9">gregWideM09</month>
<month type="10">gregWideM10</month>
<month type="11">gregWideM11</month>
<month type="12">gregWideM12</month>
</monthWidth>
</monthContext>
<monthContext type="stand-alone">
<monthWidth type="abbreviated">
<alias source="locale" path="../../monthContext[@type='format']/monthWidth[@type='abbreviated']"/>
</monthWidth>
<monthWidth type="narrow">
<month type="1">gregNarrowM1</month>
<month type="2">gregNarrowM2</month>
<month type="3">gregNarrowM3</month>
<month type="4">gregNarrowM4</month>
<month type="5">gregNarrowM5</month>
<month type="6">gregNarrowM6</month>
<month type="7">gregNarrowM7</month>
<month type="8">gregNarrowM8</month>
<month type="9">gregNarrowM9</month>
<month type="10">gregNarrowM10</month>
<month type="11">gregNarrowM11</month>
<month type="12">gregNarrowM12</month>
</monthWidth>
<monthWidth type="wide">
<alias source="locale" path="../../monthContext[@type='format']/monthWidth[@type='wide']"/>
</monthWidth>
</monthContext>
</months>
<eras>
<eraNames>
<alias source="locale" path="../eraAbbr"/>
</eraNames>
<eraAbbr>
<era type="0">BCE</era>
<era type="1">CE</era>
</eraAbbr>
<eraNarrow>
<alias source="locale" path="../eraAbbr"/>
</eraNarrow>
</eras>
</calendar>
<calendar type="hebrew">
<months>
<monthContext type="format">
<monthWidth type="abbreviated">
<alias source="locale" path="../monthWidth[@type='wide']"/>
</monthWidth>
<monthWidth type="narrow">
<alias source="locale" path="../../monthContext[@type='stand-alone']/monthWidth[@type='narrow']"/>
</monthWidth>
<monthWidth type="wide">
<month type="1">Tishri</month>
<month type="2">Heshvan</month>
<month type="3">Kislev</month>
<month type="4">Tevet</month>
<month type="5">Shevat</month>
<month type="6">Adar I</month>
<month type="7">Adar</month>
<month type="7" yeartype="leap">Adar II</month>
<month type="8">Nisan</month>
<month type="9">Iyar</month>
<month type="10">Sivan</month>
<month type="11">Tamuz</month>
<month type="12">Av</month>
<month type="13">Elul</month>
</monthWidth>
</monthContext>
<monthContext type="stand-alone">
<monthWidth type="abbreviated">
<alias source="locale" path="../../monthContext[@type='format']/monthWidth[@type='abbreviated']"/>
</monthWidth>
<monthWidth type="narrow">
<month type="1">1</month>
<month type="2">2</month>
<month type="3">3</month>
<month type="4">4</month>
<month type="5">5</month>
<month type="6">6</month>
<month type="7">7</month>
<month type="7" yeartype="leap">7</month>
<month type="8">8</month>
<month type="9">9</month>
<month type="10">10</month>
<month type="11">11</month>
<month type="12">12</month>
<month type="13">13</month>
</monthWidth>
<monthWidth type="wide">
<alias source="locale" path="../../monthContext[@type='format']/monthWidth[@type='wide']"/>
</monthWidth>
</monthContext>
</months>
<eras>
<eraNames>
<alias source="locale" path="../eraAbbr"/>
</eraNames>
<eraAbbr>
<era type="0">AM</era>
<!-- HY = Anno Mundi = -180799862400000 milliseconds since 1/1/1970 AD -->
</eraAbbr>
<eraNarrow>
<alias source="locale" path="../eraAbbr"/>
</eraNarrow>
</eras>
</calendar>
<calendar type="islamic">
<months>
<monthContext type="format">
<monthWidth type="abbreviated">
<month type="1">islAbbr1</month>
<month type="2">islAbbr2</month>
<month type="3">islAbbr3</month>
<month type="4">islAbbr4</month>
<month type="5">islAbbr5</month>
<month type="6">islAbbr6</month>
<month type="7">islAbbr7</month>
<month type="8">islAbbr8</month>
<month type="9">islAbbr9</month>
<month type="10">islAbbr10</month>
<month type="11">islAbbr11</month>
<month type="12">islAbbr12</month>
</monthWidth>
<monthWidth type="narrow">
<alias source="locale" path="../../monthContext[@type='stand-alone']/monthWidth[@type='narrow']"/>
</monthWidth>
<monthWidth type="wide">
<month type="1">islWide1</month>
<month type="2">islWide2</month>
<month type="3">islWide3</month>
<month type="4">islWide4</month>
<month type="5">islWide5</month>
<month type="6">islWide6</month>
<month type="7">islWide7</month>
<month type="8">islWide8</month>
<month type="9">islWide9</month>
<month type="10">islWide10</month>
<month type="11">islWide11</month>
<month type="12">islWide12</month>
</monthWidth>
</monthContext>
<monthContext type="stand-alone">
<monthWidth type="abbreviated">
<alias source="locale" path="../../monthContext[@type='format']/monthWidth[@type='abbreviated']"/>
</monthWidth>
<monthWidth type="narrow">
<month type="1">1</month>
<month type="2">2</month>
<month type="3">3</month>
<month type="4">4</month>
<month type="5">5</month>
<month type="6">6</month>
<month type="7">7</month>
<month type="8">8</month>
<month type="9">9</month>
<month type="10">10</month>
<month type="11">11</month>
<month type="12">12</month>
</monthWidth>
<monthWidth type="wide">
<alias source="locale" path="../../monthContext[@type='format']/monthWidth[@type='wide']"/>
</monthWidth>
</monthContext>
</months>
<eras>
<eraNames>
<alias source="locale" path="../eraAbbr"/>
</eraNames>
<eraAbbr>
<era type="0">AH</era>
</eraAbbr>
<eraNarrow>
<alias source="locale" path="../eraAbbr"/>
</eraNarrow>
</eras>
</calendar>
<calendar type="islamic-civil">
<months>
<alias source="locale" path="../../calendar[@type='islamic']/months"/>
</months>
<eras>
<alias source="locale" path="../../calendar[@type='islamic']/eras"/>
</eras>
</calendar>
<calendar type="islamic-rgsa">
<months>
<alias source="locale" path="../../calendar[@type='islamic']/months"/>
</months>
<eras>
<alias source="locale" path="../../calendar[@type='islamic']/eras"/>
</eras>
</calendar>
<calendar type="islamic-tbla">
<months>
<alias source="locale" path="../../calendar[@type='islamic']/months"/>
</months>
</calendar>
<calendar type="islamic-umalqura">
<months>
<alias source="locale" path="../../calendar[@type='islamic']/months"/>
</months>
</calendar>
<calendar type="persian">
<months>
<monthContext type="format">
<monthWidth type="abbreviated">
<alias source="locale" path="../monthWidth[@type='wide']"/>
</monthWidth>
<monthWidth type="narrow">
<alias source="locale" path="../../monthContext[@type='stand-alone']/monthWidth[@type='narrow']"/>
</monthWidth>
<monthWidth type="wide">
<month type="1">Farvardin</month>
<month type="2">Ordibehesht</month>
<month type="3">Khordad</month>
<month type="4">Tir</month>
<month type="5">Mordad</month>
<month type="6">Shahrivar</month>
<month type="7">Mehr</month>
<month type="8">Aban</month>
<month type="9">Azar</month>
<month type="10">Dey</month>
<month type="11">Bahman</month>
<month type="12">Esfand</month>
</monthWidth>
</monthContext>
<monthContext type="stand-alone">
<monthWidth type="abbreviated">
<alias source="locale" path="../../monthContext[@type='format']/monthWidth[@type='abbreviated']"/>
</monthWidth>
<monthWidth type="narrow">
<month type="1">1</month>
<month type="2">2</month>
<month type="3">3</month>
<month type="4">4</month>
<month type="5">5</month>
<month type="6">6</month>
<month type="7">7</month>
<month type="8">8</month>
<month type="9">9</month>
<month type="10">10</month>
<month type="11">11</month>
<month type="12">12</month>
</monthWidth>
<monthWidth type="wide">
<alias source="locale" path="../../monthContext[@type='format']/monthWidth[@type='wide']"/>
</monthWidth>
</monthContext>
</months>
<eras>
<eraNames>
<alias source="locale" path="../eraAbbr"/>
</eraNames>
<eraAbbr>
<era type="0">AP</era>
</eraAbbr>
<eraNarrow>
<alias source="locale" path="../eraAbbr"/>
</eraNarrow>
</eras>
</calendar>
</calendars>
<fields>
<field type="era">
<displayName>Era</displayName>
</field>
<field type="era-short">
<alias source="locale" path="../field[@type='era']"/>
</field>
<field type="era-narrow">
<alias source="locale" path="../field[@type='era-short']"/>
</field>
<field type="month">
<displayName>Month</displayName>
<relative type="-1">last month</relative>
<relative type="0">this month</relative>
<relative type="1">next month</relative>
<relativeTime type="future">
<relativeTimePattern count="other">+{0} m</relativeTimePattern>
</relativeTime>
<relativeTime type="past">
<relativeTimePattern count="other">-{0} m</relativeTimePattern>
</relativeTime>
</field>
<field type="month-short">
<alias source="locale" path="../field[@type='month']"/>
</field>
<field type="month-narrow">
<alias source="locale" path="../field[@type='month-short']"/>
</field>
</fields>
</dates>
</ldml>
+889
View File
@@ -0,0 +1,889 @@
// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT.
package test
import "golang.org/x/text/internal/cldrtree"
var tree = &cldrtree.Tree{locales, indices, buckets}
// Path values:
// <width>
// - wAbbreviated
// - wNarrow
// - wWide
// <context>
// - format
// - stand-alone
// <month>
// - leap7
// - 1..13
// <cycleType>
// - cycDayParts
// - cycDays
// - cycMonths
// - cycYears
// - cycZodiacs
// <relative>
// - before1
// - current
// - after1
//
// - calendars
// - buddhist
// - chinese
// - dangi
// - ethiopic
// - ethiopic-amete-alem
// - generic
// - gregorian
// - hebrew
// - islamic
// - islamic-civil
// - islamic-rgsa
// - islamic-tbla
// - islamic-umalqura
// - persian
// - months
// - <context>
// - <width>
// - <month>
// - eras
// - <width>
// - ""
// - variant
// - 0..1
// - filler
// - 0
// - cyclicNameSets
// - <cycleType>
// - <context>
// - <width>
// - 0..60
// - fields
// - era
// - era-short
// - era-narrow
// - month
// - month-short
// - month-narrow
// - displayName
// - ""
// - relative
// - <relative>
// - relativeTime
// - future
// - past
// - other
// - one
// - two
//
// Nr elem: 394
// uniqued size: 9778
// total string size: 9931
// bucket waste: 0
// width specifies a property of a CLDR field.
type width uint16
// context specifies a property of a CLDR field.
type context uint16
// month specifies a property of a CLDR field.
type month uint16
// cycleType specifies a property of a CLDR field.
type cycleType uint16
// relative specifies a property of a CLDR field.
type relative uint16
const (
calendars = 0 // calendars
fields = 1 // fields
buddhist = 0 // buddhist
chinese = 1 // chinese
dangi = 2 // dangi
ethiopic = 3 // ethiopic
ethiopicAmeteAlem = 4 // ethiopic-amete-alem
generic = 5 // generic
gregorian = 6 // gregorian
hebrew = 7 // hebrew
islamic = 8 // islamic
islamicCivil = 9 // islamic-civil
islamicRgsa = 10 // islamic-rgsa
islamicTbla = 11 // islamic-tbla
islamicUmalqura = 12 // islamic-umalqura
persian = 13 // persian
months = 0 // months
eras = 1 // eras
filler = 2 // filler
cyclicNameSets = 3 // cyclicNameSets
format context = 0 // format
standAlone context = 1 // stand-alone
wAbbreviated width = 0 // wAbbreviated
wNarrow width = 1 // wNarrow
wWide width = 2 // wWide
leap7 month = 0 // leap7
variant = 1 // variant
cycDayParts cycleType = 0 // cycDayParts
cycDays cycleType = 1 // cycDays
cycMonths cycleType = 2 // cycMonths
cycYears cycleType = 3 // cycYears
cycZodiacs cycleType = 4 // cycZodiacs
era = 0 // era
eraShort = 1 // era-short
eraNarrow = 2 // era-narrow
month = 3 // month
monthShort = 4 // month-short
monthNarrow = 5 // month-narrow
displayName = 0 // displayName
relative = 1 // relative
relativeTime = 2 // relativeTime
before1 relative = 0 // before1
current relative = 1 // current
after1 relative = 2 // after1
future = 0 // future
past = 1 // past
other = 0 // other
one = 1 // one
two = 2 // two
)
var locales = []uint32{ // 768 elements
// Entry 0 - 1F
0x00000000, 0x00000000, 0x0000027a, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
// Entry 20 - 3F
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
// Entry 40 - 5F
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
// Entry 60 - 7F
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
// Entry 80 - 9F
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x0000027a, 0x0000037f, 0x0000037f, 0x0000037f,
0x0000037f, 0x0000027a, 0x0000037f, 0x0000037f,
0x0000037f, 0x0000037f, 0x0000027a, 0x0000037f,
0x0000037f, 0x0000037f, 0x0000037f, 0x0000037f,
0x0000037f, 0x0000037f, 0x0000037f, 0x0000037f,
0x0000037f, 0x0000037f, 0x0000037f, 0x0000037f,
// Entry A0 - BF
0x0000037f, 0x0000037f, 0x0000037f, 0x0000037f,
0x0000037f, 0x0000037f, 0x0000037f, 0x000003dd,
0x0000037f, 0x0000037f, 0x0000037f, 0x0000037f,
0x0000037f, 0x0000027a, 0x0000037f, 0x0000037f,
0x0000037f, 0x0000037f, 0x0000037f, 0x0000037f,
0x0000037f, 0x0000037f, 0x0000037f, 0x0000037f,
0x0000037f, 0x0000037f, 0x0000037f, 0x0000037f,
0x0000037f, 0x0000037f, 0x0000037f, 0x0000027a,
// Entry C0 - DF
0x0000037f, 0x0000027a, 0x0000037f, 0x0000037f,
0x0000037f, 0x0000037f, 0x0000037f, 0x0000037f,
0x0000037f, 0x0000037f, 0x0000037f, 0x0000037f,
0x0000037f, 0x0000037f, 0x0000037f, 0x0000037f,
0x0000037f, 0x0000037f, 0x0000027a, 0x0000037f,
0x0000037f, 0x0000037f, 0x0000037f, 0x0000037f,
0x0000037f, 0x0000037f, 0x0000037f, 0x0000037f,
0x0000037f, 0x0000037f, 0x0000037f, 0x0000037f,
// Entry E0 - FF
0x0000037f, 0x0000037f, 0x0000037f, 0x0000037f,
0x0000037f, 0x0000037f, 0x0000037f, 0x0000027a,
0x0000027a, 0x0000037f, 0x0000037f, 0x0000027a,
0x0000037f, 0x0000037f, 0x0000037f, 0x0000037f,
0x0000037f, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
// Entry 100 - 11F
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
// Entry 120 - 13F
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
// Entry 140 - 15F
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
// Entry 160 - 17F
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
// Entry 180 - 19F
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
// Entry 1A0 - 1BF
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
// Entry 1C0 - 1DF
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
// Entry 1E0 - 1FF
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
// Entry 200 - 21F
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
// Entry 220 - 23F
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
// Entry 240 - 25F
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
// Entry 260 - 27F
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
// Entry 280 - 29F
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
// Entry 2A0 - 2BF
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
// Entry 2C0 - 2DF
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
// Entry 2E0 - 2FF
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
0x00000000, 0x00000000, 0x00000000, 0x00000000,
} // Size: xxxx bytes
var indices = []uint16{ // 1070 elements
// Entry 0 - 3F
0x0002, 0x0003, 0x0259, 0x000e, 0x0012, 0x0022, 0x00b9, 0x00c1,
0x00fd, 0x010d, 0x0147, 0x0181, 0x01bc, 0x0204, 0x020b, 0x0212,
0x0219, 0x0220, 0x0003, 0x9005, 0x0016, 0x001f, 0x0003, 0x001a,
0x8000, 0x8000, 0x0001, 0x001c, 0x0001, 0x0000, 0x0000, 0x0001,
0x0000, 0x0003, 0x0004, 0x0027, 0x0000, 0x00b6, 0x0050, 0x0002,
0x002a, 0x003d, 0x0003, 0x8002, 0x9001, 0x002e, 0x000d, 0x0000,
0xffff, 0x0102, 0x0111, 0x0120, 0x012f, 0x013e, 0x014d, 0x015c,
0x016b, 0x017a, 0x0189, 0x0198, 0x01a7, 0x0003, 0x9000, 0x0041,
// Entry 40 - 7F
0x9000, 0x000d, 0x0000, 0xffff, 0x01b6, 0x01c6, 0x01d6, 0x01e6,
0x01f6, 0x0206, 0x0216, 0x0226, 0x0236, 0x0246, 0x0257, 0x0268,
0x0005, 0x0056, 0x8003, 0x8003, 0x006b, 0x00b0, 0x0001, 0x0058,
0x0003, 0x005c, 0x8000, 0x8000, 0x000d, 0x0000, 0xffff, 0x0279,
0x0281, 0x0289, 0x0291, 0x0299, 0x02a1, 0x02a9, 0x02b1, 0x02b9,
0x02c1, 0x02ca, 0x02d3, 0x0001, 0x006d, 0x0003, 0x0071, 0x8000,
0x8000, 0x003d, 0x0000, 0xffff, 0x02dc, 0x02e2, 0x02e8, 0x02ee,
0x02f4, 0x02fa, 0x0300, 0x0306, 0x030c, 0x0312, 0x0319, 0x0320,
// Entry 80 - BF
0x0327, 0x032e, 0x0335, 0x033c, 0x0343, 0x034a, 0x0351, 0x0358,
0x035f, 0x0366, 0x036d, 0x0374, 0x037b, 0x0382, 0x0389, 0x0390,
0x0397, 0x039e, 0x03a5, 0x03ac, 0x03b3, 0x03ba, 0x03c1, 0x03c8,
0x03cf, 0x03d6, 0x03dd, 0x03e4, 0x03eb, 0x03f2, 0x03f9, 0x0400,
0x0407, 0x040e, 0x0415, 0x041c, 0x0423, 0x042a, 0x0431, 0x0438,
0x043f, 0x0446, 0x044d, 0x0454, 0x045b, 0x0462, 0x0469, 0x0470,
0x0001, 0x00b2, 0x0003, 0xa000, 0x8000, 0x8000, 0x0001, 0x0000,
0x0477, 0x0004, 0x9001, 0x0000, 0x00be, 0x9001, 0x0001, 0x0000,
// Entry C0 - FF
0x0576, 0x0003, 0x00c5, 0x00f0, 0x00fa, 0x0002, 0x00c8, 0x00dc,
0x0003, 0x8002, 0x9001, 0x00cc, 0x000e, 0x0000, 0xffff, 0x0675,
0x067e, 0x0685, 0x068b, 0x0692, 0x0696, 0x069e, 0x06a6, 0x06ad,
0x06b4, 0x06b9, 0x06bf, 0x06c7, 0x0003, 0x9000, 0x00e0, 0x9000,
0x000e, 0x0000, 0xffff, 0x06cf, 0x06d1, 0x06d3, 0x06d5, 0x06d7,
0x06d9, 0x06db, 0x06dd, 0x06df, 0x06e1, 0x06e4, 0x06e7, 0x06ea,
0x0003, 0x00f4, 0x8000, 0x8000, 0x0001, 0x00f6, 0x0002, 0x0000,
0x06ed, 0x06f2, 0x0001, 0x0000, 0x06f7, 0x0003, 0x9003, 0x0101,
// Entry 100 - 13F
0x010a, 0x0003, 0x0105, 0x8000, 0x8000, 0x0001, 0x0107, 0x0001,
0x0000, 0x06ed, 0x0001, 0x0000, 0x07f6, 0x0003, 0x0111, 0x013a,
0x0144, 0x0002, 0x0114, 0x0127, 0x0003, 0x8002, 0x9001, 0x0118,
0x000d, 0x0000, 0xffff, 0x08f5, 0x0900, 0x090b, 0x0916, 0x0921,
0x092c, 0x0937, 0x0942, 0x094d, 0x0958, 0x0963, 0x096e, 0x0003,
0x9000, 0x012b, 0x9000, 0x000d, 0x0000, 0xffff, 0x0979, 0x0985,
0x0991, 0x099d, 0x09a9, 0x09b5, 0x09c1, 0x09cd, 0x09d9, 0x09e5,
0x09f2, 0x09ff, 0x0003, 0x013e, 0x8000, 0x8000, 0x0001, 0x0140,
// Entry 140 - 17F
0x0002, 0x0000, 0x06ed, 0x06f2, 0x0001, 0x0000, 0x0a0c, 0x0003,
0x014b, 0x0174, 0x017e, 0x0002, 0x014e, 0x0161, 0x0003, 0x8002,
0x9001, 0x0152, 0x000d, 0x0000, 0xffff, 0x0b0b, 0x0b17, 0x0b23,
0x0b2f, 0x0b3b, 0x0b47, 0x0b53, 0x0b5f, 0x0b6b, 0x0b77, 0x0b83,
0x0b8f, 0x0003, 0x9000, 0x0165, 0x9000, 0x000d, 0x0000, 0xffff,
0x0b9b, 0x0ba8, 0x0bb5, 0x0bc2, 0x0bcf, 0x0bdc, 0x0be9, 0x0bf6,
0x0c03, 0x0c10, 0x0c1e, 0x0c2c, 0x0003, 0x0178, 0x8000, 0x8000,
0x0001, 0x017a, 0x0002, 0x0000, 0x0c3a, 0x0c3e, 0x0001, 0x0000,
// Entry 180 - 1BF
0x0c41, 0x0003, 0x0185, 0x01b0, 0x01b9, 0x0002, 0x0188, 0x019c,
0x0003, 0x8002, 0x9001, 0x018c, 0x000e, 0x0000, 0x0d6f, 0x0d40,
0x0d47, 0x0d4f, 0x0d56, 0x0d5c, 0x0d63, 0x0d6a, 0x0d77, 0x0d7d,
0x0d82, 0x0d88, 0x0d8e, 0x0d91, 0x0003, 0x9000, 0x01a0, 0x9000,
0x000e, 0x0000, 0x06db, 0x06cf, 0x06d1, 0x06d3, 0x06d5, 0x06d7,
0x06d9, 0x06db, 0x06dd, 0x06df, 0x06e1, 0x06e4, 0x06e7, 0x06ea,
0x0003, 0x01b4, 0x8000, 0x8000, 0x0001, 0x01b6, 0x0001, 0x0000,
0x0d96, 0x0001, 0x0000, 0x0d99, 0x0003, 0x01c0, 0x01f8, 0x0201,
// Entry 1C0 - 1FF
0x0002, 0x01c3, 0x01e5, 0x0003, 0x01c7, 0x9001, 0x01d6, 0x000d,
0x0000, 0xffff, 0x0e98, 0x0ea1, 0x0eaa, 0x0eb3, 0x0ebc, 0x0ec5,
0x0ece, 0x0ed7, 0x0ee0, 0x0ee9, 0x0ef3, 0x0efd, 0x000d, 0x0000,
0xffff, 0x0f07, 0x0f10, 0x0f19, 0x0f22, 0x0f2b, 0x0f34, 0x0f3d,
0x0f46, 0x0f4f, 0x0f58, 0x0f62, 0x0f6c, 0x0003, 0x9000, 0x01e9,
0x9000, 0x000d, 0x0000, 0xffff, 0x06cf, 0x06d1, 0x06d3, 0x06d5,
0x06d7, 0x06d9, 0x06db, 0x06dd, 0x06df, 0x06e1, 0x06e4, 0x06e7,
0x0003, 0x01fc, 0x8000, 0x8000, 0x0001, 0x01fe, 0x0001, 0x0000,
// Entry 200 - 23F
0x0f76, 0x0001, 0x0000, 0x0f79, 0x0003, 0x9008, 0x9008, 0x0208,
0x0001, 0x0000, 0x1078, 0x0003, 0x9008, 0x9008, 0x020f, 0x0001,
0x0000, 0x1177, 0x0003, 0x9008, 0x0000, 0x0216, 0x0001, 0x0000,
0x1276, 0x0003, 0x9008, 0x0000, 0x021d, 0x0001, 0x0000, 0x1375,
0x0003, 0x0224, 0x024d, 0x0256, 0x0002, 0x0227, 0x023a, 0x0003,
0x8002, 0x9001, 0x022b, 0x000d, 0x0000, 0xffff, 0x1474, 0x147e,
0x148a, 0x1492, 0x1496, 0x149d, 0x14a7, 0x14ac, 0x14b1, 0x14b6,
0x14ba, 0x14c1, 0x0003, 0x9000, 0x023e, 0x9000, 0x000d, 0x0000,
// Entry 240 - 27F
0xffff, 0x06cf, 0x06d1, 0x06d3, 0x06d5, 0x06d7, 0x06d9, 0x06db,
0x06dd, 0x06df, 0x06e1, 0x06e4, 0x06e7, 0x0003, 0x0251, 0x8000,
0x8000, 0x0001, 0x0253, 0x0001, 0x0000, 0x14c8, 0x0001, 0x0000,
0x14cb, 0x0006, 0x0260, 0x8000, 0x8001, 0x0265, 0x8003, 0x8004,
0x0001, 0x0262, 0x0001, 0x0000, 0x15ca, 0x0003, 0x0269, 0x026c,
0x0271, 0x0001, 0x0000, 0x15ce, 0x0003, 0x0000, 0x15d4, 0x15df,
0x15ea, 0x0002, 0x0274, 0x0277, 0x0001, 0x0000, 0x15f5, 0x0001,
0x0000, 0x15fc, 0x0002, 0x0003, 0x00cc, 0x0009, 0x000d, 0x001b,
// Entry 280 - 2BF
0x0000, 0x0000, 0x0000, 0x0060, 0x0067, 0x00b0, 0x00be, 0x0003,
0x0000, 0x0011, 0x0018, 0x0001, 0x0013, 0x0001, 0x0015, 0x0001,
0x0000, 0x0000, 0x0001, 0x0000, 0x1603, 0x0004, 0x0020, 0x0000,
0x005d, 0x0044, 0x0001, 0x0022, 0x0003, 0x0026, 0x0000, 0x0035,
0x000d, 0x0000, 0xffff, 0x1702, 0x1706, 0x170a, 0x170e, 0x1712,
0x1716, 0x171a, 0x171e, 0x1722, 0x1726, 0x172b, 0x1730, 0x000d,
0x0000, 0xffff, 0x1735, 0x1741, 0x174e, 0x175a, 0x1767, 0x1773,
0x177f, 0x178d, 0x179a, 0x17a6, 0x17b2, 0x17c1, 0x0005, 0x0000,
// Entry 2C0 - 2FF
0x0000, 0x0000, 0x0000, 0x004a, 0x0001, 0x004c, 0x0001, 0x004e,
0x000d, 0x0000, 0xffff, 0x17cf, 0x17d3, 0x17d6, 0x17dc, 0x17e3,
0x17ea, 0x17f0, 0x17f6, 0x17fb, 0x1802, 0x180a, 0x180e, 0x0001,
0x0000, 0x1812, 0x0003, 0x0000, 0x0000, 0x0064, 0x0001, 0x0000,
0x1911, 0x0003, 0x006b, 0x0093, 0x00ad, 0x0002, 0x006e, 0x0081,
0x0003, 0x0000, 0x0000, 0x0072, 0x000d, 0x0000, 0xffff, 0x1a10,
0x1a19, 0x1a22, 0x1a2b, 0x1a34, 0x1a3d, 0x1a46, 0x1a4f, 0x1a58,
0x1a61, 0x1a6b, 0x1a75, 0x0002, 0x0000, 0x0084, 0x000d, 0x0000,
// Entry 300 - 33F
0xffff, 0x1a7f, 0x1a8a, 0x1a95, 0x1aa0, 0x1aab, 0x1ab6, 0xffff,
0x1ac1, 0x1acc, 0x1ad7, 0x1ae3, 0x1aef, 0x0003, 0x00a2, 0x0000,
0x0097, 0x0002, 0x009a, 0x009e, 0x0002, 0x0000, 0x1afb, 0x1b1b,
0x0002, 0x0000, 0x1b09, 0x1b27, 0x0002, 0x00a5, 0x00a9, 0x0002,
0x0000, 0x1b32, 0x1b35, 0x0002, 0x0000, 0x0c3a, 0x0c3e, 0x0001,
0x0000, 0x1b38, 0x0003, 0x0000, 0x00b4, 0x00bb, 0x0001, 0x00b6,
0x0001, 0x00b8, 0x0001, 0x0000, 0x0d96, 0x0001, 0x0000, 0x1c37,
0x0003, 0x0000, 0x00c2, 0x00c9, 0x0001, 0x00c4, 0x0001, 0x00c6,
// Entry 340 - 37F
0x0001, 0x0000, 0x0f76, 0x0001, 0x0000, 0x1d36, 0x0005, 0x00d2,
0x0000, 0x0000, 0x00d7, 0x00ee, 0x0001, 0x00d4, 0x0001, 0x0000,
0x1e35, 0x0003, 0x00db, 0x00de, 0x00e3, 0x0001, 0x0000, 0x1e39,
0x0003, 0x0000, 0x15d4, 0x15df, 0x15ea, 0x0002, 0x00e6, 0x00ea,
0x0002, 0x0000, 0x1e49, 0x1e3f, 0x0002, 0x0000, 0x1e60, 0x1e55,
0x0003, 0x00f2, 0x00f5, 0x00fa, 0x0001, 0x0000, 0x1e6d, 0x0003,
0x0000, 0x1e71, 0x1e7a, 0x1e83, 0x0002, 0x00fd, 0x0101, 0x0002,
0x0000, 0x1e9b, 0x1e8c, 0x0002, 0x0000, 0x1ebc, 0x1eac, 0x0002,
// Entry 380 - 3BF
0x0003, 0x0033, 0x0007, 0x0000, 0x000b, 0x0000, 0x0000, 0x0000,
0x0025, 0x002c, 0x0003, 0x000f, 0x0000, 0x0022, 0x0001, 0x0011,
0x0001, 0x0013, 0x000d, 0x0000, 0xffff, 0x1ece, 0x1ed9, 0x1ee4,
0x1eef, 0x1efa, 0x1f05, 0x1f10, 0x1f1b, 0x1f26, 0x1f31, 0x1f3d,
0x1f49, 0x0001, 0x0001, 0x0000, 0x0003, 0x0000, 0x0000, 0x0029,
0x0001, 0x0001, 0x00ff, 0x0003, 0x0000, 0x0000, 0x0030, 0x0001,
0x0001, 0x01fe, 0x0006, 0x0000, 0x0000, 0x0000, 0x0000, 0x003a,
0x004b, 0x0003, 0x003e, 0x0000, 0x0041, 0x0001, 0x0001, 0x02fd,
// Entry 3C0 - 3FF
0x0002, 0x0044, 0x0048, 0x0002, 0x0001, 0x0310, 0x0300, 0x0001,
0x0001, 0x0322, 0x0003, 0x004f, 0x0000, 0x0052, 0x0001, 0x0001,
0x02fd, 0x0002, 0x0055, 0x005a, 0x0003, 0x0001, 0x0357, 0x0335,
0x0346, 0x0002, 0x0001, 0x037c, 0x036a, 0x0001, 0x0002, 0x0009,
0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x000c, 0x0000,
0x004a, 0x0003, 0x0010, 0x0000, 0x0047, 0x0002, 0x0013, 0x0035,
0x0003, 0x0017, 0x0000, 0x0026, 0x000d, 0x0001, 0xffff, 0x0390,
0x0399, 0x03a2, 0x03ab, 0x03b4, 0x03bd, 0x03c6, 0x03cf, 0x03d8,
// Entry 400 - 43F
0x03e1, 0x03eb, 0x03f5, 0x000d, 0x0001, 0xffff, 0x03ff, 0x0408,
0x0411, 0x041a, 0x0423, 0x042c, 0x0435, 0x043e, 0x0447, 0x0450,
0x045a, 0x0464, 0x0002, 0x0000, 0x0038, 0x000d, 0x0001, 0xffff,
0x046e, 0x0479, 0x0484, 0xffff, 0x048f, 0x049a, 0xffff, 0x04a5,
0x04b0, 0x04bb, 0x04c7, 0x04d3, 0x0001, 0x0001, 0x04df, 0x0003,
0x0000, 0x0000, 0x004e, 0x0001, 0x0001, 0x05de,
} // Size: xxxx bytes
var buckets = []string{
bucket0,
bucket1,
}
var bucket0 string = "" + // Size: xxxx bytes
"\x02BE\xfe\x01\x94\xfd\xc2\xfa/\xfc\xc0A\xd3\xff\x12\x04[s\xc8nO\xf9_" +
"\xf6b\xa5\xee\xe8*\xbd\xf4J-\x0bu\xfb\x18\x0d\xafH\xa7\x9e\xe0\xb1\x0d9F" +
"Q\x85\x0fԡx\x89.\xe2\x85\xec\xe1Q\x14Ux\x08u\xd6N\xe2\xd3\xd0\xd0\xdek" +
"\xf8\xf9\xb4L\xe8_\xf0DƱ\xf8;\x8e\x88;\xbf\x85z\xab\x99ŲR\xc7B\x9c2" +
"\U000e8bb7\x9e\xf8V\xf6Y\xc1\x8f\x0d\xce\xccw\xc7^z\x81\xbf\xde'_g\xcf" +
"\xe2B\xcf<\xc3T\xf3\xed\xe2־\xccN\xa3\xae^\x88Rj\x9fJW\x8b˞\xf2ԦS\x14v" +
"\x8dm)\x97a\xea\x9eOZ\xa6\xae\xc3\xfcxƪ\xe0\x81\xac\x81 \xc7 \xef\xcdlꄶ" +
"\x92^`{\xe0cqo\x96\xdd\xcd\xd0\x1du\x04\\?\x00\x0f\x8ayk\xcelQ,8\x01\xaa" +
"\xca\xee߭[Pfd\xe8\xc0\xe4\xa7q\xecื\xc1\x96]\x91\x81%\x1b|\x9c\x9c\xa5 Z" +
"\xfc\x16\xa26\xa2\xef\xcd\xd2\xd1-*y\xd0\x0echineseWideM01\x0echineseWid" +
"eM02\x0echineseWideM03\x0echineseWideM04\x0echineseWideM05\x0echineseWid" +
"eM06\x0echineseWideM07\x0echineseWideM08\x0echineseWideM09\x0echineseWid" +
"eM10\x0echineseWideM11\x0echineseWideM12\x0fchineseNarrowM1\x0fchineseNa" +
"rrowM2\x0fchineseNarrowM3\x0fchineseNarrowM4\x0fchineseNarrowM5\x0fchine" +
"seNarrowM6\x0fchineseNarrowM7\x0fchineseNarrowM8\x0fchineseNarrowM9\x10c" +
"hineseNarrowM10\x10chineseNarrowM11\x10chineseNarrowM12\x07dpAbbr1\x07dp" +
"Abbr2\x07dpAbbr3\x07dpAbbr4\x07dpAbbr5\x07dpAbbr6\x07dpAbbr7\x07dpAbbr8" +
"\x07dpAbbr9\x08dpAbbr10\x08dpAbbr11\x08dpAbbr12\x05year1\x05year2\x05yea" +
"r3\x05year4\x05year5\x05year6\x05year7\x05year8\x05year9\x06year10\x06ye" +
"ar11\x06year12\x06year13\x06year14\x06year15\x06year16\x06year17\x06year" +
"18\x06year19\x06year20\x06year21\x06year22\x06year23\x06year24\x06year25" +
"\x06year26\x06year27\x06year28\x06year29\x06year30\x06year31\x06year32" +
"\x06year33\x06year34\x06year35\x06year36\x06year37\x06year38\x06year39" +
"\x06year40\x06year41\x06year42\x06year43\x06year44\x06year45\x06year46" +
"\x06year47\x06year48\x06year49\x06year50\x06year51\x06year52\x06year53" +
"\x06year54\x06year55\x06year56\x06year57\x06year58\x06year59\x06year60" +
"\xfet\xa8(\x0a\xe9C\x9e\xb0֮\xca\x08#\xae\x02\xd6}\x86j\xc2\xc4\xfeJrPS" +
"\xda\x11\x9b\x9dOQQ@\xa2\xd7#\x9c@\xb4ZÕ\x0d\x94\x1f\xc4\xfe\x1c\x0c\xb9" +
"j\xd3\x22\xd6\x22\x82)_\xbf\xe1\x1e&\xa43\x07m\xb5\xc1DL:4\xd3*\\J\x7f" +
"\xfb\xe8с\xf7\xed;\x8c\xfe\x90O\x93\xf8\xf0m)\xbc\xd9\xed\x84{\x18.\x04d" +
"\x10\xf4Kİ\xf3\xf0:\x0d\x06\x82\x0a0\xf2W\xf8\x11A0g\x8a\xc0E\x86\xc1" +
"\xe3\xc94,\x8b\x80U\xc4f؆D\x1d%\x99\x06͉֚K\x96\x8a\xe9\xf0띖\\\xe6\xa4i<N" +
"\xbe\x88\x15\x01\xb7لkf\xeb\x02\xb5~\\\xda{l\xbah\x91\xd6\x16\xbdhl7\xb8" +
"4a:Ⱥ\xa2,\x00\x8f\xfeh\x83RsJ\xe4\xe3\xf1!z\xcd_\x83'\x08\x140\x18g\xb5" +
"\xd0g\x11\xb28\x00\x1cyW\xb2w\x19\xce?1\x88\xdf\xe5}\xee\xbfo\x82YZ\x10" +
"\xf7\xbbV,\xa0M\\='\xfe\x94)X\xc6\xdb2bg\x06I\xf3\xbc\x97٢1g5\xed悥\xdf" +
"\xe6\xf1\xa0\x11\xfbɊ\xd0\xfb\xe7\x90\x00<\x01\xe8\xe9\x96w\x03\xaff^" +
"\x9fr@\x7fK\x03\xd4\xfd\xb4t\xaa\xfe\x8a\x0d>\x05\x15\xddFP\xcfQ\x17+" +
"\x81$\x8b\xcb\x7f\x96\x9e@\x0bl[\x12wh\xb1\xc4\x12\xfa\xe9\x8c\xf5v1\xcf" +
"7\x03;KJ\xba}~\xd3\x19\xba\x14rI\xc9\x08\xacp\xd1\xc4\x06\xda\xde\x0e" +
"\x82\x8e\xb6\xba\x0dʨ\x82\x85T>\x10!<d?\xc8`;X`#fp\xba\xbc\xad\x0b\xd7" +
"\xf4\xc4\x19\x0e26#\xa8h\xd1\xea\xe1v\x9f@\xa2f1C\x1b;\xd5!V\x05\xd2\x08" +
"o\xeaԙ\xacc\xa4e=\x12(=V\x01\x9c7\x95\xa9\x8a\x12m\x09\xcf\xcb\xe3l\xdc" +
"\xc97\x88\xa5@\x9f\x8bnB\xc2݃\xaaFa\x18R\xad\x0bP(w\\w\x16\x90\xb6\x85N" +
"\x05\xb3w$\x1es\xa8\x83\xddw\xaf\xf00,m\xa8f\\B4\x1d\xdaJ\xda\xea\x08Mes" +
"kerem\x06Tekemt\x05Hedar\x06Tahsas\x03Ter\x07Yekatit\x07Megabit\x06Miazi" +
"a\x06Genbot\x04Sene\x05Hamle\x07Nehasse\x07Pagumen\x011\x012\x013\x014" +
"\x015\x016\x017\x018\x019\x0210\x0211\x0212\x0213\x04ERA0\x04ERA1\xfeYZ" +
"\xb1\x89_\x96RH\x9d\xd2δ\x9c$t0<\xbbD¹C\x03\xdbf,\x9cf\xb8x)\x05\x19\x0f" +
"\x1e\x165\xb6>4\x87\x8d?$o\xad\xfc\xe3D\xe7N\xf8\x13\x09\x0f\x800\xbc" +
"\xd5%\xac\x10e?\xf1\x82\xe0\x01 \xf7\xe1\xf7\x96\xfa\x0f\xc1k\xa7\xbb" +
"\x90\xbe*3\xe8|=`\xabb\x84q\xa4 \x83C\x83f\x18\x01\xbb\x0b\xfd\x8el\x14" +
"\x00q\xdb\x1e\xb2\xf7\xa1\x81\x94\xf1\xa0E\xa9L\x07\x885\xc7]\xff/>\x83a" +
"\x80\xba\xad\x9e\x95]\xa8@\xdct\xc4\xdc$\x98\xf8\xc2\x01\xae\xc2T\xa0" +
"\xe3dv\xb2\xee\xb1$\xfdƯ\xc1\xb7\xd8\x09\xc5\xe0\x8b^\x0e\x84Z\xaf\x9bl9" +
"W\xe9Z\xb4\xaa\x8e\x10|ۇ?-\xacR\x7f\x16\xc4լ\x87`v\x8aq^Fi˄\x0c%1\x7f" +
"\x9a6\x87t\xe5\x064\x1a\xfbFP>(\xe9.Q\xbd\x7f}KS\xb9\x02=V\xf9\xb9\xec" +
"\x99\x1a©ټE\xffd\xbb+\xf1M@Q\xa7`K\xfe(\xba\xd4M\x98\xbf\xe3\x0eT\xeb" +
"\xc0\x7f\xa4_b\xaa\xbe9\\\xc9O\xa0\xa0\xf2F\xb5ҋ.?m\xeb)\x90\x18pX\xe4" +
"\xbf\xd2\xd1d\x06S\xfc8\xa3\x0b\x0f\x83#\x1a\x96[A;\x0f&\x92~\x0d\x03." +
"\x83\x0bs+\u07b3\x09L\xb1\xa5\xfam\xec\x9f\x067^\xa2_\xe5|(S\xea\x092" +
"\x0aȀ9v\xeaʠ\x95\xc0/\x86\x9f\xd7\xdc1\x07$u\x94\x0c7Q\xd5b\x83Ğ/\xef" +
"\xd4\x1d\xf6v\xbd\xcbXU\xa0G\x0e\xfd-\xabzr\xcc^_9\xff~\xea\x0fC:\x9f綦u" +
"\xbc*\xc5\x0c\xd2\x18\xc0\x09\xe2\x1f\x91\x0f\x9d\xdb\x09\xa0\xd0Y\xc4" +
"\xcd},\xa6Z#I\xdfz\x86}\xbe݁\xe9ԉ\x16\x19\xc8<B\x89\\\xe1\xb6q\xcbzK\xca" +
"\xed\x910\xab\x1d\xd4\xcc-\x81G\xa1YPV\xb5_\x92\xa3U\xdbvZ܍=\xf8\x8e\xb9" +
"=R\x7f\x7f~\xc8i\xa7W\x03\xba\x86Գa\x10\xe9\xa0DY<\x96h\x15\xd1S\x0agenW" +
"ideM01\x0agenWideM02\x0agenWideM03\x0agenWideM04\x0agenWideM05\x0agenWid" +
"eM06\x0agenWideM07\x0agenWideM08\x0agenWideM09\x0agenWideM10\x0agenWideM" +
"11\x0agenWideM12\x0bgenNarrowM1\x0bgenNarrowM2\x0bgenNarrowM3\x0bgenNarr" +
"owM4\x0bgenNarrowM5\x0bgenNarrowM6\x0bgenNarrowM7\x0bgenNarrowM8\x0bgenN" +
"arrowM9\x0cgenNarrowM10\x0cgenNarrowM11\x0cgenNarrowM12\xfefS\x87\xdc8" +
"\xe5\x07\xe7E\x8d\xf3\xe6\xb0\xf0@5\xef\x94\x19\x88>\x03\xc0\x8e-u;\x08" +
"\xc9\x09\x0a\xab\xf1u\xfd\xb6>\x8c\xf9\xa5\xf0x7\x04\xc7A\xc1\x95\x15v&@" +
"\x1d\x94\x9e\xaam\xbd\x04\u05ed\xe5t\x9e\xabTp\xbf^\x9c\x18\xccyݤ\xe1." +
"\xfeVNˊ@\x19\xe1\xc4\x1f-\x82\x17\xc0ä7\x12\xae\x22o\xcewf1\xae\x19\xb3&" +
"\xa4\x11\xa2\x84t\x1b\xe0\x1f\xb4\xf3\xae\xfc]\uf58e\xb6\xcc\xeb\x86\x04" +
"\x86KK\x9a\xd3sˬ\x10\xea~f[)J\x8ay\x06\x91\xaaRF\xe6\xff\x8fз\xfb\x9b" +
"\x9aj\x95\x8e\xbf(\xec^\x8f\xaacJu*\xc9q\xc0\xbc\x0ccp\x04\xce\xe2b\xce" +
"\xf1.|\xf6\xd9\xcdwrQ=\xbdFav\xa0z\xb7\xc4\xf4e\xfe\x09twy\xc3\x14\x95扶_" +
"U{\x0aJ\xf6SX\x80\xb8%S\xd1&\xffr\x13T)\x05Zdt\x95\x993>\x96U\xb4:\xa3g(" +
"\xbbc\xbd(d'D\x0bgregWideM01\x0bgregWideM02\x0bgregWideM03\x0bgregWideM0" +
"4\x0bgregWideM05\x0bgregWideM06\x0bgregWideM07\x0bgregWideM08\x0bgregWid" +
"eM09\x0bgregWideM10\x0bgregWideM11\x0bgregWideM12\x0cgregNarrowM1\x0cgre" +
"gNarrowM2\x0cgregNarrowM3\x0cgregNarrowM4\x0cgregNarrowM5\x0cgregNarrowM" +
"6\x0cgregNarrowM7\x0cgregNarrowM8\x0cgregNarrowM9\x0dgregNarrowM10\x0dgr" +
"egNarrowM11\x0dgregNarrowM12\x03BCE\x02CE\xfe\x1b\xaa\x9f0]\\%\xe0R)\xbb" +
"3/~\x83u\xb7\xc4^\x1e\xa0F\x1d3<<r_tg\xb4A\xb7\xd0\xf5\xe8\x02B\xb7\xa4" +
"\xa1\x8e\xda\xe8z\xf2b\xa1\x0d3\xfc\x0d}\x9a\x0aF4\xf0{\xea\\Z\x00!/\xbc" +
"Y\x1b\xdd\xfe\xbb\x943OJ-\x92\x86s\xd2b\xad\xab\xaa\x82\x98;\x94\x96_U˒" +
"\x8ch?GB\xc1 \x99\xb72\xbd\x03c\x9c\x19yu-\x83u\x18$;t\xd6s\x01$^\xfeVa" +
"\xea\xa0B\x89\x17\xf5ZX\xcc3\xdb(M\x1f,\xaa\x05\xf1\xfd{f\x02\x98\x0f" +
"\x06\xd1\x07#\x0b\xf3\x10\xb4\x8c\xf6)B\x01}\xd6h\x0e\xb3\xab\x131\x0e" +
"\xca\x15\x81\xaf\xb3Ŷ\x19\xe5\xce\x06\x82\xd0\xdf\xc1\xfa\xde9(\x17\x9a" +
"\x9d\u008c\xd1p\xb5\xb5TN\x7f\x9bc\xb8=\xa3t\xaf\xa2\x8e\x14x\xdc\\)\x97" +
"\xa9\x83G\xec\x1eqQN\xb2h\x22\x16-\xc7Ù/\xd4\x1f\x0b,\xcc&\xe5^{\xd8\xf3" +
"\xfa7!_wKR\x16\xb5\x06Tishri\x07Heshvan\x06Kislev\x05Tevet\x06Shevat\x06" +
"Adar I\x04Adar\x07Adar II\x05Nisan\x04Iyar\x05Sivan\x05Tamuz\x02Av\x04El" +
"ul\x02AM\xfe\xb8r\xb6\xc28\x8d\xd9P\x16\x0e?\xfa;\xf0b<C\x86U\xbb\\\x8cv" +
"\x8a\xb3:\xe2\xee9!\x86t\x00\x86e\xe2\x0a:\xcd\xf8J\xbe\xf3\\\xab\xccH" +
"\x91X\xc0\x85?տ\xa9T\x22a9\xfcD\xc4\xf5\x06nQ\xdbr\xb73\xe9\xff\xb1|\xbf" +
"\x9eeIl\x07\u05c9g7͐x\x1c\xb7re\x02\xc8Ar\xcaYh\xffɽ\xd0H\x0e|\xe6\xe2_}" +
"\x0b\x80\xbe\x87B\x93\x18\xc8P8g\x9b\xa0e\xbc\x9f\xdf\xfa\xe3\xfa\x84" +
"\x86\xfc\xef݂\xce\x09\xaf\x9e\xa5\xa6H\x87\xe0k\xa7g@=\x0bx\x8a\xb0\xae" +
"\x9e#\xc1\xf7\x89\x1f\x8c\x00\x07\x0dN\xf5Ak\xf1\u0558\xac^\xb59\xf1\x13" +
"\x97\xf0g\xeb\xd1\xe4\x91\xd5\xfc\xf6\x1a\xb5\xee*\xb8/\xb7w\xadS\x8c" +
"\xfc\x11|<Pҳ\xf9\x14=Uw\x0c\x85s7\x8f+\xa3C\x84\xcc\x13\xdc\x1c+<\x93" +
"\xa3K\xbbp\xdbh)\xf2ŋ\xed\x1c|\xf8\xf7\xa2\xbaA\x0apЭI\x06\x03U\xb9\xde" +
"\x08islAbbr1\x08islAbbr2\x08islAbbr3\x08islAbbr4\x08islAbbr5\x08islAbbr6" +
"\x08islAbbr7\x08islAbbr8\x08islAbbr9\x09islAbbr10\x09islAbbr11\x09islAbb" +
"r12\x08islWide1\x08islWide2\x08islWide3\x08islWide4\x08islWide5\x08islWi" +
"de6\x08islWide7\x08islWide8\x08islWide9\x09islWide10\x09islWide11\x09isl" +
"Wide12\x02AH\xfe\xb9p\x124V\x03\xd9\xd0\xd1ܰޟ\xcc\xd2 \x13kc\xa31b\x06" +
"\xe6\x889\x80+\xa7\xc3\x0c\xa3\xf8\xddj[\x8fú\x16\x0e\x91\x83\x80W\xa8ZG" +
"\x09S0\xf8\x82\xe6M\xbb\x12\x80\x0cS\xefm\xbe.\x85,\xe6\x0b\xbb\x09\xc4." +
"\\X\xa9\xf6,Y\x04\xd6_\xbc\xb0\xa3X\xd6\xe12\xe7}ٷ\xb9\x89>\x86Nm\xac" +
"\x1a\xac\xb8\x87\xbd\x03\x01裑:\xact%\xd2٦\xf6\xee+T\x93\xac\xb09\xac(E" +
"\xeb\x0e\xfa.\xdd\x0a<\xf9k\xa9z\xd7\x1d\xae\x00U`\xab\xa2\xa2\x00z\x0f" +
"\xa0Hc\xcbiF\x9f\x94\xa3n\x89\x1e9\xad\xcb̛^4\xca(\x13\xd1\xd7CZ\xc8\xfc" +
"\xacv\xa8\x96T<}\xcdn\xd0F\x01\x1f3\x0b\xcc\xe8H\x0d4&\x8eg$\x02q\xe3M" +
"\xd9\x13\xd5\xfd\xe1d\xa1\xe0\x14\xc9\x17ދ\xd4q\xb8\xe7\x0bww\x0b\x05h" +
"\x022k8?n:\x11^\xc9\\\xb3\x01\xc7y2\x1d9\x1a\x140\xdaR\x8d,\xfe\xf0;po" +
"\x9d\x12T\x96\x90\x9b\xa8\xeex\x04\xc1\x98L,C\xb6\x89\xb53\xddƇVZ\xf5i" +
"\xfcg7\x9e\xac\xb2F9\xeczw*\x17N Y\x8fg\xbc\xb5\xebfn\xef\xcd\xe0ʇ'\xad" +
"\xfa\xb2WB\x8a\x8f2\xa8˄l\xff\xe5:-\xe15\xb4\xfe/\x0di^+\xc6\xe7\x07\xc0" +
"\xafi\x17\x88\x10\xcay\xf4.x@!LxF\x06\xab\x9b_!\xf3N\x9d\xae\x83Z?\xa8" +
"\x01\xf0{錒'>\xc6D\x7fW\xe7\x89\x18r_/X\xfd\x9d\x04\x07\x14L\xce*^}kz\xae" +
"\x1b\x9cPg\x89\x0e\x05toS\xf5g\xd4VlA\xdb\xc1:\x092\x88\xf5\xd0\xe6\x00" +
"\x1dp\x90m\x80x\x9ek:\xf6e\xa9\x12\xb8\xfb\xbfx\xf6\x86\x1dm\xb48g\x97#" +
"\xf3\xf1\xc5s\x1e\xfeh\xce\x19Cӽ\x8b\xe3\x08\xac\xd4D0\xf6}\xfbj\xfd\xf5" +
"\x22{\x8f\xf1\x0d\x87\xcf~\xeb\x0e\xbc\x03\x1d\xf9\x1c\xbcE\xad\xc6gz" +
"\x971\x11+j\xe9\x85\xe0\xfe\xc5FУ\x8d\xe1=~p\x9e1(\x89\x89\xc7l\xbd\x90" +
"\xd2h\xb35\xf0\xd2A\xf7o@KT}\xc4^=`\xe4\xa1\\\x00nNK\x86&j`\x95)\x88\xf6" +
"\xb1O\xde\x11\x92\x9e\xe5\x9b S\xcfV\x04\xdf\x09hf4\xf26\xac\x14\x16&d" +
"\x0b\xe0\x9dL\xf9\xa7\xb6\xc90'\x95j\xef\xef[b\x9e̺u\x97\xb2o\xe2\x8e" +
"\xc0\xae\xa3\xf42\xd5&\x02:\xb1b\x89\x00\xd6Y\xe0IE\x16F\xba\xfb\xbcm" +
"\x14s\x84\x91\x08\xf9\xa3\xd4:\x8b\x0f\xb7&_o\x0d\xd4X\x7fX\x90\x1b\xb4" +
"\xa3^<\\\xc8X\x1f\xb8+\x1b\xa1J\xaf\x11\xaaL8C\xb3l\xa9\x13\xa7\xb8h7" +
"\x97\xed\xa5\xb6\x90\x14~o\xe5}o\x8f\x05\xbd%.\xc2\xe1\xcf(\x1dO\x89u" +
"\xdc\xff!\xaf\xe4\x11\x99\x97yj\x88?\xb1\x1eY\xe40\\I8\x22h\xe8\xbda\xe4" +
"\x19\xf2m\x15nޕ\x98>d\xf3y*X&\xa2\xfe:r\x15\x22\xa4\xb16\x0dyw\x09\x98" +
"\x9d,\xfe\x93\x98 {\xb1u\xf0\x1e\x8b\xea2\xa8\xfc\xe3\xc1\xf0b\x9f\xe6" +
"\x08\xf9\xe8\xf1OÒ\x18r\x0cK\xb1\x88\x82\xa4܈\x95\x0b\x99a\x89\xa9&\xfb" +
"\xd6p\x814\xbf\x96\xfe\x0c\xce\x12mhI\x8f\xbf\x9f2B\xaa\x8a1|\xe3\xb4" +
"\xf5\xfdD\x0fl\x10\x8d㕄\xab\xa34Dž\xf8\x8d\x16\xd46\x1f\x04m1߭\xe7MA\x93" +
"\xd1G\xeeǐ\xd2[2$\x09\xcbA\xdb\x0dVd\xc7\x05\xb1W\xf88%)%\xa0#\xaa\xd5" +
"\xe7+:Ly+\x0a\xa7Ytئ\xc4jj\xd1x\x22\xd5\x14\x94\xebYHc\xd6&\xfb.\xfab" +
"\x0e\xa4=\xd14X\x22m\x22.\x22\xb4E\x9f\xef\x7f\xff7\xebP\xb6\xcf\xe4\xa7" +
"{վ\xa6\xfe\xc6\xe5\xf4\x02\x10\xf3\x9dØMI`\xce\xe8*\xd0\x0ac=\xe0um\x13w" +
"\xfd*\xa4\x11\xf7_$\xbfb\xf57>\x91\\J%`\x12\x10\x91\x02}\x06#\xb5\xcb%" +
"\x1d=,\x01\x95\xc0\xb1\x8b*\xdb\x10۸\x17\xc8\xe3\xfeo\xb0\xdeZ\xb1\x8e" +
"\xad\x0e\u0557!s\xb8M`\xa2u\xee>o\\\x0c*d\x81\xe7zf`\xce\xf5\x84\x11\x05" +
"\x1d\xfdů\x89\xc1\xa0\x14k\x05\x9a\x08\x9c\xbe\x0c\xa3\xc3s\x83_h\x85" +
"\xeb\x0a\xf6\u0090\xac\x1e\xf4A\x02\xe2\x8c^\xb0sS\x08\xcf_|\xee۱\xcaji." +
"4ň\xb5\x96w\x91A~\xfc\xe1:$^\x92\xd3p\xbf\xe7_\x0b\xb8]Z\x85\xbbF\x95x" +
"\xbe\x83D\x14\x01R\x18\x15R\xa2\xf0\xb0\x0b\xe3\x9d\xc9J kU\x00\x04\x97R" +
"o\xae\xd4ct\xb7\x8aeX\xe5$\xe8\x10\x0f\x1eTV\xfe\xa9vAU\xedw\x06~`\xd6" +
"\xc2\xefhƹ>\xd1k\x0f9(\x9c6\xa3-<ù\xde\x0dп]\x92-\x02\xd9i\xc7Oܭ\x82\x0c" +
"\x992\x9c6K\xec\xb6kI\xd6\xecZ+j\xff\x92\xd4?pVP\xa9\xe1\x03g\xb4\xb1" +
"\xf6d\x85!XqTu\xd1\xe5w~\xec\x91u\xe1\xcau\x99^!\x12\xf7N\x17\xac\xfa" +
"\xeb\x1e\x09Farvardin\x0bOrdibehesht\x07Khordad\x03Tir\x06Mordad\x09Shah" +
"rivar\x04Mehr\x04Aban\x04Azar\x03Dey\x06Bahman\x06Esfand\x02AP\xfeo4E" +
"\xf1\xca6\xd8\xc0>\xf0x\x90Գ\x09\xfe\xf7\x01\xaf\xd1Y7x\x89\x0e\xe4/\xb9" +
"\x8f{@\xdb@\xa1~\xf4\x83T\xc9D\xb5\xb1;\x1fe\xe2F\x8a|P\xe0\xf2\xb9\xdc." +
"9\xf2\x88\x17\xb5\xf8\xb6(\xb1\xa34\x94\xd6\xcd1\xa9_&\xdbñҎ\x01\xf0\xce" +
"yX\xd5\xffY\xe9*sBR\xb4\xa7\x92uh\xd14gn H\xab\x09\x86*\x11\x91j\xb5\xb1" +
"\x00\x95\x93f?\x17\xdc\x03\x06\xc1\xb1\xe8n\x1d\xf7\xdaw\xdat\xa5%\xaa:b" +
"'\x81\x977B;M=\x1c\xeb\x8a\xfa\xac\xcf\xf5f\x0c;+\x98\xb0ꅴ\xf37L\xa5\x93" +
"(\x08sG\x06\xf8\xbe\x0d\xfd\x1f\x18\x87\x12ݷ\x0d\x05\xe1w\xb3t\xb4e ka" +
"\x8dD\xa4-\xeaP\u05f7\x8d\xcbU2`WV\xf1\xc3G\xfd\x95Y;\x22\x8f\x8a\x0c;" +
"\xcdp֙\xf7.1o\xd2\u0590\xa1\xe7cla\xfcJ\x99\xbd>\xc73]r\x8eCk!\x95Jo\xd5" +
"\xe7W\xd1\xc3\x03Era\x05Month\x0alast month\x0athis month\x0anext month" +
"\x06+{0} m\x06-{0} m\xfeQHs\xc6\xd4tx*\xf5b\xe27\xdaT\xee\x1a\xb1\x84" +
"\x14\xb1\xd2E\x95R=\x9d\x00u\xe5u\x7fT\xd5\x14\xe0\xdf\xd5\x18\xe5q\x8e" +
"\xb4\x15S\x0c\x94\u05ff\xd3.vE\xacn\x99\xb1\xf9(ƃ\xcc\xef\xeej32y\xc0" +
"\xc1\x03X\xf4\x02\xc2\x084\x9b\xa3;\xaf\xb0X1æ\xe68\x8f\xa9E8=U\xefӐB4" +
"\xff\xc4O\xc9R\xab\xafN\x05H\xc9\x1d\xa2\x15U\x80\x9c\xd0\xc8\x1ay\xbb*r" +
"f\x9cW\x16^\xa4\xaf_/\xbc\xf2\xe7\xf68\xcf\xdc\xd8q\xcaRE\x00Yp06\x9a" +
"\xc90\xa3\x08\xce\x19Y\xff\x22H\x83\xbf\x00`\x94\x06r\x85\x965\xc9\x0d^J" +
"{Ks,\xe3o\xed(\x1f$\x10ݱ\x9a\xbf{J^3\xf5_\x9a\x1d\xb6\xd4m\x1a2P\xafR`" +
"\xbeTB+\xb9\x1b<\x08&\xa8\x8a\x18\xf8\x8cy\xc0\xcb\xed\xf1@}\x0b\xbf\xac" +
"H\x048\xf9\x0co\x92\xfa!$\x9b6\xabnY\xc05\x0cݷ\xf3\xa5\x0dE\x97\x03Mo1" +
"\x03Mo2\x03Mo3\x03Mo4\x03Mo5\x03Mo6\x03Mo7\x03Mo8\x03Mo9\x04Mo10\x04Mo11" +
"\x04Mo12\x0bFirst Month\x0cSecond Month\x0bThird Month\x0cFourth Month" +
"\x0bFifth Month\x0bSixth Month\x0dSeventh Month\x0cEighth Month\x0bNinth" +
" Month\x0bTenth Month\x0eEleventh Month\x0dTwelfth Month\x03Rat\x02Ox" +
"\x05Tiger\x06Rabbit\x06Dragon\x05Snake\x05Horse\x04Goat\x06Monkey\x07Roo" +
"ster\x03Dog\x03Pig\xfeѝ\xe0T\xfc\x12\xac\xf3cD\xd0<\xe5Wu\xa5\xc45\x0b" +
"\x9al\x9f?ium\xfc\x96\xb4\xf4\x7f\xfb\xc6\xf1\xff\x9e\x22\xe2\xc9m\x8f" +
"\xd25rg\x87L\x15Y\x10\x80\xd2t\xb5\xe5\x90\x08xH7\xfa\xdb\x02\xf70\x1fИJ" +
"\x88G\x99\xd6\x1a\x83\xb8\xbdz<\xf1\xc9t\U000953c1\xa5N\xa8\x0e\xbe\x05." +
"n\x87R\xf1\xbf\xc8>m%O?@4\xd4\xe8\xf1\x04Y\xb1_\x11\x1b\xb3\x17\xc8R\xed" +
"EHn\xa5\xf7>\xaf9:1?\x9eG\x0cg\xd0M \xbc\xcf+)\x86A\xd2qo\xbd\x18\x12N" +
"\xe4`:\x8fk|?\x8d/\x90\x8c\xe7d\xe4\x08\x9e\x8dO\x15L\x92@\xa5w}F\x7f" +
"\x84r7u\x10\x12/AΞ\xc0\xf9\x89\xb57\x1ct\xbe\x9e&\x9e\xfba\x85;\u05cb" +
"\xc2S\xc0\x97\xe3\x81]\xedg\xf6\xf6t\xd2\xfc\x1ezM\xf0\x08\x87\xeb\x12" +
"\x8f\xffd\x8a>\x09\xa5\xaa\x9ag&?\x0d\xadV\x93x!Xi{\x99\x04\xf4A r\xfeho" +
"\xd1\xffQ\x8f\xd4\xc1\xe1\x83i\x88\x9a\xfe\xfc<\x14\xd3G\x10\x94GA|\x17M" +
"2\x13\x22W@\x07\x8c-F\x81A\xe1\xb4y$S\xf18\x87v)\x07\x9b\x13R\x02\xf7<" +
"\x86\x1eD,3\xf6\xc9̳\xc3\xc3)HYX\xfbmI\x86\x93^\xe5\xa9\xe9\x12!\x82Y" +
"\xcf}a*-y\xf3\x1e6&\x91N\xe2\xec\x14\x95\x16,\x80\x1e=[E\x80\xca\xc9]." +
"\xed\x0fH:X\xd1lN}\x1d\xe0\xf1\xba'\xd6\x04\xf6u\x06\xc2\xdf\xd1g\x032" +
"\xabp55Yu'\xef\x1e>\x7f\x07\x92\xa7\x0eg\x12\xbb\xdaX\xe0p\x9c;\xd82." +
"\xa4\xc9w\xfa!\xfb\x9eD\xdd\xe7\xb7\xe2\xfa\xb9\xd8ٽ\xf4mB\x9a\xa1\xafo" +
"\x83ˣŷ#m<\x86WU\x8e\xea\xa5p:\xd4e_ܜ\xd2\xcf\x1e\u07fb$W\x96i\xa0\xc1" +
"\x00\x15o\xf8\x10\xb6h\xc2ײ:\x80\xfdO\xf5\xed\xf0\xcf4\x8d!L\x03Dc\xf2&" +
"\x8c\xcf\x15\xf6\xe3\xc3L\xbak\x08enWideM1\x08enWideM2\x08enWideM3\x08en" +
"WideM4\x08enWideM5\x08enWideM6\x08enWideM7\x08enWideM8\x08enWideM9\x09en" +
"WideM10\x09enWideM11\x09enWideM12\x0aenNarrowM1\x0aenNarrowM2\x0aenNarro" +
"wM3\x0aenNarrowM4\x0aenNarrowM5\x0aenNarrowM6\x0aenNarrowM8\x0aenNarrowM" +
"9\x0benNarrowM10\x0benNarrowM11\x0benNarrowM12\x0dBefore Christ\x11Befor" +
"e Common Era\x0bAnno Domini\x0aCommon Era\x02BC\x02AD\xfe\xfe\x1f8{\x91g" +
"\xb7\xd7\xcd\xde#Xk\xe6\x85\xd8Ì\x8e\xf7g\xf0\x10\xd02\xbdJN\x8f\xf8\x15" +
"A\xad\xfd\xcae\xac\xb6\xf7\xe1$9\xb9\xa2 \xb5\x8a\xf1f\x1d/N\xd0\xff\xb2" +
"_\xaaC͑Y\x1d\xcd$ua[\xaa\x1e\x01I\xf0\xbc\xb7\x0b\xc426\x15Ș\x19\x88\x94" +
"\x8b\xd5\xf7\xb0\xa4\xbd\\\xdb=\xafZ\x98A\xa9\xbc'\xdc\xec\xa9wCB\xaf" +
"\xe0\xdb\xf3\xb9\x03\xa2\xa0\x1ad\x98ـ-\xb4C\xa45K\xb5\xa6\x15\x87\xa9" +
"\xe9\x94j?\xb1\x9e\x10\xdf\x0dv\x7f\x1ai \x087\xe5\x17\xd2!y\x93M[\xa7ܳ" +
"\xfa\xae1ר\xe5\xfe\xe9y\xb9\xfc\x80F}Zje\xed\xbc\xc8Y.h\xfb\xb5 * S\xba" +
"\xba\xa8\xce\u07be\x03\xa6\x05\xcf\xe7,\x16i\x0ap\xbd\x16\xd6\xda$\xaf}0" +
"\xf1&\x0bCT\x19\x82x\xd5\x0c\xc7\x13\xf8\xa2R&~\x0b\xa5F\x8f\xa6\x8cݺ\\_" +
"\x06\xf8\xfc$\xbc\xda\xc1H\xe2\xf4\x7f\x84}L\x83\xfb{\xfe@\x09\xa8HF\xaf" +
"\xedRx\x9f\xbd\x0c\x0d\x06\xa5b\xebm\x9e#\xebwI\xfeDp}K\xc1\xd7\xe0\x86#" +
"\x1c;\x0f\xed\x0e`\x05\x9b\x86EI5w\xd9\x05\xfe\xb0zx\xc7T0v֚?S\xaf\xb2" +
"\x9b\x1a\x86\x12ꔚg\x14FB\xe8\x8fKvͫ\xfaz\x9c\x82\x87e\x08\x1f\x9c\x97" +
"\xc3\xc2 \x7f\x1a\xd2M#\x1f\xc2B\xcdJ\x05\xf5\x22\x94ʸ\x11\x05\xf9̄PA" +
"\x15\x8f\x0e5\xf3\xa6v\\ll\xd89y\x06\x08\x01!~\x06\xe3\x04_\xa3\x97j\xec" +
"\xeamZ\xb0\x10\x13\xdaW\x18pN\x1a\xab!\xf2k<\xea\xca\xe9%\x19\xf1\xb9" +
"\x0a\x84\xc1\x06\x84\xcb\x08\xe4\xe2\x037\xf2\x92ǭ\xd4\x0c\xf3;4b<\xc5.%" +
"\xc2!\x079\x8b\x9dG\xc9U\x86\xe6\\22\xf6\xee\xb5lʆ%\xbd\x9e\xfeQV\xf3u" +
"\xa7\xd4r \xecV\xc8V\xb1\x96\xb4\x9f2D\x88m\x13\x94\xa6X瘳\xc9\xcc\xe8K[y" +
"\xa4L\x01'IPP\xfe\xaaI+\xef)l\x86lE\xb8\xd4=\x81\x0f\x0b9렭\xf7_H\xaa\xf1" +
"\x0c\x17\xcf6\xa4\x02\xe1T\xf9\x14\xe9\x0e\xd5WmE}\xa5)\xe7s\xfc\x0c16" +
"\xd4U\xaa\x8d\xc9\xe0m\xd6\x0a\x0e\xf5ȷ9\xfen_\x02=U&vcX\x80EY U\x93\x02" +
"9\x02A\x86\xe5HGX\xf4\xed\x9ckFx(\xa2?\xfa7\x17\x8eCce\xb9\x0f5\xac\xbc" +
"\xf4\xa6\xe2C5\xdd\x08{\x1e\xd9c\x96>K\xc3\xf83\xaaܾ%\xf3\x91\x1b\xf8U" +
"\x1f\xfa<\xfd\xefв\x1b̹\x19f\xb2O\x81>f渃@\xf47l\xc9k\x13F\x1a\xa3\x84" +
"\xad\xa0\xda=_z\xf1́\x13l\xf6J\xd0\xdb\xe6\xed\x9d^ݹ\x19\x0fK\xa1H\x0b-" +
"\x7f\xed\xa8\xde&V\xbc\x9ak\xb8\x15\xc2\x12bWU\x08N1#\xe1W9ޗӬ\xacG\x80" +
"\xb2\x83ozH\xcd?\xd0T\x04ϭ\x03\xccfi\x05\xec\x02k\x9ej\x94\xa9S\xf2\xd4" +
"\xf8\x16r\x03era\x05month\x09enFutMOne\x0benFutMOther\x0aenPastMOne\x0ce" +
"nPastMOther\x03mo.\x08last mo.\x08this mo.\x08next mo.\x0eenShortFutMOne" +
"\x10enShortFutMOther\x0fenShortPastMOne\x11enShortPastMOther\x0a001AbbrM" +
"o1\x0a001AbbrMo2\x0a001AbbrMo3\x0a001AbbrMo4\x0a001AbbrMo5\x0a001AbbrMo6" +
"\x0a001AbbrMo7\x0a001AbbrMo8\x0a001AbbrMo9\x0b001AbbrMo10\x0b001AbbrMo11" +
"\x0b001AbbrMo12"
var bucket1 string = "" + // Size: xxxx bytes
"\xfe\x99ҧ\xa2ݭ\x8a\xb6\xc7&\xe6\xbe.\xca:\xec\xeb4\x0f\xd7;\xfc\x09xhhkw" +
"'\x1f\x0fb\xfb8\xe3UU^S%0XxD\x83Zg\xff\xe7\x1ds\x97n\xef\xf95\xd3k\xbf$:" +
"\x99\xbbnU\xba:n\xdeM.\xa4st\xa6E\x0eG\xf5\xf0\xd6.Q-\x1e8\x87\x11X\xf2" +
"\x19\xc1J\xacI57\xdc\x07\xf0\x87\xc1cMc\x9e\xdc\x0a\xb3%\xff\x03\xe2aR" +
"\x06,\xbf!4J\x8b]4ΙWš\x1dY2\x88:\xb9Q\x16\xfc\xb5r\xf7\xc5d^\x97\x08\xce" +
"\x04EG@\u05fa\x88\x885\x08\x8c/\x83r\x92\xb8\x96\xd4\xfa\x8d\x18\x0fF" +
"\xfd\xa2\x01\xfb\xb0\xa0ڐӔ\xca\xcd\xf7@=\xe2\x96\x03\x87\x8aH\xfa\xc3L" +
"\xa2\xe90H\x93\xf6\x80\x8ck\x05)u{d\xa4\x19D\xd4{\xfd\xb8\xc5\xc0)\xea" +
"\x01\x9b\xcb&\x12\x87y\xf6{\xbb\xcdm\x0az/\xcb\xce#\x1c\x86R\xccy\xdbC" +
"\x7f\xa2\x96\x94\xc2\x22O/\xe4t\xfe\xba4 \xc3\xf1Hdy{܃L\x9aG\xa3\xa9\xea" +
"!LmW\x05\x9d$\x01\xe5wp\x8a'<\xc1\xcao\x8d\x1b\x8d\xd8h\xccX\xdc\xe4\xfd" +
"j\xf6\x0b\xa5'\xad\xe2\x1a\x16\x8fD\xde5\x0d\xaeL\xeft\xe1\x1f/\xd8\xec" +
"\xc9\xc0\xc6C#\x18\xfa\x93\x11Wt\x82\xfc\xa7\x1c\x82\x1b\xfd\x95`\xbd" +
"\x9f;[\xb3\x9e'\xe8DmA/^Ŭ]\x15-\xf9ـb\xea\xe9\x1f\xd9̂\x92\xc8\xddL%\xaf" +
"\xd0\xcc\xc7\x02L\xbb:P3\x22\xbfU\x81\U000d06a1\xa2\xf9q\x96\xbc2\x8e" +
"\x8f\xb4\x80\xbe\x06`\x8b\x0b\xaf\xd2\xd2J\xccV>\xc7d\xf5\xfd\x1c?\xbc7⏟" +
"\xb9%\xf0\xc4\xfe\xf3P\xed\x13V<CG\x99\x12\xc2 \x8e1\x0e\xcej\x12}\xe2P" +
"\xe4\x22\xba\xf5\xb0\x98q|A\xc5\xc8\xc2\xc8\x18w\xb7yb;n\x97\\6F\xe8\xd1" +
"1\xe2Eh\x0b\x95\x09v\xc0Ze?y\xeb\xcc\xe2\xa3\xf26ۦ\xec\x02f\x11oto\xe9z" +
"\x89\xfe\x0e\x7fh\xd1\xf3\x02\x86\xde]\x86\x0a\xbeq7R\xb0\xa1\xf8\x9eLj" +
"\x05\xc4\xfd\xa7B\xe4\xbc8\xff\x1ao\xff\xc7r\xb2I\xec\x94a\x84ԯ\xe6\x919" +
"\x8a\xe3\xc5kM\xe1\x09\x02?\x18jtstj\xbe\xe3P}G\xd0e\xc8Ď\x1e\xaa$\x97" +
"\xbce\x18mx6\xaf\xe10vP\xde\xc5#\xb0\xca\xc7N\x94駢\xf0\xc35\xf6\xb6c\x00" +
":\x18\x22\x1dM\xd2\x1a\\\xdb`\xc1v\x18\xfdh\xae\x1d\xc0\x96}{mSXn]\xd29" +
"\xfdϧT\xccu\xd5\xc0\x88JΆ\x9c:\xd3\x7fﺉc\x1a%Œ:\x9cln\xaa\x08\x1e\x85U+e" +
"\x958V `\xc3C\x0d\xd9ُB\xb0ҁt\xa7\x16\x90_\x84\xc1e\xd4m\x17M\x04\xbe*`" +
"\x9dS\x0e\x01M\xa6\xb7va\xa0\xeb\xf9\xb6\xaeP>ܦ\xd7FR\x9b7\xabPu\xaa\xcf" +
"\xfca;k\xb2+\xe0zXKL\xbd\xce\xde.&\xf5ԛ\xbck\x1b\xd4F\x84\xac\x08#\x02mo" +
"\x0f001ShortFutMOne\x11001ShortFutMOther\x12001ShortPastMOther\x10001Nar" +
"rowFutMOne\x10001NarrowFutMTwo\x12001NarrowFutMOther\x11001NarrowPastMOn" +
"e\x13001NarrowPastMOther\x08gbAbbrM1\x08gbAbbrM2\x08gbAbbrM3\x08gbAbbrM4" +
"\x08gbAbbrM5\x08gbAbbrM6\x08gbAbbrM7\x08gbAbbrM8\x08gbAbbrM9\x09gbAbbrM1" +
"0\x09gbAbbrM11\x09gbAbbrM12\x08gbWideM1\x08gbWideM2\x08gbWideM3\x08gbWid" +
"eM4\x08gbWideM5\x08gbWideM6\x08gbWideM7\x08gbWideM8\x08gbWideM9\x09gbWid" +
"eM10\x09gbWideM11\x09gbWideM12\x0agbNarrowM1\x0agbNarrowM2\x0agbNarrowM3" +
"\x0agbNarrowM5\x0agbNarrowM6\x0agbNarrowM8\x0agbNarrowM9\x0bgbNarrowM10" +
"\x0bgbNarrowM11\x0bgbNarrowM12\xfeG*:*\x8e\xf9f̷\xb2p\xaa\xb9\x12{и\xf7c" +
"\u0088\xdb\x0ce\xfd\xd7\xfc_T\x0f\x05\xf9\xf1\xc1(\x80\xa2)H\x09\x02\x15" +
"\xe8Y!\xc2\xc8\xc3뿓d\x03vԧi%\xb5\xc0\x8c\x05m\x87\x0d\x02y\xe9F\xa9\xe1" +
"\xe1!e\xbc\x1a\x8d\xa0\x93q\x8b\x0c߮\xcdF\xd1Kpx\x87/is\xcc\xdd\xe0\xafʍ" +
"~\xfeҜl\xc2B\xc5\x1a\xa4#ث,kF\xe89\xec\xe6~\xaa\x12\xbf\x1a\xf6L\x0a\xba" +
"\xa9\x96n\xf1\x03Ӊ<\xf5\x03\x84dp\x98\xe1d\xf7'\x94\xe6\x97\x1a4/\x05" +
"\x99\x8f.\x7foH@\xe9\x1a\xda6`MQ\xad\x0d\x08\x99؟+\xe53\xbf\x97\x88~\xe6" +
"eh\xb7\xaf\xaf<\xe1|\xb9\x0cF\xe0\xda\xf2\xbd\xff\x19\xaa\x95\x9b\x81" +
"\xc3\x04\xe3\x1f\xd5o]$\xf5\x0f\xbbzU\xf2a\xb0\x92[\xfeX\x03\x1f\xdc\x0c" +
"\xd5I\xc0a_\xbd\xd8\xde\u009a\x1a@t\x1e\x7f\x8f&\x0c\x8d\xfeM\xd7ڟX\x90" +
"\x97\xfe%\xa3'\x88\x81\xb5\x14l\x0bL\xd9>\x8d\x99\xe2=ƭu,\x9aT \x06\xc1y" +
"\\\x01wf\xdcx\xab\xa1\xee\xec\x82\x1e8\xb09$\x88\xfe<\xb5\x13g\x95\x15NS" +
"\x83`vx\xb9\xb7\xd8h\xc7 \x9e\x9fL\x06\x9a\xadtV\xc9\x13\x85\x0d8\xc15R" +
"\xe5\xadEL\xf0\x0f\x8b:\xf6\x90\x16i۰W\x9dv\xee\xb6B\x80`Ωb\xc7w\x11\xa3" +
"N\x17\xee\xb7\xe0\xbf\xd4a\x0a\x8a\x18g\xb82\x8e\xaaVCG\xc3Ip\xc0^6\xa8N" +
"\xf1\xebt\xa6\xa4\x0cO\xd9c\x97\x8f\xfa\x11)\x1bHY\xa2ӄ\x1bLc\xd6\x08" +
"\x06\xbfj`?3s\x89\xb8\x82(\xaf\xef\x84\xdfz\xc3\x12\xf1b\xd4\xf7ir\xe8," +
"\x8apœ\x00F\xa6b+\xfa}\x03\x14..\xcb1l\xac\x93\xee\x19\x12\xaa\xbbo\x95" +
"\xf3?ݔ7\x84\xb2b\x0c4\x81\x17\xf2K@\xde\x18\x99Q\x17n\xe5?\xdao\xc6(\xfc" +
"\x9b\xees\xc6V\x91\x0dْ\x1d\x06g9o"
var enumMap = map[string]uint16{
"": 0,
"calendars": 0,
"fields": 1,
"buddhist": 0,
"chinese": 1,
"dangi": 2,
"ethiopic": 3,
"ethiopic-amete-alem": 4,
"generic": 5,
"gregorian": 6,
"hebrew": 7,
"islamic": 8,
"islamic-civil": 9,
"islamic-rgsa": 10,
"islamic-tbla": 11,
"islamic-umalqura": 12,
"persian": 13,
"months": 0,
"eras": 1,
"filler": 2,
"cyclicNameSets": 3,
"format": 0,
"stand-alone": 1,
"wAbbreviated": 0,
"wNarrow": 1,
"wWide": 2,
"leap7": 0,
"variant": 1,
"cycDayParts": 0,
"cycDays": 1,
"cycMonths": 2,
"cycYears": 3,
"cycZodiacs": 4,
"era": 0,
"era-short": 1,
"era-narrow": 2,
"month": 3,
"month-short": 4,
"month-narrow": 5,
"displayName": 0,
"relative": 1,
"relativeTime": 2,
"before1": 0,
"current": 1,
"after1": 2,
"future": 0,
"past": 1,
"other": 0,
"one": 1,
"two": 2,
}
// Total table size: xxxx bytes (14KiB); checksum: 4BFC5D9
+181
View File
@@ -0,0 +1,181 @@
// Copyright 2017 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 cldrtree
import (
"golang.org/x/text/internal"
"golang.org/x/text/language"
)
const (
inheritOffsetShift = 12
inheritMask uint16 = 0x8000
inheritValueMask uint16 = 0x0FFF
missingValue uint16 = 0xFFFF
)
// Tree holds a tree of CLDR data.
type Tree struct {
Locales []uint32
Indices []uint16
Buckets []string
}
// Lookup looks up CLDR data for the given path. The lookup adheres to the alias
// and locale inheritance rules as defined in CLDR.
//
// Each subsequent element in path indicates which subtree to select data from.
// The last element of the path must select a leaf node. All other elements
// of the path select a subindex.
func (t *Tree) Lookup(tag int, path ...uint16) string {
return t.lookup(tag, false, path...)
}
// LookupFeature is like Lookup, but will first check whether a value of "other"
// as a fallback before traversing the inheritance chain.
func (t *Tree) LookupFeature(tag int, path ...uint16) string {
return t.lookup(tag, true, path...)
}
func (t *Tree) lookup(tag int, isFeature bool, path ...uint16) string {
origLang := tag
outer:
for {
index := t.Indices[t.Locales[tag]:]
k := uint16(0)
for i := range path {
max := index[k]
if i < len(path)-1 {
// index (non-leaf)
if path[i] >= max {
break
}
k = index[k+1+path[i]]
if k == 0 {
break
}
if v := k &^ inheritMask; k != v {
offset := v >> inheritOffsetShift
value := v & inheritValueMask
path[uint16(i)-offset] = value
tag = origLang
continue outer
}
} else {
// leaf value
offset := missingValue
if path[i] < max {
offset = index[k+2+path[i]]
}
if offset == missingValue {
if !isFeature {
break
}
// "other" feature must exist
offset = index[k+2]
}
data := t.Buckets[index[k+1]]
n := uint16(data[offset])
return data[offset+1 : offset+n+1]
}
}
if tag == 0 {
break
}
tag = int(internal.Parent[tag])
}
return ""
}
func build(b *Builder) (*Tree, error) {
var t Tree
t.Locales = make([]uint32, language.NumCompactTags)
for _, loc := range b.locales {
tag, _ := language.CompactIndex(loc.tag)
t.Locales[tag] = uint32(len(t.Indices))
var x indexBuilder
x.add(loc.root)
t.Indices = append(t.Indices, x.index...)
}
// Set locales for which we don't have data to the parent's data.
for i, v := range t.Locales {
p := uint16(i)
for v == 0 && p != 0 {
p = internal.Parent[p]
v = t.Locales[p]
}
t.Locales[i] = v
}
for _, b := range b.buckets {
t.Buckets = append(t.Buckets, string(b))
}
if b.err != nil {
return nil, b.err
}
return &t, nil
}
type indexBuilder struct {
index []uint16
}
func (b *indexBuilder) add(i *Index) uint16 {
offset := len(b.index)
max := enumIndex(0)
switch {
case len(i.values) > 0:
for _, v := range i.values {
if v.key > max {
max = v.key
}
}
b.index = append(b.index, make([]uint16, max+3)...)
b.index[offset] = uint16(max) + 1
b.index[offset+1] = i.values[0].value.bucket
for i := offset + 2; i < len(b.index); i++ {
b.index[i] = missingValue
}
for _, v := range i.values {
b.index[offset+2+int(v.key)] = v.value.bucketPos
}
return uint16(offset)
case len(i.subIndex) > 0:
for _, s := range i.subIndex {
if s.meta.index > max {
max = s.meta.index
}
}
b.index = append(b.index, make([]uint16, max+2)...)
b.index[offset] = uint16(max) + 1
for _, s := range i.subIndex {
x := b.add(s)
b.index[offset+int(s.meta.index)+1] = x
}
return uint16(offset)
case i.meta.inheritOffset < 0:
v := uint16(-(i.meta.inheritOffset + 1)) << inheritOffsetShift
p := i.meta
for k := i.meta.inheritOffset; k < 0; k++ {
p = p.parent
}
v += uint16(p.typeInfo.enum.lookup(i.meta.inheritIndex))
v |= inheritMask
return v
}
return 0
}
+139
View File
@@ -0,0 +1,139 @@
// Copyright 2017 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 cldrtree
import (
"log"
"strconv"
)
// enumIndex is the numerical value of an enum value.
type enumIndex int
// An enum is a collection of enum values.
type enum struct {
name string // the Go type of the enum
rename func(string) string
keyMap map[string]enumIndex
keys []string
}
// lookup returns the index for the enum corresponding to the string. If s
// currently does not exist it will add the entry.
func (e *enum) lookup(s string) enumIndex {
if e.rename != nil {
s = e.rename(s)
}
x, ok := e.keyMap[s]
if !ok {
if e.keyMap == nil {
e.keyMap = map[string]enumIndex{}
}
u, err := strconv.ParseUint(s, 10, 32)
if err == nil {
for len(e.keys) <= int(u) {
x := enumIndex(len(e.keys))
s := strconv.Itoa(int(x))
e.keyMap[s] = x
e.keys = append(e.keys, s)
}
if e.keyMap[s] != enumIndex(u) {
// TODO: handle more gracefully.
log.Fatalf("cldrtree: mix of integer and non-integer for %q %v", s, e.keys)
}
return enumIndex(u)
}
x = enumIndex(len(e.keys))
e.keyMap[s] = x
e.keys = append(e.keys, s)
}
return x
}
// A typeInfo indicates the set of possible enum values and a mapping from
// these values to subtypes.
type typeInfo struct {
enum *enum
entries map[enumIndex]*typeInfo
keyTypeInfo *typeInfo
shareKeys bool
}
func (t *typeInfo) sharedKeys() bool {
return t.shareKeys
}
func (t *typeInfo) lookupSubtype(s string, opts *options) (x enumIndex, sub *typeInfo) {
if t.enum == nil {
if t.enum = opts.sharedEnums; t.enum == nil {
t.enum = &enum{}
}
}
if opts.sharedEnums != nil && t.enum != opts.sharedEnums {
panic("incompatible enums defined")
}
x = t.enum.lookup(s)
if t.entries == nil {
t.entries = map[enumIndex]*typeInfo{}
}
sub, ok := t.entries[x]
if !ok {
sub = opts.sharedType
if sub == nil {
sub = &typeInfo{}
}
t.entries[x] = sub
}
t.shareKeys = opts.sharedType != nil // For analysis purposes.
return x, sub
}
// metaData includes information about subtypes, possibly sharing commonality
// with sibling branches, and information about inheritance, which may differ
// per branch.
type metaData struct {
b *Builder
parent *metaData
index enumIndex // index into the parent's subtype index
key string
elem string // XML element corresponding to this type.
typeInfo *typeInfo
lookup map[enumIndex]*metaData
subs []*metaData
inheritOffset int // always negative when applicable
inheritIndex string // new value for field indicated by inheritOffset
// inheritType *metaData
}
func (m *metaData) sub(key string, opts *options) *metaData {
if m.lookup == nil {
m.lookup = map[enumIndex]*metaData{}
}
enum, info := m.typeInfo.lookupSubtype(key, opts)
sub := m.lookup[enum]
if sub == nil {
sub = &metaData{
b: m.b,
parent: m,
index: enum,
key: key,
typeInfo: info,
}
m.lookup[enum] = sub
m.subs = append(m.subs, sub)
}
return sub
}
func (m *metaData) validate() {
for _, s := range m.subs {
s.validate()
}
}
+1 -1
View File
@@ -100,7 +100,7 @@ func genTables() {
})
w := gen.NewCodeWriter()
defer w.WriteGoFile("tables.go", "idna")
defer w.WriteVersionedGoFile("tables.go", "idna")
gen.WriteUnicodeVersion(w)
@@ -2,6 +2,8 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build go1.10
package idna
import (
+84
View File
@@ -0,0 +1,84 @@
// Copyright 2016 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.
// +build !go1.10
package idna
import (
"testing"
"unicode"
"golang.org/x/text/internal/gen"
"golang.org/x/text/internal/testtext"
"golang.org/x/text/internal/ucd"
)
func TestTables(t *testing.T) {
testtext.SkipIfNotLong(t)
lookup := func(r rune) info {
v, _ := trie.lookupString(string(r))
return info(v)
}
ucd.Parse(gen.OpenUnicodeFile("idna", "", "IdnaMappingTable.txt"), func(p *ucd.Parser) {
r := p.Rune(0)
x := lookup(r)
if got, want := x.category(), catFromEntry(p); got != want {
t.Errorf("%U:category: got %x; want %x", r, got, want)
}
mapped := false
switch p.String(1) {
case "mapped", "disallowed_STD3_mapped", "deviation":
mapped = true
}
if x.isMapped() != mapped {
t.Errorf("%U:isMapped: got %v; want %v", r, x.isMapped(), mapped)
}
if !mapped {
return
}
want := string(p.Runes(2))
got := string(x.appendMapping(nil, string(r)))
if got != want {
t.Errorf("%U:mapping: got %+q; want %+q", r, got, want)
}
if x.isMapped() {
return
}
wantMark := unicode.In(r, unicode.Mark)
gotMark := x.isModifier()
if gotMark != wantMark {
t.Errorf("IsMark(%U) = %v; want %v", r, gotMark, wantMark)
}
})
ucd.Parse(gen.OpenUCDFile("UnicodeData.txt"), func(p *ucd.Parser) {
r := p.Rune(0)
x := lookup(r)
got := x.isViramaModifier()
const cccVirama = 9
want := p.Int(ucd.CanonicalCombiningClass) == cccVirama
if got != want {
t.Errorf("IsVirama(%U) = %v; want %v", r, got, want)
}
})
ucd.Parse(gen.OpenUCDFile("extracted/DerivedJoiningType.txt"), func(p *ucd.Parser) {
r := p.Rune(0)
x := lookup(r)
if x.isMapped() {
return
}
got := x.joinType()
want := joinType[p.String(1)]
if got != want {
t.Errorf("JoinType(%U) = %x; want %x", r, got, want)
}
})
}
@@ -2,6 +2,7 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
// +build go1.10
//go:generate go run gen.go gen_trieval.go gen_common.go
// Package idna implements IDNA2008 using the compatibility processing
@@ -309,7 +310,7 @@ func (p *Profile) process(s string, toASCII bool) (string, error) {
for ; len(s) > 0 && s[0] == '.'; s = s[1:] {
}
}
// TODO: allow for a quick check the tables data.
// TODO: allow for a quick check of the tables data.
// It seems like we should only create this error on ToASCII, but the
// UTS 46 conformance tests suggests we should always check this.
if err == nil && p.verifyDNSLength && s == "" {
@@ -405,6 +406,9 @@ func validateRegistration(p *Profile, s string) (idem string, bidi bool, err err
}
for i := 0; i < len(s); {
v, sz := trie.lookupString(s[i:])
if sz == 0 {
return s, bidi, runeError(utf8.RuneError)
}
bidi = bidi || info(v).isBidi(s[i:])
// Copy bytes not copied so far.
switch p.simplify(info(v).category()) {
@@ -446,6 +450,15 @@ func validateAndMap(p *Profile, s string) (vm string, bidi bool, err error) {
var combinedInfoBits info
for i := 0; i < len(s); {
v, sz := trie.lookupString(s[i:])
if sz == 0 {
b = append(b, s[k:i]...)
b = append(b, "\ufffd"...)
k = len(s)
if err == nil {
err = runeError(utf8.RuneError)
}
break
}
combinedInfoBits |= info(v)
bidi = bidi || info(v).isBidi(s[i:])
start := i
@@ -584,6 +597,9 @@ func validateFromPunycode(p *Profile, s string) error {
// loop.
for i := 0; i < len(s); {
v, sz := trie.lookupString(s[i:])
if sz == 0 {
return runeError(utf8.RuneError)
}
if c := p.simplify(info(v).category()); c != valid && c != deviation {
return &labelError{s, "V6"}
}
+140
View File
@@ -0,0 +1,140 @@
// Copyright 2016 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.
// +build go1.10
package idna
import "testing"
// TestLabelErrors tests strings returned in case of error. All results should
// be identical to the reference implementation and can be verified at
// http://unicode.org/cldr/utility/idna.jsp. The reference implementation,
// however, seems to not display Bidi and ContextJ errors.
//
// In some cases the behavior of browsers is added as a comment. In all cases,
// whenever a resolve search returns an error here, Chrome will treat the input
// string as a search string (including those for Bidi and Context J errors),
// unless noted otherwise.
func TestLabelErrors(t *testing.T) {
encode := func(s string) string { s, _ = encode(acePrefix, s); return s }
type kind struct {
name string
f func(string) (string, error)
}
punyA := kind{"PunycodeA", punycode.ToASCII}
resolve := kind{"ResolveA", Lookup.ToASCII}
display := kind{"ToUnicode", Display.ToUnicode}
p := New(VerifyDNSLength(true), MapForLookup(), BidiRule())
lengthU := kind{"CheckLengthU", p.ToUnicode}
lengthA := kind{"CheckLengthA", p.ToASCII}
p = New(MapForLookup(), StrictDomainName(false))
std3 := kind{"STD3", p.ToASCII}
testCases := []struct {
kind
input string
want string
wantErr string
}{
{lengthU, "", "", "A4"}, // From UTS 46 conformance test.
{lengthA, "", "", "A4"},
{lengthU, "xn--", "", "A4"},
{lengthU, "foo.xn--", "foo.", "A4"}, // TODO: is dropping xn-- correct?
{lengthU, "xn--.foo", ".foo", "A4"},
{lengthU, "foo.xn--.bar", "foo..bar", "A4"},
{display, "xn--", "", ""},
{display, "foo.xn--", "foo.", ""}, // TODO: is dropping xn-- correct?
{display, "xn--.foo", ".foo", ""},
{display, "foo.xn--.bar", "foo..bar", ""},
{lengthA, "a..b", "a..b", "A4"},
{punyA, ".b", ".b", ""},
// For backwards compatibility, the Punycode profile does not map runes.
{punyA, "\u3002b", "xn--b-83t", ""},
{punyA, "..b", "..b", ""},
{lengthA, ".b", ".b", "A4"},
{lengthA, "\u3002b", ".b", "A4"},
{lengthA, "..b", "..b", "A4"},
{lengthA, "b..", "b..", ""},
// Sharpened Bidi rules for Unicode 10.0.0. Apply for ALL labels in ANY
// of the labels is RTL.
{lengthA, "\ufe05\u3002\u3002\U0002603e\u1ce0", "..xn--t6f5138v", "A4"},
{lengthA, "FAX\u2a77\U0001d186\u3002\U0001e942\U000e0181\u180c", "", "B6"},
{resolve, "a..b", "a..b", ""},
// Note that leading dots are not stripped. This is to be consistent
// with the Punycode profile as well as the conformance test.
{resolve, ".b", ".b", ""},
{resolve, "\u3002b", ".b", ""},
{resolve, "..b", "..b", ""},
{resolve, "b..", "b..", ""},
{resolve, "\xed", "", "P1"},
// Raw punycode
{punyA, "", "", ""},
{punyA, "*.foo.com", "*.foo.com", ""},
{punyA, "Foo.com", "Foo.com", ""},
// STD3 rules
{display, "*.foo.com", "*.foo.com", "P1"},
{std3, "*.foo.com", "*.foo.com", ""},
// Don't map U+2490 (DIGIT NINE FULL STOP). This is the behavior of
// Chrome, Safari, and IE. Firefox will first map ⒐ to 9. and return
// lab9.be.
{resolve, "lab⒐be", "xn--labbe-zh9b", "P1"}, // encode("lab⒐be")
{display, "lab⒐be", "lab⒐be", "P1"},
{resolve, "plan⒐faß.de", "xn--planfass-c31e.de", "P1"}, // encode("plan⒐fass") + ".de"
{display, "Plan⒐faß.de", "plan⒐faß.de", "P1"},
// Chrome 54.0 recognizes the error and treats this input verbatim as a
// search string.
// Safari 10.0 (non-conform spec) decomposes "⒈" and computes the
// punycode on the result using transitional mapping.
// Firefox 49.0.1 goes haywire on this string and prints a bunch of what
// seems to be nested punycode encodings.
{resolve, "日本⒈co.ßßß.de", "xn--co-wuw5954azlb.ssssss.de", "P1"},
{display, "日本⒈co.ßßß.de", "日本⒈co.ßßß.de", "P1"},
{resolve, "a\u200Cb", "ab", ""},
{display, "a\u200Cb", "a\u200Cb", "C"},
{resolve, encode("a\u200Cb"), encode("a\u200Cb"), "C"},
{display, "a\u200Cb", "a\u200Cb", "C"},
{resolve, "grﻋﺮﺑﻲ.de", "xn--gr-gtd9a1b0g.de", "B"},
{
// Notice how the string gets transformed, even with an error.
// Chrome will use the original string if it finds an error, so not
// the transformed one.
display,
"gr\ufecb\ufeae\ufe91\ufef2.de",
"gr\u0639\u0631\u0628\u064a.de",
"B",
},
{resolve, "\u0671.\u03c3\u07dc", "xn--qib.xn--4xa21s", "B"}, // ٱ.σߜ
{display, "\u0671.\u03c3\u07dc", "\u0671.\u03c3\u07dc", "B"},
// normalize input
{resolve, "a\u0323\u0322", "xn--jta191l", ""}, // ạ̢
{display, "a\u0323\u0322", "\u1ea1\u0322", ""},
// Non-normalized strings are not normalized when they originate from
// punycode. Despite the error, Chrome, Safari and Firefox will attempt
// to look up the input punycode.
{resolve, encode("a\u0323\u0322") + ".com", "xn--a-tdbc.com", "V1"},
{display, encode("a\u0323\u0322") + ".com", "a\u0323\u0322.com", "V1"},
}
for _, tc := range testCases {
doTest(t, tc.f, tc.name, tc.input, tc.want, tc.wantErr)
}
}
+681
View File
@@ -0,0 +1,681 @@
// Copyright 2016 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.
// +build !go1.10
//go:generate go run gen.go gen_trieval.go gen_common.go
// Package idna implements IDNA2008 using the compatibility processing
// defined by UTS (Unicode Technical Standard) #46, which defines a standard to
// deal with the transition from IDNA2003.
//
// IDNA2008 (Internationalized Domain Names for Applications), is defined in RFC
// 5890, RFC 5891, RFC 5892, RFC 5893 and RFC 5894.
// UTS #46 is defined in http://www.unicode.org/reports/tr46.
// See http://unicode.org/cldr/utility/idna.jsp for a visualization of the
// differences between these two standards.
package idna // import "golang.org/x/text/internal/export/idna"
import (
"fmt"
"strings"
"unicode/utf8"
"golang.org/x/text/secure/bidirule"
"golang.org/x/text/unicode/norm"
)
// NOTE: Unlike common practice in Go APIs, the functions will return a
// sanitized domain name in case of errors. Browsers sometimes use a partially
// evaluated string as lookup.
// TODO: the current error handling is, in my opinion, the least opinionated.
// Other strategies are also viable, though:
// Option 1) Return an empty string in case of error, but allow the user to
// specify explicitly which errors to ignore.
// Option 2) Return the partially evaluated string if it is itself a valid
// string, otherwise return the empty string in case of error.
// Option 3) Option 1 and 2.
// Option 4) Always return an empty string for now and implement Option 1 as
// needed, and document that the return string may not be empty in case of
// error in the future.
// I think Option 1 is best, but it is quite opinionated.
// ToASCII is a wrapper for Punycode.ToASCII.
func ToASCII(s string) (string, error) {
return Punycode.process(s, true)
}
// ToUnicode is a wrapper for Punycode.ToUnicode.
func ToUnicode(s string) (string, error) {
return Punycode.process(s, false)
}
// An Option configures a Profile at creation time.
type Option func(*options)
// Transitional sets a Profile to use the Transitional mapping as defined in UTS
// #46. This will cause, for example, "ß" to be mapped to "ss". Using the
// transitional mapping provides a compromise between IDNA2003 and IDNA2008
// compatibility. It is used by most browsers when resolving domain names. This
// option is only meaningful if combined with MapForLookup.
func Transitional(transitional bool) Option {
return func(o *options) { o.transitional = true }
}
// VerifyDNSLength sets whether a Profile should fail if any of the IDN parts
// are longer than allowed by the RFC.
func VerifyDNSLength(verify bool) Option {
return func(o *options) { o.verifyDNSLength = verify }
}
// RemoveLeadingDots removes leading label separators. Leading runes that map to
// dots, such as U+3002 IDEOGRAPHIC FULL STOP, are removed as well.
//
// This is the behavior suggested by the UTS #46 and is adopted by some
// browsers.
func RemoveLeadingDots(remove bool) Option {
return func(o *options) { o.removeLeadingDots = remove }
}
// ValidateLabels sets whether to check the mandatory label validation criteria
// as defined in Section 5.4 of RFC 5891. This includes testing for correct use
// of hyphens ('-'), normalization, validity of runes, and the context rules.
func ValidateLabels(enable bool) Option {
return func(o *options) {
// Don't override existing mappings, but set one that at least checks
// normalization if it is not set.
if o.mapping == nil && enable {
o.mapping = normalize
}
o.trie = trie
o.validateLabels = enable
o.fromPuny = validateFromPunycode
}
}
// StrictDomainName limits the set of permissable ASCII characters to those
// allowed in domain names as defined in RFC 1034 (A-Z, a-z, 0-9 and the
// hyphen). This is set by default for MapForLookup and ValidateForRegistration.
//
// This option is useful, for instance, for browsers that allow characters
// outside this range, for example a '_' (U+005F LOW LINE). See
// http://www.rfc-editor.org/std/std3.txt for more details This option
// corresponds to the UseSTD3ASCIIRules option in UTS #46.
func StrictDomainName(use bool) Option {
return func(o *options) {
o.trie = trie
o.useSTD3Rules = use
o.fromPuny = validateFromPunycode
}
}
// NOTE: the following options pull in tables. The tables should not be linked
// in as long as the options are not used.
// BidiRule enables the Bidi rule as defined in RFC 5893. Any application
// that relies on proper validation of labels should include this rule.
func BidiRule() Option {
return func(o *options) { o.bidirule = bidirule.ValidString }
}
// ValidateForRegistration sets validation options to verify that a given IDN is
// properly formatted for registration as defined by Section 4 of RFC 5891.
func ValidateForRegistration() Option {
return func(o *options) {
o.mapping = validateRegistration
StrictDomainName(true)(o)
ValidateLabels(true)(o)
VerifyDNSLength(true)(o)
BidiRule()(o)
}
}
// MapForLookup sets validation and mapping options such that a given IDN is
// transformed for domain name lookup according to the requirements set out in
// Section 5 of RFC 5891. The mappings follow the recommendations of RFC 5894,
// RFC 5895 and UTS 46. It does not add the Bidi Rule. Use the BidiRule option
// to add this check.
//
// The mappings include normalization and mapping case, width and other
// compatibility mappings.
func MapForLookup() Option {
return func(o *options) {
o.mapping = validateAndMap
StrictDomainName(true)(o)
ValidateLabels(true)(o)
RemoveLeadingDots(true)(o)
}
}
type options struct {
transitional bool
useSTD3Rules bool
validateLabels bool
verifyDNSLength bool
removeLeadingDots bool
trie *idnaTrie
// fromPuny calls validation rules when converting A-labels to U-labels.
fromPuny func(p *Profile, s string) error
// mapping implements a validation and mapping step as defined in RFC 5895
// or UTS 46, tailored to, for example, domain registration or lookup.
mapping func(p *Profile, s string) (string, error)
// bidirule, if specified, checks whether s conforms to the Bidi Rule
// defined in RFC 5893.
bidirule func(s string) bool
}
// A Profile defines the configuration of a IDNA mapper.
type Profile struct {
options
}
func apply(o *options, opts []Option) {
for _, f := range opts {
f(o)
}
}
// New creates a new Profile.
//
// With no options, the returned Profile is the most permissive and equals the
// Punycode Profile. Options can be passed to further restrict the Profile. The
// MapForLookup and ValidateForRegistration options set a collection of options,
// for lookup and registration purposes respectively, which can be tailored by
// adding more fine-grained options, where later options override earlier
// options.
func New(o ...Option) *Profile {
p := &Profile{}
apply(&p.options, o)
return p
}
// ToASCII converts a domain or domain label to its ASCII form. For example,
// ToASCII("bücher.example.com") is "xn--bcher-kva.example.com", and
// ToASCII("golang") is "golang". If an error is encountered it will return
// an error and a (partially) processed result.
func (p *Profile) ToASCII(s string) (string, error) {
return p.process(s, true)
}
// ToUnicode converts a domain or domain label to its Unicode form. For example,
// ToUnicode("xn--bcher-kva.example.com") is "bücher.example.com", and
// ToUnicode("golang") is "golang". If an error is encountered it will return
// an error and a (partially) processed result.
func (p *Profile) ToUnicode(s string) (string, error) {
pp := *p
pp.transitional = false
return pp.process(s, false)
}
// String reports a string with a description of the profile for debugging
// purposes. The string format may change with different versions.
func (p *Profile) String() string {
s := ""
if p.transitional {
s = "Transitional"
} else {
s = "NonTransitional"
}
if p.useSTD3Rules {
s += ":UseSTD3Rules"
}
if p.validateLabels {
s += ":ValidateLabels"
}
if p.verifyDNSLength {
s += ":VerifyDNSLength"
}
return s
}
var (
// Punycode is a Profile that does raw punycode processing with a minimum
// of validation.
Punycode *Profile = punycode
// Lookup is the recommended profile for looking up domain names, according
// to Section 5 of RFC 5891. The exact configuration of this profile may
// change over time.
Lookup *Profile = lookup
// Display is the recommended profile for displaying domain names.
// The configuration of this profile may change over time.
Display *Profile = display
// Registration is the recommended profile for checking whether a given
// IDN is valid for registration, according to Section 4 of RFC 5891.
Registration *Profile = registration
punycode = &Profile{}
lookup = &Profile{options{
transitional: true,
useSTD3Rules: true,
validateLabels: true,
removeLeadingDots: true,
trie: trie,
fromPuny: validateFromPunycode,
mapping: validateAndMap,
bidirule: bidirule.ValidString,
}}
display = &Profile{options{
useSTD3Rules: true,
validateLabels: true,
removeLeadingDots: true,
trie: trie,
fromPuny: validateFromPunycode,
mapping: validateAndMap,
bidirule: bidirule.ValidString,
}}
registration = &Profile{options{
useSTD3Rules: true,
validateLabels: true,
verifyDNSLength: true,
trie: trie,
fromPuny: validateFromPunycode,
mapping: validateRegistration,
bidirule: bidirule.ValidString,
}}
// TODO: profiles
// Register: recommended for approving domain names: don't do any mappings
// but rather reject on invalid input. Bundle or block deviation characters.
)
type labelError struct{ label, code_ string }
func (e labelError) code() string { return e.code_ }
func (e labelError) Error() string {
return fmt.Sprintf("idna: invalid label %q", e.label)
}
type runeError rune
func (e runeError) code() string { return "P1" }
func (e runeError) Error() string {
return fmt.Sprintf("idna: disallowed rune %U", e)
}
// process implements the algorithm described in section 4 of UTS #46,
// see http://www.unicode.org/reports/tr46.
func (p *Profile) process(s string, toASCII bool) (string, error) {
var err error
if p.mapping != nil {
s, err = p.mapping(p, s)
}
// Remove leading empty labels.
if p.removeLeadingDots {
for ; len(s) > 0 && s[0] == '.'; s = s[1:] {
}
}
// It seems like we should only create this error on ToASCII, but the
// UTS 46 conformance tests suggests we should always check this.
if err == nil && p.verifyDNSLength && s == "" {
err = &labelError{s, "A4"}
}
labels := labelIter{orig: s}
for ; !labels.done(); labels.next() {
label := labels.label()
if label == "" {
// Empty labels are not okay. The label iterator skips the last
// label if it is empty.
if err == nil && p.verifyDNSLength {
err = &labelError{s, "A4"}
}
continue
}
if strings.HasPrefix(label, acePrefix) {
u, err2 := decode(label[len(acePrefix):])
if err2 != nil {
if err == nil {
err = err2
}
// Spec says keep the old label.
continue
}
labels.set(u)
if err == nil && p.validateLabels {
err = p.fromPuny(p, u)
}
if err == nil {
// This should be called on NonTransitional, according to the
// spec, but that currently does not have any effect. Use the
// original profile to preserve options.
err = p.validateLabel(u)
}
} else if err == nil {
err = p.validateLabel(label)
}
}
if toASCII {
for labels.reset(); !labels.done(); labels.next() {
label := labels.label()
if !ascii(label) {
a, err2 := encode(acePrefix, label)
if err == nil {
err = err2
}
label = a
labels.set(a)
}
n := len(label)
if p.verifyDNSLength && err == nil && (n == 0 || n > 63) {
err = &labelError{label, "A4"}
}
}
}
s = labels.result()
if toASCII && p.verifyDNSLength && err == nil {
// Compute the length of the domain name minus the root label and its dot.
n := len(s)
if n > 0 && s[n-1] == '.' {
n--
}
if len(s) < 1 || n > 253 {
err = &labelError{s, "A4"}
}
}
return s, err
}
func normalize(p *Profile, s string) (string, error) {
return norm.NFC.String(s), nil
}
func validateRegistration(p *Profile, s string) (string, error) {
if !norm.NFC.IsNormalString(s) {
return s, &labelError{s, "V1"}
}
for i := 0; i < len(s); {
v, sz := trie.lookupString(s[i:])
// Copy bytes not copied so far.
switch p.simplify(info(v).category()) {
// TODO: handle the NV8 defined in the Unicode idna data set to allow
// for strict conformance to IDNA2008.
case valid, deviation:
case disallowed, mapped, unknown, ignored:
r, _ := utf8.DecodeRuneInString(s[i:])
return s, runeError(r)
}
i += sz
}
return s, nil
}
func validateAndMap(p *Profile, s string) (string, error) {
var (
err error
b []byte
k int
)
for i := 0; i < len(s); {
v, sz := trie.lookupString(s[i:])
start := i
i += sz
// Copy bytes not copied so far.
switch p.simplify(info(v).category()) {
case valid:
continue
case disallowed:
if err == nil {
r, _ := utf8.DecodeRuneInString(s[start:])
err = runeError(r)
}
continue
case mapped, deviation:
b = append(b, s[k:start]...)
b = info(v).appendMapping(b, s[start:i])
case ignored:
b = append(b, s[k:start]...)
// drop the rune
case unknown:
b = append(b, s[k:start]...)
b = append(b, "\ufffd"...)
}
k = i
}
if k == 0 {
// No changes so far.
s = norm.NFC.String(s)
} else {
b = append(b, s[k:]...)
if norm.NFC.QuickSpan(b) != len(b) {
b = norm.NFC.Bytes(b)
}
// TODO: the punycode converters require strings as input.
s = string(b)
}
return s, err
}
// A labelIter allows iterating over domain name labels.
type labelIter struct {
orig string
slice []string
curStart int
curEnd int
i int
}
func (l *labelIter) reset() {
l.curStart = 0
l.curEnd = 0
l.i = 0
}
func (l *labelIter) done() bool {
return l.curStart >= len(l.orig)
}
func (l *labelIter) result() string {
if l.slice != nil {
return strings.Join(l.slice, ".")
}
return l.orig
}
func (l *labelIter) label() string {
if l.slice != nil {
return l.slice[l.i]
}
p := strings.IndexByte(l.orig[l.curStart:], '.')
l.curEnd = l.curStart + p
if p == -1 {
l.curEnd = len(l.orig)
}
return l.orig[l.curStart:l.curEnd]
}
// next sets the value to the next label. It skips the last label if it is empty.
func (l *labelIter) next() {
l.i++
if l.slice != nil {
if l.i >= len(l.slice) || l.i == len(l.slice)-1 && l.slice[l.i] == "" {
l.curStart = len(l.orig)
}
} else {
l.curStart = l.curEnd + 1
if l.curStart == len(l.orig)-1 && l.orig[l.curStart] == '.' {
l.curStart = len(l.orig)
}
}
}
func (l *labelIter) set(s string) {
if l.slice == nil {
l.slice = strings.Split(l.orig, ".")
}
l.slice[l.i] = s
}
// acePrefix is the ASCII Compatible Encoding prefix.
const acePrefix = "xn--"
func (p *Profile) simplify(cat category) category {
switch cat {
case disallowedSTD3Mapped:
if p.useSTD3Rules {
cat = disallowed
} else {
cat = mapped
}
case disallowedSTD3Valid:
if p.useSTD3Rules {
cat = disallowed
} else {
cat = valid
}
case deviation:
if !p.transitional {
cat = valid
}
case validNV8, validXV8:
// TODO: handle V2008
cat = valid
}
return cat
}
func validateFromPunycode(p *Profile, s string) error {
if !norm.NFC.IsNormalString(s) {
return &labelError{s, "V1"}
}
for i := 0; i < len(s); {
v, sz := trie.lookupString(s[i:])
if c := p.simplify(info(v).category()); c != valid && c != deviation {
return &labelError{s, "V6"}
}
i += sz
}
return nil
}
const (
zwnj = "\u200c"
zwj = "\u200d"
)
type joinState int8
const (
stateStart joinState = iota
stateVirama
stateBefore
stateBeforeVirama
stateAfter
stateFAIL
)
var joinStates = [][numJoinTypes]joinState{
stateStart: {
joiningL: stateBefore,
joiningD: stateBefore,
joinZWNJ: stateFAIL,
joinZWJ: stateFAIL,
joinVirama: stateVirama,
},
stateVirama: {
joiningL: stateBefore,
joiningD: stateBefore,
},
stateBefore: {
joiningL: stateBefore,
joiningD: stateBefore,
joiningT: stateBefore,
joinZWNJ: stateAfter,
joinZWJ: stateFAIL,
joinVirama: stateBeforeVirama,
},
stateBeforeVirama: {
joiningL: stateBefore,
joiningD: stateBefore,
joiningT: stateBefore,
},
stateAfter: {
joiningL: stateFAIL,
joiningD: stateBefore,
joiningT: stateAfter,
joiningR: stateStart,
joinZWNJ: stateFAIL,
joinZWJ: stateFAIL,
joinVirama: stateAfter, // no-op as we can't accept joiners here
},
stateFAIL: {
0: stateFAIL,
joiningL: stateFAIL,
joiningD: stateFAIL,
joiningT: stateFAIL,
joiningR: stateFAIL,
joinZWNJ: stateFAIL,
joinZWJ: stateFAIL,
joinVirama: stateFAIL,
},
}
// validateLabel validates the criteria from Section 4.1. Item 1, 4, and 6 are
// already implicitly satisfied by the overall implementation.
func (p *Profile) validateLabel(s string) error {
if s == "" {
if p.verifyDNSLength {
return &labelError{s, "A4"}
}
return nil
}
if p.bidirule != nil && !p.bidirule(s) {
return &labelError{s, "B"}
}
if !p.validateLabels {
return nil
}
trie := p.trie // p.validateLabels is only set if trie is set.
if len(s) > 4 && s[2] == '-' && s[3] == '-' {
return &labelError{s, "V2"}
}
if s[0] == '-' || s[len(s)-1] == '-' {
return &labelError{s, "V3"}
}
// TODO: merge the use of this in the trie.
v, sz := trie.lookupString(s)
x := info(v)
if x.isModifier() {
return &labelError{s, "V5"}
}
// Quickly return in the absence of zero-width (non) joiners.
if strings.Index(s, zwj) == -1 && strings.Index(s, zwnj) == -1 {
return nil
}
st := stateStart
for i := 0; ; {
jt := x.joinType()
if s[i:i+sz] == zwj {
jt = joinZWJ
} else if s[i:i+sz] == zwnj {
jt = joinZWNJ
}
st = joinStates[st][jt]
if x.isViramaModifier() {
st = joinStates[st][joinVirama]
}
if i += sz; i == len(s) {
break
}
v, sz = trie.lookupString(s[i:])
x = info(v)
}
if st == stateFAIL || st == stateAfter {
return &labelError{s, "C"}
}
return nil
}
func ascii(s string) bool {
for i := 0; i < len(s); i++ {
if s[i] >= utf8.RuneSelf {
return false
}
}
return true
}
+136
View File
@@ -0,0 +1,136 @@
// Copyright 2016 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.
// +build !go1.10
package idna
import "testing"
// TestLabelErrors tests strings returned in case of error. All results should
// be identical to the reference implementation and can be verified at
// http://unicode.org/cldr/utility/idna.jsp. The reference implementation,
// however, seems to not display Bidi and ContextJ errors.
//
// In some cases the behavior of browsers is added as a comment. In all cases,
// whenever a resolve search returns an error here, Chrome will treat the input
// string as a search string (including those for Bidi and Context J errors),
// unless noted otherwise.
func TestLabelErrors(t *testing.T) {
encode := func(s string) string { s, _ = encode(acePrefix, s); return s }
type kind struct {
name string
f func(string) (string, error)
}
punyA := kind{"PunycodeA", punycode.ToASCII}
resolve := kind{"ResolveA", Lookup.ToASCII}
display := kind{"ToUnicode", Display.ToUnicode}
p := New(VerifyDNSLength(true), MapForLookup(), BidiRule())
lengthU := kind{"CheckLengthU", p.ToUnicode}
lengthA := kind{"CheckLengthA", p.ToASCII}
p = New(MapForLookup(), StrictDomainName(false))
std3 := kind{"STD3", p.ToASCII}
testCases := []struct {
kind
input string
want string
wantErr string
}{
{lengthU, "", "", "A4"}, // From UTS 46 conformance test.
{lengthA, "", "", "A4"},
{lengthU, "xn--", "", "A4"},
{lengthU, "foo.xn--", "foo.", "A4"}, // TODO: is dropping xn-- correct?
{lengthU, "xn--.foo", ".foo", "A4"},
{lengthU, "foo.xn--.bar", "foo..bar", "A4"},
{display, "xn--", "", ""},
{display, "foo.xn--", "foo.", ""}, // TODO: is dropping xn-- correct?
{display, "xn--.foo", ".foo", ""},
{display, "foo.xn--.bar", "foo..bar", ""},
{lengthA, "a..b", "a..b", "A4"},
{punyA, ".b", ".b", ""},
// For backwards compatibility, the Punycode profile does not map runes.
{punyA, "\u3002b", "xn--b-83t", ""},
{punyA, "..b", "..b", ""},
// Only strip leading empty labels for certain profiles. Stripping
// leading empty labels here but not for "empty" punycode above seems
// inconsistent, but seems to be applied by both the conformance test
// and Chrome. So we turn it off by default, support it as an option,
// and enable it in profiles where it seems commonplace.
{lengthA, ".b", "b", ""},
{lengthA, "\u3002b", "b", ""},
{lengthA, "..b", "b", ""},
{lengthA, "b..", "b..", ""},
{resolve, "a..b", "a..b", ""},
{resolve, ".b", "b", ""},
{resolve, "\u3002b", "b", ""},
{resolve, "..b", "b", ""},
{resolve, "b..", "b..", ""},
// Raw punycode
{punyA, "", "", ""},
{punyA, "*.foo.com", "*.foo.com", ""},
{punyA, "Foo.com", "Foo.com", ""},
// STD3 rules
{display, "*.foo.com", "*.foo.com", "P1"},
{std3, "*.foo.com", "*.foo.com", ""},
// Don't map U+2490 (DIGIT NINE FULL STOP). This is the behavior of
// Chrome, Safari, and IE. Firefox will first map ⒐ to 9. and return
// lab9.be.
{resolve, "lab⒐be", "xn--labbe-zh9b", "P1"}, // encode("lab⒐be")
{display, "lab⒐be", "lab⒐be", "P1"},
{resolve, "plan⒐faß.de", "xn--planfass-c31e.de", "P1"}, // encode("plan⒐fass") + ".de"
{display, "Plan⒐faß.de", "plan⒐faß.de", "P1"},
// Chrome 54.0 recognizes the error and treats this input verbatim as a
// search string.
// Safari 10.0 (non-conform spec) decomposes "⒈" and computes the
// punycode on the result using transitional mapping.
// Firefox 49.0.1 goes haywire on this string and prints a bunch of what
// seems to be nested punycode encodings.
{resolve, "日本⒈co.ßßß.de", "xn--co-wuw5954azlb.ssssss.de", "P1"},
{display, "日本⒈co.ßßß.de", "日本⒈co.ßßß.de", "P1"},
{resolve, "a\u200Cb", "ab", ""},
{display, "a\u200Cb", "a\u200Cb", "C"},
{resolve, encode("a\u200Cb"), encode("a\u200Cb"), "C"},
{display, "a\u200Cb", "a\u200Cb", "C"},
{resolve, "grﻋﺮﺑﻲ.de", "xn--gr-gtd9a1b0g.de", "B"},
{
// Notice how the string gets transformed, even with an error.
// Chrome will use the original string if it finds an error, so not
// the transformed one.
display,
"gr\ufecb\ufeae\ufe91\ufef2.de",
"gr\u0639\u0631\u0628\u064a.de",
"B",
},
{resolve, "\u0671.\u03c3\u07dc", "xn--qib.xn--4xa21s", "B"}, // ٱ.σߜ
{display, "\u0671.\u03c3\u07dc", "\u0671.\u03c3\u07dc", "B"},
// normalize input
{resolve, "a\u0323\u0322", "xn--jta191l", ""}, // ạ̢
{display, "a\u0323\u0322", "\u1ea1\u0322", ""},
// Non-normalized strings are not normalized when they originate from
// punycode. Despite the error, Chrome, Safari and Firefox will attempt
// to look up the input punycode.
{resolve, encode("a\u0323\u0322") + ".com", "xn--a-tdbc.com", "V1"},
{display, encode("a\u0323\u0322") + ".com", "a\u0323\u0322.com", "V1"},
}
for _, tc := range testCases {
doTest(t, tc.f, tc.name, tc.input, tc.want, tc.wantErr)
}
}
-130
View File
@@ -101,136 +101,6 @@ func doTest(t *testing.T, f func(string) (string, error), name, input, want, err
})
}
// TestLabelErrors tests strings returned in case of error. All results should
// be identical to the reference implementation and can be verified at
// http://unicode.org/cldr/utility/idna.jsp. The reference implementation,
// however, seems to not display Bidi and ContextJ errors.
//
// In some cases the behavior of browsers is added as a comment. In all cases,
// whenever a resolve search returns an error here, Chrome will treat the input
// string as a search string (including those for Bidi and Context J errors),
// unless noted otherwise.
func TestLabelErrors(t *testing.T) {
encode := func(s string) string { s, _ = encode(acePrefix, s); return s }
type kind struct {
name string
f func(string) (string, error)
}
punyA := kind{"PunycodeA", punycode.ToASCII}
resolve := kind{"ResolveA", Lookup.ToASCII}
display := kind{"ToUnicode", Display.ToUnicode}
p := New(VerifyDNSLength(true), MapForLookup(), BidiRule())
lengthU := kind{"CheckLengthU", p.ToUnicode}
lengthA := kind{"CheckLengthA", p.ToASCII}
p = New(MapForLookup(), StrictDomainName(false))
std3 := kind{"STD3", p.ToASCII}
testCases := []struct {
kind
input string
want string
wantErr string
}{
{lengthU, "", "", "A4"}, // From UTS 46 conformance test.
{lengthA, "", "", "A4"},
{lengthU, "xn--", "", "A4"},
{lengthU, "foo.xn--", "foo.", "A4"}, // TODO: is dropping xn-- correct?
{lengthU, "xn--.foo", ".foo", "A4"},
{lengthU, "foo.xn--.bar", "foo..bar", "A4"},
{display, "xn--", "", ""},
{display, "foo.xn--", "foo.", ""}, // TODO: is dropping xn-- correct?
{display, "xn--.foo", ".foo", ""},
{display, "foo.xn--.bar", "foo..bar", ""},
{lengthA, "a..b", "a..b", "A4"},
{punyA, ".b", ".b", ""},
// For backwards compatibility, the Punycode profile does not map runes.
{punyA, "\u3002b", "xn--b-83t", ""},
{punyA, "..b", "..b", ""},
{lengthA, ".b", ".b", "A4"},
{lengthA, "\u3002b", ".b", "A4"},
{lengthA, "..b", "..b", "A4"},
{lengthA, "b..", "b..", ""},
// Sharpened Bidi rules for Unicode 10.0.0. Apply for ALL labels in ANY
// of the labels is RTL.
{lengthA, "\ufe05\u3002\u3002\U0002603e\u1ce0", "..xn--t6f5138v", "A4"},
{lengthA, "FAX\u2a77\U0001d186\u3002\U0001e942\U000e0181\u180c", "", "B6"},
{resolve, "a..b", "a..b", ""},
// Note that leading dots are not stripped. This is to be consistent
// with the Punycode profile as well as the conformance test.
{resolve, ".b", ".b", ""},
{resolve, "\u3002b", ".b", ""},
{resolve, "..b", "..b", ""},
{resolve, "b..", "b..", ""},
// Raw punycode
{punyA, "", "", ""},
{punyA, "*.foo.com", "*.foo.com", ""},
{punyA, "Foo.com", "Foo.com", ""},
// STD3 rules
{display, "*.foo.com", "*.foo.com", "P1"},
{std3, "*.foo.com", "*.foo.com", ""},
// Don't map U+2490 (DIGIT NINE FULL STOP). This is the behavior of
// Chrome, Safari, and IE. Firefox will first map ⒐ to 9. and return
// lab9.be.
{resolve, "lab⒐be", "xn--labbe-zh9b", "P1"}, // encode("lab⒐be")
{display, "lab⒐be", "lab⒐be", "P1"},
{resolve, "plan⒐faß.de", "xn--planfass-c31e.de", "P1"}, // encode("plan⒐fass") + ".de"
{display, "Plan⒐faß.de", "plan⒐faß.de", "P1"},
// Chrome 54.0 recognizes the error and treats this input verbatim as a
// search string.
// Safari 10.0 (non-conform spec) decomposes "⒈" and computes the
// punycode on the result using transitional mapping.
// Firefox 49.0.1 goes haywire on this string and prints a bunch of what
// seems to be nested punycode encodings.
{resolve, "日本⒈co.ßßß.de", "xn--co-wuw5954azlb.ssssss.de", "P1"},
{display, "日本⒈co.ßßß.de", "日本⒈co.ßßß.de", "P1"},
{resolve, "a\u200Cb", "ab", ""},
{display, "a\u200Cb", "a\u200Cb", "C"},
{resolve, encode("a\u200Cb"), encode("a\u200Cb"), "C"},
{display, "a\u200Cb", "a\u200Cb", "C"},
{resolve, "grﻋﺮﺑﻲ.de", "xn--gr-gtd9a1b0g.de", "B"},
{
// Notice how the string gets transformed, even with an error.
// Chrome will use the original string if it finds an error, so not
// the transformed one.
display,
"gr\ufecb\ufeae\ufe91\ufef2.de",
"gr\u0639\u0631\u0628\u064a.de",
"B",
},
{resolve, "\u0671.\u03c3\u07dc", "xn--qib.xn--4xa21s", "B"}, // ٱ.σߜ
{display, "\u0671.\u03c3\u07dc", "\u0671.\u03c3\u07dc", "B"},
// normalize input
{resolve, "a\u0323\u0322", "xn--jta191l", ""}, // ạ̢
{display, "a\u0323\u0322", "\u1ea1\u0322", ""},
// Non-normalized strings are not normalized when they originate from
// punycode. Despite the error, Chrome, Safari and Firefox will attempt
// to look up the input punycode.
{resolve, encode("a\u0323\u0322") + ".com", "xn--a-tdbc.com", "V1"},
{display, encode("a\u0323\u0322") + ".com", "a\u0323\u0322.com", "V1"},
}
for _, tc := range testCases {
doTest(t, tc.f, tc.name, tc.input, tc.want, tc.wantErr)
}
}
func TestConformance(t *testing.T) {
testtext.SkipIfNotLong(t)
@@ -1,5 +1,7 @@
// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT.
// +build go1.10
package idna
// UnicodeVersion is the Unicode version from which the tables in this package are derived.
File diff suppressed because it is too large Load Diff
+357
View File
@@ -0,0 +1,357 @@
// Copyright 2017 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 format
import (
"reflect"
"unicode/utf8"
)
// A Parser parses a format string. The result from the parse are set in the
// struct fields.
type Parser struct {
Verb rune
WidthPresent bool
PrecPresent bool
Minus bool
Plus bool
Sharp bool
Space bool
Zero bool
// For the formats %+v %#v, we set the plusV/sharpV flags
// and clear the plus/sharp flags since %+v and %#v are in effect
// different, flagless formats set at the top level.
PlusV bool
SharpV bool
HasIndex bool
Width int
Prec int // precision
// retain arguments across calls.
Args []interface{}
// retain current argument number across calls
ArgNum int
// reordered records whether the format string used argument reordering.
Reordered bool
// goodArgNum records whether the most recent reordering directive was valid.
goodArgNum bool
// position info
format string
startPos int
endPos int
Status Status
}
// Reset initializes a parser to scan format strings for the given args.
func (p *Parser) Reset(args []interface{}) {
p.Args = args
p.ArgNum = 0
p.startPos = 0
p.Reordered = false
}
// Text returns the part of the format string that was parsed by the last call
// to Scan. It returns the original substitution clause if the current scan
// parsed a substitution.
func (p *Parser) Text() string { return p.format[p.startPos:p.endPos] }
// SetFormat sets a new format string to parse. It does not reset the argument
// count.
func (p *Parser) SetFormat(format string) {
p.format = format
p.startPos = 0
p.endPos = 0
}
// Status indicates the result type of a call to Scan.
type Status int
const (
StatusText Status = iota
StatusSubstitution
StatusBadWidthSubstitution
StatusBadPrecSubstitution
StatusNoVerb
StatusBadArgNum
StatusMissingArg
)
// ClearFlags reset the parser to default behavior.
func (p *Parser) ClearFlags() {
p.WidthPresent = false
p.PrecPresent = false
p.Minus = false
p.Plus = false
p.Sharp = false
p.Space = false
p.Zero = false
p.PlusV = false
p.SharpV = false
p.HasIndex = false
}
// Scan scans the next part of the format string and sets the status to
// indicate whether it scanned a string literal, substitution or error.
func (p *Parser) Scan() bool {
p.Status = StatusText
format := p.format
end := len(format)
if p.endPos >= end {
return false
}
afterIndex := false // previous item in format was an index like [3].
p.startPos = p.endPos
p.goodArgNum = true
i := p.startPos
for i < end && format[i] != '%' {
i++
}
if i > p.startPos {
p.endPos = i
return true
}
// Process one verb
i++
p.Status = StatusSubstitution
// Do we have flags?
p.ClearFlags()
simpleFormat:
for ; i < end; i++ {
c := p.format[i]
switch c {
case '#':
p.Sharp = true
case '0':
p.Zero = !p.Minus // Only allow zero padding to the left.
case '+':
p.Plus = true
case '-':
p.Minus = true
p.Zero = false // Do not pad with zeros to the right.
case ' ':
p.Space = true
default:
// Fast path for common case of ascii lower case simple verbs
// without precision or width or argument indices.
if 'a' <= c && c <= 'z' && p.ArgNum < len(p.Args) {
if c == 'v' {
// Go syntax
p.SharpV = p.Sharp
p.Sharp = false
// Struct-field syntax
p.PlusV = p.Plus
p.Plus = false
}
p.Verb = rune(c)
p.ArgNum++
p.endPos = i + 1
return true
}
// Format is more complex than simple flags and a verb or is malformed.
break simpleFormat
}
}
// Do we have an explicit argument index?
i, afterIndex = p.updateArgNumber(format, i)
// Do we have width?
if i < end && format[i] == '*' {
i++
p.Width, p.WidthPresent = p.intFromArg()
if !p.WidthPresent {
p.Status = StatusBadWidthSubstitution
}
// We have a negative width, so take its value and ensure
// that the minus flag is set
if p.Width < 0 {
p.Width = -p.Width
p.Minus = true
p.Zero = false // Do not pad with zeros to the right.
}
afterIndex = false
} else {
p.Width, p.WidthPresent, i = parsenum(format, i, end)
if afterIndex && p.WidthPresent { // "%[3]2d"
p.goodArgNum = false
}
}
// Do we have precision?
if i+1 < end && format[i] == '.' {
i++
if afterIndex { // "%[3].2d"
p.goodArgNum = false
}
i, afterIndex = p.updateArgNumber(format, i)
if i < end && format[i] == '*' {
i++
p.Prec, p.PrecPresent = p.intFromArg()
// Negative precision arguments don't make sense
if p.Prec < 0 {
p.Prec = 0
p.PrecPresent = false
}
if !p.PrecPresent {
p.Status = StatusBadPrecSubstitution
}
afterIndex = false
} else {
p.Prec, p.PrecPresent, i = parsenum(format, i, end)
if !p.PrecPresent {
p.Prec = 0
p.PrecPresent = true
}
}
}
if !afterIndex {
i, afterIndex = p.updateArgNumber(format, i)
}
p.HasIndex = afterIndex
if i >= end {
p.endPos = i
p.Status = StatusNoVerb
return true
}
verb, w := utf8.DecodeRuneInString(format[i:])
p.endPos = i + w
p.Verb = verb
switch {
case verb == '%': // Percent does not absorb operands and ignores f.wid and f.prec.
p.startPos = p.endPos - 1
p.Status = StatusText
case !p.goodArgNum:
p.Status = StatusBadArgNum
case p.ArgNum >= len(p.Args): // No argument left over to print for the current verb.
p.Status = StatusMissingArg
case verb == 'v':
// Go syntax
p.SharpV = p.Sharp
p.Sharp = false
// Struct-field syntax
p.PlusV = p.Plus
p.Plus = false
fallthrough
default:
p.ArgNum++
}
return true
}
// intFromArg gets the ArgNumth element of Args. On return, isInt reports
// whether the argument has integer type.
func (p *Parser) intFromArg() (num int, isInt bool) {
if p.ArgNum < len(p.Args) {
arg := p.Args[p.ArgNum]
num, isInt = arg.(int) // Almost always OK.
if !isInt {
// Work harder.
switch v := reflect.ValueOf(arg); v.Kind() {
case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64:
n := v.Int()
if int64(int(n)) == n {
num = int(n)
isInt = true
}
case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr:
n := v.Uint()
if int64(n) >= 0 && uint64(int(n)) == n {
num = int(n)
isInt = true
}
default:
// Already 0, false.
}
}
p.ArgNum++
if tooLarge(num) {
num = 0
isInt = false
}
}
return
}
// parseArgNumber returns the value of the bracketed number, minus 1
// (explicit argument numbers are one-indexed but we want zero-indexed).
// The opening bracket is known to be present at format[0].
// The returned values are the index, the number of bytes to consume
// up to the closing paren, if present, and whether the number parsed
// ok. The bytes to consume will be 1 if no closing paren is present.
func parseArgNumber(format string) (index int, wid int, ok bool) {
// There must be at least 3 bytes: [n].
if len(format) < 3 {
return 0, 1, false
}
// Find closing bracket.
for i := 1; i < len(format); i++ {
if format[i] == ']' {
width, ok, newi := parsenum(format, 1, i)
if !ok || newi != i {
return 0, i + 1, false
}
return width - 1, i + 1, true // arg numbers are one-indexed and skip paren.
}
}
return 0, 1, false
}
// updateArgNumber returns the next argument to evaluate, which is either the value of the passed-in
// argNum or the value of the bracketed integer that begins format[i:]. It also returns
// the new value of i, that is, the index of the next byte of the format to process.
func (p *Parser) updateArgNumber(format string, i int) (newi int, found bool) {
if len(format) <= i || format[i] != '[' {
return i, false
}
p.Reordered = true
index, wid, ok := parseArgNumber(format[i:])
if ok && 0 <= index && index < len(p.Args) {
p.ArgNum = index
return i + wid, true
}
p.goodArgNum = false
return i + wid, ok
}
// tooLarge reports whether the magnitude of the integer is
// too large to be used as a formatting width or precision.
func tooLarge(x int) bool {
const max int = 1e6
return x > max || x < -max
}
// parsenum converts ASCII to integer. num is 0 (and isnum is false) if no number present.
func parsenum(s string, start, end int) (num int, isnum bool, newi int) {
if start >= end {
return 0, false, end
}
for newi = start; newi < end && '0' <= s[newi] && s[newi] <= '9'; newi++ {
if tooLarge(num) {
return 0, false, end // Overflow; crazy long number most likely.
}
num = num*10 + int(s[newi]-'0')
isnum = true
}
return
}
+32
View File
@@ -0,0 +1,32 @@
// Copyright 2017 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 format
import "testing"
// TODO: most of Parser is tested in x/message. Move some tests here.
func TestParsenum(t *testing.T) {
testCases := []struct {
s string
start, end int
num int
isnum bool
newi int
}{
{"a123", 0, 4, 0, false, 0},
{"1234", 1, 1, 0, false, 1},
{"123a", 0, 4, 123, true, 3},
{"12a3", 0, 4, 12, true, 2},
{"1234", 0, 4, 1234, true, 4},
{"1a234", 1, 3, 0, false, 1},
}
for _, tt := range testCases {
num, isnum, newi := parsenum(tt.s, tt.start, tt.end)
if num != tt.num || isnum != tt.isnum || newi != tt.newi {
t.Errorf("parsenum(%q, %d, %d) = %d, %v, %d, want %d, %v, %d", tt.s, tt.start, tt.end, num, isnum, newi, tt.num, tt.isnum, tt.newi)
}
}
}
+21 -3
View File
@@ -55,18 +55,36 @@ func (w *CodeWriter) WriteGoFile(filename, pkg string) {
log.Fatalf("Could not create file %s: %v", filename, err)
}
defer f.Close()
if _, err = w.WriteGo(f, pkg); err != nil {
if _, err = w.WriteGo(f, pkg, ""); err != nil {
log.Fatalf("Error writing file %s: %v", filename, err)
}
}
// WriteVersionedGoFile appends the buffer with the total size of all created
// structures and writes it as a Go file to the the given file with the given
// package name and build tags for the current Unicode version,
func (w *CodeWriter) WriteVersionedGoFile(filename, pkg string) {
tags := buildTags()
if tags != "" {
filename = insertVersion(filename, UnicodeVersion())
}
f, err := os.Create(filename)
if err != nil {
log.Fatalf("Could not create file %s: %v", filename, err)
}
defer f.Close()
if _, err = w.WriteGo(f, pkg, tags); err != nil {
log.Fatalf("Error writing file %s: %v", filename, err)
}
}
// WriteGo appends the buffer with the total size of all created structures and
// writes it as a Go file to the the given writer with the given package name.
func (w *CodeWriter) WriteGo(out io.Writer, pkg string) (n int, err error) {
func (w *CodeWriter) WriteGo(out io.Writer, pkg, tags string) (n int, err error) {
sz := w.Size
w.WriteComment("Total table size %d bytes (%dKiB); checksum: %X\n", sz, sz/1024, w.Hash.Sum32())
defer w.buf.Reset()
return WriteGo(out, pkg, w.buf.Bytes())
return WriteGo(out, pkg, tags, w.buf.Bytes())
}
func (w *CodeWriter) printf(f string, x ...interface{}) {
+58 -6
View File
@@ -31,6 +31,7 @@ import (
"os"
"path"
"path/filepath"
"strings"
"sync"
"unicode"
@@ -69,8 +70,6 @@ func Init() {
const header = `// Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT.
package %s
`
// UnicodeVersion reports the requested Unicode version.
@@ -78,11 +77,33 @@ func UnicodeVersion() string {
return *unicodeVersion
}
// UnicodeVersion reports the requested CLDR version.
// CLDRVersion reports the requested CLDR version.
func CLDRVersion() string {
return *cldrVersion
}
var tags = []struct{ version, buildTags string }{
{"10.0.0", "go1.10"},
{"", "!go1.10"},
}
// buildTags reports the build tags used for the current Unicode version.
func buildTags() string {
v := UnicodeVersion()
for _, x := range tags {
// We should do a numeric comparison, but including the collate package
// would create an import cycle. We approximate it by assuming that
// longer version strings are later.
if len(x.version) <= len(v) {
return x.buildTags
}
if len(x.version) == len(v) && x.version <= v {
return x.buildTags
}
}
return tags[0].buildTags
}
// IsLocal reports whether data files are available locally.
func IsLocal() bool {
dir, err := localReadmeFile()
@@ -243,15 +264,46 @@ func WriteGoFile(filename, pkg string, b []byte) {
log.Fatalf("Could not create file %s: %v", filename, err)
}
defer w.Close()
if _, err = WriteGo(w, pkg, b); err != nil {
if _, err = WriteGo(w, pkg, "", b); err != nil {
log.Fatalf("Error writing file %s: %v", filename, err)
}
}
func insertVersion(filename, version string) string {
suffix := ".go"
if strings.HasSuffix(filename, "_test.go") {
suffix = "_test.go"
}
return fmt.Sprint(filename[:len(filename)-len(suffix)], version, suffix)
}
// WriteVersionedGoFile prepends a standard file comment, adds build tags to
// version the file for the current Unicode version, and package statement to
// the given bytes, applies gofmt, and writes them to a file with the given
// name. It will call log.Fatal if there are any errors.
func WriteVersionedGoFile(filename, pkg string, b []byte) {
tags := buildTags()
if tags != "" {
filename = insertVersion(filename, UnicodeVersion())
}
w, err := os.Create(filename)
if err != nil {
log.Fatalf("Could not create file %s: %v", filename, err)
}
defer w.Close()
if _, err = WriteGo(w, pkg, tags, b); err != nil {
log.Fatalf("Error writing file %s: %v", filename, err)
}
}
// WriteGo prepends a standard file comment and package statement to the given
// bytes, applies gofmt, and writes them to w.
func WriteGo(w io.Writer, pkg string, b []byte) (n int, err error) {
src := []byte(fmt.Sprintf(header, pkg))
func WriteGo(w io.Writer, pkg, tags string, b []byte) (n int, err error) {
src := []byte(header)
if tags != "" {
src = append(src, fmt.Sprintf("// +build %s\n\n", tags)...)
}
src = append(src, fmt.Sprintf("package %s\n\n", pkg)...)
src = append(src, b...)
formatted, err := format.Source(src)
if err != nil {
+12 -1
View File
@@ -33,8 +33,19 @@ const (
NumSymbolTypes
)
const hasNonLatnMask = 0x8000
// symOffset is an offset into altSymData if the bit indicated by hasNonLatnMask
// is not 0 (with this bit masked out), and an offset into symIndex otherwise.
//
// TODO: this type can be a byte again if we use an indirection into altsymData
// and introduce an alt -> offset slice (the length of this will be number of
// alternatives plus 1). This also allows getting rid of the compactTag field
// in altSymData. In total this will save about 1K.
type symOffset uint16
type altSymData struct {
compactTag uint16
symIndex symOffset
system system
symIndex byte
}
+29 -17
View File
@@ -406,23 +406,35 @@ func (d *Decimal) ConvertFloat(r RoundingContext, x float64, size int) {
// By default we get the exact decimal representation.
verb := byte('g')
prec := -1
// Determine rounding, if possible. As the strconv API does not return the
// rounding accuracy (exact/rounded up|down), we can only round using
// ToNearestEven.
// Something like this would work:
// AppendDigits(dst []byte, x float64, base, size, prec int) (digits []byte, exp, accuracy int)
//
// TODO: At this point strconv's rounding is imprecise to the point that it
// is not useable for this purpose.
// See https://github.com/golang/go/issues/21714
// if r.Mode == ToNearestEven {
// if n := r.RoundSignificantDigits(); n >= 0 {
// prec = n
// } else if n = r.RoundFractionDigits(); n >= 0 {
// prec = n
// verb = 'f'
// }
// }
// As the strconv API does not return the rounding accuracy, we can only
// round using ToNearestEven.
if r.Mode == ToNearestEven {
if n := r.RoundSignificantDigits(); n >= 0 {
prec = n
} else if n = r.RoundFractionDigits(); n >= 0 {
prec = n
verb = 'f'
}
} else {
// TODO: At this point strconv's rounding is imprecise to the point that
// it is not useable for this purpose.
// See https://github.com/golang/go/issues/21714
// If rounding is requested, we ask for a large number of digits and
// round from there to simulate rounding only once.
// Ideally we would have strconv export an AppendDigits that would take
// a rounding mode and/or return an accuracy. Something like this would
// work:
// AppendDigits(dst []byte, x float64, base, size, prec int) (digits []byte, exp, accuracy int)
hasPrec := r.RoundSignificantDigits() >= 0
hasScale := r.RoundFractionDigits() >= 0
if hasPrec || hasScale {
// prec is the number of mantissa bits plus some extra for safety.
// We need at least the number of mantissa bits as decimals to
// accurately represent the floating point without rounding, as each
// bit requires one more decimal to represent: 0.5, 0.25, 0.125, ...
prec = 60
}
}
b := strconv.AppendFloat(d.Digits[:0], abs, verb, prec, size)
i := 0
+28 -11
View File
@@ -256,12 +256,10 @@ func TestConvert(t *testing.T) {
rc RoundingContext
out string
}{
// TODO: uncommented tests can be restored when convert does its own
// rounding.
// {-0.001, scale2, "-0.00"}, // not normalized
// {0.1234, prec3, "0.123"},
// {1234.0, prec3, "1230"},
// {1.2345e10, prec3, "12300000000"},
{-0.001, scale2, "-0.00"},
{0.1234, prec3, "0.123"},
{1234.0, prec3, "1230"},
{1.2345e10, prec3, "12300000000"},
{int8(-34), scale2, "-34"},
{int16(-234), scale2, "-234"},
@@ -273,18 +271,37 @@ func TestConvert(t *testing.T) {
{uint32(234), scale2, "234"},
{uint64(234), scale2, "234"},
{uint(234), scale2, "234"},
{-1e9, scale2, "-1000000000"},
{0.234, scale2away, "0.234"}, // rounding postponed as not ToNearestEven
{-1e9, scale2, "-1000000000.00"},
// The following two causes this result to have a lot of digits:
// 1) 0.234 cannot be accurately represented as a float64, and
// 2) as strconv does not support the rounding AwayFromZero, Convert
// leaves the rounding to caller.
{0.234, scale2away,
"0.2340000000000000135447209004269097931683063507080078125"},
{0.0249, inc0_05, "0.00"},
{0.025, inc0_05, "0.00"},
{0.0251, inc0_05, "0.05"},
{0.03, inc0_05, "0.05"},
{0.025, inc0_05, "0"},
{0.075, inc0_05, "0.1"},
{0.049, inc0_05, "0.05"},
{0.05, inc0_05, "0.05"},
{0.051, inc0_05, "0.05"},
{0.0749, inc0_05, "0.05"},
{0.075, inc0_05, "0.10"},
{0.0751, inc0_05, "0.10"},
{324, inc50, "300"},
{325, inc50, "300"},
{326, inc50, "350"},
{349, inc50, "350"},
{350, inc50, "350"},
{351, inc50, "350"},
{374, inc50, "350"},
{375, inc50, "400"},
{376, inc50, "400"},
// Here the scale is 2, but the digits get shifted left. As we use
// AppendFloat to do the rounding an exta 0 gets added.
{0.123, roundShift, "0.123"},
{0.123, roundShift, "0.1230"},
{converter(3), scale2, "100"},
Generated Vendored Executable → Regular
View File
Generated Vendored Executable → Regular
View File
+6 -6
View File
@@ -255,10 +255,10 @@ func genSymbols(w *gen.CodeWriter, data *cldr.CLDR) {
// resolveSymbolIndex gets the index from the closest matching locale,
// including the locale itself.
resolveSymbolIndex := func(langIndex int, ns system) byte {
resolveSymbolIndex := func(langIndex int, ns system) symOffset {
for {
if sym := symbolMap[key{langIndex, ns}]; sym != nil {
return byte(m[*sym])
return symOffset(m[*sym])
}
if langIndex == 0 {
return 0 // und, latn
@@ -270,7 +270,7 @@ func genSymbols(w *gen.CodeWriter, data *cldr.CLDR) {
// Create an index with the symbols for each locale for the latn numbering
// system. If this is not the default, or the only one, for a locale, we
// will overwrite the value later.
var langToDefaults [language.NumCompactTags]byte
var langToDefaults [language.NumCompactTags]symOffset
for _, l := range data.Locales() {
langIndex, _ := language.CompactIndex(language.MustParse(l))
langToDefaults[langIndex] = resolveSymbolIndex(langIndex, 0)
@@ -300,8 +300,8 @@ func genSymbols(w *gen.CodeWriter, data *cldr.CLDR) {
for _, l := range data.Locales() {
langIndex, _ := language.CompactIndex(language.MustParse(l))
start := len(langToAlt)
if start > 0x7F {
log.Fatal("Number of alternative assignments > 0x7F")
if start >= hasNonLatnMask {
log.Fatalf("Number of alternative assignments >= %x", hasNonLatnMask)
}
// Create the entry for the default value.
def := defaults[langIndex]
@@ -328,7 +328,7 @@ func genSymbols(w *gen.CodeWriter, data *cldr.CLDR) {
langToAlt = langToAlt[:start]
} else {
// Overwrite the entry in langToDefaults.
langToDefaults[langIndex] = 0x80 | byte(start)
langToDefaults[langIndex] = hasNonLatnMask | symOffset(start)
}
}
w.WriteComment(`
+12 -1
View File
@@ -37,8 +37,19 @@ const (
NumSymbolTypes
)
const hasNonLatnMask = 0x8000
// symOffset is an offset into altSymData if the bit indicated by hasNonLatnMask
// is not 0 (with this bit masked out), and an offset into symIndex otherwise.
//
// TODO: this type can be a byte again if we use an indirection into altsymData
// and introduce an alt -> offset slice (the length of this will be number of
// alternatives plus 1). This also allows getting rid of the compactTag field
// in altSymData. In total this will save about 1K.
type symOffset uint16
type altSymData struct {
compactTag uint16
symIndex symOffset
system system
symIndex byte
}
+30 -28
View File
@@ -17,7 +17,7 @@ import (
// Info holds number formatting configuration data.
type Info struct {
system systemData // numbering system information
symIndex byte // index to symbols
symIndex symOffset // index to symbols
}
// InfoFromLangID returns a Info for the given compact language identifier and
@@ -26,16 +26,16 @@ type Info struct {
func InfoFromLangID(compactIndex int, numberSystem string) Info {
p := langToDefaults[compactIndex]
// Lookup the entry for the language.
pSymIndex := byte(0) // Default: Latin, default symbols
pSymIndex := symOffset(0) // Default: Latin, default symbols
system, ok := systemMap[numberSystem]
if !ok {
// Take the value for the default numbering system. This is by far the
// most common case as an alternative numbering system is hardly used.
if p&0x80 == 0 {
if p&hasNonLatnMask == 0 { // Latn digits.
pSymIndex = p
} else {
} else { // Non-Latn or multiple numbering systems.
// Take the first entry from the alternatives list.
data := langToAlt[p&^0x80]
data := langToAlt[p&^hasNonLatnMask]
pSymIndex = data.symIndex
system = data.system
}
@@ -43,8 +43,8 @@ func InfoFromLangID(compactIndex int, numberSystem string) Info {
langIndex := compactIndex
ns := system
outerLoop:
for {
if p&0x80 == 0 {
for ; ; p = langToDefaults[langIndex] {
if p&hasNonLatnMask == 0 {
if ns == 0 {
// The index directly points to the symbol data.
pSymIndex = p
@@ -52,30 +52,32 @@ func InfoFromLangID(compactIndex int, numberSystem string) Info {
}
// Move to the parent and retry.
langIndex = int(internal.Parent[langIndex])
}
// The index points to a list of symbol data indexes.
for _, e := range langToAlt[p&^0x80:] {
if int(e.compactTag) != langIndex {
if langIndex == 0 {
// The CLDR root defines full symbol information for all
// numbering systems (even though mostly by means of
// aliases). This means that we will never fall back to
// the default of the language. Also, the loop is
// guaranteed to terminate as a consequence.
ns = numLatn
// Fall back to Latin and start from the original
// language. See
// http://unicode.org/reports/tr35/#Locale_Inheritance.
langIndex = compactIndex
} else {
} else {
// The index points to a list of symbol data indexes.
for _, e := range langToAlt[p&^hasNonLatnMask:] {
if int(e.compactTag) != langIndex {
if langIndex == 0 {
// The CLDR root defines full symbol information for
// all numbering systems (even though mostly by
// means of aliases). Fall back to the default entry
// for Latn if there is no data for the numbering
// system of this language.
if ns == 0 {
break
}
// Fall back to Latin and start from the original
// language. See
// http://unicode.org/reports/tr35/#Locale_Inheritance.
ns = numLatn
langIndex = compactIndex
continue outerLoop
}
// Fall back to parent.
langIndex = int(internal.Parent[langIndex])
} else if e.system == ns {
pSymIndex = e.symIndex
break outerLoop
}
break
}
if e.system == ns {
pSymIndex = e.symIndex
break outerLoop
}
}
}
+4
View File
@@ -31,6 +31,10 @@ func TestInfo(t *testing.T) {
{"de-CH-oxendict", SymGroup, "’", '9'}, // inherits from de-CH (no compact index)
{"de-CH-u-nu-deva", SymGroup, "’", '\u096f'}, // miss -> latn -> de-CH
{"bn-u-nu-beng", SymGroup, ",", '\u09ef'},
{"bn-u-nu-deva", SymGroup, ",", '\u096f'},
{"bn-u-nu-latn", SymGroup, ",", '9'},
{"pa", SymExponential, "E", '9'},
// "×۱۰^" -> U+00d7 U+06f1 U+06f0^"
+532 -475
View File
File diff suppressed because it is too large Load Diff
+86 -85
View File
@@ -4,9 +4,9 @@ package internal
// Parent maps a compact index of a tag to the compact index of the parent of
// this tag.
var Parent = []uint16{ // 754 elements
var Parent = []uint16{ // 768 elements
// Entry 0 - 3F
0x0000, 0x0053, 0x00e5, 0x0000, 0x0003, 0x0003, 0x0000, 0x0006,
0x0000, 0x0053, 0x00e8, 0x0000, 0x0003, 0x0003, 0x0000, 0x0006,
0x0000, 0x0008, 0x0000, 0x000a, 0x0000, 0x000c, 0x000c, 0x000c,
0x000c, 0x000c, 0x000c, 0x000c, 0x000c, 0x000c, 0x000c, 0x000c,
0x000c, 0x000c, 0x000c, 0x000c, 0x000c, 0x000c, 0x000c, 0x000c,
@@ -18,100 +18,101 @@ var Parent = []uint16{ // 754 elements
0x0000, 0x0040, 0x0000, 0x0042, 0x0042, 0x0000, 0x0045, 0x0045,
0x0000, 0x0048, 0x0000, 0x004a, 0x0000, 0x0000, 0x004d, 0x004c,
0x004c, 0x0000, 0x0051, 0x0051, 0x0051, 0x0051, 0x0000, 0x0056,
0x0000, 0x0058, 0x0000, 0x005a, 0x0000, 0x005c, 0x005c, 0x0000,
0x005f, 0x0000, 0x0061, 0x0000, 0x0063, 0x0000, 0x0065, 0x0065,
0x0000, 0x0068, 0x0000, 0x006a, 0x006a, 0x006a, 0x006a, 0x006a,
0x006a, 0x006a, 0x0000, 0x0072, 0x0000, 0x0074, 0x0000, 0x0076,
0x0000, 0x0000, 0x0079, 0x0000, 0x007b, 0x0000, 0x007d, 0x0000,
0x0056, 0x0000, 0x0059, 0x0000, 0x005b, 0x0000, 0x005d, 0x0000,
0x005f, 0x005f, 0x0000, 0x0062, 0x0000, 0x0064, 0x0000, 0x0066,
0x0000, 0x0068, 0x0068, 0x0000, 0x006b, 0x0000, 0x006d, 0x006d,
0x006d, 0x006d, 0x006d, 0x006d, 0x006d, 0x0000, 0x0075, 0x0000,
0x0077, 0x0000, 0x0079, 0x0000, 0x0000, 0x007c, 0x0000, 0x007e,
// Entry 80 - BF
0x007f, 0x007f, 0x0000, 0x0082, 0x0082, 0x0000, 0x0085, 0x0086,
0x0086, 0x0086, 0x0085, 0x0087, 0x0086, 0x0086, 0x0086, 0x0085,
0x0086, 0x0086, 0x0086, 0x0086, 0x0086, 0x0086, 0x0087, 0x0086,
0x0086, 0x0086, 0x0086, 0x0087, 0x0086, 0x0087, 0x0086, 0x0086,
0x0087, 0x0086, 0x0086, 0x0086, 0x0086, 0x0086, 0x0086, 0x0086,
0x0086, 0x0086, 0x0085, 0x0086, 0x0086, 0x0086, 0x0086, 0x0086,
0x0086, 0x0086, 0x0086, 0x0086, 0x0086, 0x0086, 0x0086, 0x0086,
0x0086, 0x0086, 0x0086, 0x0086, 0x0085, 0x0086, 0x0085, 0x0086,
0x0000, 0x0080, 0x0000, 0x0082, 0x0082, 0x0000, 0x0085, 0x0085,
0x0000, 0x0088, 0x0089, 0x0089, 0x0089, 0x0088, 0x008a, 0x0089,
0x0089, 0x0089, 0x0088, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089,
0x0089, 0x008a, 0x0089, 0x0089, 0x0089, 0x0089, 0x008a, 0x0089,
0x008a, 0x0089, 0x0089, 0x008a, 0x0089, 0x0089, 0x0089, 0x0089,
0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0088, 0x0089, 0x0089,
0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089,
0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0088,
// Entry C0 - FF
0x0086, 0x0086, 0x0086, 0x0086, 0x0086, 0x0086, 0x0086, 0x0087,
0x0086, 0x0086, 0x0086, 0x0086, 0x0086, 0x0086, 0x0086, 0x0085,
0x0086, 0x0086, 0x0086, 0x0086, 0x0086, 0x0087, 0x0086, 0x0086,
0x0087, 0x0086, 0x0086, 0x0086, 0x0086, 0x0086, 0x0086, 0x0086,
0x0086, 0x0086, 0x0086, 0x0086, 0x0085, 0x0085, 0x0086, 0x0086,
0x0085, 0x0086, 0x0086, 0x0086, 0x0086, 0x0086, 0x0000, 0x00ee,
0x0000, 0x00f0, 0x00f1, 0x00f1, 0x00f1, 0x00f1, 0x00f1, 0x00f1,
0x00f1, 0x00f1, 0x00f1, 0x00f0, 0x00f1, 0x00f0, 0x00f0, 0x00f1,
0x0089, 0x0088, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089,
0x0089, 0x0089, 0x008a, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089,
0x0089, 0x0089, 0x0088, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089,
0x008a, 0x0089, 0x0089, 0x008a, 0x0089, 0x0089, 0x0089, 0x0089,
0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0089, 0x0088,
0x0088, 0x0089, 0x0089, 0x0088, 0x0089, 0x0089, 0x0089, 0x0089,
0x0089, 0x0000, 0x00f1, 0x0000, 0x00f3, 0x00f4, 0x00f4, 0x00f4,
0x00f4, 0x00f4, 0x00f4, 0x00f4, 0x00f4, 0x00f4, 0x00f3, 0x00f4,
// Entry 100 - 13F
0x00f1, 0x00f0, 0x00f1, 0x00f1, 0x00f1, 0x00f1, 0x00f0, 0x00f1,
0x00f1, 0x00f1, 0x00f1, 0x00f1, 0x00f1, 0x0000, 0x010d, 0x0000,
0x010f, 0x0000, 0x0111, 0x0000, 0x0113, 0x0113, 0x0000, 0x0116,
0x0116, 0x0116, 0x0116, 0x0000, 0x011b, 0x0000, 0x011d, 0x0000,
0x011f, 0x011f, 0x0000, 0x0122, 0x0122, 0x0122, 0x0122, 0x0122,
0x0122, 0x0122, 0x0122, 0x0122, 0x0122, 0x0122, 0x0122, 0x0122,
0x0122, 0x0122, 0x0122, 0x0122, 0x0122, 0x0122, 0x0122, 0x0122,
0x0122, 0x0122, 0x0122, 0x0122, 0x0122, 0x0122, 0x0122, 0x0122,
0x00f3, 0x00f3, 0x00f4, 0x00f4, 0x00f3, 0x00f4, 0x00f4, 0x00f4,
0x00f4, 0x00f3, 0x00f4, 0x00f4, 0x00f4, 0x00f4, 0x00f4, 0x00f4,
0x0000, 0x0110, 0x0000, 0x0112, 0x0000, 0x0114, 0x0000, 0x0116,
0x0116, 0x0000, 0x0119, 0x0119, 0x0119, 0x0119, 0x0000, 0x011e,
0x0000, 0x0120, 0x0000, 0x0122, 0x0122, 0x0000, 0x0125, 0x0125,
0x0125, 0x0125, 0x0125, 0x0125, 0x0125, 0x0125, 0x0125, 0x0125,
0x0125, 0x0125, 0x0125, 0x0125, 0x0125, 0x0125, 0x0125, 0x0125,
0x0125, 0x0125, 0x0125, 0x0125, 0x0125, 0x0125, 0x0125, 0x0125,
// Entry 140 - 17F
0x0122, 0x0122, 0x0122, 0x0122, 0x0122, 0x0122, 0x0122, 0x0122,
0x0122, 0x0122, 0x0122, 0x0122, 0x0122, 0x0122, 0x0122, 0x0122,
0x0122, 0x0000, 0x0151, 0x0000, 0x0153, 0x0000, 0x0155, 0x0000,
0x0157, 0x0000, 0x0159, 0x0000, 0x015b, 0x015b, 0x015b, 0x0000,
0x015f, 0x0000, 0x0000, 0x0162, 0x0000, 0x0164, 0x0000, 0x0166,
0x0166, 0x0166, 0x0000, 0x016a, 0x0000, 0x016c, 0x0000, 0x016e,
0x0000, 0x0170, 0x0170, 0x0000, 0x0173, 0x0000, 0x0175, 0x0000,
0x0177, 0x0000, 0x0179, 0x0000, 0x017b, 0x0000, 0x017d, 0x0000,
0x0125, 0x0125, 0x0125, 0x0125, 0x0125, 0x0125, 0x0125, 0x0125,
0x0125, 0x0125, 0x0125, 0x0125, 0x0125, 0x0125, 0x0125, 0x0125,
0x0125, 0x0125, 0x0125, 0x0125, 0x0000, 0x0154, 0x0000, 0x0156,
0x0000, 0x0158, 0x0000, 0x015a, 0x0000, 0x015c, 0x0000, 0x015e,
0x015e, 0x015e, 0x0000, 0x0162, 0x0000, 0x0000, 0x0165, 0x0000,
0x0167, 0x0000, 0x0169, 0x0169, 0x0169, 0x0000, 0x016d, 0x0000,
0x016f, 0x0000, 0x0171, 0x0000, 0x0173, 0x0173, 0x0000, 0x0176,
0x0000, 0x0178, 0x0000, 0x017a, 0x0000, 0x017c, 0x0000, 0x017e,
// Entry 180 - 1BF
0x017f, 0x0000, 0x0181, 0x0181, 0x0181, 0x0181, 0x0000, 0x0000,
0x0187, 0x0000, 0x0000, 0x018a, 0x0000, 0x018c, 0x0000, 0x0000,
0x018f, 0x0000, 0x0191, 0x0000, 0x0000, 0x0194, 0x0000, 0x0000,
0x0197, 0x0000, 0x0199, 0x0000, 0x019b, 0x0000, 0x019d, 0x0000,
0x0000, 0x0180, 0x0000, 0x0000, 0x0183, 0x0000, 0x0185, 0x0185,
0x0185, 0x0185, 0x0000, 0x0000, 0x018b, 0x0000, 0x0000, 0x018e,
0x0000, 0x0190, 0x0000, 0x0000, 0x0193, 0x0000, 0x0195, 0x0000,
0x0000, 0x0198, 0x0000, 0x0000, 0x019b, 0x0000, 0x019d, 0x0000,
0x019f, 0x0000, 0x01a1, 0x0000, 0x01a3, 0x0000, 0x01a5, 0x0000,
0x01a7, 0x0000, 0x01a9, 0x0000, 0x01ab, 0x01ab, 0x0000, 0x01ae,
0x0000, 0x01b0, 0x0000, 0x01b2, 0x0000, 0x01b4, 0x0000, 0x01b6,
0x0000, 0x0000, 0x01b9, 0x0000, 0x01bb, 0x0000, 0x01bd, 0x0000,
0x01a7, 0x0000, 0x01a9, 0x0000, 0x01ab, 0x0000, 0x01ad, 0x0000,
0x01af, 0x01af, 0x0000, 0x01b2, 0x0000, 0x01b4, 0x0000, 0x01b6,
0x0000, 0x01b8, 0x0000, 0x01ba, 0x0000, 0x0000, 0x01bd, 0x0000,
// Entry 1C0 - 1FF
0x01bf, 0x0000, 0x01c1, 0x0000, 0x01c3, 0x0000, 0x01c5, 0x01c5,
0x01c5, 0x01c5, 0x0000, 0x01ca, 0x0000, 0x01cc, 0x01cc, 0x0000,
0x01cf, 0x0000, 0x01d1, 0x0000, 0x01d3, 0x0000, 0x01d5, 0x0000,
0x01d7, 0x0000, 0x01d9, 0x01d9, 0x0000, 0x01dc, 0x0000, 0x01de,
0x01bf, 0x0000, 0x01c1, 0x0000, 0x01c3, 0x0000, 0x01c5, 0x0000,
0x01c7, 0x0000, 0x01c9, 0x01c9, 0x01c9, 0x01c9, 0x0000, 0x01ce,
0x0000, 0x01d0, 0x01d0, 0x0000, 0x01d3, 0x0000, 0x01d5, 0x0000,
0x01d7, 0x0000, 0x01d9, 0x0000, 0x01db, 0x0000, 0x01dd, 0x01dd,
0x0000, 0x01e0, 0x0000, 0x01e2, 0x0000, 0x01e4, 0x0000, 0x01e6,
0x0000, 0x01e8, 0x0000, 0x01ea, 0x0000, 0x01ec, 0x0000, 0x01ee,
0x01ee, 0x01ee, 0x0000, 0x01f2, 0x0000, 0x01f4, 0x0000, 0x01f6,
0x0000, 0x01f8, 0x0000, 0x0000, 0x01fb, 0x0000, 0x01fd, 0x01fd,
0x0000, 0x01f0, 0x0000, 0x01f2, 0x01f2, 0x01f2, 0x0000, 0x01f6,
0x0000, 0x01f8, 0x0000, 0x01fa, 0x0000, 0x01fc, 0x0000, 0x0000,
// Entry 200 - 23F
0x0000, 0x0200, 0x0000, 0x0202, 0x0202, 0x0000, 0x0205, 0x0205,
0x0000, 0x0208, 0x0208, 0x0208, 0x0208, 0x0208, 0x0208, 0x0208,
0x0000, 0x0210, 0x0000, 0x0212, 0x0000, 0x0214, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x021a, 0x0000, 0x0000, 0x021d, 0x0000,
0x021f, 0x021f, 0x0000, 0x0222, 0x0000, 0x0224, 0x0224, 0x0000,
0x0000, 0x0228, 0x0227, 0x0227, 0x0000, 0x0000, 0x022d, 0x0000,
0x022f, 0x0000, 0x0231, 0x0000, 0x023d, 0x0233, 0x023d, 0x023d,
0x023d, 0x023d, 0x023d, 0x023d, 0x023d, 0x0233, 0x023d, 0x023d,
0x01ff, 0x0000, 0x0201, 0x0201, 0x0000, 0x0204, 0x0000, 0x0206,
0x0206, 0x0000, 0x0209, 0x0209, 0x0000, 0x020c, 0x020c, 0x020c,
0x020c, 0x020c, 0x020c, 0x020c, 0x0000, 0x0214, 0x0000, 0x0216,
0x0000, 0x0218, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x021e,
0x0000, 0x0000, 0x0221, 0x0000, 0x0223, 0x0223, 0x0000, 0x0226,
0x0000, 0x0228, 0x0228, 0x0000, 0x0000, 0x022c, 0x022b, 0x022b,
0x0000, 0x0000, 0x0231, 0x0000, 0x0233, 0x0000, 0x0235, 0x0000,
0x0241, 0x0237, 0x0241, 0x0241, 0x0241, 0x0241, 0x0241, 0x0241,
// Entry 240 - 27F
0x0000, 0x0240, 0x0240, 0x0240, 0x0000, 0x0244, 0x0000, 0x0246,
0x0000, 0x0248, 0x0248, 0x0000, 0x024b, 0x0000, 0x024d, 0x024d,
0x024d, 0x024d, 0x024d, 0x024d, 0x0000, 0x0254, 0x0000, 0x0256,
0x0000, 0x0258, 0x0000, 0x025a, 0x0000, 0x025c, 0x0000, 0x0000,
0x025f, 0x025f, 0x025f, 0x0000, 0x0263, 0x0000, 0x0265, 0x0000,
0x0267, 0x0000, 0x0000, 0x026a, 0x0269, 0x0269, 0x0000, 0x026e,
0x0000, 0x0270, 0x0000, 0x0272, 0x0000, 0x0000, 0x0000, 0x0000,
0x0277, 0x0000, 0x0000, 0x027a, 0x0000, 0x027c, 0x027c, 0x027c,
0x0241, 0x0237, 0x0241, 0x0241, 0x0000, 0x0244, 0x0244, 0x0244,
0x0000, 0x0248, 0x0000, 0x024a, 0x0000, 0x024c, 0x024c, 0x0000,
0x024f, 0x0000, 0x0251, 0x0251, 0x0251, 0x0251, 0x0251, 0x0251,
0x0000, 0x0258, 0x0000, 0x025a, 0x0000, 0x025c, 0x0000, 0x025e,
0x0000, 0x0260, 0x0000, 0x0262, 0x0000, 0x0000, 0x0265, 0x0265,
0x0265, 0x0000, 0x0269, 0x0000, 0x026b, 0x0000, 0x026d, 0x0000,
0x0000, 0x0270, 0x026f, 0x026f, 0x0000, 0x0274, 0x0000, 0x0276,
0x0000, 0x0278, 0x0000, 0x0000, 0x0000, 0x0000, 0x027d, 0x0000,
// Entry 280 - 2BF
0x027c, 0x0000, 0x0281, 0x0281, 0x0281, 0x0000, 0x0285, 0x0285,
0x0285, 0x0285, 0x0285, 0x0000, 0x028b, 0x028b, 0x028b, 0x028b,
0x0000, 0x0000, 0x0000, 0x0000, 0x0293, 0x0293, 0x0293, 0x0000,
0x0297, 0x0297, 0x0297, 0x0297, 0x0000, 0x0000, 0x029d, 0x029d,
0x029d, 0x029d, 0x0000, 0x02a2, 0x0000, 0x02a4, 0x02a4, 0x0000,
0x02a7, 0x0000, 0x02a9, 0x02a9, 0x0000, 0x0000, 0x02ad, 0x0000,
0x0000, 0x02b0, 0x0000, 0x02b2, 0x02b2, 0x0000, 0x0000, 0x02b6,
0x0000, 0x02b8, 0x0000, 0x02ba, 0x0000, 0x02bc, 0x0000, 0x02be,
0x0000, 0x0280, 0x0000, 0x0282, 0x0282, 0x0282, 0x0282, 0x0000,
0x0287, 0x0287, 0x0287, 0x0000, 0x028b, 0x028b, 0x028b, 0x028b,
0x028b, 0x0000, 0x0291, 0x0291, 0x0291, 0x0291, 0x0000, 0x0000,
0x0000, 0x0000, 0x0299, 0x0299, 0x0299, 0x0000, 0x029d, 0x029d,
0x029d, 0x029d, 0x0000, 0x0000, 0x02a3, 0x02a3, 0x02a3, 0x02a3,
0x0000, 0x02a8, 0x0000, 0x02aa, 0x02aa, 0x0000, 0x02ad, 0x0000,
0x02af, 0x0000, 0x02b1, 0x02b1, 0x0000, 0x0000, 0x02b5, 0x0000,
0x0000, 0x02b8, 0x0000, 0x02ba, 0x02ba, 0x0000, 0x0000, 0x02be,
// Entry 2C0 - 2FF
0x02be, 0x0000, 0x0000, 0x02c2, 0x0000, 0x02c4, 0x02c1, 0x02c1,
0x0000, 0x0000, 0x02c9, 0x02c8, 0x02c8, 0x0000, 0x0000, 0x02ce,
0x0000, 0x02d0, 0x0000, 0x02d2, 0x0000, 0x0000, 0x02d5, 0x0000,
0x0000, 0x0000, 0x02d9, 0x0000, 0x02db, 0x0000, 0x02dd, 0x0000,
0x02df, 0x02df, 0x0000, 0x02e2, 0x0000, 0x02e4, 0x0000, 0x02e6,
0x02e6, 0x02e6, 0x02e6, 0x02e6, 0x0000, 0x02ec, 0x02ed, 0x02ec,
0x0000, 0x02f0,
} // Size: 1532 bytes
0x0000, 0x02c0, 0x0000, 0x02c2, 0x0000, 0x02c4, 0x0000, 0x02c6,
0x0000, 0x02c8, 0x02c8, 0x0000, 0x0000, 0x02cc, 0x0000, 0x02ce,
0x02cb, 0x02cb, 0x0000, 0x0000, 0x02d3, 0x02d2, 0x02d2, 0x0000,
0x0000, 0x02d8, 0x0000, 0x02da, 0x0000, 0x02dc, 0x0000, 0x0000,
0x02df, 0x0000, 0x02e1, 0x0000, 0x0000, 0x02e4, 0x0000, 0x02e6,
0x0000, 0x02e8, 0x0000, 0x02ea, 0x02ea, 0x0000, 0x0000, 0x02ee,
0x02ed, 0x02ed, 0x0000, 0x02f2, 0x0000, 0x02f4, 0x02f4, 0x02f4,
0x02f4, 0x02f4, 0x0000, 0x02fa, 0x02fb, 0x02fa, 0x0000, 0x02fe,
} // Size: 1560 bytes
// Total table size 1532 bytes (1KiB); checksum: 90718A2
// Total table size 1560 bytes (1KiB); checksum: 4897681C
+1 -1
View File
@@ -16,7 +16,7 @@ func TestLinking(t *testing.T) {
compact := getSize(t, `display.English.Languages().Name(language.English)`)
if d := base - compact; d < 1.5*1024*1024 {
t.Errorf("size(base)-size(compact) was %d; want > 1.5MB", base, compact)
t.Errorf("size(base) - size(compact) = %d - %d = was %d; want > 1.5MB", base, compact, d)
}
}
+21 -12
View File
@@ -371,9 +371,6 @@ func TestTag(t *testing.T) {
{"sr-Latn", "sr-Latn-ME", "srpskohrvatski (Crna Gora)"},
// Double script and region
{"nl", "en-Cyrl-BE", "Engels (Cyrillisch, België)"},
// Canonical equivalents.
{"ro", "ro-MD", "moldovenească"},
{"ro", "mo", "moldovenească"},
}
for _, tt := range tests {
t.Run(tt.dict+"/"+tt.tag, func(t *testing.T) {
@@ -445,9 +442,6 @@ func TestLanguage(t *testing.T) {
{"en", "af-NA", "Afrikaans"},
{"en", "zu-BR", "Zulu"},
{"agq", "zh-Hant", "|[language: zh-Hant]"},
// Canonical equivalents.
{"ro", "ro-MD", "moldovenească"},
{"ro", "mo", "moldovenească"},
{"en", "sh", "Serbo-Croatian"},
{"en", "sr-Latn", "Serbo-Croatian"},
{"en", "sr", "Serbian"},
@@ -540,8 +534,6 @@ func TestRegion(t *testing.T) {
{"nl", "NL", "Nederland"},
{"en", "US", "United States"},
{"en", "ZZ", "Unknown Region"},
{"en", "UM", "U.S. Outlying Islands"},
{"en-GB", "UM", "U.S. Outlying Islands"},
{"en-GB", "NL", "Netherlands"},
// Canonical equivalents
{"en", "UK", "United Kingdom"},
@@ -628,9 +620,6 @@ func TestSelf(t *testing.T) {
{"sr-Latn-ME", "srpskohrvatski"},
{"sr-Cyrl-ME", "српски"},
{"sr-NL", "српски"},
// Canonical equivalents.
{"ro-MD", "moldovenească"},
{"mo", "moldovenească"},
// NOTE: kk is defined, but in Cyrillic script. For China, Arab is the
// dominant script. We do not have data for kk-Arab and we chose to not
// fall back in such cases.
@@ -644,6 +633,27 @@ func TestSelf(t *testing.T) {
}
}
func TestEquivalence(t *testing.T) {
testCases := []struct {
desc string
namer Namer
}{
{"Self", Self},
{"Tags", Tags(language.Romanian)},
{"Languages", Languages(language.Romanian)},
{"Scripts", Scripts(language.Romanian)},
}
for _, tc := range testCases {
t.Run(tc.desc, func(t *testing.T) {
ro := tc.namer.Name(language.Raw.MustParse("ro-MD"))
mo := tc.namer.Name(language.Raw.MustParse("mo"))
if ro != mo {
t.Errorf("%q != %q", ro, mo)
}
})
}
}
func TestDictionaryLang(t *testing.T) {
tests := []struct {
d *Dictionary
@@ -693,7 +703,6 @@ func TestDictionaryScript(t *testing.T) {
name string
}{
{English, "Cyrl", "Cyrillic"},
{Portuguese, "Gujr", "gujerati"},
{EuropeanPortuguese, "Gujr", "guzerate"},
}
for i, test := range tests {
+24050 -21280
View File
File diff suppressed because it is too large Load Diff
+8 -2
View File
@@ -1497,8 +1497,14 @@ func (b *builder) writeMatchData() {
if desired == supported && desired == "*_*_*" {
continue
}
if desired != supported { // (Weird but correct.)
log.Fatalf("not supported: desired=%q; supported=%q", desired, supported)
if desired != supported {
// This is now supported by CLDR, but only one case, which
// should already be covered by paradigm locales. For instance,
// test case "und, en, en-GU, en-IN, en-GB ; en-ZA ; en-GB" in
// testdata/CLDRLocaleMatcherTest.txt tests this.
if supported != "en_*_GB" {
log.Fatalf("not supported: desired=%q; supported=%q", desired, supported)
}
continue
}
ri := regionIntelligibility{
+1 -1
View File
@@ -49,7 +49,7 @@ func main() {
defer func() {
buf := &bytes.Buffer{}
if _, err = w.WriteGo(buf, "language"); err != nil {
if _, err = w.WriteGo(buf, "language", ""); err != nil {
log.Fatalf("Error formatting file index.go: %v", err)
}
+693 -679
View File
File diff suppressed because it is too large Load Diff
+20
View File
@@ -299,6 +299,26 @@ func (t Tag) String() string {
return string(buf[:t.genCoreBytes(buf[:])])
}
// MarshalText implements encoding.TextMarshaler.
func (t Tag) MarshalText() (text []byte, err error) {
if t.str != "" {
text = append(text, t.str...)
} else if t.script == 0 && t.region == 0 {
text = append(text, t.lang.String()...)
} else {
buf := [maxCoreSize]byte{}
text = buf[:t.genCoreBytes(buf[:])]
}
return text, nil
}
// UnmarshalText implements encoding.TextUnmarshaler.
func (t *Tag) UnmarshalText(text []byte) error {
tag, err := Raw.Parse(string(text))
*t = tag
return err
}
// Base returns the base language of the language tag. If the base language is
// unspecified, an attempt will be made to infer it from the context.
// It uses a variant of CLDR's Add Likely Subtags algorithm. This is subject to change.
+37 -4
View File
@@ -91,11 +91,11 @@ func TestCompactIndex(t *testing.T) {
{"ca-ES-valencia-u-co-phonebk", 1, true},
{"ca-ES-valencia-u-co-phonebk-va-posix", 0, false},
{"x-klingon", 0, false},
{"en-US", 229, true},
{"en-US", 232, true},
{"en-US-u-va-posix", 2, true},
{"en", 133, true},
{"en-u-co-phonebk", 133, true},
{"en-001", 134, true},
{"en", 136, true},
{"en-u-co-phonebk", 136, true},
{"en-001", 137, true},
{"sh", 0, false}, // We don't normalize.
}
for _, tt := range tests {
@@ -106,6 +106,39 @@ func TestCompactIndex(t *testing.T) {
}
}
func TestMarshal(t *testing.T) {
testCases := []string{
// TODO: these values will change with each CLDR update. This issue
// will be solved if we decide to fix the indexes.
"und",
"ca-ES-valencia",
"ca-ES-valencia-u-va-posix",
"ca-ES-valencia-u-co-phonebk",
"ca-ES-valencia-u-co-phonebk-va-posix",
"x-klingon",
"en-US",
"en-US-u-va-posix",
"en",
"en-u-co-phonebk",
"en-001",
"sh",
}
for _, tc := range testCases {
var tag Tag
err := tag.UnmarshalText([]byte(tc))
if err != nil {
t.Errorf("UnmarshalText(%q): unexpected error: %v", tc, err)
}
b, err := tag.MarshalText()
if err != nil {
t.Errorf("MarshalText(%q): unexpected error: %v", tc, err)
}
if got := string(b); got != tc {
t.Errorf("%s: got %q; want %q", tc, got, tc)
}
}
}
func TestBase(t *testing.T) {
tests := []struct {
loc, lang string
+2441 -2430
View File
File diff suppressed because it is too large Load Diff
+11 -3
View File
@@ -12,10 +12,18 @@ import (
"golang.org/x/text/message/catalog"
)
// DefaultCatalog is used by SetString.
var DefaultCatalog *catalog.Catalog = defaultCatalog
// MatchLanguage reports the matched tag obtained from language.MatchStrings for
// the Matcher of the DefaultCatalog.
func MatchLanguage(preferred ...string) language.Tag {
c := DefaultCatalog
tag, _ := language.MatchStrings(c.Matcher(), preferred...)
return tag
}
var defaultCatalog = catalog.New()
// DefaultCatalog is used by SetString.
var DefaultCatalog catalog.Catalog = defaultCatalog
var defaultCatalog = catalog.NewBuilder()
// SetString calls SetString on the initial default Catalog.
func SetString(tag language.Tag, key string, msg string) error {
+119 -42
View File
@@ -156,23 +156,127 @@ import (
"errors"
"fmt"
"golang.org/x/text/internal"
"golang.org/x/text/internal/catmsg"
"golang.org/x/text/language"
)
// A Catalog holds translations for messages for supported languages.
type Catalog struct {
// A Catalog allows lookup of translated messages.
type Catalog interface {
// Languages returns all languages for which the Catalog contains variants.
Languages() []language.Tag
// Matcher returns a Matcher for languages from this Catalog.
Matcher() language.Matcher
// A Context is used for evaluating Messages.
Context(tag language.Tag, r catmsg.Renderer) *Context
// This method also makes Catalog a private interface.
lookup(tag language.Tag, key string) (data string, ok bool)
}
// NewFromMap creates a Catalog from the given map. If a Dictionary is
// underspecified the entry is retrieved from a parent language.
func NewFromMap(dictionaries map[string]Dictionary, opts ...Option) (Catalog, error) {
options := options{}
for _, o := range opts {
o(&options)
}
c := &catalog{
dicts: map[language.Tag]Dictionary{},
}
_, hasFallback := dictionaries[options.fallback.String()]
if hasFallback {
// TODO: Should it be okay to not have a fallback language?
// Catalog generators could enforce there is always a fallback.
c.langs = append(c.langs, options.fallback)
}
for lang, dict := range dictionaries {
tag, err := language.Parse(lang)
if err != nil {
return nil, fmt.Errorf("catalog: invalid language tag %q", lang)
}
if _, ok := c.dicts[tag]; ok {
return nil, fmt.Errorf("catalog: duplicate entry for tag %q after normalization", tag)
}
c.dicts[tag] = dict
if !hasFallback || tag != options.fallback {
c.langs = append(c.langs, tag)
}
}
if hasFallback {
internal.SortTags(c.langs[1:])
} else {
internal.SortTags(c.langs)
}
c.matcher = language.NewMatcher(c.langs)
return c, nil
}
// A Dictionary is a source of translations for a single language.
type Dictionary interface {
// Lookup returns a message compiled with catmsg.Compile for the given key.
// It returns false for ok if such a message could not be found.
Lookup(key string) (data string, ok bool)
}
type catalog struct {
langs []language.Tag
dicts map[language.Tag]Dictionary
macros store
matcher language.Matcher
}
func (c *catalog) Languages() []language.Tag { return c.langs }
func (c *catalog) Matcher() language.Matcher { return c.matcher }
func (c *catalog) lookup(tag language.Tag, key string) (data string, ok bool) {
for ; ; tag = tag.Parent() {
if dict, ok := c.dicts[tag]; ok {
if data, ok := dict.Lookup(key); ok {
return data, true
}
}
if tag == language.Und {
break
}
}
return "", false
}
// Context returns a Context for formatting messages.
// Only one Message may be formatted per context at any given time.
func (c *catalog) Context(tag language.Tag, r catmsg.Renderer) *Context {
return &Context{
cat: c,
tag: tag,
dec: catmsg.NewDecoder(tag, r, &dict{&c.macros, tag}),
}
}
// A Builder allows building a Catalog programmatically.
type Builder struct {
options
matcher language.Matcher
index store
macros store
}
type options struct{}
type options struct {
fallback language.Tag
}
// An Option configures Catalog behavior.
type Option func(*options)
// Fallback specifies the default fallback language. The default is Und.
func Fallback(tag language.Tag) Option {
return func(o *options) { o.fallback = tag }
}
// TODO:
// // Catalogs specifies one or more sources for a Catalog.
// // Lookups are in order.
@@ -186,22 +290,17 @@ type Option func(*options)
//
// func Dict(tag language.Tag, d ...Dictionary) Option
// New returns a new Catalog.
func New(opts ...Option) *Catalog {
c := &Catalog{}
// NewBuilder returns an empty mutable Catalog.
func NewBuilder(opts ...Option) *Builder {
c := &Builder{}
for _, o := range opts {
o(&c.options)
}
return c
}
// Languages returns all languages for which the Catalog contains variants.
func (c *Catalog) Languages() []language.Tag {
return c.index.languages()
}
// SetString is shorthand for Set(tag, key, String(msg)).
func (c *Catalog) SetString(tag language.Tag, key string, msg string) error {
func (c *Builder) SetString(tag language.Tag, key string, msg string) error {
return c.set(tag, key, &c.index, String(msg))
}
@@ -209,26 +308,20 @@ func (c *Catalog) SetString(tag language.Tag, key string, msg string) error {
//
// When evaluation this message, the first Message in the sequence to msgs to
// evaluate to a string will be the message returned.
func (c *Catalog) Set(tag language.Tag, key string, msg ...Message) error {
func (c *Builder) Set(tag language.Tag, key string, msg ...Message) error {
return c.set(tag, key, &c.index, msg...)
}
// SetMacro defines a Message that may be substituted in another message.
// The arguments to a macro Message are passed as arguments in the
// placeholder the form "${foo(arg1, arg2)}".
func (c *Catalog) SetMacro(tag language.Tag, name string, msg ...Message) error {
func (c *Builder) SetMacro(tag language.Tag, name string, msg ...Message) error {
return c.set(tag, name, &c.macros, msg...)
}
// ErrNotFound indicates there was no message for the given key.
var ErrNotFound = errors.New("catalog: message not found")
// A Message holds a collection of translations for the same phrase that may
// vary based on the values of substitution arguments.
type Message interface {
catmsg.Message
}
// String specifies a plain message string. It can be used as fallback if no
// other strings match or as a simple standalone message.
//
@@ -247,44 +340,28 @@ func Var(name string, msg ...Message) Message {
return &catmsg.Var{Name: name, Message: firstInSequence(msg)}
}
// firstInSequence is a message type that prints the first message in the
// sequence that resolves to a match for the given substitution arguments.
type firstInSequence []Message
func (s firstInSequence) Compile(e *catmsg.Encoder) error {
e.EncodeMessageType(catmsg.First)
err := catmsg.ErrIncomplete
for i, m := range s {
if err == nil {
return fmt.Errorf("catalog: message argument %d is complete and blocks subsequent messages", i-1)
}
err = e.EncodeMessage(m)
}
return err
}
// Context returns a Context for formatting messages.
// Only one Message may be formatted per context at any given time.
func (c *Catalog) Context(tag language.Tag, r catmsg.Renderer) *Context {
func (b *Builder) Context(tag language.Tag, r catmsg.Renderer) *Context {
return &Context{
cat: c,
cat: b,
tag: tag,
dec: catmsg.NewDecoder(tag, r, &dict{&c.macros, tag}),
dec: catmsg.NewDecoder(tag, r, &dict{&b.macros, tag}),
}
}
// A Context is used for evaluating Messages.
// Only one Message may be formatted per context at any given time.
type Context struct {
cat *Catalog
tag language.Tag
cat Catalog
tag language.Tag // TODO: use compact index.
dec *catmsg.Decoder
}
// Execute looks up and executes the message with the given key.
// It returns ErrNotFound if no message could be found in the index.
func (c *Context) Execute(key string) error {
data, ok := c.cat.index.lookup(c.tag, key)
data, ok := c.cat.lookup(c.tag, key)
if !ok {
return ErrNotFound
}
+125 -23
View File
@@ -6,11 +6,11 @@ package catalog
import (
"bytes"
"fmt"
"path"
"reflect"
"strings"
"testing"
"golang.org/x/text/internal"
"golang.org/x/text/internal/catmsg"
"golang.org/x/text/language"
)
@@ -20,17 +20,33 @@ type entry struct {
msg interface{}
}
var testCases = []struct {
desc string
cat []entry
lookup []entry
}{{
func langs(s string) []language.Tag {
t, _, _ := language.ParseAcceptLanguage(s)
return t
}
type testCase struct {
desc string
cat []entry
lookup []entry
fallback string
match []string
tags []language.Tag
}
var testCases = []testCase{{
desc: "empty catalog",
lookup: []entry{
{"en", "key", ""},
{"en", "", ""},
{"nl", "", ""},
},
match: []string{
"gr -> und",
"en-US -> und",
"af -> und",
},
tags: nil, // not an empty list.
}, {
desc: "one entry",
cat: []entry{
@@ -45,6 +61,11 @@ var testCases = []struct {
{"en-oxendict", "hello", "Hello!"},
{"en-oxendict-u-ms-metric", "hello", "Hello!"},
},
match: []string{
"gr -> en",
"en-US -> en",
},
tags: langs("en"),
}, {
desc: "hierarchical languages",
cat: []entry{
@@ -52,6 +73,7 @@ var testCases = []struct {
{"en-GB", "hello", "Hellø!"},
{"en-US", "hello", "Howdy!"},
{"en", "greetings", "Greetings!"},
{"gsw", "hello", "Grüetzi!"},
},
lookup: []entry{
{"und", "hello", ""},
@@ -70,6 +92,12 @@ var testCases = []struct {
{"en-oxendict", "greetings", "Greetings!"},
{"en-US-oxendict-u-ms-metric", "greetings", "Greetings!"},
},
fallback: "gsw",
match: []string{
"gr -> gsw",
"en-US -> en-US",
},
tags: langs("gsw, en, en-GB, en-US"),
}, {
desc: "variables",
cat: []entry{
@@ -103,6 +131,7 @@ var testCases = []struct {
{"en", "scopes", "Hello Joe and Jane."},
{"en", "missing var", "Hello missing."},
},
tags: langs("en"),
}, {
desc: "macros",
cat: []entry{
@@ -122,16 +151,29 @@ var testCases = []struct {
{"en", "badnum", "Hello $!(BADNUM)."},
{"en", "undefined", "Hello undefined."},
{"en", "macroU", "Hello macroU!"},
}}}
},
tags: langs("en"),
}}
func initCat(entries []entry) (*Catalog, []language.Tag) {
tags := []language.Tag{}
cat := New()
for _, e := range entries {
func setMacros(b *Builder) {
b.SetMacro(language.English, "macro1", String("Joe"))
b.SetMacro(language.Und, "macro2", String("${macro1(1)}"))
b.SetMacro(language.English, "macroU", noMatchMessage{})
}
type buildFunc func(t *testing.T, tc testCase) Catalog
func initBuilder(t *testing.T, tc testCase) Catalog {
options := []Option{}
if tc.fallback != "" {
options = append(options, Fallback(language.MustParse(tc.fallback)))
}
cat := NewBuilder(options...)
for _, e := range tc.cat {
tag := language.MustParse(e.tag)
tags = append(tags, tag)
switch msg := e.msg.(type) {
case string:
cat.SetString(tag, e.key, msg)
case Message:
cat.Set(tag, e.key, msg)
@@ -139,23 +181,81 @@ func initCat(entries []entry) (*Catalog, []language.Tag) {
cat.Set(tag, e.key, msg...)
}
}
return cat, internal.UniqueTags(tags)
setMacros(cat)
return cat
}
type dictionary map[string]string
func (d dictionary) Lookup(key string) (data string, ok bool) {
data, ok = d[key]
return data, ok
}
func initCatalog(t *testing.T, tc testCase) Catalog {
m := map[string]Dictionary{}
for _, e := range tc.cat {
m[e.tag] = dictionary{}
}
for _, e := range tc.cat {
var msg Message
switch x := e.msg.(type) {
case string:
msg = String(x)
case Message:
msg = x
case []Message:
msg = firstInSequence(x)
}
data, _ := catmsg.Compile(language.MustParse(e.tag), nil, msg)
m[e.tag].(dictionary)[e.key] = data
}
options := []Option{}
if tc.fallback != "" {
options = append(options, Fallback(language.MustParse(tc.fallback)))
}
c, err := NewFromMap(m, options...)
if err != nil {
t.Fatal(err)
}
// TODO: implement macros for fixed catalogs.
b := NewBuilder()
setMacros(b)
c.(*catalog).macros.index = b.macros.index
return c
}
func TestMatcher(t *testing.T) {
test := func(t *testing.T, init buildFunc) {
for _, tc := range testCases {
for _, s := range tc.match {
a := strings.Split(s, "->")
t.Run(path.Join(tc.desc, a[0]), func(t *testing.T) {
cat := init(t, tc)
got, _ := language.MatchStrings(cat.Matcher(), a[0])
want := language.MustParse(strings.TrimSpace(a[1]))
if got != want {
t.Errorf("got %q; want %q", got, want)
}
})
}
}
}
t.Run("Builder", func(t *testing.T) { test(t, initBuilder) })
t.Run("Catalog", func(t *testing.T) { test(t, initCatalog) })
}
func TestCatalog(t *testing.T) {
for _, tc := range testCases {
t.Run(fmt.Sprintf("%s", tc.desc), func(t *testing.T) {
cat, wantTags := initCat(tc.cat)
cat.SetMacro(language.English, "macro1", String("Joe"))
cat.SetMacro(language.Und, "macro2", String("${macro1(1)}"))
cat.SetMacro(language.English, "macroU", noMatchMessage{})
test := func(t *testing.T, init buildFunc) {
for _, tc := range testCases {
cat := init(t, tc)
wantTags := tc.tags
if got := cat.Languages(); !reflect.DeepEqual(got, wantTags) {
t.Errorf("%s:Languages: got %v; want %v", tc.desc, got, wantTags)
}
for _, e := range tc.lookup {
t.Run(fmt.Sprintf("%s/%s", e.tag, e.key), func(t *testing.T) {
t.Run(path.Join(tc.desc, e.tag, e.key), func(t *testing.T) {
tag := language.MustParse(e.tag)
buf := testRenderer{}
ctx := cat.Context(tag, &buf)
@@ -171,8 +271,10 @@ func TestCatalog(t *testing.T) {
}
})
}
})
}
}
t.Run("Builder", func(t *testing.T) { test(t, initBuilder) })
t.Run("Catalog", func(t *testing.T) { test(t, initCatalog) })
}
type testRenderer struct {
+46 -7
View File
@@ -33,7 +33,11 @@ func (d *dict) Lookup(key string) (data string, ok bool) {
return d.s.lookup(d.tag, key)
}
func (c *Catalog) set(tag language.Tag, key string, s *store, msg ...Message) error {
func (b *Builder) lookup(tag language.Tag, key string) (data string, ok bool) {
return b.index.lookup(tag, key)
}
func (c *Builder) set(tag language.Tag, key string, s *store, msg ...Message) error {
data, err := catmsg.Compile(tag, &dict{&c.macros, tag}, firstInSequence(msg))
s.mutex.Lock()
@@ -45,6 +49,7 @@ func (c *Catalog) set(tag language.Tag, key string, s *store, msg ...Message) er
if s.index == nil {
s.index = map[language.Tag]msgMap{}
}
c.matcher = nil
s.index[tag] = m
}
@@ -52,6 +57,23 @@ func (c *Catalog) set(tag language.Tag, key string, s *store, msg ...Message) er
return err
}
func (c *Builder) Matcher() language.Matcher {
c.index.mutex.RLock()
m := c.matcher
c.index.mutex.RUnlock()
if m != nil {
return m
}
c.index.mutex.Lock()
if c.matcher == nil {
c.matcher = language.NewMatcher(c.unlockedLanguages())
}
m = c.matcher
c.index.mutex.Unlock()
return m
}
type store struct {
mutex sync.RWMutex
index map[language.Tag]msgMap
@@ -76,15 +98,32 @@ func (s *store) lookup(tag language.Tag, key string) (data string, ok bool) {
return "", false
}
// Languages returns all languages for which the store contains variants.
func (s *store) languages() []language.Tag {
// Languages returns all languages for which the Catalog contains variants.
func (b *Builder) Languages() []language.Tag {
s := &b.index
s.mutex.RLock()
defer s.mutex.RUnlock()
tags := make([]language.Tag, 0, len(s.index))
for t := range s.index {
tags = append(tags, t)
return b.unlockedLanguages()
}
func (b *Builder) unlockedLanguages() []language.Tag {
s := &b.index
if len(s.index) == 0 {
return nil
}
internal.SortTags(tags)
tags := make([]language.Tag, 0, len(s.index))
_, hasFallback := s.index[b.options.fallback]
offset := 0
if hasFallback {
tags = append(tags, b.options.fallback)
offset = 1
}
for t := range s.index {
if t != b.options.fallback {
tags = append(tags, t)
}
}
internal.SortTags(tags[offset:])
return tags
}
+15
View File
@@ -0,0 +1,15 @@
// Copyright 2017 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.
// +build go1.9
package catalog
import "golang.org/x/text/internal/catmsg"
// A Message holds a collection of translations for the same phrase that may
// vary based on the values of substitution arguments.
type Message = catmsg.Message
type firstInSequence = catmsg.FirstOf

Some files were not shown because too many files have changed in this diff Show More