diff --git a/folium/features.py b/folium/features.py index 587f5e053b..1638920697 100644 --- a/folium/features.py +++ b/folium/features.py @@ -757,8 +757,10 @@ def process_data(self, data: Any) -> dict: else: # This is a filename if not self.embed: self.embed_link = data - with open(data) as f: - return json.loads(f.read()) + # Read bytes so json can detect the encoding (UTF-8 per RFC 7946) + # instead of decoding with the platform's locale encoding. + with open(data, "rb") as f: + return json.load(f) elif hasattr(data, "__geo_interface__"): self.embed = True if hasattr(data, "to_crs"): diff --git a/tests/test_features.py b/tests/test_features.py index e41e0e8337..c05d57c7f1 100644 --- a/tests/test_features.py +++ b/tests/test_features.py @@ -232,6 +232,24 @@ def test_geojson_tooltip(): ), "GeoJsonTooltip GeometryCollection test failed." +@pytest.mark.parametrize("encoding", ["utf-8", "utf-8-sig"]) +def test_geojson_from_utf8_file(tmp_path, encoding): + data = { + "type": "FeatureCollection", + "features": [ + { + "type": "Feature", + "properties": {"name": "東京都", "alt": "Hämeenlinna"}, + "geometry": {"type": "Point", "coordinates": [139.69, 35.69]}, + } + ], + } + path = tmp_path / "data.geojson" + path.write_text(json.dumps(data, ensure_ascii=False), encoding=encoding) + + assert GeoJson(str(path)).data == data + + # GeoJsonMarker type validation. def test_geojson_marker(): m = folium.Map([30.4, -97.5], zoom_start=10)