1003 lines
52 KiB
TypeScript
1003 lines
52 KiB
TypeScript
const en = {
|
||
// ── Common ──────────────────────────────────────────
|
||
common: {
|
||
save: 'Save',
|
||
cancel: 'Cancel',
|
||
close: 'Close',
|
||
delete: 'Delete',
|
||
open: 'Open',
|
||
share: 'Share',
|
||
copy: 'Copy',
|
||
copied: 'Copied!',
|
||
copiedToClipboard: 'Copied to clipboard',
|
||
loading: 'Loading...',
|
||
loadMore: 'Load More',
|
||
remaining: '{{count}} remaining',
|
||
search: 'Search',
|
||
all: 'All',
|
||
none: 'None',
|
||
viewDataSource: 'View data source',
|
||
total: 'Total',
|
||
min: 'min',
|
||
or: 'or',
|
||
area: 'Area',
|
||
properties: 'Properties',
|
||
postcode: 'Postcode',
|
||
noAreaSelected: 'No area selected',
|
||
noAreaSelectedDesc:
|
||
'Click any coloured area on the map to see crime, schools, prices, and more',
|
||
clickForDetails: 'Click for details',
|
||
property: 'property',
|
||
propertiesPlural: 'properties',
|
||
},
|
||
|
||
// ── Header / Nav ───────────────────────────────────
|
||
header: {
|
||
appName: 'Perfect Postcode',
|
||
dashboard: 'Dashboard',
|
||
learn: 'Learn',
|
||
pricing: 'Pricing',
|
||
inviteFriends: 'Invite Friends',
|
||
saved: 'Saved',
|
||
logIn: 'Log in',
|
||
createAccount: 'Create account',
|
||
sharing: 'Sharing...',
|
||
exportLabel: 'Export',
|
||
exporting: 'Exporting...',
|
||
exportToExcel: 'Export to Excel',
|
||
openMenu: 'Open menu',
|
||
closeMenu: 'Close menu',
|
||
},
|
||
|
||
// ── User Menu ──────────────────────────────────────
|
||
userMenu: {
|
||
fullAccess: 'Full Access',
|
||
demo: 'Demo',
|
||
themeLight: 'Theme: Light',
|
||
themeDark: 'Theme: Dark',
|
||
account: 'Account',
|
||
logOut: 'Log out',
|
||
},
|
||
|
||
// ── Mobile Menu ────────────────────────────────────
|
||
mobileMenu: {
|
||
menu: 'Menu',
|
||
home: 'Home',
|
||
},
|
||
|
||
// ── Auth Modal ─────────────────────────────────────
|
||
auth: {
|
||
logIn: 'Log in',
|
||
createAccount: 'Create account',
|
||
resetPassword: 'Reset password',
|
||
valueProp: 'Save searches, bookmark properties, and build a shortlist of areas that fit.',
|
||
continueWithGoogle: 'Continue with Google',
|
||
email: 'Email',
|
||
emailPlaceholder: 'you@example.com',
|
||
password: 'Password',
|
||
passwordPlaceholderRegister: 'Min 8 characters',
|
||
passwordPlaceholderLogin: 'Your password',
|
||
forgotPassword: 'Forgot password?',
|
||
resetSent: 'Check your email for a reset link.',
|
||
pleaseWait: 'Please wait...',
|
||
sendResetLink: 'Send reset link',
|
||
backToLogin: 'Back to login',
|
||
},
|
||
|
||
// ── Upgrade Modal ──────────────────────────────────
|
||
upgrade: {
|
||
title: 'Find every matching postcode',
|
||
description:
|
||
'You’re currently exploring the demo area. Get lifetime access to every postcode, every filter, and every neighbourhood in England. One payment, forever.',
|
||
free: 'Free',
|
||
once: '/once',
|
||
freeForEarly: 'Free for early adopters. No credit card required.',
|
||
oneTimePayment: 'One-time payment. Lifetime access.',
|
||
redirecting: 'Redirecting...',
|
||
claimFreeAccess: 'Claim free access',
|
||
upgradeFor: 'Upgrade for {{price}}',
|
||
registerAndUpgrade: 'Register & Upgrade',
|
||
alreadyHaveAccount: 'Already have an account? Log in',
|
||
continueWithDemo: 'Continue with demo',
|
||
backToSharedArea: 'Back to shared area',
|
||
sharedAreaDescription:
|
||
'You’re viewing a shared area. To explore beyond it, get lifetime access to every postcode, every filter, and every neighbourhood in England.',
|
||
checkoutFailed: 'Checkout failed',
|
||
},
|
||
|
||
// ── Save Search Modal ──────────────────────────────
|
||
saveSearch: {
|
||
title: 'Save Search',
|
||
saved: 'Search saved',
|
||
savedSuccess: 'Your search has been saved successfully.',
|
||
viewSavedSearches: 'View saved searches',
|
||
name: 'Name',
|
||
namePlaceholder: 'My search',
|
||
saving: 'Saving...',
|
||
},
|
||
|
||
// ── License Success ────────────────────────────────
|
||
licenseSuccess: {
|
||
title: 'You’re in.',
|
||
subtitle: 'Your lifetime access is now active.',
|
||
description: 'Full access to every feature, every postcode, across all of England.',
|
||
startExploring: 'Start exploring',
|
||
},
|
||
|
||
// ── Filters ────────────────────────────────────────
|
||
filters: {
|
||
activeFilters: 'Active Filters',
|
||
addFilter: 'Add Filter',
|
||
findingPerfectPostcode: 'Finding the Perfect Postcode',
|
||
addFiltersHint: 'Add filters below to narrow the map to areas that match your criteria',
|
||
upgradePrompt:
|
||
'Find matching postcodes using crime, schools, noise, broadband, prices, and 50+ more filters across England.',
|
||
oneTimeLifetime: 'One-time payment, lifetime access.',
|
||
upgradeToFullMap: 'Upgrade to full map',
|
||
chooseFilters: 'Choose the filters that matter to you. The map updates as you go.',
|
||
searchFeatures: 'Search features...',
|
||
noMatchingFeatures: 'No matching features',
|
||
tryDifferentSearch: 'Try a different search term',
|
||
allFeaturesActive: 'All features are active',
|
||
removeFilterHint: 'Remove a filter to see available features',
|
||
featureInfo: 'Feature info',
|
||
replayTutorial: 'Replay interactive tutorial',
|
||
clearAll: 'Clear all',
|
||
clearAllTitle: 'Clear all filters?',
|
||
clearAllSavePrompt: 'Would you like to save your current filters before clearing?',
|
||
saveAndClear: 'Save & Clear',
|
||
clearWithoutSaving: 'Clear without saving',
|
||
},
|
||
|
||
// ── Philosophy Popup ───────────────────────────────
|
||
philosophy: {
|
||
intro:
|
||
'Start with your must-haves, then layer on nice-to-haves. The map narrows as you add filters. The areas left are your best matches.',
|
||
step1Title: 'Budget and basics',
|
||
step1Desc: '(price range, floor area, property type)',
|
||
step2Title: 'Commute',
|
||
step2Desc: '(travel time to your workplace by car, bike, or transit)',
|
||
step3Title: 'Safety',
|
||
step3Desc: '(crime rates, noise levels, ground stability)',
|
||
step4Title: 'Schools',
|
||
step4Desc: '(nearby Ofsted-rated Good or Outstanding schools)',
|
||
step5Title: 'Lifestyle',
|
||
step5Desc: '(restaurants, parks, broadband speed)',
|
||
step6Title: 'Energy',
|
||
step6Desc: '(EPC ratings, insulation, heating costs)',
|
||
tip: 'Tip: if nothing matches, relax one constraint at a time to see which trade-off opens up the most options.',
|
||
},
|
||
|
||
// ── Travel Time ────────────────────────────────────
|
||
travel: {
|
||
travelTime: 'Travel Time ({{mode}})',
|
||
maxTime: 'Max time',
|
||
selectDestination: 'Select destination...',
|
||
bestCase: 'Best case',
|
||
bestCaseTitle: 'Best case travel time',
|
||
bestCaseDesc:
|
||
'Uses the fastest realistic journey time (if you time your departure well and catch good connections). The default uses the <strong>median</strong>, representing a typical journey regardless of when you leave.',
|
||
previewOnMap: 'Preview on map',
|
||
stopPreviewing: 'Stop previewing',
|
||
removeTravelTime: 'Remove travel time',
|
||
addTravelTime: 'Add {{mode}} travel time',
|
||
clearDestination: 'Clear destination',
|
||
typeToFilter: 'Type to filter...',
|
||
noDestinations: 'No destinations found',
|
||
modeCar: 'Car',
|
||
modeBicycle: 'Bicycle',
|
||
modeWalking: 'Walking',
|
||
modeTransit: 'Public Transport',
|
||
modeCarDesc: 'Drive time via the fastest road route',
|
||
modeBicycleDesc: 'Cycling time using bike-friendly routes',
|
||
modeWalkingDesc: 'Walking time along pedestrian paths and pavements',
|
||
modeTransitDesc: 'Journey time by train, tube, and bus',
|
||
},
|
||
|
||
// ── Travel Time Info Popup ─────────────────────────
|
||
travelInfo: {
|
||
transitDesc:
|
||
' by public transport (bus, rail, tube). Times are computed across a typical weekday morning window.',
|
||
carDesc: ' by car, based on typical road speeds and the road network.',
|
||
bicycleDesc: ' by bicycle, using cycle-friendly routes.',
|
||
walkingDesc: ' on foot, using pedestrian paths and pavements.',
|
||
mainDesc: 'Shows how long it takes to reach the selected destination from each area',
|
||
sliderHint: 'Use the slider to set your maximum commute time.',
|
||
},
|
||
|
||
// ── AI Filter ──────────────────────────────────────
|
||
aiFilter: {
|
||
describeIdealArea: 'Describe where you want to live',
|
||
aiSearch: 'AI Search',
|
||
describeHint: 'describe what you’re looking for',
|
||
placeholder: 'e.g. 2-bed under £525k, 45 mins to work, quiet...',
|
||
example1: '2-bed under £525k, 45 mins to work',
|
||
example2: 'Family areas near good schools under £650k',
|
||
example3: 'More space with a sane commute',
|
||
analysing: 'Analysing your query...',
|
||
searchingDestinations: 'Searching for destinations...',
|
||
generatingFilters: 'Generating filters...',
|
||
refiningResults: 'Refining results...',
|
||
weeklyLimitReached:
|
||
'You’ve reached the weekly AI usage limit. It will reset automatically next week.',
|
||
},
|
||
|
||
// ── Map Legend ─────────────────────────────────────
|
||
mapLegend: {
|
||
clearColourView: 'Clear colour view',
|
||
historicalMatches: 'Historical property matches',
|
||
numberOfProperties: 'Number of properties',
|
||
previewing: 'Previewing \u201c{{name}}\u201d',
|
||
},
|
||
|
||
// ── Properties Pane ────────────────────────────────
|
||
propertyCard: {
|
||
unknownAddress: 'Unknown Address',
|
||
unsaveProperty: 'Unsave property',
|
||
saveProperty: 'Save property',
|
||
estValue: 'Est. value:',
|
||
type: 'Type:',
|
||
builtForm: 'Built form:',
|
||
tenure: 'Tenure:',
|
||
floorArea: 'Floor area:',
|
||
rooms: 'Rooms:',
|
||
built: 'Built:',
|
||
formerCouncil: 'Ex-council:',
|
||
exCouncilBadge: 'Ex-council',
|
||
epcRating: 'EPC rating:',
|
||
epcPotential: 'EPC potential:',
|
||
renovations: 'Renovations',
|
||
perSqm: '/m²',
|
||
searchPlaceholder: 'Search by address or postcode...',
|
||
propertyData: 'Property Data',
|
||
propertyDataDesc:
|
||
'Prices come from HM Land Registry (what buyers actually paid). Floor area, energy ratings, construction year, and tenure come from official EPC surveys. Both sources are matched by address within each postcode.',
|
||
},
|
||
|
||
// ── Area Pane ──────────────────────────────────────
|
||
areaPane: {
|
||
areaStatistics: 'Area Statistics',
|
||
statsFor: 'Stats for all properties in this {{type}}',
|
||
matchingFilters: ' matching all active filters',
|
||
filtersAffectStats:
|
||
'Left-pane filters are applied here: values, charts, and property counts use the {{count}} active filters.',
|
||
noFiltersAffectStats:
|
||
'Left-pane filters update this pane: add filters to recalculate these values for matching properties.',
|
||
noFilteredMatches: 'No properties match your filters in this area.',
|
||
unfilteredAreaCount:
|
||
'{{count}} properties exist here before filters, so the location is valid but filtered out.',
|
||
noUnfilteredAreaProperties: 'No properties were found in this selected area before filters.',
|
||
relaxFiltersHint: 'Relax or clear filters to see properties in this area.',
|
||
viewProperties: 'View {{count}} Properties',
|
||
priceHistory: 'Price History',
|
||
journeysFrom: 'Journeys from {{label}}',
|
||
to: 'To {{destination}}',
|
||
noJourneyData: 'No journey data available',
|
||
viewOnGoogleMaps: 'View on Google Maps',
|
||
walk: 'Walk',
|
||
cycle: 'Cycle',
|
||
nationalAvg: 'National avg',
|
||
},
|
||
|
||
// ── Histogram Legend ───────────────────────────────
|
||
histogramLegend: {
|
||
tealBars: 'Teal bars',
|
||
tealBarsDesc: 'show the distribution in this selected area',
|
||
greyBars: 'Grey bars',
|
||
greyBarsDesc: 'show the overall distribution across all areas',
|
||
dashedLine: 'Dashed line',
|
||
dashedLineDesc: 'indicates the national average',
|
||
},
|
||
|
||
// ── Street View ────────────────────────────────────
|
||
streetView: {
|
||
title: 'Street View',
|
||
openLarge: 'Open Street View larger',
|
||
expandedTitle: 'Expanded Street View',
|
||
},
|
||
|
||
// ── POI Pane ───────────────────────────────────────
|
||
poiPane: {
|
||
pois: 'POIs',
|
||
pointsOfInterest: 'Points of Interest',
|
||
poiDescription:
|
||
'Sourced from OpenStreetMap, NaPTAN, and GEOLYTIX Grocery Retail Points. Covers transport stops, shops, chain supermarkets, restaurants, healthcare, leisure, and more.',
|
||
searchCategories: 'Search categories...',
|
||
dataSourceInfo: 'Data source info',
|
||
},
|
||
|
||
// ── External Search Links ──────────────────────────
|
||
externalSearch: {
|
||
searchOn: 'Search {{radius}} on',
|
||
exact: 'exact',
|
||
outcodeNotRecognised: 'Outcode not recognised',
|
||
},
|
||
|
||
// ── Location Search ────────────────────────────────
|
||
locationSearch: {
|
||
placeholder: 'Search places or postcodes...',
|
||
postcodeNotFound: 'Postcode not found',
|
||
lookupFailed: 'Lookup failed',
|
||
searchLabel: 'Search places or postcodes',
|
||
locateMe: 'Go to my location',
|
||
geolocationUnsupported: 'Geolocation not supported by your browser',
|
||
geolocationFailed: 'Could not determine your location',
|
||
},
|
||
|
||
// ── Mobile Drawer ──────────────────────────────────
|
||
mobileDrawer: {
|
||
closeDrawer: 'Close drawer',
|
||
},
|
||
|
||
// ── Home Page ──────────────────────────────────────
|
||
home: {
|
||
heroEyebrow: 'For buyers asking “where should I even look?”',
|
||
heroTitle1: 'Find the postcodes',
|
||
heroTitle2: 'that fit your life',
|
||
heroTitle3: 'Not just the areas you already know.',
|
||
heroSubtitle:
|
||
'From London boroughs to commuter towns and regional cities, England has too many places to research one by one.',
|
||
heroDescription:
|
||
'Set your budget, commute, schools, safety, noise, broadband, and lifestyle needs. Perfect Postcode scans England’s postcodes and reveals the places that actually fit, including areas you would never have typed into a listing portal.',
|
||
exploreTheMap: 'Find my matching postcodes',
|
||
seeTheDifference: 'See how it works',
|
||
showcaseHeader: 'Product showcase',
|
||
showcaseContext: 'How Perfect Postcode works',
|
||
showcaseStep1Tab: 'Filter',
|
||
showcaseStep1Title: 'Turn vague needs into a tight search',
|
||
showcaseStep1Body:
|
||
'Set what matters and see exactly how many wrong-fit postcodes each requirement keeps out of your search.',
|
||
showcaseStep1Chip1: 'Quiet streets',
|
||
showcaseStep1Chip2: 'Top-rated primaries',
|
||
showcaseStep1Chip3: 'Under £500k',
|
||
showcaseStep1VennCenter: 'Postcodes that meet all three',
|
||
showcaseStep2Tab: 'Match',
|
||
showcaseStep2Title: 'Let the map surface places you would not have typed',
|
||
showcaseStep2Body:
|
||
'Scan England by fit instead of starting from familiar area names. Hidden pockets become visible before listing portals narrow your imagination.',
|
||
showcaseStep2Region: 'Greater London',
|
||
showcaseStep2Sources: 'Land Registry · ONS · Ofsted · DfT',
|
||
showcaseStep2ClustersLabel: 'Matching clusters',
|
||
showcaseStep3Tab: 'Inspect',
|
||
showcaseStep3Title: 'Inspect why a postcode made the cut',
|
||
showcaseStep3Body:
|
||
'Open any matching area and check prices, safety, schools, broadband, and trade-offs in one pane before you spend a weekend there.',
|
||
showcaseStep3HeaderArea: 'Penge · SE20',
|
||
showcaseStep3HeaderFit: 'Strong fit · 7/8',
|
||
showcaseStep3Stat1Label: 'Sold price trend',
|
||
showcaseStep3Stat2Label: 'Crime rate',
|
||
showcaseStep3Stat2Value: 'Below borough avg.',
|
||
showcaseStep3Stat3Label: 'Median age',
|
||
showcaseStep3Stat4Label: 'Broadband',
|
||
showcaseStep3Stat4Value: '1 Gbps available',
|
||
showcaseStep3Stat5Label: 'Primary schools',
|
||
showcaseStep3Stat5Value: '3 outstanding within 1 mile',
|
||
showcaseStep4Tab: 'Scout',
|
||
showcaseStep4Title: 'Scout it out yourself',
|
||
showcaseStep4Body:
|
||
'Take three grounded starting points into the real world. Walk the streets, test the commute, and compare viewings with context.',
|
||
showcaseStep4FileName: 'areas-to-scout.xlsx',
|
||
showcaseStep4ExportLabel: 'Export to Excel',
|
||
showcaseStep4ColPostcode: 'Postcode',
|
||
showcaseStep4ColScore: 'Fit',
|
||
showcaseStep4ColCommute: 'Commute',
|
||
showcaseStep4ColPrice: 'Median sold',
|
||
showcaseStep4Conclusion: 'You can start your journey from here. You are no longer lost.',
|
||
statProperties: 'historical sales',
|
||
statFilters: 'combinable filters',
|
||
statEvery: 'Every',
|
||
statPostcodeInEngland: 'postcode in England',
|
||
ourPhilosophy: 'Start with your life, not a postcode',
|
||
philosophyP1:
|
||
'Most property sites ask where you want to live. In London that is painfully hard, but the same problem shows up across England: buyers choose from the few places they know, then cross-check commute tools, Ofsted, police data, Street View, broadband checkers, and sold prices in separate tabs.',
|
||
philosophyP2:
|
||
'Perfect Postcode flips the search. Tell the map what matters and it shows the postcodes that qualify, with evidence for why they are worth inspecting. Data first, then go test the vibe.',
|
||
streetTitle: 'Places change street by street',
|
||
streetIntro:
|
||
'Broad area names hide the details that matter: the station side, the road noise, the school mix, the exact commute, and what similar homes actually sold for.',
|
||
streetCard1Title: 'Find areas you may have missed',
|
||
streetCard1Body:
|
||
'Surface postcodes that match your requirements instead of relying on familiar names, friend recommendations, or “up-and-coming” hype.',
|
||
streetCard2Title: 'See the trade-offs before viewings',
|
||
streetCard2Body:
|
||
'Compare price, space, commute, safety, schools, broadband, noise, and energy ratings before you spend weekends travelling between viewings.',
|
||
othersVs: 'Others vs',
|
||
checkMyPostcode: 'Listing portals',
|
||
areaGuides: 'Postcode reports',
|
||
compSearchWithout: 'Discover areas before you know their names',
|
||
compSearchWithoutSub: '(requirements first, location second)',
|
||
compAreaData: 'Postcode-level neighbourhood evidence',
|
||
compAreaDataSub: '(crime, schools, noise, broadband, amenities)',
|
||
compPropertyData: 'Property-level history',
|
||
compPropertyDataSub: '(sold prices, EPC, floor area, estimated value)',
|
||
compFilters: '56 filters working together',
|
||
compFiltersSub: '(not one postcode or one listing at a time)',
|
||
ctaTitle: 'Stop guessing where to buy.',
|
||
ctaDescription:
|
||
'Build a shortlist of postcodes that fit your actual life, then test them in person.',
|
||
},
|
||
|
||
// ── Pricing Page ───────────────────────────────────
|
||
pricingPage: {
|
||
title: 'Buy with a better search area',
|
||
subtitle:
|
||
'Lifetime access to the map that helps you find where to look before you book viewings.',
|
||
costContext:
|
||
'Buyers often spend evenings stitching together listings, commute checks, school reports, crime maps, Street View, and sold prices. In London this is relentless, but the same research problem appears across England. Perfect Postcode puts the area research on one map before you commit your weekends, fees, and attention.',
|
||
lessThanSurvey: 'Less than a survey. Useful before you even choose an area.',
|
||
currentTier: 'Current tier',
|
||
firstNUsers: 'First {{count}} users',
|
||
everyoneAfter: 'Everyone after',
|
||
nextNUsers: 'Next {{count}} users',
|
||
lifetime: '/lifetime',
|
||
spotsRemaining: '{{count}} spot remaining',
|
||
spotsRemainingPlural: '{{count}} spots remaining',
|
||
filled: 'Filled',
|
||
openDashboard: 'Open dashboard',
|
||
getStarted: 'Get started',
|
||
getStartedPrice: 'Get started - {{price}}',
|
||
noCreditCard: 'No credit card required',
|
||
|
||
soldOut: 'Sold out',
|
||
upcoming: 'Upcoming',
|
||
failedToLoad: 'Failed to load pricing. Please try again later.',
|
||
feat1: '56 filters across England',
|
||
feat2: 'Every postcode searchable from your needs',
|
||
feat3: 'Unlimited map exploration, saved searches and exports',
|
||
feat4: '13M historical transactions and price context',
|
||
feat5: 'Commute, schools, crime, noise, broadband and more',
|
||
feat6: 'All future data updates included',
|
||
},
|
||
|
||
// ── Learn Page ─────────────────────────────────────
|
||
learnPage: {
|
||
faq: 'FAQ',
|
||
dataSources: 'Data Sources',
|
||
support: 'Support',
|
||
dataSourcesIntro:
|
||
'This application combines {{count}} open datasets covering property prices, energy performance, transport, demographics, crime, environment, and more.',
|
||
faqIntro:
|
||
'Whether you’re narrowing a first-time buyer search, checking an unfamiliar postcode, or building a viewing shortlist, here’s how Perfect Postcode helps you work out where to look.',
|
||
supportIntro: 'Have a question? Check our FAQ or reach out to us directly.',
|
||
source: 'Source:',
|
||
optOut: 'Opt out of public disclosure',
|
||
attribution: 'Attribution',
|
||
attrLandRegistry: 'Contains HM Land Registry data © Crown copyright and database right 2025.',
|
||
attrOgl: 'Contains public sector information licensed under the',
|
||
attrOglLink: 'Open Government Licence v3.0',
|
||
attrOs: 'Contains OS data © Crown copyright and database rights 2025.',
|
||
attrTfl: 'Powered by TfL Open Data.',
|
||
attrOsm: 'Contains data from',
|
||
attrOsmContrib: '© OpenStreetMap contributors',
|
||
attrOsmLicense: 'available under the',
|
||
attrOsmLicenseLink: 'Open Data Commons Open Database License (ODbL)',
|
||
// Data source names & descriptions
|
||
dsPricePaidName: 'Price Paid Data',
|
||
dsPricePaidOrigin: 'HM Land Registry',
|
||
dsPricePaidUse: 'Complete historical property sale prices for England.',
|
||
dsEpcName: 'Energy Performance Certificates (EPC)',
|
||
dsEpcOrigin: 'Ministry of Housing, Communities & Local Government',
|
||
dsEpcUse:
|
||
'Domestic Energy Performance Certificates providing floor area, number of rooms, construction year, energy ratings, property type, and built form. Matched with Price Paid records by address within each postcode. Property owners can opt out of public disclosure.',
|
||
dsNsplName: 'National Statistics Postcode Lookup (NSPL)',
|
||
dsNsplOrigin: 'ONS / ArcGIS',
|
||
dsNsplUse:
|
||
'Maps postcodes to coordinates and statistical area codes, used to link all area-level datasets to individual properties.',
|
||
dsIodName: 'English Indices of Deprivation 2025',
|
||
dsIodOrigin: 'Ministry of Housing, Communities & Local Government',
|
||
dsIodUse:
|
||
'Relative deprivation scores across income, employment, education, health, crime, and living environment for every neighbourhood in England.',
|
||
dsEthnicityName: 'Population by Ethnicity (2021 Census)',
|
||
dsEthnicityOrigin: 'ONS',
|
||
dsEthnicityUse:
|
||
'Population percentages by ethnic group (South Asian, East Asian, Black, Mixed, White, Other) per local authority.',
|
||
dsCrimeName: 'Street-level Crime Data',
|
||
dsCrimeOrigin: 'data.police.uk',
|
||
dsCrimeUse:
|
||
'Street-level crime data from 2023 to 2025, aggregated into yearly averages by LSOA and crime type (violence, burglary, anti-social behaviour, drugs, vehicle crime, etc.).',
|
||
dsOsmName: 'OpenStreetMap POIs',
|
||
dsOsmOrigin: 'OpenStreetMap contributors / Geofabrik',
|
||
dsOsmUse:
|
||
'Points of interest covering shops, restaurants, healthcare, leisure, tourism, and more across Great Britain.',
|
||
dsGeolytixRetailName: 'GEOLYTIX Grocery Retail Points',
|
||
dsGeolytixRetailOrigin: 'GEOLYTIX',
|
||
dsGeolytixRetailUse:
|
||
'Supermarket and convenience store locations across the UK, including chain retailers such as Waitrose, Tesco, Sainsbury’s, Asda, Morrisons, Aldi, Lidl, Co-op, M&S, Iceland, and Spar.',
|
||
dsGreenspaceName: 'OS Open Greenspace',
|
||
dsGreenspaceOrigin: 'Ordnance Survey',
|
||
dsGreenspaceUse:
|
||
'Authoritative green space boundaries for Great Britain, including public parks, gardens, playing fields, and play spaces. Polygon centroids are used for park proximity counts and distance-to-nearest-park calculations.',
|
||
dsNaptanName: 'NaPTAN (Public Transport Stops)',
|
||
dsNaptanOrigin: 'Department for Transport',
|
||
dsNaptanUse:
|
||
'Station and stop locations for rail, bus, metro/tram, ferry, and airports across England.',
|
||
dsNoiseName: 'Defra Noise Mapping',
|
||
dsNoiseOrigin: 'Defra / Environment Agency',
|
||
dsNoiseUse:
|
||
'Road noise levels (24-hour weighted average) from the 2022 strategic noise mapping, modelled at high resolution and sampled at each postcode.',
|
||
dsOfstedName: 'Ofsted School Inspections',
|
||
dsOfstedOrigin: 'Ofsted',
|
||
dsOfstedUse:
|
||
'Latest inspection outcomes for state-funded schools (as at April 2025). Averaged per postcode to give a local school quality score (1=Outstanding to 4=Inadequate).',
|
||
dsBroadbandName: 'Ofcom Broadband Performance',
|
||
dsBroadbandOrigin: 'Ofcom',
|
||
dsBroadbandUse:
|
||
'Fixed broadband coverage and maximum download speeds by area from Ofcom Connected Nations 2025.',
|
||
dsCouncilTaxName: 'Council Tax Levels 2025-26',
|
||
dsCouncilTaxOrigin: 'Ministry of Housing, Communities & Local Government',
|
||
dsCouncilTaxUse:
|
||
'Annual council tax rates for Bands A-H for all 296 billing authorities in England, for a dwelling occupied by two adults. Joined to properties via local authority district code from the NSPL postcode lookup.',
|
||
dsRentalName: 'Private Rental Market Statistics',
|
||
dsRentalOrigin: 'ONS / Valuation Office Agency',
|
||
dsRentalUse:
|
||
'Median monthly private rental prices by local authority and bedroom category (Oct 2022 - Sep 2023). Joined to properties via local authority district code and estimated bedroom count.',
|
||
dsElectionName: '2024 General Election Results',
|
||
dsElectionOrigin: 'UK Parliament',
|
||
dsElectionUse:
|
||
'Candidate-level results for the July 2024 UK General Election. Aggregated to constituency level: voter turnout (%) and party vote shares (%). Joined to properties via the parliamentary constituency code (pcon) from the NSPL postcode lookup.',
|
||
// FAQ section titles
|
||
faqFindingTitle: 'Search Strategy',
|
||
faqCommuteTitle: 'Travel-Time Routing',
|
||
faqBudgetTitle: 'Estimated Prices',
|
||
faqSafetyTitle: 'Safety and Neighbourhood',
|
||
faqFamiliesTitle: 'Families and Schools',
|
||
faqEnvironmentTitle: 'Environment and Quality of Life',
|
||
faqDueDiligenceTitle: 'Scope and Due Diligence',
|
||
faqPrivacyTitle: 'Privacy and Data Protection',
|
||
faqWhyTitle: 'Why Perfect Postcode',
|
||
faqPricingTitle: 'Access',
|
||
faqTipsTitle: 'Tips and Tricks',
|
||
// FAQ items — Finding Your Area
|
||
faqFinding1Q: 'Where should I look once the obvious areas are too expensive?',
|
||
faqFinding1A:
|
||
'Set your budget, property type, floor area, commute, schools, crime, noise, broadband, parks, and other must-haves. The map removes postcodes that fail those tests, so overlooked areas can surface before you start searching listings.',
|
||
faqFinding2Q: 'How do I find good postcodes in places I do not know well?',
|
||
faqFinding2A:
|
||
'Filter the whole map by your hard requirements, then inspect the clusters that remain. You can compare unfamiliar postcodes by commute, sold prices, schools, crime, broadband, noise, and amenities instead of relying on reputation.',
|
||
faqFinding3Q: 'What should I do when my search returns too many or too few areas?',
|
||
faqFinding3A:
|
||
'Start with hard limits, then colour the map by a trade-off such as price per sqm, road noise, school score, or commute time. If the map gets too narrow, relax one slider and you can see exactly which compromise opens up more options.',
|
||
// FAQ items — Commute and Travel
|
||
faqCommute1Q: 'How are the travel times calculated?',
|
||
faqCommute1A:
|
||
'Travel times are precomputed with Conveyal R5, a routing engine used for transport analysis. For each supported destination we route to reachable postcodes over the street and transit network, then store sparse postcode travel-time files for car, cycling, walking, and public transport. That lets the map filter thousands of postcodes quickly instead of calling a route API one postcode at a time.',
|
||
faqCommute2Q: 'What should I know about the travel-time numbers?',
|
||
faqCommute2A:
|
||
'Public transport times use a morning peak departure window, 07:30 to 08:30. The default is the median journey time, which is the typical result across that window; the best-case toggle uses the 5th percentile for well-timed departures. They are modelled comparison times, not live disruption, traffic, or platform-change predictions.',
|
||
// FAQ items — Budget and Value
|
||
faqBudget1Q: 'How does the estimated current price algorithm work?',
|
||
faqBudget1A:
|
||
'The proprietary estimate starts with the last HM Land Registry sale price. It adjusts that price to today using a repeat-sales index learned from properties that sold more than once, stratified by postcode sector and property type. Sparse areas are shrunk toward district, area, national, and hedonic fallback models, then spatially smoothed. Finally, the result is blended with a nearest-neighbour estimate from nearby, recently sold, same-type homes using adjusted price per sqm and EPC floor area.',
|
||
faqBudget2Q: 'Why use estimated current price instead of last sold price?',
|
||
faqBudget2A:
|
||
'Last sold price can be years or decades old, and live asking prices only cover whatever happens to be listed today. Estimated current price puts old sales into current-market terms so you can compare more properties, calculate estimated price per sqm, and spot areas that look good value before listings appear. It is a screening estimate, not a formal valuation.',
|
||
// FAQ items — Safety and Neighbourhood
|
||
faqSafety1Q: 'What type of crime is common around this postcode?',
|
||
faqSafety1A:
|
||
'Police-recorded crime is broken down by type, including violence, burglary, robbery, vehicle crime, antisocial behaviour, shoplifting, drugs, and public order. You can filter by the specific risks you care about instead of relying on a single vague safety score.',
|
||
faqSafety2Q: 'What should I check before viewing an unfamiliar street?',
|
||
faqSafety2A:
|
||
'Check crime, road noise, deprivation, broadband, parks, groceries, schools, and commute before you book. The listing photos can still be useful, but they should not be the first time you learn what the street is like.',
|
||
// FAQ items — Families and Schools
|
||
faqFamilies1Q: 'Which areas have the right mix of schools, space, safety, and commute?',
|
||
faqFamilies1A:
|
||
'Stack Ofsted ratings, crime, parks, commute, floor area, property type, and budget on one map. The result is a practical family shortlist rather than a pile of separate school, crime, listing, and transport searches.',
|
||
faqFamilies2Q: 'Does this prove I am inside a school catchment?',
|
||
faqFamilies2A:
|
||
'No. We show nearby school quality and area-level education data, but admissions boundaries and priority rules can change. Treat Perfect Postcode as a shortlist tool, then verify catchments and admissions with the school or local authority.',
|
||
// FAQ items — Environment and Quality of Life
|
||
faqEnv1Q: 'How do I avoid a noisy road without losing commute or broadband quality?',
|
||
faqEnv1A:
|
||
'Filter by road noise, then keep commute time, broadband speed, price, and property filters active. You can colour by any one feature while the others keep the shortlist honest.',
|
||
faqEnv2Q: 'Do you show flood risk, subsidence, or survey issues?',
|
||
faqEnv2A:
|
||
'Not as live filters today. We show data such as road noise, EPC, construction age, and local environment indicators, but flood searches, title checks, structural issues, and mortgageability still need proper conveyancing, lender checks, and a survey.',
|
||
faqEnv3Q: 'What running-cost checks can I do before viewing?',
|
||
faqEnv3A:
|
||
'You can screen for EPC rating, total floor area, construction age, council tax authority, broadband, and noise before viewing. That will not predict your exact bills, but it helps you avoid obvious mismatches early.',
|
||
// FAQ items — Listing Portals and Due Diligence
|
||
faqDueDiligence1Q: 'Should I use this before or after checking Rightmove?',
|
||
faqDueDiligence1A:
|
||
'Use Perfect Postcode before and alongside listing portals. Rightmove, Zoopla, and OnTheMarket are still where you check live availability, photos, agent contact, viewings, and alerts. Perfect Postcode helps you work out which postcodes are worth searching in the first place.',
|
||
faqDueDiligence2Q: 'Why can’t I filter by garden, garage, or layout?',
|
||
faqDueDiligence2A:
|
||
'Only where the information exists in structured official data. Perfect Postcode can filter by things like floor area, property type, tenure, EPC, sold prices, and local data. Gardens, garages, aspect, room layout, and estate-agent wording still need to be checked in the listing and at the viewing.',
|
||
faqDueDiligence3Q: 'Do you track listing price cuts and time on market?',
|
||
faqDueDiligence3A:
|
||
'Not currently. Perfect Postcode is built around official sold-price, EPC, postcode, travel-time, and neighbourhood data rather than live listing feeds. You can still use date of last transaction, sold price history, estimated current value, and price per sqm to judge whether a live asking price looks stretched.',
|
||
faqDueDiligence4Q: 'What should I still verify before making an offer?',
|
||
faqDueDiligence4A:
|
||
'Use Perfect Postcode to sanity-check the area and value, then verify the live listing details, tenure, lease terms, service charge, planning history, flood risk, title issues, lender requirements, and survey findings through the usual professional process.',
|
||
// FAQ items — Privacy and Data Protection
|
||
faqPrivacy1Q: 'Do you store personal data about me?',
|
||
faqPrivacy1A:
|
||
'We do not store personal data in the property and neighbourhood datasets. Those datasets are built from official and public sources for postcode and property research. If you create an account, we store only what is needed to run the service, such as your email address, licence status, newsletter preference, saved searches, saved properties, and payment identifiers handled through Stripe. We handle that account data under UK GDPR and the Data Protection Act 2018.',
|
||
// FAQ items — Why Perfect Postcode
|
||
faqWhy1Q: 'What does this show that listing portals usually do not?',
|
||
faqWhy1A:
|
||
'Listing portals start from homes that are for sale right now. Perfect Postcode starts from the places that fit your life and budget, using sold prices, floor area, commute, schools, crime, noise, broadband, EPC, tenure, and amenities before you open the listings.',
|
||
faqWhy2Q: 'How much manual research does this save?',
|
||
faqWhy2A:
|
||
'You can, but it means stitching together Land Registry, EPC, police, Ofsted, Ofcom, ONS, Defra, travel-time, and map data one postcode at a time. Perfect Postcode makes those sources filterable across England in one place.',
|
||
faqWhy3Q: 'How reliable are the underlying sources?',
|
||
faqWhy3A:
|
||
'The core datasets come from official or authoritative sources such as HM Land Registry, EPC records, ONS, Ofsted, Ofcom, data.police.uk, Defra, Ordnance Survey, and OpenStreetMap. They are excellent for shortlisting and comparison, but any purchase decision still needs current checks and professional advice.',
|
||
// FAQ items — Pricing and Access
|
||
faqPricing1Q: 'Why pay when postcode reports are free?',
|
||
faqPricing1A:
|
||
'Free postcode tools are useful once you already know what to check. Perfect Postcode is for scanning every postcode in England against your criteria, combining filters, comparing trade-offs, saving searches, and exporting a shortlist before you commit weekends to viewings.',
|
||
faqPricing2Q: 'What does lifetime access mean?',
|
||
faqPricing2A:
|
||
'Lifetime access means one payment gives your account ongoing access to the paid Perfect Postcode map for the lifetime of the service. It is not a monthly or annual subscription, and normal data updates are included. You can use it during this search, come back later, and still have access if you move again.',
|
||
faqPricing3Q: 'What can I access on the free tier?',
|
||
faqPricing3A:
|
||
'Free users can explore all features within the demo area (inner London, roughly zones 1 to 2). To access data for the rest of England, you need lifetime access.',
|
||
|
||
// FAQ items — Tips and Tricks
|
||
faqTips1Q: 'How do I describe a search in plain English?',
|
||
faqTips1A:
|
||
'Type something like "freehold 3-bed under £550k, 45 minutes to work, quiet, good broadband", and the AI filter will set up the matching filters it understands. It will also tell you when a request, such as garden size, is not available as a structured filter.',
|
||
faqTips2Q: 'Can I save a search and come back to it later?',
|
||
faqTips2A:
|
||
'Hit the save button and everything is captured: your filters, zoom level, and which data layer you’re colouring by. Pick up exactly where you left off or share the link with your partner.',
|
||
faqTips3Q: 'Can I export the data I’m looking at?',
|
||
faqTips3A:
|
||
'Use the export button to download the currently filtered properties as a spreadsheet. The export respects your active filters, so you can take a clean shortlist into portals, viewings, spreadsheets, or conversations with someone buying with you.',
|
||
},
|
||
|
||
// ── Account Page ───────────────────────────────────
|
||
accountPage: {
|
||
emailLabel: 'Email',
|
||
subscriptionLabel: 'Subscription',
|
||
upgrade: 'Upgrade',
|
||
redirecting: 'Redirecting…',
|
||
receiveNewsletter: 'Receive newsletter emails',
|
||
needHelp: 'Need help? Email us at',
|
||
responseTime: 'We typically respond within 24 hours.',
|
||
},
|
||
|
||
// ── Saved Page ─────────────────────────────────────
|
||
savedPage: {
|
||
searches: 'Searches',
|
||
noSavedSearches: 'No saved searches yet',
|
||
noSavedSearchesDesc:
|
||
'Save your filters and map view so you can pick up exactly where you left off.',
|
||
noSavedProperties: 'No saved properties yet',
|
||
noSavedPropertiesDesc:
|
||
'Bookmark properties as you explore and build your shortlist without losing track.',
|
||
openPostcode: 'Open postcode',
|
||
clickToRename: 'Click to rename',
|
||
notesPlaceholder: 'Jot down your thoughts...',
|
||
deleteSearch: 'Delete search',
|
||
deleteSearchConfirm:
|
||
'Are you sure you want to delete this saved search? This cannot be undone.',
|
||
deleteProperty: 'Delete property',
|
||
deletePropertyConfirm:
|
||
'Are you sure you want to delete this saved property? This cannot be undone.',
|
||
bed: 'bed',
|
||
epc: 'EPC',
|
||
},
|
||
|
||
// ── Invites Page ───────────────────────────────────
|
||
invitesPage: {
|
||
inviteLinksLicensed: 'Invite links are available for licensed users.',
|
||
inviteAdminLabel: 'Invite friends (100% off)',
|
||
inviteReferralLabel: 'Invite friends (30% off)',
|
||
generateFreeInvite: 'Generate free invite link',
|
||
generateReferralLink: 'Generate referral link',
|
||
copyInviteLink: 'Copy invite link',
|
||
adminInvitesTitle: 'Admin invites (100% off)',
|
||
referralInvitesTitle: 'Referral invites (30% off)',
|
||
yourInviteLinks: 'Your invite links',
|
||
noInvitesYet: 'No invites generated yet',
|
||
link: 'Link',
|
||
status: 'Status',
|
||
created: 'Created',
|
||
redeemed: 'Redeemed',
|
||
pending: 'Pending',
|
||
},
|
||
|
||
// ── Invite Page ────────────────────────────────────
|
||
invitePage: {
|
||
youreInvited: 'You’re invited!',
|
||
specialOffer: 'Special offer!',
|
||
invitedByFree: '{{name}} has invited you to get free lifetime access.',
|
||
invitedByDiscount: '{{name}} has shared a 30% discount on lifetime access.',
|
||
genericFreeInvite: 'You have been invited to get free lifetime access.',
|
||
genericDiscount: 'A friend has shared a 30% discount on lifetime access.',
|
||
exploreEvery: 'Find postcodes that fit your life',
|
||
propertyInfo: 'Prices, commute, schools, crime, noise, broadband, EPC and more',
|
||
invalidInvite: 'Invalid invite',
|
||
inviteAlreadyUsed: 'Invite already used',
|
||
inviteAlreadyUsedDesc: 'This invite link has already been redeemed.',
|
||
invalidInviteLink: 'Invalid invite link',
|
||
invalidInviteLinkDesc: 'This invite link is invalid or has expired.',
|
||
licenseActivated: 'License activated!',
|
||
fullAccessGranted: 'You now have full access to Perfect Postcode.',
|
||
activating: 'Activating...',
|
||
activateLicense: 'Activate license',
|
||
claimDiscount: 'Claim discount',
|
||
registerToClaim: 'Register to claim',
|
||
youAlreadyHaveLicense: 'You already have a license',
|
||
accountHasFullAccess: 'Your account already has full access.',
|
||
failedToValidate: 'Failed to validate invite link',
|
||
},
|
||
|
||
// ── Map Page ───────────────────────────────────────
|
||
mapPage: {
|
||
unsavedProperty: 'Unsave',
|
||
savedProperty: 'Saved',
|
||
},
|
||
|
||
// ── Format / Time ──────────────────────────────────
|
||
format: {
|
||
justNow: 'just now',
|
||
minutesAgo: '{{count}}m ago',
|
||
hoursAgo: '{{count}}h ago',
|
||
daysAgo: '{{count}}d ago',
|
||
nFilters: '{{count}} filters',
|
||
noFilters: 'No filters',
|
||
poiCategory: '{{count}} POI category',
|
||
poiCategories: '{{count}} POI categories',
|
||
travelDestination: '{{count}} travel time destination',
|
||
travelDestinations: '{{count}} travel time destinations',
|
||
propertiesMatch: '{{count}} properties match',
|
||
setFilters: 'Set {{count}} filter(s): {{list}}',
|
||
noFiltersSet: 'No filters set',
|
||
toDestination: '{{mode}} to {{label}} {{bounds}}',
|
||
lessThanMin: '< {{max}} min',
|
||
moreThanMin: '> {{min}} min',
|
||
},
|
||
|
||
// ── Tutorial ──────────────────────────────────────
|
||
tutorial: {
|
||
step1Title: 'Tell the map what matters',
|
||
step1Content:
|
||
'Set your budget, commute limit, school quality, crime threshold, noise tolerance, broadband needs, or whatever matters to you. Only matching areas stay lit. Use the eye icon to colour by any feature.',
|
||
step2Title: 'Or just describe it',
|
||
step2Content:
|
||
'Type what you want in plain English, like "quiet area near good schools under £400k", and we’ll set up the filters for you.',
|
||
step3Title: 'Explore what’s out there',
|
||
step3Content:
|
||
'Pan and zoom across England. Click any coloured area to see why it matches: crime, schools, prices, broadband, noise, and more.',
|
||
step4Title: 'Jump to a location',
|
||
step4Content: 'Search for any place or postcode to fly straight there.',
|
||
step5Title: 'Dig into the details',
|
||
step5Content:
|
||
'See area statistics, histograms, and individual property records: prices, floor area, energy ratings, and more.',
|
||
step6Title: 'What’s nearby?',
|
||
step6Content:
|
||
'Toggle schools, shops, stations, parks, and restaurants on the map to see what’s within reach.',
|
||
},
|
||
|
||
// ── Server-derived values ──────────────────────────
|
||
// Keyed by the English server value. ts() looks up translations at display time.
|
||
// The English keys MUST match exactly what the API returns.
|
||
server: {
|
||
// ─ Feature group names ─
|
||
Properties: 'Properties',
|
||
Transport: 'Transport',
|
||
Education: 'Education',
|
||
Deprivation: 'Deprivation',
|
||
Crime: 'Crime',
|
||
Demographics: 'Demographics',
|
||
Politics: 'Politics',
|
||
Amenities: 'Amenities',
|
||
|
||
// ─ Feature names (Properties) ─
|
||
'Property type': 'Property type',
|
||
'Leasehold/Freehold': 'Leasehold/Freehold',
|
||
'Last known price': 'Last known price',
|
||
'Estimated current price': 'Estimated current price',
|
||
'Price per sqm': 'Price per sqm',
|
||
'Est. price per sqm': 'Est. price per sqm',
|
||
'Estimated monthly rent': 'Estimated monthly rent',
|
||
'Total floor area (sqm)': 'Total floor area (sqm)',
|
||
'Number of bedrooms & living rooms': 'Number of bedrooms & living rooms',
|
||
'Construction year': 'Construction year',
|
||
'Date of last transaction': 'Date of last transaction',
|
||
'Former council house': 'Former council house',
|
||
'Current energy rating': 'Current energy rating',
|
||
'Potential energy rating': 'Potential energy rating',
|
||
'Interior height (m)': 'Interior height (m)',
|
||
|
||
// ─ Feature names (Transport) ─
|
||
'Distance to nearest train or tube station (km)':
|
||
'Distance to nearest train or tube station (km)',
|
||
|
||
// ─ Feature names (Education) ─
|
||
'Good+ primary schools within 2km': 'Good+ primary schools within 2km',
|
||
'Good+ secondary schools within 2km': 'Good+ secondary schools within 2km',
|
||
'Good+ primary schools within 5km': 'Good+ primary schools within 5km',
|
||
'Good+ secondary schools within 5km': 'Good+ secondary schools within 5km',
|
||
'Outstanding primary schools within 2km': 'Outstanding primary schools within 2km',
|
||
'Outstanding secondary schools within 2km': 'Outstanding secondary schools within 2km',
|
||
'Outstanding primary schools within 5km': 'Outstanding primary schools within 5km',
|
||
'Outstanding secondary schools within 5km': 'Outstanding secondary schools within 5km',
|
||
'Education, Skills and Training Score': 'Education, Skills and Training Score',
|
||
|
||
// ─ Feature names (Deprivation) ─
|
||
'Income Score (rate)': 'Income Score (rate)',
|
||
'Employment Score (rate)': 'Employment Score (rate)',
|
||
'Health Deprivation and Disability Score': 'Health Deprivation and Disability Score',
|
||
'Living Environment Score': 'Living Environment Score',
|
||
'Indoors Sub-domain Score': 'Indoors Sub-domain Score',
|
||
'Outdoors Sub-domain Score': 'Outdoors Sub-domain Score',
|
||
|
||
// ─ Feature names (Crime) ─
|
||
'Serious crime per 1k residents (avg/yr)': 'Serious crime per 1k residents (avg/yr)',
|
||
'Minor crime per 1k residents (avg/yr)': 'Minor crime per 1k residents (avg/yr)',
|
||
'Serious crime (avg/yr)': 'Serious crime (avg/yr)',
|
||
'Minor crime (avg/yr)': 'Minor crime (avg/yr)',
|
||
'Violence and sexual offences (avg/yr)': 'Violence and sexual offences (avg/yr)',
|
||
'Burglary (avg/yr)': 'Burglary (avg/yr)',
|
||
'Robbery (avg/yr)': 'Robbery (avg/yr)',
|
||
'Vehicle crime (avg/yr)': 'Vehicle crime (avg/yr)',
|
||
'Anti-social behaviour (avg/yr)': 'Anti-social behaviour (avg/yr)',
|
||
'Criminal damage and arson (avg/yr)': 'Criminal damage and arson (avg/yr)',
|
||
'Other theft (avg/yr)': 'Other theft (avg/yr)',
|
||
'Theft from the person (avg/yr)': 'Theft from the person (avg/yr)',
|
||
'Shoplifting (avg/yr)': 'Shoplifting (avg/yr)',
|
||
'Bicycle theft (avg/yr)': 'Bicycle theft (avg/yr)',
|
||
'Drugs (avg/yr)': 'Drugs (avg/yr)',
|
||
'Possession of weapons (avg/yr)': 'Possession of weapons (avg/yr)',
|
||
'Public order (avg/yr)': 'Public order (avg/yr)',
|
||
'Other crime (avg/yr)': 'Other crime (avg/yr)',
|
||
|
||
// ─ Feature names (Demographics) ─
|
||
'Median age': 'Median age',
|
||
'% White': '% White',
|
||
'% South Asian': '% South Asian',
|
||
'% Black': '% Black',
|
||
'% East Asian': '% East Asian',
|
||
'% Mixed': '% Mixed',
|
||
'% Other': '% Other',
|
||
|
||
// ─ Feature names (Politics) ─
|
||
'Voter turnout (%)': 'Voter turnout (%)',
|
||
'% Labour': '% Labour',
|
||
'% Conservative': '% Conservative',
|
||
'% Liberal Democrat': '% Liberal Democrat',
|
||
'% Reform UK': '% Reform UK',
|
||
'% Green': '% Green',
|
||
'% Other parties': '% Other parties',
|
||
|
||
// ─ Feature names (Amenities) ─
|
||
'Distance to nearest park (km)': 'Distance to nearest park (km)',
|
||
'Number of parks within 1km': 'Number of parks within 1km',
|
||
'Number of restaurants within 2km': 'Number of restaurants within 2km',
|
||
'Number of grocery shops and supermarkets within 2km':
|
||
'Number of grocery shops and supermarkets within 2km',
|
||
'Noise (dB)': 'Noise (dB)',
|
||
'Max available download speed (Mbps)': 'Max available download speed (Mbps)',
|
||
|
||
// ─ Enum values ─
|
||
Detached: 'Detached',
|
||
'Semi-Detached': 'Semi-Detached',
|
||
Terraced: 'Terraced',
|
||
'Flats/Maisonettes': 'Flats/Maisonettes',
|
||
Other: 'Other',
|
||
Freehold: 'Freehold',
|
||
Leasehold: 'Leasehold',
|
||
Yes: 'Yes',
|
||
No: 'No',
|
||
|
||
// ─ Stacked chart labels ─
|
||
'Serious crime': 'Serious crime',
|
||
'Minor crime': 'Minor crime',
|
||
'Ethnic composition': 'Ethnic composition',
|
||
'Political vote share': 'Political vote share',
|
||
|
||
// ─ POI group names ─
|
||
'Public Transport': 'Public Transport',
|
||
Leisure: 'Leisure',
|
||
Health: 'Health',
|
||
'Emergency Services': 'Emergency Services',
|
||
Groceries: 'Groceries',
|
||
'Local Businesses': 'Local Businesses',
|
||
Culture: 'Culture',
|
||
Services: 'Services',
|
||
Shops: 'Shops',
|
||
|
||
// ─ POI categories ─
|
||
Airport: 'Airport',
|
||
Ferry: 'Ferry',
|
||
'Rail station': 'Rail station',
|
||
'Bus stop': 'Bus stop',
|
||
'Bus station': 'Bus station',
|
||
'Taxi rank': 'Taxi rank',
|
||
'Tube station': 'Tube station',
|
||
Café: 'Café',
|
||
Restaurant: 'Restaurant',
|
||
Pub: 'Pub',
|
||
Bar: 'Bar',
|
||
'Fast Food': 'Fast Food',
|
||
Nightclub: 'Nightclub',
|
||
Cinema: 'Cinema',
|
||
Theatre: 'Theatre',
|
||
'Live Music & Events': 'Live Music & Events',
|
||
Park: 'Park',
|
||
Playground: 'Playground',
|
||
'Sports Centre': 'Sports Centre',
|
||
Entertainment: 'Entertainment',
|
||
Supermarket: 'Supermarket',
|
||
'Convenience Store': 'Convenience Store',
|
||
Bakery: 'Bakery',
|
||
'Butcher & Fishmonger': 'Butcher & Fishmonger',
|
||
Greengrocer: 'Greengrocer',
|
||
'Off-Licence': 'Off-Licence',
|
||
'Deli & Specialty': 'Deli & Specialty',
|
||
'Fashion & Clothing': 'Fashion & Clothing',
|
||
Electronics: 'Electronics',
|
||
'Charity Shop': 'Charity Shop',
|
||
'DIY & Hardware': 'DIY & Hardware',
|
||
'Home & Garden': 'Home & Garden',
|
||
Bookshop: 'Bookshop',
|
||
'Pet Shop': 'Pet Shop',
|
||
'Sports & Outdoor': 'Sports & Outdoor',
|
||
Newsagent: 'Newsagent',
|
||
'Department Store': 'Department Store',
|
||
'Gift & Hobby': 'Gift & Hobby',
|
||
'Specialist Shop': 'Specialist Shop',
|
||
'Hairdresser & Beauty': 'Hairdresser & Beauty',
|
||
'Gym & Fitness': 'Gym & Fitness',
|
||
'Dry Cleaner & Laundry': 'Dry Cleaner & Laundry',
|
||
'Car Services': 'Car Services',
|
||
'Post Office': 'Post Office',
|
||
'Vet & Pet Care': 'Vet & Pet Care',
|
||
Bank: 'Bank',
|
||
'Travel Agent': 'Travel Agent',
|
||
Police: 'Police',
|
||
'Fire Station': 'Fire Station',
|
||
'Ambulance Station': 'Ambulance Station',
|
||
'GP Surgery': 'GP Surgery',
|
||
Dentist: 'Dentist',
|
||
Pharmacy: 'Pharmacy',
|
||
'Hospital & Clinic': 'Hospital & Clinic',
|
||
Optician: 'Optician',
|
||
Physiotherapy: 'Physiotherapy',
|
||
'Counselling & Therapy': 'Counselling & Therapy',
|
||
'Care Home': 'Care Home',
|
||
'Medical & Mobility': 'Medical & Mobility',
|
||
Museum: 'Museum',
|
||
Gallery: 'Gallery',
|
||
Library: 'Library',
|
||
'Place of Worship': 'Place of Worship',
|
||
'Arts Centre': 'Arts Centre',
|
||
Zoo: 'Zoo',
|
||
'Tourist Attraction': 'Tourist Attraction',
|
||
School: 'School',
|
||
Hotel: 'Hotel',
|
||
'Local Business': 'Local Business',
|
||
Offices: 'Offices',
|
||
'EV Charging': 'EV Charging',
|
||
'Fuel Station': 'Fuel Station',
|
||
'Community Centre': 'Community Centre',
|
||
|
||
// ─ Suffixes (used in formatters) ─
|
||
'/mo': '/mo',
|
||
'/yr': '/yr',
|
||
' sqm': ' sqm',
|
||
' km': ' km',
|
||
' m': ' m',
|
||
' dB': ' dB',
|
||
' years': ' years',
|
||
' rooms': ' rooms',
|
||
},
|
||
} as const;
|
||
|
||
export default en;
|
||
|
||
/**
|
||
* Recursively maps a translation object’s leaf values to `string`,
|
||
* preserving the nested key structure. Used to type-check non-English
|
||
* locale files: they must have exactly the same keys as English,
|
||
* but with their own string values.
|
||
*
|
||
* Missing key -> TS error. Extra key -> TS error.
|
||
*/
|
||
export type DeepStringify<T> = {
|
||
[K in keyof T]: T[K] extends Record<string, unknown> ? DeepStringify<T[K]> : string;
|
||
};
|
||
|
||
export type Translations = DeepStringify<typeof en>;
|