@panoramax/web-viewer 3.0.2-develop-a8ea8e60-develop-f1bb641f → 3.1.0-develop-537ffe27
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +6 -0
- package/build/index.js +1 -1
- package/build/index.js.map +1 -1
- package/docs/05_Compatibility.md +14 -0
- package/package.json +1 -1
- package/src/utils/I18n.js +13 -6
- package/src/utils/Map.js +42 -1
- package/tests/components/Map.test.js +2 -1
- package/tests/utils/I18n.test.js +84 -1
package/docs/05_Compatibility.md
CHANGED
|
@@ -83,3 +83,17 @@ A supplementary layer _grid_ can be made available for low-zoom overview:
|
|
|
83
83
|
|
|
84
84
|
- Available on zoom levels < 6
|
|
85
85
|
- Available properties: `id` (grid cell ID), `nb_pictures` (amount of pictures), `coef` (value from 0 to 1, relative quantity of available pictures)
|
|
86
|
+
|
|
87
|
+
### Labels translation
|
|
88
|
+
|
|
89
|
+
If your vector tiles support multiple languages, you can set in your `style.json` the list of supported languages :
|
|
90
|
+
|
|
91
|
+
```json
|
|
92
|
+
{
|
|
93
|
+
"metadata": {
|
|
94
|
+
"panoramax:locales": ["fr", "en", "latin"]
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
The viewer will try to find the best matching `name:LANG` property according to user browser settings.
|
package/package.json
CHANGED
package/src/utils/I18n.js
CHANGED
|
@@ -10,7 +10,13 @@ const TRANSLATIONS = {
|
|
|
10
10
|
"de": T_de, "en": T_en, "es": T_es, "fr": T_fr, "hu": T_hu, "zh_Hant": T_zh_Hant,
|
|
11
11
|
};
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
/**
|
|
14
|
+
* Find best matching language regarding of list of supported languages and browser accepted languages
|
|
15
|
+
* @param {str[]} supportedTranslations List of supported languages
|
|
16
|
+
* @param {str} fallback The fallback language
|
|
17
|
+
* @returns The best matching language
|
|
18
|
+
*/
|
|
19
|
+
export function autoDetectLocale(supportedTranslations, fallback) { // eslint-ignore import/no-unused-modules
|
|
14
20
|
for (const navigatorLang of window.navigator.languages) {
|
|
15
21
|
let language = navigatorLang;
|
|
16
22
|
// Convert browser code to weblate code
|
|
@@ -30,13 +36,14 @@ const autoDetectLocale = () => {
|
|
|
30
36
|
}
|
|
31
37
|
break;
|
|
32
38
|
}
|
|
33
|
-
const pair =
|
|
39
|
+
const pair = supportedTranslations.find((pair) => pair === language);
|
|
34
40
|
if (pair) {
|
|
35
|
-
return pair
|
|
41
|
+
return pair;
|
|
36
42
|
}
|
|
37
43
|
}
|
|
38
|
-
return
|
|
39
|
-
}
|
|
44
|
+
return fallback;
|
|
45
|
+
}
|
|
46
|
+
|
|
40
47
|
/**
|
|
41
48
|
* Get text labels translations in given language
|
|
42
49
|
*
|
|
@@ -50,7 +57,7 @@ export function getTranslations(lang = "") {
|
|
|
50
57
|
|
|
51
58
|
// No specific lang set -> use browser lang
|
|
52
59
|
if(!lang) {
|
|
53
|
-
lang = autoDetectLocale();
|
|
60
|
+
lang = autoDetectLocale(Object.keys(TRANSLATIONS), FALLBACK_LOCALE);
|
|
54
61
|
}
|
|
55
62
|
|
|
56
63
|
// Lang exists -> send it
|
package/src/utils/Map.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import maplibregl from "!maplibre-gl";
|
|
3
3
|
import LoaderImg from "../img/marker.svg";
|
|
4
4
|
import { COLORS } from "./Utils";
|
|
5
|
+
import { autoDetectLocale } from "./I18n";
|
|
5
6
|
|
|
6
7
|
export const DEFAULT_TILES = "https://panoramax.openstreetmap.fr/pmtiles/basic.json";
|
|
7
8
|
export const RASTER_LAYER_ID = "gvs-aerial";
|
|
@@ -152,7 +153,47 @@ export function combineStyles(parent, options) {
|
|
|
152
153
|
}
|
|
153
154
|
}
|
|
154
155
|
});
|
|
155
|
-
|
|
156
|
+
|
|
157
|
+
// TODO : remove override once available in default Panoramax style
|
|
158
|
+
if(!style.metadata["panoramax:locales"]) {
|
|
159
|
+
style.metadata["panoramax:locales"] = ["fr", "en", "de", "es", "ru", "pt", "zh", "hi", "latin"];
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// Override labels to use appropriate language
|
|
163
|
+
if(style.metadata["panoramax:locales"]) {
|
|
164
|
+
const prefLang = autoDetectLocale(style.metadata["panoramax:locales"], "latin");
|
|
165
|
+
style.layers.forEach(l => {
|
|
166
|
+
if(isLabelLayer(l) && l.layout["text-field"].includes("name:latin")) {
|
|
167
|
+
l.layout["text-field"] = [
|
|
168
|
+
"coalesce",
|
|
169
|
+
["get", `name:${prefLang}`],
|
|
170
|
+
["get", "name:latin"],
|
|
171
|
+
["get", "name"]
|
|
172
|
+
];
|
|
173
|
+
}
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// Fix for capital cities
|
|
178
|
+
const citiesLayer = style.layers.find(l => l.id == "place_label_city");
|
|
179
|
+
let capitalLayer = style.layers.find(l => l.id == "place_label_capital");
|
|
180
|
+
if(citiesLayer && !capitalLayer) {
|
|
181
|
+
// Create capital layer from original city style
|
|
182
|
+
capitalLayer = JSON.parse(JSON.stringify(citiesLayer));
|
|
183
|
+
capitalLayer.id = "place_label_capital";
|
|
184
|
+
capitalLayer.filter.push(["<=", "capital", 2]);
|
|
185
|
+
|
|
186
|
+
// Edit original city to make it less import
|
|
187
|
+
citiesLayer.filter.push([">", "capital", 2]);
|
|
188
|
+
citiesLayer.paint = {
|
|
189
|
+
"text-color": "hsl(0,0%,15%)",
|
|
190
|
+
"text-halo-blur": 0.5,
|
|
191
|
+
"text-halo-color": "hsl(0,0%,100%)",
|
|
192
|
+
"text-halo-width": 0.8,
|
|
193
|
+
};
|
|
194
|
+
style.layers.push(capitalLayer);
|
|
195
|
+
}
|
|
196
|
+
|
|
156
197
|
return style;
|
|
157
198
|
}
|
|
158
199
|
|
|
@@ -26,6 +26,7 @@ jest.mock("maplibre-gl", () => ({
|
|
|
26
26
|
return {
|
|
27
27
|
layers: [],
|
|
28
28
|
sources: {},
|
|
29
|
+
metadata: {},
|
|
29
30
|
};
|
|
30
31
|
}
|
|
31
32
|
resize() {;}
|
|
@@ -52,7 +53,7 @@ const createParent = () => ({
|
|
|
52
53
|
getDataBbox: jest.fn(),
|
|
53
54
|
getPicturesTilesUrl: jest.fn(),
|
|
54
55
|
_getMapRequestTransform: jest.fn(),
|
|
55
|
-
getMapStyle: () => ({ sources: {}, layers: [] }),
|
|
56
|
+
getMapStyle: () => ({ sources: {}, layers: [], metadata: {} }),
|
|
56
57
|
},
|
|
57
58
|
_t: {
|
|
58
59
|
maplibre: {},
|
package/tests/utils/I18n.test.js
CHANGED
|
@@ -1,4 +1,87 @@
|
|
|
1
|
-
import { getTranslations } from "../../src/utils/I18n";
|
|
1
|
+
import { autoDetectLocale, getTranslations } from "../../src/utils/I18n";
|
|
2
|
+
|
|
3
|
+
describe("autoDetectLocale", () => {
|
|
4
|
+
// Mock the window.navigator.languages
|
|
5
|
+
const originalNavigatorLanguages = window.navigator.languages;
|
|
6
|
+
|
|
7
|
+
afterEach(() => {
|
|
8
|
+
// Reset window.navigator.languages after each test
|
|
9
|
+
Object.defineProperty(window.navigator, "languages", {
|
|
10
|
+
value: originalNavigatorLanguages,
|
|
11
|
+
configurable: true
|
|
12
|
+
});
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
it("returns matched language from supportedTranslations", () => {
|
|
16
|
+
Object.defineProperty(window.navigator, "languages", {
|
|
17
|
+
value: ["fr-FR", "en-US"],
|
|
18
|
+
configurable: true
|
|
19
|
+
});
|
|
20
|
+
const supportedTranslations = ["en", "fr", "es"];
|
|
21
|
+
const fallback = "en";
|
|
22
|
+
expect(autoDetectLocale(supportedTranslations, fallback)).toBe("fr");
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
it("returns fallback when no match is found", () => {
|
|
26
|
+
Object.defineProperty(window.navigator, "languages", {
|
|
27
|
+
value: ["de-DE", "it-IT"],
|
|
28
|
+
configurable: true
|
|
29
|
+
});
|
|
30
|
+
const supportedTranslations = ["en", "fr", "es"];
|
|
31
|
+
const fallback = "en";
|
|
32
|
+
expect(autoDetectLocale(supportedTranslations, fallback)).toBe("en");
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
it("returns zh_Hant for Chinese Traditional locales", () => {
|
|
36
|
+
Object.defineProperty(window.navigator, "languages", {
|
|
37
|
+
value: ["zh-TW"],
|
|
38
|
+
configurable: true
|
|
39
|
+
});
|
|
40
|
+
const supportedTranslations = ["zh_Hant", "zh_Hans", "en"];
|
|
41
|
+
const fallback = "en";
|
|
42
|
+
expect(autoDetectLocale(supportedTranslations, fallback)).toBe("zh_Hant");
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
it("returns zh_Hans for Chinese Simplified locales", () => {
|
|
46
|
+
Object.defineProperty(window.navigator, "languages", {
|
|
47
|
+
value: ["zh-CN"],
|
|
48
|
+
configurable: true
|
|
49
|
+
});
|
|
50
|
+
const supportedTranslations = ["zh_Hant", "zh_Hans", "en"];
|
|
51
|
+
const fallback = "en";
|
|
52
|
+
expect(autoDetectLocale(supportedTranslations, fallback)).toBe("zh_Hans");
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
it("returns first matched language even when navigator language has region", () => {
|
|
56
|
+
Object.defineProperty(window.navigator, "languages", {
|
|
57
|
+
value: ["fr-CA", "en-US"],
|
|
58
|
+
configurable: true
|
|
59
|
+
});
|
|
60
|
+
const supportedTranslations = ["fr", "en"];
|
|
61
|
+
const fallback = "en";
|
|
62
|
+
expect(autoDetectLocale(supportedTranslations, fallback)).toBe("fr");
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
it("returns fallback when supportedTranslations is empty", () => {
|
|
66
|
+
Object.defineProperty(window.navigator, "languages", {
|
|
67
|
+
value: ["fr-FR"],
|
|
68
|
+
configurable: true
|
|
69
|
+
});
|
|
70
|
+
const supportedTranslations = [];
|
|
71
|
+
const fallback = "en";
|
|
72
|
+
expect(autoDetectLocale(supportedTranslations, fallback)).toBe("en");
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
it("handles language codes with more than two characters", () => {
|
|
76
|
+
Object.defineProperty(window.navigator, "languages", {
|
|
77
|
+
value: ["pt-BR", "en-US"],
|
|
78
|
+
configurable: true
|
|
79
|
+
});
|
|
80
|
+
const supportedTranslations = ["pt", "en"];
|
|
81
|
+
const fallback = "en";
|
|
82
|
+
expect(autoDetectLocale(supportedTranslations, fallback)).toBe("pt");
|
|
83
|
+
});
|
|
84
|
+
});
|
|
2
85
|
|
|
3
86
|
describe("getTranslations", () => {
|
|
4
87
|
it("works with default lang", () => {
|