From ce3af0673fffa501efd63f18f6bb95a58ab74e82 Mon Sep 17 00:00:00 2001 From: Ben James Date: Thu, 19 Feb 2026 20:57:54 +0000 Subject: [PATCH] feat: add Device.GetLocale bridge function for locale and regional settings Implements GetLocale on both Android (Kotlin) and iOS (Swift) to return device locale, language code, region, timezone, currency, and preferred language. Adds bridge manifest entry, documentation, and boost guidelines. --- README.md | 24 +++++++++++ nativephp.json | 6 +++ resources/android/DeviceFunctions.kt | 50 +++++++++++++++++++++++ resources/boost/guidelines/core.blade.php | 26 +++++++++++- resources/ios/DeviceFunctions.swift | 44 ++++++++++++++++++++ 5 files changed, 149 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 92197b2..89f59e3 100644 --- a/README.md +++ b/README.md @@ -37,6 +37,10 @@ $result = Device::getInfo(); // Get battery info $result = Device::getBatteryInfo(); // Returns: ['info' => '{"batteryLevel":0.85,"isCharging":false}'] + +// Get localization info +$localization = Device::localization(); +// Returns DeviceLocale object: $localization->locale, $localization->languageCode, etc. ``` ### JavaScript (Vue/React/Inertia) @@ -64,6 +68,12 @@ console.log('Platform:', info.platform); const batteryResult = await Device.getBatteryInfo(); const battery = JSON.parse(batteryResult.info); console.log('Battery level:', battery.batteryLevel * 100 + '%'); + +// Get localization info +const localeResult = await Device.getLocale(); +const localization = JSON.parse(localeResult.info); +console.log('Language:', localization.languageCode); +console.log('Timezone:', localization.timezone); ``` ## Methods @@ -116,6 +126,20 @@ Battery info includes: - `batteryLevel` - Battery level from 0.0 to 1.0 - `isCharging` - Whether device is charging +### `localization(): DeviceLocale` + +Get device locale and regional settings. + +**Returns:** `DeviceLocale` object (PHP) / `{ info: string }` JSON string (JS) + +Localization info includes: +- `locale` - Full locale identifier (e.g., "en_GB") +- `languageCode` - Language code (e.g., "en") +- `regionCode` - Region/country code (e.g., "GB") +- `timezone` - Timezone identifier (e.g., "America/New_York") +- `currencyCode` - Currency code (e.g., "GBP") +- `preferredLanguage` - User's preferred language (e.g., "en-GB") + ## Permissions ### Android diff --git a/nativephp.json b/nativephp.json index d560ab9..67ed5c0 100644 --- a/nativephp.json +++ b/nativephp.json @@ -31,6 +31,12 @@ "android": "com.nativephp.device.DeviceFunctions.GetBatteryInfo", "ios": "DeviceFunctions.GetBatteryInfo", "description": "Get battery level and charging status" + }, + { + "name": "Device.GetLocale", + "android": "com.nativephp.device.DeviceFunctions.GetLocale", + "ios": "DeviceFunctions.GetLocale", + "description": "Get device locale and regional settings" } ], diff --git a/resources/android/DeviceFunctions.kt b/resources/android/DeviceFunctions.kt index ee82fb6..681b047 100644 --- a/resources/android/DeviceFunctions.kt +++ b/resources/android/DeviceFunctions.kt @@ -8,6 +8,7 @@ import android.hardware.camera2.CameraManager import android.os.BatteryManager import android.os.Build import android.os.Debug +import android.os.LocaleList import android.os.VibrationEffect import android.os.Vibrator import android.os.VibratorManager @@ -276,4 +277,53 @@ object DeviceFunctions { } } } + + /** + * Get device locale and regional settings + * Parameters: none + * Returns: + * - info: JSON string with locale, language, region, timezone, currency, and preferred language + */ + class GetLocale(private val context: Context) : BridgeFunction { + override fun execute(parameters: Map): Map { + Log.d("Device.GetLocale", "Getting locale info") + + return try { + val locale = java.util.Locale.getDefault() + + val currencyCode = try { + java.util.Currency.getInstance(locale).currencyCode + } catch (e: Exception) { + "" + } + + val preferredLanguage = try { + val localeList = LocaleList.getDefault() + if (localeList.size() > 0) { + localeList.get(0).toLanguageTag() + } else { + locale.language + } + } catch (e: Exception) { + locale.language + } + + val localeInfo = JSONObject().apply { + put("locale", locale.toString()) + put("languageCode", locale.language) + put("regionCode", locale.country) + put("timezone", java.util.TimeZone.getDefault().id) + put("currencyCode", currencyCode) + put("preferredLanguage", preferredLanguage) + } + + val result = localeInfo.toString() + Log.d("Device.GetLocale", "Locale info retrieved") + mapOf("info" to result) + } catch (e: Exception) { + Log.e("Device.GetLocale", "Error: ${e.message}", e) + mapOf("info" to "{\"error\": \"${e.message}\"}") + } + } + } } diff --git a/resources/boost/guidelines/core.blade.php b/resources/boost/guidelines/core.blade.php index fc010c0..8027a35 100644 --- a/resources/boost/guidelines/core.blade.php +++ b/resources/boost/guidelines/core.blade.php @@ -26,6 +26,10 @@ // Get battery info $batteryInfo = Device::getBatteryInfo(); // batteryLevel: 0-1 (e.g., 0.85 = 85%), isCharging: true/false + +// Get localization info +$localization = Device::localization(); +// $localization->locale, $localization->languageCode, $localization->timezone, etc. @endverbatim @@ -58,6 +62,15 @@ const battery = JSON.parse(batteryResult.info); console.log(batteryResult.batteryLevel); // 0-1 console.log(batteryResult.isCharging); // true/false + +// Get localization info +const localeResult = await device.getLocale(); +const localization = JSON.parse(localeResult.info); +console.log(localization.locale); // e.g., 'en_GB' +console.log(localization.languageCode); // e.g., 'en' +console.log(localization.timezone); // e.g., 'America/New_York' +console.log(localization.currencyCode); // e.g., 'GBP' +console.log(localization.preferredLanguage); // e.g., 'en-GB' @endverbatim @@ -78,4 +91,15 @@ | Property | Type | Description | |----------|------|-------------| | batteryLevel | number | Charge percentage (0-1) | -| isCharging | boolean | Current charging status | \ No newline at end of file +| isCharging | boolean | Current charging status | + +### Localization Properties + +| Property | Type | Description | +|----------|------|-------------| +| locale | string | Full locale identifier (e.g., en_GB) | +| languageCode | string | Language code (e.g., en) | +| regionCode | string | Region/country code (e.g., GB) | +| timezone | string | Timezone identifier (e.g., America/New_York) | +| currencyCode | string | Currency code (e.g., GBP) | +| preferredLanguage | string | User's preferred language (e.g., en-GB) | \ No newline at end of file diff --git a/resources/ios/DeviceFunctions.swift b/resources/ios/DeviceFunctions.swift index b8eb902..cae19b7 100644 --- a/resources/ios/DeviceFunctions.swift +++ b/resources/ios/DeviceFunctions.swift @@ -233,4 +233,48 @@ enum DeviceFunctions { } } } + + // MARK: - Device.GetLocale + + /// Get device locale and regional settings + /// Parameters: none + /// Returns: + /// - info: JSON string with locale, language, region, timezone, currency, and preferred language + class GetLocale: BridgeFunction { + func execute(parameters: [String: Any]) throws -> [String: Any] { + print("Device.GetLocale called") + + let current = Locale.current + + let localeIdentifier = current.identifier + let languageCode = current.language.languageCode?.identifier ?? "" + let regionCode = current.region?.identifier ?? "" + let timezone = TimeZone.current.identifier + let currencyCode = current.currency?.identifier ?? "" + let preferredLanguage = Locale.preferredLanguages.first ?? (current.language.languageCode?.identifier ?? "") + + let localeInfo: [String: Any] = [ + "locale": localeIdentifier, + "languageCode": languageCode, + "regionCode": regionCode, + "timezone": timezone, + "currencyCode": currencyCode, + "preferredLanguage": preferredLanguage + ] + + print("Locale info collected") + + do { + let jsonData = try JSONSerialization.data(withJSONObject: localeInfo, options: []) + if let jsonString = String(data: jsonData, encoding: .utf8) { + return ["info": jsonString] + } else { + return ["info": "{\"error\": \"Failed to convert JSON data to string\"}"] + } + } catch { + print("Error serializing locale info: \(error)") + return ["info": "{\"error\": \"\(error.localizedDescription)\"}"] + } + } + } }