Merge pull request #36802 from brendandburns/i18n

Automatic merge from submit-queue

Begin paths for internationalization in kubectl

This is just the first step, purposely simple so we can get the interface correct.

@kubernetes/sig-cli @deads2k
This commit is contained in:
Kubernetes Submit Queue 2016-12-24 13:09:12 -08:00 committed by GitHub
commit 1ee7163308
53 changed files with 3769 additions and 14 deletions

16
Godeps/Godeps.json generated
View File

@ -287,6 +287,22 @@
"Comment": "v1.2.1",
"Rev": "dfb21201d9270c1082d5fb0f07f500311ff72f18"
},
{
"ImportPath": "github.com/chai2010/gettext-go/gettext",
"Rev": "c6fed771bfd517099caf0f7a961671fa8ed08723"
},
{
"ImportPath": "github.com/chai2010/gettext-go/gettext/mo",
"Rev": "c6fed771bfd517099caf0f7a961671fa8ed08723"
},
{
"ImportPath": "github.com/chai2010/gettext-go/gettext/plural",
"Rev": "c6fed771bfd517099caf0f7a961671fa8ed08723"
},
{
"ImportPath": "github.com/chai2010/gettext-go/gettext/po",
"Rev": "c6fed771bfd517099caf0f7a961671fa8ed08723"
},
{
"ImportPath": "github.com/cloudflare/cfssl/auth",
"Comment": "1.2.0",

140
Godeps/LICENSES generated
View File

@ -9643,6 +9643,146 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
================================================================================
================================================================================
= vendor/github.com/chai2010/gettext-go/gettext licensed under: =
Copyright 2013 ChaiShushan <chaishushan{AT}gmail.com>. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
= vendor/github.com/chai2010/gettext-go/LICENSE 87ce3ee0376881b02e75d3d5be2a6ba6 -
================================================================================
================================================================================
= vendor/github.com/chai2010/gettext-go/gettext/mo licensed under: =
Copyright 2013 ChaiShushan <chaishushan{AT}gmail.com>. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
= vendor/github.com/chai2010/gettext-go/LICENSE 87ce3ee0376881b02e75d3d5be2a6ba6 -
================================================================================
================================================================================
= vendor/github.com/chai2010/gettext-go/gettext/plural licensed under: =
Copyright 2013 ChaiShushan <chaishushan{AT}gmail.com>. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
= vendor/github.com/chai2010/gettext-go/LICENSE 87ce3ee0376881b02e75d3d5be2a6ba6 -
================================================================================
================================================================================
= vendor/github.com/chai2010/gettext-go/gettext/po licensed under: =
Copyright 2013 ChaiShushan <chaishushan{AT}gmail.com>. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
= vendor/github.com/chai2010/gettext-go/LICENSE 87ce3ee0376881b02e75d3d5be2a6ba6 -
================================================================================
================================================================================
= vendor/github.com/cloudflare/cfssl/auth licensed under: =

View File

@ -23,6 +23,7 @@ import (
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
)
// Create a Server that implements the kubectl command
func NewKubectlServer() *Server {
cmd := cmd.NewKubectlCommand(cmdutil.NewFactory(nil), os.Stdin, os.Stdout, os.Stderr)
localFlags := cmd.LocalFlags()

View File

@ -257,6 +257,7 @@ pkg/util/flushwriter
pkg/util/goroutinemap
pkg/util/hash
pkg/util/homedir
pkg/util/i18n
pkg/util/interrupt
pkg/util/io
pkg/util/json

View File

@ -130,7 +130,8 @@ def file_extension(filename):
return os.path.splitext(filename)[1].split(".")[-1].lower()
skipped_dirs = ['Godeps', 'third_party', '_gopath', '_output', '.git', 'cluster/env.sh',
"vendor", "test/e2e/generated/bindata.go", "hack/boilerplate/test"]
"vendor", "test/e2e/generated/bindata.go", "hack/boilerplate/test",
"pkg/generated/bindata.go"]
def normalize_files(files):
newfiles = []

View File

@ -38,6 +38,7 @@ if ! which go-bindata &>/dev/null ; then
exit 5
fi
# These are files for e2e tests.
BINDATA_OUTPUT="${KUBE_ROOT}/test/e2e/generated/bindata.go"
go-bindata -nometadata -prefix "${KUBE_ROOT}" -o "${BINDATA_OUTPUT}.tmp" -pkg generated \
-ignore .jpg -ignore .png -ignore .md \
@ -59,3 +60,23 @@ else
fi
rm -f "${BINDATA_OUTPUT}.tmp"
# These are files for runtime code
BINDATA_OUTPUT="${KUBE_ROOT}/pkg/generated/bindata.go"
go-bindata -nometadata -prefix "${KUBE_ROOT}" -o "${BINDATA_OUTPUT}.tmp" -pkg generated \
-ignore .jpg -ignore .png -ignore .md \
"${KUBE_ROOT}/translations/..."
gofmt -s -w "${BINDATA_OUTPUT}.tmp"
# Here we compare and overwrite only if different to avoid updating the
# timestamp and triggering a rebuild. The 'cat' redirect trick to preserve file
# permissions of the target file.
if ! cmp -s "${BINDATA_OUTPUT}.tmp" "${BINDATA_OUTPUT}" ; then
cat "${BINDATA_OUTPUT}.tmp" > "${BINDATA_OUTPUT}"
V=2 kube::log::info "Generated bindata file : ${BINDATA_OUTPUT} has $(wc -l ${BINDATA_OUTPUT}) lines of lovely automated artifacts"
else
V=2 kube::log::info "No changes in generated bindata file: ${BINDATA_OUTPUT}"
fi
rm -f "${BINDATA_OUTPUT}.tmp"

View File

@ -9,6 +9,9 @@ load(
go_library(
name = "go_default_library",
srcs = ["doc.go"],
srcs = [
"bindata.go",
"doc.go",
],
tags = ["automanaged"],
)

418
pkg/generated/bindata.go Normal file
View File

@ -0,0 +1,418 @@
// Code generated by go-bindata.
// sources:
// ../../../translations/kubectl/default/LC_MESSAGES/k8s.mo
// ../../../translations/kubectl/default/LC_MESSAGES/k8s.po
// ../../../translations/kubectl/en_US/LC_MESSAGES/k8s.mo
// ../../../translations/kubectl/en_US/LC_MESSAGES/k8s.po
// ../../../translations/test/default/LC_MESSAGES/k8s.mo
// ../../../translations/test/default/LC_MESSAGES/k8s.po
// ../../../translations/test/en_US/LC_MESSAGES/k8s.mo
// ../../../translations/test/en_US/LC_MESSAGES/k8s.po
// DO NOT EDIT!
package generated
import (
"bytes"
"compress/gzip"
"fmt"
"io"
"io/ioutil"
"os"
"path/filepath"
"strings"
"time"
)
func bindataRead(data []byte, name string) ([]byte, error) {
gz, err := gzip.NewReader(bytes.NewBuffer(data))
if err != nil {
return nil, fmt.Errorf("Read %q: %v", name, err)
}
var buf bytes.Buffer
_, err = io.Copy(&buf, gz)
clErr := gz.Close()
if err != nil {
return nil, fmt.Errorf("Read %q: %v", name, err)
}
if clErr != nil {
return nil, err
}
return buf.Bytes(), nil
}
type asset struct {
bytes []byte
info os.FileInfo
}
type bindataFileInfo struct {
name string
size int64
mode os.FileMode
modTime time.Time
}
func (fi bindataFileInfo) Name() string {
return fi.name
}
func (fi bindataFileInfo) Size() int64 {
return fi.size
}
func (fi bindataFileInfo) Mode() os.FileMode {
return fi.mode
}
func (fi bindataFileInfo) ModTime() time.Time {
return fi.modTime
}
func (fi bindataFileInfo) IsDir() bool {
return false
}
func (fi bindataFileInfo) Sys() interface{} {
return nil
}
var _translationsKubectlDefaultLc_messagesK8sMo = []byte("\x1f\x8b\x08\x00\x00\x09\x6e\x88\x00\xff\xbc\x93\xcf\x6e\xd3\x4e\x10\xc7\x27\xbf\xf6\x77\xf1\x91\x33\x87\x41\x02\xa9\x08\x8d\x59\xbb\xa5\xaa\x5c\x82\x50\x4b\x8b\x22\x25\x6a\x54\x5c\xd4\x23\x1b\xef\xd4\x59\xb4\xd9\xb5\x76\xd7\x4d\x7b\xe4\x21\x78\x05\x2e\xf0\x16\xbc\x02\x67\x9e\x05\x39\x86\x14\x6e\xbd\xb4\x7b\xb0\xfc\x1d\x7d\xfc\x9d\x3f\x9e\xfd\xf9\x60\xf3\x33\x00\xc0\x06\x00\x3c\x04\x80\x1d\x00\xf8\x1f\x00\xc6\xd0\x9f\x0f\x00\x30\x02\x00\x09\x00\x5b\x03\x80\xaf\x00\xf0\x6d\x00\xf0\x63\x00\xf0\x18\x00\x3e\x6d\x00\x7c\x07\x80\x2f\x1b\x00\x83\xdf\x3e\x7f\xce\x7f\xdd\xe3\xac\x51\x32\x32\xc6\x39\xa3\xb4\xd6\x45\x19\xb5\xb3\x01\x9d\x45\x89\x9e\x83\x6b\x7d\xc5\x9b\xb7\x81\x60\x29\x63\x35\x47\xdd\x85\xcd\x35\x86\xb6\x69\x9c\x8f\xac\x3a\x4a\x5b\xa5\x2f\xb5\x6a\xa5\x59\xe3\x01\xa5\x55\x6b\x85\x95\x33\x86\xab\xde\x96\xf0\x89\xfa\x8b\x5b\xb2\x67\xbc\x70\xad\x55\x9b\x77\x9f\xe2\x1e\xba\x80\xa9\x77\x1f\xb9\x8a\x34\x52\xf4\x9e\x7d\xd0\xce\x16\x58\x73\x8c\x7c\x15\xa9\x76\xc4\x57\x72\xd1\x18\x0e\x34\x67\x63\x5c\x72\xca\x5d\x05\x34\x09\xb5\x56\x74\xd0\xd6\x81\x4a\x57\x60\x32\x3d\x29\xe9\xd0\xf3\xea\x4f\xd0\x1b\x19\xb9\xc0\x5c\x64\xdb\x94\xe5\x94\xe5\x98\x8b\x42\x6c\x3f\x13\x42\x88\x64\x7a\x42\xa7\x7c\xa9\xc3\x3f\xdc\xee\x8a\xdb\xc6\x3c\x2b\x5e\xec\x90\xd8\x13\x22\x19\xcb\x10\xa9\xf4\xd2\x06\x23\xa3\xf3\x05\x1e\x78\xb6\x4a\x5a\x3c\x68\xbd\x0d\xf8\x72\xd6\xcb\x54\xa5\xb3\x2e\xf0\xba\x5e\x48\x6d\xd2\xca\x2d\x5e\x25\x93\xd1\xe4\xe8\xa6\x95\x2c\x15\xc9\xa1\xb3\x91\x6d\xa4\xf2\xba\xe1\x02\xbb\xce\x9e\x37\x46\x6a\xbb\x8f\xd5\x5c\xfa\xc0\x71\x78\x56\x1e\xd3\xde\x0d\xd7\xe5\xbd\x60\x4f\x47\xb6\x72\x4a\xdb\xba\xc0\xbd\x99\x8e\xc9\x39\xbd\x65\xcb\xbe\x2f\x68\xea\x58\xe9\x88\x59\xba\x9b\x66\x22\x39\xa7\x5e\xd3\xbb\xd5\x84\x0f\x7b\xdf\x02\x7b\xe3\xb1\xb4\x75\x2b\x6b\xa6\x92\xe5\xa2\x1b\x97\x69\xbd\x34\x74\xec\xfc\x22\x14\x68\x9b\x95\x0c\xc3\x7c\x1f\xfb\xd7\xe1\x96\xc5\x47\x43\xcc\x9e\xee\xaf\x3f\x2d\x90\x6d\x72\xab\xfb\x71\x47\x4b\x83\x4b\x19\xee\x6f\x2b\x7f\x05\x00\x00\xff\xff\xaa\xa3\x15\xc3\x6a\x04\x00\x00")
func translationsKubectlDefaultLc_messagesK8sMoBytes() ([]byte, error) {
return bindataRead(
_translationsKubectlDefaultLc_messagesK8sMo,
"translations/kubectl/default/LC_MESSAGES/k8s.mo",
)
}
func translationsKubectlDefaultLc_messagesK8sMo() (*asset, error) {
bytes, err := translationsKubectlDefaultLc_messagesK8sMoBytes()
if err != nil {
return nil, err
}
info := bindataFileInfo{name: "translations/kubectl/default/LC_MESSAGES/k8s.mo", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
var _translationsKubectlDefaultLc_messagesK8sPo = []byte("\x1f\x8b\x08\x00\x00\x09\x6e\x88\x00\xff\xbc\x53\xdd\x6e\xd3\x4c\x10\xbd\xcf\x53\xcc\xe7\xe8\x93\x5a\xc1\x1a\x3b\x85\xaa\x72\x09\xa2\x0d\x6d\xa9\x68\xd5\x28\x75\x11\x12\x20\xb4\xf1\x4e\x9c\x85\xf5\xac\xb5\x33\xee\xcf\xdb\x23\xdb\x69\x43\x90\x90\x7a\xd3\xde\xcd\xce\x9e\x99\x33\x67\xf6\xec\x10\x72\x64\x01\x09\x9a\xd8\x69\xb1\x9e\x18\x16\x3e\x40\x43\x56\x40\x90\x85\xe3\xc1\x10\x26\xbe\xbe\x0b\xb6\x5c\x0a\x6c\x4d\xb6\x61\x94\xa4\xbb\x83\x21\xe4\x4b\xcb\xb0\xb0\x0e\xc1\x32\x18\xcb\x12\xec\xbc\x11\x34\xd0\x90\xc1\x00\xb2\x44\x60\x5d\x21\x38\x5b\x20\x31\x82\xe6\x2e\x37\x3d\x98\x7c\x3a\x38\x39\x82\x5a\x17\xbf\x74\x89\x6d\xfb\xe3\xd3\xd9\x65\x0e\x07\x57\xf9\xc7\x8b\x19\xcc\x03\x92\xd1\x14\x9b\x78\xde\x04\xe2\xf7\x65\xa5\xad\x8b\x0b\x5f\xbd\xec\x88\xe3\xc1\x70\x50\x71\x69\x0d\x44\x51\x1b\xb0\x84\x36\x8a\xa6\xc1\xff\xc4\x42\xd4\xa9\x51\x9f\x31\xb0\xf5\x94\x41\x89\x22\x78\x2b\xaa\xf4\x0a\x6f\x75\x55\x3b\x64\xb5\x44\xe7\xfc\x37\x8a\x06\xd1\x0c\x6b\x1f\x44\x9d\xb7\xcd\xd4\x61\x53\xb2\xca\x7d\x06\xdd\xd5\xf4\x22\x57\x93\x80\xdd\x3e\xd4\x07\x2d\x98\xb5\xdc\x3b\x2a\x1d\xa9\x74\x04\xa3\x24\x4b\x76\x5e\x24\x49\x92\xac\xc0\x6a\x86\xd7\x96\x37\xb0\xbb\x1d\x76\x07\x46\x69\xf6\xe6\xb5\x4a\xf6\x56\xd8\x33\xcd\xa2\xf2\xd5\xb2\x7d\xc8\xe0\xb0\x57\x0b\x87\xad\x56\x78\xfb\x4f\xf1\xef\xba\xf2\xf3\xd3\xf3\xa3\xb5\xbc\x34\xee\x9b\x4e\x3c\x09\x92\xa8\xfc\xae\xc6\x0c\x5a\xc5\xaf\x6a\xa7\x2d\xed\x43\xb1\xd4\x81\x51\xc6\x57\xf9\xb1\xda\xdb\xc4\xb6\x33\x2c\x30\xa8\x23\x2a\xbc\xb1\x54\x66\xb0\x37\xb7\xd2\x61\xbe\xa8\x13\x24\x0c\xfd\x80\x53\x8f\xc6\x0a\xa4\xf1\x6e\x9c\x26\xab\xeb\x3e\xa7\x2e\x7d\x13\x0a\x9c\xf4\x1c\x19\xac\x49\xce\x34\x95\x8d\x2e\x51\xe5\xa8\xab\xfb\x95\xba\x26\x68\xa7\x8e\x7d\xa8\x38\x03\xaa\xbb\x23\x8f\x47\xfb\xd0\x87\xe3\x2d\x82\xff\xc6\x90\x6e\xef\x6f\xb4\xc8\x00\xa9\x4d\xb4\x4f\x5d\xc8\xad\x40\x74\x55\x1b\x2d\xd8\x59\x49\x13\x79\x59\x99\xd6\x13\x68\x08\xc8\xdd\x4c\xd1\xbd\x45\x1e\x0d\xee\x6c\xf4\x38\xf4\x7a\x94\x68\x10\xdd\x68\x29\x96\xed\x07\xf0\xe4\xee\x80\x9b\xba\xf5\x14\x9a\xb6\xc6\x92\xb1\xd7\xd6\x34\xda\x3d\x14\x33\x68\x32\x0f\x27\x28\xbc\x73\x58\xf4\x24\x0a\xa2\x41\xf4\xbf\xf9\x03\x7a\x83\x01\x61\xe1\x1b\x32\xd1\xda\xf1\xcf\x4a\xf8\xa3\x7f\x9a\x67\xe6\x65\x09\x5f\x93\xef\x4f\x4b\x0a\x37\x9a\xff\xa2\x4c\x9f\x98\x72\x53\xe7\xef\x00\x00\x00\xff\xff\x96\x33\xff\xe8\x78\x05\x00\x00")
func translationsKubectlDefaultLc_messagesK8sPoBytes() ([]byte, error) {
return bindataRead(
_translationsKubectlDefaultLc_messagesK8sPo,
"translations/kubectl/default/LC_MESSAGES/k8s.po",
)
}
func translationsKubectlDefaultLc_messagesK8sPo() (*asset, error) {
bytes, err := translationsKubectlDefaultLc_messagesK8sPoBytes()
if err != nil {
return nil, err
}
info := bindataFileInfo{name: "translations/kubectl/default/LC_MESSAGES/k8s.po", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
var _translationsKubectlEn_usLc_messagesK8sMo = []byte("\x1f\x8b\x08\x00\x00\x09\x6e\x88\x00\xff\xbc\x93\xcf\x6e\xd3\x40\x10\xc6\x27\xb4\x5c\x7c\xe4\xcc\x61\x90\x40\x2a\x42\x63\xd6\x0e\x54\x95\x4b\x10\x6a\x69\x51\xa5\x44\x8d\x8a\x8b\x7a\x64\xe3\x9d\x3a\x8b\x36\xbb\xd6\xee\xba\x69\x8f\x3c\x04\xaf\xc0\x05\xde\x82\x57\xe0\xcc\xb3\x20\xc7\x90\xc2\xad\x97\x76\x0f\x96\xbf\xd1\xcf\xdf\xfc\xf1\xec\xaf\x07\x9b\x5f\x00\x00\x36\x00\xe0\x21\x00\xbc\x00\x80\xfb\x00\x30\x86\xfe\x7c\x04\x80\x23\x00\x90\x00\xb0\x35\x00\xf8\x06\x00\xdf\x07\x00\x3f\x07\x00\x8f\x01\xe0\xf3\x06\xc0\x0f\x00\xf8\xba\x01\x30\xf8\xe3\xf3\xf7\xdc\xeb\x1e\xa7\x8d\x92\x91\x31\xce\x19\xa5\xb5\x2e\xca\xa8\x9d\x0d\xe8\x2c\x4a\xf4\x1c\x5c\xeb\x2b\xde\xbc\x09\x04\x4b\x19\xab\x39\xea\x2e\x6c\xae\x30\xb4\x4d\xe3\x7c\x64\xd5\x51\xda\x2a\x7d\xa1\x55\x2b\xcd\x1a\x0f\x28\xad\x5a\x2b\xac\x9c\x31\x5c\xf5\xb6\x84\x4f\xd4\x3f\xdc\x92\x3d\xe3\xb9\x6b\xad\xda\xbc\xfd\x14\x77\xd0\x05\x4c\xbd\xfb\xc4\x55\xa4\x23\x45\x1f\xd8\x07\xed\x6c\x81\x35\xc7\xc8\x97\x91\x6a\x47\x7c\x29\x17\x8d\xe1\x40\x73\x36\xc6\x25\x27\xdc\x55\x40\x93\x50\x6b\x45\x7b\x6d\x1d\xa8\x74\x05\x26\xd3\xe3\x92\xf6\x3d\xaf\xfe\x04\xbd\x95\x91\x0b\xcc\x45\x36\xa4\x2c\xa7\x2c\xc7\x5c\x14\x62\xf8\x4c\x08\x21\x92\xe9\x31\x9d\xf0\x85\x0e\xff\x71\xdb\x2b\x6e\x88\x79\x5e\x0c\x5f\x92\xd8\x11\x22\x19\xcb\x10\xa9\xf4\xd2\x06\x23\xa3\xf3\x05\xee\x79\xb6\x4a\x5a\xdc\x6b\xbd\x0d\xf8\x6a\xd6\xcb\x54\xa5\xb3\x2e\xf0\xa6\x5e\x48\x6d\xd2\xca\x2d\x5e\x27\x93\xa3\xc9\xc1\x75\x2b\x59\x2a\x92\x7d\x67\x23\xdb\x48\xe5\x55\xc3\x05\x76\x9d\x3d\x6f\x8c\xd4\x76\x17\xab\xb9\xf4\x81\xe3\xe8\xb4\x3c\xa4\x9d\x6b\xae\xcb\x7b\xce\x9e\x0e\x6c\xe5\x94\xb6\x75\x81\x3b\x33\x1d\x93\x33\x7a\xc7\x96\x7d\x5f\xd0\xd4\xb1\xd2\x11\xb3\x74\x3b\xcd\x44\x72\x46\xbd\xa6\xf7\xab\x09\xef\xf7\xbe\x05\xf6\xc6\x63\x69\xeb\x56\xd6\x4c\x25\xcb\x45\x37\x2e\xd3\x7a\x69\xe8\xd0\xf9\x45\x28\xd0\x36\x2b\x19\x46\xf9\x2e\xf6\xaf\xa3\x2d\x8b\x8f\x46\x98\x3d\xdd\x5d\x7f\x5a\x20\xdb\xe4\x46\xf7\xe3\x96\x96\x06\x97\x32\xdc\xdd\x56\xfe\x0e\x00\x00\xff\xff\x52\x15\x0d\x38\x6a\x04\x00\x00")
func translationsKubectlEn_usLc_messagesK8sMoBytes() ([]byte, error) {
return bindataRead(
_translationsKubectlEn_usLc_messagesK8sMo,
"translations/kubectl/en_US/LC_MESSAGES/k8s.mo",
)
}
func translationsKubectlEn_usLc_messagesK8sMo() (*asset, error) {
bytes, err := translationsKubectlEn_usLc_messagesK8sMoBytes()
if err != nil {
return nil, err
}
info := bindataFileInfo{name: "translations/kubectl/en_US/LC_MESSAGES/k8s.mo", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
var _translationsKubectlEn_usLc_messagesK8sPo = []byte("\x1f\x8b\x08\x00\x00\x09\x6e\x88\x00\xff\xbc\x53\x5d\x4f\xdb\x4a\x10\x7d\xcf\xaf\x98\xeb\xe8\x4a\xa0\x7b\xd7\xb5\x13\x15\x21\xd3\x54\x85\x14\x28\x2a\x88\x28\x98\xaa\x52\x5b\x55\x1b\xef\xc4\xd9\x76\x3d\x6b\xed\x8c\xf9\xf8\xf7\x95\xed\x40\x9a\x4a\x95\x78\x81\xb7\xd9\xd9\x33\x73\xe6\xcc\x9e\x1d\x42\x8e\x2c\x20\x41\x13\x3b\x2d\xd6\x13\xc3\xd2\x07\x68\xc8\x0a\x08\xb2\x70\x3c\x18\xc2\xd4\xd7\xf7\xc1\x96\x2b\x81\x9d\xe9\x2e\x8c\x92\x74\x6f\x30\x84\x7c\x65\x19\x96\xd6\x21\x58\x06\x63\x59\x82\x5d\x34\x82\x06\x1a\x32\x18\x40\x56\x08\xac\x2b\x04\x67\x0b\x24\x46\xd0\xdc\xe5\x66\x87\xd3\x8f\x87\xa7\xc7\x50\xeb\xe2\xa7\x2e\xb1\x6d\x7f\x72\x36\xbf\xca\xe1\xf0\x3a\xff\x70\x39\x87\x45\x40\x32\x9a\x62\x13\x2f\x9a\x40\xfc\xae\xac\xb4\x75\x71\xe1\xab\xff\x3b\xe2\x78\x30\x1c\x54\x5c\x5a\x03\x51\xd4\x06\x2c\xa1\x8d\xa2\x59\xf0\x3f\xb0\x10\x75\x66\xd4\x27\x0c\x6c\x3d\x65\x50\xa2\x08\xde\x89\x2a\xbd\xc2\x3b\x5d\xd5\x0e\x59\xad\xd0\x39\xff\x95\xa2\x41\x34\xc7\xda\x07\x51\x17\x6d\x33\x75\xd4\x94\xac\x72\x9f\x41\x77\x35\xbb\xcc\xd5\x34\x60\xb7\x0f\xf5\x5e\x0b\x66\x2d\xf7\x58\xa5\x23\x95\x8e\x60\x94\x64\xc9\xf8\xbf\x24\x49\x92\x35\x58\xcd\xf1\xc6\xf2\x16\x76\xaf\xc3\x8e\x61\x34\xca\xc6\xaf\x55\xb2\xbf\xc6\x9e\x6b\x16\x95\xaf\x97\xed\x43\x06\x47\xbd\x5a\x38\x6a\xb5\xc2\x9b\xbf\x8a\x7f\xdb\x95\x5f\x9c\x5d\x1c\x6f\xe4\xa5\x71\xdf\x74\xea\x49\x90\x44\xe5\xf7\x35\x66\xd0\x2a\x7e\x55\x3b\x6d\xe9\x00\x8a\x95\x0e\x8c\x32\xb9\xce\x4f\xd4\xfe\x36\xb6\x9d\x61\x89\x41\x1d\x53\xe1\x8d\xa5\x32\x83\xfd\x85\x95\x0e\xf3\x59\x9d\x22\x61\xe8\x07\x9c\x79\x34\x56\x20\x8d\xf7\xe2\x34\x59\x5f\xf7\x39\x75\xe5\x9b\x50\xe0\xb4\xe7\xc8\x60\x43\x72\xae\xa9\x6c\x74\x89\x2a\x47\x5d\x3d\xac\xd4\x35\x41\x3b\x75\xe2\x43\xc5\x19\x50\xdd\x1d\x79\x32\x3a\x80\x3e\x9c\xec\x10\xfc\x33\x81\x74\xf7\x60\xab\x45\x06\x48\x6d\xa2\x7d\xea\x42\xee\x04\xa2\xeb\xda\x68\xc1\xce\x4a\x9a\xc8\xcb\xda\xb4\x9e\x40\x43\x40\xee\x66\x8a\x1e\x2c\xf2\x64\x70\x67\xa3\xa7\xa1\x37\xa3\x44\x83\xe8\x56\x4b\xb1\x6a\x3f\x80\x27\x77\x0f\xdc\xd4\xad\xa7\xd0\xb4\x35\x96\x8c\xbd\xb1\xa6\xd1\xee\xb1\x98\x41\x93\x79\x3c\x41\xe1\x9d\xc3\xa2\x27\x51\x10\x0d\xa2\x7f\xcd\x6f\xd0\x5b\x0c\x08\x4b\xdf\x90\x89\x36\x8e\x7f\x51\xc2\xef\xfd\xd3\xbc\x30\x2f\x4b\xf8\x92\x7c\x7b\x5e\x52\xb8\xd5\xfc\x07\x65\xfa\xcc\x94\xdb\x3a\x7f\x05\x00\x00\xff\xff\x61\x66\xb9\x11\x78\x05\x00\x00")
func translationsKubectlEn_usLc_messagesK8sPoBytes() ([]byte, error) {
return bindataRead(
_translationsKubectlEn_usLc_messagesK8sPo,
"translations/kubectl/en_US/LC_MESSAGES/k8s.po",
)
}
func translationsKubectlEn_usLc_messagesK8sPo() (*asset, error) {
bytes, err := translationsKubectlEn_usLc_messagesK8sPoBytes()
if err != nil {
return nil, err
}
info := bindataFileInfo{name: "translations/kubectl/en_US/LC_MESSAGES/k8s.po", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
var _translationsTestDefaultLc_messagesK8sMo = []byte("\x1f\x8b\x08\x00\x00\x09\x6e\x88\x00\xff\x64\x51\xc1\x6e\x13\x31\x10\x7d\x0d\xe1\xb2\x47\x2e\x5c\x38\x18\xa1\x4a\x20\x34\x8b\x77\x03\x55\xe4\x10\x84\x12\x5a\x54\x94\xa8\x51\x59\x50\x6f\xe0\x64\xa7\x1b\xa3\x5d\x7b\x65\x3b\x50\x3e\x80\x4f\xe0\xc8\x1f\xf0\x4d\x7c\x0b\x4a\x36\xd0\x22\xe6\x60\xbd\x79\x7a\xef\xd9\xe3\xf9\x75\xa7\xff\x1d\x00\x6e\x01\xb8\x07\xe0\x29\x80\xdb\x00\x66\xe8\xea\x23\x80\x07\x00\x34\x80\xbb\x00\xbe\x01\xf8\x79\x00\xfc\x00\x70\x08\xe0\x4d\xaf\xf3\xb6\x3d\xe0\x60\xef\xe9\xed\xf3\x76\x15\x39\xc4\x0f\x6d\xbd\xf1\xba\xee\xdf\xc0\xf8\x0f\x87\xe8\x8d\xad\xfa\x37\x30\x16\xde\x7d\xe2\x55\xa4\xd3\x92\xde\xb3\x0f\xc6\x59\x25\x2a\x8e\x91\xaf\x22\x55\x8e\xf8\x4a\x37\x6d\xcd\x81\xd6\x5c\xd7\x2e\x39\xe7\xd6\xf9\x48\xf3\x50\x99\x92\x26\x9b\x2a\x50\xe1\x94\x48\x16\x67\x05\x4d\x3d\xeb\x68\x9c\xa5\x57\x3a\xb2\x12\xb9\xcc\x06\x94\xe5\x94\xe5\x22\x97\x4a\x0e\x1e\x4b\x29\x65\xb2\x38\xa3\x73\xfe\x6c\xc2\x3f\xba\xa3\x9d\x6e\x20\xf2\x4c\x0d\x9e\x91\x1c\x4a\x99\xcc\x74\x88\x54\x78\x6d\x43\xad\xa3\xf3\x4a\x4c\x3c\xdb\x52\x5b\x31\xd9\x78\x1b\xc4\xf3\x65\xd7\xa6\x65\xba\xdc\x12\x2f\xab\x46\x9b\x3a\x5d\xb9\xe6\x45\x32\x3f\x9d\x1f\x5f\x8f\x92\xa5\x32\x99\x3a\x1b\xd9\x46\x2a\xbe\xb6\xac\xc4\x76\xb2\x27\x6d\xad\x8d\x1d\x89\xd5\x5a\xfb\xc0\x71\xfc\xae\x38\xa1\xe1\xb5\x6e\x7b\xef\x25\x7b\x3a\xb6\x2b\x57\x1a\x5b\x29\x31\x5c\x9a\x98\x5c\xd0\x6b\xb6\xec\xbb\x07\x2d\x1c\x97\x26\x8a\x2c\x3d\x4a\x33\x99\x5c\x50\xd7\xd3\x5b\xb7\xf1\x2b\x9e\x76\xb9\x4a\x74\xc1\x33\x6d\xab\x8d\xae\x98\x0a\xd6\xcd\xf6\xbb\x76\x2b\xa1\x13\xe7\x9b\xa0\x84\xed\x36\x14\xc6\xf9\x48\x74\x70\xfc\xd0\x8a\xfb\x63\x91\x3d\x1a\xfd\xb5\x2a\xc1\x36\x41\x5c\xb3\x67\xf1\x45\x07\x71\x58\x0a\x13\xb9\xf9\xc3\x6c\x8f\x3d\x15\x70\xe9\x1c\x7e\x07\x00\x00\xff\xff\x59\x11\x2e\xef\x74\x02\x00\x00")
func translationsTestDefaultLc_messagesK8sMoBytes() ([]byte, error) {
return bindataRead(
_translationsTestDefaultLc_messagesK8sMo,
"translations/test/default/LC_MESSAGES/k8s.mo",
)
}
func translationsTestDefaultLc_messagesK8sMo() (*asset, error) {
bytes, err := translationsTestDefaultLc_messagesK8sMoBytes()
if err != nil {
return nil, err
}
info := bindataFileInfo{name: "translations/test/default/LC_MESSAGES/k8s.mo", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
var _translationsTestDefaultLc_messagesK8sPo = []byte("\x1f\x8b\x08\x00\x00\x09\x6e\x88\x00\xff\x74\x52\x61\x6f\xd3\x30\x10\xfd\x9e\x5f\x71\xa4\x42\xda\x04\x0e\x49\x2a\xa6\x29\xa3\x88\x2d\xb4\xa3\x62\xd5\xaa\x2e\x43\x48\x80\x90\x9b\x5c\x13\x43\x62\x47\xbe\x0b\x74\xff\x1e\x39\xc9\xa8\xca\xc4\x97\xc8\x7e\xef\xdd\x3d\xbf\xcb\x4d\x20\x43\x62\x60\x2b\x35\xd5\x92\x95\xd1\x04\x3b\x63\xa1\xd3\x8a\x81\x91\x98\x02\x6f\x02\xa9\x69\x1f\xac\x2a\x2b\x86\x93\xf4\x14\xe2\x30\x3a\xf3\x26\x90\x55\x8a\x60\xa7\x6a\x04\x45\x50\x28\x62\xab\xb6\x1d\x63\x01\x9d\x2e\xd0\x02\x57\x08\x24\x1b\x84\x5a\xe5\xa8\x09\x41\x52\x8f\xad\x2f\xd3\x8f\x97\xd7\x73\x68\x65\xfe\x53\x96\xe8\xda\x2f\x96\x9b\xbb\x0c\x2e\xef\xb3\x0f\xb7\x1b\xd8\x5a\xd4\x85\xd4\x41\x11\x6c\x3b\xab\xe9\x5d\xd9\x48\x55\x07\xb9\x69\x5e\xf6\xc6\x81\x37\xf1\x1a\x2a\x55\x01\xbe\xef\x0e\xc4\xd6\x9d\xfc\xb5\x35\x3f\x30\x67\xb1\x2c\xc4\x27\xb4\xa4\x8c\x4e\xa0\x44\x66\xdc\xb3\x28\x8d\xc0\xbd\x6c\xda\x1a\x49\x54\x58\xd7\xe6\xab\xf6\x3d\x7f\x83\xad\xb1\x2c\x56\xae\x99\xb8\xea\x4a\x12\x99\x49\xa0\xa7\xd6\xb7\x99\x48\x2d\xf6\xf3\x10\xef\x25\x63\xe2\xbc\xa7\x22\x8a\x45\x14\x43\x1c\x26\xe1\xf4\x45\x18\x86\xe1\x28\x16\x1b\xfc\xa5\xe8\x48\x7b\xd6\x6b\xa7\x10\x47\xc9\xf4\xb5\x08\xcf\x47\xed\x8d\x24\x16\xd9\x38\x6c\x63\x13\xb8\x1a\xd2\xc2\x95\xcb\x0a\x6f\xfe\x1b\xfe\x6d\x5f\xbe\x5a\xae\xe6\x87\x78\x51\x30\x34\x4d\x8d\x66\xd4\x2c\xb2\x87\x16\x13\x70\x89\x5f\xb5\xb5\x54\xfa\x02\xf2\x4a\x5a\x42\x9e\xdd\x67\x0b\x71\x7e\xac\x75\x6f\xd8\xa1\x15\x73\x9d\x9b\x42\xe9\x32\x81\xf3\xad\xe2\x5e\xf3\x59\x5c\xa3\x46\x3b\x3c\x70\x6d\xb0\x50\x0c\x51\x70\x16\x44\xe1\x48\x0f\x98\xb8\x33\x9d\xcd\x31\x1d\x3c\x12\x38\x98\xdc\x48\x5d\x76\xb2\x44\x91\xa1\x6c\x1e\x47\x5a\x77\x56\xd6\x62\x61\x6c\x43\x09\xe8\xb6\xbf\xd2\x2c\xbe\x80\xe1\x38\x3b\xd1\xf0\x6c\x06\xd1\xe9\xc5\x51\x8b\x04\x50\x3b\xc0\xfd\xea\x9c\xf7\x0c\xbe\x5b\xca\xef\x6e\xd9\x74\xe9\x3f\x6e\xc2\xbf\x58\xbf\x14\x3b\x63\x9e\xd4\x0d\x5e\xc7\x75\x47\xd8\x78\x7b\x4a\x11\xdb\x2f\xe1\x37\xf0\xb9\x42\x8b\xf0\x5b\x12\x3c\x2f\x40\x31\x36\x7f\xd9\xe8\xc0\xba\xcf\x48\x93\xef\xfd\x09\x00\x00\xff\xff\xbf\xc0\xcb\xd2\x64\x03\x00\x00")
func translationsTestDefaultLc_messagesK8sPoBytes() ([]byte, error) {
return bindataRead(
_translationsTestDefaultLc_messagesK8sPo,
"translations/test/default/LC_MESSAGES/k8s.po",
)
}
func translationsTestDefaultLc_messagesK8sPo() (*asset, error) {
bytes, err := translationsTestDefaultLc_messagesK8sPoBytes()
if err != nil {
return nil, err
}
info := bindataFileInfo{name: "translations/test/default/LC_MESSAGES/k8s.po", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
var _translationsTestEn_usLc_messagesK8sMo = []byte("\x1f\x8b\x08\x00\x00\x09\x6e\x88\x00\xff\x64\x51\xc1\x6e\x13\x31\x10\x7d\x0d\xe1\xb2\x47\x2e\x5c\x38\x18\xa1\x4a\x20\x34\x8b\x77\x83\xaa\xc8\x21\x08\x25\xb4\xa8\x28\x51\xa3\xb2\xa0\xde\xc0\xc9\x0e\x1b\xa3\x5d\x7b\x65\x3b\x50\xb8\xf3\x09\x1c\xf9\x03\xbe\x89\x6f\x41\xc9\x06\x5a\xd4\x39\x58\x6f\x9e\xde\x7b\xf6\x78\x7e\xdf\xe9\xff\x00\x80\x5b\x00\xee\x01\x78\x0a\xe0\x36\x80\x19\xba\xfa\x00\xe0\x01\x00\x0d\xe0\x2e\x80\xef\x00\x7e\x1d\x00\x3f\x01\x1c\x02\x78\xdd\xeb\xbc\x6d\x0f\x38\xd8\x7b\x7a\xfb\xbc\x5d\x45\x0e\xf1\x7d\x5b\x6f\xbc\xae\xfb\xd7\x30\x6e\xe0\x10\xbd\xb1\x55\xff\x1a\xc6\xc2\xbb\x4f\xbc\x8a\x74\x5a\xd2\x3b\xf6\xc1\x38\xab\x44\xc5\x31\xf2\x65\xa4\xca\x11\x5f\xea\xa6\xad\x39\xd0\x9a\xeb\xda\x25\xe7\xdc\x3a\x1f\x69\x1e\x2a\x53\xd2\x64\x53\x05\x2a\x9c\x12\xc9\xe2\xac\xa0\xa9\x67\x1d\x8d\xb3\xf4\x52\x47\x56\x22\x97\xd9\x80\xb2\x9c\xb2\x5c\xe4\x52\xc9\xc1\x63\x29\xa5\x4c\x16\x67\x74\xce\x9f\x4d\xf8\x4f\x77\xb4\xd3\x0d\x44\x9e\xab\x2c\x27\x39\x94\x32\x99\xe9\x10\xa9\xf0\xda\x86\x5a\x47\xe7\x95\x98\x78\xb6\xa5\xb6\x62\xb2\xf1\x36\x88\x67\xcb\xae\x4d\xcb\x74\xb9\x25\x5e\x54\x8d\x36\x75\xba\x72\xcd\xf3\x64\x7e\x3a\x3f\xbe\x1a\x25\x4b\x65\x32\x75\x36\xb2\x8d\x54\x7c\x6d\x59\x89\xed\x64\x4f\xda\x5a\x1b\x3b\x12\xab\xb5\xf6\x81\xe3\xf8\x6d\x71\x42\xc3\x2b\xdd\xf6\xde\x8f\xec\xe9\xd8\xae\x5c\x69\x6c\xa5\xc4\x70\x69\x62\x72\x41\xaf\xd8\xb2\xef\x1e\xb4\x70\x5c\x9a\x28\xb2\xf4\x28\xcd\x64\x72\x41\x5d\x4f\x6f\xdc\xc6\xaf\x78\xda\xe5\x2a\xd1\x05\xcf\xb4\xad\x36\xba\x62\x2a\x58\x37\xdb\xef\xda\xad\x84\x4e\x9c\x6f\x82\x12\xb6\xdb\x50\x18\xe7\x23\xd1\xc1\xf1\x43\x2b\xee\x8f\x45\xf6\x68\xf4\xcf\xaa\x04\xdb\x04\x71\xcd\x9e\xc5\x17\x1d\xc4\x61\x29\x4c\xe4\xe6\x2f\xb3\x3d\xf6\x54\xc0\x52\x7f\xc3\x9f\x00\x00\x00\xff\xff\xa9\x73\xeb\x8c\x74\x02\x00\x00")
func translationsTestEn_usLc_messagesK8sMoBytes() ([]byte, error) {
return bindataRead(
_translationsTestEn_usLc_messagesK8sMo,
"translations/test/en_US/LC_MESSAGES/k8s.mo",
)
}
func translationsTestEn_usLc_messagesK8sMo() (*asset, error) {
bytes, err := translationsTestEn_usLc_messagesK8sMoBytes()
if err != nil {
return nil, err
}
info := bindataFileInfo{name: "translations/test/en_US/LC_MESSAGES/k8s.mo", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
var _translationsTestEn_usLc_messagesK8sPo = []byte("\x1f\x8b\x08\x00\x00\x09\x6e\x88\x00\xff\x74\x52\x61\x6f\xd3\x30\x10\xfd\x9e\x5f\x71\xa4\x42\xda\x04\x0e\x49\x26\x4d\x53\x46\x11\x6b\x68\x47\xc5\xaa\x55\x5d\x86\x90\x00\x21\x37\xb9\x26\x86\xc4\x8e\x7c\x17\xe8\xf8\xf5\xc8\x49\x46\x55\x26\xbe\x44\xf6\x7b\xef\xee\xf9\x5d\x6e\x02\x19\x12\x03\x5b\xa9\xa9\x96\xac\x8c\x26\xd8\x19\x0b\x9d\x56\x0c\x8c\xc4\x14\x78\x13\x48\x4d\xfb\x60\x55\x59\x31\x9c\xa4\xa7\x10\x87\xd1\xb9\x37\x81\xac\x52\x04\x3b\x55\x23\x28\x82\x42\x11\x5b\xb5\xed\x18\x0b\xe8\x74\x81\x16\xb8\x42\x20\xd9\x20\xd4\x2a\x47\x4d\x08\x92\x7a\x6c\x7d\x95\x7e\xb8\xba\x9e\x43\x2b\xf3\x1f\xb2\x44\xd7\x7e\xb1\xdc\xdc\x65\x70\x75\x9f\xbd\xbf\xdd\xc0\xd6\xa2\x2e\xa4\x0e\x8a\x60\xdb\x59\x4d\x6f\xcb\x46\xaa\x3a\xc8\x4d\xf3\xb2\x37\x0e\xbc\x89\xd7\x50\xa9\x0a\xf0\x7d\x77\x20\xb6\xee\xe4\xaf\xad\xf9\x8e\x39\x8b\x65\x21\x3e\xa2\x25\x65\x74\x02\x25\x32\xe3\x9e\x45\x69\x04\xee\x65\xd3\xd6\x48\xa2\xc2\xba\x36\x5f\xb4\xef\xf9\x1b\x6c\x8d\x65\xb1\x72\xcd\xc4\xac\x2b\x49\x64\x26\x81\x9e\x5a\xdf\x66\x22\xb5\xd8\xcf\x43\xbc\x93\x8c\x89\xf3\x3e\x13\x51\x2c\xa2\x18\xe2\x30\x09\xcf\x5e\x84\x61\x18\x8e\x62\xb1\xc1\x9f\x8a\x8e\xb4\xe7\xbd\xf6\x0c\xe2\x38\x89\x62\x11\x5e\x8c\xda\x1b\x49\x2c\xb2\x71\xd8\xc6\x26\x30\x1b\xd2\xc2\xcc\x65\x85\xd7\xff\x0d\xff\xa6\x2f\x5f\x2d\x57\xf3\x43\xbc\x28\x18\x9a\xa6\x46\x33\x6a\x16\xd9\x43\x8b\x09\xb8\xc4\xaf\xda\x5a\x2a\x7d\x09\x79\x25\x2d\x21\x4f\xef\xb3\x85\xb8\x38\xd6\xba\x37\xec\xd0\x8a\xb9\xce\x4d\xa1\x74\x99\xc0\xc5\x56\x71\xaf\xf9\x24\xae\x51\xa3\x1d\x1e\xb8\x36\x58\x28\x86\x28\x38\x0f\xa2\x70\xa4\x07\x4c\xdc\x99\xce\xe6\x98\x0e\x1e\x09\x1c\x4c\x6e\xa4\x2e\x3b\x59\xa2\xc8\x50\x36\x8f\x23\xad\x3b\x2b\x6b\xb1\x30\xb6\xa1\x04\x74\xdb\x5f\x69\x1a\x5f\xc2\x70\x9c\x9e\x68\x78\x36\x85\xe8\xf4\xf2\xa8\x45\x02\xa8\x1d\xe0\x7e\x75\xce\x7b\x06\xdf\x2d\xe5\x37\xb7\x6c\xba\xf4\x1f\x37\xe1\x5f\xac\x5f\x8a\xad\xfc\xfd\xa4\x6e\xf0\x3a\xae\x3b\xc2\xc6\xdb\x53\x8a\xd8\x7e\x0e\xbf\x82\xcf\x15\x5a\x84\x5f\x92\xe0\x79\x01\x8a\xb1\xf9\xcb\x46\x07\xd6\x7d\x46\x9a\x7c\xef\x4f\x00\x00\x00\xff\xff\x03\xfe\xb1\xf0\x64\x03\x00\x00")
func translationsTestEn_usLc_messagesK8sPoBytes() ([]byte, error) {
return bindataRead(
_translationsTestEn_usLc_messagesK8sPo,
"translations/test/en_US/LC_MESSAGES/k8s.po",
)
}
func translationsTestEn_usLc_messagesK8sPo() (*asset, error) {
bytes, err := translationsTestEn_usLc_messagesK8sPoBytes()
if err != nil {
return nil, err
}
info := bindataFileInfo{name: "translations/test/en_US/LC_MESSAGES/k8s.po", size: 0, mode: os.FileMode(0), modTime: time.Unix(0, 0)}
a := &asset{bytes: bytes, info: info}
return a, nil
}
// Asset loads and returns the asset for the given name.
// It returns an error if the asset could not be found or
// could not be loaded.
func Asset(name string) ([]byte, error) {
cannonicalName := strings.Replace(name, "\\", "/", -1)
if f, ok := _bindata[cannonicalName]; ok {
a, err := f()
if err != nil {
return nil, fmt.Errorf("Asset %s can't read by error: %v", name, err)
}
return a.bytes, nil
}
return nil, fmt.Errorf("Asset %s not found", name)
}
// MustAsset is like Asset but panics when Asset would return an error.
// It simplifies safe initialization of global variables.
func MustAsset(name string) []byte {
a, err := Asset(name)
if err != nil {
panic("asset: Asset(" + name + "): " + err.Error())
}
return a
}
// AssetInfo loads and returns the asset info for the given name.
// It returns an error if the asset could not be found or
// could not be loaded.
func AssetInfo(name string) (os.FileInfo, error) {
cannonicalName := strings.Replace(name, "\\", "/", -1)
if f, ok := _bindata[cannonicalName]; ok {
a, err := f()
if err != nil {
return nil, fmt.Errorf("AssetInfo %s can't read by error: %v", name, err)
}
return a.info, nil
}
return nil, fmt.Errorf("AssetInfo %s not found", name)
}
// AssetNames returns the names of the assets.
func AssetNames() []string {
names := make([]string, 0, len(_bindata))
for name := range _bindata {
names = append(names, name)
}
return names
}
// _bindata is a table, holding each asset generator, mapped to its name.
var _bindata = map[string]func() (*asset, error){
"translations/kubectl/default/LC_MESSAGES/k8s.mo": translationsKubectlDefaultLc_messagesK8sMo,
"translations/kubectl/default/LC_MESSAGES/k8s.po": translationsKubectlDefaultLc_messagesK8sPo,
"translations/kubectl/en_US/LC_MESSAGES/k8s.mo": translationsKubectlEn_usLc_messagesK8sMo,
"translations/kubectl/en_US/LC_MESSAGES/k8s.po": translationsKubectlEn_usLc_messagesK8sPo,
"translations/test/default/LC_MESSAGES/k8s.mo": translationsTestDefaultLc_messagesK8sMo,
"translations/test/default/LC_MESSAGES/k8s.po": translationsTestDefaultLc_messagesK8sPo,
"translations/test/en_US/LC_MESSAGES/k8s.mo": translationsTestEn_usLc_messagesK8sMo,
"translations/test/en_US/LC_MESSAGES/k8s.po": translationsTestEn_usLc_messagesK8sPo,
}
// AssetDir returns the file names below a certain
// directory embedded in the file by go-bindata.
// For example if you run go-bindata on data/... and data contains the
// following hierarchy:
// data/
// foo.txt
// img/
// a.png
// b.png
// then AssetDir("data") would return []string{"foo.txt", "img"}
// AssetDir("data/img") would return []string{"a.png", "b.png"}
// AssetDir("foo.txt") and AssetDir("notexist") would return an error
// AssetDir("") will return []string{"data"}.
func AssetDir(name string) ([]string, error) {
node := _bintree
if len(name) != 0 {
cannonicalName := strings.Replace(name, "\\", "/", -1)
pathList := strings.Split(cannonicalName, "/")
for _, p := range pathList {
node = node.Children[p]
if node == nil {
return nil, fmt.Errorf("Asset %s not found", name)
}
}
}
if node.Func != nil {
return nil, fmt.Errorf("Asset %s not found", name)
}
rv := make([]string, 0, len(node.Children))
for childName := range node.Children {
rv = append(rv, childName)
}
return rv, nil
}
type bintree struct {
Func func() (*asset, error)
Children map[string]*bintree
}
var _bintree = &bintree{nil, map[string]*bintree{
"translations": {nil, map[string]*bintree{
"kubectl": {nil, map[string]*bintree{
"default": {nil, map[string]*bintree{
"LC_MESSAGES": {nil, map[string]*bintree{
"k8s.mo": {translationsKubectlDefaultLc_messagesK8sMo, map[string]*bintree{}},
"k8s.po": {translationsKubectlDefaultLc_messagesK8sPo, map[string]*bintree{}},
}},
}},
"en_US": {nil, map[string]*bintree{
"LC_MESSAGES": {nil, map[string]*bintree{
"k8s.mo": {translationsKubectlEn_usLc_messagesK8sMo, map[string]*bintree{}},
"k8s.po": {translationsKubectlEn_usLc_messagesK8sPo, map[string]*bintree{}},
}},
}},
}},
"test": {nil, map[string]*bintree{
"default": {nil, map[string]*bintree{
"LC_MESSAGES": {nil, map[string]*bintree{
"k8s.mo": {translationsTestDefaultLc_messagesK8sMo, map[string]*bintree{}},
"k8s.po": {translationsTestDefaultLc_messagesK8sPo, map[string]*bintree{}},
}},
}},
"en_US": {nil, map[string]*bintree{
"LC_MESSAGES": {nil, map[string]*bintree{
"k8s.mo": {translationsTestEn_usLc_messagesK8sMo, map[string]*bintree{}},
"k8s.po": {translationsTestEn_usLc_messagesK8sPo, map[string]*bintree{}},
}},
}},
}},
}},
}}
// RestoreAsset restores an asset under the given directory
func RestoreAsset(dir, name string) error {
data, err := Asset(name)
if err != nil {
return err
}
info, err := AssetInfo(name)
if err != nil {
return err
}
err = os.MkdirAll(_filePath(dir, filepath.Dir(name)), os.FileMode(0755))
if err != nil {
return err
}
err = ioutil.WriteFile(_filePath(dir, name), data, info.Mode())
if err != nil {
return err
}
err = os.Chtimes(_filePath(dir, name), info.ModTime(), info.ModTime())
if err != nil {
return err
}
return nil
}
// RestoreAssets restores an asset under the given directory recursively
func RestoreAssets(dir, name string) error {
children, err := AssetDir(name)
// File
if err != nil {
return RestoreAsset(dir, name)
}
// Dir
for _, child := range children {
err = RestoreAssets(dir, filepath.Join(name, child))
if err != nil {
return err
}
}
return nil
}
func _filePath(dir, name string) string {
cannonicalName := strings.Replace(name, "\\", "/", -1)
return filepath.Join(append([]string{dir}, strings.Split(cannonicalName, "/")...)...)
}

View File

@ -102,6 +102,7 @@ go_library(
"//pkg/util/errors:go_default_library",
"//pkg/util/exec:go_default_library",
"//pkg/util/flag:go_default_library",
"//pkg/util/i18n:go_default_library",
"//pkg/util/interrupt:go_default_library",
"//pkg/util/intstr:go_default_library",
"//pkg/util/sets:go_default_library",

View File

@ -31,6 +31,7 @@ import (
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
"k8s.io/kubernetes/pkg/kubectl/resource"
"k8s.io/kubernetes/pkg/runtime"
"k8s.io/kubernetes/pkg/util/i18n"
"k8s.io/kubernetes/pkg/util/strategicpatch"
)
@ -107,7 +108,7 @@ func NewCmdAnnotate(f cmdutil.Factory, out io.Writer) *cobra.Command {
cmd := &cobra.Command{
Use: "annotate [--overwrite] (-f FILENAME | TYPE NAME) KEY_1=VAL_1 ... KEY_N=VAL_N [--resource-version=version]",
Short: "Update the annotations on a resource",
Short: i18n.T("Update the annotations on a resource"),
Long: annotate_long,
Example: annotate_example,
Run: func(cmd *cobra.Command, args []string) {

View File

@ -27,6 +27,7 @@ import (
"k8s.io/kubernetes/pkg/kubectl/cmd/templates"
cmdutil "k8s.io/kubernetes/pkg/kubectl/cmd/util"
"k8s.io/kubernetes/pkg/util/flag"
"k8s.io/kubernetes/pkg/util/i18n"
"github.com/golang/glog"
"github.com/spf13/cobra"
@ -223,6 +224,13 @@ func NewKubectlCommand(f cmdutil.Factory, in io.Reader, out, err io.Writer) *cob
f.BindFlags(cmds.PersistentFlags())
f.BindExternalFlags(cmds.PersistentFlags())
// Sending in 'nil' for the getLanguageFn() results in using
// the LANG environment variable.
//
// TODO: Consider adding a flag or file preference for setting
// the language, instead of just loading from the LANG env. variable.
i18n.LoadTranslations("kubectl", nil)
// From this point and forward we get warnings on flags that contain "_" separators
cmds.SetGlobalNormalizationFunc(flag.WarnWordSepNormalizeFunc)

View File

@ -31,6 +31,7 @@ import (
"k8s.io/kubernetes/pkg/kubectl/resource"
"k8s.io/kubernetes/pkg/runtime"
utilerrors "k8s.io/kubernetes/pkg/util/errors"
"k8s.io/kubernetes/pkg/util/i18n"
"k8s.io/kubernetes/pkg/util/interrupt"
"k8s.io/kubernetes/pkg/util/sets"
"k8s.io/kubernetes/pkg/watch"
@ -213,7 +214,7 @@ func RunGet(f cmdutil.Factory, out, errOut io.Writer, cmd *cobra.Command, args [
return err
}
if len(infos) != 1 {
return fmt.Errorf("watch is only supported on individual resources and resource collections - %d resources were found", len(infos))
return i18n.Errorf("watch is only supported on individual resources and resource collections - %d resources were found", len(infos))
}
info := infos[0]
mapping := info.ResourceMapping()

28
pkg/util/i18n/BUILD Normal file
View File

@ -0,0 +1,28 @@
package(default_visibility = ["//visibility:public"])
licenses(["notice"])
load(
"@io_bazel_rules_go//go:def.bzl",
"go_library",
"go_test",
)
go_library(
name = "go_default_library",
srcs = ["i18n.go"],
tags = ["automanaged"],
deps = [
"//pkg/generated:go_default_library",
"//vendor:github.com/chai2010/gettext-go/gettext",
"//vendor:github.com/golang/glog",
],
)
go_test(
name = "go_default_test",
srcs = ["i18n_test.go"],
library = "go_default_library",
tags = ["automanaged"],
deps = [],
)

133
pkg/util/i18n/i18n.go Normal file
View File

@ -0,0 +1,133 @@
/*
Copyright 2016 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package i18n
import (
"archive/zip"
"bytes"
"errors"
"fmt"
"os"
"strings"
"k8s.io/kubernetes/pkg/generated"
"github.com/chai2010/gettext-go/gettext"
"github.com/golang/glog"
)
var knownTranslations = map[string][]string{
"kubectl": {
"default",
"en_US",
},
// only used for unit tests.
"test": {
"default",
"en_US",
},
}
func loadSystemLanguage() string {
langStr := os.Getenv("LANG")
if langStr == "" {
glog.V(3).Infof("Couldn't find the LANG environment variable, defaulting to en-US")
return "default"
}
pieces := strings.Split(langStr, ".")
if len(pieces) == 0 {
glog.V(3).Infof("Unexpected system language (%s), defaulting to en-US", langStr)
return "default"
}
return pieces[0]
}
func findLanguage(root string, getLanguageFn func() string) string {
langStr := getLanguageFn()
translations := knownTranslations[root]
if translations != nil {
for ix := range translations {
if translations[ix] == langStr {
return langStr
}
}
}
glog.V(3).Infof("Couldn't find translations for %s, using default", langStr)
return "default"
}
// LoadTranslations loads translation files. getLanguageFn should return a language
// string (e.g. 'en-US'). If getLanguageFn is nil, then the loadSystemLanguage function
// is used, which uses the 'LANG' environment variable.
func LoadTranslations(root string, getLanguageFn func() string) error {
if getLanguageFn == nil {
getLanguageFn = loadSystemLanguage
}
langStr := findLanguage(root, getLanguageFn)
translationFiles := []string{
fmt.Sprintf("%s/%s/LC_MESSAGES/k8s.po", root, langStr),
fmt.Sprintf("%s/%s/LC_MESSAGES/k8s.mo", root, langStr),
}
glog.V(3).Infof("Setting language to %s", langStr)
// TODO: list the directory and load all files.
buf := new(bytes.Buffer)
w := zip.NewWriter(buf)
// Make sure to check the error on Close.
for _, file := range translationFiles {
filename := "translations/" + file
f, err := w.Create(file)
if err != nil {
return err
}
data, err := generated.Asset(filename)
if err != nil {
return err
}
if _, err := f.Write(data); err != nil {
return nil
}
}
if err := w.Close(); err != nil {
return err
}
gettext.BindTextdomain("k8s", root+".zip", buf.Bytes())
gettext.Textdomain("k8s")
gettext.SetLocale(langStr)
return nil
}
// T translates a string, possibly substituting arguments into it along
// the way. If len(args) is > 0, args1 is assumed to be the plural value
// and plural translation is used.
func T(defaultValue string, args ...int) string {
if len(args) == 0 {
return gettext.PGettext(defaultValue, defaultValue)
}
return fmt.Sprintf(gettext.PNGettext(defaultValue, defaultValue, defaultValue+".plural", args[0]),
args[0])
}
// Errorf produces an error with a translated error string.
// Substitution is performed via the `T` function above, following
// the same rules.
func Errorf(defaultValue string, args ...int) error {
return errors.New(T(defaultValue, args...))
}

View File

@ -0,0 +1,64 @@
/*
Copyright 2016 The Kubernetes Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package i18n
import (
"os"
"testing"
)
func TestTranslation(t *testing.T) {
err := LoadTranslations("test", func() string { return "default" })
if err != nil {
t.Errorf("Unexpected error: %v", err)
}
result := T("test_string")
if result != "foo" {
t.Errorf("expected: %s, saw: %s", "foo", result)
}
}
func TestTranslationPlural(t *testing.T) {
err := LoadTranslations("test", func() string { return "default" })
if err != nil {
t.Errorf("Unexpected error: %v", err)
}
result := T("test_plural", 3)
if result != "there were 3 items" {
t.Errorf("expected: %s, saw: %s", "there were 3 items", result)
}
result = T("test_plural", 1)
if result != "there was 1 item" {
t.Errorf("expected: %s, saw: %s", "there was 1 item", result)
}
}
func TestTranslationEnUSEnv(t *testing.T) {
os.Setenv("LANG", "en_US.UTF-8")
err := LoadTranslations("test", nil)
if err != nil {
t.Errorf("Unexpected error: %v", err)
}
result := T("test_string")
if result != "baz" {
t.Errorf("expected: %s, saw: %s", "baz", result)
}
}

View File

@ -63,7 +63,7 @@ Density create a batch of pods latency/resource should be within limit when crea
Density create a batch of pods with higher API QPS latency/resource should be within limit when create * pods with * interval (QPS *),jlowdermilk,1
Density create a sequence of pods latency/resource should be within limit when create * pods with * background pods,wojtek-t,1
Density should allow running maximum capacity pods on nodes,smarterclayton,1
Density should allow starting * pods per node using * with * secrets,derekwaynecarr,0
Density should allow starting * pods per node using * with * secrets,brendandburns,0
Deployment RecreateDeployment should delete old pods and create new ones,pwittrock,0
Deployment RollingUpdateDeployment should delete old pods and create new ones,pwittrock,0
Deployment deployment reaping should cascade to its replica sets and pods,wojtek-t,1
@ -278,7 +278,7 @@ KubeletManagedEtcHosts should test kubelet managed /etc/hosts file,Random-Liu,1
Kubernetes Dashboard should check that the kubernetes-dashboard instance is alive,wonderfly,0
LimitRange should create a LimitRange with defaults and ensure pod has those defaults applied.,cjcullen,1
Liveness liveness pods should be automatically restarted,derekwaynecarr,0
Load capacity should be able to handle * pods per node * with * secrets,derekwaynecarr,0
Load capacity should be able to handle * pods per node * with * secrets,brendandburns,0
Loadbalancing: L7 GCE shoud create ingress with given static-ip,derekwaynecarr,0
Loadbalancing: L7 GCE should conform to Ingress spec,derekwaynecarr,0
Loadbalancing: L7 Nginx should conform to Ingress spec,ncdc,1
@ -306,7 +306,7 @@ Network Partition Pods should return to running and ready state after network pa
Network Partition should come back up if node goes down,foxish,0
Network Partition should create new pods when node is partitioned,foxish,0
Network Partition should eagerly create replacement pod during network partition when termination grace is non-zero,foxish,0
Network Partition should not reschedule stateful pods if there is a network partition,foxish,0
Network Partition should not reschedule stateful pods if there is a network partition,brendandburns,0
Network should set TCP CLOSE_WAIT timeout,bowei,0
Networking Granular Checks: Pods should function for intra-pod communication: http,stts,0
Networking Granular Checks: Pods should function for intra-pod communication: udp,freehan,0
@ -471,13 +471,14 @@ SimpleMount should be able to mount an emptydir on a container,rrati,0
"Spark should start spark master, driver and workers",jszczepkowski,1
"Staging client repo client should create pods, delete pods, watch pods",jbeda,1
StatefulSet Basic StatefulSet functionality Scaling down before scale up is finished should wait until current pod will be running and ready before it will be removed,derekwaynecarr,0
StatefulSet Basic StatefulSet functionality Scaling should happen in predictable order and halt if any stateful pod is unhealthy,derekwaynecarr,0
StatefulSet Basic StatefulSet functionality Should recreate evicted statefulset,rrati,0
StatefulSet Basic StatefulSet functionality Scaling should happen in predictable order and halt if any stateful pod is unhealthy,brendandburns,0
StatefulSet Basic StatefulSet functionality Should recreate evicted statefulset,brendandburns,0
StatefulSet Basic StatefulSet functionality should allow template updates,derekwaynecarr,0
StatefulSet Basic StatefulSet functionality should handle healthy stateful pod restarts during scale,kevin-wangzefeng,1
StatefulSet Basic StatefulSet functionality Scaling should happen in predictable order and halt if any pet is unhealthy,rkouj,0
StatefulSet Basic StatefulSet functionality should allow template updates,rkouj,0
StatefulSet Basic StatefulSet functionality should handle healthy pet restarts during scale,girishkalele,1
StatefulSet Basic StatefulSet functionality should handle healthy stateful pod restarts during scale,brendandburns,0
StatefulSet Basic StatefulSet functionality should provide basic identity,bprashanth,1
StatefulSet Deploy clustered applications should creating a working CockroachDB cluster,rkouj,0
StatefulSet Deploy clustered applications should creating a working mysql cluster,yujuhong,1
@ -511,7 +512,7 @@ k8s.io/kubernetes/cmd/kube-apiserver/app/options,nikhiljindal,0
k8s.io/kubernetes/cmd/kube-discovery/app,pmorie,1
k8s.io/kubernetes/cmd/kube-proxy/app,luxas,1
k8s.io/kubernetes/cmd/kubeadm/app/cmd,caesarxuchao,1
k8s.io/kubernetes/cmd/kubeadm/app/discovery,rrati,0
k8s.io/kubernetes/cmd/kubeadm/app/discovery,brendandburns,0
k8s.io/kubernetes/cmd/kubeadm/app/images,davidopp,1
k8s.io/kubernetes/cmd/kubeadm/app/master,apprenda,0
k8s.io/kubernetes/cmd/kubeadm/app/node,apprenda,0
@ -519,7 +520,7 @@ k8s.io/kubernetes/cmd/kubeadm/app/preflight,apprenda,0
k8s.io/kubernetes/cmd/kubeadm/app/util,krousey,1
k8s.io/kubernetes/cmd/kubeadm/test,pipejakob,0
k8s.io/kubernetes/cmd/kubelet/app,derekwaynecarr,0
k8s.io/kubernetes/cmd/kubernetes-discovery/pkg/apiserver,deads2k,0
k8s.io/kubernetes/cmd/kubernetes-discovery/pkg/apiserver,brendandburns,0
k8s.io/kubernetes/cmd/libs/go2idl/client-gen/types,caesarxuchao,0
k8s.io/kubernetes/cmd/libs/go2idl/go-to-protobuf/protobuf,smarterclayton,0
k8s.io/kubernetes/cmd/libs/go2idl/openapi-gen/generators,davidopp,1
@ -530,7 +531,7 @@ k8s.io/kubernetes/federation/apis/federation/validation,nikhiljindal,0
k8s.io/kubernetes/federation/cmd/federation-controller-manager/app,kzwang,0
k8s.io/kubernetes/federation/pkg/dnsprovider,sttts,1
k8s.io/kubernetes/federation/pkg/dnsprovider/providers/aws/route53,cjcullen,1
k8s.io/kubernetes/federation/pkg/dnsprovider/providers/coredns,quinton-hoole,0
k8s.io/kubernetes/federation/pkg/dnsprovider/providers/coredns,brendandburns,0
k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns,jsafrane,1
k8s.io/kubernetes/federation/pkg/federation-controller/cluster,nikhiljindal,0
k8s.io/kubernetes/federation/pkg/federation-controller/configmap,mwielgus,0
@ -662,7 +663,7 @@ k8s.io/kubernetes/pkg/conversion,ixdy,1
k8s.io/kubernetes/pkg/conversion/queryparams,caesarxuchao,1
k8s.io/kubernetes/pkg/credentialprovider,justinsb,1
k8s.io/kubernetes/pkg/credentialprovider/aws,zmerlynn,1
k8s.io/kubernetes/pkg/credentialprovider/azure,brendandburns,1
k8s.io/kubernetes/pkg/credentialprovider/azure,brendandburns,0
k8s.io/kubernetes/pkg/credentialprovider/gcp,mml,1
k8s.io/kubernetes/pkg/dns,rrati,0
k8s.io/kubernetes/pkg/dns/config,derekwaynecarr,0
@ -857,6 +858,7 @@ k8s.io/kubernetes/pkg/util/goroutinemap,saad-ali,0
k8s.io/kubernetes/pkg/util/hash,timothysc,1
k8s.io/kubernetes/pkg/util/httpstream,apelisse,1
k8s.io/kubernetes/pkg/util/httpstream/spdy,zmerlynn,1
k8s.io/kubernetes/pkg/util/i18n,brendandburns,0
k8s.io/kubernetes/pkg/util/integer,childsb,1
k8s.io/kubernetes/pkg/util/intstr,brendandburns,1
k8s.io/kubernetes/pkg/util/io,mtaufen,1
@ -970,7 +972,7 @@ k8s.io/kubernetes/test/integration/auth,jbeda,1
k8s.io/kubernetes/test/integration/client,Q-Lee,1
k8s.io/kubernetes/test/integration/configmap,Q-Lee,1
k8s.io/kubernetes/test/integration/discoverysummarizer,fabioy,1
k8s.io/kubernetes/test/integration/evictions,wojtek-t,1
k8s.io/kubernetes/test/integration/evictions,brendandburns,0
k8s.io/kubernetes/test/integration/examples,maisem,1
k8s.io/kubernetes/test/integration/federation,rrati,0
k8s.io/kubernetes/test/integration/garbagecollector,jlowdermilk,1

1 name owner auto-assigned
63 Density create a batch of pods with higher API QPS latency/resource should be within limit when create * pods with * interval (QPS *) jlowdermilk 1
64 Density create a sequence of pods latency/resource should be within limit when create * pods with * background pods wojtek-t 1
65 Density should allow running maximum capacity pods on nodes smarterclayton 1
66 Density should allow starting * pods per node using * with * secrets derekwaynecarr brendandburns 0
67 Deployment RecreateDeployment should delete old pods and create new ones pwittrock 0
68 Deployment RollingUpdateDeployment should delete old pods and create new ones pwittrock 0
69 Deployment deployment reaping should cascade to its replica sets and pods wojtek-t 1
278 Kubernetes Dashboard should check that the kubernetes-dashboard instance is alive wonderfly 0
279 LimitRange should create a LimitRange with defaults and ensure pod has those defaults applied. cjcullen 1
280 Liveness liveness pods should be automatically restarted derekwaynecarr 0
281 Load capacity should be able to handle * pods per node * with * secrets derekwaynecarr brendandburns 0
282 Loadbalancing: L7 GCE shoud create ingress with given static-ip derekwaynecarr 0
283 Loadbalancing: L7 GCE should conform to Ingress spec derekwaynecarr 0
284 Loadbalancing: L7 Nginx should conform to Ingress spec ncdc 1
306 Network Partition should come back up if node goes down foxish 0
307 Network Partition should create new pods when node is partitioned foxish 0
308 Network Partition should eagerly create replacement pod during network partition when termination grace is non-zero foxish 0
309 Network Partition should not reschedule stateful pods if there is a network partition foxish brendandburns 0
310 Network should set TCP CLOSE_WAIT timeout bowei 0
311 Networking Granular Checks: Pods should function for intra-pod communication: http stts 0
312 Networking Granular Checks: Pods should function for intra-pod communication: udp freehan 0
471 Spark should start spark master, driver and workers jszczepkowski 1
472 Staging client repo client should create pods, delete pods, watch pods jbeda 1
473 StatefulSet Basic StatefulSet functionality Scaling down before scale up is finished should wait until current pod will be running and ready before it will be removed derekwaynecarr 0
474 StatefulSet Basic StatefulSet functionality Scaling should happen in predictable order and halt if any stateful pod is unhealthy derekwaynecarr brendandburns 0
475 StatefulSet Basic StatefulSet functionality Should recreate evicted statefulset rrati brendandburns 0
476 StatefulSet Basic StatefulSet functionality should allow template updates derekwaynecarr 0
477 StatefulSet Basic StatefulSet functionality should handle healthy stateful pod restarts during scale kevin-wangzefeng 1
478 StatefulSet Basic StatefulSet functionality Scaling should happen in predictable order and halt if any pet is unhealthy rkouj 0
479 StatefulSet Basic StatefulSet functionality should allow template updates rkouj 0
480 StatefulSet Basic StatefulSet functionality should handle healthy pet restarts during scale girishkalele 1
481 StatefulSet Basic StatefulSet functionality should handle healthy stateful pod restarts during scale brendandburns 0
482 StatefulSet Basic StatefulSet functionality should provide basic identity bprashanth 1
483 StatefulSet Deploy clustered applications should creating a working CockroachDB cluster rkouj 0
484 StatefulSet Deploy clustered applications should creating a working mysql cluster yujuhong 1
512 k8s.io/kubernetes/cmd/kube-discovery/app pmorie 1
513 k8s.io/kubernetes/cmd/kube-proxy/app luxas 1
514 k8s.io/kubernetes/cmd/kubeadm/app/cmd caesarxuchao 1
515 k8s.io/kubernetes/cmd/kubeadm/app/discovery rrati brendandburns 0
516 k8s.io/kubernetes/cmd/kubeadm/app/images davidopp 1
517 k8s.io/kubernetes/cmd/kubeadm/app/master apprenda 0
518 k8s.io/kubernetes/cmd/kubeadm/app/node apprenda 0
520 k8s.io/kubernetes/cmd/kubeadm/app/util krousey 1
521 k8s.io/kubernetes/cmd/kubeadm/test pipejakob 0
522 k8s.io/kubernetes/cmd/kubelet/app derekwaynecarr 0
523 k8s.io/kubernetes/cmd/kubernetes-discovery/pkg/apiserver deads2k brendandburns 0
524 k8s.io/kubernetes/cmd/libs/go2idl/client-gen/types caesarxuchao 0
525 k8s.io/kubernetes/cmd/libs/go2idl/go-to-protobuf/protobuf smarterclayton 0
526 k8s.io/kubernetes/cmd/libs/go2idl/openapi-gen/generators davidopp 1
531 k8s.io/kubernetes/federation/cmd/federation-controller-manager/app kzwang 0
532 k8s.io/kubernetes/federation/pkg/dnsprovider sttts 1
533 k8s.io/kubernetes/federation/pkg/dnsprovider/providers/aws/route53 cjcullen 1
534 k8s.io/kubernetes/federation/pkg/dnsprovider/providers/coredns quinton-hoole brendandburns 0
535 k8s.io/kubernetes/federation/pkg/dnsprovider/providers/google/clouddns jsafrane 1
536 k8s.io/kubernetes/federation/pkg/federation-controller/cluster nikhiljindal 0
537 k8s.io/kubernetes/federation/pkg/federation-controller/configmap mwielgus 0
663 k8s.io/kubernetes/pkg/conversion/queryparams caesarxuchao 1
664 k8s.io/kubernetes/pkg/credentialprovider justinsb 1
665 k8s.io/kubernetes/pkg/credentialprovider/aws zmerlynn 1
666 k8s.io/kubernetes/pkg/credentialprovider/azure brendandburns 1 0
667 k8s.io/kubernetes/pkg/credentialprovider/gcp mml 1
668 k8s.io/kubernetes/pkg/dns rrati 0
669 k8s.io/kubernetes/pkg/dns/config derekwaynecarr 0
858 k8s.io/kubernetes/pkg/util/hash timothysc 1
859 k8s.io/kubernetes/pkg/util/httpstream apelisse 1
860 k8s.io/kubernetes/pkg/util/httpstream/spdy zmerlynn 1
861 k8s.io/kubernetes/pkg/util/i18n brendandburns 0
862 k8s.io/kubernetes/pkg/util/integer childsb 1
863 k8s.io/kubernetes/pkg/util/intstr brendandburns 1
864 k8s.io/kubernetes/pkg/util/io mtaufen 1
972 k8s.io/kubernetes/test/integration/client Q-Lee 1
973 k8s.io/kubernetes/test/integration/configmap Q-Lee 1
974 k8s.io/kubernetes/test/integration/discoverysummarizer fabioy 1
975 k8s.io/kubernetes/test/integration/evictions wojtek-t brendandburns 1 0
976 k8s.io/kubernetes/test/integration/examples maisem 1
977 k8s.io/kubernetes/test/integration/federation rrati 0
978 k8s.io/kubernetes/test/integration/garbagecollector jlowdermilk 1

47
translations/README.md Normal file
View File

@ -0,0 +1,47 @@
# Translations README
This is a basic sketch of the workflow needed to add translations:
# Adding/Updating Translations
## New languages
Create `translations/kubectl/<language>/LC_MESSAGES/k8s.po`. There's
no need to update `translations/test/...` which is only used for unit tests.
Move on to Adding new translations
## Adding new translations
Edit the appropriate `k8s.po` file, `poedit` is a popular open source tool
for translations.
Once you are done with your `.po` file, generate the corresponding `k8s.mo`
file. `poedit` does this automatically on save.
We use the English translation as both the `msg_id` and the `msg_context`.
## Regenerating the bindata file
Run `./hack/generate-bindata.sh, this will turn the translation files
into generated code which will in turn be packaged into the Kubernetes
binaries.
# Using translations
To use translations, you simply need to add:
```go
import pkg/i18n
...
// Get a translated string
translated := i18n.T("Your message in english here")
// Get a translated plural string
translated := i18n.T("You had % items", items)
// Translated error
return i18n.Error("Something bad happened")
// Translated plural error
return i18n.Error("%d bad things happened")
```
[![Analytics](https://kubernetes-site.appspot.com/UA-36037335-10/GitHub/translations/README.md?pixel)]()

Binary file not shown.

View File

@ -0,0 +1,40 @@
# Test translations for unit tests.
# Copyright (C) 2016
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR brendan.d.burns@gmail.com, 2016.
#
msgid ""
msgstr ""
"Project-Id-Version: gettext-go-examples-hello\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2013-12-12 20:03+0000\n"
"PO-Revision-Date: 2016-12-13 21:54-0800\n"
"Last-Translator: Brendan Burns <brendan.d.burns@gmail.com>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Generator: Poedit 1.6.10\n"
"X-Poedit-SourceCharset: UTF-8\n"
"Language-Team: \n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
"Language: en\n"
msgctxt "Update the annotations on a resource"
msgid "Update the annotations on a resource"
msgstr "Update the annotations on a resource"
msgctxt ""
"watch is only supported on individual resources and resource collections - "
"%d resources were found"
msgid ""
"watch is only supported on individual resources and resource collections - "
"%d resources were found"
msgid_plural ""
"watch is only supported on individual resources and resource collections - "
"%d resources were found"
msgstr[0] ""
"watch is only supported on individual resources and resource collections - "
"%d resource was found"
msgstr[1] ""
"watch is only supported on individual resources and resource collections - "
"%d resources were found"

Binary file not shown.

View File

@ -0,0 +1,40 @@
# Test translations for unit tests.
# Copyright (C) 2016
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR brendan.d.burns@gmail.com, 2016.
#
msgid ""
msgstr ""
"Project-Id-Version: gettext-go-examples-hello\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2013-12-12 20:03+0000\n"
"PO-Revision-Date: 2016-12-13 22:35-0800\n"
"Last-Translator: Brendan Burns <brendan.d.burns@gmail.com>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Generator: Poedit 1.6.10\n"
"X-Poedit-SourceCharset: UTF-8\n"
"Language-Team: \n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
"Language: en\n"
msgctxt "Update the annotations on a resource"
msgid "Update the annotations on a resource"
msgstr "Update the annotations on a resource"
msgctxt ""
"watch is only supported on individual resources and resource collections - "
"%d resources were found"
msgid ""
"watch is only supported on individual resources and resource collections - "
"%d resources were found"
msgid_plural ""
"watch is only supported on individual resources and resource collections - "
"%d resources were found"
msgstr[0] ""
"watch is only supported on individual resources and resource collections - "
"%d resource was found"
msgstr[1] ""
"watch is only supported on individual resources and resource collections - "
"%d resources were found"

Binary file not shown.

View File

@ -0,0 +1,30 @@
# Test translations for unit tests.
# Copyright (C) 2016
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR brendan.d.burns@gmail.com, 2016.
#
msgid ""
msgstr ""
"Project-Id-Version: gettext-go-examples-hello\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2013-12-12 20:03+0000\n"
"PO-Revision-Date: 2016-12-13 21:35-0800\n"
"Last-Translator: Brendan Burns <brendan.d.burns@gmail.com>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Generator: Poedit 1.6.10\n"
"X-Poedit-SourceCharset: UTF-8\n"
"Language-Team: \n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
"Language: en\n"
msgctxt "test_string"
msgid "test_string"
msgstr "foo"
msgctxt "test_plural"
msgid "test_plural"
msgid_plural "test_plural"
msgstr[0] "there was %d item"
msgstr[1] "there were %d items"

Binary file not shown.

View File

@ -0,0 +1,30 @@
# Test translations for unit tests.
# Copyright (C) 2016
# This file is distributed under the same license as the PACKAGE package.
# FIRST AUTHOR brendan.d.burns@gmail.com, 2016.
#
msgid ""
msgstr ""
"Project-Id-Version: gettext-go-examples-hello\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2013-12-12 20:03+0000\n"
"PO-Revision-Date: 2016-12-13 22:12-0800\n"
"Last-Translator: Brendan Burns <brendan.d.burns@gmail.com>\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"X-Generator: Poedit 1.6.10\n"
"X-Poedit-SourceCharset: UTF-8\n"
"Language-Team: \n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
"Language: en\n"
msgctxt "test_string"
msgid "test_string"
msgstr "baz"
msgctxt "test_plural"
msgid "test_plural"
msgid_plural "test_plural"
msgstr[0] "there was %d item"
msgstr[1] "there were %d items"

58
vendor/BUILD vendored
View File

@ -802,6 +802,64 @@ go_library(
tags = ["automanaged"],
)
go_library(
name = "github.com/chai2010/gettext-go/gettext",
srcs = [
"github.com/chai2010/gettext-go/gettext/caller.go",
"github.com/chai2010/gettext-go/gettext/doc.go",
"github.com/chai2010/gettext-go/gettext/domain.go",
"github.com/chai2010/gettext-go/gettext/domain_helper.go",
"github.com/chai2010/gettext-go/gettext/fs.go",
"github.com/chai2010/gettext-go/gettext/gettext.go",
"github.com/chai2010/gettext-go/gettext/local.go",
"github.com/chai2010/gettext-go/gettext/tr.go",
],
tags = ["automanaged"],
deps = [
"//vendor:github.com/chai2010/gettext-go/gettext/mo",
"//vendor:github.com/chai2010/gettext-go/gettext/plural",
"//vendor:github.com/chai2010/gettext-go/gettext/po",
],
)
go_library(
name = "github.com/chai2010/gettext-go/gettext/mo",
srcs = [
"github.com/chai2010/gettext-go/gettext/mo/doc.go",
"github.com/chai2010/gettext-go/gettext/mo/encoder.go",
"github.com/chai2010/gettext-go/gettext/mo/file.go",
"github.com/chai2010/gettext-go/gettext/mo/header.go",
"github.com/chai2010/gettext-go/gettext/mo/message.go",
"github.com/chai2010/gettext-go/gettext/mo/util.go",
],
tags = ["automanaged"],
)
go_library(
name = "github.com/chai2010/gettext-go/gettext/plural",
srcs = [
"github.com/chai2010/gettext-go/gettext/plural/doc.go",
"github.com/chai2010/gettext-go/gettext/plural/formula.go",
"github.com/chai2010/gettext-go/gettext/plural/table.go",
],
tags = ["automanaged"],
)
go_library(
name = "github.com/chai2010/gettext-go/gettext/po",
srcs = [
"github.com/chai2010/gettext-go/gettext/po/comment.go",
"github.com/chai2010/gettext-go/gettext/po/doc.go",
"github.com/chai2010/gettext-go/gettext/po/file.go",
"github.com/chai2010/gettext-go/gettext/po/header.go",
"github.com/chai2010/gettext-go/gettext/po/line_reader.go",
"github.com/chai2010/gettext-go/gettext/po/message.go",
"github.com/chai2010/gettext-go/gettext/po/re.go",
"github.com/chai2010/gettext-go/gettext/po/util.go",
],
tags = ["automanaged"],
)
go_library(
name = "github.com/cloudflare/cfssl/auth",
srcs = ["github.com/cloudflare/cfssl/auth/auth.go"],

27
vendor/github.com/chai2010/gettext-go/LICENSE generated vendored Normal file
View File

@ -0,0 +1,27 @@
Copyright 2013 ChaiShushan <chaishushan{AT}gmail.com>. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are
met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following disclaimer
in the documentation and/or other materials provided with the
distribution.
* Neither the name of Google Inc. nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@ -0,0 +1,39 @@
// Copyright 2013 ChaiShushan <chaishushan{AT}gmail.com>. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package gettext
import (
"regexp"
"runtime"
)
var (
reInit = regexp.MustCompile(`init·\d+$`) // main.init·1
reClosure = regexp.MustCompile(`func·\d+$`) // main.func·001
)
// caller types:
// runtime.goexit
// runtime.main
// main.init
// main.main
// main.init·1 -> main.init
// main.func·001 -> main.func
// code.google.com/p/gettext-go/gettext.TestCallerName
// ...
func callerName(skip int) string {
pc, _, _, ok := runtime.Caller(skip)
if !ok {
return ""
}
name := runtime.FuncForPC(pc).Name()
if reInit.MatchString(name) {
return reInit.ReplaceAllString(name, "init")
}
if reClosure.MatchString(name) {
return reClosure.ReplaceAllString(name, "func")
}
return name
}

66
vendor/github.com/chai2010/gettext-go/gettext/doc.go generated vendored Normal file
View File

@ -0,0 +1,66 @@
// Copyright 2013 <chaishushan{AT}gmail.com>. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
/*
Package gettext implements a basic GNU's gettext library.
Example:
import (
"github.com/chai2010/gettext-go/gettext"
)
func main() {
gettext.SetLocale("zh_CN")
gettext.Textdomain("hello")
// gettext.BindTextdomain("hello", "local", nil) // from local dir
// gettext.BindTextdomain("hello", "local.zip", nil) // from local zip file
// gettext.BindTextdomain("hello", "local.zip", zipData) // from embedded zip data
gettext.BindTextdomain("hello", "local", nil)
// translate source text
fmt.Println(gettext.Gettext("Hello, world!"))
// Output: 你好, 世界!
// translate resource
fmt.Println(string(gettext.Getdata("poems.txt")))
// Output: ...
}
Translate directory struct("../examples/local.zip"):
Root: "path" or "file.zip/zipBaseName"
+-default # local: $(LC_MESSAGES) or $(LANG) or "default"
| +-LC_MESSAGES # just for `gettext.Gettext`
| | +-hello.mo # $(Root)/$(local)/LC_MESSAGES/$(domain).mo
| | \-hello.po # $(Root)/$(local)/LC_MESSAGES/$(domain).mo
| |
| \-LC_RESOURCE # just for `gettext.Getdata`
| +-hello # domain map a dir in resource translate
| +-favicon.ico # $(Root)/$(local)/LC_RESOURCE/$(domain)/$(filename)
| \-poems.txt
|
\-zh_CN # simple chinese translate
+-LC_MESSAGES
| +-hello.mo # try "$(domain).mo" first
| \-hello.po # try "$(domain).po" second
|
\-LC_RESOURCE
+-hello
+-favicon.ico # try "$(local)/$(domain)/file" first
\-poems.txt # try "default/$(domain)/file" second
See:
http://en.wikipedia.org/wiki/Gettext
http://www.gnu.org/software/gettext/manual/html_node
http://www.gnu.org/software/gettext/manual/html_node/Header-Entry.html
http://www.gnu.org/software/gettext/manual/html_node/PO-Files.html
http://www.gnu.org/software/gettext/manual/html_node/MO-Files.html
http://www.poedit.net/
Please report bugs to <chaishushan{AT}gmail.com>.
Thanks!
*/
package gettext

119
vendor/github.com/chai2010/gettext-go/gettext/domain.go generated vendored Normal file
View File

@ -0,0 +1,119 @@
// Copyright 2013 ChaiShushan <chaishushan{AT}gmail.com>. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package gettext
import (
"sync"
)
type domainManager struct {
mutex sync.Mutex
locale string
domain string
domainMap map[string]*fileSystem
trTextMap map[string]*translator
}
func newDomainManager() *domainManager {
return &domainManager{
locale: DefaultLocale,
domainMap: make(map[string]*fileSystem),
trTextMap: make(map[string]*translator),
}
}
func (p *domainManager) makeTrMapKey(domain, locale string) string {
return domain + "_$$$_" + locale
}
func (p *domainManager) Bind(domain, path string, data []byte) (domains, paths []string) {
p.mutex.Lock()
defer p.mutex.Unlock()
switch {
case domain != "" && path != "": // bind new domain
p.bindDomainTranslators(domain, path, data)
case domain != "" && path == "": // delete domain
p.deleteDomain(domain)
}
// return all bind domain
for k, fs := range p.domainMap {
domains = append(domains, k)
paths = append(paths, fs.FsName)
}
return
}
func (p *domainManager) SetLocale(locale string) string {
p.mutex.Lock()
defer p.mutex.Unlock()
if locale != "" {
p.locale = locale
}
return p.locale
}
func (p *domainManager) SetDomain(domain string) string {
p.mutex.Lock()
defer p.mutex.Unlock()
if domain != "" {
p.domain = domain
}
return p.domain
}
func (p *domainManager) Getdata(name string) []byte {
return p.getdata(p.domain, name)
}
func (p *domainManager) DGetdata(domain, name string) []byte {
return p.getdata(domain, name)
}
func (p *domainManager) PNGettext(msgctxt, msgid, msgidPlural string, n int) string {
p.mutex.Lock()
defer p.mutex.Unlock()
return p.gettext(p.domain, msgctxt, msgid, msgidPlural, n)
}
func (p *domainManager) DPNGettext(domain, msgctxt, msgid, msgidPlural string, n int) string {
p.mutex.Lock()
defer p.mutex.Unlock()
return p.gettext(domain, msgctxt, msgid, msgidPlural, n)
}
func (p *domainManager) gettext(domain, msgctxt, msgid, msgidPlural string, n int) string {
if p.locale == "" || p.domain == "" {
return msgid
}
if _, ok := p.domainMap[domain]; !ok {
return msgid
}
if f, ok := p.trTextMap[p.makeTrMapKey(domain, p.locale)]; ok {
return f.PNGettext(msgctxt, msgid, msgidPlural, n)
}
return msgid
}
func (p *domainManager) getdata(domain, name string) []byte {
if p.locale == "" || p.domain == "" {
return nil
}
if _, ok := p.domainMap[domain]; !ok {
return nil
}
if fs, ok := p.domainMap[domain]; ok {
if data, err := fs.LoadResourceFile(domain, p.locale, name); err == nil {
return data
}
if p.locale != "default" {
if data, err := fs.LoadResourceFile(domain, "default", name); err == nil {
return data
}
}
}
return nil
}

View File

@ -0,0 +1,50 @@
// Copyright 2013 ChaiShushan <chaishushan{AT}gmail.com>. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package gettext
import (
"fmt"
"strings"
)
func (p *domainManager) bindDomainTranslators(domain, path string, data []byte) {
if _, ok := p.domainMap[domain]; ok {
p.deleteDomain(domain) // delete old domain
}
fs := newFileSystem(path, data)
for locale, _ := range fs.LocaleMap {
trMapKey := p.makeTrMapKey(domain, locale)
if data, err := fs.LoadMessagesFile(domain, locale, ".mo"); err == nil {
p.trTextMap[trMapKey], _ = newMoTranslator(
fmt.Sprintf("%s_%s.mo", domain, locale),
data,
)
continue
}
if data, err := fs.LoadMessagesFile(domain, locale, ".po"); err == nil {
p.trTextMap[trMapKey], _ = newPoTranslator(
fmt.Sprintf("%s_%s.po", domain, locale),
data,
)
continue
}
p.trTextMap[p.makeTrMapKey(domain, locale)] = nilTranslator
}
p.domainMap[domain] = fs
}
func (p *domainManager) deleteDomain(domain string) {
if _, ok := p.domainMap[domain]; !ok {
return
}
// delete all mo files
trMapKeyPrefix := p.makeTrMapKey(domain, "")
for k, _ := range p.trTextMap {
if strings.HasPrefix(k, trMapKeyPrefix) {
delete(p.trTextMap, k)
}
}
delete(p.domainMap, domain)
}

187
vendor/github.com/chai2010/gettext-go/gettext/fs.go generated vendored Normal file
View File

@ -0,0 +1,187 @@
// Copyright 2013 ChaiShushan <chaishushan{AT}gmail.com>. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package gettext
import (
"archive/zip"
"bytes"
"fmt"
"io/ioutil"
"log"
"os"
"strings"
)
type fileSystem struct {
FsName string
FsRoot string
FsZipData []byte
LocaleMap map[string]bool
}
func newFileSystem(path string, data []byte) *fileSystem {
fs := &fileSystem{
FsName: path,
FsZipData: data,
}
if err := fs.init(); err != nil {
log.Printf("gettext-go: invalid domain, err = %v", err)
}
return fs
}
func (p *fileSystem) init() error {
zipName := func(name string) string {
if x := strings.LastIndexAny(name, `\/`); x != -1 {
name = name[x+1:]
}
name = strings.TrimSuffix(name, ".zip")
return name
}
// zip data
if len(p.FsZipData) != 0 {
p.FsRoot = zipName(p.FsName)
p.LocaleMap = p.lsZip(p.FsZipData)
return nil
}
// local dir or zip file
fi, err := os.Stat(p.FsName)
if err != nil {
return err
}
// local dir
if fi.IsDir() {
p.FsRoot = p.FsName
p.LocaleMap = p.lsDir(p.FsName)
return nil
}
// local zip file
p.FsZipData, err = ioutil.ReadFile(p.FsName)
if err != nil {
return err
}
p.FsRoot = zipName(p.FsName)
p.LocaleMap = p.lsZip(p.FsZipData)
return nil
}
func (p *fileSystem) LoadMessagesFile(domain, local, ext string) ([]byte, error) {
if len(p.FsZipData) == 0 {
trName := p.makeMessagesFileName(domain, local, ext)
rcData, err := ioutil.ReadFile(trName)
if err != nil {
return nil, err
}
return rcData, nil
} else {
r, err := zip.NewReader(bytes.NewReader(p.FsZipData), int64(len(p.FsZipData)))
if err != nil {
return nil, err
}
trName := p.makeMessagesFileName(domain, local, ext)
for _, f := range r.File {
if f.Name != trName {
continue
}
rc, err := f.Open()
if err != nil {
return nil, err
}
rcData, err := ioutil.ReadAll(rc)
rc.Close()
return rcData, err
}
return nil, fmt.Errorf("not found")
}
}
func (p *fileSystem) LoadResourceFile(domain, local, name string) ([]byte, error) {
if len(p.FsZipData) == 0 {
rcName := p.makeResourceFileName(domain, local, name)
rcData, err := ioutil.ReadFile(rcName)
if err != nil {
return nil, err
}
return rcData, nil
} else {
r, err := zip.NewReader(bytes.NewReader(p.FsZipData), int64(len(p.FsZipData)))
if err != nil {
return nil, err
}
rcName := p.makeResourceFileName(domain, local, name)
for _, f := range r.File {
if f.Name != rcName {
continue
}
rc, err := f.Open()
if err != nil {
return nil, err
}
rcData, err := ioutil.ReadAll(rc)
rc.Close()
return rcData, err
}
return nil, fmt.Errorf("not found")
}
}
func (p *fileSystem) makeMessagesFileName(domain, local, ext string) string {
return fmt.Sprintf("%s/%s/LC_MESSAGES/%s%s", p.FsRoot, local, domain, ext)
}
func (p *fileSystem) makeResourceFileName(domain, local, name string) string {
return fmt.Sprintf("%s/%s/LC_RESOURCE/%s/%s", p.FsRoot, local, domain, name)
}
func (p *fileSystem) lsZip(data []byte) map[string]bool {
r, err := zip.NewReader(bytes.NewReader(data), int64(len(data)))
if err != nil {
return nil
}
ssMap := make(map[string]bool)
for _, f := range r.File {
if x := strings.Index(f.Name, "LC_MESSAGES"); x != -1 {
s := strings.TrimRight(f.Name[:x], `\/`)
if x = strings.LastIndexAny(s, `\/`); x != -1 {
s = s[x+1:]
}
if s != "" {
ssMap[s] = true
}
continue
}
if x := strings.Index(f.Name, "LC_RESOURCE"); x != -1 {
s := strings.TrimRight(f.Name[:x], `\/`)
if x = strings.LastIndexAny(s, `\/`); x != -1 {
s = s[x+1:]
}
if s != "" {
ssMap[s] = true
}
continue
}
}
return ssMap
}
func (p *fileSystem) lsDir(path string) map[string]bool {
list, err := ioutil.ReadDir(path)
if err != nil {
return nil
}
ssMap := make(map[string]bool)
for _, dir := range list {
if dir.IsDir() {
ssMap[dir.Name()] = true
}
}
return ssMap
}

View File

@ -0,0 +1,184 @@
// Copyright 2013 ChaiShushan <chaishushan{AT}gmail.com>. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package gettext
var (
defaultManager = newDomainManager()
)
var (
DefaultLocale = getDefaultLocale() // use $(LC_MESSAGES) or $(LANG) or "default"
)
// SetLocale sets and queries the program's current locale.
//
// If the locale is not empty string, set the new local.
//
// If the locale is empty string, don't change anything.
//
// Returns is the current locale.
//
// Examples:
// SetLocale("") // get locale: return DefaultLocale
// SetLocale("zh_CN") // set locale: return zh_CN
// SetLocale("") // get locale: return zh_CN
func SetLocale(locale string) string {
return defaultManager.SetLocale(locale)
}
// BindTextdomain sets and queries program's domains.
//
// If the domain and path are all not empty string, bind the new domain.
// If the domain already exists, return error.
//
// If the domain is not empty string, but the path is the empty string,
// delete the domain.
// If the domain don't exists, return error.
//
// If the domain and the path are all empty string, don't change anything.
//
// Returns is the all bind domains.
//
// Examples:
// BindTextdomain("poedit", "local", nil) // bind "poedit" domain
// BindTextdomain("", "", nil) // return all domains
// BindTextdomain("poedit", "", nil) // delete "poedit" domain
// BindTextdomain("", "", nil) // return all domains
//
// Use zip file:
// BindTextdomain("poedit", "local.zip", nil) // bind "poedit" domain
// BindTextdomain("poedit", "local.zip", zipData) // bind "poedit" domain
//
func BindTextdomain(domain, path string, zipData []byte) (domains, paths []string) {
return defaultManager.Bind(domain, path, zipData)
}
// Textdomain sets and retrieves the current message domain.
//
// If the domain is not empty string, set the new domains.
//
// If the domain is empty string, don't change anything.
//
// Returns is the all used domains.
//
// Examples:
// Textdomain("poedit") // set domain: poedit
// Textdomain("") // get domain: return poedit
func Textdomain(domain string) string {
return defaultManager.SetDomain(domain)
}
// Gettext attempt to translate a text string into the user's native language,
// by looking up the translation in a message catalog.
//
// It use the caller's function name as the msgctxt.
//
// Examples:
// func Foo() {
// msg := gettext.Gettext("Hello") // msgctxt is "some/package/name.Foo"
// }
func Gettext(msgid string) string {
return PGettext(callerName(2), msgid)
}
// Getdata attempt to translate a resource file into the user's native language,
// by looking up the translation in a message catalog.
//
// Examples:
// func Foo() {
// Textdomain("hello")
// BindTextdomain("hello", "local.zip", nilOrZipData)
// poems := gettext.Getdata("poems.txt")
// }
func Getdata(name string) []byte {
return defaultManager.Getdata(name)
}
// NGettext attempt to translate a text string into the user's native language,
// by looking up the appropriate plural form of the translation in a message
// catalog.
//
// It use the caller's function name as the msgctxt.
//
// Examples:
// func Foo() {
// msg := gettext.NGettext("%d people", "%d peoples", 2)
// }
func NGettext(msgid, msgidPlural string, n int) string {
return PNGettext(callerName(2), msgid, msgidPlural, n)
}
// PGettext attempt to translate a text string into the user's native language,
// by looking up the translation in a message catalog.
//
// Examples:
// func Foo() {
// msg := gettext.PGettext("gettext-go.example", "Hello") // msgctxt is "gettext-go.example"
// }
func PGettext(msgctxt, msgid string) string {
return PNGettext(msgctxt, msgid, "", 0)
}
// PNGettext attempt to translate a text string into the user's native language,
// by looking up the appropriate plural form of the translation in a message
// catalog.
//
// Examples:
// func Foo() {
// msg := gettext.PNGettext("gettext-go.example", "%d people", "%d peoples", 2)
// }
func PNGettext(msgctxt, msgid, msgidPlural string, n int) string {
return defaultManager.PNGettext(msgctxt, msgid, msgidPlural, n)
}
// DGettext like Gettext(), but looking up the message in the specified domain.
//
// Examples:
// func Foo() {
// msg := gettext.DGettext("poedit", "Hello")
// }
func DGettext(domain, msgid string) string {
return DPGettext(domain, callerName(2), msgid)
}
// DNGettext like NGettext(), but looking up the message in the specified domain.
//
// Examples:
// func Foo() {
// msg := gettext.PNGettext("poedit", "gettext-go.example", "%d people", "%d peoples", 2)
// }
func DNGettext(domain, msgid, msgidPlural string, n int) string {
return DPNGettext(domain, callerName(2), msgid, msgidPlural, n)
}
// DPGettext like PGettext(), but looking up the message in the specified domain.
//
// Examples:
// func Foo() {
// msg := gettext.DPGettext("poedit", "gettext-go.example", "Hello")
// }
func DPGettext(domain, msgctxt, msgid string) string {
return DPNGettext(domain, msgctxt, msgid, "", 0)
}
// DPNGettext like PNGettext(), but looking up the message in the specified domain.
//
// Examples:
// func Foo() {
// msg := gettext.DPNGettext("poedit", "gettext-go.example", "%d people", "%d peoples", 2)
// }
func DPNGettext(domain, msgctxt, msgid, msgidPlural string, n int) string {
return defaultManager.DPNGettext(domain, msgctxt, msgid, msgidPlural, n)
}
// DGetdata like Getdata(), but looking up the resource in the specified domain.
//
// Examples:
// func Foo() {
// msg := gettext.DGetdata("hello", "poems.txt")
// }
func DGetdata(domain, name string) []byte {
return defaultManager.DGetdata(domain, name)
}

22
vendor/github.com/chai2010/gettext-go/gettext/hello.go generated vendored Normal file
View File

@ -0,0 +1,22 @@
// Copyright 2013 <chaishushan{AT}gmail.com>. 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 (
"fmt"
"github.com/chai2010/gettext-go"
)
func main() {
gettext.SetLocale("zh_CN")
gettext.BindTextdomain("hello", "../examples/local", nil)
gettext.Textdomain("hello")
fmt.Println(gettext.Gettext("Hello, world!"))
// Output: 你好, 世界!
}

34
vendor/github.com/chai2010/gettext-go/gettext/local.go generated vendored Normal file
View File

@ -0,0 +1,34 @@
// Copyright 2013 ChaiShushan <chaishushan{AT}gmail.com>. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package gettext
import (
"os"
"strings"
)
func getDefaultLocale() string {
if v := os.Getenv("LC_MESSAGES"); v != "" {
return simplifiedLocale(v)
}
if v := os.Getenv("LANG"); v != "" {
return simplifiedLocale(v)
}
return "default"
}
func simplifiedLocale(lang string) string {
// en_US/en_US.UTF-8/zh_CN/zh_TW/el_GR@euro/...
if idx := strings.Index(lang, ":"); idx != -1 {
lang = lang[:idx]
}
if idx := strings.Index(lang, "@"); idx != -1 {
lang = lang[:idx]
}
if idx := strings.Index(lang, "."); idx != -1 {
lang = lang[:idx]
}
return strings.TrimSpace(lang)
}

View File

@ -0,0 +1,74 @@
// Copyright 2013 ChaiShushan <chaishushan{AT}gmail.com>. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
/*
Package mo provides support for reading and writing GNU MO file.
Examples:
import (
"github.com/chai2010/gettext-go/gettext/mo"
)
func main() {
moFile, err := mo.Load("test.mo")
if err != nil {
log.Fatal(err)
}
fmt.Printf("%v", moFile)
}
GNU MO file struct:
byte
+------------------------------------------+
0 | magic number = 0x950412de |
| |
4 | file format revision = 0 |
| |
8 | number of strings | == N
| |
12 | offset of table with original strings | == O
| |
16 | offset of table with translation strings | == T
| |
20 | size of hashing table | == S
| |
24 | offset of hashing table | == H
| |
. .
. (possibly more entries later) .
. .
| |
O | length & offset 0th string ----------------.
O + 8 | length & offset 1st string ------------------.
... ... | |
O + ((N-1)*8)| length & offset (N-1)th string | | |
| | | |
T | length & offset 0th translation ---------------.
T + 8 | length & offset 1st translation -----------------.
... ... | | | |
T + ((N-1)*8)| length & offset (N-1)th translation | | | | |
| | | | | |
H | start hash table | | | | |
... ... | | | |
H + S * 4 | end hash table | | | | |
| | | | | |
| NUL terminated 0th string <----------------' | | |
| | | | |
| NUL terminated 1st string <------------------' | |
| | | |
... ... | |
| | | |
| NUL terminated 0th translation <---------------' |
| | |
| NUL terminated 1st translation <-----------------'
| |
... ...
| |
+------------------------------------------+
The GNU MO file specification is at
http://www.gnu.org/software/gettext/manual/html_node/MO-Files.html.
*/
package mo

View File

@ -0,0 +1,124 @@
// Copyright 2013 ChaiShushan <chaishushan{AT}gmail.com>. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package mo
import (
"bytes"
"encoding/binary"
"sort"
"strings"
)
type moHeader struct {
MagicNumber uint32
MajorVersion uint16
MinorVersion uint16
MsgIdCount uint32
MsgIdOffset uint32
MsgStrOffset uint32
HashSize uint32
HashOffset uint32
}
type moStrPos struct {
Size uint32 // must keep fields order
Addr uint32
}
func encodeFile(f *File) []byte {
hdr := &moHeader{
MagicNumber: MoMagicLittleEndian,
}
data := encodeData(hdr, f)
data = append(encodeHeader(hdr), data...)
return data
}
// encode data and init moHeader
func encodeData(hdr *moHeader, f *File) []byte {
msgList := []Message{f.MimeHeader.toMessage()}
for _, v := range f.Messages {
if len(v.MsgId) == 0 {
continue
}
if len(v.MsgStr) == 0 && len(v.MsgStrPlural) == 0 {
continue
}
msgList = append(msgList, v)
}
sort.Sort(byMessages(msgList))
var buf bytes.Buffer
var msgIdPosList = make([]moStrPos, len(msgList))
var msgStrPosList = make([]moStrPos, len(msgList))
for i, v := range msgList {
// write msgid
msgId := encodeMsgId(v)
msgIdPosList[i].Addr = uint32(buf.Len() + MoHeaderSize)
msgIdPosList[i].Size = uint32(len(msgId))
buf.WriteString(msgId)
// write msgstr
msgStr := encodeMsgStr(v)
msgStrPosList[i].Addr = uint32(buf.Len() + MoHeaderSize)
msgStrPosList[i].Size = uint32(len(msgStr))
buf.WriteString(msgStr)
}
hdr.MsgIdOffset = uint32(buf.Len() + MoHeaderSize)
binary.Write(&buf, binary.LittleEndian, msgIdPosList)
hdr.MsgStrOffset = uint32(buf.Len() + MoHeaderSize)
binary.Write(&buf, binary.LittleEndian, msgStrPosList)
hdr.MsgIdCount = uint32(len(msgList))
return buf.Bytes()
}
// must called after encodeData
func encodeHeader(hdr *moHeader) []byte {
var buf bytes.Buffer
binary.Write(&buf, binary.LittleEndian, hdr)
return buf.Bytes()
}
func encodeMsgId(v Message) string {
if v.MsgContext != "" && v.MsgIdPlural != "" {
return v.MsgContext + EotSeparator + v.MsgId + NulSeparator + v.MsgIdPlural
}
if v.MsgContext != "" && v.MsgIdPlural == "" {
return v.MsgContext + EotSeparator + v.MsgId
}
if v.MsgContext == "" && v.MsgIdPlural != "" {
return v.MsgId + NulSeparator + v.MsgIdPlural
}
return v.MsgId
}
func encodeMsgStr(v Message) string {
if v.MsgIdPlural != "" {
return strings.Join(v.MsgStrPlural, NulSeparator)
}
return v.MsgStr
}
type byMessages []Message
func (d byMessages) Len() int {
return len(d)
}
func (d byMessages) Less(i, j int) bool {
if a, b := d[i].MsgContext, d[j].MsgContext; a != b {
return a < b
}
if a, b := d[i].MsgId, d[j].MsgId; a != b {
return a < b
}
if a, b := d[i].MsgIdPlural, d[j].MsgIdPlural; a != b {
return a < b
}
return false
}
func (d byMessages) Swap(i, j int) {
d[i], d[j] = d[j], d[i]
}

View File

@ -0,0 +1,193 @@
// Copyright 2013 ChaiShushan <chaishushan{AT}gmail.com>. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package mo
import (
"bytes"
"encoding/binary"
"fmt"
"io/ioutil"
"strings"
)
const (
MoHeaderSize = 28
MoMagicLittleEndian = 0x950412de
MoMagicBigEndian = 0xde120495
EotSeparator = "\x04" // msgctxt and msgid separator
NulSeparator = "\x00" // msgid and msgstr separator
)
// File represents an MO File.
//
// See http://www.gnu.org/software/gettext/manual/html_node/MO-Files.html
type File struct {
MagicNumber uint32
MajorVersion uint16
MinorVersion uint16
MsgIdCount uint32
MsgIdOffset uint32
MsgStrOffset uint32
HashSize uint32
HashOffset uint32
MimeHeader Header
Messages []Message
}
// Load loads a named mo file.
func Load(name string) (*File, error) {
data, err := ioutil.ReadFile(name)
if err != nil {
return nil, err
}
return LoadData(data)
}
// LoadData loads mo file format data.
func LoadData(data []byte) (*File, error) {
r := bytes.NewReader(data)
var magicNumber uint32
if err := binary.Read(r, binary.LittleEndian, &magicNumber); err != nil {
return nil, fmt.Errorf("gettext: %v", err)
}
var bo binary.ByteOrder
switch magicNumber {
case MoMagicLittleEndian:
bo = binary.LittleEndian
case MoMagicBigEndian:
bo = binary.BigEndian
default:
return nil, fmt.Errorf("gettext: %v", "invalid magic number")
}
var header struct {
MajorVersion uint16
MinorVersion uint16
MsgIdCount uint32
MsgIdOffset uint32
MsgStrOffset uint32
HashSize uint32
HashOffset uint32
}
if err := binary.Read(r, bo, &header); err != nil {
return nil, fmt.Errorf("gettext: %v", err)
}
if v := header.MajorVersion; v != 0 && v != 1 {
return nil, fmt.Errorf("gettext: %v", "invalid version number")
}
if v := header.MinorVersion; v != 0 && v != 1 {
return nil, fmt.Errorf("gettext: %v", "invalid version number")
}
msgIdStart := make([]uint32, header.MsgIdCount)
msgIdLen := make([]uint32, header.MsgIdCount)
if _, err := r.Seek(int64(header.MsgIdOffset), 0); err != nil {
return nil, fmt.Errorf("gettext: %v", err)
}
for i := 0; i < int(header.MsgIdCount); i++ {
if err := binary.Read(r, bo, &msgIdLen[i]); err != nil {
return nil, fmt.Errorf("gettext: %v", err)
}
if err := binary.Read(r, bo, &msgIdStart[i]); err != nil {
return nil, fmt.Errorf("gettext: %v", err)
}
}
msgStrStart := make([]int32, header.MsgIdCount)
msgStrLen := make([]int32, header.MsgIdCount)
if _, err := r.Seek(int64(header.MsgStrOffset), 0); err != nil {
return nil, fmt.Errorf("gettext: %v", err)
}
for i := 0; i < int(header.MsgIdCount); i++ {
if err := binary.Read(r, bo, &msgStrLen[i]); err != nil {
return nil, fmt.Errorf("gettext: %v", err)
}
if err := binary.Read(r, bo, &msgStrStart[i]); err != nil {
return nil, fmt.Errorf("gettext: %v", err)
}
}
file := &File{
MagicNumber: magicNumber,
MajorVersion: header.MajorVersion,
MinorVersion: header.MinorVersion,
MsgIdCount: header.MsgIdCount,
MsgIdOffset: header.MsgIdOffset,
MsgStrOffset: header.MsgStrOffset,
HashSize: header.HashSize,
HashOffset: header.HashOffset,
}
for i := 0; i < int(header.MsgIdCount); i++ {
if _, err := r.Seek(int64(msgIdStart[i]), 0); err != nil {
return nil, fmt.Errorf("gettext: %v", err)
}
msgIdData := make([]byte, msgIdLen[i])
if _, err := r.Read(msgIdData); err != nil {
return nil, fmt.Errorf("gettext: %v", err)
}
if _, err := r.Seek(int64(msgStrStart[i]), 0); err != nil {
return nil, fmt.Errorf("gettext: %v", err)
}
msgStrData := make([]byte, msgStrLen[i])
if _, err := r.Read(msgStrData); err != nil {
return nil, fmt.Errorf("gettext: %v", err)
}
if len(msgIdData) == 0 {
var msg = Message{
MsgId: string(msgIdData),
MsgStr: string(msgStrData),
}
file.MimeHeader.fromMessage(&msg)
} else {
var msg = Message{
MsgId: string(msgIdData),
MsgStr: string(msgStrData),
}
// Is this a context message?
if idx := strings.Index(msg.MsgId, EotSeparator); idx != -1 {
msg.MsgContext, msg.MsgId = msg.MsgId[:idx], msg.MsgId[idx+1:]
}
// Is this a plural message?
if idx := strings.Index(msg.MsgId, NulSeparator); idx != -1 {
msg.MsgId, msg.MsgIdPlural = msg.MsgId[:idx], msg.MsgId[idx+1:]
msg.MsgStrPlural = strings.Split(msg.MsgStr, NulSeparator)
msg.MsgStr = ""
}
file.Messages = append(file.Messages, msg)
}
}
return file, nil
}
// Save saves a mo file.
func (f *File) Save(name string) error {
return ioutil.WriteFile(name, f.Data(), 0666)
}
// Save returns a mo file format data.
func (f *File) Data() []byte {
return encodeFile(f)
}
// String returns the po format file string.
func (f *File) String() string {
var buf bytes.Buffer
fmt.Fprintf(&buf, "# version: %d.%d\n", f.MajorVersion, f.MinorVersion)
fmt.Fprintf(&buf, "%s\n", f.MimeHeader.String())
fmt.Fprintf(&buf, "\n")
for k, v := range f.Messages {
fmt.Fprintf(&buf, `msgid "%v"`+"\n", k)
fmt.Fprintf(&buf, `msgstr "%s"`+"\n", v.MsgStr)
fmt.Fprintf(&buf, "\n")
}
return buf.String()
}

View File

@ -0,0 +1,109 @@
// Copyright 2013 ChaiShushan <chaishushan{AT}gmail.com>. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package mo
import (
"bytes"
"fmt"
"strings"
)
// Header is the initial comments "SOME DESCRIPTIVE TITLE", "YEAR"
// and "FIRST AUTHOR <EMAIL@ADDRESS>, YEAR" ought to be replaced by sensible information.
//
// See http://www.gnu.org/software/gettext/manual/html_node/Header-Entry.html#Header-Entry
type Header struct {
ProjectIdVersion string // Project-Id-Version: PACKAGE VERSION
ReportMsgidBugsTo string // Report-Msgid-Bugs-To: FIRST AUTHOR <EMAIL@ADDRESS>
POTCreationDate string // POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE
PORevisionDate string // PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE
LastTranslator string // Last-Translator: FIRST AUTHOR <EMAIL@ADDRESS>
LanguageTeam string // Language-Team: golang-china
Language string // Language: zh_CN
MimeVersion string // MIME-Version: 1.0
ContentType string // Content-Type: text/plain; charset=UTF-8
ContentTransferEncoding string // Content-Transfer-Encoding: 8bit
PluralForms string // Plural-Forms: nplurals=2; plural=n == 1 ? 0 : 1;
XGenerator string // X-Generator: Poedit 1.5.5
UnknowFields map[string]string
}
func (p *Header) fromMessage(msg *Message) {
if msg.MsgId != "" || msg.MsgStr == "" {
return
}
lines := strings.Split(msg.MsgStr, "\n")
for i := 0; i < len(lines); i++ {
idx := strings.Index(lines[i], ":")
if idx < 0 {
continue
}
key := strings.TrimSpace(lines[i][:idx])
val := strings.TrimSpace(lines[i][idx+1:])
switch strings.ToUpper(key) {
case strings.ToUpper("Project-Id-Version"):
p.ProjectIdVersion = val
case strings.ToUpper("Report-Msgid-Bugs-To"):
p.ReportMsgidBugsTo = val
case strings.ToUpper("POT-Creation-Date"):
p.POTCreationDate = val
case strings.ToUpper("PO-Revision-Date"):
p.PORevisionDate = val
case strings.ToUpper("Last-Translator"):
p.LastTranslator = val
case strings.ToUpper("Language-Team"):
p.LanguageTeam = val
case strings.ToUpper("Language"):
p.Language = val
case strings.ToUpper("MIME-Version"):
p.MimeVersion = val
case strings.ToUpper("Content-Type"):
p.ContentType = val
case strings.ToUpper("Content-Transfer-Encoding"):
p.ContentTransferEncoding = val
case strings.ToUpper("Plural-Forms"):
p.PluralForms = val
case strings.ToUpper("X-Generator"):
p.XGenerator = val
default:
if p.UnknowFields == nil {
p.UnknowFields = make(map[string]string)
}
p.UnknowFields[key] = val
}
}
}
func (p *Header) toMessage() Message {
return Message{
MsgStr: p.String(),
}
}
// String returns the po format header string.
func (p Header) String() string {
var buf bytes.Buffer
fmt.Fprintf(&buf, `msgid ""`+"\n")
fmt.Fprintf(&buf, `msgstr ""`+"\n")
fmt.Fprintf(&buf, `"%s: %s\n"`+"\n", "Project-Id-Version", p.ProjectIdVersion)
fmt.Fprintf(&buf, `"%s: %s\n"`+"\n", "Report-Msgid-Bugs-To", p.ReportMsgidBugsTo)
fmt.Fprintf(&buf, `"%s: %s\n"`+"\n", "POT-Creation-Date", p.POTCreationDate)
fmt.Fprintf(&buf, `"%s: %s\n"`+"\n", "PO-Revision-Date", p.PORevisionDate)
fmt.Fprintf(&buf, `"%s: %s\n"`+"\n", "Last-Translator", p.LastTranslator)
fmt.Fprintf(&buf, `"%s: %s\n"`+"\n", "Language-Team", p.LanguageTeam)
fmt.Fprintf(&buf, `"%s: %s\n"`+"\n", "Language", p.Language)
if p.MimeVersion != "" {
fmt.Fprintf(&buf, `"%s: %s\n"`+"\n", "MIME-Version", p.MimeVersion)
}
fmt.Fprintf(&buf, `"%s: %s\n"`+"\n", "Content-Type", p.ContentType)
fmt.Fprintf(&buf, `"%s: %s\n"`+"\n", "Content-Transfer-Encoding", p.ContentTransferEncoding)
if p.XGenerator != "" {
fmt.Fprintf(&buf, `"%s: %s\n"`+"\n", "X-Generator", p.XGenerator)
}
for k, v := range p.UnknowFields {
fmt.Fprintf(&buf, `"%s: %s\n"`+"\n", k, v)
}
return buf.String()
}

View File

@ -0,0 +1,39 @@
// Copyright 2013 ChaiShushan <chaishushan{AT}gmail.com>. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package mo
import (
"bytes"
"fmt"
)
// A MO file is made up of many entries,
// each entry holding the relation between an original untranslated string
// and its corresponding translation.
//
// See http://www.gnu.org/software/gettext/manual/html_node/MO-Files.html
type Message struct {
MsgContext string // msgctxt context
MsgId string // msgid untranslated-string
MsgIdPlural string // msgid_plural untranslated-string-plural
MsgStr string // msgstr translated-string
MsgStrPlural []string // msgstr[0] translated-string-case-0
}
// String returns the po format entry string.
func (p Message) String() string {
var buf bytes.Buffer
fmt.Fprintf(&buf, "msgid %s", encodePoString(p.MsgId))
if p.MsgIdPlural != "" {
fmt.Fprintf(&buf, "msgid_plural %s", encodePoString(p.MsgIdPlural))
}
if p.MsgStr != "" {
fmt.Fprintf(&buf, "msgstr %s", encodePoString(p.MsgStr))
}
for i := 0; i < len(p.MsgStrPlural); i++ {
fmt.Fprintf(&buf, "msgstr[%d] %s", i, encodePoString(p.MsgStrPlural[i]))
}
return buf.String()
}

View File

@ -0,0 +1,110 @@
// Copyright 2013 ChaiShushan <chaishushan{AT}gmail.com>. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package mo
import (
"bytes"
"strings"
)
func decodePoString(text string) string {
lines := strings.Split(text, "\n")
for i := 0; i < len(lines); i++ {
left := strings.Index(lines[i], `"`)
right := strings.LastIndex(lines[i], `"`)
if left < 0 || right < 0 || left == right {
lines[i] = ""
continue
}
line := lines[i][left+1 : right]
data := make([]byte, 0, len(line))
for i := 0; i < len(line); i++ {
if line[i] != '\\' {
data = append(data, line[i])
continue
}
if i+1 >= len(line) {
break
}
switch line[i+1] {
case 'n': // \\n -> \n
data = append(data, '\n')
i++
case 't': // \\t -> \n
data = append(data, '\t')
i++
case '\\': // \\\ -> ?
data = append(data, '\\')
i++
}
}
lines[i] = string(data)
}
return strings.Join(lines, "")
}
func encodePoString(text string) string {
var buf bytes.Buffer
lines := strings.Split(text, "\n")
for i := 0; i < len(lines); i++ {
if lines[i] == "" {
if i != len(lines)-1 {
buf.WriteString(`"\n"` + "\n")
}
continue
}
buf.WriteRune('"')
for _, r := range lines[i] {
switch r {
case '\\':
buf.WriteString(`\\`)
case '"':
buf.WriteString(`\"`)
case '\n':
buf.WriteString(`\n`)
case '\t':
buf.WriteString(`\t`)
default:
buf.WriteRune(r)
}
}
buf.WriteString(`\n"` + "\n")
}
return buf.String()
}
func encodeCommentPoString(text string) string {
var buf bytes.Buffer
lines := strings.Split(text, "\n")
if len(lines) > 1 {
buf.WriteString(`""` + "\n")
}
for i := 0; i < len(lines); i++ {
if len(lines) > 0 {
buf.WriteString("#| ")
}
buf.WriteRune('"')
for _, r := range lines[i] {
switch r {
case '\\':
buf.WriteString(`\\`)
case '"':
buf.WriteString(`\"`)
case '\n':
buf.WriteString(`\n`)
case '\t':
buf.WriteString(`\t`)
default:
buf.WriteRune(r)
}
}
if i < len(lines)-1 {
buf.WriteString(`\n"` + "\n")
} else {
buf.WriteString(`"`)
}
}
return buf.String()
}

View File

@ -0,0 +1,36 @@
// Copyright 2013 ChaiShushan <chaishushan{AT}gmail.com>. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
/*
Package plural provides standard plural formulas.
Examples:
import (
"code.google.com/p/gettext-go/gettext/plural"
)
func main() {
enFormula := plural.Formula("en_US")
xxFormula := plural.Formula("zh_CN")
fmt.Printf("%s: %d\n", "en", enFormula(0))
fmt.Printf("%s: %d\n", "en", enFormula(1))
fmt.Printf("%s: %d\n", "en", enFormula(2))
fmt.Printf("%s: %d\n", "??", xxFormula(0))
fmt.Printf("%s: %d\n", "??", xxFormula(1))
fmt.Printf("%s: %d\n", "??", xxFormula(2))
fmt.Printf("%s: %d\n", "??", xxFormula(9))
// Output:
// en: 0
// en: 0
// en: 1
// ??: 0
// ??: 0
// ??: 1
// ??: 8
}
See http://www.gnu.org/software/gettext/manual/html_node/Plural-forms.html
*/
package plural

View File

@ -0,0 +1,181 @@
// Copyright 2013 ChaiShushan <chaishushan{AT}gmail.com>. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package plural
import (
"strings"
)
// Formula provides the language's standard plural formula.
func Formula(lang string) func(n int) int {
if idx := index(lang); idx != -1 {
return formulaTable[fmtForms(FormsTable[idx].Value)]
}
if idx := index("??"); idx != -1 {
return formulaTable[fmtForms(FormsTable[idx].Value)]
}
return func(n int) int {
return n
}
}
func index(lang string) int {
for i := 0; i < len(FormsTable); i++ {
if strings.HasPrefix(lang, FormsTable[i].Lang) {
return i
}
}
return -1
}
func fmtForms(forms string) string {
forms = strings.TrimSpace(forms)
forms = strings.Replace(forms, " ", "", -1)
return forms
}
var formulaTable = map[string]func(n int) int{
fmtForms("nplurals=n; plural=n-1;"): func(n int) int {
if n > 0 {
return n - 1
}
return 0
},
fmtForms("nplurals=1; plural=0;"): func(n int) int {
return 0
},
fmtForms("nplurals=2; plural=(n != 1);"): func(n int) int {
if n <= 1 {
return 0
}
return 1
},
fmtForms("nplurals=2; plural=(n > 1);"): func(n int) int {
if n <= 1 {
return 0
}
return 1
},
fmtForms("nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n != 0 ? 1 : 2);"): func(n int) int {
if n%10 == 1 && n%100 != 11 {
return 0
}
if n != 0 {
return 1
}
return 2
},
fmtForms("nplurals=3; plural=n==1 ? 0 : n==2 ? 1 : 2;"): func(n int) int {
if n == 1 {
return 0
}
if n == 2 {
return 1
}
return 2
},
fmtForms("nplurals=3; plural=n==1 ? 0 : (n==0 || (n%100 > 0 && n%100 < 20)) ? 1 : 2;"): func(n int) int {
if n == 1 {
return 0
}
if n == 0 || (n%100 > 0 && n%100 < 20) {
return 1
}
return 2
},
fmtForms("nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && (n%100<10 || n%100>=20) ? 1 : 2);"): func(n int) int {
if n%10 == 1 && n%100 != 11 {
return 0
}
if n%10 >= 2 && (n%100 < 10 || n%100 >= 20) {
return 1
}
return 2
},
fmtForms("nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);"): func(n int) int {
if n%10 == 1 && n%100 != 11 {
return 0
}
if n%10 >= 2 && n%10 <= 4 && (n%100 < 10 || n%100 >= 20) {
return 1
}
return 2
},
fmtForms("nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);"): func(n int) int {
if n%10 == 1 && n%100 != 11 {
return 0
}
if n%10 >= 2 && n%10 <= 4 && (n%100 < 10 || n%100 >= 20) {
return 1
}
return 2
},
fmtForms("nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);"): func(n int) int {
if n%10 == 1 && n%100 != 11 {
return 0
}
if n%10 >= 2 && n%10 <= 4 && (n%100 < 10 || n%100 >= 20) {
return 1
}
return 2
},
fmtForms("nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);"): func(n int) int {
if n%10 == 1 && n%100 != 11 {
return 0
}
if n%10 >= 2 && n%10 <= 4 && (n%100 < 10 || n%100 >= 20) {
return 1
}
return 2
},
fmtForms("nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);"): func(n int) int {
if n%10 == 1 && n%100 != 11 {
return 0
}
if n%10 >= 2 && n%10 <= 4 && (n%100 < 10 || n%100 >= 20) {
return 1
}
return 2
},
fmtForms("nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;"): func(n int) int {
if n == 1 {
return 0
}
if n >= 2 && n <= 4 {
return 1
}
return 2
},
fmtForms("nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;"): func(n int) int {
if n == 1 {
return 0
}
if n >= 2 && n <= 4 {
return 1
}
return 2
},
fmtForms("nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);"): func(n int) int {
if n == 1 {
return 0
}
if n%10 >= 2 && n%10 <= 4 && (n%100 < 10 || n%100 >= 20) {
return 1
}
return 2
},
fmtForms("nplurals=4; plural=(n%100==1 ? 0 : n%100==2 ? 1 : n%100==3 || n%100==4 ? 2 : 3);"): func(n int) int {
if n%100 == 1 {
return 0
}
if n%100 == 2 {
return 1
}
if n%100 == 3 || n%100 == 4 {
return 2
}
return 3
},
}

View File

@ -0,0 +1,55 @@
// Copyright 2013 ChaiShushan <chaishushan{AT}gmail.com>. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package plural
// FormsTable are standard hard-coded plural rules.
// The application developers and the translators need to understand them.
//
// See GNU's gettext library source code: gettext/gettext-tools/src/plural-table.c
var FormsTable = []struct {
Lang string
Language string
Value string
}{
{"??", "Unknown", "nplurals=1; plural=0;"},
{"ja", "Japanese", "nplurals=1; plural=0;"},
{"vi", "Vietnamese", "nplurals=1; plural=0;"},
{"ko", "Korean", "nplurals=1; plural=0;"},
{"en", "English", "nplurals=2; plural=(n != 1);"},
{"de", "German", "nplurals=2; plural=(n != 1);"},
{"nl", "Dutch", "nplurals=2; plural=(n != 1);"},
{"sv", "Swedish", "nplurals=2; plural=(n != 1);"},
{"da", "Danish", "nplurals=2; plural=(n != 1);"},
{"no", "Norwegian", "nplurals=2; plural=(n != 1);"},
{"nb", "Norwegian Bokmal", "nplurals=2; plural=(n != 1);"},
{"nn", "Norwegian Nynorsk", "nplurals=2; plural=(n != 1);"},
{"fo", "Faroese", "nplurals=2; plural=(n != 1);"},
{"es", "Spanish", "nplurals=2; plural=(n != 1);"},
{"pt", "Portuguese", "nplurals=2; plural=(n != 1);"},
{"it", "Italian", "nplurals=2; plural=(n != 1);"},
{"bg", "Bulgarian", "nplurals=2; plural=(n != 1);"},
{"el", "Greek", "nplurals=2; plural=(n != 1);"},
{"fi", "Finnish", "nplurals=2; plural=(n != 1);"},
{"et", "Estonian", "nplurals=2; plural=(n != 1);"},
{"he", "Hebrew", "nplurals=2; plural=(n != 1);"},
{"eo", "Esperanto", "nplurals=2; plural=(n != 1);"},
{"hu", "Hungarian", "nplurals=2; plural=(n != 1);"},
{"tr", "Turkish", "nplurals=2; plural=(n != 1);"},
{"pt_BR", "Brazilian", "nplurals=2; plural=(n > 1);"},
{"fr", "French", "nplurals=2; plural=(n > 1);"},
{"lv", "Latvian", "nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n != 0 ? 1 : 2);"},
{"ga", "Irish", "nplurals=3; plural=n==1 ? 0 : n==2 ? 1 : 2;"},
{"ro", "Romanian", "nplurals=3; plural=n==1 ? 0 : (n==0 || (n%100 > 0 && n%100 < 20)) ? 1 : 2;"},
{"lt", "Lithuanian", "nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && (n%100<10 || n%100>=20) ? 1 : 2);"},
{"ru", "Russian", "nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);"},
{"uk", "Ukrainian", "nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);"},
{"be", "Belarusian", "nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);"},
{"sr", "Serbian", "nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);"},
{"hr", "Croatian", "nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);"},
{"cs", "Czech", "nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;"},
{"sk", "Slovak", "nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;"},
{"pl", "Polish", "nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);"},
{"sl", "Slovenian", "nplurals=4; plural=(n%100==1 ? 0 : n%100==2 ? 1 : n%100==3 || n%100==4 ? 2 : 3);"},
}

View File

@ -0,0 +1,270 @@
// Copyright 2013 ChaiShushan <chaishushan{AT}gmail.com>. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package po
import (
"bytes"
"fmt"
"io"
"strconv"
"strings"
)
// Comment represents every message's comments.
type Comment struct {
StartLine int // comment start line
TranslatorComment string // # translator-comments // TrimSpace
ExtractedComment string // #. extracted-comments
ReferenceFile []string // #: src/msgcmp.c:338 src/po-lex.c:699
ReferenceLine []int // #: src/msgcmp.c:338 src/po-lex.c:699
Flags []string // #, fuzzy,c-format,range:0..10
PrevMsgContext string // #| msgctxt previous-context
PrevMsgId string // #| msgid previous-untranslated-string
}
func (p *Comment) less(q *Comment) bool {
if p.StartLine != 0 || q.StartLine != 0 {
return p.StartLine < q.StartLine
}
if a, b := len(p.ReferenceFile), len(q.ReferenceFile); a != b {
return a < b
}
for i := 0; i < len(p.ReferenceFile); i++ {
if a, b := p.ReferenceFile[i], q.ReferenceFile[i]; a != b {
return a < b
}
if a, b := p.ReferenceLine[i], q.ReferenceLine[i]; a != b {
return a < b
}
}
return false
}
func (p *Comment) readPoComment(r *lineReader) (err error) {
*p = Comment{}
if err = r.skipBlankLine(); err != nil {
return err
}
defer func(oldPos int) {
newPos := r.currentPos()
if newPos != oldPos && err == io.EOF {
err = nil
}
}(r.currentPos())
p.StartLine = r.currentPos() + 1
for {
var s string
if s, _, err = r.currentLine(); err != nil {
return
}
if len(s) == 0 || s[0] != '#' {
return
}
if err = p.readTranslatorComment(r); err != nil {
return
}
if err = p.readExtractedComment(r); err != nil {
return
}
if err = p.readReferenceComment(r); err != nil {
return
}
if err = p.readFlagsComment(r); err != nil {
return
}
if err = p.readPrevMsgContext(r); err != nil {
return
}
if err = p.readPrevMsgId(r); err != nil {
return
}
}
}
func (p *Comment) readTranslatorComment(r *lineReader) (err error) {
const prefix = "# " // .,:|
for {
var s string
if s, _, err = r.readLine(); err != nil {
return err
}
if len(s) < 1 || s[0] != '#' {
r.unreadLine()
return nil
}
if len(s) >= 2 {
switch s[1] {
case '.', ',', ':', '|':
r.unreadLine()
return nil
}
}
if p.TranslatorComment != "" {
p.TranslatorComment += "\n"
}
p.TranslatorComment += strings.TrimSpace(s[1:])
}
}
func (p *Comment) readExtractedComment(r *lineReader) (err error) {
const prefix = "#."
for {
var s string
if s, _, err = r.readLine(); err != nil {
return err
}
if len(s) < len(prefix) || s[:len(prefix)] != prefix {
r.unreadLine()
return nil
}
if p.ExtractedComment != "" {
p.ExtractedComment += "\n"
}
p.ExtractedComment += strings.TrimSpace(s[len(prefix):])
}
}
func (p *Comment) readReferenceComment(r *lineReader) (err error) {
const prefix = "#:"
for {
var s string
if s, _, err = r.readLine(); err != nil {
return err
}
if len(s) < len(prefix) || s[:len(prefix)] != prefix {
r.unreadLine()
return nil
}
ss := strings.Split(strings.TrimSpace(s[len(prefix):]), " ")
for i := 0; i < len(ss); i++ {
idx := strings.Index(ss[i], ":")
if idx <= 0 {
continue
}
name := strings.TrimSpace(ss[i][:idx])
line, _ := strconv.Atoi(strings.TrimSpace(ss[i][idx+1:]))
p.ReferenceFile = append(p.ReferenceFile, name)
p.ReferenceLine = append(p.ReferenceLine, line)
}
}
}
func (p *Comment) readFlagsComment(r *lineReader) (err error) {
const prefix = "#,"
for {
var s string
if s, _, err = r.readLine(); err != nil {
return err
}
if len(s) < len(prefix) || s[:len(prefix)] != prefix {
r.unreadLine()
return nil
}
ss := strings.Split(strings.TrimSpace(s[len(prefix):]), ",")
for i := 0; i < len(ss); i++ {
p.Flags = append(p.Flags, strings.TrimSpace(ss[i]))
}
}
}
func (p *Comment) readPrevMsgContext(r *lineReader) (err error) {
var s string
if s, _, err = r.currentLine(); err != nil {
return
}
if !rePrevMsgContextComments.MatchString(s) {
return
}
p.PrevMsgContext, err = p.readString(r)
return
}
func (p *Comment) readPrevMsgId(r *lineReader) (err error) {
var s string
if s, _, err = r.currentLine(); err != nil {
return
}
if !rePrevMsgIdComments.MatchString(s) {
return
}
p.PrevMsgId, err = p.readString(r)
return
}
func (p *Comment) readString(r *lineReader) (msg string, err error) {
var s string
if s, _, err = r.readLine(); err != nil {
return
}
msg += decodePoString(s)
for {
if s, _, err = r.readLine(); err != nil {
return
}
if !reStringLineComments.MatchString(s) {
r.unreadLine()
break
}
msg += decodePoString(s)
}
return
}
// GetFuzzy gets the fuzzy flag.
func (p *Comment) GetFuzzy() bool {
for _, s := range p.Flags {
if s == "fuzzy" {
return true
}
}
return false
}
// SetFuzzy sets the fuzzy flag.
func (p *Comment) SetFuzzy(fuzzy bool) {
//
}
// String returns the po format comment string.
func (p Comment) String() string {
var buf bytes.Buffer
if p.TranslatorComment != "" {
ss := strings.Split(p.TranslatorComment, "\n")
for i := 0; i < len(ss); i++ {
fmt.Fprintf(&buf, "# %s\n", ss[i])
}
}
if p.ExtractedComment != "" {
ss := strings.Split(p.ExtractedComment, "\n")
for i := 0; i < len(ss); i++ {
fmt.Fprintf(&buf, "#. %s\n", ss[i])
}
}
if a, b := len(p.ReferenceFile), len(p.ReferenceLine); a != 0 && a == b {
fmt.Fprintf(&buf, "#:")
for i := 0; i < len(p.ReferenceFile); i++ {
fmt.Fprintf(&buf, " %s:%d", p.ReferenceFile[i], p.ReferenceLine[i])
}
fmt.Fprintf(&buf, "\n")
}
if len(p.Flags) != 0 {
fmt.Fprintf(&buf, "#, %s", p.Flags[0])
for i := 1; i < len(p.Flags); i++ {
fmt.Fprintf(&buf, ", %s", p.Flags[i])
}
fmt.Fprintf(&buf, "\n")
}
if p.PrevMsgContext != "" {
s := encodeCommentPoString(p.PrevMsgContext)
fmt.Fprintf(&buf, "#| msgctxt %s\n", s)
}
if p.PrevMsgId != "" {
s := encodeCommentPoString(p.PrevMsgId)
fmt.Fprintf(&buf, "#| msgid %s\n", s)
}
return buf.String()
}

View File

@ -0,0 +1,24 @@
// Copyright 2013 ChaiShushan <chaishushan{AT}gmail.com>. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
/*
Package po provides support for reading and writing GNU PO file.
Examples:
import (
"github.com/chai2010/gettext-go/gettext/po"
)
func main() {
poFile, err := po.Load("test.po")
if err != nil {
log.Fatal(err)
}
fmt.Printf("%v", poFile)
}
The GNU PO file specification is at
http://www.gnu.org/software/gettext/manual/html_node/PO-Files.html.
*/
package po

View File

@ -0,0 +1,75 @@
// Copyright 2013 ChaiShushan <chaishushan{AT}gmail.com>. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package po
import (
"bytes"
"fmt"
"io"
"io/ioutil"
"sort"
)
// File represents an PO File.
//
// See http://www.gnu.org/software/gettext/manual/html_node/PO-Files.html
type File struct {
MimeHeader Header
Messages []Message
}
// Load loads a named po file.
func Load(name string) (*File, error) {
data, err := ioutil.ReadFile(name)
if err != nil {
return nil, err
}
return LoadData(data)
}
// LoadData loads po file format data.
func LoadData(data []byte) (*File, error) {
r := newLineReader(string(data))
var file File
for {
var msg Message
if err := msg.readPoEntry(r); err != nil {
if err == io.EOF {
return &file, nil
}
return nil, err
}
if msg.MsgId == "" {
file.MimeHeader.parseHeader(&msg)
continue
}
file.Messages = append(file.Messages, msg)
}
}
// Save saves a po file.
func (f *File) Save(name string) error {
return ioutil.WriteFile(name, []byte(f.String()), 0666)
}
// Save returns a po file format data.
func (f *File) Data() []byte {
// sort the massge as ReferenceFile/ReferenceLine field
var messages []Message
messages = append(messages, f.Messages...)
sort.Sort(byMessages(messages))
var buf bytes.Buffer
fmt.Fprintf(&buf, "%s\n", f.MimeHeader.String())
for i := 0; i < len(messages); i++ {
fmt.Fprintf(&buf, "%s\n", messages[i].String())
}
return buf.Bytes()
}
// String returns the po format file string.
func (f *File) String() string {
return string(f.Data())
}

View File

@ -0,0 +1,106 @@
// Copyright 2013 ChaiShushan <chaishushan{AT}gmail.com>. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package po
import (
"bytes"
"fmt"
"strings"
)
// Header is the initial comments "SOME DESCRIPTIVE TITLE", "YEAR"
// and "FIRST AUTHOR <EMAIL@ADDRESS>, YEAR" ought to be replaced by sensible information.
//
// See http://www.gnu.org/software/gettext/manual/html_node/Header-Entry.html#Header-Entry
type Header struct {
Comment // Header Comments
ProjectIdVersion string // Project-Id-Version: PACKAGE VERSION
ReportMsgidBugsTo string // Report-Msgid-Bugs-To: FIRST AUTHOR <EMAIL@ADDRESS>
POTCreationDate string // POT-Creation-Date: YEAR-MO-DA HO:MI+ZONE
PORevisionDate string // PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE
LastTranslator string // Last-Translator: FIRST AUTHOR <EMAIL@ADDRESS>
LanguageTeam string // Language-Team: golang-china
Language string // Language: zh_CN
MimeVersion string // MIME-Version: 1.0
ContentType string // Content-Type: text/plain; charset=UTF-8
ContentTransferEncoding string // Content-Transfer-Encoding: 8bit
PluralForms string // Plural-Forms: nplurals=2; plural=n == 1 ? 0 : 1;
XGenerator string // X-Generator: Poedit 1.5.5
UnknowFields map[string]string
}
func (p *Header) parseHeader(msg *Message) {
if msg.MsgId != "" || msg.MsgStr == "" {
return
}
lines := strings.Split(msg.MsgStr, "\n")
for i := 0; i < len(lines); i++ {
idx := strings.Index(lines[i], ":")
if idx < 0 {
continue
}
key := strings.TrimSpace(lines[i][:idx])
val := strings.TrimSpace(lines[i][idx+1:])
switch strings.ToUpper(key) {
case strings.ToUpper("Project-Id-Version"):
p.ProjectIdVersion = val
case strings.ToUpper("Report-Msgid-Bugs-To"):
p.ReportMsgidBugsTo = val
case strings.ToUpper("POT-Creation-Date"):
p.POTCreationDate = val
case strings.ToUpper("PO-Revision-Date"):
p.PORevisionDate = val
case strings.ToUpper("Last-Translator"):
p.LastTranslator = val
case strings.ToUpper("Language-Team"):
p.LanguageTeam = val
case strings.ToUpper("Language"):
p.Language = val
case strings.ToUpper("MIME-Version"):
p.MimeVersion = val
case strings.ToUpper("Content-Type"):
p.ContentType = val
case strings.ToUpper("Content-Transfer-Encoding"):
p.ContentTransferEncoding = val
case strings.ToUpper("Plural-Forms"):
p.PluralForms = val
case strings.ToUpper("X-Generator"):
p.XGenerator = val
default:
if p.UnknowFields == nil {
p.UnknowFields = make(map[string]string)
}
p.UnknowFields[key] = val
}
}
p.Comment = msg.Comment
}
// String returns the po format header string.
func (p Header) String() string {
var buf bytes.Buffer
fmt.Fprintf(&buf, "%s", p.Comment.String())
fmt.Fprintf(&buf, `msgid ""`+"\n")
fmt.Fprintf(&buf, `msgstr ""`+"\n")
fmt.Fprintf(&buf, `"%s: %s\n"`+"\n", "Project-Id-Version", p.ProjectIdVersion)
fmt.Fprintf(&buf, `"%s: %s\n"`+"\n", "Report-Msgid-Bugs-To", p.ReportMsgidBugsTo)
fmt.Fprintf(&buf, `"%s: %s\n"`+"\n", "POT-Creation-Date", p.POTCreationDate)
fmt.Fprintf(&buf, `"%s: %s\n"`+"\n", "PO-Revision-Date", p.PORevisionDate)
fmt.Fprintf(&buf, `"%s: %s\n"`+"\n", "Last-Translator", p.LastTranslator)
fmt.Fprintf(&buf, `"%s: %s\n"`+"\n", "Language-Team", p.LanguageTeam)
fmt.Fprintf(&buf, `"%s: %s\n"`+"\n", "Language", p.Language)
if p.MimeVersion != "" {
fmt.Fprintf(&buf, `"%s: %s\n"`+"\n", "MIME-Version", p.MimeVersion)
}
fmt.Fprintf(&buf, `"%s: %s\n"`+"\n", "Content-Type", p.ContentType)
fmt.Fprintf(&buf, `"%s: %s\n"`+"\n", "Content-Transfer-Encoding", p.ContentTransferEncoding)
if p.XGenerator != "" {
fmt.Fprintf(&buf, `"%s: %s\n"`+"\n", "X-Generator", p.XGenerator)
}
for k, v := range p.UnknowFields {
fmt.Fprintf(&buf, `"%s: %s\n"`+"\n", k, v)
}
return buf.String()
}

View File

@ -0,0 +1,62 @@
// Copyright 2013 ChaiShushan <chaishushan{AT}gmail.com>. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package po
import (
"io"
"strings"
)
type lineReader struct {
lines []string
pos int
}
func newLineReader(data string) *lineReader {
data = strings.Replace(data, "\r", "", -1)
lines := strings.Split(data, "\n")
return &lineReader{lines: lines}
}
func (r *lineReader) skipBlankLine() error {
for ; r.pos < len(r.lines); r.pos++ {
if strings.TrimSpace(r.lines[r.pos]) != "" {
break
}
}
if r.pos >= len(r.lines) {
return io.EOF
}
return nil
}
func (r *lineReader) currentPos() int {
return r.pos
}
func (r *lineReader) currentLine() (s string, pos int, err error) {
if r.pos >= len(r.lines) {
err = io.EOF
return
}
s, pos = r.lines[r.pos], r.pos
return
}
func (r *lineReader) readLine() (s string, pos int, err error) {
if r.pos >= len(r.lines) {
err = io.EOF
return
}
s, pos = r.lines[r.pos], r.pos
r.pos++
return
}
func (r *lineReader) unreadLine() {
if r.pos >= 0 {
r.pos--
}
}

View File

@ -0,0 +1,189 @@
// Copyright 2013 ChaiShushan <chaishushan{AT}gmail.com>. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package po
import (
"bytes"
"fmt"
"io"
"strconv"
"strings"
)
// A PO file is made up of many entries,
// each entry holding the relation between an original untranslated string
// and its corresponding translation.
//
// See http://www.gnu.org/software/gettext/manual/html_node/PO-Files.html
type Message struct {
Comment // Coments
MsgContext string // msgctxt context
MsgId string // msgid untranslated-string
MsgIdPlural string // msgid_plural untranslated-string-plural
MsgStr string // msgstr translated-string
MsgStrPlural []string // msgstr[0] translated-string-case-0
}
type byMessages []Message
func (d byMessages) Len() int {
return len(d)
}
func (d byMessages) Less(i, j int) bool {
if d[i].Comment.less(&d[j].Comment) {
return true
}
if a, b := d[i].MsgContext, d[j].MsgContext; a != b {
return a < b
}
if a, b := d[i].MsgId, d[j].MsgId; a != b {
return a < b
}
if a, b := d[i].MsgIdPlural, d[j].MsgIdPlural; a != b {
return a < b
}
return false
}
func (d byMessages) Swap(i, j int) {
d[i], d[j] = d[j], d[i]
}
func (p *Message) readPoEntry(r *lineReader) (err error) {
*p = Message{}
if err = r.skipBlankLine(); err != nil {
return
}
defer func(oldPos int) {
newPos := r.currentPos()
if newPos != oldPos && err == io.EOF {
err = nil
}
}(r.currentPos())
if err = p.Comment.readPoComment(r); err != nil {
return
}
for {
var s string
if s, _, err = r.currentLine(); err != nil {
return
}
if p.isInvalidLine(s) {
err = fmt.Errorf("gettext: line %d, %v", r.currentPos(), "invalid line")
return
}
if reComment.MatchString(s) || reBlankLine.MatchString(s) {
return
}
if err = p.readMsgContext(r); err != nil {
return
}
if err = p.readMsgId(r); err != nil {
return
}
if err = p.readMsgIdPlural(r); err != nil {
return
}
if err = p.readMsgStrOrPlural(r); err != nil {
return
}
}
}
func (p *Message) readMsgContext(r *lineReader) (err error) {
var s string
if s, _, err = r.currentLine(); err != nil {
return
}
if !reMsgContext.MatchString(s) {
return
}
p.MsgContext, err = p.readString(r)
return
}
func (p *Message) readMsgId(r *lineReader) (err error) {
var s string
if s, _, err = r.currentLine(); err != nil {
return
}
if !reMsgId.MatchString(s) {
return
}
p.MsgId, err = p.readString(r)
return
}
func (p *Message) readMsgIdPlural(r *lineReader) (err error) {
var s string
if s, _, err = r.currentLine(); err != nil {
return
}
if !reMsgIdPlural.MatchString(s) {
return
}
p.MsgIdPlural, err = p.readString(r)
return nil
}
func (p *Message) readMsgStrOrPlural(r *lineReader) (err error) {
var s string
if s, _, err = r.currentLine(); err != nil {
return
}
if !reMsgStr.MatchString(s) && !reMsgStrPlural.MatchString(s) {
return
}
if reMsgStrPlural.MatchString(s) {
left, right := strings.Index(s, `[`), strings.LastIndex(s, `]`)
idx, _ := strconv.Atoi(s[left+1 : right])
s, err = p.readString(r)
if n := len(p.MsgStrPlural); (idx + 1) > n {
p.MsgStrPlural = append(p.MsgStrPlural, make([]string, (idx+1)-n)...)
}
p.MsgStrPlural[idx] = s
} else {
p.MsgStr, err = p.readString(r)
}
return nil
}
func (p *Message) readString(r *lineReader) (msg string, err error) {
var s string
if s, _, err = r.readLine(); err != nil {
return
}
msg += decodePoString(s)
for {
if s, _, err = r.readLine(); err != nil {
return
}
if !reStringLine.MatchString(s) {
r.unreadLine()
break
}
msg += decodePoString(s)
}
return
}
// String returns the po format entry string.
func (p Message) String() string {
var buf bytes.Buffer
fmt.Fprintf(&buf, "%s", p.Comment.String())
fmt.Fprintf(&buf, "msgid %s", encodePoString(p.MsgId))
if p.MsgIdPlural != "" {
fmt.Fprintf(&buf, "msgid_plural %s", encodePoString(p.MsgIdPlural))
}
if p.MsgStr != "" {
fmt.Fprintf(&buf, "msgstr %s", encodePoString(p.MsgStr))
}
for i := 0; i < len(p.MsgStrPlural); i++ {
fmt.Fprintf(&buf, "msgstr[%d] %s", i, encodePoString(p.MsgStrPlural[i]))
}
return buf.String()
}

58
vendor/github.com/chai2010/gettext-go/gettext/po/re.go generated vendored Normal file
View File

@ -0,0 +1,58 @@
// Copyright 2013 ChaiShushan <chaishushan{AT}gmail.com>. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package po
import (
"regexp"
)
var (
reComment = regexp.MustCompile(`^#`) // #
reExtractedComments = regexp.MustCompile(`^#\.`) // #.
reReferenceComments = regexp.MustCompile(`^#:`) // #:
reFlagsComments = regexp.MustCompile(`^#,`) // #, fuzzy,c-format
rePrevMsgContextComments = regexp.MustCompile(`^#\|\s+msgctxt`) // #| msgctxt
rePrevMsgIdComments = regexp.MustCompile(`^#\|\s+msgid`) // #| msgid
reStringLineComments = regexp.MustCompile(`^#\|\s+".*"\s*$`) // #| "message"
reMsgContext = regexp.MustCompile(`^msgctxt\s+".*"\s*$`) // msgctxt
reMsgId = regexp.MustCompile(`^msgid\s+".*"\s*$`) // msgid
reMsgIdPlural = regexp.MustCompile(`^msgid_plural\s+".*"\s*$`) // msgid_plural
reMsgStr = regexp.MustCompile(`^msgstr\s*".*"\s*$`) // msgstr
reMsgStrPlural = regexp.MustCompile(`^msgstr\s*(\[\d+\])\s*".*"\s*$`) // msgstr[0]
reStringLine = regexp.MustCompile(`^\s*".*"\s*$`) // "message"
reBlankLine = regexp.MustCompile(`^\s*$`) //
)
func (p *Message) isInvalidLine(s string) bool {
if reComment.MatchString(s) {
return false
}
if reBlankLine.MatchString(s) {
return false
}
if reMsgContext.MatchString(s) {
return false
}
if reMsgId.MatchString(s) {
return false
}
if reMsgIdPlural.MatchString(s) {
return false
}
if reMsgStr.MatchString(s) {
return false
}
if reMsgStrPlural.MatchString(s) {
return false
}
if reStringLine.MatchString(s) {
return false
}
return true
}

View File

@ -0,0 +1,110 @@
// Copyright 2013 ChaiShushan <chaishushan{AT}gmail.com>. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package po
import (
"bytes"
"strings"
)
func decodePoString(text string) string {
lines := strings.Split(text, "\n")
for i := 0; i < len(lines); i++ {
left := strings.Index(lines[i], `"`)
right := strings.LastIndex(lines[i], `"`)
if left < 0 || right < 0 || left == right {
lines[i] = ""
continue
}
line := lines[i][left+1 : right]
data := make([]byte, 0, len(line))
for i := 0; i < len(line); i++ {
if line[i] != '\\' {
data = append(data, line[i])
continue
}
if i+1 >= len(line) {
break
}
switch line[i+1] {
case 'n': // \\n -> \n
data = append(data, '\n')
i++
case 't': // \\t -> \n
data = append(data, '\t')
i++
case '\\': // \\\ -> ?
data = append(data, '\\')
i++
}
}
lines[i] = string(data)
}
return strings.Join(lines, "")
}
func encodePoString(text string) string {
var buf bytes.Buffer
lines := strings.Split(text, "\n")
for i := 0; i < len(lines); i++ {
if lines[i] == "" {
if i != len(lines)-1 {
buf.WriteString(`"\n"` + "\n")
}
continue
}
buf.WriteRune('"')
for _, r := range lines[i] {
switch r {
case '\\':
buf.WriteString(`\\`)
case '"':
buf.WriteString(`\"`)
case '\n':
buf.WriteString(`\n`)
case '\t':
buf.WriteString(`\t`)
default:
buf.WriteRune(r)
}
}
buf.WriteString(`\n"` + "\n")
}
return buf.String()
}
func encodeCommentPoString(text string) string {
var buf bytes.Buffer
lines := strings.Split(text, "\n")
if len(lines) > 1 {
buf.WriteString(`""` + "\n")
}
for i := 0; i < len(lines); i++ {
if len(lines) > 0 {
buf.WriteString("#| ")
}
buf.WriteRune('"')
for _, r := range lines[i] {
switch r {
case '\\':
buf.WriteString(`\\`)
case '"':
buf.WriteString(`\"`)
case '\n':
buf.WriteString(`\n`)
case '\t':
buf.WriteString(`\t`)
default:
buf.WriteRune(r)
}
}
if i < len(lines)-1 {
buf.WriteString(`\n"` + "\n")
} else {
buf.WriteString(`"`)
}
}
return buf.String()
}

128
vendor/github.com/chai2010/gettext-go/gettext/tr.go generated vendored Normal file
View File

@ -0,0 +1,128 @@
// Copyright 2013 ChaiShushan <chaishushan{AT}gmail.com>. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package gettext
import (
"github.com/chai2010/gettext-go/gettext/mo"
"github.com/chai2010/gettext-go/gettext/plural"
"github.com/chai2010/gettext-go/gettext/po"
)
var nilTranslator = &translator{
MessageMap: make(map[string]mo.Message),
PluralFormula: plural.Formula("??"),
}
type translator struct {
MessageMap map[string]mo.Message
PluralFormula func(n int) int
}
func newMoTranslator(name string, data []byte) (*translator, error) {
var (
f *mo.File
err error
)
if len(data) != 0 {
f, err = mo.LoadData(data)
} else {
f, err = mo.Load(name)
}
if err != nil {
return nil, err
}
var tr = &translator{
MessageMap: make(map[string]mo.Message),
}
for _, v := range f.Messages {
tr.MessageMap[tr.makeMapKey(v.MsgContext, v.MsgId)] = v
}
if lang := f.MimeHeader.Language; lang != "" {
tr.PluralFormula = plural.Formula(lang)
} else {
tr.PluralFormula = plural.Formula("??")
}
return tr, nil
}
func newPoTranslator(name string, data []byte) (*translator, error) {
var (
f *po.File
err error
)
if len(data) != 0 {
f, err = po.LoadData(data)
} else {
f, err = po.Load(name)
}
if err != nil {
return nil, err
}
var tr = &translator{
MessageMap: make(map[string]mo.Message),
}
for _, v := range f.Messages {
tr.MessageMap[tr.makeMapKey(v.MsgContext, v.MsgId)] = mo.Message{
MsgContext: v.MsgContext,
MsgId: v.MsgId,
MsgIdPlural: v.MsgIdPlural,
MsgStr: v.MsgStr,
MsgStrPlural: v.MsgStrPlural,
}
}
if lang := f.MimeHeader.Language; lang != "" {
tr.PluralFormula = plural.Formula(lang)
} else {
tr.PluralFormula = plural.Formula("??")
}
return tr, nil
}
func (p *translator) PGettext(msgctxt, msgid string) string {
return p.PNGettext(msgctxt, msgid, "", 0)
}
func (p *translator) PNGettext(msgctxt, msgid, msgidPlural string, n int) string {
n = p.PluralFormula(n)
if ss := p.findMsgStrPlural(msgctxt, msgid, msgidPlural); len(ss) != 0 {
if n >= len(ss) {
n = len(ss) - 1
}
if ss[n] != "" {
return ss[n]
}
}
if msgidPlural != "" && n > 0 {
return msgidPlural
}
return msgid
}
func (p *translator) findMsgStrPlural(msgctxt, msgid, msgidPlural string) []string {
key := p.makeMapKey(msgctxt, msgid)
if v, ok := p.MessageMap[key]; ok {
if len(v.MsgIdPlural) != 0 {
if len(v.MsgStrPlural) != 0 {
return v.MsgStrPlural
} else {
return nil
}
} else {
if len(v.MsgStr) != 0 {
return []string{v.MsgStr}
} else {
return nil
}
}
}
return nil
}
func (p *translator) makeMapKey(msgctxt, msgid string) string {
if msgctxt != "" {
return msgctxt + mo.EotSeparator + msgid
}
return msgid
}