Skip to content

Commit 3f5a2a5

Browse files
authored
Merge pull request #416 from opentripplanner/dev
Feature Release: July 14, 2021
2 parents ce9d5bf + cad6636 commit 3f5a2a5

17 files changed

+1101
-127
lines changed

Diff for: __tests__/reducers/__snapshots__/create-otp-reducer.js.snap

+2
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,8 @@ Object {
9898
},
9999
"ui": Object {
100100
"diagramLeg": null,
101+
"locale": null,
102+
"localizedMessages": Object {},
101103
"mobileScreen": 1,
102104
"printView": false,
103105
},

Diff for: example-config.yml

+23
Original file line numberDiff line numberDiff line change
@@ -259,6 +259,29 @@ itinerary:
259259
# - WALK
260260
# - BICYCLE
261261

262+
### Language section to override strings.
263+
### Strings can be set globally for all languages (e.g. for strings that are brands/nouns,
264+
### e.g. TriMet's "TransitTracker") or by language.
265+
### The nested structure should be the same as the language files under the i18n folder.
266+
# language:
267+
# allLanguages
268+
# common:
269+
# accessModes:
270+
# bikeshare: Relay Bike
271+
# en-US:
272+
# common:
273+
# accessModes:
274+
# bikeshare: Blue Bike
275+
276+
### Localization section to provide language/locale settings
277+
#localization:
278+
# # An ambient currency should be defined here (defaults to USD).
279+
# # In some components such as DefaultItinerary, we display a cost element
280+
# # that falls back to $0.00 (or its equivalent in the configured ambient currency
281+
# # and in the user-selected locale) if no fare or currency info is available.
282+
# currency: 'USD'
283+
# defaultLocale: 'en-US'
284+
262285
### If using OTP Middleware, you can define the optional phone number options below.
263286
# phoneFormatOptions:
264287
# # ISO 2-letter country code for phone number formats (defaults to 'US')

Diff for: example.js

+24-3
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import {
2222
DefaultItinerary,
2323
DefaultMainPanel,
2424
FieldTripWindows,
25+
// GtfsRtVehicleOverlay,
2526
MailablesWindow,
2627
MobileResultsScreen,
2728
MobileSearchScreen,
@@ -70,6 +71,26 @@ const TermsOfStorage = () => (
7071
</>
7172
)
7273

74+
// Define custom map overlays.
75+
// customMapOverlays can be a single overlay element or an array of such elements.
76+
// Each overlay must include a name prop (and a key prop if wrapping in an array).
77+
// (Wrapping the overlays inside a React Fragment <> or other component will not work.)
78+
const customMapOverlays = [
79+
// Uncomment the code below and change props to add GTFS-rt overlays.
80+
// <GtfsRtVehicleOverlay
81+
// key='custom1'
82+
// liveFeedUrl='https://gtfs-rt.example.com/feed1.pb'
83+
// name='GTFS-rt Example Vehicles 1'
84+
// />,
85+
// <GtfsRtVehicleOverlay
86+
// key='custom2'
87+
// liveFeedUrl='https://gtfs-rt.example.com/feed2.pb'
88+
// name='GTFS-rt Example Vehicles 2'
89+
// routeDefinitionUrl='https://gtfs-rt.example.com/routes.json'
90+
// visible
91+
// />
92+
]
93+
7394
// define some application-wide components that should be used in
7495
// various places. The following components can be provided here:
7596
// - defaultMobileTitle (required)
@@ -86,8 +107,8 @@ const TermsOfStorage = () => (
86107
// - TermsOfService (required if otpConfig.persistence.strategy === 'otp_middleware')
87108
// - TermsOfStorage (required if otpConfig.persistence.strategy === 'otp_middleware')
88109
const components = {
89-
90110
defaultMobileTitle: () => <div className='navbar-title'>OpenTripPlanner</div>,
111+
getCustomMapOverlays: () => customMapOverlays,
91112
/**
92113
* Example of a custom route label provider to pass to @opentripplanner/core-utils/map#itineraryToTransitive.
93114
* @param {*} itineraryLeg The OTP itinerary leg for which to obtain a custom route label.
@@ -140,8 +161,8 @@ const store = createStore(
140161
combineReducers({
141162
callTaker: createCallTakerReducer(otpConfig),
142163
otp: createOtpReducer(otpConfig),
143-
user: createUserReducer(),
144-
router: connectRouter(history)
164+
router: connectRouter(history),
165+
user: createUserReducer()
145166
}),
146167
compose(applyMiddleware(...middleware))
147168
)

Diff for: i18n/en-US.yml

+65
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
_id: en-US
2+
_name: English
3+
4+
# This file contains localized strings (a.k.a. messages) for the language indicated above:
5+
# - Messages are organized in various categories and sub-categories.
6+
# - A component or JS module can use messages from one or more categories.
7+
# - In the code, messages are retrieved using an ID that is simply the path to the message.
8+
# Use the dot '.' to separate categories and sub-categories in the path.
9+
# For instance, for the message defined in YML below:
10+
# common
11+
# otpTransitModes
12+
# subway: Metro#
13+
# then use the snippet below with the corresponding message id:
14+
# <FormattedMessage id='common.otpTransitModes.subway' /> // renders "Metro".
15+
#
16+
# It is important that message ids in the code be consistent with
17+
# the categories in this file. Below are some general guidelines:
18+
# - For starters, there is a 'components' category and a 'common' category.
19+
# Additional categories may be added as needed.
20+
# - Each sub-category under 'components' denotes a component and
21+
# should contain messages that are used only by that component (e.g. button captions).
22+
# - In contrast, some strings are common to multiple components,
23+
# so it makes sense to group them by theme (e.g. accessModes) under the 'common' category.
24+
25+
26+
# Component-specific messages (e.g. button captions)
27+
# are defined for each component under the 'components' category.
28+
components:
29+
DefaultItinerary:
30+
clickDetails: Click to view details
31+
# Use ordered placeholders for the departure-arrival string
32+
# (this will accommodate right-to-left languages by swapping the order in this string).
33+
departureArrivalTimes: "{startTime}—{endTime}"
34+
# Use ordered placeholders when multiple modes are involved
35+
# (this will accommodate right-to-left languages by swapping the order/separator in this string).
36+
multiModeSummary: "{accessMode} to {transitMode}"
37+
# If trip is less than one hour only display the minutes.
38+
tripDurationFormatZeroHours: "{minutes, number} min"
39+
# TODO: Distinguish between one hour (singular) and 2 hours or more?
40+
tripDurationFormat: "{hours, number} hr {minutes, number} min"
41+
42+
# Common messages that appear in multiple components and modules
43+
# are grouped below by topic.
44+
common:
45+
# OTP access modes
46+
accessModes:
47+
bike: Bike
48+
bikeshare: Bikeshare
49+
drive: Drive
50+
micromobility: E-Scooter
51+
micromobilityRent: Rental E-Scooter
52+
walk: Walk
53+
54+
# OTP transit modes
55+
# Note that identifiers are OTP modes converted to lowercase.
56+
otpTransitModes:
57+
tram: Streetcar
58+
subway: Subway
59+
rail: Rail
60+
bus: Bus
61+
ferry: Ferry
62+
# The original OTP mode id is CABLE_CAR. Lowercase makes it cable_car.
63+
cable_car: Cable Car
64+
gondola: Gondola
65+
funicular: Funicular

Diff for: i18n/fr-FR.yml

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
_id: fr-FR
2+
_name: Unofficial French Translations!
3+
4+
components:
5+
DefaultItinerary:
6+
clickDetails: Cliquez pour afficher les détails
7+
departureArrivalTimes: "{startTime}—{endTime}"
8+
multiModeSummary: "{accessMode} + {transitMode}"
9+
tripDurationFormatZeroHours: "{minutes, number} mn"
10+
tripDurationFormat: "{hours, number} h, {minutes, number} mn"
11+
12+
common:
13+
accessModes:
14+
bike: Vélo
15+
bikeshare: Vélo en libre-service
16+
drive: Voiture
17+
micromobility: Trottinette électrique
18+
micromobilityRent: Trottinette électrique en libre-service
19+
walk: Marche
20+
21+
otpTransitModes:
22+
tram: Tram
23+
subway: Métro
24+
rail: Train
25+
bus: Bus
26+
ferry: Ferry
27+
cable_car: Tram tiré par câble
28+
gondola: Téléphérique
29+
funicular: Funiculaire

Diff for: lib/actions/ui.js

+20
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { createAction } from 'redux-actions'
44
import { matchPath } from 'react-router'
55

66
import { getUiUrlParams } from '../util/state'
7+
import { getDefaultLocale, loadLocaleData } from '../util/i18n'
78

89
import { findRoute, setUrlSearch } from './api'
910
import { setMapCenter, setMapZoom, setRouterId } from './config'
@@ -15,6 +16,8 @@ import {
1516
import { clearLocation } from './map'
1617
import { setActiveItinerary } from './narrative'
1718

19+
const updateLocale = createAction('UPDATE_LOCALE')
20+
1821
/**
1922
* Wrapper function for history#push (or, if specified, replace, etc.)
2023
* that preserves the current search or, if
@@ -312,3 +315,20 @@ export function showMobileSearchScreen () {
312315
dispatch(setMobileScreen(MobileScreens.SEARCH_FORM))
313316
}
314317
}
318+
319+
/**
320+
* Sets the locale to the specified value,
321+
* and loads the corresponding localized messages.
322+
* If the specified locale is null, fall back to the defaultLocale
323+
* set in the configuration.
324+
*/
325+
export function setLocale (locale) {
326+
return async function (dispatch, getState) {
327+
const { config } = getState().otp
328+
const { language: customMessages } = config
329+
const effectiveLocale = locale || getDefaultLocale(config)
330+
const messages = await loadLocaleData(effectiveLocale, customMessages)
331+
332+
dispatch(updateLocale({ locale: effectiveLocale, messages }))
333+
}
334+
}

Diff for: lib/actions/user.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,8 @@ function createNewUser (auth0User) {
3434
notificationChannel: 'email',
3535
phoneNumber: '',
3636
savedLocations: [],
37-
storeTripHistory: false // User must opt in.
37+
storeTripHistory: false, // User must opt in.
38+
use24HourFormat: true
3839
}
3940
}
4041

0 commit comments

Comments
 (0)