Key Cities: all nine region headings read in the page's language, and the region stays the key
This corrects my own "Other" fix (9d12e59b6), which could never fire. gospel's cities-internet analysis (87a168195) showed the same shape here: key-cities.json has no row with an empty region (1,646 rows), "Other" (2) and "N/A" (19) are region VALUES, and every section heading printed its raw English data string in every locale. The fallback I translated also put a label into the grouping key. Now, as in cities-internet: the raw region string stays the grouping key (sections, :key, collapse state), with 'Other' as the data guard; the heading is projected at render by regionLabel.js from the keys the data's strings already are the English values of (dashboard.wagfRegion.*, dashboard.other, wall.na), written out in full so the build ships those areas. The poster wall, whose PosterWall prints its section name as given, groups by that projected heading, as country-posters' wall does. keyCities.posters.otherRegion is no longer used. Headless (_qa-cycle/exp-shepherd/check-keycities-regions.mjs): every one of the nine region values maps to its catalogue heading in ar, zh, es and ru, and an unknown value passes through as data. key-cities is gated, so nothing in public/ changes.
This commit is contained in:
parent
f0192342eb
commit
a4622781a2
3 changed files with 54 additions and 3 deletions
|
|
@ -29,6 +29,7 @@
|
|||
import { computed, inject, ref, onMounted, h } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { sentenceParts, keep, ltr } from '@map/composables/useSentence.js'
|
||||
import { regionLabel } from './regionLabel.js'
|
||||
import { useShadowStyles } from '@map/composables/useShadowStyles.js'
|
||||
import { resolveAssetsBase } from '@map/utils/embedBase.js'
|
||||
|
||||
|
|
@ -70,7 +71,10 @@ const shown = computed(() => {
|
|||
const sections = computed(() => {
|
||||
const by = new Map()
|
||||
for (const r of shown.value) {
|
||||
const k = r.region || t('keyCities.posters.otherRegion') // a row with no region: a translated heading, not 'Other'
|
||||
// The RAW data value is the key (sections, :key, collapse state); only the heading is translated,
|
||||
// at render (secLabel below). 'Other' is a data guard for a row with no region: the sentinel
|
||||
// dashboard.other projects. No row has an empty region today; "Other" and "N/A" are region values.
|
||||
const k = r.region || 'Other'
|
||||
if (!by.has(k)) by.set(k, [])
|
||||
by.get(k).push(r)
|
||||
}
|
||||
|
|
@ -87,6 +91,7 @@ const collapsed = ref({})
|
|||
const isShut = (n) => !!collapsed.value[n]
|
||||
const toggle = (n) => { collapsed.value = { ...collapsed.value, [n]: !collapsed.value[n] } }
|
||||
const fmt = (n) => (Number(n) || 0).toLocaleString()
|
||||
const secLabel = (name) => regionLabel(t, name)
|
||||
// ONE key for the caveat's sentence: the count and the gazetteer's name go in as values, the name as
|
||||
// its own left-to-right island (it is a proper name, never translated), so each language orders it.
|
||||
const caveatRow = computed(() => h('span', sentenceParts(
|
||||
|
|
@ -156,7 +161,7 @@ const band = (a) => a === 'yes' ? 'ok' : a === 'partial' ? 'mid' : a === 'no' ?
|
|||
<section v-for="sec in sections" :key="sec.name" class="sec">
|
||||
<button type="button" class="sec-head" @click="toggle(sec.name)">
|
||||
<span class="sec-caret" :class="{ open: !isShut(sec.name) }">▶</span>
|
||||
<h3 class="sec-name">{{ sec.name }}</h3>
|
||||
<h3 class="sec-name">{{ secLabel(sec.name) }}</h3>
|
||||
<span class="sec-meta">
|
||||
{{ $t('keyCities.list.locations', { n: sec.items.length }) }} · {{ $t('keyCities.list.peopleGroups', { n: fmt(sec.groups) }) }}
|
||||
</span>
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@
|
|||
*/
|
||||
import { computed, inject, ref, onMounted } from 'vue'
|
||||
import { useI18n } from 'vue-i18n'
|
||||
import { regionLabel } from './regionLabel.js'
|
||||
import PosterWall from '@map/components/poster/PosterWall.vue'
|
||||
import { resolveAssetsBase } from '@map/utils/embedBase.js'
|
||||
|
||||
|
|
@ -48,7 +49,9 @@ const items = computed(() => rows.value
|
|||
})))
|
||||
|
||||
const { t } = useI18n()
|
||||
const groupBy = (c) => c.region || t('keyCities.posters.otherRegion')
|
||||
// PosterWall prints its section name as given, so the wall groups by the region's heading in the page's
|
||||
// language (as country-posters' wall does). 'Other' is the data guard dashboard.other projects.
|
||||
const groupBy = (c) => regionLabel(t, c.region || 'Other')
|
||||
const collapsedBy = (sec) => sec.total < 20
|
||||
</script>
|
||||
|
||||
|
|
|
|||
43
plugin-designs/key-cities/regionLabel.js
Normal file
43
plugin-designs/key-cities/regionLabel.js
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
/**
|
||||
* regionLabel.js — Key Cities' region headings, translated at RENDER.
|
||||
*
|
||||
* The same fix as cities-internet's list (87a168195), for the same reason. key-cities.json has no row
|
||||
* with an empty region (1,646 rows): "Other" and "N/A" are region VALUES, and every heading printed its
|
||||
* raw English data string, in every locale. The data's nine region strings are the catalogue's own
|
||||
* English values (dashboard.wagfRegion.*, dashboard.other, wall.na), so the English catalogue is the
|
||||
* join, and no English has to be written here.
|
||||
*
|
||||
* THE RAW VALUE STAYS THE KEY. A caller groups rows, keys its sections and keeps its collapse state by
|
||||
* the data's own string, and only the heading it prints goes through regionLabel(). Translating where
|
||||
* the rows are grouped would reset every open section on a language switch.
|
||||
*
|
||||
* THE KEYS ARE WRITTEN OUT IN FULL. The build ships a translation area only when its name appears in a
|
||||
* reached file as a literal prefix (internal/i18n-areas.mjs); keys assembled at runtime would resolve
|
||||
* in the dev tree and not in the shipped bundle.
|
||||
*/
|
||||
import { tStatic } from '@map/i18n/index.js'
|
||||
|
||||
const REGION_KEYS = [
|
||||
'dashboard.wagfRegion.asia',
|
||||
'dashboard.wagfRegion.middle_east',
|
||||
'dashboard.wagfRegion.latin_america_&_caribbean',
|
||||
'dashboard.wagfRegion.africa',
|
||||
'dashboard.wagfRegion.europe',
|
||||
'dashboard.wagfRegion.north_america_&_non-spanish_caribbean',
|
||||
'dashboard.wagfRegion.oceania',
|
||||
'dashboard.other',
|
||||
'wall.na',
|
||||
]
|
||||
// English value -> key. tStatic(key, 'en') with the EXPLICIT locale: the join must not follow the page.
|
||||
const REGION_KEY = Object.fromEntries(REGION_KEYS.map((k) => [tStatic(k, 'en'), k]).filter(([en]) => en))
|
||||
|
||||
/**
|
||||
* A region's heading in the page's language, through the caller's own translator `t` (so it follows a
|
||||
* language switch). A region the catalogue does not know is data, and is shown as it is.
|
||||
*/
|
||||
export function regionLabel(t, name) {
|
||||
const key = REGION_KEY[name]
|
||||
if (!key) return name
|
||||
const v = t(key)
|
||||
return v && v !== key ? v : name
|
||||
}
|
||||
Loading…
Reference in a new issue