359 lines
15 KiB
JavaScript
359 lines
15 KiB
JavaScript
(function initializeI18n(globalScope) {
|
|
"use strict";
|
|
|
|
const DEFAULT_LANGUAGE = "en";
|
|
const STORAGE_KEY = "xprov-language";
|
|
const TRANSLATIONS = {
|
|
en: {
|
|
languageName: "English",
|
|
pageTitle: "XPro Map Visualizer",
|
|
applicationMessages: "Application messages",
|
|
openMapControls: "Open map controls",
|
|
mapControls: "Map controls",
|
|
closeMapControls: "Close map controls",
|
|
mapVisualizer: "Map Visualizer",
|
|
openSettings: "Open settings",
|
|
closeSettings: "Close settings",
|
|
settings: "Settings",
|
|
applySettings: "Apply",
|
|
useBrowserDefault: "Use browser default",
|
|
find: "Find",
|
|
parcelExample: "e.g. 57 or 2669.1",
|
|
parcelNumber: "Parcel number",
|
|
findOnMap: "Find on map",
|
|
layers: "Layers",
|
|
waitingForConnection: "Waiting for connection.",
|
|
loadingPublishedLayers: "Loading published layers.",
|
|
baseMap: "Base map",
|
|
softMinimal: "Soft minimal",
|
|
openStreetMap: "OpenStreetMap",
|
|
satelliteImagery: "Satellite imagery",
|
|
language: "Language",
|
|
applicationLanguage: "Application language",
|
|
mapView: "Map view",
|
|
closeFeatureInformation: "Close feature information",
|
|
resetNorth: "Reset map orientation to north",
|
|
zoomVisibleLayers: "Zoom to visible layers",
|
|
copyMapLink: "Copy link to this map view",
|
|
clipboardUnavailable: "Clipboard access is unavailable.",
|
|
mapLinkCopied: "Link to this map view copied to your clipboard.",
|
|
mapLinkCopyFailed:
|
|
"Unable to copy the map link. Please copy the address from your browser.",
|
|
zoomArea: "Zoom to area",
|
|
exitAreaZoom: "Exit area zoom (Esc)",
|
|
compassRequiresHttps: "Device compass requires HTTPS; HTTP works only on localhost.",
|
|
compassUnavailable: "Device compass is unavailable on this device.",
|
|
compassPermissionDenied: "Device compass permission was not granted.",
|
|
compassOn: "Device compass orientation is on.",
|
|
compassStartFailed: "Unable to start the device compass.",
|
|
compassOff: "Device compass orientation is off.",
|
|
compassTurnOff: "Turn off device compass orientation",
|
|
compassAlign: "Align map with device compass",
|
|
dismissMessage: "Dismiss message",
|
|
enterParcel: "Enter a parcel number to search.",
|
|
searchingParcel: "Searching for parcel…",
|
|
searchFailedStatus: "Parcel search failed (status {status}).",
|
|
noParcelFound: "No parcel found with number “{parcelNumber}”.",
|
|
foundParcel: "Found parcel {parcelNumber}.",
|
|
foundParcels: "Found {count} parcels matching {parcelNumber}.",
|
|
parcelSearchFailed: "Unable to search for that parcel.",
|
|
loadingWmsLayers: "Loading WMS layers…",
|
|
wmsLoadFailed: "Unable to load the WMS service.",
|
|
geoserverConnectionFailed: "GeoServer connection failed (status {status}).",
|
|
noPublishedLayers: "No published layers were returned by the service.",
|
|
selectLayerToZoom: "Select a layer with a published extent to zoom to it.",
|
|
parcel: "Parcel",
|
|
building: "Building",
|
|
area: "Area",
|
|
areaUnavailable: "Area unavailable",
|
|
inhabited: "Inhabited",
|
|
viewCorrespondingBuilding: "View corresponding building",
|
|
associatedParcels: "Associated parcels",
|
|
viewParcel: "View parcel {parcelNumber}",
|
|
parcelWithNumber: "Parcel {parcelNumber}",
|
|
unavailable: "Unavailable",
|
|
noAssociatedParcels: "No associated parcels were found.",
|
|
zoomIn: "Zoom in",
|
|
zoomOut: "Zoom out",
|
|
attribution: "Attributions",
|
|
softAttribution:
|
|
'© <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> contributors © <a href="https://carto.com/attributions">CARTO</a>',
|
|
satelliteAttribution:
|
|
'Tiles © <a href="https://www.esri.com/en-us/legal/terms/full-master-agreement">Esri</a> — Source: Esri, Maxar, Earthstar Geographics, and the GIS User Community',
|
|
},
|
|
es: {
|
|
languageName: "Español",
|
|
pageTitle: "Visualizador de Mapas XPro",
|
|
applicationMessages: "Mensajes de la aplicación",
|
|
openMapControls: "Abrir controles del mapa",
|
|
mapControls: "Controles del mapa",
|
|
closeMapControls: "Cerrar controles del mapa",
|
|
mapVisualizer: "Visualizador de Mapas",
|
|
openSettings: "Abrir configuración",
|
|
closeSettings: "Cerrar configuración",
|
|
settings: "Configuración",
|
|
applySettings: "Aplicar",
|
|
useBrowserDefault: "Usar el idioma predeterminado del navegador",
|
|
find: "Buscar",
|
|
parcelExample: "p. ej., 57 o 2669.1",
|
|
parcelNumber: "Número de parcela",
|
|
findOnMap: "Localizar en el mapa",
|
|
layers: "Capas",
|
|
waitingForConnection: "Esperando conexión.",
|
|
loadingPublishedLayers: "Cargando capas publicadas.",
|
|
baseMap: "Mapa base",
|
|
softMinimal: "Minimalista suave",
|
|
openStreetMap: "OpenStreetMap",
|
|
satelliteImagery: "Imágenes por satélite",
|
|
language: "Idioma",
|
|
applicationLanguage: "Idioma de la aplicación",
|
|
mapView: "Vista del mapa",
|
|
closeFeatureInformation: "Cerrar información del elemento",
|
|
resetNorth: "Restablecer la orientación del mapa hacia el norte",
|
|
zoomVisibleLayers: "Ajustar a las capas visibles",
|
|
copyMapLink: "Copiar enlace a esta vista del mapa",
|
|
clipboardUnavailable: "El acceso al portapapeles no está disponible.",
|
|
mapLinkCopied: "El enlace a esta vista se ha copiado al portapapeles.",
|
|
mapLinkCopyFailed:
|
|
"No se pudo copiar el enlace. Copie la dirección desde el navegador.",
|
|
zoomArea: "Ampliar un área",
|
|
exitAreaZoom: "Salir de la ampliación de área (Esc)",
|
|
compassRequiresHttps:
|
|
"La brújula del dispositivo requiere HTTPS; HTTP solo funciona en localhost.",
|
|
compassUnavailable: "La brújula no está disponible en este dispositivo.",
|
|
compassPermissionDenied: "No se concedió permiso para usar la brújula.",
|
|
compassOn: "La orientación mediante la brújula está activada.",
|
|
compassStartFailed: "No se pudo iniciar la brújula del dispositivo.",
|
|
compassOff: "La orientación mediante la brújula está desactivada.",
|
|
compassTurnOff: "Desactivar la orientación mediante la brújula",
|
|
compassAlign: "Alinear el mapa con la brújula",
|
|
dismissMessage: "Descartar mensaje",
|
|
enterParcel: "Introduzca un número de parcela para buscar.",
|
|
searchingParcel: "Buscando la parcela…",
|
|
searchFailedStatus: "La búsqueda de la parcela falló (estado {status}).",
|
|
noParcelFound: "No se encontró la parcela con el número «{parcelNumber}».",
|
|
foundParcel: "Se encontró la parcela {parcelNumber}.",
|
|
foundParcels: "Se encontraron {count} parcelas que coinciden con {parcelNumber}.",
|
|
parcelSearchFailed: "No se pudo buscar esa parcela.",
|
|
loadingWmsLayers: "Cargando capas WMS…",
|
|
wmsLoadFailed: "No se pudo cargar el servicio WMS.",
|
|
geoserverConnectionFailed: "La conexión con GeoServer falló (estado {status}).",
|
|
noPublishedLayers: "El servicio no devolvió ninguna capa publicada.",
|
|
selectLayerToZoom: "Seleccione una capa con extensión publicada para encuadrarla.",
|
|
parcel: "Parcela",
|
|
building: "Edificio",
|
|
area: "Área",
|
|
areaUnavailable: "Área no disponible",
|
|
inhabited: "Habitada",
|
|
viewCorrespondingBuilding: "Ver el edificio correspondiente",
|
|
associatedParcels: "Parcelas asociadas",
|
|
viewParcel: "Ver parcela {parcelNumber}",
|
|
parcelWithNumber: "Parcela {parcelNumber}",
|
|
unavailable: "No disponible",
|
|
noAssociatedParcels: "No se encontraron parcelas asociadas.",
|
|
zoomIn: "Acercar",
|
|
zoomOut: "Alejar",
|
|
attribution: "Atribuciones",
|
|
softAttribution:
|
|
'© Colaboradores de <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> © <a href="https://carto.com/attributions">CARTO</a>',
|
|
satelliteAttribution:
|
|
'Mosaicos © <a href="https://www.esri.com/en-us/legal/terms/full-master-agreement">Esri</a> — Fuente: Esri, Maxar, Earthstar Geographics y la comunidad de usuarios de SIG',
|
|
},
|
|
"pt-PT": {
|
|
languageName: "Português",
|
|
pageTitle: "Visualizador de Mapas XPro",
|
|
applicationMessages: "Mensagens da aplicação",
|
|
openMapControls: "Abrir controlos do mapa",
|
|
mapControls: "Controlos do mapa",
|
|
closeMapControls: "Fechar controlos do mapa",
|
|
mapVisualizer: "Visualizador de Mapas",
|
|
openSettings: "Abrir definições",
|
|
closeSettings: "Fechar definições",
|
|
settings: "Definições",
|
|
applySettings: "Aplicar",
|
|
useBrowserDefault: "Usar predefinição do navegador",
|
|
find: "Pesquisar",
|
|
parcelExample: "p. ex. 57 ou 2669.1",
|
|
parcelNumber: "Número da parcela",
|
|
findOnMap: "Localizar no mapa",
|
|
layers: "Camadas",
|
|
waitingForConnection: "A aguardar ligação.",
|
|
loadingPublishedLayers: "A carregar camadas publicadas.",
|
|
baseMap: "Mapa base",
|
|
softMinimal: "Minimalista suave",
|
|
openStreetMap: "OpenStreetMap",
|
|
satelliteImagery: "Imagem de satélite",
|
|
language: "Idioma",
|
|
applicationLanguage: "Idioma da aplicação",
|
|
mapView: "Vista do mapa",
|
|
closeFeatureInformation: "Fechar informação do elemento",
|
|
resetNorth: "Repor a orientação do mapa para norte",
|
|
zoomVisibleLayers: "Ajustar às camadas visíveis",
|
|
copyMapLink: "Copiar ligação para esta vista do mapa",
|
|
clipboardUnavailable: "O acesso à área de transferência não está disponível.",
|
|
mapLinkCopied: "A ligação para esta vista foi copiada para a área de transferência.",
|
|
mapLinkCopyFailed:
|
|
"Não foi possível copiar a ligação. Copie o endereço a partir do navegador.",
|
|
zoomArea: "Ampliar uma área",
|
|
exitAreaZoom: "Sair da ampliação de área (Esc)",
|
|
compassRequiresHttps:
|
|
"A bússola do dispositivo requer HTTPS; HTTP funciona apenas em localhost.",
|
|
compassUnavailable: "A bússola não está disponível neste dispositivo.",
|
|
compassPermissionDenied: "A permissão para usar a bússola não foi concedida.",
|
|
compassOn: "A orientação pela bússola está ativa.",
|
|
compassStartFailed: "Não foi possível iniciar a bússola do dispositivo.",
|
|
compassOff: "A orientação pela bússola está desativada.",
|
|
compassTurnOff: "Desativar orientação pela bússola",
|
|
compassAlign: "Alinhar mapa com a bússola",
|
|
dismissMessage: "Dispensar mensagem",
|
|
enterParcel: "Introduza um número de parcela para pesquisar.",
|
|
searchingParcel: "A pesquisar a parcela…",
|
|
searchFailedStatus: "A pesquisa da parcela falhou (estado {status}).",
|
|
noParcelFound: "Não foi encontrada a parcela com o número “{parcelNumber}”.",
|
|
foundParcel: "Parcela {parcelNumber} encontrada.",
|
|
foundParcels: "Foram encontradas {count} parcelas correspondentes a {parcelNumber}.",
|
|
parcelSearchFailed: "Não foi possível pesquisar essa parcela.",
|
|
loadingWmsLayers: "A carregar camadas WMS…",
|
|
wmsLoadFailed: "Não foi possível carregar o serviço WMS.",
|
|
geoserverConnectionFailed: "A ligação ao GeoServer falhou (estado {status}).",
|
|
noPublishedLayers: "O serviço não devolveu camadas publicadas.",
|
|
selectLayerToZoom: "Selecione uma camada com extensão publicada para a enquadrar.",
|
|
parcel: "Parcela",
|
|
building: "Prédio",
|
|
area: "Área",
|
|
areaUnavailable: "Área indisponível",
|
|
inhabited: "Habitada",
|
|
viewCorrespondingBuilding: "Ver prédio correspondente",
|
|
associatedParcels: "Parcelas associadas",
|
|
viewParcel: "Ver parcela {parcelNumber}",
|
|
parcelWithNumber: "Parcela {parcelNumber}",
|
|
unavailable: "Indisponível",
|
|
noAssociatedParcels: "Não foram encontradas parcelas associadas.",
|
|
zoomIn: "Ampliar",
|
|
zoomOut: "Reduzir",
|
|
attribution: "Atribuições",
|
|
softAttribution:
|
|
'© Colaboradores do <a href="https://www.openstreetmap.org/copyright">OpenStreetMap</a> © <a href="https://carto.com/attributions">CARTO</a>',
|
|
satelliteAttribution:
|
|
'Mosaicos © <a href="https://www.esri.com/en-us/legal/terms/full-master-agreement">Esri</a> — Fonte: Esri, Maxar, Earthstar Geographics e comunidade de utilizadores de SIG',
|
|
},
|
|
};
|
|
|
|
function normalizeLanguage(language) {
|
|
if (typeof language !== "string") {
|
|
return null;
|
|
}
|
|
|
|
const normalized = language.replace("_", "-").toLowerCase();
|
|
return Object.keys(TRANSLATIONS).find((candidate) => {
|
|
const candidateNormalized = candidate.toLowerCase();
|
|
return candidateNormalized === normalized || candidateNormalized.split("-")[0] === normalized.split("-")[0];
|
|
}) || null;
|
|
}
|
|
|
|
function readStoredLanguage(storage) {
|
|
try {
|
|
return normalizeLanguage(storage?.getItem(STORAGE_KEY));
|
|
} catch {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
function detectLanguage({ storage, languages = [] } = {}) {
|
|
const storedLanguage = readStoredLanguage(storage);
|
|
if (storedLanguage) {
|
|
return storedLanguage;
|
|
}
|
|
|
|
for (const language of languages) {
|
|
const supportedLanguage = normalizeLanguage(language);
|
|
if (supportedLanguage) {
|
|
return supportedLanguage;
|
|
}
|
|
}
|
|
|
|
return DEFAULT_LANGUAGE;
|
|
}
|
|
|
|
function detectBrowserLanguage(languages = []) {
|
|
for (const language of languages) {
|
|
const supportedLanguage = normalizeLanguage(language);
|
|
if (supportedLanguage) {
|
|
return supportedLanguage;
|
|
}
|
|
}
|
|
|
|
return DEFAULT_LANGUAGE;
|
|
}
|
|
|
|
function createI18n({
|
|
storage = globalScope.localStorage,
|
|
languages = globalScope.navigator?.languages || [globalScope.navigator?.language],
|
|
} = {}) {
|
|
const browserLanguage = detectBrowserLanguage(languages);
|
|
let preference = readStoredLanguage(storage);
|
|
let language = preference || browserLanguage;
|
|
|
|
function translate(key, values = {}) {
|
|
const template = TRANSLATIONS[language]?.[key]
|
|
?? TRANSLATIONS[DEFAULT_LANGUAGE]?.[key]
|
|
?? key;
|
|
return template.replace(/\{(\w+)\}/g, (match, name) =>
|
|
Object.hasOwn(values, name) ? String(values[name]) : match,
|
|
);
|
|
}
|
|
|
|
return {
|
|
get language() {
|
|
return language;
|
|
},
|
|
get locale() {
|
|
return language;
|
|
},
|
|
get preference() {
|
|
return preference;
|
|
},
|
|
get supportedLanguages() {
|
|
return Object.keys(TRANSLATIONS);
|
|
},
|
|
setLanguage(nextLanguage) {
|
|
const useBrowserDefault = nextLanguage == null || nextLanguage === "browser";
|
|
preference = useBrowserDefault
|
|
? null
|
|
: normalizeLanguage(nextLanguage) || DEFAULT_LANGUAGE;
|
|
language = preference || browserLanguage;
|
|
try {
|
|
if (preference) {
|
|
storage?.setItem(STORAGE_KEY, preference);
|
|
} else {
|
|
storage?.removeItem(STORAGE_KEY);
|
|
}
|
|
} catch {
|
|
// A blocked storage API must not prevent language selection.
|
|
}
|
|
return language;
|
|
},
|
|
t: translate,
|
|
tp(singularKey, pluralKey, count, values = {}) {
|
|
return translate(count === 1 ? singularKey : pluralKey, { ...values, count });
|
|
},
|
|
};
|
|
}
|
|
|
|
const exported = {
|
|
DEFAULT_LANGUAGE,
|
|
STORAGE_KEY,
|
|
TRANSLATIONS,
|
|
normalizeLanguage,
|
|
detectLanguage,
|
|
detectBrowserLanguage,
|
|
createI18n,
|
|
};
|
|
|
|
if (typeof module !== "undefined" && module.exports) {
|
|
module.exports = exported;
|
|
}
|
|
|
|
globalScope.XProI18n = exported;
|
|
})(typeof window === "undefined" ? globalThis : window);
|