Key Cities (gated): the map, list, tables and posters speak the reader's language
The last bundle of the L1 pass: key-cities had no i18n at all though its entry installs it. A new
keyCities area (38 keys, all 11 locales) carries the map title, band legend, caveats, the city
sheet's labels, the list's intro, filters and section lines, the data tables' title, intro, tabs and
loading line, and the poster wall's heading, tag, nouns and "coming soon" message. Unnamed places
keep showing coordinates, now inside a translated phrase. Counts use a "label: n" form outside English
and numbers keep their existing format (numerals held). cities-map's script message goes through a
guarded useI18n with the English catalog as fallback.
check:i18n-parity PASS; placeholders match English in every locale; the bundle builds.
A library catalog change: studio lands it (rule 5B).
needs eyes: key-cities (gated) with ?lang=ar: the map legend, a city sheet, and the list.
(cherry picked from commit 7d4da13721)
This commit is contained in:
parent
7b1e64eaba
commit
5285574259
15 changed files with 630 additions and 34 deletions
54
library/i18n/locales/ar/keyCities.json
Normal file
54
library/i18n/locales/ar/keyCities.json
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
{
|
||||
"map": {
|
||||
"title": "حيث تعيش الشعوب غير المُبشَّرة",
|
||||
"bands": {
|
||||
"named": "مركز مُسمّى",
|
||||
"multi": "متعدد الشعوب",
|
||||
"single": "شعب واحد"
|
||||
},
|
||||
"note": "النقطة عنقود من مراكز الشعوب ضمن نحو 25 كم، وليست حدودًا بلدية. النقاط المُسمّاة مأخوذة من معجم جغرافي موثّق.",
|
||||
"unnamed": "موقع بلا اسم — {lat}، {lng}",
|
||||
"close": "إغلاق",
|
||||
"country": "الدولة",
|
||||
"admin": "المنطقة الإدارية",
|
||||
"peopleGroups": "الشعوب",
|
||||
"upgPopulation": "سكان الشعوب غير المُبشَّرة",
|
||||
"internet": "الإنترنت في الدولة",
|
||||
"unknown": "غير معروف",
|
||||
"pgHere": "الشعوب هنا",
|
||||
"languages": "اللغات",
|
||||
"sheetNote": "عنقود من مراكز الشعوب ضمن نحو 25 كم، وليس حدودًا بلدية. النقاط المُسمّاة مأخوذة من معجم جغرافي موثّق (Nominatim/OSM)؛ والنقاط بلا اسم تُظهر الإحداثيات بدل اسم مختلَق.",
|
||||
"national": "أرقام الإنترنت وطنية.",
|
||||
"engineMissing": "تعذّر تحميل محرك الخريطة."
|
||||
},
|
||||
"list": {
|
||||
"title": "المدن الرئيسية",
|
||||
"intro": "حيث تعيش الشعوب غير المُبشَّرة: مراكز سكانية مُسمّاة من معجم جغرافي موثّق: {named}، ضمن عناقيد محددة الموقع: {clusters}.",
|
||||
"filters": {
|
||||
"named": "المراكز السكانية المُسمّاة",
|
||||
"multi": "عناقيد متعددة الشعوب",
|
||||
"all": "كل المواقع"
|
||||
},
|
||||
"locations": "المواقع: {n}",
|
||||
"peopleGroups": "الشعوب: {n}"
|
||||
},
|
||||
"tables": {
|
||||
"title": "بيانات المدن الرئيسية",
|
||||
"intro": "كل مركز محدد الموقع، واللغات المستخدمة فيه، والقنوات التي تصل إليه. رتّب أي جدول وصفّه وصدّره؛ لكل جدول مصادره وحدوده.",
|
||||
"tabs": {
|
||||
"cities": "المدن الرئيسية",
|
||||
"langcity": "اللغات هنا",
|
||||
"languages": "حسب الدولة",
|
||||
"operators": "مزودو الإنترنت والاتصالات",
|
||||
"messaging": "تطبيقات المراسلة"
|
||||
},
|
||||
"loading": "جارٍ تحميل {name}…"
|
||||
},
|
||||
"posters": {
|
||||
"heading": "ملصقات المدن الرئيسية",
|
||||
"tag": "التعبئة للصلاة",
|
||||
"itemNoun": "مدينة",
|
||||
"itemNounPlural": "مدن",
|
||||
"soon": "قريبًا: قائمة صلاة لكل مدينة تذكر كل شعب غير مُبشَّر فيها."
|
||||
}
|
||||
}
|
||||
54
library/i18n/locales/de/keyCities.json
Normal file
54
library/i18n/locales/de/keyCities.json
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
{
|
||||
"map": {
|
||||
"title": "Wo die unerreichten Volksgruppen leben",
|
||||
"bands": {
|
||||
"named": "benanntes Zentrum",
|
||||
"multi": "mehrere Gruppen",
|
||||
"single": "eine Gruppe"
|
||||
},
|
||||
"note": "Ein Punkt ist ein Cluster von Volksgruppen-Mittelpunkten im Umkreis von ~25 km, keine Gemeindegrenze. Benannte Punkte stammen aus einem belegten Ortsverzeichnis.",
|
||||
"unnamed": "unbenannter Ort — {lat}, {lng}",
|
||||
"close": "Schließen",
|
||||
"country": "Land",
|
||||
"admin": "Verwaltungsgebiet",
|
||||
"peopleGroups": "Volksgruppen",
|
||||
"upgPopulation": "UPG-Bevölkerung",
|
||||
"internet": "Internet im Land",
|
||||
"unknown": "unbekannt",
|
||||
"pgHere": "Volksgruppen hier",
|
||||
"languages": "Sprachen",
|
||||
"sheetNote": "Ein Cluster von Volksgruppen-Mittelpunkten im Umkreis von ~25 km, keine Gemeindegrenze. Benannte Punkte stammen aus einem belegten Ortsverzeichnis (Nominatim/OSM); unbenannte zeigen Koordinaten statt eines erfundenen Ortsnamens.",
|
||||
"national": "Internetzahlen sind NATIONAL.",
|
||||
"engineMissing": "Die Karten-Engine konnte nicht geladen werden."
|
||||
},
|
||||
"list": {
|
||||
"title": "Schlüsselstädte",
|
||||
"intro": "Wo die unerreichten Volksgruppen leben: benannte Bevölkerungszentren aus einem belegten Ortsverzeichnis: {named}, in lokalisierten Clustern: {clusters}.",
|
||||
"filters": {
|
||||
"named": "Benannte Bevölkerungszentren",
|
||||
"multi": "Cluster mit mehreren Gruppen",
|
||||
"all": "Alle Orte"
|
||||
},
|
||||
"locations": "Orte: {n}",
|
||||
"peopleGroups": "Volksgruppen: {n}"
|
||||
},
|
||||
"tables": {
|
||||
"title": "Daten der Schlüsselstädte",
|
||||
"intro": "Jedes lokalisierte Zentrum, die dort gesprochenen Sprachen und die Kanäle, die es erreichen. Jede Tabelle lässt sich sortieren, filtern und exportieren; jede führt ihre eigenen Quellen und Grenzen.",
|
||||
"tabs": {
|
||||
"cities": "Schlüsselstädte",
|
||||
"langcity": "Sprachen hier",
|
||||
"languages": "Nach Land",
|
||||
"operators": "Internetanbieter & Netzbetreiber",
|
||||
"messaging": "Messenger"
|
||||
},
|
||||
"loading": "{name} wird geladen…"
|
||||
},
|
||||
"posters": {
|
||||
"heading": "Poster der Schlüsselstädte",
|
||||
"tag": "Gebetsmobilisierung",
|
||||
"itemNoun": "Stadt",
|
||||
"itemNounPlural": "Städte",
|
||||
"soon": "Demnächst: eine Gebetsliste für jede Stadt, die jede unerreichte Volksgruppe darin nennt."
|
||||
}
|
||||
}
|
||||
54
library/i18n/locales/en/keyCities.json
Normal file
54
library/i18n/locales/en/keyCities.json
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
{
|
||||
"map": {
|
||||
"title": "Where the unengaged people groups live",
|
||||
"bands": {
|
||||
"named": "named centre",
|
||||
"multi": "multi-group",
|
||||
"single": "single group"
|
||||
},
|
||||
"note": "A point is a cluster of people-group centroids within ~25 km, not a municipal boundary. Named points come from a cited gazetteer.",
|
||||
"unnamed": "unnamed location — {lat}, {lng}",
|
||||
"close": "Close",
|
||||
"country": "Country",
|
||||
"admin": "Admin area",
|
||||
"peopleGroups": "People groups",
|
||||
"upgPopulation": "UPG population",
|
||||
"internet": "Country internet",
|
||||
"unknown": "unknown",
|
||||
"pgHere": "People groups here",
|
||||
"languages": "Languages",
|
||||
"sheetNote": "A cluster of people-group centroids within ~25 km, not a municipal boundary. Named points come from a cited gazetteer (Nominatim/OSM); unnamed ones show coordinates rather than an invented place name.",
|
||||
"national": "Internet figures are NATIONAL.",
|
||||
"engineMissing": "The map engine could not be loaded."
|
||||
},
|
||||
"list": {
|
||||
"title": "Key Cities",
|
||||
"intro": "Where the unengaged people groups live: {named} population centres named from a cited gazetteer, across {clusters} located clusters.",
|
||||
"filters": {
|
||||
"named": "Named population centres",
|
||||
"multi": "Multi-group clusters",
|
||||
"all": "All locations"
|
||||
},
|
||||
"locations": "locations: {n}",
|
||||
"peopleGroups": "people groups: {n}"
|
||||
},
|
||||
"tables": {
|
||||
"title": "Key Cities Data",
|
||||
"intro": "Every located centre, the languages spoken there, and the channels that reach them. Sort, filter and export any table; each carries its own sources and limits.",
|
||||
"tabs": {
|
||||
"cities": "Key Cities",
|
||||
"langcity": "Languages Here",
|
||||
"languages": "By Country",
|
||||
"operators": "ISPs & Carriers",
|
||||
"messaging": "Messaging Apps"
|
||||
},
|
||||
"loading": "Loading {name}…"
|
||||
},
|
||||
"posters": {
|
||||
"heading": "Key City Posters",
|
||||
"tag": "Prayer Mobilization",
|
||||
"itemNoun": "city",
|
||||
"itemNounPlural": "cities",
|
||||
"soon": "Coming soon: a prayer list for each city, naming every unengaged people group in it."
|
||||
}
|
||||
}
|
||||
54
library/i18n/locales/es/keyCities.json
Normal file
54
library/i18n/locales/es/keyCities.json
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
{
|
||||
"map": {
|
||||
"title": "Dónde viven los pueblos no alcanzados",
|
||||
"bands": {
|
||||
"named": "centro con nombre",
|
||||
"multi": "varios pueblos",
|
||||
"single": "un pueblo"
|
||||
},
|
||||
"note": "Un punto es un grupo de centroides de pueblos en ~25 km, no un límite municipal. Los puntos con nombre provienen de un nomenclátor citado.",
|
||||
"unnamed": "lugar sin nombre — {lat}, {lng}",
|
||||
"close": "Cerrar",
|
||||
"country": "País",
|
||||
"admin": "Área administrativa",
|
||||
"peopleGroups": "Pueblos",
|
||||
"upgPopulation": "Población UPG",
|
||||
"internet": "Internet del país",
|
||||
"unknown": "desconocido",
|
||||
"pgHere": "Pueblos aquí",
|
||||
"languages": "Idiomas",
|
||||
"sheetNote": "Un grupo de centroides de pueblos en ~25 km, no un límite municipal. Los puntos con nombre provienen de un nomenclátor citado (Nominatim/OSM); los sin nombre muestran coordenadas en lugar de un nombre inventado.",
|
||||
"national": "Las cifras de internet son NACIONALES.",
|
||||
"engineMissing": "No se pudo cargar el motor del mapa."
|
||||
},
|
||||
"list": {
|
||||
"title": "Ciudades clave",
|
||||
"intro": "Dónde viven los pueblos no alcanzados: centros de población con nombre de un nomenclátor citado: {named}, en grupos ubicados: {clusters}.",
|
||||
"filters": {
|
||||
"named": "Centros de población con nombre",
|
||||
"multi": "Grupos de varios pueblos",
|
||||
"all": "Todos los lugares"
|
||||
},
|
||||
"locations": "lugares: {n}",
|
||||
"peopleGroups": "pueblos: {n}"
|
||||
},
|
||||
"tables": {
|
||||
"title": "Datos de ciudades clave",
|
||||
"intro": "Cada centro ubicado, los idiomas que se hablan allí y los canales que lo alcanzan. Ordena, filtra y exporta cualquier tabla; cada una indica sus fuentes y límites.",
|
||||
"tabs": {
|
||||
"cities": "Ciudades clave",
|
||||
"langcity": "Idiomas aquí",
|
||||
"languages": "Por país",
|
||||
"operators": "Proveedores y operadores",
|
||||
"messaging": "Mensajería"
|
||||
},
|
||||
"loading": "Cargando {name}…"
|
||||
},
|
||||
"posters": {
|
||||
"heading": "Carteles de ciudades clave",
|
||||
"tag": "Movilización de oración",
|
||||
"itemNoun": "ciudad",
|
||||
"itemNounPlural": "ciudades",
|
||||
"soon": "Próximamente: una lista de oración para cada ciudad, con cada pueblo no alcanzado que vive en ella."
|
||||
}
|
||||
}
|
||||
54
library/i18n/locales/fr/keyCities.json
Normal file
54
library/i18n/locales/fr/keyCities.json
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
{
|
||||
"map": {
|
||||
"title": "Où vivent les peuples non atteints",
|
||||
"bands": {
|
||||
"named": "centre nommé",
|
||||
"multi": "plusieurs peuples",
|
||||
"single": "un seul peuple"
|
||||
},
|
||||
"note": "Un point est un regroupement de centroïdes de peuples dans un rayon d’environ 25 km, pas une limite municipale. Les points nommés proviennent d’un répertoire géographique cité.",
|
||||
"unnamed": "lieu sans nom — {lat}, {lng}",
|
||||
"close": "Fermer",
|
||||
"country": "Pays",
|
||||
"admin": "Zone administrative",
|
||||
"peopleGroups": "Peuples",
|
||||
"upgPopulation": "Population UPG",
|
||||
"internet": "Internet du pays",
|
||||
"unknown": "inconnu",
|
||||
"pgHere": "Peuples ici",
|
||||
"languages": "Langues",
|
||||
"sheetNote": "Un regroupement de centroïdes de peuples dans un rayon d’environ 25 km, pas une limite municipale. Les points nommés proviennent d’un répertoire géographique cité (Nominatim/OSM) ; les points sans nom affichent des coordonnées plutôt qu’un nom inventé.",
|
||||
"national": "Les chiffres Internet sont NATIONAUX.",
|
||||
"engineMissing": "Le moteur de carte n’a pas pu être chargé."
|
||||
},
|
||||
"list": {
|
||||
"title": "Villes clés",
|
||||
"intro": "Où vivent les peuples non atteints : centres de population nommés d’après un répertoire cité : {named}, sur des regroupements localisés : {clusters}.",
|
||||
"filters": {
|
||||
"named": "Centres de population nommés",
|
||||
"multi": "Regroupements de plusieurs peuples",
|
||||
"all": "Tous les lieux"
|
||||
},
|
||||
"locations": "lieux : {n}",
|
||||
"peopleGroups": "peuples : {n}"
|
||||
},
|
||||
"tables": {
|
||||
"title": "Données des villes clés",
|
||||
"intro": "Chaque centre localisé, les langues qu’on y parle et les canaux qui l’atteignent. Triez, filtrez et exportez chaque tableau ; chacun indique ses sources et ses limites.",
|
||||
"tabs": {
|
||||
"cities": "Villes clés",
|
||||
"langcity": "Langues ici",
|
||||
"languages": "Par pays",
|
||||
"operators": "FAI et opérateurs",
|
||||
"messaging": "Messageries"
|
||||
},
|
||||
"loading": "Chargement de {name}…"
|
||||
},
|
||||
"posters": {
|
||||
"heading": "Affiches des villes clés",
|
||||
"tag": "Mobilisation à la prière",
|
||||
"itemNoun": "ville",
|
||||
"itemNounPlural": "villes",
|
||||
"soon": "Bientôt : une liste de prière pour chaque ville, nommant chaque peuple non atteint qui y vit."
|
||||
}
|
||||
}
|
||||
54
library/i18n/locales/hi/keyCities.json
Normal file
54
library/i18n/locales/hi/keyCities.json
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
{
|
||||
"map": {
|
||||
"title": "अपहुँचे जनसमूह कहाँ रहते हैं",
|
||||
"bands": {
|
||||
"named": "नामित केंद्र",
|
||||
"multi": "कई जनसमूह",
|
||||
"single": "एक जनसमूह"
|
||||
},
|
||||
"note": "एक बिंदु लगभग 25 किमी के भीतर जनसमूह केंद्रों का समूह है, नगरपालिका सीमा नहीं। नामित बिंदु एक उद्धृत भौगोलिक सूची से लिए गए हैं।",
|
||||
"unnamed": "बिना नाम का स्थान — {lat}, {lng}",
|
||||
"close": "बंद करें",
|
||||
"country": "देश",
|
||||
"admin": "प्रशासनिक क्षेत्र",
|
||||
"peopleGroups": "जनसमूह",
|
||||
"upgPopulation": "UPG जनसंख्या",
|
||||
"internet": "देश में इंटरनेट",
|
||||
"unknown": "अज्ञात",
|
||||
"pgHere": "यहाँ के जनसमूह",
|
||||
"languages": "भाषाएँ",
|
||||
"sheetNote": "लगभग 25 किमी के भीतर जनसमूह केंद्रों का समूह, नगरपालिका सीमा नहीं। नामित बिंदु एक उद्धृत भौगोलिक सूची (Nominatim/OSM) से हैं; बिना नाम वाले बिंदु गढ़े हुए नाम के बजाय निर्देशांक दिखाते हैं।",
|
||||
"national": "इंटरनेट के आँकड़े राष्ट्रीय हैं।",
|
||||
"engineMissing": "नक्शे का इंजन लोड नहीं हो सका।"
|
||||
},
|
||||
"list": {
|
||||
"title": "मुख्य शहर",
|
||||
"intro": "अपहुँचे जनसमूह कहाँ रहते हैं: उद्धृत भौगोलिक सूची से नामित जनसंख्या केंद्र: {named}, स्थित समूहों में: {clusters}।",
|
||||
"filters": {
|
||||
"named": "नामित जनसंख्या केंद्र",
|
||||
"multi": "कई जनसमूहों वाले समूह",
|
||||
"all": "सभी स्थान"
|
||||
},
|
||||
"locations": "स्थान: {n}",
|
||||
"peopleGroups": "जनसमूह: {n}"
|
||||
},
|
||||
"tables": {
|
||||
"title": "मुख्य शहरों का डेटा",
|
||||
"intro": "हर स्थित केंद्र, वहाँ बोली जाने वाली भाषाएँ, और उन तक पहुँचने वाले माध्यम। किसी भी तालिका को क्रमबद्ध, फ़िल्टर और निर्यात करें; हर तालिका अपने स्रोत और सीमाएँ साथ रखती है।",
|
||||
"tabs": {
|
||||
"cities": "मुख्य शहर",
|
||||
"langcity": "यहाँ की भाषाएँ",
|
||||
"languages": "देश के अनुसार",
|
||||
"operators": "इंटरनेट प्रदाता और ऑपरेटर",
|
||||
"messaging": "मैसेजिंग ऐप"
|
||||
},
|
||||
"loading": "{name} लोड हो रहा है…"
|
||||
},
|
||||
"posters": {
|
||||
"heading": "मुख्य शहरों के पोस्टर",
|
||||
"tag": "प्रार्थना संचालन",
|
||||
"itemNoun": "शहर",
|
||||
"itemNounPlural": "शहर",
|
||||
"soon": "जल्द आ रहा है: हर शहर के लिए एक प्रार्थना सूची, जिसमें उसके हर अपहुँचे जनसमूह का नाम होगा।"
|
||||
}
|
||||
}
|
||||
54
library/i18n/locales/it/keyCities.json
Normal file
54
library/i18n/locales/it/keyCities.json
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
{
|
||||
"map": {
|
||||
"title": "Dove vivono i popoli non raggiunti",
|
||||
"bands": {
|
||||
"named": "centro con nome",
|
||||
"multi": "più popoli",
|
||||
"single": "un solo popolo"
|
||||
},
|
||||
"note": "Un punto è un raggruppamento di centroidi di popoli entro ~25 km, non un confine comunale. I punti con nome provengono da un gazetteer citato.",
|
||||
"unnamed": "luogo senza nome — {lat}, {lng}",
|
||||
"close": "Chiudi",
|
||||
"country": "Paese",
|
||||
"admin": "Area amministrativa",
|
||||
"peopleGroups": "Popoli",
|
||||
"upgPopulation": "Popolazione UPG",
|
||||
"internet": "Internet nel paese",
|
||||
"unknown": "sconosciuto",
|
||||
"pgHere": "Popoli qui",
|
||||
"languages": "Lingue",
|
||||
"sheetNote": "Un raggruppamento di centroidi di popoli entro ~25 km, non un confine comunale. I punti con nome provengono da un gazetteer citato (Nominatim/OSM); quelli senza nome mostrano le coordinate invece di un nome inventato.",
|
||||
"national": "I dati su Internet sono NAZIONALI.",
|
||||
"engineMissing": "Impossibile caricare il motore della mappa."
|
||||
},
|
||||
"list": {
|
||||
"title": "Città chiave",
|
||||
"intro": "Dove vivono i popoli non raggiunti: centri abitati con nome da un gazetteer citato: {named}, in raggruppamenti localizzati: {clusters}.",
|
||||
"filters": {
|
||||
"named": "Centri abitati con nome",
|
||||
"multi": "Raggruppamenti di più popoli",
|
||||
"all": "Tutti i luoghi"
|
||||
},
|
||||
"locations": "luoghi: {n}",
|
||||
"peopleGroups": "popoli: {n}"
|
||||
},
|
||||
"tables": {
|
||||
"title": "Dati delle città chiave",
|
||||
"intro": "Ogni centro localizzato, le lingue parlate lì e i canali che lo raggiungono. Ordina, filtra ed esporta ogni tabella; ognuna riporta le proprie fonti e i propri limiti.",
|
||||
"tabs": {
|
||||
"cities": "Città chiave",
|
||||
"langcity": "Lingue qui",
|
||||
"languages": "Per paese",
|
||||
"operators": "Provider e operatori",
|
||||
"messaging": "Messaggistica"
|
||||
},
|
||||
"loading": "Caricamento di {name}…"
|
||||
},
|
||||
"posters": {
|
||||
"heading": "Poster delle città chiave",
|
||||
"tag": "Mobilitazione alla preghiera",
|
||||
"itemNoun": "città",
|
||||
"itemNounPlural": "città",
|
||||
"soon": "Presto: un elenco di preghiera per ogni città, con ogni popolo non raggiunto che vi abita."
|
||||
}
|
||||
}
|
||||
54
library/i18n/locales/pt/keyCities.json
Normal file
54
library/i18n/locales/pt/keyCities.json
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
{
|
||||
"map": {
|
||||
"title": "Onde vivem os povos não alcançados",
|
||||
"bands": {
|
||||
"named": "centro com nome",
|
||||
"multi": "vários povos",
|
||||
"single": "um povo"
|
||||
},
|
||||
"note": "Um ponto é um agrupamento de centroides de povos num raio de ~25 km, não um limite municipal. Os pontos com nome vêm de um gazetteer citado.",
|
||||
"unnamed": "local sem nome — {lat}, {lng}",
|
||||
"close": "Fechar",
|
||||
"country": "País",
|
||||
"admin": "Área administrativa",
|
||||
"peopleGroups": "Povos",
|
||||
"upgPopulation": "População UPG",
|
||||
"internet": "Internet do país",
|
||||
"unknown": "desconhecido",
|
||||
"pgHere": "Povos aqui",
|
||||
"languages": "Idiomas",
|
||||
"sheetNote": "Um agrupamento de centroides de povos num raio de ~25 km, não um limite municipal. Os pontos com nome vêm de um gazetteer citado (Nominatim/OSM); os sem nome mostram coordenadas em vez de um nome inventado.",
|
||||
"national": "Os números de internet são NACIONAIS.",
|
||||
"engineMissing": "Não foi possível carregar o motor do mapa."
|
||||
},
|
||||
"list": {
|
||||
"title": "Cidades-chave",
|
||||
"intro": "Onde vivem os povos não alcançados: centros populacionais com nome de um gazetteer citado: {named}, em agrupamentos localizados: {clusters}.",
|
||||
"filters": {
|
||||
"named": "Centros populacionais com nome",
|
||||
"multi": "Agrupamentos de vários povos",
|
||||
"all": "Todos os locais"
|
||||
},
|
||||
"locations": "locais: {n}",
|
||||
"peopleGroups": "povos: {n}"
|
||||
},
|
||||
"tables": {
|
||||
"title": "Dados das cidades-chave",
|
||||
"intro": "Cada centro localizado, os idiomas falados ali e os canais que o alcançam. Ordene, filtre e exporte qualquer tabela; cada uma indica as suas fontes e limites.",
|
||||
"tabs": {
|
||||
"cities": "Cidades-chave",
|
||||
"langcity": "Idiomas aqui",
|
||||
"languages": "Por país",
|
||||
"operators": "Fornecedores e operadoras",
|
||||
"messaging": "Mensagens"
|
||||
},
|
||||
"loading": "A carregar {name}…"
|
||||
},
|
||||
"posters": {
|
||||
"heading": "Cartazes das cidades-chave",
|
||||
"tag": "Mobilização de oração",
|
||||
"itemNoun": "cidade",
|
||||
"itemNounPlural": "cidades",
|
||||
"soon": "Em breve: uma lista de oração para cada cidade, com cada povo não alcançado que vive nela."
|
||||
}
|
||||
}
|
||||
54
library/i18n/locales/ro/keyCities.json
Normal file
54
library/i18n/locales/ro/keyCities.json
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
{
|
||||
"map": {
|
||||
"title": "Unde trăiesc popoarele neatinse",
|
||||
"bands": {
|
||||
"named": "centru numit",
|
||||
"multi": "mai multe popoare",
|
||||
"single": "un singur popor"
|
||||
},
|
||||
"note": "Un punct este un grup de centroizi ai popoarelor pe o rază de ~25 km, nu o limită municipală. Punctele numite provin dintr-un gazetteer citat.",
|
||||
"unnamed": "loc fără nume — {lat}, {lng}",
|
||||
"close": "Închide",
|
||||
"country": "Țară",
|
||||
"admin": "Zonă administrativă",
|
||||
"peopleGroups": "Popoare",
|
||||
"upgPopulation": "Populație UPG",
|
||||
"internet": "Internet în țară",
|
||||
"unknown": "necunoscut",
|
||||
"pgHere": "Popoare aici",
|
||||
"languages": "Limbi",
|
||||
"sheetNote": "Un grup de centroizi ai popoarelor pe o rază de ~25 km, nu o limită municipală. Punctele numite provin dintr-un gazetteer citat (Nominatim/OSM); cele fără nume arată coordonate în loc de un nume inventat.",
|
||||
"national": "Cifrele de internet sunt NAȚIONALE.",
|
||||
"engineMissing": "Motorul hărții nu a putut fi încărcat."
|
||||
},
|
||||
"list": {
|
||||
"title": "Orașe-cheie",
|
||||
"intro": "Unde trăiesc popoarele neatinse: centre de populație numite dintr-un gazetteer citat: {named}, în grupuri localizate: {clusters}.",
|
||||
"filters": {
|
||||
"named": "Centre de populație numite",
|
||||
"multi": "Grupuri cu mai multe popoare",
|
||||
"all": "Toate locurile"
|
||||
},
|
||||
"locations": "locuri: {n}",
|
||||
"peopleGroups": "popoare: {n}"
|
||||
},
|
||||
"tables": {
|
||||
"title": "Datele orașelor-cheie",
|
||||
"intro": "Fiecare centru localizat, limbile vorbite acolo și canalele care ajung la el. Sortați, filtrați și exportați orice tabel; fiecare își poartă sursele și limitele.",
|
||||
"tabs": {
|
||||
"cities": "Orașe-cheie",
|
||||
"langcity": "Limbi aici",
|
||||
"languages": "După țară",
|
||||
"operators": "Furnizori și operatori",
|
||||
"messaging": "Aplicații de mesagerie"
|
||||
},
|
||||
"loading": "Se încarcă {name}…"
|
||||
},
|
||||
"posters": {
|
||||
"heading": "Afișe ale orașelor-cheie",
|
||||
"tag": "Mobilizare la rugăciune",
|
||||
"itemNoun": "oraș",
|
||||
"itemNounPlural": "orașe",
|
||||
"soon": "În curând: o listă de rugăciune pentru fiecare oraș, cu fiecare popor neatins care trăiește acolo."
|
||||
}
|
||||
}
|
||||
54
library/i18n/locales/ru/keyCities.json
Normal file
54
library/i18n/locales/ru/keyCities.json
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
{
|
||||
"map": {
|
||||
"title": "Где живут неохваченные народы",
|
||||
"bands": {
|
||||
"named": "центр с названием",
|
||||
"multi": "несколько народов",
|
||||
"single": "один народ"
|
||||
},
|
||||
"note": "Точка — это скопление центров народов в радиусе ~25 км, а не граница муниципалитета. Названия точек взяты из цитируемого справочника.",
|
||||
"unnamed": "место без названия — {lat}, {lng}",
|
||||
"close": "Закрыть",
|
||||
"country": "Страна",
|
||||
"admin": "Административный район",
|
||||
"peopleGroups": "Народы",
|
||||
"upgPopulation": "Население UPG",
|
||||
"internet": "Интернет в стране",
|
||||
"unknown": "неизвестно",
|
||||
"pgHere": "Народы здесь",
|
||||
"languages": "Языки",
|
||||
"sheetNote": "Скопление центров народов в радиусе ~25 км, а не граница муниципалитета. Названия точек взяты из цитируемого справочника (Nominatim/OSM); у точек без названия показаны координаты, а не выдуманное название.",
|
||||
"national": "Данные об интернете — НАЦИОНАЛЬНЫЕ.",
|
||||
"engineMissing": "Не удалось загрузить движок карты."
|
||||
},
|
||||
"list": {
|
||||
"title": "Ключевые города",
|
||||
"intro": "Где живут неохваченные народы: населённых пунктов с названием из цитируемого справочника: {named}, в найденных скоплениях: {clusters}.",
|
||||
"filters": {
|
||||
"named": "Населённые пункты с названием",
|
||||
"multi": "Скопления нескольких народов",
|
||||
"all": "Все места"
|
||||
},
|
||||
"locations": "мест: {n}",
|
||||
"peopleGroups": "народов: {n}"
|
||||
},
|
||||
"tables": {
|
||||
"title": "Данные по ключевым городам",
|
||||
"intro": "Каждый найденный центр, языки, на которых там говорят, и каналы, которые до него доходят. Сортируйте, фильтруйте и экспортируйте любую таблицу; у каждой свои источники и ограничения.",
|
||||
"tabs": {
|
||||
"cities": "Ключевые города",
|
||||
"langcity": "Языки здесь",
|
||||
"languages": "По странам",
|
||||
"operators": "Провайдеры и операторы",
|
||||
"messaging": "Мессенджеры"
|
||||
},
|
||||
"loading": "Загрузка: {name}…"
|
||||
},
|
||||
"posters": {
|
||||
"heading": "Плакаты ключевых городов",
|
||||
"tag": "Молитвенная мобилизация",
|
||||
"itemNoun": "город",
|
||||
"itemNounPlural": "города",
|
||||
"soon": "Скоро: молитвенный список для каждого города с каждым неохваченным народом в нём."
|
||||
}
|
||||
}
|
||||
54
library/i18n/locales/zh/keyCities.json
Normal file
54
library/i18n/locales/zh/keyCities.json
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
{
|
||||
"map": {
|
||||
"title": "未得之民生活在哪里",
|
||||
"bands": {
|
||||
"named": "已命名中心",
|
||||
"multi": "多个族群",
|
||||
"single": "单一族群"
|
||||
},
|
||||
"note": "一个点是约 25 公里内族群中心点的聚合,并非市级边界。已命名的点来自有出处的地名录。",
|
||||
"unnamed": "未命名地点 — {lat},{lng}",
|
||||
"close": "关闭",
|
||||
"country": "国家",
|
||||
"admin": "行政区",
|
||||
"peopleGroups": "族群",
|
||||
"upgPopulation": "UPG 人口",
|
||||
"internet": "国家互联网",
|
||||
"unknown": "未知",
|
||||
"pgHere": "此处的族群",
|
||||
"languages": "语言",
|
||||
"sheetNote": "约 25 公里内族群中心点的聚合,并非市级边界。已命名的点来自有出处的地名录(Nominatim/OSM);未命名的点显示坐标,而不是编造的地名。",
|
||||
"national": "互联网数据为全国数据。",
|
||||
"engineMissing": "无法加载地图引擎。"
|
||||
},
|
||||
"list": {
|
||||
"title": "重点城市",
|
||||
"intro": "未得之民生活在哪里:来自有出处地名录的已命名人口中心:{named},分布于已定位聚合:{clusters}。",
|
||||
"filters": {
|
||||
"named": "已命名的人口中心",
|
||||
"multi": "多族群聚合",
|
||||
"all": "所有地点"
|
||||
},
|
||||
"locations": "地点:{n}",
|
||||
"peopleGroups": "族群:{n}"
|
||||
},
|
||||
"tables": {
|
||||
"title": "重点城市数据",
|
||||
"intro": "每个已定位的中心、那里使用的语言,以及能触及它们的渠道。任何表格都可排序、筛选和导出;每张表都注明各自的来源与局限。",
|
||||
"tabs": {
|
||||
"cities": "重点城市",
|
||||
"langcity": "此处的语言",
|
||||
"languages": "按国家",
|
||||
"operators": "网络服务商与运营商",
|
||||
"messaging": "即时通讯"
|
||||
},
|
||||
"loading": "正在加载{name}…"
|
||||
},
|
||||
"posters": {
|
||||
"heading": "重点城市海报",
|
||||
"tag": "祷告动员",
|
||||
"itemNoun": "城市",
|
||||
"itemNounPlural": "城市",
|
||||
"soon": "即将推出:每座城市的祷告清单,列出其中每一个未得之民。"
|
||||
}
|
||||
}
|
||||
|
|
@ -134,10 +134,9 @@ const band = (a) => a === 'yes' ? 'ok' : a === 'partial' ? 'mid' : a === 'no' ?
|
|||
|
||||
<template>
|
||||
<div class="kc" :class="{ 'is-dark': isDark }">
|
||||
<h2 class="kc-h">Key Cities</h2>
|
||||
<h2 class="kc-h">{{ $t('keyCities.list.title') }}</h2>
|
||||
<p class="kc-sub">
|
||||
Where the unengaged people groups live — {{ fmt(named.length) }} population centres
|
||||
named from a cited gazetteer, across {{ fmt(rows.length) }} located clusters.
|
||||
{{ $t('keyCities.list.intro', { named: fmt(named.length), clusters: fmt(rows.length) }) }}
|
||||
</p>
|
||||
|
||||
<div v-if="loadErr" class="caveat">{{ loadErr }}</div>
|
||||
|
|
@ -145,7 +144,7 @@ const band = (a) => a === 'yes' ? 'ok' : a === 'partial' ? 'mid' : a === 'no' ?
|
|||
<div class="kc-tabs">
|
||||
<button v-for="f in FILTERS" :key="f.id" type="button"
|
||||
class="kc-tab" :class="{ on: filter === f.id }" @click="filter = f.id">
|
||||
{{ f.label }}
|
||||
{{ $t('keyCities.list.filters.' + f.id) }}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
|
|
@ -154,7 +153,7 @@ const band = (a) => a === 'yes' ? 'ok' : a === 'partial' ? 'mid' : a === 'no' ?
|
|||
<span class="sec-caret" :class="{ open: !isShut(sec.name) }">▶</span>
|
||||
<h3 class="sec-name">{{ sec.name }}</h3>
|
||||
<span class="sec-meta">
|
||||
{{ sec.items.length }} locations · {{ fmt(sec.groups) }} people groups
|
||||
{{ $t('keyCities.list.locations', { n: sec.items.length }) }} · {{ $t('keyCities.list.peopleGroups', { n: fmt(sec.groups) }) }}
|
||||
</span>
|
||||
</button>
|
||||
|
||||
|
|
@ -164,7 +163,7 @@ const band = (a) => a === 'yes' ? 'ok' : a === 'partial' ? 'mid' : a === 'no' ?
|
|||
<!-- An unnamed cluster says so, with its coordinates. Inventing a name
|
||||
here is the one thing this dataset must never do. -->
|
||||
<div :class="r.place_name ? 'r-name' : 'r-unnamed'">
|
||||
{{ r.place_name || `unnamed location — ${r.lat}, ${r.lng}` }}
|
||||
{{ r.place_name || $t('keyCities.map.unnamed', { lat: r.lat, lng: r.lng }) }}
|
||||
</div>
|
||||
<div class="r-meta">
|
||||
{{ r.country }}<template v-if="r.admin_state"> · {{ r.admin_state }}</template>
|
||||
|
|
|
|||
|
|
@ -39,6 +39,11 @@ import { addMapAttribution } from '@map/composables/useMapAttribution'
|
|||
import { ensureEngineScript, engineGlobal } from '@map/composables/useMapInstance.js'
|
||||
import { installRtlTextPlugin } from '@map/maps/rtl-text.js'
|
||||
import { resolveAssetsBase } from '@map/utils/embedBase.js'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import enKeyCities from '@map/i18n/locales/en/keyCities.json'
|
||||
// guarded: useI18n() throws on a host without vue-i18n; the English catalog is the fallback
|
||||
let t = (k) => String(k).replace(/^keyCities\./, '').split('.').reduce((o, x) => (o == null ? o : o[x]), enKeyCities) ?? k
|
||||
try { t = useI18n().t } catch (_) { /* no i18n on this host */ }
|
||||
|
||||
const profileConfig = inject('profileConfig', ref(null))
|
||||
const isDark = computed(() => profileConfig.value?.isDark === true)
|
||||
|
|
@ -143,7 +148,7 @@ onMounted(async () => {
|
|||
// (it leaked every visitor's IP to Mapbox under provider=maplibre). This map is Mapbox-only.
|
||||
try { await ensureEngineScript('mapbox') } catch (_) {}
|
||||
const gl = engineGlobal('mapbox')
|
||||
if (!gl || !mapEl.value) { err.value = 'mapbox-gl not loaded'; return }
|
||||
if (!gl || !mapEl.value) { err.value = t('keyCities.map.engineMissing'); return }
|
||||
// RTL SHAPING before the map exists: a raw map is not covered by useMapInstance's install, and
|
||||
// the Mapbox basemap draws Middle-East places in Arabic/Persian/Hebrew script for every viewer.
|
||||
installRtlTextPlugin(gl)
|
||||
|
|
@ -302,14 +307,14 @@ useShadowStyles(
|
|||
<div ref="mapEl" class="gm-map"></div>
|
||||
|
||||
<div class="gm-legend">
|
||||
<div class="gm-title">Where the unengaged people groups live</div>
|
||||
<div class="gm-title">{{ $t('keyCities.map.title') }}</div>
|
||||
<div class="gm-keys">
|
||||
<span v-for="b in BANDS" :key="b.id" class="gm-key">
|
||||
<i class="gm-sw" :style="{ background: b.color }"></i>{{ b.label }}
|
||||
<i class="gm-sw" :style="{ background: b.color }"></i>{{ $t('keyCities.map.bands.' + b.id) }}
|
||||
</span>
|
||||
</div>
|
||||
<div class="gm-caveat">
|
||||
A point is a cluster of people-group centroids within ~25km, not a municipal boundary. Named points come from a cited gazetteer.
|
||||
{{ $t('keyCities.map.note') }}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
@ -318,26 +323,25 @@ useShadowStyles(
|
|||
<!-- Tap a country: bottom sheet on mobile, corner card on desktop. -->
|
||||
<div v-if="selected" class="gm-sheet">
|
||||
<div class="gm-sh-head">
|
||||
<span class="gm-sh-name">{{ selected.place_name || `unnamed location — ${selected.lat}, ${selected.lng}` }}</span>
|
||||
<button type="button" class="gm-x" @click="selected = null">Close</button>
|
||||
<span class="gm-sh-name">{{ selected.place_name || $t('keyCities.map.unnamed', { lat: selected.lat, lng: selected.lng }) }}</span>
|
||||
<button type="button" class="gm-x" @click="selected = null">{{ $t('keyCities.map.close') }}</button>
|
||||
</div>
|
||||
<div class="gm-stat"><span>Country</span><b>{{ selected.country }}</b></div>
|
||||
<div v-if="selected.admin_state" class="gm-stat"><span>Admin area</span><b>{{ selected.admin_state }}</b></div>
|
||||
<div class="gm-stat"><span>People groups</span><b>{{ fmt(selected.people_group_count) }}</b></div>
|
||||
<div class="gm-stat"><span>UPG population</span><b>{{ fmt(selected.upg_population) }}</b></div>
|
||||
<div class="gm-stat"><span>Country internet</span><b>{{ selected.country_internet_pct != null ? selected.country_internet_pct + '%' : 'unknown' }}</b></div>
|
||||
<div class="gm-stat"><span>{{ $t('keyCities.map.country') }}</span><b>{{ selected.country }}</b></div>
|
||||
<div v-if="selected.admin_state" class="gm-stat"><span>{{ $t('keyCities.map.admin') }}</span><b>{{ selected.admin_state }}</b></div>
|
||||
<div class="gm-stat"><span>{{ $t('keyCities.map.peopleGroups') }}</span><b>{{ fmt(selected.people_group_count) }}</b></div>
|
||||
<div class="gm-stat"><span>{{ $t('keyCities.map.upgPopulation') }}</span><b>{{ fmt(selected.upg_population) }}</b></div>
|
||||
<div class="gm-stat"><span>{{ $t('keyCities.map.internet') }}</span><b>{{ selected.country_internet_pct != null ? selected.country_internet_pct + '%' : $t('keyCities.map.unknown') }}</b></div>
|
||||
<div v-if="selected.people_groups" class="gm-list">
|
||||
<div class="gm-list-h">People groups here</div>
|
||||
<div class="gm-list-h">{{ $t('keyCities.map.pgHere') }}</div>
|
||||
<ul><li v-for="(g, i) in String(selected.people_groups).split(', ')" :key="i">{{ g }}</li></ul>
|
||||
</div>
|
||||
<div v-if="selected.languages" class="gm-list">
|
||||
<div class="gm-list-h">Languages</div>
|
||||
<div class="gm-list-h">{{ $t('keyCities.map.languages') }}</div>
|
||||
<ul><li v-for="(l, i) in String(selected.languages).split(', ')" :key="i">{{ l }}</li></ul>
|
||||
</div>
|
||||
<p class="gm-note">
|
||||
A cluster of people-group centroids within ~25km, not a municipal boundary. Named points come from a cited
|
||||
gazetteer (Nominatim/OSM); unnamed ones show coordinates rather than an invented placename.
|
||||
Internet figures are NATIONAL.
|
||||
{{ $t('keyCities.map.sheetNote') }}
|
||||
{{ $t('keyCities.map.national') }}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -61,15 +61,15 @@ const intro =
|
|||
:is-dark="isDark"
|
||||
:assets-base="assetsBase"
|
||||
event-name="doxa-key-cities:show-on-map"
|
||||
heading="Key City Posters"
|
||||
tag="Prayer Mobilization"
|
||||
:heading="$t('keyCities.posters.heading')"
|
||||
:tag="$t('keyCities.posters.tag')"
|
||||
:intro="intro"
|
||||
unit="UPG"
|
||||
item-noun="city"
|
||||
item-noun-plural="cities"
|
||||
:item-noun="$t('keyCities.posters.itemNoun')"
|
||||
:item-noun-plural="$t('keyCities.posters.itemNounPlural')"
|
||||
:collapsible="true"
|
||||
:collapsed-by="collapsedBy"
|
||||
prayer-list-soon-message="Coming soon — a prayer list for each city, naming every unengaged people group in it."
|
||||
:prayer-list-soon-message="$t('keyCities.posters.soon')"
|
||||
download-prefix="doxa-city"
|
||||
/>
|
||||
</template>
|
||||
|
|
|
|||
|
|
@ -83,16 +83,15 @@ useShadowStyles(
|
|||
|
||||
<template>
|
||||
<div class="ct" :class="{ 'is-dark': isDark }">
|
||||
<h2 class="ct-h">Key Cities Data</h2>
|
||||
<h2 class="ct-h">{{ $t('keyCities.tables.title') }}</h2>
|
||||
<p class="ct-sub">
|
||||
Every located centre, the languages spoken there, and the channels that reach them.
|
||||
Sort, filter and export any table; each carries its own sources and limits.
|
||||
{{ $t('keyCities.tables.intro') }}
|
||||
</p>
|
||||
|
||||
<div class="ct-tabs">
|
||||
<button v-for="t in TABS" :key="t.id" type="button"
|
||||
class="ct-tab" :class="{ on: active === t.id }" @click="active = t.id">
|
||||
{{ t.label }}<span class="ct-n" v-if="cache[t.file]">{{ (cache[t.file].rows || []).length.toLocaleString() }}</span>
|
||||
<button v-for="tab in TABS" :key="tab.id" type="button"
|
||||
class="ct-tab" :class="{ on: active === tab.id }" @click="active = tab.id">
|
||||
{{ $t('keyCities.tables.tabs.' + tab.id) }}<span class="ct-n" v-if="cache[tab.file]">{{ (cache[tab.file].rows || []).length.toLocaleString() }}</span>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
|
|
@ -100,7 +99,7 @@ useShadowStyles(
|
|||
swapping both columns AND data on a live instance is where column state
|
||||
(frozen, widths, filters) desynchronises from the new schema. -->
|
||||
<div v-if="loadErr" class="ct-err">{{ loadErr }}</div>
|
||||
<div v-else-if="!table" class="ct-load">Loading {{ current.label }}…</div>
|
||||
<div v-else-if="!table" class="ct-load">{{ $t('keyCities.tables.loading', { name: $t('keyCities.tables.tabs.' + current.id) }) }}</div>
|
||||
<DataTable
|
||||
v-else
|
||||
:key="current.id"
|
||||
|
|
|
|||
Loading…
Reference in a new issue