vendor: update all dependencies to latest versions
This commit is contained in:
+39
-9
@@ -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
@@ -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
|
||||
|
||||
Generated
Vendored
+2
@@ -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.
|
||||
Generated
Vendored
+2
@@ -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
File diff suppressed because it is too large
Load Diff
+1156
File diff suppressed because it is too large
Load Diff
+49
@@ -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
@@ -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
@@ -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
|
||||
Generated
Vendored
Executable
+186
@@ -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"
|
||||
}
|
||||
]
|
||||
}
|
||||
Generated
Vendored
Executable
+137
@@ -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"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
Generated
Vendored
Executable
+82
@@ -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})"
|
||||
}
|
||||
]
|
||||
}
|
||||
Generated
Vendored
Executable
+154
@@ -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"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
Generated
Vendored
Executable
+203
@@ -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"
|
||||
}
|
||||
]
|
||||
}
|
||||
Generated
Vendored
Executable
+137
@@ -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
@@ -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)
|
||||
}
|
||||
+57
@@ -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
|
||||
Generated
Vendored
Executable
+39
@@ -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"
|
||||
}
|
||||
]
|
||||
}
|
||||
Generated
Vendored
Executable
+39
@@ -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"
|
||||
}
|
||||
]
|
||||
}
|
||||
Generated
Vendored
+39
@@ -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
|
||||
}
|
||||
]
|
||||
}
|
||||
Generated
Vendored
Executable
+35
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
File diff suppressed because it is too large
Load Diff
+335
@@ -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
@@ -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
@@ -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
File diff suppressed because it is too large
Load Diff
+61
-54
@@ -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
|
||||
|
||||
+202
-194
@@ -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
@@ -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
@@ -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
@@ -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.
|
||||
|
||||
+1
-1
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
|
||||
}
|
||||
}
|
||||
+89
@@ -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
@@ -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
|
||||
+171
@@ -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>
|
||||
+60
@@ -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>
|
||||
+63
@@ -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>
|
||||
+646
@@ -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
@@ -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
@@ -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
@@ -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
@@ -100,7 +100,7 @@ func genTables() {
|
||||
})
|
||||
|
||||
w := gen.NewCodeWriter()
|
||||
defer w.WriteGoFile("tables.go", "idna")
|
||||
defer w.WriteVersionedGoFile("tables.go", "idna")
|
||||
|
||||
gen.WriteUnicodeVersion(w)
|
||||
|
||||
|
||||
Generated
Vendored
+2
@@ -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
@@ -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)
|
||||
}
|
||||
})
|
||||
}
|
||||
Generated
Vendored
+17
-1
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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)
|
||||
|
||||
|
||||
Generated
Vendored
+2
@@ -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.
|
||||
+4486
File diff suppressed because it is too large
Load Diff
+357
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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"},
|
||||
|
||||
|
||||
+6
-6
@@ -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
@@ -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
@@ -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
@@ -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
File diff suppressed because it is too large
Load Diff
+86
-85
@@ -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
@@ -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
@@ -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
File diff suppressed because it is too large
Load Diff
+8
-2
@@ -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
@@ -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
File diff suppressed because it is too large
Load Diff
+20
@@ -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
@@ -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
File diff suppressed because it is too large
Load Diff
+11
-3
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
Reference in New Issue
Block a user