Skip to content

feat(localization): add 3D map localization sample across Kotlin, Java, Compose and Snippets - #74

Draft
LoyalAbbas wants to merge 1 commit into
feat/upgrade_to_16.0.0from
feat/maps_localization
Draft

LoyalAbbas wants to merge 1 commit into
feat/upgrade_to_16.0.0from
feat/maps_localization

Conversation

@LoyalAbbas

Copy link
Copy Markdown
Collaborator

Adds the Maps Localization sample demonstrating dynamic 3D map language and region localization using LocaleOptions and GoogleMap3D.setLocale(LocaleOptions) across Kotlin Views, Java Views, Jetpack Compose, and Snippets.

Key Changes

  • Shared Clean Architecture Layer (:Maps3DSamples:ApiDemos:common):

    • Added LocalizationData.kt (MapLocalePreset, LocalizationState, DEFAULT_LOCALIZATION_CAMERA) with curated locale presets (en-US, zh-CN, fr-FR, ja-JP, es-ES, ar-SA, de-DE, and SYSTEM_DEFAULT) and toLocaleOptions() mapping.
    • Added LocalizationController.kt state machine and MapsLocalizationViewModel.kt exposing StateFlow (for Kotlin/Compose) and LiveData via asLiveData() (for Java Views).
    • Added shared control panel layout (control_panel_maps_localization.xml) and localized string resources (strings.xml).
  • 3-Way Feature Parity:

    • Kotlin Views (:Maps3DSamples:ApiDemos:kotlin-app): Added MapsLocalizationActivity.kt extending SampleBaseActivity and registered in MainActivity.kt / AndroidManifest.xml.
    • Java Views (:Maps3DSamples:ApiDemos:java-app): Added MapsLocalizationActivity.java extending SampleBaseActivity and registered in MainActivity.java / AndroidManifest.xml.
    • Jetpack Compose (:Maps3DSamples:ComposeDemos:app): Added MapsLocalizationActivity.kt with MapsLocalizationScreen and LocalizationControlCard composables, registered in MainActivity.kt / AndroidManifest.xml.
  • Documentation Snippets (:snippets:kotlin-app & :snippets:java-app):

    • Added MapLocalizationSnippets.kt and MapLocalizationSnippets.java with region tags (maps_android_3d_localization_*) demonstrating LocaleOptions and map.setLocale(localeOptions).
    • Added setLocale(LocaleOptions) pass-through to TrackedMap3D.kt and TrackedMap3D.java and registered the snippet group in SnippetRegistry.
  • Testing Suite:

    • Added Tier 2 & Tier 3 unit tests (LocalizationControllerTest.kt, MapsLocalizationViewModelTest.kt).
    • Added Tier 4 visual regression tests (MapsLocalizationVisualTest.kt, MapsLocalizationVisualTest.java).

Verification

  • Verified :Maps3DSamples:ApiDemos:common:testDebugUnitTest unit tests pass.
  • Verified Kotlin Views, Java Views, Jetpack Compose, and Snippets compile and format cleanly with spotlessApply.
  • Verified runtime language and region switching updates 3D map labels in-place without recreating Map3DView.

@LoyalAbbas
LoyalAbbas requested a review from dkhawk September 24, 2026 05:18
@LoyalAbbas
LoyalAbbas added this pull request to stack #75 September 24, 2026 05:18

@dkhawk dkhawk left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Summary & Verification

LGTM! Excellent work on this feature.

100% 3-way language parity across Kotlin Views, Java Views, Jetpack Compose, and interactive Snippets is fully verified. We tested this build on a physical Pixel 6 (using the 16.0.0 RC artifact in local Maven) and confirmed that:

  1. Runtime Localization: Language and region switching via GoogleMap3D.setLocale(LocaleOptions) successfully updates 3D map tile labels in-place without reloading the scene or recreating Map3DView.
  2. Architecture & Tests: Clean separation of concerns (Data -> Controller -> ViewModel -> Views). All Tier 2 and Tier 3 unit tests (LocalizationControllerTest, MapsLocalizationViewModelTest) pass with 100% success rate.
  3. Snippet Region Tags: Interactive documentation samples in snippets/ strictly follow Google documentation region tags (maps_android_3d_localization_*).
  4. CI Status: The 4 failing CI jobs on GitHub Actions are an expected external artifact of the parent branch stack (#67) pending the public GMaven publication of play-services-maps3d:16.0.0.

Left two minor polish suggestions inline regarding dynamic SYSTEM_DEFAULT resolution and Compose effect keying. Approving the PR!

Comment on lines +91 to +96
SYSTEM_DEFAULT(
displayName = "System Default",
nativeLabel = SYSTEM_DEFAULT_CODE,
language = Locale.getDefault().language,
region = Locale.getDefault().country,
)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

In MapLocalePreset.SYSTEM_DEFAULT, language and region are evaluated once at class initialization time as constructor arguments (Locale.getDefault().language / country). If a user changes their device system language in Android Settings while the app process is cached in memory, this enum constant will retain the stale initial locale.

Consider making language and region dynamic custom property accessors on MapLocalePreset so that selecting SYSTEM_DEFAULT always queries Locale.getDefault() dynamically:

// [START maps_android_3d_localization_preset_dynamic_locale]
enum class MapLocalePreset(
    val displayName: String,
    val nativeLabel: String,
    private val rawLanguage: String? = null,
    private val rawRegion: String? = null,
) {
    ENGLISH_US("English (US)", "en-US", "en", "US"),
    CHINESE_CHINA("Chinese (China)", "中文 (zh-CN)", "zh", "CN"),
    FRENCH_FRANCE("French (France)", "Français (fr-FR)", "fr", "FR"),
    JAPANESE_JAPAN("Japanese (Japan)", "日本語 (ja-JP)", "ja", "JP"),
    SPANISH_SPAIN("Spanish (Spain)", "Español (es-ES)", "es", "ES"),
    ARABIC_SAUDI_ARABIA("Arabic (Saudi Arabia)", "العربية (ar-SA)", "ar", "SA"),
    GERMAN_GERMANY("German (Germany)", "Deutsch (de-DE)", "de", "DE"),
    SYSTEM_DEFAULT("System Default", SYSTEM_DEFAULT_CODE);

    val language: String
        get() = rawLanguage ?: Locale.getDefault().language

    val region: String
        get() = rawRegion ?: Locale.getDefault().country
}
// [END maps_android_3d_localization_preset_dynamic_locale]

Comment on lines +132 to +134
LaunchedEffect(googleMap3DInstance, state.selectedPreset) {
googleMap3DInstance?.setLocale(state.toLocaleOptions())
}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

In MapsLocalizationScreen, LaunchedEffect is keyed on (googleMap3DInstance, state.selectedPreset). Keying on (googleMap3DInstance, state.languageCode, state.regionCode) (or state.toLocaleOptions()) directly decouples the effect from preset selection, ensuring that any custom locale modifications trigger the in-place map update even if selectedPreset does not change:

// [START maps_android_3d_localization_compose_sync_suggested]
    LaunchedEffect(googleMap3DInstance, state.languageCode, state.regionCode) {
        googleMap3DInstance?.setLocale(state.toLocaleOptions())
    }
// [END maps_android_3d_localization_compose_sync_suggested]

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.

2 participants