Files
TREK/client/src/utils/placeLocality.ts
T
Maurice 8f02337d45 fix(i18n): hand Intl and the document the real language tag for br and gr
TREK's codes 'br' (Brazilian Portuguese) and 'gr' (Greek) went straight
into <html lang> and into ten Intl calls. 'br' is Breton, so Brazilian
users got Breton month names and screen readers announced the page as
Breton; 'gr' is no language at all, so Greek users got the default
locale. getIntlLanguage maps both, and every one of those sites goes
through it.
2026-10-07 16:34:59 +02:00

46 lines
1.7 KiB
TypeScript

import { getIntlLanguage } from '@trek/shared'
export interface PlaceLocality {
/** The country's name in the reader's language, or as the address spells it. */
country: string | null
/** State, province or prefecture, as resolved from the position. */
region: string | null
}
interface LocatedPlace {
address?: string | null
country_code?: string | null
region_name?: string | null
}
const hasDigits = (part: string) => /\d/.test(part)
const hasLetters = (part: string) => /\p{L}/u.test(part)
/** The last part of a formatted address is the country, when it reads like one. */
function countryFromAddress(address: string | null | undefined): string | null {
const parts = (address ?? '').split(',').map(p => p.trim()).filter(Boolean)
if (parts.length < 2) return null
const last = parts[parts.length - 1]
return !hasDigits(last) && hasLetters(last) ? last : null
}
/**
* Where a place lies, for filtering the trip's places (#2537).
*
* Both halves come from the position the server resolved, which is exact: the country
* code, named in the reader's language, and the region. A city is not offered, since a
* formatted address cannot tell one apart reliably (it names the borough before Berlin
* and the county before Schönefeld). A place not resolved yet falls back to the country
* its address ends on.
*/
export function placeLocality(place: LocatedPlace, language: string): PlaceLocality {
let country: string | null = null
if (place.country_code) {
try { country = new Intl.DisplayNames([getIntlLanguage(language)], { type: 'region' }).of(place.country_code.toUpperCase()) ?? null } catch { country = null }
}
return {
country: country ?? countryFromAddress(place.address),
region: place.region_name || null,
}
}