This commit is contained in:
Andras Schmelczer 2026-06-25 22:08:36 +01:00
parent c2c4ed6708
commit 2efa4d9f47
9 changed files with 1324 additions and 125 deletions

View file

@ -214,16 +214,41 @@ function readServerFeatureNames() {
return [...new Set(names)];
}
// Names of the Enum/Numeric feature *configs* (each needs a description + detail
// translation). We take the FIRST `name:` field after every Feature::Enum( /
// Feature::Numeric( opening. This deliberately skips macro-generated configs
// whose name is a `concat!(...)` expression (the crime rates — handled via
// deriveLegacyCrimeKeys instead) and stops the lazy match from running past such
// a config into an unrelated FeatureGroup `name:` (which previously made the
// group name "Properties" look like a required feature).
function readServerFeatureConfigNames() {
const src = readFileSync(FEATURES_RS, 'utf8');
const names = [];
const re = /Feature::(?:Enum|Numeric)\([^]*?name:\s*"((?:\\.|[^"\\])*)"/g;
for (const match of src.matchAll(re)) {
names.push(JSON.parse(`"${match[1]}"`));
const re = /Feature::(?:Enum|Numeric)\(/g;
let m;
while ((m = re.exec(src))) {
const after = src.slice(m.index + m[0].length);
const nm = after.match(/\bname:\s*(?:"((?:\\.|[^"\\])*)"|concat!)/);
if (nm && nm[1] !== undefined) names.push(JSON.parse(`"${nm[1]}"`));
}
return [...new Set(names)];
}
// The crime-rate features are generated by the crime_rate_features! macro and
// named "<type> (/yr, 7y|2y)". Their description/detail translations are shared
// across both windows under a single legacy "<type> (avg/yr)" key. This mirror
// of legacyCrimeFeatureKey() in descriptions.ts MUST use the same suffix regex,
// derived straight from the server keys so the checker and the runtime lookup
// stay in lock-step.
function deriveLegacyCrimeKeys(serverKeys) {
const legacy = new Set();
for (const key of serverKeys) {
const match = key.match(/^(.*) \(\/yr, \d+y\)$/);
if (match) legacy.add(`${match[1]} (avg/yr)`);
}
return legacy;
}
function readNamedRecord(file, varName) {
const sf = parseFile(join(I18N_DIR, file));
const init = findVarInitializer(sf, varName);
@ -355,7 +380,7 @@ function checkLocales(supportedCodes) {
}
}
function checkRecordCoverage(file, varName, supportedCodes, serverKeys, requiredKeys) {
function checkRecordCoverage(file, varName, supportedCodes, serverKeys, requiredKeys, legacyCrimeKeys) {
const record = readNamedRecord(file, varName);
const expected = supportedCodes.filter((c) => c !== 'en');
const present = Object.keys(record);
@ -397,10 +422,12 @@ function checkRecordCoverage(file, varName, supportedCodes, serverKeys, required
}
}
// Every key here must also be a translatable feature name in en.ts > server.
// Otherwise the description is unreachable — ts() looks up server.${name}.
// Every key here must also be a translatable feature name in en.ts > server,
// or a legacy crime key that maps onto the per-window server keys (see
// deriveLegacyCrimeKeys / legacyCrimeFeatureKey). Otherwise the description is
// unreachable — ts() looks up server.${name}.
for (const key of union) {
if (!serverKeys.has(key)) {
if (!serverKeys.has(key) && !legacyCrimeKeys.has(key)) {
fail(`${file}: key "${key}" has no matching entry in en.ts > server`);
}
}
@ -478,16 +505,25 @@ function main() {
checkLocaleLoaders(supportedCodes);
const en = readLocale('en');
const serverKeys = new Set(Object.keys(en.server ?? {}));
const sourceFeatureKeys = readServerFeatureConfigNames();
const legacyCrimeKeys = deriveLegacyCrimeKeys(serverKeys);
const requiredKeys = [...readServerFeatureConfigNames(), ...legacyCrimeKeys];
checkServerSourceCoverage(serverKeys);
checkRecordCoverage(
'descriptions.ts',
'descriptions',
supportedCodes,
serverKeys,
sourceFeatureKeys
requiredKeys,
legacyCrimeKeys
);
checkRecordCoverage(
'details.ts',
'details',
supportedCodes,
serverKeys,
requiredKeys,
legacyCrimeKeys
);
checkRecordCoverage('details.ts', 'details', supportedCodes, serverKeys, sourceFeatureKeys);
checkForbiddenVisibleStrings();
for (const w of warnings) console.warn(`warn: ${w}`);

View file

@ -516,6 +516,18 @@ const descriptions: Record<string, Record<string, string>> = {
},
};
/**
* The crime features carry a window suffix ("Burglary (/yr, 7y)"), but the
* per-locale description/detail/icon maps are keyed by the bare type's legacy
* "(avg/yr)" name and the text is the same for both windows. Map a crime
* feature name back to that legacy key so the existing translations resolve
* without duplicating every entry per window.
*/
export function legacyCrimeFeatureKey(featureName: string): string {
const match = featureName.match(/^(.*) \(\/yr, \d+y\)$/);
return match ? `${match[1]} (avg/yr)` : featureName;
}
/**
* Translate a feature description.
* - English: returns the server-provided description (single source of truth)
@ -524,7 +536,8 @@ const descriptions: Record<string, Record<string, string>> = {
export function tsDesc(featureName: string, englishFromServer: string): string {
const lang = i18n.language;
if (lang === 'en') return englishFromServer;
return descriptions[lang]?.[featureName] ?? englishFromServer;
const key = legacyCrimeFeatureKey(featureName);
return descriptions[lang]?.[key] ?? englishFromServer;
}
/**
@ -534,5 +547,6 @@ export function tsDesc(featureName: string, englishFromServer: string): string {
export function tsDetail(featureName: string, englishFromServer: string): string {
const lang = i18n.language;
if (lang === 'en') return englishFromServer;
return details[lang]?.[featureName] ?? englishFromServer;
const key = legacyCrimeFeatureKey(featureName);
return details[lang]?.[key] ?? englishFromServer;
}

View file

@ -26,6 +26,8 @@ const de: Translations = {
copy: 'Kopieren',
copied: 'Kopiert!',
copiedToClipboard: 'In die Zwischenablage kopiert',
captions: 'Untertitel',
sqm: 'm²',
loading: 'Wird geladen...',
loadMore: 'Mehr anzeigen',
remaining: 'noch {{count}}',
@ -622,6 +624,10 @@ const de: Translations = {
backToLogin: 'Zurück zur Anmeldung',
registerConsent:
'Mit der Kontoerstellung akzeptierst du unsere <terms>Nutzungsbedingungen</terms> und unsere <privacy>Datenschutzerklärung</privacy>.',
loginFailed: 'Anmeldung fehlgeschlagen',
registrationFailed: 'Registrierung fehlgeschlagen',
oauthFailed: 'OAuth-Anmeldung fehlgeschlagen',
passwordResetFailed: 'Anfrage zum Zurücksetzen des Passworts fehlgeschlagen',
},
// ── Upgrade Modal ──────────────────────────────────
@ -718,6 +724,11 @@ const de: Translations = {
outstanding: 'Outstanding',
distance: 'Entfernung',
crimeType: 'Deliktart',
qualificationLevel: 'Qualifikationsniveau',
tenureType: 'Wohnform',
crimeWindow: 'Zeitraum',
crimeWindow7y: '7 Jahre',
crimeWindow2y: '2 Jahre',
ethnicity: 'Ethnie',
poiType: 'POI-Typ',
party: 'Partei',
@ -808,6 +819,7 @@ const de: Translations = {
refiningResults: 'Ergebnisse werden verfeinert...',
weeklyLimitReached:
'Du hast das wöchentliche KI-Limit erreicht. Es wird nächste Woche automatisch zurückgesetzt.',
generateFailed: 'Filter konnten nicht generiert werden',
},
// ── Map Legend ─────────────────────────────────────
@ -827,6 +839,18 @@ const de: Translations = {
ogSchools: 'Schulen',
ogCrimeStats: 'Kriminalitätsdaten',
ogTransport: 'Transport',
basemap: { standard: 'Karte', satellite: 'Satellit' },
error: {
heading: 'Bei der Karte ist ein Problem aufgetreten',
body: 'Das kann passieren, wenn der Grafikkontext deines Browsers unterbrochen wird.',
reload: 'Karte neu laden',
},
actualListings: {
label: 'Inserate',
show: 'Tatsächliche Inserate anzeigen',
hide: 'Tatsächliche Inserate ausblenden',
},
poi: { zoomInToSeeDetails: 'Für Details hineinzoomen' },
},
// ── Properties Pane ────────────────────────────────
@ -906,6 +930,20 @@ const de: Translations = {
crimeDataEnds: 'Polizeidaten für dieses Gebiet enden {{year}}',
residents: 'Einwohner',
residentsTooltip: 'Wohnbevölkerung (ONS-Zensus 2021)',
crimeWindow7y: 'Letzte 7 Jahre',
crimeWindow2y: 'Letzte 2 Jahre',
crimeWindowLabel: 'Zeitraum',
crimeCardTitle: '{{name}} pro Jahr',
crimeRecordsToggle: 'Einzelne Straftaten anzeigen',
crimeRecordsHide: 'Einzelne Straftaten ausblenden',
crimeRecordsCount: '{{count}} Straftaten',
crimeRecordsLoading: 'Straftaten werden geladen…',
crimeRecordsEmpty: 'Keine einzelnen Straftaten erfasst',
crimeRecordsError: 'Straftaten konnten nicht geladen werden',
crimeRecordsLoadMore: 'Mehr laden',
crimeNoLocation: 'Ort nicht angegeben',
crimeOutcomeUnknown: 'Ergebnis nicht erfasst',
crimeYearPointTooltip: '{{year}}: {{rate}}/Jahr',
},
// ── Street View ────────────────────────────────────
@ -930,6 +968,7 @@ const de: Translations = {
searchOn: 'Im Umkreis von {{radius}} suchen bei',
exact: 'genau',
outcodeNotRecognised: 'Outcode nicht erkannt',
radiusMi: 'Umkreis {{count}} mi',
},
// ── Location Search ────────────────────────────────
@ -986,6 +1025,7 @@ const de: Translations = {
showcaseJourneyRoutes: 'Routen',
showcaseNearby: '{{value}} in der Nähe',
showcasePoliticalVoteShare: 'Politischer Stimmenanteil',
showcaseGe2024: 'Unterhauswahl 2024',
showcaseLotsMore: '...und vieles mehr',
showcaseMinutes: '{{count}} Min.',
showcaseSendShortlist: 'Shortlist senden',
@ -1418,6 +1458,8 @@ const de: Translations = {
noShareLinksYet: 'Noch keine geteilten Links',
copyShareLink: 'Geteilten Link kopieren',
clicksLabel: 'Klicks',
fetchShareLinksError: 'Geteilte Links konnten nicht abgerufen werden',
updateNewsletterError: 'Newsletter konnte nicht aktualisiert werden',
},
// ── Saved Page ─────────────────────────────────────
@ -1433,6 +1475,12 @@ const de: Translations = {
'Möchtest du diese gespeicherte Suche wirklich löschen? Dies kann nicht rückgängig gemacht werden.',
isBeingUpdated: '<strong>{{name}}</strong> wird aktualisiert',
updating: 'Wird aktualisiert...',
loadFailed: 'Suchen konnten nicht geladen werden',
saveFailed: 'Suche konnte nicht gespeichert werden',
deleteFailed: 'Suche konnte nicht gelöscht werden',
updateNotesFailed: 'Notizen konnten nicht aktualisiert werden',
updateNameFailed: 'Name konnte nicht aktualisiert werden',
updateFailed: 'Suche konnte nicht aktualisiert werden',
},
// ── Invites Page ───────────────────────────────────
@ -1452,6 +1500,7 @@ const de: Translations = {
created: 'Erstellt',
redeemed: 'Eingelöst',
pending: 'Ausstehend',
createInviteError: 'Einladung konnte nicht erstellt werden',
},
// ── Invite Page ────────────────────────────────────
@ -1478,6 +1527,99 @@ const de: Translations = {
youAlreadyHaveLicense: 'Du hast bereits eine Lizenz',
accountHasFullAccess: 'Dein Konto hat bereits vollen Zugang.',
failedToValidate: 'Einladungslink konnte nicht geprüft werden',
redeemFailed: 'Einladung konnte nicht eingelöst werden',
},
errors: {
appCrashTitle: 'Etwas ist schiefgelaufen',
appCrashBody: 'Lade die Seite neu, um es erneut zu versuchen.',
},
listing: {
viewed: 'Angesehen',
openListing: 'Inserat öffnen',
listings: 'Inserate',
listing: 'Inserat',
showingOf: '{{visible}} von {{count}} werden angezeigt',
groupedNear: 'Gruppiert an dieser Kartenposition',
},
overlays: {
heading: 'Overlays',
baseMap: 'Basiskarte',
colourOpacity: 'Farbdeckkraft',
dataOverlays: 'Daten-Overlays',
about: 'Über {{name}}',
zoomWarning: 'Zoome weiter hinein, um das ausgewählte Overlay zu sehen.',
zoomWarning_other: 'Zoome weiter hinein, um die ausgewählten Overlays zu sehen.',
noise: {
label: 'Lärm',
detail:
'Defra Strategic Noise Mapping Round 4 (2022), kombiniert Quellen aus Straße, Schiene und Flughäfen. Die Werte verwenden die EU-Standardgröße Lden (gewichteter 24-Stunden-Mittelwert für Tag, Abend und Nacht), modelliert auf einem 10-m-Raster in 4 m Höhe über Grund. Hellere Bereiche zeigen höhere modellierte Lärmwerte an. Lizenziert unter der Open Government Licence v3.0.',
},
crimeHotspots: {
label: 'Kriminalitäts-Hotspots',
detail:
'Clientseitige Heatmap der von police.uk veröffentlichten Straftaten auf Straßenebene der letzten Monate. Die Koordinaten von police.uk sind anonymisierte, auf ein Raster gerundete Punkte und keine exakten Tatorte. Die Heatmap sollte daher als Näherung der relativen Dichte und nicht als präzise Karte einzelner Vorfälle gelesen werden.',
},
treesOutsideWoodlands: {
label: 'Bäume & Wald',
detail:
'Canopy-Polygone aus Forest Research Trees Outside Woodland (TOW) v1 — Einzelbäume und Baumgruppen — vereint mit Waldflächen des National Forest Inventory (NFI) (≥0,5 ha), die TOW bewusst ausschließt. Zusammen erfassen sie sowohl Straßenbäume als auch tatsächliche Wälder. Die Deckkraft der Polygone skaliert mit der Kronenfläche.',
},
propertyBorders: {
label: 'Grundstücksgrenzen',
detail:
'HM Land Registry INSPIRE Index Polygons — die Lage und ungefähre Ausdehnung von im Freehold eingetragenem Eigentum in England & Wales, dargestellt als Umrisse auf Straßenebene. Dies sind „general boundaries“ nur zur Orientierung und nicht die genaue rechtliche Grundstücksgrenze; sie schließen reine Leasehold-Interessen und nicht eingetragenes Land aus (rund 8590 % des Freehold-Lands sind erfasst). Diese Informationen unterliegen dem Crown copyright und den Datenbankrechten 2026 und werden mit Genehmigung des HM Land Registry wiedergegeben. Die Polygone (einschließlich der zugehörigen Geometrie, namentlich x-, y-Koordinaten) unterliegen dem Crown copyright und den Datenbankrechten 2026 Ordnance Survey AC0000851063. Lizenziert unter der Open Government Licence v3.0.',
},
newDevelopments: {
label: 'Neubauprojekte',
detail:
'Eine vorausschauende Pipeline neuer Wohnbauten. Blaue Marker kennzeichnen Standorte in den gesetzlichen MHCLG Brownfield Land Registers — jeweils mit einer geschätzten Netto-Wohnungskapazität und einem Status der Baugenehmigung — zusammen mit Veräußerungsstandorten des Homes England Land Hub. Sie zeigen, wo neue Wohnungen geplant sind, oft Jahre bevor sie in EPC- oder Verkaufsdaten auftauchen. Die Wohnungszahlen sind Kapazitätsschätzungen, keine Zusagen, und ein Standort in einem Register ist eine Gelegenheit und keine Garantie für eine Bebauung. Lizenziert unter der Open Government Licence v3.0.',
},
},
crimeTypes: {
violenceAndSexualOffences: 'Gewalt- & Sexualdelikte',
antiSocialBehaviour: 'Antisoziales Verhalten',
criminalDamageAndArson: 'Sachbeschädigung & Brandstiftung',
publicOrder: 'Öffentliche Ordnung',
shoplifting: 'Ladendiebstahl',
vehicleCrime: 'Fahrzeugkriminalität',
burglary: 'Einbruch',
otherTheft: 'Sonstiger Diebstahl',
theftFromThePerson: 'Diebstahl an Personen',
bicycleTheft: 'Fahrraddiebstahl',
drugs: 'Drogen',
robbery: 'Raub',
possessionOfWeapons: 'Waffenbesitz',
otherCrime: 'Sonstige Kriminalität',
},
journey: {
bus: 'Bus',
lineSuffix: 'Linie',
},
poiPopup: {
school: {
capacity: 'Kapazität',
type: 'Art',
ages: 'Alter',
gender: 'Geschlecht',
pupilsLabel: 'Schüler',
pupils: 'Schüler',
freeMeal: 'Kostenloses Essen',
ofsted: 'Ofsted',
sixthForm: 'Oberstufe',
religion: 'Religion',
admissions: 'Aufnahme',
trust: 'Trust',
address: 'Adresse',
localAuthority: 'LA',
head: 'Schulleitung',
website: 'Website',
},
},
// ── Format / Time ──────────────────────────────────
@ -1519,6 +1661,9 @@ const de: Translations = {
step6Title: 'Was ist in der Nähe?',
step6Content:
'Blende Schulen, Geschäfte, Bahnhöfe, Parks und Restaurants auf der Karte ein, um zu sehen, was erreichbar ist.',
step7Title: 'Mehr Kontext einblenden',
step7Content:
'Blende Overlays wie Kriminalitäts-Hotspots, Lärm, Baumbestand, Grundstücksgrenzen und Neubaugebiete auf der Karte ein und wechsle die Basiskarte nach Bedarf.',
},
// ── Server-derived values ──────────────────────────
@ -1541,11 +1686,11 @@ const de: Translations = {
'Property type': 'Immobilientyp',
'Leasehold/Freehold': 'Leasehold/Freehold',
'Last known price': 'Letzter bekannter Preis',
'Estimated price': 'Geschätzter Preis',
'Estimated current price': 'Geschätzter heutiger Preis',
'Estimated price': 'Gesch. Preis',
'Estimated current price': 'Gesch. heutiger Preis',
'Price per sqm': 'Preis pro m²',
'Est. price per sqm': 'Gesch. Preis pro m²',
'Estimated monthly rent': 'Geschätzte Monatsmiete',
'Estimated monthly rent': 'Gesch. Monatsmiete',
'Total floor area (sqm)': 'Gesamtwohnfläche (m²)',
'Number of bedrooms & living rooms': 'Anzahl Schlaf- und Wohnzimmer',
'Construction year': 'Baujahr',
@ -1578,23 +1723,58 @@ const de: Translations = {
'Housing Conditions Score': 'Wert der Wohnbedingungen',
'Air Quality and Road Safety Score': 'Wert für Luftqualität und Verkehrssicherheit',
// ─ Feature names (Crime) ─
'Serious crime (avg/yr)': 'Schwere Straftaten (Dichte)',
'Minor crime (avg/yr)': 'Leichte Straftaten (Dichte)',
'Violence and sexual offences (avg/yr)': 'Gewalt- und Sexualdelikte (Dichte)',
'Burglary (avg/yr)': 'Einbrüche (Dichte)',
'Robbery (avg/yr)': 'Raubüberfälle (Dichte)',
'Vehicle crime (avg/yr)': 'Fahrzeugkriminalität (Dichte)',
'Anti-social behaviour (avg/yr)': 'Antisoziales Verhalten (Dichte)',
'Criminal damage and arson (avg/yr)': 'Sachbeschädigung und Brandstiftung (Dichte)',
'Other theft (avg/yr)': 'Sonstiger Diebstahl (Dichte)',
'Theft from the person (avg/yr)': 'Diebstahl von der Person (Dichte)',
'Shoplifting (avg/yr)': 'Ladendiebstahl (Dichte)',
'Bicycle theft (avg/yr)': 'Fahrraddiebstahl (Dichte)',
'Drugs (avg/yr)': 'Drogendelikte (Dichte)',
'Possession of weapons (avg/yr)': 'Waffenbesitz (Dichte)',
'Public order (avg/yr)': 'Störung der öffentlichen Ordnung (Dichte)',
'Other crime (avg/yr)': 'Sonstige Straftaten (Dichte)',
// ─ Feature names (Crime) — bevölkerungsnormierte Rate, 7 Jahre & 2 Jahre ─
'Serious crime (/yr, 7y)': 'Schwere Straftaten (pro Jahr, 7 J.)',
'Serious crime (/yr, 2y)': 'Schwere Straftaten (pro Jahr, 2 J.)',
'Minor crime (/yr, 7y)': 'Leichte Straftaten (pro Jahr, 7 J.)',
'Minor crime (/yr, 2y)': 'Leichte Straftaten (pro Jahr, 2 J.)',
'Violence and sexual offences (/yr, 7y)':
'Gewalt- und Sexualdelikte (pro Jahr, 7 J.)',
'Violence and sexual offences (/yr, 2y)':
'Gewalt- und Sexualdelikte (pro Jahr, 2 J.)',
'Burglary (/yr, 7y)': 'Einbrüche (pro Jahr, 7 J.)',
'Burglary (/yr, 2y)': 'Einbrüche (pro Jahr, 2 J.)',
'Robbery (/yr, 7y)': 'Raubüberfälle (pro Jahr, 7 J.)',
'Robbery (/yr, 2y)': 'Raubüberfälle (pro Jahr, 2 J.)',
'Vehicle crime (/yr, 7y)': 'Fahrzeugkriminalität (pro Jahr, 7 J.)',
'Vehicle crime (/yr, 2y)': 'Fahrzeugkriminalität (pro Jahr, 2 J.)',
'Anti-social behaviour (/yr, 7y)': 'Antisoziales Verhalten (pro Jahr, 7 J.)',
'Anti-social behaviour (/yr, 2y)': 'Antisoziales Verhalten (pro Jahr, 2 J.)',
'Criminal damage and arson (/yr, 7y)':
'Sachbeschädigung und Brandstiftung (pro Jahr, 7 J.)',
'Criminal damage and arson (/yr, 2y)':
'Sachbeschädigung und Brandstiftung (pro Jahr, 2 J.)',
'Other theft (/yr, 7y)': 'Sonstiger Diebstahl (pro Jahr, 7 J.)',
'Other theft (/yr, 2y)': 'Sonstiger Diebstahl (pro Jahr, 2 J.)',
'Theft from the person (/yr, 7y)': 'Diebstahl von der Person (pro Jahr, 7 J.)',
'Theft from the person (/yr, 2y)': 'Diebstahl von der Person (pro Jahr, 2 J.)',
'Shoplifting (/yr, 7y)': 'Ladendiebstahl (pro Jahr, 7 J.)',
'Shoplifting (/yr, 2y)': 'Ladendiebstahl (pro Jahr, 2 J.)',
'Bicycle theft (/yr, 7y)': 'Fahrraddiebstahl (pro Jahr, 7 J.)',
'Bicycle theft (/yr, 2y)': 'Fahrraddiebstahl (pro Jahr, 2 J.)',
'Drugs (/yr, 7y)': 'Drogendelikte (pro Jahr, 7 J.)',
'Drugs (/yr, 2y)': 'Drogendelikte (pro Jahr, 2 J.)',
'Possession of weapons (/yr, 7y)': 'Waffenbesitz (pro Jahr, 7 J.)',
'Possession of weapons (/yr, 2y)': 'Waffenbesitz (pro Jahr, 2 J.)',
'Public order (/yr, 7y)': 'Störung der öffentlichen Ordnung (pro Jahr, 7 J.)',
'Public order (/yr, 2y)': 'Störung der öffentlichen Ordnung (pro Jahr, 2 J.)',
'Other crime (/yr, 7y)': 'Sonstige Straftaten (pro Jahr, 7 J.)',
'Other crime (/yr, 2y)': 'Sonstige Straftaten (pro Jahr, 2 J.)',
// Reine Deliktbezeichnungen (Aufschlüsselung nach Art + Einzeldatensätze).
// („Burglary“ ist bereits bei den spezifischen Delikten unten definiert.)
'Violence and sexual offences': 'Gewalt- und Sexualdelikte',
Robbery: 'Raubüberfälle',
'Vehicle crime': 'Fahrzeugkriminalität',
'Anti-social behaviour': 'Antisoziales Verhalten',
'Criminal damage and arson': 'Sachbeschädigung und Brandstiftung',
'Other theft': 'Sonstiger Diebstahl',
'Theft from the person': 'Diebstahl von der Person',
Shoplifting: 'Ladendiebstahl',
'Bicycle theft': 'Fahrraddiebstahl',
Drugs: 'Drogendelikte',
'Possession of weapons': 'Waffenbesitz',
'Public order': 'Störung der öffentlichen Ordnung',
'Other crime': 'Sonstige Straftaten',
// ─ Feature names (Neighbours) ─
'Median age': 'Medianalter',

View file

@ -56,6 +56,8 @@ const en = {
closePane: 'Close pane',
yes: 'Yes',
no: 'No',
captions: 'Captions',
sqm: 'sqm',
},
// ── Header / Nav ───────────────────────────────────
@ -610,6 +612,10 @@ const en = {
backToLogin: 'Back to login',
registerConsent:
'By creating an account you agree to our <terms>Terms of Service</terms> and <privacy>Privacy Policy</privacy>.',
loginFailed: 'Login failed',
registrationFailed: 'Registration failed',
oauthFailed: 'OAuth login failed',
passwordResetFailed: 'Password reset request failed',
},
// ── Upgrade Modal ──────────────────────────────────
@ -704,6 +710,11 @@ const en = {
outstanding: 'Outstanding',
distance: 'Distance',
crimeType: 'Crime type',
qualificationLevel: 'Qualification level',
tenureType: 'Tenure type',
crimeWindow: 'Averaging period',
crimeWindow7y: '7-year',
crimeWindow2y: '2-year',
ethnicity: 'Ethnicity',
poiType: 'POI type',
party: 'Party',
@ -794,6 +805,7 @@ const en = {
refiningResults: 'Refining results...',
weeklyLimitReached:
'Youve reached the weekly AI usage limit. Itll reset automatically next week.',
generateFailed: 'Failed to generate filters',
},
// ── Map Legend ─────────────────────────────────────
@ -813,6 +825,23 @@ const en = {
ogSchools: 'Schools',
ogCrimeStats: 'Crime stats',
ogTransport: 'Transport',
basemap: {
standard: 'Map',
satellite: 'Satellite',
},
error: {
heading: 'The map ran into a problem',
body: 'This can happen when your browsers graphics context is interrupted.',
reload: 'Reload the map',
},
actualListings: {
label: 'Listings',
show: 'Show actual listings',
hide: 'Hide actual listings',
},
poi: {
zoomInToSeeDetails: 'Zoom in to see details',
},
},
// ── Properties Pane ────────────────────────────────
@ -890,6 +919,20 @@ const en = {
crimeDataEnds: 'Police data for this area ends {{year}}',
residents: 'Residents',
residentsTooltip: 'Usual residents (ONS Census 2021)',
crimeWindow7y: 'Last 7 years',
crimeWindow2y: 'Last 2 years',
crimeWindowLabel: 'Time period',
crimeCardTitle: '{{name}} per year',
crimeRecordsToggle: 'Show individual crimes',
crimeRecordsHide: 'Hide individual crimes',
crimeRecordsCount: '{{count}} crimes',
crimeRecordsLoading: 'Loading crimes…',
crimeRecordsEmpty: 'No individual crimes recorded',
crimeRecordsError: 'Could not load crimes',
crimeRecordsLoadMore: 'Load more',
crimeNoLocation: 'Location withheld',
crimeOutcomeUnknown: 'Outcome not recorded',
crimeYearPointTooltip: '{{year}}: {{rate}}/yr',
},
// ── Street View ────────────────────────────────────
@ -914,6 +957,7 @@ const en = {
searchOn: 'Search {{radius}} on',
exact: 'exact',
outcodeNotRecognised: 'Outcode not recognised',
radiusMi: '{{count}} mi radius',
},
// ── Location Search ────────────────────────────────
@ -971,6 +1015,7 @@ const en = {
showcaseJourneyRoutes: 'Journey routes',
showcaseNearby: '{{value}} nearby',
showcasePoliticalVoteShare: 'Political vote share',
showcaseGe2024: '2024 GE',
showcaseLotsMore: '...and lots more',
showcaseMinutes: '{{count}} min',
showcaseSendShortlist: 'Send the shortlist',
@ -1395,6 +1440,8 @@ const en = {
noShareLinksYet: 'No shared links yet',
copyShareLink: 'Copy shared link',
clicksLabel: 'clicks',
fetchShareLinksError: 'Failed to fetch share links',
updateNewsletterError: 'Failed to update newsletter',
},
// ── Saved Page ─────────────────────────────────────
@ -1409,6 +1456,12 @@ const en = {
deleteSearchConfirm: 'Are you sure you want to delete this saved search? This cant be undone.',
isBeingUpdated: '<strong>{{name}}</strong> is being updated',
updating: 'Updating...',
loadFailed: 'Failed to load searches',
saveFailed: 'Failed to save search',
deleteFailed: 'Failed to delete search',
updateNotesFailed: 'Failed to update notes',
updateNameFailed: 'Failed to update name',
updateFailed: 'Failed to update search',
},
// ── Invites Page ───────────────────────────────────
@ -1428,6 +1481,7 @@ const en = {
created: 'Created',
redeemed: 'Redeemed',
pending: 'Pending',
createInviteError: 'Failed to create invite',
},
// ── Invite Page ────────────────────────────────────
@ -1454,6 +1508,105 @@ const en = {
youAlreadyHaveLicense: 'You already have a license',
accountHasFullAccess: 'Your account already has full access.',
failedToValidate: 'Failed to validate invite link',
redeemFailed: 'Failed to redeem invite',
},
// ── Error Boundaries ───────────────────────────────
errors: {
appCrashTitle: 'Something went wrong',
appCrashBody: 'Refresh the page to try again.',
},
// ── Listing Popups ─────────────────────────────────
listing: {
viewed: 'Viewed',
openListing: 'Open listing',
listings: 'listings',
listing: 'Listing',
showingOf: 'Showing {{visible}} of {{count}}',
groupedNear: 'Grouped near this map position',
},
// ── Map Overlays Pane ──────────────────────────────
overlays: {
heading: 'Overlays',
baseMap: 'Base map',
colourOpacity: 'Colour opacity',
dataOverlays: 'Data overlays',
about: 'About {{name}}',
zoomWarning: 'Zoom in further to see the selected overlay.',
zoomWarning_other: 'Zoom in further to see the selected overlays.',
noise: {
label: 'Noise',
detail:
'Defra Strategic Noise Mapping Round 4 (2022), combining road, rail, and airport sources. Values are the EU-standard Lden metric (day-evening-night 24-hour weighted average), modelled on a 10m grid at 4m above ground. Brighter areas indicate higher modelled noise. Licensed under the Open Government Licence v3.0.',
},
crimeHotspots: {
label: 'Crime hotspots',
detail:
'Client-side heatmap of street-level crimes published by police.uk over the most recent months. Police.uk coordinates are anonymised snap-to-grid points, not exact offence locations, so the heatmap should be read as an approximation of relative density rather than a precise map of incidents.',
},
treesOutsideWoodlands: {
label: 'Trees & woodland',
detail:
'Forest Research Trees Outside Woodland (TOW) v1 canopy polygons — lone trees and groups of trees — unioned with National Forest Inventory (NFI) woodland blocks (≥0.5 ha) that TOW deliberately excludes. Together they cover both street trees and actual woods. Polygon opacity scales with canopy area.',
},
propertyBorders: {
label: 'Property borders',
detail:
'HM Land Registry INSPIRE Index Polygons — the position and indicative extent of freehold registered property in England & Wales, drawn as outlines at street level. These are "general boundaries" for guidance only, not the precise legal boundary of a property, and they exclude leasehold-only interests and unregistered land (roughly 8590% of freehold land is covered). This information is subject to Crown copyright and database rights 2026 and is reproduced with the permission of HM Land Registry. The polygons (including the associated geometry, namely x, y co-ordinates) are subject to Crown copyright and database rights 2026 Ordnance Survey AC0000851063. Licensed under the Open Government Licence v3.0.',
},
newDevelopments: {
label: 'New developments',
detail:
'A forward-looking pipeline of new housing. Blue markers mark sites on the statutory MHCLG Brownfield Land registers — each carrying an estimated net-dwelling capacity and planning-permission status — together with Homes England Land Hub disposal sites. These show where new homes are planned, often years before they appear in EPC or sale records. Dwelling figures are capacity estimates, not commitments, and a site on a register is an opportunity rather than a guarantee of construction. Licensed under the Open Government Licence v3.0.',
},
},
// ── Crime-type overlay selector ────────────────────
crimeTypes: {
violenceAndSexualOffences: 'Violence & sexual offences',
antiSocialBehaviour: 'Anti-social behaviour',
criminalDamageAndArson: 'Criminal damage & arson',
publicOrder: 'Public order',
shoplifting: 'Shoplifting',
vehicleCrime: 'Vehicle crime',
burglary: 'Burglary',
otherTheft: 'Other theft',
theftFromThePerson: 'Theft from the person',
bicycleTheft: 'Bicycle theft',
drugs: 'Drugs',
robbery: 'Robbery',
possessionOfWeapons: 'Possession of weapons',
otherCrime: 'Other crime',
},
// ── Journey Instructions ───────────────────────────
journey: {
bus: 'Bus',
lineSuffix: 'line',
},
// ── POI Popups ─────────────────────────────────────
poiPopup: {
school: {
capacity: 'Capacity',
type: 'Type',
ages: 'Ages',
gender: 'Gender',
pupilsLabel: 'Pupils',
pupils: 'pupils',
freeMeal: 'Free meal',
ofsted: 'Ofsted',
sixthForm: 'Sixth form',
religion: 'Religion',
admissions: 'Admissions',
trust: 'Trust',
address: 'Address',
localAuthority: 'LA',
head: 'Head',
website: 'Website',
},
},
// ── Format / Time ──────────────────────────────────
@ -1495,6 +1648,9 @@ const en = {
step6Title: 'Whats nearby?',
step6Content:
'Toggle schools, shops, stations, parks, and restaurants on the map to see whats within reach.',
step7Title: 'Layer on more context',
step7Content:
'Toggle overlays like crime hotspots, noise, tree cover, property boundaries, and new-build sites on the map, and switch the basemap to suit.',
},
// ── Server-derived values ──────────────────────────
@ -1517,11 +1673,11 @@ const en = {
'Property type': 'Property type',
'Leasehold/Freehold': 'Leasehold/Freehold',
'Last known price': 'Last known price',
'Estimated price': 'Estimated price',
'Estimated current price': 'Estimated current price',
'Estimated price': 'Est. price',
'Estimated current price': 'Est. current price',
'Price per sqm': 'Price per sqm',
'Est. price per sqm': 'Est. price per sqm',
'Estimated monthly rent': 'Estimated monthly rent',
'Estimated monthly rent': 'Est. monthly rent',
'Total floor area (sqm)': 'Total floor area (sqm)',
'Number of bedrooms & living rooms': 'Number of bedrooms & living rooms',
'Construction year': 'Construction year',
@ -1552,23 +1708,56 @@ const en = {
'Housing Conditions Score': 'Housing Conditions Score',
'Air Quality and Road Safety Score': 'Air Quality and Road Safety Score',
// ─ Feature names (Crime) ─
'Serious crime (avg/yr)': 'Serious crime (density)',
'Minor crime (avg/yr)': 'Minor crime (density)',
'Violence and sexual offences (avg/yr)': 'Violence and sexual offences (density)',
'Burglary (avg/yr)': 'Burglary (density)',
'Robbery (avg/yr)': 'Robbery (density)',
'Vehicle crime (avg/yr)': 'Vehicle crime (density)',
'Anti-social behaviour (avg/yr)': 'Anti-social behaviour (density)',
'Criminal damage and arson (avg/yr)': 'Criminal damage and arson (density)',
'Other theft (avg/yr)': 'Other theft (density)',
'Theft from the person (avg/yr)': 'Theft from the person (density)',
'Shoplifting (avg/yr)': 'Shoplifting (density)',
'Bicycle theft (avg/yr)': 'Bicycle theft (density)',
'Drugs (avg/yr)': 'Drugs (density)',
'Possession of weapons (avg/yr)': 'Possession of weapons (density)',
'Public order (avg/yr)': 'Public order (density)',
'Other crime (avg/yr)': 'Other crime (density)',
// ─ Feature names (Crime) — population-normalised rate, 7-year & 2-year ─
'Serious crime (/yr, 7y)': 'Serious crime (per year, 7yr)',
'Serious crime (/yr, 2y)': 'Serious crime (per year, 2yr)',
'Minor crime (/yr, 7y)': 'Minor crime (per year, 7yr)',
'Minor crime (/yr, 2y)': 'Minor crime (per year, 2yr)',
'Violence and sexual offences (/yr, 7y)':
'Violence & sexual offences (per year, 7yr)',
'Violence and sexual offences (/yr, 2y)':
'Violence & sexual offences (per year, 2yr)',
'Burglary (/yr, 7y)': 'Burglary (per year, 7yr)',
'Burglary (/yr, 2y)': 'Burglary (per year, 2yr)',
'Robbery (/yr, 7y)': 'Robbery (per year, 7yr)',
'Robbery (/yr, 2y)': 'Robbery (per year, 2yr)',
'Vehicle crime (/yr, 7y)': 'Vehicle crime (per year, 7yr)',
'Vehicle crime (/yr, 2y)': 'Vehicle crime (per year, 2yr)',
'Anti-social behaviour (/yr, 7y)': 'Anti-social behaviour (per year, 7yr)',
'Anti-social behaviour (/yr, 2y)': 'Anti-social behaviour (per year, 2yr)',
'Criminal damage and arson (/yr, 7y)': 'Criminal damage & arson (per year, 7yr)',
'Criminal damage and arson (/yr, 2y)': 'Criminal damage & arson (per year, 2yr)',
'Other theft (/yr, 7y)': 'Other theft (per year, 7yr)',
'Other theft (/yr, 2y)': 'Other theft (per year, 2yr)',
'Theft from the person (/yr, 7y)': 'Theft from the person (per year, 7yr)',
'Theft from the person (/yr, 2y)': 'Theft from the person (per year, 2yr)',
'Shoplifting (/yr, 7y)': 'Shoplifting (per year, 7yr)',
'Shoplifting (/yr, 2y)': 'Shoplifting (per year, 2yr)',
'Bicycle theft (/yr, 7y)': 'Bicycle theft (per year, 7yr)',
'Bicycle theft (/yr, 2y)': 'Bicycle theft (per year, 2yr)',
'Drugs (/yr, 7y)': 'Drugs (per year, 7yr)',
'Drugs (/yr, 2y)': 'Drugs (per year, 2yr)',
'Possession of weapons (/yr, 7y)': 'Possession of weapons (per year, 7yr)',
'Possession of weapons (/yr, 2y)': 'Possession of weapons (per year, 2yr)',
'Public order (/yr, 7y)': 'Public order (per year, 7yr)',
'Public order (/yr, 2y)': 'Public order (per year, 2yr)',
'Other crime (/yr, 7y)': 'Other crime (per year, 7yr)',
'Other crime (/yr, 2y)': 'Other crime (per year, 2yr)',
// Bare crime-type labels (per-type breakdown rows + records list).
// ("Burglary" is already defined in the specific-crime overflow keys below.)
'Violence and sexual offences': 'Violence & sexual offences',
Robbery: 'Robbery',
'Vehicle crime': 'Vehicle crime',
'Anti-social behaviour': 'Anti-social behaviour',
'Criminal damage and arson': 'Criminal damage & arson',
'Other theft': 'Other theft',
'Theft from the person': 'Theft from the person',
Shoplifting: 'Shoplifting',
'Bicycle theft': 'Bicycle theft',
Drugs: 'Drugs',
'Possession of weapons': 'Possession of weapons',
'Public order': 'Public order',
'Other crime': 'Other crime',
// ─ Feature names (Neighbours) ─
'Median age': 'Median age',

View file

@ -58,6 +58,8 @@ const fr: Translations = {
closePane: 'Fermer le panneau',
yes: 'Oui',
no: 'Non',
captions: 'Légendes',
sqm: 'm²',
},
// ── Header / Nav ───────────────────────────────────
@ -635,6 +637,10 @@ const fr: Translations = {
backToLogin: 'Retour à la connexion',
registerConsent:
'En créant un compte, vous acceptez nos <terms>Conditions dutilisation</terms> et notre <privacy>Politique de confidentialité</privacy>.',
loginFailed: 'Échec de la connexion',
registrationFailed: 'Échec de linscription',
oauthFailed: 'Échec de la connexion OAuth',
passwordResetFailed: 'Échec de la demande de réinitialisation du mot de passe',
},
// ── Upgrade Modal ──────────────────────────────────
@ -732,6 +738,11 @@ const fr: Translations = {
outstanding: 'Outstanding',
distance: 'Distance',
crimeType: 'Type dinfraction',
qualificationLevel: 'Niveau de qualification',
tenureType: 'Statut doccupation',
crimeWindow: 'Période',
crimeWindow7y: '7 ans',
crimeWindow2y: '2 ans',
ethnicity: 'Origine ethnique',
poiType: 'Type de point dintérêt',
party: 'Parti',
@ -822,6 +833,7 @@ const fr: Translations = {
refiningResults: 'Affinage des résultats...',
weeklyLimitReached:
'Vous avez atteint la limite hebdomadaire dutilisation de lIA. Elle se réinitialisera automatiquement la semaine prochaine.',
generateFailed: 'Échec de la génération des filtres',
},
// ── Map Legend ─────────────────────────────────────
@ -841,6 +853,18 @@ const fr: Translations = {
ogSchools: 'Écoles',
ogCrimeStats: 'Criminalité',
ogTransport: 'Transports',
basemap: { standard: 'Carte', satellite: 'Satellite' },
error: {
heading: 'La carte a rencontré un problème',
body: 'Cela peut se produire lorsque le contexte graphique de votre navigateur est interrompu.',
reload: 'Recharger la carte',
},
actualListings: {
label: 'Annonces',
show: 'Afficher les annonces réelles',
hide: 'Masquer les annonces réelles',
},
poi: { zoomInToSeeDetails: 'Zoomez pour voir les détails' },
},
// ── Properties Pane ────────────────────────────────
@ -919,6 +943,20 @@ const fr: Translations = {
crimeDataEnds: "Les données de police pour cette zone s'arrêtent en {{year}}",
residents: 'Habitants',
residentsTooltip: 'Résidents habituels (recensement ONS 2021)',
crimeWindow7y: 'Ces 7 dernières années',
crimeWindow2y: 'Ces 2 dernières années',
crimeWindowLabel: 'Période',
crimeCardTitle: '{{name}} par an',
crimeRecordsToggle: 'Afficher les infractions individuelles',
crimeRecordsHide: 'Masquer les infractions individuelles',
crimeRecordsCount: '{{count}} infractions',
crimeRecordsLoading: 'Chargement des infractions…',
crimeRecordsEmpty: 'Aucune infraction individuelle enregistrée',
crimeRecordsError: 'Impossible de charger les infractions',
crimeRecordsLoadMore: 'Charger plus',
crimeNoLocation: 'Lieu non communiqué',
crimeOutcomeUnknown: 'Résultat non enregistré',
crimeYearPointTooltip: '{{year}} : {{rate}}/an',
},
// ── Street View ────────────────────────────────────
@ -943,6 +981,7 @@ const fr: Translations = {
searchOn: 'Rechercher dans un rayon de {{radius}} sur',
exact: 'exact',
outcodeNotRecognised: 'Code postal non reconnu',
radiusMi: 'rayon de {{count}} mi',
},
// ── Location Search ────────────────────────────────
@ -999,6 +1038,7 @@ const fr: Translations = {
showcaseJourneyRoutes: 'Itinéraires',
showcaseNearby: '{{value}} à proximité',
showcasePoliticalVoteShare: 'Répartition des voix',
showcaseGe2024: 'Législatives 2024',
showcaseLotsMore: '...et bien plus',
showcaseMinutes: '{{count}} min',
showcaseSendShortlist: 'Envoyer la sélection',
@ -1435,6 +1475,8 @@ const fr: Translations = {
noShareLinksYet: 'Aucun lien partagé pour linstant',
copyShareLink: 'Copier le lien partagé',
clicksLabel: 'clics',
fetchShareLinksError: 'Échec de la récupération des liens partagés',
updateNewsletterError: 'Échec de la mise à jour de la newsletter',
},
// ── Saved Page ─────────────────────────────────────
@ -1450,6 +1492,12 @@ const fr: Translations = {
'Êtes-vous sûr de vouloir supprimer cette recherche enregistrée ? Cette action est irréversible.',
isBeingUpdated: 'Mise à jour de <strong>{{name}}</strong>',
updating: 'Mise à jour...',
loadFailed: 'Échec du chargement des recherches',
saveFailed: 'Échec de lenregistrement de la recherche',
deleteFailed: 'Échec de la suppression de la recherche',
updateNotesFailed: 'Échec de la mise à jour des notes',
updateNameFailed: 'Échec de la mise à jour du nom',
updateFailed: 'Échec de la mise à jour de la recherche',
},
// ── Invites Page ───────────────────────────────────
@ -1470,6 +1518,7 @@ const fr: Translations = {
created: 'Créé',
redeemed: 'Utilisé',
pending: 'En attente',
createInviteError: 'Échec de la création de linvitation',
},
// ── Invite Page ────────────────────────────────────
@ -1496,6 +1545,105 @@ const fr: Translations = {
youAlreadyHaveLicense: 'Vous avez déjà une licence',
accountHasFullAccess: 'Votre compte dispose déjà dun accès complet.',
failedToValidate: 'Échec de la validation du lien dinvitation',
redeemFailed: 'Échec de lutilisation de linvitation',
},
// ── Errors ─────────────────────────────────────────
errors: {
appCrashTitle: 'Une erreur est survenue',
appCrashBody: 'Actualisez la page pour réessayer.',
},
// ── Listing ────────────────────────────────────────
listing: {
viewed: 'Consulté',
openListing: 'Ouvrir lannonce',
listings: 'annonces',
listing: 'Annonce',
showingOf: 'Affichage de {{visible}} sur {{count}}',
groupedNear: 'Regroupées près de cette position sur la carte',
},
// ── Overlays ───────────────────────────────────────
overlays: {
heading: 'Calques',
baseMap: 'Fond de carte',
colourOpacity: 'Opacité des couleurs',
dataOverlays: 'Calques de données',
about: 'À propos de {{name}}',
zoomWarning: 'Zoomez davantage pour voir le calque sélectionné.',
zoomWarning_other: 'Zoomez davantage pour voir les calques sélectionnés.',
noise: {
label: 'Bruit',
detail:
'Cartographie stratégique du bruit Defra, 4ᵉ cycle (2022), combinant les sources routières, ferroviaires et aéroportuaires. Les valeurs correspondent à lindicateur Lden standard de lEU (moyenne pondérée sur 24 heures jour-soir-nuit), modélisé sur une grille de 10 m à 4 m au-dessus du sol. Les zones plus claires indiquent un bruit modélisé plus élevé. Sous licence Open Government Licence v3.0.',
},
crimeHotspots: {
label: 'Points chauds de criminalité',
detail:
'Carte de chaleur générée côté client des délits de proximité publiés par police.uk au cours des mois les plus récents. Les coordonnées de police.uk sont des points anonymisés calés sur une grille, et non les lieux exacts des infractions ; la carte de chaleur doit donc être lue comme une approximation de la densité relative plutôt que comme une carte précise des incidents.',
},
treesOutsideWoodlands: {
label: 'Arbres et boisements',
detail:
'Polygones de canopée Forest Research Trees Outside Woodland (TOW) v1 — arbres isolés et groupes darbres — fusionnés avec les blocs boisés du National Forest Inventory (NFI) (≥0,5 ha) que TOW exclut délibérément. Ensemble, ils couvrent à la fois les arbres de rue et les véritables bois. Lopacité des polygones varie selon la surface de canopée.',
},
propertyBorders: {
label: 'Limites de propriété',
detail:
'INSPIRE Index Polygons du HM Land Registry — la position et létendue indicative des biens en pleine propriété (freehold) enregistrés en Angleterre et au pays de Galles, tracés en contours au niveau de la rue. Il sagit de « limites générales » fournies à titre indicatif uniquement, et non de la limite légale précise dun bien ; elles excluent les intérêts uniquement en location longue durée (leasehold) et les terrains non enregistrés (environ 85 à 90 % des terrains en pleine propriété sont couverts). Ces informations sont soumises au Crown copyright et aux droits sur les bases de données 2026 et sont reproduites avec lautorisation du HM Land Registry. Les polygones (y compris la géométrie associée, à savoir les coordonnées x, y) sont soumis au Crown copyright et aux droits sur les bases de données 2026 Ordnance Survey AC0000851063. Sous licence Open Government Licence v3.0.',
},
newDevelopments: {
label: 'Nouveaux développements',
detail:
'Un pipeline prospectif de nouveaux logements. Les repères bleus signalent les sites des registres statutaires des terrains en friche (Brownfield Land) du MHCLG — chacun assorti dune capacité nette estimée en logements et dun statut de permis de construire — ainsi que les sites de cession du Homes England Land Hub. Ils indiquent où de nouveaux logements sont prévus, souvent des années avant quils napparaissent dans les registres EPC ou de ventes. Les chiffres de logements sont des estimations de capacité, et non des engagements, et un site inscrit à un registre est une opportunité plutôt quune garantie de construction. Sous licence Open Government Licence v3.0.',
},
},
// ── Crime Types ────────────────────────────────────
crimeTypes: {
violenceAndSexualOffences: 'Violences et infractions sexuelles',
antiSocialBehaviour: 'Comportement antisocial',
criminalDamageAndArson: 'Dégradations et incendies volontaires',
publicOrder: 'Atteintes à lordre public',
shoplifting: 'Vol à létalage',
vehicleCrime: 'Délits liés aux véhicules',
burglary: 'Cambriolage',
otherTheft: 'Autres vols',
theftFromThePerson: 'Vol à la tire',
bicycleTheft: 'Vol de vélo',
drugs: 'Stupéfiants',
robbery: 'Vol avec violence',
possessionOfWeapons: 'Port darmes',
otherCrime: 'Autres délits',
},
// ── Journey ────────────────────────────────────────
journey: {
bus: 'Bus',
lineSuffix: 'ligne',
},
// ── POI Popup ──────────────────────────────────────
poiPopup: {
school: {
capacity: 'Capacité',
type: 'Type',
ages: 'Âges',
gender: 'Mixité',
pupilsLabel: 'Élèves',
pupils: 'élèves',
freeMeal: 'Repas gratuit',
ofsted: 'Ofsted',
sixthForm: 'Lycée (sixth form)',
religion: 'Religion',
admissions: 'Admissions',
trust: 'Trust',
address: 'Adresse',
localAuthority: 'LA',
head: 'Directeur',
website: 'Site web',
},
},
// ── Format / Time ──────────────────────────────────
@ -1538,6 +1686,9 @@ const fr: Translations = {
step6Title: 'Quy a-t-il à proximité ?',
step6Content:
'Activez les écoles, commerces, gares, parcs et restaurants sur la carte pour voir ce qui est à portée.',
step7Title: 'Ajoutez du contexte',
step7Content:
'Activez des calques comme les points chauds de criminalité, le bruit, la couverture arborée, les limites de propriété et les nouveaux programmes immobiliers, et changez de fond de carte selon vos besoins.',
},
// ── Server-derived values ──────────────────────────
@ -1595,23 +1746,70 @@ const fr: Translations = {
'Housing Conditions Score': 'Score des conditions de logement',
'Air Quality and Road Safety Score': 'Score qualité de lair et sécurité routière',
// ─ Feature names (Crime) ─
'Serious crime (avg/yr)': 'Infractions graves (densité)',
'Minor crime (avg/yr)': 'Infractions mineures (densité)',
'Violence and sexual offences (avg/yr)': 'Violences et infractions sexuelles (densité)',
'Burglary (avg/yr)': 'Cambriolages (densité)',
'Robbery (avg/yr)': 'Vols avec violence (densité)',
'Vehicle crime (avg/yr)': 'Infractions liées aux véhicules (densité)',
'Anti-social behaviour (avg/yr)': 'Comportements antisociaux (densité)',
'Criminal damage and arson (avg/yr)': 'Dégradations et incendies criminels (densité)',
'Other theft (avg/yr)': 'Autres vols (densité)',
'Theft from the person (avg/yr)': 'Vols à la personne (densité)',
'Shoplifting (avg/yr)': 'Vols à létalage (densité)',
'Bicycle theft (avg/yr)': 'Vols de vélos (densité)',
'Drugs (avg/yr)': 'Infractions liées aux stupéfiants (densité)',
'Possession of weapons (avg/yr)': 'Possession darmes (densité)',
'Public order (avg/yr)': 'Troubles à lordre public (densité)',
'Other crime (avg/yr)': 'Autres infractions (densité)',
// ─ Feature names (Crime) — taux normalisé par population, 7 ans & 2 ans ─
'Serious crime (/yr, 7y)': 'Infractions graves (par an, 7 ans)',
'Serious crime (/yr, 2y)': 'Infractions graves (par an, 2 ans)',
'Minor crime (/yr, 7y)': 'Infractions mineures (par an, 7 ans)',
'Minor crime (/yr, 2y)': 'Infractions mineures (par an, 2 ans)',
'Violence and sexual offences (/yr, 7y)':
'Violences et infractions sexuelles (par an, 7 ans)',
'Violence and sexual offences (/yr, 2y)':
'Violences et infractions sexuelles (par an, 2 ans)',
'Burglary (/yr, 7y)': 'Cambriolages (par an, 7 ans)',
'Burglary (/yr, 2y)': 'Cambriolages (par an, 2 ans)',
'Robbery (/yr, 7y)': 'Vols avec violence (par an, 7 ans)',
'Robbery (/yr, 2y)': 'Vols avec violence (par an, 2 ans)',
'Vehicle crime (/yr, 7y)':
'Infractions liées aux véhicules (par an, 7 ans)',
'Vehicle crime (/yr, 2y)':
'Infractions liées aux véhicules (par an, 2 ans)',
'Anti-social behaviour (/yr, 7y)':
'Comportements antisociaux (par an, 7 ans)',
'Anti-social behaviour (/yr, 2y)':
'Comportements antisociaux (par an, 2 ans)',
'Criminal damage and arson (/yr, 7y)':
'Dégradations et incendies criminels (par an, 7 ans)',
'Criminal damage and arson (/yr, 2y)':
'Dégradations et incendies criminels (par an, 2 ans)',
'Other theft (/yr, 7y)': 'Autres vols (par an, 7 ans)',
'Other theft (/yr, 2y)': 'Autres vols (par an, 2 ans)',
'Theft from the person (/yr, 7y)':
'Vols à la personne (par an, 7 ans)',
'Theft from the person (/yr, 2y)':
'Vols à la personne (par an, 2 ans)',
'Shoplifting (/yr, 7y)': 'Vols à létalage (par an, 7 ans)',
'Shoplifting (/yr, 2y)': 'Vols à létalage (par an, 2 ans)',
'Bicycle theft (/yr, 7y)': 'Vols de vélos (par an, 7 ans)',
'Bicycle theft (/yr, 2y)': 'Vols de vélos (par an, 2 ans)',
'Drugs (/yr, 7y)':
'Infractions liées aux stupéfiants (par an, 7 ans)',
'Drugs (/yr, 2y)':
'Infractions liées aux stupéfiants (par an, 2 ans)',
'Possession of weapons (/yr, 7y)':
'Possession darmes (par an, 7 ans)',
'Possession of weapons (/yr, 2y)':
'Possession darmes (par an, 2 ans)',
'Public order (/yr, 7y)':
'Troubles à lordre public (par an, 7 ans)',
'Public order (/yr, 2y)':
'Troubles à lordre public (par an, 2 ans)',
'Other crime (/yr, 7y)': 'Autres infractions (par an, 7 ans)',
'Other crime (/yr, 2y)': 'Autres infractions (par an, 2 ans)',
// Libellés de type dinfraction seuls (ventilation par type + liste des enregistrements).
// (« Burglary » est déjà défini parmi les infractions spécifiques ci-dessous.)
'Violence and sexual offences': 'Violences et infractions sexuelles',
Robbery: 'Vols avec violence',
'Vehicle crime': 'Infractions liées aux véhicules',
'Anti-social behaviour': 'Comportements antisociaux',
'Criminal damage and arson': 'Dégradations et incendies criminels',
'Other theft': 'Autres vols',
'Theft from the person': 'Vols à la personne',
Shoplifting: 'Vols à létalage',
'Bicycle theft': 'Vols de vélos',
Drugs: 'Infractions liées aux stupéfiants',
'Possession of weapons': 'Possession darmes',
'Public order': 'Troubles à lordre public',
'Other crime': 'Autres infractions',
// ─ Feature names (Neighbours) ─
'Median age': 'Âge médian',

View file

@ -57,6 +57,8 @@ const hi: Translations = {
closePane: 'पैन बंद करें',
yes: 'हाँ',
no: 'नहीं',
captions: 'कैप्शन',
sqm: 'वर्ग मीटर',
},
header: {
@ -608,6 +610,10 @@ const hi: Translations = {
backToLogin: 'लॉग इन पर वापस जाएं',
registerConsent:
'खाता बनाकर आप हमारी <terms>सेवा की शर्तों</terms> और <privacy>गोपनीयता नीति</privacy> से सहमत होते हैं.',
loginFailed: 'लॉग इन विफल रहा',
registrationFailed: 'पंजीकरण विफल रहा',
oauthFailed: 'OAuth लॉग इन विफल रहा',
passwordResetFailed: 'पासवर्ड रीसेट अनुरोध विफल रहा',
},
upgrade: {
@ -699,6 +705,11 @@ const hi: Translations = {
outstanding: 'उत्कृष्ट',
distance: 'दूरी',
crimeType: 'अपराध प्रकार',
qualificationLevel: 'योग्यता स्तर',
tenureType: 'आवास स्वामित्व',
crimeWindow: 'अवधि',
crimeWindow7y: '7 वर्ष',
crimeWindow2y: '2 वर्ष',
ethnicity: 'जातीय समूह',
poiType: 'रुचि-स्थल प्रकार',
party: 'पार्टी',
@ -785,6 +796,7 @@ const hi: Translations = {
refiningResults: 'परिणाम सुधारे जा रहे हैं...',
weeklyLimitReached:
'आप साप्ताहिक AI उपयोग सीमा तक पहुंच गए हैं. यह अगले सप्ताह अपने आप फिर से शुरू हो जाएगी.',
generateFailed: 'फ़िल्टर बनाने में विफल',
},
mapLegend: {
@ -802,6 +814,18 @@ const hi: Translations = {
ogSchools: 'स्कूल',
ogCrimeStats: 'अपराध आंकड़े',
ogTransport: 'परिवहन',
basemap: { standard: 'मैप', satellite: 'सैटेलाइट' },
error: {
heading: 'मैप में एक समस्या आ गई',
body: 'ऐसा तब हो सकता है जब आपके ब्राउज़र का ग्राफिक्स संदर्भ बाधित हो जाए.',
reload: 'मैप फिर से लोड करें',
},
actualListings: {
label: 'लिस्टिंग',
show: 'वास्तविक लिस्टिंग दिखाएं',
hide: 'वास्तविक लिस्टिंग छिपाएं',
},
poi: { zoomInToSeeDetails: 'विवरण देखने के लिए ज़ूम इन करें' },
},
propertyCard: {
@ -878,6 +902,20 @@ const hi: Translations = {
crimeDataEnds: 'इस क्षेत्र के लिए पुलिस डेटा {{year}} में समाप्त होता है',
residents: 'निवासी',
residentsTooltip: 'सामान्य निवासी (ONS जनगणना 2021)',
crimeWindow7y: 'पिछले 7 वर्ष',
crimeWindow2y: 'पिछले 2 वर्ष',
crimeWindowLabel: 'समयावधि',
crimeCardTitle: '{{name}} प्रति वर्ष',
crimeRecordsToggle: 'अलग-अलग अपराध दिखाएँ',
crimeRecordsHide: 'अलग-अलग अपराध छिपाएँ',
crimeRecordsCount: '{{count}} अपराध',
crimeRecordsLoading: 'अपराध लोड हो रहे हैं…',
crimeRecordsEmpty: 'कोई अलग-अलग अपराध दर्ज नहीं',
crimeRecordsError: 'अपराध लोड नहीं हो सके',
crimeRecordsLoadMore: 'और लोड करें',
crimeNoLocation: 'स्थान नहीं बताया गया',
crimeOutcomeUnknown: 'परिणाम दर्ज नहीं',
crimeYearPointTooltip: '{{year}}: {{rate}}/वर्ष',
},
streetView: {
@ -899,6 +937,7 @@ const hi: Translations = {
searchOn: 'इन पर {{radius}} खोजें:',
exact: 'सटीक',
outcodeNotRecognised: 'आउटकोड पहचाना नहीं गया',
radiusMi: '{{count}} मील की त्रिज्या',
},
locationSearch: {
@ -952,6 +991,7 @@ const hi: Translations = {
showcaseJourneyRoutes: 'यात्रा मार्ग',
showcaseNearby: '{{value}} पास में',
showcasePoliticalVoteShare: 'राजनीतिक वोट हिस्सेदारी',
showcaseGe2024: '2024 आम चुनाव',
showcaseLotsMore: '...और भी बहुत कुछ',
showcaseMinutes: '{{count}} मिनट',
showcaseSendShortlist: 'शॉर्टलिस्ट भेजें',
@ -1359,6 +1399,8 @@ const hi: Translations = {
noShareLinksYet: 'अभी कोई साझा लिंक नहीं',
copyShareLink: 'साझा लिंक कॉपी करें',
clicksLabel: 'क्लिक',
fetchShareLinksError: 'साझा लिंक प्राप्त करने में विफल',
updateNewsletterError: 'न्यूज़लेटर अपडेट करने में विफल',
},
savedPage: {
@ -1373,6 +1415,12 @@ const hi: Translations = {
'क्या आप वाकई यह सहेजी गई खोज हटाना चाहते हैं? इसे वापस नहीं किया जा सकता.',
isBeingUpdated: '<strong>{{name}}</strong> अपडेट हो रहा है',
updating: 'अपडेट हो रहा है...',
loadFailed: 'खोजें लोड करने में विफल',
saveFailed: 'खोज सहेजने में विफल',
deleteFailed: 'खोज हटाने में विफल',
updateNotesFailed: 'नोट्स अपडेट करने में विफल',
updateNameFailed: 'नाम अपडेट करने में विफल',
updateFailed: 'खोज अपडेट करने में विफल',
},
invitesPage: {
@ -1391,6 +1439,7 @@ const hi: Translations = {
created: 'बनाया गया',
redeemed: 'भुनाया गया',
pending: 'लंबित',
createInviteError: 'आमंत्रण बनाने में विफल',
},
invitePage: {
@ -1416,6 +1465,99 @@ const hi: Translations = {
youAlreadyHaveLicense: 'आपके पास पहले से लाइसेंस है',
accountHasFullAccess: 'आपके खाते में पहले से पूरी पहुँच है.',
failedToValidate: 'आमंत्रण लिंक सत्यापित नहीं हो सका',
redeemFailed: 'आमंत्रण भुनाने में विफल',
},
errors: {
appCrashTitle: 'कुछ गलत हो गया',
appCrashBody: 'फिर से प्रयास करने के लिए पेज रीफ्रेश करें.',
},
listing: {
viewed: 'देखा गया',
openListing: 'लिस्टिंग खोलें',
listings: 'लिस्टिंग',
listing: 'लिस्टिंग',
showingOf: '{{count}} में से {{visible}} दिखाई जा रही हैं',
groupedNear: 'इस मैप स्थिति के पास समूहीकृत',
},
overlays: {
heading: 'ओवरले',
baseMap: 'बेस मैप',
colourOpacity: 'रंग अपारदर्शिता',
dataOverlays: 'डेटा ओवरले',
about: '{{name}} के बारे में',
zoomWarning: 'चुने गए ओवरले को देखने के लिए और ज़ूम इन करें.',
zoomWarning_other: 'चुने गए ओवरले देखने के लिए और ज़ूम इन करें.',
noise: {
label: 'शोर',
detail:
'Defra Strategic Noise Mapping Round 4 (2022), जिसमें सड़क, रेल और हवाई अड्डे के स्रोत शामिल हैं. मान EU-मानक Lden मीट्रिक (दिन-शाम-रात 24-घंटे भारित औसत) हैं, जो ज़मीन से 4 मीटर ऊपर 10 मीटर ग्रिड पर मॉडल किए गए हैं. अधिक चमकीले क्षेत्र अधिक मॉडल किए गए शोर को दर्शाते हैं. Open Government Licence v3.0 के तहत लाइसेंस प्राप्त.',
},
crimeHotspots: {
label: 'अपराध हॉटस्पॉट',
detail:
'police.uk द्वारा सबसे हाल के महीनों में प्रकाशित सड़क-स्तरीय अपराधों का क्लाइंट-साइड हीटमैप. Police.uk के निर्देशांक गुमनाम स्नैप-टू-ग्रिड बिंदु हैं, अपराध के सटीक स्थान नहीं, इसलिए हीटमैप को घटनाओं के सटीक मानचित्र के बजाय सापेक्ष घनत्व के अनुमान के रूप में पढ़ा जाना चाहिए.',
},
treesOutsideWoodlands: {
label: 'पेड़ और वुडलैंड',
detail:
'Forest Research Trees Outside Woodland (TOW) v1 कैनोपी पॉलीगॉन — अकेले पेड़ और पेड़ों के समूह — National Forest Inventory (NFI) वुडलैंड ब्लॉक्स (≥0.5 हेक्टेयर) के साथ जोड़े गए हैं जिन्हें TOW जानबूझकर बाहर रखता है. साथ में ये सड़क के पेड़ और असली जंगल दोनों को कवर करते हैं. पॉलीगॉन की अपारदर्शिता कैनोपी क्षेत्र के अनुसार बढ़ती है.',
},
propertyBorders: {
label: 'संपत्ति सीमाएं',
detail:
'HM Land Registry INSPIRE Index Polygons — इंग्लैंड और वेल्स में फ्रीहोल्ड पंजीकृत संपत्ति की स्थिति और संकेतात्मक विस्तार, सड़क स्तर पर रूपरेखा के रूप में बनाई गई. ये केवल मार्गदर्शन के लिए "सामान्य सीमाएं" हैं, किसी संपत्ति की सटीक कानूनी सीमा नहीं, और इनमें केवल-लीजहोल्ड हित और अपंजीकृत भूमि शामिल नहीं हैं (लगभग 8590% फ्रीहोल्ड भूमि कवर है). यह जानकारी Crown copyright और डेटाबेस अधिकार 2026 के अधीन है और HM Land Registry की अनुमति से पुनरुत्पादित की गई है. पॉलीगॉन (संबंधित ज्यामिति सहित, अर्थात् x, y निर्देशांक) Crown copyright और डेटाबेस अधिकार 2026 Ordnance Survey AC0000851063 के अधीन हैं. Open Government Licence v3.0 के तहत लाइसेंस प्राप्त.',
},
newDevelopments: {
label: 'नए विकास',
detail:
'नए आवास की एक भविष्योन्मुखी पाइपलाइन. नीले मार्कर वैधानिक MHCLG Brownfield Land registers पर साइटों को चिह्नित करते हैं — प्रत्येक में अनुमानित शुद्ध-आवास क्षमता और योजना-अनुमति स्थिति होती है — साथ ही Homes England Land Hub निपटान साइटें. ये दर्शाते हैं कि नए घर कहां योजनाबद्ध हैं, अक्सर EPC या बिक्री रिकॉर्ड में दिखाई देने से वर्षों पहले. आवास आंकड़े क्षमता अनुमान हैं, प्रतिबद्धताएं नहीं, और किसी रजिस्टर पर साइट निर्माण की गारंटी के बजाय एक अवसर है. Open Government Licence v3.0 के तहत लाइसेंस प्राप्त.',
},
},
crimeTypes: {
violenceAndSexualOffences: 'हिंसा और यौन अपराध',
antiSocialBehaviour: 'असामाजिक व्यवहार',
criminalDamageAndArson: 'आपराधिक क्षति और आगजनी',
publicOrder: 'सार्वजनिक व्यवस्था',
shoplifting: 'दुकान से चोरी',
vehicleCrime: 'वाहन अपराध',
burglary: 'सेंधमारी',
otherTheft: 'अन्य चोरी',
theftFromThePerson: 'व्यक्ति से चोरी',
bicycleTheft: 'साइकिल चोरी',
drugs: 'नशीले पदार्थ',
robbery: 'डकैती',
possessionOfWeapons: 'हथियार रखना',
otherCrime: 'अन्य अपराध',
},
journey: {
bus: 'बस',
lineSuffix: 'लाइन',
},
poiPopup: {
school: {
capacity: 'क्षमता',
type: 'प्रकार',
ages: 'आयु',
gender: 'लिंग',
pupilsLabel: 'विद्यार्थी',
pupils: 'विद्यार्थी',
freeMeal: 'मुफ्त भोजन',
ofsted: 'Ofsted',
sixthForm: 'सिक्स्थ फॉर्म',
religion: 'धर्म',
admissions: 'प्रवेश',
trust: 'ट्रस्ट',
address: 'पता',
localAuthority: 'LA',
head: 'प्रधानाध्यापक',
website: 'वेबसाइट',
},
},
format: {
@ -1455,6 +1597,9 @@ const hi: Translations = {
step6Title: 'पास में क्या है?',
step6Content:
'मानचित्र पर स्कूल, दुकानें, स्टेशन, पार्क और रेस्तरां चालू करें और देखें क्या पहुंच में है.',
step7Title: 'और संदर्भ जोड़ें',
step7Content:
'मानचित्र पर अपराध हॉटस्पॉट, शोर, वृक्षावरण, संपत्ति सीमाएं और नई आवासीय परियोजनाओं जैसी ओवरले परतें चालू करें और जरूरत के अनुसार आधार मानचित्र बदलें.',
},
server: {
@ -1501,22 +1646,59 @@ const hi: Translations = {
'Health Deprivation and Disability Score': 'स्वास्थ्य वंचना और विकलांगता स्कोर',
'Housing Conditions Score': 'आवास स्थिति स्कोर',
'Air Quality and Road Safety Score': 'हवा की गुणवत्ता और सड़क सुरक्षा स्कोर',
'Serious crime (avg/yr)': 'गंभीर अपराध (घनत्व)',
'Minor crime (avg/yr)': 'मामूली अपराध (घनत्व)',
'Violence and sexual offences (avg/yr)': 'हिंसा और यौन अपराध (घनत्व)',
'Burglary (avg/yr)': 'सेंधमारी (घनत्व)',
'Robbery (avg/yr)': 'लूट (घनत्व)',
'Vehicle crime (avg/yr)': 'वाहन अपराध (घनत्व)',
'Anti-social behaviour (avg/yr)': 'असामाजिक व्यवहार (घनत्व)',
'Criminal damage and arson (avg/yr)': 'आपराधिक क्षति और आगजनी (घनत्व)',
'Other theft (avg/yr)': 'अन्य चोरी (घनत्व)',
'Theft from the person (avg/yr)': 'व्यक्ति से चोरी (घनत्व)',
'Shoplifting (avg/yr)': 'दुकान से चोरी (घनत्व)',
'Bicycle theft (avg/yr)': 'साइकिल चोरी (घनत्व)',
'Drugs (avg/yr)': 'ड्रग्स (घनत्व)',
'Possession of weapons (avg/yr)': 'हथियार रखने के अपराध (घनत्व)',
'Public order (avg/yr)': 'सार्वजनिक व्यवस्था अपराध (घनत्व)',
'Other crime (avg/yr)': 'अन्य अपराध (घनत्व)',
'Serious crime (/yr, 7y)': 'गंभीर अपराध (प्रति वर्ष, 7 वर्ष)',
'Serious crime (/yr, 2y)': 'गंभीर अपराध (प्रति वर्ष, 2 वर्ष)',
'Minor crime (/yr, 7y)': 'मामूली अपराध (प्रति वर्ष, 7 वर्ष)',
'Minor crime (/yr, 2y)': 'मामूली अपराध (प्रति वर्ष, 2 वर्ष)',
'Violence and sexual offences (/yr, 7y)':
'हिंसा और यौन अपराध (प्रति वर्ष, 7 वर्ष)',
'Violence and sexual offences (/yr, 2y)':
'हिंसा और यौन अपराध (प्रति वर्ष, 2 वर्ष)',
'Burglary (/yr, 7y)': 'सेंधमारी (प्रति वर्ष, 7 वर्ष)',
'Burglary (/yr, 2y)': 'सेंधमारी (प्रति वर्ष, 2 वर्ष)',
'Robbery (/yr, 7y)': 'लूट (प्रति वर्ष, 7 वर्ष)',
'Robbery (/yr, 2y)': 'लूट (प्रति वर्ष, 2 वर्ष)',
'Vehicle crime (/yr, 7y)': 'वाहन अपराध (प्रति वर्ष, 7 वर्ष)',
'Vehicle crime (/yr, 2y)': 'वाहन अपराध (प्रति वर्ष, 2 वर्ष)',
'Anti-social behaviour (/yr, 7y)': 'असामाजिक व्यवहार (प्रति वर्ष, 7 वर्ष)',
'Anti-social behaviour (/yr, 2y)': 'असामाजिक व्यवहार (प्रति वर्ष, 2 वर्ष)',
'Criminal damage and arson (/yr, 7y)':
'आपराधिक क्षति और आगजनी (प्रति वर्ष, 7 वर्ष)',
'Criminal damage and arson (/yr, 2y)':
'आपराधिक क्षति और आगजनी (प्रति वर्ष, 2 वर्ष)',
'Other theft (/yr, 7y)': 'अन्य चोरी (प्रति वर्ष, 7 वर्ष)',
'Other theft (/yr, 2y)': 'अन्य चोरी (प्रति वर्ष, 2 वर्ष)',
'Theft from the person (/yr, 7y)': 'व्यक्ति से चोरी (प्रति वर्ष, 7 वर्ष)',
'Theft from the person (/yr, 2y)': 'व्यक्ति से चोरी (प्रति वर्ष, 2 वर्ष)',
'Shoplifting (/yr, 7y)': 'दुकान से चोरी (प्रति वर्ष, 7 वर्ष)',
'Shoplifting (/yr, 2y)': 'दुकान से चोरी (प्रति वर्ष, 2 वर्ष)',
'Bicycle theft (/yr, 7y)': 'साइकिल चोरी (प्रति वर्ष, 7 वर्ष)',
'Bicycle theft (/yr, 2y)': 'साइकिल चोरी (प्रति वर्ष, 2 वर्ष)',
'Drugs (/yr, 7y)': 'ड्रग्स (प्रति वर्ष, 7 वर्ष)',
'Drugs (/yr, 2y)': 'ड्रग्स (प्रति वर्ष, 2 वर्ष)',
'Possession of weapons (/yr, 7y)':
'हथियार रखने के अपराध (प्रति वर्ष, 7 वर्ष)',
'Possession of weapons (/yr, 2y)':
'हथियार रखने के अपराध (प्रति वर्ष, 2 वर्ष)',
'Public order (/yr, 7y)': 'सार्वजनिक व्यवस्था अपराध (प्रति वर्ष, 7 वर्ष)',
'Public order (/yr, 2y)': 'सार्वजनिक व्यवस्था अपराध (प्रति वर्ष, 2 वर्ष)',
'Other crime (/yr, 7y)': 'अन्य अपराध (प्रति वर्ष, 7 वर्ष)',
'Other crime (/yr, 2y)': 'अन्य अपराध (प्रति वर्ष, 2 वर्ष)',
// केवल अपराध-प्रकार के लेबल (प्रकार-वार विवरण + रिकॉर्ड सूची)।
// ("Burglary" पहले से ही नीचे विशिष्ट अपराधों में परिभाषित है।)
'Violence and sexual offences': 'हिंसा और यौन अपराध',
Robbery: 'लूट',
'Vehicle crime': 'वाहन अपराध',
'Anti-social behaviour': 'असामाजिक व्यवहार',
'Criminal damage and arson': 'आपराधिक क्षति और आगजनी',
'Other theft': 'अन्य चोरी',
'Theft from the person': 'व्यक्ति से चोरी',
Shoplifting: 'दुकान से चोरी',
'Bicycle theft': 'साइकिल चोरी',
Drugs: 'ड्रग्स',
'Possession of weapons': 'हथियार रखने के अपराध',
'Public order': 'सार्वजनिक व्यवस्था अपराध',
'Other crime': 'अन्य अपराध',
'Median age': 'मध्य आयु',
'% No qualifications': '% कोई योग्यता नहीं',
'% Some GCSEs': '% कुछ GCSE',

View file

@ -58,6 +58,8 @@ const hu: Translations = {
closePane: 'Panel bezárása',
yes: 'Igen',
no: 'Nem',
captions: 'Feliratok',
sqm: 'm²',
},
// ── Header / Nav ───────────────────────────────────
@ -626,6 +628,10 @@ const hu: Translations = {
backToLogin: 'Vissza a bejelentkezéshez',
registerConsent:
'A fiók létrehozásával elfogadod a <terms>Felhasználási feltételeket</terms> és az <privacy>Adatvédelmi tájékoztatót</privacy>.',
loginFailed: 'A bejelentkezés sikertelen',
registrationFailed: 'A regisztráció sikertelen',
oauthFailed: 'Az OAuth-bejelentkezés sikertelen',
passwordResetFailed: 'A jelszó-visszaállítási kérés sikertelen',
},
// ── Upgrade Modal ──────────────────────────────────
@ -721,6 +727,11 @@ const hu: Translations = {
outstanding: 'Kiváló',
distance: 'Távolság',
crimeType: 'Bűncselekménytípus',
qualificationLevel: 'Képzettségi szint',
tenureType: 'Lakhatási forma',
crimeWindow: 'Időszak',
crimeWindow7y: '7 év',
crimeWindow2y: '2 év',
ethnicity: 'Etnikai csoport',
poiType: 'POI-típus',
party: 'Párt',
@ -810,6 +821,7 @@ const hu: Translations = {
generatingFilters: 'Szűrők létrehozása...',
refiningResults: 'Eredmények finomhangolása...',
weeklyLimitReached: 'Elérted a heti AI-használati limitet. Automatikusan visszaáll jövő héten.',
generateFailed: 'A szűrők létrehozása sikertelen',
},
// ── Map Legend ─────────────────────────────────────
@ -829,6 +841,18 @@ const hu: Translations = {
ogSchools: 'Iskolák',
ogCrimeStats: 'Bűnözési adatok',
ogTransport: 'Közlekedés',
basemap: { standard: 'Térkép', satellite: 'Műhold' },
error: {
heading: 'A térkép hibába ütközött',
body: 'Ez akkor fordulhat elő, ha a böngésződ grafikus környezete megszakad.',
reload: 'Térkép újratöltése',
},
actualListings: {
label: 'Hirdetések',
show: 'Valódi hirdetések megjelenítése',
hide: 'Valódi hirdetések elrejtése',
},
poi: { zoomInToSeeDetails: 'Nagyíts rá a részletekért' },
},
// ── Properties Pane ────────────────────────────────
@ -907,6 +931,20 @@ const hu: Translations = {
crimeDataEnds: 'A körzet rendőrségi adatai {{year}}-ig érhetők el',
residents: 'Lakosok',
residentsTooltip: 'Állandó lakosok (ONS 2021-es népszámlálás)',
crimeWindow7y: 'Az elmúlt 7 év',
crimeWindow2y: 'Az elmúlt 2 év',
crimeWindowLabel: 'Időszak',
crimeCardTitle: '{{name}} évente',
crimeRecordsToggle: 'Egyedi bűncselekmények megjelenítése',
crimeRecordsHide: 'Egyedi bűncselekmények elrejtése',
crimeRecordsCount: '{{count}} bűncselekmény',
crimeRecordsLoading: 'Bűncselekmények betöltése…',
crimeRecordsEmpty: 'Nincs rögzített egyedi bűncselekmény',
crimeRecordsError: 'A bűncselekményeket nem sikerült betölteni',
crimeRecordsLoadMore: 'Több betöltése',
crimeNoLocation: 'A helyszín nincs megadva',
crimeOutcomeUnknown: 'Az eredmény nincs rögzítve',
crimeYearPointTooltip: '{{year}}: {{rate}}/év',
},
// ── Street View ────────────────────────────────────
@ -931,6 +969,7 @@ const hu: Translations = {
searchOn: 'Keresés {{radius}} sugárban ezen:',
exact: 'pontos',
outcodeNotRecognised: 'Ismeretlen irányítószám-körzet',
radiusMi: '{{count}} mérföldes sugár',
},
// ── Location Search ────────────────────────────────
@ -1036,6 +1075,7 @@ const hu: Translations = {
showcaseStep4ColCommute: 'Ingázás',
showcaseStep4ColPrice: 'Medián eladási ár',
showcaseStep4Conclusion: 'Innen már el tudod indítani a keresést.',
showcaseGe2024: '2024-es választás',
statProperties: 'korábbi eladás',
statFilters: 'kombinálható szűrő',
statEvery: 'Minden',
@ -1414,6 +1454,8 @@ const hu: Translations = {
noShareLinksYet: 'Még nincsenek megosztott hivatkozások',
copyShareLink: 'Megosztott hivatkozás másolása',
clicksLabel: 'kattintás',
fetchShareLinksError: 'A megosztott hivatkozások lekérése sikertelen',
updateNewsletterError: 'A hírlevél frissítése sikertelen',
},
// ── Saved Page ─────────────────────────────────────
@ -1429,6 +1471,12 @@ const hu: Translations = {
'Biztosan törölni szeretnéd ezt a mentett keresést? Ez nem vonható vissza.',
isBeingUpdated: '<strong>{{name}}</strong> frissítése folyamatban',
updating: 'Frissítés...',
loadFailed: 'A keresések betöltése sikertelen',
saveFailed: 'A keresés mentése sikertelen',
deleteFailed: 'A keresés törlése sikertelen',
updateNotesFailed: 'A jegyzetek frissítése sikertelen',
updateNameFailed: 'A név frissítése sikertelen',
updateFailed: 'A keresés frissítése sikertelen',
},
// ── Invites Page ───────────────────────────────────
@ -1448,6 +1496,7 @@ const hu: Translations = {
created: 'Létrehozva',
redeemed: 'Beváltva',
pending: 'Függőben',
createInviteError: 'A meghívó létrehozása sikertelen',
},
// ── Invite Page ────────────────────────────────────
@ -1476,6 +1525,105 @@ const hu: Translations = {
youAlreadyHaveLicense: 'Már van licenced',
accountHasFullAccess: 'A fiókod már teljes hozzáféréssel rendelkezik.',
failedToValidate: 'Nem sikerült a meghívó hivatkozás érvényesítése',
redeemFailed: 'A meghívó beváltása sikertelen',
},
// ── Errors ─────────────────────────────────────────
errors: {
appCrashTitle: 'Valami hiba történt',
appCrashBody: 'Frissítsd az oldalt az újrapróbálkozáshoz.',
},
// ── Listing ────────────────────────────────────────
listing: {
viewed: 'Megtekintve',
openListing: 'Hirdetés megnyitása',
listings: 'hirdetés',
listing: 'Hirdetés',
showingOf: '{{visible}} / {{count}} megjelenítve',
groupedNear: 'Ennél a térképponton csoportosítva',
},
// ── Overlays ───────────────────────────────────────
overlays: {
heading: 'Rétegek',
baseMap: 'Alaptérkép',
colourOpacity: 'Színek átlátszósága',
dataOverlays: 'Adatrétegek',
about: 'Névjegy: {{name}}',
zoomWarning: 'Nagyíts tovább a kiválasztott réteg megtekintéséhez.',
zoomWarning_other: 'Nagyíts tovább a kiválasztott rétegek megtekintéséhez.',
noise: {
label: 'Zaj',
detail:
'Defra Strategic Noise Mapping Round 4 (2022), amely az úti, vasúti és repülőtéri forrásokat egyesíti. Az értékek az EU-szabványos Lden mutató szerintiek (nappal-este-éjjel 24 órás súlyozott átlag), 10 m-es rácson, a talaj felett 4 m-en modellezve. A világosabb területek magasabb modellezett zajt jeleznek. Licenc: Open Government Licence v3.0.',
},
crimeHotspots: {
label: 'Bűnözési gócpontok',
detail:
'A police.uk által közzétett, utcaszintű bűncselekmények kliensoldali hőtérképe a legutóbbi hónapokból. A police.uk koordinátái anonimizált, rácshoz illesztett pontok, nem pontos bűncselekményi helyszínek, ezért a hőtérképet a relatív sűrűség közelítéseként érdemes olvasni, nem az esetek pontos térképeként.',
},
treesOutsideWoodlands: {
label: 'Fák és erdő',
detail:
'Forest Research Trees Outside Woodland (TOW) v1 lombkorona-poligonok — magányos fák és facsoportok — egyesítve a National Forest Inventory (NFI) erdőblokkjaival (≥0,5 ha), amelyeket a TOW szándékosan kihagy. Együtt lefedik mind az utcai fákat, mind a valódi erdőket. A poligonok átlátszatlansága a lombkorona-területtel arányosan változik.',
},
propertyBorders: {
label: 'Telekhatárok',
detail:
'HM Land Registry INSPIRE Index Polygons — a szabad tulajdonú, bejegyzett ingatlanok helyzete és tájékoztató kiterjedése Angliában és Walesben, utcaszinten körvonalként ábrázolva. Ezek csak tájékoztató „általános határok”, nem az ingatlan pontos jogi határai, és nem tartalmazzák a kizárólag bérleti jogú érdekeltségeket és a be nem jegyzett földeket (a szabad tulajdonú föld nagyjából 8590%-a van lefedve). Ezek az információk Crown copyright és adatbázis-jogok 2026 hatálya alá tartoznak, és a HM Land Registry engedélyével kerülnek közlésre. A poligonok (beleértve a hozzájuk tartozó geometriát, azaz az x, y koordinátákat) Crown copyright és adatbázis-jogok 2026 Ordnance Survey AC0000851063 hatálya alá tartoznak. Licenc: Open Government Licence v3.0.',
},
newDevelopments: {
label: 'Új fejlesztések',
detail:
'Előretekintő lista az új lakásépítésekről. A kék jelölők a törvényi MHCLG Brownfield Land nyilvántartásokban szereplő helyszíneket mutatják — mindegyik becsült nettó lakáskapacitással és építési engedélyezési státusszal —, a Homes England Land Hub értékesítési helyszíneivel együtt. Ezek megmutatják, hol terveznek új otthonokat, gyakran évekkel azelőtt, hogy megjelennének az EPC- vagy eladási nyilvántartásokban. A lakásszámok kapacitásbecslések, nem kötelezettségvállalások, és egy nyilvántartásban szereplő helyszín lehetőség, nem az építkezés garanciája. Licenc: Open Government Licence v3.0.',
},
},
// ── Crime Types ────────────────────────────────────
crimeTypes: {
violenceAndSexualOffences: 'Erőszakos és szexuális bűncselekmények',
antiSocialBehaviour: 'Közösségellenes viselkedés',
criminalDamageAndArson: 'Rongálás és gyújtogatás',
publicOrder: 'Közrend elleni cselekmény',
shoplifting: 'Bolti lopás',
vehicleCrime: 'Járművel kapcsolatos bűncselekmény',
burglary: 'Betörés',
otherTheft: 'Egyéb lopás',
theftFromThePerson: 'Személytől való lopás',
bicycleTheft: 'Kerékpárlopás',
drugs: 'Kábítószer',
robbery: 'Rablás',
possessionOfWeapons: 'Fegyvertartás',
otherCrime: 'Egyéb bűncselekmény',
},
// ── Journey ────────────────────────────────────────
journey: {
bus: 'Busz',
lineSuffix: 'vonal',
},
// ── POI Popup ──────────────────────────────────────
poiPopup: {
school: {
capacity: 'Kapacitás',
type: 'Típus',
ages: 'Életkor',
gender: 'Nem',
pupilsLabel: 'Tanulók',
pupils: 'tanuló',
freeMeal: 'Ingyenes étkezés',
ofsted: 'Ofsted',
sixthForm: 'Felső középfok',
religion: 'Vallás',
admissions: 'Felvétel',
trust: 'Fenntartó',
address: 'Cím',
localAuthority: 'Önk.',
head: 'Igazgató',
website: 'Weboldal',
},
},
// ── Format / Time ──────────────────────────────────
@ -1517,6 +1665,9 @@ const hu: Translations = {
step6Title: 'Mi van a közelben?',
step6Content:
'Kapcsolja be az iskolákat, üzleteket, állomásokat, parkokat és éttermeket a térképen, hogy lássa, mi érhető el.',
step7Title: 'Adjon hozzá több réteget',
step7Content:
'Kapcsoljon be olyan rétegeket a térképen, mint a bűnözési gócpontok, zaj, faállomány, telekhatárok és új építésű területek, és váltson alaptérképet igény szerint.',
},
// ── Server-derived values ──────────────────────────
@ -1574,23 +1725,60 @@ const hu: Translations = {
'Housing Conditions Score': 'Lakáskörülmények pontszám',
'Air Quality and Road Safety Score': 'Levegőminőség és közlekedésbiztonság pontszám',
// ─ Feature names (Crime) ─
'Serious crime (avg/yr)': 'Súlyos bűncselekmény (sűrűség)',
'Minor crime (avg/yr)': 'Kisebb bűncselekmény (sűrűség)',
'Violence and sexual offences (avg/yr)': 'Erőszak és szexuális bűncselekmények (sűrűség)',
'Burglary (avg/yr)': 'Betörés (sűrűség)',
'Robbery (avg/yr)': 'Rablás (sűrűség)',
'Vehicle crime (avg/yr)': 'Járművel kapcsolatos bűncselekmények (sűrűség)',
'Anti-social behaviour (avg/yr)': 'Közösségellenes magatartás (sűrűség)',
'Criminal damage and arson (avg/yr)': 'Rongálás és gyújtogatás (sűrűség)',
'Other theft (avg/yr)': 'Egyéb lopás (sűrűség)',
'Theft from the person (avg/yr)': 'Személytől történő lopás (sűrűség)',
'Shoplifting (avg/yr)': 'Bolti lopás (sűrűség)',
'Bicycle theft (avg/yr)': 'Kerékpárlopás (sűrűség)',
'Drugs (avg/yr)': 'Kábítószer (sűrűség)',
'Possession of weapons (avg/yr)': 'Fegyverbirtoklás (sűrűség)',
'Public order (avg/yr)': 'Közrend (sűrűség)',
'Other crime (avg/yr)': 'Egyéb bűncselekmény (sűrűség)',
// ─ Feature names (Crime) — népességre normált ráta, 7 év és 2 év ─
'Serious crime (/yr, 7y)': 'Súlyos bűncselekmény (évente, 7 év)',
'Serious crime (/yr, 2y)': 'Súlyos bűncselekmény (évente, 2 év)',
'Minor crime (/yr, 7y)': 'Kisebb bűncselekmény (évente, 7 év)',
'Minor crime (/yr, 2y)': 'Kisebb bűncselekmény (évente, 2 év)',
'Violence and sexual offences (/yr, 7y)':
'Erőszak és szexuális bűncselekmények (évente, 7 év)',
'Violence and sexual offences (/yr, 2y)':
'Erőszak és szexuális bűncselekmények (évente, 2 év)',
'Burglary (/yr, 7y)': 'Betörés (évente, 7 év)',
'Burglary (/yr, 2y)': 'Betörés (évente, 2 év)',
'Robbery (/yr, 7y)': 'Rablás (évente, 7 év)',
'Robbery (/yr, 2y)': 'Rablás (évente, 2 év)',
'Vehicle crime (/yr, 7y)':
'Járművel kapcsolatos bűncselekmények (évente, 7 év)',
'Vehicle crime (/yr, 2y)':
'Járművel kapcsolatos bűncselekmények (évente, 2 év)',
'Anti-social behaviour (/yr, 7y)': 'Közösségellenes magatartás (évente, 7 év)',
'Anti-social behaviour (/yr, 2y)': 'Közösségellenes magatartás (évente, 2 év)',
'Criminal damage and arson (/yr, 7y)':
'Rongálás és gyújtogatás (évente, 7 év)',
'Criminal damage and arson (/yr, 2y)':
'Rongálás és gyújtogatás (évente, 2 év)',
'Other theft (/yr, 7y)': 'Egyéb lopás (évente, 7 év)',
'Other theft (/yr, 2y)': 'Egyéb lopás (évente, 2 év)',
'Theft from the person (/yr, 7y)': 'Személytől történő lopás (évente, 7 év)',
'Theft from the person (/yr, 2y)': 'Személytől történő lopás (évente, 2 év)',
'Shoplifting (/yr, 7y)': 'Bolti lopás (évente, 7 év)',
'Shoplifting (/yr, 2y)': 'Bolti lopás (évente, 2 év)',
'Bicycle theft (/yr, 7y)': 'Kerékpárlopás (évente, 7 év)',
'Bicycle theft (/yr, 2y)': 'Kerékpárlopás (évente, 2 év)',
'Drugs (/yr, 7y)': 'Kábítószer (évente, 7 év)',
'Drugs (/yr, 2y)': 'Kábítószer (évente, 2 év)',
'Possession of weapons (/yr, 7y)': 'Fegyverbirtoklás (évente, 7 év)',
'Possession of weapons (/yr, 2y)': 'Fegyverbirtoklás (évente, 2 év)',
'Public order (/yr, 7y)': 'Közrend (évente, 7 év)',
'Public order (/yr, 2y)': 'Közrend (évente, 2 év)',
'Other crime (/yr, 7y)': 'Egyéb bűncselekmény (évente, 7 év)',
'Other crime (/yr, 2y)': 'Egyéb bűncselekmény (évente, 2 év)',
// Csak a bűncselekménytípus megnevezések (típusonkénti bontás + rekordlista).
// (A „Burglary” már szerepel lent a konkrét bűncselekmények között.)
'Violence and sexual offences': 'Erőszak és szexuális bűncselekmények',
Robbery: 'Rablás',
'Vehicle crime': 'Járművel kapcsolatos bűncselekmények',
'Anti-social behaviour': 'Közösségellenes magatartás',
'Criminal damage and arson': 'Rongálás és gyújtogatás',
'Other theft': 'Egyéb lopás',
'Theft from the person': 'Személytől történő lopás',
Shoplifting: 'Bolti lopás',
'Bicycle theft': 'Kerékpárlopás',
Drugs: 'Kábítószer',
'Possession of weapons': 'Fegyverbirtoklás',
'Public order': 'Közrend',
'Other crime': 'Egyéb bűncselekmény',
// ─ Feature names (Neighbours) ─
'Median age': 'Medián életkor',

View file

@ -57,6 +57,8 @@ const zh: Translations = {
closePane: '关闭面板',
yes: '是',
no: '否',
captions: '字幕',
sqm: '平方米',
},
// ── Header / Nav ───────────────────────────────────
@ -574,6 +576,10 @@ const zh: Translations = {
backToLogin: '返回登录',
registerConsent:
'创建账户即表示您同意我们的<terms>服务条款</terms>和<privacy>隐私政策</privacy>。',
loginFailed: '登录失败',
registrationFailed: '注册失败',
oauthFailed: 'OAuth 登录失败',
passwordResetFailed: '密码重置请求失败',
},
// ── Upgrade Modal ──────────────────────────────────
@ -667,6 +673,11 @@ const zh: Translations = {
outstanding: '优秀',
distance: '距离',
crimeType: '犯罪类别',
qualificationLevel: '学历水平',
tenureType: '住房产权类型',
crimeWindow: '统计周期',
crimeWindow7y: '7 年',
crimeWindow2y: '2 年',
ethnicity: '族裔',
poiType: '地点类型',
party: '政党',
@ -755,6 +766,7 @@ const zh: Translations = {
generatingFilters: '正在生成筛选条件...',
refiningResults: '正在优化结果...',
weeklyLimitReached: '您已达到每周 AI 使用上限。下周将自动重置。',
generateFailed: '生成筛选条件失败',
},
// ── Map Legend ─────────────────────────────────────
@ -774,6 +786,14 @@ const zh: Translations = {
ogSchools: '学校',
ogCrimeStats: '治安数据',
ogTransport: '交通',
basemap: { standard: '地图', satellite: '卫星' },
error: {
heading: '地图遇到了问题',
body: '当您浏览器的图形上下文被中断时,可能会出现这种情况。',
reload: '重新加载地图',
},
actualListings: { label: '房源', show: '显示实际房源', hide: '隐藏实际房源' },
poi: { zoomInToSeeDetails: '放大以查看详情' },
},
// ── Properties Pane ────────────────────────────────
@ -849,6 +869,20 @@ const zh: Translations = {
crimeDataEnds: '该地区的警方数据截至{{year}}年',
residents: '居民',
residentsTooltip: '常住居民ONS 2021 年人口普查)',
crimeWindow7y: '过去 7 年',
crimeWindow2y: '过去 2 年',
crimeWindowLabel: '时间范围',
crimeCardTitle: '{{name}}(每年)',
crimeRecordsToggle: '显示单起犯罪',
crimeRecordsHide: '隐藏单起犯罪',
crimeRecordsCount: '{{count}} 起犯罪',
crimeRecordsLoading: '正在加载犯罪记录…',
crimeRecordsEmpty: '没有单起犯罪记录',
crimeRecordsError: '无法加载犯罪记录',
crimeRecordsLoadMore: '加载更多',
crimeNoLocation: '地点未公开',
crimeOutcomeUnknown: '结果未记录',
crimeYearPointTooltip: '{{year}}: {{rate}}/年',
},
// ── Street View ────────────────────────────────────
@ -873,6 +907,7 @@ const zh: Translations = {
searchOn: '在 {{radius}} 范围内搜索',
exact: '精确',
outcodeNotRecognised: '无法识别该邮编区域',
radiusMi: '{{count}} 英里范围内',
},
// ── Location Search ────────────────────────────────
@ -929,6 +964,7 @@ const zh: Translations = {
showcaseJourneyRoutes: '出行路线',
showcaseNearby: '附近 {{value}} 个',
showcasePoliticalVoteShare: '政党得票份额',
showcaseGe2024: '2024 大选',
showcaseLotsMore: '……还有更多',
showcaseMinutes: '{{count}} 分钟',
showcaseSendShortlist: '发送候选名单',
@ -1340,6 +1376,8 @@ const zh: Translations = {
noShareLinksYet: '暂无已分享的链接',
copyShareLink: '复制分享链接',
clicksLabel: '点击',
fetchShareLinksError: '获取分享链接失败',
updateNewsletterError: '更新新闻邮件设置失败',
},
// ── Saved Page ─────────────────────────────────────
@ -1353,6 +1391,12 @@ const zh: Translations = {
deleteSearchConfirm: '确定要删除这个保存的搜索吗?此操作无法撤销。',
isBeingUpdated: '正在更新 <strong>{{name}}</strong>',
updating: '更新中...',
loadFailed: '加载搜索失败',
saveFailed: '保存搜索失败',
deleteFailed: '删除搜索失败',
updateNotesFailed: '更新备注失败',
updateNameFailed: '更新名称失败',
updateFailed: '更新搜索失败',
},
// ── Invites Page ───────────────────────────────────
@ -1372,6 +1416,7 @@ const zh: Translations = {
created: '创建时间',
redeemed: '已兑换',
pending: '待兑换',
createInviteError: '创建邀请失败',
},
// ── Invite Page ────────────────────────────────────
@ -1398,6 +1443,105 @@ const zh: Translations = {
youAlreadyHaveLicense: '您已拥有授权',
accountHasFullAccess: '您的账户已拥有完整访问权限。',
failedToValidate: '验证邀请链接失败',
redeemFailed: '兑换邀请失败',
},
// ── Errors ─────────────────────────────────────────
errors: {
appCrashTitle: '出错了',
appCrashBody: '请刷新页面后重试。',
},
// ── Listing ────────────────────────────────────────
listing: {
viewed: '已查看',
openListing: '打开房源',
listings: '套房源',
listing: '房源',
showingOf: '显示 {{count}} 套中的 {{visible}} 套',
groupedNear: '按此地图位置聚合',
},
// ── Overlays ───────────────────────────────────────
overlays: {
heading: '叠加图层',
baseMap: '底图',
colourOpacity: '颜色不透明度',
dataOverlays: '数据叠加层',
about: '关于{{name}}',
zoomWarning: '请进一步放大以查看所选叠加层。',
zoomWarning_other: '请进一步放大以查看所选叠加层。',
noise: {
label: '噪音',
detail:
'Defra 第 4 轮战略噪音地图2022 年),综合道路、铁路和机场来源。数值采用 EU 标准的 Lden 指标(昼-暮-夜 24 小时加权平均),在距地面 4 米高度的 10 米网格上建模。颜色越亮表示建模噪音越高。依据 Open Government Licence v3.0 授权。',
},
crimeHotspots: {
label: '犯罪热点',
detail:
'基于 police.uk 近几个月公布的街道级犯罪数据在客户端生成的热力图。police.uk 的坐标是经过匿名化、对齐到网格的点位,而非确切的案发地点,因此该热力图应被视为相对密度的近似呈现,而非确切的案件分布图。',
},
treesOutsideWoodlands: {
label: '树木与林地',
detail:
'Forest Research Trees Outside Woodland (TOW) v1 树冠多边形——单棵树木和树木群——与 TOW 有意排除的 National Forest Inventory (NFI) 林地地块≥0.5 公顷)合并。二者共同覆盖行道树和真正的林地。多边形的不透明度随树冠面积变化。',
},
propertyBorders: {
label: '房产边界',
detail:
'HM Land Registry INSPIRE Index Polygons——英格兰和威尔士已登记的自由保有房产的位置和大致范围以街道级的轮廓线绘制。这些是仅供参考的“一般边界”并非房产的确切法律边界且不包含仅租赁权益和未登记土地大约覆盖 8590% 的自由保有土地)。本信息受 Crown copyright and database rights 2026 保护,经 HM Land Registry 许可复制。这些多边形(包括相关几何信息,即 x、y 坐标)受 Crown copyright and database rights 2026 Ordnance Survey AC0000851063 保护。依据 Open Government Licence v3.0 授权。',
},
newDevelopments: {
label: '新开发项目',
detail:
'前瞻性的新住房供应管线。蓝色标记表示位于法定 MHCLG Brownfield Land 登记册上的地块——每个都附有预估的净住宅容量和规划许可状态——以及 Homes England Land Hub 处置地块。这些显示了新住房的规划地点,通常比它们出现在 EPC 或成交记录中早数年。住宅数量为容量估算值,而非承诺,登记册上的地块是机会,而非建设的保证。依据 Open Government Licence v3.0 授权。',
},
},
// ── Crime Types ────────────────────────────────────
crimeTypes: {
violenceAndSexualOffences: '暴力与性侵犯',
antiSocialBehaviour: '反社会行为',
criminalDamageAndArson: '故意毁坏与纵火',
publicOrder: '扰乱公共秩序',
shoplifting: '入店行窃',
vehicleCrime: '车辆犯罪',
burglary: '入室盗窃',
otherTheft: '其他盗窃',
theftFromThePerson: '扒窃',
bicycleTheft: '自行车盗窃',
drugs: '毒品',
robbery: '抢劫',
possessionOfWeapons: '持有武器',
otherCrime: '其他犯罪',
},
// ── Journey ────────────────────────────────────────
journey: {
bus: '公交',
lineSuffix: '线',
},
// ── POI Popup ──────────────────────────────────────
poiPopup: {
school: {
capacity: '容量',
type: '类型',
ages: '年龄段',
gender: '性别',
pupilsLabel: '学生',
pupils: '名学生',
freeMeal: '免费餐',
ofsted: 'Ofsted',
sixthForm: '六年级',
religion: '宗教',
admissions: '招生',
trust: '学校联盟',
address: '地址',
localAuthority: 'LA',
head: '校长',
website: '网站',
},
},
// ── Format / Time ──────────────────────────────────
@ -1437,6 +1581,9 @@ const zh: Translations = {
step5Content: '查看区域统计、直方图和单个房产记录:价格、建筑面积、能效评级等。',
step6Title: '附近有什么?',
step6Content: '在地图上开启学校、商店、车站、公园和餐厅图层,查看周边设施。',
step7Title: '叠加更多信息',
step7Content:
'在地图上开启犯罪热点、噪音、树木覆盖、房产边界和新建住宅项目等叠加图层,并按需切换底图。',
},
// ── Server-derived values ──────────────────────────
@ -1493,23 +1640,54 @@ const zh: Translations = {
'Housing Conditions Score': '住房状况得分',
'Air Quality and Road Safety Score': '空气质量与道路安全得分',
// ─ Feature names (Crime) ─
'Serious crime (avg/yr)': '严重犯罪(密度)',
'Minor crime (avg/yr)': '轻微犯罪(密度)',
'Violence and sexual offences (avg/yr)': '暴力和性犯罪(密度)',
'Burglary (avg/yr)': '入室盗窃(密度)',
'Robbery (avg/yr)': '抢劫(密度)',
'Vehicle crime (avg/yr)': '车辆犯罪(密度)',
'Anti-social behaviour (avg/yr)': '反社会行为(密度)',
'Criminal damage and arson (avg/yr)': '刑事毁坏和纵火(密度)',
'Other theft (avg/yr)': '其他盗窃(密度)',
'Theft from the person (avg/yr)': '人身盗窃(密度)',
'Shoplifting (avg/yr)': '商店盗窃(密度)',
'Bicycle theft (avg/yr)': '自行车盗窃(密度)',
'Drugs (avg/yr)': '毒品犯罪(密度)',
'Possession of weapons (avg/yr)': '非法持有武器(密度)',
'Public order (avg/yr)': '扰乱公共秩序(密度)',
'Other crime (avg/yr)': '其他犯罪(密度)',
// ─ Feature names (Crime) — 按人口标准化的比率7 年与 2 年 ─
'Serious crime (/yr, 7y)': '严重犯罪每年7 年)',
'Serious crime (/yr, 2y)': '严重犯罪每年2 年)',
'Minor crime (/yr, 7y)': '轻微犯罪每年7 年)',
'Minor crime (/yr, 2y)': '轻微犯罪每年2 年)',
'Violence and sexual offences (/yr, 7y)': '暴力和性犯罪每年7 年)',
'Violence and sexual offences (/yr, 2y)': '暴力和性犯罪每年2 年)',
'Burglary (/yr, 7y)': '入室盗窃每年7 年)',
'Burglary (/yr, 2y)': '入室盗窃每年2 年)',
'Robbery (/yr, 7y)': '抢劫每年7 年)',
'Robbery (/yr, 2y)': '抢劫每年2 年)',
'Vehicle crime (/yr, 7y)': '车辆犯罪每年7 年)',
'Vehicle crime (/yr, 2y)': '车辆犯罪每年2 年)',
'Anti-social behaviour (/yr, 7y)': '反社会行为每年7 年)',
'Anti-social behaviour (/yr, 2y)': '反社会行为每年2 年)',
'Criminal damage and arson (/yr, 7y)': '刑事毁坏和纵火每年7 年)',
'Criminal damage and arson (/yr, 2y)': '刑事毁坏和纵火每年2 年)',
'Other theft (/yr, 7y)': '其他盗窃每年7 年)',
'Other theft (/yr, 2y)': '其他盗窃每年2 年)',
'Theft from the person (/yr, 7y)': '人身盗窃每年7 年)',
'Theft from the person (/yr, 2y)': '人身盗窃每年2 年)',
'Shoplifting (/yr, 7y)': '商店盗窃每年7 年)',
'Shoplifting (/yr, 2y)': '商店盗窃每年2 年)',
'Bicycle theft (/yr, 7y)': '自行车盗窃每年7 年)',
'Bicycle theft (/yr, 2y)': '自行车盗窃每年2 年)',
'Drugs (/yr, 7y)': '毒品犯罪每年7 年)',
'Drugs (/yr, 2y)': '毒品犯罪每年2 年)',
'Possession of weapons (/yr, 7y)': '非法持有武器每年7 年)',
'Possession of weapons (/yr, 2y)': '非法持有武器每年2 年)',
'Public order (/yr, 7y)': '扰乱公共秩序每年7 年)',
'Public order (/yr, 2y)': '扰乱公共秩序每年2 年)',
'Other crime (/yr, 7y)': '其他犯罪每年7 年)',
'Other crime (/yr, 2y)': '其他犯罪每年2 年)',
// 仅犯罪类型标签(按类型细分 + 记录列表)。
// “Burglary” 已在下方具体犯罪中定义。)
'Violence and sexual offences': '暴力和性犯罪',
Robbery: '抢劫',
'Vehicle crime': '车辆犯罪',
'Anti-social behaviour': '反社会行为',
'Criminal damage and arson': '刑事毁坏和纵火',
'Other theft': '其他盗窃',
'Theft from the person': '人身盗窃',
Shoplifting: '商店盗窃',
'Bicycle theft': '自行车盗窃',
Drugs: '毒品犯罪',
'Possession of weapons': '非法持有武器',
'Public order': '扰乱公共秩序',
'Other crime': '其他犯罪',
// ─ Feature names (Neighbours) ─
'Median age': '中位年龄',

View file

@ -310,23 +310,51 @@ export interface CrimeYearPoint {
}
export interface CrimeYearStats {
/** Crime type without the " (avg/yr)" suffix (e.g. "Burglary"). */
/** Bare crime type (e.g. "Burglary"). */
name: string;
points: CrimeYearPoint[];
}
export interface CrimeAreaAverage {
/** Crime type without the " (avg/yr)" suffix (e.g. "Burglary"). */
/** Full rate-feature name (e.g. "Burglary (per 1k/yr, 7y)"). */
name: string;
/** Exact national mean (avg/yr). Preferred over the histogram-bin national
/** Exact national mean rate. Preferred over the histogram-bin national
* average for crime so all reference numbers share one estimator. */
national?: number;
/** Mean headline rate (avg/yr) across the selection's outcode. */
/** Mean rate across the selection's outcode. */
outcode?: number;
/** Mean headline rate (avg/yr) across the selection's postcode sector. */
/** Mean rate across the selection's postcode sector. */
sector?: number;
}
export interface CrimeRawStats {
/** Bare crime type (e.g. "Burglary"). */
name: string;
/** Mean recorded incidents/yr over the last 7 years. */
per_yr_7y?: number;
/** Mean recorded incidents/yr over the last 2 years. */
per_yr_2y?: number;
}
/** One individual police.uk crime, from /api/crime-records. */
export interface CrimeIncident {
/** "YYYY-MM". */
month: string;
/** Crime type (e.g. "Burglary"). */
type: string;
location?: string;
outcome?: string;
lat: number;
lon: number;
}
export interface CrimeRecordsResponse {
records: CrimeIncident[];
total: number;
offset: number;
truncated: boolean;
}
export interface FilterExclusion {
name: string;
kind: 'numeric' | 'enum' | 'poi' | 'travel';
@ -358,9 +386,15 @@ export interface HexagonStatsResponse {
/** Postcode sector (e.g. "E14 2") of the selection's central postcode, when
* sector crime averages are available for it. */
crime_sector?: string;
/** Per-crime-type average rates across the central postcode's outcode and
/** Per-rate-feature average rates across the central postcode's outcode and
* sector, shown alongside the national average for each crime metric. */
crime_area_averages?: CrimeAreaAverage[];
/** Raw (un-normalised) recorded incidents/yr per crime type, shown beside the
* normalised rate. Display-only. */
crime_raw?: CrimeRawStats[];
/** Total individual crime records (last 7 years) across the selection's
* postcodes the count behind the "individual crimes" list. */
crime_total_records?: number;
central_postcode?: string;
/** Total usual residents (ONS Census 2021) across the postcodes in this
* selection. Display-only; independent of active filters. */