Fix locale detection on Windows and Linux
This commit is contained in:
parent
7b39bc5df8
commit
ab5a48b3c1
11 changed files with 172 additions and 34 deletions
|
@ -1,3 +1,6 @@
|
|||
1.4.1:
|
||||
- Fix locale detection on Windows and Linux
|
||||
|
||||
1.4.0:
|
||||
- Auto-scale font size to fit text
|
||||
- Support returning to the main menu
|
||||
|
|
18
flags.go
18
flags.go
|
@ -11,6 +11,7 @@ import (
|
|||
"os"
|
||||
"os/exec"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"code.rocket9labs.com/tslocum/bgammon"
|
||||
|
@ -87,14 +88,21 @@ func parseFlags() *game.Game {
|
|||
|
||||
var forceLanguage *language.Tag
|
||||
if locale == "" {
|
||||
locale = game.DefaultLocale()
|
||||
var err error
|
||||
locale, err = game.GetLocale()
|
||||
if err != nil {
|
||||
locale = ""
|
||||
}
|
||||
}
|
||||
if locale != "" {
|
||||
tag, err := language.Parse(locale)
|
||||
if err != nil {
|
||||
log.Fatalf("unknown locale: %s", locale)
|
||||
dotIndex := strings.IndexByte(locale, '.')
|
||||
if dotIndex != -1 {
|
||||
locale = locale[:dotIndex]
|
||||
}
|
||||
tag, err := language.Parse(locale)
|
||||
if err == nil {
|
||||
forceLanguage = &tag
|
||||
}
|
||||
forceLanguage = &tag
|
||||
}
|
||||
game.LoadLocale(forceLanguage)
|
||||
|
||||
|
|
|
@ -9,8 +9,8 @@ import (
|
|||
|
||||
func parseFlags() *game.Game {
|
||||
var forceLanguage *language.Tag
|
||||
locale := game.DefaultLocale()
|
||||
if locale != "" {
|
||||
locale, err := game.GetLocale()
|
||||
if err == nil && locale != "" {
|
||||
tag, err := language.Parse(locale)
|
||||
if err == nil {
|
||||
forceLanguage = &tag
|
||||
|
|
|
@ -7,7 +7,6 @@ import (
|
|||
"fmt"
|
||||
"log"
|
||||
"net"
|
||||
"runtime/debug"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
|
@ -89,7 +88,6 @@ func (c *Client) LoggedIn() bool {
|
|||
|
||||
func (c *Client) connectWebSocket() {
|
||||
if !c.connecting {
|
||||
debug.PrintStack()
|
||||
return
|
||||
}
|
||||
|
||||
|
@ -101,7 +99,6 @@ func (c *Client) connectWebSocket() {
|
|||
}
|
||||
for {
|
||||
if !c.connecting {
|
||||
debug.PrintStack()
|
||||
return
|
||||
}
|
||||
if !focused() {
|
||||
|
|
|
@ -15,7 +15,6 @@ import (
|
|||
"time"
|
||||
|
||||
"code.rocket9labs.com/tslocum/gotext"
|
||||
"golang.org/x/text/language"
|
||||
)
|
||||
|
||||
const (
|
||||
|
@ -61,21 +60,6 @@ func init() {
|
|||
return
|
||||
}
|
||||
time.Local = tz
|
||||
|
||||
// Detect locale.
|
||||
out, err = exec.Command("/system/bin/getprop", "persist.sys.locale").Output()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
tag, err := language.Parse(strings.TrimSpace(string(out)))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
LoadLocale(&tag)
|
||||
}
|
||||
|
||||
func DefaultLocale() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func focused() bool {
|
||||
|
|
|
@ -21,10 +21,6 @@ const (
|
|||
targetFPS = 144
|
||||
)
|
||||
|
||||
func DefaultLocale() string {
|
||||
return ""
|
||||
}
|
||||
|
||||
func focused() bool {
|
||||
return true
|
||||
}
|
||||
|
|
|
@ -36,10 +36,6 @@ func init() {
|
|||
}
|
||||
}
|
||||
|
||||
func DefaultLocale() string {
|
||||
return js.Global().Get("navigator").Get("language").String()
|
||||
}
|
||||
|
||||
func focused() bool {
|
||||
document := js.Global().Get("document")
|
||||
hasFocus := document.Call("hasFocus", nil)
|
||||
|
|
31
game/locale_android.go
Normal file
31
game/locale_android.go
Normal file
|
@ -0,0 +1,31 @@
|
|||
//go:build android
|
||||
|
||||
package game
|
||||
|
||||
import (
|
||||
"os/exec"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/text/language"
|
||||
)
|
||||
|
||||
func init() {
|
||||
// Load locale early on Android.
|
||||
locale, err := GetLocale()
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
tag, err := language.Parse(strings.TrimSpace(locale))
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
LoadLocale(&tag)
|
||||
}
|
||||
|
||||
func GetLocale() (string, error) {
|
||||
out, err := exec.Command("/system/bin/getprop", "persist.sys.locale").Output()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return string(out), nil
|
||||
}
|
11
game/locale_linux.go
Normal file
11
game/locale_linux.go
Normal file
|
@ -0,0 +1,11 @@
|
|||
//go:build linux && !android
|
||||
|
||||
package game
|
||||
|
||||
import (
|
||||
"os"
|
||||
)
|
||||
|
||||
func GetLocale() (string, error) {
|
||||
return os.Getenv("LANG"), nil
|
||||
}
|
9
game/locale_wasm.go
Normal file
9
game/locale_wasm.go
Normal file
|
@ -0,0 +1,9 @@
|
|||
//go:build js && wasm
|
||||
|
||||
package game
|
||||
|
||||
import "syscall/js"
|
||||
|
||||
func GetLocale() (string, error) {
|
||||
return js.Global().Get("navigator").Get("language").String(), nil
|
||||
}
|
103
game/locale_windows.go
Normal file
103
game/locale_windows.go
Normal file
|
@ -0,0 +1,103 @@
|
|||
//go:build windows
|
||||
|
||||
package game
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"unsafe"
|
||||
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
// Source code in this file was copied from https://github.com/jeandeaual/go-locale
|
||||
// The following license applies to the source code in this file:
|
||||
//
|
||||
// MIT License
|
||||
//
|
||||
// Copyright (c) 2020 Alexis Jeandeau
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
// 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 splitLocale(locale string) (string, string) {
|
||||
// Remove the encoding, if present.
|
||||
formattedLocale, _, _ := strings.Cut(locale, ".")
|
||||
|
||||
// Normalize by replacing the hyphens with underscores
|
||||
formattedLocale = strings.ReplaceAll(formattedLocale, "-", "_")
|
||||
|
||||
// Split at the underscore.
|
||||
language, territory, _ := strings.Cut(formattedLocale, "_")
|
||||
return language, territory
|
||||
}
|
||||
|
||||
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
|
||||
}
|
Loading…
Reference in a new issue