Constants for language access
This commit is contained in:
parent
f4201bea7a
commit
da7cf45f8a
@ -4,12 +4,8 @@ import kotlinx.html.body
|
|||||||
import kotlinx.html.head
|
import kotlinx.html.head
|
||||||
import kotlinx.html.title
|
import kotlinx.html.title
|
||||||
import space.kscience.dataforge.data.Data
|
import space.kscience.dataforge.data.Data
|
||||||
import space.kscience.dataforge.data.getItem
|
|
||||||
import space.kscience.dataforge.meta.*
|
import space.kscience.dataforge.meta.*
|
||||||
import space.kscience.dataforge.names.Name
|
import space.kscience.dataforge.names.Name
|
||||||
import space.kscience.dataforge.names.asName
|
|
||||||
import space.kscience.dataforge.names.plus
|
|
||||||
import space.kscience.dataforge.names.removeHeadOrNull
|
|
||||||
import kotlin.reflect.typeOf
|
import kotlin.reflect.typeOf
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -21,63 +17,24 @@ public interface DataRenderer {
|
|||||||
public operator fun invoke(name: Name, data: Data<Any>)
|
public operator fun invoke(name: Name, data: Data<Any>)
|
||||||
|
|
||||||
public companion object {
|
public companion object {
|
||||||
|
|
||||||
// context (SiteBuilder)
|
|
||||||
// public fun buildPageMeta(name: Name, data: Data<Any>): Laminate {
|
|
||||||
// val languages = languages.mapKeys { it.value["key"]?.string ?: it.key }
|
|
||||||
//
|
|
||||||
// // detect current language by prefix if it is not defined explicitly
|
|
||||||
// val currentLanguage: String = data.meta["language"]?.string
|
|
||||||
// ?: languages.keys.firstOrNull() { key -> name.startsWith(key.parseAsName()) } ?: defaultLanguage
|
|
||||||
//
|
|
||||||
// //
|
|
||||||
// val languageMap = Meta {
|
|
||||||
// languages.forEach { (key, meta) ->
|
|
||||||
// val languagePrefix: String = meta.string ?: meta["name"]?.string ?: return@forEach
|
|
||||||
// val targetName = name.removeHeadOrNull("")
|
|
||||||
// val targetData = this@SiteBuilder.data[targetName.parseAsName()]
|
|
||||||
// if (targetData != null) key put targetName
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// val languageMeta = Meta {
|
|
||||||
// "language" put currentLanguage
|
|
||||||
// if (!languageMap.isEmpty()) {
|
|
||||||
// "languageMap" put languageMap
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// return Laminate(data.meta, languageMeta, siteMeta)
|
|
||||||
// }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Automatically build a language map for a data piece with given [name] based on existence of appropriate data nodes.
|
|
||||||
*/
|
|
||||||
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: 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()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public val DEFAULT: DataRenderer = object : DataRenderer {
|
public val DEFAULT: DataRenderer = object : DataRenderer {
|
||||||
|
|
||||||
context(SiteBuilder)
|
context(SiteBuilder)
|
||||||
override fun invoke(name: Name, data: Data<Any>) {
|
override fun invoke(name: Name, data: Data<Any>) {
|
||||||
if (data.type == typeOf<HtmlData>()) {
|
if (data.type == typeOf<HtmlData>()) {
|
||||||
page(name, data.meta) {
|
val languageMeta: Meta = Language.forName(name)
|
||||||
|
|
||||||
|
val dataMeta: Meta = if (languageMeta.isEmpty()) {
|
||||||
|
data.meta
|
||||||
|
} else {
|
||||||
|
data.meta.toMutableMeta().apply {
|
||||||
|
"languages" put languageMeta
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
page(name, dataMeta) {
|
||||||
head {
|
head {
|
||||||
title = data.meta["title"].string ?: "Untitled page"
|
title = dataMeta["title"].string ?: "Untitled page"
|
||||||
}
|
}
|
||||||
body {
|
body {
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
147
snark-html/src/main/kotlin/space/kscience/snark/html/Language.kt
Normal file
147
snark-html/src/main/kotlin/space/kscience/snark/html/Language.kt
Normal file
@ -0,0 +1,147 @@
|
|||||||
|
package space.kscience.snark.html
|
||||||
|
|
||||||
|
import space.kscience.dataforge.data.getItem
|
||||||
|
import space.kscience.dataforge.meta.*
|
||||||
|
import space.kscience.dataforge.names.*
|
||||||
|
import space.kscience.snark.html.Language.Companion.SITE_LANGUAGES_KEY
|
||||||
|
import space.kscience.snark.html.Language.Companion.SITE_LANGUAGE_KEY
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public class Language : Scheme() {
|
||||||
|
/**
|
||||||
|
* Language key override
|
||||||
|
*/
|
||||||
|
public var key: String? by string()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Page name prefix
|
||||||
|
*/
|
||||||
|
public var prefix: String? by string()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Target page name with a given language key
|
||||||
|
*/
|
||||||
|
public var target: Name?
|
||||||
|
get() = meta["target"].string?.parseAsName(false)
|
||||||
|
set(value) {
|
||||||
|
meta["target"] = value?.toString()?.asValue()
|
||||||
|
}
|
||||||
|
|
||||||
|
public companion object : SchemeSpec<Language>(::Language) {
|
||||||
|
|
||||||
|
public val LANGUAGE_KEY: Name = "language".asName()
|
||||||
|
|
||||||
|
public val LANGUAGES_KEY: Name = "languages".asName()
|
||||||
|
|
||||||
|
public val SITE_LANGUAGE_KEY: Name = SiteBuilder.SITE_META_KEY + LANGUAGE_KEY
|
||||||
|
|
||||||
|
public val SITE_LANGUAGES_KEY: Name = SiteBuilder.SITE_META_KEY + LANGUAGES_KEY
|
||||||
|
|
||||||
|
public const val DEFAULT_LANGUAGE: String = "en"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Automatically build a language map for a data piece with given [name] based on existence of appropriate data nodes.
|
||||||
|
*/
|
||||||
|
context(SiteBuilder)
|
||||||
|
public fun forName(name: Name): Meta = Meta {
|
||||||
|
val currentLanguagePrefix = languages[language]?.get(Language::prefix.name)?.string ?: language
|
||||||
|
val fullName = (route.removeHeadOrNull(currentLanguagePrefix.asName()) ?: route) + name
|
||||||
|
languages.forEach { (key, meta) ->
|
||||||
|
val languagePrefix: String = meta[Language::prefix.name].string ?: key
|
||||||
|
val nameWithLanguage: Name = if (languagePrefix.isBlank()) {
|
||||||
|
fullName
|
||||||
|
} else {
|
||||||
|
languagePrefix.asName() + fullName
|
||||||
|
}
|
||||||
|
if (data.getItem(name) != null) {
|
||||||
|
key put meta.asMutableMeta().apply {
|
||||||
|
Language::target.name put nameWithLanguage.toString()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public val SiteBuilder.languages: Map<String, Meta>
|
||||||
|
get() = siteMeta[SITE_LANGUAGES_KEY]?.items?.mapKeys { it.key.toStringUnescaped() } ?: emptyMap()
|
||||||
|
|
||||||
|
public val SiteBuilder.language: String
|
||||||
|
get() = siteMeta[SITE_LANGUAGE_KEY].string ?: Language.DEFAULT_LANGUAGE
|
||||||
|
|
||||||
|
public val SiteBuilder.languagePrefix: Name
|
||||||
|
get() = languages[language]?.let { it[Language::prefix.name].string ?: language }?.parseAsName() ?: Name.EMPTY
|
||||||
|
|
||||||
|
public fun SiteBuilder.withLanguages(languageMap: Map<String, Meta>, block: SiteBuilder.(language: String) -> Unit) {
|
||||||
|
languageMap.forEach { (languageKey, languageMeta) ->
|
||||||
|
val prefix = languageMeta[Language::prefix.name].string ?: languageKey
|
||||||
|
val routeMeta = Meta {
|
||||||
|
SITE_LANGUAGE_KEY put languageKey
|
||||||
|
SITE_LANGUAGES_KEY put Meta {
|
||||||
|
languageMap.forEach {
|
||||||
|
it.key put it.value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
route(prefix, routeMeta = routeMeta) {
|
||||||
|
block(languageKey)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public fun SiteBuilder.withLanguages(
|
||||||
|
vararg language: Pair<String, String>,
|
||||||
|
block: SiteBuilder.(language: String) -> Unit,
|
||||||
|
) {
|
||||||
|
val languageMap = language.associate {
|
||||||
|
it.first to Meta {
|
||||||
|
Language::prefix.name put it.second
|
||||||
|
}
|
||||||
|
}
|
||||||
|
withLanguages(languageMap, block)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The language key of this page
|
||||||
|
*/
|
||||||
|
public val WebPage.language: String
|
||||||
|
get() = pageMeta[Language.LANGUAGE_KEY]?.string ?: pageMeta[SITE_LANGUAGE_KEY]?.string ?: Language.DEFAULT_LANGUAGE
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mapping of language keys to other language versions of this page
|
||||||
|
*/
|
||||||
|
public val WebPage.languages: Map<String, Meta>
|
||||||
|
get() = pageMeta[Language.LANGUAGES_KEY]?.items?.mapKeys { it.key.toStringUnescaped() } ?: emptyMap()
|
||||||
|
|
||||||
|
public fun WebPage.localisedPageRef(pageName: Name, relative: Boolean = false): String {
|
||||||
|
val prefix = languages[language]?.get(Language::prefix.name)?.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)
|
||||||
|
}
|
@ -89,6 +89,7 @@ public interface SiteBuilder : ContextAware, SnarkContext {
|
|||||||
|
|
||||||
|
|
||||||
public companion object {
|
public companion object {
|
||||||
|
public val SITE_META_KEY: Name = "site".asName()
|
||||||
public val INDEX_PAGE_TOKEN: NameToken = NameToken("index")
|
public val INDEX_PAGE_TOKEN: NameToken = NameToken("index")
|
||||||
public val UP_PAGE_TOKEN: NameToken = NameToken("..")
|
public val UP_PAGE_TOKEN: NameToken = NameToken("..")
|
||||||
}
|
}
|
||||||
|
@ -1,88 +0,0 @@
|
|||||||
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
|
|
||||||
import space.kscience.dataforge.names.Name
|
|
||||||
import space.kscience.dataforge.names.parseAsName
|
|
||||||
import space.kscience.dataforge.names.plus
|
|
||||||
|
|
||||||
public val SiteBuilder.languages: Map<String, Meta>
|
|
||||||
get() = siteMeta["site.languages"]?.items?.mapKeys { it.key.toStringUnescaped() } ?: emptyMap()
|
|
||||||
|
|
||||||
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<String, Meta>, block: SiteBuilder.(language: String) -> Unit) {
|
|
||||||
languageMap.forEach { (languageKey, languageMeta) ->
|
|
||||||
val prefix = languageMeta["prefix"].string ?: languageKey
|
|
||||||
val routeMeta = Meta {
|
|
||||||
"site.language" put languageKey
|
|
||||||
"site.languages" put Meta {
|
|
||||||
languageMap.forEach {
|
|
||||||
it.key put it.value
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
route(prefix, routeMeta = routeMeta) {
|
|
||||||
block(languageKey)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public fun SiteBuilder.withLanguages(
|
|
||||||
vararg language: Pair<String, String>,
|
|
||||||
block: SiteBuilder.(language: String) -> Unit,
|
|
||||||
) {
|
|
||||||
val languageMap = language.associate {
|
|
||||||
it.first to Meta {
|
|
||||||
"prefix" put it.second
|
|
||||||
}
|
|
||||||
}
|
|
||||||
withLanguages(languageMap, block)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The language key of this page
|
|
||||||
*/
|
|
||||||
public val WebPage.language: String get() = pageMeta["language"]?.string ?: pageMeta["site.language"]?.string ?: "en"
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Mapping of language keys to other language versions of this page
|
|
||||||
*/
|
|
||||||
public val WebPage.languages: Map<String, Meta>
|
|
||||||
get() = pageMeta["languages"]?.items?.mapKeys { it.key.toStringUnescaped() } ?: emptyMap()
|
|
||||||
|
|
||||||
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)
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user