Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions messages/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -471,5 +471,37 @@
"nearby_stations": "Nearby Stations"
},
"unableToDetectVersions": "Unable to detect versions within this feed."
},
"home": {
"title": "Explore and Access Global Transit Data",
"servingOver": "Currently serving over",
"feeds": "transportation data feeds from over",
"fromOver": "from over",
"countries": "countries.",
"or": "or",
"browseFeeds": "Browse Feeds",
"addFeed": "Add a feed",
"signUpApi": "Sign up for the API",
"description": "The Mobility Database is an open data catalog including over 4000 GTFS, GTFS Realtime, and GBFS feeds in over 75 countries. Whether you're a transportation operator, a researcher studying public transit and shared mobility trends, or a maps app needing reliable data to use with your application, the Mobility Database has everything you need in one central location.",
"validatorIntro": "Our database integrates with",
"gtfsValidator": "the Canonical GTFS Schedule Validator",
"and": "and",
"gbfsValidator": "the GBFS Validator",
"validatorOutro": "to provide detailed data quality reports on every feed."
},
"about": {
"title": "About",
"description": "The Mobility Database is an open catalog including over 4000 GTFS, GTFS Realtime, and GBFS feeds in over 75 countries. It integrates with the Canonical GTFS Schedule and GBFS Validators to share data quality reports for each feed.\n\nThis database is hosted and maintained by MobilityData, the global non-profit organization dedicated to the advancement of open transportation data standards.",
"learnMore": "Learn more about MobilityData",
"whyUse": "Why Use the Mobility Database?",
"whyUseAnswer": "The Mobility Database provides free access to historical and current GTFS, GTFS Realtime, and GBFS feeds from around the world. These feeds are checked for updates every day, ensuring that the data you're looking at is the most recent data available.",
"gtfsValidator": "the Canonical GTFS Schedule Validator",
"gbfsValidator": "the GBFS Validator.",
"benefits": {
"mirrored": "Mirrored versions of operator-hosted GTFS Schedule feeds to avoid operator website downtimes and geoblocking",
"boundingBoxes": "Bounding boxes that help to visualize or filter in the API by a select region",
"addFeeds": "A simple, easy-to-use form to add new feeds",
"openSource": "An open source community actively working to improve the tools"
}
}
}
32 changes: 32 additions & 0 deletions messages/fr.json
Original file line number Diff line number Diff line change
Expand Up @@ -471,5 +471,37 @@
"nearby_stations": "Nearby Stations"
},
"unableToDetectVersions": "Unable to detect versions within this feed."
},
"home": {
"title": "Explorez et accédez aux données de transport mondiales",
"servingOver": "Actuellement plus de",
"feeds": "flux de données de transport de plus de",
"fromOver": "de plus de",
"countries": "pays.",
"or": "ou",
"browseFeeds": "Parcourir les flux",
"addFeed": "Ajouter un flux",
"signUpApi": "S'inscrire à l'API",
"description": "La Mobility Database est un catalogue de données ouvertes comprenant plus de 4000 flux GTFS, GTFS Realtime et GBFS dans plus de 75 pays. Que vous soyez un opérateur de transport, un chercheur étudiant les tendances du transport public et de la mobilité partagée, ou une application de cartes ayant besoin de données fiables, la Mobility Database a tout ce dont vous avez besoin en un seul endroit.",
"validatorIntro": "Notre base de données s'intègre avec",
"gtfsValidator": "le validateur canonique GTFS Schedule",
"and": "et",
"gbfsValidator": "le validateur GBFS",
"validatorOutro": "pour fournir des rapports détaillés sur la qualité des données de chaque flux."
},
"about": {
"title": "À propos",
"description": "La Mobility Database est un catalogue ouvert comprenant plus de 4000 flux GTFS, GTFS Realtime et GBFS dans plus de 75 pays. Elle s'intègre avec les validateurs canoniques GTFS Schedule et GBFS pour partager des rapports de qualité des données pour chaque flux.\n\nCette base de données est hébergée et maintenue par MobilityData, l'organisation mondiale à but non lucratif dédiée à l'avancement des standards de données de transport ouvertes.",
"learnMore": "En savoir plus sur MobilityData",
"whyUse": "Pourquoi utiliser la Mobility Database ?",
"whyUseAnswer": "La Mobility Database fournit un accès gratuit aux flux GTFS, GTFS Realtime et GBFS historiques et actuels du monde entier. Ces flux sont vérifiés quotidiennement pour les mises à jour, garantissant que les données que vous consultez sont les plus récentes disponibles.",
"gtfsValidator": "le validateur canonique GTFS Schedule",
"gbfsValidator": "le validateur GBFS.",
"benefits": {
"mirrored": "Versions miroirs des flux GTFS Schedule hébergés par les opérateurs pour éviter les temps d'arrêt et le blocage géographique",
"boundingBoxes": "Boîtes englobantes pour visualiser ou filtrer par région sélectionnée dans l'API",
"addFeeds": "Un formulaire simple et facile à utiliser pour ajouter de nouveaux flux",
"openSource": "Une communauté open source travaillant activement à améliorer les outils"
}
}
}
5 changes: 4 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@
"react-draggable": "^4.5.0",
"react-ga4": "^2.1.0",
"react-google-recaptcha": "^3.1.0",
"react-helmet-async": "^2.0.5",
"react-hook-form": "^7.52.1",
"react-leaflet": "^4.2.1",
"react-map-gl": "^8.0.4",
Expand All @@ -56,6 +55,7 @@
},
"scripts": {
"build:prod": "next build",
"build:analyze": "next experimental-analyze",
"start:dev": "next dev",
"start:dev:mock": "NEXT_PUBLIC_API_MOCKING=enabled next dev -p 3001",
"start:prod": "next build && next start",
Expand All @@ -73,6 +73,9 @@
"generate:gbfs-validator-types:output": "npm exec -- openapi-typescript ./external_types/GbfsValidator.yaml -o $npm_config_output_path && eslint $npm_config_output_path --fix",
"generate:gbfs-validator-types": "npm run generate:gbfs-validator-types:output -- --output-file=src/app/services/feeds/gbfs-validator-types.ts"
},
"resolutions": {
"tar": "^7.5.7"
},
"eslintConfig": {
"extends": [
"react-app",
Expand Down
37 changes: 17 additions & 20 deletions src/app/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,19 @@ import { Suspense, useEffect, useState } from 'react';
import { AdapterDayjs } from '@mui/x-date-pickers/AdapterDayjs';
import { LocalizationProvider } from '@mui/x-date-pickers/LocalizationProvider';
import AppContainer from './AppContainer';
import { Helmet, HelmetProvider } from 'react-helmet-async';

function App(): React.ReactElement {
interface AppProps {
locale?: string;
}

function App({ locale }: AppProps): React.ReactElement {
const dispatch = useDispatch();
const [isAppReady, setIsAppReady] = useState(false);

// Determine basename for BrowserRouter based on locale
// Non-default locales (e.g., 'fr') need their prefix as basename
const basename = locale != null && locale !== 'en' ? `/${locale}` : undefined;

useEffect(() => {
app.auth().onAuthStateChanged((user) => {
if (user != null) {
Expand All @@ -29,24 +36,14 @@ function App(): React.ReactElement {
}, [dispatch]);

return (
<HelmetProvider>
<Helmet>
<meta
name='description'
content={
"Access GTFS, GTFS Realtime, GBFS transit data with over 4,000 feeds from 70+ countries on the web's leading transit data platform."
}
/>
</Helmet>
<Suspense>
<LocalizationProvider dateAdapter={AdapterDayjs}>
{/* BrowserRouter will be deprecated in favor of Next AppRouter */}
<BrowserRouter>
<AppContainer>{isAppReady ? <AppRouter /> : null}</AppContainer>
</BrowserRouter>
</LocalizationProvider>
</Suspense>
</HelmetProvider>
<Suspense>
<LocalizationProvider dateAdapter={AdapterDayjs}>
{/* BrowserRouter will be deprecated in favor of Next AppRouter */}
<BrowserRouter basename={basename}>
<AppContainer>{isAppReady ? <AppRouter /> : null}</AppContainer>
</BrowserRouter>
</LocalizationProvider>
</Suspense>
);
}

Expand Down
5 changes: 0 additions & 5 deletions src/app/AppContainer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,24 +4,19 @@ import * as React from 'react';
import { Box, LinearProgress } from '@mui/material';
import type ContextProviderProps from './interface/ContextProviderProps';
import { useLocation } from 'react-router-dom';
import { Helmet } from 'react-helmet-async';
import { selectLoadingApp } from './store/selectors';
import { useSelector } from 'react-redux';

const AppContainer: React.FC<ContextProviderProps> = ({ children }) => {
const isAppLoading = useSelector(selectLoadingApp);
const location = useLocation();
const canonicalUrl = window.location.origin + location.pathname;

React.useLayoutEffect(() => {
window.scrollTo({ top: 0, left: 0, behavior: 'instant' });
}, [location.pathname]);

return (
<>
<Helmet>
<link rel='canonical' href={canonicalUrl} />
</Helmet>
<Box id='app-main-container'>
{isAppLoading ? (
<Box sx={{ width: '100%', mt: '-31px' }}>
Expand Down
12 changes: 0 additions & 12 deletions src/app/[[...slug]]/page.tsx

This file was deleted.

22 changes: 22 additions & 0 deletions src/app/[locale]/[...slug]/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
'use client';

// This page is temporary to ease the migration to Next.js App Router
// It will be deprecated once the migration is fully complete
import { type ReactNode, use } from 'react';
import dynamic from 'next/dynamic';

const App = dynamic(async () => await import('../../App'), { ssr: false });

interface PageProps {
params: Promise<{
locale: string;
slug: string[];
}>;
}

export default function Page({ params }: PageProps): ReactNode {
const { locale } = use(params);

// Pass locale to App so BrowserRouter can use correct basename
return <App locale={locale} />;
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
import { Container, Typography, Button } from '@mui/material';
import OpenInNewIcon from '@mui/icons-material/OpenInNew';
import { type ReactElement } from 'react';
import { getTranslations } from 'next-intl/server';

export default async function AboutPage(): Promise<ReactElement> {
const t = await getTranslations('about');

export default function Page(): ReactElement {
return (
<Container component='main'>
<Typography variant='h1'>About</Typography>
{/* ColoredContainer: This component uses style which is a client use only. Investigate pattern for SSR optimal Theme rendering */}
<Typography variant='h1'>{t('title')}</Typography>
<Container
sx={{
backgroundColor: 'background.paper',
Expand All @@ -18,14 +20,7 @@ export default function Page(): ReactElement {
maxWidth={false}
>
<Typography sx={{ fontWeight: 700 }}>
The Mobility Database is an open catalog including over 4000 GTFS,
GTFS Realtime, and GBFS feeds in over 75 countries. It integrates with
the Canonical GTFS Schedule and GBFS Validators to share data quality
reports for each feed.
<br /> <br />
This database is hosted and maintained by MobilityData, the global
non-profit organization dedicated to the advancement of open
transportation data standards.
{t('description')}
<br />
<Button
component={'a'}
Expand All @@ -36,21 +31,18 @@ export default function Page(): ReactElement {
rel='noreferrer'
target='_blank'
>
Learn more about MobilityData
{t('learnMore')}
</Button>
</Typography>
<Typography
variant='h5'
color='primary'
sx={{ fontWeight: 700, mt: 5, mb: 1 }}
>
Why Use the Mobility Database?
{t('whyUse')}
</Typography>
<Typography className='answer'>
The Mobility Database provides free access to historical and current
GTFS, GTFS Realtime, and GBFS feeds from around the world. These feeds
are checked for updates every day, ensuring that the data you’re
looking at is the most recent data available.
{t('whyUseAnswer')}
<br /> <br />
In addition to our database, we develop and maintain other tools that
integrate with it such as&#20;
Comment on lines 46 to 48
Copy link

Copilot AI Feb 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Line 47-48 contains hardcoded English text that should be moved to the translation file. This text is not internationalized while the rest of the page uses t() for translations. Move this content to messages/en.json and messages/fr.json under the about namespace.

Copilot uses AI. Check for mistakes.
Expand All @@ -62,7 +54,7 @@ export default function Page(): ReactElement {
target='_blank'
endIcon={<OpenInNewIcon />}
>
the Canonical GTFS Schedule Validator
{t('gtfsValidator')}
</Button>
and&#20;
<Button
Expand All @@ -73,32 +65,24 @@ export default function Page(): ReactElement {
target='_blank'
endIcon={<OpenInNewIcon />}
>
the GBFS Validator.
{t('gbfsValidator')}
</Button>
Additional benefits of using the Mobility Database include
Copy link

Copilot AI Feb 3, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This line contains hardcoded English text that should be moved to the translation file. While the list items below use t('benefits.*'), the introductory text is not internationalized. Add this text to the translation files for proper i18n support.

Suggested change
Additional benefits of using the Mobility Database include
{t('additionalBenefitsIntro')}

Copilot uses AI. Check for mistakes.
<ul>
<li>
Mirrored versions of operator-hosted GTFS Schedule feeds to avoid
operator website downtimes and geoblocking
</li>
<li>
Bounding boxes that help to visualize or filter in the API by a
select region
</li>
<li>{t('benefits.mirrored')}</li>
<li>{t('benefits.boundingBoxes')}</li>
<li>
<Button
variant='text'
className='line-start inline'
href={'/contribute'}
href='/contribute'
rel='noreferrer'
target='_blank'
>
A simple, easy-to-use form to add new feeds
{t('benefits.addFeeds')}
</Button>
</li>
<li>
An open source community actively working to improve the tools
</li>
<li>{t('benefits.openSource')}</li>
</ul>
</Typography>
</Container>
Expand Down
26 changes: 26 additions & 0 deletions src/app/[locale]/about/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { type ReactElement } from 'react';
import { setRequestLocale } from 'next-intl/server';
import { type AVAILABLE_LOCALES, routing } from '../../../i18n/routing';
import AboutPage from './components/AboutPage';

export const dynamic = 'force-static';

export function generateStaticParams(): Array<{
locale: (typeof AVAILABLE_LOCALES)[number];
}> {
return routing.locales.map((locale) => ({ locale }));
}

interface PageProps {
params: Promise<{ locale: string }>;
}

export default async function About({
params,
}: PageProps): Promise<ReactElement> {
const { locale } = await params;

setRequestLocale(locale);

return <AboutPage />;
}
Loading
Loading