fix(map): pin the GL basemap label language to the UI language (#1299)
On a GL map (Mapbox Standard) the basemap labels fell back to the browser/OS locale, so place and country names showed stacked in several scripts (e.g. 'India / भारत / India') regardless of the chosen language. Pin Mapbox Standard's basemap label language to the user's UI language via the basemap 'language' config property, mapping the few TREK codes that differ (br->pt, gr->el, zh/zhTw->zh-Hans/zh-Hant). Applies to both the trip map and the journey map; classic and MapLibre styles are left unchanged.
This commit is contained in:
parent
4e91fbca48
commit
649735726f
@ -5,7 +5,7 @@ import 'mapbox-gl/dist/mapbox-gl.css'
|
||||
import 'maplibre-gl/dist/maplibre-gl.css'
|
||||
import { useSettingsStore } from '../../store/settingsStore'
|
||||
import { isStandardFamily, supportsCustom3d, wantsTerrain, addCustom3dBuildings, addTerrainAndSky } from '../Map/mapboxSetup'
|
||||
import { MAPBOX_DEFAULT_STYLE, styleForActiveProvider, type GlMapProvider } from '../Map/glProviders'
|
||||
import { MAPBOX_DEFAULT_STYLE, styleForActiveProvider, basemapLanguage, type GlMapProvider } from '../Map/glProviders'
|
||||
|
||||
export interface JourneyMapGLHandle {
|
||||
highlightMarker: (id: string | null) => void
|
||||
@ -215,6 +215,7 @@ const JourneyMapGL = forwardRef<JourneyMapGLHandle, Props>(function JourneyMapGL
|
||||
const mapboxToken = useSettingsStore(s => s.settings.mapbox_access_token || '')
|
||||
const mapbox3d = useSettingsStore(s => s.settings.mapbox_3d_enabled !== false)
|
||||
const mapboxQuality = useSettingsStore(s => s.settings.mapbox_quality_mode === true)
|
||||
const mapLang = useSettingsStore(s => s.settings.language)
|
||||
const isMapLibre = glProvider === 'maplibre-gl'
|
||||
const gl = (isMapLibre ? maplibregl : mapboxgl) as any
|
||||
const glStyle = styleForActiveProvider(glProvider, rawMapboxStyle, rawMaplibreStyle)
|
||||
@ -375,6 +376,11 @@ const JourneyMapGL = forwardRef<JourneyMapGLHandle, Props>(function JourneyMapGL
|
||||
if (glStyle === MAPBOX_DEFAULT_STYLE) {
|
||||
try { map.setTerrain(null) } catch { /* noop */ }
|
||||
}
|
||||
// Pin the basemap label language to the UI language so labels don't fall back to the
|
||||
// browser/OS locale and stack multiple scripts per place (#1299).
|
||||
if (!isMapLibre && isStandardFamily(glStyle)) {
|
||||
try { map.setConfigProperty('basemap', 'language', basemapLanguage(mapLang)) } catch { /* style/SDK may not support it */ }
|
||||
}
|
||||
|
||||
// route trail — dashed line connecting entries in time order
|
||||
if (items.length > 1) {
|
||||
|
||||
@ -11,7 +11,7 @@ import { CATEGORY_ICON_MAP } from '../shared/categoryIcons'
|
||||
import { isStandardFamily, supportsCustom3d, wantsTerrain, addCustom3dBuildings, addTerrainAndSky } from './mapboxSetup'
|
||||
import { attachLocationMarker, type LocationMarkerHandle } from './locationMarkerMapbox'
|
||||
import { ReservationMapboxOverlay } from './reservationsMapbox'
|
||||
import { MAPBOX_DEFAULT_STYLE, styleForActiveProvider, type GlMapProvider } from './glProviders'
|
||||
import { MAPBOX_DEFAULT_STYLE, styleForActiveProvider, basemapLanguage, type GlMapProvider } from './glProviders'
|
||||
import LocationButton from './LocationButton'
|
||||
import { useGeolocation } from '../../hooks/useGeolocation'
|
||||
import type { Place, Reservation } from '../../types'
|
||||
@ -183,6 +183,7 @@ export function MapViewGL({
|
||||
const mapbox3d = useSettingsStore(s => s.settings.mapbox_3d_enabled !== false)
|
||||
const mapboxQuality = useSettingsStore(s => s.settings.mapbox_quality_mode === true)
|
||||
const showEndpointLabels = useSettingsStore(s => s.settings.map_booking_labels) !== false
|
||||
const mapLang = useSettingsStore(s => s.settings.language)
|
||||
const isMapLibre = glProvider === 'maplibre-gl'
|
||||
const gl = (isMapLibre ? maplibregl : mapboxgl) as any
|
||||
const glStyle = styleForActiveProvider(glProvider, rawMapboxStyle, rawMaplibreStyle)
|
||||
@ -412,6 +413,16 @@ export function MapViewGL({
|
||||
}
|
||||
}, [glProvider, glStyle, mapboxToken, enableMapbox3d, mapboxQuality]) // rebuild on provider/style changes only
|
||||
|
||||
// Pin the basemap label language to the UI language so labels don't fall back to the
|
||||
// browser/OS locale and stack multiple scripts per place (e.g. "India/भारत/India", #1299).
|
||||
// Mapbox Standard exposes this via a basemap config property; classic and MapLibre styles
|
||||
// are left as-is. Runs on load (mapReady) and whenever the UI language changes.
|
||||
useEffect(() => {
|
||||
const map = mapRef.current
|
||||
if (!map || !mapReady || isMapLibre || !isStandardFamily(glStyle)) return
|
||||
try { map.setConfigProperty('basemap', 'language', basemapLanguage(mapLang)) } catch { /* style/SDK may not support the basemap language property */ }
|
||||
}, [mapLang, mapReady, isMapLibre, glStyle])
|
||||
|
||||
// Photo loading — mirrors the Leaflet MapView. Updates via RAF to batch
|
||||
// simultaneous thumb arrivals into one re-render.
|
||||
const pendingThumbsRef = useRef<Record<string, string>>({})
|
||||
|
||||
@ -5,6 +5,7 @@ import {
|
||||
isOpenFreeMapStyle,
|
||||
normalizeStyleForProvider,
|
||||
styleForActiveProvider,
|
||||
basemapLanguage,
|
||||
} from './glProviders'
|
||||
|
||||
describe('glProviders', () => {
|
||||
@ -52,4 +53,20 @@ describe('glProviders', () => {
|
||||
// An empty MapLibre slot falls back to the OpenFreeMap default, leaving mapbox untouched.
|
||||
expect(styleForActiveProvider('maplibre-gl', mb, '')).toBe(OPENFREEMAP_DEFAULT_STYLE)
|
||||
})
|
||||
|
||||
it('basemapLanguage maps TREK UI codes to basemap label codes (#1299)', () => {
|
||||
// Pass-through for plain ISO 639-1 codes.
|
||||
expect(basemapLanguage('en')).toBe('en')
|
||||
expect(basemapLanguage('de')).toBe('de')
|
||||
expect(basemapLanguage('fr')).toBe('fr')
|
||||
// TREK-specific overrides.
|
||||
expect(basemapLanguage('br')).toBe('pt')
|
||||
expect(basemapLanguage('gr')).toBe('el')
|
||||
expect(basemapLanguage('zh')).toBe('zh-Hans')
|
||||
expect(basemapLanguage('zhTw')).toBe('zh-Hant')
|
||||
expect(basemapLanguage('zh-TW')).toBe('zh-Hant')
|
||||
// Falls back to English when unset.
|
||||
expect(basemapLanguage(undefined)).toBe('en')
|
||||
expect(basemapLanguage('')).toBe('en')
|
||||
})
|
||||
})
|
||||
|
||||
@ -66,3 +66,22 @@ export function styleForActiveProvider(
|
||||
): string {
|
||||
return normalizeStyleForProvider(provider, provider === 'maplibre-gl' ? maplibreStyle : mapboxStyle)
|
||||
}
|
||||
|
||||
// A few TREK UI language codes differ from what the GL basemap expects for its labels.
|
||||
const BASEMAP_LANG_OVERRIDES: Record<string, string> = {
|
||||
br: 'pt', // TREK 'br' = Brazilian Portuguese
|
||||
gr: 'el', // TREK 'gr' = Greek
|
||||
zh: 'zh-Hans',
|
||||
zhTw: 'zh-Hant',
|
||||
'zh-TW': 'zh-Hant',
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps a TREK UI language code to the label language the GL basemap expects. Used to pin
|
||||
* Mapbox Standard's basemap labels to the user's language so they don't fall back to the
|
||||
* browser/OS locale and stack multiple scripts per place (#1299).
|
||||
*/
|
||||
export function basemapLanguage(uiLang: string | undefined): string {
|
||||
const code = (uiLang || 'en').trim()
|
||||
return BASEMAP_LANG_OVERRIDES[code] ?? code
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user