locale.go RawHistoryFolder
1package environment
2
3import (
4 "log"
5 "os"
6 "os/exec"
7 "strings"
8)
9
10// DetectAndSetKeyboardLocale attempts to determine the current keyboard layout
11// and hints it to the webkit input layer for accelerator compatibility.
12func DetectAndSetKeyboardLocale() {
13 const colonSplitParts = 2 // Number of parts when splitting on colon
14
15 var locale string
16
17 // 0) Explicit override
18 locale = os.Getenv("DUMBER_KEYBOARD_LOCALE")
19 if locale == "" {
20 locale = os.Getenv("DUMB_BROWSER_KEYBOARD_LOCALE") // legacy prefix
21 }
22
23 // 1) XKB env override (actual keyboard layout)
24 if locale == "" {
25 locale = os.Getenv("XKB_DEFAULT_LAYOUT")
26 }
27
28 // 2) Best-effort probe of localectl/setxkbmap (actual keyboard layout)
29 // Check these BEFORE LANG since LANG is system language, not keyboard layout
30 if locale == "" {
31 if out, err := exec.Command("localectl", "status").Output(); err == nil {
32 s := string(out)
33 for _, line := range strings.Split(s, "\n") {
34 line = strings.TrimSpace(line)
35 if strings.HasPrefix(strings.ToLower(line), "x11 layout:") || strings.HasPrefix(strings.ToLower(line), "keyboard layout:") {
36 parts := strings.SplitN(line, ":", colonSplitParts)
37 if len(parts) == colonSplitParts {
38 cand := strings.TrimSpace(parts[1])
39 if cand != "" {
40 locale = cand
41 log.Printf("[locale] keyboard layout from localectl: %s", locale)
42 }
43 }
44 break
45 }
46 }
47 }
48 }
49 if locale == "" {
50 if out, err := exec.Command("setxkbmap", "-query").Output(); err == nil {
51 s := string(out)
52 for _, line := range strings.Split(s, "\n") {
53 line = strings.TrimSpace(line)
54 if strings.HasPrefix(strings.ToLower(line), "layout:") {
55 parts := strings.SplitN(line, ":", colonSplitParts)
56 if len(parts) == colonSplitParts {
57 cand := strings.TrimSpace(parts[1])
58 if cand != "" {
59 locale = cand
60 log.Printf("[locale] keyboard layout from setxkbmap: %s", locale)
61 }
62 }
63 break
64 }
65 }
66 }
67 }
68
69 // 3) Fallback to system locale (language, not keyboard layout)
70 if locale == "" {
71 locale = os.Getenv("LC_ALL")
72 }
73 if locale == "" {
74 locale = os.Getenv("LANG")
75 }
76 if locale == "" {
77 locale = os.Getenv("LC_CTYPE")
78 }
79 // Trim variants from locale
80 if locale != "" {
81 if i := strings.IndexByte(locale, '.'); i > 0 {
82 locale = locale[:i]
83 }
84 if i := strings.IndexByte(locale, '@'); i > 0 {
85 locale = locale[:i]
86 }
87 if i := strings.IndexByte(locale, '_'); i > 0 {
88 locale = locale[:i]
89 }
90 log.Printf("[locale] keyboard layout from system locale: %s", locale)
91 }
92
93 if locale == "" {
94 locale = "en"
95 log.Printf("[locale] keyboard layout defaulted to: %s", locale)
96 }
97
98 log.Printf("[locale] keyboard locale detected: %s", locale)
99}