Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make the dropdowns for the multi-label also be configurable #945

Open
shankari opened this issue Aug 10, 2023 · 9 comments
Open

Make the dropdowns for the multi-label also be configurable #945

shankari opened this issue Aug 10, 2023 · 9 comments

Comments

@shankari
Copy link
Contributor

We need to also make the list of mode, purpose and replaced mode labels read from the dynamic config?

I know that the CA e-bike program wants to change our defaults, and I suspect that Laos may also want to tweak them.

For example, we currently don't have mopeds/gas powered two-wheelers on the list, but they are huge in Laos (~ 70% of vehicle registrations are "two wheelers"). And today, the Laos team said that the ministry was also strongly pushing electric three-wheelers (e.g. autorickshaw/tuk-tuk) https://en.wikipedia.org/wiki/Auto_rickshaw

@shankari
Copy link
Contributor Author

From @JGreenlee:

So should the dynamic config include the list of modes as well as their translations? Or should we keep translations separately?

@shankari
Copy link
Contributor Author

That's a great question.

  • Related but un-asked question: I think that we should have the list of modes in a separate file (similar to the survey) and not inline in the config
  • the current format for the dropdowns is to have separate files for each language. However, the current format for our dynamic config is to have all languages inline

The second option might be better for the long-term because we do not need to duplicate the emission/energy/MET numbers across the languages.

If possible, it would be good to support the second option now, with a fallback to the existing method for "old style" configs which assume the hardcoded config file location.

@JGreenlee
Copy link

If the list of modes + purposes is kept in a separate file from the dynamic config, and referenced by URL similar to surveys, then it's critical that we implement caching for it.

I think it would be very bad if we had to download that list every time the app is run.

@shankari
Copy link
Contributor Author

Agreed.

To start simple, I think it would be fine to download all supplemental files once during install, similar to the one-time download for the dynamic config. When we do build in the functionality to update the dynamic config, we can update all of them.

The updates are not hard conceptually, but they make backwards compat potentially more challenging, and I would rather deal with them as a separate task that we think about carefully

@JGreenlee
Copy link

Let me check my understanding - how does this example configuration look?

en.json

{
    ...
     "modes": {
        "walk": "Walk",
        "bike": "Bike",
        "e-bike": "e-bike",
        "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",
        "taxi": "Taxi/Uber/Lyft",
        "bus": "Bus",
        "train": "Train",
        "free_shuttle": "Free Shuttle",
        "air": "Air",
        "other": "Other"
    },
    "purposes": {
        "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"
    }
    ...
}

ca-ebike.nrel-op.json

{
  ...
    "label_options": "https://raw.githubusercontent.com/e-mission/nrel-openpath-deploy-configs/main/label_options/ca-ebike-label_options.json"
  ...
}

ca-ebike-label_options.json

{
    "modes": [
        {"key":"walk", "met_equivalent": "WALKING", "co2PerMeter": 0},
        {"key":"bike", "met_equivalent": "BICYCLING", "co2PerMeter": 0},
        {"key":"e-bike", "met": {"ALL": {"range": [0, -1], "mets": 4.9}}, "co2PerMeter": 0.00728},
        {"key":"scootershare", "met_equivalent": "IN_VEHICLE", "co2PerMeter": 0.00894},
        {"key":"drove_alone", "met_equivalent": "IN_VEHICLE", "co2PerMeter": 0.22031},
        {"key":"shared_ride", "met_equivalent": "IN_VEHICLE", "co2PerMeter": 0.11015},
        {"key":"e_car_drove_alone", "met_equivalent": "IN_VEHICLE", "co2PerMeter": 0.08216},
        {"key":"e_car_shared_ride", "met_equivalent": "IN_VEHICLE", "co2PerMeter": 0.04108},
        {"key":"taxi", "met_equivalent": "IN_VEHICLE", "co2PerMeter": 0.30741},
        {"key":"bus", "met_equivalent": "IN_VEHICLE", "co2PerMeter": 0.20727},
        {"key":"train", "met_equivalent": "IN_VEHICLE", "co2PerMeter": 0.12256},
        {"key":"free_shuttle", "met_equivalent": "IN_VEHICLE", "co2PerMeter": 0.20727},
        {"key":"air", "met_equivalent": "IN_VEHICLE", "co2PerMeter": 0.09975},
        {"key":"other", "met_equivalent": "UNKNOWN", "co2PerMeter": 0}
    ],
    "purposes" : [
        {"key":"home"},
        {"key":"work"},
        {"key":"at_work"},
        {"key":"school"},
        {"key":"transit_transfer"},
        {"key":"shopping"},
        {"key":"meal"},
        {"key":"pick_drop_person"},
        {"key":"pick_drop_item"},
        {"key":"personal_med"},
        {"key":"access_recreation"},
        {"key":"exercise"},
        {"key":"entertainment"},
        {"key":"religious"},
        {"key":"other"}
    ]
}

@shankari
Copy link
Contributor Author

shankari commented Aug 10, 2023

So I agree with ca-ebike.nrel-op.json and ca-ebike-label_options.json.

However, I think that we should put the text of the translations in ca-ebike-label_options.json as well, just like we put the translated label text for the surveys in the dynamic config.

If we have the translations in en.json, we will have to push out a new release every time a program wants a different mode or purpose included. As we (hopefully) scale, that will no longer be feasible.

Note also that we should support replaced_mode as well. replaced_mode is almost the same as mode, with a few additional entries such as no travel. We should be able to construct it from the mode label list by tacking on those additional entries.

@JGreenlee
Copy link

Like this?

ca-ebike-label_options.json

{
    "modes": [
        {"key":"walk", "met_equivalent": "WALKING", "co2PerMeter": 0},
        {"key":"bike", "met_equivalent": "BICYCLING", "co2PerMeter": 0},
        {"key":"e-bike", "met": {"ALL": {"range": [0, -1], "mets": 4.9}}, "co2PerMeter": 0.00728},
        {"key":"scootershare", "met_equivalent": "IN_VEHICLE", "co2PerMeter": 0.00894},
        {"key":"drove_alone", "met_equivalent": "IN_VEHICLE", "co2PerMeter": 0.22031},
        {"key":"shared_ride", "met_equivalent": "IN_VEHICLE", "co2PerMeter": 0.11015},
        {"key":"e_car_drove_alone", "met_equivalent": "IN_VEHICLE", "co2PerMeter": 0.08216},
        {"key":"e_car_shared_ride", "met_equivalent": "IN_VEHICLE", "co2PerMeter": 0.04108},
        {"key":"taxi", "met_equivalent": "IN_VEHICLE", "co2PerMeter": 0.30741},
        {"key":"bus", "met_equivalent": "IN_VEHICLE", "co2PerMeter": 0.20727},
        {"key":"train", "met_equivalent": "IN_VEHICLE", "co2PerMeter": 0.12256},
        {"key":"free_shuttle", "met_equivalent": "IN_VEHICLE", "co2PerMeter": 0.20727},
        {"key":"air", "met_equivalent": "IN_VEHICLE", "co2PerMeter": 0.09975},
        {"key":"other", "met_equivalent": "UNKNOWN", "co2PerMeter": 0}
    ],
    "replaced_modes": [
        {"key":"no_travel"},
        {"key":"walk"},
        {"key":"bike"},
        {"key":"bikeshare"},
        {"key":"scootershare"},
        {"key":"drove_alone"},
        {"key":"shared_ride"},
        {"key":"e_car_drove_alone"},
        {"key":"e_car_shared_ride"},
        {"key":"taxi"},
        {"key":"bus"},
        {"key":"train"},
        {"key":"free_shuttle"},
        {"key":"other"}
    ],
    "purposes": [
        {"key":"home"},
        {"key":"work"},
        {"key":"at_work"},
        {"key":"school"},
        {"key":"transit_transfer"},
        {"key":"shopping"},
        {"key":"meal"},
        {"key":"pick_drop_person"},
        {"key":"pick_drop_item"},
        {"key":"personal_med"},
        {"key":"access_recreation"},
        {"key":"exercise"},
        {"key":"entertainment"},
        {"key":"religious"},
        {"key":"other"}
    ],
    "translations": {
        "en": {
            "modes": {
                "walk": "Walk",
                "bike": "Bike",
                "e-bike": "e-bike",
                "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",
                "taxi": "Taxi/Uber/Lyft",
                "bus": "Bus",
                "train": "Train",
                "free_shuttle": "Free Shuttle",
                "air": "Air",
                "other": "Other",
                "no_travel": "No travel"
            },
            "purposes": {
                "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": {
            "modes": {
                "walk": "Caminando",
                "bike": "Bicicleta",
                "e-bike": "e-bicicleta",
                ...
            },
            "purposes": {
                "home": "Inicio",
                "work": "Trabajo",
                "at_work": "En el trabajo",
                ...
            }
        }
    }
}

@shankari
Copy link
Contributor Author

That would be fine. We can also put the translations into the entries

{"key":"walk", "met_equivalent": "WALKING", "co2PerMeter": 0, "translations: {"en": ...., "es": ...}},

I will let you pick whichever is easier to implement

JGreenlee added a commit to JGreenlee/e-mission-phone that referenced this issue Aug 18, 2023
This Typescript file will replace the ConfirmHelper service, and also support reading multilabel options from a URL specified in the dynamic config, instead of from separate JSON files (e-mission/e-mission-docs#945). But if label_options is not in the dynamic config, we just fall back to the old method.

This file is type safe :)
@JGreenlee
Copy link

I haven't forgotten about this 😄

In e-mission/e-mission-phone#1014, I rewrote the ConfirmHelper service as a new Typescript file confirmHelper.ts, and it's structured in such a way that it can either read 'label options' from the URL in dynamic config, or it can fallback to the old way (which is internationalized JSON files).

The fallback is at least working the same as before. I haven't tested dynamic label options yet, but I will be trying it out tomorrow with the following example configs (I slightly changed the fields to be more consistent with the fallback method)

Study:

{
  "MODE": [
    {"key":"walk", "met_equivalent": "WALKING", "co2PerMeter": 0},
    {"key":"bike", "met_equivalent": "BICYCLING", "co2PerMeter": 0},
    {"key":"e-bike", "met": {"ALL": {"range": [0, -1], "mets": 4.9}}, "co2PerMeter": 0.00728},
    {"key":"scootershare", "met_equivalent": "IN_VEHICLE", "co2PerMeter": 0.00894},
    {"key":"drove_alone", "met_equivalent": "IN_VEHICLE", "co2PerMeter": 0.22031},
    {"key":"shared_ride", "met_equivalent": "IN_VEHICLE", "co2PerMeter": 0.11015},
    {"key":"e_car_drove_alone", "met_equivalent": "IN_VEHICLE", "co2PerMeter": 0.08216},
    {"key":"e_car_shared_ride", "met_equivalent": "IN_VEHICLE", "co2PerMeter": 0.04108},
    {"key":"taxi", "met_equivalent": "IN_VEHICLE", "co2PerMeter": 0.30741},
    {"key":"bus", "met_equivalent": "IN_VEHICLE", "co2PerMeter": 0.20727},
    {"key":"train", "met_equivalent": "IN_VEHICLE", "co2PerMeter": 0.12256},
    {"key":"free_shuttle", "met_equivalent": "IN_VEHICLE", "co2PerMeter": 0.20727},
    {"key":"air", "met_equivalent": "IN_VEHICLE", "co2PerMeter": 0.09975},
    {"key":"other", "met_equivalent": "UNKNOWN", "co2PerMeter": 0}
  ],
  "PURPOSE": [
    {"key":"home"},
    {"key":"work"},
    {"key":"at_work"},
    {"key":"school"},
    {"key":"transit_transfer"},
    {"key":"shopping"},
    {"key":"meal"},
    {"key":"pick_drop_person"},
    {"key":"pick_drop_item"},
    {"key":"personal_med"},
    {"key":"access_recreation"},
    {"key":"exercise"},
    {"key":"entertainment"},
    {"key":"religious"},
    {"key":"other"}
  ],
  "translations": {
    "en": {
      "walk": "Walk",
      "bike": "Bike",
      "e-bike": "e-bike",
      "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",
      "taxi": "Taxi/Uber/Lyft",
      "bus": "Bus",
      "train": "Train",
      "free_shuttle": "Free Shuttle",
      "air": "Air",
      "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",
      "bike": "Bicicleta",
      "e-bike": "e-bicicleta",
      "home": "Inicio",
      "work": "Trabajo",
      "at_work": "En el trabajo",
      ...
    }
  }
}

Program:

{
  "MODE": [
    {"key":"walk", "met_equivalent": "WALKING", "co2PerMeter": 0},
    {"key":"bike", "met_equivalent": "BICYCLING", "co2PerMeter": 0},
    {"key":"e-bike", "met": {"ALL": {"range": [0, -1], "mets": 4.9}}, "co2PerMeter": 0.00728},
    {"key":"scootershare", "met_equivalent": "IN_VEHICLE", "co2PerMeter": 0.00894},
    {"key":"drove_alone", "met_equivalent": "IN_VEHICLE", "co2PerMeter": 0.22031},
    {"key":"shared_ride", "met_equivalent": "IN_VEHICLE", "co2PerMeter": 0.11015},
    {"key":"e_car_drove_alone", "met_equivalent": "IN_VEHICLE", "co2PerMeter": 0.08216},
    {"key":"e_car_shared_ride", "met_equivalent": "IN_VEHICLE", "co2PerMeter": 0.04108},
    {"key":"taxi", "met_equivalent": "IN_VEHICLE", "co2PerMeter": 0.30741},
    {"key":"bus", "met_equivalent": "IN_VEHICLE", "co2PerMeter": 0.20727},
    {"key":"train", "met_equivalent": "IN_VEHICLE", "co2PerMeter": 0.12256},
    {"key":"free_shuttle", "met_equivalent": "IN_VEHICLE", "co2PerMeter": 0.20727},
    {"key":"air", "met_equivalent": "IN_VEHICLE", "co2PerMeter": 0.09975},
    {"key":"other", "met_equivalent": "UNKNOWN", "co2PerMeter": 0}
  ],
  "PURPOSE": [
    {"key":"home"},
    {"key":"work"},
    {"key":"at_work"},
    {"key":"school"},
    {"key":"transit_transfer"},
    {"key":"shopping"},
    {"key":"meal"},
    {"key":"pick_drop_person"},
    {"key":"pick_drop_item"},
    {"key":"personal_med"},
    {"key":"access_recreation"},
    {"key":"exercise"},
    {"key":"entertainment"},
    {"key":"religious"},
    {"key":"other"}
  ],
  "REPLACED_MODE": [
    {"key":"no_travel"},
    {"key":"walk"},
    {"key":"bike"},
    {"key":"bikeshare"},
    {"key":"scootershare"},
    {"key":"drove_alone"},
    {"key":"shared_ride"},
    {"key":"e_car_drove_alone"},
    {"key":"e_car_shared_ride"},
    {"key":"taxi"},
    {"key":"bus"},
    {"key":"train"},
    {"key":"free_shuttle"},
    {"key":"other"}
  ],
  "translations": {
    "en": {
      "walk": "Walk",
      "bike": "Bike",
      "e-bike": "e-bike",
      "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",
      "taxi": "Taxi/Uber/Lyft",
      "bus": "Bus",
      "train": "Train",
      "free_shuttle": "Free Shuttle",
      "air": "Air",
      "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",
      "bike": "Bicicleta",
      "e-bike": "e-bicicleta",
      ...
      "home": "Inicio",
      "work": "Trabajo",
      "at_work": "En el trabajo",
      ...
    }
  }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants