From 7fbad5499c4cb7d91d8df4ca4f5fe94bc2013480 Mon Sep 17 00:00:00 2001 From: Doxa Maps Date: Sat, 26 Sep 2026 07:48:28 +0000 Subject: [PATCH] Map controls speak the reader's language on both engines ('Zoom in', 'Toggle attribution', gesture hints) MapLibre's and Mapbox's own control labels stayed English under ar/es (rega's row 30). Both engines take a `locale` map of their UI strings at construction; useMapInstance now passes one built from the new mapui catalogue (17 strings x 11 locales, parity PASS) for the reader's language. The keys are the engines' own (MapLibre 5.24's list, plus Mapbox's gesture-hint names); an engine ignores the rest. Built doxa-simple-map carries the translations; check:i18n-treeshake PASS. --- library/composables/useMapInstance.js | 28 +++++++++++++++++++++++++++ library/i18n/locales/ar/mapui.json | 19 ++++++++++++++++++ library/i18n/locales/de/mapui.json | 19 ++++++++++++++++++ library/i18n/locales/en/mapui.json | 19 ++++++++++++++++++ library/i18n/locales/es/mapui.json | 19 ++++++++++++++++++ library/i18n/locales/fr/mapui.json | 19 ++++++++++++++++++ library/i18n/locales/hi/mapui.json | 19 ++++++++++++++++++ library/i18n/locales/it/mapui.json | 19 ++++++++++++++++++ library/i18n/locales/pt/mapui.json | 19 ++++++++++++++++++ library/i18n/locales/ro/mapui.json | 19 ++++++++++++++++++ library/i18n/locales/ru/mapui.json | 19 ++++++++++++++++++ library/i18n/locales/zh/mapui.json | 19 ++++++++++++++++++ 12 files changed, 237 insertions(+) create mode 100644 library/i18n/locales/ar/mapui.json create mode 100644 library/i18n/locales/de/mapui.json create mode 100644 library/i18n/locales/en/mapui.json create mode 100644 library/i18n/locales/es/mapui.json create mode 100644 library/i18n/locales/fr/mapui.json create mode 100644 library/i18n/locales/hi/mapui.json create mode 100644 library/i18n/locales/it/mapui.json create mode 100644 library/i18n/locales/pt/mapui.json create mode 100644 library/i18n/locales/ro/mapui.json create mode 100644 library/i18n/locales/ru/mapui.json create mode 100644 library/i18n/locales/zh/mapui.json diff --git a/library/composables/useMapInstance.js b/library/composables/useMapInstance.js index 106d79a58..be7b8dfb0 100644 --- a/library/composables/useMapInstance.js +++ b/library/composables/useMapInstance.js @@ -38,6 +38,31 @@ const ENGINES = { maplibre: { global: 'maplibregl', js: CDN.maplibreGlJs.url, css: CDN.maplibreGlCss.url }, } +// THE ENGINE'S OWN CONTROL LABELS ("Zoom in", "Toggle attribution", the gesture hints…) in the reader's +// language. Both engines take a `locale` map of their UI strings at construction; without one they stay +// English under ar/es (rega's row 30). Strings live in library/i18n/locales//mapui.json. The keys are +// the engines' own; an engine ignores the ones it does not use. +const ENGINE_UI_KEYS = { + 'Map.Title': 'map', 'Marker.Title': 'marker', 'Popup.Close': 'closePopup', + 'NavigationControl.ZoomIn': 'zoomIn', 'NavigationControl.ZoomOut': 'zoomOut', 'NavigationControl.ResetBearing': 'resetBearing', + 'AttributionControl.ToggleAttribution': 'toggleAttribution', 'AttributionControl.MapFeedback': 'mapFeedback', + 'FullscreenControl.Enter': 'enterFullscreen', 'FullscreenControl.Exit': 'exitFullscreen', + 'GeolocateControl.FindMyLocation': 'findMyLocation', 'GeolocateControl.LocationNotAvailable': 'locationNotAvailable', + 'GlobeControl.Enable': 'enableGlobe', 'GlobeControl.Disable': 'disableGlobe', + 'CooperativeGesturesHandler.WindowsHelpText': 'ctrlScroll', 'CooperativeGesturesHandler.MacHelpText': 'cmdScroll', + 'CooperativeGesturesHandler.MobileHelpText': 'twoFingers', + // Mapbox's names for the same gesture hints + 'ScrollZoomBlocker.CtrlMessage': 'ctrlScroll', 'ScrollZoomBlocker.CmdMessage': 'cmdScroll', 'TouchPanBlocker.Message': 'twoFingers', +} +export function engineUiLocale(lang) { + const out = {} + for (const [engineKey, ours] of Object.entries(ENGINE_UI_KEYS)) { + const v = tStatic(`mapui.${ours}`, lang) + if (v) out[engineKey] = v + } + return out +} + // ONE MAPBOX WORDMARK PER PAGE: every map instance renders its own logo, so a // page composing several maps stacks duplicates. First live instance keeps the // logo (Mapbox attribution satisfied once per document); later ones hide theirs @@ -72,6 +97,7 @@ import { resolveMapProvider, explicitMapProvider } from './useMapProvider.js' import { CDN, pinElement } from '../constants/cdn.js' import { installRtlTextPlugin } from '../maps/rtl-text.js' import { localizeBasemapLabels } from '../maps/localize-labels.js' +import { tStatic } from '../i18n/index.js' /** * The live engine global for a provider, or undefined if not yet loaded. @@ -515,6 +541,7 @@ export function useMapInstance({ // day/night decision, not a guess made here. (Computed above the branch: the Mapbox // branch's own `initialConfig` is scoped to that branch and is NOT visible here.) style: maplibreStyle(effectiveStyle, _bootPreset), + locale: engineUiLocale(readerLang()), center, zoom, minZoom: initialMinZoom, @@ -541,6 +568,7 @@ export function useMapInstance({ accessToken: token, // BP #1 from W1A — per-instance token; avoids last-writer-wins on multi-embed pages container: containerRef.value, // real DOM element — never a string ID in shadow DOM style: effectiveStyle, + locale: engineUiLocale(readerLang()), // Pins a Standard basemap's lightPreset/theme BEFORE its first frame; without it the // schema default 'day' paints one LIGHT frame before any setConfigProperty can run. ...(initialConfig ? { config: initialConfig } : {}), diff --git a/library/i18n/locales/ar/mapui.json b/library/i18n/locales/ar/mapui.json new file mode 100644 index 000000000..2794241db --- /dev/null +++ b/library/i18n/locales/ar/mapui.json @@ -0,0 +1,19 @@ +{ + "map": "الخريطة", + "marker": "علامة على الخريطة", + "closePopup": "إغلاق النافذة المنبثقة", + "zoomIn": "تكبير", + "zoomOut": "تصغير", + "resetBearing": "اسحب لتدوير الخريطة، وانقر لإعادة الشمال", + "toggleAttribution": "إظهار/إخفاء المصادر", + "mapFeedback": "ملاحظات على الخريطة", + "enterFullscreen": "ملء الشاشة", + "exitFullscreen": "الخروج من ملء الشاشة", + "findMyLocation": "تحديد موقعي", + "locationNotAvailable": "الموقع غير متاح", + "enableGlobe": "تفعيل الكرة الأرضية", + "disableGlobe": "إيقاف الكرة الأرضية", + "ctrlScroll": "استخدم Ctrl مع التمرير لتكبير الخريطة", + "cmdScroll": "استخدم ⌘ مع التمرير لتكبير الخريطة", + "twoFingers": "استخدم إصبعين لتحريك الخريطة" +} diff --git a/library/i18n/locales/de/mapui.json b/library/i18n/locales/de/mapui.json new file mode 100644 index 000000000..b7adb5a19 --- /dev/null +++ b/library/i18n/locales/de/mapui.json @@ -0,0 +1,19 @@ +{ + "map": "Karte", + "marker": "Kartenmarkierung", + "closePopup": "Popup schließen", + "zoomIn": "Vergrößern", + "zoomOut": "Verkleinern", + "resetBearing": "Ziehen, um die Karte zu drehen; klicken, um nach Norden auszurichten", + "toggleAttribution": "Quellenangaben ein-/ausblenden", + "mapFeedback": "Feedback zur Karte", + "enterFullscreen": "Vollbild", + "exitFullscreen": "Vollbild beenden", + "findMyLocation": "Meinen Standort finden", + "locationNotAvailable": "Standort nicht verfügbar", + "enableGlobe": "Globus einschalten", + "disableGlobe": "Globus ausschalten", + "ctrlScroll": "Strg + Scrollen zum Zoomen der Karte", + "cmdScroll": "⌘ + Scrollen zum Zoomen der Karte", + "twoFingers": "Mit zwei Fingern die Karte bewegen" +} diff --git a/library/i18n/locales/en/mapui.json b/library/i18n/locales/en/mapui.json new file mode 100644 index 000000000..a48e51a4c --- /dev/null +++ b/library/i18n/locales/en/mapui.json @@ -0,0 +1,19 @@ +{ + "map": "Map", + "marker": "Map marker", + "closePopup": "Close popup", + "zoomIn": "Zoom in", + "zoomOut": "Zoom out", + "resetBearing": "Drag to rotate map, click to reset north", + "toggleAttribution": "Toggle attribution", + "mapFeedback": "Map feedback", + "enterFullscreen": "Enter fullscreen", + "exitFullscreen": "Exit fullscreen", + "findMyLocation": "Find my location", + "locationNotAvailable": "Location not available", + "enableGlobe": "Enable globe", + "disableGlobe": "Disable globe", + "ctrlScroll": "Use Ctrl + scroll to zoom the map", + "cmdScroll": "Use ⌘ + scroll to zoom the map", + "twoFingers": "Use two fingers to move the map" +} diff --git a/library/i18n/locales/es/mapui.json b/library/i18n/locales/es/mapui.json new file mode 100644 index 000000000..a4fb8b933 --- /dev/null +++ b/library/i18n/locales/es/mapui.json @@ -0,0 +1,19 @@ +{ + "map": "Mapa", + "marker": "Marcador del mapa", + "closePopup": "Cerrar ventana", + "zoomIn": "Acercar", + "zoomOut": "Alejar", + "resetBearing": "Arrastra para girar el mapa; haz clic para orientar al norte", + "toggleAttribution": "Mostrar u ocultar atribución", + "mapFeedback": "Comentarios sobre el mapa", + "enterFullscreen": "Pantalla completa", + "exitFullscreen": "Salir de pantalla completa", + "findMyLocation": "Buscar mi ubicación", + "locationNotAvailable": "Ubicación no disponible", + "enableGlobe": "Activar globo", + "disableGlobe": "Desactivar globo", + "ctrlScroll": "Usa Ctrl + desplazamiento para hacer zoom en el mapa", + "cmdScroll": "Usa ⌘ + desplazamiento para hacer zoom en el mapa", + "twoFingers": "Usa dos dedos para mover el mapa" +} diff --git a/library/i18n/locales/fr/mapui.json b/library/i18n/locales/fr/mapui.json new file mode 100644 index 000000000..eb0154d14 --- /dev/null +++ b/library/i18n/locales/fr/mapui.json @@ -0,0 +1,19 @@ +{ + "map": "Carte", + "marker": "Marqueur de carte", + "closePopup": "Fermer la fenêtre", + "zoomIn": "Zoom avant", + "zoomOut": "Zoom arrière", + "resetBearing": "Faites glisser pour faire pivoter la carte, cliquez pour revenir au nord", + "toggleAttribution": "Afficher/masquer l'attribution", + "mapFeedback": "Commentaires sur la carte", + "enterFullscreen": "Plein écran", + "exitFullscreen": "Quitter le plein écran", + "findMyLocation": "Trouver ma position", + "locationNotAvailable": "Position non disponible", + "enableGlobe": "Activer le globe", + "disableGlobe": "Désactiver le globe", + "ctrlScroll": "Utilisez Ctrl + molette pour zoomer sur la carte", + "cmdScroll": "Utilisez ⌘ + molette pour zoomer sur la carte", + "twoFingers": "Utilisez deux doigts pour déplacer la carte" +} diff --git a/library/i18n/locales/hi/mapui.json b/library/i18n/locales/hi/mapui.json new file mode 100644 index 000000000..3a70a993c --- /dev/null +++ b/library/i18n/locales/hi/mapui.json @@ -0,0 +1,19 @@ +{ + "map": "मानचित्र", + "marker": "मानचित्र चिह्न", + "closePopup": "पॉपअप बंद करें", + "zoomIn": "ज़ूम इन", + "zoomOut": "ज़ूम आउट", + "resetBearing": "मानचित्र घुमाने के लिए खींचें, उत्तर पर लौटने के लिए क्लिक करें", + "toggleAttribution": "श्रेय दिखाएँ/छिपाएँ", + "mapFeedback": "मानचित्र पर प्रतिक्रिया", + "enterFullscreen": "पूर्ण स्क्रीन", + "exitFullscreen": "पूर्ण स्क्रीन से बाहर निकलें", + "findMyLocation": "मेरा स्थान खोजें", + "locationNotAvailable": "स्थान उपलब्ध नहीं", + "enableGlobe": "ग्लोब चालू करें", + "disableGlobe": "ग्लोब बंद करें", + "ctrlScroll": "मानचित्र ज़ूम करने के लिए Ctrl + स्क्रॉल करें", + "cmdScroll": "मानचित्र ज़ूम करने के लिए ⌘ + स्क्रॉल करें", + "twoFingers": "मानचित्र हिलाने के लिए दो उँगलियों का उपयोग करें" +} diff --git a/library/i18n/locales/it/mapui.json b/library/i18n/locales/it/mapui.json new file mode 100644 index 000000000..d295f8606 --- /dev/null +++ b/library/i18n/locales/it/mapui.json @@ -0,0 +1,19 @@ +{ + "map": "Mappa", + "marker": "Indicatore sulla mappa", + "closePopup": "Chiudi popup", + "zoomIn": "Ingrandisci", + "zoomOut": "Riduci", + "resetBearing": "Trascina per ruotare la mappa, fai clic per tornare al nord", + "toggleAttribution": "Mostra/nascondi attribuzione", + "mapFeedback": "Feedback sulla mappa", + "enterFullscreen": "Schermo intero", + "exitFullscreen": "Esci da schermo intero", + "findMyLocation": "Trova la mia posizione", + "locationNotAvailable": "Posizione non disponibile", + "enableGlobe": "Attiva globo", + "disableGlobe": "Disattiva globo", + "ctrlScroll": "Usa Ctrl + scorrimento per ingrandire la mappa", + "cmdScroll": "Usa ⌘ + scorrimento per ingrandire la mappa", + "twoFingers": "Usa due dita per spostare la mappa" +} diff --git a/library/i18n/locales/pt/mapui.json b/library/i18n/locales/pt/mapui.json new file mode 100644 index 000000000..d95d6a6fa --- /dev/null +++ b/library/i18n/locales/pt/mapui.json @@ -0,0 +1,19 @@ +{ + "map": "Mapa", + "marker": "Marcador do mapa", + "closePopup": "Fechar janela", + "zoomIn": "Aumentar zoom", + "zoomOut": "Diminuir zoom", + "resetBearing": "Arraste para girar o mapa, clique para voltar ao norte", + "toggleAttribution": "Mostrar/ocultar atribuição", + "mapFeedback": "Comentários sobre o mapa", + "enterFullscreen": "Tela cheia", + "exitFullscreen": "Sair da tela cheia", + "findMyLocation": "Encontrar minha localização", + "locationNotAvailable": "Localização indisponível", + "enableGlobe": "Ativar globo", + "disableGlobe": "Desativar globo", + "ctrlScroll": "Use Ctrl + rolagem para ampliar o mapa", + "cmdScroll": "Use ⌘ + rolagem para ampliar o mapa", + "twoFingers": "Use dois dedos para mover o mapa" +} diff --git a/library/i18n/locales/ro/mapui.json b/library/i18n/locales/ro/mapui.json new file mode 100644 index 000000000..f6420e37c --- /dev/null +++ b/library/i18n/locales/ro/mapui.json @@ -0,0 +1,19 @@ +{ + "map": "Hartă", + "marker": "Marcaj pe hartă", + "closePopup": "Închide fereastra", + "zoomIn": "Mărește", + "zoomOut": "Micșorează", + "resetBearing": "Trage pentru a roti harta, apasă pentru a reveni la nord", + "toggleAttribution": "Afișează/ascunde atribuirea", + "mapFeedback": "Feedback despre hartă", + "enterFullscreen": "Ecran complet", + "exitFullscreen": "Ieși din ecran complet", + "findMyLocation": "Găsește-mi locația", + "locationNotAvailable": "Locație indisponibilă", + "enableGlobe": "Activează globul", + "disableGlobe": "Dezactivează globul", + "ctrlScroll": "Folosește Ctrl + derulare pentru a mări harta", + "cmdScroll": "Folosește ⌘ + derulare pentru a mări harta", + "twoFingers": "Folosește două degete pentru a muta harta" +} diff --git a/library/i18n/locales/ru/mapui.json b/library/i18n/locales/ru/mapui.json new file mode 100644 index 000000000..1800ef058 --- /dev/null +++ b/library/i18n/locales/ru/mapui.json @@ -0,0 +1,19 @@ +{ + "map": "Карта", + "marker": "Метка на карте", + "closePopup": "Закрыть окно", + "zoomIn": "Приблизить", + "zoomOut": "Отдалить", + "resetBearing": "Перетащите, чтобы повернуть карту; нажмите, чтобы вернуть север", + "toggleAttribution": "Показать/скрыть источники", + "mapFeedback": "Отзыв о карте", + "enterFullscreen": "Во весь экран", + "exitFullscreen": "Выйти из полноэкранного режима", + "findMyLocation": "Найти моё местоположение", + "locationNotAvailable": "Местоположение недоступно", + "enableGlobe": "Включить глобус", + "disableGlobe": "Выключить глобус", + "ctrlScroll": "Используйте Ctrl + прокрутку для масштабирования карты", + "cmdScroll": "Используйте ⌘ + прокрутку для масштабирования карты", + "twoFingers": "Используйте два пальца, чтобы перемещать карту" +} diff --git a/library/i18n/locales/zh/mapui.json b/library/i18n/locales/zh/mapui.json new file mode 100644 index 000000000..b2bcbc51d --- /dev/null +++ b/library/i18n/locales/zh/mapui.json @@ -0,0 +1,19 @@ +{ + "map": "地图", + "marker": "地图标记", + "closePopup": "关闭弹窗", + "zoomIn": "放大", + "zoomOut": "缩小", + "resetBearing": "拖动以旋转地图,点击以恢复正北", + "toggleAttribution": "显示/隐藏数据来源", + "mapFeedback": "地图反馈", + "enterFullscreen": "全屏", + "exitFullscreen": "退出全屏", + "findMyLocation": "查找我的位置", + "locationNotAvailable": "无法获取位置", + "enableGlobe": "启用地球仪", + "disableGlobe": "停用地球仪", + "ctrlScroll": "使用 Ctrl + 滚轮缩放地图", + "cmdScroll": "使用 ⌘ + 滚轮缩放地图", + "twoFingers": "使用两根手指移动地图" +}