Skip to content

Commit

Permalink
[#43] Additional attributes per LocalizedString
Browse files Browse the repository at this point in the history
  • Loading branch information
MarcelHeckel committed Dec 21, 2023
1 parent b0dae4d commit c1f879f
Show file tree
Hide file tree
Showing 19 changed files with 493 additions and 22 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@ open class MessageBundle(
private val localeToStringsRef: AtomicRef<PersistentMap<Locale, MessagesProvider>> =
atomic(persistentMapOf())

/** Handles the locales with the "attrib"-extension */
private val attribToLocaleToStringsRef: AtomicRef<PersistentMap<CharSequence, PersistentMap<Locale, MessagesProvider>>> =
atomic(persistentMapOf())

/** Names of the keys mapped to the corresponding objects. */
private val keyObjectsByName: AtomicRef<PersistentMap<String, MessageBundleEntry>> =
atomic(persistentMapOf())
Expand All @@ -49,8 +53,23 @@ open class MessageBundle(

/** Add or replaces a translation in this message bundle */
fun registerTranslation(messagesProvider: MessagesProvider) {
localeToStringsRef.update { localeToStrings ->
localeToStrings.put(messagesProvider.locale, messagesProvider)
val extension = messagesProvider.locale.getExtension(EXTENSION_KEY_PRIVATE)
if (extension?.startsWith(EXTENSION_VALUE_ATTRIB_PREFIX) == true) {
val attrib = extension.substring(EXTENSION_VALUE_ATTRIB_PREFIX.length)
// store as attribute provider
attribToLocaleToStringsRef.update { attribToLocaleToStrings ->
val localeToStrings =
(attribToLocaleToStrings[attrib] ?: persistentMapOf()).put(
messagesProvider.locale.stripExtensions(),
messagesProvider
)
attribToLocaleToStrings.put(attrib, localeToStrings)
}

} else {
localeToStringsRef.update { localeToStrings ->
localeToStrings.put(messagesProvider.locale.stripExtensions(), messagesProvider)
}
}
}

Expand Down Expand Up @@ -87,6 +106,7 @@ open class MessageBundle(
/** Remove all registered translations (see [registerTranslation]) */
fun unregisterAllTranslations() {
localeToStringsRef.update { persistentMapOf() }
attribToLocaleToStringsRef.update { persistentMapOf() }
}

/**
Expand Down Expand Up @@ -118,10 +138,24 @@ open class MessageBundle(
* Use default locale if no [MessagesProvider] or string at index is `null`
*/
protected fun getString0(index: Int, locale: Locale?): String {
return getMapString0(localeToStringsRef.value, index, locale)
?: "?${getEntryByIndex(index)?.messageKey ?: index}?"
}

protected fun getAttribString0(attrib: CharSequence, index: Int, locale: Locale?): String? {
val map = attribToLocaleToStringsRef.value[attrib] ?: return null
return getMapString0(map, index, locale)
}

protected fun getMapString0(
map: PersistentMap<Locale, MessagesProvider>,
index: Int,
locale: Locale?
): String? {
if (index < 0)
throw IllegalArgumentException("Index must be greater or equal to 0")
val localeToUse = locale ?: i18n4k.locale
val messages = localeToStringsRef.value[localeToUse]
val messages = map[localeToUse]
var string: String? = null
if (messages !== null && index < messages.size)
string = messages[index]
Expand All @@ -131,14 +165,12 @@ open class MessageBundle(
if (string === null) {
val lessSpecificLocale = localeToUse.lessSpecificLocale
if (lessSpecificLocale != null)
string = getString0(index, lessSpecificLocale)
string = getMapString0(map, index, lessSpecificLocale)
}
// try default locale
if (string === null && locale != i18n4k.defaultLocale)
string = getString0(index, i18n4k.defaultLocale)
string = getMapString0(map, index, i18n4k.defaultLocale)

if (string === null)
return "?${getEntryByIndex(index)?.messageKey ?: index}?"
return string
}

Expand All @@ -148,8 +180,8 @@ open class MessageBundle(
// http://www.unicode.org/cldr/charts/27/supplemental/language_plural_rules.html

/**
* Similar to [getString0] but parameters are evaluated
* via the set [MessageFormatter] in [i18n4k]
* Similar to [getMapString0] but parameters are
* evaluated via the set [MessageFormatter] in [i18n4k]
* ([de.comahe.i18n4k.config.I18n4kConfig.messageFormatter])
*/
protected fun getStringN(index: Int, parameters: List<Any>, locale: Locale?) =
Expand All @@ -159,6 +191,7 @@ open class MessageBundle(
locale ?: i18n4k.locale
)

// @formatter:off

/**
* Create a [LocalizedString] for the given index.
Expand Down Expand Up @@ -219,6 +252,7 @@ open class MessageBundle(
): MessageBundleLocalizedString =
LocalizedStringN(this, key, index, listOf(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9))

// @formatter:on

/**
* Create a factory for [LocalizedString] for the given index.
Expand Down Expand Up @@ -296,6 +330,14 @@ open class MessageBundle(
): MessageBundleLocalizedStringFactory10 =
LocalizedStringFactory10Bundled(this, key, index)

////////////////////////////////////////////////////////////
// companion
////////////////////////////////////////////////////////////

companion object {
private const val EXTENSION_KEY_PRIVATE = 'x'
private const val EXTENSION_VALUE_ATTRIB_PREFIX = "attrib-"
}

////////////////////////////////////////////////////////////
// LocalizedString
Expand All @@ -317,6 +359,9 @@ open class MessageBundle(
override fun toString(locale: Locale?) =
messageBundle.getString0(messageIndex, locale)

override fun getAttribute(attributeName: CharSequence, locale: Locale?): String? {
return messageBundle.getAttribString0(attributeName, messageIndex, locale)
}

override fun equals(other: Any?): Boolean {
if (this === other) return true
Expand Down Expand Up @@ -353,6 +398,9 @@ open class MessageBundle(
override fun toString(locale: Locale?) =
messageBundle.getStringN(messageIndex, parameters, locale)

override fun getAttribute(attributeName: CharSequence, locale: Locale?): String? {
return messageBundle.getAttribString0(attributeName, messageIndex, locale)
}

override fun equals(other: Any?): Boolean {
if (this === other) return true
Expand Down Expand Up @@ -488,11 +536,13 @@ open class MessageBundle(
fun toString(locale: Locale?) =
messageBundle.getString0(messageIndex, locale)

// @formatter:off
override fun createString(p0: Any, p1: Any, p2: Any, p3: Any, p4: Any, p5: Any, locale: Locale?) =
messageBundle.getStringN(messageIndex, listOf(p0, p1, p2, p3, p4, p5), locale)

override fun createLocalizedString(p0: Any, p1: Any, p2: Any, p3: Any, p4: Any, p5: Any) =
messageBundle.getLocalizedString6(messageKey, messageIndex, p0, p1, p2, p3, p4, p5)
// @formatter:on
}

private data class LocalizedStringFactory7Bundled(
Expand All @@ -507,11 +557,13 @@ open class MessageBundle(
fun toString(locale: Locale?) =
messageBundle.getString0(messageIndex, locale)

// @formatter:off
override fun createString(p0: Any, p1: Any, p2: Any, p3: Any, p4: Any, p5: Any, p6: Any, locale: Locale?) =
messageBundle.getStringN(messageIndex, listOf(p0, p1, p2, p3, p4, p5, p6), locale)

override fun createLocalizedString(p0: Any, p1: Any, p2: Any, p3: Any, p4: Any, p5: Any, p6: Any) =
messageBundle.getLocalizedString7(messageKey, messageIndex, p0, p1, p2, p3, p4, p5, p6)
// @formatter:on
}

private data class LocalizedStringFactory8Bundled(
Expand All @@ -526,11 +578,13 @@ open class MessageBundle(
fun toString(locale: Locale?) =
messageBundle.getString0(messageIndex, locale)

// @formatter:off
override fun createString(p0: Any, p1: Any, p2: Any, p3: Any, p4: Any, p5: Any, p6: Any, p7: Any, locale: Locale?) =
messageBundle.getStringN(messageIndex, listOf(p0, p1, p2, p3, p4, p5, p6, p7), locale)

override fun createLocalizedString(p0: Any, p1: Any, p2: Any, p3: Any, p4: Any, p5: Any, p6: Any, p7: Any) =
messageBundle.getLocalizedString8(messageKey, messageIndex, p0, p1, p2, p3, p4, p5, p6, p7)
// @formatter:on
}

private data class LocalizedStringFactory9Bundled(
Expand All @@ -545,11 +599,13 @@ open class MessageBundle(
fun toString(locale: Locale?) =
messageBundle.getString0(messageIndex, locale)

// @formatter:off
override fun createString(p0: Any, p1: Any, p2: Any, p3: Any, p4: Any, p5: Any, p6: Any, p7: Any, p8: Any, locale: Locale?) =
messageBundle.getStringN(messageIndex, listOf(p0, p1, p2, p3, p4, p5, p6, p7, p8), locale)

override fun createLocalizedString(p0: Any, p1: Any, p2: Any, p3: Any, p4: Any, p5: Any, p6: Any, p7: Any, p8: Any) =
messageBundle.getLocalizedString9(messageKey, messageIndex, p0, p1, p2, p3, p4, p5, p6, p7, p8)
// @formatter:on
}

private data class LocalizedStringFactory10Bundled(
Expand All @@ -564,10 +620,12 @@ open class MessageBundle(
fun toString(locale: Locale?) =
messageBundle.getString0(messageIndex, locale)

// @formatter:off
override fun createString(p0: Any, p1: Any, p2: Any, p3: Any, p4: Any, p5: Any, p6: Any, p7: Any, p8: Any, p9: Any, locale: Locale?) =
messageBundle.getStringN(messageIndex, listOf(p0, p1, p2, p3, p4, p5, p6, p7, p8, p9), locale)

override fun createLocalizedString(p0: Any, p1: Any, p2: Any, p3: Any, p4: Any, p5: Any, p6: Any, p7: Any, p8: Any, p9: Any) =
messageBundle.getLocalizedString10(messageKey, messageIndex, p0, p1, p2, p3, p4, p5, p6, p7, p8, p9)
// @formatter:on
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,13 @@ import de.comahe.i18n4k.Locale
import de.comahe.i18n4k.messages.formatter.parsing.MessageFormatContext
import de.comahe.i18n4k.messages.formatter.parsing.MessageParser
import de.comahe.i18n4k.messages.formatter.parsing.MessagePart
import de.comahe.i18n4k.messages.formatter.types.MessageAttribFormatter
import de.comahe.i18n4k.messages.formatter.types.MessageNumberFormatters
import de.comahe.i18n4k.messages.formatter.types.MessageSelectFormatter
import de.comahe.i18n4k.messages.formatter.types.MessageTransformFormatters
import kotlinx.atomicfu.atomic
import kotlinx.atomicfu.update
import kotlinx.collections.immutable.persistentMapOf
import kotlinx.collections.immutable.toPersistentMap

/**
* Default formatter for messages of `i18n4k`
Expand Down Expand Up @@ -81,8 +81,8 @@ object MessageFormatterDefault : MessageFormatter {
MessageFormatContext(
(MessageNumberFormatters.all
+ MessageTransformFormatters.all
+ MessageSelectFormatter)
.associateBy({ it.typeId }, { it }).toPersistentMap()
+ MessageSelectFormatter
+ MessageAttribFormatter)
)
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,19 @@ interface MessageValueFormatter {
/** ID of the type of the formatter */
val typeId: String

/**
* True if [typeId] is just a prefix for the type.
*
* The suffix is handled by the formatter.
*/
val typeIdIsPrefix: Boolean
get() = false

/** Formats the given [value] and writes is to [result]. */
fun format(
result: StringBuilder,
value: Any?,
typeId: CharSequence,
style: StylePart?,
parameters: List<Any>,
locale: Locale,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,26 @@
package de.comahe.i18n4k.messages.formatter.parsing

import de.comahe.i18n4k.messages.formatter.MessageValueFormatter
import kotlinx.collections.immutable.ImmutableList
import kotlinx.collections.immutable.ImmutableMap
import kotlinx.collections.immutable.toImmutableList
import kotlinx.collections.immutable.toPersistentMap

data class MessageFormatContext(
val formatterTypes : ImmutableMap<String, MessageValueFormatter>
val formatterTypes: ImmutableMap<CharSequence, MessageValueFormatter>,
val formatterPrefixTypes: ImmutableList<MessageValueFormatter>,
) {
constructor(formatters: Collection<MessageValueFormatter>) :
this(
@Suppress("USELESS_CAST")
formatters.filter { !it.typeIdIsPrefix }
.associateBy({ it.typeId as CharSequence }, { it })
.toPersistentMap(),
formatters.filter { it.typeIdIsPrefix }.toImmutableList(),
)

fun getFormatterFor(typeId: CharSequence): MessageValueFormatter? {
return formatterTypes[typeId]
?: formatterPrefixTypes.firstOrNull { typeId.startsWith(it.typeId) }
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,17 +28,14 @@ data class MessagePartParam(val index: Int?, val type: CharSequence?, var style:
parameters[index]
}

if (value is LocalizedString)
value = value.toString(locale)

if (type == null) {
if (value == null)
result.append("{~}")
else
result.append(value)
return
}
val formatter = context.formatterTypes[type]
val formatter = context.getFormatterFor(type)
if (formatter == null) {
if (value == null)
result.append("{~}")
Expand All @@ -47,7 +44,7 @@ data class MessagePartParam(val index: Int?, val type: CharSequence?, var style:
return
}

formatter.format(result, value, style, parameters, locale, context)
formatter.format(result, value, type, style, parameters, locale, context)
}

}
Loading

0 comments on commit c1f879f

Please sign in to comment.