Skip to content

Commit 81ee4f7

Browse files
authored
Optimize StyleInterface.localizeLabels (#2178)
* Optimize StyleInterface.localizeLabels * minor * changelog * change locale per layer if needed * PR fixes * PR fixes * Optimize further * Go even in DEEPER optimization * minor PR fix * PR fix * changelog
1 parent b953849 commit 81ee4f7

File tree

2 files changed

+80
-53
lines changed

2 files changed

+80
-53
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,9 @@
22

33
Mapbox welcomes participation and contributions from everyone.
44

5+
# 10.16.4
6+
## ## Features ✨ and improvements 🏁
7+
* Improve performance of `StyleInterface.localizeLabels` method.
58

69
# 10.16.3 December 08, 2023
710
## Bug fixes 🐞

extension-localization/src/main/java/com/mapbox/maps/extension/localization/Localization.kt

Lines changed: 77 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,9 @@
11
package com.mapbox.maps.extension.localization
22

3-
import com.mapbox.maps.StyleObjectInfo
3+
import com.mapbox.bindgen.Value
4+
import com.mapbox.maps.StylePropertyValueKind
45
import com.mapbox.maps.extension.style.StyleInterface
56
import com.mapbox.maps.extension.style.expressions.dsl.generated.get
6-
import com.mapbox.maps.extension.style.expressions.generated.Expression
7-
import com.mapbox.maps.extension.style.layers.generated.SymbolLayer
8-
import com.mapbox.maps.extension.style.layers.getLayerAs
9-
import com.mapbox.maps.extension.style.sources.generated.VectorSource
10-
import com.mapbox.maps.extension.style.sources.getSourceAs
117
import com.mapbox.maps.logE
128
import com.mapbox.maps.logI
139
import java.util.*
@@ -20,70 +16,98 @@ import java.util.*
2016
* `["format",["coalesce",["get","name_de"],["get","name"]],{}]`
2117
*/
2218
internal fun setMapLanguage(locale: Locale, style: StyleInterface, layerIds: List<String>?) {
23-
var convertedLocale = "name_${locale.language}"
19+
val convertedLocale = "name_${locale.language}"
2420
if (!isSupportedLanguage(convertedLocale)) {
2521
logE(TAG, "Locale: $locale is not supported.")
2622
return
2723
}
2824

29-
style.styleSources
30-
.forEach { source ->
31-
style.styleLayers
32-
.filter { it.type == LAYER_TYPE_SYMBOL }
33-
.filter { layer ->
34-
layerIds?.contains(layer.id) ?: true
35-
}
36-
.forEach { layer ->
37-
val symbolLayer = style.getLayerAs<SymbolLayer>(layer.id)
38-
symbolLayer?.let {
39-
it.textFieldAsExpression?.let { textFieldExpression ->
40-
if (BuildConfig.DEBUG) {
41-
logI(TAG, "Localize layer id: ${it.layerId}")
42-
}
43-
44-
if (sourceIsStreetsV8(style, source)) {
45-
convertedLocale = getLanguageNameV8(locale)
46-
} else if (sourceIsStreetsV7(style, source)) {
47-
convertedLocale = getLanguageNameV7(locale)
48-
}
49-
convertExpression(convertedLocale, it, textFieldExpression)
50-
}
51-
}
52-
}
25+
layerIds?.forEach { id ->
26+
localizeTextFieldExpression(
27+
style = style,
28+
layerId = id,
29+
locale = locale,
30+
convertedLocale = convertedLocale,
31+
filterSymbolLayers = true,
32+
)
33+
} ?: style.styleLayers.forEach { layer ->
34+
if (layer.type == SYMBOL) {
35+
localizeTextFieldExpression(
36+
style = style,
37+
layerId = layer.id,
38+
locale = locale,
39+
convertedLocale = convertedLocale,
40+
filterSymbolLayers = false,
41+
)
5342
}
43+
}
5444
}
5545

56-
private fun convertExpression(language: String, layer: SymbolLayer, textField: Expression?) {
57-
textField?.let {
58-
val stringExpression: String = it.toJson().replace(
59-
EXPRESSION_REGEX,
60-
get(language).toJson()
61-
).replace(EXPRESSION_ABBR_REGEX, get(language).toJson())
62-
if (BuildConfig.DEBUG) {
63-
logI(TAG, "Localize layer with expression: $stringExpression")
46+
private fun localizeTextFieldExpression(
47+
style: StyleInterface,
48+
layerId: String,
49+
locale: Locale,
50+
convertedLocale: String,
51+
filterSymbolLayers: Boolean,
52+
) {
53+
if (filterSymbolLayers) {
54+
val type = style.getStyleLayerProperty(layerId, TYPE).value.contents as? String
55+
if (type != SYMBOL) {
56+
return
6457
}
65-
layer.textField(Expression.fromRaw(stringExpression))
58+
}
59+
val textFieldProperty = style.getStyleLayerProperty(layerId, TEXT_FIELD)
60+
if (textFieldProperty.kind != StylePropertyValueKind.EXPRESSION) {
61+
return
62+
}
63+
val textField = textFieldProperty.value.toJson()
64+
val adaptedLocale = adaptLocaleToV8orV7IfNeeded(
65+
style,
66+
style.getStyleLayerProperty(layerId, SOURCE).value.contents as? String ?: "",
67+
locale
68+
) ?: convertedLocale
69+
val getExpression = get(adaptedLocale).toJson()
70+
val localizedTextFieldExpressionAsJson = textField.replace(
71+
EXPRESSION_REGEX,
72+
getExpression
73+
).replace(EXPRESSION_ABBR_REGEX, getExpression)
74+
if (BuildConfig.DEBUG) {
75+
logI(TAG, "Localize layer with expression: $localizedTextFieldExpressionAsJson")
76+
}
77+
val expected = Value.fromJson(localizedTextFieldExpressionAsJson)
78+
expected.value?.let { value ->
79+
style.setStyleLayerProperty(
80+
layerId,
81+
TEXT_FIELD,
82+
value
83+
)
84+
} ?: run {
85+
logE(TAG, "An error ${expected.error} occurred when converting $localizedTextFieldExpressionAsJson to a Value!")
6686
}
6787
}
6888

69-
private fun sourceIsStreetsV8(style: StyleInterface, source: StyleObjectInfo): Boolean =
70-
sourceIsType(style, source, STREET_V8)
71-
72-
private fun sourceIsStreetsV7(style: StyleInterface, source: StyleObjectInfo): Boolean =
73-
sourceIsType(style, source, STREET_V7)
74-
75-
private fun sourceIsType(style: StyleInterface, source: StyleObjectInfo, type: String): Boolean {
76-
if (source.type == SOURCE_TYPE_VECTOR) {
77-
style.getSourceAs<VectorSource>(source.id)?.url?.let {
78-
return it.contains(type)
89+
private fun adaptLocaleToV8orV7IfNeeded(style: StyleInterface, sourceId: String, locale: Locale): String? {
90+
if ((style.getStyleSourceProperty(sourceId, TYPE).value.contents as? String) == VECTOR) {
91+
(style.getStyleSourceProperty(sourceId, URL).value.contents as? String)?.let { url ->
92+
return if (url.contains(STREET_V8)) {
93+
getLanguageNameV8(locale)
94+
} else if (url.contains(STREET_V7)) {
95+
getLanguageNameV7(locale)
96+
} else {
97+
null
98+
}
7999
}
80100
}
81-
return false
101+
return null
82102
}
83103

84104
private const val TAG = "LocalizationPluginImpl"
85-
private const val SOURCE_TYPE_VECTOR = "vector"
86-
private const val LAYER_TYPE_SYMBOL = "symbol"
105+
private const val TYPE = "type"
106+
private const val SOURCE = "source"
107+
private const val SYMBOL = "symbol"
108+
private const val URL = "url"
109+
private const val VECTOR = "vector"
110+
private const val TEXT_FIELD = "text-field"
87111
private const val STREET_V7 = "mapbox.mapbox-streets-v7"
88112
private const val STREET_V8 = "mapbox.mapbox-streets-v8"
89113
private val EXPRESSION_REGEX = Regex("\\[\"get\",\\s*\"(name_.{2,7})\"\\]")

0 commit comments

Comments
 (0)