Country Posters: India's state and union territory cards named in the reader's language; the state table retried after a failure
countryPosters.stateNames x11, keyed by ISO 3166-2, for the India section's CARD labels (the wall, the print HUD, the
packet and list titles). The printed sheet stays English by recorded decision, like every country poster.
Generated, not typed: scripts/emit-india-state-names.mjs reads Wikidata labels by ISO 3166-2 (P300), dissolved items
excluded; Wikidata is CC0 (source, licence, query, date and every fallback in data/india-state-names.meta.json).
- Four codes ISO has renamed (IN-CT/OR/TG/UT -> CG/OD/TS/UK) are queried under the current code.
- English is the table's own name. Where the table is briefer than its item ("Delhi" vs "National Capital Territory
of Delhi"), the same-named item's labels win, so hi/ru match the English.
- Reviewed by eye (hi, ar, zh): two explicit overrides with their evidence (ar Odisha = the ar.wikipedia title,
not the pre-2011 label; zh Dadra and Nagar Haveli and Daman and Diu = Simplified, the only label being
Traditional). A zh name from a plain "zh" label with no reviewed override FAILS the generator (poisoned: it did).
The India section retries a failed table fetch at 5 s, 20 s and 60 s (bounded, cancelled on unmount), instead of
staying hidden until the filter changes.
check:country-sheet-one-path ARM D: every locale's stateNames == the table's 36 codes (a runtime-built key the i18n
call-site gates cannot see), English == the table, and the licence recorded; its two poisons join the self-test.
This commit is contained in:
parent
671295b5b1
commit
a63a873ef4
15 changed files with 661 additions and 27 deletions
|
|
@ -1,5 +1,43 @@
|
|||
{
|
||||
"indiaNote": "للهند قسمها الخاص في المقدّمة: عدد الشعوب غير المُبشَّرة فيها {count}، وهو أكثر بكثير من أي بلد آخر، لذا لكل ولاية وإقليم اتحادي فيها ملصقه الخاص.",
|
||||
"indiaStateNoGroups": "لا توجد هنا شعوب غير مُبشَّرة مُدرَجة.",
|
||||
"indiaItemCount": "لا ولايات ولا أقاليم | ولاية أو إقليم اتحادي واحد | ولايتان أو إقليمان | {n} ولايات وأقاليم اتحادية | {n} ولاية وإقليمًا اتحاديًا | {n} ولاية وإقليم اتحادي"
|
||||
"indiaItemCount": "لا ولايات ولا أقاليم | ولاية أو إقليم اتحادي واحد | ولايتان أو إقليمان | {n} ولايات وأقاليم اتحادية | {n} ولاية وإقليمًا اتحاديًا | {n} ولاية وإقليم اتحادي",
|
||||
"stateNames": {
|
||||
"IN-AN": "جزر أندمان وَ نِكُبَار",
|
||||
"IN-AP": "أندرا برديش",
|
||||
"IN-AR": "أروناجل برديش",
|
||||
"IN-AS": "آسام",
|
||||
"IN-BR": "بهار",
|
||||
"IN-CH": "شَنديغار",
|
||||
"IN-CT": "تشاتيسغار",
|
||||
"IN-DH": "دادرا وناغار هافيلي ودامان وديو",
|
||||
"IN-DL": "دلهي",
|
||||
"IN-GA": "غوا",
|
||||
"IN-GJ": "كجرات",
|
||||
"IN-HP": "هماجل برديش",
|
||||
"IN-HR": "هريانة",
|
||||
"IN-JH": "جاركند",
|
||||
"IN-JK": "إقليم جمون وكشمير",
|
||||
"IN-KA": "كرناتك",
|
||||
"IN-KL": "كيرلا",
|
||||
"IN-LA": "لداخ",
|
||||
"IN-LD": "لكشديب",
|
||||
"IN-MH": "مهاراشترة",
|
||||
"IN-ML": "ميكالية",
|
||||
"IN-MN": "منيبور",
|
||||
"IN-MP": "مدية برديش",
|
||||
"IN-MZ": "مِزُورَم",
|
||||
"IN-NL": "ناغالند",
|
||||
"IN-OR": "أديشة",
|
||||
"IN-PB": "بنجاب",
|
||||
"IN-PY": "بُدُجيري",
|
||||
"IN-RJ": "راجستان",
|
||||
"IN-SK": "سِكِم",
|
||||
"IN-TG": "تلنكانة",
|
||||
"IN-TN": "تاميل نادو",
|
||||
"IN-TR": "تريبورة",
|
||||
"IN-UP": "أتر برديش",
|
||||
"IN-UT": "أوتاراخند",
|
||||
"IN-WB": "بنغال الغربية"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,43 @@
|
|||
{
|
||||
"indiaNote": "Indien hat einen eigenen Abschnitt, ganz oben: Mit {count} unerreichten Volksgruppen, weit mehr als jedes andere Land, hat jeder seiner Bundesstaaten und Unionsterritorien ein eigenes Plakat.",
|
||||
"indiaStateNoGroups": "Hier sind keine unerreichten Volksgruppen verzeichnet.",
|
||||
"indiaItemCount": "{n} Bundesstaat oder Unionsterritorium | {n} Bundesstaaten und Unionsterritorien"
|
||||
"indiaItemCount": "{n} Bundesstaat oder Unionsterritorium | {n} Bundesstaaten und Unionsterritorien",
|
||||
"stateNames": {
|
||||
"IN-AN": "Andamanen und Nikobaren",
|
||||
"IN-AP": "Andhra Pradesh",
|
||||
"IN-AR": "Arunachal Pradesh",
|
||||
"IN-AS": "Assam",
|
||||
"IN-BR": "Bihar",
|
||||
"IN-CH": "Chandigarh",
|
||||
"IN-CT": "Chhattisgarh",
|
||||
"IN-DH": "Dadra und Nagar Haveli und Daman und Diu",
|
||||
"IN-DL": "Delhi",
|
||||
"IN-GA": "Goa",
|
||||
"IN-GJ": "Gujarat",
|
||||
"IN-HP": "Himachal Pradesh",
|
||||
"IN-HR": "Haryana",
|
||||
"IN-JH": "Jharkhand",
|
||||
"IN-JK": "Jammu und Kashmir",
|
||||
"IN-KA": "Karnataka",
|
||||
"IN-KL": "Kerala",
|
||||
"IN-LA": "Ladakh",
|
||||
"IN-LD": "Lakshadweep",
|
||||
"IN-MH": "Maharashtra",
|
||||
"IN-ML": "Meghalaya",
|
||||
"IN-MN": "Manipur",
|
||||
"IN-MP": "Madhya Pradesh",
|
||||
"IN-MZ": "Mizoram",
|
||||
"IN-NL": "Nagaland",
|
||||
"IN-OR": "Odisha",
|
||||
"IN-PB": "Punjab",
|
||||
"IN-PY": "Puducherry",
|
||||
"IN-RJ": "Rajasthan",
|
||||
"IN-SK": "Sikkim",
|
||||
"IN-TG": "Telangana",
|
||||
"IN-TN": "Tamil Nadu",
|
||||
"IN-TR": "Tripura",
|
||||
"IN-UP": "Uttar Pradesh",
|
||||
"IN-UT": "Uttarakhand",
|
||||
"IN-WB": "Westbengalen"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,43 @@
|
|||
{
|
||||
"indiaNote": "India has its own section, first: it has {count} unreached people groups, far more than any other country, so each of its states and union territories has its own poster.",
|
||||
"indiaStateNoGroups": "No unreached people groups are listed here.",
|
||||
"indiaItemCount": "{n} states and union territories | {n} state or union territory | {n} states and union territories"
|
||||
"indiaItemCount": "{n} states and union territories | {n} state or union territory | {n} states and union territories",
|
||||
"stateNames": {
|
||||
"IN-AN": "Andaman and Nicobar Islands",
|
||||
"IN-AP": "Andhra Pradesh",
|
||||
"IN-AR": "Arunachal Pradesh",
|
||||
"IN-AS": "Assam",
|
||||
"IN-BR": "Bihar",
|
||||
"IN-CH": "Chandigarh",
|
||||
"IN-CT": "Chhattisgarh",
|
||||
"IN-DH": "Dadra and Nagar Haveli and Daman and Diu",
|
||||
"IN-DL": "Delhi",
|
||||
"IN-GA": "Goa",
|
||||
"IN-GJ": "Gujarat",
|
||||
"IN-HP": "Himachal Pradesh",
|
||||
"IN-HR": "Haryana",
|
||||
"IN-JH": "Jharkhand",
|
||||
"IN-JK": "Jammu and Kashmir",
|
||||
"IN-KA": "Karnataka",
|
||||
"IN-KL": "Kerala",
|
||||
"IN-LA": "Ladakh",
|
||||
"IN-LD": "Lakshadweep",
|
||||
"IN-MH": "Maharashtra",
|
||||
"IN-ML": "Meghalaya",
|
||||
"IN-MN": "Manipur",
|
||||
"IN-MP": "Madhya Pradesh",
|
||||
"IN-MZ": "Mizoram",
|
||||
"IN-NL": "Nagaland",
|
||||
"IN-OR": "Odisha",
|
||||
"IN-PB": "Punjab",
|
||||
"IN-PY": "Puducherry",
|
||||
"IN-RJ": "Rajasthan",
|
||||
"IN-SK": "Sikkim",
|
||||
"IN-TG": "Telangana",
|
||||
"IN-TN": "Tamil Nadu",
|
||||
"IN-TR": "Tripura",
|
||||
"IN-UP": "Uttar Pradesh",
|
||||
"IN-UT": "Uttarakhand",
|
||||
"IN-WB": "West Bengal"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,43 @@
|
|||
{
|
||||
"indiaNote": "India tiene su propia sección, la primera: tiene {count} pueblos no alcanzados, muchos más que cualquier otro país, así que cada uno de sus estados y territorios de la unión tiene su propio cartel.",
|
||||
"indiaStateNoGroups": "Aquí no figura ningún pueblo no alcanzado.",
|
||||
"indiaItemCount": "{n} estado o territorio de la unión | {n} de estados y territorios de la unión | {n} estados y territorios de la unión"
|
||||
"indiaItemCount": "{n} estado o territorio de la unión | {n} de estados y territorios de la unión | {n} estados y territorios de la unión",
|
||||
"stateNames": {
|
||||
"IN-AN": "Islas Andamán y Nicobar",
|
||||
"IN-AP": "Andhra Pradesh",
|
||||
"IN-AR": "Arunachal Pradesh",
|
||||
"IN-AS": "Assam",
|
||||
"IN-BR": "Bihar",
|
||||
"IN-CH": "Chandigarh",
|
||||
"IN-CT": "Chhattisgarh",
|
||||
"IN-DH": "Dadra y Nagar Haveli y Damán y Diu",
|
||||
"IN-DL": "Delhi",
|
||||
"IN-GA": "Goa",
|
||||
"IN-GJ": "Guyarat",
|
||||
"IN-HP": "Himachal Pradesh",
|
||||
"IN-HR": "Haryana",
|
||||
"IN-JH": "Jharkhand",
|
||||
"IN-JK": "Jammu y Cachemira",
|
||||
"IN-KA": "Karnataka",
|
||||
"IN-KL": "Kerala",
|
||||
"IN-LA": "Ladakh",
|
||||
"IN-LD": "Laquedivas",
|
||||
"IN-MH": "Maharashtra",
|
||||
"IN-ML": "Meghalaya",
|
||||
"IN-MN": "Manipur",
|
||||
"IN-MP": "Madhya Pradesh",
|
||||
"IN-MZ": "Mizoram",
|
||||
"IN-NL": "Nagaland",
|
||||
"IN-OR": "Orissa",
|
||||
"IN-PB": "Punyab",
|
||||
"IN-PY": "Puducherry",
|
||||
"IN-RJ": "Rajastán",
|
||||
"IN-SK": "Sikkim",
|
||||
"IN-TG": "Telangana",
|
||||
"IN-TN": "Tamil Nadu",
|
||||
"IN-TR": "Tripura",
|
||||
"IN-UP": "Uttar Pradesh",
|
||||
"IN-UT": "Uttarakhand",
|
||||
"IN-WB": "Bengala Occidental"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,43 @@
|
|||
{
|
||||
"indiaNote": "L’Inde a sa propre section, en premier : elle compte {count} peuples non atteints, bien plus que tout autre pays ; chacun de ses États et territoires de l’Union a donc sa propre affiche.",
|
||||
"indiaStateNoGroups": "Aucun peuple non atteint n’est répertorié ici.",
|
||||
"indiaItemCount": "{n} État ou territoire de l’Union | {n} d’États et territoires de l’Union | {n} États et territoires de l’Union"
|
||||
"indiaItemCount": "{n} État ou territoire de l’Union | {n} d’États et territoires de l’Union | {n} États et territoires de l’Union",
|
||||
"stateNames": {
|
||||
"IN-AN": "Îles Andaman-et-Nicobar",
|
||||
"IN-AP": "Andhra Pradesh",
|
||||
"IN-AR": "Arunachal Pradesh",
|
||||
"IN-AS": "Assam",
|
||||
"IN-BR": "Bihar",
|
||||
"IN-CH": "Chandigarh",
|
||||
"IN-CT": "Chhattisgarh",
|
||||
"IN-DH": "Dadra et Nagar Haveli et Daman et Diu",
|
||||
"IN-DL": "Delhi",
|
||||
"IN-GA": "Goa",
|
||||
"IN-GJ": "Gujarat",
|
||||
"IN-HP": "Himachal Pradesh",
|
||||
"IN-HR": "Haryana",
|
||||
"IN-JH": "Jharkhand",
|
||||
"IN-JK": "Jammu-et-Cachemire",
|
||||
"IN-KA": "Karnataka",
|
||||
"IN-KL": "Kerala",
|
||||
"IN-LA": "Ladakh",
|
||||
"IN-LD": "Lakshadweep",
|
||||
"IN-MH": "Maharashtra",
|
||||
"IN-ML": "Meghalaya",
|
||||
"IN-MN": "Manipur",
|
||||
"IN-MP": "Madhya Pradesh",
|
||||
"IN-MZ": "Mizoram",
|
||||
"IN-NL": "Nagaland",
|
||||
"IN-OR": "Odisha",
|
||||
"IN-PB": "Pendjab",
|
||||
"IN-PY": "Territoire de Pondichéry",
|
||||
"IN-RJ": "Rajasthan",
|
||||
"IN-SK": "Sikkim",
|
||||
"IN-TG": "Telangana",
|
||||
"IN-TN": "Tamil Nadu",
|
||||
"IN-TR": "Tripura",
|
||||
"IN-UP": "Uttar Pradesh",
|
||||
"IN-UT": "Uttarakhand",
|
||||
"IN-WB": "Bengale-Occidental"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,43 @@
|
|||
{
|
||||
"indiaNote": "भारत का अपना अलग खंड है, सबसे पहले: इसमें {count} अपहुँचे जनसमूह हैं, किसी भी अन्य देश से कहीं अधिक, इसलिए इसके हर राज्य और केंद्र शासित प्रदेश का अपना पोस्टर है।",
|
||||
"indiaStateNoGroups": "यहाँ कोई अपहुँचा जनसमूह सूचीबद्ध नहीं है।",
|
||||
"indiaItemCount": "{n} राज्य या केंद्र शासित प्रदेश | {n} राज्य और केंद्र शासित प्रदेश"
|
||||
"indiaItemCount": "{n} राज्य या केंद्र शासित प्रदेश | {n} राज्य और केंद्र शासित प्रदेश",
|
||||
"stateNames": {
|
||||
"IN-AN": "अण्डमान और निकोबार द्वीपसमूह",
|
||||
"IN-AP": "आन्ध्र प्रदेश",
|
||||
"IN-AR": "अरुणाचल प्रदेश",
|
||||
"IN-AS": "असम",
|
||||
"IN-BR": "बिहार",
|
||||
"IN-CH": "चण्डीगढ़",
|
||||
"IN-CT": "छत्तीसगढ़",
|
||||
"IN-DH": "दादरा और नगर हवेली और दमन और दीव",
|
||||
"IN-DL": "दिल्ली",
|
||||
"IN-GA": "गोवा",
|
||||
"IN-GJ": "गुजरात",
|
||||
"IN-HP": "हिमाचल प्रदेश",
|
||||
"IN-HR": "हरियाणा",
|
||||
"IN-JH": "झारखण्ड",
|
||||
"IN-JK": "जम्मू और कश्मीर",
|
||||
"IN-KA": "कर्नाटक",
|
||||
"IN-KL": "केरल",
|
||||
"IN-LA": "लद्दाख़",
|
||||
"IN-LD": "लक्षद्वीप",
|
||||
"IN-MH": "महाराष्ट्र",
|
||||
"IN-ML": "मेघालय",
|
||||
"IN-MN": "मणिपुर",
|
||||
"IN-MP": "मध्य प्रदेश",
|
||||
"IN-MZ": "मिज़ोरम",
|
||||
"IN-NL": "नागालैण्ड",
|
||||
"IN-OR": "ओडिशा",
|
||||
"IN-PB": "पंजाब",
|
||||
"IN-PY": "पुदुचेरी",
|
||||
"IN-RJ": "राजस्थान",
|
||||
"IN-SK": "सिक्किम",
|
||||
"IN-TG": "तेलंगाना",
|
||||
"IN-TN": "तमिल नाडु",
|
||||
"IN-TR": "त्रिपुरा",
|
||||
"IN-UP": "उत्तर प्रदेश",
|
||||
"IN-UT": "उत्तराखण्ड",
|
||||
"IN-WB": "पश्चिम बंगाल"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,43 @@
|
|||
{
|
||||
"indiaNote": "L’India ha una sezione tutta sua, la prima: conta {count} popoli non raggiunti, molti più di qualsiasi altro paese, quindi ognuno dei suoi stati e territori dell’Unione ha il proprio manifesto.",
|
||||
"indiaStateNoGroups": "Qui non è elencato alcun popolo non raggiunto.",
|
||||
"indiaItemCount": "{n} stato o territorio dell’Unione | {n} di stati e territori dell’Unione | {n} stati e territori dell’Unione"
|
||||
"indiaItemCount": "{n} stato o territorio dell’Unione | {n} di stati e territori dell’Unione | {n} stati e territori dell’Unione",
|
||||
"stateNames": {
|
||||
"IN-AN": "isole Andamane e Nicobare",
|
||||
"IN-AP": "Andhra Pradesh",
|
||||
"IN-AR": "Arunachal Pradesh",
|
||||
"IN-AS": "Assam",
|
||||
"IN-BR": "Bihar",
|
||||
"IN-CH": "Chandigarh",
|
||||
"IN-CT": "Chhattisgarh",
|
||||
"IN-DH": "Dadra e Nagar Haveli e Daman e Diu",
|
||||
"IN-DL": "Delhi",
|
||||
"IN-GA": "Goa",
|
||||
"IN-GJ": "Gujarat",
|
||||
"IN-HP": "Himachal Pradesh",
|
||||
"IN-HR": "Haryana",
|
||||
"IN-JH": "Jharkhand",
|
||||
"IN-JK": "Jammu e Kashmir",
|
||||
"IN-KA": "Karnataka",
|
||||
"IN-KL": "Kerala",
|
||||
"IN-LA": "Ladakh",
|
||||
"IN-LD": "Laccadive",
|
||||
"IN-MH": "Maharashtra",
|
||||
"IN-ML": "Meghalaya",
|
||||
"IN-MN": "Manipur",
|
||||
"IN-MP": "Madhya Pradesh",
|
||||
"IN-MZ": "Mizoram",
|
||||
"IN-NL": "Nagaland",
|
||||
"IN-OR": "Orissa",
|
||||
"IN-PB": "Punjab",
|
||||
"IN-PY": "Pondicherry",
|
||||
"IN-RJ": "Rajasthan",
|
||||
"IN-SK": "Sikkim",
|
||||
"IN-TG": "Telangana",
|
||||
"IN-TN": "Tamil Nadu",
|
||||
"IN-TR": "Tripura",
|
||||
"IN-UP": "Uttar Pradesh",
|
||||
"IN-UT": "Uttarakhand",
|
||||
"IN-WB": "Bengala Occidentale"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,43 @@
|
|||
{
|
||||
"indiaNote": "A Índia tem a sua própria seção, a primeira: tem {count} povos não alcançados, muito mais do que qualquer outro país, por isso cada um dos seus estados e territórios da união tem o seu próprio cartaz.",
|
||||
"indiaStateNoGroups": "Nenhum povo não alcançado está listado aqui.",
|
||||
"indiaItemCount": "{n} estado ou território da união | {n} de estados e territórios da união | {n} estados e territórios da união"
|
||||
"indiaItemCount": "{n} estado ou território da união | {n} de estados e territórios da união | {n} estados e territórios da união",
|
||||
"stateNames": {
|
||||
"IN-AN": "Andamão e Nicobar",
|
||||
"IN-AP": "Andra Pradexe",
|
||||
"IN-AR": "Arunachal Pradesh",
|
||||
"IN-AS": "Assam",
|
||||
"IN-BR": "Bihar",
|
||||
"IN-CH": "Chandigarh",
|
||||
"IN-CT": "Chhattisgarh",
|
||||
"IN-DH": "Dadrá e Nagar Aveli e Damão e Diu",
|
||||
"IN-DL": "Delhi",
|
||||
"IN-GA": "Goa",
|
||||
"IN-GJ": "Gujarate",
|
||||
"IN-HP": "Himachal Pradesh",
|
||||
"IN-HR": "Haryana",
|
||||
"IN-JH": "Jharkhand",
|
||||
"IN-JK": "Jammu e Caxemira",
|
||||
"IN-KA": "Carnataca",
|
||||
"IN-KL": "Kerala",
|
||||
"IN-LA": "Ladaque",
|
||||
"IN-LD": "Laquedivas",
|
||||
"IN-MH": "Maarastra",
|
||||
"IN-ML": "Meghalaya",
|
||||
"IN-MN": "Manipur",
|
||||
"IN-MP": "Madhya Pradesh",
|
||||
"IN-MZ": "Mizoram",
|
||||
"IN-NL": "Nagaland",
|
||||
"IN-OR": "Orissa",
|
||||
"IN-PB": "Punjab",
|
||||
"IN-PY": "Puducherry",
|
||||
"IN-RJ": "Rajastão",
|
||||
"IN-SK": "Siquim",
|
||||
"IN-TG": "Telangana",
|
||||
"IN-TN": "Tamil Nadu",
|
||||
"IN-TR": "Tripura",
|
||||
"IN-UP": "Utar Pradexe",
|
||||
"IN-UT": "Utaracanda",
|
||||
"IN-WB": "Bengala Ocidental"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,43 @@
|
|||
{
|
||||
"indiaNote": "India are propria secțiune, prima: are {count} popoare neatinse, mult mai multe decât orice altă țară, așa că fiecare dintre statele și teritoriile sale ale Uniunii are propriul afiș.",
|
||||
"indiaStateNoGroups": "Aici nu este listat niciun popor neatins.",
|
||||
"indiaItemCount": "un stat sau teritoriu al Uniunii | {n} state și teritorii ale Uniunii | {n} de state și teritorii ale Uniunii"
|
||||
"indiaItemCount": "un stat sau teritoriu al Uniunii | {n} state și teritorii ale Uniunii | {n} de state și teritorii ale Uniunii",
|
||||
"stateNames": {
|
||||
"IN-AN": "Insulele Andaman și Nicobar",
|
||||
"IN-AP": "Andhra Pradesh",
|
||||
"IN-AR": "Arunachal Pradesh",
|
||||
"IN-AS": "Assam",
|
||||
"IN-BR": "Bihar",
|
||||
"IN-CH": "Teritoriul Unional Chandigarh",
|
||||
"IN-CT": "Chhattisgarh",
|
||||
"IN-DH": "Dadra și Nagar Haveli și Daman și Diu",
|
||||
"IN-DL": "Delhi",
|
||||
"IN-GA": "Goa",
|
||||
"IN-GJ": "Gujarat",
|
||||
"IN-HP": "Himachal Pradesh",
|
||||
"IN-HR": "Haryana",
|
||||
"IN-JH": "Jharkhand",
|
||||
"IN-JK": "Jammu și Cașmir",
|
||||
"IN-KA": "Karnataka",
|
||||
"IN-KL": "Kerala",
|
||||
"IN-LA": "Ladakh",
|
||||
"IN-LD": "Lakshadweep",
|
||||
"IN-MH": "Maharashtra",
|
||||
"IN-ML": "Meghalaya",
|
||||
"IN-MN": "Manipur",
|
||||
"IN-MP": "Madhya Pradesh",
|
||||
"IN-MZ": "Mizoram",
|
||||
"IN-NL": "Nagaland",
|
||||
"IN-OR": "Odisha",
|
||||
"IN-PB": "Punjab",
|
||||
"IN-PY": "Puducherry",
|
||||
"IN-RJ": "Rajasthan",
|
||||
"IN-SK": "Sikkim",
|
||||
"IN-TG": "Telangana",
|
||||
"IN-TN": "Tamil Nadu",
|
||||
"IN-TR": "Tripura",
|
||||
"IN-UP": "Uttar Pradesh",
|
||||
"IN-UT": "Uttarakhand",
|
||||
"IN-WB": "Bengalul de Vest"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,43 @@
|
|||
{
|
||||
"indiaNote": "У Индии свой раздел, первый: число недостигнутых народов в ней — {count}, намного больше, чем в любой другой стране, поэтому у каждого её штата и союзной территории есть свой плакат.",
|
||||
"indiaStateNoGroups": "Здесь не указано ни одного недостигнутого народа.",
|
||||
"indiaItemCount": "{n} штат или союзная территория | {n} штата и союзные территории | {n} штатов и союзных территорий | {n} штата и союзной территории"
|
||||
"indiaItemCount": "{n} штат или союзная территория | {n} штата и союзные территории | {n} штатов и союзных территорий | {n} штата и союзной территории",
|
||||
"stateNames": {
|
||||
"IN-AN": "Андаманские и Никобарские острова",
|
||||
"IN-AP": "Андхра-Прадеш",
|
||||
"IN-AR": "Аруначал-Прадеш",
|
||||
"IN-AS": "Ассам",
|
||||
"IN-BR": "Бихар",
|
||||
"IN-CH": "Чандигарх",
|
||||
"IN-CT": "Чхаттисгарх",
|
||||
"IN-DH": "Дадра и Нагар-Хавели и Даман и Диу",
|
||||
"IN-DL": "Дели",
|
||||
"IN-GA": "Гоа",
|
||||
"IN-GJ": "Гуджарат",
|
||||
"IN-HP": "Химачал-Прадеш",
|
||||
"IN-HR": "Харьяна",
|
||||
"IN-JH": "Джаркханд",
|
||||
"IN-JK": "Джамму и Кашмир",
|
||||
"IN-KA": "Карнатака",
|
||||
"IN-KL": "Керала",
|
||||
"IN-LA": "Ладакх",
|
||||
"IN-LD": "Лакшадвип",
|
||||
"IN-MH": "Махараштра",
|
||||
"IN-ML": "Мегхалая",
|
||||
"IN-MN": "Манипур",
|
||||
"IN-MP": "Мадхья-Прадеш",
|
||||
"IN-MZ": "Мизорам",
|
||||
"IN-NL": "Нагаленд",
|
||||
"IN-OR": "Одиша",
|
||||
"IN-PB": "Пенджаб",
|
||||
"IN-PY": "Пондичерри",
|
||||
"IN-RJ": "Раджастхан",
|
||||
"IN-SK": "Сикким",
|
||||
"IN-TG": "Телингана",
|
||||
"IN-TN": "Тамилнад",
|
||||
"IN-TR": "Трипура",
|
||||
"IN-UP": "Уттар-Прадеш",
|
||||
"IN-UT": "Уттаракханд",
|
||||
"IN-WB": "Западная Бенгалия"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,43 @@
|
|||
{
|
||||
"indiaNote": "印度有单独的一栏,排在最前:这里有 {count} 个未得之民族群,远多于任何其他国家,因此它的每个邦和中央直辖区都有自己的海报。",
|
||||
"indiaStateNoGroups": "此处未列出任何未得之民族群。",
|
||||
"indiaItemCount": "{n} 个邦和中央直辖区"
|
||||
"indiaItemCount": "{n} 个邦和中央直辖区",
|
||||
"stateNames": {
|
||||
"IN-AN": "安达曼-尼科巴群岛",
|
||||
"IN-AP": "安得拉邦",
|
||||
"IN-AR": "阿鲁纳恰尔邦",
|
||||
"IN-AS": "阿萨姆邦",
|
||||
"IN-BR": "比哈尔邦",
|
||||
"IN-CH": "昌迪加尔",
|
||||
"IN-CT": "切蒂斯格尔邦",
|
||||
"IN-DH": "达德拉-纳加尔哈维利和达曼-第乌",
|
||||
"IN-DL": "德里",
|
||||
"IN-GA": "果阿邦",
|
||||
"IN-GJ": "古吉拉特邦",
|
||||
"IN-HP": "喜马偕尔邦",
|
||||
"IN-HR": "哈里亚纳邦",
|
||||
"IN-JH": "贾坎德邦",
|
||||
"IN-JK": "查谟和克什米尔",
|
||||
"IN-KA": "卡纳塔克邦",
|
||||
"IN-KL": "喀拉拉邦",
|
||||
"IN-LA": "拉达克",
|
||||
"IN-LD": "拉克沙群岛",
|
||||
"IN-MH": "马哈拉施特拉邦",
|
||||
"IN-ML": "梅加拉亚邦",
|
||||
"IN-MN": "曼尼普尔邦",
|
||||
"IN-MP": "中央邦",
|
||||
"IN-MZ": "米佐拉姆邦",
|
||||
"IN-NL": "那加兰邦",
|
||||
"IN-OR": "奥迪沙邦",
|
||||
"IN-PB": "旁遮普邦",
|
||||
"IN-PY": "本地治里",
|
||||
"IN-RJ": "拉贾斯坦邦",
|
||||
"IN-SK": "锡金邦",
|
||||
"IN-TG": "特伦甘纳邦",
|
||||
"IN-TN": "泰米尔纳德邦",
|
||||
"IN-TR": "特里普拉邦",
|
||||
"IN-UP": "北方邦",
|
||||
"IN-UT": "北阿坎德邦",
|
||||
"IN-WB": "西孟加拉邦"
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,14 +31,14 @@
|
|||
* The shared wall always sorts sections AND cards by descending count, so the
|
||||
* dense countries lead and the long tail sinks. There is no floor.
|
||||
*/
|
||||
import { computed, inject, ref, watch } from 'vue'
|
||||
import { computed, inject, onBeforeUnmount, ref, watch } from 'vue'
|
||||
import PosterWall from '@map/components/poster/PosterWall.vue'
|
||||
import { useOptionalT, useOptionalI18n } from '@map/composables/useOptionalT.js'
|
||||
// A country's name in the reader's language (Intl, joined from our ISO-3 codes).
|
||||
import { countryName } from '@map/utils/countryName.js'
|
||||
import { createPeopleGroupRecords } from '@map/lists/peopleGroupRecords.js'
|
||||
import { getApiBaseUrl } from '@map/api/apiBaseUrl.js'
|
||||
import { getRuntimeLocale, detectLocale } from '@map/i18n/index.js'
|
||||
import { getRuntimeLocale, detectLocale, tStatic } from '@map/i18n/index.js'
|
||||
// MOVED to the shared library 2026-09-24: the regions-dashboard poster dropdown is a second
|
||||
// consumer of this same dataset, and RULE 2 puts a dataset with a named second consumer in
|
||||
// library/. Generated by library/scripts/posters/emit-countries.mjs, which now writes there.
|
||||
|
|
@ -108,21 +108,30 @@ try { tRegions = useRegionsI18n().t } catch (_) { /* a host with no i18n reads t
|
|||
|
||||
// ★ INDIA'S STATES AND UNION TERRITORIES, one poster each, like a country one level down. The table is
|
||||
// fetched (and sha-checked) only when the unfiltered wall is shown; a host's filtered wall never asks for it.
|
||||
// A failure hides the section rather than showing cards that cannot print. States with no people groups
|
||||
// listed (Nagaland, Mizoram) are NAMED with a card that says so, never silently left out.
|
||||
// A failure hides the section rather than showing cards that cannot print, and is retried a bounded number of
|
||||
// times (the loader drops a failed fetch from its cache, so a retry really fetches again). States with no people
|
||||
// groups listed (Nagaland, Mizoram) are NAMED with a card that says so, never silently left out.
|
||||
const indiaStates = ref(null)
|
||||
const STATE_RETRY_MS = [5000, 20000, 60000]
|
||||
let stateRetry = null
|
||||
function loadStates(attempt = 0) {
|
||||
loadIndiaStates(assetsBase.value).then((table) => { indiaStates.value = table.states }).catch(() => {
|
||||
if (attempt < STATE_RETRY_MS.length && !filtered.value) stateRetry = setTimeout(() => loadStates(attempt + 1), STATE_RETRY_MS[attempt])
|
||||
})
|
||||
}
|
||||
watch(filtered, (f) => {
|
||||
if (f || indiaStates.value) return
|
||||
loadIndiaStates(assetsBase.value).then((table) => { indiaStates.value = table.states }).catch(() => { indiaStates.value = null })
|
||||
if (f || indiaStates.value || stateRetry) return
|
||||
loadStates()
|
||||
}, { immediate: true })
|
||||
onBeforeUnmount(() => { clearTimeout(stateRetry) })
|
||||
const INDIA_REGION = (byIso3.get('IND') || {}).region || 'Asia'
|
||||
const stateItems = computed(() => {
|
||||
const all = indiaStates.value
|
||||
if (filtered.value || !all) return []
|
||||
const withGroups = statesWithPosters(all).map((st) => ({
|
||||
id: st.id, label: st.name, count: st.count, sheet: '3x3', region: INDIA_REGION, indiaState: true, slugs: st.slugs,
|
||||
id: st.id, iso: st.iso, label: st.name, count: st.count, sheet: '3x3', region: INDIA_REGION, indiaState: true, slugs: st.slugs,
|
||||
}))
|
||||
const none = all.filter((st) => !st.count).map((st) => ({ id: st.id, label: st.name, count: 0, indiaState: true, noGroups: true, slugs: [] }))
|
||||
const none = all.filter((st) => !st.count).map((st) => ({ id: st.id, iso: st.iso, label: st.name, count: 0, indiaState: true, noGroups: true, slugs: [] }))
|
||||
return [...withGroups, ...none]
|
||||
})
|
||||
|
||||
|
|
@ -130,12 +139,15 @@ const items = computed(() => {
|
|||
const l = wallLocale && (wallLocale.value ?? wallLocale)
|
||||
const locale = (typeof l === 'string' && l) || getRuntimeLocale() || detectLocale() || 'en'
|
||||
const countries = selected.value
|
||||
// State names stay as the table has them (place names from the data); only country names are localized.
|
||||
if (/^en\b/i.test(locale)) return [...countries, ...stateItems.value]
|
||||
// A state's card is named in the reader's language from the catalogue (countryPosters.stateNames, generated from
|
||||
// Wikidata by scripts/emit-india-state-names.mjs); its printed sheet stays English, like a country's.
|
||||
const states = /^en\b/i.test(locale) ? stateItems.value
|
||||
: stateItems.value.map((st) => ({ ...st, label: tStatic(`countryPosters.stateNames.${st.iso}`, locale) || st.label }))
|
||||
if (/^en\b/i.test(locale)) return [...countries, ...states]
|
||||
return [...countries.map((c) => {
|
||||
const name = countryName(c.iso3, locale)
|
||||
return name && name !== c.iso3 ? { ...c, label: name } : c
|
||||
}), ...stateItems.value]
|
||||
}), ...states]
|
||||
})
|
||||
|
||||
// ★ EVERY COUNTRY PRINTS ITS PRAYER RESOURCES — the list, the card deck and the packet — through the
|
||||
|
|
|
|||
44
plugin-designs/country-posters/data/india-state-names.meta.json
vendored
Normal file
44
plugin-designs/country-posters/data/india-state-names.meta.json
vendored
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
{
|
||||
"what": "India's 36 states and union territories, named in the 11 UI locales, for the Country Posters wall's card labels.",
|
||||
"source": "Wikidata (https://www.wikidata.org): labels of the items whose ISO 3166-2 code (P300) matches data/people-groups/india-states.json; dissolved items (P576) excluded.",
|
||||
"licence": "CC0 1.0: Wikidata structured data is released under CC0 (https://creativecommons.org/publicdomain/zero/1.0/).",
|
||||
"english": "the state table's own name (the English wall is unchanged); Wikidata's English is only a cross-check",
|
||||
"retrieved": "2026-09-30",
|
||||
"regenerate": "node plugin-designs/country-posters/scripts/emit-india-state-names.mjs",
|
||||
"query": "SELECT ?code ?lang ?label WHERE {\n VALUES ?code { \"IN-AN\" \"IN-AP\" \"IN-AR\" \"IN-AS\" \"IN-BR\" \"IN-CG\" \"IN-CH\" \"IN-DH\" \"IN-DL\" \"IN-GA\" \"IN-GJ\" \"IN-HP\" \"IN-HR\" \"IN-JH\" \"IN-JK\" \"IN-KA\" \"IN-KL\" \"IN-LA\" \"IN-LD\" \"IN-MH\" \"IN-ML\" \"IN-MN\" \"IN-MP\" \"IN-MZ\" \"IN-NL\" \"IN-OD\" \"IN-PB\" \"IN-PY\" \"IN-RJ\" \"IN-SK\" \"IN-TN\" \"IN-TR\" \"IN-TS\" \"IN-UK\" \"IN-UP\" \"IN-WB\" }\n ?item wdt:P300 ?code .\n FILTER NOT EXISTS { ?item wdt:P576 ?dissolved }\n ?item rdfs:label ?label . BIND(LANG(?label) AS ?lang)\n FILTER(?lang IN (\"en\", \"es\", \"fr\", \"pt\", \"de\", \"it\", \"ro\", \"ru\", \"ar\", \"hi\", \"zh-hans\", \"zh-cn\", \"zh\"))\n}",
|
||||
"codeAliases": {
|
||||
"IN-CT": "IN-CG",
|
||||
"IN-OR": "IN-OD",
|
||||
"IN-TG": "IN-TS",
|
||||
"IN-UT": "IN-UK"
|
||||
},
|
||||
"reviewedOverrides": [
|
||||
"IN-DH zh: \"达德拉-纳加尔哈维利和达曼-第乌\" (Wikidata has only a Traditional-script zh label; converted character by character to the Simplified catalogue script)",
|
||||
"IN-OR ar: \"أديشة\" (the label is the pre-2011 name Orissa (أريسة); ar.wikipedia's title for the item is أديشة (Odisha))"
|
||||
],
|
||||
"gaps": [],
|
||||
"ambiguous": [],
|
||||
"fallbacks": [
|
||||
"IN-CH es: \"Chandigarh\" from the same-named item (1 of 1)",
|
||||
"IN-CH fr: \"Chandigarh\" from the same-named item (1 of 1)",
|
||||
"IN-CH pt: \"Chandigarh\" from the same-named item (1 of 1)",
|
||||
"IN-CH de: \"Chandigarh\" from the same-named item (1 of 1)",
|
||||
"IN-CH it: \"Chandigarh\" from the same-named item (1 of 1)",
|
||||
"IN-CH ar: \"شَنديغار\" from the same-named item (1 of 1)",
|
||||
"IN-CH hi: \"चण्डीगढ़\" from the same-named item (1 of 1)",
|
||||
"IN-CH zh: \"昌迪加尔\" from the same-named item (1 of 1)",
|
||||
"IN-DL es: \"Delhi\" from the same-named item (preferred)",
|
||||
"IN-DL fr: \"Delhi\" from the same-named item (preferred)",
|
||||
"IN-DL pt: \"Delhi\" from the same-named item (preferred)",
|
||||
"IN-DL de: \"Delhi\" from the same-named item (preferred)",
|
||||
"IN-DL it: \"Delhi\" from the same-named item (preferred)",
|
||||
"IN-DL ro: \"Delhi\" from the same-named item (preferred)",
|
||||
"IN-DL ru: \"Дели\" from the same-named item (preferred)",
|
||||
"IN-DL ar: \"دلهي\" from the same-named item (preferred)",
|
||||
"IN-DL hi: \"दिल्ली\" from the same-named item (preferred)",
|
||||
"IN-DL zh: \"德里\" from the same-named item (preferred)"
|
||||
],
|
||||
"englishMismatches": [
|
||||
"IN-DL: table \"Delhi\" vs Wikidata \"National Capital Territory of Delhi\"; same-named labels preferred"
|
||||
]
|
||||
}
|
||||
|
|
@ -141,9 +141,27 @@ export function armC(H, states, adm1Ind) {
|
|||
return fails
|
||||
}
|
||||
|
||||
// ARM E: India is its OWN section, FIRST, counted ONCE. The India country card, the state cards and the none-listed
|
||||
// cards group together; the section's total is India's own count (not the card sum, which counts 855 twice); on that
|
||||
// true total it outranks every regional section. PosterWall's default (no sectionTotal) must still be the card sum.
|
||||
// ARM D: the state cards' localized names cover EXACTLY the table's divisions in every locale (a runtime-built key,
|
||||
// `countryPosters.stateNames.${iso}`, that the i18n call-site gates cannot see), English is the table's own name, and
|
||||
// the generated names carry their source licence.
|
||||
const NAME_LOCALES = ['en', 'es', 'fr', 'pt', 'de', 'it', 'ro', 'ru', 'ar', 'hi', 'zh']
|
||||
export function armD(states, areas, meta) {
|
||||
const fails = []
|
||||
const want = new Set((states || []).map((st) => st.iso))
|
||||
for (const l of NAME_LOCALES) {
|
||||
const names = (areas[l] && areas[l].stateNames) || {}
|
||||
const have = new Set(Object.keys(names))
|
||||
const missing = [...want].filter((x) => !have.has(x)), extra = [...have].filter((x) => !want.has(x))
|
||||
const empty = Object.entries(names).filter(([, v]) => typeof v !== 'string' || !v.trim()).map(([k]) => k)
|
||||
if (missing.length || extra.length || empty.length) fails.push(`${l} countryPosters.stateNames: missing [${missing}] extra [${extra}] empty [${empty}]`)
|
||||
}
|
||||
const en = (areas.en && areas.en.stateNames) || {}
|
||||
const drift = (states || []).filter((st) => en[st.iso] !== st.name).map((st) => st.iso)
|
||||
if (drift.length) fails.push(`English state names differ from the table's: ${drift.join(', ')} (re-run emit-india-state-names.mjs)`)
|
||||
if (!meta || !/CC0/.test(String(meta.licence || ''))) fails.push('india-state-names.meta.json must record the source licence (CC0)')
|
||||
return fails
|
||||
}
|
||||
|
||||
// ARM F — A DESKTOP-ONLY CARD ON A PHONE (India): in EACH caller (the wall, the Regions list) its rows REJECT with
|
||||
// poster.phoneLimitAll before any record is fetched, never resolve [] (the print path reads [] as "that list has no
|
||||
// people groups to print", on a card that has 855), and the card shows the same full-block notice.
|
||||
|
|
@ -158,6 +176,9 @@ export function armF(srcs) {
|
|||
return fails
|
||||
}
|
||||
|
||||
// ARM E: India is its OWN section, FIRST, counted ONCE. The India country card, the state cards and the none-listed
|
||||
// cards group together; the section's total is India's own count (not the card sum, which counts 855 twice); on that
|
||||
// true total it outranks every regional section. PosterWall's default (no sectionTotal) must still be the card sum.
|
||||
export function armE(countries, states, wallSrc, posterWallSrc, H) {
|
||||
const fails = []
|
||||
if (!/:section-total=/.test(wallSrc)) fails.push('country-poster-wall.vue does not pass :section-total, so India is counted twice')
|
||||
|
|
@ -189,6 +210,9 @@ async function main() {
|
|||
const adm1Ind = JSON.parse(readFileSync(join(ROOT, 'public/dx-maps/assets/boundaries/gb-IND-ADM1.geojson'), 'utf8'))
|
||||
if (states.length < 30 || (adm1Ind.features || []).length < 30) { console.log(`NOT MEASURED: state table ${states.length} / ADM1 ${(adm1Ind.features || []).length} features (floor 30)`); process.exitCode = 75; return }
|
||||
|
||||
const areas = Object.fromEntries(NAME_LOCALES.map((l) => [l, JSON.parse(readFileSync(join(ROOT, `library/i18n/locales/${l}/countryPosters.json`), 'utf8'))]))
|
||||
const meta = JSON.parse(readFileSync(join(ROOT, 'plugin-designs/country-posters/data/india-state-names.meta.json'), 'utf8'))
|
||||
|
||||
const files = {}
|
||||
for (const p of listSources(PD)) files[relative(ROOT, p)] = readFileSync(p, 'utf8')
|
||||
|
||||
|
|
@ -210,6 +234,8 @@ async function main() {
|
|||
['a packet page becomes a large sheet', () => armB(seriesFor, countries, (it, f) => (it?.iso3 === 'IND' ? '60x96' : f))],
|
||||
['the wall resolves [] for a phone-blocked card', () => armF({ wall: files[wall].replace("const desktopOnly = () => Promise.reject(keyedError('poster.phoneLimitAll'", "const desktopOnly = () => Promise.resolve([]) || (keyedError('poster.phoneLimitAll'"), regions: REG })],
|
||||
['the Regions list resolves [] for a phone-blocked card', () => armF({ wall: files[wall], regions: REG.replace("phoneBlocked(item) ? Promise.reject(keyedError('poster.phoneLimitAll'", "phoneBlocked(item) ? Promise.resolve([]) || (keyedError('poster.phoneLimitAll'") })],
|
||||
['a locale loses a state name', () => armD(states, { ...areas, ro: { ...areas.ro, stateNames: Object.fromEntries(Object.entries(areas.ro.stateNames).filter(([k]) => k !== 'IN-GJ')) } }, meta)],
|
||||
['the names lose their licence line', () => armD(states, areas, { ...meta, licence: '' })],
|
||||
['a helper that mutates the shared ADM1', () => armC({ ...H, stateGeometry: (z, a, n) => { (a.features || []).forEach((f) => { if (f.properties.shapeName === n) f.properties.listId = z.id }); return H.stateGeometry(z, a, n) } }, states, JSON.parse(JSON.stringify(adm1Ind)))],
|
||||
]
|
||||
let bad = 0
|
||||
|
|
@ -228,12 +254,12 @@ async function main() {
|
|||
|
||||
const callers = []
|
||||
const E = armE(countries, states, files['plugin-designs/country-posters/country-poster-wall.vue'], readFileSync(join(ROOT, 'library/components/poster/PosterWall.vue'), 'utf8'), H)
|
||||
const fails = [...armA(files, callers), ...armB(seriesFor, countries, sheetFormatFor), ...armC(H, states, adm1Ind), ...E.fails, ...armF({ wall: files['plugin-designs/country-posters/country-poster-wall.vue'], regions: REG })]
|
||||
const fails = [...armA(files, callers), ...armB(seriesFor, countries, sheetFormatFor), ...armC(H, states, adm1Ind), ...E.fails, ...armD(states, areas, meta), ...armF({ wall: files['plugin-designs/country-posters/country-poster-wall.vue'], regions: REG })]
|
||||
const missing = [...KNOWN_CALLERS, `${STATE_CALLER}#state`].filter((k) => !callers.includes(k))
|
||||
if (missing.length) fails.push(`known callers not found calling makeCountrySheet: ${missing.join(', ')}`)
|
||||
if (fails.length) { fails.forEach((f) => console.log(`FAIL ${f}`)); process.exitCode = 1; return }
|
||||
const ind = seriesFor(countries, countries.find((c) => c.iso3 === 'IND'))
|
||||
console.log(`PASS check:country-sheet-one-path — ${Object.keys(files).length} plugin sources parsed-or-skipped, makeCountrySheet callers: ${callers.join(', ')}; seriesFor over ${countries.length} countries (India ${ind.index} of ${ind.totalLists}); ${H.statesWithPosters(states).length} state posters, series 1..${H.statesWithPosters(states).length}, every outline found; sections ${E.order.slice(0, 3).map(([g, t]) => `${g} ${t}`).join(' > ')}`)
|
||||
console.log(`PASS check:country-sheet-one-path — ${Object.keys(files).length} plugin sources parsed-or-skipped, makeCountrySheet callers: ${callers.join(', ')}; seriesFor over ${countries.length} countries (India ${ind.index} of ${ind.totalLists}); ${H.statesWithPosters(states).length} state posters, series 1..${H.statesWithPosters(states).length}, every outline found; sections ${E.order.slice(0, 3).map(([g, t]) => `${g} ${t}`).join(' > ')}; state names in ${NAME_LOCALES.length} locales x ${states.length}`)
|
||||
}
|
||||
|
||||
main().catch((e) => { console.error(`FAIL ${e.stack || e}`); process.exitCode = 1 })
|
||||
|
|
|
|||
|
|
@ -0,0 +1,134 @@
|
|||
#!/usr/bin/env node
|
||||
// emit-india-state-names.mjs — India's 36 states and union territories named in the 11 UI locales, for the Country
|
||||
// Posters wall's India section: the CARD labels, the print HUD and the packet/list titles. The printed sheet stays
|
||||
// English by recorded decision (series.json english_only_note), like every country poster.
|
||||
//
|
||||
// SOURCE: Wikidata labels, matched on ISO 3166-2 (P300) against data/people-groups/india-states.json. Wikidata's
|
||||
// structured data is CC0. The labels are human-edited, not machine translation. Dissolved items (P576) are excluded,
|
||||
// so a retired code such as the pre-2020 Dadra and Nagar Haveli cannot win.
|
||||
// English is the TABLE's own name, so the English wall does not change; Wikidata's English is only a cross-check.
|
||||
// A locale Wikidata has no label for falls back to the English name AND is recorded in the meta file, never silently.
|
||||
//
|
||||
// Writes: library/i18n/locales/<locale>/countryPosters.json -> "stateNames": { "IN-GJ": "…", … } (other keys kept)
|
||||
// plugin-designs/country-posters/data/india-state-names.meta.json (source, licence, query, date, gaps)
|
||||
// Regenerate: node plugin-designs/country-posters/scripts/emit-india-state-names.mjs
|
||||
import { readFileSync, writeFileSync } from 'node:fs'
|
||||
import { join, dirname } from 'node:path'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
|
||||
const ROOT = join(dirname(fileURLToPath(import.meta.url)), '..', '..', '..')
|
||||
const LOCALES = ['en', 'es', 'fr', 'pt', 'de', 'it', 'ro', 'ru', 'ar', 'hi', 'zh']
|
||||
const WD_LANG = { zh: ['zh-hans', 'zh-cn', 'zh'] } // the zh catalogue is Simplified
|
||||
const wdLangs = (l) => WD_LANG[l] || [l]
|
||||
|
||||
// The state table keeps geoBoundaries' ISO codes; ISO 3166-2:IN has since renamed four, and Wikidata's P300 holds
|
||||
// the CURRENT code. Queried under the current code, keyed back to the table's.
|
||||
const CODE_ALIAS = { 'IN-CT': 'IN-CG', 'IN-OR': 'IN-OD', 'IN-TG': 'IN-TS', 'IN-UT': 'IN-UK' }
|
||||
const wdCode = (iso) => CODE_ALIAS[iso] || iso
|
||||
|
||||
// REVIEWED OVERRIDES (hi, ar, zh read by eye, 2026-09-30), each with its evidence. Kept small and explicit: neither
|
||||
// Wikidata's labels nor its Wikipedia titles are uniformly current (zh's Odisha TITLE is the old Orissa while its
|
||||
// label is current; ar's Odisha LABEL is the old Orissa while its title is current), so no blanket rule is safe.
|
||||
const OVERRIDES = {
|
||||
'IN-OR': { ar: ['أديشة', "the label is the pre-2011 name Orissa (أريسة); ar.wikipedia's title for the item is أديشة (Odisha)"] },
|
||||
'IN-DH': { zh: ['达德拉-纳加尔哈维利和达曼-第乌', 'Wikidata has only a Traditional-script zh label; converted character by character to the Simplified catalogue script'] },
|
||||
}
|
||||
|
||||
const states = JSON.parse(readFileSync(join(ROOT, 'data/people-groups/india-states.json'), 'utf8')).states
|
||||
const isos = states.map((s) => wdCode(s.iso)).sort()
|
||||
const langs = [...new Set(LOCALES.flatMap(wdLangs))]
|
||||
const query = `SELECT ?code ?lang ?label WHERE {
|
||||
VALUES ?code { ${isos.map((c) => `"${c}"`).join(' ')} }
|
||||
?item wdt:P300 ?code .
|
||||
FILTER NOT EXISTS { ?item wdt:P576 ?dissolved }
|
||||
?item rdfs:label ?label . BIND(LANG(?label) AS ?lang)
|
||||
FILTER(?lang IN (${langs.map((l) => `"${l}"`).join(', ')}))
|
||||
}`
|
||||
const res = await fetch('https://query.wikidata.org/sparql?format=json&query=' + encodeURIComponent(query), {
|
||||
headers: { accept: 'application/sparql-results+json', 'user-agent': 'dx-maps country-posters emit-india-state-names' },
|
||||
signal: AbortSignal.timeout(60000),
|
||||
})
|
||||
if (!res.ok) { console.error(`Wikidata ${res.status}`); process.exit(1) }
|
||||
const rows = (await res.json()).results.bindings
|
||||
const got = {} // iso -> Wikidata language -> Set(labels)
|
||||
for (const r of rows) ((got[r.code.value] ||= {})[r.lang.value] ||= new Set()).add(r.label.value)
|
||||
|
||||
// FALLBACK for a language the matched item has no label in (e.g. the "National Capital Territory of Delhi" item):
|
||||
// the labels of items in India (P17 = Q668) whose English label IS the table's name (the city of Delhi,
|
||||
// Chandigarh). Used only for the missing languages, and recorded.
|
||||
async function sameNameLabels(name) {
|
||||
const q = `SELECT ?lang ?label WHERE { ?item rdfs:label ${JSON.stringify(name)}@en ; wdt:P17 wd:Q668 .
|
||||
?item rdfs:label ?label . BIND(LANG(?label) AS ?lang) FILTER(?lang IN (${langs.map((l) => `"${l}"`).join(', ')})) }`
|
||||
const r = await fetch('https://query.wikidata.org/sparql?format=json&query=' + encodeURIComponent(q), {
|
||||
headers: { accept: 'application/sparql-results+json', 'user-agent': 'dx-maps country-posters emit-india-state-names' },
|
||||
signal: AbortSignal.timeout(60000),
|
||||
})
|
||||
if (!r.ok) throw new Error(`Wikidata ${r.status}`)
|
||||
const by = {}
|
||||
for (const b of (await r.json()).results.bindings) {
|
||||
const m = (by[b.lang.value] ||= new Map()); m.set(b.label.value, (m.get(b.label.value) || 0) + 1)
|
||||
}
|
||||
return by // lang -> Map(label -> how many same-named items carry it)
|
||||
}
|
||||
const fallbacks = [], overridden = [], unreviewedZh = []
|
||||
|
||||
const gaps = [], ambiguous = [], englishMismatches = []
|
||||
const names = Object.fromEntries(LOCALES.map((l) => [l, {}]))
|
||||
for (const st of [...states].sort((a, b) => a.iso.localeCompare(b.iso))) {
|
||||
const wd = got[wdCode(st.iso)] || {}
|
||||
if (!Object.keys(wd).length) gaps.push(`${st.iso}: no Wikidata item (queried as ${wdCode(st.iso)})`)
|
||||
let same = null
|
||||
const wdEn = wd.en && [...wd.en][0]
|
||||
// The table names the division more briefly than its item ("Delhi" vs "National Capital Territory of Delhi"): then
|
||||
// the SAME-NAMED item's labels (the city of Delhi) are preferred in every language, so hi and ru match the English.
|
||||
const preferSame = Boolean(wdEn && wdEn !== st.name)
|
||||
if (preferSame) englishMismatches.push(`${st.iso}: table "${st.name}" vs Wikidata "${wdEn}"; same-named labels preferred`)
|
||||
for (const l of LOCALES) {
|
||||
if (l === 'en') { names.en[st.iso] = st.name; continue }
|
||||
const ov = OVERRIDES[st.iso] && OVERRIDES[st.iso][l]
|
||||
if (ov) { names[l][st.iso] = ov[0]; overridden.push(`${st.iso} ${l}: "${ov[0]}" (${ov[1]})`); continue }
|
||||
if (preferSame) {
|
||||
same ||= await sameNameLabels(st.name)
|
||||
const m = wdLangs(l).map((w) => same[w]).find((x) => x && x.size)
|
||||
if (m) { const [label] = [...m].sort((a, b) => b[1] - a[1] || a[0].localeCompare(b[0]))[0]; names[l][st.iso] = label; fallbacks.push(`${st.iso} ${l}: "${label}" from the same-named item (preferred)`); continue }
|
||||
}
|
||||
const src = wdLangs(l).find((w) => wd[w] && wd[w].size)
|
||||
if (l === 'zh' && src === 'zh') unreviewedZh.push(`${st.iso}: only a plain "zh" label (script unknown: may be Traditional); add a reviewed OVERRIDE`)
|
||||
const hit = src && wd[src]
|
||||
if (!hit) {
|
||||
same ||= await sameNameLabels(st.name)
|
||||
const m = wdLangs(l).map((w) => same[w]).find((x) => x && x.size)
|
||||
if (m) {
|
||||
const [label, n] = [...m].sort((a, b) => b[1] - a[1] || a[0].localeCompare(b[0]))[0]
|
||||
names[l][st.iso] = label; fallbacks.push(`${st.iso} ${l}: "${label}" from the same-named item (${n} of ${[...m.values()].reduce((a, x) => a + x, 0)})`)
|
||||
continue
|
||||
}
|
||||
names[l][st.iso] = st.name; gaps.push(`${st.iso} ${l}: no label, English used`); continue
|
||||
}
|
||||
if (hit.size > 1) ambiguous.push(`${st.iso} ${l}: ${[...hit].join(' | ')}`)
|
||||
names[l][st.iso] = [...hit].sort()[0]
|
||||
}
|
||||
}
|
||||
for (const l of LOCALES) {
|
||||
const p = join(ROOT, `library/i18n/locales/${l}/countryPosters.json`)
|
||||
const area = JSON.parse(readFileSync(p, 'utf8'))
|
||||
area.stateNames = names[l]
|
||||
writeFileSync(p, JSON.stringify(area, null, 2) + '\n')
|
||||
}
|
||||
const meta = {
|
||||
what: "India's 36 states and union territories, named in the 11 UI locales, for the Country Posters wall's card labels.",
|
||||
source: 'Wikidata (https://www.wikidata.org): labels of the items whose ISO 3166-2 code (P300) matches data/people-groups/india-states.json; dissolved items (P576) excluded.',
|
||||
licence: 'CC0 1.0: Wikidata structured data is released under CC0 (https://creativecommons.org/publicdomain/zero/1.0/).',
|
||||
english: "the state table's own name (the English wall is unchanged); Wikidata's English is only a cross-check",
|
||||
retrieved: new Date().toISOString().slice(0, 10),
|
||||
regenerate: 'node plugin-designs/country-posters/scripts/emit-india-state-names.mjs',
|
||||
query,
|
||||
codeAliases: CODE_ALIAS,
|
||||
reviewedOverrides: overridden,
|
||||
gaps, ambiguous, fallbacks, englishMismatches,
|
||||
}
|
||||
writeFileSync(join(ROOT, 'plugin-designs/country-posters/data/india-state-names.meta.json'), JSON.stringify(meta, null, 2) + '\n')
|
||||
console.log(`states ${states.length}, Wikidata rows ${rows.length}; gaps ${gaps.length}, ambiguous ${ambiguous.length}, fallbacks ${fallbacks.length}, English mismatches ${englishMismatches.length}`)
|
||||
for (const x of [...gaps, ...ambiguous, ...fallbacks, ...overridden, ...englishMismatches]) console.log(' ' + x)
|
||||
// A zh name from a plain "zh" label may be Traditional script in a Simplified catalogue: refuse rather than ship it.
|
||||
if (unreviewedZh.length) { unreviewedZh.forEach((x) => console.error('FAIL ' + x)); process.exitCode = 1 }
|
||||
Loading…
Reference in a new issue