// +build darwin,!ios package locale import ( "fmt" "os/exec" "regexp" "strings" "syscall" ) func execCommand(cmd string, args ...string) (status int, out []byte, err error) { status = -1 command := exec.Command(cmd, args...) // Execute the command and get the standard and error outputs out, err = command.CombinedOutput() if err != nil { return } // Check the status code if w, ok := command.ProcessState.Sys().(syscall.WaitStatus); ok { status = w.ExitStatus() } return } // GetLocale retrieves the IETF BCP 47 language tag set on the system. func GetLocale() (string, error) { _, output, err := execCommand("defaults", "read", "-g", "AppleLocale") if err != nil { return "", fmt.Errorf("cannot determine locale: %v (output: %s)", err, output) } return strings.TrimRight(strings.Replace(string(output), "_", "-", 1), "\n"), nil } // appleLanguagesRegex is used to parse the output of "defaults read -g AppleLanguages" // e.g.: // ( // "en-US", // "fr-FR", // "ja-JP" // ) var appleLanguagesRegex = regexp.MustCompile(`"([a-z]{2}-[A-Z]{2})"`) // GetLocales retrieves the IETF BCP 47 language tags set on the system. func GetLocales() ([]string, error) { _, output, err := execCommand("defaults", "read", "-g", "AppleLanguages") if err != nil { return nil, fmt.Errorf("cannot determine locale: %v (output: %s)", err, output) } matches := appleLanguagesRegex.FindAllStringSubmatch(string(output), -1) if len(matches) == 0 { return nil, fmt.Errorf("invalid output from \"defaults read -g AppleLanguages\": %s", output) } locales := make([]string, 0, len(matches)) for _, match := range matches { locales = append(locales, match[1]) } return locales, nil } // GetLanguage retrieves the IETF BCP 47 language tag set on the system and // returns the language part of the tag. func GetLanguage() (string, error) { language := "" locale, err := GetLocale() if err == nil { language, _ = splitLocale(locale) } return language, err } // GetRegion retrieves the IETF BCP 47 language tag set on the system and // returns the region part of the tag. func GetRegion() (string, error) { region := "" locale, err := GetLocale() if err == nil { _, region = splitLocale(locale) } return region, err }