Cities with Internet: its load and engine errors speak the reader's language
The engine-missing message read the shared messages.engineMissing through this file's connectivity-prefixed t(), so it always missed and showed English in every locale. Shared keys are now read qualified with tStatic: engineMissing, engineNotLoaded, and couldNotLoadNamed for a data table that fails to load (naming the tab in the reader's language, not 'table not found (404)'). Four unused English tab labels are removed.
This commit is contained in:
parent
c9905dd9db
commit
5dc161daa9
2 changed files with 21 additions and 13 deletions
|
|
@ -33,7 +33,8 @@
|
|||
* carrier flag is a NAME-PATTERN HEURISTIC, not a verified classification.
|
||||
*/
|
||||
import { computed, inject, ref, shallowRef, markRaw, onMounted, onBeforeUnmount } from 'vue'
|
||||
import { useOptionalT } from '@map/composables/useOptionalT.js'
|
||||
import { useOptionalT, fillParams } from '@map/composables/useOptionalT.js'
|
||||
import { tStatic } from '@map/i18n/index.js'
|
||||
import { useShadowStyles } from '@map/composables/useShadowStyles.js'
|
||||
import { addMapAttribution } from '@map/composables/useMapAttribution'
|
||||
|
||||
|
|
@ -374,12 +375,13 @@ onMounted(async () => {
|
|||
if (!gl) {
|
||||
const engine = ciProvider === 'maplibre' ? 'MapLibre' : 'Mapbox'
|
||||
console.warn(`[connectivity-map] the ${engine} engine did not load; refusing to substitute another engine.`)
|
||||
// messages.engineMissing is the shared key (studio's landing 3); English only if a host has no catalogue.
|
||||
const msg = t('messages.engineMissing', { engine })
|
||||
err.value = msg && msg !== 'messages.engineMissing' ? msg : `The ${engine} map engine did not load.`
|
||||
// messages.engineMissing is the SHARED key, so read it qualified with tStatic: this file's t() prefixes
|
||||
// every key with connectivity., which made it connectivity.messages.engineMissing, a miss, so the
|
||||
// message was English in every locale. tStatic follows the page locale and falls back to English itself.
|
||||
err.value = fillParams(tStatic('messages.engineMissing'), { engine })
|
||||
return
|
||||
}
|
||||
if (!mapEl.value) { err.value = 'map engine not loaded'; return }
|
||||
if (!mapEl.value) { err.value = tStatic('messages.engineNotLoaded'); return }
|
||||
// RTL SHAPING, before the first map exists. This raw map does not go through useMapInstance
|
||||
// (which installs it), and the basemap draws each place in its OWN script: over the Middle East
|
||||
// most labels are Arabic, Persian or Hebrew for EVERY viewer. An entry-time call cannot do this,
|
||||
|
|
|
|||
|
|
@ -25,7 +25,8 @@ import { computed, inject, ref, watch } from 'vue'
|
|||
import DataTable from '@map/components/tables/DataTable.vue'
|
||||
import { useShadowStyles } from '@map/composables/useShadowStyles.js'
|
||||
import { resolveAssetsBase } from '@map/utils/embedBase.js'
|
||||
import { useOptionalT } from '@map/composables/useOptionalT.js'
|
||||
import { useOptionalT, fillParams } from '@map/composables/useOptionalT.js'
|
||||
import { tStatic } from '@map/i18n/index.js'
|
||||
|
||||
|
||||
const profileConfig = inject('profileConfig', ref(null))
|
||||
|
|
@ -49,13 +50,13 @@ const t = useOptionalT('connectivity')
|
|||
const num = (n) => (Number(n) || 0).toLocaleString()
|
||||
|
||||
const TABS = [
|
||||
{ id: 'cities', label: 'Key Cities', file: 'key-cities' },
|
||||
{ id: 'internet', label: 'Connectivity', file: 'country-connectivity' },
|
||||
{ id: 'operators', label: 'ISPs & Carriers', file: 'network-operators' },
|
||||
{ id: 'social', label: 'Social Platforms', file: 'social-platforms' },
|
||||
{ id: 'cities', file: 'key-cities' },
|
||||
{ id: 'internet', file: 'country-connectivity' },
|
||||
{ id: 'operators', file: 'network-operators' },
|
||||
{ id: 'social', file: 'social-platforms' },
|
||||
// Messaging apps are the channel referral stats CANNOT see — WhatsApp tops 54
|
||||
// countries, Telegram 38, and neither appears in StatCounter at all.
|
||||
{ id: 'messaging', label: 'Messaging Apps', file: 'messaging-channels' },
|
||||
{ id: 'messaging', file: 'messaging-channels' },
|
||||
]
|
||||
const active = ref('cities')
|
||||
const current = computed(() => TABS.find((t) => t.id === active.value) || TABS[0])
|
||||
|
|
@ -73,9 +74,14 @@ async function ensure(file) {
|
|||
loading.value = true; loadErr.value = null
|
||||
try {
|
||||
const r = await fetch(`${assetsBase.value}/tables/${file}.json`)
|
||||
if (!r.ok) throw new Error(`table not found (${r.status})`)
|
||||
if (!r.ok) throw new Error(String(r.status))
|
||||
cache.value = { ...cache.value, [file]: await r.json() }
|
||||
} catch (e) { loadErr.value = String(e.message || e) }
|
||||
} catch (_) {
|
||||
// The reader sees the shared, translated "Could not load {name}." (qualified via tStatic: this file's
|
||||
// t() would prefix connectivity.), naming the tab in their language; the status went to the console.
|
||||
const tab = TABS.find((x) => x.file === file)
|
||||
loadErr.value = fillParams(tStatic('messages.couldNotLoadNamed'), { name: tab ? t('tables.tabs.' + tab.id) : file })
|
||||
}
|
||||
finally { loading.value = false }
|
||||
}
|
||||
watch(current, (t) => t && ensure(t.file), { immediate: true })
|
||||
|
|
|
|||
Loading…
Reference in a new issue