Outerstellar Outerstellar
← All Projects

Outerstellar Framework

Headless, framework-agnostic Kotlin utilities for modern JVM development — hot-reloading i18n, JSON-based theming, a plugin engine, and build-time translation validation.

Outerstellar Framework

Headless Kotlin utility modules for i18n, theming, and plugin discovery. No web framework or UI toolkit dependencies — each module is a standalone artifact you can add to any JVM project.

View on GitHub

Published to GitHub Packages at maven.pkg.github.com/rygel/outerstellar-framework.


What modules are included?

outerstellar-i18n

Translation service backed by ResourceBundle with parameter substitution and locale fallback. Bundles are cached per locale and can be reloaded at runtime without a restart.

val i18n = I18nService.create("messages") // loads messages.properties

// Simple lookup
val greeting = i18n.translate("welcome.title")
// → "Welcome to Outerstellar"

// Parameter substitution ({0}, {1} style)
val personalized = i18n.translate("welcome.message", userName)
// → "Hello, Alex! Welcome back."

// Locale-specific
val german = i18n.translate("welcome.title", Locale.GERMAN)
// → "Willkommen bei Outerstellar"

Thread-safe. Zero dependencies beyond the Kotlin stdlib.

outerstellar-theme

Reads color definitions from JSON files and produces CSS custom properties or raw color values for programmatic use. Supports shade generation (lighter/darker variants from a base color).

val theme = ThemeService.create().loadFromClasspath("themes/dark.json")

// CSS output
val css = theme.toCssForSelector(":root")
// → ":root { --color-primary: #f97316; --color-bg: #0f172a; ... }"

// Programmatic access
val primary = theme.color("primary")
val lighter = theme.shade("primary", 0.2) // 20% lighter

Theme file:

{
  "name": "dark",
  "colors": {
    "primary": "#f97316",
    "background": "#0f172a",
    "surface": "#1e293b",
    "text": "#f1f5f9",
    "muted": "#64748b"
  }
}

Themes can be loaded from the classpath, file system, or built programmatically. Hot reload is supported in development.

outerstellar-plugin

ServiceLoader-based plugin discovery with lifecycle hooks and caching.

interface AnalyticsPlugin {
    fun trackEvent(name: String, properties: Map<String, Any>)
}

// Discovers all implementations on the classpath
val plugins = PluginEngine.discover<AnalyticsPlugin>()
plugins.forEach { it.trackEvent("page_view", mapOf("path" to "/")) }

Plugins are found automatically when their JAR is on the classpath. The engine caches discovery results and provides onLoad/onUnload lifecycle hooks.


How does build-time translation validation work?

The framework includes tools to detect translation problems at build time rather than in production.

Checks

CheckWhat it catches
Missing translationsKeys in the default bundle that are absent in a locale
Unused keysKeys defined in bundles but never referenced in source
Undefined referencesKeys used in source code but missing from all bundles
Parameter mismatchesPlaceholder differences ({0}, {1}) between locales

Maven Plugin

Runs during mvn verify and fails the build on issues:

<plugin>
    <groupId>io.github.rygel</groupId>
    <artifactId>outerstellar-i18n-validator-maven-plugin</artifactId>
    <version>1.0.14</version>
    <executions>
        <execution>
            <goals><goal>validate</goal></goals>
            <configuration>
                <bundleName>messages</bundleName>
                <sourceDirectories>
                    <directory>src/main/kotlin</directory>
                </sourceDirectories>
                <locales>
                    <locale>en</locale>
                    <locale>de</locale>
                    <locale>fr</locale>
                </locales>
            </configuration>
        </execution>
    </executions>
</plugin>

CLI

For use outside Maven or in CI pipelines:

java -jar outerstellar-i18n-validator-cli.jar \
    --bundle messages \
    --source src/main/kotlin \
    --locales en,de,fr

GUI

A Swing application for browsing translation files and seeing coverage at a glance. Intended for translators and content editors.


How do I add the framework to my project?

Add the GitHub Packages repository:

<repositories>
    <repository>
        <id>github-rygel</id>
        <url>https://maven.pkg.github.com/rygel/outerstellar-framework</url>
    </repository>
</repositories>

Then add modules as needed:

<dependency>
    <groupId>io.github.rygel</groupId>
    <artifactId>outerstellar-i18n</artifactId>
    <version>1.0.14</version>
</dependency>

<dependency>
    <groupId>io.github.rygel</groupId>
    <artifactId>outerstellar-theme</artifactId>
    <version>1.0.14</version>
</dependency>

<dependency>
    <groupId>io.github.rygel</groupId>
    <artifactId>outerstellar-plugin</artifactId>
    <version>1.0.14</version>
</dependency>

Project Structure

outerstellar-framework/
├── outerstellar-i18n/                         Translation service
├── outerstellar-theme/                        Theming engine
├── outerstellar-plugin/                       Plugin discovery
├── outerstellar-i18n-validator/               Validation core
├── outerstellar-i18n-validator-maven-plugin/  Maven plugin
├── outerstellar-i18n-validator-cli/           CLI
└── outerstellar-i18n-validator-gui/           Swing GUI

Requirements

  • JDK 21+
  • Kotlin 2.0+ (compiles against 2.0 for consumer compatibility; works with 2.3+)

FAQ

What is the Outerstellar Framework?

A set of headless, framework-agnostic Kotlin utility modules for internationalisation (i18n), theming, and plugin discovery. Each module is a standalone Maven artifact with zero web framework dependencies — add only what you need.

What does the i18n module do?

It provides a ResourceBundle-backed translation service with parameter substitution ({0}, {1} style), locale fallback, and hot reload at runtime. A Maven plugin and CLI tool validate translations at build time, catching missing keys, unused keys, undefined references, and parameter mismatches between locales.

Does the theming module require a specific CSS framework?

No. It reads color definitions from JSON files and outputs CSS custom properties (for web) or raw color values (for desktop or programmatic use). Shade generation produces lighter/darker variants from a base color. It works with Tailwind CSS, plain CSS, or no CSS at all.

What is the plugin engine?

A ServiceLoader-based plugin discovery system with lifecycle hooks (onLoad/onUnload) and caching. Plugins are discovered automatically when their JAR is on the classpath. No annotation processing or code generation required.

What Java version is required?

JDK 21 or later. The framework compiles against Kotlin 2.0 for consumer compatibility and works with Kotlin 2.3+.

License

Apache License 2.0