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
3 changes: 3 additions & 0 deletions fixtures/basic/translations.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
table_name,field_name,language,translation,field_value,record_id,record_sub_id
stops,stop_name,nl,Stop Gebied,,stop1,
stops,stop_name,fr,Arrêt Région,"Stop Area",,
2 changes: 2 additions & 0 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ pub enum Error {
ReferenceError(String),
#[error("Could not read GTFS: {0} is neither a file nor a directory")]
NotFileNorDirectory(String),
#[error("Invalid translation: {0}")]
InvalidTranslation(String),
#[error("'{0}' is not a valid time")]
InvalidTime(String),
#[error("'{0}' is not a valid color")]
Expand Down
121 changes: 121 additions & 0 deletions src/gtfs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,18 @@ pub struct Gtfs {
pub shapes: HashMap<String, Vec<Shape>>,
pub fare_attributes: HashMap<String, FareAttribute>,
pub feed_info: Vec<FeedInfo>,
pub translations_by_id: HashMap<TranslationByIdKey, String>,
pub translations_by_value: HashMap<TranslationByValueKey, String>,
}

impl TryFrom<RawGtfs> for Gtfs {
type Error = Error;
fn try_from(raw: RawGtfs) -> Result<Gtfs, Error> {
let stops = to_stop_map(raw.stops?);
let trips = create_trips(raw.trips?, raw.stop_times?, &stops)?;
let (translations_by_id, translations_by_value) = create_translations(
raw.translations.unwrap_or(Ok(vec!()))?
)?;

Ok(Gtfs {
stops,
Expand All @@ -40,6 +45,8 @@ impl TryFrom<RawGtfs> for Gtfs {
calendar_dates: to_calendar_dates(
raw.calendar_dates.unwrap_or_else(|| Ok(Vec::new()))?,
),
translations_by_id,
translations_by_value,
read_duration: raw.read_duration,
})
}
Expand Down Expand Up @@ -133,27 +140,85 @@ impl Gtfs {
result
}

pub fn translate(
&self,
table_name: &str,
field_name: &str,
language: &str,
record_id: &str,
record_sub_id: Option<&str>,
field_value: &String
) -> String {
if let Some(ret) = self.translations_by_id.get(&TranslationByIdKey{
table_name: table_name.to_string(),
field_name: field_name.to_string(),
language: language.to_string(),
record_id: record_id.to_string(),
record_sub_id: record_sub_id.map(|x| x.to_string()),
}) {
return ret.to_string();
}

if let Some(ret) = self.translations_by_value.get(&TranslationByValueKey{
table_name: table_name.to_string(),
field_name: field_name.to_string(),
language: language.to_string(),
field_value: field_value.to_string(),
}) {
return ret.to_string();
}

field_value.to_string()
}

pub fn get_stop<'a>(&'a self, id: &str) -> Result<&'a Stop, Error> {
match self.stops.get(id) {
Some(stop) => Ok(stop),
None => Err(Error::ReferenceError(id.to_owned())),
}
}

pub fn get_stop_translated(
&self,
id: &str,
language: &str
) -> Result<Stop, Error> {
let stop = self.get_stop(id)?;
Ok(stop.to_owned().translate(self, language))
}

pub fn get_trip<'a>(&'a self, id: &str) -> Result<&'a Trip, Error> {
match self.trips.get(id) {
Some(trip) => Ok(trip),
None => Err(Error::ReferenceError(id.to_owned())),
}
}

pub fn get_trip_translated(
&self,
id: &str,
language: &str
) -> Result<Trip, Error> {
let trip = self.get_trip(id)?;
Ok(trip.to_owned().translate(self, language))
}

pub fn get_route<'a>(&'a self, id: &str) -> Result<&'a Route, Error> {
match self.routes.get(id) {
Some(route) => Ok(route),
None => Err(Error::ReferenceError(id.to_owned())),
}
}

pub fn get_route_translated(
&self,
id: &str,
language: &str
) -> Result<Route, Error> {
let route = self.get_route(id)?;
Ok(route.to_owned().translate(self, language))
}

pub fn get_calendar<'a>(&'a self, id: &str) -> Result<&'a Calendar, Error> {
match self.calendar.get(id) {
Some(calendar) => Ok(calendar),
Expand Down Expand Up @@ -253,3 +318,59 @@ fn create_trips(
}
Ok(trips)
}

fn create_translations(
raw_translations: Vec<Translation>
) -> Result<(
HashMap<TranslationByIdKey, String>,
HashMap<TranslationByValueKey, String>
), Error> {
let mut translations_by_id = HashMap::new();
let mut translations_by_value = HashMap::new();

for translation in raw_translations {
if translation.record_id.is_some() {
// Make sure it is not forbidden
if translation.field_value.is_some() ||
translation.table_name == "feed_info".to_string() {
return Err(Error::InvalidTranslation(
"record_id was defined when it was forbidden".to_string()
));
}

// Make sure record_sub_id is there if and only if it is required
if translation.table_name == "stop_times".to_string() &&
translation.record_sub_id.is_none() {
return Err(Error::InvalidTranslation(
"record_sub_id was not set when it was required".to_string()
));
}

translations_by_id.insert(TranslationByIdKey {
table_name: translation.table_name,
field_name: translation.field_name,
language: translation.language,
record_id: translation.record_id.unwrap(),
record_sub_id: translation.record_sub_id,
}, translation.translation);
} else if translation.field_value.is_some() {
// Make sure it is not forbidden
if translation.record_id.is_some() ||
translation.record_sub_id.is_some() ||
translation.table_name == "feed_info".to_string() {
return Err(Error::InvalidTranslation(
"field_value was defined when it was forbidden".to_string()
));
}

translations_by_value.insert(TranslationByValueKey {
table_name: translation.table_name,
field_name: translation.field_name,
language: translation.language,
field_value: translation.field_value.unwrap(),
}, translation.translation);
}
}

return Ok((translations_by_id, translations_by_value));
}
Loading