Skip to content

AtlasLang

Multilingual engine used by every Nautic Studios plugin. Stores each player’s language in a database, loads per-language YAML files and exposes the AtlasAPI v2 so any plugin can translate messages without owning the data.

Reads are cached in memory, writes are async — every API method is safe to call from the main thread.

GitHub: nauticstudios/AtlasLang · API source: api/

config.yml
default: english
register:
languages:
- en_US:english:messages.yml
- es_ES:spanish:messages.yml
- pt_BR:portuguese:messages.yml

Folder layout:

languages/
├── english/
│ ├── messages.yml
│ ├── scoreboard.yml
│ └── atlasaddon.yml
└── spanish/
└── ...
%alang_(file)_(path)%
%alang_(messages)_(join_message)%
%alang_(lobby:scoreboard)_(title)%

Resolves using the player’s language. Missing keys return a safe error string.

Base: /atlaslang

CommandPermission
/atlaslang help
/atlaslang listatlaslang.list
/atlaslang aliasesatlaslang.aliases
/atlaslang set <player> <language>atlaslang.set
/atlaslang reset <player>atlaslang.reset
/atlaslang info <player>atlaslang.info
/atlaslang reloadatlaslang.reload
/atlaslang github syncatlaslang.github
/atlaslang github statusatlaslang.github

atlaslang.admin grants every permission above.

Maven module: com.github.nautic:api. Three types — AtlasAPI, AtlasProvider, PlayerLanguageChangeEvent.

pom.xml
<repositories>
<repository>
<id>jitpack.io</id>
<url>https://jitpack.io</url>
</repository>
</repositories>
<dependency>
<groupId>com.github.nauticstudios.AtlasLang</groupId>
<artifactId>api</artifactId>
<version>VERSION</version>
<scope>provided</scope>
</dependency>
build.gradle.kts
repositories { maven("https://jitpack.io") }
dependencies {
compileOnly("com.github.nauticstudios.AtlasLang:api:VERSION")
}
plugin.yml
depend: [AtlasLang] # or: softdepend: [AtlasLang]
Example.java
import com.github.nautic.api.AtlasAPI;
String msg = AtlasAPI.translate(player, "join.welcome");
String greet = AtlasAPI.translateOrDefault(
player.getUniqueId(), "myaddon", "join.welcome", "Welcome!"
);
AtlasAPI.setLanguage(player, "spanish");
String lang = AtlasAPI.getLanguage(player);
  • Every method has a Player and a UUID overload.
  • langInput accepts either a locale code (en_US) or folder (english).
  • namespace is a folder inside languages/<lang>/. Defaults to atlasaddon.
  • getPlayerLanguage(...) reads from memory — no DB call.
ConstantValue
AtlasAPI.API_VERSION2
AtlasAPI.DEFAULT_NAMESPACE"atlasaddon"
MyPlugin.java
package com.example.myplugin;
import org.bukkit.plugin.java.JavaPlugin;
import com.github.nautic.api.AtlasAPI;
public final class MyPlugin extends JavaPlugin {
@Override
public void onEnable() {
if (!AtlasAPI.isAvailable()) {
getServer().getPluginManager().disablePlugin(this);
return;
}
try {
AtlasAPI.requireVersion(2);
} catch (IllegalStateException error) {
getLogger().severe(error.getMessage());
getServer().getPluginManager().disablePlugin(this);
}
}
}
AtlasAPI.translate(player, "join.welcome");
AtlasAPI.translate(player, "mycrates", "open.message");
AtlasAPI.translate(uuid, "join.welcome");
AtlasAPI.translate(uuid, "mycrates", "open.message");
AtlasAPI.translateInLang("english", "join.welcome");
AtlasAPI.translateInLang("es_ES", "mycrates", "open.message");
AtlasAPI.translateOrDefault(uuid, "mycrates", "open.message", "&aFallback");
boolean ok = AtlasAPI.setLanguage(player, "spanish");
AtlasAPI.setLanguageAsync(uuid, "spanish").thenAccept(success -> {
// ...
});

Both forms fire PlayerLanguageChangeEvent and persist asynchronously. The sync form returns true if the language was resolved and the event was not cancelled; the async form completes once the DB row is committed.

String folder = AtlasAPI.getLanguage(player);
String locale = AtlasAPI.api().getLocaleOf(folder); // nullable
Set<String> folders = AtlasAPI.getRegistered();
Set<String> locales = AtlasAPI.getLocales();
String fallback = AtlasAPI.getDefault();
AtlasAPI.api().compatibleLanguages(List.of("en_US", "fr_FR", "es_ES"));
MethodReturns
message(Player / UUID, [namespace,] path)String
messageInLang(langInput, [namespace,] path)String
messageOrDefault(UUID, namespace, path, fallback)String
has(langInput, [namespace,] path)boolean
setPlayerLanguage(Player / UUID, langInput)boolean
setPlayerLanguageAsync(UUID, langInput)CompletableFuture<Boolean>
getPlayerLanguage(Player / UUID)String
isLanguageRegistered(langInput) / supports(langInput)boolean
getRegisteredLanguages() / getRegisteredLocales()Set<String>
getDefaultLanguage()String
getLocaleOf(folder)String?
compatibleLanguages(Collection<String>)Set<String>
getApiVersion()int
Static callDelegates to
AtlasAPI.api()AtlasProvider.get()
AtlasAPI.isAvailable()AtlasProvider.isRegistered()
AtlasAPI.requireVersion(int)Throws if API_VERSION is lower.
translate(...)message(...)
translateInLang(...)messageInLang(...)
translateOrDefault(...)messageOrDefault(...)
exists(...)has(...)
setLanguage(...)setPlayerLanguage(...)
setLanguageAsync(...)setPlayerLanguageAsync(...)
getLanguage(...)getPlayerLanguage(...)
getRegistered() / getLocales() / getDefault()corresponding instance method

Cancellable. New language can be rewritten with setNewLanguage(...).

MethodReturns
getUniqueId()UUID
getPreviousLanguage()String?
getNewLanguage()String
setNewLanguage(String)void
isCancelled() / setCancelled(boolean)
LanguageGuard.java
package com.example.plugin.listener;
import org.bukkit.event.EventHandler;
import org.bukkit.event.EventPriority;
import org.bukkit.event.Listener;
import com.github.nautic.api.event.PlayerLanguageChangeEvent;
import java.util.Set;
public final class LanguageGuard implements Listener {
private static final Set<String> BLOCKED = Set.of("klingon");
@EventHandler(priority = EventPriority.HIGH, ignoreCancelled = true)
public void onChange(final PlayerLanguageChangeEvent event) {
if (BLOCKED.contains(event.getNewLanguage())) {
event.setCancelled(true);
return;
}
if ("portuguese".equals(event.getNewLanguage())) {
event.setNewLanguage("portuguese_br");
}
}
}
WelcomePlugin.java
package com.example.welcome;
import org.bukkit.command.Command;
import org.bukkit.command.CommandSender;
import org.bukkit.entity.Player;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.plugin.java.JavaPlugin;
import com.github.nautic.api.AtlasAPI;
public final class WelcomePlugin extends JavaPlugin implements Listener {
private static final String NAMESPACE = "welcome";
@Override
public void onEnable() {
if (!AtlasAPI.isAvailable()) {
getServer().getPluginManager().disablePlugin(this);
return;
}
AtlasAPI.requireVersion(2);
getServer().getPluginManager().registerEvents(this, this);
}
@EventHandler
public void onJoin(final PlayerJoinEvent event) {
final Player player = event.getPlayer();
player.sendMessage(AtlasAPI.translateOrDefault(
player.getUniqueId(), NAMESPACE, "join.message",
"&aWelcome, " + player.getName() + "!"
));
}
@Override
public boolean onCommand(final CommandSender sender, final Command command,
final String label, final String[] args) {
if (!(sender instanceof Player player)) return false;
player.sendMessage(AtlasAPI.translate(player, NAMESPACE, "command.welcome"));
return true;
}
}
welcome.yml
join:
message: "&aWelcome back, %player_name%!"
command:
welcome: "&bHello from AtlasLang!"
config.yml
github:
repository:
name: "owner/repository"
branch: "main"
authentication:
type: "none"
token: ""
paths:
remote-root: "languages"
local-root: "languages"
sync:
create-missing: true
overwrite-existing: true
delete-missing: false
reload-after-sync: true

Trigger manually with /atlaslang github sync.

Last updated: May 23, 2026 by Senkex in cfd9d75