feat: add consent-based GPS location
This commit is contained in:
30
lib/i18n.tsx
30
lib/i18n.tsx
@@ -36,6 +36,21 @@ const translations = {
|
||||
"location.currentSource": "{location}: odczyt ze stacji IMGW {station}, około {distance} km.",
|
||||
"location.heroSource": "stacja IMGW: {station} · około {distance} km",
|
||||
"location.attribution": "Wyszukiwanie miejscowości:",
|
||||
"location.gpsUse": "Użyj mojej lokalizacji",
|
||||
"location.gpsLocating": "Ustalam lokalizację…",
|
||||
"location.gpsPromptTitle": "Pokazać pogodę dla Twojej lokalizacji?",
|
||||
"location.gpsPromptDescription": "Po Twojej zgodzie wtr. użyje GPS, aby wybrać miejscowość, najbliższą stację IMGW i prognozę. Pozycja zostanie zaokrąglona do około 100 metrów.",
|
||||
"location.gpsAllow": "Użyj GPS",
|
||||
"location.gpsNotNow": "Nie teraz",
|
||||
"location.gpsSecureContext": "GPS wymaga HTTPS. Na iPhonie lokalny adres HTTP z adresem IP nie może wyświetlić systemowego pytania o położenie. Użyj wdrożonej wersji HTTPS.",
|
||||
"location.gpsUnavailable": "Ta przeglądarka nie udostępnia lokalizacji GPS.",
|
||||
"location.gpsDenied": "Dostęp do lokalizacji został odrzucony. Możesz zmienić uprawnienia witryny w ustawieniach przeglądarki.",
|
||||
"location.gpsTimeout": "Nie udało się ustalić lokalizacji w wymaganym czasie. Spróbuj ponownie.",
|
||||
"location.gpsPositionUnavailable": "Nie udało się ustalić lokalizacji GPS. Sprawdź ustawienia urządzenia i spróbuj ponownie.",
|
||||
"location.gpsStationsPending": "Lista stacji IMGW nie jest jeszcze gotowa. Spróbuj ponownie za chwilę.",
|
||||
"location.gpsFallbackName": "Bieżąca lokalizacja",
|
||||
"location.gpsSelected": "Wybrano lokalizację: {location}.",
|
||||
"location.gpsAttribution": "Nazwy miejsc dla GPS:",
|
||||
"featured.label": "Szybki wybór",
|
||||
"featured.title": "Wybrane stacje IMGW",
|
||||
"favorites.title": "Ulubione lokalizacje",
|
||||
@@ -165,6 +180,21 @@ const translations = {
|
||||
"location.currentSource": "{location}: reading from IMGW station {station}, approximately {distance} km away.",
|
||||
"location.heroSource": "IMGW station: {station} · approximately {distance} km",
|
||||
"location.attribution": "Place search:",
|
||||
"location.gpsUse": "Use my location",
|
||||
"location.gpsLocating": "Finding your location…",
|
||||
"location.gpsPromptTitle": "Show weather for your location?",
|
||||
"location.gpsPromptDescription": "With your permission, wtr. will use GPS to select your place, the nearest IMGW station and the forecast. Your position will be rounded to approximately 100 metres.",
|
||||
"location.gpsAllow": "Use GPS",
|
||||
"location.gpsNotNow": "Not now",
|
||||
"location.gpsSecureContext": "GPS requires HTTPS. On iPhone, a local HTTP address using an IP cannot display the system location prompt. Use the deployed HTTPS version.",
|
||||
"location.gpsUnavailable": "This browser does not provide GPS location access.",
|
||||
"location.gpsDenied": "Location access was denied. You can change the website permission in your browser settings.",
|
||||
"location.gpsTimeout": "Your location could not be determined in time. Try again.",
|
||||
"location.gpsPositionUnavailable": "Your GPS location could not be determined. Check your device settings and try again.",
|
||||
"location.gpsStationsPending": "The IMGW station list is not ready yet. Try again in a moment.",
|
||||
"location.gpsFallbackName": "Current location",
|
||||
"location.gpsSelected": "Selected location: {location}.",
|
||||
"location.gpsAttribution": "GPS place names:",
|
||||
"featured.label": "Quick select",
|
||||
"featured.title": "Selected IMGW stations",
|
||||
"favorites.title": "Favourite locations",
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import type { Language } from "@/lib/i18n";
|
||||
import type { LocationSearchResult } from "@/types/location";
|
||||
import type { LocationSearchResult, ReverseLocationResult } from "@/types/location";
|
||||
|
||||
export async function fetchLocations(query: string, language: Language, signal?: AbortSignal): Promise<LocationSearchResult[]> {
|
||||
const params = new URLSearchParams({ query, language });
|
||||
@@ -7,3 +7,10 @@ export async function fetchLocations(query: string, language: Language, signal?:
|
||||
if (!response.ok) throw new Error("Location search is temporarily unavailable.");
|
||||
return response.json() as Promise<LocationSearchResult[]>;
|
||||
}
|
||||
|
||||
export async function fetchReverseLocation(latitude: number, longitude: number, language: Language): Promise<ReverseLocationResult> {
|
||||
const params = new URLSearchParams({ latitude: String(latitude), longitude: String(longitude), language });
|
||||
const response = await fetch(`/api/locations/reverse?${params}`);
|
||||
if (!response.ok) throw new Error("Reverse location search is temporarily unavailable.");
|
||||
return response.json() as Promise<ReverseLocationResult>;
|
||||
}
|
||||
|
||||
@@ -50,7 +50,10 @@ export function locateSynopStations(stations: SynopStation[], positions: MeteoSt
|
||||
});
|
||||
}
|
||||
|
||||
export function findNearestSynopStation(location: LocationSearchResult, stations: LocatedSynopStation[]): SelectedLocation | null {
|
||||
export function findNearestSynopStation(
|
||||
location: Pick<LocationSearchResult, "name" | "province" | "latitude" | "longitude">,
|
||||
stations: LocatedSynopStation[],
|
||||
): SelectedLocation | null {
|
||||
const nearest = stations.reduce<{ station: LocatedSynopStation; distanceKm: number } | null>((best, station) => {
|
||||
const distance = distanceKm(location.latitude, location.longitude, station.latitude, station.longitude);
|
||||
return !best || distance < best.distanceKm ? { station, distanceKm: distance } : best;
|
||||
|
||||
Reference in New Issue
Block a user