Skip to content
Open
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
49 changes: 39 additions & 10 deletions messages/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -75,10 +75,10 @@
},
"5": {
"name": "Cable tram",
"description": "Used for street-level rail cars where the cable runs beneath the vehicle (e.g., cable car in San Francisco)."
"description": "Used for street-level rail cars where the cable runs beneath the vehicle (e.g. cable car in San Francisco)."
},
"6": {
"name": "Aerial lift/Suspended cable car (e.g., gondola lift, aerial tramway)",
"name": "Aerial lift/Suspended cable car (e.g. gondola lift, aerial tramway)",
"description": "Cable transport where cabins, cars, gondolas or open chairs are suspended by means of one or more cables."
},
"7": {
Expand Down Expand Up @@ -609,7 +609,7 @@
"hero": {
"title": "The Benchmark for Reliable GTFS Schedule Data",
"paragraphs": [
"It's hard to measure if data is trustworthy. Transit agencies struggle to know if their GTFS data works for riders; data vendors lack a baseline of quality to aspire to, and trip planning apps end up spending time pre-processing feeds rather than seamlessly consuming them",
"It's hard to measure if data is trustworthy. Transit agencies struggle to know if their GTFS data works for riders; data vendors lack a baseline of quality to aspire to, and trip planning apps end up spending too much time pre-processing feeds rather than seamlessly consuming them",
"That's where the MobilityData Seal of Reliability comes in. As a clear measure of baseline quality, the Seal of Reliability is applied to feeds that meet five key criteria: they're official, stable, available, compliant, and fresh."
],
"ctaButton": "See a feed measured against the standard (todo)",
Expand Down Expand Up @@ -732,6 +732,14 @@
"riskAwareness": {
"question": "As a data producer, how do I know if I'm at risk of losing the Seal?",
"answer": "The best way is to check your feed on the Mobility Database 1-2 times a month to see your Seal status. Our team is working on email notifications, so in the future you can be notified when you've entered a grace period."
},
"thresholds": {
"question": "How did you select the thresholds for each criterion and grace period?",
"answer": "Thresholds were determined based on a mix of GTFS Best Practices review, examining real world data, and consulting consumers. For example, we decided on the grace period lengths based on reviewing the average time it takes for producers to correct the data evaluated on the Mobility Database. We have aimed to strike a balance between setting an ambitious bar for producers that promotes higher quality data, and setting goals that transit agencies can feasibly reach."
},
"freshRolling7Days": {
"question": "Why did you choose 7 days for the Fresh: Rolling Coverage criterion?",
"answer": "7 days was selected for two reasons: it is in the minimum threshold already specified in GTFS for service coverage, and upon reviewing international data, several high-ridership transit agencies failed higher test thresholds. This indicated that a higher threshold, like 14 or 30 days, may not be feasible with operational timelines for transit agencies."
}
},
"howItIsCalculated": {
Expand All @@ -757,25 +765,46 @@
"official": {
"title": "Official",
"paragraphs": [
"A feed is Official when MobilityData has confirmed it is authorized by the transit agency. This means it is published by, or on behalf of, the agency itself. MobilityData assesses this based on the domain of the producer URL, the feed submission contributor's personal information, the agency's website, and the `feed_info.txt` file. This determination is made manually and does not change based on automated checks.",
"Unlike the other five criteria, Official status is not subject to the six-month probation."
"A feed is Official when MobilityData has confirmed it is authorized by the transit agency. This means it is published by, or on behalf of, the agency itself.",
"This determination is made manually and does not change based on automated checks.",
"The Official status is not subject to the six-month probation."
],
"notice": "There is no grace period for Official. The designation is either confirmed or it is not."
"notice": "There is no grace period for Official. The designation is either confirmed or it is not.",
"assessmentIntro": "MobilityData assesses this based on:",
"assessmentItems": [
"The domain of the producer URL",
"The feed submission contributor’s personal information",
"The agency’s website",
"The `feed_info.txt` file"
]
},
"stable": {
"title": "Stable",
"description": "The Mobility Database evaluates stability based on the producer URL. A feed is considered Stable when:",
"items": [
"The same URL has served the feed without redirects for at least six months",
"The same URL has served the feed for at least six months",
"The URL appears to be permanent, meaning it does not look like a temporary file path with dates, times or seasons"
],
"notice": "There is no grace period for Stable. If the URL changes, the criterion fails immediately and the six-month probation restarts from the date the new URL is added as a new feed."
"notice": "There is no grace period for Stable. If the URL changes, the criterion fails immediately and the six-month probation restarts from the date the new URL is added as a new feed.",
"urlPatternsIntro": "Examples of URL patterns that would fail:",
"urlPatterns": [
"Dates in any format (e.g. https://opendata.bratislava.sk/dataset/download/cestovny-poriadok-20220725/1)",
"Seasonal slugs (e.g. `/summer-2024/`, `/winter-schedule/`)",
"Timestamps in the filename"
],
"redirectNote": "A permanent redirect (301) from an old URL to a new one passes the Stable criterion."
},
"available": {
"title": "Available",
"description": "Once per day, the Mobility Database attempts to download the feed from its producer URL. A fetch is considered successful when the response returns an HTTP response in the 200 range.",
"description": "Once per day, the Mobility Database attempts to download the feed from its producer URL.",
"noticeTitle": "14-day grace period.",
"notice": "If a fetch fails, producers have 14 days to restore access. If the feed is still unreachable after 14 days, the Seal is revoked."
"notice": "If a fetch fails, producers have 14 days to restore access. If the feed is still unreachable after 14 days, the Seal is revoked.",
"descriptionFetchIntro": "A fetch is considered successful when the response returns:",
"descriptionFetchItems": [
"An HTTP response in the 200 range",
"A redirect (301, 302, 303, 307, or 308) that resolves to the feed at another URL",
"A 304 Not Modified response indicating the feed content is unchanged"
]
},
"compliant": {
"title": "Compliant",
Expand Down
39 changes: 34 additions & 5 deletions messages/fr.json
Original file line number Diff line number Diff line change
Expand Up @@ -732,6 +732,14 @@
"riskAwareness": {
"question": "En tant que producteur de données, comment savoir si je risque de perdre le Sceau ?",
"answer": "La meilleure façon est de consulter le statut de votre flux sur la Mobility Database 1 à 2 fois par mois. Notre équipe travaille sur des notifications par courriel, afin qu'à l'avenir vous puissiez être averti dès l'entrée en période de grâce."
},
"thresholds": {
"question": "How did you select the thresholds for each criteria and grace period?",
"answer": "Placeholder answer for threshold selection."
},
"freshRolling7Days": {
"question": "Why did you choose 7 days for the freshness: rolling coverage criteria?",
"answer": "Placeholder answer for the 7-day freshness rolling coverage threshold."
}
},
"howItIsCalculated": {
Expand All @@ -757,10 +765,18 @@
"official": {
"title": "Officiel",
"paragraphs": [
"Un flux est Officiel lorsque MobilityData a confirmé qu'il est autorisé par l'agence de transport. Cela signifie qu'il est publié par l'agence elle-même ou en son nom. MobilityData évalue ce point à partir du domaine de l'URL du producteur, des informations personnelles du contributeur ayant soumis le flux, du site web de l'agence et du fichier `feed_info.txt`. Cette détermination est faite manuellement et ne change pas en fonction de vérifications automatisées.",
"Un flux est Officiel lorsque MobilityData a confirmé qu'il est autorisé par l'agence de transport. Cela signifie qu'il est publié par l'agence elle-même ou en son nom.",
"Cette détermination est faite manuellement et ne change pas en fonction de vérifications automatisées.",
"Contrairement aux cinq autres critères, le statut Officiel n'est pas soumis à la période probatoire de six mois."
],
"notice": "Il n'y a pas de période de grâce pour le critère Officiel. La désignation est soit confirmée, soit elle ne l'est pas."
"notice": "Il n'y a pas de période de grâce pour le critère Officiel. La désignation est soit confirmée, soit elle ne l'est pas.",
"assessmentIntro": "MobilityData évalue ce point à partir de :",
"assessmentItems": [
"Le domaine de l'URL du producteur",
"Les informations personnelles du contributeur ayant soumis le flux",
"Le site web de l'agence",
"Le fichier `feed_info.txt`"
]
},
"stable": {
"title": "Stable",
Expand All @@ -769,13 +785,26 @@
"La même URL sert le flux sans redirection depuis au moins six mois",
"L'URL semble permanente, c'est-à-dire qu'elle ne ressemble pas à un chemin de fichier temporaire comportant des dates, des heures ou des saisons"
],
"notice": "Il n'y a pas de période de grâce pour le critère Stable. Si l'URL change, le critère échoue immédiatement et la période probatoire de six mois repart à la date à laquelle la nouvelle URL est ajoutée en tant que nouveau flux."
"notice": "Il n'y a pas de période de grâce pour le critère Stable. Si l'URL change, le critère échoue immédiatement et la période probatoire de six mois repart à la date à laquelle la nouvelle URL est ajoutée en tant que nouveau flux.",
"urlPatternsIntro": "Exemples de modèles d'URL qui échoueraient :",
"urlPatterns": [
"Des dates dans n'importe quel format (ex. : https://opendata.bratislava.sk/dataset/download/cestovny-poriadok-20220725/1)",
"Des slugs saisonniers (ex. : `/summer-2024/`, `/winter-schedule/`)",
"Des numéros de version ou des horodatages dans le nom du fichier"
],
"redirectNote": "Une redirection permanente (301) d'une ancienne URL vers une nouvelle satisfait le critère Stable."
},
"available": {
"title": "Disponible",
"description": "Une fois par jour, la Mobility Database tente de télécharger le flux depuis l'URL de son producteur. Une récupération est considérée comme réussie lorsque la réponse HTTP se situe dans la plage 200.",
"description": "Une fois par jour, la Mobility Database tente de télécharger le flux depuis l'URL de son producteur.",
"noticeTitle": "Période de grâce de 14 jours.",
"notice": "En cas d'échec de récupération, les producteurs disposent de 14 jours pour rétablir l'accès. Si le flux reste inaccessible après 14 jours, le Sceau est retiré."
"notice": "En cas d'échec de récupération, les producteurs disposent de 14 jours pour rétablir l'accès. Si le flux reste inaccessible après 14 jours, le Sceau est retiré.",
"descriptionFetchIntro": "Une récupération est considérée comme réussie lorsque la réponse retourne :",
"descriptionFetchItems": [
"Une réponse HTTP dans la plage 200",
"Une redirection (301, 302, 303, 307 ou 308) qui résout vers le flux à une autre URL",
"Une réponse 304 Non Modifié indiquant que le contenu du flux est inchangé"
]
},
"compliant": {
"title": "Conforme",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ import {
heroContent,
} from '../lib/content';

const FEEDS_MEETING_STANDARD_PERCENT = 41;
const FEEDS_MEETING_STANDARD_PERCENT = 36;
const FEEDS_BELOW_STANDARD_PERCENT = 100 - FEEDS_MEETING_STANDARD_PERCENT;

export default async function SealOfReliabilityDescriptionPage(): Promise<ReactElement> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -158,7 +158,14 @@ export default async function HowItIsCalculatedPage(): Promise<ReactElement> {
{t('official.title')}
</Typography>
<Box sx={criterionBodyStyle}>
{officialParagraphs.map((paragraph) => (
<Typography variant='body1'>
<RichText text={officialParagraphs[0]} />
</Typography>
<Typography variant='body1'>
{t('official.assessmentIntro')}
</Typography>
<BulletList items={t.raw('official.assessmentItems') as string[]} />
{officialParagraphs.slice(1).map((paragraph) => (
<Typography variant='body1' key={paragraph}>
<RichText text={paragraph} />
</Typography>
Expand All @@ -175,6 +182,11 @@ export default async function HowItIsCalculatedPage(): Promise<ReactElement> {
<Box sx={criterionBodyStyle}>
<Typography variant='body1'>{t('stable.description')}</Typography>
<BulletList items={stableItems} />
<Typography variant='body1'>
{t('stable.urlPatternsIntro')}
</Typography>
<BulletList items={t.raw('stable.urlPatterns') as string[]} />
<Typography variant='body1'>{t('stable.redirectNote')}</Typography>
<Alert severity='info'>{t('stable.notice')}</Alert>
</Box>
</SectionContainer>
Expand All @@ -188,6 +200,12 @@ export default async function HowItIsCalculatedPage(): Promise<ReactElement> {
<Typography variant='body1'>
{t('available.description')}
</Typography>
<Typography variant='body1'>
{t('available.descriptionFetchIntro')}
</Typography>
<BulletList
items={t.raw('available.descriptionFetchItems') as string[]}
/>
<Alert severity='warning'>
<AlertTitle>{t('available.noticeTitle')}</AlertTitle>
{t('available.notice')}
Expand Down
8 changes: 8 additions & 0 deletions src/app/[locale]/seal-of-reliability/lib/content.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -150,4 +150,12 @@ export const faqEntries: FaqEntry[] = [
questionKey: 'faq.riskAwareness.question',
answerKey: 'faq.riskAwareness.answer',
},
{
questionKey: 'faq.thresholds.question',
answerKey: 'faq.thresholds.answer',
},
{
questionKey: 'faq.freshRolling7Days.question',
answerKey: 'faq.freshRolling7Days.answer',
},
];
Loading