diff --git a/pkg/kubectl/util/i18n/i18n.go b/pkg/kubectl/util/i18n/i18n.go index e287eab97d..f1e730b6fd 100644 --- a/pkg/kubectl/util/i18n/i18n.go +++ b/pkg/kubectl/util/i18n/i18n.go @@ -50,9 +50,18 @@ var knownTranslations = map[string][]string{ } func loadSystemLanguage() string { - langStr := os.Getenv("LANG") + // Implements the following locale priority order: LC_ALL, LC_MESSAGES, LANG + // Similarly to: https://www.gnu.org/software/gettext/manual/html_node/Locale-Environment-Variables.html + langStr := os.Getenv("LC_ALL") if langStr == "" { - glog.V(3).Infof("Couldn't find the LANG environment variable, defaulting to en_US") + langStr = os.Getenv("LC_MESSAGES") + } + if langStr == "" { + langStr = os.Getenv("LANG") + } + + if langStr == "" { + glog.V(3).Infof("Couldn't find the LC_ALL, LC_MESSAGES or LANG environment variables, defaulting to en_US") return "default" } pieces := strings.Split(langStr, ".") diff --git a/pkg/kubectl/util/i18n/i18n_test.go b/pkg/kubectl/util/i18n/i18n_test.go index 1f879eed6b..eff6188d5b 100644 --- a/pkg/kubectl/util/i18n/i18n_test.go +++ b/pkg/kubectl/util/i18n/i18n_test.go @@ -21,6 +21,8 @@ import ( "testing" ) +var knownTestLocale = "en_US.UTF-8" + func TestTranslation(t *testing.T) { err := LoadTranslations("test", func() string { return "default" }) if err != nil { @@ -50,15 +52,106 @@ func TestTranslationPlural(t *testing.T) { } } -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) +func TestTranslationUsingEnvVar(t *testing.T) { + // We must backup and restore env vars before setting test values in tests + // othervise we are risking to break other tests/test cases + // which rely on the same env vars + envVarsToBackup := []string{"LC_MESSAGES", "LANG", "LC_ALL"} + expectedStrEnUSLocale := "baz" + expectedStrFallback := "foo" + + testCases := []struct { + name string + setenvFn func() + expectedStr string + }{ + { + name: "Only LC_ALL is set", + setenvFn: func() { os.Setenv("LC_ALL", knownTestLocale) }, + expectedStr: expectedStrEnUSLocale, + }, + { + name: "Only LC_MESSAGES is set", + setenvFn: func() { os.Setenv("LC_MESSAGES", knownTestLocale) }, + expectedStr: expectedStrEnUSLocale, + }, + { + name: "Only LANG", + setenvFn: func() { os.Setenv("LANG", knownTestLocale) }, + expectedStr: expectedStrEnUSLocale, + }, + { + name: "LC_MESSAGES overrides LANG", + setenvFn: func() { + os.Setenv("LANG", "be_BY.UTF-8") // Unknown locale + os.Setenv("LC_MESSAGES", knownTestLocale) + }, + expectedStr: expectedStrEnUSLocale, + }, + { + name: "LC_ALL overrides LANG", + setenvFn: func() { + os.Setenv("LANG", "be_BY.UTF-8") // Unknown locale + os.Setenv("LC_ALL", knownTestLocale) + }, + expectedStr: expectedStrEnUSLocale, + }, + { + name: "LC_ALL overrides LC_MESSAGES", + setenvFn: func() { + os.Setenv("LC_MESSAGES", "be_BY.UTF-8") // Unknown locale + os.Setenv("LC_ALL", knownTestLocale) + }, + expectedStr: expectedStrEnUSLocale, + }, + { + name: "Unknown locale in LANG", + setenvFn: func() { os.Setenv("LANG", "be_BY.UTF-8") }, + expectedStr: expectedStrFallback, + }, + { + name: "Unknown locale in LC_MESSAGES", + setenvFn: func() { os.Setenv("LC_MESSAGES", "be_BY.UTF-8") }, + expectedStr: expectedStrFallback, + }, + { + name: "Unknown locale in LC_ALL", + setenvFn: func() { os.Setenv("LC_ALL", "be_BY.UTF-8") }, + expectedStr: expectedStrFallback, + }, + { + name: "Invalid env var", + setenvFn: func() { os.Setenv("LC_MESSAGES", "fake.locale.UTF-8") }, + expectedStr: expectedStrFallback, + }, + { + name: "No env vars", + setenvFn: func() {}, + expectedStr: expectedStrFallback, + }, } - result := T("test_string") - if result != "baz" { - t.Errorf("expected: %s, saw: %s", "baz", result) + for _, test := range testCases { + t.Run(test.name, func(t *testing.T) { + for _, envVar := range envVarsToBackup { + if envVarValue := os.Getenv(envVar); envVarValue != "" { + os.Unsetenv(envVar) + // Restore env var at the end + defer func() { os.Setenv(envVar, envVarValue) }() + } + } + + test.setenvFn() + + err := LoadTranslations("test", nil) + if err != nil { + t.Errorf("Unexpected error: %v", err) + } + + result := T("test_string") + if result != test.expectedStr { + t.Errorf("expected: %s, saw: %s", test.expectedStr, result) + } + }) } }