Baseflow / Baseflow/flutter-geocoding

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

Ouverte Adaptée aux débutants
#309 0 commentaires 0 réactions 0 personnes assignées Voir sur GitHub
Langage dominant
Dart
Étoiles
153
Forks
92
Métriques de merge des PR
Aucune PR mergée en 30 j

Description

### Is there an existing issue for this?

- [x] I have searched the [existing issues](https://github.com/baseflow/flutter-geocoding/issues) — found none covering this.

### Affected platform(s)

- [x] 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()`:

```dart
// 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 **underscore** — `Locale('zh','TW').toString() == "zh_TW"`.

Native side parses with `forLanguageTag()`:

```kotlin
// 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

```dart
// 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:

```dart
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:

```dart
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`

Guide de contribution

Ouvrir le guide de contribution

Piste de recherche

Commencez dans geocoding_android-5.1.0/lib/src/geocoding_android.dart:164 et comparez l’identifiant de locale avec android/src/main/kotlin/com/baseflow/geocoding/proxies/LocaleProxyApi.kt:17. Vérifiez les tests existants du package, puis assurez-vous que les locales de pays et de script parviennent à l’API native sous forme de balises BCP-47 valides et que la localisation Android est préservée sans affecter iOS.

Rédigé par le modèle d'indexation à partir du texte de l'issue.

Évaluation

Stack technique
android, dart, flutter
Domaine
mobile
Type d'issue
Bug
Difficulté
2/5
Temps estimé
1-3 heures
Activité
Calme
Clarté
Clairement spécifiée
Accessibilité débutants
84/100

Recevez les nouvelles issues par e-mail

Un résumé court des issues GitHub adaptées aux débutants.