Commit 27730644 authored by Brendan Burns's avatar Brendan Burns

Add initial translation support.

parent 6dd760d3
......@@ -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()
......
......@@ -255,6 +255,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
......
......@@ -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 = []
......
......@@ -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"
......@@ -9,6 +9,9 @@ load(
go_library(
name = "go_default_library",
srcs = ["doc.go"],
srcs = [
"bindata.go",
"doc.go",
],
tags = ["automanaged"],
)
......@@ -101,6 +101,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",
......
......@@ -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) {
......
......@@ -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)
......
......@@ -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()
......
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 = [],
)
/*
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...))
}
/*
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)
}
}
......@@ -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
......@@ -179,6 +179,8 @@ Federation secrets Secret objects should be created and deleted successfully,pmo
Federation secrets Secret objects should be deleted from underlying clusters when OrphanDependents is false,nikhiljindal,0
Federation secrets Secret objects should not be deleted from underlying clusters when OrphanDependents is nil,nikhiljindal,0
Federation secrets Secret objects should not be deleted from underlying clusters when OrphanDependents is true,nikhiljindal,0
Firewall rule should create valid firewall rules for LoadBalancer type service,brendandburns,0
Firewall rule should have correct firewall rules for e2e cluster,brendandburns,0
GCP Volumes GlusterFS should be mountable,nikhiljindal,0
GCP Volumes NFSv4 should be mountable for NFSv4,nikhiljindal,0
GKE local SSD should write and read from node local SSD,fabioy,0
......@@ -276,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
......@@ -304,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
......@@ -469,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
......@@ -509,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
......@@ -517,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
......@@ -528,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
......@@ -659,7 +662,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
......@@ -854,6 +857,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
......@@ -967,7 +971,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
......
# 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)]()
# 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"
# 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"
# 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"
# 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"
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment