Baseflow / Baseflow/flutter-geocoding

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

Đang mở Phù hợp với người mới
#309 0 bình luận 0 reaction 0 người được giao Xem trên GitHub
Ngôn ngữ chính
Dart
Star
153
Fork
92
Chỉ số merge pull request
Không có pull request nào được merge trong 30 ngày

Mô tả

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

Hướng dẫn đóng góp

Mở hướng dẫn đóng góp

Hướng nghiên cứu

Bắt đầu tại geocoding_android-5.1.0/lib/src/geocoding_android.dart:164 và so sánh mã định danh locale với android/src/main/kotlin/com/baseflow/geocoding/proxies/LocaleProxyApi.kt:17. Kiểm tra các bài kiểm thử package hiện có, sau đó xác minh rằng các locale quốc gia và script được truyền đến native API dưới dạng các thẻ BCP-47 hợp lệ, đồng thời vẫn giữ nguyên khả năng bản địa hóa của Android mà không ảnh hưởng đến iOS.

Do mô hình lập chỉ mục viết ra từ nội dung của issue.

Đánh giá

Công nghệ
android, dart, flutter
Lĩnh vực
mobile
Loại issue
Lỗi
Độ khó
2/5
Thời gian dự kiến
1-3 giờ
Mức độ hoạt động
Ít trao đổi
Độ rõ ràng
Đặc tả rõ ràng
Mức phù hợp với người mới
84/100

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.