diff --git a/CHANGELOG.md b/CHANGELOG.md index 9fe6a9667c..8ba9ce4d98 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,7 @@ ## Unreleased * Ref: Rename Fragment span operation from `ui.fragment.load` to `ui.load` (#1824) +* Feat: Add locale to device context and deprecate language (#1832) * Ref: change `java.util.Random` to `java.security.SecureRandom` for possible security reasons (#1831) ## 5.4.3 diff --git a/sentry-android-core/src/main/java/io/sentry/android/core/DefaultAndroidEventProcessor.java b/sentry-android-core/src/main/java/io/sentry/android/core/DefaultAndroidEventProcessor.java index 4606736fb6..0341f95282 100644 --- a/sentry-android-core/src/main/java/io/sentry/android/core/DefaultAndroidEventProcessor.java +++ b/sentry-android-core/src/main/java/io/sentry/android/core/DefaultAndroidEventProcessor.java @@ -310,8 +310,13 @@ private void setArchitectures(final @NotNull Device device) { if (device.getId() == null) { device.setId(getDeviceId()); } + + final Locale locale = Locale.getDefault(); if (device.getLanguage() == null) { - device.setLanguage(Locale.getDefault().toString()); // eg en_US + device.setLanguage(locale.getLanguage()); + } + if (device.getLocale() == null) { + device.setLocale(locale.toString()); // eg en_US } return device; diff --git a/sentry-android-core/src/test/java/io/sentry/android/core/DefaultAndroidEventProcessorTest.kt b/sentry-android-core/src/test/java/io/sentry/android/core/DefaultAndroidEventProcessorTest.kt index ce1697cbcf..904a2c6f1e 100644 --- a/sentry-android-core/src/test/java/io/sentry/android/core/DefaultAndroidEventProcessorTest.kt +++ b/sentry-android-core/src/test/java/io/sentry/android/core/DefaultAndroidEventProcessorTest.kt @@ -27,6 +27,7 @@ import io.sentry.protocol.SentryTransaction import io.sentry.protocol.User import io.sentry.test.getCtor import org.junit.runner.RunWith +import java.util.Locale import kotlin.test.BeforeTest import kotlin.test.Test import kotlin.test.assertEquals @@ -44,6 +45,10 @@ class DefaultAndroidEventProcessorTest { private val className = "io.sentry.android.core.DefaultAndroidEventProcessor" private val ctorTypes = arrayOf(Context::class.java, ILogger::class.java, IBuildInfoProvider::class.java) + init { + Locale.setDefault(Locale.US) + } + private class Fixture { val buildInfo = mock() val options = SentryOptions().apply { @@ -376,4 +381,15 @@ class DefaultAndroidEventProcessorTest { // assertNotNull(device.connectionType) } } + + @Test + fun `Event sets language and locale`() { + val sut = fixture.getSut(context) + + assertNotNull(sut.process(SentryEvent(), null)) { + val device = it.contexts.device!! + assertEquals("en", device.language) + assertEquals("en_US", device.locale) + } + } } diff --git a/sentry/api/sentry.api b/sentry/api/sentry.api index 51e89b8755..4d183bb41e 100644 --- a/sentry/api/sentry.api +++ b/sentry/api/sentry.api @@ -1532,6 +1532,7 @@ public final class io/sentry/protocol/Device : io/sentry/IUnknownPropertiesConsu public fun getFreeStorage ()Ljava/lang/Long; public fun getId ()Ljava/lang/String; public fun getLanguage ()Ljava/lang/String; + public fun getLocale ()Ljava/lang/String; public fun getManufacturer ()Ljava/lang/String; public fun getMemorySize ()Ljava/lang/Long; public fun getModel ()Ljava/lang/String; @@ -1563,6 +1564,7 @@ public final class io/sentry/protocol/Device : io/sentry/IUnknownPropertiesConsu public fun setFreeStorage (Ljava/lang/Long;)V public fun setId (Ljava/lang/String;)V public fun setLanguage (Ljava/lang/String;)V + public fun setLocale (Ljava/lang/String;)V public fun setLowMemory (Ljava/lang/Boolean;)V public fun setManufacturer (Ljava/lang/String;)V public fun setMemorySize (Ljava/lang/Long;)V diff --git a/sentry/src/main/java/io/sentry/protocol/Device.java b/sentry/src/main/java/io/sentry/protocol/Device.java index d36361f05b..2a16faa410 100644 --- a/sentry/src/main/java/io/sentry/protocol/Device.java +++ b/sentry/src/main/java/io/sentry/protocol/Device.java @@ -93,7 +93,18 @@ public final class Device implements IUnknownPropertiesConsumer { private @Nullable TimeZone timezone; private @Nullable String id; - private @Nullable String language; + + /** + * This method returns the language code for this locale, which will either be the empty string or + * a lowercase ISO 639 code. + * + * @deprecated use {@link Device#getLocale()} + */ + @Deprecated private @Nullable String language; + + /** The locale of the device. For example, en-US. */ + private @Nullable String locale; + private @Nullable String connectionType; /** battery's temperature in celsius */ @@ -135,6 +146,7 @@ public Device() {} this.batteryLevel = device.batteryLevel; final String[] archsRef = device.archs; this.archs = archsRef != null ? archsRef.clone() : null; + this.locale = device.locale; final TimeZone timezoneRef = device.timezone; this.timezone = timezoneRef != null ? (TimeZone) timezoneRef.clone() : null; @@ -384,6 +396,14 @@ public void setBatteryTemperature(final @Nullable Float batteryTemperature) { this.batteryTemperature = batteryTemperature; } + public @Nullable String getLocale() { + return locale; + } + + public void setLocale(final @Nullable String locale) { + this.locale = locale; + } + @TestOnly @Nullable Map getUnknown() {