Skip to content

A high-performance, developer-friendly localization library for Kotlin and PaperMC. It bridges the gap between raw configuration files and rich, interactive Adventure Components.

License

Notifications You must be signed in to change notification settings

MrLarkyy/KLocale

Repository files navigation

🌍 KLocale

CodeFactor Reposilite Kotlin Discord

KLocale is a high-performance, developer-friendly localization library for Kotlin and PaperMC. It bridges the gap between raw configuration files and rich, interactive Adventure Components.

✨ Features

  • High Performance: Pre-renders static messages to minimize object allocation.
  • Smart Fallbacks: Automatic locale resolution (e.g., en_US -> en -> default).
  • MiniMessage Ready: Native support for Kyori MiniMessage and legacy color codes.
  • Single-Pass Replacement: Optimized placeholder system to prevent double-replacement issues.
  • Multi-Provider: Load locales from YAML, GitHub, HTTP, or internal resources.
  • Async Loading: Coroutine-based loading to keep your server tick-rate silky smooth.
  • Fail-Safe: Customizable strategies for missing keys (MissingKeyHandler).

📦 Installation

Add the library to your build.gradle.kts:

repositories {
    maven("https://repo.nekroplex.com/releases")
}

dependencies {
    implementation("gg.aquatic:KLocale:VERSION")
    implementation("gg.aquatic:KLocale-Paper:VERSION")
}

🚀 Quick Start (Paper)

Initialize your locale manager using the clean Kotlin DSL:

val localeManager = KLocale.paper {
    defaultLanguage = "en"

    // Add one or more providers
    providers += YamlLocaleProvider(
        file = File(dataFolder, "lang.yml"),
        serializer = YamlLocaleProvider.DefaultSerializer
    )
    // Optional: Use a custom MiniMessage instance (comes with 'ccmd' tag by default!)
    // miniMessage = MiniMessage.miniMessage()

    // Optional: Handle missing keys gracefully instead of throwing exceptions
    missingKeyHandler = MissingKeyHandler.Throwing()
}

// Reload locales (suspended call)
scope.launch {
    localeManager.invalidate()
}

Sending Messages

Fetching and sending messages is intuitive and chainable:

fun welcome(player: Player) {
    localeManager.getOrDefault(player.locale(), "welcome-message")
        .replace("player", player.name)
        // Native support for replacing placeholders with rich Components
        .replace("balance", Component.text("$500", NamedTextColor.GREEN))
        .send(player)
}

🛠 Advanced Usage

Type-Safe Enums

Implement CfgMessageHandler to access your messages globally with clean syntax: Check out MessagesExample for a full example.

enum class Messages(override val path: String) : CfgMessageHandler<PaperMessage> {
    WELCOME("welcome-message"),
    STAFF_LIST("staff-list");

    override val manager: LocaleManager<PaperMessage>
        get() = MyPlugin.localeManager }

// Usage:
Messages.WELCOME.message(player.locale()).replace("player", name).send(player)

Handling Custom Languages

If you need to support languages that aren't constants in java.util.Locale (like Czech, Slovak, or regional dialects), use IETF BCP 47 language tags:

// For Czech
val czech = Locale.forLanguageTag("cs-CZ")

// For custom/internal tags
val custom = Locale.forLanguageTag("pirate")

// Usage with manager
localeManager.getOrDefault(czech, "welcome-key")

Custom Callbacks

Attach logic directly to messages (useful for logging or triggering events):

message.withCallback { player, msg -> 
    plugin.logger.info("Sent ${msg.lines.size} lines to ${player.name}")
}.send(player)

Merging Multiple Sources

The MergedLocaleProvider allows you to combine base translations with local user overrides:

val localeManager = KLocale.paper(plugin) {
    // You can specify your own minimessage with custom tag resolvers
    miniMessage = MiniMessage.miniMessage()
    provider = MergedLocaleProvider(
        listOf(
            // 1. Remote "Base" translations
            GitHubLocaleProvider("User", "Repo", "path/to/locales", serializer),

            // 2. Local "User" overrides (Takes priority)
            YamlLocaleProvider(File(dataFolder, "overrides.yml"), serializer)
        )
    )
}

Missing Key Strategies

You can define what happens when a key is missing by implementing MissingKeyHandler. The default behavior is to throw an exception, but you can override this globally:

class MyCustomHandler : MissingKeyHandler<PaperMessage> {
    override fun handle(key: String, language: String): PaperMessage {
        return PaperMessage.of(Component.text("Missing: $key", NamedTextColor.RED))
    }
}

🤝 Contributing

Contributions are welcome! Please feel free to submit a Pull Request.


💬 Community & Support

Got questions, need help, or want to showcase what you've built with KLocale? Join our community!

Discord Banner


Built with ❤️ by Larkyy

About

A high-performance, developer-friendly localization library for Kotlin and PaperMC. It bridges the gap between raw configuration files and rich, interactive Adventure Components.

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Contributors 2

  •  
  •  

Languages