https://github.com/leycm/i18label4j
A fast, server-side translation and label provider for high-performance Text & MiniMessage localization
https://github.com/leycm/i18label4j
4j adventure-api i18n java java21 kotlin minimessage papermc
Last synced: 2 days ago
JSON representation
A fast, server-side translation and label provider for high-performance Text & MiniMessage localization
- Host: GitHub
- URL: https://github.com/leycm/i18label4j
- Owner: leycm
- License: lgpl-3.0
- Created: 2026-03-15T17:17:38.000Z (21 days ago)
- Default Branch: main
- Last Pushed: 2026-04-01T12:41:11.000Z (5 days ago)
- Last Synced: 2026-04-01T14:48:20.527Z (4 days ago)
- Topics: 4j, adventure-api, i18n, java, java21, kotlin, minimessage, papermc
- Language: Java
- Homepage:
- Size: 326 KB
- Stars: 3
- Watchers: 2
- Forks: 2
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE.LGPL
Awesome Lists containing this project
README
[![Contributors][contributors-shield]][contributors-url]
[![Forks][forks-shield]][forks-url]
[![Stargazers][stars-shield]][stars-url]
[![Issues][issues-shield]][issues-url]
[![LGPL License][license-shield]][license-url]
i18label4j
A simple and lightweight registry library with flexible identifiers and namespaces for Java.
Localize your application cleanly — with typed labels, dynamic placeholders, and pluggable serializers.
Explore the docs »
·
Report Bug
·
Request Feature
---
Table of Contents
- About The Project
-
Getting Started
- Usage
- Architecture
- Roadmap
- Contributing
- License
- Contact
- Acknowledgments
---
## About The Project
**i18label4j** is a modular Java library for managing localizable text labels with a clean, fluent API. It provides:
- **Typed labels** — distinguish between locale-aware i18n labels and immutable literal labels at compile time.
- **Placeholder substitution** — register static or dynamic `Mapping` objects on any label and apply them via configurable `MappingRule` strategies (supports `${key}`, `{key}`, `%key%`, ``, and more out of the box).
- **Pluggable serializers** — convert labels to any target type (plain `String`, Adventure `Component`, etc.) by registering a `LabelSerializer`.
- **Multiple localization sources** — load translations from a flat directory (`FileSource`), a nested directory tree (`DirSource`), or implement your own `LocalizationSource`.
- **Format support** — JSON, YAML, TOML, and Java `.properties` files are supported out of the box.
- **Translation caching** — the `CommonLabelProvider` caches translations per locale with thread-safe `ConcurrentHashMap` internals and explicit cache eviction.
### Built With
- [![Java][java-badge]][java-url]
- [![Gradle][gradle-badge]][gradle-url]
- [![Lombok][lombok-badge]][lombok-url]
- [SnakeYAML](https://bitbucket.org/snakeyaml/snakeyaml) · [toml4j](https://github.com/moandjiezana/toml4j) · [org.json](https://github.com/stleary/JSON-java)
- [Adventure API](https://docs.advntr.net/) *(optional serializer target)*
---
## Getting Started
### Prerequisites
- Java 21+
- Gradle 9+ (wrapper included)
### Installation
Add the repository and dependency to your `build.gradle.kts`:
```kotlin
repositories {
maven("https://leycm.github.io/repository/")
}
dependencies {
// API only (compile against the interface)
compileOnly("de.leycm:i18label4j-api:1.0")
// Full implementation (includes CommonLabelProvider, FileSource, DirSource, etc.)
implementation("de.leycm:i18label4j-impl:1.0")
}
```
Or with Maven (`pom.xml`):
```xml
leycm-repo
https://leycm.github.io/repository/
de.leycm
i18label4j-api
1.0
provided
de.leycm
i18label4j-impl
1.0
```
---
## Usage
### 1. Set up a `LabelProvider`
```java
// Load translations from a flat directory of JSON files:
// resources/lang/en.json, de.json, ...
LocalizationSource source = FileSource.json(
URI.create("resource://lang")
);
LabelProvider provider = CommonLabelProvider.builder()
.locale(Locale.ENGLISH) // default locale
.defaultMappingRule(MappingRule.DOLLAR_CURLY) // ${placeholder} syntax
.withSerializer(String.class, new MyStringSerializer())
.buildWarm(source, Locale.ENGLISH, Locale.GERMAN); // pre-load cache
// Register as singleton
Instanceable.register(provider, LabelProvider.class);
```
### 2. Create and resolve labels
```java
// Translatable label — looks up "greeting" in the active locale
Label hello = Label.of("greeting");
System.out.println(hello.in(Locale.ENGLISH)); // -> "Hello!"
System.out.println(hello.in(Locale.GERMAN)); // -> "Hallo!"
// Literal label — always returns the fixed string
Label version = Label.literal("v1.0.0");
System.out.println(version.in(Locale.JAPANESE)); // -> "v1.0.0"
```
### 3. Placeholder substitution
```java
Label message = Label.of("welcome.message")
.mapTo("name", () -> currentUser.getDisplayName())
.mapTo("count", itemCount);
// Translation: "Welcome, ${name}! You have ${count} items."
System.out.println(message.mapped(Locale.ENGLISH));
// -> "Welcome, Alice! You have 3 items."
```
### 4. Serialize to a custom type
```java
// Assuming an Adventure Component serializer is registered:
Component component = Label.of("server.motd").serialize(Component.class);
```
### 5. Translation file layout (`FileSource`)
```
resources/lang/
en.json -> {"greeting": "Hello!", "welcome.message": "Welcome, ${name}!"}
de.json -> {"greeting": "Hallo!", "welcome.message": "Willkommen, ${name}!"}
```
### 6. Nested directory layout (`DirSource`)
```
resources/lang/
en/
messages.json -> {"greeting": "Hello!"}
errors.json -> {"not_found": "Not found."}
de/
messages.json -> {"greeting": "Hallo!"}
```
Keys are prefixed with the filename stem: `messages.greeting`, `errors.not_found`.
### Available `MappingRule` styles
| Constant | Example |
|---|---|
| `MappingRule.DOLLAR_CURLY` | `${variable}` |
| `MappingRule.CURLY` | `{variable}` |
| `MappingRule.DOUBLE_CURLY` | `{{variable}}` |
| `MappingRule.PERCENT` | `%variable%` |
| `MappingRule.TAG` | `` |
| `MappingRule.SHELL` | `$variable` |
| `MappingRule.MINI_MESSAGE` | `` |
| ... | ... |
---
## Architecture
```
i18label4j
├── i18-api/ # Public API — Label, LabelProvider, Mapping, MappingRule, LabelSerializer, LocalizationSource
└── i18-impl/ # Implementation — CommonLabelProvider, LiteralLabel, LocaleLabel,
# FileSource, DirSource, FileParser, FileUtils
```
The library is split into two modules so downstream projects can depend only on the API and swap implementations at runtime via `Instanceable.register(...)`.
---
## Roadmap
- [x] Core `Label` API with `LiteralLabel` and `LocaleLabel`
- [x] `CommonLabelProvider` with thread-safe translation cache
- [x] `MappingRule` with 10+ built-in placeholder styles
- [x] `FileSource` and `DirSource` with JSON, YAML, TOML, `.properties` support
- [x] Classpath (`resource://`), filesystem (`file://`), and remote (`http(s)://`) URI schemes
- [x] Nested/hierarchical key support in `DirSource`
- [x] Hot-reload support for translation files
- [ ] Maven / Gradle plugin for compile-time key validation
- [ ] Additional serializer modules (Adventure, MiniMessage)
See the [open issues](https://github.com/leycm/i18label4j/issues) for the full list of proposed features and known bugs.
---
## Contributing
Contributions are what make open source such a great place to learn and build. Any contributions you make are **greatly appreciated**.
1. Fork the project
2. Create your feature branch (`git checkout -b feat/amazing-feature`)
3. Commit your changes (`git commit -m 'feat: add some amazing Features'`)
4. Push to the branch (`git push origin feat/amazing-feature`)
5. Open a Pull Request
---
## License
Distributed under the **GNU Lesser General Public License v3.0**. See [`LICENSE.LGPL`](LICENSE.LGPL) for more information.
---
## Contact
**Lennard** — leycm@proton.me
Project Link: [https://github.com/leycm/i18label4j](https://github.com/leycm/i18label4j)
---
## Acknowledgments
- [Lombok](https://projectlombok.org/) — boilerplate-free Java
- [SnakeYAML](https://bitbucket.org/snakeyaml/snakeyaml) — YAML parsing
- [toml4j](https://github.com/moandjiezana/toml4j) — TOML parsing
- [org.json](https://github.com/stleary/JSON-java) — JSON parsing
- [Adventure API](https://docs.advntr.net/) — Minecraft text component library
- [Best-README-Template](https://github.com/othneildrew/Best-README-Template) — README structure inspiration
- [Choose an Open Source License](https://choosealicense.com)
- [Shields.io](https://shields.io)
---
[contributors-shield]: https://img.shields.io/github/contributors/leycm/i18label4j.svg?style=for-the-badge
[contributors-url]: https://github.com/leycm/i18label4j/graphs/contributors
[forks-shield]: https://img.shields.io/github/forks/leycm/i18label4j.svg?style=for-the-badge
[forks-url]: https://github.com/leycm/i18label4j/network/members
[stars-shield]: https://img.shields.io/github/stars/leycm/i18label4j.svg?style=for-the-badge
[stars-url]: https://github.com/leycm/i18label4j/stargazers
[issues-shield]: https://img.shields.io/github/issues/leycm/i18label4j.svg?style=for-the-badge
[issues-url]: https://github.com/leycm/i18label4j/issues
[license-shield]: https://img.shields.io/github/license/leycm/i18label4j.svg?style=for-the-badge
[license-url]: https://github.com/leycm/i18label4j/blob/master/LICENSE.LGPL
[java-badge]: https://img.shields.io/badge/Java_21-ED8B00?style=for-the-badge&logo=openjdk&logoColor=white
[java-url]: https://openjdk.org/projects/jdk/21/
[gradle-badge]: https://img.shields.io/badge/Gradle-02303A?style=for-the-badge&logo=gradle&logoColor=white
[gradle-url]: https://gradle.org/
[lombok-badge]: https://img.shields.io/badge/Lombok-BC4521?style=for-the-badge&logo=lombok&logoColor=white
[lombok-url]: https://projectlombok.org/