..
This commit is contained in:
parent
ab688243d7
commit
463bd4c647
54 changed files with 13239 additions and 625 deletions
|
|
@ -4,7 +4,7 @@
|
||||||
"cell_type": "markdown",
|
"cell_type": "markdown",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"# Postcode Boundary Quality — Bank Station (1km radius)\n",
|
"# Postcode Boundary Quality: Bank Station (1km radius)\n",
|
||||||
"\n",
|
"\n",
|
||||||
"Compares postcode boundaries **before** and **after** greenspace/water subtraction."
|
"Compares postcode boundaries **before** and **after** greenspace/water subtraction."
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -390,14 +390,14 @@
|
||||||
"name": "stdout",
|
"name": "stdout",
|
||||||
"output_type": "stream",
|
"output_type": "stream",
|
||||||
"text": [
|
"text": [
|
||||||
"PROPERTY_TYPE — 5 distinct values:\n",
|
"PROPERTY_TYPE: 5 distinct values:\n",
|
||||||
" House 17,437,884\n",
|
" House 17,437,884\n",
|
||||||
" Flat 8,236,696\n",
|
" Flat 8,236,696\n",
|
||||||
" Bungalow 2,448,109\n",
|
" Bungalow 2,448,109\n",
|
||||||
" Maisonette 710,695\n",
|
" Maisonette 710,695\n",
|
||||||
" Park home 14,577\n",
|
" Park home 14,577\n",
|
||||||
"\n",
|
"\n",
|
||||||
"BUILT_FORM — 9 distinct values:\n",
|
"BUILT_FORM: 9 distinct values:\n",
|
||||||
" Semi-Detached 8,777,318\n",
|
" Semi-Detached 8,777,318\n",
|
||||||
" Mid-Terrace 7,972,697\n",
|
" Mid-Terrace 7,972,697\n",
|
||||||
" Detached 6,428,144\n",
|
" Detached 6,428,144\n",
|
||||||
|
|
@ -414,7 +414,7 @@
|
||||||
"source": [
|
"source": [
|
||||||
"for col_name in [\"PROPERTY_TYPE\", \"BUILT_FORM\"]:\n",
|
"for col_name in [\"PROPERTY_TYPE\", \"BUILT_FORM\"]:\n",
|
||||||
" counts = scan().group_by(col_name).len().sort(\"len\", descending=True).collect()\n",
|
" counts = scan().group_by(col_name).len().sort(\"len\", descending=True).collect()\n",
|
||||||
" print(f\"{col_name} — {len(counts)} distinct values:\")\n",
|
" print(f\"{col_name}: {len(counts)} distinct values:\")\n",
|
||||||
" for row in counts.iter_rows(named=True):\n",
|
" for row in counts.iter_rows(named=True):\n",
|
||||||
" print(f\" {row[col_name]!s:30s} {row['len']:>12,}\")\n",
|
" print(f\" {row[col_name]!s:30s} {row['len']:>12,}\")\n",
|
||||||
" print()"
|
" print()"
|
||||||
|
|
|
||||||
|
|
@ -5,9 +5,9 @@
|
||||||
"id": "21f27a93",
|
"id": "21f27a93",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"# Online Buy Listings — data quality & cleanup\n",
|
"# Online Buy Listings: data quality & cleanup\n",
|
||||||
"\n",
|
"\n",
|
||||||
"Source: `finder/data/online_listings_buy.parquet` — ~112k UK *for-sale* property listings\n",
|
"Source: `finder/data/online_listings_buy.parquet`, ~112k UK *for-sale* property listings\n",
|
||||||
"(Greater London) scraped from **Rightmove**, **OnTheMarket** and **Zoopla** and merged by the\n",
|
"(Greater London) scraped from **Rightmove**, **OnTheMarket** and **Zoopla** and merged by the\n",
|
||||||
"`finder` pipeline (`transform.py` / `onthemarket.py` / `zoopla.py` → `storage.py`).\n",
|
"`finder` pipeline (`transform.py` / `onthemarket.py` / `zoopla.py` → `storage.py`).\n",
|
||||||
"\n",
|
"\n",
|
||||||
|
|
@ -453,7 +453,7 @@
|
||||||
"id": "7ea9293c",
|
"id": "7ea9293c",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"### 3.1 · 🔴 Mislabeled column — `Number of bedrooms & living rooms` is actually `Bedrooms + Bathrooms`\n",
|
"### 3.1 · 🔴 Mislabeled column: `Number of bedrooms & living rooms` is actually `Bedrooms + Bathrooms`\n",
|
||||||
"\n",
|
"\n",
|
||||||
"The column name promises *living rooms / receptions*, but `storage.py` recomputes it as\n",
|
"The column name promises *living rooms / receptions*, but `storage.py` recomputes it as\n",
|
||||||
"`Bedrooms + Bathrooms` for **every** row of **every** portal (Zoopla's `+ receptions` line is\n",
|
"`Bedrooms + Bathrooms` for **every** row of **every** portal (Zoopla's `+ receptions` line is\n",
|
||||||
|
|
@ -529,7 +529,7 @@
|
||||||
"### 3.2 · 🔴 Price integrity\n",
|
"### 3.2 · 🔴 Price integrity\n",
|
||||||
"\n",
|
"\n",
|
||||||
"- **Shared-ownership / part-buy** listings store the *share* price as `Asking price`, not full value\n",
|
"- **Shared-ownership / part-buy** listings store the *share* price as `Asking price`, not full value\n",
|
||||||
" (median ~£146k vs ~£550k) — corrupts any price / £-per-sqm aggregate.\n",
|
" (median ~£146k vs ~£550k). Corrupts any price / £-per-sqm aggregate.\n",
|
||||||
"- **38% of rows carry a non-firm qualifier** (Guide / Offers Over / OIEO / From / Shared); `Asking price`\n",
|
"- **38% of rows carry a non-firm qualifier** (Guide / Offers Over / OIEO / From / Shared); `Asking price`\n",
|
||||||
" is stored identically regardless.\n",
|
" is stored identically regardless.\n",
|
||||||
"- A `<£10k` tail of auction land/garage lots + two `£1` placeholders; 364 nulls (price ≤ 0 → null)."
|
"- A `<£10k` tail of auction land/garage lots + two `£1` placeholders; 364 nulls (price ≤ 0 → null)."
|
||||||
|
|
@ -657,7 +657,7 @@
|
||||||
"\n",
|
"\n",
|
||||||
"- ~49% of `Total floor area (sqm)` is null (OnTheMarket ~87%).\n",
|
"- ~49% of `Total floor area (sqm)` is null (OnTheMarket ~87%).\n",
|
||||||
"- **Impossible tiny areas**: rows under 20 m² with ≥2 bedrooms (single-room dimensions parsed as total).\n",
|
"- **Impossible tiny areas**: rows under 20 m² with ≥2 bedrooms (single-room dimensions parsed as total).\n",
|
||||||
"- **Suspiciously large areas** (>400 m²) — likely sq ft never converted to m².\n",
|
"- **Suspiciously large areas** (>400 m²): likely sq ft never converted to m².\n",
|
||||||
"- `Asking price per sqm` is mechanically correct but faithfully amplifies bad areas (max £410,959/m²)."
|
"- `Asking price per sqm` is mechanically correct but faithfully amplifies bad areas (max £410,959/m²)."
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
@ -755,7 +755,7 @@
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"source": [
|
"source": [
|
||||||
"# Floor area vs bedrooms — red points are physically impossible (area < beds * 8 m²)\n",
|
"# Floor area vs bedrooms: red points are physically impossible (area < beds * 8 m²)\n",
|
||||||
"s = raw.filter(fa.is_not_null() & (fa < 160)).select(\"Bedrooms\", \"Total floor area (sqm)\")\n",
|
"s = raw.filter(fa.is_not_null() & (fa < 160)).select(\"Bedrooms\", \"Total floor area (sqm)\")\n",
|
||||||
"rng = np.random.default_rng(0)\n",
|
"rng = np.random.default_rng(0)\n",
|
||||||
"xb = s[\"Bedrooms\"].to_numpy().astype(float)\n",
|
"xb = s[\"Bedrooms\"].to_numpy().astype(float)\n",
|
||||||
|
|
@ -946,7 +946,7 @@
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"source": [
|
"source": [
|
||||||
"# Listings by provider (downsampled) — shows London footprint + centroid clusters\n",
|
"# Listings by provider (downsampled): shows London footprint + centroid clusters\n",
|
||||||
"g = raw.sample(min(25_000, raw.height), seed=0).select(\"lat\", \"lon\", \"provider\")\n",
|
"g = raw.sample(min(25_000, raw.height), seed=0).select(\"lat\", \"lon\", \"provider\")\n",
|
||||||
"colors = {\"Rightmove\": \"#2563eb\", \"OnTheMarket\": \"#16a34a\", \"Zoopla\": \"#dc2626\"}\n",
|
"colors = {\"Rightmove\": \"#2563eb\", \"OnTheMarket\": \"#16a34a\", \"Zoopla\": \"#dc2626\"}\n",
|
||||||
"fig, ax = plt.subplots(figsize=(8, 7))\n",
|
"fig, ax = plt.subplots(figsize=(8, 7))\n",
|
||||||
|
|
@ -971,7 +971,7 @@
|
||||||
"\n",
|
"\n",
|
||||||
"No cross-source identity resolution: the same physical property appears across portals, and is\n",
|
"No cross-source identity resolution: the same physical property appears across portals, and is\n",
|
||||||
"re-listed multiple times within a portal (especially Zoopla). `UPRN` (Zoopla-only, 1.8% coverage)\n",
|
"re-listed multiple times within a portal (especially Zoopla). `UPRN` (Zoopla-only, 1.8% coverage)\n",
|
||||||
"is not 1:1 — 405 UPRNs repeat up to 7×, breaking the intended exact EPC join."
|
"is not 1:1. 405 UPRNs repeat up to 7×, breaking the intended exact EPC join."
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -1024,7 +1024,7 @@
|
||||||
"- `Listing status` is a constant `\"For sale\"` (dead column).\n",
|
"- `Listing status` is a constant `\"For sale\"` (dead column).\n",
|
||||||
"- `Property sub-type` has 79 values with portal-spelling variants (`Apartment`↔`Flat`, `X House`↔`X`, …).\n",
|
"- `Property sub-type` has 79 values with portal-spelling variants (`Apartment`↔`Flat`, `X House`↔`X`, …).\n",
|
||||||
"- `Price qualifier` has case-only duplicate pairs (Rightmove TitleCase vs OTM sentence-case).\n",
|
"- `Price qualifier` has case-only duplicate pairs (Rightmove TitleCase vs OTM sentence-case).\n",
|
||||||
"- Missing values are encoded inconsistently — empty-string in some columns, `null` in others."
|
"- Missing values are encoded inconsistently: empty-string in some columns, `null` in others."
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -1155,7 +1155,7 @@
|
||||||
"### 3.8 · 🔴/🟡 Listing date\n",
|
"### 3.8 · 🔴/🟡 Listing date\n",
|
||||||
"\n",
|
"\n",
|
||||||
"`Listing date` is **null for 100% of OnTheMarket & Zoopla** (Rightmove-only `firstVisibleDate`), so any\n",
|
"`Listing date` is **null for 100% of OnTheMarket & Zoopla** (Rightmove-only `firstVisibleDate`), so any\n",
|
||||||
"recency analysis is biased to 82% of the data — and it reaches back to **2011** in a live for-sale set."
|
"recency analysis is biased to 82% of the data, and it reaches back to **2011** in a live for-sale set."
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -1293,7 +1293,7 @@
|
||||||
"id": "2491e545",
|
"id": "2491e545",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"**Step A** — drop dead/redundant columns, normalise empty-string → null, canonicalise `Price qualifier`, derive `price_basis` + `is_shared_ownership`."
|
"**Step A**: drop dead/redundant columns, normalise empty-string → null, canonicalise `Price qualifier`, derive `price_basis` + `is_shared_ownership`."
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -1392,7 +1392,7 @@
|
||||||
"id": "58767c84",
|
"id": "58767c84",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"**Step B** — floor-area sanity (null impossibly-small, flag suspiciously-large) + recompute `Asking price per sqm` (excluding shared-ownership); null sentinel-`0` beds/baths for dwellings; canonicalise sub-types; add `is_residential`, `location_precision`; strip fake unit postcodes from outcode-only rows."
|
"**Step B**: floor-area sanity (null impossibly-small, flag suspiciously-large) + recompute `Asking price per sqm` (excluding shared-ownership); null sentinel-`0` beds/baths for dwellings; canonicalise sub-types; add `is_residential`, `location_precision`; strip fake unit postcodes from outcode-only rows."
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -1481,7 +1481,7 @@
|
||||||
"id": "33e81cf5",
|
"id": "33e81cf5",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"**Step C** — de-duplicate to one row per physical property. Heuristic key: `(lat, lon, Asking price, Bedrooms)`, keeping the most-recently-listed row. This collapses both cross-portal and intra-portal duplicates; `raw` is retained for provenance."
|
"**Step C**: de-duplicate to one row per physical property. Heuristic key: `(lat, lon, Asking price, Bedrooms)`, keeping the most-recently-listed row. This collapses both cross-portal and intra-portal duplicates; `raw` is retained for provenance."
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -1554,7 +1554,7 @@
|
||||||
"id": "7d17dd05",
|
"id": "7d17dd05",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"## 5 · After cleanup — re-show the stats"
|
"## 5 · After cleanup: re-show the stats"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -1737,7 +1737,7 @@
|
||||||
"id": "0a16d168",
|
"id": "0a16d168",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"**Missingness after cleanup** — beds/baths now legitimately null where unknown; empty-strings gone; per-sqm follows cleaned area:"
|
"**Missingness after cleanup**: beds/baths now legitimately null where unknown; empty-strings gone; per-sqm follows cleaned area:"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -1924,7 +1924,7 @@
|
||||||
"id": "e833c578",
|
"id": "e833c578",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"**Categoricals normalised** — sub-type variants collapsed, qualifier casing merged:"
|
"**Categoricals normalised**: sub-type variants collapsed, qualifier casing merged:"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -2007,7 +2007,7 @@
|
||||||
"id": "94ac0585",
|
"id": "94ac0585",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"**Before/after — key metrics chart:**"
|
"**Before/after key metrics chart:**"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -2076,7 +2076,7 @@
|
||||||
"\n",
|
"\n",
|
||||||
"- **`clean` keeps every row** (issues are flagged, not dropped) so it stays comparable to `raw`; use the\n",
|
"- **`clean` keeps every row** (issues are flagged, not dropped) so it stays comparable to `raw`; use the\n",
|
||||||
" `is_residential` / `is_shared_ownership` / `floor_area_suspect_*` / `location_precision` flags to filter.\n",
|
" `is_residential` / `is_shared_ownership` / `floor_area_suspect_*` / `location_precision` flags to filter.\n",
|
||||||
"- **Shared-ownership full prices cannot be recovered** here — those rows are flagged and excluded from\n",
|
"- **Shared-ownership full prices cannot be recovered** here: those rows are flagged and excluded from\n",
|
||||||
" `£/sqm`, but their `Asking price` is still a share. Likewise **suspiciously-large areas are flagged,\n",
|
" `£/sqm`, but their `Asking price` is still a share. Likewise **suspiciously-large areas are flagged,\n",
|
||||||
" not auto-converted** from sq ft (the conversion factor isn't certain per-row).\n",
|
" not auto-converted** from sq ft (the conversion factor isn't certain per-row).\n",
|
||||||
"- **De-dup is heuristic** (`lat,lon,price,beds`); it can over-collapse distinct units sharing a\n",
|
"- **De-dup is heuristic** (`lat,lon,price,beds`); it can over-collapse distinct units sharing a\n",
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@
|
||||||
"id": "46a28f40",
|
"id": "46a28f40",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"# School catchment model — the working\n",
|
"# School catchment model: the working\n",
|
||||||
"\n",
|
"\n",
|
||||||
"The postcode features **\"Good+/Outstanding primary/secondary school catchments\"** count the\n",
|
"The postcode features **\"Good+/Outstanding primary/secondary school catchments\"** count the\n",
|
||||||
"rated state schools whose modelled *admission cutoff radius* covers a postcode. This notebook\n",
|
"rated state schools whose modelled *admission cutoff radius* covers a postcode. This notebook\n",
|
||||||
|
|
@ -17,7 +17,7 @@
|
||||||
"Pupil Database. What *is* public: where every school is and how many pupils it has (GIAS), how\n",
|
"Pupil Database. What *is* public: where every school is and how many pupils it has (GIAS), how\n",
|
||||||
"many children live where (Census 2021), and the fact that most English admissions are run as\n",
|
"many children live where (Census 2021), and the fact that most English admissions are run as\n",
|
||||||
"**deferred acceptance with distance tie-breaks**. That is enough to *solve for* each school's\n",
|
"**deferred acceptance with distance tie-breaks**. That is enough to *solve for* each school's\n",
|
||||||
"cutoff distance — the \"last distance offered\" that councils publish each offer day — and those\n",
|
"cutoff distance (the \"last distance offered\" that councils publish each offer day) and those\n",
|
||||||
"published figures give us ground truth to calibrate against.\n",
|
"published figures give us ground truth to calibrate against.\n",
|
||||||
"\n",
|
"\n",
|
||||||
"The production code is `pipeline/transform/school_catchments.py`; the calibration harness is\n",
|
"The production code is `pipeline/transform/school_catchments.py`; the calibration harness is\n",
|
||||||
|
|
@ -81,14 +81,14 @@
|
||||||
"id": "e13f2bc4",
|
"id": "e13f2bc4",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"## 1. Supply — schools and their phase fill targets\n",
|
"## 1. Supply: schools and their phase fill targets\n",
|
||||||
"\n",
|
"\n",
|
||||||
"Every open, **non-selective** state school (academies, LA-maintained, free schools) takes part.\n",
|
"Every open, **non-selective** state school (academies, LA-maintained, free schools) takes part.\n",
|
||||||
"Grammar schools are excluded outright: their intakes are test-based and region-wide, so any\n",
|
"Grammar schools are excluded outright: their intakes are test-based and region-wide, so any\n",
|
||||||
"distance-based catchment would be fabricated. Independent, special and Welsh schools don't\n",
|
"distance-based catchment would be fabricated. Independent, special and Welsh schools don't\n",
|
||||||
"admit by distance either.\n",
|
"admit by distance either.\n",
|
||||||
"\n",
|
"\n",
|
||||||
"A school's *fill target* is `max(capacity, headcount)` — an over-full school keeps its\n",
|
"A school's *fill target* is `max(capacity, headcount)`: an over-full school keeps its\n",
|
||||||
"demonstrated size, an under-full one can admit up to capacity (the feature asks \"would you get\n",
|
"demonstrated size, an under-full one can admit up to capacity (the feature asks \"would you get\n",
|
||||||
"a place?\", not \"does a pupil already live there?\"). The target is prorated over the cohort ages\n",
|
"a place?\", not \"does a pupil already live there?\"). The target is prorated over the cohort ages\n",
|
||||||
"the school teaches, parsed from its age range: nursery years weigh 0.5 and sixth-form years 0.6,\n",
|
"the school teaches, parsed from its age range: nursery years weigh 0.5 and sixth-form years 0.6,\n",
|
||||||
|
|
@ -182,16 +182,16 @@
|
||||||
"id": "2905514f",
|
"id": "2905514f",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"## 2. Demand — children per postcode\n",
|
"## 2. Demand: children per postcode\n",
|
||||||
"\n",
|
"\n",
|
||||||
"Census 2021 (TS007A) gives children by five-year band per LSOA. Bands don't align with school\n",
|
"Census 2021 (TS007A) gives children by five-year band per LSOA. Bands don't align with school\n",
|
||||||
"phases, so phases take fractional shares — primary (ages 4–10) = ⅕·(0–4) + (5–9) + ⅕·(10–14);\n",
|
"phases, so phases take fractional shares: primary (ages 4–10) = ⅕·(0–4) + (5–9) + ⅕·(10–14);\n",
|
||||||
"secondary (11–15) = ⅘·(10–14) + ⅕·(15–19) — and each LSOA's total is split evenly across its\n",
|
"secondary (11–15) = ⅘·(10–14) + ⅕·(15–19), and each LSOA's total is split evenly across its\n",
|
||||||
"live postcodes (LSOAs hold ~40 postcodes, small enough at catchment scale).\n",
|
"live postcodes (LSOAs hold ~40 postcodes, small enough at catchment scale).\n",
|
||||||
"\n",
|
"\n",
|
||||||
"Not all of those children compete for state places: births fell ~10% between 2016 and 2021\n",
|
"Not all of those children compete for state places: births fell ~10% between 2016 and 2021\n",
|
||||||
"(exactly the gap between the census stock and the cohorts reaching Reception by mid-decade) and\n",
|
"(exactly the gap between the census stock and the cohorts reaching Reception by mid-decade) and\n",
|
||||||
"~7% attend independent schools or are home-educated. `DEMAND_SCALE = 0.8` absorbs both — without\n",
|
"~7% attend independent schools or are home-educated. `DEMAND_SCALE = 0.8` absorbs both, without\n",
|
||||||
"it, modelled cutoffs run systematically tight and half the genuinely undersubscribed schools\n",
|
"it, modelled cutoffs run systematically tight and half the genuinely undersubscribed schools\n",
|
||||||
"look full (this was the single biggest correction the ground truth forced; see §7).\n"
|
"look full (this was the single biggest correction the ground truth forced; see §7).\n"
|
||||||
]
|
]
|
||||||
|
|
@ -241,18 +241,18 @@
|
||||||
"id": "20d44b21",
|
"id": "20d44b21",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"## 3. Preferences — grade bonuses and logit choice\n",
|
"## 3. Preferences: grade bonuses and logit choice\n",
|
||||||
"\n",
|
"\n",
|
||||||
"Families don't just pick the nearest school. Two ingredients:\n",
|
"Families don't just pick the nearest school. Two ingredients:\n",
|
||||||
"\n",
|
"\n",
|
||||||
"- **Grade bonus** — a school's *effective distance* is its real distance minus an Ofsted-grade\n",
|
"- **Grade bonus**: a school's *effective distance* is its real distance minus an Ofsted-grade\n",
|
||||||
" bonus (+0.6 km Outstanding, +0.3 km Good, −0.3/−0.6 km for grade 3/4). A family accepts that\n",
|
" bonus (+0.6 km Outstanding, +0.3 km Good, −0.3/−0.6 km for grade 3/4). A family accepts that\n",
|
||||||
" much extra travel for a better school.\n",
|
" much extra travel for a better school.\n",
|
||||||
"- **Logit smearing** — even so, not everyone at a postcode ranks the same school first. Each\n",
|
"- **Logit smearing**: even so, not everyone at a postcode ranks the same school first. Each\n",
|
||||||
" postcode's children split across the nearby feasible schools with weights\n",
|
" postcode's children split across the nearby feasible schools with weights\n",
|
||||||
" `softmax(−effective_distance / τ)`, τ = 0.3 km. This matters more than it looks: with\n",
|
" `softmax(−effective_distance / τ)`, τ = 0.3 km. This matters more than it looks: with\n",
|
||||||
" deterministic choice a popular school fills entirely from its nearest band, putting its\n",
|
" deterministic choice a popular school fills entirely from its nearest band, putting its\n",
|
||||||
" marginal admitted child — and therefore its cutoff — unrealistically close (about 2× too\n",
|
" marginal admitted child (and therefore its cutoff) unrealistically close (about 2× too\n",
|
||||||
" tight against published cutoffs).\n",
|
" tight against published cutoffs).\n",
|
||||||
"\n",
|
"\n",
|
||||||
"Below: the share of applications a Good school captures against an unrated neighbour 1 km away.\n"
|
"Below: the share of applications a Good school captures against an unrated neighbour 1 km away.\n"
|
||||||
|
|
@ -306,7 +306,7 @@
|
||||||
"id": "04bcfbcf",
|
"id": "04bcfbcf",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"## 4. The equilibrium — cutoff dynamics\n",
|
"## 4. The equilibrium: cutoff dynamics\n",
|
||||||
"\n",
|
"\n",
|
||||||
"English admissions run deferred acceptance with distance priority; in a continuum economy that\n",
|
"English admissions run deferred acceptance with distance priority; in a continuum economy that\n",
|
||||||
"is equivalent to finding **market-clearing cutoff distances** (Azevedo & Leshno 2016). The solver:\n",
|
"is equivalent to finding **market-clearing cutoff distances** (Azevedo & Leshno 2016). The solver:\n",
|
||||||
|
|
@ -314,7 +314,7 @@
|
||||||
"1. start every school's cutoff at ∞;\n",
|
"1. start every school's cutoff at ∞;\n",
|
||||||
"2. every child unit applies to its preferred school(s) among those whose cutoff still covers it;\n",
|
"2. every child unit applies to its preferred school(s) among those whose cutoff still covers it;\n",
|
||||||
"3. every oversubscribed school tightens its cutoff to the distance of its **marginal admitted\n",
|
"3. every oversubscribed school tightens its cutoff to the distance of its **marginal admitted\n",
|
||||||
" child** — exactly the published \"last distance offered\";\n",
|
" child**, exactly the published \"last distance offered\";\n",
|
||||||
"4. repeat. Cutoffs only ever tighten, so the iteration converges to the deferred-acceptance\n",
|
"4. repeat. Cutoffs only ever tighten, so the iteration converges to the deferred-acceptance\n",
|
||||||
" outcome. Schools that never fill keep no binding cutoff; their radius falls back to the\n",
|
" outcome. Schools that never fill keep no binding cutoff; their radius falls back to the\n",
|
||||||
" distance within which the local child population would cover their fill target.\n",
|
" distance within which the local child population would cover their fill target.\n",
|
||||||
|
|
@ -533,7 +533,7 @@
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"The bimodal logic is visible: oversubscribed urban schools cluster well under 1 km while schools\n",
|
"The bimodal logic is visible: oversubscribed urban schools cluster well under 1 km while schools\n",
|
||||||
"with spare places reach further. A concrete slice — Cambridge and its villages. Circles are the\n",
|
"with spare places reach further. A concrete slice: Cambridge and its villages. Circles are the\n",
|
||||||
"calibrated catchment radii of Good+ primary schools: tight in town, wide in the villages.\n"
|
"calibrated catchment radii of Good+ primary schools: tight in town, wide in the villages.\n"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|
@ -600,11 +600,11 @@
|
||||||
"id": "25770af8",
|
"id": "25770af8",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"## 6. Calibration — modelled vs published cutoffs\n",
|
"## 6. Calibration: modelled vs published cutoffs\n",
|
||||||
"\n",
|
"\n",
|
||||||
"Councils publish each school's **last distance offered** in their allocation reports. We scraped\n",
|
"Councils publish each school's **last distance offered** in their allocation reports. We scraped\n",
|
||||||
"783 rows from nine authorities (Hertfordshire, Surrey, Stockport, Manchester, Bristol, Barnet,\n",
|
"783 rows from nine authorities (Hertfordshire, Surrey, Stockport, Manchester, Bristol, Barnet,\n",
|
||||||
"Redbridge, Ealing, Lambeth — `property-data/ground_truth/`), matched them to GIAS URNs, and\n",
|
"Redbridge, Ealing, Lambeth: `property-data/ground_truth/`), matched them to GIAS URNs, and\n",
|
||||||
"compare against the modelled radii. Faith schools are reported separately: their published\n",
|
"compare against the modelled radii. Faith schools are reported separately: their published\n",
|
||||||
"cutoff applies *within* faith priority, which a postcode model cannot see. \"All applicants\n",
|
"cutoff applies *within* faith priority, which a postcode model cannot see. \"All applicants\n",
|
||||||
"offered\" schools test whether the model agrees there was no binding cutoff at all.\n"
|
"offered\" schools test whether the model agrees there was no binding cutoff at all.\n"
|
||||||
|
|
@ -823,11 +823,11 @@
|
||||||
"source": [
|
"source": [
|
||||||
"## 8. Limitations\n",
|
"## 8. Limitations\n",
|
||||||
"\n",
|
"\n",
|
||||||
"- **Faith admissions are not modelled** — whether a faith school's catchment is open to a given\n",
|
"- **Faith admissions are not modelled**: whether a faith school's catchment is open to a given\n",
|
||||||
" family depends on the family. Their fit is accordingly worse (the orange triangles above).\n",
|
" family depends on the family. Their fit is accordingly worse (the orange triangles above).\n",
|
||||||
"- **Cutoffs are single-year snapshots**; real ones move with each cohort. The model is a\n",
|
"- **Cutoffs are single-year snapshots**; real ones move with each cohort. The model is a\n",
|
||||||
" steady-state estimate, not this September's number.\n",
|
" steady-state estimate, not this September's number.\n",
|
||||||
"- **Straight-line distance** is used throughout — it is the modal LA tie-break, but some\n",
|
"- **Straight-line distance** is used throughout. It is the modal LA tie-break, but some\n",
|
||||||
" authorities measure walking routes, and none of sibling priority, feeder schools or\n",
|
" authorities measure walking routes, and none of sibling priority, feeder schools or\n",
|
||||||
" designated catchment polygons are visible to the model.\n",
|
" designated catchment polygons are visible to the model.\n",
|
||||||
"- Census 2021 child counts age; `DEMAND_SCALE` should drift upward as the birth-rate dip works\n",
|
"- Census 2021 child counts age; `DEMAND_SCALE` should drift upward as the birth-rate dip works\n",
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@
|
||||||
"id": "db1n423kpm8",
|
"id": "db1n423kpm8",
|
||||||
"metadata": {},
|
"metadata": {},
|
||||||
"source": [
|
"source": [
|
||||||
"# Rightmove vs Home.co.uk — Source Overlap Analysis\n",
|
"# Rightmove vs Home.co.uk: Source Overlap Analysis\n",
|
||||||
"\n",
|
"\n",
|
||||||
"The property scraper collects listings from two sources: **Rightmove** and **home.co.uk**. During merging, cross-source deduplication removes home.co.uk listings that match a Rightmove listing by `(postcode, bedrooms, price)`.\n",
|
"The property scraper collects listings from two sources: **Rightmove** and **home.co.uk**. During merging, cross-source deduplication removes home.co.uk listings that match a Rightmove listing by `(postcode, bedrooms, price)`.\n",
|
||||||
"\n",
|
"\n",
|
||||||
|
|
@ -81,7 +81,7 @@
|
||||||
"\n",
|
"\n",
|
||||||
"The merged parquet contains already-deduplicated data. Home.co.uk listings that matched a Rightmove listing by `(postcode, bedrooms, price)` were removed during scraping. The log reported **2,220 cross-source dedupes** for BUY.\n",
|
"The merged parquet contains already-deduplicated data. Home.co.uk listings that matched a Rightmove listing by `(postcode, bedrooms, price)` were removed during scraping. The log reported **2,220 cross-source dedupes** for BUY.\n",
|
||||||
"\n",
|
"\n",
|
||||||
"So the true home.co.uk total was 20,650 (unique) + 2,220 (deduped) = **22,870** — giving a **9.7% overlap rate** on the outcodes that were scraped."
|
"So the true home.co.uk total was 20,650 (unique) + 2,220 (deduped) = **22,870**, giving a **9.7% overlap rate** on the outcodes that were scraped."
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -3164,7 +3164,7 @@
|
||||||
"---\n",
|
"---\n",
|
||||||
"## 3. Approximate Overlap via Fuzzy Matching\n",
|
"## 3. Approximate Overlap via Fuzzy Matching\n",
|
||||||
"\n",
|
"\n",
|
||||||
"The scraper deduped by exact `(postcode, bedrooms, price)`. We can also check for near-matches — properties at the same postcode with similar price that might be the same listing with slightly different data."
|
"The scraper deduped by exact `(postcode, bedrooms, price)`. We can also check for near-matches: properties at the same postcode with similar price that might be the same listing with slightly different data."
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -5246,7 +5246,7 @@
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"source": [
|
"source": [
|
||||||
"# Property sub-type comparison — top home.co.uk sub-types\n",
|
"# Property sub-type comparison: top home.co.uk sub-types\n",
|
||||||
"hk_subtypes = (\n",
|
"hk_subtypes = (\n",
|
||||||
" buy.filter(pl.col(\"source\") == \"Home.co.uk\")[\"Property sub-type\"]\n",
|
" buy.filter(pl.col(\"source\") == \"Home.co.uk\")[\"Property sub-type\"]\n",
|
||||||
" .value_counts()\n",
|
" .value_counts()\n",
|
||||||
|
|
@ -6304,7 +6304,7 @@
|
||||||
"---\n",
|
"---\n",
|
||||||
"## 7. What Does Home.co.uk Add?\n",
|
"## 7. What Does Home.co.uk Add?\n",
|
||||||
"\n",
|
"\n",
|
||||||
"Home.co.uk listings that passed the dedup filter are genuinely unique — not on Rightmove at all (or listed with different price/beds). What do they look like?"
|
"Home.co.uk listings that passed the dedup filter are genuinely unique: not on Rightmove at all (or listed with different price/beds). What do they look like?"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
@ -6409,13 +6409,13 @@
|
||||||
"output_type": "stream",
|
"output_type": "stream",
|
||||||
"text": [
|
"text": [
|
||||||
"\n",
|
"\n",
|
||||||
"Rightmove — days on market:\n",
|
"Rightmove: days on market:\n",
|
||||||
" Median: 74\n",
|
" Median: 74\n",
|
||||||
" Mean: 140\n",
|
" Mean: 140\n",
|
||||||
" P25: 26\n",
|
" P25: 26\n",
|
||||||
" P75: 189\n",
|
" P75: 189\n",
|
||||||
"\n",
|
"\n",
|
||||||
"Home.co.uk — days on market:\n",
|
"Home.co.uk: days on market:\n",
|
||||||
" Median: 156\n",
|
" Median: 156\n",
|
||||||
" Mean: 164\n",
|
" Mean: 164\n",
|
||||||
" P25: 50\n",
|
" P25: 50\n",
|
||||||
|
|
@ -6424,7 +6424,7 @@
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"source": [
|
"source": [
|
||||||
"# Listing age comparison — are home.co.uk listings older/newer?\n",
|
"# Listing age comparison: are home.co.uk listings older/newer?\n",
|
||||||
"import datetime\n",
|
"import datetime\n",
|
||||||
"\n",
|
"\n",
|
||||||
"now = datetime.datetime(2026, 3, 11)\n",
|
"now = datetime.datetime(2026, 3, 11)\n",
|
||||||
|
|
@ -6435,7 +6435,7 @@
|
||||||
"for src in [\"Rightmove\", \"Home.co.uk\"]:\n",
|
"for src in [\"Rightmove\", \"Home.co.uk\"]:\n",
|
||||||
" age = with_age.filter(pl.col(\"source\") == src)[\"days_on_market\"].drop_nulls()\n",
|
" age = with_age.filter(pl.col(\"source\") == src)[\"days_on_market\"].drop_nulls()\n",
|
||||||
" if len(age) > 0:\n",
|
" if len(age) > 0:\n",
|
||||||
" print(f\"\\n{src} — days on market:\")\n",
|
" print(f\"\\n{src}: days on market:\")\n",
|
||||||
" print(f\" Median: {age.median():.0f}\")\n",
|
" print(f\" Median: {age.median():.0f}\")\n",
|
||||||
" print(f\" Mean: {age.mean():.0f}\")\n",
|
" print(f\" Mean: {age.mean():.0f}\")\n",
|
||||||
" print(f\" P25: {age.quantile(0.25):.0f}\")\n",
|
" print(f\" P25: {age.quantile(0.25):.0f}\")\n",
|
||||||
|
|
@ -7388,7 +7388,7 @@
|
||||||
" Projected unique additions: ~274,584\n",
|
" Projected unique additions: ~274,584\n",
|
||||||
" Projected merged dataset: ~728,899 (60.4% increase)\n",
|
" Projected merged dataset: ~728,899 (60.4% increase)\n",
|
||||||
"\n",
|
"\n",
|
||||||
"⚠️ These are rough estimates — the covered outcodes may not be representative\n"
|
"⚠️ These are rough estimates: the covered outcodes may not be representative\n"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
|
@ -7425,7 +7425,7 @@
|
||||||
" f\" Projected merged dataset: ~{rm_buy + projected_unique:,} ({projected_unique / rm_buy * 100:.1f}% increase)\"\n",
|
" f\" Projected merged dataset: ~{rm_buy + projected_unique:,} ({projected_unique / rm_buy * 100:.1f}% increase)\"\n",
|
||||||
")\n",
|
")\n",
|
||||||
"print()\n",
|
"print()\n",
|
||||||
"print(\"⚠️ These are rough estimates — the covered outcodes may not be representative\")"
|
"print(\"⚠️ These are rough estimates: the covered outcodes may not be representative\")"
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -403120,7 +403120,7 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"title": {
|
"title": {
|
||||||
"text": "Bank — Median transit error (R5 − TfL easy), minutes"
|
"text": "Bank: Median transit error (R5 − TfL easy), minutes"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -403143,7 +403143,7 @@
|
||||||
" zoom=6,\n",
|
" zoom=6,\n",
|
||||||
" center={\"lat\": 51.5, \"lon\": -0.1},\n",
|
" center={\"lat\": 51.5, \"lon\": -0.1},\n",
|
||||||
" opacity=0.5,\n",
|
" opacity=0.5,\n",
|
||||||
" title=\"Bank — Median transit error (R5 − TfL easy), minutes\",\n",
|
" title=\"Bank: Median transit error (R5 − TfL easy), minutes\",\n",
|
||||||
" hover_data={\n",
|
" hover_data={\n",
|
||||||
" \"pcds\": True,\n",
|
" \"pcds\": True,\n",
|
||||||
" \"travel_minutes\": True,\n",
|
" \"travel_minutes\": True,\n",
|
||||||
|
|
@ -804061,7 +804061,7 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"title": {
|
"title": {
|
||||||
"text": "Bank — Best transit error (R5 − TfL quick), minutes"
|
"text": "Bank: Best transit error (R5 − TfL quick), minutes"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -804081,7 +804081,7 @@
|
||||||
" zoom=6,\n",
|
" zoom=6,\n",
|
||||||
" center={\"lat\": 51.5, \"lon\": -0.1},\n",
|
" center={\"lat\": 51.5, \"lon\": -0.1},\n",
|
||||||
" opacity=0.5,\n",
|
" opacity=0.5,\n",
|
||||||
" title=\"Bank — Best transit error (R5 − TfL quick), minutes\",\n",
|
" title=\"Bank: Best transit error (R5 − TfL quick), minutes\",\n",
|
||||||
" hover_data={\n",
|
" hover_data={\n",
|
||||||
" \"pcds\": True,\n",
|
" \"pcds\": True,\n",
|
||||||
" \"best_minutes\": True,\n",
|
" \"best_minutes\": True,\n",
|
||||||
|
|
@ -1204999,7 +1204999,7 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"title": {
|
"title": {
|
||||||
"text": "Bank — Absolute median transit error |R5 − TfL easy|, minutes"
|
"text": "Bank: Absolute median transit error |R5 − TfL easy|, minutes"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1205019,7 +1205019,7 @@
|
||||||
" zoom=6,\n",
|
" zoom=6,\n",
|
||||||
" center={\"lat\": 51.5, \"lon\": -0.1},\n",
|
" center={\"lat\": 51.5, \"lon\": -0.1},\n",
|
||||||
" opacity=0.5,\n",
|
" opacity=0.5,\n",
|
||||||
" title=\"Bank — Absolute median transit error |R5 − TfL easy|, minutes\",\n",
|
" title=\"Bank: Absolute median transit error |R5 − TfL easy|, minutes\",\n",
|
||||||
" hover_data={\n",
|
" hover_data={\n",
|
||||||
" \"pcds\": True,\n",
|
" \"pcds\": True,\n",
|
||||||
" \"travel_minutes\": True,\n",
|
" \"travel_minutes\": True,\n",
|
||||||
|
|
|
||||||
299
analysis/build_pages.py
Normal file
299
analysis/build_pages.py
Normal file
|
|
@ -0,0 +1,299 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Build the SEO page batch from findings.
|
||||||
|
|
||||||
|
Emits, from analysis/out/findings/*.json:
|
||||||
|
- frontend/public/<slug>/index.html: standalone, crawlable, on-brand landing page per finding
|
||||||
|
- frontend/public/cheaper-twins/index.html: a hub page linking every twin (internal-link mesh)
|
||||||
|
- server-rs/src/generated_data_pages.rs: registry the og_middleware consults (path/title/desc + the
|
||||||
|
screenshot query so the OG card shows the finding, not a blank map)
|
||||||
|
- frontend/public/sitemap.xml: data-page <url> entries inserted between markers (idempotent)
|
||||||
|
|
||||||
|
These are static files: webpack copies public/ -> dist/, and the server serves dist/<path>/index.html exactly
|
||||||
|
like the existing prerendered pages. og_middleware must register each path or it 404s. That registration is generated_data_pages.rs.
|
||||||
|
English-only by design (no 6-locale i18n), per the growth strategy.
|
||||||
|
|
||||||
|
Run: source .venv/bin/activate && python analysis/build_pages.py (after cheaper_twins.py + generate_findings.py)
|
||||||
|
"""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import html
|
||||||
|
import json
|
||||||
|
import urllib.parse
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
ROOT = Path(".")
|
||||||
|
FIND = Path("analysis/out/findings")
|
||||||
|
PUBLIC = ROOT / "frontend/public"
|
||||||
|
RUST = ROOT / "server-rs/src/generated_data_pages.rs"
|
||||||
|
SITEMAP = PUBLIC / "sitemap.xml"
|
||||||
|
SITE = "https://perfect-postcode.co.uk"
|
||||||
|
|
||||||
|
CSS = """
|
||||||
|
:root{color-scheme:light dark}
|
||||||
|
*{box-sizing:border-box}
|
||||||
|
body{margin:0;font-family:ui-sans-serif,system-ui,-apple-system,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;
|
||||||
|
color:#0b1220;background:#f7f5f0;line-height:1.6}
|
||||||
|
a{color:#0d9488}
|
||||||
|
.topbar{background:#0b1220;color:#e7ecf3;padding:.7rem 1.25rem;display:flex;justify-content:space-between;align-items:center}
|
||||||
|
.topbar a{color:#2dd4bf;text-decoration:none;font-weight:700}
|
||||||
|
.wrap{max-width:54rem;margin:0 auto;padding:0 1.25rem}
|
||||||
|
.hero{background:linear-gradient(#0b1220,#111a2e);color:#fff;padding:3rem 0 2.5rem}
|
||||||
|
.eyebrow{color:#2dd4bf;font-weight:700;text-transform:uppercase;letter-spacing:.05em;font-size:.8rem;margin:0 0 .5rem}
|
||||||
|
h1{font-size:2rem;line-height:1.15;margin:.2rem 0 .6rem}
|
||||||
|
.hook{color:#cbd5e1;font-size:1.15rem;margin:.5rem 0 1.4rem;max-width:42rem}
|
||||||
|
.big{font-size:3rem;font-weight:800;color:#2dd4bf;margin:.3rem 0}
|
||||||
|
.cta{display:inline-block;margin-top:.4rem;padding:.8rem 1.4rem;border-radius:.6rem;background:#f09a22;color:#0b1220;
|
||||||
|
font-weight:700;text-decoration:none;box-shadow:0 6px 20px rgba(122,57,5,.35)}
|
||||||
|
.cta:hover{background:#df8614}
|
||||||
|
table{width:100%;border-collapse:collapse;margin:1.5rem 0;background:#fff;border-radius:.6rem;overflow:hidden;
|
||||||
|
box-shadow:0 1px 3px rgba(0,0,0,.08)}
|
||||||
|
th,td{padding:.7rem .9rem;text-align:left;border-bottom:1px solid #ece8e0;font-size:.95rem}
|
||||||
|
thead th{background:#0b1220;color:#fff}
|
||||||
|
tbody tr:last-child td{border-bottom:0}
|
||||||
|
.val{font-variant-numeric:tabular-nums;font-weight:600}
|
||||||
|
.cheaper{color:#0d9488}
|
||||||
|
section{margin:2rem 0}
|
||||||
|
h2{font-size:1.3rem;margin:0 0 .6rem}
|
||||||
|
.note{font-size:.82rem;color:#6b7280;border-top:1px solid #e5e1d8;padding-top:1rem;margin-top:2rem}
|
||||||
|
.links{display:grid;gap:.6rem;grid-template-columns:repeat(auto-fit,minmax(15rem,1fr));margin:1rem 0}
|
||||||
|
.links a{display:block;background:#fff;border:1px solid #ece8e0;border-radius:.5rem;padding:.8rem 1rem;text-decoration:none;color:#0b1220}
|
||||||
|
.links a:hover{border-color:#5eead4}
|
||||||
|
.links b{color:#0d9488}
|
||||||
|
.cards{display:grid;gap:1rem;grid-template-columns:repeat(auto-fit,minmax(18rem,1fr))}
|
||||||
|
.card{background:#fff;border:1px solid #ece8e0;border-radius:.6rem;padding:1.1rem;text-decoration:none;color:#0b1220}
|
||||||
|
.card:hover{border-color:#5eead4}
|
||||||
|
.card .n{color:#0d9488;font-weight:800;font-size:1.4rem}
|
||||||
|
footer{color:#6b7280;font-size:.8rem;padding:2rem 0 3rem}
|
||||||
|
@media(prefers-color-scheme:dark){body{background:#0b1220;color:#e7ecf3}table{background:#13203a}
|
||||||
|
th,td{border-color:#223153}.card,.links a{background:#13203a;border-color:#223153;color:#e7ecf3}
|
||||||
|
.note{border-color:#223153;color:#9fb0c3}}
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
def esc(s) -> str:
|
||||||
|
return html.escape(str(s), quote=True)
|
||||||
|
|
||||||
|
|
||||||
|
def gbp(n) -> str:
|
||||||
|
return f"£{int(n):,}"
|
||||||
|
|
||||||
|
|
||||||
|
def rust_str(s: str) -> str:
|
||||||
|
return '"' + str(s).replace("\\", "\\\\").replace('"', '\\"') + '"'
|
||||||
|
|
||||||
|
|
||||||
|
def page_shell(title: str, desc: str, path: str, jsonld: dict, body: str) -> str:
|
||||||
|
return f"""<!doctype html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
<title>{esc(title)} | Perfect Postcode</title>
|
||||||
|
<meta name="description" content="{esc(desc)}" />
|
||||||
|
<link rel="canonical" href="{SITE}{esc(path)}" />
|
||||||
|
<style>{CSS}</style>
|
||||||
|
<script type="application/ld+json">{json.dumps(jsonld)}</script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="topbar"><a href="/">Perfect Postcode</a><a href="/?ref=twin">Open the map →</a></div>
|
||||||
|
{body}
|
||||||
|
<footer><div class="wrap">Sources: {esc(SOURCES)}. {esc(ATTRIB)}</div></footer>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
SOURCES = "HM Land Registry · EPC (DLUHC) · Ofsted · DfT · ONS · Police.uk"
|
||||||
|
ATTRIB = "Contains HM Land Registry data © Crown copyright and database right. Licensed under the Open Government Licence v3.0."
|
||||||
|
|
||||||
|
|
||||||
|
def breadcrumb(path: str, name: str) -> dict:
|
||||||
|
return {
|
||||||
|
"@context": "https://schema.org",
|
||||||
|
"@type": "BreadcrumbList",
|
||||||
|
"itemListElement": [
|
||||||
|
{"@type": "ListItem", "position": 1, "name": "Home", "item": SITE + "/"},
|
||||||
|
{"@type": "ListItem", "position": 2, "name": "Cheaper twins", "item": SITE + "/cheaper-twins"},
|
||||||
|
{"@type": "ListItem", "position": 3, "name": name, "item": SITE + path},
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def twin_html(f: dict, siblings: list[dict]) -> str:
|
||||||
|
p, w, s = f["pricey"], f["twin"], f["stats"]
|
||||||
|
typ = s["dominant_type"].lower()
|
||||||
|
map_url = f["map_url"]
|
||||||
|
rows = [
|
||||||
|
("Estimated £/m²", gbp(p["est_psqm"]), gbp(w["est_psqm"])),
|
||||||
|
("On a 90 m² home", gbp(p["est_psqm"] * 90), f'<span class="cheaper">{gbp(w["est_psqm"]*90)}</span>'),
|
||||||
|
("Dominant property type", esc(s["dominant_type"]), esc(s["dominant_type"])),
|
||||||
|
("Typical build era", f"~{s['build_year']}", f"~{s['build_year']}"),
|
||||||
|
("Good+ secondary catchments", f"{s['good_secondary_catchments']:.1f}", f"{s['good_secondary_catchments']:.1f}"),
|
||||||
|
("Nearest station", f"~{s['station_km']} km", f"~{s['station_km']} km"),
|
||||||
|
("Sales in sample (N)", f"{p['n']:,}", f"{w['n']:,}"),
|
||||||
|
]
|
||||||
|
table_rows = "\n".join(
|
||||||
|
f"<tr><td>{esc(k)}</td><td class='val'>{a}</td><td class='val'>{b}</td></tr>" for k, a, b in rows
|
||||||
|
)
|
||||||
|
prose = (
|
||||||
|
f"{esc(p['label'])} and {esc(w['label'])} sit about {s['distance_km']} km apart, share the same "
|
||||||
|
f"dominant housing ({typ}, typically built around {s['build_year']}), comparable good-school catchments "
|
||||||
|
f"and the same level of station access. Yet an equivalent home works out roughly "
|
||||||
|
f"<b>{s['gap_pct']:.0f}% (about {gbp(s['gap_on_90sqm'])} on a 90 m² property) cheaper in "
|
||||||
|
f"{esc(w['name'] or w['sector'])}</b>. On the measures that move price they are near-identical; the gap "
|
||||||
|
f"is mostly the premium attached to the better-known name."
|
||||||
|
)
|
||||||
|
sib_links = "\n".join(
|
||||||
|
f'<a href="{esc(sf["page_path"])}"><b>{esc(sf["title"].split(":")[0])}</b><br>{esc(sf["hook"])}</a>'
|
||||||
|
for sf in siblings
|
||||||
|
)
|
||||||
|
body = f"""
|
||||||
|
<div class="hero"><div class="wrap">
|
||||||
|
<p class="eyebrow">Cheaper twin · England</p>
|
||||||
|
<h1>{esc(f['title'])}</h1>
|
||||||
|
<div class="big">{esc(f['shocking_number'])} cheaper / m²</div>
|
||||||
|
<p class="hook">{esc(f['hook'])}</p>
|
||||||
|
<a class="cta" href="{esc(map_url)}">See both areas on the live map →</a>
|
||||||
|
</div></div>
|
||||||
|
<div class="wrap">
|
||||||
|
<table><thead><tr><th></th><th>{esc(p['label'])}</th><th>{esc(w['label'])}</th></tr></thead>
|
||||||
|
<tbody>{table_rows}</tbody></table>
|
||||||
|
<section><h2>The same life, one postcode cheaper</h2><p>{prose}</p></section>
|
||||||
|
<section><h2>How we worked this out</h2><p>{esc(f['methodology'])}</p></section>
|
||||||
|
<section><h2>Compare more areas</h2>
|
||||||
|
<div class="links">
|
||||||
|
<a href="/cheaper-twins"><b>All cheaper twins →</b><br>Browse every England name-premium pair we found.</a>
|
||||||
|
<a href="/postcode-checker"><b>Postcode checker →</b><br>Prices, crime, schools, broadband for any postcode.</a>
|
||||||
|
<a href="/property-price-map"><b>Property price map →</b><br>Rank England by what each £ buys.</a>
|
||||||
|
</div>
|
||||||
|
<div class="links">{sib_links}</div>
|
||||||
|
</section>
|
||||||
|
<p class="note">{esc(ATTRIB)} Figures are estimates derived from recorded sales and EPC floor areas, aggregated to postcode sector, not valuations, and not address-level.</p>
|
||||||
|
</div>
|
||||||
|
"""
|
||||||
|
return page_shell(f["title"], meta_desc(f), f["page_path"], breadcrumb(f["page_path"], f["title"].split(":")[0]), body)
|
||||||
|
|
||||||
|
|
||||||
|
def national_html(f: dict) -> str:
|
||||||
|
b, d = f["stats"]["best"], f["stats"]["dearest"]
|
||||||
|
body = f"""
|
||||||
|
<div class="hero"><div class="wrap">
|
||||||
|
<p class="eyebrow">England · value index</p>
|
||||||
|
<h1>{esc(f['title'])}</h1>
|
||||||
|
<div class="big">{esc(f['shocking_number'])}</div>
|
||||||
|
<p class="hook">{esc(f['hook'])}</p>
|
||||||
|
<a class="cta" href="{SITE}/?{esc(f['map_query'])}">Explore the value map →</a>
|
||||||
|
</div></div>
|
||||||
|
<div class="wrap">
|
||||||
|
<table><thead><tr><th>Sector</th><th>Est. £/m²</th><th>m² for £100k</th><th>N</th></tr></thead><tbody>
|
||||||
|
<tr><td>{esc(b['sector'])} (best value)</td><td class='val'>{gbp(b['est_psqm'])}</td><td class='val cheaper'>{b['sqm_per_100k']:.0f} m²</td><td class='val'>{b['n']:,}</td></tr>
|
||||||
|
<tr><td>{esc(d['sector'])} (dearest)</td><td class='val'>{gbp(d['est_psqm'])}</td><td class='val'>{d['sqm_per_100k']:.0f} m²</td><td class='val'>{d['n']:,}</td></tr>
|
||||||
|
</tbody></table>
|
||||||
|
<section><h2>How we worked this out</h2><p>{esc(f['methodology'])}</p></section>
|
||||||
|
<section><h2>More</h2><div class="links">
|
||||||
|
<a href="/cheaper-twins"><b>Cheaper twins →</b><br>Pairs of areas priced apart for the name, not the home.</a>
|
||||||
|
<a href="/postcode-checker"><b>Postcode checker →</b><br>Everything known about any postcode.</a>
|
||||||
|
</div></section>
|
||||||
|
<p class="note">{esc(ATTRIB)}</p>
|
||||||
|
</div>
|
||||||
|
"""
|
||||||
|
return page_shell(f["title"], meta_desc(f), f["page_path"], breadcrumb(f["page_path"], f["title"]), body)
|
||||||
|
|
||||||
|
|
||||||
|
def hub_html(twins: list[dict]) -> str:
|
||||||
|
cards = "\n".join(
|
||||||
|
f'<a class="card" href="{esc(f["page_path"])}"><div class="n">{esc(f["shocking_number"])}</div>'
|
||||||
|
f'<div>{esc(f["title"].split(":")[0])}</div></a>'
|
||||||
|
for f in twins
|
||||||
|
)
|
||||||
|
body = f"""
|
||||||
|
<div class="hero"><div class="wrap">
|
||||||
|
<p class="eyebrow">England</p>
|
||||||
|
<h1>Cheaper twins: pay for the home, not the name</h1>
|
||||||
|
<p class="hook">Pairs of neighbouring England postcodes that share a station, school catchment and build era,
|
||||||
|
but sell thousands apart because one name got bid up. Built from {len(twins)} verified pairs.</p>
|
||||||
|
<a class="cta" href="/?ref=twins-hub">Find your cheaper twin on the map →</a>
|
||||||
|
</div></div>
|
||||||
|
<div class="wrap">
|
||||||
|
<section><div class="cards">{cards}</div></section>
|
||||||
|
<p class="note">{esc(ATTRIB)}</p>
|
||||||
|
</div>
|
||||||
|
"""
|
||||||
|
jsonld = {"@context": "https://schema.org", "@type": "CollectionPage", "name": "Cheaper twins", "url": SITE + "/cheaper-twins"}
|
||||||
|
return page_shell("Cheaper twin postcodes in England", "Neighbouring England postcodes priced apart for the name, not the home. Find the cheaper twin of a pricier area.", "/cheaper-twins", jsonld, body)
|
||||||
|
|
||||||
|
|
||||||
|
def meta_desc(f: dict) -> str:
|
||||||
|
return (f.get("hook") or f.get("title"))[:155]
|
||||||
|
|
||||||
|
|
||||||
|
def write_page(path: str, content: str):
|
||||||
|
out = PUBLIC / path.strip("/") / "index.html"
|
||||||
|
out.parent.mkdir(parents=True, exist_ok=True)
|
||||||
|
out.write_text(content)
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
findings = [json.loads(p.read_text()) for p in sorted(FIND.glob("*.json"))]
|
||||||
|
twins = [f for f in findings if f["type"] == "cheaper_twin"]
|
||||||
|
nationals = [f for f in findings if f["type"] == "national_table"]
|
||||||
|
|
||||||
|
pages = [] # (path, title, description, screenshot_query)
|
||||||
|
for i, f in enumerate(twins):
|
||||||
|
siblings = [twins[(i + k) % len(twins)] for k in (1, 2, 3)][: max(0, len(twins) - 1)]
|
||||||
|
write_page(f["page_path"], twin_html(f, siblings))
|
||||||
|
pages.append((f["page_path"], f["title"], meta_desc(f), f["map_query"]))
|
||||||
|
for f in nationals:
|
||||||
|
write_page(f["page_path"], national_html(f))
|
||||||
|
pages.append((f["page_path"], f["title"], meta_desc(f), f["map_query"]))
|
||||||
|
|
||||||
|
write_page("/cheaper-twins", hub_html(twins))
|
||||||
|
pages.append(("/cheaper-twins", "Cheaper twin postcodes in England", "Neighbouring England postcodes priced apart for the name, not the home.", ""))
|
||||||
|
|
||||||
|
# Rust registry
|
||||||
|
entries = "\n".join(
|
||||||
|
f" DataPage {{ path: {rust_str(p)}, title: {rust_str(t)}, description: {rust_str(d)}, screenshot_query: {rust_str(q)} }},"
|
||||||
|
for p, t, d, q in pages
|
||||||
|
)
|
||||||
|
RUST.write_text(
|
||||||
|
"// @generated by analysis/build_pages.py. Do not edit by hand.\n"
|
||||||
|
"// Registers the data-driven growth pages so og_middleware serves them (not 404) with the\n"
|
||||||
|
"// right title/description and an OG card pointed at the finding's map view.\n\n"
|
||||||
|
"pub struct DataPage {\n"
|
||||||
|
" pub path: &'static str,\n"
|
||||||
|
" pub title: &'static str,\n"
|
||||||
|
" pub description: &'static str,\n"
|
||||||
|
" /// Map query string the OG screenshot should frame (empty = default map).\n"
|
||||||
|
" pub screenshot_query: &'static str,\n"
|
||||||
|
"}\n\n"
|
||||||
|
f"pub static DATA_PAGES: &[DataPage] = &[\n{entries}\n];\n\n"
|
||||||
|
"/// Look up a generated data page by request path (already trailing-slash-trimmed).\n"
|
||||||
|
"pub fn data_page(path: &str) -> Option<&'static DataPage> {\n"
|
||||||
|
" DATA_PAGES.iter().find(|p| p.path == path)\n"
|
||||||
|
"}\n"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Sitemap: replace the block between markers (idempotent), else insert before </urlset>.
|
||||||
|
start, end = "<!-- DATA_PAGES_START -->", "<!-- DATA_PAGES_END -->"
|
||||||
|
block = [start]
|
||||||
|
for p, *_ in pages:
|
||||||
|
block.append(f" <url>\n <loc>{SITE}{p}</loc>\n <changefreq>monthly</changefreq>\n <priority>0.7</priority>\n </url>")
|
||||||
|
block.append(end)
|
||||||
|
block_str = "\n".join(block)
|
||||||
|
sm = SITEMAP.read_text()
|
||||||
|
if start in sm and end in sm:
|
||||||
|
pre, rest = sm.split(start, 1)
|
||||||
|
_, post = rest.split(end, 1)
|
||||||
|
sm = pre + block_str + post
|
||||||
|
else:
|
||||||
|
sm = sm.replace("</urlset>", block_str + "\n</urlset>")
|
||||||
|
SITEMAP.write_text(sm)
|
||||||
|
|
||||||
|
print(f"Wrote {len(pages)} pages to {PUBLIC}/ (+ hub), {RUST}, and {len(pages)} sitemap entries.")
|
||||||
|
print("Pages:")
|
||||||
|
for p, t, *_ in pages:
|
||||||
|
print(f" {p}")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
221
analysis/build_video_scripts.py
Normal file
221
analysis/build_video_scripts.py
Normal file
|
|
@ -0,0 +1,221 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Turn each finding into a ready-to-film VIDEO KIT.
|
||||||
|
|
||||||
|
The founder films manually (screen-recording the live map), so this emits everything needed to shoot a
|
||||||
|
payoff-first "cheaper twin" video without writing anything: the hook, a beat-by-beat shot list tied to
|
||||||
|
applying each filter, a human-VO narration script, ≤6-word captions, the exact map URL to record, and the
|
||||||
|
YouTube title/description/chapters/tags/thumbnail. It also prints a storyboard spec (filters + suggested
|
||||||
|
city) for the optional automated render path (video/src/storyboard.ts AD_CONFIGS + render.sh, which needs the
|
||||||
|
running stack + login creds, so that part is yours to run).
|
||||||
|
|
||||||
|
Outputs:
|
||||||
|
analysis/out/video_scripts/<slug>.md: one filming kit per finding
|
||||||
|
analysis/out/video_scripts/INDEX.md: overview + how to film
|
||||||
|
|
||||||
|
Run: source .venv/bin/activate && python analysis/build_video_scripts.py (after generate_findings.py)
|
||||||
|
"""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import json
|
||||||
|
import re
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
FIND = Path("analysis/out/findings")
|
||||||
|
OUT = Path("analysis/out/video_scripts")
|
||||||
|
SITE = "https://perfect-postcode.co.uk"
|
||||||
|
SOURCES = "Land Registry, EPC, Ofsted, DfT, Police.uk"
|
||||||
|
|
||||||
|
# Suggested CityKey for the optional auto-render path (storyboard.ts CityKey union).
|
||||||
|
CITY_OUTCODES = {
|
||||||
|
"manchester": {"M", "SK", "OL", "BL", "WN"},
|
||||||
|
"birmingham": {"B"},
|
||||||
|
"bristol": {"BS"},
|
||||||
|
"leeds": {"LS", "WF", "BD"},
|
||||||
|
}
|
||||||
|
LONDON = {"E", "EC", "WC", "W", "SW", "SE", "N", "NW", "BR", "IG", "RM", "TW", "KT", "HA", "SM", "CR", "UB", "EN", "DA"}
|
||||||
|
|
||||||
|
|
||||||
|
def gbp(n) -> str:
|
||||||
|
return f"£{int(n):,}"
|
||||||
|
|
||||||
|
|
||||||
|
def outward_area(sector: str) -> str:
|
||||||
|
return re.match(r"^[A-Z]+", sector).group(0)
|
||||||
|
|
||||||
|
|
||||||
|
def city_key(pricey_sector: str) -> str:
|
||||||
|
area = outward_area(pricey_sector)
|
||||||
|
if area in LONDON:
|
||||||
|
return "london"
|
||||||
|
for city, codes in CITY_OUTCODES.items():
|
||||||
|
if area in codes:
|
||||||
|
return city
|
||||||
|
return "london" # fallback; only matters for the auto-render variant
|
||||||
|
|
||||||
|
|
||||||
|
def twin_kit(f: dict) -> str:
|
||||||
|
p, w, s = f["pricey"], f["twin"], f["stats"]
|
||||||
|
pn, wn = p["name"] or p["sector"], w["name"] or w["sector"]
|
||||||
|
typ = s["dominant_type"].lower()
|
||||||
|
plural = {
|
||||||
|
"Flats/Maisonettes": "flats",
|
||||||
|
"Terraced": "terraced houses",
|
||||||
|
"Semi-Detached": "semi-detached houses",
|
||||||
|
"Detached": "detached houses",
|
||||||
|
}.get(s["dominant_type"], typ + "s")
|
||||||
|
gap = f"{s['gap_pct']:.0f}%"
|
||||||
|
money = gbp(s["gap_on_90sqm"])
|
||||||
|
url = f["map_url"]
|
||||||
|
|
||||||
|
titles = [
|
||||||
|
f["title"],
|
||||||
|
f"{pn} vs {wn}: same station, same schools, {money} cheaper",
|
||||||
|
f"Why {wn} is the smart-money version of {pn} ({gap} less per m²)",
|
||||||
|
]
|
||||||
|
captions = [
|
||||||
|
f"{pn} vs {wn}",
|
||||||
|
f"Same station. Same schools.",
|
||||||
|
f"{money} cheaper",
|
||||||
|
f"Same {typ}, ~{s['build_year']}",
|
||||||
|
f"{gap} less per m²",
|
||||||
|
"Find your cheaper twin, free",
|
||||||
|
]
|
||||||
|
narration = (
|
||||||
|
f"This is {pn}. And this is {wn}, right next door. Same station. "
|
||||||
|
f"Same {'secondary school catchment' if s['good_secondary_catchments'] else 'schools'}. "
|
||||||
|
f"The same kind of home: {plural} built around {s['build_year']}. "
|
||||||
|
f"On every measure that moves price, they're twins. "
|
||||||
|
f"But watch the price per square metre. {pn}: {gbp(p['est_psqm'])}. {wn}: {gbp(w['est_psqm'])}. "
|
||||||
|
f"That's {gap} cheaper, about {money} on a typical 90-square-metre home, "
|
||||||
|
f"for the same life, one postcode over. You're not paying for the house. You're paying for the name. "
|
||||||
|
f"You can find the cheaper twin of any postcode in England on the map for free, no signup."
|
||||||
|
)
|
||||||
|
chapters = [
|
||||||
|
("0:00", f"The two postcodes ({pn} & {wn})"),
|
||||||
|
("0:08", "Same station"),
|
||||||
|
("0:18", "Same school catchment"),
|
||||||
|
("0:28", "Same kind of home"),
|
||||||
|
("0:38", "The price-per-m² reveal"),
|
||||||
|
("0:52", "Find your own cheaper twin (free map)"),
|
||||||
|
]
|
||||||
|
description = (
|
||||||
|
f"{url}\n\n"
|
||||||
|
f"{pn} and {wn} share a station, a school catchment and the same era of housing, but {wn} costs about "
|
||||||
|
f"{gap} less per square metre ({money} on a 90 m² home). I built a map that ranks every postcode in "
|
||||||
|
f"England by what each pound actually buys, from official open data ({SOURCES}). Find the cheaper twin "
|
||||||
|
f"of any area, free and with no signup, at {SITE}.\n\n"
|
||||||
|
+ "\n".join(f"{ts} {label}" for ts, label in chapters)
|
||||||
|
+ "\n\nData: Contains HM Land Registry data © Crown copyright and database right, OGL v3.0. "
|
||||||
|
"Figures are estimates aggregated to postcode sector, not valuations."
|
||||||
|
)
|
||||||
|
shotlist = [
|
||||||
|
("0:00–0:06", "COLD OPEN: payoff first", f"Open on the map already showing both areas with the £/m² gap visible. Caption: '{money} cheaper'. Say the hook.", "Land on the map URL below (filters pre-applied)."),
|
||||||
|
("0:06–0:18", "Same station", "Pan/zoom to show both areas sit by the same line/station. Toggle the commute context if you want.", "Caption: 'Same station.'"),
|
||||||
|
("0:18–0:28", "Same schools", "Show the Good+ secondary catchment covering both.", "Caption: 'Same school catchment.'"),
|
||||||
|
("0:28–0:38", "Same homes", f"Note the dominant type ({plural}) and build era (~{s['build_year']}).", "Caption: 'Same homes.'"),
|
||||||
|
("0:38–0:52", "THE REVEAL", f"Show the £/m² side by side: {pn} {gbp(p['est_psqm'])} vs {wn} {gbp(w['est_psqm'])}.", f"Caption: '{gap} less per m²'."),
|
||||||
|
("0:52–1:00", "CTA", "End on the map; invite them to find their own cheaper twin.", "Caption: 'Free. No signup.'"),
|
||||||
|
]
|
||||||
|
|
||||||
|
ck = city_key(p["sector"])
|
||||||
|
psqm_cap = int(round(w["est_psqm"] * 1.05, -2))
|
||||||
|
spec = {
|
||||||
|
"name": f"twin-{f['slug'].split('/')[-1]}",
|
||||||
|
"city": ck,
|
||||||
|
"promptText": f"Best value {typ}s near {pn}: same schools and station, lower price",
|
||||||
|
"initialFilters": {
|
||||||
|
"Est. price per sqm": [0, psqm_cap],
|
||||||
|
"Good+ secondary school catchments": [1, 11],
|
||||||
|
},
|
||||||
|
"outroLine": f"{wn}: same life, {gap} cheaper.",
|
||||||
|
}
|
||||||
|
|
||||||
|
lines = [
|
||||||
|
f"# Video kit: {pn} vs {wn}",
|
||||||
|
"",
|
||||||
|
f"**Page:** {SITE}{f['page_path']} · **Format:** faceless screen-record, ~45–60s long + a 9:16 Short cut",
|
||||||
|
"",
|
||||||
|
f"## 🎬 Map URL to record (open this, hit record)",
|
||||||
|
f"`{url}`",
|
||||||
|
"*(filters are pre-applied so the value is on screen immediately)*",
|
||||||
|
"",
|
||||||
|
"## Hook (first 2 seconds, on screen + said)",
|
||||||
|
f"**\"{money} cheaper. Same station. Same schools.\"**",
|
||||||
|
"",
|
||||||
|
"## Shot list",
|
||||||
|
"| Time | Beat | What to show | On-screen |",
|
||||||
|
"|------|------|--------------|-----------|",
|
||||||
|
]
|
||||||
|
for t, beat, show, cap in shotlist:
|
||||||
|
lines.append(f"| {t} | {beat} | {show} | {cap} |")
|
||||||
|
lines += [
|
||||||
|
"",
|
||||||
|
"## Narration (human voiceover, never raw TTS for a property audience)",
|
||||||
|
f"> {narration}",
|
||||||
|
"",
|
||||||
|
"## Captions (≤6 words, sound-off)",
|
||||||
|
*[f"- {c}" for c in captions],
|
||||||
|
"",
|
||||||
|
"## YouTube",
|
||||||
|
"**Title options:**",
|
||||||
|
*[f"{i+1}. {t}" for i, t in enumerate(titles)],
|
||||||
|
"",
|
||||||
|
"**Thumbnail text:** big number `" + money + " cheaper` + the two names `" + f"{pn} → {wn}`",
|
||||||
|
"",
|
||||||
|
"**Description (paste as-is):**",
|
||||||
|
"```",
|
||||||
|
description,
|
||||||
|
"```",
|
||||||
|
"",
|
||||||
|
"## 9:16 Short (cut from the same recording)",
|
||||||
|
f"First 3 seconds: the £/m² reveal ({pn} {gbp(p['est_psqm'])} → {wn} {gbp(w['est_psqm'])}) + caption '{gap} less'. "
|
||||||
|
"End card: 'Find your cheaper twin, free, no signup.'",
|
||||||
|
"",
|
||||||
|
"## Optional auto-render spec (video/src/storyboard.ts AD_CONFIGS)",
|
||||||
|
"Add this as a `DemoAdStoryboardConfig` and run `video/render.sh --prod` (needs login creds + the live stack). "
|
||||||
|
"Filter names must match live `/api/features` or preflight fails.",
|
||||||
|
"```json",
|
||||||
|
json.dumps(spec, indent=2),
|
||||||
|
"```",
|
||||||
|
]
|
||||||
|
return "\n".join(lines)
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
OUT.mkdir(parents=True, exist_ok=True)
|
||||||
|
findings = [json.loads(p.read_text()) for p in sorted(FIND.glob("*.json"))]
|
||||||
|
twins = [f for f in findings if f["type"] == "cheaper_twin"]
|
||||||
|
|
||||||
|
made = []
|
||||||
|
for f in twins:
|
||||||
|
slug = f["slug"].split("/")[-1]
|
||||||
|
(OUT / f"{slug}.md").write_text(twin_kit(f))
|
||||||
|
made.append((slug, f))
|
||||||
|
|
||||||
|
index = [
|
||||||
|
"# Video kits: film one per 1–2 weeks",
|
||||||
|
"",
|
||||||
|
"Each kit is a complete, payoff-first faceless video you can screen-record off the live map. "
|
||||||
|
"Pick one, open its Map URL, record, read the narration (human voice), export one clean cut + a 9:16 Short.",
|
||||||
|
"",
|
||||||
|
"**Priority order (relatable family-home twins first, since they convert better than prime London):**",
|
||||||
|
"",
|
||||||
|
"| Kit | Hook | File |",
|
||||||
|
"|-----|------|------|",
|
||||||
|
]
|
||||||
|
# Family homes first, then the rest, by £ gap.
|
||||||
|
fam = [m for m in made if m[1]["stats"]["dominant_type"] in ("Terraced", "Semi-Detached", "Detached")]
|
||||||
|
rest = [m for m in made if m not in fam]
|
||||||
|
for slug, f in sorted(fam, key=lambda m: m[1]["stats"]["gap_on_90sqm"], reverse=True) + sorted(
|
||||||
|
rest, key=lambda m: m[1]["stats"]["gap_on_90sqm"], reverse=True
|
||||||
|
):
|
||||||
|
p, w = f["pricey"], f["twin"]
|
||||||
|
index.append(f"| {p['name'] or p['sector']} → {w['name'] or w['sector']} | {f['shocking_number']} / {gbp(f['stats']['gap_on_90sqm'])} | `{slug}.md` |")
|
||||||
|
(OUT / "INDEX.md").write_text("\n".join(index))
|
||||||
|
print(f"Wrote {len(made)} video kits + INDEX.md to {OUT}/")
|
||||||
|
for slug, f in made[:6]:
|
||||||
|
print(f" {slug}.md: {f['title']}")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
341
analysis/cheaper_twins.py
Normal file
341
analysis/cheaper_twins.py
Normal file
|
|
@ -0,0 +1,341 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Cheaper-twin / name-premium index over all-England property data.
|
||||||
|
|
||||||
|
This is the ROOT growth artifact: every page, OG card, video and outreach number derives from its
|
||||||
|
output. It reads the local property data, aggregates to POSTCODE SECTOR grain (e.g. "N1 1", the same
|
||||||
|
grain the homepage TwinProof block uses, which is load-bearing), and finds "cheaper twins": nearby
|
||||||
|
sectors that match on property type, build era, school provision and station access but differ
|
||||||
|
materially in estimated price per square metre.
|
||||||
|
|
||||||
|
Defensibility rules baked in (see growth/README.md):
|
||||||
|
- Sector aggregation only, never address-level output (Royal Mail / OS rights).
|
||||||
|
- Minimum sample sizes per sector (--min-props, --min-recorded).
|
||||||
|
- Robust statistics: median £/sqm; a sector needs real recorded sales, not just modelled estimates.
|
||||||
|
- England only (ctry25cd starts with "E").
|
||||||
|
- Every row stamps its N.
|
||||||
|
- "Twin" requires genuine like-for-like matching before any price claim is made.
|
||||||
|
|
||||||
|
Outputs (analysis/out/):
|
||||||
|
- sector_index.parquet / .csv: per-sector value table (powers "best value", "£100k buys X m²", etc.)
|
||||||
|
- cheaper_twins.parquet / .csv: ranked twin pairs (pricey name -> cheaper twin)
|
||||||
|
- national_facts.json: headline stats for collateral/finding placeholders
|
||||||
|
|
||||||
|
Run: source .venv/bin/activate && python analysis/cheaper_twins.py
|
||||||
|
"""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import json
|
||||||
|
import math
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
import numpy as np
|
||||||
|
import polars as pl
|
||||||
|
from scipy.spatial import cKDTree
|
||||||
|
|
||||||
|
DATA = Path("property-data")
|
||||||
|
OUT = Path("analysis/out")
|
||||||
|
# Postcode sector = outward code + first inward digit, e.g. "N1 1", "M20 2".
|
||||||
|
SECTOR_RE = r"^([A-Z]{1,2}[0-9][A-Z0-9]? [0-9])"
|
||||||
|
|
||||||
|
STATION_DIST_COLS = [
|
||||||
|
"Distance to nearest amenity (Rail station) (km)",
|
||||||
|
"Distance to nearest amenity (Tube station) (km)",
|
||||||
|
"Distance to nearest amenity (DLR station) (km)",
|
||||||
|
"Distance to nearest amenity (Tram & Metro stop) (km)",
|
||||||
|
]
|
||||||
|
AREA_COLS = [
|
||||||
|
"lat",
|
||||||
|
"lon",
|
||||||
|
"Good+ primary school catchments",
|
||||||
|
"Good+ secondary school catchments",
|
||||||
|
"Outstanding primary school catchments",
|
||||||
|
"Outstanding secondary school catchments",
|
||||||
|
"Serious crime (/yr, 7y)",
|
||||||
|
"Minor crime (/yr, 7y)",
|
||||||
|
"Noise (dB)",
|
||||||
|
"Max available download speed (Mbps)",
|
||||||
|
"Median age",
|
||||||
|
"% Owner occupied",
|
||||||
|
"% Degree or higher",
|
||||||
|
*STATION_DIST_COLS,
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def _collect(lf: pl.LazyFrame) -> pl.DataFrame:
|
||||||
|
"""Collect with streaming if the installed polars supports it, else fall back."""
|
||||||
|
try:
|
||||||
|
return lf.collect(streaming=True)
|
||||||
|
except Exception:
|
||||||
|
return lf.collect()
|
||||||
|
|
||||||
|
|
||||||
|
def property_aggregates() -> pl.DataFrame:
|
||||||
|
props = (
|
||||||
|
pl.scan_parquet(DATA / "properties.parquet")
|
||||||
|
.with_columns(pl.col("Postcode").str.extract(SECTOR_RE, 1).alias("Sector"))
|
||||||
|
.filter(pl.col("Sector").is_not_null())
|
||||||
|
)
|
||||||
|
agg = props.group_by("Sector").agg(
|
||||||
|
pl.len().alias("n_props"),
|
||||||
|
pl.col("Price per sqm").drop_nulls().len().alias("n_recorded"),
|
||||||
|
pl.col("Est. price per sqm").median().alias("est_psqm"),
|
||||||
|
pl.col("Price per sqm").median().alias("recorded_psqm"),
|
||||||
|
pl.col("Last known price").median().alias("median_price"),
|
||||||
|
pl.col("Estimated current price").median().alias("est_price"),
|
||||||
|
pl.col("Total floor area (sqm)").median().alias("median_floor"),
|
||||||
|
pl.col("Number of bedrooms & living rooms").median().alias("median_rooms"),
|
||||||
|
pl.col("Construction year")
|
||||||
|
.filter(pl.col("Construction year") > 1800)
|
||||||
|
.median()
|
||||||
|
.alias("median_build_year"),
|
||||||
|
)
|
||||||
|
|
||||||
|
# Dominant property type + its share, per sector (robust mode without ordering assumptions).
|
||||||
|
tc = props.group_by(["Sector", "Property type"]).agg(pl.len().alias("c"))
|
||||||
|
tc = tc.with_columns(
|
||||||
|
(pl.col("c") / pl.col("c").sum().over("Sector")).alias("share"),
|
||||||
|
pl.col("c").max().over("Sector").alias("maxc"),
|
||||||
|
)
|
||||||
|
dom = (
|
||||||
|
tc.filter(pl.col("c") == pl.col("maxc"))
|
||||||
|
.unique(subset="Sector", keep="first")
|
||||||
|
.select(
|
||||||
|
pl.col("Sector"),
|
||||||
|
pl.col("Property type").alias("dominant_type"),
|
||||||
|
pl.col("share").alias("dominant_share"),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
return _collect(agg).join(_collect(dom), on="Sector", how="left")
|
||||||
|
|
||||||
|
|
||||||
|
def area_aggregates() -> pl.DataFrame:
|
||||||
|
# Property counts per postcode unit -> weights, so area features are weighted by housing stock.
|
||||||
|
unit_counts = _collect(
|
||||||
|
pl.scan_parquet(DATA / "properties.parquet")
|
||||||
|
.group_by("Postcode")
|
||||||
|
.agg(pl.len().alias("n"))
|
||||||
|
)
|
||||||
|
|
||||||
|
pc = pl.read_parquet(DATA / "postcode.parquet", columns=["Postcode", "ctry25cd", *AREA_COLS])
|
||||||
|
pc = pc.filter(pl.col("ctry25cd").str.starts_with("E")) # England only
|
||||||
|
pc = pc.join(unit_counts, on="Postcode", how="inner") # only units that contain homes
|
||||||
|
pc = pc.with_columns(
|
||||||
|
pl.col("Postcode").str.extract(SECTOR_RE, 1).alias("Sector"),
|
||||||
|
pl.min_horizontal(STATION_DIST_COLS).alias("dist_station_km"),
|
||||||
|
).filter(pl.col("Sector").is_not_null())
|
||||||
|
|
||||||
|
def wmean(col: str, alias: str) -> pl.Expr:
|
||||||
|
# weighted mean ignoring nulls: sum(col*n) / sum(n where col not null)
|
||||||
|
num = (pl.col(col) * pl.col("n")).sum()
|
||||||
|
den = pl.col("n").filter(pl.col(col).is_not_null()).sum()
|
||||||
|
return (num / den).alias(alias)
|
||||||
|
|
||||||
|
return pc.group_by("Sector").agg(
|
||||||
|
pl.col("n").sum().alias("area_n"),
|
||||||
|
wmean("lat", "lat"),
|
||||||
|
wmean("lon", "lon"),
|
||||||
|
wmean("Good+ primary school catchments", "good_primary"),
|
||||||
|
wmean("Good+ secondary school catchments", "good_secondary"),
|
||||||
|
wmean("Outstanding primary school catchments", "outstanding_primary"),
|
||||||
|
wmean("Outstanding secondary school catchments", "outstanding_secondary"),
|
||||||
|
wmean("Serious crime (/yr, 7y)", "serious_crime"),
|
||||||
|
wmean("Noise (dB)", "noise_db"),
|
||||||
|
wmean("Max available download speed (Mbps)", "broadband_mbps"),
|
||||||
|
wmean("Median age", "median_age"),
|
||||||
|
wmean("% Owner occupied", "pct_owner"),
|
||||||
|
wmean("% Degree or higher", "pct_degree"),
|
||||||
|
wmean("dist_station_km", "dist_station_km"),
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def build_index(args) -> pl.DataFrame:
|
||||||
|
idx = property_aggregates().join(area_aggregates(), on="Sector", how="inner")
|
||||||
|
idx = idx.filter(
|
||||||
|
(pl.col("n_props") >= args.min_props)
|
||||||
|
& (pl.col("n_recorded") >= args.min_recorded)
|
||||||
|
& pl.col("est_psqm").is_not_null()
|
||||||
|
& (pl.col("est_psqm") > 0)
|
||||||
|
& pl.col("lat").is_not_null()
|
||||||
|
& pl.col("lon").is_not_null()
|
||||||
|
& pl.col("dist_station_km").is_not_null()
|
||||||
|
)
|
||||||
|
idx = idx.with_columns(
|
||||||
|
(100_000 / pl.col("est_psqm")).round(1).alias("sqm_per_100k"),
|
||||||
|
pl.col("est_psqm").round().cast(pl.Int64),
|
||||||
|
pl.col("recorded_psqm").round().cast(pl.Int64),
|
||||||
|
)
|
||||||
|
return idx.sort("est_psqm", descending=True)
|
||||||
|
|
||||||
|
|
||||||
|
def find_twins(idx: pl.DataFrame, args) -> pl.DataFrame:
|
||||||
|
d = idx.to_dict(as_series=False)
|
||||||
|
n = len(d["Sector"])
|
||||||
|
lat = np.array(d["lat"], float)
|
||||||
|
lon = np.array(d["lon"], float)
|
||||||
|
psqm = np.array(d["est_psqm"], float)
|
||||||
|
floor = np.array([f if f is not None else np.nan for f in d["median_floor"]], float)
|
||||||
|
build = np.array([b if b is not None else np.nan for b in d["median_build_year"]], float)
|
||||||
|
dom = d["dominant_type"]
|
||||||
|
good_sec = np.array(d["good_secondary"], float)
|
||||||
|
good_pri = np.array(d["good_primary"], float)
|
||||||
|
crime = np.array(d["serious_crime"], float)
|
||||||
|
station = np.array(d["dist_station_km"], float)
|
||||||
|
owner = np.array(d["pct_owner"], float)
|
||||||
|
degree = np.array(d["pct_degree"], float)
|
||||||
|
age = np.array(d["median_age"], float)
|
||||||
|
|
||||||
|
# Planar projection (km) for a local KD-tree radius search.
|
||||||
|
lat0 = math.radians(float(np.nanmean(lat)))
|
||||||
|
x = lon * 111.320 * math.cos(lat0)
|
||||||
|
y = lat * 110.574
|
||||||
|
tree = cKDTree(np.column_stack([x, y]))
|
||||||
|
|
||||||
|
rows = []
|
||||||
|
for i in range(n):
|
||||||
|
neigh = tree.query_ball_point([x[i], y[i]], args.max_km)
|
||||||
|
best_j, best_gap = -1, -1.0
|
||||||
|
for j in neigh:
|
||||||
|
if j == i or psqm[i] <= psqm[j]:
|
||||||
|
continue # i must be the pricier side
|
||||||
|
gap = 1.0 - psqm[j] / psqm[i]
|
||||||
|
# A genuine "twin" sits in a believable band: below min it's not a story,
|
||||||
|
# above max it's a different market tier (city-centre premium / prime), not a twin.
|
||||||
|
if gap < args.min_gap or gap > args.max_gap:
|
||||||
|
continue
|
||||||
|
if dom[i] != dom[j]:
|
||||||
|
continue
|
||||||
|
if not (np.isfinite(build[i]) and np.isfinite(build[j])) or abs(build[i] - build[j]) > args.build_band:
|
||||||
|
continue
|
||||||
|
if abs(good_sec[i] - good_sec[j]) > args.school_tol or abs(good_pri[i] - good_pri[j]) > args.school_tol:
|
||||||
|
continue
|
||||||
|
if station[i] > args.station_max or station[j] > args.station_max or abs(station[i] - station[j]) > args.station_tol:
|
||||||
|
continue
|
||||||
|
# Similarity gates: the two must be the SAME KIND of neighbourhood, so the gap
|
||||||
|
# reads as a name premium, not a tier jump (deprivation/tenure/education/age/safety/size).
|
||||||
|
if crime[j] > crime[i] * args.crime_ratio or crime[i] > crime[j] * args.crime_ratio:
|
||||||
|
continue
|
||||||
|
if abs(owner[i] - owner[j]) > args.owner_tol:
|
||||||
|
continue
|
||||||
|
if abs(degree[i] - degree[j]) > args.degree_tol:
|
||||||
|
continue
|
||||||
|
if np.isfinite(age[i]) and np.isfinite(age[j]) and abs(age[i] - age[j]) > args.age_tol:
|
||||||
|
continue
|
||||||
|
if np.isfinite(floor[i]) and np.isfinite(floor[j]) and floor[j] > 0:
|
||||||
|
fr = floor[i] / floor[j]
|
||||||
|
if fr < args.floor_ratio or fr > 1.0 / args.floor_ratio:
|
||||||
|
continue
|
||||||
|
if gap > best_gap:
|
||||||
|
best_gap, best_j = gap, j
|
||||||
|
if best_j < 0:
|
||||||
|
continue
|
||||||
|
j = best_j
|
||||||
|
avg_floor = np.nanmean([floor[i], floor[j]])
|
||||||
|
if not np.isfinite(avg_floor):
|
||||||
|
avg_floor = 90.0
|
||||||
|
rows.append(
|
||||||
|
{
|
||||||
|
"pricey_sector": d["Sector"][i],
|
||||||
|
"twin_sector": d["Sector"][j],
|
||||||
|
"pricey_psqm": int(psqm[i]),
|
||||||
|
"twin_psqm": int(psqm[j]),
|
||||||
|
"gap_pct": round(best_gap * 100, 1),
|
||||||
|
"gap_per_sqm": int(psqm[i] - psqm[j]),
|
||||||
|
"gap_on_avg_home": int((psqm[i] - psqm[j]) * avg_floor),
|
||||||
|
"gap_on_90sqm": int((psqm[i] - psqm[j]) * 90),
|
||||||
|
"dist_km": round(math.hypot(x[i] - x[j], y[i] - y[j]), 2),
|
||||||
|
"dominant_type": dom[i],
|
||||||
|
"build_year": None if not np.isfinite(build[i]) else int(build[i]),
|
||||||
|
"good_secondary": round(float(good_sec[i]), 1),
|
||||||
|
"station_km": round(float(station[i]), 2),
|
||||||
|
"pricey_lat": round(float(lat[i]), 5),
|
||||||
|
"pricey_lon": round(float(lon[i]), 5),
|
||||||
|
"twin_lat": round(float(lat[j]), 5),
|
||||||
|
"twin_lon": round(float(lon[j]), 5),
|
||||||
|
"pricey_n": int(d["n_props"][i]),
|
||||||
|
"twin_n": int(d["n_props"][j]),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
if not rows:
|
||||||
|
return pl.DataFrame()
|
||||||
|
tw = pl.DataFrame(rows)
|
||||||
|
# Dedup unordered pairs, keep the biggest gap.
|
||||||
|
tw = tw.with_columns(
|
||||||
|
pl.concat_list(
|
||||||
|
[
|
||||||
|
pl.min_horizontal("pricey_sector", "twin_sector"),
|
||||||
|
pl.max_horizontal("pricey_sector", "twin_sector"),
|
||||||
|
]
|
||||||
|
)
|
||||||
|
.list.join("|")
|
||||||
|
.alias("_pair")
|
||||||
|
)
|
||||||
|
tw = tw.sort("gap_pct", descending=True).unique(subset="_pair", keep="first").drop("_pair")
|
||||||
|
return tw.filter(pl.col("gap_on_90sqm") >= args.min_abs_gap).sort("gap_pct", descending=True)
|
||||||
|
|
||||||
|
|
||||||
|
def national_facts(idx: pl.DataFrame, twins: pl.DataFrame, args) -> dict:
|
||||||
|
valid = idx.filter(pl.col("n_props") >= args.min_props)
|
||||||
|
cheapest = valid.sort("est_psqm").head(1).to_dicts()[0]
|
||||||
|
dearest = valid.sort("est_psqm", descending=True).head(1).to_dicts()[0]
|
||||||
|
facts = {
|
||||||
|
"generated_with": "analysis/cheaper_twins.py",
|
||||||
|
"params": vars(args),
|
||||||
|
"n_sectors": idx.height,
|
||||||
|
"n_twin_pairs": twins.height,
|
||||||
|
"attribution": "Contains HM Land Registry data © Crown copyright and database right. Licensed under the Open Government Licence v3.0.",
|
||||||
|
"best_value_sector": {"sector": cheapest["Sector"], "est_psqm": cheapest["est_psqm"], "sqm_per_100k": cheapest["sqm_per_100k"], "n": cheapest["n_props"]},
|
||||||
|
"dearest_sector": {"sector": dearest["Sector"], "est_psqm": dearest["est_psqm"], "sqm_per_100k": dearest["sqm_per_100k"], "n": dearest["n_props"]},
|
||||||
|
}
|
||||||
|
if twins.height:
|
||||||
|
top = twins.head(10).to_dicts()
|
||||||
|
facts["biggest_twin_gap"] = top[0]
|
||||||
|
facts["top_twins"] = top
|
||||||
|
return facts
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
p = argparse.ArgumentParser(description=__doc__)
|
||||||
|
p.add_argument("--min-props", type=int, default=150, help="min properties per sector")
|
||||||
|
p.add_argument("--min-recorded", type=int, default=40, help="min recorded sales (with floor area) per sector")
|
||||||
|
p.add_argument("--max-km", type=float, default=3.0, help="max centroid distance for a twin (km)")
|
||||||
|
p.add_argument("--min-gap", type=float, default=0.15, help="min fractional £/sqm gap")
|
||||||
|
p.add_argument("--max-gap", type=float, default=0.45, help="max fractional gap (above this it's a tier jump, not a twin)")
|
||||||
|
p.add_argument("--build-band", type=float, default=30, help="max build-year difference")
|
||||||
|
p.add_argument("--school-tol", type=float, default=1.5, help="max difference in good-catchment counts")
|
||||||
|
p.add_argument("--station-max", type=float, default=1.5, help="both sectors must be within this many km of a station")
|
||||||
|
p.add_argument("--station-tol", type=float, default=0.9, help="max difference in station distance (km)")
|
||||||
|
p.add_argument("--crime-ratio", type=float, default=1.5, help="serious crime must be within this ratio either way")
|
||||||
|
p.add_argument("--owner-tol", type=float, default=22, help="max difference in %% owner-occupied")
|
||||||
|
p.add_argument("--degree-tol", type=float, default=22, help="max difference in %% degree-or-higher")
|
||||||
|
p.add_argument("--age-tol", type=float, default=12, help="max difference in median age (years)")
|
||||||
|
p.add_argument("--floor-ratio", type=float, default=0.72, help="median floor area must be within this ratio either way")
|
||||||
|
p.add_argument("--min-abs-gap", type=int, default=20000, help="min £ gap on a 90 sqm home for the twin list")
|
||||||
|
args = p.parse_args()
|
||||||
|
|
||||||
|
OUT.mkdir(parents=True, exist_ok=True)
|
||||||
|
print("Aggregating 22.4M properties to sector grain ...")
|
||||||
|
idx = build_index(args)
|
||||||
|
print(f" {idx.height} valid England sectors (>= {args.min_props} props, >= {args.min_recorded} recorded sales)")
|
||||||
|
idx.write_parquet(OUT / "sector_index.parquet")
|
||||||
|
idx.write_csv(OUT / "sector_index.csv")
|
||||||
|
|
||||||
|
print("Matching cheaper twins ...")
|
||||||
|
twins = find_twins(idx, args)
|
||||||
|
print(f" {twins.height} twin pairs")
|
||||||
|
if twins.height:
|
||||||
|
twins.write_parquet(OUT / "cheaper_twins.parquet")
|
||||||
|
twins.write_csv(OUT / "cheaper_twins.csv")
|
||||||
|
|
||||||
|
facts = national_facts(idx, twins, args)
|
||||||
|
(OUT / "national_facts.json").write_text(json.dumps(facts, indent=2, default=str))
|
||||||
|
print(f"Wrote outputs to {OUT}/")
|
||||||
|
if twins.height:
|
||||||
|
print("\nTop 10 cheaper twins (pricey -> twin, gap%, £ on 90sqm):")
|
||||||
|
for r in twins.head(10).to_dicts():
|
||||||
|
print(f" {r['pricey_sector']:>7} -> {r['twin_sector']:<7} {r['gap_pct']:>5}% £{r['gap_on_90sqm']:,} ({r['dominant_type']}, ~{r['build_year']})")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
220
analysis/generate_findings.py
Normal file
220
analysis/generate_findings.py
Normal file
|
|
@ -0,0 +1,220 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Turn the cheaper-twin index into publishable FINDINGS.
|
||||||
|
|
||||||
|
Each finding is the single artifact the whole engine renders four ways (growth/README.md):
|
||||||
|
an SEO page, an OG/unfurl card, a video storyboard, and a ≤3-filter deep-link CTA into the live map.
|
||||||
|
This script curates the raw 415 twin pairs into a reviewed set of findings and emits:
|
||||||
|
|
||||||
|
analysis/out/findings/<slug>.json: one machine-readable finding per page/video
|
||||||
|
analysis/out/findings_review.md: human-readable sheet for the founder to eyeball + fix names
|
||||||
|
|
||||||
|
Place labels come from analysis/place_names.json (APPROXIMATE, verify before publishing).
|
||||||
|
|
||||||
|
Run: source .venv/bin/activate && python analysis/generate_findings.py
|
||||||
|
"""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import json
|
||||||
|
import urllib.parse
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
import polars as pl
|
||||||
|
|
||||||
|
OUT = Path("analysis/out")
|
||||||
|
FIND = OUT / "findings"
|
||||||
|
SITE = "https://perfect-postcode.co.uk"
|
||||||
|
ATTRIB = "Contains HM Land Registry data © Crown copyright and database right. Licensed under the Open Government Licence v3.0."
|
||||||
|
SOURCES = "HM Land Registry · EPC (DLUHC) · Ofsted · DfT · ONS · Police.uk"
|
||||||
|
TYPE_SINGULAR = {
|
||||||
|
"Flats/Maisonettes": "flat",
|
||||||
|
"Terraced": "terraced house",
|
||||||
|
"Semi-Detached": "semi-detached house",
|
||||||
|
"Detached": "detached house",
|
||||||
|
}
|
||||||
|
|
||||||
|
NAMES = json.loads(Path("analysis/place_names.json").read_text())
|
||||||
|
|
||||||
|
|
||||||
|
def label(sector: str) -> dict:
|
||||||
|
outward = sector.split(" ")[0]
|
||||||
|
name = NAMES.get(outward)
|
||||||
|
return {"sector": sector, "name": name, "label": f"{name} ({sector})" if name else sector, "named": bool(name)}
|
||||||
|
|
||||||
|
|
||||||
|
def sector_slug(sector: str) -> str:
|
||||||
|
return sector.lower().replace(" ", "-")
|
||||||
|
|
||||||
|
|
||||||
|
def map_query(t: dict) -> str:
|
||||||
|
"""A ≤3-filter deep link that frames the value: centre between the pair, cap £/sqm near the
|
||||||
|
cheaper twin, require a good secondary catchment. Reproducible by non-payers (DEMO_MAX_FILTERS=3)."""
|
||||||
|
mid_lat = round((t["pricey_lat"] + t["twin_lat"]) / 2, 5)
|
||||||
|
mid_lon = round((t["pricey_lon"] + t["twin_lon"]) / 2, 5)
|
||||||
|
psqm_cap = int(round(t["twin_psqm"] * 1.05, -2))
|
||||||
|
enc_psqm = urllib.parse.quote("Est. price per sqm", safe="")
|
||||||
|
enc_school = urllib.parse.quote("Good+ secondary school catchments", safe="")
|
||||||
|
# Two plain numeric filters (within the 3-filter demo cap): frames value + good schools and
|
||||||
|
# uses the well-understood filter=NAME:MIN:MAX form so the OG-card filter-name guard passes.
|
||||||
|
parts = [
|
||||||
|
f"lat={mid_lat}",
|
||||||
|
f"lon={mid_lon}",
|
||||||
|
"zoom=12.5",
|
||||||
|
f"filter={enc_psqm}:0:{psqm_cap}",
|
||||||
|
f"filter={enc_school}:1:11",
|
||||||
|
]
|
||||||
|
return "&".join(parts)
|
||||||
|
|
||||||
|
|
||||||
|
def twin_finding(t: dict) -> dict:
|
||||||
|
p, w = label(t["pricey_sector"]), label(t["twin_sector"])
|
||||||
|
typ = TYPE_SINGULAR.get(t["dominant_type"], "home")
|
||||||
|
slug = f"cheaper-twin/{sector_slug(t['pricey_sector'])}-vs-{sector_slug(t['twin_sector'])}"
|
||||||
|
q = map_query(t)
|
||||||
|
headline_name = f"{p['name']} vs {w['name']}" if p["named"] and w["named"] else f"{t['pricey_sector']} vs {t['twin_sector']}"
|
||||||
|
return {
|
||||||
|
"slug": slug,
|
||||||
|
"type": "cheaper_twin",
|
||||||
|
"page_path": f"/{slug}",
|
||||||
|
"title": f"{headline_name}: the same {typ}, about {t['gap_pct']:.0f}% cheaper per m²",
|
||||||
|
"hook": f"£{t['gap_on_90sqm']:,} less for an equivalent {typ}: same station, similar schools, ~{t['dist_km']}km apart",
|
||||||
|
"shocking_number": f"{t['gap_pct']:.0f}%",
|
||||||
|
"pricey": {**p, "est_psqm": t["pricey_psqm"], "n": t["pricey_n"]},
|
||||||
|
"twin": {**w, "est_psqm": t["twin_psqm"], "n": t["twin_n"]},
|
||||||
|
"stats": {
|
||||||
|
"gap_pct": t["gap_pct"],
|
||||||
|
"gap_per_sqm": t["gap_per_sqm"],
|
||||||
|
"gap_on_90sqm": t["gap_on_90sqm"],
|
||||||
|
"gap_on_avg_home": t["gap_on_avg_home"],
|
||||||
|
"dominant_type": t["dominant_type"],
|
||||||
|
"build_year": t["build_year"],
|
||||||
|
"good_secondary_catchments": t["good_secondary"],
|
||||||
|
"station_km": t["station_km"],
|
||||||
|
"distance_km": t["dist_km"],
|
||||||
|
},
|
||||||
|
"map_query": q,
|
||||||
|
"map_url": f"{SITE}/?{q}",
|
||||||
|
"og_image": f"{SITE}/api/screenshot?og=1&{q}",
|
||||||
|
"methodology": (
|
||||||
|
"Postcode sectors (e.g. N10 3) compared on estimated £/m² of floor space. A pair is only "
|
||||||
|
"called a 'twin' when the two sectors share the dominant property type, build era (±30y), "
|
||||||
|
"good-school catchment provision, station access, deprivation/tenure, education, age and "
|
||||||
|
"home size, so the price gap reflects a name premium, not a different kind of area. "
|
||||||
|
"Estimates, not valuations; aggregated to sector, never address-level."
|
||||||
|
),
|
||||||
|
"needs_name_check": not (p["named"] and w["named"]),
|
||||||
|
"attribution": ATTRIB,
|
||||||
|
"sources": SOURCES,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def curate(tw: pl.DataFrame) -> list[dict]:
|
||||||
|
rows = tw.to_dicts()
|
||||||
|
london = ("E", "EC", "WC", "W", "SW", "SE", "N", "NW")
|
||||||
|
|
||||||
|
def area(s):
|
||||||
|
import re
|
||||||
|
|
||||||
|
return re.match(r"^[A-Z]+", s).group(0)
|
||||||
|
|
||||||
|
family = [r for r in rows if r["dominant_type"] in ("Terraced", "Semi-Detached", "Detached")]
|
||||||
|
prime = sorted(rows, key=lambda r: r["gap_on_90sqm"], reverse=True)
|
||||||
|
regional_family = sorted(
|
||||||
|
[r for r in family if area(r["pricey_sector"]) not in london],
|
||||||
|
key=lambda r: r["gap_on_90sqm"],
|
||||||
|
reverse=True,
|
||||||
|
)
|
||||||
|
london_family = sorted(
|
||||||
|
[r for r in family if area(r["pricey_sector"]) in london],
|
||||||
|
key=lambda r: r["gap_on_90sqm"],
|
||||||
|
reverse=True,
|
||||||
|
)
|
||||||
|
# A spread: biggest national name premiums (PR) + relatable family-home twins (buyer video).
|
||||||
|
picks, seen = [], set()
|
||||||
|
for r in prime[:6] + regional_family[:8] + london_family[:6]:
|
||||||
|
key = r["pricey_sector"] + "|" + r["twin_sector"]
|
||||||
|
if key not in seen:
|
||||||
|
seen.add(key)
|
||||||
|
picks.append(r)
|
||||||
|
return picks
|
||||||
|
|
||||||
|
|
||||||
|
def national_findings(idx: pl.DataFrame, facts: dict) -> list[dict]:
|
||||||
|
named = idx.with_columns(
|
||||||
|
pl.col("Sector").str.extract(r"^([A-Z]+[0-9][A-Z0-9]?)", 1).alias("outward")
|
||||||
|
)
|
||||||
|
best = facts["best_value_sector"]
|
||||||
|
dear = facts["dearest_sector"]
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
"slug": "square-metres-per-100k",
|
||||||
|
"type": "national_table",
|
||||||
|
"page_path": "/square-metres-per-100k",
|
||||||
|
"title": "How many square metres £100,000 buys across England",
|
||||||
|
"shocking_number": f"{best['sqm_per_100k']:.0f} m² vs {dear['sqm_per_100k']:.0f} m²",
|
||||||
|
"hook": (
|
||||||
|
f"£100k buys ~{best['sqm_per_100k']:.0f} m² of floor space in {label(best['sector'])['label']} "
|
||||||
|
f"but only ~{dear['sqm_per_100k']:.0f} m² in {label(dear['sector'])['label']}"
|
||||||
|
),
|
||||||
|
"stats": {"best": best, "dearest": dear, "n_sectors": facts["n_sectors"]},
|
||||||
|
"map_query": "zoom=6&filter=" + urllib.parse.quote("Est. price per sqm", safe="") + ":0:4000",
|
||||||
|
"methodology": "100000 ÷ median estimated £/m², per England postcode sector with sufficient sales.",
|
||||||
|
"needs_name_check": not (label(best["sector"])["named"] and label(dear["sector"])["named"]),
|
||||||
|
"attribution": ATTRIB,
|
||||||
|
"sources": SOURCES,
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
FIND.mkdir(parents=True, exist_ok=True)
|
||||||
|
tw = pl.read_parquet(OUT / "cheaper_twins.parquet")
|
||||||
|
idx = pl.read_parquet(OUT / "sector_index.parquet")
|
||||||
|
facts = json.loads((OUT / "national_facts.json").read_text())
|
||||||
|
|
||||||
|
findings = [twin_finding(r) for r in curate(tw)] + national_findings(idx, facts)
|
||||||
|
|
||||||
|
for f in findings:
|
||||||
|
(FIND / (f["slug"].replace("/", "__") + ".json")).write_text(json.dumps(f, indent=2, default=str))
|
||||||
|
|
||||||
|
# Human review sheet
|
||||||
|
lines = [
|
||||||
|
"# Findings: review before publishing",
|
||||||
|
"",
|
||||||
|
f"{len(findings)} findings generated from analysis/out/cheaper_twins.parquet.",
|
||||||
|
"**Check the place names** (⚠ = unnamed sector, needs a label in analysis/place_names.json) "
|
||||||
|
"and spot-check a couple of numbers. Then these feed the page batch + video factory.",
|
||||||
|
"",
|
||||||
|
"| ⚠ | Title | Hook number | Page path | Deep link |",
|
||||||
|
"|---|-------|-------------|-----------|-----------|",
|
||||||
|
]
|
||||||
|
for f in findings:
|
||||||
|
warn = "⚠" if f.get("needs_name_check") else ""
|
||||||
|
lines.append(
|
||||||
|
f"| {warn} | {f['title']} | {f.get('shocking_number','')} | `{f['page_path']}` | "
|
||||||
|
f"[map]({f.get('map_url', SITE + '/?' + f['map_query'])}) |"
|
||||||
|
)
|
||||||
|
lines += ["", "## Per-finding detail", ""]
|
||||||
|
for f in findings:
|
||||||
|
lines.append(f"### {f['title']}")
|
||||||
|
lines.append(f"- **Type:** {f['type']} · **Page:** `{f['page_path']}`")
|
||||||
|
lines.append(f"- **Hook:** {f['hook']}")
|
||||||
|
if f["type"] == "cheaper_twin":
|
||||||
|
lines.append(
|
||||||
|
f"- **{f['pricey']['label']}** £{f['pricey']['est_psqm']:,}/m² (n={f['pricey']['n']:,}) → "
|
||||||
|
f"**{f['twin']['label']}** £{f['twin']['est_psqm']:,}/m² (n={f['twin']['n']:,}) · "
|
||||||
|
f"gap {f['stats']['gap_pct']}% · {f['stats']['dominant_type']}, ~{f['stats']['build_year']}"
|
||||||
|
)
|
||||||
|
lines.append(f"- **OG card / deep link:** `{f['map_query']}`")
|
||||||
|
lines.append("")
|
||||||
|
(OUT / "findings_review.md").write_text("\n".join(lines))
|
||||||
|
|
||||||
|
n_named = sum(1 for f in findings if not f.get("needs_name_check"))
|
||||||
|
print(f"Wrote {len(findings)} findings to {FIND}/ ({n_named} fully named, {len(findings)-n_named} need a name check)")
|
||||||
|
print(f"Review sheet: {OUT / 'findings_review.md'}")
|
||||||
|
for f in findings[:14]:
|
||||||
|
flag = " ⚠needs-name" if f.get("needs_name_check") else ""
|
||||||
|
print(f" [{f['shocking_number']:>14}] {f['title']}{flag}")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
777
analysis/newbuild_vs_existing_london.ipynb
Normal file
777
analysis/newbuild_vs_existing_london.ipynb
Normal file
File diff suppressed because one or more lines are too long
175
analysis/og_preflight.py
Normal file
175
analysis/og_preflight.py
Normal file
|
|
@ -0,0 +1,175 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
"""OG / share-card preflight for Perfect Postcode growth findings.
|
||||||
|
|
||||||
|
Before publishing growth findings we must confirm that each finding's Open
|
||||||
|
Graph share card actually renders, and that the filter name baked into its
|
||||||
|
deep-link map query still matches a live feature. The OG render has no guard
|
||||||
|
today, so a wrong/renamed filter silently ships a card whose map contradicts
|
||||||
|
the headline.
|
||||||
|
|
||||||
|
For every analysis/out/findings/*.json this script:
|
||||||
|
1. Fetches the OG render at {BASE}/api/screenshot?og=1&{map_query} and checks
|
||||||
|
it is a non-trivial image (HTTP 200, image/*, > MIN_IMAGE_BYTES, and
|
||||||
|
~1200x630 when Pillow is installed).
|
||||||
|
2. Cross-checks every `filter=<NAME>:...` in the map query against the live
|
||||||
|
feature list from {BASE}/api/features, failing on any drifted name.
|
||||||
|
|
||||||
|
Exits non-zero if any finding fails, so it can gate a publish step.
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
source .venv/bin/activate && python analysis/og_preflight.py --base https://perfect-postcode.co.uk
|
||||||
|
|
||||||
|
Needs the server (local dev or prod) reachable at --base / $OG_BASE
|
||||||
|
(default http://localhost:8001); it makes live HTTP requests.
|
||||||
|
"""
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import urllib.parse
|
||||||
|
import urllib.request
|
||||||
|
from io import BytesIO
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
# Pillow is optional: when present we additionally decode the image and verify
|
||||||
|
# its dimensions; otherwise we fall back to status/content-type/size checks.
|
||||||
|
try:
|
||||||
|
from PIL import Image # type: ignore
|
||||||
|
|
||||||
|
_HAVE_PIL = True
|
||||||
|
except Exception:
|
||||||
|
_HAVE_PIL = False
|
||||||
|
|
||||||
|
FINDINGS_DIR = Path(__file__).resolve().parent / "out" / "findings"
|
||||||
|
DEFAULT_BASE = os.environ.get("OG_BASE", "http://localhost:8001")
|
||||||
|
MIN_IMAGE_BYTES = 5 * 1024 # a blank/error render is far smaller than this
|
||||||
|
OG_SIZE = (1200, 630) # screenshot service VIEWPORT, device scale factor 1
|
||||||
|
SIZE_TOLERANCE = 4 # px slack when checking decoded dimensions
|
||||||
|
|
||||||
|
|
||||||
|
def http_get(url: str, timeout: float):
|
||||||
|
"""GET a URL, returning (status, content_type, body_bytes). Raises on error."""
|
||||||
|
req = urllib.request.Request(url, headers={"User-Agent": "og-preflight"})
|
||||||
|
with urllib.request.urlopen(req, timeout=timeout) as resp:
|
||||||
|
return resp.status, resp.headers.get("Content-Type", ""), resp.read()
|
||||||
|
|
||||||
|
|
||||||
|
def filter_names(map_query: str) -> list[str]:
|
||||||
|
"""Extract the feature name from each `filter=<name>:...` query param.
|
||||||
|
|
||||||
|
Mirrors the frontend parser (url-state.ts): the name is everything before
|
||||||
|
the first colon of a URL-decoded filter value, e.g. "Est. price per sqm".
|
||||||
|
Non-filter params (school=, crime=, ...) carry no feature name and are
|
||||||
|
ignored here.
|
||||||
|
"""
|
||||||
|
names = []
|
||||||
|
for key, value in urllib.parse.parse_qsl(map_query, keep_blank_values=True):
|
||||||
|
if key == "filter" and ":" in value:
|
||||||
|
names.append(value.split(":", 1)[0])
|
||||||
|
return names
|
||||||
|
|
||||||
|
|
||||||
|
def live_feature_names(base: str, timeout: float) -> set[str]:
|
||||||
|
"""Collect every feature `name` from the grouped {base}/api/features response."""
|
||||||
|
status, _ctype, body = http_get(f"{base}/api/features", timeout)
|
||||||
|
if status != 200:
|
||||||
|
raise RuntimeError(f"/api/features returned HTTP {status}")
|
||||||
|
payload = json.loads(body)
|
||||||
|
names: set[str] = set()
|
||||||
|
for group in payload.get("groups", []):
|
||||||
|
for feature in group.get("features", []):
|
||||||
|
name = feature.get("name")
|
||||||
|
if name:
|
||||||
|
names.add(name)
|
||||||
|
return names
|
||||||
|
|
||||||
|
|
||||||
|
def check_og(map_query: str, base: str, timeout: float) -> tuple[bool, str]:
|
||||||
|
"""Render the OG card and validate it looks like a real image."""
|
||||||
|
url = f"{base}/api/screenshot?og=1&{map_query}"
|
||||||
|
try:
|
||||||
|
status, ctype, body = http_get(url, timeout)
|
||||||
|
except Exception as exc: # network / HTTP error
|
||||||
|
return False, f"request failed: {exc}"
|
||||||
|
if status != 200:
|
||||||
|
return False, f"HTTP {status}"
|
||||||
|
if not ctype.lower().startswith("image/"):
|
||||||
|
return False, f"content-type {ctype!r} is not an image"
|
||||||
|
if len(body) < MIN_IMAGE_BYTES:
|
||||||
|
return False, f"image too small ({len(body)} B) - likely blank/error render"
|
||||||
|
if _HAVE_PIL:
|
||||||
|
try:
|
||||||
|
img = Image.open(BytesIO(body))
|
||||||
|
img.load() # force a full decode; raises on a corrupt image
|
||||||
|
w, h = img.size
|
||||||
|
except Exception as exc:
|
||||||
|
return False, f"undecodable image: {exc}"
|
||||||
|
if abs(w - OG_SIZE[0]) > SIZE_TOLERANCE or abs(h - OG_SIZE[1]) > SIZE_TOLERANCE:
|
||||||
|
return False, f"unexpected size {w}x{h} (want ~{OG_SIZE[0]}x{OG_SIZE[1]})"
|
||||||
|
return True, f"{len(body)} B, {w}x{h}"
|
||||||
|
return True, f"{len(body)} B"
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> int:
|
||||||
|
parser = argparse.ArgumentParser(description="Preflight OG cards for growth findings.")
|
||||||
|
parser.add_argument(
|
||||||
|
"--base", default=DEFAULT_BASE, help=f"server base URL (default {DEFAULT_BASE}; or $OG_BASE)"
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"--findings-dir", default=str(FINDINGS_DIR), help="directory of finding *.json files"
|
||||||
|
)
|
||||||
|
parser.add_argument(
|
||||||
|
"--timeout", type=float, default=30.0, help="per-request timeout in seconds (default 30)"
|
||||||
|
)
|
||||||
|
args = parser.parse_args()
|
||||||
|
base = args.base.rstrip("/")
|
||||||
|
|
||||||
|
finding_paths = sorted(Path(args.findings_dir).glob("*.json"))
|
||||||
|
if not finding_paths:
|
||||||
|
print(f"No findings found in {args.findings_dir}", file=sys.stderr)
|
||||||
|
return 2
|
||||||
|
|
||||||
|
# The drift guard needs the live feature list; if we cannot fetch it the
|
||||||
|
# whole gate is inconclusive, so bail out non-zero before checking cards.
|
||||||
|
try:
|
||||||
|
live_names = live_feature_names(base, args.timeout)
|
||||||
|
except Exception as exc:
|
||||||
|
print(f"FATAL: could not load {base}/api/features: {exc}", file=sys.stderr)
|
||||||
|
return 2
|
||||||
|
print(f"Loaded {len(live_names)} live feature names from {base}/api/features")
|
||||||
|
if not _HAVE_PIL:
|
||||||
|
print("(Pillow not installed - skipping image dimension check)")
|
||||||
|
|
||||||
|
passed = failed = 0
|
||||||
|
for path in finding_paths:
|
||||||
|
finding = json.loads(path.read_text())
|
||||||
|
slug = finding.get("slug", path.stem)
|
||||||
|
map_query = finding.get("map_query")
|
||||||
|
if not map_query:
|
||||||
|
print(f"FAIL {slug}: no map_query field")
|
||||||
|
failed += 1
|
||||||
|
continue
|
||||||
|
|
||||||
|
# Drift guard first: a renamed filter is the silent-ship bug we most
|
||||||
|
# want to catch, and it makes the rendered card meaningless anyway.
|
||||||
|
drifted = [n for n in filter_names(map_query) if n not in live_names]
|
||||||
|
og_ok, og_reason = check_og(map_query, base, args.timeout)
|
||||||
|
|
||||||
|
if drifted:
|
||||||
|
print(f"FAIL {slug}: unknown filter name(s): {', '.join(drifted)}")
|
||||||
|
failed += 1
|
||||||
|
elif not og_ok:
|
||||||
|
print(f"FAIL {slug}: OG render - {og_reason}")
|
||||||
|
failed += 1
|
||||||
|
else:
|
||||||
|
print(f"PASS {slug}: OG {og_reason}")
|
||||||
|
passed += 1
|
||||||
|
|
||||||
|
print(f"\n{passed} passed / {failed} failed (of {passed + failed})")
|
||||||
|
return 0 if failed == 0 else 1
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
sys.exit(main())
|
||||||
416
analysis/out/cheaper_twins.csv
Normal file
416
analysis/out/cheaper_twins.csv
Normal file
|
|
@ -0,0 +1,416 @@
|
||||||
|
pricey_sector,twin_sector,pricey_psqm,twin_psqm,gap_pct,gap_per_sqm,gap_on_avg_home,gap_on_90sqm,dist_km,dominant_type,build_year,good_secondary,station_km,pricey_lat,pricey_lon,twin_lat,twin_lon,pricey_n,twin_n
|
||||||
|
W1U 3,EC1N 7,16948,9362,44.8,7586,504469,682740,2.89,Flats/Maisonettes,1940,1.3,0.41,51.51712,-0.15271,51.52057,-0.11049,302,747
|
||||||
|
WC2R 1,SW1V 1,19997,11119,44.4,8878,665850,799020,2.82,Flats/Maisonettes,2017,2.0,0.21,51.51228,-0.11525,51.49297,-0.14234,316,1408
|
||||||
|
L8 7,L7 0,2757,1541,44.1,1216,78432,109440,2.36,Flats/Maisonettes,1914,2.3,1.04,53.39791,-2.96459,53.41174,-2.93813,2054,2208
|
||||||
|
L3 2,L5 5,1642,920,44.0,722,47291,64980,1.61,Flats/Maisonettes,2004,1.5,0.47,53.41155,-2.98583,53.42544,-2.97852,1341,706
|
||||||
|
S2 4,S3 9,2468,1402,43.2,1066,73554,95940,2.82,Flats/Maisonettes,1986,2.6,0.72,53.36993,-1.46978,53.39521,-1.46478,2423,1778
|
||||||
|
W1U 4,NW1 4,24238,13766,43.2,10472,759220,942480,0.97,Flats/Maisonettes,1940,1.0,0.44,51.51958,-0.15295,51.52803,-0.14886,984,1340
|
||||||
|
WC2A 2,EC2A 2,25482,14576,42.8,10906,834309,981540,2.3,Flats/Maisonettes,2019,2.0,0.42,51.51496,-0.11456,51.52119,-0.08217,254,772
|
||||||
|
M40 5,M9 4,2812,1626,42.2,1186,91915,106740,1.18,Terraced,1958,2.6,0.72,53.51372,-2.18713,53.51214,-2.20436,1632,3530
|
||||||
|
W11 2,NW1 6,19262,11154,42.1,8108,482426,729720,2.94,Flats/Maisonettes,1890,4.0,0.53,51.51407,-0.20373,51.5237,-0.16342,4082,3312
|
||||||
|
N10 3,N12 0,9590,5554,42.1,4036,296646,363240,2.97,Flats/Maisonettes,1914,3.9,1.16,51.58839,-0.14404,51.60872,-0.17254,3984,3282
|
||||||
|
W1U 1,SW1V 1,19096,11119,41.8,7977,506539,717930,2.54,Flats/Maisonettes,1986,2.0,0.17,51.51535,-0.15064,51.49297,-0.14234,416,1408
|
||||||
|
SW1X 8,SW7 2,26735,15611,41.6,11124,1301508,1001160,1.31,Flats/Maisonettes,1890,3.7,0.43,51.49787,-0.15472,51.49729,-0.17406,1410,1126
|
||||||
|
W1U 5,WC1E 6,20074,11756,41.4,8318,486603,748620,1.34,Flats/Maisonettes,1940,1.0,0.26,51.5214,-0.15392,51.52242,-0.13419,796,424
|
||||||
|
SW3 1,SW5 0,22813,13361,41.4,9452,652188,850680,1.82,Flats/Maisonettes,1914,3.0,0.39,51.49847,-0.16393,51.4925,-0.18898,1104,4266
|
||||||
|
HD4 5,HD1 3,2219,1301,41.4,918,65637,82620,1.79,Terraced,1940,5.0,1.12,53.63444,-1.81642,53.63808,-1.79069,4888,3052
|
||||||
|
W11 3,W12 9,15942,9343,41.4,6599,458630,593910,2.87,Flats/Maisonettes,1914,3.5,0.26,51.50961,-0.20173,51.50318,-0.24269,2643,5847
|
||||||
|
W1J 7,SW7 3,32986,19392,41.2,13594,1077324,1223460,2.6,Flats/Maisonettes,1914,2.0,0.3,51.5059,-0.14756,51.49122,-0.1775,724,2581
|
||||||
|
EC3N 1,EC1V 8,15538,9196,40.8,6342,383691,570780,2.25,Flats/Maisonettes,2021,0.0,0.15,51.51271,-0.07495,51.52808,-0.09657,162,1192
|
||||||
|
SE1 8,SE1 5,11517,6831,40.7,4686,285846,421740,2.8,Flats/Maisonettes,1998,4.8,0.26,51.50309,-0.10794,51.48984,-0.07272,2354,4478
|
||||||
|
EC1A 7,E1W 1,16062,9651,39.9,6411,413509,576990,2.52,Flats/Maisonettes,1999,0.0,0.2,51.51834,-0.09869,51.50581,-0.06777,574,1353
|
||||||
|
WC1B 5,EC1N 7,15504,9362,39.6,6142,411514,552780,0.98,Flats/Maisonettes,1914,1.4,0.26,51.52107,-0.12492,51.52057,-0.11049,168,747
|
||||||
|
EC3R 6,EC1A 9,19039,11553,39.3,7486,426702,673740,1.82,Flats/Maisonettes,2018,1.0,0.31,51.50832,-0.08023,51.5181,-0.10183,325,367
|
||||||
|
S2 5,S3 9,2308,1402,39.3,906,63873,81540,2.0,Flats/Maisonettes,1958,1.2,0.51,53.37989,-1.44909,53.39521,-1.46478,3807,1778
|
||||||
|
W1K 5,W2 3,19600,11893,39.3,7707,454713,693630,2.17,Flats/Maisonettes,1890,2.0,0.11,51.51346,-0.14947,51.513,-0.18143,233,5113
|
||||||
|
W1S 1,WC2E 7,24324,14910,38.7,9414,663687,847260,1.53,Flats/Maisonettes,2012,2.0,0.17,51.51339,-0.14384,51.51193,-0.1214,274,337
|
||||||
|
W13 0,UB1 3,8242,5063,38.6,3179,220940,286110,2.55,Flats/Maisonettes,1971,3.0,0.41,51.51603,-0.3258,51.51377,-0.36322,4716,2761
|
||||||
|
L9 9,L4 6,2410,1482,38.5,928,76096,83520,2.76,Terraced,1940,1.2,0.52,53.46789,-2.94392,53.44478,-2.95911,1898,1185
|
||||||
|
W1T 6,EC1N 7,15122,9362,38.1,5760,322560,518400,2.07,Flats/Maisonettes,1914,1.6,0.25,51.52266,-0.14074,51.52057,-0.11049,562,747
|
||||||
|
SW3 2,SW10 9,21360,13240,38.0,8120,596820,730800,1.66,Flats/Maisonettes,1890,3.5,0.44,51.49428,-0.16481,51.48648,-0.18567,2546,5825
|
||||||
|
WC2E 9,SW1V 2,16982,10522,38.0,6460,381140,581400,2.55,Flats/Maisonettes,1940,2.0,0.14,51.51211,-0.1249,51.49031,-0.13734,406,3528
|
||||||
|
SW10 0,SW11 3,12094,7514,37.9,4580,329760,412200,1.08,Flats/Maisonettes,1971,6.1,0.65,51.48064,-0.18125,51.47181,-0.17455,5124,7592
|
||||||
|
N2 9,N12 0,8942,5554,37.9,3388,255794,304920,1.92,Flats/Maisonettes,1940,3.5,0.73,51.59254,-0.16238,51.60872,-0.17254,2927,3282
|
||||||
|
B11 3,B11 1,2787,1741,37.5,1046,82111,94140,1.99,Terraced,1914,2.8,0.86,52.44872,-1.84954,52.46166,-1.86989,4748,3202
|
||||||
|
W1J 8,SW1A 2,27270,17088,37.3,10182,1089474,916380,1.31,Flats/Maisonettes,2000,2.0,0.18,51.50769,-0.1444,51.50557,-0.12549,295,261
|
||||||
|
W1H 6,NW1 4,21897,13766,37.1,8131,719593,731790,1.38,Flats/Maisonettes,1940,1.3,0.45,51.5162,-0.15546,51.52803,-0.14886,233,1340
|
||||||
|
B5 6,B16 8,4080,2588,36.6,1492,90266,134280,1.78,Flats/Maisonettes,2022,3.0,0.58,52.47243,-1.89503,52.47603,-1.92066,2784,5647
|
||||||
|
W1K 3,SW7 2,24608,15611,36.6,8997,1025658,809730,2.35,Flats/Maisonettes,1914,2.0,0.34,51.5108,-0.14739,51.49729,-0.17406,263,1126
|
||||||
|
W11 1,W12 8,13227,8399,36.5,4828,272782,434520,2.07,Flats/Maisonettes,1940,4.3,0.27,51.51697,-0.20643,51.5037,-0.22797,4436,4802
|
||||||
|
W1J 5,W8 5,26103,16629,36.3,9474,916609,852660,2.89,Flats/Maisonettes,1914,2.0,0.4,51.50796,-0.14833,51.49913,-0.1884,503,2829
|
||||||
|
E7 0,IG1 3,7737,4926,36.3,2811,195364,252990,2.75,Flats/Maisonettes,1914,2.1,0.38,51.552,0.02729,51.56639,0.06025,4114,5219
|
||||||
|
BB1 8,BB1 6,2318,1498,35.4,820,75030,73800,0.97,Terraced,1958,3.0,1.48,53.76182,-2.48651,53.75666,-2.47488,3550,1175
|
||||||
|
M4 6,M3 1,4332,2797,35.4,1535,103612,138150,1.56,Flats/Maisonettes,2016,3.2,0.46,53.48377,-2.2243,53.48836,-2.24596,3944,1313
|
||||||
|
N10 2,N12 0,8571,5554,35.2,3017,209681,271530,2.29,Flats/Maisonettes,1940,3.7,1.29,51.59958,-0.14231,51.60872,-0.17254,3792,3282
|
||||||
|
E2 7,E1 4,10016,6518,34.9,3498,227370,314820,1.87,Flats/Maisonettes,1958,4.9,0.41,51.52816,-0.07104,51.52181,-0.04552,3508,4193
|
||||||
|
W11 4,W6 0,15604,10152,34.9,5452,346202,490680,1.98,Flats/Maisonettes,1958,3.6,0.35,51.50884,-0.21361,51.49621,-0.23419,4044,6681
|
||||||
|
NW10 1,NW10 0,7284,4776,34.4,2508,169290,225720,1.21,Flats/Maisonettes,1940,2.1,0.37,51.55484,-0.2425,51.55677,-0.25998,3163,3308
|
||||||
|
NW1 8,N7 9,12470,8179,34.4,4291,276769,386190,2.09,Flats/Maisonettes,1958,2.8,0.32,51.54247,-0.15026,51.54901,-0.12137,4113,4630
|
||||||
|
M19 3,M18 8,2911,1916,34.2,995,74127,89550,2.51,Terraced,1914,3.3,0.61,53.44574,-2.18452,53.46589,-2.16737,4046,4415
|
||||||
|
SW1X 0,SW7 5,23489,15480,34.1,8009,784882,720810,1.31,Flats/Maisonettes,1890,3.1,0.45,51.49639,-0.16144,51.49667,-0.18078,1606,3238
|
||||||
|
W1K 6,W8 4,23400,15425,34.1,7975,626037,717750,2.83,Flats/Maisonettes,1914,2.0,0.29,51.5128,-0.15349,51.50498,-0.19312,562,2309
|
||||||
|
NW3 1,NW6 3,16761,11048,34.1,5713,437044,514170,1.65,Flats/Maisonettes,1914,1.2,0.33,51.5575,-0.17458,51.54407,-0.18523,2098,4073
|
||||||
|
WC1A 2,EC1N 7,14183,9362,34.0,4821,310954,433890,0.94,Flats/Maisonettes,1914,1.7,0.28,51.51831,-0.12387,51.52057,-0.11049,234,747
|
||||||
|
E9 7,E3 4,9732,6430,33.9,3302,224536,297180,2.4,Flats/Maisonettes,1958,5.6,0.6,51.53924,-0.04918,51.52221,-0.02733,4570,6823
|
||||||
|
BD21 1,BD21 2,1419,938,33.9,481,37999,43290,1.01,Terraced,1914,1.7,0.7,53.85976,-1.91701,53.86885,-1.9178,2292,2303
|
||||||
|
SW10 9,W14 9,13240,8770,33.8,4470,270435,402300,1.55,Flats/Maisonettes,1914,4.5,0.63,51.48648,-0.18567,51.48883,-0.20815,5825,7258
|
||||||
|
L22 5,L21 3,2224,1472,33.8,752,48880,67680,1.65,Flats/Maisonettes,1958,0.8,0.28,53.47329,-3.02717,53.46477,-3.00727,821,259
|
||||||
|
EC2A 2,E1W 1,14576,9651,33.8,4925,354600,443250,1.96,Flats/Maisonettes,2021,0.8,0.33,51.52119,-0.08217,51.50581,-0.06777,772,1353
|
||||||
|
L20 7,L5 7,1728,1146,33.7,582,42195,52380,1.59,Terraced,1979,2.0,0.39,53.44391,-2.99118,53.42998,-2.98541,1243,848
|
||||||
|
B6 6,B21 9,2148,1428,33.5,720,63000,64800,2.92,Terraced,1914,3.9,0.74,52.50775,-1.89127,52.50746,-1.93433,2834,3409
|
||||||
|
B15 1,B16 8,3888,2588,33.4,1300,74100,117000,0.49,Flats/Maisonettes,2018,2.2,0.17,52.47397,-1.9142,52.47603,-1.92066,2987,5647
|
||||||
|
W1F 9,SW1V 2,15806,10522,33.4,5284,272126,475560,2.44,Flats/Maisonettes,1940,2.0,0.32,51.51241,-0.13704,51.49031,-0.13734,340,3528
|
||||||
|
E17 6,N15 6,8263,5515,33.3,2748,186864,247320,2.95,Flats/Maisonettes,1958,2.9,0.49,51.58862,-0.03531,51.57766,-0.07499,8292,4196
|
||||||
|
N5 1,N7 7,10770,7185,33.3,3585,227647,322650,0.69,Flats/Maisonettes,1958,3.5,0.31,51.55439,-0.10301,51.55818,-0.11109,5686,3539
|
||||||
|
W1W 5,EC1R 4,14857,9931,33.2,4926,310338,443340,2.41,Flats/Maisonettes,1971,1.0,0.19,51.52234,-0.14327,51.52666,-0.10846,790,634
|
||||||
|
W1H 7,NW1 5,15131,10126,33.1,5005,402902,450450,0.69,Flats/Maisonettes,1914,1.4,0.33,51.51532,-0.15973,51.52135,-0.16228,1094,1593
|
||||||
|
SW11 4,SW11 3,11216,7514,33.0,3702,264693,333180,1.24,Flats/Maisonettes,1971,5.4,0.72,51.47665,-0.15803,51.47181,-0.17455,5268,7592
|
||||||
|
W7 3,UB1 3,7546,5063,32.9,2483,175051,223470,1.66,Flats/Maisonettes,1958,3.8,0.56,51.51276,-0.33883,51.51377,-0.36322,4515,2761
|
||||||
|
B68 8,B67 7,3056,2053,32.8,1003,79237,90270,2.09,Terraced,1958,3.1,0.84,52.48621,-2.00783,52.49476,-1.98036,3700,2852
|
||||||
|
W1F 7,SW1V 1,16512,11119,32.7,5393,320883,485370,2.28,Flats/Maisonettes,1971,2.0,0.27,51.51336,-0.13775,51.49297,-0.14234,382,1408
|
||||||
|
L32 0,L33 9,2106,1422,32.5,684,53010,61560,2.16,Terraced,1958,1.9,0.42,53.48356,-2.90176,53.49051,-2.87196,1371,821
|
||||||
|
L7 7,L3 2,2432,1642,32.5,790,46215,71100,1.87,Flats/Maisonettes,2004,1.2,1.01,53.40015,-2.96557,53.41155,-2.98583,910,1341
|
||||||
|
L13 1,L7 4,2015,1363,32.4,652,42054,58680,2.09,Terraced,1940,4.3,0.4,53.40739,-2.91819,53.39725,-2.94425,610,401
|
||||||
|
W1G 9,WC1E 7,18377,12426,32.4,5951,499884,535590,1.07,Flats/Maisonettes,1940,1.5,0.42,51.51814,-0.14732,51.52141,-0.13245,426,386
|
||||||
|
L8 3,L8 0,2096,1420,32.3,676,42926,60840,0.81,Flats/Maisonettes,1914,5.0,1.28,53.38744,-2.95519,53.39354,-2.94861,2200,3137
|
||||||
|
E2 8,E1 4,9634,6518,32.3,3116,200982,280440,2.17,Flats/Maisonettes,1995,6.8,0.36,51.53258,-0.07231,51.52181,-0.04552,3891,4193
|
||||||
|
N1 1,NW1 9,13560,9213,32.1,4347,269514,391230,1.64,Flats/Maisonettes,1914,2.3,0.41,51.54168,-0.10954,51.544,-0.13333,5369,4459
|
||||||
|
W3 6,NW10 8,7977,5414,32.1,2563,144809,230670,2.88,Flats/Maisonettes,1999,2.8,0.28,51.51541,-0.26423,51.54116,-0.25786,8573,4510
|
||||||
|
NW1 4,EC1N 7,13766,9362,32.0,4404,295068,396360,2.73,Flats/Maisonettes,1940,1.9,0.42,51.52803,-0.14886,51.52057,-0.11049,1340,747
|
||||||
|
L1 5,L3 2,2416,1642,32.0,774,47988,69660,1.28,Flats/Maisonettes,2004,2.8,0.51,53.40039,-2.98092,53.41155,-2.98583,1724,1341
|
||||||
|
N1 4,E2 0,10333,7036,31.9,3297,212656,296730,2.99,Flats/Maisonettes,1940,7.1,0.41,51.54667,-0.0819,51.52807,-0.04998,3830,4330
|
||||||
|
SE1 9,SE1 3,13534,9218,31.9,4316,308594,388440,1.69,Flats/Maisonettes,2009,3.4,0.4,51.50702,-0.10046,51.49842,-0.07986,2358,4683
|
||||||
|
SW7 3,SW10 9,19392,13240,31.7,6152,453710,553680,0.76,Flats/Maisonettes,1890,3.3,0.41,51.49122,-0.1775,51.48648,-0.18567,2581,5825
|
||||||
|
W1K 2,SW1X 0,34362,23489,31.6,10873,1293887,978570,1.62,Flats/Maisonettes,1914,2.0,0.5,51.50983,-0.15202,51.49639,-0.16144,591,1606
|
||||||
|
E8 4,E2 0,10272,7036,31.5,3236,207104,291240,1.79,Flats/Maisonettes,1979,7.2,0.34,51.53852,-0.07013,51.52807,-0.04998,4554,4330
|
||||||
|
SW12 9,SW16 2,9262,6351,31.4,2911,190670,261990,2.33,Flats/Maisonettes,1914,5.7,0.38,51.44479,-0.1475,51.43068,-0.12196,5519,7620
|
||||||
|
BR3 3,CR0 7,7153,4910,31.4,2243,214206,201870,2.02,Terraced,1940,7.8,0.73,51.3949,-0.03019,51.38447,-0.05469,4514,5143
|
||||||
|
NE8 3,NE6 2,1812,1248,31.1,564,35814,50760,2.38,Flats/Maisonettes,1986,1.5,0.5,54.95623,-1.58964,54.97313,-1.568,3727,4445
|
||||||
|
KT13 8,KT15 2,6738,4663,30.8,2075,150437,186750,1.98,Flats/Maisonettes,1971,3.7,1.25,51.37281,-0.45766,51.3727,-0.48684,3317,4145
|
||||||
|
W2 5,W10 4,13145,9102,30.8,4043,254709,363870,1.73,Flats/Maisonettes,1914,3.6,0.38,51.51783,-0.19337,51.52944,-0.21048,5062,3629
|
||||||
|
WC1A 1,W1T 1,23988,16609,30.8,7379,472256,664110,0.48,Flats/Maisonettes,2016,2.0,0.21,51.517,-0.1274,51.51779,-0.1344,241,584
|
||||||
|
EC1V 2,EC1V 8,13244,9196,30.6,4048,267168,364320,0.11,Flats/Maisonettes,2020,0.1,0.55,51.52885,-0.09564,51.52808,-0.09657,1056,1192
|
||||||
|
W2 4,W1H 5,15000,10428,30.5,4572,290322,411480,2.0,Flats/Maisonettes,1914,2.1,0.28,51.51248,-0.19214,51.5169,-0.16353,5441,1194
|
||||||
|
N15 5,N17 0,7488,5207,30.5,2281,141422,205290,2.58,Flats/Maisonettes,1940,2.6,0.47,51.58315,-0.08094,51.60306,-0.06115,3757,4447
|
||||||
|
W1K 4,W1G 6,22808,15856,30.5,6952,590920,625680,1.05,Flats/Maisonettes,1940,2.0,0.23,51.51197,-0.14832,51.52144,-0.15008,229,588
|
||||||
|
NW2 1,NW2 7,7494,5224,30.3,2270,164575,204300,1.95,Flats/Maisonettes,1958,1.4,0.52,51.56613,-0.21393,51.56404,-0.24245,3610,3368
|
||||||
|
SE4 2,SE6 2,7845,5474,30.2,2371,156486,213390,2.85,Flats/Maisonettes,1914,1.0,0.39,51.46145,-0.04025,51.44106,-0.01466,5138,5519
|
||||||
|
B18 4,B21 9,2042,1428,30.1,614,48506,55260,1.65,Terraced,1914,2.7,0.69,52.49286,-1.93966,52.50746,-1.93433,1927,3409
|
||||||
|
L8 8,L7 4,1950,1363,30.1,587,40796,52830,1.55,Terraced,1940,3.8,1.13,53.39004,-2.96384,53.39725,-2.94425,1868,401
|
||||||
|
NW10 5,NW10 2,10106,7078,30.0,3028,199848,272520,1.75,Flats/Maisonettes,1914,3.0,0.4,51.5329,-0.2278,51.54767,-0.23691,5023,3505
|
||||||
|
B19 3,B7 4,3417,2397,29.9,1020,69360,91800,1.88,Flats/Maisonettes,1958,2.0,0.47,52.49095,-1.90381,52.48861,-1.87637,1584,1469
|
||||||
|
W1U 7,WC1N 2,18854,13224,29.9,5630,375802,506700,2.67,Flats/Maisonettes,1914,1.0,0.44,51.51885,-0.15472,51.52321,-0.11611,216,514
|
||||||
|
L15 4,L7 4,1942,1363,29.8,579,39661,52110,1.33,Terraced,1914,3.2,0.52,53.40136,-2.9259,53.39725,-2.94425,2027,401
|
||||||
|
CH62 8,CH62 9,3363,2362,29.8,1001,81831,90090,0.74,Semi-Detached,1958,4.0,0.91,53.31456,-2.97287,53.30801,-2.97057,1775,1274
|
||||||
|
SE1 0,SE1 5,9712,6831,29.7,2881,167098,259290,2.32,Flats/Maisonettes,2005,5.6,0.41,51.5023,-0.10018,51.48984,-0.07272,2736,4478
|
||||||
|
SE28 8,DA18 4,4850,3409,29.7,1441,104112,129690,1.72,Terraced,1993,2.8,1.39,51.5066,0.11805,51.49419,0.1333,5033,1063
|
||||||
|
BD21 2,BD21 3,938,660,29.6,278,24186,25020,0.88,Terraced,1914,2.0,1.07,53.86885,-1.9178,53.87113,-1.90541,2303,1377
|
||||||
|
W7 1,UB1 3,7184,5063,29.5,2121,148470,190890,2.06,Flats/Maisonettes,1958,3.8,0.36,51.51927,-0.3343,51.51377,-0.36322,3765,2761
|
||||||
|
L16 7,L14 6,4026,2840,29.5,1186,117414,106740,1.88,Semi-Detached,1940,5.1,1.22,53.39586,-2.89157,53.41102,-2.87901,500,809
|
||||||
|
W1G 8,WC1N 2,18737,13224,29.4,5513,395557,496170,2.31,Flats/Maisonettes,1914,1.0,0.49,51.51913,-0.14944,51.52321,-0.11611,707,514
|
||||||
|
L6 1,L5 8,2573,1818,29.3,755,47376,67950,1.72,Flats/Maisonettes,2009,2.0,1.1,53.41331,-2.96373,53.42093,-2.98578,1468,800
|
||||||
|
W12 7,W12 0,11848,8378,29.3,3470,225550,312300,0.73,Flats/Maisonettes,1958,2.7,0.37,51.51063,-0.22867,51.51319,-0.23865,7409,5147
|
||||||
|
NW8 0,W2 2,13358,9441,29.3,3917,272231,352530,2.73,Flats/Maisonettes,1958,3.0,0.38,51.53784,-0.18192,51.51475,-0.1679,2625,4150
|
||||||
|
W1K 1,W1G 7,28754,20358,29.2,8396,812313,755640,1.52,Flats/Maisonettes,1940,2.0,0.49,51.50754,-0.15204,51.52096,-0.14696,288,280
|
||||||
|
WC1N 2,EC1N 7,13224,9362,29.2,3862,230754,347580,0.48,Flats/Maisonettes,1914,0.9,0.53,51.52321,-0.11611,51.52057,-0.11049,514,747
|
||||||
|
BB11 2,BB11 3,1455,1032,29.1,423,32042,38070,0.74,Terraced,1914,0.1,0.71,53.78136,-2.24549,53.78377,-2.23529,1925,2642
|
||||||
|
E11 3,E12 5,7858,5570,29.1,2288,156728,205920,2.78,Flats/Maisonettes,1940,2.9,0.65,51.56154,0.01383,51.55444,0.05315,5821,5288
|
||||||
|
L3 5,L3 2,2315,1642,29.1,673,38697,60570,0.98,Flats/Maisonettes,2004,1.5,0.34,53.40732,-2.97319,53.41155,-2.98583,1300,1341
|
||||||
|
IG1 2,IG11 8,5300,3768,28.9,1532,98814,137880,1.16,Flats/Maisonettes,1986,2.6,0.81,51.5513,0.07504,51.5409,0.07766,7114,4525
|
||||||
|
E8 3,E1 4,9141,6518,28.7,2623,174429,236070,2.67,Flats/Maisonettes,1999,6.7,0.32,51.54269,-0.0654,51.52181,-0.04552,4980,4193
|
||||||
|
E17 9,E10 7,9498,6778,28.6,2720,175440,244800,1.56,Flats/Maisonettes,1914,2.3,0.52,51.5812,-0.01156,51.56938,-0.02405,5616,4807
|
||||||
|
B20 3,B21 9,2000,1428,28.6,572,49764,51480,2.0,Terraced,1914,2.4,0.76,52.51116,-1.90551,52.50746,-1.93433,4683,3409
|
||||||
|
SW1Y 6,WC2H 9,19050,13619,28.5,5431,353015,488790,1.02,Flats/Maisonettes,1914,2.0,0.26,51.50775,-0.13677,51.51405,-0.12585,343,726
|
||||||
|
EC2Y 8,E1W 1,13481,9651,28.4,3830,268100,344700,2.4,Flats/Maisonettes,1971,0.0,0.2,51.52001,-0.09446,51.50581,-0.06777,2082,1353
|
||||||
|
L15 1,L7 4,1902,1363,28.3,539,35843,48510,0.76,Terraced,1914,4.0,0.84,53.39986,-2.93392,53.39725,-2.94425,1301,401
|
||||||
|
NW6 2,NW2 5,9924,7120,28.3,2804,165436,252360,2.23,Flats/Maisonettes,1940,1.5,0.27,51.54603,-0.19676,51.54856,-0.22936,3822,4370
|
||||||
|
NW3 6,NW11 8,10350,7423,28.3,2927,191718,263430,2.42,Flats/Maisonettes,1914,1.8,0.22,51.55188,-0.1812,51.57032,-0.2005,3182,2951
|
||||||
|
NE1 2,NE8 3,2524,1812,28.2,712,41296,64080,1.88,Flats/Maisonettes,2003,2.6,0.41,54.97209,-1.59959,54.95623,-1.58964,1713,3727
|
||||||
|
WC1R 4,EC1Y 8,12388,8894,28.2,3494,204399,314460,1.82,Flats/Maisonettes,1958,1.0,0.28,51.51938,-0.11755,51.5234,-0.09159,362,1020
|
||||||
|
B8 3,B8 1,2451,1761,28.2,690,55200,62100,0.95,Terraced,1914,3.9,1.07,52.48814,-1.84204,52.49094,-1.85524,4026,2834
|
||||||
|
TW12 2,TW16 5,8001,5764,28.0,2237,189585,201330,2.42,Flats/Maisonettes,1958,1.5,0.51,51.41708,-0.37008,51.41307,-0.4051,3364,2205
|
||||||
|
W4 1,W3 0,10328,7440,28.0,2888,254144,259920,2.74,Flats/Maisonettes,1914,2.3,0.41,51.49721,-0.25518,51.5193,-0.2734,3571,2316
|
||||||
|
B1 3,B16 8,3590,2588,27.9,1002,60120,90180,1.04,Flats/Maisonettes,2017,2.0,0.52,52.48455,-1.91433,52.47603,-1.92066,2657,5647
|
||||||
|
W1W 7,SW1P 4,15530,11191,27.9,4339,269018,390510,2.94,Flats/Maisonettes,1979,1.9,0.35,51.51856,-0.14057,51.49278,-0.1299,602,3443
|
||||||
|
WC1N 1,WC1H 8,12880,9294,27.8,3586,188265,322740,0.42,Flats/Maisonettes,1940,2.3,0.21,51.52432,-0.12359,51.5279,-0.12161,1191,815
|
||||||
|
SW8 1,SE5 0,9368,6774,27.7,2594,164719,233460,1.7,Flats/Maisonettes,1960,4.3,0.37,51.48059,-0.12115,51.47961,-0.09617,6064,3441
|
||||||
|
E20 1,E15 2,8586,6208,27.7,2378,160515,214020,0.88,Flats/Maisonettes,2017,3.9,0.28,51.54601,-0.00917,51.53827,-0.00621,6585,6157
|
||||||
|
EC1Y 1,EC1V 9,11663,8443,27.6,3220,214130,289800,0.26,Flats/Maisonettes,2010,1.0,0.1,51.52492,-0.08698,51.52596,-0.09038,155,960
|
||||||
|
N15 3,N17 0,7178,5207,27.5,1971,116289,177390,3.0,Flats/Maisonettes,1914,3.4,0.67,51.58598,-0.09545,51.60306,-0.06115,4481,4447
|
||||||
|
W1T 1,SW1Y 4,16609,12054,27.4,4555,247108,409950,1.01,Flats/Maisonettes,1993,2.0,0.2,51.51779,-0.1344,51.50869,-0.1327,584,176
|
||||||
|
N7 9,NW1 3,8179,5948,27.3,2231,142784,200790,2.66,Flats/Maisonettes,1971,3.7,0.39,51.54901,-0.12137,51.5281,-0.14076,4630,1949
|
||||||
|
L22 9,L22 4,2838,2067,27.2,771,74208,69390,0.51,Terraced,1914,1.4,0.47,53.47895,-3.02768,53.47998,-3.02039,567,716
|
||||||
|
HU1 2,HU2 8,2320,1690,27.2,630,34335,56700,0.77,Flats/Maisonettes,1979,1.1,0.49,53.74094,-0.34259,53.74792,-0.34183,1177,1146
|
||||||
|
SE1 3,SE16 3,9218,6721,27.1,2497,157311,224730,1.33,Flats/Maisonettes,1999,4.8,0.77,51.49842,-0.07986,51.49091,-0.06454,4683,4240
|
||||||
|
LE1 6,LE1 3,2159,1576,27.0,583,26526,52470,0.95,Flats/Maisonettes,2004,5.4,0.42,52.63073,-1.13046,52.63932,-1.13017,2093,1426
|
||||||
|
BB2 3,BB1 1,1608,1174,27.0,434,35154,39060,1.5,Terraced,1971,3.5,1.42,53.73342,-2.47718,53.74438,-2.4641,4798,3580
|
||||||
|
N1 2,N7 6,11472,8394,26.8,3078,192375,277020,2.21,Flats/Maisonettes,1940,3.2,0.32,51.54325,-0.09732,51.55896,-0.11742,4823,3705
|
||||||
|
L35 3,L34 6,2438,1786,26.7,652,48574,58680,2.38,Terraced,1971,0.8,0.61,53.41043,-2.7958,53.43186,-2.79945,3080,858
|
||||||
|
B33 0,B37 5,2704,1984,26.6,720,53640,64800,1.46,Terraced,1958,4.1,1.06,52.47541,-1.77066,52.47855,-1.74975,4058,3580
|
||||||
|
W1W 6,EC1N 7,12734,9362,26.5,3372,180402,303480,2.11,Flats/Maisonettes,1914,1.0,0.41,51.52013,-0.14163,51.52057,-0.11049,946,747
|
||||||
|
E2 6,E1 4,8850,6518,26.4,2332,148082,209880,1.38,Flats/Maisonettes,1986,5.7,0.41,51.52646,-0.06445,51.52181,-0.04552,3414,4193
|
||||||
|
SW17 8,SW16 2,8612,6351,26.3,2261,151487,203490,2.36,Flats/Maisonettes,1914,5.9,0.49,51.43266,-0.1565,51.43068,-0.12196,7040,7620
|
||||||
|
LE1 4,LE1 3,2136,1576,26.2,560,26600,50400,0.58,Flats/Maisonettes,2018,4.5,1.17,52.63787,-1.13834,52.63932,-1.13017,1436,1426
|
||||||
|
B15 2,B16 8,3508,2588,26.2,920,57960,82800,1.21,Flats/Maisonettes,2004,2.5,0.59,52.46686,-1.91097,52.47603,-1.92066,4678,5647
|
||||||
|
NE31 2,NE32 3,2197,1629,25.9,568,43452,51120,2.31,Semi-Detached,1958,1.7,1.14,54.96595,-1.50844,54.97725,-1.47983,4787,2350
|
||||||
|
W1T 2,EC4V 5,15137,11220,25.9,3917,230123,352530,2.37,Flats/Maisonettes,1914,1.5,0.15,51.51933,-0.13475,51.51284,-0.10141,334,208
|
||||||
|
SK6 6,SK6 3,4485,3329,25.8,1156,99416,104040,2.56,Semi-Detached,1958,1.0,0.5,53.3973,-2.07179,53.41157,-2.1014,2365,1915
|
||||||
|
SE1 1,SE16 3,9062,6721,25.8,2341,145142,210690,2.34,Flats/Maisonettes,1999,4.3,0.23,51.50157,-0.09427,51.49091,-0.06454,1565,4240
|
||||||
|
SW3 3,SW10 9,17851,13240,25.8,4611,262827,414990,1.42,Flats/Maisonettes,1940,4.1,0.55,51.49144,-0.1664,51.48648,-0.18567,3413,5825
|
||||||
|
E12 5,IG1 1,5570,4137,25.7,1433,99593,128970,1.98,Flats/Maisonettes,1940,1.6,0.73,51.55444,0.05315,51.55757,0.0819,5288,4839
|
||||||
|
WC1X 0,EC1A 4,13653,10144,25.7,3509,236857,315810,1.29,Flats/Maisonettes,2012,0.2,0.62,51.52581,-0.11375,51.51977,-0.09756,1688,188
|
||||||
|
B33 9,B37 5,2667,1984,25.6,683,49176,61470,2.98,Terraced,1958,3.0,0.74,52.48615,-1.79185,52.47855,-1.74975,3962,3580
|
||||||
|
W1B 1,W1G 9,24699,18377,25.6,6322,678034,568980,0.43,Flats/Maisonettes,1958,1.1,0.17,51.52197,-0.14618,51.51814,-0.14732,466,426
|
||||||
|
SW17 9,CR4 2,8157,6067,25.6,2090,145777,188100,1.15,Flats/Maisonettes,1914,5.0,0.44,51.42261,-0.16219,51.41288,-0.15632,6187,4538
|
||||||
|
EC1Y 0,EC1Y 8,11961,8894,25.6,3067,181719,276030,0.3,Flats/Maisonettes,1971,0.0,0.29,51.52254,-0.09582,51.5234,-0.09159,686,1020
|
||||||
|
IG8 7,IG6 2,7148,5325,25.5,1823,143105,164070,2.98,Terraced,1958,2.8,0.58,51.60562,0.03933,51.59914,0.08194,2965,4423
|
||||||
|
LS28 5,LS28 6,3598,2682,25.5,916,68242,82440,1.38,Terraced,1958,1.6,1.24,53.81629,-1.67775,53.80707,-1.66403,4799,1534
|
||||||
|
WC2E 7,SW1V 1,14910,11119,25.4,3791,242624,341190,2.53,Flats/Maisonettes,1986,2.0,0.26,51.51193,-0.1214,51.49297,-0.14234,337,1408
|
||||||
|
DN35 7,DN32 9,1278,954,25.4,324,27864,29160,1.8,Terraced,1914,1.2,0.9,53.56767,-0.04891,53.56012,-0.07242,4576,3714
|
||||||
|
SE22 9,SE23 1,10024,7474,25.4,2550,178500,229500,2.36,Flats/Maisonettes,1914,4.6,0.82,51.4571,-0.0718,51.446,-0.04209,3946,3974
|
||||||
|
N16 0,E5 9,10653,7944,25.4,2709,174730,243810,1.72,Flats/Maisonettes,1940,5.9,0.64,51.56195,-0.07997,51.56528,-0.0553,3007,5763
|
||||||
|
CH43 7,CH49 8,2680,2001,25.3,679,53301,61110,2.7,Terraced,1979,4.2,0.84,53.39925,-3.07298,53.37667,-3.08801,2619,1101
|
||||||
|
CH1 2,CH1 3,3642,2720,25.3,922,59008,82980,0.87,Flats/Maisonettes,1994,2.7,1.23,53.19006,-2.89451,53.19535,-2.88502,842,2725
|
||||||
|
N1C 4,N1 7,14255,10642,25.3,3613,251103,325170,2.36,Flats/Maisonettes,2018,2.5,0.6,51.53756,-0.12621,51.5324,-0.09254,1949,5352
|
||||||
|
NW2 2,NW2 7,6991,5224,25.3,1767,122806,159030,2.74,Flats/Maisonettes,1958,0.9,0.82,51.56242,-0.20213,51.56404,-0.24245,3603,3368
|
||||||
|
SW15 6,SW19 6,8335,6233,25.2,2102,145038,189180,1.89,Flats/Maisonettes,1958,4.0,0.64,51.4602,-0.22549,51.44413,-0.21583,4327,4199
|
||||||
|
HA0 4,NW10 0,6382,4776,25.2,1606,114026,144540,2.84,Flats/Maisonettes,1940,3.7,0.41,51.54606,-0.29796,51.55677,-0.25998,3934,3308
|
||||||
|
NE22 7,NE22 5,2220,1662,25.1,558,41292,50220,1.25,Semi-Detached,1958,2.8,0.9,55.1417,-1.56867,55.13372,-1.58167,1369,3178
|
||||||
|
B13 8,B13 9,3557,2669,25.0,888,59940,79920,1.35,Flats/Maisonettes,1958,3.3,0.65,52.44751,-1.89353,52.44314,-1.87493,3567,6454
|
||||||
|
L1 2,L3 8,2481,1863,24.9,618,35226,55620,0.97,Flats/Maisonettes,2006,1.0,0.33,53.40313,-2.97495,53.41171,-2.97208,531,1603
|
||||||
|
SE21 8,SW16 3,7738,5811,24.9,1927,150306,173430,2.71,Flats/Maisonettes,1940,5.2,0.47,51.4369,-0.09319,51.4182,-0.11905,4505,3133
|
||||||
|
SW7 1,SW1A 1,22459,16895,24.8,5564,730275,500760,1.99,Flats/Maisonettes,1940,2.9,0.46,51.50025,-0.16756,51.50602,-0.13973,1864,229
|
||||||
|
N3 2,N12 0,7373,5554,24.7,1819,123692,163710,1.22,Flats/Maisonettes,1940,3.2,0.52,51.60127,-0.18578,51.60872,-0.17254,3926,3282
|
||||||
|
W1H 1,W1H 4,18118,13634,24.7,4484,242136,403560,0.25,Flats/Maisonettes,1914,2.5,0.28,51.52019,-0.16119,51.51941,-0.16464,626,484
|
||||||
|
SW5 9,W6 8,13297,10011,24.7,3286,190588,295740,1.49,Flats/Maisonettes,1914,3.4,0.24,51.49114,-0.19565,51.48654,-0.21631,5808,3253
|
||||||
|
SE15 4,SE23 1,9910,7474,24.6,2436,171738,219240,2.95,Flats/Maisonettes,1914,3.4,0.46,51.46584,-0.07115,51.446,-0.04209,3545,3974
|
||||||
|
E8 2,E2 0,9330,7036,24.6,2294,144522,206460,2.8,Flats/Maisonettes,1940,6.8,0.39,51.55034,-0.0696,51.52807,-0.04998,4333,4330
|
||||||
|
W1U 6,W2 6,14569,10990,24.6,3579,238003,322110,1.81,Flats/Maisonettes,1914,1.0,0.23,51.52059,-0.15781,51.51704,-0.18386,1075,4210
|
||||||
|
SE16 6,E14 3,8241,6225,24.5,2016,139104,181440,2.21,Flats/Maisonettes,1993,1.7,0.54,51.50061,-0.04314,51.49193,-0.01389,1940,8179
|
||||||
|
SW13 9,W4 5,12220,9220,24.5,3000,231750,270000,2.61,Flats/Maisonettes,1940,2.5,0.93,51.48023,-0.24118,51.49745,-0.26758,2631,4935
|
||||||
|
L22 6,L22 7,3710,2800,24.5,910,73710,81900,0.4,Semi-Detached,1940,0.0,0.7,53.48144,-3.04085,53.47948,-3.03589,464,450
|
||||||
|
L3 0,L5 9,2906,2198,24.4,708,47790,63720,1.03,Flats/Maisonettes,2001,1.0,1.03,53.41642,-3.00063,53.42433,-2.99258,1085,525
|
||||||
|
WC2B 5,SW1V 1,14709,11119,24.4,3590,211810,323100,2.86,Flats/Maisonettes,1971,2.0,0.21,51.5155,-0.1218,51.49297,-0.14234,891,1408
|
||||||
|
W10 5,NW6 5,10968,8303,24.3,2665,163897,239850,1.66,Flats/Maisonettes,1971,4.0,0.55,51.5225,-0.21145,51.53337,-0.19455,5247,4901
|
||||||
|
L16 5,L14 6,3753,2840,24.3,913,79431,82170,1.4,Semi-Detached,1940,4.7,0.97,53.3991,-2.88607,53.41102,-2.87901,453,809
|
||||||
|
NE1 3,NE1 6,2754,2090,24.1,664,36520,59760,0.55,Flats/Maisonettes,2008,2.3,0.35,54.96753,-1.61131,54.972,-1.60784,903,712
|
||||||
|
W1T 3,SW1P 2,15879,12102,23.8,3777,247393,339930,2.58,Flats/Maisonettes,2015,1.9,0.3,51.51842,-0.13787,51.49529,-0.13253,827,2039
|
||||||
|
N1 8,NW1 9,12078,9213,23.7,2865,181927,257850,2.53,Flats/Maisonettes,1940,1.4,0.41,51.53533,-0.09877,51.544,-0.13333,3569,4459
|
||||||
|
SW1W 0,SW1E 5,16694,12733,23.7,3961,354509,356490,0.38,Flats/Maisonettes,1979,3.3,0.21,51.49667,-0.146,51.49843,-0.14124,595,272
|
||||||
|
L1 3,L2 0,2929,2234,23.7,695,33360,62550,0.5,Flats/Maisonettes,2009,2.0,0.39,53.40327,-2.98663,53.40563,-2.99288,365,609
|
||||||
|
KT2 5,KT2 7,8290,6333,23.6,1957,148732,176130,1.59,Flats/Maisonettes,1995,2.4,0.94,51.42071,-0.30084,51.41822,-0.27782,6209,3298
|
||||||
|
E1 2,E1 4,8529,6518,23.6,2011,120660,180990,1.1,Flats/Maisonettes,1999,6.2,0.3,51.51519,-0.0577,51.52181,-0.04552,3511,4193
|
||||||
|
SW1H 9,EC4V 3,14058,10757,23.5,3301,209613,297090,2.75,Flats/Maisonettes,1999,3.0,0.2,51.50018,-0.13284,51.51065,-0.09613,289,315
|
||||||
|
WV2 3,WV3 0,2407,1842,23.5,565,42375,50850,1.33,Terraced,1914,2.5,1.27,52.57102,-2.12564,52.57828,-2.14126,1725,3074
|
||||||
|
W1H 4,W1H 5,13634,10428,23.5,3206,201978,288540,0.29,Flats/Maisonettes,1940,3.3,0.27,51.51941,-0.16464,51.5169,-0.16353,484,1194
|
||||||
|
W4 5,TW8 9,9220,7062,23.4,2158,132717,194220,2.91,Flats/Maisonettes,1958,2.8,0.32,51.49745,-0.26758,51.49138,-0.30937,4935,2835
|
||||||
|
N15 4,N17 0,6797,5207,23.4,1590,94605,143100,2.03,Flats/Maisonettes,1958,2.4,0.48,51.58626,-0.07309,51.60306,-0.06115,5055,4447
|
||||||
|
B3 1,B16 8,3374,2588,23.3,786,44802,70740,1.35,Flats/Maisonettes,2009,2.0,0.31,52.48427,-1.90599,52.47603,-1.92066,3141,5647
|
||||||
|
BB9 8,BB9 7,1452,1115,23.2,337,27465,30330,1.05,Terraced,1940,1.4,1.36,53.84457,-2.20627,53.838,-2.21735,3407,2693
|
||||||
|
B4 6,B5 5,4045,3105,23.2,940,45590,84600,0.55,Flats/Maisonettes,2017,2.0,0.23,52.4845,-1.89523,52.48086,-1.88965,2116,434
|
||||||
|
EC1V 1,EC1V 8,11949,9196,23.0,2753,173439,247770,0.23,Flats/Maisonettes,2016,0.5,0.44,51.52897,-0.09357,51.52808,-0.09657,1360,1192
|
||||||
|
NW6 1,NW2 4,10139,7802,23.0,2337,157747,210330,1.63,Flats/Maisonettes,1914,1.4,0.42,51.55137,-0.19415,51.55025,-0.21803,5669,3614
|
||||||
|
NW5 1,N19 3,11360,8742,23.0,2618,175406,235620,1.65,Flats/Maisonettes,1914,4.4,0.39,51.55724,-0.14407,51.56879,-0.12869,3114,5518
|
||||||
|
L9 8,L20 9,1951,1502,23.0,449,40410,40410,1.84,Terraced,1940,2.4,0.44,53.46493,-2.9656,53.45061,-2.97938,1769,2306
|
||||||
|
SW17 7,SW16 6,8557,6603,22.8,1954,132872,175860,2.25,Flats/Maisonettes,1940,4.1,0.41,51.43851,-0.16223,51.42335,-0.14006,6006,6534
|
||||||
|
WC2H 9,SW1V 2,13619,10522,22.7,3097,170335,278730,2.74,Flats/Maisonettes,1940,2.0,0.18,51.51405,-0.12585,51.49031,-0.13734,726,3528
|
||||||
|
NE8 2,NE8 3,2343,1812,22.7,531,34780,47790,2.06,Flats/Maisonettes,2004,2.0,0.87,54.95767,-1.61988,54.95623,-1.58964,3437,3727
|
||||||
|
NE6 1,NE8 3,2345,1812,22.7,533,33845,47970,1.96,Flats/Maisonettes,1986,1.8,0.6,54.97331,-1.58183,54.95623,-1.58964,1688,3727
|
||||||
|
LE1 5,LE1 3,2034,1576,22.5,458,20381,41220,0.93,Flats/Maisonettes,1999,5.0,0.73,52.6316,-1.13556,52.63932,-1.13017,1626,1426
|
||||||
|
WC1N 3,WC1H 8,11955,9294,22.3,2661,154338,239490,0.73,Flats/Maisonettes,1940,1.0,0.38,51.52146,-0.11947,51.5279,-0.12161,917,815
|
||||||
|
E1 0,E1 4,8390,6518,22.3,1872,123552,168480,0.99,Flats/Maisonettes,1971,5.1,0.35,51.51313,-0.04908,51.52181,-0.04552,3486,4193
|
||||||
|
BB11 4,BB11 3,1328,1032,22.3,296,21090,26640,1.59,Terraced,1914,0.0,0.63,53.78411,-2.25864,53.78377,-2.23529,3293,2642
|
||||||
|
SE3 7,SE12 8,7893,6137,22.2,1756,126432,158040,2.72,Flats/Maisonettes,1940,3.6,0.65,51.47871,0.0152,51.45411,0.01431,3853,3365
|
||||||
|
B42 2,B20 1,3168,2464,22.2,704,54560,63360,2.14,Semi-Detached,1958,2.6,1.27,52.53357,-1.90811,52.52345,-1.93504,5931,2309
|
||||||
|
E17 7,E10 7,8712,6778,22.2,1934,126677,174060,1.45,Flats/Maisonettes,1940,2.0,0.28,51.58188,-0.03031,51.56938,-0.02405,6041,4807
|
||||||
|
W1G 7,W1G 6,20358,15856,22.1,4502,387172,405180,0.22,Flats/Maisonettes,1940,1.0,0.29,51.52096,-0.14696,51.52144,-0.15008,280,588
|
||||||
|
FY1 5,FY1 3,1190,927,22.1,263,20251,23670,1.43,Terraced,1940,0.0,0.71,53.80886,-3.04494,53.8218,-3.0435,3510,2642
|
||||||
|
L17 8,L8 3,2687,2096,22.0,591,37233,53190,0.78,Flats/Maisonettes,1914,5.7,0.79,53.3819,-2.94808,53.38744,-2.95519,2017,2200
|
||||||
|
SE10 0,E14 2,7544,5898,21.8,1646,116866,148140,1.89,Flats/Maisonettes,2016,2.0,0.58,51.49297,0.01055,51.50866,-0.00067,10015,844
|
||||||
|
E3 5,E3 4,8220,6430,21.8,1790,126195,161100,1.18,Flats/Maisonettes,1971,5.5,0.74,51.53199,-0.03426,51.52221,-0.02733,4925,6823
|
||||||
|
DL1 1,DL1 4,2015,1576,21.8,439,32486,39510,1.07,Semi-Detached,1986,2.2,0.97,54.52695,-1.53562,54.51731,-1.53379,3425,5446
|
||||||
|
NW5 3,NW1 1,11150,8731,21.7,2419,151187,217710,1.95,Flats/Maisonettes,1958,2.7,0.23,51.54742,-0.14738,51.53218,-0.13296,1597,2651
|
||||||
|
AL8 6,AL7 1,6072,4755,21.7,1317,90873,118530,1.96,Flats/Maisonettes,1958,2.0,0.84,51.79764,-0.21351,51.80767,-0.18975,2609,3209
|
||||||
|
N8 0,N22 6,8463,6637,21.6,1826,115038,164340,0.83,Flats/Maisonettes,1940,3.5,0.44,51.58777,-0.10664,51.59482,-0.10227,6469,4971
|
||||||
|
E14 5,E14 2,7510,5898,21.5,1612,114452,145080,0.85,Flats/Maisonettes,2000,0.8,0.37,51.50474,-0.0115,51.50866,-0.00067,712,844
|
||||||
|
N8 7,N22 8,7980,6261,21.5,1719,102280,154710,1.96,Flats/Maisonettes,1958,2.9,0.6,51.58797,-0.11977,51.6055,-0.11564,4703,4514
|
||||||
|
GU16 7,GU15 3,4558,3581,21.4,977,70832,87930,2.46,Flats/Maisonettes,1971,2.1,0.46,51.31468,-0.74357,51.33663,-0.7494,953,3911
|
||||||
|
E9 5,E15 4,7728,6072,21.4,1656,106812,149040,2.92,Flats/Maisonettes,1979,4.7,0.44,51.54638,-0.03302,51.54158,0.00934,4708,4460
|
||||||
|
B3 2,B16 8,3290,2588,21.3,702,38610,63180,1.43,Flats/Maisonettes,2014,2.0,0.23,52.48237,-1.90234,52.47603,-1.92066,178,5647
|
||||||
|
E1W 1,SE16 5,9651,7596,21.3,2055,146932,184950,1.93,Flats/Maisonettes,1998,1.4,0.57,51.50581,-0.06777,51.50438,-0.03943,1353,2901
|
||||||
|
L16 1,L14 6,3607,2840,21.3,767,61360,69030,1.18,Semi-Detached,1940,5.2,0.51,53.40267,-2.88984,53.41102,-2.87901,434,809
|
||||||
|
LA14 2,LA14 1,1252,985,21.3,267,18022,24030,0.81,Terraced,1914,1.1,1.37,54.10749,-3.22482,54.11479,-3.22584,3502,2195
|
||||||
|
B11 2,B11 1,2208,1741,21.2,467,36192,42030,1.57,Terraced,1914,2.2,0.64,52.4551,-1.84936,52.46166,-1.86989,1291,3202
|
||||||
|
L13 3,L13 2,2078,1637,21.2,441,34618,39690,0.48,Terraced,1914,4.1,1.34,53.41643,-2.91645,53.41304,-2.92082,1350,1340
|
||||||
|
E14 9,E14 3,7903,6225,21.2,1678,111587,151020,0.99,Flats/Maisonettes,2013,0.8,0.26,51.50073,-0.01626,51.49193,-0.01389,18659,8179
|
||||||
|
B25 8,B10 0,2476,1952,21.2,524,38514,47160,2.64,Terraced,1940,3.8,1.45,52.4666,-1.81995,52.46765,-1.85885,5605,2837
|
||||||
|
SW3 6,SW10 9,16803,13240,21.2,3563,260099,320670,0.84,Flats/Maisonettes,1914,4.3,0.67,51.48869,-0.17386,51.48648,-0.18567,1594,5825
|
||||||
|
WC1B 3,EC4V 5,14214,11220,21.1,2994,210328,269460,1.92,Flats/Maisonettes,1914,1.9,0.23,51.51799,-0.12848,51.51284,-0.10141,322,208
|
||||||
|
NW1 6,NW6 4,11154,8814,21.0,2340,136890,210600,2.62,Flats/Maisonettes,1914,3.1,0.23,51.5237,-0.16342,51.54102,-0.18969,3312,3641
|
||||||
|
EC1V 4,EC1Y 8,11255,8894,21.0,2361,151104,212490,0.83,Flats/Maisonettes,1999,0.0,0.43,51.52548,-0.10341,51.5234,-0.09159,897,1020
|
||||||
|
NW5 2,N19 3,11064,8742,21.0,2322,145125,208980,2.09,Flats/Maisonettes,1914,3.9,0.35,51.5506,-0.13698,51.56879,-0.12869,4088,5518
|
||||||
|
BB12 0,BB12 6,2222,1756,21.0,466,35882,41940,1.82,Terraced,1971,0.3,0.76,53.79775,-2.257,53.79231,-2.28235,3008,3957
|
||||||
|
L8 4,L7 6,2126,1682,20.9,444,30636,39960,2.4,Terraced,1958,3.5,0.69,53.3828,-2.9662,53.4,-2.94456,1582,885
|
||||||
|
N22 7,N11 2,8317,6576,20.9,1741,127093,156690,1.09,Flats/Maisonettes,1914,3.9,0.49,51.59943,-0.12437,51.60923,-0.12642,2841,3946
|
||||||
|
SW17 0,CR4 2,7672,6067,20.9,1605,111948,144450,2.42,Flats/Maisonettes,1958,5.0,0.6,51.43102,-0.17616,51.41288,-0.15632,7498,4538
|
||||||
|
TW7 7,TW7 4,6663,5276,20.8,1387,101944,124830,1.84,Flats/Maisonettes,1971,3.4,1.05,51.46225,-0.3339,51.47701,-0.34628,3353,3229
|
||||||
|
L16 2,L36 4,3306,2618,20.8,688,65016,61920,1.21,Semi-Detached,1958,3.5,1.21,53.40324,-2.87211,53.41162,-2.86068,807,2242
|
||||||
|
CH42 9,CH42 0,1726,1367,20.8,359,30694,32310,0.8,Terraced,1914,4.9,1.49,53.37733,-3.03646,53.38266,-3.02855,1821,1277
|
||||||
|
ST4 2,ST1 4,1611,1276,20.8,335,23785,30150,1.7,Terraced,1914,1.0,0.79,53.00742,-2.17135,53.01975,-2.18626,2587,1893
|
||||||
|
L36 9,L36 5,3227,2558,20.7,669,63555,60210,0.94,Semi-Detached,1986,2.4,0.35,53.41196,-2.84932,53.40572,-2.83991,824,1467
|
||||||
|
E2 9,E1 4,8218,6518,20.7,1700,105400,153000,1.34,Flats/Maisonettes,1971,6.3,0.31,51.53204,-0.05617,51.52181,-0.04552,3336,4193
|
||||||
|
N1 0,NW5 4,11018,8753,20.6,2265,144960,203850,2.96,Flats/Maisonettes,1958,1.6,0.54,51.53742,-0.11419,51.55049,-0.15229,4577,2697
|
||||||
|
NG7 7,NG7 6,2175,1730,20.5,445,31595,40050,0.71,Terraced,1914,4.1,0.56,52.97526,-1.16804,52.96909,-1.16531,2339,3559
|
||||||
|
NG7 2,NG2 1,2801,2228,20.5,573,42688,51570,1.76,Terraced,1958,4.4,0.58,52.94656,-1.17989,52.94167,-1.15523,3214,1056
|
||||||
|
NG1 7,NG1 1,2786,2216,20.5,570,30210,51300,0.49,Flats/Maisonettes,2010,3.4,0.2,52.94995,-1.14699,52.95301,-1.14178,945,2895
|
||||||
|
NR32 1,NR32 2,2311,1840,20.4,471,32734,42390,0.81,Terraced,1914,2.0,0.86,52.48169,1.75296,52.47962,1.74151,2532,4026
|
||||||
|
TW4 5,TW3 3,5776,4597,20.4,1179,76045,106110,1.08,Flats/Maisonettes,1979,5.5,1.24,51.45786,-0.3795,51.46635,-0.37157,3500,4518
|
||||||
|
L15 0,L7 4,1712,1363,20.4,349,23906,31410,0.75,Terraced,1914,4.8,1.06,53.39699,-2.93315,53.39725,-2.94425,1329,401
|
||||||
|
WF8 2,WF11 8,2705,2152,20.4,553,42304,49770,2.99,Semi-Detached,1958,1.8,0.8,53.6932,-1.29594,53.70935,-1.26056,7519,2858
|
||||||
|
CH42 2,CH42 0,1715,1367,20.3,348,28536,31320,1.85,Terraced,1940,2.9,0.32,53.37035,-3.01,53.38266,-3.02855,1267,1277
|
||||||
|
SW9 0,SE5 0,8502,6774,20.3,1728,112320,155520,1.46,Flats/Maisonettes,1958,3.7,0.46,51.47388,-0.11558,51.47961,-0.09617,4980,3441
|
||||||
|
LS6 3,LS6 2,3230,2577,20.2,653,51587,58770,1.69,Flats/Maisonettes,1940,1.6,0.68,53.82002,-1.58519,53.81733,-1.56075,4033,3873
|
||||||
|
SW20 0,KT3 4,8740,6972,20.2,1768,144092,159120,1.41,Flats/Maisonettes,1958,4.8,0.75,51.41269,-0.23796,51.40313,-0.25172,3673,2531
|
||||||
|
RM14 2,RM12 5,6360,5079,20.1,1281,111447,115290,2.99,Semi-Detached,1940,3.7,0.77,51.55277,0.24307,51.54507,0.20079,3026,3133
|
||||||
|
N7 8,N7 7,8998,7185,20.1,1813,110593,163170,1.11,Flats/Maisonettes,1979,3.2,0.28,51.54816,-0.11264,51.55818,-0.11109,4607,3539
|
||||||
|
B19 1,B21 9,1788,1428,20.1,360,30060,32400,1.69,Terraced,1914,3.6,1.2,52.50297,-1.91051,52.50746,-1.93433,3162,3409
|
||||||
|
L18 6,L15 6,3877,3098,20.1,779,88806,70110,1.54,Semi-Detached,1940,4.8,0.87,53.38188,-2.90414,53.39565,-2.90712,564,901
|
||||||
|
WV14 6,WV14 7,2774,2218,20.0,556,41700,50040,1.05,Semi-Detached,1958,3.5,0.74,52.57348,-2.0784,52.56866,-2.06512,2963,1517
|
||||||
|
DN35 8,DN35 7,1598,1278,20.0,320,26400,28800,1.7,Terraced,1914,0.7,0.65,53.55706,-0.03085,53.56767,-0.04891,3803,4576
|
||||||
|
NE4 5,NE8 1,1503,1202,20.0,301,21070,27090,2.84,Flats/Maisonettes,1914,2.0,0.96,54.97595,-1.63497,54.95588,-1.60896,3018,2310
|
||||||
|
B9 5,B10 9,2597,2079,19.9,518,44289,46620,0.95,Terraced,1940,5.5,1.05,52.47881,-1.84057,52.47059,-1.84439,5554,4180
|
||||||
|
SE11 4,SE5 0,8462,6774,19.9,1688,111408,151920,1.4,Flats/Maisonettes,1971,5.3,0.32,51.49044,-0.10679,51.47961,-0.09617,4439,3441
|
||||||
|
SE10 9,E14 3,7769,6225,19.9,1544,107308,138960,1.14,Flats/Maisonettes,2012,2.0,0.31,51.48279,-0.00612,51.49193,-0.01389,6113,8179
|
||||||
|
W2 6,NW6 4,10990,8814,19.8,2176,129472,195840,2.68,Flats/Maisonettes,1914,2.5,0.3,51.51704,-0.18386,51.54102,-0.18969,4210,3641
|
||||||
|
SE11 6,SE1 5,8493,6831,19.6,1662,103044,149580,2.81,Flats/Maisonettes,1971,4.7,0.58,51.49243,-0.11392,51.48984,-0.07272,2536,4478
|
||||||
|
TW10 6,SW14 7,11640,9375,19.5,2265,175537,203850,1.91,Flats/Maisonettes,1914,1.8,0.79,51.45695,-0.29727,51.46517,-0.27252,4157,2831
|
||||||
|
N2 0,NW11 0,8195,6594,19.5,1601,123277,144090,2.02,Flats/Maisonettes,1940,1.8,0.83,51.5874,-0.17339,51.58225,-0.2019,3685,2109
|
||||||
|
S1 2,S1 4,2568,2069,19.4,499,21207,44910,0.47,Flats/Maisonettes,2012,3.2,0.24,53.38187,-1.46947,53.37885,-1.47441,2182,5583
|
||||||
|
TW2 7,TW3 2,6971,5620,19.4,1351,113821,121590,1.0,Semi-Detached,1940,5.4,0.59,51.45266,-0.35393,51.4609,-0.36011,3377,2964
|
||||||
|
L15 7,L14 6,3518,2840,19.3,678,56274,61020,2.0,Semi-Detached,1940,5.1,0.83,53.40286,-2.90524,53.41102,-2.87901,1032,809
|
||||||
|
CH45 1,CH45 4,2213,1785,19.3,428,38948,38520,1.26,Semi-Detached,1914,1.7,0.83,53.43265,-3.03879,53.42321,-3.04925,1283,1465
|
||||||
|
N1 9,N1 6,10402,8392,19.3,2010,115575,180900,2.16,Flats/Maisonettes,1971,1.1,0.31,51.53273,-0.1152,51.52938,-0.08379,2833,3384
|
||||||
|
EC3R 8,E1 7,10309,8330,19.2,1979,101918,178110,0.99,Flats/Maisonettes,1986,0.0,0.19,51.50999,-0.08419,51.51629,-0.07389,221,2146
|
||||||
|
L18 9,L19 4,3921,3169,19.2,752,69184,67680,0.66,Semi-Detached,1958,4.2,0.67,53.36947,-2.89798,53.3647,-2.89212,1296,1311
|
||||||
|
BB9 0,BB9 7,1378,1115,19.1,263,22092,23670,1.05,Terraced,1914,1.0,0.84,53.82989,-2.20929,53.838,-2.21735,4211,2693
|
||||||
|
M25 9,M27 4,3607,2917,19.1,690,55890,62100,2.99,Semi-Detached,1958,1.5,1.33,53.52156,-2.2855,53.5097,-2.32514,2959,2295
|
||||||
|
E16 2,SE18 5,6146,4972,19.1,1174,78658,105660,1.26,Flats/Maisonettes,2017,3.1,0.33,51.502,0.04566,51.49158,0.05314,11558,3903
|
||||||
|
SK15 2,OL6 6,3024,2450,19.0,574,40754,51660,2.77,Terraced,1958,2.2,1.36,53.47937,-2.04467,53.48856,-2.08261,3742,2416
|
||||||
|
WV14 8,WS10 7,3186,2581,19.0,605,42652,54450,2.72,Semi-Detached,1958,1.7,0.62,52.54996,-2.06972,52.55734,-2.03155,5736,2725
|
||||||
|
TW12 3,KT8 1,7042,5708,18.9,1334,107053,120060,2.23,Terraced,1979,3.2,1.27,51.42588,-0.37796,51.40643,-0.36933,2527,1567
|
||||||
|
LS1 4,LS11 9,3513,2848,18.9,665,40897,59850,0.82,Flats/Maisonettes,2006,3.0,0.46,53.79487,-1.55334,53.78743,-1.55422,2171,2841
|
||||||
|
NE3 4,NE3 2,3298,2676,18.9,622,53803,55980,1.92,Semi-Detached,1958,4.9,1.25,55.00102,-1.63652,55.01655,-1.64912,3991,4588
|
||||||
|
CT19 5,CT19 4,3399,2761,18.8,638,53592,57420,2.06,Terraced,1940,3.0,0.77,51.08812,1.17314,51.08929,1.14286,4481,3250
|
||||||
|
L31 3,L10 2,3176,2578,18.8,598,56212,53820,2.77,Semi-Detached,1971,2.0,0.35,53.50739,-2.93196,53.48371,-2.94544,661,347
|
||||||
|
L9 0,L20 9,1849,1502,18.8,347,30189,31230,2.77,Terraced,1914,1.9,0.6,53.46914,-2.95196,53.45061,-2.97938,1477,2306
|
||||||
|
L30 7,L30 8,2650,2154,18.7,496,40176,44640,0.79,Semi-Detached,1979,3.0,1.02,53.49196,-2.96368,53.48815,-2.95383,790,425
|
||||||
|
BN2 0,BN2 4,5633,4582,18.7,1051,69366,94590,2.32,Flats/Maisonettes,1958,3.0,1.35,50.82353,-0.12438,50.84309,-0.11204,3130,5322
|
||||||
|
SW3 5,SW10 9,16271,13240,18.6,3031,207623,272790,1.09,Flats/Maisonettes,1914,4.8,1.05,51.48503,-0.16986,51.48648,-0.18567,3183,5825
|
||||||
|
IP4 1,IP1 1,2606,2120,18.6,486,28674,43740,0.79,Flats/Maisonettes,2004,2.1,0.95,52.05439,1.16289,52.05524,1.15128,2603,1100
|
||||||
|
NR33 0,NR32 2,2261,1840,18.6,421,30943,37890,1.62,Terraced,1914,2.0,1.29,52.46508,1.739,52.47962,1.74151,3979,4026
|
||||||
|
L9 2,L9 4,1807,1472,18.5,335,27637,30150,1.02,Terraced,1940,1.8,0.37,53.45663,-2.95873,53.46584,-2.95873,1133,551
|
||||||
|
B12 8,B11 1,2135,1741,18.5,394,30929,35460,0.88,Terraced,1914,1.8,1.16,52.45575,-1.87847,52.46166,-1.86989,2418,3202
|
||||||
|
NW3 5,NW3 6,12706,10350,18.5,2356,174344,212040,0.5,Flats/Maisonettes,1914,2.6,0.36,51.54962,-0.17479,51.55188,-0.1812,3173,3182
|
||||||
|
SW4 6,SE5 0,8312,6774,18.5,1538,100739,138420,2.69,Flats/Maisonettes,1958,3.4,0.27,51.46863,-0.13154,51.47961,-0.09617,4563,3441
|
||||||
|
L23 0,L21 9,3007,2450,18.5,557,49016,50130,1.48,Semi-Detached,1940,2.0,1.2,53.48494,-3.01832,53.47603,-3.00214,1547,1758
|
||||||
|
SW1W 8,SW1P 4,13714,11191,18.4,2523,166518,227070,1.55,Flats/Maisonettes,1993,3.8,0.47,51.48954,-0.15204,51.49278,-0.1299,3312,3443
|
||||||
|
TS4 3,TS4 2,1675,1367,18.4,308,23100,27720,1.7,Terraced,1958,1.6,1.03,54.548,-1.22043,54.56321,-1.22413,3973,4228
|
||||||
|
CR4 2,CR4 4,6067,4969,18.1,1098,76036,98820,2.29,Flats/Maisonettes,1940,4.4,0.48,51.41288,-0.15632,51.39323,-0.16681,4538,3840
|
||||||
|
PL1 3,PL4 0,2904,2378,18.1,526,35242,47340,1.79,Flats/Maisonettes,1986,2.3,1.41,50.36686,-4.15566,50.36895,-4.12957,4256,1753
|
||||||
|
E9 6,E1 4,7954,6518,18.1,1436,92622,129240,2.76,Flats/Maisonettes,1971,6.8,0.38,51.54675,-0.04816,51.52181,-0.04552,3947,4193
|
||||||
|
LS18 5,LS16 6,4110,3367,18.1,743,59068,66870,1.91,Semi-Detached,1958,2.8,1.03,53.84265,-1.63652,53.84651,-1.60911,3580,4155
|
||||||
|
E1 1,E14 7,7686,6306,18.0,1380,84180,124200,2.27,Flats/Maisonettes,2000,3.4,0.38,51.51507,-0.06529,51.51406,-0.03192,3545,5687
|
||||||
|
SW7 4,W14 8,14200,11646,18.0,2554,176226,229860,1.54,Flats/Maisonettes,1914,2.6,0.31,51.49492,-0.18518,51.49743,-0.20756,3430,7221
|
||||||
|
SW20 8,KT3 4,8500,6972,18.0,1528,116892,137520,2.23,Flats/Maisonettes,1940,4.6,0.46,51.41147,-0.22174,51.40313,-0.25172,5155,2531
|
||||||
|
L4 5,L20 2,1410,1158,17.9,252,19908,22680,1.18,Terraced,1914,2.0,0.99,53.44347,-2.96715,53.44207,-2.98445,2817,1300
|
||||||
|
SM6 7,SM6 0,5628,4620,17.9,1008,67032,90720,1.97,Flats/Maisonettes,1996,4.0,0.55,51.37513,-0.15286,51.35737,-0.15137,3418,3099
|
||||||
|
NW5 4,N7 7,8753,7185,17.9,1568,94864,141120,2.92,Flats/Maisonettes,1971,3.0,0.42,51.55049,-0.15229,51.55818,-0.11109,2697,3539
|
||||||
|
M3 7,M3 6,3816,3134,17.9,682,40579,61380,0.7,Flats/Maisonettes,2018,3.8,0.46,53.48713,-2.25085,53.4858,-2.26093,5941,3553
|
||||||
|
NE2 2,NE2 1,3146,2584,17.9,562,44960,50580,1.01,Flats/Maisonettes,1914,3.3,0.63,54.99126,-1.60136,54.98237,-1.5983,2656,3970
|
||||||
|
W4 2,W4 4,10174,8372,17.7,1802,128843,162180,1.1,Flats/Maisonettes,1914,1.8,0.69,51.48794,-0.25401,51.49057,-0.26957,4027,2732
|
||||||
|
SW4 0,SW2 1,9983,8214,17.7,1769,113216,159210,2.14,Flats/Maisonettes,1940,4.2,0.52,51.4646,-0.14415,51.45683,-0.11529,3931,3735
|
||||||
|
EC1M 5,EC1Y 8,10803,8894,17.7,1909,128857,171810,0.78,Flats/Maisonettes,1999,0.0,0.18,51.52179,-0.10282,51.5234,-0.09159,521,1020
|
||||||
|
L4 1,L20 7,2098,1728,17.6,370,27565,33300,1.2,Terraced,1979,2.3,0.49,53.43506,-2.98101,53.44391,-2.99118,1667,1243
|
||||||
|
EC3N 2,EC1V 9,10244,8443,17.6,1801,112562,162090,1.86,Flats/Maisonettes,1999,0.0,0.08,51.5113,-0.07707,51.52596,-0.09038,166,960
|
||||||
|
SE27 0,SW16 3,7049,5811,17.6,1238,95326,111420,1.5,Flats/Maisonettes,1940,5.6,0.53,51.42953,-0.10688,51.4182,-0.11905,5574,3133
|
||||||
|
B43 5,B20 1,2989,2464,17.6,525,43312,47250,1.8,Semi-Detached,1958,2.2,1.28,52.5392,-1.94182,52.52345,-1.93504,3455,2309
|
||||||
|
W6 0,W12 0,10152,8378,17.5,1774,116197,159660,1.9,Flats/Maisonettes,1940,3.2,0.33,51.49621,-0.23419,51.51319,-0.23865,6681,5147
|
||||||
|
UB3 4,UB7 9,6151,5076,17.5,1075,76325,96750,2.94,Flats/Maisonettes,2004,1.9,0.55,51.49951,-0.41996,51.50394,-0.46273,4607,4365
|
||||||
|
M7 1,M5 3,3274,2701,17.5,573,39823,51570,2.67,Flats/Maisonettes,2007,3.1,1.23,53.49476,-2.26295,53.47213,-2.27652,2375,5106
|
||||||
|
SW1V 4,SW1V 2,12739,10522,17.4,2217,116392,199530,0.47,Flats/Maisonettes,1890,3.0,0.61,51.48917,-0.14394,51.49031,-0.13734,3227,3528
|
||||||
|
HA7 2,HA3 0,6834,5646,17.4,1188,108108,106920,2.57,Semi-Detached,1940,2.9,1.31,51.60329,-0.31221,51.58069,-0.30359,2775,3122
|
||||||
|
EC1R 0,EC1R 4,12020,9931,17.4,2089,133696,188010,0.25,Flats/Maisonettes,1971,0.0,0.51,51.52501,-0.10599,51.52666,-0.10846,532,634
|
||||||
|
L19 7,L19 9,4230,3496,17.4,734,72666,66060,0.48,Semi-Detached,1940,4.0,0.53,53.36525,-2.90341,53.36383,-2.91015,446,1110
|
||||||
|
B90 2,B28 0,4200,3470,17.4,730,63145,65700,1.76,Semi-Detached,1958,1.9,0.99,52.40657,-1.83487,52.42046,-1.84765,4449,4603
|
||||||
|
SE8 5,E14 3,7524,6225,17.3,1299,88981,116910,1.7,Flats/Maisonettes,1986,1.6,0.67,51.48642,-0.03731,51.49193,-0.01389,5494,8179
|
||||||
|
SE10 8,E14 3,7531,6225,17.3,1306,90767,117540,1.98,Flats/Maisonettes,2001,1.0,0.36,51.47401,-0.01359,51.49193,-0.01389,5455,8179
|
||||||
|
BN7 1,BN7 2,6210,5138,17.3,1072,82544,96480,1.0,Terraced,1958,1.8,1.01,50.87346,-0.00155,50.87753,0.01166,3196,3571
|
||||||
|
NW10 4,NW10 9,7114,5893,17.2,1221,73260,109890,0.84,Flats/Maisonettes,1914,2.8,0.51,51.53703,-0.24549,51.5439,-0.25092,4233,3624
|
||||||
|
E14 0,E15 2,7497,6208,17.2,1289,83140,116010,2.9,Flats/Maisonettes,2016,2.5,0.36,51.51208,-0.0033,51.53827,-0.00621,8378,6157
|
||||||
|
UB5 4,UB5 5,5964,4938,17.2,1026,72333,92340,1.65,Flats/Maisonettes,1958,2.9,0.58,51.5526,-0.36148,51.54333,-0.38054,5251,4277
|
||||||
|
WC1X 9,WC1H 8,11211,9294,17.1,1917,106393,172530,0.45,Flats/Maisonettes,1940,0.5,0.41,51.52919,-0.11524,51.5279,-0.12161,1540,815
|
||||||
|
S6 4,S6 1,2988,2476,17.1,512,40192,46080,1.64,Terraced,1940,1.9,0.49,53.40639,-1.51241,53.42047,-1.50486,4963,4420
|
||||||
|
SO23 9,SO23 0,6311,5240,17.0,1071,79789,96390,1.31,Flats/Maisonettes,1971,3.2,1.28,51.05626,-1.31826,51.06197,-1.30127,2026,2127
|
||||||
|
L39 5,L39 6,3842,3187,17.0,655,74997,58950,1.36,Detached,1971,0.0,0.59,53.55169,-2.90318,53.53975,-2.90771,1515,821
|
||||||
|
SW11 8,SW11 7,13444,11155,17.0,2289,168241,206010,0.78,Flats/Maisonettes,2016,3.2,0.38,51.48159,-0.14506,51.48145,-0.13354,5298,4866
|
||||||
|
TS19 0,TS18 4,1750,1453,17.0,297,25096,26730,1.3,Semi-Detached,1958,2.3,1.23,54.57472,-1.33294,54.56297,-1.33273,4499,2209
|
||||||
|
CH63 3,CH63 2,3484,2896,16.9,588,51450,52920,1.01,Semi-Detached,1940,2.7,0.83,53.34542,-3.0082,53.3507,-3.02031,1436,1530
|
||||||
|
CH41 8,CH41 7,1806,1503,16.8,303,22270,27270,1.1,Terraced,1958,4.5,0.41,53.40007,-3.04816,53.40356,-3.06336,1683,1078
|
||||||
|
WS12 4,WS11 6,3130,2604,16.8,526,39450,47340,2.04,Semi-Detached,1986,2.9,1.48,52.71611,-2.0179,52.69769,-2.01587,6766,1607
|
||||||
|
SE24 0,SE5 9,9093,7561,16.8,1532,101112,137880,1.33,Flats/Maisonettes,1914,3.1,0.44,51.45863,-0.10307,51.47044,-0.09938,4116,4741
|
||||||
|
WF10 1,WF10 4,2506,2084,16.8,422,31861,37980,1.76,Terraced,1958,0.9,0.94,53.72625,-1.36697,53.72026,-1.34292,2055,4531
|
||||||
|
S20 7,S20 1,2922,2430,16.8,492,35424,44280,1.31,Semi-Detached,1979,0.2,0.39,53.33769,-1.35432,53.34676,-1.342,1346,2233
|
||||||
|
NW10 2,NW10 9,7078,5893,16.7,1185,71100,106650,1.04,Flats/Maisonettes,1940,2.2,0.56,51.54767,-0.23691,51.5439,-0.25092,3505,3624
|
||||||
|
L3 6,L5 3,2356,1962,16.7,394,24034,35460,1.21,Flats/Maisonettes,2003,1.5,0.64,53.41455,-2.99003,53.42081,-2.97545,1725,1454
|
||||||
|
L22 0,L22 1,2609,2175,16.6,434,28861,39060,0.66,Flats/Maisonettes,1914,1.3,0.24,53.47671,-3.02473,53.4711,-3.02158,710,617
|
||||||
|
SW4 9,SW2 5,10076,8400,16.6,1676,118158,150840,1.23,Flats/Maisonettes,1914,5.1,0.49,51.45624,-0.14204,51.45674,-0.1239,4010,5125
|
||||||
|
L9 3,L20 9,1802,1502,16.6,300,27450,27000,1.34,Terraced,1914,3.0,0.29,53.46011,-2.96714,53.45061,-2.97938,864,2306
|
||||||
|
BB2 2,BB2 1,1405,1172,16.6,233,16892,20970,0.83,Terraced,1940,4.7,0.56,53.73966,-2.50046,53.74659,-2.49571,2449,2156
|
||||||
|
NG8 5,NG8 6,2654,2216,16.5,438,29346,39420,1.54,Terraced,1940,3.4,1.11,52.97537,-1.19714,52.97907,-1.21893,5034,4450
|
||||||
|
KT1 4,KT2 7,7580,6333,16.5,1247,88537,112230,2.4,Flats/Maisonettes,1971,2.4,0.23,51.41458,-0.31269,51.41822,-0.27782,1490,3298
|
||||||
|
EC1N 8,E1 7,9979,8330,16.5,1649,96466,148410,2.35,Flats/Maisonettes,2002,0.8,0.21,51.52047,-0.10778,51.51629,-0.07389,573,2146
|
||||||
|
SE19 1,SW16 3,6947,5811,16.4,1136,87472,102240,2.43,Flats/Maisonettes,1958,4.9,0.37,51.42311,-0.08413,51.4182,-0.11905,4346,3133
|
||||||
|
TW1 2,TW1 1,9945,8322,16.3,1623,120913,146070,1.04,Flats/Maisonettes,1914,3.0,0.6,51.45459,-0.31202,51.45653,-0.32698,2753,3637
|
||||||
|
SW9 9,SW9 7,8416,7041,16.3,1375,89375,123750,1.0,Flats/Maisonettes,1940,2.8,0.36,51.46731,-0.123,51.46801,-0.10832,6031,3760
|
||||||
|
BN3 5,BN3 3,6741,5645,16.3,1096,74528,98640,1.24,Flats/Maisonettes,1914,5.6,0.44,50.83387,-0.18759,50.83132,-0.16973,5310,8935
|
||||||
|
L2 5,L1 6,1878,1574,16.2,304,14592,27360,0.16,Flats/Maisonettes,2006,1.0,0.19,53.40738,-2.98838,53.40797,-2.98616,369,881
|
||||||
|
L4 3,L20 2,1382,1158,16.2,224,18144,20160,0.68,Terraced,1914,2.2,0.47,53.44124,-2.97449,53.44207,-2.98445,1796,1300
|
||||||
|
L31 7,L10 3,3036,2545,16.2,491,44926,44190,2.43,Semi-Detached,1958,2.0,1.21,53.50819,-2.94793,53.48632,-2.94406,886,418
|
||||||
|
SM2 7,KT17 3,6904,5790,16.1,1114,173227,100260,2.55,Detached,1940,2.8,0.72,51.34792,-0.21697,51.32954,-0.23953,1934,1519
|
||||||
|
NW4 2,NW9 0,6465,5422,16.1,1043,75617,93870,2.92,Flats/Maisonettes,1940,5.2,0.69,51.58597,-0.21789,51.58914,-0.26066,3448,3514
|
||||||
|
BN1 3,BN2 3,6411,5387,16.0,1024,61952,92160,1.62,Flats/Maisonettes,1890,4.0,0.51,50.8283,-0.1474,50.83424,-0.12553,7052,5567
|
||||||
|
NW11 6,N2 0,9752,8195,16.0,1557,130788,140130,1.13,Flats/Maisonettes,1914,1.9,1.34,51.58492,-0.1896,51.5874,-0.17339,2269,3685
|
||||||
|
SN2 1,SN2 8,3293,2767,16.0,526,38924,47340,0.91,Terraced,1958,2.5,1.12,51.57453,-1.78706,51.57392,-1.77363,4720,1056
|
||||||
|
WA10 2,WA9 1,1701,1431,15.9,270,18225,24300,2.12,Terraced,1979,1.5,1.14,53.45722,-2.74475,53.4528,-2.71443,2814,3230
|
||||||
|
WD24 4,WD18 7,5679,4774,15.9,905,62445,81450,2.17,Flats/Maisonettes,1993,4.0,0.51,51.6669,-0.39275,51.65289,-0.41509,2014,4190
|
||||||
|
RM20 3,RM20 4,4648,3908,15.9,740,49580,66600,1.37,Terraced,2012,3.0,1.06,51.47874,0.27854,51.47707,0.29861,1330,1542
|
||||||
|
CH46 2,CH44 5,2334,1962,15.9,372,30504,33480,3.0,Terraced,1958,1.8,1.0,53.41644,-3.09066,53.41539,-3.04651,966,1407
|
||||||
|
SE15 3,SE15 1,8041,6766,15.9,1275,87337,114750,2.04,Flats/Maisonettes,1958,2.1,0.65,51.46242,-0.05615,51.48086,-0.05779,4646,3041
|
||||||
|
NW7 2,NW4 1,6545,5506,15.9,1039,81042,93510,1.94,Flats/Maisonettes,1958,5.9,0.88,51.60921,-0.23469,51.59454,-0.219,2863,3256
|
||||||
|
CH66 2,CH66 1,3004,2530,15.8,474,39342,42660,2.84,Semi-Detached,1971,1.3,1.4,53.26372,-2.92341,53.28903,-2.93023,4041,2959
|
||||||
|
PR8 3,PR8 4,2962,2498,15.7,464,43152,41760,2.97,Semi-Detached,1958,1.9,0.94,53.60196,-3.03175,53.6256,-3.01102,4601,3996
|
||||||
|
SM6 8,SM6 0,5483,4620,15.7,863,59547,77670,0.94,Flats/Maisonettes,1958,4.7,0.68,51.3632,-0.14127,51.35737,-0.15137,4470,3099
|
||||||
|
L32 5,L33 0,1870,1576,15.7,294,20874,26460,1.24,Terraced,1993,2.0,0.9,53.47912,-2.89684,53.4823,-2.8793,431,591
|
||||||
|
SW1P 1,SW1V 2,12483,10522,15.7,1961,126484,176490,0.55,Flats/Maisonettes,1914,3.0,0.35,51.49525,-0.13811,51.49031,-0.13734,1402,3528
|
||||||
|
M3 5,M5 4,4152,3503,15.6,649,39264,58410,1.18,Flats/Maisonettes,2020,2.9,0.3,53.48267,-2.25473,53.47828,-2.27064,4203,7855
|
||||||
|
SW1W 9,SW3 6,19900,16803,15.6,3097,277181,278730,1.68,Flats/Maisonettes,1914,4.0,0.38,51.49389,-0.15063,51.48869,-0.17386,1512,1594
|
||||||
|
L21 8,L20 5,1536,1297,15.6,239,19239,21510,0.75,Terraced,1940,2.0,0.76,53.46498,-2.99614,53.45858,-2.99252,1753,1206
|
||||||
|
NG1 5,NG7 3,2298,1941,15.5,357,21063,32130,1.12,Flats/Maisonettes,2004,4.1,0.35,52.95503,-1.15757,52.95802,-1.17335,1227,3268
|
||||||
|
PL31 1,PL31 2,2902,2451,15.5,451,35403,40590,0.68,Terraced,1979,1.0,0.91,50.46537,-4.72475,50.47146,-4.72295,3265,3650
|
||||||
|
N21 3,EN1 2,6539,5529,15.4,1010,85850,90900,2.0,Flats/Maisonettes,1940,2.4,0.67,51.62986,-0.09786,51.64171,-0.07559,2506,2804
|
||||||
|
NW3 2,NW3 6,12230,10350,15.4,1880,123140,169200,1.42,Flats/Maisonettes,1940,2.7,0.31,51.55255,-0.16025,51.55188,-0.1812,5663,3182
|
||||||
|
L16 3,L14 6,3353,2840,15.3,513,43348,46170,0.83,Semi-Detached,1958,5.4,0.79,53.4038,-2.8825,53.41102,-2.87901,646,809
|
||||||
|
ME7 2,ME7 5,3614,3061,15.3,553,42304,49770,1.62,Terraced,1940,3.0,1.29,51.38449,0.56629,51.38258,0.54265,4375,3928
|
||||||
|
B10 9,B8 1,2079,1761,15.3,318,26871,28620,2.37,Terraced,1914,4.9,1.28,52.47059,-1.84439,52.49094,-1.85524,4180,2834
|
||||||
|
SM5 2,SM6 0,5455,4620,15.3,835,55945,75150,2.06,Flats/Maisonettes,1971,4.6,0.63,51.37365,-0.16616,51.35737,-0.15137,4877,3099
|
||||||
|
S12 3,S12 4,2902,2461,15.2,441,33957,39690,1.88,Semi-Detached,1958,0.0,0.45,53.34167,-1.41358,53.34743,-1.38757,3092,4427
|
||||||
|
EC1V 7,EC1Y 8,10494,8894,15.2,1600,100800,144000,0.9,Flats/Maisonettes,1999,0.0,0.47,51.52856,-0.10175,51.5234,-0.09159,1368,1020
|
||||||
|
SW9 8,SW9 7,8306,7041,15.2,1265,81592,113850,0.69,Flats/Maisonettes,1979,3.1,0.37,51.46184,-0.1102,51.46801,-0.10832,3059,3760
|
||||||
|
N16 6,N15 6,6500,5515,15.2,985,65010,88650,1.01,Flats/Maisonettes,1914,3.7,0.51,51.5696,-0.06789,51.57766,-0.07499,4716,4196
|
||||||
|
EN2 6,EN1 1,6398,5424,15.2,974,67693,87660,1.32,Flats/Maisonettes,1958,4.5,0.42,51.65156,-0.08438,51.64635,-0.06695,1875,5034
|
||||||
|
SW11 6,SW18 3,10999,9326,15.2,1673,157262,150570,1.75,Flats/Maisonettes,1914,5.2,0.84,51.4556,-0.16199,51.44534,-0.18171,4237,5500
|
||||||
|
BB1 7,BB1 6,1764,1498,15.1,266,25935,23940,0.62,Terraced,1914,4.1,0.91,53.75417,-2.48301,53.75666,-2.47488,850,1175
|
||||||
|
WF6 2,WF6 1,2630,2234,15.1,396,30492,35640,1.36,Semi-Detached,1971,1.2,0.94,53.70552,-1.42098,53.69415,-1.41339,4466,4718
|
||||||
|
W9 2,W10 4,10718,9102,15.1,1616,103424,145440,1.32,Flats/Maisonettes,1914,4.1,0.48,51.52498,-0.19242,51.52944,-0.21048,5679,3629
|
||||||
|
NW11 7,NW2 2,8238,6991,15.1,1247,86978,112230,1.51,Flats/Maisonettes,1940,0.5,0.56,51.57475,-0.19246,51.56242,-0.20213,2668,3603
|
||||||
|
WR1 3,WR1 1,3131,2660,15.0,471,28731,42390,0.39,Flats/Maisonettes,1958,3.5,0.69,52.1988,-2.22707,52.19991,-2.22163,1651,2759
|
||||||
|
BIN
analysis/out/cheaper_twins.parquet
Normal file
BIN
analysis/out/cheaper_twins.parquet
Normal file
Binary file not shown.
120
analysis/out/findings_review.md
Normal file
120
analysis/out/findings_review.md
Normal file
|
|
@ -0,0 +1,120 @@
|
||||||
|
# Findings: review before publishing
|
||||||
|
|
||||||
|
16 findings generated from analysis/out/cheaper_twins.parquet.
|
||||||
|
**Check the place names** (⚠ = unnamed sector, needs a label in analysis/place_names.json) and spot-check a couple of numbers. Then these feed the page batch + video factory.
|
||||||
|
|
||||||
|
| ⚠ | Title | Hook number | Page path | Deep link |
|
||||||
|
|---|-------|-------------|-----------|-----------|
|
||||||
|
| ⚠ | W1J 7 vs SW7 3: the same flat, about 41% cheaper per m² | 41% | `/cheaper-twin/w1j-7-vs-sw7-3` | [map](https://perfect-postcode.co.uk/?lat=51.49856&lon=-0.16253&zoom=12.5&filter=Est.%20price%20per%20sqm:0:20400&filter=Good%2B%20secondary%20school%20catchments:1:11) |
|
||||||
|
| ⚠ | SW1X 8 vs SW7 2: the same flat, about 42% cheaper per m² | 42% | `/cheaper-twin/sw1x-8-vs-sw7-2` | [map](https://perfect-postcode.co.uk/?lat=51.49758&lon=-0.16439&zoom=12.5&filter=Est.%20price%20per%20sqm:0:16400&filter=Good%2B%20secondary%20school%20catchments:1:11) |
|
||||||
|
| ⚠ | WC2A 2 vs EC2A 2: the same flat, about 43% cheaper per m² | 43% | `/cheaper-twin/wc2a-2-vs-ec2a-2` | [map](https://perfect-postcode.co.uk/?lat=51.51807&lon=-0.09837&zoom=12.5&filter=Est.%20price%20per%20sqm:0:15300&filter=Good%2B%20secondary%20school%20catchments:1:11) |
|
||||||
|
| ⚠ | W1K 2 vs SW1X 0: the same flat, about 32% cheaper per m² | 32% | `/cheaper-twin/w1k-2-vs-sw1x-0` | [map](https://perfect-postcode.co.uk/?lat=51.50311&lon=-0.15673&zoom=12.5&filter=Est.%20price%20per%20sqm:0:24700&filter=Good%2B%20secondary%20school%20catchments:1:11) |
|
||||||
|
| | Marylebone vs Camden: the same flat, about 43% cheaper per m² | 43% | `/cheaper-twin/w1u-4-vs-nw1-4` | [map](https://perfect-postcode.co.uk/?lat=51.5238&lon=-0.15091&zoom=12.5&filter=Est.%20price%20per%20sqm:0:14500&filter=Good%2B%20secondary%20school%20catchments:1:11) |
|
||||||
|
| ⚠ | W1J 8 vs SW1A 2: the same flat, about 37% cheaper per m² | 37% | `/cheaper-twin/w1j-8-vs-sw1a-2` | [map](https://perfect-postcode.co.uk/?lat=51.50663&lon=-0.13494&zoom=12.5&filter=Est.%20price%20per%20sqm:0:17900&filter=Good%2B%20secondary%20school%20catchments:1:11) |
|
||||||
|
| | Beckenham vs Croydon: the same terraced house, about 31% cheaper per m² | 31% | `/cheaper-twin/br3-3-vs-cr0-7` | [map](https://perfect-postcode.co.uk/?lat=51.38969&lon=-0.04244&zoom=12.5&filter=Est.%20price%20per%20sqm:0:5200&filter=Good%2B%20secondary%20school%20catchments:1:11) |
|
||||||
|
| | Woodford Green vs Barkingside: the same terraced house, about 26% cheaper per m² | 26% | `/cheaper-twin/ig8-7-vs-ig6-2` | [map](https://perfect-postcode.co.uk/?lat=51.60238&lon=0.06063&zoom=12.5&filter=Est.%20price%20per%20sqm:0:5600&filter=Good%2B%20secondary%20school%20catchments:1:11) |
|
||||||
|
| | Twickenham vs Hounslow: the same semi-detached house, about 19% cheaper per m² | 19% | `/cheaper-twin/tw2-7-vs-tw3-2` | [map](https://perfect-postcode.co.uk/?lat=51.45678&lon=-0.35702&zoom=12.5&filter=Est.%20price%20per%20sqm:0:5900&filter=Good%2B%20secondary%20school%20catchments:1:11) |
|
||||||
|
| | Hampton vs East Molesey: the same terraced house, about 19% cheaper per m² | 19% | `/cheaper-twin/tw12-3-vs-kt8-1` | [map](https://perfect-postcode.co.uk/?lat=51.41616&lon=-0.37365&zoom=12.5&filter=Est.%20price%20per%20sqm:0:6000&filter=Good%2B%20secondary%20school%20catchments:1:11) |
|
||||||
|
| | Upminster vs Hornchurch: the same semi-detached house, about 20% cheaper per m² | 20% | `/cheaper-twin/rm14-2-vs-rm12-5` | [map](https://perfect-postcode.co.uk/?lat=51.54892&lon=0.22193&zoom=12.5&filter=Est.%20price%20per%20sqm:0:5300&filter=Good%2B%20secondary%20school%20catchments:1:11) |
|
||||||
|
| | Stanmore vs Kenton: the same semi-detached house, about 17% cheaper per m² | 17% | `/cheaper-twin/ha7-2-vs-ha3-0` | [map](https://perfect-postcode.co.uk/?lat=51.59199&lon=-0.3079&zoom=12.5&filter=Est.%20price%20per%20sqm:0:5900&filter=Good%2B%20secondary%20school%20catchments:1:11) |
|
||||||
|
| | Newton Heath vs Harpurhey: the same terraced house, about 42% cheaper per m² | 42% | `/cheaper-twin/m40-5-vs-m9-4` | [map](https://perfect-postcode.co.uk/?lat=53.51293&lon=-2.19574&zoom=12.5&filter=Est.%20price%20per%20sqm:0:1700&filter=Good%2B%20secondary%20school%20catchments:1:11) |
|
||||||
|
| | Childwall vs Broadgreen: the same semi-detached house, about 30% cheaper per m² | 30% | `/cheaper-twin/l16-7-vs-l14-6` | [map](https://perfect-postcode.co.uk/?lat=53.40344&lon=-2.88529&zoom=12.5&filter=Est.%20price%20per%20sqm:0:3000&filter=Good%2B%20secondary%20school%20catchments:1:11) |
|
||||||
|
| ⚠ | SE28 8 vs DA18 4: the same terraced house, about 30% cheaper per m² | 30% | `/cheaper-twin/se28-8-vs-da18-4` | [map](https://perfect-postcode.co.uk/?lat=51.50039&lon=0.12568&zoom=12.5&filter=Est.%20price%20per%20sqm:0:3600&filter=Good%2B%20secondary%20school%20catchments:1:11) |
|
||||||
|
| ⚠ | How many square metres £100,000 buys across England | 152 m² vs 3 m² | `/square-metres-per-100k` | [map](https://perfect-postcode.co.uk/?zoom=6&filter=Est.%20price%20per%20sqm:0:4000) |
|
||||||
|
|
||||||
|
## Per-finding detail
|
||||||
|
|
||||||
|
### W1J 7 vs SW7 3: the same flat, about 41% cheaper per m²
|
||||||
|
- **Type:** cheaper_twin · **Page:** `/cheaper-twin/w1j-7-vs-sw7-3`
|
||||||
|
- **Hook:** £1,223,460 less for an equivalent flat: same station, similar schools, ~2.6km apart
|
||||||
|
- **Mayfair (W1J 7)** £32,986/m² (n=724) → **SW7 3** £19,392/m² (n=2,581) · gap 41.2% · Flats/Maisonettes, ~1914
|
||||||
|
- **OG card / deep link:** `lat=51.49856&lon=-0.16253&zoom=12.5&filter=Est.%20price%20per%20sqm:0:20400&filter=Good%2B%20secondary%20school%20catchments:1:11`
|
||||||
|
|
||||||
|
### SW1X 8 vs SW7 2: the same flat, about 42% cheaper per m²
|
||||||
|
- **Type:** cheaper_twin · **Page:** `/cheaper-twin/sw1x-8-vs-sw7-2`
|
||||||
|
- **Hook:** £1,001,160 less for an equivalent flat: same station, similar schools, ~1.31km apart
|
||||||
|
- **SW1X 8** £26,735/m² (n=1,410) → **SW7 2** £15,611/m² (n=1,126) · gap 41.6% · Flats/Maisonettes, ~1890
|
||||||
|
- **OG card / deep link:** `lat=51.49758&lon=-0.16439&zoom=12.5&filter=Est.%20price%20per%20sqm:0:16400&filter=Good%2B%20secondary%20school%20catchments:1:11`
|
||||||
|
|
||||||
|
### WC2A 2 vs EC2A 2: the same flat, about 43% cheaper per m²
|
||||||
|
- **Type:** cheaper_twin · **Page:** `/cheaper-twin/wc2a-2-vs-ec2a-2`
|
||||||
|
- **Hook:** £981,540 less for an equivalent flat: same station, similar schools, ~2.3km apart
|
||||||
|
- **WC2A 2** £25,482/m² (n=254) → **EC2A 2** £14,576/m² (n=772) · gap 42.8% · Flats/Maisonettes, ~2019
|
||||||
|
- **OG card / deep link:** `lat=51.51807&lon=-0.09837&zoom=12.5&filter=Est.%20price%20per%20sqm:0:15300&filter=Good%2B%20secondary%20school%20catchments:1:11`
|
||||||
|
|
||||||
|
### W1K 2 vs SW1X 0: the same flat, about 32% cheaper per m²
|
||||||
|
- **Type:** cheaper_twin · **Page:** `/cheaper-twin/w1k-2-vs-sw1x-0`
|
||||||
|
- **Hook:** £978,570 less for an equivalent flat: same station, similar schools, ~1.62km apart
|
||||||
|
- **Mayfair (W1K 2)** £34,362/m² (n=591) → **SW1X 0** £23,489/m² (n=1,606) · gap 31.6% · Flats/Maisonettes, ~1914
|
||||||
|
- **OG card / deep link:** `lat=51.50311&lon=-0.15673&zoom=12.5&filter=Est.%20price%20per%20sqm:0:24700&filter=Good%2B%20secondary%20school%20catchments:1:11`
|
||||||
|
|
||||||
|
### Marylebone vs Camden: the same flat, about 43% cheaper per m²
|
||||||
|
- **Type:** cheaper_twin · **Page:** `/cheaper-twin/w1u-4-vs-nw1-4`
|
||||||
|
- **Hook:** £942,480 less for an equivalent flat: same station, similar schools, ~0.97km apart
|
||||||
|
- **Marylebone (W1U 4)** £24,238/m² (n=984) → **Camden (NW1 4)** £13,766/m² (n=1,340) · gap 43.2% · Flats/Maisonettes, ~1940
|
||||||
|
- **OG card / deep link:** `lat=51.5238&lon=-0.15091&zoom=12.5&filter=Est.%20price%20per%20sqm:0:14500&filter=Good%2B%20secondary%20school%20catchments:1:11`
|
||||||
|
|
||||||
|
### W1J 8 vs SW1A 2: the same flat, about 37% cheaper per m²
|
||||||
|
- **Type:** cheaper_twin · **Page:** `/cheaper-twin/w1j-8-vs-sw1a-2`
|
||||||
|
- **Hook:** £916,380 less for an equivalent flat: same station, similar schools, ~1.31km apart
|
||||||
|
- **Mayfair (W1J 8)** £27,270/m² (n=295) → **SW1A 2** £17,088/m² (n=261) · gap 37.3% · Flats/Maisonettes, ~2000
|
||||||
|
- **OG card / deep link:** `lat=51.50663&lon=-0.13494&zoom=12.5&filter=Est.%20price%20per%20sqm:0:17900&filter=Good%2B%20secondary%20school%20catchments:1:11`
|
||||||
|
|
||||||
|
### Beckenham vs Croydon: the same terraced house, about 31% cheaper per m²
|
||||||
|
- **Type:** cheaper_twin · **Page:** `/cheaper-twin/br3-3-vs-cr0-7`
|
||||||
|
- **Hook:** £201,870 less for an equivalent terraced house: same station, similar schools, ~2.02km apart
|
||||||
|
- **Beckenham (BR3 3)** £7,153/m² (n=4,514) → **Croydon (CR0 7)** £4,910/m² (n=5,143) · gap 31.4% · Terraced, ~1940
|
||||||
|
- **OG card / deep link:** `lat=51.38969&lon=-0.04244&zoom=12.5&filter=Est.%20price%20per%20sqm:0:5200&filter=Good%2B%20secondary%20school%20catchments:1:11`
|
||||||
|
|
||||||
|
### Woodford Green vs Barkingside: the same terraced house, about 26% cheaper per m²
|
||||||
|
- **Type:** cheaper_twin · **Page:** `/cheaper-twin/ig8-7-vs-ig6-2`
|
||||||
|
- **Hook:** £164,070 less for an equivalent terraced house: same station, similar schools, ~2.98km apart
|
||||||
|
- **Woodford Green (IG8 7)** £7,148/m² (n=2,965) → **Barkingside (IG6 2)** £5,325/m² (n=4,423) · gap 25.5% · Terraced, ~1958
|
||||||
|
- **OG card / deep link:** `lat=51.60238&lon=0.06063&zoom=12.5&filter=Est.%20price%20per%20sqm:0:5600&filter=Good%2B%20secondary%20school%20catchments:1:11`
|
||||||
|
|
||||||
|
### Twickenham vs Hounslow: the same semi-detached house, about 19% cheaper per m²
|
||||||
|
- **Type:** cheaper_twin · **Page:** `/cheaper-twin/tw2-7-vs-tw3-2`
|
||||||
|
- **Hook:** £121,590 less for an equivalent semi-detached house: same station, similar schools, ~1.0km apart
|
||||||
|
- **Twickenham (TW2 7)** £6,971/m² (n=3,377) → **Hounslow (TW3 2)** £5,620/m² (n=2,964) · gap 19.4% · Semi-Detached, ~1940
|
||||||
|
- **OG card / deep link:** `lat=51.45678&lon=-0.35702&zoom=12.5&filter=Est.%20price%20per%20sqm:0:5900&filter=Good%2B%20secondary%20school%20catchments:1:11`
|
||||||
|
|
||||||
|
### Hampton vs East Molesey: the same terraced house, about 19% cheaper per m²
|
||||||
|
- **Type:** cheaper_twin · **Page:** `/cheaper-twin/tw12-3-vs-kt8-1`
|
||||||
|
- **Hook:** £120,060 less for an equivalent terraced house: same station, similar schools, ~2.23km apart
|
||||||
|
- **Hampton (TW12 3)** £7,042/m² (n=2,527) → **East Molesey (KT8 1)** £5,708/m² (n=1,567) · gap 18.9% · Terraced, ~1979
|
||||||
|
- **OG card / deep link:** `lat=51.41616&lon=-0.37365&zoom=12.5&filter=Est.%20price%20per%20sqm:0:6000&filter=Good%2B%20secondary%20school%20catchments:1:11`
|
||||||
|
|
||||||
|
### Upminster vs Hornchurch: the same semi-detached house, about 20% cheaper per m²
|
||||||
|
- **Type:** cheaper_twin · **Page:** `/cheaper-twin/rm14-2-vs-rm12-5`
|
||||||
|
- **Hook:** £115,290 less for an equivalent semi-detached house: same station, similar schools, ~2.99km apart
|
||||||
|
- **Upminster (RM14 2)** £6,360/m² (n=3,026) → **Hornchurch (RM12 5)** £5,079/m² (n=3,133) · gap 20.1% · Semi-Detached, ~1940
|
||||||
|
- **OG card / deep link:** `lat=51.54892&lon=0.22193&zoom=12.5&filter=Est.%20price%20per%20sqm:0:5300&filter=Good%2B%20secondary%20school%20catchments:1:11`
|
||||||
|
|
||||||
|
### Stanmore vs Kenton: the same semi-detached house, about 17% cheaper per m²
|
||||||
|
- **Type:** cheaper_twin · **Page:** `/cheaper-twin/ha7-2-vs-ha3-0`
|
||||||
|
- **Hook:** £106,920 less for an equivalent semi-detached house: same station, similar schools, ~2.57km apart
|
||||||
|
- **Stanmore (HA7 2)** £6,834/m² (n=2,775) → **Kenton (HA3 0)** £5,646/m² (n=3,122) · gap 17.4% · Semi-Detached, ~1940
|
||||||
|
- **OG card / deep link:** `lat=51.59199&lon=-0.3079&zoom=12.5&filter=Est.%20price%20per%20sqm:0:5900&filter=Good%2B%20secondary%20school%20catchments:1:11`
|
||||||
|
|
||||||
|
### Newton Heath vs Harpurhey: the same terraced house, about 42% cheaper per m²
|
||||||
|
- **Type:** cheaper_twin · **Page:** `/cheaper-twin/m40-5-vs-m9-4`
|
||||||
|
- **Hook:** £106,740 less for an equivalent terraced house: same station, similar schools, ~1.18km apart
|
||||||
|
- **Newton Heath (M40 5)** £2,812/m² (n=1,632) → **Harpurhey (M9 4)** £1,626/m² (n=3,530) · gap 42.2% · Terraced, ~1958
|
||||||
|
- **OG card / deep link:** `lat=53.51293&lon=-2.19574&zoom=12.5&filter=Est.%20price%20per%20sqm:0:1700&filter=Good%2B%20secondary%20school%20catchments:1:11`
|
||||||
|
|
||||||
|
### Childwall vs Broadgreen: the same semi-detached house, about 30% cheaper per m²
|
||||||
|
- **Type:** cheaper_twin · **Page:** `/cheaper-twin/l16-7-vs-l14-6`
|
||||||
|
- **Hook:** £106,740 less for an equivalent semi-detached house: same station, similar schools, ~1.88km apart
|
||||||
|
- **Childwall (L16 7)** £4,026/m² (n=500) → **Broadgreen (L14 6)** £2,840/m² (n=809) · gap 29.5% · Semi-Detached, ~1940
|
||||||
|
- **OG card / deep link:** `lat=53.40344&lon=-2.88529&zoom=12.5&filter=Est.%20price%20per%20sqm:0:3000&filter=Good%2B%20secondary%20school%20catchments:1:11`
|
||||||
|
|
||||||
|
### SE28 8 vs DA18 4: the same terraced house, about 30% cheaper per m²
|
||||||
|
- **Type:** cheaper_twin · **Page:** `/cheaper-twin/se28-8-vs-da18-4`
|
||||||
|
- **Hook:** £129,690 less for an equivalent terraced house: same station, similar schools, ~1.72km apart
|
||||||
|
- **SE28 8** £4,850/m² (n=5,033) → **DA18 4** £3,409/m² (n=1,063) · gap 29.7% · Terraced, ~1993
|
||||||
|
- **OG card / deep link:** `lat=51.50039&lon=0.12568&zoom=12.5&filter=Est.%20price%20per%20sqm:0:3600&filter=Good%2B%20secondary%20school%20catchments:1:11`
|
||||||
|
|
||||||
|
### How many square metres £100,000 buys across England
|
||||||
|
- **Type:** national_table · **Page:** `/square-metres-per-100k`
|
||||||
|
- **Hook:** £100k buys ~152 m² of floor space in BD21 3 but only ~3 m² in Mayfair (W1K 2)
|
||||||
|
- **OG card / deep link:** `zoom=6&filter=Est.%20price%20per%20sqm:0:4000`
|
||||||
268
analysis/out/national_facts.json
Normal file
268
analysis/out/national_facts.json
Normal file
|
|
@ -0,0 +1,268 @@
|
||||||
|
{
|
||||||
|
"generated_with": "analysis/cheaper_twins.py",
|
||||||
|
"params": {
|
||||||
|
"min_props": 150,
|
||||||
|
"min_recorded": 40,
|
||||||
|
"max_km": 3.0,
|
||||||
|
"min_gap": 0.15,
|
||||||
|
"max_gap": 0.45,
|
||||||
|
"build_band": 30,
|
||||||
|
"school_tol": 1.5,
|
||||||
|
"station_max": 1.5,
|
||||||
|
"station_tol": 0.9,
|
||||||
|
"crime_ratio": 1.5,
|
||||||
|
"owner_tol": 22,
|
||||||
|
"degree_tol": 22,
|
||||||
|
"age_tol": 12,
|
||||||
|
"floor_ratio": 0.72,
|
||||||
|
"min_abs_gap": 20000
|
||||||
|
},
|
||||||
|
"n_sectors": 7560,
|
||||||
|
"n_twin_pairs": 415,
|
||||||
|
"attribution": "Contains HM Land Registry data \u00a9 Crown copyright and database right. Licensed under the Open Government Licence v3.0.",
|
||||||
|
"best_value_sector": {
|
||||||
|
"sector": "BD21 3",
|
||||||
|
"est_psqm": 660,
|
||||||
|
"sqm_per_100k": 151.6,
|
||||||
|
"n": 1377
|
||||||
|
},
|
||||||
|
"dearest_sector": {
|
||||||
|
"sector": "W1K 2",
|
||||||
|
"est_psqm": 34362,
|
||||||
|
"sqm_per_100k": 2.9,
|
||||||
|
"n": 591
|
||||||
|
},
|
||||||
|
"biggest_twin_gap": {
|
||||||
|
"pricey_sector": "W1U 3",
|
||||||
|
"twin_sector": "EC1N 7",
|
||||||
|
"pricey_psqm": 16948,
|
||||||
|
"twin_psqm": 9362,
|
||||||
|
"gap_pct": 44.8,
|
||||||
|
"gap_per_sqm": 7586,
|
||||||
|
"gap_on_avg_home": 504469,
|
||||||
|
"gap_on_90sqm": 682740,
|
||||||
|
"dist_km": 2.89,
|
||||||
|
"dominant_type": "Flats/Maisonettes",
|
||||||
|
"build_year": 1940,
|
||||||
|
"good_secondary": 1.3,
|
||||||
|
"station_km": 0.41,
|
||||||
|
"pricey_lat": 51.51712,
|
||||||
|
"pricey_lon": -0.15271,
|
||||||
|
"twin_lat": 51.52057,
|
||||||
|
"twin_lon": -0.11049,
|
||||||
|
"pricey_n": 302,
|
||||||
|
"twin_n": 747
|
||||||
|
},
|
||||||
|
"top_twins": [
|
||||||
|
{
|
||||||
|
"pricey_sector": "W1U 3",
|
||||||
|
"twin_sector": "EC1N 7",
|
||||||
|
"pricey_psqm": 16948,
|
||||||
|
"twin_psqm": 9362,
|
||||||
|
"gap_pct": 44.8,
|
||||||
|
"gap_per_sqm": 7586,
|
||||||
|
"gap_on_avg_home": 504469,
|
||||||
|
"gap_on_90sqm": 682740,
|
||||||
|
"dist_km": 2.89,
|
||||||
|
"dominant_type": "Flats/Maisonettes",
|
||||||
|
"build_year": 1940,
|
||||||
|
"good_secondary": 1.3,
|
||||||
|
"station_km": 0.41,
|
||||||
|
"pricey_lat": 51.51712,
|
||||||
|
"pricey_lon": -0.15271,
|
||||||
|
"twin_lat": 51.52057,
|
||||||
|
"twin_lon": -0.11049,
|
||||||
|
"pricey_n": 302,
|
||||||
|
"twin_n": 747
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pricey_sector": "WC2R 1",
|
||||||
|
"twin_sector": "SW1V 1",
|
||||||
|
"pricey_psqm": 19997,
|
||||||
|
"twin_psqm": 11119,
|
||||||
|
"gap_pct": 44.4,
|
||||||
|
"gap_per_sqm": 8878,
|
||||||
|
"gap_on_avg_home": 665850,
|
||||||
|
"gap_on_90sqm": 799020,
|
||||||
|
"dist_km": 2.82,
|
||||||
|
"dominant_type": "Flats/Maisonettes",
|
||||||
|
"build_year": 2017,
|
||||||
|
"good_secondary": 2.0,
|
||||||
|
"station_km": 0.21,
|
||||||
|
"pricey_lat": 51.51228,
|
||||||
|
"pricey_lon": -0.11525,
|
||||||
|
"twin_lat": 51.49297,
|
||||||
|
"twin_lon": -0.14234,
|
||||||
|
"pricey_n": 316,
|
||||||
|
"twin_n": 1408
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pricey_sector": "L8 7",
|
||||||
|
"twin_sector": "L7 0",
|
||||||
|
"pricey_psqm": 2757,
|
||||||
|
"twin_psqm": 1541,
|
||||||
|
"gap_pct": 44.1,
|
||||||
|
"gap_per_sqm": 1216,
|
||||||
|
"gap_on_avg_home": 78432,
|
||||||
|
"gap_on_90sqm": 109440,
|
||||||
|
"dist_km": 2.36,
|
||||||
|
"dominant_type": "Flats/Maisonettes",
|
||||||
|
"build_year": 1914,
|
||||||
|
"good_secondary": 2.3,
|
||||||
|
"station_km": 1.04,
|
||||||
|
"pricey_lat": 53.39791,
|
||||||
|
"pricey_lon": -2.96459,
|
||||||
|
"twin_lat": 53.41174,
|
||||||
|
"twin_lon": -2.93813,
|
||||||
|
"pricey_n": 2054,
|
||||||
|
"twin_n": 2208
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pricey_sector": "L3 2",
|
||||||
|
"twin_sector": "L5 5",
|
||||||
|
"pricey_psqm": 1642,
|
||||||
|
"twin_psqm": 920,
|
||||||
|
"gap_pct": 44.0,
|
||||||
|
"gap_per_sqm": 722,
|
||||||
|
"gap_on_avg_home": 47291,
|
||||||
|
"gap_on_90sqm": 64980,
|
||||||
|
"dist_km": 1.61,
|
||||||
|
"dominant_type": "Flats/Maisonettes",
|
||||||
|
"build_year": 2004,
|
||||||
|
"good_secondary": 1.5,
|
||||||
|
"station_km": 0.47,
|
||||||
|
"pricey_lat": 53.41155,
|
||||||
|
"pricey_lon": -2.98583,
|
||||||
|
"twin_lat": 53.42544,
|
||||||
|
"twin_lon": -2.97852,
|
||||||
|
"pricey_n": 1341,
|
||||||
|
"twin_n": 706
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pricey_sector": "S2 4",
|
||||||
|
"twin_sector": "S3 9",
|
||||||
|
"pricey_psqm": 2468,
|
||||||
|
"twin_psqm": 1402,
|
||||||
|
"gap_pct": 43.2,
|
||||||
|
"gap_per_sqm": 1066,
|
||||||
|
"gap_on_avg_home": 73554,
|
||||||
|
"gap_on_90sqm": 95940,
|
||||||
|
"dist_km": 2.82,
|
||||||
|
"dominant_type": "Flats/Maisonettes",
|
||||||
|
"build_year": 1986,
|
||||||
|
"good_secondary": 2.6,
|
||||||
|
"station_km": 0.72,
|
||||||
|
"pricey_lat": 53.36993,
|
||||||
|
"pricey_lon": -1.46978,
|
||||||
|
"twin_lat": 53.39521,
|
||||||
|
"twin_lon": -1.46478,
|
||||||
|
"pricey_n": 2423,
|
||||||
|
"twin_n": 1778
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pricey_sector": "W1U 4",
|
||||||
|
"twin_sector": "NW1 4",
|
||||||
|
"pricey_psqm": 24238,
|
||||||
|
"twin_psqm": 13766,
|
||||||
|
"gap_pct": 43.2,
|
||||||
|
"gap_per_sqm": 10472,
|
||||||
|
"gap_on_avg_home": 759220,
|
||||||
|
"gap_on_90sqm": 942480,
|
||||||
|
"dist_km": 0.97,
|
||||||
|
"dominant_type": "Flats/Maisonettes",
|
||||||
|
"build_year": 1940,
|
||||||
|
"good_secondary": 1.0,
|
||||||
|
"station_km": 0.44,
|
||||||
|
"pricey_lat": 51.51958,
|
||||||
|
"pricey_lon": -0.15295,
|
||||||
|
"twin_lat": 51.52803,
|
||||||
|
"twin_lon": -0.14886,
|
||||||
|
"pricey_n": 984,
|
||||||
|
"twin_n": 1340
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pricey_sector": "WC2A 2",
|
||||||
|
"twin_sector": "EC2A 2",
|
||||||
|
"pricey_psqm": 25482,
|
||||||
|
"twin_psqm": 14576,
|
||||||
|
"gap_pct": 42.8,
|
||||||
|
"gap_per_sqm": 10906,
|
||||||
|
"gap_on_avg_home": 834309,
|
||||||
|
"gap_on_90sqm": 981540,
|
||||||
|
"dist_km": 2.3,
|
||||||
|
"dominant_type": "Flats/Maisonettes",
|
||||||
|
"build_year": 2019,
|
||||||
|
"good_secondary": 2.0,
|
||||||
|
"station_km": 0.42,
|
||||||
|
"pricey_lat": 51.51496,
|
||||||
|
"pricey_lon": -0.11456,
|
||||||
|
"twin_lat": 51.52119,
|
||||||
|
"twin_lon": -0.08217,
|
||||||
|
"pricey_n": 254,
|
||||||
|
"twin_n": 772
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pricey_sector": "M40 5",
|
||||||
|
"twin_sector": "M9 4",
|
||||||
|
"pricey_psqm": 2812,
|
||||||
|
"twin_psqm": 1626,
|
||||||
|
"gap_pct": 42.2,
|
||||||
|
"gap_per_sqm": 1186,
|
||||||
|
"gap_on_avg_home": 91915,
|
||||||
|
"gap_on_90sqm": 106740,
|
||||||
|
"dist_km": 1.18,
|
||||||
|
"dominant_type": "Terraced",
|
||||||
|
"build_year": 1958,
|
||||||
|
"good_secondary": 2.6,
|
||||||
|
"station_km": 0.72,
|
||||||
|
"pricey_lat": 53.51372,
|
||||||
|
"pricey_lon": -2.18713,
|
||||||
|
"twin_lat": 53.51214,
|
||||||
|
"twin_lon": -2.20436,
|
||||||
|
"pricey_n": 1632,
|
||||||
|
"twin_n": 3530
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pricey_sector": "W11 2",
|
||||||
|
"twin_sector": "NW1 6",
|
||||||
|
"pricey_psqm": 19262,
|
||||||
|
"twin_psqm": 11154,
|
||||||
|
"gap_pct": 42.1,
|
||||||
|
"gap_per_sqm": 8108,
|
||||||
|
"gap_on_avg_home": 482426,
|
||||||
|
"gap_on_90sqm": 729720,
|
||||||
|
"dist_km": 2.94,
|
||||||
|
"dominant_type": "Flats/Maisonettes",
|
||||||
|
"build_year": 1890,
|
||||||
|
"good_secondary": 4.0,
|
||||||
|
"station_km": 0.53,
|
||||||
|
"pricey_lat": 51.51407,
|
||||||
|
"pricey_lon": -0.20373,
|
||||||
|
"twin_lat": 51.5237,
|
||||||
|
"twin_lon": -0.16342,
|
||||||
|
"pricey_n": 4082,
|
||||||
|
"twin_n": 3312
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"pricey_sector": "N10 3",
|
||||||
|
"twin_sector": "N12 0",
|
||||||
|
"pricey_psqm": 9590,
|
||||||
|
"twin_psqm": 5554,
|
||||||
|
"gap_pct": 42.1,
|
||||||
|
"gap_per_sqm": 4036,
|
||||||
|
"gap_on_avg_home": 296646,
|
||||||
|
"gap_on_90sqm": 363240,
|
||||||
|
"dist_km": 2.97,
|
||||||
|
"dominant_type": "Flats/Maisonettes",
|
||||||
|
"build_year": 1914,
|
||||||
|
"good_secondary": 3.9,
|
||||||
|
"station_km": 1.16,
|
||||||
|
"pricey_lat": 51.58839,
|
||||||
|
"pricey_lon": -0.14404,
|
||||||
|
"twin_lat": 51.60872,
|
||||||
|
"twin_lon": -0.17254,
|
||||||
|
"pricey_n": 3984,
|
||||||
|
"twin_n": 3282
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
7561
analysis/out/sector_index.csv
Normal file
7561
analysis/out/sector_index.csv
Normal file
File diff suppressed because it is too large
Load diff
BIN
analysis/out/sector_index.parquet
Normal file
BIN
analysis/out/sector_index.parquet
Normal file
Binary file not shown.
23
analysis/place_names.json
Normal file
23
analysis/place_names.json
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
{
|
||||||
|
"_comment": "Outward-code -> approximate neighbourhood label, used by generate_findings.py. APPROXIMATE (an outward code can span more than one area). VERIFY before publishing a page/video. Add entries to name more sectors; unknown codes fall back to the bare sector code and are flagged NEEDS-NAME in findings_review.md.",
|
||||||
|
"W11": "Notting Hill", "W12": "Shepherd's Bush", "W4": "Chiswick", "W3": "Acton",
|
||||||
|
"W1H": "Marylebone", "W1U": "Marylebone", "W1K": "Mayfair", "W1J": "Mayfair",
|
||||||
|
"SW3": "Chelsea", "SW5": "Earl's Court", "SW1V": "Pimlico", "SW13": "Barnes", "SW1H": "Westminster",
|
||||||
|
"N1": "Islington", "N7": "Holloway", "N10": "Muswell Hill", "N12": "North Finchley", "N16": "Stoke Newington",
|
||||||
|
"NW1": "Camden", "NW6": "West Hampstead", "NW2": "Cricklewood", "NW10": "Willesden",
|
||||||
|
"E2": "Bethnal Green", "E5": "Clapton", "E8": "Hackney",
|
||||||
|
"EC1V": "Clerkenwell", "EC1Y": "Old Street", "EC1N": "Farringdon", "EC4V": "Blackfriars",
|
||||||
|
"WC1N": "Bloomsbury", "WC1B": "Bloomsbury", "WC2R": "Covent Garden", "WC1E": "Bloomsbury",
|
||||||
|
"SE1": "Bermondsey",
|
||||||
|
"BR3": "Beckenham", "CR0": "Croydon",
|
||||||
|
"HA7": "Stanmore", "HA3": "Kenton",
|
||||||
|
"IG8": "Woodford Green", "IG6": "Barkingside",
|
||||||
|
"TW2": "Twickenham", "TW3": "Hounslow", "TW12": "Hampton", "KT8": "East Molesey",
|
||||||
|
"RM14": "Upminster", "RM12": "Hornchurch",
|
||||||
|
"SM2": "Sutton", "KT17": "Ewell",
|
||||||
|
"B11": "Sparkhill",
|
||||||
|
"M40": "Newton Heath", "M9": "Harpurhey",
|
||||||
|
"L16": "Childwall", "L14": "Broadgreen", "L8": "Toxteth", "L7": "Kensington (L'pool)",
|
||||||
|
"SK6": "Romiley",
|
||||||
|
"BN7": "Lewes"
|
||||||
|
}
|
||||||
354
analysis/weekly_readout.py
Normal file
354
analysis/weekly_readout.py
Normal file
|
|
@ -0,0 +1,354 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
"""Perfect Postcode: weekly growth-metrics readout.
|
||||||
|
|
||||||
|
Assembles a one-screen, dated markdown block (SEO + YouTube + product funnel)
|
||||||
|
suitable for pasting into a weekly note. Every section degrades gracefully: if a
|
||||||
|
credential is missing the section prints "⚠ set X to enable" instead of crashing.
|
||||||
|
|
||||||
|
USAGE
|
||||||
|
python3 analysis/weekly_readout.py # prints the readout to stdout
|
||||||
|
|
||||||
|
DATA SOURCES & CREDENTIALS (all read from the environment)
|
||||||
|
|
||||||
|
SEO: Google Search Console (Search Analytics API)
|
||||||
|
GSC_SITE_URL Property as registered in GSC, e.g.
|
||||||
|
"sc-domain:perfect-postcode.co.uk" or
|
||||||
|
"https://perfect-postcode.co.uk/".
|
||||||
|
GOOGLE_APPLICATION_CREDENTIALS (or GSC_CREDENTIALS)
|
||||||
|
Path to a service-account JSON key. Create it in
|
||||||
|
Google Cloud → IAM → Service Accounts, enable the
|
||||||
|
"Google Search Console API", then in Search Console
|
||||||
|
→ Settings → Users add the service-account email as a
|
||||||
|
(restricted) user on the property.
|
||||||
|
|
||||||
|
YouTube: view counts (Data API v3, API key) + impressions/CTR/retention
|
||||||
|
(Analytics API, founder OAuth)
|
||||||
|
YT_API_KEY Public Data API v3 key (Cloud console → Credentials).
|
||||||
|
Gives per-video view/like/comment counts.
|
||||||
|
YT_CHANNEL_ID Channel id (starts "UC..."). See
|
||||||
|
youtube.com/account_advanced.
|
||||||
|
YT_OAUTH_TOKEN (optional) Path to an authorized_user OAuth token
|
||||||
|
JSON for the channel owner. ONLY this unlocks
|
||||||
|
impressions, CTR and average view duration, which are
|
||||||
|
private and need the founder's Google login + scope
|
||||||
|
yt-analytics.readonly. Without it we show public views
|
||||||
|
only.
|
||||||
|
|
||||||
|
Funnel: Plausible (self-hosted) Stats API v2
|
||||||
|
PLAUSIBLE_API_KEY Stats API key (Plausible → Settings → API Keys).
|
||||||
|
PLAUSIBLE_SITE_ID (default perfect-postcode.co.uk)
|
||||||
|
PLAUSIBLE_HOST (default https://stats.schmelczer.dev)
|
||||||
|
|
||||||
|
KILL / KEEP rule (printed at the bottom): keep going if BOTH search impressions
|
||||||
|
AND map opens grew month-over-month; otherwise reconsider.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import urllib.error
|
||||||
|
import urllib.parse
|
||||||
|
import urllib.request
|
||||||
|
from datetime import date, timedelta
|
||||||
|
|
||||||
|
from google.auth.transport.requests import Request
|
||||||
|
from google.oauth2 import service_account
|
||||||
|
from google.oauth2.credentials import Credentials
|
||||||
|
|
||||||
|
TODAY = date.today()
|
||||||
|
WARN = "⚠"
|
||||||
|
|
||||||
|
|
||||||
|
# Comparison windows (yesterday-anchored). GSC data lags ~2-3 days, so the most
|
||||||
|
# recent days of the SEO section may read low, which is expected.
|
||||||
|
def window(end_offset: int, length: int) -> tuple[str, str]:
|
||||||
|
end = TODAY - timedelta(days=end_offset)
|
||||||
|
return (end - timedelta(days=length - 1)).isoformat(), end.isoformat()
|
||||||
|
|
||||||
|
|
||||||
|
WK_CUR, WK_PREV = window(1, 7), window(8, 7) # weekly readout
|
||||||
|
MO_CUR, MO_PREV = window(1, 28), window(29, 28) # monthly kill/keep gate
|
||||||
|
|
||||||
|
|
||||||
|
def delta(cur: float, prev: float) -> str:
|
||||||
|
if prev == 0:
|
||||||
|
return " (new)" if cur else ""
|
||||||
|
pct = (cur - prev) / prev * 100
|
||||||
|
return f" {'▲' if pct >= 0 else '▼'}{pct:+.0f}%"
|
||||||
|
|
||||||
|
|
||||||
|
def http_json(url, *, method="GET", headers=None, body=None):
|
||||||
|
data = json.dumps(body).encode() if body is not None else None
|
||||||
|
req = urllib.request.Request(url, data=data, method=method, headers=headers or {})
|
||||||
|
if data is not None:
|
||||||
|
req.add_header("Content-Type", "application/json")
|
||||||
|
with urllib.request.urlopen(req, timeout=30) as resp:
|
||||||
|
return json.loads(resp.read().decode())
|
||||||
|
|
||||||
|
|
||||||
|
def google_token(creds_path, scopes, *, authorized_user):
|
||||||
|
"""Mint an OAuth bearer token from a Google credential file."""
|
||||||
|
if authorized_user:
|
||||||
|
creds = Credentials.from_authorized_user_file(creds_path, scopes)
|
||||||
|
else:
|
||||||
|
creds = service_account.Credentials.from_service_account_file(
|
||||||
|
creds_path, scopes=scopes
|
||||||
|
)
|
||||||
|
creds.refresh(Request())
|
||||||
|
return creds.token
|
||||||
|
|
||||||
|
|
||||||
|
# --- shared GSC + Plausible query helpers (reused by sections and kill/keep) ---
|
||||||
|
def gsc_creds():
|
||||||
|
return os.environ.get("GSC_SITE_URL"), (
|
||||||
|
os.environ.get("GOOGLE_APPLICATION_CREDENTIALS")
|
||||||
|
or os.environ.get("GSC_CREDENTIALS")
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
_GSC_TOKEN = {} # cache: creds_path -> token
|
||||||
|
|
||||||
|
|
||||||
|
def gsc_query(start, end, dimensions=None, limit=1):
|
||||||
|
"""Search Analytics query. Caller must have verified gsc_creds() first."""
|
||||||
|
site, creds = gsc_creds()
|
||||||
|
if creds not in _GSC_TOKEN:
|
||||||
|
_GSC_TOKEN[creds] = google_token(
|
||||||
|
creds,
|
||||||
|
["https://www.googleapis.com/auth/webmasters.readonly"],
|
||||||
|
authorized_user=False,
|
||||||
|
)
|
||||||
|
body = {"startDate": start, "endDate": end, "rowLimit": limit}
|
||||||
|
if dimensions:
|
||||||
|
body["dimensions"] = dimensions
|
||||||
|
url = (
|
||||||
|
"https://searchconsole.googleapis.com/webmasters/v3/sites/"
|
||||||
|
+ urllib.parse.quote(site, safe="")
|
||||||
|
+ "/searchAnalytics/query"
|
||||||
|
)
|
||||||
|
headers = {"Authorization": f"Bearer {_GSC_TOKEN[creds]}"}
|
||||||
|
return http_json(url, method="POST", headers=headers, body=body).get("rows", [])
|
||||||
|
|
||||||
|
|
||||||
|
def plausible_query(metrics, date_range, filters=None):
|
||||||
|
"""Stats API v2 aggregate query -> list of metric values (aligned to
|
||||||
|
`metrics`). Caller must have verified PLAUSIBLE_API_KEY first."""
|
||||||
|
key = os.environ["PLAUSIBLE_API_KEY"]
|
||||||
|
site = os.environ.get("PLAUSIBLE_SITE_ID", "perfect-postcode.co.uk")
|
||||||
|
host = os.environ.get("PLAUSIBLE_HOST", "https://stats.schmelczer.dev").rstrip("/")
|
||||||
|
body = {"site_id": site, "metrics": metrics, "date_range": list(date_range)}
|
||||||
|
if filters:
|
||||||
|
body["filters"] = filters
|
||||||
|
res = http_json(
|
||||||
|
host + "/api/v2/query",
|
||||||
|
method="POST",
|
||||||
|
headers={"Authorization": f"Bearer {key}"},
|
||||||
|
body=body,
|
||||||
|
).get("results", [])
|
||||||
|
return res[0]["metrics"] if res else [0] * len(metrics)
|
||||||
|
|
||||||
|
|
||||||
|
# Real Plausible events (frontend/src/lib/analytics.ts + MapPage.tsx):
|
||||||
|
# pageview /dashboard -> map opens (no dedicated "Map Open" event exists)
|
||||||
|
# "Filter Add" -> a filter was applied (props.feature = feature name)
|
||||||
|
# "Upgrade Modal Shown" -> the 3-filter demo cap (DEMO_MAX_FILTERS) was hit
|
||||||
|
MAP_FILTER = [["is", "event:page", ["/dashboard"]]]
|
||||||
|
ADD_FILTER = [["is", "event:name", ["Filter Add"]]]
|
||||||
|
CAP_FILTER = [["is", "event:name", ["Upgrade Modal Shown"]]]
|
||||||
|
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# 1. SEO: Google Search Console
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
def section_seo() -> None:
|
||||||
|
print("## SEO: Google Search Console")
|
||||||
|
site, creds = gsc_creds()
|
||||||
|
if not site or not creds:
|
||||||
|
print(f"{WARN} set GSC_SITE_URL + GOOGLE_APPLICATION_CREDENTIALS to enable\n")
|
||||||
|
return
|
||||||
|
try:
|
||||||
|
cur = gsc_query(*WK_CUR)
|
||||||
|
prev = gsc_query(*WK_PREV)
|
||||||
|
except Exception as exc: # noqa: BLE001
|
||||||
|
print(f"{WARN} GSC failed: {exc}\n")
|
||||||
|
return
|
||||||
|
|
||||||
|
c, p = (cur[0] if cur else {}), (prev[0] if prev else {})
|
||||||
|
ci, cc = c.get("impressions", 0), c.get("clicks", 0)
|
||||||
|
pi, pc = p.get("impressions", 0), p.get("clicks", 0)
|
||||||
|
print(f" impressions {ci:>8,.0f}{delta(ci, pi)} (prior {pi:,.0f})")
|
||||||
|
print(f" clicks {cc:>8,.0f}{delta(cc, pc)} (prior {pc:,.0f})")
|
||||||
|
print(f" CTR {(cc / ci * 100 if ci else 0):>7.2f}%")
|
||||||
|
|
||||||
|
rows = sorted(
|
||||||
|
gsc_query(*WK_CUR, dimensions=["page"], limit=1000),
|
||||||
|
key=lambda r: r.get("impressions", 0),
|
||||||
|
reverse=True,
|
||||||
|
)
|
||||||
|
watch = ("twin", "postcode", "dashboard", "property-search", "cheaper")
|
||||||
|
print(" top pages (impressions / clicks):")
|
||||||
|
for r in rows[:8]:
|
||||||
|
page = r["keys"][0]
|
||||||
|
star = " ★" if any(w in page.lower() for w in watch) else ""
|
||||||
|
path = page.replace("https://perfect-postcode.co.uk", "") or "/"
|
||||||
|
print(
|
||||||
|
f" {r.get('impressions', 0):>6,.0f} / {r.get('clicks', 0):>4,.0f}"
|
||||||
|
f" {path}{star}"
|
||||||
|
)
|
||||||
|
print()
|
||||||
|
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# 2. YouTube
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
def section_youtube() -> None:
|
||||||
|
print("## YouTube")
|
||||||
|
api_key, channel = os.environ.get("YT_API_KEY"), os.environ.get("YT_CHANNEL_ID")
|
||||||
|
if not api_key or not channel:
|
||||||
|
print(f"{WARN} set YT_API_KEY + YT_CHANNEL_ID to enable\n")
|
||||||
|
return
|
||||||
|
try:
|
||||||
|
search = http_json(
|
||||||
|
"https://www.googleapis.com/youtube/v3/search?"
|
||||||
|
f"key={api_key}&channelId={channel}&part=id&type=video"
|
||||||
|
"&order=date&maxResults=15"
|
||||||
|
)
|
||||||
|
ids = [
|
||||||
|
it["id"]["videoId"]
|
||||||
|
for it in search.get("items", [])
|
||||||
|
if it.get("id", {}).get("videoId")
|
||||||
|
]
|
||||||
|
if not ids:
|
||||||
|
print(" (no public videos found)\n")
|
||||||
|
return
|
||||||
|
stats = http_json(
|
||||||
|
"https://www.googleapis.com/youtube/v3/videos?"
|
||||||
|
f"key={api_key}&part=snippet,statistics&id={','.join(ids)}"
|
||||||
|
)
|
||||||
|
print(" public views (Data API v3):")
|
||||||
|
for it in stats.get("items", []):
|
||||||
|
views = int(it.get("statistics", {}).get("viewCount", 0))
|
||||||
|
print(f" {views:>8,} {it['snippet']['title'][:48]}")
|
||||||
|
except Exception as exc: # noqa: BLE001
|
||||||
|
print(f"{WARN} YouTube Data API failed: {exc}")
|
||||||
|
|
||||||
|
oauth = os.environ.get("YT_OAUTH_TOKEN") # private metrics need founder OAuth
|
||||||
|
if not oauth:
|
||||||
|
print(
|
||||||
|
f" {WARN} set YT_OAUTH_TOKEN (founder OAuth) to add impressions, CTR "
|
||||||
|
"and avg view duration\n"
|
||||||
|
)
|
||||||
|
return
|
||||||
|
try:
|
||||||
|
token = google_token(
|
||||||
|
oauth,
|
||||||
|
["https://www.googleapis.com/auth/yt-analytics.readonly"],
|
||||||
|
authorized_user=True,
|
||||||
|
)
|
||||||
|
rep = http_json(
|
||||||
|
"https://youtubeanalytics.googleapis.com/v2/reports?ids=channel==MINE"
|
||||||
|
f"&startDate={WK_CUR[0]}&endDate={WK_CUR[1]}"
|
||||||
|
"&metrics=impressions,impressionsClickThroughRate,averageViewDuration,views"
|
||||||
|
"&dimensions=video&sort=-impressions&maxResults=15",
|
||||||
|
headers={"Authorization": f"Bearer {token}"},
|
||||||
|
)
|
||||||
|
print(" impressions / CTR% / avg-dur(s) (Analytics API):")
|
||||||
|
for vid, impr, ctr, avgdur, _views in rep.get("rows", []):
|
||||||
|
print(f" {impr:>7,} CTR {ctr:>5.1f}% {avgdur:>4.0f}s {vid}")
|
||||||
|
except Exception as exc: # noqa: BLE001
|
||||||
|
print(f" {WARN} YouTube Analytics failed: {exc}")
|
||||||
|
print()
|
||||||
|
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# 3. Funnel: Plausible (self-hosted)
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
def section_funnel():
|
||||||
|
print("## Funnel: Plausible")
|
||||||
|
if not os.environ.get("PLAUSIBLE_API_KEY"):
|
||||||
|
site = os.environ.get("PLAUSIBLE_SITE_ID", "perfect-postcode.co.uk")
|
||||||
|
print(f"{WARN} set PLAUSIBLE_API_KEY to enable (site={site})\n")
|
||||||
|
return None
|
||||||
|
|
||||||
|
def snapshot(rng):
|
||||||
|
return (
|
||||||
|
plausible_query(["visitors"], rng)[0],
|
||||||
|
plausible_query(["pageviews"], rng, MAP_FILTER)[0],
|
||||||
|
plausible_query(["visitors"], rng, ADD_FILTER)[0],
|
||||||
|
plausible_query(["visitors"], rng, CAP_FILTER)[0],
|
||||||
|
)
|
||||||
|
|
||||||
|
try:
|
||||||
|
cv, cm, cf, cc = snapshot(WK_CUR)
|
||||||
|
pv, pm, _pf, _pc = snapshot(WK_PREV)
|
||||||
|
except urllib.error.HTTPError as exc:
|
||||||
|
print(f"{WARN} Plausible query failed ({exc.code}); check key/site_id\n")
|
||||||
|
return None
|
||||||
|
except Exception as exc: # noqa: BLE001
|
||||||
|
print(f"{WARN} Plausible query failed: {exc}\n")
|
||||||
|
return None
|
||||||
|
|
||||||
|
print(f" visitors {cv:>7,}{delta(cv, pv)} (prior {pv:,})")
|
||||||
|
print(f" map opens {cm:>7,}{delta(cm, pm)} (prior {pm:,})")
|
||||||
|
print(
|
||||||
|
f" ≥1 filter applied {cf:>7,} = {(cf / cv * 100 if cv else 0):.0f}% of visitors"
|
||||||
|
)
|
||||||
|
print(
|
||||||
|
f" 3-filter cap hit {cc:>7,} = {(cc / cm * 100 if cm else 0):.0f}% of map opens"
|
||||||
|
)
|
||||||
|
print()
|
||||||
|
return cm # weekly map opens (unused below, but handy for callers)
|
||||||
|
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Kill / keep: month-over-month gate
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
def kill_keep(_map_opens_weekly) -> None:
|
||||||
|
print("## Kill / Keep")
|
||||||
|
impr_up = map_up = None
|
||||||
|
|
||||||
|
site, creds = gsc_creds()
|
||||||
|
if site and creds:
|
||||||
|
try:
|
||||||
|
cur = gsc_query(*MO_CUR)
|
||||||
|
prev = gsc_query(*MO_PREV)
|
||||||
|
impr_up = (cur[0]["impressions"] if cur else 0) > (
|
||||||
|
prev[0]["impressions"] if prev else 0
|
||||||
|
)
|
||||||
|
except Exception: # noqa: BLE001
|
||||||
|
impr_up = None
|
||||||
|
|
||||||
|
if os.environ.get("PLAUSIBLE_API_KEY"):
|
||||||
|
try:
|
||||||
|
map_up = (
|
||||||
|
plausible_query(["pageviews"], MO_CUR, MAP_FILTER)[0]
|
||||||
|
> plausible_query(["pageviews"], MO_PREV, MAP_FILTER)[0]
|
||||||
|
)
|
||||||
|
except Exception: # noqa: BLE001
|
||||||
|
map_up = None
|
||||||
|
|
||||||
|
fmt = lambda v: "?" if v is None else ("up" if v else "down") # noqa: E731
|
||||||
|
if impr_up and map_up:
|
||||||
|
verdict = "KEEP: impressions ↑ and map opens ↑ MoM"
|
||||||
|
elif impr_up is None or map_up is None:
|
||||||
|
verdict = "INCONCLUSIVE: enable GSC + Plausible to decide"
|
||||||
|
else:
|
||||||
|
verdict = "REVIEW: impressions and/or map opens did not grow MoM"
|
||||||
|
print(f" impressions MoM: {fmt(impr_up)} | map opens MoM: {fmt(map_up)}")
|
||||||
|
print(f" → {verdict}\n")
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> int:
|
||||||
|
print(f"# Perfect Postcode: weekly readout ({TODAY.isoformat()})")
|
||||||
|
print(f"week {WK_CUR[0]}…{WK_CUR[1]} vs prior {WK_PREV[0]}…{WK_PREV[1]}\n")
|
||||||
|
section_seo()
|
||||||
|
section_youtube()
|
||||||
|
map_opens_weekly = section_funnel()
|
||||||
|
kill_keep(map_opens_weekly)
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
sys.exit(main())
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
"""Zoopla (zoopla.co.uk) scraper — sale properties.
|
"""Zoopla (zoopla.co.uk) scraper: sale properties.
|
||||||
|
|
||||||
Zoopla is behind Cloudflare Turnstile (managed interactive challenge), which
|
Zoopla is behind Cloudflare Turnstile (managed interactive challenge), which
|
||||||
blocks non-browser HTTP clients and even Playwright with stealth patches. Only
|
blocks non-browser HTTP clients and even Playwright with stealth patches. Only
|
||||||
|
|
@ -522,7 +522,7 @@ def _gluetun_set_vpn_status(client: httpx.Client, status: str) -> bool:
|
||||||
return False
|
return False
|
||||||
if resp.status_code == 401:
|
if resp.status_code == 401:
|
||||||
log.warning(
|
log.warning(
|
||||||
"Gluetun vpn/status %s: 401 Unauthorized — the API key must be "
|
"Gluetun vpn/status %s: 401 Unauthorized. The API key must be "
|
||||||
"authorised for 'PUT /v1/vpn/status' in Gluetun's auth config.toml",
|
"authorised for 'PUT /v1/vpn/status' in Gluetun's auth config.toml",
|
||||||
status,
|
status,
|
||||||
)
|
)
|
||||||
|
|
@ -593,7 +593,7 @@ def _rotate_and_retry_challenge(page, max_rotations: int) -> bool:
|
||||||
"""Rotate IP and reload until the challenge clears. Returns True on success."""
|
"""Rotate IP and reload until the challenge clears. Returns True on success."""
|
||||||
for attempt in range(1, max_rotations + 1):
|
for attempt in range(1, max_rotations + 1):
|
||||||
log.warning(
|
log.warning(
|
||||||
"Cloudflare Turnstile challenge — rotating Gluetun IP (attempt %d/%d)",
|
"Cloudflare Turnstile challenge, rotating Gluetun IP (attempt %d/%d)",
|
||||||
attempt, max_rotations,
|
attempt, max_rotations,
|
||||||
)
|
)
|
||||||
if not _rotate_gluetun_ip():
|
if not _rotate_gluetun_ip():
|
||||||
|
|
@ -637,7 +637,7 @@ def _wait_for_turnstile(page, headless_mode: bool | str) -> None:
|
||||||
if not _is_turnstile_challenge(page):
|
if not _is_turnstile_challenge(page):
|
||||||
return
|
return
|
||||||
|
|
||||||
# Try Gluetun IP rotation first — works in any mode and is the only option
|
# Try Gluetun IP rotation first: works in any mode and is the only option
|
||||||
# in headless/unattended runs where no human can click the challenge.
|
# in headless/unattended runs where no human can click the challenge.
|
||||||
max_rotations = _gluetun_max_rotations()
|
max_rotations = _gluetun_max_rotations()
|
||||||
if max_rotations > 0 and _rotate_and_retry_challenge(page, max_rotations):
|
if max_rotations > 0 and _rotate_and_retry_challenge(page, max_rotations):
|
||||||
|
|
@ -654,7 +654,7 @@ def _wait_for_turnstile(page, headless_mode: bool | str) -> None:
|
||||||
|
|
||||||
timeout = _challenge_timeout_seconds()
|
timeout = _challenge_timeout_seconds()
|
||||||
log.warning(
|
log.warning(
|
||||||
"Gluetun rotation insufficient — falling back to interactive solve. "
|
"Gluetun rotation insufficient. Falling back to interactive solve. "
|
||||||
"Complete the Cloudflare challenge in the Zoopla browser window; "
|
"Complete the Cloudflare challenge in the Zoopla browser window; "
|
||||||
"waiting up to %ds. Profile: %s",
|
"waiting up to %ds. Profile: %s",
|
||||||
timeout,
|
timeout,
|
||||||
|
|
@ -727,7 +727,7 @@ def launch_browser():
|
||||||
page.goto(f"{ZOOPLA_BASE}/", wait_until="domcontentloaded", timeout=60000)
|
page.goto(f"{ZOOPLA_BASE}/", wait_until="domcontentloaded", timeout=60000)
|
||||||
_wait_for_turnstile(page, headless_mode)
|
_wait_for_turnstile(page, headless_mode)
|
||||||
|
|
||||||
log.info("Zoopla browser ready — title: %s", page.title())
|
log.info("Zoopla browser ready, title: %s", page.title())
|
||||||
time.sleep(2)
|
time.sleep(2)
|
||||||
|
|
||||||
# Dismiss cookie consent
|
# Dismiss cookie consent
|
||||||
|
|
@ -1117,14 +1117,14 @@ def _extract_outcode(text: str) -> str | None:
|
||||||
# "outcode":...,"postcode":...,"uprn":...} feeding the map widgets.
|
# "outcode":...,"postcode":...,"uprn":...} feeding the map widgets.
|
||||||
# Nearby points of interest (stations, schools, EV chargers) and comparable
|
# Nearby points of interest (stations, schools, EV chargers) and comparable
|
||||||
# listings carry their own "coordinates" too, but never inside the property's
|
# listings carry their own "coordinates" too, but never inside the property's
|
||||||
# own "location" / "address":{"fullAddress" wrapper — so the wrapper, not a
|
# own "location" / "address":{"fullAddress" wrapper, so the wrapper, not a
|
||||||
# loose coordinates object, is what we anchor on (see parse_detail_geo).
|
# loose coordinates object, is what we anchor on (see parse_detail_geo).
|
||||||
|
|
||||||
# listingId -> parsed detail dict (or None). Failures are cached too, so a
|
# listingId -> parsed detail dict (or None). Failures are cached too, so a
|
||||||
# broken listing is not re-fetched within a run (the same listing reappears
|
# broken listing is not re-fetched within a run (the same listing reappears
|
||||||
# across overlapping outcode searches). Seeded from / dumped to a persistent
|
# across overlapping outcode searches). Seeded from / dumped to a persistent
|
||||||
# on-disk cache by the orchestrator (see postcode_cache.py) so a recurring
|
# on-disk cache by the orchestrator (see postcode_cache.py) so a recurring
|
||||||
# scrape only re-fetches newly-listed properties — the biggest saving for
|
# scrape only re-fetches newly-listed properties, the biggest saving for
|
||||||
# Zoopla, whose detail fetch drives a real browser tab.
|
# Zoopla, whose detail fetch drives a real browser tab.
|
||||||
_detail_cache: dict[str, dict | None] = {}
|
_detail_cache: dict[str, dict | None] = {}
|
||||||
|
|
||||||
|
|
@ -1144,7 +1144,7 @@ _LISTING_ID_RE = re.compile(r"/details/(\d+)/?")
|
||||||
# The property's own location is carried by a `"location":{...}` wrapper and a
|
# The property's own location is carried by a `"location":{...}` wrapper and a
|
||||||
# twin `"address":{"fullAddress":...}` widget object. We anchor on those
|
# twin `"address":{"fullAddress":...}` widget object. We anchor on those
|
||||||
# wrappers (and capture their full object body, which contains exactly one
|
# wrappers (and capture their full object body, which contains exactly one
|
||||||
# nested object — `coordinates`) rather than scanning for loose coordinate
|
# nested object, `coordinates`) rather than scanning for loose coordinate
|
||||||
# objects: nearby points of interest (stations/schools/EV chargers) and
|
# objects: nearby points of interest (stations/schools/EV chargers) and
|
||||||
# comparable/"similar" listings also embed coordinates, but never inside the
|
# comparable/"similar" listings also embed coordinates, but never inside the
|
||||||
# property's own `"location"` / `"address":{"fullAddress"` wrapper, so the
|
# property's own `"location"` / `"address":{"fullAddress"` wrapper, so the
|
||||||
|
|
@ -1225,7 +1225,7 @@ def parse_detail_geo(html: str, search_outcode: str | None = None) -> dict | Non
|
||||||
# twin, not the `location` wrapper we anchor coordinates on. Pull it from
|
# twin, not the `location` wrapper we anchor coordinates on. Pull it from
|
||||||
# the twin that shares this property's uprn; when there is no uprn to
|
# the twin that shares this property's uprn; when there is no uprn to
|
||||||
# disambiguate, fall back to the first twin (document order = primary
|
# disambiguate, fall back to the first twin (document order = primary
|
||||||
# listing), but never guess a twin when a uprn exists and none matches —
|
# listing), but never guess a twin when a uprn exists and none matches:
|
||||||
# that would risk grabbing a comparable listing's address.
|
# that would risk grabbing a comparable listing's address.
|
||||||
if result is None or result.get("full_address"):
|
if result is None or result.get("full_address"):
|
||||||
return result
|
return result
|
||||||
|
|
@ -1245,7 +1245,7 @@ def parse_detail_geo(html: str, search_outcode: str | None = None) -> dict | Non
|
||||||
result["full_address"] = first
|
result["full_address"] = first
|
||||||
return result
|
return result
|
||||||
|
|
||||||
# Strategy 1 — the property's own `location` wrapper (authoritative). Take
|
# Strategy 1: the property's own `location` wrapper (authoritative). Take
|
||||||
# the first match (the primary listing precedes any comparables in the
|
# the first match (the primary listing precedes any comparables in the
|
||||||
# flight stream), but prefer one whose outcode matches the searched outcode.
|
# flight stream), but prefer one whose outcode matches the searched outcode.
|
||||||
first_location = None
|
first_location = None
|
||||||
|
|
@ -1269,7 +1269,7 @@ def parse_detail_geo(html: str, search_outcode: str | None = None) -> dict | Non
|
||||||
if first_location is not None:
|
if first_location is not None:
|
||||||
return attach_full_address(first_location)
|
return attach_full_address(first_location)
|
||||||
|
|
||||||
# Strategy 2 — the `address` map-widget twin (same coordinates, backup).
|
# Strategy 2: the `address` map-widget twin (same coordinates, backup).
|
||||||
for match in _DETAIL_ADDRESS_RE.finditer(buf):
|
for match in _DETAIL_ADDRESS_RE.finditer(buf):
|
||||||
full_address = match.group(1) or None
|
full_address = match.group(1) or None
|
||||||
body = match.group(2)
|
body = match.group(2)
|
||||||
|
|
@ -1284,7 +1284,7 @@ def parse_detail_geo(html: str, search_outcode: str | None = None) -> dict | Non
|
||||||
|
|
||||||
|
|
||||||
def _detail_cache_key(listing_url: str) -> str:
|
def _detail_cache_key(listing_url: str) -> str:
|
||||||
"""Cache key for a listing detail page — its numeric id when present."""
|
"""Cache key for a listing detail page: its numeric id when present."""
|
||||||
id_match = _LISTING_ID_RE.search(listing_url)
|
id_match = _LISTING_ID_RE.search(listing_url)
|
||||||
return id_match.group(1) if id_match else listing_url
|
return id_match.group(1) if id_match else listing_url
|
||||||
|
|
||||||
|
|
@ -1388,7 +1388,7 @@ def transform_property(
|
||||||
location comes from the listing's detail page (see ``parse_detail_geo`` /
|
location comes from the listing's detail page (see ``parse_detail_geo`` /
|
||||||
``_fetch_listing_detail``), passed in as ``detail``. When detail-page
|
``_fetch_listing_detail``), passed in as ``detail``. When detail-page
|
||||||
coordinates are available we resolve the nearest postcode via the spatial
|
coordinates are available we resolve the nearest postcode via the spatial
|
||||||
index — mirroring rightmove/onthemarket — and only fall back to the coarse
|
index (mirroring rightmove/onthemarket) and only fall back to the coarse
|
||||||
outcode centroid when no detail location could be obtained."""
|
outcode centroid when no detail location could be obtained."""
|
||||||
price = parse_int_value(raw.get("price")) or 0
|
price = parse_int_value(raw.get("price")) or 0
|
||||||
|
|
||||||
|
|
@ -1563,7 +1563,7 @@ def search_outcode(
|
||||||
if detail_budget_seconds is not None:
|
if detail_budget_seconds is not None:
|
||||||
detail_deadline = time.monotonic() + detail_budget_seconds
|
detail_deadline = time.monotonic() + detail_budget_seconds
|
||||||
|
|
||||||
# Always try extraction even if result count is 0 — the count regex may
|
# Always try extraction even if result count is 0: the count regex may
|
||||||
# not match Zoopla's current text format, but listings may still be in DOM
|
# not match Zoopla's current text format, but listings may still be in DOM
|
||||||
raw_listings = _paginate(
|
raw_listings = _paginate(
|
||||||
page,
|
page,
|
||||||
|
|
@ -1577,7 +1577,7 @@ def search_outcode(
|
||||||
if not raw_listings:
|
if not raw_listings:
|
||||||
if total_results > 0:
|
if total_results > 0:
|
||||||
log.debug(
|
log.debug(
|
||||||
"Zoopla %s %s: page claims %d results but extraction found 0 — "
|
"Zoopla %s %s: page claims %d results but extraction found 0; "
|
||||||
"DOM selectors may need updating",
|
"DOM selectors may need updating",
|
||||||
outcode, "BUY", total_results,
|
outcode, "BUY", total_results,
|
||||||
)
|
)
|
||||||
|
|
|
||||||
87
frontend/public/cheaper-twin/br3-3-vs-cr0-7/index.html
Normal file
87
frontend/public/cheaper-twin/br3-3-vs-cr0-7/index.html
Normal file
|
|
@ -0,0 +1,87 @@
|
||||||
|
<!doctype html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
<title>Beckenham vs Croydon: the same terraced house, about 31% cheaper per m² | Perfect Postcode</title>
|
||||||
|
<meta name="description" content="£201,870 less for an equivalent terraced house: same station, similar schools, ~2.02km apart" />
|
||||||
|
<link rel="canonical" href="https://perfect-postcode.co.uk/cheaper-twin/br3-3-vs-cr0-7" />
|
||||||
|
<style>
|
||||||
|
:root{color-scheme:light dark}
|
||||||
|
*{box-sizing:border-box}
|
||||||
|
body{margin:0;font-family:ui-sans-serif,system-ui,-apple-system,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;
|
||||||
|
color:#0b1220;background:#f7f5f0;line-height:1.6}
|
||||||
|
a{color:#0d9488}
|
||||||
|
.topbar{background:#0b1220;color:#e7ecf3;padding:.7rem 1.25rem;display:flex;justify-content:space-between;align-items:center}
|
||||||
|
.topbar a{color:#2dd4bf;text-decoration:none;font-weight:700}
|
||||||
|
.wrap{max-width:54rem;margin:0 auto;padding:0 1.25rem}
|
||||||
|
.hero{background:linear-gradient(#0b1220,#111a2e);color:#fff;padding:3rem 0 2.5rem}
|
||||||
|
.eyebrow{color:#2dd4bf;font-weight:700;text-transform:uppercase;letter-spacing:.05em;font-size:.8rem;margin:0 0 .5rem}
|
||||||
|
h1{font-size:2rem;line-height:1.15;margin:.2rem 0 .6rem}
|
||||||
|
.hook{color:#cbd5e1;font-size:1.15rem;margin:.5rem 0 1.4rem;max-width:42rem}
|
||||||
|
.big{font-size:3rem;font-weight:800;color:#2dd4bf;margin:.3rem 0}
|
||||||
|
.cta{display:inline-block;margin-top:.4rem;padding:.8rem 1.4rem;border-radius:.6rem;background:#f09a22;color:#0b1220;
|
||||||
|
font-weight:700;text-decoration:none;box-shadow:0 6px 20px rgba(122,57,5,.35)}
|
||||||
|
.cta:hover{background:#df8614}
|
||||||
|
table{width:100%;border-collapse:collapse;margin:1.5rem 0;background:#fff;border-radius:.6rem;overflow:hidden;
|
||||||
|
box-shadow:0 1px 3px rgba(0,0,0,.08)}
|
||||||
|
th,td{padding:.7rem .9rem;text-align:left;border-bottom:1px solid #ece8e0;font-size:.95rem}
|
||||||
|
thead th{background:#0b1220;color:#fff}
|
||||||
|
tbody tr:last-child td{border-bottom:0}
|
||||||
|
.val{font-variant-numeric:tabular-nums;font-weight:600}
|
||||||
|
.cheaper{color:#0d9488}
|
||||||
|
section{margin:2rem 0}
|
||||||
|
h2{font-size:1.3rem;margin:0 0 .6rem}
|
||||||
|
.note{font-size:.82rem;color:#6b7280;border-top:1px solid #e5e1d8;padding-top:1rem;margin-top:2rem}
|
||||||
|
.links{display:grid;gap:.6rem;grid-template-columns:repeat(auto-fit,minmax(15rem,1fr));margin:1rem 0}
|
||||||
|
.links a{display:block;background:#fff;border:1px solid #ece8e0;border-radius:.5rem;padding:.8rem 1rem;text-decoration:none;color:#0b1220}
|
||||||
|
.links a:hover{border-color:#5eead4}
|
||||||
|
.links b{color:#0d9488}
|
||||||
|
.cards{display:grid;gap:1rem;grid-template-columns:repeat(auto-fit,minmax(18rem,1fr))}
|
||||||
|
.card{background:#fff;border:1px solid #ece8e0;border-radius:.6rem;padding:1.1rem;text-decoration:none;color:#0b1220}
|
||||||
|
.card:hover{border-color:#5eead4}
|
||||||
|
.card .n{color:#0d9488;font-weight:800;font-size:1.4rem}
|
||||||
|
footer{color:#6b7280;font-size:.8rem;padding:2rem 0 3rem}
|
||||||
|
@media(prefers-color-scheme:dark){body{background:#0b1220;color:#e7ecf3}table{background:#13203a}
|
||||||
|
th,td{border-color:#223153}.card,.links a{background:#13203a;border-color:#223153;color:#e7ecf3}
|
||||||
|
.note{border-color:#223153;color:#9fb0c3}}
|
||||||
|
</style>
|
||||||
|
<script type="application/ld+json">{"@context": "https://schema.org", "@type": "BreadcrumbList", "itemListElement": [{"@type": "ListItem", "position": 1, "name": "Home", "item": "https://perfect-postcode.co.uk/"}, {"@type": "ListItem", "position": 2, "name": "Cheaper twins", "item": "https://perfect-postcode.co.uk/cheaper-twins"}, {"@type": "ListItem", "position": 3, "name": "Beckenham vs Croydon", "item": "https://perfect-postcode.co.uk/cheaper-twin/br3-3-vs-cr0-7"}]}</script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="topbar"><a href="/">Perfect Postcode</a><a href="/?ref=twin">Open the map →</a></div>
|
||||||
|
|
||||||
|
<div class="hero"><div class="wrap">
|
||||||
|
<p class="eyebrow">Cheaper twin · England</p>
|
||||||
|
<h1>Beckenham vs Croydon: the same terraced house, about 31% cheaper per m²</h1>
|
||||||
|
<div class="big">31% cheaper / m²</div>
|
||||||
|
<p class="hook">£201,870 less for an equivalent terraced house: same station, similar schools, ~2.02km apart</p>
|
||||||
|
<a class="cta" href="https://perfect-postcode.co.uk/?lat=51.38969&lon=-0.04244&zoom=12.5&filter=Est.%20price%20per%20sqm:0:5200&filter=Good%2B%20secondary%20school%20catchments:1:11">See both areas on the live map →</a>
|
||||||
|
</div></div>
|
||||||
|
<div class="wrap">
|
||||||
|
<table><thead><tr><th></th><th>Beckenham (BR3 3)</th><th>Croydon (CR0 7)</th></tr></thead>
|
||||||
|
<tbody><tr><td>Estimated £/m²</td><td class='val'>£7,153</td><td class='val'>£4,910</td></tr>
|
||||||
|
<tr><td>On a 90 m² home</td><td class='val'>£643,770</td><td class='val'><span class="cheaper">£441,900</span></td></tr>
|
||||||
|
<tr><td>Dominant property type</td><td class='val'>Terraced</td><td class='val'>Terraced</td></tr>
|
||||||
|
<tr><td>Typical build era</td><td class='val'>~1940</td><td class='val'>~1940</td></tr>
|
||||||
|
<tr><td>Good+ secondary catchments</td><td class='val'>7.8</td><td class='val'>7.8</td></tr>
|
||||||
|
<tr><td>Nearest station</td><td class='val'>~0.73 km</td><td class='val'>~0.73 km</td></tr>
|
||||||
|
<tr><td>Sales in sample (N)</td><td class='val'>4,514</td><td class='val'>5,143</td></tr></tbody></table>
|
||||||
|
<section><h2>The same life, one postcode cheaper</h2><p>Beckenham (BR3 3) and Croydon (CR0 7) sit about 2.02 km apart, share the same dominant housing (terraced, typically built around 1940), comparable good-school catchments and the same level of station access. Yet an equivalent home works out roughly <b>31% (about £201,870 on a 90 m² property) cheaper in Croydon</b>. On the measures that move price they are near-identical; the gap is mostly the premium attached to the better-known name.</p></section>
|
||||||
|
<section><h2>How we worked this out</h2><p>Postcode sectors (e.g. N10 3) compared on estimated £/m² of floor space. A pair is only called a 'twin' when the two sectors share the dominant property type, build era (±30y), good-school catchment provision, station access, deprivation/tenure, education, age and home size, so the price gap reflects a name premium, not a different kind of area. Estimates, not valuations; aggregated to sector, never address-level.</p></section>
|
||||||
|
<section><h2>Compare more areas</h2>
|
||||||
|
<div class="links">
|
||||||
|
<a href="/cheaper-twins"><b>All cheaper twins →</b><br>Browse every England name-premium pair we found.</a>
|
||||||
|
<a href="/postcode-checker"><b>Postcode checker →</b><br>Prices, crime, schools, broadband for any postcode.</a>
|
||||||
|
<a href="/property-price-map"><b>Property price map →</b><br>Rank England by what each £ buys.</a>
|
||||||
|
</div>
|
||||||
|
<div class="links"><a href="/cheaper-twin/ha7-2-vs-ha3-0"><b>Stanmore vs Kenton</b><br>£106,920 less for an equivalent semi-detached house: same station, similar schools, ~2.57km apart</a>
|
||||||
|
<a href="/cheaper-twin/ig8-7-vs-ig6-2"><b>Woodford Green vs Barkingside</b><br>£164,070 less for an equivalent terraced house: same station, similar schools, ~2.98km apart</a>
|
||||||
|
<a href="/cheaper-twin/l16-7-vs-l14-6"><b>Childwall vs Broadgreen</b><br>£106,740 less for an equivalent semi-detached house: same station, similar schools, ~1.88km apart</a></div>
|
||||||
|
</section>
|
||||||
|
<p class="note">Contains HM Land Registry data © Crown copyright and database right. Licensed under the Open Government Licence v3.0. Figures are estimates derived from recorded sales and EPC floor areas, aggregated to postcode sector, not valuations, and not address-level.</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<footer><div class="wrap">Sources: HM Land Registry · EPC (DLUHC) · Ofsted · DfT · ONS · Police.uk. Contains HM Land Registry data © Crown copyright and database right. Licensed under the Open Government Licence v3.0.</div></footer>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
87
frontend/public/cheaper-twin/ha7-2-vs-ha3-0/index.html
Normal file
87
frontend/public/cheaper-twin/ha7-2-vs-ha3-0/index.html
Normal file
|
|
@ -0,0 +1,87 @@
|
||||||
|
<!doctype html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
<title>Stanmore vs Kenton: the same semi-detached house, about 17% cheaper per m² | Perfect Postcode</title>
|
||||||
|
<meta name="description" content="£106,920 less for an equivalent semi-detached house: same station, similar schools, ~2.57km apart" />
|
||||||
|
<link rel="canonical" href="https://perfect-postcode.co.uk/cheaper-twin/ha7-2-vs-ha3-0" />
|
||||||
|
<style>
|
||||||
|
:root{color-scheme:light dark}
|
||||||
|
*{box-sizing:border-box}
|
||||||
|
body{margin:0;font-family:ui-sans-serif,system-ui,-apple-system,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;
|
||||||
|
color:#0b1220;background:#f7f5f0;line-height:1.6}
|
||||||
|
a{color:#0d9488}
|
||||||
|
.topbar{background:#0b1220;color:#e7ecf3;padding:.7rem 1.25rem;display:flex;justify-content:space-between;align-items:center}
|
||||||
|
.topbar a{color:#2dd4bf;text-decoration:none;font-weight:700}
|
||||||
|
.wrap{max-width:54rem;margin:0 auto;padding:0 1.25rem}
|
||||||
|
.hero{background:linear-gradient(#0b1220,#111a2e);color:#fff;padding:3rem 0 2.5rem}
|
||||||
|
.eyebrow{color:#2dd4bf;font-weight:700;text-transform:uppercase;letter-spacing:.05em;font-size:.8rem;margin:0 0 .5rem}
|
||||||
|
h1{font-size:2rem;line-height:1.15;margin:.2rem 0 .6rem}
|
||||||
|
.hook{color:#cbd5e1;font-size:1.15rem;margin:.5rem 0 1.4rem;max-width:42rem}
|
||||||
|
.big{font-size:3rem;font-weight:800;color:#2dd4bf;margin:.3rem 0}
|
||||||
|
.cta{display:inline-block;margin-top:.4rem;padding:.8rem 1.4rem;border-radius:.6rem;background:#f09a22;color:#0b1220;
|
||||||
|
font-weight:700;text-decoration:none;box-shadow:0 6px 20px rgba(122,57,5,.35)}
|
||||||
|
.cta:hover{background:#df8614}
|
||||||
|
table{width:100%;border-collapse:collapse;margin:1.5rem 0;background:#fff;border-radius:.6rem;overflow:hidden;
|
||||||
|
box-shadow:0 1px 3px rgba(0,0,0,.08)}
|
||||||
|
th,td{padding:.7rem .9rem;text-align:left;border-bottom:1px solid #ece8e0;font-size:.95rem}
|
||||||
|
thead th{background:#0b1220;color:#fff}
|
||||||
|
tbody tr:last-child td{border-bottom:0}
|
||||||
|
.val{font-variant-numeric:tabular-nums;font-weight:600}
|
||||||
|
.cheaper{color:#0d9488}
|
||||||
|
section{margin:2rem 0}
|
||||||
|
h2{font-size:1.3rem;margin:0 0 .6rem}
|
||||||
|
.note{font-size:.82rem;color:#6b7280;border-top:1px solid #e5e1d8;padding-top:1rem;margin-top:2rem}
|
||||||
|
.links{display:grid;gap:.6rem;grid-template-columns:repeat(auto-fit,minmax(15rem,1fr));margin:1rem 0}
|
||||||
|
.links a{display:block;background:#fff;border:1px solid #ece8e0;border-radius:.5rem;padding:.8rem 1rem;text-decoration:none;color:#0b1220}
|
||||||
|
.links a:hover{border-color:#5eead4}
|
||||||
|
.links b{color:#0d9488}
|
||||||
|
.cards{display:grid;gap:1rem;grid-template-columns:repeat(auto-fit,minmax(18rem,1fr))}
|
||||||
|
.card{background:#fff;border:1px solid #ece8e0;border-radius:.6rem;padding:1.1rem;text-decoration:none;color:#0b1220}
|
||||||
|
.card:hover{border-color:#5eead4}
|
||||||
|
.card .n{color:#0d9488;font-weight:800;font-size:1.4rem}
|
||||||
|
footer{color:#6b7280;font-size:.8rem;padding:2rem 0 3rem}
|
||||||
|
@media(prefers-color-scheme:dark){body{background:#0b1220;color:#e7ecf3}table{background:#13203a}
|
||||||
|
th,td{border-color:#223153}.card,.links a{background:#13203a;border-color:#223153;color:#e7ecf3}
|
||||||
|
.note{border-color:#223153;color:#9fb0c3}}
|
||||||
|
</style>
|
||||||
|
<script type="application/ld+json">{"@context": "https://schema.org", "@type": "BreadcrumbList", "itemListElement": [{"@type": "ListItem", "position": 1, "name": "Home", "item": "https://perfect-postcode.co.uk/"}, {"@type": "ListItem", "position": 2, "name": "Cheaper twins", "item": "https://perfect-postcode.co.uk/cheaper-twins"}, {"@type": "ListItem", "position": 3, "name": "Stanmore vs Kenton", "item": "https://perfect-postcode.co.uk/cheaper-twin/ha7-2-vs-ha3-0"}]}</script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="topbar"><a href="/">Perfect Postcode</a><a href="/?ref=twin">Open the map →</a></div>
|
||||||
|
|
||||||
|
<div class="hero"><div class="wrap">
|
||||||
|
<p class="eyebrow">Cheaper twin · England</p>
|
||||||
|
<h1>Stanmore vs Kenton: the same semi-detached house, about 17% cheaper per m²</h1>
|
||||||
|
<div class="big">17% cheaper / m²</div>
|
||||||
|
<p class="hook">£106,920 less for an equivalent semi-detached house: same station, similar schools, ~2.57km apart</p>
|
||||||
|
<a class="cta" href="https://perfect-postcode.co.uk/?lat=51.59199&lon=-0.3079&zoom=12.5&filter=Est.%20price%20per%20sqm:0:5900&filter=Good%2B%20secondary%20school%20catchments:1:11">See both areas on the live map →</a>
|
||||||
|
</div></div>
|
||||||
|
<div class="wrap">
|
||||||
|
<table><thead><tr><th></th><th>Stanmore (HA7 2)</th><th>Kenton (HA3 0)</th></tr></thead>
|
||||||
|
<tbody><tr><td>Estimated £/m²</td><td class='val'>£6,834</td><td class='val'>£5,646</td></tr>
|
||||||
|
<tr><td>On a 90 m² home</td><td class='val'>£615,060</td><td class='val'><span class="cheaper">£508,140</span></td></tr>
|
||||||
|
<tr><td>Dominant property type</td><td class='val'>Semi-Detached</td><td class='val'>Semi-Detached</td></tr>
|
||||||
|
<tr><td>Typical build era</td><td class='val'>~1940</td><td class='val'>~1940</td></tr>
|
||||||
|
<tr><td>Good+ secondary catchments</td><td class='val'>2.9</td><td class='val'>2.9</td></tr>
|
||||||
|
<tr><td>Nearest station</td><td class='val'>~1.31 km</td><td class='val'>~1.31 km</td></tr>
|
||||||
|
<tr><td>Sales in sample (N)</td><td class='val'>2,775</td><td class='val'>3,122</td></tr></tbody></table>
|
||||||
|
<section><h2>The same life, one postcode cheaper</h2><p>Stanmore (HA7 2) and Kenton (HA3 0) sit about 2.57 km apart, share the same dominant housing (semi-detached, typically built around 1940), comparable good-school catchments and the same level of station access. Yet an equivalent home works out roughly <b>17% (about £106,920 on a 90 m² property) cheaper in Kenton</b>. On the measures that move price they are near-identical; the gap is mostly the premium attached to the better-known name.</p></section>
|
||||||
|
<section><h2>How we worked this out</h2><p>Postcode sectors (e.g. N10 3) compared on estimated £/m² of floor space. A pair is only called a 'twin' when the two sectors share the dominant property type, build era (±30y), good-school catchment provision, station access, deprivation/tenure, education, age and home size, so the price gap reflects a name premium, not a different kind of area. Estimates, not valuations; aggregated to sector, never address-level.</p></section>
|
||||||
|
<section><h2>Compare more areas</h2>
|
||||||
|
<div class="links">
|
||||||
|
<a href="/cheaper-twins"><b>All cheaper twins →</b><br>Browse every England name-premium pair we found.</a>
|
||||||
|
<a href="/postcode-checker"><b>Postcode checker →</b><br>Prices, crime, schools, broadband for any postcode.</a>
|
||||||
|
<a href="/property-price-map"><b>Property price map →</b><br>Rank England by what each £ buys.</a>
|
||||||
|
</div>
|
||||||
|
<div class="links"><a href="/cheaper-twin/ig8-7-vs-ig6-2"><b>Woodford Green vs Barkingside</b><br>£164,070 less for an equivalent terraced house: same station, similar schools, ~2.98km apart</a>
|
||||||
|
<a href="/cheaper-twin/l16-7-vs-l14-6"><b>Childwall vs Broadgreen</b><br>£106,740 less for an equivalent semi-detached house: same station, similar schools, ~1.88km apart</a>
|
||||||
|
<a href="/cheaper-twin/m40-5-vs-m9-4"><b>Newton Heath vs Harpurhey</b><br>£106,740 less for an equivalent terraced house: same station, similar schools, ~1.18km apart</a></div>
|
||||||
|
</section>
|
||||||
|
<p class="note">Contains HM Land Registry data © Crown copyright and database right. Licensed under the Open Government Licence v3.0. Figures are estimates derived from recorded sales and EPC floor areas, aggregated to postcode sector, not valuations, and not address-level.</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<footer><div class="wrap">Sources: HM Land Registry · EPC (DLUHC) · Ofsted · DfT · ONS · Police.uk. Contains HM Land Registry data © Crown copyright and database right. Licensed under the Open Government Licence v3.0.</div></footer>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
87
frontend/public/cheaper-twin/ig8-7-vs-ig6-2/index.html
Normal file
87
frontend/public/cheaper-twin/ig8-7-vs-ig6-2/index.html
Normal file
|
|
@ -0,0 +1,87 @@
|
||||||
|
<!doctype html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
<title>Woodford Green vs Barkingside: the same terraced house, about 26% cheaper per m² | Perfect Postcode</title>
|
||||||
|
<meta name="description" content="£164,070 less for an equivalent terraced house: same station, similar schools, ~2.98km apart" />
|
||||||
|
<link rel="canonical" href="https://perfect-postcode.co.uk/cheaper-twin/ig8-7-vs-ig6-2" />
|
||||||
|
<style>
|
||||||
|
:root{color-scheme:light dark}
|
||||||
|
*{box-sizing:border-box}
|
||||||
|
body{margin:0;font-family:ui-sans-serif,system-ui,-apple-system,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;
|
||||||
|
color:#0b1220;background:#f7f5f0;line-height:1.6}
|
||||||
|
a{color:#0d9488}
|
||||||
|
.topbar{background:#0b1220;color:#e7ecf3;padding:.7rem 1.25rem;display:flex;justify-content:space-between;align-items:center}
|
||||||
|
.topbar a{color:#2dd4bf;text-decoration:none;font-weight:700}
|
||||||
|
.wrap{max-width:54rem;margin:0 auto;padding:0 1.25rem}
|
||||||
|
.hero{background:linear-gradient(#0b1220,#111a2e);color:#fff;padding:3rem 0 2.5rem}
|
||||||
|
.eyebrow{color:#2dd4bf;font-weight:700;text-transform:uppercase;letter-spacing:.05em;font-size:.8rem;margin:0 0 .5rem}
|
||||||
|
h1{font-size:2rem;line-height:1.15;margin:.2rem 0 .6rem}
|
||||||
|
.hook{color:#cbd5e1;font-size:1.15rem;margin:.5rem 0 1.4rem;max-width:42rem}
|
||||||
|
.big{font-size:3rem;font-weight:800;color:#2dd4bf;margin:.3rem 0}
|
||||||
|
.cta{display:inline-block;margin-top:.4rem;padding:.8rem 1.4rem;border-radius:.6rem;background:#f09a22;color:#0b1220;
|
||||||
|
font-weight:700;text-decoration:none;box-shadow:0 6px 20px rgba(122,57,5,.35)}
|
||||||
|
.cta:hover{background:#df8614}
|
||||||
|
table{width:100%;border-collapse:collapse;margin:1.5rem 0;background:#fff;border-radius:.6rem;overflow:hidden;
|
||||||
|
box-shadow:0 1px 3px rgba(0,0,0,.08)}
|
||||||
|
th,td{padding:.7rem .9rem;text-align:left;border-bottom:1px solid #ece8e0;font-size:.95rem}
|
||||||
|
thead th{background:#0b1220;color:#fff}
|
||||||
|
tbody tr:last-child td{border-bottom:0}
|
||||||
|
.val{font-variant-numeric:tabular-nums;font-weight:600}
|
||||||
|
.cheaper{color:#0d9488}
|
||||||
|
section{margin:2rem 0}
|
||||||
|
h2{font-size:1.3rem;margin:0 0 .6rem}
|
||||||
|
.note{font-size:.82rem;color:#6b7280;border-top:1px solid #e5e1d8;padding-top:1rem;margin-top:2rem}
|
||||||
|
.links{display:grid;gap:.6rem;grid-template-columns:repeat(auto-fit,minmax(15rem,1fr));margin:1rem 0}
|
||||||
|
.links a{display:block;background:#fff;border:1px solid #ece8e0;border-radius:.5rem;padding:.8rem 1rem;text-decoration:none;color:#0b1220}
|
||||||
|
.links a:hover{border-color:#5eead4}
|
||||||
|
.links b{color:#0d9488}
|
||||||
|
.cards{display:grid;gap:1rem;grid-template-columns:repeat(auto-fit,minmax(18rem,1fr))}
|
||||||
|
.card{background:#fff;border:1px solid #ece8e0;border-radius:.6rem;padding:1.1rem;text-decoration:none;color:#0b1220}
|
||||||
|
.card:hover{border-color:#5eead4}
|
||||||
|
.card .n{color:#0d9488;font-weight:800;font-size:1.4rem}
|
||||||
|
footer{color:#6b7280;font-size:.8rem;padding:2rem 0 3rem}
|
||||||
|
@media(prefers-color-scheme:dark){body{background:#0b1220;color:#e7ecf3}table{background:#13203a}
|
||||||
|
th,td{border-color:#223153}.card,.links a{background:#13203a;border-color:#223153;color:#e7ecf3}
|
||||||
|
.note{border-color:#223153;color:#9fb0c3}}
|
||||||
|
</style>
|
||||||
|
<script type="application/ld+json">{"@context": "https://schema.org", "@type": "BreadcrumbList", "itemListElement": [{"@type": "ListItem", "position": 1, "name": "Home", "item": "https://perfect-postcode.co.uk/"}, {"@type": "ListItem", "position": 2, "name": "Cheaper twins", "item": "https://perfect-postcode.co.uk/cheaper-twins"}, {"@type": "ListItem", "position": 3, "name": "Woodford Green vs Barkingside", "item": "https://perfect-postcode.co.uk/cheaper-twin/ig8-7-vs-ig6-2"}]}</script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="topbar"><a href="/">Perfect Postcode</a><a href="/?ref=twin">Open the map →</a></div>
|
||||||
|
|
||||||
|
<div class="hero"><div class="wrap">
|
||||||
|
<p class="eyebrow">Cheaper twin · England</p>
|
||||||
|
<h1>Woodford Green vs Barkingside: the same terraced house, about 26% cheaper per m²</h1>
|
||||||
|
<div class="big">26% cheaper / m²</div>
|
||||||
|
<p class="hook">£164,070 less for an equivalent terraced house: same station, similar schools, ~2.98km apart</p>
|
||||||
|
<a class="cta" href="https://perfect-postcode.co.uk/?lat=51.60238&lon=0.06063&zoom=12.5&filter=Est.%20price%20per%20sqm:0:5600&filter=Good%2B%20secondary%20school%20catchments:1:11">See both areas on the live map →</a>
|
||||||
|
</div></div>
|
||||||
|
<div class="wrap">
|
||||||
|
<table><thead><tr><th></th><th>Woodford Green (IG8 7)</th><th>Barkingside (IG6 2)</th></tr></thead>
|
||||||
|
<tbody><tr><td>Estimated £/m²</td><td class='val'>£7,148</td><td class='val'>£5,325</td></tr>
|
||||||
|
<tr><td>On a 90 m² home</td><td class='val'>£643,320</td><td class='val'><span class="cheaper">£479,250</span></td></tr>
|
||||||
|
<tr><td>Dominant property type</td><td class='val'>Terraced</td><td class='val'>Terraced</td></tr>
|
||||||
|
<tr><td>Typical build era</td><td class='val'>~1958</td><td class='val'>~1958</td></tr>
|
||||||
|
<tr><td>Good+ secondary catchments</td><td class='val'>2.8</td><td class='val'>2.8</td></tr>
|
||||||
|
<tr><td>Nearest station</td><td class='val'>~0.58 km</td><td class='val'>~0.58 km</td></tr>
|
||||||
|
<tr><td>Sales in sample (N)</td><td class='val'>2,965</td><td class='val'>4,423</td></tr></tbody></table>
|
||||||
|
<section><h2>The same life, one postcode cheaper</h2><p>Woodford Green (IG8 7) and Barkingside (IG6 2) sit about 2.98 km apart, share the same dominant housing (terraced, typically built around 1958), comparable good-school catchments and the same level of station access. Yet an equivalent home works out roughly <b>26% (about £164,070 on a 90 m² property) cheaper in Barkingside</b>. On the measures that move price they are near-identical; the gap is mostly the premium attached to the better-known name.</p></section>
|
||||||
|
<section><h2>How we worked this out</h2><p>Postcode sectors (e.g. N10 3) compared on estimated £/m² of floor space. A pair is only called a 'twin' when the two sectors share the dominant property type, build era (±30y), good-school catchment provision, station access, deprivation/tenure, education, age and home size, so the price gap reflects a name premium, not a different kind of area. Estimates, not valuations; aggregated to sector, never address-level.</p></section>
|
||||||
|
<section><h2>Compare more areas</h2>
|
||||||
|
<div class="links">
|
||||||
|
<a href="/cheaper-twins"><b>All cheaper twins →</b><br>Browse every England name-premium pair we found.</a>
|
||||||
|
<a href="/postcode-checker"><b>Postcode checker →</b><br>Prices, crime, schools, broadband for any postcode.</a>
|
||||||
|
<a href="/property-price-map"><b>Property price map →</b><br>Rank England by what each £ buys.</a>
|
||||||
|
</div>
|
||||||
|
<div class="links"><a href="/cheaper-twin/l16-7-vs-l14-6"><b>Childwall vs Broadgreen</b><br>£106,740 less for an equivalent semi-detached house: same station, similar schools, ~1.88km apart</a>
|
||||||
|
<a href="/cheaper-twin/m40-5-vs-m9-4"><b>Newton Heath vs Harpurhey</b><br>£106,740 less for an equivalent terraced house: same station, similar schools, ~1.18km apart</a>
|
||||||
|
<a href="/cheaper-twin/rm14-2-vs-rm12-5"><b>Upminster vs Hornchurch</b><br>£115,290 less for an equivalent semi-detached house: same station, similar schools, ~2.99km apart</a></div>
|
||||||
|
</section>
|
||||||
|
<p class="note">Contains HM Land Registry data © Crown copyright and database right. Licensed under the Open Government Licence v3.0. Figures are estimates derived from recorded sales and EPC floor areas, aggregated to postcode sector, not valuations, and not address-level.</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<footer><div class="wrap">Sources: HM Land Registry · EPC (DLUHC) · Ofsted · DfT · ONS · Police.uk. Contains HM Land Registry data © Crown copyright and database right. Licensed under the Open Government Licence v3.0.</div></footer>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
87
frontend/public/cheaper-twin/l16-7-vs-l14-6/index.html
Normal file
87
frontend/public/cheaper-twin/l16-7-vs-l14-6/index.html
Normal file
|
|
@ -0,0 +1,87 @@
|
||||||
|
<!doctype html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
<title>Childwall vs Broadgreen: the same semi-detached house, about 30% cheaper per m² | Perfect Postcode</title>
|
||||||
|
<meta name="description" content="£106,740 less for an equivalent semi-detached house: same station, similar schools, ~1.88km apart" />
|
||||||
|
<link rel="canonical" href="https://perfect-postcode.co.uk/cheaper-twin/l16-7-vs-l14-6" />
|
||||||
|
<style>
|
||||||
|
:root{color-scheme:light dark}
|
||||||
|
*{box-sizing:border-box}
|
||||||
|
body{margin:0;font-family:ui-sans-serif,system-ui,-apple-system,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;
|
||||||
|
color:#0b1220;background:#f7f5f0;line-height:1.6}
|
||||||
|
a{color:#0d9488}
|
||||||
|
.topbar{background:#0b1220;color:#e7ecf3;padding:.7rem 1.25rem;display:flex;justify-content:space-between;align-items:center}
|
||||||
|
.topbar a{color:#2dd4bf;text-decoration:none;font-weight:700}
|
||||||
|
.wrap{max-width:54rem;margin:0 auto;padding:0 1.25rem}
|
||||||
|
.hero{background:linear-gradient(#0b1220,#111a2e);color:#fff;padding:3rem 0 2.5rem}
|
||||||
|
.eyebrow{color:#2dd4bf;font-weight:700;text-transform:uppercase;letter-spacing:.05em;font-size:.8rem;margin:0 0 .5rem}
|
||||||
|
h1{font-size:2rem;line-height:1.15;margin:.2rem 0 .6rem}
|
||||||
|
.hook{color:#cbd5e1;font-size:1.15rem;margin:.5rem 0 1.4rem;max-width:42rem}
|
||||||
|
.big{font-size:3rem;font-weight:800;color:#2dd4bf;margin:.3rem 0}
|
||||||
|
.cta{display:inline-block;margin-top:.4rem;padding:.8rem 1.4rem;border-radius:.6rem;background:#f09a22;color:#0b1220;
|
||||||
|
font-weight:700;text-decoration:none;box-shadow:0 6px 20px rgba(122,57,5,.35)}
|
||||||
|
.cta:hover{background:#df8614}
|
||||||
|
table{width:100%;border-collapse:collapse;margin:1.5rem 0;background:#fff;border-radius:.6rem;overflow:hidden;
|
||||||
|
box-shadow:0 1px 3px rgba(0,0,0,.08)}
|
||||||
|
th,td{padding:.7rem .9rem;text-align:left;border-bottom:1px solid #ece8e0;font-size:.95rem}
|
||||||
|
thead th{background:#0b1220;color:#fff}
|
||||||
|
tbody tr:last-child td{border-bottom:0}
|
||||||
|
.val{font-variant-numeric:tabular-nums;font-weight:600}
|
||||||
|
.cheaper{color:#0d9488}
|
||||||
|
section{margin:2rem 0}
|
||||||
|
h2{font-size:1.3rem;margin:0 0 .6rem}
|
||||||
|
.note{font-size:.82rem;color:#6b7280;border-top:1px solid #e5e1d8;padding-top:1rem;margin-top:2rem}
|
||||||
|
.links{display:grid;gap:.6rem;grid-template-columns:repeat(auto-fit,minmax(15rem,1fr));margin:1rem 0}
|
||||||
|
.links a{display:block;background:#fff;border:1px solid #ece8e0;border-radius:.5rem;padding:.8rem 1rem;text-decoration:none;color:#0b1220}
|
||||||
|
.links a:hover{border-color:#5eead4}
|
||||||
|
.links b{color:#0d9488}
|
||||||
|
.cards{display:grid;gap:1rem;grid-template-columns:repeat(auto-fit,minmax(18rem,1fr))}
|
||||||
|
.card{background:#fff;border:1px solid #ece8e0;border-radius:.6rem;padding:1.1rem;text-decoration:none;color:#0b1220}
|
||||||
|
.card:hover{border-color:#5eead4}
|
||||||
|
.card .n{color:#0d9488;font-weight:800;font-size:1.4rem}
|
||||||
|
footer{color:#6b7280;font-size:.8rem;padding:2rem 0 3rem}
|
||||||
|
@media(prefers-color-scheme:dark){body{background:#0b1220;color:#e7ecf3}table{background:#13203a}
|
||||||
|
th,td{border-color:#223153}.card,.links a{background:#13203a;border-color:#223153;color:#e7ecf3}
|
||||||
|
.note{border-color:#223153;color:#9fb0c3}}
|
||||||
|
</style>
|
||||||
|
<script type="application/ld+json">{"@context": "https://schema.org", "@type": "BreadcrumbList", "itemListElement": [{"@type": "ListItem", "position": 1, "name": "Home", "item": "https://perfect-postcode.co.uk/"}, {"@type": "ListItem", "position": 2, "name": "Cheaper twins", "item": "https://perfect-postcode.co.uk/cheaper-twins"}, {"@type": "ListItem", "position": 3, "name": "Childwall vs Broadgreen", "item": "https://perfect-postcode.co.uk/cheaper-twin/l16-7-vs-l14-6"}]}</script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="topbar"><a href="/">Perfect Postcode</a><a href="/?ref=twin">Open the map →</a></div>
|
||||||
|
|
||||||
|
<div class="hero"><div class="wrap">
|
||||||
|
<p class="eyebrow">Cheaper twin · England</p>
|
||||||
|
<h1>Childwall vs Broadgreen: the same semi-detached house, about 30% cheaper per m²</h1>
|
||||||
|
<div class="big">30% cheaper / m²</div>
|
||||||
|
<p class="hook">£106,740 less for an equivalent semi-detached house: same station, similar schools, ~1.88km apart</p>
|
||||||
|
<a class="cta" href="https://perfect-postcode.co.uk/?lat=53.40344&lon=-2.88529&zoom=12.5&filter=Est.%20price%20per%20sqm:0:3000&filter=Good%2B%20secondary%20school%20catchments:1:11">See both areas on the live map →</a>
|
||||||
|
</div></div>
|
||||||
|
<div class="wrap">
|
||||||
|
<table><thead><tr><th></th><th>Childwall (L16 7)</th><th>Broadgreen (L14 6)</th></tr></thead>
|
||||||
|
<tbody><tr><td>Estimated £/m²</td><td class='val'>£4,026</td><td class='val'>£2,840</td></tr>
|
||||||
|
<tr><td>On a 90 m² home</td><td class='val'>£362,340</td><td class='val'><span class="cheaper">£255,600</span></td></tr>
|
||||||
|
<tr><td>Dominant property type</td><td class='val'>Semi-Detached</td><td class='val'>Semi-Detached</td></tr>
|
||||||
|
<tr><td>Typical build era</td><td class='val'>~1940</td><td class='val'>~1940</td></tr>
|
||||||
|
<tr><td>Good+ secondary catchments</td><td class='val'>5.1</td><td class='val'>5.1</td></tr>
|
||||||
|
<tr><td>Nearest station</td><td class='val'>~1.22 km</td><td class='val'>~1.22 km</td></tr>
|
||||||
|
<tr><td>Sales in sample (N)</td><td class='val'>500</td><td class='val'>809</td></tr></tbody></table>
|
||||||
|
<section><h2>The same life, one postcode cheaper</h2><p>Childwall (L16 7) and Broadgreen (L14 6) sit about 1.88 km apart, share the same dominant housing (semi-detached, typically built around 1940), comparable good-school catchments and the same level of station access. Yet an equivalent home works out roughly <b>30% (about £106,740 on a 90 m² property) cheaper in Broadgreen</b>. On the measures that move price they are near-identical; the gap is mostly the premium attached to the better-known name.</p></section>
|
||||||
|
<section><h2>How we worked this out</h2><p>Postcode sectors (e.g. N10 3) compared on estimated £/m² of floor space. A pair is only called a 'twin' when the two sectors share the dominant property type, build era (±30y), good-school catchment provision, station access, deprivation/tenure, education, age and home size, so the price gap reflects a name premium, not a different kind of area. Estimates, not valuations; aggregated to sector, never address-level.</p></section>
|
||||||
|
<section><h2>Compare more areas</h2>
|
||||||
|
<div class="links">
|
||||||
|
<a href="/cheaper-twins"><b>All cheaper twins →</b><br>Browse every England name-premium pair we found.</a>
|
||||||
|
<a href="/postcode-checker"><b>Postcode checker →</b><br>Prices, crime, schools, broadband for any postcode.</a>
|
||||||
|
<a href="/property-price-map"><b>Property price map →</b><br>Rank England by what each £ buys.</a>
|
||||||
|
</div>
|
||||||
|
<div class="links"><a href="/cheaper-twin/m40-5-vs-m9-4"><b>Newton Heath vs Harpurhey</b><br>£106,740 less for an equivalent terraced house: same station, similar schools, ~1.18km apart</a>
|
||||||
|
<a href="/cheaper-twin/rm14-2-vs-rm12-5"><b>Upminster vs Hornchurch</b><br>£115,290 less for an equivalent semi-detached house: same station, similar schools, ~2.99km apart</a>
|
||||||
|
<a href="/cheaper-twin/se28-8-vs-da18-4"><b>SE28 8 vs DA18 4</b><br>£129,690 less for an equivalent terraced house: same station, similar schools, ~1.72km apart</a></div>
|
||||||
|
</section>
|
||||||
|
<p class="note">Contains HM Land Registry data © Crown copyright and database right. Licensed under the Open Government Licence v3.0. Figures are estimates derived from recorded sales and EPC floor areas, aggregated to postcode sector, not valuations, and not address-level.</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<footer><div class="wrap">Sources: HM Land Registry · EPC (DLUHC) · Ofsted · DfT · ONS · Police.uk. Contains HM Land Registry data © Crown copyright and database right. Licensed under the Open Government Licence v3.0.</div></footer>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
87
frontend/public/cheaper-twin/m40-5-vs-m9-4/index.html
Normal file
87
frontend/public/cheaper-twin/m40-5-vs-m9-4/index.html
Normal file
|
|
@ -0,0 +1,87 @@
|
||||||
|
<!doctype html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
<title>Newton Heath vs Harpurhey: the same terraced house, about 42% cheaper per m² | Perfect Postcode</title>
|
||||||
|
<meta name="description" content="£106,740 less for an equivalent terraced house: same station, similar schools, ~1.18km apart" />
|
||||||
|
<link rel="canonical" href="https://perfect-postcode.co.uk/cheaper-twin/m40-5-vs-m9-4" />
|
||||||
|
<style>
|
||||||
|
:root{color-scheme:light dark}
|
||||||
|
*{box-sizing:border-box}
|
||||||
|
body{margin:0;font-family:ui-sans-serif,system-ui,-apple-system,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;
|
||||||
|
color:#0b1220;background:#f7f5f0;line-height:1.6}
|
||||||
|
a{color:#0d9488}
|
||||||
|
.topbar{background:#0b1220;color:#e7ecf3;padding:.7rem 1.25rem;display:flex;justify-content:space-between;align-items:center}
|
||||||
|
.topbar a{color:#2dd4bf;text-decoration:none;font-weight:700}
|
||||||
|
.wrap{max-width:54rem;margin:0 auto;padding:0 1.25rem}
|
||||||
|
.hero{background:linear-gradient(#0b1220,#111a2e);color:#fff;padding:3rem 0 2.5rem}
|
||||||
|
.eyebrow{color:#2dd4bf;font-weight:700;text-transform:uppercase;letter-spacing:.05em;font-size:.8rem;margin:0 0 .5rem}
|
||||||
|
h1{font-size:2rem;line-height:1.15;margin:.2rem 0 .6rem}
|
||||||
|
.hook{color:#cbd5e1;font-size:1.15rem;margin:.5rem 0 1.4rem;max-width:42rem}
|
||||||
|
.big{font-size:3rem;font-weight:800;color:#2dd4bf;margin:.3rem 0}
|
||||||
|
.cta{display:inline-block;margin-top:.4rem;padding:.8rem 1.4rem;border-radius:.6rem;background:#f09a22;color:#0b1220;
|
||||||
|
font-weight:700;text-decoration:none;box-shadow:0 6px 20px rgba(122,57,5,.35)}
|
||||||
|
.cta:hover{background:#df8614}
|
||||||
|
table{width:100%;border-collapse:collapse;margin:1.5rem 0;background:#fff;border-radius:.6rem;overflow:hidden;
|
||||||
|
box-shadow:0 1px 3px rgba(0,0,0,.08)}
|
||||||
|
th,td{padding:.7rem .9rem;text-align:left;border-bottom:1px solid #ece8e0;font-size:.95rem}
|
||||||
|
thead th{background:#0b1220;color:#fff}
|
||||||
|
tbody tr:last-child td{border-bottom:0}
|
||||||
|
.val{font-variant-numeric:tabular-nums;font-weight:600}
|
||||||
|
.cheaper{color:#0d9488}
|
||||||
|
section{margin:2rem 0}
|
||||||
|
h2{font-size:1.3rem;margin:0 0 .6rem}
|
||||||
|
.note{font-size:.82rem;color:#6b7280;border-top:1px solid #e5e1d8;padding-top:1rem;margin-top:2rem}
|
||||||
|
.links{display:grid;gap:.6rem;grid-template-columns:repeat(auto-fit,minmax(15rem,1fr));margin:1rem 0}
|
||||||
|
.links a{display:block;background:#fff;border:1px solid #ece8e0;border-radius:.5rem;padding:.8rem 1rem;text-decoration:none;color:#0b1220}
|
||||||
|
.links a:hover{border-color:#5eead4}
|
||||||
|
.links b{color:#0d9488}
|
||||||
|
.cards{display:grid;gap:1rem;grid-template-columns:repeat(auto-fit,minmax(18rem,1fr))}
|
||||||
|
.card{background:#fff;border:1px solid #ece8e0;border-radius:.6rem;padding:1.1rem;text-decoration:none;color:#0b1220}
|
||||||
|
.card:hover{border-color:#5eead4}
|
||||||
|
.card .n{color:#0d9488;font-weight:800;font-size:1.4rem}
|
||||||
|
footer{color:#6b7280;font-size:.8rem;padding:2rem 0 3rem}
|
||||||
|
@media(prefers-color-scheme:dark){body{background:#0b1220;color:#e7ecf3}table{background:#13203a}
|
||||||
|
th,td{border-color:#223153}.card,.links a{background:#13203a;border-color:#223153;color:#e7ecf3}
|
||||||
|
.note{border-color:#223153;color:#9fb0c3}}
|
||||||
|
</style>
|
||||||
|
<script type="application/ld+json">{"@context": "https://schema.org", "@type": "BreadcrumbList", "itemListElement": [{"@type": "ListItem", "position": 1, "name": "Home", "item": "https://perfect-postcode.co.uk/"}, {"@type": "ListItem", "position": 2, "name": "Cheaper twins", "item": "https://perfect-postcode.co.uk/cheaper-twins"}, {"@type": "ListItem", "position": 3, "name": "Newton Heath vs Harpurhey", "item": "https://perfect-postcode.co.uk/cheaper-twin/m40-5-vs-m9-4"}]}</script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="topbar"><a href="/">Perfect Postcode</a><a href="/?ref=twin">Open the map →</a></div>
|
||||||
|
|
||||||
|
<div class="hero"><div class="wrap">
|
||||||
|
<p class="eyebrow">Cheaper twin · England</p>
|
||||||
|
<h1>Newton Heath vs Harpurhey: the same terraced house, about 42% cheaper per m²</h1>
|
||||||
|
<div class="big">42% cheaper / m²</div>
|
||||||
|
<p class="hook">£106,740 less for an equivalent terraced house: same station, similar schools, ~1.18km apart</p>
|
||||||
|
<a class="cta" href="https://perfect-postcode.co.uk/?lat=53.51293&lon=-2.19574&zoom=12.5&filter=Est.%20price%20per%20sqm:0:1700&filter=Good%2B%20secondary%20school%20catchments:1:11">See both areas on the live map →</a>
|
||||||
|
</div></div>
|
||||||
|
<div class="wrap">
|
||||||
|
<table><thead><tr><th></th><th>Newton Heath (M40 5)</th><th>Harpurhey (M9 4)</th></tr></thead>
|
||||||
|
<tbody><tr><td>Estimated £/m²</td><td class='val'>£2,812</td><td class='val'>£1,626</td></tr>
|
||||||
|
<tr><td>On a 90 m² home</td><td class='val'>£253,080</td><td class='val'><span class="cheaper">£146,340</span></td></tr>
|
||||||
|
<tr><td>Dominant property type</td><td class='val'>Terraced</td><td class='val'>Terraced</td></tr>
|
||||||
|
<tr><td>Typical build era</td><td class='val'>~1958</td><td class='val'>~1958</td></tr>
|
||||||
|
<tr><td>Good+ secondary catchments</td><td class='val'>2.6</td><td class='val'>2.6</td></tr>
|
||||||
|
<tr><td>Nearest station</td><td class='val'>~0.72 km</td><td class='val'>~0.72 km</td></tr>
|
||||||
|
<tr><td>Sales in sample (N)</td><td class='val'>1,632</td><td class='val'>3,530</td></tr></tbody></table>
|
||||||
|
<section><h2>The same life, one postcode cheaper</h2><p>Newton Heath (M40 5) and Harpurhey (M9 4) sit about 1.18 km apart, share the same dominant housing (terraced, typically built around 1958), comparable good-school catchments and the same level of station access. Yet an equivalent home works out roughly <b>42% (about £106,740 on a 90 m² property) cheaper in Harpurhey</b>. On the measures that move price they are near-identical; the gap is mostly the premium attached to the better-known name.</p></section>
|
||||||
|
<section><h2>How we worked this out</h2><p>Postcode sectors (e.g. N10 3) compared on estimated £/m² of floor space. A pair is only called a 'twin' when the two sectors share the dominant property type, build era (±30y), good-school catchment provision, station access, deprivation/tenure, education, age and home size, so the price gap reflects a name premium, not a different kind of area. Estimates, not valuations; aggregated to sector, never address-level.</p></section>
|
||||||
|
<section><h2>Compare more areas</h2>
|
||||||
|
<div class="links">
|
||||||
|
<a href="/cheaper-twins"><b>All cheaper twins →</b><br>Browse every England name-premium pair we found.</a>
|
||||||
|
<a href="/postcode-checker"><b>Postcode checker →</b><br>Prices, crime, schools, broadband for any postcode.</a>
|
||||||
|
<a href="/property-price-map"><b>Property price map →</b><br>Rank England by what each £ buys.</a>
|
||||||
|
</div>
|
||||||
|
<div class="links"><a href="/cheaper-twin/rm14-2-vs-rm12-5"><b>Upminster vs Hornchurch</b><br>£115,290 less for an equivalent semi-detached house: same station, similar schools, ~2.99km apart</a>
|
||||||
|
<a href="/cheaper-twin/se28-8-vs-da18-4"><b>SE28 8 vs DA18 4</b><br>£129,690 less for an equivalent terraced house: same station, similar schools, ~1.72km apart</a>
|
||||||
|
<a href="/cheaper-twin/sw1x-8-vs-sw7-2"><b>SW1X 8 vs SW7 2</b><br>£1,001,160 less for an equivalent flat: same station, similar schools, ~1.31km apart</a></div>
|
||||||
|
</section>
|
||||||
|
<p class="note">Contains HM Land Registry data © Crown copyright and database right. Licensed under the Open Government Licence v3.0. Figures are estimates derived from recorded sales and EPC floor areas, aggregated to postcode sector, not valuations, and not address-level.</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<footer><div class="wrap">Sources: HM Land Registry · EPC (DLUHC) · Ofsted · DfT · ONS · Police.uk. Contains HM Land Registry data © Crown copyright and database right. Licensed under the Open Government Licence v3.0.</div></footer>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
87
frontend/public/cheaper-twin/rm14-2-vs-rm12-5/index.html
Normal file
87
frontend/public/cheaper-twin/rm14-2-vs-rm12-5/index.html
Normal file
|
|
@ -0,0 +1,87 @@
|
||||||
|
<!doctype html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
<title>Upminster vs Hornchurch: the same semi-detached house, about 20% cheaper per m² | Perfect Postcode</title>
|
||||||
|
<meta name="description" content="£115,290 less for an equivalent semi-detached house: same station, similar schools, ~2.99km apart" />
|
||||||
|
<link rel="canonical" href="https://perfect-postcode.co.uk/cheaper-twin/rm14-2-vs-rm12-5" />
|
||||||
|
<style>
|
||||||
|
:root{color-scheme:light dark}
|
||||||
|
*{box-sizing:border-box}
|
||||||
|
body{margin:0;font-family:ui-sans-serif,system-ui,-apple-system,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;
|
||||||
|
color:#0b1220;background:#f7f5f0;line-height:1.6}
|
||||||
|
a{color:#0d9488}
|
||||||
|
.topbar{background:#0b1220;color:#e7ecf3;padding:.7rem 1.25rem;display:flex;justify-content:space-between;align-items:center}
|
||||||
|
.topbar a{color:#2dd4bf;text-decoration:none;font-weight:700}
|
||||||
|
.wrap{max-width:54rem;margin:0 auto;padding:0 1.25rem}
|
||||||
|
.hero{background:linear-gradient(#0b1220,#111a2e);color:#fff;padding:3rem 0 2.5rem}
|
||||||
|
.eyebrow{color:#2dd4bf;font-weight:700;text-transform:uppercase;letter-spacing:.05em;font-size:.8rem;margin:0 0 .5rem}
|
||||||
|
h1{font-size:2rem;line-height:1.15;margin:.2rem 0 .6rem}
|
||||||
|
.hook{color:#cbd5e1;font-size:1.15rem;margin:.5rem 0 1.4rem;max-width:42rem}
|
||||||
|
.big{font-size:3rem;font-weight:800;color:#2dd4bf;margin:.3rem 0}
|
||||||
|
.cta{display:inline-block;margin-top:.4rem;padding:.8rem 1.4rem;border-radius:.6rem;background:#f09a22;color:#0b1220;
|
||||||
|
font-weight:700;text-decoration:none;box-shadow:0 6px 20px rgba(122,57,5,.35)}
|
||||||
|
.cta:hover{background:#df8614}
|
||||||
|
table{width:100%;border-collapse:collapse;margin:1.5rem 0;background:#fff;border-radius:.6rem;overflow:hidden;
|
||||||
|
box-shadow:0 1px 3px rgba(0,0,0,.08)}
|
||||||
|
th,td{padding:.7rem .9rem;text-align:left;border-bottom:1px solid #ece8e0;font-size:.95rem}
|
||||||
|
thead th{background:#0b1220;color:#fff}
|
||||||
|
tbody tr:last-child td{border-bottom:0}
|
||||||
|
.val{font-variant-numeric:tabular-nums;font-weight:600}
|
||||||
|
.cheaper{color:#0d9488}
|
||||||
|
section{margin:2rem 0}
|
||||||
|
h2{font-size:1.3rem;margin:0 0 .6rem}
|
||||||
|
.note{font-size:.82rem;color:#6b7280;border-top:1px solid #e5e1d8;padding-top:1rem;margin-top:2rem}
|
||||||
|
.links{display:grid;gap:.6rem;grid-template-columns:repeat(auto-fit,minmax(15rem,1fr));margin:1rem 0}
|
||||||
|
.links a{display:block;background:#fff;border:1px solid #ece8e0;border-radius:.5rem;padding:.8rem 1rem;text-decoration:none;color:#0b1220}
|
||||||
|
.links a:hover{border-color:#5eead4}
|
||||||
|
.links b{color:#0d9488}
|
||||||
|
.cards{display:grid;gap:1rem;grid-template-columns:repeat(auto-fit,minmax(18rem,1fr))}
|
||||||
|
.card{background:#fff;border:1px solid #ece8e0;border-radius:.6rem;padding:1.1rem;text-decoration:none;color:#0b1220}
|
||||||
|
.card:hover{border-color:#5eead4}
|
||||||
|
.card .n{color:#0d9488;font-weight:800;font-size:1.4rem}
|
||||||
|
footer{color:#6b7280;font-size:.8rem;padding:2rem 0 3rem}
|
||||||
|
@media(prefers-color-scheme:dark){body{background:#0b1220;color:#e7ecf3}table{background:#13203a}
|
||||||
|
th,td{border-color:#223153}.card,.links a{background:#13203a;border-color:#223153;color:#e7ecf3}
|
||||||
|
.note{border-color:#223153;color:#9fb0c3}}
|
||||||
|
</style>
|
||||||
|
<script type="application/ld+json">{"@context": "https://schema.org", "@type": "BreadcrumbList", "itemListElement": [{"@type": "ListItem", "position": 1, "name": "Home", "item": "https://perfect-postcode.co.uk/"}, {"@type": "ListItem", "position": 2, "name": "Cheaper twins", "item": "https://perfect-postcode.co.uk/cheaper-twins"}, {"@type": "ListItem", "position": 3, "name": "Upminster vs Hornchurch", "item": "https://perfect-postcode.co.uk/cheaper-twin/rm14-2-vs-rm12-5"}]}</script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="topbar"><a href="/">Perfect Postcode</a><a href="/?ref=twin">Open the map →</a></div>
|
||||||
|
|
||||||
|
<div class="hero"><div class="wrap">
|
||||||
|
<p class="eyebrow">Cheaper twin · England</p>
|
||||||
|
<h1>Upminster vs Hornchurch: the same semi-detached house, about 20% cheaper per m²</h1>
|
||||||
|
<div class="big">20% cheaper / m²</div>
|
||||||
|
<p class="hook">£115,290 less for an equivalent semi-detached house: same station, similar schools, ~2.99km apart</p>
|
||||||
|
<a class="cta" href="https://perfect-postcode.co.uk/?lat=51.54892&lon=0.22193&zoom=12.5&filter=Est.%20price%20per%20sqm:0:5300&filter=Good%2B%20secondary%20school%20catchments:1:11">See both areas on the live map →</a>
|
||||||
|
</div></div>
|
||||||
|
<div class="wrap">
|
||||||
|
<table><thead><tr><th></th><th>Upminster (RM14 2)</th><th>Hornchurch (RM12 5)</th></tr></thead>
|
||||||
|
<tbody><tr><td>Estimated £/m²</td><td class='val'>£6,360</td><td class='val'>£5,079</td></tr>
|
||||||
|
<tr><td>On a 90 m² home</td><td class='val'>£572,400</td><td class='val'><span class="cheaper">£457,110</span></td></tr>
|
||||||
|
<tr><td>Dominant property type</td><td class='val'>Semi-Detached</td><td class='val'>Semi-Detached</td></tr>
|
||||||
|
<tr><td>Typical build era</td><td class='val'>~1940</td><td class='val'>~1940</td></tr>
|
||||||
|
<tr><td>Good+ secondary catchments</td><td class='val'>3.7</td><td class='val'>3.7</td></tr>
|
||||||
|
<tr><td>Nearest station</td><td class='val'>~0.77 km</td><td class='val'>~0.77 km</td></tr>
|
||||||
|
<tr><td>Sales in sample (N)</td><td class='val'>3,026</td><td class='val'>3,133</td></tr></tbody></table>
|
||||||
|
<section><h2>The same life, one postcode cheaper</h2><p>Upminster (RM14 2) and Hornchurch (RM12 5) sit about 2.99 km apart, share the same dominant housing (semi-detached, typically built around 1940), comparable good-school catchments and the same level of station access. Yet an equivalent home works out roughly <b>20% (about £115,290 on a 90 m² property) cheaper in Hornchurch</b>. On the measures that move price they are near-identical; the gap is mostly the premium attached to the better-known name.</p></section>
|
||||||
|
<section><h2>How we worked this out</h2><p>Postcode sectors (e.g. N10 3) compared on estimated £/m² of floor space. A pair is only called a 'twin' when the two sectors share the dominant property type, build era (±30y), good-school catchment provision, station access, deprivation/tenure, education, age and home size, so the price gap reflects a name premium, not a different kind of area. Estimates, not valuations; aggregated to sector, never address-level.</p></section>
|
||||||
|
<section><h2>Compare more areas</h2>
|
||||||
|
<div class="links">
|
||||||
|
<a href="/cheaper-twins"><b>All cheaper twins →</b><br>Browse every England name-premium pair we found.</a>
|
||||||
|
<a href="/postcode-checker"><b>Postcode checker →</b><br>Prices, crime, schools, broadband for any postcode.</a>
|
||||||
|
<a href="/property-price-map"><b>Property price map →</b><br>Rank England by what each £ buys.</a>
|
||||||
|
</div>
|
||||||
|
<div class="links"><a href="/cheaper-twin/se28-8-vs-da18-4"><b>SE28 8 vs DA18 4</b><br>£129,690 less for an equivalent terraced house: same station, similar schools, ~1.72km apart</a>
|
||||||
|
<a href="/cheaper-twin/sw1x-8-vs-sw7-2"><b>SW1X 8 vs SW7 2</b><br>£1,001,160 less for an equivalent flat: same station, similar schools, ~1.31km apart</a>
|
||||||
|
<a href="/cheaper-twin/tw12-3-vs-kt8-1"><b>Hampton vs East Molesey</b><br>£120,060 less for an equivalent terraced house: same station, similar schools, ~2.23km apart</a></div>
|
||||||
|
</section>
|
||||||
|
<p class="note">Contains HM Land Registry data © Crown copyright and database right. Licensed under the Open Government Licence v3.0. Figures are estimates derived from recorded sales and EPC floor areas, aggregated to postcode sector, not valuations, and not address-level.</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<footer><div class="wrap">Sources: HM Land Registry · EPC (DLUHC) · Ofsted · DfT · ONS · Police.uk. Contains HM Land Registry data © Crown copyright and database right. Licensed under the Open Government Licence v3.0.</div></footer>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
87
frontend/public/cheaper-twin/se28-8-vs-da18-4/index.html
Normal file
87
frontend/public/cheaper-twin/se28-8-vs-da18-4/index.html
Normal file
|
|
@ -0,0 +1,87 @@
|
||||||
|
<!doctype html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
<title>SE28 8 vs DA18 4: the same terraced house, about 30% cheaper per m² | Perfect Postcode</title>
|
||||||
|
<meta name="description" content="£129,690 less for an equivalent terraced house: same station, similar schools, ~1.72km apart" />
|
||||||
|
<link rel="canonical" href="https://perfect-postcode.co.uk/cheaper-twin/se28-8-vs-da18-4" />
|
||||||
|
<style>
|
||||||
|
:root{color-scheme:light dark}
|
||||||
|
*{box-sizing:border-box}
|
||||||
|
body{margin:0;font-family:ui-sans-serif,system-ui,-apple-system,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;
|
||||||
|
color:#0b1220;background:#f7f5f0;line-height:1.6}
|
||||||
|
a{color:#0d9488}
|
||||||
|
.topbar{background:#0b1220;color:#e7ecf3;padding:.7rem 1.25rem;display:flex;justify-content:space-between;align-items:center}
|
||||||
|
.topbar a{color:#2dd4bf;text-decoration:none;font-weight:700}
|
||||||
|
.wrap{max-width:54rem;margin:0 auto;padding:0 1.25rem}
|
||||||
|
.hero{background:linear-gradient(#0b1220,#111a2e);color:#fff;padding:3rem 0 2.5rem}
|
||||||
|
.eyebrow{color:#2dd4bf;font-weight:700;text-transform:uppercase;letter-spacing:.05em;font-size:.8rem;margin:0 0 .5rem}
|
||||||
|
h1{font-size:2rem;line-height:1.15;margin:.2rem 0 .6rem}
|
||||||
|
.hook{color:#cbd5e1;font-size:1.15rem;margin:.5rem 0 1.4rem;max-width:42rem}
|
||||||
|
.big{font-size:3rem;font-weight:800;color:#2dd4bf;margin:.3rem 0}
|
||||||
|
.cta{display:inline-block;margin-top:.4rem;padding:.8rem 1.4rem;border-radius:.6rem;background:#f09a22;color:#0b1220;
|
||||||
|
font-weight:700;text-decoration:none;box-shadow:0 6px 20px rgba(122,57,5,.35)}
|
||||||
|
.cta:hover{background:#df8614}
|
||||||
|
table{width:100%;border-collapse:collapse;margin:1.5rem 0;background:#fff;border-radius:.6rem;overflow:hidden;
|
||||||
|
box-shadow:0 1px 3px rgba(0,0,0,.08)}
|
||||||
|
th,td{padding:.7rem .9rem;text-align:left;border-bottom:1px solid #ece8e0;font-size:.95rem}
|
||||||
|
thead th{background:#0b1220;color:#fff}
|
||||||
|
tbody tr:last-child td{border-bottom:0}
|
||||||
|
.val{font-variant-numeric:tabular-nums;font-weight:600}
|
||||||
|
.cheaper{color:#0d9488}
|
||||||
|
section{margin:2rem 0}
|
||||||
|
h2{font-size:1.3rem;margin:0 0 .6rem}
|
||||||
|
.note{font-size:.82rem;color:#6b7280;border-top:1px solid #e5e1d8;padding-top:1rem;margin-top:2rem}
|
||||||
|
.links{display:grid;gap:.6rem;grid-template-columns:repeat(auto-fit,minmax(15rem,1fr));margin:1rem 0}
|
||||||
|
.links a{display:block;background:#fff;border:1px solid #ece8e0;border-radius:.5rem;padding:.8rem 1rem;text-decoration:none;color:#0b1220}
|
||||||
|
.links a:hover{border-color:#5eead4}
|
||||||
|
.links b{color:#0d9488}
|
||||||
|
.cards{display:grid;gap:1rem;grid-template-columns:repeat(auto-fit,minmax(18rem,1fr))}
|
||||||
|
.card{background:#fff;border:1px solid #ece8e0;border-radius:.6rem;padding:1.1rem;text-decoration:none;color:#0b1220}
|
||||||
|
.card:hover{border-color:#5eead4}
|
||||||
|
.card .n{color:#0d9488;font-weight:800;font-size:1.4rem}
|
||||||
|
footer{color:#6b7280;font-size:.8rem;padding:2rem 0 3rem}
|
||||||
|
@media(prefers-color-scheme:dark){body{background:#0b1220;color:#e7ecf3}table{background:#13203a}
|
||||||
|
th,td{border-color:#223153}.card,.links a{background:#13203a;border-color:#223153;color:#e7ecf3}
|
||||||
|
.note{border-color:#223153;color:#9fb0c3}}
|
||||||
|
</style>
|
||||||
|
<script type="application/ld+json">{"@context": "https://schema.org", "@type": "BreadcrumbList", "itemListElement": [{"@type": "ListItem", "position": 1, "name": "Home", "item": "https://perfect-postcode.co.uk/"}, {"@type": "ListItem", "position": 2, "name": "Cheaper twins", "item": "https://perfect-postcode.co.uk/cheaper-twins"}, {"@type": "ListItem", "position": 3, "name": "SE28 8 vs DA18 4", "item": "https://perfect-postcode.co.uk/cheaper-twin/se28-8-vs-da18-4"}]}</script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="topbar"><a href="/">Perfect Postcode</a><a href="/?ref=twin">Open the map →</a></div>
|
||||||
|
|
||||||
|
<div class="hero"><div class="wrap">
|
||||||
|
<p class="eyebrow">Cheaper twin · England</p>
|
||||||
|
<h1>SE28 8 vs DA18 4: the same terraced house, about 30% cheaper per m²</h1>
|
||||||
|
<div class="big">30% cheaper / m²</div>
|
||||||
|
<p class="hook">£129,690 less for an equivalent terraced house: same station, similar schools, ~1.72km apart</p>
|
||||||
|
<a class="cta" href="https://perfect-postcode.co.uk/?lat=51.50039&lon=0.12568&zoom=12.5&filter=Est.%20price%20per%20sqm:0:3600&filter=Good%2B%20secondary%20school%20catchments:1:11">See both areas on the live map →</a>
|
||||||
|
</div></div>
|
||||||
|
<div class="wrap">
|
||||||
|
<table><thead><tr><th></th><th>SE28 8</th><th>DA18 4</th></tr></thead>
|
||||||
|
<tbody><tr><td>Estimated £/m²</td><td class='val'>£4,850</td><td class='val'>£3,409</td></tr>
|
||||||
|
<tr><td>On a 90 m² home</td><td class='val'>£436,500</td><td class='val'><span class="cheaper">£306,810</span></td></tr>
|
||||||
|
<tr><td>Dominant property type</td><td class='val'>Terraced</td><td class='val'>Terraced</td></tr>
|
||||||
|
<tr><td>Typical build era</td><td class='val'>~1993</td><td class='val'>~1993</td></tr>
|
||||||
|
<tr><td>Good+ secondary catchments</td><td class='val'>2.8</td><td class='val'>2.8</td></tr>
|
||||||
|
<tr><td>Nearest station</td><td class='val'>~1.39 km</td><td class='val'>~1.39 km</td></tr>
|
||||||
|
<tr><td>Sales in sample (N)</td><td class='val'>5,033</td><td class='val'>1,063</td></tr></tbody></table>
|
||||||
|
<section><h2>The same life, one postcode cheaper</h2><p>SE28 8 and DA18 4 sit about 1.72 km apart, share the same dominant housing (terraced, typically built around 1993), comparable good-school catchments and the same level of station access. Yet an equivalent home works out roughly <b>30% (about £129,690 on a 90 m² property) cheaper in DA18 4</b>. On the measures that move price they are near-identical; the gap is mostly the premium attached to the better-known name.</p></section>
|
||||||
|
<section><h2>How we worked this out</h2><p>Postcode sectors (e.g. N10 3) compared on estimated £/m² of floor space. A pair is only called a 'twin' when the two sectors share the dominant property type, build era (±30y), good-school catchment provision, station access, deprivation/tenure, education, age and home size, so the price gap reflects a name premium, not a different kind of area. Estimates, not valuations; aggregated to sector, never address-level.</p></section>
|
||||||
|
<section><h2>Compare more areas</h2>
|
||||||
|
<div class="links">
|
||||||
|
<a href="/cheaper-twins"><b>All cheaper twins →</b><br>Browse every England name-premium pair we found.</a>
|
||||||
|
<a href="/postcode-checker"><b>Postcode checker →</b><br>Prices, crime, schools, broadband for any postcode.</a>
|
||||||
|
<a href="/property-price-map"><b>Property price map →</b><br>Rank England by what each £ buys.</a>
|
||||||
|
</div>
|
||||||
|
<div class="links"><a href="/cheaper-twin/sw1x-8-vs-sw7-2"><b>SW1X 8 vs SW7 2</b><br>£1,001,160 less for an equivalent flat: same station, similar schools, ~1.31km apart</a>
|
||||||
|
<a href="/cheaper-twin/tw12-3-vs-kt8-1"><b>Hampton vs East Molesey</b><br>£120,060 less for an equivalent terraced house: same station, similar schools, ~2.23km apart</a>
|
||||||
|
<a href="/cheaper-twin/tw2-7-vs-tw3-2"><b>Twickenham vs Hounslow</b><br>£121,590 less for an equivalent semi-detached house: same station, similar schools, ~1.0km apart</a></div>
|
||||||
|
</section>
|
||||||
|
<p class="note">Contains HM Land Registry data © Crown copyright and database right. Licensed under the Open Government Licence v3.0. Figures are estimates derived from recorded sales and EPC floor areas, aggregated to postcode sector, not valuations, and not address-level.</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<footer><div class="wrap">Sources: HM Land Registry · EPC (DLUHC) · Ofsted · DfT · ONS · Police.uk. Contains HM Land Registry data © Crown copyright and database right. Licensed under the Open Government Licence v3.0.</div></footer>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
87
frontend/public/cheaper-twin/sw1x-8-vs-sw7-2/index.html
Normal file
87
frontend/public/cheaper-twin/sw1x-8-vs-sw7-2/index.html
Normal file
|
|
@ -0,0 +1,87 @@
|
||||||
|
<!doctype html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
<title>SW1X 8 vs SW7 2: the same flat, about 42% cheaper per m² | Perfect Postcode</title>
|
||||||
|
<meta name="description" content="£1,001,160 less for an equivalent flat: same station, similar schools, ~1.31km apart" />
|
||||||
|
<link rel="canonical" href="https://perfect-postcode.co.uk/cheaper-twin/sw1x-8-vs-sw7-2" />
|
||||||
|
<style>
|
||||||
|
:root{color-scheme:light dark}
|
||||||
|
*{box-sizing:border-box}
|
||||||
|
body{margin:0;font-family:ui-sans-serif,system-ui,-apple-system,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;
|
||||||
|
color:#0b1220;background:#f7f5f0;line-height:1.6}
|
||||||
|
a{color:#0d9488}
|
||||||
|
.topbar{background:#0b1220;color:#e7ecf3;padding:.7rem 1.25rem;display:flex;justify-content:space-between;align-items:center}
|
||||||
|
.topbar a{color:#2dd4bf;text-decoration:none;font-weight:700}
|
||||||
|
.wrap{max-width:54rem;margin:0 auto;padding:0 1.25rem}
|
||||||
|
.hero{background:linear-gradient(#0b1220,#111a2e);color:#fff;padding:3rem 0 2.5rem}
|
||||||
|
.eyebrow{color:#2dd4bf;font-weight:700;text-transform:uppercase;letter-spacing:.05em;font-size:.8rem;margin:0 0 .5rem}
|
||||||
|
h1{font-size:2rem;line-height:1.15;margin:.2rem 0 .6rem}
|
||||||
|
.hook{color:#cbd5e1;font-size:1.15rem;margin:.5rem 0 1.4rem;max-width:42rem}
|
||||||
|
.big{font-size:3rem;font-weight:800;color:#2dd4bf;margin:.3rem 0}
|
||||||
|
.cta{display:inline-block;margin-top:.4rem;padding:.8rem 1.4rem;border-radius:.6rem;background:#f09a22;color:#0b1220;
|
||||||
|
font-weight:700;text-decoration:none;box-shadow:0 6px 20px rgba(122,57,5,.35)}
|
||||||
|
.cta:hover{background:#df8614}
|
||||||
|
table{width:100%;border-collapse:collapse;margin:1.5rem 0;background:#fff;border-radius:.6rem;overflow:hidden;
|
||||||
|
box-shadow:0 1px 3px rgba(0,0,0,.08)}
|
||||||
|
th,td{padding:.7rem .9rem;text-align:left;border-bottom:1px solid #ece8e0;font-size:.95rem}
|
||||||
|
thead th{background:#0b1220;color:#fff}
|
||||||
|
tbody tr:last-child td{border-bottom:0}
|
||||||
|
.val{font-variant-numeric:tabular-nums;font-weight:600}
|
||||||
|
.cheaper{color:#0d9488}
|
||||||
|
section{margin:2rem 0}
|
||||||
|
h2{font-size:1.3rem;margin:0 0 .6rem}
|
||||||
|
.note{font-size:.82rem;color:#6b7280;border-top:1px solid #e5e1d8;padding-top:1rem;margin-top:2rem}
|
||||||
|
.links{display:grid;gap:.6rem;grid-template-columns:repeat(auto-fit,minmax(15rem,1fr));margin:1rem 0}
|
||||||
|
.links a{display:block;background:#fff;border:1px solid #ece8e0;border-radius:.5rem;padding:.8rem 1rem;text-decoration:none;color:#0b1220}
|
||||||
|
.links a:hover{border-color:#5eead4}
|
||||||
|
.links b{color:#0d9488}
|
||||||
|
.cards{display:grid;gap:1rem;grid-template-columns:repeat(auto-fit,minmax(18rem,1fr))}
|
||||||
|
.card{background:#fff;border:1px solid #ece8e0;border-radius:.6rem;padding:1.1rem;text-decoration:none;color:#0b1220}
|
||||||
|
.card:hover{border-color:#5eead4}
|
||||||
|
.card .n{color:#0d9488;font-weight:800;font-size:1.4rem}
|
||||||
|
footer{color:#6b7280;font-size:.8rem;padding:2rem 0 3rem}
|
||||||
|
@media(prefers-color-scheme:dark){body{background:#0b1220;color:#e7ecf3}table{background:#13203a}
|
||||||
|
th,td{border-color:#223153}.card,.links a{background:#13203a;border-color:#223153;color:#e7ecf3}
|
||||||
|
.note{border-color:#223153;color:#9fb0c3}}
|
||||||
|
</style>
|
||||||
|
<script type="application/ld+json">{"@context": "https://schema.org", "@type": "BreadcrumbList", "itemListElement": [{"@type": "ListItem", "position": 1, "name": "Home", "item": "https://perfect-postcode.co.uk/"}, {"@type": "ListItem", "position": 2, "name": "Cheaper twins", "item": "https://perfect-postcode.co.uk/cheaper-twins"}, {"@type": "ListItem", "position": 3, "name": "SW1X 8 vs SW7 2", "item": "https://perfect-postcode.co.uk/cheaper-twin/sw1x-8-vs-sw7-2"}]}</script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="topbar"><a href="/">Perfect Postcode</a><a href="/?ref=twin">Open the map →</a></div>
|
||||||
|
|
||||||
|
<div class="hero"><div class="wrap">
|
||||||
|
<p class="eyebrow">Cheaper twin · England</p>
|
||||||
|
<h1>SW1X 8 vs SW7 2: the same flat, about 42% cheaper per m²</h1>
|
||||||
|
<div class="big">42% cheaper / m²</div>
|
||||||
|
<p class="hook">£1,001,160 less for an equivalent flat: same station, similar schools, ~1.31km apart</p>
|
||||||
|
<a class="cta" href="https://perfect-postcode.co.uk/?lat=51.49758&lon=-0.16439&zoom=12.5&filter=Est.%20price%20per%20sqm:0:16400&filter=Good%2B%20secondary%20school%20catchments:1:11">See both areas on the live map →</a>
|
||||||
|
</div></div>
|
||||||
|
<div class="wrap">
|
||||||
|
<table><thead><tr><th></th><th>SW1X 8</th><th>SW7 2</th></tr></thead>
|
||||||
|
<tbody><tr><td>Estimated £/m²</td><td class='val'>£26,735</td><td class='val'>£15,611</td></tr>
|
||||||
|
<tr><td>On a 90 m² home</td><td class='val'>£2,406,150</td><td class='val'><span class="cheaper">£1,404,990</span></td></tr>
|
||||||
|
<tr><td>Dominant property type</td><td class='val'>Flats/Maisonettes</td><td class='val'>Flats/Maisonettes</td></tr>
|
||||||
|
<tr><td>Typical build era</td><td class='val'>~1890</td><td class='val'>~1890</td></tr>
|
||||||
|
<tr><td>Good+ secondary catchments</td><td class='val'>3.7</td><td class='val'>3.7</td></tr>
|
||||||
|
<tr><td>Nearest station</td><td class='val'>~0.43 km</td><td class='val'>~0.43 km</td></tr>
|
||||||
|
<tr><td>Sales in sample (N)</td><td class='val'>1,410</td><td class='val'>1,126</td></tr></tbody></table>
|
||||||
|
<section><h2>The same life, one postcode cheaper</h2><p>SW1X 8 and SW7 2 sit about 1.31 km apart, share the same dominant housing (flats/maisonettes, typically built around 1890), comparable good-school catchments and the same level of station access. Yet an equivalent home works out roughly <b>42% (about £1,001,160 on a 90 m² property) cheaper in SW7 2</b>. On the measures that move price they are near-identical; the gap is mostly the premium attached to the better-known name.</p></section>
|
||||||
|
<section><h2>How we worked this out</h2><p>Postcode sectors (e.g. N10 3) compared on estimated £/m² of floor space. A pair is only called a 'twin' when the two sectors share the dominant property type, build era (±30y), good-school catchment provision, station access, deprivation/tenure, education, age and home size, so the price gap reflects a name premium, not a different kind of area. Estimates, not valuations; aggregated to sector, never address-level.</p></section>
|
||||||
|
<section><h2>Compare more areas</h2>
|
||||||
|
<div class="links">
|
||||||
|
<a href="/cheaper-twins"><b>All cheaper twins →</b><br>Browse every England name-premium pair we found.</a>
|
||||||
|
<a href="/postcode-checker"><b>Postcode checker →</b><br>Prices, crime, schools, broadband for any postcode.</a>
|
||||||
|
<a href="/property-price-map"><b>Property price map →</b><br>Rank England by what each £ buys.</a>
|
||||||
|
</div>
|
||||||
|
<div class="links"><a href="/cheaper-twin/tw12-3-vs-kt8-1"><b>Hampton vs East Molesey</b><br>£120,060 less for an equivalent terraced house: same station, similar schools, ~2.23km apart</a>
|
||||||
|
<a href="/cheaper-twin/tw2-7-vs-tw3-2"><b>Twickenham vs Hounslow</b><br>£121,590 less for an equivalent semi-detached house: same station, similar schools, ~1.0km apart</a>
|
||||||
|
<a href="/cheaper-twin/w1j-7-vs-sw7-3"><b>W1J 7 vs SW7 3</b><br>£1,223,460 less for an equivalent flat: same station, similar schools, ~2.6km apart</a></div>
|
||||||
|
</section>
|
||||||
|
<p class="note">Contains HM Land Registry data © Crown copyright and database right. Licensed under the Open Government Licence v3.0. Figures are estimates derived from recorded sales and EPC floor areas, aggregated to postcode sector, not valuations, and not address-level.</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<footer><div class="wrap">Sources: HM Land Registry · EPC (DLUHC) · Ofsted · DfT · ONS · Police.uk. Contains HM Land Registry data © Crown copyright and database right. Licensed under the Open Government Licence v3.0.</div></footer>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
87
frontend/public/cheaper-twin/tw12-3-vs-kt8-1/index.html
Normal file
87
frontend/public/cheaper-twin/tw12-3-vs-kt8-1/index.html
Normal file
|
|
@ -0,0 +1,87 @@
|
||||||
|
<!doctype html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
<title>Hampton vs East Molesey: the same terraced house, about 19% cheaper per m² | Perfect Postcode</title>
|
||||||
|
<meta name="description" content="£120,060 less for an equivalent terraced house: same station, similar schools, ~2.23km apart" />
|
||||||
|
<link rel="canonical" href="https://perfect-postcode.co.uk/cheaper-twin/tw12-3-vs-kt8-1" />
|
||||||
|
<style>
|
||||||
|
:root{color-scheme:light dark}
|
||||||
|
*{box-sizing:border-box}
|
||||||
|
body{margin:0;font-family:ui-sans-serif,system-ui,-apple-system,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;
|
||||||
|
color:#0b1220;background:#f7f5f0;line-height:1.6}
|
||||||
|
a{color:#0d9488}
|
||||||
|
.topbar{background:#0b1220;color:#e7ecf3;padding:.7rem 1.25rem;display:flex;justify-content:space-between;align-items:center}
|
||||||
|
.topbar a{color:#2dd4bf;text-decoration:none;font-weight:700}
|
||||||
|
.wrap{max-width:54rem;margin:0 auto;padding:0 1.25rem}
|
||||||
|
.hero{background:linear-gradient(#0b1220,#111a2e);color:#fff;padding:3rem 0 2.5rem}
|
||||||
|
.eyebrow{color:#2dd4bf;font-weight:700;text-transform:uppercase;letter-spacing:.05em;font-size:.8rem;margin:0 0 .5rem}
|
||||||
|
h1{font-size:2rem;line-height:1.15;margin:.2rem 0 .6rem}
|
||||||
|
.hook{color:#cbd5e1;font-size:1.15rem;margin:.5rem 0 1.4rem;max-width:42rem}
|
||||||
|
.big{font-size:3rem;font-weight:800;color:#2dd4bf;margin:.3rem 0}
|
||||||
|
.cta{display:inline-block;margin-top:.4rem;padding:.8rem 1.4rem;border-radius:.6rem;background:#f09a22;color:#0b1220;
|
||||||
|
font-weight:700;text-decoration:none;box-shadow:0 6px 20px rgba(122,57,5,.35)}
|
||||||
|
.cta:hover{background:#df8614}
|
||||||
|
table{width:100%;border-collapse:collapse;margin:1.5rem 0;background:#fff;border-radius:.6rem;overflow:hidden;
|
||||||
|
box-shadow:0 1px 3px rgba(0,0,0,.08)}
|
||||||
|
th,td{padding:.7rem .9rem;text-align:left;border-bottom:1px solid #ece8e0;font-size:.95rem}
|
||||||
|
thead th{background:#0b1220;color:#fff}
|
||||||
|
tbody tr:last-child td{border-bottom:0}
|
||||||
|
.val{font-variant-numeric:tabular-nums;font-weight:600}
|
||||||
|
.cheaper{color:#0d9488}
|
||||||
|
section{margin:2rem 0}
|
||||||
|
h2{font-size:1.3rem;margin:0 0 .6rem}
|
||||||
|
.note{font-size:.82rem;color:#6b7280;border-top:1px solid #e5e1d8;padding-top:1rem;margin-top:2rem}
|
||||||
|
.links{display:grid;gap:.6rem;grid-template-columns:repeat(auto-fit,minmax(15rem,1fr));margin:1rem 0}
|
||||||
|
.links a{display:block;background:#fff;border:1px solid #ece8e0;border-radius:.5rem;padding:.8rem 1rem;text-decoration:none;color:#0b1220}
|
||||||
|
.links a:hover{border-color:#5eead4}
|
||||||
|
.links b{color:#0d9488}
|
||||||
|
.cards{display:grid;gap:1rem;grid-template-columns:repeat(auto-fit,minmax(18rem,1fr))}
|
||||||
|
.card{background:#fff;border:1px solid #ece8e0;border-radius:.6rem;padding:1.1rem;text-decoration:none;color:#0b1220}
|
||||||
|
.card:hover{border-color:#5eead4}
|
||||||
|
.card .n{color:#0d9488;font-weight:800;font-size:1.4rem}
|
||||||
|
footer{color:#6b7280;font-size:.8rem;padding:2rem 0 3rem}
|
||||||
|
@media(prefers-color-scheme:dark){body{background:#0b1220;color:#e7ecf3}table{background:#13203a}
|
||||||
|
th,td{border-color:#223153}.card,.links a{background:#13203a;border-color:#223153;color:#e7ecf3}
|
||||||
|
.note{border-color:#223153;color:#9fb0c3}}
|
||||||
|
</style>
|
||||||
|
<script type="application/ld+json">{"@context": "https://schema.org", "@type": "BreadcrumbList", "itemListElement": [{"@type": "ListItem", "position": 1, "name": "Home", "item": "https://perfect-postcode.co.uk/"}, {"@type": "ListItem", "position": 2, "name": "Cheaper twins", "item": "https://perfect-postcode.co.uk/cheaper-twins"}, {"@type": "ListItem", "position": 3, "name": "Hampton vs East Molesey", "item": "https://perfect-postcode.co.uk/cheaper-twin/tw12-3-vs-kt8-1"}]}</script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="topbar"><a href="/">Perfect Postcode</a><a href="/?ref=twin">Open the map →</a></div>
|
||||||
|
|
||||||
|
<div class="hero"><div class="wrap">
|
||||||
|
<p class="eyebrow">Cheaper twin · England</p>
|
||||||
|
<h1>Hampton vs East Molesey: the same terraced house, about 19% cheaper per m²</h1>
|
||||||
|
<div class="big">19% cheaper / m²</div>
|
||||||
|
<p class="hook">£120,060 less for an equivalent terraced house: same station, similar schools, ~2.23km apart</p>
|
||||||
|
<a class="cta" href="https://perfect-postcode.co.uk/?lat=51.41616&lon=-0.37365&zoom=12.5&filter=Est.%20price%20per%20sqm:0:6000&filter=Good%2B%20secondary%20school%20catchments:1:11">See both areas on the live map →</a>
|
||||||
|
</div></div>
|
||||||
|
<div class="wrap">
|
||||||
|
<table><thead><tr><th></th><th>Hampton (TW12 3)</th><th>East Molesey (KT8 1)</th></tr></thead>
|
||||||
|
<tbody><tr><td>Estimated £/m²</td><td class='val'>£7,042</td><td class='val'>£5,708</td></tr>
|
||||||
|
<tr><td>On a 90 m² home</td><td class='val'>£633,780</td><td class='val'><span class="cheaper">£513,720</span></td></tr>
|
||||||
|
<tr><td>Dominant property type</td><td class='val'>Terraced</td><td class='val'>Terraced</td></tr>
|
||||||
|
<tr><td>Typical build era</td><td class='val'>~1979</td><td class='val'>~1979</td></tr>
|
||||||
|
<tr><td>Good+ secondary catchments</td><td class='val'>3.2</td><td class='val'>3.2</td></tr>
|
||||||
|
<tr><td>Nearest station</td><td class='val'>~1.27 km</td><td class='val'>~1.27 km</td></tr>
|
||||||
|
<tr><td>Sales in sample (N)</td><td class='val'>2,527</td><td class='val'>1,567</td></tr></tbody></table>
|
||||||
|
<section><h2>The same life, one postcode cheaper</h2><p>Hampton (TW12 3) and East Molesey (KT8 1) sit about 2.23 km apart, share the same dominant housing (terraced, typically built around 1979), comparable good-school catchments and the same level of station access. Yet an equivalent home works out roughly <b>19% (about £120,060 on a 90 m² property) cheaper in East Molesey</b>. On the measures that move price they are near-identical; the gap is mostly the premium attached to the better-known name.</p></section>
|
||||||
|
<section><h2>How we worked this out</h2><p>Postcode sectors (e.g. N10 3) compared on estimated £/m² of floor space. A pair is only called a 'twin' when the two sectors share the dominant property type, build era (±30y), good-school catchment provision, station access, deprivation/tenure, education, age and home size, so the price gap reflects a name premium, not a different kind of area. Estimates, not valuations; aggregated to sector, never address-level.</p></section>
|
||||||
|
<section><h2>Compare more areas</h2>
|
||||||
|
<div class="links">
|
||||||
|
<a href="/cheaper-twins"><b>All cheaper twins →</b><br>Browse every England name-premium pair we found.</a>
|
||||||
|
<a href="/postcode-checker"><b>Postcode checker →</b><br>Prices, crime, schools, broadband for any postcode.</a>
|
||||||
|
<a href="/property-price-map"><b>Property price map →</b><br>Rank England by what each £ buys.</a>
|
||||||
|
</div>
|
||||||
|
<div class="links"><a href="/cheaper-twin/tw2-7-vs-tw3-2"><b>Twickenham vs Hounslow</b><br>£121,590 less for an equivalent semi-detached house: same station, similar schools, ~1.0km apart</a>
|
||||||
|
<a href="/cheaper-twin/w1j-7-vs-sw7-3"><b>W1J 7 vs SW7 3</b><br>£1,223,460 less for an equivalent flat: same station, similar schools, ~2.6km apart</a>
|
||||||
|
<a href="/cheaper-twin/w1j-8-vs-sw1a-2"><b>W1J 8 vs SW1A 2</b><br>£916,380 less for an equivalent flat: same station, similar schools, ~1.31km apart</a></div>
|
||||||
|
</section>
|
||||||
|
<p class="note">Contains HM Land Registry data © Crown copyright and database right. Licensed under the Open Government Licence v3.0. Figures are estimates derived from recorded sales and EPC floor areas, aggregated to postcode sector, not valuations, and not address-level.</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<footer><div class="wrap">Sources: HM Land Registry · EPC (DLUHC) · Ofsted · DfT · ONS · Police.uk. Contains HM Land Registry data © Crown copyright and database right. Licensed under the Open Government Licence v3.0.</div></footer>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
87
frontend/public/cheaper-twin/tw2-7-vs-tw3-2/index.html
Normal file
87
frontend/public/cheaper-twin/tw2-7-vs-tw3-2/index.html
Normal file
|
|
@ -0,0 +1,87 @@
|
||||||
|
<!doctype html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
<title>Twickenham vs Hounslow: the same semi-detached house, about 19% cheaper per m² | Perfect Postcode</title>
|
||||||
|
<meta name="description" content="£121,590 less for an equivalent semi-detached house: same station, similar schools, ~1.0km apart" />
|
||||||
|
<link rel="canonical" href="https://perfect-postcode.co.uk/cheaper-twin/tw2-7-vs-tw3-2" />
|
||||||
|
<style>
|
||||||
|
:root{color-scheme:light dark}
|
||||||
|
*{box-sizing:border-box}
|
||||||
|
body{margin:0;font-family:ui-sans-serif,system-ui,-apple-system,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;
|
||||||
|
color:#0b1220;background:#f7f5f0;line-height:1.6}
|
||||||
|
a{color:#0d9488}
|
||||||
|
.topbar{background:#0b1220;color:#e7ecf3;padding:.7rem 1.25rem;display:flex;justify-content:space-between;align-items:center}
|
||||||
|
.topbar a{color:#2dd4bf;text-decoration:none;font-weight:700}
|
||||||
|
.wrap{max-width:54rem;margin:0 auto;padding:0 1.25rem}
|
||||||
|
.hero{background:linear-gradient(#0b1220,#111a2e);color:#fff;padding:3rem 0 2.5rem}
|
||||||
|
.eyebrow{color:#2dd4bf;font-weight:700;text-transform:uppercase;letter-spacing:.05em;font-size:.8rem;margin:0 0 .5rem}
|
||||||
|
h1{font-size:2rem;line-height:1.15;margin:.2rem 0 .6rem}
|
||||||
|
.hook{color:#cbd5e1;font-size:1.15rem;margin:.5rem 0 1.4rem;max-width:42rem}
|
||||||
|
.big{font-size:3rem;font-weight:800;color:#2dd4bf;margin:.3rem 0}
|
||||||
|
.cta{display:inline-block;margin-top:.4rem;padding:.8rem 1.4rem;border-radius:.6rem;background:#f09a22;color:#0b1220;
|
||||||
|
font-weight:700;text-decoration:none;box-shadow:0 6px 20px rgba(122,57,5,.35)}
|
||||||
|
.cta:hover{background:#df8614}
|
||||||
|
table{width:100%;border-collapse:collapse;margin:1.5rem 0;background:#fff;border-radius:.6rem;overflow:hidden;
|
||||||
|
box-shadow:0 1px 3px rgba(0,0,0,.08)}
|
||||||
|
th,td{padding:.7rem .9rem;text-align:left;border-bottom:1px solid #ece8e0;font-size:.95rem}
|
||||||
|
thead th{background:#0b1220;color:#fff}
|
||||||
|
tbody tr:last-child td{border-bottom:0}
|
||||||
|
.val{font-variant-numeric:tabular-nums;font-weight:600}
|
||||||
|
.cheaper{color:#0d9488}
|
||||||
|
section{margin:2rem 0}
|
||||||
|
h2{font-size:1.3rem;margin:0 0 .6rem}
|
||||||
|
.note{font-size:.82rem;color:#6b7280;border-top:1px solid #e5e1d8;padding-top:1rem;margin-top:2rem}
|
||||||
|
.links{display:grid;gap:.6rem;grid-template-columns:repeat(auto-fit,minmax(15rem,1fr));margin:1rem 0}
|
||||||
|
.links a{display:block;background:#fff;border:1px solid #ece8e0;border-radius:.5rem;padding:.8rem 1rem;text-decoration:none;color:#0b1220}
|
||||||
|
.links a:hover{border-color:#5eead4}
|
||||||
|
.links b{color:#0d9488}
|
||||||
|
.cards{display:grid;gap:1rem;grid-template-columns:repeat(auto-fit,minmax(18rem,1fr))}
|
||||||
|
.card{background:#fff;border:1px solid #ece8e0;border-radius:.6rem;padding:1.1rem;text-decoration:none;color:#0b1220}
|
||||||
|
.card:hover{border-color:#5eead4}
|
||||||
|
.card .n{color:#0d9488;font-weight:800;font-size:1.4rem}
|
||||||
|
footer{color:#6b7280;font-size:.8rem;padding:2rem 0 3rem}
|
||||||
|
@media(prefers-color-scheme:dark){body{background:#0b1220;color:#e7ecf3}table{background:#13203a}
|
||||||
|
th,td{border-color:#223153}.card,.links a{background:#13203a;border-color:#223153;color:#e7ecf3}
|
||||||
|
.note{border-color:#223153;color:#9fb0c3}}
|
||||||
|
</style>
|
||||||
|
<script type="application/ld+json">{"@context": "https://schema.org", "@type": "BreadcrumbList", "itemListElement": [{"@type": "ListItem", "position": 1, "name": "Home", "item": "https://perfect-postcode.co.uk/"}, {"@type": "ListItem", "position": 2, "name": "Cheaper twins", "item": "https://perfect-postcode.co.uk/cheaper-twins"}, {"@type": "ListItem", "position": 3, "name": "Twickenham vs Hounslow", "item": "https://perfect-postcode.co.uk/cheaper-twin/tw2-7-vs-tw3-2"}]}</script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="topbar"><a href="/">Perfect Postcode</a><a href="/?ref=twin">Open the map →</a></div>
|
||||||
|
|
||||||
|
<div class="hero"><div class="wrap">
|
||||||
|
<p class="eyebrow">Cheaper twin · England</p>
|
||||||
|
<h1>Twickenham vs Hounslow: the same semi-detached house, about 19% cheaper per m²</h1>
|
||||||
|
<div class="big">19% cheaper / m²</div>
|
||||||
|
<p class="hook">£121,590 less for an equivalent semi-detached house: same station, similar schools, ~1.0km apart</p>
|
||||||
|
<a class="cta" href="https://perfect-postcode.co.uk/?lat=51.45678&lon=-0.35702&zoom=12.5&filter=Est.%20price%20per%20sqm:0:5900&filter=Good%2B%20secondary%20school%20catchments:1:11">See both areas on the live map →</a>
|
||||||
|
</div></div>
|
||||||
|
<div class="wrap">
|
||||||
|
<table><thead><tr><th></th><th>Twickenham (TW2 7)</th><th>Hounslow (TW3 2)</th></tr></thead>
|
||||||
|
<tbody><tr><td>Estimated £/m²</td><td class='val'>£6,971</td><td class='val'>£5,620</td></tr>
|
||||||
|
<tr><td>On a 90 m² home</td><td class='val'>£627,390</td><td class='val'><span class="cheaper">£505,800</span></td></tr>
|
||||||
|
<tr><td>Dominant property type</td><td class='val'>Semi-Detached</td><td class='val'>Semi-Detached</td></tr>
|
||||||
|
<tr><td>Typical build era</td><td class='val'>~1940</td><td class='val'>~1940</td></tr>
|
||||||
|
<tr><td>Good+ secondary catchments</td><td class='val'>5.4</td><td class='val'>5.4</td></tr>
|
||||||
|
<tr><td>Nearest station</td><td class='val'>~0.59 km</td><td class='val'>~0.59 km</td></tr>
|
||||||
|
<tr><td>Sales in sample (N)</td><td class='val'>3,377</td><td class='val'>2,964</td></tr></tbody></table>
|
||||||
|
<section><h2>The same life, one postcode cheaper</h2><p>Twickenham (TW2 7) and Hounslow (TW3 2) sit about 1.0 km apart, share the same dominant housing (semi-detached, typically built around 1940), comparable good-school catchments and the same level of station access. Yet an equivalent home works out roughly <b>19% (about £121,590 on a 90 m² property) cheaper in Hounslow</b>. On the measures that move price they are near-identical; the gap is mostly the premium attached to the better-known name.</p></section>
|
||||||
|
<section><h2>How we worked this out</h2><p>Postcode sectors (e.g. N10 3) compared on estimated £/m² of floor space. A pair is only called a 'twin' when the two sectors share the dominant property type, build era (±30y), good-school catchment provision, station access, deprivation/tenure, education, age and home size, so the price gap reflects a name premium, not a different kind of area. Estimates, not valuations; aggregated to sector, never address-level.</p></section>
|
||||||
|
<section><h2>Compare more areas</h2>
|
||||||
|
<div class="links">
|
||||||
|
<a href="/cheaper-twins"><b>All cheaper twins →</b><br>Browse every England name-premium pair we found.</a>
|
||||||
|
<a href="/postcode-checker"><b>Postcode checker →</b><br>Prices, crime, schools, broadband for any postcode.</a>
|
||||||
|
<a href="/property-price-map"><b>Property price map →</b><br>Rank England by what each £ buys.</a>
|
||||||
|
</div>
|
||||||
|
<div class="links"><a href="/cheaper-twin/w1j-7-vs-sw7-3"><b>W1J 7 vs SW7 3</b><br>£1,223,460 less for an equivalent flat: same station, similar schools, ~2.6km apart</a>
|
||||||
|
<a href="/cheaper-twin/w1j-8-vs-sw1a-2"><b>W1J 8 vs SW1A 2</b><br>£916,380 less for an equivalent flat: same station, similar schools, ~1.31km apart</a>
|
||||||
|
<a href="/cheaper-twin/w1k-2-vs-sw1x-0"><b>W1K 2 vs SW1X 0</b><br>£978,570 less for an equivalent flat: same station, similar schools, ~1.62km apart</a></div>
|
||||||
|
</section>
|
||||||
|
<p class="note">Contains HM Land Registry data © Crown copyright and database right. Licensed under the Open Government Licence v3.0. Figures are estimates derived from recorded sales and EPC floor areas, aggregated to postcode sector, not valuations, and not address-level.</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<footer><div class="wrap">Sources: HM Land Registry · EPC (DLUHC) · Ofsted · DfT · ONS · Police.uk. Contains HM Land Registry data © Crown copyright and database right. Licensed under the Open Government Licence v3.0.</div></footer>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
87
frontend/public/cheaper-twin/w1j-7-vs-sw7-3/index.html
Normal file
87
frontend/public/cheaper-twin/w1j-7-vs-sw7-3/index.html
Normal file
|
|
@ -0,0 +1,87 @@
|
||||||
|
<!doctype html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
<title>W1J 7 vs SW7 3: the same flat, about 41% cheaper per m² | Perfect Postcode</title>
|
||||||
|
<meta name="description" content="£1,223,460 less for an equivalent flat: same station, similar schools, ~2.6km apart" />
|
||||||
|
<link rel="canonical" href="https://perfect-postcode.co.uk/cheaper-twin/w1j-7-vs-sw7-3" />
|
||||||
|
<style>
|
||||||
|
:root{color-scheme:light dark}
|
||||||
|
*{box-sizing:border-box}
|
||||||
|
body{margin:0;font-family:ui-sans-serif,system-ui,-apple-system,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;
|
||||||
|
color:#0b1220;background:#f7f5f0;line-height:1.6}
|
||||||
|
a{color:#0d9488}
|
||||||
|
.topbar{background:#0b1220;color:#e7ecf3;padding:.7rem 1.25rem;display:flex;justify-content:space-between;align-items:center}
|
||||||
|
.topbar a{color:#2dd4bf;text-decoration:none;font-weight:700}
|
||||||
|
.wrap{max-width:54rem;margin:0 auto;padding:0 1.25rem}
|
||||||
|
.hero{background:linear-gradient(#0b1220,#111a2e);color:#fff;padding:3rem 0 2.5rem}
|
||||||
|
.eyebrow{color:#2dd4bf;font-weight:700;text-transform:uppercase;letter-spacing:.05em;font-size:.8rem;margin:0 0 .5rem}
|
||||||
|
h1{font-size:2rem;line-height:1.15;margin:.2rem 0 .6rem}
|
||||||
|
.hook{color:#cbd5e1;font-size:1.15rem;margin:.5rem 0 1.4rem;max-width:42rem}
|
||||||
|
.big{font-size:3rem;font-weight:800;color:#2dd4bf;margin:.3rem 0}
|
||||||
|
.cta{display:inline-block;margin-top:.4rem;padding:.8rem 1.4rem;border-radius:.6rem;background:#f09a22;color:#0b1220;
|
||||||
|
font-weight:700;text-decoration:none;box-shadow:0 6px 20px rgba(122,57,5,.35)}
|
||||||
|
.cta:hover{background:#df8614}
|
||||||
|
table{width:100%;border-collapse:collapse;margin:1.5rem 0;background:#fff;border-radius:.6rem;overflow:hidden;
|
||||||
|
box-shadow:0 1px 3px rgba(0,0,0,.08)}
|
||||||
|
th,td{padding:.7rem .9rem;text-align:left;border-bottom:1px solid #ece8e0;font-size:.95rem}
|
||||||
|
thead th{background:#0b1220;color:#fff}
|
||||||
|
tbody tr:last-child td{border-bottom:0}
|
||||||
|
.val{font-variant-numeric:tabular-nums;font-weight:600}
|
||||||
|
.cheaper{color:#0d9488}
|
||||||
|
section{margin:2rem 0}
|
||||||
|
h2{font-size:1.3rem;margin:0 0 .6rem}
|
||||||
|
.note{font-size:.82rem;color:#6b7280;border-top:1px solid #e5e1d8;padding-top:1rem;margin-top:2rem}
|
||||||
|
.links{display:grid;gap:.6rem;grid-template-columns:repeat(auto-fit,minmax(15rem,1fr));margin:1rem 0}
|
||||||
|
.links a{display:block;background:#fff;border:1px solid #ece8e0;border-radius:.5rem;padding:.8rem 1rem;text-decoration:none;color:#0b1220}
|
||||||
|
.links a:hover{border-color:#5eead4}
|
||||||
|
.links b{color:#0d9488}
|
||||||
|
.cards{display:grid;gap:1rem;grid-template-columns:repeat(auto-fit,minmax(18rem,1fr))}
|
||||||
|
.card{background:#fff;border:1px solid #ece8e0;border-radius:.6rem;padding:1.1rem;text-decoration:none;color:#0b1220}
|
||||||
|
.card:hover{border-color:#5eead4}
|
||||||
|
.card .n{color:#0d9488;font-weight:800;font-size:1.4rem}
|
||||||
|
footer{color:#6b7280;font-size:.8rem;padding:2rem 0 3rem}
|
||||||
|
@media(prefers-color-scheme:dark){body{background:#0b1220;color:#e7ecf3}table{background:#13203a}
|
||||||
|
th,td{border-color:#223153}.card,.links a{background:#13203a;border-color:#223153;color:#e7ecf3}
|
||||||
|
.note{border-color:#223153;color:#9fb0c3}}
|
||||||
|
</style>
|
||||||
|
<script type="application/ld+json">{"@context": "https://schema.org", "@type": "BreadcrumbList", "itemListElement": [{"@type": "ListItem", "position": 1, "name": "Home", "item": "https://perfect-postcode.co.uk/"}, {"@type": "ListItem", "position": 2, "name": "Cheaper twins", "item": "https://perfect-postcode.co.uk/cheaper-twins"}, {"@type": "ListItem", "position": 3, "name": "W1J 7 vs SW7 3", "item": "https://perfect-postcode.co.uk/cheaper-twin/w1j-7-vs-sw7-3"}]}</script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="topbar"><a href="/">Perfect Postcode</a><a href="/?ref=twin">Open the map →</a></div>
|
||||||
|
|
||||||
|
<div class="hero"><div class="wrap">
|
||||||
|
<p class="eyebrow">Cheaper twin · England</p>
|
||||||
|
<h1>W1J 7 vs SW7 3: the same flat, about 41% cheaper per m²</h1>
|
||||||
|
<div class="big">41% cheaper / m²</div>
|
||||||
|
<p class="hook">£1,223,460 less for an equivalent flat: same station, similar schools, ~2.6km apart</p>
|
||||||
|
<a class="cta" href="https://perfect-postcode.co.uk/?lat=51.49856&lon=-0.16253&zoom=12.5&filter=Est.%20price%20per%20sqm:0:20400&filter=Good%2B%20secondary%20school%20catchments:1:11">See both areas on the live map →</a>
|
||||||
|
</div></div>
|
||||||
|
<div class="wrap">
|
||||||
|
<table><thead><tr><th></th><th>Mayfair (W1J 7)</th><th>SW7 3</th></tr></thead>
|
||||||
|
<tbody><tr><td>Estimated £/m²</td><td class='val'>£32,986</td><td class='val'>£19,392</td></tr>
|
||||||
|
<tr><td>On a 90 m² home</td><td class='val'>£2,968,740</td><td class='val'><span class="cheaper">£1,745,280</span></td></tr>
|
||||||
|
<tr><td>Dominant property type</td><td class='val'>Flats/Maisonettes</td><td class='val'>Flats/Maisonettes</td></tr>
|
||||||
|
<tr><td>Typical build era</td><td class='val'>~1914</td><td class='val'>~1914</td></tr>
|
||||||
|
<tr><td>Good+ secondary catchments</td><td class='val'>2.0</td><td class='val'>2.0</td></tr>
|
||||||
|
<tr><td>Nearest station</td><td class='val'>~0.3 km</td><td class='val'>~0.3 km</td></tr>
|
||||||
|
<tr><td>Sales in sample (N)</td><td class='val'>724</td><td class='val'>2,581</td></tr></tbody></table>
|
||||||
|
<section><h2>The same life, one postcode cheaper</h2><p>Mayfair (W1J 7) and SW7 3 sit about 2.6 km apart, share the same dominant housing (flats/maisonettes, typically built around 1914), comparable good-school catchments and the same level of station access. Yet an equivalent home works out roughly <b>41% (about £1,223,460 on a 90 m² property) cheaper in SW7 3</b>. On the measures that move price they are near-identical; the gap is mostly the premium attached to the better-known name.</p></section>
|
||||||
|
<section><h2>How we worked this out</h2><p>Postcode sectors (e.g. N10 3) compared on estimated £/m² of floor space. A pair is only called a 'twin' when the two sectors share the dominant property type, build era (±30y), good-school catchment provision, station access, deprivation/tenure, education, age and home size, so the price gap reflects a name premium, not a different kind of area. Estimates, not valuations; aggregated to sector, never address-level.</p></section>
|
||||||
|
<section><h2>Compare more areas</h2>
|
||||||
|
<div class="links">
|
||||||
|
<a href="/cheaper-twins"><b>All cheaper twins →</b><br>Browse every England name-premium pair we found.</a>
|
||||||
|
<a href="/postcode-checker"><b>Postcode checker →</b><br>Prices, crime, schools, broadband for any postcode.</a>
|
||||||
|
<a href="/property-price-map"><b>Property price map →</b><br>Rank England by what each £ buys.</a>
|
||||||
|
</div>
|
||||||
|
<div class="links"><a href="/cheaper-twin/w1j-8-vs-sw1a-2"><b>W1J 8 vs SW1A 2</b><br>£916,380 less for an equivalent flat: same station, similar schools, ~1.31km apart</a>
|
||||||
|
<a href="/cheaper-twin/w1k-2-vs-sw1x-0"><b>W1K 2 vs SW1X 0</b><br>£978,570 less for an equivalent flat: same station, similar schools, ~1.62km apart</a>
|
||||||
|
<a href="/cheaper-twin/w1u-4-vs-nw1-4"><b>Marylebone vs Camden</b><br>£942,480 less for an equivalent flat: same station, similar schools, ~0.97km apart</a></div>
|
||||||
|
</section>
|
||||||
|
<p class="note">Contains HM Land Registry data © Crown copyright and database right. Licensed under the Open Government Licence v3.0. Figures are estimates derived from recorded sales and EPC floor areas, aggregated to postcode sector, not valuations, and not address-level.</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<footer><div class="wrap">Sources: HM Land Registry · EPC (DLUHC) · Ofsted · DfT · ONS · Police.uk. Contains HM Land Registry data © Crown copyright and database right. Licensed under the Open Government Licence v3.0.</div></footer>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
87
frontend/public/cheaper-twin/w1j-8-vs-sw1a-2/index.html
Normal file
87
frontend/public/cheaper-twin/w1j-8-vs-sw1a-2/index.html
Normal file
|
|
@ -0,0 +1,87 @@
|
||||||
|
<!doctype html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
<title>W1J 8 vs SW1A 2: the same flat, about 37% cheaper per m² | Perfect Postcode</title>
|
||||||
|
<meta name="description" content="£916,380 less for an equivalent flat: same station, similar schools, ~1.31km apart" />
|
||||||
|
<link rel="canonical" href="https://perfect-postcode.co.uk/cheaper-twin/w1j-8-vs-sw1a-2" />
|
||||||
|
<style>
|
||||||
|
:root{color-scheme:light dark}
|
||||||
|
*{box-sizing:border-box}
|
||||||
|
body{margin:0;font-family:ui-sans-serif,system-ui,-apple-system,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;
|
||||||
|
color:#0b1220;background:#f7f5f0;line-height:1.6}
|
||||||
|
a{color:#0d9488}
|
||||||
|
.topbar{background:#0b1220;color:#e7ecf3;padding:.7rem 1.25rem;display:flex;justify-content:space-between;align-items:center}
|
||||||
|
.topbar a{color:#2dd4bf;text-decoration:none;font-weight:700}
|
||||||
|
.wrap{max-width:54rem;margin:0 auto;padding:0 1.25rem}
|
||||||
|
.hero{background:linear-gradient(#0b1220,#111a2e);color:#fff;padding:3rem 0 2.5rem}
|
||||||
|
.eyebrow{color:#2dd4bf;font-weight:700;text-transform:uppercase;letter-spacing:.05em;font-size:.8rem;margin:0 0 .5rem}
|
||||||
|
h1{font-size:2rem;line-height:1.15;margin:.2rem 0 .6rem}
|
||||||
|
.hook{color:#cbd5e1;font-size:1.15rem;margin:.5rem 0 1.4rem;max-width:42rem}
|
||||||
|
.big{font-size:3rem;font-weight:800;color:#2dd4bf;margin:.3rem 0}
|
||||||
|
.cta{display:inline-block;margin-top:.4rem;padding:.8rem 1.4rem;border-radius:.6rem;background:#f09a22;color:#0b1220;
|
||||||
|
font-weight:700;text-decoration:none;box-shadow:0 6px 20px rgba(122,57,5,.35)}
|
||||||
|
.cta:hover{background:#df8614}
|
||||||
|
table{width:100%;border-collapse:collapse;margin:1.5rem 0;background:#fff;border-radius:.6rem;overflow:hidden;
|
||||||
|
box-shadow:0 1px 3px rgba(0,0,0,.08)}
|
||||||
|
th,td{padding:.7rem .9rem;text-align:left;border-bottom:1px solid #ece8e0;font-size:.95rem}
|
||||||
|
thead th{background:#0b1220;color:#fff}
|
||||||
|
tbody tr:last-child td{border-bottom:0}
|
||||||
|
.val{font-variant-numeric:tabular-nums;font-weight:600}
|
||||||
|
.cheaper{color:#0d9488}
|
||||||
|
section{margin:2rem 0}
|
||||||
|
h2{font-size:1.3rem;margin:0 0 .6rem}
|
||||||
|
.note{font-size:.82rem;color:#6b7280;border-top:1px solid #e5e1d8;padding-top:1rem;margin-top:2rem}
|
||||||
|
.links{display:grid;gap:.6rem;grid-template-columns:repeat(auto-fit,minmax(15rem,1fr));margin:1rem 0}
|
||||||
|
.links a{display:block;background:#fff;border:1px solid #ece8e0;border-radius:.5rem;padding:.8rem 1rem;text-decoration:none;color:#0b1220}
|
||||||
|
.links a:hover{border-color:#5eead4}
|
||||||
|
.links b{color:#0d9488}
|
||||||
|
.cards{display:grid;gap:1rem;grid-template-columns:repeat(auto-fit,minmax(18rem,1fr))}
|
||||||
|
.card{background:#fff;border:1px solid #ece8e0;border-radius:.6rem;padding:1.1rem;text-decoration:none;color:#0b1220}
|
||||||
|
.card:hover{border-color:#5eead4}
|
||||||
|
.card .n{color:#0d9488;font-weight:800;font-size:1.4rem}
|
||||||
|
footer{color:#6b7280;font-size:.8rem;padding:2rem 0 3rem}
|
||||||
|
@media(prefers-color-scheme:dark){body{background:#0b1220;color:#e7ecf3}table{background:#13203a}
|
||||||
|
th,td{border-color:#223153}.card,.links a{background:#13203a;border-color:#223153;color:#e7ecf3}
|
||||||
|
.note{border-color:#223153;color:#9fb0c3}}
|
||||||
|
</style>
|
||||||
|
<script type="application/ld+json">{"@context": "https://schema.org", "@type": "BreadcrumbList", "itemListElement": [{"@type": "ListItem", "position": 1, "name": "Home", "item": "https://perfect-postcode.co.uk/"}, {"@type": "ListItem", "position": 2, "name": "Cheaper twins", "item": "https://perfect-postcode.co.uk/cheaper-twins"}, {"@type": "ListItem", "position": 3, "name": "W1J 8 vs SW1A 2", "item": "https://perfect-postcode.co.uk/cheaper-twin/w1j-8-vs-sw1a-2"}]}</script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="topbar"><a href="/">Perfect Postcode</a><a href="/?ref=twin">Open the map →</a></div>
|
||||||
|
|
||||||
|
<div class="hero"><div class="wrap">
|
||||||
|
<p class="eyebrow">Cheaper twin · England</p>
|
||||||
|
<h1>W1J 8 vs SW1A 2: the same flat, about 37% cheaper per m²</h1>
|
||||||
|
<div class="big">37% cheaper / m²</div>
|
||||||
|
<p class="hook">£916,380 less for an equivalent flat: same station, similar schools, ~1.31km apart</p>
|
||||||
|
<a class="cta" href="https://perfect-postcode.co.uk/?lat=51.50663&lon=-0.13494&zoom=12.5&filter=Est.%20price%20per%20sqm:0:17900&filter=Good%2B%20secondary%20school%20catchments:1:11">See both areas on the live map →</a>
|
||||||
|
</div></div>
|
||||||
|
<div class="wrap">
|
||||||
|
<table><thead><tr><th></th><th>Mayfair (W1J 8)</th><th>SW1A 2</th></tr></thead>
|
||||||
|
<tbody><tr><td>Estimated £/m²</td><td class='val'>£27,270</td><td class='val'>£17,088</td></tr>
|
||||||
|
<tr><td>On a 90 m² home</td><td class='val'>£2,454,300</td><td class='val'><span class="cheaper">£1,537,920</span></td></tr>
|
||||||
|
<tr><td>Dominant property type</td><td class='val'>Flats/Maisonettes</td><td class='val'>Flats/Maisonettes</td></tr>
|
||||||
|
<tr><td>Typical build era</td><td class='val'>~2000</td><td class='val'>~2000</td></tr>
|
||||||
|
<tr><td>Good+ secondary catchments</td><td class='val'>2.0</td><td class='val'>2.0</td></tr>
|
||||||
|
<tr><td>Nearest station</td><td class='val'>~0.18 km</td><td class='val'>~0.18 km</td></tr>
|
||||||
|
<tr><td>Sales in sample (N)</td><td class='val'>295</td><td class='val'>261</td></tr></tbody></table>
|
||||||
|
<section><h2>The same life, one postcode cheaper</h2><p>Mayfair (W1J 8) and SW1A 2 sit about 1.31 km apart, share the same dominant housing (flats/maisonettes, typically built around 2000), comparable good-school catchments and the same level of station access. Yet an equivalent home works out roughly <b>37% (about £916,380 on a 90 m² property) cheaper in SW1A 2</b>. On the measures that move price they are near-identical; the gap is mostly the premium attached to the better-known name.</p></section>
|
||||||
|
<section><h2>How we worked this out</h2><p>Postcode sectors (e.g. N10 3) compared on estimated £/m² of floor space. A pair is only called a 'twin' when the two sectors share the dominant property type, build era (±30y), good-school catchment provision, station access, deprivation/tenure, education, age and home size, so the price gap reflects a name premium, not a different kind of area. Estimates, not valuations; aggregated to sector, never address-level.</p></section>
|
||||||
|
<section><h2>Compare more areas</h2>
|
||||||
|
<div class="links">
|
||||||
|
<a href="/cheaper-twins"><b>All cheaper twins →</b><br>Browse every England name-premium pair we found.</a>
|
||||||
|
<a href="/postcode-checker"><b>Postcode checker →</b><br>Prices, crime, schools, broadband for any postcode.</a>
|
||||||
|
<a href="/property-price-map"><b>Property price map →</b><br>Rank England by what each £ buys.</a>
|
||||||
|
</div>
|
||||||
|
<div class="links"><a href="/cheaper-twin/w1k-2-vs-sw1x-0"><b>W1K 2 vs SW1X 0</b><br>£978,570 less for an equivalent flat: same station, similar schools, ~1.62km apart</a>
|
||||||
|
<a href="/cheaper-twin/w1u-4-vs-nw1-4"><b>Marylebone vs Camden</b><br>£942,480 less for an equivalent flat: same station, similar schools, ~0.97km apart</a>
|
||||||
|
<a href="/cheaper-twin/wc2a-2-vs-ec2a-2"><b>WC2A 2 vs EC2A 2</b><br>£981,540 less for an equivalent flat: same station, similar schools, ~2.3km apart</a></div>
|
||||||
|
</section>
|
||||||
|
<p class="note">Contains HM Land Registry data © Crown copyright and database right. Licensed under the Open Government Licence v3.0. Figures are estimates derived from recorded sales and EPC floor areas, aggregated to postcode sector, not valuations, and not address-level.</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<footer><div class="wrap">Sources: HM Land Registry · EPC (DLUHC) · Ofsted · DfT · ONS · Police.uk. Contains HM Land Registry data © Crown copyright and database right. Licensed under the Open Government Licence v3.0.</div></footer>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
87
frontend/public/cheaper-twin/w1k-2-vs-sw1x-0/index.html
Normal file
87
frontend/public/cheaper-twin/w1k-2-vs-sw1x-0/index.html
Normal file
|
|
@ -0,0 +1,87 @@
|
||||||
|
<!doctype html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
<title>W1K 2 vs SW1X 0: the same flat, about 32% cheaper per m² | Perfect Postcode</title>
|
||||||
|
<meta name="description" content="£978,570 less for an equivalent flat: same station, similar schools, ~1.62km apart" />
|
||||||
|
<link rel="canonical" href="https://perfect-postcode.co.uk/cheaper-twin/w1k-2-vs-sw1x-0" />
|
||||||
|
<style>
|
||||||
|
:root{color-scheme:light dark}
|
||||||
|
*{box-sizing:border-box}
|
||||||
|
body{margin:0;font-family:ui-sans-serif,system-ui,-apple-system,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;
|
||||||
|
color:#0b1220;background:#f7f5f0;line-height:1.6}
|
||||||
|
a{color:#0d9488}
|
||||||
|
.topbar{background:#0b1220;color:#e7ecf3;padding:.7rem 1.25rem;display:flex;justify-content:space-between;align-items:center}
|
||||||
|
.topbar a{color:#2dd4bf;text-decoration:none;font-weight:700}
|
||||||
|
.wrap{max-width:54rem;margin:0 auto;padding:0 1.25rem}
|
||||||
|
.hero{background:linear-gradient(#0b1220,#111a2e);color:#fff;padding:3rem 0 2.5rem}
|
||||||
|
.eyebrow{color:#2dd4bf;font-weight:700;text-transform:uppercase;letter-spacing:.05em;font-size:.8rem;margin:0 0 .5rem}
|
||||||
|
h1{font-size:2rem;line-height:1.15;margin:.2rem 0 .6rem}
|
||||||
|
.hook{color:#cbd5e1;font-size:1.15rem;margin:.5rem 0 1.4rem;max-width:42rem}
|
||||||
|
.big{font-size:3rem;font-weight:800;color:#2dd4bf;margin:.3rem 0}
|
||||||
|
.cta{display:inline-block;margin-top:.4rem;padding:.8rem 1.4rem;border-radius:.6rem;background:#f09a22;color:#0b1220;
|
||||||
|
font-weight:700;text-decoration:none;box-shadow:0 6px 20px rgba(122,57,5,.35)}
|
||||||
|
.cta:hover{background:#df8614}
|
||||||
|
table{width:100%;border-collapse:collapse;margin:1.5rem 0;background:#fff;border-radius:.6rem;overflow:hidden;
|
||||||
|
box-shadow:0 1px 3px rgba(0,0,0,.08)}
|
||||||
|
th,td{padding:.7rem .9rem;text-align:left;border-bottom:1px solid #ece8e0;font-size:.95rem}
|
||||||
|
thead th{background:#0b1220;color:#fff}
|
||||||
|
tbody tr:last-child td{border-bottom:0}
|
||||||
|
.val{font-variant-numeric:tabular-nums;font-weight:600}
|
||||||
|
.cheaper{color:#0d9488}
|
||||||
|
section{margin:2rem 0}
|
||||||
|
h2{font-size:1.3rem;margin:0 0 .6rem}
|
||||||
|
.note{font-size:.82rem;color:#6b7280;border-top:1px solid #e5e1d8;padding-top:1rem;margin-top:2rem}
|
||||||
|
.links{display:grid;gap:.6rem;grid-template-columns:repeat(auto-fit,minmax(15rem,1fr));margin:1rem 0}
|
||||||
|
.links a{display:block;background:#fff;border:1px solid #ece8e0;border-radius:.5rem;padding:.8rem 1rem;text-decoration:none;color:#0b1220}
|
||||||
|
.links a:hover{border-color:#5eead4}
|
||||||
|
.links b{color:#0d9488}
|
||||||
|
.cards{display:grid;gap:1rem;grid-template-columns:repeat(auto-fit,minmax(18rem,1fr))}
|
||||||
|
.card{background:#fff;border:1px solid #ece8e0;border-radius:.6rem;padding:1.1rem;text-decoration:none;color:#0b1220}
|
||||||
|
.card:hover{border-color:#5eead4}
|
||||||
|
.card .n{color:#0d9488;font-weight:800;font-size:1.4rem}
|
||||||
|
footer{color:#6b7280;font-size:.8rem;padding:2rem 0 3rem}
|
||||||
|
@media(prefers-color-scheme:dark){body{background:#0b1220;color:#e7ecf3}table{background:#13203a}
|
||||||
|
th,td{border-color:#223153}.card,.links a{background:#13203a;border-color:#223153;color:#e7ecf3}
|
||||||
|
.note{border-color:#223153;color:#9fb0c3}}
|
||||||
|
</style>
|
||||||
|
<script type="application/ld+json">{"@context": "https://schema.org", "@type": "BreadcrumbList", "itemListElement": [{"@type": "ListItem", "position": 1, "name": "Home", "item": "https://perfect-postcode.co.uk/"}, {"@type": "ListItem", "position": 2, "name": "Cheaper twins", "item": "https://perfect-postcode.co.uk/cheaper-twins"}, {"@type": "ListItem", "position": 3, "name": "W1K 2 vs SW1X 0", "item": "https://perfect-postcode.co.uk/cheaper-twin/w1k-2-vs-sw1x-0"}]}</script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="topbar"><a href="/">Perfect Postcode</a><a href="/?ref=twin">Open the map →</a></div>
|
||||||
|
|
||||||
|
<div class="hero"><div class="wrap">
|
||||||
|
<p class="eyebrow">Cheaper twin · England</p>
|
||||||
|
<h1>W1K 2 vs SW1X 0: the same flat, about 32% cheaper per m²</h1>
|
||||||
|
<div class="big">32% cheaper / m²</div>
|
||||||
|
<p class="hook">£978,570 less for an equivalent flat: same station, similar schools, ~1.62km apart</p>
|
||||||
|
<a class="cta" href="https://perfect-postcode.co.uk/?lat=51.50311&lon=-0.15673&zoom=12.5&filter=Est.%20price%20per%20sqm:0:24700&filter=Good%2B%20secondary%20school%20catchments:1:11">See both areas on the live map →</a>
|
||||||
|
</div></div>
|
||||||
|
<div class="wrap">
|
||||||
|
<table><thead><tr><th></th><th>Mayfair (W1K 2)</th><th>SW1X 0</th></tr></thead>
|
||||||
|
<tbody><tr><td>Estimated £/m²</td><td class='val'>£34,362</td><td class='val'>£23,489</td></tr>
|
||||||
|
<tr><td>On a 90 m² home</td><td class='val'>£3,092,580</td><td class='val'><span class="cheaper">£2,114,010</span></td></tr>
|
||||||
|
<tr><td>Dominant property type</td><td class='val'>Flats/Maisonettes</td><td class='val'>Flats/Maisonettes</td></tr>
|
||||||
|
<tr><td>Typical build era</td><td class='val'>~1914</td><td class='val'>~1914</td></tr>
|
||||||
|
<tr><td>Good+ secondary catchments</td><td class='val'>2.0</td><td class='val'>2.0</td></tr>
|
||||||
|
<tr><td>Nearest station</td><td class='val'>~0.5 km</td><td class='val'>~0.5 km</td></tr>
|
||||||
|
<tr><td>Sales in sample (N)</td><td class='val'>591</td><td class='val'>1,606</td></tr></tbody></table>
|
||||||
|
<section><h2>The same life, one postcode cheaper</h2><p>Mayfair (W1K 2) and SW1X 0 sit about 1.62 km apart, share the same dominant housing (flats/maisonettes, typically built around 1914), comparable good-school catchments and the same level of station access. Yet an equivalent home works out roughly <b>32% (about £978,570 on a 90 m² property) cheaper in SW1X 0</b>. On the measures that move price they are near-identical; the gap is mostly the premium attached to the better-known name.</p></section>
|
||||||
|
<section><h2>How we worked this out</h2><p>Postcode sectors (e.g. N10 3) compared on estimated £/m² of floor space. A pair is only called a 'twin' when the two sectors share the dominant property type, build era (±30y), good-school catchment provision, station access, deprivation/tenure, education, age and home size, so the price gap reflects a name premium, not a different kind of area. Estimates, not valuations; aggregated to sector, never address-level.</p></section>
|
||||||
|
<section><h2>Compare more areas</h2>
|
||||||
|
<div class="links">
|
||||||
|
<a href="/cheaper-twins"><b>All cheaper twins →</b><br>Browse every England name-premium pair we found.</a>
|
||||||
|
<a href="/postcode-checker"><b>Postcode checker →</b><br>Prices, crime, schools, broadband for any postcode.</a>
|
||||||
|
<a href="/property-price-map"><b>Property price map →</b><br>Rank England by what each £ buys.</a>
|
||||||
|
</div>
|
||||||
|
<div class="links"><a href="/cheaper-twin/w1u-4-vs-nw1-4"><b>Marylebone vs Camden</b><br>£942,480 less for an equivalent flat: same station, similar schools, ~0.97km apart</a>
|
||||||
|
<a href="/cheaper-twin/wc2a-2-vs-ec2a-2"><b>WC2A 2 vs EC2A 2</b><br>£981,540 less for an equivalent flat: same station, similar schools, ~2.3km apart</a>
|
||||||
|
<a href="/cheaper-twin/br3-3-vs-cr0-7"><b>Beckenham vs Croydon</b><br>£201,870 less for an equivalent terraced house: same station, similar schools, ~2.02km apart</a></div>
|
||||||
|
</section>
|
||||||
|
<p class="note">Contains HM Land Registry data © Crown copyright and database right. Licensed under the Open Government Licence v3.0. Figures are estimates derived from recorded sales and EPC floor areas, aggregated to postcode sector, not valuations, and not address-level.</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<footer><div class="wrap">Sources: HM Land Registry · EPC (DLUHC) · Ofsted · DfT · ONS · Police.uk. Contains HM Land Registry data © Crown copyright and database right. Licensed under the Open Government Licence v3.0.</div></footer>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
87
frontend/public/cheaper-twin/w1u-4-vs-nw1-4/index.html
Normal file
87
frontend/public/cheaper-twin/w1u-4-vs-nw1-4/index.html
Normal file
|
|
@ -0,0 +1,87 @@
|
||||||
|
<!doctype html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
<title>Marylebone vs Camden: the same flat, about 43% cheaper per m² | Perfect Postcode</title>
|
||||||
|
<meta name="description" content="£942,480 less for an equivalent flat: same station, similar schools, ~0.97km apart" />
|
||||||
|
<link rel="canonical" href="https://perfect-postcode.co.uk/cheaper-twin/w1u-4-vs-nw1-4" />
|
||||||
|
<style>
|
||||||
|
:root{color-scheme:light dark}
|
||||||
|
*{box-sizing:border-box}
|
||||||
|
body{margin:0;font-family:ui-sans-serif,system-ui,-apple-system,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;
|
||||||
|
color:#0b1220;background:#f7f5f0;line-height:1.6}
|
||||||
|
a{color:#0d9488}
|
||||||
|
.topbar{background:#0b1220;color:#e7ecf3;padding:.7rem 1.25rem;display:flex;justify-content:space-between;align-items:center}
|
||||||
|
.topbar a{color:#2dd4bf;text-decoration:none;font-weight:700}
|
||||||
|
.wrap{max-width:54rem;margin:0 auto;padding:0 1.25rem}
|
||||||
|
.hero{background:linear-gradient(#0b1220,#111a2e);color:#fff;padding:3rem 0 2.5rem}
|
||||||
|
.eyebrow{color:#2dd4bf;font-weight:700;text-transform:uppercase;letter-spacing:.05em;font-size:.8rem;margin:0 0 .5rem}
|
||||||
|
h1{font-size:2rem;line-height:1.15;margin:.2rem 0 .6rem}
|
||||||
|
.hook{color:#cbd5e1;font-size:1.15rem;margin:.5rem 0 1.4rem;max-width:42rem}
|
||||||
|
.big{font-size:3rem;font-weight:800;color:#2dd4bf;margin:.3rem 0}
|
||||||
|
.cta{display:inline-block;margin-top:.4rem;padding:.8rem 1.4rem;border-radius:.6rem;background:#f09a22;color:#0b1220;
|
||||||
|
font-weight:700;text-decoration:none;box-shadow:0 6px 20px rgba(122,57,5,.35)}
|
||||||
|
.cta:hover{background:#df8614}
|
||||||
|
table{width:100%;border-collapse:collapse;margin:1.5rem 0;background:#fff;border-radius:.6rem;overflow:hidden;
|
||||||
|
box-shadow:0 1px 3px rgba(0,0,0,.08)}
|
||||||
|
th,td{padding:.7rem .9rem;text-align:left;border-bottom:1px solid #ece8e0;font-size:.95rem}
|
||||||
|
thead th{background:#0b1220;color:#fff}
|
||||||
|
tbody tr:last-child td{border-bottom:0}
|
||||||
|
.val{font-variant-numeric:tabular-nums;font-weight:600}
|
||||||
|
.cheaper{color:#0d9488}
|
||||||
|
section{margin:2rem 0}
|
||||||
|
h2{font-size:1.3rem;margin:0 0 .6rem}
|
||||||
|
.note{font-size:.82rem;color:#6b7280;border-top:1px solid #e5e1d8;padding-top:1rem;margin-top:2rem}
|
||||||
|
.links{display:grid;gap:.6rem;grid-template-columns:repeat(auto-fit,minmax(15rem,1fr));margin:1rem 0}
|
||||||
|
.links a{display:block;background:#fff;border:1px solid #ece8e0;border-radius:.5rem;padding:.8rem 1rem;text-decoration:none;color:#0b1220}
|
||||||
|
.links a:hover{border-color:#5eead4}
|
||||||
|
.links b{color:#0d9488}
|
||||||
|
.cards{display:grid;gap:1rem;grid-template-columns:repeat(auto-fit,minmax(18rem,1fr))}
|
||||||
|
.card{background:#fff;border:1px solid #ece8e0;border-radius:.6rem;padding:1.1rem;text-decoration:none;color:#0b1220}
|
||||||
|
.card:hover{border-color:#5eead4}
|
||||||
|
.card .n{color:#0d9488;font-weight:800;font-size:1.4rem}
|
||||||
|
footer{color:#6b7280;font-size:.8rem;padding:2rem 0 3rem}
|
||||||
|
@media(prefers-color-scheme:dark){body{background:#0b1220;color:#e7ecf3}table{background:#13203a}
|
||||||
|
th,td{border-color:#223153}.card,.links a{background:#13203a;border-color:#223153;color:#e7ecf3}
|
||||||
|
.note{border-color:#223153;color:#9fb0c3}}
|
||||||
|
</style>
|
||||||
|
<script type="application/ld+json">{"@context": "https://schema.org", "@type": "BreadcrumbList", "itemListElement": [{"@type": "ListItem", "position": 1, "name": "Home", "item": "https://perfect-postcode.co.uk/"}, {"@type": "ListItem", "position": 2, "name": "Cheaper twins", "item": "https://perfect-postcode.co.uk/cheaper-twins"}, {"@type": "ListItem", "position": 3, "name": "Marylebone vs Camden", "item": "https://perfect-postcode.co.uk/cheaper-twin/w1u-4-vs-nw1-4"}]}</script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="topbar"><a href="/">Perfect Postcode</a><a href="/?ref=twin">Open the map →</a></div>
|
||||||
|
|
||||||
|
<div class="hero"><div class="wrap">
|
||||||
|
<p class="eyebrow">Cheaper twin · England</p>
|
||||||
|
<h1>Marylebone vs Camden: the same flat, about 43% cheaper per m²</h1>
|
||||||
|
<div class="big">43% cheaper / m²</div>
|
||||||
|
<p class="hook">£942,480 less for an equivalent flat: same station, similar schools, ~0.97km apart</p>
|
||||||
|
<a class="cta" href="https://perfect-postcode.co.uk/?lat=51.5238&lon=-0.15091&zoom=12.5&filter=Est.%20price%20per%20sqm:0:14500&filter=Good%2B%20secondary%20school%20catchments:1:11">See both areas on the live map →</a>
|
||||||
|
</div></div>
|
||||||
|
<div class="wrap">
|
||||||
|
<table><thead><tr><th></th><th>Marylebone (W1U 4)</th><th>Camden (NW1 4)</th></tr></thead>
|
||||||
|
<tbody><tr><td>Estimated £/m²</td><td class='val'>£24,238</td><td class='val'>£13,766</td></tr>
|
||||||
|
<tr><td>On a 90 m² home</td><td class='val'>£2,181,420</td><td class='val'><span class="cheaper">£1,238,940</span></td></tr>
|
||||||
|
<tr><td>Dominant property type</td><td class='val'>Flats/Maisonettes</td><td class='val'>Flats/Maisonettes</td></tr>
|
||||||
|
<tr><td>Typical build era</td><td class='val'>~1940</td><td class='val'>~1940</td></tr>
|
||||||
|
<tr><td>Good+ secondary catchments</td><td class='val'>1.0</td><td class='val'>1.0</td></tr>
|
||||||
|
<tr><td>Nearest station</td><td class='val'>~0.44 km</td><td class='val'>~0.44 km</td></tr>
|
||||||
|
<tr><td>Sales in sample (N)</td><td class='val'>984</td><td class='val'>1,340</td></tr></tbody></table>
|
||||||
|
<section><h2>The same life, one postcode cheaper</h2><p>Marylebone (W1U 4) and Camden (NW1 4) sit about 0.97 km apart, share the same dominant housing (flats/maisonettes, typically built around 1940), comparable good-school catchments and the same level of station access. Yet an equivalent home works out roughly <b>43% (about £942,480 on a 90 m² property) cheaper in Camden</b>. On the measures that move price they are near-identical; the gap is mostly the premium attached to the better-known name.</p></section>
|
||||||
|
<section><h2>How we worked this out</h2><p>Postcode sectors (e.g. N10 3) compared on estimated £/m² of floor space. A pair is only called a 'twin' when the two sectors share the dominant property type, build era (±30y), good-school catchment provision, station access, deprivation/tenure, education, age and home size, so the price gap reflects a name premium, not a different kind of area. Estimates, not valuations; aggregated to sector, never address-level.</p></section>
|
||||||
|
<section><h2>Compare more areas</h2>
|
||||||
|
<div class="links">
|
||||||
|
<a href="/cheaper-twins"><b>All cheaper twins →</b><br>Browse every England name-premium pair we found.</a>
|
||||||
|
<a href="/postcode-checker"><b>Postcode checker →</b><br>Prices, crime, schools, broadband for any postcode.</a>
|
||||||
|
<a href="/property-price-map"><b>Property price map →</b><br>Rank England by what each £ buys.</a>
|
||||||
|
</div>
|
||||||
|
<div class="links"><a href="/cheaper-twin/wc2a-2-vs-ec2a-2"><b>WC2A 2 vs EC2A 2</b><br>£981,540 less for an equivalent flat: same station, similar schools, ~2.3km apart</a>
|
||||||
|
<a href="/cheaper-twin/br3-3-vs-cr0-7"><b>Beckenham vs Croydon</b><br>£201,870 less for an equivalent terraced house: same station, similar schools, ~2.02km apart</a>
|
||||||
|
<a href="/cheaper-twin/ha7-2-vs-ha3-0"><b>Stanmore vs Kenton</b><br>£106,920 less for an equivalent semi-detached house: same station, similar schools, ~2.57km apart</a></div>
|
||||||
|
</section>
|
||||||
|
<p class="note">Contains HM Land Registry data © Crown copyright and database right. Licensed under the Open Government Licence v3.0. Figures are estimates derived from recorded sales and EPC floor areas, aggregated to postcode sector, not valuations, and not address-level.</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<footer><div class="wrap">Sources: HM Land Registry · EPC (DLUHC) · Ofsted · DfT · ONS · Police.uk. Contains HM Land Registry data © Crown copyright and database right. Licensed under the Open Government Licence v3.0.</div></footer>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
87
frontend/public/cheaper-twin/wc2a-2-vs-ec2a-2/index.html
Normal file
87
frontend/public/cheaper-twin/wc2a-2-vs-ec2a-2/index.html
Normal file
|
|
@ -0,0 +1,87 @@
|
||||||
|
<!doctype html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
<title>WC2A 2 vs EC2A 2: the same flat, about 43% cheaper per m² | Perfect Postcode</title>
|
||||||
|
<meta name="description" content="£981,540 less for an equivalent flat: same station, similar schools, ~2.3km apart" />
|
||||||
|
<link rel="canonical" href="https://perfect-postcode.co.uk/cheaper-twin/wc2a-2-vs-ec2a-2" />
|
||||||
|
<style>
|
||||||
|
:root{color-scheme:light dark}
|
||||||
|
*{box-sizing:border-box}
|
||||||
|
body{margin:0;font-family:ui-sans-serif,system-ui,-apple-system,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;
|
||||||
|
color:#0b1220;background:#f7f5f0;line-height:1.6}
|
||||||
|
a{color:#0d9488}
|
||||||
|
.topbar{background:#0b1220;color:#e7ecf3;padding:.7rem 1.25rem;display:flex;justify-content:space-between;align-items:center}
|
||||||
|
.topbar a{color:#2dd4bf;text-decoration:none;font-weight:700}
|
||||||
|
.wrap{max-width:54rem;margin:0 auto;padding:0 1.25rem}
|
||||||
|
.hero{background:linear-gradient(#0b1220,#111a2e);color:#fff;padding:3rem 0 2.5rem}
|
||||||
|
.eyebrow{color:#2dd4bf;font-weight:700;text-transform:uppercase;letter-spacing:.05em;font-size:.8rem;margin:0 0 .5rem}
|
||||||
|
h1{font-size:2rem;line-height:1.15;margin:.2rem 0 .6rem}
|
||||||
|
.hook{color:#cbd5e1;font-size:1.15rem;margin:.5rem 0 1.4rem;max-width:42rem}
|
||||||
|
.big{font-size:3rem;font-weight:800;color:#2dd4bf;margin:.3rem 0}
|
||||||
|
.cta{display:inline-block;margin-top:.4rem;padding:.8rem 1.4rem;border-radius:.6rem;background:#f09a22;color:#0b1220;
|
||||||
|
font-weight:700;text-decoration:none;box-shadow:0 6px 20px rgba(122,57,5,.35)}
|
||||||
|
.cta:hover{background:#df8614}
|
||||||
|
table{width:100%;border-collapse:collapse;margin:1.5rem 0;background:#fff;border-radius:.6rem;overflow:hidden;
|
||||||
|
box-shadow:0 1px 3px rgba(0,0,0,.08)}
|
||||||
|
th,td{padding:.7rem .9rem;text-align:left;border-bottom:1px solid #ece8e0;font-size:.95rem}
|
||||||
|
thead th{background:#0b1220;color:#fff}
|
||||||
|
tbody tr:last-child td{border-bottom:0}
|
||||||
|
.val{font-variant-numeric:tabular-nums;font-weight:600}
|
||||||
|
.cheaper{color:#0d9488}
|
||||||
|
section{margin:2rem 0}
|
||||||
|
h2{font-size:1.3rem;margin:0 0 .6rem}
|
||||||
|
.note{font-size:.82rem;color:#6b7280;border-top:1px solid #e5e1d8;padding-top:1rem;margin-top:2rem}
|
||||||
|
.links{display:grid;gap:.6rem;grid-template-columns:repeat(auto-fit,minmax(15rem,1fr));margin:1rem 0}
|
||||||
|
.links a{display:block;background:#fff;border:1px solid #ece8e0;border-radius:.5rem;padding:.8rem 1rem;text-decoration:none;color:#0b1220}
|
||||||
|
.links a:hover{border-color:#5eead4}
|
||||||
|
.links b{color:#0d9488}
|
||||||
|
.cards{display:grid;gap:1rem;grid-template-columns:repeat(auto-fit,minmax(18rem,1fr))}
|
||||||
|
.card{background:#fff;border:1px solid #ece8e0;border-radius:.6rem;padding:1.1rem;text-decoration:none;color:#0b1220}
|
||||||
|
.card:hover{border-color:#5eead4}
|
||||||
|
.card .n{color:#0d9488;font-weight:800;font-size:1.4rem}
|
||||||
|
footer{color:#6b7280;font-size:.8rem;padding:2rem 0 3rem}
|
||||||
|
@media(prefers-color-scheme:dark){body{background:#0b1220;color:#e7ecf3}table{background:#13203a}
|
||||||
|
th,td{border-color:#223153}.card,.links a{background:#13203a;border-color:#223153;color:#e7ecf3}
|
||||||
|
.note{border-color:#223153;color:#9fb0c3}}
|
||||||
|
</style>
|
||||||
|
<script type="application/ld+json">{"@context": "https://schema.org", "@type": "BreadcrumbList", "itemListElement": [{"@type": "ListItem", "position": 1, "name": "Home", "item": "https://perfect-postcode.co.uk/"}, {"@type": "ListItem", "position": 2, "name": "Cheaper twins", "item": "https://perfect-postcode.co.uk/cheaper-twins"}, {"@type": "ListItem", "position": 3, "name": "WC2A 2 vs EC2A 2", "item": "https://perfect-postcode.co.uk/cheaper-twin/wc2a-2-vs-ec2a-2"}]}</script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="topbar"><a href="/">Perfect Postcode</a><a href="/?ref=twin">Open the map →</a></div>
|
||||||
|
|
||||||
|
<div class="hero"><div class="wrap">
|
||||||
|
<p class="eyebrow">Cheaper twin · England</p>
|
||||||
|
<h1>WC2A 2 vs EC2A 2: the same flat, about 43% cheaper per m²</h1>
|
||||||
|
<div class="big">43% cheaper / m²</div>
|
||||||
|
<p class="hook">£981,540 less for an equivalent flat: same station, similar schools, ~2.3km apart</p>
|
||||||
|
<a class="cta" href="https://perfect-postcode.co.uk/?lat=51.51807&lon=-0.09837&zoom=12.5&filter=Est.%20price%20per%20sqm:0:15300&filter=Good%2B%20secondary%20school%20catchments:1:11">See both areas on the live map →</a>
|
||||||
|
</div></div>
|
||||||
|
<div class="wrap">
|
||||||
|
<table><thead><tr><th></th><th>WC2A 2</th><th>EC2A 2</th></tr></thead>
|
||||||
|
<tbody><tr><td>Estimated £/m²</td><td class='val'>£25,482</td><td class='val'>£14,576</td></tr>
|
||||||
|
<tr><td>On a 90 m² home</td><td class='val'>£2,293,380</td><td class='val'><span class="cheaper">£1,311,840</span></td></tr>
|
||||||
|
<tr><td>Dominant property type</td><td class='val'>Flats/Maisonettes</td><td class='val'>Flats/Maisonettes</td></tr>
|
||||||
|
<tr><td>Typical build era</td><td class='val'>~2019</td><td class='val'>~2019</td></tr>
|
||||||
|
<tr><td>Good+ secondary catchments</td><td class='val'>2.0</td><td class='val'>2.0</td></tr>
|
||||||
|
<tr><td>Nearest station</td><td class='val'>~0.42 km</td><td class='val'>~0.42 km</td></tr>
|
||||||
|
<tr><td>Sales in sample (N)</td><td class='val'>254</td><td class='val'>772</td></tr></tbody></table>
|
||||||
|
<section><h2>The same life, one postcode cheaper</h2><p>WC2A 2 and EC2A 2 sit about 2.3 km apart, share the same dominant housing (flats/maisonettes, typically built around 2019), comparable good-school catchments and the same level of station access. Yet an equivalent home works out roughly <b>43% (about £981,540 on a 90 m² property) cheaper in EC2A 2</b>. On the measures that move price they are near-identical; the gap is mostly the premium attached to the better-known name.</p></section>
|
||||||
|
<section><h2>How we worked this out</h2><p>Postcode sectors (e.g. N10 3) compared on estimated £/m² of floor space. A pair is only called a 'twin' when the two sectors share the dominant property type, build era (±30y), good-school catchment provision, station access, deprivation/tenure, education, age and home size, so the price gap reflects a name premium, not a different kind of area. Estimates, not valuations; aggregated to sector, never address-level.</p></section>
|
||||||
|
<section><h2>Compare more areas</h2>
|
||||||
|
<div class="links">
|
||||||
|
<a href="/cheaper-twins"><b>All cheaper twins →</b><br>Browse every England name-premium pair we found.</a>
|
||||||
|
<a href="/postcode-checker"><b>Postcode checker →</b><br>Prices, crime, schools, broadband for any postcode.</a>
|
||||||
|
<a href="/property-price-map"><b>Property price map →</b><br>Rank England by what each £ buys.</a>
|
||||||
|
</div>
|
||||||
|
<div class="links"><a href="/cheaper-twin/br3-3-vs-cr0-7"><b>Beckenham vs Croydon</b><br>£201,870 less for an equivalent terraced house: same station, similar schools, ~2.02km apart</a>
|
||||||
|
<a href="/cheaper-twin/ha7-2-vs-ha3-0"><b>Stanmore vs Kenton</b><br>£106,920 less for an equivalent semi-detached house: same station, similar schools, ~2.57km apart</a>
|
||||||
|
<a href="/cheaper-twin/ig8-7-vs-ig6-2"><b>Woodford Green vs Barkingside</b><br>£164,070 less for an equivalent terraced house: same station, similar schools, ~2.98km apart</a></div>
|
||||||
|
</section>
|
||||||
|
<p class="note">Contains HM Land Registry data © Crown copyright and database right. Licensed under the Open Government Licence v3.0. Figures are estimates derived from recorded sales and EPC floor areas, aggregated to postcode sector, not valuations, and not address-level.</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<footer><div class="wrap">Sources: HM Land Registry · EPC (DLUHC) · Ofsted · DfT · ONS · Police.uk. Contains HM Land Registry data © Crown copyright and database right. Licensed under the Open Government Licence v3.0.</div></footer>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
82
frontend/public/cheaper-twins/index.html
Normal file
82
frontend/public/cheaper-twins/index.html
Normal file
|
|
@ -0,0 +1,82 @@
|
||||||
|
<!doctype html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
<title>Cheaper twin postcodes in England | Perfect Postcode</title>
|
||||||
|
<meta name="description" content="Neighbouring England postcodes priced apart for the name, not the home. Find the cheaper twin of a pricier area." />
|
||||||
|
<link rel="canonical" href="https://perfect-postcode.co.uk/cheaper-twins" />
|
||||||
|
<style>
|
||||||
|
:root{color-scheme:light dark}
|
||||||
|
*{box-sizing:border-box}
|
||||||
|
body{margin:0;font-family:ui-sans-serif,system-ui,-apple-system,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;
|
||||||
|
color:#0b1220;background:#f7f5f0;line-height:1.6}
|
||||||
|
a{color:#0d9488}
|
||||||
|
.topbar{background:#0b1220;color:#e7ecf3;padding:.7rem 1.25rem;display:flex;justify-content:space-between;align-items:center}
|
||||||
|
.topbar a{color:#2dd4bf;text-decoration:none;font-weight:700}
|
||||||
|
.wrap{max-width:54rem;margin:0 auto;padding:0 1.25rem}
|
||||||
|
.hero{background:linear-gradient(#0b1220,#111a2e);color:#fff;padding:3rem 0 2.5rem}
|
||||||
|
.eyebrow{color:#2dd4bf;font-weight:700;text-transform:uppercase;letter-spacing:.05em;font-size:.8rem;margin:0 0 .5rem}
|
||||||
|
h1{font-size:2rem;line-height:1.15;margin:.2rem 0 .6rem}
|
||||||
|
.hook{color:#cbd5e1;font-size:1.15rem;margin:.5rem 0 1.4rem;max-width:42rem}
|
||||||
|
.big{font-size:3rem;font-weight:800;color:#2dd4bf;margin:.3rem 0}
|
||||||
|
.cta{display:inline-block;margin-top:.4rem;padding:.8rem 1.4rem;border-radius:.6rem;background:#f09a22;color:#0b1220;
|
||||||
|
font-weight:700;text-decoration:none;box-shadow:0 6px 20px rgba(122,57,5,.35)}
|
||||||
|
.cta:hover{background:#df8614}
|
||||||
|
table{width:100%;border-collapse:collapse;margin:1.5rem 0;background:#fff;border-radius:.6rem;overflow:hidden;
|
||||||
|
box-shadow:0 1px 3px rgba(0,0,0,.08)}
|
||||||
|
th,td{padding:.7rem .9rem;text-align:left;border-bottom:1px solid #ece8e0;font-size:.95rem}
|
||||||
|
thead th{background:#0b1220;color:#fff}
|
||||||
|
tbody tr:last-child td{border-bottom:0}
|
||||||
|
.val{font-variant-numeric:tabular-nums;font-weight:600}
|
||||||
|
.cheaper{color:#0d9488}
|
||||||
|
section{margin:2rem 0}
|
||||||
|
h2{font-size:1.3rem;margin:0 0 .6rem}
|
||||||
|
.note{font-size:.82rem;color:#6b7280;border-top:1px solid #e5e1d8;padding-top:1rem;margin-top:2rem}
|
||||||
|
.links{display:grid;gap:.6rem;grid-template-columns:repeat(auto-fit,minmax(15rem,1fr));margin:1rem 0}
|
||||||
|
.links a{display:block;background:#fff;border:1px solid #ece8e0;border-radius:.5rem;padding:.8rem 1rem;text-decoration:none;color:#0b1220}
|
||||||
|
.links a:hover{border-color:#5eead4}
|
||||||
|
.links b{color:#0d9488}
|
||||||
|
.cards{display:grid;gap:1rem;grid-template-columns:repeat(auto-fit,minmax(18rem,1fr))}
|
||||||
|
.card{background:#fff;border:1px solid #ece8e0;border-radius:.6rem;padding:1.1rem;text-decoration:none;color:#0b1220}
|
||||||
|
.card:hover{border-color:#5eead4}
|
||||||
|
.card .n{color:#0d9488;font-weight:800;font-size:1.4rem}
|
||||||
|
footer{color:#6b7280;font-size:.8rem;padding:2rem 0 3rem}
|
||||||
|
@media(prefers-color-scheme:dark){body{background:#0b1220;color:#e7ecf3}table{background:#13203a}
|
||||||
|
th,td{border-color:#223153}.card,.links a{background:#13203a;border-color:#223153;color:#e7ecf3}
|
||||||
|
.note{border-color:#223153;color:#9fb0c3}}
|
||||||
|
</style>
|
||||||
|
<script type="application/ld+json">{"@context": "https://schema.org", "@type": "CollectionPage", "name": "Cheaper twins", "url": "https://perfect-postcode.co.uk/cheaper-twins"}</script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="topbar"><a href="/">Perfect Postcode</a><a href="/?ref=twin">Open the map →</a></div>
|
||||||
|
|
||||||
|
<div class="hero"><div class="wrap">
|
||||||
|
<p class="eyebrow">England</p>
|
||||||
|
<h1>Cheaper twins: pay for the home, not the name</h1>
|
||||||
|
<p class="hook">Pairs of neighbouring England postcodes that share a station, school catchment and build era,
|
||||||
|
but sell thousands apart because one name got bid up. Built from 15 verified pairs.</p>
|
||||||
|
<a class="cta" href="/?ref=twins-hub">Find your cheaper twin on the map →</a>
|
||||||
|
</div></div>
|
||||||
|
<div class="wrap">
|
||||||
|
<section><div class="cards"><a class="card" href="/cheaper-twin/br3-3-vs-cr0-7"><div class="n">31%</div><div>Beckenham vs Croydon</div></a>
|
||||||
|
<a class="card" href="/cheaper-twin/ha7-2-vs-ha3-0"><div class="n">17%</div><div>Stanmore vs Kenton</div></a>
|
||||||
|
<a class="card" href="/cheaper-twin/ig8-7-vs-ig6-2"><div class="n">26%</div><div>Woodford Green vs Barkingside</div></a>
|
||||||
|
<a class="card" href="/cheaper-twin/l16-7-vs-l14-6"><div class="n">30%</div><div>Childwall vs Broadgreen</div></a>
|
||||||
|
<a class="card" href="/cheaper-twin/m40-5-vs-m9-4"><div class="n">42%</div><div>Newton Heath vs Harpurhey</div></a>
|
||||||
|
<a class="card" href="/cheaper-twin/rm14-2-vs-rm12-5"><div class="n">20%</div><div>Upminster vs Hornchurch</div></a>
|
||||||
|
<a class="card" href="/cheaper-twin/se28-8-vs-da18-4"><div class="n">30%</div><div>SE28 8 vs DA18 4</div></a>
|
||||||
|
<a class="card" href="/cheaper-twin/sw1x-8-vs-sw7-2"><div class="n">42%</div><div>SW1X 8 vs SW7 2</div></a>
|
||||||
|
<a class="card" href="/cheaper-twin/tw12-3-vs-kt8-1"><div class="n">19%</div><div>Hampton vs East Molesey</div></a>
|
||||||
|
<a class="card" href="/cheaper-twin/tw2-7-vs-tw3-2"><div class="n">19%</div><div>Twickenham vs Hounslow</div></a>
|
||||||
|
<a class="card" href="/cheaper-twin/w1j-7-vs-sw7-3"><div class="n">41%</div><div>W1J 7 vs SW7 3</div></a>
|
||||||
|
<a class="card" href="/cheaper-twin/w1j-8-vs-sw1a-2"><div class="n">37%</div><div>W1J 8 vs SW1A 2</div></a>
|
||||||
|
<a class="card" href="/cheaper-twin/w1k-2-vs-sw1x-0"><div class="n">32%</div><div>W1K 2 vs SW1X 0</div></a>
|
||||||
|
<a class="card" href="/cheaper-twin/w1u-4-vs-nw1-4"><div class="n">43%</div><div>Marylebone vs Camden</div></a>
|
||||||
|
<a class="card" href="/cheaper-twin/wc2a-2-vs-ec2a-2"><div class="n">43%</div><div>WC2A 2 vs EC2A 2</div></a></div></section>
|
||||||
|
<p class="note">Contains HM Land Registry data © Crown copyright and database right. Licensed under the Open Government Licence v3.0.</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<footer><div class="wrap">Sources: HM Land Registry · EPC (DLUHC) · Ofsted · DfT · ONS · Police.uk. Contains HM Land Registry data © Crown copyright and database right. Licensed under the Open Government Licence v3.0.</div></footer>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
@ -80,4 +80,91 @@
|
||||||
<changefreq>yearly</changefreq>
|
<changefreq>yearly</changefreq>
|
||||||
<priority>0.3</priority>
|
<priority>0.3</priority>
|
||||||
</url>
|
</url>
|
||||||
|
<!-- DATA_PAGES_START -->
|
||||||
|
<url>
|
||||||
|
<loc>https://perfect-postcode.co.uk/cheaper-twin/br3-3-vs-cr0-7</loc>
|
||||||
|
<changefreq>monthly</changefreq>
|
||||||
|
<priority>0.7</priority>
|
||||||
|
</url>
|
||||||
|
<url>
|
||||||
|
<loc>https://perfect-postcode.co.uk/cheaper-twin/ha7-2-vs-ha3-0</loc>
|
||||||
|
<changefreq>monthly</changefreq>
|
||||||
|
<priority>0.7</priority>
|
||||||
|
</url>
|
||||||
|
<url>
|
||||||
|
<loc>https://perfect-postcode.co.uk/cheaper-twin/ig8-7-vs-ig6-2</loc>
|
||||||
|
<changefreq>monthly</changefreq>
|
||||||
|
<priority>0.7</priority>
|
||||||
|
</url>
|
||||||
|
<url>
|
||||||
|
<loc>https://perfect-postcode.co.uk/cheaper-twin/l16-7-vs-l14-6</loc>
|
||||||
|
<changefreq>monthly</changefreq>
|
||||||
|
<priority>0.7</priority>
|
||||||
|
</url>
|
||||||
|
<url>
|
||||||
|
<loc>https://perfect-postcode.co.uk/cheaper-twin/m40-5-vs-m9-4</loc>
|
||||||
|
<changefreq>monthly</changefreq>
|
||||||
|
<priority>0.7</priority>
|
||||||
|
</url>
|
||||||
|
<url>
|
||||||
|
<loc>https://perfect-postcode.co.uk/cheaper-twin/rm14-2-vs-rm12-5</loc>
|
||||||
|
<changefreq>monthly</changefreq>
|
||||||
|
<priority>0.7</priority>
|
||||||
|
</url>
|
||||||
|
<url>
|
||||||
|
<loc>https://perfect-postcode.co.uk/cheaper-twin/se28-8-vs-da18-4</loc>
|
||||||
|
<changefreq>monthly</changefreq>
|
||||||
|
<priority>0.7</priority>
|
||||||
|
</url>
|
||||||
|
<url>
|
||||||
|
<loc>https://perfect-postcode.co.uk/cheaper-twin/sw1x-8-vs-sw7-2</loc>
|
||||||
|
<changefreq>monthly</changefreq>
|
||||||
|
<priority>0.7</priority>
|
||||||
|
</url>
|
||||||
|
<url>
|
||||||
|
<loc>https://perfect-postcode.co.uk/cheaper-twin/tw12-3-vs-kt8-1</loc>
|
||||||
|
<changefreq>monthly</changefreq>
|
||||||
|
<priority>0.7</priority>
|
||||||
|
</url>
|
||||||
|
<url>
|
||||||
|
<loc>https://perfect-postcode.co.uk/cheaper-twin/tw2-7-vs-tw3-2</loc>
|
||||||
|
<changefreq>monthly</changefreq>
|
||||||
|
<priority>0.7</priority>
|
||||||
|
</url>
|
||||||
|
<url>
|
||||||
|
<loc>https://perfect-postcode.co.uk/cheaper-twin/w1j-7-vs-sw7-3</loc>
|
||||||
|
<changefreq>monthly</changefreq>
|
||||||
|
<priority>0.7</priority>
|
||||||
|
</url>
|
||||||
|
<url>
|
||||||
|
<loc>https://perfect-postcode.co.uk/cheaper-twin/w1j-8-vs-sw1a-2</loc>
|
||||||
|
<changefreq>monthly</changefreq>
|
||||||
|
<priority>0.7</priority>
|
||||||
|
</url>
|
||||||
|
<url>
|
||||||
|
<loc>https://perfect-postcode.co.uk/cheaper-twin/w1k-2-vs-sw1x-0</loc>
|
||||||
|
<changefreq>monthly</changefreq>
|
||||||
|
<priority>0.7</priority>
|
||||||
|
</url>
|
||||||
|
<url>
|
||||||
|
<loc>https://perfect-postcode.co.uk/cheaper-twin/w1u-4-vs-nw1-4</loc>
|
||||||
|
<changefreq>monthly</changefreq>
|
||||||
|
<priority>0.7</priority>
|
||||||
|
</url>
|
||||||
|
<url>
|
||||||
|
<loc>https://perfect-postcode.co.uk/cheaper-twin/wc2a-2-vs-ec2a-2</loc>
|
||||||
|
<changefreq>monthly</changefreq>
|
||||||
|
<priority>0.7</priority>
|
||||||
|
</url>
|
||||||
|
<url>
|
||||||
|
<loc>https://perfect-postcode.co.uk/square-metres-per-100k</loc>
|
||||||
|
<changefreq>monthly</changefreq>
|
||||||
|
<priority>0.7</priority>
|
||||||
|
</url>
|
||||||
|
<url>
|
||||||
|
<loc>https://perfect-postcode.co.uk/cheaper-twins</loc>
|
||||||
|
<changefreq>monthly</changefreq>
|
||||||
|
<priority>0.7</priority>
|
||||||
|
</url>
|
||||||
|
<!-- DATA_PAGES_END -->
|
||||||
</urlset>
|
</urlset>
|
||||||
|
|
|
||||||
76
frontend/public/square-metres-per-100k/index.html
Normal file
76
frontend/public/square-metres-per-100k/index.html
Normal file
|
|
@ -0,0 +1,76 @@
|
||||||
|
<!doctype html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8" />
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
|
<title>How many square metres £100,000 buys across England | Perfect Postcode</title>
|
||||||
|
<meta name="description" content="£100k buys ~152 m² of floor space in BD21 3 but only ~3 m² in Mayfair (W1K 2)" />
|
||||||
|
<link rel="canonical" href="https://perfect-postcode.co.uk/square-metres-per-100k" />
|
||||||
|
<style>
|
||||||
|
:root{color-scheme:light dark}
|
||||||
|
*{box-sizing:border-box}
|
||||||
|
body{margin:0;font-family:ui-sans-serif,system-ui,-apple-system,"Segoe UI",Roboto,Helvetica,Arial,sans-serif;
|
||||||
|
color:#0b1220;background:#f7f5f0;line-height:1.6}
|
||||||
|
a{color:#0d9488}
|
||||||
|
.topbar{background:#0b1220;color:#e7ecf3;padding:.7rem 1.25rem;display:flex;justify-content:space-between;align-items:center}
|
||||||
|
.topbar a{color:#2dd4bf;text-decoration:none;font-weight:700}
|
||||||
|
.wrap{max-width:54rem;margin:0 auto;padding:0 1.25rem}
|
||||||
|
.hero{background:linear-gradient(#0b1220,#111a2e);color:#fff;padding:3rem 0 2.5rem}
|
||||||
|
.eyebrow{color:#2dd4bf;font-weight:700;text-transform:uppercase;letter-spacing:.05em;font-size:.8rem;margin:0 0 .5rem}
|
||||||
|
h1{font-size:2rem;line-height:1.15;margin:.2rem 0 .6rem}
|
||||||
|
.hook{color:#cbd5e1;font-size:1.15rem;margin:.5rem 0 1.4rem;max-width:42rem}
|
||||||
|
.big{font-size:3rem;font-weight:800;color:#2dd4bf;margin:.3rem 0}
|
||||||
|
.cta{display:inline-block;margin-top:.4rem;padding:.8rem 1.4rem;border-radius:.6rem;background:#f09a22;color:#0b1220;
|
||||||
|
font-weight:700;text-decoration:none;box-shadow:0 6px 20px rgba(122,57,5,.35)}
|
||||||
|
.cta:hover{background:#df8614}
|
||||||
|
table{width:100%;border-collapse:collapse;margin:1.5rem 0;background:#fff;border-radius:.6rem;overflow:hidden;
|
||||||
|
box-shadow:0 1px 3px rgba(0,0,0,.08)}
|
||||||
|
th,td{padding:.7rem .9rem;text-align:left;border-bottom:1px solid #ece8e0;font-size:.95rem}
|
||||||
|
thead th{background:#0b1220;color:#fff}
|
||||||
|
tbody tr:last-child td{border-bottom:0}
|
||||||
|
.val{font-variant-numeric:tabular-nums;font-weight:600}
|
||||||
|
.cheaper{color:#0d9488}
|
||||||
|
section{margin:2rem 0}
|
||||||
|
h2{font-size:1.3rem;margin:0 0 .6rem}
|
||||||
|
.note{font-size:.82rem;color:#6b7280;border-top:1px solid #e5e1d8;padding-top:1rem;margin-top:2rem}
|
||||||
|
.links{display:grid;gap:.6rem;grid-template-columns:repeat(auto-fit,minmax(15rem,1fr));margin:1rem 0}
|
||||||
|
.links a{display:block;background:#fff;border:1px solid #ece8e0;border-radius:.5rem;padding:.8rem 1rem;text-decoration:none;color:#0b1220}
|
||||||
|
.links a:hover{border-color:#5eead4}
|
||||||
|
.links b{color:#0d9488}
|
||||||
|
.cards{display:grid;gap:1rem;grid-template-columns:repeat(auto-fit,minmax(18rem,1fr))}
|
||||||
|
.card{background:#fff;border:1px solid #ece8e0;border-radius:.6rem;padding:1.1rem;text-decoration:none;color:#0b1220}
|
||||||
|
.card:hover{border-color:#5eead4}
|
||||||
|
.card .n{color:#0d9488;font-weight:800;font-size:1.4rem}
|
||||||
|
footer{color:#6b7280;font-size:.8rem;padding:2rem 0 3rem}
|
||||||
|
@media(prefers-color-scheme:dark){body{background:#0b1220;color:#e7ecf3}table{background:#13203a}
|
||||||
|
th,td{border-color:#223153}.card,.links a{background:#13203a;border-color:#223153;color:#e7ecf3}
|
||||||
|
.note{border-color:#223153;color:#9fb0c3}}
|
||||||
|
</style>
|
||||||
|
<script type="application/ld+json">{"@context": "https://schema.org", "@type": "BreadcrumbList", "itemListElement": [{"@type": "ListItem", "position": 1, "name": "Home", "item": "https://perfect-postcode.co.uk/"}, {"@type": "ListItem", "position": 2, "name": "Cheaper twins", "item": "https://perfect-postcode.co.uk/cheaper-twins"}, {"@type": "ListItem", "position": 3, "name": "How many square metres \u00a3100,000 buys across England", "item": "https://perfect-postcode.co.uk/square-metres-per-100k"}]}</script>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="topbar"><a href="/">Perfect Postcode</a><a href="/?ref=twin">Open the map →</a></div>
|
||||||
|
|
||||||
|
<div class="hero"><div class="wrap">
|
||||||
|
<p class="eyebrow">England · value index</p>
|
||||||
|
<h1>How many square metres £100,000 buys across England</h1>
|
||||||
|
<div class="big">152 m² vs 3 m²</div>
|
||||||
|
<p class="hook">£100k buys ~152 m² of floor space in BD21 3 but only ~3 m² in Mayfair (W1K 2)</p>
|
||||||
|
<a class="cta" href="https://perfect-postcode.co.uk/?zoom=6&filter=Est.%20price%20per%20sqm:0:4000">Explore the value map →</a>
|
||||||
|
</div></div>
|
||||||
|
<div class="wrap">
|
||||||
|
<table><thead><tr><th>Sector</th><th>Est. £/m²</th><th>m² for £100k</th><th>N</th></tr></thead><tbody>
|
||||||
|
<tr><td>BD21 3 (best value)</td><td class='val'>£660</td><td class='val cheaper'>152 m²</td><td class='val'>1,377</td></tr>
|
||||||
|
<tr><td>W1K 2 (dearest)</td><td class='val'>£34,362</td><td class='val'>3 m²</td><td class='val'>591</td></tr>
|
||||||
|
</tbody></table>
|
||||||
|
<section><h2>How we worked this out</h2><p>100000 ÷ median estimated £/m², per England postcode sector with sufficient sales.</p></section>
|
||||||
|
<section><h2>More</h2><div class="links">
|
||||||
|
<a href="/cheaper-twins"><b>Cheaper twins →</b><br>Pairs of areas priced apart for the name, not the home.</a>
|
||||||
|
<a href="/postcode-checker"><b>Postcode checker →</b><br>Everything known about any postcode.</a>
|
||||||
|
</div></section>
|
||||||
|
<p class="note">Contains HM Land Registry data © Crown copyright and database right. Licensed under the Open Government Licence v3.0.</p>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<footer><div class="wrap">Sources: HM Land Registry · EPC (DLUHC) · Ofsted · DfT · ONS · Police.uk. Contains HM Land Registry data © Crown copyright and database right. Licensed under the Open Government Licence v3.0.</div></footer>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|
@ -14,6 +14,7 @@ const de: Translations = {
|
||||||
},
|
},
|
||||||
// ── Common ──────────────────────────────────────────
|
// ── Common ──────────────────────────────────────────
|
||||||
common: {
|
common: {
|
||||||
|
retry: 'Erneut versuchen',
|
||||||
save: 'Speichern',
|
save: 'Speichern',
|
||||||
update: 'Aktualisieren',
|
update: 'Aktualisieren',
|
||||||
cancel: 'Abbrechen',
|
cancel: 'Abbrechen',
|
||||||
|
|
@ -93,7 +94,7 @@ const de: Translations = {
|
||||||
'Exportiere alle auf der Karte sichtbaren Postcodes, die deinen aktuellen Filtern entsprechen.',
|
'Exportiere alle auf der Karte sichtbaren Postcodes, die deinen aktuellen Filtern entsprechen.',
|
||||||
modeList: 'Postcode-Liste',
|
modeList: 'Postcode-Liste',
|
||||||
modeListHint:
|
modeListHint:
|
||||||
'Füge deine Postcodes einzeln hinzu – Schreibweise und Leerzeichen werden für dich korrigiert.',
|
'Füge deine Postcodes einzeln hinzu. Schreibweise und Leerzeichen werden für dich korrigiert.',
|
||||||
listLabel: 'Postcodes',
|
listLabel: 'Postcodes',
|
||||||
listPlaceholder: 'z. B. SW1A 1AA',
|
listPlaceholder: 'z. B. SW1A 1AA',
|
||||||
addRow: 'Postcode hinzufügen',
|
addRow: 'Postcode hinzufügen',
|
||||||
|
|
@ -104,6 +105,7 @@ const de: Translations = {
|
||||||
|
|
||||||
// ── User Menu ──────────────────────────────────────
|
// ── User Menu ──────────────────────────────────────
|
||||||
userMenu: {
|
userMenu: {
|
||||||
|
accountMenu: 'Kontomenü',
|
||||||
fullAccess: 'Voller Zugriff',
|
fullAccess: 'Voller Zugriff',
|
||||||
demo: 'Demo',
|
demo: 'Demo',
|
||||||
themeLight: 'Design: hell',
|
themeLight: 'Design: hell',
|
||||||
|
|
@ -505,9 +507,9 @@ const de: Translations = {
|
||||||
'Wie Konto- und gespeicherte Suchdaten im Produkt behandelt werden.',
|
'Wie Konto- und gespeicherte Suchdaten im Produkt behandelt werden.',
|
||||||
'Compare Bristol postcodes': 'Bristol-Postcodes vergleichen',
|
'Compare Bristol postcodes': 'Bristol-Postcodes vergleichen',
|
||||||
'Trust and coverage': 'Vertrauen und Abdeckung',
|
'Trust and coverage': 'Vertrauen und Abdeckung',
|
||||||
'Perfect Postcode data sources and coverage': 'Perfect Postcode – Datenquellen und Abdeckung',
|
'Perfect Postcode data sources and coverage': 'Perfect Postcode: Datenquellen und Abdeckung',
|
||||||
'Perfect Postcode data sources - Property, schools, commute and local context':
|
'Perfect Postcode data sources - Property, schools, commute and local context':
|
||||||
'Perfect Postcode – Datenquellen: Immobilien, Schulen, Pendelweg und lokaler Kontext',
|
'Perfect Postcode Datenquellen: Immobilien, Schulen, Pendelweg und lokaler Kontext',
|
||||||
'Review the public and official datasets used by Perfect Postcode, including property prices, EPC, schools, crime, broadband, noise and travel-time context.':
|
'Review the public and official datasets used by Perfect Postcode, including property prices, EPC, schools, crime, broadband, noise and travel-time context.':
|
||||||
'Prüfe die von Perfect Postcode verwendeten öffentlichen und offiziellen Datensätze, einschließlich Immobilienpreise, EPC, Schulen, Kriminalität, Breitband, Lärm und Fahrzeitkontext.',
|
'Prüfe die von Perfect Postcode verwendeten öffentlichen und offiziellen Datensätze, einschließlich Immobilienpreise, EPC, Schulen, Kriminalität, Breitband, Lärm und Fahrzeitkontext.',
|
||||||
'Perfect Postcode combines property, transport, education, environment, and local-service datasets so buyers can compare postcodes consistently. This page explains what the data is for and where it should be verified.':
|
'Perfect Postcode combines property, transport, education, environment, and local-service datasets so buyers can compare postcodes consistently. This page explains what the data is for and where it should be verified.':
|
||||||
|
|
@ -607,12 +609,24 @@ const de: Translations = {
|
||||||
|
|
||||||
// ── Auth Modal ─────────────────────────────────────
|
// ── Auth Modal ─────────────────────────────────────
|
||||||
auth: {
|
auth: {
|
||||||
|
errorRateLimited:
|
||||||
|
'Zu viele Versuche. Bitte warten Sie eine Minute und versuchen Sie es erneut.',
|
||||||
|
errorNetwork:
|
||||||
|
'Server nicht erreichbar. Überprüfen Sie Ihre Verbindung und versuchen Sie es erneut.',
|
||||||
|
errorEmailTaken: 'Ein Konto mit dieser E-Mail-Adresse existiert bereits.',
|
||||||
|
errorPasswordWeak: 'Das Passwort muss mindestens 8 Zeichen lang sein.',
|
||||||
|
errorEmailInvalid: 'Bitte geben Sie eine gültige E-Mail-Adresse ein.',
|
||||||
|
errorInvalidCredentials: 'E-Mail oder Passwort ist falsch.',
|
||||||
|
logInInstead: 'Stattdessen anmelden',
|
||||||
|
accountCreatedPleaseLogIn: 'Konto erstellt. Bitte melden Sie sich an, um fortzufahren.',
|
||||||
|
accountCreatedRateLimited:
|
||||||
|
'Konto erstellt. Gerade zu viele Versuche. Bitte warten Sie einen Moment und melden Sie sich dann an.',
|
||||||
logIn: 'Anmelden',
|
logIn: 'Anmelden',
|
||||||
createAccount: 'Konto erstellen',
|
createAccount: 'Konto erstellen',
|
||||||
resetPassword: 'Passwort zurücksetzen',
|
resetPassword: 'Passwort zurücksetzen',
|
||||||
valueProp: 'Speichere Suchen, merke Immobilien und erstelle eine Shortlist passender Gebiete.',
|
valueProp: 'Speichere Suchen, merke Immobilien und erstelle eine Shortlist passender Gebiete.',
|
||||||
dashboardActionsValueProp:
|
dashboardActionsValueProp:
|
||||||
'Erstelle ein kostenloses Konto, um deine Suchen zu speichern, zu teilen und zu exportieren — kostenlos, keine Kreditkarte erforderlich.',
|
'Erstelle ein kostenloses Konto, um deine Suchen zu speichern, zu teilen und zu exportieren, kostenlos, keine Kreditkarte erforderlich.',
|
||||||
continueWithGoogle: 'Weiter mit Google',
|
continueWithGoogle: 'Weiter mit Google',
|
||||||
email: 'E-Mail',
|
email: 'E-Mail',
|
||||||
emailPlaceholder: 'name@beispiel.de',
|
emailPlaceholder: 'name@beispiel.de',
|
||||||
|
|
@ -639,12 +653,12 @@ const de: Translations = {
|
||||||
'Du hast alle 5 Filter deines kostenlosen Kontos genutzt. Erhalte lebenslangen Zugang, um unbegrenzt Filter über jeden Postcode und jede Nachbarschaft in England hinweg zu kombinieren. Einmal zahlen, für immer nutzen.',
|
'Du hast alle 5 Filter deines kostenlosen Kontos genutzt. Erhalte lebenslangen Zugang, um unbegrenzt Filter über jeden Postcode und jede Nachbarschaft in England hinweg zu kombinieren. Einmal zahlen, für immer nutzen.',
|
||||||
titleRegister: 'Kostenloses Konto erstellen',
|
titleRegister: 'Kostenloses Konto erstellen',
|
||||||
descriptionRegister:
|
descriptionRegister:
|
||||||
'Kostenlose Konten schalten bis zu 5 Filter sowie Speichern, Teilen und Exportieren frei — keine Kreditkarte erforderlich. Willst du unbegrenzte Filter für ganz England? Wähle den lebenslangen Zugang.',
|
'Kostenlose Konten schalten bis zu 5 Filter sowie Speichern, Teilen und Exportieren frei. Keine Kreditkarte erforderlich. Willst du unbegrenzte Filter für ganz England? Wähle den lebenslangen Zugang.',
|
||||||
descriptionSharedRegister:
|
descriptionSharedRegister:
|
||||||
'Das ist eine geteilte Suche. Erstelle ein kostenloses Konto, um deine eigene mit bis zu 5 Filtern zu erstellen und zu speichern, teilen & exportieren — oder wähle den lebenslangen Zugang für unbegrenzte Filter.',
|
'Das ist eine geteilte Suche. Erstelle ein kostenloses Konto, um deine eigene mit bis zu 5 Filtern zu erstellen und zu speichern, teilen & exportieren, oder wähle den lebenslangen Zugang für unbegrenzte Filter.',
|
||||||
registerFree: 'Kostenloses Konto erstellen',
|
registerFree: 'Kostenloses Konto erstellen',
|
||||||
lifetimeUpsell: 'Willst du unbegrenzte Filter?',
|
lifetimeUpsell: 'Willst du unbegrenzte Filter?',
|
||||||
goLifetime: 'Lebenslangen Zugang erhalten — {{price}}',
|
goLifetime: 'Lebenslangen Zugang erhalten: {{price}}',
|
||||||
free: 'Kostenlos',
|
free: 'Kostenlos',
|
||||||
freeForEarly: 'Kostenlos für Frühnutzer. Keine Kreditkarte erforderlich.',
|
freeForEarly: 'Kostenlos für Frühnutzer. Keine Kreditkarte erforderlich.',
|
||||||
oneTimePayment: 'Einmalzahlung. Lebenslanger Zugang.',
|
oneTimePayment: 'Einmalzahlung. Lebenslanger Zugang.',
|
||||||
|
|
@ -696,7 +710,7 @@ const de: Translations = {
|
||||||
registerPrompt:
|
registerPrompt:
|
||||||
'Erstelle ein kostenloses Konto, um bis zu 5 Filter zu kombinieren und deine Suchen zu speichern, zu teilen & zu exportieren.',
|
'Erstelle ein kostenloses Konto, um bis zu 5 Filter zu kombinieren und deine Suchen zu speichern, zu teilen & zu exportieren.',
|
||||||
registerSubPrompt:
|
registerSubPrompt:
|
||||||
'Kostenlos — keine Kreditkarte erforderlich. Unbegrenzte Filter mit lebenslangem Zugang.',
|
'Kostenlos, keine Kreditkarte erforderlich. Unbegrenzte Filter mit lebenslangem Zugang.',
|
||||||
registerCta: 'Kostenloses Konto erstellen',
|
registerCta: 'Kostenloses Konto erstellen',
|
||||||
oneTimeLifetime: 'Einmalzahlung, lebenslanger Zugang.',
|
oneTimeLifetime: 'Einmalzahlung, lebenslanger Zugang.',
|
||||||
upgradeToFullMap: 'Auf die vollständige Karte upgraden',
|
upgradeToFullMap: 'Auf die vollständige Karte upgraden',
|
||||||
|
|
@ -738,6 +752,11 @@ const de: Translations = {
|
||||||
crimeType: 'Deliktart',
|
crimeType: 'Deliktart',
|
||||||
qualificationLevel: 'Qualifikationsniveau',
|
qualificationLevel: 'Qualifikationsniveau',
|
||||||
tenureType: 'Wohnform',
|
tenureType: 'Wohnform',
|
||||||
|
councilType: 'Art der Kommunalwohnung',
|
||||||
|
councilStatus: 'Art',
|
||||||
|
councilCurrent: 'Aktuell',
|
||||||
|
councilEx: 'Ehemalig',
|
||||||
|
councilBoth: 'Beide',
|
||||||
crimeWindow: 'Zeitraum',
|
crimeWindow: 'Zeitraum',
|
||||||
crimeWindow7y: '7 Jahre',
|
crimeWindow7y: '7 Jahre',
|
||||||
crimeWindow2y: '2 Jahre',
|
crimeWindow2y: '2 Jahre',
|
||||||
|
|
@ -859,8 +878,11 @@ const de: Translations = {
|
||||||
},
|
},
|
||||||
actualListings: {
|
actualListings: {
|
||||||
label: 'Inserate',
|
label: 'Inserate',
|
||||||
show: 'Tatsächliche Inserate anzeigen',
|
modes: {
|
||||||
hide: 'Tatsächliche Inserate ausblenden',
|
new: 'Neubauten',
|
||||||
|
nonNew: 'Bestand',
|
||||||
|
hint: '„Neubauten“ zeigt Neubauprojekte; „Bestand“ zeigt Wiederverkäufe und andere Inserate.',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
poi: { zoomInToSeeDetails: 'Für Details hineinzoomen' },
|
poi: { zoomInToSeeDetails: 'Für Details hineinzoomen' },
|
||||||
},
|
},
|
||||||
|
|
@ -887,6 +909,7 @@ const de: Translations = {
|
||||||
historyTitle: 'Historie',
|
historyTitle: 'Historie',
|
||||||
historySale: 'Verkauf',
|
historySale: 'Verkauf',
|
||||||
historyBuilt: 'Baujahr',
|
historyBuilt: 'Baujahr',
|
||||||
|
historyNewBuild: 'Neubau',
|
||||||
tenureOwnerOccupied: 'Eigennutzung',
|
tenureOwnerOccupied: 'Eigennutzung',
|
||||||
tenureRentedPrivate: 'Privat vermietet',
|
tenureRentedPrivate: 'Privat vermietet',
|
||||||
tenureRentedSocial: 'Sozialwohnung',
|
tenureRentedSocial: 'Sozialwohnung',
|
||||||
|
|
@ -1002,20 +1025,22 @@ const de: Translations = {
|
||||||
|
|
||||||
// ── Home Page ──────────────────────────────────────
|
// ── Home Page ──────────────────────────────────────
|
||||||
home: {
|
home: {
|
||||||
heroEyebrow: 'Für Käufer, die fragen: „Wo soll ich überhaupt suchen?“',
|
heroEyebrow: 'Für Käufer, die nicht für den Ruf eines Postcodes zu viel zahlen wollen',
|
||||||
heroTitle1: 'Finde die Postcodes',
|
heroTitle1: 'Finde den',
|
||||||
heroTitle2: 'die zu deinem Leben passen',
|
heroTitle2: 'Geheimtipp-Postcode',
|
||||||
heroTitle3: 'Nicht nur die Gegenden, die du schon kennst.',
|
heroTitle3: 'Gleiche Schulen, gleicher Pendelweg, und still günstiger.',
|
||||||
heroSubtitle:
|
heroSubtitle:
|
||||||
'Von Londoner Stadtteilen über Pendlerorte bis zu regionalen Städten: England hat zu viele Orte, um sie einzeln zu recherchieren.',
|
'Zwei Straßen können dieselbe Schule, denselben Bahnhof und dasselbe Baujahr teilen und sich am Ende um Zehntausende im Preis unterscheiden. Eine davon ist falsch bepreist. Wir finden heraus, welche.',
|
||||||
heroDescription:
|
heroDescription:
|
||||||
'Lege Budget, Pendelzeit, Schulen, Sicherheit, Lärm, Breitband und Lebensstil fest. Perfect Postcode scannt Englands Postcodes und zeigt Orte, die wirklich passen, auch Gegenden, die du nie in ein Immobilienportal eingegeben hättest.',
|
'Lege dein Budget und deine unverzichtbaren Kriterien fest. Perfect Postcode bewertet jeden Postcode in England danach, was jedes Pfund wirklich bringt (Wohnfläche, Schulen, Pendelweg und Sicherheit) mit den Belegen hinter jeder Empfehlung.',
|
||||||
exploreTheMap: 'Passende Postcodes finden',
|
exploreTheMap: 'Meinen Geheimtipp-Postcode finden',
|
||||||
seeTheDifference: 'So funktioniert es',
|
seeTheDifference: 'Einen echten Geheimtipp ansehen',
|
||||||
|
freeToExplore: 'Erkunde die Live-Karte kostenlos, ohne Anmeldung, ohne Karte.',
|
||||||
|
dataSourcesLabel: 'Basiert auf offiziellen Daten',
|
||||||
|
dataSources: 'Land Registry · ONS · Ofsted · DfT · Ordnance Survey · Police.uk',
|
||||||
productDemoLabel: 'Perfect Postcode-Produktdemo',
|
productDemoLabel: 'Perfect Postcode-Produktdemo',
|
||||||
playProductDemo: 'Perfect Postcode-Produktdemo abspielen',
|
playProductDemo: 'Perfect Postcode-Produktdemo abspielen',
|
||||||
scrollToProductDemo: 'Zur Produktdemo scrollen',
|
scrollToProductDemo: 'Zur Produktdemo scrollen',
|
||||||
showcaseHeader: 'So funktioniert es',
|
|
||||||
showcaseContext: 'So funktioniert Perfect Postcode',
|
showcaseContext: 'So funktioniert Perfect Postcode',
|
||||||
showcaseFeaturePriceShort: 'Preis',
|
showcaseFeaturePriceShort: 'Preis',
|
||||||
showcaseFeatureNoiseShort: 'Lärm',
|
showcaseFeatureNoiseShort: 'Lärm',
|
||||||
|
|
@ -1030,94 +1055,96 @@ const de: Translations = {
|
||||||
showcaseNearby: '{{value}} in der Nähe',
|
showcaseNearby: '{{value}} in der Nähe',
|
||||||
showcasePoliticalVoteShare: 'Politischer Stimmenanteil',
|
showcasePoliticalVoteShare: 'Politischer Stimmenanteil',
|
||||||
showcaseGe2024: 'Unterhauswahl 2024',
|
showcaseGe2024: 'Unterhauswahl 2024',
|
||||||
showcaseLotsMore: '...und vieles mehr',
|
showcaseLotsMore: '… und vieles mehr',
|
||||||
showcaseMinutes: '{{count}} Min.',
|
showcaseMinutes: '{{count}} Min.',
|
||||||
showcaseSendShortlist: 'Shortlist senden',
|
showcaseSendShortlist: 'Shortlist senden',
|
||||||
showcaseDownloadXlsx: '.xlsx herunterladen',
|
showcaseDownloadXlsx: '.xlsx herunterladen',
|
||||||
showcaseTopThree: 'Top 3',
|
showcaseTopThree: 'Top 3',
|
||||||
showcaseScoutBullet1: 'Geh durch die Straßen, bevor die Inseratsuche deine Optionen verengt.',
|
showcaseScoutBullet1:
|
||||||
|
'Geh durch die Straßen des Postcodes, der seinen teureren Nachbarn schlägt.',
|
||||||
showcaseScoutBullet2:
|
showcaseScoutBullet2:
|
||||||
'Teste den Pendelweg von einer echten Haustür, nicht nur anhand eines Borough-Namens.',
|
'Teste den Pendelweg von einer echten Haustür aus, nicht anhand eines Borough-Namens.',
|
||||||
showcaseScoutBullet3: 'Vergleiche Besichtigungen mit belastbaren Daten im Rücken.',
|
showcaseScoutBullet3: 'Vergleiche Besichtigungen mit den Belegen schon in der Hand.',
|
||||||
showcaseStep1Tab: 'Filtern',
|
showcaseStep1Tab: 'Filtern',
|
||||||
showcaseStep1Title: 'Aus vagen Wünschen eine präzise Suche machen',
|
showcaseStep1Title: 'Aus vagen Wünschen eine präzise Suche machen',
|
||||||
showcaseStep1Body:
|
showcaseStep1Body:
|
||||||
'Lege fest, was zählt, und sieh genau, wie viele unpassende Postcodes jede Anforderung aus deiner Suche ausschließt.',
|
'Lege fest, was zählt, und sieh genau, wie viele unpassende Postcodes jede Anforderung aus deiner Suche ausschließt.',
|
||||||
showcaseStep1Chip1: 'Ruhige Straßen',
|
|
||||||
showcaseStep1Chip2: 'Top-Grundschulen',
|
|
||||||
showcaseStep1Chip3: 'Unter £500k',
|
|
||||||
showcaseStep1VennCenter: 'Postcodes, die alle drei erfüllen',
|
|
||||||
showcaseStep2Tab: 'Abgleichen',
|
showcaseStep2Tab: 'Abgleichen',
|
||||||
showcaseStep2Title: 'Lass die Karte Orte zeigen, die du nicht eingegeben hättest',
|
showcaseStep2Title: 'Sieh, wie die unterbewerteten Postcodes aufleuchten',
|
||||||
showcaseStep2Body:
|
showcaseStep2Body:
|
||||||
'Durchsuche England nach Passung, statt mit vertrauten Gebietsnamen zu beginnen. Übersehene Ecken werden sichtbar, bevor Immobilienportale deine Suche einengen.',
|
'Sortiere England nach Preis-Leistung, nicht nach Gebietsnamen, die du schon kennst. Die unterbewerteten Ecken (stark bei Preis pro Quadratmeter, Schulen und Pendelweg) steigen nach oben.',
|
||||||
showcaseStep2Region: 'Großraum London',
|
showcaseStep2Region: 'Großraum London',
|
||||||
showcaseStep2Sources: 'Land Registry · ONS · Ofsted · DfT',
|
showcaseStep2Sources: 'Land Registry · ONS · Ofsted · DfT',
|
||||||
showcaseStep2ClustersLabel: 'Passende Cluster',
|
|
||||||
showcaseStep3Tab: 'Prüfen',
|
showcaseStep3Tab: 'Prüfen',
|
||||||
showcaseStep3Title: 'Prüfen, warum ein Postcode passt',
|
showcaseStep3Title: 'Prüfen, warum es ein Postcode in die Auswahl geschafft hat',
|
||||||
showcaseStep3Body:
|
showcaseStep3Body:
|
||||||
'Öffne ein passendes Gebiet und prüfe Preise, Sicherheit, Schulen, Breitband und Kompromisse in einem Bereich, bevor du ein Wochenende dort verbringst.',
|
'Öffne ein passendes Gebiet und prüfe Preise, Sicherheit, Schulen, Breitband und Kompromisse in einem Bereich, bevor du ein Wochenende dort verbringst.',
|
||||||
showcaseStep3HeaderArea: 'Dein perfekter Postcode',
|
showcaseStep3Stat2Label: 'Kriminalitätsrate',
|
||||||
showcaseStep3HeaderFit: 'Nachbarschaftsdaten',
|
|
||||||
showcaseStep3Stat1Label: 'Verkaufspreis-Trend',
|
|
||||||
showcaseStep3Stat2Label: 'Kriminalität',
|
|
||||||
showcaseStep3Stat2Value: 'Unter dem Borough-Schnitt',
|
|
||||||
showcaseStep3Stat3Label: 'Median-Alter',
|
|
||||||
showcaseStep3Stat4Label: 'Breitband',
|
|
||||||
showcaseStep3Stat4Value: '1 Gbps verfügbar',
|
|
||||||
showcaseStep3Stat5Label: 'Grundschulen',
|
|
||||||
showcaseStep3Stat5Value: '3 Outstanding innerhalb von 1 Meile',
|
|
||||||
showcaseStep4Tab: 'Erkunden',
|
showcaseStep4Tab: 'Erkunden',
|
||||||
showcaseStep4Title: 'Selbst vor Ort prüfen',
|
showcaseStep4Title: 'Selbst vor Ort erkunden',
|
||||||
showcaseStep4Body:
|
showcaseStep4Body:
|
||||||
'Nimm drei fundierte Ausgangspunkte mit in die echte Welt. Lauf durch die Straßen, teste den Pendelweg und vergleiche Besichtigungen mit Kontext.',
|
'Nimm deine drei besten Postcodes mit in die echte Welt. Lauf durch die Straßen, teste den Pendelweg und vergleiche Besichtigungen mit Kontext.',
|
||||||
showcaseStep4FileName: 'areas-to-scout.xlsx',
|
showcaseStep4FileName: 'areas-to-scout.xlsx',
|
||||||
showcaseStep4ExportLabel: 'Nach Excel exportieren',
|
|
||||||
showcaseStep4ColPostcode: 'Postcode',
|
showcaseStep4ColPostcode: 'Postcode',
|
||||||
showcaseStep4ColScore: 'Passung',
|
showcaseStep4ColScore: 'Passung',
|
||||||
showcaseStep4ColCommute: 'Pendelweg',
|
showcaseStep4ColCommute: 'Pendelweg',
|
||||||
showcaseStep4ColPrice: 'Median-Verkaufspreis',
|
showcaseStep4ColPrice: '£/sqm',
|
||||||
showcaseStep4Conclusion: 'Von hier aus kannst du deine Suche beginnen.',
|
showcaseStep4Conclusion: 'Von hier aus kannst du losziehen.',
|
||||||
statProperties: 'historische Verkäufe',
|
statProperties: 'historische Verkäufe',
|
||||||
statFilters: 'kombinierbare Filter',
|
statFilters: 'kombinierbare Filter',
|
||||||
statEvery: 'Jeder',
|
statEvery: 'Jeder',
|
||||||
statPostcodeInEngland: 'Postcode in England',
|
statPostcodeInEngland: 'Postcode in England',
|
||||||
coverageNote:
|
coverageNote:
|
||||||
'Deckt jeden Postcode in England ab — je 200+ Datenfelder. Schottland und Wales sind in Planung.',
|
'Deckt jeden Postcode in England ab, je 200+ Datenfelder. Schottland und Wales sind in Planung.',
|
||||||
priceStrip:
|
priceStrip:
|
||||||
'Lebenslanger Zugang, aktuell {{price}} — der Preis steigt, sobald sich die Stufen füllen.',
|
'Einmal zahlen für lebenslangen Zugang: aktuell {{price}}, steigend, sobald sich jede Stufe füllt.',
|
||||||
priceStripSpots: 'Noch {{count}} Platz zu diesem Preis.',
|
priceStripSpots: 'Noch {{count}} Platz zu diesem Preis.',
|
||||||
priceStripSpotsPlural: 'Noch {{count}} Plätze zu diesem Preis.',
|
priceStripSpotsPlural: 'Noch {{count}} Plätze zu diesem Preis.',
|
||||||
priceStripCta: 'Preise ansehen',
|
priceStripCta: 'Preise ansehen',
|
||||||
ourPhilosophy: 'Beginne mit dem, was zählt, und finde den passenden Postcode',
|
ourPhilosophy: 'Der Ruf ist eingepreist. Der Wert noch nicht.',
|
||||||
philosophyP1:
|
philosophyP1:
|
||||||
'Die meisten Immobilienseiten fragen, wo du wohnen möchtest. In London ist das besonders schwierig, aber dasselbe Problem gibt es in ganz England: Käufer starten mit wenigen bekannten Orten und prüfen dann Pendelzeit, Schulen, Kriminalität, Street View, Breitband und Verkaufspreise in getrennten Tabs.',
|
'Ein Teil des Preises eines Postcodes sind seine Bausubstanz, sein Einzugsgebiet und sein Pendelweg. Der Rest ist nur der Name. Käufer treiben die Postcodes hoch, von denen sie gehört haben, also liegt die Straße dahinter (in jeder preisrelevanten Kennzahl identisch) still günstiger. Diese Lücke von Hand zu finden bedeutet ein Dutzend Browser-Tabs: Verkaufspreise, Ofsted, Kriminalität, Lärm, Wohnflächen.',
|
||||||
philosophyP2:
|
philosophyP2:
|
||||||
'Perfect Postcode dreht die Suche um. Sag der Karte, was zählt, und sie zeigt passende Postcodes mit nachvollziehbaren Gründen. Erst Daten, dann vor Ort das Gefühl prüfen.',
|
'Perfect Postcode übernimmt den Abgleich für dich. Sag der Karte dein Budget und deine unverzichtbaren Kriterien; sie gewichtet jeden Postcode in England nach den preisrelevanten Faktoren und stellt die unterbewerteten nach oben. Dann geh hin und lauf sie ab.',
|
||||||
streetTitle: 'Orte ändern sich von Straße zu Straße',
|
streetTitle: 'Die Lücke zeigt sich Straße für Straße',
|
||||||
streetIntro:
|
streetIntro:
|
||||||
'Grobe Gebietsnamen verdecken die Details, die zählen: Bahnhofsseite, Straßenlärm, Schulmix, genaue Pendelzeit und echte Verkaufspreise.',
|
'Grobe Gebietsnamen verdecken, wo die Schnäppchen liegen: die günstigere Bahnhofsseite, die ruhigere Straße, dasselbe Schul-Einzugsgebiet und wofür nahezu identische Immobilien tatsächlich pro Quadratmeter verkauft wurden.',
|
||||||
streetCard1Title: 'Finde Gegenden, die du übersehen hättest',
|
streetCard1Title: 'Finde den günstigeren Zwilling',
|
||||||
streetCard1Body:
|
streetCard1Body:
|
||||||
'Entdecke Postcodes, die deinen Anforderungen entsprechen, statt dich nur auf bekannte Namen, Empfehlungen oder Hype zu verlassen.',
|
'Jeder berühmte Postcode hat einen ruhigeren Nachbarn mit demselben Einzugsgebiet, demselben Bahnhof und derselben Bauepoche, ohne den Aufpreis und ohne den „angesagt“-Zuschlag. Wir stellen beide nebeneinander, sodass die Lücke unmöglich zu übersehen ist.',
|
||||||
streetCard2Title: 'Sieh Kompromisse vor Besichtigungen',
|
streetCard2Title: 'Sieh, was dein Geld wirklich kauft',
|
||||||
streetCard2Body:
|
streetCard2Body:
|
||||||
'Vergleiche Preis, Platz, Pendelzeit, Sicherheit, Schulen, Breitband, Lärm und Energieeffizienz, bevor du Wochenenden mit Besichtigungen verbringst.',
|
'Wohnfläche, Verkaufspreise, Pendelweg, Kriminalität, Schulen, Breitband, Lärm und Energieeffizienz auf einem Bildschirm, nicht acht Tabs und eine Tabelle. Entscheide, was einen Samstag wert ist, bevor du den Samstag investierst.',
|
||||||
othersVs: 'Andere vs.',
|
othersVs: 'Andere vs.',
|
||||||
checkMyPostcode: 'Immobilienportale',
|
checkMyPostcode: 'Immobilienportale',
|
||||||
areaGuides: 'Postcode-Berichte',
|
areaGuides: 'Postcode-Berichte',
|
||||||
compSearchWithout: 'Gegenden entdecken, bevor du die Namen kennst',
|
compSearchWithout: 'Sortiert nach dem, was du bekommst, nicht danach, wer davon gehört hat',
|
||||||
compSearchWithoutSub: '(erst Anforderungen, dann Ort)',
|
compSearchWithoutSub: '(der günstigere Zwilling für deine Bedürfnisse, nicht der Name)',
|
||||||
compAreaData: 'Nachbarschaftsdaten auf Postcode-Ebene',
|
compAreaData: 'Nachbarschaftsdaten auf Postcode-Ebene',
|
||||||
compAreaDataSub: '(Kriminalität, Schulen, Lärm, Breitband, Infrastruktur)',
|
compAreaDataSub: '(Kriminalität, Schulen, Lärm, Breitband, Infrastruktur)',
|
||||||
compPropertyData: 'Historie auf Immobilienebene',
|
compPropertyData: 'Historie auf Immobilienebene',
|
||||||
compPropertyDataSub: '(Verkaufspreise, EPC, Wohnfläche, Schätzwert)',
|
compPropertyDataSub: '(Verkaufspreise, EPC, Wohnfläche, Schätzwert)',
|
||||||
compFilters: '40+ Filter, die zusammenarbeiten',
|
compFilters: '40+ Filter, die zusammenarbeiten',
|
||||||
compFiltersSub: '(nicht ein Postcode oder ein Inserat nach dem anderen)',
|
compFiltersSub: '(nicht ein Postcode oder ein Inserat nach dem anderen)',
|
||||||
ctaTitle: 'Hör auf zu raten, wo du kaufen sollst.',
|
compListings: 'Aktuelle Inserate, Fotos und Besichtigungen',
|
||||||
|
compListingsSub: '(das Tagesgeschäft beim Kauf einer konkreten Immobilie)',
|
||||||
|
twinBadge: 'Echtes Beispiel',
|
||||||
|
twinTitle: 'Dasselbe Leben, einen Postcode günstiger',
|
||||||
|
twinIntro:
|
||||||
|
'Zwei Nachbarn im Norden Londons, 1,3 km voneinander entfernt: Wohnungen mit vergleichbaren Grundschul-Einzugsgebieten und demselben rund 30-minütigen Pendelweg, doch sehr unterschiedlich bepreist pro Quadratmeter.',
|
||||||
|
twinPriceyLabel: 'Der Name, den jeder kennt',
|
||||||
|
twinValueLabel: 'Sein ruhigerer Nachbar',
|
||||||
|
twinPerSqm: '{{value}}/sqm',
|
||||||
|
twinSameSchool: 'Beide in Einzugsgebieten mit „Outstanding“ bewerteter Grundschule',
|
||||||
|
twinSameCommute: 'Beide rund 30 Min. mit dem Nahverkehr ins Zentrum Londons',
|
||||||
|
twinDelta: '{{percent}} weniger pro Quadratmeter',
|
||||||
|
twinFootnote:
|
||||||
|
'Ein echtes Beispiel aus unseren Daten: Median-£/qm für seit 2021 verkaufte Wohnungen. Erkunde die Live-Karte und finde dein eigenes.',
|
||||||
|
twinCta: 'Einen solchen Geheimtipp in meiner Nähe finden',
|
||||||
|
ctaTitle: 'Hör auf, für einen Namen zu viel zu zahlen.',
|
||||||
ctaDescription:
|
ctaDescription:
|
||||||
'Erstelle eine Shortlist von Postcodes, die zu deinem echten Leben passen, und prüfe sie dann vor Ort.',
|
'Erstelle deine Shortlist auf der Live-Karte, kostenlos. Wenn du überzeugt bist, schalte jeden Filter für immer frei. Einmal zahlen, kein Abo.',
|
||||||
|
guaranteeNote: 'Einmal zahlen. Niemals ein Abo. 30 Tage Geld-zurück-Garantie.',
|
||||||
},
|
},
|
||||||
|
|
||||||
// ── Pricing Page ───────────────────────────────────
|
// ── Pricing Page ───────────────────────────────────
|
||||||
|
|
@ -1144,13 +1171,17 @@ const de: Translations = {
|
||||||
},
|
},
|
||||||
|
|
||||||
pricingPage: {
|
pricingPage: {
|
||||||
|
cachedNotice:
|
||||||
|
'Live-Preise konnten nicht aktualisiert werden; diese Angaben sind möglicherweise veraltet.',
|
||||||
|
scrollPrev: 'Vorherige Tarife anzeigen',
|
||||||
|
scrollNext: 'Weitere Tarife anzeigen',
|
||||||
title: 'Mit einem besseren Suchgebiet kaufen',
|
title: 'Mit einem besseren Suchgebiet kaufen',
|
||||||
subtitle:
|
subtitle:
|
||||||
'Lebenslanger Zugang zu der Karte, die zeigt, wo du suchen solltest, bevor du Besichtigungen buchst.',
|
'Lebenslanger Zugang zu der Karte, die zeigt, wo du suchen solltest, bevor du Besichtigungen buchst.',
|
||||||
costContext:
|
costContext:
|
||||||
'Käufer verbringen oft Abende damit, Inserate, Pendelzeiten, Schulberichte, Kriminalitätskarten, Street View und Verkaufspreise zusammenzuführen. In London ist das besonders mühsam, aber dasselbe Rechercheproblem gibt es in ganz England. Perfect Postcode bringt die Gebietsrecherche auf eine Karte, bevor du Wochenenden, Gebühren und Aufmerksamkeit investierst.',
|
'Käufer verbringen oft Abende damit, Inserate, Pendelzeiten, Schulberichte, Kriminalitätskarten, Street View und Verkaufspreise zusammenzuführen. In London ist das besonders mühsam, aber dasselbe Rechercheproblem gibt es in ganz England. Perfect Postcode bringt die Gebietsrecherche auf eine Karte, bevor du Wochenenden, Gebühren und Aufmerksamkeit investierst.',
|
||||||
lessThanSurvey:
|
lessThanSurvey:
|
||||||
'Kostet weniger als ein Zehntel eines Gutachtens — und prägt eine weit größere Entscheidung.',
|
'Kostet weniger als ein Zehntel eines Gutachtens und prägt eine weit größere Entscheidung.',
|
||||||
currentTier: 'Aktuelle Stufe',
|
currentTier: 'Aktuelle Stufe',
|
||||||
firstNUsers: 'Erste {{count}} Nutzer',
|
firstNUsers: 'Erste {{count}} Nutzer',
|
||||||
everyoneAfter: 'Alle danach',
|
everyoneAfter: 'Alle danach',
|
||||||
|
|
@ -1161,7 +1192,7 @@ const de: Translations = {
|
||||||
filled: 'Vergeben',
|
filled: 'Vergeben',
|
||||||
openDashboard: 'Dashboard öffnen',
|
openDashboard: 'Dashboard öffnen',
|
||||||
getStarted: 'Jetzt starten',
|
getStarted: 'Jetzt starten',
|
||||||
getStartedPrice: 'Jetzt starten — {{price}}',
|
getStartedPrice: 'Jetzt starten: {{price}}',
|
||||||
noCreditCard: 'Keine Kreditkarte erforderlich',
|
noCreditCard: 'Keine Kreditkarte erforderlich',
|
||||||
moneyBack: '14 Tage Geld-zurück-Garantie.',
|
moneyBack: '14 Tage Geld-zurück-Garantie.',
|
||||||
|
|
||||||
|
|
@ -1192,25 +1223,25 @@ const de: Translations = {
|
||||||
videos: 'Videos',
|
videos: 'Videos',
|
||||||
videosTitle: 'Social-Media-Videos',
|
videosTitle: 'Social-Media-Videos',
|
||||||
videosIntro:
|
videosIntro:
|
||||||
'Kurze Clips aus unseren Social-Media-Kanälen – jeder zeigt eine einzelne Suche in Aktion, von ruhigen Straßen über Schuleinzugsgebiete bis zu Pendelzeiten.',
|
'Kurze Clips aus unseren Social-Media-Kanälen: jeder zeigt eine einzelne Suche in Aktion, von ruhigen Straßen über Schuleinzugsgebiete bis zu Pendelzeiten.',
|
||||||
video01Title: 'Finde den günstigeren Zwilling',
|
video01Title: 'Finde den günstigeren Zwilling',
|
||||||
video01Desc:
|
video01Desc:
|
||||||
'Gib deinen kompletten Wohnungswunsch in einem schlichten Satz ein und sieh zu, wie sich jede passende Postleitzahl in England nach Preis-Leistung sortiert – und der günstigere Zwilling auftaucht, den niemand hochgeboten hat.',
|
'Gib deinen kompletten Wohnungswunsch in einem schlichten Satz ein und sieh zu, wie sich jede passende Postleitzahl in England nach Preis-Leistung sortiert, und der günstigere Zwilling auftaucht, den niemand hochgeboten hat.',
|
||||||
video02Title: 'Die 20-Minuten-Pendelkarte',
|
video02Title: 'Die 20-Minuten-Pendelkarte',
|
||||||
video02Desc:
|
video02Desc:
|
||||||
'Färbe London nach Pendelzeit ins Zentrum, beschränke auf eine 20-minütige Fahrt und sieh, wie sich identische Wege in die Namen, die jeder kennt, und ruhigere Postleitzahlen aufteilen, die niemand hochgeboten hat.',
|
'Färbe London nach Pendelzeit ins Zentrum, beschränke auf eine 20-minütige Fahrt und sieh, wie sich identische Wege in die Namen, die jeder kennt, und ruhigere Postleitzahlen aufteilen, die niemand hochgeboten hat.',
|
||||||
video03Title: 'Die Beweisakte zur Postleitzahl',
|
video03Title: 'Die Beweisakte zur Postleitzahl',
|
||||||
video03Desc:
|
video03Desc:
|
||||||
'Tippe auf eine Postleitzahl und ein Panel öffnet sich mit ihren verkauften Preisen, Schul-Einzugsgebieten, Kriminalität und Street View – so erkennst du, ob du für Substanz zahlst oder nur für einen Ruf.',
|
'Tippe auf eine Postleitzahl und ein Panel öffnet sich mit ihren verkauften Preisen, Schul-Einzugsgebieten, Kriminalität und Street View. So erkennst du, ob du für Substanz zahlst oder nur für einen Ruf.',
|
||||||
video04Title: 'Die übersehene ruhige Straße',
|
video04Title: 'Die übersehene ruhige Straße',
|
||||||
video04Desc:
|
video04Desc:
|
||||||
'Berühmte Postleitzahlen preisen ihren Ruf ein, doch ein Anzeigenfoto schweigt zum Lärm. Filtere nach Dezibel und finde die wirklich ruhige Straße eine weiter, die niemand hochgeboten hat.',
|
'Berühmte Postleitzahlen preisen ihren Ruf ein, doch ein Anzeigenfoto schweigt zum Lärm. Filtere nach Dezibel und finde die wirklich ruhige Straße eine weiter, die niemand hochgeboten hat.',
|
||||||
video05Title: 'Das Einzugsgebiet ohne den Aufschlag',
|
video05Title: 'Das Einzugsgebiet ohne den Aufschlag',
|
||||||
video05Desc:
|
video05Desc:
|
||||||
'Eine Familie in Leeds sucht eine gute Grundschule, wenig Kriminalität und ein Budget unter £350k – und findet die still günstigeren Straßen, die genau dasselbe Einzugsgebiet teilen.',
|
'Eine Familie in Leeds sucht eine gute Grundschule, wenig Kriminalität und ein Budget unter £350k, und findet die still günstigeren Straßen, die genau dasselbe Einzugsgebiet teilen.',
|
||||||
video06Title: 'Der Waitrose-Effekt, eingepreist',
|
video06Title: 'Der Waitrose-Effekt, eingepreist',
|
||||||
video06Desc:
|
video06Desc:
|
||||||
'Zu Fuß zu einem Waitrose, einer U-Bahn-Station und einem Park ist ein eingepreister Aufschlag – finde die nahen Postleitzahlen mit denselben Annehmlichkeiten für weniger pro Quadratmeter.',
|
'Zu Fuß zu einem Waitrose, einer U-Bahn-Station und einem Park ist ein eingepreister Aufschlag. Finde die nahen Postleitzahlen mit denselben Annehmlichkeiten für weniger pro Quadratmeter.',
|
||||||
video07Title: 'Eine Preis-Leistungs-Karte für Mieter',
|
video07Title: 'Eine Preis-Leistungs-Karte für Mieter',
|
||||||
video07Desc:
|
video07Desc:
|
||||||
'Auch namhafte Postleitzahlen kosten mehr Miete. Lege deine Miete, deinen Arbeitsweg und eine ruhige Straße fest und sieh, welche Londoner Postleitzahlen wirklich ins Budget passen.',
|
'Auch namhafte Postleitzahlen kosten mehr Miete. Lege deine Miete, deinen Arbeitsweg und eine ruhige Straße fest und sieh, welche Londoner Postleitzahlen wirklich ins Budget passen.',
|
||||||
|
|
@ -1323,7 +1354,7 @@ const de: Translations = {
|
||||||
faqPricingTitle: 'Zugang',
|
faqPricingTitle: 'Zugang',
|
||||||
faqTipsTitle: 'Kartentipps',
|
faqTipsTitle: 'Kartentipps',
|
||||||
faqBehindDataTitle: 'Hinter den Daten',
|
faqBehindDataTitle: 'Hinter den Daten',
|
||||||
// FAQ items — Finding Your Area
|
// FAQ items: Finding Your Area
|
||||||
faqFinding1Q: 'Wo soll ich suchen, wenn die offensichtlichen Gebiete zu teuer sind?',
|
faqFinding1Q: 'Wo soll ich suchen, wenn die offensichtlichen Gebiete zu teuer sind?',
|
||||||
faqFinding1A:
|
faqFinding1A:
|
||||||
'Beginne mit dem, worauf du nicht verzichten kannst: Budget, Haustyp, Platz, Pendelzeit, Schulen, Sicherheit, Lärm, Breitband, Parks und alles Weitere, was wichtig ist. Die Karte blendet Orte aus, die nicht passen, sodass weniger offensichtliche Gebiete sichtbar werden, bevor du Inserate durchsuchst.',
|
'Beginne mit dem, worauf du nicht verzichten kannst: Budget, Haustyp, Platz, Pendelzeit, Schulen, Sicherheit, Lärm, Breitband, Parks und alles Weitere, was wichtig ist. Die Karte blendet Orte aus, die nicht passen, sodass weniger offensichtliche Gebiete sichtbar werden, bevor du Inserate durchsuchst.',
|
||||||
|
|
@ -1333,7 +1364,7 @@ const de: Translations = {
|
||||||
faqFinding3Q: 'Was mache ich, wenn die Suche zu viele oder zu wenige Gebiete zeigt?',
|
faqFinding3Q: 'Was mache ich, wenn die Suche zu viele oder zu wenige Gebiete zeigt?',
|
||||||
faqFinding3A:
|
faqFinding3A:
|
||||||
'Lass deine Muss-Anforderungen aktiv und färbe die Karte nach einer Sache ein, die du vergleichen möchtest, etwa Preis pro m², Straßenlärm, Schulbewertung oder Fahrzeit. Wenn fast nichts übrig bleibt, lockere einen Regler und sieh, welche Änderung neue Optionen öffnet.',
|
'Lass deine Muss-Anforderungen aktiv und färbe die Karte nach einer Sache ein, die du vergleichen möchtest, etwa Preis pro m², Straßenlärm, Schulbewertung oder Fahrzeit. Wenn fast nichts übrig bleibt, lockere einen Regler und sieh, welche Änderung neue Optionen öffnet.',
|
||||||
// FAQ items — Commute and Travel
|
// FAQ items: Commute and Travel
|
||||||
faqCommute1Q: 'Wie werden die Fahrzeiten berechnet?',
|
faqCommute1Q: 'Wie werden die Fahrzeiten berechnet?',
|
||||||
faqCommute1A:
|
faqCommute1A:
|
||||||
'Die Fahrzeiten werden im Voraus für jedes gespeicherte Ziel berechnet. Wir prüfen, welche Postleitzahlen dieses Ziel per Auto, Fahrrad, zu Fuß oder mit öffentlichen Verkehrsmitteln erreichen können, und speichern diese Ergebnisse, damit die Karte beim Filtern schnell reagiert.',
|
'Die Fahrzeiten werden im Voraus für jedes gespeicherte Ziel berechnet. Wir prüfen, welche Postleitzahlen dieses Ziel per Auto, Fahrrad, zu Fuß oder mit öffentlichen Verkehrsmitteln erreichen können, und speichern diese Ergebnisse, damit die Karte beim Filtern schnell reagiert.',
|
||||||
|
|
@ -1343,21 +1374,21 @@ const de: Translations = {
|
||||||
faqCommute3Q: 'Wann sollte ich die Bestwert-Schaltfläche nutzen?',
|
faqCommute3Q: 'Wann sollte ich die Bestwert-Schaltfläche nutzen?',
|
||||||
faqCommute3A:
|
faqCommute3A:
|
||||||
'Nutze die Bestwert-Schaltfläche bei ÖPNV-Suchen, wenn du die Fahrt mit gut gewählter Abfahrt und guten Anschlüssen sehen möchtest. Lass sie für den Alltagsvergleich ausgeschaltet, da die normale Einstellung näher an dem liegt, was du an den meisten Tagen erwarten solltest.',
|
'Nutze die Bestwert-Schaltfläche bei ÖPNV-Suchen, wenn du die Fahrt mit gut gewählter Abfahrt und guten Anschlüssen sehen möchtest. Lass sie für den Alltagsvergleich ausgeschaltet, da die normale Einstellung näher an dem liegt, was du an den meisten Tagen erwarten solltest.',
|
||||||
// FAQ items — Budget and Value
|
// FAQ items: Budget and Value
|
||||||
faqBudget1Q: 'Wie schätzt ihr aktuelle Immobilienpreise?',
|
faqBudget1Q: 'Wie schätzt ihr aktuelle Immobilienpreise?',
|
||||||
faqBudget1A:
|
faqBudget1A:
|
||||||
'Die Schätzung beginnt mit dem letzten bei HM Land Registry erfassten Verkaufspreis. Wir bringen diesen Verkauf näher an den heutigen Markt, indem wir betrachten, wie sich ähnliche Immobilien entwickelt haben, besonders Immobilien desselben Typs in der Nähe. Wenn es nur wenige lokale Verkäufe gibt, stützt sich die Schätzung stärker auf weiter gefasste Gebietstrends. Anschließend wird sie mit nahegelegenen jüngeren Verkäufen und der Wohnfläche abgeglichen, damit das Ergebnis für Vergleiche nützlich ist.',
|
'Die Schätzung beginnt mit dem letzten bei HM Land Registry erfassten Verkaufspreis. Wir bringen diesen Verkauf näher an den heutigen Markt, indem wir betrachten, wie sich ähnliche Immobilien entwickelt haben, besonders Immobilien desselben Typs in der Nähe. Wenn es nur wenige lokale Verkäufe gibt, stützt sich die Schätzung stärker auf weiter gefasste Gebietstrends. Anschließend wird sie mit nahegelegenen jüngeren Verkäufen und der Wohnfläche abgeglichen, damit das Ergebnis für Vergleiche nützlich ist.',
|
||||||
faqBudget2Q: 'Warum den geschätzten aktuellen Preis statt des letzten Verkaufspreises nutzen?',
|
faqBudget2Q: 'Warum den geschätzten aktuellen Preis statt des letzten Verkaufspreises nutzen?',
|
||||||
faqBudget2A:
|
faqBudget2A:
|
||||||
'Der letzte Verkaufspreis kann Jahre oder Jahrzehnte alt sein, und Angebotspreise zeigen nur, was heute zum Verkauf steht. Der geschätzte aktuelle Preis bringt ältere Verkäufe näher an den heutigen Markt, damit du mehr Immobilien vergleichen und Gebiete mit möglichem Wert erkennen kannst, bevor passende Inserate erscheinen. Nutze ihn als Orientierung für deine Auswahlliste, nicht als Bankbewertung.',
|
'Der letzte Verkaufspreis kann Jahre oder Jahrzehnte alt sein, und Angebotspreise zeigen nur, was heute zum Verkauf steht. Der geschätzte aktuelle Preis bringt ältere Verkäufe näher an den heutigen Markt, damit du mehr Immobilien vergleichen und Gebiete mit möglichem Wert erkennen kannst, bevor passende Inserate erscheinen. Nutze ihn als Orientierung für deine Auswahlliste, nicht als Bankbewertung.',
|
||||||
// FAQ items — Safety and Neighbourhood
|
// FAQ items: Safety and Neighbourhood
|
||||||
faqSafety1Q: 'Welche Art von Kriminalität ist rund um diese Postleitzahl häufig?',
|
faqSafety1Q: 'Welche Art von Kriminalität ist rund um diese Postleitzahl häufig?',
|
||||||
faqSafety1A:
|
faqSafety1A:
|
||||||
'Kriminalität ist nach Art aufgeschlüsselt, etwa Gewalt, Einbruch, Raub, Fahrzeugkriminalität, antisoziales Verhalten, Ladendiebstahl, Drogen und öffentliche Ordnung. Du kannst dich auf die Risiken konzentrieren, die dir wichtig sind, statt dich auf einen vagen Sicherheitswert zu verlassen.',
|
'Kriminalität ist nach Art aufgeschlüsselt, etwa Gewalt, Einbruch, Raub, Fahrzeugkriminalität, antisoziales Verhalten, Ladendiebstahl, Drogen und öffentliche Ordnung. Du kannst dich auf die Risiken konzentrieren, die dir wichtig sind, statt dich auf einen vagen Sicherheitswert zu verlassen.',
|
||||||
faqSafety2Q: 'Was sollte ich vor einer Besichtigung in einer unbekannten Straße prüfen?',
|
faqSafety2Q: 'Was sollte ich vor einer Besichtigung in einer unbekannten Straße prüfen?',
|
||||||
faqSafety2A:
|
faqSafety2A:
|
||||||
'Prüfe Kriminalität, Straßenlärm, Breitband, Parks, Lebensmittelgeschäfte, Schulen und Pendelzeit, bevor du buchst. Inseratsfotos können nützlich sein, sollten aber nicht das Erste sein, woraus du erfährst, wie die Straße ist.',
|
'Prüfe Kriminalität, Straßenlärm, Breitband, Parks, Lebensmittelgeschäfte, Schulen und Pendelzeit, bevor du buchst. Inseratsfotos können nützlich sein, sollten aber nicht das Erste sein, woraus du erfährst, wie die Straße ist.',
|
||||||
// FAQ items — Families and Schools
|
// FAQ items: Families and Schools
|
||||||
faqFamilies1Q:
|
faqFamilies1Q:
|
||||||
'Welche Gebiete haben die richtige Mischung aus Schulen, Platz, Sicherheit und Pendelzeit?',
|
'Welche Gebiete haben die richtige Mischung aus Schulen, Platz, Sicherheit und Pendelzeit?',
|
||||||
faqFamilies1A:
|
faqFamilies1A:
|
||||||
|
|
@ -1365,7 +1396,7 @@ const de: Translations = {
|
||||||
faqFamilies2Q: 'Beweist das, dass ich im Einzugsgebiet einer Schule liege?',
|
faqFamilies2Q: 'Beweist das, dass ich im Einzugsgebiet einer Schule liege?',
|
||||||
faqFamilies2A:
|
faqFamilies2A:
|
||||||
'Nein. Wir zeigen nahegelegene Schulqualität und lokale Bildungsinformationen, aber Aufnahmegebiete und Prioritätsregeln können sich ändern. Nutze Perfect Postcode für die Vorauswahl und prüfe Einzugsgebiete anschließend bei der Schule oder Gemeinde.',
|
'Nein. Wir zeigen nahegelegene Schulqualität und lokale Bildungsinformationen, aber Aufnahmegebiete und Prioritätsregeln können sich ändern. Nutze Perfect Postcode für die Vorauswahl und prüfe Einzugsgebiete anschließend bei der Schule oder Gemeinde.',
|
||||||
// FAQ items — Environment and Quality of Life
|
// FAQ items: Environment and Quality of Life
|
||||||
faqEnv1Q:
|
faqEnv1Q:
|
||||||
'Wie vermeide ich eine laute Straße, ohne Pendelzeit oder Breitbandqualität zu verlieren?',
|
'Wie vermeide ich eine laute Straße, ohne Pendelzeit oder Breitbandqualität zu verlieren?',
|
||||||
faqEnv1A:
|
faqEnv1A:
|
||||||
|
|
@ -1376,7 +1407,7 @@ const de: Translations = {
|
||||||
faqEnv3Q: 'Welche laufenden Kosten kann ich vor einer Besichtigung prüfen?',
|
faqEnv3Q: 'Welche laufenden Kosten kann ich vor einer Besichtigung prüfen?',
|
||||||
faqEnv3A:
|
faqEnv3A:
|
||||||
'Du kannst vor der Besichtigung Energieklasse, Wohnfläche, Baualter, Council-Tax-Gebiet, Breitband und Lärm prüfen. Das sagt deine genauen Rechnungen nicht voraus, hilft aber, offensichtliche Fehlgriffe früh zu vermeiden.',
|
'Du kannst vor der Besichtigung Energieklasse, Wohnfläche, Baualter, Council-Tax-Gebiet, Breitband und Lärm prüfen. Das sagt deine genauen Rechnungen nicht voraus, hilft aber, offensichtliche Fehlgriffe früh zu vermeiden.',
|
||||||
// FAQ items — Listing Portals and Due Diligence
|
// FAQ items: Listing Portals and Due Diligence
|
||||||
faqDueDiligence1Q: 'Sollte ich das vor oder nach Rightmove nutzen?',
|
faqDueDiligence1Q: 'Sollte ich das vor oder nach Rightmove nutzen?',
|
||||||
faqDueDiligence1A:
|
faqDueDiligence1A:
|
||||||
'Nutze Perfect Postcode vor und parallel zu Inseratsseiten. Rightmove, Zoopla und OnTheMarket bleiben die Orte für aktuell verfügbare Immobilien, Fotos, Makler, Besichtigungen und Benachrichtigungen. Perfect Postcode hilft zu entscheiden, welche Postleitzahlen die Suche wert sind.',
|
'Nutze Perfect Postcode vor und parallel zu Inseratsseiten. Rightmove, Zoopla und OnTheMarket bleiben die Orte für aktuell verfügbare Immobilien, Fotos, Makler, Besichtigungen und Benachrichtigungen. Perfect Postcode hilft zu entscheiden, welche Postleitzahlen die Suche wert sind.',
|
||||||
|
|
@ -1389,11 +1420,11 @@ const de: Translations = {
|
||||||
faqDueDiligence4Q: 'Was sollte ich vor einem Angebot trotzdem prüfen?',
|
faqDueDiligence4Q: 'Was sollte ich vor einem Angebot trotzdem prüfen?',
|
||||||
faqDueDiligence4A:
|
faqDueDiligence4A:
|
||||||
'Nutze Perfect Postcode, um Gebiet und wahrscheinlichen Wert zu prüfen, und bestätige dann die Inseratsdetails vor einem Angebot. Prüfe außerdem die Eigentumsform, Details zum Erbbaurecht, Nebenkosten, Planungshistorie, Hochwasserrisiko, rechtliche Fragen, Hypothekenanforderungen und Gutachten.',
|
'Nutze Perfect Postcode, um Gebiet und wahrscheinlichen Wert zu prüfen, und bestätige dann die Inseratsdetails vor einem Angebot. Prüfe außerdem die Eigentumsform, Details zum Erbbaurecht, Nebenkosten, Planungshistorie, Hochwasserrisiko, rechtliche Fragen, Hypothekenanforderungen und Gutachten.',
|
||||||
// FAQ items — Privacy and Data Protection
|
// FAQ items: Privacy and Data Protection
|
||||||
faqPrivacy1Q: 'Speichert ihr personenbezogene Daten über mich?',
|
faqPrivacy1Q: 'Speichert ihr personenbezogene Daten über mich?',
|
||||||
faqPrivacy1A:
|
faqPrivacy1A:
|
||||||
'Die Immobilien- und Nachbarschaftsinformationen enthalten keine persönlichen Angaben über dich. Wenn du ein Konto erstellst, speichern wir nur, was für den Dienst nötig ist, etwa E-Mail-Adresse, Zugangsstatus, Newsletter-Auswahl, gespeicherte Suchen, geteilte Links und von Stripe verwaltete Zahlungsdaten. Diese Kontodaten behandeln wir nach britischem Datenschutzrecht.',
|
'Die Immobilien- und Nachbarschaftsinformationen enthalten keine persönlichen Angaben über dich. Wenn du ein Konto erstellst, speichern wir nur, was für den Dienst nötig ist, etwa E-Mail-Adresse, Zugangsstatus, Newsletter-Auswahl, gespeicherte Suchen, geteilte Links und von Stripe verwaltete Zahlungsdaten. Diese Kontodaten behandeln wir nach britischem Datenschutzrecht.',
|
||||||
// FAQ items — Why Perfect Postcode
|
// FAQ items: Why Perfect Postcode
|
||||||
faqWhy1Q: 'Was zeigt das, was Immobilienportale normalerweise nicht zeigen?',
|
faqWhy1Q: 'Was zeigt das, was Immobilienportale normalerweise nicht zeigen?',
|
||||||
faqWhy1A:
|
faqWhy1A:
|
||||||
'Inseratsseiten beginnen mit Immobilien, die gerade zum Verkauf stehen. Perfect Postcode beginnt mit Orten, die zu deinem Leben und Budget passen, mit Verkaufspreisen, Platz, Pendelzeit, Schulen, Kriminalität, Lärm, Breitband, Energieklasse, Eigentumsform und Infrastruktur, bevor du Inserate öffnest.',
|
'Inseratsseiten beginnen mit Immobilien, die gerade zum Verkauf stehen. Perfect Postcode beginnt mit Orten, die zu deinem Leben und Budget passen, mit Verkaufspreisen, Platz, Pendelzeit, Schulen, Kriminalität, Lärm, Breitband, Energieklasse, Eigentumsform und Infrastruktur, bevor du Inserate öffnest.',
|
||||||
|
|
@ -1403,7 +1434,7 @@ const de: Translations = {
|
||||||
faqWhy3Q: 'Wie verlässlich sind die Daten?',
|
faqWhy3Q: 'Wie verlässlich sind die Daten?',
|
||||||
faqWhy3A:
|
faqWhy3A:
|
||||||
'Die wichtigsten Quellen sind offizielle oder weit genutzte öffentliche Daten: Verkaufspreise, Energieklassen, lokale Fakten, Schulbewertungen, Breitband, Kriminalität, Umwelt, Karten und Straßendaten. Sie sind nützlich für Auswahllisten und Vergleiche, aber jede Kaufentscheidung braucht aktuelle Prüfungen und bei Bedarf fachlichen Rat.',
|
'Die wichtigsten Quellen sind offizielle oder weit genutzte öffentliche Daten: Verkaufspreise, Energieklassen, lokale Fakten, Schulbewertungen, Breitband, Kriminalität, Umwelt, Karten und Straßendaten. Sie sind nützlich für Auswahllisten und Vergleiche, aber jede Kaufentscheidung braucht aktuelle Prüfungen und bei Bedarf fachlichen Rat.',
|
||||||
// FAQ items — Pricing and Access
|
// FAQ items: Pricing and Access
|
||||||
faqPricing1Q: 'Warum bezahlen, wenn Postleitzahlberichte kostenlos sind?',
|
faqPricing1Q: 'Warum bezahlen, wenn Postleitzahlberichte kostenlos sind?',
|
||||||
faqPricing1A:
|
faqPricing1A:
|
||||||
'Kostenlose Postleitzahltools sind nützlich, wenn du schon weißt, was du prüfen willst. Perfect Postcode durchsucht jede Postleitzahl in England nach deinen Bedürfnissen, kombiniert Filter, vergleicht Optionen, speichert Suchen und exportiert eine Auswahlliste, bevor du Wochenenden für Besichtigungen einplanst.',
|
'Kostenlose Postleitzahltools sind nützlich, wenn du schon weißt, was du prüfen willst. Perfect Postcode durchsucht jede Postleitzahl in England nach deinen Bedürfnissen, kombiniert Filter, vergleicht Optionen, speichert Suchen und exportiert eine Auswahlliste, bevor du Wochenenden für Besichtigungen einplanst.',
|
||||||
|
|
@ -1412,9 +1443,9 @@ const de: Translations = {
|
||||||
'Lebenslanger Zugang bedeutet, dass eine Zahlung deinem Konto laufenden Zugriff auf die kostenpflichtige Perfect-Postcode-Karte für die Lebensdauer des Dienstes gibt. Es ist kein Monats- oder Jahresabo, und normale Datenaktualisierungen sind enthalten. Du kannst es während dieser Suche nutzen, später zurückkommen und weiterhin Zugriff haben, wenn du erneut umziehst.',
|
'Lebenslanger Zugang bedeutet, dass eine Zahlung deinem Konto laufenden Zugriff auf die kostenpflichtige Perfect-Postcode-Karte für die Lebensdauer des Dienstes gibt. Es ist kein Monats- oder Jahresabo, und normale Datenaktualisierungen sind enthalten. Du kannst es während dieser Suche nutzen, später zurückkommen und weiterhin Zugriff haben, wenn du erneut umziehst.',
|
||||||
faqPricing3Q: 'Was kann ich mit der kostenlosen Version nutzen?',
|
faqPricing3Q: 'Was kann ich mit der kostenlosen Version nutzen?',
|
||||||
faqPricing3A:
|
faqPricing3A:
|
||||||
'Kostenlose Nutzer erhalten die vollständige Perfect-Postcode-Karte für ganz England – jeden Postcode und jede Funktion – und können bis zu 3 Filter gleichzeitig anwenden. Der lebenslange Zugang hebt diese Grenze auf, sodass du unbegrenzt Filter kombinieren kannst.',
|
'Kostenlose Nutzer erhalten die vollständige Perfect-Postcode-Karte für ganz England (jeden Postcode und jede Funktion) und können bis zu 3 Filter gleichzeitig anwenden. Der lebenslange Zugang hebt diese Grenze auf, sodass du unbegrenzt Filter kombinieren kannst.',
|
||||||
|
|
||||||
// FAQ items — Tips and Tricks
|
// FAQ items: Tips and Tricks
|
||||||
faqTips1Q: 'Wie sehe ich eine Filtervorschau auf der Karte?',
|
faqTips1Q: 'Wie sehe ich eine Filtervorschau auf der Karte?',
|
||||||
faqTips1A:
|
faqTips1A:
|
||||||
'Klicke auf „Färben“ neben einem Filter oder Merkmal, um die Karte nach diesem Punkt einzufärben. Deine aktiven Filter bleiben bestehen, sodass du schnell eine Sache wie Preis, Pendelzeit, Schulen, Kriminalität oder Lärm vergleichen kannst, ohne die Auswahlliste zu ändern.',
|
'Klicke auf „Färben“ neben einem Filter oder Merkmal, um die Karte nach diesem Punkt einzufärben. Deine aktiven Filter bleiben bestehen, sodass du schnell eine Sache wie Preis, Pendelzeit, Schulen, Kriminalität oder Lärm vergleichen kannst, ohne die Auswahlliste zu ändern.',
|
||||||
|
|
@ -1425,21 +1456,21 @@ const de: Translations = {
|
||||||
faqTips3A:
|
faqTips3A:
|
||||||
'Wenn ein Merkmal die Karte einfärbt, nutze „Farbskala zurücksetzen“ in der Kartenlegende, um die Farben für die aktuell angezeigten Ergebnisse zu aktualisieren. Das ist nach Verschieben, Zoomen oder geänderten Filtern nützlich.',
|
'Wenn ein Merkmal die Karte einfärbt, nutze „Farbskala zurücksetzen“ in der Kartenlegende, um die Farben für die aktuell angezeigten Ergebnisse zu aktualisieren. Das ist nach Verschieben, Zoomen oder geänderten Filtern nützlich.',
|
||||||
|
|
||||||
// FAQ items — Behind The Data
|
// FAQ items: Behind The Data
|
||||||
faqBehindData1Q: 'Warum wirkt ein Flughafen manchmal leiser als die Straßen drumherum?',
|
faqBehindData1Q: 'Warum wirkt ein Flughafen manchmal leiser als die Straßen drumherum?',
|
||||||
faqBehindData1A:
|
faqBehindData1A:
|
||||||
'Der Lärmwert einer Postleitzahl ist der lauteste der drei Defra-Quellen — Straße, Schiene und Flugzeug — modelliert in 4 m Höhe als 24-Stunden-Mittelwert (Lden). In einer belebten Wohnstraße dominiert der Straßenverkehr, typischerweise 65–75 dB. Innerhalb eines Flughafenzauns gibt es keine großen öffentlichen Straßen, also fällt der Straßenanteil weg, und nur der Flugzeug-Durchschnitt bleibt übrig. London City Airport etwa hat eine Nachtruhe und begrenzte Bewegungen, sodass sein 24-Stunden-Flugzeug-Lden moderat ist (ca. 60–66 dB an der Startbahn) — und das Flughafengelände erscheint leiser als die A-Straßen drumherum. Dasselbe gilt für Heathrow. Das ist ein echter Effekt der Messung von Verkehrslärm auf Wohn-Empfängerhöhe, kein Fehler.',
|
'Der Lärmwert einer Postleitzahl ist der lauteste der drei Defra-Quellen (Straße, Schiene und Flugzeug) modelliert in 4 m Höhe als 24-Stunden-Mittelwert (Lden). In einer belebten Wohnstraße dominiert der Straßenverkehr, typischerweise 65–75 dB. Innerhalb eines Flughafenzauns gibt es keine großen öffentlichen Straßen, also fällt der Straßenanteil weg, und nur der Flugzeug-Durchschnitt bleibt übrig. London City Airport etwa hat eine Nachtruhe und begrenzte Bewegungen, sodass sein 24-Stunden-Flugzeug-Lden moderat ist (ca. 60–66 dB an der Startbahn), und das Flughafengelände erscheint leiser als die A-Straßen drumherum. Dasselbe gilt für Heathrow. Das ist ein echter Effekt der Messung von Verkehrslärm auf Wohn-Empfängerhöhe, kein Fehler.',
|
||||||
faqBehindData2Q:
|
faqBehindData2Q:
|
||||||
'Warum erscheint der Flughafen, die Autobahn oder ein Park als eine große Fläche?',
|
'Warum erscheint der Flughafen, die Autobahn oder ein Park als eine große Fläche?',
|
||||||
faqBehindData2A:
|
faqBehindData2A:
|
||||||
'In Großbritannien haben Postleitzahlen offiziell keine Grenzen — Royal Mail definiert eine Postleitzahl als Liste von Zustelladressen, nicht als Fläche. Perfect Postcode erzeugt die Polygone, indem jeder Adresse ihr Anteil der umgebenden Fläche zugeordnet wird. Orte ohne Adressen, etwa eine Startbahn, eine Autobahnspur, ein Park oder ein Stausee, werden von der nächstgelegenen Wohn-Postleitzahl ausgefüllt. Daher erscheint ein Flughafen oder eine offene Fläche oft als ein einziges großes Polygon, und der angezeigte Wert stammt von den wenigen Postleitzahlen innerhalb des Geländes.',
|
'In Großbritannien haben Postleitzahlen offiziell keine Grenzen. Royal Mail definiert eine Postleitzahl als Liste von Zustelladressen, nicht als Fläche. Perfect Postcode erzeugt die Polygone, indem jeder Adresse ihr Anteil der umgebenden Fläche zugeordnet wird. Orte ohne Adressen, etwa eine Startbahn, eine Autobahnspur, ein Park oder ein Stausee, werden von der nächstgelegenen Wohn-Postleitzahl ausgefüllt. Daher erscheint ein Flughafen oder eine offene Fläche oft als ein einziges großes Polygon, und der angezeigte Wert stammt von den wenigen Postleitzahlen innerhalb des Geländes.',
|
||||||
faqBehindData3Q: 'Warum zeigen benachbarte Postleitzahlen identische Kriminalitätszahlen?',
|
faqBehindData3Q: 'Warum zeigen benachbarte Postleitzahlen identische Kriminalitätszahlen?',
|
||||||
faqBehindData3A:
|
faqBehindData3A:
|
||||||
'Polizeilich erfasste Kriminalität auf Straßenebene wird auf LSOA-Ebene veröffentlicht — kleine Nachbarschaftsgebiete mit etwa 1.500 Einwohnern. Jede Postleitzahl innerhalb derselben LSOA übernimmt dieselben Jahreszahlen, sodass eine ruhige Wohnstraße und eine Hauptstraße einen Block entfernt identische Werte zeigen können, wenn sie auf derselben Seite der Grenze liegen. Die Pro-Kopf-Rate kann in Postleitzahlen mit Krankenhäusern, Universitätsgeländen oder Industriegebieten ungewöhnlich hoch wirken, weil dort viele Vorfälle gezählt werden, aber wenige Einwohner gemeldet sind.',
|
'Polizeilich erfasste Kriminalität auf Straßenebene wird auf LSOA-Ebene veröffentlicht: kleine Nachbarschaftsgebiete mit etwa 1.500 Einwohnern. Jede Postleitzahl innerhalb derselben LSOA übernimmt dieselben Jahreszahlen, sodass eine ruhige Wohnstraße und eine Hauptstraße einen Block entfernt identische Werte zeigen können, wenn sie auf derselben Seite der Grenze liegen. Die Pro-Kopf-Rate kann in Postleitzahlen mit Krankenhäusern, Universitätsgeländen oder Industriegebieten ungewöhnlich hoch wirken, weil dort viele Vorfälle gezählt werden, aber wenige Einwohner gemeldet sind.',
|
||||||
faqBehindData4Q:
|
faqBehindData4Q:
|
||||||
'Was bedeutet die Zahl der „Schul-Einzugsgebiete“ — kann mein Kind diese Schulen besuchen?',
|
'Was bedeutet die Zahl der „Schul-Einzugsgebiete“? Kann mein Kind diese Schulen besuchen?',
|
||||||
faqBehindData4A:
|
faqBehindData4A:
|
||||||
'Jede Zahl gibt an, wie viele staatliche Schulen mit der Bewertung Gut oder Hervorragend ein modelliertes historisches Einzugsgebiet haben, das die Postleitzahl abdeckt. Wir simulieren, wie Englands entfernungsbasierte Aufnahmen Plätze vergeben: Kinder (Zensus 2021) bewerben sich an nahegelegenen Schulen und wägen dabei Entfernung gegen Ofsted-Bewertung ab; eine überbuchte Schule nimmt die nächstgelegenen Bewerber auf, bis sie voll ist — ihr Einzugsradius ist die Entfernung des zuletzt aufgenommenen Kindes, genau die „zuletzt vergebene Entfernung“, die Gemeinden veröffentlichen. Das Modell ist an Hunderten dieser veröffentlichten Werte kalibriert. Es schätzt, wo man plausibel einen Platz bekommt; es ist kein offizielles Aufnahmegebiet. Konfessionelle und selektive Aufnahmen, Geschwisterpriorität und jährliche Grenzänderungen werden nicht modelliert — prüfe Einzugsgebiete und Aufnahmeregeln daher immer bei der Schule oder Gemeinde, bevor du eine Entscheidung darauf stützt.',
|
'Jede Zahl gibt an, wie viele staatliche Schulen mit der Bewertung Gut oder Hervorragend ein modelliertes historisches Einzugsgebiet haben, das die Postleitzahl abdeckt. Wir simulieren, wie Englands entfernungsbasierte Aufnahmen Plätze vergeben: Kinder (Zensus 2021) bewerben sich an nahegelegenen Schulen und wägen dabei Entfernung gegen Ofsted-Bewertung ab; eine überbuchte Schule nimmt die nächstgelegenen Bewerber auf, bis sie voll ist: ihr Einzugsradius ist die Entfernung des zuletzt aufgenommenen Kindes, genau die „zuletzt vergebene Entfernung“, die Gemeinden veröffentlichen. Das Modell ist an Hunderten dieser veröffentlichten Werte kalibriert. Es schätzt, wo man plausibel einen Platz bekommt; es ist kein offizielles Aufnahmegebiet. Konfessionelle und selektive Aufnahmen, Geschwisterpriorität und jährliche Grenzänderungen werden nicht modelliert. Prüfe Einzugsgebiete und Aufnahmeregeln daher immer bei der Schule oder Gemeinde, bevor du eine Entscheidung darauf stützt.',
|
||||||
faqBehindData5Q:
|
faqBehindData5Q:
|
||||||
'Warum zeigt eine Postleitzahl „Gigabit“, wenn nicht jedes Haus Glasfaser hat?',
|
'Warum zeigt eine Postleitzahl „Gigabit“, wenn nicht jedes Haus Glasfaser hat?',
|
||||||
faqBehindData5A:
|
faqBehindData5A:
|
||||||
|
|
@ -1509,6 +1540,7 @@ const de: Translations = {
|
||||||
|
|
||||||
// ── Invite Page ────────────────────────────────────
|
// ── Invite Page ────────────────────────────────────
|
||||||
invitePage: {
|
invitePage: {
|
||||||
|
couldNotValidateTitle: 'Einladung konnte nicht überprüft werden',
|
||||||
youreInvited: 'Du bist eingeladen!',
|
youreInvited: 'Du bist eingeladen!',
|
||||||
specialOffer: 'Sonderangebot!',
|
specialOffer: 'Sonderangebot!',
|
||||||
invitedByFree: '{{name}} hat dich eingeladen, kostenlosen lebenslangen Zugang zu erhalten.',
|
invitedByFree: '{{name}} hat dich eingeladen, kostenlosen lebenslangen Zugang zu erhalten.',
|
||||||
|
|
@ -1569,17 +1601,17 @@ const de: Translations = {
|
||||||
treesOutsideWoodlands: {
|
treesOutsideWoodlands: {
|
||||||
label: 'Bäume & Wald',
|
label: 'Bäume & Wald',
|
||||||
detail:
|
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.',
|
'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: {
|
propertyBorders: {
|
||||||
label: 'Grundstücksgrenzen',
|
label: 'Grundstücksgrenzen',
|
||||||
detail:
|
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 85–90 % 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.',
|
'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 85–90 % 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: {
|
newDevelopments: {
|
||||||
label: 'Neubauprojekte',
|
label: 'Neubauprojekte',
|
||||||
detail:
|
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.',
|
'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.',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
@ -1727,7 +1759,7 @@ const de: Translations = {
|
||||||
'Housing Conditions Score': 'Wert der Wohnbedingungen',
|
'Housing Conditions Score': 'Wert der Wohnbedingungen',
|
||||||
'Air Quality and Road Safety Score': 'Wert für Luftqualität und Verkehrssicherheit',
|
'Air Quality and Road Safety Score': 'Wert für Luftqualität und Verkehrssicherheit',
|
||||||
|
|
||||||
// ─ Feature names (Crime) — bevölkerungsnormierte Rate, 7 Jahre & 2 Jahre ─
|
// ─ Feature names (Crime): bevölkerungsnormierte Rate, 7 Jahre & 2 Jahre ─
|
||||||
'Serious crime (/yr, 7y)': 'Schwere Straftaten (pro Jahr, 7 J.)',
|
'Serious crime (/yr, 7y)': 'Schwere Straftaten (pro Jahr, 7 J.)',
|
||||||
'Serious crime (/yr, 2y)': 'Schwere Straftaten (pro Jahr, 2 J.)',
|
'Serious crime (/yr, 2y)': 'Schwere Straftaten (pro Jahr, 2 J.)',
|
||||||
'Minor crime (/yr, 7y)': 'Leichte Straftaten (pro Jahr, 7 J.)',
|
'Minor crime (/yr, 7y)': 'Leichte Straftaten (pro Jahr, 7 J.)',
|
||||||
|
|
@ -1788,6 +1820,8 @@ const de: Translations = {
|
||||||
'% Owner occupied': '% Wohneigentum',
|
'% Owner occupied': '% Wohneigentum',
|
||||||
'% Social rent': '% Sozialwohnung',
|
'% Social rent': '% Sozialwohnung',
|
||||||
'% Private rent': '% Privatmiete',
|
'% Private rent': '% Privatmiete',
|
||||||
|
'% Council housing': '% Kommunalwohnung',
|
||||||
|
'% Ex-council': '% Ehemalige Kommunalwohnung',
|
||||||
'% White': '% weiß',
|
'% White': '% weiß',
|
||||||
'% South Asian': '% südasiatisch',
|
'% South Asian': '% südasiatisch',
|
||||||
'% Black': '% schwarz',
|
'% Black': '% schwarz',
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@ const en = {
|
||||||
},
|
},
|
||||||
// ── Common ──────────────────────────────────────────
|
// ── Common ──────────────────────────────────────────
|
||||||
common: {
|
common: {
|
||||||
|
retry: 'Retry',
|
||||||
save: 'Save',
|
save: 'Save',
|
||||||
update: 'Update',
|
update: 'Update',
|
||||||
cancel: 'Cancel',
|
cancel: 'Cancel',
|
||||||
|
|
@ -90,7 +91,7 @@ const en = {
|
||||||
modeFiltersHint: 'Export every postcode visible on the map that matches your current filters.',
|
modeFiltersHint: 'Export every postcode visible on the map that matches your current filters.',
|
||||||
modeList: 'List of postcodes',
|
modeList: 'List of postcodes',
|
||||||
modeListHint:
|
modeListHint:
|
||||||
'Add your own postcodes one by one — we tidy up the spacing and capitalisation for you.',
|
'Add your own postcodes one by one. We tidy up the spacing and capitalisation for you.',
|
||||||
listLabel: 'Postcodes',
|
listLabel: 'Postcodes',
|
||||||
listPlaceholder: 'e.g. SW1A 1AA',
|
listPlaceholder: 'e.g. SW1A 1AA',
|
||||||
addRow: 'Add postcode',
|
addRow: 'Add postcode',
|
||||||
|
|
@ -101,6 +102,7 @@ const en = {
|
||||||
|
|
||||||
// ── User Menu ──────────────────────────────────────
|
// ── User Menu ──────────────────────────────────────
|
||||||
userMenu: {
|
userMenu: {
|
||||||
|
accountMenu: 'Account menu',
|
||||||
fullAccess: 'Full Access',
|
fullAccess: 'Full Access',
|
||||||
demo: 'Demo',
|
demo: 'Demo',
|
||||||
themeLight: 'Theme: Light',
|
themeLight: 'Theme: Light',
|
||||||
|
|
@ -124,7 +126,7 @@ const en = {
|
||||||
'Each page is built around real shortlisting work: removing impossible places, comparing the remaining postcodes, and deciding what to validate next.',
|
'Each page is built around real shortlisting work: removing impossible places, comparing the remaining postcodes, and deciding what to validate next.',
|
||||||
howToUseIt: 'How to use it',
|
howToUseIt: 'How to use it',
|
||||||
howToUseItDesc:
|
howToUseItDesc:
|
||||||
'Use these workflows to make the page useful before you open a listing portal or book a viewing.',
|
'Use these workflows to rank postcodes by value, narrow your shortlist, and decide which areas are worth a closer look.',
|
||||||
methodAndLimitations: 'Method and limitations',
|
methodAndLimitations: 'Method and limitations',
|
||||||
methodAndLimitationsDesc:
|
methodAndLimitationsDesc:
|
||||||
'The data is designed for comparison and shortlisting. Important decisions still need current listings, professional checks, and direct local validation.',
|
'The data is designed for comparison and shortlisting. Important decisions still need current listings, professional checks, and direct local validation.',
|
||||||
|
|
@ -596,12 +598,22 @@ const en = {
|
||||||
|
|
||||||
// ── Auth Modal ─────────────────────────────────────
|
// ── Auth Modal ─────────────────────────────────────
|
||||||
auth: {
|
auth: {
|
||||||
|
errorRateLimited: 'Too many attempts. Please wait a minute and try again.',
|
||||||
|
errorNetwork: 'Could not reach the server. Check your connection and try again.',
|
||||||
|
errorEmailTaken: 'An account with this email already exists.',
|
||||||
|
errorPasswordWeak: 'Password must be at least 8 characters.',
|
||||||
|
errorEmailInvalid: 'Please enter a valid email address.',
|
||||||
|
errorInvalidCredentials: 'Incorrect email or password.',
|
||||||
|
logInInstead: 'Log in instead',
|
||||||
|
accountCreatedPleaseLogIn: 'Account created. Please log in to continue.',
|
||||||
|
accountCreatedRateLimited:
|
||||||
|
'Account created, but too many attempts just now. Please wait a moment, then log in.',
|
||||||
logIn: 'Log in',
|
logIn: 'Log in',
|
||||||
createAccount: 'Create account',
|
createAccount: 'Create account',
|
||||||
resetPassword: 'Reset password',
|
resetPassword: 'Reset password',
|
||||||
valueProp: 'Save searches, bookmark properties, and build a shortlist of areas that fit.',
|
valueProp: 'Save searches, bookmark properties, and build a shortlist of areas that fit.',
|
||||||
dashboardActionsValueProp:
|
dashboardActionsValueProp:
|
||||||
'Create a free account to save, share and export your searches — no card needed.',
|
'Create a free account to save, share and export your searches. No card needed.',
|
||||||
continueWithGoogle: 'Continue with Google',
|
continueWithGoogle: 'Continue with Google',
|
||||||
email: 'Email',
|
email: 'Email',
|
||||||
emailPlaceholder: 'you@example.com',
|
emailPlaceholder: 'you@example.com',
|
||||||
|
|
@ -623,19 +635,19 @@ const en = {
|
||||||
|
|
||||||
// ── Upgrade Modal ──────────────────────────────────
|
// ── Upgrade Modal ──────────────────────────────────
|
||||||
upgrade: {
|
upgrade: {
|
||||||
// Registered (logged-in, non-paying) users — the lifetime upsell.
|
// Registered (logged-in, non-paying) users: the lifetime upsell.
|
||||||
title: 'Stack unlimited filters',
|
title: 'Stack unlimited filters',
|
||||||
description:
|
description:
|
||||||
'You’ve used all 5 filters on your free account. Get lifetime access to stack unlimited filters across every postcode and neighbourhood in England. One payment, forever.',
|
'You’ve used all 5 filters on your free account. Get lifetime access to stack unlimited filters across every postcode and neighbourhood in England. One payment, forever.',
|
||||||
// Anonymous users — create a free account first.
|
// Anonymous users: create a free account first.
|
||||||
titleRegister: 'Create a free account',
|
titleRegister: 'Create a free account',
|
||||||
descriptionRegister:
|
descriptionRegister:
|
||||||
'Free accounts include up to 5 filters plus save, share and export — no card needed. Want unlimited filters across all of England? Go lifetime.',
|
'Free accounts include up to 5 filters plus save, share and export. No card needed. Want unlimited filters across all of England? Go lifetime.',
|
||||||
descriptionSharedRegister:
|
descriptionSharedRegister:
|
||||||
'This is a shared search. Create a free account to build your own with up to 5 filters and save, share & export — or go lifetime for unlimited.',
|
'This is a shared search. Create a free account to build your own with up to 5 filters and save, share & export, or go lifetime for unlimited.',
|
||||||
registerFree: 'Create free account',
|
registerFree: 'Create free account',
|
||||||
lifetimeUpsell: 'Want unlimited filters?',
|
lifetimeUpsell: 'Want unlimited filters?',
|
||||||
goLifetime: 'Get lifetime access — {{price}}',
|
goLifetime: 'Get lifetime access for {{price}}',
|
||||||
free: 'Free',
|
free: 'Free',
|
||||||
freeForEarly: 'Free for early adopters. No credit card required.',
|
freeForEarly: 'Free for early adopters. No credit card required.',
|
||||||
oneTimePayment: 'One-time payment. Lifetime access.',
|
oneTimePayment: 'One-time payment. Lifetime access.',
|
||||||
|
|
@ -686,7 +698,7 @@ const en = {
|
||||||
upgradeToFullMap: 'Upgrade to full map',
|
upgradeToFullMap: 'Upgrade to full map',
|
||||||
registerPrompt:
|
registerPrompt:
|
||||||
'Create a free account to combine up to 5 filters and save, share & export your searches.',
|
'Create a free account to combine up to 5 filters and save, share & export your searches.',
|
||||||
registerSubPrompt: 'Free — no card needed. Unlimited filters with lifetime access.',
|
registerSubPrompt: 'Free, no card needed. Unlimited filters with lifetime access.',
|
||||||
registerCta: 'Create free account',
|
registerCta: 'Create free account',
|
||||||
chooseFilters: 'Click Add to filter. The small buttons show data details or colour the map.',
|
chooseFilters: 'Click Add to filter. The small buttons show data details or colour the map.',
|
||||||
searchFeatures: 'Search features…',
|
searchFeatures: 'Search features…',
|
||||||
|
|
@ -725,6 +737,11 @@ const en = {
|
||||||
crimeType: 'Crime type',
|
crimeType: 'Crime type',
|
||||||
qualificationLevel: 'Qualification level',
|
qualificationLevel: 'Qualification level',
|
||||||
tenureType: 'Tenure type',
|
tenureType: 'Tenure type',
|
||||||
|
councilType: 'Council housing type',
|
||||||
|
councilStatus: 'Type',
|
||||||
|
councilCurrent: 'Current',
|
||||||
|
councilEx: 'Ex-council',
|
||||||
|
councilBoth: 'Both',
|
||||||
crimeWindow: 'Averaging period',
|
crimeWindow: 'Averaging period',
|
||||||
crimeWindow7y: '7-year',
|
crimeWindow7y: '7-year',
|
||||||
crimeWindow2y: '2-year',
|
crimeWindow2y: '2-year',
|
||||||
|
|
@ -766,15 +783,15 @@ const en = {
|
||||||
noChange: 'No change',
|
noChange: 'No change',
|
||||||
noChangeTitle: 'No-change journeys only',
|
noChangeTitle: 'No-change journeys only',
|
||||||
noChangeDesc:
|
noChangeDesc:
|
||||||
'Restricts to journeys with <strong>no transfers</strong> — walk, board one transit service, then walk to the destination. Useful when you want a single straight-through commute.',
|
'Restricts to journeys with <strong>no transfers</strong>: walk, board one transit service, then walk to the destination. Useful when you want a single straight-through commute.',
|
||||||
oneChange: 'One change',
|
oneChange: 'One change',
|
||||||
oneChangeTitle: 'One-change journeys',
|
oneChangeTitle: 'One-change journeys',
|
||||||
oneChangeDesc:
|
oneChangeDesc:
|
||||||
'Allows journeys with <strong>at most one transfer</strong> — so a single change between two transit services is fine, but no more. A middle ground between no-change and unrestricted journeys.',
|
'Allows journeys with <strong>at most one transfer</strong>: a single change between two transit services is fine, but no more. A middle ground between no-change and unrestricted journeys.',
|
||||||
noBuses: 'No buses',
|
noBuses: 'No buses',
|
||||||
noBusesTitle: 'Excluding buses',
|
noBusesTitle: 'Excluding buses',
|
||||||
noBusesDesc:
|
noBusesDesc:
|
||||||
'Drops bus services from the allowed transit modes — <strong>rail, tube, tram and ferry only</strong>. Helpful for filtering to journeys that avoid traffic delays.',
|
'Drops bus services from the allowed transit modes: <strong>rail, tube, tram and ferry only</strong>. Helpful for filtering to journeys that avoid traffic delays.',
|
||||||
previewOnMap: 'Preview on map',
|
previewOnMap: 'Preview on map',
|
||||||
stopPreviewing: 'Stop previewing',
|
stopPreviewing: 'Stop previewing',
|
||||||
removeTravelTime: 'Remove travel time',
|
removeTravelTime: 'Remove travel time',
|
||||||
|
|
@ -849,8 +866,11 @@ const en = {
|
||||||
},
|
},
|
||||||
actualListings: {
|
actualListings: {
|
||||||
label: 'Listings',
|
label: 'Listings',
|
||||||
show: 'Show actual listings',
|
modes: {
|
||||||
hide: 'Hide actual listings',
|
new: 'New builds',
|
||||||
|
nonNew: 'Non-new',
|
||||||
|
hint: '“New builds” shows new-build developments; “Non-new” shows resale and other listings.',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
poi: {
|
poi: {
|
||||||
zoomInToSeeDetails: 'Zoom in to see details',
|
zoomInToSeeDetails: 'Zoom in to see details',
|
||||||
|
|
@ -879,6 +899,7 @@ const en = {
|
||||||
historyTitle: 'History',
|
historyTitle: 'History',
|
||||||
historySale: 'Sale',
|
historySale: 'Sale',
|
||||||
historyBuilt: 'Built',
|
historyBuilt: 'Built',
|
||||||
|
historyNewBuild: 'New build',
|
||||||
tenureOwnerOccupied: 'Owner-occupied',
|
tenureOwnerOccupied: 'Owner-occupied',
|
||||||
tenureRentedPrivate: 'Privately rented',
|
tenureRentedPrivate: 'Privately rented',
|
||||||
tenureRentedSocial: 'Social housing',
|
tenureRentedSocial: 'Social housing',
|
||||||
|
|
@ -995,17 +1016,19 @@ const en = {
|
||||||
heroEyebrow: 'For buyers who refuse to overpay for a postcode’s reputation',
|
heroEyebrow: 'For buyers who refuse to overpay for a postcode’s reputation',
|
||||||
heroTitle1: 'Find the',
|
heroTitle1: 'Find the',
|
||||||
heroTitle2: 'hidden-gem postcode',
|
heroTitle2: 'hidden-gem postcode',
|
||||||
heroTitle3: 'Best £/sqm, schools and commute for the money.',
|
heroTitle3: 'Same schools, same commute, quietly cheaper.',
|
||||||
heroSubtitle:
|
heroSubtitle:
|
||||||
'Across England, two streets can share the same schools and commute yet sell for very different money.',
|
'Two streets can share a school, a station and a build year, then sell tens of thousands apart. One of them is mispriced. We find which.',
|
||||||
heroDescription:
|
heroDescription:
|
||||||
'Set your budget and must-haves. Perfect Postcode ranks every postcode in England on price per square metre, schools, commute and safety, surfacing the underpriced ones with the evidence behind each pick.',
|
'Set your budget and your non-negotiables. Perfect Postcode ranks every postcode in England by what each pound actually buys (floor space, schools, commute and safety), with the evidence behind every pick.',
|
||||||
exploreTheMap: 'Find my best-value postcodes',
|
exploreTheMap: 'Find my hidden-gem postcode',
|
||||||
seeTheDifference: 'See how it works',
|
seeTheDifference: 'See a real hidden gem',
|
||||||
|
freeToExplore: 'Explore the live map free, no sign-up, no card.',
|
||||||
|
dataSourcesLabel: 'Built on official records',
|
||||||
|
dataSources: 'Land Registry · ONS · Ofsted · DfT · Ordnance Survey · Police.uk',
|
||||||
productDemoLabel: 'Perfect Postcode product demo',
|
productDemoLabel: 'Perfect Postcode product demo',
|
||||||
playProductDemo: 'Play Perfect Postcode product demo',
|
playProductDemo: 'Play Perfect Postcode product demo',
|
||||||
scrollToProductDemo: 'Scroll to product demo',
|
scrollToProductDemo: 'Scroll to product demo',
|
||||||
showcaseHeader: 'How it works',
|
|
||||||
showcaseContext: 'How Perfect Postcode works',
|
showcaseContext: 'How Perfect Postcode works',
|
||||||
showcaseFeaturePriceShort: 'Price',
|
showcaseFeaturePriceShort: 'Price',
|
||||||
showcaseFeatureNoiseShort: 'Noise',
|
showcaseFeatureNoiseShort: 'Noise',
|
||||||
|
|
@ -1032,80 +1055,81 @@ const en = {
|
||||||
showcaseStep1Title: 'Turn vague needs into a tight search',
|
showcaseStep1Title: 'Turn vague needs into a tight search',
|
||||||
showcaseStep1Body:
|
showcaseStep1Body:
|
||||||
'Set what matters and see exactly how many wrong-fit postcodes each requirement keeps out of your search.',
|
'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',
|
showcaseStep2Tab: 'Match',
|
||||||
showcaseStep2Title: 'Let the map surface places you wouldn’t have typed',
|
showcaseStep2Title: 'Watch the underpriced postcodes light up',
|
||||||
showcaseStep2Body:
|
showcaseStep2Body:
|
||||||
'Rank England by value for money, not by area names you already know. The underpriced pockets — strong on £/sqm, schools and commute — rise to the top.',
|
'Rank England by value for money, not by area names you already know. The underpriced pockets (strong on £/sqm, schools and commute) rise to the top.',
|
||||||
showcaseStep2Region: 'Greater London',
|
showcaseStep2Region: 'Greater London',
|
||||||
showcaseStep2Sources: 'Land Registry · ONS · Ofsted · DfT',
|
showcaseStep2Sources: 'Land Registry · ONS · Ofsted · DfT',
|
||||||
showcaseStep2ClustersLabel: 'Matching clusters',
|
|
||||||
showcaseStep3Tab: 'Inspect',
|
showcaseStep3Tab: 'Inspect',
|
||||||
showcaseStep3Title: 'Inspect why a postcode made the cut',
|
showcaseStep3Title: 'Inspect why a postcode made the cut',
|
||||||
showcaseStep3Body:
|
showcaseStep3Body:
|
||||||
'Open any matching area and check prices, safety, schools, broadband, and trade-offs in one pane before you spend a weekend there.',
|
'Open any matching area and check prices, safety, schools, broadband, and trade-offs in one pane before you spend a weekend there.',
|
||||||
showcaseStep3HeaderArea: 'Your perfect postcode',
|
|
||||||
showcaseStep3HeaderFit: 'Neighbourhood evidence',
|
|
||||||
showcaseStep3Stat1Label: 'Sold price trend',
|
|
||||||
showcaseStep3Stat2Label: 'Crime rate',
|
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',
|
showcaseStep4Tab: 'Scout',
|
||||||
showcaseStep4Title: 'Scout it out yourself',
|
showcaseStep4Title: 'Scout it out yourself',
|
||||||
showcaseStep4Body:
|
showcaseStep4Body:
|
||||||
'Take your top three postcodes into the real world. Walk the streets, test the commute, and compare viewings with context.',
|
'Take your top three postcodes into the real world. Walk the streets, test the commute, and compare viewings with context.',
|
||||||
showcaseStep4FileName: 'areas-to-scout.xlsx',
|
showcaseStep4FileName: 'areas-to-scout.xlsx',
|
||||||
showcaseStep4ExportLabel: 'Export to Excel',
|
|
||||||
showcaseStep4ColPostcode: 'Postcode',
|
showcaseStep4ColPostcode: 'Postcode',
|
||||||
showcaseStep4ColScore: 'Fit',
|
showcaseStep4ColScore: 'Fit',
|
||||||
showcaseStep4ColCommute: 'Commute',
|
showcaseStep4ColCommute: 'Commute',
|
||||||
showcaseStep4ColPrice: 'Median sold',
|
showcaseStep4ColPrice: '£/sqm',
|
||||||
showcaseStep4Conclusion: 'Start scouting from here.',
|
showcaseStep4Conclusion: 'Start scouting from here.',
|
||||||
statProperties: 'historical sales',
|
statProperties: 'historical sales',
|
||||||
statFilters: 'combinable filters',
|
statFilters: 'combinable filters',
|
||||||
statEvery: 'Every',
|
statEvery: 'Every',
|
||||||
statPostcodeInEngland: 'postcode in England',
|
statPostcodeInEngland: 'postcode in England',
|
||||||
coverageNote:
|
coverageNote:
|
||||||
'Covers every postcode in England — 200+ data fields each. Scotland & Wales are on the roadmap.',
|
'Covers every postcode in England, with 200+ data fields each. Scotland & Wales are on the roadmap.',
|
||||||
priceStrip: 'Lifetime access, currently {{price}} — the price rises as tiers fill.',
|
priceStrip: 'Pay once for lifetime access, currently {{price}}, rising as each tier fills.',
|
||||||
priceStripSpots: '{{count}} spot left at this price.',
|
priceStripSpots: '{{count}} spot left at this price.',
|
||||||
priceStripSpotsPlural: '{{count}} spots left at this price.',
|
priceStripSpotsPlural: '{{count}} spots left at this price.',
|
||||||
priceStripCta: 'See pricing',
|
priceStripCta: 'See pricing',
|
||||||
ourPhilosophy: 'Reputation is priced in. Value isn’t yet.',
|
ourPhilosophy: 'Reputation is priced in. Value isn’t yet.',
|
||||||
philosophyP1:
|
philosophyP1:
|
||||||
'A postcode’s price is partly its fundamentals and partly its reputation. People pay up for names they know, while the postcode one street over — same schools, same commute — sits quietly cheaper because nobody has bid it up. Spotting that gap means cross-checking sold prices, Ofsted, crime, noise and floor areas tab by tab.',
|
'Part of a postcode’s price is its bricks, its catchment and its commute. The rest is just the name. Buyers bid up the postcodes they’ve heard of, so the road behind (identical on every measure that moves price) sits quietly cheaper. Finding that gap by hand means a dozen browser tabs: sold prices, Ofsted, crime, noise, floor areas.',
|
||||||
philosophyP2:
|
philosophyP2:
|
||||||
'Perfect Postcode ranks by value instead. Tell the map your budget and must-haves, and it surfaces the postcodes with the best £/sqm, schools and commute for the money. Then go test it in person.',
|
'Perfect Postcode does the cross-checking for you. Tell the map your budget and your non-negotiables; it weighs every postcode in England on the things that move price and puts the underpriced ones on top. Then go and walk it.',
|
||||||
streetTitle: 'Value changes street by street',
|
streetTitle: 'The gap is street by street',
|
||||||
streetIntro:
|
streetIntro:
|
||||||
'Broad area names hide where the value sits: the cheaper station side, the quieter road, the same school catchment, and what near-identical homes sold for per square metre.',
|
'Broad area names hide where the bargains sit: the cheaper station side, the quieter road, the same school catchment, and what near-identical homes actually sold for per square metre.',
|
||||||
streetCard1Title: 'Find the cheaper twin',
|
streetCard1Title: 'Find the cheaper twin',
|
||||||
streetCard1Body:
|
streetCard1Body:
|
||||||
'Surface the postcodes with the same schools, commute and build as the names everyone pays a premium for — minus the premium, and minus the “up-and-coming” hype.',
|
'Every famous postcode has a quieter neighbour with the same catchment, the same station and the same era of housing, without the premium and without the “up-and-coming” mark-up. We set the two side by side so the gap is impossible to miss.',
|
||||||
streetCard2Title: 'See what your money actually buys',
|
streetCard2Title: 'See what your money actually buys',
|
||||||
streetCard2Body:
|
streetCard2Body:
|
||||||
'Compare £/sqm, sold prices, space, commute, safety, schools, broadband, noise and energy ratings side by side, before you spend weekends between viewings.',
|
'Floor space, sold prices, commute, crime, schools, broadband, noise and energy ratings on one screen, not eight tabs and a spreadsheet. Decide what’s worth a Saturday before you spend the Saturday.',
|
||||||
othersVs: 'Others vs',
|
othersVs: 'Others vs',
|
||||||
checkMyPostcode: 'Listing portals',
|
checkMyPostcode: 'Listing portals',
|
||||||
areaGuides: 'Postcode reports',
|
areaGuides: 'Postcode reports',
|
||||||
compSearchWithout: 'Rank postcodes by value, not by reputation',
|
compSearchWithout: 'Ranked by what you get, not who’s heard of it',
|
||||||
compSearchWithoutSub: '(best £/sqm for your needs, not the name)',
|
compSearchWithoutSub: '(the cheaper twin for your needs, not the name)',
|
||||||
compAreaData: 'Postcode-level neighbourhood evidence',
|
compAreaData: 'Postcode-level neighbourhood evidence',
|
||||||
compAreaDataSub: '(crime, schools, noise, broadband, amenities)',
|
compAreaDataSub: '(crime, schools, noise, broadband, amenities)',
|
||||||
compPropertyData: 'Property-level history',
|
compPropertyData: 'Property-level history',
|
||||||
compPropertyDataSub: '(sold prices, EPC, floor area, estimated value)',
|
compPropertyDataSub: '(sold prices, EPC, floor area, estimated value)',
|
||||||
compFilters: '40+ filters working together',
|
compFilters: '40+ filters working together',
|
||||||
compFiltersSub: '(not one postcode or one listing at a time)',
|
compFiltersSub: '(not one postcode or one listing at a time)',
|
||||||
|
compListings: 'Live listings, photos and viewings',
|
||||||
|
compListingsSub: '(the day-to-day of buying a specific home)',
|
||||||
|
twinBadge: 'Real example',
|
||||||
|
twinTitle: 'The same life, one postcode cheaper',
|
||||||
|
twinIntro:
|
||||||
|
'Two North London neighbours, 1.3 km apart: flats with comparable primary-school catchments and the same ~30-minute commute, yet priced very differently per square metre.',
|
||||||
|
twinPriceyLabel: 'The name everyone knows',
|
||||||
|
twinValueLabel: 'Its quieter neighbour',
|
||||||
|
twinPerSqm: '{{value}}/sqm',
|
||||||
|
twinSameSchool: 'Both in Outstanding-rated primary catchments',
|
||||||
|
twinSameCommute: 'Both ~30 min to central London by transit',
|
||||||
|
twinDelta: '{{percent}} less per square metre',
|
||||||
|
twinFootnote:
|
||||||
|
'A real example from our data: median £/sqm for flats sold since 2021. Explore the live map to find your own.',
|
||||||
|
twinCta: 'Find a gem like this near me',
|
||||||
ctaTitle: 'Stop overpaying for a name.',
|
ctaTitle: 'Stop overpaying for a name.',
|
||||||
ctaDescription:
|
ctaDescription:
|
||||||
'Build a shortlist of the best-value postcodes for your budget, then confirm it in person.',
|
'Build your shortlist on the live map, free. When you’re convinced, unlock every filter for life. Pay once, no subscription.',
|
||||||
|
guaranteeNote: 'Pay once. No subscription, ever. 30-day money-back guarantee.',
|
||||||
},
|
},
|
||||||
|
|
||||||
// ── Pricing Page ───────────────────────────────────
|
// ── Pricing Page ───────────────────────────────────
|
||||||
|
|
@ -1132,12 +1156,15 @@ const en = {
|
||||||
},
|
},
|
||||||
|
|
||||||
pricingPage: {
|
pricingPage: {
|
||||||
|
cachedNotice: 'We couldn’t refresh live pricing, so these figures may be out of date.',
|
||||||
|
scrollPrev: 'Show previous plans',
|
||||||
|
scrollNext: 'Show more plans',
|
||||||
title: 'Buy with a better search area',
|
title: 'Buy with a better search area',
|
||||||
subtitle:
|
subtitle:
|
||||||
'Lifetime access to the map that helps you find where to look before you book viewings.',
|
'Lifetime access to the map that helps you find where to look before you book viewings.',
|
||||||
costContext:
|
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.',
|
'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: 'Costs less than a tenth of a survey — and shapes a far bigger decision.',
|
lessThanSurvey: 'Costs less than a tenth of a survey, and shapes a far bigger decision.',
|
||||||
currentTier: 'Current tier',
|
currentTier: 'Current tier',
|
||||||
firstNUsers: 'First {{count}} users',
|
firstNUsers: 'First {{count}} users',
|
||||||
everyoneAfter: 'Everyone after',
|
everyoneAfter: 'Everyone after',
|
||||||
|
|
@ -1148,7 +1175,7 @@ const en = {
|
||||||
filled: 'Filled',
|
filled: 'Filled',
|
||||||
openDashboard: 'Open dashboard',
|
openDashboard: 'Open dashboard',
|
||||||
getStarted: 'Get started',
|
getStarted: 'Get started',
|
||||||
getStartedPrice: 'Get started – {{price}}',
|
getStartedPrice: 'Get started for {{price}}',
|
||||||
noCreditCard: 'No credit card required',
|
noCreditCard: 'No credit card required',
|
||||||
moneyBack: '14-day money-back guarantee.',
|
moneyBack: '14-day money-back guarantee.',
|
||||||
|
|
||||||
|
|
@ -1179,7 +1206,7 @@ const en = {
|
||||||
videos: 'Videos',
|
videos: 'Videos',
|
||||||
videosTitle: 'Social media videos',
|
videosTitle: 'Social media videos',
|
||||||
videosIntro:
|
videosIntro:
|
||||||
'Short clips from our social channels — each one shows a single search in action, from quiet streets to school catchments and commute times.',
|
'Short clips from our social channels: each one shows a single search in action, from quiet streets to school catchments and commute times.',
|
||||||
video01Title: 'Find the cheaper twin',
|
video01Title: 'Find the cheaper twin',
|
||||||
video01Desc:
|
video01Desc:
|
||||||
'Type your whole house brief in one plain sentence and watch every matching postcode in England sort by value, surfacing the cheaper twin everyone overlooked.',
|
'Type your whole house brief in one plain sentence and watch every matching postcode in England sort by value, surfacing the cheaper twin everyone overlooked.',
|
||||||
|
|
@ -1188,7 +1215,7 @@ const en = {
|
||||||
'Colour London by commute to the centre, prune to a 20-minute ride, and watch identical journeys split into the names everyone knows and quieter postcodes nobody bid up.',
|
'Colour London by commute to the centre, prune to a 20-minute ride, and watch identical journeys split into the names everyone knows and quieter postcodes nobody bid up.',
|
||||||
video03Title: 'The postcode evidence file',
|
video03Title: 'The postcode evidence file',
|
||||||
video03Desc:
|
video03Desc:
|
||||||
'Tap any postcode and a panel opens with its sold prices, school catchments, crime and Street View — so you can tell whether you are paying for value or just a reputation.',
|
'Tap any postcode and a panel opens with its sold prices, school catchments, crime and Street View, so you can tell whether you are paying for value or just a reputation.',
|
||||||
video04Title: 'The overlooked quiet street',
|
video04Title: 'The overlooked quiet street',
|
||||||
video04Desc:
|
video04Desc:
|
||||||
'Famous postcodes price in their reputation, but a listing photo stays silent on noise. Filter by decibels to find the genuinely quiet street one over that never paid the premium.',
|
'Famous postcodes price in their reputation, but a listing photo stays silent on noise. Filter by decibels to find the genuinely quiet street one over that never paid the premium.',
|
||||||
|
|
@ -1197,7 +1224,7 @@ const en = {
|
||||||
'A Leeds family search for a good primary, low crime and a budget under £350k surfaces the quietly cheaper streets that share the very same catchment.',
|
'A Leeds family search for a good primary, low crime and a budget under £350k surfaces the quietly cheaper streets that share the very same catchment.',
|
||||||
video06Title: 'The Waitrose effect, priced in',
|
video06Title: 'The Waitrose effect, priced in',
|
||||||
video06Desc:
|
video06Desc:
|
||||||
'Walking distance to a Waitrose, a tube station and a park is a priced-in premium — find the nearby postcodes with the same amenities for less per square metre.',
|
'Walking distance to a Waitrose, a tube station and a park is a priced-in premium. Find the nearby postcodes with the same amenities for less per square metre.',
|
||||||
video07Title: 'A value map for renters',
|
video07Title: 'A value map for renters',
|
||||||
video07Desc:
|
video07Desc:
|
||||||
'Big-name postcodes cost more to rent, too. Set your rent, commute and a quiet street, and see which London postcodes actually fit the money.',
|
'Big-name postcodes cost more to rent, too. Set your rent, commute and a quiet street, and see which London postcodes actually fit the money.',
|
||||||
|
|
@ -1309,7 +1336,7 @@ const en = {
|
||||||
faqPricingTitle: 'Access',
|
faqPricingTitle: 'Access',
|
||||||
faqTipsTitle: 'Map Tips',
|
faqTipsTitle: 'Map Tips',
|
||||||
faqBehindDataTitle: 'Behind the Data',
|
faqBehindDataTitle: 'Behind the Data',
|
||||||
// FAQ items — Finding Your Area
|
// FAQ items:Finding Your Area
|
||||||
faqFinding1Q: 'Where should I look once the obvious areas are too expensive?',
|
faqFinding1Q: 'Where should I look once the obvious areas are too expensive?',
|
||||||
faqFinding1A:
|
faqFinding1A:
|
||||||
'Start with the things you can’t compromise on: budget, home type, space, commute, schools, safety, noise, broadband, parks, and anything else that matters. The map hides places that don’t fit, so less obvious areas can surface before you start scrolling listings.',
|
'Start with the things you can’t compromise on: budget, home type, space, commute, schools, safety, noise, broadband, parks, and anything else that matters. The map hides places that don’t fit, so less obvious areas can surface before you start scrolling listings.',
|
||||||
|
|
@ -1319,7 +1346,7 @@ const en = {
|
||||||
faqFinding3Q: 'What should I do when my search returns too many or too few areas?',
|
faqFinding3Q: 'What should I do when my search returns too many or too few areas?',
|
||||||
faqFinding3A:
|
faqFinding3A:
|
||||||
'Keep your must-haves in place, then colour the map by one thing you want to compare, such as price per square metre, road noise, school score, or commute time. If almost nothing is left, loosen one slider and see which change opens up more options.',
|
'Keep your must-haves in place, then colour the map by one thing you want to compare, such as price per square metre, road noise, school score, or commute time. If almost nothing is left, loosen one slider and see which change opens up more options.',
|
||||||
// FAQ items — Commute and Travel
|
// FAQ items:Commute and Travel
|
||||||
faqCommute1Q: 'How are the travel times calculated?',
|
faqCommute1Q: 'How are the travel times calculated?',
|
||||||
faqCommute1A:
|
faqCommute1A:
|
||||||
'Travel times are calculated in advance for each saved destination. We work out which postcodes can reach that destination by car, bike, walking, or public transport, then save those results so the map can respond quickly while you filter.',
|
'Travel times are calculated in advance for each saved destination. We work out which postcodes can reach that destination by car, bike, walking, or public transport, then save those results so the map can respond quickly while you filter.',
|
||||||
|
|
@ -1329,28 +1356,28 @@ const en = {
|
||||||
faqCommute3Q: 'When should I use the Best case button?',
|
faqCommute3Q: 'When should I use the Best case button?',
|
||||||
faqCommute3A:
|
faqCommute3A:
|
||||||
'Use the Best case button on public-transport searches when you want to see the journey with a well-timed departure and good connections. Leave it off for the everyday comparison, because the normal setting is closer to what you should expect most days.',
|
'Use the Best case button on public-transport searches when you want to see the journey with a well-timed departure and good connections. Leave it off for the everyday comparison, because the normal setting is closer to what you should expect most days.',
|
||||||
// FAQ items — Budget and Value
|
// FAQ items:Budget and Value
|
||||||
faqBudget1Q: 'How do you estimate current property prices?',
|
faqBudget1Q: 'How do you estimate current property prices?',
|
||||||
faqBudget1A:
|
faqBudget1A:
|
||||||
'The estimate starts with the home’s last recorded sale price from HM Land Registry. We bring that sale up to today’s market by looking at how similar homes have changed in value over time, especially homes of the same type nearby. Where there are fewer local sales, the estimate leans more on wider area trends. It’s then checked against nearby recent sales and floor area so the result is useful for comparison.',
|
'The estimate starts with the home’s last recorded sale price from HM Land Registry. We bring that sale up to today’s market by looking at how similar homes have changed in value over time, especially homes of the same type nearby. Where there are fewer local sales, the estimate leans more on wider area trends. It’s then checked against nearby recent sales and floor area so the result is useful for comparison.',
|
||||||
faqBudget2Q: 'Why use estimated current price instead of last sold price?',
|
faqBudget2Q: 'Why use estimated current price instead of last sold price?',
|
||||||
faqBudget2A:
|
faqBudget2A:
|
||||||
'Last sold price can be years or decades old, while asking prices only cover homes listed today. Estimated current price puts older sales into today’s market, so you can compare more homes and spot areas that may offer better value before listings appear. Treat it as a guide for shortlisting, not a bank valuation.',
|
'Last sold price can be years or decades old, while asking prices only cover homes listed today. Estimated current price puts older sales into today’s market, so you can compare more homes and spot areas that may offer better value before listings appear. Treat it as a guide for shortlisting, not a bank valuation.',
|
||||||
// FAQ items — Safety and Neighbourhood
|
// FAQ items:Safety and Neighbourhood
|
||||||
faqSafety1Q: 'What type of crime is common around this postcode?',
|
faqSafety1Q: 'What type of crime is common around this postcode?',
|
||||||
faqSafety1A:
|
faqSafety1A:
|
||||||
'Crime is broken down by type, including violence, burglary, robbery, vehicle crime, anti-social behaviour, shoplifting, drugs, and public order. You can focus on the risks that matter to you instead of relying on one vague safety score.',
|
'Crime is broken down by type, including violence, burglary, robbery, vehicle crime, anti-social behaviour, shoplifting, drugs, and public order. You can focus on the risks that matter to you instead of relying on one vague safety score.',
|
||||||
faqSafety2Q: 'What should I check before viewing an unfamiliar street?',
|
faqSafety2Q: 'What should I check before viewing an unfamiliar street?',
|
||||||
faqSafety2A:
|
faqSafety2A:
|
||||||
'Check crime, road noise, broadband, parks, food shops, schools, and commute before you book. Listing photos are useful, but they shouldn’t be the first time you learn what the street is like.',
|
'Check crime, road noise, broadband, parks, food shops, schools, and commute before you book. Listing photos are useful, but they shouldn’t be the first time you learn what the street is like.',
|
||||||
// FAQ items — Families and Schools
|
// FAQ items:Families and Schools
|
||||||
faqFamilies1Q: 'Which areas have the right mix of schools, space, safety, and commute?',
|
faqFamilies1Q: 'Which areas have the right mix of schools, space, safety, and commute?',
|
||||||
faqFamilies1A:
|
faqFamilies1A:
|
||||||
'Put school ratings, crime, parks, commute, space, home type, and budget on one map. The result is a practical family shortlist instead of a pile of separate school, crime, listing, and transport searches.',
|
'Put school ratings, crime, parks, commute, space, home type, and budget on one map. The result is a practical family shortlist instead of a pile of separate school, crime, listing, and transport searches.',
|
||||||
faqFamilies2Q: 'Does this prove I’m inside a school catchment?',
|
faqFamilies2Q: 'Does this prove I’m inside a school catchment?',
|
||||||
faqFamilies2A:
|
faqFamilies2A:
|
||||||
'No. We show nearby school quality and local education data, but admissions areas and priority rules can change. Use Perfect Postcode to shortlist places, then check catchments and admissions with the school or local council.',
|
'No. We show nearby school quality and local education data, but admissions areas and priority rules can change. Use Perfect Postcode to shortlist places, then check catchments and admissions with the school or local council.',
|
||||||
// FAQ items — Environment and Quality of Life
|
// FAQ items:Environment and Quality of Life
|
||||||
faqEnv1Q: 'How do I avoid a noisy road without losing commute or broadband quality?',
|
faqEnv1Q: 'How do I avoid a noisy road without losing commute or broadband quality?',
|
||||||
faqEnv1A:
|
faqEnv1A:
|
||||||
'Filter by road noise, then keep your commute, broadband, price, and home filters switched on. You can colour the map by one feature while the others keep the shortlist honest.',
|
'Filter by road noise, then keep your commute, broadband, price, and home filters switched on. You can colour the map by one feature while the others keep the shortlist honest.',
|
||||||
|
|
@ -1360,10 +1387,10 @@ const en = {
|
||||||
faqEnv3Q: 'What running-cost checks can I do before viewing?',
|
faqEnv3Q: 'What running-cost checks can I do before viewing?',
|
||||||
faqEnv3A:
|
faqEnv3A:
|
||||||
'You can check energy rating, floor area, building age, council tax area, broadband, and noise before viewing. It won’t predict your exact bills, but it helps you avoid obvious mismatches early.',
|
'You can check energy rating, floor area, building age, council tax area, broadband, and noise before viewing. It won’t predict your exact bills, but it helps you avoid obvious mismatches early.',
|
||||||
// FAQ items — Listing Portals and Due Diligence
|
// FAQ items:Listing Portals and Due Diligence
|
||||||
faqDueDiligence1Q: 'How is this different from searching on Rightmove?',
|
faqDueDiligence1Q: 'How is this different from searching on Rightmove?',
|
||||||
faqDueDiligence1A:
|
faqDueDiligence1A:
|
||||||
'They answer different questions. Rightmove, Zoopla, and OnTheMarket show what’s for sale now — photos, agents, viewings, and alerts. Perfect Postcode works at the postcode level, weighing sold prices, £/sqm, schools, commute, and crime to show where you’d get more home for your money.',
|
'They answer different questions. Rightmove, Zoopla, and OnTheMarket show what’s for sale now: photos, agents, viewings, and alerts. Perfect Postcode works at the postcode level, weighing sold prices, £/sqm, schools, commute, and crime to show where you’d get more home for your money.',
|
||||||
faqDueDiligence2Q: 'Why can’t I filter by garden, garage, or layout?',
|
faqDueDiligence2Q: 'Why can’t I filter by garden, garage, or layout?',
|
||||||
faqDueDiligence2A:
|
faqDueDiligence2A:
|
||||||
'Those details aren’t available consistently for every home. Perfect Postcode can filter by things such as floor area, home type, ownership type, energy rating, sold prices, and local area data. Gardens, garages, aspect, room layout, and estate-agent wording still need to be checked in the listing and at the viewing.',
|
'Those details aren’t available consistently for every home. Perfect Postcode can filter by things such as floor area, home type, ownership type, energy rating, sold prices, and local area data. Gardens, garages, aspect, room layout, and estate-agent wording still need to be checked in the listing and at the viewing.',
|
||||||
|
|
@ -1373,21 +1400,21 @@ const en = {
|
||||||
faqDueDiligence4Q: 'What should I still verify before making an offer?',
|
faqDueDiligence4Q: 'What should I still verify before making an offer?',
|
||||||
faqDueDiligence4A:
|
faqDueDiligence4A:
|
||||||
'Use Perfect Postcode to check the area and likely value, then confirm the listing details before making an offer. You should still check ownership type, lease details, service charges, planning history, flood risk, legal issues, mortgage requirements, and survey results.',
|
'Use Perfect Postcode to check the area and likely value, then confirm the listing details before making an offer. You should still check ownership type, lease details, service charges, planning history, flood risk, legal issues, mortgage requirements, and survey results.',
|
||||||
// FAQ items — Privacy and Data Protection
|
// FAQ items:Privacy and Data Protection
|
||||||
faqPrivacy1Q: 'Do you store personal data about me?',
|
faqPrivacy1Q: 'Do you store personal data about me?',
|
||||||
faqPrivacy1A:
|
faqPrivacy1A:
|
||||||
'The property and neighbourhood data doesn’t contain your personal details. If you create an account, we store only what’s needed to run the service, such as your email address, access status, newsletter choice, saved searches, shared links, and payment records handled by Stripe. We handle account data under UK privacy law.',
|
'The property and neighbourhood data doesn’t contain your personal details. If you create an account, we store only what’s needed to run the service, such as your email address, access status, newsletter choice, saved searches, shared links, and payment records handled by Stripe. We handle account data under UK privacy law.',
|
||||||
// FAQ items — Why Perfect Postcode
|
// FAQ items:Why Perfect Postcode
|
||||||
faqWhy1Q: 'What does this show that listing portals usually don’t?',
|
faqWhy1Q: 'What does this show that listing portals usually don’t?',
|
||||||
faqWhy1A:
|
faqWhy1A:
|
||||||
'Listing sites start from homes that are for sale right now. Perfect Postcode starts from the places that fit your life and budget, using sold prices, space, commute, schools, crime, noise, broadband, energy rating, ownership type, and local amenities before you open the listings.',
|
'Listing sites start from individual homes for sale right now. Perfect Postcode starts from the postcode: it ranks every postcode in England by value for money (sold prices, £/sqm, space, commute, schools, crime, noise, broadband, energy rating and ownership type), so you find the underpriced areas before you commit to one.',
|
||||||
faqWhy2Q: 'How much manual research does this save?',
|
faqWhy2Q: 'How much manual research does this save?',
|
||||||
faqWhy2A:
|
faqWhy2A:
|
||||||
'You could do the research yourself, but it means checking sold prices, energy ratings, crime, schools, broadband, local facts, environment details, travel times, and maps one postcode at a time. Perfect Postcode puts those sources in one searchable map for England.',
|
'You could do the research yourself, but it means checking sold prices, energy ratings, crime, schools, broadband, local facts, environment details, travel times, and maps one postcode at a time. Perfect Postcode puts those sources in one searchable map for England.',
|
||||||
faqWhy3Q: 'How reliable is the data?',
|
faqWhy3Q: 'How reliable is the data?',
|
||||||
faqWhy3A:
|
faqWhy3A:
|
||||||
'The main sources are official or widely used public data, including sold prices, energy ratings, local facts, school ratings, broadband, crime, environment, map, and street data. They’re useful for shortlisting and comparison, but any purchase decision still needs current checks and expert advice where needed.',
|
'The main sources are official or widely used public data, including sold prices, energy ratings, local facts, school ratings, broadband, crime, environment, map, and street data. They’re useful for shortlisting and comparison, but any purchase decision still needs current checks and expert advice where needed.',
|
||||||
// FAQ items — Pricing and Access
|
// FAQ items:Pricing and Access
|
||||||
faqPricing1Q: 'Why pay when postcode reports are free?',
|
faqPricing1Q: 'Why pay when postcode reports are free?',
|
||||||
faqPricing1A:
|
faqPricing1A:
|
||||||
'Free postcode tools are useful once you already know what to check. Perfect Postcode is for scanning every postcode in England against your needs, combining filters, comparing options, saving searches, and exporting a shortlist before you spend weekends on viewings.',
|
'Free postcode tools are useful once you already know what to check. Perfect Postcode is for scanning every postcode in England against your needs, combining filters, comparing options, saving searches, and exporting a shortlist before you spend weekends on viewings.',
|
||||||
|
|
@ -1396,9 +1423,9 @@ const en = {
|
||||||
'Lifetime access means one payment gives your account ongoing access to the paid Perfect Postcode map for as long as the service runs. It isn’t 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.',
|
'Lifetime access means one payment gives your account ongoing access to the paid Perfect Postcode map for as long as the service runs. It isn’t 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?',
|
faqPricing3Q: 'What can I access on the free tier?',
|
||||||
faqPricing3A:
|
faqPricing3A:
|
||||||
'Free users get the full Perfect Postcode map across all of England — every postcode and every feature — and can apply up to 3 filters at a time. Lifetime access removes that limit so you can stack unlimited filters.',
|
'Free users get the full Perfect Postcode map across all of England (every postcode and every feature) and can apply up to 3 filters at a time. Lifetime access removes that limit so you can stack unlimited filters.',
|
||||||
|
|
||||||
// FAQ items — Tips and Tricks
|
// FAQ items:Tips and Tricks
|
||||||
faqTips1Q: 'How do I preview a filter on the map?',
|
faqTips1Q: 'How do I preview a filter on the map?',
|
||||||
faqTips1A:
|
faqTips1A:
|
||||||
'Click Colour beside a filter or feature to colour the map by that item. Your active filters stay in place, so this is a quick way to compare one thing, such as price, commute time, schools, crime, or noise, without changing your shortlist.',
|
'Click Colour beside a filter or feature to colour the map by that item. Your active filters stay in place, so this is a quick way to compare one thing, such as price, commute time, schools, crime, or noise, without changing your shortlist.',
|
||||||
|
|
@ -1409,20 +1436,20 @@ const en = {
|
||||||
faqTips3A:
|
faqTips3A:
|
||||||
'When a feature is colouring the map, use Reset colour scale in the map legend to refresh the colours for the results you’re looking at now. This is useful after moving the map, zooming, or changing filters.',
|
'When a feature is colouring the map, use Reset colour scale in the map legend to refresh the colours for the results you’re looking at now. This is useful after moving the map, zooming, or changing filters.',
|
||||||
|
|
||||||
// FAQ items — Behind The Data
|
// FAQ items:Behind The Data
|
||||||
faqBehindData1Q: 'Why does an airport sometimes look quieter than the streets around it?',
|
faqBehindData1Q: 'Why does an airport sometimes look quieter than the streets around it?',
|
||||||
faqBehindData1A:
|
faqBehindData1A:
|
||||||
'The noise figure shown for a postcode is the loudest of three Defra sources — road, rail, and aircraft — modelled at 4m above ground as a 24-hour weighted average (Lden). On a busy residential street the road component dominates, typically 65–75 dB. Inside an airport perimeter there are no major public roads, so the road term drops and only the aircraft average is left. London City Airport has a curfew and limited movements, so its 24-hour aircraft Lden is moderate (around 60–66 dB at the runway), and the airfield ends up looking quieter than the A-roads that flank it. The same effect appears at Heathrow. It’s a real artefact of measuring transport noise at residential receptor height, not a bug.',
|
'The noise figure shown for a postcode is the loudest of three Defra sources (road, rail, and aircraft) modelled at 4m above ground as a 24-hour weighted average (Lden). On a busy residential street the road component dominates, typically 65–75 dB. Inside an airport perimeter there are no major public roads, so the road term drops and only the aircraft average is left. London City Airport has a curfew and limited movements, so its 24-hour aircraft Lden is moderate (around 60–66 dB at the runway), and the airfield ends up looking quieter than the A-roads that flank it. The same effect appears at Heathrow. It’s a real artefact of measuring transport noise at residential receptor height, not a bug.',
|
||||||
faqBehindData2Q: 'Why does the airport, motorway or park show up as one big shape?',
|
faqBehindData2Q: 'Why does the airport, motorway or park show up as one big shape?',
|
||||||
faqBehindData2A:
|
faqBehindData2A:
|
||||||
'Postcodes don’t officially have boundaries in the UK — Royal Mail defines a postcode as a list of delivery addresses, not as an area. Perfect Postcode synthesises the polygons by giving each address its share of the surrounding land. Places with no addresses, such as a runway, motorway carriageway, park or reservoir, get filled in by whichever nearby residential postcode is closest. That is why an airport or open space often appears as a single large polygon rather than many small ones, and the value shown for that polygon comes from the handful of postcodes that happen to sit inside the perimeter.',
|
'Postcodes don’t officially have boundaries in the UK. Royal Mail defines a postcode as a list of delivery addresses, not as an area. Perfect Postcode synthesises the polygons by giving each address its share of the surrounding land. Places with no addresses, such as a runway, motorway carriageway, park or reservoir, get filled in by whichever nearby residential postcode is closest. That is why an airport or open space often appears as a single large polygon rather than many small ones, and the value shown for that polygon comes from the handful of postcodes that happen to sit inside the perimeter.',
|
||||||
faqBehindData3Q: 'Why do nearby postcodes share the same crime numbers?',
|
faqBehindData3Q: 'Why do nearby postcodes share the same crime numbers?',
|
||||||
faqBehindData3A:
|
faqBehindData3A:
|
||||||
'Police-recorded street-level crime is published at LSOA level — small neighbourhood areas of about 1,500 residents. Every postcode inside the same LSOA inherits the same yearly totals, so a quiet residential street and a high street one block over can show identical figures if they fall on the same side of the boundary. Per-capita rates can also look unusually high in postcodes covering hospitals, university campuses or industrial estates, because those areas record incidents normally but have very few residents on paper to divide the count across.',
|
'Police-recorded street-level crime is published at LSOA level (small neighbourhood areas of about 1,500 residents). Every postcode inside the same LSOA inherits the same yearly totals, so a quiet residential street and a high street one block over can show identical figures if they fall on the same side of the boundary. Per-capita rates can also look unusually high in postcodes covering hospitals, university campuses or industrial estates, because those areas record incidents normally but have very few residents on paper to divide the count across.',
|
||||||
faqBehindData4Q:
|
faqBehindData4Q:
|
||||||
'What does a “school catchments” count mean — can my child attend those schools?',
|
'What does a “school catchments” count mean, and can my child attend those schools?',
|
||||||
faqBehindData4A:
|
faqBehindData4A:
|
||||||
'Each count is the number of Good or Outstanding state schools whose modelled historical catchment area covers the postcode. We simulate how England’s distance-based admissions allocate places: children (Census 2021) apply to nearby schools, trading distance against Ofsted rating, and an oversubscribed school admits its closest applicants until full — its catchment radius is the distance of the last child admitted, the same “last distance offered” councils publish, and the model is calibrated against hundreds of those published figures. It estimates where pupils plausibly get a place; it is not an official admission area. Faith and selective admissions, sibling priority and yearly boundary changes are not modelled, so always confirm catchments and admission rules with the school or local authority before relying on them for a decision.',
|
'Each count is the number of Good or Outstanding state schools whose modelled historical catchment area covers the postcode. We simulate how England’s distance-based admissions allocate places: children (Census 2021) apply to nearby schools, trading distance against Ofsted rating, and an oversubscribed school admits its closest applicants until full. Its catchment radius is the distance of the last child admitted, the same “last distance offered” councils publish, and the model is calibrated against hundreds of those published figures. It estimates where pupils plausibly get a place; it is not an official admission area. Faith and selective admissions, sibling priority and yearly boundary changes are not modelled, so always confirm catchments and admission rules with the school or local authority before relying on them for a decision.',
|
||||||
faqBehindData5Q: 'Why does a postcode show “Gigabit” when not every home has fibre?',
|
faqBehindData5Q: 'Why does a postcode show “Gigabit” when not every home has fibre?',
|
||||||
faqBehindData5A:
|
faqBehindData5A:
|
||||||
'Broadband coverage from Ofcom Connected Nations is reported per postcode as the percentage of premises that can get each speed tier. We display the highest tier with any availability, so a postcode where even one home can reach Gigabit reads “Gigabit available”. It is the right answer for “is full-fibre on this street at all?”, but does not guarantee every flat in a block can be ordered today. Always verify with the providers for your specific address before signing.',
|
'Broadband coverage from Ofcom Connected Nations is reported per postcode as the percentage of premises that can get each speed tier. We display the highest tier with any availability, so a postcode where even one home can reach Gigabit reads “Gigabit available”. It is the right answer for “is full-fibre on this street at all?”, but does not guarantee every flat in a block can be ordered today. Always verify with the providers for your specific address before signing.',
|
||||||
|
|
@ -1490,6 +1517,7 @@ const en = {
|
||||||
|
|
||||||
// ── Invite Page ────────────────────────────────────
|
// ── Invite Page ────────────────────────────────────
|
||||||
invitePage: {
|
invitePage: {
|
||||||
|
couldNotValidateTitle: 'Couldn’t validate invite',
|
||||||
youreInvited: 'You’re invited!',
|
youreInvited: 'You’re invited!',
|
||||||
specialOffer: 'Special offer!',
|
specialOffer: 'Special offer!',
|
||||||
invitedByFree: '{{name}} has invited you to get free lifetime access.',
|
invitedByFree: '{{name}} has invited you to get free lifetime access.',
|
||||||
|
|
@ -1553,17 +1581,17 @@ const en = {
|
||||||
treesOutsideWoodlands: {
|
treesOutsideWoodlands: {
|
||||||
label: 'Trees & woodland',
|
label: 'Trees & woodland',
|
||||||
detail:
|
detail:
|
||||||
'Forest Research Trees Outside Woodland (TOW) v1 canopy polygons — lone trees and groups of trees — combined 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.',
|
'Forest Research Trees Outside Woodland (TOW) v1 canopy polygons (lone trees and groups of trees) combined 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: {
|
propertyBorders: {
|
||||||
label: 'Property borders',
|
label: 'Property borders',
|
||||||
detail:
|
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 85–90% 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.',
|
'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 85–90% 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: {
|
newDevelopments: {
|
||||||
label: 'New developments',
|
label: 'New developments',
|
||||||
detail:
|
detail:
|
||||||
'A pipeline of new housing. Blue markers show 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.',
|
'A pipeline of new housing. Blue markers show 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.',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
@ -1712,7 +1740,7 @@ const en = {
|
||||||
'Housing Conditions Score': 'Housing Conditions Score',
|
'Housing Conditions Score': 'Housing Conditions Score',
|
||||||
'Air Quality and Road Safety Score': 'Air Quality and Road Safety Score',
|
'Air Quality and Road Safety Score': 'Air Quality and Road Safety Score',
|
||||||
|
|
||||||
// ─ Feature names (Crime) — population-normalised rate, 7-year & 2-year ─
|
// ─ Feature names (Crime): population-normalised rate, 7-year & 2-year ─
|
||||||
'Serious crime (/yr, 7y)': 'Serious crime (per year, 7yr)',
|
'Serious crime (/yr, 7y)': 'Serious crime (per year, 7yr)',
|
||||||
'Serious crime (/yr, 2y)': 'Serious crime (per year, 2yr)',
|
'Serious crime (/yr, 2y)': 'Serious crime (per year, 2yr)',
|
||||||
'Minor crime (/yr, 7y)': 'Minor crime (per year, 7yr)',
|
'Minor crime (/yr, 7y)': 'Minor crime (per year, 7yr)',
|
||||||
|
|
@ -1773,6 +1801,8 @@ const en = {
|
||||||
'% Owner occupied': '% Owner occupied',
|
'% Owner occupied': '% Owner occupied',
|
||||||
'% Social rent': '% Social rent',
|
'% Social rent': '% Social rent',
|
||||||
'% Private rent': '% Private rent',
|
'% Private rent': '% Private rent',
|
||||||
|
'% Council housing': '% Council housing',
|
||||||
|
'% Ex-council': '% Ex-council',
|
||||||
'% White': '% White',
|
'% White': '% White',
|
||||||
'% South Asian': '% South Asian',
|
'% South Asian': '% South Asian',
|
||||||
'% Black': '% Black',
|
'% Black': '% Black',
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ const fr: Translations = {
|
||||||
},
|
},
|
||||||
// ── Common ──────────────────────────────────────────
|
// ── Common ──────────────────────────────────────────
|
||||||
common: {
|
common: {
|
||||||
|
retry: 'Réessayer',
|
||||||
save: 'Enregistrer',
|
save: 'Enregistrer',
|
||||||
update: 'Mettre à jour',
|
update: 'Mettre à jour',
|
||||||
cancel: 'Annuler',
|
cancel: 'Annuler',
|
||||||
|
|
@ -104,6 +105,7 @@ const fr: Translations = {
|
||||||
|
|
||||||
// ── User Menu ──────────────────────────────────────
|
// ── User Menu ──────────────────────────────────────
|
||||||
userMenu: {
|
userMenu: {
|
||||||
|
accountMenu: 'Menu du compte',
|
||||||
fullAccess: 'Accès complet',
|
fullAccess: 'Accès complet',
|
||||||
demo: 'Démo',
|
demo: 'Démo',
|
||||||
themeLight: 'Thème : Clair',
|
themeLight: 'Thème : Clair',
|
||||||
|
|
@ -514,9 +516,9 @@ const fr: Translations = {
|
||||||
'Compare Bristol postcodes': 'Comparez les codes postaux de Bristol',
|
'Compare Bristol postcodes': 'Comparez les codes postaux de Bristol',
|
||||||
'Trust and coverage': 'Confiance et couverture',
|
'Trust and coverage': 'Confiance et couverture',
|
||||||
'Perfect Postcode data sources and coverage':
|
'Perfect Postcode data sources and coverage':
|
||||||
'Perfect Postcode — sources de données et couverture',
|
'Perfect Postcode : sources de données et couverture',
|
||||||
'Perfect Postcode data sources - Property, schools, commute and local context':
|
'Perfect Postcode data sources - Property, schools, commute and local context':
|
||||||
'Sources de données Perfect Postcode – Immobilier, écoles, trajet et contexte local',
|
'Sources de données Perfect Postcode : Immobilier, écoles, trajet et contexte local',
|
||||||
'Review the public and official datasets used by Perfect Postcode, including property prices, EPC, schools, crime, broadband, noise and travel-time context.':
|
'Review the public and official datasets used by Perfect Postcode, including property prices, EPC, schools, crime, broadband, noise and travel-time context.':
|
||||||
'Examinez les jeux de données publics et officiels utilisés par Perfect Postcode, notamment les prix immobiliers, l’EPC, les écoles, la criminalité, le haut débit, le bruit et le contexte du temps de trajet.',
|
'Examinez les jeux de données publics et officiels utilisés par Perfect Postcode, notamment les prix immobiliers, l’EPC, les écoles, la criminalité, le haut débit, le bruit et le contexte du temps de trajet.',
|
||||||
'Perfect Postcode combines property, transport, education, environment, and local-service datasets so buyers can compare postcodes consistently. This page explains what the data is for and where it should be verified.':
|
'Perfect Postcode combines property, transport, education, environment, and local-service datasets so buyers can compare postcodes consistently. This page explains what the data is for and where it should be verified.':
|
||||||
|
|
@ -583,7 +585,7 @@ const fr: Translations = {
|
||||||
'Privacy and security for saved property searches':
|
'Privacy and security for saved property searches':
|
||||||
'Confidentialité et sécurité des recherches immobilières enregistrées',
|
'Confidentialité et sécurité des recherches immobilières enregistrées',
|
||||||
'Perfect Postcode privacy and security - Saved searches and account data':
|
'Perfect Postcode privacy and security - Saved searches and account data':
|
||||||
'Perfect Postcode — confidentialité et sécurité : recherches enregistrées et données de compte',
|
'Perfect Postcode, confidentialité et sécurité : recherches enregistrées et données de compte',
|
||||||
'Learn how Perfect Postcode treats saved searches, account data and property research workflows with privacy and security in mind.':
|
'Learn how Perfect Postcode treats saved searches, account data and property research workflows with privacy and security in mind.':
|
||||||
'Découvrez comment Perfect Postcode traite les recherches enregistrées, les données de compte et les parcours de recherche immobilière en tenant compte de la confidentialité et de la sécurité.',
|
'Découvrez comment Perfect Postcode traite les recherches enregistrées, les données de compte et les parcours de recherche immobilière en tenant compte de la confidentialité et de la sécurité.',
|
||||||
'Property research can reveal personal priorities, budgets, and locations. The product keeps public SEO pages separate from account-only areas and marks private dashboard/account routes as noindex.':
|
'Property research can reveal personal priorities, budgets, and locations. The product keeps public SEO pages separate from account-only areas and marks private dashboard/account routes as noindex.':
|
||||||
|
|
@ -619,13 +621,23 @@ const fr: Translations = {
|
||||||
|
|
||||||
// ── Auth Modal ─────────────────────────────────────
|
// ── Auth Modal ─────────────────────────────────────
|
||||||
auth: {
|
auth: {
|
||||||
|
errorRateLimited: 'Trop de tentatives. Veuillez patienter une minute, puis réessayer.',
|
||||||
|
errorNetwork: 'Impossible de joindre le serveur. Vérifiez votre connexion, puis réessayez.',
|
||||||
|
errorEmailTaken: 'Un compte avec cette adresse e-mail existe déjà.',
|
||||||
|
errorPasswordWeak: 'Le mot de passe doit comporter au moins 8 caractères.',
|
||||||
|
errorEmailInvalid: 'Veuillez saisir une adresse e-mail valide.',
|
||||||
|
errorInvalidCredentials: 'E-mail ou mot de passe incorrect.',
|
||||||
|
logInInstead: 'Se connecter plutôt',
|
||||||
|
accountCreatedPleaseLogIn: 'Compte créé. Veuillez vous connecter pour continuer.',
|
||||||
|
accountCreatedRateLimited:
|
||||||
|
'Compte créé. Trop de tentatives à l’instant. Veuillez patienter un moment, puis vous connecter.',
|
||||||
logIn: 'Se connecter',
|
logIn: 'Se connecter',
|
||||||
createAccount: 'Créer un compte',
|
createAccount: 'Créer un compte',
|
||||||
resetPassword: 'Réinitialiser le mot de passe',
|
resetPassword: 'Réinitialiser le mot de passe',
|
||||||
valueProp:
|
valueProp:
|
||||||
'Enregistrez vos recherches, ajoutez des biens en favoris et créez une sélection de secteurs adaptés à vos critères.',
|
'Enregistrez vos recherches, ajoutez des biens en favoris et créez une sélection de secteurs adaptés à vos critères.',
|
||||||
dashboardActionsValueProp:
|
dashboardActionsValueProp:
|
||||||
'Créez un compte gratuit pour enregistrer, partager et exporter vos recherches — gratuit, sans carte bancaire.',
|
'Créez un compte gratuit pour enregistrer, partager et exporter vos recherches : gratuit, sans carte bancaire.',
|
||||||
continueWithGoogle: 'Continuer avec Google',
|
continueWithGoogle: 'Continuer avec Google',
|
||||||
email: 'E-mail',
|
email: 'E-mail',
|
||||||
emailPlaceholder: 'vous@exemple.com',
|
emailPlaceholder: 'vous@exemple.com',
|
||||||
|
|
@ -652,12 +664,12 @@ const fr: Translations = {
|
||||||
'Vous avez utilisé les 5 filtres de votre compte gratuit. Obtenez un accès à vie pour superposer un nombre illimité de filtres sur chaque code postal et quartier d’Angleterre. Un seul paiement, pour toujours.',
|
'Vous avez utilisé les 5 filtres de votre compte gratuit. Obtenez un accès à vie pour superposer un nombre illimité de filtres sur chaque code postal et quartier d’Angleterre. Un seul paiement, pour toujours.',
|
||||||
titleRegister: 'Créer un compte gratuit',
|
titleRegister: 'Créer un compte gratuit',
|
||||||
descriptionRegister:
|
descriptionRegister:
|
||||||
'Les comptes gratuits débloquent jusqu’à 5 filtres ainsi que la sauvegarde, le partage et l’export — sans carte bancaire. Des filtres illimités dans toute l’Angleterre ? Passez à l’accès à vie.',
|
'Les comptes gratuits débloquent jusqu’à 5 filtres ainsi que la sauvegarde, le partage et l’export. Sans carte bancaire. Des filtres illimités dans toute l’Angleterre ? Passez à l’accès à vie.',
|
||||||
descriptionSharedRegister:
|
descriptionSharedRegister:
|
||||||
'Il s’agit d’une recherche partagée. Créez un compte gratuit pour construire la vôtre avec jusqu’à 5 filtres et enregistrer, partager et exporter — ou passez à l’accès à vie pour des filtres illimités.',
|
'Il s’agit d’une recherche partagée. Créez un compte gratuit pour construire la vôtre avec jusqu’à 5 filtres et enregistrer, partager et exporter, ou passez à l’accès à vie pour des filtres illimités.',
|
||||||
registerFree: 'Créer un compte gratuit',
|
registerFree: 'Créer un compte gratuit',
|
||||||
lifetimeUpsell: 'Des filtres illimités ?',
|
lifetimeUpsell: 'Des filtres illimités ?',
|
||||||
goLifetime: 'Obtenir l’accès à vie — {{price}}',
|
goLifetime: 'Obtenir l’accès à vie : {{price}}',
|
||||||
free: 'Gratuit',
|
free: 'Gratuit',
|
||||||
freeForEarly: 'Gratuit pour les premiers utilisateurs. Aucune carte bancaire requise.',
|
freeForEarly: 'Gratuit pour les premiers utilisateurs. Aucune carte bancaire requise.',
|
||||||
oneTimePayment: 'Paiement unique. Accès à vie.',
|
oneTimePayment: 'Paiement unique. Accès à vie.',
|
||||||
|
|
@ -711,7 +723,7 @@ const fr: Translations = {
|
||||||
upgradeToFullMap: 'Passer à la carte complète',
|
upgradeToFullMap: 'Passer à la carte complète',
|
||||||
registerPrompt:
|
registerPrompt:
|
||||||
'Créez un compte gratuit pour combiner jusqu’à 5 filtres et enregistrer, partager et exporter vos recherches.',
|
'Créez un compte gratuit pour combiner jusqu’à 5 filtres et enregistrer, partager et exporter vos recherches.',
|
||||||
registerSubPrompt: 'Gratuit — sans carte bancaire. Filtres illimités avec l’accès à vie.',
|
registerSubPrompt: 'Gratuit, sans carte bancaire. Filtres illimités avec l’accès à vie.',
|
||||||
registerCta: 'Créer un compte gratuit',
|
registerCta: 'Créer un compte gratuit',
|
||||||
chooseFilters:
|
chooseFilters:
|
||||||
'Cliquez sur Ajouter pour filtrer. Les petits boutons affichent les détails des données ou colorent la carte.',
|
'Cliquez sur Ajouter pour filtrer. Les petits boutons affichent les détails des données ou colorent la carte.',
|
||||||
|
|
@ -751,6 +763,11 @@ const fr: Translations = {
|
||||||
crimeType: 'Type d’infraction',
|
crimeType: 'Type d’infraction',
|
||||||
qualificationLevel: 'Niveau de qualification',
|
qualificationLevel: 'Niveau de qualification',
|
||||||
tenureType: 'Statut d’occupation',
|
tenureType: 'Statut d’occupation',
|
||||||
|
councilType: 'Type de logement municipal',
|
||||||
|
councilStatus: 'Type',
|
||||||
|
councilCurrent: 'Actuel',
|
||||||
|
councilEx: 'Ancien',
|
||||||
|
councilBoth: 'Les deux',
|
||||||
crimeWindow: 'Période',
|
crimeWindow: 'Période',
|
||||||
crimeWindow7y: '7 ans',
|
crimeWindow7y: '7 ans',
|
||||||
crimeWindow2y: '2 ans',
|
crimeWindow2y: '2 ans',
|
||||||
|
|
@ -872,8 +889,11 @@ const fr: Translations = {
|
||||||
},
|
},
|
||||||
actualListings: {
|
actualListings: {
|
||||||
label: 'Annonces',
|
label: 'Annonces',
|
||||||
show: 'Afficher les annonces réelles',
|
modes: {
|
||||||
hide: 'Masquer les annonces réelles',
|
new: 'Neuf',
|
||||||
|
nonNew: 'Ancien',
|
||||||
|
hint: '« Neuf » affiche les programmes neufs ; « Ancien » la revente et les autres annonces.',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
poi: { zoomInToSeeDetails: 'Zoomez pour voir les détails' },
|
poi: { zoomInToSeeDetails: 'Zoomez pour voir les détails' },
|
||||||
},
|
},
|
||||||
|
|
@ -900,6 +920,7 @@ const fr: Translations = {
|
||||||
historyTitle: 'Historique',
|
historyTitle: 'Historique',
|
||||||
historySale: 'Vente',
|
historySale: 'Vente',
|
||||||
historyBuilt: 'Construit',
|
historyBuilt: 'Construit',
|
||||||
|
historyNewBuild: 'Neuf',
|
||||||
tenureOwnerOccupied: 'Propriétaire occupant',
|
tenureOwnerOccupied: 'Propriétaire occupant',
|
||||||
tenureRentedPrivate: 'Loué (privé)',
|
tenureRentedPrivate: 'Loué (privé)',
|
||||||
tenureRentedSocial: 'Logement social',
|
tenureRentedSocial: 'Logement social',
|
||||||
|
|
@ -1014,26 +1035,29 @@ const fr: Translations = {
|
||||||
|
|
||||||
// ── Home Page ──────────────────────────────────────
|
// ── Home Page ──────────────────────────────────────
|
||||||
home: {
|
home: {
|
||||||
heroEyebrow: 'Pour celles et ceux qui se demandent « où chercher ? »',
|
heroEyebrow: 'Pour les acheteurs qui refusent de surpayer la réputation d’un code postal',
|
||||||
heroTitle1: 'Trouvez les codes postaux',
|
heroTitle1: 'Trouvez le',
|
||||||
heroTitle2: 'adaptés à votre vie',
|
heroTitle2: 'code postal pépite cachée',
|
||||||
heroTitle3: 'Pas seulement les quartiers que vous connaissez déjà.',
|
heroTitle3: 'Mêmes écoles, même trajet, discrètement moins cher.',
|
||||||
heroSubtitle:
|
heroSubtitle:
|
||||||
'Des boroughs londoniens aux villes de commuter belt et aux grandes villes régionales, l’Angleterre compte trop de lieux pour tout vérifier un par un.',
|
'Deux rues peuvent partager la même école, la même gare et la même année de construction, puis se vendre avec des dizaines de milliers de livres d’écart. L’une d’elles est mal évaluée. Nous trouvons laquelle.',
|
||||||
heroDescription:
|
heroDescription:
|
||||||
'Définissez budget, trajet, écoles, sécurité, bruit, haut débit et cadre de vie. Perfect Postcode analyse les codes postaux d’Angleterre et révèle les lieux vraiment compatibles, y compris ceux que vous n’auriez jamais tapés dans un portail immobilier.',
|
'Définissez votre budget et vos critères non négociables. Perfect Postcode classe chaque code postal d’Angleterre selon ce que chaque livre achète réellement (surface, écoles, trajet et sécurité) avec les preuves derrière chaque choix.',
|
||||||
exploreTheMap: 'Trouver mes codes postaux',
|
exploreTheMap: 'Trouver mon code postal pépite',
|
||||||
seeTheDifference: 'Voir comment ça marche',
|
seeTheDifference: 'Voir une vraie pépite',
|
||||||
|
freeToExplore:
|
||||||
|
'Explorez la carte en direct gratuitement, sans inscription, sans carte bancaire.',
|
||||||
|
dataSourcesLabel: 'Fondé sur des données officielles',
|
||||||
|
dataSources: 'Land Registry · ONS · Ofsted · DfT · Ordnance Survey · Police.uk',
|
||||||
productDemoLabel: 'Démo produit Perfect Postcode',
|
productDemoLabel: 'Démo produit Perfect Postcode',
|
||||||
playProductDemo: 'Lancer la démo produit Perfect Postcode',
|
playProductDemo: 'Lancer la démo produit Perfect Postcode',
|
||||||
scrollToProductDemo: 'Faire défiler jusqu’à la démo produit',
|
scrollToProductDemo: 'Faire défiler jusqu’à la démo produit',
|
||||||
showcaseHeader: 'Comment ça marche',
|
|
||||||
showcaseContext: 'Comment fonctionne Perfect Postcode',
|
showcaseContext: 'Comment fonctionne Perfect Postcode',
|
||||||
showcaseFeaturePriceShort: 'Prix',
|
showcaseFeaturePriceShort: 'Prix',
|
||||||
showcaseFeatureNoiseShort: 'Bruit',
|
showcaseFeatureNoiseShort: 'Bruit',
|
||||||
showcaseFeatureSchoolsShort: 'Écoles',
|
showcaseFeatureSchoolsShort: 'Écoles',
|
||||||
showcaseFeatureTravelShort: 'Trajet',
|
showcaseFeatureTravelShort: 'Trajet',
|
||||||
showcaseGoodPrimariesNearby: 'Dans {{count}}+ zones de recrutement de primaires Good+',
|
showcaseGoodPrimariesNearby: 'Dans {{count}}+ secteurs de primaires bien notées',
|
||||||
showcaseWithinRail: 'À moins de {{count}} min du train',
|
showcaseWithinRail: 'À moins de {{count}} min du train',
|
||||||
showcaseMatchingHomesLabel: 'Biens compatibles',
|
showcaseMatchingHomesLabel: 'Biens compatibles',
|
||||||
showcaseMatchingHomes: '{{value}} biens compatibles',
|
showcaseMatchingHomes: '{{value}} biens compatibles',
|
||||||
|
|
@ -1042,95 +1066,96 @@ const fr: Translations = {
|
||||||
showcaseNearby: '{{value}} à proximité',
|
showcaseNearby: '{{value}} à proximité',
|
||||||
showcasePoliticalVoteShare: 'Répartition des voix',
|
showcasePoliticalVoteShare: 'Répartition des voix',
|
||||||
showcaseGe2024: 'Législatives 2024',
|
showcaseGe2024: 'Législatives 2024',
|
||||||
showcaseLotsMore: '...et bien plus',
|
showcaseLotsMore: '…et bien plus',
|
||||||
showcaseMinutes: '{{count}} min',
|
showcaseMinutes: '{{count}} min',
|
||||||
showcaseSendShortlist: 'Envoyer la sélection',
|
showcaseSendShortlist: 'Envoyer la sélection',
|
||||||
showcaseDownloadXlsx: 'Télécharger le .xlsx',
|
showcaseDownloadXlsx: 'Télécharger le .xlsx',
|
||||||
showcaseTopThree: 'Top 3',
|
showcaseTopThree: 'Top 3',
|
||||||
showcaseScoutBullet1:
|
showcaseScoutBullet1: 'Parcourez les rues du code postal qui bat son voisin plus cher.',
|
||||||
'Parcourez les rues avant que la recherche d’annonces ne réduise vos options.',
|
|
||||||
showcaseScoutBullet2:
|
showcaseScoutBullet2:
|
||||||
'Testez le trajet depuis une vraie porte d’entrée, pas seulement depuis un nom d’arrondissement.',
|
'Testez le trajet depuis une vraie porte d’entrée, pas depuis un nom d’arrondissement.',
|
||||||
showcaseScoutBullet3: 'Comparez les visites avec des données déjà en main.',
|
showcaseScoutBullet3: 'Comparez les visites avec des preuves déjà en main.',
|
||||||
showcaseStep1Tab: 'Filtrer',
|
showcaseStep1Tab: 'Filtrer',
|
||||||
showcaseStep1Title: 'Transformez des besoins vagues en recherche précise',
|
showcaseStep1Title: 'Transformez des besoins vagues en recherche précise',
|
||||||
showcaseStep1Body:
|
showcaseStep1Body:
|
||||||
'Définissez ce qui compte et voyez exactement combien de codes postaux inadaptés chaque exigence retire de votre recherche.',
|
'Définissez ce qui compte et voyez exactement combien de codes postaux inadaptés chaque exigence retire de votre recherche.',
|
||||||
showcaseStep1Chip1: 'Rues calmes',
|
showcaseStep2Tab: 'Correspondance',
|
||||||
showcaseStep1Chip2: 'Écoles primaires bien notées',
|
showcaseStep2Title: 'Voyez les codes postaux sous-cotés s’illuminer',
|
||||||
showcaseStep1Chip3: 'Moins de £500k',
|
|
||||||
showcaseStep1VennCenter: 'Codes postaux qui cochent les trois',
|
|
||||||
showcaseStep2Tab: 'Résultats',
|
|
||||||
showcaseStep2Title: 'Laissez la carte révéler des lieux que vous n’auriez pas tapés',
|
|
||||||
showcaseStep2Body:
|
showcaseStep2Body:
|
||||||
'Parcourez l’Angleterre par compatibilité plutôt qu’à partir de noms de quartiers familiers. Des secteurs méconnus deviennent visibles avant que les portails d’annonces ne réduisent votre horizon.',
|
'Classez l’Angleterre selon le rapport qualité-prix, pas selon les noms de quartiers que vous connaissez déjà. Les secteurs sous-cotés (forts en £/m², écoles et trajet) remontent en tête.',
|
||||||
showcaseStep2Region: 'Grand Londres',
|
showcaseStep2Region: 'Grand Londres',
|
||||||
showcaseStep2Sources: 'Land Registry · ONS · Ofsted · DfT',
|
showcaseStep2Sources: 'Land Registry · ONS · Ofsted · DfT',
|
||||||
showcaseStep2ClustersLabel: 'Groupes compatibles',
|
|
||||||
showcaseStep3Tab: 'Inspecter',
|
showcaseStep3Tab: 'Inspecter',
|
||||||
showcaseStep3Title: 'Comprenez pourquoi un code postal ressort',
|
showcaseStep3Title: 'Comprenez pourquoi un code postal a été retenu',
|
||||||
showcaseStep3Body:
|
showcaseStep3Body:
|
||||||
'Ouvrez n’importe quel secteur compatible et vérifiez prix, sécurité, écoles, haut débit et compromis dans un seul panneau avant d’y passer un week-end.',
|
'Ouvrez n’importe quel secteur compatible et vérifiez prix, sécurité, écoles, haut débit et compromis dans un seul panneau avant d’y passer un week-end.',
|
||||||
showcaseStep3HeaderArea: 'Votre code postal idéal',
|
showcaseStep3Stat2Label: 'Taux de criminalité',
|
||||||
showcaseStep3HeaderFit: 'Indicateurs du quartier',
|
|
||||||
showcaseStep3Stat1Label: 'Tendance des prix vendus',
|
|
||||||
showcaseStep3Stat2Label: 'Criminalité',
|
|
||||||
showcaseStep3Stat2Value: 'Sous la moyenne de l’arrondissement',
|
|
||||||
showcaseStep3Stat3Label: 'Âge médian',
|
|
||||||
showcaseStep3Stat4Label: 'Débit internet',
|
|
||||||
showcaseStep3Stat4Value: '1 Gbps disponible',
|
|
||||||
showcaseStep3Stat5Label: 'Écoles primaires',
|
|
||||||
showcaseStep3Stat5Value: '3 Outstanding à moins d’un mile',
|
|
||||||
showcaseStep4Tab: 'Repérer',
|
showcaseStep4Tab: 'Repérer',
|
||||||
showcaseStep4Title: 'Allez vérifier par vous-même',
|
showcaseStep4Title: 'Allez vérifier par vous-même',
|
||||||
showcaseStep4Body:
|
showcaseStep4Body:
|
||||||
'Emportez trois points de départ solides dans le monde réel. Parcourez les rues, testez le trajet et comparez les visites avec du contexte.',
|
'Emportez vos trois meilleurs codes postaux dans le monde réel. Parcourez les rues, testez le trajet et comparez les visites avec du contexte.',
|
||||||
showcaseStep4FileName: 'areas-to-scout.xlsx',
|
showcaseStep4FileName: 'areas-to-scout.xlsx',
|
||||||
showcaseStep4ExportLabel: 'Exporter vers Excel',
|
|
||||||
showcaseStep4ColPostcode: 'Code postal',
|
showcaseStep4ColPostcode: 'Code postal',
|
||||||
showcaseStep4ColScore: 'Compatibilité',
|
showcaseStep4ColScore: 'Compatibilité',
|
||||||
showcaseStep4ColCommute: 'Trajet',
|
showcaseStep4ColCommute: 'Trajet',
|
||||||
showcaseStep4ColPrice: 'Prix vendu médian',
|
showcaseStep4ColPrice: '£/sqm',
|
||||||
showcaseStep4Conclusion: 'Vous pouvez commencer votre recherche ici.',
|
showcaseStep4Conclusion: 'Commencez vos repérages ici.',
|
||||||
statProperties: 'ventes historiques',
|
statProperties: 'ventes historiques',
|
||||||
statFilters: 'filtres combinables',
|
statFilters: 'filtres combinables',
|
||||||
statEvery: 'Chaque',
|
statEvery: 'Chaque',
|
||||||
statPostcodeInEngland: 'code postal d’Angleterre',
|
statPostcodeInEngland: 'code postal d’Angleterre',
|
||||||
coverageNote:
|
coverageNote:
|
||||||
'Couvre tous les codes postaux d’Angleterre — plus de 200 champs de données chacun. L’Écosse et le pays de Galles sont sur la feuille de route.',
|
'Couvre tous les codes postaux d’Angleterre, plus de 200 champs de données chacun. L’Écosse et le pays de Galles sont sur la feuille de route.',
|
||||||
priceStrip:
|
priceStrip:
|
||||||
'Accès à vie, actuellement {{price}} — le prix augmente à mesure que les paliers se remplissent.',
|
'Payez une fois pour un accès à vie : actuellement {{price}}, en hausse à mesure que chaque palier se remplit.',
|
||||||
priceStripSpots: '{{count}} place restante à ce prix.',
|
priceStripSpots: '{{count}} place restante à ce prix.',
|
||||||
priceStripSpotsPlural: '{{count}} places restantes à ce prix.',
|
priceStripSpotsPlural: '{{count}} places restantes à ce prix.',
|
||||||
priceStripCta: 'Voir les tarifs',
|
priceStripCta: 'Voir les tarifs',
|
||||||
ourPhilosophy: 'Commencez par ce qui compte, puis trouvez le bon code postal',
|
ourPhilosophy: 'La réputation est déjà dans le prix. La valeur, pas encore.',
|
||||||
philosophyP1:
|
philosophyP1:
|
||||||
'La plupart des sites immobiliers demandent où vous voulez vivre. À Londres, c’est particulièrement difficile, mais le même problème existe partout en Angleterre : les acheteurs partent des quelques lieux qu’ils connaissent, puis vérifient séparément trajets, écoles, criminalité, Street View, haut débit et prix vendus.',
|
'Une partie du prix d’un code postal vient de ses murs, de son secteur scolaire et de son trajet. Le reste, c’est juste le nom. Les acheteurs font monter les codes postaux dont ils ont entendu parler, si bien que la rue d’à côté (identique sur chaque critère qui influe sur le prix) reste discrètement moins chère. Repérer cet écart à la main exige une douzaine d’onglets : prix vendus, Ofsted, criminalité, bruit, surfaces.',
|
||||||
philosophyP2:
|
philosophyP2:
|
||||||
'Perfect Postcode inverse la recherche. Dites à la carte ce qui compte et elle affiche les codes postaux compatibles, avec les raisons pour lesquelles ils méritent d’être étudiés. Les données d’abord, puis allez tester l’ambiance.',
|
'Perfect Postcode fait les recoupements pour vous. Indiquez à la carte votre budget et vos critères non négociables ; elle évalue chaque code postal d’Angleterre sur les éléments qui influent sur le prix et place les sous-cotés en tête. Ensuite, allez les arpenter.',
|
||||||
streetTitle: 'Tout change rue par rue',
|
streetTitle: 'L’écart se joue rue par rue',
|
||||||
streetIntro:
|
streetIntro:
|
||||||
'Les grands noms de quartiers cachent les détails importants : le côté de la gare, le bruit routier, les écoles, le trajet exact et les vrais prix de vente.',
|
'Les grands noms de quartiers cachent où se trouvent les bonnes affaires : le côté de la gare moins cher, la rue plus calme, le même secteur scolaire, et le vrai prix au mètre carré de biens quasi identiques.',
|
||||||
streetCard1Title: 'Trouvez les secteurs que vous auriez manqués',
|
streetCard1Title: 'Trouvez le jumeau moins cher',
|
||||||
streetCard1Body:
|
streetCard1Body:
|
||||||
'Faites ressortir les codes postaux adaptés à vos critères, au lieu de dépendre seulement des noms connus ou des recommandations.',
|
'Chaque code postal réputé a un voisin plus calme avec le même secteur scolaire, la même gare et la même époque de construction, sans la prime, et sans la surcote du quartier « en devenir ». Nous plaçons les deux côte à côte pour que l’écart soit impossible à manquer.',
|
||||||
streetCard2Title: 'Voyez les compromis avant les visites',
|
streetCard2Title: 'Voyez ce que votre argent achète vraiment',
|
||||||
streetCard2Body:
|
streetCard2Body:
|
||||||
'Comparez prix, surface, trajet, sécurité, écoles, haut débit, bruit et énergie avant de passer vos week-ends à enchaîner les visites.',
|
'Surface, prix vendus, trajet, criminalité, écoles, haut débit, bruit et classement énergétique sur un seul écran, pas huit onglets et un tableur. Décidez ce qui mérite un samedi avant de passer ce samedi.',
|
||||||
othersVs: 'Autres outils vs',
|
othersVs: 'Les autres vs',
|
||||||
checkMyPostcode: 'Portails d’annonces',
|
checkMyPostcode: 'Portails d’annonces',
|
||||||
areaGuides: 'Rapports de code postal',
|
areaGuides: 'Rapports de code postal',
|
||||||
compSearchWithout: 'Découvrir des secteurs avant d’en connaître le nom',
|
compSearchWithout: 'Classé selon ce que vous obtenez, pas selon qui en a entendu parler',
|
||||||
compSearchWithoutSub: '(besoins d’abord, lieu ensuite)',
|
compSearchWithoutSub: '(le jumeau moins cher pour vos besoins, pas le nom)',
|
||||||
compAreaData: 'Données de quartier au niveau du code postal',
|
compAreaData: 'Données de quartier au niveau du code postal',
|
||||||
compAreaDataSub: '(criminalité, écoles, bruit, haut débit, services)',
|
compAreaDataSub: '(criminalité, écoles, bruit, haut débit, services)',
|
||||||
compPropertyData: 'Historique par bien',
|
compPropertyData: 'Historique par bien',
|
||||||
compPropertyDataSub: '(prix vendus, EPC, surface, valeur estimée)',
|
compPropertyDataSub: '(prix vendus, EPC, surface, valeur estimée)',
|
||||||
compFilters: '40+ filtres qui fonctionnent ensemble',
|
compFilters: '40+ filtres qui fonctionnent ensemble',
|
||||||
compFiltersSub: '(pas un code postal ou une annonce à la fois)',
|
compFiltersSub: '(pas un code postal ou une annonce à la fois)',
|
||||||
ctaTitle: 'Arrêtez de deviner où acheter ou louer.',
|
compListings: 'Annonces en direct, photos et visites',
|
||||||
|
compListingsSub: '(le quotidien de l’achat d’un bien précis)',
|
||||||
|
twinBadge: 'Exemple réel',
|
||||||
|
twinTitle: 'La même vie, un code postal moins cher',
|
||||||
|
twinIntro:
|
||||||
|
'Deux voisins du nord de Londres, distants de 1,3 km : des appartements aux secteurs de primaire comparables et au même trajet d’environ 30 minutes, pourtant à un prix au mètre carré très différent.',
|
||||||
|
twinPriceyLabel: 'Le nom que tout le monde connaît',
|
||||||
|
twinValueLabel: 'Son voisin plus calme',
|
||||||
|
twinPerSqm: '{{value}}/sqm',
|
||||||
|
twinSameSchool: 'Tous deux dans des secteurs de primaire classée Outstanding',
|
||||||
|
twinSameCommute: 'Tous deux à environ 30 min du centre de Londres en transports',
|
||||||
|
twinDelta: '{{percent}} de moins par mètre carré',
|
||||||
|
twinFootnote:
|
||||||
|
'Un exemple réel issu de nos données : £/m² médian pour les appartements vendus depuis 2021. Explorez la carte en direct pour trouver le vôtre.',
|
||||||
|
twinCta: 'Trouver une pépite comme celle-ci près de chez moi',
|
||||||
|
ctaTitle: 'Arrêtez de surpayer un nom.',
|
||||||
ctaDescription:
|
ctaDescription:
|
||||||
'Construisez une sélection de codes postaux adaptés à votre vraie vie, puis allez les tester sur place.',
|
'Construisez votre sélection sur la carte en direct, gratuitement. Une fois convaincu, débloquez tous les filtres à vie. Payez une fois, sans abonnement.',
|
||||||
|
guaranteeNote:
|
||||||
|
'Payez une fois. Jamais d’abonnement. Garantie satisfait ou remboursé de 30 jours.',
|
||||||
},
|
},
|
||||||
|
|
||||||
// ── Pricing Page ───────────────────────────────────
|
// ── Pricing Page ───────────────────────────────────
|
||||||
|
|
@ -1157,13 +1182,17 @@ const fr: Translations = {
|
||||||
},
|
},
|
||||||
|
|
||||||
pricingPage: {
|
pricingPage: {
|
||||||
|
cachedNotice:
|
||||||
|
'Impossible d’actualiser les tarifs en direct ; ces chiffres peuvent être obsolètes.',
|
||||||
|
scrollPrev: 'Afficher les offres précédentes',
|
||||||
|
scrollNext: 'Afficher plus d’offres',
|
||||||
title: 'Acheter avec un meilleur secteur de recherche',
|
title: 'Acheter avec un meilleur secteur de recherche',
|
||||||
subtitle:
|
subtitle:
|
||||||
'Accès à vie à la carte qui vous aide à savoir où chercher avant de réserver des visites.',
|
'Accès à vie à la carte qui vous aide à savoir où chercher avant de réserver des visites.',
|
||||||
costContext:
|
costContext:
|
||||||
'Les acheteurs passent souvent leurs soirées à recouper annonces, trajets, rapports scolaires, cartes de criminalité, Street View et prix vendus. À Londres, c’est incessant, mais le même problème existe dans toute l’Angleterre. Perfect Postcode rassemble la recherche de secteur sur une seule carte avant que vous n’engagiez vos week-ends, vos frais et votre attention.',
|
'Les acheteurs passent souvent leurs soirées à recouper annonces, trajets, rapports scolaires, cartes de criminalité, Street View et prix vendus. À Londres, c’est incessant, mais le même problème existe dans toute l’Angleterre. Perfect Postcode rassemble la recherche de secteur sur une seule carte avant que vous n’engagiez vos week-ends, vos frais et votre attention.',
|
||||||
lessThanSurvey:
|
lessThanSurvey:
|
||||||
'Moins d’un dixième du prix d’une expertise — pour une décision bien plus importante.',
|
'Moins d’un dixième du prix d’une expertise, pour une décision bien plus importante.',
|
||||||
currentTier: 'Offre actuelle',
|
currentTier: 'Offre actuelle',
|
||||||
firstNUsers: '{{count}} premiers utilisateurs',
|
firstNUsers: '{{count}} premiers utilisateurs',
|
||||||
everyoneAfter: 'Utilisateurs suivants',
|
everyoneAfter: 'Utilisateurs suivants',
|
||||||
|
|
@ -1205,7 +1234,7 @@ const fr: Translations = {
|
||||||
videos: 'Vidéos',
|
videos: 'Vidéos',
|
||||||
videosTitle: 'Vidéos pour les réseaux sociaux',
|
videosTitle: 'Vidéos pour les réseaux sociaux',
|
||||||
videosIntro:
|
videosIntro:
|
||||||
'De courtes vidéos de nos réseaux sociaux — chacune montre une recherche en action, des rues calmes aux secteurs scolaires en passant par les temps de trajet.',
|
'De courtes vidéos de nos réseaux sociaux : chacune montre une recherche en action, des rues calmes aux secteurs scolaires en passant par les temps de trajet.',
|
||||||
video01Title: 'Trouvez le jumeau moins cher',
|
video01Title: 'Trouvez le jumeau moins cher',
|
||||||
video01Desc:
|
video01Desc:
|
||||||
'Décrivez tout votre projet immobilier en une phrase simple et voyez chaque code postal correspondant en Angleterre se classer par rapport qualité-prix, révélant le jumeau moins cher que personne n’a fait monter aux enchères.',
|
'Décrivez tout votre projet immobilier en une phrase simple et voyez chaque code postal correspondant en Angleterre se classer par rapport qualité-prix, révélant le jumeau moins cher que personne n’a fait monter aux enchères.',
|
||||||
|
|
@ -1214,7 +1243,7 @@ const fr: Translations = {
|
||||||
'Colorez Londres selon le temps de trajet vers le centre, limitez à 20 minutes, et voyez des trajets identiques se diviser entre les noms que tout le monde connaît et les codes postaux plus calmes que personne n’a fait monter.',
|
'Colorez Londres selon le temps de trajet vers le centre, limitez à 20 minutes, et voyez des trajets identiques se diviser entre les noms que tout le monde connaît et les codes postaux plus calmes que personne n’a fait monter.',
|
||||||
video03Title: 'Le dossier de preuves du code postal',
|
video03Title: 'Le dossier de preuves du code postal',
|
||||||
video03Desc:
|
video03Desc:
|
||||||
'Touchez un code postal et un panneau s’ouvre avec ses prix de vente, ses secteurs scolaires, la criminalité et Street View — pour savoir si vous payez pour de la valeur ou seulement pour une réputation.',
|
'Touchez un code postal et un panneau s’ouvre avec ses prix de vente, ses secteurs scolaires, la criminalité et Street View, pour savoir si vous payez pour de la valeur ou seulement pour une réputation.',
|
||||||
video04Title: 'La rue calme qu’on néglige',
|
video04Title: 'La rue calme qu’on néglige',
|
||||||
video04Desc:
|
video04Desc:
|
||||||
'Les codes postaux célèbres intègrent leur réputation au prix, mais une photo d’annonce reste muette sur le bruit. Filtrez par décibels pour trouver la rue vraiment calme juste à côté que personne n’a fait monter.',
|
'Les codes postaux célèbres intègrent leur réputation au prix, mais une photo d’annonce reste muette sur le bruit. Filtrez par décibels pour trouver la rue vraiment calme juste à côté que personne n’a fait monter.',
|
||||||
|
|
@ -1223,7 +1252,7 @@ const fr: Translations = {
|
||||||
'Une famille de Leeds cherche une bonne école primaire, peu de criminalité et un budget sous £350k, et fait apparaître les rues discrètement moins chères qui partagent exactement le même secteur.',
|
'Une famille de Leeds cherche une bonne école primaire, peu de criminalité et un budget sous £350k, et fait apparaître les rues discrètement moins chères qui partagent exactement le même secteur.',
|
||||||
video06Title: 'L’effet Waitrose, déjà dans le prix',
|
video06Title: 'L’effet Waitrose, déjà dans le prix',
|
||||||
video06Desc:
|
video06Desc:
|
||||||
'Être à pied d’un Waitrose, d’une station de métro et d’un parc est un surcoût déjà intégré — trouvez les codes postaux voisins offrant les mêmes commodités pour moins cher au mètre carré.',
|
'Être à pied d’un Waitrose, d’une station de métro et d’un parc est un surcoût déjà intégré. Trouvez les codes postaux voisins offrant les mêmes commodités pour moins cher au mètre carré.',
|
||||||
video07Title: 'Une carte de la valeur pour les locataires',
|
video07Title: 'Une carte de la valeur pour les locataires',
|
||||||
video07Desc:
|
video07Desc:
|
||||||
'Les codes postaux réputés coûtent aussi plus cher à louer. Indiquez votre loyer, votre trajet et une rue calme, et voyez quels codes postaux de Londres tiennent vraiment dans le budget.',
|
'Les codes postaux réputés coûtent aussi plus cher à louer. Indiquez votre loyer, votre trajet et une rue calme, et voyez quels codes postaux de Londres tiennent vraiment dans le budget.',
|
||||||
|
|
@ -1336,7 +1365,7 @@ const fr: Translations = {
|
||||||
faqPricingTitle: 'Accès',
|
faqPricingTitle: 'Accès',
|
||||||
faqTipsTitle: 'Astuces carte',
|
faqTipsTitle: 'Astuces carte',
|
||||||
faqBehindDataTitle: 'Dans les coulisses',
|
faqBehindDataTitle: 'Dans les coulisses',
|
||||||
// FAQ items — Finding Your Area
|
// FAQ items: Finding Your Area
|
||||||
faqFinding1Q: 'Où chercher quand les zones évidentes sont trop chères ?',
|
faqFinding1Q: 'Où chercher quand les zones évidentes sont trop chères ?',
|
||||||
faqFinding1A:
|
faqFinding1A:
|
||||||
'Commencez par ce qui est non négociable : budget, type de logement, espace, trajet, écoles, sécurité, bruit, haut débit, parcs et tout ce qui compte pour vous. La carte masque les lieux qui ne correspondent pas, afin de faire apparaître des zones moins évidentes avant de parcourir les annonces.',
|
'Commencez par ce qui est non négociable : budget, type de logement, espace, trajet, écoles, sécurité, bruit, haut débit, parcs et tout ce qui compte pour vous. La carte masque les lieux qui ne correspondent pas, afin de faire apparaître des zones moins évidentes avant de parcourir les annonces.',
|
||||||
|
|
@ -1346,7 +1375,7 @@ const fr: Translations = {
|
||||||
faqFinding3Q: 'Que faire si ma recherche renvoie trop ou trop peu de zones ?',
|
faqFinding3Q: 'Que faire si ma recherche renvoie trop ou trop peu de zones ?',
|
||||||
faqFinding3A:
|
faqFinding3A:
|
||||||
'Gardez vos indispensables, puis colorez la carte selon une chose à comparer, comme le prix au m², le bruit routier, le score des écoles ou le temps de trajet. S’il ne reste presque rien, relâchez un curseur et voyez quel changement ouvre de nouvelles options.',
|
'Gardez vos indispensables, puis colorez la carte selon une chose à comparer, comme le prix au m², le bruit routier, le score des écoles ou le temps de trajet. S’il ne reste presque rien, relâchez un curseur et voyez quel changement ouvre de nouvelles options.',
|
||||||
// FAQ items — Commute and Travel
|
// FAQ items: Commute and Travel
|
||||||
faqCommute1Q: 'Comment les temps de trajet sont-ils calculés ?',
|
faqCommute1Q: 'Comment les temps de trajet sont-ils calculés ?',
|
||||||
faqCommute1A:
|
faqCommute1A:
|
||||||
'Les temps de trajet sont calculés à l’avance pour chaque destination enregistrée. Nous déterminons quels codes postaux peuvent atteindre cette destination en voiture, à vélo, à pied ou en transports en commun, puis nous conservons ces résultats pour que la carte réponde vite pendant que vous filtrez.',
|
'Les temps de trajet sont calculés à l’avance pour chaque destination enregistrée. Nous déterminons quels codes postaux peuvent atteindre cette destination en voiture, à vélo, à pied ou en transports en commun, puis nous conservons ces résultats pour que la carte réponde vite pendant que vous filtrez.',
|
||||||
|
|
@ -1356,21 +1385,21 @@ const fr: Translations = {
|
||||||
faqCommute3Q: 'Quand utiliser le bouton Meilleur cas ?',
|
faqCommute3Q: 'Quand utiliser le bouton Meilleur cas ?',
|
||||||
faqCommute3A:
|
faqCommute3A:
|
||||||
'Utilisez le bouton Meilleur cas pour les trajets en transports en commun lorsque vous voulez voir le résultat avec un départ bien choisi et de bonnes correspondances. Laissez-le désactivé pour la comparaison quotidienne, car le réglage normal est plus proche de ce à quoi vous attendre la plupart des jours.',
|
'Utilisez le bouton Meilleur cas pour les trajets en transports en commun lorsque vous voulez voir le résultat avec un départ bien choisi et de bonnes correspondances. Laissez-le désactivé pour la comparaison quotidienne, car le réglage normal est plus proche de ce à quoi vous attendre la plupart des jours.',
|
||||||
// FAQ items — Budget and Value
|
// FAQ items: Budget and Value
|
||||||
faqBudget1Q: 'Comment estimez-vous les prix actuels ?',
|
faqBudget1Q: 'Comment estimez-vous les prix actuels ?',
|
||||||
faqBudget1A:
|
faqBudget1A:
|
||||||
'L’estimation part du dernier prix de vente enregistré par HM Land Registry. Nous le ramenons au marché actuel en observant comment des logements similaires ont évolué, surtout les logements du même type à proximité. Quand il y a peu de ventes locales, l’estimation s’appuie davantage sur les tendances d’une zone plus large. Elle est ensuite comparée aux ventes récentes proches et à la surface du logement.',
|
'L’estimation part du dernier prix de vente enregistré par HM Land Registry. Nous le ramenons au marché actuel en observant comment des logements similaires ont évolué, surtout les logements du même type à proximité. Quand il y a peu de ventes locales, l’estimation s’appuie davantage sur les tendances d’une zone plus large. Elle est ensuite comparée aux ventes récentes proches et à la surface du logement.',
|
||||||
faqBudget2Q: 'Pourquoi utiliser le prix actuel estimé plutôt que le dernier prix vendu ?',
|
faqBudget2Q: 'Pourquoi utiliser le prix actuel estimé plutôt que le dernier prix vendu ?',
|
||||||
faqBudget2A:
|
faqBudget2A:
|
||||||
'Le dernier prix vendu peut dater de plusieurs années ou décennies, alors que les prix demandés ne couvrent que les biens en vente aujourd’hui. Le prix actuel estimé rapproche les anciennes ventes du marché actuel, pour comparer plus de logements et repérer des zones qui semblent offrir une meilleure valeur. C’est un guide pour préparer une sélection, pas une estimation bancaire.',
|
'Le dernier prix vendu peut dater de plusieurs années ou décennies, alors que les prix demandés ne couvrent que les biens en vente aujourd’hui. Le prix actuel estimé rapproche les anciennes ventes du marché actuel, pour comparer plus de logements et repérer des zones qui semblent offrir une meilleure valeur. C’est un guide pour préparer une sélection, pas une estimation bancaire.',
|
||||||
// FAQ items — Safety and Neighbourhood
|
// FAQ items: Safety and Neighbourhood
|
||||||
faqSafety1Q: 'Quels types de criminalité sont courants autour de ce code postal ?',
|
faqSafety1Q: 'Quels types de criminalité sont courants autour de ce code postal ?',
|
||||||
faqSafety1A:
|
faqSafety1A:
|
||||||
'La criminalité enregistrée par la police est ventilée par type, notamment violences, cambriolages, vols avec violence, infractions liées aux véhicules, comportements antisociaux, vols à l’étalage, stupéfiants et ordre public. Vous pouvez filtrer les risques précis qui vous importent au lieu de dépendre d’un score de sécurité vague.',
|
'La criminalité enregistrée par la police est ventilée par type, notamment violences, cambriolages, vols avec violence, infractions liées aux véhicules, comportements antisociaux, vols à l’étalage, stupéfiants et ordre public. Vous pouvez filtrer les risques précis qui vous importent au lieu de dépendre d’un score de sécurité vague.',
|
||||||
faqSafety2Q: 'Que vérifier avant de visiter une rue que je ne connais pas ?',
|
faqSafety2Q: 'Que vérifier avant de visiter une rue que je ne connais pas ?',
|
||||||
faqSafety2A:
|
faqSafety2A:
|
||||||
'Vérifiez criminalité, bruit routier, haut débit, parcs, commerces alimentaires, écoles et trajet avant de réserver. Les photos d’annonce peuvent être utiles, mais elles ne devraient pas être votre première source sur la rue.',
|
'Vérifiez criminalité, bruit routier, haut débit, parcs, commerces alimentaires, écoles et trajet avant de réserver. Les photos d’annonce peuvent être utiles, mais elles ne devraient pas être votre première source sur la rue.',
|
||||||
// FAQ items — Families and Schools
|
// FAQ items: Families and Schools
|
||||||
faqFamilies1Q:
|
faqFamilies1Q:
|
||||||
'Quelles zones offrent le bon équilibre entre écoles, espace, sécurité et trajet ?',
|
'Quelles zones offrent le bon équilibre entre écoles, espace, sécurité et trajet ?',
|
||||||
faqFamilies1A:
|
faqFamilies1A:
|
||||||
|
|
@ -1378,7 +1407,7 @@ const fr: Translations = {
|
||||||
faqFamilies2Q: 'Est-ce que cela prouve que je suis dans le secteur d’une école ?',
|
faqFamilies2Q: 'Est-ce que cela prouve que je suis dans le secteur d’une école ?',
|
||||||
faqFamilies2A:
|
faqFamilies2A:
|
||||||
'Non. Nous montrons la qualité des écoles proches et les informations locales sur l’éducation, mais les secteurs d’admission et règles de priorité peuvent changer. Utilisez Perfect Postcode pour sélectionner des lieux, puis vérifiez les admissions auprès de l’école ou de la mairie.',
|
'Non. Nous montrons la qualité des écoles proches et les informations locales sur l’éducation, mais les secteurs d’admission et règles de priorité peuvent changer. Utilisez Perfect Postcode pour sélectionner des lieux, puis vérifiez les admissions auprès de l’école ou de la mairie.',
|
||||||
// FAQ items — Environment and Quality of Life
|
// FAQ items: Environment and Quality of Life
|
||||||
faqEnv1Q:
|
faqEnv1Q:
|
||||||
'Comment éviter une route bruyante sans perdre en qualité de trajet ou de haut débit ?',
|
'Comment éviter une route bruyante sans perdre en qualité de trajet ou de haut débit ?',
|
||||||
faqEnv1A:
|
faqEnv1A:
|
||||||
|
|
@ -1390,7 +1419,7 @@ const fr: Translations = {
|
||||||
faqEnv3Q: 'Quels coûts d’usage puis-je vérifier avant une visite ?',
|
faqEnv3Q: 'Quels coûts d’usage puis-je vérifier avant une visite ?',
|
||||||
faqEnv3A:
|
faqEnv3A:
|
||||||
'Vous pouvez vérifier la note énergétique, la surface, l’âge du bâtiment, la zone de council tax, le haut débit et le bruit avant la visite. Cela ne prédit pas vos factures exactes, mais aide à éviter tôt les incompatibilités évidentes.',
|
'Vous pouvez vérifier la note énergétique, la surface, l’âge du bâtiment, la zone de council tax, le haut débit et le bruit avant la visite. Cela ne prédit pas vos factures exactes, mais aide à éviter tôt les incompatibilités évidentes.',
|
||||||
// FAQ items — Listing Portals and Due Diligence
|
// FAQ items: Listing Portals and Due Diligence
|
||||||
faqDueDiligence1Q: 'Faut-il l’utiliser avant ou après Rightmove ?',
|
faqDueDiligence1Q: 'Faut-il l’utiliser avant ou après Rightmove ?',
|
||||||
faqDueDiligence1A:
|
faqDueDiligence1A:
|
||||||
'Utilisez Perfect Postcode avant et en parallèle des sites d’annonces. Rightmove, Zoopla et OnTheMarket restent les endroits où vérifier ce qui est en vente maintenant, les photos, les agents, les visites et les alertes. Perfect Postcode vous aide à décider quels codes postaux valent la peine d’être cherchés.',
|
'Utilisez Perfect Postcode avant et en parallèle des sites d’annonces. Rightmove, Zoopla et OnTheMarket restent les endroits où vérifier ce qui est en vente maintenant, les photos, les agents, les visites et les alertes. Perfect Postcode vous aide à décider quels codes postaux valent la peine d’être cherchés.',
|
||||||
|
|
@ -1404,11 +1433,11 @@ const fr: Translations = {
|
||||||
faqDueDiligence4Q: 'Que dois-je encore vérifier avant de faire une offre ?',
|
faqDueDiligence4Q: 'Que dois-je encore vérifier avant de faire une offre ?',
|
||||||
faqDueDiligence4A:
|
faqDueDiligence4A:
|
||||||
'Utilisez Perfect Postcode pour vérifier la zone et la valeur probable, puis confirmez les détails de l’annonce avant de faire une offre. Vérifiez aussi le statut de propriété, les conditions du bail, les charges, l’historique d’urbanisme, le risque d’inondation, les questions juridiques, les exigences du prêt et les rapports d’expertise.',
|
'Utilisez Perfect Postcode pour vérifier la zone et la valeur probable, puis confirmez les détails de l’annonce avant de faire une offre. Vérifiez aussi le statut de propriété, les conditions du bail, les charges, l’historique d’urbanisme, le risque d’inondation, les questions juridiques, les exigences du prêt et les rapports d’expertise.',
|
||||||
// FAQ items — Privacy and Data Protection
|
// FAQ items: Privacy and Data Protection
|
||||||
faqPrivacy1Q: 'Stockez-vous des données personnelles me concernant ?',
|
faqPrivacy1Q: 'Stockez-vous des données personnelles me concernant ?',
|
||||||
faqPrivacy1A:
|
faqPrivacy1A:
|
||||||
'Les informations immobilières et de quartier ne contiennent pas vos données personnelles. Si vous créez un compte, nous stockons seulement ce qui est nécessaire au service, comme votre adresse e-mail, votre statut d’accès, votre choix de newsletter, vos recherches enregistrées, vos liens partagés et les enregistrements de paiement gérés par Stripe. Ces données de compte sont traitées selon la loi britannique sur la confidentialité.',
|
'Les informations immobilières et de quartier ne contiennent pas vos données personnelles. Si vous créez un compte, nous stockons seulement ce qui est nécessaire au service, comme votre adresse e-mail, votre statut d’accès, votre choix de newsletter, vos recherches enregistrées, vos liens partagés et les enregistrements de paiement gérés par Stripe. Ces données de compte sont traitées selon la loi britannique sur la confidentialité.',
|
||||||
// FAQ items — Why Perfect Postcode
|
// FAQ items: Why Perfect Postcode
|
||||||
faqWhy1Q: 'Que montre cet outil que les portails d’annonces ne montrent généralement pas ?',
|
faqWhy1Q: 'Que montre cet outil que les portails d’annonces ne montrent généralement pas ?',
|
||||||
faqWhy1A:
|
faqWhy1A:
|
||||||
'Les sites d’annonces partent des logements à vendre aujourd’hui. Perfect Postcode part des lieux qui correspondent à votre vie et à votre budget, avec prix vendus, espace, trajet, écoles, criminalité, bruit, haut débit, note énergétique, statut de propriété et services avant d’ouvrir les annonces.',
|
'Les sites d’annonces partent des logements à vendre aujourd’hui. Perfect Postcode part des lieux qui correspondent à votre vie et à votre budget, avec prix vendus, espace, trajet, écoles, criminalité, bruit, haut débit, note énergétique, statut de propriété et services avant d’ouvrir les annonces.',
|
||||||
|
|
@ -1418,7 +1447,7 @@ const fr: Translations = {
|
||||||
faqWhy3Q: 'Quelle est la fiabilité des données ?',
|
faqWhy3Q: 'Quelle est la fiabilité des données ?',
|
||||||
faqWhy3A:
|
faqWhy3A:
|
||||||
'Les principales sources sont officielles ou largement utilisées : prix vendus, notes énergétiques, informations locales, écoles, haut débit, criminalité, environnement, données cartographiques et données de rue. Elles sont utiles pour sélectionner et comparer, mais toute décision d’achat demande encore des vérifications à jour et, si besoin, un avis expert.',
|
'Les principales sources sont officielles ou largement utilisées : prix vendus, notes énergétiques, informations locales, écoles, haut débit, criminalité, environnement, données cartographiques et données de rue. Elles sont utiles pour sélectionner et comparer, mais toute décision d’achat demande encore des vérifications à jour et, si besoin, un avis expert.',
|
||||||
// FAQ items — Pricing and Access
|
// FAQ items: Pricing and Access
|
||||||
faqPricing1Q: 'Pourquoi payer alors que les rapports de code postal sont gratuits ?',
|
faqPricing1Q: 'Pourquoi payer alors que les rapports de code postal sont gratuits ?',
|
||||||
faqPricing1A:
|
faqPricing1A:
|
||||||
'Les outils gratuits par code postal sont utiles quand vous savez déjà quoi vérifier. Perfect Postcode sert à analyser chaque code postal d’Angleterre selon vos besoins, combiner les filtres, comparer les options, enregistrer les recherches et exporter une sélection avant d’engager vos week-ends de visites.',
|
'Les outils gratuits par code postal sont utiles quand vous savez déjà quoi vérifier. Perfect Postcode sert à analyser chaque code postal d’Angleterre selon vos besoins, combiner les filtres, comparer les options, enregistrer les recherches et exporter une sélection avant d’engager vos week-ends de visites.',
|
||||||
|
|
@ -1427,9 +1456,9 @@ const fr: Translations = {
|
||||||
'L’accès à vie signifie qu’un paiement donne à votre compte un accès continu à la carte payante Perfect Postcode pendant la durée de vie du service. Ce n’est pas un abonnement mensuel ou annuel, et les mises à jour normales des données sont incluses. Vous pouvez l’utiliser pendant cette recherche, revenir plus tard et conserver l’accès si vous déménagez à nouveau.',
|
'L’accès à vie signifie qu’un paiement donne à votre compte un accès continu à la carte payante Perfect Postcode pendant la durée de vie du service. Ce n’est pas un abonnement mensuel ou annuel, et les mises à jour normales des données sont incluses. Vous pouvez l’utiliser pendant cette recherche, revenir plus tard et conserver l’accès si vous déménagez à nouveau.',
|
||||||
faqPricing3Q: 'Que puis-je faire avec la version gratuite ?',
|
faqPricing3Q: 'Que puis-je faire avec la version gratuite ?',
|
||||||
faqPricing3A:
|
faqPricing3A:
|
||||||
'Les utilisateurs gratuits bénéficient de la carte Perfect Postcode complète sur toute l’Angleterre — tous les codes postaux et toutes les fonctionnalités — et peuvent appliquer jusqu’à 3 filtres à la fois. L’accès à vie supprime cette limite pour vous permettre de superposer un nombre illimité de filtres.',
|
'Les utilisateurs gratuits bénéficient de la carte Perfect Postcode complète sur toute l’Angleterre (tous les codes postaux et toutes les fonctionnalités) et peuvent appliquer jusqu’à 3 filtres à la fois. L’accès à vie supprime cette limite pour vous permettre de superposer un nombre illimité de filtres.',
|
||||||
|
|
||||||
// FAQ items — Tips and Tricks
|
// FAQ items: Tips and Tricks
|
||||||
faqTips1Q: 'Comment prévisualiser un filtre sur la carte ?',
|
faqTips1Q: 'Comment prévisualiser un filtre sur la carte ?',
|
||||||
faqTips1A:
|
faqTips1A:
|
||||||
'Cliquez sur Colorer à côté d’un filtre ou d’un critère pour colorer la carte selon cet élément. Vos filtres actifs restent en place, ce qui permet de comparer rapidement une chose comme le prix, le trajet, les écoles, la criminalité ou le bruit sans modifier votre sélection.',
|
'Cliquez sur Colorer à côté d’un filtre ou d’un critère pour colorer la carte selon cet élément. Vos filtres actifs restent en place, ce qui permet de comparer rapidement une chose comme le prix, le trajet, les écoles, la criminalité ou le bruit sans modifier votre sélection.',
|
||||||
|
|
@ -1440,22 +1469,22 @@ const fr: Translations = {
|
||||||
faqTips3A:
|
faqTips3A:
|
||||||
'Lorsqu’un critère colore la carte, utilisez Réinitialiser l’échelle de couleur dans la légende de la carte pour actualiser les couleurs des résultats affichés. C’est utile après un déplacement, un zoom ou une modification des filtres.',
|
'Lorsqu’un critère colore la carte, utilisez Réinitialiser l’échelle de couleur dans la légende de la carte pour actualiser les couleurs des résultats affichés. C’est utile après un déplacement, un zoom ou une modification des filtres.',
|
||||||
|
|
||||||
// FAQ items — Behind The Data
|
// FAQ items: Behind The Data
|
||||||
faqBehindData1Q: 'Pourquoi un aéroport peut-il sembler plus calme que les rues alentour ?',
|
faqBehindData1Q: 'Pourquoi un aéroport peut-il sembler plus calme que les rues alentour ?',
|
||||||
faqBehindData1A:
|
faqBehindData1A:
|
||||||
'Le niveau de bruit affiché pour un code postal est le plus fort des trois sources Defra — route, rail et avion — modélisé à 4 m du sol comme une moyenne pondérée sur 24 h (Lden). Dans une rue résidentielle passante, le bruit routier domine, généralement 65–75 dB. À l’intérieur du périmètre d’un aéroport, il n’y a pas de grands axes publics, donc la composante routière disparaît et il ne reste que la moyenne aérienne. London City Airport, par exemple, a un couvre-feu et un trafic limité, donc son Lden aérien sur 24 h reste modéré (environ 60–66 dB près de la piste) — l’aéroport apparaît donc plus calme que les axes A qui le bordent. On retrouve le même effet à Heathrow. C’est un artefact réel de la mesure du bruit des transports à hauteur de récepteur résidentiel, pas un bug.',
|
'Le niveau de bruit affiché pour un code postal est le plus fort des trois sources Defra (route, rail et avion) modélisé à 4 m du sol comme une moyenne pondérée sur 24 h (Lden). Dans une rue résidentielle passante, le bruit routier domine, généralement 65–75 dB. À l’intérieur du périmètre d’un aéroport, il n’y a pas de grands axes publics, donc la composante routière disparaît et il ne reste que la moyenne aérienne. London City Airport, par exemple, a un couvre-feu et un trafic limité, donc son Lden aérien sur 24 h reste modéré (environ 60–66 dB près de la piste), l’aéroport apparaît donc plus calme que les axes A qui le bordent. On retrouve le même effet à Heathrow. C’est un artefact réel de la mesure du bruit des transports à hauteur de récepteur résidentiel, pas un bug.',
|
||||||
faqBehindData2Q:
|
faqBehindData2Q:
|
||||||
'Pourquoi l’aéroport, l’autoroute ou un parc apparaît-il comme une grande forme ?',
|
'Pourquoi l’aéroport, l’autoroute ou un parc apparaît-il comme une grande forme ?',
|
||||||
faqBehindData2A:
|
faqBehindData2A:
|
||||||
'Au Royaume-Uni, les codes postaux n’ont pas de frontières officielles — Royal Mail définit un code postal comme une liste d’adresses de livraison, pas comme une zone. Perfect Postcode synthétise les polygones en donnant à chaque adresse sa part de terrain alentour. Les endroits sans adresse (une piste, une chaussée d’autoroute, un parc, un réservoir) sont remplis par le code postal résidentiel le plus proche. C’est pourquoi un aéroport ou un espace ouvert apparaît souvent comme un seul grand polygone, et sa valeur vient des quelques codes postaux situés à l’intérieur du périmètre.',
|
'Au Royaume-Uni, les codes postaux n’ont pas de frontières officielles. Royal Mail définit un code postal comme une liste d’adresses de livraison, pas comme une zone. Perfect Postcode synthétise les polygones en donnant à chaque adresse sa part de terrain alentour. Les endroits sans adresse (une piste, une chaussée d’autoroute, un parc, un réservoir) sont remplis par le code postal résidentiel le plus proche. C’est pourquoi un aéroport ou un espace ouvert apparaît souvent comme un seul grand polygone, et sa valeur vient des quelques codes postaux situés à l’intérieur du périmètre.',
|
||||||
faqBehindData3Q:
|
faqBehindData3Q:
|
||||||
'Pourquoi des codes postaux voisins partagent-ils les mêmes chiffres de criminalité ?',
|
'Pourquoi des codes postaux voisins partagent-ils les mêmes chiffres de criminalité ?',
|
||||||
faqBehindData3A:
|
faqBehindData3A:
|
||||||
'La criminalité enregistrée par la police au niveau rue est publiée à l’échelle LSOA — de petits quartiers d’environ 1 500 habitants. Chaque code postal situé dans la même LSOA hérite des mêmes totaux annuels, donc une rue résidentielle calme et une rue commerçante un pâté de maisons plus loin peuvent afficher des chiffres identiques si elles sont du même côté de la limite. Les taux par habitant peuvent sembler anormalement élevés dans des codes postaux couvrant des hôpitaux, des campus ou des zones industrielles, car ils enregistrent des incidents normalement mais comptent peu de résidents officiels.',
|
'La criminalité enregistrée par la police au niveau rue est publiée à l’échelle LSOA : de petits quartiers d’environ 1 500 habitants. Chaque code postal situé dans la même LSOA hérite des mêmes totaux annuels, donc une rue résidentielle calme et une rue commerçante un pâté de maisons plus loin peuvent afficher des chiffres identiques si elles sont du même côté de la limite. Les taux par habitant peuvent sembler anormalement élevés dans des codes postaux couvrant des hôpitaux, des campus ou des zones industrielles, car ils enregistrent des incidents normalement mais comptent peu de résidents officiels.',
|
||||||
faqBehindData4Q:
|
faqBehindData4Q:
|
||||||
'Que signifie le nombre de « zones de recrutement » — mon enfant peut-il fréquenter ces écoles ?',
|
'Que signifie le nombre de « zones de recrutement » ? Mon enfant peut-il fréquenter ces écoles ?',
|
||||||
faqBehindData4A:
|
faqBehindData4A:
|
||||||
'Chaque nombre correspond aux écoles publiques notées Bien ou Excellent dont la zone de recrutement historique modélisée couvre le code postal. Nous simulons la façon dont les admissions anglaises fondées sur la distance attribuent les places : les enfants (recensement 2021) candidatent aux écoles proches en arbitrant entre distance et note Ofsted, et une école sursouscrite admet les candidats les plus proches jusqu’à être pleine — son rayon de recrutement est la distance du dernier enfant admis, la « dernière distance d’admission » que publient les collectivités. Le modèle est calibré sur des centaines de ces distances publiées. Il estime où une place est plausible ; ce n’est pas un secteur d’admission officiel. Les critères religieux ou sélectifs, la priorité fratrie et les changements annuels de limites ne sont pas modélisés : confirmez toujours les zones et les règles d’admission auprès de l’école ou de la mairie avant de vous y fier pour une décision.',
|
'Chaque nombre correspond aux écoles publiques notées Bien ou Excellent dont la zone de recrutement historique modélisée couvre le code postal. Nous simulons la façon dont les admissions anglaises fondées sur la distance attribuent les places : les enfants (recensement 2021) candidatent aux écoles proches en arbitrant entre distance et note Ofsted, et une école sursouscrite admet les candidats les plus proches jusqu’à être pleine : son rayon de recrutement est la distance du dernier enfant admis, la « dernière distance d’admission » que publient les collectivités. Le modèle est calibré sur des centaines de ces distances publiées. Il estime où une place est plausible ; ce n’est pas un secteur d’admission officiel. Les critères religieux ou sélectifs, la priorité fratrie et les changements annuels de limites ne sont pas modélisés : confirmez toujours les zones et les règles d’admission auprès de l’école ou de la mairie avant de vous y fier pour une décision.',
|
||||||
faqBehindData5Q:
|
faqBehindData5Q:
|
||||||
'Pourquoi un code postal affiche-t-il « Gigabit » quand toutes les maisons n’en ont pas ?',
|
'Pourquoi un code postal affiche-t-il « Gigabit » quand toutes les maisons n’en ont pas ?',
|
||||||
faqBehindData5A:
|
faqBehindData5A:
|
||||||
|
|
@ -1526,6 +1555,7 @@ const fr: Translations = {
|
||||||
|
|
||||||
// ── Invite Page ────────────────────────────────────
|
// ── Invite Page ────────────────────────────────────
|
||||||
invitePage: {
|
invitePage: {
|
||||||
|
couldNotValidateTitle: 'Impossible de valider l’invitation',
|
||||||
youreInvited: 'Vous êtes invité !',
|
youreInvited: 'Vous êtes invité !',
|
||||||
specialOffer: 'Offre spéciale !',
|
specialOffer: 'Offre spéciale !',
|
||||||
invitedByFree: '{{name}} vous invite à obtenir un accès à vie gratuit.',
|
invitedByFree: '{{name}} vous invite à obtenir un accès à vie gratuit.',
|
||||||
|
|
@ -1589,17 +1619,17 @@ const fr: Translations = {
|
||||||
treesOutsideWoodlands: {
|
treesOutsideWoodlands: {
|
||||||
label: 'Arbres et boisements',
|
label: 'Arbres et boisements',
|
||||||
detail:
|
detail:
|
||||||
'Polygones de canopée Forest Research Trees Outside Woodland (TOW) v1 — arbres isolés et groupes d’arbres — 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. L’opacité des polygones varie selon la surface de canopée.',
|
'Polygones de canopée Forest Research Trees Outside Woodland (TOW) v1 (arbres isolés et groupes d’arbres) 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. L’opacité des polygones varie selon la surface de canopée.',
|
||||||
},
|
},
|
||||||
propertyBorders: {
|
propertyBorders: {
|
||||||
label: 'Limites de propriété',
|
label: 'Limites de propriété',
|
||||||
detail:
|
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 s’agit de « limites générales » fournies à titre indicatif uniquement, et non de la limite légale précise d’un 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 l’autorisation 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.',
|
'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 s’agit de « limites générales » fournies à titre indicatif uniquement, et non de la limite légale précise d’un 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 l’autorisation 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: {
|
newDevelopments: {
|
||||||
label: 'Nouveaux développements',
|
label: 'Nouveaux développements',
|
||||||
detail:
|
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 d’une capacité nette estimée en logements et d’un 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 qu’ils n’apparaissent 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 qu’une garantie de construction. Sous licence Open Government Licence v3.0.',
|
'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 d’une capacité nette estimée en logements et d’un 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 qu’ils n’apparaissent 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 qu’une garantie de construction. Sous licence Open Government Licence v3.0.',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
@ -1749,7 +1779,7 @@ const fr: Translations = {
|
||||||
'Housing Conditions Score': 'Score des conditions de logement',
|
'Housing Conditions Score': 'Score des conditions de logement',
|
||||||
'Air Quality and Road Safety Score': 'Score qualité de l’air et sécurité routière',
|
'Air Quality and Road Safety Score': 'Score qualité de l’air et sécurité routière',
|
||||||
|
|
||||||
// ─ Feature names (Crime) — taux normalisé par population, 7 ans & 2 ans ─
|
// ─ Feature names (Crime): taux normalisé par population, 7 ans & 2 ans ─
|
||||||
'Serious crime (/yr, 7y)': 'Infractions graves (par an, 7 ans)',
|
'Serious crime (/yr, 7y)': 'Infractions graves (par an, 7 ans)',
|
||||||
'Serious crime (/yr, 2y)': 'Infractions graves (par an, 2 ans)',
|
'Serious crime (/yr, 2y)': 'Infractions graves (par an, 2 ans)',
|
||||||
'Minor crime (/yr, 7y)': 'Infractions mineures (par an, 7 ans)',
|
'Minor crime (/yr, 7y)': 'Infractions mineures (par an, 7 ans)',
|
||||||
|
|
@ -1810,6 +1840,8 @@ const fr: Translations = {
|
||||||
'% Owner occupied': '% Propriétaires occupants',
|
'% Owner occupied': '% Propriétaires occupants',
|
||||||
'% Social rent': '% Logements sociaux',
|
'% Social rent': '% Logements sociaux',
|
||||||
'% Private rent': '% Location privée',
|
'% Private rent': '% Location privée',
|
||||||
|
'% Council housing': '% Logement municipal',
|
||||||
|
'% Ex-council': '% Ancien logement municipal',
|
||||||
'% White': '% Blancs',
|
'% White': '% Blancs',
|
||||||
'% South Asian': '% Sud-Asiatiques',
|
'% South Asian': '% Sud-Asiatiques',
|
||||||
'% Black': '% Noirs',
|
'% Black': '% Noirs',
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@ const hi: Translations = {
|
||||||
viewRecord: 'योजना रिकॉर्ड देखें ↗',
|
viewRecord: 'योजना रिकॉर्ड देखें ↗',
|
||||||
},
|
},
|
||||||
common: {
|
common: {
|
||||||
|
retry: 'पुनः प्रयास करें',
|
||||||
save: 'सहेजें',
|
save: 'सहेजें',
|
||||||
update: 'अपडेट करें',
|
update: 'अपडेट करें',
|
||||||
cancel: 'रद्द करें',
|
cancel: 'रद्द करें',
|
||||||
|
|
@ -90,7 +91,7 @@ const hi: Translations = {
|
||||||
'मैप पर दिख रहे उन सभी पोस्टकोड को export करें जो आपके मौजूदा फ़िल्टर से मैच करते हैं.',
|
'मैप पर दिख रहे उन सभी पोस्टकोड को export करें जो आपके मौजूदा फ़िल्टर से मैच करते हैं.',
|
||||||
modeList: 'पोस्टकोड की सूची',
|
modeList: 'पोस्टकोड की सूची',
|
||||||
modeListHint:
|
modeListHint:
|
||||||
'अपने पोस्टकोड एक-एक करके जोड़ें — स्पेसिंग और अक्षरों का रूप अपने आप ठीक हो जाएगा.',
|
'अपने पोस्टकोड एक-एक करके जोड़ें: स्पेसिंग और अक्षरों का रूप अपने आप ठीक हो जाएगा.',
|
||||||
listLabel: 'पोस्टकोड',
|
listLabel: 'पोस्टकोड',
|
||||||
listPlaceholder: 'जैसे SW1A 1AA',
|
listPlaceholder: 'जैसे SW1A 1AA',
|
||||||
addRow: 'पोस्टकोड जोड़ें',
|
addRow: 'पोस्टकोड जोड़ें',
|
||||||
|
|
@ -100,6 +101,7 @@ const hi: Translations = {
|
||||||
},
|
},
|
||||||
|
|
||||||
userMenu: {
|
userMenu: {
|
||||||
|
accountMenu: 'खाता मेनू',
|
||||||
fullAccess: 'Full access',
|
fullAccess: 'Full access',
|
||||||
demo: 'डेमो',
|
demo: 'डेमो',
|
||||||
themeLight: 'थीम: Light',
|
themeLight: 'थीम: Light',
|
||||||
|
|
@ -592,13 +594,23 @@ const hi: Translations = {
|
||||||
},
|
},
|
||||||
|
|
||||||
auth: {
|
auth: {
|
||||||
|
errorRateLimited: 'बहुत अधिक प्रयास। कृपया एक मिनट प्रतीक्षा करें और पुनः प्रयास करें।',
|
||||||
|
errorNetwork: 'सर्वर तक नहीं पहुँच सके। अपना कनेक्शन जाँचें और पुनः प्रयास करें।',
|
||||||
|
errorEmailTaken: 'इस ईमेल से एक खाता पहले से मौजूद है।',
|
||||||
|
errorPasswordWeak: 'पासवर्ड कम से कम 8 अक्षरों का होना चाहिए।',
|
||||||
|
errorEmailInvalid: 'कृपया एक मान्य ईमेल पता दर्ज करें।',
|
||||||
|
errorInvalidCredentials: 'ईमेल या पासवर्ड गलत है।',
|
||||||
|
logInInstead: 'इसके बजाय लॉग इन करें',
|
||||||
|
accountCreatedPleaseLogIn: 'खाता बन गया। जारी रखने के लिए कृपया लॉग इन करें।',
|
||||||
|
accountCreatedRateLimited:
|
||||||
|
'खाता बन गया। अभी बहुत अधिक प्रयास हुए। कृपया थोड़ी देर रुकें, फिर लॉग इन करें।',
|
||||||
logIn: 'लॉग इन',
|
logIn: 'लॉग इन',
|
||||||
createAccount: 'खाता बनाएं',
|
createAccount: 'खाता बनाएं',
|
||||||
resetPassword: 'पासवर्ड रीसेट करें',
|
resetPassword: 'पासवर्ड रीसेट करें',
|
||||||
valueProp:
|
valueProp:
|
||||||
'खोजें सहेजें, संपत्तियों को बुकमार्क करें और अपनी जरूरतों से मेल खाने वाले क्षेत्रों की शॉर्टलिस्ट बनाएं.',
|
'खोजें सहेजें, संपत्तियों को बुकमार्क करें और अपनी जरूरतों से मेल खाने वाले क्षेत्रों की शॉर्टलिस्ट बनाएं.',
|
||||||
dashboardActionsValueProp:
|
dashboardActionsValueProp:
|
||||||
'अपनी खोजें सहेजने, साझा करने और export करने के लिए मुफ्त खाता बनाएं — मुफ्त, कार्ड की जरूरत नहीं.',
|
'अपनी खोजें सहेजने, साझा करने और export करने के लिए मुफ्त खाता बनाएं: मुफ्त, कार्ड की जरूरत नहीं.',
|
||||||
continueWithGoogle: 'Google से जारी रखें',
|
continueWithGoogle: 'Google से जारी रखें',
|
||||||
email: 'ईमेल',
|
email: 'ईमेल',
|
||||||
emailPlaceholder: 'you@example.com',
|
emailPlaceholder: 'you@example.com',
|
||||||
|
|
@ -624,12 +636,12 @@ const hi: Translations = {
|
||||||
'आपने अपने मुफ्त खाते के सभी 5 फ़िल्टर इस्तेमाल कर लिए हैं. इंग्लैंड के हर पोस्टकोड और पड़ोस में असीमित फ़िल्टर लगाने के लिए आजीवन पहुँच पाएं. एक भुगतान, हमेशा के लिए.',
|
'आपने अपने मुफ्त खाते के सभी 5 फ़िल्टर इस्तेमाल कर लिए हैं. इंग्लैंड के हर पोस्टकोड और पड़ोस में असीमित फ़िल्टर लगाने के लिए आजीवन पहुँच पाएं. एक भुगतान, हमेशा के लिए.',
|
||||||
titleRegister: 'मुफ्त खाता बनाएं',
|
titleRegister: 'मुफ्त खाता बनाएं',
|
||||||
descriptionRegister:
|
descriptionRegister:
|
||||||
'मुफ्त खाते में 5 फ़िल्टर के साथ-साथ सहेजें, साझा करें और export करें — कार्ड की जरूरत नहीं. पूरे इंग्लैंड में असीमित फ़िल्टर चाहिए? आजीवन पहुँच लें.',
|
'मुफ्त खाते में 5 फ़िल्टर के साथ-साथ सहेजें, साझा करें और export करें: कार्ड की जरूरत नहीं. पूरे इंग्लैंड में असीमित फ़िल्टर चाहिए? आजीवन पहुँच लें.',
|
||||||
descriptionSharedRegister:
|
descriptionSharedRegister:
|
||||||
'यह एक साझा खोज है. अपनी खुद की 5 फ़िल्टर तक की खोज बनाने और सहेजने, साझा करने व export करने के लिए मुफ्त खाता बनाएं — या असीमित के लिए आजीवन पहुँच लें.',
|
'यह एक साझा खोज है. अपनी खुद की 5 फ़िल्टर तक की खोज बनाने और सहेजने, साझा करने व export करने के लिए मुफ्त खाता बनाएं, या असीमित के लिए आजीवन पहुँच लें.',
|
||||||
registerFree: 'मुफ्त खाता बनाएं',
|
registerFree: 'मुफ्त खाता बनाएं',
|
||||||
lifetimeUpsell: 'असीमित फ़िल्टर चाहिए?',
|
lifetimeUpsell: 'असीमित फ़िल्टर चाहिए?',
|
||||||
goLifetime: 'आजीवन पहुँच पाएं — {{price}}',
|
goLifetime: 'आजीवन पहुँच पाएं: {{price}}',
|
||||||
free: 'मुफ्त',
|
free: 'मुफ्त',
|
||||||
freeForEarly: 'शुरुआती उपयोगकर्ताओं के लिए मुफ्त. क्रेडिट कार्ड की जरूरत नहीं.',
|
freeForEarly: 'शुरुआती उपयोगकर्ताओं के लिए मुफ्त. क्रेडिट कार्ड की जरूरत नहीं.',
|
||||||
oneTimePayment: 'एक बार भुगतान. आजीवन पहुँच.',
|
oneTimePayment: 'एक बार भुगतान. आजीवन पहुँच.',
|
||||||
|
|
@ -677,7 +689,7 @@ const hi: Translations = {
|
||||||
upgradeToFullMap: 'पूरे मानचित्र पर अपग्रेड करें',
|
upgradeToFullMap: 'पूरे मानचित्र पर अपग्रेड करें',
|
||||||
registerPrompt:
|
registerPrompt:
|
||||||
'5 फ़िल्टर तक जोड़ने और अपनी खोजें सहेजने, साझा करने व export करने के लिए मुफ्त खाता बनाएं.',
|
'5 फ़िल्टर तक जोड़ने और अपनी खोजें सहेजने, साझा करने व export करने के लिए मुफ्त खाता बनाएं.',
|
||||||
registerSubPrompt: 'मुफ्त — कार्ड की जरूरत नहीं. आजीवन पहुँच के साथ असीमित फ़िल्टर.',
|
registerSubPrompt: 'मुफ्त: कार्ड की जरूरत नहीं. आजीवन पहुँच के साथ असीमित फ़िल्टर.',
|
||||||
registerCta: 'मुफ्त खाता बनाएं',
|
registerCta: 'मुफ्त खाता बनाएं',
|
||||||
chooseFilters:
|
chooseFilters:
|
||||||
'फ़िल्टर लगाने के लिए जोड़ें पर क्लिक करें. छोटे बटन डेटा विवरण दिखाते हैं या मानचित्र को रंगते हैं.',
|
'फ़िल्टर लगाने के लिए जोड़ें पर क्लिक करें. छोटे बटन डेटा विवरण दिखाते हैं या मानचित्र को रंगते हैं.',
|
||||||
|
|
@ -717,6 +729,11 @@ const hi: Translations = {
|
||||||
crimeType: 'अपराध प्रकार',
|
crimeType: 'अपराध प्रकार',
|
||||||
qualificationLevel: 'योग्यता स्तर',
|
qualificationLevel: 'योग्यता स्तर',
|
||||||
tenureType: 'आवास स्वामित्व',
|
tenureType: 'आवास स्वामित्व',
|
||||||
|
councilType: 'काउंसिल आवास का प्रकार',
|
||||||
|
councilStatus: 'प्रकार',
|
||||||
|
councilCurrent: 'वर्तमान',
|
||||||
|
councilEx: 'पूर्व काउंसिल',
|
||||||
|
councilBoth: 'दोनों',
|
||||||
crimeWindow: 'अवधि',
|
crimeWindow: 'अवधि',
|
||||||
crimeWindow7y: '7 वर्ष',
|
crimeWindow7y: '7 वर्ष',
|
||||||
crimeWindow2y: '2 वर्ष',
|
crimeWindow2y: '2 वर्ष',
|
||||||
|
|
@ -756,15 +773,15 @@ const hi: Translations = {
|
||||||
noChange: 'बिना बदलाव',
|
noChange: 'बिना बदलाव',
|
||||||
noChangeTitle: 'केवल सीधी यात्राएँ',
|
noChangeTitle: 'केवल सीधी यात्राएँ',
|
||||||
noChangeDesc:
|
noChangeDesc:
|
||||||
'<strong>बिना बदलाव</strong> वाली यात्राओं तक सीमित — पैदल चलें, एक सार्वजनिक परिवहन सेवा लें, फिर गंतव्य तक पैदल जाएं. सीधे आवागमन के लिए उपयोगी.',
|
'<strong>बिना बदलाव</strong> वाली यात्राओं तक सीमित: पैदल चलें, एक सार्वजनिक परिवहन सेवा लें, फिर गंतव्य तक पैदल जाएं. सीधे आवागमन के लिए उपयोगी.',
|
||||||
oneChange: 'एक बदलाव',
|
oneChange: 'एक बदलाव',
|
||||||
oneChangeTitle: 'एक बदलाव वाली यात्राएँ',
|
oneChangeTitle: 'एक बदलाव वाली यात्राएँ',
|
||||||
oneChangeDesc:
|
oneChangeDesc:
|
||||||
'<strong>अधिकतम एक बदलाव</strong> वाली यात्राओं की अनुमति देता है — दो परिवहन सेवाओं के बीच एक बदलाव ठीक है, इससे अधिक नहीं. बिना बदलाव और असीमित यात्राओं के बीच का विकल्प.',
|
'<strong>अधिकतम एक बदलाव</strong> वाली यात्राओं की अनुमति देता है: दो परिवहन सेवाओं के बीच एक बदलाव ठीक है, इससे अधिक नहीं. बिना बदलाव और असीमित यात्राओं के बीच का विकल्प.',
|
||||||
noBuses: 'बसों के बिना',
|
noBuses: 'बसों के बिना',
|
||||||
noBusesTitle: 'बसों को बाहर रखें',
|
noBusesTitle: 'बसों को बाहर रखें',
|
||||||
noBusesDesc:
|
noBusesDesc:
|
||||||
'बस सेवाओं को हटा देता है — केवल <strong>रेल, ट्यूब, ट्राम और फ़ेरी</strong>. ट्रैफिक देरी से बचने वाली यात्राओं को छांटने में उपयोगी.',
|
'बस सेवाओं को हटा देता है: केवल <strong>रेल, ट्यूब, ट्राम और फ़ेरी</strong>. ट्रैफिक देरी से बचने वाली यात्राओं को छांटने में उपयोगी.',
|
||||||
previewOnMap: 'मानचित्र पर पूर्वावलोकन',
|
previewOnMap: 'मानचित्र पर पूर्वावलोकन',
|
||||||
stopPreviewing: 'पूर्वावलोकन रोकें',
|
stopPreviewing: 'पूर्वावलोकन रोकें',
|
||||||
removeTravelTime: 'यात्रा समय हटाएं',
|
removeTravelTime: 'यात्रा समय हटाएं',
|
||||||
|
|
@ -832,8 +849,11 @@ const hi: Translations = {
|
||||||
},
|
},
|
||||||
actualListings: {
|
actualListings: {
|
||||||
label: 'लिस्टिंग',
|
label: 'लिस्टिंग',
|
||||||
show: 'वास्तविक लिस्टिंग दिखाएं',
|
modes: {
|
||||||
hide: 'वास्तविक लिस्टिंग छिपाएं',
|
new: 'नए निर्माण',
|
||||||
|
nonNew: 'गैर-नए',
|
||||||
|
hint: '“नए निर्माण” नई परियोजनाएँ दिखाता है; “गैर-नए” पुनर्विक्रय और अन्य लिस्टिंग दिखाता है।',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
poi: { zoomInToSeeDetails: 'विवरण देखने के लिए ज़ूम इन करें' },
|
poi: { zoomInToSeeDetails: 'विवरण देखने के लिए ज़ूम इन करें' },
|
||||||
},
|
},
|
||||||
|
|
@ -859,6 +879,7 @@ const hi: Translations = {
|
||||||
historyTitle: 'इतिहास',
|
historyTitle: 'इतिहास',
|
||||||
historySale: 'बिक्री',
|
historySale: 'बिक्री',
|
||||||
historyBuilt: 'निर्मित',
|
historyBuilt: 'निर्मित',
|
||||||
|
historyNewBuild: 'नया निर्माण',
|
||||||
tenureOwnerOccupied: 'मालिक का निवास',
|
tenureOwnerOccupied: 'मालिक का निवास',
|
||||||
tenureRentedPrivate: 'निजी किराये पर',
|
tenureRentedPrivate: 'निजी किराये पर',
|
||||||
tenureRentedSocial: 'सामाजिक किराया आवास',
|
tenureRentedSocial: 'सामाजिक किराया आवास',
|
||||||
|
|
@ -966,26 +987,29 @@ const hi: Translations = {
|
||||||
},
|
},
|
||||||
|
|
||||||
home: {
|
home: {
|
||||||
heroEyebrow: 'उन खरीदारों के लिए जो पूछते हैं “मुझे देखना कहां शुरू करना चाहिए?”',
|
heroEyebrow:
|
||||||
heroTitle1: 'वे पोस्टकोड खोजें जो',
|
'उन खरीदारों के लिए जो किसी पोस्टकोड की प्रतिष्ठा के लिए ज़्यादा कीमत चुकाने से इनकार करते हैं',
|
||||||
heroTitle2: 'आपकी जिंदगी से मेल खाते हैं',
|
heroTitle1: 'खोजें वह',
|
||||||
heroTitle3: 'सिर्फ वे क्षेत्र नहीं जिन्हें आप पहले से जानते हैं.',
|
heroTitle2: 'छिपा हुआ रत्न पोस्टकोड',
|
||||||
|
heroTitle3: 'वही स्कूल, वही आवागमन: चुपचाप सस्ता.',
|
||||||
heroSubtitle:
|
heroSubtitle:
|
||||||
'लंदन के बरो से लेकर आवागमन वाले कस्बों और क्षेत्रीय शहरों तक, इंग्लैंड में एक-एक जगह अलग से शोध करने के लिए बहुत अधिक स्थान हैं.',
|
'दो सड़कें एक ही स्कूल, एक ही स्टेशन और एक ही निर्माण वर्ष साझा कर सकती हैं, फिर भी हज़ारों के अंतर से बिकती हैं. इनमें से एक की कीमत गलत है: हम बताते हैं कि कौन सी.',
|
||||||
heroDescription:
|
heroDescription:
|
||||||
'अपना बजट, आवागमन, स्कूल, सुरक्षा, शोर, ब्रॉडबैंड और जीवनशैली की जरूरतें सेट करें. Perfect Postcode इंग्लैंड के पोस्टकोड स्कैन करता है और वे जगहें दिखाता है जो सच में मेल खाती हैं, उन क्षेत्रों सहित जिन्हें आप किसी लिस्टिंग पोर्टल में कभी टाइप नहीं करते.',
|
'अपना बजट और अपनी ज़रूरी शर्तें तय करें. Perfect Postcode इंग्लैंड के हर पोस्टकोड को इस आधार पर क्रम देता है कि हर पाउंड असल में क्या खरीदता है (फर्श क्षेत्रफल, स्कूल, आवागमन और सुरक्षा) और हर चुनाव के पीछे का प्रमाण साथ देता है.',
|
||||||
exploreTheMap: 'मेरे मेल खाते पोस्टकोड खोजें',
|
exploreTheMap: 'मेरा छिपा हुआ रत्न पोस्टकोड खोजें',
|
||||||
seeTheDifference: 'देखें यह कैसे काम करता है',
|
seeTheDifference: 'एक असली छिपा रत्न देखें',
|
||||||
|
freeToExplore: 'लाइव मानचित्र मुफ़्त देखें: न साइन-अप, न कार्ड.',
|
||||||
|
dataSourcesLabel: 'आधिकारिक रिकॉर्ड पर आधारित',
|
||||||
|
dataSources: 'Land Registry · ONS · Ofsted · DfT · Ordnance Survey · Police.uk',
|
||||||
productDemoLabel: 'Perfect Postcode उत्पाद डेमो',
|
productDemoLabel: 'Perfect Postcode उत्पाद डेमो',
|
||||||
playProductDemo: 'Perfect Postcode उत्पाद डेमो चलाएं',
|
playProductDemo: 'Perfect Postcode उत्पाद डेमो चलाएं',
|
||||||
scrollToProductDemo: 'उत्पाद डेमो तक स्क्रोल करें',
|
scrollToProductDemo: 'उत्पाद डेमो तक स्क्रोल करें',
|
||||||
showcaseHeader: 'यह कैसे काम करता है',
|
|
||||||
showcaseContext: 'Perfect Postcode कैसे काम करता है',
|
showcaseContext: 'Perfect Postcode कैसे काम करता है',
|
||||||
showcaseFeaturePriceShort: 'कीमत',
|
showcaseFeaturePriceShort: 'कीमत',
|
||||||
showcaseFeatureNoiseShort: 'शोर',
|
showcaseFeatureNoiseShort: 'शोर',
|
||||||
showcaseFeatureSchoolsShort: 'स्कूल',
|
showcaseFeatureSchoolsShort: 'स्कूल',
|
||||||
showcaseFeatureTravelShort: 'यात्रा',
|
showcaseFeatureTravelShort: 'यात्रा',
|
||||||
showcaseGoodPrimariesNearby: '{{count}}+ अच्छे प्राइमरी स्कूलों के कैचमेंट क्षेत्र में',
|
showcaseGoodPrimariesNearby: '{{count}}+ अच्छे प्राइमरी कैचमेंट क्षेत्रों में',
|
||||||
showcaseWithinRail: 'रेल से {{count}} मिनट के भीतर',
|
showcaseWithinRail: 'रेल से {{count}} मिनट के भीतर',
|
||||||
showcaseMatchingHomesLabel: 'मेल खाते घर',
|
showcaseMatchingHomesLabel: 'मेल खाते घर',
|
||||||
showcaseMatchingHomes: '{{value}} मेल खाते घर',
|
showcaseMatchingHomes: '{{value}} मेल खाते घर',
|
||||||
|
|
@ -994,92 +1018,94 @@ const hi: Translations = {
|
||||||
showcaseNearby: '{{value}} पास में',
|
showcaseNearby: '{{value}} पास में',
|
||||||
showcasePoliticalVoteShare: 'राजनीतिक वोट हिस्सेदारी',
|
showcasePoliticalVoteShare: 'राजनीतिक वोट हिस्सेदारी',
|
||||||
showcaseGe2024: '2024 आम चुनाव',
|
showcaseGe2024: '2024 आम चुनाव',
|
||||||
showcaseLotsMore: '...और भी बहुत कुछ',
|
showcaseLotsMore: '…और भी बहुत कुछ',
|
||||||
showcaseMinutes: '{{count}} मिनट',
|
showcaseMinutes: '{{count}} मिनट',
|
||||||
showcaseSendShortlist: 'शॉर्टलिस्ट भेजें',
|
showcaseSendShortlist: 'शॉर्टलिस्ट भेजें',
|
||||||
showcaseDownloadXlsx: '.xlsx डाउनलोड करें',
|
showcaseDownloadXlsx: '.xlsx डाउनलोड करें',
|
||||||
showcaseTopThree: 'शीर्ष 3',
|
showcaseTopThree: 'शीर्ष 3',
|
||||||
showcaseScoutBullet1: 'लिस्टिंग खोज आपके विकल्प घटाए, उससे पहले सड़कों पर जाकर देखें.',
|
showcaseScoutBullet1: 'उस पोस्टकोड की सड़कों पर पैदल घूमें जो अपने महंगे पड़ोसी से बेहतर है.',
|
||||||
showcaseScoutBullet2: 'आवागमन किसी असली पते से जांचें, सिर्फ बरो नाम से नहीं.',
|
showcaseScoutBullet2: 'आवागमन को किसी असली दरवाज़े से परखें, सिर्फ बरो के नाम से नहीं.',
|
||||||
showcaseScoutBullet3: 'पहले से मौजूद प्रमाण के साथ मकान देखने की तुलना करें.',
|
showcaseScoutBullet3: 'पहले से मौजूद प्रमाण के साथ मकान देखने की तुलना करें.',
|
||||||
showcaseStep1Tab: 'फ़िल्टर',
|
showcaseStep1Tab: 'फ़िल्टर',
|
||||||
showcaseStep1Title: 'अस्पष्ट जरूरतों को सटीक खोज में बदलें',
|
showcaseStep1Title: 'अस्पष्ट जरूरतों को सटीक खोज में बदलें',
|
||||||
showcaseStep1Body:
|
showcaseStep1Body:
|
||||||
'जो मायने रखता है उसे सेट करें और देखें कि हर जरूरत कितने अनुपयुक्त पोस्टकोड को आपकी खोज से बाहर रखती है.',
|
'जो मायने रखता है उसे सेट करें और ठीक-ठीक देखें कि हर शर्त कितने अनुपयुक्त पोस्टकोड को आपकी खोज से बाहर रखती है.',
|
||||||
showcaseStep1Chip1: 'शांत सड़कें',
|
|
||||||
showcaseStep1Chip2: 'शीर्ष-रेटेड प्राइमरी',
|
|
||||||
showcaseStep1Chip3: '£500,000 से कम',
|
|
||||||
showcaseStep1VennCenter: 'तीनों शर्तों को पूरा करने वाले पोस्टकोड',
|
|
||||||
showcaseStep2Tab: 'मिलान',
|
showcaseStep2Tab: 'मिलान',
|
||||||
showcaseStep2Title: 'मानचित्र को वे जगहें दिखाने दें जिन्हें आप टाइप नहीं करते',
|
showcaseStep2Title: 'देखें कि कम कीमत वाले पोस्टकोड कैसे उभरकर आते हैं',
|
||||||
showcaseStep2Body:
|
showcaseStep2Body:
|
||||||
'परिचित इलाकों के नामों से शुरू करने के बजाय अपनी जरूरतों से मेल के आधार पर इंग्लैंड देखें. लिस्टिंग पोर्टल आपकी सोच सीमित करें, उससे पहले छिपे हुए अच्छे इलाके सामने आ जाते हैं.',
|
'इंग्लैंड को उन इलाकों के नामों से नहीं, बल्कि पैसे के बदले मूल्य के आधार पर क्रम दें. कम कीमत वाले इलाके, जो £/sqm, स्कूल और आवागमन में मजबूत हैं, सबसे ऊपर आ जाते हैं.',
|
||||||
showcaseStep2Region: 'ग्रेटर लंदन',
|
showcaseStep2Region: 'ग्रेटर लंदन',
|
||||||
showcaseStep2Sources: 'Land Registry · ONS · Ofsted · DfT',
|
showcaseStep2Sources: 'Land Registry · ONS · Ofsted · DfT',
|
||||||
showcaseStep2ClustersLabel: 'मेल खाते क्लस्टर',
|
|
||||||
showcaseStep3Tab: 'जांचें',
|
showcaseStep3Tab: 'जांचें',
|
||||||
showcaseStep3Title: 'जांचें कि कोई पोस्टकोड क्यों चुना गया',
|
showcaseStep3Title: 'जांचें कि कोई पोस्टकोड क्यों चुना गया',
|
||||||
showcaseStep3Body:
|
showcaseStep3Body:
|
||||||
'किसी भी मेल खाते क्षेत्र को खोलें और वहां सप्ताहांत बिताने से पहले कीमतें, सुरक्षा, स्कूल, ब्रॉडबैंड और समझौते एक ही पैनल में जांचें.',
|
'किसी भी मेल खाते क्षेत्र को खोलें और वहां सप्ताहांत बिताने से पहले कीमतें, सुरक्षा, स्कूल, ब्रॉडबैंड और समझौते एक ही पैनल में जांचें.',
|
||||||
showcaseStep3HeaderArea: 'आपका परफेक्ट पोस्टकोड',
|
|
||||||
showcaseStep3HeaderFit: 'पड़ोस का प्रमाण',
|
|
||||||
showcaseStep3Stat1Label: 'बेची गई कीमत का रुझान',
|
|
||||||
showcaseStep3Stat2Label: 'अपराध दर',
|
showcaseStep3Stat2Label: 'अपराध दर',
|
||||||
showcaseStep3Stat2Value: 'बरो औसत से कम',
|
|
||||||
showcaseStep3Stat3Label: 'मध्य आयु',
|
|
||||||
showcaseStep3Stat4Label: 'ब्रॉडबैंड',
|
|
||||||
showcaseStep3Stat4Value: '1 Gbps उपलब्ध',
|
|
||||||
showcaseStep3Stat5Label: 'प्राइमरी स्कूल',
|
|
||||||
showcaseStep3Stat5Value: '1 मील के अंदर 3 उत्कृष्ट',
|
|
||||||
showcaseStep4Tab: 'जाकर देखें',
|
showcaseStep4Tab: 'जाकर देखें',
|
||||||
showcaseStep4Title: 'खुद जाकर परखें',
|
showcaseStep4Title: 'खुद जाकर परखें',
|
||||||
showcaseStep4Body:
|
showcaseStep4Body:
|
||||||
'तीन ठोस शुरुआती बिंदुओं को वास्तविक दुनिया में ले जाएं. सड़कें पैदल देखें, आवागमन आजमाएं और संदर्भ के साथ मकान देखने के अनुभवों की तुलना करें.',
|
'अपने शीर्ष तीन पोस्टकोड को वास्तविक दुनिया में ले जाएं. सड़कें पैदल देखें, आवागमन आजमाएं और संदर्भ के साथ मकान देखने की तुलना करें.',
|
||||||
showcaseStep4FileName: 'areas-to-scout.xlsx',
|
showcaseStep4FileName: 'areas-to-scout.xlsx',
|
||||||
showcaseStep4ExportLabel: 'Excel में निर्यात करें',
|
|
||||||
showcaseStep4ColPostcode: 'पोस्टकोड',
|
showcaseStep4ColPostcode: 'पोस्टकोड',
|
||||||
showcaseStep4ColScore: 'फिट',
|
showcaseStep4ColScore: 'फिट',
|
||||||
showcaseStep4ColCommute: 'आवागमन',
|
showcaseStep4ColCommute: 'आवागमन',
|
||||||
showcaseStep4ColPrice: 'मध्यिका बिक्री',
|
showcaseStep4ColPrice: '£/sqm',
|
||||||
showcaseStep4Conclusion: 'आप अपनी यात्रा यहां से शुरू कर सकते हैं.',
|
showcaseStep4Conclusion: 'यहीं से जाकर देखना शुरू करें.',
|
||||||
statProperties: 'ऐतिहासिक बिक्री',
|
statProperties: 'ऐतिहासिक बिक्री',
|
||||||
statFilters: 'जोड़े जा सकने वाले फ़िल्टर',
|
statFilters: 'जोड़े जा सकने वाले फ़िल्टर',
|
||||||
statEvery: 'इंग्लैंड का हर',
|
statEvery: 'इंग्लैंड का हर',
|
||||||
statPostcodeInEngland: 'पोस्टकोड',
|
statPostcodeInEngland: 'पोस्टकोड',
|
||||||
coverageNote:
|
coverageNote:
|
||||||
'इंग्लैंड का हर पोस्टकोड कवर — हर एक के लिए 200+ डेटा फ़ील्ड. स्कॉटलैंड और वेल्स रोडमैप पर हैं.',
|
'इंग्लैंड का हर पोस्टकोड कवर: हर एक के लिए 200+ डेटा फ़ील्ड. स्कॉटलैंड और वेल्स रोडमैप पर हैं.',
|
||||||
priceStrip: 'लाइफ़टाइम एक्सेस, अभी {{price}} — टियर भरने पर क़ीमत बढ़ती है.',
|
priceStrip:
|
||||||
priceStripSpots: 'इस क़ीमत पर सिर्फ़ {{count}} जगह बची है.',
|
'आजीवन पहुँच के लिए एक बार भुगतान करें: अभी {{price}}, हर टियर भरने पर कीमत बढ़ती है.',
|
||||||
priceStripSpotsPlural: 'इस क़ीमत पर सिर्फ़ {{count}} जगहें बची हैं.',
|
priceStripSpots: 'इस कीमत पर {{count}} जगह बची है.',
|
||||||
priceStripCta: 'क़ीमतें देखें',
|
priceStripSpotsPlural: 'इस कीमत पर {{count}} जगहें बची हैं.',
|
||||||
ourPhilosophy: 'जो मायने रखता है उससे शुरू करें, फिर सही पोस्टकोड खोजें',
|
priceStripCta: 'कीमतें देखें',
|
||||||
|
ourPhilosophy: 'प्रतिष्ठा कीमत में जुड़ चुकी है. मूल्य अभी नहीं.',
|
||||||
philosophyP1:
|
philosophyP1:
|
||||||
'अधिकांश संपत्ति साइटें पूछती हैं कि आप कहां रहना चाहते हैं. लंदन में यह बहुत मुश्किल है, लेकिन यही समस्या पूरे इंग्लैंड में आती है: खरीदार उन कुछ जगहों में से चुनते हैं जिन्हें वे जानते हैं, फिर आवागमन साधन, Ofsted, पुलिस डेटा, Street View, ब्रॉडबैंड जांच और बेचे गए दामों को अलग-अलग टैब में मिलाते हैं.',
|
'किसी पोस्टकोड की कीमत का एक हिस्सा उसकी ईंटों, उसके कैचमेंट और उसके आवागमन का होता है. बाकी सिर्फ नाम है. खरीदार उन्हीं पोस्टकोड की बोली बढ़ाते हैं जिनके बारे में उन्होंने सुना है, इसलिए ठीक पीछे की सड़क, जो कीमत बदलने वाली हर कसौटी पर एक जैसी है, चुपचाप सस्ती रह जाती है. इस अंतर को हाथ से खोजना यानी दर्जनभर ब्राउज़र टैब: बेची गई कीमतें, Ofsted, अपराध, शोर, फर्श क्षेत्रफल.',
|
||||||
philosophyP2:
|
philosophyP2:
|
||||||
'Perfect Postcode खोज को उलट देता है. मानचित्र को बताएं कि क्या मायने रखता है और यह वे पोस्टकोड दिखाता है जो योग्य हैं, साथ में प्रमाण भी कि वे देखने लायक क्यों हैं. पहले डेटा, फिर माहौल खुद परखें.',
|
'Perfect Postcode यह मिलान-जांच आपके लिए करता है. मानचित्र को अपना बजट और अपनी जरूरी शर्तें बताएं; यह इंग्लैंड के हर पोस्टकोड को कीमत बदलने वाली चीजों पर तौलता है और कम कीमत वालों को सबसे ऊपर रखता है. फिर जाकर खुद घूम आएं.',
|
||||||
streetTitle: 'जगहें सड़क-दर-सड़क बदलती हैं',
|
streetTitle: 'अंतर सड़क-दर-सड़क होता है',
|
||||||
streetIntro:
|
streetIntro:
|
||||||
'बड़े क्षेत्र नाम वे विवरण छिपा देते हैं जो मायने रखते हैं: स्टेशन किस तरफ है, सड़क का शोर, स्कूल मिश्रण, सटीक आवागमन और समान घर वास्तव में किस कीमत पर बिके.',
|
'बड़े क्षेत्र नाम छिपा देते हैं कि सस्ते सौदे कहां हैं: स्टेशन का सस्ता हिस्सा, ज्यादा शांत सड़क, वही स्कूल कैचमेंट, और लगभग एक जैसे घर प्रति वर्ग मीटर असल में किस कीमत पर बिके.',
|
||||||
streetCard1Title: 'वे क्षेत्र खोजें जो आपसे छूट सकते थे',
|
streetCard1Title: 'सस्ता जुड़वाँ खोजें',
|
||||||
streetCard1Body:
|
streetCard1Body:
|
||||||
'परिचित नामों, दोस्तों की सिफारिशों या “उभरते इलाके” की चर्चा पर निर्भर रहने के बजाय अपनी जरूरतों से मेल खाते पोस्टकोड सामने लाएं.',
|
'हर मशहूर पोस्टकोड का एक ज्यादा शांत पड़ोसी होता है जिसका कैचमेंट, स्टेशन और घरों का दौर वही होता है: बिना प्रीमियम के, और बिना “उभरते इलाके” वाली बढ़ी कीमत के. हम दोनों को आमने-सामने रखते हैं ताकि अंतर नजरअंदाज करना नामुमकिन हो जाए.',
|
||||||
streetCard2Title: 'मकान देखने से पहले समझौते समझें',
|
streetCard2Title: 'देखें कि आपका पैसा असल में क्या खरीदता है',
|
||||||
streetCard2Body:
|
streetCard2Body:
|
||||||
'सप्ताहांत मकान देखने में बिताने से पहले कीमत, जगह, आवागमन, सुरक्षा, स्कूल, ब्रॉडबैंड, शोर और ऊर्जा रेटिंग की तुलना करें.',
|
'फर्श क्षेत्रफल, बेची गई कीमतें, आवागमन, अपराध, स्कूल, ब्रॉडबैंड, शोर और ऊर्जा रेटिंग एक ही स्क्रीन पर: आठ टैब और एक स्प्रेडशीट नहीं. शनिवार बिताने से पहले तय करें कि कौन सी जगह शनिवार के लायक है.',
|
||||||
othersVs: 'अन्य बनाम',
|
othersVs: 'अन्य बनाम',
|
||||||
checkMyPostcode: 'लिस्टिंग पोर्टल',
|
checkMyPostcode: 'लिस्टिंग पोर्टल',
|
||||||
areaGuides: 'पोस्टकोड रिपोर्ट',
|
areaGuides: 'पोस्टकोड रिपोर्ट',
|
||||||
compSearchWithout: 'नाम जाने बिना क्षेत्र खोजें',
|
compSearchWithout: 'इस आधार पर क्रम कि आपको क्या मिलता है, न कि किसने उसका नाम सुना है',
|
||||||
compSearchWithoutSub: '(पहले जरूरतें, बाद में स्थान)',
|
compSearchWithoutSub: '(आपकी जरूरतों के लिए सस्ता जुड़वाँ, नाम नहीं)',
|
||||||
compAreaData: 'पोस्टकोड-स्तर पड़ोस प्रमाण',
|
compAreaData: 'पोस्टकोड-स्तर पड़ोस प्रमाण',
|
||||||
compAreaDataSub: '(अपराध, स्कूल, शोर, ब्रॉडबैंड, सुविधाएं)',
|
compAreaDataSub: '(अपराध, स्कूल, शोर, ब्रॉडबैंड, सुविधाएं)',
|
||||||
compPropertyData: 'संपत्ति-स्तर इतिहास',
|
compPropertyData: 'संपत्ति-स्तर इतिहास',
|
||||||
compPropertyDataSub: '(बेची कीमतें, EPC, फर्श क्षेत्रफल, अनुमानित मूल्य)',
|
compPropertyDataSub: '(बेची कीमतें, EPC, फर्श क्षेत्रफल, अनुमानित मूल्य)',
|
||||||
compFilters: '40+ फ़िल्टर साथ काम करते हुए',
|
compFilters: '40+ फ़िल्टर साथ मिलकर काम करते हुए',
|
||||||
compFiltersSub: '(एक समय में केवल एक पोस्टकोड या एक लिस्टिंग नहीं)',
|
compFiltersSub: '(एक समय में सिर्फ एक पोस्टकोड या एक लिस्टिंग नहीं)',
|
||||||
ctaTitle: 'कहां खरीदना है, इसका अनुमान लगाना बंद करें.',
|
compListings: 'लाइव लिस्टिंग, तस्वीरें और मकान देखना',
|
||||||
|
compListingsSub: '(किसी खास घर को खरीदने की रोज़मर्रा की प्रक्रिया)',
|
||||||
|
twinBadge: 'असली उदाहरण',
|
||||||
|
twinTitle: 'वही जिंदगी, एक पोस्टकोड सस्ता',
|
||||||
|
twinIntro:
|
||||||
|
'North London के दो पड़ोसी इलाके, 1.3 किमी की दूरी पर: फ्लैट जिनके प्राइमरी-स्कूल कैचमेंट लगभग एक जैसे हैं और आवागमन भी वही ~30 मिनट का, फिर भी प्रति वर्ग मीटर कीमत में काफी अंतर.',
|
||||||
|
twinPriceyLabel: 'वह नाम जिसे हर कोई जानता है',
|
||||||
|
twinValueLabel: 'इसका ज्यादा शांत पड़ोसी',
|
||||||
|
twinPerSqm: '{{value}}/sqm',
|
||||||
|
twinSameSchool: 'दोनों Outstanding-रेटेड प्राइमरी कैचमेंट में',
|
||||||
|
twinSameCommute: 'दोनों ट्रांज़िट से सेंट्रल London तक ~30 मिनट',
|
||||||
|
twinDelta: 'प्रति वर्ग मीटर {{percent}} कम',
|
||||||
|
twinFootnote:
|
||||||
|
'हमारे डेटा से एक असली उदाहरण: 2021 से बिके फ्लैटों का मध्यिका £/sqm. अपना खुद का खोजने के लिए लाइव मानचित्र देखें.',
|
||||||
|
twinCta: 'मेरे पास ऐसा ही एक रत्न खोजें',
|
||||||
|
ctaTitle: 'किसी नाम के लिए ज्यादा कीमत चुकाना बंद करें.',
|
||||||
ctaDescription:
|
ctaDescription:
|
||||||
'उन पोस्टकोड की शॉर्टलिस्ट बनाएं जो आपकी वास्तविक जिंदगी से मेल खाते हैं, फिर उन्हें खुद जांचें.',
|
'लाइव मानचित्र पर अपनी शॉर्टलिस्ट मुफ़्त में बनाएं. जब आप आश्वस्त हो जाएं, तो हर फ़िल्टर को जीवनभर के लिए अनलॉक करें: एक बार भुगतान करें, कोई सदस्यता नहीं.',
|
||||||
|
guaranteeNote: 'एक बार भुगतान करें. कोई सदस्यता नहीं, कभी नहीं. 30 दिन की मनी-बैक गारंटी.',
|
||||||
},
|
},
|
||||||
|
|
||||||
// ── Footer ─────────────────────────────────────────
|
// ── Footer ─────────────────────────────────────────
|
||||||
|
|
@ -1105,13 +1131,16 @@ const hi: Translations = {
|
||||||
},
|
},
|
||||||
|
|
||||||
pricingPage: {
|
pricingPage: {
|
||||||
|
cachedNotice: 'हम लाइव मूल्य ताज़ा नहीं कर सके, इसलिए ये आँकड़े पुराने हो सकते हैं।',
|
||||||
|
scrollPrev: 'पिछली योजनाएँ दिखाएँ',
|
||||||
|
scrollNext: 'और योजनाएँ दिखाएँ',
|
||||||
title: 'बेहतर खोज क्षेत्र के साथ खरीदें',
|
title: 'बेहतर खोज क्षेत्र के साथ खरीदें',
|
||||||
subtitle:
|
subtitle:
|
||||||
'उस मानचित्र की आजीवन पहुँच जो मकान देखने की बुकिंग से पहले यह तय करने में मदद करता है कि कहां देखना है.',
|
'उस मानचित्र की आजीवन पहुँच जो मकान देखने की बुकिंग से पहले यह तय करने में मदद करता है कि कहां देखना है.',
|
||||||
costContext:
|
costContext:
|
||||||
'खरीदार अक्सर शामें लिस्टिंग, आवागमन जांच, स्कूल रिपोर्ट, अपराध मानचित्र, Street View और बेचे गए दामों को जोड़ने में बिताते हैं. लंदन में यह लगातार होता है, लेकिन यही शोध समस्या पूरे इंग्लैंड में दिखती है. Perfect Postcode आपके सप्ताहांत, फीस और ध्यान लगाने से पहले क्षेत्र शोध को एक मानचित्र पर रखता है.',
|
'खरीदार अक्सर शामें लिस्टिंग, आवागमन जांच, स्कूल रिपोर्ट, अपराध मानचित्र, Street View और बेचे गए दामों को जोड़ने में बिताते हैं. लंदन में यह लगातार होता है, लेकिन यही शोध समस्या पूरे इंग्लैंड में दिखती है. Perfect Postcode आपके सप्ताहांत, फीस और ध्यान लगाने से पहले क्षेत्र शोध को एक मानचित्र पर रखता है.',
|
||||||
lessThanSurvey:
|
lessThanSurvey:
|
||||||
'एक मकान सर्वेक्षण की क़ीमत के दसवें हिस्से से भी कम — और कहीं बड़े फ़ैसले में मददगार.',
|
'एक मकान सर्वेक्षण की क़ीमत के दसवें हिस्से से भी कम, और कहीं बड़े फ़ैसले में मददगार.',
|
||||||
currentTier: 'मौजूदा स्तर',
|
currentTier: 'मौजूदा स्तर',
|
||||||
firstNUsers: 'पहले {{count}} उपयोगकर्ता',
|
firstNUsers: 'पहले {{count}} उपयोगकर्ता',
|
||||||
everyoneAfter: 'उसके बाद सभी',
|
everyoneAfter: 'उसके बाद सभी',
|
||||||
|
|
@ -1151,16 +1180,16 @@ const hi: Translations = {
|
||||||
videos: 'वीडियो',
|
videos: 'वीडियो',
|
||||||
videosTitle: 'सोशल मीडिया वीडियो',
|
videosTitle: 'सोशल मीडिया वीडियो',
|
||||||
videosIntro:
|
videosIntro:
|
||||||
'हमारे सोशल चैनलों की छोटी क्लिप्स — हर एक एक खोज को क्रिया में दिखाती है, शांत गलियों से लेकर स्कूल कैचमेंट और सफर के समय तक.',
|
'हमारे सोशल चैनलों की छोटी क्लिप्स: हर एक एक खोज को क्रिया में दिखाती है, शांत गलियों से लेकर स्कूल कैचमेंट और सफर के समय तक.',
|
||||||
video01Title: 'सस्ता जुड़वाँ खोजें',
|
video01Title: 'सस्ता जुड़वाँ खोजें',
|
||||||
video01Desc:
|
video01Desc:
|
||||||
'अपनी पूरी घर की ज़रूरत एक सरल वाक्य में लिखें और देखें कि इंग्लैंड का हर मेल खाता पोस्टकोड मूल्य के अनुसार छँटता है, उस सस्ते जुड़वाँ को सामने लाता है जिसकी किसी ने बोली नहीं बढ़ाई.',
|
'अपनी पूरी घर की ज़रूरत एक सरल वाक्य में लिखें और देखें कि इंग्लैंड का हर मेल खाता पोस्टकोड मूल्य के अनुसार छँटता है, उस सस्ते जुड़वाँ को सामने लाता है जिसकी किसी ने बोली नहीं बढ़ाई.',
|
||||||
video02Title: '20 मिनट का आवागमन नक्शा',
|
video02Title: '20 मिनट का आवागमन नक्शा',
|
||||||
video02Desc:
|
video02Desc:
|
||||||
'लंदन को केंद्र तक आवागमन के अनुसार रंगें, 20 मिनट की सवारी तक सीमित करें, और देखें कि एक जैसे सफर कैसे बँट जाते हैं — मशहूर नामों और उन शांत पोस्टकोडों में जिनकी किसी ने बोली नहीं बढ़ाई.',
|
'लंदन को केंद्र तक आवागमन के अनुसार रंगें, 20 मिनट की सवारी तक सीमित करें, और देखें कि एक जैसे सफर कैसे बँट जाते हैं: मशहूर नामों और उन शांत पोस्टकोडों में जिनकी किसी ने बोली नहीं बढ़ाई.',
|
||||||
video03Title: 'पोस्टकोड की सबूत-फ़ाइल',
|
video03Title: 'पोस्टकोड की सबूत-फ़ाइल',
|
||||||
video03Desc:
|
video03Desc:
|
||||||
'किसी भी पोस्टकोड पर टैप करें और एक पैनल खुलता है जिसमें उसके बिक्री मूल्य, स्कूल कैचमेंट, अपराध और स्ट्रीट व्यू होते हैं — ताकि आप जान सकें कि आप मूल्य के लिए चुका रहे हैं या सिर्फ़ एक नाम के लिए.',
|
'किसी भी पोस्टकोड पर टैप करें और एक पैनल खुलता है जिसमें उसके बिक्री मूल्य, स्कूल कैचमेंट, अपराध और स्ट्रीट व्यू होते हैं, ताकि आप जान सकें कि आप मूल्य के लिए चुका रहे हैं या सिर्फ़ एक नाम के लिए.',
|
||||||
video04Title: 'अनदेखी की गई शांत गली',
|
video04Title: 'अनदेखी की गई शांत गली',
|
||||||
video04Desc:
|
video04Desc:
|
||||||
'मशहूर पोस्टकोड अपनी प्रतिष्ठा को कीमत में जोड़ लेते हैं, पर विज्ञापन की तस्वीर शोर पर खामोश रहती है. डेसिबल से छानकर ठीक बगल की सचमुच शांत गली खोजें जिसकी किसी ने बोली नहीं बढ़ाई.',
|
'मशहूर पोस्टकोड अपनी प्रतिष्ठा को कीमत में जोड़ लेते हैं, पर विज्ञापन की तस्वीर शोर पर खामोश रहती है. डेसिबल से छानकर ठीक बगल की सचमुच शांत गली खोजें जिसकी किसी ने बोली नहीं बढ़ाई.',
|
||||||
|
|
@ -1169,7 +1198,7 @@ const hi: Translations = {
|
||||||
'लीड्स का एक परिवार अच्छे प्राइमरी, कम अपराध और £350,000 से कम बजट की खोज करता है, और उन चुपचाप सस्ती गलियों को सामने लाता है जो ठीक वही कैचमेंट साझा करती हैं.',
|
'लीड्स का एक परिवार अच्छे प्राइमरी, कम अपराध और £350,000 से कम बजट की खोज करता है, और उन चुपचाप सस्ती गलियों को सामने लाता है जो ठीक वही कैचमेंट साझा करती हैं.',
|
||||||
video06Title: 'वेट्रोज़ असर, कीमत में शामिल',
|
video06Title: 'वेट्रोज़ असर, कीमत में शामिल',
|
||||||
video06Desc:
|
video06Desc:
|
||||||
'किसी वेट्रोज़, ट्यूब स्टेशन और पार्क से पैदल दूरी एक कीमत-में-शामिल प्रीमियम है — पास के वे पोस्टकोड खोजें जिनमें वही सुविधाएँ प्रति वर्ग मीटर कम दाम पर मिलती हैं.',
|
'किसी वेट्रोज़, ट्यूब स्टेशन और पार्क से पैदल दूरी एक कीमत-में-शामिल प्रीमियम है। पास के वे पोस्टकोड खोजें जिनमें वही सुविधाएँ प्रति वर्ग मीटर कम दाम पर मिलती हैं.',
|
||||||
video07Title: 'किराएदारों के लिए मूल्य नक्शा',
|
video07Title: 'किराएदारों के लिए मूल्य नक्शा',
|
||||||
video07Desc:
|
video07Desc:
|
||||||
'मशहूर पोस्टकोड किराये पर भी महँगे पड़ते हैं. अपना किराया, आवागमन और एक शांत गली तय करें, और देखें कि लंदन के कौन-से पोस्टकोड वाकई बजट में बैठते हैं.',
|
'मशहूर पोस्टकोड किराये पर भी महँगे पड़ते हैं. अपना किराया, आवागमन और एक शांत गली तय करें, और देखें कि लंदन के कौन-से पोस्टकोड वाकई बजट में बैठते हैं.',
|
||||||
|
|
@ -1356,7 +1385,7 @@ const hi: Translations = {
|
||||||
'आजीवन पहुँच का मतलब है कि एक भुगतान आपके खाते को सेवा चलने तक सशुल्क Perfect Postcode मानचित्र की लगातार पहुँच देता है. यह मासिक या वार्षिक सदस्यता नहीं है, और सामान्य डेटा अपडेट शामिल हैं. आप इसे इस खोज में उपयोग कर सकते हैं, बाद में लौट सकते हैं और फिर स्थान बदलने पर भी पहुँच रहेगी.',
|
'आजीवन पहुँच का मतलब है कि एक भुगतान आपके खाते को सेवा चलने तक सशुल्क Perfect Postcode मानचित्र की लगातार पहुँच देता है. यह मासिक या वार्षिक सदस्यता नहीं है, और सामान्य डेटा अपडेट शामिल हैं. आप इसे इस खोज में उपयोग कर सकते हैं, बाद में लौट सकते हैं और फिर स्थान बदलने पर भी पहुँच रहेगी.',
|
||||||
faqPricing3Q: 'मुफ्त स्तर पर मैं क्या उपयोग कर सकता हूं?',
|
faqPricing3Q: 'मुफ्त स्तर पर मैं क्या उपयोग कर सकता हूं?',
|
||||||
faqPricing3A:
|
faqPricing3A:
|
||||||
'मुफ्त उपयोगकर्ताओं को पूरे इंग्लैंड में पूरा Perfect Postcode मानचित्र मिलता है — हर पोस्टकोड और हर सुविधा — और वे एक बार में 3 फ़िल्टर तक लगा सकते हैं. आजीवन पहुँच यह सीमा हटा देती है, ताकि आप असीमित फ़िल्टर लगा सकें.',
|
'मुफ्त उपयोगकर्ताओं को पूरे इंग्लैंड में पूरा Perfect Postcode मानचित्र मिलता है (हर पोस्टकोड और हर सुविधा) और वे एक बार में 3 फ़िल्टर तक लगा सकते हैं. आजीवन पहुँच यह सीमा हटा देती है, ताकि आप असीमित फ़िल्टर लगा सकें.',
|
||||||
faqTips1Q: 'मानचित्र पर फ़िल्टर पूर्वावलोकन कैसे करें?',
|
faqTips1Q: 'मानचित्र पर फ़िल्टर पूर्वावलोकन कैसे करें?',
|
||||||
faqTips1A:
|
faqTips1A:
|
||||||
'किसी फ़िल्टर या सुविधा के पास रंगें पर क्लिक करें ताकि मानचित्र उसी मद से रंग जाए. आपके सक्रिय फ़िल्टर वैसे ही रहते हैं, इसलिए आप कीमत, आवागमन समय, स्कूल, अपराध या शोर जैसी एक चीज सूची बदले बिना तुलना कर सकते हैं.',
|
'किसी फ़िल्टर या सुविधा के पास रंगें पर क्लिक करें ताकि मानचित्र उसी मद से रंग जाए. आपके सक्रिय फ़िल्टर वैसे ही रहते हैं, इसलिए आप कीमत, आवागमन समय, स्कूल, अपराध या शोर जैसी एक चीज सूची बदले बिना तुलना कर सकते हैं.',
|
||||||
|
|
@ -1367,20 +1396,20 @@ const hi: Translations = {
|
||||||
faqTips3A:
|
faqTips3A:
|
||||||
'जब कोई सुविधा मानचित्र को रंग रही हो, तो मानचित्र संकेतक में रंग स्केल रीसेट करें उपयोग करें ताकि अभी दिख रहे परिणामों के रंग ताजा हों. मानचित्र खिसकाने, ज़ूम करने या फ़िल्टर बदलने के बाद यह उपयोगी है.',
|
'जब कोई सुविधा मानचित्र को रंग रही हो, तो मानचित्र संकेतक में रंग स्केल रीसेट करें उपयोग करें ताकि अभी दिख रहे परिणामों के रंग ताजा हों. मानचित्र खिसकाने, ज़ूम करने या फ़िल्टर बदलने के बाद यह उपयोगी है.',
|
||||||
|
|
||||||
// FAQ items — Behind The Data
|
// FAQ items: Behind The Data
|
||||||
faqBehindData1Q: 'कभी-कभी एयरपोर्ट आसपास की सड़कों से शांत क्यों दिखता है?',
|
faqBehindData1Q: 'कभी-कभी एयरपोर्ट आसपास की सड़कों से शांत क्यों दिखता है?',
|
||||||
faqBehindData1A:
|
faqBehindData1A:
|
||||||
'किसी पोस्टकोड के लिए दिखाया गया शोर स्तर Defra के तीन स्रोतों — सड़क, रेल और विमान — में से सबसे ऊँचा होता है, जो ज़मीन से 4 मीटर ऊपर 24-घंटे के भारित औसत (Lden) के रूप में मॉडल किया जाता है. व्यस्त आवासीय सड़क पर सड़क शोर हावी रहता है, आमतौर पर 65–75 dB. एयरपोर्ट की सीमा के भीतर कोई बड़ी सार्वजनिक सड़कें नहीं होतीं, इसलिए सड़क घटक गिर जाता है और केवल विमान औसत बचता है. उदाहरण के लिए, London City Airport में कर्फ्यू है और सीमित उड़ानें हैं, इसलिए इसका 24-घंटे विमान Lden मध्यम रहता है (रनवे पर लगभग 60–66 dB) — और एयरपोर्ट का भीतरी हिस्सा उसके आसपास की A-सड़कों से शांत दिखता है. यही प्रभाव Heathrow में भी दिखाई देता है. यह आवासीय रिसेप्टर ऊँचाई पर परिवहन शोर मापने का वास्तविक परिणाम है, बग नहीं.',
|
'किसी पोस्टकोड के लिए दिखाया गया शोर स्तर Defra के तीन स्रोतों (सड़क, रेल और विमान) में से सबसे ऊँचा होता है, जो ज़मीन से 4 मीटर ऊपर 24-घंटे के भारित औसत (Lden) के रूप में मॉडल किया जाता है. व्यस्त आवासीय सड़क पर सड़क शोर हावी रहता है, आमतौर पर 65–75 dB. एयरपोर्ट की सीमा के भीतर कोई बड़ी सार्वजनिक सड़कें नहीं होतीं, इसलिए सड़क घटक गिर जाता है और केवल विमान औसत बचता है. उदाहरण के लिए, London City Airport में कर्फ्यू है और सीमित उड़ानें हैं, इसलिए इसका 24-घंटे विमान Lden मध्यम रहता है (रनवे पर लगभग 60–66 dB), और एयरपोर्ट का भीतरी हिस्सा उसके आसपास की A-सड़कों से शांत दिखता है. यही प्रभाव Heathrow में भी दिखाई देता है. यह आवासीय रिसेप्टर ऊँचाई पर परिवहन शोर मापने का वास्तविक परिणाम है, बग नहीं.',
|
||||||
faqBehindData2Q: 'एयरपोर्ट, हाईवे या पार्क एक बड़े आकार के रूप में क्यों दिखता है?',
|
faqBehindData2Q: 'एयरपोर्ट, हाईवे या पार्क एक बड़े आकार के रूप में क्यों दिखता है?',
|
||||||
faqBehindData2A:
|
faqBehindData2A:
|
||||||
'यूके में पोस्टकोड की आधिकारिक सीमाएँ नहीं होतीं — Royal Mail पोस्टकोड को डिलीवरी पतों की सूची के रूप में परिभाषित करता है, क्षेत्र के रूप में नहीं. Perfect Postcode प्रत्येक पते को आसपास की भूमि का हिस्सा देकर बहुभुज बनाता है. बिना पतों वाली जगहें (रनवे, मोटरवे कैरिजवे, पार्क, जलाशय) निकटतम आवासीय पोस्टकोड में शामिल हो जाती हैं. इसलिए एयरपोर्ट या खुला क्षेत्र अक्सर कई छोटे आकारों के बजाय एक बड़े बहुभुज की तरह दिखता है, और उसका मान सीमा के भीतर मौजूद कुछ पोस्टकोड से आता है.',
|
'यूके में पोस्टकोड की आधिकारिक सीमाएँ नहीं होतीं: Royal Mail पोस्टकोड को डिलीवरी पतों की सूची के रूप में परिभाषित करता है, क्षेत्र के रूप में नहीं. Perfect Postcode प्रत्येक पते को आसपास की भूमि का हिस्सा देकर बहुभुज बनाता है. बिना पतों वाली जगहें (रनवे, मोटरवे कैरिजवे, पार्क, जलाशय) निकटतम आवासीय पोस्टकोड में शामिल हो जाती हैं. इसलिए एयरपोर्ट या खुला क्षेत्र अक्सर कई छोटे आकारों के बजाय एक बड़े बहुभुज की तरह दिखता है, और उसका मान सीमा के भीतर मौजूद कुछ पोस्टकोड से आता है.',
|
||||||
faqBehindData3Q: 'पास के पोस्टकोड में अपराध संख्या समान क्यों होती है?',
|
faqBehindData3Q: 'पास के पोस्टकोड में अपराध संख्या समान क्यों होती है?',
|
||||||
faqBehindData3A:
|
faqBehindData3A:
|
||||||
'पुलिस द्वारा दर्ज सड़क-स्तरीय अपराध डेटा LSOA स्तर पर प्रकाशित होता है — लगभग 1,500 निवासियों वाले छोटे पड़ोस क्षेत्र. एक ही LSOA के सभी पोस्टकोड को समान वार्षिक संख्याएँ मिलती हैं, इसलिए एक शांत आवासीय सड़क और एक ब्लॉक दूर मुख्य सड़क समान आँकड़े दिखा सकती हैं अगर वे सीमा के एक ही ओर हों. अस्पतालों, विश्वविद्यालय परिसरों या औद्योगिक क्षेत्रों को कवर करने वाले पोस्टकोड में प्रति-व्यक्ति दर असामान्य रूप से ऊँची लग सकती है, क्योंकि वहाँ घटनाएँ सामान्य रूप से दर्ज होती हैं पर कागज़ पर निवासी कम होते हैं.',
|
'पुलिस द्वारा दर्ज सड़क-स्तरीय अपराध डेटा LSOA स्तर पर प्रकाशित होता है: लगभग 1,500 निवासियों वाले छोटे पड़ोस क्षेत्र. एक ही LSOA के सभी पोस्टकोड को समान वार्षिक संख्याएँ मिलती हैं, इसलिए एक शांत आवासीय सड़क और एक ब्लॉक दूर मुख्य सड़क समान आँकड़े दिखा सकती हैं अगर वे सीमा के एक ही ओर हों. अस्पतालों, विश्वविद्यालय परिसरों या औद्योगिक क्षेत्रों को कवर करने वाले पोस्टकोड में प्रति-व्यक्ति दर असामान्य रूप से ऊँची लग सकती है, क्योंकि वहाँ घटनाएँ सामान्य रूप से दर्ज होती हैं पर कागज़ पर निवासी कम होते हैं.',
|
||||||
faqBehindData4Q:
|
faqBehindData4Q:
|
||||||
'"स्कूल कैचमेंट क्षेत्र" की संख्या का क्या मतलब है — क्या मेरा बच्चा उन स्कूलों में जा सकता है?',
|
'"स्कूल कैचमेंट क्षेत्र" की संख्या का क्या मतलब है? क्या मेरा बच्चा उन स्कूलों में जा सकता है?',
|
||||||
faqBehindData4A:
|
faqBehindData4A:
|
||||||
'हर संख्या उन अच्छी या उत्कृष्ट रेटिंग वाले सरकारी स्कूलों की गिनती है जिनका मॉडल किया गया ऐतिहासिक कैचमेंट क्षेत्र इस पोस्टकोड को कवर करता है. हम अनुकरण करते हैं कि इंग्लैंड के दूरी-आधारित दाखिले सीटें कैसे बाँटते हैं: बच्चे (जनगणना 2021) दूरी और Ofsted रेटिंग को तौलते हुए पास के स्कूलों में आवेदन करते हैं, और ज़्यादा माँग वाला स्कूल भरने तक सबसे नज़दीकी आवेदकों को लेता है — उसका कैचमेंट दायरा आखिरी दाखिल बच्चे की दूरी है, वही "आखिरी दाखिला दूरी" जो परिषदें प्रकाशित करती हैं. मॉडल ऐसी सैकड़ों प्रकाशित दूरियों पर कैलिब्रेट किया गया है. यह अनुमान है कि कहाँ सीट मिलना संभव है; यह आधिकारिक दाखिला क्षेत्र नहीं है. धार्मिक या चयनात्मक दाखिले, भाई-बहन प्राथमिकता और सीमाओं में वार्षिक बदलाव मॉडल नहीं किए जाते, इसलिए निर्णय से पहले कैचमेंट और दाखिला नियमों की पुष्टि हमेशा स्कूल या स्थानीय प्राधिकरण से करें.',
|
'हर संख्या उन अच्छी या उत्कृष्ट रेटिंग वाले सरकारी स्कूलों की गिनती है जिनका मॉडल किया गया ऐतिहासिक कैचमेंट क्षेत्र इस पोस्टकोड को कवर करता है. हम अनुकरण करते हैं कि इंग्लैंड के दूरी-आधारित दाखिले सीटें कैसे बाँटते हैं: बच्चे (जनगणना 2021) दूरी और Ofsted रेटिंग को तौलते हुए पास के स्कूलों में आवेदन करते हैं, और ज़्यादा माँग वाला स्कूल भरने तक सबसे नज़दीकी आवेदकों को लेता है: उसका कैचमेंट दायरा आखिरी दाखिल बच्चे की दूरी है, वही "आखिरी दाखिला दूरी" जो परिषदें प्रकाशित करती हैं. मॉडल ऐसी सैकड़ों प्रकाशित दूरियों पर कैलिब्रेट किया गया है. यह अनुमान है कि कहाँ सीट मिलना संभव है; यह आधिकारिक दाखिला क्षेत्र नहीं है. धार्मिक या चयनात्मक दाखिले, भाई-बहन प्राथमिकता और सीमाओं में वार्षिक बदलाव मॉडल नहीं किए जाते, इसलिए निर्णय से पहले कैचमेंट और दाखिला नियमों की पुष्टि हमेशा स्कूल या स्थानीय प्राधिकरण से करें.',
|
||||||
faqBehindData5Q: 'जब हर घर में फ़ाइबर नहीं है, तो पोस्टकोड "Gigabit" क्यों दिखाता है?',
|
faqBehindData5Q: 'जब हर घर में फ़ाइबर नहीं है, तो पोस्टकोड "Gigabit" क्यों दिखाता है?',
|
||||||
faqBehindData5A:
|
faqBehindData5A:
|
||||||
'Ofcom Connected Nations का ब्रॉडबैंड कवरेज प्रति पोस्टकोड इस प्रतिशत के रूप में दिया जाता है कि कितने परिसर हर गति स्तर पा सकते हैं. हम किसी भी उपलब्धता वाला सर्वोच्च स्तर दिखाते हैं, इसलिए जिस पोस्टकोड में सिर्फ एक घर Gigabit पा सकता है वह "Gigabit उपलब्ध" दिखाता है. "क्या इस सड़क पर कहीं भी फुल-फ़ाइबर है?" के लिए यह सही उत्तर है, पर इससे यह गारंटी नहीं मिलती कि ब्लॉक के हर फ्लैट में आज सेवा लगवाई जा सकती है. अनुबंध करने से पहले अपने सटीक पते के लिए हमेशा प्रदाताओं से जाँच करें.',
|
'Ofcom Connected Nations का ब्रॉडबैंड कवरेज प्रति पोस्टकोड इस प्रतिशत के रूप में दिया जाता है कि कितने परिसर हर गति स्तर पा सकते हैं. हम किसी भी उपलब्धता वाला सर्वोच्च स्तर दिखाते हैं, इसलिए जिस पोस्टकोड में सिर्फ एक घर Gigabit पा सकता है वह "Gigabit उपलब्ध" दिखाता है. "क्या इस सड़क पर कहीं भी फुल-फ़ाइबर है?" के लिए यह सही उत्तर है, पर इससे यह गारंटी नहीं मिलती कि ब्लॉक के हर फ्लैट में आज सेवा लगवाई जा सकती है. अनुबंध करने से पहले अपने सटीक पते के लिए हमेशा प्रदाताओं से जाँच करें.',
|
||||||
|
|
@ -1445,6 +1474,7 @@ const hi: Translations = {
|
||||||
},
|
},
|
||||||
|
|
||||||
invitePage: {
|
invitePage: {
|
||||||
|
couldNotValidateTitle: 'निमंत्रण सत्यापित नहीं हो सका',
|
||||||
youreInvited: 'आप आमंत्रित हैं!',
|
youreInvited: 'आप आमंत्रित हैं!',
|
||||||
specialOffer: 'विशेष ऑफर!',
|
specialOffer: 'विशेष ऑफर!',
|
||||||
invitedByFree: '{{name}} ने आपको मुफ्त आजीवन पहुँच लेने के लिए आमंत्रित किया है.',
|
invitedByFree: '{{name}} ने आपको मुफ्त आजीवन पहुँच लेने के लिए आमंत्रित किया है.',
|
||||||
|
|
@ -1505,17 +1535,17 @@ const hi: Translations = {
|
||||||
treesOutsideWoodlands: {
|
treesOutsideWoodlands: {
|
||||||
label: 'पेड़ और वुडलैंड',
|
label: 'पेड़ और वुडलैंड',
|
||||||
detail:
|
detail:
|
||||||
'Forest Research Trees Outside Woodland (TOW) v1 कैनोपी पॉलीगॉन — अकेले पेड़ और पेड़ों के समूह — National Forest Inventory (NFI) वुडलैंड ब्लॉक्स (≥0.5 हेक्टेयर) के साथ जोड़े गए हैं जिन्हें TOW जानबूझकर बाहर रखता है. साथ में ये सड़क के पेड़ और असली जंगल दोनों को कवर करते हैं. पॉलीगॉन की अपारदर्शिता कैनोपी क्षेत्र के अनुसार बढ़ती है.',
|
'Forest Research Trees Outside Woodland (TOW) v1 कैनोपी पॉलीगॉन (अकेले पेड़ और पेड़ों के समूह) National Forest Inventory (NFI) वुडलैंड ब्लॉक्स (≥0.5 हेक्टेयर) के साथ जोड़े गए हैं जिन्हें TOW जानबूझकर बाहर रखता है. साथ में ये सड़क के पेड़ और असली जंगल दोनों को कवर करते हैं. पॉलीगॉन की अपारदर्शिता कैनोपी क्षेत्र के अनुसार बढ़ती है.',
|
||||||
},
|
},
|
||||||
propertyBorders: {
|
propertyBorders: {
|
||||||
label: 'संपत्ति सीमाएं',
|
label: 'संपत्ति सीमाएं',
|
||||||
detail:
|
detail:
|
||||||
'HM Land Registry INSPIRE Index Polygons — इंग्लैंड और वेल्स में फ्रीहोल्ड पंजीकृत संपत्ति की स्थिति और संकेतात्मक विस्तार, सड़क स्तर पर रूपरेखा के रूप में बनाई गई. ये केवल मार्गदर्शन के लिए "सामान्य सीमाएं" हैं, किसी संपत्ति की सटीक कानूनी सीमा नहीं, और इनमें केवल-लीजहोल्ड हित और अपंजीकृत भूमि शामिल नहीं हैं (लगभग 85–90% फ्रीहोल्ड भूमि कवर है). यह जानकारी Crown copyright और डेटाबेस अधिकार 2026 के अधीन है और HM Land Registry की अनुमति से पुनरुत्पादित की गई है. पॉलीगॉन (संबंधित ज्यामिति सहित, अर्थात् x, y निर्देशांक) Crown copyright और डेटाबेस अधिकार 2026 Ordnance Survey AC0000851063 के अधीन हैं. Open Government Licence v3.0 के तहत लाइसेंस प्राप्त.',
|
'HM Land Registry INSPIRE Index Polygons: इंग्लैंड और वेल्स में फ्रीहोल्ड पंजीकृत संपत्ति की स्थिति और संकेतात्मक विस्तार, सड़क स्तर पर रूपरेखा के रूप में बनाई गई. ये केवल मार्गदर्शन के लिए "सामान्य सीमाएं" हैं, किसी संपत्ति की सटीक कानूनी सीमा नहीं, और इनमें केवल-लीजहोल्ड हित और अपंजीकृत भूमि शामिल नहीं हैं (लगभग 85–90% फ्रीहोल्ड भूमि कवर है). यह जानकारी Crown copyright और डेटाबेस अधिकार 2026 के अधीन है और HM Land Registry की अनुमति से पुनरुत्पादित की गई है. पॉलीगॉन (संबंधित ज्यामिति सहित, अर्थात् x, y निर्देशांक) Crown copyright और डेटाबेस अधिकार 2026 Ordnance Survey AC0000851063 के अधीन हैं. Open Government Licence v3.0 के तहत लाइसेंस प्राप्त.',
|
||||||
},
|
},
|
||||||
newDevelopments: {
|
newDevelopments: {
|
||||||
label: 'नए विकास',
|
label: 'नए विकास',
|
||||||
detail:
|
detail:
|
||||||
'नए आवास की एक भविष्योन्मुखी पाइपलाइन. नीले मार्कर वैधानिक MHCLG Brownfield Land registers पर साइटों को चिह्नित करते हैं — प्रत्येक में अनुमानित शुद्ध-आवास क्षमता और योजना-अनुमति स्थिति होती है — साथ ही Homes England Land Hub निपटान साइटें. ये दर्शाते हैं कि नए घर कहां योजनाबद्ध हैं, अक्सर EPC या बिक्री रिकॉर्ड में दिखाई देने से वर्षों पहले. आवास आंकड़े क्षमता अनुमान हैं, प्रतिबद्धताएं नहीं, और किसी रजिस्टर पर साइट निर्माण की गारंटी के बजाय एक अवसर है. Open Government Licence v3.0 के तहत लाइसेंस प्राप्त.',
|
'नए आवास की एक भविष्योन्मुखी पाइपलाइन. नीले मार्कर वैधानिक MHCLG Brownfield Land registers पर साइटों को चिह्नित करते हैं (प्रत्येक में अनुमानित शुद्ध-आवास क्षमता और योजना-अनुमति स्थिति होती है) साथ ही Homes England Land Hub निपटान साइटें. ये दर्शाते हैं कि नए घर कहां योजनाबद्ध हैं, अक्सर EPC या बिक्री रिकॉर्ड में दिखाई देने से वर्षों पहले. आवास आंकड़े क्षमता अनुमान हैं, प्रतिबद्धताएं नहीं, और किसी रजिस्टर पर साइट निर्माण की गारंटी के बजाय एक अवसर है. Open Government Licence v3.0 के तहत लाइसेंस प्राप्त.',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
@ -1706,6 +1736,8 @@ const hi: Translations = {
|
||||||
'% Owner occupied': '% स्वामित्व वाले घर',
|
'% Owner occupied': '% स्वामित्व वाले घर',
|
||||||
'% Social rent': '% सामाजिक किराया',
|
'% Social rent': '% सामाजिक किराया',
|
||||||
'% Private rent': '% निजी किराया',
|
'% Private rent': '% निजी किराया',
|
||||||
|
'% Council housing': '% काउंसिल आवास',
|
||||||
|
'% Ex-council': '% पूर्व काउंसिल',
|
||||||
'% White': '% श्वेत',
|
'% White': '% श्वेत',
|
||||||
'% South Asian': '% दक्षिण एशियाई',
|
'% South Asian': '% दक्षिण एशियाई',
|
||||||
'% Black': '% अश्वेत',
|
'% Black': '% अश्वेत',
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ const hu: Translations = {
|
||||||
},
|
},
|
||||||
// ── Common ──────────────────────────────────────────
|
// ── Common ──────────────────────────────────────────
|
||||||
common: {
|
common: {
|
||||||
|
retry: 'Újra',
|
||||||
save: 'Mentés',
|
save: 'Mentés',
|
||||||
update: 'Frissítés',
|
update: 'Frissítés',
|
||||||
cancel: 'Mégse',
|
cancel: 'Mégse',
|
||||||
|
|
@ -93,7 +94,7 @@ const hu: Translations = {
|
||||||
'Exportáld a térképen látható összes irányítószámot, amely megfelel a jelenlegi szűrőknek.',
|
'Exportáld a térképen látható összes irányítószámot, amely megfelel a jelenlegi szűrőknek.',
|
||||||
modeList: 'Irányítószám-lista',
|
modeList: 'Irányítószám-lista',
|
||||||
modeListHint:
|
modeListHint:
|
||||||
'Add meg az irányítószámokat egyenként – a szóközöket és a kis- és nagybetűket automatikusan javítjuk.',
|
'Add meg az irányítószámokat egyenként. A szóközöket és a kis- és nagybetűket automatikusan javítjuk.',
|
||||||
listLabel: 'Irányítószámok',
|
listLabel: 'Irányítószámok',
|
||||||
listPlaceholder: 'pl. SW1A 1AA',
|
listPlaceholder: 'pl. SW1A 1AA',
|
||||||
addRow: 'Irányítószám hozzáadása',
|
addRow: 'Irányítószám hozzáadása',
|
||||||
|
|
@ -104,6 +105,7 @@ const hu: Translations = {
|
||||||
|
|
||||||
// ── User Menu ──────────────────────────────────────
|
// ── User Menu ──────────────────────────────────────
|
||||||
userMenu: {
|
userMenu: {
|
||||||
|
accountMenu: 'Fiók menü',
|
||||||
fullAccess: 'Teljes hozzáférés',
|
fullAccess: 'Teljes hozzáférés',
|
||||||
demo: 'Demó',
|
demo: 'Demó',
|
||||||
themeLight: 'Téma: Világos',
|
themeLight: 'Téma: Világos',
|
||||||
|
|
@ -209,7 +211,7 @@ const hu: Translations = {
|
||||||
'Find postcodes that match your property search criteria':
|
'Find postcodes that match your property search criteria':
|
||||||
'Keress az ingatlankeresési feltételeidnek megfelelő irányítószámokat',
|
'Keress az ingatlankeresési feltételeidnek megfelelő irányítószámokat',
|
||||||
'Postcode property search - Find areas that match your criteria':
|
'Postcode property search - Find areas that match your criteria':
|
||||||
'Irányítószám-alapú ingatlankeresés – Találd meg a feltételeidnek megfelelő területeket',
|
'Irányítószám-alapú ingatlankeresés: Találd meg a feltételeidnek megfelelő területeket',
|
||||||
'Search every postcode by budget, property type, floor area, tenure, commute, schools, crime, broadband, noise, parks and local amenities.':
|
'Search every postcode by budget, property type, floor area, tenure, commute, schools, crime, broadband, noise, parks and local amenities.':
|
||||||
'Keress az összes irányítószám között költségvetés, ingatlantípus, alapterület, tulajdonforma, ingázás, iskolák, bűnözés, szélessáv, zaj, parkok és helyi szolgáltatások alapján.',
|
'Keress az összes irányítószám között költségvetés, ingatlantípus, alapterület, tulajdonforma, ingázás, iskolák, bűnözés, szélessáv, zaj, parkok és helyi szolgáltatások alapján.',
|
||||||
'Search every postcode by budget, property type, size, tenure, commute, schools, crime, broadband, noise, parks, and local amenities instead of checking areas one at a time.':
|
'Search every postcode by budget, property type, size, tenure, commute, schools, crime, broadband, noise, parks, and local amenities instead of checking areas one at a time.':
|
||||||
|
|
@ -257,7 +259,7 @@ const hu: Translations = {
|
||||||
'Commute property search': 'Ingázás alapú ingatlankeresés',
|
'Commute property search': 'Ingázás alapú ingatlankeresés',
|
||||||
'Search for places to live by commute time': 'Keress lakóhelyet ingázási idő alapján',
|
'Search for places to live by commute time': 'Keress lakóhelyet ingázási idő alapján',
|
||||||
'Commute property search - Find places to live by travel time':
|
'Commute property search - Find places to live by travel time':
|
||||||
'Ingázás alapú ingatlankeresés – Lakóhelykeresés utazási idő alapján',
|
'Ingázás alapú ingatlankeresés: Lakóhelykeresés utazási idő alapján',
|
||||||
'Filter postcodes by commute time, then compare price, schools, safety, broadband, road noise, parks and property data on one map.':
|
'Filter postcodes by commute time, then compare price, schools, safety, broadband, road noise, parks and property data on one map.':
|
||||||
'Szűrd az irányítószámokat ingázási idő szerint, majd hasonlítsd össze az árakat, az iskolákat, a biztonságot, a szélessávot, az útzajt, a parkokat és az ingatlanadatokat egy térképen.',
|
'Szűrd az irányítószámokat ingázási idő szerint, majd hasonlítsd össze az árakat, az iskolákat, a biztonságot, a szélessávot, az útzajt, a parkokat és az ingatlanadatokat egy térképen.',
|
||||||
'Filter postcodes by modelled car, cycling, walking, and public transport travel times, then layer on property price, schools, crime, broadband, noise, and local amenities.':
|
'Filter postcodes by modelled car, cycling, walking, and public transport travel times, then layer on property price, schools, crime, broadband, noise, and local amenities.':
|
||||||
|
|
@ -310,7 +312,7 @@ const hu: Translations = {
|
||||||
'Find property search areas with schools and family trade-offs in view':
|
'Find property search areas with schools and family trade-offs in view':
|
||||||
'Keress olyan területeket, ahol az iskolák és a családi kompromisszumok is látszanak',
|
'Keress olyan területeket, ahol az iskolák és a családi kompromisszumok is látszanak',
|
||||||
'School property search - Compare postcodes for family moves':
|
'School property search - Compare postcodes for family moves':
|
||||||
'Iskolák és ingatlankeresés – Irányítószámok összehasonlítása családi költözéshez',
|
'Iskolák és ingatlankeresés: Irányítószámok összehasonlítása családi költözéshez',
|
||||||
'Compare nearby schools, property size, prices, parks, safety, commute and local amenities before building a viewing shortlist.':
|
'Compare nearby schools, property size, prices, parks, safety, commute and local amenities before building a viewing shortlist.':
|
||||||
'Hasonlítsd össze a közeli iskolákat, az ingatlanméretet, az árakat, a parkokat, a biztonságot, az ingázást és a helyi szolgáltatásokat, mielőtt megtekintési listát állítasz össze.',
|
'Hasonlítsd össze a közeli iskolákat, az ingatlanméretet, az árakat, a parkokat, a biztonságot, az ingázást és a helyi szolgáltatásokat, mielőtt megtekintési listát állítasz össze.',
|
||||||
'Compare nearby Ofsted ratings, education context, property size, budget, safety, parks, commute, and local amenities before narrowing your viewing shortlist.':
|
'Compare nearby Ofsted ratings, education context, property size, budget, safety, parks, commute, and local amenities before narrowing your viewing shortlist.':
|
||||||
|
|
@ -358,7 +360,7 @@ const hu: Translations = {
|
||||||
'Check postcode data before you book a viewing':
|
'Check postcode data before you book a viewing':
|
||||||
'A megtekintés lefoglalása előtt ellenőrizze az irányítószám adatait',
|
'A megtekintés lefoglalása előtt ellenőrizze az irányítószám adatait',
|
||||||
'Postcode checker - Property, crime, broadband, noise and schools':
|
'Postcode checker - Property, crime, broadband, noise and schools':
|
||||||
'Irányítószám-ellenőrző – Ingatlanok, bűnözés, szélessáv, zaj és iskolák',
|
'Irányítószám-ellenőrző: Ingatlanok, bűnözés, szélessáv, zaj és iskolák',
|
||||||
'Check postcode-level property prices, EPC data, crime, broadband, road noise, schools, council tax, amenities and travel-time context.':
|
'Check postcode-level property prices, EPC data, crime, broadband, road noise, schools, council tax, amenities and travel-time context.':
|
||||||
'Ellenőrizd az irányítószám-szintű ingatlanárakat, az EPC-adatokat, a bűnözést, a szélessávot, az útzajt, az iskolákat, a council tax szintjét, a szolgáltatásokat és az utazási időt.',
|
'Ellenőrizd az irányítószám-szintű ingatlanárakat, az EPC-adatokat, a bűnözést, a szélessávot, az útzajt, az iskolákat, a council tax szintjét, a szolgáltatásokat és az utazási időt.',
|
||||||
'Review property prices, EPC context, crime, broadband, road noise, local amenities, schools, deprivation, council tax, and travel-time data from one postcode-first map.':
|
'Review property prices, EPC context, crime, broadband, road noise, local amenities, schools, deprivation, council tax, and travel-time data from one postcode-first map.':
|
||||||
|
|
@ -404,7 +406,7 @@ const hu: Translations = {
|
||||||
'How to compare Birmingham postcodes before a property search':
|
'How to compare Birmingham postcodes before a property search':
|
||||||
'Birmingham irányítószámainak összehasonlítása ingatlankeresés előtt',
|
'Birmingham irányítószámainak összehasonlítása ingatlankeresés előtt',
|
||||||
'Birmingham property search - Compare postcodes by price and commute':
|
'Birmingham property search - Compare postcodes by price and commute':
|
||||||
'Birminghami ingatlankeresés – Hasonlítsd össze az irányítószámokat ár és ingázás alapján',
|
'Birminghami ingatlankeresés: Hasonlítsd össze az irányítószámokat ár és ingázás alapján',
|
||||||
'Use postcode-level data to compare Birmingham property prices, commute trade-offs, schools, crime, broadband and local amenities before viewings.':
|
'Use postcode-level data to compare Birmingham property prices, commute trade-offs, schools, crime, broadband and local amenities before viewings.':
|
||||||
'Használd az irányítószám-szintű adatokat a birminghami ingatlanárak, ingázási kompromisszumok, iskolák, bűnözés, szélessáv és helyi szolgáltatások összehasonlítására a megtekintések előtt.',
|
'Használd az irányítószám-szintű adatokat a birminghami ingatlanárak, ingázási kompromisszumok, iskolák, bűnözés, szélessáv és helyi szolgáltatások összehasonlítására a megtekintések előtt.',
|
||||||
'Birmingham searches can change quickly from street to street. Use postcode-level evidence to compare budget, commute, schools, noise, crime, and local services before deciding where to watch listings.':
|
'Birmingham searches can change quickly from street to street. Use postcode-level evidence to compare budget, commute, schools, noise, crime, and local services before deciding where to watch listings.':
|
||||||
|
|
@ -476,7 +478,7 @@ const hu: Translations = {
|
||||||
'How to compare Bristol postcodes before a property search':
|
'How to compare Bristol postcodes before a property search':
|
||||||
'Hogyan hasonlítsuk össze Bristol irányítószámait ingatlankeresés előtt',
|
'Hogyan hasonlítsuk össze Bristol irányítószámait ingatlankeresés előtt',
|
||||||
'Bristol property search - Compare postcodes by commute and price':
|
'Bristol property search - Compare postcodes by commute and price':
|
||||||
'Ingatlankeresés Bristolban – Hasonlítsd össze az irányítószámokat ingázás és ár alapján',
|
'Ingatlankeresés Bristolban: Hasonlítsd össze az irányítószámokat ingázás és ár alapján',
|
||||||
'Compare Bristol postcodes by price, commute, property size, schools, broadband, crime, road noise, parks and amenities before viewings.':
|
'Compare Bristol postcodes by price, commute, property size, schools, broadband, crime, road noise, parks and amenities before viewings.':
|
||||||
'Hasonlítsd össze Bristol irányítószámait ár, ingázás, ingatlanméret, iskolák, szélessáv, bűnözés, közúti zaj, parkok és szolgáltatások szerint a megtekintés előtt.',
|
'Hasonlítsd össze Bristol irányítószámait ár, ingázás, ingatlanméret, iskolák, szélessáv, bűnözés, közúti zaj, parkok és szolgáltatások szerint a megtekintés előtt.',
|
||||||
'Bristol searches often involve sharp trade-offs between price, journey time, property size, and neighbourhood context. A postcode-first comparison keeps those trade-offs visible.':
|
'Bristol searches often involve sharp trade-offs between price, journey time, property size, and neighbourhood context. A postcode-first comparison keeps those trade-offs visible.':
|
||||||
|
|
@ -510,7 +512,7 @@ const hu: Translations = {
|
||||||
'Trust and coverage': 'Megbízhatóság és lefedettség',
|
'Trust and coverage': 'Megbízhatóság és lefedettség',
|
||||||
'Perfect Postcode data sources and coverage': 'Perfect Postcode adatforrások és lefedettség',
|
'Perfect Postcode data sources and coverage': 'Perfect Postcode adatforrások és lefedettség',
|
||||||
'Perfect Postcode data sources - Property, schools, commute and local context':
|
'Perfect Postcode data sources - Property, schools, commute and local context':
|
||||||
'Perfect Postcode-adatforrások – ingatlanok, iskolák, ingázás és helyi környezet',
|
'Perfect Postcode-adatforrások: ingatlanok, iskolák, ingázás és helyi környezet',
|
||||||
'Review the public and official datasets used by Perfect Postcode, including property prices, EPC, schools, crime, broadband, noise and travel-time context.':
|
'Review the public and official datasets used by Perfect Postcode, including property prices, EPC, schools, crime, broadband, noise and travel-time context.':
|
||||||
'Nézd át a Perfect Postcode által használt nyilvános és hivatalos adatkészleteket, többek között az ingatlanárakat, az EPC-t, az iskolákat, a bűnözést, a szélessávot, a zajt és az utazásiidő-adatokat.',
|
'Nézd át a Perfect Postcode által használt nyilvános és hivatalos adatkészleteket, többek között az ingatlanárakat, az EPC-t, az iskolákat, a bűnözést, a szélessávot, a zajt és az utazásiidő-adatokat.',
|
||||||
'Perfect Postcode combines property, transport, education, environment, and local-service datasets so buyers can compare postcodes consistently. This page explains what the data is for and where it should be verified.':
|
'Perfect Postcode combines property, transport, education, environment, and local-service datasets so buyers can compare postcodes consistently. This page explains what the data is for and where it should be verified.':
|
||||||
|
|
@ -545,7 +547,7 @@ const hu: Translations = {
|
||||||
'Methodology for postcode property research':
|
'Methodology for postcode property research':
|
||||||
'Az irányítószám-alapú ingatlankutatás módszertana',
|
'Az irányítószám-alapú ingatlankutatás módszertana',
|
||||||
'Perfect Postcode methodology - How to interpret postcode property data':
|
'Perfect Postcode methodology - How to interpret postcode property data':
|
||||||
'Perfect Postcode módszertan – Az irányítószám-alapú ingatlanadatok értelmezése',
|
'Perfect Postcode módszertan: Az irányítószám-alapú ingatlanadatok értelmezése',
|
||||||
'Understand how to use postcode filters, property estimates, travel-time data, school context and local signals as a home-buying shortlist tool.':
|
'Understand how to use postcode filters, property estimates, travel-time data, school context and local signals as a home-buying shortlist tool.':
|
||||||
'Ismerd meg, hogyan használhatod az irányítószám-szűrőket, az ingatlanbecsléseket, az utazásiidő-adatokat, az iskolai környezetet és a helyi jeleket lakásvásárlási előválogatáshoz.',
|
'Ismerd meg, hogyan használhatod az irányítószám-szűrőket, az ingatlanbecsléseket, az utazásiidő-adatokat, az iskolai környezetet és a helyi jeleket lakásvásárlási előválogatáshoz.',
|
||||||
'Perfect Postcode is designed to make area shortlisting more evidence-led. It doesn’t replace estate agents, surveyors, conveyancers, lenders, school admissions teams, or local authority checks.':
|
'Perfect Postcode is designed to make area shortlisting more evidence-led. It doesn’t replace estate agents, surveyors, conveyancers, lenders, school admissions teams, or local authority checks.':
|
||||||
|
|
@ -575,7 +577,7 @@ const hu: Translations = {
|
||||||
'Privacy and security for saved property searches':
|
'Privacy and security for saved property searches':
|
||||||
'Adatvédelem és biztonság a mentett ingatlankereséshez',
|
'Adatvédelem és biztonság a mentett ingatlankereséshez',
|
||||||
'Perfect Postcode privacy and security - Saved searches and account data':
|
'Perfect Postcode privacy and security - Saved searches and account data':
|
||||||
'Perfect Postcode adatvédelem és biztonság – Mentett keresések és fiókadatok',
|
'Perfect Postcode adatvédelem és biztonság: Mentett keresések és fiókadatok',
|
||||||
'Learn how Perfect Postcode treats saved searches, account data and property research workflows with privacy and security in mind.':
|
'Learn how Perfect Postcode treats saved searches, account data and property research workflows with privacy and security in mind.':
|
||||||
'Ismerd meg, hogyan kezeli a Perfect Postcode a mentett kereséseket, a fiókadatokat és az ingatlankutatási munkafolyamatokat adatvédelmi és biztonsági szempontból.',
|
'Ismerd meg, hogyan kezeli a Perfect Postcode a mentett kereséseket, a fiókadatokat és az ingatlankutatási munkafolyamatokat adatvédelmi és biztonsági szempontból.',
|
||||||
'Property research can reveal personal priorities, budgets, and locations. The product keeps public SEO pages separate from account-only areas and marks private dashboard/account routes as noindex.':
|
'Property research can reveal personal priorities, budgets, and locations. The product keeps public SEO pages separate from account-only areas and marks private dashboard/account routes as noindex.':
|
||||||
|
|
@ -610,13 +612,23 @@ const hu: Translations = {
|
||||||
|
|
||||||
// ── Auth Modal ─────────────────────────────────────
|
// ── Auth Modal ─────────────────────────────────────
|
||||||
auth: {
|
auth: {
|
||||||
|
errorRateLimited: 'Túl sok próbálkozás. Kérjük, várj egy percet, majd próbáld újra.',
|
||||||
|
errorNetwork: 'Nem sikerült elérni a szervert. Ellenőrizd a kapcsolatot, majd próbáld újra.',
|
||||||
|
errorEmailTaken: 'Ezzel az e-mail-címmel már létezik fiók.',
|
||||||
|
errorPasswordWeak: 'A jelszónak legalább 8 karakter hosszúnak kell lennie.',
|
||||||
|
errorEmailInvalid: 'Kérjük, adj meg egy érvényes e-mail-címet.',
|
||||||
|
errorInvalidCredentials: 'Hibás e-mail-cím vagy jelszó.',
|
||||||
|
logInInstead: 'Inkább jelentkezz be',
|
||||||
|
accountCreatedPleaseLogIn: 'A fiók létrejött. A folytatáshoz jelentkezz be.',
|
||||||
|
accountCreatedRateLimited:
|
||||||
|
'A fiók létrejött. Épp túl sok volt a próbálkozás. Kérjük, várj egy pillanatot, majd jelentkezz be.',
|
||||||
logIn: 'Bejelentkezés',
|
logIn: 'Bejelentkezés',
|
||||||
createAccount: 'Regisztráció',
|
createAccount: 'Regisztráció',
|
||||||
resetPassword: 'Jelszó visszaállítása',
|
resetPassword: 'Jelszó visszaállítása',
|
||||||
valueProp:
|
valueProp:
|
||||||
'Mentsd el a kereséseidet, jelöld meg az ingatlanokat, és állíts össze egy listát a megfelelő területekből.',
|
'Mentsd el a kereséseidet, jelöld meg az ingatlanokat, és állíts össze egy listát a megfelelő területekből.',
|
||||||
dashboardActionsValueProp:
|
dashboardActionsValueProp:
|
||||||
'Hozz létre egy ingyenes fiókot a kereséseid mentéséhez, megosztásához és exportálásához – ingyenes, kártya nélkül.',
|
'Hozz létre egy ingyenes fiókot a kereséseid mentéséhez, megosztásához és exportálásához. Ingyenes, kártya nélkül.',
|
||||||
continueWithGoogle: 'Folytatás Google-lel',
|
continueWithGoogle: 'Folytatás Google-lel',
|
||||||
email: 'E-mail',
|
email: 'E-mail',
|
||||||
emailPlaceholder: 'te@pelda.hu',
|
emailPlaceholder: 'te@pelda.hu',
|
||||||
|
|
@ -643,12 +655,12 @@ const hu: Translations = {
|
||||||
'Felhasználtad az ingyenes fiókod mind az 5 szűrőjét. Szerezz élethosszig tartó hozzáférést, hogy korlátlanul rétegezhesd a szűrőket Anglia minden irányítószámán és környékén. Egyetlen fizetés, örökre.',
|
'Felhasználtad az ingyenes fiókod mind az 5 szűrőjét. Szerezz élethosszig tartó hozzáférést, hogy korlátlanul rétegezhesd a szűrőket Anglia minden irányítószámán és környékén. Egyetlen fizetés, örökre.',
|
||||||
titleRegister: 'Ingyenes fiók létrehozása',
|
titleRegister: 'Ingyenes fiók létrehozása',
|
||||||
descriptionRegister:
|
descriptionRegister:
|
||||||
'Az ingyenes fiókok akár 5 szűrőt oldanak fel, ráadásul menthetsz, megoszthatsz és exportálhatsz – kártya nélkül. Korlátlan szűrőket szeretnél egész Angliában? Válaszd az élethosszig tartó hozzáférést.',
|
'Az ingyenes fiókok akár 5 szűrőt oldanak fel, ráadásul menthetsz, megoszthatsz és exportálhatsz, kártya nélkül. Korlátlan szűrőket szeretnél egész Angliában? Válaszd az élethosszig tartó hozzáférést.',
|
||||||
descriptionSharedRegister:
|
descriptionSharedRegister:
|
||||||
'Ez egy megosztott keresés. Hozz létre egy ingyenes fiókot, hogy sajátot készíthess akár 5 szűrővel, és menthess, megoszthass és exportálhass – vagy válassz élethosszig tartó hozzáférést a korlátlan szűrőkért.',
|
'Ez egy megosztott keresés. Hozz létre egy ingyenes fiókot, hogy sajátot készíthess akár 5 szűrővel, és menthess, megoszthass és exportálhass, vagy válassz élethosszig tartó hozzáférést a korlátlan szűrőkért.',
|
||||||
registerFree: 'Ingyenes fiók létrehozása',
|
registerFree: 'Ingyenes fiók létrehozása',
|
||||||
lifetimeUpsell: 'Korlátlan szűrőket szeretnél?',
|
lifetimeUpsell: 'Korlátlan szűrőket szeretnél?',
|
||||||
goLifetime: 'Élethosszig tartó hozzáférés – {{price}}',
|
goLifetime: 'Élethosszig tartó hozzáférés: {{price}}',
|
||||||
free: 'Ingyenes',
|
free: 'Ingyenes',
|
||||||
freeForEarly: 'Ingyenes a korai felhasználóknak. Bankkártya nélkül.',
|
freeForEarly: 'Ingyenes a korai felhasználóknak. Bankkártya nélkül.',
|
||||||
oneTimePayment: 'Egyszeri fizetés. Élethosszig tartó hozzáférés.',
|
oneTimePayment: 'Egyszeri fizetés. Élethosszig tartó hozzáférés.',
|
||||||
|
|
@ -700,8 +712,7 @@ const hu: Translations = {
|
||||||
upgradeToFullMap: 'Teljes térkép megnyitása',
|
upgradeToFullMap: 'Teljes térkép megnyitása',
|
||||||
registerPrompt:
|
registerPrompt:
|
||||||
'Hozz létre egy ingyenes fiókot, hogy akár 5 szűrőt kombinálhass, és menthess, megoszthass és exportálhass kereséseket.',
|
'Hozz létre egy ingyenes fiókot, hogy akár 5 szűrőt kombinálhass, és menthess, megoszthass és exportálhass kereséseket.',
|
||||||
registerSubPrompt:
|
registerSubPrompt: 'Ingyenes, kártya nélkül. Korlátlan szűrők élethosszig tartó hozzáféréssel.',
|
||||||
'Ingyenes – kártya nélkül. Korlátlan szűrők élethosszig tartó hozzáféréssel.',
|
|
||||||
registerCta: 'Ingyenes fiók létrehozása',
|
registerCta: 'Ingyenes fiók létrehozása',
|
||||||
chooseFilters:
|
chooseFilters:
|
||||||
'Kattints a Hozzáadásra a szűréshez. A kis gombok adatokat mutatnak vagy színezik a térképet.',
|
'Kattints a Hozzáadásra a szűréshez. A kis gombok adatokat mutatnak vagy színezik a térképet.',
|
||||||
|
|
@ -741,6 +752,11 @@ const hu: Translations = {
|
||||||
crimeType: 'Bűncselekménytípus',
|
crimeType: 'Bűncselekménytípus',
|
||||||
qualificationLevel: 'Képzettségi szint',
|
qualificationLevel: 'Képzettségi szint',
|
||||||
tenureType: 'Lakhatási forma',
|
tenureType: 'Lakhatási forma',
|
||||||
|
councilType: 'Önkormányzati lakás típusa',
|
||||||
|
councilStatus: 'Típus',
|
||||||
|
councilCurrent: 'Jelenlegi',
|
||||||
|
councilEx: 'Korábbi',
|
||||||
|
councilBoth: 'Mindkettő',
|
||||||
crimeWindow: 'Időszak',
|
crimeWindow: 'Időszak',
|
||||||
crimeWindow7y: '7 év',
|
crimeWindow7y: '7 év',
|
||||||
crimeWindow2y: '2 év',
|
crimeWindow2y: '2 év',
|
||||||
|
|
@ -861,8 +877,11 @@ const hu: Translations = {
|
||||||
},
|
},
|
||||||
actualListings: {
|
actualListings: {
|
||||||
label: 'Hirdetések',
|
label: 'Hirdetések',
|
||||||
show: 'Valódi hirdetések megjelenítése',
|
modes: {
|
||||||
hide: 'Valódi hirdetések elrejtése',
|
new: 'Új építésű',
|
||||||
|
nonNew: 'Használt',
|
||||||
|
hint: 'Az „Új építésű” az új fejlesztéseket, a „Használt” a viszonteladásokat és egyéb hirdetéseket mutatja.',
|
||||||
|
},
|
||||||
},
|
},
|
||||||
poi: { zoomInToSeeDetails: 'Nagyíts rá a részletekért' },
|
poi: { zoomInToSeeDetails: 'Nagyíts rá a részletekért' },
|
||||||
},
|
},
|
||||||
|
|
@ -889,6 +908,7 @@ const hu: Translations = {
|
||||||
historyTitle: 'Előzmények',
|
historyTitle: 'Előzmények',
|
||||||
historySale: 'Eladás',
|
historySale: 'Eladás',
|
||||||
historyBuilt: 'Építés',
|
historyBuilt: 'Építés',
|
||||||
|
historyNewBuild: 'Újépítésű',
|
||||||
tenureOwnerOccupied: 'Tulajdonos lakja',
|
tenureOwnerOccupied: 'Tulajdonos lakja',
|
||||||
tenureRentedPrivate: 'Magánbérlemény',
|
tenureRentedPrivate: 'Magánbérlemény',
|
||||||
tenureRentedSocial: 'Szociális bérlakás',
|
tenureRentedSocial: 'Szociális bérlakás',
|
||||||
|
|
@ -1003,20 +1023,22 @@ const hu: Translations = {
|
||||||
|
|
||||||
// ── Home Page ──────────────────────────────────────
|
// ── Home Page ──────────────────────────────────────
|
||||||
home: {
|
home: {
|
||||||
heroEyebrow: 'Vevőknek, akik azt kérdezik: „hol is kezdjem?”',
|
heroEyebrow: 'Vevőknek, akik nem hajlandók túlfizetni egy irányítószám hírnevéért',
|
||||||
heroTitle1: 'Találd meg az irányítószámokat',
|
heroTitle1: 'Találd meg a',
|
||||||
heroTitle2: 'amelyek illenek az életedhez',
|
heroTitle2: 'rejtett kincs irányítószámot',
|
||||||
heroTitle3: 'Nem csak azokat a környékeket, amelyeket már ismersz.',
|
heroTitle3: 'Ugyanazok az iskolák, ugyanaz az ingázás, csendben olcsóbban.',
|
||||||
heroSubtitle:
|
heroSubtitle:
|
||||||
'A londoni városrészeken, ingázó településeken és regionális városokon át Angliában túl sok hely van ahhoz, hogy egyenként kutasd át őket.',
|
'Két utca osztozhat ugyanazon az iskolán, állomáson és építési éven, mégis tízezrekkel eltérő áron kel el. Az egyik rosszul van beárazva. Mi megtaláljuk, melyik.',
|
||||||
heroDescription:
|
heroDescription:
|
||||||
'Állítsd be a költségvetést, ingázást, iskolákat, biztonságot, zajt, internetet és életstílust. A Perfect Postcode átnézi Anglia irányítószámait, és megmutatja azokat a helyeket is, amelyeket sosem írtál volna be egy ingatlanportálra.',
|
'Állítsd be a költségvetésed és azt, amiből nem engedsz. A Perfect Postcode Anglia minden irányítószámát aszerint rangsorolja, hogy mit ér valójában minden font (alapterületet, iskolákat, ingázást és biztonságot), és minden választás mögött ott a bizonyíték.',
|
||||||
exploreTheMap: 'Megfelelő irányítószámok keresése',
|
exploreTheMap: 'Találd meg a rejtett kincs irányítószámomat',
|
||||||
seeTheDifference: 'Így működik',
|
seeTheDifference: 'Nézz meg egy valódi rejtett kincset',
|
||||||
|
freeToExplore: 'Fedezd fel az élő térképet ingyen, regisztráció és bankkártya nélkül.',
|
||||||
|
dataSourcesLabel: 'Hivatalos adatokra építve',
|
||||||
|
dataSources: 'Land Registry · ONS · Ofsted · DfT · Ordnance Survey · Police.uk',
|
||||||
productDemoLabel: 'Perfect Postcode termékdemó',
|
productDemoLabel: 'Perfect Postcode termékdemó',
|
||||||
playProductDemo: 'Perfect Postcode termékdemó lejátszása',
|
playProductDemo: 'Perfect Postcode termékdemó lejátszása',
|
||||||
scrollToProductDemo: 'Ugrás a termékdemóhoz',
|
scrollToProductDemo: 'Ugrás a termékdemóhoz',
|
||||||
showcaseHeader: 'Így működik',
|
|
||||||
showcaseContext: 'Így működik a Perfect Postcode',
|
showcaseContext: 'Így működik a Perfect Postcode',
|
||||||
showcaseFeaturePriceShort: 'Ár',
|
showcaseFeaturePriceShort: 'Ár',
|
||||||
showcaseFeatureNoiseShort: 'Zaj',
|
showcaseFeatureNoiseShort: 'Zaj',
|
||||||
|
|
@ -1030,94 +1052,99 @@ const hu: Translations = {
|
||||||
showcaseJourneyRoutes: 'Útvonalak',
|
showcaseJourneyRoutes: 'Útvonalak',
|
||||||
showcaseNearby: '{{value}} a közelben',
|
showcaseNearby: '{{value}} a közelben',
|
||||||
showcasePoliticalVoteShare: 'Politikai szavazatarány',
|
showcasePoliticalVoteShare: 'Politikai szavazatarány',
|
||||||
showcaseLotsMore: '...és még sok más',
|
showcaseGe2024: '2024-es választás',
|
||||||
|
showcaseLotsMore: '…és még sok más',
|
||||||
showcaseMinutes: '{{count}} perc',
|
showcaseMinutes: '{{count}} perc',
|
||||||
showcaseSendShortlist: 'Küldd el a szűkített listát',
|
showcaseSendShortlist: 'Küldd el a szűkített listát',
|
||||||
showcaseDownloadXlsx: '.xlsx letöltése',
|
showcaseDownloadXlsx: '.xlsx letöltése',
|
||||||
showcaseTopThree: 'Legjobb 3',
|
showcaseTopThree: 'Legjobb 3',
|
||||||
showcaseScoutBullet1:
|
showcaseScoutBullet1:
|
||||||
'Járd be az utcákat, mielőtt a hirdetéskeresés leszűkíti a lehetőségeidet.',
|
'Járd be annak az irányítószámnak az utcáit, amely lekörözi drágább szomszédját.',
|
||||||
showcaseScoutBullet2: 'Valódi bejárati ajtótól teszteld az ingázást, ne csak városrésznévből.',
|
showcaseScoutBullet2:
|
||||||
showcaseScoutBullet3: 'Bizonyítékokkal a kezedben hasonlítsd össze a megtekintéseket.',
|
'Teszteld az ingázást egy valódi bejárati ajtótól, ne egy kerület nevéből.',
|
||||||
|
showcaseScoutBullet3:
|
||||||
|
'Hasonlítsd össze a megtekintéseket úgy, hogy a bizonyíték már a kezedben van.',
|
||||||
showcaseStep1Tab: 'Szűrés',
|
showcaseStep1Tab: 'Szűrés',
|
||||||
showcaseStep1Title: 'A homályos igényekből pontos keresés lesz',
|
showcaseStep1Title: 'A homályos igényekből pontos keresés lesz',
|
||||||
showcaseStep1Body:
|
showcaseStep1Body:
|
||||||
'Állítsd be, mi számít, és pontosan lásd, hogy minden feltétel hány nem megfelelő irányítószámot zár ki a keresésből.',
|
'Állítsd be, mi számít, és pontosan lásd, hogy minden feltétel hány nem megfelelő irányítószámot zár ki a keresésből.',
|
||||||
showcaseStep1Chip1: 'Csendes utcák',
|
|
||||||
showcaseStep1Chip2: 'Kiváló általános iskolák',
|
|
||||||
showcaseStep1Chip3: '£500k alatt',
|
|
||||||
showcaseStep1VennCenter: 'Mindhárom feltételt teljesítő irányítószámok',
|
|
||||||
showcaseStep2Tab: 'Találat',
|
showcaseStep2Tab: 'Találat',
|
||||||
showcaseStep2Title: 'A térkép olyan helyeket hoz felszínre, amelyeket be sem írtál volna',
|
showcaseStep2Title: 'Nézd, ahogy felragyognak az alulárazott irányítószámok',
|
||||||
showcaseStep2Body:
|
showcaseStep2Body:
|
||||||
'Ismert területnevek helyett illeszkedés alapján pásztázd végig Angliát. A rejtett, jó lehetőségek láthatóvá válnak, mielőtt a hirdetési portálok leszűkítenék a gondolkodásodat.',
|
'Rangsorold Angliát ár-érték arány szerint, ne a már ismert területnevek alapján. Az alulárazott zugok (erősek £/m²-ben, iskolákban és ingázásban) a lista élére kerülnek.',
|
||||||
showcaseStep2Region: 'Nagy-London',
|
showcaseStep2Region: 'Nagy-London',
|
||||||
showcaseStep2Sources: 'Land Registry · ONS · Ofsted · DfT',
|
showcaseStep2Sources: 'Land Registry · ONS · Ofsted · DfT',
|
||||||
showcaseStep2ClustersLabel: 'Találati csoportok',
|
|
||||||
showcaseStep3Tab: 'Vizsgálat',
|
showcaseStep3Tab: 'Vizsgálat',
|
||||||
showcaseStep3Title: 'Nézd meg, miért került be egy irányítószám',
|
showcaseStep3Title: 'Nézd meg, miért került be egy irányítószám',
|
||||||
showcaseStep3Body:
|
showcaseStep3Body:
|
||||||
'Nyiss meg bármelyik megfelelő területet, és egy panelen ellenőrizd az árakat, biztonságot, iskolákat, internetet és kompromisszumokat, mielőtt rászánsz egy hétvégét.',
|
'Nyiss meg bármelyik megfelelő területet, és egyetlen panelen ellenőrizd az árakat, a biztonságot, az iskolákat, az internetet és a kompromisszumokat, mielőtt egy hétvégét rászánnál.',
|
||||||
showcaseStep3HeaderArea: 'A te tökéletes irányítószámod',
|
|
||||||
showcaseStep3HeaderFit: 'Környékadatok',
|
|
||||||
showcaseStep3Stat1Label: 'Eladási ár trend',
|
|
||||||
showcaseStep3Stat2Label: 'Bűnözési ráta',
|
showcaseStep3Stat2Label: 'Bűnözési ráta',
|
||||||
showcaseStep3Stat2Value: 'Kerületi átlag alatt',
|
|
||||||
showcaseStep3Stat3Label: 'Medián életkor',
|
|
||||||
showcaseStep3Stat4Label: 'Internet',
|
|
||||||
showcaseStep3Stat4Value: '1 Gbps elérhető',
|
|
||||||
showcaseStep3Stat5Label: 'Általános iskolák',
|
|
||||||
showcaseStep3Stat5Value: '3 kiváló iskola 1 mérföldön belül',
|
|
||||||
showcaseStep4Tab: 'Felderítés',
|
showcaseStep4Tab: 'Felderítés',
|
||||||
showcaseStep4Title: 'Nézd meg személyesen',
|
showcaseStep4Title: 'Derítsd fel személyesen',
|
||||||
showcaseStep4Body:
|
showcaseStep4Body:
|
||||||
'Vigyél magaddal három megalapozott kiindulópontot a való világba. Sétáld be az utcákat, próbáld ki az ingázást, és háttéradatokkal a kezedben hasonlítsd össze a megtekintéseket.',
|
'Vidd magaddal a három legjobb irányítószámot a való világba. Sétáld be az utcákat, próbáld ki az ingázást, és háttéradatokkal hasonlítsd össze a megtekintéseket.',
|
||||||
showcaseStep4FileName: 'areas-to-scout.xlsx',
|
showcaseStep4FileName: 'areas-to-scout.xlsx',
|
||||||
showcaseStep4ExportLabel: 'Exportálás Excelbe',
|
|
||||||
showcaseStep4ColPostcode: 'Irányítószám',
|
showcaseStep4ColPostcode: 'Irányítószám',
|
||||||
showcaseStep4ColScore: 'Egyezés',
|
showcaseStep4ColScore: 'Egyezés',
|
||||||
showcaseStep4ColCommute: 'Ingázás',
|
showcaseStep4ColCommute: 'Ingázás',
|
||||||
showcaseStep4ColPrice: 'Medián eladási ár',
|
showcaseStep4ColPrice: '£/sqm',
|
||||||
showcaseStep4Conclusion: 'Innen már el tudod indítani a keresést.',
|
showcaseStep4Conclusion: 'Innen indulj felderíteni.',
|
||||||
showcaseGe2024: '2024-es választás',
|
|
||||||
statProperties: 'korábbi eladás',
|
statProperties: 'korábbi eladás',
|
||||||
statFilters: 'kombinálható szűrő',
|
statFilters: 'kombinálható szűrő',
|
||||||
statEvery: 'Minden',
|
statEvery: 'Minden',
|
||||||
statPostcodeInEngland: 'irányítószám Angliában',
|
statPostcodeInEngland: 'irányítószám Angliában',
|
||||||
coverageNote:
|
coverageNote:
|
||||||
'Anglia összes irányítószámát lefedi — egyenként 200+ adatmezővel. Skócia és Wales a terveink között szerepel.',
|
'Anglia összes irányítószámát lefedi, egyenként 200+ adatmezővel. Skócia és Wales a terveink között szerepel.',
|
||||||
priceStrip: 'Örökös hozzáférés, jelenleg {{price}} — az ár a szintek betelésével emelkedik.',
|
priceStrip:
|
||||||
|
'Fizess egyszer az örökös hozzáférésért: jelenleg {{price}}, és az ár a szintek betelésével emelkedik.',
|
||||||
priceStripSpots: 'Már csak {{count}} hely ezen az áron.',
|
priceStripSpots: 'Már csak {{count}} hely ezen az áron.',
|
||||||
priceStripSpotsPlural: 'Már csak {{count}} hely ezen az áron.',
|
priceStripSpotsPlural: 'Már csak {{count}} hely ezen az áron.',
|
||||||
priceStripCta: 'Árak megtekintése',
|
priceStripCta: 'Árak megtekintése',
|
||||||
ourPhilosophy: 'Indulj ki abból, ami számít, majd találd meg a megfelelő irányítószámot',
|
ourPhilosophy: 'A hírnév már be van árazva. Az érték még nincs.',
|
||||||
philosophyP1:
|
philosophyP1:
|
||||||
'A legtöbb ingatlanoldal először azt kérdezi, hol szeretnél élni. Londonban ez különösen nehéz, de ugyanez a probléma egész Angliában megjelenik: a vevők néhány ismert helyből indulnak ki, majd külön füleken ellenőrzik az ingázást, iskolákat, bűnözést, Street View-t, internetet és eladási árakat.',
|
'Egy irányítószám árának egy részét a falai, az iskolakörzete és az ingázása adják. A többi csak a név. A vevők azokat az irányítószámokat licitálják fel, amelyekről hallottak, így a mögöttük húzódó utca (amely minden ártényezőben azonos) csendben olcsóbb marad. Ezt a rést kézzel megtalálni tucatnyi böngészőfület jelent: eladási árak, Ofsted, bűnözés, zaj, alapterületek.',
|
||||||
philosophyP2:
|
philosophyP2:
|
||||||
'A Perfect Postcode megfordítja a keresést. Mondd meg a térképnek, mi számít, és megmutatja a megfelelő irányítószámokat, indoklással együtt. Előbb az adatok, aztán a helyszíni benyomás.',
|
'A Perfect Postcode helyetted végzi el az összevetést. Mondd meg a térképnek a költségvetésed és azt, amiből nem engedsz; minden angliai irányítószámot az árat meghatározó tényezők alapján mér le, és az alulárazottakat teszi a lista élére. Aztán menj, és járd be személyesen.',
|
||||||
streetTitle: 'A helyek utcáról utcára változnak',
|
streetTitle: 'A különbség utcáról utcára változik',
|
||||||
streetIntro:
|
streetIntro:
|
||||||
'A nagy környéknevek elrejtik a fontos részleteket: az állomás melyik oldalát, az útzajt, az iskolákat, a pontos ingázást és a valódi eladási árakat.',
|
'A nagy területnevek elrejtik, hol vannak a jó vételek: az állomás olcsóbb oldalát, a csendesebb utcát, az azonos iskolakörzetet, és azt, hogy a szinte azonos otthonok valójában mennyiért keltek el négyzetméterenként.',
|
||||||
streetCard1Title: 'Találd meg a kihagyott környékeket',
|
streetCard1Title: 'Találd meg az olcsóbb ikertestvért',
|
||||||
streetCard1Body:
|
streetCard1Body:
|
||||||
'Hozd felszínre azokat az irányítószámokat, amelyek megfelelnek a feltételeidnek, ne csak ismert nevekre vagy ajánlásokra hagyatkozz.',
|
'Minden ismert irányítószámnak van egy csendesebb szomszédja ugyanazzal az iskolakörzettel, ugyanazzal az állomással és ugyanabból a korszakból származó házakkal, felár nélkül, és a „feltörekvő” felárcímke nélkül. Egymás mellé tesszük a kettőt, hogy a különbséget lehetetlen legyen nem észrevenni.',
|
||||||
streetCard2Title: 'Lásd a kompromisszumokat megtekintés előtt',
|
streetCard2Title: 'Lásd, mit kapsz valójában a pénzedért',
|
||||||
streetCard2Body:
|
streetCard2Body:
|
||||||
'Hasonlítsd össze az árat, méretet, ingázást, biztonságot, iskolákat, internetet, zajt és energiahatékonyságot, mielőtt hétvégéket töltesz megtekintésekkel.',
|
'Alapterület, eladási árak, ingázás, bűnözés, iskolák, internet, zaj és energiabesorolás egyetlen képernyőn, nem nyolc böngészőfülön és egy táblázatban. Döntsd el, mi ér meg egy szombatot, mielőtt elköltöd rá a szombatot.',
|
||||||
othersVs: 'Mások vs.',
|
othersVs: 'Mások vs.',
|
||||||
checkMyPostcode: 'Ingatlanportálok',
|
checkMyPostcode: 'Ingatlanportálok',
|
||||||
areaGuides: 'Irányítószám-jelentések',
|
areaGuides: 'Irányítószám-jelentések',
|
||||||
compSearchWithout: 'Területek felfedezése a nevük ismerete előtt',
|
compSearchWithout: 'Aszerint rangsorolva, hogy mit kapsz, nem aszerint, ki hallott róla',
|
||||||
compSearchWithoutSub: '(előbb igények, aztán helyszín)',
|
compSearchWithoutSub: '(az igényeidhez illő olcsóbb ikertestvér, nem a név)',
|
||||||
compAreaData: 'Irányítószám-szintű környékadatok',
|
compAreaData: 'Irányítószám-szintű környékadatok',
|
||||||
compAreaDataSub: '(bűnözés, iskolák, zaj, internet, szolgáltatások)',
|
compAreaDataSub: '(bűnözés, iskolák, zaj, internet, szolgáltatások)',
|
||||||
compPropertyData: 'Ingatlanszintű előzmények',
|
compPropertyData: 'Ingatlanszintű előzmények',
|
||||||
compPropertyDataSub: '(eladási árak, EPC, alapterület, becsült érték)',
|
compPropertyDataSub: '(eladási árak, EPC, alapterület, becsült érték)',
|
||||||
compFilters: '40+ együtt működő szűrő',
|
compFilters: '40+ együtt működő szűrő',
|
||||||
compFiltersSub: '(nem egyenkénti irányítószám- vagy hirdetésellenőrzés)',
|
compFiltersSub: '(nem egyenkénti irányítószám- vagy hirdetésellenőrzés)',
|
||||||
ctaTitle: 'Ne találgasd, hol vegyél.',
|
compListings: 'Élő hirdetések, fotók és megtekintések',
|
||||||
|
compListingsSub: '(egy konkrét otthon megvásárlásának napi teendői)',
|
||||||
|
twinBadge: 'Valós példa',
|
||||||
|
twinTitle: 'Ugyanaz az élet, egy irányítószámmal olcsóbban',
|
||||||
|
twinIntro:
|
||||||
|
'Két észak-londoni szomszéd, egymástól 1,3 km-re: lakások hasonló általános iskolai körzetekkel és ugyanazzal a ~30 perces ingázással, mégis négyzetméterenként nagyon eltérő áron.',
|
||||||
|
twinPriceyLabel: 'A név, amelyet mindenki ismer',
|
||||||
|
twinValueLabel: 'A csendesebb szomszédja',
|
||||||
|
twinPerSqm: '{{value}}/sqm',
|
||||||
|
twinSameSchool: 'Mindkettő „kiváló” minősítésű általános iskolai körzetben',
|
||||||
|
twinSameCommute: 'Mindkettő ~30 perc tömegközlekedéssel London központjáig',
|
||||||
|
twinDelta: '{{percent}}-kal kevesebb négyzetméterenként',
|
||||||
|
twinFootnote:
|
||||||
|
'Valós példa az adatainkból: a 2021 óta eladott lakások medián £/m² ára. Fedezd fel az élő térképet, hogy megtaláld a sajátodat.',
|
||||||
|
twinCta: 'Találj egy ehhez hasonló kincset a közelemben',
|
||||||
|
ctaTitle: 'Ne fizess túl egy névért.',
|
||||||
ctaDescription:
|
ctaDescription:
|
||||||
'Készíts listát olyan irányítószámokból, amelyek illenek a valós életedhez, majd nézd meg őket személyesen.',
|
'Állítsd össze a szűkített listád az élő térképen, ingyen. Amikor meggyőződtél róla, oldd fel az összes szűrőt egy életre. Fizess egyszer, előfizetés nélkül.',
|
||||||
|
guaranteeNote:
|
||||||
|
'Fizess egyszer. Soha semmilyen előfizetés. 30 napos pénzvisszafizetési garancia.',
|
||||||
},
|
},
|
||||||
|
|
||||||
// ── Pricing Page ───────────────────────────────────
|
// ── Pricing Page ───────────────────────────────────
|
||||||
|
|
@ -1143,12 +1170,15 @@ const hu: Translations = {
|
||||||
},
|
},
|
||||||
|
|
||||||
pricingPage: {
|
pricingPage: {
|
||||||
|
cachedNotice: 'Nem sikerült frissíteni az élő árakat, így ezek az adatok elavultak lehetnek.',
|
||||||
|
scrollPrev: 'Előző csomagok megjelenítése',
|
||||||
|
scrollNext: 'További csomagok megjelenítése',
|
||||||
title: 'Vásárolj jobb keresési területből kiindulva',
|
title: 'Vásárolj jobb keresési területből kiindulva',
|
||||||
subtitle:
|
subtitle:
|
||||||
'Élethosszig tartó hozzáférés a térképhez, amely segít eldönteni, hol érdemes keresni, mielőtt megtekintéseket foglalnál.',
|
'Élethosszig tartó hozzáférés a térképhez, amely segít eldönteni, hol érdemes keresni, mielőtt megtekintéseket foglalnál.',
|
||||||
costContext:
|
costContext:
|
||||||
'A vevők gyakran estéket töltenek hirdetések, ingázási ellenőrzések, iskolai jelentések, bűnözési térképek, Street View és eladási árak összeillesztésével. Londonban ez kimerítő, de ugyanez a kutatási probléma egész Angliában megjelenik. A Perfect Postcode egy térképre teszi a területkutatást, mielőtt a hétvégéidet, díjaidat és figyelmedet rászánnád.',
|
'A vevők gyakran estéket töltenek hirdetések, ingázási ellenőrzések, iskolai jelentések, bűnözési térképek, Street View és eladási árak összeillesztésével. Londonban ez kimerítő, de ugyanez a kutatási probléma egész Angliában megjelenik. A Perfect Postcode egy térképre teszi a területkutatást, mielőtt a hétvégéidet, díjaidat és figyelmedet rászánnád.',
|
||||||
lessThanSurvey: 'Egy műszaki felmérés árának töredékéért — egy sokkal nagyobb döntéshez.',
|
lessThanSurvey: 'Egy műszaki felmérés árának töredékéért, egy sokkal nagyobb döntéshez.',
|
||||||
currentTier: 'Jelenlegi szint',
|
currentTier: 'Jelenlegi szint',
|
||||||
firstNUsers: 'Első {{count}} felhasználó',
|
firstNUsers: 'Első {{count}} felhasználó',
|
||||||
everyoneAfter: 'Mindenki más utána',
|
everyoneAfter: 'Mindenki más utána',
|
||||||
|
|
@ -1159,7 +1189,7 @@ const hu: Translations = {
|
||||||
filled: 'Betelt',
|
filled: 'Betelt',
|
||||||
openDashboard: 'Térkép megnyitása',
|
openDashboard: 'Térkép megnyitása',
|
||||||
getStarted: 'Kezdjük el',
|
getStarted: 'Kezdjük el',
|
||||||
getStartedPrice: 'Kezdjük el – {{price}}',
|
getStartedPrice: 'Kezdjük el: {{price}}',
|
||||||
noCreditCard: 'Nem szükséges bankkártya',
|
noCreditCard: 'Nem szükséges bankkártya',
|
||||||
moneyBack: '14 napos pénzvisszafizetési garancia.',
|
moneyBack: '14 napos pénzvisszafizetési garancia.',
|
||||||
|
|
||||||
|
|
@ -1190,7 +1220,7 @@ const hu: Translations = {
|
||||||
videos: 'Videók',
|
videos: 'Videók',
|
||||||
videosTitle: 'Közösségimédia-videók',
|
videosTitle: 'Közösségimédia-videók',
|
||||||
videosIntro:
|
videosIntro:
|
||||||
'Rövid klipek a közösségi csatornáinkról – mindegyik egy-egy keresést mutat be működés közben, a csendes utcáktól az iskolai körzeteken át az utazási időkig.',
|
'Rövid klipek a közösségi csatornáinkról: mindegyik egy-egy keresést mutat be működés közben, a csendes utcáktól az iskolai körzeteken át az utazási időkig.',
|
||||||
video01Title: 'Találd meg az olcsóbb ikertestvért',
|
video01Title: 'Találd meg az olcsóbb ikertestvért',
|
||||||
video01Desc:
|
video01Desc:
|
||||||
'Írd le a teljes lakáskeresési igényedet egyetlen egyszerű mondatban, és nézd, ahogy Anglia minden illeszkedő irányítószáma ár-érték szerint rendeződik, felszínre hozva az olcsóbb ikertestvért, amit senki sem vert fel.',
|
'Írd le a teljes lakáskeresési igényedet egyetlen egyszerű mondatban, és nézd, ahogy Anglia minden illeszkedő irányítószáma ár-érték szerint rendeződik, felszínre hozva az olcsóbb ikertestvért, amit senki sem vert fel.',
|
||||||
|
|
@ -1199,7 +1229,7 @@ const hu: Translations = {
|
||||||
'Színezd Londont a központba tartó ingázás szerint, szűkítsd 20 perces útra, és nézd, ahogy az azonos utak kettéválnak a mindenki által ismert nevekre és a csendesebb irányítószámokra, amelyeket senki sem vert fel.',
|
'Színezd Londont a központba tartó ingázás szerint, szűkítsd 20 perces útra, és nézd, ahogy az azonos utak kettéválnak a mindenki által ismert nevekre és a csendesebb irányítószámokra, amelyeket senki sem vert fel.',
|
||||||
video03Title: 'Az irányítószám bizonyítékaktája',
|
video03Title: 'Az irányítószám bizonyítékaktája',
|
||||||
video03Desc:
|
video03Desc:
|
||||||
'Koppints bármelyik irányítószámra, és megnyílik egy panel az eladási áraival, iskolai körzeteivel, bűnözéssel és Street View-val – így megállapíthatod, valódi értékért fizetsz-e, vagy csak egy hírnévért.',
|
'Koppints bármelyik irányítószámra, és megnyílik egy panel az eladási áraival, iskolai körzeteivel, bűnözéssel és Street View-val, így megállapíthatod, valódi értékért fizetsz-e, vagy csak egy hírnévért.',
|
||||||
video04Title: 'A figyelmen kívül hagyott csendes utca',
|
video04Title: 'A figyelmen kívül hagyott csendes utca',
|
||||||
video04Desc:
|
video04Desc:
|
||||||
'A híres irányítószámak beárazzák a hírnevüket, de egy hirdetésfotó néma a zajról. Szűrj decibel szerint, és találd meg az igazán csendes utcát egy sarokkal arrébb, amit senki sem vert fel.',
|
'A híres irányítószámak beárazzák a hírnevüket, de egy hirdetésfotó néma a zajról. Szűrj decibel szerint, és találd meg az igazán csendes utcát egy sarokkal arrébb, amit senki sem vert fel.',
|
||||||
|
|
@ -1208,7 +1238,7 @@ const hu: Translations = {
|
||||||
'Egy leedsi család jó általános iskolát, alacsony bűnözést és £350k alatti költségvetést keres, és felszínre hozza a csendben olcsóbb utcákat, amelyek ugyanazt a körzetet osztják.',
|
'Egy leedsi család jó általános iskolát, alacsony bűnözést és £350k alatti költségvetést keres, és felszínre hozza a csendben olcsóbb utcákat, amelyek ugyanazt a körzetet osztják.',
|
||||||
video06Title: 'A Waitrose-hatás, beárazva',
|
video06Title: 'A Waitrose-hatás, beárazva',
|
||||||
video06Desc:
|
video06Desc:
|
||||||
'Sétatávolságra egy Waitrose-tól, egy metrómegállótól és egy parktól – ez egy beárazott felár; találd meg a közeli irányítószámokat ugyanazokkal a szolgáltatásokkal, négyzetméterenként olcsóbban.',
|
'Sétatávolságra egy Waitrose-tól, egy metrómegállótól és egy parktól: ez egy beárazott felár; találd meg a közeli irányítószámokat ugyanazokkal a szolgáltatásokkal, négyzetméterenként olcsóbban.',
|
||||||
video07Title: 'Ár-érték térkép bérlőknek',
|
video07Title: 'Ár-érték térkép bérlőknek',
|
||||||
video07Desc:
|
video07Desc:
|
||||||
'A neves irányítószámok bérelni is drágábbak. Add meg a bérleti díjat, az ingázást és egy csendes utcát, és lásd, mely londoni irányítószámok férnek tényleg a pénztárcádba.',
|
'A neves irányítószámok bérelni is drágábbak. Add meg a bérleti díjat, az ingázást és egy csendes utcát, és lásd, mely londoni irányítószámok férnek tényleg a pénztárcádba.',
|
||||||
|
|
@ -1321,7 +1351,7 @@ const hu: Translations = {
|
||||||
faqPricingTitle: 'Hozzáférés',
|
faqPricingTitle: 'Hozzáférés',
|
||||||
faqTipsTitle: 'Térképtippek',
|
faqTipsTitle: 'Térképtippek',
|
||||||
faqBehindDataTitle: 'A háttérben',
|
faqBehindDataTitle: 'A háttérben',
|
||||||
// FAQ items — Finding Your Area
|
// FAQ items: Finding Your Area
|
||||||
faqFinding1Q: 'Hol keressek, ha a nyilvánvaló környékek túl drágák?',
|
faqFinding1Q: 'Hol keressek, ha a nyilvánvaló környékek túl drágák?',
|
||||||
faqFinding1A:
|
faqFinding1A:
|
||||||
'Kezdd azokkal, amikből nem engedsz: költségvetés, otthontípus, alapterület, ingázás, iskolák, biztonság, zaj, internet, parkok és minden más fontos szempont. A térkép elrejti a nem illő helyeket, így kevésbé nyilvánvaló területek is előkerülhetnek a hirdetések böngészése előtt.',
|
'Kezdd azokkal, amikből nem engedsz: költségvetés, otthontípus, alapterület, ingázás, iskolák, biztonság, zaj, internet, parkok és minden más fontos szempont. A térkép elrejti a nem illő helyeket, így kevésbé nyilvánvaló területek is előkerülhetnek a hirdetések böngészése előtt.',
|
||||||
|
|
@ -1331,7 +1361,7 @@ const hu: Translations = {
|
||||||
faqFinding3Q: 'Mit tegyek, ha a keresés túl sok vagy túl kevés területet ad?',
|
faqFinding3Q: 'Mit tegyek, ha a keresés túl sok vagy túl kevés területet ad?',
|
||||||
faqFinding3A:
|
faqFinding3A:
|
||||||
'Tartsd meg a kötelező feltételeket, majd színezd a térképet egy összehasonlítandó dolog szerint, például négyzetméterár, közúti zaj, iskolai pontszám vagy utazási idő alapján. Ha szinte semmi sem marad, lazíts egy csúszkán, és lásd, melyik változtatás nyit új lehetőségeket.',
|
'Tartsd meg a kötelező feltételeket, majd színezd a térképet egy összehasonlítandó dolog szerint, például négyzetméterár, közúti zaj, iskolai pontszám vagy utazási idő alapján. Ha szinte semmi sem marad, lazíts egy csúszkán, és lásd, melyik változtatás nyit új lehetőségeket.',
|
||||||
// FAQ items — Commute and Travel
|
// FAQ items: Commute and Travel
|
||||||
faqCommute1Q: 'Hogyan számítjátok az utazási időket?',
|
faqCommute1Q: 'Hogyan számítjátok az utazási időket?',
|
||||||
faqCommute1A:
|
faqCommute1A:
|
||||||
'Az utazási időket minden mentett célhoz előre kiszámítjuk. Megnézzük, mely irányítószámok érhetik el az adott célt autóval, kerékpárral, gyalog vagy tömegközlekedéssel, majd eltároljuk az eredményeket, hogy a térkép gyorsan reagáljon szűrés közben.',
|
'Az utazási időket minden mentett célhoz előre kiszámítjuk. Megnézzük, mely irányítószámok érhetik el az adott célt autóval, kerékpárral, gyalog vagy tömegközlekedéssel, majd eltároljuk az eredményeket, hogy a térkép gyorsan reagáljon szűrés közben.',
|
||||||
|
|
@ -1341,28 +1371,28 @@ const hu: Translations = {
|
||||||
faqCommute3Q: 'Mikor használjam a Legjobb eset gombot?',
|
faqCommute3Q: 'Mikor használjam a Legjobb eset gombot?',
|
||||||
faqCommute3A:
|
faqCommute3A:
|
||||||
'A Legjobb eset gombot tömegközlekedésnél használd, ha azt szeretnéd látni, milyen az út jól időzített indulással és jó csatlakozásokkal. Hagyd kikapcsolva a hétköznapi összehasonlításhoz.',
|
'A Legjobb eset gombot tömegközlekedésnél használd, ha azt szeretnéd látni, milyen az út jól időzített indulással és jó csatlakozásokkal. Hagyd kikapcsolva a hétköznapi összehasonlításhoz.',
|
||||||
// FAQ items — Budget and Value
|
// FAQ items: Budget and Value
|
||||||
faqBudget1Q: 'Hogyan becsülitek a jelenlegi ingatlanárakat?',
|
faqBudget1Q: 'Hogyan becsülitek a jelenlegi ingatlanárakat?',
|
||||||
faqBudget1A:
|
faqBudget1A:
|
||||||
'A becslés a HM Land Registryben rögzített legutóbbi eladási árból indul. Ezt közelebb hozzuk a mai piachoz azzal, hogy megnézzük, hogyan változott hasonló otthonok értéke, különösen azonos típusú közeli otthonoké. Ha kevés a helyi eladás, a becslés nagyobb terület trendjeire támaszkodik. Végül összevetjük közeli friss eladásokkal és az alapterülettel.',
|
'A becslés a HM Land Registryben rögzített legutóbbi eladási árból indul. Ezt közelebb hozzuk a mai piachoz azzal, hogy megnézzük, hogyan változott hasonló otthonok értéke, különösen azonos típusú közeli otthonoké. Ha kevés a helyi eladás, a becslés nagyobb terület trendjeire támaszkodik. Végül összevetjük közeli friss eladásokkal és az alapterülettel.',
|
||||||
faqBudget2Q: 'Miért használjam a becsült jelenlegi árat a legutóbbi eladási ár helyett?',
|
faqBudget2Q: 'Miért használjam a becsült jelenlegi árat a legutóbbi eladási ár helyett?',
|
||||||
faqBudget2A:
|
faqBudget2A:
|
||||||
'A legutóbbi eladási ár akár évekkel vagy évtizedekkel korábbi lehet, az aktuális irányárak pedig csak a ma hirdetett otthonokat fedik le. A becsült jelenlegi ár a régebbi eladásokat közelebb hozza a mai piachoz, így több otthont hasonlíthatsz össze és jobb értékűnek tűnő területeket találhatsz. Előválogatáshoz való iránymutatás, nem banki értékbecslés.',
|
'A legutóbbi eladási ár akár évekkel vagy évtizedekkel korábbi lehet, az aktuális irányárak pedig csak a ma hirdetett otthonokat fedik le. A becsült jelenlegi ár a régebbi eladásokat közelebb hozza a mai piachoz, így több otthont hasonlíthatsz össze és jobb értékűnek tűnő területeket találhatsz. Előválogatáshoz való iránymutatás, nem banki értékbecslés.',
|
||||||
// FAQ items — Safety and Neighbourhood
|
// FAQ items: Safety and Neighbourhood
|
||||||
faqSafety1Q: 'Milyen bűncselekmények gyakoriak az irányítószám környékén?',
|
faqSafety1Q: 'Milyen bűncselekmények gyakoriak az irányítószám környékén?',
|
||||||
faqSafety1A:
|
faqSafety1A:
|
||||||
'A rendőrségi bűnözési adatok típusokra vannak bontva, például erőszak, betörés, rablás, járművel kapcsolatos bűncselekmények, közösségellenes magatartás, bolti lopás, kábítószer és közrend. Szűrhetsz a számodra fontos konkrét kockázatokra egy homályos biztonsági pontszám helyett.',
|
'A rendőrségi bűnözési adatok típusokra vannak bontva, például erőszak, betörés, rablás, járművel kapcsolatos bűncselekmények, közösségellenes magatartás, bolti lopás, kábítószer és közrend. Szűrhetsz a számodra fontos konkrét kockázatokra egy homályos biztonsági pontszám helyett.',
|
||||||
faqSafety2Q: 'Mit ellenőrizzek egy ismeretlen utca megtekintése előtt?',
|
faqSafety2Q: 'Mit ellenőrizzek egy ismeretlen utca megtekintése előtt?',
|
||||||
faqSafety2A:
|
faqSafety2A:
|
||||||
'Foglalás előtt ellenőrizd a bűnözést, közúti zajt, internetet, parkokat, élelmiszerboltokat, iskolákat és ingázást. A hirdetési fotók hasznosak lehetnek, de ne azokból derüljön ki először, milyen az utca.',
|
'Foglalás előtt ellenőrizd a bűnözést, közúti zajt, internetet, parkokat, élelmiszerboltokat, iskolákat és ingázást. A hirdetési fotók hasznosak lehetnek, de ne azokból derüljön ki először, milyen az utca.',
|
||||||
// FAQ items — Families and Schools
|
// FAQ items: Families and Schools
|
||||||
faqFamilies1Q: 'Mely területeken jó az iskolák, tér, biztonság és ingázás keveréke?',
|
faqFamilies1Q: 'Mely területeken jó az iskolák, tér, biztonság és ingázás keveréke?',
|
||||||
faqFamilies1A:
|
faqFamilies1A:
|
||||||
'Tedd egy térképre az iskolaminősítéseket, bűnözést, parkokat, ingázást, alapterületet, otthontípust és költségvetést. Az eredmény gyakorlati családi szűkített lista, nem sok külön keresés halmaza.',
|
'Tedd egy térképre az iskolaminősítéseket, bűnözést, parkokat, ingázást, alapterületet, otthontípust és költségvetést. Az eredmény gyakorlati családi szűkített lista, nem sok külön keresés halmaza.',
|
||||||
faqFamilies2Q: 'Ez bizonyítja, hogy iskolai körzeten belül vagyok?',
|
faqFamilies2Q: 'Ez bizonyítja, hogy iskolai körzeten belül vagyok?',
|
||||||
faqFamilies2A:
|
faqFamilies2A:
|
||||||
'Nem. Közeli iskolaminőséget és helyi oktatási információkat mutatunk, de a felvételi körzetek és elsőbbségi szabályok változhatnak. A Perfect Postcode-dal válogass helyeket, majd ellenőrizd a körzeteket és a felvételi szabályokat az iskolánál vagy a helyi önkormányzatnál.',
|
'Nem. Közeli iskolaminőséget és helyi oktatási információkat mutatunk, de a felvételi körzetek és elsőbbségi szabályok változhatnak. A Perfect Postcode-dal válogass helyeket, majd ellenőrizd a körzeteket és a felvételi szabályokat az iskolánál vagy a helyi önkormányzatnál.',
|
||||||
// FAQ items — Environment and Quality of Life
|
// FAQ items: Environment and Quality of Life
|
||||||
faqEnv1Q:
|
faqEnv1Q:
|
||||||
'Hogyan kerülhetek el zajos utat az ingázás vagy internet minőségének elvesztése nélkül?',
|
'Hogyan kerülhetek el zajos utat az ingázás vagy internet minőségének elvesztése nélkül?',
|
||||||
faqEnv1A:
|
faqEnv1A:
|
||||||
|
|
@ -1373,7 +1403,7 @@ const hu: Translations = {
|
||||||
faqEnv3Q: 'Milyen fenntartási költségeket ellenőrizhetek megtekintés előtt?',
|
faqEnv3Q: 'Milyen fenntartási költségeket ellenőrizhetek megtekintés előtt?',
|
||||||
faqEnv3A:
|
faqEnv3A:
|
||||||
'Megtekintés előtt ellenőrizhetsz energiaértékelést, alapterületet, építési kort, önkormányzati adót, internetet és zajt. Ez nem jósolja meg a pontos számláidat, de segít korán elkerülni a nyilvánvalóan rossz illeszkedéseket.',
|
'Megtekintés előtt ellenőrizhetsz energiaértékelést, alapterületet, építési kort, önkormányzati adót, internetet és zajt. Ez nem jósolja meg a pontos számláidat, de segít korán elkerülni a nyilvánvalóan rossz illeszkedéseket.',
|
||||||
// FAQ items — Listing Portals and Due Diligence
|
// FAQ items: Listing Portals and Due Diligence
|
||||||
faqDueDiligence1Q: 'Rightmove előtt vagy után használjam?',
|
faqDueDiligence1Q: 'Rightmove előtt vagy után használjam?',
|
||||||
faqDueDiligence1A:
|
faqDueDiligence1A:
|
||||||
'Használd a Perfect Postcode-ot a hirdetési oldalak előtt és mellett. A Rightmove, Zoopla és OnTheMarket továbbra is az aktuálisan eladó otthonok, fotók, ingatlanközvetítők, megtekintések és értesítések helye. A Perfect Postcode abban segít, hogy mely irányítószámokat érdemes keresni.',
|
'Használd a Perfect Postcode-ot a hirdetési oldalak előtt és mellett. A Rightmove, Zoopla és OnTheMarket továbbra is az aktuálisan eladó otthonok, fotók, ingatlanközvetítők, megtekintések és értesítések helye. A Perfect Postcode abban segít, hogy mely irányítószámokat érdemes keresni.',
|
||||||
|
|
@ -1387,11 +1417,11 @@ const hu: Translations = {
|
||||||
faqDueDiligence4Q: 'Mit kell még ellenőriznem ajánlattétel előtt?',
|
faqDueDiligence4Q: 'Mit kell még ellenőriznem ajánlattétel előtt?',
|
||||||
faqDueDiligence4A:
|
faqDueDiligence4A:
|
||||||
'A Perfect Postcode-dal ellenőrizd a környéket és a valószínű értéket, majd ajánlattétel előtt erősítsd meg a hirdetés részleteit. Ellenőrizd a tulajdonformát, a bérleti jog részleteit, a szolgáltatási díjakat, a tervezési előzményeket, az árvízkockázatot, a jogi kérdéseket, a hitelfeltételeket és a műszaki felmérési eredményeket is.',
|
'A Perfect Postcode-dal ellenőrizd a környéket és a valószínű értéket, majd ajánlattétel előtt erősítsd meg a hirdetés részleteit. Ellenőrizd a tulajdonformát, a bérleti jog részleteit, a szolgáltatási díjakat, a tervezési előzményeket, az árvízkockázatot, a jogi kérdéseket, a hitelfeltételeket és a műszaki felmérési eredményeket is.',
|
||||||
// FAQ items — Privacy and Data Protection
|
// FAQ items: Privacy and Data Protection
|
||||||
faqPrivacy1Q: 'Tároltok rólam személyes adatokat?',
|
faqPrivacy1Q: 'Tároltok rólam személyes adatokat?',
|
||||||
faqPrivacy1A:
|
faqPrivacy1A:
|
||||||
'Az ingatlan- és környékinformációk nem tartalmazzák a személyes adataidat. Ha fiókot hozol létre, csak a szolgáltatáshoz szükséges adatokat tároljuk, például e-mail címet, hozzáférési állapotot, hírlevél-választást, mentett kereséseket, megosztott hivatkozásokat és a Stripe által kezelt fizetési nyilvántartásokat. A fiókadatokat az Egyesült Királyság adatvédelmi törvényei szerint kezeljük.',
|
'Az ingatlan- és környékinformációk nem tartalmazzák a személyes adataidat. Ha fiókot hozol létre, csak a szolgáltatáshoz szükséges adatokat tároljuk, például e-mail címet, hozzáférési állapotot, hírlevél-választást, mentett kereséseket, megosztott hivatkozásokat és a Stripe által kezelt fizetési nyilvántartásokat. A fiókadatokat az Egyesült Királyság adatvédelmi törvényei szerint kezeljük.',
|
||||||
// FAQ items — Why Perfect Postcode
|
// FAQ items: Why Perfect Postcode
|
||||||
faqWhy1Q: 'Mit mutat ez, amit a hirdetési portálok általában nem?',
|
faqWhy1Q: 'Mit mutat ez, amit a hirdetési portálok általában nem?',
|
||||||
faqWhy1A:
|
faqWhy1A:
|
||||||
'A hirdetési oldalak a most eladó otthonokból indulnak ki. A Perfect Postcode azokból a helyekből indul, amelyek illenek az életedhez és költségvetésedhez, eladási árakkal, alapterülettel, ingázással, iskolákkal, bűnözéssel, zajjal, internettel, energiaértékeléssel, tulajdonformával és szolgáltatásokkal, még a hirdetések megnyitása előtt.',
|
'A hirdetési oldalak a most eladó otthonokból indulnak ki. A Perfect Postcode azokból a helyekből indul, amelyek illenek az életedhez és költségvetésedhez, eladási árakkal, alapterülettel, ingázással, iskolákkal, bűnözéssel, zajjal, internettel, energiaértékeléssel, tulajdonformával és szolgáltatásokkal, még a hirdetések megnyitása előtt.',
|
||||||
|
|
@ -1401,7 +1431,7 @@ const hu: Translations = {
|
||||||
faqWhy3Q: 'Mennyire megbízhatóak az adatok?',
|
faqWhy3Q: 'Mennyire megbízhatóak az adatok?',
|
||||||
faqWhy3A:
|
faqWhy3A:
|
||||||
'A fő források hivatalos vagy széles körben használt nyilvános adatok: eladási árak, energiaértékelések, helyi tények, iskolaminősítések, internet, bűnözés, környezet, térképek és utcai adatok. Hasznosak előválogatáshoz és összehasonlításhoz, de minden vásárlási döntéshez aktuális ellenőrzések és szükség esetén szakértői tanács kell.',
|
'A fő források hivatalos vagy széles körben használt nyilvános adatok: eladási árak, energiaértékelések, helyi tények, iskolaminősítések, internet, bűnözés, környezet, térképek és utcai adatok. Hasznosak előválogatáshoz és összehasonlításhoz, de minden vásárlási döntéshez aktuális ellenőrzések és szükség esetén szakértői tanács kell.',
|
||||||
// FAQ items — Pricing and Access
|
// FAQ items: Pricing and Access
|
||||||
faqPricing1Q: 'Miért fizessek, ha vannak ingyenes irányítószám-jelentések?',
|
faqPricing1Q: 'Miért fizessek, ha vannak ingyenes irányítószám-jelentések?',
|
||||||
faqPricing1A:
|
faqPricing1A:
|
||||||
'Az ingyenes irányítószám-eszközök hasznosak, ha már tudod, mit kell ellenőrizni. A Perfect Postcode arra való, hogy Anglia minden irányítószámát végignézd az igényeid alapján, szűrőket kombinálj, lehetőségeket hasonlíts össze, kereséseket ments és szűkített listát exportálj, mielőtt hétvégéket kötnél le megtekintésekre.',
|
'Az ingyenes irányítószám-eszközök hasznosak, ha már tudod, mit kell ellenőrizni. A Perfect Postcode arra való, hogy Anglia minden irányítószámát végignézd az igényeid alapján, szűrőket kombinálj, lehetőségeket hasonlíts össze, kereséseket ments és szűkített listát exportálj, mielőtt hétvégéket kötnél le megtekintésekre.',
|
||||||
|
|
@ -1410,9 +1440,9 @@ const hu: Translations = {
|
||||||
'Az élethosszig tartó hozzáférés azt jelenti, hogy egy fizetéssel a fiókod folyamatos hozzáférést kap a fizetős Perfect Postcode térképhez a szolgáltatás élettartamára. Ez nem havi vagy éves előfizetés, és a szokásos adatfrissítések benne vannak. Használhatod a mostani kereséshez, később visszatérhetsz, és akkor is hozzáférsz, ha újra költözöl.',
|
'Az élethosszig tartó hozzáférés azt jelenti, hogy egy fizetéssel a fiókod folyamatos hozzáférést kap a fizetős Perfect Postcode térképhez a szolgáltatás élettartamára. Ez nem havi vagy éves előfizetés, és a szokásos adatfrissítések benne vannak. Használhatod a mostani kereséshez, később visszatérhetsz, és akkor is hozzáférsz, ha újra költözöl.',
|
||||||
faqPricing3Q: 'Mit érhetek el az ingyenes szinten?',
|
faqPricing3Q: 'Mit érhetek el az ingyenes szinten?',
|
||||||
faqPricing3A:
|
faqPricing3A:
|
||||||
'Az ingyenes felhasználók a teljes Perfect Postcode térképet megkapják egész Angliában — minden irányítószámot és minden funkciót —, és egyszerre legfeljebb 3 szűrőt alkalmazhatnak. Az élethosszig tartó hozzáférés feloldja ezt a korlátot, így korlátlanul rétegezheted a szűrőket.',
|
'Az ingyenes felhasználók a teljes Perfect Postcode térképet megkapják egész Angliában (minden irányítószámot és minden funkciót), és egyszerre legfeljebb 3 szűrőt alkalmazhatnak. Az élethosszig tartó hozzáférés feloldja ezt a korlátot, így korlátlanul rétegezheted a szűrőket.',
|
||||||
|
|
||||||
// FAQ items — Tips and Tricks
|
// FAQ items: Tips and Tricks
|
||||||
faqTips1Q: 'Hogyan nézhetek meg egy szűrőt a térképen?',
|
faqTips1Q: 'Hogyan nézhetek meg egy szűrőt a térképen?',
|
||||||
faqTips1A:
|
faqTips1A:
|
||||||
'Kattints a Színezés gombra egy szűrő vagy jellemző mellett, hogy a térkép az adott elem alapján színeződjön. Az aktív szűrők megmaradnak, így gyorsan összehasonlíthatsz egy dolgot, például árat, ingázási időt, iskolákat, bűnözést vagy zajt a lista módosítása nélkül.',
|
'Kattints a Színezés gombra egy szűrő vagy jellemző mellett, hogy a térkép az adott elem alapján színeződjön. Az aktív szűrők megmaradnak, így gyorsan összehasonlíthatsz egy dolgot, például árat, ingázási időt, iskolákat, bűnözést vagy zajt a lista módosítása nélkül.',
|
||||||
|
|
@ -1423,20 +1453,20 @@ const hu: Translations = {
|
||||||
faqTips3A:
|
faqTips3A:
|
||||||
'Amikor egy jellemző színezi a térképet, a jelmagyarázatban a Színskála visszaállítása gombbal frissítheted az aktuálisan látott eredmények színeit. Ez hasznos térképmozgatás, nagyítás vagy szűrőmódosítás után.',
|
'Amikor egy jellemző színezi a térképet, a jelmagyarázatban a Színskála visszaállítása gombbal frissítheted az aktuálisan látott eredmények színeit. Ez hasznos térképmozgatás, nagyítás vagy szűrőmódosítás után.',
|
||||||
|
|
||||||
// FAQ items — Behind The Data
|
// FAQ items: Behind The Data
|
||||||
faqBehindData1Q: 'Miért tűnik egy repülőtér néha csendesebbnek, mint a körülötte lévő utcák?',
|
faqBehindData1Q: 'Miért tűnik egy repülőtér néha csendesebbnek, mint a körülötte lévő utcák?',
|
||||||
faqBehindData1A:
|
faqBehindData1A:
|
||||||
'Egy irányítószámhoz tartozó zajérték a Defra három forrásának (közút, vasút, repülő) közül a leghangosabb, 4 méter magasságban modellezve, 24 órás súlyozott átlagként (Lden). Egy forgalmas lakóutcán a közúti komponens dominál, jellemzően 65–75 dB. A repülőtér kerítésén belül nincsenek főutak, ezért a közúti tag leesik, és csak a repülőzaj átlaga marad. A London City repülőtér például éjszakai zárva tartással és korlátozott forgalommal üzemel, így a 24 órás repülő-átlag mérsékelt (a futópálya mellett kb. 60–66 dB), a repülőtér belseje pedig csendesebbnek látszik, mint a mellette húzódó főutak. Ugyanez figyelhető meg a Heathrow-nál is. Nem hiba, hanem a lakossági receptormagasságon mért közlekedési zaj természetes velejárója.',
|
'Egy irányítószámhoz tartozó zajérték a Defra három forrásának (közút, vasút, repülő) közül a leghangosabb, 4 méter magasságban modellezve, 24 órás súlyozott átlagként (Lden). Egy forgalmas lakóutcán a közúti komponens dominál, jellemzően 65–75 dB. A repülőtér kerítésén belül nincsenek főutak, ezért a közúti tag leesik, és csak a repülőzaj átlaga marad. A London City repülőtér például éjszakai zárva tartással és korlátozott forgalommal üzemel, így a 24 órás repülő-átlag mérsékelt (a futópálya mellett kb. 60–66 dB), a repülőtér belseje pedig csendesebbnek látszik, mint a mellette húzódó főutak. Ugyanez figyelhető meg a Heathrow-nál is. Nem hiba, hanem a lakossági receptormagasságon mért közlekedési zaj természetes velejárója.',
|
||||||
faqBehindData2Q: 'Miért látszik a repülőtér, autópálya vagy park egyetlen nagy foltként?',
|
faqBehindData2Q: 'Miért látszik a repülőtér, autópálya vagy park egyetlen nagy foltként?',
|
||||||
faqBehindData2A:
|
faqBehindData2A:
|
||||||
'Az Egyesült Királyságban az irányítószámoknak hivatalosan nincs határa — a Royal Mail az irányítószámot kézbesítési címek listájaként definiálja, nem területként. A Perfect Postcode úgy állítja elő a poligonokat, hogy minden címhez hozzárendeli a körülötte lévő terület arányos részét. A címek nélküli helyeket (futópálya, autópálya, park, víztározó) a legközelebbi lakott irányítószám tölti ki. Ezért jelenik meg a repülőtér vagy nyílt terület gyakran egyetlen nagy poligonként, és az értéke a határain belül lévő néhány irányítószámból származik.',
|
'Az Egyesült Királyságban az irányítószámoknak hivatalosan nincs határa. A Royal Mail az irányítószámot kézbesítési címek listájaként definiálja, nem területként. A Perfect Postcode úgy állítja elő a poligonokat, hogy minden címhez hozzárendeli a körülötte lévő terület arányos részét. A címek nélküli helyeket (futópálya, autópálya, park, víztározó) a legközelebbi lakott irányítószám tölti ki. Ezért jelenik meg a repülőtér vagy nyílt terület gyakran egyetlen nagy poligonként, és az értéke a határain belül lévő néhány irányítószámból származik.',
|
||||||
faqBehindData3Q: 'Miért egyezik meg több közeli irányítószám bűnözési száma?',
|
faqBehindData3Q: 'Miért egyezik meg több közeli irányítószám bűnözési száma?',
|
||||||
faqBehindData3A:
|
faqBehindData3A:
|
||||||
'A rendőrségi utcaszintű bűnözési adatok LSOA-szinten kerülnek közzétételre — ezek kb. 1500 lakosú kis környékek. Az ugyanazon LSOA-ban lévő minden irányítószám ugyanazokat az éves számokat kapja, így egy csendes lakóutca és egy egy háztömbnyire lévő főutca azonos értékeket mutathat, ha ugyanazon az oldalon vannak a határnak. Az egy főre jutó ráta szokatlanul magasnak tűnhet kórházakat, egyetemi kampuszokat vagy ipari területeket lefedő irányítószámoknál, mert ott normál mennyiségű incidens történik, de papíron kevés a lakos.',
|
'A rendőrségi utcaszintű bűnözési adatok LSOA-szinten kerülnek közzétételre: ezek kb. 1500 lakosú kis környékek. Az ugyanazon LSOA-ban lévő minden irányítószám ugyanazokat az éves számokat kapja, így egy csendes lakóutca és egy egy háztömbnyire lévő főutca azonos értékeket mutathat, ha ugyanazon az oldalon vannak a határnak. Az egy főre jutó ráta szokatlanul magasnak tűnhet kórházakat, egyetemi kampuszokat vagy ipari területeket lefedő irányítószámoknál, mert ott normál mennyiségű incidens történik, de papíron kevés a lakos.',
|
||||||
faqBehindData4Q:
|
faqBehindData4Q:
|
||||||
'Mit jelent az „iskolai körzetek” száma — beiratkozhat a gyerekem ezekbe az iskolákba?',
|
'Mit jelent az „iskolai körzetek” száma? Beiratkozhat a gyerekem ezekbe az iskolákba?',
|
||||||
faqBehindData4A:
|
faqBehindData4A:
|
||||||
'Mindegyik szám azt mutatja, hány Jó vagy Kiváló minősítésű állami iskola modellezett történeti körzete fedi le az irányítószámot. Azt szimuláljuk, ahogyan az angol távolságalapú felvételi elosztja a helyeket: a gyerekek (2021-es népszámlálás) a közeli iskolákba jelentkeznek, mérlegelve a távolságot és az Ofsted-minősítést, a túljelentkezéses iskola pedig a legközelebbi jelentkezőket veszi fel, amíg meg nem telik — körzetének sugara az utolsóként felvett gyerek távolsága, pontosan az önkormányzatok által közzétett „utolsó felvett távolság”. A modellt több száz ilyen közzétett értékhez kalibráltuk. Azt becsüli, hol kapható életszerűen hely; nem hivatalos felvételi körzet. A vallási és szelektív felvételit, a testvérprioritást és az évenkénti határváltozásokat nem modellezzük, ezért a körzeteket és a felvételi szabályokat mindig egyeztesd az iskolával vagy az önkormányzattal, mielőtt döntést alapoznál rájuk.',
|
'Mindegyik szám azt mutatja, hány Jó vagy Kiváló minősítésű állami iskola modellezett történeti körzete fedi le az irányítószámot. Azt szimuláljuk, ahogyan az angol távolságalapú felvételi elosztja a helyeket: a gyerekek (2021-es népszámlálás) a közeli iskolákba jelentkeznek, mérlegelve a távolságot és az Ofsted-minősítést, a túljelentkezéses iskola pedig a legközelebbi jelentkezőket veszi fel, amíg meg nem telik: körzetének sugara az utolsóként felvett gyerek távolsága, pontosan az önkormányzatok által közzétett „utolsó felvett távolság”. A modellt több száz ilyen közzétett értékhez kalibráltuk. Azt becsüli, hol kapható életszerűen hely; nem hivatalos felvételi körzet. A vallási és szelektív felvételit, a testvérprioritást és az évenkénti határváltozásokat nem modellezzük, ezért a körzeteket és a felvételi szabályokat mindig egyeztesd az iskolával vagy az önkormányzattal, mielőtt döntést alapoznál rájuk.',
|
||||||
faqBehindData5Q: 'Miért mutat „Gigabit”-et egy irányítószám, ha nem minden otthon kapja?',
|
faqBehindData5Q: 'Miért mutat „Gigabit”-et egy irányítószám, ha nem minden otthon kapja?',
|
||||||
faqBehindData5A:
|
faqBehindData5A:
|
||||||
'Az Ofcom Connected Nations szélessáv-lefedettsége irányítószámonként az egyes sebességszinteket elérni képes ingatlanok százalékát adja meg. Mi a legmagasabb elérhető szintet jelenítjük meg, így ha akár egyetlen otthon eléri a gigabites sebességet, az irányítószám „Gigabit elérhető”-ként jelenik meg. Ez jól válaszol arra, hogy „van-e egyáltalán optikai internet ezen az utcán?”, de nem garantálja, hogy a tömbben minden lakásba megrendelhető. Mindig ellenőrizd a szolgáltatóknál a saját címedre vonatkozóan, mielőtt szerződnél.',
|
'Az Ofcom Connected Nations szélessáv-lefedettsége irányítószámonként az egyes sebességszinteket elérni képes ingatlanok százalékát adja meg. Mi a legmagasabb elérhető szintet jelenítjük meg, így ha akár egyetlen otthon eléri a gigabites sebességet, az irányítószám „Gigabit elérhető”-ként jelenik meg. Ez jól válaszol arra, hogy „van-e egyáltalán optikai internet ezen az utcán?”, de nem garantálja, hogy a tömbben minden lakásba megrendelhető. Mindig ellenőrizd a szolgáltatóknál a saját címedre vonatkozóan, mielőtt szerződnél.',
|
||||||
|
|
@ -1505,6 +1535,7 @@ const hu: Translations = {
|
||||||
|
|
||||||
// ── Invite Page ────────────────────────────────────
|
// ── Invite Page ────────────────────────────────────
|
||||||
invitePage: {
|
invitePage: {
|
||||||
|
couldNotValidateTitle: 'Nem sikerült érvényesíteni a meghívót',
|
||||||
youreInvited: 'Meghívást kaptál!',
|
youreInvited: 'Meghívást kaptál!',
|
||||||
specialOffer: 'Különleges ajánlat!',
|
specialOffer: 'Különleges ajánlat!',
|
||||||
invitedByFree: '{{name}} meghívott, hogy ingyenes élethosszig tartó hozzáférést kapj.',
|
invitedByFree: '{{name}} meghívott, hogy ingyenes élethosszig tartó hozzáférést kapj.',
|
||||||
|
|
@ -1570,17 +1601,17 @@ const hu: Translations = {
|
||||||
treesOutsideWoodlands: {
|
treesOutsideWoodlands: {
|
||||||
label: 'Fák és erdő',
|
label: 'Fák és erdő',
|
||||||
detail:
|
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.',
|
'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: {
|
propertyBorders: {
|
||||||
label: 'Telekhatárok',
|
label: 'Telekhatárok',
|
||||||
detail:
|
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 85–90%-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.',
|
'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 85–90%-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: {
|
newDevelopments: {
|
||||||
label: 'Új fejlesztések',
|
label: 'Új fejlesztések',
|
||||||
detail:
|
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.',
|
'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.',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
@ -1729,7 +1760,7 @@ const hu: Translations = {
|
||||||
'Housing Conditions Score': 'Lakáskörülmények pontszám',
|
'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',
|
'Air Quality and Road Safety Score': 'Levegőminőség és közlekedésbiztonság pontszám',
|
||||||
|
|
||||||
// ─ Feature names (Crime) — népességre normált ráta, 7 év és 2 év ─
|
// ─ 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, 7y)': 'Súlyos bűncselekmény (évente, 7 év)',
|
||||||
'Serious crime (/yr, 2y)': 'Súlyos bűncselekmény (évente, 2 é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, 7y)': 'Kisebb bűncselekmény (évente, 7 év)',
|
||||||
|
|
@ -1790,6 +1821,8 @@ const hu: Translations = {
|
||||||
'% Owner occupied': '% Saját tulajdonú lakás',
|
'% Owner occupied': '% Saját tulajdonú lakás',
|
||||||
'% Social rent': '% Szociális bérlakás',
|
'% Social rent': '% Szociális bérlakás',
|
||||||
'% Private rent': '% Magánbérlemény',
|
'% Private rent': '% Magánbérlemény',
|
||||||
|
'% Council housing': '% Önkormányzati lakás',
|
||||||
|
'% Ex-council': '% Korábbi önkormányzati',
|
||||||
'% White': '% fehér',
|
'% White': '% fehér',
|
||||||
'% South Asian': '% dél-ázsiai',
|
'% South Asian': '% dél-ázsiai',
|
||||||
'% Black': '% fekete',
|
'% Black': '% fekete',
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ const zh: Translations = {
|
||||||
},
|
},
|
||||||
// ── Common ──────────────────────────────────────────
|
// ── Common ──────────────────────────────────────────
|
||||||
common: {
|
common: {
|
||||||
|
retry: '重试',
|
||||||
save: '保存',
|
save: '保存',
|
||||||
update: '更新',
|
update: '更新',
|
||||||
cancel: '取消',
|
cancel: '取消',
|
||||||
|
|
@ -101,6 +102,7 @@ const zh: Translations = {
|
||||||
|
|
||||||
// ── User Menu ──────────────────────────────────────
|
// ── User Menu ──────────────────────────────────────
|
||||||
userMenu: {
|
userMenu: {
|
||||||
|
accountMenu: '账户菜单',
|
||||||
fullAccess: '完整权限',
|
fullAccess: '完整权限',
|
||||||
demo: '演示版',
|
demo: '演示版',
|
||||||
themeLight: '主题:浅色',
|
themeLight: '主题:浅色',
|
||||||
|
|
@ -309,7 +311,7 @@ const zh: Translations = {
|
||||||
'学校数据能指出有潜力的区域,但招生规则和招生范围都可能调整。请直接向学校和地方政府核实当前安排。',
|
'学校数据能指出有潜力的区域,但招生规则和招生范围都可能调整。请直接向学校和地方政府核实当前安排。',
|
||||||
'School quality is one part of the shortlist': '学校只是候选名单中的一环',
|
'School quality is one part of the shortlist': '学校只是候选名单中的一环',
|
||||||
'Perfect Postcode helps you compare nearby school data with the other practical constraints that shape a family move: space, price, commute, parks, safety, and local services.':
|
'Perfect Postcode helps you compare nearby school data with the other practical constraints that shape a family move: space, price, commute, parks, safety, and local services.':
|
||||||
'Perfect Postcode 把附近学校数据与影响家庭搬家的其他硬条件——空间、价格、通勤、公园、治安、本地服务——放在一起比较。',
|
'Perfect Postcode 把附近学校数据与影响家庭搬家的其他硬条件(空间、价格、通勤、公园、治安、本地服务)放在一起比较。',
|
||||||
'Check catchments before making decisions': '做决定前先查清招生范围',
|
'Check catchments before making decisions': '做决定前先查清招生范围',
|
||||||
'Admissions rules and catchment boundaries can change. Use postcode-level school data to find promising areas, then verify current admissions details with the school or local authority.':
|
'Admissions rules and catchment boundaries can change. Use postcode-level school data to find promising areas, then verify current admissions details with the school or local authority.':
|
||||||
'招生规则和招生范围边界都可能调整。先用邮编层级的学校数据锁定有潜力的区域,再向学校或地方政府核实最新招生细节。',
|
'招生规则和招生范围边界都可能调整。先用邮编层级的学校数据锁定有潜力的区域,再向学校或地方政府核实最新招生细节。',
|
||||||
|
|
@ -383,7 +385,7 @@ const zh: Translations = {
|
||||||
'伯明翰一街之隔,情况可能就大不相同。在决定关注哪片房源之前,先用邮编层级的数据比较预算、通勤、学校、噪音、治安和本地服务。',
|
'伯明翰一街之隔,情况可能就大不相同。在决定关注哪片房源之前,先用邮编层级的数据比较预算、通勤、学校、噪音、治安和本地服务。',
|
||||||
'Start with commute corridors': '从通勤动线入手',
|
'Start with commute corridors': '从通勤动线入手',
|
||||||
'Choose the destination that matters, such as a workplace, station, university, or hospital, then compare reachable postcodes by transport mode and travel-time band.':
|
'Choose the destination that matters, such as a workplace, station, university, or hospital, then compare reachable postcodes by transport mode and travel-time band.':
|
||||||
'先锁定最重要的目的地——公司、车站、大学或医院——再按交通方式和出行时长档位比较可达的邮编。',
|
'先锁定最重要的目的地(公司、车站、大学或医院)再按交通方式和出行时长档位比较可达的邮编。',
|
||||||
'Use commute time as a hard filter before judging price.':
|
'Use commute time as a hard filter before judging price.':
|
||||||
'判断价格之前,先把出行时间当作硬性筛选条件。',
|
'判断价格之前,先把出行时间当作硬性筛选条件。',
|
||||||
'Compare public transport with car, cycling, or walking where available.':
|
'Compare public transport with car, cycling, or walking where available.':
|
||||||
|
|
@ -559,11 +561,20 @@ const zh: Translations = {
|
||||||
|
|
||||||
// ── Auth Modal ─────────────────────────────────────
|
// ── Auth Modal ─────────────────────────────────────
|
||||||
auth: {
|
auth: {
|
||||||
|
errorRateLimited: '尝试次数过多。请稍等一分钟后重试。',
|
||||||
|
errorNetwork: '无法连接服务器。请检查网络连接后重试。',
|
||||||
|
errorEmailTaken: '该电子邮箱已注册账户。',
|
||||||
|
errorPasswordWeak: '密码至少需要 8 个字符。',
|
||||||
|
errorEmailInvalid: '请输入有效的电子邮箱地址。',
|
||||||
|
errorInvalidCredentials: '电子邮箱或密码不正确。',
|
||||||
|
logInInstead: '改为登录',
|
||||||
|
accountCreatedPleaseLogIn: '账户已创建。请登录以继续。',
|
||||||
|
accountCreatedRateLimited: '账户已创建。刚才尝试次数过多。请稍候片刻后登录。',
|
||||||
logIn: '登录',
|
logIn: '登录',
|
||||||
createAccount: '注册账户',
|
createAccount: '注册账户',
|
||||||
resetPassword: '重置密码',
|
resetPassword: '重置密码',
|
||||||
valueProp: '保存搜索、收藏房产,并整理出符合您需求的候选区域。',
|
valueProp: '保存搜索、收藏房产,并整理出符合您需求的候选区域。',
|
||||||
dashboardActionsValueProp: '注册免费账户,保存、分享并导出您的搜索 — 免费,无需信用卡。',
|
dashboardActionsValueProp: '注册免费账户,保存、分享并导出您的搜索。免费,无需信用卡。',
|
||||||
continueWithGoogle: '使用 Google 账号继续',
|
continueWithGoogle: '使用 Google 账号继续',
|
||||||
email: '邮箱',
|
email: '邮箱',
|
||||||
emailPlaceholder: 'you@example.com',
|
emailPlaceholder: 'you@example.com',
|
||||||
|
|
@ -599,12 +610,12 @@ const zh: Translations = {
|
||||||
continueFree: '暂时继续浏览',
|
continueFree: '暂时继续浏览',
|
||||||
titleRegister: '注册免费账户',
|
titleRegister: '注册免费账户',
|
||||||
descriptionRegister:
|
descriptionRegister:
|
||||||
'免费账户解锁最多 5 个筛选条件,并支持保存、分享和导出 — 无需信用卡。想要在整个英格兰使用无限筛选?选择终身访问。',
|
'免费账户解锁最多 5 个筛选条件,并支持保存、分享和导出,无需信用卡。想要在整个英格兰使用无限筛选?选择终身访问。',
|
||||||
descriptionSharedRegister:
|
descriptionSharedRegister:
|
||||||
'这是一个分享的搜索。注册免费账户,可使用最多 5 个筛选条件,并保存、分享和导出 — 或选择终身访问以解锁无限筛选。',
|
'这是一个分享的搜索。注册免费账户,可使用最多 5 个筛选条件,并保存、分享和导出,或选择终身访问以解锁无限筛选。',
|
||||||
registerFree: '注册免费账户',
|
registerFree: '注册免费账户',
|
||||||
lifetimeUpsell: '想要无限筛选?',
|
lifetimeUpsell: '想要无限筛选?',
|
||||||
goLifetime: '获取终身访问权限 — {{price}}',
|
goLifetime: '获取终身访问权限:{{price}}',
|
||||||
checkoutFailed: '结账失败',
|
checkoutFailed: '结账失败',
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
@ -643,7 +654,7 @@ const zh: Translations = {
|
||||||
addFiltersHint: '添加以下筛选条件,将地图缩小到符合您要求的区域',
|
addFiltersHint: '添加以下筛选条件,将地图缩小到符合您要求的区域',
|
||||||
upgradePrompt: '选择终身访问,在英格兰每个邮编上叠加无限筛选条件。',
|
upgradePrompt: '选择终身访问,在英格兰每个邮编上叠加无限筛选条件。',
|
||||||
registerPrompt: '注册免费账户,可组合最多 5 个筛选条件,并保存、分享和导出您的搜索。',
|
registerPrompt: '注册免费账户,可组合最多 5 个筛选条件,并保存、分享和导出您的搜索。',
|
||||||
registerSubPrompt: '免费 — 无需信用卡。终身访问可解锁无限筛选。',
|
registerSubPrompt: '免费,无需信用卡。终身访问可解锁无限筛选。',
|
||||||
registerCta: '注册免费账户',
|
registerCta: '注册免费账户',
|
||||||
oneTimeLifetime: '一次性付款,终身访问。',
|
oneTimeLifetime: '一次性付款,终身访问。',
|
||||||
upgradeToFullMap: '升级到完整地图',
|
upgradeToFullMap: '升级到完整地图',
|
||||||
|
|
@ -683,6 +694,11 @@ const zh: Translations = {
|
||||||
crimeType: '犯罪类别',
|
crimeType: '犯罪类别',
|
||||||
qualificationLevel: '学历水平',
|
qualificationLevel: '学历水平',
|
||||||
tenureType: '住房产权类型',
|
tenureType: '住房产权类型',
|
||||||
|
councilType: '公共住房类型',
|
||||||
|
councilStatus: '类型',
|
||||||
|
councilCurrent: '当前',
|
||||||
|
councilEx: '前公共住房',
|
||||||
|
councilBoth: '两者',
|
||||||
crimeWindow: '统计周期',
|
crimeWindow: '统计周期',
|
||||||
crimeWindow7y: '7 年',
|
crimeWindow7y: '7 年',
|
||||||
crimeWindow2y: '2 年',
|
crimeWindow2y: '2 年',
|
||||||
|
|
@ -800,7 +816,14 @@ const zh: Translations = {
|
||||||
body: '当您浏览器的图形上下文被中断时,可能会出现这种情况。',
|
body: '当您浏览器的图形上下文被中断时,可能会出现这种情况。',
|
||||||
reload: '重新加载地图',
|
reload: '重新加载地图',
|
||||||
},
|
},
|
||||||
actualListings: { label: '房源', show: '显示实际房源', hide: '隐藏实际房源' },
|
actualListings: {
|
||||||
|
label: '房源',
|
||||||
|
modes: {
|
||||||
|
new: '新房',
|
||||||
|
nonNew: '二手房',
|
||||||
|
hint: '“新房”显示新建楼盘;“二手房”显示转售及其他房源。',
|
||||||
|
},
|
||||||
|
},
|
||||||
poi: { zoomInToSeeDetails: '放大以查看详情' },
|
poi: { zoomInToSeeDetails: '放大以查看详情' },
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
@ -826,6 +849,7 @@ const zh: Translations = {
|
||||||
historyTitle: '历史',
|
historyTitle: '历史',
|
||||||
historySale: '成交',
|
historySale: '成交',
|
||||||
historyBuilt: '建成',
|
historyBuilt: '建成',
|
||||||
|
historyNewBuild: '新建',
|
||||||
tenureOwnerOccupied: '自住',
|
tenureOwnerOccupied: '自住',
|
||||||
tenureRentedPrivate: '私人出租',
|
tenureRentedPrivate: '私人出租',
|
||||||
tenureRentedSocial: '社会租赁',
|
tenureRentedSocial: '社会租赁',
|
||||||
|
|
@ -937,27 +961,29 @@ const zh: Translations = {
|
||||||
|
|
||||||
// ── Home Page ──────────────────────────────────────
|
// ── Home Page ──────────────────────────────────────
|
||||||
home: {
|
home: {
|
||||||
heroEyebrow: '给正在问“到底该去哪儿找?”的买家',
|
heroEyebrow: '献给不愿为邮编名气多付钱的买家',
|
||||||
heroTitle1: '找到真正',
|
heroTitle1: '找到那个',
|
||||||
heroTitle2: '适合您生活的邮编',
|
heroTitle2: '被低估的宝藏邮编',
|
||||||
heroTitle3: '不只局限于您已经熟悉的区域。',
|
heroTitle3: '同样的学校、同样的通勤,却悄悄更便宜。',
|
||||||
heroSubtitle:
|
heroSubtitle:
|
||||||
'从伦敦街区,到通勤城镇,再到英格兰各地的城市——可看的地方太多,根本一个个筛不过来。',
|
'相邻两条街可能共用同一所学校、同一个车站、同一个建造年份,成交价却相差数万英镑。其中一个被定错了价,我们帮您找出是哪一个。',
|
||||||
heroDescription:
|
heroDescription:
|
||||||
'设好预算、通勤、学校、治安、噪音、宽带和生活方式要求。Perfect Postcode 会扫描英格兰每一个邮编,找出真正契合的地方,包括您原本不会在房源网站上搜索的区域。',
|
'设好预算和不可妥协的条件。Perfect Postcode 会按每一英镑实际能买到的东西(居住面积、学校、通勤和治安)为英格兰每个邮编排序,每个推荐背后都有数据支撑。',
|
||||||
exploreTheMap: '找到匹配的邮编',
|
exploreTheMap: '找到我的宝藏邮编',
|
||||||
seeTheDifference: '查看使用方式',
|
seeTheDifference: '看一个真实的宝藏案例',
|
||||||
|
freeToExplore: '免费探索实时地图,无需注册,无需银行卡。',
|
||||||
|
dataSourcesLabel: '基于官方公开记录',
|
||||||
|
dataSources: 'Land Registry · ONS · Ofsted · DfT · Ordnance Survey · Police.uk',
|
||||||
productDemoLabel: 'Perfect Postcode 产品演示',
|
productDemoLabel: 'Perfect Postcode 产品演示',
|
||||||
playProductDemo: '播放 Perfect Postcode 产品演示',
|
playProductDemo: '播放 Perfect Postcode 产品演示',
|
||||||
scrollToProductDemo: '滚动到产品演示',
|
scrollToProductDemo: '滚动到产品演示',
|
||||||
showcaseHeader: '工作原理',
|
showcaseContext: 'Perfect Postcode 的工作原理',
|
||||||
showcaseContext: 'Perfect Postcode 的工作流程',
|
|
||||||
showcaseFeaturePriceShort: '价格',
|
showcaseFeaturePriceShort: '价格',
|
||||||
showcaseFeatureNoiseShort: '噪音',
|
showcaseFeatureNoiseShort: '噪音',
|
||||||
showcaseFeatureSchoolsShort: '学校',
|
showcaseFeatureSchoolsShort: '学校',
|
||||||
showcaseFeatureTravelShort: '出行',
|
showcaseFeatureTravelShort: '出行',
|
||||||
showcaseGoodPrimariesNearby: '位于 {{count}}+ 个良好及以上小学学区内',
|
showcaseGoodPrimariesNearby: '位于 {{count}}+ 个优质小学学区内',
|
||||||
showcaseWithinRail: '到火车/地铁站 {{count}} 分钟内',
|
showcaseWithinRail: '距火车/地铁站 {{count}} 分钟内',
|
||||||
showcaseMatchingHomesLabel: '匹配房源',
|
showcaseMatchingHomesLabel: '匹配房源',
|
||||||
showcaseMatchingHomes: '{{value}} 套匹配房源',
|
showcaseMatchingHomes: '{{value}} 套匹配房源',
|
||||||
showcaseMedianPrice: '中位价 {{value}}',
|
showcaseMedianPrice: '中位价 {{value}}',
|
||||||
|
|
@ -970,83 +996,86 @@ const zh: Translations = {
|
||||||
showcaseSendShortlist: '发送候选名单',
|
showcaseSendShortlist: '发送候选名单',
|
||||||
showcaseDownloadXlsx: '下载 .xlsx',
|
showcaseDownloadXlsx: '下载 .xlsx',
|
||||||
showcaseTopThree: '前 3 名',
|
showcaseTopThree: '前 3 名',
|
||||||
showcaseScoutBullet1: '别等房源把选项缩小,先去街上走一走。',
|
showcaseScoutBullet1: '走一走那个胜过昂贵邻居的邮编的街道。',
|
||||||
showcaseScoutBullet2: '从真实门牌算通勤,而不是只看行政区名。',
|
showcaseScoutBullet2: '从真实门牌测试通勤,而不是只看行政区名。',
|
||||||
showcaseScoutBullet3: '带着已有证据去比较看房结果。',
|
showcaseScoutBullet3: '带着已有的数据去比较看房结果。',
|
||||||
showcaseStep1Tab: '筛选',
|
showcaseStep1Tab: '筛选',
|
||||||
showcaseStep1Title: '把模糊需求变成精准搜索',
|
showcaseStep1Title: '把模糊需求变成精准搜索',
|
||||||
showcaseStep1Body: '设好真正重要的条件,看清每加一个要求帮您剔除了多少不合适的邮编。',
|
showcaseStep1Body: '设好真正重要的条件,看清每个要求帮您从搜索中剔除了多少不合适的邮编。',
|
||||||
showcaseStep1Chip1: '安静街道',
|
|
||||||
showcaseStep1Chip2: '顶级小学',
|
|
||||||
showcaseStep1Chip3: '£500,000 以内',
|
|
||||||
showcaseStep1VennCenter: '同时满足三项条件的邮编',
|
|
||||||
showcaseStep2Tab: '匹配',
|
showcaseStep2Tab: '匹配',
|
||||||
showcaseStep2Title: '让地图找出您原本不会输入的地方',
|
showcaseStep2Title: '看着被低估的邮编逐一亮起',
|
||||||
showcaseStep2Body:
|
showcaseStep2Body:
|
||||||
'按匹配度扫描整个英格兰,不再从熟悉的地名出发。在房源网站收窄您的想象之前,先发现那些容易被忽略的好区域。',
|
'按性价比为整个英格兰排序,而不是从您已经熟悉的地名出发。那些被低估的地带(在每平方米价格、学校和通勤上都很出色)会浮到最前面。',
|
||||||
showcaseStep2Region: '大伦敦',
|
showcaseStep2Region: '大伦敦',
|
||||||
showcaseStep2Sources: 'Land Registry · ONS · Ofsted · DfT',
|
showcaseStep2Sources: 'Land Registry · ONS · Ofsted · DfT',
|
||||||
showcaseStep2ClustersLabel: '匹配集群',
|
|
||||||
showcaseStep3Tab: '查看',
|
showcaseStep3Tab: '查看',
|
||||||
showcaseStep3Title: '看清某个邮编为什么入选',
|
showcaseStep3Title: '看清某个邮编为什么入选',
|
||||||
showcaseStep3Body:
|
showcaseStep3Body:
|
||||||
'打开任意匹配区域,在同一个面板里看完价格、治安、学校、宽带和取舍,再决定是否花一个周末实地走一趟。',
|
'打开任意匹配区域,在同一个面板里看完价格、治安、学校、宽带和取舍,再决定是否花一个周末实地走一趟。',
|
||||||
showcaseStep3HeaderArea: '您的理想邮编',
|
showcaseStep3Stat2Label: '犯罪率',
|
||||||
showcaseStep3HeaderFit: '周边数据',
|
showcaseStep4Tab: '实地考察',
|
||||||
showcaseStep3Stat1Label: '成交价走势',
|
showcaseStep4Title: '亲自去实地考察',
|
||||||
showcaseStep3Stat2Label: '治安',
|
|
||||||
showcaseStep3Stat2Value: '低于本区平均水平',
|
|
||||||
showcaseStep3Stat3Label: '中位年龄',
|
|
||||||
showcaseStep3Stat4Label: '宽带',
|
|
||||||
showcaseStep3Stat4Value: '可用 1 Gbps',
|
|
||||||
showcaseStep3Stat5Label: '小学',
|
|
||||||
showcaseStep3Stat5Value: '1 英里内有 3 所“优秀”学校',
|
|
||||||
showcaseStep4Tab: '实地看',
|
|
||||||
showcaseStep4Title: '亲自去看一看',
|
|
||||||
showcaseStep4Body:
|
showcaseStep4Body:
|
||||||
'带上三个有数据支持的起点走进现实:实地走街、亲身试通勤,再带着背景资料比较看房结果。',
|
'带上排名前三的邮编走进现实:实地走街、亲身试通勤,再带着背景资料比较看房结果。',
|
||||||
showcaseStep4FileName: 'areas-to-scout.xlsx',
|
showcaseStep4FileName: 'areas-to-scout.xlsx',
|
||||||
showcaseStep4ExportLabel: '导出到 Excel',
|
|
||||||
showcaseStep4ColPostcode: '邮编',
|
showcaseStep4ColPostcode: '邮编',
|
||||||
showcaseStep4ColScore: '匹配',
|
showcaseStep4ColScore: '匹配度',
|
||||||
showcaseStep4ColCommute: '通勤',
|
showcaseStep4ColCommute: '通勤',
|
||||||
showcaseStep4ColPrice: '成交中位价',
|
showcaseStep4ColPrice: '£/sqm',
|
||||||
showcaseStep4Conclusion: '您可以从这里开始。',
|
showcaseStep4Conclusion: '从这里开始实地考察。',
|
||||||
statProperties: '历史成交记录',
|
statProperties: '历史成交记录',
|
||||||
statFilters: '可组合筛选条件',
|
statFilters: '可组合筛选条件',
|
||||||
statEvery: '覆盖',
|
statEvery: '每一个',
|
||||||
statPostcodeInEngland: '英格兰每个邮编',
|
statPostcodeInEngland: '英格兰的邮编',
|
||||||
coverageNote: '覆盖英格兰所有邮编——每个邮编 200 多个数据字段。苏格兰和威尔士已在计划中。',
|
coverageNote: '覆盖英格兰所有邮编,每个邮编 200 多个数据字段。苏格兰和威尔士已在计划中。',
|
||||||
priceStrip: '终身使用权,当前价格 {{price}}——名额售出后价格将上调。',
|
priceStrip: '一次付费,终身使用。当前价格 {{price}},随着各档名额售罄而上调。',
|
||||||
priceStripSpots: '此价格仅剩 {{count}} 个名额。',
|
priceStripSpots: '此价格仅剩 {{count}} 个名额。',
|
||||||
priceStripSpotsPlural: '此价格仅剩 {{count}} 个名额。',
|
priceStripSpotsPlural: '此价格仅剩 {{count}} 个名额。',
|
||||||
priceStripCta: '查看价格',
|
priceStripCta: '查看价格',
|
||||||
ourPhilosophy: '先明确重要条件,再找到合适的邮编',
|
ourPhilosophy: '名气早已计入价格,价值却还没有。',
|
||||||
philosophyP1:
|
philosophyP1:
|
||||||
'大多数房源网站一上来就问:您想住哪儿?在伦敦尤其难答,英格兰其他地方也是一样。买家通常只能从几个熟悉的地方入手,再分别去查通勤、学校、治安、街景、宽带和成交价。',
|
'一个邮编的价格,一部分来自它的房子、学区和通勤,剩下的只是名声。买家会抬高那些他们听说过的邮编,于是后面那条路(在每一项影响价格的指标上都一模一样)却悄悄更便宜。靠人工找出这个差距,意味着要开十几个浏览器标签页:成交价、Ofsted、犯罪、噪音、室内面积。',
|
||||||
philosophyP2:
|
philosophyP2:
|
||||||
'Perfect Postcode 把搜索方向反了过来:告诉地图什么对您重要,它就会显示符合条件的邮编,并讲清楚为什么值得一看。先看数据,再去现场感受。',
|
'Perfect Postcode 替您完成所有交叉核对。把预算和不可妥协的条件告诉地图,它就会按真正影响价格的因素衡量英格兰每个邮编,把被低估的那些排在最前面。然后,您只管去实地走一走。',
|
||||||
streetTitle: '一街之隔,可能就大不一样',
|
streetTitle: '差距就藏在一街之隔',
|
||||||
streetIntro:
|
streetIntro:
|
||||||
'笼统的区域名容易掩盖关键差异:在车站哪一侧、道路噪音、学校组合、真实通勤时间,以及同类房产实际成交价。',
|
'笼统的区域名会掩盖实惠藏在哪里:车站更便宜的那一侧、更安静的那条路、同一个学校学区,以及几乎一模一样的房子每平方米究竟卖了多少钱。',
|
||||||
streetCard1Title: '发现您可能错过的区域',
|
streetCard1Title: '找到更便宜的孪生邮编',
|
||||||
streetCard1Body: '根据您的条件找出匹配的邮编,不再只凭熟悉的地名、朋友推荐或“潜力区域”的宣传。',
|
streetCard1Body:
|
||||||
streetCard2Title: '看房前先看清取舍',
|
'每个知名邮编都有一个更安静的邻居:同样的学区、同样的车站、同样年代的房子,却没有那份溢价,也没有所谓「潜力区」的加价。我们把两者并排摆出,让差距无可遁形。',
|
||||||
|
streetCard2Title: '看清您的钱实际能买到什么',
|
||||||
streetCard2Body:
|
streetCard2Body:
|
||||||
'把周末花在看房之前,先把价格、空间、通勤、治安、学校、宽带、噪音和能源评级一并对比。',
|
'居住面积、成交价、通勤、犯罪、学校、宽带、噪音和能源评级,全在同一个屏幕上,不必开八个标签页再加一张表格。在花掉一个周六之前,先想清楚哪个值得这个周六。',
|
||||||
othersVs: '与其他平台对比',
|
othersVs: '其他平台对比',
|
||||||
checkMyPostcode: '房源网站',
|
checkMyPostcode: '房源网站',
|
||||||
areaGuides: '邮编报告',
|
areaGuides: '邮编报告',
|
||||||
compSearchWithout: '不知道地名也能先发现区域',
|
compSearchWithout: '按您能得到什么排序,而不是按谁听说过它',
|
||||||
compSearchWithoutSub: '(先看需求,再定地点)',
|
compSearchWithoutSub: '(按需求挑更便宜的孪生邮编,而不是看名气)',
|
||||||
compAreaData: '邮编级的周边数据',
|
compAreaData: '邮编级的周边数据',
|
||||||
compAreaDataSub: '(治安、学校、噪音、宽带、周边设施)',
|
compAreaDataSub: '(犯罪、学校、噪音、宽带、周边设施)',
|
||||||
compPropertyData: '房产级的历史记录',
|
compPropertyData: '房产级的历史记录',
|
||||||
compPropertyDataSub: '(成交价、EPC、室内面积、估值)',
|
compPropertyDataSub: '(成交价、EPC、室内面积、估值)',
|
||||||
compFilters: '40+ 项联动筛选',
|
compFilters: '40+ 项联动筛选',
|
||||||
compFiltersSub: '(不必一次只查一个邮编或一套房源)',
|
compFiltersSub: '(不必一次只查一个邮编或一套房源)',
|
||||||
ctaTitle: '别再猜哪里值得买。',
|
compListings: '实时房源、照片和看房',
|
||||||
ctaDescription: '先按真实生活需求建好邮编候选名单,再去实地感受。',
|
compListingsSub: '(买某一套具体房子的日常环节)',
|
||||||
|
twinBadge: '真实案例',
|
||||||
|
twinTitle: '同样的生活,换个邮编更便宜',
|
||||||
|
twinIntro:
|
||||||
|
'伦敦北部两个相距 1.3 公里的邻居:都是公寓,小学学区相当,通勤同样约 30 分钟,每平方米价格却相差悬殊。',
|
||||||
|
twinPriceyLabel: '人人皆知的那个名字',
|
||||||
|
twinValueLabel: '它更安静的邻居',
|
||||||
|
twinPerSqm: '{{value}}/sqm',
|
||||||
|
twinSameSchool: '两者都位于评级为「优秀」的小学学区内',
|
||||||
|
twinSameCommute: '两者乘公共交通到伦敦市中心都约 30 分钟',
|
||||||
|
twinDelta: '每平方米便宜 {{percent}}',
|
||||||
|
twinFootnote:
|
||||||
|
'这是来自我们数据的真实案例:2021 年以来公寓成交的每平方米价格中位数。打开实时地图,找到属于您自己的那个。',
|
||||||
|
twinCta: '在我附近找到这样的宝藏',
|
||||||
|
ctaTitle: '别再为一个名字多花钱。',
|
||||||
|
ctaDescription:
|
||||||
|
'在实时地图上免费建立您的候选名单。当您确信无疑时,再终身解锁全部筛选条件,一次付费,无需订阅。',
|
||||||
|
guaranteeNote: '一次付费,永不订阅。30 天退款保证。',
|
||||||
},
|
},
|
||||||
|
|
||||||
// ── Pricing Page ───────────────────────────────────
|
// ── Pricing Page ───────────────────────────────────
|
||||||
|
|
@ -1072,6 +1101,9 @@ const zh: Translations = {
|
||||||
},
|
},
|
||||||
|
|
||||||
pricingPage: {
|
pricingPage: {
|
||||||
|
cachedNotice: '无法刷新实时价格,以下数据可能已过时。',
|
||||||
|
scrollPrev: '显示上一组方案',
|
||||||
|
scrollNext: '显示更多方案',
|
||||||
title: '用更靠谱的搜索范围去买房',
|
title: '用更靠谱的搜索范围去买房',
|
||||||
subtitle: '终身访问这张地图,预约看房前先弄清楚该去哪儿看。',
|
subtitle: '终身访问这张地图,预约看房前先弄清楚该去哪儿看。',
|
||||||
costContext:
|
costContext:
|
||||||
|
|
@ -1118,7 +1150,7 @@ const zh: Translations = {
|
||||||
videos: '视频',
|
videos: '视频',
|
||||||
videosTitle: '社交媒体视频',
|
videosTitle: '社交媒体视频',
|
||||||
videosIntro:
|
videosIntro:
|
||||||
'来自我们社交平台的短片——每一个都展示一次实际搜索,从安静街道到学校学区,再到通勤时间。',
|
'来自我们社交平台的短片:每一个都展示一次实际搜索,从安静街道到学校学区,再到通勤时间。',
|
||||||
video01Title: '找到更便宜的孪生邮编',
|
video01Title: '找到更便宜的孪生邮编',
|
||||||
video01Desc:
|
video01Desc:
|
||||||
'用一句平实的话写下你的全部购房需求,看着英格兰每个符合条件的邮编按性价比排序,浮现出那个无人抬价、更便宜的孪生邮编。',
|
'用一句平实的话写下你的全部购房需求,看着英格兰每个符合条件的邮编按性价比排序,浮现出那个无人抬价、更便宜的孪生邮编。',
|
||||||
|
|
@ -1127,7 +1159,7 @@ const zh: Translations = {
|
||||||
'按到市中心的通勤时间为伦敦着色,收窄到 20 分钟车程,看着相同的通勤路程被分成人人皆知的名字,和那些无人抬价、更安静的邮编。',
|
'按到市中心的通勤时间为伦敦着色,收窄到 20 分钟车程,看着相同的通勤路程被分成人人皆知的名字,和那些无人抬价、更安静的邮编。',
|
||||||
video03Title: '邮编证据档案',
|
video03Title: '邮编证据档案',
|
||||||
video03Desc:
|
video03Desc:
|
||||||
'点按任意邮编,便会打开一个面板,列出它的成交价、学校学区、犯罪和街景——让你看清自己付的是真正的价值,还是仅仅一个名声。',
|
'点按任意邮编,便会打开一个面板,列出它的成交价、学校学区、犯罪和街景,让你看清自己付的是真正的价值,还是仅仅一个名声。',
|
||||||
video04Title: '被忽视的安静街道',
|
video04Title: '被忽视的安静街道',
|
||||||
video04Desc:
|
video04Desc:
|
||||||
'知名邮编把名声计入了价格,但房源照片对噪音却只字不提。按分贝筛选,找到隔壁那条真正安静、无人抬价的街道。',
|
'知名邮编把名声计入了价格,但房源照片对噪音却只字不提。按分贝筛选,找到隔壁那条真正安静、无人抬价的街道。',
|
||||||
|
|
@ -1136,7 +1168,7 @@ const zh: Translations = {
|
||||||
'利兹的一家人寻找优质小学、低犯罪率以及 £350,000 以下的预算,便浮现出那些悄然更便宜、却共享同一学区的街道。',
|
'利兹的一家人寻找优质小学、低犯罪率以及 £350,000 以下的预算,便浮现出那些悄然更便宜、却共享同一学区的街道。',
|
||||||
video06Title: 'Waitrose 效应,已计入价格',
|
video06Title: 'Waitrose 效应,已计入价格',
|
||||||
video06Desc:
|
video06Desc:
|
||||||
'步行可达 Waitrose、地铁站和公园是一种已计入价格的溢价——找到附近拥有同样配套、每平方米却更便宜的邮编。',
|
'步行可达 Waitrose、地铁站和公园是一种已计入价格的溢价:找到附近拥有同样配套、每平方米却更便宜的邮编。',
|
||||||
video07Title: '为租房者准备的价值地图',
|
video07Title: '为租房者准备的价值地图',
|
||||||
video07Desc:
|
video07Desc:
|
||||||
'知名邮编租起来也更贵。设定你的租金、通勤和一条安静街道,看看伦敦哪些邮编真正符合预算。',
|
'知名邮编租起来也更贵。设定你的租金、通勤和一条安静街道,看看伦敦哪些邮编真正符合预算。',
|
||||||
|
|
@ -1242,7 +1274,7 @@ const zh: Translations = {
|
||||||
faqPricingTitle: '访问权限',
|
faqPricingTitle: '访问权限',
|
||||||
faqTipsTitle: '使用技巧',
|
faqTipsTitle: '使用技巧',
|
||||||
faqBehindDataTitle: '数据背后',
|
faqBehindDataTitle: '数据背后',
|
||||||
// FAQ items — Finding Your Area
|
// FAQ items: Finding Your Area
|
||||||
faqFinding1Q: '明显的区域太贵时,我应该去哪里找?',
|
faqFinding1Q: '明显的区域太贵时,我应该去哪里找?',
|
||||||
faqFinding1A:
|
faqFinding1A:
|
||||||
'把预算、房屋类型、室内面积、通勤、学校、治安、噪音、宽带、公园这些硬条件都设好。地图会剔除不符合的邮编,让容易被忽略的区域在您逛房源前先浮现出来。',
|
'把预算、房屋类型、室内面积、通勤、学校、治安、噪音、宽带、公园这些硬条件都设好。地图会剔除不符合的邮编,让容易被忽略的区域在您逛房源前先浮现出来。',
|
||||||
|
|
@ -1252,7 +1284,7 @@ const zh: Translations = {
|
||||||
faqFinding3Q: '搜索结果过多或过少,该怎么办?',
|
faqFinding3Q: '搜索结果过多或过少,该怎么办?',
|
||||||
faqFinding3A:
|
faqFinding3A:
|
||||||
'硬条件先保留不动,再用一个想比较的维度给地图着色:每平方米单价、道路噪音、学校评分或通勤时间都行。如果结果太少,放宽其中一个滑块,看看哪个让步能带来最多选项。',
|
'硬条件先保留不动,再用一个想比较的维度给地图着色:每平方米单价、道路噪音、学校评分或通勤时间都行。如果结果太少,放宽其中一个滑块,看看哪个让步能带来最多选项。',
|
||||||
// FAQ items — Commute and Travel
|
// FAQ items: Commute and Travel
|
||||||
faqCommute1Q: '出行时间是如何计算的?',
|
faqCommute1Q: '出行时间是如何计算的?',
|
||||||
faqCommute1A:
|
faqCommute1A:
|
||||||
'我们会对每个已保存的目的地预先算好出行时间,判断哪些邮编能通过驾车、骑行、步行或公共交通到达,并把结果保存下来,让您筛选时地图能即时响应。',
|
'我们会对每个已保存的目的地预先算好出行时间,判断哪些邮编能通过驾车、骑行、步行或公共交通到达,并把结果保存下来,让您筛选时地图能即时响应。',
|
||||||
|
|
@ -1262,28 +1294,28 @@ const zh: Translations = {
|
||||||
faqCommute3Q: '什么时候用“最快情况”按钮?',
|
faqCommute3Q: '什么时候用“最快情况”按钮?',
|
||||||
faqCommute3A:
|
faqCommute3A:
|
||||||
'在公共交通模式下,若想查看出发时间合适、换乘也顺利时的通勤表现,就开启“最快情况”。日常比较时请保持关闭,因为默认设置更接近大多数日子的预期。',
|
'在公共交通模式下,若想查看出发时间合适、换乘也顺利时的通勤表现,就开启“最快情况”。日常比较时请保持关闭,因为默认设置更接近大多数日子的预期。',
|
||||||
// FAQ items — Budget and Value
|
// FAQ items: Budget and Value
|
||||||
faqBudget1Q: '你们如何估算当前房价?',
|
faqBudget1Q: '你们如何估算当前房价?',
|
||||||
faqBudget1A:
|
faqBudget1A:
|
||||||
'估算从 HM Land Registry 记录的最近成交价出发。我们会观察类似房屋的价值如何随时间变化,尤其是附近同类型房屋,再把这笔成交调整到接近今天的市场水平。当地成交较少时,会更多参考更大范围的走势;最后再结合附近近期成交和房屋面积做校验。',
|
'估算从 HM Land Registry 记录的最近成交价出发。我们会观察类似房屋的价值如何随时间变化,尤其是附近同类型房屋,再把这笔成交调整到接近今天的市场水平。当地成交较少时,会更多参考更大范围的走势;最后再结合附近近期成交和房屋面积做校验。',
|
||||||
faqBudget2Q: '为什么用估算当前价格,而不是最近成交价?',
|
faqBudget2Q: '为什么用估算当前价格,而不是最近成交价?',
|
||||||
faqBudget2A:
|
faqBudget2A:
|
||||||
'最近成交价可能是好几年甚至几十年前的价格,挂牌价又只覆盖当下在售的房源。估算当前价格把旧成交折算到接近今天的市场水平,可比较的房屋更多,也更容易发现潜在价值区域。请把它当作筛选参考,而非银行估值。',
|
'最近成交价可能是好几年甚至几十年前的价格,挂牌价又只覆盖当下在售的房源。估算当前价格把旧成交折算到接近今天的市场水平,可比较的房屋更多,也更容易发现潜在价值区域。请把它当作筛选参考,而非银行估值。',
|
||||||
// FAQ items — Safety and Neighbourhood
|
// FAQ items: Safety and Neighbourhood
|
||||||
faqSafety1Q: '这个邮编周边常见哪些犯罪类型?',
|
faqSafety1Q: '这个邮编周边常见哪些犯罪类型?',
|
||||||
faqSafety1A:
|
faqSafety1A:
|
||||||
'警方记录的犯罪按类型分项呈现:暴力、入室盗窃、抢劫、车辆犯罪、反社会行为、商店行窃、毒品、公共秩序等。您可以按自己关心的具体风险筛选,而不是只看一个笼统的治安分。',
|
'警方记录的犯罪按类型分项呈现:暴力、入室盗窃、抢劫、车辆犯罪、反社会行为、商店行窃、毒品、公共秩序等。您可以按自己关心的具体风险筛选,而不是只看一个笼统的治安分。',
|
||||||
faqSafety2Q: '看一条陌生街道之前,该先查什么?',
|
faqSafety2Q: '看一条陌生街道之前,该先查什么?',
|
||||||
faqSafety2A:
|
faqSafety2A:
|
||||||
'预约前先把治安、道路噪音、宽带、公园、食品店、学校和通勤查一遍。房源照片仍然有用,但不该成为您第一次了解这条街的方式。',
|
'预约前先把治安、道路噪音、宽带、公园、食品店、学校和通勤查一遍。房源照片仍然有用,但不该成为您第一次了解这条街的方式。',
|
||||||
// FAQ items — Families and Schools
|
// FAQ items: Families and Schools
|
||||||
faqFamilies1Q: '哪些区域在学校、空间、治安和通勤之间取得了合适平衡?',
|
faqFamilies1Q: '哪些区域在学校、空间、治安和通勤之间取得了合适平衡?',
|
||||||
faqFamilies1A:
|
faqFamilies1A:
|
||||||
'把学校评分、治安、公园、通勤、空间、房屋类型和预算汇到同一张地图上,结果就是一份实用的家庭候选名单,不必再东查一处、西查一处。',
|
'把学校评分、治安、公园、通勤、空间、房屋类型和预算汇到同一张地图上,结果就是一份实用的家庭候选名单,不必再东查一处、西查一处。',
|
||||||
faqFamilies2Q: '这能证明我在某所学校的招生范围里吗?',
|
faqFamilies2Q: '这能证明我在某所学校的招生范围里吗?',
|
||||||
faqFamilies2A:
|
faqFamilies2A:
|
||||||
'不能。我们呈现的是附近学校质量和本地教育情况,但招生边界和优先规则随时可能变。请先用 Perfect Postcode 圈定地点,再向学校或地方政府核实招生范围和录取规则。',
|
'不能。我们呈现的是附近学校质量和本地教育情况,但招生边界和优先规则随时可能变。请先用 Perfect Postcode 圈定地点,再向学校或地方政府核实招生范围和录取规则。',
|
||||||
// FAQ items — Environment and Quality of Life
|
// FAQ items: Environment and Quality of Life
|
||||||
faqEnv1Q: '如何避开嘈杂道路,同时不牺牲通勤或宽带质量?',
|
faqEnv1Q: '如何避开嘈杂道路,同时不牺牲通勤或宽带质量?',
|
||||||
faqEnv1A:
|
faqEnv1A:
|
||||||
'按道路噪音筛选的同时,把通勤、宽带、价格和房屋条件一并保留。再用其中一项给地图着色,其他筛选仍会保留,候选范围不会跑偏。',
|
'按道路噪音筛选的同时,把通勤、宽带、价格和房屋条件一并保留。再用其中一项给地图着色,其他筛选仍会保留,候选范围不会跑偏。',
|
||||||
|
|
@ -1293,7 +1325,7 @@ const zh: Translations = {
|
||||||
faqEnv3Q: '看房前能做哪些用房成本预估?',
|
faqEnv3Q: '看房前能做哪些用房成本预估?',
|
||||||
faqEnv3A:
|
faqEnv3A:
|
||||||
'看房前可以先看 EPC 评级、室内面积、建造年代、Council Tax 辖区、宽带和噪音。这没法预测您每月的具体账单,但能帮您尽早排除明显不合适的房子。',
|
'看房前可以先看 EPC 评级、室内面积、建造年代、Council Tax 辖区、宽带和噪音。这没法预测您每月的具体账单,但能帮您尽早排除明显不合适的房子。',
|
||||||
// FAQ items — Listing Portals and Due Diligence
|
// FAQ items: Listing Portals and Due Diligence
|
||||||
faqDueDiligence1Q: '应该在查看 Rightmove 前还是之后使用?',
|
faqDueDiligence1Q: '应该在查看 Rightmove 前还是之后使用?',
|
||||||
faqDueDiligence1A:
|
faqDueDiligence1A:
|
||||||
'Perfect Postcode 适合在打开房源网站之前以及同时使用。Rightmove、Zoopla、OnTheMarket 仍负责呈现当下在售的房源、照片、中介、预约和提醒;Perfect Postcode 则帮您先判断哪些邮编值得去搜。',
|
'Perfect Postcode 适合在打开房源网站之前以及同时使用。Rightmove、Zoopla、OnTheMarket 仍负责呈现当下在售的房源、照片、中介、预约和提醒;Perfect Postcode 则帮您先判断哪些邮编值得去搜。',
|
||||||
|
|
@ -1306,11 +1338,11 @@ const zh: Translations = {
|
||||||
faqDueDiligence4Q: '出价前还要核实哪些事?',
|
faqDueDiligence4Q: '出价前还要核实哪些事?',
|
||||||
faqDueDiligence4A:
|
faqDueDiligence4A:
|
||||||
'可以先用 Perfect Postcode 把区域和大致价值过一遍,再在出价前核对房源细节。此外还应核实产权类型、租赁条款、服务费、规划历史、洪水风险、法律问题、贷款要求和验房结果。',
|
'可以先用 Perfect Postcode 把区域和大致价值过一遍,再在出价前核对房源细节。此外还应核实产权类型、租赁条款、服务费、规划历史、洪水风险、法律问题、贷款要求和验房结果。',
|
||||||
// FAQ items — Privacy and Data Protection
|
// FAQ items: Privacy and Data Protection
|
||||||
faqPrivacy1Q: '你们会存储关于我的个人数据吗?',
|
faqPrivacy1Q: '你们会存储关于我的个人数据吗?',
|
||||||
faqPrivacy1A:
|
faqPrivacy1A:
|
||||||
'房产与周边信息本身不含您的个人资料。若您创建账户,我们只存储运行服务所必需的信息:邮箱地址、访问状态、邮件更新订阅选择、已保存的搜索、分享链接,以及由 Stripe 处理的付款记录。账户数据按英国隐私法律处理。',
|
'房产与周边信息本身不含您的个人资料。若您创建账户,我们只存储运行服务所必需的信息:邮箱地址、访问状态、邮件更新订阅选择、已保存的搜索、分享链接,以及由 Stripe 处理的付款记录。账户数据按英国隐私法律处理。',
|
||||||
// FAQ items — Why Perfect Postcode
|
// FAQ items: Why Perfect Postcode
|
||||||
faqWhy1Q: '它展示了哪些房源网站通常看不到的信息?',
|
faqWhy1Q: '它展示了哪些房源网站通常看不到的信息?',
|
||||||
faqWhy1A:
|
faqWhy1A:
|
||||||
'房源网站从当下在售的房子出发;Perfect Postcode 从契合您生活与预算的地方出发,在您打开房源之前就把成交价、空间、通勤、学校、治安、噪音、宽带、EPC 评级、产权和周边设施综合到一起。',
|
'房源网站从当下在售的房子出发;Perfect Postcode 从契合您生活与预算的地方出发,在您打开房源之前就把成交价、空间、通勤、学校、治安、噪音、宽带、EPC 评级、产权和周边设施综合到一起。',
|
||||||
|
|
@ -1320,7 +1352,7 @@ const zh: Translations = {
|
||||||
faqWhy3Q: '数据有多可靠?',
|
faqWhy3Q: '数据有多可靠?',
|
||||||
faqWhy3A:
|
faqWhy3A:
|
||||||
'主要来源是官方或被广泛使用的公开数据,涵盖成交价、EPC 评级、本地信息、学校评分、宽带、治安、环境、地图和街道数据。它们适合用于筛选和比较;真正决定购房时,仍需最新核查,必要时还要咨询专业人士。',
|
'主要来源是官方或被广泛使用的公开数据,涵盖成交价、EPC 评级、本地信息、学校评分、宽带、治安、环境、地图和街道数据。它们适合用于筛选和比较;真正决定购房时,仍需最新核查,必要时还要咨询专业人士。',
|
||||||
// FAQ items — Pricing and Access
|
// FAQ items: Pricing and Access
|
||||||
faqPricing1Q: '既然邮编报告是免费的,为什么还要付费?',
|
faqPricing1Q: '既然邮编报告是免费的,为什么还要付费?',
|
||||||
faqPricing1A:
|
faqPricing1A:
|
||||||
'免费的邮编工具在您已经知道要查什么时确实好用。Perfect Postcode 的价值,在于按您的条件扫描英格兰每个邮编、组合筛选、横向比较、保存搜索,并在投入周末看房之前导出候选名单。',
|
'免费的邮编工具在您已经知道要查什么时确实好用。Perfect Postcode 的价值,在于按您的条件扫描英格兰每个邮编、组合筛选、横向比较、保存搜索,并在投入周末看房之前导出候选名单。',
|
||||||
|
|
@ -1329,32 +1361,32 @@ const zh: Translations = {
|
||||||
'终身访问就是一次付款后,您的账户在 Perfect Postcode 服务存续期间都能持续访问付费地图。它不是按月或按年订阅,且涵盖后续数据更新。本次找房可以用,事后回来再看也行;将来再次搬家时,访问权限依然有效。',
|
'终身访问就是一次付款后,您的账户在 Perfect Postcode 服务存续期间都能持续访问付费地图。它不是按月或按年订阅,且涵盖后续数据更新。本次找房可以用,事后回来再看也行;将来再次搬家时,访问权限依然有效。',
|
||||||
faqPricing3Q: '免费版能用哪些功能?',
|
faqPricing3Q: '免费版能用哪些功能?',
|
||||||
faqPricing3A:
|
faqPricing3A:
|
||||||
'免费用户可以使用覆盖整个英格兰的完整 Perfect Postcode 地图——每个邮编、每项功能——并且每次最多可应用 3 个筛选条件。获取终身访问权限即可解除该限制,让您叠加无限多个筛选条件。',
|
'免费用户可以使用覆盖整个英格兰的完整 Perfect Postcode 地图(每个邮编、每项功能),并且每次最多可应用 3 个筛选条件。获取终身访问权限即可解除该限制,让您叠加无限多个筛选条件。',
|
||||||
|
|
||||||
// FAQ items — Tips and Tricks
|
// FAQ items: Tips and Tricks
|
||||||
faqTips1Q: '如何在地图上预览筛选条件?',
|
faqTips1Q: '如何在地图上预览筛选条件?',
|
||||||
faqTips1A:
|
faqTips1A:
|
||||||
'点击筛选条件或数据项旁的“地图着色”,就能按该项给地图着色。当前的筛选保持不变,因此可以快速对比价格、出行时间、学校、治安或噪音等单项,候选范围不会改变。',
|
'点击筛选条件或数据项旁的“地图着色”,就能按该项给地图着色。当前的筛选保持不变,因此可以快速对比价格、出行时间、学校、治安或噪音等单项,候选范围不会改变。',
|
||||||
faqTips2Q: '如何了解某个筛选条件的含义?',
|
faqTips2Q: '如何了解某个筛选条件的含义?',
|
||||||
faqTips2A:
|
faqTips2A:
|
||||||
'点击筛选条件或数据项旁的“关于”,会有一段简短说明,告诉您它是什么、该怎么读。地图中的一些部分——例如出行时间卡片——也有各自的数据说明。',
|
'点击筛选条件或数据项旁的“关于”,会有一段简短说明,告诉您它是什么、该怎么读。地图中的一些部分(例如出行时间卡片)也有各自的数据说明。',
|
||||||
faqTips3Q: '如何刷新地图颜色?',
|
faqTips3Q: '如何刷新地图颜色?',
|
||||||
faqTips3A:
|
faqTips3A:
|
||||||
'当某个数据项正在给地图着色时,在地图图例里点“重置颜色刻度”即可按当前结果重新配色。平移、缩放或调整筛选之后尤其有用。',
|
'当某个数据项正在给地图着色时,在地图图例里点“重置颜色刻度”即可按当前结果重新配色。平移、缩放或调整筛选之后尤其有用。',
|
||||||
|
|
||||||
// FAQ items — Behind The Data
|
// FAQ items: Behind The Data
|
||||||
faqBehindData1Q: '为什么机场有时看起来比周围的街道更安静?',
|
faqBehindData1Q: '为什么机场有时看起来比周围的街道更安静?',
|
||||||
faqBehindData1A:
|
faqBehindData1A:
|
||||||
'邮编上显示的噪音值是 Defra 三个来源(道路、铁路、飞机)中最大的一个,按离地 4 米建模为 24 小时加权平均(Lden)。在繁忙住宅街道上,道路噪音通常占主导,约 65–75 dB。机场围栏内没有大型公共道路,道路项下降,只剩下飞机平均值。例如伦敦城市机场有宵禁、航班受限,因此其 24 小时飞机 Lden 较温和(跑道处约 60–66 dB),所以机场内部看起来比两侧 A 级公路更安静。希思罗机场也存在同样现象。这是在住宅接收点高度测量交通噪音的真实表现,而不是系统错误。',
|
'邮编上显示的噪音值是 Defra 三个来源(道路、铁路、飞机)中最大的一个,按离地 4 米建模为 24 小时加权平均(Lden)。在繁忙住宅街道上,道路噪音通常占主导,约 65–75 dB。机场围栏内没有大型公共道路,道路项下降,只剩下飞机平均值。例如伦敦城市机场有宵禁、航班受限,因此其 24 小时飞机 Lden 较温和(跑道处约 60–66 dB),所以机场内部看起来比两侧 A 级公路更安静。希思罗机场也存在同样现象。这是在住宅接收点高度测量交通噪音的真实表现,而不是系统错误。',
|
||||||
faqBehindData2Q: '为什么机场、高速公路或公园会显示为一大块?',
|
faqBehindData2Q: '为什么机场、高速公路或公园会显示为一大块?',
|
||||||
faqBehindData2A:
|
faqBehindData2A:
|
||||||
'英国的邮编没有官方边界——Royal Mail 把邮编定义为投递地址列表,而不是一个区域。Perfect Postcode 把每个地址的周围土地分配给它,从而合成多边形。没有地址的地方(跑道、高速车道、公园、水库)由最近的住宅邮编填充。因此机场或开阔区域常常显示为一个大多边形,其数值来自围栏内的少数几个邮编。',
|
'英国的邮编没有官方边界:Royal Mail 把邮编定义为投递地址列表,而不是一个区域。Perfect Postcode 把每个地址的周围土地分配给它,从而合成多边形。没有地址的地方(跑道、高速车道、公园、水库)由最近的住宅邮编填充。因此机场或开阔区域常常显示为一个大多边形,其数值来自围栏内的少数几个邮编。',
|
||||||
faqBehindData3Q: '为什么相邻邮编的犯罪数字相同?',
|
faqBehindData3Q: '为什么相邻邮编的犯罪数字相同?',
|
||||||
faqBehindData3A:
|
faqBehindData3A:
|
||||||
'警方街道级犯罪数据按 LSOA 发布,即大约 1,500 名居民的小型社区单元。同一 LSOA 内每个邮编都继承同一年度总数,因此一条安静的住宅街和一个街区外的繁华街道,如果在同一边界内,可能显示完全相同的数据。覆盖医院、大学校园或工业园区的邮编,人均率可能异常偏高,因为那里事件数正常但登记居民很少。',
|
'警方街道级犯罪数据按 LSOA 发布,即大约 1,500 名居民的小型社区单元。同一 LSOA 内每个邮编都继承同一年度总数,因此一条安静的住宅街和一个街区外的繁华街道,如果在同一边界内,可能显示完全相同的数据。覆盖医院、大学校园或工业园区的邮编,人均率可能异常偏高,因为那里事件数正常但登记居民很少。',
|
||||||
faqBehindData4Q: '“学区数量”是什么意思——我的孩子能入读这些学校吗?',
|
faqBehindData4Q: '“学区数量”是什么意思?我的孩子能入读这些学校吗?',
|
||||||
faqBehindData4A:
|
faqBehindData4A:
|
||||||
'每个数字表示有多少所评级为“良好”或“优秀”的公立学校,其建模的历史学区覆盖该邮编。我们模拟英格兰按距离录取的实际分配过程:儿童(2021 年人口普查)在距离与 Ofsted 评级之间权衡后向附近学校申请,报名超额的学校按距离由近及远录取直至满额——其学区半径就是最后一名被录取儿童的距离,即各地方政府公布的“最远录取距离”。模型已用数百个此类公布距离进行校准。它估计的是在哪里大概率能获得学位,并非官方招生范围。宗教或选拔性录取、兄弟姐妹优先以及每年的边界变化均未建模,因此在做决定前,请务必向学校或地方政府确认学区和录取规则。',
|
'每个数字表示有多少所评级为“良好”或“优秀”的公立学校,其建模的历史学区覆盖该邮编。我们模拟英格兰按距离录取的实际分配过程:儿童(2021 年人口普查)在距离与 Ofsted 评级之间权衡后向附近学校申请,报名超额的学校按距离由近及远录取直至满额,其学区半径就是最后一名被录取儿童的距离,即各地方政府公布的“最远录取距离”。模型已用数百个此类公布距离进行校准。它估计的是在哪里大概率能获得学位,并非官方招生范围。宗教或选拔性录取、兄弟姐妹优先以及每年的边界变化均未建模,因此在做决定前,请务必向学校或地方政府确认学区和录取规则。',
|
||||||
faqBehindData5Q: '为什么并非每户都有光纤的邮编也显示“Gigabit”?',
|
faqBehindData5Q: '为什么并非每户都有光纤的邮编也显示“Gigabit”?',
|
||||||
faqBehindData5A:
|
faqBehindData5A:
|
||||||
'Ofcom Connected Nations 的宽带覆盖按邮编给出可达到每个速度档的房产百分比。我们显示有任何可用性的最高档,因此只要邮编内有一户能达到 Gigabit,就会显示“Gigabit 可用”。这回答的是“这条街上到底有没有光纤?”,但并不保证楼里每一套今天都能下单。签约前,请始终就您的具体地址向运营商核实。',
|
'Ofcom Connected Nations 的宽带覆盖按邮编给出可达到每个速度档的房产百分比。我们显示有任何可用性的最高档,因此只要邮编内有一户能达到 Gigabit,就会显示“Gigabit 可用”。这回答的是“这条街上到底有没有光纤?”,但并不保证楼里每一套今天都能下单。签约前,请始终就您的具体地址向运营商核实。',
|
||||||
|
|
@ -1421,6 +1453,7 @@ const zh: Translations = {
|
||||||
|
|
||||||
// ── Invite Page ────────────────────────────────────
|
// ── Invite Page ────────────────────────────────────
|
||||||
invitePage: {
|
invitePage: {
|
||||||
|
couldNotValidateTitle: '无法验证邀请',
|
||||||
youreInvited: '您收到了邀请!',
|
youreInvited: '您收到了邀请!',
|
||||||
specialOffer: '特别优惠!',
|
specialOffer: '特别优惠!',
|
||||||
invitedByFree: '{{name}} 邀请您获取免费终身访问权限。',
|
invitedByFree: '{{name}} 邀请您获取免费终身访问权限。',
|
||||||
|
|
@ -1484,17 +1517,17 @@ const zh: Translations = {
|
||||||
treesOutsideWoodlands: {
|
treesOutsideWoodlands: {
|
||||||
label: '树木与林地',
|
label: '树木与林地',
|
||||||
detail:
|
detail:
|
||||||
'Forest Research Trees Outside Woodland (TOW) v1 树冠多边形——单棵树木和树木群——与 TOW 有意排除的 National Forest Inventory (NFI) 林地地块(≥0.5 公顷)合并。二者共同覆盖行道树和真正的林地。多边形的不透明度随树冠面积变化。',
|
'Forest Research Trees Outside Woodland (TOW) v1 树冠多边形(单棵树木和树木群)与 TOW 有意排除的 National Forest Inventory (NFI) 林地地块(≥0.5 公顷)合并。二者共同覆盖行道树和真正的林地。多边形的不透明度随树冠面积变化。',
|
||||||
},
|
},
|
||||||
propertyBorders: {
|
propertyBorders: {
|
||||||
label: '房产边界',
|
label: '房产边界',
|
||||||
detail:
|
detail:
|
||||||
'HM Land Registry INSPIRE Index Polygons——英格兰和威尔士已登记的自由保有房产的位置和大致范围,以街道级的轮廓线绘制。这些是仅供参考的“一般边界”,并非房产的确切法律边界,且不包含仅租赁权益和未登记土地(大约覆盖 85–90% 的自由保有土地)。本信息受 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 授权。',
|
'HM Land Registry INSPIRE Index Polygons:英格兰和威尔士已登记的自由保有房产的位置和大致范围,以街道级的轮廓线绘制。这些是仅供参考的“一般边界”,并非房产的确切法律边界,且不包含仅租赁权益和未登记土地(大约覆盖 85–90% 的自由保有土地)。本信息受 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: {
|
newDevelopments: {
|
||||||
label: '新开发项目',
|
label: '新开发项目',
|
||||||
detail:
|
detail:
|
||||||
'前瞻性的新住房供应管线。蓝色标记表示位于法定 MHCLG Brownfield Land 登记册上的地块——每个都附有预估的净住宅容量和规划许可状态——以及 Homes England Land Hub 处置地块。这些显示了新住房的规划地点,通常比它们出现在 EPC 或成交记录中早数年。住宅数量为容量估算值,而非承诺,登记册上的地块是机会,而非建设的保证。依据 Open Government Licence v3.0 授权。',
|
'前瞻性的新住房供应管线。蓝色标记表示位于法定 MHCLG Brownfield Land 登记册上的地块(每个都附有预估的净住宅容量和规划许可状态),以及 Homes England Land Hub 处置地块。这些显示了新住房的规划地点,通常比它们出现在 EPC 或成交记录中早数年。住宅数量为容量估算值,而非承诺,登记册上的地块是机会,而非建设的保证。依据 Open Government Licence v3.0 授权。',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
@ -1640,7 +1673,7 @@ const zh: Translations = {
|
||||||
'Housing Conditions Score': '住房状况得分',
|
'Housing Conditions Score': '住房状况得分',
|
||||||
'Air Quality and Road Safety Score': '空气质量与道路安全得分',
|
'Air Quality and Road Safety Score': '空气质量与道路安全得分',
|
||||||
|
|
||||||
// ─ Feature names (Crime) — 按人口标准化的比率,7 年与 2 年 ─
|
// ─ Feature names (Crime):按人口标准化的比率,7 年与 2 年 ─
|
||||||
'Serious crime (/yr, 7y)': '严重犯罪(每年,7 年)',
|
'Serious crime (/yr, 7y)': '严重犯罪(每年,7 年)',
|
||||||
'Serious crime (/yr, 2y)': '严重犯罪(每年,2 年)',
|
'Serious crime (/yr, 2y)': '严重犯罪(每年,2 年)',
|
||||||
'Minor crime (/yr, 7y)': '轻微犯罪(每年,7 年)',
|
'Minor crime (/yr, 7y)': '轻微犯罪(每年,7 年)',
|
||||||
|
|
@ -1701,6 +1734,8 @@ const zh: Translations = {
|
||||||
'% Owner occupied': '% 自有住房',
|
'% Owner occupied': '% 自有住房',
|
||||||
'% Social rent': '% 社会租赁',
|
'% Social rent': '% 社会租赁',
|
||||||
'% Private rent': '% 私人租赁',
|
'% Private rent': '% 私人租赁',
|
||||||
|
'% Council housing': '% 公共住房',
|
||||||
|
'% Ex-council': '% 前公共住房',
|
||||||
'% White': '% 白人',
|
'% White': '% 白人',
|
||||||
'% South Asian': '% 南亚裔',
|
'% South Asian': '% 南亚裔',
|
||||||
'% Black': '% 黑人',
|
'% Black': '% 黑人',
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ import {
|
||||||
|
|
||||||
// "Serious crime" and "Minor crime" are aggregate severity rollups (they overlap
|
// "Serious crime" and "Minor crime" are aggregate severity rollups (they overlap
|
||||||
// the 14 detailed categories, so they must stay OUT of the "Specific crimes"
|
// the 14 detailed categories, so they must stay OUT of the "Specific crimes"
|
||||||
// dropdown). Each is a single feature with a 7-year/2-year window toggle — the
|
// dropdown). Each is a single feature with a 7-year/2-year window toggle, the
|
||||||
// same folding the specific-crimes card has, but with no variant dropdown (one
|
// same folding the specific-crimes card has, but with no variant dropdown (one
|
||||||
// variant). Modeled on the multi-filter-name POI pattern: one lib, two filter
|
// variant). Modeled on the multi-filter-name POI pattern: one lib, two filter
|
||||||
// names, distinguished by their key prefix / bare crime type.
|
// names, distinguished by their key prefix / bare crime type.
|
||||||
|
|
|
||||||
|
|
@ -152,7 +152,7 @@ export function buildPropertySearchUrls({
|
||||||
? Math.max(0, habitableRoomsFilter[1] - 1)
|
? Math.max(0, habitableRoomsFilter[1] - 1)
|
||||||
: undefined;
|
: undefined;
|
||||||
|
|
||||||
// Rightmove — requires locationIdentifier from typeahead API
|
// Rightmove: requires locationIdentifier from typeahead API
|
||||||
let rightmove: string | null = null;
|
let rightmove: string | null = null;
|
||||||
if (rightmoveLocationId) {
|
if (rightmoveLocationId) {
|
||||||
const rmParams = new URLSearchParams();
|
const rmParams = new URLSearchParams();
|
||||||
|
|
@ -190,7 +190,7 @@ export function buildPropertySearchUrls({
|
||||||
rightmove = `https://www.rightmove.co.uk/property-for-sale/find.html?${rmParams.toString()}`;
|
rightmove = `https://www.rightmove.co.uk/property-for-sale/find.html?${rmParams.toString()}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
// OnTheMarket — postcode slug in URL path (e.g. "SW1A 1AA" → "sw1a-1aa")
|
// OnTheMarket: postcode slug in URL path (e.g. "SW1A 1AA" → "sw1a-1aa")
|
||||||
const otmSlug = postcode.toLowerCase().replace(/\s+/g, '-');
|
const otmSlug = postcode.toLowerCase().replace(/\s+/g, '-');
|
||||||
const otmParams = new URLSearchParams();
|
const otmParams = new URLSearchParams();
|
||||||
otmParams.set('radius', String(nearestRadius(radiusMiles, OTM_RADII)));
|
otmParams.set('radius', String(nearestRadius(radiusMiles, OTM_RADII)));
|
||||||
|
|
|
||||||
|
|
@ -80,7 +80,7 @@ export function parseInputValue(
|
||||||
|
|
||||||
export function formatDuration(d: string): string {
|
export function formatDuration(d: string): string {
|
||||||
if (d === 'F' || d === 'L') {
|
if (d === 'F' || d === 'L') {
|
||||||
// These are server enum values — translate via ts()
|
// These are server enum values: translate via ts()
|
||||||
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
||||||
const { ts } = require('../i18n/server') as { ts: (v: string) => string };
|
const { ts } = require('../i18n/server') as { ts: (v: string) => string };
|
||||||
if (d === 'F') return ts('Freehold');
|
if (d === 'F') return ts('Freehold');
|
||||||
|
|
|
||||||
52
frontend/src/lib/listings.test.ts
Normal file
52
frontend/src/lib/listings.test.ts
Normal file
|
|
@ -0,0 +1,52 @@
|
||||||
|
import { describe, expect, it } from 'vitest';
|
||||||
|
|
||||||
|
import type { ActualListing } from '../types';
|
||||||
|
import { filterListingsByMode, isNewBuildListing } from './listings';
|
||||||
|
|
||||||
|
function listing(listing_url: string): ActualListing {
|
||||||
|
return {
|
||||||
|
lat: 51.5,
|
||||||
|
lon: -0.1,
|
||||||
|
postcode: 'N1 1AA',
|
||||||
|
listing_url,
|
||||||
|
features: [],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const newBuild = listing('https://www.rightmove.co.uk/properties/1#/?channel=RES_NEW');
|
||||||
|
const resale = listing('https://www.rightmove.co.uk/properties/2#/?channel=RES_BUY');
|
||||||
|
const otherPortal = listing('https://www.onthemarket.com/details/3/');
|
||||||
|
|
||||||
|
describe('isNewBuildListing', () => {
|
||||||
|
it('flags RES_NEW channel URLs as new builds', () => {
|
||||||
|
expect(isNewBuildListing(newBuild)).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('treats RES_BUY (resale) as non-new', () => {
|
||||||
|
expect(isNewBuildListing(resale)).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('treats non-Rightmove portals as non-new', () => {
|
||||||
|
expect(isNewBuildListing(otherPortal)).toBe(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('filterListingsByMode', () => {
|
||||||
|
const all = [newBuild, resale, otherPortal];
|
||||||
|
|
||||||
|
it('returns everything for "all"', () => {
|
||||||
|
expect(filterListingsByMode(all, 'all')).toEqual(all);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns only new builds for "new"', () => {
|
||||||
|
expect(filterListingsByMode(all, 'new')).toEqual([newBuild]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('excludes new builds for "non-new"', () => {
|
||||||
|
expect(filterListingsByMode(all, 'non-new')).toEqual([resale, otherPortal]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('returns nothing for "none"', () => {
|
||||||
|
expect(filterListingsByMode(all, 'none')).toEqual([]);
|
||||||
|
});
|
||||||
|
});
|
||||||
41
frontend/src/lib/listings.ts
Normal file
41
frontend/src/lib/listings.ts
Normal file
|
|
@ -0,0 +1,41 @@
|
||||||
|
import type { ActualListing } from '../types';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Which slice of the live for-sale listings to render on the map.
|
||||||
|
*
|
||||||
|
* - `all`: every listing in view
|
||||||
|
* - `new`: new-build listings only
|
||||||
|
* - `non-new`: everything that isn't a new build (resale, OnTheMarket, …)
|
||||||
|
* - `none`: hide listings entirely (also skips the fetch)
|
||||||
|
*/
|
||||||
|
export type ListingsMode = 'all' | 'new' | 'non-new' | 'none';
|
||||||
|
|
||||||
|
export const LISTINGS_MODES: readonly ListingsMode[] = ['all', 'new', 'non-new', 'none'];
|
||||||
|
|
||||||
|
export const DEFAULT_LISTINGS_MODE: ListingsMode = 'all';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rightmove encodes the sales channel in the listing URL: `?channel=RES_NEW` for
|
||||||
|
* new-build developments and `?channel=RES_BUY` for ordinary resale. Anything
|
||||||
|
* without `RES_NEW` (resale, OnTheMarket and other portals) is treated as non-new.
|
||||||
|
*/
|
||||||
|
export function isNewBuildListing(listing: Pick<ActualListing, 'listing_url'>): boolean {
|
||||||
|
return listing.listing_url.includes('RES_NEW');
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Apply a {@link ListingsMode} to a list of listings. */
|
||||||
|
export function filterListingsByMode(
|
||||||
|
listings: ActualListing[],
|
||||||
|
mode: ListingsMode
|
||||||
|
): ActualListing[] {
|
||||||
|
switch (mode) {
|
||||||
|
case 'all':
|
||||||
|
return listings;
|
||||||
|
case 'new':
|
||||||
|
return listings.filter(isNewBuildListing);
|
||||||
|
case 'non-new':
|
||||||
|
return listings.filter((listing) => !isNewBuildListing(listing));
|
||||||
|
case 'none':
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -24,7 +24,7 @@ export interface PlacedItem<T> {
|
||||||
* Greedily keep a spaced-out subset of screen-space items so dense areas don't
|
* Greedily keep a spaced-out subset of screen-space items so dense areas don't
|
||||||
* render a wall of overlapping cards. Walks `candidates` in order, keeping one
|
* render a wall of overlapping cards. Walks `candidates` in order, keeping one
|
||||||
* only when it clears every already-kept item by `minDx`/`minDy`, and stops at
|
* only when it clears every already-kept item by `minDx`/`minDy`, and stops at
|
||||||
* `max`. Order-dependent by design — pass candidates in priority order.
|
* `max`. Order-dependent by design: pass candidates in priority order.
|
||||||
*/
|
*/
|
||||||
export function selectSpacedItems<T>(
|
export function selectSpacedItems<T>(
|
||||||
candidates: PlacedItem<T>[],
|
candidates: PlacedItem<T>[],
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@ pub(super) struct AddressQuery {
|
||||||
full_postcode: Option<String>,
|
full_postcode: Option<String>,
|
||||||
/// Compact uppercase outward code (optionally with a sector digit) recovered when the
|
/// Compact uppercase outward code (optionally with a sector digit) recovered when the
|
||||||
/// user appended a partial postcode like "NW1" or "NW1 6". Used as an additive ranking
|
/// user appended a partial postcode like "NW1" or "NW1 6". Used as an additive ranking
|
||||||
/// bias, never as a hard filter — so the disambiguating hint is honoured without
|
/// bias, never as a hard filter, so the disambiguating hint is honoured without
|
||||||
/// excluding the same road in other areas.
|
/// excluding the same road in other areas.
|
||||||
postcode_area: Option<String>,
|
postcode_area: Option<String>,
|
||||||
text_groups: Vec<AddressTermGroup>,
|
text_groups: Vec<AddressTermGroup>,
|
||||||
|
|
@ -252,7 +252,7 @@ pub(super) fn address_search_tokens(text: &str) -> Vec<String> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Search tokens for a property row, covering its display address plus an
|
/// Search tokens for a property row, covering its display address plus an
|
||||||
/// alternative spelling (`alt`, the EPC form) when distinct — so the property is
|
/// alternative spelling (`alt`, the EPC form) when distinct, so the property is
|
||||||
/// findable by either form. The result is deduped: each token appears at most
|
/// findable by either form. The result is deduped: each token appears at most
|
||||||
/// once, which the inverted-index posting lists rely on (a token must post a
|
/// once, which the inverted-index posting lists rely on (a token must post a
|
||||||
/// given row exactly once to keep those lists strictly ascending and unique).
|
/// given row exactly once to keep those lists strictly ascending and unique).
|
||||||
|
|
@ -370,7 +370,7 @@ fn union_sorted(left: &[u32], right: &[u32]) -> Vec<u32> {
|
||||||
out
|
out
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An ordinal like "1st", "2nd", "3rd", "21st" — part of the street name ("2nd Avenue"), not a
|
/// An ordinal like "1st", "2nd", "3rd", "21st", part of the street name ("2nd Avenue"), not a
|
||||||
/// house-number prefix.
|
/// house-number prefix.
|
||||||
fn is_ordinal_token(token: &str) -> bool {
|
fn is_ordinal_token(token: &str) -> bool {
|
||||||
let split = token.len().saturating_sub(2);
|
let split = token.len().saturating_sub(2);
|
||||||
|
|
@ -467,7 +467,7 @@ fn parse_address_query(query: &str) -> AddressQuery {
|
||||||
let skip_postcode_tokens: FxHashSet<usize> = postcode_token_indices.into_iter().collect();
|
let skip_postcode_tokens: FxHashSet<usize> = postcode_token_indices.into_iter().collect();
|
||||||
|
|
||||||
// Recover an appended partial postcode (outcode, or outcode + sector digit) as a ranking
|
// Recover an appended partial postcode (outcode, or outcode + sector digit) as a ranking
|
||||||
// bias rather than discarding it — but only from the TRAILING position, so a leading road
|
// bias rather than discarding it, but only from the TRAILING position, so a leading road
|
||||||
// designation like "A4 Great West Road" is not mistaken for an area refinement.
|
// designation like "A4 Great West Road" is not mistaken for an area refinement.
|
||||||
let mut postcode_area: Option<String> = None;
|
let mut postcode_area: Option<String> = None;
|
||||||
let mut consumed_partial_tokens: FxHashSet<usize> = FxHashSet::default();
|
let mut consumed_partial_tokens: FxHashSet<usize> = FxHashSet::default();
|
||||||
|
|
@ -610,7 +610,7 @@ impl PropertyData {
|
||||||
|
|
||||||
// When the user appended a partial postcode, keep in-area rows ahead of the cut so the
|
// When the user appended a partial postcode, keep in-area rows ahead of the cut so the
|
||||||
// refinement still surfaces even for very common roads. Single pass (stable partition) so
|
// refinement still surfaces even for very common roads. Single pass (stable partition) so
|
||||||
// the postcode check — which allocates — runs exactly once per candidate.
|
// the postcode check (which allocates) runs exactly once per candidate.
|
||||||
if let Some(area) = parsed.postcode_area.as_deref() {
|
if let Some(area) = parsed.postcode_area.as_deref() {
|
||||||
let mut in_area = Vec::new();
|
let mut in_area = Vec::new();
|
||||||
let mut others = Vec::new();
|
let mut others = Vec::new();
|
||||||
|
|
@ -710,7 +710,7 @@ impl PropertyData {
|
||||||
self.prefix_seed_rows(terms)
|
self.prefix_seed_rows(terms)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Seed rows from the smallest prefix-expanded term — used only when no word matched an
|
/// Seed rows from the smallest prefix-expanded term, used only when no word matched an
|
||||||
/// indexed token exactly (i.e. the user is still typing the final word).
|
/// indexed token exactly (i.e. the user is still typing the final word).
|
||||||
fn prefix_seed_rows(&self, terms: &[String]) -> Vec<u32> {
|
fn prefix_seed_rows(&self, terms: &[String]) -> Vec<u32> {
|
||||||
let mut best: Option<Vec<u32>> = None;
|
let mut best: Option<Vec<u32>> = None;
|
||||||
|
|
@ -967,7 +967,7 @@ mod tests {
|
||||||
assert!(merged.contains(&"road".to_string()));
|
assert!(merged.contains(&"road".to_string()));
|
||||||
assert!(merged.contains(&"10".to_string()));
|
assert!(merged.contains(&"10".to_string()));
|
||||||
|
|
||||||
// No token repeats — posting-list uniqueness depends on this.
|
// No token repeats: posting-list uniqueness depends on this.
|
||||||
let mut deduped = merged.clone();
|
let mut deduped = merged.clone();
|
||||||
deduped.sort_unstable();
|
deduped.sort_unstable();
|
||||||
deduped.dedup();
|
deduped.dedup();
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,13 @@
|
||||||
//! Optional disk-backed storage for the large flat arrays in [`PropertyData`].
|
//! Optional disk-backed storage for the large flat arrays in [`PropertyData`].
|
||||||
//!
|
//!
|
||||||
//! In production every property array is held as an owned `Vec` in RAM — fastest,
|
//! In production every property array is held as an owned `Vec` in RAM (fastest),
|
||||||
//! but the feature matrix plus the flat address-search arrays are ~4GB, which a
|
//! but the feature matrix plus the flat address-search arrays are ~4GB, which a
|
||||||
//! memory-constrained dev box can't hold reliably. When a spill directory is
|
//! memory-constrained dev box can't hold reliably. When a spill directory is
|
||||||
//! configured (the `--spill-dir` dev flag), each large array is instead written
|
//! configured (the `--spill-dir` dev flag), each large array is instead written
|
||||||
//! to an anonymous file in that directory and memory-mapped read-only. The mapped
|
//! to an anonymous file in that directory and memory-mapped read-only. The mapped
|
||||||
//! pages are file-backed and clean, so under memory pressure the kernel evicts
|
//! pages are file-backed and clean, so under memory pressure the kernel evicts
|
||||||
//! them (re-faulting from disk on next touch) rather than the process being
|
//! them (re-faulting from disk on next touch) rather than the process being
|
||||||
//! OOM-killed — the same "let the kernel page it" trade-off the PMTiles reader
|
//! OOM-killed: the same "let the kernel page it" trade-off the PMTiles reader
|
||||||
//! already makes. The backing files are unlinked immediately after creation, so
|
//! already makes. The backing files are unlinked immediately after creation, so
|
||||||
//! they leave nothing on disk and are reclaimed when the map drops at shutdown.
|
//! they leave nothing on disk and are reclaimed when the map drops at shutdown.
|
||||||
//!
|
//!
|
||||||
|
|
@ -28,8 +28,8 @@ use memmap2::{Mmap, MmapMut};
|
||||||
/// round-trip losslessly through their raw bytes.
|
/// round-trip losslessly through their raw bytes.
|
||||||
///
|
///
|
||||||
/// # Safety
|
/// # Safety
|
||||||
/// Implementors must be `Copy`, contain no padding, and accept — for any value we
|
/// Implementors must be `Copy`, contain no padding, and accept (for any value we
|
||||||
/// could have stored — the exact bytes we wrote when reinterpreted as `Self`. We
|
/// could have stored) the exact bytes we wrote when reinterpreted as `Self`. We
|
||||||
/// only ever read back bytes produced from genuine `Self` values, so niche types
|
/// only ever read back bytes produced from genuine `Self` values, so niche types
|
||||||
/// such as `lasso::Spur` (a `NonZeroU32`) are sound here: the bytes always come
|
/// such as `lasso::Spur` (a `NonZeroU32`) are sound here: the bytes always come
|
||||||
/// from real, non-zero interner keys and are never reinterpreted from arbitrary
|
/// from real, non-zero interner keys and are never reinterpreted from arbitrary
|
||||||
|
|
@ -86,7 +86,7 @@ impl<T: SpillElem> SpillVec<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SpillVec<u16> {
|
impl SpillVec<u16> {
|
||||||
/// Build a `u16` array of `len` elements by filling it in place — on the heap
|
/// Build a `u16` array of `len` elements by filling it in place: on the heap
|
||||||
/// when `dir` is `None`, or directly inside an mmap-backed spill file when
|
/// when `dir` is `None`, or directly inside an mmap-backed spill file when
|
||||||
/// `Some`, so the (large) buffer never simultaneously exists on the heap. Every
|
/// `Some`, so the (large) buffer never simultaneously exists on the heap. Every
|
||||||
/// element is initialized to `default` first; `fill` then overwrites the cells
|
/// element is initialized to `default` first; `fill` then overwrites the cells
|
||||||
|
|
@ -138,7 +138,7 @@ impl SpillVec<u16> {
|
||||||
///
|
///
|
||||||
/// When a spill `dir` is set (and the length is non-zero) the backing store is a
|
/// When a spill `dir` is set (and the length is non-zero) the backing store is a
|
||||||
/// pre-sized, memory-mapped file and each pushed element is written straight into
|
/// pre-sized, memory-mapped file and each pushed element is written straight into
|
||||||
/// it — so the array never exists as a heap `Vec` and is never copied a second
|
/// it, so the array never exists as a heap `Vec` and is never copied a second
|
||||||
/// time on finalisation, unlike [`SpillVec::maybe_spill`], which takes an
|
/// time on finalisation, unlike [`SpillVec::maybe_spill`], which takes an
|
||||||
/// already-built `Vec` and so needs the whole thing resident first. Without a
|
/// already-built `Vec` and so needs the whole thing resident first. Without a
|
||||||
/// spill dir it accumulates into an owned `Vec` (production behaviour, identical
|
/// spill dir it accumulates into an owned `Vec` (production behaviour, identical
|
||||||
|
|
@ -200,7 +200,7 @@ impl<T: SpillElem> SpillVecBuilder<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Append one element. Panics if more than the declared `len` elements are
|
/// Append one element. Panics if more than the declared `len` elements are
|
||||||
/// pushed — enforced identically on both backings so a streaming bug fails
|
/// pushed. Enforced identically on both backings so a streaming bug fails
|
||||||
/// the same way in production (owned) as in dev (spilled).
|
/// the same way in production (owned) as in dev (spilled).
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn push(&mut self, value: T) {
|
pub fn push(&mut self, value: T) {
|
||||||
|
|
@ -320,7 +320,7 @@ fn spill_vec<T: SpillElem>(values: Vec<T>, dir: &Path, label: &str) -> anyhow::R
|
||||||
|
|
||||||
/// Size a freshly-created spill file to `byte_len` bytes, reserving the disk
|
/// Size a freshly-created spill file to `byte_len` bytes, reserving the disk
|
||||||
/// blocks up front. We write the array through a mutable mmap, and writing to a
|
/// blocks up front. We write the array through a mutable mmap, and writing to a
|
||||||
/// dirty mmap page the kernel can't back at writeback raises `SIGBUS` — so a
|
/// dirty mmap page the kernel can't back at writeback raises `SIGBUS`, so a
|
||||||
/// plain sparse `set_len` would turn an out-of-space dev disk into a crash. On
|
/// plain sparse `set_len` would turn an out-of-space dev disk into a crash. On
|
||||||
/// Linux `posix_fallocate` allocates the blocks now, surfacing the shortfall as a
|
/// Linux `posix_fallocate` allocates the blocks now, surfacing the shortfall as a
|
||||||
/// clean `ENOSPC` error here instead. Elsewhere we fall back to `set_len`.
|
/// clean `ENOSPC` error here instead. Elsewhere we fall back to `set_len`.
|
||||||
|
|
@ -348,7 +348,7 @@ fn allocate_spill_file(file: &File, byte_len: usize, label: &str) -> anyhow::Res
|
||||||
/// Create a spill file in `dir` and immediately unlink it. On Unix the open
|
/// Create a spill file in `dir` and immediately unlink it. On Unix the open
|
||||||
/// descriptor (and the mapping built from it) keep the inode alive, so the file is
|
/// descriptor (and the mapping built from it) keep the inode alive, so the file is
|
||||||
/// invisible in the directory and its blocks are reclaimed automatically when the
|
/// invisible in the directory and its blocks are reclaimed automatically when the
|
||||||
/// map is dropped — no cleanup, no leftovers across runs.
|
/// map is dropped: no cleanup, no leftovers across runs.
|
||||||
fn anon_file(dir: &Path, label: &str) -> anyhow::Result<File> {
|
fn anon_file(dir: &Path, label: &str) -> anyhow::Result<File> {
|
||||||
std::fs::create_dir_all(dir)
|
std::fs::create_dir_all(dir)
|
||||||
.with_context(|| format!("creating spill directory {}", dir.display()))?;
|
.with_context(|| format!("creating spill directory {}", dir.display()))?;
|
||||||
|
|
@ -437,7 +437,7 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn spur_keys_survive_the_mmap_roundtrip() {
|
fn spur_keys_survive_the_mmap_roundtrip() {
|
||||||
// Spur is a NonZeroU32 niche type — exercises the SpillElem soundness claim.
|
// Spur is a NonZeroU32 niche type: exercises the SpillElem soundness claim.
|
||||||
let mut rodeo = lasso::Rodeo::default();
|
let mut rodeo = lasso::Rodeo::default();
|
||||||
let keys: Vec<lasso::Spur> = (0..2000)
|
let keys: Vec<lasso::Spur> = (0..2000)
|
||||||
.map(|n| rodeo.get_or_intern(format!("token-{n}")))
|
.map(|n| rodeo.get_or_intern(format!("token-{n}")))
|
||||||
|
|
@ -493,7 +493,7 @@ mod tests {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn builder_spurs_survive_the_mmap_roundtrip() {
|
fn builder_spurs_survive_the_mmap_roundtrip() {
|
||||||
// Spur is a NonZeroU32 niche type — exercises the streamed write path for
|
// Spur is a NonZeroU32 niche type: exercises the streamed write path for
|
||||||
// the crime-records `location` column.
|
// the crime-records `location` column.
|
||||||
let mut rodeo = lasso::Rodeo::default();
|
let mut rodeo = lasso::Rodeo::default();
|
||||||
let keys: Vec<lasso::Spur> = (0..3000)
|
let keys: Vec<lasso::Spur> = (0..3000)
|
||||||
|
|
|
||||||
|
|
@ -315,7 +315,7 @@ fn parse_postcode_list(
|
||||||
Some(&pc_idx) if seen.insert(pc_idx) => {
|
Some(&pc_idx) if seen.insert(pc_idx) => {
|
||||||
entries.push((pc_idx, normalized));
|
entries.push((pc_idx, normalized));
|
||||||
}
|
}
|
||||||
Some(_) => {} // duplicate — skip silently
|
Some(_) => {} // duplicate, skip silently
|
||||||
None => unknown.push(normalized),
|
None => unknown.push(normalized),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -444,7 +444,7 @@ pub async fn get_export(
|
||||||
) -> Result<impl IntoResponse, axum::response::Response> {
|
) -> Result<impl IntoResponse, axum::response::Response> {
|
||||||
let state = shared.load_state();
|
let state = shared.load_state();
|
||||||
|
|
||||||
// Exporting requires an account — no anonymous/demo exports.
|
// Exporting requires an account: no anonymous/demo exports.
|
||||||
if user.0.is_none() {
|
if user.0.is_none() {
|
||||||
return Err((
|
return Err((
|
||||||
StatusCode::UNAUTHORIZED,
|
StatusCode::UNAUTHORIZED,
|
||||||
|
|
@ -958,7 +958,7 @@ pub async fn get_export(
|
||||||
|
|
||||||
// Two sheets in both modes: "Selected" (just the features behind the
|
// Two sheets in both modes: "Selected" (just the features behind the
|
||||||
// active filters, including any POI amenity metrics) and "All Data"
|
// active filters, including any POI amenity metrics) and "All Data"
|
||||||
// (every property/area feature, but no POI amenity counts/distances —
|
// (every property/area feature, but no POI amenity counts/distances;
|
||||||
// those live only on the Selected sheet). The Selected sheet carries the
|
// those live only on the Selected sheet). The Selected sheet carries the
|
||||||
// dashboard link + screenshot only in bounds mode, where the export is
|
// dashboard link + screenshot only in bounds mode, where the export is
|
||||||
// tied to a map view; in list mode the user picked the postcodes
|
// tied to a map view; in list mode the user picked the postcodes
|
||||||
|
|
@ -1104,7 +1104,7 @@ pub async fn get_export(
|
||||||
// outcode summary row acts as the header for its postcodes.
|
// outcode summary row acts as the header for its postcodes.
|
||||||
sheet.group_symbols_above(true);
|
sheet.group_symbols_above(true);
|
||||||
|
|
||||||
// Data rows — one bold outcode summary row followed by its postcodes,
|
// Data rows: one bold outcode summary row followed by its postcodes,
|
||||||
// the latter wrapped in a collapsible outline group.
|
// the latter wrapped in a collapsible outline group.
|
||||||
let data_start_row = desc_row + 1;
|
let data_start_row = desc_row + 1;
|
||||||
let mut row = data_start_row;
|
let mut row = data_start_row;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue