2021-11-22 08:39:11 +00:00
|
|
|
//go:build windows
|
2021-10-07 21:36:00 +00:00
|
|
|
// +build windows
|
|
|
|
|
|
|
|
package locale
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"unsafe"
|
|
|
|
|
|
|
|
"golang.org/x/sys/windows"
|
|
|
|
)
|
|
|
|
|
|
|
|
// LocaleNameMaxLength is the maximum length of a locale name on Windows.
|
|
|
|
// See https://docs.microsoft.com/en-us/windows/win32/intl/locale-name-constants.
|
|
|
|
const LocaleNameMaxLength uint32 = 85
|
|
|
|
|
|
|
|
func getWindowsLocaleFromProc(syscall string) (string, error) {
|
|
|
|
dll, err := windows.LoadDLL("kernel32")
|
|
|
|
if err != nil {
|
|
|
|
return "", fmt.Errorf("could not find the kernel32 DLL: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
proc, err := dll.FindProc(syscall)
|
|
|
|
if err != nil {
|
|
|
|
return "", fmt.Errorf("could not find the %s proc in kernel32: %v", syscall, err)
|
|
|
|
}
|
|
|
|
|
|
|
|
buffer := make([]uint16, LocaleNameMaxLength)
|
|
|
|
|
|
|
|
// See https://docs.microsoft.com/en-us/windows/win32/api/winnls/nf-winnls-getuserdefaultlocalename
|
|
|
|
// and https://docs.microsoft.com/en-us/windows/win32/api/winnls/nf-winnls-getsystemdefaultlocalename
|
|
|
|
// GetUserDefaultLocaleName and GetSystemDefaultLocaleName both take a buffer and a buffer size,
|
|
|
|
// and return the length of the locale name (0 if not found).
|
|
|
|
ret, _, err := proc.Call(uintptr(unsafe.Pointer(&buffer[0])), uintptr(LocaleNameMaxLength))
|
|
|
|
if ret == 0 {
|
|
|
|
return "", fmt.Errorf("locale not found when calling %s: %v", syscall, err)
|
|
|
|
}
|
|
|
|
|
|
|
|
return windows.UTF16ToString(buffer), nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func getWindowsLocale() (string, error) {
|
|
|
|
var (
|
|
|
|
locale string
|
|
|
|
err error
|
|
|
|
)
|
|
|
|
|
|
|
|
for _, proc := range [...]string{"GetUserDefaultLocaleName", "GetSystemDefaultLocaleName"} {
|
|
|
|
locale, err = getWindowsLocaleFromProc(proc)
|
|
|
|
if err == nil {
|
|
|
|
return locale, err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return locale, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetLocale retrieves the IETF BCP 47 language tag set on the system.
|
|
|
|
func GetLocale() (string, error) {
|
|
|
|
locale, err := getWindowsLocale()
|
|
|
|
if err != nil {
|
|
|
|
return "", fmt.Errorf("cannot determine locale: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
return locale, err
|
|
|
|
}
|
|
|
|
|
|
|
|
// GetLocales retrieves the IETF BCP 47 language tags set on the system.
|
|
|
|
func GetLocales() ([]string, error) {
|
|
|
|
locale, err := GetLocale()
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
return []string{locale}, 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
|
|
|
|
}
|