From f4201bea7a4556cbebd8b9b4642ea83d850f2b51 Mon Sep 17 00:00:00 2001 From: Alexander Nozik Date: Sun, 8 Jan 2023 21:26:11 +0300 Subject: [PATCH] Add language support --- .../space/kscience/snark/html/DataRenderer.kt | 14 +++++++-- .../kscience/snark/html/StaticSiteBuilder.kt | 7 ++++- .../space/kscience/snark/html/WebPage.kt | 2 ++ .../html/{language.kt => localization.kt} | 29 +++++++++++++++++++ .../kscience/snark/ktor/KtorSiteBuilder.kt | 8 ++++- 5 files changed, 55 insertions(+), 5 deletions(-) rename snark-html/src/main/kotlin/space/kscience/snark/html/{language.kt => localization.kt} (68%) diff --git a/snark-html/src/main/kotlin/space/kscience/snark/html/DataRenderer.kt b/snark-html/src/main/kotlin/space/kscience/snark/html/DataRenderer.kt index cd1a00f..36c0363 100644 --- a/snark-html/src/main/kotlin/space/kscience/snark/html/DataRenderer.kt +++ b/snark-html/src/main/kotlin/space/kscience/snark/html/DataRenderer.kt @@ -7,7 +7,9 @@ import space.kscience.dataforge.data.Data import space.kscience.dataforge.data.getItem import space.kscience.dataforge.meta.* import space.kscience.dataforge.names.Name -import space.kscience.dataforge.names.appendLeft +import space.kscience.dataforge.names.asName +import space.kscience.dataforge.names.plus +import space.kscience.dataforge.names.removeHeadOrNull import kotlin.reflect.typeOf /** @@ -51,9 +53,15 @@ public interface DataRenderer { */ context(SiteBuilder) public fun buildLanguageMeta(name: Name): Meta = Meta { + val currentLanguagePrefix = languages[language]?.get("prefix")?.string ?: language + val fullName = (route.removeHeadOrNull(currentLanguagePrefix.asName()) ?: route) + name languages.forEach { (key, meta) -> - val languagePrefix = meta["prefix"].string ?: key - val nameWithLanguage: Name = if (languagePrefix.isBlank()) name else name.appendLeft(languagePrefix) + val languagePrefix: String = meta["prefix"].string ?: key + val nameWithLanguage: Name = if (languagePrefix.isBlank()) { + fullName + } else { + languagePrefix.asName() + fullName + } if (data.getItem(name) != null) { key put meta.asMutableMeta().apply { "target" put nameWithLanguage.toString() diff --git a/snark-html/src/main/kotlin/space/kscience/snark/html/StaticSiteBuilder.kt b/snark-html/src/main/kotlin/space/kscience/snark/html/StaticSiteBuilder.kt index b998d5f..fb764ca 100644 --- a/snark-html/src/main/kotlin/space/kscience/snark/html/StaticSiteBuilder.kt +++ b/snark-html/src/main/kotlin/space/kscience/snark/html/StaticSiteBuilder.kt @@ -6,6 +6,7 @@ import kotlinx.html.stream.createHTML import space.kscience.dataforge.data.DataTree import space.kscience.dataforge.meta.Laminate import space.kscience.dataforge.meta.Meta +import space.kscience.dataforge.meta.toMutableMeta import space.kscience.dataforge.names.Name import space.kscience.dataforge.names.isEmpty import space.kscience.dataforge.names.plus @@ -87,8 +88,12 @@ internal class StaticSiteBuilder( override fun page(route: Name, pageMeta: Meta, content: context(WebPage, HTML) () -> Unit) { val htmlBuilder = createHTML() + val modifiedPageMeta = pageMeta.toMutableMeta().apply { + "name" put route.toString() + } + htmlBuilder.html { - content(StaticWebPage(pageMeta), this) + content(StaticWebPage(Laminate(modifiedPageMeta, siteMeta)), this) } val newPath = if (route.isEmpty()) { diff --git a/snark-html/src/main/kotlin/space/kscience/snark/html/WebPage.kt b/snark-html/src/main/kotlin/space/kscience/snark/html/WebPage.kt index d7f338b..f35ca6f 100644 --- a/snark-html/src/main/kotlin/space/kscience/snark/html/WebPage.kt +++ b/snark-html/src/main/kotlin/space/kscience/snark/html/WebPage.kt @@ -56,6 +56,8 @@ public fun WebPage.resolvePageRef(pageName: String): String = resolvePageRef(pag public val WebPage.homeRef: String get() = resolvePageRef(SiteBuilder.INDEX_PAGE_TOKEN.asName()) +public val WebPage.name: Name? get() = pageMeta["name"].string?.parseAsName() + /** * Resolve a Html builder by its full name */ diff --git a/snark-html/src/main/kotlin/space/kscience/snark/html/language.kt b/snark-html/src/main/kotlin/space/kscience/snark/html/localization.kt similarity index 68% rename from snark-html/src/main/kotlin/space/kscience/snark/html/language.kt rename to snark-html/src/main/kotlin/space/kscience/snark/html/localization.kt index eac5566..2f6122d 100644 --- a/snark-html/src/main/kotlin/space/kscience/snark/html/language.kt +++ b/snark-html/src/main/kotlin/space/kscience/snark/html/localization.kt @@ -1,5 +1,6 @@ package space.kscience.snark.html +import space.kscience.dataforge.data.getItem import space.kscience.dataforge.meta.Meta import space.kscience.dataforge.meta.get import space.kscience.dataforge.meta.string @@ -13,6 +14,9 @@ public val SiteBuilder.languages: Map public val SiteBuilder.language: String get() = siteMeta["site.language"].string ?: "en" +public val SiteBuilder.languagePrefix: Name + get() = languages[language]?.let { it["prefix"].string ?: language }?.parseAsName() ?: Name.EMPTY + public fun SiteBuilder.withLanguages(languageMap: Map, block: SiteBuilder.(language: String) -> Unit) { languageMap.forEach { (languageKey, languageMeta) -> val prefix = languageMeta["prefix"].string ?: languageKey @@ -56,4 +60,29 @@ public val WebPage.languages: Map public fun WebPage.localisedPageRef(pageName: Name, relative: Boolean = false): String { val prefix = languages[language]?.get("prefix")?.string?.parseAsName() ?: Name.EMPTY return resolvePageRef(prefix + pageName, relative) +} + + +/** + * Render all pages in a node with given name. Use localization prefix if appropriate data is available. + */ +public fun SiteBuilder.localizedPages( + dataPath: Name, + remotePath: Name = dataPath, + dataRenderer: DataRenderer = DataRenderer.DEFAULT, +) { + val item = data.getItem(languagePrefix + dataPath) + ?: data.getItem(dataPath) + ?: error("No data found by name $dataPath") + route(remotePath) { + pages(item, dataRenderer) + } +} + +public fun SiteBuilder.localizedPages( + dataPath: String, + remotePath: Name = dataPath.parseAsName(), + dataRenderer: DataRenderer = DataRenderer.DEFAULT, +) { + localizedPages(dataPath.parseAsName(), remotePath, dataRenderer = dataRenderer) } \ No newline at end of file diff --git a/snark-ktor/src/main/kotlin/space/kscience/snark/ktor/KtorSiteBuilder.kt b/snark-ktor/src/main/kotlin/space/kscience/snark/ktor/KtorSiteBuilder.kt index 015f707..86850ed 100644 --- a/snark-ktor/src/main/kotlin/space/kscience/snark/ktor/KtorSiteBuilder.kt +++ b/snark-ktor/src/main/kotlin/space/kscience/snark/ktor/KtorSiteBuilder.kt @@ -18,6 +18,7 @@ import kotlinx.html.style import space.kscience.dataforge.data.DataTree import space.kscience.dataforge.meta.Laminate import space.kscience.dataforge.meta.Meta +import space.kscience.dataforge.meta.toMutableMeta import space.kscience.dataforge.names.Name import space.kscience.dataforge.names.cutLast import space.kscience.dataforge.names.endsWith @@ -97,7 +98,12 @@ public class KtorSiteBuilder( port = request.origin.port } - val pageBuilder = KtorWebPage(url.buildString(), Laminate(pageMeta, siteMeta)) + val modifiedPageMeta = pageMeta.toMutableMeta().apply { + "name" put route.toString() + "url" put url.buildString() + } + + val pageBuilder = KtorWebPage(url.buildString(), Laminate(modifiedPageMeta, siteMeta)) content(pageBuilder, this) } }