Places: Display map in UI language #1391
This commit is contained in:
parent
68dbcf4039
commit
8577202b0a
4 changed files with 187 additions and 11 deletions
|
@ -54,8 +54,8 @@ import VueFilters from "vue2-filters";
|
|||
import VueFullscreen from "vue-fullscreen";
|
||||
import VueInfiniteScroll from "vue-infinite-scroll";
|
||||
import Hls from "hls.js";
|
||||
import "common/maptiler-lang";
|
||||
import { $gettext, Mount } from "common/vm";
|
||||
import * as options from "options/options";
|
||||
import * as offline from "@lcdp/offline-plugin/runtime";
|
||||
|
||||
// Initialize helpers
|
||||
|
@ -68,8 +68,8 @@ const isMobile =
|
|||
// Initialize language and detect alignment
|
||||
Vue.config.language = config.values.settings.ui.language;
|
||||
Settings.defaultLocale = Vue.config.language.substring(0, 2);
|
||||
const languages = options.Languages();
|
||||
const rtl = languages.some((lang) => lang.value === Vue.config.language && lang.rtl);
|
||||
// Detect right-to-left languages such as Arabic and Hebrew
|
||||
const rtl = config.rtl();
|
||||
|
||||
// Get initial theme colors from config
|
||||
const theme = config.theme.colors;
|
||||
|
|
|
@ -32,6 +32,7 @@ import Event from "pubsub-js";
|
|||
import themes from "options/themes.json";
|
||||
import translations from "locales/translations.json";
|
||||
import Api from "./api";
|
||||
import { Languages } from "options/options";
|
||||
|
||||
export default class Config {
|
||||
/**
|
||||
|
@ -311,6 +312,14 @@ export default class Config {
|
|||
return this.values.settings;
|
||||
}
|
||||
|
||||
rtl() {
|
||||
if (!this.values || !this.values.settings || !this.values.settings.ui.language) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return Languages().some((lang) => lang.value === this.values.settings.ui.language && lang.rtl);
|
||||
}
|
||||
|
||||
downloadToken() {
|
||||
return this.values["downloadToken"];
|
||||
}
|
||||
|
|
174
frontend/src/common/maptiler-lang.js
Normal file
174
frontend/src/common/maptiler-lang.js
Normal file
|
@ -0,0 +1,174 @@
|
|||
/* @preserve
|
||||
* https://github.com/klokantech/openmaptiles-language
|
||||
* (c) 2018 Klokan Technologies GmbH
|
||||
*/
|
||||
import mapboxgl from "mapbox-gl";
|
||||
import { config } from "../session";
|
||||
|
||||
const langFallbackDecorate = function (style, cfg) {
|
||||
let layers = style.layers;
|
||||
let lf = cfg["layer-filter"];
|
||||
let decorators = cfg["decorators"];
|
||||
let lfProp = lf[1];
|
||||
let lfValues = lf.slice(2);
|
||||
|
||||
for (let i = layers.length - 1; i >= 0; i--) {
|
||||
let layer = layers[i];
|
||||
if (
|
||||
!(
|
||||
lf[0] === "in" &&
|
||||
lfProp === "layout.text-field" &&
|
||||
layer.layout &&
|
||||
layer.layout["text-field"] &&
|
||||
lfValues.indexOf(layer.layout["text-field"]) >= 0
|
||||
)
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
for (let j = decorators.length - 1; j >= 0; j--) {
|
||||
let decorator = decorators[j];
|
||||
let postfix = decorator["layer-name-postfix"] || "";
|
||||
postfix = postfix.replace(/(^-+|-+$)/g, "");
|
||||
let newLayer;
|
||||
if (j > 0) {
|
||||
newLayer = JSON.parse(JSON.stringify(layer));
|
||||
layers.splice(i + 1, 0, newLayer);
|
||||
} else {
|
||||
newLayer = layer;
|
||||
}
|
||||
newLayer.id += postfix ? "-" + postfix : "";
|
||||
newLayer.layout["text-field"] = decorator["layout.text-field"];
|
||||
if (newLayer.layout["symbol-placement"] === "line") {
|
||||
newLayer.layout["text-field"] = newLayer.layout["text-field"].replace("\n", " ");
|
||||
}
|
||||
let filterPart = decorator["filter-all-part"].concat();
|
||||
if (!newLayer.filter) {
|
||||
newLayer.filter = filterPart;
|
||||
} else if (newLayer.filter[0] === "all") {
|
||||
newLayer.filter.push(filterPart);
|
||||
} else {
|
||||
newLayer.filter = ["all", newLayer.filter, filterPart];
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
let langEnabled = true;
|
||||
|
||||
let setStyleMutex = false;
|
||||
let origSetStyle = mapboxgl.Map.prototype.setStyle;
|
||||
mapboxgl.Map.prototype.setStyle = function () {
|
||||
origSetStyle.apply(this, arguments);
|
||||
|
||||
if (langEnabled && !setStyleMutex) {
|
||||
if (this.styleUndecorated) {
|
||||
this.styleUndecorated = undefined;
|
||||
}
|
||||
this.once(
|
||||
"styledata",
|
||||
function () {
|
||||
if (this.languageOptions) {
|
||||
this.setLanguage(this.languageOptions.language, this.languageOptions.noAlt);
|
||||
}
|
||||
}.bind(this)
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
mapboxgl.Map.prototype.setLanguageEnabled = function (enable) {
|
||||
langEnabled = enable;
|
||||
};
|
||||
|
||||
mapboxgl.Map.prototype.setLanguage = function (language, noAlt) {
|
||||
this.languageOptions = {
|
||||
language: language,
|
||||
noAlt: noAlt,
|
||||
};
|
||||
if (!this.styleUndecorated) {
|
||||
try {
|
||||
this.styleUndecorated = this.getStyle();
|
||||
} catch (e) {
|
||||
// Ignore.
|
||||
}
|
||||
}
|
||||
if (!this.styleUndecorated) {
|
||||
return;
|
||||
}
|
||||
|
||||
let isNonlatin =
|
||||
[
|
||||
"ar",
|
||||
"hy",
|
||||
"be",
|
||||
"bg",
|
||||
"zh",
|
||||
"ka",
|
||||
"el",
|
||||
"he",
|
||||
"ja",
|
||||
"ja_kana",
|
||||
"kn",
|
||||
"kk",
|
||||
"ko",
|
||||
"mk",
|
||||
"ru",
|
||||
"sr",
|
||||
"th",
|
||||
"uk",
|
||||
].indexOf(language) >= 0;
|
||||
|
||||
let style = JSON.parse(JSON.stringify(this.styleUndecorated));
|
||||
let langCfg = {
|
||||
"layer-filter": [
|
||||
"in",
|
||||
"layout.text-field",
|
||||
"{name}",
|
||||
"{name_de}",
|
||||
"{name_en}",
|
||||
"{name:latin}",
|
||||
"{name:latin} {name:nonlatin}",
|
||||
"{name:latin}\n{name:nonlatin}",
|
||||
],
|
||||
decorators: [
|
||||
{
|
||||
"layout.text-field": isNonlatin
|
||||
? "{name:nonlatin}" + (noAlt ? "" : "\n{name:latin}")
|
||||
: "{name:latin}" + (noAlt ? "" : "\n{name:nonlatin}"),
|
||||
"filter-all-part": ["!has", "name:" + language],
|
||||
},
|
||||
{
|
||||
"layer-name-postfix": language,
|
||||
"layout.text-field":
|
||||
"{name:" +
|
||||
language +
|
||||
"}" +
|
||||
(noAlt ? "" : "\n{name:" + (isNonlatin ? "latin" : "nonlatin") + "}"),
|
||||
"filter-all-part": ["has", "name:" + language],
|
||||
},
|
||||
],
|
||||
};
|
||||
if (language === "native") {
|
||||
langCfg["decorators"] = [
|
||||
{
|
||||
"layout.text-field": "{name}",
|
||||
"filter-all-part": ["all"],
|
||||
},
|
||||
];
|
||||
}
|
||||
langFallbackDecorate(style, langCfg);
|
||||
|
||||
setStyleMutex = true;
|
||||
this.setStyle(style);
|
||||
setStyleMutex = false;
|
||||
};
|
||||
|
||||
mapboxgl.Map.prototype.autodetectLanguage = function (opt_fallback) {
|
||||
this.setLanguage(config.values.settings.ui.language.split("-")[0] || opt_fallback || "native");
|
||||
};
|
||||
|
||||
// See https://docs.mapbox.com/mapbox-gl-js/example/mapbox-gl-rtl-text/
|
||||
mapboxgl.setRTLTextPlugin(
|
||||
`${config.staticUri}/plugins/mapbox-gl-rtl-text/v0.2.3/mapbox-gl-rtl-text.js`,
|
||||
null,
|
||||
true // Lazy load the plugin
|
||||
);
|
|
@ -272,15 +272,8 @@ export default {
|
|||
}).catch(() => this.loading = false);
|
||||
},
|
||||
renderMap() {
|
||||
// In case of facing RTL language on the map, this plugin will be fetched (only by lazy!) and will set RTL properly support.
|
||||
// See mapbox documentation here https://docs.mapbox.com/mapbox-gl-js/example/mapbox-gl-rtl-text/
|
||||
mapboxgl.setRTLTextPlugin(
|
||||
`${this.$config.staticUri}/plugins/mapbox-gl-rtl-text/v0.2.3/mapbox-gl-rtl-text.js`,
|
||||
null,
|
||||
true // Lazy load the plugin
|
||||
);
|
||||
|
||||
this.map = new mapboxgl.Map(this.options);
|
||||
this.map.setLanguage(this.$config.values.settings.ui.language.split("-")[0]);
|
||||
|
||||
this.map.addControl(new mapboxgl.NavigationControl({showCompass: true}, 'top-right'));
|
||||
this.map.addControl(new mapboxgl.FullscreenControl({container: document.querySelector('body')}));
|
||||
|
|
Loading…
Reference in a new issue