Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -1092,6 +1092,14 @@ public String getNetworkJson() {
}
}

/**
* Returns the device's configured locale as a BCP-47 language tag
* (e.g. "nb-NO", "en-US").
*/
public String getLocale() {
return java.util.Locale.getDefault().toLanguageTag();
}

/**
* Watch (1) / unwatch (0) the soft keyboard, emitting "common:keyboard"
* {visible,height} (height in px) via an inset listener on the content view.
Expand Down
14 changes: 14 additions & 0 deletions v3/pkg/application/locale_android.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
//go:build android

package application

// SystemLocale returns the device's configured locale as a BCP-47 language tag
// (e.g. "nb-NO", "en-US"). On Android this calls Locale.getDefault().toLanguageTag()
// via the WailsBridge.
func SystemLocale() string {
s, _ := androidBridgeString("getLocale")
if s == "" {
return "en"
}
return s
Comment thread
mortenolsrud marked this conversation as resolved.
}
42 changes: 42 additions & 0 deletions v3/pkg/application/locale_darwin.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
//go:build darwin && !ios && !server

package application

/*
#cgo CFLAGS: -x objective-c
#cgo LDFLAGS: -framework Foundation
#import <Foundation/Foundation.h>
#include <stdlib.h>

static const char* getSystemLocale() {
// Use languageIdentifier (macOS 13+ / iOS 16+) for clean BCP-47 output.
// localeIdentifier can include POSIX modifiers like @collation=pinyin.
if (@available(macOS 13, *)) {
NSString *tag = [[NSLocale currentLocale] languageIdentifier];
return strdup([tag UTF8String]);
}
// Fallback for macOS < 13: build from components to preserve script subtags
// (e.g. zh-Hant-TW, not just zh-TW).
NSLocale *locale = [NSLocale currentLocale];
NSString *lang = [locale languageCode];
NSString *script = [locale scriptCode];
NSString *country = [locale countryCode];
NSMutableString *tag = [NSMutableString stringWithString:lang ?: @"en"];
if (script.length > 0) [tag appendFormat:@"-%@", script];
if (country.length > 0) [tag appendFormat:@"-%@", country];
return strdup([tag UTF8String]);
}
*/
import "C"
import "unsafe"

// SystemLocale returns the system's configured locale as a BCP-47 language tag
// (e.g. "nb-NO", "en-US").
func SystemLocale() string {
cStr := C.getSystemLocale()
if cStr == nil {
return "en"
}
defer C.free(unsafe.Pointer(cStr))
return C.GoString(cStr)
}
10 changes: 10 additions & 0 deletions v3/pkg/application/locale_ios.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
//go:build ios

package application

// SystemLocale returns the device's configured locale as a BCP-47 language tag
// (e.g. "nb-NO", "en-US"). Delegates to the iOS mobile manager which calls
// ios_system_locale() via the CGO preamble in mobile_features_ios.go.
func SystemLocale() string {
return IOS.SystemLocale()
}
38 changes: 38 additions & 0 deletions v3/pkg/application/locale_linux.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
//go:build linux && !android && !server

package application

import (
"os"
"strings"
)

// SystemLocale returns the system's configured locale as a BCP-47 language tag
// (e.g. "nb-NO", "en-US"). Reads from LANG/LC_ALL/LC_MESSAGES environment
// variables and normalizes to BCP-47 format.
func SystemLocale() string {
// Check in order of specificity
for _, env := range []string{"LC_ALL", "LC_MESSAGES", "LANG"} {
if val := os.Getenv(env); val != "" {
return parsePosixLocale(val)
}
}
return "en"
}

// parsePosixLocale converts a POSIX locale (e.g. "nb_NO.UTF-8") to BCP-47 ("nb-NO").
func parsePosixLocale(posix string) string {
// Strip encoding (.UTF-8) and modifier (@euro)
if i := strings.IndexByte(posix, '.'); i >= 0 {
posix = posix[:i]
}
if i := strings.IndexByte(posix, '@'); i >= 0 {
posix = posix[:i]
}
// Replace underscore with hyphen (nb_NO → nb-NO)
posix = strings.ReplaceAll(posix, "_", "-")
if posix == "" || posix == "C" || posix == "POSIX" {
return "en"
}
return posix
}
34 changes: 34 additions & 0 deletions v3/pkg/application/locale_server.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
//go:build server

package application

import "os"
import "strings"

// SystemLocale returns the system's configured locale as a BCP-47 language tag.
// In server mode, reads from environment variables.
func SystemLocale() string {
for _, env := range []string{"LC_ALL", "LC_MESSAGES", "LANG"} {
if val := os.Getenv(env); val != "" {
return parsePosixLocaleBCP47(val)
}
}
return "en"
}

// parsePosixLocaleBCP47 converts a POSIX locale (e.g. "nb_NO.UTF-8@euro") to BCP-47 ("nb-NO").
func parsePosixLocaleBCP47(posix string) string {
// Strip encoding (.UTF-8) and modifier (@euro)
if i := strings.IndexByte(posix, '.'); i >= 0 {
posix = posix[:i]
}
if i := strings.IndexByte(posix, '@'); i >= 0 {
posix = posix[:i]
}
// Replace underscore with hyphen (nb_NO → nb-NO)
posix = strings.ReplaceAll(posix, "_", "-")
if posix == "" || posix == "C" || posix == "POSIX" {
return "en"
}
return posix
}
27 changes: 27 additions & 0 deletions v3/pkg/application/locale_windows.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
//go:build windows && !server

package application

import (
"syscall"
"unsafe"
)

var (
kernel32 = syscall.NewLazyDLL("kernel32.dll")
procGetUserDefaultLocaleName = kernel32.NewProc("GetUserDefaultLocaleName")
)

// SystemLocale returns the system's configured locale as a BCP-47 language tag
// (e.g. "nb-NO", "en-US").
func SystemLocale() string {
buf := make([]uint16, 85) // LOCALE_NAME_MAX_LENGTH
r, _, _ := procGetUserDefaultLocaleName.Call(
uintptr(unsafe.Pointer(&buf[0])),
uintptr(len(buf)),
)
if r == 0 {
return "en"
}
return syscall.UTF16ToString(buf)
}
1 change: 1 addition & 0 deletions v3/pkg/application/mobile.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ type MobileManager interface {
StoragePath() string
PowerJSON() string
NetworkJSON() string
SystemLocale() string

// Permissions / async results (delivered as common:* events)
BiometricAuthenticate(reason string)
Expand Down
10 changes: 10 additions & 0 deletions v3/pkg/application/mobile_features_android.go
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,16 @@ func (androidManager) PowerJSON() string { s, _ := androidBridgeString("getPower
// NetworkJSON returns {"connected":bool,"type":"wifi|cellular|ethernet|none"}.
func (androidManager) NetworkJSON() string { s, _ := androidBridgeString("getNetworkJson"); return s }

// SystemLocale returns the device's configured locale as a BCP-47 language tag
// (e.g. "nb-NO", "en-US"). Uses Locale.getDefault().toLanguageTag().
func (androidManager) SystemLocale() string {
s, _ := androidBridgeString("getLocale")
if s == "" {
return "en"
}
return s
}

// SetKeyboardWatch starts/stops emitting "common:keyboard"
// {visible,height} events as the soft keyboard shows and hides.
func (androidManager) SetKeyboardWatch(enabled bool) {
Expand Down
4 changes: 4 additions & 0 deletions v3/pkg/application/mobile_features_ios.go
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,10 @@ func (iosManager) PowerJSON() string { return cStr(C.ios_power_json()) }
// NetworkJSON returns {"connected":bool,"type":"wifi|cellular|none"}.
func (iosManager) NetworkJSON() string { return cStr(C.ios_network_json()) }

// SystemLocale returns the device's configured locale as a BCP-47 language tag
// (e.g. "nb-NO", "en-US"). Uses NSLocale.currentLocale.
func (iosManager) SystemLocale() string { return cStr(C.ios_system_locale()) }

// SetKeyboardWatch starts/stops emitting "common:keyboard" {visible,height}
// events as the software keyboard shows and hides.
func (iosManager) SetKeyboardWatch(enabled bool) { C.ios_set_keyboard_watch(C.bool(enabled)) }
Expand Down
1 change: 1 addition & 0 deletions v3/pkg/application/mobile_features_ios.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ const char* ios_storage_json(void); // {"free":bytes,"total":bytes}
const char* ios_storage_path(void); // absolute path to the app's Application Support directory
const char* ios_power_json(void); // {"level":0-1,"charging":bool,"lowPower":bool}
const char* ios_network_json(void); // {"connected":bool,"type":"wifi|cellular|none"}
const char* ios_system_locale(void); // BCP-47 language tag (e.g. "nb-NO")
void ios_set_keyboard_watch(bool enabled); // keyboard insets → "common:keyboard" {visible,height}
void ios_set_screen_protect(bool enabled); // screenshot/recording detection → "common:screenCapture"

Expand Down
19 changes: 19 additions & 0 deletions v3/pkg/application/mobile_features_ios.m
Original file line number Diff line number Diff line change
Expand Up @@ -696,6 +696,25 @@ void ios_stop_speak(void) {
return mfDup(json);
}

const char* ios_system_locale(void) {
// Use languageIdentifier which returns a clean BCP-47 tag (e.g. "en-US"),
// unlike localeIdentifier which can include POSIX modifiers and currency info.
if (@available(iOS 16, *)) {
NSString *tag = [[NSLocale currentLocale] languageIdentifier];
return mfDup(tag);
}
// Fallback for iOS < 16: build from components to preserve script subtags
// (e.g. zh-Hant-TW, not just zh-TW).
NSLocale *locale = [NSLocale currentLocale];
NSString *lang = [locale languageCode];
NSString *script = [locale scriptCode];
NSString *country = [locale countryCode];
NSMutableString *tag = [NSMutableString stringWithString:lang ?: @"en"];
if (script.length > 0) [tag appendFormat:@"-%@", script];
if (country.length > 0) [tag appendFormat:@"-%@", country];
return mfDup(tag);
}

// MARK: - Keyboard insets

static id g_mfKeyboardShowObs = nil;
Expand Down
1 change: 1 addition & 0 deletions v3/pkg/application/mobile_stub.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ func (mobileStub) StorageJSON() string { return "" }
func (mobileStub) StoragePath() string { return "" }
func (mobileStub) PowerJSON() string { return "" }
func (mobileStub) NetworkJSON() string { return "" }
func (mobileStub) SystemLocale() string { return SystemLocale() }
func (mobileStub) BiometricAuthenticate(string) {}
func (mobileStub) SecureGet(string) string { return "" }
func (mobileStub) SecureDelete(string) {}
Expand Down
Loading