Skip to content

Commit

Permalink
Attempt to localize mapbox UI
Browse files Browse the repository at this point in the history
  • Loading branch information
dmytro-gokun committed Nov 12, 2019
1 parent da00339 commit d609cdc
Show file tree
Hide file tree
Showing 7 changed files with 73 additions and 27 deletions.
6 changes: 5 additions & 1 deletion src/ui/control/fullscreen_control.js
Original file line number Diff line number Diff line change
Expand Up @@ -93,11 +93,15 @@ class FullscreenControl {
}

_updateTitle() {
const title = this._isFullscreen() ? "Exit fullscreen" : "Enter fullscreen";
const title = this._getTitle();
this._fullscreenButton.setAttribute("aria-label", title);
this._fullscreenButton.title = title;
}

_getTitle() {
return this._map._getUIString(this._isFullscreen() ? 'FullscreenControl.Exit' : 'FullscreenControl.Enter');
}

_isFullscreen() {
return this._fullscreen;
}
Expand Down
17 changes: 11 additions & 6 deletions src/ui/control/geolocate_control.js
Original file line number Diff line number Diff line change
Expand Up @@ -263,8 +263,9 @@ class GeolocateControl extends Evented {
this._geolocateButton.classList.remove('mapboxgl-ctrl-geolocate-background');
this._geolocateButton.classList.remove('mapboxgl-ctrl-geolocate-background-error');
this._geolocateButton.disabled = true;
this._geolocateButton.title = 'Location not available';
this._geolocateButton.setAttribute('aria-label', 'Location not available');
const title = this._map._getUIString('GeolocateControl.LocationNotAvailable');
this._geolocateButton.title = title;
this._geolocateButton.setAttribute('aria-label', title);

if (this._geolocationWatchID !== undefined) {
this._clearWatch();
Expand Down Expand Up @@ -293,13 +294,17 @@ class GeolocateControl extends Evented {
this._geolocateButton = DOM.create('button', `mapboxgl-ctrl-geolocate`, this._container);
DOM.create('span', `mapboxgl-ctrl-icon`, this._geolocateButton).setAttribute('aria-hidden', true);
this._geolocateButton.type = 'button';
this._geolocateButton.title = 'Find my location';
this._geolocateButton.setAttribute('aria-label', 'Find my location');

if (supported === false) {
warnOnce('Geolocation support is not available so the GeolocateControl will be disabled.');
const title = this._map._getUIString('GeolocateControl.LocationNotAvailable');
this._geolocateButton.disabled = true;
this._geolocateButton.title = 'Location not available';
this._geolocateButton.setAttribute('aria-label', 'Location not available');
this._geolocateButton.title = title;
this._geolocateButton.setAttribute('aria-label', title);
} else {
const title = this._map._getUIString('GeolocateControl.FindMyLocation');
this._geolocateButton.title = title;
this._geolocateButton.setAttribute('aria-label', title);
}

if (this.options.trackUserLocation) {
Expand Down
2 changes: 1 addition & 1 deletion src/ui/control/logo_control.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ class LogoControl {
anchor.target = "_blank";
anchor.rel = "noopener nofollow";
anchor.href = "https://www.mapbox.com/";
anchor.setAttribute("aria-label", "Mapbox logo");
anchor.setAttribute("aria-label", this._map._getUIString('LogoControl.Title'));
anchor.setAttribute("rel", "noopener nofollow");
this._container.appendChild(anchor);
this._container.style.display = 'none';
Expand Down
20 changes: 14 additions & 6 deletions src/ui/control/navigation_control.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,18 +50,19 @@ class NavigationControl {

if (this.options.showZoom) {
bindAll([
'_setButtonTitle',
'_updateZoomButtons'
], this);
this._zoomInButton = this._createButton('mapboxgl-ctrl-zoom-in', 'Zoom in', (e) => this._map.zoomIn({}, {originalEvent: e}));
this._zoomInButton = this._createButton('mapboxgl-ctrl-zoom-in', (e) => this._map.zoomIn({}, {originalEvent: e}));
DOM.create('span', `mapboxgl-ctrl-icon`, this._zoomInButton).setAttribute('aria-hidden', true);
this._zoomOutButton = this._createButton('mapboxgl-ctrl-zoom-out', 'Zoom out', (e) => this._map.zoomOut({}, {originalEvent: e}));
this._zoomOutButton = this._createButton('mapboxgl-ctrl-zoom-out', (e) => this._map.zoomOut({}, {originalEvent: e}));
DOM.create('span', `mapboxgl-ctrl-icon`, this._zoomOutButton).setAttribute('aria-hidden', true);
}
if (this.options.showCompass) {
bindAll([
'_rotateCompassArrow'
], this);
this._compass = this._createButton('mapboxgl-ctrl-compass', 'Reset bearing to north', (e) => {
this._compass = this._createButton('mapboxgl-ctrl-compass', (e) => {
if (this.options.visualizePitch) {
this._map.resetNorthPitch({}, {originalEvent: e});
} else {
Expand Down Expand Up @@ -90,10 +91,13 @@ class NavigationControl {
onAdd(map: Map) {
this._map = map;
if (this.options.showZoom) {
this._setButtonTitle(this._zoomInButton, 'ZoomIn');
this._setButtonTitle(this._zoomOutButton, 'ZoomOut');
this._map.on('zoom', this._updateZoomButtons);
this._updateZoomButtons();
}
if (this.options.showCompass) {
this._setButtonTitle(this._compass, 'ResetBearing');
if (this.options.visualizePitch) {
this._map.on('pitch', this._rotateCompassArrow);
}
Expand Down Expand Up @@ -126,14 +130,18 @@ class NavigationControl {
delete this._map;
}

_createButton(className: string, ariaLabel: string, fn: () => mixed) {
_createButton(className: string, fn: () => mixed) {
const a = DOM.create('button', className, this._container);
a.type = 'button';
a.title = ariaLabel;
a.setAttribute('aria-label', ariaLabel);
a.addEventListener('click', fn);
return a;
}

_setButtonTitle(button: HTMLButtonElement, title: string) {
const str = this._map._getUIString('NavigationControl.' + title);
button.title = str;
button.setAttribute('aria-label', str);
}
}

export default NavigationControl;
18 changes: 7 additions & 11 deletions src/ui/control/scale_control.js
Original file line number Diff line number Diff line change
Expand Up @@ -100,27 +100,23 @@ function updateScale(map, container, options) {
const maxFeet = 3.2808 * maxMeters;
if (maxFeet > 5280) {
const maxMiles = maxFeet / 5280;
setScale(container, maxWidth, maxMiles, 'mi');
setScale(container, maxWidth, maxMiles, map._getUIString('ScaleControl.Miles'));
} else {
setScale(container, maxWidth, maxFeet, 'ft');
setScale(container, maxWidth, maxFeet, map._getUIString('ScaleControl.Feet'));
}
} else if (options && options.unit === 'nautical') {
const maxNauticals = maxMeters / 1852;
setScale(container, maxWidth, maxNauticals, 'nm');
setScale(container, maxWidth, maxNauticals, map._getUIString('ScaleControl.NauticalMiles'));
} else if (maxMeters >= 1000) {
setScale(container, maxWidth, maxMeters / 1000, map._getUIString('ScaleControl.Kilometers'));
} else {
setScale(container, maxWidth, maxMeters, 'm');
setScale(container, maxWidth, maxMeters, map._getUIString('ScaleControl.Meters'));
}
}

function setScale(container, maxWidth, maxDistance, unit) {
let distance = getRoundNum(maxDistance);
const distance = getRoundNum(maxDistance);
const ratio = distance / maxDistance;

if (unit === 'm' && distance >= 1000) {
distance = distance / 1000;
unit = 'km';
}

container.style.width = `${maxWidth * ratio}px`;
container.innerHTML = distance + unit;
}
Expand Down
20 changes: 20 additions & 0 deletions src/ui/default_locale.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// @flow

const defaultLocale = {
'FullscreenControl.Enter': 'Enter fullscreen',
'FullscreenControl.Exit': 'Exit fullscreen',
'GeolocateControl.FindMyLocation': 'Find my location',
'GeolocateControl.LocationNotAvailable': 'Location not available',
'LogoControl.Title': 'Mapbox logo',
'NavigationControl.ResetBearing': 'Reset bearing to north',
'NavigationControl.ZoomIn': 'Zoom in',
'NavigationControl.ZoomOut': 'Zoom out',
'ScaleControl.Feet': 'ft',
'ScaleControl.Meters': 'm',
'ScaleControl.Kilometers': 'km',
'ScaleControl.Miles': 'mi',
'ScaleControl.NauticalMiles': 'nm'

};

export default defaultLocale;
17 changes: 15 additions & 2 deletions src/ui/map.js
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ import type DragPanHandler, {DragPanOptions} from './handler/drag_pan';
import type KeyboardHandler from './handler/keyboard';
import type DoubleClickZoomHandler from './handler/dblclick_zoom';
import type TouchZoomRotateHandler from './handler/touch_zoom_rotate';
import defaultLocale from './default_locale';
import type {TaskID} from '../util/task_queue';
import type {Cancelable} from '../types/cancelable';
import type {
Expand Down Expand Up @@ -96,7 +97,8 @@ type MapOptions = {
renderWorldCopies?: boolean,
maxTileCacheSize?: number,
transformRequest?: RequestTransformFunction,
accessToken: string
accessToken: string,
locale?: Object
};

const defaultMinZoom = 0;
Expand Down Expand Up @@ -235,7 +237,7 @@ const defaultOptions = {
* @param {number} [options.fadeDuration=300] Controls the duration of the fade-in/fade-out animation for label collisions, in milliseconds. This setting affects all symbol layers. This setting does not affect the duration of runtime styling transitions or raster tile cross-fading.
* @param {boolean} [options.crossSourceCollisions=true] If `true`, symbols from multiple sources can collide with each other during collision detection. If `false`, collision detection is run separately for the symbols in each source.
* @param {string} [options.accessToken=null] If specified, map will use this token instead of the one defined in mapboxgl.accessToken.
* @param {string} [options.locale=null] A patch to apply to the default localization table for UI strings, e.g. control tooltips. The `locale` object maps namespaced UI string IDs to translated strings in the target language; see `src/ui/default_locale.js` for an example with all supported string IDs. The object may specify all UI strings (thereby adding support for a new translation) or only a subset of strings (thereby patching the default translation table).
* @example
* var map = new mapboxgl.Map({
* container: 'map',
Expand Down Expand Up @@ -293,6 +295,7 @@ class Map extends Camera {
_mapId: number;
_localIdeographFontFamily: string;
_requestManager: RequestManager;
_locale: Object;

/**
* The map's {@link ScrollZoomHandler}, which implements zooming in and out with a scroll wheel or trackpad.
Expand Down Expand Up @@ -374,6 +377,7 @@ class Map extends Camera {
this._renderTaskQueue = new TaskQueue();
this._controls = [];
this._mapId = uniqueId();
this._locale = extend({}, defaultLocale, options.locale);

this._requestManager = new RequestManager(options.transformRequest, options.accessToken);

Expand Down Expand Up @@ -1168,6 +1172,15 @@ class Map extends Camera {
}
}

_getUIString(key: string) {
const str = this._locale[key];
if (str == null) {
throw new Error(`Missing UI string '${key}'`);
}

return str;
}

_updateStyle(style: StyleSpecification | string | null, options?: {diff?: boolean} & StyleOptions) {
if (this.style) {
this.style.setEventedParent(null);
Expand Down

0 comments on commit d609cdc

Please sign in to comment.