Skip to content

feat(android): resolve locale against declared app languages - #832

Draft
dustinbyrne wants to merge 2 commits into
mainfrom
spike/locale-resolution
Draft

dustinbyrne wants to merge 2 commits into
mainfrom
spike/locale-resolution

Conversation

@dustinbyrne

@dustinbyrne dustinbyrne commented Oct 2, 2026 •

Copy link
Copy Markdown
Contributor

💡 Motivation and Context

Discussion draft for #822. Proposes resolving Android $locale against the languages the app declares as supported, instead of always emitting the process-default language/country pair.

Proposed flow

  1. Read ordered app-specific language preferences, or system preferences when none are set.
  2. Read supported locales from localeConfig: platform APIs on Android 13+, the same packaged manifest/XML declaration on Android 6–12.
  3. Return the first matching supported tag, preferring exact matches before language/script-compatible matches. For example, de-CH can resolve to declared de.
  4. If nothing matches, use an explicitly declared default that belongs to the supported list.
  5. If information is missing, invalid, or unreadable, retain the existing Locale.getDefault() language-country value.

Packaged declarations are cached. User preferences and Android 14+ runtime locale-config overrides are read dynamically. A runtime override does not inherit the packaged declaration's default.

AppCompat remains optional: on older Android versions, the SDK reads its public locale getter reflectively only when the host provides it. There is no new required AppCompat dependency. AndroidX Core is updated from 1.5.0 to 1.9.0 to reuse its language/script matcher; the separate AndroidX test dependency versions remain unchanged. Core 1.9.0 preserves the existing consumer compile-SDK 33 floor already imposed by Lifecycle 2.6.2.

Discussion points

  • On Android 14+, detecting live supported-locale overrides currently adds a system-service lookup per event, even without a packaged declaration. Caching and invalidation are open performance questions for this proposal.

  • This changes captured values for apps with suitable declarations. A supported language-only tag may replace a language-country value. No public SDK API is added; the changeset proposes a minor release.

  • This is best-supported-language negotiation, not a guarantee of the language of every displayed string. The earlier standalone spike found differences from resource lookup in an Android 6 Chinese-script case and an Android 13 dependency-language case.

  • Apps without a declaration retain current behavior. We do not infer app support from assets.locales, which includes system and dependency locales, or assume that the first supported locale is the default.

  • The explicit XML default is not present in every app. Dynamic language delivery and live AppCompat activity recreation need further device coverage before treating this as production-ready.

💚 How did you test it?

  • Full Android release unit suite: 798 passed, 3 skipped, 0 failures (801 cases).
  • Focused locale/context tests: 61 passed in debug and release, covering API 23–35 as applicable, matching, parsing, fallback, optional AppCompat, context properties, preference changes, and runtime-override wiring. Runtime-override service responses are mocked because Robolectric does not implement that service behavior.
  • :posthog-android:assembleRelease and :posthog-android:lintRelease passed.
  • A separate consumer using the built AAR and core JAR, without AppCompat, built successfully with compile SDK 33 and R8 minification after selecting Core 1.9.0. Its device run is still pending: the local emulator refused to start because of insufficient disk space.
  • The earlier standalone spike ran installed APKs on Android 6 and 13. Those results establish the underlying declaration-reading strategy, not validation of this integrated SDK artifact.

📝 Checklist

  • I reviewed the submitted code.
  • I added tests to verify the changes.
  • I updated the docs if needed.
  • No breaking change or entry added to the changelog.

If releasing new changes

  • Ran pnpm changeset to generate a changeset file.

🤖 Agent context

Autonomy: Human-driven (agent-assisted).

Pi was used for implementation, local Gradle validation, and a fresh read-only review. The human directed the locale-matching strategy and required AppCompat to remain optional. This PR is a proposal for discussion, not a claim that the default capture change is ready to merge.

@dustinbyrne dustinbyrne self-assigned this Oct 2, 2026
@greptile-apps

greptile-apps Bot commented Oct 2, 2026 •

Copy link
Copy Markdown
Contributor

Retrigger

[Medium risk] Adds locale resolution logic for analytics events.

The PR should not merge until the AndroidX Core upgrade’s consumer build compatibility is addressed.

Reviews (1) · Last reviewed commit: "feat(android): resolve locale against de..."

val OKHTTP = "4.12.0"
val CURTAINS = "1.2.5"
val ANDROIDX_CORE = "1.5.0"
val ANDROIDX_CORE = "1.13.1"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Consumer builds may fail If a consuming app compiles against API 33 or lower, the new AndroidX Core 1.13.1 runtime dependency can require a newer compile SDK and prevent that app from building. Preserve compatibility with those consumers or make the new requirement explicit before release.

Knowledge Base Used: Roll back the Android compile SDK to 33

Prompt To Fix With AI
This is a comment left during a code review.
Path: buildSrc/src/main/java/PosthogBuildConfig.kt
Line: 69

Comment:
**Consumer builds may fail** If a consuming app compiles against API 33 or lower, the new AndroidX Core 1.13.1 runtime dependency can require a newer compile SDK and prevent that app from building. Preserve compatibility with those consumers or make the new requirement explicit before release.

**Knowledge Base Used:** [Roll back the Android compile SDK to 33](https://app.greptile.com/posthog-org-19734/-/custom-context/knowledge-base/posthog/posthog-android/-/reverts/rollback_98-20240222-android-compile-sdk-8234415.md)

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

@RequiresApi(33)
private fun currentPlatformSupport(): SupportedLocales? {
if (Build.VERSION.SDK_INT >= 34) {
val override = context.getSystemService(LocaleManager::class.java).overrideLocaleConfig

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 System lookup on every event On Android 14+, each captured event reads overrideLocaleConfig, even when the app has no locale declaration. That adds a system-service lookup to event capture where $locale previously needed only an in-process read. Avoid the per-event lookup where possible while still detecting live overrides.

Knowledge Base Used: Android SDK platform layer

Prompt To Fix With AI
This is a comment left during a code review.
Path: posthog-android/src/main/java/com/posthog/android/internal/PostHogLocaleProvider.kt
Line: 78

Comment:
**System lookup on every event** On Android 14+, each captured event reads `overrideLocaleConfig`, even when the app has no locale declaration. That adds a system-service lookup to event capture where `$locale` previously needed only an in-process read. Avoid the per-event lookup where possible while still detecting live overrides.

**Knowledge Base Used:** [Android SDK platform layer](https://app.greptile.com/posthog-org-19734/-/custom-context/knowledge-base/posthog/posthog-android/-/docs/android-sdk-platform.md)

---

For each issue above, determine whether it is valid and should be fixed. If so, fix it directly.

Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant