feat(localization): add 3D map localization sample across Kotlin, Java, Compose and Snippets - #74
LoyalAbbas wants to merge 1 commit into
Conversation
…a, Compose, and Snippets
dkhawk
left a comment
There was a problem hiding this comment.
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:
- Runtime Localization: Language and region switching via
GoogleMap3D.setLocale(LocaleOptions)successfully updates 3D map tile labels in-place without reloading the scene or recreatingMap3DView. - 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. - Snippet Region Tags: Interactive documentation samples in
snippets/strictly follow Google documentation region tags (maps_android_3d_localization_*). - 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!
| SYSTEM_DEFAULT( | ||
| displayName = "System Default", | ||
| nativeLabel = SYSTEM_DEFAULT_CODE, | ||
| language = Locale.getDefault().language, | ||
| region = Locale.getDefault().country, | ||
| ) |
There was a problem hiding this comment.
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]| LaunchedEffect(googleMap3DInstance, state.selectedPreset) { | ||
| googleMap3DInstance?.setLocale(state.toLocaleOptions()) | ||
| } |
There was a problem hiding this comment.
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]
Adds the Maps Localization sample demonstrating dynamic 3D map language and region localization using
LocaleOptionsandGoogleMap3D.setLocale(LocaleOptions)across Kotlin Views, Java Views, Jetpack Compose, and Snippets.Key Changes
Shared Clean Architecture Layer (
:Maps3DSamples:ApiDemos:common):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, andSYSTEM_DEFAULT) andtoLocaleOptions()mapping.LocalizationController.ktstate machine andMapsLocalizationViewModel.ktexposingStateFlow(for Kotlin/Compose) andLiveDataviaasLiveData()(for Java Views).control_panel_maps_localization.xml) and localized string resources (strings.xml).3-Way Feature Parity:
:Maps3DSamples:ApiDemos:kotlin-app): AddedMapsLocalizationActivity.ktextendingSampleBaseActivityand registered inMainActivity.kt/AndroidManifest.xml.:Maps3DSamples:ApiDemos:java-app): AddedMapsLocalizationActivity.javaextendingSampleBaseActivityand registered inMainActivity.java/AndroidManifest.xml.:Maps3DSamples:ComposeDemos:app): AddedMapsLocalizationActivity.ktwithMapsLocalizationScreenandLocalizationControlCardcomposables, registered inMainActivity.kt/AndroidManifest.xml.Documentation Snippets (
:snippets:kotlin-app&:snippets:java-app):MapLocalizationSnippets.ktandMapLocalizationSnippets.javawith region tags (maps_android_3d_localization_*) demonstratingLocaleOptionsandmap.setLocale(localeOptions).setLocale(LocaleOptions)pass-through toTrackedMap3D.ktandTrackedMap3D.javaand registered the snippet group inSnippetRegistry.Testing Suite:
LocalizationControllerTest.kt,MapsLocalizationViewModelTest.kt).MapsLocalizationVisualTest.kt,MapsLocalizationVisualTest.java).Verification
:Maps3DSamples:ApiDemos:common:testDebugUnitTestunit tests pass.spotlessApply.Map3DView.