From 2b08a4e8de9c36695bb0d15cc9b8fe213b77ee0f Mon Sep 17 00:00:00 2001 From: doxa-maps-88655c70 <88627970+doxa-maps-88655c70@users.noreply.github.com> Date: Thu, 24 Sep 2026 03:00:38 +0000 Subject: [PATCH] i18n: 408 strings copied from DX-life, 8 locales, RTL, and the data follows too MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Localisation was the lowest dimension on the board at 12. The repo already had the vue-i18n layer — 11 locales, one JSON per area, eager glob, fallbackLocale en — so this adds an AREA, not a mechanism: library/i18n/locales// regions.json, 51 keys x 8 locales, every string COPIED from their own common.json rather than translated by me. The composer takes the namespace from the FILENAME, so the files are flat like legend.json (a "regions" wrapper would have produced regions.regions.*). ★ THE REASON IT DIDN'T WORK, AND WHY IT FAILED SILENTLY. With the Spanish catalogue provably in the bundle, every string still rendered English. The bundle installed i18n with app.use() but never app.provide('appI18n') — so ProfileLoader could not drive the locale (it does exactly that at ProfileLoader.vue:168-169, from profile-config.locale, its "established contract"), and createAppI18n resolves its locale ONCE from , which every generated leaf page bakes as "en". One line, copied from doxa-simple-map/index.js:84-86. It degraded quietly because the t() shim falls back to its key, so a missing catalogue renders as English instead of throwing — convenient in production, and exactly what hid this. t() is a shim, not vue-i18n's t(), because their keys ARE English sentences and several contain dots ('Loading results...', 'Type to search...') which is vue-i18n's key separator. tm() returns the namespace object and we index it by the literal string, so the port reads 1:1 with their source: t('Prayer Coverage'). Plugin-local, per the placement rule — it is four lines shaped entirely by how these pages were written. THE DATA FOLLOWS THE LOCALE TOO, which the chrome alone would have hidden. The prayer API localises its labels from ?lang=, and our components read cfg.languageCode while the locale arrives as cfg.locale. Measured with ar: the whole UI translated and every country in the table stayed English. Now the fetch falls through locale/lang and refetches on change (Angola -> the Arabic list). RTL: ar sets dir on OUR OWN root via RTL_LOCALES, the house pattern (doxa-simple-map.vue:246/1346) — never document.documentElement, which belongs to whatever page embeds us. Verified in a screenshot, not just an attribute: the goal cards reverse order, the table right-aligns, the progress bars fill from the right. A CLONE FIX came free with it. Porting their uupgListTranslations.ts — the authoritative list of what this component's labels are called — corrected strings I had written from the markup instead: the rop1 filter is "People Group" and I had "Affinity Bloc"; the search placeholder is the full "Search names, country/continent, religions..."; prayer_coverage reads "Intercessors". Two assertions of mine were wrong again, both failing on correct behaviour: the back-link compared for equality when it carries their leading arrow, and the RTL check read document.documentElement.dir when an embedded element must not set it. Not done: it/ro/zh have no regions.json — DX-life translates 8 of our 11 — and resolve through fallbackLocale en, which library/i18n/README says is fine. Oswald (their Cyrillic heading face) is still unvendored. English unchanged throughout: region 68/68 vs live, country 28/28, chooser, map and dashboard suites all green, no gate newly red. --- library/i18n/locales/ar/regions.json | 53 ++++++++++ library/i18n/locales/de/regions.json | 53 ++++++++++ library/i18n/locales/en/regions.json | 53 ++++++++++ library/i18n/locales/es/regions.json | 53 ++++++++++ library/i18n/locales/fr/regions.json | 53 ++++++++++ library/i18n/locales/hi/regions.json | 53 ++++++++++ library/i18n/locales/pt/regions.json | 53 ++++++++++ library/i18n/locales/ru/regions.json | 53 ++++++++++ plugin-designs/regions-dashboard/index.js | 13 ++- .../regions-dashboard/region-dashboards.vue | 100 +++++++++++------- .../regions-dashboard/regions-list.vue | 17 ++- .../regions-dashboard/src/UupgsList.vue | 62 ++++++++--- .../regions-dashboard/src/useRegionsI18n.js | 53 ++++++++++ public/doxa-maps/manifest.json | 8 +- .../region-dashboards/index.html | 2 +- .../regions-dashboard/regions-dashboard.js | 52 ++++----- .../regions-dashboard/regions-list/index.html | 2 +- .../regions-dashboard/regions-mfe/index.html | 2 +- 18 files changed, 644 insertions(+), 91 deletions(-) create mode 100644 library/i18n/locales/ar/regions.json create mode 100644 library/i18n/locales/de/regions.json create mode 100644 library/i18n/locales/en/regions.json create mode 100644 library/i18n/locales/es/regions.json create mode 100644 library/i18n/locales/fr/regions.json create mode 100644 library/i18n/locales/hi/regions.json create mode 100644 library/i18n/locales/pt/regions.json create mode 100644 library/i18n/locales/ru/regions.json create mode 100644 plugin-designs/regions-dashboard/src/useRegionsI18n.js diff --git a/library/i18n/locales/ar/regions.json b/library/i18n/locales/ar/regions.json new file mode 100644 index 000000000..3dea65cfe --- /dev/null +++ b/library/i18n/locales/ar/regions.json @@ -0,0 +1,53 @@ +{ + "%count% people groups in %countries% countries": "%count% مجموعة بشرية في %countries% دولة", + "%region% has %count% people groups across %countries% countries. Each pin is coloured by how many people are praying for that people group.": "تضم %region% %count% مجموعة بشرية في %countries% دولة. يشير لون كل نقطة إلى عدد الأشخاص الذين يصلّون من أجل تلك المجموعة البشرية.", + "1+ People Praying": "شخص واحد أو أكثر يصلّي", + "100+ People Praying": "أكثر من 100 شخص يصلّون", + "Adopted": "تم انتماؤه", + "Adoption Progress": "تقدُّم الإنتماء", + "All Regions": "جميع المناطق", + "Alternate Names": "الأسماء البديلة", + "Clear All": "مسح الكل", + "Countries": "الدول", + "Countries in this region": "الدول في هذه المنطقة", + "Country": "الدولة", + "Engaged": "مُنخرَط", + "Engagement Progress": "تقدُّم الانخراط", + "Every unengaged people group adopted by a church committed to prayer, giving, and sending": "كل مجموعة بشرية غير مبشرة تتبناها كنيسة ملتزمة بالصلاة والعطاء والإرسال", + "Exact Search": "بحث دقيق", + "Find unreached people groups by region and country.": "ابحث عن المجموعات البشرية غير المُبلَّغة حسب المنطقة والدولة.", + "Full Profile": "الملف الشخصي الكامل", + "Goal": "الهدف", + "Hide Filters": "إخفاء المرشحات", + "Intercessors": "المتشفعين", + "Load More": "تحميل المزيد", + "Loading results...": "النتائج قيد التحميل...", + "Mobilize 100+ people praying daily for each DOXA people group": "حشد أكثر من 100 شخص للصلاة يوميًا من أجل كل مجموعة بشرية من مجموعات دوكسا", + "No One Praying": "لا أحد يصلّي", + "No options found": "لم يتم العثور على أي خيارات", + "No unengaged people groups by 2033": "الهدف هو القضاء على جميع الشعوب الغير مخدومة روحيا بحلول عام 2033", + "Not Adopted": "لم يتم انتماؤه", + "Other": "أخرى", + "Page Not Found": "الصفحة غير موجودة", + "People Group": "مجموعة بشرية", + "People Groups": "مجموعات بشرية", + "People committed to praying": "الأشخاص الذين التزموا بالصلاة", + "Population": "عدد السكان", + "Prayer Coverage": "التغطية المستمرة بالصلاة", + "Prayer coverage progress": "تقدم تغطية الصلاة", + "Regions": "المناطق", + "Religion": "الدين", + "Search names, country/continent, religions...": "إبحث عن الأسماء، الدولة/القارة، الأديان...", + "See %region% dashboard": "عرض لوحة معلومات %region%", + "See All": "عرض جميع العناصر", + "Select": "اختر", + "Show Filters": "إظهار عوامل التصفية", + "There are %count% people groups in %country%. Check the map for the people groups on the border of this country as well.": "توجد %count% مجموعات بشرية في %country%. تحقق من الخريطة لمعرفة المجموعات البشرية الواقعة على حدود هذه الدولة أيضًا.", + "Total": "المجموع", + "Type to search...": "اكتب ما تريد البحث عنه...", + "Unengaged people groups": "الشعوب الغير متفاعلة", + "WAGF Block": "كتلة WAGF", + "WAGF Region": "منطقة WAGF", + "people groups adopted": "الشعوب المنتمية", + "people groups engaged": "مجموعات بشرية مُنخرِطة" +} diff --git a/library/i18n/locales/de/regions.json b/library/i18n/locales/de/regions.json new file mode 100644 index 000000000..dc3904698 --- /dev/null +++ b/library/i18n/locales/de/regions.json @@ -0,0 +1,53 @@ +{ + "%count% people groups in %countries% countries": "%count% Volksgruppen in %countries% Ländern", + "%region% has %count% people groups across %countries% countries. Each pin is coloured by how many people are praying for that people group.": "%region% hat %count% Volksgruppen in %countries% Ländern. Die Farbe jedes Punktes zeigt, wie viele Menschen für diese Volksgruppe beten.", + "1+ People Praying": "1+ Menschen beten", + "100+ People Praying": "100+ Menschen beten", + "Adopted": "Angenommen", + "Adoption Progress": "Adoptionsfortschritt", + "All Regions": "Alle Regionen", + "Alternate Names": "Alternative Namen", + "Clear All": "Alle löschen", + "Countries": "Länder", + "Countries in this region": "Länder in dieser Region", + "Country": "Land", + "Engaged": "Engagiert", + "Engagement Progress": "Engagement-Fortschritt", + "Every unengaged people group adopted by a church committed to prayer, giving, and sending": "Jede einzelne der völlig unerreichten Volksgruppen soll von einer Ortsgemeinde adoptiert werden, durch Beten, Geben und Senden", + "Exact Search": "Exakte Suche", + "Find unreached people groups by region and country.": "Finde unerreichte Volksgruppen nach Region und Land.", + "Full Profile": "Vollständiges Profil", + "Goal": "Ziel", + "Hide Filters": "Filter ausblenden", + "Intercessors": "Fürbitter", + "Load More": "Mehr laden", + "Loading results...": "Ergebnisse werden geladen...", + "Mobilize 100+ people praying daily for each DOXA people group": "Mobilisiere 100+ Menschen, die täglich für jede DOXA-Volksgruppe beten", + "No One Praying": "Niemand betet", + "No options found": "Keine Standorte gefunden", + "No unengaged people groups by 2033": "Dass es bis 2033 keine völlig unerreichte Volksgruppe mehr gibt", + "Not Adopted": "noch nicht adoptiert", + "Other": "Andere", + "Page Not Found": "Seite nicht gefunden", + "People Group": "Personengruppe", + "People Groups": "Volksgruppen", + "People committed to praying": "Menschen, die sich dem Beten verpflichtet haben", + "Population": "Bevölkerung", + "Prayer Coverage": "Gebetsabdeckung", + "Prayer coverage progress": "Fortschritt der Gebetsabdeckung", + "Regions": "Regionen", + "Religion": "Primäre Religion", + "Search names, country/continent, religions...": "Suche nach Namen, Land/Kontinent, Religionen...", + "See %region% dashboard": "Dashboard anzeigen: %region%", + "See All": "Alle anzeigen", + "Select": "Auswählen", + "Show Filters": "Filter anzeigen", + "There are %count% people groups in %country%. Check the map for the people groups on the border of this country as well.": "In %country% gibt es %count% Volksgruppen. Sieh auch auf der Karte nach den Volksgruppen an der Grenze dieses Landes.", + "Total": "Gesamt", + "Type to search...": "Geben Sie etwas ein, um danach zu suchen", + "Unengaged people groups": "Völlig unerreichte Volksgruppen", + "WAGF Block": "WAGF-Block", + "WAGF Region": "WAGF-Region", + "people groups adopted": "adoptierte Volksgruppen", + "people groups engaged": "engagierte Volksgruppen" +} diff --git a/library/i18n/locales/en/regions.json b/library/i18n/locales/en/regions.json new file mode 100644 index 000000000..bc97d7bd2 --- /dev/null +++ b/library/i18n/locales/en/regions.json @@ -0,0 +1,53 @@ +{ + "%count% people groups in %countries% countries": "%count% people groups in %countries% countries", + "%region% has %count% people groups across %countries% countries. Each pin is coloured by how many people are praying for that people group.": "%region% has %count% people groups across %countries% countries. Each pin is coloured by how many people are praying for that people group.", + "1+ People Praying": "1+ People Praying", + "100+ People Praying": "100+ People Praying", + "Adopted": "Adopted", + "Adoption Progress": "Adoption Progress", + "All Regions": "All Regions", + "Alternate Names": "Alternate Names", + "Clear All": "Clear All", + "Countries": "Countries", + "Countries in this region": "Countries in this region", + "Country": "Country", + "Engaged": "Engaged", + "Engagement Progress": "Engagement Progress", + "Every unengaged people group adopted by a church committed to prayer, giving, and sending": "Every unengaged people group adopted by a church committed to prayer, giving, and sending", + "Exact Search": "Exact Search", + "Find unreached people groups by region and country.": "Find unreached people groups by region and country.", + "Full Profile": "Full Profile", + "Goal": "Goal", + "Hide Filters": "Hide Filters", + "Intercessors": "Intercessors", + "Load More": "Load More", + "Loading results...": "Loading results...", + "Mobilize 100+ people praying daily for each DOXA people group": "Mobilize 100+ people praying daily for each DOXA people group", + "No One Praying": "No One Praying", + "No options found": "No options found", + "No unengaged people groups by 2033": "No unengaged people groups by 2033", + "Not Adopted": "Not Adopted", + "Other": "Other", + "Page Not Found": "Page Not Found", + "People Group": "People Group", + "People Groups": "People Groups", + "People committed to praying": "People committed to praying", + "Population": "Population", + "Prayer Coverage": "Prayer Coverage", + "Prayer coverage progress": "Prayer coverage progress", + "Regions": "Regions", + "Religion": "Religion", + "Search names, country/continent, religions...": "Search names, country/continent, religions...", + "See %region% dashboard": "See %region% dashboard", + "See All": "See All", + "Select": "Select", + "Show Filters": "Show Filters", + "There are %count% people groups in %country%. Check the map for the people groups on the border of this country as well.": "There are %count% people groups in %country%. Check the map for the people groups on the border of this country as well.", + "Total": "Total", + "Type to search...": "Type to search...", + "Unengaged people groups": "Unengaged people groups", + "WAGF Block": "WAGF Block", + "WAGF Region": "WAGF Region", + "people groups adopted": "people groups adopted", + "people groups engaged": "people groups engaged" +} diff --git a/library/i18n/locales/es/regions.json b/library/i18n/locales/es/regions.json new file mode 100644 index 000000000..1adc8e2e8 --- /dev/null +++ b/library/i18n/locales/es/regions.json @@ -0,0 +1,53 @@ +{ + "%count% people groups in %countries% countries": "%count% grupos étnicos en %countries% países", + "%region% has %count% people groups across %countries% countries. Each pin is coloured by how many people are praying for that people group.": "%region% tiene %count% grupos étnicos en %countries% países. El color de cada punto indica cuántas personas oran por ese grupo étnico.", + "1+ People Praying": "1+ personas orando", + "100+ People Praying": "100+ personas orando", + "Adopted": "Aprobado", + "Adoption Progress": "Progreso de la adopción", + "All Regions": "Todas las regiones", + "Alternate Names": "Nombres alternativos", + "Clear All": "Borrar todo", + "Countries": "Países", + "Countries in this region": "Países de esta región", + "Country": "País", + "Engaged": "Comprometido", + "Engagement Progress": "Progreso del compromiso", + "Every unengaged people group adopted by a church committed to prayer, giving, and sending": "Cada grupo étnico no evangelizado adoptado por una iglesia comprometida con la oración, la ofrenda y el envío.", + "Exact Search": "Búsqueda exacta", + "Find unreached people groups by region and country.": "Encuentra grupos étnicos no alcanzados por región y país.", + "Full Profile": "Perfil completo", + "Goal": "Meta", + "Hide Filters": "Ocultar filtros", + "Intercessors": "Intercesores", + "Load More": "Cargar más", + "Loading results...": "Cargando resultados...", + "Mobilize 100+ people praying daily for each DOXA people group": "Movilizar a más de 100 personas que oren diariamente por cada grupo étnico DOXA.", + "No One Praying": "Nadie orando", + "No options found": "No se han encontrado opciones", + "No unengaged people groups by 2033": "No habrá grupos étnicos sin evangelizar para 2033", + "Not Adopted": "No adoptado", + "Other": "Otros", + "Page Not Found": "Página no encontrada", + "People Group": "Grupo Étnico", + "People Groups": "Grupos Étnicos", + "People committed to praying": "Personas comprometidas con la oración", + "Population": "Población", + "Prayer Coverage": "Cobertura de oración", + "Prayer coverage progress": "Progreso de la cobertura de oración", + "Regions": "Regiones", + "Religion": "Religión", + "Search names, country/continent, religions...": "Buscar nombres, país/continente, religiones...", + "See %region% dashboard": "Ver el panel de %region%", + "See All": "Ver todo", + "Select": "Seleccionar", + "Show Filters": "Mostrar filtros", + "There are %count% people groups in %country%. Check the map for the people groups on the border of this country as well.": "Hay %count% grupos étnicos en %country%. Consulta también el mapa para ver los grupos étnicos en la frontera de este país.", + "Total": "Total", + "Type to search...": "Escribe para buscar...", + "Unengaged people groups": "Grupos étnicos no comprometidos", + "WAGF Block": "Bloque WAGF", + "WAGF Region": "Región de la WAGF", + "people groups adopted": "grupos de personas adoptados", + "people groups engaged": "grupos étnicos comprometidos" +} diff --git a/library/i18n/locales/fr/regions.json b/library/i18n/locales/fr/regions.json new file mode 100644 index 000000000..2ae96b41e --- /dev/null +++ b/library/i18n/locales/fr/regions.json @@ -0,0 +1,53 @@ +{ + "%count% people groups in %countries% countries": "%count% peuples dans %countries% pays", + "%region% has %count% people groups across %countries% countries. Each pin is coloured by how many people are praying for that people group.": "%region% compte %count% peuples répartis dans %countries% pays. La couleur de chaque point indique combien de personnes prient pour ce peuple.", + "1+ People Praying": "1+ personnes en prière", + "100+ People Praying": "100+ personnes en prière", + "Adopted": "Adopté", + "Adoption Progress": "Progrès de l'adoption", + "All Regions": "Toutes les régions", + "Alternate Names": "Autres noms", + "Clear All": "Tout effacer", + "Countries": "Pays", + "Countries in this region": "Pays de cette région", + "Country": "Pays", + "Engaged": "Engagé", + "Engagement Progress": "Progrès de l'engagement", + "Every unengaged people group adopted by a church committed to prayer, giving, and sending": "Chaque peuple non engagé adopté par une église locale engagée dans la prière, le don et l'envoi", + "Exact Search": "Recherche exacte", + "Find unreached people groups by region and country.": "Trouvez des peuples non atteints par région et par pays.", + "Full Profile": "Profil complet", + "Goal": "Objectif", + "Hide Filters": "Masquer les filtres", + "Intercessors": "Intercesseurs", + "Load More": "Afficher plus", + "Loading results...": "Chargement des résultats...", + "Mobilize 100+ people praying daily for each DOXA people group": "Mobiliser plus de 100 personnes priant chaque jour pour chaque peuple DOXA", + "No One Praying": "Personne ne prie", + "No options found": "Aucun lieu trouvé", + "No unengaged people groups by 2033": "Plus aucun peuple non engagé d'ici 2033", + "Not Adopted": "Non adopté", + "Other": "Autre", + "Page Not Found": "Page introuvable", + "People Group": "Peuple", + "People Groups": "Peuples", + "People committed to praying": "Personnes engagées dans la prière", + "Population": "Population", + "Prayer Coverage": "Couverture de prière", + "Prayer coverage progress": "Progression de la couverture de prière", + "Regions": "Régions", + "Religion": "Religion", + "Search names, country/continent, religions...": "Rechercher des noms, pays/continent, religions...", + "See %region% dashboard": "Voir le tableau de bord : %region%", + "See All": "Tout afficher", + "Select": "Sélectionner", + "Show Filters": "Afficher les filtres", + "There are %count% people groups in %country%. Check the map for the people groups on the border of this country as well.": "Il y a %count% peuples en %country%. Consultez la carte pour découvrir également les peuples situés à la frontière de ce pays.", + "Total": "Total", + "Type to search...": "Entrer votre recherche", + "Unengaged people groups": "Peuples non engagés", + "WAGF Block": "Bloc WAGF", + "WAGF Region": "Région WAGF", + "people groups adopted": "peuples adoptés", + "people groups engaged": "peuples engagés" +} diff --git a/library/i18n/locales/hi/regions.json b/library/i18n/locales/hi/regions.json new file mode 100644 index 000000000..8e8d48246 --- /dev/null +++ b/library/i18n/locales/hi/regions.json @@ -0,0 +1,53 @@ +{ + "%count% people groups in %countries% countries": "%countries% देशों में %count% लोगों के समूह", + "%region% has %count% people groups across %countries% countries. Each pin is coloured by how many people are praying for that people group.": "%region% में %countries% देशों में %count% लोगों के समूह हैं। प्रत्येक बिंदु का रंग दर्शाता है कि उस लोगों के समूह के लिए कितने लोग प्रार्थना कर रहे हैं।", + "1+ People Praying": "1+ लोग प्रार्थना कर रहे हैं", + "100+ People Praying": "100+ लोग प्रार्थना कर रहे हैं", + "Adopted": "दत्तक लिया गया", + "Adoption Progress": "दत्तक ग्रहण की प्रगति", + "All Regions": "सभी क्षेत्र", + "Alternate Names": "वैकल्पिक नाम", + "Clear All": "सभी साफ़ करें", + "Countries": "देश", + "Countries in this region": "इस क्षेत्र के देश", + "Country": "देश", + "Engaged": "प्रवेशित", + "Engagement Progress": "प्रवेश की प्रगति", + "Every unengaged people group adopted by a church committed to prayer, giving, and sending": "प्रत्येक असंलग्न जनसमूह जिसे प्रार्थना, दान और भेजने के लिए प्रतिबद्ध एक चर्च ने अपनाया है।", + "Exact Search": "सटीक खोज", + "Find unreached people groups by region and country.": "क्षेत्र और देश के अनुसार अगम्य लोगों के समूह खोजें।", + "Full Profile": "पूर्ण प्रोफ़ाइल", + "Goal": "लक्ष्य", + "Hide Filters": "फ़िल्टर छिपाएँ", + "Intercessors": "मध्यस्थ", + "Load More": "और लोड करें", + "Loading results...": "परिणाम लोड हो रहे हैं..।", + "Mobilize 100+ people praying daily for each DOXA people group": "प्रत्येक DOXA जनसमूह के लिए प्रतिदिन प्रार्थना करने हेतु 100+ लोगों को सक्रिय करें।", + "No One Praying": "कोई प्रार्थना नहीं कर रहा", + "No options found": "कोई विकल्प नहीं मिला", + "No unengaged people groups by 2033": "2033 तक कोई भी संलग्न न किया गया जनसमूह नहीं रहेगा।", + "Not Adopted": "दत्तक नहीं लिया गया", + "Other": "अन्य", + "Page Not Found": "पृष्ठ नहीं मिला", + "People Group": "लोगों का समूह", + "People Groups": "लोगों के समूह", + "People committed to praying": "प्रार्थना के लिए प्रतिबद्ध लोग", + "Population": "जनसँख्या", + "Prayer Coverage": "प्रार्थना कवरेज", + "Prayer coverage progress": "प्रार्थना कवरेज की प्रगति", + "Regions": "क्षेत्र", + "Religion": "धर्म", + "Search names, country/continent, religions...": "नाम, देश/महाद्वीप, धर्म खोजें..।", + "See %region% dashboard": "%region% डैशबोर्ड देखें", + "See All": "सभी देखें", + "Select": "चयन/छंटनी", + "Show Filters": "फ़िल्टर दिखाएँ", + "There are %count% people groups in %country%. Check the map for the people groups on the border of this country as well.": "%country% में %count% लोगों के समूह हैं। इस देश की सीमा पर स्थित लोगों के समूहों के लिए मानचित्र भी देखें।", + "Total": "संपूर्ण", + "Type to search...": "खोजने के लिए टाइप करें..।", + "Unengaged people groups": "अनलग्न लोगों के समूह", + "WAGF Block": "WAGF ब्लॉक", + "WAGF Region": "डब्ल्यूएजीएफ क्षेत्र", + "people groups adopted": "लोगों के समूहों ने अपनाया", + "people groups engaged": "प्रवेशित लोगों के समूह" +} diff --git a/library/i18n/locales/pt/regions.json b/library/i18n/locales/pt/regions.json new file mode 100644 index 000000000..a6de810a7 --- /dev/null +++ b/library/i18n/locales/pt/regions.json @@ -0,0 +1,53 @@ +{ + "%count% people groups in %countries% countries": "%count% grupos étnicos em %countries% países", + "%region% has %count% people groups across %countries% countries. Each pin is coloured by how many people are praying for that people group.": "%region% tem %count% grupos étnicos em %countries% países. A cor de cada ponto indica quantas pessoas oram por esse grupo étnico.", + "1+ People Praying": "1+ pessoas orando", + "100+ People Praying": "100+ pessoas orando", + "Adopted": "Aprovado", + "Adoption Progress": "Progresso da adoção", + "All Regions": "Todas as regiões", + "Alternate Names": "Nomes alternativos", + "Clear All": "Limpar tudo", + "Countries": "Países", + "Countries in this region": "Países desta região", + "Country": "País", + "Engaged": "Engajado", + "Engagement Progress": "Progresso do engajamento", + "Every unengaged people group adopted by a church committed to prayer, giving, and sending": "Cada grupo étnico não engajado adotado por uma igreja comprometida com a oração, contribuição e o envio", + "Exact Search": "Pesquisa exata", + "Find unreached people groups by region and country.": "Encontre grupos étnicos não alcançados por região e país.", + "Full Profile": "Perfil completo", + "Goal": "Meta", + "Hide Filters": "Ocultar filtros", + "Intercessors": "Intercessores", + "Load More": "Carregar mais", + "Loading results...": "A carregar resultados...", + "Mobilize 100+ people praying daily for each DOXA people group": "Mobilizar mais de 100 pessoas para orar diariamente por cada grupo étnico DOXA", + "No One Praying": "Ninguém orando", + "No options found": "Não foram encontradas opções", + "No unengaged people groups by 2033": "Nenhum grupo étnico não engajado até 2033", + "Not Adopted": "Não adotado", + "Other": "Outros", + "Page Not Found": "Página não encontrada", + "People Group": "Grupo étnico", + "People Groups": "Grupos étnicos", + "People committed to praying": "Pessoas comprometidas com a oração", + "Population": "Aplicação", + "Prayer Coverage": "Cobertura de oração", + "Prayer coverage progress": "Progresso da cobertura de oração", + "Regions": "Regiões", + "Religion": "Religião", + "Search names, country/continent, religions...": "Busque nomes, país/continente, religiões...", + "See %region% dashboard": "Ver o painel: %region%", + "See All": "Ver tudo", + "Select": "Selecionar", + "Show Filters": "Mostrar filtros", + "There are %count% people groups in %country%. Check the map for the people groups on the border of this country as well.": "Existem %count% grupos étnicos em %country%. Verifique no mapa também os grupos étnicos na fronteira deste país.", + "Total": "Total", + "Type to search...": "Digite para pesquisar...", + "Unengaged people groups": "Grupos étnicos não engajados", + "WAGF Block": "Bloco WAGF", + "WAGF Region": "Região da WAGF", + "people groups adopted": "grupos étnicos adotados", + "people groups engaged": "grupos étnicos engajados" +} diff --git a/library/i18n/locales/ru/regions.json b/library/i18n/locales/ru/regions.json new file mode 100644 index 000000000..6f384d97e --- /dev/null +++ b/library/i18n/locales/ru/regions.json @@ -0,0 +1,53 @@ +{ + "%count% people groups in %countries% countries": "%count% групп людей в %countries% странах", + "%region% has %count% people groups across %countries% countries. Each pin is coloured by how many people are praying for that people group.": "В регионе %region% — %count% групп людей в %countries% странах. Цвет каждой точки показывает, сколько человек молится за эту группу людей.", + "1+ People Praying": "1+ человек молится", + "100+ People Praying": "100+ человек молятся", + "Adopted": "Принято", + "Adoption Progress": "Прогресс принятия", + "All Regions": "Все регионы", + "Alternate Names": "Альтернативные названия", + "Clear All": "Очистить всё", + "Countries": "Страны", + "Countries in this region": "Страны этого региона", + "Country": "Страна", + "Engaged": "Вовлечённый", + "Engagement Progress": "Прогресс вовлечения", + "Every unengaged people group adopted by a church committed to prayer, giving, and sending": "Каждая незадействованная народность принята церковью, приверженной молитве, пожертвованиям и посылке миссионеров", + "Exact Search": "Точный поиск", + "Find unreached people groups by region and country.": "Найдите недостигнутые группы людей по регионам и странам.", + "Full Profile": "Полный профиль", + "Goal": "Цель", + "Hide Filters": "Скрыть фильтры", + "Intercessors": "Ходатаи", + "Load More": "Загрузить еще", + "Loading results...": "Загрузка результатов...", + "Mobilize 100+ people praying daily for each DOXA people group": "Мобилизуйте 100+ человек для ежедневной молитвы за каждую народность DOXA", + "No One Praying": "Никто не молится", + "No options found": "Вариантов не найдено", + "No unengaged people groups by 2033": "К 2033 году не останется незадействованных народов", + "Not Adopted": "Не принято", + "Other": "Другое", + "Page Not Found": "Страница не найдена", + "People Group": "Группа людей", + "People Groups": "Группы людей", + "People committed to praying": "Люди, посвятившие себя молитве", + "Population": "Население", + "Prayer Coverage": "Молитвенное покрытие", + "Prayer coverage progress": "Прогресс молитвенного покрытия", + "Regions": "Регионы", + "Religion": "Религия", + "Search names, country/continent, religions...": "Поиск по именам, странам/континентам, религиям...", + "See %region% dashboard": "Открыть панель: %region%", + "See All": "Смотреть все", + "Select": "Выбрать", + "Show Filters": "Показать фильтры", + "There are %count% people groups in %country%. Check the map for the people groups on the border of this country as well.": "Страна %country% насчитывает %count% групп людей. Проверьте также на карте группы людей, расположенные вдоль границ этой страны.", + "Total": "Итого", + "Type to search...": "Введите текст для поиска...", + "Unengaged people groups": "Невовлечённые группы людей", + "WAGF Block": "Блок WAGF", + "WAGF Region": "Регион WAGF", + "people groups adopted": "принятые группы людей", + "people groups engaged": "вовлечённые группы людей" +} diff --git a/plugin-designs/regions-dashboard/index.js b/plugin-designs/regions-dashboard/index.js index 33ecc08ce..15e81e0f7 100644 --- a/plugin-designs/regions-dashboard/index.js +++ b/plugin-designs/regions-dashboard/index.js @@ -41,7 +41,18 @@ function buildRegionsDashboardElement() { return defineCustomElement(ProfileLoader, { configureApp(app) { app.use(createPinia()) - app.use(createAppI18n()) + // Install i18n AND hand the instance to ProfileLoader by reference, the way + // doxa-simple-map/index.js:84-86 does. app.use() alone is not enough: createAppI18n() + // resolves its locale ONCE from , and every generated leaf page bakes + // lang="en", so the element was permanently English no matter what the host asked for. + // ProfileLoader drives appI18n.global.locale.value from profile-config.locale (its + // "established contract", ProfileLoader.vue:148-169) — but only if appI18n is PROVIDED. + // MEASURED before this line: with a Spanish catalogue present in the bundle and es set, + // every string still rendered English, and silently, because the t() shim falls back to + // its key rather than throwing. + const i18n = createAppI18n() + app.use(i18n) + app.provide('appI18n', i18n) app.provide('profileModules', profileModules) } }) diff --git a/plugin-designs/regions-dashboard/region-dashboards.vue b/plugin-designs/regions-dashboard/region-dashboards.vue index 49920f186..2714e105f 100644 --- a/plugin-designs/regions-dashboard/region-dashboards.vue +++ b/plugin-designs/regions-dashboard/region-dashboards.vue @@ -24,9 +24,17 @@ */ import { inject, ref, computed, onMounted, onBeforeUnmount, watch } from 'vue' import { useShadowStyles } from '@map/composables/useShadowStyles.js' +// ar renders right-to-left. RTL_LOCALES is the shared set and :dir on our own root is the +// house pattern (doxa-simple-map.vue:18, :246, :1346) — an EMBEDDED element must not reach for +// document.documentElement.dir, which belongs to the host page. +import { RTL_LOCALES } from '@map/i18n/index.js' import { useDocumentFont, BEBAS_NEUE_FACES, POPPINS_FACES } from '@map/composables/useDocumentFont.js' import FilterDropdown from '@map/components/search/FilterDropdown.vue' import UupgsList from './src/UupgsList.vue' +// Their strings, via their own English keys (see src/useRegionsI18n.js). The goal sentences, +// the stat labels and the table headers are all t() calls on their page; hardcoding the +// English was the last thing keeping this clone monolingual. +import { useRegionsI18n } from './src/useRegionsI18n.js' // Region colours come from the shared strategy (check:one-palette), and REGION_ORDER is the // order its CVD separation was validated in — the legend must render in it for that to hold. import { PALETTE as REGION_PALETTE, WAGF_REGIONS, REGION_ORDER } from '@map/colors/wagf-region.js' @@ -56,7 +64,13 @@ const cfg = computed(() => { try { return JSON.parse(props.profileConfig) || {} } catch { return {} } }) const prayBaseUrl = computed(() => props.prayBaseUrl || cfg.value.prayBaseUrl || 'https://pray.doxa.life') -const languageCode = computed(() => props.languageCode || cfg.value.languageCode || '') +// The prayer API localises its LABELS from ?lang= — country names, region names, religion +// names. MEASURED: with locale=ar the UI translated but every country in the table stayed +// English, because this read only cfg.languageCode while the locale arrives as +// cfg.locale (ProfileLoader's contract, ProfileLoader.vue:156 accepts locale OR lang). +// Falling through to the same keys means translating the chrome also translates the data. +const languageCode = computed(() => + props.languageCode || cfg.value.languageCode || cfg.value.locale || cfg.value.lang || '') const instanceId = computed(() => cfg.value.instanceId || '') // THE CAP-4 ASSET-PATH LESSON (BUG-UPG100MFE-ASSET-PATH, and it bit again here): DataTable // injects the vendored Tabulator from a path RELATIVE to the document. Nested inside the @@ -80,6 +94,9 @@ useDocumentFont('Bebas Neue', BEBAS_NEUE_FACES, assetsBase.value) useDocumentFont('Poppins', POPPINS_FACES, assetsBase.value) // ── state ─────────────────────────────────────────────────────────────────── +const { t, tf , locale } = useRegionsI18n() +const isRTL = computed(() => RTL_LOCALES.has(locale.value)) + const regions = ref([]) // The rollup aggregates records away, and the map needs them one by one. Kept flat and // pre-parsed once here rather than re-fetched inside the map child, as DX-life's CountryMap @@ -262,11 +279,11 @@ function percentOfSubject(count) { const stats = computed(() => { const s = subject.value.stats || emptyStats() const unengaged = Math.max(0, (s.count || 0) - (s.engaged || 0)) - const four = [{ label: 'People Groups', value: formatNumber(s.count) }] - if (subject.value.kind === 'country') four.push({ label: 'Engaged', value: formatNumber(s.engaged) }) - else four.push({ label: 'Countries', value: formatNumber(subject.value.kind === 'all' ? totalCountryCount.value : (selectedRegion.value?.countryCount || 0)) }) - four.push({ label: 'Population', value: formatNumber(s.population) }) - four.push({ label: 'Unengaged people groups', value: formatNumber(unengaged) }) + const four = [{ label: t('People Groups'), value: formatNumber(s.count) }] + if (subject.value.kind === 'country') four.push({ label: t('Engaged'), value: formatNumber(s.engaged) }) + else four.push({ label: t('Countries'), value: formatNumber(subject.value.kind === 'all' ? totalCountryCount.value : (selectedRegion.value?.countryCount || 0)) }) + four.push({ label: t('Population'), value: formatNumber(s.population) }) + four.push({ label: t('Unengaged people groups'), value: formatNumber(unengaged) }) return four }) @@ -297,12 +314,11 @@ const tableRows = computed(() => { }) const tableTitle = computed(() => { - if (subject.value.kind === 'all') return 'All regions' - if (subject.value.kind === 'country') return 'Countries in ' + (selectedRegion.value?.label || 'this region') - return 'Countries in this region' + if (subject.value.kind === 'all') return t('Regions') + return t('Countries in this region') }) -const tableFirstCol = computed(() => (subject.value.kind === 'all' ? 'Region' : 'Country')) +const tableFirstCol = computed(() => (subject.value.kind === 'all' ? t('Region') : t('Country'))) // Their summary line, RegionDetail.vue:32-36 / the list's own. Kept as a %token% template for // the same reason tab 1 keeps it -- it is how their i18n carries this string. @@ -312,9 +328,9 @@ const summaryLine = computed(() => { return formatNumber(s.count) + ' people groups \u00b7 ' + (selectedCountry.value?.region?.label || 'Other') } const countries = subject.value.kind === 'all' ? totalCountryCount.value : (selectedRegion.value?.countryCount || 0) - return '%count% people groups in %countries% countries' - .replace('%count%', formatNumber(s.count)) - .replace('%countries%', formatNumber(countries)) + return tf('%count% people groups in %countries% countries', { + count: formatNumber(s.count), countries: formatNumber(countries), + }) }) // ★ THE NO-SELECTION QUESTION, answered from what DX-life actually does. @@ -440,16 +456,15 @@ const mapZoom = computed(() => { // RegionDetail.vue:38-42 and CountryDetail.vue:29-33. const mapNote = computed(() => { if (selectedCountry.value) { - return 'There are %count% people groups in %country%. Check the map for the people groups on the border of this country as well.' - .replace('%count%', formatNumber(selectedCountry.value.count)) - .replace('%country%', selectedCountry.value.name) + return tf('There are %count% people groups in %country%. Check the map for the people groups on the border of this country as well.', { + count: formatNumber(selectedCountry.value.count), country: selectedCountry.value.name, + }) } const label = subject.value.title const countries = subject.value.kind === 'all' ? totalCountryCount.value : (selectedRegion.value?.countryCount || 0) - return '%region% has %count% people groups across %countries% countries. Each pin is coloured by how many people are praying for that people group.' - .replace('%region%', label) - .replace('%count%', formatNumber(subject.value.stats.count)) - .replace('%countries%', formatNumber(countries)) + return tf('%region% has %count% people groups across %countries% countries. Each pin is coloured by how many people are praying for that people group.', { + region: label, count: formatNumber(subject.value.stats.count), countries: formatNumber(countries), + }) }) // The country page's list is DX-life's own UupgsList, ported at src/UupgsList.vue — not a table @@ -586,6 +601,11 @@ async function loadRegions() { } } +// A locale change has to REFETCH, not just re-render: the labels come from the API's ?lang=, +// so without this the chrome switches language and the country names keep the language of +// first paint. +watch(languageCode, () => { loadRegions() }) + onMounted(async () => { window.addEventListener(SELECT_EVENT, onSelect) if (URL_SYNC) window.addEventListener('popstate', onPopState) @@ -785,7 +805,7 @@ useShadowStyles(