使用 i18n 更改语言时,使用 react-leaflet 更新 GeoJson 上的工具提示
Update the tooltip on GeoJson with react-leaflet when changing language with i18n
由于 react-leaflet,我目前正在显示一个带有 GeoJSON 组件的地图。
我还在某些国家/地区悬停时显示了一些工具提示(例如,当我将鼠标悬停在法国时,工具提示显示 "France")。
我也在使用 i18n 进行国际化。
问题是,当我切换语言时,它适用于整个页面,但不适用于这些工具提示。
我认为问题出在函数 onEachFeature 上,它只在创建 JSX 元素 GeoJSON 时被调用一次,因此当我们切换语言时它不会更新。
我认为是这样,因为工具提示在出现时使用正确的语言(如果语言最初设置为法语,则工具提示为法语,如果语言设置为英语,则它们将设置为英语)。但是当我们在 GeoJSON 组件初始化后更改语言时,它们根本不会更新。
我希望我已经说清楚了
这是我的界面:
interface position {
latlng: LatLngLiteral,
tooltip: string
}
interface state {
markers: position[],
zoom: number,
display: position[] | any,
geoJson: any,
countries: { [key: string]: position }
}
这是我组件开头的内容:
// t is the translation function, that should translate in the selected language. It is dynamic, it means that when we switch languages, it automatically update the translated string
const { t }: { t: TFunction } = useTranslation();
const countryToString = (countries: string[]): string => countries.join(", ");
// List of position and label of tooltip for the GeoJson object, for each country
const countries: { [key: string]: position } = {
DEU: {
latlng: {
lat: 51.0834196,
lng: 10.4234469,
},
tooltip: countryToString([
t("travel.germany.munich"),
t("travel.germany.berlin"),
t("travel.germany.hamburg"),
t("travel.germany.munster"),
t("travel.germany.country"),
])
},
CZE: {
latlng: {
lat: 49.667628,
lng: 15.326962,
},
tooltip: countryToString([
t("travel.tchequie.prague"),
t("travel.tchequie.country"),
])
},
...
}
// List of position and tooltip for the cities Markers
const cities: position[] = [
{
latlng: {
lat: 48.13825988769531,
lng: 11.584508895874023,
},
tooltip: t("travel.germany.munich"),
},
{
latlng: {
lat: 52.51763153076172,
lng: 13.40965747833252,
},
tooltip: t("travel.germany.berlin"),
},
...
我有一个国家列表,我通过 GeoJSON 组件显示它,还有一个城市列表,我通过标记列表显示它。
然后是功能部分:
// Contains the json containing the polygons of the countries
const data: geojson.FeatureCollection = geoJsonData as geojson.FeatureCollection;
let geoJson: any = <GeoJSON
key='my-geojson'
data={data}
style={() => ({
color: '#4a83ec',
weight: 1,
fillColor: "#1a1d62",
fillOpacity: 0.25,
})}
// PROBLEM : does not update the tooltips when we switch languages
// FIX ME
onEachFeature={(feature: geojson.Feature<geojson.GeometryObject>, layer: Layer) => {
layer.on({
'mouseover': (e: LeafletMouseEvent) => {
const country = state.countries[e.target.feature.properties.adm0_a3];
layer.bindTooltip(country.tooltip);
layer.openTooltip(country.latlng);
},
'mouseout': () => {
layer.unbindTooltip();
layer.closeTooltip();
},
});
}}
/>
const [state, setState] = useState<state>({
markers: cities,
zoom: 3,
geoJson: geoJson,
display: geoJson,
countries: countries
});
// Update on zoom change
function onZoom(e: LeafletMouseEvent): void {
const zoom = e.target._zoom;
const newDisplay = updateDisplay(zoom);
setState({
...state,
zoom,
display: newDisplay,
});
}
// Called on every zoom change, in order to display either the GeoJson, or the cities Marker
function updateDisplay(zoom: number): Marker[] | any {
if (zoom >= 4) {
return (state.markers.map(
(
c: position,
i: number
) => {
return (
<Marker key={c.latlng.lat + c.latlng.lng} position={c.latlng}>
<Tooltip>{c.tooltip}</Tooltip>
</Marker>
);
}
));
} else {
return state.geoJson;
}
}
return (
<Map
style={{ height: "500px" }}
center={[54.370138916189596, -29.918133437500003]}
zoom={state.zoom}
onZoomend={onZoom}
>
<TileLayer url="https://api.mapbox.com/styles/v1/mapbox/streets-v11/tiles/{z}/{x}/{y}?access_token=pk.eyJ1IjoibWFwYm94IiwiYSI6ImNpejY4NXVycTA2emYycXBndHRqcmZ3N3gifQ.rJcFIG214AriISLbB6B5aw" />
{state.display}
</Map>
);
如果你想看完整的代码,你可以在那里看到:
https://github.com/TheTisiboth/WebCV/blob/WIP/src/components/customMap.tsx
显然插件无法处理 "travel.italy.roma, travel.italy.naples, travel.italy.pompei, travel.italy.country
连接形式的多个连接字符串,而且更重要的是,您似乎需要将函数调用放在标记中(不是 100% 确定为什么因为我不熟悉这个插件 - 也许有替代品)。
<Map
style={{ height: "500px" }}
center={[54.370138916189596, -29.918133437500003]}
zoom={state.zoom}
onZoomend={onZoom}
>
<TileLayer url='https://api.mapbox.com/styles/v1/mapbox/streets-v11/tiles/{z}/{x}/{y}?access_token=pk.eyJ1IjoibWFwYm94IiwiYSI6ImNpejY4NXVycTA2emYycXBndHRqcmZ3N3gifQ.rJcFIG214AriISLbB6B5aw' />
{state.markers.map(
(c: position, i: number): ReactElement => {
if (state.zoom >= 5) {
return (
<Marker key={i} position={[c.lat, c.lon]}>
<Tooltip>{t(c.tooltip)}</Tooltip>
</Marker>
);
} else {
return (
<CircleMarker
key={i}
center={[c.lat, c.lon]}
color='red'
radius={state.radius}
>
<Tooltip>{t(c.tooltip)}</Tooltip>
</CircleMarker>
);
}
}
)}
</Map>
因为如果您记录 countries
变量,您会看到没有对该函数的引用,只有打印的字符串。所以字符串只会在第一次加载,不会因为没有函数调用而改变。
因此,处理翻译参考的更理想方式是采用如下形式:
英语:
"travel": {
"germany": "Munich, Berlin, Hamburg, Münster, Germany",
"munich": "Munich",
"tchequie": "Czech Republic, Prague",
...
}
法语:
"travel": {
"germany": "Munich, Berlin, Hambourg, Münster, Allemagne",
"munich": "Munchen",
"tchequie": "Tchéquie, Prague",
...
}
在您的自定义地图中:
let countries: position[] = [
{
// germany
lat: 51.0834196,
lon: 10.4234469,
tooltip: "travel.germany",
},
{
// tchequie
lat: 49.667628,
lon: 15.326962,
tooltip: "travel.tchequie",
},
...
]
更新:你的城市应该是这样的:
let cities: position[] = [
{
lat: 48.13825988769531,
lon: 11.584508895874023,
tooltip: "travel.munich",
},
...
]
由于 react-leaflet,我目前正在显示一个带有 GeoJSON 组件的地图。 我还在某些国家/地区悬停时显示了一些工具提示(例如,当我将鼠标悬停在法国时,工具提示显示 "France")。 我也在使用 i18n 进行国际化。 问题是,当我切换语言时,它适用于整个页面,但不适用于这些工具提示。
我认为问题出在函数 onEachFeature 上,它只在创建 JSX 元素 GeoJSON 时被调用一次,因此当我们切换语言时它不会更新。 我认为是这样,因为工具提示在出现时使用正确的语言(如果语言最初设置为法语,则工具提示为法语,如果语言设置为英语,则它们将设置为英语)。但是当我们在 GeoJSON 组件初始化后更改语言时,它们根本不会更新。
我希望我已经说清楚了
这是我的界面:
interface position {
latlng: LatLngLiteral,
tooltip: string
}
interface state {
markers: position[],
zoom: number,
display: position[] | any,
geoJson: any,
countries: { [key: string]: position }
}
这是我组件开头的内容:
// t is the translation function, that should translate in the selected language. It is dynamic, it means that when we switch languages, it automatically update the translated string
const { t }: { t: TFunction } = useTranslation();
const countryToString = (countries: string[]): string => countries.join(", ");
// List of position and label of tooltip for the GeoJson object, for each country
const countries: { [key: string]: position } = {
DEU: {
latlng: {
lat: 51.0834196,
lng: 10.4234469,
},
tooltip: countryToString([
t("travel.germany.munich"),
t("travel.germany.berlin"),
t("travel.germany.hamburg"),
t("travel.germany.munster"),
t("travel.germany.country"),
])
},
CZE: {
latlng: {
lat: 49.667628,
lng: 15.326962,
},
tooltip: countryToString([
t("travel.tchequie.prague"),
t("travel.tchequie.country"),
])
},
...
}
// List of position and tooltip for the cities Markers
const cities: position[] = [
{
latlng: {
lat: 48.13825988769531,
lng: 11.584508895874023,
},
tooltip: t("travel.germany.munich"),
},
{
latlng: {
lat: 52.51763153076172,
lng: 13.40965747833252,
},
tooltip: t("travel.germany.berlin"),
},
...
我有一个国家列表,我通过 GeoJSON 组件显示它,还有一个城市列表,我通过标记列表显示它。
然后是功能部分:
// Contains the json containing the polygons of the countries
const data: geojson.FeatureCollection = geoJsonData as geojson.FeatureCollection;
let geoJson: any = <GeoJSON
key='my-geojson'
data={data}
style={() => ({
color: '#4a83ec',
weight: 1,
fillColor: "#1a1d62",
fillOpacity: 0.25,
})}
// PROBLEM : does not update the tooltips when we switch languages
// FIX ME
onEachFeature={(feature: geojson.Feature<geojson.GeometryObject>, layer: Layer) => {
layer.on({
'mouseover': (e: LeafletMouseEvent) => {
const country = state.countries[e.target.feature.properties.adm0_a3];
layer.bindTooltip(country.tooltip);
layer.openTooltip(country.latlng);
},
'mouseout': () => {
layer.unbindTooltip();
layer.closeTooltip();
},
});
}}
/>
const [state, setState] = useState<state>({
markers: cities,
zoom: 3,
geoJson: geoJson,
display: geoJson,
countries: countries
});
// Update on zoom change
function onZoom(e: LeafletMouseEvent): void {
const zoom = e.target._zoom;
const newDisplay = updateDisplay(zoom);
setState({
...state,
zoom,
display: newDisplay,
});
}
// Called on every zoom change, in order to display either the GeoJson, or the cities Marker
function updateDisplay(zoom: number): Marker[] | any {
if (zoom >= 4) {
return (state.markers.map(
(
c: position,
i: number
) => {
return (
<Marker key={c.latlng.lat + c.latlng.lng} position={c.latlng}>
<Tooltip>{c.tooltip}</Tooltip>
</Marker>
);
}
));
} else {
return state.geoJson;
}
}
return (
<Map
style={{ height: "500px" }}
center={[54.370138916189596, -29.918133437500003]}
zoom={state.zoom}
onZoomend={onZoom}
>
<TileLayer url="https://api.mapbox.com/styles/v1/mapbox/streets-v11/tiles/{z}/{x}/{y}?access_token=pk.eyJ1IjoibWFwYm94IiwiYSI6ImNpejY4NXVycTA2emYycXBndHRqcmZ3N3gifQ.rJcFIG214AriISLbB6B5aw" />
{state.display}
</Map>
);
如果你想看完整的代码,你可以在那里看到:
https://github.com/TheTisiboth/WebCV/blob/WIP/src/components/customMap.tsx
显然插件无法处理 "travel.italy.roma, travel.italy.naples, travel.italy.pompei, travel.italy.country
连接形式的多个连接字符串,而且更重要的是,您似乎需要将函数调用放在标记中(不是 100% 确定为什么因为我不熟悉这个插件 - 也许有替代品)。
<Map
style={{ height: "500px" }}
center={[54.370138916189596, -29.918133437500003]}
zoom={state.zoom}
onZoomend={onZoom}
>
<TileLayer url='https://api.mapbox.com/styles/v1/mapbox/streets-v11/tiles/{z}/{x}/{y}?access_token=pk.eyJ1IjoibWFwYm94IiwiYSI6ImNpejY4NXVycTA2emYycXBndHRqcmZ3N3gifQ.rJcFIG214AriISLbB6B5aw' />
{state.markers.map(
(c: position, i: number): ReactElement => {
if (state.zoom >= 5) {
return (
<Marker key={i} position={[c.lat, c.lon]}>
<Tooltip>{t(c.tooltip)}</Tooltip>
</Marker>
);
} else {
return (
<CircleMarker
key={i}
center={[c.lat, c.lon]}
color='red'
radius={state.radius}
>
<Tooltip>{t(c.tooltip)}</Tooltip>
</CircleMarker>
);
}
}
)}
</Map>
因为如果您记录 countries
变量,您会看到没有对该函数的引用,只有打印的字符串。所以字符串只会在第一次加载,不会因为没有函数调用而改变。
因此,处理翻译参考的更理想方式是采用如下形式:
英语:
"travel": {
"germany": "Munich, Berlin, Hamburg, Münster, Germany",
"munich": "Munich",
"tchequie": "Czech Republic, Prague",
...
}
法语:
"travel": {
"germany": "Munich, Berlin, Hambourg, Münster, Allemagne",
"munich": "Munchen",
"tchequie": "Tchéquie, Prague",
...
}
在您的自定义地图中:
let countries: position[] = [
{
// germany
lat: 51.0834196,
lon: 10.4234469,
tooltip: "travel.germany",
},
{
// tchequie
lat: 49.667628,
lon: 15.326962,
tooltip: "travel.tchequie",
},
...
]
更新:你的城市应该是这样的:
let cities: position[] = [
{
lat: 48.13825988769531,
lon: 11.584508895874023,
tooltip: "travel.munich",
},
...
]