import type { Metadata } from 'next'; import Link from 'next/link'; import { Suspense } from 'react'; import { t } from '@/i18n'; import { api, safe } from '@/lib/api'; import { apiExplore } from '@/lib/api-explore'; import { formatDate } from '@/lib/format'; import { SITE_URL, routes } from '@/lib/site'; import { toCountryLite } from '@/lib/types-compare'; import type { IndicatorOption } from '@/components/controls/indicator-select'; import { Section } from '@/components/data/section'; import { CodeBlock } from '@/components/explore/copy-button'; import { DownloadPicker } from '@/components/explore/download-picker'; import { PageHeader } from '@/components/explore/page-header'; import { FooterCredits } from '@/components/layout/site-footer'; import { DownloadBuilder } from '@/components/platform/download-builder'; export const revalidate = 3600; export const metadata: Metadata = { title: t('download.title'), description: t('download.description'), alternates: { canonical: routes.download() }, }; const COLUMNS = ['country_id', 'country_name', 'indicator_id', 'indicator_name', 'period', 'year', 'frequency', 'value', 'unit', 'is_estimate', 'is_forecast', 'status', 'source', 'source_name', 'dataset', 'series_code', 'retrieved_at', 'source_updated_at', 'url', 'licence']; export default async function DownloadPage() { const [sources, countriesRes, indicatorsRes] = await Promise.all([safe(apiExplore.sources()), safe(api.countries()), safe(apiExplore.indicators({ with_data: true }))]); const items = sources?.items ?? []; const names = items.map((s) => s.name ?? s.id); const built = sources?.meta.built_at ?? null; const countries = (countriesRes?.items ?? []).filter((c) => c.kind !== 'aggregate').map(toCountryLite).sort((a, b) => a.name.localeCompare(b.name)); // Plain data for the client builder (the helper in indicator-select.tsx is a client module; map here on the server). const indicators: IndicatorOption[] = (indicatorsRes?.items ?? []).map((i) => ({ slug: i.slug, name: i.name ?? i.slug, short_name: i.short_name, topic: i.topic, unit: i.unit, featured: i.featured, first_year: i.first_year, last_year: i.last_year, n_countries: i.n_countries })); const maxYear = Math.max(new Date().getUTCFullYear(), ...indicators.map((i) => i.last_year ?? 0)); const bulk = `# list indicators, then fetch each dataset\ncurl -s "${SITE_URL}/api/v1/indicators" | jq -r '.items[].slug' | while read slug; do\n curl -s -o "$slug.csv" "${SITE_URL}/api/v1/indicators/$slug/download.csv"; sleep 0.6\ndone`; return ( <>

{t('download.quick.country')}

{t('download.quick.countrySub')}

{t('download.quick.indicator')}

{t('download.quick.indicatorSub')}

{t('download.bulk.text')}

    {COLUMNS.map((c) => (
  • {c}
  • ))}

{t('download.api.title')}

{t('download.api.text', { base: `${SITE_URL}/api/v1` })}

{t('download.api.link')} →

{t('download.licence.compilation')}

{t('download.licence.sources')}

{items.length ? ( {items.map((s) => ( ))}
{t('download.licence.source')} {t('download.licence.licence')} {t('download.licence.attribution')}
{s.name ?? s.id} {s.licence ?? t('common.na')} {s.attribution ?? ''}
) : null}

{t('download.licence.example')}

{t('download.licence.exampleText', { sources: names.slice(0, 4).join(', ') || 'World Bank, IMF, OECD', date: formatDate(built ?? new Date().toISOString()) })}
); }