Translate pages
This commit is contained in:
parent
a7aaf5effa
commit
96402228e3
49 changed files with 1458 additions and 926 deletions
297
frontend/src/i18n/descriptions.ts
Normal file
297
frontend/src/i18n/descriptions.ts
Normal file
|
|
@ -0,0 +1,297 @@
|
|||
import i18n from 'i18next';
|
||||
|
||||
/**
|
||||
* Feature description translations, keyed by feature name.
|
||||
*
|
||||
* English descriptions are NOT here — the server is the single source of truth
|
||||
* for English. Fix a typo in features.rs and it propagates automatically.
|
||||
*
|
||||
* Non-English translations are keyed by the stable feature name, so they're
|
||||
* independent of the English description text. If a translation is missing,
|
||||
* tsDesc() falls back to the server's English description.
|
||||
*/
|
||||
const descriptions: Record<string, Record<string, string>> = {
|
||||
fr: {
|
||||
'Listing status': 'Indique si le bien provient de ventes historiques, est en vente ou en location',
|
||||
'Property type': 'Type de bien : individuel, jumel\u00E9, mitoyen, appartement ou autre',
|
||||
'Leasehold/Freehold': 'Indique si le bien est en bail ou en pleine propri\u00E9t\u00E9',
|
||||
'Last known price': 'Dernier prix de vente enregistr\u00E9 au Land Registry',
|
||||
'Estimated current price': 'Estimation du prix actuel ajust\u00E9 \u00E0 l\u2019inflation',
|
||||
'Asking price': 'Prix demand\u00E9 pour les biens actuellement en vente',
|
||||
'Price per sqm': 'Prix de vente divis\u00E9 par la surface totale',
|
||||
'Est. price per sqm': 'Prix actuel estim\u00E9 divis\u00E9 par la surface totale',
|
||||
'Asking price per sqm': 'Prix demand\u00E9 divis\u00E9 par la surface totale',
|
||||
'Estimated monthly rent': 'Loyer mensuel priv\u00E9 m\u00E9dian pour le secteur',
|
||||
'Asking rent (monthly)': 'Loyer mensuel affich\u00E9 pour les biens en location',
|
||||
'Total floor area (sqm)': 'Surface int\u00E9rieure issue du diagnostic EPC',
|
||||
'Number of bedrooms & living rooms': 'Nombre de pi\u00E8ces habitables selon le diagnostic EPC',
|
||||
'Bedrooms': 'Nombre de chambres selon l\u2019annonce en ligne',
|
||||
'Bathrooms': 'Nombre de salles de bain selon l\u2019annonce en ligne',
|
||||
'Construction year': 'Ann\u00E9e de construction estim\u00E9e selon l\u2019EPC',
|
||||
'Date of last transaction': 'Date de la derni\u00E8re vente enregistr\u00E9e au Land Registry',
|
||||
'Listing date': 'Date de premi\u00E8re mise en ligne du bien',
|
||||
'Former council house': 'Indique si le bien a \u00E9t\u00E9 r\u00E9pertori\u00E9 comme logement social',
|
||||
'Current energy rating': 'Classement \u00E9nerg\u00E9tique EPC actuel (A = meilleur, G = pire)',
|
||||
'Potential energy rating': 'Classement EPC potentiel si toutes les am\u00E9liorations recommand\u00E9es \u00E9taient r\u00E9alis\u00E9es',
|
||||
'Interior height (m)': 'Hauteur moyenne d\u2019\u00E9tage selon le diagnostic EPC',
|
||||
'Distance to nearest train or tube station (km)': 'Distance \u00E0 la gare ou station de m\u00E9tro la plus proche',
|
||||
'Train or tube stations within 1km': 'Nombre de gares ou stations de m\u00E9tro \u00E0 moins d\u20191 km',
|
||||
'Good+ primary schools within 2km': '\u00C9coles primaires not\u00E9es Bien ou Excellent par Ofsted dans un rayon de 2 km',
|
||||
'Good+ secondary schools within 2km': 'Coll\u00E8ges/lyc\u00E9es not\u00E9s Bien ou Excellent par Ofsted dans un rayon de 2 km',
|
||||
'Good+ primary schools within 5km': '\u00C9coles primaires not\u00E9es Bien ou Excellent par Ofsted dans un rayon de 5 km',
|
||||
'Good+ secondary schools within 5km': 'Coll\u00E8ges/lyc\u00E9es not\u00E9s Bien ou Excellent par Ofsted dans un rayon de 5 km',
|
||||
'Education, Skills and Training Score': 'Score de qualit\u00E9 \u00E9ducative du secteur (plus \u00E9lev\u00E9 = meilleur)',
|
||||
'Income Score (rate)': 'Taux de pr\u00E9carit\u00E9 de revenu, invers\u00E9 (plus \u00E9lev\u00E9 = moins pr\u00E9caire)',
|
||||
'Employment Score (rate)': 'Taux de pr\u00E9carit\u00E9 d\u2019emploi, invers\u00E9 (plus \u00E9lev\u00E9 = moins pr\u00E9caire)',
|
||||
'Health Deprivation and Disability Score': 'Score de sant\u00E9 et handicap (plus \u00E9lev\u00E9 = meilleurs r\u00E9sultats)',
|
||||
'Living Environment Score': 'Qualit\u00E9 de l\u2019environnement int\u00E9rieur et ext\u00E9rieur (plus \u00E9lev\u00E9 = meilleur)',
|
||||
'Indoors Sub-domain Score': 'Qualit\u00E9 et \u00E9tat du logement (plus \u00E9lev\u00E9 = meilleur)',
|
||||
'Outdoors Sub-domain Score': 'Qualit\u00E9 de l\u2019air et s\u00E9curit\u00E9 routi\u00E8re (plus \u00E9lev\u00E9 = meilleur)',
|
||||
'Serious crime per 1k residents (avg/yr)': 'Taux de crimes graves pour 1 000 habitants par an',
|
||||
'Minor crime per 1k residents (avg/yr)': 'Taux de d\u00E9lits mineurs pour 1 000 habitants par an',
|
||||
'Serious crime (avg/yr)': 'Agr\u00E9gat des cat\u00E9gories de crimes graves par an',
|
||||
'Minor crime (avg/yr)': 'Agr\u00E9gat des cat\u00E9gories de d\u00E9lits mineurs par an',
|
||||
'Violence and sexual offences (avg/yr)': 'Moyenne annuelle des violences et infractions sexuelles dans le secteur',
|
||||
'Burglary (avg/yr)': 'Moyenne annuelle des cambriolages dans le secteur',
|
||||
'Robbery (avg/yr)': 'Moyenne annuelle des vols avec violence dans le secteur',
|
||||
'Vehicle crime (avg/yr)': 'Moyenne annuelle des crimes li\u00E9s aux v\u00E9hicules dans le secteur',
|
||||
'Anti-social behaviour (avg/yr)': 'Moyenne annuelle des comportements antisociaux dans le secteur',
|
||||
'Criminal damage and arson (avg/yr)': 'Moyenne annuelle des d\u00E9gradations et incendies criminels dans le secteur',
|
||||
'Other theft (avg/yr)': 'Moyenne annuelle des autres vols dans le secteur',
|
||||
'Theft from the person (avg/yr)': 'Moyenne annuelle des vols \u00E0 la personne dans le secteur',
|
||||
'Shoplifting (avg/yr)': 'Moyenne annuelle des vols \u00E0 l\u2019\u00E9talage dans le secteur',
|
||||
'Bicycle theft (avg/yr)': 'Moyenne annuelle des vols de v\u00E9los dans le secteur',
|
||||
'Drugs (avg/yr)': 'Moyenne annuelle des infractions li\u00E9es aux stup\u00E9fiants dans le secteur',
|
||||
'Possession of weapons (avg/yr)': 'Moyenne annuelle des infractions de possession d\u2019armes dans le secteur',
|
||||
'Public order (avg/yr)': 'Moyenne annuelle des troubles \u00E0 l\u2019ordre public dans le secteur',
|
||||
'Other crime (avg/yr)': 'Moyenne annuelle des autres crimes dans le secteur',
|
||||
'Median age': '\u00C2ge m\u00E9dian de la population locale',
|
||||
'% White': 'Pourcentage de la population se d\u00E9clarant Blanche',
|
||||
'% South Asian': 'Pourcentage de la population se d\u00E9clarant Sud-Asiatique',
|
||||
'% Black': 'Pourcentage de la population se d\u00E9clarant Noire',
|
||||
'% East Asian': 'Pourcentage de la population se d\u00E9clarant Est-Asiatique',
|
||||
'% Mixed': 'Pourcentage de la population se d\u00E9clarant M\u00E9tisse ou de plusieurs groupes ethniques',
|
||||
'% Other': 'Pourcentage de la population se d\u00E9clarant d\u2019un autre groupe ethnique',
|
||||
'Distance to nearest park (km)': 'Distance au parc ou espace vert le plus proche',
|
||||
'Number of parks within 2km': 'Nombre de parcs et espaces verts \u00E0 moins de 2 km',
|
||||
'Number of restaurants within 2km': 'Nombre de restaurants et caf\u00E9s \u00E0 moins de 2 km',
|
||||
'Number of grocery shops and supermarkets within 2km': 'Nombre d\u2019\u00E9piceries et supermarch\u00E9s \u00E0 moins de 2 km',
|
||||
'Noise (dB)': 'Niveau de bruit routier au code postal en d\u00E9cibels (Lden)',
|
||||
'Max available download speed (Mbps)': 'D\u00E9bit descendant maximal disponible au code postal',
|
||||
},
|
||||
de: {
|
||||
'Listing status': 'Ob die Immobilie aus historischen Verk\u00E4ufen stammt, aktuell zum Verkauf oder zur Miete steht',
|
||||
'Property type': 'Immobilientyp: freistehend, Doppelhaush\u00E4lfte, Reihenhaus, Wohnung oder sonstige',
|
||||
'Leasehold/Freehold': 'Ob die Immobilie Erbbaurecht oder Volleigentum ist',
|
||||
'Last known price': 'Letzter Verkaufspreis laut Land Registry',
|
||||
'Estimated current price': 'Inflationsbereinigter Sch\u00E4tzwert der Immobilie',
|
||||
'Asking price': 'Angebotspreis f\u00FCr aktuell zum Verkauf stehende Immobilien',
|
||||
'Price per sqm': 'Verkaufspreis geteilt durch die Gesamtfl\u00E4che',
|
||||
'Est. price per sqm': 'Gesch\u00E4tzter aktueller Preis geteilt durch die Gesamtfl\u00E4che',
|
||||
'Asking price per sqm': 'Angebotspreis geteilt durch die Gesamtfl\u00E4che',
|
||||
'Estimated monthly rent': 'Mittlere monatliche Privatmiete in der Gegend',
|
||||
'Asking rent (monthly)': 'Angebotene Monatsmiete f\u00FCr Mietimmobilien',
|
||||
'Total floor area (sqm)': 'Wohnfl\u00E4che laut EPC-Gutachten',
|
||||
'Number of bedrooms & living rooms': 'Anzahl bewohnbarer R\u00E4ume laut EPC-Gutachten',
|
||||
'Bedrooms': 'Anzahl Schlafzimmer laut Online-Inserat',
|
||||
'Bathrooms': 'Anzahl Badezimmer laut Online-Inserat',
|
||||
'Construction year': 'Gesch\u00E4tztes Baujahr laut EPC',
|
||||
'Date of last transaction': 'Datum des letzten Verkaufs laut Land Registry',
|
||||
'Listing date': 'Datum der Erstver\u00F6ffentlichung des Inserats',
|
||||
'Former council house': 'Ob die Immobilie jemals als Sozialbau erfasst wurde',
|
||||
'Current energy rating': 'Aktuelle EPC-Energieeffizienzklasse (A = beste, G = schlechteste)',
|
||||
'Potential energy rating': 'Potenzielle EPC-Klasse bei Umsetzung aller empfohlenen Ma\u00DFnahmen',
|
||||
'Interior height (m)': 'Durchschnittliche Geschossh\u00F6he laut EPC-Gutachten',
|
||||
'Distance to nearest train or tube station (km)': 'Entfernung zum n\u00E4chsten Bahn- oder U-Bahnhof',
|
||||
'Train or tube stations within 1km': 'Anzahl Bahn- oder U-Bahnh\u00F6fe im Umkreis von 1 km',
|
||||
'Good+ primary schools within 2km': 'Von Ofsted mit Gut oder Hervorragend bewertete Grundschulen im Umkreis von 2 km',
|
||||
'Good+ secondary schools within 2km': 'Von Ofsted mit Gut oder Hervorragend bewertete weiterf\u00FChrende Schulen im Umkreis von 2 km',
|
||||
'Good+ primary schools within 5km': 'Von Ofsted mit Gut oder Hervorragend bewertete Grundschulen im Umkreis von 5 km',
|
||||
'Good+ secondary schools within 5km': 'Von Ofsted mit Gut oder Hervorragend bewertete weiterf\u00FChrende Schulen im Umkreis von 5 km',
|
||||
'Education, Skills and Training Score': 'Bildungsqualit\u00E4tsscore der Gegend (h\u00F6her = besser)',
|
||||
'Income Score (rate)': 'Einkommensbenachteiligungsrate, invertiert (h\u00F6her = weniger benachteiligt)',
|
||||
'Employment Score (rate)': 'Besch\u00E4ftigungsbenachteiligungsrate, invertiert (h\u00F6her = weniger benachteiligt)',
|
||||
'Health Deprivation and Disability Score': 'Gesundheits- und Behinderungsscore (h\u00F6her = bessere Ergebnisse)',
|
||||
'Living Environment Score': 'Qualit\u00E4t der Innen- und Au\u00DFenumgebung (h\u00F6her = besser)',
|
||||
'Indoors Sub-domain Score': 'Wohnqualit\u00E4t und -zustand (h\u00F6her = besser)',
|
||||
'Outdoors Sub-domain Score': 'Luftqualit\u00E4t und Verkehrssicherheit (h\u00F6her = besser)',
|
||||
'Serious crime per 1k residents (avg/yr)': 'Rate schwerer Straftaten pro 1.000 Einwohner pro Jahr',
|
||||
'Minor crime per 1k residents (avg/yr)': 'Rate leichter Straftaten pro 1.000 Einwohner pro Jahr',
|
||||
'Serious crime (avg/yr)': 'Summe der schweren Straftaten-Kategorien pro Jahr',
|
||||
'Minor crime (avg/yr)': 'Summe der leichten Straftaten-Kategorien pro Jahr',
|
||||
'Violence and sexual offences (avg/yr)': 'J\u00E4hrlicher Durchschnitt der Gewalt- und Sexualdelikte in der Gegend',
|
||||
'Burglary (avg/yr)': 'J\u00E4hrlicher Durchschnitt der Einbr\u00FCche in der Gegend',
|
||||
'Robbery (avg/yr)': 'J\u00E4hrlicher Durchschnitt der Raub\u00FCberf\u00E4lle in der Gegend',
|
||||
'Vehicle crime (avg/yr)': 'J\u00E4hrlicher Durchschnitt der Fahrzeugkriminalit\u00E4t in der Gegend',
|
||||
'Anti-social behaviour (avg/yr)': 'J\u00E4hrlicher Durchschnitt des antisozialen Verhaltens in der Gegend',
|
||||
'Criminal damage and arson (avg/yr)': 'J\u00E4hrlicher Durchschnitt der Sachbesch\u00E4digungen und Brandstiftungen in der Gegend',
|
||||
'Other theft (avg/yr)': 'J\u00E4hrlicher Durchschnitt des sonstigen Diebstahls in der Gegend',
|
||||
'Theft from the person (avg/yr)': 'J\u00E4hrlicher Durchschnitt des Taschendiebstahls in der Gegend',
|
||||
'Shoplifting (avg/yr)': 'J\u00E4hrlicher Durchschnitt des Ladendiebstahls in der Gegend',
|
||||
'Bicycle theft (avg/yr)': 'J\u00E4hrlicher Durchschnitt des Fahrraddiebstahls in der Gegend',
|
||||
'Drugs (avg/yr)': 'J\u00E4hrlicher Durchschnitt der Drogendelikte in der Gegend',
|
||||
'Possession of weapons (avg/yr)': 'J\u00E4hrlicher Durchschnitt der Waffenbesitzdelikte in der Gegend',
|
||||
'Public order (avg/yr)': 'J\u00E4hrlicher Durchschnitt der St\u00F6rungen der \u00F6ffentlichen Ordnung in der Gegend',
|
||||
'Other crime (avg/yr)': 'J\u00E4hrlicher Durchschnitt sonstiger Straftaten in der Gegend',
|
||||
'Median age': 'Medianalter der lokalen Bev\u00F6lkerung',
|
||||
'% White': 'Anteil der Bev\u00F6lkerung, der sich als Wei\u00DF identifiziert',
|
||||
'% South Asian': 'Anteil der Bev\u00F6lkerung, der sich als S\u00FCdasiatisch identifiziert',
|
||||
'% Black': 'Anteil der Bev\u00F6lkerung, der sich als Schwarz identifiziert',
|
||||
'% East Asian': 'Anteil der Bev\u00F6lkerung, der sich als Ostasiatisch identifiziert',
|
||||
'% Mixed': 'Anteil der Bev\u00F6lkerung, der sich als gemischt oder mehreren ethnischen Gruppen zugeh\u00F6rig identifiziert',
|
||||
'% Other': 'Anteil der Bev\u00F6lkerung, der sich einer anderen ethnischen Gruppe zuordnet',
|
||||
'Distance to nearest park (km)': 'Entfernung zum n\u00E4chsten Park oder Gr\u00FCnfl\u00E4che',
|
||||
'Number of parks within 2km': 'Anzahl Parks und Gr\u00FCnfl\u00E4chen im Umkreis von 2 km',
|
||||
'Number of restaurants within 2km': 'Anzahl Restaurants und Caf\u00E9s im Umkreis von 2 km',
|
||||
'Number of grocery shops and supermarkets within 2km': 'Anzahl Lebensmittelgesch\u00E4fte und Superm\u00E4rkte im Umkreis von 2 km',
|
||||
'Noise (dB)': 'Stra\u00DFenl\u00E4rmpegel an der Postleitzahl in Dezibel (Lden)',
|
||||
'Max available download speed (Mbps)': 'Maximal verf\u00FCgbare Breitband-Downloadgeschwindigkeit an der Postleitzahl',
|
||||
},
|
||||
zh: {
|
||||
'Listing status': '\u8BE5\u623F\u4EA7\u662F\u5386\u53F2\u9500\u552E\u3001\u5F53\u524D\u5728\u552E\u8FD8\u662F\u51FA\u79DF',
|
||||
'Property type': '\u623F\u4EA7\u7C7B\u578B\uFF1A\u72EC\u7ACB\u5F0F\u3001\u534A\u72EC\u7ACB\u5F0F\u3001\u8054\u6392\u3001\u516C\u5BD3\u6216\u5176\u4ED6',
|
||||
'Leasehold/Freehold': '\u8BE5\u623F\u4EA7\u662F\u79DF\u8D41\u4EA7\u6743\u8FD8\u662F\u6C38\u4E45\u4EA7\u6743',
|
||||
'Last known price': 'Land Registry\u8BB0\u5F55\u7684\u6700\u8FD1\u4E00\u6B21\u552E\u4EF7',
|
||||
'Estimated current price': '\u7ECF\u901A\u80C0\u8C03\u6574\u540E\u7684\u5F53\u524D\u4F30\u8BA1\u4EF7\u503C',
|
||||
'Asking price': '\u5F53\u524D\u5728\u552E\u623F\u4EA7\u7684\u6302\u724C\u4EF7',
|
||||
'Price per sqm': '\u552E\u4EF7\u9664\u4EE5\u603B\u5EFA\u7B51\u9762\u79EF',
|
||||
'Est. price per sqm': '\u4F30\u8BA1\u5F53\u524D\u4EF7\u683C\u9664\u4EE5\u603B\u5EFA\u7B51\u9762\u79EF',
|
||||
'Asking price per sqm': '\u6302\u724C\u4EF7\u9664\u4EE5\u603B\u5EFA\u7B51\u9762\u79EF',
|
||||
'Estimated monthly rent': '\u5F53\u5730\u79C1\u4EBA\u79DF\u8D41\u7684\u4E2D\u4F4D\u6708\u79DF',
|
||||
'Asking rent (monthly)': '\u5F53\u524D\u51FA\u79DF\u623F\u4EA7\u7684\u6302\u724C\u6708\u79DF',
|
||||
'Total floor area (sqm)': 'EPC\u8BC4\u4F30\u7684\u5BA4\u5185\u5EFA\u7B51\u9762\u79EF',
|
||||
'Number of bedrooms & living rooms': 'EPC\u8BC4\u4F30\u7684\u5B9C\u5C45\u623F\u95F4\u6570',
|
||||
'Bedrooms': '\u5728\u7EBF\u623F\u6E90\u4E2D\u7684\u5367\u5BA4\u6570\u91CF',
|
||||
'Bathrooms': '\u5728\u7EBF\u623F\u6E90\u4E2D\u7684\u6D74\u5BA4\u6570\u91CF',
|
||||
'Construction year': 'EPC\u8BC4\u4F30\u7684\u5EFA\u9020\u5E74\u4EFD',
|
||||
'Date of last transaction': 'Land Registry\u8BB0\u5F55\u7684\u6700\u8FD1\u4E00\u6B21\u9500\u552E\u65E5\u671F',
|
||||
'Listing date': '\u623F\u4EA7\u9996\u6B21\u5728\u7EBF\u4E0A\u5E02\u7684\u65E5\u671F',
|
||||
'Former council house': '\u8BE5\u623F\u4EA7\u662F\u5426\u66FE\u88AB\u8BB0\u5F55\u4E3A\u516C\u5171\u4F4F\u623F',
|
||||
'Current energy rating': '\u5F53\u524DEPC\u80FD\u6548\u8BC4\u7EA7\uFF08A = \u6700\u4F73\uFF0CG = \u6700\u5DEE\uFF09',
|
||||
'Potential energy rating': '\u5B9E\u65BD\u6240\u6709\u5EFA\u8BAE\u6539\u8FDB\u540E\u7684\u6F5C\u5728EPC\u8BC4\u7EA7',
|
||||
'Interior height (m)': 'EPC\u8BC4\u4F30\u7684\u5E73\u5747\u5C42\u9AD8',
|
||||
'Distance to nearest train or tube station (km)': '\u5230\u6700\u8FD1\u706B\u8F66\u6216\u5730\u94C1\u7AD9\u7684\u8DDD\u79BB',
|
||||
'Train or tube stations within 1km': '1\u516C\u91CC\u5185\u706B\u8F66\u6216\u5730\u94C1\u7AD9\u7684\u6570\u91CF',
|
||||
'Good+ primary schools within 2km': 'Ofsted\u8BC4\u4E3A\u826F\u597D\u6216\u4F18\u79C0\u76842\u516C\u91CC\u5185\u5C0F\u5B66',
|
||||
'Good+ secondary schools within 2km': 'Ofsted\u8BC4\u4E3A\u826F\u597D\u6216\u4F18\u79C0\u76842\u516C\u91CC\u5185\u4E2D\u5B66',
|
||||
'Good+ primary schools within 5km': 'Ofsted\u8BC4\u4E3A\u826F\u597D\u6216\u4F18\u79C0\u76845\u516C\u91CC\u5185\u5C0F\u5B66',
|
||||
'Good+ secondary schools within 5km': 'Ofsted\u8BC4\u4E3A\u826F\u597D\u6216\u4F18\u79C0\u76845\u516C\u91CC\u5185\u4E2D\u5B66',
|
||||
'Education, Skills and Training Score': '\u5F53\u5730\u6559\u80B2\u8D28\u91CF\u5F97\u5206\uFF08\u8D8A\u9AD8\u8D8A\u597D\uFF09',
|
||||
'Income Score (rate)': '\u6536\u5165\u8D2B\u56F0\u7387\uFF0C\u53CD\u5411\u6307\u6807\uFF08\u8D8A\u9AD8\u8D8A\u4E0D\u8D2B\u56F0\uFF09',
|
||||
'Employment Score (rate)': '\u5C31\u4E1A\u8D2B\u56F0\u7387\uFF0C\u53CD\u5411\u6307\u6807\uFF08\u8D8A\u9AD8\u8D8A\u4E0D\u8D2B\u56F0\uFF09',
|
||||
'Health Deprivation and Disability Score': '\u5065\u5EB7\u4E0E\u6B8B\u969C\u5F97\u5206\uFF08\u8D8A\u9AD8\u5065\u5EB7\u72B6\u51B5\u8D8A\u597D\uFF09',
|
||||
'Living Environment Score': '\u5BA4\u5185\u5916\u73AF\u5883\u8D28\u91CF\uFF08\u8D8A\u9AD8\u8D8A\u597D\uFF09',
|
||||
'Indoors Sub-domain Score': '\u4F4F\u623F\u8D28\u91CF\u548C\u72B6\u51B5\uFF08\u8D8A\u9AD8\u8D8A\u597D\uFF09',
|
||||
'Outdoors Sub-domain Score': '\u7A7A\u6C14\u8D28\u91CF\u548C\u9053\u8DEF\u5B89\u5168\uFF08\u8D8A\u9AD8\u8D8A\u597D\uFF09',
|
||||
'Serious crime per 1k residents (avg/yr)': '\u6BCF\u5343\u4EBA\u6BCF\u5E74\u4E25\u91CD\u72AF\u7F6A\u7387',
|
||||
'Minor crime per 1k residents (avg/yr)': '\u6BCF\u5343\u4EBA\u6BCF\u5E74\u8F7B\u5FAE\u72AF\u7F6A\u7387',
|
||||
'Serious crime (avg/yr)': '\u4E25\u91CD\u72AF\u7F6A\u7C7B\u522B\u5E74\u5EA6\u603B\u8BA1',
|
||||
'Minor crime (avg/yr)': '\u8F7B\u5FAE\u72AF\u7F6A\u7C7B\u522B\u5E74\u5EA6\u603B\u8BA1',
|
||||
'Violence and sexual offences (avg/yr)': '\u8BE5\u5730\u533A\u5E74\u5747\u66B4\u529B\u548C\u6027\u72AF\u7F6A\u6570',
|
||||
'Burglary (avg/yr)': '\u8BE5\u5730\u533A\u5E74\u5747\u5165\u5BA4\u76D7\u7A83\u6570',
|
||||
'Robbery (avg/yr)': '\u8BE5\u5730\u533A\u5E74\u5747\u62A2\u52AB\u6570',
|
||||
'Vehicle crime (avg/yr)': '\u8BE5\u5730\u533A\u5E74\u5747\u8F66\u8F86\u72AF\u7F6A\u6570',
|
||||
'Anti-social behaviour (avg/yr)': '\u8BE5\u5730\u533A\u5E74\u5747\u53CD\u793E\u4F1A\u884C\u4E3A\u6570',
|
||||
'Criminal damage and arson (avg/yr)': '\u8BE5\u5730\u533A\u5E74\u5747\u5211\u4E8B\u6BC1\u574F\u548C\u7EB5\u706B\u6570',
|
||||
'Other theft (avg/yr)': '\u8BE5\u5730\u533A\u5E74\u5747\u5176\u4ED6\u76D7\u7A83\u6570',
|
||||
'Theft from the person (avg/yr)': '\u8BE5\u5730\u533A\u5E74\u5747\u4EBA\u8EAB\u76D7\u7A83\u6570',
|
||||
'Shoplifting (avg/yr)': '\u8BE5\u5730\u533A\u5E74\u5747\u5546\u5E97\u76D7\u7A83\u6570',
|
||||
'Bicycle theft (avg/yr)': '\u8BE5\u5730\u533A\u5E74\u5747\u81EA\u884C\u8F66\u76D7\u7A83\u6570',
|
||||
'Drugs (avg/yr)': '\u8BE5\u5730\u533A\u5E74\u5747\u6BD2\u54C1\u72AF\u7F6A\u6570',
|
||||
'Possession of weapons (avg/yr)': '\u8BE5\u5730\u533A\u5E74\u5747\u975E\u6CD5\u6301\u6709\u6B66\u5668\u6570',
|
||||
'Public order (avg/yr)': '\u8BE5\u5730\u533A\u5E74\u5747\u6270\u4E71\u516C\u5171\u79E9\u5E8F\u6570',
|
||||
'Other crime (avg/yr)': '\u8BE5\u5730\u533A\u5E74\u5747\u5176\u4ED6\u72AF\u7F6A\u6570',
|
||||
'Median age': '\u5F53\u5730\u4EBA\u53E3\u7684\u4E2D\u4F4D\u5E74\u9F84',
|
||||
'% White': '\u767D\u4EBA\u4EBA\u53E3\u6BD4\u4F8B',
|
||||
'% South Asian': '\u5357\u4E9A\u88D4\u4EBA\u53E3\u6BD4\u4F8B',
|
||||
'% Black': '\u9ED1\u4EBA\u4EBA\u53E3\u6BD4\u4F8B',
|
||||
'% East Asian': '\u4E1C\u4E9A\u88D4\u4EBA\u53E3\u6BD4\u4F8B',
|
||||
'% Mixed': '\u6DF7\u8840\u6216\u591A\u65CF\u88D4\u4EBA\u53E3\u6BD4\u4F8B',
|
||||
'% Other': '\u5176\u4ED6\u65CF\u88D4\u4EBA\u53E3\u6BD4\u4F8B',
|
||||
'Distance to nearest park (km)': '\u5230\u6700\u8FD1\u516C\u56ED\u6216\u7EFF\u5730\u7684\u8DDD\u79BB',
|
||||
'Number of parks within 2km': '2\u516C\u91CC\u5185\u516C\u56ED\u548C\u7EFF\u5730\u6570\u91CF',
|
||||
'Number of restaurants within 2km': '2\u516C\u91CC\u5185\u9910\u5385\u548C\u5496\u5561\u9986\u6570\u91CF',
|
||||
'Number of grocery shops and supermarkets within 2km': '2\u516C\u91CC\u5185\u98DF\u54C1\u5E97\u548C\u8D85\u5E02\u6570\u91CF',
|
||||
'Noise (dB)': '\u8BE5\u90AE\u7F16\u7684\u9053\u8DEF\u566A\u97F3\u6C34\u5E73\uFF08\u5206\u8D1D\uFF0CLden\uFF09',
|
||||
'Max available download speed (Mbps)': '\u8BE5\u90AE\u7F16\u53EF\u7528\u7684\u6700\u5927\u5BBD\u5E26\u4E0B\u8F7D\u901F\u5EA6',
|
||||
},
|
||||
hu: {
|
||||
'Listing status': 'Az ingatlan kor\u00E1bbi elad\u00E1sb\u00F3l sz\u00E1rmazik, jelenleg elad\u00F3 vagy kiad\u00F3',
|
||||
'Property type': 'Ingatlant\u00EDpus: k\u00FCl\u00F6n\u00E1ll\u00F3, ikerh\u00E1z, sorh\u00E1z, lak\u00E1s vagy egy\u00E9b',
|
||||
'Leasehold/Freehold': 'Az ingatlan b\u00E9rleti jog\u00FA vagy teljes tulajdon\u00FA',
|
||||
'Last known price': 'A Land Registry-ben r\u00F6gz\u00EDtett utols\u00F3 elad\u00E1si \u00E1r',
|
||||
'Estimated current price': 'Infl\u00E1ci\u00F3val korrig\u00E1lt becs\u00FClt jelenlegi \u00E9rt\u00E9k',
|
||||
'Asking price': 'A jelenleg elad\u00E1sra k\u00EDn\u00E1lt ingatlanok ir\u00E1ny\u00E1ra',
|
||||
'Price per sqm': 'Elad\u00E1si \u00E1r osztva az \u00F6sszes alapter\u00FClettel',
|
||||
'Est. price per sqm': 'Becs\u00FClt jelenlegi \u00E1r osztva az \u00F6sszes alapter\u00FClettel',
|
||||
'Asking price per sqm': 'Ir\u00E1ny\u00E1r osztva az \u00F6sszes alapter\u00FClettel',
|
||||
'Estimated monthly rent': 'A k\u00F6rny\u00E9k medi\u00E1n havi mag\u00E1nb\u00E9rleti d\u00EDja',
|
||||
'Asking rent (monthly)': 'A kiad\u00F3 ingatlanok hirdetett havi b\u00E9rleti d\u00EDja',
|
||||
'Total floor area (sqm)': 'Az EPC felm\u00E9r\u00E9sb\u0151l sz\u00E1rmaz\u00F3 bels\u0151 alapter\u00FClet',
|
||||
'Number of bedrooms & living rooms': 'Lak\u00F3szob\u00E1k sz\u00E1ma az EPC felm\u00E9r\u00E9s alapj\u00E1n',
|
||||
'Bedrooms': 'H\u00E1l\u00F3szob\u00E1k sz\u00E1ma az online hirdet\u00E9s szerint',
|
||||
'Bathrooms': 'F\u00FCrd\u0151szob\u00E1k sz\u00E1ma az online hirdet\u00E9s szerint',
|
||||
'Construction year': 'Becs\u00FClt \u00E9p\u00EDt\u00E9si \u00E9v az EPC alapj\u00E1n',
|
||||
'Date of last transaction': 'Az utols\u00F3 elad\u00E1s d\u00E1tuma a Land Registry szerint',
|
||||
'Listing date': 'Az ingatlan els\u0151 online megjelen\u00E9s\u00E9nek d\u00E1tuma',
|
||||
'Former council house': 'Az ingatlan szerepelt-e valaha \u00F6nkorm\u00E1nyzati lak\u00E1sk\u00E9nt',
|
||||
'Current energy rating': 'Jelenlegi EPC energiabesorol\u00E1s (A = legjobb, G = legrosszabb)',
|
||||
'Potential energy rating': 'Potenci\u00E1lis EPC besorol\u00E1s az \u00F6sszes javasolt fejleszt\u00E9s elv\u00E9gz\u00E9se ut\u00E1n',
|
||||
'Interior height (m)': '\u00C1tlagos belmagass\u00E1g az EPC felm\u00E9r\u00E9s alapj\u00E1n',
|
||||
'Distance to nearest train or tube station (km)': 'T\u00E1vols\u00E1g a legk\u00F6zelebbi vas\u00FAt- vagy metr\u00F3\u00E1llom\u00E1sig',
|
||||
'Train or tube stations within 1km': 'Vas\u00FAt- vagy metr\u00F3\u00E1llom\u00E1sok sz\u00E1ma 1 km-en bel\u00FCl',
|
||||
'Good+ primary schools within 2km': 'Ofsted \u00E1ltal J\u00F3 vagy Kiv\u00E1l\u00F3 min\u0151s\u00EDt\u00E9s\u0171 \u00E1ltal\u00E1nos iskol\u00E1k 2 km-en bel\u00FCl',
|
||||
'Good+ secondary schools within 2km': 'Ofsted \u00E1ltal J\u00F3 vagy Kiv\u00E1l\u00F3 min\u0151s\u00EDt\u00E9s\u0171 k\u00F6z\u00E9piskol\u00E1k 2 km-en bel\u00FCl',
|
||||
'Good+ primary schools within 5km': 'Ofsted \u00E1ltal J\u00F3 vagy Kiv\u00E1l\u00F3 min\u0151s\u00EDt\u00E9s\u0171 \u00E1ltal\u00E1nos iskol\u00E1k 5 km-en bel\u00FCl',
|
||||
'Good+ secondary schools within 5km': 'Ofsted \u00E1ltal J\u00F3 vagy Kiv\u00E1l\u00F3 min\u0151s\u00EDt\u00E9s\u0171 k\u00F6z\u00E9piskol\u00E1k 5 km-en bel\u00FCl',
|
||||
'Education, Skills and Training Score': 'A k\u00F6rny\u00E9k oktat\u00E1si min\u0151s\u00E9gi pontsz\u00E1ma (magasabb = jobb)',
|
||||
'Income Score (rate)': 'J\u00F6vedelmi depriv\u00E1ci\u00F3s r\u00E1ta, invert\u00E1lva (magasabb = kev\u00E9sb\u00E9 h\u00E1tr\u00E1nyos)',
|
||||
'Employment Score (rate)': 'Foglalkoztat\u00E1si depriv\u00E1ci\u00F3s r\u00E1ta, invert\u00E1lva (magasabb = kev\u00E9sb\u00E9 h\u00E1tr\u00E1nyos)',
|
||||
'Health Deprivation and Disability Score': 'Eg\u00E9szs\u00E9g\u00FCgyi \u00E9s fogyat\u00E9koss\u00E1gi pontsz\u00E1m (magasabb = jobb eredm\u00E9nyek)',
|
||||
'Living Environment Score': 'Bels\u0151 \u00E9s k\u00FCls\u0151 k\u00F6rnyezet min\u0151s\u00E9ge (magasabb = jobb)',
|
||||
'Indoors Sub-domain Score': 'Lak\u00E1smin\u0151s\u00E9g \u00E9s \u00E1llapot (magasabb = jobb)',
|
||||
'Outdoors Sub-domain Score': 'Leveg\u0151min\u0151s\u00E9g \u00E9s k\u00F6zleked\u00E9sbiztons\u00E1g (magasabb = jobb)',
|
||||
'Serious crime per 1k residents (avg/yr)': 'S\u00FAlyos b\u0171ncselekm\u00E9nyek ar\u00E1nya 1000 lakosra \u00E9vente',
|
||||
'Minor crime per 1k residents (avg/yr)': 'Kisebb b\u0171ncselekm\u00E9nyek ar\u00E1nya 1000 lakosra \u00E9vente',
|
||||
'Serious crime (avg/yr)': 'S\u00FAlyos b\u0171ncselekm\u00E9nyi kateg\u00F3ri\u00E1k \u00E9ves \u00F6sszes\u00EDt\u00E9se',
|
||||
'Minor crime (avg/yr)': 'Kisebb b\u0171ncselekm\u00E9nyi kateg\u00F3ri\u00E1k \u00E9ves \u00F6sszes\u00EDt\u00E9se',
|
||||
'Violence and sexual offences (avg/yr)': 'Er\u0151szakos \u00E9s szexu\u00E1lis b\u0171ncselekm\u00E9nyek \u00E9ves \u00E1tlaga a k\u00F6rny\u00E9ken',
|
||||
'Burglary (avg/yr)': 'Bet\u00F6r\u00E9sek \u00E9ves \u00E1tlaga a k\u00F6rny\u00E9ken',
|
||||
'Robbery (avg/yr)': 'Rabl\u00E1sok \u00E9ves \u00E1tlaga a k\u00F6rny\u00E9ken',
|
||||
'Vehicle crime (avg/yr)': 'G\u00E9pj\u00E1rm\u0171vel kapcsolatos b\u0171ncselekm\u00E9nyek \u00E9ves \u00E1tlaga a k\u00F6rny\u00E9ken',
|
||||
'Anti-social behaviour (avg/yr)': 'K\u00F6z\u00F6ss\u00E9gellenes magatart\u00E1s \u00E9ves \u00E1tlaga a k\u00F6rny\u00E9ken',
|
||||
'Criminal damage and arson (avg/yr)': 'Rong\u00E1l\u00E1s \u00E9s gy\u00FAjtogat\u00E1s \u00E9ves \u00E1tlaga a k\u00F6rny\u00E9ken',
|
||||
'Other theft (avg/yr)': 'Egy\u00E9b lop\u00E1sok \u00E9ves \u00E1tlaga a k\u00F6rny\u00E9ken',
|
||||
'Theft from the person (avg/yr)': 'Szem\u00E9lyek elleni lop\u00E1sok \u00E9ves \u00E1tlaga a k\u00F6rny\u00E9ken',
|
||||
'Shoplifting (avg/yr)': 'Bolti lop\u00E1sok \u00E9ves \u00E1tlaga a k\u00F6rny\u00E9ken',
|
||||
'Bicycle theft (avg/yr)': 'Ker\u00E9kp\u00E1rlop\u00E1sok \u00E9ves \u00E1tlaga a k\u00F6rny\u00E9ken',
|
||||
'Drugs (avg/yr)': 'K\u00E1b\u00EDt\u00F3szerrel kapcsolatos b\u0171ncselekm\u00E9nyek \u00E9ves \u00E1tlaga a k\u00F6rny\u00E9ken',
|
||||
'Possession of weapons (avg/yr)': 'Fegyvertart\u00E1ssal kapcsolatos b\u0171ncselekm\u00E9nyek \u00E9ves \u00E1tlaga a k\u00F6rny\u00E9ken',
|
||||
'Public order (avg/yr)': 'K\u00F6zrend elleni b\u0171ncselekm\u00E9nyek \u00E9ves \u00E1tlaga a k\u00F6rny\u00E9ken',
|
||||
'Other crime (avg/yr)': 'Egy\u00E9b b\u0171ncselekm\u00E9nyek \u00E9ves \u00E1tlaga a k\u00F6rny\u00E9ken',
|
||||
'Median age': 'A helyi lakoss\u00E1g medi\u00E1n \u00E9letkora',
|
||||
'% White': 'A feh\u00E9rk\u00E9nt azonos\u00EDtott lakoss\u00E1g ar\u00E1nya',
|
||||
'% South Asian': 'A d\u00E9l-\u00E1zsiaiként azonos\u00EDtott lakoss\u00E1g ar\u00E1nya',
|
||||
'% Black': 'A feketek\u00E9nt azonos\u00EDtott lakoss\u00E1g ar\u00E1nya',
|
||||
'% East Asian': 'A kelet-\u00E1zsiaiként azonos\u00EDtott lakoss\u00E1g ar\u00E1nya',
|
||||
'% Mixed': 'A vegyes vagy t\u00F6bb etnikai csoporthoz tartoz\u00F3k\u00E9nt azonos\u00EDtott lakoss\u00E1g ar\u00E1nya',
|
||||
'% Other': 'Az egy\u00E9b etnikai csoportba tartoz\u00F3k\u00E9nt azonos\u00EDtott lakoss\u00E1g ar\u00E1nya',
|
||||
'Distance to nearest park (km)': 'T\u00E1vols\u00E1g a legk\u00F6zelebbi parkig vagy z\u00F6ldter\u00FCletig',
|
||||
'Number of parks within 2km': 'Parkok \u00E9s z\u00F6ldter\u00FCletek sz\u00E1ma 2 km-en bel\u00FCl',
|
||||
'Number of restaurants within 2km': '\u00C9ttermek \u00E9s k\u00E1v\u00E9z\u00F3k sz\u00E1ma 2 km-en bel\u00FCl',
|
||||
'Number of grocery shops and supermarkets within 2km': '\u00C9lelmiszerboltok \u00E9s szupermarketek sz\u00E1ma 2 km-en bel\u00FCl',
|
||||
'Noise (dB)': 'K\u00F6z\u00FAti zajszint az ir\u00E1ny\u00EDt\u00F3sz\u00E1mn\u00E1l decibelben (Lden)',
|
||||
'Max available download speed (Mbps)': 'Az ir\u00E1ny\u00EDt\u00F3sz\u00E1mn\u00E1l el\u00E9rhet\u0151 maxim\u00E1lis sz\u00E9less\u00E1v\u00FA let\u00F6lt\u00E9si sebess\u00E9g',
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* Translate a feature description.
|
||||
* - English: returns the server-provided description (single source of truth)
|
||||
* - Other languages: looks up by feature name, falls back to English if missing
|
||||
*/
|
||||
export function tsDesc(featureName: string, englishFromServer: string): string {
|
||||
const lang = i18n.language;
|
||||
if (lang === 'en') return englishFromServer;
|
||||
return descriptions[lang]?.[featureName] ?? englishFromServer;
|
||||
}
|
||||
11
frontend/src/i18n/i18next.d.ts
vendored
Normal file
11
frontend/src/i18n/i18next.d.ts
vendored
Normal file
|
|
@ -0,0 +1,11 @@
|
|||
import 'i18next';
|
||||
import type en from './locales/en';
|
||||
|
||||
declare module 'i18next' {
|
||||
interface CustomTypeOptions {
|
||||
defaultNS: 'translation';
|
||||
resources: {
|
||||
translation: typeof en;
|
||||
};
|
||||
}
|
||||
}
|
||||
64
frontend/src/i18n/index.ts
Normal file
64
frontend/src/i18n/index.ts
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
import i18n from 'i18next';
|
||||
import { initReactI18next } from 'react-i18next';
|
||||
import en from './locales/en';
|
||||
import de from './locales/de';
|
||||
import fr from './locales/fr';
|
||||
import hu from './locales/hu';
|
||||
import zh from './locales/zh';
|
||||
|
||||
export const SUPPORTED_LANGUAGES = [
|
||||
{ code: 'en', label: 'English', flag: '\uD83C\uDDEC\uD83C\uDDE7' },
|
||||
{ code: 'fr', label: 'Fran\u00E7ais', flag: '\uD83C\uDDEB\uD83C\uDDF7' },
|
||||
{ code: 'de', label: 'Deutsch', flag: '\uD83C\uDDE9\uD83C\uDDEA' },
|
||||
{ code: 'hu', label: 'Magyar', flag: '\uD83C\uDDED\uD83C\uDDFA' },
|
||||
{ code: 'zh', label: '\u4E2D\u6587', flag: '\uD83C\uDDE8\uD83C\uDDF3' },
|
||||
] as const;
|
||||
|
||||
export type LanguageCode = (typeof SUPPORTED_LANGUAGES)[number]['code'];
|
||||
|
||||
const supportedCodes: Set<string> = new Set(SUPPORTED_LANGUAGES.map((l) => l.code));
|
||||
|
||||
function detectLanguage(): string {
|
||||
// 1. Explicit user choice (persisted from the language dropdown)
|
||||
const stored = localStorage.getItem('language');
|
||||
if (stored && supportedCodes.has(stored)) return stored;
|
||||
|
||||
// 2. Browser preference (navigator.languages falls back to navigator.language)
|
||||
for (const tag of navigator.languages ?? [navigator.language]) {
|
||||
// Match full tag first (e.g. "zh-CN" → "zh"), then just the prefix
|
||||
const lower = tag.toLowerCase();
|
||||
if (supportedCodes.has(lower)) return lower;
|
||||
const prefix = lower.split('-')[0];
|
||||
if (supportedCodes.has(prefix)) return prefix;
|
||||
}
|
||||
|
||||
return 'en';
|
||||
}
|
||||
|
||||
const initialLang = detectLanguage();
|
||||
|
||||
i18n.use(initReactI18next).init({
|
||||
resources: {
|
||||
en: { translation: en },
|
||||
fr: { translation: fr },
|
||||
de: { translation: de },
|
||||
hu: { translation: hu },
|
||||
zh: { translation: zh },
|
||||
},
|
||||
lng: initialLang,
|
||||
fallbackLng: 'en',
|
||||
interpolation: {
|
||||
escapeValue: false, // React already escapes
|
||||
},
|
||||
});
|
||||
|
||||
/**
|
||||
* Translate a key that is computed at runtime (not a literal).
|
||||
* Bypasses the strict type checking on t() for dynamic key construction.
|
||||
*/
|
||||
export function tDynamic(key: string): string {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
return (i18n.t as any)(key);
|
||||
}
|
||||
|
||||
export default i18n;
|
||||
|
|
@ -591,6 +591,42 @@ const hu: Translations = {
|
|||
savedProperty: 'Mentve',
|
||||
},
|
||||
|
||||
// ── Format / Time ──────────────────────────────────
|
||||
format: {
|
||||
justNow: 'az im\u00E9nt',
|
||||
minutesAgo: '{{count}} perce',
|
||||
hoursAgo: '{{count}} \u00F3r\u00E1ja',
|
||||
daysAgo: '{{count}} napja',
|
||||
nFilters: '{{count}} sz\u0171r\u0151',
|
||||
noFilters: 'Nincs sz\u0171r\u0151',
|
||||
poiCategory: '{{count}} POI-kateg\u00F3ria',
|
||||
poiCategories: '{{count}} POI-kateg\u00F3ria',
|
||||
travelDestination: '{{count}} utaz\u00E1si c\u00E9l',
|
||||
travelDestinations: '{{count}} utaz\u00E1si c\u00E9l',
|
||||
propertiesMatch: '{{count}} ingatlan megfelel',
|
||||
setFilters: '{{count}} sz\u0171r\u0151 be\u00E1ll\u00EDt\u00E1sa: {{list}}',
|
||||
noFiltersSet: 'Nincs sz\u0171r\u0151 be\u00E1ll\u00EDtva',
|
||||
toDestination: '{{mode}} ide: {{label}} {{bounds}}',
|
||||
lessThanMin: '< {{max}} perc',
|
||||
moreThanMin: '> {{min}} perc',
|
||||
},
|
||||
|
||||
// ── Tutorial ──────────────────────────────────────
|
||||
tutorial: {
|
||||
step1Title: 'Mondja el a t\u00E9rk\u00E9pnek, mi fontos',
|
||||
step1Content: '\u00C1ll\u00EDtsa be a k\u00F6lts\u00E9gvet\u00E9st, maximalis ingaz\u00E1si id\u0151t, iskola min\u0151s\u00E9get \u00E9s b\u0171n\u00F6z\u00E9si k\u00FAsz\u00F6b\u00F6t. Ami \u00D6nnek fontos. Csak a megfelel\u0151 ter\u00FCletek maradnak kiemelve. Haszn\u00E1lja a szem ikont b\u00E1rmely jellemz\u0151 szerinti sz\u00EDnez\u00E9shez.',
|
||||
step2Title: 'Vagy egyszer\u0171en \u00EDrja le',
|
||||
step2Content: '\u00CDrja le magyarul, mit keres, p\u00E9ld\u00E1ul \u201Ecsendes ter\u00FClet j\u00F3 iskol\u00E1k k\u00F6zel\u00E9ben \u00A3400k alatt\u201D, \u00E9s be\u00E1ll\u00EDtjuk a sz\u0171r\u0151ket \u00D6nnek.',
|
||||
step3Title: 'Fedezze fel, mi van odakint',
|
||||
step3Content: 'G\u00F6rgessen \u00E9s nagy\u00EDtson Anglia-szerte. Kattintson b\u00E1rmely sz\u00EDnes ter\u00FCletre a b\u0171n\u00F6z\u00E9s, iskol\u00E1k, \u00E1rak, sz\u00E9less\u00E1v, zaj \u00E9s egy\u00E9b adatok megtekint\u00E9s\u00E9hez.',
|
||||
step4Title: 'Ugr\u00E1s egy helyre',
|
||||
step4Content: 'Keressen r\u00E1 b\u00E1rmely helyre vagy ir\u00E1ny\u00EDt\u00F3sz\u00E1mra, hogy azonnal odajusson.',
|
||||
step5Title: 'Mer\u00FClj\u00F6n el a r\u00E9szletekben',
|
||||
step5Content: 'Tekintse meg a ter\u00FCleti statisztik\u00E1kat, hisztogramokat \u00E9s az egyes ingatlanadatokat: \u00E1rak, alapter\u00FClet, energetikai besorol\u00E1s \u00E9s t\u00F6bb.',
|
||||
step6Title: 'Mi van a k\u00F6zelben?',
|
||||
step6Content: 'Kapcsolja be az iskol\u00E1kat, \u00FCzleteket, \u00E1llom\u00E1sokat, parkokat \u00E9s \u00E9ttermeket a t\u00E9rk\u00E9pen, hogy l\u00E1ssa, mi \u00E9rhet\u0151 el.',
|
||||
},
|
||||
|
||||
// ── Server-derived values ──────────────────────────
|
||||
// Keyed by the English server value. ts() looks up translations at display time.
|
||||
// The English keys MUST match exactly what the API returns.
|
||||
|
|
|
|||
|
|
@ -590,6 +590,42 @@ const zh: Translations = {
|
|||
savedProperty: '已收藏',
|
||||
},
|
||||
|
||||
// ── Format / Time ──────────────────────────────────
|
||||
format: {
|
||||
justNow: '\u521A\u521A',
|
||||
minutesAgo: '{{count}}\u5206\u949F\u524D',
|
||||
hoursAgo: '{{count}}\u5C0F\u65F6\u524D',
|
||||
daysAgo: '{{count}}\u5929\u524D',
|
||||
nFilters: '{{count}} \u4E2A\u7B5B\u9009',
|
||||
noFilters: '\u65E0\u7B5B\u9009',
|
||||
poiCategory: '{{count}} \u4E2A POI \u7C7B\u522B',
|
||||
poiCategories: '{{count}} \u4E2A POI \u7C7B\u522B',
|
||||
travelDestination: '{{count}} \u4E2A\u51FA\u884C\u76EE\u7684\u5730',
|
||||
travelDestinations: '{{count}} \u4E2A\u51FA\u884C\u76EE\u7684\u5730',
|
||||
propertiesMatch: '{{count}} \u5957\u623F\u4EA7\u7B26\u5408',
|
||||
setFilters: '\u8BBE\u7F6E {{count}} \u4E2A\u7B5B\u9009\uFF1A{{list}}',
|
||||
noFiltersSet: '\u672A\u8BBE\u7F6E\u7B5B\u9009',
|
||||
toDestination: '{{mode}}\u5230 {{label}} {{bounds}}',
|
||||
lessThanMin: '< {{max}} \u5206\u949F',
|
||||
moreThanMin: '> {{min}} \u5206\u949F',
|
||||
},
|
||||
|
||||
// ── Tutorial ──────────────────────────────────────
|
||||
tutorial: {
|
||||
step1Title: '\u544A\u8BC9\u5730\u56FE\u4EC0\u4E48\u91CD\u8981',
|
||||
step1Content: '\u8BBE\u7F6E\u9884\u7B97\u3001\u901A\u52E4\u4E0A\u9650\u3001\u5B66\u6821\u8D28\u91CF\u3001\u72AF\u7F6A\u95E8\u69DB\u3002\u60A8\u5173\u5FC3\u7684\u4E00\u5207\u3002\u53EA\u6709\u7B26\u5408\u6761\u4EF6\u7684\u533A\u57DF\u4F1A\u4FDD\u6301\u9AD8\u4EAE\u3002\u4F7F\u7528\u773C\u775B\u56FE\u6807\u6309\u4EFB\u610F\u7279\u5F81\u7740\u8272\u3002',
|
||||
step2Title: '\u6216\u8005\u76F4\u63A5\u63CF\u8FF0',
|
||||
step2Content: '\u7528\u4E2D\u6587\u8F93\u5165\u60A8\u7684\u9700\u6C42\uFF0C\u4F8B\u5982\u201C\u5B89\u9759\u7684\u5730\u533A\uFF0C\u9760\u8FD1\u597D\u5B66\u6821\uFF0C\u00A3400k \u4EE5\u4E0B\u201D\uFF0C\u6211\u4EEC\u4F1A\u4E3A\u60A8\u8BBE\u7F6E\u7B5B\u9009\u3002',
|
||||
step3Title: '\u63A2\u7D22\u73B0\u6709\u4F4F\u5B85',
|
||||
step3Content: '\u5728\u82F1\u683C\u5170\u5404\u5730\u5E73\u79FB\u548C\u7F29\u653E\u3002\u70B9\u51FB\u4EFB\u4F55\u5F69\u8272\u533A\u57DF\u67E5\u770B\u72AF\u7F6A\u3001\u5B66\u6821\u3001\u4EF7\u683C\u3001\u5BBD\u5E26\u3001\u566A\u97F3\u7B49\u4FE1\u606F\u3002',
|
||||
step4Title: '\u8DF3\u8F6C\u5230\u67D0\u4E2A\u4F4D\u7F6E',
|
||||
step4Content: '\u641C\u7D22\u4EFB\u4F55\u5730\u70B9\u6216\u90AE\u7F16\uFF0C\u5373\u53EF\u76F4\u63A5\u8DF3\u8F6C\u3002',
|
||||
step5Title: '\u6DF1\u5165\u4E86\u89E3\u7EC6\u8282',
|
||||
step5Content: '\u67E5\u770B\u533A\u57DF\u7EDF\u8BA1\u3001\u76F4\u65B9\u56FE\u548C\u5355\u4E2A\u623F\u4EA7\u8BB0\u5F55\uFF1A\u4EF7\u683C\u3001\u5EFA\u7B51\u9762\u79EF\u3001\u80FD\u6548\u8BC4\u7EA7\u7B49\u3002',
|
||||
step6Title: '\u9644\u8FD1\u6709\u4EC0\u4E48\uFF1F',
|
||||
step6Content: '\u5728\u5730\u56FE\u4E0A\u5F00\u542F\u5B66\u6821\u3001\u5546\u5E97\u3001\u8F66\u7AD9\u3001\u516C\u56ED\u548C\u9910\u5385\u56FE\u5C42\uFF0C\u67E5\u770B\u5468\u8FB9\u8BBE\u65BD\u3002',
|
||||
},
|
||||
|
||||
// ── Server-derived values ──────────────────────────
|
||||
// Keyed by the English server value. ts() looks up translations at display time.
|
||||
// The English keys MUST match exactly what the API returns.
|
||||
|
|
|
|||
15
frontend/src/i18n/server.ts
Normal file
15
frontend/src/i18n/server.ts
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
import i18n from 'i18next';
|
||||
|
||||
/**
|
||||
* Translate a server-derived value (feature name, enum value, group name, etc.).
|
||||
* Looks up `server.${value}` in the current locale. Falls back to the original
|
||||
* English string if no translation exists, so unknown values are safe.
|
||||
*/
|
||||
export function ts(value: string): string {
|
||||
const key = `server.${value}`;
|
||||
const result = i18n.t(key, { defaultValue: value });
|
||||
return typeof result === 'string' ? result : value;
|
||||
}
|
||||
|
||||
// Re-export tsDesc from descriptions.ts for convenience
|
||||
export { tsDesc } from './descriptions';
|
||||
Loading…
Add table
Add a link
Reference in a new issue