Map features
-Add layers
-+
Map features
+Add layers
+This map starts empty on purpose. Users bring their own services — paste a URL, pick from the capabilities, done.
+
Try it: the + button in the layer panel. Paste
https://data.wien.gv.at/daten/geo as WMS (375 layers, use the filter box), or
switch to WMTS and paste
@@ -28,20 +28,20 @@
Add layers
What this demo shows
+What this demo shows
-
-
- WMS and WMTS capabilities parsed in the browser — no server component involved -
- Filterable layer list with multi-select for services with hundreds of layers -
- Layers arrive fully wired: GetFeatureInfo, legend, metadata link, and a zoom range derived from the service's scale hints -
- Layers without a WebMercator offering are flagged before you add them (D-02) -
- Added layers appear in their own section of the panel and can be removed again +
- WMS and WMTS capabilities parsed in the browser — no server component involved +
- Filterable layer list with multi-select for services with hundreds of layers +
- Layers arrive fully wired: GetFeatureInfo, legend, metadata link, and a zoom range derived from the service's scale hints +
- Layers without a WebMercator offering are flagged before you add them (D-02) +
- Added layers appear in their own section of the panel and can be removed again
+
User-added layers never touch the page config. They live in session state — and, because
this demo also enables permalink, they travel in the share link, so a
colleague opens the map with your services already loaded.
What this demo shows
Configuration
+Configuration
-Set allowAdd: false for a locked-down map where only configured layers exist.
Set allowAdd: false for a locked-down map where only configured layers exist.
The same thing from code
+The same thing from code
const api = document.querySelector('map0-viewer').api;
diff --git a/site/demos/cog.html b/site/demos/cog.html
index 4265534..ff09a1e 100644
--- a/site/demos/cog.html
+++ b/site/demos/cog.html
@@ -3,7 +3,7 @@
- Cloud Optimized GeoTIFF — map0 demos
+ Cloud Optimized GeoTIFF — map0 demos
@@ -11,9 +11,9 @@
- Data sources
+ Data sources
Cloud Optimized GeoTIFF
-
+
A raster file on plain storage, read directly by the browser — no tile server, no
server-side rendering. HTTP range requests fetch only the tiles in view. One map per
rendering mode below: RGB imagery, a DEM as terrain, and a classified single-band raster
@@ -22,14 +22,14 @@
Cloud Optimized GeoTIFF
- Imagery — a URL is enough
-
+
Imagery — a URL is enough
+
An RGB orthophoto over Catalonia. The layer definition is nothing but a URL: bounds and
zoom range come from the file's own header.
-
+
Try it: open the network tab and pan around — only small byte ranges of
the 50 MB file are ever fetched, and tiles already seen never hit the network again.
@@ -38,8 +38,8 @@ Imagery — a URL is enough
Terrain — one DEM, two renderings
-+
Terrain — one DEM, two renderings
+
The same 3 MB elevation file (BEV 25 m terrain model, Großglockner region)
drives two layers: hillshade renders relief shading,
color maps the elevation band onto a hypsometric ramp. The legend derives
@@ -47,7 +47,7 @@
Terrain — one DEM, two renderings
+
Try it: toggle either layer off to see the other alone. A hillshade paints only shadows and highlights — flat terrain stays see-through — and its opacity slider scales the shading intensity. @@ -57,8 +57,8 @@
Terrain — one DEM, two renderings
Classification — your own values and colors
-+
Classification — your own values and colors
+
A ramp never fits categorical data. color.classes styles exact pixel values
(or from–to ranges) with hand-picked colors instead — here a binary sealed-surfaces
raster for all of Austria, 1.3 GB on a plain bucket. The legend takes one labelled
@@ -66,7 +66,7 @@
Classification — your own values and colors
+
Try it: the unsealed class uses an 8-digit hex color — the last two digits are alpha, so the basemap shows through. Drop that class from the config and unsealed pixels disappear entirely. @@ -76,16 +76,16 @@
Classification — your own values and colors
What these demos show
+What these demos show
-
-
- A
coglayer needs nothing but a URL — bounds and zoom range come from the file's own header
- colormaps a single band onto a named ramp (ColorBrewer/CARTOColors), discrete classes or continuous
- color.classesinstead styles exact values or from–to ranges directly, with hand-picked colors and labels
- hillshaderenders a single-band DEM as relief shading (exaggeration, light direction, colors)
- - The legend panel derives its entries from the color ramp or the classes automatically -
- The decoder (geotiff.js, ~150 KB) loads on demand — configs without a COG layer never pay for it +
- A
coglayer needs nothing but a URL — bounds and zoom range come from the file's own header
+ colormaps a single band onto a named ramp (ColorBrewer/CARTOColors), discrete classes or continuous
+ color.classesinstead styles exact values or from–to ranges directly, with hand-picked colors and labels
+ hillshaderenders a single-band DEM as relief shading (exaggeration, light direction, colors)
+ - The legend panel derives its entries from the color ramp or the classes automatically +
- The decoder (geotiff.js, ~150 KB) loads on demand — configs without a COG layer never pay for it
+
Ramp names follow the source palettes: Brewer<Name><classes>
(e.g. BrewerSpectral9, 3–12 classes depending on the palette) and
Carto<Name> (e.g. CartoEarth). The protocol library
@@ -93,7 +93,7 @@
What these demos show
color scheme cheatsheet. A typo fails fast — the layer turns to error state with "… is not a supported color scheme". -+
Class ranges follow one fixed rule instead of an inclusive/exclusive knob:
from is inclusive, to is exclusive — except the class with the
highest to, which includes it, so the data maximum never falls off the top
@@ -101,7 +101,7 @@
What these demos show
classes with a ramp or hillshade rendering on one page (the per-pixel color
function is keyed by the COG URL).
- What these demos show
When to reach for COG
-+
When to reach for COG
+COG is the raster twin of PMTiles: publish one file on any static bucket that supports range requests and you have a zoomable overlay — orthophotos, elevation, model output, sensor rasters. For nationwide imagery with heavy traffic, a tiled service (WMTS) with a CDN in front still wins; for the long tail of project rasters that would otherwise need their own GeoServer, a COG on object storage is hard to beat.
-+
The protocol behind this layer type is @geomatico/maplibre-cog-protocol (pre-1.0, pinned): RGB and grayscale imagery, single-band color ramps and DEM hillshading. diff --git a/site/demos/coordinates.html b/site/demos/coordinates.html index 792e770..5c710bb 100644 --- a/site/demos/coordinates.html +++ b/site/demos/coordinates.html @@ -3,7 +3,7 @@
-Map features
-Coordinates
-+
Map features
+Coordinates
+The map renders in Web Mercator — but nobody in an Austrian office writes down Web Mercator. Coordinates are displayed in whichever systems your users actually need.
+
Try it: right-click anywhere (or press and hold on a touch device). Each row has a copy button.
What this demo shows
+What this demo shows
-
-
- Right-click and long-press both open the readout -
- Reprojection happens client-side with proj4 — no service call -
- Built-in definitions: MGI/Gauss-Krueger M28, M31, M34, Austria Lambert and all UTM zones -
- Any other CRS works by supplying a proj4
defin the config (EPSG:3416 below)
+ - Right-click and long-press both open the readout +
- Reprojection happens client-side with proj4 — no service call +
- Built-in definitions: MGI/Gauss-Krueger M28, M31, M34, Austria Lambert and all UTM zones +
- Any other CRS works by supplying a proj4
defin the config (EPSG:3416 below)
+
Without a crs list map0 chooses sensibly by itself: WGS 84, the Gauss-Krueger
strip matching the clicked longitude, and the matching UTM zone. That default is what the
other demos on this site use.
What this demo shows
Configuration
+Configuration
-Defaults, or off
+Defaults, or off
"controls": {
"coordinates": true, // WGS 84 + matching GK strip + matching UTM zone
diff --git a/site/demos/demo.css b/site/demos/demo.css
index 7ee16d5..faffeaf 100644
--- a/site/demos/demo.css
+++ b/site/demos/demo.css
@@ -166,6 +166,25 @@ a {
display: none;
}
+/* language switcher */
+.lang {
+ display: inline-flex;
+ gap: 2px;
+ padding: 2px;
+ border: 1px solid var(--border);
+ border-radius: 9px;
+}
+.topbar nav .lang a {
+ padding: 1px 7px;
+ border-radius: 6px;
+ font-size: 12.5px;
+ font-weight: 600;
+}
+.topbar nav .lang a[aria-current] {
+ background: color-mix(in srgb, var(--accent) 14%, transparent);
+ color: var(--accent);
+}
+
.topbar nav a.gh svg {
display: block;
fill: currentColor;
@@ -590,12 +609,13 @@ footer.site a.footmark {
.topbar .wrap {
padding: 0 16px;
}
- /* the toggle joined the topbar; the landing anchor links are the ones a
- small screen can do without */
+ /* the toggle and switcher joined the topbar; the landing anchor links are
+ the ones a small screen can do without */
.topbar nav {
gap: 14px;
}
- .topbar nav a[href^="/#"] {
+ .topbar nav a[href^="/#"],
+ .topbar nav a[href^="/de/#"] {
display: none;
}
map0-viewer {
diff --git a/site/demos/demo.ts b/site/demos/demo.ts
index 4b9ff8a..de0c34c 100644
--- a/site/demos/demo.ts
+++ b/site/demos/demo.ts
@@ -3,8 +3,9 @@
* and footer are injected by vite.config.ts on every page of the site).
* Code blocks come from ../code.ts, which the landing page uses as well.
*/
-import { DEMOS, GROUPS, type Demo } from "./demos.js";
+import { DEMOS, GROUPS, GROUP_LABELS_DE, type Demo } from "./demos.js";
import { enhanceCode } from "../code.js";
+import { LANG, LANG_PREFIX } from "../lang.js";
/* The standalone demo ships the built bundle and registers the element itself.
It must NOT fall back to the sources: a silent fallback would make a broken
@@ -13,14 +14,19 @@ if (document.body.dataset.client !== "bundle") await import("@map0/ui");
/* --------------------------------- chrome -------------------------------- */
+const title = (d: Demo): string => (LANG === "de" && d.titleDe) || d.title;
+const blurb = (d: Demo): string => (LANG === "de" ? d.blurbDe : d.blurb);
+const href = (d: Demo): string => `${LANG_PREFIX}/demos/${d.id}.html`;
+
function pager(current: Demo): string {
const i = DEMOS.findIndex((d) => d.id === current.id);
const prev = DEMOS[i - 1];
const next = DEMOS[i + 1];
+ const [prevLabel, nextLabel] = LANG === "de" ? ["Zurück", "Weiter"] : ["Previous", "Next"];
return `
- ${prev ? `Previous${prev.icon} ${prev.title}` : ""}
- ${next ? `Next${next.icon} ${next.title}` : ""}
+ ${prev ? `${prevLabel}${prev.icon} ${title(prev)}` : ""}
+ ${next ? `${nextLabel}${next.icon} ${title(next)}` : ""}
`;
}
@@ -29,14 +35,15 @@ function gallery(): string {
const cards = DEMOS.filter((d) => d.group === group)
.map(
(d) => `
-
+
${d.icon}
- ${d.title}
- ${d.blurb}
+ ${title(d)}
+ ${blurb(d)}
`,
)
.join("");
- return `${group}
${cards}`;
+ const label = LANG === "de" ? GROUP_LABELS_DE[group] : group;
+ return `${label}
${cards}`;
}).join("");
}
diff --git a/site/demos/demos.ts b/site/demos/demos.ts
index 81d6527..848108e 100644
--- a/site/demos/demos.ts
+++ b/site/demos/demos.ts
@@ -3,7 +3,10 @@
export interface Demo {
id: string;
title: string;
+ /** German title — omitted where the English one is a proper name anyway */
+ titleDe?: string;
blurb: string;
+ blurbDe: string;
group: "Data sources" | "Map features" | "Configuration" | "Integration";
icon: string;
}
@@ -13,6 +16,7 @@ export const DEMOS: Demo[] = [
id: "wms",
title: "WMS",
blurb: "Raster map services with GetFeatureInfo popups and GetLegendGraphic legends.",
+ blurbDe: "Raster-Kartendienste mit GetFeatureInfo-Popups und GetLegendGraphic-Legenden.",
group: "Data sources",
icon: "🗺️",
},
@@ -20,20 +24,25 @@ export const DEMOS: Demo[] = [
id: "wmts",
title: "WMTS",
blurb: "Tiled services resolved straight from GetCapabilities — matrix set, style and mirrors.",
+ blurbDe: "Kacheldienste direkt aus den GetCapabilities aufgelöst — Matrix-Set, Style und Mirrors.",
group: "Data sources",
icon: "🧱",
},
{
id: "vector-tiles",
title: "Vector tiles",
+ titleDe: "Vector Tiles",
blurb: "MVT overlays styled with the MapLibre style spec; PMTiles works the same way.",
+ blurbDe: "MVT-Overlays, gestylt mit der MapLibre-Style-Spezifikation; PMTiles funktioniert genauso.",
group: "Data sources",
icon: "🔺",
},
{
id: "geojson",
title: "GeoJSON & clustering",
+ titleDe: "GeoJSON & Clustering",
blurb: "Remote and inline GeoJSON, simplified styling and built-in point clustering.",
+ blurbDe: "Externes und eingebettetes GeoJSON, vereinfachtes Styling und eingebautes Punkt-Clustering.",
group: "Data sources",
icon: "💧",
},
@@ -41,76 +50,97 @@ export const DEMOS: Demo[] = [
id: "cog",
title: "Cloud Optimized GeoTIFF",
blurb: "Rasters read straight from static storage — imagery, terrain and classified values.",
+ blurbDe: "Raster direkt aus statischem Speicher gelesen — Orthofoto, Gelände und klassifizierte Werte.",
group: "Data sources",
icon: "🛰️",
},
{
id: "popups",
title: "Popups & hover",
+ titleDe: "Popups & Hover",
blurb: "Templates, field tables, hover tooltips, selection highlight and multi-layer hits.",
+ blurbDe: "Templates, Attributtabellen, Hover-Tooltips, Hervorhebung und Treffer über mehrere Layer.",
group: "Map features",
icon: "💬",
},
{
id: "legend",
title: "Legend",
+ titleDe: "Legende",
blurb: "Service legends, swatches derived from the style, and hand-written legend entries.",
+ blurbDe: "Dienst-Legenden, aus dem Style abgeleitete Farbfelder und handgeschriebene Einträge.",
group: "Map features",
icon: "📊",
},
{
id: "search",
title: "Search",
+ titleDe: "Suche",
blurb: "Type-ahead place and address search, with any gazetteer behind it.",
+ blurbDe: "Orts- und Adresssuche mit Vorschlägen — dahinter ein Gazetteer Ihrer Wahl.",
group: "Map features",
icon: "🔍",
},
{
id: "coordinates",
title: "Coordinates",
+ titleDe: "Koordinaten",
blurb: "Right-click readout in WGS 84, Gauss-Krueger and UTM — with copy buttons.",
+ blurbDe: "Rechtsklick-Anzeige in WGS 84, Gauß-Krüger und UTM — mit Kopier-Buttons.",
group: "Map features",
icon: "📐",
},
{
id: "measure",
title: "Measure",
+ titleDe: "Messen",
blurb: "Distance and area on the sphere — click, drag a vertex, double-click.",
+ blurbDe: "Strecke und Fläche auf der Kugel — klicken, Stützpunkt ziehen, Doppelklick.",
group: "Map features",
icon: "📏",
},
{
id: "print",
title: "Print & export",
+ titleDe: "Drucken & Export",
blurb: "High-resolution PNG export and a print view with title, legend and scale bar.",
+ blurbDe: "Hochauflösender PNG-Export und eine Druckansicht mit Titel, Legende und Maßstab.",
group: "Map features",
icon: "🖨️",
},
{
id: "add-layer",
title: "Add layers",
+ titleDe: "Layer hinzufügen",
blurb: "Users paste a WMS or WMTS URL; capabilities are parsed in the browser.",
+ blurbDe: "Eine WMS- oder WMTS-URL genügt; die Capabilities werden im Browser geparst.",
group: "Map features",
icon: "➕",
},
{
id: "permalink",
title: "Share & permalink",
+ titleDe: "Teilen & Permalink",
blurb: "The full map state travels in the URL — view, basemap, layers, added services.",
+ blurbDe: "Der komplette Kartenzustand steckt in der URL — Ausschnitt, Hintergrund, Layer, Dienste.",
group: "Map features",
icon: "🔗",
},
{
id: "globe",
title: "Globe",
+ titleDe: "Globus",
blurb: "MapLibre's globe projection, one config key and a control away.",
+ blurbDe: "MapLibres Globus-Projektion — nur einen Config-Schlüssel und ein Control entfernt.",
group: "Map features",
icon: "🌍",
},
{
id: "minimal",
title: "Minimal config",
+ titleDe: "Minimale Config",
blurb: "The contract: a version and one basemap must already give you a usable map.",
+ blurbDe: "Die Garantie: Version plus eine Basemap ergeben bereits eine brauchbare Karte.",
group: "Configuration",
icon: "🧪",
},
@@ -118,41 +148,52 @@ export const DEMOS: Demo[] = [
id: "theming",
title: "Theming",
blurb: "Design tokens from config or host CSS, light/dark, and runtime restyling.",
+ blurbDe: "Design-Tokens aus Config oder Host-CSS, Hell/Dunkel und Umstylen zur Laufzeit.",
group: "Configuration",
icon: "🎨",
},
{
id: "i18n",
title: "Languages",
+ titleDe: "Sprachen",
blurb: "Built-in German and English UI plus per-locale string overrides from config.",
+ blurbDe: "Deutsche und englische UI eingebaut, plus String-Overrides je Sprache aus der Config.",
group: "Configuration",
icon: "🌐",
},
{
id: "extends",
title: "Config inheritance",
+ titleDe: "Config-Vererbung",
blurb: "One shared organisation base config, per-map deltas via extends.",
+ blurbDe: "Eine gemeinsame Basis-Config der Organisation, Abweichungen je Karte via extends.",
group: "Configuration",
icon: "🧬",
},
{
id: "validate",
title: "Validate a config",
+ titleDe: "Config validieren",
blurb: "Paste a config and run map0's validator online — plus every other place a config is checked.",
+ blurbDe: "Config einfügen und direkt online validieren — plus ein Überblick über alle anderen Prüfstellen.",
group: "Configuration",
icon: "✅",
},
{
id: "standalone",
title: "Script tag embed",
+ titleDe: "Script-Tag-Einbindung",
blurb: "The built bundle on a plain HTML page — no bundler, no framework.",
+ blurbDe: "Das gebaute Bundle auf einer einfachen HTML-Seite — ohne Bundler, ohne Framework.",
group: "Integration",
icon: "📦",
},
{
id: "lazy",
title: "Lazy loading",
+ titleDe: "Lazy Loading",
blurb: "A map below the fold costs 20 KB until someone scrolls to it.",
+ blurbDe: "Eine Karte unterhalb des sichtbaren Bereichs kostet 20 KB — bis jemand hinscrollt.",
group: "Integration",
icon: "🪶",
},
@@ -165,6 +206,13 @@ export const GROUPS: Array = [
"Integration",
];
+export const GROUP_LABELS_DE: Record = {
+ "Data sources": "Datenquellen",
+ "Map features": "Kartenfunktionen",
+ Configuration: "Konfiguration",
+ Integration: "Integration",
+};
+
export function demoById(id: string): Demo | undefined {
return DEMOS.find((d) => d.id === id);
}
diff --git a/site/demos/extends.html b/site/demos/extends.html
index e4eb357..1f90619 100644
--- a/site/demos/extends.html
+++ b/site/demos/extends.html
@@ -3,7 +3,7 @@
- Config inheritance — map0 demos
+ Config inheritance — map0 demos
@@ -11,9 +11,9 @@
- Configuration
- Config inheritance
-
+
Configuration
+ Config inheritance
+
Fifty maps across an organisation should not repeat the same three basemaps fifty times.
One shared base config holds the house standard; each map only writes down what makes it
different.
@@ -21,30 +21,30 @@
Config inheritance
-
+
What you see: three basemaps, the home button, the legend position and the
share link all come from the organisation base file. This map itself only declares one
layer, a view and its own accent colour.
- The map config
- Short, because it inherits:
+ The map config
+ Short, because it inherits:
- The shared base
- Maintained once, centrally, and reused by every map in the organisation:
+ The shared base
+ Maintained once, centrally, and reused by every map in the organisation:
- Merge rules
+ Merge rules
- - Objects merge recursively — the child's
theme.primary wins, the base's theme.radius survives
- - Arrays replace as a whole — a layer list is an ordered statement, not a set to merge
- - Chains up to three levels deep (global → department → map), with cycle detection
- - Relative
extends URLs resolve against the config file that declares them
+ - Objects merge recursively — the child's
theme.primary wins, the base's theme.radius survives
+ - Arrays replace as a whole — a layer list is an ordered statement, not a set to merge
+ - Chains up to three levels deep (global → department → map), with cycle detection
+ - Relative
extends URLs resolve against the config file that declares them
-
+
Why arrays replace
Merging layer arrays sounds convenient until you try to remove an inherited layer, reorder
two of them, or explain to an editor why layer three appeared out of nowhere. Replacing is
diff --git a/site/demos/geojson.html b/site/demos/geojson.html
index b34ea83..9c2e93d 100644
--- a/site/demos/geojson.html
+++ b/site/demos/geojson.html
@@ -3,7 +3,7 @@
- GeoJSON & clustering — map0 demos
+ GeoJSON & clustering — map0 demos
@@ -11,30 +11,30 @@
- Data sources
- GeoJSON & clustering
-
+
Data sources
+ GeoJSON & clustering
+
Three ways to get features onto the map — a remote service, a file next to the page, and
a feature collection written straight into the config.
-
+
Try it: ~2400 drinking fountains arrive as one GeoJSON document and are
clustered on the GPU. Zoom in until the clusters break apart, and use the zoom-to-layer
button in the layer panel to jump to the local demo file.
- What this demo shows
+ What this demo shows
- data accepts a URL or an inline GeoJSON object — here a WFS response, a static file and a literal
- - Clustering is one config key; MapLibre does the grouping
- - The simplified style (
circle-*, line-*, fill-*) expands into proper style layers per geometry type
- - Zoom-to-layer computes the bounding box from the data itself
+ data accepts a URL or an inline GeoJSON object — here a WFS response, a static file and a literal
+ - Clustering is one config key; MapLibre does the grouping
+ - The simplified style (
circle-*, line-*, fill-*) expands into proper style layers per geometry type
+ - Zoom-to-layer computes the bounding box from the data itself
-
+
For a WFS, the trick is simply asking for GeoJSON: append
outputFormat=json and srsName=EPSG:4326 to a GetFeature request
and the response is a source map0 can use directly. A dedicated wfs layer
@@ -43,13 +43,13 @@
What this demo shows
- Configuration
+ Configuration
- Full control over the style
-
+
Full control over the style
+
When the flat style object is not enough, pass an array of MapLibre style-spec layers
instead — expressions, filters, everything. map0 injects the source and keeps the layer
order:
diff --git a/site/demos/globe.html b/site/demos/globe.html
index 378d857..029b6f1 100644
--- a/site/demos/globe.html
+++ b/site/demos/globe.html
@@ -3,7 +3,7 @@
- Globe — map0 demos
+ Globe — map0 demos
@@ -11,37 +11,37 @@
- Map features
- Globe
-
+
Map features
+ Globe
+
A real globe projection, not a plugin and not a second rendering engine — this is the one
thing MapLibre gives us that no OpenLayers-based client has for free.
-
+
Try it: drag the globe, then use the globe button in the control stack to
switch between globe and flat Mercator. Zoom in far enough and the projection blends into
Mercator by itself.
- What this demo shows
+ What this demo shows
- map.projection: "globe" starts the map as a globe
- - The globe control toggles projections at runtime — overlays keep rendering
- - Overlays, popups and clustering behave exactly as in the flat map
- - Dark theme via
theme.mode, so the globe sits on a dark backdrop
+ map.projection: "globe" starts the map as a globe
+ - The globe control toggles projections at runtime — overlays keep rendering
+ - Overlays, popups and clustering behave exactly as in the flat map
+ - Dark theme via
theme.mode, so the globe sits on a dark backdrop
-
+
The projection survives a basemap change, because map0 carries it through the style
transformation that re-injects overlays.
- Configuration
+ Configuration
diff --git a/site/demos/i18n.html b/site/demos/i18n.html
index 1bbc591..ef98d72 100644
--- a/site/demos/i18n.html
+++ b/site/demos/i18n.html
@@ -3,7 +3,7 @@
- Languages — map0 demos
+ Languages — map0 demos
@@ -11,30 +11,30 @@
- Configuration
- Languages
-
+
Configuration
+ Languages
+
German and English ship with the client. Every single string can be overridden per
locale from the config — including terms your organisation insists on.
-
+
Look closely: the panel is titled Kartenthemen, not the built-in
Kartenebenen, and the legend reads Zeichenerklärung. Both come from
i18n.overrides. Tooltips of the MapLibre controls follow the same locale.
- How the locale is chosen
+ How the locale is chosen
- locale: "auto" (the default) follows the visitor's browser language
- - A fixed
locale pins the UI — useful when the surrounding page is single-language
- fallback catches keys the chosen locale does not define
- - Overrides can even introduce a locale map0 does not ship, without a rebuild
+ locale: "auto" (the default) follows the visitor's browser language
+ - A fixed
locale pins the UI — useful when the surrounding page is single-language
+ fallback catches keys the chosen locale does not define
+ - Overrides can even introduce a locale map0 does not ship, without a rebuild
-
+
Lookup order per key: your override for the locale, the built-in dictionary for the
locale, your override for the fallback, the built-in fallback. Nothing crashes on a
missing key — the key itself is shown, which makes gaps obvious in testing.
@@ -42,12 +42,12 @@
How the locale is chosen
- Configuration
+ Configuration
- A new language from config alone
+ A new language from config alone
"i18n": {
"locale": "it",
@@ -61,7 +61,7 @@ A new language from config alone
}
}
- Anything not translated falls back to English rather than disappearing.
+ Anything not translated falls back to English rather than disappearing.
diff --git a/site/demos/index.html b/site/demos/index.html
index 18ce92f..8230847 100644
--- a/site/demos/index.html
+++ b/site/demos/index.html
@@ -12,8 +12,8 @@
Demos
- One topic per demo
-
+
One topic per demo
+
Every page below runs the real client against live services — mostly basemap.at and the
City of Vienna open data services. Each demo shows a map, explains what it demonstrates,
and prints the exact configuration that produced it.
diff --git a/site/demos/lazy.html b/site/demos/lazy.html
index 9dc1d41..fdd0a35 100644
--- a/site/demos/lazy.html
+++ b/site/demos/lazy.html
@@ -3,7 +3,7 @@
- Lazy loading — map0 demos
+ Lazy loading — map0 demos