Commit 58eca486 authored by Jonas Waeber's avatar Jonas Waeber
Browse files

Merge branch 'update-date-sort-and-facet'

# Conflicts:
#	src/main/kotlin/ch/memobase/helpers/DateFacetBuildHelpers.kt
parents 570c0fc9 3ec4a536
deploymentName: di-es-transformer-prod k8sName: es-transformer
k8sGroupId: di
k8sGroupName: documents-import
outputTopic: mb-di-frontend-es-documents-prod outputTopic: mb-di-frontend-es-documents-prod
inputTopic: mb-di-processed-records-prod inputTopic: mb-di-processed-records-prod
reportingTopic: mb-di-reporting-prod reportingTopic: mb-di-reporting-prod
...@@ -10,6 +13,8 @@ documentTypeLabels: prod-document-type-labels ...@@ -10,6 +13,8 @@ documentTypeLabels: prod-document-type-labels
accessTermLabels: prod-access-term-labels accessTermLabels: prod-access-term-labels
reuseStatementLabels: prod-reuse-statement-labels reuseStatementLabels: prod-reuse-statement-labels
applicationIdVersion: v1 # change this variable when the data from the kafka topic should be fully re-imported.
documentsIndexSource: prod-documents-index documentsIndexSource: prod-documents-index
institutionIndexSource: prod-institutions-index institutionIndexSource: prod-institutions-index
recordSetIndexSource: prod-record-sets-index recordSetIndexSource: prod-record-sets-index
......
deploymentName: di-es-transformer-stage k8sName: es-transformer
k8sGroupId: di
k8sGroupName: documents-import
outputTopic: mb-di-frontend-es-documents-stage outputTopic: mb-di-frontend-es-documents-stage
inputTopic: mb-di-processed-records-stage inputTopic: mb-di-processed-records-stage
reportingTopic: mb-di-reporting-stage reportingTopic: mb-di-reporting-stage
...@@ -10,6 +13,8 @@ documentTypeLabels: stage-document-type-labels ...@@ -10,6 +13,8 @@ documentTypeLabels: stage-document-type-labels
accessTermLabels: stage-access-term-labels accessTermLabels: stage-access-term-labels
reuseStatementLabels: stage-reuse-statement-labels reuseStatementLabels: stage-reuse-statement-labels
applicationIdVersion: v1 # change this variable when the data from the kafka topic should be fully re-imported.
documentsIndexSource: stage-documents-index documentsIndexSource: stage-documents-index
institutionIndexSource: stage-institutions-index institutionIndexSource: stage-institutions-index
recordSetIndexSource: stage-record-sets-index recordSetIndexSource: stage-record-sets-index
......
deploymentName: di-es-transformer-test k8sName: es-transformer
k8sGroupId: di
k8sGroupName: documents-import
outputTopic: mb-di-frontend-es-documents-prod outputTopic: mb-di-frontend-es-documents-prod
inputTopic: mb-di-processed-records-prod inputTopic: mb-di-processed-records-prod
reportingTopic: mb-di-reporting-prod reportingTopic: mb-di-reporting-prod
...@@ -10,6 +13,8 @@ documentTypeLabels: test-document-type-labels ...@@ -10,6 +13,8 @@ documentTypeLabels: test-document-type-labels
accessTermLabels: test-access-term-labels accessTermLabels: test-access-term-labels
reuseStatementLabels: test-reuse-statement-labels reuseStatementLabels: test-reuse-statement-labels
applicationIdVersion: v4 # change this variable when the data from the kafka topic should be fully re-imported.
documentsIndexSource: test-documents-index documentsIndexSource: test-documents-index
institutionIndexSource: test-institutions-index institutionIndexSource: test-institutions-index
recordSetIndexSource: test-record-sets-index recordSetIndexSource: test-record-sets-index
......
deploymentName: gi-es-institutions-transformer-prod k8sName: es-institutions-transformer
k8sGroupId: gi
k8sGroupName: group-import
outputTopic: mb-gi-frontend-es-institutions-prod outputTopic: mb-gi-frontend-es-institutions-prod
inputTopic: mb-gi-processed-institutions-prod inputTopic: mb-gi-processed-institutions-prod
reportingTopic: mb-di-reporting-prod reportingTopic: mb-di-reporting-prod
...@@ -11,6 +14,8 @@ documentTypeLabels: prod-document-type-labels ...@@ -11,6 +14,8 @@ documentTypeLabels: prod-document-type-labels
accessTermLabels: prod-access-term-labels accessTermLabels: prod-access-term-labels
reuseStatementLabels: prod-reuse-statement-labels reuseStatementLabels: prod-reuse-statement-labels
applicationIdVersion: v1 # change this variable when the data from the kafka topic should be fully re-imported.
documentsIndexSource: prod-documents-index documentsIndexSource: prod-documents-index
institutionIndexSource: prod-institutions-index institutionIndexSource: prod-institutions-index
recordSetIndexSource: prod-record-sets-index recordSetIndexSource: prod-record-sets-index
......
deploymentName: gi-es-institutions-transformer-stage k8sName: es-institutions-transformer
k8sGroupId: gi
k8sGroupName: group-import
outputTopic: mb-gi-frontend-es-institutions-stage outputTopic: mb-gi-frontend-es-institutions-stage
inputTopic: mb-gi-processed-institutions-stage inputTopic: mb-gi-processed-institutions-stage
reportingTopic: mb-di-reporting-stage reportingTopic: mb-di-reporting-stage
...@@ -11,6 +14,8 @@ documentTypeLabels: stage-document-type-labels ...@@ -11,6 +14,8 @@ documentTypeLabels: stage-document-type-labels
accessTermLabels: stage-access-term-labels accessTermLabels: stage-access-term-labels
reuseStatementLabels: stage-reuse-statement-labels reuseStatementLabels: stage-reuse-statement-labels
applicationIdVersion: v1 # change this variable when the data from the kafka topic should be fully re-imported.
documentsIndexSource: stage-documents-index documentsIndexSource: stage-documents-index
institutionIndexSource: stage-institutions-index institutionIndexSource: stage-institutions-index
recordSetIndexSource: stage-record-sets-index recordSetIndexSource: stage-record-sets-index
......
deploymentName: gi-es-institutions-transformer-test k8sName: es-institutions-transformer
k8sGroupId: gi
k8sGroupName: group-import
outputTopic: mb-gi-frontend-es-institutions-prod outputTopic: mb-gi-frontend-es-institutions-prod
inputTopic: mb-gi-processed-institutions-prod inputTopic: mb-gi-processed-institutions-prod
reportingTopic: mb-di-reporting-prod reportingTopic: mb-di-reporting-prod
...@@ -11,6 +14,8 @@ documentTypeLabels: test-document-type-labels ...@@ -11,6 +14,8 @@ documentTypeLabels: test-document-type-labels
accessTermLabels: test-access-term-labels accessTermLabels: test-access-term-labels
reuseStatementLabels: test-reuse-statement-labels reuseStatementLabels: test-reuse-statement-labels
applicationIdVersion: v1 # change this variable when the data from the kafka topic should be fully re-imported.
documentsIndexSource: test-documents-index documentsIndexSource: test-documents-index
institutionIndexSource: test-institutions-index institutionIndexSource: test-institutions-index
recordSetIndexSource: test-record-sets-index recordSetIndexSource: test-record-sets-index
......
deploymentName: gi-es-record-sets-transformer-prod k8sName: es-record-sets-transformer
k8sGroupId: gi
k8sGroupName: group-import
outputTopic: mb-gi-frontend-es-record-sets-prod outputTopic: mb-gi-frontend-es-record-sets-prod
inputTopic: mb-gi-processed-record-sets-prod inputTopic: mb-gi-processed-record-sets-prod
reportingTopic: mb-di-reporting-prod reportingTopic: mb-di-reporting-prod
...@@ -11,6 +14,8 @@ documentTypeLabels: prod-document-type-labels ...@@ -11,6 +14,8 @@ documentTypeLabels: prod-document-type-labels
accessTermLabels: prod-access-term-labels accessTermLabels: prod-access-term-labels
reuseStatementLabels: prod-reuse-statement-labels reuseStatementLabels: prod-reuse-statement-labels
applicationIdVersion: v1 # change this variable when the data from the kafka topic should be fully re-imported.
documentsIndexSource: prod-documents-index documentsIndexSource: prod-documents-index
institutionIndexSource: prod-institutions-index institutionIndexSource: prod-institutions-index
recordSetIndexSource: prod-record-sets-index recordSetIndexSource: prod-record-sets-index
......
deploymentName: gi-es-record-sets-transformer-stage k8sName: es-record-sets-transformer
k8sGroupId: gi
k8sGroupName: group-import
outputTopic: mb-gi-frontend-es-record-sets-stage outputTopic: mb-gi-frontend-es-record-sets-stage
inputTopic: mb-gi-processed-record-sets-stage inputTopic: mb-gi-processed-record-sets-stage
reportingTopic: mb-di-reporting-stage reportingTopic: mb-di-reporting-stage
...@@ -11,6 +14,8 @@ documentTypeLabels: stage-document-type-labels ...@@ -11,6 +14,8 @@ documentTypeLabels: stage-document-type-labels
accessTermLabels: stage-access-term-labels accessTermLabels: stage-access-term-labels
reuseStatementLabels: stage-reuse-statement-labels reuseStatementLabels: stage-reuse-statement-labels
applicationIdVersion: v1 # change this variable when the data from the kafka topic should be fully re-imported.
documentsIndexSource: stage-documents-index documentsIndexSource: stage-documents-index
institutionIndexSource: stage-institutions-index institutionIndexSource: stage-institutions-index
recordSetIndexSource: stage-record-sets-index recordSetIndexSource: stage-record-sets-index
......
deploymentName: gi-es-record-sets-transformer-test k8sName: es-record-sets-transformer
k8sGroupId: gi
k8sGroupName: group-import
outputTopic: mb-gi-frontend-es-record-sets-prod outputTopic: mb-gi-frontend-es-record-sets-prod
inputTopic: mb-gi-processed-record-sets-prod inputTopic: mb-gi-processed-record-sets-prod
reportingTopic: mb-di-reporting-prod reportingTopic: mb-di-reporting-prod
...@@ -11,6 +14,8 @@ documentTypeLabels: test-document-type-labels ...@@ -11,6 +14,8 @@ documentTypeLabels: test-document-type-labels
accessTermLabels: test-access-term-labels accessTermLabels: test-access-term-labels
reuseStatementLabels: test-reuse-statement-labels reuseStatementLabels: test-reuse-statement-labels
applicationIdVersion: v1 # change this variable when the data from the kafka topic should be fully re-imported.
documentsIndexSource: test-documents-index documentsIndexSource: test-documents-index
institutionIndexSource: test-institutions-index institutionIndexSource: test-institutions-index
recordSetIndexSource: test-record-sets-index recordSetIndexSource: test-record-sets-index
......
apiVersion: v1 apiVersion: v1
kind: ConfigMap kind: ConfigMap
metadata: metadata:
name: "{{ .Values.deploymentName }}-app-config" name: "{{ .Values.k8sGroupId }}-{{ .Values.k8sName }}-{{ .Values.k8sEnvironment }}-app-config"
namespace: memobase namespace: memobase
labels:
app: "{{ .Values.k8sName }}"
environment: {{ .Values.k8sEnvironment }}
group: "{{ .Values.k8sGroupName }}"
data: data:
APPLICATION_ID: "{{ .Values.deploymentName }}-app" APPLICATION_ID: "{{ .Values.k8sGroupId }}-{{ .Values.k8sName }}-{{ .Values.k8sEnvironment }}-{{.Values.applicationIdVersion }}-app"
MEDIA_SERVER_URL: "{{ .Values.mediaServerUrl }}" MEDIA_SERVER_URL: "{{ .Values.mediaServerUrl }}"
UPDATE_TOPIC: "{{ .Values.updateTopic }}" UPDATE_TOPIC: "{{ .Values.updateTopic }}"
TOPIC_IN: "{{ .Values.inputTopic }}" TOPIC_IN: "{{ .Values.inputTopic }}"
......
apiVersion: apps/v1 apiVersion: apps/v1
kind: Deployment kind: Deployment
metadata: metadata:
name: "{{ .Values.deploymentName }}-deployment" name: "{{ .Values.k8sGroupId }}-{{ .Values.k8sName }}-{{ .Values.k8sEnvironment }}-deployment"
namespace: memobase namespace: memobase
labels: labels:
app: "{{ .Values.deploymentName }}" app: "{{ .Values.k8sName }}"
environment: {{ .Values.k8sEnvironment }} environment: {{ .Values.k8sEnvironment }}
group: "documents-import" group: "{{ .Values.k8sGroupName }}"
spec: spec:
selector: selector:
matchLabels: matchLabels:
app: "{{ .Values.deploymentName }}" app: "{{ .Values.k8sName }}"
replicas: {{ .Values.k8sReplicas }} replicas: {{ .Values.k8sReplicas }}
template: template:
metadata: metadata:
labels: labels:
app: "{{ .Values.deploymentName }}" app: "{{ .Values.k8sName }}"
environment: {{ .Values.k8sEnvironment }} environment: {{ .Values.k8sEnvironment }}
group: "documents-import" group: "{{ .Values.k8sGroupName }}"
spec: spec:
containers: containers:
- name: "{{ .Values.deploymentName }}-container" - name: "{{ .Values.k8sGroupId }}-{{ .Values.k8sName }}-{{ .Values.k8sEnvironment }}-container"
image: "{{.Values.registry}}/{{ .Values.image }}:{{ .Values.tag }}" image: "{{.Values.registry}}/{{ .Values.image }}:{{ .Values.tag }}"
imagePullPolicy: Always imagePullPolicy: Always
resources: resources:
...@@ -52,7 +52,7 @@ spec: ...@@ -52,7 +52,7 @@ spec:
- configMapRef: - configMapRef:
name: "{{ .Values.elasticConfigs }}" name: "{{ .Values.elasticConfigs }}"
- configMapRef: - configMapRef:
name: "{{ .Values.deploymentName}}-app-config" name: "{{ .Values.k8sGroupId }}-{{ .Values.k8sName }}-{{ .Values.k8sEnvironment }}-app-config"
volumeMounts: volumeMounts:
- name: instituion-type-labels - name: instituion-type-labels
mountPath: "/configs/institution_types/" mountPath: "/configs/institution_types/"
......
...@@ -3,6 +3,10 @@ registry: "cr.gitlab.switch.ch" ...@@ -3,6 +3,10 @@ registry: "cr.gitlab.switch.ch"
image: "memoriav/memobase-2020/services/elastic-services/search-doc-service" image: "memoriav/memobase-2020/services/elastic-services/search-doc-service"
tag: "latest" tag: "latest"
k8sName: placeholder
k8sGroupId: placeholder
k8sGroupName: placeholder
k8sEnvironment: placeholder k8sEnvironment: placeholder
k8sReplicas: 1 k8sReplicas: 1
k8sRequestsCpu: "0.1" k8sRequestsCpu: "0.1"
...@@ -10,7 +14,6 @@ k8sRequestsMemory: "128Mi" ...@@ -10,7 +14,6 @@ k8sRequestsMemory: "128Mi"
k8sLimitsCpu: "0.5" k8sLimitsCpu: "0.5"
k8sLimitsMemory: "512Mi" k8sLimitsMemory: "512Mi"
deploymentName: placeholder
kafkaConfigs: placeholder kafkaConfigs: placeholder
elasticConfigs: placeholder elasticConfigs: placeholder
...@@ -20,6 +23,7 @@ recordSetIndexSource: placeholder ...@@ -20,6 +23,7 @@ recordSetIndexSource: placeholder
outputTopic: placeholder outputTopic: placeholder
inputTopic: placeholder inputTopic: placeholder
reportingTopic: placeholder reportingTopic: placeholder
applicationIdVersion: placeholder # change this variable when the data from the kafka topic should be fully re-imported.
instutionTypeLabels: placeholder instutionTypeLabels: placeholder
documentTypeLabels: placeholder documentTypeLabels: placeholder
......
...@@ -18,7 +18,7 @@ ...@@ -18,7 +18,7 @@
package ch.memobase package ch.memobase
import ch.memobase.builders.AgentContainerBuilder import ch.memobase.builders.AgentContainerBuilder
import ch.memobase.builders.DateContainerBuilder import ch.memobase.builders.DateSearchFieldBuilder
import ch.memobase.builders.EnrichedFacetContainerBuilder import ch.memobase.builders.EnrichedFacetContainerBuilder
import ch.memobase.builders.FacettedContainerBuilder import ch.memobase.builders.FacettedContainerBuilder
import ch.memobase.builders.IFieldBuilder import ch.memobase.builders.IFieldBuilder
...@@ -106,9 +106,9 @@ class DocumentsSearchDocBuilder( ...@@ -106,9 +106,9 @@ class DocumentsSearchDocBuilder(
val placeFacetBuilder = PlaceFacetBuilder() val placeFacetBuilder = PlaceFacetBuilder()
val dateCreatedBuilder = DateContainerBuilder(dateCreatedIds) val dateCreatedBuilder = DateSearchFieldBuilder(dateCreatedIds, "created")
val dateIssuedBuilder = DateContainerBuilder(dateIssuedIds) val dateIssuedBuilder = DateSearchFieldBuilder(dateIssuedIds, "issued")
val temporalBuilder = DateContainerBuilder(temporalIds) val temporalBuilder = DateSearchFieldBuilder(temporalIds, "temporal")
val suggestContainerBuilder = SuggestContainerBuilder(keywordIds) val suggestContainerBuilder = SuggestContainerBuilder(keywordIds)
...@@ -265,9 +265,10 @@ class DocumentsSearchDocBuilder( ...@@ -265,9 +265,10 @@ class DocumentsSearchDocBuilder(
), ),
relatedMaterial = Extract.languageContainer("relation (record id: $key)", record["relation"]), relatedMaterial = Extract.languageContainer("relation (record id: $key)", record["relation"]),
source = Extract.languageContainer("source (record id: $key)", record["source"]), source = Extract.languageContainer("source (record id: $key)", record["source"]),
temporal = temporalBuilder.build(), temporal = temporalBuilder.build().first,
dateCreated = dateCreatedBuilder.build(), dateCreated = dateCreatedBuilder.build().first,
dateIssued = dateIssuedBuilder.build(), dateIssued = dateIssuedBuilder.build().first,
dateFacetField = dateCreatedBuilder.build().second + dateIssuedBuilder.build().second,
placeCapture = placeCapturedBuilder.build(), placeCapture = placeCapturedBuilder.build(),
placeRelated = placesRelatedBuilder.build(), placeRelated = placesRelatedBuilder.build(),
placeFacet = placeFacetBuilder.build(), placeFacet = placeFacetBuilder.build(),
......
...@@ -17,18 +17,21 @@ ...@@ -17,18 +17,21 @@
*/ */
package ch.memobase.builders package ch.memobase.builders
import ch.memobase.helpers.Constants
import ch.memobase.helpers.DateFacetBuildHelpers
import ch.memobase.model.DateFacetField
import ch.memobase.model.DateSearchField
import ch.memobase.model.LanguageContainer
import ch.memobase.rdf.NS import ch.memobase.rdf.NS
import com.beust.klaxon.JsonArray import com.beust.klaxon.JsonArray
import com.beust.klaxon.JsonObject import com.beust.klaxon.JsonObject
import org.apache.logging.log4j.LogManager import org.apache.logging.log4j.LogManager
import ch.memobase.helpers.DateFacetBuildHelpers
import ch.memobase.helpers.Constants
import ch.memobase.model.DateContainer
class DateContainerBuilder(private val containedIds: List<String>) : IFieldBuilder { class DateSearchFieldBuilder(private val containedIds: List<String>, private val type: String) : IFieldBuilder {
private val log = LogManager.getLogger("DateContainerBuilder") private val log = LogManager.getLogger("DateContainerBuilder")
private val dateContainers = mutableListOf<DateContainer>() private val dateSearchFields = mutableListOf<DateSearchField>()
private val dateFacetFields = mutableListOf<DateFacetField>()
override fun filter(jsonObject: JsonObject): Boolean { override fun filter(jsonObject: JsonObject): Boolean {
return if (containedIds.contains(jsonObject[Constants.entityId])) return if (containedIds.contains(jsonObject[Constants.entityId]))
...@@ -59,15 +62,55 @@ class DateContainerBuilder(private val containedIds: List<String>) : IFieldBuild ...@@ -59,15 +62,55 @@ class DateContainerBuilder(private val containedIds: List<String>) : IFieldBuild
is JsonArray<*> -> value.mapNotNull { it as String? } is JsonArray<*> -> value.mapNotNull { it as String? }
else -> emptyList() else -> emptyList()
} }
val facetList = when (jsonObject["@type"] as String) { val facetLists = listOf("de", "fr", "it").map {
collectFacetStrings(
jsonObject,
isNormalized, date, key, it
)
}
dateSearchFields.add(
DateSearchField(
date = date,
qualifier = qualifier,
certainty = certainty
)
)
dateFacetFields.add(
DateFacetField(
display = date,
type = type,
sort = sort,
facet = LanguageContainer(
de = facetLists[0],
fr = facetLists[1],
it = facetLists[2]
)
)
)
return "Transformed date to date container."
}
override fun build(): Pair<List<DateSearchField>, List<DateFacetField>> {
return Pair(dateSearchFields, dateFacetFields)
}
private fun collectFacetStrings(
jsonObject: JsonObject,
isNormalized: Boolean,
date: String,
key: String,
language: String
): List<String> {
return when (jsonObject["@type"] as String) {
NS.rico + "SingleDate" -> NS.rico + "SingleDate" ->
if (isNormalized) if (isNormalized)
DateFacetBuildHelpers.buildFromNormalizedSingleDate(date) DateFacetBuildHelpers.buildFromNormalizedSingleDate(date, language)
else emptyList() else emptyList()
NS.rico + "DateRange" -> NS.rico + "DateRange" ->
if (isNormalized) { if (isNormalized) {
try { try {
DateFacetBuildHelpers.buildFromNormalizedDateRange(date) DateFacetBuildHelpers.buildFromNormalizedDateRange(date, language)
} catch (ex: NumberFormatException) { } catch (ex: NumberFormatException) {
log.error("Could not parse normalized date $date in resource $key.") log.error("Could not parse normalized date $date in resource $key.")
emptyList<String>() emptyList<String>()
...@@ -77,19 +120,5 @@ class DateContainerBuilder(private val containedIds: List<String>) : IFieldBuild ...@@ -77,19 +120,5 @@ class DateContainerBuilder(private val containedIds: List<String>) : IFieldBuild
} }
else -> emptyList() else -> emptyList()
} }
dateContainers.add(
DateContainer(
date = date,
sort = sort,
qualifier = qualifier,
certainty = certainty,
facet = facetList
)
)
return "Transformed date to date container."
}
override fun build(): List<DateContainer> {
return dateContainers
} }
} }
\ No newline at end of file
...@@ -27,7 +27,11 @@ object DateFacetBuildHelpers { ...@@ -27,7 +27,11 @@ object DateFacetBuildHelpers {
private const val level_1 = "0" private const val level_1 = "0"
private const val level_2 = "1" private const val level_2 = "1"
private const val centuryName = "Jahrhundert" private val centuryNames = mapOf(
Pair("de", "Jahrhundert"),
Pair("fr", "siècle"),
Pair("it", "secolo")
)
/** /**
* Builds the hierarchical facet for a normalized SingleDate date. * Builds the hierarchical facet for a normalized SingleDate date.
...@@ -36,8 +40,8 @@ object DateFacetBuildHelpers { ...@@ -36,8 +40,8 @@ object DateFacetBuildHelpers {
* *
* @return The facet values to construct the hierarchy with century and decade. * @return The facet values to construct the hierarchy with century and decade.
*/ */
fun buildFromNormalizedSingleDate(date: String): List<String> { fun buildFromNormalizedSingleDate(date: String, language: String): List<String> {
val century = getCentury(date.substring(0, 4)) val century = getCentury(date.substring(0, 4), language)
val decade = getDecade(date.substring(0, 4)) val decade = getDecade(date.substring(0, 4))
return listOf( return listOf(
"$level_1$separator$century$separator", "$level_1$separator$century$separator",
...@@ -54,7 +58,7 @@ object DateFacetBuildHelpers { ...@@ -54,7 +58,7 @@ object DateFacetBuildHelpers {
* *
* @return The facet values used by outermedia. * @return The facet values used by outermedia.
*/ */
fun buildFromNormalizedDateRange(date: String): List<String> { fun buildFromNormalizedDateRange(date: String, language: String): List<String> {
if (date.length <= 3) { if (date.length <= 3) {
log.error("Normalized date range has less than 4 characters: $date.") log.error("Normalized date range has less than 4 characters: $date.")
return emptyList() return emptyList()
...@@ -77,17 +81,17 @@ object DateFacetBuildHelpers { ...@@ -77,17 +81,17 @@ object DateFacetBuildHelpers {
} }
return if (until.isEmpty()) { return if (until.isEmpty()) {
val century = getCentury(from) val century = getCentury(from, language)
val decade = getDecade(from) val decade = getDecade(from)
listOf(