Skip to content

feat:add map language control#385

Open
rohhann12 wants to merge 5 commits into
valhalla:masterfrom
rohhann12:feat-language-support-maps-clean
Open

feat:add map language control#385
rohhann12 wants to merge 5 commits into
valhalla:masterfrom
rohhann12:feat-language-support-maps-clean

Conversation

@rohhann12
Copy link
Copy Markdown
Contributor

Starting Step to close #384

🛠️ Fixes Issue

The issue was the map would show the names of the countries in the format of their own local language (eg- middle eastern countries name would be shown in arabic).

👨‍💻 Changes proposed

-src/components/map/index.tsx
-src/components/map/map-language-control.tsx

📄 Note to reviewers

Approach:
The Shortbread OSM vector tiles use text-field: "{name}" on all symbol layers for label rendering. The tiles also provide name_en and name_de as alternative name properties.
I added a MapLanguageControl component that:

  1. Iterates over all symbol layers in the current map style
  2. Swaps the text-field layout property between {name}, {name_en}, or {name_de} based on user selection
  3. Persists the choice in localStorage so it survives page reloads and style switches (restored via onLoad and onStyleData events)
    Currently limited to 3 languages since that's all Shortbread tiles support. This can be extended once we move to Maptiler tiles which offer broader language coverage.

📷 Screenshots

Screen.Recording.2026-03-18.at.6.55.27.PM.mov

@github-actions
Copy link
Copy Markdown

Preview is ready! 🚀 You can view it here: https://valhalla-app-tests.gis-ops.com/385

@nilsnolde
Copy link
Copy Markdown
Member

the video doesn't work on my machine/browser (maybe re-encode to smth else?). and just looking at the app I have no idea how I show shortbread tiles with english/german names.

@nilsnolde
Copy link
Copy Markdown
Member

ah now it worked and my eyes didn't see the new map control. I think that's because that's a really strange place to put smth like that. we don't want 2 places with the same intention, language control. we want to rename the "directions language" dropdown and just always show it. then match to german/english for the map, everything else becomes "local".

@nilsnolde
Copy link
Copy Markdown
Member

lastly, are you sure the stadiamaps "alidade smooth" doesn't offer language support? I'd be surprised if not. probably via a header.

@rohhann12
Copy link
Copy Markdown
Contributor Author

hey @nilsnolde
updated as requested
1.Removed the separate map language control — unified it with the existing language dropdown in the settings panel
2.Renamed "Directions Language" to "Language" and made it visible on all tabs (not just directions)
3.When language is changed, it now updates both navigation instructions and map labels — en-* maps to English labels, de-DE to German, everything else falls back to local names
4. Added support for both Shortbread (string-based text-field) and Alidade Smooth (expression-based text-field) label formats
5.Alidade Smooth supports language via style modification (not request headers) — the code now handles both tile sources
https://github.com/user-attachments/assets/32de5f2d-6139-4be7-8b8d-a8f9c5aaa6fd

@rohhann12
Copy link
Copy Markdown
Contributor Author

Hi @nilsnolde
1.Updated the settings panel tests to reflect the changes — "Directions Language" is now "Language" and is visible on all tabs.
2.Also added mocks for useMap and updateMapLabels.

nilsnolde
nilsnolde previously approved these changes Mar 19, 2026
Copy link
Copy Markdown
Member

@nilsnolde nilsnolde left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks, LGTM. and there's no AI note necessary in the PR description? I should've written the guidelines in a way to always put a AI note, no matter if used or not. now it's too ambiguous..

Comment on lines +2 to +3
const base = directionsLanguage.split('-')[0];
if (base === 'en' || base === 'de') {
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

@nilsnolde
Copy link
Copy Markdown
Member

nilsnolde commented Mar 19, 2026

there's actually one small thing that's already a problem now in master: on first page load the language doesn't get set in localstorage, so even though we fall back to system language, the map or instructions serve the "default" en-US.

feel free to fix that in this PR. if not, we'll do it in a separate PR. it's more important now with (default) basemap language control than it was before with maneuver language, which the vast majority of people probably won't look at anyways when playing around.

@rohhann12
Copy link
Copy Markdown
Contributor Author

Hi @nilsnolde
So on first page load, if no language is stored in localStorage, it now resolves the system language (falling back to en-US) and persists it immediately. This way the map labels and instructions stay in sync from the start.
Let me know if we should keep it local.

@nilsnolde
Copy link
Copy Markdown
Member

Let me know if we should keep it local.

I think it's only consistent to change the behavior, i.e. only local if language doesn't have a match.

and there's no AI note necessary in the PR description?

how about this?

@rohhann12
Copy link
Copy Markdown
Contributor Author

Agreed — current behavior already does that. If the system locale matches a supported language (e.g. en-*, de-DE), it uses that for both map labels and instructions. Otherwise it falls back to local names.
No change needed there,already did that.

AI Disclosure: Code was written by me. Used AI to help reframe PR descriptions and comments for grammar corrections :D

@rohhann12 rohhann12 requested a review from nilsnolde March 19, 2026 10:06
Comment on lines +25 to +38
// Shortbread: simple string like "{name}", "{name_en}", "{name_de}"
if (typeof textField === 'string') {
if (!textField.match(/\{name(_[a-z]{2})?\}/)) continue;

const newTextField = langKey ? `{name_${langKey}}` : '{name}';
map.setLayoutProperty(layer.id, 'text-field', newTextField);
continue;
}

// Alidade Smooth: expression-based, e.g. ["get", "name:latin"]
// or ["coalesce", ["get", "name:en"], ["get", "name:latin"]]
if (Array.isArray(textField)) {
const json = JSON.stringify(textField);
if (!json.includes('"name:') && !json.includes('"name"')) continue;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

these ifs look a bit "smelly". I'm not sure if somehow making this more dependent on the MVT endpoint instead of field types (which is still a provider dependency, any MVT source can do anything to support languages) or name or whatever would make it more or less "smelly". wdyt @mustaphaturhan ?

@rohhann12 rohhann12 requested a review from nilsnolde March 23, 2026 15:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

i18n: Show English names for country labels on the map

2 participants