From 37be42648bf500aca3bf35150c4a2dc563a16716 Mon Sep 17 00:00:00 2001 From: Sebastian Barry Date: Thu, 12 Oct 2023 13:16:09 -0600 Subject: [PATCH 1/5] Adding default label-options confirmHelper.ts - Removed archaic behavior or using old Angular i18nUtils module to get the filename of the translations' trip_confirm_options.json file - The "else" default "no label_options found in config" behavior is almost identical to the if(appConfig.label_options), but it just uses the default label options URL at label-options.json.sample - Pulled the language-specific text handling behavior out of the if statement, because either way (label_options or no label_options) the JSON data model will look the same - The for loop for filling in the translatied text for label-options checks 1. The label-options file first, then 2. The i18next file for the translation label-options.json.sample - Created new file - Replaces trip_confirm_options.json.sample (this location in confirmHelper.ts was the only place in the codebase using this file) - Modeled after https://github.com/e-mission/nrel-openpath-deploy-configs/blob/main/label_options/example-program-label-options.json - Only has translations for EN and ES trip_confirm_options.json.sample - Removed this file --- www/js/survey/multilabel/confirmHelper.ts | 37 +++---- www/json/label-options.json.sample | 124 ++++++++++++++++++++++ www/json/trip_confirm_options.json.sample | 52 --------- 3 files changed, 140 insertions(+), 73 deletions(-) create mode 100644 www/json/label-options.json.sample delete mode 100644 www/json/trip_confirm_options.json.sample diff --git a/www/js/survey/multilabel/confirmHelper.ts b/www/js/survey/multilabel/confirmHelper.ts index 6350745eb..c7cf74c26 100644 --- a/www/js/survey/multilabel/confirmHelper.ts +++ b/www/js/survey/multilabel/confirmHelper.ts @@ -36,29 +36,24 @@ export async function getLabelOptions(appConfigParam?) { if (appConfig.label_options) { const labelOptionsJson = await fetchUrlCached(appConfig.label_options); + logDebug("label_options found in config, using dynamic label options at " + appConfig.label_options); labelOptions = JSON.parse(labelOptionsJson) as LabelOptions; - /* fill in the translations to the 'text' fields of the labelOptions, - according to the current language */ - const lang = i18next.language; - for (const opt in labelOptions) { - labelOptions[opt]?.forEach?.((o, i) => { - const translationKey = o.value; - const translation = labelOptions.translations[lang][translationKey]; - labelOptions[opt][i].text = translation; - }); - } } else { - // backwards compat: if dynamic config doesn't have label_options, use the old way - const i18nUtils = getAngularService("i18nUtils"); - const optionFileName = await i18nUtils.geti18nFileName("json/", "trip_confirm_options", ".json"); - try { - const optionJson = await fetch(optionFileName).then(r => r.json()); - labelOptions = optionJson as LabelOptions; - } catch (e) { - logDebug("error "+JSON.stringify(e)+" while reading confirm options, reverting to defaults"); - const optionJson = await fetch("json/trip_confirm_options.json.sample").then(r => r.json()); - labelOptions = optionJson as LabelOptions; - } + const defaultLabelOptionsURL = 'json/label-options.json.sample'; + logDebug("No label_options found in config, using default label options at " + defaultLabelOptionsURL); + const defaultLabelOptionsJson = await fetchUrlCached(defaultLabelOptionsURL); + labelOptions = JSON.parse(defaultLabelOptionsJson) as LabelOptions; + } + /* fill in the translations to the 'text' fields of the labelOptions, + according to the current language */ + const lang = i18next.language; + for (const opt in labelOptions) { + labelOptions[opt]?.forEach?.((o, i) => { + const translationKey = o.value; + // If translation exists in i18next, use that. Otherwise, use the one in the labelOptions. + const translation = labelOptions.translations[lang][translationKey] || i18next.t(`multilabel.${translationKey}`); + labelOptions[opt][i].text = translation; + }); } return labelOptions; } diff --git a/www/json/label-options.json.sample b/www/json/label-options.json.sample new file mode 100644 index 000000000..9d3447bda --- /dev/null +++ b/www/json/label-options.json.sample @@ -0,0 +1,124 @@ +{ + "MODE": [ + {"value":"walk", "baseMode":"WALKING", "met_equivalent":"WALKING", "kgCo2PerKm": 0}, + {"value":"e-bike", "baseMode":"E_BIKE", "met": {"ALL": {"range": [0, -1], "mets": 4.9}}, "kgCo2PerKm": 0.00728}, + {"value":"bike", "baseMode":"BICYCLING", "met_equivalent":"BICYCLING", "kgCo2PerKm": 0}, + {"value":"bikeshare", "baseMode":"BICYCLING", "met_equivalent":"BICYCLING", "kgCo2PerKm": 0}, + {"value":"scootershare", "baseMode":"E_SCOOTER", "met_equivalent":"IN_VEHICLE", "kgCo2PerKm": 0.00894}, + {"value":"drove_alone", "baseMode":"CAR", "met_equivalent":"IN_VEHICLE", "kgCo2PerKm": 0.22031}, + {"value":"shared_ride", "baseMode":"CAR", "met_equivalent":"IN_VEHICLE", "kgCo2PerKm": 0.11015}, + {"value":"e_car_drove_alone", "baseMode":"E_CAR", "met_equivalent":"IN_VEHICLE", "kgCo2PerKm": 0.08216}, + {"value":"e_car_shared_ride", "baseMode":"E_CAR", "met_equivalent":"IN_VEHICLE", "kgCo2PerKm": 0.04108}, + {"value":"moped", "baseMode":"MOPED", "met_equivalent":"IN_VEHICLE", "kgCo2PerKm": 0.05555}, + {"value":"taxi", "baseMode":"TAXI", "met_equivalent":"IN_VEHICLE", "kgCo2PerKm": 0.30741}, + {"value":"bus", "baseMode":"BUS", "met_equivalent":"IN_VEHICLE", "kgCo2PerKm": 0.20727}, + {"value":"train", "baseMode":"TRAIN", "met_equivalent":"IN_VEHICLE", "kgCo2PerKm": 0.12256}, + {"value":"free_shuttle", "baseMode":"BUS", "met_equivalent":"IN_VEHICLE", "kgCo2PerKm": 0.20727}, + {"value":"air", "baseMode":"AIR", "met_equivalent":"IN_VEHICLE", "kgCo2PerKm": 0.09975}, + {"value":"not_a_trip", "baseMode":"UNKNOWN", "met_equivalent":"UNKNOWN", "kgCo2PerKm": 0}, + {"value":"other", "baseMode":"OTHER", "met_equivalent":"UNKNOWN", "kgCo2PerKm": 0} + ], + "PURPOSE": [ + {"value":"home"}, + {"value":"work"}, + {"value":"at_work"}, + {"value":"school"}, + {"value":"transit_transfer"}, + {"value":"shopping"}, + {"value":"meal"}, + {"value":"pick_drop_person"}, + {"value":"pick_drop_item"}, + {"value":"personal_med"}, + {"value":"access_recreation"}, + {"value":"exercise"}, + {"value":"entertainment"}, + {"value":"religious"}, + {"value":"other"} + ], + "REPLACED_MODE": [ + {"value":"no_travel"}, + {"value":"walk"}, + {"value":"bike"}, + {"value":"bikeshare"}, + {"value":"scootershare"}, + {"value":"drove_alone"}, + {"value":"shared_ride"}, + {"value":"e_car_drove_alone"}, + {"value":"e_car_shared_ride"}, + {"value":"taxi"}, + {"value":"bus"}, + {"value":"train"}, + {"value":"free_shuttle"}, + {"value":"other"} + ], + "translations": { + "en": { + "walk": "Walk", + "e-bike": "E-bike", + "bike": "Regular Bike", + "bikeshare": "Bikeshare", + "scootershare": "Scooter share", + "drove_alone": "Gas Car Drove Alone", + "shared_ride": "Gas Car Shared Ride", + "e_car_drove_alone": "E-Car Drove Alone", + "e_car_shared_ride": "E-Car Shared Ride", + "moped": "Moped", + "taxi": "Taxi/Uber/Lyft", + "bus": "Bus", + "train": "Train", + "free_shuttle": "Free Shuttle", + "air": "Air", + "not_a_trip": "Not a trip", + "no_travel": "No travel", + "home": "Home", + "work": "To Work", + "at_work": "At Work", + "school": "School", + "transit_transfer": "Transit transfer", + "shopping": "Shopping", + "meal": "Meal", + "pick_drop_person": "Pick-up/ Drop off Person", + "pick_drop_item": "Pick-up/ Drop off Item", + "personal_med": "Personal/ Medical", + "access_recreation": "Access Recreation", + "exercise": "Recreation/ Exercise", + "entertainment": "Entertainment/ Social", + "religious": "Religious", + "other": "Other" + }, + "es": { + "walk": "Caminando", + "e-bike": "e-bicicleta", + "bike": "Bicicleta", + "bikeshare": "Bicicleta compartida", + "scootershare": "Motoneta compartida", + "drove_alone": "Coche de Gas, Condujo solo", + "shared_ride": "Coche de Gas, Condujo con otros", + "e_car_drove_alone": "e-coche, Condujo solo", + "e_car_shared_ride": "e-coche, Condujo con ontras", + "moped": "Ciclomotor", + "taxi": "Taxi/Uber/Lyft", + "bus": "Autobús", + "train": "Tren", + "free_shuttle": "Colectivo gratuito", + "air": "Avión", + "not_a_trip": "No es un viaje", + "no_travel": "No viajar", + "home": "Inicio", + "work": "Trabajo", + "at_work": "En el trabajo", + "school": "Escuela", + "transit_transfer": "Transbordo", + "shopping": "Compras", + "meal": "Comida", + "pick_drop_person": "Recoger/ Entregar Individuo", + "pick_drop_item": "Recoger/ Entregar Objeto", + "personal_med": "Personal/ Médico", + "access_recreation": "Acceder a Recreación", + "exercise": "Recreación/ Ejercicio", + "entertainment": "Entretenimiento/ Social", + "religious": "Religioso", + "other": "Otros" + } + } +} \ No newline at end of file diff --git a/www/json/trip_confirm_options.json.sample b/www/json/trip_confirm_options.json.sample deleted file mode 100644 index 1e90bc1bb..000000000 --- a/www/json/trip_confirm_options.json.sample +++ /dev/null @@ -1,52 +0,0 @@ -{ - "MODE" : [ - {"text":"Walk", "value":"walk", "baseMode":"WALKING", "met_equivalent": "WALKING", "kgCo2PerKm": 0}, - {"text":"E-bike","value":"e-bike", "baseMode": "E_BIKE", "met": { - "ALL": {"range": [0, -1], "mets": 4.9} - }, "kgCo2PerKm": 0.00728}, - {"text":"Regular Bike","value":"bike", "baseMode":"BICYCLING", "met_equivalent": "BICYCLING", "kgCo2PerKm": 0}, - {"text":"Bikeshare","value":"bikeshare", "baseMode":"BICYCLING", "met_equivalent": "BICYCLING", "kgCo2PerKm": 0}, - {"text":"Scooter share","value":"scootershare", "baseMode":"E_SCOOTER", "met_equivalent": "IN_VEHICLE", "kgCo2PerKm": 0.00894}, - {"text":"Gas Car Drove Alone","value":"drove_alone", "baseMode":"CAR", "met_equivalent": "IN_VEHICLE", "kgCo2PerKm": 0.22031}, - {"text":"Gas Car Shared Ride","value":"shared_ride", "baseMode":"CAR", "met_equivalent": "IN_VEHICLE", "kgCo2PerKm": 0.11015}, - {"text":"E-Car Drove Alone","value":"e_car_drove_alone", "baseMode":"E_CAR", "met_equivalent": "IN_VEHICLE", "kgCo2PerKm": 0.08216}, - {"text":"E-Car Shared Ride","value":"e_car_shared_ride", "baseMode":"E_CAR", "met_equivalent": "IN_VEHICLE", "kgCo2PerKm": 0.04108}, - {"text":"Taxi/Uber/Lyft","value":"taxi", "baseMode":"TAXI", "met_equivalent": "IN_VEHICLE", "kgCo2PerKm": 0.30741}, - {"text":"Bus","value":"bus", "baseMode":"BUS", "met_equivalent": "IN_VEHICLE", "kgCo2PerKm": 0.20727}, - {"text":"Train","value":"train", "baseMode":"TRAIN", "met_equivalent": "IN_VEHICLE", "kgCo2PerKm": 0.12256}, - {"text":"Free Shuttle","value":"free_shuttle", "baseMode":"BUS", "met_equivalent": "IN_VEHICLE", "kgCo2PerKm": 0.20727}, - {"text":"Air","value":"air", "baseMode":"AIR", "met_equivalent": "IN_VEHICLE", "kgCo2PerKm": 0.09975}, - {"text":"Not a Trip","value":"not_a_trip", "baseMode":"UNKNOWN", "met_equivalent": "UNKNOWN", "kgCo2PerKm": 0}, - {"text":"Other","value":"other", "baseMode":"OTHER", "met_equivalent": "UNKNOWN", "kgCo2PerKm": 0}], - "REPLACED_MODE" : [ - {"text":"No travel", "value":"no_travel"}, - {"text":"Walk", "value":"walk"}, - {"text":"Regular Bike","value":"bike"}, - {"text":"Bikeshare","value":"bikeshare"}, - {"text":"Scooter share","value":"scootershare"}, - {"text":"Gas Car, drove alone","value":"drove_alone"}, - {"text":"Gas Car, with others","value":"shared_ride"}, - {"text":"E-Car, drove alone","value":"e_car_drove_alone"}, - {"text":"E-Car, with others","value":"e_car_shared_ride"}, - {"text":"Taxi/Uber/Lyft","value":"taxi"}, - {"text":"Bus","value":"bus"}, - {"text":"Train","value":"train"}, - {"text":"Free Shuttle","value":"free_shuttle"}, - {"text":"Other","value":"other"}], - "PURPOSE" : [ - {"text":"Home", "value":"home"}, - {"text":"To Work","value":"work"}, - {"text":"At Work","value":"at_work"}, - {"text":"School","value":"school"}, - {"text":"Transit transfer", "value":"transit_transfer"}, - {"text":"Shopping","value":"shopping"}, - {"text":"Meal","value":"meal"}, - {"text":"Pick-up/ Drop off Person","value":"pick_drop_person"}, - {"text":"Pick-up/ Drop off Item","value":"pick_drop_item"}, - {"text":"Personal/ Medical","value":"personal_med"}, - {"text":"Access Recreation","value":"access_recreation"}, - {"text":"Recreation/ Exercise","value":"exercise"}, - {"text":"Entertainment/ Social","value":"entertainment"}, - {"text":"Religious", "value":"religious"}, - {"text":"Other","value":"other"}] -} From 650851763f6146ec8cb934ba63d0e1683e37e6b9 Mon Sep 17 00:00:00 2001 From: Sebastian Barry Date: Thu, 12 Oct 2023 13:17:08 -0600 Subject: [PATCH 2/5] Adding examples of multilabel translations to en.json en.json - Added multilabel filed filled with a few multilabel translations in EN --- www/i18n/en.json | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/www/i18n/en.json b/www/i18n/en.json index e47fdd62d..07d31c2b3 100644 --- a/www/i18n/en.json +++ b/www/i18n/en.json @@ -146,6 +146,41 @@ "no-travel-hint": "To see more, change the filters above or go record some travel!" }, + "multilabel":{ + "walk": "Walk", + "e-bike": "E-bike", + "bike": "Regular Bike", + "bikeshare": "Bikeshare", + "scootershare": "Scooter share", + "drove_alone": "Gas Car Drove Alone", + "shared_ride": "Gas Car Shared Ride", + "e_car_drove_alone": "E-Car Drove Alone", + "e_car_shared_ride": "E-Car Shared Ride", + "moped": "Moped", + "taxi": "Taxi/Uber/Lyft", + "bus": "Bus", + "train": "Train", + "free_shuttle": "Free Shuttle", + "air": "Air", + "not_a_trip": "Not a trip", + "no_travel": "No travel", + "home": "Home", + "work": "To Work", + "at_work": "At Work", + "school": "School", + "transit_transfer": "Transit transfer", + "shopping": "Shopping", + "meal": "Meal", + "pick_drop_person": "Pick-up/ Drop off Person", + "pick_drop_item": "Pick-up/ Drop off Item", + "personal_med": "Personal/ Medical", + "access_recreation": "Access Recreation", + "exercise": "Recreation/ Exercise", + "entertainment": "Entertainment/ Social", + "religious": "Religious", + "other": "Other" + }, + "main-metrics":{ "summary": "My Summary", "chart": "Chart", From 36b56daad2be26a6ce0ed1241797f6048707a65e Mon Sep 17 00:00:00 2001 From: Sebastian Barry <61334340+sebastianbarry@users.noreply.github.com> Date: Tue, 17 Oct 2023 11:07:17 -0600 Subject: [PATCH 3/5] Correct text in comment > JGreenlee > It's the other way around. labelOptions first, then i18next. > The code is correct but the comment is not --- www/js/survey/multilabel/confirmHelper.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/www/js/survey/multilabel/confirmHelper.ts b/www/js/survey/multilabel/confirmHelper.ts index c7cf74c26..cb94c1f2e 100644 --- a/www/js/survey/multilabel/confirmHelper.ts +++ b/www/js/survey/multilabel/confirmHelper.ts @@ -50,7 +50,7 @@ export async function getLabelOptions(appConfigParam?) { for (const opt in labelOptions) { labelOptions[opt]?.forEach?.((o, i) => { const translationKey = o.value; - // If translation exists in i18next, use that. Otherwise, use the one in the labelOptions. + // If translation exists in labelOptions, use that. Otherwise, use the one in the i18next. const translation = labelOptions.translations[lang][translationKey] || i18next.t(`multilabel.${translationKey}`); labelOptions[opt][i].text = translation; }); From 202f6dbbe71db89cce6e9e83a9a4a1dc5362d082 Mon Sep 17 00:00:00 2001 From: Sebastian Barry Date: Tue, 17 Oct 2023 11:11:45 -0600 Subject: [PATCH 4/5] Adding spaces between slashes in text > JGreenlee > While we are rewriting and have this opportunity, can we make all the text with slashes look "like / this" instead of "like/ this"? > I believe they were made like that a while ago to force a line break. But we don't do that anymore in the UI so the slashes end up looking weird. --- www/i18n/en.json | 12 ++++++------ www/json/label-options.json.sample | 24 ++++++++++++------------ 2 files changed, 18 insertions(+), 18 deletions(-) diff --git a/www/i18n/en.json b/www/i18n/en.json index 07d31c2b3..9217339f7 100644 --- a/www/i18n/en.json +++ b/www/i18n/en.json @@ -157,7 +157,7 @@ "e_car_drove_alone": "E-Car Drove Alone", "e_car_shared_ride": "E-Car Shared Ride", "moped": "Moped", - "taxi": "Taxi/Uber/Lyft", + "taxi": "Taxi / Uber / Lyft", "bus": "Bus", "train": "Train", "free_shuttle": "Free Shuttle", @@ -171,12 +171,12 @@ "transit_transfer": "Transit transfer", "shopping": "Shopping", "meal": "Meal", - "pick_drop_person": "Pick-up/ Drop off Person", - "pick_drop_item": "Pick-up/ Drop off Item", - "personal_med": "Personal/ Medical", + "pick_drop_person": "Pick-up / Drop off Person", + "pick_drop_item": "Pick-up / Drop off Item", + "personal_med": "Personal / Medical", "access_recreation": "Access Recreation", - "exercise": "Recreation/ Exercise", - "entertainment": "Entertainment/ Social", + "exercise": "Recreation / Exercise", + "entertainment": "Entertainment / Social", "religious": "Religious", "other": "Other" }, diff --git a/www/json/label-options.json.sample b/www/json/label-options.json.sample index 9d3447bda..0f4292c7f 100644 --- a/www/json/label-options.json.sample +++ b/www/json/label-options.json.sample @@ -63,7 +63,7 @@ "e_car_drove_alone": "E-Car Drove Alone", "e_car_shared_ride": "E-Car Shared Ride", "moped": "Moped", - "taxi": "Taxi/Uber/Lyft", + "taxi": "Taxi / Uber / Lyft", "bus": "Bus", "train": "Train", "free_shuttle": "Free Shuttle", @@ -77,12 +77,12 @@ "transit_transfer": "Transit transfer", "shopping": "Shopping", "meal": "Meal", - "pick_drop_person": "Pick-up/ Drop off Person", - "pick_drop_item": "Pick-up/ Drop off Item", - "personal_med": "Personal/ Medical", + "pick_drop_person": "Pick-up / Drop off Person", + "pick_drop_item": "Pick-up / Drop off Item", + "personal_med": "Personal / Medical", "access_recreation": "Access Recreation", - "exercise": "Recreation/ Exercise", - "entertainment": "Entertainment/ Social", + "exercise": "Recreation / Exercise", + "entertainment": "Entertainment / Social", "religious": "Religious", "other": "Other" }, @@ -97,7 +97,7 @@ "e_car_drove_alone": "e-coche, Condujo solo", "e_car_shared_ride": "e-coche, Condujo con ontras", "moped": "Ciclomotor", - "taxi": "Taxi/Uber/Lyft", + "taxi": "Taxi / Uber / Lyft", "bus": "Autobús", "train": "Tren", "free_shuttle": "Colectivo gratuito", @@ -111,12 +111,12 @@ "transit_transfer": "Transbordo", "shopping": "Compras", "meal": "Comida", - "pick_drop_person": "Recoger/ Entregar Individuo", - "pick_drop_item": "Recoger/ Entregar Objeto", - "personal_med": "Personal/ Médico", + "pick_drop_person": "Recoger / Entregar Individuo", + "pick_drop_item": "Recoger / Entregar Objeto", + "personal_med": "Personal / Médico", "access_recreation": "Acceder a Recreación", - "exercise": "Recreación/ Ejercicio", - "entertainment": "Entretenimiento/ Social", + "exercise": "Recreación / Ejercicio", + "entertainment": "Entretenimiento / Social", "religious": "Religioso", "other": "Otros" } From 2c6739a185c109fb24d70ea20ff57236dfa80c4d Mon Sep 17 00:00:00 2001 From: Sebastian Barry Date: Fri, 20 Oct 2023 12:41:24 -0600 Subject: [PATCH 5/5] Remove translations from label-options.json.sample Since the default translations are in 18next files, we don't need a duplicate of the default label options translations in this file Also changed the logic because I didn't have it right when labelOptions.translations is undefined --- www/js/survey/multilabel/confirmHelper.ts | 4 +- www/json/label-options.json.sample | 72 +---------------------- 2 files changed, 3 insertions(+), 73 deletions(-) diff --git a/www/js/survey/multilabel/confirmHelper.ts b/www/js/survey/multilabel/confirmHelper.ts index cb94c1f2e..b668669bf 100644 --- a/www/js/survey/multilabel/confirmHelper.ts +++ b/www/js/survey/multilabel/confirmHelper.ts @@ -50,8 +50,8 @@ export async function getLabelOptions(appConfigParam?) { for (const opt in labelOptions) { labelOptions[opt]?.forEach?.((o, i) => { const translationKey = o.value; - // If translation exists in labelOptions, use that. Otherwise, use the one in the i18next. - const translation = labelOptions.translations[lang][translationKey] || i18next.t(`multilabel.${translationKey}`); + // If translation exists in labelOptions, use that. Otherwise, use the one in the i18next. If there is not "translations" field in labelOptions, defaultly use the one in the i18next. + const translation = labelOptions.translations ? labelOptions.translations[lang][translationKey] || i18next.t(`multilabel.${translationKey}`) : i18next.t(`multilabel.${translationKey}`); labelOptions[opt][i].text = translation; }); } diff --git a/www/json/label-options.json.sample b/www/json/label-options.json.sample index 0f4292c7f..9870b744f 100644 --- a/www/json/label-options.json.sample +++ b/www/json/label-options.json.sample @@ -50,75 +50,5 @@ {"value":"train"}, {"value":"free_shuttle"}, {"value":"other"} - ], - "translations": { - "en": { - "walk": "Walk", - "e-bike": "E-bike", - "bike": "Regular Bike", - "bikeshare": "Bikeshare", - "scootershare": "Scooter share", - "drove_alone": "Gas Car Drove Alone", - "shared_ride": "Gas Car Shared Ride", - "e_car_drove_alone": "E-Car Drove Alone", - "e_car_shared_ride": "E-Car Shared Ride", - "moped": "Moped", - "taxi": "Taxi / Uber / Lyft", - "bus": "Bus", - "train": "Train", - "free_shuttle": "Free Shuttle", - "air": "Air", - "not_a_trip": "Not a trip", - "no_travel": "No travel", - "home": "Home", - "work": "To Work", - "at_work": "At Work", - "school": "School", - "transit_transfer": "Transit transfer", - "shopping": "Shopping", - "meal": "Meal", - "pick_drop_person": "Pick-up / Drop off Person", - "pick_drop_item": "Pick-up / Drop off Item", - "personal_med": "Personal / Medical", - "access_recreation": "Access Recreation", - "exercise": "Recreation / Exercise", - "entertainment": "Entertainment / Social", - "religious": "Religious", - "other": "Other" - }, - "es": { - "walk": "Caminando", - "e-bike": "e-bicicleta", - "bike": "Bicicleta", - "bikeshare": "Bicicleta compartida", - "scootershare": "Motoneta compartida", - "drove_alone": "Coche de Gas, Condujo solo", - "shared_ride": "Coche de Gas, Condujo con otros", - "e_car_drove_alone": "e-coche, Condujo solo", - "e_car_shared_ride": "e-coche, Condujo con ontras", - "moped": "Ciclomotor", - "taxi": "Taxi / Uber / Lyft", - "bus": "Autobús", - "train": "Tren", - "free_shuttle": "Colectivo gratuito", - "air": "Avión", - "not_a_trip": "No es un viaje", - "no_travel": "No viajar", - "home": "Inicio", - "work": "Trabajo", - "at_work": "En el trabajo", - "school": "Escuela", - "transit_transfer": "Transbordo", - "shopping": "Compras", - "meal": "Comida", - "pick_drop_person": "Recoger / Entregar Individuo", - "pick_drop_item": "Recoger / Entregar Objeto", - "personal_med": "Personal / Médico", - "access_recreation": "Acceder a Recreación", - "exercise": "Recreación / Ejercicio", - "entertainment": "Entretenimiento / Social", - "religious": "Religioso", - "other": "Otros" - } - } + ] } \ No newline at end of file