Files

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);