[Regression]: Locale silently ignored on Android — toString() emits "zh_TW" but native forLanguageTag() accepts BCP-47 only

Aperta Adatta ai principianti
#309 0 commenti 0 reazioni 0 assegnatari Vedi su GitHub

Nessuno ha ancora preso questa issue.

Valutazione

Difficoltà
2/5
Tempo stimato
1-3 ore
Idoneità per principianti
84/100
Tipo di issue
Bug
Chiarezza
Specificata chiaramente
Stato di attività
Tranquilla
Stack tecnologico
android, dart, flutter
Ambito
mobile

Direzione di ricerca

Inizia da geocoding_android-5.1.0/lib/src/geocoding_android.dart:164 e confronta l’identificatore della locale con android/src/main/kotlin/com/baseflow/geocoding/proxies/LocaleProxyApi.kt:17. Controlla i test esistenti del package, quindi verifica che le locale di paese e di script raggiungano l’API nativa come tag BCP-47 validi e che la localizzazione Android venga preservata senza influire su iOS.

Scritto dal modello di indicizzazione a partire dal testo della issue.

Descrizione

Is there an existing issue for this?
Affected platform(s)
  • Android
  • iOS
Old behavior

On geocoding_android 4.x, passing a Locale with a country subtag worked: the returned placemarks were localized to that locale. The native side converted the identifier manually (LocaleConverter.java, splitting the string on _), which accepted the underscore form that the Dart side produces.

Current behavior

On geocoding_android 5.x the locale is silently ignored — results come back in the device's default language. The call succeeds, no exception, nothing observable at the call site.

Root cause is a mismatch between the producer and the consumer of the identifier string.

Dart side serializes with toString():

// geocoding_android-5.1.0/lib/src/geocoding_android.dart:164
final Locale? nativeLocale =
    locale != null ? Locale(identifier: locale.toString()) : null;

Flutter's Locale.toString() joins subtags with an underscoreLocale('zh','TW').toString() == "zh_TW".

Native side parses with forLanguageTag():

// geocoding_android/android/src/main/kotlin/com/baseflow/geocoding/proxies/LocaleProxyApi.kt:17
return Locale.forLanguageTag(identifier);

Locale.forLanguageTag accepts BCP-47 only. Per the Javadoc: "If the specified language tag contains any ill-formed subtags, the first such subtag and all following subtags are ignored." zh_TW is a single ill-formed subtag, so the entire tag is dropped and an empty (und) Locale is returned.

Verified on JDK 21:

forLanguageTag("zh_TW")      -> language=""   country=""   toLanguageTag="und"
forLanguageTag("zh-TW")      -> language="zh" country="TW" toLanguageTag="zh-TW"
forLanguageTag("zh_Hant_TW") -> language=""   country=""   toLanguageTag="und"
forLanguageTag("en_US")      -> language=""   country=""   toLanguageTag="und"

Note that GeocoderProxyApi passes this non-null but empty Locale straight to Geocoder(context, locale), so it does not fall back to the null-locale path — the request goes out with an undetermined locale.

This affects every locale carrying a country or script subtag (en_US, pt_BR, zh_Hant_TW, …). A language-only locale such as Locale('ja') happens to still work, since "ja" is already a well-formed tag.

Side note: the README still documents the identifier format as [languageCode]_[countryCode] (underscore) — which is now precisely the form that fails.

Steps to reproduce
  1. On Android, set the device language to something other than the locale you are about to request (e.g. device in English).
  2. Call placemarkFromCoordinates(lat, lng, locale: const Locale('zh', 'TW')) — any locale with a country subtag reproduces it.
  3. Observe the returned Placemark fields: they are in the device language, not the requested one. No error is raised.
  4. Repeat with const Locale('zh-TW') (single subtag, so toString() already yields a hyphen) — the result is correctly localized.
Code sample
Code sample
// Ignored on Android (serializes to "zh_TW" -> forLanguageTag -> und):
final ignored = await Geocoding().placemarkFromCoordinates(
  25.0330, 121.5654,
  locale: const Locale('zh', 'TW'),
);

// Honored (serializes to "zh-TW"):
final honored = await Geocoding().placemarkFromCoordinates(
  25.0330, 121.5654,
  locale: const Locale('zh-TW'),
);
Suggested fix

Serialize with toLanguageTag() instead of toString() on the Dart side:

Locale(identifier: locale.toLanguageTag())   // "zh-TW"

toLanguageTag() emits exactly BCP-47, which is what forLanguageTag expects. One line, no native change required.

iOS is unaffected either way — geocoding_darwin uses Locale(identifier:), and Foundation parses "zh_TW" and "zh-TW" identically (verified on macOS: both yield language=zh region=TW). So switching to toLanguageTag() is safe for both platforms.

Workaround for users

Pass the tag as a single-subtag Dart Locale, so that toString() already produces the hyphenated form:

const Locale('zh-TW')    // toString() == "zh-TW"  -> honored
const Locale('zh', 'TW') // toString() == "zh_TW"  -> silently ignored
Current version

geocoding: 5.0.0 / geocoding_android: 5.1.0 (latest at time of writing) / geocoding_platform_interface: 5.0.0. Still present on main.

Last version without regression

geocoding_android: 4.0.1

Lingua principale
Dart
Stelle
153
Fork
92
Metriche di merge delle PR
Nessuna PR unita negli ultimi 30g

Guida per i contributori

Apri la guida per i contributori

Come iniziare

  1. Leggi tutta la issue e poi la guida ai contributi del progetto.
  2. Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
  3. Fai un fork del repository e lavora su un branch.
  4. Apri una pull request che faccia riferimento al numero della issue.

Altre issue di Baseflow/flutter-geocoding

Tutte le issue di Baseflow/flutter-geocoding

Issue simili

Altre issue su Dart

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.