Skip to content

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

2 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages